GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / staging / rtl8723bs / hal / rtl8723bs_recv.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 #define _RTL8723BS_RECV_C_
8
9 #include <drv_types.h>
10 #include <rtw_debug.h>
11 #include <rtl8723b_hal.h>
12
13 static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
14 {
15         INIT_LIST_HEAD(&precvbuf->list);
16         spin_lock_init(&precvbuf->recvbuf_lock);
17
18         precvbuf->adapter = padapter;
19
20         return _SUCCESS;
21 }
22
23 static void update_recvframe_attrib(struct adapter *padapter,
24                                     union recv_frame *precvframe,
25                                     struct recv_stat *prxstat)
26 {
27         struct rx_pkt_attrib *pattrib;
28         struct recv_stat report;
29         PRXREPORT prxreport = (PRXREPORT)&report;
30
31         report.rxdw0 = prxstat->rxdw0;
32         report.rxdw1 = prxstat->rxdw1;
33         report.rxdw2 = prxstat->rxdw2;
34         report.rxdw3 = prxstat->rxdw3;
35         report.rxdw4 = prxstat->rxdw4;
36         report.rxdw5 = prxstat->rxdw5;
37
38         pattrib = &precvframe->u.hdr.attrib;
39         memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
40
41         /*  update rx report to recv_frame attribute */
42         pattrib->pkt_rpt_type = prxreport->c2h_ind ? C2H_PACKET : NORMAL_RX;
43 /*      DBG_871X("%s: pkt_rpt_type =%d\n", __func__, pattrib->pkt_rpt_type); */
44
45         if (pattrib->pkt_rpt_type == NORMAL_RX) {
46                 /*  Normal rx packet */
47                 /*  update rx report to recv_frame attribute */
48                 pattrib->pkt_len = (u16)prxreport->pktlen;
49                 pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3);
50                 pattrib->physt = (u8)prxreport->physt;
51
52                 pattrib->crc_err = (u8)prxreport->crc32;
53                 pattrib->icv_err = (u8)prxreport->icverr;
54
55                 pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1);
56                 pattrib->encrypt = (u8)prxreport->security;
57
58                 pattrib->qos = (u8)prxreport->qos;
59                 pattrib->priority = (u8)prxreport->tid;
60
61                 pattrib->amsdu = (u8)prxreport->amsdu;
62
63                 pattrib->seq_num = (u16)prxreport->seq;
64                 pattrib->frag_num = (u8)prxreport->frag;
65                 pattrib->mfrag = (u8)prxreport->mf;
66                 pattrib->mdata = (u8)prxreport->md;
67
68                 pattrib->data_rate = (u8)prxreport->rx_rate;
69         } else {
70                 pattrib->pkt_len = (u16)prxreport->pktlen;
71         }
72 }
73
74 /*
75  * Notice:
76  *Before calling this function,
77  *precvframe->u.hdr.rx_data should be ready!
78  */
79 static void update_recvframe_phyinfo(union recv_frame *precvframe,
80                                      struct phy_stat *pphy_status)
81 {
82         struct adapter *padapter = precvframe->u.hdr.adapter;
83         struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
84         struct hal_com_data *p_hal_data = GET_HAL_DATA(padapter);
85         struct odm_phy_info *p_phy_info =
86                 (struct odm_phy_info *)(&pattrib->phy_info);
87
88         u8 *wlanhdr;
89         u8 *my_bssid;
90         u8 *rx_bssid;
91         u8 *rx_ra;
92         u8 *my_hwaddr;
93         u8 *sa = NULL;
94
95         struct odm_packet_info pkt_info = {
96                 .data_rate   = 0x00,
97                 .station_id  = 0x00,
98                 .bssid_match = false,
99                 .to_self     = false,
100                 .is_beacon   = false,
101         };
102
103         /* _irqL                irqL; */
104         struct sta_priv *pstapriv;
105         struct sta_info *psta;
106
107         wlanhdr = get_recvframe_data(precvframe);
108         my_bssid = get_bssid(&padapter->mlmepriv);
109         rx_bssid = get_hdr_bssid(wlanhdr);
110         pkt_info.bssid_match = ((!IsFrameTypeCtrl(wlanhdr)) &&
111                                 !pattrib->icv_err && !pattrib->crc_err &&
112                                 ether_addr_equal(rx_bssid, my_bssid));
113
114         rx_ra = get_ra(wlanhdr);
115         my_hwaddr = myid(&padapter->eeprompriv);
116         pkt_info.to_self = pkt_info.bssid_match &&
117                 ether_addr_equal(rx_ra, my_hwaddr);
118
119
120         pkt_info.is_beacon = pkt_info.bssid_match &&
121                 (GetFrameSubType(wlanhdr) == WIFI_BEACON);
122
123         sa = get_ta(wlanhdr);
124
125         pkt_info.station_id = 0xFF;
126
127         pstapriv = &padapter->stapriv;
128         psta = rtw_get_stainfo(pstapriv, sa);
129         if (psta) {
130                 pkt_info.station_id = psta->mac_id;
131                 /* DBG_8192C("%s ==> StationID(%d)\n",
132                  *        __func__, pkt_info.station_id); */
133         }
134         pkt_info.data_rate = pattrib->data_rate;
135
136         /* rtl8723b_query_rx_phy_status(precvframe, pphy_status); */
137         /* spin_lock_bh(&p_hal_data->odm_stainfo_lock); */
138         ODM_PhyStatusQuery(&p_hal_data->odmpriv, p_phy_info,
139                            (u8 *)pphy_status, &(pkt_info));
140         if (psta)
141                 psta->rssi = pattrib->phy_info.RecvSignalPower;
142         /* spin_unlock_bh(&p_hal_data->odm_stainfo_lock); */
143         precvframe->u.hdr.psta = NULL;
144         if (
145                 pkt_info.bssid_match &&
146                 (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)
147         ) {
148                 if (psta) {
149                         precvframe->u.hdr.psta = psta;
150                         rtl8723b_process_phy_info(padapter, precvframe);
151                 }
152         } else if (pkt_info.to_self || pkt_info.is_beacon) {
153                 u32 adhoc_state = WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE;
154                 if (check_fwstate(&padapter->mlmepriv, adhoc_state))
155                         if (psta)
156                                 precvframe->u.hdr.psta = psta;
157                 rtl8723b_process_phy_info(padapter, precvframe);
158         }
159 }
160
161 static void rtl8723bs_c2h_packet_handler(struct adapter *padapter,
162                                          u8 *pbuf, u16 length)
163 {
164         u8 *tmp = NULL;
165         u8 res = false;
166
167         if (length == 0)
168                 return;
169
170         /* DBG_871X("+%s() length =%d\n", __func__, length); */
171
172         tmp = rtw_zmalloc(length);
173         if (tmp == NULL)
174                 return;
175
176         memcpy(tmp, pbuf, length);
177
178         res = rtw_c2h_packet_wk_cmd(padapter, tmp, length);
179
180         if (res == false)
181                 kfree(tmp);
182
183         /* DBG_871X("-%s res(%d)\n", __func__, res); */
184
185         return;
186 }
187
188 static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv,
189                                                     struct recv_buf *precvbuf)
190 {
191         union recv_frame *precvframe;
192
193         precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
194         if (!precvframe) {
195                 DBG_8192C("%s: no enough recv frame!\n", __func__);
196                 rtw_enqueue_recvbuf_to_head(precvbuf,
197                                             &precvpriv->recv_buf_pending_queue);
198
199                 /*  The case of can't allocte recvframe should be temporary, */
200                 /*  schedule again and hope recvframe is available next time. */
201                 tasklet_schedule(&precvpriv->recv_tasklet);
202         }
203
204         return precvframe;
205 }
206
207 static inline bool rx_crc_err(struct recv_priv *precvpriv,
208                               struct hal_com_data *p_hal_data,
209                               struct rx_pkt_attrib *pattrib,
210                               union recv_frame *precvframe)
211 {
212         /*  fix Hardware RX data error, drop whole recv_buffer */
213         if ((!(p_hal_data->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
214                 DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n",
215                           __func__, __LINE__);
216                 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
217                 return true;
218         }
219
220         return false;
221 }
222
223 static inline bool pkt_exceeds_tail(struct recv_priv *precvpriv,
224                                     u8 *end, u8 *tail,
225                                     union recv_frame *precvframe)
226 {
227         if (end > tail) {
228                 DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n",
229                           __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail);
230                 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
231                 return true;
232         }
233
234         return false;
235 }
236
237 static void rtl8723bs_recv_tasklet(void *priv)
238 {
239         struct adapter *padapter;
240         struct hal_com_data *p_hal_data;
241         struct recv_priv *precvpriv;
242         struct recv_buf *precvbuf;
243         union recv_frame *precvframe;
244         struct rx_pkt_attrib *pattrib;
245         struct __queue *recv_buf_queue;
246         u8 *ptr;
247         u32 pkt_offset, skb_len, alloc_sz;
248         _pkt *pkt_copy = NULL;
249         u8 shift_sz = 0, rx_report_sz = 0;
250
251         padapter = priv;
252         p_hal_data = GET_HAL_DATA(padapter);
253         precvpriv = &padapter->recvpriv;
254         recv_buf_queue = &precvpriv->recv_buf_pending_queue;
255
256         do {
257                 precvbuf = rtw_dequeue_recvbuf(recv_buf_queue);
258                 if (!precvbuf)
259                         break;
260
261                 ptr = precvbuf->pdata;
262
263                 while (ptr < precvbuf->ptail) {
264                         precvframe = try_alloc_recvframe(precvpriv, precvbuf);
265                         if(!precvframe)
266                                 return;
267
268                         /* rx desc parsing */
269                         update_recvframe_attrib(padapter, precvframe,
270                                                 (struct recv_stat *)ptr);
271
272                         pattrib = &precvframe->u.hdr.attrib;
273
274                         if(rx_crc_err(precvpriv, p_hal_data,
275                                       pattrib, precvframe))
276                                 break;
277
278                         rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz;
279                         pkt_offset = rx_report_sz +
280                                 pattrib->shift_sz +
281                                 pattrib->pkt_len;
282
283                         if(pkt_exceeds_tail(precvpriv, ptr + pkt_offset,
284                                             precvbuf->ptail, precvframe))
285                                 break;
286
287                         if ((pattrib->crc_err) || (pattrib->icv_err)) {
288                                 DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n",
289                                           __func__, pattrib->crc_err,
290                                           pattrib->icv_err);
291                                 rtw_free_recvframe(precvframe,
292                                                    &precvpriv->free_recv_queue);
293                         } else {
294                                 /*      Modified by Albert 20101213 */
295                                 /*      For 8 bytes IP header alignment. */
296                                 if (pattrib->qos)       /*      Qos data, wireless lan header length is 26 */
297                                         shift_sz = 6;
298                                 else
299                                         shift_sz = 0;
300
301                                 skb_len = pattrib->pkt_len;
302
303                                 /*  for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. */
304                                 /*  modify alloc_sz for recvive crc error packet by thomas 2011-06-02 */
305                                 if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
306                                         if (skb_len <= 1650)
307                                                 alloc_sz = 1664;
308                                         else
309                                                 alloc_sz = skb_len + 14;
310                                 } else {
311                                         alloc_sz = skb_len;
312                                         /*      6 is for IP header 8 bytes alignment in QoS packet case. */
313                                         /*      8 is for skb->data 4 bytes alignment. */
314                                         alloc_sz += 14;
315                                 }
316
317                                 pkt_copy = rtw_skb_alloc(alloc_sz);
318
319                                 if (pkt_copy) {
320                                         pkt_copy->dev = padapter->pnetdev;
321                                         precvframe->u.hdr.pkt = pkt_copy;
322                                         skb_reserve(pkt_copy, 8 - ((SIZE_PTR)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */
323                                         skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
324                                         memcpy(pkt_copy->data, (ptr + rx_report_sz + pattrib->shift_sz), skb_len);
325                                         precvframe->u.hdr.rx_head = pkt_copy->head;
326                                         precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_copy->data;
327                                         precvframe->u.hdr.rx_end = skb_end_pointer(pkt_copy);
328                                 } else {
329                                         if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
330                                                 DBG_8192C("%s: alloc_skb fail, drop frag frame\n", __func__);
331                                                 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
332                                                 break;
333                                         }
334
335                                         precvframe->u.hdr.pkt = rtw_skb_clone(precvbuf->pskb);
336                                         if (precvframe->u.hdr.pkt) {
337                                                 _pkt *pkt_clone = precvframe->u.hdr.pkt;
338
339                                                 pkt_clone->data = ptr + rx_report_sz + pattrib->shift_sz;
340                                                 skb_reset_tail_pointer(pkt_clone);
341                                                 precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail
342                                                         = pkt_clone->data;
343                                                 precvframe->u.hdr.rx_end = pkt_clone->data + skb_len;
344                                         } else {
345                                                 DBG_8192C("%s: rtw_skb_clone fail\n", __func__);
346                                                 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
347                                                 break;
348                                         }
349                                 }
350
351                                 recvframe_put(precvframe, skb_len);
352                                 /* recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); */
353
354                                 if (p_hal_data->ReceiveConfig & RCR_APPFCS)
355                                         recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN);
356
357                                 /*  move to drv info position */
358                                 ptr += RXDESC_SIZE;
359
360                                 /*  update drv info */
361                                 if (p_hal_data->ReceiveConfig & RCR_APP_BA_SSN) {
362                                         /* rtl8723s_update_bassn(padapter, pdrvinfo); */
363                                         ptr += 4;
364                                 }
365
366                                 if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */
367                                         if (pattrib->physt)
368                                                 update_recvframe_phyinfo(precvframe, (struct phy_stat *)ptr);
369
370                                         if (rtw_recv_entry(precvframe) != _SUCCESS) {
371                                                 RT_TRACE(_module_rtl871x_recv_c_, _drv_dump_, ("%s: rtw_recv_entry(precvframe) != _SUCCESS\n", __func__));
372                                         }
373                                 } else if (pattrib->pkt_rpt_type == C2H_PACKET) {
374                                         C2H_EVT_HDR     C2hEvent;
375
376                                         u16 len_c2h = pattrib->pkt_len;
377                                         u8 *pbuf_c2h = precvframe->u.hdr.rx_data;
378                                         u8 *pdata_c2h;
379
380                                         C2hEvent.CmdID = pbuf_c2h[0];
381                                         C2hEvent.CmdSeq = pbuf_c2h[1];
382                                         C2hEvent.CmdLen = (len_c2h-2);
383                                         pdata_c2h = pbuf_c2h+2;
384
385                                         if (C2hEvent.CmdID == C2H_CCX_TX_RPT)
386                                                 CCX_FwC2HTxRpt_8723b(padapter, pdata_c2h, C2hEvent.CmdLen);
387                                         else
388                                                 rtl8723bs_c2h_packet_handler(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
389
390                                         rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
391                                 }
392                         }
393
394                         pkt_offset = _RND8(pkt_offset);
395                         precvbuf->pdata += pkt_offset;
396                         ptr = precvbuf->pdata;
397                         precvframe = NULL;
398                         pkt_copy = NULL;
399                 }
400
401                 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
402         } while (1);
403 }
404
405 /*
406  * Initialize recv private variable for hardware dependent
407  * 1. recv buf
408  * 2. recv tasklet
409  *
410  */
411 s32 rtl8723bs_init_recv_priv(struct adapter *padapter)
412 {
413         s32 res;
414         u32 i, n;
415         struct recv_priv *precvpriv;
416         struct recv_buf *precvbuf;
417
418         res = _SUCCESS;
419         precvpriv = &padapter->recvpriv;
420
421         /* 3 1. init recv buffer */
422         _rtw_init_queue(&precvpriv->free_recv_buf_queue);
423         _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
424
425         n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
426         precvpriv->pallocated_recv_buf = rtw_zmalloc(n);
427         if (precvpriv->pallocated_recv_buf == NULL) {
428                 res = _FAIL;
429                 RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n"));
430                 goto exit;
431         }
432
433         precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
434
435         /*  init each recv buffer */
436         precvbuf = (struct recv_buf *)precvpriv->precv_buf;
437         for (i = 0; i < NR_RECVBUFF; i++) {
438                 res = initrecvbuf(precvbuf, padapter);
439                 if (res == _FAIL)
440                         break;
441
442                 if (precvbuf->pskb == NULL) {
443                         SIZE_PTR tmpaddr = 0;
444                         SIZE_PTR alignment = 0;
445
446                         precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
447
448                         if (precvbuf->pskb) {
449                                 precvbuf->pskb->dev = padapter->pnetdev;
450
451                                 tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
452                                 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
453                                 skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
454                         }
455
456                         if (precvbuf->pskb == NULL) {
457                                 DBG_871X("%s: alloc_skb fail!\n", __func__);
458                         }
459                 }
460
461                 list_add_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue);
462
463                 precvbuf++;
464         }
465         precvpriv->free_recv_buf_queue_cnt = i;
466
467         if (res == _FAIL)
468                 goto initbuferror;
469
470         /* 3 2. init tasklet */
471         tasklet_init(
472                 &precvpriv->recv_tasklet,
473                 (void(*)(unsigned long))rtl8723bs_recv_tasklet,
474                 (unsigned long)padapter
475         );
476
477         goto exit;
478
479 initbuferror:
480         precvbuf = (struct recv_buf *)precvpriv->precv_buf;
481         if (precvbuf) {
482                 n = precvpriv->free_recv_buf_queue_cnt;
483                 precvpriv->free_recv_buf_queue_cnt = 0;
484                 for (i = 0; i < n ; i++) {
485                         list_del_init(&precvbuf->list);
486                         rtw_os_recvbuf_resource_free(padapter, precvbuf);
487                         precvbuf++;
488                 }
489                 precvpriv->precv_buf = NULL;
490         }
491
492         if (precvpriv->pallocated_recv_buf) {
493                 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
494                 kfree(precvpriv->pallocated_recv_buf);
495                 precvpriv->pallocated_recv_buf = NULL;
496         }
497
498 exit:
499         return res;
500 }
501
502 /*
503  * Free recv private variable of hardware dependent
504  * 1. recv buf
505  * 2. recv tasklet
506  *
507  */
508 void rtl8723bs_free_recv_priv(struct adapter *padapter)
509 {
510         u32 i, n;
511         struct recv_priv *precvpriv;
512         struct recv_buf *precvbuf;
513
514         precvpriv = &padapter->recvpriv;
515
516         /* 3 1. kill tasklet */
517         tasklet_kill(&precvpriv->recv_tasklet);
518
519         /* 3 2. free all recv buffers */
520         precvbuf = (struct recv_buf *)precvpriv->precv_buf;
521         if (precvbuf) {
522                 n = NR_RECVBUFF;
523                 precvpriv->free_recv_buf_queue_cnt = 0;
524                 for (i = 0; i < n ; i++) {
525                         list_del_init(&precvbuf->list);
526                         rtw_os_recvbuf_resource_free(padapter, precvbuf);
527                         precvbuf++;
528                 }
529                 precvpriv->precv_buf = NULL;
530         }
531
532         if (precvpriv->pallocated_recv_buf) {
533                 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
534                 kfree(precvpriv->pallocated_recv_buf);
535                 precvpriv->pallocated_recv_buf = NULL;
536         }
537 }