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