Patch from Russell King - 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); _