diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 111 |
1 files changed, 109 insertions, 2 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 4e25d9c7cc39..fe0a6b7662f7 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -751,6 +751,106 @@ static int power_off_slot(struct acpiphp_slot *slot) | |||
751 | } | 751 | } |
752 | 752 | ||
753 | 753 | ||
754 | |||
755 | /** | ||
756 | * acpiphp_max_busnr - return the highest reserved bus number under | ||
757 | * the given bus. | ||
758 | * @bus: bus to start search with | ||
759 | * | ||
760 | */ | ||
761 | static unsigned char acpiphp_max_busnr(struct pci_bus *bus) | ||
762 | { | ||
763 | struct list_head *tmp; | ||
764 | unsigned char max, n; | ||
765 | |||
766 | /* | ||
767 | * pci_bus_max_busnr will return the highest | ||
768 | * reserved busnr for all these children. | ||
769 | * that is equivalent to the bus->subordinate | ||
770 | * value. We don't want to use the parent's | ||
771 | * bus->subordinate value because it could have | ||
772 | * padding in it. | ||
773 | */ | ||
774 | max = bus->secondary; | ||
775 | |||
776 | list_for_each(tmp, &bus->children) { | ||
777 | n = pci_bus_max_busnr(pci_bus_b(tmp)); | ||
778 | if (n > max) | ||
779 | max = n; | ||
780 | } | ||
781 | return max; | ||
782 | } | ||
783 | |||
784 | |||
785 | |||
786 | /** | ||
787 | * get_func - get a pointer to acpiphp_func given a slot, device | ||
788 | * @slot: slot to search | ||
789 | * @dev: pci_dev struct to match. | ||
790 | * | ||
791 | * This function will increase the reference count of pci_dev, | ||
792 | * so callers should call pci_dev_put when complete. | ||
793 | * | ||
794 | */ | ||
795 | static struct acpiphp_func * | ||
796 | get_func(struct acpiphp_slot *slot, struct pci_dev *dev) | ||
797 | { | ||
798 | struct acpiphp_func *func = NULL; | ||
799 | struct pci_bus *bus = slot->bridge->pci_bus; | ||
800 | struct pci_dev *pdev; | ||
801 | |||
802 | list_for_each_entry(func, &slot->funcs, sibling) { | ||
803 | pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, | ||
804 | func->function)); | ||
805 | if (pdev) { | ||
806 | if (pdev == dev) | ||
807 | break; | ||
808 | pci_dev_put(pdev); | ||
809 | } | ||
810 | } | ||
811 | return func; | ||
812 | } | ||
813 | |||
814 | |||
815 | /** | ||
816 | * acpiphp_bus_add - add a new bus to acpi subsystem | ||
817 | * @func: acpiphp_func of the bridge | ||
818 | * | ||
819 | */ | ||
820 | static int acpiphp_bus_add(struct acpiphp_func *func) | ||
821 | { | ||
822 | acpi_handle phandle; | ||
823 | struct acpi_device *device, *pdevice; | ||
824 | int ret_val; | ||
825 | |||
826 | acpi_get_parent(func->handle, &phandle); | ||
827 | if (acpi_bus_get_device(phandle, &pdevice)) { | ||
828 | dbg("no parent device, assuming NULL\n"); | ||
829 | pdevice = NULL; | ||
830 | } | ||
831 | if (acpi_bus_get_device(func->handle, &device)) { | ||
832 | ret_val = acpi_bus_add(&device, pdevice, func->handle, | ||
833 | ACPI_BUS_TYPE_DEVICE); | ||
834 | if (ret_val) { | ||
835 | dbg("error adding bus, %x\n", | ||
836 | -ret_val); | ||
837 | goto acpiphp_bus_add_out; | ||
838 | } | ||
839 | } | ||
840 | /* | ||
841 | * try to start anyway. We could have failed to add | ||
842 | * simply because this bus had previously been added | ||
843 | * on another add. Don't bother with the return value | ||
844 | * we just keep going. | ||
845 | */ | ||
846 | ret_val = acpi_bus_start(device); | ||
847 | |||
848 | acpiphp_bus_add_out: | ||
849 | return ret_val; | ||
850 | } | ||
851 | |||
852 | |||
853 | |||
754 | /** | 854 | /** |
755 | * enable_device - enable, configure a slot | 855 | * enable_device - enable, configure a slot |
756 | * @slot: slot to be enabled | 856 | * @slot: slot to be enabled |
@@ -788,7 +888,7 @@ static int enable_device(struct acpiphp_slot *slot) | |||
788 | goto err_exit; | 888 | goto err_exit; |
789 | } | 889 | } |
790 | 890 | ||
791 | max = bus->secondary; | 891 | max = acpiphp_max_busnr(bus); |
792 | for (pass = 0; pass < 2; pass++) { | 892 | for (pass = 0; pass < 2; pass++) { |
793 | list_for_each_entry(dev, &bus->devices, bus_list) { | 893 | list_for_each_entry(dev, &bus->devices, bus_list) { |
794 | if (PCI_SLOT(dev->devfn) != slot->device) | 894 | if (PCI_SLOT(dev->devfn) != slot->device) |
@@ -796,8 +896,15 @@ static int enable_device(struct acpiphp_slot *slot) | |||
796 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 896 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
797 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { | 897 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { |
798 | max = pci_scan_bridge(bus, dev, max, pass); | 898 | max = pci_scan_bridge(bus, dev, max, pass); |
799 | if (pass && dev->subordinate) | 899 | if (pass && dev->subordinate) { |
800 | pci_bus_size_bridges(dev->subordinate); | 900 | pci_bus_size_bridges(dev->subordinate); |
901 | func = get_func(slot, dev); | ||
902 | if (func) { | ||
903 | acpiphp_bus_add(func); | ||
904 | /* side effect of get_func */ | ||
905 | pci_dev_put(dev); | ||
906 | } | ||
907 | } | ||
801 | } | 908 | } |
802 | } | 909 | } |
803 | } | 910 | } |