patch-2.4.0-test12 linux/drivers/pci/pci.c

Next file: linux/drivers/pci/setup-bus.c
Previous file: linux/drivers/parport/parport_pc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test11/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
@@ -300,18 +300,25 @@
 pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
 {
 	const struct pci_device_id *id;
+	int ret = 0;
 
 	if (drv->id_table) {
 		id = pci_match_device(drv->id_table, dev);
-		if (!id)
-			return 0;
+		if (!id) {
+			ret = 0;
+			goto out;
+		}
 	} else
 		id = NULL;
+
+	dev_probe_lock();
 	if (drv->probe(dev, id) >= 0) {
 		dev->driver = drv;
-		return 1;
+		ret = 1;
 	}
-	return 0;
+	dev_probe_unlock();
+out:
+	return ret;
 }
 
 int
@@ -354,16 +361,16 @@
 run_sbin_hotplug(struct pci_dev *pdev, int insert)
 {
 	int i;
-	char *argv[3], *envp[7];
-	char id[20], sub_id[24], bus_id[64], class_id[20];
+	char *argv[3], *envp[8];
+	char id[20], sub_id[24], bus_id[24], class_id[20];
 
 	if (!hotplug_path[0])
 		return;
 
-	sprintf(class_id, "PCI_CLASS=%X", pdev->class >> 8);
-	sprintf(id, "PCI_ID=%X/%X", pdev->vendor, pdev->device);
-	sprintf(sub_id, "PCI_SUBSYS_ID=%X/%X", pdev->subsystem_vendor, pdev->subsystem_device);
-	sprintf(bus_id, "PCI_BUS_ID=%s", pdev->slot_name);
+	sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+	sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+	sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
+	sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
 
 	i = 0;
 	argv[i++] = hotplug_path;
@@ -376,6 +383,7 @@
 	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
 	
 	/* other stuff we want to pass to /sbin/hotplug */
+	envp[i++] = class_id;
 	envp[i++] = id;
 	envp[i++] = sub_id;
 	envp[i++] = bus_id;
@@ -539,15 +547,9 @@
 static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
 {
 	unsigned int pos, reg, next;
-	u32 l, sz, tmp;
-	u16 cmd;
+	u32 l, sz;
 	struct resource *res;
 
-	/* Disable IO and memory while we fiddle */
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-	pci_write_config_word(dev, PCI_COMMAND, tmp);
-	
 	for(pos=0; pos<howmany; pos = next) {
 		next = pos+1;
 		res = &dev->resource[pos];
@@ -578,10 +580,11 @@
 			res->start |= ((unsigned long) l) << 32;
 			res->end = res->start + sz;
 			pci_write_config_dword(dev, reg+4, ~0);
-			pci_read_config_dword(dev, reg+4, &tmp);
+			pci_read_config_dword(dev, reg+4, &sz);
 			pci_write_config_dword(dev, reg+4, l);
-			if (l)
-				res->end = res->start + (((unsigned long) ~l) << 32);
+			if (~sz)
+				res->end = res->start + 0xffffffff +
+						(((unsigned long) ~sz) << 32);
 #else
 			if (l) {
 				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
@@ -610,7 +613,6 @@
 		}
 		res->name = dev->name;
 	}
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
 }
 
 void __init pci_read_bridge_bases(struct pci_bus *child)
@@ -710,6 +712,7 @@
 static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
 {
 	struct pci_bus *child;
+	int i;
 
 	/*
 	 * Allocate a new bus, and inherit stuff from the parent..
@@ -731,6 +734,10 @@
 	child->primary = parent->secondary;
 	child->subordinate = 0xff;
 
+	/* Set up default resource pointers.. */
+	for (i = 0; i < 4; i++)
+		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
 	return child;
 }
 
@@ -755,7 +762,7 @@
 
 	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
 	DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
-	if ((buses & 0xffffff) && !pcibios_assign_all_busses()) {
+	if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
 		/*
 		 * Bus already configured by firmware, process it in the first
 		 * pass and just note the configuration.
@@ -771,9 +778,8 @@
 			unsigned int cmax = pci_do_scan_bus(child);
 			if (cmax > max) max = cmax;
 		} else {
-			int i;
-			for (i = 0; i < 4; i++)
-				child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+			unsigned int cmax = child->subordinate;
+			if (cmax > max) max = cmax;
 		}
 	} else {
 		/*
@@ -786,6 +792,7 @@
 		pci_read_config_word(dev, PCI_COMMAND, &cr);
 		pci_write_config_word(dev, PCI_COMMAND, 0x0000);
 		pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
 		child = pci_add_new_bus(bus, dev, ++max);
 		buses = (buses & 0xff000000)
 		      | ((unsigned int)(child->primary)     <<  0)
@@ -799,15 +806,12 @@
 			/* Now we can scan all subordinate buses... */
 			max = pci_do_scan_bus(child);
 		} else {
-			int i;
 			/*
 			 * For CardBus bridges, we leave 4 bus numbers
 			 * as cards with a PCI-to-PCI bridge can be
 			 * inserted later.
 			 */
 			max += 3;
-			for (i = 0; i < 4; i++)
-				child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
 		}
 		/*
 		 * Set the subordinate bus number to its real value.
@@ -1086,6 +1090,9 @@
 	return 0;
 }
 
+
+/* take care to suspend/resume bridges only once */
+
 static int pci_pm_suspend_bus(struct pci_bus *bus)
 {
 	struct list_head *list;
@@ -1097,9 +1104,6 @@
 	/* Walk the device children list */
 	list_for_each(list, &bus->devices)
 		pci_pm_suspend_device(pci_dev_b(list));
-
-	/* Suspend the bus controller.. */
-	pci_pm_suspend_device(bus->self);
 	return 0;
 }
 
@@ -1107,8 +1111,6 @@
 {
 	struct list_head *list;
 
-	pci_pm_resume_device(bus->self);
-
 	/* Walk the device children list */
 	list_for_each(list, &bus->devices)
 		pci_pm_resume_device(pci_dev_b(list));
@@ -1122,18 +1124,26 @@
 static int pci_pm_suspend(void)
 {
 	struct list_head *list;
+	struct pci_bus *bus;
 
-	list_for_each(list, &pci_root_buses)
-		pci_pm_suspend_bus(pci_bus_b(list));
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		pci_pm_suspend_bus(bus);
+		pci_pm_suspend_device(bus->self);
+	}
 	return 0;
 }
 
 static int pci_pm_resume(void)
 {
 	struct list_head *list;
+	struct pci_bus *bus;
 
-	list_for_each(list, &pci_root_buses)
-		pci_pm_resume_bus(pci_bus_b(list));
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		pci_pm_resume_device(bus->self);
+		pci_pm_resume_bus(bus);
+	}
 	return 0;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)