Просмотр исходного кода

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

* HEAD:
  [SPARC]: Fix OF register translations under sub-PCI busses.
  [SPARC64]: Refine Sabre wsync logic.
  [SERIAL] sunsu: Handle keyboard and mouse ports directly.
  [SPARC64]: Fix 2 bugs in sabre_irq_build()
  [SPARC64]: Update defconfig.
  [SPARC64]: Fix make headers_install
  [SPARC64]: of_device_register() error checking fix
Linus Torvalds 19 лет назад
Родитель
Сommit
0e2ffbf650

+ 113 - 60
arch/sparc/kernel/of_device.c

@@ -183,7 +183,7 @@ struct bus_type of_bus_type = {
 };
 EXPORT_SYMBOL(of_bus_type);
 
-static inline u64 of_read_addr(u32 *cell, int size)
+static inline u64 of_read_addr(const u32 *cell, int size)
 {
 	u64 r = 0;
 	while (size--)
@@ -209,8 +209,8 @@ struct of_bus {
 	int		(*match)(struct device_node *parent);
 	void		(*count_cells)(struct device_node *child,
 				       int *addrc, int *sizec);
-	u64		(*map)(u32 *addr, u32 *range, int na, int ns, int pna);
-	int		(*translate)(u32 *addr, u64 offset, int na);
+	int		(*map)(u32 *addr, const u32 *range,
+			       int na, int ns, int pna);
 	unsigned int	(*get_flags)(u32 *addr);
 };
 
@@ -224,27 +224,49 @@ static void of_bus_default_count_cells(struct device_node *dev,
 	get_cells(dev, addrc, sizec);
 }
 
-static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+/* Make sure the least significant 64-bits are in-range.  Even
+ * for 3 or 4 cell values it is a good enough approximation.
+ */
+static int of_out_of_range(const u32 *addr, const u32 *base,
+			   const u32 *size, int na, int ns)
 {
-	u64 cp, s, da;
+	u64 a = of_read_addr(addr, na);
+	u64 b = of_read_addr(base, na);
+
+	if (a < b)
+		return 1;
 
-	cp = of_read_addr(range, na);
-	s  = of_read_addr(range + na + pna, ns);
-	da = of_read_addr(addr, na);
+	b += of_read_addr(size, ns);
+	if (a >= b)
+		return 1;
 
-	if (da < cp || da >= (cp + s))
-		return OF_BAD_ADDR;
-	return da - cp;
+	return 0;
 }
 
-static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+static int of_bus_default_map(u32 *addr, const u32 *range,
+			      int na, int ns, int pna)
 {
-	u64 a = of_read_addr(addr, na);
-	memset(addr, 0, na * 4);
-	a += offset;
-	if (na > 1)
-		addr[na - 2] = a >> 32;
-	addr[na - 1] = a & 0xffffffffu;
+	u32 result[OF_MAX_ADDR_CELLS];
+	int i;
+
+	if (ns > 2) {
+		printk("of_device: Cannot handle size cells (%d) > 2.", ns);
+		return -EINVAL;
+	}
+
+	if (of_out_of_range(addr, range, range + na + pna, na, ns))
+		return -EINVAL;
+
+	/* Start with the parent range base.  */
+	memcpy(result, range + na, pna * 4);
+
+	/* Add in the child address offset.  */
+	for (i = 0; i < na; i++)
+		result[pna - 1 - i] +=
+			(addr[na - 1 - i] -
+			 range[na - 1 - i]);
+
+	memcpy(addr, result, pna * 4);
 
 	return 0;
 }
@@ -254,14 +276,26 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
 	return IORESOURCE_MEM;
 }
 
-
 /*
  * PCI bus specific translator
  */
 
 static int of_bus_pci_match(struct device_node *np)
 {
-	return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex");
+	if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+		/* Do not do PCI specific frobbing if the
+		 * PCI bridge lacks a ranges property.  We
+		 * want to pass it through up to the next
+		 * parent as-is, not with the PCI translate
+		 * method which chops off the top address cell.
+		 */
+		if (!of_find_property(np, "ranges", NULL))
+			return 0;
+
+		return 1;
+	}
+
+	return 0;
 }
 
 static void of_bus_pci_count_cells(struct device_node *np,
@@ -273,27 +307,32 @@ static void of_bus_pci_count_cells(struct device_node *np,
 		*sizec = 2;
 }
 
-static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+static int of_bus_pci_map(u32 *addr, const u32 *range,
+			  int na, int ns, int pna)
 {
-	u64 cp, s, da;
+	u32 result[OF_MAX_ADDR_CELLS];
+	int i;
 
 	/* Check address type match */
 	if ((addr[0] ^ range[0]) & 0x03000000)
-		return OF_BAD_ADDR;
+		return -EINVAL;
 
-	/* Read address values, skipping high cell */
-	cp = of_read_addr(range + 1, na - 1);
-	s  = of_read_addr(range + na + pna, ns);
-	da = of_read_addr(addr + 1, na - 1);
+	if (of_out_of_range(addr + 1, range + 1, range + na + pna,
+			    na - 1, ns))
+		return -EINVAL;
 
-	if (da < cp || da >= (cp + s))
-		return OF_BAD_ADDR;
-	return da - cp;
-}
+	/* Start with the parent range base.  */
+	memcpy(result, range + na, pna * 4);
 
-static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
-{
-	return of_bus_default_translate(addr + 1, offset, na - 1);
+	/* Add in the child address offset, skipping high cell.  */
+	for (i = 0; i < na - 1; i++)
+		result[pna - 1 - i] +=
+			(addr[na - 1 - i] -
+			 range[na - 1 - i]);
+
+	memcpy(addr, result, pna * 4);
+
+	return 0;
 }
 
 static unsigned int of_bus_pci_get_flags(u32 *addr)
@@ -332,16 +371,11 @@ static void of_bus_sbus_count_cells(struct device_node *child,
 		*sizec = 1;
 }
 
-static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna)
+static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
 {
 	return of_bus_default_map(addr, range, na, ns, pna);
 }
 
-static int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
-{
-	return of_bus_default_translate(addr, offset, na);
-}
-
 static unsigned int of_bus_sbus_get_flags(u32 *addr)
 {
 	return IORESOURCE_MEM;
@@ -360,7 +394,6 @@ static struct of_bus of_busses[] = {
 		.match = of_bus_pci_match,
 		.count_cells = of_bus_pci_count_cells,
 		.map = of_bus_pci_map,
-		.translate = of_bus_pci_translate,
 		.get_flags = of_bus_pci_get_flags,
 	},
 	/* SBUS */
@@ -370,7 +403,6 @@ static struct of_bus of_busses[] = {
 		.match = of_bus_sbus_match,
 		.count_cells = of_bus_sbus_count_cells,
 		.map = of_bus_sbus_map,
-		.translate = of_bus_sbus_translate,
 		.get_flags = of_bus_sbus_get_flags,
 	},
 	/* Default */
@@ -380,7 +412,6 @@ static struct of_bus of_busses[] = {
 		.match = NULL,
 		.count_cells = of_bus_default_count_cells,
 		.map = of_bus_default_map,
-		.translate = of_bus_default_translate,
 		.get_flags = of_bus_default_get_flags,
 	},
 };
@@ -405,33 +436,34 @@ static int __init build_one_resource(struct device_node *parent,
 	u32 *ranges;
 	unsigned int rlen;
 	int rone;
-	u64 offset = OF_BAD_ADDR;
 
 	ranges = of_get_property(parent, "ranges", &rlen);
 	if (ranges == NULL || rlen == 0) {
-		offset = of_read_addr(addr, na);
-		memset(addr, 0, pna * 4);
-		goto finish;
+		u32 result[OF_MAX_ADDR_CELLS];
+		int i;
+
+		memset(result, 0, pna * 4);
+		for (i = 0; i < na; i++)
+			result[pna - 1 - i] =
+				addr[na - 1 - i];
+
+		memcpy(addr, result, pna * 4);
+		return 0;
 	}
 
 	/* Now walk through the ranges */
 	rlen /= 4;
 	rone = na + pna + ns;
 	for (; rlen >= rone; rlen -= rone, ranges += rone) {
-		offset = bus->map(addr, ranges, na, ns, pna);
-		if (offset != OF_BAD_ADDR)
-			break;
+		if (!bus->map(addr, ranges, na, ns, pna))
+			return 0;
 	}
-	if (offset == OF_BAD_ADDR)
-		return 1;
 
-	memcpy(addr, ranges + na, 4 * pna);
-
-finish:
-	/* Translate it into parent bus space */
-	return pbus->translate(addr, offset, pna);
+	return 1;
 }
 
+static int of_resource_verbose;
+
 static void __init build_device_resources(struct of_device *op,
 					  struct device *parent)
 {
@@ -497,7 +529,8 @@ static void __init build_device_resources(struct of_device *op,
 			pbus = of_match_bus(pp);
 			pbus->count_cells(dp, &pna, &pns);
 
-			if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna))
+			if (build_one_resource(dp, bus, pbus, addr,
+					       dna, dns, pna))
 				break;
 
 			dna = pna;
@@ -507,6 +540,12 @@ static void __init build_device_resources(struct of_device *op,
 
 	build_res:
 		memset(r, 0, sizeof(*r));
+
+		if (of_resource_verbose)
+			printk("%s reg[%d] -> %llx\n",
+			       op->node->full_name, index,
+			       result);
+
 		if (result != OF_BAD_ADDR) {
 			r->start = result & 0xffffffff;
 			r->end = result + size - 1;
@@ -643,6 +682,18 @@ static int __init of_bus_driver_init(void)
 
 postcore_initcall(of_bus_driver_init);
 
+static int __init of_debug(char *str)
+{
+	int val = 0;
+
+	get_option(&str, &val);
+	if (val & 1)
+		of_resource_verbose = 1;
+	return 1;
+}
+
+__setup("of_debug=", of_debug);
+
 int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
 {
 	/* initialize common driver fields */
@@ -695,9 +746,11 @@ int of_device_register(struct of_device *ofdev)
 	if (rc)
 		return rc;
 
-	device_create_file(&ofdev->dev, &dev_attr_devspec);
+	rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+	if (rc)
+		device_unregister(&ofdev->dev);
 
-	return 0;
+	return rc;
 }
 
 void of_device_unregister(struct of_device *ofdev)

+ 31 - 8
arch/sparc64/defconfig

@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17
-# Fri Jun 23 23:17:09 2006
+# Linux kernel version: 2.6.18-rc1
+# Wed Jul 12 14:00:58 2006
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -18,6 +18,7 @@ CONFIG_SECCOMP=y
 CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
 # Code maturity level options
@@ -51,10 +52,12 @@ CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
+CONFIG_RT_MUTEXES=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_SHMEM=y
 CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 # CONFIG_SLOB is not set
@@ -127,8 +130,8 @@ CONFIG_SPARSEMEM=y
 CONFIG_HAVE_MEMORY_PRESENT=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPARSEMEM_EXTREME=y
-CONFIG_MEMORY_HOTPLUG=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
@@ -203,7 +206,6 @@ CONFIG_TCP_CONG_VEGAS=m
 CONFIG_TCP_CONG_SCALABLE=m
 CONFIG_TCP_CONG_LP=m
 CONFIG_TCP_CONG_VENO=m
-CONFIG_TCP_CONG_COMPOUND=m
 CONFIG_IPV6=m
 CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
@@ -461,9 +463,8 @@ CONFIG_MD_LINEAR=m
 CONFIG_MD_RAID0=m
 CONFIG_MD_RAID1=m
 CONFIG_MD_RAID10=m
-CONFIG_MD_RAID5=m
+CONFIG_MD_RAID456=m
 # CONFIG_MD_RAID5_RESHAPE is not set
-CONFIG_MD_RAID6=m
 CONFIG_MD_MULTIPATH=m
 # CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=m
@@ -663,6 +664,7 @@ CONFIG_SERIO_RAW=m
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -693,6 +695,7 @@ CONFIG_UNIX98_PTYS=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 CONFIG_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
@@ -839,12 +842,13 @@ CONFIG_VIDEO_V4L2=y
 #
 # Graphics support
 #
+# CONFIG_FIRMWARE_EDID is not set
 CONFIG_FB=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_MACMODES is not set
-# CONFIG_FB_FIRMWARE_EDID is not set
+# CONFIG_FB_BACKLIGHT is not set
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 # CONFIG_FB_CIRRUS is not set
@@ -954,6 +958,18 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
@@ -1263,6 +1279,7 @@ CONFIG_RAMFS=y
 # CONFIG_NFSD is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
+# CONFIG_CIFS_DEBUG2 is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
@@ -1331,14 +1348,19 @@ CONFIG_KPROBES=y
 #
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_DETECT_SOFTLOCKUP=y
 CONFIG_SCHEDSTATS=y
 # CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
@@ -1402,3 +1424,4 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y

+ 166 - 148
arch/sparc64/kernel/of_device.c

@@ -210,7 +210,7 @@ struct bus_type of_bus_type = {
 };
 EXPORT_SYMBOL(of_bus_type);
 
-static inline u64 of_read_addr(u32 *cell, int size)
+static inline u64 of_read_addr(const u32 *cell, int size)
 {
 	u64 r = 0;
 	while (size--)
@@ -236,8 +236,8 @@ struct of_bus {
 	int		(*match)(struct device_node *parent);
 	void		(*count_cells)(struct device_node *child,
 				       int *addrc, int *sizec);
-	u64		(*map)(u32 *addr, u32 *range, int na, int ns, int pna);
-	int		(*translate)(u32 *addr, u64 offset, int na);
+	int		(*map)(u32 *addr, const u32 *range,
+			       int na, int ns, int pna);
 	unsigned int	(*get_flags)(u32 *addr);
 };
 
@@ -251,27 +251,49 @@ static void of_bus_default_count_cells(struct device_node *dev,
 	get_cells(dev, addrc, sizec);
 }
 
-static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+/* Make sure the least significant 64-bits are in-range.  Even
+ * for 3 or 4 cell values it is a good enough approximation.
+ */
+static int of_out_of_range(const u32 *addr, const u32 *base,
+			   const u32 *size, int na, int ns)
 {
-	u64 cp, s, da;
+	u64 a = of_read_addr(addr, na);
+	u64 b = of_read_addr(base, na);
 
-	cp = of_read_addr(range, na);
-	s  = of_read_addr(range + na + pna, ns);
-	da = of_read_addr(addr, na);
+	if (a < b)
+		return 1;
 
-	if (da < cp || da >= (cp + s))
-		return OF_BAD_ADDR;
-	return da - cp;
+	b += of_read_addr(size, ns);
+	if (a >= b)
+		return 1;
+
+	return 0;
 }
 
-static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+static int of_bus_default_map(u32 *addr, const u32 *range,
+			      int na, int ns, int pna)
 {
-	u64 a = of_read_addr(addr, na);
-	memset(addr, 0, na * 4);
-	a += offset;
-	if (na > 1)
-		addr[na - 2] = a >> 32;
-	addr[na - 1] = a & 0xffffffffu;
+	u32 result[OF_MAX_ADDR_CELLS];
+	int i;
+
+	if (ns > 2) {
+		printk("of_device: Cannot handle size cells (%d) > 2.", ns);
+		return -EINVAL;
+	}
+
+	if (of_out_of_range(addr, range, range + na + pna, na, ns))
+		return -EINVAL;
+
+	/* Start with the parent range base.  */
+	memcpy(result, range + na, pna * 4);
+
+	/* Add in the child address offset.  */
+	for (i = 0; i < na; i++)
+		result[pna - 1 - i] +=
+			(addr[na - 1 - i] -
+			 range[na - 1 - i]);
+
+	memcpy(addr, result, pna * 4);
 
 	return 0;
 }
@@ -287,7 +309,20 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
 
 static int of_bus_pci_match(struct device_node *np)
 {
-	return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex");
+	if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+		/* Do not do PCI specific frobbing if the
+		 * PCI bridge lacks a ranges property.  We
+		 * want to pass it through up to the next
+		 * parent as-is, not with the PCI translate
+		 * method which chops off the top address cell.
+		 */
+		if (!of_find_property(np, "ranges", NULL))
+			return 0;
+
+		return 1;
+	}
+
+	return 0;
 }
 
 static void of_bus_pci_count_cells(struct device_node *np,
@@ -299,27 +334,32 @@ static void of_bus_pci_count_cells(struct device_node *np,
 		*sizec = 2;
 }
 
-static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+static int of_bus_pci_map(u32 *addr, const u32 *range,
+			  int na, int ns, int pna)
 {
-	u64 cp, s, da;
+	u32 result[OF_MAX_ADDR_CELLS];
+	int i;
 
 	/* Check address type match */
 	if ((addr[0] ^ range[0]) & 0x03000000)
-		return OF_BAD_ADDR;
+		return -EINVAL;
 
-	/* Read address values, skipping high cell */
-	cp = of_read_addr(range + 1, na - 1);
-	s  = of_read_addr(range + na + pna, ns);
-	da = of_read_addr(addr + 1, na - 1);
+	if (of_out_of_range(addr + 1, range + 1, range + na + pna,
+			    na - 1, ns))
+		return -EINVAL;
 
-	if (da < cp || da >= (cp + s))
-		return OF_BAD_ADDR;
-	return da - cp;
-}
+	/* Start with the parent range base.  */
+	memcpy(result, range + na, pna * 4);
 
-static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
-{
-	return of_bus_default_translate(addr + 1, offset, na - 1);
+	/* Add in the child address offset, skipping high cell.  */
+	for (i = 0; i < na - 1; i++)
+		result[pna - 1 - i] +=
+			(addr[na - 1 - i] -
+			 range[na - 1 - i]);
+
+	memcpy(addr, result, pna * 4);
+
+	return 0;
 }
 
 static unsigned int of_bus_pci_get_flags(u32 *addr)
@@ -339,59 +379,6 @@ static unsigned int of_bus_pci_get_flags(u32 *addr)
 	return flags;
 }
 
-/*
- * ISA bus specific translator
- */
-
-static int of_bus_isa_match(struct device_node *np)
-{
-	return !strcmp(np->name, "isa");
-}
-
-static void of_bus_isa_count_cells(struct device_node *child,
-				   int *addrc, int *sizec)
-{
-	if (addrc)
-		*addrc = 2;
-	if (sizec)
-		*sizec = 1;
-}
-
-static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
-{
-	u64 cp, s, da;
-
-	/* Check address type match */
-	if ((addr[0] ^ range[0]) & 0x00000001)
-		return OF_BAD_ADDR;
-
-	/* Read address values, skipping high cell */
-	cp = of_read_addr(range + 1, na - 1);
-	s  = of_read_addr(range + na + pna, ns);
-	da = of_read_addr(addr + 1, na - 1);
-
-	if (da < cp || da >= (cp + s))
-		return OF_BAD_ADDR;
-	return da - cp;
-}
-
-static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
-{
-	return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-static unsigned int of_bus_isa_get_flags(u32 *addr)
-{
-	unsigned int flags = 0;
-	u32 w = addr[0];
-
-	if (w & 1)
-		flags |= IORESOURCE_IO;
-	else
-		flags |= IORESOURCE_MEM;
-	return flags;
-}
-
 /*
  * SBUS bus specific translator
  */
@@ -411,16 +398,11 @@ static void of_bus_sbus_count_cells(struct device_node *child,
 		*sizec = 1;
 }
 
-static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna)
+static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
 {
 	return of_bus_default_map(addr, range, na, ns, pna);
 }
 
-static int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
-{
-	return of_bus_default_translate(addr, offset, na);
-}
-
 static unsigned int of_bus_sbus_get_flags(u32 *addr)
 {
 	return IORESOURCE_MEM;
@@ -439,19 +421,8 @@ static struct of_bus of_busses[] = {
 		.match = of_bus_pci_match,
 		.count_cells = of_bus_pci_count_cells,
 		.map = of_bus_pci_map,
-		.translate = of_bus_pci_translate,
 		.get_flags = of_bus_pci_get_flags,
 	},
-	/* ISA */
-	{
-		.name = "isa",
-		.addr_prop_name = "reg",
-		.match = of_bus_isa_match,
-		.count_cells = of_bus_isa_count_cells,
-		.map = of_bus_isa_map,
-		.translate = of_bus_isa_translate,
-		.get_flags = of_bus_isa_get_flags,
-	},
 	/* SBUS */
 	{
 		.name = "sbus",
@@ -459,7 +430,6 @@ static struct of_bus of_busses[] = {
 		.match = of_bus_sbus_match,
 		.count_cells = of_bus_sbus_count_cells,
 		.map = of_bus_sbus_map,
-		.translate = of_bus_sbus_translate,
 		.get_flags = of_bus_sbus_get_flags,
 	},
 	/* Default */
@@ -469,7 +439,6 @@ static struct of_bus of_busses[] = {
 		.match = NULL,
 		.count_cells = of_bus_default_count_cells,
 		.map = of_bus_default_map,
-		.translate = of_bus_default_translate,
 		.get_flags = of_bus_default_get_flags,
 	},
 };
@@ -494,33 +463,62 @@ static int __init build_one_resource(struct device_node *parent,
 	u32 *ranges;
 	unsigned int rlen;
 	int rone;
-	u64 offset = OF_BAD_ADDR;
 
 	ranges = of_get_property(parent, "ranges", &rlen);
 	if (ranges == NULL || rlen == 0) {
-		offset = of_read_addr(addr, na);
-		memset(addr, 0, pna * 4);
-		goto finish;
+		u32 result[OF_MAX_ADDR_CELLS];
+		int i;
+
+		memset(result, 0, pna * 4);
+		for (i = 0; i < na; i++)
+			result[pna - 1 - i] =
+				addr[na - 1 - i];
+
+		memcpy(addr, result, pna * 4);
+		return 0;
 	}
 
 	/* Now walk through the ranges */
 	rlen /= 4;
 	rone = na + pna + ns;
 	for (; rlen >= rone; rlen -= rone, ranges += rone) {
-		offset = bus->map(addr, ranges, na, ns, pna);
-		if (offset != OF_BAD_ADDR)
-			break;
+		if (!bus->map(addr, ranges, na, ns, pna))
+			return 0;
 	}
-	if (offset == OF_BAD_ADDR)
+
+	return 1;
+}
+
+static int __init use_1to1_mapping(struct device_node *pp)
+{
+	char *model;
+
+	/* If this is on the PMU bus, don't try to translate it even
+	 * if a ranges property exists.
+	 */
+	if (!strcmp(pp->name, "pmu"))
 		return 1;
 
-	memcpy(addr, ranges + na, 4 * pna);
+	/* If we have a ranges property in the parent, use it.  */
+	if (of_find_property(pp, "ranges", NULL) != NULL)
+		return 0;
+
+	/* If the parent is the dma node of an ISA bus, pass
+	 * the translation up to the root.
+	 */
+	if (!strcmp(pp->name, "dma"))
+		return 0;
+
+	/* Similarly for Simba PCI bridges.  */
+	model = of_get_property(pp, "model", NULL);
+	if (model && !strcmp(model, "SUNW,simba"))
+		return 0;
 
-finish:
-	/* Translate it into parent bus space */
-	return pbus->translate(addr, offset, pna);
+	return 1;
 }
 
+static int of_resource_verbose;
+
 static void __init build_device_resources(struct of_device *op,
 					  struct device *parent)
 {
@@ -564,15 +562,7 @@ static void __init build_device_resources(struct of_device *op,
 
 		memcpy(addr, reg, na * 4);
 
-		/* If the immediate parent has no ranges property to apply,
-		 * just use a 1<->1 mapping.  Unless it is the 'dma' child
-		 * of an isa bus, which must be passed up towards the root.
-		 *
-		 * Also, don't try to translate PMU bus device registers.
-		 */
-		if ((of_find_property(pp, "ranges", NULL) == NULL &&
-		     strcmp(pp->name, "dma") != 0) ||
-		    !strcmp(pp->name, "pmu")) {
+		if (use_1to1_mapping(pp)) {
 			result = of_read_addr(addr, na);
 			goto build_res;
 		}
@@ -591,7 +581,8 @@ static void __init build_device_resources(struct of_device *op,
 			pbus = of_match_bus(pp);
 			pbus->count_cells(dp, &pna, &pns);
 
-			if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna))
+			if (build_one_resource(dp, bus, pbus, addr,
+					       dna, dns, pna))
 				break;
 
 			dna = pna;
@@ -601,6 +592,12 @@ static void __init build_device_resources(struct of_device *op,
 
 	build_res:
 		memset(r, 0, sizeof(*r));
+
+		if (of_resource_verbose)
+			printk("%s reg[%d] -> %lx\n",
+			       op->node->full_name, index,
+			       result);
+
 		if (result != OF_BAD_ADDR) {
 			if (tlb_type == hypervisor)
 				result &= 0x0fffffffffffffffUL;
@@ -684,6 +681,8 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
 	return ret;
 }
 
+static int of_irq_verbose;
+
 static unsigned int __init build_one_device_irq(struct of_device *op,
 						struct device *parent,
 						unsigned int irq)
@@ -698,10 +697,11 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
 	if (dp->irq_trans) {
 		irq = dp->irq_trans->irq_build(dp, irq,
 					       dp->irq_trans->data);
-#if 1
-		printk("%s: direct translate %x --> %x\n",
-		       dp->full_name, orig_irq, irq);
-#endif
+
+		if (of_irq_verbose)
+			printk("%s: direct translate %x --> %x\n",
+			       dp->full_name, orig_irq, irq);
+
 		return irq;
 	}
 
@@ -728,12 +728,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
 			iret = apply_interrupt_map(dp, pp,
 						   imap, imlen, imsk,
 						   &irq);
-#if 1
-			printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
-			       op->node->full_name,
-			       pp->full_name, this_orig_irq,
-			       (iret ? iret->full_name : "NULL"), irq);
-#endif
+
+			if (of_irq_verbose)
+				printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
+				       op->node->full_name,
+				       pp->full_name, this_orig_irq,
+				       (iret ? iret->full_name : "NULL"), irq);
+
 			if (!iret)
 				break;
 
@@ -747,11 +748,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
 				unsigned int this_orig_irq = irq;
 
 				irq = pci_irq_swizzle(dp, pp, irq);
-#if 1
-				printk("%s: PCI swizzle [%s] %x --> %x\n",
-				       op->node->full_name,
-				       pp->full_name, this_orig_irq, irq);
-#endif
+				if (of_irq_verbose)
+					printk("%s: PCI swizzle [%s] "
+					       "%x --> %x\n",
+					       op->node->full_name,
+					       pp->full_name, this_orig_irq,
+					       irq);
+
 			}
 
 			if (pp->irq_trans) {
@@ -767,10 +770,9 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
 
 	irq = ip->irq_trans->irq_build(op->node, irq,
 				       ip->irq_trans->data);
-#if 1
-	printk("%s: Apply IRQ trans [%s] %x --> %x\n",
-	       op->node->full_name, ip->full_name, orig_irq, irq);
-#endif
+	if (of_irq_verbose)
+		printk("%s: Apply IRQ trans [%s] %x --> %x\n",
+		       op->node->full_name, ip->full_name, orig_irq, irq);
 
 	return irq;
 }
@@ -870,6 +872,20 @@ static int __init of_bus_driver_init(void)
 
 postcore_initcall(of_bus_driver_init);
 
+static int __init of_debug(char *str)
+{
+	int val = 0;
+
+	get_option(&str, &val);
+	if (val & 1)
+		of_resource_verbose = 1;
+	if (val & 2)
+		of_irq_verbose = 1;
+	return 1;
+}
+
+__setup("of_debug=", of_debug);
+
 int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
 {
 	/* initialize common driver fields */
@@ -922,9 +938,11 @@ int of_device_register(struct of_device *ofdev)
 	if (rc)
 		return rc;
 
-	device_create_file(&ofdev->dev, &dev_attr_devspec);
+	rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+	if (rc)
+		device_unregister(&ofdev->dev);
 
-	return 0;
+	return rc;
 }
 
 void of_device_unregister(struct of_device *ofdev)

+ 46 - 5
arch/sparc64/kernel/prom.c

@@ -539,6 +539,45 @@ static unsigned long __sabre_onboard_imap_off[] = {
 	((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
 			(SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
 
+static int sabre_device_needs_wsync(struct device_node *dp)
+{
+	struct device_node *parent = dp->parent;
+	char *parent_model, *parent_compat;
+
+	/* This traversal up towards the root is meant to
+	 * handle two cases:
+	 *
+	 * 1) non-PCI bus sitting under PCI, such as 'ebus'
+	 * 2) the PCI controller interrupts themselves, which
+	 *    will use the sabre_irq_build but do not need
+	 *    the DMA synchronization handling
+	 */
+	while (parent) {
+		if (!strcmp(parent->type, "pci"))
+			break;
+		parent = parent->parent;
+	}
+
+	if (!parent)
+		return 0;
+
+	parent_model = of_get_property(parent,
+				       "model", NULL);
+	if (parent_model &&
+	    (!strcmp(parent_model, "SUNW,sabre") ||
+	     !strcmp(parent_model, "SUNW,simba")))
+		return 0;
+
+	parent_compat = of_get_property(parent,
+					"compatible", NULL);
+	if (parent_compat &&
+	    (!strcmp(parent_compat, "pci108e,a000") ||
+	     !strcmp(parent_compat, "pci108e,a001")))
+		return 0;
+
+	return 1;
+}
+
 static unsigned int sabre_irq_build(struct device_node *dp,
 				    unsigned int ino,
 				    void *_data)
@@ -577,15 +616,17 @@ static unsigned int sabre_irq_build(struct device_node *dp,
 
 	virt_irq = build_irq(inofixup, iclr, imap);
 
+	/* If the parent device is a PCI<->PCI bridge other than
+	 * APB, we have to install a pre-handler to ensure that
+	 * all pending DMA is drained before the interrupt handler
+	 * is run.
+	 */
 	regs = of_get_property(dp, "reg", NULL);
-	if (regs &&
-	    ((regs->phys_hi >> 16) & 0xff) != irq_data->pci_first_busno) {
+	if (regs && sabre_device_needs_wsync(dp)) {
 		irq_install_pre_handler(virt_irq,
 					sabre_wsync_handler,
 					(void *) (long) regs->phys_hi,
-					(void *)
-					controller_regs +
-					SABRE_WRSYNC);
+					(void *) irq_data);
 	}
 
 	return virt_irq;

+ 26 - 9
drivers/serial/sunsu.c

@@ -1406,25 +1406,35 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
 	struct device_node *dp = op->node;
 	struct uart_sunsu_port *up;
 	struct resource *rp;
+	enum su_type type;
 	int err;
 
-	if (inst >= UART_NR)
-		return -EINVAL;
+	type = su_get_type(dp);
+	if (type == SU_PORT_PORT) {
+		if (inst >= UART_NR)
+			return -EINVAL;
+		up = &sunsu_ports[inst];
+	} else {
+		up = kzalloc(sizeof(*up), GFP_KERNEL);
+		if (!up)
+			return -ENOMEM;
+	}
 
-	up = &sunsu_ports[inst];
 	up->port.line = inst;
 
 	spin_lock_init(&up->port.lock);
 
-	up->su_type = su_get_type(dp);
+	up->su_type = type;
 
 	rp = &op->resource[0];
-	up->port.mapbase = op->resource[0].start;
-
+	up->port.mapbase = rp->start;
 	up->reg_size = (rp->end - rp->start) + 1;
 	up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
-	if (!up->port.membase)
+	if (!up->port.membase) {
+		if (type != SU_PORT_PORT)
+			kfree(up);
 		return -ENOMEM;
+	}
 
 	up->port.irq = op->irqs[0];
 
@@ -1436,8 +1446,11 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
 	err = 0;
 	if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
 		err = sunsu_kbd_ms_init(up);
-		if (err)
+		if (err) {
+			kfree(up);
 			goto out_unmap;
+		}
+		dev_set_drvdata(&op->dev, up);
 
 		return 0;
 	}
@@ -1476,8 +1489,12 @@ static int __devexit su_remove(struct of_device *dev)
 #ifdef CONFIG_SERIO
 		serio_unregister_port(&up->serio);
 #endif
-	} else if (up->port.type != PORT_UNKNOWN)
+		kfree(up);
+	} else if (up->port.type != PORT_UNKNOWN) {
 		uart_remove_one_port(&sunsu_reg, &up->port);
+	}
+
+	dev_set_drvdata(&dev->dev, NULL);
 
 	return 0;
 }

+ 1 - 1
include/asm-sparc64/Kbuild

@@ -4,7 +4,7 @@ ALTARCH := sparc
 ARCHDEF := defined __sparc__ && defined __arch64__
 ALTARCHDEF := defined __sparc__ && !defined __arch64__
 
-unifdef-y := fbio.h perfctr.h
+unifdef-y += fbio.h perfctr.h
 header-y += apb.h asi.h bbc.h bpp.h display7seg.h envctrl.h floppy.h	\
 	ipc.h kdebug.h mostek.h openprom.h openpromio.h parport.h	\
 	pconf.h psrcompat.h pstate.h reg.h uctx.h utrap.h watchdog.h