xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rtl8822bs/hal/rtl8822b/sdio/rtl8822bs_recv.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2015 - 2019 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 _RTL8822BS_RECV_C_
16 
17 #include <drv_types.h>		/* PADAPTER and etc. */
18 #include <hal_data.h>		/* HAL_DATA_TYPE */
19 #include "../../hal_halmac.h"	/* BIT_ACRC32_8822B and etc. */
20 #include "../rtl8822b.h"	/* rtl8822b_rxdesc2attribute(), rtl8822b_c2h_handler_no_io() */
21 
22 
initrecvbuf(struct recv_buf * precvbuf,PADAPTER adapter)23 static s32 initrecvbuf(struct recv_buf *precvbuf, PADAPTER adapter)
24 {
25 	_rtw_init_listhead(&precvbuf->list);
26 	_rtw_spinlock_init(&precvbuf->recvbuf_lock);
27 
28 	precvbuf->adapter = adapter;
29 
30 	return _SUCCESS;
31 }
32 
freerecvbuf(struct recv_buf * precvbuf)33 static void freerecvbuf(struct recv_buf *precvbuf)
34 {
35 	_rtw_spinlock_free(&precvbuf->recvbuf_lock);
36 }
37 
start_rx_handle(PADAPTER p)38 static void start_rx_handle(PADAPTER p)
39 {
40 #ifdef CONFIG_RECV_THREAD_MODE
41 	_rtw_up_sema(&p->recvpriv.recv_sema);
42 #else
43 	#ifdef PLATFORM_LINUX
44 	tasklet_schedule(&p->recvpriv.recv_tasklet);
45 	#endif
46 #endif
47 }
48 
stop_rx_handle(PADAPTER p)49 static void stop_rx_handle(PADAPTER p)
50 {
51 #ifdef CONFIG_RECV_THREAD_MODE
52 #else
53 	#ifdef PLATFORM_LINUX
54 	tasklet_kill(&p->recvpriv.recv_tasklet);
55 	#endif
56 #endif
57 }
58 
59 /*
60  * Return:
61  *	Pointer of _pkt, otherwise NULL.
62  */
alloc_recvbuf_skb(struct recv_buf * recvbuf,u32 size)63 static _pkt *alloc_recvbuf_skb(struct recv_buf *recvbuf, u32 size)
64 {
65 	_pkt *skb;
66 
67 #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER
68 	skb = rtw_alloc_skb_premem(size);
69 	if (!skb) {
70 		RTW_WARN("%s: Fail to get pre-alloc skb! size=%d\n",
71 			 __FUNCTION__, size);
72 		return NULL;
73 	}
74 #else /* !CONFIG_PREALLOC_RX_SKB_BUFFER */
75 	u32 alignsz = RECVBUFF_ALIGN_SZ;
76 #ifdef PLATFORM_LINUX
77 	SIZE_PTR tmpaddr = 0;
78 	SIZE_PTR alignment = 0;
79 #endif /* PLATFORM_LINUX */
80 
81 
82 	size += alignsz;
83 	skb = rtw_skb_alloc(size);
84 	if (!skb) {
85 		RTW_WARN("%s: alloc_skb fail! size=%d\n", __FUNCTION__, size);
86 		return NULL;
87 	}
88 
89 #ifdef PLATFORM_LINUX
90 	tmpaddr = (SIZE_PTR)skb->data;
91 	alignment = tmpaddr & (alignsz - 1);
92 	skb_reserve(skb, alignsz - alignment);
93 #endif /* PLATFORM_LINUX */
94 #endif /* !CONFIG_PREALLOC_RX_SKB_BUFFER */
95 
96 #ifdef PLATFORM_LINUX
97 	skb->dev = recvbuf->adapter->pnetdev;
98 #endif /* PLATFORM_LINUX */
99 
100 	recvbuf->pskb = skb;
101 
102 	return skb;
103 }
104 
105 /*
106  * Description:
107  *	Allocate skb for recv_buf, the size is MAX_RECVBUF_SZ
108  *
109  * Parameters:
110  *	recvbuf	pointer of struct recv_buf
111  *	size	skb size, only valid when NOT define CONFIG_SDIO_RX_COPY.
112  *		If CONFIG_SDIO_RX_COPY, size always be MAX_RECVBUF_SZ.
113  *
114  * Return:
115  *	Pointer of _pkt, otherwise NULL.
116  */
rtl8822bs_alloc_recvbuf_skb(struct recv_buf * recvbuf,u32 size)117 _pkt *rtl8822bs_alloc_recvbuf_skb(struct recv_buf *recvbuf, u32 size)
118 {
119 	_pkt *skb;
120 
121 
122 	skb = recvbuf->pskb;
123 #ifdef CONFIG_SDIO_RX_COPY
124 	if (skb) {
125 		skb_reset_tail_pointer(skb);
126 		skb->len = 0;
127 		return skb;
128 	}
129 
130 	RTW_WARN("%s: skb not exist in recv_buf!\n", __FUNCTION__);
131 	size = MAX_RECVBUF_SZ;
132 #else /* !CONFIG_SDIO_RX_COPY */
133 	if (skb) {
134 		RTW_WARN("%s: skb already exist in recv_buf!\n", __FUNCTION__);
135 		rtl8822bs_free_recvbuf_skb(recvbuf);
136 	}
137 #endif /* !CONFIG_SDIO_RX_COPY */
138 
139 	skb = alloc_recvbuf_skb(recvbuf, size);
140 	if (!skb)
141 		return NULL;
142 
143 	return skb;
144 }
145 
free_recvbuf_skb(struct recv_buf * recvbuf)146 static void free_recvbuf_skb(struct recv_buf *recvbuf)
147 {
148 	_pkt *skb;
149 
150 
151 	skb = recvbuf->pskb;
152 	if (!skb)
153 		return;
154 	recvbuf->pskb = NULL;
155 #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER
156 	rtw_free_skb_premem(skb);
157 #else /* !CONFIG_PREALLOC_RX_SKB_BUFFER */
158 	rtw_skb_free(skb);
159 #endif /* !CONFIG_PREALLOC_RX_SKB_BUFFER */
160 }
161 
rtl8822bs_free_recvbuf_skb(struct recv_buf * recvbuf)162 void rtl8822bs_free_recvbuf_skb(struct recv_buf *recvbuf)
163 {
164 #ifndef CONFIG_SDIO_RX_COPY
165 	free_recvbuf_skb(recvbuf);
166 #endif /* !CONFIG_SDIO_RX_COPY */
167 }
168 
169 /*
170  * Return:
171  *	_SUCCESS	Allocate resource OK.
172  *	_FAIL		Fail to allocate resource.
173  */
os_recvbuf_resource_alloc(PADAPTER adapter,struct recv_buf * recvbuf)174 static inline s32 os_recvbuf_resource_alloc(PADAPTER adapter, struct recv_buf *recvbuf)
175 {
176 	s32 ret = _SUCCESS;
177 
178 #ifdef CONFIG_SDIO_RX_COPY
179 	alloc_recvbuf_skb(recvbuf, MAX_RECVBUF_SZ);
180 #endif /* CONFIG_SDIO_RX_COPY */
181 
182 	return ret;
183 }
184 
os_recvbuf_resource_free(PADAPTER adapter,struct recv_buf * recvbuf)185 static inline void os_recvbuf_resource_free(PADAPTER adapter, struct recv_buf *recvbuf)
186 {
187 #ifdef CONFIG_SDIO_RX_COPY
188 	free_recvbuf_skb(recvbuf);
189 #endif /* CONFIG_SDIO_RX_COPY */
190 }
191 #if 0
192 static union recv_frame *copy_recvframe(union recv_frame *recvframe, PADAPTER adapter)
193 {
194 	PHAL_DATA_TYPE hal;
195 	struct recv_priv *precvpriv;
196 	_queue *pfree_recv_queue;
197 	struct rx_pkt_attrib *attrib = NULL;
198 	union recv_frame *copyframe = NULL;
199 	_pkt *copypkt = NULL;
200 
201 
202 	hal = GET_HAL_DATA(adapter);
203 	precvpriv = &adapter->recvpriv;
204 	pfree_recv_queue = &precvpriv->free_recv_queue;
205 	attrib = &recvframe->u.hdr.attrib;
206 
207 	copyframe = rtw_alloc_recvframe(pfree_recv_queue);
208 	if (!copyframe) {
209 		RTW_INFO(FUNC_ADPT_FMT ": Alloc recvframe FAIL!\n",
210 			 FUNC_ADPT_ARG(adapter));
211 		return NULL;
212 	}
213 	copyframe->u.hdr.adapter = adapter;
214 	_rtw_memcpy(&copyframe->u.hdr.attrib, attrib, sizeof(struct rx_pkt_attrib));
215 #if 0
216 	/*
217 	 * driver need to set skb len for skb_copy().
218 	 * If skb->len is zero, skb_copy() will not copy data from original skb.
219 	 */
220 	skb_put(recvframe->u.hdr.pkt, attrib->pkt_len);
221 #else
222 	RTW_INFO(FUNC_ADPT_FMT ": skb len=%d!\n",
223 		 FUNC_ADPT_ARG(adapter), recvframe->u.hdr.pkt->len);
224 #endif
225 
226 	copypkt = rtw_skb_copy(recvframe->u.hdr.pkt);
227 	if (!copypkt) {
228 		if ((attrib->mfrag == 1) && (attrib->frag_num == 0)) {
229 			RTW_ERR(FUNC_ADPT_FMT ": rtw_skb_copy fail for first fragment!\n",
230 				 FUNC_ADPT_ARG(adapter));
231 			rtw_free_recvframe(recvframe, &precvpriv->free_recv_queue);
232 			return NULL;
233 		}
234 
235 		copypkt = rtw_skb_clone(recvframe->u.hdr.pkt);
236 		if (!copypkt) {
237 			RTW_ERR(FUNC_ADPT_FMT ": rtw_skb_clone fail, drop frame!\n",
238 				 FUNC_ADPT_ARG(adapter));
239 			rtw_free_recvframe(recvframe, &precvpriv->free_recv_queue);
240 			return NULL;
241 		}
242 	}
243 	copypkt->dev = adapter->pnetdev;
244 
245 	copyframe->u.hdr.pkt = copypkt;
246 	copyframe->u.hdr.len = copypkt->len;
247 	copyframe->u.hdr.rx_head = copypkt->head;
248 	copyframe->u.hdr.rx_data = copypkt->data;
249 	copyframe->u.hdr.rx_tail = skb_tail_pointer(copypkt);
250 	copyframe->u.hdr.rx_end = skb_end_pointer(copypkt);
251 
252 	return copyframe;
253 }
254 #endif
255 /*
256  * Return:
257  *	_SUCCESS	OK to send packet
258  *	_FAIL		FAIL to send packet
259  */
recv_entry(union recv_frame * recvframe,u8 * phy_status)260 static s32 recv_entry(union recv_frame *recvframe, u8 *phy_status)
261 {
262 	s32 ret = _SUCCESS;
263 	PADAPTER adapter;
264 	struct rx_pkt_attrib *attrib = NULL;
265 #ifdef CONFIG_CONCURRENT_MODE
266 	struct dvobj_priv *d;
267 	u8 *addr1, *macaddr;
268 	u8 mcast, i;
269 	union recv_frame *copyframe = NULL;
270 #endif /* CONFIG_CONCURRENT_MODE */
271 
272 
273 	attrib = &recvframe->u.hdr.attrib;
274 
275 #if 0
276 	d = adapter_to_dvobj(recvframe->u.hdr.adapter);
277 	addr1 = GetAddr1Ptr(recvframe->u.hdr.rx_data);
278 	mcast = IS_MCAST(addr1);
279 	if (_TRUE == mcast) {
280 		/* BC/MC packets */
281 		for (i = 1; i < d->iface_nums; i++) {
282 			adapter = d->adapters[i];
283 
284 			if (rtw_if_up(adapter) == _FALSE)
285 				continue;
286 
287 			copyframe = copy_recvframe(recvframe, adapter);
288 			if (!copyframe)
289 				break;
290 
291 			if (attrib->physt)
292 				rx_query_phy_status(copyframe, phy_status);
293 
294 			ret = rtw_recv_entry(copyframe);
295 		}
296 	} else {
297 		/* unicast packets */
298 		for (i = 0; i < d->iface_nums; i++) {
299 			adapter = d->adapters[i];
300 
301 			if (rtw_if_up(adapter) == _FALSE)
302 				continue;
303 
304 			macaddr = adapter_mac_addr(adapter);
305 			if (_rtw_memcmp(addr1, macaddr, ETH_ALEN) == _FALSE)
306 				continue;
307 
308 			/* change to target interface */
309 			recvframe->u.hdr.adapter = adapter;
310 			recvframe->u.hdr.pkt->dev = adapter->pnetdev;
311 			break;
312 		}
313 	}
314 #else
315 	ret = pre_recv_entry(recvframe, attrib->physt ? phy_status : NULL);
316 #endif
317 
318 	return ret;
319 }
320 
321 /*
322  * Return:
323  *	_TRUE	Finish preparing recv_frame
324  *	_FALSE	Something fail to prepare recv_frame
325  */
prepare_recvframe_pkt(struct recv_buf * recvbuf,union recv_frame * recvframe)326 static _pkt *prepare_recvframe_pkt(struct recv_buf *recvbuf, union recv_frame *recvframe)
327 {
328 	_pkt *pkt = NULL;
329 	struct rx_pkt_attrib *attrib;
330 	u32 desc_size;
331 	u32 skb_len;
332 	u8 *data;
333 #ifdef CONFIG_SDIO_RX_COPY
334 	u32 shift_sz, alloc_sz;
335 #endif /* CONFIG_SDIO_RX_COPY */
336 
337 
338 	pkt = recvframe->u.hdr.pkt;
339 	if (pkt) {
340 		RTW_WARN("%s: recvframe pkt already exist!\n", __FUNCTION__);
341 		return pkt;
342 	}
343 
344 	desc_size = rtl8822b_get_rx_desc_size(recvbuf->adapter);
345 
346 	attrib = &recvframe->u.hdr.attrib;
347 	skb_len = attrib->pkt_len;
348 	if (rtl8822b_rx_fcs_appended(recvbuf->adapter))
349 		skb_len -= IEEE80211_FCS_LEN;
350 	data = recvbuf->pdata + desc_size + attrib->drvinfo_sz;
351 #if 0
352 	data += attrib->shift_sz;
353 #endif
354 
355 #ifdef CONFIG_SDIO_RX_COPY
356 	/* For 8 bytes IP header alignment. */
357 	if (attrib->qos)
358 		/* Qos data, wireless lan header length is 26 */
359 		shift_sz = 6;
360 	else
361 		shift_sz = 0;
362 
363 	/*
364 	 * For first fragment packet, driver need allocate
365 	 * (1536 + drvinfo_sz + RXDESC_SIZE) to defrag packet.
366 	 * In 8822B, drvinfo_sz = 32, RXDESC_SIZE = 24, 1536 + 32 + 24 = 1592.
367 	 * And need 8 is for skb->data 8 bytes alignment.
368 	 * Round (1536 + 24 + 32 + shift_sz + 8) to 128 bytes alignment,
369 	 * and finally get 1664.
370 	 */
371 	if ((attrib->mfrag == 1) && (attrib->frag_num == 0)) {
372 		if (skb_len <= 1650)
373 			alloc_sz = 1664;
374 		else
375 			alloc_sz = skb_len + 14;
376 	} else {
377 		alloc_sz = skb_len;
378 		/*
379 		 * 6 is for IP header 8 bytes alignment in QoS packet case.
380 		 * 8 is for skb->data 4 bytes alignment.
381 		 */
382 		alloc_sz += 14;
383 	}
384 
385 	pkt = rtw_skb_alloc(alloc_sz);
386 	if (pkt) {
387 		pkt->dev = recvframe->u.hdr.adapter->pnetdev;
388 		/* force pkt->data at 8-byte alignment address */
389 		skb_reserve(pkt, 8 - ((SIZE_PTR)pkt->data & 7));
390 		/* force ip_hdr at 8-byte alignment address according to shift_sz. */
391 		skb_reserve(pkt, shift_sz);
392 		_rtw_memcpy(skb_put(pkt, skb_len), data, skb_len);
393 	} else if ((attrib->mfrag == 1) && (attrib->frag_num == 0)) {
394 		RTW_ERR("%s: alloc_skb fail for first fragement\n", __FUNCTION__);
395 		return NULL;
396 	}
397 #endif /* CONFIG_SDIO_RX_COPY */
398 
399 	if (!pkt) {
400 		pkt = rtw_skb_clone(recvbuf->pskb);
401 		if (!pkt) {
402 			RTW_ERR("%s: rtw_skb_clone fail\n", __FUNCTION__);
403 			return NULL;
404 		}
405 		pkt->data = data;
406 		skb_set_tail_pointer(pkt, skb_len);
407 		pkt->len = skb_len;
408 	}
409 
410 	recvframe->u.hdr.pkt = pkt;
411 	recvframe->u.hdr.len = pkt->len;
412 	recvframe->u.hdr.rx_head = pkt->head;
413 	recvframe->u.hdr.rx_data = pkt->data;
414 	recvframe->u.hdr.rx_tail = skb_tail_pointer(pkt);
415 	recvframe->u.hdr.rx_end = skb_end_pointer(pkt);
416 
417 	return pkt;
418 }
419 
420 /*
421  * Return:
422  *	_SUCCESS	Finish processing recv_buf
423  *	others		Something fail to process recv_buf
424  */
recvbuf_handler(struct recv_buf * recvbuf)425 static u8 recvbuf_handler(struct recv_buf *recvbuf)
426 {
427 	PADAPTER p;
428 	struct recv_priv *recvpriv;
429 	union recv_frame *recvframe;
430 	struct rx_pkt_attrib *attrib;
431 	u32 desc_size;
432 	_pkt *pkt;
433 	u32 rx_report_sz, pkt_offset, pkt_len;
434 	u8 *ptr;
435 	u8 ret = _SUCCESS;
436 
437 
438 	p = recvbuf->adapter;
439 	recvpriv = &p->recvpriv;
440 	ptr = recvbuf->pdata;
441 	desc_size = rtl8822b_get_rx_desc_size(p);
442 
443 	while (ptr < recvbuf->ptail) {
444 		recvframe = rtw_alloc_recvframe(&recvpriv->free_recv_queue);
445 		if (!recvframe) {
446 			RTW_WARN("%s: no enough recv frame!\n", __FUNCTION__);
447 			ret = RTW_RFRAME_UNAVAIL;
448 			break;
449 		}
450 
451 		/* rx desc parsing */
452 		attrib = &recvframe->u.hdr.attrib;
453 		rtl8822b_rxdesc2attribute(attrib, ptr);
454 
455 		/* drop recvbuf if pkt_len of rx desc is too small */
456 		pkt_len = attrib->pkt_len;
457 		if (pkt_len && rtl8822b_rx_fcs_appended(recvbuf->adapter)) {
458 			if (pkt_len > IEEE80211_FCS_LEN)
459 				pkt_len -= IEEE80211_FCS_LEN;
460 			else
461 				pkt_len = 0;
462 		}
463 		if (pkt_len == 0) {
464 			RTW_WARN("%s: pkt len(%u) is too small, skip!\n",
465 				 __FUNCTION__, attrib->pkt_len);
466 			rtw_free_recvframe(recvframe, &recvpriv->free_recv_queue);
467 			break;
468 		}
469 
470 		rx_report_sz = desc_size + attrib->drvinfo_sz;
471 		pkt_offset = rx_report_sz + attrib->shift_sz + attrib->pkt_len;
472 
473 		if ((ptr + pkt_offset) > recvbuf->ptail) {
474 			RTW_WARN("%s: next pkt len(%p,%d) exceed ptail(%p)!\n",
475 				 __FUNCTION__, ptr, pkt_offset, recvbuf->ptail);
476 			rtw_free_recvframe(recvframe, &recvpriv->free_recv_queue);
477 			break;
478 		}
479 
480 		/* fix Hardware RX data error, drop whole recv_buffer */
481 		if (!rtw_hal_rcr_check(p, BIT_ACRC32_8822B)
482 		    && attrib->crc_err) {
483 			RTW_WARN("%s: Received unexpected CRC error packet!!\n", __FUNCTION__);
484 			rtw_free_recvframe(recvframe, &recvpriv->free_recv_queue);
485 			break;
486 		}
487 
488 		if ((attrib->crc_err) || (attrib->icv_err)) {
489 #ifdef CONFIG_MP_INCLUDED
490 			if (p->registrypriv.mp_mode == 1) {
491 				if (check_fwstate(&p->mlmepriv, WIFI_MP_STATE) == _TRUE) {
492 					if (attrib->crc_err == 1)
493 						p->mppriv.rx_crcerrpktcount++;
494 				}
495 			} else
496 #endif /* CONFIG_MP_INCLUDED */
497 			{
498 				RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n",
499 					__FUNCTION__, attrib->crc_err, attrib->icv_err);
500 			}
501 			rtw_free_recvframe(recvframe, &recvpriv->free_recv_queue);
502 		} else {
503 			pkt = prepare_recvframe_pkt(recvbuf, recvframe);
504 			if (!pkt) {
505 				rtw_free_recvframe(recvframe, &recvpriv->free_recv_queue);
506 				ret = RTW_RFRAME_PKT_UNAVAIL;
507 				break;
508 			}
509 
510 			/* move to start of PHY_STATUS */
511 			ptr += desc_size;
512 			if (rtl8822b_rx_ba_ssn_appended(p))
513 				ptr += RTW_HALMAC_BA_SSN_RPT_SIZE;
514 
515 			recv_entry(recvframe, ptr);
516 		}
517 
518 		pkt_offset = _RND8(pkt_offset);
519 		recvbuf->pdata += pkt_offset;
520 		ptr = recvbuf->pdata;
521 	}
522 
523 	return ret;
524 }
525 
c2h_hdl(struct _ADAPTER * a,struct recv_buf * recvbuf)526 static struct recv_buf* c2h_hdl(struct _ADAPTER *a, struct recv_buf *recvbuf)
527 {
528 	u8 c2h = 0;
529 
530 
531 	c2h = GET_RX_DESC_C2H_8822B(recvbuf->pdata);
532 	if (c2h) {
533 		rtl8822b_c2h_handler_no_io(a, recvbuf->pdata, recvbuf->len);
534 
535 		/* free recv_buf */
536 		rtl8822bs_free_recvbuf_skb(recvbuf);
537 		rtw_enqueue_recvbuf(recvbuf, &a->recvpriv.free_recv_buf_queue);
538 		recvbuf = NULL;
539 	}
540 
541 	return recvbuf;
542 }
543 
rtl8822bs_recv_hdl(_adapter * adapter)544 s32 rtl8822bs_recv_hdl(_adapter *adapter)
545 {
546 	struct recv_priv *recvpriv;
547 	struct recv_buf *recvbuf;
548 	s32 ret = _SUCCESS;
549 
550 	recvpriv = &adapter->recvpriv;
551 
552 	do {
553 		recvbuf = rtw_dequeue_recvbuf(&recvpriv->recv_buf_pending_queue);
554 		if (NULL == recvbuf)
555 			break;
556 
557 #ifndef RTW_HANDLE_C2H_IN_ISR
558 		recvbuf = c2h_hdl(adapter, recvbuf);
559 		if (!recvbuf)
560 			continue;
561 #endif /* !RTW_HANDLE_C2H_IN_ISR */
562 
563 		if (adapter_to_dvobj(adapter)->processing_dev_remove != _TRUE) {
564 			ret = recvbuf_handler(recvbuf);
565 			if (ret != _SUCCESS) {
566 				rtw_enqueue_recvbuf_to_head(recvbuf, &recvpriv->recv_buf_pending_queue);
567 				break;
568 			}
569 		} else {
570 			/* drop recv buffer */
571 			RTW_PRINT("%s: drop recv buffer during dev remove!\n", __func__);
572 		}
573 
574 		/* free recv_buf */
575 		rtl8822bs_free_recvbuf_skb(recvbuf);
576 		rtw_enqueue_recvbuf(recvbuf, &recvpriv->free_recv_buf_queue);
577 	} while (1);
578 
579 #ifdef CONFIG_RTW_NAPI
580 #ifdef CONFIG_RTW_NAPI_V2
581 	if (adapter->registrypriv.en_napi) {
582 		struct dvobj_priv *d;
583 		struct _ADAPTER *a;
584 		u8 i;
585 
586 		d = adapter_to_dvobj(adapter);
587 		for (i = 0; i < d->iface_nums; i++) {
588 			a = d->padapters[i];
589 			recvpriv = &a->recvpriv;
590 			if ((rtw_if_up(a) == _TRUE)
591 			    && skb_queue_len(&recvpriv->rx_napi_skb_queue))
592 				napi_schedule(&a->napi);
593 		}
594 	}
595 #endif /* CONFIG_RTW_NAPI_V2 */
596 #endif /* CONFIG_RTW_NAPI */
597 
598 	return ret;
599 }
600 
recv_tasklet(void * priv)601 static void recv_tasklet(void *priv)
602 {
603 	PADAPTER adapter;
604 	s32 ret;
605 
606 	adapter = (PADAPTER)priv;
607 
608 	ret = rtl8822bs_recv_hdl(adapter);
609 	if (ret == RTW_RFRAME_UNAVAIL
610 		|| ret == RTW_RFRAME_PKT_UNAVAIL)
611 		start_rx_handle(adapter);
612 }
613 
614 /*
615  * Initialize recv private variable for hardware dependent
616  * 1. recv buf
617  * 2. recv tasklet
618  */
rtl8822bs_init_recv_priv(PADAPTER adapter)619 s32 rtl8822bs_init_recv_priv(PADAPTER adapter)
620 {
621 	s32 res;
622 	u32 i, n;
623 	struct recv_priv *precvpriv;
624 	struct recv_buf *precvbuf;
625 
626 
627 	res = _SUCCESS;
628 	precvpriv = &adapter->recvpriv;
629 
630 	/* 1. init recv buffer */
631 	_rtw_init_queue(&precvpriv->free_recv_buf_queue);
632 	_rtw_init_queue(&precvpriv->recv_buf_pending_queue);
633 
634 	n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
635 	precvpriv->pallocated_recv_buf = rtw_zmalloc(n);
636 	if (precvpriv->pallocated_recv_buf == NULL) {
637 		res = _FAIL;
638 		goto exit;
639 	}
640 
641 	precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
642 
643 	/* init each recv buffer */
644 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
645 	for (i = 0; i < NR_RECVBUFF; i++) {
646 		res = initrecvbuf(precvbuf, adapter);
647 		if (res == _FAIL)
648 			break;
649 
650 		res = rtw_os_recvbuf_resource_alloc(adapter, precvbuf);
651 		if (res == _FAIL) {
652 			freerecvbuf(precvbuf);
653 			break;
654 		}
655 
656 		res = os_recvbuf_resource_alloc(adapter, precvbuf);
657 		if (res == _FAIL) {
658 			freerecvbuf(precvbuf);
659 			break;
660 		}
661 
662 		rtw_list_insert_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue);
663 
664 		precvbuf++;
665 	}
666 	precvpriv->free_recv_buf_queue_cnt = i;
667 
668 	if (res == _FAIL)
669 		goto initbuferror;
670 
671 	/* 2. init tasklet */
672 #ifdef PLATFORM_LINUX
673 	tasklet_init(&precvpriv->recv_tasklet,
674 		     (void(*)(unsigned long))recv_tasklet,
675 		     (unsigned long)adapter);
676 #endif
677 
678 	goto exit;
679 
680 initbuferror:
681 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
682 	if (precvbuf) {
683 		n = precvpriv->free_recv_buf_queue_cnt;
684 		precvpriv->free_recv_buf_queue_cnt = 0;
685 		for (i = 0; i < n ; i++) {
686 			rtw_list_delete(&precvbuf->list);
687 			os_recvbuf_resource_free(adapter, precvbuf);
688 			rtw_os_recvbuf_resource_free(adapter, precvbuf);
689 			freerecvbuf(precvbuf);
690 			precvbuf++;
691 		}
692 		precvpriv->precv_buf = NULL;
693 	}
694 
695 	if (precvpriv->pallocated_recv_buf) {
696 		n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
697 		rtw_mfree(precvpriv->pallocated_recv_buf, n);
698 		precvpriv->pallocated_recv_buf = NULL;
699 	}
700 
701 exit:
702 	return res;
703 }
704 
705 /*
706  * Free recv private variable of hardware dependent
707  * 1. recv buf
708  * 2. recv tasklet
709  */
rtl8822bs_free_recv_priv(PADAPTER adapter)710 void rtl8822bs_free_recv_priv(PADAPTER adapter)
711 {
712 	u32 i, n;
713 	struct recv_priv *precvpriv;
714 	struct recv_buf *precvbuf;
715 
716 
717 	precvpriv = &adapter->recvpriv;
718 
719 	/* 1. kill tasklet */
720 	stop_rx_handle(adapter);
721 
722 	/* 2. free all recv buffers */
723 	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
724 	if (precvbuf) {
725 		n = precvpriv->free_recv_buf_queue_cnt;
726 		precvpriv->free_recv_buf_queue_cnt = 0;
727 		for (i = 0; i < n ; i++) {
728 			rtw_list_delete(&precvbuf->list);
729 			os_recvbuf_resource_free(adapter, precvbuf);
730 			rtw_os_recvbuf_resource_free(adapter, precvbuf);
731 			freerecvbuf(precvbuf);
732 			precvbuf++;
733 		}
734 		precvpriv->precv_buf = NULL;
735 	}
736 
737 	if (precvpriv->pallocated_recv_buf) {
738 		n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
739 		rtw_mfree(precvpriv->pallocated_recv_buf, n);
740 		precvpriv->pallocated_recv_buf = NULL;
741 	}
742 }
743 
rtl8822bs_rxhandler(PADAPTER adapter,struct recv_buf * recvbuf)744 void rtl8822bs_rxhandler(PADAPTER adapter, struct recv_buf *recvbuf)
745 {
746 	struct recv_priv *recvpriv;
747 	_queue *pending_queue;
748 
749 
750 #ifdef RTW_HANDLE_C2H_IN_ISR
751 	recvbuf = c2h_hdl(adapter, recvbuf);
752 	if (!recvbuf)
753 		return;
754 #endif /* RTW_HANDLE_C2H_IN_ISR */
755 
756 	recvpriv = &adapter->recvpriv;
757 	pending_queue = &recvpriv->recv_buf_pending_queue;
758 
759 	/* 1. enqueue recvbuf */
760 	rtw_enqueue_recvbuf(recvbuf, pending_queue);
761 
762 	/* 2. schedule tasklet */
763 	start_rx_handle(adapter);
764 }
765