Commit 64964f5b authored by Russell King's avatar Russell King Committed by Linus Torvalds

[PATCH] Only add devices to bus->devices while scanning...

  The pci_find* functions search using the following lists:
        bus->children   (for subordinate buses)
        pci_root_buses  (for all root buses)
        pci_devices     (for devices)

  This leaves one list which we can add devices to without any drivers
  finding the new devices before we've finished with them.

- initialise bus->node list head.

- pci_scan_slot will scan the specified slot, and add the discovered
  devices to the bus->devices list only.  These devices will not
  appear on the global device list, and do not show in sysfs, procfs.
  pci_scan_slot returns the number of functions found.  If you want
  to find the devices, you have to scan bus->devices and look for
  devices where list_empty(&dev->global_list) is true.

- new function "pci_bus_add_devices" adds newly discovered devices
  to the global device lists, and handles the sysfs and procfs
  stuff, making the devices available to drivers.  All our buses
  which have an empty list head are treated as "new" (since they
  are not attached to the parent buses list of children) and are
  also added.  Currently, no buses will be in this state when this
  function is called.

- new function "pci_scan_child_bus" scans a complete bus, building
  a list of devices on bus->devices only, performing bus fixups
  via pcibios_fixup_bus() and scanning behind bridges.  It does
  make devices externally visible.

- pci_do_scan_bus retains its original behaviour - ie, it scans
  and makes devices available immediately.
parent 7c3db3a8
...@@ -12,6 +12,10 @@ ...@@ -12,6 +12,10 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include "pci.h"
/** /**
* pci_bus_alloc_resource - allocate a resource from a parent bus * pci_bus_alloc_resource - allocate a resource from a parent bus
...@@ -64,6 +68,47 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, ...@@ -64,6 +68,47 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
return ret; return ret;
} }
/**
* pci_bus_add_devices - insert newly discovered PCI devices
* @bus: bus to check for new devices
*
* Add newly discovered PCI devices (which are on the bus->devices
* list) to the global PCI device list, add the sysfs and procfs
* entries. Where a bridge is found, add the discovered bus to
* the parents list of child buses, and recurse.
*
* Call hotplug for each new devices.
*/
void __devinit pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
/*
* Skip already-present devices (which are on the
* global device list.)
*/
if (!list_empty(&dev->global_list))
continue;
device_register(&dev->dev);
list_add_tail(&dev->global_list, &pci_devices);
#ifdef CONFIG_PROC_FS
pci_proc_attach_device(dev);
#endif
pci_create_sysfs_dev_files(dev);
/*
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/
if (dev->subordinate && list_empty(&dev->subordinate->node)) {
list_add_tail(&dev->subordinate->node, &dev->bus->children);
pci_bus_add_devices(dev->subordinate);
}
}
}
void pci_enable_bridges(struct pci_bus *bus) void pci_enable_bridges(struct pci_bus *bus)
{ {
struct pci_dev *dev; struct pci_dev *dev;
...@@ -78,4 +123,5 @@ void pci_enable_bridges(struct pci_bus *bus) ...@@ -78,4 +123,5 @@ void pci_enable_bridges(struct pci_bus *bus)
} }
EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL(pci_bus_alloc_resource);
EXPORT_SYMBOL(pci_bus_add_devices);
EXPORT_SYMBOL(pci_enable_bridges); EXPORT_SYMBOL(pci_enable_bridges);
...@@ -221,6 +221,7 @@ static struct pci_bus * __devinit pci_alloc_bus(void) ...@@ -221,6 +221,7 @@ static struct pci_bus * __devinit pci_alloc_bus(void)
b = kmalloc(sizeof(*b), GFP_KERNEL); b = kmalloc(sizeof(*b), GFP_KERNEL);
if (b) { if (b) {
memset(b, 0, sizeof(*b)); memset(b, 0, sizeof(*b));
INIT_LIST_HEAD(&b->node);
INIT_LIST_HEAD(&b->children); INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices); INIT_LIST_HEAD(&b->devices);
} }
...@@ -477,10 +478,18 @@ pci_scan_device(struct pci_bus *bus, int devfn) ...@@ -477,10 +478,18 @@ pci_scan_device(struct pci_bus *bus, int devfn)
return dev; return dev;
} }
struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn) /**
* pci_scan_slot - scan a PCI slot on a bus for devices.
* @bus: PCI bus to scan
* @devfn: slot number to scan (must have zero function.)
*
* Scan a PCI slot on the specified PCI bus for devices, adding
* discovered devices to the @bus->devices list. New devices
* will have an empty dev->global_list head.
*/
int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
{ {
struct pci_dev *first_dev = NULL; int func, nr = 0;
int func;
for (func = 0; func < 8; func++, devfn++) { for (func = 0; func < 8; func++, devfn++) {
struct pci_dev *dev; struct pci_dev *dev;
...@@ -489,22 +498,19 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn) ...@@ -489,22 +498,19 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
if (!dev) if (!dev)
continue; continue;
if (func == 0) { if (func != 0)
first_dev = dev;
} else {
dev->multifunction = 1; dev->multifunction = 1;
}
/* Fix up broken headers */ /* Fix up broken headers */
pci_fixup_device(PCI_FIXUP_HEADER, dev); pci_fixup_device(PCI_FIXUP_HEADER, dev);
/* /*
* Link the device to both the global PCI device chain and * Add the device to our list of discovered devices
* the per-bus list of devices and add the /proc entry. * and the bus list for fixup functions, etc.
* Note: this also runs the hotplug notifiers (bad!) --rmk
*/ */
device_register(&dev->dev); INIT_LIST_HEAD(&dev->global_list);
pci_insert_device (dev, bus); list_add_tail(&dev->bus_list, &bus->devices);
nr++;
/* /*
* If this is a single function device, * If this is a single function device,
...@@ -513,17 +519,15 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn) ...@@ -513,17 +519,15 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
if (!dev->multifunction) if (!dev->multifunction)
break; break;
} }
return first_dev; return nr;
} }
unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) static unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
{ {
unsigned int devfn, max, pass; unsigned int devfn, pass, max = bus->secondary;
struct list_head *ln;
struct pci_dev *dev; struct pci_dev *dev;
DBG("Scanning bus %02x\n", bus->number); DBG("Scanning bus %02x\n", bus->number);
max = bus->secondary;
/* Go find them, Rover! */ /* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8) for (devfn = 0; devfn < 0x100; devfn += 8)
...@@ -553,6 +557,20 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) ...@@ -553,6 +557,20 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
return max; return max;
} }
unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
{
unsigned int max;
max = pci_scan_child_bus(bus);
/*
* Make the discovered devices available.
*/
pci_bus_add_devices(bus);
return max;
}
int __devinit pci_bus_exists(const struct list_head *list, int nr) int __devinit pci_bus_exists(const struct list_head *list, int nr)
{ {
const struct pci_bus *b; const struct pci_bus *b;
......
...@@ -549,7 +549,8 @@ static inline struct pci_bus *pci_alloc_primary_bus(int bus) ...@@ -549,7 +549,8 @@ static inline struct pci_bus *pci_alloc_primary_bus(int bus)
{ {
return pci_alloc_primary_bus_parented(NULL, bus); return pci_alloc_primary_bus_parented(NULL, bus);
} }
struct pci_dev *pci_scan_slot(struct pci_bus *bus, int devfn); int pci_scan_slot(struct pci_bus *bus, int devfn);
void pci_bus_add_devices(struct pci_bus *bus);
int pci_proc_attach_device(struct pci_dev *dev); int pci_proc_attach_device(struct pci_dev *dev);
int pci_proc_detach_device(struct pci_dev *dev); int pci_proc_detach_device(struct pci_dev *dev);
int pci_proc_attach_bus(struct pci_bus *bus); int pci_proc_attach_bus(struct pci_bus *bus);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment