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