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