*/
int
pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
- unsigned long size, unsigned long align, unsigned long min,
- unsigned int type_mask,
- void (*alignf)(void *, struct resource *,
- unsigned long, unsigned long),
- void *alignf_data)
+ resource_size_t size, resource_size_t align,
+ resource_size_t min, unsigned int type_mask,
+ void (*alignf)(void *, struct resource *, resource_size_t,
+ resource_size_t),
+ void *alignf_data)
{
int i, ret = -ENOMEM;
continue;
/* Ok, try it out.. */
- ret = allocate_resource(r, res, size, min, -1, align,
+ ret = allocate_resource(r, res, size,
+ r->start ? : min,
+ -1, align,
alignf, alignf_data);
if (ret == 0)
break;
* This adds a single pci device to the global
* device list and adds sysfs and procfs entries
*/
-void __devinit pci_bus_add_device(struct pci_dev *dev)
+int pci_bus_add_device(struct pci_dev *dev)
{
- device_add(&dev->dev);
-
- spin_lock(&pci_bus_lock);
- list_add_tail(&dev->global_list, &pci_devices);
- spin_unlock(&pci_bus_lock);
+ int retval;
+ retval = device_add(&dev->dev);
+ if (retval)
+ return retval;
+ dev->is_added = 1;
pci_proc_attach_device(dev);
pci_create_sysfs_dev_files(dev);
+ return 0;
}
/**
*
* Call hotplug for each new devices.
*/
-void __devinit pci_bus_add_devices(struct pci_bus *bus)
+void pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
+ struct pci_bus *child_bus;
+ int retval;
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))
+ /* Skip already-added devices */
+ if (dev->is_added)
continue;
- pci_bus_add_device(dev);
+ retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "Error adding device, continuing\n");
}
list_for_each_entry(dev, &bus->devices, bus_list) {
-
- BUG_ON(list_empty(&dev->global_list));
+ BUG_ON(!dev->is_added);
/*
* If there is an unattached subordinate bus, attach
*/
if (dev->subordinate) {
if (list_empty(&dev->subordinate->node)) {
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_add_tail(&dev->subordinate->node,
&dev->bus->children);
- spin_unlock(&pci_bus_lock);
- }
+ up_write(&pci_bus_sem);
+ }
pci_bus_add_devices(dev->subordinate);
- sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
+ /* register the bus with sysfs as the parent is now
+ * properly registered. */
+ child_bus = dev->subordinate;
+ if (child_bus->is_added)
+ continue;
+ child_bus->dev.parent = child_bus->bridge;
+ retval = device_register(&child_bus->dev);
+ if (retval)
+ dev_err(&dev->dev, "Error registering pci_bus,"
+ " continuing...\n");
+ else {
+ child_bus->is_added = 1;
+ retval = device_create_file(&child_bus->dev,
+ &dev_attr_cpuaffinity);
+ }
+ if (retval)
+ dev_err(&dev->dev, "Error creating cpuaffinity"
+ " file, continuing...\n");
}
}
}
void pci_enable_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
+ int retval;
list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->subordinate) {
- pci_enable_device(dev);
+ retval = pci_enable_device(dev);
pci_set_master(dev);
pci_enable_bridges(dev->subordinate);
}
}
}
+/** pci_walk_bus - walk devices on/under bus, calling callback.
+ * @top bus whose devices should be walked
+ * @cb callback to be called for each device found
+ * @userdata arbitrary pointer to be passed to callback.
+ *
+ * Walk the given bus, including any bridged devices
+ * on buses under this bus. Call the provided callback
+ * on each device found.
+ */
+void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
+ void *userdata)
+{
+ struct pci_dev *dev;
+ struct pci_bus *bus;
+ struct list_head *next;
+
+ bus = top;
+ down_read(&pci_bus_sem);
+ next = top->devices.next;
+ for (;;) {
+ if (next == &bus->devices) {
+ /* end of this bus, go up or finish */
+ if (bus == top)
+ break;
+ next = bus->self->bus_list.next;
+ bus = bus->self->bus;
+ continue;
+ }
+ dev = list_entry(next, struct pci_dev, bus_list);
+ if (dev->subordinate) {
+ /* this is a pci-pci bridge, do its devices next */
+ next = dev->subordinate->devices.next;
+ bus = dev->subordinate;
+ } else
+ next = dev->bus_list.next;
+
+ /* Run device routines with the device locked */
+ down(&dev->dev.sem);
+ cb(dev, userdata);
+ up(&dev->dev.sem);
+ }
+ up_read(&pci_bus_sem);
+}
+
EXPORT_SYMBOL(pci_bus_alloc_resource);
EXPORT_SYMBOL_GPL(pci_bus_add_device);
EXPORT_SYMBOL(pci_bus_add_devices);