}
/**
- * add a single device
+ * pci_bus_add_device - add a single device
* @dev: device to add
*
* 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);
-
- down_write(&pci_bus_sem);
- list_add_tail(&dev->global_list, &pci_devices);
- up_write(&pci_bus_sem);
+ 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;
+}
+
+/**
+ * pci_bus_add_child - add a child bus
+ * @bus: bus to add
+ *
+ * This adds sysfs entries for a single bus
+ */
+int pci_bus_add_child(struct pci_bus *bus)
+{
+ int retval;
+
+ if (bus->bridge)
+ bus->dev.parent = bus->bridge;
+
+ retval = device_register(&bus->dev);
+ if (retval)
+ return retval;
+
+ bus->is_added = 1;
+
+ retval = device_create_file(&bus->dev, &dev_attr_cpuaffinity);
+ if (retval)
+ return retval;
+
+ retval = device_create_file(&bus->dev, &dev_attr_cpulistaffinity);
+
+ /* Create legacy_io and legacy_mem files for this bus */
+ pci_create_legacy_files(bus);
+
+ return retval;
}
/**
*
* 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;
+ 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(!dev->is_added);
- BUG_ON(list_empty(&dev->global_list));
-
+ child = dev->subordinate;
/*
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/
- if (dev->subordinate) {
- if (list_empty(&dev->subordinate->node)) {
- down_write(&pci_bus_sem);
- list_add_tail(&dev->subordinate->node,
- &dev->bus->children);
- up_write(&pci_bus_sem);
- }
- pci_bus_add_devices(dev->subordinate);
-
- sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
+ if (!child)
+ continue;
+ if (list_empty(&child->node)) {
+ down_write(&pci_bus_sem);
+ list_add_tail(&child->node, &dev->bus->children);
+ up_write(&pci_bus_sem);
}
+ pci_bus_add_devices(child);
+
+ /*
+ * register the bus with sysfs as the parent is now
+ * properly registered.
+ */
+ if (child->is_added)
+ continue;
+ retval = pci_bus_add_child(child);
+ if (retval)
+ dev_err(&dev->dev, "Error adding bus, continuing\n");
}
}
}
up_read(&pci_bus_sem);
}
-EXPORT_SYMBOL_GPL(pci_walk_bus);
EXPORT_SYMBOL(pci_bus_alloc_resource);
EXPORT_SYMBOL_GPL(pci_bus_add_device);