linux/drivers/staging/rtl8723au/os_dep/xmit_linux.c
<<
>>
Prefs
   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 <linux/if_ether.h>
  21#include <linux/ip.h>
  22#include <wifi.h>
  23#include <mlme_osdep.h>
  24#include <xmit_osdep.h>
  25#include <osdep_intf.h>
  26
  27int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter,
  28                               struct xmit_buf *pxmitbuf, u32 alloc_sz)
  29{
  30        int i;
  31
  32        pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL);
  33        if (pxmitbuf->pallocated_buf == NULL)
  34                return _FAIL;
  35
  36        pxmitbuf->pbuf = PTR_ALIGN(pxmitbuf->pallocated_buf, XMITBUF_ALIGN_SZ);
  37
  38        for (i = 0; i < 8; i++) {
  39                pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
  40                if (pxmitbuf->pxmit_urb[i] == NULL) {
  41                        DBG_8723A("pxmitbuf->pxmit_urb[i]==NULL");
  42                        return _FAIL;
  43                }
  44        }
  45        return _SUCCESS;
  46}
  47
  48void rtw_os_xmit_resource_free23a(struct rtw_adapter *padapter,
  49                               struct xmit_buf *pxmitbuf)
  50{
  51        int i;
  52
  53        for (i = 0; i < 8; i++)
  54                usb_free_urb(pxmitbuf->pxmit_urb[i]);
  55        kfree(pxmitbuf->pallocated_buf);
  56}
  57
  58#define WMM_XMIT_THRESHOLD      (NR_XMITFRAME*2/5)
  59
  60void rtw_os_pkt_complete23a(struct rtw_adapter *padapter, struct sk_buff *pkt)
  61{
  62        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
  63        u16     queue;
  64
  65        queue = skb_get_queue_mapping(pkt);
  66        if (padapter->registrypriv.wifi_spec) {
  67                if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
  68                    (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
  69                        netif_wake_subqueue(padapter->pnetdev, queue);
  70        } else {
  71                if (__netif_subqueue_stopped(padapter->pnetdev, queue))
  72                        netif_wake_subqueue(padapter->pnetdev, queue);
  73        }
  74        dev_kfree_skb_any(pkt);
  75}
  76
  77void rtw_os_xmit_complete23a(struct rtw_adapter *padapter,
  78                          struct xmit_frame *pxframe)
  79{
  80        if (pxframe->pkt)
  81                rtw_os_pkt_complete23a(padapter, pxframe->pkt);
  82
  83        pxframe->pkt = NULL;
  84}
  85
  86void rtw_os_xmit_schedule23a(struct rtw_adapter *padapter)
  87{
  88        struct xmit_priv *pxmitpriv;
  89
  90        if (!padapter)
  91                return;
  92        pxmitpriv = &padapter->xmitpriv;
  93
  94        spin_lock_bh(&pxmitpriv->lock);
  95
  96        if (rtw_txframes_pending23a(padapter))
  97                tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
  98        spin_unlock_bh(&pxmitpriv->lock);
  99}
 100
 101static void rtw_check_xmit_resource(struct rtw_adapter *padapter,
 102                                    struct sk_buff *pkt)
 103{
 104        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 105        u16     queue;
 106
 107        queue = skb_get_queue_mapping(pkt);
 108        if (padapter->registrypriv.wifi_spec) {
 109                /* No free space for Tx, tx_worker is too slow */
 110                if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
 111                        netif_stop_subqueue(padapter->pnetdev, queue);
 112        } else {
 113                if (pxmitpriv->free_xmitframe_cnt <= 4) {
 114                        if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
 115                                netif_stop_subqueue(padapter->pnetdev, queue);
 116                }
 117        }
 118}
 119
 120int rtw_xmit23a_entry23a(struct sk_buff *skb, struct net_device *pnetdev)
 121{
 122        struct rtw_adapter *padapter = netdev_priv(pnetdev);
 123        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 124        int res = 0;
 125
 126        RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, "+xmit_enry\n");
 127
 128        if (!rtw_if_up23a(padapter)) {
 129                RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
 130                         "rtw_xmit23a_entry23a: rtw_if_up23a fail\n");
 131                goto drop_packet;
 132        }
 133
 134        rtw_check_xmit_resource(padapter, skb);
 135
 136        res = rtw_xmit23a(padapter, skb);
 137        if (res < 0)
 138                goto drop_packet;
 139
 140        pxmitpriv->tx_pkts++;
 141        RT_TRACE(_module_xmit_osdep_c_, _drv_info_,
 142                 "rtw_xmit23a_entry23a: tx_pkts=%d\n",
 143                 (u32)pxmitpriv->tx_pkts);
 144        goto exit;
 145
 146drop_packet:
 147        pxmitpriv->tx_drop++;
 148        dev_kfree_skb_any(skb);
 149        RT_TRACE(_module_xmit_osdep_c_, _drv_notice_,
 150                 "rtw_xmit23a_entry23a: drop, tx_drop=%d\n",
 151                 (u32)pxmitpriv->tx_drop);
 152exit:
 153        return 0;
 154}
 155