linux/drivers/net/wireless/ath/wil6210/netdev.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2017 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, "open\n");
  26
  27        if (debug_fw ||
  28            test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
  29                wil_err(wil, "while in debug_fw or wmi_only mode\n");
  30                return -EINVAL;
  31        }
  32
  33        return wil_up(wil);
  34}
  35
  36static int wil_stop(struct net_device *ndev)
  37{
  38        struct wil6210_priv *wil = ndev_to_wil(ndev);
  39
  40        wil_dbg_misc(wil, "stop\n");
  41
  42        return wil_down(wil);
  43}
  44
  45static const struct net_device_ops wil_netdev_ops = {
  46        .ndo_open               = wil_open,
  47        .ndo_stop               = wil_stop,
  48        .ndo_start_xmit         = wil_start_xmit,
  49        .ndo_set_mac_address    = eth_mac_addr,
  50        .ndo_validate_addr      = eth_validate_addr,
  51};
  52
  53static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
  54{
  55        struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
  56                                                napi_rx);
  57        int quota = budget;
  58        int done;
  59
  60        wil_rx_handle(wil, &quota);
  61        done = budget - quota;
  62
  63        if (done < budget) {
  64                napi_complete_done(napi, done);
  65                wil6210_unmask_irq_rx(wil);
  66                wil_dbg_txrx(wil, "NAPI RX complete\n");
  67        }
  68
  69        wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done);
  70
  71        return done;
  72}
  73
  74static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
  75{
  76        struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
  77                                                napi_tx);
  78        int tx_done = 0;
  79        uint i;
  80
  81        /* always process ALL Tx complete, regardless budget - it is fast */
  82        for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
  83                struct vring *vring = &wil->vring_tx[i];
  84                struct vring_tx_data *txdata = &wil->vring_tx_data[i];
  85
  86                if (!vring->va || !txdata->enabled)
  87                        continue;
  88
  89                tx_done += wil_tx_complete(wil, i);
  90        }
  91
  92        if (tx_done < budget) {
  93                napi_complete(napi);
  94                wil6210_unmask_irq_tx(wil);
  95                wil_dbg_txrx(wil, "NAPI TX complete\n");
  96        }
  97
  98        wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done);
  99
 100        return min(tx_done, budget);
 101}
 102
 103static void wil_dev_setup(struct net_device *dev)
 104{
 105        ether_setup(dev);
 106        dev->max_mtu = mtu_max;
 107        dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
 108}
 109
 110void *wil_if_alloc(struct device *dev)
 111{
 112        struct net_device *ndev;
 113        struct wireless_dev *wdev;
 114        struct wil6210_priv *wil;
 115        struct ieee80211_channel *ch;
 116        int rc = 0;
 117
 118        wdev = wil_cfg80211_init(dev);
 119        if (IS_ERR(wdev)) {
 120                dev_err(dev, "wil_cfg80211_init failed\n");
 121                return wdev;
 122        }
 123
 124        wil = wdev_to_wil(wdev);
 125        wil->wdev = wdev;
 126        wil->radio_wdev = wdev;
 127
 128        wil_dbg_misc(wil, "if_alloc\n");
 129
 130        rc = wil_priv_init(wil);
 131        if (rc) {
 132                dev_err(dev, "wil_priv_init failed\n");
 133                goto out_wdev;
 134        }
 135
 136        wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
 137        /* default monitor channel */
 138        ch = wdev->wiphy->bands[NL80211_BAND_60GHZ]->channels;
 139        cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
 140
 141        ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
 142        if (!ndev) {
 143                dev_err(dev, "alloc_netdev_mqs failed\n");
 144                rc = -ENOMEM;
 145                goto out_priv;
 146        }
 147
 148        ndev->netdev_ops = &wil_netdev_ops;
 149        wil_set_ethtoolops(ndev);
 150        ndev->ieee80211_ptr = wdev;
 151        ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
 152                            NETIF_F_SG | NETIF_F_GRO |
 153                            NETIF_F_TSO | NETIF_F_TSO6 |
 154                            NETIF_F_RXHASH;
 155
 156        ndev->features |= ndev->hw_features;
 157        SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
 158        wdev->netdev = ndev;
 159
 160        return wil;
 161
 162 out_priv:
 163        wil_priv_deinit(wil);
 164
 165 out_wdev:
 166        wil_wdev_free(wil);
 167
 168        return ERR_PTR(rc);
 169}
 170
 171void wil_if_free(struct wil6210_priv *wil)
 172{
 173        struct net_device *ndev = wil_to_ndev(wil);
 174
 175        wil_dbg_misc(wil, "if_free\n");
 176
 177        if (!ndev)
 178                return;
 179
 180        wil_priv_deinit(wil);
 181
 182        wil_to_ndev(wil) = NULL;
 183        free_netdev(ndev);
 184
 185        wil_wdev_free(wil);
 186}
 187
 188int wil_if_add(struct wil6210_priv *wil)
 189{
 190        struct wireless_dev *wdev = wil_to_wdev(wil);
 191        struct wiphy *wiphy = wdev->wiphy;
 192        struct net_device *ndev = wil_to_ndev(wil);
 193        int rc;
 194
 195        wil_dbg_misc(wil, "entered");
 196
 197        strlcpy(wiphy->fw_version, wil->fw_version, sizeof(wiphy->fw_version));
 198
 199        rc = wiphy_register(wiphy);
 200        if (rc < 0) {
 201                wil_err(wil, "failed to register wiphy, err %d\n", rc);
 202                return rc;
 203        }
 204
 205        netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
 206                       WIL6210_NAPI_BUDGET);
 207        netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
 208                          WIL6210_NAPI_BUDGET);
 209
 210        wil_update_net_queues_bh(wil, NULL, true);
 211
 212        rc = register_netdev(ndev);
 213        if (rc < 0) {
 214                dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
 215                goto out_wiphy;
 216        }
 217
 218        return 0;
 219
 220out_wiphy:
 221        wiphy_unregister(wdev->wiphy);
 222        return rc;
 223}
 224
 225void wil_if_remove(struct wil6210_priv *wil)
 226{
 227        struct net_device *ndev = wil_to_ndev(wil);
 228        struct wireless_dev *wdev = wil_to_wdev(wil);
 229
 230        wil_dbg_misc(wil, "if_remove\n");
 231
 232        unregister_netdev(ndev);
 233        wiphy_unregister(wdev->wiphy);
 234}
 235