OSDN Git Service

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