Merge branch 'linus' into perf/core
[deliverable/linux.git] / drivers / net / wireless / rtlwifi / rtl8192c / fw_common.c
CommitLineData
0c817338
LF
1/******************************************************************************
2 *
fc616856 3 * Copyright(c) 2009-2012 Realtek Corporation.
0c817338
LF
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
0c817338
LF
30#include "../wifi.h"
31#include "../pci.h"
32#include "../base.h"
1472d3a8
LF
33#include "../rtl8192ce/reg.h"
34#include "../rtl8192ce/def.h"
35#include "fw_common.h"
d273bb20 36#include <linux/export.h>
f11bbfd8 37#include <linux/kmemleak.h>
0c817338
LF
38
39static 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
ff6ff96b
LF
74static 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
0c817338
LF
102static 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;
abfabc9b 110 u32 data;
0c817338 111
ff6ff96b
LF
112 if (rtlpriv->io.writeN_sync) {
113 rtl_block_fw_writeN(hw, buffer, size);
114 return;
115 }
0c817338
LF
116 blockCount = size / blockSize;
117 remainSize = size % blockSize;
abfabc9b
LF
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 }
0c817338
LF
124
125 for (i = 0; i < blockCount; i++) {
126 offset = i * blockSize;
abfabc9b
LF
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));
0c817338 132 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
abfabc9b 133 data);
0c817338
LF
134 }
135}
136
137static 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
150static 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
166static 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));
2c208890 171 u8 *bufferPtr = buffer;
0c817338 172
f30d7507 173 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes\n", size);
0c817338 174
25b2bc30 175 if (IS_CHIP_VER_B(version)) {
0c817338
LF
176 u32 pageNums, remainSize;
177 u32 page, offset;
178
25b2bc30 179 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
0c817338
LF
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,
f30d7507 187 "Page numbers should not greater then 4\n");
0c817338
LF
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
207static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
208{
209 struct rtl_priv *rtlpriv = rtl_priv(hw);
0c817338
LF
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,
f30d7507 220 "chksum report faill ! REG_MCUFWDL:0x%08x\n", value32);
32473284 221 return -EIO;
0c817338
LF
222 }
223
224 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
f30d7507 225 "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
0c817338
LF
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,
f30d7507
JP
238 "Polling FW ready success!! REG_MCUFWDL:0x%08x\n",
239 value32);
32473284 240 return 0;
0c817338
LF
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,
f30d7507 248 "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", value32);
32473284 249 return -EIO;
0c817338
LF
250}
251
252int 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;
0c817338
LF
259 enum version_8192c version = rtlhal->version;
260
b0302aba 261 if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
0c817338 262 return 1;
0c817338
LF
263
264 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
2c208890 265 pfwdata = rtlhal->pfirmware;
3ac5e26a 266 fwsize = rtlhal->fwsize;
0c817338
LF
267
268 if (IS_FW_HEADER_EXIST(pfwheader)) {
269 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
f30d7507 270 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
abfabc9b
LF
271 le16_to_cpu(pfwheader->version),
272 le16_to_cpu(pfwheader->signature),
f30d7507 273 (uint)sizeof(struct rtl92c_firmware_header));
0c817338
LF
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
32473284 283 if (_rtl92c_fw_free_to_go(hw)) {
0c817338 284 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
f30d7507 285 "Firmware is not ready to run!\n");
0c817338
LF
286 } else {
287 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
f30d7507 288 "Firmware is ready to run!\n");
0c817338
LF
289 }
290
291 return 0;
292}
1472d3a8 293EXPORT_SYMBOL(rtl92c_download_fw);
0c817338
LF
294
295static 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
309static 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;
9f219bd2 315 u16 box_reg = 0, box_extreg = 0;
0c817338
LF
316 u8 u1b_tmp;
317 bool isfw_read = false;
4907cb7b 318 bool bwrite_success = false;
0c817338
LF
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
f30d7507 326 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
0c817338
LF
327
328 while (true) {
329 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
7ea47240 330 if (rtlhal->h2c_setinprogress) {
0c817338 331 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
f30d7507
JP
332 "H2C set in progress! Wait to set..element_id(%d)\n",
333 element_id);
0c817338 334
7ea47240 335 while (rtlhal->h2c_setinprogress) {
0c817338
LF
336 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
337 flag);
338 h2c_waitcounter++;
339 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
f30d7507
JP
340 "Wait 100 us (%d times)...\n",
341 h2c_waitcounter);
0c817338
LF
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 {
7ea47240 351 rtlhal->h2c_setinprogress = true;
0c817338
LF
352 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
353 break;
354 }
355 }
356
4907cb7b 357 while (!bwrite_success) {
0c817338
LF
358 wait_writeh2c_limmit--;
359 if (wait_writeh2c_limmit == 0) {
360 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
f30d7507 361 "Write H2C fail because no trigger for FW INT!\n");
0c817338
LF
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,
f30d7507 385 "switch case not processed\n");
0c817338
LF
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,
f30d7507
JP
395 "Waiting too long for FW read clear HMEBox(%d)!\n",
396 boxnum);
0c817338
LF
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,
f30d7507
JP
405 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
406 boxnum, u1b_tmp);
0c817338
LF
407 }
408
409 if (!isfw_read) {
410 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
f30d7507
JP
411 "Write H2C register BOX[%d] fail!!!!! Fw do not read\n",
412 boxnum);
0c817338
LF
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,
f30d7507
JP
420 "Write element_id box_reg(%4x) = %2x\n",
421 box_reg, element_id);
0c817338
LF
422
423 switch (cmd_len) {
424 case 1:
425 boxcontent[0] &= ~(BIT(7));
426 memcpy((u8 *) (boxcontent) + 1,
32473284 427 p_cmdbuffer, 1);
0c817338
LF
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,
32473284 437 p_cmdbuffer, 2);
0c817338
LF
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,
32473284 447 p_cmdbuffer, 3);
0c817338
LF
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),
32473284 457 p_cmdbuffer, 2);
0c817338 458 memcpy((u8 *) (boxcontent) + 1,
32473284 459 p_cmdbuffer + 2, 2);
0c817338
LF
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),
32473284 474 p_cmdbuffer, 2);
0c817338 475 memcpy((u8 *) (boxcontent) + 1,
32473284 476 p_cmdbuffer + 2, 3);
0c817338
LF
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,
f30d7507 490 "switch case not processed\n");
0c817338
LF
491 break;
492 }
493
4907cb7b 494 bwrite_success = true;
0c817338
LF
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,
f30d7507
JP
501 "pHalData->last_hmeboxnum = %d\n",
502 rtlhal->last_hmeboxnum);
0c817338
LF
503 }
504
505 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
7ea47240 506 rtlhal->h2c_setinprogress = false;
0c817338
LF
507 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
508
f30d7507 509 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
0c817338
LF
510}
511
512void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
513 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
514{
0c817338
LF
515 u32 tmp_cmdbuf[2];
516
0c817338
LF
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}
1472d3a8 523EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
0c817338
LF
524
525void 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) {
9d833ed7 537 RT_ASSERT(false, "8051 reset fail\n");
0c817338
LF
538 break;
539 }
540 udelay(50);
541 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
542 }
543}
1472d3a8 544EXPORT_SYMBOL(rtl92c_firmware_selfreset);
0c817338
LF
545
546void 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
f30d7507 552 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
0c817338
LF
553
554 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
3a16b412
LF
555 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
556 (rtlpriv->mac80211.p2p) ?
557 ppsc->smart_ps : 1);
0c817338
LF
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,
af08687b 562 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
0c817338
LF
563 u1_h2c_set_pwrmode, 3);
564 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
565
566}
1472d3a8 567EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
0c817338 568
3ac5e26a
C
569static 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;
3ac5e26a
C
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);
6babc283 582 kfree_skb(pskb);
3ac5e26a
C
583
584 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
585
586 pdesc = &ring->desc[0];
3ac5e26a
C
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
0c817338
LF
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
606static 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
3ac5e26a 716void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
0c817338
LF
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};
3ac5e26a 725 bool dlok = false;
0c817338
LF
726
727 u8 *beacon;
3ac5e26a 728 u8 *pspoll;
0c817338 729 u8 *nullfunc;
3ac5e26a 730 u8 *probersp;
0c817338
LF
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 --------------------------------------------------------*/
3ac5e26a
C
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);
0c817338
LF
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 ----------------------------------------------------------*/
3ac5e26a
C
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);
0c817338
LF
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,
af08687b 771 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
0c817338
LF
772 &reserved_page_packet[0], totalpacketlen);
773 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
af08687b 774 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
0c817338
LF
775 u1RsvdPageLoc, 3);
776
777
778 skb = dev_alloc_skb(totalpacketlen);
76a92be5
LF
779 if (!skb)
780 return;
f11bbfd8
LF
781 kmemleak_not_leak(skb);
782
0c817338
LF
783 memcpy((u8 *) skb_put(skb, totalpacketlen),
784 &reserved_page_packet, totalpacketlen);
785
3ac5e26a 786 rtstatus = _rtl92c_cmd_send_packet(hw, skb);
0c817338
LF
787
788 if (rtstatus)
3ac5e26a 789 dlok = true;
0c817338 790
3ac5e26a 791 if (dlok) {
0c817338 792 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
f30d7507 793 "Set RSVD page location to Fw\n");
0c817338 794 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
af08687b 795 "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
0c817338
LF
796 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
797 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
798 } else
799 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
f30d7507 800 "Set RSVD page location to Fw FAIL!!!!!!\n");
0c817338 801}
1472d3a8 802EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
0c817338
LF
803
804void 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}
1472d3a8 812EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
3a16b412
LF
813
814static 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
821void 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}
907EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);
This page took 0.405919 seconds and 5 git commands to generate.