|
@@ -751,6 +751,106 @@ static int power_off_slot(struct acpiphp_slot *slot)
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
+/**
|
|
|
+ * acpiphp_max_busnr - return the highest reserved bus number under
|
|
|
+ * the given bus.
|
|
|
+ * @bus: bus to start search with
|
|
|
+ *
|
|
|
+ */
|
|
|
+static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
|
|
|
+{
|
|
|
+ struct list_head *tmp;
|
|
|
+ unsigned char max, n;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * pci_bus_max_busnr will return the highest
|
|
|
+ * reserved busnr for all these children.
|
|
|
+ * that is equivalent to the bus->subordinate
|
|
|
+ * value. We don't want to use the parent's
|
|
|
+ * bus->subordinate value because it could have
|
|
|
+ * padding in it.
|
|
|
+ */
|
|
|
+ max = bus->secondary;
|
|
|
+
|
|
|
+ list_for_each(tmp, &bus->children) {
|
|
|
+ n = pci_bus_max_busnr(pci_bus_b(tmp));
|
|
|
+ if (n > max)
|
|
|
+ max = n;
|
|
|
+ }
|
|
|
+ return max;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * get_func - get a pointer to acpiphp_func given a slot, device
|
|
|
+ * @slot: slot to search
|
|
|
+ * @dev: pci_dev struct to match.
|
|
|
+ *
|
|
|
+ * This function will increase the reference count of pci_dev,
|
|
|
+ * so callers should call pci_dev_put when complete.
|
|
|
+ *
|
|
|
+ */
|
|
|
+static struct acpiphp_func *
|
|
|
+get_func(struct acpiphp_slot *slot, struct pci_dev *dev)
|
|
|
+{
|
|
|
+ struct acpiphp_func *func = NULL;
|
|
|
+ struct pci_bus *bus = slot->bridge->pci_bus;
|
|
|
+ struct pci_dev *pdev;
|
|
|
+
|
|
|
+ list_for_each_entry(func, &slot->funcs, sibling) {
|
|
|
+ pdev = pci_get_slot(bus, PCI_DEVFN(slot->device,
|
|
|
+ func->function));
|
|
|
+ if (pdev) {
|
|
|
+ if (pdev == dev)
|
|
|
+ break;
|
|
|
+ pci_dev_put(pdev);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return func;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * acpiphp_bus_add - add a new bus to acpi subsystem
|
|
|
+ * @func: acpiphp_func of the bridge
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int acpiphp_bus_add(struct acpiphp_func *func)
|
|
|
+{
|
|
|
+ acpi_handle phandle;
|
|
|
+ struct acpi_device *device, *pdevice;
|
|
|
+ int ret_val;
|
|
|
+
|
|
|
+ acpi_get_parent(func->handle, &phandle);
|
|
|
+ if (acpi_bus_get_device(phandle, &pdevice)) {
|
|
|
+ dbg("no parent device, assuming NULL\n");
|
|
|
+ pdevice = NULL;
|
|
|
+ }
|
|
|
+ if (acpi_bus_get_device(func->handle, &device)) {
|
|
|
+ ret_val = acpi_bus_add(&device, pdevice, func->handle,
|
|
|
+ ACPI_BUS_TYPE_DEVICE);
|
|
|
+ if (ret_val) {
|
|
|
+ dbg("error adding bus, %x\n",
|
|
|
+ -ret_val);
|
|
|
+ goto acpiphp_bus_add_out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * try to start anyway. We could have failed to add
|
|
|
+ * simply because this bus had previously been added
|
|
|
+ * on another add. Don't bother with the return value
|
|
|
+ * we just keep going.
|
|
|
+ */
|
|
|
+ ret_val = acpi_bus_start(device);
|
|
|
+
|
|
|
+acpiphp_bus_add_out:
|
|
|
+ return ret_val;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* enable_device - enable, configure a slot
|
|
|
* @slot: slot to be enabled
|
|
@@ -788,7 +888,7 @@ static int enable_device(struct acpiphp_slot *slot)
|
|
|
goto err_exit;
|
|
|
}
|
|
|
|
|
|
- max = bus->secondary;
|
|
|
+ max = acpiphp_max_busnr(bus);
|
|
|
for (pass = 0; pass < 2; pass++) {
|
|
|
list_for_each_entry(dev, &bus->devices, bus_list) {
|
|
|
if (PCI_SLOT(dev->devfn) != slot->device)
|
|
@@ -796,8 +896,15 @@ static int enable_device(struct acpiphp_slot *slot)
|
|
|
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
|
|
|
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
|
|
|
max = pci_scan_bridge(bus, dev, max, pass);
|
|
|
- if (pass && dev->subordinate)
|
|
|
+ if (pass && dev->subordinate) {
|
|
|
pci_bus_size_bridges(dev->subordinate);
|
|
|
+ func = get_func(slot, dev);
|
|
|
+ if (func) {
|
|
|
+ acpiphp_bus_add(func);
|
|
|
+ /* side effect of get_func */
|
|
|
+ pci_dev_put(dev);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|