linux/drivers/net/ntb_netdev.c
<<
>>
Prefs
   1/*
   2 * This file is provided under a dual BSD/GPLv2 license.  When using or
   3 *   redistributing this file, you may do so under either license.
   4 *
   5 *   GPL LICENSE SUMMARY
   6 *
   7 *   Copyright(c) 2012 Intel Corporation. All rights reserved.
   8 *
   9 *   This program is free software; you can redistribute it and/or modify
  10 *   it under the terms of version 2 of the GNU General Public License as
  11 *   published by the Free Software Foundation.
  12 *
  13 *   BSD LICENSE
  14 *
  15 *   Copyright(c) 2012 Intel Corporation. All rights reserved.
  16 *
  17 *   Redistribution and use in source and binary forms, with or without
  18 *   modification, are permitted provided that the following conditions
  19 *   are met:
  20 *
  21 *     * Redistributions of source code must retain the above copyright
  22 *       notice, this list of conditions and the following disclaimer.
  23 *     * Redistributions in binary form must reproduce the above copy
  24 *       notice, this list of conditions and the following disclaimer in
  25 *       the documentation and/or other materials provided with the
  26 *       distribution.
  27 *     * Neither the name of Intel Corporation nor the names of its
  28 *       contributors may be used to endorse or promote products derived
  29 *       from this software without specific prior written permission.
  30 *
  31 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  34 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  37 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  38 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  39 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  40 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  41 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42 *
  43 * Intel PCIe NTB Network Linux driver
  44 *
  45 * Contact Information:
  46 * Jon Mason <jon.mason@intel.com>
  47 */
  48#include <linux/etherdevice.h>
  49#include <linux/ethtool.h>
  50#include <linux/module.h>
  51#include <linux/pci.h>
  52#include <linux/ntb.h>
  53
  54#define NTB_NETDEV_VER  "0.7"
  55
  56MODULE_DESCRIPTION(KBUILD_MODNAME);
  57MODULE_VERSION(NTB_NETDEV_VER);
  58MODULE_LICENSE("Dual BSD/GPL");
  59MODULE_AUTHOR("Intel Corporation");
  60
  61struct ntb_netdev {
  62        struct list_head list;
  63        struct pci_dev *pdev;
  64        struct net_device *ndev;
  65        struct ntb_transport_qp *qp;
  66};
  67
  68#define NTB_TX_TIMEOUT_MS       1000
  69#define NTB_RXQ_SIZE            100
  70
  71static LIST_HEAD(dev_list);
  72
  73static void ntb_netdev_event_handler(void *data, int status)
  74{
  75        struct net_device *ndev = data;
  76        struct ntb_netdev *dev = netdev_priv(ndev);
  77
  78        netdev_dbg(ndev, "Event %x, Link %x\n", status,
  79                   ntb_transport_link_query(dev->qp));
  80
  81        /* Currently, only link status event is supported */
  82        if (status)
  83                netif_carrier_on(ndev);
  84        else
  85                netif_carrier_off(ndev);
  86}
  87
  88static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
  89                                  void *data, int len)
  90{
  91        struct net_device *ndev = qp_data;
  92        struct sk_buff *skb;
  93        int rc;
  94
  95        skb = data;
  96        if (!skb)
  97                return;
  98
  99        netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
 100
 101        skb_put(skb, len);
 102        skb->protocol = eth_type_trans(skb, ndev);
 103        skb->ip_summed = CHECKSUM_NONE;
 104
 105        if (netif_rx(skb) == NET_RX_DROP) {
 106                ndev->stats.rx_errors++;
 107                ndev->stats.rx_dropped++;
 108        } else {
 109                ndev->stats.rx_packets++;
 110                ndev->stats.rx_bytes += len;
 111        }
 112
 113        skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
 114        if (!skb) {
 115                ndev->stats.rx_errors++;
 116                ndev->stats.rx_frame_errors++;
 117                return;
 118        }
 119
 120        rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
 121        if (rc) {
 122                dev_kfree_skb(skb);
 123                ndev->stats.rx_errors++;
 124                ndev->stats.rx_fifo_errors++;
 125        }
 126}
 127
 128static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
 129                                  void *data, int len)
 130{
 131        struct net_device *ndev = qp_data;
 132        struct sk_buff *skb;
 133
 134        skb = data;
 135        if (!skb || !ndev)
 136                return;
 137
 138        if (len > 0) {
 139                ndev->stats.tx_packets++;
 140                ndev->stats.tx_bytes += skb->len;
 141        } else {
 142                ndev->stats.tx_errors++;
 143                ndev->stats.tx_aborted_errors++;
 144        }
 145
 146        dev_kfree_skb(skb);
 147}
 148
 149static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
 150                                         struct net_device *ndev)
 151{
 152        struct ntb_netdev *dev = netdev_priv(ndev);
 153        int rc;
 154
 155        netdev_dbg(ndev, "%s: skb len %d\n", __func__, skb->len);
 156
 157        rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
 158        if (rc)
 159                goto err;
 160
 161        return NETDEV_TX_OK;
 162
 163err:
 164        ndev->stats.tx_dropped++;
 165        ndev->stats.tx_errors++;
 166        return NETDEV_TX_BUSY;
 167}
 168
 169static int ntb_netdev_open(struct net_device *ndev)
 170{
 171        struct ntb_netdev *dev = netdev_priv(ndev);
 172        struct sk_buff *skb;
 173        int rc, i, len;
 174
 175        /* Add some empty rx bufs */
 176        for (i = 0; i < NTB_RXQ_SIZE; i++) {
 177                skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
 178                if (!skb) {
 179                        rc = -ENOMEM;
 180                        goto err;
 181                }
 182
 183                rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
 184                                              ndev->mtu + ETH_HLEN);
 185                if (rc == -EINVAL)
 186                        goto err;
 187        }
 188
 189        netif_carrier_off(ndev);
 190        ntb_transport_link_up(dev->qp);
 191
 192        return 0;
 193
 194err:
 195        while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
 196                dev_kfree_skb(skb);
 197        return rc;
 198}
 199
 200static int ntb_netdev_close(struct net_device *ndev)
 201{
 202        struct ntb_netdev *dev = netdev_priv(ndev);
 203        struct sk_buff *skb;
 204        int len;
 205
 206        ntb_transport_link_down(dev->qp);
 207
 208        while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
 209                dev_kfree_skb(skb);
 210
 211        return 0;
 212}
 213
 214static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)
 215{
 216        struct ntb_netdev *dev = netdev_priv(ndev);
 217        struct sk_buff *skb;
 218        int len, rc;
 219
 220        if (new_mtu > ntb_transport_max_size(dev->qp) - ETH_HLEN)
 221                return -EINVAL;
 222
 223        if (!netif_running(ndev)) {
 224                ndev->mtu = new_mtu;
 225                return 0;
 226        }
 227
 228        /* Bring down the link and dispose of posted rx entries */
 229        ntb_transport_link_down(dev->qp);
 230
 231        if (ndev->mtu < new_mtu) {
 232                int i;
 233
 234                for (i = 0; (skb = ntb_transport_rx_remove(dev->qp, &len)); i++)
 235                        dev_kfree_skb(skb);
 236
 237                for (; i; i--) {
 238                        skb = netdev_alloc_skb(ndev, new_mtu + ETH_HLEN);
 239                        if (!skb) {
 240                                rc = -ENOMEM;
 241                                goto err;
 242                        }
 243
 244                        rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
 245                                                      new_mtu + ETH_HLEN);
 246                        if (rc) {
 247                                dev_kfree_skb(skb);
 248                                goto err;
 249                        }
 250                }
 251        }
 252
 253        ndev->mtu = new_mtu;
 254
 255        ntb_transport_link_up(dev->qp);
 256
 257        return 0;
 258
 259err:
 260        ntb_transport_link_down(dev->qp);
 261
 262        while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
 263                dev_kfree_skb(skb);
 264
 265        netdev_err(ndev, "Error changing MTU, device inoperable\n");
 266        return rc;
 267}
 268
 269static const struct net_device_ops ntb_netdev_ops = {
 270        .ndo_open = ntb_netdev_open,
 271        .ndo_stop = ntb_netdev_close,
 272        .ndo_start_xmit = ntb_netdev_start_xmit,
 273        .ndo_change_mtu = ntb_netdev_change_mtu,
 274        .ndo_set_mac_address = eth_mac_addr,
 275};
 276
 277static void ntb_get_drvinfo(struct net_device *ndev,
 278                            struct ethtool_drvinfo *info)
 279{
 280        struct ntb_netdev *dev = netdev_priv(ndev);
 281
 282        strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
 283        strlcpy(info->version, NTB_NETDEV_VER, sizeof(info->version));
 284        strlcpy(info->bus_info, pci_name(dev->pdev), sizeof(info->bus_info));
 285}
 286
 287static int ntb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 288{
 289        cmd->supported = SUPPORTED_Backplane;
 290        cmd->advertising = ADVERTISED_Backplane;
 291        cmd->speed = SPEED_UNKNOWN;
 292        ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
 293        cmd->duplex = DUPLEX_FULL;
 294        cmd->port = PORT_OTHER;
 295        cmd->phy_address = 0;
 296        cmd->transceiver = XCVR_DUMMY1;
 297        cmd->autoneg = AUTONEG_ENABLE;
 298        cmd->maxtxpkt = 0;
 299        cmd->maxrxpkt = 0;
 300
 301        return 0;
 302}
 303
 304static const struct ethtool_ops ntb_ethtool_ops = {
 305        .get_drvinfo = ntb_get_drvinfo,
 306        .get_link = ethtool_op_get_link,
 307        .get_settings = ntb_get_settings,
 308};
 309
 310static const struct ntb_queue_handlers ntb_netdev_handlers = {
 311        .tx_handler = ntb_netdev_tx_handler,
 312        .rx_handler = ntb_netdev_rx_handler,
 313        .event_handler = ntb_netdev_event_handler,
 314};
 315
 316static int ntb_netdev_probe(struct pci_dev *pdev)
 317{
 318        struct net_device *ndev;
 319        struct ntb_netdev *dev;
 320        int rc;
 321
 322        ndev = alloc_etherdev(sizeof(struct ntb_netdev));
 323        if (!ndev)
 324                return -ENOMEM;
 325
 326        dev = netdev_priv(ndev);
 327        dev->ndev = ndev;
 328        dev->pdev = pdev;
 329        BUG_ON(!dev->pdev);
 330        ndev->features = NETIF_F_HIGHDMA;
 331
 332        ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 333
 334        ndev->hw_features = ndev->features;
 335        ndev->watchdog_timeo = msecs_to_jiffies(NTB_TX_TIMEOUT_MS);
 336
 337        random_ether_addr(ndev->perm_addr);
 338        memcpy(ndev->dev_addr, ndev->perm_addr, ndev->addr_len);
 339
 340        ndev->netdev_ops = &ntb_netdev_ops;
 341        SET_ETHTOOL_OPS(ndev, &ntb_ethtool_ops);
 342
 343        dev->qp = ntb_transport_create_queue(ndev, pdev, &ntb_netdev_handlers);
 344        if (!dev->qp) {
 345                rc = -EIO;
 346                goto err;
 347        }
 348
 349        ndev->mtu = ntb_transport_max_size(dev->qp) - ETH_HLEN;
 350
 351        rc = register_netdev(ndev);
 352        if (rc)
 353                goto err1;
 354
 355        list_add(&dev->list, &dev_list);
 356        dev_info(&pdev->dev, "%s created\n", ndev->name);
 357        return 0;
 358
 359err1:
 360        ntb_transport_free_queue(dev->qp);
 361err:
 362        free_netdev(ndev);
 363        return rc;
 364}
 365
 366static void ntb_netdev_remove(struct pci_dev *pdev)
 367{
 368        struct net_device *ndev;
 369        struct ntb_netdev *dev;
 370
 371        list_for_each_entry(dev, &dev_list, list) {
 372                if (dev->pdev == pdev)
 373                        break;
 374        }
 375        if (dev == NULL)
 376                return;
 377
 378        list_del(&dev->list);
 379
 380        ndev = dev->ndev;
 381
 382        unregister_netdev(ndev);
 383        ntb_transport_free_queue(dev->qp);
 384        free_netdev(ndev);
 385}
 386
 387static struct ntb_client ntb_netdev_client = {
 388        .driver.name = KBUILD_MODNAME,
 389        .driver.owner = THIS_MODULE,
 390        .probe = ntb_netdev_probe,
 391        .remove = ntb_netdev_remove,
 392};
 393
 394static int __init ntb_netdev_init_module(void)
 395{
 396        int rc;
 397
 398        rc = ntb_register_client_dev(KBUILD_MODNAME);
 399        if (rc)
 400                return rc;
 401        return ntb_register_client(&ntb_netdev_client);
 402}
 403module_init(ntb_netdev_init_module);
 404
 405static void __exit ntb_netdev_exit_module(void)
 406{
 407        ntb_unregister_client(&ntb_netdev_client);
 408        ntb_unregister_client_dev(KBUILD_MODNAME);
 409}
 410module_exit(ntb_netdev_exit_module);
 411
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.