OSDN Git Service

Remove duplicate copy of if_ether.h and use the kernel provided one
[android-x86/external-modules-rtl8723au.git] / os_dep / xmit_linux.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 _XMIT_OSDEP_C_
21
22 #include <drv_conf.h>
23 #include <osdep_service.h>
24 #include <drv_types.h>
25
26 #include <linux/if_ether.h>
27 #include <ip.h>
28 #include <wifi.h>
29 #include <mlme_osdep.h>
30 #include <xmit_osdep.h>
31 #include <osdep_intf.h>
32 #include <circ_buf.h>
33
34 uint rtw_remainder_len(struct pkt_file *pfile)
35 {
36         return (pfile->buf_len - ((unsigned long)(pfile->cur_addr) - (unsigned long)(pfile->buf_start)));
37 }
38
39 void _rtw_open_pktfile (_pkt *pktptr, struct pkt_file *pfile)
40 {
41 _func_enter_;
42
43         pfile->pkt = pktptr;
44         pfile->cur_addr = pfile->buf_start = pktptr->data;
45         pfile->pkt_len = pfile->buf_len = pktptr->len;
46
47         pfile->cur_buffer = pfile->buf_start ;
48
49 _func_exit_;
50 }
51
52 uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
53 {
54         uint    len = 0;
55
56 _func_enter_;
57
58        len =  rtw_remainder_len(pfile);
59         len = (rlen > len)? len: rlen;
60
61        if(rmem)
62           skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
63
64        pfile->cur_addr += len;
65        pfile->pkt_len -= len;
66
67 _func_exit_;
68
69         return len;
70 }
71
72 int rtw_endofpktfile(struct pkt_file *pfile)
73 {
74 _func_enter_;
75
76         if (pfile->pkt_len == 0) {
77 _func_exit_;
78                 return _TRUE;
79         }
80
81 _func_exit_;
82
83         return _FALSE;
84 }
85
86 void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib)
87 {
88
89 #ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
90         struct sk_buff *skb = (struct sk_buff *)pkt;
91         pattrib->hw_tcp_csum = 0;
92
93         if (skb->ip_summed == CHECKSUM_PARTIAL) {
94                 if (skb_shinfo(skb)->nr_frags == 0)
95                 {
96                         const struct iphdr *ip = ip_hdr(skb);
97                         if (ip->protocol == IPPROTO_TCP) {
98                                 // TCP checksum offload by HW
99                                 DBG_8723A("CHECKSUM_PARTIAL TCP\n");
100                                 pattrib->hw_tcp_csum = 1;
101                                 //skb_checksum_help(skb);
102                         } else if (ip->protocol == IPPROTO_UDP) {
103                                 //DBG_8723A("CHECKSUM_PARTIAL UDP\n");
104 #if 1
105                                 skb_checksum_help(skb);
106 #else
107                                 // Set UDP checksum = 0 to skip checksum check
108                                 struct udphdr *udp = skb_transport_header(skb);
109                                 udp->check = 0;
110 #endif
111                         } else {
112                                 DBG_8723A("%s-%d TCP CSUM offload Error!!\n", __FUNCTION__, __LINE__);
113                                 WARN_ON(1);     /* we need a WARN() */
114                             }
115                 }
116                 else { // IP fragmentation case
117                         DBG_8723A("%s-%d nr_frags != 0, using skb_checksum_help(skb);!!\n", __FUNCTION__, __LINE__);
118                         skb_checksum_help(skb);
119                 }
120         }
121 #endif
122
123 }
124
125 int rtw_os_xmit_resource_alloc(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 alloc_sz)
126 {
127         int i;
128         struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
129         struct usb_device       *pusbd = pdvobjpriv->pusbdev;
130
131 #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
132         pxmitbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)alloc_sz, &pxmitbuf->dma_transfer_addr);
133         pxmitbuf->pbuf = pxmitbuf->pallocated_buf;
134         if(pxmitbuf->pallocated_buf == NULL)
135                 return _FAIL;
136 #else // CONFIG_USE_USB_BUFFER_ALLOC_TX
137
138         pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL);
139         if (pxmitbuf->pallocated_buf == NULL) {
140                 return _FAIL;
141         }
142
143         pxmitbuf->pbuf = PTR_ALIGN(pxmitbuf->pallocated_buf, XMITBUF_ALIGN_SZ);
144         pxmitbuf->dma_transfer_addr = 0;
145
146 #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
147
148         for(i=0; i<8; i++)
149         {
150                 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
151                 if(pxmitbuf->pxmit_urb[i] == NULL)
152                 {
153                         DBG_8723A("pxmitbuf->pxmit_urb[i]==NULL");
154                         return _FAIL;
155                 }
156
157         }
158         return _SUCCESS;
159 }
160
161 void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 free_sz)
162 {
163         int i;
164         struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
165         struct usb_device       *pusbd = pdvobjpriv->pusbdev;
166
167         for(i=0; i<8; i++)
168         {
169                 if(pxmitbuf->pxmit_urb[i])
170                 {
171                         //usb_kill_urb(pxmitbuf->pxmit_urb[i]);
172                         usb_free_urb(pxmitbuf->pxmit_urb[i]);
173                 }
174         }
175
176 #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
177         rtw_usb_buffer_free(pusbd, (size_t)free_sz, pxmitbuf->pallocated_buf, pxmitbuf->dma_transfer_addr);
178         pxmitbuf->pallocated_buf =  NULL;
179         pxmitbuf->dma_transfer_addr = 0;
180 #else   // CONFIG_USE_USB_BUFFER_ALLOC_TX
181         if(pxmitbuf->pallocated_buf)
182                 kfree(pxmitbuf->pallocated_buf);
183 #endif  // CONFIG_USE_USB_BUFFER_ALLOC_TX
184
185 }
186
187 #define WMM_XMIT_THRESHOLD      (NR_XMITFRAME*2/5)
188
189 void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt)
190 {
191 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
192         u16     queue;
193         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
194
195         queue = skb_get_queue_mapping(pkt);
196         if (padapter->registrypriv.wifi_spec) {
197                 if(__netif_subqueue_stopped(padapter->pnetdev, queue) &&
198                         (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
199                 {
200                         netif_wake_subqueue(padapter->pnetdev, queue);
201                 }
202         } else {
203                 if(__netif_subqueue_stopped(padapter->pnetdev, queue))
204                         netif_wake_subqueue(padapter->pnetdev, queue);
205         }
206 #else
207         if (netif_queue_stopped(padapter->pnetdev))
208                 netif_wake_queue(padapter->pnetdev);
209 #endif
210
211         dev_kfree_skb_any(pkt);
212 }
213
214 void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe)
215 {
216         if(pxframe->pkt)
217         {
218                 //RT_TRACE(_module_xmit_osdep_c_,_drv_err_,("linux : rtw_os_xmit_complete, dev_kfree_skb()\n"));
219
220                 //dev_kfree_skb_any(pxframe->pkt);
221                 rtw_os_pkt_complete(padapter, pxframe->pkt);
222
223         }
224
225         pxframe->pkt = NULL;
226 }
227
228 void rtw_os_xmit_schedule(_adapter *padapter)
229 {
230         _adapter *pri_adapter = padapter;
231         _irqL  irqL;
232         struct xmit_priv *pxmitpriv;
233
234         if(!padapter)
235                 return;
236
237         pxmitpriv = &padapter->xmitpriv;
238
239         spin_lock_bh(&pxmitpriv->lock);
240
241         if(rtw_txframes_pending(padapter))
242         {
243                 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
244         }
245
246         spin_unlock_bh(&pxmitpriv->lock);
247 }
248
249 static void rtw_check_xmit_resource(_adapter *padapter, _pkt *pkt)
250 {
251         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
252 #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
253         u16     queue;
254
255         queue = skb_get_queue_mapping(pkt);
256         if (padapter->registrypriv.wifi_spec) {
257                 /* No free space for Tx, tx_worker is too slow */
258                 if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) {
259                         //DBG_8723A("%s(): stop netif_subqueue[%d]\n", __FUNCTION__, queue);
260                         netif_stop_subqueue(padapter->pnetdev, queue);
261                 }
262         } else {
263                 if(pxmitpriv->free_xmitframe_cnt<=4) {
264                         if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
265                                 netif_stop_subqueue(padapter->pnetdev, queue);
266                 }
267         }
268 #else
269         if(pxmitpriv->free_xmitframe_cnt<=4)
270         {
271                 if (!rtw_netif_queue_stopped(padapter->pnetdev))
272                         rtw_netif_stop_queue(padapter->pnetdev);
273         }
274 #endif
275 }
276
277 #ifdef CONFIG_TX_MCAST2UNI
278 int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb)
279 {
280         struct  sta_priv *pstapriv = &padapter->stapriv;
281         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
282         _irqL   irqL;
283         _list   *phead, *plist;
284         struct sk_buff *newskb;
285         struct sta_info *psta = NULL;
286         u8 chk_alive_num = 0;
287         char chk_alive_list[NUM_STA];
288         u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
289         u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
290
291         int i;
292         s32     res;
293
294         spin_lock_bh(&pstapriv->asoc_list_lock);
295         phead = &pstapriv->asoc_list;
296         plist = get_next(phead);
297
298         //free sta asoc_queue
299         while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
300                 int stainfo_offset;
301                 psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
302                 plist = get_next(plist);
303
304                 stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
305                 if (stainfo_offset_valid(stainfo_offset)) {
306                         chk_alive_list[chk_alive_num++] = stainfo_offset;
307                 }
308         }
309         spin_unlock_bh(&pstapriv->asoc_list_lock);
310
311         for (i = 0; i < chk_alive_num; i++) {
312                 psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
313                 if(!(psta->state &_FW_LINKED))
314                         continue;
315
316                 /* avoid come from STA1 and send back STA1 */
317                 if (!memcmp(psta->hwaddr, &skb->data[6], 6) ||
318                     !memcmp(psta->hwaddr, null_addr, 6) ||
319                     !memcmp(psta->hwaddr, bc_addr, 6))
320                         continue;
321
322                 newskb = skb_copy(skb, GFP_ATOMIC);
323
324                 if (newskb) {
325                         memcpy(newskb->data, psta->hwaddr, 6);
326                         res = rtw_xmit(padapter, &newskb);
327                         if (res < 0) {
328                                 DBG_8723A("%s()-%d: rtw_xmit() return error!\n", __FUNCTION__, __LINE__);
329                                 pxmitpriv->tx_drop++;
330                                 dev_kfree_skb_any(newskb);
331                         } else
332                                 pxmitpriv->tx_pkts++;
333                 } else {
334                         DBG_8723A("%s-%d: skb_copy() failed!\n", __FUNCTION__, __LINE__);
335                         pxmitpriv->tx_drop++;
336                         //dev_kfree_skb_any(skb);
337                         return _FALSE;  // Caller shall tx this multicast frame via normal way.
338                 }
339         }
340
341         dev_kfree_skb_any(skb);
342         return _TRUE;
343 }
344 #endif  // CONFIG_TX_MCAST2UNI
345
346
347 int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
348 {
349         _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
350         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
351 #ifdef CONFIG_TX_MCAST2UNI
352         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
353         extern int rtw_mc2u_disable;
354 #endif  // CONFIG_TX_MCAST2UNI
355         s32 res = 0;
356 #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
357         u16 queue;
358 #endif
359
360 _func_enter_;
361
362         RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
363
364         if (rtw_if_up(padapter) == _FALSE) {
365                 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
366                 #ifdef DBG_TX_DROP_FRAME
367                 DBG_8723A("DBG_TX_DROP_FRAME %s if_up fail\n", __FUNCTION__);
368                 #endif
369                 goto drop_packet;
370         }
371
372         rtw_check_xmit_resource(padapter, pkt);
373
374 #ifdef CONFIG_TX_MCAST2UNI
375         if ( !rtw_mc2u_disable
376                 && check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE
377                 && ( IP_MCAST_MAC(pkt->data)
378                         || ICMPV6_MCAST_MAC(pkt->data) )
379                 && (padapter->registrypriv.wifi_spec == 0)
380                 )
381         {
382                 if ( pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4) ) {
383                         res = rtw_mlcst2unicst(padapter, pkt);
384                         if (res == _TRUE) {
385                                 goto exit;
386                         }
387                 } else {
388                         //DBG_8723A("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt);
389                         //DBG_8723A("!m2u );
390                 }
391         }
392 #endif  // CONFIG_TX_MCAST2UNI
393
394         res = rtw_xmit(padapter, &pkt);
395         if (res < 0) {
396                 #ifdef DBG_TX_DROP_FRAME
397                 DBG_8723A("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);
398                 #endif
399                 goto drop_packet;
400         }
401
402         pxmitpriv->tx_pkts++;
403         RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
404         goto exit;
405
406 drop_packet:
407         pxmitpriv->tx_drop++;
408         dev_kfree_skb_any(pkt);
409         RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
410
411 exit:
412
413 _func_exit_;
414
415         return 0;
416 }