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&¢ral == 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; }