OSDN Git Service

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