Patch from Russell King <rmk@arm.linux.org.uk>

- Eliminate the stack allocation of a struct pci_dev, and make
  pci_scan_slot() take a bus and a devfn argument.
- Add "dev->multifunction" to indicate whether this is a multifunction
  device.
- Run header fixups before inserting the new pci device into any
  device lists or announcing it to the drivers.
- Convert some more stuff to use the list_for_each* macro(s).

  No real behavioural change yet.



 25-akpm/drivers/hotplug/acpiphp_glue.c     |   12 ----
 25-akpm/drivers/hotplug/cpci_hotplug_pci.c |    8 --
 25-akpm/drivers/hotplug/cpqphp_pci.c       |    9 ---
 25-akpm/drivers/hotplug/ibmphp_core.c      |   12 +---
 25-akpm/drivers/pci/probe.c                |   87 ++++++++++++++---------------
 25-akpm/include/linux/pci.h                |    3 -
 6 files changed, 54 insertions(+), 77 deletions(-)

diff -puN drivers/hotplug/acpiphp_glue.c~pci-2 drivers/hotplug/acpiphp_glue.c
--- 25/drivers/hotplug/acpiphp_glue.c~pci-2	Tue Mar  4 16:49:11 2003
+++ 25-akpm/drivers/hotplug/acpiphp_glue.c	Tue Mar  4 16:49:11 2003
@@ -801,7 +801,7 @@ static int power_off_slot (struct acpiph
 static int enable_device (struct acpiphp_slot *slot)
 {
 	u8 bus;
-	struct pci_dev dev0, *dev;
+	struct pci_dev *dev;
 	struct pci_bus *child;
 	struct list_head *l;
 	struct acpiphp_func *func;
@@ -824,16 +824,8 @@ static int enable_device (struct acpiphp
 	if (retval)
 		goto err_exit;
 
-	memset(&dev0, 0, sizeof (struct pci_dev));
-
-	dev0.bus = slot->bridge->pci_bus;
-	dev0.devfn = PCI_DEVFN(slot->device, 0);
-	dev0.sysdata = dev0.bus->sysdata;
-	dev0.dev.parent = dev0.bus->dev;
-	dev0.dev.bus = &pci_bus_type;
-
 	/* returned `dev' is the *first function* only! */
-	dev = pci_scan_slot (&dev0);
+	dev = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
 
 	if (!dev) {
 		err("No new device found\n");
diff -puN drivers/hotplug/cpci_hotplug_pci.c~pci-2 drivers/hotplug/cpci_hotplug_pci.c
--- 25/drivers/hotplug/cpci_hotplug_pci.c~pci-2	Tue Mar  4 16:49:11 2003
+++ 25-akpm/drivers/hotplug/cpci_hotplug_pci.c	Tue Mar  4 16:49:11 2003
@@ -574,19 +574,13 @@ int cpci_configure_slot(struct slot* slo
 
 	/* Still NULL? Well then scan for it! */
 	if(slot->dev == NULL) {
-		struct pci_dev dev0;
-
 		dbg("pci_dev still null");
-		memset(&dev0, 0, sizeof (struct pci_dev));
-		dev0.bus = slot->bus;
-		dev0.devfn = slot->devfn;
-		dev0.sysdata = slot->bus->self->sysdata;
 
 		/*
 		 * This will generate pci_dev structures for all functions, but
 		 * we will only call this case when lookup fails.
 		 */
-		slot->dev = pci_scan_slot(&dev0);
+		slot->dev = pci_scan_slot(slot->bus, slot->devfn);
 		if(slot->dev == NULL) {
 			err("Could not find PCI device for slot %02x", slot->number);
 			return 0;
diff -puN drivers/hotplug/cpqphp_pci.c~pci-2 drivers/hotplug/cpqphp_pci.c
--- 25/drivers/hotplug/cpqphp_pci.c~pci-2	Tue Mar  4 16:49:11 2003
+++ 25-akpm/drivers/hotplug/cpqphp_pci.c	Tue Mar  4 16:49:11 2003
@@ -84,24 +84,19 @@ static void *detect_HRT_floating_pointer
 int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)  
 {
 	unsigned char bus;
-	struct pci_dev dev0;
 	struct pci_bus *child;
 	int rc = 0;
 
-	memset(&dev0, 0, sizeof(struct pci_dev));
-
 	if (func->pci_dev == NULL)
 		func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7));
 
 	//Still NULL ? Well then scan for it !
 	if (func->pci_dev == NULL) {
 		dbg("INFO: pci_dev still null\n");
-		dev0.bus = ctrl->pci_dev->bus;
-		dev0.devfn = (func->device << 3) + (func->function & 0x7);
-		dev0.sysdata = ctrl->pci_dev->sysdata;
 
 		//this will generate pci_dev structures for all functions, but we will only call this case when lookup fails
-		func->pci_dev = pci_scan_slot(&dev0);
+		func->pci_dev = pci_scan_slot(ctrl->pci_dev->bus,
+				 (func->device << 3) + (func->function & 0x7));
 		if (func->pci_dev == NULL) {
 			dbg("ERROR: pci_dev still null\n");
 			return 0;
diff -puN drivers/hotplug/ibmphp_core.c~pci-2 drivers/hotplug/ibmphp_core.c
--- 25/drivers/hotplug/ibmphp_core.c~pci-2	Tue Mar  4 16:49:11 2003
+++ 25-akpm/drivers/hotplug/ibmphp_core.c	Tue Mar  4 16:50:10 2003
@@ -845,26 +845,22 @@ static u8 bus_structure_fixup (u8 busno)
 static int ibm_configure_device (struct pci_func *func)
 {
 	unsigned char bus;
-	struct pci_dev dev0;
 	struct pci_bus *child;
 	int rc = 0;
 	int flag = 0;	/* this is to make sure we don't double scan the bus, for bridged devices primarily */
 
-	memset (&dev0, 0, sizeof (struct pci_dev));
-
 	if (!(bus_structure_fixup (func->busno)))
 		flag = 1;
 	if (func->dev == NULL)
 		func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
 
 	if (func->dev == NULL) {
-		dev0.bus = ibmphp_find_bus (func->busno);
-		if (!dev0.bus)
+		struct pci_bus *bus = ibmphp_find_bus (func->busno);
+		if (!bus)
 			return 0;
-		dev0.devfn = ((func->device << 3) + (func->function & 0x7));
-		dev0.sysdata = dev0.bus->sysdata;
 
-		func->dev = pci_scan_slot (&dev0);
+		func->dev = pci_scan_slot(bus,
+				 (func->device << 3) + (func->function & 0x7));
 
 		if (func->dev == NULL) {
 			err ("ERROR... : pci_dev still NULL \n");
diff -puN drivers/pci/probe.c~pci-2 drivers/pci/probe.c
--- 25/drivers/pci/probe.c~pci-2	Tue Mar  4 16:49:11 2003
+++ 25-akpm/drivers/pci/probe.c	Tue Mar  4 16:49:11 2003
@@ -374,7 +374,8 @@ int pci_setup_device(struct pci_dev * de
 	dev->class = class;
 	class >>= 8;
 
-	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn,
+		dev->vendor, dev->device, class, dev->hdr_type);
 
 	/* "Unknown power state" */
 	dev->current_state = 4;
@@ -427,23 +428,35 @@ int pci_setup_device(struct pci_dev * de
  * Read the config data for a PCI device, sanity-check it
  * and fill in the dev structure...
  */
-struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
+static struct pci_dev * __devinit
+pci_scan_device(struct pci_bus *bus, int devfn)
 {
 	struct pci_dev *dev;
 	u32 l;
+	u8 hdr_type;
+
+	if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
+		return NULL;
 
-	if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l))
+	if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
 		return NULL;
 
 	/* some broken boards return 0 or ~0 if a slot is empty: */
 	if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
 		return NULL;
 
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
 	if (!dev)
 		return NULL;
 
-	memcpy(dev, temp, sizeof(*dev));
+	memset(dev, 0, sizeof(struct pci_dev));
+	dev->bus = bus;
+	dev->sysdata = bus->sysdata;
+	dev->dev.parent = bus->dev;
+	dev->dev.bus = &pci_bus_type;
+	dev->devfn = devfn;
+	dev->hdr_type = hdr_type & 0x7f;
+	dev->multifunction = !!(hdr_type & 0x80);
 	dev->vendor = l & 0xffff;
 	dev->device = (l >> 16) & 0xffff;
 
@@ -461,42 +474,44 @@ struct pci_dev * __devinit pci_scan_devi
 	strcpy(dev->dev.bus_id,dev->slot_name);
 	dev->dev.dma_mask = &dev->dma_mask;
 
-	device_register(&dev->dev);
 	return dev;
 }
 
-struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
+struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
 {
-	struct pci_bus *bus = temp->bus;
-	struct pci_dev *dev;
 	struct pci_dev *first_dev = NULL;
-	int func = 0;
-	int is_multi = 0;
-	u8 hdr_type;
+	int func;
 
-	for (func = 0; func < 8; func++, temp->devfn++) {
-		if (func && !is_multi)		/* not a multi-function device */
-			continue;
-		if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
-			continue;
-		temp->hdr_type = hdr_type & 0x7f;
+	for (func = 0; func < 8; func++, devfn++) {
+		struct pci_dev *dev;
 
-		dev = pci_scan_device(temp);
+		dev = pci_scan_device(bus, devfn);
 		if (!dev)
 			continue;
-		if (!func) {
-			is_multi = hdr_type & 0x80;
+
+		if (func == 0) {
 			first_dev = dev;
+		} else {
+			dev->multifunction = 1;
 		}
 
+		/* Fix up broken headers */
+		pci_fixup_device(PCI_FIXUP_HEADER, dev);
+
 		/*
 		 * Link the device to both the global PCI device chain and
 		 * the per-bus list of devices and add the /proc entry.
+		 * Note: this also runs the hotplug notifiers (bad!) --rmk
 		 */
+		device_register(&dev->dev);
 		pci_insert_device (dev, bus);
 
-		/* Fix up broken headers */
-		pci_fixup_device(PCI_FIXUP_HEADER, dev);
+		/*
+		 * If this is a single function device,
+		 * don't scan past the first function.
+		 */
+		if (!dev->multifunction)
+			break;
 	}
 	return first_dev;
 }
@@ -507,28 +522,12 @@ unsigned int __devinit pci_do_scan_bus(s
 	struct list_head *ln;
 	struct pci_dev *dev;
 
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		printk(KERN_ERR "Out of memory in %s\n", __FUNCTION__);
-		return 0;
-	}
-
 	DBG("Scanning bus %02x\n", bus->number);
 	max = bus->secondary;
 
-	/* Create a device template */
-	memset(dev, 0, sizeof(*dev));
-	dev->bus = bus;
-	dev->sysdata = bus->sysdata;
-	dev->dev.parent = bus->dev;
-	dev->dev.bus = &pci_bus_type;
-
 	/* Go find them, Rover! */
-	for (devfn = 0; devfn < 0x100; devfn += 8) {
-		dev->devfn = devfn;
-		pci_scan_slot(dev);
-	}
-	kfree(dev);
+	for (devfn = 0; devfn < 0x100; devfn += 8)
+		pci_scan_slot(bus, devfn);
 
 	/*
 	 * After performing arch-dependent fixup of the bus, look behind
@@ -537,9 +536,9 @@ unsigned int __devinit pci_do_scan_bus(s
 	DBG("Fixups for bus %02x\n", bus->number);
 	pcibios_fixup_bus(bus);
 	for (pass=0; pass < 2; pass++)
-		for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-			dev = pci_dev_b(ln);
-			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+		list_for_each_entry(dev, &bus->devices, bus_list) {
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 				max = pci_scan_bridge(bus, dev, max, pass);
 		}
 
diff -puN include/linux/pci.h~pci-2 include/linux/pci.h
--- 25/include/linux/pci.h~pci-2	Tue Mar  4 16:49:11 2003
+++ 25-akpm/include/linux/pci.h	Tue Mar  4 16:49:11 2003
@@ -413,6 +413,7 @@ struct pci_dev {
 
 	/* These fields are used by common fixups */
 	unsigned int	transparent:1;	/* Transparent PCI bridge */
+	unsigned int	multifunction:1;/* Part of multi-function device */
 };
 
 #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
@@ -548,7 +549,7 @@ static inline struct pci_bus *pci_alloc_
 {
 	return pci_alloc_primary_bus_parented(NULL, bus);
 }
-struct pci_dev *pci_scan_slot(struct pci_dev *temp);
+struct pci_dev *pci_scan_slot(struct pci_bus *bus, int devfn);
 int pci_proc_attach_device(struct pci_dev *dev);
 int pci_proc_detach_device(struct pci_dev *dev);
 int pci_proc_attach_bus(struct pci_bus *bus);

_