[SPARC64]: Simplify VNET probing.

Only probe on the vdc-port VIO devices, create parent
vnet objects on-demand.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2007-07-17 22:19:10 -07:00
parent 80dc35dfb9
commit 9184a04632
2 changed files with 130 additions and 132 deletions

View File

@ -12,6 +12,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/mutex.h>
#include <asm/vio.h> #include <asm/vio.h>
#include <asm/ldc.h> #include <asm/ldc.h>
@ -875,6 +876,115 @@ static int __devinit vnet_port_alloc_tx_bufs(struct vnet_port *port)
return err; return err;
} }
static LIST_HEAD(vnet_list);
static DEFINE_MUTEX(vnet_list_mutex);
static struct vnet * __devinit vnet_new(const u64 *local_mac)
{
struct net_device *dev;
struct vnet *vp;
int err, i;
dev = alloc_etherdev(sizeof(*vp));
if (!dev) {
printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
return ERR_PTR(-ENOMEM);
}
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
vp = netdev_priv(dev);
spin_lock_init(&vp->lock);
vp->dev = dev;
INIT_LIST_HEAD(&vp->port_list);
for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
INIT_HLIST_HEAD(&vp->port_hash[i]);
INIT_LIST_HEAD(&vp->list);
vp->local_mac = *local_mac;
dev->open = vnet_open;
dev->stop = vnet_close;
dev->set_multicast_list = vnet_set_rx_mode;
dev->set_mac_address = vnet_set_mac_addr;
dev->tx_timeout = vnet_tx_timeout;
dev->ethtool_ops = &vnet_ethtool_ops;
dev->watchdog_timeo = VNET_TX_TIMEOUT;
dev->change_mtu = vnet_change_mtu;
dev->hard_start_xmit = vnet_start_xmit;
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
"aborting.\n");
goto err_out_free_dev;
}
printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
list_add(&vp->list, &vnet_list);
return vp;
err_out_free_dev:
free_netdev(dev);
return ERR_PTR(err);
}
static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
{
struct vnet *iter, *vp;
mutex_lock(&vnet_list_mutex);
vp = NULL;
list_for_each_entry(iter, &vnet_list, list) {
if (iter->local_mac == *local_mac) {
vp = iter;
break;
}
}
if (!vp)
vp = vnet_new(local_mac);
mutex_unlock(&vnet_list_mutex);
return vp;
}
static const char *local_mac_prop = "local-mac-address";
static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
u64 port_node)
{
const u64 *local_mac = NULL;
u64 a;
mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
u64 target = mdesc_arc_target(hp, a);
const char *name;
name = mdesc_get_property(hp, target, "name", NULL);
if (!name || strcmp(name, "network"))
continue;
local_mac = mdesc_get_property(hp, target,
local_mac_prop, NULL);
if (local_mac)
break;
}
if (!local_mac)
return ERR_PTR(-ENODEV);
return vnet_find_or_create(local_mac);
}
static struct ldc_channel_config vnet_ldc_cfg = { static struct ldc_channel_config vnet_ldc_cfg = {
.event = vnet_event, .event = vnet_event,
.mtu = 64, .mtu = 64,
@ -887,6 +997,14 @@ static struct vio_driver_ops vnet_vio_ops = {
.handshake_complete = vnet_handshake_complete, .handshake_complete = vnet_handshake_complete,
}; };
static void print_version(void)
{
static int version_printed;
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
}
const char *remote_macaddr_prop = "remote-mac-address"; const char *remote_macaddr_prop = "remote-mac-address";
static int __devinit vnet_port_probe(struct vio_dev *vdev, static int __devinit vnet_port_probe(struct vio_dev *vdev,
@ -899,14 +1017,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
const u64 *rmac; const u64 *rmac;
int len, i, err, switch_port; int len, i, err, switch_port;
vp = dev_get_drvdata(vdev->dev.parent); print_version();
if (!vp) {
printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
return -ENODEV;
}
hp = mdesc_grab(); hp = mdesc_grab();
vp = vnet_find_parent(hp, vdev->mp);
if (IS_ERR(vp)) {
printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
err = PTR_ERR(vp);
goto err_out_put_mdesc;
}
rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
err = -ENODEV; err = -ENODEV;
if (!rmac) { if (!rmac) {
@ -1025,139 +1146,14 @@ static struct vio_driver vnet_port_driver = {
} }
}; };
const char *local_mac_prop = "local-mac-address";
static int __devinit vnet_probe(struct vio_dev *vdev,
const struct vio_device_id *id)
{
static int vnet_version_printed;
struct mdesc_handle *hp;
struct net_device *dev;
struct vnet *vp;
const u64 *mac;
int err, i, len;
if (vnet_version_printed++ == 0)
printk(KERN_INFO "%s", version);
hp = mdesc_grab();
mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
if (!mac) {
printk(KERN_ERR PFX "vnet lacks %s property.\n",
local_mac_prop);
err = -ENODEV;
goto err_out;
}
dev = alloc_etherdev(sizeof(*vp));
if (!dev) {
printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out;
}
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
SET_NETDEV_DEV(dev, &vdev->dev);
vp = netdev_priv(dev);
spin_lock_init(&vp->lock);
vp->dev = dev;
vp->vdev = vdev;
INIT_LIST_HEAD(&vp->port_list);
for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
INIT_HLIST_HEAD(&vp->port_hash[i]);
dev->open = vnet_open;
dev->stop = vnet_close;
dev->set_multicast_list = vnet_set_rx_mode;
dev->set_mac_address = vnet_set_mac_addr;
dev->tx_timeout = vnet_tx_timeout;
dev->ethtool_ops = &vnet_ethtool_ops;
dev->watchdog_timeo = VNET_TX_TIMEOUT;
dev->change_mtu = vnet_change_mtu;
dev->hard_start_xmit = vnet_start_xmit;
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
"aborting.\n");
goto err_out_free_dev;
}
printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
dev_set_drvdata(&vdev->dev, vp);
mdesc_release(hp);
return 0;
err_out_free_dev:
free_netdev(dev);
err_out:
mdesc_release(hp);
return err;
}
static int vnet_remove(struct vio_dev *vdev)
{
struct vnet *vp = dev_get_drvdata(&vdev->dev);
if (vp) {
/* XXX unregister port, or at least check XXX */
unregister_netdevice(vp->dev);
dev_set_drvdata(&vdev->dev, NULL);
}
return 0;
}
static struct vio_device_id vnet_match[] = {
{
.type = "network",
},
{},
};
MODULE_DEVICE_TABLE(vio, vnet_match);
static struct vio_driver vnet_driver = {
.id_table = vnet_match,
.probe = vnet_probe,
.remove = vnet_remove,
.driver = {
.name = "vnet",
.owner = THIS_MODULE,
}
};
static int __init vnet_init(void) static int __init vnet_init(void)
{ {
int err = vio_register_driver(&vnet_driver); return vio_register_driver(&vnet_port_driver);
if (!err) {
err = vio_register_driver(&vnet_port_driver);
if (err)
vio_unregister_driver(&vnet_driver);
}
return err;
} }
static void __exit vnet_exit(void) static void __exit vnet_exit(void)
{ {
vio_unregister_driver(&vnet_port_driver); vio_unregister_driver(&vnet_port_driver);
vio_unregister_driver(&vnet_driver);
} }
module_init(vnet_init); module_init(vnet_init);

View File

@ -60,11 +60,13 @@ struct vnet {
struct net_device *dev; struct net_device *dev;
u32 msg_enable; u32 msg_enable;
struct vio_dev *vdev;
struct list_head port_list; struct list_head port_list;
struct hlist_head port_hash[VNET_PORT_HASH_SIZE]; struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
struct list_head list;
u64 local_mac;
}; };
#endif /* _SUNVNET_H */ #endif /* _SUNVNET_H */