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