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 
37 static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw)
38 {
39  struct rtl_priv *rtlpriv = rtl_priv(hw);
40 
41  rtl_write_dword(rtlpriv, RQPN, 0xffffffff);
42  rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff);
43  rtl_write_byte(rtlpriv, RQPN + 8, 0xff);
44  rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80);
45 }
46 
47 static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw)
48 {
49  struct rtl_priv *rtlpriv = rtl_priv(hw);
50  u32 ichecktime = 200;
51  u16 tmpu2b;
52  u8 tmpu1b, cpustatus = 0;
53 
54  _rtl92s_fw_set_rqpn(hw);
55 
56  /* Enable CPU. */
57  tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR);
58  /* AFE source */
59  rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL));
60 
61  tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
62  rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN));
63 
64  /* Polling IMEM Ready after CPU has refilled. */
65  do {
66  cpustatus = rtl_read_byte(rtlpriv, TCR);
67  if (cpustatus & IMEM_RDY) {
68  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
69  "IMEM Ready after CPU has refilled\n");
70  break;
71  }
72 
73  udelay(100);
74  } while (ichecktime--);
75 
76  if (!(cpustatus & IMEM_RDY))
77  return false;
78 
79  return true;
80 }
81 
82 static enum fw_status _rtl92s_firmware_get_nextstatus(
83  enum fw_status fw_currentstatus)
84 {
85  enum fw_status next_fwstatus = 0;
86 
87  switch (fw_currentstatus) {
88  case FW_STATUS_INIT:
89  next_fwstatus = FW_STATUS_LOAD_IMEM;
90  break;
92  next_fwstatus = FW_STATUS_LOAD_EMEM;
93  break;
95  next_fwstatus = FW_STATUS_LOAD_DMEM;
96  break;
98  next_fwstatus = FW_STATUS_READY;
99  break;
100  default:
101  break;
102  }
103 
104  return next_fwstatus;
105 }
106 
107 static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw)
108 {
109  struct rtl_priv *rtlpriv = rtl_priv(hw);
110  struct rtl_phy *rtlphy = &(rtlpriv->phy);
111 
112  switch (rtlphy->rf_type) {
113  case RF_1T1R:
114  return 0x11;
115  break;
116  case RF_1T2R:
117  return 0x12;
118  break;
119  case RF_2T2R:
120  return 0x22;
121  break;
122  default:
123  RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Unknown RF type(%x)\n",
124  rtlphy->rf_type);
125  break;
126  }
127  return 0x22;
128 }
129 
130 static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw,
131  struct fw_priv *pfw_priv)
132 {
133  /* Update RF types for RATR settings. */
134  pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw);
135 }
136 
137 
138 
139 static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw,
140  struct sk_buff *skb, u8 last)
141 {
142  struct rtl_priv *rtlpriv = rtl_priv(hw);
143  struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
144  struct rtl8192_tx_ring *ring;
145  struct rtl_tx_desc *pdesc;
146  unsigned long flags;
147  u8 idx = 0;
148 
149  ring = &rtlpci->tx_ring[TXCMD_QUEUE];
150 
151  spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
152 
153  idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
154  pdesc = &ring->desc[idx];
155  rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
156  __skb_queue_tail(&ring->queue, skb);
157 
158  spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
159 
160  return true;
161 }
162 
163 static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
164  u8 *code_virtual_address, u32 buffer_len)
165 {
166  struct rtl_priv *rtlpriv = rtl_priv(hw);
167  struct sk_buff *skb;
168  struct rtl_tcb_desc *tcb_desc;
169  unsigned char *seg_ptr;
171  u16 frag_length, frag_offset = 0;
172  u16 extra_descoffset = 0;
173  u8 last_inipkt = 0;
174 
175  _rtl92s_fw_set_rqpn(hw);
176 
177  if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) {
178  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
179  "Size over FIRMWARE_CODE_SIZE!\n");
180 
181  return false;
182  }
183 
184  extra_descoffset = 0;
185 
186  do {
187  if ((buffer_len - frag_offset) > frag_threshold) {
188  frag_length = frag_threshold + extra_descoffset;
189  } else {
190  frag_length = (u16)(buffer_len - frag_offset +
191  extra_descoffset);
192  last_inipkt = 1;
193  }
194 
195  /* Allocate skb buffer to contain firmware */
196  /* info and tx descriptor info. */
197  skb = dev_alloc_skb(frag_length);
198  if (!skb)
199  return false;
200  skb_reserve(skb, extra_descoffset);
201  seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length -
202  extra_descoffset));
203  memcpy(seg_ptr, code_virtual_address + frag_offset,
204  (u32)(frag_length - extra_descoffset));
205 
206  tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
207  tcb_desc->queue_index = TXCMD_QUEUE;
209  tcb_desc->last_inipkt = last_inipkt;
210 
211  _rtl92s_cmd_send_packet(hw, skb, last_inipkt);
212 
213  frag_offset += (frag_length - extra_descoffset);
214 
215  } while (frag_offset < buffer_len);
216 
217  rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ);
218 
219  return true ;
220 }
221 
222 static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw,
223  u8 loadfw_status)
224 {
225  struct rtl_priv *rtlpriv = rtl_priv(hw);
226  struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
227  struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware;
228  u32 tmpu4b;
229  u8 cpustatus = 0;
230  short pollingcnt = 1000;
231  bool rtstatus = true;
232 
233  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
234  "LoadStaus(%d)\n", loadfw_status);
235 
236  firmware->fwstatus = (enum fw_status)loadfw_status;
237 
238  switch (loadfw_status) {
239  case FW_STATUS_LOAD_IMEM:
240  /* Polling IMEM code done. */
241  do {
242  cpustatus = rtl_read_byte(rtlpriv, TCR);
243  if (cpustatus & IMEM_CODE_DONE)
244  break;
245  udelay(5);
246  } while (pollingcnt--);
247 
248  if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) {
249  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
250  "FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\n",
251  cpustatus);
252  goto status_check_fail;
253  }
254  break;
255 
256  case FW_STATUS_LOAD_EMEM:
257  /* Check Put Code OK and Turn On CPU */
258  /* Polling EMEM code done. */
259  do {
260  cpustatus = rtl_read_byte(rtlpriv, TCR);
261  if (cpustatus & EMEM_CODE_DONE)
262  break;
263  udelay(5);
264  } while (pollingcnt--);
265 
266  if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) {
267  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
268  "FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\n",
269  cpustatus);
270  goto status_check_fail;
271  }
272 
273  /* Turn On CPU */
274  rtstatus = _rtl92s_firmware_enable_cpu(hw);
275  if (!rtstatus) {
276  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
277  "Enable CPU fail!\n");
278  goto status_check_fail;
279  }
280  break;
281 
282  case FW_STATUS_LOAD_DMEM:
283  /* Polling DMEM code done */
284  do {
285  cpustatus = rtl_read_byte(rtlpriv, TCR);
286  if (cpustatus & DMEM_CODE_DONE)
287  break;
288  udelay(5);
289  } while (pollingcnt--);
290 
291  if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) {
292  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
293  "Polling DMEM code done fail ! cpustatus(%#x)\n",
294  cpustatus);
295  goto status_check_fail;
296  }
297 
298  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
299  "DMEM code download success, cpustatus(%#x)\n",
300  cpustatus);
301 
302  /* Prevent Delay too much and being scheduled out */
303  /* Polling Load Firmware ready */
304  pollingcnt = 2000;
305  do {
306  cpustatus = rtl_read_byte(rtlpriv, TCR);
307  if (cpustatus & FWRDY)
308  break;
309  udelay(40);
310  } while (pollingcnt--);
311 
312  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
313  "Polling Load Firmware ready, cpustatus(%x)\n",
314  cpustatus);
315 
316  if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) ||
317  (pollingcnt <= 0)) {
318  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
319  "Polling Load Firmware ready fail ! cpustatus(%x)\n",
320  cpustatus);
321  goto status_check_fail;
322  }
323 
324  /* If right here, we can set TCR/RCR to desired value */
325  /* and config MAC lookback mode to normal mode */
326  tmpu4b = rtl_read_dword(rtlpriv, TCR);
327  rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV)));
328 
329  tmpu4b = rtl_read_dword(rtlpriv, RCR);
330  rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS |
332 
333  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
334  "Current RCR settings(%#x)\n", tmpu4b);
335 
336  /* Set to normal mode. */
337  rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL);
338  break;
339 
340  default:
341  RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
342  "Unknown status check!\n");
343  rtstatus = false;
344  break;
345  }
346 
347 status_check_fail:
348  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
349  "loadfw_status(%d), rtstatus(%x)\n",
350  loadfw_status, rtstatus);
351  return rtstatus;
352 }
353 
355 {
356  struct rtl_priv *rtlpriv = rtl_priv(hw);
357  struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
358  struct rt_firmware *firmware = NULL;
359  struct fw_hdr *pfwheader;
360  struct fw_priv *pfw_priv = NULL;
361  u8 *puc_mappedfile = NULL;
362  u32 ul_filelength = 0;
363  u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE;
364  u8 fwstatus = FW_STATUS_INIT;
365  bool rtstatus = true;
366 
367  if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
368  return 1;
369 
370  firmware = (struct rt_firmware *)rtlhal->pfirmware;
371  firmware->fwstatus = FW_STATUS_INIT;
372 
373  puc_mappedfile = firmware->sz_fw_tmpbuffer;
374 
375  /* 1. Retrieve FW header. */
376  firmware->pfwheader = (struct fw_hdr *) puc_mappedfile;
377  pfwheader = firmware->pfwheader;
378  firmware->firmwareversion = byte(pfwheader->version, 0);
379  firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */
380 
381  RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
382  "signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n",
383  pfwheader->signature,
384  pfwheader->version, pfwheader->dmem_size,
385  pfwheader->img_imem_size, pfwheader->img_sram_size);
386 
387  /* 2. Retrieve IMEM image. */
388  if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size >
389  sizeof(firmware->fw_imem))) {
390  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
391  "memory for data image is less than IMEM required\n");
392  goto fail;
393  } else {
394  puc_mappedfile += fwhdr_size;
395 
396  memcpy(firmware->fw_imem, puc_mappedfile,
397  pfwheader->img_imem_size);
398  firmware->fw_imem_len = pfwheader->img_imem_size;
399  }
400 
401  /* 3. Retriecve EMEM image. */
402  if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) {
403  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
404  "memory for data image is less than EMEM required\n");
405  goto fail;
406  } else {
407  puc_mappedfile += firmware->fw_imem_len;
408 
409  memcpy(firmware->fw_emem, puc_mappedfile,
410  pfwheader->img_sram_size);
411  firmware->fw_emem_len = pfwheader->img_sram_size;
412  }
413 
414  /* 4. download fw now */
415  fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
416  while (fwstatus != FW_STATUS_READY) {
417  /* Image buffer redirection. */
418  switch (fwstatus) {
419  case FW_STATUS_LOAD_IMEM:
420  puc_mappedfile = firmware->fw_imem;
421  ul_filelength = firmware->fw_imem_len;
422  break;
423  case FW_STATUS_LOAD_EMEM:
424  puc_mappedfile = firmware->fw_emem;
425  ul_filelength = firmware->fw_emem_len;
426  break;
427  case FW_STATUS_LOAD_DMEM:
428  /* Partial update the content of header private. */
429  pfwheader = firmware->pfwheader;
430  pfw_priv = &pfwheader->fwpriv;
431  _rtl92s_firmwareheader_priveupdate(hw, pfw_priv);
432  puc_mappedfile = (u8 *)(firmware->pfwheader) +
434  ul_filelength = fwhdr_size -
436  break;
437  default:
438  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
439  "Unexpected Download step!!\n");
440  goto fail;
441  break;
442  }
443 
444  /* <2> Download image file */
445  rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile,
446  ul_filelength);
447 
448  if (!rtstatus) {
449  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "fail!\n");
450  goto fail;
451  }
452 
453  /* <3> Check whether load FW process is ready */
454  rtstatus = _rtl92s_firmware_checkready(hw, fwstatus);
455  if (!rtstatus) {
456  RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "fail!\n");
457  goto fail;
458  }
459 
460  fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
461  }
462 
463  return rtstatus;
464 fail:
465  return 0;
466 }
467 
468 static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen,
469  u32 cmd_num, u32 *pelement_id, u32 *pcmd_len,
470  u8 **pcmb_buffer, u8 *cmd_start_seq)
471 {
472  u32 totallen = 0, len = 0, tx_desclen = 0;
473  u32 pre_continueoffset = 0;
474  u8 *ph2c_buffer;
475  u8 i = 0;
476 
477  do {
478  /* 8 - Byte aligment */
479  len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
480 
481  /* Buffer length is not enough */
482  if (h2cbufferlen < totallen + len + tx_desclen)
483  break;
484 
485  /* Clear content */
486  ph2c_buffer = (u8 *)skb_put(skb, (u32)len);
487  memset((ph2c_buffer + totallen + tx_desclen), 0, len);
488 
489  /* CMD len */
490  SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
491  0, 16, pcmd_len[i]);
492 
493  /* CMD ID */
494  SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
495  16, 8, pelement_id[i]);
496 
497  /* CMD Sequence */
498  *cmd_start_seq = *cmd_start_seq % 0x80;
499  SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
500  24, 7, *cmd_start_seq);
501  ++*cmd_start_seq;
502 
503  /* Copy memory */
504  memcpy((ph2c_buffer + totallen + tx_desclen +
505  H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]);
506 
507  /* CMD continue */
508  /* set the continue in prevoius cmd. */
509  if (i < cmd_num - 1)
510  SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset),
511  31, 1, 1);
512 
513  pre_continueoffset = totallen;
514 
515  totallen += len;
516  } while (++i < cmd_num);
517 
518  return totallen;
519 }
520 
521 static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len)
522 {
523  u32 totallen = 0, len = 0, tx_desclen = 0;
524  u8 i = 0;
525 
526  do {
527  /* 8 - Byte aligment */
528  len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
529 
530  /* Buffer length is not enough */
531  if (h2cbufferlen < totallen + len + tx_desclen)
532  break;
533 
534  totallen += len;
535  } while (++i < cmd_num);
536 
537  return totallen + tx_desclen;
538 }
539 
540 static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
541  u8 *pcmd_buffer)
542 {
543  struct rtl_priv *rtlpriv = rtl_priv(hw);
544  struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
545  struct rtl_tcb_desc *cb_desc;
546  struct sk_buff *skb;
547  u32 element_id = 0;
548  u32 cmd_len = 0;
549  u32 len;
550 
551  switch (h2c_cmd) {
552  case FW_H2C_SETPWRMODE:
553  element_id = H2C_SETPWRMODE_CMD ;
554  cmd_len = sizeof(struct h2c_set_pwrmode_parm);
555  break;
556  case FW_H2C_JOINBSSRPT:
557  element_id = H2C_JOINBSSRPT_CMD;
558  cmd_len = sizeof(struct h2c_joinbss_rpt_parm);
559  break;
561  element_id = H2C_WOWLAN_UPDATE_GTK_CMD;
562  cmd_len = sizeof(struct h2c_wpa_two_way_parm);
563  break;
565  element_id = H2C_WOWLAN_UPDATE_IV_CMD;
566  cmd_len = sizeof(unsigned long long);
567  break;
569  element_id = H2C_WOWLAN_FW_OFFLOAD;
570  cmd_len = sizeof(u8);
571  break;
572  default:
573  break;
574  }
575 
576  len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
577  skb = dev_alloc_skb(len);
578  if (!skb)
579  return false;
580  cb_desc = (struct rtl_tcb_desc *)(skb->cb);
581  cb_desc->queue_index = TXCMD_QUEUE;
583  cb_desc->last_inipkt = false;
584 
585  _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id,
586  &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq);
587  _rtl92s_cmd_send_packet(hw, skb, false);
588  rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE);
589 
590  return true;
591 }
592 
594 {
595  struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
596  struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
597  struct h2c_set_pwrmode_parm pwrmode;
598  u16 max_wakeup_period = 0;
599 
600  pwrmode.mode = Mode;
601  pwrmode.flag_low_traffic_en = 0;
602  pwrmode.flag_lpnav_en = 0;
603  pwrmode.flag_rf_low_snr_en = 0;
604  pwrmode.flag_dps_en = 0;
605  pwrmode.bcn_rx_en = 0;
606  pwrmode.bcn_to = 0;
607  SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16,
608  mac->vif->bss_conf.beacon_int);
609  pwrmode.app_itv = 0;
610  pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl;
611  pwrmode.smart_ps = 1;
612  pwrmode.bcn_pass_period = 10;
613 
614  /* Set beacon pass count */
615  if (pwrmode.mode == FW_PS_MIN_MODE)
616  max_wakeup_period = mac->vif->bss_conf.beacon_int;
617  else if (pwrmode.mode == FW_PS_MAX_MODE)
618  max_wakeup_period = mac->vif->bss_conf.beacon_int *
619  mac->vif->bss_conf.dtim_period;
620 
621  if (max_wakeup_period >= 500)
622  pwrmode.bcn_pass_cnt = 1;
623  else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500))
624  pwrmode.bcn_pass_cnt = 2;
625  else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300))
626  pwrmode.bcn_pass_cnt = 3;
627  else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200))
628  pwrmode.bcn_pass_cnt = 5;
629  else
630  pwrmode.bcn_pass_cnt = 1;
631 
632  _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode);
633 
634 }
635 
637  u8 mstatus, u8 ps_qosinfo)
638 {
639  struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
640  struct h2c_joinbss_rpt_parm joinbss_rpt;
641 
642  joinbss_rpt.opmode = mstatus;
643  joinbss_rpt.ps_qos_info = ps_qosinfo;
644  joinbss_rpt.bssid[0] = mac->bssid[0];
645  joinbss_rpt.bssid[1] = mac->bssid[1];
646  joinbss_rpt.bssid[2] = mac->bssid[2];
647  joinbss_rpt.bssid[3] = mac->bssid[3];
648  joinbss_rpt.bssid[4] = mac->bssid[4];
649  joinbss_rpt.bssid[5] = mac->bssid[5];
650  SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16,
651  mac->vif->bss_conf.beacon_int);
652  SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id);
653 
654  _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt);
655 }
656