[parisc-linux-cvs] [PATCH] walk entire io_range and use willy's idea to avoid micro-hangs.

Ryan Bradetich rbradetich@uswest.net
16 Nov 2002 10:57:29 -0700


--=-M4EPu1foyjm7LtQ3nkU6
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

The E-Class (and probably other) systems need to walk the entire
io_io_low -> io_io_high range to locate devices on the bus.

I implimented Willy's idea to prevent the micro-hang problems
we experience with linux-2.4.


- Ryan

--=-M4EPu1foyjm7LtQ3nkU6
Content-Disposition: attachment; filename=drivers.diff
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-patch; name=drivers.diff; charset=ISO-8859-1

Index: Makefile
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/Makefile,v
retrieving revision 1.44
diff -u -p -r1.44 Makefile
--- Makefile	16 Nov 2002 17:49:46 -0000	1.44
+++ Makefile	16 Nov 2002 17:50:39 -0000
@@ -1,7 +1,7 @@
 VERSION =3D 2
 PATCHLEVEL =3D 5
 SUBLEVEL =3D 47
-EXTRAVERSION =3D -pa5
+EXTRAVERSION =3D -pa6
=20
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
Index: arch/parisc/kernel/drivers.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/arch/parisc/kernel/drivers.c,v
retrieving revision 1.4
diff -u -p -r1.4 drivers.c
--- arch/parisc/kernel/drivers.c	1 Nov 2002 01:04:30 -0000	1.4
+++ arch/parisc/kernel/drivers.c	16 Nov 2002 17:50:39 -0000
@@ -9,6 +9,7 @@
  * Copyright (c) 1999 The Puffin Group
  * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
  * Copyright (c) 2001 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2001,2002 Ryan Bradetich=20
  *=20
  * The file handles registering devices and drivers, then matching them.
  * It's the closest we get to a dating agency.
@@ -467,27 +468,41 @@ int register_parisc_device(struct parisc
         ((gsc_readl(&((struct bc_module *)dev->hpa)->io_status) \
                 & BC_PORT_MASK) =3D=3D BC_LOWER_PORT)
=20
-#define READ_IO_IO_LOW(dev) \
-	(dev->id.hw_type =3D=3D HPHW_IOA ? \
-	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io=
_low) << 16 : \
-	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io=
_low))
+#define MAX_NATIVE_DEVICES 64
+#define NATIVE_DEVICE_OFFSET 0x1000
+
+#define FLEX_MASK 	(unsigned long)0xfffffffffffc0000
+#define IO_IO_LOW	offsetof(struct bc_module, io_io_low)
+#define IO_IO_HIGH	offsetof(struct bc_module, io_io_high)
+#define READ_IO_IO_LOW(dev)  (unsigned long)(signed int)__raw_readl(dev->h=
pa + IO_IO_LOW)
+#define READ_IO_IO_HIGH(dev) (unsigned long)(signed int)__raw_readl(dev->h=
pa + IO_IO_HIGH)
+
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_h=
igh,
+                            struct parisc_device *parent);
=20
-static void walk_native_bus(unsigned long addr, struct parisc_device *pare=
nt);
 void walk_lower_bus(struct parisc_device *dev)
 {
+	unsigned long io_io_low, io_io_high;
=20
 	if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
 		return;
=20
-	walk_native_bus((unsigned long)(signed int)READ_IO_IO_LOW(dev), dev);
-}
+	if(dev->id.hw_type =3D=3D HPHW_IOA) {
+		io_io_low =3D (unsigned long)(signed int)(READ_IO_IO_LOW(dev) << 16);
+		io_io_high =3D io_io_low + MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET;
+	} else {
+		io_io_low =3D (READ_IO_IO_LOW(dev) + ~FLEX_MASK) & FLEX_MASK;
+		io_io_high =3D (READ_IO_IO_HIGH(dev)+ ~FLEX_MASK) & FLEX_MASK;
+	}
=20
-#define MAX_NATIVE_DEVICES 64
-#define NATIVE_DEVICE_OFFSET 0x1000
+	walk_native_bus(io_io_low, io_io_high, dev);
+}
=20
 /**
  * walk_native_bus -- Probe a bus for devices
- * @addr: Base address of this bus.
+ * @io_io_low: Base address of this bus.
+ * @io_io_high: Last address of this bus.
+ * @parent: The parent bus device.
  *=20
  * A native bus (eg Runway or GSC) may have up to 64 devices on it,
  * spaced at intervals of 0x1000 bytes.  PDC may not inform us of these
@@ -495,28 +510,32 @@ void walk_lower_bus(struct parisc_device
  * devices which are not physically connected (such as extra serial &
  * keyboard ports).  This problem is not yet solved.
  */
-static void walk_native_bus(unsigned long addr, struct parisc_device *pare=
nt)
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_h=
igh,
+                            struct parisc_device *parent)
 {
-	int i;
+	int i, devices_found =3D 0;
+	unsigned long hpa =3D io_io_low;
 	struct hardware_path path;
=20
 	get_node_path(parent, &path);
-	for (i =3D 0; i < MAX_NATIVE_DEVICES; i++) {
-		unsigned long hpa =3D (addr + i * NATIVE_DEVICE_OFFSET);
-		struct parisc_device *dev;
-
-		/* Was the device already added by Firmware? */
-		dev =3D find_device_by_addr(hpa);
-		if (!dev) {
-			path.mod =3D i;
-			dev =3D alloc_pa_dev(hpa, &path);
-			if (!dev)
-				continue;
+	do {
+		for(i =3D 0; i < MAX_NATIVE_DEVICES; i++, hpa +=3D NATIVE_DEVICE_OFFSET)=
 {
+			struct parisc_device *dev;
=20
-			register_parisc_device(dev);
+			/* Was the device already added by Firmware? */
+			dev =3D find_device_by_addr(hpa);
+			if (!dev) {
+				path.mod =3D i;
+				dev =3D alloc_pa_dev(hpa, &path);
+				if (!dev)
+					continue;
+
+				register_parisc_device(dev);
+				devices_found++;
+			}
+			walk_lower_bus(dev);
 		}
-		walk_lower_bus(dev);
-	}
+	} while(!devices_found && hpa < io_io_high);
 }
=20
 #define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
@@ -529,7 +548,9 @@ static void walk_native_bus(unsigned lon
  */
 void walk_central_bus(void)
 {
-	walk_native_bus(CENTRAL_BUS_ADDR, &root);
+	walk_native_bus(CENTRAL_BUS_ADDR,
+			CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
+			&root);
 }
=20
 void fixup_child_irqs(struct parisc_device *parent, int base,

--=-M4EPu1foyjm7LtQ3nkU6--