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 _RTL8723DS_RECV_C_
22 #include <rtl8723d_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 rtl8723ds_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 allocate recvframe should be temporary, */
73 /* schedule again and hope recvframe is available next time. */
75 tasklet_schedule(&precvpriv->recv_tasklet);
81 rtl8723d_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);
129 recvframe_put(precvframe, pattrib->pkt_len);
130 /* move to drv info position */
133 /* update drv info */
134 if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) {
135 /* rtl8723s_update_bassn(padapter, pdrvinfo); */
139 if (pattrib->pkt_rpt_type == NORMAL_RX) {
140 /* skip the rx packet with abnormal length */
141 if (pattrib->pkt_len < 14 || pattrib->pkt_len > 8192) {
142 RTW_INFO("skip abnormal rx packet(%d)\n", pattrib->pkt_len);
143 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
147 #ifdef CONFIG_CONCURRENT_MODE
148 pre_recv_entry(precvframe, ptr);
152 rx_query_phy_status(precvframe, ptr);
154 rtw_recv_entry(precvframe);
156 #ifdef CONFIG_FW_C2H_PKT
157 if (pattrib->pkt_rpt_type == C2H_PACKET)
158 rtw_hal_c2h_pkt_pre_hdl(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
160 RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
161 __FUNCTION__, pattrib->pkt_rpt_type);
164 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
168 pkt_offset = _RND8(pkt_offset);
169 precvbuf->pdata += pkt_offset;
170 ptr = precvbuf->pdata;
174 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
179 static void rtl8723ds_recv_tasklet(void *priv)
182 PHAL_DATA_TYPE pHalData;
183 struct recv_priv *precvpriv;
184 struct recv_buf *precvbuf;
185 union recv_frame *precvframe;
186 struct recv_frame_hdr *phdr;
187 struct rx_pkt_attrib *pattrib;
192 padapter = (PADAPTER)priv;
193 pHalData = GET_HAL_DATA(padapter);
194 precvpriv = &padapter->recvpriv;
197 precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
198 if (NULL == precvbuf)
201 ptr = precvbuf->pdata;
203 while (ptr < precvbuf->ptail) {
204 precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
205 if (precvframe == NULL) {
206 rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
208 /* The case of can't allocate recvframe should be temporary, */
209 /* schedule again and hope recvframe is available next time. */
210 #ifdef PLATFORM_LINUX
211 tasklet_schedule(&precvpriv->recv_tasklet);
216 phdr = &precvframe->u.hdr;
217 pattrib = &phdr->attrib;
219 rtl8723d_query_rx_desc_status(precvframe, ptr);
226 if ((*(pptr + RXDESC_SIZE + pattrib->drvinfo_sz) != 0x80) && (*(pptr + RXDESC_SIZE + pattrib->drvinfo_sz) != 0x40)) {
227 RTW_INFO("##############RxDESC###############\n");
228 for (i = 0; i < 32; i = i + 16)
229 RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(pptr + i),
230 *(pptr + i + 1), *(pptr + i + 2) , *(pptr + i + 3) , *(pptr + i + 4), *(pptr + i + 5), *(pptr + i + 6), *(pptr + i + 7), *(pptr + i + 8),
231 *(pptr + i + 9), *(pptr + i + 10),
232 *(pptr + i + 11), *(pptr + i + 12), *(pptr + i + 13), *(pptr + i + 14), *(pptr + i + 15));
234 if (pattrib->pkt_len < 100)
235 len = pattrib->pkt_len;
236 pptr = ptr + RXDESC_SIZE + pattrib->drvinfo_sz;
237 RTW_INFO("##############Len=%d###############\n", pattrib->pkt_len);
238 for (i = 0; i < len; i = i + 16)
239 RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(pptr + i),
240 *(pptr + i + 1), *(pptr + i + 2) , *(pptr + i + 3) , *(pptr + i + 4), *(pptr + i + 5), *(pptr + i + 6), *(pptr + i + 7), *(pptr + i + 8),
241 *(pptr + i + 9), *(pptr + i + 10),
242 *(pptr + i + 11), *(pptr + i + 12), *(pptr + i + 13), *(pptr + i + 14), *(pptr + i + 15));
243 RTW_INFO("#############################\n");
248 /* fix Hardware RX data error, drop whole recv_buffer */
249 if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
250 RTW_INFO("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__);
251 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
255 pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->pkt_len;
256 #if 0 /* reduce check to speed up */
257 if ((ptr + pkt_offset) > precvbuf->ptail) {
258 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
263 if ((pattrib->crc_err) || (pattrib->icv_err)) {
264 #ifdef CONFIG_MP_INCLUDED
265 if (padapter->registrypriv.mp_mode == 1) {
266 if (check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _TRUE) { /* &&(padapter->mppriv.check_mp_pkt == 0)) */
267 if (pattrib->crc_err == 1)
268 padapter->mppriv.rx_crcerrpktcount++;
273 RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err);
275 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
277 ppkt = rtw_skb_clone(precvbuf->pskb);
279 RTW_INFO("%s: no enough memory to allocate SKB!\n", __FUNCTION__);
280 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
281 rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
283 /* The case of can't allocate skb is serious and may never be recovered, */
284 /* once bDriverStopped is enable, this task should be stopped. */
285 if (!rtw_is_drv_stopped(padapter)) {
286 #ifdef PLATFORM_LINUX
287 tasklet_schedule(&precvpriv->recv_tasklet);
296 phdr->rx_head = precvbuf->phead;
297 phdr->rx_data = phdr->rx_tail = precvbuf->pdata;
298 phdr->rx_end = precvbuf->pend;
299 recvframe_put(precvframe, pkt_offset);
300 recvframe_pull(precvframe, RXDESC_SIZE + pattrib->drvinfo_sz);
301 skb_pull(ppkt, RXDESC_SIZE + pattrib->drvinfo_sz);
303 #ifdef CONFIG_RX_PACKET_APPEND_FCS
304 if (check_fwstate(&padapter->mlmepriv, WIFI_MONITOR_STATE) == _FALSE) {
305 if ((pattrib->pkt_rpt_type == NORMAL_RX) && (pHalData->ReceiveConfig & RCR_APPFCS)) {
306 recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN);
307 pattrib->pkt_len -= IEEE80211_FCS_LEN;
308 ppkt->len = pattrib->pkt_len;
313 /* move to drv info position */
316 /* update drv info */
317 if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) {
318 /* rtl8723s_update_bassn(padapter, pdrvinfo); */
322 if (pattrib->pkt_rpt_type == NORMAL_RX) {
323 #ifdef CONFIG_CONCURRENT_MODE
324 pre_recv_entry(precvframe, ptr);
325 #endif /*CONFIG_CONCURRENT_MODE*/
328 rx_query_phy_status(precvframe, ptr);
330 rtw_recv_entry(precvframe);
332 #ifdef CONFIG_FW_C2H_PKT
333 if (pattrib->pkt_rpt_type == C2H_PACKET)
334 rtw_hal_c2h_pkt_pre_hdl(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
336 RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
337 __FUNCTION__, pattrib->pkt_rpt_type);
340 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
344 pkt_offset = _RND8(pkt_offset);
345 precvbuf->pdata += pkt_offset;
346 ptr = precvbuf->pdata;
349 rtw_skb_free(precvbuf->pskb);
350 precvbuf->pskb = NULL;
351 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
357 * Initialize recv private variable for hardware dependent
362 s32 rtl8723ds_init_recv_priv(PADAPTER padapter)
366 struct recv_priv *precvpriv;
367 struct recv_buf *precvbuf;
371 precvpriv = &padapter->recvpriv;
373 /* 3 1. init recv buffer */
374 _rtw_init_queue(&precvpriv->free_recv_buf_queue);
375 _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
377 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
378 precvpriv->pallocated_recv_buf = rtw_zmalloc(n);
379 if (precvpriv->pallocated_recv_buf == NULL) {
384 precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
386 /* init each recv buffer */
387 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
388 for (i = 0; i < NR_RECVBUFF; i++) {
389 res = initrecvbuf(precvbuf, padapter);
393 res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
395 freerecvbuf(precvbuf);
399 #ifdef CONFIG_SDIO_RX_COPY
400 if (precvbuf->pskb == NULL) {
401 SIZE_PTR tmpaddr = 0;
402 SIZE_PTR alignment = 0;
404 precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
406 if (precvbuf->pskb) {
407 precvbuf->pskb->dev = padapter->pnetdev;
409 tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
410 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
411 skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
414 if (precvbuf->pskb == NULL)
415 RTW_INFO("%s: alloc_skb fail!\n", __FUNCTION__);
419 rtw_list_insert_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue);
423 precvpriv->free_recv_buf_queue_cnt = i;
428 /* 3 2. init tasklet */
429 #ifdef PLATFORM_LINUX
430 tasklet_init(&precvpriv->recv_tasklet,
431 (void(*)(unsigned long))rtl8723ds_recv_tasklet,
432 (unsigned long)padapter);
438 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
440 n = precvpriv->free_recv_buf_queue_cnt;
441 precvpriv->free_recv_buf_queue_cnt = 0;
442 for (i = 0; i < n ; i++) {
443 rtw_list_delete(&precvbuf->list);
444 rtw_os_recvbuf_resource_free(padapter, precvbuf);
445 freerecvbuf(precvbuf);
448 precvpriv->precv_buf = NULL;
451 if (precvpriv->pallocated_recv_buf) {
452 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
453 rtw_mfree(precvpriv->pallocated_recv_buf, n);
454 precvpriv->pallocated_recv_buf = NULL;
462 * Free recv private variable of hardware dependent
467 void rtl8723ds_free_recv_priv(PADAPTER padapter)
470 struct recv_priv *precvpriv;
471 struct recv_buf *precvbuf;
474 precvpriv = &padapter->recvpriv;
476 /* 3 1. kill tasklet */
477 #ifdef PLATFORM_LINUX
478 tasklet_kill(&precvpriv->recv_tasklet);
481 /* 3 2. free all recv buffers */
482 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
485 precvpriv->free_recv_buf_queue_cnt = 0;
486 for (i = 0; i < n ; i++) {
487 rtw_list_delete(&precvbuf->list);
488 rtw_os_recvbuf_resource_free(padapter, precvbuf);
489 freerecvbuf(precvbuf);
492 precvpriv->precv_buf = NULL;
495 if (precvpriv->pallocated_recv_buf) {
496 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
497 rtw_mfree(precvpriv->pallocated_recv_buf, n);
498 precvpriv->pallocated_recv_buf = NULL;