]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
Merge branch 'slab/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penber...
[karo-tx-linux.git] / drivers / net / wireless / rtlwifi / rtl8723ae / fw.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  ****************************************************************************
29  */
30
31 #include "../wifi.h"
32 #include "../pci.h"
33 #include "../base.h"
34 #include "reg.h"
35 #include "def.h"
36 #include "fw.h"
37
38 static void _rtl8723ae_enable_fw_download(struct ieee80211_hw *hw, bool enable)
39 {
40         struct rtl_priv *rtlpriv = rtl_priv(hw);
41         u8 tmp;
42         if (enable) {
43                 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
44                 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
45
46                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
47                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
48
49                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
50                 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
51         } else {
52                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
53                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
54
55                 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
56         }
57 }
58
59 static void _rtl8723ae_fw_block_write(struct ieee80211_hw *hw,
60                                       const u8 *buffer, u32 size)
61 {
62         struct rtl_priv *rtlpriv = rtl_priv(hw);
63         u32 blockSize = sizeof(u32);
64         u8 *bufferPtr = (u8 *) buffer;
65         u32 *pu4BytePtr = (u32 *) buffer;
66         u32 i, offset, blockCount, remainSize;
67
68         blockCount = size / blockSize;
69         remainSize = size % blockSize;
70
71         for (i = 0; i < blockCount; i++) {
72                 offset = i * blockSize;
73                 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
74                                 *(pu4BytePtr + i));
75         }
76
77         if (remainSize) {
78                 offset = blockCount * blockSize;
79                 bufferPtr += offset;
80                 for (i = 0; i < remainSize; i++) {
81                         rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
82                                                  offset + i), *(bufferPtr + i));
83                 }
84         }
85 }
86
87 static void _rtl8723ae_fw_page_write(struct ieee80211_hw *hw,
88                                      u32 page, const u8 *buffer, u32 size)
89 {
90         struct rtl_priv *rtlpriv = rtl_priv(hw);
91         u8 value8;
92         u8 u8page = (u8) (page & 0x07);
93
94         value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
95
96         rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
97         _rtl8723ae_fw_block_write(hw, buffer, size);
98 }
99
100 static void _rtl8723ae_write_fw(struct ieee80211_hw *hw,
101                                 enum version_8723e version, u8 *buffer,
102                                 u32 size)
103 {
104         struct rtl_priv *rtlpriv = rtl_priv(hw);
105         u8 *bufferPtr = (u8 *) buffer;
106         u32 page_nums, remain_size;
107         u32 page, offset;
108
109         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
110
111         page_nums = size / FW_8192C_PAGE_SIZE;
112         remain_size = size % FW_8192C_PAGE_SIZE;
113
114         if (page_nums > 6) {
115                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
116                          "Page numbers should not be greater then 6\n");
117         }
118
119         for (page = 0; page < page_nums; page++) {
120                 offset = page * FW_8192C_PAGE_SIZE;
121                 _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
122                                          FW_8192C_PAGE_SIZE);
123         }
124
125         if (remain_size) {
126                 offset = page_nums * FW_8192C_PAGE_SIZE;
127                 page = page_nums;
128                 _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
129                                          remain_size);
130         }
131
132         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
133 }
134
135 static int _rtl8723ae_fw_free_to_go(struct ieee80211_hw *hw)
136 {
137         struct rtl_priv *rtlpriv = rtl_priv(hw);
138         int err = -EIO;
139         u32 counter = 0;
140         u32 value32;
141
142         do {
143                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
144         } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
145                  (!(value32 & FWDL_ChkSum_rpt)));
146
147         if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
148                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
149                          "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
150                          value32);
151                 goto exit;
152         }
153
154         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
155                  "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
156
157         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
158         value32 |= MCUFWDL_RDY;
159         value32 &= ~WINTINI_RDY;
160         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
161
162         counter = 0;
163
164         do {
165                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
166                 if (value32 & WINTINI_RDY) {
167                         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
168                                  "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
169                                  value32);
170                         err = 0;
171                         goto exit;
172                 }
173
174                 mdelay(FW_8192C_POLLING_DELAY);
175
176         } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
177
178         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
179                  "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
180
181 exit:
182         return err;
183 }
184
185 int rtl8723ae_download_fw(struct ieee80211_hw *hw)
186 {
187         struct rtl_priv *rtlpriv = rtl_priv(hw);
188         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
189         struct rtl8723ae_firmware_header *pfwheader;
190         u8 *pfwdata;
191         u32 fwsize;
192         int err;
193         enum version_8723e version = rtlhal->version;
194
195         if (!rtlhal->pfirmware)
196                 return 1;
197
198         pfwheader = (struct rtl8723ae_firmware_header *)rtlhal->pfirmware;
199         pfwdata = (u8 *) rtlhal->pfirmware;
200         fwsize = rtlhal->fwsize;
201
202         if (IS_FW_HEADER_EXIST(pfwheader)) {
203                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
204                          "Firmware Version(%d), Signature(%#x),Size(%d)\n",
205                          pfwheader->version, pfwheader->signature,
206                          (int)sizeof(struct rtl8723ae_firmware_header));
207
208                 pfwdata = pfwdata + sizeof(struct rtl8723ae_firmware_header);
209                 fwsize = fwsize - sizeof(struct rtl8723ae_firmware_header);
210         }
211
212         if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
213                 rtl8723ae_firmware_selfreset(hw);
214                 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
215         }
216         _rtl8723ae_enable_fw_download(hw, true);
217         _rtl8723ae_write_fw(hw, version, pfwdata, fwsize);
218         _rtl8723ae_enable_fw_download(hw, false);
219
220         err = _rtl8723ae_fw_free_to_go(hw);
221         if (err) {
222                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
223                          "Firmware is not ready to run!\n");
224         } else {
225                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
226                          "Firmware is ready to run!\n");
227         }
228         return 0;
229 }
230
231 static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
232 {
233         struct rtl_priv *rtlpriv = rtl_priv(hw);
234         u8 val_hmetfr, val_mcutst_1;
235         bool result = false;
236
237         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
238         val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
239
240         if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
241                 result = true;
242         return result;
243 }
244
245 static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw,
246                                         u8 element_id, u32 cmd_len,
247                                         u8 *p_cmdbuffer)
248 {
249         struct rtl_priv *rtlpriv = rtl_priv(hw);
250         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
251         u8 boxnum;
252         u16 box_reg = 0, box_extreg = 0;
253         u8 u1tmp;
254         bool isfw_rd = false;
255         bool bwrite_sucess = false;
256         u8 wait_h2c_limmit = 100;
257         u8 wait_writeh2c_limmit = 100;
258         u8 boxcontent[4], boxextcontent[2];
259         u32 h2c_waitcounter = 0;
260         unsigned long flag;
261         u8 idx;
262
263         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
264
265         while (true) {
266                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
267                 if (rtlhal->h2c_setinprogress) {
268                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
269                                  "H2C set in progress! Wait to set..element_id(%d).\n",
270                                  element_id);
271
272                         while (rtlhal->h2c_setinprogress) {
273                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
274                                                        flag);
275                                 h2c_waitcounter++;
276                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
277                                          "Wait 100 us (%d times)...\n",
278                                          h2c_waitcounter);
279                                 udelay(100);
280
281                                 if (h2c_waitcounter > 1000)
282                                         return;
283                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
284                                                   flag);
285                         }
286                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
287                 } else {
288                         rtlhal->h2c_setinprogress = true;
289                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
290                         break;
291                 }
292         }
293
294         while (!bwrite_sucess) {
295                 wait_writeh2c_limmit--;
296                 if (wait_writeh2c_limmit == 0) {
297                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
298                                  "Write H2C fail because no trigger "
299                                  "for FW INT!\n");
300                         break;
301                 }
302
303                 boxnum = rtlhal->last_hmeboxnum;
304                 switch (boxnum) {
305                 case 0:
306                         box_reg = REG_HMEBOX_0;
307                         box_extreg = REG_HMEBOX_EXT_0;
308                         break;
309                 case 1:
310                         box_reg = REG_HMEBOX_1;
311                         box_extreg = REG_HMEBOX_EXT_1;
312                         break;
313                 case 2:
314                         box_reg = REG_HMEBOX_2;
315                         box_extreg = REG_HMEBOX_EXT_2;
316                         break;
317                 case 3:
318                         box_reg = REG_HMEBOX_3;
319                         box_extreg = REG_HMEBOX_EXT_3;
320                         break;
321                 default:
322                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
323                                  "switch case not processed\n");
324                         break;
325                 }
326
327                 isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
328                 while (!isfw_rd) {
329
330                         wait_h2c_limmit--;
331                         if (wait_h2c_limmit == 0) {
332                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
333                                          "Wating too long for FW read clear HMEBox(%d)!\n",
334                                          boxnum);
335                                 break;
336                         }
337
338                         udelay(10);
339
340                         isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
341                         u1tmp = rtl_read_byte(rtlpriv, 0x1BF);
342                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
343                                  "Wating for FW read clear HMEBox(%d)!!! "
344                                  "0x1BF = %2x\n", boxnum, u1tmp);
345                 }
346
347                 if (!isfw_rd) {
348                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
349                                  "Write H2C register BOX[%d] fail!!!!! "
350                                  "Fw do not read.\n", boxnum);
351                         break;
352                 }
353
354                 memset(boxcontent, 0, sizeof(boxcontent));
355                 memset(boxextcontent, 0, sizeof(boxextcontent));
356                 boxcontent[0] = element_id;
357                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
358                          "Write element_id box_reg(%4x) = %2x\n",
359                           box_reg, element_id);
360
361                 switch (cmd_len) {
362                 case 1:
363                         boxcontent[0] &= ~(BIT(7));
364                         memcpy((u8 *) (boxcontent) + 1,
365                                p_cmdbuffer, 1);
366
367                         for (idx = 0; idx < 4; idx++) {
368                                 rtl_write_byte(rtlpriv, box_reg + idx,
369                                                boxcontent[idx]);
370                         }
371                         break;
372                 case 2:
373                         boxcontent[0] &= ~(BIT(7));
374                         memcpy((u8 *) (boxcontent) + 1,
375                                p_cmdbuffer, 2);
376
377                         for (idx = 0; idx < 4; idx++) {
378                                 rtl_write_byte(rtlpriv, box_reg + idx,
379                                                boxcontent[idx]);
380                         }
381                         break;
382                 case 3:
383                         boxcontent[0] &= ~(BIT(7));
384                         memcpy((u8 *) (boxcontent) + 1,
385                                p_cmdbuffer, 3);
386
387                         for (idx = 0; idx < 4; idx++) {
388                                 rtl_write_byte(rtlpriv, box_reg + idx,
389                                                boxcontent[idx]);
390                         }
391                         break;
392                 case 4:
393                         boxcontent[0] |= (BIT(7));
394                         memcpy((u8 *) (boxextcontent),
395                                p_cmdbuffer, 2);
396                         memcpy((u8 *) (boxcontent) + 1,
397                                p_cmdbuffer + 2, 2);
398
399                         for (idx = 0; idx < 2; idx++) {
400                                 rtl_write_byte(rtlpriv, box_extreg + idx,
401                                                boxextcontent[idx]);
402                         }
403
404                         for (idx = 0; idx < 4; idx++) {
405                                 rtl_write_byte(rtlpriv, box_reg + idx,
406                                                boxcontent[idx]);
407                         }
408                         break;
409                 case 5:
410                         boxcontent[0] |= (BIT(7));
411                         memcpy((u8 *) (boxextcontent),
412                                p_cmdbuffer, 2);
413                         memcpy((u8 *) (boxcontent) + 1,
414                                p_cmdbuffer + 2, 3);
415
416                         for (idx = 0; idx < 2; idx++) {
417                                 rtl_write_byte(rtlpriv, box_extreg + idx,
418                                                boxextcontent[idx]);
419                         }
420
421                         for (idx = 0; idx < 4; idx++) {
422                                 rtl_write_byte(rtlpriv, box_reg + idx,
423                                                boxcontent[idx]);
424                         }
425                         break;
426                 default:
427                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
428                                  "switch case not process\n");
429                         break;
430                 }
431
432                 bwrite_sucess = true;
433
434                 rtlhal->last_hmeboxnum = boxnum + 1;
435                 if (rtlhal->last_hmeboxnum == 4)
436                         rtlhal->last_hmeboxnum = 0;
437
438                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
439                          "pHalData->last_hmeboxnum  = %d\n",
440                          rtlhal->last_hmeboxnum);
441         }
442
443         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
444         rtlhal->h2c_setinprogress = false;
445         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
446
447         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
448 }
449
450 void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw,
451                             u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
452 {
453         struct rtl_priv *rtlpriv = rtl_priv(hw);
454         struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
455
456         if (rtlhal->fw_ready == false) {
457                 RT_ASSERT(false,
458                          "return H2C cmd because of Fw download fail!!!\n");
459                 return;
460         }
461
462         _rtl8723ae_fill_h2c_command(hw, element_id, cmd_len, p_cmdbuffer);
463         return;
464 }
465
466 void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
467 {
468         u8 u1tmp;
469         u8 delay = 100;
470         struct rtl_priv *rtlpriv = rtl_priv(hw);
471
472         rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
473         u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
474
475         while (u1tmp & BIT(2)) {
476                 delay--;
477                 if (delay == 0)
478                         break;
479                 udelay(50);
480                 u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
481         }
482         if (delay == 0) {
483                 u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
484                 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
485         }
486 }
487
488 void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
489 {
490         struct rtl_priv *rtlpriv = rtl_priv(hw);
491         u8 u1_h2c_set_pwrmode[3] = { 0 };
492         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
493
494         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
495
496         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
497         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
498         SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
499                                               ppsc->reg_max_lps_awakeintvl);
500
501         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
502                       "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
503                       u1_h2c_set_pwrmode, 3);
504         rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
505
506 }
507
508 static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
509                                        struct sk_buff *skb)
510 {
511         struct rtl_priv *rtlpriv = rtl_priv(hw);
512         struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
513         struct rtl8192_tx_ring *ring;
514         struct rtl_tx_desc *pdesc;
515         u8 own;
516         unsigned long flags;
517         struct sk_buff *pskb = NULL;
518
519         ring = &rtlpci->tx_ring[BEACON_QUEUE];
520
521         pskb = __skb_dequeue(&ring->queue);
522         if (pskb)
523                 kfree_skb(pskb);
524
525         spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
526
527         pdesc = &ring->desc[0];
528         own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
529
530         rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
531
532         __skb_queue_tail(&ring->queue, skb);
533
534         spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
535
536         rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
537
538         return true;
539 }
540
541 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
542         /* page 0 beacon */
543         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
544         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
545         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
546         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
548         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
549         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
550         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
551         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
552         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
553         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
557         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559
560         /* page 1 beacon */
561         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
574         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577
578         /* page 2  ps-poll */
579         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
580         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
581         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
582         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
592         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
593         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595
596         /* page 3  null */
597         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
598         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
599         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
600         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
610         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
611         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613
614         /* page 4  probe_resp */
615         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
616         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
617         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
618         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
619         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
620         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
621         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
622         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
623         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
624         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
625         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
629         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631
632         /* page 5  probe_resp */
633         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649 };
650
651 void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
652 {
653         struct rtl_priv *rtlpriv = rtl_priv(hw);
654         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
655         struct sk_buff *skb = NULL;
656
657         u32 totalpacketlen;
658         bool rtstatus;
659         u8 u1RsvdPageLoc[3] = { 0 };
660         bool dlok = false;
661
662         u8 *beacon;
663         u8 *p_pspoll;
664         u8 *nullfunc;
665         u8 *p_probersp;
666         /*---------------------------------------------------------
667                                 (1) beacon
668         ---------------------------------------------------------
669         */
670         beacon = &reserved_page_packet[BEACON_PG * 128];
671         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
672         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
673
674         /*-------------------------------------------------------
675                                 (2) ps-poll
676         --------------------------------------------------------
677         */
678         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
679         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
680         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
681         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
682
683         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
684
685         /*--------------------------------------------------------
686                                 (3) null data
687         ---------------------------------------------------------i
688         */
689         nullfunc = &reserved_page_packet[NULL_PG * 128];
690         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
691         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
692         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
693
694         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
695
696         /*---------------------------------------------------------
697                                 (4) probe response
698         ----------------------------------------------------------
699         */
700         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
701         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
702         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
703         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
704
705         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
706
707         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
708
709         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
710                       "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
711                       &reserved_page_packet[0], totalpacketlen);
712         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
713                       "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
714                       u1RsvdPageLoc, 3);
715
716         skb = dev_alloc_skb(totalpacketlen);
717         memcpy((u8 *) skb_put(skb, totalpacketlen),
718                &reserved_page_packet, totalpacketlen);
719
720         rtstatus = _rtl8723ae_cmd_send_packet(hw, skb);
721
722         if (rtstatus)
723                 dlok = true;
724
725         if (dlok) {
726                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
727                          "Set RSVD page location to Fw.\n");
728                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
729                                 "H2C_RSVDPAGE:\n",
730                                 u1RsvdPageLoc, 3);
731                 rtl8723ae_fill_h2c_cmd(hw, H2C_RSVDPAGE,
732                                        sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
733         } else
734                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
735                          "Set RSVD page location to Fw FAIL!!!!!!.\n");
736 }
737
738 void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
739 {
740         u8 u1_joinbssrpt_parm[1] = { 0 };
741
742         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
743
744         rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
745 }