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]: fix section mismatch warning in mdesc.c
  [SPARC64]: fix section mismatch warning in pci_sunv4
  [SPARC64]: Stop using drivers/char/rtc.c
  [SPARC64]: Convert parport to of_platform_driver.
  [SPARC]: Implement fb_is_primary_device().
  [SPARC64]: Fix virq decomposition.
  [SPARC64]: Use KERN_ERR in IRQ manipulation error printks.
  [SPARC64]: Do not flood log with failed DS messages.
  [SPARC64]: Add proper multicast support to VNET driver.
  [SPARC64]: Handle multiple domain-services-port nodes properly.
  [SPARC64]: Improve VIO device naming further.
  [SPARC]: Make sure dev_archdata is filled in for all devices.
  [SPARC]: Define minimal struct dev_archdata, similarly to sparc64.
  [SPARC]: Fix serial console device detection.
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index 7bb86b9c..ac352eb 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -148,6 +148,7 @@
 {
 	const struct linux_prom_registers *regs;
 	struct linux_ebus_child *child;
+	struct dev_archdata *sd;
 	const int *irqs;
 	int i, n, len;
 	unsigned long baseaddr;
@@ -234,6 +235,10 @@
 		}
 	}
 
+	sd = &dev->ofdev.dev.archdata;
+	sd->prom_node = dp;
+	sd->op = &dev->ofdev;
+
 	dev->ofdev.node = dp;
 	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
 	dev->ofdev.dev.bus = &ebus_bus_type;
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 7176040..36383f7 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -420,11 +420,16 @@
 {
 	struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
 	const struct linux_prom_irqs *intr;
+	struct dev_archdata *sd;
 	int len, i;
 
 	if (!op)
 		return NULL;
 
+	sd = &op->dev.archdata;
+	sd->prom_node = dp;
+	sd->op = op;
+
 	op->node = dp;
 
 	op->clock_freq = of_getintprop_default(dp, "clock-frequency",
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 8c37f8f..33f7a3d 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -39,6 +39,7 @@
 #include <asm/processor.h>
 #include <asm/psr.h>
 #include <asm/elf.h>
+#include <asm/prom.h>
 #include <asm/unistd.h>
 
 /* 
@@ -150,7 +151,7 @@
 	local_irq_enable();
 	mdelay(8);
 	local_irq_disable();
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	prom_halt();
 	panic("Halt failed!");
@@ -166,7 +167,7 @@
 
 	p = strchr (reboot_command, '\n');
 	if (p) *p = 0;
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	if (cmd)
 		prom_reboot(cmd);
@@ -179,7 +180,8 @@
 void machine_power_off(void)
 {
 #ifdef CONFIG_SUN_AUXIO
-	if (auxio_power_register && (!serial_console || scons_pwroff))
+	if (auxio_power_register &&
+	    (strcmp(of_console_device->type, "serial") || scons_pwroff))
 		*auxio_power_register |= AUXIO_POWER_OFF;
 #endif
 	machine_halt();
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index 012f983..e3a5376 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -397,6 +397,135 @@
 	return dp;
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+extern void restore_current(void);
+
+static void __init of_console_init(void)
+{
+	char *msg = "OF stdout device is: %s\n";
+	struct device_node *dp;
+	unsigned long flags;
+	const char *type;
+	phandle node;
+	int skip, fd;
+
+	of_console_path = prom_early_alloc(256);
+
+	switch (prom_vers) {
+	case PROM_V0:
+	case PROM_SUN4:
+		skip = 0;
+		switch (*romvec->pv_stdout) {
+		case PROMDEV_SCREEN:
+			type = "display";
+			break;
+
+		case PROMDEV_TTYB:
+			skip = 1;
+			/* FALLTHRU */
+
+		case PROMDEV_TTYA:
+			type = "serial";
+			break;
+
+		default:
+			prom_printf("Invalid PROM_V0 stdout value %u\n",
+				    *romvec->pv_stdout);
+			prom_halt();
+		}
+
+		for_each_node_by_type(dp, type) {
+			if (!skip--)
+				break;
+		}
+		if (!dp) {
+			prom_printf("Cannot find PROM_V0 console node.\n");
+			prom_halt();
+		}
+		of_console_device = dp;
+
+		strcpy(of_console_path, dp->full_name);
+		if (!strcmp(type, "serial")) {
+			strcat(of_console_path,
+			       (skip ? ":b" : ":a"));
+		}
+		break;
+
+	default:
+	case PROM_V2:
+	case PROM_V3:
+		fd = *romvec->pv_v2bootargs.fd_stdout;
+
+		spin_lock_irqsave(&prom_lock, flags);
+		node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
+		restore_current();
+		spin_unlock_irqrestore(&prom_lock, flags);
+
+		if (!node) {
+			prom_printf("Cannot resolve stdout node from "
+				    "instance %08x.\n", fd);
+			prom_halt();
+		}
+		dp = of_find_node_by_phandle(node);
+		type = of_get_property(dp, "device_type", NULL);
+
+		if (!type) {
+			prom_printf("Console stdout lacks "
+				    "device_type property.\n");
+			prom_halt();
+		}
+
+		if (strcmp(type, "display") && strcmp(type, "serial")) {
+			prom_printf("Console device_type is neither display "
+				    "nor serial.\n");
+			prom_halt();
+		}
+
+		of_console_device = dp;
+
+		if (prom_vers == PROM_V2) {
+			strcpy(of_console_path, dp->full_name);
+			switch (*romvec->pv_stdout) {
+			case PROMDEV_TTYA:
+				strcat(of_console_path, ":a");
+				break;
+			case PROMDEV_TTYB:
+				strcat(of_console_path, ":b");
+				break;
+			}
+		} else {
+			const char *path;
+
+			dp = of_find_node_by_path("/");
+			path = of_get_property(dp, "stdout-path", NULL);
+			if (!path) {
+				prom_printf("No stdout-path in root node.\n");
+				prom_halt();
+			}
+			strcpy(of_console_path, path);
+		}
+		break;
+	}
+
+	of_console_options = strrchr(of_console_path, ':');
+	if (of_console_options) {
+		of_console_options++;
+		if (*of_console_options == '\0')
+			of_console_options = NULL;
+	}
+
+	prom_printf(msg, of_console_path);
+	printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
 	struct device_node **nextp;
@@ -409,6 +538,8 @@
 	allnodes->child = build_tree(allnodes,
 				     prom_getchild(allnodes->node),
 				     &nextp);
+	of_console_init();
+
 	printk("PROM: Built device tree with %u bytes of memory.\n",
 	       prom_early_allocated);
 }
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 64c0ed9..f822838 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -146,31 +146,6 @@
 	}
 }
 
-static void __init process_console(char *commands)
-{
-	serial_console = 0;
-	commands += 8;
-	/* Linux-style serial */
-	if (!strncmp(commands, "ttyS", 4))
-		serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-	else if (!strncmp(commands, "tty", 3)) {
-		char c = *(commands + 3);
-		/* Solaris-style serial */
-		if (c == 'a' || c == 'b')
-			serial_console = c - 'a' + 1;
-		/* else Linux-style fbcon, not serial */
-	}
-#if defined(CONFIG_PROM_CONSOLE)
-	if (!strncmp(commands, "prom", 4)) {
-		char *p;
-
-		for (p = commands - 8; *p && *p != ' '; p++)
-			*p = ' ';
-		conswitchp = &prom_con;
-	}
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
 	while (*commands) {
@@ -187,9 +162,7 @@
 				process_switch(*commands++);
 			continue;
 		}
-		if (!strncmp(commands, "console=", 8)) {
-			process_console(commands);
-		} else if (!strncmp(commands, "mem=", 4)) {
+		if (!strncmp(commands, "mem=", 4)) {
 			/*
 			 * "mem=XXX[kKmM] overrides the PROM-reported
 			 * memory size.
@@ -341,41 +314,6 @@
 	smp_setup_cpu_possible_map();
 }
 
-static int __init set_preferred_console(void)
-{
-	int idev, odev;
-
-	/* The user has requested a console so this is already set up. */
-	if (serial_console >= 0)
-		return -EBUSY;
-
-	idev = prom_query_input_device();
-	odev = prom_query_output_device();
-	if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-		serial_console = 0;
-	} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-		serial_console = 1;
-	} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-		serial_console = 2;
-	} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
-		prom_printf("MrCoffee ttya\n");
-		serial_console = 1;
-	} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
-		serial_console = 0;
-		prom_printf("MrCoffee keyboard\n");
-	} else {
-		prom_printf("Confusing console (idev %d, odev %d)\n",
-		    idev, odev);
-		serial_console = 1;
-	}
-
-	if (serial_console)
-		return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-	return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 extern char *sparc_cpu_type;
 extern char *sparc_fpu_type;
 
@@ -461,7 +399,6 @@
 	prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
 
 static int __init topology_init(void)
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 4e6e41d..8d1cfb0 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -102,119 +102,3 @@
 	while(prom_nbputchar(c) == -1) ;
 	return;
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-	unsigned long flags;
-	int st_p;
-	char propb[64];
-	char *p;
-	int propl;
-
-	switch(prom_vers) {
-	case PROM_V0:
-	case PROM_V2:
-	case PROM_SUN4:
-	default:
-		switch(*romvec->pv_stdin) {
-		case PROMDEV_KBD:	return PROMDEV_IKBD;
-		case PROMDEV_TTYA:	return PROMDEV_ITTYA;
-		case PROMDEV_TTYB:	return PROMDEV_ITTYB;
-		default:
-			return PROMDEV_I_UNK;
-		};
-	case PROM_V3:
-		spin_lock_irqsave(&prom_lock, flags);
-		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
-		restore_current();
-		spin_unlock_irqrestore(&prom_lock, flags);
-		if(prom_node_has_property(st_p, "keyboard"))
-			return PROMDEV_IKBD;
-		if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
-			if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
-				return PROMDEV_IKBD;
-		}
-		if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
-		if(strncmp(propb, "serial", sizeof("serial")))
-			return PROMDEV_I_UNK;
-		}
-		propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
-		if(propl > 2) {
-			p = propb;
-			while(*p) p++; p -= 2;
-			if(p[0] == ':') {
-				if(p[1] == 'a')
-					return PROMDEV_ITTYA;
-				else if(p[1] == 'b')
-					return PROMDEV_ITTYB;
-			}
-		}
-		return PROMDEV_I_UNK;
-	}
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-	unsigned long flags;
-	int st_p;
-	char propb[64];
-	char *p;
-	int propl;
-
-	switch(prom_vers) {
-	case PROM_V0:
-	case PROM_SUN4:
-		switch(*romvec->pv_stdin) {
-		case PROMDEV_SCREEN:	return PROMDEV_OSCREEN;
-		case PROMDEV_TTYA:	return PROMDEV_OTTYA;
-		case PROMDEV_TTYB:	return PROMDEV_OTTYB;
-		};
-		break;
-	case PROM_V2:
-	case PROM_V3:
-		spin_lock_irqsave(&prom_lock, flags);
-		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
-		restore_current();
-		spin_unlock_irqrestore(&prom_lock, flags);
-		propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-		if (propl == sizeof("display") &&
-			strncmp("display", propb, sizeof("display")) == 0)
-		{
-			return PROMDEV_OSCREEN;
-		}
-		if(prom_vers == PROM_V3) {
-			if(propl >= 0 &&
-			    strncmp("serial", propb, sizeof("serial")) != 0)
-				return PROMDEV_O_UNK;
-			propl = prom_getproperty(prom_root_node, "stdout-path",
-						 propb, sizeof(propb));
-			if(propl == CON_SIZE_JMC &&
-			    strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
-				return PROMDEV_OTTYA;
-			if(propl > 2) {
-				p = propb;
-				while(*p) p++; p-= 2;
-				if(p[0]==':') {
-					if(p[1] == 'a')
-						return PROMDEV_OTTYA;
-					else if(p[1] == 'b')
-						return PROMDEV_OTTYB;
-				}
-			}
-		} else {
-			switch(*romvec->pv_stdin) {
-			case PROMDEV_TTYA:	return PROMDEV_OTTYA;
-			case PROMDEV_TTYB:	return PROMDEV_OTTYB;
-			};
-		}
-		break;
-	default:
-		;
-	};
-	return PROMDEV_O_UNK;
-}
diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c
index 1942c7c..37cff5f 100644
--- a/arch/sparc/prom/misc.c
+++ b/arch/sparc/prom/misc.c
@@ -58,7 +58,7 @@
 	extern void install_linux_ticker(void);
 	unsigned long flags;
 
-	if(!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	spin_lock_irqsave(&prom_lock, flags);
 	install_obp_ticker();
@@ -69,7 +69,7 @@
 #ifdef CONFIG_SUN_AUXIO
 	set_auxio(AUXIO_LED, 0);
 #endif
-	if(!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (0);
 }
 
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index 1a2062e..9f472a7 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -124,10 +124,11 @@
 	__u64			result;
 };
 
+struct ds_info;
 struct ds_cap_state {
 	__u64			handle;
 
-	void			(*data)(struct ldc_channel *lp,
+	void			(*data)(struct ds_info *dp,
 					struct ds_cap_state *cp,
 					void *buf, int len);
 
@@ -139,27 +140,27 @@
 #define CAP_STATE_REGISTERED	0x02
 };
 
-static void md_update_data(struct ldc_channel *lp, struct ds_cap_state *cp,
+static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
 			   void *buf, int len);
-static void domain_shutdown_data(struct ldc_channel *lp,
+static void domain_shutdown_data(struct ds_info *dp,
 				 struct ds_cap_state *cp,
 				 void *buf, int len);
-static void domain_panic_data(struct ldc_channel *lp,
+static void domain_panic_data(struct ds_info *dp,
 			      struct ds_cap_state *cp,
 			      void *buf, int len);
 #ifdef CONFIG_HOTPLUG_CPU
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len);
 #endif
-static void ds_pri_data(struct ldc_channel *lp,
+static void ds_pri_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len);
-static void ds_var_data(struct ldc_channel *lp,
+static void ds_var_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len);
 
-struct ds_cap_state ds_states[] = {
+struct ds_cap_state ds_states_template[] = {
 	{
 		.service_id	= "md-update",
 		.data		= md_update_data,
@@ -200,30 +201,38 @@
 #define DS_HS_START		0x01
 #define DS_HS_DONE		0x02
 
+	u64			id;
+
 	void			*rcv_buf;
 	int			rcv_buf_len;
+
+	struct ds_cap_state	*ds_states;
+	int			num_ds_states;
+
+	struct ds_info		*next;
 };
 
-static struct ds_info *ds_info;
+static struct ds_info *ds_info_list;
 
-static struct ds_cap_state *find_cap(u64 handle)
+static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
 {
 	unsigned int index = handle >> 32;
 
-	if (index >= ARRAY_SIZE(ds_states))
+	if (index >= dp->num_ds_states)
 		return NULL;
-	return &ds_states[index];
+	return &dp->ds_states[index];
 }
 
-static struct ds_cap_state *find_cap_by_string(const char *name)
+static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
+					       const char *name)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-		if (strcmp(ds_states[i].service_id, name))
+	for (i = 0; i < dp->num_ds_states; i++) {
+		if (strcmp(dp->ds_states[i].service_id, name))
 			continue;
 
-		return &ds_states[i];
+		return &dp->ds_states[i];
 	}
 	return NULL;
 }
@@ -264,10 +273,11 @@
 	__u32				result;
 };
 
-static void md_update_data(struct ldc_channel *lp,
-			   struct ds_cap_state *dp,
+static void md_update_data(struct ds_info *dp,
+			   struct ds_cap_state *cp,
 			   void *buf, int len)
 {
+	struct ldc_channel *lp = dp->lp;
 	struct ds_data *dpkt = buf;
 	struct ds_md_update_req *rp;
 	struct {
@@ -277,14 +287,14 @@
 
 	rp = (struct ds_md_update_req *) (dpkt + 1);
 
-	printk(KERN_INFO PFX "Machine description update.\n");
+	printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
 
 	mdesc_update();
 
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.data.tag.type = DS_DATA;
 	pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-	pkt.data.handle = dp->handle;
+	pkt.data.handle = cp->handle;
 	pkt.res.req_num = rp->req_num;
 	pkt.res.result = DS_OK;
 
@@ -302,10 +312,11 @@
 	char				reason[1];
 };
 
-static void domain_shutdown_data(struct ldc_channel *lp,
-				 struct ds_cap_state *dp,
+static void domain_shutdown_data(struct ds_info *dp,
+				 struct ds_cap_state *cp,
 				 void *buf, int len)
 {
+	struct ldc_channel *lp = dp->lp;
 	struct ds_data *dpkt = buf;
 	struct ds_shutdown_req *rp;
 	struct {
@@ -315,13 +326,13 @@
 
 	rp = (struct ds_shutdown_req *) (dpkt + 1);
 
-	printk(KERN_ALERT PFX "Shutdown request from "
-	       "LDOM manager received.\n");
+	printk(KERN_ALERT "ds-%lu: Shutdown request from "
+	       "LDOM manager received.\n", dp->id);
 
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.data.tag.type = DS_DATA;
 	pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-	pkt.data.handle = dp->handle;
+	pkt.data.handle = cp->handle;
 	pkt.res.req_num = rp->req_num;
 	pkt.res.result = DS_OK;
 	pkt.res.reason[0] = 0;
@@ -341,10 +352,11 @@
 	char				reason[1];
 };
 
-static void domain_panic_data(struct ldc_channel *lp,
-			      struct ds_cap_state *dp,
+static void domain_panic_data(struct ds_info *dp,
+			      struct ds_cap_state *cp,
 			      void *buf, int len)
 {
+	struct ldc_channel *lp = dp->lp;
 	struct ds_data *dpkt = buf;
 	struct ds_panic_req *rp;
 	struct {
@@ -354,13 +366,13 @@
 
 	rp = (struct ds_panic_req *) (dpkt + 1);
 
-	printk(KERN_ALERT PFX "Panic request from "
-	       "LDOM manager received.\n");
+	printk(KERN_ALERT "ds-%lu: Panic request from "
+	       "LDOM manager received.\n", dp->id);
 
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.data.tag.type = DS_DATA;
 	pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-	pkt.data.handle = dp->handle;
+	pkt.data.handle = cp->handle;
 	pkt.res.req_num = rp->req_num;
 	pkt.res.result = DS_OK;
 	pkt.res.reason[0] = 0;
@@ -403,10 +415,11 @@
 	__u32				str_off;
 };
 
-static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void __dr_cpu_send_error(struct ds_info *dp,
+				struct ds_cap_state *cp,
+				struct ds_data *data)
 {
 	struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
-	struct ds_info *dp = ds_info;
 	struct {
 		struct ds_data		data;
 		struct dr_cpu_tag	tag;
@@ -428,12 +441,14 @@
 	__ds_send(dp->lp, &pkt, msg_len);
 }
 
-static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void dr_cpu_send_error(struct ds_info *dp,
+			      struct ds_cap_state *cp,
+			      struct ds_data *data)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&ds_lock, flags);
-	__dr_cpu_send_error(cp, data);
+	__dr_cpu_send_error(dp, cp, data);
 	spin_unlock_irqrestore(&ds_lock, flags);
 }
 
@@ -511,7 +526,9 @@
 	}
 }
 
-static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_configure(struct ds_info *dp,
+			    struct ds_cap_state *cp,
+			    u64 req_num,
 			    cpumask_t *mask)
 {
 	struct ds_data *resp;
@@ -533,7 +550,8 @@
 	for_each_cpu_mask(cpu, *mask) {
 		int err;
 
-		printk(KERN_INFO PFX "Starting cpu %d...\n", cpu);
+		printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
+		       dp->id, cpu);
 		err = cpu_up(cpu);
 		if (err) {
 			__u32 res = DR_CPU_RES_FAILURE;
@@ -548,14 +566,14 @@
 				res = DR_CPU_RES_CPU_NOT_RESPONDING;
 			}
 
-			printk(KERN_INFO PFX "CPU startup failed err=%d\n",
-			       err);
+			printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
+			       dp->id, err);
 			dr_cpu_mark(resp, cpu, ncpus, res, stat);
 		}
 	}
 
 	spin_lock_irqsave(&ds_lock, flags);
-	__ds_send(ds_info->lp, resp, resp_len);
+	__ds_send(dp->lp, resp, resp_len);
 	spin_unlock_irqrestore(&ds_lock, flags);
 
 	kfree(resp);
@@ -566,7 +584,9 @@
 	return 0;
 }
 
-static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_unconfigure(struct ds_info *dp,
+			      struct ds_cap_state *cp,
+			      u64 req_num,
 			      cpumask_t *mask)
 {
 	struct ds_data *resp;
@@ -586,8 +606,8 @@
 	for_each_cpu_mask(cpu, *mask) {
 		int err;
 
-		printk(KERN_INFO PFX "CPU[%d]: Shutting down cpu %d...\n",
-		       smp_processor_id(), cpu);
+		printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
+		       dp->id, cpu);
 		err = cpu_down(cpu);
 		if (err)
 			dr_cpu_mark(resp, cpu, ncpus,
@@ -596,7 +616,7 @@
 	}
 
 	spin_lock_irqsave(&ds_lock, flags);
-	__ds_send(ds_info->lp, resp, resp_len);
+	__ds_send(dp->lp, resp, resp_len);
 	spin_unlock_irqrestore(&ds_lock, flags);
 
 	kfree(resp);
@@ -604,7 +624,7 @@
 	return 0;
 }
 
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len)
 {
@@ -623,7 +643,7 @@
 		break;
 
 	default:
-		dr_cpu_send_error(cp, data);
+		dr_cpu_send_error(dp, cp, data);
 		return;
 	}
 
@@ -639,12 +659,12 @@
 	}
 
 	if (tag->type == DR_CPU_CONFIGURE)
-		err = dr_cpu_configure(cp, req_num, &mask);
+		err = dr_cpu_configure(dp, cp, req_num, &mask);
 	else
-		err = dr_cpu_unconfigure(cp, req_num, &mask);
+		err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
 
 	if (err)
-		dr_cpu_send_error(cp, data);
+		dr_cpu_send_error(dp, cp, data);
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
@@ -656,8 +676,8 @@
 #define DS_PRI_UPDATE			0x02
 };
 
-static void ds_pri_data(struct ldc_channel *lp,
-			struct ds_cap_state *dp,
+static void ds_pri_data(struct ds_info *dp,
+			struct ds_cap_state *cp,
 			void *buf, int len)
 {
 	struct ds_data *dpkt = buf;
@@ -665,8 +685,8 @@
 
 	rp = (struct ds_pri_msg *) (dpkt + 1);
 
-	printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n",
-	       rp->req_num, rp->type, len);
+	printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
+	       dp->id, rp->req_num, rp->type, len);
 }
 
 struct ds_var_hdr {
@@ -701,8 +721,8 @@
 static int ds_var_doorbell;
 static int ds_var_response;
 
-static void ds_var_data(struct ldc_channel *lp,
-			struct ds_cap_state *dp,
+static void ds_var_data(struct ds_info *dp,
+			struct ds_cap_state *cp,
 			void *buf, int len)
 {
 	struct ds_data *dpkt = buf;
@@ -721,14 +741,35 @@
 
 void ldom_set_var(const char *var, const char *value)
 {
-	struct ds_info *dp = ds_info;
 	struct ds_cap_state *cp;
+	struct ds_info *dp;
+	unsigned long flags;
 
-	cp = find_cap_by_string("var-config");
-	if (cp->state != CAP_STATE_REGISTERED)
-		cp = find_cap_by_string("var-config-backup");
+	spin_lock_irqsave(&ds_lock, flags);
+	cp = NULL;
+	for (dp = ds_info_list; dp; dp = dp->next) {
+		struct ds_cap_state *tmp;
 
-	if (cp->state == CAP_STATE_REGISTERED) {
+		tmp = find_cap_by_string(dp, "var-config");
+		if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+			cp = tmp;
+			break;
+		}
+	}
+	if (!cp) {
+		for (dp = ds_info_list; dp; dp = dp->next) {
+			struct ds_cap_state *tmp;
+
+			tmp = find_cap_by_string(dp, "var-config-backup");
+			if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+				cp = tmp;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&ds_lock, flags);
+
+	if (cp) {
 		union {
 			struct {
 				struct ds_data		data;
@@ -736,7 +777,6 @@
 			} header;
 			char			all[512];
 		} pkt;
-		unsigned long flags;
 		char  *base, *p;
 		int msg_len, loops;
 
@@ -777,9 +817,9 @@
 
 		if (ds_var_doorbell == 0 ||
 		    ds_var_response != DS_VAR_SUCCESS)
-			printk(KERN_ERR PFX "var-config [%s:%s] "
+			printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
 			       "failed, response(%d).\n",
-			       var, value,
+			       dp->id, var, value,
 			       ds_var_response);
 	} else {
 		printk(KERN_ERR PFX "var-config not registered so "
@@ -811,8 +851,8 @@
 
 static void ds_conn_reset(struct ds_info *dp)
 {
-	printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
-	       __builtin_return_address(0));
+	printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
+	       dp->id, __builtin_return_address(0));
 }
 
 static int register_services(struct ds_info *dp)
@@ -820,12 +860,12 @@
 	struct ldc_channel *lp = dp->lp;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+	for (i = 0; i < dp->num_ds_states; i++) {
 		struct {
 			struct ds_reg_req req;
 			u8 id_buf[256];
 		} pbuf;
-		struct ds_cap_state *cp = &ds_states[i];
+		struct ds_cap_state *cp = &dp->ds_states[i];
 		int err, msg_len;
 		u64 new_count;
 
@@ -870,28 +910,26 @@
 
 	if (pkt->type == DS_REG_ACK) {
 		struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
-		struct ds_cap_state *cp = find_cap(ap->handle);
+		struct ds_cap_state *cp = find_cap(dp, ap->handle);
 
 		if (!cp) {
-			printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n",
-			       ap->handle);
+			printk(KERN_ERR "ds-%lu: REG ACK for unknown "
+			       "handle %lx\n", dp->id, ap->handle);
 			return 0;
 		}
-		printk(KERN_INFO PFX "Registered %s service.\n",
-		       cp->service_id);
+		printk(KERN_INFO "ds-%lu: Registered %s service.\n",
+		       dp->id, cp->service_id);
 		cp->state = CAP_STATE_REGISTERED;
 	} else if (pkt->type == DS_REG_NACK) {
 		struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
-		struct ds_cap_state *cp = find_cap(np->handle);
+		struct ds_cap_state *cp = find_cap(dp, np->handle);
 
 		if (!cp) {
-			printk(KERN_ERR PFX "REG NACK for "
+			printk(KERN_ERR "ds-%lu: REG NACK for "
 			       "unknown handle %lx\n",
-			       np->handle);
+			       dp->id, np->handle);
 			return 0;
 		}
-		printk(KERN_INFO PFX "Could not register %s service\n",
-		       cp->service_id);
 		cp->state = CAP_STATE_UNKNOWN;
 	}
 
@@ -922,6 +960,7 @@
 
 struct ds_queue_entry {
 	struct list_head		list;
+	struct ds_info			*dp;
 	int				req_len;
 	int				__pad;
 	u64				req[0];
@@ -930,7 +969,6 @@
 static void process_ds_work(void)
 {
 	struct ds_queue_entry *qp, *tmp;
-	static struct ds_info *dp;
 	unsigned long flags;
 	LIST_HEAD(todo);
 
@@ -939,22 +977,22 @@
 	INIT_LIST_HEAD(&ds_work_list);
 	spin_unlock_irqrestore(&ds_lock, flags);
 
-	dp = ds_info;
-
 	list_for_each_entry_safe(qp, tmp, &todo, list) {
 		struct ds_data *dpkt = (struct ds_data *) qp->req;
-		struct ds_cap_state *cp = find_cap(dpkt->handle);
+		struct ds_info *dp = qp->dp;
+		struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
 		int req_len = qp->req_len;
 
 		if (!cp) {
-			printk(KERN_ERR PFX "Data for unknown handle %lu\n",
-			       dpkt->handle);
+			printk(KERN_ERR "ds-%lu: Data for unknown "
+			       "handle %lu\n",
+			       dp->id, dpkt->handle);
 
 			spin_lock_irqsave(&ds_lock, flags);
 			__send_ds_nack(dp, dpkt->handle);
 			spin_unlock_irqrestore(&ds_lock, flags);
 		} else {
-			cp->data(dp->lp, cp, dpkt, req_len);
+			cp->data(dp, cp, dpkt, req_len);
 		}
 
 		list_del(&qp->list);
@@ -990,6 +1028,7 @@
 	if (!qp) {
 		__send_ds_nack(dp, dpkt->handle);
 	} else {
+		qp->dp = dp;
 		memcpy(&qp->req, pkt, len);
 		list_add_tail(&qp->list, &ds_work_list);
 		wake_up(&ds_wait);
@@ -1019,8 +1058,8 @@
 
 	dp->hs_state = 0;
 
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-		struct ds_cap_state *cp = &ds_states[i];
+	for (i = 0; i < dp->num_ds_states; i++) {
+		struct ds_cap_state *cp = &dp->ds_states[i];
 
 		cp->state = CAP_STATE_UNKNOWN;
 	}
@@ -1048,7 +1087,8 @@
 	}
 
 	if (event != LDC_EVENT_DATA_READY) {
-		printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+		printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
+		       dp->id, event);
 		spin_unlock_irqrestore(&ds_lock, flags);
 		return;
 	}
@@ -1099,9 +1139,11 @@
 		.mtu		= 4096,
 		.mode		= LDC_MODE_STREAM,
 	};
+	struct mdesc_handle *hp;
 	struct ldc_channel *lp;
 	struct ds_info *dp;
-	int err;
+	const u64 *val;
+	int err, i;
 
 	if (ds_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -1111,19 +1153,37 @@
 	if (!dp)
 		goto out_err;
 
+	hp = mdesc_grab();
+	val = mdesc_get_property(hp, vdev->mp, "id", NULL);
+	if (val)
+		dp->id = *val;
+	mdesc_release(hp);
+
 	dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
 	if (!dp->rcv_buf)
 		goto out_free_dp;
 
 	dp->rcv_buf_len = 4096;
 
+	dp->ds_states = kzalloc(sizeof(ds_states_template),
+				GFP_KERNEL);
+	if (!dp->ds_states)
+		goto out_free_rcv_buf;
+
+	memcpy(dp->ds_states, ds_states_template,
+	       sizeof(ds_states_template));
+	dp->num_ds_states = ARRAY_SIZE(ds_states_template);
+
+	for (i = 0; i < dp->num_ds_states; i++)
+		dp->ds_states[i].handle = ((u64)i << 32);
+
 	ds_cfg.tx_irq = vdev->tx_irq;
 	ds_cfg.rx_irq = vdev->rx_irq;
 
 	lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
 	if (IS_ERR(lp)) {
 		err = PTR_ERR(lp);
-		goto out_free_rcv_buf;
+		goto out_free_ds_states;
 	}
 	dp->lp = lp;
 
@@ -1131,13 +1191,19 @@
 	if (err)
 		goto out_free_ldc;
 
-	ds_info = dp;
+	spin_lock_irq(&ds_lock);
+	dp->next = ds_info_list;
+	ds_info_list = dp;
+	spin_unlock_irq(&ds_lock);
 
 	return err;
 
 out_free_ldc:
 	ldc_free(dp->lp);
 
+out_free_ds_states:
+	kfree(dp->ds_states);
+
 out_free_rcv_buf:
 	kfree(dp->rcv_buf);
 
@@ -1172,11 +1238,6 @@
 
 static int __init ds_init(void)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++)
-		ds_states[i].handle = ((u64)i << 32);
-
 	kthread_run(ds_thread, NULL, "kldomd");
 
 	return vio_register_driver(&ds_driver);
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index ad55a9b..6d29561 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -362,6 +362,7 @@
 static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
 {
 	struct linux_ebus_child *child;
+	struct dev_archdata *sd;
 	struct of_device *op;
 	int i, len;
 
@@ -387,6 +388,10 @@
 			dev->irqs[i] = op->irqs[i];
 	}
 
+	sd = &dev->ofdev.dev.archdata;
+	sd->prom_node = dp;
+	sd->op = &dev->ofdev;
+
 	dev->ofdev.node = dp;
 	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
 	dev->ofdev.dev.bus = &ebus_bus_type;
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index c727956..db31bf6 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -87,7 +87,11 @@
  */
 #define irq_work(__cpu)	&(trap_block[(__cpu)].irq_worklist)
 
-static unsigned int virt_to_real_irq_table[NR_IRQS];
+static struct {
+	unsigned int irq;
+	unsigned int dev_handle;
+	unsigned int dev_ino;
+} virt_to_real_irq_table[NR_IRQS];
 
 static unsigned char virt_irq_alloc(unsigned int real_irq)
 {
@@ -96,7 +100,7 @@
 	BUILD_BUG_ON(NR_IRQS >= 256);
 
 	for (ent = 1; ent < NR_IRQS; ent++) {
-		if (!virt_to_real_irq_table[ent])
+		if (!virt_to_real_irq_table[ent].irq)
 			break;
 	}
 	if (ent >= NR_IRQS) {
@@ -104,7 +108,7 @@
 		return 0;
 	}
 
-	virt_to_real_irq_table[ent] = real_irq;
+	virt_to_real_irq_table[ent].irq = real_irq;
 
 	return ent;
 }
@@ -117,8 +121,8 @@
 	if (virt_irq >= NR_IRQS)
 		return;
 
-	real_irq = virt_to_real_irq_table[virt_irq];
-	virt_to_real_irq_table[virt_irq] = 0;
+	real_irq = virt_to_real_irq_table[virt_irq].irq;
+	virt_to_real_irq_table[virt_irq].irq = 0;
 
 	__bucket(real_irq)->virt_irq = 0;
 }
@@ -126,7 +130,7 @@
 
 static unsigned int virt_to_real_irq(unsigned char virt_irq)
 {
-	return virt_to_real_irq_table[virt_irq];
+	return virt_to_real_irq_table[virt_irq].irq;
 }
 
 /*
@@ -336,15 +340,15 @@
 
 		err = sun4v_intr_settarget(ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-			       ino, cpuid, err);
+			printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+			       "err(%d)\n", ino, cpuid, err);
 		err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setstate(%x): "
+			printk(KERN_ERR "sun4v_intr_setstate(%x): "
 			       "err(%d)\n", ino, err);
 		err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setenabled(%x): err(%d)\n",
+			printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
 			       ino, err);
 	}
 }
@@ -362,8 +366,8 @@
 
 		err = sun4v_intr_settarget(ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-			       ino, cpuid, err);
+			printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+			       "err(%d)\n", ino, cpuid, err);
 	}
 }
 
@@ -377,7 +381,7 @@
 
 		err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setenabled(%x): "
+			printk(KERN_ERR "sun4v_intr_setenabled(%x): "
 			       "err(%d)\n", ino, err);
 	}
 }
@@ -410,7 +414,7 @@
 
 		err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setstate(%x): "
+			printk(KERN_ERR "sun4v_intr_setstate(%x): "
 			       "err(%d)\n", ino, err);
 	}
 }
@@ -418,7 +422,6 @@
 static void sun4v_virq_enable(unsigned int virt_irq)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 
 	if (likely(bucket)) {
 		unsigned long cpuid, dev_handle, dev_ino;
@@ -426,24 +429,24 @@
 
 		cpuid = irq_choose_cpu(virt_irq);
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+			printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
 			       "err(%d)\n",
 			       dev_handle, dev_ino, cpuid, err);
 		err = sun4v_vintr_set_state(dev_handle, dev_ino,
 					    HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 				"HV_INTR_STATE_IDLE): err(%d)\n",
 			       dev_handle, dev_ino, err);
 		err = sun4v_vintr_set_valid(dev_handle, dev_ino,
 					    HV_INTR_ENABLED);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 			       "HV_INTR_ENABLED): err(%d)\n",
 			       dev_handle, dev_ino, err);
 	}
@@ -452,7 +455,6 @@
 static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 
 	if (likely(bucket)) {
 		unsigned long cpuid, dev_handle, dev_ino;
@@ -460,12 +462,12 @@
 
 		cpuid = irq_choose_cpu(virt_irq);
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+			printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
 			       "err(%d)\n",
 			       dev_handle, dev_ino, cpuid, err);
 	}
@@ -474,19 +476,18 @@
 static void sun4v_virq_disable(unsigned int virt_irq)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 
 	if (likely(bucket)) {
 		unsigned long dev_handle, dev_ino;
 		int err;
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_valid(dev_handle, dev_ino,
 					    HV_INTR_DISABLED);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 			       "HV_INTR_DISABLED): err(%d)\n",
 			       dev_handle, dev_ino, err);
 	}
@@ -495,7 +496,6 @@
 static void sun4v_virq_end(unsigned int virt_irq)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 	struct irq_desc *desc = irq_desc + virt_irq;
 
 	if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
@@ -505,13 +505,13 @@
 		unsigned long dev_handle, dev_ino;
 		int err;
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_state(dev_handle, dev_ino,
 					    HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 				"HV_INTR_STATE_IDLE): err(%d)\n",
 			       dev_handle, dev_ino, err);
 	}
@@ -700,6 +700,7 @@
 unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
 {
 	unsigned long sysino, hv_err;
+	unsigned int virq;
 
 	BUG_ON(devhandle & devino);
 
@@ -713,7 +714,12 @@
 		prom_halt();
 	}
 
-	return sun4v_build_common(sysino, &sun4v_virq);
+	virq = sun4v_build_common(sysino, &sun4v_virq);
+
+	virt_to_real_irq_table[virq].dev_handle = devhandle;
+	virt_to_real_irq_table[virq].dev_ino = devino;
+
+	return virq;
 }
 
 #ifdef CONFIG_PCI_MSI
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 6a6882e..1a1043f 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -79,6 +79,7 @@
 
 	while (dp) {
 		struct sparc_isa_device *isa_dev;
+		struct dev_archdata *sd;
 
 		isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
 		if (!isa_dev) {
@@ -86,6 +87,10 @@
 			return;
 		}
 
+		sd = &isa_dev->ofdev.dev.archdata;
+		sd->prom_node = dp;
+		sd->op = &isa_dev->ofdev;
+
 		isa_dev->ofdev.node = dp;
 		isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
 		isa_dev->ofdev.dev.bus = &isa_bus_type;
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index 13a79fe..cce4d0d 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -83,7 +83,7 @@
 	hp->handle_size = handle_size;
 }
 
-static struct mdesc_handle *mdesc_bootmem_alloc(unsigned int mdesc_size)
+static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size)
 {
 	struct mdesc_handle *hp;
 	unsigned int handle_size, alloc_size;
@@ -123,7 +123,7 @@
 	}
 }
 
-static struct mdesc_mem_ops bootmem_mdesc_memops = {
+static struct mdesc_mem_ops bootmem_mdesc_ops = {
 	.alloc = mdesc_bootmem_alloc,
 	.free  = mdesc_bootmem_free,
 };
@@ -860,7 +860,7 @@
 
 	printk("MDESC: Size is %lu bytes.\n", len);
 
-	hp = mdesc_alloc(len, &bootmem_mdesc_memops);
+	hp = mdesc_alloc(len, &bootmem_mdesc_ops);
 	if (hp == NULL) {
 		prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
 		prom_halt();
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 7b0dce9..4cc7748 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -752,11 +752,16 @@
 {
 	struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
 	const unsigned int *irq;
+	struct dev_archdata *sd;
 	int len, i;
 
 	if (!op)
 		return NULL;
 
+	sd = &op->dev.archdata;
+	sd->prom_node = dp;
+	sd->op = op;
+
 	op->node = dp;
 
 	op->clock_freq = of_getintprop_default(dp, "clock-frequency",
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 6b3fe2c..639cf06 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -1129,7 +1129,7 @@
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
+static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
 {
 	struct pci_pbm_info *pbm;
 
@@ -1163,7 +1163,7 @@
 	pci_sun4v_msi_init(pbm);
 }
 
-void sun4v_pci_init(struct device_node *dp, char *model_name)
+void __init sun4v_pci_init(struct device_node *dp, char *model_name)
 {
 	static int hvapi_negotiated = 0;
 	struct pci_controller_info *p;
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index b00feb0..881a09e 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -46,7 +46,7 @@
 void machine_power_off(void)
 {
 	sstate_poweroff();
-	if (!serial_console || scons_pwroff) {
+	if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
 		if (power_reg) {
 			/* Both register bits seem to have the
 			 * same effect, so until I figure out
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 9355750..fd7899b 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -119,7 +119,7 @@
 void machine_halt(void)
 {
 	sstate_halt();
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	if (prom_keyboard)
 		prom_keyboard();
@@ -130,7 +130,7 @@
 void machine_alt_power_off(void)
 {
 	sstate_poweroff();
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette(1);
 	if (prom_keyboard)
 		prom_keyboard();
@@ -145,7 +145,7 @@
 	sstate_reboot();
 	p = strchr (reboot_command, '\n');
 	if (p) *p = 0;
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	if (prom_keyboard)
 		prom_keyboard();
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 2b2017c..f4e0a9a 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -1646,6 +1646,60 @@
 	smp_fill_in_sib_core_maps();
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+static void __init of_console_init(void)
+{
+	char *msg = "OF stdout device is: %s\n";
+	struct device_node *dp;
+	const char *type;
+	phandle node;
+
+	of_console_path = prom_early_alloc(256);
+	if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
+		prom_printf("Cannot obtain path of stdout.\n");
+		prom_halt();
+	}
+	of_console_options = strrchr(of_console_path, ':');
+	if (of_console_options) {
+		of_console_options++;
+		if (*of_console_options == '\0')
+			of_console_options = NULL;
+	}
+
+	node = prom_inst2pkg(prom_stdout);
+	if (!node) {
+		prom_printf("Cannot resolve stdout node from "
+			    "instance %08x.\n", prom_stdout);
+		prom_halt();
+	}
+
+	dp = of_find_node_by_phandle(node);
+	type = of_get_property(dp, "device_type", NULL);
+	if (!type) {
+		prom_printf("Console stdout lacks device_type property.\n");
+		prom_halt();
+	}
+
+	if (strcmp(type, "display") && strcmp(type, "serial")) {
+		prom_printf("Console device_type is neither display "
+			    "nor serial.\n");
+		prom_halt();
+	}
+
+	of_console_device = dp;
+
+	prom_printf(msg, of_console_path);
+	printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
 	struct device_node **nextp;
@@ -1658,6 +1712,8 @@
 	allnodes->child = build_tree(allnodes,
 				     prom_getchild(allnodes->node),
 				     &nextp);
+	of_console_init();
+
 	printk("PROM: Built device tree with %u bytes of memory.\n",
 	       prom_early_allocated);
 
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index aafde3d..0f5be82 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -133,33 +133,6 @@
 	}
 }
 
-static void __init process_console(char *commands)
-{
-	serial_console = 0;
-	commands += 8;
-	/* Linux-style serial */
-	if (!strncmp(commands, "ttyS", 4))
-		serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-	else if (!strncmp(commands, "tty", 3)) {
-		char c = *(commands + 3);
-		/* Solaris-style serial */
-		if (c == 'a' || c == 'b') {
-			serial_console = c - 'a' + 1;
-			prom_printf ("Using /dev/tty%c as console.\n", c);
-		}
-		/* else Linux-style fbcon, not serial */
-	}
-#if defined(CONFIG_PROM_CONSOLE)
-	if (!strncmp(commands, "prom", 4)) {
-		char *p;
-
-		for (p = commands - 8; *p && *p != ' '; p++)
-			*p = ' ';
-		conswitchp = &prom_con;
-	}
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
 	while (*commands) {
@@ -176,9 +149,7 @@
 				process_switch(*commands++);
 			continue;
 		}
-		if (!strncmp(commands, "console=", 8)) {
-			process_console(commands);
-		} else if (!strncmp(commands, "mem=", 4)) {
+		if (!strncmp(commands, "mem=", 4)) {
 			/*
 			 * "mem=XXX[kKmM]" overrides the PROM-reported
 			 * memory size.
@@ -378,44 +349,6 @@
 	paging_init();
 }
 
-static int __init set_preferred_console(void)
-{
-	int idev, odev;
-
-	/* The user has requested a console so this is already set up. */
-	if (serial_console >= 0)
-		return -EBUSY;
-
-	idev = prom_query_input_device();
-	odev = prom_query_output_device();
-	if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-		serial_console = 0;
-	} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-		serial_console = 1;
-	} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-		serial_console = 2;
-	} else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
-		serial_console = 3;
-	} else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
-		/* sunhv_console_init() doesn't check the serial_console
-		 * value anyways...
-		 */
-		serial_console = 4;
-		return add_preferred_console("ttyHV", 0, NULL);
-	} else {
-		prom_printf("Inconsistent console: "
-			    "input %d, output %d\n",
-			    idev, odev);
-		prom_halt();
-	}
-
-	if (serial_console)
-		return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-	return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 /* BUFFER is PAGE_SIZE bytes long. */
 
 extern char *sparc_cpu_type;
@@ -508,5 +441,4 @@
 	prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 719d676..7d36531 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -330,7 +330,6 @@
 
 /* for input/keybdev */
 EXPORT_SYMBOL(sun_do_break);
-EXPORT_SYMBOL(serial_console);
 EXPORT_SYMBOL(stop_a_enabled);
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 592ffcd..e340eb4 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1434,6 +1434,78 @@
 
 	return 0;
 }
+
+static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
+{
+	unsigned char ctrl;
+
+	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+	rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
+
+	ctrl = CMOS_READ(RTC_CONTROL);
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(rtc_tm->tm_sec);
+		BCD_TO_BIN(rtc_tm->tm_min);
+		BCD_TO_BIN(rtc_tm->tm_hour);
+		BCD_TO_BIN(rtc_tm->tm_mday);
+		BCD_TO_BIN(rtc_tm->tm_mon);
+		BCD_TO_BIN(rtc_tm->tm_year);
+		BCD_TO_BIN(rtc_tm->tm_wday);
+	}
+
+	if (rtc_tm->tm_year <= 69)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
+
+static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
+{
+	unsigned char mon, day, hrs, min, sec;
+	unsigned char save_control, save_freq_select;
+	unsigned int yrs;
+
+	yrs = rtc_tm->tm_year;
+	mon = rtc_tm->tm_mon + 1;
+	day = rtc_tm->tm_mday;
+	hrs = rtc_tm->tm_hour;
+	min = rtc_tm->tm_min;
+	sec = rtc_tm->tm_sec;
+
+	if (yrs >= 100)
+		yrs -= 100;
+
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(sec);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(hrs);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(mon);
+		BIN_TO_BCD(yrs);
+	}
+
+	save_control = CMOS_READ(RTC_CONTROL);
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+	CMOS_WRITE(yrs, RTC_YEAR);
+	CMOS_WRITE(mon, RTC_MONTH);
+	CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(hrs, RTC_HOURS);
+	CMOS_WRITE(min, RTC_MINUTES);
+	CMOS_WRITE(sec, RTC_SECONDS);
+
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	return 0;
+}
 #endif /* CONFIG_PCI */
 
 struct mini_rtc_ops {
@@ -1456,6 +1528,11 @@
 	.get_rtc_time = bq4802_get_rtc_time,
 	.set_rtc_time = bq4802_set_rtc_time,
 };
+
+static struct mini_rtc_ops cmos_rtc_ops = {
+	.get_rtc_time = cmos_get_rtc_time,
+	.set_rtc_time = cmos_set_rtc_time,
+};
 #endif /* CONFIG_PCI */
 
 static struct mini_rtc_ops *mini_rtc_ops;
@@ -1583,6 +1660,8 @@
 #ifdef CONFIG_PCI
 	else if (bq4802_regs)
 		mini_rtc_ops = &bq4802_rtc_ops;
+	else if (ds1287_regs)
+		mini_rtc_ops = &cmos_rtc_ops;
 #endif /* CONFIG_PCI */
 	else
 		return -ENODEV;
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 491223a..3685daf 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -205,7 +205,8 @@
 	struct device_node *dp;
 	struct vio_dev *vdev;
 	int err, tlen, clen;
-	const u64 *id;
+	const u64 *id, *cfg_handle;
+	u64 a;
 
 	type = mdesc_get_property(hp, mp, "device-type", &tlen);
 	if (!type) {
@@ -221,26 +222,18 @@
 		return NULL;
 	}
 
-	if (!strcmp(type, "vdc-port")) {
-		u64 a;
+	id = mdesc_get_property(hp, mp, "id", NULL);
 
-		id = NULL;
-		mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
-			u64 target;
+	cfg_handle = NULL;
+	mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+		u64 target;
 
-			target = mdesc_arc_target(hp, a);
-			id = mdesc_get_property(hp, target,
+		target = mdesc_arc_target(hp, a);
+		cfg_handle = mdesc_get_property(hp, target,
 						"cfg-handle", NULL);
-			if (id)
-				break;
-		}
-		if (!id) {
-			printk(KERN_ERR "VIO: vdc-port lacks parent "
-			       "cfg-handle.\n");
-			return NULL;
-		}
-	} else
-		id = mdesc_get_property(hp, mp, "id", NULL);
+		if (cfg_handle)
+			break;
+	}
 
 	bus_id_name = type;
 	if (!strcmp(type, "domain-services-port"))
@@ -285,10 +278,14 @@
 		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
 			 bus_id_name);
 		vdev->dev_no = ~(u64)0;
-	} else {
+	} else if (!cfg_handle) {
 		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
 			 bus_id_name, *id);
 		vdev->dev_no = *id;
+	} else {
+		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu-%lu",
+			 bus_id_name, *cfg_handle, *id);
+		vdev->dev_no = *cfg_handle;
 	}
 
 	vdev->dev.parent = parent;
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
index 7c25c54..3fafa9a 100644
--- a/arch/sparc64/prom/console.c
+++ b/arch/sparc64/prom/console.c
@@ -73,88 +73,3 @@
 			   P1275_INOUT(3,1),
 			   prom_stdout, s, P1275_SIZE(len));
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-	int st_p;
-	char propb[64];
-
-	st_p = prom_inst2pkg(prom_stdin);
-	if(prom_node_has_property(st_p, "keyboard"))
-		return PROMDEV_IKBD;
-	prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-	if(strncmp(propb, "serial", 6))
-		return PROMDEV_I_UNK;
-	/* FIXME: Is there any better way how to find out? */	
-	memset(propb, 0, sizeof(propb));
-	st_p = prom_finddevice ("/options");
-	prom_getproperty(st_p, "input-device", propb, sizeof(propb));
-
-	/*
-	 * If we get here with propb == 'keyboard', we are on ttya, as
-	 * the PROM defaulted to this due to 'no input device'.
-	 */
-	if (!strncmp(propb, "keyboard", 8))
-		return PROMDEV_ITTYA;
-
-	if (!strncmp (propb, "rsc", 3))
-		return PROMDEV_IRSC;
-
-	if (!strncmp (propb, "virtual-console", 3))
-		return PROMDEV_IVCONS;
-
-	if (strncmp (propb, "tty", 3) || !propb[3])
-		return PROMDEV_I_UNK;
-
-	switch (propb[3]) {
-		case 'a': return PROMDEV_ITTYA;
-		case 'b': return PROMDEV_ITTYB;
-		default: return PROMDEV_I_UNK;
-	}
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-	int st_p;
-	char propb[64];
-	int propl;
-
-	st_p = prom_inst2pkg(prom_stdout);
-	propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-	if (propl >= 0 && propl == sizeof("display") &&
-	    strncmp("display", propb, sizeof("display")) == 0)
-		return PROMDEV_OSCREEN;
-	if(strncmp("serial", propb, 6))
-		return PROMDEV_O_UNK;
-	/* FIXME: Is there any better way how to find out? */	
-	memset(propb, 0, sizeof(propb));
-	st_p = prom_finddevice ("/options");
-	prom_getproperty(st_p, "output-device", propb, sizeof(propb));
-
-	/*
-	 * If we get here with propb == 'screen', we are on ttya, as
-	 * the PROM defaulted to this due to 'no input device'.
-	 */
-	if (!strncmp(propb, "screen", 6))
-		return PROMDEV_OTTYA;
-
-	if (!strncmp (propb, "rsc", 3))
-		return PROMDEV_ORSC;
-
-	if (!strncmp (propb, "virtual-console", 3))
-		return PROMDEV_OVCONS;
-
-	if (strncmp (propb, "tty", 3) || !propb[3])
-		return PROMDEV_O_UNK;
-
-	switch (propb[3]) {
-		case 'a': return PROMDEV_OTTYA;
-		case 'b': return PROMDEV_OTTYB;
-		default: return PROMDEV_O_UNK;
-	}
-}
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 33c5b7d..68c83ad 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -72,7 +72,7 @@
 
 	local_irq_save(flags);
 
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette(1);
 
 #ifdef CONFIG_SMP
@@ -85,7 +85,7 @@
 	smp_release();
 #endif
 
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette(0);
 
 	local_irq_restore(flags);
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
index 17b7ecf..b2c5b12 100644
--- a/arch/sparc64/prom/tree.c
+++ b/arch/sparc64/prom/tree.c
@@ -304,3 +304,11 @@
 	if (node == -1) return 0;
 	return node;
 }
+
+int prom_ihandle2path(int handle, char *buffer, int bufsize)
+{
+	return p1275_cmd("instance-to-path",
+			 P1275_ARG(1,P1275_ARG_OUT_BUF)|
+			 P1275_INOUT(3, 1),
+			 handle, buffer, P1275_SIZE(bufsize));
+}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 4373d7c..c8dfd18 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -726,7 +726,7 @@
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+	depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390
 	---help---
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 22cf7aa..30c3f54 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -86,12 +86,9 @@
 #include <asm/hpet.h>
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 #include <linux/pci.h>
 #include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
 
 static unsigned long rtc_port;
 static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@
 	unsigned int year, ctrl;
 	char *guess = NULL;
 #endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
-	struct sparc_isa_bridge *isa_br;
-	struct sparc_isa_device *isa_dev;
-#endif
 #else
 	void *r;
 #ifdef RTC_IRQ
@@ -944,7 +937,7 @@
 #endif
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
 			if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@
 			}
 		}
 	}
-#ifdef __sparc_v9__
-	for_each_isa(isa_br) {
-		for_each_isadev(isa_dev, isa_br) {
-			if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
-				rtc_port = isa_dev->resource.start;
-				rtc_irq = isa_dev->irq;
-				goto found;
-			}
-		}
-	}
-#endif
 	rtc_has_irq = 0;
 	printk(KERN_ERR "rtc_init: no PC rtc found\n");
 	return -EIO;
@@ -1020,7 +1002,7 @@
 
 #endif
 
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
 
 	if (misc_register(&rtc_dev)) {
 #ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@
 	remove_proc_entry ("driver/rtc", NULL);
 	misc_deregister(&rtc_dev);
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	if (rtc_has_irq)
 		free_irq (rtc_irq, &rtc_port);
 #else
@@ -1117,7 +1099,7 @@
 	if (rtc_has_irq)
 		free_irq (RTC_IRQ, NULL);
 #endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
 }
 
 module_init(rtc_init);
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index ef0066b..61f9825 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -459,6 +459,22 @@
 	return 0;
 }
 
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+	struct vio_net_mcast_info *pkt = msgbuf;
+
+	if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+		printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+		       "[%02x:%02x:%04x:%08x]\n",
+		       port->vp->dev->name,
+		       pkt->tag.type,
+		       pkt->tag.stype,
+		       pkt->tag.stype_env,
+		       pkt->tag.sid);
+
+	return 0;
+}
+
 static void maybe_tx_wakeup(struct vnet *vp)
 {
 	struct net_device *dev = vp->dev;
@@ -544,7 +560,10 @@
 				err = vnet_nack(port, &msgbuf);
 			}
 		} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
-			err = vio_control_pkt_engine(vio, &msgbuf);
+			if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+				err = handle_mcast(port, &msgbuf);
+			else
+				err = vio_control_pkt_engine(vio, &msgbuf);
 			if (err)
 				break;
 		} else {
@@ -731,9 +750,122 @@
 	return 0;
 }
 
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+	struct vnet_mcast_entry *m;
+
+	for (m = vp->mcast_list; m; m = m->next) {
+		if (!memcmp(m->addr, addr, ETH_ALEN))
+			return m;
+	}
+	return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+	struct dev_addr_list *p;
+
+	for (p = dev->mc_list; p; p = p->next) {
+		struct vnet_mcast_entry *m;
+
+		m = __vnet_mc_find(vp, p->dmi_addr);
+		if (m) {
+			m->hit = 1;
+			continue;
+		}
+
+		if (!m) {
+			m = kzalloc(sizeof(*m), GFP_ATOMIC);
+			if (!m)
+				continue;
+			memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+			m->hit = 1;
+
+			m->next = vp->mcast_list;
+			vp->mcast_list = m;
+		}
+	}
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+	struct vio_net_mcast_info info;
+	struct vnet_mcast_entry *m, **pp;
+	int n_addrs;
+
+	memset(&info, 0, sizeof(info));
+
+	info.tag.type = VIO_TYPE_CTRL;
+	info.tag.stype = VIO_SUBTYPE_INFO;
+	info.tag.stype_env = VNET_MCAST_INFO;
+	info.tag.sid = vio_send_sid(&port->vio);
+	info.set = 1;
+
+	n_addrs = 0;
+	for (m = vp->mcast_list; m; m = m->next) {
+		if (m->sent)
+			continue;
+		m->sent = 1;
+		memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+		       m->addr, ETH_ALEN);
+		if (++n_addrs == VNET_NUM_MCAST) {
+			info.count = n_addrs;
+
+			(void) vio_ldc_send(&port->vio, &info,
+					    sizeof(info));
+			n_addrs = 0;
+		}
+	}
+	if (n_addrs) {
+		info.count = n_addrs;
+		(void) vio_ldc_send(&port->vio, &info, sizeof(info));
+	}
+
+	info.set = 0;
+
+	n_addrs = 0;
+	pp = &vp->mcast_list;
+	while ((m = *pp) != NULL) {
+		if (m->hit) {
+			m->hit = 0;
+			pp = &m->next;
+			continue;
+		}
+
+		memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+		       m->addr, ETH_ALEN);
+		if (++n_addrs == VNET_NUM_MCAST) {
+			info.count = n_addrs;
+			(void) vio_ldc_send(&port->vio, &info,
+					    sizeof(info));
+			n_addrs = 0;
+		}
+
+		*pp = m->next;
+		kfree(m);
+	}
+	if (n_addrs) {
+		info.count = n_addrs;
+		(void) vio_ldc_send(&port->vio, &info, sizeof(info));
+	}
+}
+
 static void vnet_set_rx_mode(struct net_device *dev)
 {
-	/* XXX Implement multicast support XXX */
+	struct vnet *vp = netdev_priv(dev);
+	struct vnet_port *port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vp->lock, flags);
+	if (!list_empty(&vp->port_list)) {
+		port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+		if (port->switch_port) {
+			__update_mc_list(vp, dev);
+			__send_mc_list(vp, port);
+		}
+	}
+	spin_unlock_irqrestore(&vp->lock, flags);
 }
 
 static int vnet_change_mtu(struct net_device *dev, int new_mtu)
@@ -1070,6 +1202,7 @@
 	switch_port = 0;
 	if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
 		switch_port = 1;
+	port->switch_port = switch_port;
 
 	spin_lock_irqsave(&vp->lock, flags);
 	if (switch_port)
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
index 7d3a0ca..d347a5b 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/sunvnet.h
@@ -30,6 +30,8 @@
 
 	struct hlist_node	hash;
 	u8			raddr[ETH_ALEN];
+	u8			switch_port;
+	u8			__pad;
 
 	struct vnet		*vp;
 
@@ -53,6 +55,13 @@
 	return val & (VNET_PORT_HASH_MASK);
 }
 
+struct vnet_mcast_entry {
+	u8			addr[ETH_ALEN];
+	u8			sent;
+	u8			hit;
+	struct vnet_mcast_entry	*next;
+};
+
 struct vnet {
 	/* Protects port_list and port_hash.  */
 	spinlock_t		lock;
@@ -65,6 +74,8 @@
 
 	struct hlist_head	port_hash[VNET_PORT_HASH_SIZE];
 
+	struct vnet_mcast_entry	*mcast_list;
+
 	struct list_head	list;
 	u64			local_mac;
 };
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 0026433..2553629 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -33,6 +33,7 @@
 
 static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
 {
+	struct dev_archdata *sd;
 	unsigned long base;
 	const void *pval;
 	int len, err;
@@ -67,6 +68,10 @@
 
 	sbus_fill_device_irq(sdev);
 
+	sd = &sdev->ofdev.dev.archdata;
+	sd->prom_node = dp;
+	sd->op = &sdev->ofdev;
+
 	sdev->ofdev.node = dp;
 	if (sdev->parent)
 		sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index b45ba53..70a09a3 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -16,9 +16,10 @@
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/serial_core.h>
 #include <linux/init.h>
 
-#include <asm/oplib.h>
+#include <asm/prom.h>
 
 #include "suncore.h"
 
@@ -26,92 +27,60 @@
 
 EXPORT_SYMBOL(sunserial_current_minor);
 
+int sunserial_console_match(struct console *con, struct device_node *dp,
+			    struct uart_driver *drv, int line)
+{
+	int off;
+
+	if (!con || of_console_device != dp)
+		return 0;
+
+	off = 0;
+	if (of_console_options &&
+	    *of_console_options == 'b')
+		off = 1;
+
+	if ((line & 1) != off)
+		return 0;
+
+	con->index = line;
+	drv->cons = con;
+	add_preferred_console(con->name, line, NULL);
+
+	return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
+
 void
 sunserial_console_termios(struct console *con)
 {
-	char mode[16], buf[16], *s;
+	struct device_node *dp;
+	const char *od, *mode, *s;
 	char mode_prop[] = "ttyX-mode";
-	char cd_prop[]   = "ttyX-ignore-cd";
-	char dtr_prop[]  = "ttyX-rts-dtr-off";
-	char *ssp_console_modes_prop = "ssp-console-modes";
 	int baud, bits, stop, cflag;
 	char parity;
-	int carrier = 0;
-	int rtsdtr = 1;
-	int topnd, nd;
 
-	if (!serial_console)
-		return;
+	dp = of_find_node_by_path("/options");
+	od = of_get_property(dp, "output-device", NULL);
+	if (!strcmp(od, "rsc")) {
+		mode = of_get_property(of_console_device,
+				       "ssp-console-modes", NULL);
+		if (!mode)
+			mode = "115200,8,n,1,-";
+	} else {
+		char c;
 
-	switch (serial_console) {
-	case PROMDEV_OTTYA:
-		mode_prop[3] = 'a';
-		cd_prop[3] = 'a';
-		dtr_prop[3] = 'a';
-		break;
+		c = 'a';
+		if (of_console_options)
+			c = *of_console_options;
 
-	case PROMDEV_OTTYB:
-		mode_prop[3] = 'b';
-		cd_prop[3] = 'b';
-		dtr_prop[3] = 'b';
-		break;
+		mode_prop[3] = c;
 
-	case PROMDEV_ORSC:
-
-		nd = prom_pathtoinode("rsc");
-		if (!nd) {
-			strcpy(mode, "115200,8,n,1,-");
-			goto no_options;
-		}
-
-		if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
-			strcpy(mode, "115200,8,n,1,-");
-			goto no_options;
-		}
-
-		memset(mode, 0, sizeof(mode));
-		prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
-		goto no_options;
-
-	default:
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
+		mode = of_get_property(dp, mode_prop, NULL);
+		if (!mode)
+			mode = "9600,8,n,1,-";
 	}
 
-	topnd = prom_getchild(prom_root_node);
-	nd = prom_searchsiblings(topnd, "options");
-	if (!nd) {
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
-	}
-
-	if (!prom_node_has_property(nd, mode_prop)) {
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
-	}
-
-	memset(mode, 0, sizeof(mode));
-	prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
-	if (prom_node_has_property(nd, cd_prop)) {
-		memset(buf, 0, sizeof(buf));
-		prom_getstring(nd, cd_prop, buf, sizeof(buf));
-		if (!strcmp(buf, "false"))
-			carrier = 1;
-
-		/* XXX: this is unused below. */
-	}
-
-	if (prom_node_has_property(nd, dtr_prop)) {
-		memset(buf, 0, sizeof(buf));
-		prom_getstring(nd, dtr_prop, buf, sizeof(buf));
-		if (!strcmp(buf, "false"))
-			rtsdtr = 0;
-
-		/* XXX: this is unused below. */
-	}
-
-no_options:
 	cflag = CREAD | HUPCL | CLOCAL;
 
 	s = mode;
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
index 513916a..829d7d6 100644
--- a/drivers/serial/suncore.h
+++ b/drivers/serial/suncore.h
@@ -24,6 +24,8 @@
 
 extern int sunserial_current_minor;
 
+extern int sunserial_console_match(struct console *, struct device_node *,
+				   struct uart_driver *, int);
 extern void sunserial_console_termios(struct console *);
 
 #endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index d82be42..8ff900b 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -520,16 +520,6 @@
 	.data	=	&sunhv_reg,
 };
 
-static inline struct console *SUNHV_CONSOLE(void)
-{
-	if (con_is_present())
-		return NULL;
-
-	sunhv_console.index = 0;
-
-	return &sunhv_console;
-}
-
 static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct uart_port *port;
@@ -582,7 +572,8 @@
 	sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
 	sunserial_current_minor += 1;
 
-	sunhv_reg.cons = SUNHV_CONSOLE();
+	sunserial_console_match(&sunhv_console, op->node,
+				&sunhv_reg, port->line);
 
 	err = uart_add_one_port(&sunhv_reg, port);
 	if (err)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 8a0f9e4..bca57bb 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -968,22 +968,6 @@
 
 static inline struct console *SUNSAB_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < num_channels; i++) {
-		int this_minor = sunsab_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == num_channels)
-		return NULL;
-
-	sunsab_console.index = i;
-
 	return &sunsab_console;
 }
 #else
@@ -1080,7 +1064,12 @@
 		return err;
 	}
 
+	sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+				&sunsab_reg, up[0].port.line);
 	uart_add_one_port(&sunsab_reg, &up[0].port);
+
+	sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+				&sunsab_reg, up[1].port.line);
 	uart_add_one_port(&sunsab_reg, &up[1].port);
 
 	dev_set_drvdata(&op->dev, &up[0]);
@@ -1164,7 +1153,6 @@
 		}
 
 		sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
-		sunsab_reg.cons = SUNSAB_CONSOLE();
 		sunserial_current_minor += num_channels;
 	}
 
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 26d720b..79b1368 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1371,28 +1371,12 @@
  *	Register console.
  */
 
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < num_uart; i++) {
-		int this_minor = sunsu_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == num_uart)
-		return NULL;
-
-	sunsu_console.index = i;
-
 	return &sunsu_console;
 }
 #else
-#define SUNSU_CONSOLE(num_uart)		(NULL)
+#define SUNSU_CONSOLE()			(NULL)
 #define sunsu_serial_console_init()	do { } while (0)
 #endif
 
@@ -1482,6 +1466,8 @@
 
 	up->port.ops = &sunsu_pops;
 
+	sunserial_console_match(SUNSU_CONSOLE(), dp,
+				&sunsu_reg, up->port.line);
 	err = uart_add_one_port(&sunsu_reg, &up->port);
 	if (err)
 		goto out_unmap;
@@ -1572,7 +1558,6 @@
 			return err;
 		sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
 		sunserial_current_minor += num_uart;
-		sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
 	}
 
 	err = of_register_driver(&su_driver, &of_bus_type);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 0a3e10a..1d262c0 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1226,23 +1226,6 @@
 
 static inline struct console *SUNZILOG_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		int this_minor = sunzilog_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == NUM_CHANNELS)
-		return NULL;
-
-	sunzilog_console_ops.index = i;
-	sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
 	return &sunzilog_console_ops;
 }
 
@@ -1428,12 +1411,18 @@
 	sunzilog_init_hw(&up[1]);
 
 	if (!keyboard_mouse) {
+		if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+					    &sunzilog_reg, up[0].port.line))
+			up->flags |= SUNZILOG_FLAG_IS_CONS;
 		err = uart_add_one_port(&sunzilog_reg, &up[0].port);
 		if (err) {
 			of_iounmap(&op->resource[0],
 				   rp, sizeof(struct zilog_layout));
 			return err;
 		}
+		if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+					    &sunzilog_reg, up[1].port.line))
+			up->flags |= SUNZILOG_FLAG_IS_CONS;
 		err = uart_add_one_port(&sunzilog_reg, &up[1].port);
 		if (err) {
 			uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1531,7 +1520,6 @@
 			goto out_free_tables;
 
 		sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
-		sunzilog_reg.cons = SUNZILOG_CONSOLE();
 
 		sunserial_current_minor += uart_count;
 	}
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 0c7bf75..1399069 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2913,10 +2913,6 @@
 	int node, len, i, j, ret;
 	u32 mem, chip_id;
 
-	/* Do not attach when we have a serial console. */
-	if (!con_is_present())
-		return -ENXIO;
-
 	/*
 	 * Map memory-mapped registers.
 	 */
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index eb1a481..b87ea21 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -379,10 +379,6 @@
 	if (fb_get_options("igafb", NULL))
 		return -ENODEV;
 
-        /* Do not attach when we have a serial console. */
-        if (!con_is_present())
-                return -ENXIO;
-
         pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
                                PCI_DEVICE_ID_INTERG_1682, 0);
 	if (pdev == NULL) {
diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h
index d8f9872..4a56d84 100644
--- a/include/asm-sparc/device.h
+++ b/include/asm-sparc/device.h
@@ -3,5 +3,17 @@
  *
  * This file is released under the GPLv2
  */
-#include <asm-generic/device.h>
+#ifndef _ASM_SPARC_DEVICE_H
+#define _ASM_SPARC_DEVICE_H
+
+struct device_node;
+struct of_device;
+
+struct dev_archdata {
+	struct device_node	*prom_node;
+	struct of_device	*op;
+};
+
+#endif /* _ASM_SPARC_DEVICE_H */
+
 
diff --git a/include/asm-sparc/fb.h b/include/asm-sparc/fb.h
index c7df380..c73ca08 100644
--- a/include/asm-sparc/fb.h
+++ b/include/asm-sparc/fb.h
@@ -1,11 +1,20 @@
 #ifndef _ASM_FB_H_
 #define _ASM_FB_H_
 #include <linux/fb.h>
+#include <asm/prom.h>
 
 #define fb_pgprotect(...) do {} while (0)
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+	struct device *dev = info->device;
+	struct device_node *node;
+
+	node = dev->archdata.prom_node;
+	if (node &&
+	    node == of_console_device)
+		return 1;
+
 	return 0;
 }
 
diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h
index 91691e5..17ba82ee 100644
--- a/include/asm-sparc/oplib.h
+++ b/include/asm-sparc/oplib.h
@@ -158,32 +158,6 @@
 extern void prom_printf(char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-	PROMDEV_IKBD,			/* input from keyboard */
-	PROMDEV_ITTYA,			/* input from ttya */
-	PROMDEV_ITTYB,			/* input from ttyb */
-	PROMDEV_IRSC,			/* input from rsc */
-	PROMDEV_IVCONS,			/* input from virtual-console */
-	PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-	PROMDEV_OSCREEN,		/* to screen */
-	PROMDEV_OTTYA,			/* to ttya */
-	PROMDEV_OTTYB,			/* to ttyb */
-	PROMDEV_ORSC,			/* to rsc */
-	PROMDEV_OVCONS,			/* to virtual-console */
-	PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 
 /* Start the CPU with the given device tree node, context table, and context
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
index db9feb7..350676c 100644
--- a/include/asm-sparc/prom.h
+++ b/include/asm-sparc/prom.h
@@ -85,5 +85,9 @@
  */
 #include <linux/of.h>
 
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC_PROM_H */
diff --git a/include/asm-sparc64/fb.h b/include/asm-sparc64/fb.h
index d6cd3a1..389012e 100644
--- a/include/asm-sparc64/fb.h
+++ b/include/asm-sparc64/fb.h
@@ -3,6 +3,7 @@
 #include <linux/fb.h>
 #include <linux/fs.h>
 #include <asm/page.h>
+#include <asm/prom.h>
 
 static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
 				unsigned long off)
@@ -12,6 +13,14 @@
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+	struct device *dev = info->device;
+	struct device_node *node;
+
+	node = dev->archdata.prom_node;
+	if (node &&
+	    node == of_console_device)
+		return 1;
+
 	return 0;
 }
 
diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h
index 992f9f7..3f23c5d 100644
--- a/include/asm-sparc64/oplib.h
+++ b/include/asm-sparc64/oplib.h
@@ -140,32 +140,6 @@
 extern void prom_printf(const char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-	PROMDEV_IKBD,			/* input from keyboard */
-	PROMDEV_ITTYA,			/* input from ttya */
-	PROMDEV_ITTYB,			/* input from ttyb */
-	PROMDEV_IRSC,			/* input from rsc */
-	PROMDEV_IVCONS,			/* input from virtual-console */
-	PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-	PROMDEV_OSCREEN,		/* to screen */
-	PROMDEV_OTTYA,			/* to ttya */
-	PROMDEV_OTTYB,			/* to ttyb */
-	PROMDEV_ORSC,			/* to rsc */
-	PROMDEV_OVCONS,			/* to virtual-console */
-	PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 #ifdef CONFIG_SMP
 /* Start the CPU with the given device tree node at the passed program
@@ -319,6 +293,8 @@
 extern int prom_service_exists(const char *service_name);
 extern void prom_sun4v_guest_soft_state(void);
 
+extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
+
 /* Client interface level routines. */
 extern void prom_set_trap_table(unsigned long tba);
 extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index 23cc63f..600afe5 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -8,8 +8,9 @@
 #define _ASM_SPARC64_PARPORT_H 1
 
 #include <asm/ebus.h>
-#include <asm/isa.h>
 #include <asm/ns87303.h>
+#include <asm/of_device.h>
+#include <asm/prom.h>
 
 #define PARPORT_PC_MAX_PORTS	PARPORT_MAX
 
@@ -35,8 +36,12 @@
 	unsigned int addr;
 	unsigned int count;
 	int lock;
+
+	struct parport *port;
 } sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
 
+static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS);
+
 static __inline__ int request_dma(unsigned int dmanr, const char *device_id)
 {
 	if (dmanr >= PARPORT_PC_MAX_PORTS)
@@ -98,117 +103,145 @@
 	return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
 }
 
-static int ebus_ecpp_p(struct linux_ebus_device *edev)
+static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match)
 {
-	if (!strcmp(edev->prom_node->name, "ecpp"))
-		return 1;
-	if (!strcmp(edev->prom_node->name, "parallel")) {
-		const char *compat;
+	unsigned long base = op->resource[0].start;
+	unsigned long config = op->resource[1].start;
+	unsigned long d_base = op->resource[2].start;
+	unsigned long d_len;
+	struct device_node *parent;
+	struct parport *p;
+	int slot, err;
 
-		compat = of_get_property(edev->prom_node,
-					 "compatible", NULL);
-		if (compat &&
-		    (!strcmp(compat, "ecpp") ||
-		     !strcmp(compat, "ns87317-ecpp") ||
-		     !strcmp(compat + 13, "ecpp")))
-			return 1;
+	parent = op->node->parent;
+	if (!strcmp(parent->name, "dma")) {
+		p = parport_pc_probe_port(base, base + 0x400,
+					  op->irqs[0], PARPORT_DMA_NOFIFO,
+					  op->dev.parent);
+		if (!p)
+			return -ENOMEM;
+		dev_set_drvdata(&op->dev, p);
+		return 0;
 	}
+
+	for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) {
+		if (!test_and_set_bit(slot, dma_slot_map))
+			break;
+	}
+	err = -ENODEV;
+	if (slot >= PARPORT_PC_MAX_PORTS)
+		goto out_err;
+
+	spin_lock_init(&sparc_ebus_dmas[slot].info.lock);
+
+	d_len = (op->resource[2].end - d_base) + 1UL;
+	sparc_ebus_dmas[slot].info.regs =
+		of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA");
+
+	if (!sparc_ebus_dmas[slot].info.regs)
+		goto out_clear_map;
+
+	sparc_ebus_dmas[slot].info.flags = 0;
+	sparc_ebus_dmas[slot].info.callback = NULL;
+	sparc_ebus_dmas[slot].info.client_cookie = NULL;
+	sparc_ebus_dmas[slot].info.irq = 0xdeadbeef;
+	strcpy(sparc_ebus_dmas[slot].info.name, "parport");
+	if (ebus_dma_register(&sparc_ebus_dmas[slot].info))
+		goto out_unmap_regs;
+
+	ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1);
+
+	/* Configure IRQ to Push Pull, Level Low */
+	/* Enable ECP, set bit 2 of the CTR first */
+	outb(0x04, base + 0x02);
+	ns87303_modify(config, PCR,
+		       PCR_EPP_ENABLE |
+		       PCR_IRQ_ODRAIN,
+		       PCR_ECP_ENABLE |
+		       PCR_ECP_CLK_ENA |
+		       PCR_IRQ_POLAR);
+
+	/* CTR bit 5 controls direction of port */
+	ns87303_modify(config, PTR,
+		       0, PTR_LPT_REG_DIR);
+
+	p = parport_pc_probe_port(base, base + 0x400,
+				  op->irqs[0],
+				  slot,
+				  op->dev.parent);
+	err = -ENOMEM;
+	if (!p)
+		goto out_disable_irq;
+
+	dev_set_drvdata(&op->dev, p);
+
+	return 0;
+
+out_disable_irq:
+	ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+	ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+
+out_unmap_regs:
+	of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len);
+
+out_clear_map:
+	clear_bit(slot, dma_slot_map);
+
+out_err:
+	return err;
+}
+
+static int __devexit ecpp_remove(struct of_device *op)
+{
+	struct parport *p = dev_get_drvdata(&op->dev);
+	int slot = p->dma;
+
+	parport_pc_unregister_port(p);
+
+	if (slot != PARPORT_DMA_NOFIFO) {
+		unsigned long d_base = op->resource[2].start;
+		unsigned long d_len;
+
+		d_len = (op->resource[2].end - d_base) + 1UL;
+
+		ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+		ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+		of_iounmap(&op->resource[2],
+			   sparc_ebus_dmas[slot].info.regs,
+			   d_len);
+		clear_bit(slot, dma_slot_map);
+	}
+
 	return 0;
 }
 
-static int parport_isa_probe(int count)
+static struct of_device_id ecpp_match[] = {
+	{
+		.name = "ecpp",
+	},
+	{
+		.name = "parallel",
+		.compatible = "ecpp",
+	},
+	{
+		.name = "parallel",
+		.compatible = "ns87317-ecpp",
+	},
+	{},
+};
+
+static struct of_platform_driver ecpp_driver = {
+	.name			= "ecpp",
+	.match_table		= ecpp_match,
+	.probe			= ecpp_probe,
+	.remove			= __devexit_p(ecpp_remove),
+};
+
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
 {
-	struct sparc_isa_bridge *isa_br;
-	struct sparc_isa_device *isa_dev;
+	of_register_driver(&ecpp_driver, &of_bus_type);
 
-	for_each_isa(isa_br) {
-		for_each_isadev(isa_dev, isa_br) {
-			struct sparc_isa_device *child;
-			unsigned long base;
-
-			if (strcmp(isa_dev->prom_node->name, "dma"))
-				continue;
-
-			child = isa_dev->child;
-			while (child) {
-				if (!strcmp(child->prom_node->name, "parallel"))
-					break;
-				child = child->next;
-			}
-			if (!child)
-				continue;
-
-			base = child->resource.start;
-
-			/* No DMA, see commentary in
-			 * asm-sparc64/floppy.h:isa_floppy_init()
-			 */
-			if (parport_pc_probe_port(base, base + 0x400,
-						  child->irq, PARPORT_DMA_NOFIFO,
-						  &child->bus->self->dev))
-				count++;
-		}
-	}
-
-	return count;
-}
-
-static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
-{
-	struct linux_ebus *ebus;
-	struct linux_ebus_device *edev;
-	int count = 0;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (ebus_ecpp_p(edev)) {
-				unsigned long base = edev->resource[0].start;
-				unsigned long config = edev->resource[1].start;
-				unsigned long d_base = edev->resource[2].start;
-				unsigned long d_len;
-
-				spin_lock_init(&sparc_ebus_dmas[count].info.lock);
-				d_len = (edev->resource[2].end -
-					 d_base) + 1;
-				sparc_ebus_dmas[count].info.regs =
-					ioremap(d_base, d_len);
-				if (!sparc_ebus_dmas[count].info.regs)
-					continue;
-				sparc_ebus_dmas[count].info.flags = 0;
-				sparc_ebus_dmas[count].info.callback = NULL;
-				sparc_ebus_dmas[count].info.client_cookie = NULL;
-				sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
-				strcpy(sparc_ebus_dmas[count].info.name, "parport");
-				if (ebus_dma_register(&sparc_ebus_dmas[count].info))
-					continue;
-				ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
-
-				/* Configure IRQ to Push Pull, Level Low */
-				/* Enable ECP, set bit 2 of the CTR first */
-				outb(0x04, base + 0x02);
-				ns87303_modify(config, PCR,
-					       PCR_EPP_ENABLE |
-					       PCR_IRQ_ODRAIN,
-					       PCR_ECP_ENABLE |
-					       PCR_ECP_CLK_ENA |
-					       PCR_IRQ_POLAR);
-
-				/* CTR bit 5 controls direction of port */
-				ns87303_modify(config, PTR,
-					       0, PTR_LPT_REG_DIR);
-
-				if (parport_pc_probe_port(base, base + 0x400,
-							  edev->irqs[0],
-							  count,
-							  &ebus->self->dev))
-					count++;
-			}
-		}
-	}
-
-	count = parport_isa_probe(count);
-
-	return count;
+	return 0;
 }
 
 #endif /* !(_ASM_SPARC64_PARPORT_H */
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h
index 2b9e0d7..31dcb92 100644
--- a/include/asm-sparc64/prom.h
+++ b/include/asm-sparc64/prom.h
@@ -94,5 +94,9 @@
  */
 #include <linux/of.h>
 
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC64_PROM_H */
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 4090674..64891cb 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -115,14 +115,8 @@
 #ifndef __ASSEMBLY__
 
 extern void sun_do_break(void);
-extern int serial_console;
 extern int stop_a_enabled;
 
-static __inline__ int con_is_present(void)
-{
-	return serial_console ? 0 : 1;
-}
-
 extern void synchronize_user_stack(void);
 
 extern void __flushw_user(void);