OSDN Git Service

Another round of malloc/free wrapper removal
[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 <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 - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(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 sint 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 #ifdef CONFIG_USB_HCI
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 = kzalloc(alloc_sz, GFP_KERNEL);
140         if (pxmitbuf->pallocated_buf == NULL) {
141                 return _FAIL;
142         }
143
144         pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
145         pxmitbuf->dma_transfer_addr = 0;
146
147 #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
148
149         for(i=0; i<8; i++)
150         {
151                 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
152                 if(pxmitbuf->pxmit_urb[i] == NULL)
153                 {
154                         DBG_8723A("pxmitbuf->pxmit_urb[i]==NULL");
155                         return _FAIL;
156                 }
157
158         }
159 #endif
160 #if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
161         pxmitbuf->pallocated_buf = kzalloc(alloc_sz);
162         if (pxmitbuf->pallocated_buf == NULL) {
163                 return _FAIL;
164         }
165
166         pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
167 #endif
168
169         return _SUCCESS;
170 }
171
172 void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 free_sz)
173 {
174 #ifdef CONFIG_USB_HCI
175         int i;
176         struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
177         struct usb_device       *pusbd = pdvobjpriv->pusbdev;
178
179
180         for(i=0; i<8; i++)
181         {
182                 if(pxmitbuf->pxmit_urb[i])
183                 {
184                         //usb_kill_urb(pxmitbuf->pxmit_urb[i]);
185                         usb_free_urb(pxmitbuf->pxmit_urb[i]);
186                 }
187         }
188
189 #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
190         rtw_usb_buffer_free(pusbd, (size_t)free_sz, pxmitbuf->pallocated_buf, pxmitbuf->dma_transfer_addr);
191         pxmitbuf->pallocated_buf =  NULL;
192         pxmitbuf->dma_transfer_addr = 0;
193 #else   // CONFIG_USE_USB_BUFFER_ALLOC_TX
194         if(pxmitbuf->pallocated_buf)
195                 kfree(pxmitbuf->pallocated_buf);
196 #endif  // CONFIG_USE_USB_BUFFER_ALLOC_TX
197
198 #endif
199 #if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
200         if(pxmitbuf->pallocated_buf)
201                 kfree(pxmitbuf->pallocated_buf);
202 #endif
203 }
204
205 #define WMM_XMIT_THRESHOLD      (NR_XMITFRAME*2/5)
206
207 void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt)
208 {
209 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
210         u16     queue;
211         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
212
213         queue = skb_get_queue_mapping(pkt);
214         if (padapter->registrypriv.wifi_spec) {
215                 if(__netif_subqueue_stopped(padapter->pnetdev, queue) &&
216                         (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
217                 {
218                         netif_wake_subqueue(padapter->pnetdev, queue);
219                 }
220         } else {
221                 if(__netif_subqueue_stopped(padapter->pnetdev, queue))
222                         netif_wake_subqueue(padapter->pnetdev, queue);
223         }
224 #else
225         if (netif_queue_stopped(padapter->pnetdev))
226                 netif_wake_queue(padapter->pnetdev);
227 #endif
228
229         dev_kfree_skb_any(pkt);
230 }
231
232 void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe)
233 {
234         if(pxframe->pkt)
235         {
236                 //RT_TRACE(_module_xmit_osdep_c_,_drv_err_,("linux : rtw_os_xmit_complete, dev_kfree_skb()\n"));
237
238                 //dev_kfree_skb_any(pxframe->pkt);
239                 rtw_os_pkt_complete(padapter, pxframe->pkt);
240
241         }
242
243         pxframe->pkt = NULL;
244 }
245
246 void rtw_os_xmit_schedule(_adapter *padapter)
247 {
248         _adapter *pri_adapter = padapter;
249
250 #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
251         if(!padapter)
252                 return;
253
254 #ifdef CONFIG_CONCURRENT_MODE
255         if(padapter->adapter_type > PRIMARY_ADAPTER)
256                 pri_adapter = padapter->pbuddy_adapter;
257 #endif
258
259         if (_rtw_queue_empty(&pri_adapter->xmitpriv.pending_xmitbuf_queue) == _FALSE)
260                 _rtw_up_sema(&pri_adapter->xmitpriv.xmit_sema);
261
262
263 #else
264         _irqL  irqL;
265         struct xmit_priv *pxmitpriv;
266
267         if(!padapter)
268                 return;
269
270         pxmitpriv = &padapter->xmitpriv;
271
272         _enter_critical_bh(&pxmitpriv->lock, &irqL);
273
274         if(rtw_txframes_pending(padapter))
275         {
276                 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
277         }
278
279         _exit_critical_bh(&pxmitpriv->lock, &irqL);
280 #endif
281 }
282
283 static void rtw_check_xmit_resource(_adapter *padapter, _pkt *pkt)
284 {
285         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
286 #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
287         u16     queue;
288
289         queue = skb_get_queue_mapping(pkt);
290         if (padapter->registrypriv.wifi_spec) {
291                 /* No free space for Tx, tx_worker is too slow */
292                 if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) {
293                         //DBG_8723A("%s(): stop netif_subqueue[%d]\n", __FUNCTION__, queue);
294                         netif_stop_subqueue(padapter->pnetdev, queue);
295                 }
296         } else {
297                 if(pxmitpriv->free_xmitframe_cnt<=4) {
298                         if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
299                                 netif_stop_subqueue(padapter->pnetdev, queue);
300                 }
301         }
302 #else
303         if(pxmitpriv->free_xmitframe_cnt<=4)
304         {
305                 if (!rtw_netif_queue_stopped(padapter->pnetdev))
306                         rtw_netif_stop_queue(padapter->pnetdev);
307         }
308 #endif
309 }
310
311 #ifdef CONFIG_TX_MCAST2UNI
312 int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb)
313 {
314         struct  sta_priv *pstapriv = &padapter->stapriv;
315         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
316         _irqL   irqL;
317         _list   *phead, *plist;
318         struct sk_buff *newskb;
319         struct sta_info *psta = NULL;
320         u8 chk_alive_num = 0;
321         char chk_alive_list[NUM_STA];
322         u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
323         u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
324
325         int i;
326         s32     res;
327
328         _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
329         phead = &pstapriv->asoc_list;
330         plist = get_next(phead);
331
332         //free sta asoc_queue
333         while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
334                 int stainfo_offset;
335                 psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
336                 plist = get_next(plist);
337
338                 stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
339                 if (stainfo_offset_valid(stainfo_offset)) {
340                         chk_alive_list[chk_alive_num++] = stainfo_offset;
341                 }
342         }
343         _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
344
345         for (i = 0; i < chk_alive_num; i++) {
346                 psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
347                 if(!(psta->state &_FW_LINKED))
348                         continue;
349
350                 /* avoid come from STA1 and send back STA1 */
351                 if (!memcmp(psta->hwaddr, &skb->data[6], 6) ||
352                     !memcmp(psta->hwaddr, null_addr, 6) ||
353                     !memcmp(psta->hwaddr, bc_addr, 6))
354                         continue;
355
356                 newskb = skb_copy(skb, GFP_ATOMIC);
357
358                 if (newskb) {
359                         memcpy(newskb->data, psta->hwaddr, 6);
360                         res = rtw_xmit(padapter, &newskb);
361                         if (res < 0) {
362                                 DBG_8723A("%s()-%d: rtw_xmit() return error!\n", __FUNCTION__, __LINE__);
363                                 pxmitpriv->tx_drop++;
364                                 dev_kfree_skb_any(newskb);
365                         } else
366                                 pxmitpriv->tx_pkts++;
367                 } else {
368                         DBG_8723A("%s-%d: skb_copy() failed!\n", __FUNCTION__, __LINE__);
369                         pxmitpriv->tx_drop++;
370                         //dev_kfree_skb_any(skb);
371                         return _FALSE;  // Caller shall tx this multicast frame via normal way.
372                 }
373         }
374
375         dev_kfree_skb_any(skb);
376         return _TRUE;
377 }
378 #endif  // CONFIG_TX_MCAST2UNI
379
380
381 int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
382 {
383         _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
384         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
385 #ifdef CONFIG_TX_MCAST2UNI
386         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
387         extern int rtw_mc2u_disable;
388 #endif  // CONFIG_TX_MCAST2UNI
389         s32 res = 0;
390 #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
391         u16 queue;
392 #endif
393
394 _func_enter_;
395
396         RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
397
398         if (rtw_if_up(padapter) == _FALSE) {
399                 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
400                 #ifdef DBG_TX_DROP_FRAME
401                 DBG_8723A("DBG_TX_DROP_FRAME %s if_up fail\n", __FUNCTION__);
402                 #endif
403                 goto drop_packet;
404         }
405
406         rtw_check_xmit_resource(padapter, pkt);
407
408 #ifdef CONFIG_TX_MCAST2UNI
409         if ( !rtw_mc2u_disable
410                 && check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE
411                 && ( IP_MCAST_MAC(pkt->data)
412                         || ICMPV6_MCAST_MAC(pkt->data) )
413                 && (padapter->registrypriv.wifi_spec == 0)
414                 )
415         {
416                 if ( pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4) ) {
417                         res = rtw_mlcst2unicst(padapter, pkt);
418                         if (res == _TRUE) {
419                                 goto exit;
420                         }
421                 } else {
422                         //DBG_8723A("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt);
423                         //DBG_8723A("!m2u );
424                 }
425         }
426 #endif  // CONFIG_TX_MCAST2UNI
427
428         res = rtw_xmit(padapter, &pkt);
429         if (res < 0) {
430                 #ifdef DBG_TX_DROP_FRAME
431                 DBG_8723A("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);
432                 #endif
433                 goto drop_packet;
434         }
435
436         pxmitpriv->tx_pkts++;
437         RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
438         goto exit;
439
440 drop_packet:
441         pxmitpriv->tx_drop++;
442         dev_kfree_skb_any(pkt);
443         RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
444
445 exit:
446
447 _func_exit_;
448
449         return 0;
450 }