Преглед на файлове

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

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Use alloc_pci_dev() in PCI bus probes.
  [SPARC64]: Bump PROMINTR_MAX to 32.
  [SPARC64]: Fix recursion in PROM tree building.
  [SERIAL] sunzilog: Interrupt enable before ISR handler installed
  [SPARC64] PCI: Consolidate PCI access code into pci_common.c
Linus Torvalds преди 18 години
родител
ревизия
0ab598099c

+ 1 - 1
arch/sparc64/kernel/pci.c

@@ -377,7 +377,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
 	const char *type;
 	u32 class;
 
-	dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	dev = alloc_pci_dev();
 	if (!dev)
 		return NULL;
 

+ 194 - 0
arch/sparc64/kernel/pci_common.c

@@ -14,6 +14,200 @@
 #include <asm/oplib.h>
 
 #include "pci_impl.h"
+#include "pci_sun4v.h"
+
+static int config_out_of_range(struct pci_pbm_info *pbm,
+			       unsigned long bus,
+			       unsigned long devfn,
+			       unsigned long reg)
+{
+	if (bus < pbm->pci_first_busno ||
+	    bus > pbm->pci_last_busno)
+		return 1;
+	return 0;
+}
+
+static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm,
+				 unsigned long bus,
+				 unsigned long devfn,
+				 unsigned long reg)
+{
+	unsigned long rbits = pbm->config_space_reg_bits;
+
+	if (config_out_of_range(pbm, bus, devfn, reg))
+		return NULL;
+
+	reg = (reg & ((1 << rbits) - 1));
+	devfn <<= rbits;
+	bus <<= rbits + 8;
+
+	return (void *)	(pbm->config_space | bus | devfn | reg);
+}
+
+static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+			      int where, int size, u32 *value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	unsigned char bus = bus_dev->number;
+	u32 *addr;
+	u16 tmp16;
+	u8 tmp8;
+
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+						    size, value);
+
+	switch (size) {
+	case 1:
+		*value = 0xff;
+		break;
+	case 2:
+		*value = 0xffff;
+		break;
+	case 4:
+		*value = 0xffffffff;
+		break;
+	}
+
+	addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	switch (size) {
+	case 1:
+		pci_config_read8((u8 *)addr, &tmp8);
+		*value = (u32) tmp8;
+		break;
+
+	case 2:
+		if (where & 0x01) {
+			printk("pci_read_config_word: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		pci_config_read16((u16 *)addr, &tmp16);
+		*value = (u32) tmp16;
+		break;
+
+	case 4:
+		if (where & 0x03) {
+			printk("pci_read_config_dword: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		pci_config_read32(addr, value);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+			       int where, int size, u32 value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	unsigned char bus = bus_dev->number;
+	u32 *addr;
+
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+						     size, value);
+	addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	switch (size) {
+	case 1:
+		pci_config_write8((u8 *)addr, value);
+		break;
+
+	case 2:
+		if (where & 0x01) {
+			printk("pci_write_config_word: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		pci_config_write16((u16 *)addr, value);
+		break;
+
+	case 4:
+		if (where & 0x03) {
+			printk("pci_write_config_dword: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		pci_config_write32(addr, value);
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sun4u_pci_ops = {
+	.read =		sun4u_read_pci_cfg,
+	.write =	sun4u_write_pci_cfg,
+};
+
+static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+			      int where, int size, u32 *value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	u32 devhandle = pbm->devhandle;
+	unsigned int bus = bus_dev->number;
+	unsigned int device = PCI_SLOT(devfn);
+	unsigned int func = PCI_FUNC(devfn);
+	unsigned long ret;
+
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+						    size, value);
+	if (config_out_of_range(pbm, bus, devfn, where)) {
+		ret = ~0UL;
+	} else {
+		ret = pci_sun4v_config_get(devhandle,
+				HV_PCI_DEVICE_BUILD(bus, device, func),
+				where, size);
+	}
+	switch (size) {
+	case 1:
+		*value = ret & 0xff;
+		break;
+	case 2:
+		*value = ret & 0xffff;
+		break;
+	case 4:
+		*value = ret & 0xffffffff;
+		break;
+	};
+
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+			       int where, int size, u32 value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	u32 devhandle = pbm->devhandle;
+	unsigned int bus = bus_dev->number;
+	unsigned int device = PCI_SLOT(devfn);
+	unsigned int func = PCI_FUNC(devfn);
+	unsigned long ret;
+
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+						     size, value);
+	if (config_out_of_range(pbm, bus, devfn, where)) {
+		/* Do nothing. */
+	} else {
+		ret = pci_sun4v_config_put(devhandle,
+				HV_PCI_DEVICE_BUILD(bus, device, func),
+				where, size, value);
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sun4v_pci_ops = {
+	.read =		sun4v_read_pci_cfg,
+	.write =	sun4v_write_pci_cfg,
+};
 
 void pci_get_pbm_props(struct pci_pbm_info *pbm)
 {

+ 2 - 133
arch/sparc64/kernel/pci_fire.c

@@ -27,138 +27,6 @@
 			       "i" (ASI_PHYS_BYPASS_EC_E) \
 			     : "memory")
 
-/* Fire config space address format is nearly identical to
- * that of SCHIZO and PSYCHO, except that in order to accomodate
- * PCI-E extended config space the encoding can handle 12 bits
- * of register address:
- *
- *  32     28 27 20 19    15 14      12 11  2  1 0
- * -------------------------------------------------
- * |0 0 0 0 0| bus | device | function | reg | 0 0 |
- * -------------------------------------------------
- */
-#define FIRE_CONFIG_BASE(PBM)	((PBM)->config_space)
-#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
-	(((unsigned long)(BUS)   << 20) |	\
-	 ((unsigned long)(DEVFN) << 12)  |	\
-	 ((unsigned long)(REG)))
-
-static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm,
-				      unsigned char bus,
-				      unsigned int devfn,
-				      int where)
-{
-	if (!pbm)
-		return NULL;
-	return (void *)
-		(FIRE_CONFIG_BASE(pbm) |
-		 FIRE_CONFIG_ENCODE(bus, devfn, where));
-}
-
-/* FIRE PCI configuration space accessors. */
-
-static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-			     int where, int size, u32 *value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-	u16 tmp16;
-	u8 tmp8;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-						    size, value);
-	switch (size) {
-	case 1:
-		*value = 0xff;
-		break;
-	case 2:
-		*value = 0xffff;
-		break;
-	case 4:
-		*value = 0xffffffff;
-		break;
-	}
-
-	addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	switch (size) {
-	case 1:
-		pci_config_read8((u8 *)addr, &tmp8);
-		*value = tmp8;
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_read_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_read16((u16 *)addr, &tmp16);
-		*value = tmp16;
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_read_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-
-		pci_config_read32(addr, value);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-			      int where, int size, u32 value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-						     size, value);
-	addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	switch (size) {
-	case 1:
-		pci_config_write8((u8 *)addr, value);
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_write_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_write16((u16 *)addr, value);
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_write_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-
-		pci_config_write32(addr, value);
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_fire_ops = {
-	.read	=	fire_read_pci_cfg,
-	.write	=	fire_write_pci_cfg,
-};
-
 static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
 {
 	pbm->pci_bus = pci_scan_one_pbm(pbm);
@@ -314,7 +182,8 @@ static void pci_fire_pbm_init(struct pci_controller_info *p,
 	pci_pbm_root = pbm;
 
 	pbm->scan_bus = pci_fire_scan_bus;
-	pbm->pci_ops = &pci_fire_ops;
+	pbm->pci_ops = &sun4u_pci_ops;
+	pbm->config_space_reg_bits = 12;
 
 	pbm->index = pci_num_pbms++;
 

+ 6 - 0
arch/sparc64/kernel/pci_impl.h

@@ -77,6 +77,9 @@ struct pci_pbm_info {
 	/* Base of PCI Config space, can be per-PBM or shared. */
 	unsigned long			config_space;
 
+	/* This will be 12 on PCI-E controllers, 8 elsewhere.  */
+	unsigned long			config_space_reg_bits;
+
 	/* State of 66MHz capabilities on this PBM. */
 	int				is_66mhz_capable;
 	int				all_devs_66mhz;
@@ -156,4 +159,7 @@ extern void pci_config_write8(u8 *addr, u8 val);
 extern void pci_config_write16(u16 *addr, u16 val);
 extern void pci_config_write32(u32 *addr, u32 val);
 
+extern struct pci_ops sun4u_pci_ops;
+extern struct pci_ops sun4v_pci_ops;
+
 #endif /* !(PCI_IMPL_H) */

+ 2 - 117
arch/sparc64/kernel/pci_psycho.c

@@ -94,122 +94,6 @@ static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
 		 PSYCHO_CONFIG_ENCODE(bus, devfn, where));
 }
 
-static int psycho_out_of_range(struct pci_pbm_info *pbm,
-			       unsigned char bus,
-			       unsigned char devfn)
-{
-	return ((bus == pbm->pci_first_busno) &&
-		PCI_SLOT(devfn) > 8);
-}
-
-/* PSYCHO PCI configuration space accessors. */
-
-static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-			       int where, int size, u32 *value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-	u16 tmp16;
-	u8 tmp8;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-						    size, value);
-
-	switch (size) {
-	case 1:
-		*value = 0xff;
-		break;
-	case 2:
-		*value = 0xffff;
-		break;
-	case 4:
-		*value = 0xffffffff;
-		break;
-	}
-
-	addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	if (psycho_out_of_range(pbm, bus, devfn))
-		return PCIBIOS_SUCCESSFUL;
-	switch (size) {
-	case 1:
-		pci_config_read8((u8 *)addr, &tmp8);
-		*value = (u32) tmp8;
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_read_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_read16((u16 *)addr, &tmp16);
-		*value = (u32) tmp16;
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_read_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_read32(addr, value);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-				int where, int size, u32 value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-						     size, value);
-	addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	if (psycho_out_of_range(pbm, bus, devfn))
-		return PCIBIOS_SUCCESSFUL;
-
-	switch (size) {
-	case 1:
-		pci_config_write8((u8 *)addr, value);
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_write_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_write16((u16 *)addr, value);
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_write_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_write32(addr, value);
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops psycho_ops = {
-	.read =		psycho_read_pci_cfg,
-	.write =	psycho_write_pci_cfg,
-};
-
 /* PSYCHO error handling support. */
 enum psycho_error_type {
 	UE_ERR, CE_ERR, PCI_ERR
@@ -1089,7 +973,8 @@ static void psycho_pbm_init(struct pci_controller_info *p,
 	pci_pbm_root = pbm;
 
 	pbm->scan_bus = psycho_scan_bus;
-	pbm->pci_ops = &psycho_ops;
+	pbm->pci_ops = &sun4u_pci_ops;
+	pbm->config_space_reg_bits = 8;
 
 	pbm->index = pci_num_pbms++;
 

+ 2 - 286
arch/sparc64/kernel/pci_sabre.c

@@ -205,294 +205,9 @@
 #define SABRE_MEMSPACE		0x100000000UL
 #define SABRE_MEMSPACE_SIZE	0x07fffffffUL
 
-/* UltraSparc-IIi Programmer's Manual, page 325, PCI
- * configuration space address format:
- * 
- *  32             24 23 16 15    11 10       8 7   2  1 0
- * ---------------------------------------------------------
- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
- * ---------------------------------------------------------
- */
-#define SABRE_CONFIG_BASE(PBM)	\
-	((PBM)->config_space | (1UL << 24))
-#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
-	(((unsigned long)(BUS)   << 16) |	\
-	 ((unsigned long)(DEVFN) << 8)  |	\
-	 ((unsigned long)(REG)))
-
 static int hummingbird_p;
 static struct pci_bus *sabre_root_bus;
 
-static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm,
-				     unsigned char bus,
-				     unsigned int devfn,
-				     int where)
-{
-	if (!pbm)
-		return NULL;
-	return (void *)
-		(SABRE_CONFIG_BASE(pbm) |
-		 SABRE_CONFIG_ENCODE(bus, devfn, where));
-}
-
-static int sabre_out_of_range(unsigned char devfn)
-{
-	if (hummingbird_p)
-		return 0;
-
-	return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
-		((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
-		(PCI_SLOT(devfn) > 1));
-}
-
-static int __sabre_out_of_range(struct pci_pbm_info *pbm,
-				unsigned char bus,
-				unsigned char devfn)
-{
-	if (hummingbird_p)
-		return 0;
-
-	return ((pbm->parent == 0) ||
-		((pbm == &pbm->parent->pbm_A) &&
-		 (bus == pbm->pci_first_busno) &&
-		 PCI_SLOT(devfn) > 8));
-}
-
-static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-				int where, int size, u32 *value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-	u16 tmp16;
-	u8 tmp8;
-
-	switch (size) {
-	case 1:
-		*value = 0xff;
-		break;
-	case 2:
-		*value = 0xffff;
-		break;
-	case 4:
-		*value = 0xffffffff;
-		break;
-	}
-
-	addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	if (__sabre_out_of_range(pbm, bus, devfn))
-		return PCIBIOS_SUCCESSFUL;
-
-	switch (size) {
-	case 1:
-		pci_config_read8((u8 *) addr, &tmp8);
-		*value = tmp8;
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_read_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_read16((u16 *) addr, &tmp16);
-		*value = tmp16;
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_read_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_read32(addr, value);
-		break;
-	}
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
-			      int where, int size, u32 *value)
-{
-	struct pci_pbm_info *pbm = bus->sysdata;
-
-	if (bus == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_read_pci_cfg(bus, devfn, where,
-						    size, value);
-
-	if (!bus->number && sabre_out_of_range(devfn)) {
-		switch (size) {
-		case 1:
-			*value = 0xff;
-			break;
-		case 2:
-			*value = 0xffff;
-			break;
-		case 4:
-			*value = 0xffffffff;
-			break;
-		}
-		return PCIBIOS_SUCCESSFUL;
-	}
-
-	if (bus->number || PCI_SLOT(devfn))
-		return __sabre_read_pci_cfg(bus, devfn, where, size, value);
-
-	/* When accessing PCI config space of the PCI controller itself (bus
-	 * 0, device slot 0, function 0) there are restrictions.  Each
-	 * register must be accessed as it's natural size.  Thus, for example
-	 * the Vendor ID must be accessed as a 16-bit quantity.
-	 */
-
-	switch (size) {
-	case 1:
-		if (where < 8) {
-			u32 tmp32;
-			u16 tmp16;
-
-			__sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
-			tmp16 = (u16) tmp32;
-			if (where & 1)
-				*value = tmp16 >> 8;
-			else
-				*value = tmp16 & 0xff;
-		} else
-			return __sabre_read_pci_cfg(bus, devfn, where, 1, value);
-		break;
-
-	case 2:
-		if (where < 8)
-			return __sabre_read_pci_cfg(bus, devfn, where, 2, value);
-		else {
-			u32 tmp32;
-			u8 tmp8;
-
-			__sabre_read_pci_cfg(bus, devfn, where, 1, &tmp32);
-			tmp8 = (u8) tmp32;
-			*value = tmp8;
-			__sabre_read_pci_cfg(bus, devfn, where + 1, 1, &tmp32);
-			tmp8 = (u8) tmp32;
-			*value |= tmp8 << 8;
-		}
-		break;
-
-	case 4: {
-		u32 tmp32;
-		u16 tmp16;
-
-		sabre_read_pci_cfg(bus, devfn, where, 2, &tmp32);
-		tmp16 = (u16) tmp32;
-		*value = tmp16;
-		sabre_read_pci_cfg(bus, devfn, where + 2, 2, &tmp32);
-		tmp16 = (u16) tmp32;
-		*value |= tmp16 << 16;
-		break;
-	}
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-				 int where, int size, u32 value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-
-	addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	if (__sabre_out_of_range(pbm, bus, devfn))
-		return PCIBIOS_SUCCESSFUL;
-
-	switch (size) {
-	case 1:
-		pci_config_write8((u8 *) addr, value);
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_write_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_write16((u16 *) addr, value);
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_write_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_write32(addr, value);
-		break;
-	}
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
-			       int where, int size, u32 value)
-{
-	struct pci_pbm_info *pbm = bus->sysdata;
-
-	if (bus == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_write_pci_cfg(bus, devfn, where,
-						     size, value);
-
-	if (bus->number)
-		return __sabre_write_pci_cfg(bus, devfn, where, size, value);
-
-	if (sabre_out_of_range(devfn))
-		return PCIBIOS_SUCCESSFUL;
-
-	switch (size) {
-	case 1:
-		if (where < 8) {
-			u32 tmp32;
-			u16 tmp16;
-
-			__sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
-			tmp16 = (u16) tmp32;
-			if (where & 1) {
-				value &= 0x00ff;
-				value |= tmp16 << 8;
-			} else {
-				value &= 0xff00;
-				value |= tmp16;
-			}
-			tmp32 = (u32) tmp16;
-			return __sabre_write_pci_cfg(bus, devfn, where & ~1, 2, tmp32);
-		} else
-			return __sabre_write_pci_cfg(bus, devfn, where, 1, value);
-		break;
-	case 2:
-		if (where < 8)
-			return __sabre_write_pci_cfg(bus, devfn, where, 2, value);
-		else {
-			__sabre_write_pci_cfg(bus, devfn, where, 1, value & 0xff);
-			__sabre_write_pci_cfg(bus, devfn, where + 1, 1, value >> 8);
-		}
-		break;
-	case 4:
-		sabre_write_pci_cfg(bus, devfn, where, 2, value & 0xffff);
-		sabre_write_pci_cfg(bus, devfn, where + 2, 2, value >> 16);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops sabre_ops = {
-	.read =		sabre_read_pci_cfg,
-	.write =	sabre_write_pci_cfg,
-};
-
 /* SABRE error handling support. */
 static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
 				    unsigned long afsr,
@@ -1010,7 +725,8 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *p
 	printk("%s: SABRE PCI Bus Module\n", pbm->name);
 
 	pbm->scan_bus = sabre_scan_bus;
-	pbm->pci_ops = &sabre_ops;
+	pbm->pci_ops = &sun4u_pci_ops;
+	pbm->config_space_reg_bits = 8;
 
 	pbm->index = pci_num_pbms++;
 

+ 2 - 120
arch/sparc64/kernel/pci_schizo.c

@@ -104,125 +104,6 @@ static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm,
 		 SCHIZO_CONFIG_ENCODE(bus, devfn, where));
 }
 
-/* Just make sure the bus number is in range.  */
-static int schizo_out_of_range(struct pci_pbm_info *pbm,
-			       unsigned char bus,
-			       unsigned char devfn)
-{
-	if (bus < pbm->pci_first_busno ||
-	    bus > pbm->pci_last_busno)
-		return 1;
-	return 0;
-}
-
-/* SCHIZO PCI configuration space accessors. */
-
-static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-			       int where, int size, u32 *value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-	u16 tmp16;
-	u8 tmp8;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-						    size, value);
-	switch (size) {
-	case 1:
-		*value = 0xff;
-		break;
-	case 2:
-		*value = 0xffff;
-		break;
-	case 4:
-		*value = 0xffffffff;
-		break;
-	}
-
-	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	if (schizo_out_of_range(pbm, bus, devfn))
-		return PCIBIOS_SUCCESSFUL;
-	switch (size) {
-	case 1:
-		pci_config_read8((u8 *)addr, &tmp8);
-		*value = tmp8;
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_read_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_read16((u16 *)addr, &tmp16);
-		*value = tmp16;
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_read_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_read32(addr, value);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-				int where, int size, u32 value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	unsigned char bus = bus_dev->number;
-	u32 *addr;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-						     size, value);
-	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
-	if (!addr)
-		return PCIBIOS_SUCCESSFUL;
-
-	if (schizo_out_of_range(pbm, bus, devfn))
-		return PCIBIOS_SUCCESSFUL;
-
-	switch (size) {
-	case 1:
-		pci_config_write8((u8 *)addr, value);
-		break;
-
-	case 2:
-		if (where & 0x01) {
-			printk("pci_write_config_word: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-		pci_config_write16((u16 *)addr, value);
-		break;
-
-	case 4:
-		if (where & 0x03) {
-			printk("pci_write_config_dword: misaligned reg [%x]\n",
-			       where);
-			return PCIBIOS_SUCCESSFUL;
-		}
-
-		pci_config_write32(addr, value);
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops schizo_ops = {
-	.read =		schizo_read_pci_cfg,
-	.write =	schizo_write_pci_cfg,
-};
-
 /* SCHIZO error handling support. */
 enum schizo_error_type {
 	UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
@@ -1494,7 +1375,8 @@ static void schizo_pbm_init(struct pci_controller_info *p,
 	pci_pbm_root = pbm;
 
 	pbm->scan_bus = schizo_scan_bus;
-	pbm->pci_ops = &schizo_ops;
+	pbm->pci_ops = &sun4u_pci_ops;
+	pbm->config_space_reg_bits = 8;
 
 	pbm->index = pci_num_pbms++;
 

+ 2 - 84
arch/sparc64/kernel/pci_sun4v.c

@@ -593,89 +593,6 @@ const struct pci_iommu_ops pci_sun4v_iommu_ops = {
 	.dma_sync_sg_for_cpu		= pci_4v_dma_sync_sg_for_cpu,
 };
 
-static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func)
-{
-	if (bus < pbm->pci_first_busno ||
-	    bus > pbm->pci_last_busno)
-		return 1;
-	return 0;
-}
-
-static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-				  int where, int size, u32 *value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	u32 devhandle = pbm->devhandle;
-	unsigned int bus = bus_dev->number;
-	unsigned int device = PCI_SLOT(devfn);
-	unsigned int func = PCI_FUNC(devfn);
-	unsigned long ret;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-						    size, value);
-	if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
-		ret = ~0UL;
-	} else {
-		ret = pci_sun4v_config_get(devhandle,
-				HV_PCI_DEVICE_BUILD(bus, device, func),
-				where, size);
-#if 0
-		printk("rcfg: [%x:%x:%x:%d]=[%lx]\n",
-		       devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
-		       where, size, ret);
-#endif
-	}
-	switch (size) {
-	case 1:
-		*value = ret & 0xff;
-		break;
-	case 2:
-		*value = ret & 0xffff;
-		break;
-	case 4:
-		*value = ret & 0xffffffff;
-		break;
-	};
-
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-				   int where, int size, u32 value)
-{
-	struct pci_pbm_info *pbm = bus_dev->sysdata;
-	u32 devhandle = pbm->devhandle;
-	unsigned int bus = bus_dev->number;
-	unsigned int device = PCI_SLOT(devfn);
-	unsigned int func = PCI_FUNC(devfn);
-	unsigned long ret;
-
-	if (bus_dev == pbm->pci_bus && devfn == 0x00)
-		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-						     size, value);
-	if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
-		/* Do nothing. */
-	} else {
-		ret = pci_sun4v_config_put(devhandle,
-				HV_PCI_DEVICE_BUILD(bus, device, func),
-				where, size, value);
-#if 0
-		printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n",
-		       devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
-		       where, size, value, ret);
-#endif
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_sun4v_ops = {
-	.read =		pci_sun4v_read_pci_cfg,
-	.write =	pci_sun4v_write_pci_cfg,
-};
-
-
 static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
 {
 	struct property *prop;
@@ -1238,7 +1155,8 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
 	pci_pbm_root = pbm;
 
 	pbm->scan_bus = pci_sun4v_scan_bus;
-	pbm->pci_ops = &pci_sun4v_ops;
+	pbm->pci_ops = &sun4v_pci_ops;
+	pbm->config_space_reg_bits = 12;
 
 	pbm->index = pci_num_pbms++;
 

+ 15 - 4
arch/sparc64/kernel/prom.c

@@ -1636,10 +1636,21 @@ static struct device_node * __init create_node(phandle node, struct device_node
 
 static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
 {
+	struct device_node *ret = NULL, *prev_sibling = NULL;
 	struct device_node *dp;
 
-	dp = create_node(node, parent);
-	if (dp) {
+	while (1) {
+		dp = create_node(node, parent);
+		if (!dp)
+			break;
+
+		if (prev_sibling)
+			prev_sibling->sibling = dp;
+
+		if (!ret)
+			ret = dp;
+		prev_sibling = dp;
+
 		*(*nextp) = dp;
 		*nextp = &dp->allnext;
 
@@ -1648,10 +1659,10 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
 
 		dp->child = build_tree(dp, prom_getchild(node), nextp);
 
-		dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+		node = prom_getsibling(node);
 	}
 
-	return dp;
+	return ret;
 }
 
 void __init prom_build_devicetree(void)

+ 104 - 34
drivers/serial/sunzilog.c

@@ -92,6 +92,8 @@ struct uart_sunzilog_port {
 #define SUNZILOG_FLAG_REGS_HELD		0x00000040
 #define SUNZILOG_FLAG_TX_STOPPED	0x00000080
 #define SUNZILOG_FLAG_TX_ACTIVE		0x00000100
+#define SUNZILOG_FLAG_ESCC		0x00000200
+#define SUNZILOG_FLAG_ISR_HANDLER	0x00000400
 
 	unsigned int cflag;
 
@@ -174,9 +176,11 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
 /* This function must only be called when the TX is not busy.  The UART
  * port lock must be held and local interrupts disabled.
  */
-static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
+static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
 {
 	int i;
+	int escc;
+	unsigned char r15;
 
 	/* Let pending transmits finish.  */
 	for (i = 0; i < 1000; i++) {
@@ -229,11 +233,25 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
 	write_zsreg(channel, R14, regs[R14]);
 
 	/* External status interrupt control.  */
-	write_zsreg(channel, R15, regs[R15]);
+	write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
+
+	/* ESCC Extension Register */
+	r15 = read_zsreg(channel, R15);
+	if (r15 & 0x01)	{
+		write_zsreg(channel, R7,  regs[R7p]);
+
+		/* External status interrupt and FIFO control.  */
+		write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
+		escc = 1;
+	} else {
+		 /* Clear FIFO bit case it is an issue */
+		regs[R15] &= ~FIFOEN;
+		escc = 0;
+	}
 
 	/* Reset external status interrupts.  */
-	write_zsreg(channel, R0, RES_EXT_INT);
-	write_zsreg(channel, R0, RES_EXT_INT);
+	write_zsreg(channel, R0, RES_EXT_INT); /* First Latch  */
+	write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
 
 	/* Rewrite R3/R5, this time without enables masked.  */
 	write_zsreg(channel, R3, regs[R3]);
@@ -241,6 +259,8 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
 
 	/* Rewrite R1, this time without IRQ enabled masked.  */
 	write_zsreg(channel, R1, regs[R1]);
+
+	return escc;
 }
 
 /* Reprogram the Zilog channel HW registers with the copies found in the
@@ -731,7 +751,7 @@ static void sunzilog_enable_ms(struct uart_port *port)
 		up->curregs[R15] = new_reg;
 
 		/* NOTE: Not subject to 'transmitter active' rule.  */ 
-		write_zsreg(channel, R15, up->curregs[R15]);
+		write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
 	}
 }
 
@@ -861,44 +881,44 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
 	up->curregs[R14] = BRSRC | BRENAB;
 
 	/* Character size, stop bits, and parity. */
-	up->curregs[3] &= ~RxN_MASK;
-	up->curregs[5] &= ~TxN_MASK;
+	up->curregs[R3] &= ~RxN_MASK;
+	up->curregs[R5] &= ~TxN_MASK;
 	switch (cflag & CSIZE) {
 	case CS5:
-		up->curregs[3] |= Rx5;
-		up->curregs[5] |= Tx5;
+		up->curregs[R3] |= Rx5;
+		up->curregs[R5] |= Tx5;
 		up->parity_mask = 0x1f;
 		break;
 	case CS6:
-		up->curregs[3] |= Rx6;
-		up->curregs[5] |= Tx6;
+		up->curregs[R3] |= Rx6;
+		up->curregs[R5] |= Tx6;
 		up->parity_mask = 0x3f;
 		break;
 	case CS7:
-		up->curregs[3] |= Rx7;
-		up->curregs[5] |= Tx7;
+		up->curregs[R3] |= Rx7;
+		up->curregs[R5] |= Tx7;
 		up->parity_mask = 0x7f;
 		break;
 	case CS8:
 	default:
-		up->curregs[3] |= Rx8;
-		up->curregs[5] |= Tx8;
+		up->curregs[R3] |= Rx8;
+		up->curregs[R5] |= Tx8;
 		up->parity_mask = 0xff;
 		break;
 	};
-	up->curregs[4] &= ~0x0c;
+	up->curregs[R4] &= ~0x0c;
 	if (cflag & CSTOPB)
-		up->curregs[4] |= SB2;
+		up->curregs[R4] |= SB2;
 	else
-		up->curregs[4] |= SB1;
+		up->curregs[R4] |= SB1;
 	if (cflag & PARENB)
-		up->curregs[4] |= PAR_ENAB;
+		up->curregs[R4] |= PAR_ENAB;
 	else
-		up->curregs[4] &= ~PAR_ENAB;
+		up->curregs[R4] &= ~PAR_ENAB;
 	if (!(cflag & PARODD))
-		up->curregs[4] |= PAR_EVEN;
+		up->curregs[R4] |= PAR_EVEN;
 	else
-		up->curregs[4] &= ~PAR_EVEN;
+		up->curregs[R4] &= ~PAR_EVEN;
 
 	up->port.read_status_mask = Rx_OVR;
 	if (iflag & INPCK)
@@ -952,7 +972,9 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static const char *sunzilog_type(struct uart_port *port)
 {
-	return "zs";
+	struct uart_sunzilog_port *up = UART_ZILOG(port);
+
+	return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
 }
 
 /* We do not request/release mappings of the registers here, this
@@ -1170,7 +1192,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
 
 	spin_lock_irqsave(&up->port.lock, flags);
 
-	up->curregs[R15] = BRKIE;
+	up->curregs[R15] |= BRKIE;
 	sunzilog_convert_to_zs(up, con->cflag, 0, brg);
 
 	sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1229,7 +1251,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
 		baud = 4800;
 	}
 
-	up->curregs[R15] = BRKIE;
+	up->curregs[R15] |= BRKIE;
 	brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
 	sunzilog_convert_to_zs(up, up->cflag, 0, brg);
 	sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1283,8 +1305,18 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
 
 	if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
 			 SUNZILOG_FLAG_CONS_MOUSE)) {
+		up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+		up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+		up->curregs[R3] = RxENAB | Rx8;
+		up->curregs[R5] = TxENAB | Tx8;
+		up->curregs[R6] = 0x00; /* SDLC Address */
+		up->curregs[R7] = 0x7E; /* SDLC Flag    */
+		up->curregs[R9] = NV;
+		up->curregs[R7p] = 0x00;
 		sunzilog_init_kbdms(up, up->port.line);
-		up->curregs[R9] |= (NV | MIE);
+		/* Only enable interrupts if an ISR handler available */
+		if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+			up->curregs[R9] |= MIE;
 		write_zsreg(channel, R9, up->curregs[R9]);
 	} else {
 		/* Normal serial TTY. */
@@ -1293,7 +1325,9 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
 		up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
 		up->curregs[R3] = RxENAB | Rx8;
 		up->curregs[R5] = TxENAB | Tx8;
-		up->curregs[R9] = NV | MIE;
+		up->curregs[R6] = 0x00; /* SDLC Address */
+		up->curregs[R7] = 0x7E; /* SDLC Flag    */
+		up->curregs[R9] = NV;
 		up->curregs[R10] = NRZ;
 		up->curregs[R11] = TCBR | RCBR;
 		baud = 9600;
@@ -1301,7 +1335,14 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
 		up->curregs[R12] = (brg & 0xff);
 		up->curregs[R13] = (brg >> 8) & 0xff;
 		up->curregs[R14] = BRSRC | BRENAB;
-		__load_zsregs(channel, up->curregs);
+		up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
+		up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
+		if (__load_zsregs(channel, up->curregs)) {
+			up->flags |= SUNZILOG_FLAG_ESCC;
+		}
+		/* Only enable interrupts if an ISR handler available */
+		if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+			up->curregs[R9] |= MIE;
 		write_zsreg(channel, R9, up->curregs[R9]);
 	}
 
@@ -1390,12 +1431,14 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
 			return err;
 		}
 	} else {
-		printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
-		       "is a zs\n",
-		       op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
-		printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
-		       "is a zs\n",
-		       op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
+		printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
+		       "is a %s\n",
+		       op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
+		       sunzilog_type (&up[0].port));
+		printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
+		       "is a %s\n",
+		       op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
+		       sunzilog_type (&up[1].port));
 	}
 
 	dev_set_drvdata(&op->dev, &up[0]);
@@ -1487,10 +1530,23 @@ static int __init sunzilog_init(void)
 		goto out_unregister_uart;
 
 	if (zilog_irq != -1) {
+		struct uart_sunzilog_port *up = sunzilog_irq_chain;
 		err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
 				  "zs", sunzilog_irq_chain);
 		if (err)
 			goto out_unregister_driver;
+
+		/* Enable Interrupts */
+		while (up) {
+			struct zilog_channel __iomem *channel;
+
+			/* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
+			channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+			up->flags       |= SUNZILOG_FLAG_ISR_HANDLER;
+			up->curregs[R9] |= MIE;
+			write_zsreg(channel, R9, up->curregs[R9]);
+			up = up->next;
+		}
 	}
 
 out:
@@ -1515,6 +1571,20 @@ static void __exit sunzilog_exit(void)
 	of_unregister_driver(&zs_driver);
 
 	if (zilog_irq != -1) {
+		struct uart_sunzilog_port *up = sunzilog_irq_chain;
+
+		/* Disable Interrupts */
+		while (up) {
+			struct zilog_channel __iomem *channel;
+
+			/* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
+			channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+			up->flags       &= ~SUNZILOG_FLAG_ISR_HANDLER;
+			up->curregs[R9] &= ~MIE;
+			write_zsreg(channel, R9, up->curregs[R9]);
+			up = up->next;
+		}
+
 		free_irq(zilog_irq, sunzilog_irq_chain);
 		zilog_irq = -1;
 	}

+ 18 - 1
drivers/serial/sunzilog.h

@@ -13,7 +13,8 @@ struct zilog_layout {
 	struct zilog_channel channelA;
 };
 
-#define NUM_ZSREGS    16
+#define	NUM_ZSREGS	17
+#define	R7p		16 /* Written as R7 with P15 bit 0 set */
 
 /* Conversion routines to/from brg time constants from/to bits
  * per second.
@@ -127,6 +128,15 @@ struct zilog_layout {
 
 /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
 
+/* Write Register 7' (ESCC Only) */
+#define	AUTO_TxFLAG	1	/* Automatic Tx SDLC Flag */
+#define	AUTO_EOM_RST	2	/* Automatic EOM Reset */
+#define	AUTOnRTS	4	/* Automatic /RTS pin deactivation */
+#define	RxFIFO_LVL	8	/* Receive FIFO interrupt level */
+#define	nDTRnREQ	0x10	/* /DTR/REQ timing */
+#define	TxFIFO_LVL	0x20	/* Transmit FIFO interrupt level */
+#define	EXT_RD_EN	0x40	/* Extended read register enable */
+
 /* Write Register 8 (transmit buffer) */
 
 /* Write Register 9 (Master interrupt control) */
@@ -135,6 +145,7 @@ struct zilog_layout {
 #define	DLC	4	/* Disable Lower Chain */
 #define	MIE	8	/* Master Interrupt Enable */
 #define	STATHI	0x10	/* Status high */
+#define	SWIACK  0x20    /* Software Interrupt Ack (not on NMOS) */
 #define	NORESET	0	/* No reset on write to R9 */
 #define	CHRB	0x40	/* Reset channel B */
 #define	CHRA	0x80	/* Reset channel A */
@@ -187,7 +198,9 @@ struct zilog_layout {
 #define	SNRZI	0xe0	/* Set NRZI mode */
 
 /* Write Register 15 (external/status interrupt control) */
+#define	WR7pEN	1	/* WR7' Enable (ESCC only) */
 #define	ZCIE	2	/* Zero count IE */
+#define	FIFOEN	4	/* FIFO Enable (ESCC only) */
 #define	DCDIE	8	/* DCD IE */
 #define	SYNCIE	0x10	/* Sync/hunt IE */
 #define	CTSIE	0x20	/* CTS IE */
@@ -241,6 +254,10 @@ struct zilog_layout {
 #define	CHATxIP	0x10		/* Channel A Tx IP */
 #define	CHARxIP	0x20		/* Channel A Rx IP */
 
+/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
+
+/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
+
 /* Read Register 8 (receive data register) */
 
 /* Read Register 10  (misc status bits) */

+ 1 - 1
include/asm-sparc64/openprom.h

@@ -177,7 +177,7 @@ struct linux_nodeops {
 /* More fun PROM structures for device probing. */
 #define PROMREG_MAX     24
 #define PROMVADDR_MAX   16
-#define PROMINTR_MAX    15
+#define PROMINTR_MAX    32
 
 struct linux_prom_registers {
 	unsigned which_io;	/* hi part of physical address			*/