1 /******************************************************************************
3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
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
19 ******************************************************************************/
20 #include <rtl8723d_hal.h>
22 #ifdef CONFIG_LPS_POFF
23 /****************************************************************************
24 * Function: constuct Register Setting for HW to Backup Before LPS
25 * page 2/4/6/7/8~F and page 0x24(for NAN)
26 *****************************************************************************/
27 static bool hal_construct_poff_static_file(PADAPTER padapter)
29 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
30 lps_poff_info_t *lps_poff_info = NULL;
31 u8 *staticFile = NULL;
33 u8 page_count = 0, page_offset = 0, round = 0;
34 /*There are 256 bytes in each register bank, and 64 dwords*/
36 u16 offset = 0, addr_value = 0;
38 if (pwrpriv->plps_poff_info == NULL) {
39 RTW_INFO("%s: please alloc plps_poff_info first!!\n", __func__);
43 lps_poff_info = pwrpriv->plps_poff_info;
45 if (lps_poff_info->pStaticFile == NULL) {
46 RTW_INFO("%s: please alloc static configure file first!!\n",
50 staticFile = lps_poff_info->pStaticFile + TXDESC_SIZE;
52 for (page_count = 2 ; page_count < 16 ; page_count++) {
54 if (page_count == 3 || page_count == 5)
57 offset = (round << 9);
59 for (page_offset = 0 ; page_offset < total ; page_offset++) {
60 start_at = staticFile + offset + (page_offset << 3);
62 ((page_count << 8) + (page_offset << 2)) >> 2;
64 SET_HOIE_ENTRY_LOW_DATA(start_at, 0);
65 SET_HOIE_ENTRY_HIGH_DATA(start_at, 0);
66 SET_HOIE_ENTRY_MODE_SELECT(start_at, 0);
67 SET_HOIE_ENTRY_ADDRESS(start_at, addr_value);
68 SET_HOIE_ENTRY_BYTE_MASK(start_at, 0xF);
69 SET_HOIE_ENTRY_IO_LOCK(start_at, 0);
70 SET_HOIE_ENTRY_WR_EN(start_at, 1);
71 SET_HOIE_ENTRY_RD_EN(start_at, 1);
72 SET_HOIE_ENTRY_RAW_RW(start_at, 0);
73 SET_HOIE_ENTRY_RAW(start_at, 0);
74 SET_HOIE_ENTRY_IO_DELAY(start_at, 0);
81 offset = (round << 9);
82 for (page_offset = 0 ; page_offset < total ; page_offset++) {
83 start_at = staticFile + offset + (page_offset << 3);
84 addr_value = ((0x24 << 8) + (page_offset << 2)) >> 2;
86 SET_HOIE_ENTRY_LOW_DATA(start_at, 0);
87 SET_HOIE_ENTRY_HIGH_DATA(start_at, 0);
88 SET_HOIE_ENTRY_MODE_SELECT(start_at, 0);
89 SET_HOIE_ENTRY_ADDRESS(start_at, addr_value);
90 SET_HOIE_ENTRY_BYTE_MASK(start_at, 0xF);
91 SET_HOIE_ENTRY_IO_LOCK(start_at, 0);
92 SET_HOIE_ENTRY_WR_EN(start_at, 1);
93 SET_HOIE_ENTRY_RD_EN(start_at, 1);
94 SET_HOIE_ENTRY_RAW_RW(start_at, 0);
95 SET_HOIE_ENTRY_RAW(start_at, 0);
96 SET_HOIE_ENTRY_IO_DELAY(start_at, 0);
98 RTW_INFO("%s: (round << 9) + (PageOffset << 3) = %#08x\n",
99 __func__, offset + (page_offset << 3));
101 start_at = staticFile + offset + (page_offset << 3);
102 /* add last command: 00 00 00 00 00 40 30 00,suggested by DD */
108 *(start_at + 5) = 0x40;
109 *(start_at + 6) = 0x30;
115 /****************************************************************************
116 Function: send Location of configuration file and other info for FW
117 *****************************************************************************/
118 static void rtl8723d_lps_poff_h2c_param(PADAPTER padapter, u8 tx_bndy, u16 len,
121 u8 lps_poff_param[H2C_LPS_POFF_PARAM_LEN] = {0};
122 u8 start_addr_l = 0, start_addr_h = 0;
123 u8 end_addr_l = 0, end_addr_h = 0;
124 u16 start_addr = 0, end_addr = 0;
129 set start address, The parameter is entrys. every page has 16 entrys
130 The Tx Descriptor is 40Byte which locate 5 entries
133 start_addr = (tx_bndy << 4) + 5;
134 end_addr = start_addr + (len >> 3) - 1;
136 RTW_INFO("%s: start_addr = %#02X, end_addr= %#02X\n",
137 __func__, start_addr, end_addr);
139 start_addr_l = (u8)start_addr;
140 start_addr_h = (u8)(start_addr >> 8);
142 end_addr_l = (u8)end_addr;
143 end_addr_h = (u8)(end_addr >> 8);
145 /*construct H2C Cmd*/
147 SET_H2CCMD_LPS_POFF_PARAM_RDVLD(lps_poff_param, 0);
149 SET_H2CCMD_LPS_POFF_PARAM_RDVLD(lps_poff_param, 1);
151 SET_H2CCMD_LPS_POFF_PARAM_WRVLD(lps_poff_param, 1);
152 SET_H2CCMD_LPS_POFF_PARAM_STARTADDL(lps_poff_param, start_addr_l);
153 SET_H2CCMD_LPS_POFF_PARAM_STARTADDH(lps_poff_param, start_addr_h);
154 SET_H2CCMD_LPS_POFF_PARAM_ENDADDL(lps_poff_param, end_addr_l);
155 SET_H2CCMD_LPS_POFF_PARAM_ENDADDH(lps_poff_param, end_addr_h);
157 rtw_hal_fill_h2c_cmd(padapter, H2C_LPS_POFF_PARAM,
158 H2C_LPS_POFF_PARAM_LEN, lps_poff_param);
161 /*************************************************************************
162 Function: SET Location of Configuration File to FW
163 **************************************************************************/
164 static void rtl8723d_lps_poff_set_param(PADAPTER padapter)
166 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
167 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
169 u8 static_tx_bndy = 0;
170 u8 dynamic_tx_bndy = 0;
171 u16 static_len = 0, dynamic_len = 0;
173 static_tx_bndy = plps_poff_info->tx_bndy_static;
174 dynamic_tx_bndy = plps_poff_info->tx_bndy_dynamic;
176 dynamic_len = plps_poff_info->ConfLenForPTK +
177 plps_poff_info->ConfLenForGTK;
179 if (ATOMIC_READ(&plps_poff_info->bSetPOFFParm) == _TRUE)
182 /* download static configuration */
183 static_len = LPS_POFF_STATIC_FILE_LEN - TXDESC_SIZE;
184 rtl8723d_lps_poff_h2c_param(padapter, static_tx_bndy,
187 /* download dynamic configuration */
188 /* the length must be add more 8 Byte due to hard bug */
189 if (dynamic_len != 0) {
191 rtl8723d_lps_poff_h2c_param(padapter, dynamic_tx_bndy,
195 ATOMIC_SET(&plps_poff_info->bSetPOFFParm, _TRUE);
199 /****************************************************************************
200 Function: change tx boundary
201 *****************************************************************************/
202 static void rtl8723d_lps_poff_set_tx_bndy(PADAPTER padapter, u8 tx_bndy)
212 #if (DEV_BUS_TYPE == RT_PCI_INTERFACE)
216 numPubQ = tx_bndy - numHQ - numLQ - numNQ - 1;
218 val32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN;
220 rtw_write8(padapter, REG_RQPN_NPQ, val8);
221 rtw_write32(padapter, REG_RQPN, val32);
224 /****************************************************************************
225 Function: change tx boundary flow
226 *****************************************************************************/
227 static bool rtl8723d_lps_poff_tx_bndy_flow(PADAPTER padapter, bool enable)
229 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
230 struct xmit_priv *pxmitpriv;
231 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
232 u8 tx_bndy = 0, tx_bndy_new = 0, count = 0, queue_pending = _FALSE;
237 pxmitpriv = &padapter->xmitpriv;
238 rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_BOUNDARY, (u8 *)&tx_bndy);
240 RTW_INFO("%s: tx_bndy: %#X, tx_bndy_static: %#X\n",
241 __func__, tx_bndy, plps_poff_info->tx_bndy_static);
244 tx_bndy_new = plps_poff_info->tx_bndy_static + 1;
246 tx_bndy_new = tx_bndy;
248 ATOMIC_SET(&plps_poff_info->bTxBoundInProgress, _TRUE);
250 /* stop os layer TX*/
251 rtw_mi_netif_stop_queue(padapter, _FALSE);
253 val16 = rtw_read16(padapter, REG_TXPKT_EMPTY);
255 /* stop tx process and wait tx empty */
256 while ((val16 & 0x05FF) != 0x05FF) {
258 val16 = rtw_read16(padapter, REG_TXPKT_EMPTY);
262 val16 = rtw_read16(padapter, REG_TXPKT_EMPTY);
263 RTW_INFO("%s, txpkt_empty: %#04x\n", __func__, val16);
264 val8 = rtw_read8(padapter, REG_CPU_MGQ_INFORMATION);
265 RTW_INFO("%s, REG_CPU_MGQ_INFORMATION: %#02x\n",
267 RTW_INFO("%s, wait for tx empty timeout!!\n", __func__);
268 ATOMIC_SET(&plps_poff_info->bTxBoundInProgress, _FALSE);
269 rtw_mi_netif_wake_queue(padapter);
274 /* change tx boundary*/
275 rtl8723d_lps_poff_set_tx_bndy(padapter, tx_bndy_new);
278 val32 = rtw_read32(padapter, REG_FWHW_TXQ_CTRL);
280 rtw_write32(padapter, REG_FWHW_TXQ_CTRL, val32);
281 rtw_write8(padapter, REG_BCNQ_BDNY, tx_bndy_new);
283 RTW_INFO("%s: free tail = %#x after\n", __func__,
284 rtw_read8(padapter, REG_FW_FREE_TAIL_8723D));
287 val32 = rtw_read32(padapter, REG_FWHW_TXQ_CTRL);
289 rtw_write32(padapter, REG_FWHW_TXQ_CTRL, val32);
290 rtw_write8(padapter, REG_BCNQ_BDNY, tx_bndy);
293 rtl8723d_InitLLTTable(padapter);
296 val32 = rtw_read32(padapter, REG_TXDMA_STATUS);
299 RTW_INFO("%s: REG_TXDMA_STATUS: %#08x\n", __func__, val32);
300 rtw_write32(padapter, REG_TXDMA_STATUS, val32);
303 ATOMIC_SET(&plps_poff_info->bTxBoundInProgress, _FALSE);
308 rtw_mi_netif_wake_queue(padapter);
313 /****************************************************************************
314 Function: Append extra bytes for dynamic confiure file
315 Add one entry to fix hw bug,
316 list command: 00 00 00 00 00 40 30 00, suggested by DD
317 *****************************************************************************/
318 static u8 rtl8723d_lps_poff_append_extra_info(PADAPTER padapter, u32 len)
320 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
321 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
322 u32 data_offset = len + plps_poff_info->ConfFileOffset;
324 *(plps_poff_info->pDynamicFile + (data_offset)) = 0x00;
325 *(plps_poff_info->pDynamicFile + (data_offset + 1)) = 0x00;
326 *(plps_poff_info->pDynamicFile + (data_offset + 2)) = 0x00;
327 *(plps_poff_info->pDynamicFile + (data_offset + 3)) = 0x00;
328 *(plps_poff_info->pDynamicFile + (data_offset + 4)) = 0x00;
329 *(plps_poff_info->pDynamicFile + (data_offset + 5)) = 0x40;
330 *(plps_poff_info->pDynamicFile + (data_offset + 6)) = 0x30;
331 *(plps_poff_info->pDynamicFile + (data_offset + 7)) = 0x00;
335 /****************************************************************************
336 Function: xmit config file to write port.
337 *****************************************************************************/
338 static void rtl8723d_lps_poff_send_config_frame(PADAPTER padapter,
341 struct xmit_frame *pcmdframe = NULL;
342 struct pkt_attrib *pattrib;
343 struct xmit_priv *pxmitpriv;
346 pxmitpriv = &padapter->xmitpriv;
347 pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
349 if (pcmdframe == NULL)
350 RTW_INFO("%s: alloc cmdframe fail\n", __func__);
352 _rtw_memcpy(pcmdframe->buf_addr, pFile, len);
354 pattrib = &pcmdframe->attrib;
355 update_mgntframe_attrib(padapter, pattrib);
356 pattrib->qsel = QSLT_BEACON;
357 pattrib->pktlen = len - TXDESC_OFFSET;
358 pattrib->last_txcmdsz = len - TXDESC_OFFSET;
360 RTW_INFO("%s, len: %d, MAX_CMDBUF_SZ: %d\n", __func__, len,
362 #ifdef CONFIG_PCI_HCI
363 dump_mgntframe(padapter, pcmdframe);
365 dump_mgntframe_and_wait(padapter, pcmdframe, 100);
370 /****************************************************************************
371 Function: download config file flow
372 *****************************************************************************/
373 static void rtl8723d_lps_poff_send_config_file(PADAPTER padapter,
374 u8 *pFile, u8 loc, u32 len)
376 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
377 bool bRecover = _FALSE, bcn_valid = _FALSE;
378 u8 DLBcnCount = 0, val8 = 0, tx_bndy = 0;
381 rtw_hal_get_def_var(padapter,
382 HAL_DEF_TX_PAGE_BOUNDARY, (u8 *)&tx_bndy);
384 /* set 0x100[8]=1 for SW beacon */
385 val8 = rtw_read8(padapter, REG_CR + 1);
387 rtw_write8(padapter, REG_CR + 1, val8);
389 /*set 0x422[6]=0 to disable beacon DMA pass to MACTx*/
391 if (pHalData->RegFwHwTxQCtrl & BIT(6))
394 rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
395 pHalData->RegFwHwTxQCtrl & ~BIT(6));
396 pHalData->RegFwHwTxQCtrl &= ~BIT(6);
398 /* Clear beacon valid check bit. */
399 rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
400 rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
402 /* set 0x209[7:0] beacon queue head page to start download location */
403 rtw_write8(padapter, REG_TDECTRL_8723D + 1, loc);
409 rtl8723d_lps_poff_send_config_frame(padapter, pFile, len);
413 /*check rsvd page download OK.*/
414 rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID,
417 } while (!bcn_valid && (poll % 10) != 0
418 && !RTW_CANNOT_RUN(padapter));
419 } while (!bcn_valid && DLBcnCount <= 100 && !RTW_CANNOT_RUN(padapter));
422 RTW_INFO(ADPT_FMT": 1 DL RSVD page failed! DLBcnCount:%u, poll:%u\n",
423 ADPT_ARG(padapter), DLBcnCount, poll);
425 RTW_INFO(ADPT_FMT": 1 DL RSVD page success! DLBcnCount:%u, poll:%u\n",
426 ADPT_ARG(padapter), DLBcnCount, poll);
428 /*restore bcn operation*/
429 rtw_write8(padapter, REG_TDECTRL_8723D + 1, tx_bndy);
431 /*restore 0x422[6]=1 for normal bcn*/
433 rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
434 pHalData->RegFwHwTxQCtrl | BIT(6));
435 pHalData->RegFwHwTxQCtrl |= BIT(6);
438 /*restore 0x100[8]=0 for SW beacon*/
439 /* Clear CR[8] or beacon packet will not be send to TxBuf anymore.*/
440 #ifndef CONFIG_PCI_HCI
441 val8 = rtw_read8(padapter, REG_CR + 1);
443 rtw_write8(padapter, REG_CR + 1, val8);
447 /****************************************************************************
448 Function: Prepare Confiure File
449 *****************************************************************************/
450 static void rtl8723d_lps_poff_dl_config_file(PADAPTER padapter)
452 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
453 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
454 u8 count = 0, append_len = 0;
455 u32 offset = 0, static_file_len = 0, dynamic_file_len = 0;
458 offset = plps_poff_info->ConfFileOffset;
460 static_file_len = LPS_POFF_STATIC_FILE_LEN - offset;
463 plps_poff_info->ConfLenForPTK + plps_poff_info->ConfLenForGTK;
465 RTW_INFO("%s: static_file_len: %d dynamic_file_len: %d, offset: %d\n",
466 __func__, static_file_len, dynamic_file_len, offset);
469 rtl8723d_lps_poff_send_config_file(padapter,
470 plps_poff_info->pStaticFile + offset,
471 plps_poff_info->tx_bndy_static,
475 if (dynamic_file_len != 0) {
476 dynamic_file_len += TXDESC_SIZE - offset;
479 rtl8723d_lps_poff_append_extra_info(padapter,
481 dynamic_file_len += append_len;
482 rtl8723d_lps_poff_send_config_file(padapter,
483 plps_poff_info->pDynamicFile + offset,
484 plps_poff_info->tx_bndy_dynamic,
489 static u8 rtl8723d_lps_poff_set_dynamic_file(u8 *pFile, u32 type, u32 wdata)
491 SET_HOIE_ENTRY_LOW_DATA(pFile, (u16)wdata);
492 SET_HOIE_ENTRY_HIGH_DATA(pFile, (u16)(wdata >> 16));
493 SET_HOIE_ENTRY_MODE_SELECT(pFile, 0);
494 SET_HOIE_ENTRY_ADDRESS(pFile, (type >> 2));
495 SET_HOIE_ENTRY_BYTE_MASK(pFile, 0xF);
496 SET_HOIE_ENTRY_IO_LOCK(pFile, 0);
497 SET_HOIE_ENTRY_WR_EN(pFile, 1);
498 SET_HOIE_ENTRY_RD_EN(pFile, 0);
499 SET_HOIE_ENTRY_RAW_RW(pFile, 0);
500 SET_HOIE_ENTRY_RAW(pFile, 0);
501 SET_HOIE_ENTRY_IO_DELAY(pFile, 0);
506 static void rtl8723d_lps_poff_dynamic_file(PADAPTER padapter, u8 index, u8 isGK)
508 struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
509 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
510 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
513 u32 tgt_cmd = 0, tgt_wdata = 0;
516 for (i = 0 ; i < CAM_CONTENT_COUNT; i++) {
518 ptkfile = plps_poff_info->pDynamicFile +
519 plps_poff_info->ConfLenForPTK + TXDESC_SIZE;
521 ptkfile = plps_poff_info->pDynamicFile +
522 plps_poff_info->ConfLenForPTK +
523 plps_poff_info->ConfLenForGTK + TXDESC_SIZE;
525 tgt_cmd = i + (CAM_CONTENT_COUNT * index);
526 tgt_cmd = tgt_cmd | CAM_POLLINIG | CAM_WRITE;
530 tgt_wdata = dvobj->cam_cache[index].ctrl |
531 dvobj->cam_cache[index].mac[0] << 16 |
532 dvobj->cam_cache[index].mac[1] << 24;
535 tgt_wdata = dvobj->cam_cache[index].mac[2] |
536 dvobj->cam_cache[index].mac[3] << 8 |
537 dvobj->cam_cache[index].mac[4] << 16 |
538 dvobj->cam_cache[index].mac[5] << 24;
543 dvobj->cam_cache[index].key[j + 3] << 24 |
544 dvobj->cam_cache[index].key[j + 2] << 16 |
545 dvobj->cam_cache[index].key[j + 1] << 8 |
546 dvobj->cam_cache[index].key[j];
550 ret = rtl8723d_lps_poff_set_dynamic_file(ptkfile,
554 plps_poff_info->ConfLenForPTK += ret;
556 ptkfile = plps_poff_info->pDynamicFile +
557 plps_poff_info->ConfLenForPTK + TXDESC_SIZE;
559 plps_poff_info->ConfLenForGTK += ret;
560 ptkfile = plps_poff_info->pDynamicFile +
561 plps_poff_info->ConfLenForPTK +
562 plps_poff_info->ConfLenForGTK + TXDESC_SIZE;
565 ret = rtl8723d_lps_poff_set_dynamic_file(ptkfile,
569 plps_poff_info->ConfLenForPTK += ret;
571 plps_poff_info->ConfLenForGTK += ret;
574 RTW_INFO("%s: tgt_wdata: %#08x\n", __func__, tgt_wdata);
579 static void rtl8723d_lps_poff_sec_cam_opt(PADAPTER padapter)
581 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
582 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
583 struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
584 struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl;
585 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
586 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
588 u8 isValid = 0, isGK = 0, index = 0, key_id = 0xff, gk_start = 0xff;
589 u16 val16 = 0, len = 0;
591 /*Using cam cache to create config file for FW use.*/
592 /*1- deail with pairwise key*/
594 for (i = 0 ; i < cam_ctl->num ; i++) {
596 val16 = dvobj->cam_cache[i].ctrl;
597 isValid = (val16 >> 15) & 0x01;
598 isGK = (val16 >> 6) & 0x01;
600 if (isValid && !isGK) {
601 rtl8723d_lps_poff_dynamic_file(padapter, i, _FALSE);
602 RTW_INFO("%s: id: %2u, kid: %3u, ctrl: %#04x, "MAC_FMT""KEY_FMT"\n",
603 __func__, i, (dvobj->cam_cache[i].ctrl) & 0x03,
604 dvobj->cam_cache[i].ctrl,
605 MAC_ARG(dvobj->cam_cache[i].mac),
606 KEY_ARG(dvobj->cam_cache[i].key));
608 key_id = dvobj->cam_cache[i].ctrl & 0x03;
609 if (key_id == pmlmeinfo->key_index)
611 RTW_INFO("%s: GK_start at %d\n", __func__, gk_start);
612 RTW_INFO("%s: id: %2u, kid: %3u, ctrl: %#04x, "MAC_FMT""KEY_FMT"\n",
613 __func__, i, key_id, dvobj->cam_cache[i].ctrl,
614 MAC_ARG(dvobj->cam_cache[i].mac),
615 KEY_ARG(dvobj->cam_cache[i].key));
619 /*2- deail with group key*/
620 rtl8723d_lps_poff_dynamic_file(padapter, gk_start, _TRUE);
622 RTW_INFO("%s: ConfLenForPTK: %d, ConfLenForGTK: %d\n", __func__,
623 plps_poff_info->ConfLenForPTK, plps_poff_info->ConfLenForGTK);
626 /****************************************************************************
627 Function: Prepare enter LPS partial off status.
628 change tx boundary, download configuration file if necessary and send info to FW
629 *****************************************************************************/
630 static bool rtl8723d_prepare_for_enter_poff(PADAPTER padapter, bool bEnterLPS)
632 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
633 struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
634 struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl;
635 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
637 u8 i = 0, cam_cache_num = 0;
639 for (i = 0 ; i < cam_ctl->num; i++) {
640 if (dvobj->cam_cache[i].ctrl != 0)
644 ret = rtl8723d_lps_poff_tx_bndy_flow(padapter, bEnterLPS);
647 if (cam_cache_num > 0) {
648 rtl8723d_lps_poff_sec_cam_opt(padapter);
650 plps_poff_info->ConfLenForPTK = 0;
651 plps_poff_info->ConfLenForGTK = 0;
653 rtl8723d_lps_poff_dl_config_file(padapter);
654 rtl8723d_lps_poff_set_param(padapter);
659 /*************************************************************************
660 Function: SET H2C To Enable Partial Off
661 **************************************************************************/
662 void rtl8723d_lps_poff_h2c_ctrl(PADAPTER padapter, u8 en)
664 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
665 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
666 struct registry_priv *pregistrypriv = &padapter->registrypriv;
667 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
670 if (pregistrypriv->wifi_spec == 1)
673 if (plps_poff_info->bEn == _FALSE)
676 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
678 RTW_INFO("%s: enable case\n", __func__);
679 SET_H2CCMD_LPS_POFF_CTRL_EN(¶m, 1);
681 RTW_INFO("%s: disable case\n", __func__);
682 ATOMIC_SET(&plps_poff_info->bSetPOFFParm, _FALSE);
683 SET_H2CCMD_LPS_POFF_CTRL_EN(¶m, 0);
685 rtw_hal_fill_h2c_cmd(padapter, H2C_LPS_POFF_CTRL,
686 H2C_LPS_POFF_CTRL_LEN, ¶m);
690 /*************************************************************************
691 Function: The operation to Enter or Leave FWLPS 32K when partial off enable
692 **************************************************************************/
693 void rtl8723d_lps_poff_set_ps_mode(PADAPTER padapter, bool bEnterLPS)
696 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
697 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
698 struct registry_priv *pregistrypriv = &padapter->registrypriv;
701 if (pregistrypriv->wifi_spec == 1)
704 if (plps_poff_info->bEn) {
706 plps_poff_info->ConfLenForPTK = 0;
707 plps_poff_info->ConfLenForGTK = 0;
710 res = rtl8723d_prepare_for_enter_poff(padapter,
712 ATOMIC_SET(&plps_poff_info->bEnterPOFF, res);
714 rtl8723d_lps_poff_tx_bndy_flow(padapter, bEnterLPS);
718 /*************************************************************************
719 Function: Get LPS-POFF Enter Status
720 **************************************************************************/
721 bool rtl8723d_lps_poff_get_status(PADAPTER padapter)
723 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
724 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
725 struct registry_priv *pregistrypriv = &padapter->registrypriv;
727 if (pregistrypriv->wifi_spec == 1) {
728 RTW_INFO("%s: wifi_spec is enable\n", __func__);
732 if (plps_poff_info->bEn == _FALSE) {
733 RTW_INFO("%s: POFF is disable\n", __func__);
737 return ATOMIC_READ(&plps_poff_info->bEnterPOFF);
740 /*************************************************************************
741 Function: Get LPS-POFF change tx bndy status
742 **************************************************************************/
743 bool rtl8723d_lps_poff_get_txbndy_status(PADAPTER padapter)
745 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
746 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
748 return ATOMIC_READ(&plps_poff_info->bTxBoundInProgress);
751 /*************************************************************************
752 Function: Get LPS-POFF initial
753 **************************************************************************/
754 void rtl8723d_lps_poff_init(PADAPTER padapter)
756 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
757 struct registry_priv *pregistrypriv = &padapter->registrypriv;
758 lps_poff_info_t *lps_poff_info;
759 u8 tx_bndy = 0, page_size = 0, total_page = 0, page_num = 0;
762 if (pregistrypriv->wifi_spec == 1)
765 if (is_primary_adapter(padapter)) {
767 rtw_hal_get_def_var(padapter,
768 HAL_DEF_TX_PAGE_BOUNDARY, (u8 *)&val);
771 rtw_hal_get_def_var(padapter,
772 HAL_DEF_TX_PAGE_SIZE, (u8 *)&val);
775 total_page = PageNum(LPS_POFF_STATIC_FILE_LEN, page_size) +
776 PageNum(LPS_POFF_DYNAMIC_FILE_LEN, page_size);
779 (lps_poff_info_t *)rtw_zmalloc(sizeof(lps_poff_info_t));
781 if (lps_poff_info != NULL) {
782 pwrpriv->plps_poff_info = lps_poff_info;
784 lps_poff_info->pStaticFile =
785 (u8 *)rtw_zmalloc(LPS_POFF_STATIC_FILE_LEN);
786 if (lps_poff_info->pStaticFile == NULL) {
787 RTW_INFO("%s: alloc pStaticFile fail\n",
789 goto alloc_static_conf_file_fail;
791 pwrpriv->plps_poff_info->pStaticFile =
792 lps_poff_info->pStaticFile;
795 lps_poff_info->pDynamicFile =
796 (u8 *)rtw_zmalloc(LPS_POFF_DYNAMIC_FILE_LEN);
797 if (lps_poff_info->pDynamicFile == NULL) {
798 RTW_INFO("%s: alloc pDynamicFile fail\n",
800 goto alloc_dynamic_conf_file_fail;
802 pwrpriv->plps_poff_info->pDynamicFile =
803 lps_poff_info->pDynamicFile;
806 pwrpriv->plps_poff_info->bEn = _TRUE;
807 ATOMIC_SET(&pwrpriv->plps_poff_info->bEnterPOFF,
809 ATOMIC_SET(&pwrpriv->plps_poff_info->bSetPOFFParm,
811 ATOMIC_SET(&pwrpriv->plps_poff_info->bTxBoundInProgress,
813 #ifdef CONFIG_PCI_HCI
814 pwrpriv->plps_poff_info->ConfFileOffset = 40;
816 pwrpriv->plps_poff_info->ConfFileOffset = 0;
818 pwrpriv->plps_poff_info->tx_bndy_static =
819 tx_bndy - total_page;
820 page_num = PageNum(LPS_POFF_DYNAMIC_FILE_LEN,
822 pwrpriv->plps_poff_info->tx_bndy_dynamic =
825 construct static DLConfiguration File
827 hal_construct_poff_static_file(padapter);
830 RTW_INFO("%s: alloc lps_poff_info fail\n", __func__);
835 alloc_dynamic_conf_file_fail:
836 rtw_mfree((u8 *)pwrpriv->plps_poff_info->pStaticFile,
837 LPS_POFF_STATIC_FILE_LEN);
838 pwrpriv->plps_poff_info->pStaticFile = NULL;
839 alloc_static_conf_file_fail:
840 rtw_mfree((u8 *)pwrpriv->plps_poff_info, sizeof(lps_poff_info_t));
841 pwrpriv->plps_poff_info = NULL;
846 /*************************************************************************
847 Function: Get LPS-POFF de-initial
848 **************************************************************************/
849 void rtl8723d_lps_poff_deinit(PADAPTER padapter)
851 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
852 lps_poff_info_t *plps_poff_info = pwrpriv->plps_poff_info;
853 struct registry_priv *pregistrypriv = &padapter->registrypriv;
855 if (pregistrypriv->wifi_spec == 1)
858 if (is_primary_adapter(padapter)) {
859 if (plps_poff_info->pDynamicFile != NULL) {
860 rtw_mfree((u8 *)plps_poff_info->pDynamicFile,
861 LPS_POFF_DYNAMIC_FILE_LEN);
862 plps_poff_info->pDynamicFile = NULL;
864 if (plps_poff_info->pStaticFile != NULL) {
865 rtw_mfree((u8 *)plps_poff_info->pStaticFile,
866 LPS_POFF_STATIC_FILE_LEN);
867 plps_poff_info->pStaticFile = NULL;
869 if (plps_poff_info != NULL) {
870 rtw_mfree((u8 *)plps_poff_info,
871 sizeof(lps_poff_info_t));
872 plps_poff_info = NULL;