1 /******************************************************************************
2 *
3 * Copyright(c) 2016 - 2017 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 *****************************************************************************/
15 /* ************************************************************
16 * Description:
17 *
18 * This file is for 8821C dynamic mechanism
19 *
20 *
21 * ************************************************************ */
22 #define _RTL8812C_DM_C_
23
24 /* ************************************************************
25 * include files
26 * ************************************************************
27 */
28
29 #include <drv_types.h>
30 #include <rtl8821c_hal.h>
31
32 /* ************************************************************
33 * Global var
34 * ************************************************************ */
35 #ifdef CONFIG_SUPPORT_HW_WPS_PBC
dm_CheckPbcGPIO(PADAPTER adapter)36 static void dm_CheckPbcGPIO(PADAPTER adapter)
37 {
38 u8 tmp1byte;
39 u8 bPbcPressed = _FALSE;
40
41 if (!adapter->registrypriv.hw_wps_pbc)
42 return;
43
44 #ifdef CONFIG_USB_HCI
45 tmp1byte = rtw_read8(adapter, GPIO_IO_SEL);
46 tmp1byte |= (HAL_8192C_HW_GPIO_WPS_BIT);
47 rtw_write8(adapter, GPIO_IO_SEL, tmp1byte); /* enable GPIO[2] as output mode */
48
49 tmp1byte &= ~(HAL_8192C_HW_GPIO_WPS_BIT);
50 rtw_write8(adapter, GPIO_IN, tmp1byte); /* reset the floating voltage level */
51
52 tmp1byte = rtw_read8(adapter, GPIO_IO_SEL);
53 tmp1byte &= ~(HAL_8192C_HW_GPIO_WPS_BIT);
54 rtw_write8(adapter, GPIO_IO_SEL, tmp1byte); /* enable GPIO[2] as input mode */
55
56 tmp1byte = rtw_read8(adapter, GPIO_IN);
57 if (tmp1byte == 0xff)
58 return;
59
60 if (tmp1byte & HAL_8192C_HW_GPIO_WPS_BIT)
61 bPbcPressed = _TRUE;
62 #else
63 tmp1byte = rtw_read8(adapter, GPIO_IN);
64
65 if ((tmp1byte == 0xff) || adapter->init_adpt_in_progress)
66 return;
67
68 if ((tmp1byte & HAL_8192C_HW_GPIO_WPS_BIT) == 0)
69 bPbcPressed = _TRUE;
70 #endif
71
72 if (_TRUE == bPbcPressed) {
73 /*
74 * Here we only set bPbcPressed to true
75 * After trigger PBC, the variable will be set to false
76 */
77 RTW_INFO("CheckPbcGPIO - PBC is pressed\n");
78 rtw_request_wps_pbc_event(adapter);
79 }
80 }
81 #endif /* CONFIG_SUPPORT_HW_WPS_PBC */
82
83
84 #ifdef CONFIG_PCI_HCI
85 /*
86 * Description:
87 * Perform interrupt migration dynamically to reduce CPU utilization.
88 *
89 * Assumption:
90 * 1. Do not enable migration under WIFI test.
91 */
dm_InterruptMigration(PADAPTER adapter)92 void dm_InterruptMigration(PADAPTER adapter)
93 {
94 PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
95 struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
96 BOOLEAN bCurrentIntMt, bCurrentACIntDisable;
97 BOOLEAN IntMtToSet = _FALSE;
98 BOOLEAN ACIntToSet = _FALSE;
99
100
101 /* Retrieve current interrupt migration and Tx four ACs IMR settings first. */
102 bCurrentIntMt = hal->bInterruptMigration;
103 bCurrentACIntDisable = hal->bDisableTxInt;
104
105 /*
106 * <Roger_Notes> Currently we use busy traffic for reference instead of RxIntOK counts to prevent non-linear Rx statistics
107 * when interrupt migration is set before. 2010.03.05.
108 */
109 if (!adapter->registrypriv.wifi_spec
110 && (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _TRUE)
111 && pmlmepriv->LinkDetectInfo.bHigherBusyTraffic) {
112 IntMtToSet = _TRUE;
113
114 /* To check whether we should disable Tx interrupt or not. */
115 if (pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic)
116 ACIntToSet = _TRUE;
117 }
118
119 /* Update current settings. */
120 if (bCurrentIntMt != IntMtToSet) {
121 RTW_INFO("%s: Update interrrupt migration(%d)\n", __FUNCTION__, IntMtToSet);
122 if (IntMtToSet) {
123 /*
124 * <Roger_Notes> Set interrrupt migration timer and corresponging Tx/Rx counter.
125 * timer 25ns*0xfa0=100us for 0xf packets.
126 * 2010.03.05.
127 */
128 rtw_write32(adapter, REG_INT_MIG, 0xff000fa0); /* 0x306:Rx, 0x307:Tx */
129 hal->bInterruptMigration = IntMtToSet;
130 } else {
131 /* Reset all interrupt migration settings. */
132 rtw_write32(adapter, REG_INT_MIG, 0);
133 hal->bInterruptMigration = IntMtToSet;
134 }
135 }
136 }
137 #endif /* CONFIG_PCI_HCI */
138
139 /*
140 * ============================================================
141 * functions
142 * ============================================================
143 */
init_phydm_cominfo(PADAPTER adapter)144 static void init_phydm_cominfo(PADAPTER adapter)
145 {
146 PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
147 struct dm_struct *pDM_Odm = &hal->odmpriv;
148
149 Init_ODM_ComInfo(adapter);
150
151 odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_PACKAGE_TYPE, hal->PackageType);
152
153 RTW_INFO("%s: Fv=%d Cv=%d\n", __FUNCTION__, hal->version_id.VendorType, hal->version_id.CUTVersion);
154 odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_FAB_VER, hal->version_id.VendorType);
155 odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_CUT_VER, hal->version_id.CUTVersion);
156
157 }
158
rtl8821c_phy_init_dm_priv(PADAPTER adapter)159 void rtl8821c_phy_init_dm_priv(PADAPTER adapter)
160 {
161 struct dm_struct *phydm = adapter_to_phydm(adapter);
162
163 init_phydm_cominfo(adapter);
164 odm_init_all_timers(phydm);
165 }
166
rtl8821c_phy_deinit_dm_priv(PADAPTER adapter)167 void rtl8821c_phy_deinit_dm_priv(PADAPTER adapter)
168 {
169 struct dm_struct *phydm = adapter_to_phydm(adapter);
170
171 odm_cancel_all_timers(phydm);
172 }
173
rtl8821c_phy_init_haldm(PADAPTER adapter)174 void rtl8821c_phy_init_haldm(PADAPTER adapter)
175 {
176 rtw_phydm_init(adapter);
177 }
178
check_rxfifo_full(PADAPTER adapter)179 static void check_rxfifo_full(PADAPTER adapter)
180 {
181 struct dvobj_priv *psdpriv = adapter->dvobj;
182 struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
183 struct registry_priv *regsty = &adapter->registrypriv;
184 u8 val8 = 0;
185
186 if (regsty->check_hw_status == 1) {
187 /* switch counter to RX fifo */
188 val8 = rtw_read8(adapter, REG_RXERR_RPT_8821C + 3);
189 rtw_write8(adapter, REG_RXERR_RPT_8821C + 3, (val8 | 0xa0));
190
191 pdbgpriv->dbg_rx_fifo_last_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow;
192 pdbgpriv->dbg_rx_fifo_curr_overflow = rtw_read16(adapter, REG_RXERR_RPT_8821C);
193 if (pdbgpriv->dbg_rx_fifo_curr_overflow >= pdbgpriv->dbg_rx_fifo_last_overflow)
194 pdbgpriv->dbg_rx_fifo_diff_overflow =
195 pdbgpriv->dbg_rx_fifo_curr_overflow - pdbgpriv->dbg_rx_fifo_last_overflow;
196 else
197 pdbgpriv->dbg_rx_fifo_diff_overflow =
198 (0xFFFF - pdbgpriv->dbg_rx_fifo_last_overflow)
199 + pdbgpriv->dbg_rx_fifo_curr_overflow;
200
201 }
202 }
203
204
rtl8821c_phy_haldm_watchdog(PADAPTER Adapter)205 void rtl8821c_phy_haldm_watchdog(PADAPTER Adapter)
206 {
207 BOOLEAN bFwCurrentInPSMode = _FALSE;
208 u8 bFwPSAwake = _TRUE;
209 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter);
210 u8 in_lps = _FALSE;
211 PADAPTER current_lps_iface = NULL, iface = NULL;
212 struct dvobj_priv *dvobj = adapter_to_dvobj(Adapter);
213 u8 i = 0;
214
215 if (!rtw_is_hw_init_completed(Adapter))
216 goto skip_dm;
217
218 #ifdef CONFIG_LPS
219 bFwCurrentInPSMode = pwrpriv->bFwCurrentInPSMode;
220 rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, &bFwPSAwake);
221 #endif
222
223 #ifdef CONFIG_P2P_PS
224 /* Fw is under p2p powersaving mode, driver should stop dynamic mechanism.
225 modifed by thomas. 2011.06.11.*/
226 if (Adapter->wdinfo.p2p_ps_mode)
227 bFwPSAwake = _FALSE;
228 #endif /*CONFIG_P2P_PS*/
229
230 if ((rtw_is_hw_init_completed(Adapter))
231 && ((!bFwCurrentInPSMode) && bFwPSAwake)) {
232
233 /* check rx fifo */
234 check_rxfifo_full(Adapter);
235
236 /* Dynamically switch RTS/CTS protection.*/
237 }
238
239 #ifdef CONFIG_LPS
240 if (pwrpriv->bLeisurePs && bFwCurrentInPSMode && pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
241 in_lps = _TRUE;
242
243 for (i = 0; i < dvobj->iface_nums; i++) {
244 iface = dvobj->padapters[i];
245 if (pwrpriv->current_lps_hw_port_id == rtw_hal_get_port(iface)) {
246 current_lps_iface = iface;
247 rtw_lps_rfon_ctrl(current_lps_iface, rf_on);
248 break;
249 }
250 }
251
252 if (!current_lps_iface) {
253 RTW_WARN("Can't find a adapter with LPS to enable RFON function !\n");
254 goto skip_dm;
255 }
256 }
257 #endif
258
259 #ifdef CONFIG_BEAMFORMING
260 #ifdef RTW_BEAMFORMING_VERSION_2
261 if (check_fwstate(&Adapter->mlmepriv, WIFI_STATION_STATE) &&
262 check_fwstate(&Adapter->mlmepriv, WIFI_ASOC_STATE))
263 rtw_hal_beamforming_config_csirate(Adapter);
264 #endif
265 #endif
266
267 #ifdef CONFIG_DISABLE_ODM
268 goto skip_dm;
269 #endif
270
271 rtw_phydm_watchdog(Adapter, in_lps);
272
273 skip_dm:
274
275 #ifdef CONFIG_LPS
276 if (current_lps_iface)
277 rtw_lps_rfon_ctrl(current_lps_iface, rf_off);
278 #endif
279 #ifdef CONFIG_SUPPORT_HW_WPS_PBC
280 /* Check GPIO to determine current Pbc status.*/
281 dm_CheckPbcGPIO(Adapter);
282 #endif
283 return;
284 }
285
286