1 /******************************************************************************
3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
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.
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
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 ******************************************************************************/
20 #define _RTL8703BS_RECV_C_
22 #include <rtl8703b_hal.h>
25 static s32 initrecvbuf(struct recv_buf *precvbuf, PADAPTER padapter)
27 _rtw_init_listhead(&precvbuf->list);
28 _rtw_spinlock_init(&precvbuf->recvbuf_lock);
30 precvbuf->adapter = padapter;
35 static void freerecvbuf(struct recv_buf *precvbuf)
37 _rtw_spinlock_free(&precvbuf->recvbuf_lock);
40 #ifdef CONFIG_SDIO_RX_COPY
41 static void rtl8703bs_recv_tasklet(void *priv)
44 PHAL_DATA_TYPE pHalData;
45 struct recv_priv *precvpriv;
46 struct recv_buf *precvbuf;
47 union recv_frame *precvframe;
48 struct recv_frame_hdr *phdr;
49 struct rx_pkt_attrib *pattrib;
51 u32 pkt_len, pkt_offset;
55 padapter = (PADAPTER)priv;
56 pHalData = GET_HAL_DATA(padapter);
57 precvpriv = &padapter->recvpriv;
60 precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
64 ptr = precvbuf->pdata;
66 while (ptr < precvbuf->ptail) {
67 precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
68 if (precvframe == NULL) {
69 RTW_INFO("%s: no enough recv frame!\n", __FUNCTION__);
70 rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
72 /* The case of can't allocte recvframe should be temporary, */
73 /* schedule again and hope recvframe is available next time. */
75 tasklet_schedule(&precvpriv->recv_tasklet);
81 rtl8703b_query_rx_desc_status(precvframe, ptr);
83 pattrib = &precvframe->u.hdr.attrib;
85 /* fix Hardware RX data error, drop whole recv_buffer */
86 if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
88 RTW_INFO("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__);
90 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
94 rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz;
95 pkt_offset = rx_report_sz + pattrib->shift_sz + pattrib->pkt_len;
97 if ((ptr + pkt_offset) > precvbuf->ptail) {
98 RTW_INFO("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", __FUNCTION__, __LINE__, ptr, pkt_offset, precvbuf->ptail);
99 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
103 if ((pattrib->crc_err) || (pattrib->icv_err)) {
104 #ifdef CONFIG_MP_INCLUDED
105 if (padapter->registrypriv.mp_mode == 1) {
106 if ((check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _TRUE)) { /* &&(padapter->mppriv.check_mp_pkt == 0)) */
107 if (pattrib->crc_err == 1)
108 padapter->mppriv.rx_crcerrpktcount++;
113 RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err);
115 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
117 #ifdef CONFIG_RX_PACKET_APPEND_FCS
118 if (check_fwstate(&padapter->mlmepriv, WIFI_MONITOR_STATE) == _FALSE)
119 if ((pattrib->pkt_rpt_type == NORMAL_RX) && (pHalData->ReceiveConfig & RCR_APPFCS))
120 pattrib->pkt_len -= IEEE80211_FCS_LEN;
123 if (rtw_os_alloc_recvframe(padapter, precvframe,
124 (ptr + rx_report_sz + pattrib->shift_sz), precvbuf->pskb) == _FAIL) {
125 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
128 recvframe_put(precvframe, pattrib->pkt_len);
129 /* recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); */
131 /* move to drv info position */
134 /* update drv info */
135 if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) {
136 /* rtl8703s_update_bassn(padapter, pdrvinfo); */
140 if (pattrib->pkt_rpt_type == NORMAL_RX) {
141 /* skip the rx packet with abnormal length */
142 if (pattrib->pkt_len < 14 || pattrib->pkt_len > 8192) {
143 RTW_INFO("skip abnormal rx packet(%d)\n", pattrib->pkt_len);
144 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
148 #ifdef CONFIG_CONCURRENT_MODE
149 pre_recv_entry(precvframe, ptr);
150 #endif /*CONFIG_CONCURRENT_MODE*/
153 rx_query_phy_status(precvframe, ptr);
155 rtw_recv_entry(precvframe);
157 #ifdef CONFIG_FW_C2H_PKT
158 if (pattrib->pkt_rpt_type == C2H_PACKET)
159 rtw_hal_c2h_pkt_pre_hdl(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
161 RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
162 __FUNCTION__, pattrib->pkt_rpt_type);
165 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
169 pkt_offset = _RND8(pkt_offset);
170 precvbuf->pdata += pkt_offset;
171 ptr = precvbuf->pdata;
175 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
180 static void rtl8703bs_recv_tasklet(void *priv)
183 PHAL_DATA_TYPE pHalData;
184 struct recv_priv *precvpriv;
185 struct recv_buf *precvbuf;
186 union recv_frame *precvframe;
187 struct recv_frame_hdr *phdr;
188 struct rx_pkt_attrib *pattrib;
193 padapter = (PADAPTER)priv;
194 pHalData = GET_HAL_DATA(padapter);
195 precvpriv = &padapter->recvpriv;
198 precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
199 if (NULL == precvbuf)
202 ptr = precvbuf->pdata;
204 while (ptr < precvbuf->ptail) {
205 precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
206 if (precvframe == NULL) {
207 rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
209 /* The case of can't allocte recvframe should be temporary, */
210 /* schedule again and hope recvframe is available next time. */
211 #ifdef PLATFORM_LINUX
212 tasklet_schedule(&precvpriv->recv_tasklet);
217 phdr = &precvframe->u.hdr;
218 pattrib = &phdr->attrib;
220 rtl8703b_query_rx_desc_status(precvframe, ptr);
227 if ((*(pptr + RXDESC_SIZE + pattrib->drvinfo_sz) != 0x80) && (*(pptr + RXDESC_SIZE + pattrib->drvinfo_sz) != 0x40)) {
228 RTW_INFO("##############RxDESC###############\n");
229 for (i = 0; i < 32; i = i + 16)
230 RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(pptr + i),
231 *(pptr + i + 1), *(pptr + i + 2) , *(pptr + i + 3) , *(pptr + i + 4), *(pptr + i + 5), *(pptr + i + 6), *(pptr + i + 7), *(pptr + i + 8),
232 *(pptr + i + 9), *(pptr + i + 10),
233 *(pptr + i + 11), *(pptr + i + 12), *(pptr + i + 13), *(pptr + i + 14), *(pptr + i + 15));
235 if (pattrib->pkt_len < 100)
236 len = pattrib->pkt_len;
237 pptr = ptr + RXDESC_SIZE + pattrib->drvinfo_sz;
238 RTW_INFO("##############Len=%d###############\n", pattrib->pkt_len);
239 for (i = 0; i < len; i = i + 16)
240 RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(pptr + i),
241 *(pptr + i + 1), *(pptr + i + 2) , *(pptr + i + 3) , *(pptr + i + 4), *(pptr + i + 5), *(pptr + i + 6), *(pptr + i + 7), *(pptr + i + 8),
242 *(pptr + i + 9), *(pptr + i + 10),
243 *(pptr + i + 11), *(pptr + i + 12), *(pptr + i + 13), *(pptr + i + 14), *(pptr + i + 15));
244 RTW_INFO("#############################\n");
249 /* fix Hardware RX data error, drop whole recv_buffer */
250 if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
251 RTW_INFO("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__);
252 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
256 pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->pkt_len;
257 #if 0 /* reduce check to speed up */
258 if ((ptr + pkt_offset) > precvbuf->ptail) {
259 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
264 if ((pattrib->crc_err) || (pattrib->icv_err)) {
265 #ifdef CONFIG_MP_INCLUDED
266 if (padapter->registrypriv.mp_mode == 1) {
267 if ((check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _TRUE)) { /* &&(padapter->mppriv.check_mp_pkt == 0)) */
268 if (pattrib->crc_err == 1)
269 padapter->mppriv.rx_crcerrpktcount++;
274 RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err);
276 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
278 ppkt = rtw_skb_clone(precvbuf->pskb);
280 RTW_INFO("%s: no enough memory to allocate SKB!\n", __FUNCTION__);
281 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
282 rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
284 /* The case of can't allocte skb is serious and may never be recovered, */
285 /* once bDriverStopped is enable, this task should be stopped. */
286 if (!rtw_is_drv_stopped(padapter)) {
287 #ifdef PLATFORM_LINUX
288 tasklet_schedule(&precvpriv->recv_tasklet);
297 phdr->rx_head = precvbuf->phead;
298 phdr->rx_data = phdr->rx_tail = precvbuf->pdata;
299 phdr->rx_end = precvbuf->pend;
300 recvframe_put(precvframe, pkt_offset);
301 recvframe_pull(precvframe, RXDESC_SIZE + pattrib->drvinfo_sz);
302 skb_pull(ppkt, RXDESC_SIZE + pattrib->drvinfo_sz);
304 #ifdef CONFIG_RX_PACKET_APPEND_FCS
305 if (check_fwstate(&padapter->mlmepriv, WIFI_MONITOR_STATE) == _FALSE) {
306 if ((pattrib->pkt_rpt_type == NORMAL_RX) && (pHalData->ReceiveConfig & RCR_APPFCS)) {
307 recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN);
308 pattrib->pkt_len -= IEEE80211_FCS_LEN;
309 ppkt->len = pattrib->pkt_len;
314 /* move to drv info position */
317 /* update drv info */
318 if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) {
319 /* rtl8703s_update_bassn(padapter, pdrvinfo); */
323 if (pattrib->pkt_rpt_type == NORMAL_RX) {
325 #ifdef CONFIG_CONCURRENT_MODE
326 pre_recv_entry(precvframe, ptr);
327 #endif /*CONFIG_CONCURRENT_MODE*/
331 rx_query_phy_status(precvframe, ptr);
333 rtw_recv_entry(precvframe);
337 #ifdef CONFIG_FW_C2H_PKT
338 if (pattrib->pkt_rpt_type == C2H_PACKET)
339 rtw_hal_c2h_pkt_pre_hdl(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
341 RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
342 __FUNCTION__, pattrib->pkt_rpt_type);
345 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
349 pkt_offset = _RND8(pkt_offset);
350 precvbuf->pdata += pkt_offset;
351 ptr = precvbuf->pdata;
354 rtw_skb_free(precvbuf->pskb);
355 precvbuf->pskb = NULL;
356 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
362 * Initialize recv private variable for hardware dependent
367 s32 rtl8703bs_init_recv_priv(PADAPTER padapter)
371 struct recv_priv *precvpriv;
372 struct recv_buf *precvbuf;
376 precvpriv = &padapter->recvpriv;
378 /* 3 1. init recv buffer */
379 _rtw_init_queue(&precvpriv->free_recv_buf_queue);
380 _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
382 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
383 precvpriv->pallocated_recv_buf = rtw_zmalloc(n);
384 if (precvpriv->pallocated_recv_buf == NULL) {
389 precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
391 /* init each recv buffer */
392 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
393 for (i = 0; i < NR_RECVBUFF; i++) {
394 res = initrecvbuf(precvbuf, padapter);
398 res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
400 freerecvbuf(precvbuf);
404 #ifdef CONFIG_SDIO_RX_COPY
405 if (precvbuf->pskb == NULL) {
406 SIZE_PTR tmpaddr = 0;
407 SIZE_PTR alignment = 0;
409 precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
411 if (precvbuf->pskb) {
412 precvbuf->pskb->dev = padapter->pnetdev;
414 tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
415 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
416 skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
419 if (precvbuf->pskb == NULL)
420 RTW_INFO("%s: alloc_skb fail!\n", __FUNCTION__);
424 rtw_list_insert_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue);
428 precvpriv->free_recv_buf_queue_cnt = i;
433 /* 3 2. init tasklet */
434 #ifdef PLATFORM_LINUX
435 tasklet_init(&precvpriv->recv_tasklet,
436 (void(*)(unsigned long))rtl8703bs_recv_tasklet,
437 (unsigned long)padapter);
443 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
445 n = precvpriv->free_recv_buf_queue_cnt;
446 precvpriv->free_recv_buf_queue_cnt = 0;
447 for (i = 0; i < n ; i++) {
448 rtw_list_delete(&precvbuf->list);
449 rtw_os_recvbuf_resource_free(padapter, precvbuf);
450 freerecvbuf(precvbuf);
453 precvpriv->precv_buf = NULL;
456 if (precvpriv->pallocated_recv_buf) {
457 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
458 rtw_mfree(precvpriv->pallocated_recv_buf, n);
459 precvpriv->pallocated_recv_buf = NULL;
467 * Free recv private variable of hardware dependent
472 void rtl8703bs_free_recv_priv(PADAPTER padapter)
475 struct recv_priv *precvpriv;
476 struct recv_buf *precvbuf;
479 precvpriv = &padapter->recvpriv;
481 /* 3 1. kill tasklet */
482 #ifdef PLATFORM_LINUX
483 tasklet_kill(&precvpriv->recv_tasklet);
486 /* 3 2. free all recv buffers */
487 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
490 precvpriv->free_recv_buf_queue_cnt = 0;
491 for (i = 0; i < n ; i++) {
492 rtw_list_delete(&precvbuf->list);
493 rtw_os_recvbuf_resource_free(padapter, precvbuf);
494 freerecvbuf(precvbuf);
497 precvpriv->precv_buf = NULL;
500 if (precvpriv->pallocated_recv_buf) {
501 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
502 rtw_mfree(precvpriv->pallocated_recv_buf, n);
503 precvpriv->pallocated_recv_buf = NULL;