xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8723ds/hal/rtl8723d/sdio/rtl8723ds_recv.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 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 _RTL8723DS_RECV_C_
16 
17 #include <rtl8723d_hal.h>
18 
19 #ifdef CONFIG_SDIO_RX_COPY
rtl8723ds_recv_hdl(_adapter * padapter)20 s32 rtl8723ds_recv_hdl(_adapter *padapter)
21 {
22 	PHAL_DATA_TYPE		pHalData;
23 	struct recv_priv		*precvpriv;
24 	struct recv_buf	*precvbuf;
25 	union recv_frame		*precvframe;
26 	struct recv_frame_hdr	*phdr;
27 	struct rx_pkt_attrib	*pattrib;
28 	u8	*ptr;
29 	u32	pkt_len, pkt_offset;
30 	u8	rx_report_sz = 0;
31 
32 	pHalData = GET_HAL_DATA(padapter);
33 	precvpriv = &padapter->recvpriv;
34 
35 	do {
36 		precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
37 		if (NULL == precvbuf)
38 			break;
39 
40 		ptr = precvbuf->pdata;
41 
42 		while (ptr < precvbuf->ptail) {
43 			precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
44 			if (precvframe == NULL) {
45 				RTW_INFO("%s: no enough recv frame!\n", __FUNCTION__);
46 				rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
47 				return RTW_RFRAME_UNAVAIL;
48 			}
49 
50 			/* rx desc parsing */
51 			rtl8723d_query_rx_desc_status(precvframe, ptr);
52 
53 			pattrib = &precvframe->u.hdr.attrib;
54 
55 			/* fix Hardware RX data error, drop whole recv_buffer */
56 			if (!rtw_hal_rcr_check(padapter, RCR_ACRC32) && pattrib->crc_err) {
57 #if !(MP_DRIVER == 1)
58 				RTW_INFO("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__);
59 #endif
60 				rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
61 				break;
62 			}
63 
64 			rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz;
65 			pkt_offset = rx_report_sz + pattrib->shift_sz + pattrib->pkt_len;
66 
67 			if ((ptr + pkt_offset) > precvbuf->ptail) {
68 				RTW_INFO("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", __FUNCTION__, __LINE__, ptr, pkt_offset, precvbuf->ptail);
69 				rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
70 				break;
71 			}
72 
73 			if ((pattrib->crc_err) || (pattrib->icv_err)) {
74 #ifdef CONFIG_MP_INCLUDED
75 				if (padapter->registrypriv.mp_mode == 1) {
76 					if (check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _TRUE) { /* &&(padapter->mppriv.check_mp_pkt == 0)) */
77 						if (pattrib->crc_err == 1)
78 							padapter->mppriv.rx_crcerrpktcount++;
79 					}
80 				} else
81 #endif
82 				{
83 					RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err);
84 				}
85 				rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
86 			} else {
87 #ifdef CONFIG_RX_PACKET_APPEND_FCS
88 				if (check_fwstate(&padapter->mlmepriv, WIFI_MONITOR_STATE) == _FALSE)
89 					if ((pattrib->pkt_rpt_type == NORMAL_RX) && rtw_hal_rcr_check(padapter, RCR_APPFCS))
90 						pattrib->pkt_len -= IEEE80211_FCS_LEN;
91 #endif
92 
93 				if (rtw_os_alloc_recvframe(padapter, precvframe,
94 					(ptr + rx_report_sz + pattrib->shift_sz), precvbuf->pskb) == _FAIL) {
95 					rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
96 					break;
97 				}
98 
99 				recvframe_put(precvframe, pattrib->pkt_len);
100 				/* move to drv info position */
101 				ptr += RXDESC_SIZE;
102 
103 				/* update drv info */
104 				if (rtw_hal_rcr_check(padapter, RCR_APP_BA_SSN)) {
105 					/* rtl8723s_update_bassn(padapter, pdrvinfo); */
106 					ptr += 4;
107 				}
108 
109 				if (pattrib->pkt_rpt_type == NORMAL_RX) {
110 					/* skip the rx packet with abnormal length */
111 					if (pattrib->pkt_len < 14 || pattrib->pkt_len > 8192) {
112 						RTW_INFO("skip abnormal rx packet(%d)\n", pattrib->pkt_len);
113 						rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
114 						break;
115 					}
116 
117 					pre_recv_entry(precvframe, pattrib->physt ? ptr : NULL);
118 
119 				} else {
120 #ifdef CONFIG_FW_C2H_PKT
121 					if (pattrib->pkt_rpt_type == C2H_PACKET)
122 						rtw_hal_c2h_pkt_pre_hdl(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
123 					else {
124 						RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
125 							__FUNCTION__, pattrib->pkt_rpt_type);
126 					}
127 #endif
128 					rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
129 				}
130 			}
131 
132 			pkt_offset = _RND8(pkt_offset);
133 			precvbuf->pdata += pkt_offset;
134 			ptr = precvbuf->pdata;
135 			precvframe = NULL;
136 		}
137 
138 		rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
139 	} while (1);
140 
141 #ifdef CONFIG_RTW_NAPI
142 #ifdef CONFIG_RTW_NAPI_V2
143 	if (padapter->registrypriv.en_napi) {
144 		struct dvobj_priv *d;
145 		struct _ADAPTER *a;
146 		u8 i;
147 
148 		d = adapter_to_dvobj(padapter);
149 		for (i = 0; i < d->iface_nums; i++) {
150 			a = d->padapters[i];
151 			precvpriv = &a->recvpriv;
152 			if (rtw_if_up(a) == _TRUE
153 				&& skb_queue_len(&precvpriv->rx_napi_skb_queue))
154 				napi_schedule(&a->napi);
155 
156 		}
157 	}
158 #endif /* CONFIG_RTW_NAPI_V2 */
159 #endif /* CONFIG_RTW_NAPI */
160 
161 	return _SUCCESS;
162 }
163 
rtl8723ds_recv_tasklet(void * priv)164 static void rtl8723ds_recv_tasklet(void *priv)
165 {
166 	_adapter *adapter = (_adapter *)priv;
167 	s32 ret;
168 
169 	ret = rtl8723ds_recv_hdl(adapter);
170 	if (ret == RTW_RFRAME_UNAVAIL
171 		|| ret == RTW_RFRAME_PKT_UNAVAIL
172 	) {
173 		/* schedule again and hope recvframe/packet is available next time. */
174 		#ifdef PLATFORM_LINUX
175 		tasklet_schedule(&adapter->recvpriv.recv_tasklet);
176 		#endif
177 	}
178 }
179 #else
rtl8723ds_recv_tasklet(void * priv)180 static void rtl8723ds_recv_tasklet(void *priv)
181 {
182 	PADAPTER				padapter;
183 	PHAL_DATA_TYPE			pHalData;
184 	struct recv_priv		*precvpriv;
185 	struct recv_buf		*precvbuf;
186 	union recv_frame		*precvframe;
187 	struct recv_frame_hdr	*phdr;
188 	struct rx_pkt_attrib	*pattrib;
189 	u8			*ptr;
190 	_pkt		*ppkt;
191 	u32		pkt_offset;
192 
193 	padapter = (PADAPTER)priv;
194 	pHalData = GET_HAL_DATA(padapter);
195 	precvpriv = &padapter->recvpriv;
196 
197 	do {
198 		precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
199 		if (NULL == precvbuf)
200 			break;
201 
202 		ptr = precvbuf->pdata;
203 
204 		while (ptr < precvbuf->ptail) {
205 			precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
206 			if (precvframe == NULL) {
207 				rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
208 
209 				/* The case of can't allocate recvframe should be temporary, */
210 				/* schedule again and hope recvframe is available next time. */
211 #ifdef PLATFORM_LINUX
212 				tasklet_schedule(&precvpriv->recv_tasklet);
213 #endif
214 				return;
215 			}
216 
217 			phdr = &precvframe->u.hdr;
218 			pattrib = &phdr->attrib;
219 
220 			rtl8723d_query_rx_desc_status(precvframe, ptr);
221 
222 #if 0
223 			{
224 				int i, len = 64;
225 				u8 *pptr = ptr;
226 
227 				if ((*(pptr + RXDESC_SIZE + pattrib->drvinfo_sz) != 0x80) && (*(pptr + RXDESC_SIZE + pattrib->drvinfo_sz) != 0x40)) {
228 					RTW_INFO("##############RxDESC###############\n");
229 					for (i = 0; i < 32; i = i + 16)
230 						RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(pptr + i),
231 							*(pptr + i + 1), *(pptr + i + 2) , *(pptr + i + 3) , *(pptr + i + 4), *(pptr + i + 5), *(pptr + i + 6), *(pptr + i + 7), *(pptr + i + 8),
232 							*(pptr + i + 9), *(pptr + i + 10),
233 							*(pptr + i + 11), *(pptr + i + 12), *(pptr + i + 13), *(pptr + i + 14), *(pptr + i + 15));
234 
235 					if (pattrib->pkt_len < 100)
236 						len = pattrib->pkt_len;
237 					pptr = ptr + RXDESC_SIZE + pattrib->drvinfo_sz;
238 					RTW_INFO("##############Len=%d###############\n", pattrib->pkt_len);
239 					for (i = 0; i < len; i = i + 16)
240 						RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(pptr + i),
241 							*(pptr + i + 1), *(pptr + i + 2) , *(pptr + i + 3) , *(pptr + i + 4), *(pptr + i + 5), *(pptr + i + 6), *(pptr + i + 7), *(pptr + i + 8),
242 							*(pptr + i + 9), *(pptr + i + 10),
243 							*(pptr + i + 11), *(pptr + i + 12), *(pptr + i + 13), *(pptr + i + 14), *(pptr + i + 15));
244 					RTW_INFO("#############################\n");
245 				}
246 			}
247 #endif
248 
249 			/* fix Hardware RX data error, drop whole recv_buffer */
250 			if (!rtw_hal_rcr_check(padapter, RCR_ACRC32) && pattrib->crc_err) {
251 				RTW_INFO("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__);
252 				rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
253 				break;
254 			}
255 
256 			pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->pkt_len;
257 #if 0 /* reduce check to speed up */
258 			if ((ptr + pkt_offset) > precvbuf->ptail) {
259 				rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
260 				break;
261 			}
262 #endif
263 
264 			if ((pattrib->crc_err) || (pattrib->icv_err)) {
265 #ifdef CONFIG_MP_INCLUDED
266 				if (padapter->registrypriv.mp_mode == 1) {
267 					if (check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _TRUE) { /* &&(padapter->mppriv.check_mp_pkt == 0)) */
268 						if (pattrib->crc_err == 1)
269 							padapter->mppriv.rx_crcerrpktcount++;
270 					}
271 				} else
272 #endif
273 				{
274 					RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err);
275 				}
276 				rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
277 			} else {
278 				ppkt = rtw_skb_clone(precvbuf->pskb);
279 				if (ppkt == NULL) {
280 					RTW_INFO("%s: no enough memory to allocate SKB!\n", __FUNCTION__);
281 					rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
282 					rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
283 
284 					/* The case of can't allocate skb is serious and may never be recovered, */
285 					/* once bDriverStopped is enable, this task should be stopped. */
286 					if (!rtw_is_drv_stopped(padapter)) {
287 #ifdef PLATFORM_LINUX
288 						tasklet_schedule(&precvpriv->recv_tasklet);
289 #endif
290 					}
291 
292 					return;
293 				}
294 
295 				phdr->pkt = ppkt;
296 				phdr->len = 0;
297 				phdr->rx_head = precvbuf->phead;
298 				phdr->rx_data = phdr->rx_tail = precvbuf->pdata;
299 				phdr->rx_end = precvbuf->pend;
300 				recvframe_put(precvframe, pkt_offset);
301 				recvframe_pull(precvframe, RXDESC_SIZE + pattrib->drvinfo_sz);
302 				skb_pull(ppkt, RXDESC_SIZE + pattrib->drvinfo_sz);
303 
304 #ifdef CONFIG_RX_PACKET_APPEND_FCS
305 				if (check_fwstate(&padapter->mlmepriv, WIFI_MONITOR_STATE) == _FALSE) {
306 					if ((pattrib->pkt_rpt_type == NORMAL_RX) && rtw_hal_rcr_check(padapter, RCR_APPFCS)) {
307 						recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN);
308 						pattrib->pkt_len -= IEEE80211_FCS_LEN;
309 						ppkt->len = pattrib->pkt_len;
310 					}
311 				}
312 #endif
313 
314 				/* move to drv info position */
315 				ptr += RXDESC_SIZE;
316 
317 				/* update drv info */
318 				if (rtw_hal_rcr_check(padapter, RCR_APP_BA_SSN)) {
319 					/* rtl8723s_update_bassn(padapter, pdrvinfo); */
320 					ptr += 4;
321 				}
322 
323 				if (pattrib->pkt_rpt_type == NORMAL_RX)
324 					pre_recv_entry(precvframe, pattrib->physt ? ptr : NULL);
325 				else {
326 #ifdef CONFIG_FW_C2H_PKT
327 					if (pattrib->pkt_rpt_type == C2H_PACKET)
328 						rtw_hal_c2h_pkt_pre_hdl(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
329 					else {
330 						RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
331 							__FUNCTION__, pattrib->pkt_rpt_type);
332 					}
333 #endif
334 					rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
335 				}
336 			}
337 
338 			pkt_offset = _RND8(pkt_offset);
339 			precvbuf->pdata += pkt_offset;
340 			ptr = precvbuf->pdata;
341 		}
342 
343 		rtw_skb_free(precvbuf->pskb);
344 		precvbuf->pskb = NULL;
345 		rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
346 	} while (1);
347 }
348 #endif
349 
350 /*
351  * Initialize recv private variable for hardware dependent
352  * 1. recv buf
353  * 2. recv tasklet
354  *
355  */
rtl8723ds_init_recv_priv(PADAPTER padapter)356 s32 rtl8723ds_init_recv_priv(PADAPTER padapter)
357 {
358 	struct registry_priv *regsty = adapter_to_regsty(padapter);
359 	s32			res;
360 	u32			i, n;
361 	struct recv_priv	*precvpriv;
362 	struct recv_buf		*precvbuf;
363 
364 
365 	res = _SUCCESS;
366 	precvpriv = &padapter->recvpriv;
367 
368 	/* 3 1. init recv buffer */
369 	_rtw_init_queue(&precvpriv->free_recv_buf_queue);
370 	_rtw_init_queue(&precvpriv->recv_buf_pending_queue);
371 
372 	n = regsty->recvbuf_nr * sizeof(struct recv_buf) + 4;
373 	precvpriv->pallocated_recv_buf = rtw_zmalloc(n);
374 	if (precvpriv->pallocated_recv_buf == NULL) {
375 		res = _FAIL;
376 		goto exit;
377 	}
378 
379 	precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
380 
381 	/* init each recv buffer */
382 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
383 	for (i = 0; i < regsty->recvbuf_nr; i++) {
384 		res = sdio_initrecvbuf(precvbuf, padapter);
385 		if (res == _FAIL)
386 			break;
387 
388 		res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf, MAX_RECVBUF_SZ);
389 		if (res == _FAIL) {
390 			sdio_freerecvbuf(precvbuf);
391 			break;
392 		}
393 
394 		rtw_list_insert_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue);
395 
396 		precvbuf++;
397 	}
398 	precvpriv->free_recv_buf_queue_cnt = i;
399 
400 	if (res == _FAIL)
401 		goto initbuferror;
402 
403 	/* 3 2. init tasklet */
404 #ifdef PLATFORM_LINUX
405 	tasklet_init(&precvpriv->recv_tasklet,
406 		     (void(*)(unsigned long))rtl8723ds_recv_tasklet,
407 		     (unsigned long)padapter);
408 #endif
409 
410 	goto exit;
411 
412 initbuferror:
413 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
414 	if (precvbuf) {
415 		n = precvpriv->free_recv_buf_queue_cnt;
416 		precvpriv->free_recv_buf_queue_cnt = 0;
417 		for (i = 0; i < n ; i++) {
418 			rtw_list_delete(&precvbuf->list);
419 			rtw_os_recvbuf_resource_free(padapter, precvbuf);
420 			sdio_freerecvbuf(precvbuf);
421 			precvbuf++;
422 		}
423 		precvpriv->precv_buf = NULL;
424 	}
425 
426 	if (precvpriv->pallocated_recv_buf) {
427 		n = regsty->recvbuf_nr * sizeof(struct recv_buf) + 4;
428 		rtw_mfree(precvpriv->pallocated_recv_buf, n);
429 		precvpriv->pallocated_recv_buf = NULL;
430 	}
431 
432 exit:
433 	return res;
434 }
435 
436 /*
437  * Free recv private variable of hardware dependent
438  * 1. recv buf
439  * 2. recv tasklet
440  *
441  */
rtl8723ds_free_recv_priv(PADAPTER padapter)442 void rtl8723ds_free_recv_priv(PADAPTER padapter)
443 {
444 	struct registry_priv *regsty = &padapter->registrypriv;
445 	u32			i, n;
446 	struct recv_priv	*precvpriv;
447 	struct recv_buf		*precvbuf;
448 
449 
450 	precvpriv = &padapter->recvpriv;
451 
452 	/* 3 1. kill tasklet */
453 #ifdef PLATFORM_LINUX
454 	tasklet_kill(&precvpriv->recv_tasklet);
455 #endif
456 
457 	/* 3 2. free all recv buffers */
458 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
459 	if (precvbuf) {
460 		n = regsty->recvbuf_nr;
461 		precvpriv->free_recv_buf_queue_cnt = 0;
462 		for (i = 0; i < n ; i++) {
463 			rtw_list_delete(&precvbuf->list);
464 			rtw_os_recvbuf_resource_free(padapter, precvbuf);
465 			sdio_freerecvbuf(precvbuf);
466 			precvbuf++;
467 		}
468 		precvpriv->precv_buf = NULL;
469 	}
470 
471 	if (precvpriv->pallocated_recv_buf) {
472 		n = regsty->recvbuf_nr * sizeof(struct recv_buf) + 4;
473 		rtw_mfree(precvpriv->pallocated_recv_buf, n);
474 		precvpriv->pallocated_recv_buf = NULL;
475 	}
476 }
477