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
_rtl92c_enable_fw_download(struct ieee80211_hw * hw,bool enable)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
rtl_block_fw_writeN(struct ieee80211_hw * hw,const u8 * buffer,u32 size)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
_rtl92c_fw_block_write(struct ieee80211_hw * hw,const u8 * buffer,u32 size)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
_rtl92c_fw_page_write(struct ieee80211_hw * hw,u32 page,const u8 * buffer,u32 size)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
_rtl92c_fill_dummy(u8 * pfwbuf,u32 * pfwlen)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
_rtl92c_write_fw(struct ieee80211_hw * hw,enum version_8192c version,u8 * buffer,u32 size)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
_rtl92c_fw_free_to_go(struct ieee80211_hw * hw)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
rtl92c_download_fw(struct ieee80211_hw * hw)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
_rtl92c_check_fw_read_last_h2c(struct ieee80211_hw * hw,u8 boxnum)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
_rtl92c_fill_h2c_command(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * p_cmdbuffer)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
rtl92c_fill_h2c_cmd(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * p_cmdbuffer)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
rtl92c_firmware_selfreset(struct ieee80211_hw * hw)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
rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw * hw,u8 mode)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
_rtl92c_cmd_send_packet(struct ieee80211_hw * hw,struct sk_buff * skb)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
rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw * hw,bool dl_finished)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
rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw * hw,u8 mstatus)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);
809