OSDN Git Service

Replace malloc/free wrappers with proper kmalloc/kfree
[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                 rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
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                 rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
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 (_rtw_memcmp(psta->hwaddr, &skb->data[6], 6) == _TRUE
352                         || _rtw_memcmp(psta->hwaddr, null_addr, 6) == _TRUE
353                         || _rtw_memcmp(psta->hwaddr, bc_addr, 6) == _TRUE
354                 )
355                         continue;
356
357                 newskb = skb_copy(skb, GFP_ATOMIC);
358
359                 if (newskb) {
360                         _rtw_memcpy(newskb->data, psta->hwaddr, 6);
361                         res = rtw_xmit(padapter, &newskb);
362                         if (res < 0) {
363                                 DBG_8723A("%s()-%d: rtw_xmit() return error!\n", __FUNCTION__, __LINE__);
364                                 pxmitpriv->tx_drop++;
365                                 dev_kfree_skb_any(newskb);
366                         } else
367                                 pxmitpriv->tx_pkts++;
368                 } else {
369                         DBG_8723A("%s-%d: skb_copy() failed!\n", __FUNCTION__, __LINE__);
370                         pxmitpriv->tx_drop++;
371                         //dev_kfree_skb_any(skb);
372                         return _FALSE;  // Caller shall tx this multicast frame via normal way.
373                 }
374         }
375
376         dev_kfree_skb_any(skb);
377         return _TRUE;
378 }
379 #endif  // CONFIG_TX_MCAST2UNI
380
381
382 int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
383 {
384         _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
385         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
386 #ifdef CONFIG_TX_MCAST2UNI
387         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
388         extern int rtw_mc2u_disable;
389 #endif  // CONFIG_TX_MCAST2UNI
390         s32 res = 0;
391 #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
392         u16 queue;
393 #endif
394
395 _func_enter_;
396
397         RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
398
399         if (rtw_if_up(padapter) == _FALSE) {
400                 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
401                 #ifdef DBG_TX_DROP_FRAME
402                 DBG_8723A("DBG_TX_DROP_FRAME %s if_up fail\n", __FUNCTION__);
403                 #endif
404                 goto drop_packet;
405         }
406
407         rtw_check_xmit_resource(padapter, pkt);
408
409 #ifdef CONFIG_TX_MCAST2UNI
410         if ( !rtw_mc2u_disable
411                 && check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE
412                 && ( IP_MCAST_MAC(pkt->data)
413                         || ICMPV6_MCAST_MAC(pkt->data) )
414                 && (padapter->registrypriv.wifi_spec == 0)
415                 )
416         {
417                 if ( pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4) ) {
418                         res = rtw_mlcst2unicst(padapter, pkt);
419                         if (res == _TRUE) {
420                                 goto exit;
421                         }
422                 } else {
423                         //DBG_8723A("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt);
424                         //DBG_8723A("!m2u );
425                 }
426         }
427 #endif  // CONFIG_TX_MCAST2UNI
428
429         res = rtw_xmit(padapter, &pkt);
430         if (res < 0) {
431                 #ifdef DBG_TX_DROP_FRAME
432                 DBG_8723A("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);
433                 #endif
434                 goto drop_packet;
435         }
436
437         pxmitpriv->tx_pkts++;
438         RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
439         goto exit;
440
441 drop_packet:
442         pxmitpriv->tx_drop++;
443         dev_kfree_skb_any(pkt);
444         RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
445
446 exit:
447
448 _func_exit_;
449
450         return 0;
451 }