linux/drivers/net/ethernet/sun/sunvnet.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* sunvnet.c: Sun LDOM Virtual Network Driver.
   3 *
   4 * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
   5 * Copyright (C) 2016-2017 Oracle. All rights reserved.
   6 */
   7
   8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9
  10#include <linux/module.h>
  11#include <linux/kernel.h>
  12#include <linux/types.h>
  13#include <linux/slab.h>
  14#include <linux/delay.h>
  15#include <linux/init.h>
  16#include <linux/netdevice.h>
  17#include <linux/ethtool.h>
  18#include <linux/etherdevice.h>
  19#include <linux/mutex.h>
  20#include <linux/highmem.h>
  21#include <linux/if_vlan.h>
  22
  23#if IS_ENABLED(CONFIG_IPV6)
  24#include <linux/icmpv6.h>
  25#endif
  26
  27#include <net/ip.h>
  28#include <net/icmp.h>
  29#include <net/route.h>
  30
  31#include <asm/vio.h>
  32#include <asm/ldc.h>
  33
  34#include "sunvnet_common.h"
  35
  36/* length of time before we decide the hardware is borked,
  37 * and dev->tx_timeout() should be called to fix the problem
  38 */
  39#define VNET_TX_TIMEOUT                 (5 * HZ)
  40
  41#define DRV_MODULE_NAME         "sunvnet"
  42#define DRV_MODULE_VERSION      "2.0"
  43#define DRV_MODULE_RELDATE      "February 3, 2017"
  44
  45static char version[] =
  46        DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")";
  47MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
  48MODULE_DESCRIPTION("Sun LDOM virtual network driver");
  49MODULE_LICENSE("GPL");
  50MODULE_VERSION(DRV_MODULE_VERSION);
  51
  52/* Ordered from largest major to lowest */
  53static struct vio_version vnet_versions[] = {
  54        { .major = 1, .minor = 8 },
  55        { .major = 1, .minor = 7 },
  56        { .major = 1, .minor = 6 },
  57        { .major = 1, .minor = 0 },
  58};
  59
  60static void vnet_get_drvinfo(struct net_device *dev,
  61                             struct ethtool_drvinfo *info)
  62{
  63        strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
  64        strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
  65}
  66
  67static u32 vnet_get_msglevel(struct net_device *dev)
  68{
  69        struct vnet *vp = netdev_priv(dev);
  70
  71        return vp->msg_enable;
  72}
  73
  74static void vnet_set_msglevel(struct net_device *dev, u32 value)
  75{
  76        struct vnet *vp = netdev_priv(dev);
  77
  78        vp->msg_enable = value;
  79}
  80
  81static const struct {
  82        const char string[ETH_GSTRING_LEN];
  83} ethtool_stats_keys[] = {
  84        { "rx_packets" },
  85        { "tx_packets" },
  86        { "rx_bytes" },
  87        { "tx_bytes" },
  88        { "rx_errors" },
  89        { "tx_errors" },
  90        { "rx_dropped" },
  91        { "tx_dropped" },
  92        { "multicast" },
  93        { "rx_length_errors" },
  94        { "rx_frame_errors" },
  95        { "rx_missed_errors" },
  96        { "tx_carrier_errors" },
  97        { "nports" },
  98};
  99
 100static int vnet_get_sset_count(struct net_device *dev, int sset)
 101{
 102        struct vnet *vp = (struct vnet *)netdev_priv(dev);
 103
 104        switch (sset) {
 105        case ETH_SS_STATS:
 106                return ARRAY_SIZE(ethtool_stats_keys)
 107                        + (NUM_VNET_PORT_STATS * vp->nports);
 108        default:
 109                return -EOPNOTSUPP;
 110        }
 111}
 112
 113static void vnet_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
 114{
 115        struct vnet *vp = (struct vnet *)netdev_priv(dev);
 116        struct vnet_port *port;
 117        char *p = (char *)buf;
 118
 119        switch (stringset) {
 120        case ETH_SS_STATS:
 121                memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
 122                p += sizeof(ethtool_stats_keys);
 123
 124                rcu_read_lock();
 125                list_for_each_entry_rcu(port, &vp->port_list, list) {
 126                        snprintf(p, ETH_GSTRING_LEN, "p%u.%s-%pM",
 127                                 port->q_index, port->switch_port ? "s" : "q",
 128                                 port->raddr);
 129                        p += ETH_GSTRING_LEN;
 130                        snprintf(p, ETH_GSTRING_LEN, "p%u.rx_packets",
 131                                 port->q_index);
 132                        p += ETH_GSTRING_LEN;
 133                        snprintf(p, ETH_GSTRING_LEN, "p%u.tx_packets",
 134                                 port->q_index);
 135                        p += ETH_GSTRING_LEN;
 136                        snprintf(p, ETH_GSTRING_LEN, "p%u.rx_bytes",
 137                                 port->q_index);
 138                        p += ETH_GSTRING_LEN;
 139                        snprintf(p, ETH_GSTRING_LEN, "p%u.tx_bytes",
 140                                 port->q_index);
 141                        p += ETH_GSTRING_LEN;
 142                        snprintf(p, ETH_GSTRING_LEN, "p%u.event_up",
 143                                 port->q_index);
 144                        p += ETH_GSTRING_LEN;
 145                        snprintf(p, ETH_GSTRING_LEN, "p%u.event_reset",
 146                                 port->q_index);
 147                        p += ETH_GSTRING_LEN;
 148                }
 149                rcu_read_unlock();
 150                break;
 151        default:
 152                WARN_ON(1);
 153                break;
 154        }
 155}
 156
 157static void vnet_get_ethtool_stats(struct net_device *dev,
 158                                   struct ethtool_stats *estats, u64 *data)
 159{
 160        struct vnet *vp = (struct vnet *)netdev_priv(dev);
 161        struct vnet_port *port;
 162        int i = 0;
 163
 164        data[i++] = dev->stats.rx_packets;
 165        data[i++] = dev->stats.tx_packets;
 166        data[i++] = dev->stats.rx_bytes;
 167        data[i++] = dev->stats.tx_bytes;
 168        data[i++] = dev->stats.rx_errors;
 169        data[i++] = dev->stats.tx_errors;
 170        data[i++] = dev->stats.rx_dropped;
 171        data[i++] = dev->stats.tx_dropped;
 172        data[i++] = dev->stats.multicast;
 173        data[i++] = dev->stats.rx_length_errors;
 174        data[i++] = dev->stats.rx_frame_errors;
 175        data[i++] = dev->stats.rx_missed_errors;
 176        data[i++] = dev->stats.tx_carrier_errors;
 177        data[i++] = vp->nports;
 178
 179        rcu_read_lock();
 180        list_for_each_entry_rcu(port, &vp->port_list, list) {
 181                data[i++] = port->q_index;
 182                data[i++] = port->stats.rx_packets;
 183                data[i++] = port->stats.tx_packets;
 184                data[i++] = port->stats.rx_bytes;
 185                data[i++] = port->stats.tx_bytes;
 186                data[i++] = port->stats.event_up;
 187                data[i++] = port->stats.event_reset;
 188        }
 189        rcu_read_unlock();
 190}
 191
 192static const struct ethtool_ops vnet_ethtool_ops = {
 193        .get_drvinfo            = vnet_get_drvinfo,
 194        .get_msglevel           = vnet_get_msglevel,
 195        .set_msglevel           = vnet_set_msglevel,
 196        .get_link               = ethtool_op_get_link,
 197        .get_sset_count         = vnet_get_sset_count,
 198        .get_strings            = vnet_get_strings,
 199        .get_ethtool_stats      = vnet_get_ethtool_stats,
 200};
 201
 202static LIST_HEAD(vnet_list);
 203static DEFINE_MUTEX(vnet_list_mutex);
 204
 205static struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb)
 206{
 207        unsigned int hash = vnet_hashfn(skb->data);
 208        struct hlist_head *hp = &vp->port_hash[hash];
 209        struct vnet_port *port;
 210
 211        hlist_for_each_entry_rcu(port, hp, hash) {
 212                if (!sunvnet_port_is_up_common(port))
 213                        continue;
 214                if (ether_addr_equal(port->raddr, skb->data))
 215                        return port;
 216        }
 217        list_for_each_entry_rcu(port, &vp->port_list, list) {
 218                if (!port->switch_port)
 219                        continue;
 220                if (!sunvnet_port_is_up_common(port))
 221                        continue;
 222                return port;
 223        }
 224        return NULL;
 225}
 226
 227/* func arg to vnet_start_xmit_common() to get the proper tx port */
 228static struct vnet_port *vnet_tx_port_find(struct sk_buff *skb,
 229                                           struct net_device *dev)
 230{
 231        struct vnet *vp = netdev_priv(dev);
 232
 233        return __tx_port_find(vp, skb);
 234}
 235
 236static u16 vnet_select_queue(struct net_device *dev, struct sk_buff *skb,
 237                             struct net_device *sb_dev)
 238{
 239        struct vnet *vp = netdev_priv(dev);
 240        struct vnet_port *port = __tx_port_find(vp, skb);
 241
 242        if (!port)
 243                return 0;
 244
 245        return port->q_index;
 246}
 247
 248/* Wrappers to common functions */
 249static netdev_tx_t vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 250{
 251        return sunvnet_start_xmit_common(skb, dev, vnet_tx_port_find);
 252}
 253
 254static void vnet_set_rx_mode(struct net_device *dev)
 255{
 256        struct vnet *vp = netdev_priv(dev);
 257
 258        return sunvnet_set_rx_mode_common(dev, vp);
 259}
 260
 261#ifdef CONFIG_NET_POLL_CONTROLLER
 262static void vnet_poll_controller(struct net_device *dev)
 263{
 264        struct vnet *vp = netdev_priv(dev);
 265
 266        return sunvnet_poll_controller_common(dev, vp);
 267}
 268#endif
 269
 270static const struct net_device_ops vnet_ops = {
 271        .ndo_open               = sunvnet_open_common,
 272        .ndo_stop               = sunvnet_close_common,
 273        .ndo_set_rx_mode        = vnet_set_rx_mode,
 274        .ndo_set_mac_address    = sunvnet_set_mac_addr_common,
 275        .ndo_validate_addr      = eth_validate_addr,
 276        .ndo_tx_timeout         = sunvnet_tx_timeout_common,
 277        .ndo_start_xmit         = vnet_start_xmit,
 278        .ndo_select_queue       = vnet_select_queue,
 279#ifdef CONFIG_NET_POLL_CONTROLLER
 280        .ndo_poll_controller    = vnet_poll_controller,
 281#endif
 282};
 283
 284static struct vnet *vnet_new(const u64 *local_mac,
 285                             struct vio_dev *vdev)
 286{
 287        struct net_device *dev;
 288        struct vnet *vp;
 289        int err, i;
 290
 291        dev = alloc_etherdev_mqs(sizeof(*vp), VNET_MAX_TXQS, 1);
 292        if (!dev)
 293                return ERR_PTR(-ENOMEM);
 294        dev->needed_headroom = VNET_PACKET_SKIP + 8;
 295        dev->needed_tailroom = 8;
 296
 297        for (i = 0; i < ETH_ALEN; i++)
 298                dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
 299
 300        vp = netdev_priv(dev);
 301
 302        spin_lock_init(&vp->lock);
 303        vp->dev = dev;
 304
 305        INIT_LIST_HEAD(&vp->port_list);
 306        for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
 307                INIT_HLIST_HEAD(&vp->port_hash[i]);
 308        INIT_LIST_HEAD(&vp->list);
 309        vp->local_mac = *local_mac;
 310
 311        dev->netdev_ops = &vnet_ops;
 312        dev->ethtool_ops = &vnet_ethtool_ops;
 313        dev->watchdog_timeo = VNET_TX_TIMEOUT;
 314
 315        dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_ALL_TSO |
 316                           NETIF_F_HW_CSUM | NETIF_F_SG;
 317        dev->features = dev->hw_features;
 318
 319        /* MTU range: 68 - 65535 */
 320        dev->min_mtu = ETH_MIN_MTU;
 321        dev->max_mtu = VNET_MAX_MTU;
 322
 323        SET_NETDEV_DEV(dev, &vdev->dev);
 324
 325        err = register_netdev(dev);
 326        if (err) {
 327                pr_err("Cannot register net device, aborting\n");
 328                goto err_out_free_dev;
 329        }
 330
 331        netdev_info(dev, "Sun LDOM vnet %pM\n", dev->dev_addr);
 332
 333        list_add(&vp->list, &vnet_list);
 334
 335        return vp;
 336
 337err_out_free_dev:
 338        free_netdev(dev);
 339
 340        return ERR_PTR(err);
 341}
 342
 343static struct vnet *vnet_find_or_create(const u64 *local_mac,
 344                                        struct vio_dev *vdev)
 345{
 346        struct vnet *iter, *vp;
 347
 348        mutex_lock(&vnet_list_mutex);
 349        vp = NULL;
 350        list_for_each_entry(iter, &vnet_list, list) {
 351                if (iter->local_mac == *local_mac) {
 352                        vp = iter;
 353                        break;
 354                }
 355        }
 356        if (!vp)
 357                vp = vnet_new(local_mac, vdev);
 358        mutex_unlock(&vnet_list_mutex);
 359
 360        return vp;
 361}
 362
 363static void vnet_cleanup(void)
 364{
 365        struct vnet *vp;
 366        struct net_device *dev;
 367
 368        mutex_lock(&vnet_list_mutex);
 369        while (!list_empty(&vnet_list)) {
 370                vp = list_first_entry(&vnet_list, struct vnet, list);
 371                list_del(&vp->list);
 372                dev = vp->dev;
 373                /* vio_unregister_driver() should have cleaned up port_list */
 374                BUG_ON(!list_empty(&vp->port_list));
 375                unregister_netdev(dev);
 376                free_netdev(dev);
 377        }
 378        mutex_unlock(&vnet_list_mutex);
 379}
 380
 381static const char *local_mac_prop = "local-mac-address";
 382
 383static struct vnet *vnet_find_parent(struct mdesc_handle *hp,
 384                                     u64 port_node,
 385                                     struct vio_dev *vdev)
 386{
 387        const u64 *local_mac = NULL;
 388        u64 a;
 389
 390        mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
 391                u64 target = mdesc_arc_target(hp, a);
 392                const char *name;
 393
 394                name = mdesc_get_property(hp, target, "name", NULL);
 395                if (!name || strcmp(name, "network"))
 396                        continue;
 397
 398                local_mac = mdesc_get_property(hp, target,
 399                                               local_mac_prop, NULL);
 400                if (local_mac)
 401                        break;
 402        }
 403        if (!local_mac)
 404                return ERR_PTR(-ENODEV);
 405
 406        return vnet_find_or_create(local_mac, vdev);
 407}
 408
 409static struct ldc_channel_config vnet_ldc_cfg = {
 410        .event          = sunvnet_event_common,
 411        .mtu            = 64,
 412        .mode           = LDC_MODE_UNRELIABLE,
 413};
 414
 415static struct vio_driver_ops vnet_vio_ops = {
 416        .send_attr              = sunvnet_send_attr_common,
 417        .handle_attr            = sunvnet_handle_attr_common,
 418        .handshake_complete     = sunvnet_handshake_complete_common,
 419};
 420
 421const char *remote_macaddr_prop = "remote-mac-address";
 422
 423static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 424{
 425        struct mdesc_handle *hp;
 426        struct vnet_port *port;
 427        unsigned long flags;
 428        struct vnet *vp;
 429        const u64 *rmac;
 430        int len, i, err, switch_port;
 431
 432        hp = mdesc_grab();
 433
 434        vp = vnet_find_parent(hp, vdev->mp, vdev);
 435        if (IS_ERR(vp)) {
 436                pr_err("Cannot find port parent vnet\n");
 437                err = PTR_ERR(vp);
 438                goto err_out_put_mdesc;
 439        }
 440
 441        rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
 442        err = -ENODEV;
 443        if (!rmac) {
 444                pr_err("Port lacks %s property\n", remote_macaddr_prop);
 445                goto err_out_put_mdesc;
 446        }
 447
 448        port = kzalloc(sizeof(*port), GFP_KERNEL);
 449        err = -ENOMEM;
 450        if (!port)
 451                goto err_out_put_mdesc;
 452
 453        for (i = 0; i < ETH_ALEN; i++)
 454                port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff;
 455
 456        port->vp = vp;
 457
 458        err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK,
 459                              vnet_versions, ARRAY_SIZE(vnet_versions),
 460                              &vnet_vio_ops, vp->dev->name);
 461        if (err)
 462                goto err_out_free_port;
 463
 464        err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port);
 465        if (err)
 466                goto err_out_free_port;
 467
 468        netif_napi_add(port->vp->dev, &port->napi, sunvnet_poll_common,
 469                       NAPI_POLL_WEIGHT);
 470
 471        INIT_HLIST_NODE(&port->hash);
 472        INIT_LIST_HEAD(&port->list);
 473
 474        switch_port = 0;
 475        if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL))
 476                switch_port = 1;
 477        port->switch_port = switch_port;
 478        port->tso = true;
 479        port->tsolen = 0;
 480
 481        spin_lock_irqsave(&vp->lock, flags);
 482        if (switch_port)
 483                list_add_rcu(&port->list, &vp->port_list);
 484        else
 485                list_add_tail_rcu(&port->list, &vp->port_list);
 486        hlist_add_head_rcu(&port->hash,
 487                           &vp->port_hash[vnet_hashfn(port->raddr)]);
 488        sunvnet_port_add_txq_common(port);
 489        spin_unlock_irqrestore(&vp->lock, flags);
 490
 491        dev_set_drvdata(&vdev->dev, port);
 492
 493        pr_info("%s: PORT ( remote-mac %pM%s )\n",
 494                vp->dev->name, port->raddr, switch_port ? " switch-port" : "");
 495
 496        timer_setup(&port->clean_timer, sunvnet_clean_timer_expire_common, 0);
 497
 498        napi_enable(&port->napi);
 499        vio_port_up(&port->vio);
 500
 501        mdesc_release(hp);
 502
 503        return 0;
 504
 505err_out_free_port:
 506        kfree(port);
 507
 508err_out_put_mdesc:
 509        mdesc_release(hp);
 510        return err;
 511}
 512
 513static void vnet_port_remove(struct vio_dev *vdev)
 514{
 515        struct vnet_port *port = dev_get_drvdata(&vdev->dev);
 516
 517        if (port) {
 518                del_timer_sync(&port->vio.timer);
 519
 520                napi_disable(&port->napi);
 521
 522                list_del_rcu(&port->list);
 523                hlist_del_rcu(&port->hash);
 524
 525                synchronize_rcu();
 526                del_timer_sync(&port->clean_timer);
 527                sunvnet_port_rm_txq_common(port);
 528                netif_napi_del(&port->napi);
 529                sunvnet_port_free_tx_bufs_common(port);
 530                vio_ldc_free(&port->vio);
 531
 532                dev_set_drvdata(&vdev->dev, NULL);
 533
 534                kfree(port);
 535        }
 536}
 537
 538static const struct vio_device_id vnet_port_match[] = {
 539        {
 540                .type = "vnet-port",
 541        },
 542        {},
 543};
 544MODULE_DEVICE_TABLE(vio, vnet_port_match);
 545
 546static struct vio_driver vnet_port_driver = {
 547        .id_table       = vnet_port_match,
 548        .probe          = vnet_port_probe,
 549        .remove         = vnet_port_remove,
 550        .name           = "vnet_port",
 551};
 552
 553static int __init vnet_init(void)
 554{
 555        pr_info("%s\n", version);
 556        return vio_register_driver(&vnet_port_driver);
 557}
 558
 559static void __exit vnet_exit(void)
 560{
 561        vio_unregister_driver(&vnet_port_driver);
 562        vnet_cleanup();
 563}
 564
 565module_init(vnet_init);
 566module_exit(vnet_exit);
 567