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