This patch resolves our need for some devices (bridges) to have multiple links. 
The K8 is one example, but there are other devices (e.g. I2C) that also have 
multiple links. The way this was done in v2 was a big confusing; this way is 
less so. 

The changes are easy. Getting them right has been hard :-)

First, for a k8 north that has three links, you can name each one as follows:
pci0@18,0
pci1@18,0
pci2@18,0

We have to have the same pcidevfn on these because that is how the k8 works. 
But the unit numbers (pci0, pci1, etc.) distinguish them. 

The dts will properly generate a "v3 device code" 
compatible static tree that puts the links in the right place in the 
data structure. 

The changes to dts are trivial. 
As before, dts nodes with children are understood to be a bridge. 
But what if there is a dts entry like this:
pci1@18,0 {/config/("northbridge/amd/k8/pci");};

This entry has no children in the dts. 
How does dt compiler know it is a bridge? It can not know unless 
we add information to the dts for that northbridge part. 
To ensure that all bridge devices are detected, we support the following: 
if a dts node for a device has a bridge property, e.g.: 
 {
        device_operations = "k8_ops";
       bridge;
 };

The dt compiler will treat it as a bridge whether it has children or not. 

Why would a device not have children? Because it might be attached to a
pci or other socket, and we don't know at build time if the socket is empty, 
or what might be in the socket. 

This code has been tested on dbe62 and k8 simnow, and works on each. 
It is minimal in size and it does what we need. I hope it resolves our 
discussion for now. We might want to improve or change the device code
later but, at this point, forward motion is important -- I'm on a deadline for
a very important demo Oct. 22!

Also included in this patch are new debug prints in k8 north. 

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>

IIndex: mainboard/amd/serengeti/dts
===================================================================
--- mainboard/amd/serengeti/dts	(revision 862)
+++ mainboard/amd/serengeti/dts	(working copy)
@@ -28,7 +28,7 @@
 		pci@1,0{
 		};
 		/* guesses; we need a real lspci */
-		pci@18,0 {
+		pci0@18,0 {
 			/config/("northbridge/amd/k8/pci");
 			pci@0,0 {
 				/config/("southbridge/amd/amd8111/amd8111.dts");
@@ -40,6 +40,15 @@
 				/config/("southbridge/amd/amd8111/nic.dts");
 			};
 		};
+		pci1@18,0 {
+			/config/("northbridge/amd/k8/pci");
+		};
+		pci2@18,0 {
+			/config/("northbridge/amd/k8/pci");
+			/* just for illustrating link #2 */
+			pci@2,0{
+			};
+		};
 		ioport@2e {
 			/config/("superio/winbond/w83627hf/dts");
 			com1enable = "1";
Index: northbridge/amd/k8/domain.c
===================================================================
--- northbridge/amd/k8/domain.c	(revision 862)
+++ northbridge/amd/k8/domain.c	(working copy)
@@ -104,6 +104,7 @@
 	unsigned reg;
 
 	/* Find the already assigned resource pairs */
+	printk(BIOS_DEBUG, "k8_pci_domain_read_resources\n");
 	get_fx_devs();
 	for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
 		u32 base, limit;
@@ -166,6 +167,7 @@
 
 static void k8_pci_domain_set_resources(struct device * dev)
 {
+	printk(BIOS_DEBUG, "k8_pci_domain_set_resources\n");
 #if CONFIG_HW_MEM_HOLE_SIZEK != 0
 	struct hw_mem_hole_info get_hw_mem_hole_info(void);
 	void disable_hoist_memory(unsigned long hole_startk, int i);
@@ -367,6 +369,7 @@
 {
 	unsigned reg;
 	int i;
+	printk(BIOS_DEBUG, "k8_domain_scan_bus\n");
 	/* Unmap all of the HT chains */
 	for(reg = 0xe0; reg <= 0xec; reg += 4) {
 		f1_write_config32(reg, 0);
Index: northbridge/amd/k8/pci
===================================================================
--- northbridge/amd/k8/pci	(revision 862)
+++ northbridge/amd/k8/pci	(working copy)
@@ -20,4 +20,5 @@
 
 {
 	device_operations = "k8_ops";
+	bridge;
 };
Index: northbridge/amd/k8/pci.c
===================================================================
--- northbridge/amd/k8/pci.c	(revision 862)
+++ northbridge/amd/k8/pci.c	(working copy)
@@ -74,6 +74,7 @@
 		if (!(link_type & LinkConnected)) {
 			return max;
 		}
+		printk(BIOS_DEBUG, "amdk8_scan_chain: link %d is connected\n", link);
 		do {
 			link_type = pci_read_config32(dev, dev->link[link].cap + 0x18);
 		} while(!(link_type & InitComplete));
@@ -211,6 +212,8 @@
 	unsigned offset_unitid = 0;
         nodeid = amdk8_nodeid(dev);
 	
+	printk(BIOS_DEBUG, "amdk8_scan_chains\n");
+
         if(nodeid==0) {
                 sblink = (pci_read_config32(dev, 0x64)>>8) & 3;
 #if SB_HT_CHAIN_ON_BUS0 > 0
@@ -371,6 +374,7 @@
 
 static void amdk8_read_resources(struct device * dev)
 {
+	printk(BIOS_DEBUG, "amdk8_read_resources\n");
 	unsigned nodeid, link;
 	nodeid = amdk8_nodeid(dev);
 	for(link = 0; link < dev->links; link++) {
@@ -385,7 +389,7 @@
 	resource_t rbase, rend;
 	unsigned reg, link;
 	char buf[50];
-
+	printk(BIOS_DEBUG, "amdk8_set_resource\n");
 	/* Make certain the resource has actually been set */
 	if (!(resource->flags & IORESOURCE_ASSIGNED)) {
 		return;
@@ -536,6 +540,7 @@
 	/* Find the nodeid */
 	nodeid = amdk8_nodeid(dev);
 
+	printk(BIOS_DEBUG, "amdk8_set_resources: nodeid %d\n", nodeid);
 	amdk8_create_vga_resource(dev, nodeid);
 	
 	/* Set each resource we have found */
@@ -554,6 +559,7 @@
 
 static void amdk8_enable_resources(struct device * dev)
 {
+	printk(BIOS_DEBUG, "amdk8_enable_resources\n");
 	pci_dev_enable_resources(dev);
 	enable_childrens_resources(dev);
 }
Index: northbridge/amd/geodelx/pci
===================================================================
--- northbridge/amd/geodelx/pci	(revision 862)
+++ northbridge/amd/geodelx/pci	(working copy)
@@ -20,5 +20,6 @@
 
 {
 	device_operations = "geodelx_north_pci";
+	bridge;
 };
 
Index: util/dtc/flattree.c
===================================================================
--- util/dtc/flattree.c	(revision 862)
+++ util/dtc/flattree.c	(working copy)
@@ -529,6 +529,31 @@
 	fprintf(f, "\tu32 p%d = \tOF_DT_PROP;\n", unique++);
 }
 
+/* Is the node a bridge? 
+ * If it has children, yes. 
+ * OR if it has a config, if the config has 
+ * the 'bridge' property, yes. 
+ */
+static int is_bridge(struct node *tree)
+{
+	int bridge = 0;
+	struct property *prop;
+	/* simple test: does it have children? If so, it's a bridge */
+	if (tree->children)
+		return 1;
+	if (tree->config){
+		for_each_config(tree, prop) {
+			if (streq(prop->name, "bridge")){
+				bridge = 1;
+			}
+		}
+	}
+
+	return bridge;
+
+}
+
+
 static void coreboot_emit_special(FILE *e, struct node *tree)
 {
 	FILE *f = e;
@@ -538,6 +563,7 @@
 	char *configname;
 	char *path;
 	int enabled = 1;
+	int linkcount = 0;
 
 	fprintf(f, "struct device dev_%s = {\n", tree->label);
 	/* special case -- the root has a distinguished path */
@@ -661,23 +687,56 @@
 	}
 	if (tree->next_sibling) 
 		fprintf(f, "\t.sibling = &dev_%s,\n", tree->next_sibling->label);
-	/* now do we do next? */
-	/* this will need to do a bus for every child. And, below, we're going to need to find which bus we're on*/
-	/* for now, let's keep it to the minimum that will work, while we see if we like this. */
-	if (tree->children){
-		fprintf(f,"\t.links = 1,\n");
+
+	/* If we are a bridge, and we have not been linked, then set up our links.
+	 * There is a good chance we could expand the for loop to contain this first bit of code. 
+	 * OTOH, the compiler can do it for us, and the initial conditions are clearer this way.
+	 */
+	if ((! tree->linked) && is_bridge(tree)){
+		struct node *siblings; 
 		fprintf(f,"\t.link = {\n");
-		fprintf(f,"\t\t[0] = {\n");
+		fprintf(f,"\t\t[%d] = {\n", linkcount);
 		fprintf(f,"\t\t\t.dev = &dev_%s,\n", tree->label);
-		fprintf(f,"\t\t\t.link = 0,\n");
-		fprintf(f,"\t\t\t.children = &dev_%s\n", tree->children->label);
+		fprintf(f,"\t\t\t.link = %d,\n", linkcount);
+		if (tree->children)
+			fprintf(f,"\t\t\t.children = &dev_%s\n", tree->children->label);
 		fprintf(f,"\t\t},\n");
+		/* indicate that we are linked. We just point to ourselves; this makes later code
+		 * simpler and is not wrong. 
+		 */
+		tree->linked = 1;
+		tree->whichlink = linkcount;
+		tree->linknode = tree;
+		/* now we need to handle our siblings. */
+		linkcount++;
+		for_all_siblings(tree, siblings) {
+			if (is_bridge(siblings) && (!siblings->linked)){
+				fprintf(f,"\t\t[%d] = {\n", linkcount);
+				fprintf(f,"\t\t\t.dev = &dev_%s,\n", siblings->label);
+				fprintf(f,"\t\t\t.link = %d,\n", linkcount);
+				if (siblings->children) {
+					fprintf(f,"\t\t\t.children = &dev_%s\n", siblings->children->label);
+					siblings->children->linked = 1;
+					siblings->children->linknode = tree;
+					siblings->children->whichlink = linkcount;
+				}
+				fprintf(f,"\t\t},\n");
+				siblings->linked = 1;
+				siblings->whichlink = linkcount;
+				siblings->linknode = tree;
+				linkcount++;
+			}
+		}
 		fprintf(f,"\t},\n");
 	}
+	fprintf(f,"\t.links = %d,\n", linkcount);
 	/* fill in the 'bus I am on' entry */
-	if (tree->parent)
+	/* being 'linked' on a bus overrides the parent link */
+	if (tree->linked) 
+		fprintf(f, "\t.bus = &dev_%s.link[%d],\n", tree->linknode->label, tree->whichlink);
+	else if (tree->parent)
 		fprintf(f, "\t.bus = &dev_%s.link[0],\n", tree->parent->label);
-	else
+	else 		/* this is a very unusual case: the root */
 		fprintf(f, "\t.bus = &dev_%s.link[0],\n", tree->label);
 
 	if (tree->next)
@@ -784,6 +843,8 @@
 
 }
 
+char *emitted_names[256];
+int emitted_names_count = 0;
 static void flatten_tree_emit_structdecls(struct node *tree, struct emitter *emit,
 			 void *etarget, struct data *strbuf,
 			 struct version_info *vi)
@@ -794,10 +855,24 @@
 	struct node *child;
 	int seen_name_prop = 0;
 	FILE *f = etarget;
+	int doconfig = 0;
+	int already_done = 0;
 
 	if (tree->config){
+		int i;
 //		treename = clean(tree->label, 0);
 		treename = toname(tree->config->label, "_config");
+		for(i = 0; i < emitted_names_count; i++)
+			if (!strcmp(treename, emitted_names[i]))
+				already_done++;
+		if (! already_done) {
+			emitted_names[emitted_names_count++] = treename;
+			doconfig = 1;
+		}
+	}
+
+	if (doconfig) {
+
 		emit->beginnode(etarget, treename);
 
 
Index: util/dtc/dtc.h
===================================================================
--- util/dtc/dtc.h	(revision 862)
+++ util/dtc/dtc.h	(working copy)
@@ -166,6 +166,10 @@
 	int addr_cells, size_cells;
 
 	char *label;
+	/* coreboot-specific */
+	int linked; /* has this node been added to the links for a bridge? */
+	struct node *linknode; /* If I am linked, which node is it? */
+	int whichlink; /* which link of the node am I on? */
 };
 
 #define for_each_property(n, p) \
@@ -174,6 +178,10 @@
 #define for_each_child(n, c)	\
 	for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
 
+/* N.B.: includes ourselves */
+#define for_all_siblings(n, s)	\
+	for ((s) = (n->next_sibling); (s); (s) = (s)->next_sibling)
+
 #define for_each_config(n, p)	\
 	for ((p) = (n)->config; (p); (p) = (p)->next)
 
