blob: 49a064bdbce6d26225674eab7e8540b29a747607 [file] [log] [blame]
Larry Finger0c817332010-12-08 11:12:31 -06001/******************************************************************************
2 *
3 * Copyright(c) 2009-2010 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
Joe Perches292b1192011-07-20 08:51:35 -070030#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
Larry Finger0c817332010-12-08 11:12:31 -060032#include <linux/firmware.h>
33#include "../wifi.h"
34#include "../pci.h"
35#include "../base.h"
Larry Finger1472d3a2011-02-23 10:24:58 -060036#include "../rtl8192ce/reg.h"
37#include "../rtl8192ce/def.h"
38#include "fw_common.h"
Larry Finger0c817332010-12-08 11:12:31 -060039
40static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
41{
42 struct rtl_priv *rtlpriv = rtl_priv(hw);
43 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
44
45 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
46 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
47 if (enable)
48 value32 |= MCUFWDL_EN;
49 else
50 value32 &= ~MCUFWDL_EN;
51 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
52 } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
53 u8 tmp;
54 if (enable) {
55
56 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
57 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
58 tmp | 0x04);
59
60 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
61 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
62
63 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
64 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
65 } else {
66
67 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
68 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
69
70 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
71 }
72 }
73}
74
75static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
76 const u8 *buffer, u32 size)
77{
78 struct rtl_priv *rtlpriv = rtl_priv(hw);
79 u32 blockSize = sizeof(u32);
80 u8 *bufferPtr = (u8 *) buffer;
81 u32 *pu4BytePtr = (u32 *) buffer;
82 u32 i, offset, blockCount, remainSize;
83
84 blockCount = size / blockSize;
85 remainSize = size % blockSize;
86
87 for (i = 0; i < blockCount; i++) {
88 offset = i * blockSize;
89 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
90 *(pu4BytePtr + i));
91 }
92
93 if (remainSize) {
94 offset = blockCount * blockSize;
95 bufferPtr += offset;
96 for (i = 0; i < remainSize; i++) {
97 rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
98 offset + i), *(bufferPtr + i));
99 }
100 }
101}
102
103static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
104 u32 page, const u8 *buffer, u32 size)
105{
106 struct rtl_priv *rtlpriv = rtl_priv(hw);
107 u8 value8;
108 u8 u8page = (u8) (page & 0x07);
109
110 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
111
112 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
113 _rtl92c_fw_block_write(hw, buffer, size);
114}
115
116static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
117{
118 u32 fwlen = *pfwlen;
119 u8 remain = (u8) (fwlen % 4);
120
121 remain = (remain == 0) ? 0 : (4 - remain);
122
123 while (remain > 0) {
124 pfwbuf[fwlen] = 0;
125 fwlen++;
126 remain--;
127 }
128
129 *pfwlen = fwlen;
130}
131
132static void _rtl92c_write_fw(struct ieee80211_hw *hw,
133 enum version_8192c version, u8 *buffer, u32 size)
134{
135 struct rtl_priv *rtlpriv = rtl_priv(hw);
136 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger0c817332010-12-08 11:12:31 -0600137 u8 *bufferPtr = (u8 *) buffer;
138
139 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
140
Larry Finger25b2bc32011-02-11 14:34:03 -0600141 if (IS_CHIP_VER_B(version)) {
Larry Finger0c817332010-12-08 11:12:31 -0600142 u32 pageNums, remainSize;
143 u32 page, offset;
144
Larry Finger25b2bc32011-02-11 14:34:03 -0600145 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
Larry Finger0c817332010-12-08 11:12:31 -0600146 _rtl92c_fill_dummy(bufferPtr, &size);
147
148 pageNums = size / FW_8192C_PAGE_SIZE;
149 remainSize = size % FW_8192C_PAGE_SIZE;
150
151 if (pageNums > 4) {
152 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
153 ("Page numbers should not greater then 4\n"));
154 }
155
156 for (page = 0; page < pageNums; page++) {
157 offset = page * FW_8192C_PAGE_SIZE;
158 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
159 FW_8192C_PAGE_SIZE);
160 }
161
162 if (remainSize) {
163 offset = pageNums * FW_8192C_PAGE_SIZE;
164 page = pageNums;
165 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
166 remainSize);
167 }
168 } else {
169 _rtl92c_fw_block_write(hw, buffer, size);
170 }
171}
172
173static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
174{
175 struct rtl_priv *rtlpriv = rtl_priv(hw);
Larry Finger0c817332010-12-08 11:12:31 -0600176 u32 counter = 0;
177 u32 value32;
178
179 do {
180 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
181 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
182 (!(value32 & FWDL_ChkSum_rpt)));
183
184 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
185 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
186 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
187 value32));
Larry Finger32473282011-03-27 16:19:57 -0500188 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600189 }
190
191 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
192 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
193
194 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
195 value32 |= MCUFWDL_RDY;
196 value32 &= ~WINTINI_RDY;
197 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
198
199 counter = 0;
200
201 do {
202 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
203 if (value32 & WINTINI_RDY) {
204 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
205 ("Polling FW ready success!!"
206 " REG_MCUFWDL:0x%08x .\n",
207 value32));
Larry Finger32473282011-03-27 16:19:57 -0500208 return 0;
Larry Finger0c817332010-12-08 11:12:31 -0600209 }
210
211 mdelay(FW_8192C_POLLING_DELAY);
212
213 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
214
215 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
216 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
Larry Finger32473282011-03-27 16:19:57 -0500217 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600218}
219
220int rtl92c_download_fw(struct ieee80211_hw *hw)
221{
222 struct rtl_priv *rtlpriv = rtl_priv(hw);
223 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
224 struct rtl92c_firmware_header *pfwheader;
225 u8 *pfwdata;
226 u32 fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600227 enum version_8192c version = rtlhal->version;
228
Joe Perches292b1192011-07-20 08:51:35 -0700229 pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500230 if (!rtlhal->pfirmware)
Larry Finger0c817332010-12-08 11:12:31 -0600231 return 1;
Larry Finger0c817332010-12-08 11:12:31 -0600232
233 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
234 pfwdata = (u8 *) rtlhal->pfirmware;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500235 fwsize = rtlhal->fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600236
237 if (IS_FW_HEADER_EXIST(pfwheader)) {
238 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
239 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
240 pfwheader->version, pfwheader->signature,
241 (uint)sizeof(struct rtl92c_firmware_header)));
242
243 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
244 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
245 }
246
247 _rtl92c_enable_fw_download(hw, true);
248 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
249 _rtl92c_enable_fw_download(hw, false);
250
Larry Finger32473282011-03-27 16:19:57 -0500251 if (_rtl92c_fw_free_to_go(hw)) {
Larry Finger0c817332010-12-08 11:12:31 -0600252 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
253 ("Firmware is not ready to run!\n"));
254 } else {
255 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
256 ("Firmware is ready to run!\n"));
257 }
258
259 return 0;
260}
Larry Finger1472d3a2011-02-23 10:24:58 -0600261EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600262
263static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
264{
265 struct rtl_priv *rtlpriv = rtl_priv(hw);
266 u8 val_hmetfr, val_mcutst_1;
267 bool result = false;
268
269 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
270 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
271
272 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
273 result = true;
274 return result;
275}
276
277static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
278 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
279{
280 struct rtl_priv *rtlpriv = rtl_priv(hw);
281 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
282 u8 boxnum;
Larry Finger9f219bd2011-04-13 21:00:02 -0500283 u16 box_reg = 0, box_extreg = 0;
Larry Finger0c817332010-12-08 11:12:31 -0600284 u8 u1b_tmp;
285 bool isfw_read = false;
Larry Finger0c817332010-12-08 11:12:31 -0600286 bool bwrite_sucess = false;
287 u8 wait_h2c_limmit = 100;
288 u8 wait_writeh2c_limmit = 100;
289 u8 boxcontent[4], boxextcontent[2];
290 u32 h2c_waitcounter = 0;
291 unsigned long flag;
292 u8 idx;
293
294 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
295
296 while (true) {
297 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600298 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600299 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
300 ("H2C set in progress! Wait to set.."
301 "element_id(%d).\n", element_id));
302
Larry Finger7ea47242011-02-19 16:28:57 -0600303 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600304 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
305 flag);
306 h2c_waitcounter++;
307 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
308 ("Wait 100 us (%d times)...\n",
309 h2c_waitcounter));
310 udelay(100);
311
312 if (h2c_waitcounter > 1000)
313 return;
314 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
315 flag);
316 }
317 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
318 } else {
Larry Finger7ea47242011-02-19 16:28:57 -0600319 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600320 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
321 break;
322 }
323 }
324
325 while (!bwrite_sucess) {
326 wait_writeh2c_limmit--;
327 if (wait_writeh2c_limmit == 0) {
328 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
329 ("Write H2C fail because no trigger "
330 "for FW INT!\n"));
331 break;
332 }
333
334 boxnum = rtlhal->last_hmeboxnum;
335 switch (boxnum) {
336 case 0:
337 box_reg = REG_HMEBOX_0;
338 box_extreg = REG_HMEBOX_EXT_0;
339 break;
340 case 1:
341 box_reg = REG_HMEBOX_1;
342 box_extreg = REG_HMEBOX_EXT_1;
343 break;
344 case 2:
345 box_reg = REG_HMEBOX_2;
346 box_extreg = REG_HMEBOX_EXT_2;
347 break;
348 case 3:
349 box_reg = REG_HMEBOX_3;
350 box_extreg = REG_HMEBOX_EXT_3;
351 break;
352 default:
353 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
354 ("switch case not process\n"));
355 break;
356 }
357
358 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
359 while (!isfw_read) {
360
361 wait_h2c_limmit--;
362 if (wait_h2c_limmit == 0) {
363 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
364 ("Wating too long for FW read "
365 "clear HMEBox(%d)!\n", boxnum));
366 break;
367 }
368
369 udelay(10);
370
371 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
372 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
373 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
374 ("Wating for FW read clear HMEBox(%d)!!! "
375 "0x1BF = %2x\n", boxnum, u1b_tmp));
376 }
377
378 if (!isfw_read) {
379 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
380 ("Write H2C register BOX[%d] fail!!!!! "
381 "Fw do not read.\n", boxnum));
382 break;
383 }
384
385 memset(boxcontent, 0, sizeof(boxcontent));
386 memset(boxextcontent, 0, sizeof(boxextcontent));
387 boxcontent[0] = element_id;
388 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
389 ("Write element_id box_reg(%4x) = %2x\n",
390 box_reg, element_id));
391
392 switch (cmd_len) {
393 case 1:
394 boxcontent[0] &= ~(BIT(7));
395 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500396 p_cmdbuffer, 1);
Larry Finger0c817332010-12-08 11:12:31 -0600397
398 for (idx = 0; idx < 4; idx++) {
399 rtl_write_byte(rtlpriv, box_reg + idx,
400 boxcontent[idx]);
401 }
402 break;
403 case 2:
404 boxcontent[0] &= ~(BIT(7));
405 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500406 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600407
408 for (idx = 0; idx < 4; idx++) {
409 rtl_write_byte(rtlpriv, box_reg + idx,
410 boxcontent[idx]);
411 }
412 break;
413 case 3:
414 boxcontent[0] &= ~(BIT(7));
415 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500416 p_cmdbuffer, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600417
418 for (idx = 0; idx < 4; idx++) {
419 rtl_write_byte(rtlpriv, box_reg + idx,
420 boxcontent[idx]);
421 }
422 break;
423 case 4:
424 boxcontent[0] |= (BIT(7));
425 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500426 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600427 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500428 p_cmdbuffer + 2, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600429
430 for (idx = 0; idx < 2; idx++) {
431 rtl_write_byte(rtlpriv, box_extreg + idx,
432 boxextcontent[idx]);
433 }
434
435 for (idx = 0; idx < 4; idx++) {
436 rtl_write_byte(rtlpriv, box_reg + idx,
437 boxcontent[idx]);
438 }
439 break;
440 case 5:
441 boxcontent[0] |= (BIT(7));
442 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500443 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600444 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500445 p_cmdbuffer + 2, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600446
447 for (idx = 0; idx < 2; idx++) {
448 rtl_write_byte(rtlpriv, box_extreg + idx,
449 boxextcontent[idx]);
450 }
451
452 for (idx = 0; idx < 4; idx++) {
453 rtl_write_byte(rtlpriv, box_reg + idx,
454 boxcontent[idx]);
455 }
456 break;
457 default:
458 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
459 ("switch case not process\n"));
460 break;
461 }
462
463 bwrite_sucess = true;
464
465 rtlhal->last_hmeboxnum = boxnum + 1;
466 if (rtlhal->last_hmeboxnum == 4)
467 rtlhal->last_hmeboxnum = 0;
468
469 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
470 ("pHalData->last_hmeboxnum = %d\n",
471 rtlhal->last_hmeboxnum));
472 }
473
474 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600475 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600476 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
477
478 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
479}
480
481void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
482 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
483{
484 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
485 u32 tmp_cmdbuf[2];
486
Larry Finger7ea47242011-02-19 16:28:57 -0600487 if (rtlhal->fw_ready == false) {
Larry Finger0c817332010-12-08 11:12:31 -0600488 RT_ASSERT(false, ("return H2C cmd because of Fw "
489 "download fail!!!\n"));
490 return;
491 }
492
493 memset(tmp_cmdbuf, 0, 8);
494 memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
495 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
496
497 return;
498}
Larry Finger1472d3a2011-02-23 10:24:58 -0600499EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600500
501void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
502{
503 u8 u1b_tmp;
504 u8 delay = 100;
505 struct rtl_priv *rtlpriv = rtl_priv(hw);
506
507 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
508 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
509
510 while (u1b_tmp & BIT(2)) {
511 delay--;
512 if (delay == 0) {
513 RT_ASSERT(false, ("8051 reset fail.\n"));
514 break;
515 }
516 udelay(50);
517 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
518 }
519}
Larry Finger1472d3a2011-02-23 10:24:58 -0600520EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600521
522void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
523{
524 struct rtl_priv *rtlpriv = rtl_priv(hw);
525 u8 u1_h2c_set_pwrmode[3] = {0};
526 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
527
528 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
529
530 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
531 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
532 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
533 ppsc->reg_max_lps_awakeintvl);
534
535 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
536 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
537 u1_h2c_set_pwrmode, 3);
538 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
539
540}
Larry Finger1472d3a2011-02-23 10:24:58 -0600541EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600542
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500543static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
544 struct sk_buff *skb)
545{
546 struct rtl_priv *rtlpriv = rtl_priv(hw);
547 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
548 struct rtl8192_tx_ring *ring;
549 struct rtl_tx_desc *pdesc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500550 unsigned long flags;
551 struct sk_buff *pskb = NULL;
552
553 ring = &rtlpci->tx_ring[BEACON_QUEUE];
554
555 pskb = __skb_dequeue(&ring->queue);
556 if (pskb)
557 kfree_skb(pskb);
558
559 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
560
561 pdesc = &ring->desc[0];
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500562
563 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
564
565 __skb_queue_tail(&ring->queue, skb);
566
567 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
568
569 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
570
571 return true;
572}
573
Larry Finger0c817332010-12-08 11:12:31 -0600574#define BEACON_PG 0 /*->1*/
575#define PSPOLL_PG 2
576#define NULL_PG 3
577#define PROBERSP_PG 4 /*->5*/
578
579#define TOTAL_RESERVED_PKT_LEN 768
580
581static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
582 /* page 0 beacon */
583 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
584 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
585 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
588 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
589 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
590 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
591 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
592 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
593 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
597 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599
600 /* page 1 beacon */
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617
618 /* page 2 ps-poll */
619 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
620 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
633 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635
636 /* page 3 null */
637 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
638 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
639 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
651 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653
654 /* page 4 probe_resp */
655 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
656 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
657 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
658 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
659 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
660 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
661 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
662 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
663 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
664 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
665 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
669 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671
672 /* page 5 probe_resp */
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689};
690
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500691void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
Larry Finger0c817332010-12-08 11:12:31 -0600692{
693 struct rtl_priv *rtlpriv = rtl_priv(hw);
694 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
695 struct sk_buff *skb = NULL;
696
697 u32 totalpacketlen;
698 bool rtstatus;
699 u8 u1RsvdPageLoc[3] = {0};
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500700 bool dlok = false;
Larry Finger0c817332010-12-08 11:12:31 -0600701
702 u8 *beacon;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500703 u8 *pspoll;
Larry Finger0c817332010-12-08 11:12:31 -0600704 u8 *nullfunc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500705 u8 *probersp;
Larry Finger0c817332010-12-08 11:12:31 -0600706 /*---------------------------------------------------------
707 (1) beacon
708 ---------------------------------------------------------*/
709 beacon = &reserved_page_packet[BEACON_PG * 128];
710 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
711 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
712
713 /*-------------------------------------------------------
714 (2) ps-poll
715 --------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500716 pspoll = &reserved_page_packet[PSPOLL_PG * 128];
717 SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
718 SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
719 SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
Larry Finger0c817332010-12-08 11:12:31 -0600720
721 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
722
723 /*--------------------------------------------------------
724 (3) null data
725 ---------------------------------------------------------*/
726 nullfunc = &reserved_page_packet[NULL_PG * 128];
727 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
728 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
729 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
730
731 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
732
733 /*---------------------------------------------------------
734 (4) probe response
735 ----------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500736 probersp = &reserved_page_packet[PROBERSP_PG * 128];
737 SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
738 SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
739 SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
Larry Finger0c817332010-12-08 11:12:31 -0600740
741 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
742
743 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
744
745 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
746 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
747 &reserved_page_packet[0], totalpacketlen);
748 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
749 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
750 u1RsvdPageLoc, 3);
751
752
753 skb = dev_alloc_skb(totalpacketlen);
754 memcpy((u8 *) skb_put(skb, totalpacketlen),
755 &reserved_page_packet, totalpacketlen);
756
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500757 rtstatus = _rtl92c_cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600758
759 if (rtstatus)
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500760 dlok = true;
Larry Finger0c817332010-12-08 11:12:31 -0600761
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500762 if (dlok) {
Larry Finger0c817332010-12-08 11:12:31 -0600763 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
764 ("Set RSVD page location to Fw.\n"));
765 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
766 "H2C_RSVDPAGE:\n",
767 u1RsvdPageLoc, 3);
768 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
769 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
770 } else
771 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
772 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
773}
Larry Finger1472d3a2011-02-23 10:24:58 -0600774EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600775
776void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
777{
778 u8 u1_joinbssrpt_parm[1] = {0};
779
780 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
781
782 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
783}
Larry Finger1472d3a2011-02-23 10:24:58 -0600784EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);