• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright(c) 2015 - 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 #define _RTL8822C_CMD_C_
16 
17 #include <hal_data.h>		/* HAL_DATA_TYPE */
18 #include "../hal_halmac.h"	/* HRTW_HALMAC_H2C_MAX_SIZE, CMD_ID_RSVD_PAGE and etc. */
19 #include "rtl8822c.h"
20 
21 /*
22  * Below functions are for C2H
23  */
24 /*****************************************
25  * H2C Msg format :
26  *| 31 - 8		|7-5	| 4 - 0	|
27  *| h2c_msg		|Class	|CMD_ID	|
28  *| 31-0				|
29  *| Ext msg				|
30  *
31  ******************************************/
rtl8822c_fillh2ccmd(PADAPTER adapter,u8 id,u32 buf_len,u8 * pbuf)32 s32 rtl8822c_fillh2ccmd(PADAPTER adapter, u8 id, u32 buf_len, u8 *pbuf)
33 {
34 	u8 h2c[RTW_HALMAC_H2C_MAX_SIZE] = {0};
35 #ifdef CONFIG_RTW_DEBUG
36 	u8 msg[(RTW_HALMAC_H2C_MAX_SIZE - 1) * 5 + 1] = {0};
37 	u8 *msg_p;
38 	u32 msg_size, i, n;
39 #endif /* CONFIG_RTW_DEBUG */
40 	int err;
41 	s32 ret = _FAIL;
42 
43 
44 	if (!pbuf)
45 		goto exit;
46 
47 	if (buf_len > (RTW_HALMAC_H2C_MAX_SIZE - 1))
48 		goto exit;
49 
50 	if (rtw_is_surprise_removed(adapter))
51 		goto exit;
52 
53 #ifdef CONFIG_RTW_DEBUG
54 	msg_p = msg;
55 	msg_size = (RTW_HALMAC_H2C_MAX_SIZE - 1) * 5 + 1;
56 	for (i = 0; i < buf_len; i++) {
57 		n = rtw_sprintf(msg_p, msg_size, " 0x%02x", pbuf[i]);
58 		msg_p += n;
59 		msg_size -= n;
60 		if (msg_size == 0)
61 			break;
62 	}
63 	RTW_DBG(FUNC_ADPT_FMT ": id=0x%02x buf=%s\n",
64 		 FUNC_ADPT_ARG(adapter), id, msg);
65 #endif /* CONFIG_RTW_DEBUG */
66 
67 	h2c[0] = id;
68 	_rtw_memcpy(h2c + 1, pbuf, buf_len);
69 
70 	err = rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
71 	if (!err)
72 		ret = _SUCCESS;
73 
74 exit:
75 
76 	return ret;
77 }
78 
rtl8822c_req_txrpt_cmd(PADAPTER adapter,u8 macid)79 void rtl8822c_req_txrpt_cmd(PADAPTER adapter, u8 macid)
80 {
81 	u8 h2c[RTW_HALMAC_H2C_MAX_SIZE] = {0};
82 
83 	AP_REQ_TXRPT_SET_CMD_ID(h2c, CMD_ID_AP_REQ_TXRPT);
84 	AP_REQ_TXRPT_SET_CLASS(h2c, CLASS_AP_REQ_TXRPT);
85 
86 	AP_REQ_TXRPT_SET_STA1_MACID(h2c, macid);
87 	AP_REQ_TXRPT_SET_STA2_MACID(h2c, 0xff);
88 	AP_REQ_TXRPT_SET_RTY_OK_TOTAL(h2c, 0x00);
89 	AP_REQ_TXRPT_SET_RTY_CNT_MACID(h2c, 0x00);
90 	rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
91 
92 	AP_REQ_TXRPT_SET_RTY_CNT_MACID(h2c, 0x01);
93 	rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
94 }
95 
96 #define SET_PWR_MODE_SET_BCN_RECEIVING_TIME(h2c_pkt, value)                    \
97 	SET_BITS_TO_LE_4BYTE(h2c_pkt + 0X04, 24, 5, value)
98 #define SET_PWR_MODE_SET_ADOPT_BCN_RECEIVING_TIME(h2c_pkt, value)              \
99 	SET_BITS_TO_LE_4BYTE(h2c_pkt + 0X04, 31, 1, value)
100 
_rtl8822c_set_FwPwrMode_cmd(PADAPTER adapter,u8 psmode,u8 rfon_ctrl)101 void _rtl8822c_set_FwPwrMode_cmd(PADAPTER adapter, u8 psmode, u8 rfon_ctrl)
102 {
103 	int i;
104 	u8 smart_ps = 0, mode = 0;
105 	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter);
106 #ifdef CONFIG_BCN_RECV_TIME
107 	u8 bcn_recv_time;
108 	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
109 #endif
110 #ifdef CONFIG_WMMPS_STA
111 	struct mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
112 	struct qos_priv	*pqospriv = &pmlmepriv->qospriv;
113 #endif /* CONFIG_WMMPS_STA */
114 	u8 h2c[RTW_HALMAC_H2C_MAX_SIZE] = {0};
115 	u8 PowerState = 0, awake_intvl = 1, rlbm = 0;
116 	u8 allQueueUAPSD = 0;
117 	char *fw_psmode_str = "";
118 #ifdef CONFIG_P2P
119 	struct wifidirect_info *wdinfo = &adapter->wdinfo;
120 #endif /* CONFIG_P2P */
121 	u8 hw_port = rtw_hal_get_port(adapter);
122 
123 	if (pwrpriv->pwr_mode != psmode) {
124 		if (pwrpriv->dtim > 0)
125 			RTW_INFO(FUNC_ADPT_FMT ": dtim=%d, HW port id=%d\n", FUNC_ADPT_ARG(adapter),
126 				pwrpriv->dtim, psmode == PS_MODE_ACTIVE ? pwrpriv->current_lps_hw_port_id : hw_port);
127 		else
128 			RTW_INFO(FUNC_ADPT_FMT ": HW port id=%d\n", FUNC_ADPT_ARG(adapter),
129 				psmode == PS_MODE_ACTIVE ? pwrpriv->current_lps_hw_port_id : hw_port);
130 	}
131 
132 	if (psmode == PS_MODE_MIN || psmode == PS_MODE_MAX) {
133 #ifdef CONFIG_WMMPS_STA
134 		if (rtw_is_wmmps_mode(adapter)) {
135 			mode = 2;
136 
137 			smart_ps = pwrpriv->wmm_smart_ps;
138 
139 			/* (WMMPS) allQueueUAPSD: 0: PSPoll, 1: QosNullData (if wmm_smart_ps=1) or do nothing (if wmm_smart_ps=2) */
140 			if ((pqospriv->uapsd_tid & BIT_MASK_TID_TC) == ALL_TID_TC_SUPPORTED_UAPSD)
141 				allQueueUAPSD = 1;
142 		} else
143 #endif /* CONFIG_WMMPS_STA */
144 		{
145 			mode = 1;
146 #ifdef CONFIG_WMMPS_STA
147 			/* For WMMPS test case, the station must retain sleep mode to capture buffered data on LPS mechanism */
148 			if ((pqospriv->uapsd_tid & BIT_MASK_TID_TC)  != 0)
149 				smart_ps = 0;
150 			else
151 #endif /* CONFIG_WMMPS_STA */
152 			{
153 				smart_ps = pwrpriv->smart_ps;
154 			}
155 		}
156 
157 		if (psmode == PS_MODE_MIN)
158 			rlbm = 0;
159 		else
160 			rlbm = 1;
161 	} else if (psmode == PS_MODE_DTIM) {
162 		mode = 1;
163 		/* For WOWLAN LPS, DTIM = (awake_intvl - 1) */
164 		if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16)
165 			/* DTIM = (awake_intvl - 1) */
166 			awake_intvl = pwrpriv->dtim + 1;
167 		else
168 			/* DTIM = 3 */
169 			awake_intvl = 4;
170 
171 		rlbm = 2;
172 		smart_ps = pwrpriv->smart_ps;
173 	} else if (psmode == PS_MODE_ACTIVE) {
174 		mode = 0;
175 	} else {
176 		rlbm = 2;
177 		awake_intvl = 4;
178 		smart_ps = pwrpriv->smart_ps;
179 	}
180 
181 #ifdef CONFIG_P2P
182 	if (!rtw_p2p_chk_state(wdinfo, P2P_STATE_NONE)) {
183 		awake_intvl = 2;
184 		rlbm = 1;
185 	}
186 #endif /* CONFIG_P2P */
187 
188 	if (adapter->registrypriv.wifi_spec == 1) {
189 		awake_intvl = 2;
190 		rlbm = 1;
191 	}
192 
193 	if (psmode > 0) {
194 #ifdef CONFIG_BT_COEXIST
195 		if (rtw_btcoex_IsBtControlLps(adapter) == _TRUE)
196 			PowerState = rtw_btcoex_RpwmVal(adapter);
197 		else
198 #endif /* CONFIG_BT_COEXIST */
199 		{
200 			if (rfon_ctrl == rf_on)
201 				PowerState = 0x04; /* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
202 			else
203 				PowerState = 0x00; /* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
204 		}
205 	} else
206 		PowerState = 0x0C; /* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
207 
208 	if (pwrpriv->pwr_mode != psmode) {
209 		if (mode == 0)
210 			fw_psmode_str = "ACTIVE";
211 		else if (mode == 1)
212 			fw_psmode_str = "LPS";
213 		else if (mode == 2)
214 			fw_psmode_str = "WMMPS";
215 		else
216 			fw_psmode_str = "UNSPECIFIED";
217 
218 		RTW_INFO(FUNC_ADPT_FMT": fw ps mode = %s, drv ps mode = %d, rlbm = %d ,"
219 				    "smart_ps = %d, allQueueUAPSD = %d, PowerState = %d\n",
220 				    FUNC_ADPT_ARG(adapter), fw_psmode_str, psmode, rlbm, smart_ps,
221 				    allQueueUAPSD, PowerState);
222 	}
223 
224 #ifdef CONFIG_LPS_1T1R
225 	if (psmode > PS_MODE_ACTIVE) {
226 		HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
227 
228 		if (hal_data->lps_1t1r != pwrpriv->lps_1t1r
229 			/* if rf_type already 1T1R, no need to enable LPS-1T1R */
230 			&& hal_data->NumTotalRFPath > 1
231 			/* for now, FW LPS 1T1R operates on TX:A, RX:A */
232 			&& GET_HAL_TX_PATH_BMP(adapter) & 0x01
233 			&& GET_HAL_RX_PATH_BMP(adapter) & 0x01
234 		) {
235 			/* TODO: cmd macro defined by halmac */
236 			#define SET_PWR_MODE_EXT_SET_1T1R_EN(h2c_pkt, value) SET_BITS_TO_LE_4BYTE(h2c_pkt + 0X00, 8, 1, value)
237 			u8 h2c_ext[RTW_HALMAC_H2C_MAX_SIZE] = {0};
238 
239 			SET_PWR_MODE_SET_CMD_ID(h2c_ext, 0x11); /* TODO: CMD_ID defined by halmac */
240 			SET_PWR_MODE_SET_CLASS(h2c_ext, CLASS_SET_PWR_MODE);
241 			SET_PWR_MODE_EXT_SET_1T1R_EN(h2c_ext, pwrpriv->lps_1t1r);
242 			RTW_DBG_DUMP("H2C-PwrModeExt Parm:", h2c_ext, RTW_HALMAC_H2C_MAX_SIZE);
243 			if (rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c_ext) == 0)
244 				hal_data->lps_1t1r = pwrpriv->lps_1t1r;
245 		}
246 	}
247 #endif
248 
249 	SET_PWR_MODE_SET_CMD_ID(h2c, CMD_ID_SET_PWR_MODE);
250 	SET_PWR_MODE_SET_CLASS(h2c, CLASS_SET_PWR_MODE);
251 	SET_PWR_MODE_SET_MODE(h2c, mode);
252 	SET_PWR_MODE_SET_SMART_PS(h2c, smart_ps);
253 	SET_PWR_MODE_SET_RLBM(h2c, rlbm);
254 	SET_PWR_MODE_SET_AWAKE_INTERVAL(h2c, awake_intvl);
255 	SET_PWR_MODE_SET_B_ALL_QUEUE_UAPSD(h2c, allQueueUAPSD);
256 	SET_PWR_MODE_SET_PWR_STATE(h2c, PowerState);
257 	if (psmode == PS_MODE_ACTIVE) {
258 		/* Leave LPS, set the same HW port ID */
259 		SET_PWR_MODE_SET_PORT_ID(h2c, pwrpriv->current_lps_hw_port_id);
260 	} else {
261 		/* Enter LPS, record HW port ID */
262 		SET_PWR_MODE_SET_PORT_ID(h2c, hw_port);
263 		pwrpriv->current_lps_hw_port_id = hw_port;
264 	}
265 #ifdef CONFIG_BCN_RECV_TIME
266 	if (pmlmeext->bcn_rx_time) {
267 		bcn_recv_time = pmlmeext->bcn_rx_time / 128; /*unit : 128 us*/
268 		if (pmlmeext->bcn_rx_time % 128)
269 			bcn_recv_time += 1;
270 
271 		if (bcn_recv_time > 31)
272 			bcn_recv_time = 31;
273 		SET_PWR_MODE_SET_ADOPT_BCN_RECEIVING_TIME(h2c, 1);
274 		SET_PWR_MODE_SET_BCN_RECEIVING_TIME(h2c, bcn_recv_time);
275 	}
276 #endif
277 
278 #ifdef CONFIG_BT_COEXIST
279 	rtw_btcoex_RecordPwrMode(adapter, h2c + 1, RTW_HALMAC_H2C_MAX_SIZE - 1);
280 #endif /* CONFIG_BT_COEXIST */
281 
282 	RTW_DBG_DUMP("H2C-PwrMode Parm:", h2c, RTW_HALMAC_H2C_MAX_SIZE);
283 	rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
284 }
285 
rtl8822c_set_FwPwrMode_cmd(PADAPTER adapter,u8 psmode)286 void rtl8822c_set_FwPwrMode_cmd(PADAPTER adapter, u8 psmode)
287 {
288 	return _rtl8822c_set_FwPwrMode_cmd(adapter, psmode, rf_off);
289 }
290 
rtl8822c_set_FwPwrMode_rfon_ctrl_cmd(PADAPTER adapter,u8 rfon_ctrl)291 void rtl8822c_set_FwPwrMode_rfon_ctrl_cmd(PADAPTER adapter, u8 rfon_ctrl)
292 {
293 	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter);
294 
295 	return _rtl8822c_set_FwPwrMode_cmd(adapter, pwrpriv->power_mgnt, rfon_ctrl);
296 }
297 
rtl8822c_set_FwPwrModeInIPS_cmd(PADAPTER adapter,u8 cmd_param)298 void rtl8822c_set_FwPwrModeInIPS_cmd(PADAPTER adapter, u8 cmd_param)
299 {
300 
301 	u8 h2c[RTW_HALMAC_H2C_MAX_SIZE] = {0};
302 
303 	INACTIVE_PS_SET_CMD_ID(h2c, CMD_ID_INACTIVE_PS);
304 	INACTIVE_PS_SET_CLASS(h2c, CLASS_INACTIVE_PS);
305 
306 	if (cmd_param & BIT0)
307 		INACTIVE_PS_SET_ENABLE(h2c, 1);
308 
309 	if (cmd_param & BIT1)
310 		INACTIVE_PS_SET_IGNORE_PS_CONDITION(h2c, 1);
311 
312 	RTW_DBG_DUMP("H2C-FwPwrModeInIPS Parm:", h2c, RTW_HALMAC_H2C_MAX_SIZE);
313 	rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
314 }
315 
316 #ifdef CONFIG_WOWLAN
317 
rtl8822c_set_fw_pwrmode_inips_cmd_wowlan(PADAPTER padapter,u8 ps_mode)318 void rtl8822c_set_fw_pwrmode_inips_cmd_wowlan(PADAPTER padapter, u8 ps_mode)
319 {
320 	struct registry_priv  *registry_par = &padapter->registrypriv;
321 	u8 param[H2C_INACTIVE_PS_LEN] = {0};
322 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
323 
324 	RTW_INFO("%s, ps_mode: %d\n", __func__, ps_mode);
325 	if (ps_mode == PS_MODE_ACTIVE) {
326 		SET_H2CCMD_INACTIVE_PS_EN(param, 0);
327 	}
328 	else {
329 		SET_H2CCMD_INACTIVE_PS_EN(param, 1);
330 		if(registry_par->suspend_type == FW_IPS_DISABLE_BBRF && !check_fwstate(pmlmepriv, WIFI_ASOC_STATE))
331 			SET_H2CCMD_INACTIVE_DISBBRF(param, 1);
332 		if(registry_par->suspend_type == FW_IPS_WRC) {
333 			SET_H2CCMD_INACTIVE_PERIOD_SCAN_EN(param, 1);
334 			SET_H2CCMD_INACTIVE_PS_FREQ(param, 3);
335 			SET_H2CCMD_INACTIVE_PS_DURATION(param, 1);
336 			SET_H2CCMD_INACTIVE_PS_PERIOD_SCAN_TIME(param, 3);
337 		}
338 	}
339 
340 	rtl8822c_fillh2ccmd(padapter, H2C_INACTIVE_PS_, sizeof(param), param);
341 }
342 
343 #endif /* CONFIG_WOWLAN */
344 
rtl8822c_set_usb_suspend_mode(PADAPTER padapter)345 void rtl8822c_set_usb_suspend_mode(PADAPTER padapter)
346 {
347 	struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter);
348 	u8 param[H2C_BT_UNKNOWN_DEVICE_WA_LEN] = {0};
349 
350 	SET_H2CCMD_BT_UNKNOWN_DEVICE_WA_FORCE_IB_EN(param, 1);
351 	rtl8822c_fillh2ccmd(padapter, H2C_BT_UNKNOWN_DEVICE_WA, H2C_BT_UNKNOWN_DEVICE_WA_LEN, param);
352 }
353 
354 
355 
356 
357 
358 #ifdef CONFIG_BT_COEXIST
rtl8822c_download_BTCoex_AP_mode_rsvd_page(PADAPTER adapter)359 void rtl8822c_download_BTCoex_AP_mode_rsvd_page(PADAPTER adapter)
360 {
361 	hw_var_set_dl_rsvd_page(adapter, RT_MEDIA_CONNECT);
362 }
363 #endif /* CONFIG_BT_COEXIST */
364 
365 
366 /*
367  * Below functions are for C2H
368  */
c2h_ccx_rpt(PADAPTER adapter,u8 * pdata)369 static void c2h_ccx_rpt(PADAPTER adapter, u8 *pdata)
370 {
371 #ifdef CONFIG_XMIT_ACK
372 	u8 tx_state;
373 
374 
375 	tx_state = CCX_RPT_GET_TX_STATE(pdata);
376 
377 	/* 0 means success, 1 means retry drop */
378 	if (tx_state == 0)
379 		rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_SUCCESS);
380 	else
381 		rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL);
382 #endif /* CONFIG_XMIT_ACK */
383 }
384 
385 static void
C2HTxRPTHandler_8822c(PADAPTER Adapter,u8 * CmdBuf,u8 CmdLen)386 C2HTxRPTHandler_8822c(
387 		PADAPTER	Adapter,
388 		u8			*CmdBuf,
389 		u8			CmdLen
390 )
391 {
392 	_irqL	 irqL;
393 	u8 macid = 0, IniRate = 0;
394 	u16 TxOK = 0, TxFail = 0;
395 	struct sta_priv	*pstapriv = &(GET_PRIMARY_ADAPTER(Adapter))->stapriv, *pstapriv_original = NULL;
396 	u8 TxOK0 = 0, TxOK1 = 0;
397 	u8 TxFail0 = 0, TxFail1 = 0;
398 	struct sta_info *psta = NULL;
399 	PADAPTER	adapter_ognl = NULL;
400 
401 	if(!pstapriv->gotc2h) {
402 		RTW_WARN("%s,%d: No gotc2h!\n", __FUNCTION__, __LINE__);
403 		return;
404 	}
405 
406 	adapter_ognl = rtw_get_iface_by_id(GET_PRIMARY_ADAPTER(Adapter), pstapriv->c2h_adapter_id);
407 	if(!adapter_ognl) {
408 		RTW_WARN("%s: No adapter!\n", __FUNCTION__);
409 		return;
410 	}
411 
412 	psta = rtw_get_stainfo(&adapter_ognl->stapriv, pstapriv->c2h_sta_mac);
413 	if (!psta) {
414 		RTW_WARN("%s: No corresponding sta_info!\n", __FUNCTION__);
415 		return;
416 	}
417 
418 	macid = C2H_AP_REQ_TXRPT_GET_STA1_MACID(CmdBuf);
419 	TxOK0 = C2H_AP_REQ_TXRPT_GET_TX_OK1_0(CmdBuf);
420 	TxOK1 = C2H_AP_REQ_TXRPT_GET_TX_OK1_1(CmdBuf);
421 	TxOK = (TxOK1 << 8) | TxOK0;
422 	TxFail0 = C2H_AP_REQ_TXRPT_GET_TX_FAIL1_0(CmdBuf);
423 	TxFail1 = C2H_AP_REQ_TXRPT_GET_TX_FAIL1_1(CmdBuf);
424 	TxFail = (TxFail1 << 8) | TxFail0;
425 	IniRate = C2H_AP_REQ_TXRPT_GET_INITIAL_RATE1(CmdBuf);
426 
427 	psta->sta_stats.tx_ok_cnt = TxOK;
428 	psta->sta_stats.tx_fail_cnt = TxFail;
429 	psta->sta_stats.tx_fail_cnt_sum += TxFail;
430 }
431 
432 static void
C2HSPC_STAT_8822c(PADAPTER Adapter,u8 * CmdBuf,u8 CmdLen)433 C2HSPC_STAT_8822c(
434 		PADAPTER	Adapter,
435 		u8			*CmdBuf,
436 		u8			CmdLen
437 )
438 {
439 	_irqL	 irqL;
440 	struct sta_priv *pstapriv = &(GET_PRIMARY_ADAPTER(Adapter))->stapriv;
441 	struct sta_info *psta = NULL;
442 	struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(Adapter);
443 	_list	*plist, *phead;
444 	u8 idx = C2H_SPECIAL_STATISTICS_GET_STATISTICS_IDX(CmdBuf);
445 	PADAPTER	adapter_ognl = NULL;
446 
447 	if(!pstapriv->gotc2h) {
448 		RTW_WARN("%s, %d: No gotc2h!\n", __FUNCTION__, __LINE__);
449 		return;
450 	}
451 
452 	adapter_ognl = rtw_get_iface_by_id(GET_PRIMARY_ADAPTER(Adapter), pstapriv->c2h_adapter_id);
453 	if(!adapter_ognl) {
454 		RTW_WARN("%s: No adapter!\n", __FUNCTION__);
455 		return;
456 	}
457 
458 	psta = rtw_get_stainfo(&adapter_ognl->stapriv, pstapriv->c2h_sta_mac);
459 	if (!psta) {
460 		RTW_WARN("%s: No corresponding sta_info!\n", __FUNCTION__);
461 		return;
462 	}
463 	psta->sta_stats.tx_retry_cnt = (C2H_SPECIAL_STATISTICS_GET_DATA3(CmdBuf) << 8) | C2H_SPECIAL_STATISTICS_GET_DATA2(CmdBuf);
464 	psta->sta_stats.tx_retry_cnt_sum += psta->sta_stats.tx_retry_cnt;
465 
466 	enter_critical_bh(&pstapriv->tx_rpt_lock);
467 	rtw_sctx_done(&pstapriv->gotc2h);
468 	exit_critical_bh(&pstapriv->tx_rpt_lock);
469 }
470 #ifdef CONFIG_FW_HANDLE_TXBCN
471 #define C2H_SUB_CMD_ID_FW_TBTT_RPT  0X23
472 #define TBTT_RPT_GET_SN(c2h_pkt)	LE_BITS_TO_4BYTE(c2h_pkt + 0X01, 0, 8)
473 #define TBTT_RPT_GET_PORT_ID(c2h_pkt)	LE_BITS_TO_4BYTE(c2h_pkt + 0X04, 0, 8)
474 
475 #define TBTT_ROOT	0x00
476 #define TBTT_VAP1	0x10
477 #define TBTT_VAP2	0x20
478 #define TBTT_VAP3	0x30
479 
c2h_tbtt_rpt(PADAPTER adapter,u8 * pdata)480 static void c2h_tbtt_rpt(PADAPTER adapter, u8 *pdata)
481 {
482 	u8 ap_id, c2h_sn;
483 
484 	ap_id = TBTT_RPT_GET_PORT_ID(pdata);
485 	c2h_sn = TBTT_RPT_GET_SN(pdata);
486 #ifdef DBG_FW_TBTT_RPT
487 	if (ap_id == TBTT_ROOT)
488 		RTW_INFO("== TBTT ROOT SN:%d==\n", c2h_sn);
489 	else if (ap_id == TBTT_VAP1)
490 		RTW_INFO("== TBTT_VAP1 SN:%d==\n", c2h_sn);
491 	else if (ap_id == TBTT_VAP2)
492 		RTW_INFO("== TBTT_VAP2 SN:%d==\n", c2h_sn);
493 	else if (ap_id == TBTT_VAP3)
494 		RTW_INFO("== TBTT_VAP3 SN:%d==\n", c2h_sn);
495 	else
496 		RTW_ERR("TBTT RPT INFO ERROR\n");
497 #endif
498 }
499 #endif
500 
501 /**
502  * c2h = RXDESC + c2h packet
503  * size = RXDESC_SIZE + c2h packet size
504  * c2h payload = c2h packet revmoe id & seq
505  */
process_c2h_event(PADAPTER adapter,u8 * c2h,u32 size)506 static void process_c2h_event(PADAPTER adapter, u8 *c2h, u32 size)
507 {
508 	struct mlme_ext_priv *pmlmeext;
509 	struct mlme_ext_info *pmlmeinfo;
510 	u32 desc_size;
511 	u8 id, seq;
512 	u8 c2h_len, c2h_payload_len;
513 	u8 *pc2h_data, *pc2h_payload;
514 
515 
516 	if (!c2h) {
517 		RTW_INFO("%s: c2h buffer is NULL!!\n", __FUNCTION__);
518 		return;
519 	}
520 
521 	desc_size = rtl8822c_get_rx_desc_size(adapter);
522 
523 	if (size < desc_size) {
524 		RTW_INFO("%s: c2h length(%d) is smaller than RXDESC_SIZE(%d)!!\n",
525 			 __FUNCTION__, size, desc_size);
526 		return;
527 	}
528 
529 	pmlmeext = &adapter->mlmeextpriv;
530 	pmlmeinfo = &pmlmeext->mlmext_info;
531 
532 	/* shift rx desc len */
533 	pc2h_data = c2h + desc_size;
534 	c2h_len = size - desc_size;
535 
536 	if (c2h_len >= 4) {
537 		id = C2H_GET_CMD_ID(pc2h_data);
538 		seq = C2H_GET_SEQ(pc2h_data);
539 	} else {
540 		id = C2H_GET_CMD_ID_1BYTE(pc2h_data);
541 		seq = C2H_GET_SEQ_1BYTE(pc2h_data);
542 	}
543 
544 	/* shift 2 byte to remove cmd id & seq */
545 	pc2h_payload = pc2h_data + 2;
546 	c2h_payload_len = c2h_len - 2;
547 
548 	switch (id) {
549 #ifdef CONFIG_BEAMFORMING
550 	case CMD_ID_C2H_SND_TXBF:
551 		RTW_INFO("%s: [CMD_ID_C2H_SND_TXBF] len=%d\n", __FUNCTION__, c2h_payload_len);
552 		rtw_bf_c2h_handler(adapter, id, pc2h_data, c2h_len);
553 		break;
554 #endif /* CONFIG_BEAMFORMING */
555 
556 	case CMD_ID_C2H_AP_REQ_TXRPT:
557 		/*RTW_INFO("[C2H], C2H_AP_REQ_TXRPT!!\n");*/
558 		C2HTxRPTHandler_8822c(adapter, pc2h_data, c2h_len);
559 		break;
560 
561 	case CMD_ID_C2H_SPECIAL_STATISTICS:
562 		/*RTW_INFO("[C2H], C2H_SPC_STAT!!\n");*/
563 		C2HSPC_STAT_8822c(adapter, pc2h_data, c2h_len);
564 		break;
565 
566 	case CMD_ID_C2H_CUR_CHANNEL:
567 	{
568 		PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
569 		struct submit_ctx *chsw_sctx = &hal->chsw_sctx;
570 
571 		RTW_INFO("[C2H], CMD_ID_C2H_CUR_CHANNEL!!\n");
572 		rtw_sctx_done(&chsw_sctx);
573 		break;
574 	}
575 
576 	case C2H_EXTEND:
577 		if (C2H_HDR_GET_C2H_SUB_CMD_ID(pc2h_data) == C2H_SUB_CMD_ID_CCX_RPT) {
578 			/* Shift C2H HDR 4 bytes */
579 			c2h_ccx_rpt(adapter, pc2h_data);
580 			break;
581 		}
582 #ifdef CONFIG_FW_HANDLE_TXBCN
583 		else if (C2H_HDR_GET_C2H_SUB_CMD_ID(pc2h_data) == C2H_SUB_CMD_ID_FW_TBTT_RPT) {
584 			c2h_tbtt_rpt(adapter, pc2h_data);
585 			break;
586 		}
587 #endif
588 		/* indicate c2h pkt + rx desc to halmac */
589 		rtw_halmac_c2h_handle(adapter_to_dvobj(adapter), c2h, size);
590 		break;
591 
592 	/* others for c2h common code */
593 	default:
594 		c2h_handler(adapter, id, seq, c2h_payload_len, pc2h_payload);
595 		break;
596 	}
597 }
598 
rtl8822c_c2h_handler(PADAPTER adapter,u8 * pbuf,u16 length)599 void rtl8822c_c2h_handler(PADAPTER adapter, u8 *pbuf, u16 length)
600 {
601 #ifdef CONFIG_WOWLAN
602 	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter);
603 
604 
605 	if (pwrpriv->wowlan_mode == _TRUE) {
606 #ifdef CONFIG_RTW_DEBUG
607 		u32 desc_size;
608 
609 		desc_size = rtl8822c_get_rx_desc_size(adapter);
610 		RTW_INFO("%s: return because wowolan_mode==TRUE! CMDID=%d\n",
611 			 __FUNCTION__, C2H_GET_CMD_ID(pbuf + desc_size));
612 #endif /* CONFIG_RTW_DEBUG */
613 		return;
614 	}
615 #endif /* CONFIG_WOWLAN*/
616 
617 	process_c2h_event(adapter, pbuf, length);
618 }
619 
620 /**
621  * pbuf = RXDESC + c2h packet
622  * length = RXDESC_SIZE + c2h packet size
623  */
rtl8822c_c2h_handler_no_io(PADAPTER adapter,u8 * pbuf,u16 length)624 void rtl8822c_c2h_handler_no_io(PADAPTER adapter, u8 *pbuf, u16 length)
625 {
626 	u32 desc_size;
627 	u8 id, seq;
628 	u8 *pc2h_content;
629 	u8 res;
630 
631 
632 	if ((length == 0) || (!pbuf))
633 		return;
634 
635 	desc_size = rtl8822c_get_rx_desc_size(adapter);
636 
637 	/* shift rx desc len to get c2h packet content */
638 	pc2h_content = pbuf + desc_size;
639 	id = C2H_GET_CMD_ID(pc2h_content);
640 	seq = C2H_GET_SEQ(pc2h_content);
641 
642 	RTW_DBG("%s: C2H, ID=%d seq=%d len=%d\n",
643 		 __FUNCTION__, id, seq, length);
644 
645 	switch (id) {
646 	case CMD_ID_C2H_SND_TXBF:
647 	case CMD_ID_C2H_CCX_RPT:
648 	case C2H_BT_MP_INFO:
649 	case C2H_FW_CHNL_SWITCH_COMPLETE:
650 	case C2H_IQK_FINISH:
651 	case C2H_MCC:
652 	case C2H_BCN_EARLY_RPT:
653 	case C2H_LPS_STATUS_RPT:
654 	case C2H_EXTEND:
655 		/* no I/O, process directly */
656 		process_c2h_event(adapter, pbuf, length);
657 		break;
658 
659 	default:
660 		/* Others may need I/O, run in command thread */
661 		res = rtw_c2h_packet_wk_cmd(adapter, pbuf, length);
662 		if (res == _FAIL)
663 			RTW_ERR("%s: C2H(%d) enqueue FAIL!\n", __FUNCTION__, id);
664 		break;
665 	}
666 }
667