sparc32 sunzilog prom walk patch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi

The current sun4d prom walk for serial ports is missing it's last leg,
The "bare bone" attachment is a brute force fixit, the "alternate"
attachment recovers a chunk of code space

Either one would work

Thanx
  Ray

--- linux-2.6.17-rc6.orig/drivers/serial/sunzilog.c	Tue Jun  6 00:57:02 2006
+++ linux-2.6.17-rc6/drivers/serial/sunzilog.c	Wed Jun 21 08:08:18 2006
@@ -1046,12 +1046,31 @@
 	}
 }
 
+/*
+ * We scan the PROM tree recursively. This is the most reliable way
+ * to find Zilog nodes on various platforms. However, we face an extreme
+ * shortage of kernel stack, so we must be very careful. To that end,
+ * we scan only to a certain depth, and we use a common property buffer
+ * in the scan structure.
+ */
+#define ZS_PROPSIZE  128
+#define ZS_SCAN_DEPTH	5
+
+struct zs_probe_scan {
+	int depth;
+	void (*scanner)(struct zs_probe_scan *t, int node);
+
+	int devices;
+	char prop[ZS_PROPSIZE];
+	int hist[ZS_SCAN_DEPTH];
+};
+
 #ifdef CONFIG_SPARC64
 
 /* We used to attempt to use the address property of the Zilog device node
  * but that totally is not necessary on sparc64.
  */
-static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
+static struct zilog_layout __iomem * __init get_zs_sun4u(struct zs_probe_scan *t, int zsnode)
 {
 	void __iomem *mapped_addr;
 	unsigned int sun4u_ino;
@@ -1070,7 +1089,7 @@
  found:
 	if (sdev == NULL && central_bus == NULL) {
 		prom_printf("SunZilog: sdev&&central == NULL for "
-			    "Zilog %d in get_zs_sun4u.\n", chip);
+			    "Zilog %d in get_zs_sun4u.\n", t->devices);
 		prom_halt();
 	}
 	if (central_bus == NULL) {
@@ -1087,7 +1106,7 @@
 		if (err == -1) {
 			prom_printf("SunZilog: Cannot map "
 				    "Zilog %d regs on "
-				    "central bus.\n", chip);
+				    "central bus.\n", t->devices);
 			prom_halt();
 		}
 		apply_fhc_ranges(central_bus->child,
@@ -1120,10 +1139,10 @@
 #else /* CONFIG_SPARC64 */
 
 /*
- * XXX The sun4d case is utterly screwed: it tries to re-walk the tree
- * (for the 3rd time) in order to find bootbus and cpu. Streamline it.
+ * sparc32
+ * apply address range indicated by prom.
  */
-static struct zilog_layout __iomem * __init get_zs_sun4cmd(int chip, int node)
+static struct zilog_layout __iomem * __init get_zs_sun4cmd(struct zs_probe_scan *t, int node)
 {
 	struct linux_prom_irqs irq_info[2];
 	void __iomem *mapped_addr = NULL;
@@ -1132,35 +1151,35 @@
 	struct resource res;
 
 	if (sparc_cpu_model == sun4d) {
-		int walk;
+		int len;
 
-		zsnode = 0;
-		bbnode = 0;
-		cpunode = 0;
-		for (walk = prom_getchild(prom_root_node);
-		     (walk = prom_searchsiblings(walk, "cpu-unit")) != 0;
-		     walk = prom_getsibling(walk)) {
-			bbnode = prom_getchild(walk);
-			if (bbnode &&
-			    (bbnode = prom_searchsiblings(bbnode, "bootbus"))) {
-				if ((zsnode = prom_getchild(bbnode)) == node) {
-					cpunode = walk;
-					break;
-				}
-			}
+		/*
+		 * prom root node is not stored
+		 * cpu-unit node should be in t->hist[0]
+		 * bootbus node should be in t->hist[1]
+		 * zs should be in node and depth =2
+		 * simplified comparison functions would help
+		 */
+		if (t->depth < 2) {
+			goto bail;
 		}
-		if (!walk) {
-			prom_printf("SunZilog: Cannot find the %d'th bootbus on sun4d.\n",
-				    (chip / 2));
-			prom_halt();
+		zsnode=node;
+		bbnode=t->hist[t->depth - 1];
+		cpunode=t->hist[t->depth - 2];
+
+		len = prom_getproperty(cpunode, "name", t->prop, ZS_PROPSIZE);
+		if (strncmp(t->prop, "cpu-unit", len) != 0) {
+			goto bail;
+		}
+		len = prom_getproperty(bbnode, "name", t->prop, ZS_PROPSIZE);
+		if (strncmp(t->prop, "bootbus", len) != 0) {
+			goto bail;
 		}
-
 		if (prom_getproperty(zsnode, "reg",
 				     (char *) zsreg, sizeof(zsreg)) == -1) {
-			prom_printf("SunZilog: Cannot map Zilog %d\n", chip);
+			prom_printf("SunZilog: Cannot map Zilog %d\n", t->devices);
 			prom_halt();
 		}
-		/* XXX Looks like an off by one? */
 		prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1);
 		res.start = zsreg[0].phys_addr;
 		res.end = res.start + (8 - 1);
@@ -1185,7 +1204,7 @@
 
 		if (prom_getproperty(zsnode, "reg",
 				     (char *) zsreg, sizeof(zsreg)) == -1) {
-			prom_printf("SunZilog: Cannot map Zilog %d\n", chip);
+			prom_printf("SunZilog: Cannot map Zilog %d\n", t->devices);
 			prom_halt();
 		}
 		if (sparc_cpu_model == sun4m)	/* Crude. Pass parent. XXX */
@@ -1200,7 +1219,7 @@
 			     (char *) irq_info, sizeof(irq_info))
 		    % sizeof(struct linux_prom_irqs)) {
 		prom_printf("SunZilog: Cannot get IRQ property for Zilog %d.\n",
-			    chip);
+			    t->devices);
 		prom_halt();
 	}
 	if (zilog_irq == -1) {
@@ -1208,31 +1227,34 @@
 	} else if (zilog_irq != irq_info[0].pri) {
 		/* XXX. Dumb. Should handle per-chip IRQ, for add-ons. */
 		prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n",
-			    chip);
+			    t->devices);
 		prom_halt();
 	}
 
 	return (struct zilog_layout __iomem *) mapped_addr;
+bail:
+			prom_printf("SunZilog: Error traversing prom %d\n", t->devices);
+			prom_halt();
 }
 #endif /* !(CONFIG_SPARC64) */
 
 /* Get the address of the registers for SunZilog instance CHIP.  */
-static struct zilog_layout __iomem * __init get_zs(int chip, int node)
+static struct zilog_layout __iomem * __init get_zs(struct zs_probe_scan *t, int node)
 {
-	if (chip < 0 || chip >= NUM_SUNZILOG) {
-		prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip);
+	if (t->devices < 0 || t->devices >= NUM_SUNZILOG) {
+		prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", t->devices);
 		prom_halt();
 	}
 
 #ifdef CONFIG_SPARC64
-	return get_zs_sun4u(chip, node);
+	return get_zs_sun4u(t, node);
 #else
 
 	if (sparc_cpu_model == sun4) {
 		struct resource res;
 
 		/* Not probe-able, hard code it. */
-		switch (chip) {
+		switch (t->devices) {
 		case 0:
 			res.start = 0xf1000000;
 			break;
@@ -1246,7 +1268,7 @@
 		return sbus_ioremap(&res, 0, 8, "SunZilog");
 	}
 
-	return get_zs_sun4cmd(chip, node);
+	return get_zs_sun4cmd(t, node);
 #endif
 }
 
@@ -1435,24 +1457,6 @@
 #define sunzilog_console_init() do { } while (0)
 #endif
 
-/*
- * We scan the PROM tree recursively. This is the most reliable way
- * to find Zilog nodes on various platforms. However, we face an extreme
- * shortage of kernel stack, so we must be very careful. To that end,
- * we scan only to a certain depth, and we use a common property buffer
- * in the scan structure.
- */
-#define ZS_PROPSIZE  128
-#define ZS_SCAN_DEPTH	5
-
-struct zs_probe_scan {
-	int depth;
-	void (*scanner)(struct zs_probe_scan *t, int node);
-
-	int devices;
-	char prop[ZS_PROPSIZE];
-};
-
 static int __inline__ sunzilog_node_ok(int node, const char *name, int len)
 {
 	if (strncmp(name, "zs", len) == 0)
@@ -1466,6 +1470,7 @@
 	int len;
 
 	for (; node != 0; node = prom_getsibling(node)) {
+		t->hist[t->depth]=node;
 		len = prom_getproperty(node, "name", t->prop, ZS_PROPSIZE);
 		if (len <= 1)
 			continue;		/* Broken PROM node */
@@ -1636,11 +1641,11 @@
 	}
 }
 
-static struct zilog_layout __iomem * __init get_zs(int chip, int node);
+static struct zilog_layout __iomem * __init get_zs(struct zs_probe_scan *t, int node);
 
 static void __init sunzilog_scan_probe(struct zs_probe_scan *t, int node)
 {
-	sunzilog_chip_regs[t->devices] = get_zs(t->devices, node);
+	sunzilog_chip_regs[t->devices] = get_zs(t, node);
 	t->devices++;
 }
 
@@ -1671,16 +1676,12 @@
 	/* We can only init this once we have probed the Zilogs
 	 * in the system. Do not count channels assigned to keyboards
 	 * or mice when we are deciding how many ports to register.
-	 */
-	uart_count = 0;
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		struct uart_sunzilog_port *up = &sunzilog_port_table[i];
-
-		if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up))
-			continue;
 
-		uart_count++;
-	}
+	 * : changed :
+	 * accounted for during processing of generic uart_port
+	 * doing it here causes the last 2 serial port to fail initialization
+	 */
+	uart_count = NUM_CHANNELS;
 		
 	sunzilog_reg.nr = uart_count;
 	sunzilog_reg.minor = sunserial_current_minor;
--- linux-2.6.17-rc6.orig/drivers/serial/sunzilog.c	Tue Jun  6 00:57:02 2006
+++ linux-2.6.17-rc6/drivers/serial/sunzilog.c	Thu Jun 15 03:33:25 2006
@@ -1143,7 +1143,10 @@
 			bbnode = prom_getchild(walk);
 			if (bbnode &&
 			    (bbnode = prom_searchsiblings(bbnode, "bootbus"))) {
-				if ((zsnode = prom_getchild(bbnode)) == node) {
+				zsnode = prom_getchild(bbnode);
+				while (zsnode && (zsnode != node)) 
+					zsnode = prom_getsibling(zsnode);
+				if (zsnode && (zsnode == node)) {
 					cpunode = walk;
 					break;
 				}

[Index of Archives]     [Kernel Development]     [DCCP]     [Linux ARM Development]     [Linux]     [Photo]     [Yosemite Help]     [Linux ARM Kernel]     [Linux SCSI]     [Linux x86_64]     [Linux Hams]

  Powered by Linux