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(©frame->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