diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/pci/setup-bus.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 508 |
1 files changed, 401 insertions, 107 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index cb1a027eb552..19b111383f62 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -27,37 +27,91 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include "pci.h" | 28 | #include "pci.h" |
29 | 29 | ||
30 | static void pbus_assign_resources_sorted(const struct pci_bus *bus) | 30 | struct resource_list_x { |
31 | { | 31 | struct resource_list_x *next; |
32 | struct pci_dev *dev; | ||
33 | struct resource *res; | 32 | struct resource *res; |
34 | struct resource_list head, *list, *tmp; | 33 | struct pci_dev *dev; |
35 | int idx; | 34 | resource_size_t start; |
35 | resource_size_t end; | ||
36 | unsigned long flags; | ||
37 | }; | ||
36 | 38 | ||
37 | head.next = NULL; | 39 | static void add_to_failed_list(struct resource_list_x *head, |
38 | list_for_each_entry(dev, &bus->devices, bus_list) { | 40 | struct pci_dev *dev, struct resource *res) |
39 | u16 class = dev->class >> 8; | 41 | { |
42 | struct resource_list_x *list = head; | ||
43 | struct resource_list_x *ln = list->next; | ||
44 | struct resource_list_x *tmp; | ||
40 | 45 | ||
41 | /* Don't touch classless devices or host bridges or ioapics. */ | 46 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |
42 | if (class == PCI_CLASS_NOT_DEFINED || | 47 | if (!tmp) { |
43 | class == PCI_CLASS_BRIDGE_HOST) | 48 | pr_warning("add_to_failed_list: kmalloc() failed!\n"); |
44 | continue; | 49 | return; |
50 | } | ||
45 | 51 | ||
46 | /* Don't touch ioapic devices already enabled by firmware */ | 52 | tmp->next = ln; |
47 | if (class == PCI_CLASS_SYSTEM_PIC) { | 53 | tmp->res = res; |
48 | u16 command; | 54 | tmp->dev = dev; |
49 | pci_read_config_word(dev, PCI_COMMAND, &command); | 55 | tmp->start = res->start; |
50 | if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | 56 | tmp->end = res->end; |
51 | continue; | 57 | tmp->flags = res->flags; |
52 | } | 58 | list->next = tmp; |
59 | } | ||
60 | |||
61 | static void free_failed_list(struct resource_list_x *head) | ||
62 | { | ||
63 | struct resource_list_x *list, *tmp; | ||
53 | 64 | ||
54 | pdev_sort_resources(dev, &head); | 65 | for (list = head->next; list;) { |
66 | tmp = list; | ||
67 | list = list->next; | ||
68 | kfree(tmp); | ||
55 | } | 69 | } |
56 | 70 | ||
57 | for (list = head.next; list;) { | 71 | head->next = NULL; |
72 | } | ||
73 | |||
74 | static void __dev_sort_resources(struct pci_dev *dev, | ||
75 | struct resource_list *head) | ||
76 | { | ||
77 | u16 class = dev->class >> 8; | ||
78 | |||
79 | /* Don't touch classless devices or host bridges or ioapics. */ | ||
80 | if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) | ||
81 | return; | ||
82 | |||
83 | /* Don't touch ioapic devices already enabled by firmware */ | ||
84 | if (class == PCI_CLASS_SYSTEM_PIC) { | ||
85 | u16 command; | ||
86 | pci_read_config_word(dev, PCI_COMMAND, &command); | ||
87 | if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | pdev_sort_resources(dev, head); | ||
92 | } | ||
93 | |||
94 | static void __assign_resources_sorted(struct resource_list *head, | ||
95 | struct resource_list_x *fail_head) | ||
96 | { | ||
97 | struct resource *res; | ||
98 | struct resource_list *list, *tmp; | ||
99 | int idx; | ||
100 | |||
101 | for (list = head->next; list;) { | ||
58 | res = list->res; | 102 | res = list->res; |
59 | idx = res - &list->dev->resource[0]; | 103 | idx = res - &list->dev->resource[0]; |
104 | |||
60 | if (pci_assign_resource(list->dev, idx)) { | 105 | if (pci_assign_resource(list->dev, idx)) { |
106 | if (fail_head && !pci_is_root_bus(list->dev->bus)) { | ||
107 | /* | ||
108 | * if the failed res is for ROM BAR, and it will | ||
109 | * be enabled later, don't add it to the list | ||
110 | */ | ||
111 | if (!((idx == PCI_ROM_RESOURCE) && | ||
112 | (!(res->flags & IORESOURCE_ROM_ENABLE)))) | ||
113 | add_to_failed_list(fail_head, list->dev, res); | ||
114 | } | ||
61 | res->start = 0; | 115 | res->start = 0; |
62 | res->end = 0; | 116 | res->end = 0; |
63 | res->flags = 0; | 117 | res->flags = 0; |
@@ -68,56 +122,77 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus) | |||
68 | } | 122 | } |
69 | } | 123 | } |
70 | 124 | ||
125 | static void pdev_assign_resources_sorted(struct pci_dev *dev, | ||
126 | struct resource_list_x *fail_head) | ||
127 | { | ||
128 | struct resource_list head; | ||
129 | |||
130 | head.next = NULL; | ||
131 | __dev_sort_resources(dev, &head); | ||
132 | __assign_resources_sorted(&head, fail_head); | ||
133 | |||
134 | } | ||
135 | |||
136 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, | ||
137 | struct resource_list_x *fail_head) | ||
138 | { | ||
139 | struct pci_dev *dev; | ||
140 | struct resource_list head; | ||
141 | |||
142 | head.next = NULL; | ||
143 | list_for_each_entry(dev, &bus->devices, bus_list) | ||
144 | __dev_sort_resources(dev, &head); | ||
145 | |||
146 | __assign_resources_sorted(&head, fail_head); | ||
147 | } | ||
148 | |||
71 | void pci_setup_cardbus(struct pci_bus *bus) | 149 | void pci_setup_cardbus(struct pci_bus *bus) |
72 | { | 150 | { |
73 | struct pci_dev *bridge = bus->self; | 151 | struct pci_dev *bridge = bus->self; |
152 | struct resource *res; | ||
74 | struct pci_bus_region region; | 153 | struct pci_bus_region region; |
75 | 154 | ||
76 | dev_info(&bridge->dev, "CardBus bridge, secondary bus %04x:%02x\n", | 155 | dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n", |
77 | pci_domain_nr(bus), bus->number); | 156 | bus->secondary, bus->subordinate); |
78 | 157 | ||
79 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); | 158 | res = bus->resource[0]; |
80 | if (bus->resource[0]->flags & IORESOURCE_IO) { | 159 | pcibios_resource_to_bus(bridge, ®ion, res); |
160 | if (res->flags & IORESOURCE_IO) { | ||
81 | /* | 161 | /* |
82 | * The IO resource is allocated a range twice as large as it | 162 | * The IO resource is allocated a range twice as large as it |
83 | * would normally need. This allows us to set both IO regs. | 163 | * would normally need. This allows us to set both IO regs. |
84 | */ | 164 | */ |
85 | dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", | 165 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
86 | (unsigned long)region.start, | ||
87 | (unsigned long)region.end); | ||
88 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, | 166 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, |
89 | region.start); | 167 | region.start); |
90 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, | 168 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, |
91 | region.end); | 169 | region.end); |
92 | } | 170 | } |
93 | 171 | ||
94 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); | 172 | res = bus->resource[1]; |
95 | if (bus->resource[1]->flags & IORESOURCE_IO) { | 173 | pcibios_resource_to_bus(bridge, ®ion, res); |
96 | dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", | 174 | if (res->flags & IORESOURCE_IO) { |
97 | (unsigned long)region.start, | 175 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
98 | (unsigned long)region.end); | ||
99 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, | 176 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, |
100 | region.start); | 177 | region.start); |
101 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, | 178 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, |
102 | region.end); | 179 | region.end); |
103 | } | 180 | } |
104 | 181 | ||
105 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); | 182 | res = bus->resource[2]; |
106 | if (bus->resource[2]->flags & IORESOURCE_MEM) { | 183 | pcibios_resource_to_bus(bridge, ®ion, res); |
107 | dev_info(&bridge->dev, " PREFETCH window: %#08lx-%#08lx\n", | 184 | if (res->flags & IORESOURCE_MEM) { |
108 | (unsigned long)region.start, | 185 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
109 | (unsigned long)region.end); | ||
110 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, | 186 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, |
111 | region.start); | 187 | region.start); |
112 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, | 188 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, |
113 | region.end); | 189 | region.end); |
114 | } | 190 | } |
115 | 191 | ||
116 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]); | 192 | res = bus->resource[3]; |
117 | if (bus->resource[3]->flags & IORESOURCE_MEM) { | 193 | pcibios_resource_to_bus(bridge, ®ion, res); |
118 | dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", | 194 | if (res->flags & IORESOURCE_MEM) { |
119 | (unsigned long)region.start, | 195 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
120 | (unsigned long)region.end); | ||
121 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, | 196 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, |
122 | region.start); | 197 | region.start); |
123 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, | 198 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, |
@@ -137,37 +212,29 @@ EXPORT_SYMBOL(pci_setup_cardbus); | |||
137 | config space writes, so it's quite possible that an I/O window of | 212 | config space writes, so it's quite possible that an I/O window of |
138 | the bridge will have some undesirable address (e.g. 0) after the | 213 | the bridge will have some undesirable address (e.g. 0) after the |
139 | first write. Ditto 64-bit prefetchable MMIO. */ | 214 | first write. Ditto 64-bit prefetchable MMIO. */ |
140 | static void pci_setup_bridge(struct pci_bus *bus) | 215 | static void pci_setup_bridge_io(struct pci_bus *bus) |
141 | { | 216 | { |
142 | struct pci_dev *bridge = bus->self; | 217 | struct pci_dev *bridge = bus->self; |
218 | struct resource *res; | ||
143 | struct pci_bus_region region; | 219 | struct pci_bus_region region; |
144 | u32 l, bu, lu, io_upper16; | 220 | u32 l, io_upper16; |
145 | int pref_mem64; | ||
146 | |||
147 | if (pci_is_enabled(bridge)) | ||
148 | return; | ||
149 | |||
150 | dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", | ||
151 | pci_domain_nr(bus), bus->number); | ||
152 | 221 | ||
153 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ | 222 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ |
154 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); | 223 | res = bus->resource[0]; |
155 | if (bus->resource[0]->flags & IORESOURCE_IO) { | 224 | pcibios_resource_to_bus(bridge, ®ion, res); |
225 | if (res->flags & IORESOURCE_IO) { | ||
156 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); | 226 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); |
157 | l &= 0xffff0000; | 227 | l &= 0xffff0000; |
158 | l |= (region.start >> 8) & 0x00f0; | 228 | l |= (region.start >> 8) & 0x00f0; |
159 | l |= region.end & 0xf000; | 229 | l |= region.end & 0xf000; |
160 | /* Set up upper 16 bits of I/O base/limit. */ | 230 | /* Set up upper 16 bits of I/O base/limit. */ |
161 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); | 231 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); |
162 | dev_info(&bridge->dev, " IO window: %#04lx-%#04lx\n", | 232 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
163 | (unsigned long)region.start, | 233 | } else { |
164 | (unsigned long)region.end); | ||
165 | } | ||
166 | else { | ||
167 | /* Clear upper 16 bits of I/O base/limit. */ | 234 | /* Clear upper 16 bits of I/O base/limit. */ |
168 | io_upper16 = 0; | 235 | io_upper16 = 0; |
169 | l = 0x00f0; | 236 | l = 0x00f0; |
170 | dev_info(&bridge->dev, " IO window: disabled\n"); | 237 | dev_info(&bridge->dev, " bridge window [io disabled]\n"); |
171 | } | 238 | } |
172 | /* Temporarily disable the I/O range before updating PCI_IO_BASE. */ | 239 | /* Temporarily disable the I/O range before updating PCI_IO_BASE. */ |
173 | pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); | 240 | pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); |
@@ -175,22 +242,35 @@ static void pci_setup_bridge(struct pci_bus *bus) | |||
175 | pci_write_config_dword(bridge, PCI_IO_BASE, l); | 242 | pci_write_config_dword(bridge, PCI_IO_BASE, l); |
176 | /* Update upper 16 bits of I/O base/limit. */ | 243 | /* Update upper 16 bits of I/O base/limit. */ |
177 | pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); | 244 | pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); |
245 | } | ||
178 | 246 | ||
179 | /* Set up the top and bottom of the PCI Memory segment | 247 | static void pci_setup_bridge_mmio(struct pci_bus *bus) |
180 | for this bus. */ | 248 | { |
181 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); | 249 | struct pci_dev *bridge = bus->self; |
182 | if (bus->resource[1]->flags & IORESOURCE_MEM) { | 250 | struct resource *res; |
251 | struct pci_bus_region region; | ||
252 | u32 l; | ||
253 | |||
254 | /* Set up the top and bottom of the PCI Memory segment for this bus. */ | ||
255 | res = bus->resource[1]; | ||
256 | pcibios_resource_to_bus(bridge, ®ion, res); | ||
257 | if (res->flags & IORESOURCE_MEM) { | ||
183 | l = (region.start >> 16) & 0xfff0; | 258 | l = (region.start >> 16) & 0xfff0; |
184 | l |= region.end & 0xfff00000; | 259 | l |= region.end & 0xfff00000; |
185 | dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", | 260 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
186 | (unsigned long)region.start, | 261 | } else { |
187 | (unsigned long)region.end); | ||
188 | } | ||
189 | else { | ||
190 | l = 0x0000fff0; | 262 | l = 0x0000fff0; |
191 | dev_info(&bridge->dev, " MEM window: disabled\n"); | 263 | dev_info(&bridge->dev, " bridge window [mem disabled]\n"); |
192 | } | 264 | } |
193 | pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); | 265 | pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); |
266 | } | ||
267 | |||
268 | static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) | ||
269 | { | ||
270 | struct pci_dev *bridge = bus->self; | ||
271 | struct resource *res; | ||
272 | struct pci_bus_region region; | ||
273 | u32 l, bu, lu; | ||
194 | 274 | ||
195 | /* Clear out the upper 32 bits of PREF limit. | 275 | /* Clear out the upper 32 bits of PREF limit. |
196 | If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily | 276 | If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily |
@@ -198,38 +278,55 @@ static void pci_setup_bridge(struct pci_bus *bus) | |||
198 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); | 278 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); |
199 | 279 | ||
200 | /* Set up PREF base/limit. */ | 280 | /* Set up PREF base/limit. */ |
201 | pref_mem64 = 0; | ||
202 | bu = lu = 0; | 281 | bu = lu = 0; |
203 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); | 282 | res = bus->resource[2]; |
204 | if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { | 283 | pcibios_resource_to_bus(bridge, ®ion, res); |
205 | int width = 8; | 284 | if (res->flags & IORESOURCE_PREFETCH) { |
206 | l = (region.start >> 16) & 0xfff0; | 285 | l = (region.start >> 16) & 0xfff0; |
207 | l |= region.end & 0xfff00000; | 286 | l |= region.end & 0xfff00000; |
208 | if (bus->resource[2]->flags & IORESOURCE_MEM_64) { | 287 | if (res->flags & IORESOURCE_MEM_64) { |
209 | pref_mem64 = 1; | ||
210 | bu = upper_32_bits(region.start); | 288 | bu = upper_32_bits(region.start); |
211 | lu = upper_32_bits(region.end); | 289 | lu = upper_32_bits(region.end); |
212 | width = 16; | ||
213 | } | 290 | } |
214 | dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n", | 291 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
215 | width, (unsigned long long)region.start, | 292 | } else { |
216 | width, (unsigned long long)region.end); | ||
217 | } | ||
218 | else { | ||
219 | l = 0x0000fff0; | 293 | l = 0x0000fff0; |
220 | dev_info(&bridge->dev, " PREFETCH window: disabled\n"); | 294 | dev_info(&bridge->dev, " bridge window [mem pref disabled]\n"); |
221 | } | 295 | } |
222 | pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); | 296 | pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); |
223 | 297 | ||
224 | if (pref_mem64) { | 298 | /* Set the upper 32 bits of PREF base & limit. */ |
225 | /* Set the upper 32 bits of PREF base & limit. */ | 299 | pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); |
226 | pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); | 300 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); |
227 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); | 301 | } |
228 | } | 302 | |
303 | static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) | ||
304 | { | ||
305 | struct pci_dev *bridge = bus->self; | ||
306 | |||
307 | dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", | ||
308 | bus->secondary, bus->subordinate); | ||
309 | |||
310 | if (type & IORESOURCE_IO) | ||
311 | pci_setup_bridge_io(bus); | ||
312 | |||
313 | if (type & IORESOURCE_MEM) | ||
314 | pci_setup_bridge_mmio(bus); | ||
315 | |||
316 | if (type & IORESOURCE_PREFETCH) | ||
317 | pci_setup_bridge_mmio_pref(bus); | ||
229 | 318 | ||
230 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); | 319 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); |
231 | } | 320 | } |
232 | 321 | ||
322 | static void pci_setup_bridge(struct pci_bus *bus) | ||
323 | { | ||
324 | unsigned long type = IORESOURCE_IO | IORESOURCE_MEM | | ||
325 | IORESOURCE_PREFETCH; | ||
326 | |||
327 | __pci_setup_bridge(bus, type); | ||
328 | } | ||
329 | |||
233 | /* Check whether the bridge supports optional I/O and | 330 | /* Check whether the bridge supports optional I/O and |
234 | prefetchable memory ranges. If not, the respective | 331 | prefetchable memory ranges. If not, the respective |
235 | base/limit registers must be read-only and read as 0. */ | 332 | base/limit registers must be read-only and read as 0. */ |
@@ -265,8 +362,11 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) | |||
265 | } | 362 | } |
266 | if (pmem) { | 363 | if (pmem) { |
267 | b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; | 364 | b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; |
268 | if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) | 365 | if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == |
366 | PCI_PREF_RANGE_TYPE_64) { | ||
269 | b_res[2].flags |= IORESOURCE_MEM_64; | 367 | b_res[2].flags |= IORESOURCE_MEM_64; |
368 | b_res[2].flags |= PCI_PREF_RANGE_TYPE_64; | ||
369 | } | ||
270 | } | 370 | } |
271 | 371 | ||
272 | /* double check if bridge does support 64 bit pref */ | 372 | /* double check if bridge does support 64 bit pref */ |
@@ -295,8 +395,7 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon | |||
295 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | 395 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | |
296 | IORESOURCE_PREFETCH; | 396 | IORESOURCE_PREFETCH; |
297 | 397 | ||
298 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | 398 | pci_bus_for_each_resource(bus, r, i) { |
299 | r = bus->resource[i]; | ||
300 | if (r == &ioport_resource || r == &iomem_resource) | 399 | if (r == &ioport_resource || r == &iomem_resource) |
301 | continue; | 400 | continue; |
302 | if (r && (r->flags & type_mask) == type && !r->parent) | 401 | if (r && (r->flags & type_mask) == type && !r->parent) |
@@ -313,7 +412,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) | |||
313 | { | 412 | { |
314 | struct pci_dev *dev; | 413 | struct pci_dev *dev; |
315 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 414 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
316 | unsigned long size = 0, size1 = 0; | 415 | unsigned long size = 0, size1 = 0, old_size; |
317 | 416 | ||
318 | if (!b_res) | 417 | if (!b_res) |
319 | return; | 418 | return; |
@@ -338,13 +437,22 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) | |||
338 | } | 437 | } |
339 | if (size < min_size) | 438 | if (size < min_size) |
340 | size = min_size; | 439 | size = min_size; |
440 | old_size = resource_size(b_res); | ||
441 | if (old_size == 1) | ||
442 | old_size = 0; | ||
341 | /* To be fixed in 2.5: we should have sort of HAVE_ISA | 443 | /* To be fixed in 2.5: we should have sort of HAVE_ISA |
342 | flag in the struct pci_bus. */ | 444 | flag in the struct pci_bus. */ |
343 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) | 445 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) |
344 | size = (size & 0xff) + ((size & ~0xffUL) << 2); | 446 | size = (size & 0xff) + ((size & ~0xffUL) << 2); |
345 | #endif | 447 | #endif |
346 | size = ALIGN(size + size1, 4096); | 448 | size = ALIGN(size + size1, 4096); |
449 | if (size < old_size) | ||
450 | size = old_size; | ||
347 | if (!size) { | 451 | if (!size) { |
452 | if (b_res->start || b_res->end) | ||
453 | dev_info(&bus->self->dev, "disabling bridge window " | ||
454 | "%pR to [bus %02x-%02x] (unused)\n", b_res, | ||
455 | bus->secondary, bus->subordinate); | ||
348 | b_res->flags = 0; | 456 | b_res->flags = 0; |
349 | return; | 457 | return; |
350 | } | 458 | } |
@@ -360,7 +468,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
360 | unsigned long type, resource_size_t min_size) | 468 | unsigned long type, resource_size_t min_size) |
361 | { | 469 | { |
362 | struct pci_dev *dev; | 470 | struct pci_dev *dev; |
363 | resource_size_t min_align, align, size; | 471 | resource_size_t min_align, align, size, old_size; |
364 | resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ | 472 | resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ |
365 | int order, max_order; | 473 | int order, max_order; |
366 | struct resource *b_res = find_free_bus_resource(bus, type); | 474 | struct resource *b_res = find_free_bus_resource(bus, type); |
@@ -390,8 +498,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
390 | align = pci_resource_alignment(dev, r); | 498 | align = pci_resource_alignment(dev, r); |
391 | order = __ffs(align) - 20; | 499 | order = __ffs(align) - 20; |
392 | if (order > 11) { | 500 | if (order > 11) { |
393 | dev_warn(&dev->dev, "BAR %d bad alignment %llx: " | 501 | dev_warn(&dev->dev, "disabling BAR %d: %pR " |
394 | "%pR\n", i, (unsigned long long)align, r); | 502 | "(bad alignment %#llx)\n", i, r, |
503 | (unsigned long long) align); | ||
395 | r->flags = 0; | 504 | r->flags = 0; |
396 | continue; | 505 | continue; |
397 | } | 506 | } |
@@ -409,6 +518,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
409 | } | 518 | } |
410 | if (size < min_size) | 519 | if (size < min_size) |
411 | size = min_size; | 520 | size = min_size; |
521 | old_size = resource_size(b_res); | ||
522 | if (old_size == 1) | ||
523 | old_size = 0; | ||
524 | if (size < old_size) | ||
525 | size = old_size; | ||
412 | 526 | ||
413 | align = 0; | 527 | align = 0; |
414 | min_align = 0; | 528 | min_align = 0; |
@@ -425,6 +539,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
425 | } | 539 | } |
426 | size = ALIGN(size, min_align); | 540 | size = ALIGN(size, min_align); |
427 | if (!size) { | 541 | if (!size) { |
542 | if (b_res->start || b_res->end) | ||
543 | dev_info(&bus->self->dev, "disabling bridge window " | ||
544 | "%pR to [bus %02x-%02x] (unused)\n", b_res, | ||
545 | bus->secondary, bus->subordinate); | ||
428 | b_res->flags = 0; | 546 | b_res->flags = 0; |
429 | return 1; | 547 | return 1; |
430 | } | 548 | } |
@@ -541,23 +659,25 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
541 | } | 659 | } |
542 | EXPORT_SYMBOL(pci_bus_size_bridges); | 660 | EXPORT_SYMBOL(pci_bus_size_bridges); |
543 | 661 | ||
544 | void __ref pci_bus_assign_resources(const struct pci_bus *bus) | 662 | static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, |
663 | struct resource_list_x *fail_head) | ||
545 | { | 664 | { |
546 | struct pci_bus *b; | 665 | struct pci_bus *b; |
547 | struct pci_dev *dev; | 666 | struct pci_dev *dev; |
548 | 667 | ||
549 | pbus_assign_resources_sorted(bus); | 668 | pbus_assign_resources_sorted(bus, fail_head); |
550 | 669 | ||
551 | list_for_each_entry(dev, &bus->devices, bus_list) { | 670 | list_for_each_entry(dev, &bus->devices, bus_list) { |
552 | b = dev->subordinate; | 671 | b = dev->subordinate; |
553 | if (!b) | 672 | if (!b) |
554 | continue; | 673 | continue; |
555 | 674 | ||
556 | pci_bus_assign_resources(b); | 675 | __pci_bus_assign_resources(b, fail_head); |
557 | 676 | ||
558 | switch (dev->class >> 8) { | 677 | switch (dev->class >> 8) { |
559 | case PCI_CLASS_BRIDGE_PCI: | 678 | case PCI_CLASS_BRIDGE_PCI: |
560 | pci_setup_bridge(b); | 679 | if (!pci_is_enabled(dev)) |
680 | pci_setup_bridge(b); | ||
561 | break; | 681 | break; |
562 | 682 | ||
563 | case PCI_CLASS_BRIDGE_CARDBUS: | 683 | case PCI_CLASS_BRIDGE_CARDBUS: |
@@ -571,21 +691,133 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus) | |||
571 | } | 691 | } |
572 | } | 692 | } |
573 | } | 693 | } |
694 | |||
695 | void __ref pci_bus_assign_resources(const struct pci_bus *bus) | ||
696 | { | ||
697 | __pci_bus_assign_resources(bus, NULL); | ||
698 | } | ||
574 | EXPORT_SYMBOL(pci_bus_assign_resources); | 699 | EXPORT_SYMBOL(pci_bus_assign_resources); |
575 | 700 | ||
701 | static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, | ||
702 | struct resource_list_x *fail_head) | ||
703 | { | ||
704 | struct pci_bus *b; | ||
705 | |||
706 | pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head); | ||
707 | |||
708 | b = bridge->subordinate; | ||
709 | if (!b) | ||
710 | return; | ||
711 | |||
712 | __pci_bus_assign_resources(b, fail_head); | ||
713 | |||
714 | switch (bridge->class >> 8) { | ||
715 | case PCI_CLASS_BRIDGE_PCI: | ||
716 | pci_setup_bridge(b); | ||
717 | break; | ||
718 | |||
719 | case PCI_CLASS_BRIDGE_CARDBUS: | ||
720 | pci_setup_cardbus(b); | ||
721 | break; | ||
722 | |||
723 | default: | ||
724 | dev_info(&bridge->dev, "not setting up bridge for bus " | ||
725 | "%04x:%02x\n", pci_domain_nr(b), b->number); | ||
726 | break; | ||
727 | } | ||
728 | } | ||
729 | static void pci_bridge_release_resources(struct pci_bus *bus, | ||
730 | unsigned long type) | ||
731 | { | ||
732 | int idx; | ||
733 | bool changed = false; | ||
734 | struct pci_dev *dev; | ||
735 | struct resource *r; | ||
736 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | ||
737 | IORESOURCE_PREFETCH; | ||
738 | |||
739 | dev = bus->self; | ||
740 | for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END; | ||
741 | idx++) { | ||
742 | r = &dev->resource[idx]; | ||
743 | if ((r->flags & type_mask) != type) | ||
744 | continue; | ||
745 | if (!r->parent) | ||
746 | continue; | ||
747 | /* | ||
748 | * if there are children under that, we should release them | ||
749 | * all | ||
750 | */ | ||
751 | release_child_resources(r); | ||
752 | if (!release_resource(r)) { | ||
753 | dev_printk(KERN_DEBUG, &dev->dev, | ||
754 | "resource %d %pR released\n", idx, r); | ||
755 | /* keep the old size */ | ||
756 | r->end = resource_size(r) - 1; | ||
757 | r->start = 0; | ||
758 | r->flags = 0; | ||
759 | changed = true; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | if (changed) { | ||
764 | /* avoiding touch the one without PREF */ | ||
765 | if (type & IORESOURCE_PREFETCH) | ||
766 | type = IORESOURCE_PREFETCH; | ||
767 | __pci_setup_bridge(bus, type); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | enum release_type { | ||
772 | leaf_only, | ||
773 | whole_subtree, | ||
774 | }; | ||
775 | /* | ||
776 | * try to release pci bridge resources that is from leaf bridge, | ||
777 | * so we can allocate big new one later | ||
778 | */ | ||
779 | static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus, | ||
780 | unsigned long type, | ||
781 | enum release_type rel_type) | ||
782 | { | ||
783 | struct pci_dev *dev; | ||
784 | bool is_leaf_bridge = true; | ||
785 | |||
786 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
787 | struct pci_bus *b = dev->subordinate; | ||
788 | if (!b) | ||
789 | continue; | ||
790 | |||
791 | is_leaf_bridge = false; | ||
792 | |||
793 | if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) | ||
794 | continue; | ||
795 | |||
796 | if (rel_type == whole_subtree) | ||
797 | pci_bus_release_bridge_resources(b, type, | ||
798 | whole_subtree); | ||
799 | } | ||
800 | |||
801 | if (pci_is_root_bus(bus)) | ||
802 | return; | ||
803 | |||
804 | if ((bus->self->class >> 8) != PCI_CLASS_BRIDGE_PCI) | ||
805 | return; | ||
806 | |||
807 | if ((rel_type == whole_subtree) || is_leaf_bridge) | ||
808 | pci_bridge_release_resources(bus, type); | ||
809 | } | ||
810 | |||
576 | static void pci_bus_dump_res(struct pci_bus *bus) | 811 | static void pci_bus_dump_res(struct pci_bus *bus) |
577 | { | 812 | { |
578 | int i; | 813 | struct resource *res; |
814 | int i; | ||
579 | 815 | ||
580 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | 816 | pci_bus_for_each_resource(bus, res, i) { |
581 | struct resource *res = bus->resource[i]; | 817 | if (!res || !res->end || !res->flags) |
582 | if (!res || !res->end) | ||
583 | continue; | 818 | continue; |
584 | 819 | ||
585 | dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i, | 820 | dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res); |
586 | (res->flags & IORESOURCE_IO) ? "io: " : | ||
587 | ((res->flags & IORESOURCE_PREFETCH)? "pref mem":"mem:"), | ||
588 | res); | ||
589 | } | 821 | } |
590 | } | 822 | } |
591 | 823 | ||
@@ -627,3 +859,65 @@ pci_assign_unassigned_resources(void) | |||
627 | pci_bus_dump_resources(bus); | 859 | pci_bus_dump_resources(bus); |
628 | } | 860 | } |
629 | } | 861 | } |
862 | |||
863 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) | ||
864 | { | ||
865 | struct pci_bus *parent = bridge->subordinate; | ||
866 | int tried_times = 0; | ||
867 | struct resource_list_x head, *list; | ||
868 | int retval; | ||
869 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | ||
870 | IORESOURCE_PREFETCH; | ||
871 | |||
872 | head.next = NULL; | ||
873 | |||
874 | again: | ||
875 | pci_bus_size_bridges(parent); | ||
876 | __pci_bridge_assign_resources(bridge, &head); | ||
877 | retval = pci_reenable_device(bridge); | ||
878 | pci_set_master(bridge); | ||
879 | pci_enable_bridges(parent); | ||
880 | |||
881 | tried_times++; | ||
882 | |||
883 | if (!head.next) | ||
884 | return; | ||
885 | |||
886 | if (tried_times >= 2) { | ||
887 | /* still fail, don't need to try more */ | ||
888 | free_failed_list(&head); | ||
889 | return; | ||
890 | } | ||
891 | |||
892 | printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n", | ||
893 | tried_times + 1); | ||
894 | |||
895 | /* | ||
896 | * Try to release leaf bridge's resources that doesn't fit resource of | ||
897 | * child device under that bridge | ||
898 | */ | ||
899 | for (list = head.next; list;) { | ||
900 | struct pci_bus *bus = list->dev->bus; | ||
901 | unsigned long flags = list->flags; | ||
902 | |||
903 | pci_bus_release_bridge_resources(bus, flags & type_mask, | ||
904 | whole_subtree); | ||
905 | list = list->next; | ||
906 | } | ||
907 | /* restore size and flags */ | ||
908 | for (list = head.next; list;) { | ||
909 | struct resource *res = list->res; | ||
910 | |||
911 | res->start = list->start; | ||
912 | res->end = list->end; | ||
913 | res->flags = list->flags; | ||
914 | if (list->dev->subordinate) | ||
915 | res->flags = 0; | ||
916 | |||
917 | list = list->next; | ||
918 | } | ||
919 | free_failed_list(&head); | ||
920 | |||
921 | goto again; | ||
922 | } | ||
923 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); | ||