Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Set vio->desc_buf to NULL after freeing.
  [SPARC]: Mark sparc and sparc64 as not having virt_to_bus
  [SPARC64]: Fix reset handling in VNET driver.
  [SPARC64]: Handle reset events in vio_link_state_change().
  [SPARC64]: Handle LDC resets properly in domain-services driver.
  [SPARC64]: Massively simplify VIO device layer and support hot add/remove.
  [SPARC64]: Simplify VNET probing.
  [SPARC64]: Simplify VDC device probing.
  [SPARC64]: Add basic infrastructure for MD add/remove notification.
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 73df711..603d83a 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -21,6 +21,9 @@
 	bool
 	default y
 
+config ARCH_NO_VIRT_TO_BUS
+	def_bool y
+
 source "init/Kconfig"
 
 menu "General machine setup"
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index b84b6af..df6ee71 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -62,6 +62,9 @@
 	bool
 	default y
 
+config ARCH_NO_VIRT_TO_BUS
+	def_bool y
+
 choice
 	prompt "Kernel page size"
 	default SPARC64_PAGE_SIZE_8KB
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index ba01533..fa1f04d 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -1013,6 +1013,19 @@
 		dp->hs_state = DS_HS_START;
 }
 
+static void ds_reset(struct ds_info *dp)
+{
+	int i;
+
+	dp->hs_state = 0;
+
+	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+		struct ds_cap_state *cp = &ds_states[i];
+
+		cp->state = CAP_STATE_UNKNOWN;
+	}
+}
+
 static void ds_event(void *arg, int event)
 {
 	struct ds_info *dp = arg;
@@ -1028,6 +1041,12 @@
 		return;
 	}
 
+	if (event == LDC_EVENT_RESET) {
+		ds_reset(dp);
+		spin_unlock_irqrestore(&ds_lock, flags);
+		return;
+	}
+
 	if (event != LDC_EVENT_DATA_READY) {
 		printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
 		spin_unlock_irqrestore(&ds_lock, flags);
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index de5310f..302ba5e 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -137,7 +137,7 @@
 		       sizeof(struct mdesc_hdr) +
 		       mdesc_size);
 
-	base = kmalloc(handle_size + 15, GFP_KERNEL);
+	base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
 	if (base) {
 		struct mdesc_handle *hp;
 		unsigned long addr;
@@ -214,18 +214,83 @@
 }
 EXPORT_SYMBOL(mdesc_release);
 
+static DEFINE_MUTEX(mdesc_mutex);
+static struct mdesc_notifier_client *client_list;
+
+void mdesc_register_notifier(struct mdesc_notifier_client *client)
+{
+	u64 node;
+
+	mutex_lock(&mdesc_mutex);
+	client->next = client_list;
+	client_list = client;
+
+	mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
+		client->add(cur_mdesc, node);
+
+	mutex_unlock(&mdesc_mutex);
+}
+
+/* Run 'func' on nodes which are in A but not in B.  */
+static void invoke_on_missing(const char *name,
+			      struct mdesc_handle *a,
+			      struct mdesc_handle *b,
+			      void (*func)(struct mdesc_handle *, u64))
+{
+	u64 node;
+
+	mdesc_for_each_node_by_name(a, node, name) {
+		const u64 *id = mdesc_get_property(a, node, "id", NULL);
+		int found = 0;
+		u64 fnode;
+
+		mdesc_for_each_node_by_name(b, fnode, name) {
+			const u64 *fid = mdesc_get_property(b, fnode,
+							    "id", NULL);
+
+			if (*id == *fid) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			func(a, node);
+	}
+}
+
+static void notify_one(struct mdesc_notifier_client *p,
+		       struct mdesc_handle *old_hp,
+		       struct mdesc_handle *new_hp)
+{
+	invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
+	invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
+}
+
+static void mdesc_notify_clients(struct mdesc_handle *old_hp,
+				 struct mdesc_handle *new_hp)
+{
+	struct mdesc_notifier_client *p = client_list;
+
+	while (p) {
+		notify_one(p, old_hp, new_hp);
+		p = p->next;
+	}
+}
+
 void mdesc_update(void)
 {
 	unsigned long len, real_len, status;
 	struct mdesc_handle *hp, *orig_hp;
 	unsigned long flags;
 
+	mutex_lock(&mdesc_mutex);
+
 	(void) sun4v_mach_desc(0UL, 0UL, &len);
 
 	hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
 	if (!hp) {
 		printk(KERN_ERR "MD: mdesc alloc fails\n");
-		return;
+		goto out;
 	}
 
 	status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
@@ -234,18 +299,25 @@
 		       status);
 		atomic_dec(&hp->refcnt);
 		mdesc_free(hp);
-		return;
+		goto out;
 	}
 
 	spin_lock_irqsave(&mdesc_lock, flags);
 	orig_hp = cur_mdesc;
 	cur_mdesc = hp;
+	spin_unlock_irqrestore(&mdesc_lock, flags);
 
+	mdesc_notify_clients(orig_hp, hp);
+
+	spin_lock_irqsave(&mdesc_lock, flags);
 	if (atomic_dec_and_test(&orig_hp->refcnt))
 		mdesc_free(orig_hp);
 	else
 		list_add(&orig_hp->list, &mdesc_zombie_list);
 	spin_unlock_irqrestore(&mdesc_lock, flags);
+
+out:
+	mutex_unlock(&mdesc_mutex);
 }
 
 static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 49569b4..8d3cc4f 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -201,10 +201,11 @@
 static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
 				      struct device *parent)
 {
-	const char *type, *compat;
+	const char *type, *compat, *bus_id_name;
 	struct device_node *dp;
 	struct vio_dev *vdev;
 	int err, tlen, clen;
+	const u64 *id;
 
 	type = mdesc_get_property(hp, mp, "device-type", &tlen);
 	if (!type) {
@@ -220,6 +221,16 @@
 		return NULL;
 	}
 
+	bus_id_name = type;
+	if (!strcmp(type, "domain-services-port"))
+		bus_id_name = "ds";
+
+	if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
+		printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
+		       bus_id_name);
+		return NULL;
+	}
+
 	compat = mdesc_get_property(hp, mp, "device-type", &clen);
 	if (!compat) {
 		clen = 0;
@@ -249,7 +260,14 @@
 
 	vio_fill_channel_info(hp, mp, vdev);
 
-	snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
+	id = mdesc_get_property(hp, mp, "id", NULL);
+	if (!id)
+		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
+			 bus_id_name);
+	else
+		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
+			 bus_id_name, *id);
+
 	vdev->dev.parent = parent;
 	vdev->dev.bus = &vio_bus_type;
 	vdev->dev.release = vio_dev_release;
@@ -269,6 +287,8 @@
 	}
 	vdev->dp = dp;
 
+	printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
+
 	err = device_register(&vdev->dev);
 	if (err) {
 		printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
@@ -283,45 +303,45 @@
 	return vdev;
 }
 
-static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
+static void vio_add(struct mdesc_handle *hp, u64 node)
 {
-	u64 a;
+	(void) vio_create_one(hp, node, &root_vdev->dev);
+}
 
-	mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
-		struct vio_dev *vdev;
-		u64 target;
+static int vio_md_node_match(struct device *dev, void *arg)
+{
+	struct vio_dev *vdev = to_vio_dev(dev);
 
-		target = mdesc_arc_target(hp, a);
-		vdev = vio_create_one(hp, target, &parent->dev);
-		if (vdev)
-			walk_tree(hp, target, vdev);
+	if (vdev->mp == (u64) arg)
+		return 1;
+
+	return 0;
+}
+
+static void vio_remove(struct mdesc_handle *hp, u64 node)
+{
+	struct device *dev;
+
+	dev = device_find_child(&root_vdev->dev, (void *) node,
+				vio_md_node_match);
+	if (dev) {
+		printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
+
+		device_unregister(dev);
 	}
 }
 
-static void create_devices(struct mdesc_handle *hp, u64 root)
-{
-	u64 mp;
+static struct mdesc_notifier_client vio_device_notifier = {
+	.add		= vio_add,
+	.remove		= vio_remove,
+	.node_name	= "virtual-device-port",
+};
 
-	root_vdev = vio_create_one(hp, root, NULL);
-	if (!root_vdev) {
-		printk(KERN_ERR "VIO: Coult not create root device.\n");
-		return;
-	}
-
-	walk_tree(hp, root, root_vdev);
-
-	/* Domain services is odd as it doesn't sit underneath the
-	 * channel-devices node, so we plug it in manually.
-	 */
-	mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
-	if (mp != MDESC_NODE_NULL) {
-		struct vio_dev *parent = vio_create_one(hp, mp,
-							&root_vdev->dev);
-
-		if (parent)
-			walk_tree(hp, mp, parent);
-	}
-}
+static struct mdesc_notifier_client vio_ds_notifier = {
+	.add		= vio_add,
+	.remove		= vio_remove,
+	.node_name	= "domain-services-port",
+};
 
 const char *channel_devices_node = "channel-devices";
 const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
@@ -381,11 +401,19 @@
 
 	cdev_cfg_handle = *cfg_handle;
 
-	create_devices(hp, root);
+	root_vdev = vio_create_one(hp, root, NULL);
+	err = -ENODEV;
+	if (!root_vdev) {
+		printk(KERN_ERR "VIO: Coult not create root device.\n");
+		goto out_release;
+	}
+
+	mdesc_register_notifier(&vio_device_notifier);
+	mdesc_register_notifier(&vio_ds_notifier);
 
 	mdesc_release(hp);
 
-	return 0;
+	return err;
 
 out_release:
 	mdesc_release(hp);
diff --git a/arch/sparc64/kernel/viohs.c b/arch/sparc64/kernel/viohs.c
index 15613ad..09126fc 100644
--- a/arch/sparc64/kernel/viohs.c
+++ b/arch/sparc64/kernel/viohs.c
@@ -78,6 +78,24 @@
 	return 0;
 }
 
+static void flush_rx_dring(struct vio_driver_state *vio)
+{
+	struct vio_dring_state *dr;
+	u64 ident;
+
+	BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
+
+	dr = &vio->drings[VIO_DRIVER_RX_RING];
+	ident = dr->ident;
+
+	BUG_ON(!vio->desc_buf);
+	kfree(vio->desc_buf);
+	vio->desc_buf = NULL;
+
+	memset(dr, 0, sizeof(*dr));
+	dr->ident = ident;
+}
+
 void vio_link_state_change(struct vio_driver_state *vio, int event)
 {
 	if (event == LDC_EVENT_UP) {
@@ -98,6 +116,16 @@
 			break;
 		}
 		start_handshake(vio);
+	} else if (event == LDC_EVENT_RESET) {
+		vio->hs_state = VIO_HS_INVALID;
+
+		if (vio->dr_state & VIO_DR_STATE_RXREG)
+			flush_rx_dring(vio);
+
+		vio->dr_state = 0x00;
+		memset(&vio->ver, 0, sizeof(vio->ver));
+
+		ldc_disconnect(vio->lp);
 	}
 }
 EXPORT_SYMBOL(vio_link_state_change);
@@ -396,6 +424,8 @@
 	if (vio->dr_state & VIO_DR_STATE_RXREG)
 		goto send_nack;
 
+	BUG_ON(vio->desc_buf);
+
 	vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
 	if (!vio->desc_buf)
 		goto send_nack;
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 0f5e3ca..2288b55 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -45,8 +45,6 @@
 struct vdc_port {
 	struct vio_driver_state	vio;
 
-	struct vdc		*vp;
-
 	struct gendisk		*disk;
 
 	struct vdc_completion	*cmp;
@@ -72,8 +70,6 @@
 
 	struct vio_disk_geom	geom;
 	struct vio_disk_vtoc	label;
-
-	struct list_head	list;
 };
 
 static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
@@ -81,15 +77,6 @@
 	return container_of(vio, struct vdc_port, vio);
 }
 
-struct vdc {
-	/* Protects prot_list.  */
-	spinlock_t		lock;
-
-	struct vio_dev		*dev;
-
-	struct list_head	port_list;
-};
-
 /* Ordered from largest major to lowest */
 static struct vio_version vdc_versions[] = {
 	{ .major = 1, .minor = 0 },
@@ -747,21 +734,23 @@
 	.handshake_complete	= vdc_handshake_complete,
 };
 
+static void print_version(void)
+{
+	static int version_printed;
+
+	if (version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+}
+
 static int __devinit vdc_port_probe(struct vio_dev *vdev,
 				    const struct vio_device_id *id)
 {
 	struct mdesc_handle *hp;
 	struct vdc_port *port;
-	unsigned long flags;
-	struct vdc *vp;
 	const u64 *port_id;
 	int err;
 
-	vp = dev_get_drvdata(vdev->dev.parent);
-	if (!vp) {
-		printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
-		return -ENODEV;
-	}
+	print_version();
 
 	hp = mdesc_grab();
 
@@ -783,7 +772,6 @@
 		goto err_out_release_mdesc;
 	}
 
-	port->vp = vp;
 	port->dev_no = *port_id;
 
 	if (port->dev_no >= 26)
@@ -818,12 +806,6 @@
 	if (err)
 		goto err_out_free_tx_ring;
 
-	INIT_LIST_HEAD(&port->list);
-
-	spin_lock_irqsave(&vp->lock, flags);
-	list_add(&port->list, &vp->port_list);
-	spin_unlock_irqrestore(&vp->lock, flags);
-
 	dev_set_drvdata(&vdev->dev, port);
 
 	mdesc_release(hp);
@@ -879,58 +861,6 @@
 	}
 };
 
-static int __devinit vdc_probe(struct vio_dev *vdev,
-			       const struct vio_device_id *id)
-{
-	static int vdc_version_printed;
-	struct vdc *vp;
-
-	if (vdc_version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-
-	vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
-	if (!vp)
-		return -ENOMEM;
-
-	spin_lock_init(&vp->lock);
-	vp->dev = vdev;
-	INIT_LIST_HEAD(&vp->port_list);
-
-	dev_set_drvdata(&vdev->dev, vp);
-
-	return 0;
-}
-
-static int vdc_remove(struct vio_dev *vdev)
-{
-
-	struct vdc *vp = dev_get_drvdata(&vdev->dev);
-
-	if (vp) {
-		kfree(vp);
-		dev_set_drvdata(&vdev->dev, NULL);
-	}
-	return 0;
-}
-
-static struct vio_device_id vdc_match[] = {
-	{
-		.type = "block",
-	},
-	{},
-};
-MODULE_DEVICE_TABLE(vio, vdc_match);
-
-static struct vio_driver vdc_driver = {
-	.id_table	= vdc_match,
-	.probe		= vdc_probe,
-	.remove		= vdc_remove,
-	.driver		= {
-		.name	= "vdc",
-		.owner	= THIS_MODULE,
-	}
-};
-
 static int __init vdc_init(void)
 {
 	int err;
@@ -940,19 +870,13 @@
 		goto out_err;
 
 	vdc_major = err;
-	err = vio_register_driver(&vdc_driver);
-	if (err)
-		goto out_unregister_blkdev;
 
 	err = vio_register_driver(&vdc_port_driver);
 	if (err)
-		goto out_unregister_vdc;
+		goto out_unregister_blkdev;
 
 	return 0;
 
-out_unregister_vdc:
-	vio_unregister_driver(&vdc_driver);
-
 out_unregister_blkdev:
 	unregister_blkdev(vdc_major, VDCBLK_NAME);
 	vdc_major = 0;
@@ -964,7 +888,6 @@
 static void __exit vdc_exit(void)
 {
 	vio_unregister_driver(&vdc_port_driver);
-	vio_unregister_driver(&vdc_driver);
 	unregister_blkdev(vdc_major, VDCBLK_NAME);
 }
 
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 8a667c1..b801e3b 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
+#include <linux/mutex.h>
 
 #include <asm/vio.h>
 #include <asm/ldc.h>
@@ -497,6 +498,8 @@
 		vio_link_state_change(vio, event);
 		spin_unlock_irqrestore(&vio->lock, flags);
 
+		if (event == LDC_EVENT_RESET)
+			vio_port_up(vio);
 		return;
 	}
 
@@ -875,6 +878,115 @@
 	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 = {
 	.event		= vnet_event,
 	.mtu		= 64,
@@ -887,6 +999,14 @@
 	.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";
 
 static int __devinit vnet_port_probe(struct vio_dev *vdev,
@@ -899,14 +1019,17 @@
 	const u64 *rmac;
 	int len, i, err, switch_port;
 
-	vp = dev_get_drvdata(vdev->dev.parent);
-	if (!vp) {
-		printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
-		return -ENODEV;
-	}
+	print_version();
 
 	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);
 	err = -ENODEV;
 	if (!rmac) {
@@ -1025,139 +1148,14 @@
 	}
 };
 
-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)
 {
-	int err = vio_register_driver(&vnet_driver);
-
-	if (!err) {
-		err = vio_register_driver(&vnet_port_driver);
-		if (err)
-			vio_unregister_driver(&vnet_driver);
-	}
-
-	return err;
+	return vio_register_driver(&vnet_port_driver);
 }
 
 static void __exit vnet_exit(void)
 {
 	vio_unregister_driver(&vnet_port_driver);
-	vio_unregister_driver(&vnet_driver);
 }
 
 module_init(vnet_init);
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
index 1c88730..7d3a0ca 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/sunvnet.h
@@ -60,11 +60,13 @@
 	struct net_device	*dev;
 
 	u32			msg_enable;
-	struct vio_dev		*vdev;
 
 	struct list_head	port_list;
 
 	struct hlist_head	port_hash[VNET_PORT_HASH_SIZE];
+
+	struct list_head	list;
+	u64			local_mac;
 };
 
 #endif /* _SUNVNET_H */
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index ad595b6..9565a89 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -14,11 +14,6 @@
 #define __SLOW_DOWN_IO	do { } while (0)
 #define SLOW_DOWN_IO	do { } while (0)
 
-extern unsigned long virt_to_bus_not_defined_use_pci_map(volatile void *addr);
-#define virt_to_bus virt_to_bus_not_defined_use_pci_map
-extern unsigned long bus_to_virt_not_defined_use_pci_map(volatile void *addr);
-#define bus_to_virt bus_to_virt_not_defined_use_pci_map
-
 /* BIO layer definitions. */
 extern unsigned long kern_base, kern_size;
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
diff --git a/include/asm-sparc64/mdesc.h b/include/asm-sparc64/mdesc.h
index e97c431..1acc727 100644
--- a/include/asm-sparc64/mdesc.h
+++ b/include/asm-sparc64/mdesc.h
@@ -61,6 +61,16 @@
 
 extern void mdesc_update(void);
 
+struct mdesc_notifier_client {
+	void (*add)(struct mdesc_handle *handle, u64 node);
+	void (*remove)(struct mdesc_handle *handle, u64 node);
+
+	const char			*node_name;
+	struct mdesc_notifier_client	*next;
+};
+
+extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
+
 extern void mdesc_fill_in_cpu_data(cpumask_t mask);
 
 extern void sun4v_mdesc_init(void);
diff --git a/include/asm-sparc64/vio.h b/include/asm-sparc64/vio.h
index 83c9642..c0a8d4e 100644
--- a/include/asm-sparc64/vio.h
+++ b/include/asm-sparc64/vio.h
@@ -264,7 +264,7 @@
 		((dr->prod - dr->cons) & (ring_size - 1)));
 }
 
-#define VIO_MAX_TYPE_LEN	64
+#define VIO_MAX_TYPE_LEN	32
 #define VIO_MAX_COMPAT_LEN	64
 
 struct vio_dev {