]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
rtlwifi: Convert to asynchronous firmware load
[mv-sheeva.git] / drivers / net / wireless / rtlwifi / rtl8192c / fw_common.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 #include "../wifi.h"
31 #include "../pci.h"
32 #include "../base.h"
33 #include "../rtl8192ce/reg.h"
34 #include "../rtl8192ce/def.h"
35 #include "fw_common.h"
36 #include <linux/export.h>
37
38 static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
39 {
40         struct rtl_priv *rtlpriv = rtl_priv(hw);
41         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
42
43         if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
44                 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
45                 if (enable)
46                         value32 |= MCUFWDL_EN;
47                 else
48                         value32 &= ~MCUFWDL_EN;
49                 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
50         } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
51                 u8 tmp;
52                 if (enable) {
53
54                         tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
55                         rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
56                                        tmp | 0x04);
57
58                         tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
59                         rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
60
61                         tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
62                         rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
63                 } else {
64
65                         tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
66                         rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
67
68                         rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
69                 }
70         }
71 }
72
73 static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer,
74                                 u32 size)
75 {
76         struct rtl_priv *rtlpriv = rtl_priv(hw);
77         u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20;
78         u8 *bufferPtr = (u8 *) buffer;
79         u32 i, offset, blockCount, remainSize;
80
81         blockCount = size / blockSize;
82         remainSize = size % blockSize;
83
84         for (i = 0; i < blockCount; i++) {
85                 offset = i * blockSize;
86                 rtlpriv->io.writeN_sync(rtlpriv,
87                                         (FW_8192C_START_ADDRESS + offset),
88                                         (void *)(bufferPtr + offset),
89                                         blockSize);
90         }
91
92         if (remainSize) {
93                 offset = blockCount * blockSize;
94                 rtlpriv->io.writeN_sync(rtlpriv,
95                                         (FW_8192C_START_ADDRESS + offset),
96                                         (void *)(bufferPtr + offset),
97                                         remainSize);
98         }
99 }
100
101 static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
102                                    const u8 *buffer, u32 size)
103 {
104         struct rtl_priv *rtlpriv = rtl_priv(hw);
105         u32 blockSize = sizeof(u32);
106         u8 *bufferPtr = (u8 *) buffer;
107         u32 *pu4BytePtr = (u32 *) buffer;
108         u32 i, offset, blockCount, remainSize;
109         u32 data;
110
111         if (rtlpriv->io.writeN_sync) {
112                 rtl_block_fw_writeN(hw, buffer, size);
113                 return;
114         }
115         blockCount = size / blockSize;
116         remainSize = size % blockSize;
117         if (remainSize) {
118                 /* the last word is < 4 bytes - pad it with zeros */
119                 for (i = 0; i < 4 - remainSize; i++)
120                         *(bufferPtr + size + i) = 0;
121                 blockCount++;
122         }
123
124         for (i = 0; i < blockCount; i++) {
125                 offset = i * blockSize;
126                 /* for big-endian platforms, the firmware data need to be byte
127                  * swapped as it was read as a byte string and will be written
128                  * as 32-bit dwords and byte swapped when written
129                  */
130                 data = le32_to_cpu(*(__le32 *)(pu4BytePtr + i));
131                 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
132                                 data);
133         }
134 }
135
136 static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
137                                   u32 page, const u8 *buffer, u32 size)
138 {
139         struct rtl_priv *rtlpriv = rtl_priv(hw);
140         u8 value8;
141         u8 u8page = (u8) (page & 0x07);
142
143         value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
144
145         rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
146         _rtl92c_fw_block_write(hw, buffer, size);
147 }
148
149 static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
150 {
151         u32 fwlen = *pfwlen;
152         u8 remain = (u8) (fwlen % 4);
153
154         remain = (remain == 0) ? 0 : (4 - remain);
155
156         while (remain > 0) {
157                 pfwbuf[fwlen] = 0;
158                 fwlen++;
159                 remain--;
160         }
161
162         *pfwlen = fwlen;
163 }
164
165 static void _rtl92c_write_fw(struct ieee80211_hw *hw,
166                              enum version_8192c version, u8 *buffer, u32 size)
167 {
168         struct rtl_priv *rtlpriv = rtl_priv(hw);
169         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
170         u8 *bufferPtr = (u8 *) buffer;
171
172         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes\n", size);
173
174         if (IS_CHIP_VER_B(version)) {
175                 u32 pageNums, remainSize;
176                 u32 page, offset;
177
178                 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
179                         _rtl92c_fill_dummy(bufferPtr, &size);
180
181                 pageNums = size / FW_8192C_PAGE_SIZE;
182                 remainSize = size % FW_8192C_PAGE_SIZE;
183
184                 if (pageNums > 4) {
185                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
186                                  "Page numbers should not greater then 4\n");
187                 }
188
189                 for (page = 0; page < pageNums; page++) {
190                         offset = page * FW_8192C_PAGE_SIZE;
191                         _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
192                                               FW_8192C_PAGE_SIZE);
193                 }
194
195                 if (remainSize) {
196                         offset = pageNums * FW_8192C_PAGE_SIZE;
197                         page = pageNums;
198                         _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
199                                               remainSize);
200                 }
201         } else {
202                 _rtl92c_fw_block_write(hw, buffer, size);
203         }
204 }
205
206 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
207 {
208         struct rtl_priv *rtlpriv = rtl_priv(hw);
209         u32 counter = 0;
210         u32 value32;
211
212         do {
213                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
214         } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
215                  (!(value32 & FWDL_ChkSum_rpt)));
216
217         if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
218                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
219                          "chksum report faill ! REG_MCUFWDL:0x%08x\n", value32);
220                 return -EIO;
221         }
222
223         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
224                  "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
225
226         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
227         value32 |= MCUFWDL_RDY;
228         value32 &= ~WINTINI_RDY;
229         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
230
231         counter = 0;
232
233         do {
234                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
235                 if (value32 & WINTINI_RDY) {
236                         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
237                                  "Polling FW ready success!! REG_MCUFWDL:0x%08x\n",
238                                  value32);
239                         return 0;
240                 }
241
242                 mdelay(FW_8192C_POLLING_DELAY);
243
244         } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
245
246         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
247                  "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", value32);
248         return -EIO;
249 }
250
251 int rtl92c_download_fw(struct ieee80211_hw *hw)
252 {
253         struct rtl_priv *rtlpriv = rtl_priv(hw);
254         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
255         struct rtl92c_firmware_header *pfwheader;
256         u8 *pfwdata;
257         u32 fwsize;
258         enum version_8192c version = rtlhal->version;
259
260         if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
261                 return 1;
262
263         pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
264         pfwdata = (u8 *) rtlhal->pfirmware;
265         fwsize = rtlhal->fwsize;
266
267         if (IS_FW_HEADER_EXIST(pfwheader)) {
268                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
269                          "Firmware Version(%d), Signature(%#x),Size(%d)\n",
270                          le16_to_cpu(pfwheader->version),
271                          le16_to_cpu(pfwheader->signature),
272                          (uint)sizeof(struct rtl92c_firmware_header));
273
274                 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
275                 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
276         }
277
278         _rtl92c_enable_fw_download(hw, true);
279         _rtl92c_write_fw(hw, version, pfwdata, fwsize);
280         _rtl92c_enable_fw_download(hw, false);
281
282         if (_rtl92c_fw_free_to_go(hw)) {
283                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
284                          "Firmware is not ready to run!\n");
285         } else {
286                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
287                          "Firmware is ready to run!\n");
288         }
289
290         return 0;
291 }
292 EXPORT_SYMBOL(rtl92c_download_fw);
293
294 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
295 {
296         struct rtl_priv *rtlpriv = rtl_priv(hw);
297         u8 val_hmetfr, val_mcutst_1;
298         bool result = false;
299
300         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
301         val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
302
303         if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
304                 result = true;
305         return result;
306 }
307
308 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
309                               u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
310 {
311         struct rtl_priv *rtlpriv = rtl_priv(hw);
312         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
313         u8 boxnum;
314         u16 box_reg = 0, box_extreg = 0;
315         u8 u1b_tmp;
316         bool isfw_read = false;
317         bool bwrite_sucess = false;
318         u8 wait_h2c_limmit = 100;
319         u8 wait_writeh2c_limmit = 100;
320         u8 boxcontent[4], boxextcontent[2];
321         u32 h2c_waitcounter = 0;
322         unsigned long flag;
323         u8 idx;
324
325         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
326
327         while (true) {
328                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
329                 if (rtlhal->h2c_setinprogress) {
330                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
331                                  "H2C set in progress! Wait to set..element_id(%d)\n",
332                                  element_id);
333
334                         while (rtlhal->h2c_setinprogress) {
335                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
336                                                        flag);
337                                 h2c_waitcounter++;
338                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
339                                          "Wait 100 us (%d times)...\n",
340                                          h2c_waitcounter);
341                                 udelay(100);
342
343                                 if (h2c_waitcounter > 1000)
344                                         return;
345                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
346                                                   flag);
347                         }
348                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
349                 } else {
350                         rtlhal->h2c_setinprogress = true;
351                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
352                         break;
353                 }
354         }
355
356         while (!bwrite_sucess) {
357                 wait_writeh2c_limmit--;
358                 if (wait_writeh2c_limmit == 0) {
359                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
360                                  "Write H2C fail because no trigger for FW INT!\n");
361                         break;
362                 }
363
364                 boxnum = rtlhal->last_hmeboxnum;
365                 switch (boxnum) {
366                 case 0:
367                         box_reg = REG_HMEBOX_0;
368                         box_extreg = REG_HMEBOX_EXT_0;
369                         break;
370                 case 1:
371                         box_reg = REG_HMEBOX_1;
372                         box_extreg = REG_HMEBOX_EXT_1;
373                         break;
374                 case 2:
375                         box_reg = REG_HMEBOX_2;
376                         box_extreg = REG_HMEBOX_EXT_2;
377                         break;
378                 case 3:
379                         box_reg = REG_HMEBOX_3;
380                         box_extreg = REG_HMEBOX_EXT_3;
381                         break;
382                 default:
383                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
384                                  "switch case not processed\n");
385                         break;
386                 }
387
388                 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
389                 while (!isfw_read) {
390
391                         wait_h2c_limmit--;
392                         if (wait_h2c_limmit == 0) {
393                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
394                                          "Waiting too long for FW read clear HMEBox(%d)!\n",
395                                          boxnum);
396                                 break;
397                         }
398
399                         udelay(10);
400
401                         isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
402                         u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
403                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
404                                  "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
405                                  boxnum, u1b_tmp);
406                 }
407
408                 if (!isfw_read) {
409                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
410                                  "Write H2C register BOX[%d] fail!!!!! Fw do not read\n",
411                                  boxnum);
412                         break;
413                 }
414
415                 memset(boxcontent, 0, sizeof(boxcontent));
416                 memset(boxextcontent, 0, sizeof(boxextcontent));
417                 boxcontent[0] = element_id;
418                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
419                          "Write element_id box_reg(%4x) = %2x\n",
420                          box_reg, element_id);
421
422                 switch (cmd_len) {
423                 case 1:
424                         boxcontent[0] &= ~(BIT(7));
425                         memcpy((u8 *) (boxcontent) + 1,
426                                p_cmdbuffer, 1);
427
428                         for (idx = 0; idx < 4; idx++) {
429                                 rtl_write_byte(rtlpriv, box_reg + idx,
430                                                boxcontent[idx]);
431                         }
432                         break;
433                 case 2:
434                         boxcontent[0] &= ~(BIT(7));
435                         memcpy((u8 *) (boxcontent) + 1,
436                                p_cmdbuffer, 2);
437
438                         for (idx = 0; idx < 4; idx++) {
439                                 rtl_write_byte(rtlpriv, box_reg + idx,
440                                                boxcontent[idx]);
441                         }
442                         break;
443                 case 3:
444                         boxcontent[0] &= ~(BIT(7));
445                         memcpy((u8 *) (boxcontent) + 1,
446                                p_cmdbuffer, 3);
447
448                         for (idx = 0; idx < 4; idx++) {
449                                 rtl_write_byte(rtlpriv, box_reg + idx,
450                                                boxcontent[idx]);
451                         }
452                         break;
453                 case 4:
454                         boxcontent[0] |= (BIT(7));
455                         memcpy((u8 *) (boxextcontent),
456                                p_cmdbuffer, 2);
457                         memcpy((u8 *) (boxcontent) + 1,
458                                p_cmdbuffer + 2, 2);
459
460                         for (idx = 0; idx < 2; idx++) {
461                                 rtl_write_byte(rtlpriv, box_extreg + idx,
462                                                boxextcontent[idx]);
463                         }
464
465                         for (idx = 0; idx < 4; idx++) {
466                                 rtl_write_byte(rtlpriv, box_reg + idx,
467                                                boxcontent[idx]);
468                         }
469                         break;
470                 case 5:
471                         boxcontent[0] |= (BIT(7));
472                         memcpy((u8 *) (boxextcontent),
473                                p_cmdbuffer, 2);
474                         memcpy((u8 *) (boxcontent) + 1,
475                                p_cmdbuffer + 2, 3);
476
477                         for (idx = 0; idx < 2; idx++) {
478                                 rtl_write_byte(rtlpriv, box_extreg + idx,
479                                                boxextcontent[idx]);
480                         }
481
482                         for (idx = 0; idx < 4; idx++) {
483                                 rtl_write_byte(rtlpriv, box_reg + idx,
484                                                boxcontent[idx]);
485                         }
486                         break;
487                 default:
488                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
489                                  "switch case not processed\n");
490                         break;
491                 }
492
493                 bwrite_sucess = true;
494
495                 rtlhal->last_hmeboxnum = boxnum + 1;
496                 if (rtlhal->last_hmeboxnum == 4)
497                         rtlhal->last_hmeboxnum = 0;
498
499                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
500                          "pHalData->last_hmeboxnum  = %d\n",
501                          rtlhal->last_hmeboxnum);
502         }
503
504         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
505         rtlhal->h2c_setinprogress = false;
506         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
507
508         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
509 }
510
511 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
512                          u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
513 {
514         u32 tmp_cmdbuf[2];
515
516         memset(tmp_cmdbuf, 0, 8);
517         memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
518         _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
519
520         return;
521 }
522 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
523
524 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
525 {
526         u8 u1b_tmp;
527         u8 delay = 100;
528         struct rtl_priv *rtlpriv = rtl_priv(hw);
529
530         rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
531         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
532
533         while (u1b_tmp & BIT(2)) {
534                 delay--;
535                 if (delay == 0) {
536                         RT_ASSERT(false, "8051 reset fail\n");
537                         break;
538                 }
539                 udelay(50);
540                 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
541         }
542 }
543 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
544
545 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
546 {
547         struct rtl_priv *rtlpriv = rtl_priv(hw);
548         u8 u1_h2c_set_pwrmode[3] = {0};
549         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
550
551         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
552
553         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
554         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
555         SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
556                                               ppsc->reg_max_lps_awakeintvl);
557
558         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
559                       "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
560                       u1_h2c_set_pwrmode, 3);
561         rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
562
563 }
564 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
565
566 static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
567                                 struct sk_buff *skb)
568 {
569         struct rtl_priv *rtlpriv = rtl_priv(hw);
570         struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
571         struct rtl8192_tx_ring *ring;
572         struct rtl_tx_desc *pdesc;
573         unsigned long flags;
574         struct sk_buff *pskb = NULL;
575
576         ring = &rtlpci->tx_ring[BEACON_QUEUE];
577
578         pskb = __skb_dequeue(&ring->queue);
579         if (pskb)
580                 kfree_skb(pskb);
581
582         spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
583
584         pdesc = &ring->desc[0];
585
586         rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
587
588         __skb_queue_tail(&ring->queue, skb);
589
590         spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
591
592         rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
593
594         return true;
595 }
596
597 #define BEACON_PG               0 /*->1*/
598 #define PSPOLL_PG               2
599 #define NULL_PG                 3
600 #define PROBERSP_PG             4 /*->5*/
601
602 #define TOTAL_RESERVED_PKT_LEN  768
603
604 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
605         /* page 0 beacon */
606         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
607         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
608         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
609         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
611         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
612         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
613         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
614         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
615         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
616         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
620         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622
623         /* page 1 beacon */
624         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625         0x00, 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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
637         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640
641         /* page 2  ps-poll */
642         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
643         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
655         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
656         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
657         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658
659         /* page 3  null */
660         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
661         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
662         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
663         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
673         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
674         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676
677         /* page 4  probe_resp */
678         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
679         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
680         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
681         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
682         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
683         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
684         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
685         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
686         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
687         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
688         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
692         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694
695         /* page 5  probe_resp */
696         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
697         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
710         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712 };
713
714 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
715 {
716         struct rtl_priv *rtlpriv = rtl_priv(hw);
717         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
718         struct sk_buff *skb = NULL;
719
720         u32 totalpacketlen;
721         bool rtstatus;
722         u8 u1RsvdPageLoc[3] = {0};
723         bool dlok = false;
724
725         u8 *beacon;
726         u8 *pspoll;
727         u8 *nullfunc;
728         u8 *probersp;
729         /*---------------------------------------------------------
730                                 (1) beacon
731         ---------------------------------------------------------*/
732         beacon = &reserved_page_packet[BEACON_PG * 128];
733         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
734         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
735
736         /*-------------------------------------------------------
737                                 (2) ps-poll
738         --------------------------------------------------------*/
739         pspoll = &reserved_page_packet[PSPOLL_PG * 128];
740         SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
741         SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
742         SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
743
744         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
745
746         /*--------------------------------------------------------
747                                 (3) null data
748         ---------------------------------------------------------*/
749         nullfunc = &reserved_page_packet[NULL_PG * 128];
750         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
751         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
752         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
753
754         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
755
756         /*---------------------------------------------------------
757                                 (4) probe response
758         ----------------------------------------------------------*/
759         probersp = &reserved_page_packet[PROBERSP_PG * 128];
760         SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
761         SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
762         SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
763
764         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
765
766         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
767
768         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
769                       "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
770                       &reserved_page_packet[0], totalpacketlen);
771         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
772                       "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
773                       u1RsvdPageLoc, 3);
774
775
776         skb = dev_alloc_skb(totalpacketlen);
777         if (!skb)
778                 return;
779         memcpy((u8 *) skb_put(skb, totalpacketlen),
780                &reserved_page_packet, totalpacketlen);
781
782         rtstatus = _rtl92c_cmd_send_packet(hw, skb);
783
784         if (rtstatus)
785                 dlok = true;
786
787         if (dlok) {
788                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
789                          "Set RSVD page location to Fw\n");
790                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
791                               "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
792                 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
793                                     sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
794         } else
795                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
796                          "Set RSVD page location to Fw FAIL!!!!!!\n");
797 }
798 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
799
800 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
801 {
802         u8 u1_joinbssrpt_parm[1] = {0};
803
804         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
805
806         rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
807 }
808 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);