1e689cf4aSJeff Kirsher /* sunvnet.c: Sun LDOM Virtual Network Driver. 2e689cf4aSJeff Kirsher * 3e689cf4aSJeff Kirsher * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> 4e689cf4aSJeff Kirsher */ 5e689cf4aSJeff Kirsher 6e689cf4aSJeff Kirsher #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7e689cf4aSJeff Kirsher 8e689cf4aSJeff Kirsher #include <linux/module.h> 9e689cf4aSJeff Kirsher #include <linux/kernel.h> 10e689cf4aSJeff Kirsher #include <linux/types.h> 11e689cf4aSJeff Kirsher #include <linux/slab.h> 12e689cf4aSJeff Kirsher #include <linux/delay.h> 13e689cf4aSJeff Kirsher #include <linux/init.h> 14e689cf4aSJeff Kirsher #include <linux/netdevice.h> 15e689cf4aSJeff Kirsher #include <linux/ethtool.h> 16e689cf4aSJeff Kirsher #include <linux/etherdevice.h> 17e689cf4aSJeff Kirsher #include <linux/mutex.h> 18da38c564SDavid L Stevens #include <linux/highmem.h> 19e4defc77SDavid L Stevens #include <linux/if_vlan.h> 20e689cf4aSJeff Kirsher 21a2b78e9bSDavid L Stevens #if IS_ENABLED(CONFIG_IPV6) 22a2b78e9bSDavid L Stevens #include <linux/icmpv6.h> 23a2b78e9bSDavid L Stevens #endif 24a2b78e9bSDavid L Stevens 256d0ba919SDavid L Stevens #include <net/ip.h> 26a2b78e9bSDavid L Stevens #include <net/icmp.h> 27a2b78e9bSDavid L Stevens #include <net/route.h> 28a2b78e9bSDavid L Stevens 29e689cf4aSJeff Kirsher #include <asm/vio.h> 30e689cf4aSJeff Kirsher #include <asm/ldc.h> 31e689cf4aSJeff Kirsher 32*31762eaaSAaron Young #include "sunvnet_common.h" 33*31762eaaSAaron Young 34*31762eaaSAaron Young /* length of time before we decide the hardware is borked, 35*31762eaaSAaron Young * and dev->tx_timeout() should be called to fix the problem 36*31762eaaSAaron Young */ 37*31762eaaSAaron Young #define VNET_TX_TIMEOUT (5 * HZ) 38e689cf4aSJeff Kirsher 39e689cf4aSJeff Kirsher #define DRV_MODULE_NAME "sunvnet" 40e689cf4aSJeff Kirsher #define DRV_MODULE_VERSION "1.0" 41e689cf4aSJeff Kirsher #define DRV_MODULE_RELDATE "June 25, 2007" 42e689cf4aSJeff Kirsher 43f73d12bdSBill Pemberton static char version[] = 44e689cf4aSJeff Kirsher DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 45e689cf4aSJeff Kirsher MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 46e689cf4aSJeff Kirsher MODULE_DESCRIPTION("Sun LDOM virtual network driver"); 47e689cf4aSJeff Kirsher MODULE_LICENSE("GPL"); 48e689cf4aSJeff Kirsher MODULE_VERSION(DRV_MODULE_VERSION); 49e689cf4aSJeff Kirsher 50e689cf4aSJeff Kirsher /* Ordered from largest major to lowest */ 51e689cf4aSJeff Kirsher static struct vio_version vnet_versions[] = { 526d0ba919SDavid L Stevens { .major = 1, .minor = 8 }, 536d0ba919SDavid L Stevens { .major = 1, .minor = 7 }, 54e4defc77SDavid L Stevens { .major = 1, .minor = 6 }, 55e689cf4aSJeff Kirsher { .major = 1, .minor = 0 }, 56e689cf4aSJeff Kirsher }; 57e689cf4aSJeff Kirsher 58e689cf4aSJeff Kirsher static void vnet_get_drvinfo(struct net_device *dev, 59e689cf4aSJeff Kirsher struct ethtool_drvinfo *info) 60e689cf4aSJeff Kirsher { 617826d43fSJiri Pirko strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 627826d43fSJiri Pirko strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); 63e689cf4aSJeff Kirsher } 64e689cf4aSJeff Kirsher 65e689cf4aSJeff Kirsher static u32 vnet_get_msglevel(struct net_device *dev) 66e689cf4aSJeff Kirsher { 67e689cf4aSJeff Kirsher struct vnet *vp = netdev_priv(dev); 68e689cf4aSJeff Kirsher return vp->msg_enable; 69e689cf4aSJeff Kirsher } 70e689cf4aSJeff Kirsher 71e689cf4aSJeff Kirsher static void vnet_set_msglevel(struct net_device *dev, u32 value) 72e689cf4aSJeff Kirsher { 73e689cf4aSJeff Kirsher struct vnet *vp = netdev_priv(dev); 74e689cf4aSJeff Kirsher vp->msg_enable = value; 75e689cf4aSJeff Kirsher } 76e689cf4aSJeff Kirsher 77e689cf4aSJeff Kirsher static const struct ethtool_ops vnet_ethtool_ops = { 78e689cf4aSJeff Kirsher .get_drvinfo = vnet_get_drvinfo, 79e689cf4aSJeff Kirsher .get_msglevel = vnet_get_msglevel, 80e689cf4aSJeff Kirsher .set_msglevel = vnet_set_msglevel, 81e689cf4aSJeff Kirsher .get_link = ethtool_op_get_link, 82e689cf4aSJeff Kirsher }; 83e689cf4aSJeff Kirsher 84e689cf4aSJeff Kirsher static LIST_HEAD(vnet_list); 85e689cf4aSJeff Kirsher static DEFINE_MUTEX(vnet_list_mutex); 86e689cf4aSJeff Kirsher 87e689cf4aSJeff Kirsher static const struct net_device_ops vnet_ops = { 88*31762eaaSAaron Young .ndo_open = sunvnet_open_common, 89*31762eaaSAaron Young .ndo_stop = sunvnet_close_common, 90*31762eaaSAaron Young .ndo_set_rx_mode = sunvnet_set_rx_mode_common, 91*31762eaaSAaron Young .ndo_set_mac_address = sunvnet_set_mac_addr_common, 92e689cf4aSJeff Kirsher .ndo_validate_addr = eth_validate_addr, 93*31762eaaSAaron Young .ndo_tx_timeout = sunvnet_tx_timeout_common, 94*31762eaaSAaron Young .ndo_change_mtu = sunvnet_change_mtu_common, 95*31762eaaSAaron Young .ndo_start_xmit = sunvnet_start_xmit_common, 96*31762eaaSAaron Young .ndo_select_queue = sunvnet_select_queue_common, 9769088822SSowmini Varadhan #ifdef CONFIG_NET_POLL_CONTROLLER 98*31762eaaSAaron Young .ndo_poll_controller = sunvnet_poll_controller_common, 9969088822SSowmini Varadhan #endif 100e689cf4aSJeff Kirsher }; 101e689cf4aSJeff Kirsher 1024c5d283aSSowmini Varadhan static struct vnet *vnet_new(const u64 *local_mac, 1034c5d283aSSowmini Varadhan struct vio_dev *vdev) 104e689cf4aSJeff Kirsher { 105e689cf4aSJeff Kirsher struct net_device *dev; 106e689cf4aSJeff Kirsher struct vnet *vp; 107e689cf4aSJeff Kirsher int err, i; 108e689cf4aSJeff Kirsher 109d51bffd1SSowmini Varadhan dev = alloc_etherdev_mqs(sizeof(*vp), VNET_MAX_TXQS, 1); 11041de8d4cSJoe Perches if (!dev) 111e689cf4aSJeff Kirsher return ERR_PTR(-ENOMEM); 1128e845f4cSDavid L Stevens dev->needed_headroom = VNET_PACKET_SKIP + 8; 1138e845f4cSDavid L Stevens dev->needed_tailroom = 8; 114e689cf4aSJeff Kirsher 115e689cf4aSJeff Kirsher for (i = 0; i < ETH_ALEN; i++) 116e689cf4aSJeff Kirsher dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff; 117e689cf4aSJeff Kirsher 118e689cf4aSJeff Kirsher vp = netdev_priv(dev); 119e689cf4aSJeff Kirsher 120e689cf4aSJeff Kirsher spin_lock_init(&vp->lock); 121e689cf4aSJeff Kirsher vp->dev = dev; 122e689cf4aSJeff Kirsher 123e689cf4aSJeff Kirsher INIT_LIST_HEAD(&vp->port_list); 124e689cf4aSJeff Kirsher for (i = 0; i < VNET_PORT_HASH_SIZE; i++) 125e689cf4aSJeff Kirsher INIT_HLIST_HEAD(&vp->port_hash[i]); 126e689cf4aSJeff Kirsher INIT_LIST_HEAD(&vp->list); 127e689cf4aSJeff Kirsher vp->local_mac = *local_mac; 128e689cf4aSJeff Kirsher 129e689cf4aSJeff Kirsher dev->netdev_ops = &vnet_ops; 130e689cf4aSJeff Kirsher dev->ethtool_ops = &vnet_ethtool_ops; 131e689cf4aSJeff Kirsher dev->watchdog_timeo = VNET_TX_TIMEOUT; 132e689cf4aSJeff Kirsher 133368e36edSDavid L Stevens dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE | 1349a72dd4dSDavid L Stevens NETIF_F_HW_CSUM | NETIF_F_SG; 135da38c564SDavid L Stevens dev->features = dev->hw_features; 136da38c564SDavid L Stevens 1374c5d283aSSowmini Varadhan SET_NETDEV_DEV(dev, &vdev->dev); 1384c5d283aSSowmini Varadhan 139e689cf4aSJeff Kirsher err = register_netdev(dev); 140e689cf4aSJeff Kirsher if (err) { 141e689cf4aSJeff Kirsher pr_err("Cannot register net device, aborting\n"); 142e689cf4aSJeff Kirsher goto err_out_free_dev; 143e689cf4aSJeff Kirsher } 144e689cf4aSJeff Kirsher 145e689cf4aSJeff Kirsher netdev_info(dev, "Sun LDOM vnet %pM\n", dev->dev_addr); 146e689cf4aSJeff Kirsher 147e689cf4aSJeff Kirsher list_add(&vp->list, &vnet_list); 148e689cf4aSJeff Kirsher 149e689cf4aSJeff Kirsher return vp; 150e689cf4aSJeff Kirsher 151e689cf4aSJeff Kirsher err_out_free_dev: 152e689cf4aSJeff Kirsher free_netdev(dev); 153e689cf4aSJeff Kirsher 154e689cf4aSJeff Kirsher return ERR_PTR(err); 155e689cf4aSJeff Kirsher } 156e689cf4aSJeff Kirsher 1574c5d283aSSowmini Varadhan static struct vnet *vnet_find_or_create(const u64 *local_mac, 1584c5d283aSSowmini Varadhan struct vio_dev *vdev) 159e689cf4aSJeff Kirsher { 160e689cf4aSJeff Kirsher struct vnet *iter, *vp; 161e689cf4aSJeff Kirsher 162e689cf4aSJeff Kirsher mutex_lock(&vnet_list_mutex); 163e689cf4aSJeff Kirsher vp = NULL; 164e689cf4aSJeff Kirsher list_for_each_entry(iter, &vnet_list, list) { 165e689cf4aSJeff Kirsher if (iter->local_mac == *local_mac) { 166e689cf4aSJeff Kirsher vp = iter; 167e689cf4aSJeff Kirsher break; 168e689cf4aSJeff Kirsher } 169e689cf4aSJeff Kirsher } 170e689cf4aSJeff Kirsher if (!vp) 1714c5d283aSSowmini Varadhan vp = vnet_new(local_mac, vdev); 172e689cf4aSJeff Kirsher mutex_unlock(&vnet_list_mutex); 173e689cf4aSJeff Kirsher 174e689cf4aSJeff Kirsher return vp; 175e689cf4aSJeff Kirsher } 176e689cf4aSJeff Kirsher 177a4b70a07SSowmini Varadhan static void vnet_cleanup(void) 178a4b70a07SSowmini Varadhan { 179a4b70a07SSowmini Varadhan struct vnet *vp; 180a4b70a07SSowmini Varadhan struct net_device *dev; 181a4b70a07SSowmini Varadhan 182a4b70a07SSowmini Varadhan mutex_lock(&vnet_list_mutex); 183a4b70a07SSowmini Varadhan while (!list_empty(&vnet_list)) { 184a4b70a07SSowmini Varadhan vp = list_first_entry(&vnet_list, struct vnet, list); 185a4b70a07SSowmini Varadhan list_del(&vp->list); 186a4b70a07SSowmini Varadhan dev = vp->dev; 187a4b70a07SSowmini Varadhan /* vio_unregister_driver() should have cleaned up port_list */ 188a4b70a07SSowmini Varadhan BUG_ON(!list_empty(&vp->port_list)); 189a4b70a07SSowmini Varadhan unregister_netdev(dev); 190a4b70a07SSowmini Varadhan free_netdev(dev); 191a4b70a07SSowmini Varadhan } 192a4b70a07SSowmini Varadhan mutex_unlock(&vnet_list_mutex); 193a4b70a07SSowmini Varadhan } 194a4b70a07SSowmini Varadhan 195e689cf4aSJeff Kirsher static const char *local_mac_prop = "local-mac-address"; 196e689cf4aSJeff Kirsher 197f73d12bdSBill Pemberton static struct vnet *vnet_find_parent(struct mdesc_handle *hp, 1984c5d283aSSowmini Varadhan u64 port_node, 1994c5d283aSSowmini Varadhan struct vio_dev *vdev) 200e689cf4aSJeff Kirsher { 201e689cf4aSJeff Kirsher const u64 *local_mac = NULL; 202e689cf4aSJeff Kirsher u64 a; 203e689cf4aSJeff Kirsher 204e689cf4aSJeff Kirsher mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) { 205e689cf4aSJeff Kirsher u64 target = mdesc_arc_target(hp, a); 206e689cf4aSJeff Kirsher const char *name; 207e689cf4aSJeff Kirsher 208e689cf4aSJeff Kirsher name = mdesc_get_property(hp, target, "name", NULL); 209e689cf4aSJeff Kirsher if (!name || strcmp(name, "network")) 210e689cf4aSJeff Kirsher continue; 211e689cf4aSJeff Kirsher 212e689cf4aSJeff Kirsher local_mac = mdesc_get_property(hp, target, 213e689cf4aSJeff Kirsher local_mac_prop, NULL); 214e689cf4aSJeff Kirsher if (local_mac) 215e689cf4aSJeff Kirsher break; 216e689cf4aSJeff Kirsher } 217e689cf4aSJeff Kirsher if (!local_mac) 218e689cf4aSJeff Kirsher return ERR_PTR(-ENODEV); 219e689cf4aSJeff Kirsher 2204c5d283aSSowmini Varadhan return vnet_find_or_create(local_mac, vdev); 221e689cf4aSJeff Kirsher } 222e689cf4aSJeff Kirsher 223e689cf4aSJeff Kirsher static struct ldc_channel_config vnet_ldc_cfg = { 224*31762eaaSAaron Young .event = sunvnet_event_common, 225e689cf4aSJeff Kirsher .mtu = 64, 226e689cf4aSJeff Kirsher .mode = LDC_MODE_UNRELIABLE, 227e689cf4aSJeff Kirsher }; 228e689cf4aSJeff Kirsher 229e689cf4aSJeff Kirsher static struct vio_driver_ops vnet_vio_ops = { 230*31762eaaSAaron Young .send_attr = sunvnet_send_attr_common, 231*31762eaaSAaron Young .handle_attr = sunvnet_handle_attr_common, 232*31762eaaSAaron Young .handshake_complete = sunvnet_handshake_complete_common, 233e689cf4aSJeff Kirsher }; 234e689cf4aSJeff Kirsher 235f73d12bdSBill Pemberton static void print_version(void) 236e689cf4aSJeff Kirsher { 237e689cf4aSJeff Kirsher printk_once(KERN_INFO "%s", version); 238e689cf4aSJeff Kirsher } 239e689cf4aSJeff Kirsher 240e689cf4aSJeff Kirsher const char *remote_macaddr_prop = "remote-mac-address"; 241e689cf4aSJeff Kirsher 2421dd06ae8SGreg Kroah-Hartman static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) 243e689cf4aSJeff Kirsher { 244e689cf4aSJeff Kirsher struct mdesc_handle *hp; 245e689cf4aSJeff Kirsher struct vnet_port *port; 246e689cf4aSJeff Kirsher unsigned long flags; 247e689cf4aSJeff Kirsher struct vnet *vp; 248e689cf4aSJeff Kirsher const u64 *rmac; 249e689cf4aSJeff Kirsher int len, i, err, switch_port; 250e689cf4aSJeff Kirsher 251e689cf4aSJeff Kirsher print_version(); 252e689cf4aSJeff Kirsher 253e689cf4aSJeff Kirsher hp = mdesc_grab(); 254e689cf4aSJeff Kirsher 2554c5d283aSSowmini Varadhan vp = vnet_find_parent(hp, vdev->mp, vdev); 256e689cf4aSJeff Kirsher if (IS_ERR(vp)) { 257e689cf4aSJeff Kirsher pr_err("Cannot find port parent vnet\n"); 258e689cf4aSJeff Kirsher err = PTR_ERR(vp); 259e689cf4aSJeff Kirsher goto err_out_put_mdesc; 260e689cf4aSJeff Kirsher } 261e689cf4aSJeff Kirsher 262e689cf4aSJeff Kirsher rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); 263e689cf4aSJeff Kirsher err = -ENODEV; 264e689cf4aSJeff Kirsher if (!rmac) { 265e689cf4aSJeff Kirsher pr_err("Port lacks %s property\n", remote_macaddr_prop); 266e689cf4aSJeff Kirsher goto err_out_put_mdesc; 267e689cf4aSJeff Kirsher } 268e689cf4aSJeff Kirsher 269e689cf4aSJeff Kirsher port = kzalloc(sizeof(*port), GFP_KERNEL); 270e689cf4aSJeff Kirsher err = -ENOMEM; 271e404decbSJoe Perches if (!port) 272e689cf4aSJeff Kirsher goto err_out_put_mdesc; 273e689cf4aSJeff Kirsher 274e689cf4aSJeff Kirsher for (i = 0; i < ETH_ALEN; i++) 275e689cf4aSJeff Kirsher port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff; 276e689cf4aSJeff Kirsher 277e689cf4aSJeff Kirsher port->vp = vp; 278e689cf4aSJeff Kirsher 279e689cf4aSJeff Kirsher err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK, 280e689cf4aSJeff Kirsher vnet_versions, ARRAY_SIZE(vnet_versions), 281e689cf4aSJeff Kirsher &vnet_vio_ops, vp->dev->name); 282e689cf4aSJeff Kirsher if (err) 283e689cf4aSJeff Kirsher goto err_out_free_port; 284e689cf4aSJeff Kirsher 285e689cf4aSJeff Kirsher err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port); 286e689cf4aSJeff Kirsher if (err) 287e689cf4aSJeff Kirsher goto err_out_free_port; 288e689cf4aSJeff Kirsher 289*31762eaaSAaron Young netif_napi_add(port->vp->dev, &port->napi, sunvnet_poll_common, 290*31762eaaSAaron Young NAPI_POLL_WEIGHT); 29169088822SSowmini Varadhan 292e689cf4aSJeff Kirsher INIT_HLIST_NODE(&port->hash); 293e689cf4aSJeff Kirsher INIT_LIST_HEAD(&port->list); 294e689cf4aSJeff Kirsher 295e689cf4aSJeff Kirsher switch_port = 0; 296e689cf4aSJeff Kirsher if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL) 297e689cf4aSJeff Kirsher switch_port = 1; 298e689cf4aSJeff Kirsher port->switch_port = switch_port; 299368e36edSDavid L Stevens port->tso = true; 300368e36edSDavid L Stevens port->tsolen = 0; 301e689cf4aSJeff Kirsher 302e689cf4aSJeff Kirsher spin_lock_irqsave(&vp->lock, flags); 303e689cf4aSJeff Kirsher if (switch_port) 3042a968dd8SSowmini Varadhan list_add_rcu(&port->list, &vp->port_list); 305e689cf4aSJeff Kirsher else 3062a968dd8SSowmini Varadhan list_add_tail_rcu(&port->list, &vp->port_list); 3072a968dd8SSowmini Varadhan hlist_add_head_rcu(&port->hash, 3082a968dd8SSowmini Varadhan &vp->port_hash[vnet_hashfn(port->raddr)]); 309*31762eaaSAaron Young sunvnet_port_add_txq_common(port); 310e689cf4aSJeff Kirsher spin_unlock_irqrestore(&vp->lock, flags); 311e689cf4aSJeff Kirsher 312e689cf4aSJeff Kirsher dev_set_drvdata(&vdev->dev, port); 313e689cf4aSJeff Kirsher 314e689cf4aSJeff Kirsher pr_info("%s: PORT ( remote-mac %pM%s )\n", 315e689cf4aSJeff Kirsher vp->dev->name, port->raddr, switch_port ? " switch-port" : ""); 316e689cf4aSJeff Kirsher 317*31762eaaSAaron Young setup_timer(&port->clean_timer, sunvnet_clean_timer_expire_common, 3188e845f4cSDavid L Stevens (unsigned long)port); 3198e845f4cSDavid L Stevens 32069088822SSowmini Varadhan napi_enable(&port->napi); 321e689cf4aSJeff Kirsher vio_port_up(&port->vio); 322e689cf4aSJeff Kirsher 323e689cf4aSJeff Kirsher mdesc_release(hp); 324e689cf4aSJeff Kirsher 325e689cf4aSJeff Kirsher return 0; 326e689cf4aSJeff Kirsher 327e689cf4aSJeff Kirsher err_out_free_port: 328e689cf4aSJeff Kirsher kfree(port); 329e689cf4aSJeff Kirsher 330e689cf4aSJeff Kirsher err_out_put_mdesc: 331e689cf4aSJeff Kirsher mdesc_release(hp); 332e689cf4aSJeff Kirsher return err; 333e689cf4aSJeff Kirsher } 334e689cf4aSJeff Kirsher 335e689cf4aSJeff Kirsher static int vnet_port_remove(struct vio_dev *vdev) 336e689cf4aSJeff Kirsher { 337e689cf4aSJeff Kirsher struct vnet_port *port = dev_get_drvdata(&vdev->dev); 338e689cf4aSJeff Kirsher 339e689cf4aSJeff Kirsher if (port) { 340e689cf4aSJeff Kirsher 341e689cf4aSJeff Kirsher del_timer_sync(&port->vio.timer); 342e689cf4aSJeff Kirsher 34369088822SSowmini Varadhan napi_disable(&port->napi); 344e689cf4aSJeff Kirsher 3452a968dd8SSowmini Varadhan list_del_rcu(&port->list); 3462a968dd8SSowmini Varadhan hlist_del_rcu(&port->hash); 3472a968dd8SSowmini Varadhan 3482a968dd8SSowmini Varadhan synchronize_rcu(); 3492a968dd8SSowmini Varadhan del_timer_sync(&port->clean_timer); 350*31762eaaSAaron Young sunvnet_port_rm_txq_common(port); 35169088822SSowmini Varadhan netif_napi_del(&port->napi); 352*31762eaaSAaron Young sunvnet_port_free_tx_bufs_common(port); 353e689cf4aSJeff Kirsher vio_ldc_free(&port->vio); 354e689cf4aSJeff Kirsher 355e689cf4aSJeff Kirsher dev_set_drvdata(&vdev->dev, NULL); 356e689cf4aSJeff Kirsher 357e689cf4aSJeff Kirsher kfree(port); 358aabb9875SDave Kleikamp 359e689cf4aSJeff Kirsher } 360e689cf4aSJeff Kirsher return 0; 361e689cf4aSJeff Kirsher } 362e689cf4aSJeff Kirsher 363e689cf4aSJeff Kirsher static const struct vio_device_id vnet_port_match[] = { 364e689cf4aSJeff Kirsher { 365e689cf4aSJeff Kirsher .type = "vnet-port", 366e689cf4aSJeff Kirsher }, 367e689cf4aSJeff Kirsher {}, 368e689cf4aSJeff Kirsher }; 369e689cf4aSJeff Kirsher MODULE_DEVICE_TABLE(vio, vnet_port_match); 370e689cf4aSJeff Kirsher 371e689cf4aSJeff Kirsher static struct vio_driver vnet_port_driver = { 372e689cf4aSJeff Kirsher .id_table = vnet_port_match, 373e689cf4aSJeff Kirsher .probe = vnet_port_probe, 374e689cf4aSJeff Kirsher .remove = vnet_port_remove, 375e689cf4aSJeff Kirsher .name = "vnet_port", 376e689cf4aSJeff Kirsher }; 377e689cf4aSJeff Kirsher 378e689cf4aSJeff Kirsher static int __init vnet_init(void) 379e689cf4aSJeff Kirsher { 380e689cf4aSJeff Kirsher return vio_register_driver(&vnet_port_driver); 381e689cf4aSJeff Kirsher } 382e689cf4aSJeff Kirsher 383e689cf4aSJeff Kirsher static void __exit vnet_exit(void) 384e689cf4aSJeff Kirsher { 385e689cf4aSJeff Kirsher vio_unregister_driver(&vnet_port_driver); 386a4b70a07SSowmini Varadhan vnet_cleanup(); 387e689cf4aSJeff Kirsher } 388e689cf4aSJeff Kirsher 389e689cf4aSJeff Kirsher module_init(vnet_init); 390e689cf4aSJeff Kirsher module_exit(vnet_exit); 391