diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 116 |
1 files changed, 89 insertions, 27 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index f76f6e90f3b9..b19a56b8b17a 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -71,35 +71,34 @@ static void free_failed_list(struct resource_list_x *head) | |||
71 | head->next = NULL; | 71 | head->next = NULL; |
72 | } | 72 | } |
73 | 73 | ||
74 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, | 74 | static void __dev_sort_resources(struct pci_dev *dev, |
75 | struct resource_list_x *fail_head) | 75 | struct resource_list *head) |
76 | { | 76 | { |
77 | struct pci_dev *dev; | 77 | u16 class = dev->class >> 8; |
78 | struct resource *res; | ||
79 | struct resource_list head, *list, *tmp; | ||
80 | int idx; | ||
81 | 78 | ||
82 | head.next = NULL; | 79 | /* Don't touch classless devices or host bridges or ioapics. */ |
83 | list_for_each_entry(dev, &bus->devices, bus_list) { | 80 | if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) |
84 | u16 class = dev->class >> 8; | 81 | return; |
85 | 82 | ||
86 | /* Don't touch classless devices or host bridges or ioapics. */ | 83 | /* Don't touch ioapic devices already enabled by firmware */ |
87 | if (class == PCI_CLASS_NOT_DEFINED || | 84 | if (class == PCI_CLASS_SYSTEM_PIC) { |
88 | class == PCI_CLASS_BRIDGE_HOST) | 85 | u16 command; |
89 | continue; | 86 | pci_read_config_word(dev, PCI_COMMAND, &command); |
87 | if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | ||
88 | return; | ||
89 | } | ||
90 | 90 | ||
91 | /* Don't touch ioapic devices already enabled by firmware */ | 91 | pdev_sort_resources(dev, head); |
92 | if (class == PCI_CLASS_SYSTEM_PIC) { | 92 | } |
93 | u16 command; | ||
94 | pci_read_config_word(dev, PCI_COMMAND, &command); | ||
95 | if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | ||
96 | continue; | ||
97 | } | ||
98 | 93 | ||
99 | pdev_sort_resources(dev, &head); | 94 | static void __assign_resources_sorted(struct resource_list *head, |
100 | } | 95 | struct resource_list_x *fail_head) |
96 | { | ||
97 | struct resource *res; | ||
98 | struct resource_list *list, *tmp; | ||
99 | int idx; | ||
101 | 100 | ||
102 | for (list = head.next; list;) { | 101 | for (list = head->next; list;) { |
103 | res = list->res; | 102 | res = list->res; |
104 | idx = res - &list->dev->resource[0]; | 103 | idx = res - &list->dev->resource[0]; |
105 | if (pci_assign_resource(list->dev, idx)) { | 104 | if (pci_assign_resource(list->dev, idx)) { |
@@ -115,6 +114,30 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus, | |||
115 | } | 114 | } |
116 | } | 115 | } |
117 | 116 | ||
117 | static void pdev_assign_resources_sorted(struct pci_dev *dev, | ||
118 | struct resource_list_x *fail_head) | ||
119 | { | ||
120 | struct resource_list head; | ||
121 | |||
122 | head.next = NULL; | ||
123 | __dev_sort_resources(dev, &head); | ||
124 | __assign_resources_sorted(&head, fail_head); | ||
125 | |||
126 | } | ||
127 | |||
128 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, | ||
129 | struct resource_list_x *fail_head) | ||
130 | { | ||
131 | struct pci_dev *dev; | ||
132 | struct resource_list head; | ||
133 | |||
134 | head.next = NULL; | ||
135 | list_for_each_entry(dev, &bus->devices, bus_list) | ||
136 | __dev_sort_resources(dev, &head); | ||
137 | |||
138 | __assign_resources_sorted(&head, fail_head); | ||
139 | } | ||
140 | |||
118 | void pci_setup_cardbus(struct pci_bus *bus) | 141 | void pci_setup_cardbus(struct pci_bus *bus) |
119 | { | 142 | { |
120 | struct pci_dev *bridge = bus->self; | 143 | struct pci_dev *bridge = bus->self; |
@@ -273,9 +296,6 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) | |||
273 | { | 296 | { |
274 | struct pci_dev *bridge = bus->self; | 297 | struct pci_dev *bridge = bus->self; |
275 | 298 | ||
276 | if (pci_is_enabled(bridge)) | ||
277 | return; | ||
278 | |||
279 | dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", | 299 | dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", |
280 | bus->secondary, bus->subordinate); | 300 | bus->secondary, bus->subordinate); |
281 | 301 | ||
@@ -646,7 +666,8 @@ static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, | |||
646 | 666 | ||
647 | switch (dev->class >> 8) { | 667 | switch (dev->class >> 8) { |
648 | case PCI_CLASS_BRIDGE_PCI: | 668 | case PCI_CLASS_BRIDGE_PCI: |
649 | pci_setup_bridge(b); | 669 | if (!pci_is_enabled(dev)) |
670 | pci_setup_bridge(b); | ||
650 | break; | 671 | break; |
651 | 672 | ||
652 | case PCI_CLASS_BRIDGE_CARDBUS: | 673 | case PCI_CLASS_BRIDGE_CARDBUS: |
@@ -667,6 +688,34 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus) | |||
667 | } | 688 | } |
668 | EXPORT_SYMBOL(pci_bus_assign_resources); | 689 | EXPORT_SYMBOL(pci_bus_assign_resources); |
669 | 690 | ||
691 | static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, | ||
692 | struct resource_list_x *fail_head) | ||
693 | { | ||
694 | struct pci_bus *b; | ||
695 | |||
696 | pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head); | ||
697 | |||
698 | b = bridge->subordinate; | ||
699 | if (!b) | ||
700 | return; | ||
701 | |||
702 | __pci_bus_assign_resources(b, fail_head); | ||
703 | |||
704 | switch (bridge->class >> 8) { | ||
705 | case PCI_CLASS_BRIDGE_PCI: | ||
706 | pci_setup_bridge(b); | ||
707 | break; | ||
708 | |||
709 | case PCI_CLASS_BRIDGE_CARDBUS: | ||
710 | pci_setup_cardbus(b); | ||
711 | break; | ||
712 | |||
713 | default: | ||
714 | dev_info(&bridge->dev, "not setting up bridge for bus " | ||
715 | "%04x:%02x\n", pci_domain_nr(b), b->number); | ||
716 | break; | ||
717 | } | ||
718 | } | ||
670 | static void pci_bridge_release_resources(struct pci_bus *bus, | 719 | static void pci_bridge_release_resources(struct pci_bus *bus, |
671 | unsigned long type) | 720 | unsigned long type) |
672 | { | 721 | { |
@@ -911,3 +960,16 @@ enable_and_dump: | |||
911 | pci_bus_dump_resources(bus); | 960 | pci_bus_dump_resources(bus); |
912 | } | 961 | } |
913 | } | 962 | } |
963 | |||
964 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) | ||
965 | { | ||
966 | struct pci_bus *parent = bridge->subordinate; | ||
967 | int retval; | ||
968 | |||
969 | pci_bus_size_bridges(parent); | ||
970 | __pci_bridge_assign_resources(bridge, NULL); | ||
971 | retval = pci_reenable_device(bridge); | ||
972 | pci_set_master(bridge); | ||
973 | pci_enable_bridges(parent); | ||
974 | } | ||
975 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); | ||