linux/drivers/net/wireless/ath/wil6210/netdev.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/etherdevice.h>
  18#include "wil6210.h"
  19#include "txrx.h"
  20
  21static int wil_open(struct net_device *ndev)
  22{
  23        struct wil6210_priv *wil = ndev_to_wil(ndev);
  24
  25        wil_dbg_misc(wil, "%s()\n", __func__);
  26
  27        if (debug_fw) {
  28                wil_err(wil, "%s() while in debug_fw mode\n", __func__);
  29                return -EINVAL;
  30        }
  31
  32        return wil_up(wil);
  33}
  34
  35static int wil_stop(struct net_device *ndev)
  36{
  37        struct wil6210_priv *wil = ndev_to_wil(ndev);
  38
  39        wil_dbg_misc(wil, "%s()\n", __func__);
  40
  41        return wil_down(wil);
  42}
  43
  44static int wil_change_mtu(struct net_device *ndev, int new_mtu)
  45{
  46        struct wil6210_priv *wil = ndev_to_wil(ndev);
  47
  48        if (new_mtu < 68 || new_mtu > mtu_max) {
  49                wil_err(wil, "invalid MTU %d\n", new_mtu);
  50                return -EINVAL;
  51        }
  52
  53        wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu);
  54        ndev->mtu = new_mtu;
  55
  56        return 0;
  57}
  58
  59static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
  60{
  61        struct wil6210_priv *wil = ndev_to_wil(ndev);
  62
  63        int ret = wil_ioctl(wil, ifr->ifr_data, cmd);
  64
  65        wil_dbg_misc(wil, "ioctl(0x%04x) -> %d\n", cmd, ret);
  66
  67        return ret;
  68}
  69
  70static const struct net_device_ops wil_netdev_ops = {
  71        .ndo_open               = wil_open,
  72        .ndo_stop               = wil_stop,
  73        .ndo_start_xmit         = wil_start_xmit,
  74        .ndo_set_mac_address    = eth_mac_addr,
  75        .ndo_validate_addr      = eth_validate_addr,
  76        .ndo_change_mtu         = wil_change_mtu,
  77        .ndo_do_ioctl           = wil_do_ioctl,
  78};
  79
  80static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
  81{
  82        struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
  83                                                napi_rx);
  84        int quota = budget;
  85        int done;
  86
  87        wil_rx_handle(wil, &quota);
  88        done = budget - quota;
  89
  90        if (done < budget) {
  91                napi_complete(napi);
  92                wil6210_unmask_irq_rx(wil);
  93                wil_dbg_txrx(wil, "NAPI RX complete\n");
  94        }
  95
  96        wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done);
  97
  98        return done;
  99}
 100
 101static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
 102{
 103        struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
 104                                                napi_tx);
 105        int tx_done = 0;
 106        uint i;
 107
 108        /* always process ALL Tx complete, regardless budget - it is fast */
 109        for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
 110                struct vring *vring = &wil->vring_tx[i];
 111                struct vring_tx_data *txdata = &wil->vring_tx_data[i];
 112
 113                if (!vring->va || !txdata->enabled)
 114                        continue;
 115
 116                tx_done += wil_tx_complete(wil, i);
 117        }
 118
 119        if (tx_done < budget) {
 120                napi_complete(napi);
 121                wil6210_unmask_irq_tx(wil);
 122                wil_dbg_txrx(wil, "NAPI TX complete\n");
 123        }
 124
 125        wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done);
 126
 127        return min(tx_done, budget);
 128}
 129
 130static void wil_dev_setup(struct net_device *dev)
 131{
 132        ether_setup(dev);
 133        dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
 134}
 135
 136void *wil_if_alloc(struct device *dev)
 137{
 138        struct net_device *ndev;
 139        struct wireless_dev *wdev;
 140        struct wil6210_priv *wil;
 141        struct ieee80211_channel *ch;
 142        int rc = 0;
 143
 144        wdev = wil_cfg80211_init(dev);
 145        if (IS_ERR(wdev)) {
 146                dev_err(dev, "wil_cfg80211_init failed\n");
 147                return wdev;
 148        }
 149
 150        wil = wdev_to_wil(wdev);
 151        wil->wdev = wdev;
 152
 153        wil_dbg_misc(wil, "%s()\n", __func__);
 154
 155        rc = wil_priv_init(wil);
 156        if (rc) {
 157                dev_err(dev, "wil_priv_init failed\n");
 158                goto out_wdev;
 159        }
 160
 161        wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
 162        /* default monitor channel */
 163        ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
 164        cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
 165
 166        ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
 167        if (!ndev) {
 168                dev_err(dev, "alloc_netdev_mqs failed\n");
 169                rc = -ENOMEM;
 170                goto out_priv;
 171        }
 172
 173        ndev->netdev_ops = &wil_netdev_ops;
 174        wil_set_ethtoolops(ndev);
 175        ndev->ieee80211_ptr = wdev;
 176        ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
 177                            NETIF_F_SG | NETIF_F_GRO |
 178                            NETIF_F_TSO | NETIF_F_TSO6 |
 179                            NETIF_F_RXHASH;
 180
 181        ndev->features |= ndev->hw_features;
 182        SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
 183        wdev->netdev = ndev;
 184
 185        netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
 186                       WIL6210_NAPI_BUDGET);
 187        netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
 188                       WIL6210_NAPI_BUDGET);
 189
 190        netif_tx_stop_all_queues(ndev);
 191
 192        return wil;
 193
 194 out_priv:
 195        wil_priv_deinit(wil);
 196
 197 out_wdev:
 198        wil_wdev_free(wil);
 199
 200        return ERR_PTR(rc);
 201}
 202
 203void wil_if_free(struct wil6210_priv *wil)
 204{
 205        struct net_device *ndev = wil_to_ndev(wil);
 206
 207        wil_dbg_misc(wil, "%s()\n", __func__);
 208
 209        if (!ndev)
 210                return;
 211
 212        wil_priv_deinit(wil);
 213
 214        wil_to_ndev(wil) = NULL;
 215        free_netdev(ndev);
 216
 217        wil_wdev_free(wil);
 218}
 219
 220int wil_if_add(struct wil6210_priv *wil)
 221{
 222        struct net_device *ndev = wil_to_ndev(wil);
 223        int rc;
 224
 225        wil_dbg_misc(wil, "%s()\n", __func__);
 226
 227        rc = register_netdev(ndev);
 228        if (rc < 0) {
 229                dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
 230                return rc;
 231        }
 232
 233        return 0;
 234}
 235
 236void wil_if_remove(struct wil6210_priv *wil)
 237{
 238        struct net_device *ndev = wil_to_ndev(wil);
 239
 240        wil_dbg_misc(wil, "%s()\n", __func__);
 241
 242        unregister_netdev(ndev);
 243}
 244