cris: add arch/cris/include/asm/serial.h
[linux-2.6/next.git] / drivers / net / wireless / rtlwifi / rtl8192de / fw.c
blob82f060bdbc0b7fa8b22b14b96c8b478c977758ee
1 /******************************************************************************
3 * Copyright(c) 2009-2010 Realtek Corporation.
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.
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.
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
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
21 * Contact Information:
22 * wlanfae <wlanfae@realtek.com>
23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24 * Hsinchu 300, Taiwan.
26 * Larry Finger <Larry.Finger@lwfinger.net>
28 *****************************************************************************/
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 #include "sw.h"
38 static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)
40 return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ?
41 true : false;
44 static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)
46 struct rtl_priv *rtlpriv = rtl_priv(hw);
47 u8 tmp;
49 if (enable) {
50 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
51 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
52 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
53 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
54 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
55 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
56 } else {
57 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
58 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
59 /* Reserved for fw extension.
60 * 0x81[7] is used for mac0 status ,
61 * so don't write this reg here
62 * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);*/
66 static void _rtl92d_fw_block_write(struct ieee80211_hw *hw,
67 const u8 *buffer, u32 size)
69 struct rtl_priv *rtlpriv = rtl_priv(hw);
70 u32 blocksize = sizeof(u32);
71 u8 *bufferptr = (u8 *) buffer;
72 u32 *pu4BytePtr = (u32 *) buffer;
73 u32 i, offset, blockCount, remainSize;
75 blockCount = size / blocksize;
76 remainSize = size % blocksize;
77 for (i = 0; i < blockCount; i++) {
78 offset = i * blocksize;
79 rtl_write_dword(rtlpriv, (FW_8192D_START_ADDRESS + offset),
80 *(pu4BytePtr + i));
82 if (remainSize) {
83 offset = blockCount * blocksize;
84 bufferptr += offset;
85 for (i = 0; i < remainSize; i++) {
86 rtl_write_byte(rtlpriv, (FW_8192D_START_ADDRESS +
87 offset + i), *(bufferptr + i));
92 static void _rtl92d_fw_page_write(struct ieee80211_hw *hw,
93 u32 page, const u8 *buffer, u32 size)
95 struct rtl_priv *rtlpriv = rtl_priv(hw);
96 u8 value8;
97 u8 u8page = (u8) (page & 0x07);
99 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
100 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
101 _rtl92d_fw_block_write(hw, buffer, size);
104 static void _rtl92d_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
106 u32 fwlen = *pfwlen;
107 u8 remain = (u8) (fwlen % 4);
109 remain = (remain == 0) ? 0 : (4 - remain);
110 while (remain > 0) {
111 pfwbuf[fwlen] = 0;
112 fwlen++;
113 remain--;
115 *pfwlen = fwlen;
118 static void _rtl92d_write_fw(struct ieee80211_hw *hw,
119 enum version_8192d version, u8 *buffer, u32 size)
121 struct rtl_priv *rtlpriv = rtl_priv(hw);
122 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
123 u8 *bufferPtr = (u8 *) buffer;
124 u32 pagenums, remainSize;
125 u32 page, offset;
127 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
128 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE)
129 _rtl92d_fill_dummy(bufferPtr, &size);
130 pagenums = size / FW_8192D_PAGE_SIZE;
131 remainSize = size % FW_8192D_PAGE_SIZE;
132 if (pagenums > 8) {
133 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
134 ("Page numbers should not greater then 8\n"));
136 for (page = 0; page < pagenums; page++) {
137 offset = page * FW_8192D_PAGE_SIZE;
138 _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
139 FW_8192D_PAGE_SIZE);
141 if (remainSize) {
142 offset = pagenums * FW_8192D_PAGE_SIZE;
143 page = pagenums;
144 _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
145 remainSize);
149 static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
151 struct rtl_priv *rtlpriv = rtl_priv(hw);
152 u32 counter = 0;
153 u32 value32;
155 do {
156 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
157 } while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) &&
158 (!(value32 & FWDL_ChkSum_rpt)));
159 if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) {
160 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
161 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
162 value32));
163 return -EIO;
165 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
166 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
167 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
168 value32 |= MCUFWDL_RDY;
169 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
170 return 0;
173 void rtl92d_firmware_selfreset(struct ieee80211_hw *hw)
175 struct rtl_priv *rtlpriv = rtl_priv(hw);
176 u8 u1b_tmp;
177 u8 delay = 100;
179 /* Set (REG_HMETFR + 3) to 0x20 is reset 8051 */
180 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
181 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
182 while (u1b_tmp & BIT(2)) {
183 delay--;
184 if (delay == 0)
185 break;
186 udelay(50);
187 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
189 RT_ASSERT((delay > 0), ("8051 reset failed!\n"));
190 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
191 ("=====> 8051 reset success (%d) .\n", delay));
194 static int _rtl92d_fw_init(struct ieee80211_hw *hw)
196 struct rtl_priv *rtlpriv = rtl_priv(hw);
197 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
198 u32 counter;
200 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, ("FW already have download\n"));
201 /* polling for FW ready */
202 counter = 0;
203 do {
204 if (rtlhal->interfaceindex == 0) {
205 if (rtl_read_byte(rtlpriv, FW_MAC0_READY) &
206 MAC0_READY) {
207 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
208 ("Polling FW ready success!! "
209 "REG_MCUFWDL: 0x%x .\n",
210 rtl_read_byte(rtlpriv,
211 FW_MAC0_READY)));
212 return 0;
214 udelay(5);
215 } else {
216 if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
217 MAC1_READY) {
218 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
219 ("Polling FW ready success!! "
220 "REG_MCUFWDL: 0x%x .\n",
221 rtl_read_byte(rtlpriv,
222 FW_MAC1_READY)));
223 return 0;
225 udelay(5);
227 } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
229 if (rtlhal->interfaceindex == 0) {
230 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
231 ("Polling FW ready fail!! MAC0 FW init not ready: "
232 "0x%x .\n",
233 rtl_read_byte(rtlpriv, FW_MAC0_READY)));
234 } else {
235 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
236 ("Polling FW ready fail!! MAC1 FW init not ready: "
237 "0x%x .\n",
238 rtl_read_byte(rtlpriv, FW_MAC1_READY)));
240 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
241 ("Polling FW ready fail!! REG_MCUFWDL:0x%08ul .\n",
242 rtl_read_dword(rtlpriv, REG_MCUFWDL)));
243 return -1;
246 int rtl92d_download_fw(struct ieee80211_hw *hw)
248 struct rtl_priv *rtlpriv = rtl_priv(hw);
249 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
250 u8 *pfwheader;
251 u8 *pfwdata;
252 u32 fwsize;
253 int err;
254 enum version_8192d version = rtlhal->version;
255 u8 value;
256 u32 count;
257 bool fw_downloaded = false, fwdl_in_process = false;
258 unsigned long flags;
260 if (!rtlhal->pfirmware)
261 return 1;
262 fwsize = rtlhal->fwsize;
263 pfwheader = (u8 *) rtlhal->pfirmware;
264 pfwdata = (u8 *) rtlhal->pfirmware;
265 rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
266 rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
267 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, (" FirmwareVersion(%d),"
268 "FirmwareSubVersion(%d), Signature(%#x)\n",
269 rtlhal->fw_version, rtlhal->fw_subversion,
270 GET_FIRMWARE_HDR_SIGNATURE(pfwheader)));
271 if (IS_FW_HEADER_EXIST(pfwheader)) {
272 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
273 ("Shift 32 bytes for FW header!!\n"));
274 pfwdata = pfwdata + 32;
275 fwsize = fwsize - 32;
278 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
279 fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
280 if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
281 fwdl_in_process = true;
282 else
283 fwdl_in_process = false;
284 if (fw_downloaded) {
285 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
286 goto exit;
287 } else if (fwdl_in_process) {
288 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
289 for (count = 0; count < 5000; count++) {
290 udelay(500);
291 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
292 fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
293 if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
294 fwdl_in_process = true;
295 else
296 fwdl_in_process = false;
297 spin_unlock_irqrestore(&globalmutex_for_fwdownload,
298 flags);
299 if (fw_downloaded)
300 goto exit;
301 else if (!fwdl_in_process)
302 break;
303 else
304 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
305 ("Wait for another mac "
306 "download fw\n"));
308 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
309 value = rtl_read_byte(rtlpriv, 0x1f);
310 value |= BIT(5);
311 rtl_write_byte(rtlpriv, 0x1f, value);
312 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
313 } else {
314 value = rtl_read_byte(rtlpriv, 0x1f);
315 value |= BIT(5);
316 rtl_write_byte(rtlpriv, 0x1f, value);
317 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
320 /* If 8051 is running in RAM code, driver should
321 * inform Fw to reset by itself, or it will cause
322 * download Fw fail.*/
323 /* 8051 RAM code */
324 if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
325 rtl92d_firmware_selfreset(hw);
326 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
328 _rtl92d_enable_fw_download(hw, true);
329 _rtl92d_write_fw(hw, version, pfwdata, fwsize);
330 _rtl92d_enable_fw_download(hw, false);
331 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
332 err = _rtl92d_fw_free_to_go(hw);
333 /* download fw over,clear 0x1f[5] */
334 value = rtl_read_byte(rtlpriv, 0x1f);
335 value &= (~BIT(5));
336 rtl_write_byte(rtlpriv, 0x1f, value);
337 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
338 if (err) {
339 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
340 ("fw is not ready to run!\n"));
341 goto exit;
342 } else {
343 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
344 ("fw is ready to run!\n"));
346 exit:
347 err = _rtl92d_fw_init(hw);
348 return err;
351 static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
353 struct rtl_priv *rtlpriv = rtl_priv(hw);
354 u8 val_hmetfr;
355 bool result = false;
357 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
358 if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
359 result = true;
360 return result;
363 static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
364 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
366 struct rtl_priv *rtlpriv = rtl_priv(hw);
367 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
368 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
369 u8 boxnum;
370 u16 box_reg = 0, box_extreg = 0;
371 u8 u1b_tmp;
372 bool isfw_read = false;
373 u8 buf_index = 0;
374 bool bwrite_sucess = false;
375 u8 wait_h2c_limmit = 100;
376 u8 wait_writeh2c_limmit = 100;
377 u8 boxcontent[4], boxextcontent[2];
378 u32 h2c_waitcounter = 0;
379 unsigned long flag;
380 u8 idx;
382 if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
383 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
384 ("Return as RF is off!!!\n"));
385 return;
387 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
388 while (true) {
389 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
390 if (rtlhal->h2c_setinprogress) {
391 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
392 ("H2C set in progress! Wait to set.."
393 "element_id(%d).\n", element_id));
395 while (rtlhal->h2c_setinprogress) {
396 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
397 flag);
398 h2c_waitcounter++;
399 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
400 ("Wait 100 us (%d times)...\n",
401 h2c_waitcounter));
402 udelay(100);
404 if (h2c_waitcounter > 1000)
405 return;
407 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
408 flag);
410 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
411 } else {
412 rtlhal->h2c_setinprogress = true;
413 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
414 break;
417 while (!bwrite_sucess) {
418 wait_writeh2c_limmit--;
419 if (wait_writeh2c_limmit == 0) {
420 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
421 ("Write H2C fail because no trigger "
422 "for FW INT!\n"));
423 break;
425 boxnum = rtlhal->last_hmeboxnum;
426 switch (boxnum) {
427 case 0:
428 box_reg = REG_HMEBOX_0;
429 box_extreg = REG_HMEBOX_EXT_0;
430 break;
431 case 1:
432 box_reg = REG_HMEBOX_1;
433 box_extreg = REG_HMEBOX_EXT_1;
434 break;
435 case 2:
436 box_reg = REG_HMEBOX_2;
437 box_extreg = REG_HMEBOX_EXT_2;
438 break;
439 case 3:
440 box_reg = REG_HMEBOX_3;
441 box_extreg = REG_HMEBOX_EXT_3;
442 break;
443 default:
444 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
445 ("switch case not process\n"));
446 break;
448 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
449 while (!isfw_read) {
450 wait_h2c_limmit--;
451 if (wait_h2c_limmit == 0) {
452 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
453 ("Wating too long for FW read "
454 "clear HMEBox(%d)!\n", boxnum));
455 break;
457 udelay(10);
458 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
459 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
460 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
461 ("Wating for FW read clear HMEBox(%d)!!! "
462 "0x1BF = %2x\n", boxnum, u1b_tmp));
464 if (!isfw_read) {
465 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
466 ("Write H2C register BOX[%d] fail!!!!! "
467 "Fw do not read.\n", boxnum));
468 break;
470 memset(boxcontent, 0, sizeof(boxcontent));
471 memset(boxextcontent, 0, sizeof(boxextcontent));
472 boxcontent[0] = element_id;
473 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
474 ("Write element_id box_reg(%4x) = %2x\n",
475 box_reg, element_id));
476 switch (cmd_len) {
477 case 1:
478 boxcontent[0] &= ~(BIT(7));
479 memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
480 for (idx = 0; idx < 4; idx++)
481 rtl_write_byte(rtlpriv, box_reg + idx,
482 boxcontent[idx]);
483 break;
484 case 2:
485 boxcontent[0] &= ~(BIT(7));
486 memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
487 for (idx = 0; idx < 4; idx++)
488 rtl_write_byte(rtlpriv, box_reg + idx,
489 boxcontent[idx]);
490 break;
491 case 3:
492 boxcontent[0] &= ~(BIT(7));
493 memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
494 for (idx = 0; idx < 4; idx++)
495 rtl_write_byte(rtlpriv, box_reg + idx,
496 boxcontent[idx]);
497 break;
498 case 4:
499 boxcontent[0] |= (BIT(7));
500 memcpy(boxextcontent, cmdbuffer + buf_index, 2);
501 memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
502 for (idx = 0; idx < 2; idx++)
503 rtl_write_byte(rtlpriv, box_extreg + idx,
504 boxextcontent[idx]);
505 for (idx = 0; idx < 4; idx++)
506 rtl_write_byte(rtlpriv, box_reg + idx,
507 boxcontent[idx]);
508 break;
509 case 5:
510 boxcontent[0] |= (BIT(7));
511 memcpy(boxextcontent, cmdbuffer + buf_index, 2);
512 memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
513 for (idx = 0; idx < 2; idx++)
514 rtl_write_byte(rtlpriv, box_extreg + idx,
515 boxextcontent[idx]);
516 for (idx = 0; idx < 4; idx++)
517 rtl_write_byte(rtlpriv, box_reg + idx,
518 boxcontent[idx]);
519 break;
520 default:
521 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
522 ("switch case not process\n"));
523 break;
525 bwrite_sucess = true;
526 rtlhal->last_hmeboxnum = boxnum + 1;
527 if (rtlhal->last_hmeboxnum == 4)
528 rtlhal->last_hmeboxnum = 0;
529 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
530 ("pHalData->last_hmeboxnum = %d\n",
531 rtlhal->last_hmeboxnum));
533 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
534 rtlhal->h2c_setinprogress = false;
535 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
536 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
539 void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
540 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
542 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
543 u32 tmp_cmdbuf[2];
545 if (rtlhal->fw_ready == false) {
546 RT_ASSERT(false, ("return H2C cmd because of Fw "
547 "download fail!!!\n"));
548 return;
550 memset(tmp_cmdbuf, 0, 8);
551 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
552 _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
553 return;
556 void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
558 struct rtl_priv *rtlpriv = rtl_priv(hw);
559 u8 u1_h2c_set_pwrmode[3] = { 0 };
560 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
562 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
563 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
564 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
565 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
566 ppsc->reg_max_lps_awakeintvl);
567 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
568 "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
569 u1_h2c_set_pwrmode, 3);
570 rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
573 static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
574 struct sk_buff *skb)
576 struct rtl_priv *rtlpriv = rtl_priv(hw);
577 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
578 struct rtl8192_tx_ring *ring;
579 struct rtl_tx_desc *pdesc;
580 u8 idx = 0;
581 unsigned long flags;
582 struct sk_buff *pskb;
584 ring = &rtlpci->tx_ring[BEACON_QUEUE];
585 pskb = __skb_dequeue(&ring->queue);
586 if (pskb)
587 kfree_skb(pskb);
588 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
589 pdesc = &ring->desc[idx];
590 /* discard output from call below */
591 rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
592 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
593 __skb_queue_tail(&ring->queue, skb);
594 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
595 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
596 return true;
599 #define BEACON_PG 0 /*->1 */
600 #define PSPOLL_PG 2
601 #define NULL_PG 3
602 #define PROBERSP_PG 4 /*->5 */
603 #define TOTAL_RESERVED_PKT_LEN 768
605 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
606 /* page 0 beacon */
607 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
608 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
609 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
612 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
613 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
614 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
615 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
616 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
617 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
621 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 /* page 1 beacon */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
638 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 /* page 2 ps-poll */
643 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
644 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
657 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660 /* page 3 null */
661 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
662 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
663 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
675 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 /* page 4 probe_resp */
679 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
680 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
681 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
682 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
683 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
684 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
685 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
686 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
687 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
688 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
689 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
693 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696 /* page 5 probe_resp */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715 void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
717 struct rtl_priv *rtlpriv = rtl_priv(hw);
718 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
719 struct sk_buff *skb = NULL;
720 u32 totalpacketlen;
721 bool rtstatus;
722 u8 u1RsvdPageLoc[3] = { 0 };
723 bool dlok = false;
724 u8 *beacon;
725 u8 *p_pspoll;
726 u8 *nullfunc;
727 u8 *p_probersp;
728 /*---------------------------------------------------------
729 (1) beacon
730 ---------------------------------------------------------*/
731 beacon = &reserved_page_packet[BEACON_PG * 128];
732 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
733 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
734 /*-------------------------------------------------------
735 (2) ps-poll
736 --------------------------------------------------------*/
737 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
738 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
739 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
740 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
741 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
742 /*--------------------------------------------------------
743 (3) null data
744 ---------------------------------------------------------*/
745 nullfunc = &reserved_page_packet[NULL_PG * 128];
746 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
747 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
748 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
749 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
750 /*---------------------------------------------------------
751 (4) probe response
752 ----------------------------------------------------------*/
753 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
754 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
755 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
756 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
757 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
758 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
759 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
760 "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
761 &reserved_page_packet[0], totalpacketlen);
762 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
763 "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
764 u1RsvdPageLoc, 3);
765 skb = dev_alloc_skb(totalpacketlen);
766 memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet,
767 totalpacketlen);
768 rtstatus = _rtl92d_cmd_send_packet(hw, skb);
770 if (rtstatus)
771 dlok = true;
772 if (dlok) {
773 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
774 ("Set RSVD page location to Fw.\n"));
775 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
776 "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3);
777 rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
778 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
779 } else
780 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
781 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
784 void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
786 u8 u1_joinbssrpt_parm[1] = {0};
788 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
789 rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);