Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fw.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012 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 <[email protected]>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <[email protected]>
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 #include "sw.h"
37 
38 static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)
39 {
40  return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ?
41  true : false;
42 }
43 
44 static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)
45 {
46  struct rtl_priv *rtlpriv = rtl_priv(hw);
47  u8 tmp;
48 
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);*/
63  }
64 }
65 
66 static void _rtl92d_fw_block_write(struct ieee80211_hw *hw,
67  const u8 *buffer, u32 size)
68 {
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;
74 
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));
81  }
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));
88  }
89  }
90 }
91 
92 static void _rtl92d_fw_page_write(struct ieee80211_hw *hw,
93  u32 page, const u8 *buffer, u32 size)
94 {
95  struct rtl_priv *rtlpriv = rtl_priv(hw);
96  u8 value8;
97  u8 u8page = (u8) (page & 0x07);
98 
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);
102 }
103 
104 static void _rtl92d_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
105 {
106  u32 fwlen = *pfwlen;
107  u8 remain = (u8) (fwlen % 4);
108 
109  remain = (remain == 0) ? 0 : (4 - remain);
110  while (remain > 0) {
111  pfwbuf[fwlen] = 0;
112  fwlen++;
113  remain--;
114  }
115  *pfwlen = fwlen;
116 }
117 
118 static void _rtl92d_write_fw(struct ieee80211_hw *hw,
119  enum version_8192d version, u8 *buffer, u32 size)
120 {
121  struct rtl_priv *rtlpriv = rtl_priv(hw);
122  struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
123  u8 *bufferPtr = buffer;
124  u32 pagenums, remainSize;
125  u32 page, offset;
126 
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");
135  }
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);
140  }
141  if (remainSize) {
142  offset = pagenums * FW_8192D_PAGE_SIZE;
143  page = pagenums;
144  _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
145  remainSize);
146  }
147 }
148 
149 static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
150 {
151  struct rtl_priv *rtlpriv = rtl_priv(hw);
152  u32 counter = 0;
153  u32 value32;
154 
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;
164  }
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;
171 }
172 
174 {
175  struct rtl_priv *rtlpriv = rtl_priv(hw);
176  u8 u1b_tmp;
177  u8 delay = 100;
178 
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);
188  }
189  RT_ASSERT((delay > 0), "8051 reset failed!\n");
190  RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
191  "=====> 8051 reset success (%d)\n", delay);
192 }
193 
194 static int _rtl92d_fw_init(struct ieee80211_hw *hw)
195 {
196  struct rtl_priv *rtlpriv = rtl_priv(hw);
197  struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
198  u32 counter;
199 
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!! REG_MCUFWDL: 0x%x\n",
209  rtl_read_byte(rtlpriv,
210  FW_MAC0_READY));
211  return 0;
212  }
213  udelay(5);
214  } else {
215  if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
216  MAC1_READY) {
217  RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
218  "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
219  rtl_read_byte(rtlpriv,
220  FW_MAC1_READY));
221  return 0;
222  }
223  udelay(5);
224  }
225  } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
226 
227  if (rtlhal->interfaceindex == 0) {
228  RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
229  "Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n",
230  rtl_read_byte(rtlpriv, FW_MAC0_READY));
231  } else {
232  RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
233  "Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n",
234  rtl_read_byte(rtlpriv, FW_MAC1_READY));
235  }
236  RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
237  "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n",
238  rtl_read_dword(rtlpriv, REG_MCUFWDL));
239  return -1;
240 }
241 
243 {
244  struct rtl_priv *rtlpriv = rtl_priv(hw);
245  struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
246  u8 *pfwheader;
247  u8 *pfwdata;
248  u32 fwsize;
249  int err;
250  enum version_8192d version = rtlhal->version;
251  u8 value;
252  u32 count;
253  bool fw_downloaded = false, fwdl_in_process = false;
254  unsigned long flags;
255 
256  if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
257  return 1;
258  fwsize = rtlhal->fwsize;
259  pfwheader = rtlhal->pfirmware;
260  pfwdata = rtlhal->pfirmware;
261  rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
262  rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
263  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
264  "FirmwareVersion(%d), FirmwareSubVersion(%d), Signature(%#x)\n",
265  rtlhal->fw_version, rtlhal->fw_subversion,
266  GET_FIRMWARE_HDR_SIGNATURE(pfwheader));
267  if (IS_FW_HEADER_EXIST(pfwheader)) {
268  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
269  "Shift 32 bytes for FW header!!\n");
270  pfwdata = pfwdata + 32;
271  fwsize = fwsize - 32;
272  }
273 
275  fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
276  if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
277  fwdl_in_process = true;
278  else
279  fwdl_in_process = false;
280  if (fw_downloaded) {
281  spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
282  goto exit;
283  } else if (fwdl_in_process) {
284  spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
285  for (count = 0; count < 5000; count++) {
286  udelay(500);
288  fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
289  if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
290  fwdl_in_process = true;
291  else
292  fwdl_in_process = false;
293  spin_unlock_irqrestore(&globalmutex_for_fwdownload,
294  flags);
295  if (fw_downloaded)
296  goto exit;
297  else if (!fwdl_in_process)
298  break;
299  else
300  RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
301  "Wait for another mac download fw\n");
302  }
304  value = rtl_read_byte(rtlpriv, 0x1f);
305  value |= BIT(5);
306  rtl_write_byte(rtlpriv, 0x1f, value);
307  spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
308  } else {
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  }
314 
315  /* If 8051 is running in RAM code, driver should
316  * inform Fw to reset by itself, or it will cause
317  * download Fw fail.*/
318  /* 8051 RAM code */
319  if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
321  rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
322  }
323  _rtl92d_enable_fw_download(hw, true);
324  _rtl92d_write_fw(hw, version, pfwdata, fwsize);
325  _rtl92d_enable_fw_download(hw, false);
327  err = _rtl92d_fw_free_to_go(hw);
328  /* download fw over,clear 0x1f[5] */
329  value = rtl_read_byte(rtlpriv, 0x1f);
330  value &= (~BIT(5));
331  rtl_write_byte(rtlpriv, 0x1f, value);
332  spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
333  if (err) {
334  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
335  "fw is not ready to run!\n");
336  goto exit;
337  } else {
338  RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "fw is ready to run!\n");
339  }
340 exit:
341  err = _rtl92d_fw_init(hw);
342  return err;
343 }
344 
345 static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
346 {
347  struct rtl_priv *rtlpriv = rtl_priv(hw);
348  u8 val_hmetfr;
349  bool result = false;
350 
351  val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
352  if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
353  result = true;
354  return result;
355 }
356 
357 static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
358  u8 element_id, u32 cmd_len, u8 *cmdbuffer)
359 {
360  struct rtl_priv *rtlpriv = rtl_priv(hw);
361  struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
362  struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
363  u8 boxnum;
364  u16 box_reg = 0, box_extreg = 0;
365  u8 u1b_tmp;
366  bool isfw_read = false;
367  u8 buf_index = 0;
368  bool bwrite_success = false;
369  u8 wait_h2c_limmit = 100;
370  u8 wait_writeh2c_limmit = 100;
371  u8 boxcontent[4], boxextcontent[2];
372  u32 h2c_waitcounter = 0;
373  unsigned long flag;
374  u8 idx;
375 
376  if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
377  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
378  "Return as RF is off!!!\n");
379  return;
380  }
381  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
382  while (true) {
383  spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
384  if (rtlhal->h2c_setinprogress) {
385  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
386  "H2C set in progress! Wait to set..element_id(%d)\n",
387  element_id);
388 
389  while (rtlhal->h2c_setinprogress) {
390  spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
391  flag);
392  h2c_waitcounter++;
393  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
394  "Wait 100 us (%d times)...\n",
395  h2c_waitcounter);
396  udelay(100);
397 
398  if (h2c_waitcounter > 1000)
399  return;
400 
401  spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
402  flag);
403  }
404  spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
405  } else {
406  rtlhal->h2c_setinprogress = true;
407  spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
408  break;
409  }
410  }
411  while (!bwrite_success) {
412  wait_writeh2c_limmit--;
413  if (wait_writeh2c_limmit == 0) {
414  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
415  "Write H2C fail because no trigger for FW INT!\n");
416  break;
417  }
418  boxnum = rtlhal->last_hmeboxnum;
419  switch (boxnum) {
420  case 0:
421  box_reg = REG_HMEBOX_0;
422  box_extreg = REG_HMEBOX_EXT_0;
423  break;
424  case 1:
425  box_reg = REG_HMEBOX_1;
426  box_extreg = REG_HMEBOX_EXT_1;
427  break;
428  case 2:
429  box_reg = REG_HMEBOX_2;
430  box_extreg = REG_HMEBOX_EXT_2;
431  break;
432  case 3:
433  box_reg = REG_HMEBOX_3;
434  box_extreg = REG_HMEBOX_EXT_3;
435  break;
436  default:
437  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
438  "switch case not processed\n");
439  break;
440  }
441  isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
442  while (!isfw_read) {
443  wait_h2c_limmit--;
444  if (wait_h2c_limmit == 0) {
445  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
446  "Waiting too long for FW read clear HMEBox(%d)!\n",
447  boxnum);
448  break;
449  }
450  udelay(10);
451  isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
452  u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
453  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
454  "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
455  boxnum, u1b_tmp);
456  }
457  if (!isfw_read) {
458  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
459  "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
460  boxnum);
461  break;
462  }
463  memset(boxcontent, 0, sizeof(boxcontent));
464  memset(boxextcontent, 0, sizeof(boxextcontent));
465  boxcontent[0] = element_id;
466  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
467  "Write element_id box_reg(%4x) = %2x\n",
468  box_reg, element_id);
469  switch (cmd_len) {
470  case 1:
471  boxcontent[0] &= ~(BIT(7));
472  memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
473  for (idx = 0; idx < 4; idx++)
474  rtl_write_byte(rtlpriv, box_reg + idx,
475  boxcontent[idx]);
476  break;
477  case 2:
478  boxcontent[0] &= ~(BIT(7));
479  memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
480  for (idx = 0; idx < 4; idx++)
481  rtl_write_byte(rtlpriv, box_reg + idx,
482  boxcontent[idx]);
483  break;
484  case 3:
485  boxcontent[0] &= ~(BIT(7));
486  memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
487  for (idx = 0; idx < 4; idx++)
488  rtl_write_byte(rtlpriv, box_reg + idx,
489  boxcontent[idx]);
490  break;
491  case 4:
492  boxcontent[0] |= (BIT(7));
493  memcpy(boxextcontent, cmdbuffer + buf_index, 2);
494  memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
495  for (idx = 0; idx < 2; idx++)
496  rtl_write_byte(rtlpriv, box_extreg + idx,
497  boxextcontent[idx]);
498  for (idx = 0; idx < 4; idx++)
499  rtl_write_byte(rtlpriv, box_reg + idx,
500  boxcontent[idx]);
501  break;
502  case 5:
503  boxcontent[0] |= (BIT(7));
504  memcpy(boxextcontent, cmdbuffer + buf_index, 2);
505  memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
506  for (idx = 0; idx < 2; idx++)
507  rtl_write_byte(rtlpriv, box_extreg + idx,
508  boxextcontent[idx]);
509  for (idx = 0; idx < 4; idx++)
510  rtl_write_byte(rtlpriv, box_reg + idx,
511  boxcontent[idx]);
512  break;
513  default:
514  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
515  "switch case not processed\n");
516  break;
517  }
518  bwrite_success = true;
519  rtlhal->last_hmeboxnum = boxnum + 1;
520  if (rtlhal->last_hmeboxnum == 4)
521  rtlhal->last_hmeboxnum = 0;
522  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
523  "pHalData->last_hmeboxnum = %d\n",
524  rtlhal->last_hmeboxnum);
525  }
526  spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
527  rtlhal->h2c_setinprogress = false;
528  spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
529  RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
530 }
531 
533  u8 element_id, u32 cmd_len, u8 *cmdbuffer)
534 {
535  u32 tmp_cmdbuf[2];
536 
537  memset(tmp_cmdbuf, 0, 8);
538  memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
539  _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
540  return;
541 }
542 
544 {
545  struct rtl_priv *rtlpriv = rtl_priv(hw);
546  u8 u1_h2c_set_pwrmode[3] = { 0 };
547  struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
548 
549  RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
550  SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
551  SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
552  SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
553  ppsc->reg_max_lps_awakeintvl);
554  RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
555  "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
556  u1_h2c_set_pwrmode, 3);
557  rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
558 }
559 
560 static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
561  struct sk_buff *skb)
562 {
563  struct rtl_priv *rtlpriv = rtl_priv(hw);
564  struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
565  struct rtl8192_tx_ring *ring;
566  struct rtl_tx_desc *pdesc;
567  u8 idx = 0;
568  unsigned long flags;
569  struct sk_buff *pskb;
570 
571  ring = &rtlpci->tx_ring[BEACON_QUEUE];
572  pskb = __skb_dequeue(&ring->queue);
573  kfree_skb(pskb);
574  spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
575  pdesc = &ring->desc[idx];
576  /* discard output from call below */
577  rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
578  rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
579  __skb_queue_tail(&ring->queue, skb);
580  spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
581  rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
582  return true;
583 }
584 
585 #define BEACON_PG 0 /*->1 */
586 #define PSPOLL_PG 2
587 #define NULL_PG 3
588 #define PROBERSP_PG 4 /*->5 */
589 #define TOTAL_RESERVED_PKT_LEN 768
590 
591 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
592  /* page 0 beacon */
593  0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
594  0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
595  0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
596  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597  0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
598  0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
599  0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
600  0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
601  0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
602  0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
603  0x03, 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  0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
607  0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 
610  /* page 1 beacon */
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  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617  0x00, 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  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623  0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
624  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627 
628  /* page 2 ps-poll */
629  0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
630  0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
631  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
633  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638  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  0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
642  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
643  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 
646  /* page 3 null */
647  0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
648  0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
649  0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
650  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
656  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
657  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659  0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
660  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
661  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
662  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663 
664  /* page 4 probe_resp */
665  0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
666  0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
667  0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
668  0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
669  0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
670  0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
671  0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
672  0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
673  0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
674  0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
675  0x03, 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  0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
679  0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 
682  /* page 5 probe_resp */
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  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
697  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699 };
700 
701 void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
702 {
703  struct rtl_priv *rtlpriv = rtl_priv(hw);
704  struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
705  struct sk_buff *skb = NULL;
706  u32 totalpacketlen;
707  bool rtstatus;
708  u8 u1RsvdPageLoc[3] = { 0 };
709  bool dlok = false;
710  u8 *beacon;
711  u8 *p_pspoll;
712  u8 *nullfunc;
713  u8 *p_probersp;
714  /*---------------------------------------------------------
715  (1) beacon
716  ---------------------------------------------------------*/
717  beacon = &reserved_page_packet[BEACON_PG * 128];
718  SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
719  SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
720  /*-------------------------------------------------------
721  (2) ps-poll
722  --------------------------------------------------------*/
723  p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
724  SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
725  SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
726  SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
728  /*--------------------------------------------------------
729  (3) null data
730  ---------------------------------------------------------*/
731  nullfunc = &reserved_page_packet[NULL_PG * 128];
732  SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
733  SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
734  SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
736  /*---------------------------------------------------------
737  (4) probe response
738  ----------------------------------------------------------*/
739  p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
740  SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
741  SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
742  SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
744  totalpacketlen = TOTAL_RESERVED_PKT_LEN;
745  RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
746  "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
747  &reserved_page_packet[0], totalpacketlen);
748  RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
749  "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
750  u1RsvdPageLoc, 3);
751  skb = dev_alloc_skb(totalpacketlen);
752  if (!skb) {
753  dlok = false;
754  } else {
755  memcpy((u8 *) skb_put(skb, totalpacketlen),
756  &reserved_page_packet, totalpacketlen);
757  rtstatus = _rtl92d_cmd_send_packet(hw, skb);
758 
759  if (rtstatus)
760  dlok = true;
761  }
762  if (dlok) {
763  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", u1RsvdPageLoc, 3);
768  sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
769  } else
770  RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
771  "Set RSVD page location to Fw FAIL!!!!!!\n");
772 }
773 
775 {
776  u8 u1_joinbssrpt_parm[1] = {0};
777 
778  SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
779  rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
780 }