Linux 3.9-rc8
[firefly-linux-kernel-4.4.55.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_success = 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_success) {
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_success = 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         unsigned long flags;
516         struct sk_buff *pskb = NULL;
517
518         ring = &rtlpci->tx_ring[BEACON_QUEUE];
519
520         pskb = __skb_dequeue(&ring->queue);
521         if (pskb)
522                 kfree_skb(pskb);
523
524         spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
525
526         pdesc = &ring->desc[0];
527
528         rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
529
530         __skb_queue_tail(&ring->queue, skb);
531
532         spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
533
534         rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
535
536         return true;
537 }
538
539 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
540         /* page 0 beacon */
541         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
542         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
543         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
544         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
546         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
547         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
548         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
549         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
550         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
551         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
553         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
555         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557
558         /* page 1 beacon */
559         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
572         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575
576         /* page 2  ps-poll */
577         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
578         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
579         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
590         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
591         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593
594         /* page 3  null */
595         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
596         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
597         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
598         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
608         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
609         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611
612         /* page 4  probe_resp */
613         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
614         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
615         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
616         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
617         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
618         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
619         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
620         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
621         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
622         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
623         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
627         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629
630         /* page 5  probe_resp */
631         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 };
648
649 void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
650 {
651         struct rtl_priv *rtlpriv = rtl_priv(hw);
652         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
653         struct sk_buff *skb = NULL;
654
655         u32 totalpacketlen;
656         bool rtstatus;
657         u8 u1RsvdPageLoc[3] = { 0 };
658         bool dlok = false;
659
660         u8 *beacon;
661         u8 *p_pspoll;
662         u8 *nullfunc;
663         u8 *p_probersp;
664         /*---------------------------------------------------------
665                                 (1) beacon
666         ---------------------------------------------------------
667         */
668         beacon = &reserved_page_packet[BEACON_PG * 128];
669         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
670         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
671
672         /*-------------------------------------------------------
673                                 (2) ps-poll
674         --------------------------------------------------------
675         */
676         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
677         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
678         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
679         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
680
681         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
682
683         /*--------------------------------------------------------
684                                 (3) null data
685         ---------------------------------------------------------i
686         */
687         nullfunc = &reserved_page_packet[NULL_PG * 128];
688         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
689         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
690         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
691
692         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
693
694         /*---------------------------------------------------------
695                                 (4) probe response
696         ----------------------------------------------------------
697         */
698         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
699         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
700         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
701         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
702
703         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
704
705         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
706
707         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
708                       "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
709                       &reserved_page_packet[0], totalpacketlen);
710         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
711                       "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
712                       u1RsvdPageLoc, 3);
713
714         skb = dev_alloc_skb(totalpacketlen);
715         memcpy((u8 *) skb_put(skb, totalpacketlen),
716                &reserved_page_packet, totalpacketlen);
717
718         rtstatus = _rtl8723ae_cmd_send_packet(hw, skb);
719
720         if (rtstatus)
721                 dlok = true;
722
723         if (dlok) {
724                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
725                          "Set RSVD page location to Fw.\n");
726                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
727                                 "H2C_RSVDPAGE:\n",
728                                 u1RsvdPageLoc, 3);
729                 rtl8723ae_fill_h2c_cmd(hw, H2C_RSVDPAGE,
730                                        sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
731         } else
732                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
733                          "Set RSVD page location to Fw FAIL!!!!!!.\n");
734 }
735
736 void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
737 {
738         u8 u1_joinbssrpt_parm[1] = { 0 };
739
740         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
741
742         rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
743 }