net: wireless: rockchip_wlan: add rtl8723cs support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723cs / hal / rtl8703b / sdio / rtl8703bs_recv.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
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  * 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
17  *
18  *
19  ******************************************************************************/
20 #define _RTL8703BS_RECV_C_
21
22 #include <rtl8703b_hal.h>
23
24
25 static s32 initrecvbuf(struct recv_buf *precvbuf, PADAPTER padapter)
26 {
27         _rtw_init_listhead(&precvbuf->list);
28         _rtw_spinlock_init(&precvbuf->recvbuf_lock);
29
30         precvbuf->adapter = padapter;
31
32         return _SUCCESS;
33 }
34
35 static void freerecvbuf(struct recv_buf *precvbuf)
36 {
37         _rtw_spinlock_free(&precvbuf->recvbuf_lock);
38 }
39
40 #ifdef CONFIG_SDIO_RX_COPY
41 static void rtl8703bs_recv_tasklet(void *priv)
42 {
43         PADAPTER                        padapter;
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;
50         u8      *ptr;
51         u32     pkt_len, pkt_offset;
52         u8      rx_report_sz = 0;
53
54
55         padapter = (PADAPTER)priv;
56         pHalData = GET_HAL_DATA(padapter);
57         precvpriv = &padapter->recvpriv;
58
59         do {
60                 precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
61                 if (NULL == precvbuf)
62                         break;
63
64                 ptr = precvbuf->pdata;
65
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);
71
72                                 /* The case of can't allocte recvframe should be temporary, */
73                                 /* schedule again and hope recvframe is available next time. */
74 #ifdef PLATFORM_LINUX
75                                 tasklet_schedule(&precvpriv->recv_tasklet);
76 #endif
77                                 return;
78                         }
79
80                         /* rx desc parsing */
81                         rtl8703b_query_rx_desc_status(precvframe, ptr);
82
83                         pattrib = &precvframe->u.hdr.attrib;
84
85                         /* fix Hardware RX data error, drop whole recv_buffer */
86                         if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
87 #if !(MP_DRIVER == 1)
88                                 RTW_INFO("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__);
89 #endif
90                                 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
91                                 break;
92                         }
93
94                         rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz;
95                         pkt_offset = rx_report_sz + pattrib->shift_sz + pattrib->pkt_len;
96
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);
100                                 break;
101                         }
102
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++;
109                                         }
110                                 } else
111 #endif
112                                 {
113                                         RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err);
114                                 }
115                                 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
116                         } else {
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;
121 #endif
122
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);
126                                         break;
127                                 }
128                                 recvframe_put(precvframe, pattrib->pkt_len);
129                                 /* recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); */
130
131                                 /* move to drv info position */
132                                 ptr += RXDESC_SIZE;
133
134                                 /* update drv info */
135                                 if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) {
136                                         /* rtl8703s_update_bassn(padapter, pdrvinfo); */
137                                         ptr += 4;
138                                 }
139
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);
145                                                 break;
146                                         }
147
148 #ifdef CONFIG_CONCURRENT_MODE
149                                         pre_recv_entry(precvframe, ptr);
150 #endif /*CONFIG_CONCURRENT_MODE*/
151
152                                         if (pattrib->physt)
153                                                 rx_query_phy_status(precvframe, ptr);
154
155                                         rtw_recv_entry(precvframe);
156                                 } else {
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);
160                                         else {
161                                                 RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
162                                                         __FUNCTION__, pattrib->pkt_rpt_type);
163                                         }
164 #endif
165                                         rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
166                                 }
167                         }
168
169                         pkt_offset = _RND8(pkt_offset);
170                         precvbuf->pdata += pkt_offset;
171                         ptr = precvbuf->pdata;
172                         precvframe = NULL;
173                 }
174
175                 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
176         } while (1);
177
178 }
179 #else
180 static void rtl8703bs_recv_tasklet(void *priv)
181 {
182         PADAPTER                                padapter;
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;
189         u8              *ptr;
190         _pkt            *ppkt;
191         u32             pkt_offset;
192
193         padapter = (PADAPTER)priv;
194         pHalData = GET_HAL_DATA(padapter);
195         precvpriv = &padapter->recvpriv;
196
197         do {
198                 precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
199                 if (NULL == precvbuf)
200                         break;
201
202                 ptr = precvbuf->pdata;
203
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);
208
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);
213 #endif
214                                 return;
215                         }
216
217                         phdr = &precvframe->u.hdr;
218                         pattrib = &phdr->attrib;
219
220                         rtl8703b_query_rx_desc_status(precvframe, ptr);
221
222 #if 0
223                         {
224                                 int i, len = 64;
225                                 u8 *pptr = ptr;
226
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));
234
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");
245                                 }
246                         }
247 #endif
248
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);
253                                 break;
254                         }
255
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);
260                                 break;
261                         }
262 #endif
263
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++;
270                                         }
271                                 } else
272 #endif
273                                 {
274                                         RTW_INFO("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err);
275                                 }
276                                 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
277                         } else {
278                                 ppkt = rtw_skb_clone(precvbuf->pskb);
279                                 if (ppkt == NULL) {
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);
283
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);
289 #endif
290                                         }
291
292                                         return;
293                                 }
294
295                                 phdr->pkt = ppkt;
296                                 phdr->len = 0;
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);
303
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;
310                                         }
311                                 }
312 #endif
313
314                                 /* move to drv info position */
315                                 ptr += RXDESC_SIZE;
316
317                                 /* update drv info */
318                                 if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) {
319                                         /* rtl8703s_update_bassn(padapter, pdrvinfo); */
320                                         ptr += 4;
321                                 }
322
323                                 if (pattrib->pkt_rpt_type == NORMAL_RX) {
324
325 #ifdef CONFIG_CONCURRENT_MODE
326                                         pre_recv_entry(precvframe, ptr);
327 #endif /*CONFIG_CONCURRENT_MODE*/
328
329
330                                         if (pattrib->physt)
331                                                 rx_query_phy_status(precvframe, ptr);
332
333                                         rtw_recv_entry(precvframe);
334
335
336                                 } else {
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);
340                                         else {
341                                                 RTW_INFO("%s: [WARNNING] RX type(%d) not be handled!\n",
342                                                         __FUNCTION__, pattrib->pkt_rpt_type);
343                                         }
344 #endif
345                                         rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
346                                 }
347                         }
348
349                         pkt_offset = _RND8(pkt_offset);
350                         precvbuf->pdata += pkt_offset;
351                         ptr = precvbuf->pdata;
352                 }
353
354                 rtw_skb_free(precvbuf->pskb);
355                 precvbuf->pskb = NULL;
356                 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
357         } while (1);
358 }
359 #endif
360
361 /*
362  * Initialize recv private variable for hardware dependent
363  * 1. recv buf
364  * 2. recv tasklet
365  *
366  */
367 s32 rtl8703bs_init_recv_priv(PADAPTER padapter)
368 {
369         s32                     res;
370         u32                     i, n;
371         struct recv_priv        *precvpriv;
372         struct recv_buf         *precvbuf;
373
374
375         res = _SUCCESS;
376         precvpriv = &padapter->recvpriv;
377
378         /* 3 1. init recv buffer */
379         _rtw_init_queue(&precvpriv->free_recv_buf_queue);
380         _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
381
382         n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
383         precvpriv->pallocated_recv_buf = rtw_zmalloc(n);
384         if (precvpriv->pallocated_recv_buf == NULL) {
385                 res = _FAIL;
386                 goto exit;
387         }
388
389         precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
390
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);
395                 if (res == _FAIL)
396                         break;
397
398                 res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
399                 if (res == _FAIL) {
400                         freerecvbuf(precvbuf);
401                         break;
402                 }
403
404 #ifdef CONFIG_SDIO_RX_COPY
405                 if (precvbuf->pskb == NULL) {
406                         SIZE_PTR tmpaddr = 0;
407                         SIZE_PTR alignment = 0;
408
409                         precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
410
411                         if (precvbuf->pskb) {
412                                 precvbuf->pskb->dev = padapter->pnetdev;
413
414                                 tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
415                                 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
416                                 skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
417                         }
418
419                         if (precvbuf->pskb == NULL)
420                                 RTW_INFO("%s: alloc_skb fail!\n", __FUNCTION__);
421                 }
422 #endif
423
424                 rtw_list_insert_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue);
425
426                 precvbuf++;
427         }
428         precvpriv->free_recv_buf_queue_cnt = i;
429
430         if (res == _FAIL)
431                 goto initbuferror;
432
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);
438 #endif
439
440         goto exit;
441
442 initbuferror:
443         precvbuf = (struct recv_buf *)precvpriv->precv_buf;
444         if (precvbuf) {
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);
451                         precvbuf++;
452                 }
453                 precvpriv->precv_buf = NULL;
454         }
455
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;
460         }
461
462 exit:
463         return res;
464 }
465
466 /*
467  * Free recv private variable of hardware dependent
468  * 1. recv buf
469  * 2. recv tasklet
470  *
471  */
472 void rtl8703bs_free_recv_priv(PADAPTER padapter)
473 {
474         u32                     i, n;
475         struct recv_priv        *precvpriv;
476         struct recv_buf         *precvbuf;
477
478
479         precvpriv = &padapter->recvpriv;
480
481         /* 3 1. kill tasklet */
482 #ifdef PLATFORM_LINUX
483         tasklet_kill(&precvpriv->recv_tasklet);
484 #endif
485
486         /* 3 2. free all recv buffers */
487         precvbuf = (struct recv_buf *)precvpriv->precv_buf;
488         if (precvbuf) {
489                 n = NR_RECVBUFF;
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);
495                         precvbuf++;
496                 }
497                 precvpriv->precv_buf = NULL;
498         }
499
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;
504         }
505 }