Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / rtl8723au / hal / rtl8723au_recv.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2011 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  ******************************************************************************/
15 #define _RTL8192CU_RECV_C_
16 #include <osdep_service.h>
17 #include <drv_types.h>
18 #include <recv_osdep.h>
19 #include <mlme_osdep.h>
20 #include <linux/ip.h>
21 #include <linux/if_ether.h>
22 #include <usb_ops.h>
23 #include <wifi.h>
24 #include <rtl8723a_hal.h>
25
26 int rtl8723au_init_recv_priv(struct rtw_adapter *padapter)
27 {
28         struct recv_priv *precvpriv = &padapter->recvpriv;
29         int i, size, res = _SUCCESS;
30         struct recv_buf *precvbuf;
31         unsigned long tmpaddr;
32         unsigned long alignment;
33         struct sk_buff *pskb;
34
35         tasklet_init(&precvpriv->recv_tasklet,
36                      (void(*)(unsigned long))rtl8723au_recv_tasklet,
37                      (unsigned long)padapter);
38
39         precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
40         if (!precvpriv->int_in_urb)
41                 DBG_8723A("alloc_urb for interrupt in endpoint fail !!!!\n");
42         precvpriv->int_in_buf = kzalloc(USB_INTR_CONTENT_LENGTH, GFP_KERNEL);
43         if (!precvpriv->int_in_buf)
44                 DBG_8723A("alloc_mem for interrupt in endpoint fail !!!!\n");
45
46         size = NR_RECVBUFF * sizeof(struct recv_buf);
47         precvpriv->precv_buf = kzalloc(size, GFP_KERNEL);
48         if (!precvpriv->precv_buf) {
49                 res = _FAIL;
50                 RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
51                          "alloc recv_buf fail!\n");
52                 goto exit;
53         }
54
55         precvbuf = (struct recv_buf *)precvpriv->precv_buf;
56
57         for (i = 0; i < NR_RECVBUFF; i++) {
58                 INIT_LIST_HEAD(&precvbuf->list);
59
60                 precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
61                 if (!precvbuf->purb)
62                         break;
63
64                 precvbuf->adapter = padapter;
65
66                 precvbuf++;
67         }
68
69         skb_queue_head_init(&precvpriv->rx_skb_queue);
70         skb_queue_head_init(&precvpriv->free_recv_skb_queue);
71
72         for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
73                 size = MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ;
74                 pskb = __netdev_alloc_skb(padapter->pnetdev, size, GFP_KERNEL);
75
76                 if (pskb) {
77                         pskb->dev = padapter->pnetdev;
78
79                         tmpaddr = (unsigned long)pskb->data;
80                         alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
81                         skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
82
83                         skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
84                 }
85
86                 pskb = NULL;
87         }
88
89 exit:
90         return res;
91 }
92
93 void rtl8723au_free_recv_priv(struct rtw_adapter *padapter)
94 {
95         int     i;
96         struct recv_buf *precvbuf;
97         struct recv_priv *precvpriv = &padapter->recvpriv;
98
99         precvbuf = (struct recv_buf *)precvpriv->precv_buf;
100
101         for (i = 0; i < NR_RECVBUFF; i++) {
102                 usb_free_urb(precvbuf->purb);
103
104                 if (precvbuf->pskb)
105                         dev_kfree_skb_any(precvbuf->pskb);
106
107                 precvbuf++;
108         }
109
110         kfree(precvpriv->precv_buf);
111
112         usb_free_urb(precvpriv->int_in_urb);
113         kfree(precvpriv->int_in_buf);
114
115         if (skb_queue_len(&precvpriv->rx_skb_queue))
116                 DBG_8723A(KERN_WARNING "rx_skb_queue not empty\n");
117
118         skb_queue_purge(&precvpriv->rx_skb_queue);
119
120         if (skb_queue_len(&precvpriv->free_recv_skb_queue)) {
121                 DBG_8723A(KERN_WARNING "free_recv_skb_queue not empty, %d\n",
122                           skb_queue_len(&precvpriv->free_recv_skb_queue));
123         }
124
125         skb_queue_purge(&precvpriv->free_recv_skb_queue);
126 }
127
128 struct recv_stat_cpu {
129         u32 rxdw0;
130         u32 rxdw1;
131         u32 rxdw2;
132         u32 rxdw3;
133         u32 rxdw4;
134         u32 rxdw5;
135 };
136
137 void update_recvframe_attrib(struct recv_frame *precvframe,
138                              struct recv_stat *prxstat)
139 {
140         struct rx_pkt_attrib *pattrib;
141         struct recv_stat_cpu report;
142         struct rxreport_8723a *prxreport;
143
144         report.rxdw0 = le32_to_cpu(prxstat->rxdw0);
145         report.rxdw1 = le32_to_cpu(prxstat->rxdw1);
146         report.rxdw2 = le32_to_cpu(prxstat->rxdw2);
147         report.rxdw3 = le32_to_cpu(prxstat->rxdw3);
148         report.rxdw4 = le32_to_cpu(prxstat->rxdw4);
149         report.rxdw5 = le32_to_cpu(prxstat->rxdw5);
150
151         prxreport = (struct rxreport_8723a *)&report;
152
153         pattrib = &precvframe->attrib;
154         memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
155
156         /*  update rx report to recv_frame attribute */
157         pattrib->pkt_len = (u16)prxreport->pktlen;
158         pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3);
159         pattrib->physt = (u8)prxreport->physt;
160
161         pattrib->crc_err = (u8)prxreport->crc32;
162         pattrib->icv_err = (u8)prxreport->icverr;
163
164         pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1);
165         pattrib->encrypt = (u8)prxreport->security;
166
167         pattrib->qos = (u8)prxreport->qos;
168         pattrib->priority = (u8)prxreport->tid;
169
170         pattrib->amsdu = (u8)prxreport->amsdu;
171
172         pattrib->seq_num = (u16)prxreport->seq;
173         pattrib->frag_num = (u8)prxreport->frag;
174         pattrib->mfrag = (u8)prxreport->mf;
175         pattrib->mdata = (u8)prxreport->md;
176
177         pattrib->mcs_rate = (u8)prxreport->rxmcs;
178         pattrib->rxht = (u8)prxreport->rxht;
179 }
180
181 void update_recvframe_phyinfo(struct recv_frame *precvframe,
182                               struct phy_stat *pphy_status)
183 {
184         struct rtw_adapter *padapter = precvframe->adapter;
185         struct rx_pkt_attrib *pattrib = &precvframe->attrib;
186         struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
187         struct phy_info *pPHYInfo = &pattrib->phy_info;
188         struct odm_packet_info pkt_info;
189         u8 *sa = NULL, *da;
190         struct sta_priv *pstapriv;
191         struct sta_info *psta;
192         struct sk_buff *skb = precvframe->pkt;
193         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
194         bool matchbssid = false;
195         u8 *bssid;
196
197         matchbssid = !ieee80211_is_ctl(hdr->frame_control) &&
198                       !pattrib->icv_err && !pattrib->crc_err;
199
200         if (matchbssid) {
201                 switch (hdr->frame_control &
202                         cpu_to_le16(IEEE80211_FCTL_TODS |
203                                     IEEE80211_FCTL_FROMDS)) {
204                 case cpu_to_le16(IEEE80211_FCTL_TODS):
205                         bssid = hdr->addr1;
206                         break;
207                 case cpu_to_le16(IEEE80211_FCTL_FROMDS):
208                         bssid = hdr->addr2;
209                         break;
210                 case cpu_to_le16(0):
211                         bssid = hdr->addr3;
212                         break;
213                 default:
214                         bssid = NULL;
215                         matchbssid = false;
216                 }
217
218                 if (bssid)
219                         matchbssid = ether_addr_equal(
220                                 get_bssid(&padapter->mlmepriv), bssid);
221         }
222
223         pkt_info.bPacketMatchBSSID = matchbssid;
224
225         da = ieee80211_get_DA(hdr);
226         pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID &&
227                 (!memcmp(da, myid(&padapter->eeprompriv), ETH_ALEN));
228
229         pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID &&
230                 ieee80211_is_beacon(hdr->frame_control);
231
232         pkt_info.StationID = 0xFF;
233         if (pkt_info.bPacketBeacon) {
234                 if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == true)
235                         sa = padapter->mlmepriv.cur_network.network.MacAddress;
236                 /* to do Ad-hoc */
237         } else {
238                 sa = ieee80211_get_SA(hdr);
239         }
240
241         pstapriv = &padapter->stapriv;
242         psta = rtw_get_stainfo23a(pstapriv, sa);
243         if (psta) {
244                 pkt_info.StationID = psta->mac_id;
245                 /* printk("%s ==> StationID(%d)\n", __func__, pkt_info.StationID); */
246         }
247         pkt_info.Rate = pattrib->mcs_rate;
248
249         ODM_PhyStatusQuery23a(&pHalData->odmpriv, pPHYInfo,
250                               (u8 *)pphy_status, &pkt_info);
251         precvframe->psta = NULL;
252         if (pkt_info.bPacketMatchBSSID &&
253             (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) {
254                 if (psta) {
255                         precvframe->psta = psta;
256                         rtl8723a_process_phy_info(padapter, precvframe);
257                 }
258         } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
259                 if (check_fwstate(&padapter->mlmepriv,
260                                   WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) ==
261                     true) {
262                         if (psta)
263                                 precvframe->psta = psta;
264                 }
265                 rtl8723a_process_phy_info(padapter, precvframe);
266         }
267 }