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