aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rtlwifi/rtl8188ee/fw.c')
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/fw.c830
1 files changed, 830 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
new file mode 100644
index 000000000000..57e4cc5833a9
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
@@ -0,0 +1,830 @@
1/******************************************************************************
2 *
3 * Copyright(c) 2009-2013 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 "reg.h"
34#include "def.h"
35#include "fw.h"
36
37#include <linux/kmemleak.h>
38
39static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
40{
41 struct rtl_priv *rtlpriv = rtl_priv(hw);
42 u8 tmp;
43
44 if (enable) {
45 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
46 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
47
48 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
49 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
50
51 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
52 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
53 } else {
54 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
55 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
56
57 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
58 }
59}
60
61static void _rtl88e_fw_block_write(struct ieee80211_hw *hw,
62 const u8 *buffer, u32 size)
63{
64 struct rtl_priv *rtlpriv = rtl_priv(hw);
65 u32 blk_sz = sizeof(u32);
66 u8 *buf_ptr = (u8 *)buffer;
67 u32 *pu4BytePtr = (u32 *)buffer;
68 u32 i, offset, blk_cnt, remain;
69
70 blk_cnt = size / blk_sz;
71 remain = size % blk_sz;
72
73 for (i = 0; i < blk_cnt; i++) {
74 offset = i * blk_sz;
75 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
76 *(pu4BytePtr + i));
77 }
78
79 if (remain) {
80 offset = blk_cnt * blk_sz;
81 buf_ptr += offset;
82 for (i = 0; i < remain; i++) {
83 rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
84 offset + i), *(buf_ptr + i));
85 }
86 }
87}
88
89static void _rtl88e_fw_page_write(struct ieee80211_hw *hw,
90 u32 page, const u8 *buffer, u32 size)
91{
92 struct rtl_priv *rtlpriv = rtl_priv(hw);
93 u8 value8;
94 u8 u8page = (u8) (page & 0x07);
95
96 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
97
98 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
99 _rtl88e_fw_block_write(hw, buffer, size);
100}
101
102static void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
103{
104 u32 fwlen = *pfwlen;
105 u8 remain = (u8) (fwlen % 4);
106
107 remain = (remain == 0) ? 0 : (4 - remain);
108
109 while (remain > 0) {
110 pfwbuf[fwlen] = 0;
111 fwlen++;
112 remain--;
113 }
114
115 *pfwlen = fwlen;
116}
117
118static void _rtl88e_write_fw(struct ieee80211_hw *hw,
119 enum version_8188e version, u8 *buffer, u32 size)
120{
121 struct rtl_priv *rtlpriv = rtl_priv(hw);
122 u8 *buf_ptr = (u8 *)buffer;
123 u32 page_no, remain;
124 u32 page, offset;
125
126 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
127
128 _rtl88e_fill_dummy(buf_ptr, &size);
129
130 page_no = size / FW_8192C_PAGE_SIZE;
131 remain = size % FW_8192C_PAGE_SIZE;
132
133 if (page_no > 8) {
134 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
135 "Page numbers should not greater then 8\n");
136 }
137
138 for (page = 0; page < page_no; page++) {
139 offset = page * FW_8192C_PAGE_SIZE;
140 _rtl88e_fw_page_write(hw, page, (buf_ptr + offset),
141 FW_8192C_PAGE_SIZE);
142 }
143
144 if (remain) {
145 offset = page_no * FW_8192C_PAGE_SIZE;
146 page = page_no;
147 _rtl88e_fw_page_write(hw, page, (buf_ptr + offset), remain);
148 }
149}
150
151static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
152{
153 struct rtl_priv *rtlpriv = rtl_priv(hw);
154 int err = -EIO;
155 u32 counter = 0;
156 u32 value32;
157
158 do {
159 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
160 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
161 (!(value32 & FWDL_CHKSUM_RPT)));
162
163 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
164 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
165 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
166 value32);
167 goto exit;
168 }
169
170 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
171 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
172
173 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
174 value32 |= MCUFWDL_RDY;
175 value32 &= ~WINTINI_RDY;
176 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
177
178 rtl88e_firmware_selfreset(hw);
179 counter = 0;
180
181 do {
182 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
183 if (value32 & WINTINI_RDY) {
184 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
185 "Polling FW ready success!! REG_MCUFWDL:0x%08x.\n",
186 value32);
187 err = 0;
188 goto exit;
189 }
190
191 udelay(FW_8192C_POLLING_DELAY);
192
193 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
194
195 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
196 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
197
198exit:
199 return err;
200}
201
202int rtl88e_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
203{
204 struct rtl_priv *rtlpriv = rtl_priv(hw);
205 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
206 struct rtl92c_firmware_header *pfwheader;
207 u8 *pfwdata;
208 u32 fwsize;
209 int err;
210 enum version_8188e version = rtlhal->version;
211
212 if (!rtlhal->pfirmware)
213 return 1;
214
215 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
216 pfwdata = (u8 *)rtlhal->pfirmware;
217 fwsize = rtlhal->fwsize;
218 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
219 "normal Firmware SIZE %d\n", fwsize);
220
221 if (IS_FW_HEADER_EXIST(pfwheader)) {
222 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
223 "Firmware Version(%d), Signature(%#x), Size(%d)\n",
224 pfwheader->version, pfwheader->signature,
225 (int)sizeof(struct rtl92c_firmware_header));
226
227 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
228 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
229 }
230
231 if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
232 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
233 rtl88e_firmware_selfreset(hw);
234 }
235 _rtl88e_enable_fw_download(hw, true);
236 _rtl88e_write_fw(hw, version, pfwdata, fwsize);
237 _rtl88e_enable_fw_download(hw, false);
238
239 err = _rtl88e_fw_free_to_go(hw);
240
241 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
242 "Firmware is%s ready to run!\n", err ? " not" : "");
243 return 0;
244}
245
246static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
247{
248 struct rtl_priv *rtlpriv = rtl_priv(hw);
249 u8 val_hmetfr;
250
251 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
252 if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
253 return true;
254 return false;
255}
256
257static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
258 u8 element_id, u32 cmd_len,
259 u8 *cmd_b)
260{
261 struct rtl_priv *rtlpriv = rtl_priv(hw);
262 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
263 u8 boxnum;
264 u16 box_reg = 0, box_extreg = 0;
265 u8 u1b_tmp;
266 bool isfw_read = false;
267 u8 buf_index = 0;
268 bool write_sucess = false;
269 u8 wait_h2c_limit = 100;
270 u8 wait_writeh2c_limit = 100;
271 u8 boxc[4], boxext[2];
272 u32 h2c_waitcounter = 0;
273 unsigned long flag;
274 u8 idx;
275
276 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
277
278 while (true) {
279 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
280 if (rtlhal->h2c_setinprogress) {
281 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
282 "H2C set in progress! Wait to set..element_id(%d).\n",
283 element_id);
284
285 while (rtlhal->h2c_setinprogress) {
286 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
287 flag);
288 h2c_waitcounter++;
289 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
290 "Wait 100 us (%d times)...\n",
291 h2c_waitcounter);
292 udelay(100);
293
294 if (h2c_waitcounter > 1000)
295 return;
296 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
297 flag);
298 }
299 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
300 } else {
301 rtlhal->h2c_setinprogress = true;
302 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
303 break;
304 }
305 }
306
307 while (!write_sucess) {
308 wait_writeh2c_limit--;
309 if (wait_writeh2c_limit == 0) {
310 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
311 "Write H2C fail because no trigger for FW INT!\n");
312 break;
313 }
314
315 boxnum = rtlhal->last_hmeboxnum;
316 switch (boxnum) {
317 case 0:
318 box_reg = REG_HMEBOX_0;
319 box_extreg = REG_HMEBOX_EXT_0;
320 break;
321 case 1:
322 box_reg = REG_HMEBOX_1;
323 box_extreg = REG_HMEBOX_EXT_1;
324 break;
325 case 2:
326 box_reg = REG_HMEBOX_2;
327 box_extreg = REG_HMEBOX_EXT_2;
328 break;
329 case 3:
330 box_reg = REG_HMEBOX_3;
331 box_extreg = REG_HMEBOX_EXT_3;
332 break;
333 default:
334 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
335 "switch case not processed\n");
336 break;
337 }
338
339 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
340 while (!isfw_read) {
341 wait_h2c_limit--;
342 if (wait_h2c_limit == 0) {
343 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
344 "Wating too long for FW read "
345 "clear HMEBox(%d)!\n", boxnum);
346 break;
347 }
348
349 udelay(10);
350
351 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
352 u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
353 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
354 "Wating for FW read clear HMEBox(%d)!!! "
355 "0x130 = %2x\n", boxnum, u1b_tmp);
356 }
357
358 if (!isfw_read) {
359 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
360 "Write H2C register BOX[%d] fail!!!!! "
361 "Fw do not read.\n", boxnum);
362 break;
363 }
364
365 memset(boxc, 0, sizeof(boxc));
366 memset(boxext, 0, sizeof(boxext));
367 boxc[0] = element_id;
368 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
369 "Write element_id box_reg(%4x) = %2x\n",
370 box_reg, element_id);
371
372 switch (cmd_len) {
373 case 1:
374 case 2:
375 case 3:
376 /*boxc[0] &= ~(BIT(7));*/
377 memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, cmd_len);
378
379 for (idx = 0; idx < 4; idx++)
380 rtl_write_byte(rtlpriv, box_reg+idx, boxc[idx]);
381 break;
382 case 4:
383 case 5:
384 case 6:
385 case 7:
386 /*boxc[0] |= (BIT(7));*/
387 memcpy((u8 *)(boxext), cmd_b + buf_index+3, cmd_len-3);
388 memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, 3);
389
390 for (idx = 0; idx < 2; idx++) {
391 rtl_write_byte(rtlpriv, box_extreg + idx,
392 boxext[idx]);
393 }
394
395 for (idx = 0; idx < 4; idx++) {
396 rtl_write_byte(rtlpriv, box_reg + idx,
397 boxc[idx]);
398 }
399 break;
400 default:
401 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
402 "switch case not processed\n");
403 break;
404 }
405
406 write_sucess = true;
407
408 rtlhal->last_hmeboxnum = boxnum + 1;
409 if (rtlhal->last_hmeboxnum == 4)
410 rtlhal->last_hmeboxnum = 0;
411
412 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
413 "pHalData->last_hmeboxnum = %d\n",
414 rtlhal->last_hmeboxnum);
415 }
416
417 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
418 rtlhal->h2c_setinprogress = false;
419 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
420
421 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
422}
423
424void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
425 u8 element_id, u32 cmd_len, u8 *cmd_b)
426{
427 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
428 u32 tmp_cmdbuf[2];
429
430 if (rtlhal->fw_ready == false) {
431 RT_ASSERT(false, "fail H2C cmd - Fw download fail!!!\n");
432 return;
433 }
434
435 memset(tmp_cmdbuf, 0, 8);
436 memcpy(tmp_cmdbuf, cmd_b, cmd_len);
437 _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
438
439 return;
440}
441
442void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
443{
444 u8 u1b_tmp;
445 struct rtl_priv *rtlpriv = rtl_priv(hw);
446
447 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
448 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
449 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
450 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
451 "8051Reset88E(): 8051 reset success.\n");
452}
453
454void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
455{
456 struct rtl_priv *rtlpriv = rtl_priv(hw);
457 u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
458 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
459 u8 power_state = 0;
460
461 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
462 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
463 SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, 0);
464 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
465 (rtlpriv->mac80211.p2p) ?
466 ppsc->smart_ps : 1);
467 SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
468 ppsc->reg_max_lps_awakeintvl);
469 SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
470 if (mode == FW_PS_ACTIVE_MODE)
471 power_state |= FW_PWR_STATE_ACTIVE;
472 else
473 power_state |= FW_PWR_STATE_RF_OFF;
474 SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
475
476 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
477 "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
478 u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
479 rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE, H2C_88E_PWEMODE_LENGTH,
480 u1_h2c_set_pwrmode);
481}
482
483void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
484{
485 u8 u1_joinbssrpt_parm[1] = { 0 };
486
487 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
488
489 rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
490}
491
492void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
493 u8 ap_offload_enable)
494{
495 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
496 u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
497
498 SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
499 SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
500 SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
501
502 rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD, H2C_88E_AP_OFFLOAD_LENGTH,
503 u1_apoffload_parm);
504}
505
506static bool _rtl88e_cmd_send_packet(struct ieee80211_hw *hw,
507 struct sk_buff *skb)
508{
509 struct rtl_priv *rtlpriv = rtl_priv(hw);
510 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
511 struct rtl8192_tx_ring *ring;
512 struct rtl_tx_desc *pdesc;
513 struct sk_buff *pskb = NULL;
514 unsigned long flags;
515
516 ring = &rtlpci->tx_ring[BEACON_QUEUE];
517
518 pskb = __skb_dequeue(&ring->queue);
519 if (pskb)
520 kfree_skb(pskb);
521
522 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
523
524 pdesc = &ring->desc[0];
525
526 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
527
528 __skb_queue_tail(&ring->queue, skb);
529
530 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
531
532 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
533
534 return true;
535}
536
537#define BEACON_PG 0 /* ->1 */
538#define PSPOLL_PG 2
539#define NULL_PG 3
540#define PROBERSP_PG 4 /* ->5 */
541
542#define TOTAL_RESERVED_PKT_LEN 768
543
544static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
545 /* page 0 beacon */
546 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
547 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
548 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
550 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
551 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
552 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
553 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
554 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
555 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
556 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
560 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562
563 /* page 1 beacon */
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580
581 /* page 2 ps-poll */
582 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
583 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
596 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598
599 /* page 3 null */
600 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
601 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
602 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
614 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616
617 /* page 4 probe_resp */
618 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
619 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
620 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
621 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
622 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
623 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
624 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
625 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
626 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
627 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
628 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
632 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634
635 /* page 5 probe_resp */
636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652};
653
654void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
655{
656 struct rtl_priv *rtlpriv = rtl_priv(hw);
657 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
658 struct sk_buff *skb = NULL;
659
660 u32 totalpacketlen;
661 u8 u1RsvdPageLoc[5] = { 0 };
662
663 u8 *beacon;
664 u8 *pspoll;
665 u8 *nullfunc;
666 u8 *probersp;
667 /*---------------------------------------------------------
668 * (1) beacon
669 *---------------------------------------------------------
670 */
671 beacon = &reserved_page_packet[BEACON_PG * 128];
672 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
673 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
674
675 /*-------------------------------------------------------
676 * (2) ps-poll
677 *--------------------------------------------------------
678 */
679 pspoll = &reserved_page_packet[PSPOLL_PG * 128];
680 SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
681 SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
682 SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
683
684 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
685
686 /*--------------------------------------------------------
687 * (3) null data
688 *---------------------------------------------------------
689 */
690 nullfunc = &reserved_page_packet[NULL_PG * 128];
691 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
692 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
693 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
694
695 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
696
697 /*---------------------------------------------------------
698 * (4) probe response
699 *----------------------------------------------------------
700 */
701 probersp = &reserved_page_packet[PROBERSP_PG * 128];
702 SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
703 SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
704 SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
705
706 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
707
708 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
709
710 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
711 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
712 &reserved_page_packet[0], totalpacketlen);
713 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
714 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
715 u1RsvdPageLoc, 3);
716
717 skb = dev_alloc_skb(totalpacketlen);
718 if (!skb)
719 return;
720 kmemleak_not_leak(skb);
721 memcpy(skb_put(skb, totalpacketlen),
722 &reserved_page_packet, totalpacketlen);
723
724 if (_rtl88e_cmd_send_packet(hw, skb)) {
725 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
726 "Set RSVD page location to Fw.\n");
727 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
728 "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3);
729 rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
730 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
731 } else
732 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
733 "Set RSVD page location to Fw FAIL!!!!!!.\n");
734}
735
736/*Shoud check FW support p2p or not.*/
737static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
738{
739 u8 u1_ctwindow_period[1] = {ctwindow};
740
741 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
742}
743
744void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
745{
746 struct rtl_priv *rtlpriv = rtl_priv(hw);
747 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
748 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
749 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
750 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
751 u8 i;
752 u16 ctwindow;
753 u32 start_time, tsf_low;
754
755 switch (p2p_ps_state) {
756 case P2P_PS_DISABLE:
757 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
758 memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
759 break;
760 case P2P_PS_ENABLE:
761 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
762 /* update CTWindow value. */
763 if (p2pinfo->ctwindow > 0) {
764 p2p_ps_offload->ctwindow_en = 1;
765 ctwindow = p2pinfo->ctwindow;
766 rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
767 }
768 /* hw only support 2 set of NoA */
769 for (i = 0; i < p2pinfo->noa_num; i++) {
770 /* To control the register setting for which NOA*/
771 rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
772 if (i == 0)
773 p2p_ps_offload->noa0_en = 1;
774 else
775 p2p_ps_offload->noa1_en = 1;
776
777 /* config P2P NoA Descriptor Register */
778 rtl_write_dword(rtlpriv, 0x5E0,
779 p2pinfo->noa_duration[i]);
780 rtl_write_dword(rtlpriv, 0x5E4,
781 p2pinfo->noa_interval[i]);
782
783 /*Get Current TSF value */
784 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
785
786 start_time = p2pinfo->noa_start_time[i];
787 if (p2pinfo->noa_count_type[i] != 1) {
788 while (start_time <= (tsf_low + (50 * 1024))) {
789 start_time += p2pinfo->noa_interval[i];
790 if (p2pinfo->noa_count_type[i] != 255)
791 p2pinfo->noa_count_type[i]--;
792 }
793 }
794 rtl_write_dword(rtlpriv, 0x5E8, start_time);
795 rtl_write_dword(rtlpriv, 0x5EC,
796 p2pinfo->noa_count_type[i]);
797 }
798
799 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
800 /* rst p2p circuit */
801 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
802
803 p2p_ps_offload->offload_en = 1;
804
805 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
806 p2p_ps_offload->role = 1;
807 p2p_ps_offload->allstasleep = 0;
808 } else {
809 p2p_ps_offload->role = 0;
810 }
811
812 p2p_ps_offload->discovery = 0;
813 }
814 break;
815 case P2P_PS_SCAN:
816 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
817 p2p_ps_offload->discovery = 1;
818 break;
819 case P2P_PS_SCAN_DONE:
820 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
821 p2p_ps_offload->discovery = 0;
822 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
823 break;
824 default:
825 break;
826 }
827
828 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
829 (u8 *)p2p_ps_offload);
830}