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