- O2, enums, and switch statements work in romcc
  - Support for compiling romcc on non x86 platforms
  - new romc options -msse and -mmmx for specifying extra registers to use
  - Bug fixes to device the device disable/enable framework and an amd8111 implementation
  - Move the link specification to the chip specification instead of the path
  - Allow specifying devices with internal bridges.
  - Initial via epia support
 - Opteron errata fixes


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1200 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/src/devices/chip.c b/src/devices/chip.c
index b7eace3..c9e1ac5 100644
--- a/src/devices/chip.c
+++ b/src/devices/chip.c
@@ -46,16 +46,33 @@
 		int identical_paths;
 		identical_paths = 
 			(i > 0) &&
-			(path_eq(&chip->path[i - 1].path, &chip->path[i].path)) &&
-			(chip->path[i - 1].channel == chip->path[i].channel);
+			(path_eq(&chip->path[i - 1].path, &chip->path[i].path));
 		if (!identical_paths) {
+			struct bus *parent;
+			int bus;
 			link = 0;
 			dev = 0;
+			parent = chip->bus;
 			switch(chip->path[i].path.type) {
 			case DEVICE_PATH_NONE:
 				break;
+			case DEVICE_PATH_PCI:
+				bus = chip->path[i].path.u.pci.bus;
+				if (bus != 0) {
+					device_t dev;
+					int i = 1;
+					dev = chip->dev;
+					while(dev && (i != bus)) {
+						dev = dev->next;
+						i++;
+					}
+					if ((i == bus) && dev) {
+						parent = &dev->link[0];
+					}
+				}
+				/* Fall through */
 			default:
-				dev = alloc_dev(chip->bus, &chip->path[i].path);
+				dev = alloc_dev(parent, &chip->path[i].path);
 				break;
 			}
 		}
@@ -63,12 +80,13 @@
 			link += 1;
 		}
 		if (dev) {
-			printk_spew("path %s %s\n", dev_path(dev), identical_paths?"identical":"");
+			printk_spew("path (%p) %s %s", dev, dev_path(dev), identical_paths?"identical":"");
+			printk_spew(" parent: (%p) %s\n",dev->bus->dev,  dev_path(dev->bus->dev));
+			dev->chip = chip;
 			dev->enable = chip->path[i].enable;
 			dev->links = link + 1;
 			for(child = chip->children; child; child = child->next) {
-				if (!child->bus &&
-					child->path[0].channel == i) {
+				if (!child->bus && child->link == i) {
 					child->bus = &dev->link[link];
 				}
 			}
diff --git a/src/devices/device.c b/src/devices/device.c
index 289c076..c6dd5fc 100644
--- a/src/devices/device.c
+++ b/src/devices/device.c
@@ -115,6 +115,9 @@
 				dev_path(curdev));
 			continue;
 		}
+		if (!curdev->enable) {
+			continue;
+		}
 		curdev->ops->read_resources(curdev);
 		/* Read in subtractive resources behind the current device */
 		links = 0;
@@ -251,16 +254,12 @@
 	min_align = 0;
 	base = bridge->base;
 
-	printk_spew("%s: bus %p, bridge %p, type_mask 0x%x, type 0x%x\n",
-				__FUNCTION__, 
-				bus, bridge, type_mask, type);
-	printk_spew("vendor 0x%x device 0x%x class 0x%x \n", 
-			bus->dev->vendor, bus->dev->device, bus->dev->class);
-		printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", 
-			dev_path(bus->dev),
-			(bridge->flags & IORESOURCE_IO)? "io":
-			(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
-			base, bridge->size, bridge->align, bridge->gran);
+	printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", 
+		dev_path(bus->dev),
+		(bridge->flags & IORESOURCE_IO)? "io":
+		(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
+		base, bridge->size, bridge->align, bridge->gran);
+
 
 	/* We want different minimum alignments for different kinds of
 	 * resources.  These minimums are not device type specific
@@ -406,6 +405,9 @@
 				dev_path(curdev));
 			continue;
 		}
+		if (!curdev->enable) {
+			continue;
+		}
 		curdev->ops->set_resources(curdev);
 	}
 	printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary);
@@ -422,6 +424,9 @@
 			dev_path(dev));
 		return;
 	}
+	if (!dev->enable) {
+		return;
+	}
 	dev->ops->enable_resources(dev);
 }
 
@@ -444,13 +449,12 @@
 void dev_configure(void)
 {
 	struct device *root = &dev_root;
-	printk_info("%s: Allocating resources...", __FUNCTION__);
+	printk_info("Allocating resources...");
 	printk_debug("\n");
 
 
 	root->ops->read_resources(root);
 
-	printk_spew("%s: done reading resources...\n", __FUNCTION__);
 	/* Make certain the io devices are allocated somewhere
 	 * safe.
 	 */
@@ -465,10 +469,8 @@
 	root->resource[1].flags |= IORESOURCE_SET;
 	// now just set things into registers ... we hope ...
 	root->ops->set_resources(root);
-	printk_spew("%s: done setting resources...\n", __FUNCTION__);
 
 	allocate_vga_resource();
-	printk_spew("%s: done vga resources...\n", __FUNCTION__);
 
 	printk_info("done.\n");
 }
@@ -494,7 +496,7 @@
 
 	printk_info("Initializing devices...\n");
 	for (dev = all_devices; dev; dev = dev->next) {
-		if (dev->ops && dev->ops->init) {
+		if (dev->enable && dev->ops && dev->ops->init) {
 			printk_debug("%s init\n", dev_path(dev));
 			dev->ops->init(dev);
 		}
diff --git a/src/devices/device_util.c b/src/devices/device_util.c
index 384a3be..6652c86 100644
--- a/src/devices/device_util.c
+++ b/src/devices/device_util.c
@@ -30,15 +30,17 @@
  */
 struct device *dev_find_slot(unsigned int bus, unsigned int devfn)
 {
-	struct device *dev;
+	struct device *dev, *result;
 
+	result = 0;
 	for (dev = all_devices; dev; dev = dev->next) {
 		if ((dev->bus->secondary == bus) && 
 			(dev->path.u.pci.devfn == devfn)) {
+			result = dev;
 			break;
 		}
 	}
-	return dev;
+	return result;
 }
 
 /** Find a device of a given vendor and type
@@ -88,6 +90,9 @@
 	}
 	else {
 		switch(dev->path.type) {
+		case DEVICE_PATH_ROOT:
+			memcpy(buffer, "Root Device", 12);
+			break;
 		case DEVICE_PATH_PCI:
 			sprintf(buffer, "PCI: %02x:%02x.%01x",
 				dev->bus->secondary, 
@@ -116,8 +121,12 @@
 		switch(path1->type) {
 		case DEVICE_PATH_NONE:
 			break;
+		case DEVICE_PATH_ROOT:
+			equal = 1;
+			break;
 		case DEVICE_PATH_PCI:
-			equal = path1->u.pci.devfn == path2->u.pci.devfn;
+			equal = (path1->u.pci.bus == path2->u.pci.bus) &&
+				(path1->u.pci.devfn == path2->u.pci.devfn);
 			break;
 		case DEVICE_PATH_PNP:
 			equal = (path1->u.pnp.port == path2->u.pnp.port) &&
diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c
index 0c1dc39..326f343 100644
--- a/src/devices/hypertransport.c
+++ b/src/devices/hypertransport.c
@@ -4,6 +4,7 @@
 #include <device/path.h>
 #include <device/pci.h>
 #include <device/hypertransport.h>
+#include <device/chip.h>
 #include <part/hard_reset.h>
 #include <part/fallback_boot.h>
 
@@ -243,11 +244,19 @@
 			/* Add this device to the pci bus chain */
 			*chain_last = dev;
 			/* Run the magice enable/disable sequence for the device */
-			if (dev->ops && dev->ops->enable) {
-				dev->ops->enable(dev);
+			if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) {
+				dev->chip->control->enable_dev(dev);
 			}
 			/* Now read the vendor and device id */
 			id = pci_read_config32(dev, PCI_VENDOR_ID);
+
+			/* If the chain is fully enumerated quit */
+			if (id == 0xffffffff || id == 0x00000000 ||
+				id == 0x0000ffff || id == 0xffff0000) {
+				printk_err("Missing static device: %s\n",
+					dev_path(dev));
+				break;
+			}
 		}
 		/* Update the device chain tail */
 		for(func = dev; func; func = func->sibling) {
@@ -268,7 +277,8 @@
 		/* Find the hypertransport link capability */
 		pos = ht_lookup_slave_capability(dev);
 		if (pos == 0) {
-			printk_err("Hypertransport link capability not found");
+			printk_err("%s Hypertransport link capability not found", 
+				dev_path(dev));
 			break;
 		}
 		
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c
index 806734c..031d855 100644
--- a/src/devices/pci_device.c
+++ b/src/devices/pci_device.c
@@ -18,6 +18,7 @@
 #include <device/device.h>
 #include <device/pci.h>
 #include <device/pci_ids.h>
+#include <device/chip.h>
 #include <part/hard_reset.h>
 #include <part/fallback_boot.h>
 
@@ -175,7 +176,6 @@
 
 	/* FIXME handle bridges without some of the optional resources */
 
-	printk_spew("%s: path %s\n", __FUNCTION__, dev_path(dev));
 	/* Initialize the io space constraints on the current bus */
 	dev->resource[reg].base  = 0;
 	dev->resource[reg].size  = 0;
@@ -215,7 +215,6 @@
 	reg++;
 
 	dev->resources = reg;
-	printk_spew("DONE %s: path %s\n", __FUNCTION__, dev_path(dev));
 }
 
 
@@ -455,11 +454,13 @@
 		break;
 	default:
 	bad:
-		printk_err("%s [%04x/%04x/%06x] has unknown header "
-			"type %02x, ignoring.\n",
-			dev_path(dev),
-			dev->vendor, dev->device, 
-			dev->class >> 8, dev->hdr_type);
+		if (dev->enable) {
+			printk_err("%s [%04x/%04x/%06x] has unknown header "
+				"type %02x, ignoring.\n",
+				dev_path(dev),
+				dev->vendor, dev->device, 
+				dev->class >> 8, dev->hdr_type);
+		}
 	}
 	return;
 }
@@ -556,17 +557,16 @@
 		}
 		else {
 			/* Run the magic enable/disable sequence for the device */
-			if (dev->ops && dev->ops->enable) {
-				dev->ops->enable(dev);
+			if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) {
+				dev->chip->control->enable_dev(dev);
 			}
 			/* Now read the vendor and device id */
 			id = pci_read_config32(dev, PCI_VENDOR_ID);
 		}
-
 		/* Read the rest of the pci configuration information */
 		hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
 		class = pci_read_config32(dev, PCI_CLASS_REVISION);
-
+		
 		/* Store the interesting information in the device structure */
 		dev->vendor = id & 0xffff;
 		dev->device = (id >> 16) & 0xffff;
@@ -576,20 +576,19 @@
 
 		/* Look at the vendor and device id, or at least the 
 		 * header type and class and figure out which set of configuration
-		 * methods to use.
+		 * methods to use.  Unless we already have some pci ops.
 		 */
-		if (!dev->ops) {
-			set_pci_ops(dev);
-			/* Error if we don't have some pci operations for it */
-			if (!dev->ops) {
-				printk_err("%s No device operations\n",
-					dev_path(dev));
-				continue;
-			}
-			/* Now run the magic enable/disable sequence for the device */
-			if (dev->ops && dev->ops->enable) {
-				dev->ops->enable(dev);
-			}
+		set_pci_ops(dev);
+		/* Error if we don't have some pci operations for it */
+		if (dev->enable && !dev->ops) {
+			printk_err("%s No device operations\n",
+				dev_path(dev));
+			continue;
+		}
+
+		/* Now run the magic enable/disable sequence for the device */
+		if (dev->ops && dev->ops->enable) {
+			dev->ops->enable(dev);
 		}
 
 		printk_debug("%s [%04x/%04x] %s\n", 
@@ -632,8 +631,7 @@
 	struct bus *bus;
 	uint32_t buses;
 	uint16_t cr;
-	
-	printk_spew("%s: dev %p, max %d\n", __FUNCTION__, dev, max);
+
 	bus = &dev->link[0];
 	dev->links = 1;
 
@@ -707,7 +705,6 @@
 	}
 }
 
-
 /*
     This function assigns IRQs for all functions contained within
     the indicated device address.  If the device does not exist or does
diff --git a/src/devices/root_device.c b/src/devices/root_device.c
index ae02277..4a076a1 100644
--- a/src/devices/root_device.c
+++ b/src/devices/root_device.c
@@ -123,6 +123,8 @@
 struct device dev_root = {
 	.ops = &default_dev_ops_root,
 	.bus = &dev_root.link[0],
+	.path = { .type = DEVICE_PATH_ROOT },
+	.enable = 1,
 	.links = 1,
 	.link = {
 		[0] = {