GNU Linux-libre 4.14.266-gnu1
[releases.git] / drivers / staging / rtl8188eu / 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  ******************************************************************************/
15 #define _XMIT_OSDEP_C_
16
17 #include <osdep_service.h>
18 #include <drv_types.h>
19
20 #include <wifi.h>
21 #include <mlme_osdep.h>
22 #include <xmit_osdep.h>
23 #include <osdep_intf.h>
24
25 uint rtw_remainder_len(struct pkt_file *pfile)
26 {
27         return pfile->buf_len - ((size_t)(pfile->cur_addr) -
28                (size_t)(pfile->buf_start));
29 }
30
31 void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
32 {
33
34         pfile->pkt = pktptr;
35         pfile->cur_addr = pktptr->data;
36         pfile->buf_start = pktptr->data;
37         pfile->pkt_len = pktptr->len;
38         pfile->buf_len = pktptr->len;
39
40         pfile->cur_buffer = pfile->buf_start;
41
42 }
43
44 uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
45 {
46         uint    len = 0;
47
48
49         len =  rtw_remainder_len(pfile);
50         len = min(rlen, len);
51
52         if (rmem)
53                 skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
54
55         pfile->cur_addr += len;
56         pfile->pkt_len -= len;
57
58
59         return len;
60 }
61
62 int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz)
63 {
64         int i;
65
66         pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL);
67         if (pxmitbuf->pallocated_buf == NULL)
68                 return _FAIL;
69
70         pxmitbuf->pbuf = PTR_ALIGN(pxmitbuf->pallocated_buf, XMITBUF_ALIGN_SZ);
71         pxmitbuf->dma_transfer_addr = 0;
72
73         for (i = 0; i < 8; i++) {
74                 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
75                 if (!pxmitbuf->pxmit_urb[i]) {
76                         DBG_88E("pxmitbuf->pxmit_urb[i]==NULL");
77                         return _FAIL;
78                 }
79         }
80         return _SUCCESS;
81 }
82
83 void rtw_os_xmit_resource_free(struct xmit_buf *pxmitbuf)
84 {
85         int i;
86
87         for (i = 0; i < 8; i++)
88                 usb_free_urb(pxmitbuf->pxmit_urb[i]);
89
90         kfree(pxmitbuf->pallocated_buf);
91 }
92
93 #define WMM_XMIT_THRESHOLD      (NR_XMITFRAME*2/5)
94
95 void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
96 {
97         u16     queue;
98         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
99
100         queue = skb_get_queue_mapping(pkt);
101         if (padapter->registrypriv.wifi_spec) {
102                 if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
103                     (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
104                         netif_wake_subqueue(padapter->pnetdev, queue);
105         } else {
106                 if (__netif_subqueue_stopped(padapter->pnetdev, queue))
107                         netif_wake_subqueue(padapter->pnetdev, queue);
108         }
109
110         dev_kfree_skb_any(pkt);
111 }
112
113 void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe)
114 {
115         if (pxframe->pkt)
116                 rtw_os_pkt_complete(padapter, pxframe->pkt);
117         pxframe->pkt = NULL;
118 }
119
120 void rtw_os_xmit_schedule(struct adapter *padapter)
121 {
122         struct xmit_priv *pxmitpriv;
123
124         if (!padapter)
125                 return;
126
127         pxmitpriv = &padapter->xmitpriv;
128
129         spin_lock_bh(&pxmitpriv->lock);
130
131         if (rtw_txframes_pending(padapter))
132                 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
133
134         spin_unlock_bh(&pxmitpriv->lock);
135 }
136
137 static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt)
138 {
139         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
140         u16     queue;
141
142         queue = skb_get_queue_mapping(pkt);
143         if (padapter->registrypriv.wifi_spec) {
144                 /* No free space for Tx, tx_worker is too slow */
145                 if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
146                         netif_stop_subqueue(padapter->pnetdev, queue);
147         } else {
148                 if (pxmitpriv->free_xmitframe_cnt <= 4) {
149                         if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
150                                 netif_stop_subqueue(padapter->pnetdev, queue);
151                 }
152         }
153 }
154
155 static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
156 {
157         struct  sta_priv *pstapriv = &padapter->stapriv;
158         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
159         struct list_head *phead, *plist;
160         struct sk_buff *newskb;
161         struct sta_info *psta = NULL;
162         s32     res;
163
164         spin_lock_bh(&pstapriv->asoc_list_lock);
165         phead = &pstapriv->asoc_list;
166         plist = phead->next;
167
168         /* free sta asoc_queue */
169         while (phead != plist) {
170                 psta = container_of(plist, struct sta_info, asoc_list);
171
172                 plist = plist->next;
173
174                 /* avoid   come from STA1 and send back STA1 */
175                 if (!memcmp(psta->hwaddr, &skb->data[6], 6))
176                         continue;
177
178                 newskb = skb_copy(skb, GFP_ATOMIC);
179
180                 if (newskb) {
181                         memcpy(newskb->data, psta->hwaddr, 6);
182                         res = rtw_xmit(padapter, &newskb);
183                         if (res < 0) {
184                                 DBG_88E("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__);
185                                 pxmitpriv->tx_drop++;
186                                 dev_kfree_skb_any(newskb);
187                         } else {
188                                 pxmitpriv->tx_pkts++;
189                         }
190                 } else {
191                         DBG_88E("%s-%d: skb_copy() failed!\n", __func__, __LINE__);
192                         pxmitpriv->tx_drop++;
193
194                         spin_unlock_bh(&pstapriv->asoc_list_lock);
195                         return false;   /*  Caller shall tx this multicast frame via normal way. */
196                 }
197         }
198
199         spin_unlock_bh(&pstapriv->asoc_list_lock);
200         dev_kfree_skb_any(skb);
201         return true;
202 }
203
204
205 int rtw_xmit_entry(struct sk_buff *pkt, struct  net_device *pnetdev)
206 {
207         struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
208         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
209         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
210         s32 res = 0;
211
212
213         RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
214
215         if (rtw_if_up(padapter) == false) {
216                 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
217                 goto drop_packet;
218         }
219
220         rtw_check_xmit_resource(padapter, pkt);
221
222         if (!rtw_mc2u_disable && check_fwstate(pmlmepriv, WIFI_AP_STATE) &&
223             (IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data)) &&
224             (padapter->registrypriv.wifi_spec == 0)) {
225                 if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
226                         res = rtw_mlcst2unicst(padapter, pkt);
227                         if (res)
228                                 goto exit;
229                 }
230         }
231
232         res = rtw_xmit(padapter, &pkt);
233         if (res < 0)
234                 goto drop_packet;
235
236         pxmitpriv->tx_pkts++;
237         RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
238         goto exit;
239
240 drop_packet:
241         pxmitpriv->tx_drop++;
242         dev_kfree_skb_any(pkt);
243         RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
244
245 exit:
246
247
248         return 0;
249 }