blob: 4b1b04e007151aa260b1f3c36f11e40f0f7e4e2f [file] [log] [blame]
Larry Fingerc2478d32013-08-21 22:34:02 -05001/******************************************************************************
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 *
Larry Fingerc2478d32013-08-21 22:34:02 -050014 ******************************************************************************/
15#define _XMIT_OSDEP_C_
16
Larry Fingerc2478d32013-08-21 22:34:02 -050017#include <osdep_service.h>
18#include <drv_types.h>
19
Larry Fingerc2478d32013-08-21 22:34:02 -050020#include <wifi.h>
21#include <mlme_osdep.h>
22#include <xmit_osdep.h>
23#include <osdep_intf.h>
Larry Fingerc2478d32013-08-21 22:34:02 -050024
25uint 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
31void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
32{
Larry Fingerc2478d32013-08-21 22:34:02 -050033
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
Larry Fingerc2478d32013-08-21 22:34:02 -050042}
43
Jia He7be921a22014-11-04 09:39:58 +080044uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
Larry Fingerc2478d32013-08-21 22:34:02 -050045{
46 uint len = 0;
47
Larry Fingerc2478d32013-08-21 22:34:02 -050048
49 len = rtw_remainder_len(pfile);
Ivan Safonov20e76532015-10-27 22:16:25 +070050 len = min(rlen, len);
Larry Fingerc2478d32013-08-21 22:34:02 -050051
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
Larry Fingerc2478d32013-08-21 22:34:02 -050058
59 return len;
60}
61
62int rtw_endofpktfile(struct pkt_file *pfile)
63{
Krzysztof Konopko31d4cf12014-11-10 18:54:22 +000064 return pfile->pkt_len == 0;
Larry Fingerc2478d32013-08-21 22:34:02 -050065}
66
Larry Fingerc2478d32013-08-21 22:34:02 -050067int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz)
68{
69 int i;
70
navin patidarfadbe0c2014-06-22 14:06:23 +053071 pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL);
Larry Fingerc2478d32013-08-21 22:34:02 -050072 if (pxmitbuf->pallocated_buf == NULL)
73 return _FAIL;
74
Ivan Safonovfb113402016-09-19 00:25:40 +070075 pxmitbuf->pbuf = PTR_ALIGN(pxmitbuf->pallocated_buf, XMITBUF_ALIGN_SZ);
Larry Fingerc2478d32013-08-21 22:34:02 -050076 pxmitbuf->dma_transfer_addr = 0;
77
78 for (i = 0; i < 8; i++) {
79 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
80 if (pxmitbuf->pxmit_urb[i] == NULL) {
81 DBG_88E("pxmitbuf->pxmit_urb[i]==NULL");
82 return _FAIL;
83 }
84 }
85 return _SUCCESS;
86}
87
88void rtw_os_xmit_resource_free(struct adapter *padapter,
89 struct xmit_buf *pxmitbuf, u32 free_sz)
90{
91 int i;
92
93 for (i = 0; i < 8; i++)
94 usb_free_urb(pxmitbuf->pxmit_urb[i]);
95
96 kfree(pxmitbuf->pallocated_buf);
97}
98
99#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5)
100
101void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
102{
Larry Fingerc2478d32013-08-21 22:34:02 -0500103 u16 queue;
104 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
105
106 queue = skb_get_queue_mapping(pkt);
107 if (padapter->registrypriv.wifi_spec) {
108 if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
109 (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
110 netif_wake_subqueue(padapter->pnetdev, queue);
111 } else {
112 if (__netif_subqueue_stopped(padapter->pnetdev, queue))
113 netif_wake_subqueue(padapter->pnetdev, queue);
114 }
Larry Fingerc2478d32013-08-21 22:34:02 -0500115
116 dev_kfree_skb_any(pkt);
117}
118
119void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe)
120{
121 if (pxframe->pkt)
122 rtw_os_pkt_complete(padapter, pxframe->pkt);
123 pxframe->pkt = NULL;
124}
125
126void rtw_os_xmit_schedule(struct adapter *padapter)
127{
Larry Fingerc2478d32013-08-21 22:34:02 -0500128 struct xmit_priv *pxmitpriv;
129
130 if (!padapter)
131 return;
132
133 pxmitpriv = &padapter->xmitpriv;
134
Larry Finger7057dcb2013-12-19 22:38:34 -0600135 spin_lock_bh(&pxmitpriv->lock);
Larry Fingerc2478d32013-08-21 22:34:02 -0500136
137 if (rtw_txframes_pending(padapter))
138 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
139
Larry Fingere02bcf62013-12-19 22:38:35 -0600140 spin_unlock_bh(&pxmitpriv->lock);
Larry Fingerc2478d32013-08-21 22:34:02 -0500141}
142
143static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt)
144{
145 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
146 u16 queue;
147
148 queue = skb_get_queue_mapping(pkt);
149 if (padapter->registrypriv.wifi_spec) {
150 /* No free space for Tx, tx_worker is too slow */
151 if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
152 netif_stop_subqueue(padapter->pnetdev, queue);
153 } else {
154 if (pxmitpriv->free_xmitframe_cnt <= 4) {
155 if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
156 netif_stop_subqueue(padapter->pnetdev, queue);
157 }
158 }
159}
160
161static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
162{
163 struct sta_priv *pstapriv = &padapter->stapriv;
164 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
Larry Fingerc2478d32013-08-21 22:34:02 -0500165 struct list_head *phead, *plist;
166 struct sk_buff *newskb;
167 struct sta_info *psta = NULL;
168 s32 res;
169
Larry Finger7057dcb2013-12-19 22:38:34 -0600170 spin_lock_bh(&pstapriv->asoc_list_lock);
Larry Fingerc2478d32013-08-21 22:34:02 -0500171 phead = &pstapriv->asoc_list;
Larry Fingerc44e5e32014-02-09 15:15:58 -0600172 plist = phead->next;
Larry Fingerc2478d32013-08-21 22:34:02 -0500173
174 /* free sta asoc_queue */
navin patidar84660702014-06-22 13:49:32 +0530175 while (phead != plist) {
Larry Fingerbea88102014-02-09 15:15:57 -0600176 psta = container_of(plist, struct sta_info, asoc_list);
Larry Fingerc2478d32013-08-21 22:34:02 -0500177
Larry Fingerc44e5e32014-02-09 15:15:58 -0600178 plist = plist->next;
Larry Fingerc2478d32013-08-21 22:34:02 -0500179
180 /* avoid come from STA1 and send back STA1 */
181 if (!memcmp(psta->hwaddr, &skb->data[6], 6))
182 continue;
183
184 newskb = skb_copy(skb, GFP_ATOMIC);
185
186 if (newskb) {
187 memcpy(newskb->data, psta->hwaddr, 6);
188 res = rtw_xmit(padapter, &newskb);
189 if (res < 0) {
190 DBG_88E("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__);
191 pxmitpriv->tx_drop++;
192 dev_kfree_skb_any(newskb);
193 } else {
194 pxmitpriv->tx_pkts++;
195 }
196 } else {
197 DBG_88E("%s-%d: skb_copy() failed!\n", __func__, __LINE__);
198 pxmitpriv->tx_drop++;
199
Larry Fingere02bcf62013-12-19 22:38:35 -0600200 spin_unlock_bh(&pstapriv->asoc_list_lock);
Larry Fingerc2478d32013-08-21 22:34:02 -0500201 return false; /* Caller shall tx this multicast frame via normal way. */
202 }
203 }
204
Larry Fingere02bcf62013-12-19 22:38:35 -0600205 spin_unlock_bh(&pstapriv->asoc_list_lock);
Larry Fingerc2478d32013-08-21 22:34:02 -0500206 dev_kfree_skb_any(skb);
207 return true;
208}
209
210
211int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
212{
213 struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
214 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
215 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
216 s32 res = 0;
217
Larry Fingerc2478d32013-08-21 22:34:02 -0500218
219 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
220
221 if (rtw_if_up(padapter) == false) {
222 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
223 goto drop_packet;
224 }
225
226 rtw_check_xmit_resource(padapter, pkt);
227
228 if (!rtw_mc2u_disable && check_fwstate(pmlmepriv, WIFI_AP_STATE) &&
229 (IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data)) &&
230 (padapter->registrypriv.wifi_spec == 0)) {
231 if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
232 res = rtw_mlcst2unicst(padapter, pkt);
233 if (res)
234 goto exit;
235 }
236 }
237
238 res = rtw_xmit(padapter, &pkt);
239 if (res < 0)
240 goto drop_packet;
241
242 pxmitpriv->tx_pkts++;
243 RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
244 goto exit;
245
246drop_packet:
247 pxmitpriv->tx_drop++;
248 dev_kfree_skb_any(pkt);
249 RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
250
251exit:
252
Larry Fingerc2478d32013-08-21 22:34:02 -0500253
254 return 0;
255}