OSDN Git Service

Add rtl8723bu driver version 4.4.5
[android-x86/external-kernel-drivers.git] / rtl8723bu / os_dep / linux / 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_types.h>
23
24 #define DBG_DUMP_OS_QUEUE_CTL 0
25
26 uint rtw_remainder_len(struct pkt_file *pfile)
27 {
28         return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start)));
29 }
30
31 void _rtw_open_pktfile (_pkt *pktptr, struct pkt_file *pfile)
32 {
33 _func_enter_;
34
35         pfile->pkt = pktptr;
36         pfile->cur_addr = pfile->buf_start = pktptr->data;
37         pfile->pkt_len = pfile->buf_len = pktptr->len;
38
39         pfile->cur_buffer = pfile->buf_start ;
40
41 _func_exit_;
42 }
43
44 uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
45 {
46         uint    len = 0;
47
48 _func_enter_;
49
50        len =  rtw_remainder_len(pfile);
51         len = (rlen > len)? len: rlen;
52
53        if(rmem)
54           skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
55
56        pfile->cur_addr += len;
57        pfile->pkt_len -= len;
58
59 _func_exit_;
60
61         return len;
62 }
63
64 sint rtw_endofpktfile(struct pkt_file *pfile)
65 {
66 _func_enter_;
67
68         if (pfile->pkt_len == 0) {
69 _func_exit_;
70                 return _TRUE;
71         }
72
73 _func_exit_;
74
75         return _FALSE;
76 }
77
78 void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib)
79 {
80
81 #ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
82         struct sk_buff *skb = (struct sk_buff *)pkt;
83         pattrib->hw_tcp_csum = 0;
84
85         if (skb->ip_summed == CHECKSUM_PARTIAL) {
86                 if (skb_shinfo(skb)->nr_frags == 0)
87                 {
88                         const struct iphdr *ip = ip_hdr(skb);
89                         if (ip->protocol == IPPROTO_TCP) {
90                                 // TCP checksum offload by HW
91                                 DBG_871X("CHECKSUM_PARTIAL TCP\n");
92                                 pattrib->hw_tcp_csum = 1;
93                                 //skb_checksum_help(skb);
94                         } else if (ip->protocol == IPPROTO_UDP) {
95                                 //DBG_871X("CHECKSUM_PARTIAL UDP\n");
96 #if 1
97                                 skb_checksum_help(skb);
98 #else
99                                 // Set UDP checksum = 0 to skip checksum check
100                                 struct udphdr *udp = skb_transport_header(skb);
101                                 udp->check = 0;
102 #endif
103                         } else {
104                                 DBG_871X("%s-%d TCP CSUM offload Error!!\n", __FUNCTION__, __LINE__);
105                                 WARN_ON(1);     /* we need a WARN() */
106                             }
107                 }
108                 else { // IP fragmentation case
109                         DBG_871X("%s-%d nr_frags != 0, using skb_checksum_help(skb);!!\n", __FUNCTION__, __LINE__);
110                         skb_checksum_help(skb);
111                 }
112         }
113 #endif
114
115 }
116
117 int rtw_os_xmit_resource_alloc(_adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag)
118 {
119         if (alloc_sz > 0) {
120 #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
121                 struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
122                 struct usb_device       *pusbd = pdvobjpriv->pusbdev;
123
124                 pxmitbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)alloc_sz, &pxmitbuf->dma_transfer_addr);
125                 pxmitbuf->pbuf = pxmitbuf->pallocated_buf;
126                 if(pxmitbuf->pallocated_buf == NULL)
127                         return _FAIL;
128 #else // CONFIG_USE_USB_BUFFER_ALLOC_TX
129
130                 pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
131                 if (pxmitbuf->pallocated_buf == NULL)
132                 {
133                         return _FAIL;
134                 }
135
136                 pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
137
138 #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
139         }
140
141         if (flag) {
142 #ifdef CONFIG_USB_HCI
143                 int i;
144                 for(i=0; i<8; i++)
145                 {
146                         pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
147                      if(pxmitbuf->pxmit_urb[i] == NULL)
148                      {
149                         DBG_871X("pxmitbuf->pxmit_urb[i]==NULL");
150                         return _FAIL;
151                      }
152                 }
153 #endif
154         }
155
156         return _SUCCESS;
157 }
158
159 void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 free_sz, u8 flag)
160 {
161         if (flag) {
162 #ifdef CONFIG_USB_HCI
163                 int i;
164
165                 for(i=0; i<8; i++)
166                 {
167                         if(pxmitbuf->pxmit_urb[i])
168                         {
169                                 //usb_kill_urb(pxmitbuf->pxmit_urb[i]);
170                                 usb_free_urb(pxmitbuf->pxmit_urb[i]);
171                         }
172                 }
173 #endif
174         }
175
176         if (free_sz > 0 ) {
177 #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
178                 struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
179                 struct usb_device       *pusbd = pdvobjpriv->pusbdev;
180
181                 rtw_usb_buffer_free(pusbd, (size_t)free_sz, pxmitbuf->pallocated_buf, pxmitbuf->dma_transfer_addr);
182                 pxmitbuf->pallocated_buf =  NULL;
183                 pxmitbuf->dma_transfer_addr = 0;
184 #else   // CONFIG_USE_USB_BUFFER_ALLOC_TX
185                 if(pxmitbuf->pallocated_buf)
186                         rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
187 #endif  // CONFIG_USE_USB_BUFFER_ALLOC_TX
188         }
189 }
190
191 void dump_os_queue(void *sel, _adapter *padapter)
192 {
193         struct net_device *ndev = padapter->pnetdev;
194
195 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
196         int i;
197
198         for (i=0;i<4;i++) {
199                 DBG_871X_SEL_NL(sel, "os_queue[%d]:%s\n"
200                         , i, __netif_subqueue_stopped(ndev, i)?"stopped":"waked");
201         }
202 #else
203         DBG_871X_SEL_NL(sel, "os_queue:%s\n"
204                         , netif_queue_stopped(ndev)?"stopped":"waked");
205 #endif
206 }
207
208 #define WMM_XMIT_THRESHOLD      (NR_XMITFRAME*2/5)
209
210 inline static bool rtw_os_need_wake_queue(_adapter *padapter, u16 qidx)
211 {
212 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
213         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
214
215         if (padapter->registrypriv.wifi_spec) {
216                 if (pxmitpriv->hwxmits[qidx].accnt < WMM_XMIT_THRESHOLD)
217                         return _TRUE;
218         } else {
219                 return _TRUE;
220         }
221         return _FALSE;
222 #else
223         return _TRUE;
224 #endif
225 }
226
227 inline static bool rtw_os_need_stop_queue(_adapter *padapter, u16 qidx)
228 {
229         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
230 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
231         if (padapter->registrypriv.wifi_spec) {
232                 /* No free space for Tx, tx_worker is too slow */
233                 if (pxmitpriv->hwxmits[qidx].accnt > WMM_XMIT_THRESHOLD)
234                         return _TRUE;
235         } else {
236                 if(pxmitpriv->free_xmitframe_cnt<=4)
237                         return _TRUE;
238         }
239 #else
240         if(pxmitpriv->free_xmitframe_cnt<=4)
241                 return _TRUE;
242 #endif
243         return _FALSE;
244 }
245
246 void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt)
247 {
248 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
249         u16     qidx;
250
251         qidx = skb_get_queue_mapping(pkt);
252         if (rtw_os_need_wake_queue(padapter, qidx)) {
253                 if (DBG_DUMP_OS_QUEUE_CTL)
254                         DBG_871X(FUNC_ADPT_FMT": netif_wake_subqueue[%d]\n", FUNC_ADPT_ARG(padapter), qidx);
255                 netif_wake_subqueue(padapter->pnetdev, qidx);
256         }
257 #else
258         if (rtw_os_need_wake_queue(padapter, 0)) {
259                 if (DBG_DUMP_OS_QUEUE_CTL)
260                         DBG_871X(FUNC_ADPT_FMT": netif_wake_queue\n", FUNC_ADPT_ARG(padapter));
261                 netif_wake_queue(padapter->pnetdev);
262         }
263 #endif
264
265         rtw_skb_free(pkt);
266 }
267
268 void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe)
269 {
270         if(pxframe->pkt)
271                 rtw_os_pkt_complete(padapter, pxframe->pkt);
272
273         pxframe->pkt = NULL;
274 }
275
276 void rtw_os_xmit_schedule(_adapter *padapter)
277 {
278         _adapter *pri_adapter = padapter;
279
280 #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
281         if(!padapter)
282                 return;
283
284 #ifdef CONFIG_CONCURRENT_MODE
285         if(padapter->adapter_type > PRIMARY_ADAPTER)
286                 pri_adapter = padapter->pbuddy_adapter;
287 #endif
288
289         if (_rtw_queue_empty(&padapter->xmitpriv.pending_xmitbuf_queue) == _FALSE)
290                 _rtw_up_sema(&pri_adapter->xmitpriv.xmit_sema);
291
292
293 #else
294         _irqL  irqL;
295         struct xmit_priv *pxmitpriv;
296
297         if(!padapter)
298                 return;
299
300         pxmitpriv = &padapter->xmitpriv;
301
302         _enter_critical_bh(&pxmitpriv->lock, &irqL);
303
304         if(rtw_txframes_pending(padapter))
305         {
306                 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
307         }
308
309         _exit_critical_bh(&pxmitpriv->lock, &irqL);
310 #endif
311 }
312
313 static bool rtw_check_xmit_resource(_adapter *padapter, _pkt *pkt)
314 {
315         bool busy = _FALSE;
316         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
317 #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
318         u16     qidx;
319
320         qidx = skb_get_queue_mapping(pkt);
321         if (rtw_os_need_stop_queue(padapter, qidx)) {
322                 if (DBG_DUMP_OS_QUEUE_CTL)
323                         DBG_871X(FUNC_ADPT_FMT": netif_stop_subqueue[%d]\n", FUNC_ADPT_ARG(padapter), qidx);
324                 netif_stop_subqueue(padapter->pnetdev, qidx);
325                 busy = _TRUE;
326         }
327 #else
328         if (rtw_os_need_stop_queue(padapter, 0)) {
329                 if (DBG_DUMP_OS_QUEUE_CTL)
330                         DBG_871X(FUNC_ADPT_FMT": netif_stop_queue\n", FUNC_ADPT_ARG(padapter));
331                 rtw_netif_stop_queue(padapter->pnetdev);
332                 busy = _TRUE;
333         }
334 #endif
335         return busy;
336 }
337
338 void rtw_os_wake_queue_at_free_stainfo(_adapter *padapter, int *qcnt_freed)
339 {
340 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
341         int i;
342
343         for (i=0;i<4;i++) {
344                 if (qcnt_freed[i] == 0)
345                         continue;
346
347                 if(rtw_os_need_wake_queue(padapter, i)) {
348                         if (DBG_DUMP_OS_QUEUE_CTL)
349                                 DBG_871X(FUNC_ADPT_FMT": netif_wake_subqueue[%d]\n", FUNC_ADPT_ARG(padapter), i);
350                         netif_wake_subqueue(padapter->pnetdev, i);
351                 }
352         }
353 #else
354         if (qcnt_freed[0] || qcnt_freed[1] || qcnt_freed[2] || qcnt_freed[3]) {
355                 if(rtw_os_need_wake_queue(padapter, 0)) {
356                         if (DBG_DUMP_OS_QUEUE_CTL)
357                                 DBG_871X(FUNC_ADPT_FMT": netif_wake_queue\n", FUNC_ADPT_ARG(padapter));
358                         netif_wake_queue(padapter->pnetdev);
359                 }
360         }
361 #endif
362 }
363
364 #ifdef CONFIG_TX_MCAST2UNI
365 int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb)
366 {
367         struct  sta_priv *pstapriv = &padapter->stapriv;
368         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
369         _irqL   irqL;
370         _list   *phead, *plist;
371         struct sk_buff *newskb;
372         struct sta_info *psta = NULL;
373         u8 chk_alive_num = 0;
374         char chk_alive_list[NUM_STA];
375         u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
376         u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
377
378         int i;
379         s32     res;
380
381         DBG_COUNTER(padapter->tx_logs.os_tx_m2u);
382
383         _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
384         phead = &pstapriv->asoc_list;
385         plist = get_next(phead);
386
387         //free sta asoc_queue
388         while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
389                 int stainfo_offset;
390                 psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
391                 plist = get_next(plist);
392
393                 stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
394                 if (stainfo_offset_valid(stainfo_offset)) {
395                         chk_alive_list[chk_alive_num++] = stainfo_offset;
396                 }
397         }
398         _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
399
400         for (i = 0; i < chk_alive_num; i++) {
401                 psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
402                 if(!(psta->state &_FW_LINKED))
403                 {
404                         DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked);
405                         continue;
406                 }
407
408                 /* avoid come from STA1 and send back STA1 */
409                 if (_rtw_memcmp(psta->hwaddr, &skb->data[6], 6) == _TRUE
410                         || _rtw_memcmp(psta->hwaddr, null_addr, 6) == _TRUE
411                         || _rtw_memcmp(psta->hwaddr, bc_addr, 6) == _TRUE
412                 )
413                 {
414                         DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_self);
415                         continue;
416                 }
417
418                 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry);
419
420                 newskb = rtw_skb_copy(skb);
421
422                 if (newskb) {
423                         _rtw_memcpy(newskb->data, psta->hwaddr, 6);
424                         res = rtw_xmit(padapter, &newskb);
425                         if (res < 0) {
426                                 DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_xmit);
427                                 DBG_871X("%s()-%d: rtw_xmit() return error! res=%d\n", __FUNCTION__, __LINE__, res);
428                                 pxmitpriv->tx_drop++;
429                                 rtw_skb_free(newskb);
430                         }
431                 } else {
432                         DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_skb);
433                         DBG_871X("%s-%d: rtw_skb_copy() failed!\n", __FUNCTION__, __LINE__);
434                         pxmitpriv->tx_drop++;
435                         //rtw_skb_free(skb);
436                         return _FALSE;  // Caller shall tx this multicast frame via normal way.
437                 }
438         }
439
440         rtw_skb_free(skb);
441         return _TRUE;
442 }
443 #endif  // CONFIG_TX_MCAST2UNI
444
445
446 int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
447 {
448         _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
449         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
450 #ifdef CONFIG_TX_MCAST2UNI
451         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
452         extern int rtw_mc2u_disable;
453 #endif  // CONFIG_TX_MCAST2UNI
454         s32 res = 0;
455 #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
456         u16 queue;
457 #endif
458
459 _func_enter_;
460
461         DBG_COUNTER(padapter->tx_logs.os_tx);
462         RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
463
464         if (rtw_if_up(padapter) == _FALSE) {
465                 DBG_COUNTER(padapter->tx_logs.os_tx_err_up);
466                 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
467                 #ifdef DBG_TX_DROP_FRAME
468                 DBG_871X("DBG_TX_DROP_FRAME %s if_up fail\n", __FUNCTION__);
469                 #endif
470                 goto drop_packet;
471         }
472
473         rtw_check_xmit_resource(padapter, pkt);
474
475 #ifdef CONFIG_TX_MCAST2UNI
476         if ( !rtw_mc2u_disable
477                 && check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE
478                 && ( IP_MCAST_MAC(pkt->data)
479                         || ICMPV6_MCAST_MAC(pkt->data)
480                         #ifdef CONFIG_TX_BCAST2UNI
481                         || is_broadcast_mac_addr(pkt->data)
482                         #endif
483                         )
484                 && (padapter->registrypriv.wifi_spec == 0)
485                 )
486         {
487                 if ( pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4) ) {
488                         res = rtw_mlcst2unicst(padapter, pkt);
489                         if (res == _TRUE) {
490                                 goto exit;
491                         }
492                 } else {
493                         //DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt);
494                         //DBG_871X("!m2u );
495                         DBG_COUNTER(padapter->tx_logs.os_tx_m2u_stop);
496                 }
497         }
498 #endif  // CONFIG_TX_MCAST2UNI
499
500         res = rtw_xmit(padapter, &pkt);
501         if (res < 0) {
502                 #ifdef DBG_TX_DROP_FRAME
503                 DBG_871X("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);
504                 #endif
505                 goto drop_packet;
506         }
507
508         RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
509         goto exit;
510
511 drop_packet:
512         pxmitpriv->tx_drop++;
513         rtw_os_pkt_complete(padapter, pkt);
514         RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
515
516 exit:
517
518 _func_exit_;
519
520         return 0;
521 }
522
523 int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
524 {
525         _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
526         struct  mlme_priv       *pmlmepriv = &(padapter->mlmepriv);
527         int ret = 0;
528
529         if (pkt) {
530                 if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) == _TRUE) {
531                         rtw_monitor_xmit_entry((struct sk_buff *)pkt, pnetdev);
532                 } else {
533                         rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize);
534                         ret = _rtw_xmit_entry(pkt, pnetdev);
535                 }
536
537         }
538
539         return ret;
540 }