Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /******************************************************************************
0003  * rtl8712_recv.c
0004  *
0005  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
0006  * Linux device driver for RTL8192SU
0007  *
0008  * Modifications for inclusion into the Linux staging tree are
0009  * Copyright(c) 2010 Larry Finger. All rights reserved.
0010  *
0011  * Contact information:
0012  * WLAN FAE <wlanfae@realtek.com>
0013  * Larry Finger <Larry.Finger@lwfinger.net>
0014  *
0015  ******************************************************************************/
0016 
0017 #define _RTL8712_RECV_C_
0018 
0019 #include <linux/if_ether.h>
0020 #include <linux/ip.h>
0021 #include <net/cfg80211.h>
0022 
0023 #include "osdep_service.h"
0024 #include "drv_types.h"
0025 #include "recv_osdep.h"
0026 #include "mlme_osdep.h"
0027 #include "ethernet.h"
0028 #include "usb_ops.h"
0029 #include "wifi.h"
0030 
0031 static void recv_tasklet(struct tasklet_struct *t);
0032 
0033 void r8712_init_recv_priv(struct recv_priv *precvpriv,
0034               struct _adapter *padapter)
0035 {
0036     int i;
0037     struct recv_buf *precvbuf;
0038     addr_t tmpaddr = 0;
0039     int alignment = 0;
0040     struct sk_buff *pskb = NULL;
0041 
0042     /*init recv_buf*/
0043     _init_queue(&precvpriv->free_recv_buf_queue);
0044     precvpriv->pallocated_recv_buf =
0045         kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4, GFP_ATOMIC);
0046     if (!precvpriv->pallocated_recv_buf)
0047         return;
0048     precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 -
0049                   ((addr_t)(precvpriv->pallocated_recv_buf) & 3);
0050     precvbuf = (struct recv_buf *)precvpriv->precv_buf;
0051     for (i = 0; i < NR_RECVBUFF; i++) {
0052         INIT_LIST_HEAD(&precvbuf->list);
0053         spin_lock_init(&precvbuf->recvbuf_lock);
0054         if (r8712_os_recvbuf_resource_alloc(padapter, precvbuf))
0055             break;
0056         precvbuf->ref_cnt = 0;
0057         precvbuf->adapter = padapter;
0058         list_add_tail(&precvbuf->list,
0059                   &precvpriv->free_recv_buf_queue.queue);
0060         precvbuf++;
0061     }
0062     precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
0063     tasklet_setup(&precvpriv->recv_tasklet, recv_tasklet);
0064     skb_queue_head_init(&precvpriv->rx_skb_queue);
0065 
0066     skb_queue_head_init(&precvpriv->free_recv_skb_queue);
0067     for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
0068         pskb = netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ +
0069                RECVBUFF_ALIGN_SZ);
0070         if (pskb) {
0071             tmpaddr = (addr_t)pskb->data;
0072             alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
0073             skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
0074             skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
0075         }
0076         pskb = NULL;
0077     }
0078 }
0079 
0080 void r8712_free_recv_priv(struct recv_priv *precvpriv)
0081 {
0082     int i;
0083     struct recv_buf *precvbuf;
0084     struct _adapter *padapter = precvpriv->adapter;
0085 
0086     precvbuf = (struct recv_buf *)precvpriv->precv_buf;
0087     for (i = 0; i < NR_RECVBUFF; i++) {
0088         r8712_os_recvbuf_resource_free(padapter, precvbuf);
0089         precvbuf++;
0090     }
0091     kfree(precvpriv->pallocated_recv_buf);
0092     skb_queue_purge(&precvpriv->rx_skb_queue);
0093     if (skb_queue_len(&precvpriv->rx_skb_queue))
0094         netdev_warn(padapter->pnetdev, "r8712u: rx_skb_queue not empty\n");
0095     skb_queue_purge(&precvpriv->free_recv_skb_queue);
0096     if (skb_queue_len(&precvpriv->free_recv_skb_queue))
0097         netdev_warn(padapter->pnetdev, "r8712u: free_recv_skb_queue not empty %d\n",
0098                 skb_queue_len(&precvpriv->free_recv_skb_queue));
0099 }
0100 
0101 void r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf)
0102 {
0103     precvbuf->transfer_len = 0;
0104     precvbuf->len = 0;
0105     precvbuf->ref_cnt = 0;
0106     if (precvbuf->pbuf) {
0107         precvbuf->pdata = precvbuf->pbuf;
0108         precvbuf->phead = precvbuf->pbuf;
0109         precvbuf->ptail = precvbuf->pbuf;
0110         precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ;
0111     }
0112 }
0113 
0114 void r8712_free_recvframe(union recv_frame *precvframe,
0115               struct  __queue *pfree_recv_queue)
0116 {
0117     unsigned long irqL;
0118     struct _adapter *padapter = precvframe->u.hdr.adapter;
0119     struct recv_priv *precvpriv = &padapter->recvpriv;
0120 
0121     if (precvframe->u.hdr.pkt) {
0122         dev_kfree_skb_any(precvframe->u.hdr.pkt);/*free skb by driver*/
0123         precvframe->u.hdr.pkt = NULL;
0124     }
0125     spin_lock_irqsave(&pfree_recv_queue->lock, irqL);
0126     list_del_init(&precvframe->u.hdr.list);
0127     list_add_tail(&precvframe->u.hdr.list, &pfree_recv_queue->queue);
0128     if (padapter) {
0129         if (pfree_recv_queue == &precvpriv->free_recv_queue)
0130             precvpriv->free_recvframe_cnt++;
0131     }
0132     spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL);
0133 }
0134 
0135 static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib,
0136                           struct recv_stat *prxstat)
0137 {
0138     u16 drvinfo_sz;
0139 
0140     drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16;
0141     drvinfo_sz <<= 3;
0142     /*TODO:
0143      * Offset 0
0144      */
0145     pattrib->bdecrypted = (le32_to_cpu(prxstat->rxdw0) & BIT(27)) == 0;
0146     pattrib->crc_err = (le32_to_cpu(prxstat->rxdw0) & BIT(14)) != 0;
0147     /*Offset 4*/
0148     /*Offset 8*/
0149     /*Offset 12*/
0150     if (le32_to_cpu(prxstat->rxdw3) & BIT(13)) {
0151         pattrib->tcpchk_valid = 1; /* valid */
0152         if (le32_to_cpu(prxstat->rxdw3) & BIT(11))
0153             pattrib->tcp_chkrpt = 1; /* correct */
0154         else
0155             pattrib->tcp_chkrpt = 0; /* incorrect */
0156         if (le32_to_cpu(prxstat->rxdw3) & BIT(12))
0157             pattrib->ip_chkrpt = 1; /* correct */
0158         else
0159             pattrib->ip_chkrpt = 0; /* incorrect */
0160     } else {
0161         pattrib->tcpchk_valid = 0; /* invalid */
0162     }
0163     pattrib->mcs_rate = (u8)((le32_to_cpu(prxstat->rxdw3)) & 0x3f);
0164     pattrib->htc = (u8)((le32_to_cpu(prxstat->rxdw3) >> 14) & 0x1);
0165     /*Offset 16*/
0166     /*Offset 20*/
0167     /*phy_info*/
0168 }
0169 
0170 /*perform defrag*/
0171 static union recv_frame *recvframe_defrag(struct _adapter *adapter,
0172                       struct  __queue *defrag_q)
0173 {
0174     struct list_head *plist, *phead;
0175     u8 wlanhdr_offset;
0176     u8  curfragnum;
0177     struct recv_frame_hdr *pfhdr, *pnfhdr;
0178     union recv_frame *prframe, *pnextrframe;
0179     struct  __queue *pfree_recv_queue;
0180 
0181     pfree_recv_queue = &adapter->recvpriv.free_recv_queue;
0182     phead = &defrag_q->queue;
0183     plist = phead->next;
0184     prframe = container_of(plist, union recv_frame, u.list);
0185     list_del_init(&prframe->u.list);
0186     pfhdr = &prframe->u.hdr;
0187     curfragnum = 0;
0188     if (curfragnum != pfhdr->attrib.frag_num) {
0189         /*the first fragment number must be 0
0190          *free the whole queue
0191          */
0192         r8712_free_recvframe(prframe, pfree_recv_queue);
0193         r8712_free_recvframe_queue(defrag_q, pfree_recv_queue);
0194         return NULL;
0195     }
0196     curfragnum++;
0197     plist = &defrag_q->queue;
0198     plist = plist->next;
0199     while (!end_of_queue_search(phead, plist)) {
0200         pnextrframe = container_of(plist, union recv_frame, u.list);
0201         pnfhdr = &pnextrframe->u.hdr;
0202         /*check the fragment sequence  (2nd ~n fragment frame) */
0203         if (curfragnum != pnfhdr->attrib.frag_num) {
0204             /* the fragment number must increase  (after decache)
0205              * release the defrag_q & prframe
0206              */
0207             r8712_free_recvframe(prframe, pfree_recv_queue);
0208             r8712_free_recvframe_queue(defrag_q, pfree_recv_queue);
0209             return NULL;
0210         }
0211         curfragnum++;
0212         /* copy the 2nd~n fragment frame's payload to the first fragment
0213          * get the 2nd~last fragment frame's payload
0214          */
0215         wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len;
0216         recvframe_pull(pnextrframe, wlanhdr_offset);
0217         /* append  to first fragment frame's tail (if privacy frame,
0218          * pull the ICV)
0219          */
0220         recvframe_pull_tail(prframe, pfhdr->attrib.icv_len);
0221         memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len);
0222         recvframe_put(prframe, pnfhdr->len);
0223         pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
0224         plist = plist->next;
0225     }
0226     /* free the defrag_q queue and return the prframe */
0227     r8712_free_recvframe_queue(defrag_q, pfree_recv_queue);
0228     return prframe;
0229 }
0230 
0231 /* check if need to defrag, if needed queue the frame to defrag_q */
0232 union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter,
0233                          union recv_frame *precv_frame)
0234 {
0235     u8  ismfrag;
0236     u8  fragnum;
0237     u8   *psta_addr;
0238     struct recv_frame_hdr *pfhdr;
0239     struct sta_info *psta;
0240     struct  sta_priv *pstapriv;
0241     struct list_head *phead;
0242     union recv_frame *prtnframe = NULL;
0243     struct  __queue *pfree_recv_queue, *pdefrag_q;
0244 
0245     pstapriv = &padapter->stapriv;
0246     pfhdr = &precv_frame->u.hdr;
0247     pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
0248     /* need to define struct of wlan header frame ctrl */
0249     ismfrag = pfhdr->attrib.mfrag;
0250     fragnum = pfhdr->attrib.frag_num;
0251     psta_addr = pfhdr->attrib.ta;
0252     psta = r8712_get_stainfo(pstapriv, psta_addr);
0253     if (!psta)
0254         pdefrag_q = NULL;
0255     else
0256         pdefrag_q = &psta->sta_recvpriv.defrag_q;
0257 
0258     if ((ismfrag == 0) && (fragnum == 0))
0259         prtnframe = precv_frame;/*isn't a fragment frame*/
0260     if (ismfrag == 1) {
0261         /* 0~(n-1) fragment frame
0262          * enqueue to defraf_g
0263          */
0264         if (pdefrag_q) {
0265             if (fragnum == 0) {
0266                 /*the first fragment*/
0267                 if (!list_empty(&pdefrag_q->queue)) {
0268                     /*free current defrag_q */
0269                     r8712_free_recvframe_queue(pdefrag_q,
0270                                  pfree_recv_queue);
0271                 }
0272             }
0273             /* Then enqueue the 0~(n-1) fragment to the defrag_q */
0274             phead = &pdefrag_q->queue;
0275             list_add_tail(&pfhdr->list, phead);
0276             prtnframe = NULL;
0277         } else {
0278             /* can't find this ta's defrag_queue, so free this
0279              * recv_frame
0280              */
0281             r8712_free_recvframe(precv_frame, pfree_recv_queue);
0282             prtnframe = NULL;
0283         }
0284     }
0285     if ((ismfrag == 0) && (fragnum != 0)) {
0286         /* the last fragment frame
0287          * enqueue the last fragment
0288          */
0289         if (pdefrag_q) {
0290             phead = &pdefrag_q->queue;
0291             list_add_tail(&pfhdr->list, phead);
0292             /*call recvframe_defrag to defrag*/
0293             precv_frame = recvframe_defrag(padapter, pdefrag_q);
0294             prtnframe = precv_frame;
0295         } else {
0296             /* can't find this ta's defrag_queue, so free this
0297              *  recv_frame
0298              */
0299             r8712_free_recvframe(precv_frame, pfree_recv_queue);
0300             prtnframe = NULL;
0301         }
0302     }
0303     if (prtnframe && (prtnframe->u.hdr.attrib.privacy)) {
0304         /* after defrag we must check tkip mic code */
0305         if (r8712_recvframe_chkmic(padapter, prtnframe) == _FAIL) {
0306             r8712_free_recvframe(prtnframe, pfree_recv_queue);
0307             prtnframe = NULL;
0308         }
0309     }
0310     return prtnframe;
0311 }
0312 
0313 static void amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe)
0314 {
0315     int a_len, padding_len;
0316     u16 eth_type, nSubframe_Length;
0317     u8  nr_subframes, i;
0318     unsigned char *pdata;
0319     struct rx_pkt_attrib *pattrib;
0320     _pkt *sub_skb, *subframes[MAX_SUBFRAME_COUNT];
0321     struct recv_priv *precvpriv = &padapter->recvpriv;
0322     struct  __queue *pfree_recv_queue = &precvpriv->free_recv_queue;
0323 
0324     nr_subframes = 0;
0325     pattrib = &prframe->u.hdr.attrib;
0326     recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen);
0327     if (prframe->u.hdr.attrib.iv_len > 0)
0328         recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len);
0329     a_len = prframe->u.hdr.len;
0330     pdata = prframe->u.hdr.rx_data;
0331     while (a_len > ETH_HLEN) {
0332         /* Offset 12 denote 2 mac address */
0333         nSubframe_Length = *((u16 *)(pdata + 12));
0334         /*==m==>change the length order*/
0335         nSubframe_Length = (nSubframe_Length >> 8) +
0336                    (nSubframe_Length << 8);
0337         if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
0338             netdev_warn(padapter->pnetdev, "r8712u: nRemain_Length is %d and nSubframe_Length is: %d\n",
0339                     a_len, nSubframe_Length);
0340             goto exit;
0341         }
0342         /* move the data point to data content */
0343         pdata += ETH_HLEN;
0344         a_len -= ETH_HLEN;
0345         /* Allocate new skb for releasing to upper layer */
0346         sub_skb = dev_alloc_skb(nSubframe_Length + 12);
0347         if (!sub_skb)
0348             break;
0349         skb_reserve(sub_skb, 12);
0350         skb_put_data(sub_skb, pdata, nSubframe_Length);
0351         subframes[nr_subframes++] = sub_skb;
0352         if (nr_subframes >= MAX_SUBFRAME_COUNT) {
0353             netdev_warn(padapter->pnetdev, "r8712u: ParseSubframe(): Too many Subframes! Packets dropped!\n");
0354             break;
0355         }
0356         pdata += nSubframe_Length;
0357         a_len -= nSubframe_Length;
0358         if (a_len != 0) {
0359             padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & 3);
0360             if (padding_len == 4)
0361                 padding_len = 0;
0362             if (a_len < padding_len)
0363                 goto exit;
0364             pdata += padding_len;
0365             a_len -= padding_len;
0366         }
0367     }
0368     for (i = 0; i < nr_subframes; i++) {
0369         sub_skb = subframes[i];
0370         /* convert hdr + possible LLC headers into Ethernet header */
0371         eth_type = (sub_skb->data[6] << 8) | sub_skb->data[7];
0372         if (sub_skb->len >= 8 &&
0373             ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) &&
0374               eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
0375              !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) {
0376             /* remove RFC1042 or Bridge-Tunnel encapsulation and
0377              * replace EtherType
0378              */
0379             skb_pull(sub_skb, SNAP_SIZE);
0380             memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src,
0381                    ETH_ALEN);
0382             memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst,
0383                    ETH_ALEN);
0384         } else {
0385             __be16 len;
0386             /* Leave Ethernet header part of hdr and full payload */
0387             len = htons(sub_skb->len);
0388             memcpy(skb_push(sub_skb, 2), &len, 2);
0389             memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src,
0390                    ETH_ALEN);
0391             memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst,
0392                    ETH_ALEN);
0393         }
0394         /* Indicate the packets to upper layer */
0395         if (sub_skb) {
0396             sub_skb->protocol =
0397                  eth_type_trans(sub_skb, padapter->pnetdev);
0398             sub_skb->dev = padapter->pnetdev;
0399             if ((pattrib->tcpchk_valid == 1) &&
0400                 (pattrib->tcp_chkrpt == 1)) {
0401                 sub_skb->ip_summed = CHECKSUM_UNNECESSARY;
0402             } else {
0403                 sub_skb->ip_summed = CHECKSUM_NONE;
0404             }
0405             netif_rx(sub_skb);
0406         }
0407     }
0408 exit:
0409     prframe->u.hdr.len = 0;
0410     r8712_free_recvframe(prframe, pfree_recv_queue);
0411 }
0412 
0413 void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf)
0414 {
0415     __le32 voffset;
0416     u8 *poffset;
0417     u16 cmd_len, drvinfo_sz;
0418     struct recv_stat *prxstat;
0419 
0420     poffset = prxcmdbuf;
0421     voffset = *(__le32 *)poffset;
0422     prxstat = prxcmdbuf;
0423     drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16;
0424     drvinfo_sz <<= 3;
0425     poffset += RXDESC_SIZE + drvinfo_sz;
0426     do {
0427         voffset  = *(__le32 *)poffset;
0428         cmd_len = (u16)(le32_to_cpu(voffset) & 0xffff);
0429         r8712_event_handle(padapter, (__le32 *)poffset);
0430         poffset += (cmd_len + 8);/*8 bytes alignment*/
0431     } while (le32_to_cpu(voffset) & BIT(31));
0432 }
0433 
0434 static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl,
0435                   u16 seq_num)
0436 {
0437     u8 wsize = preorder_ctrl->wsize_b;
0438     u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) % 4096;
0439 
0440     /* Rx Reorder initialize condition.*/
0441     if (preorder_ctrl->indicate_seq == 0xffff)
0442         preorder_ctrl->indicate_seq = seq_num;
0443     /* Drop out the packet which SeqNum is smaller than WinStart */
0444     if (SN_LESS(seq_num, preorder_ctrl->indicate_seq))
0445         return false;
0446     /*
0447      * Sliding window manipulation. Conditions includes:
0448      * 1. Incoming SeqNum is equal to WinStart =>Window shift 1
0449      * 2. Incoming SeqNum is larger than the WinEnd => Window shift N
0450      */
0451     if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq))
0452         preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq +
0453                           1) % 4096;
0454     else if (SN_LESS(wend, seq_num)) {
0455         if (seq_num >= (wsize - 1))
0456             preorder_ctrl->indicate_seq = seq_num + 1 - wsize;
0457         else
0458             preorder_ctrl->indicate_seq = 4095 - (wsize -
0459                               (seq_num + 1)) + 1;
0460     }
0461     return true;
0462 }
0463 
0464 static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl,
0465                      union recv_frame *prframe)
0466 {
0467     struct list_head *phead, *plist;
0468     union recv_frame *pnextrframe;
0469     struct rx_pkt_attrib *pnextattrib;
0470     struct  __queue *ppending_recvframe_queue =
0471                     &preorder_ctrl->pending_recvframe_queue;
0472     struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
0473 
0474     phead = &ppending_recvframe_queue->queue;
0475     plist = phead->next;
0476     while (!end_of_queue_search(phead, plist)) {
0477         pnextrframe = container_of(plist, union recv_frame, u.list);
0478         pnextattrib = &pnextrframe->u.hdr.attrib;
0479 
0480         if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num))
0481             return false;
0482 
0483         if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num))
0484             plist = plist->next;
0485         else
0486             break;
0487     }
0488     list_del_init(&prframe->u.hdr.list);
0489     list_add_tail(&prframe->u.hdr.list, plist);
0490     return true;
0491 }
0492 
0493 int r8712_recv_indicatepkts_in_order(struct _adapter *padapter,
0494                      struct recv_reorder_ctrl *preorder_ctrl,
0495                      int bforced)
0496 {
0497     struct list_head *phead, *plist;
0498     union recv_frame *prframe;
0499     struct rx_pkt_attrib *pattrib;
0500     int bPktInBuf = false;
0501     struct  __queue *ppending_recvframe_queue =
0502              &preorder_ctrl->pending_recvframe_queue;
0503 
0504     phead = &ppending_recvframe_queue->queue;
0505     plist = phead->next;
0506     /* Handling some condition for forced indicate case.*/
0507     if (bforced) {
0508         if (list_empty(phead))
0509             return true;
0510 
0511         prframe = container_of(plist, union recv_frame, u.list);
0512         pattrib = &prframe->u.hdr.attrib;
0513         preorder_ctrl->indicate_seq = pattrib->seq_num;
0514     }
0515     /* Prepare indication list and indication.
0516      * Check if there is any packet need indicate.
0517      */
0518     while (!list_empty(phead)) {
0519         prframe = container_of(plist, union recv_frame, u.list);
0520         pattrib = &prframe->u.hdr.attrib;
0521         if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
0522             plist = plist->next;
0523             list_del_init(&prframe->u.hdr.list);
0524             if (SN_EQUAL(preorder_ctrl->indicate_seq,
0525                      pattrib->seq_num))
0526                 preorder_ctrl->indicate_seq =
0527                   (preorder_ctrl->indicate_seq + 1) % 4096;
0528             /*indicate this recv_frame*/
0529             if (!pattrib->amsdu) {
0530                 if (!padapter->driver_stopped &&
0531                     !padapter->surprise_removed) {
0532                     /* indicate this recv_frame */
0533                     r8712_recv_indicatepkt(padapter,
0534                                    prframe);
0535                 }
0536             } else if (pattrib->amsdu == 1) {
0537                 amsdu_to_msdu(padapter, prframe);
0538             }
0539             /* Update local variables. */
0540             bPktInBuf = false;
0541         } else {
0542             bPktInBuf = true;
0543             break;
0544         }
0545     }
0546     return bPktInBuf;
0547 }
0548 
0549 static int recv_indicatepkt_reorder(struct _adapter *padapter,
0550                     union recv_frame *prframe)
0551 {
0552     unsigned long irql;
0553     struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
0554     struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl;
0555     struct  __queue *ppending_recvframe_queue =
0556              &preorder_ctrl->pending_recvframe_queue;
0557 
0558     if (!pattrib->amsdu) {
0559         /* s1. */
0560         r8712_wlanhdr_to_ethhdr(prframe);
0561         if (pattrib->qos != 1) {
0562             if (!padapter->driver_stopped &&
0563                 !padapter->surprise_removed) {
0564                 r8712_recv_indicatepkt(padapter, prframe);
0565                 return 0;
0566             } else {
0567                 return -EINVAL;
0568             }
0569         }
0570     }
0571     spin_lock_irqsave(&ppending_recvframe_queue->lock, irql);
0572     /*s2. check if winstart_b(indicate_seq) needs to be updated*/
0573     if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num))
0574         goto _err_exit;
0575     /*s3. Insert all packet into Reorder Queue to maintain its ordering.*/
0576     if (!enqueue_reorder_recvframe(preorder_ctrl, prframe))
0577         goto _err_exit;
0578     /*s4.
0579      * Indication process.
0580      * After Packet dropping and Sliding Window shifting as above, we can
0581      * now just indicate the packets with the SeqNum smaller than latest
0582      * WinStart and buffer other packets.
0583      *
0584      * For Rx Reorder condition:
0585      * 1. All packets with SeqNum smaller than WinStart => Indicate
0586      * 2. All packets with SeqNum larger than or equal to
0587      * WinStart => Buffer it.
0588      */
0589     if (r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) {
0590         mod_timer(&preorder_ctrl->reordering_ctrl_timer,
0591               jiffies + msecs_to_jiffies(REORDER_WAIT_TIME));
0592         spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
0593     } else {
0594         spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
0595         del_timer(&preorder_ctrl->reordering_ctrl_timer);
0596     }
0597     return 0;
0598 _err_exit:
0599     spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
0600     return -ENOMEM;
0601 }
0602 
0603 void r8712_reordering_ctrl_timeout_handler(void *pcontext)
0604 {
0605     unsigned long irql;
0606     struct recv_reorder_ctrl *preorder_ctrl = pcontext;
0607     struct _adapter *padapter = preorder_ctrl->padapter;
0608     struct  __queue *ppending_recvframe_queue =
0609                  &preorder_ctrl->pending_recvframe_queue;
0610 
0611     if (padapter->driver_stopped || padapter->surprise_removed)
0612         return;
0613     spin_lock_irqsave(&ppending_recvframe_queue->lock, irql);
0614     r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, true);
0615     spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
0616 }
0617 
0618 static int r8712_process_recv_indicatepkts(struct _adapter *padapter,
0619                        union recv_frame *prframe)
0620 {
0621     int retval = _SUCCESS;
0622     struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
0623     struct ht_priv  *phtpriv = &pmlmepriv->htpriv;
0624 
0625     if (phtpriv->ht_option == 1) { /*B/G/N Mode*/
0626         if (recv_indicatepkt_reorder(padapter, prframe)) {
0627             /* including perform A-MPDU Rx Ordering Buffer Control*/
0628             if (!padapter->driver_stopped &&
0629                 !padapter->surprise_removed)
0630                 return _FAIL;
0631         }
0632     } else { /*B/G mode*/
0633         retval = r8712_wlanhdr_to_ethhdr(prframe);
0634         if (retval)
0635             return _FAIL;
0636         if (!padapter->driver_stopped && !padapter->surprise_removed) {
0637             /* indicate this recv_frame */
0638             r8712_recv_indicatepkt(padapter, prframe);
0639         } else {
0640             return _FAIL;
0641         }
0642     }
0643     return retval;
0644 }
0645 
0646 static u8 query_rx_pwr_percentage(s8 antpower)
0647 {
0648     if ((antpower <= -100) || (antpower >= 20))
0649         return  0;
0650     else if (antpower >= 0)
0651         return  100;
0652     else
0653         return 100 + antpower;
0654 }
0655 
0656 static u8 evm_db2percentage(s8 value)
0657 {
0658     /*
0659      * -33dB~0dB to 0%~99%
0660      */
0661     s8 ret_val = clamp(-value, 0, 33) * 3;
0662 
0663     if (ret_val == 99)
0664         ret_val = 100;
0665 
0666     return ret_val;
0667 }
0668 
0669 s32 r8712_signal_scale_mapping(s32 cur_sig)
0670 {
0671     s32 ret_sig;
0672 
0673     if (cur_sig >= 51 && cur_sig <= 100)
0674         ret_sig = 100;
0675     else if (cur_sig >= 41 && cur_sig <= 50)
0676         ret_sig = 80 + ((cur_sig - 40) * 2);
0677     else if (cur_sig >= 31 && cur_sig <= 40)
0678         ret_sig = 66 + (cur_sig - 30);
0679     else if (cur_sig >= 21 && cur_sig <= 30)
0680         ret_sig = 54 + (cur_sig - 20);
0681     else if (cur_sig >= 10 && cur_sig <= 20)
0682         ret_sig = 42 + (((cur_sig - 10) * 2) / 3);
0683     else if (cur_sig >= 5 && cur_sig <= 9)
0684         ret_sig = 22 + (((cur_sig - 5) * 3) / 2);
0685     else if (cur_sig >= 1 && cur_sig <= 4)
0686         ret_sig = 6 + (((cur_sig - 1) * 3) / 2);
0687     else
0688         ret_sig = cur_sig;
0689     return ret_sig;
0690 }
0691 
0692 static s32  translate2dbm(struct _adapter *padapter, u8 signal_strength_idx)
0693 {
0694     s32 signal_power; /* in dBm.*/
0695     /* Translate to dBm (x=0.5y-95).*/
0696     signal_power = (s32)((signal_strength_idx + 1) >> 1);
0697     signal_power -= 95;
0698     return signal_power;
0699 }
0700 
0701 static void query_rx_phy_status(struct _adapter *padapter,
0702                 union recv_frame *prframe)
0703 {
0704     u8 i, max_spatial_stream, evm;
0705     struct recv_stat *prxstat = (struct recv_stat *)prframe->u.hdr.rx_head;
0706     struct phy_stat *pphy_stat = (struct phy_stat *)(prxstat + 1);
0707     u8 *pphy_head = (u8 *)(prxstat + 1);
0708     s8 rx_pwr[4], rx_pwr_all;
0709     u8 pwdb_all;
0710     u32 rssi, total_rssi = 0;
0711     u8 bcck_rate = 0, rf_rx_num = 0, cck_highpwr = 0;
0712     struct phy_cck_rx_status *pcck_buf;
0713     u8 sq;
0714 
0715     /* Record it for next packet processing*/
0716     bcck_rate = (prframe->u.hdr.attrib.mcs_rate <= 3 ? 1 : 0);
0717     if (bcck_rate) {
0718         u8 report;
0719 
0720         /* CCK Driver info Structure is not the same as OFDM packet.*/
0721         pcck_buf = (struct phy_cck_rx_status *)pphy_stat;
0722         /* (1)Hardware does not provide RSSI for CCK
0723          * (2)PWDB, Average PWDB calculated by hardware
0724          * (for rate adaptive)
0725          */
0726         if (!cck_highpwr) {
0727             report = pcck_buf->cck_agc_rpt & 0xc0;
0728             report >>= 6;
0729             switch (report) {
0730             /* Modify the RF RNA gain value to -40, -20,
0731              * -2, 14 by Jenyu's suggestion
0732              * Note: different RF with the different
0733              * RNA gain.
0734              */
0735             case 0x3:
0736                 rx_pwr_all = -40 - (pcck_buf->cck_agc_rpt &
0737                          0x3e);
0738                 break;
0739             case 0x2:
0740                 rx_pwr_all = -20 - (pcck_buf->cck_agc_rpt &
0741                          0x3e);
0742                 break;
0743             case 0x1:
0744                 rx_pwr_all = -2 - (pcck_buf->cck_agc_rpt &
0745                          0x3e);
0746                 break;
0747             case 0x0:
0748                 rx_pwr_all = 14 - (pcck_buf->cck_agc_rpt &
0749                          0x3e);
0750                 break;
0751             }
0752         } else {
0753             report = ((u8)(le32_to_cpu(pphy_stat->phydw1) >> 8)) &
0754                  0x60;
0755             report >>= 5;
0756             switch (report) {
0757             case 0x3:
0758                 rx_pwr_all = -40 - ((pcck_buf->cck_agc_rpt &
0759                          0x1f) << 1);
0760                 break;
0761             case 0x2:
0762                 rx_pwr_all = -20 - ((pcck_buf->cck_agc_rpt &
0763                          0x1f) << 1);
0764                 break;
0765             case 0x1:
0766                 rx_pwr_all = -2 - ((pcck_buf->cck_agc_rpt &
0767                          0x1f) << 1);
0768                 break;
0769             case 0x0:
0770                 rx_pwr_all = 14 - ((pcck_buf->cck_agc_rpt &
0771                          0x1f) << 1);
0772                 break;
0773             }
0774         }
0775         pwdb_all = query_rx_pwr_percentage(rx_pwr_all);
0776         /* CCK gain is smaller than OFDM/MCS gain,*/
0777         /* so we add gain diff by experiences, the val is 6 */
0778         pwdb_all += 6;
0779         if (pwdb_all > 100)
0780             pwdb_all = 100;
0781         /* modify the offset to make the same gain index with OFDM.*/
0782         if (pwdb_all > 34 && pwdb_all <= 42)
0783             pwdb_all -= 2;
0784         else if (pwdb_all > 26 && pwdb_all <= 34)
0785             pwdb_all -= 6;
0786         else if (pwdb_all > 14 && pwdb_all <= 26)
0787             pwdb_all -= 8;
0788         else if (pwdb_all > 4 && pwdb_all <= 14)
0789             pwdb_all -= 4;
0790         /*
0791          * (3) Get Signal Quality (EVM)
0792          */
0793         if (pwdb_all > 40) {
0794             sq = 100;
0795         } else {
0796             sq = pcck_buf->sq_rpt;
0797             if (pcck_buf->sq_rpt > 64)
0798                 sq = 0;
0799             else if (pcck_buf->sq_rpt < 20)
0800                 sq = 100;
0801             else
0802                 sq = ((64 - sq) * 100) / 44;
0803         }
0804         prframe->u.hdr.attrib.signal_qual = sq;
0805         prframe->u.hdr.attrib.rx_mimo_signal_qual[0] = sq;
0806         prframe->u.hdr.attrib.rx_mimo_signal_qual[1] = -1;
0807     } else {
0808         /* (1)Get RSSI for HT rate */
0809         for (i = 0; i < ((padapter->registrypriv.rf_config) &
0810                 0x0f); i++) {
0811             rf_rx_num++;
0812             rx_pwr[i] = ((pphy_head[PHY_STAT_GAIN_TRSW_SHT + i]
0813                     & 0x3F) * 2) - 110;
0814             /* Translate DBM to percentage. */
0815             rssi = query_rx_pwr_percentage(rx_pwr[i]);
0816             total_rssi += rssi;
0817         }
0818         /* (2)PWDB, Average PWDB calculated by hardware (for
0819          * rate adaptive)
0820          */
0821         rx_pwr_all = (((pphy_head[PHY_STAT_PWDB_ALL_SHT]) >> 1) & 0x7f)
0822                  - 106;
0823         pwdb_all = query_rx_pwr_percentage(rx_pwr_all);
0824 
0825         {
0826             /* (3)EVM of HT rate */
0827             if (prframe->u.hdr.attrib.htc &&
0828                 prframe->u.hdr.attrib.mcs_rate >= 20 &&
0829                 prframe->u.hdr.attrib.mcs_rate <= 27) {
0830                 /* both spatial stream make sense */
0831                 max_spatial_stream = 2;
0832             } else {
0833                 /* only spatial stream 1 makes sense */
0834                 max_spatial_stream = 1;
0835             }
0836             for (i = 0; i < max_spatial_stream; i++) {
0837                 evm = evm_db2percentage((pphy_head
0838                       [PHY_STAT_RXEVM_SHT + i]));/*dbm*/
0839                 prframe->u.hdr.attrib.signal_qual =
0840                      (u8)(evm & 0xff);
0841                 prframe->u.hdr.attrib.rx_mimo_signal_qual[i] =
0842                      (u8)(evm & 0xff);
0843             }
0844         }
0845     }
0846     /* UI BSS List signal strength(in percentage), make it good looking,
0847      * from 0~100. It is assigned to the BSS List in
0848      * GetValueFromBeaconOrProbeRsp().
0849      */
0850     if (bcck_rate) {
0851         prframe->u.hdr.attrib.signal_strength =
0852              (u8)r8712_signal_scale_mapping(pwdb_all);
0853     } else {
0854         if (rf_rx_num != 0)
0855             prframe->u.hdr.attrib.signal_strength =
0856                  (u8)(r8712_signal_scale_mapping(total_rssi /=
0857                  rf_rx_num));
0858     }
0859 }
0860 
0861 static void process_link_qual(struct _adapter *padapter,
0862                   union recv_frame *prframe)
0863 {
0864     u32 last_evm = 0, tmpVal;
0865     struct rx_pkt_attrib *pattrib;
0866     struct smooth_rssi_data *sqd = &padapter->recvpriv.signal_qual_data;
0867 
0868     if (!prframe || !padapter)
0869         return;
0870     pattrib = &prframe->u.hdr.attrib;
0871     if (pattrib->signal_qual != 0) {
0872         /*
0873          * 1. Record the general EVM to the sliding window.
0874          */
0875         if (sqd->total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) {
0876             sqd->total_num = PHY_LINKQUALITY_SLID_WIN_MAX;
0877             last_evm = sqd->elements[sqd->index];
0878             sqd->total_val -= last_evm;
0879         }
0880         sqd->total_val += pattrib->signal_qual;
0881         sqd->elements[sqd->index++] = pattrib->signal_qual;
0882         if (sqd->index >= PHY_LINKQUALITY_SLID_WIN_MAX)
0883             sqd->index = 0;
0884 
0885         /* <1> Showed on UI for user, in percentage. */
0886         tmpVal = sqd->total_val / sqd->total_num;
0887         padapter->recvpriv.signal = (u8)tmpVal;
0888     }
0889 }
0890 
0891 static void process_rssi(struct _adapter *padapter, union recv_frame *prframe)
0892 {
0893     u32 last_rssi, tmp_val;
0894     struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
0895     struct smooth_rssi_data *ssd = &padapter->recvpriv.signal_strength_data;
0896 
0897     if (ssd->total_num++ >= PHY_RSSI_SLID_WIN_MAX) {
0898         ssd->total_num = PHY_RSSI_SLID_WIN_MAX;
0899         last_rssi = ssd->elements[ssd->index];
0900         ssd->total_val -= last_rssi;
0901     }
0902     ssd->total_val += pattrib->signal_strength;
0903     ssd->elements[ssd->index++] = pattrib->signal_strength;
0904     if (ssd->index >= PHY_RSSI_SLID_WIN_MAX)
0905         ssd->index = 0;
0906     tmp_val = ssd->total_val / ssd->total_num;
0907     padapter->recvpriv.rssi = (s8)translate2dbm(padapter, (u8)tmp_val);
0908 }
0909 
0910 static void process_phy_info(struct _adapter *padapter,
0911                  union recv_frame *prframe)
0912 {
0913     query_rx_phy_status(padapter, prframe);
0914     process_rssi(padapter, prframe);
0915     process_link_qual(padapter,  prframe);
0916 }
0917 
0918 int recv_func(struct _adapter *padapter, void *pcontext)
0919 {
0920     struct rx_pkt_attrib *pattrib;
0921     union recv_frame *prframe, *orig_prframe;
0922     int retval = _SUCCESS;
0923     struct  __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
0924     struct  mlme_priv   *pmlmepriv = &padapter->mlmepriv;
0925 
0926     prframe = pcontext;
0927     orig_prframe = prframe;
0928     pattrib = &prframe->u.hdr.attrib;
0929     if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
0930         if (pattrib->crc_err == 1)
0931             padapter->mppriv.rx_crcerrpktcount++;
0932         else
0933             padapter->mppriv.rx_pktcount++;
0934         if (!check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE)) {
0935             /* free this recv_frame */
0936             r8712_free_recvframe(orig_prframe, pfree_recv_queue);
0937             goto _exit_recv_func;
0938         }
0939     }
0940     /* check the frame crtl field and decache */
0941     retval = r8712_validate_recv_frame(padapter, prframe);
0942     if (retval != _SUCCESS) {
0943         /* free this recv_frame */
0944         r8712_free_recvframe(orig_prframe, pfree_recv_queue);
0945         goto _exit_recv_func;
0946     }
0947     process_phy_info(padapter, prframe);
0948     prframe = r8712_decryptor(padapter, prframe);
0949     if (!prframe) {
0950         retval = _FAIL;
0951         goto _exit_recv_func;
0952     }
0953     prframe = r8712_recvframe_chk_defrag(padapter, prframe);
0954     if (!prframe)
0955         goto _exit_recv_func;
0956     prframe = r8712_portctrl(padapter, prframe);
0957     if (!prframe) {
0958         retval = _FAIL;
0959         goto _exit_recv_func;
0960     }
0961     retval = r8712_process_recv_indicatepkts(padapter, prframe);
0962     if (retval != _SUCCESS) {
0963         r8712_free_recvframe(orig_prframe, pfree_recv_queue);
0964         goto _exit_recv_func;
0965     }
0966 _exit_recv_func:
0967     return retval;
0968 }
0969 
0970 static void recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
0971 {
0972     u8 *pbuf, shift_sz = 0;
0973     u8  frag, mf;
0974     uint    pkt_len;
0975     u32 transfer_len;
0976     struct recv_stat *prxstat;
0977     u16 pkt_cnt, drvinfo_sz, pkt_offset, tmp_len, alloc_sz;
0978     struct  __queue *pfree_recv_queue;
0979     _pkt  *pkt_copy = NULL;
0980     union recv_frame *precvframe = NULL;
0981     struct recv_priv *precvpriv = &padapter->recvpriv;
0982 
0983     pfree_recv_queue = &precvpriv->free_recv_queue;
0984     pbuf = pskb->data;
0985     prxstat = (struct recv_stat *)pbuf;
0986     pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff;
0987     pkt_len =  le32_to_cpu(prxstat->rxdw0) & 0x00003fff;
0988     transfer_len = pskb->len;
0989     /* Test throughput with Netgear 3700 (No security) with Chariot 3T3R
0990      * pairs. The packet count will be a big number so that the containing
0991      * packet will effect the Rx reordering.
0992      */
0993     if (transfer_len < pkt_len) {
0994         /* In this case, it means the MAX_RECVBUF_SZ is too small to
0995          * get the data from 8712u.
0996          */
0997         return;
0998     }
0999     do {
1000         prxstat = (struct recv_stat *)pbuf;
1001         pkt_len =  le32_to_cpu(prxstat->rxdw0) & 0x00003fff;
1002         /* more fragment bit */
1003         mf = (le32_to_cpu(prxstat->rxdw1) >> 27) & 0x1;
1004         /* ragmentation number */
1005         frag = (le32_to_cpu(prxstat->rxdw2) >> 12) & 0xf;
1006         /* uint 2^3 = 8 bytes */
1007         drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16;
1008         drvinfo_sz <<= 3;
1009         if (pkt_len <= 0)
1010             return;
1011         /* Qos data, wireless lan header length is 26 */
1012         if ((le32_to_cpu(prxstat->rxdw0) >> 23) & 0x01)
1013             shift_sz = 2;
1014         precvframe = r8712_alloc_recvframe(pfree_recv_queue);
1015         if (!precvframe)
1016             return;
1017         INIT_LIST_HEAD(&precvframe->u.hdr.list);
1018         precvframe->u.hdr.precvbuf = NULL; /*can't access the precvbuf*/
1019         precvframe->u.hdr.len = 0;
1020         tmp_len = pkt_len + drvinfo_sz + RXDESC_SIZE;
1021         pkt_offset = (u16)round_up(tmp_len, 128);
1022         /* for first fragment packet, driver need allocate 1536 +
1023          * drvinfo_sz + RXDESC_SIZE to defrag packet.
1024          */
1025         if ((mf == 1) && (frag == 0))
1026             /*1658+6=1664, 1664 is 128 alignment.*/
1027             alloc_sz = max_t(u16, tmp_len, 1658);
1028         else
1029             alloc_sz = tmp_len;
1030         /* 2 is for IP header 4 bytes alignment in QoS packet case.
1031          * 4 is for skb->data 4 bytes alignment.
1032          */
1033         alloc_sz += 6;
1034         pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz);
1035         if (!pkt_copy)
1036             return;
1037 
1038         precvframe->u.hdr.pkt = pkt_copy;
1039         skb_reserve(pkt_copy, 4 - ((addr_t)(pkt_copy->data) % 4));
1040         skb_reserve(pkt_copy, shift_sz);
1041         memcpy(pkt_copy->data, pbuf, tmp_len);
1042         precvframe->u.hdr.rx_head = pkt_copy->data;
1043         precvframe->u.hdr.rx_data = pkt_copy->data;
1044         precvframe->u.hdr.rx_tail = pkt_copy->data;
1045         precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
1046 
1047         recvframe_put(precvframe, tmp_len);
1048         recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE);
1049         /* because the endian issue, driver avoid reference to the
1050          * rxstat after calling update_recvframe_attrib_from_recvstat();
1051          */
1052         update_recvframe_attrib_from_recvstat(&precvframe->u.hdr.attrib,
1053                               prxstat);
1054         r8712_recv_entry(precvframe);
1055         transfer_len -= pkt_offset;
1056         pbuf += pkt_offset;
1057         pkt_cnt--;
1058         precvframe = NULL;
1059         pkt_copy = NULL;
1060     } while ((transfer_len > 0) && pkt_cnt > 0);
1061 }
1062 
1063 static void recv_tasklet(struct tasklet_struct *t)
1064 {
1065     struct sk_buff *pskb;
1066     struct _adapter *padapter = from_tasklet(padapter, t,
1067                          recvpriv.recv_tasklet);
1068     struct recv_priv *precvpriv = &padapter->recvpriv;
1069 
1070     while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
1071         recvbuf2recvframe(padapter, pskb);
1072         skb_reset_tail_pointer(pskb);
1073         pskb->len = 0;
1074         if (!skb_cloned(pskb))
1075             skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
1076         else
1077             consume_skb(pskb);
1078     }
1079 }