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