blob: 950c65a15b8a7fa0521471f5124cd89ee111268b [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>
Paul Gortmakeree40fa02011-05-27 16:14:23 -040033#include <linux/export.h>
Larry Finger0c817332010-12-08 11:12:31 -060034#include "../wifi.h"
35#include "../pci.h"
36#include "../base.h"
Larry Finger1472d3a2011-02-23 10:24:58 -060037#include "../rtl8192ce/reg.h"
38#include "../rtl8192ce/def.h"
39#include "fw_common.h"
Larry Finger0c817332010-12-08 11:12:31 -060040
41static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
42{
43 struct rtl_priv *rtlpriv = rtl_priv(hw);
44 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
45
46 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
47 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
48 if (enable)
49 value32 |= MCUFWDL_EN;
50 else
51 value32 &= ~MCUFWDL_EN;
52 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
53 } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
54 u8 tmp;
55 if (enable) {
56
57 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
58 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
59 tmp | 0x04);
60
61 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
62 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
63
64 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
65 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
66 } else {
67
68 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
69 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
70
71 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
72 }
73 }
74}
75
76static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
77 const u8 *buffer, u32 size)
78{
79 struct rtl_priv *rtlpriv = rtl_priv(hw);
80 u32 blockSize = sizeof(u32);
81 u8 *bufferPtr = (u8 *) buffer;
82 u32 *pu4BytePtr = (u32 *) buffer;
83 u32 i, offset, blockCount, remainSize;
84
85 blockCount = size / blockSize;
86 remainSize = size % blockSize;
87
88 for (i = 0; i < blockCount; i++) {
89 offset = i * blockSize;
90 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
91 *(pu4BytePtr + i));
92 }
93
94 if (remainSize) {
95 offset = blockCount * blockSize;
96 bufferPtr += offset;
97 for (i = 0; i < remainSize; i++) {
98 rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
99 offset + i), *(bufferPtr + i));
100 }
101 }
102}
103
104static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
105 u32 page, const u8 *buffer, u32 size)
106{
107 struct rtl_priv *rtlpriv = rtl_priv(hw);
108 u8 value8;
109 u8 u8page = (u8) (page & 0x07);
110
111 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
112
113 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
114 _rtl92c_fw_block_write(hw, buffer, size);
115}
116
117static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
118{
119 u32 fwlen = *pfwlen;
120 u8 remain = (u8) (fwlen % 4);
121
122 remain = (remain == 0) ? 0 : (4 - remain);
123
124 while (remain > 0) {
125 pfwbuf[fwlen] = 0;
126 fwlen++;
127 remain--;
128 }
129
130 *pfwlen = fwlen;
131}
132
133static void _rtl92c_write_fw(struct ieee80211_hw *hw,
134 enum version_8192c version, u8 *buffer, u32 size)
135{
136 struct rtl_priv *rtlpriv = rtl_priv(hw);
137 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger0c817332010-12-08 11:12:31 -0600138 u8 *bufferPtr = (u8 *) buffer;
139
140 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
141
Larry Finger25b2bc32011-02-11 14:34:03 -0600142 if (IS_CHIP_VER_B(version)) {
Larry Finger0c817332010-12-08 11:12:31 -0600143 u32 pageNums, remainSize;
144 u32 page, offset;
145
Larry Finger25b2bc32011-02-11 14:34:03 -0600146 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
Larry Finger0c817332010-12-08 11:12:31 -0600147 _rtl92c_fill_dummy(bufferPtr, &size);
148
149 pageNums = size / FW_8192C_PAGE_SIZE;
150 remainSize = size % FW_8192C_PAGE_SIZE;
151
152 if (pageNums > 4) {
153 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
154 ("Page numbers should not greater then 4\n"));
155 }
156
157 for (page = 0; page < pageNums; page++) {
158 offset = page * FW_8192C_PAGE_SIZE;
159 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
160 FW_8192C_PAGE_SIZE);
161 }
162
163 if (remainSize) {
164 offset = pageNums * FW_8192C_PAGE_SIZE;
165 page = pageNums;
166 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
167 remainSize);
168 }
169 } else {
170 _rtl92c_fw_block_write(hw, buffer, size);
171 }
172}
173
174static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
175{
176 struct rtl_priv *rtlpriv = rtl_priv(hw);
Larry Finger0c817332010-12-08 11:12:31 -0600177 u32 counter = 0;
178 u32 value32;
179
180 do {
181 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
182 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
183 (!(value32 & FWDL_ChkSum_rpt)));
184
185 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
186 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
187 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
188 value32));
Larry Finger32473282011-03-27 16:19:57 -0500189 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600190 }
191
192 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
193 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
194
195 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
196 value32 |= MCUFWDL_RDY;
197 value32 &= ~WINTINI_RDY;
198 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
199
200 counter = 0;
201
202 do {
203 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
204 if (value32 & WINTINI_RDY) {
205 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
206 ("Polling FW ready success!!"
207 " REG_MCUFWDL:0x%08x .\n",
208 value32));
Larry Finger32473282011-03-27 16:19:57 -0500209 return 0;
Larry Finger0c817332010-12-08 11:12:31 -0600210 }
211
212 mdelay(FW_8192C_POLLING_DELAY);
213
214 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
215
216 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
217 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
Larry Finger32473282011-03-27 16:19:57 -0500218 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600219}
220
221int rtl92c_download_fw(struct ieee80211_hw *hw)
222{
223 struct rtl_priv *rtlpriv = rtl_priv(hw);
224 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
225 struct rtl92c_firmware_header *pfwheader;
226 u8 *pfwdata;
227 u32 fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600228 enum version_8192c version = rtlhal->version;
229
Joe Perches292b1192011-07-20 08:51:35 -0700230 pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500231 if (!rtlhal->pfirmware)
Larry Finger0c817332010-12-08 11:12:31 -0600232 return 1;
Larry Finger0c817332010-12-08 11:12:31 -0600233
234 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
235 pfwdata = (u8 *) rtlhal->pfirmware;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500236 fwsize = rtlhal->fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600237
238 if (IS_FW_HEADER_EXIST(pfwheader)) {
239 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
240 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
241 pfwheader->version, pfwheader->signature,
242 (uint)sizeof(struct rtl92c_firmware_header)));
243
244 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
245 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
246 }
247
248 _rtl92c_enable_fw_download(hw, true);
249 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
250 _rtl92c_enable_fw_download(hw, false);
251
Larry Finger32473282011-03-27 16:19:57 -0500252 if (_rtl92c_fw_free_to_go(hw)) {
Larry Finger0c817332010-12-08 11:12:31 -0600253 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
254 ("Firmware is not ready to run!\n"));
255 } else {
256 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
257 ("Firmware is ready to run!\n"));
258 }
259
260 return 0;
261}
Larry Finger1472d3a2011-02-23 10:24:58 -0600262EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600263
264static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
265{
266 struct rtl_priv *rtlpriv = rtl_priv(hw);
267 u8 val_hmetfr, val_mcutst_1;
268 bool result = false;
269
270 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
271 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
272
273 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
274 result = true;
275 return result;
276}
277
278static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
279 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
280{
281 struct rtl_priv *rtlpriv = rtl_priv(hw);
282 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
283 u8 boxnum;
Larry Finger9f219bd2011-04-13 21:00:02 -0500284 u16 box_reg = 0, box_extreg = 0;
Larry Finger0c817332010-12-08 11:12:31 -0600285 u8 u1b_tmp;
286 bool isfw_read = false;
Larry Finger0c817332010-12-08 11:12:31 -0600287 bool bwrite_sucess = false;
288 u8 wait_h2c_limmit = 100;
289 u8 wait_writeh2c_limmit = 100;
290 u8 boxcontent[4], boxextcontent[2];
291 u32 h2c_waitcounter = 0;
292 unsigned long flag;
293 u8 idx;
294
295 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
296
297 while (true) {
298 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600299 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600300 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
301 ("H2C set in progress! Wait to set.."
302 "element_id(%d).\n", element_id));
303
Larry Finger7ea47242011-02-19 16:28:57 -0600304 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600305 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
306 flag);
307 h2c_waitcounter++;
308 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
309 ("Wait 100 us (%d times)...\n",
310 h2c_waitcounter));
311 udelay(100);
312
313 if (h2c_waitcounter > 1000)
314 return;
315 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
316 flag);
317 }
318 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
319 } else {
Larry Finger7ea47242011-02-19 16:28:57 -0600320 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600321 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
322 break;
323 }
324 }
325
326 while (!bwrite_sucess) {
327 wait_writeh2c_limmit--;
328 if (wait_writeh2c_limmit == 0) {
329 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
330 ("Write H2C fail because no trigger "
331 "for FW INT!\n"));
332 break;
333 }
334
335 boxnum = rtlhal->last_hmeboxnum;
336 switch (boxnum) {
337 case 0:
338 box_reg = REG_HMEBOX_0;
339 box_extreg = REG_HMEBOX_EXT_0;
340 break;
341 case 1:
342 box_reg = REG_HMEBOX_1;
343 box_extreg = REG_HMEBOX_EXT_1;
344 break;
345 case 2:
346 box_reg = REG_HMEBOX_2;
347 box_extreg = REG_HMEBOX_EXT_2;
348 break;
349 case 3:
350 box_reg = REG_HMEBOX_3;
351 box_extreg = REG_HMEBOX_EXT_3;
352 break;
353 default:
354 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
355 ("switch case not process\n"));
356 break;
357 }
358
359 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
360 while (!isfw_read) {
361
362 wait_h2c_limmit--;
363 if (wait_h2c_limmit == 0) {
364 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
365 ("Wating too long for FW read "
366 "clear HMEBox(%d)!\n", boxnum));
367 break;
368 }
369
370 udelay(10);
371
372 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
373 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
374 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
375 ("Wating for FW read clear HMEBox(%d)!!! "
376 "0x1BF = %2x\n", boxnum, u1b_tmp));
377 }
378
379 if (!isfw_read) {
380 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
381 ("Write H2C register BOX[%d] fail!!!!! "
382 "Fw do not read.\n", boxnum));
383 break;
384 }
385
386 memset(boxcontent, 0, sizeof(boxcontent));
387 memset(boxextcontent, 0, sizeof(boxextcontent));
388 boxcontent[0] = element_id;
389 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
390 ("Write element_id box_reg(%4x) = %2x\n",
391 box_reg, element_id));
392
393 switch (cmd_len) {
394 case 1:
395 boxcontent[0] &= ~(BIT(7));
396 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500397 p_cmdbuffer, 1);
Larry Finger0c817332010-12-08 11:12:31 -0600398
399 for (idx = 0; idx < 4; idx++) {
400 rtl_write_byte(rtlpriv, box_reg + idx,
401 boxcontent[idx]);
402 }
403 break;
404 case 2:
405 boxcontent[0] &= ~(BIT(7));
406 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500407 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600408
409 for (idx = 0; idx < 4; idx++) {
410 rtl_write_byte(rtlpriv, box_reg + idx,
411 boxcontent[idx]);
412 }
413 break;
414 case 3:
415 boxcontent[0] &= ~(BIT(7));
416 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500417 p_cmdbuffer, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600418
419 for (idx = 0; idx < 4; idx++) {
420 rtl_write_byte(rtlpriv, box_reg + idx,
421 boxcontent[idx]);
422 }
423 break;
424 case 4:
425 boxcontent[0] |= (BIT(7));
426 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500427 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600428 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500429 p_cmdbuffer + 2, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600430
431 for (idx = 0; idx < 2; idx++) {
432 rtl_write_byte(rtlpriv, box_extreg + idx,
433 boxextcontent[idx]);
434 }
435
436 for (idx = 0; idx < 4; idx++) {
437 rtl_write_byte(rtlpriv, box_reg + idx,
438 boxcontent[idx]);
439 }
440 break;
441 case 5:
442 boxcontent[0] |= (BIT(7));
443 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500444 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600445 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500446 p_cmdbuffer + 2, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600447
448 for (idx = 0; idx < 2; idx++) {
449 rtl_write_byte(rtlpriv, box_extreg + idx,
450 boxextcontent[idx]);
451 }
452
453 for (idx = 0; idx < 4; idx++) {
454 rtl_write_byte(rtlpriv, box_reg + idx,
455 boxcontent[idx]);
456 }
457 break;
458 default:
459 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
460 ("switch case not process\n"));
461 break;
462 }
463
464 bwrite_sucess = true;
465
466 rtlhal->last_hmeboxnum = boxnum + 1;
467 if (rtlhal->last_hmeboxnum == 4)
468 rtlhal->last_hmeboxnum = 0;
469
470 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
471 ("pHalData->last_hmeboxnum = %d\n",
472 rtlhal->last_hmeboxnum));
473 }
474
475 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600476 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600477 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
478
479 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
480}
481
482void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
483 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
484{
485 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
486 u32 tmp_cmdbuf[2];
487
Larry Finger7ea47242011-02-19 16:28:57 -0600488 if (rtlhal->fw_ready == false) {
Larry Finger0c817332010-12-08 11:12:31 -0600489 RT_ASSERT(false, ("return H2C cmd because of Fw "
490 "download fail!!!\n"));
491 return;
492 }
493
494 memset(tmp_cmdbuf, 0, 8);
495 memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
496 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
497
498 return;
499}
Larry Finger1472d3a2011-02-23 10:24:58 -0600500EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600501
502void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
503{
504 u8 u1b_tmp;
505 u8 delay = 100;
506 struct rtl_priv *rtlpriv = rtl_priv(hw);
507
508 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
509 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
510
511 while (u1b_tmp & BIT(2)) {
512 delay--;
513 if (delay == 0) {
514 RT_ASSERT(false, ("8051 reset fail.\n"));
515 break;
516 }
517 udelay(50);
518 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
519 }
520}
Larry Finger1472d3a2011-02-23 10:24:58 -0600521EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600522
523void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
524{
525 struct rtl_priv *rtlpriv = rtl_priv(hw);
526 u8 u1_h2c_set_pwrmode[3] = {0};
527 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
528
529 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
530
531 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
532 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
533 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
534 ppsc->reg_max_lps_awakeintvl);
535
536 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
537 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
538 u1_h2c_set_pwrmode, 3);
539 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
540
541}
Larry Finger1472d3a2011-02-23 10:24:58 -0600542EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600543
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500544static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
545 struct sk_buff *skb)
546{
547 struct rtl_priv *rtlpriv = rtl_priv(hw);
548 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
549 struct rtl8192_tx_ring *ring;
550 struct rtl_tx_desc *pdesc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500551 unsigned long flags;
552 struct sk_buff *pskb = NULL;
553
554 ring = &rtlpci->tx_ring[BEACON_QUEUE];
555
556 pskb = __skb_dequeue(&ring->queue);
557 if (pskb)
558 kfree_skb(pskb);
559
560 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
561
562 pdesc = &ring->desc[0];
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500563
564 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
565
566 __skb_queue_tail(&ring->queue, skb);
567
568 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
569
570 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
571
572 return true;
573}
574
Larry Finger0c817332010-12-08 11:12:31 -0600575#define BEACON_PG 0 /*->1*/
576#define PSPOLL_PG 2
577#define NULL_PG 3
578#define PROBERSP_PG 4 /*->5*/
579
580#define TOTAL_RESERVED_PKT_LEN 768
581
582static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
583 /* page 0 beacon */
584 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
585 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
586 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
589 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
590 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
591 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
592 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
593 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
594 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
598 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600
601 /* page 1 beacon */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618
619 /* page 2 ps-poll */
620 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
621 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
634 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636
637 /* page 3 null */
638 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
639 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
640 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
652 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654
655 /* page 4 probe_resp */
656 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
657 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
658 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
659 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
660 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
661 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
662 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
663 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
664 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
665 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
666 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
670 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672
673 /* page 5 probe_resp */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690};
691
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500692void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
Larry Finger0c817332010-12-08 11:12:31 -0600693{
694 struct rtl_priv *rtlpriv = rtl_priv(hw);
695 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
696 struct sk_buff *skb = NULL;
697
698 u32 totalpacketlen;
699 bool rtstatus;
700 u8 u1RsvdPageLoc[3] = {0};
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500701 bool dlok = false;
Larry Finger0c817332010-12-08 11:12:31 -0600702
703 u8 *beacon;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500704 u8 *pspoll;
Larry Finger0c817332010-12-08 11:12:31 -0600705 u8 *nullfunc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500706 u8 *probersp;
Larry Finger0c817332010-12-08 11:12:31 -0600707 /*---------------------------------------------------------
708 (1) beacon
709 ---------------------------------------------------------*/
710 beacon = &reserved_page_packet[BEACON_PG * 128];
711 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
712 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
713
714 /*-------------------------------------------------------
715 (2) ps-poll
716 --------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500717 pspoll = &reserved_page_packet[PSPOLL_PG * 128];
718 SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
719 SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
720 SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
Larry Finger0c817332010-12-08 11:12:31 -0600721
722 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
723
724 /*--------------------------------------------------------
725 (3) null data
726 ---------------------------------------------------------*/
727 nullfunc = &reserved_page_packet[NULL_PG * 128];
728 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
729 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
730 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
731
732 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
733
734 /*---------------------------------------------------------
735 (4) probe response
736 ----------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500737 probersp = &reserved_page_packet[PROBERSP_PG * 128];
738 SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
739 SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
740 SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
Larry Finger0c817332010-12-08 11:12:31 -0600741
742 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
743
744 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
745
746 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
747 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
748 &reserved_page_packet[0], totalpacketlen);
749 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
750 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
751 u1RsvdPageLoc, 3);
752
753
754 skb = dev_alloc_skb(totalpacketlen);
755 memcpy((u8 *) skb_put(skb, totalpacketlen),
756 &reserved_page_packet, totalpacketlen);
757
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500758 rtstatus = _rtl92c_cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600759
760 if (rtstatus)
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500761 dlok = true;
Larry Finger0c817332010-12-08 11:12:31 -0600762
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500763 if (dlok) {
Larry Finger0c817332010-12-08 11:12:31 -0600764 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
765 ("Set RSVD page location to Fw.\n"));
766 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
767 "H2C_RSVDPAGE:\n",
768 u1RsvdPageLoc, 3);
769 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
770 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
771 } else
772 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
773 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
774}
Larry Finger1472d3a2011-02-23 10:24:58 -0600775EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600776
777void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
778{
779 u8 u1_joinbssrpt_parm[1] = {0};
780
781 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
782
783 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
784}
Larry Finger1472d3a2011-02-23 10:24:58 -0600785EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);