Subject: Re: obio attachment and Macs w/ two or more I/O controllers
To: Chris Tribo <ctribo@college.dtcc.edu>
From: Tim Kelly <hockey@dialectronics.com>
List: port-macppc
Date: 11/16/2004 05:48:16
Hi Chris,

> I added a dmesg to http://nycbug.org/dmesgd for the PDQ and my beige
> g3.

Is this a searchable database?

> I'd also like to note that GENERIC did not find the root device on
> wd0a by itself. I've had to compile kernels with it hardcoded in.

I've got a patch that will work for your beige G3, but it won't fix  the
PDQ, as I'll explain:

> obio0 at pci0 dev 13 function 0: addr 0xf3000000

This is exactly what I'm describing (I take it this is from the PDQ). If
you look at your device tree in Open Firmware, 

dev / ls

dev pci/mac-io@D .properties

you'll see that the PCI device 13 does not have address 0xf3000000. It
probably has 0xf400000, if it is consistent with the Wallstreet PB I've
had access to. The mac-io chips are Paddington. I'm not sure if it is
one chip acting as a Heathrow compatible and a Gatwick compatible chip,
or if it is two separate chips with the same PCI vendor and device code.

But the bottom line is that the attachment process has gotten the wrong
node. The reason for this is that obio.c depends on the alias "mac-io"
or "pci/mac-io" to be the only I/O controller present. In OF, when
walking the tree to find a node, if the node is not specified, then the
first child of the parent node is used. In the case of two or more
controllers, "mac-io" will find mac-io/@10 (16 in hex). Or in other
words, this device:

> Apple Computer MAC-IO I/O Controller (Paddington) (undefined subclass
> 0x00) at pci0 dev 16 function 0 not configured

Now, I've had a chance to look at things, and the patch that I have
fixes the above problem by correlating the PCI tag with the Open
Firmware node using code already in the tree in autoconf.c instead of
using aliases. This is the correct way to play nicely with the PCI
discovery process, as I said in my first post that the discovery process
does not always match the OF tree structure. The patch correctly
attaches mediabays that are under the I/O at 13. However, I still get
the above not configured message. I have not fully traced this back.
Without the configuring, the vast bulk of the OF tree (and devices under
the primary I/O controller) will not get attached.

> boot device: <unknown>
> root device: wd0a

You're getting this message because the canonical path to your boot
device does not match the device tree generated by the attachment
process. That would be because the expected boot device path would come
through obio0 at device 16, but obio0 attached at 13. There is no
node in the OF tree at PCI device 13 that matches wd0. The proper
attachment would have obio0 at 13 and obio1 at 16.

I will have some time this morning, early, but overall I'm going to be
offline today until later afternoon or evening. There are two patches
attached (well, four overall). One is for obio.c. It'll break your PDQ,
but I need the dmesg of the break, and it would be great if you could
test it on your beige G3, which I think has only one I/O controller, in
which case it should not have any effect at all and this is essential
for getting the patch committed. The second patch is for autconf.c and
will address some other bootpath discovery issues, that of finding the
first child node even if you booted from a different node. It adds a
frontend to the Open Firmware method "canon" so two other files get
affected as well.

As always, with new patches always keep a known working kernel in a
place the bootloader can get to it.

thanks,
tim

Index: obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/dev/obio.c,v
retrieving revision 1.19
diff -d -u -r1.19 obio.c
--- obio.c	15 Jul 2003 02:43:30 -0000	1.19
+++ obio.c	16 Nov 2004 02:34:53 -0000
@@ -69,7 +69,6 @@
 
 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE)
 		switch (PCI_PRODUCT(pa->pa_id)) {
-
 		case PCI_PRODUCT_APPLE_GC:
 		case PCI_PRODUCT_APPLE_OHARE:
 		case PCI_PRODUCT_APPLE_HEATHROW:
@@ -96,29 +95,26 @@
 	struct confargs ca;
 	int node, child, namelen;
 	u_int reg[20];
-	int intr[6];
+	int intr[6], parent_intr = 0, parent_nintr = 0;
 	char name[32];
+	char compat[32];
 
 	switch (PCI_PRODUCT(pa->pa_id)) {
 
-	/* XXX should not use name */
 	case PCI_PRODUCT_APPLE_GC:
-		node = OF_finddevice("/bandit/gc");
-		break;
-
 	case PCI_PRODUCT_APPLE_OHARE:
-		node = OF_finddevice("/bandit/ohare");
-		break;
-
 	case PCI_PRODUCT_APPLE_HEATHROW:
 	case PCI_PRODUCT_APPLE_PADDINGTON:
 	case PCI_PRODUCT_APPLE_KEYLARGO:
 	case PCI_PRODUCT_APPLE_PANGEA_MACIO:
 	case PCI_PRODUCT_APPLE_INTREPID:
-		node = OF_finddevice("mac-io");
+		node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
 		if (node == -1)
-			node = OF_finddevice("/pci/mac-io");
+			node = OF_finddevice("mac-io");
+			if (node == -1)
+				node = OF_finddevice("/pci/mac-io");
 		break;
+			
 
 	default:
 		printf("obio_attach: unknown obio controller\n");
@@ -132,10 +128,20 @@
 	ca.ca_baseaddr = reg[2];
 
 	printf(": addr 0x%x\n", ca.ca_baseaddr);
+	
+	/* Gatwick and Paddington use same product ID */
+	namelen = OF_getprop(node, "compatible", compat, sizeof(compat));
 
+	if (strcmp(compat, "gatwick") == 0) {
+		parent_nintr = OF_getprop(node, "AAPL,interrupts", intr,
+					sizeof(intr));
+		parent_intr = intr[0];
+
+	} else {
 	/* Enable CD and microphone sound input. */
-	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PADDINGTON)
-		out8(ca.ca_baseaddr + 0x37, 0x03);
+		if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PADDINGTON)
+			out8(ca.ca_baseaddr + 0x37, 0x03);
+	}
 
 	for (child = OF_child(node); child; child = OF_peer(child)) {
 		namelen = OF_getprop(child, "name", name, sizeof(name));
@@ -148,13 +154,18 @@
 		ca.ca_name = name;
 		ca.ca_node = child;
 
-		ca.ca_nreg  = OF_getprop(child, "reg", reg, sizeof(reg));
-		ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr,
-				sizeof(intr));
-		if (ca.ca_nintr == -1)
-			ca.ca_nintr = OF_getprop(child, "interrupts", intr,
+		ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg));
+		
+		if (strcmp(compat, "gatwick") != 0) {
+			ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr,
 					sizeof(intr));
-
+			if (ca.ca_nintr == -1)
+				ca.ca_nintr = OF_getprop(child, "interrupts", intr,
+						sizeof(intr));
+		} else {
+			intr[0] = parent_intr;
+			ca.ca_nintr = parent_nintr;
+		}
 		ca.ca_reg = reg;
 		ca.ca_intr = intr;
 
Index: autoconf.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/macppc/autoconf.c,v
retrieving revision 1.41
diff -d -u -r1.41 autoconf.c
--- autoconf.c	23 Oct 2004 17:07:39 -0000	1.41
+++ autoconf.c	11 Nov 2004 21:38:22 -0000
@@ -90,117 +90,99 @@
 void
 canonicalize_bootpath()
 {
-	int node;
+
 	char *p, *lastp;
-	char last[32];
+	int bnode, cnode;
+	char buf[128];
+	int result = 0;
 
-	/*
-	 * If the bootpath doesn't start with a / then it isn't
-	 * an OFW path and probably is an alias, so look up the alias
-	 * and regenerate the full bootpath so device_register will work.
+	 /* 
+	 * pick up the partition separator
+	 * go back to first /
+	 * read forward to @
+	 * reach ':' means no node, assume 0
+	 * add node to canonized bootpath
+	 * 
 	 */
-	if (bootpath[0] != '/' && bootpath[0] != '\0') {
-		int aliases = OF_finddevice("/aliases");
-		char tmpbuf[100];
-		char aliasbuf[256];
-		if (aliases != 0) {
-			char *cp1, *cp2, *cp;
-			char saved_ch = '\0';
-			int len;
-			cp1 = strchr(bootpath, ':');
-			cp2 = strchr(bootpath, ',');
-			cp = cp1;
-			if (cp1 == NULL || (cp2 != NULL && cp2 < cp1))
-				cp = cp2;
-			tmpbuf[0] = '\0';
-			if (cp != NULL) {
-				strcpy(tmpbuf, cp);
-				saved_ch = *cp;
-				*cp = '\0';
-			}
-			len = OF_getprop(aliases, bootpath, aliasbuf,
-			    sizeof(aliasbuf));
-			if (len > 0) {
-				if (aliasbuf[len-1] == '\0')
-					len--;
-				memcpy(bootpath, aliasbuf, len);
-				strcpy(&bootpath[len], tmpbuf);
-			} else {
-				*cp = saved_ch;
-			}
-		}
-	}
 
-	/*
-	 * Strip kernel name.  bootpath contains "OF-path"/"kernel".
-	 *
-	 * for example:
-	 *   /bandit@F2000000/gc@10/53c94@10000/sd@0,0/netbsd	(OF-1.x)
-	 *   /pci/mac-io/ata-3@2000/disk@0:0/netbsd.new		(OF-3.x)
-	 */
-	strcpy(cbootpath, bootpath);
-	while ((node = OF_finddevice(cbootpath)) == -1) {
-		if ((p = strrchr(cbootpath, '/')) == NULL)
-			break;
-		*p = '\0';
-	}
+	printf("\nautoconf.c bootpath: %s\n", bootpath);
+        
+	strcpy(buf, bootpath);
 
-	if (node == -1) {
-		/* Cannot canonicalize... use bootpath anyway. */
-		strcpy(cbootpath, bootpath);
+	/* go to end, drop kernel name from buf */
+	for (p = buf; *p != '\0' && p <= (buf + sizeof(buf)); p++)
+		;
 
-		return;
-	}
+	for (; *p != '/' && p >= buf; p--)
+		;
 
-	/*
-	 * cbootpath is a valid OF path.  Use package-to-path to
-	 * canonicalize pathname.
-	 */
+	if (*p == '/')
+		*p = '\0'; 
 
-	/* Back up the last component for later use. */
-	if ((p = strrchr(cbootpath, '/')) != NULL)
-		strcpy(last, p + 1);
+	for (; p >= buf && *p != '@' && *p != '/'; p--)
+		;
+
+	if (*p == '@')
+		bnode = *++p;
 	else
-		last[0] = '\0';
+		bnode = '0';
 
-	memset(cbootpath, 0, sizeof(cbootpath));
-	OF_package_to_path(node, cbootpath, sizeof(cbootpath) - 1);
+	/* if p == buf, OF_canon will kick out with -1 */
+
+	result = OF_canon(buf, buf, sizeof(buf));
+	if (result == -1) {
+                /* Cannot canonicalize... use bootpath anyway. */
+                strcpy(cbootpath, bootpath);
+                goto exit;
+	}	
+
+	printf("autoconf.c OF_canon result: %s\n", buf);
+
+	/* let's find out if the node was preserved */
+	for (p = buf; *p != 0 && p <= (buf + sizeof(buf)); p++)
+		;
+
+	lastp = p;
+
+	for (; p >= buf && *p != '/'; p--)
+		; 
+
+	for (; p <= lastp && *p != '@'; p++)
+		;
+
+	if (p == lastp) {
+		/* no node was preserved, append */
+		cnode = bnode;
+		*lastp++ = '@';	
+		*lastp++ = cnode;
+		*lastp = '\0';
 
-	/*
-	 * OF_1.x (at least) always returns addr == 0 for
-	 * SCSI disks (i.e. "/bandit@.../.../sd@0,0").
-	 */
-	lastp = strrchr(cbootpath, '/');
-	if (lastp != NULL) {
-		lastp++;
-		if (strncmp(lastp, "sd@", 3) == 0 
-		    && strncmp(last, "sd@", 3) == 0)
-			strcpy(lastp, last);
 	} else {
-		lastp = cbootpath;
+		p++;
+		cnode = *p;
+		if (cnode != bnode) {
+			 /* wrong node preserved, correct */
+			cnode = bnode;
+			*p = bnode;
+			*++p = '\0';
+		}
+		else 
+		/* right node, terminate */
+			*++p = '\0';
 	}
 
 	/*
-	 * At this point, cbootpath contains like:
-	 * "/pci@80000000/mac-io@10/ata-3@20000/disk"
-	 *
-	 * The last component may have no address... so append it.
+	 * we should have a consistency between bnode and cnode
+	 * at this point, so now we can do something
 	 */
-	if (strchr(lastp, '@') == NULL) {
-		/* Append it. */
-		if ((p = strrchr(last, '@')) != NULL)
-			strcat(cbootpath, p);
-	}
+	
+	strcpy(cbootpath, buf);
 
-	if ((p = strrchr(lastp, ':')) != NULL) {
-		*p++ = '\0';
-		/* booted_partition = *p - '0';		XXX correct? */
-	}
+exit:
+	printf("autoconf.c cbootpath: %s\n", cbootpath);
+
+}	
 
-	/* XXX Does this belong here, or device_register()? */
-	if ((p = strrchr(lastp, ',')) != NULL)
-		*p = '\0';
-}
 
 #define DEVICE_IS(dev, name) \
 	(!strncmp(dev->dv_xname, name, sizeof(name) - 1) && \
@@ -315,7 +297,7 @@
 	/* If we reach this point, then dev is a match for the current
 	 * path component.
 	 */
-
+	printf("device name: %s\n", dev->dv_xname);
 	if (p && *p) {
 		parent = dev;
 		cp = p;

Index: openfirm.c
===================================================================
RCS file: /cvsroot/src/sys/arch/powerpc/powerpc/openfirm.c,v
retrieving revision 1.14
diff -d -u -r1.14 openfirm.c
--- openfirm.c	27 Sep 2003 04:44:42 -0000	1.14
+++ openfirm.c	11 Nov 2004 16:52:01 -0000
@@ -245,6 +245,31 @@
 }
 
 int
+OF_canon(char *alias, char *device, int maxlen)
+{
+	static struct {
+		char *name;
+		int nargs;
+		int nreturns;
+		char *alias;
+		char *device;
+		int maxlen;
+		int fullLen;
+	} args = {
+		"canon",
+		3,
+		1,
+	};
+
+	args.alias = alias;
+	args.device = device;
+	args.maxlen = maxlen;
+	if (openfirmware(&args) == -1)
+		return -1;
+	return args.fullLen;
+}
+
+int
 OF_instance_to_path(int ihandle, char *buf, int buflen)
 {
 	static struct {

Index: openfirm.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ofw/openfirm.h,v
retrieving revision 1.19
diff -d -u -r1.19 openfirm.h
--- openfirm.h	5 Oct 2002 17:01:52 -0000	1.19
+++ openfirm.h	11 Nov 2004 16:52:45 -0000
@@ -87,6 +87,7 @@
 int	OF_nextprop(int, char *, void *);
 int	OF_setprop(int, char *, const void *, int);
 int	OF_finddevice(char *);
+int	OF_canon(char *, char *, int);
 int	OF_instance_to_path(int, char *, int);
 int	OF_package_to_path(int, char *, int);
 int	OF_call_method_1(char *, int, int, ...);