aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2013-01-09 13:37:16 -0500
committerBjorn Helgaas <bhelgaas@google.com>2013-01-09 13:37:16 -0500
commite84813c0cba2af80f0910484f5ba4931375f57ba (patch)
treec400c9c06465f3c6888bbc91fe759c51056e5463 /arch/x86
parente84d0dedd324379bd784be748314b251334a79b6 (diff)
parentb3e65e1f9185a2eb034defe4270ba178ba70b9a9 (diff)
Merge branch 'pci/yinghai-survey-resources' into next
* pci/yinghai-survey-resources: x86/PCI: Implement pcibios_resource_survey_bus() PCI/ACPI: Reserve firmware-allocated resources for hot-added root buses x86/PCI: Keep resource allocation functions after boot x86/PCI: Don't track firmware-assigned BAR values for hot-added devices x86/PCI: Factor out pcibios_allocate_dev_rom_resource() x86/PCI: Allocate resources on a per-bus basis for hot-adding root buses x86/PCI: Factor out pcibios_allocate_dev_resources() x86/PCI: Factor out pcibios_allocate_bridge_resources()
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/pci/i386.c185
1 files changed, 121 insertions, 64 deletions
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index dd8ca6f7223b..94919e307f8e 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -51,6 +51,7 @@ struct pcibios_fwaddrmap {
51 51
52static LIST_HEAD(pcibios_fwaddrmappings); 52static LIST_HEAD(pcibios_fwaddrmappings);
53static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock); 53static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
54static bool pcibios_fw_addr_done;
54 55
55/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */ 56/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
56static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev) 57static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev)
@@ -72,6 +73,9 @@ pcibios_save_fw_addr(struct pci_dev *dev, int idx, resource_size_t fw_addr)
72 unsigned long flags; 73 unsigned long flags;
73 struct pcibios_fwaddrmap *map; 74 struct pcibios_fwaddrmap *map;
74 75
76 if (pcibios_fw_addr_done)
77 return;
78
75 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags); 79 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
76 map = pcibios_fwaddrmap_lookup(dev); 80 map = pcibios_fwaddrmap_lookup(dev);
77 if (!map) { 81 if (!map) {
@@ -97,6 +101,9 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
97 struct pcibios_fwaddrmap *map; 101 struct pcibios_fwaddrmap *map;
98 resource_size_t fw_addr = 0; 102 resource_size_t fw_addr = 0;
99 103
104 if (pcibios_fw_addr_done)
105 return 0;
106
100 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags); 107 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
101 map = pcibios_fwaddrmap_lookup(dev); 108 map = pcibios_fwaddrmap_lookup(dev);
102 if (map) 109 if (map)
@@ -106,7 +113,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
106 return fw_addr; 113 return fw_addr;
107} 114}
108 115
109static void pcibios_fw_addr_list_del(void) 116static void __init pcibios_fw_addr_list_del(void)
110{ 117{
111 unsigned long flags; 118 unsigned long flags;
112 struct pcibios_fwaddrmap *entry, *next; 119 struct pcibios_fwaddrmap *entry, *next;
@@ -118,6 +125,7 @@ static void pcibios_fw_addr_list_del(void)
118 kfree(entry); 125 kfree(entry);
119 } 126 }
120 spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags); 127 spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
128 pcibios_fw_addr_done = true;
121} 129}
122 130
123static int 131static int
@@ -193,46 +201,46 @@ EXPORT_SYMBOL(pcibios_align_resource);
193 * as well. 201 * as well.
194 */ 202 */
195 203
196static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) 204static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
197{ 205{
198 struct pci_bus *bus;
199 struct pci_dev *dev;
200 int idx; 206 int idx;
201 struct resource *r; 207 struct resource *r;
202 208
203 /* Depth-First Search on bus tree */ 209 for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
204 list_for_each_entry(bus, bus_list, node) { 210 r = &dev->resource[idx];
205 if ((dev = bus->self)) { 211 if (!r->flags)
206 for (idx = PCI_BRIDGE_RESOURCES; 212 continue;
207 idx < PCI_NUM_RESOURCES; idx++) { 213 if (!r->start || pci_claim_resource(dev, idx) < 0) {
208 r = &dev->resource[idx]; 214 /*
209 if (!r->flags) 215 * Something is wrong with the region.
210 continue; 216 * Invalidate the resource to prevent
211 if (!r->start || 217 * child resource allocations in this
212 pci_claim_resource(dev, idx) < 0) { 218 * range.
213 /* 219 */
214 * Something is wrong with the region. 220 r->start = r->end = 0;
215 * Invalidate the resource to prevent 221 r->flags = 0;
216 * child resource allocations in this
217 * range.
218 */
219 r->start = r->end = 0;
220 r->flags = 0;
221 }
222 }
223 } 222 }
224 pcibios_allocate_bus_resources(&bus->children);
225 } 223 }
226} 224}
227 225
226static void pcibios_allocate_bus_resources(struct pci_bus *bus)
227{
228 struct pci_bus *child;
229
230 /* Depth-First Search on bus tree */
231 if (bus->self)
232 pcibios_allocate_bridge_resources(bus->self);
233 list_for_each_entry(child, &bus->children, node)
234 pcibios_allocate_bus_resources(child);
235}
236
228struct pci_check_idx_range { 237struct pci_check_idx_range {
229 int start; 238 int start;
230 int end; 239 int end;
231}; 240};
232 241
233static void __init pcibios_allocate_resources(int pass) 242static void pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
234{ 243{
235 struct pci_dev *dev = NULL;
236 int idx, disabled, i; 244 int idx, disabled, i;
237 u16 command; 245 u16 command;
238 struct resource *r; 246 struct resource *r;
@@ -244,14 +252,13 @@ static void __init pcibios_allocate_resources(int pass)
244#endif 252#endif
245 }; 253 };
246 254
247 for_each_pci_dev(dev) { 255 pci_read_config_word(dev, PCI_COMMAND, &command);
248 pci_read_config_word(dev, PCI_COMMAND, &command); 256 for (i = 0; i < ARRAY_SIZE(idx_range); i++)
249 for (i = 0; i < ARRAY_SIZE(idx_range); i++)
250 for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) { 257 for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
251 r = &dev->resource[idx]; 258 r = &dev->resource[idx];
252 if (r->parent) /* Already allocated */ 259 if (r->parent) /* Already allocated */
253 continue; 260 continue;
254 if (!r->start) /* Address not assigned at all */ 261 if (!r->start) /* Address not assigned at all */
255 continue; 262 continue;
256 if (r->flags & IORESOURCE_IO) 263 if (r->flags & IORESOURCE_IO)
257 disabled = !(command & PCI_COMMAND_IO); 264 disabled = !(command & PCI_COMMAND_IO);
@@ -270,44 +277,74 @@ static void __init pcibios_allocate_resources(int pass)
270 } 277 }
271 } 278 }
272 } 279 }
273 if (!pass) { 280 if (!pass) {
274 r = &dev->resource[PCI_ROM_RESOURCE]; 281 r = &dev->resource[PCI_ROM_RESOURCE];
275 if (r->flags & IORESOURCE_ROM_ENABLE) { 282 if (r->flags & IORESOURCE_ROM_ENABLE) {
276 /* Turn the ROM off, leave the resource region, 283 /* Turn the ROM off, leave the resource region,
277 * but keep it unregistered. */ 284 * but keep it unregistered. */
278 u32 reg; 285 u32 reg;
279 dev_dbg(&dev->dev, "disabling ROM %pR\n", r); 286 dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
280 r->flags &= ~IORESOURCE_ROM_ENABLE; 287 r->flags &= ~IORESOURCE_ROM_ENABLE;
281 pci_read_config_dword(dev, 288 pci_read_config_dword(dev, dev->rom_base_reg, &reg);
282 dev->rom_base_reg, &reg); 289 pci_write_config_dword(dev, dev->rom_base_reg,
283 pci_write_config_dword(dev, dev->rom_base_reg,
284 reg & ~PCI_ROM_ADDRESS_ENABLE); 290 reg & ~PCI_ROM_ADDRESS_ENABLE);
285 }
286 } 291 }
287 } 292 }
288} 293}
289 294
290static int __init pcibios_assign_resources(void) 295static void pcibios_allocate_resources(struct pci_bus *bus, int pass)
296{
297 struct pci_dev *dev;
298 struct pci_bus *child;
299
300 list_for_each_entry(dev, &bus->devices, bus_list) {
301 pcibios_allocate_dev_resources(dev, pass);
302
303 child = dev->subordinate;
304 if (child)
305 pcibios_allocate_resources(child, pass);
306 }
307}
308
309static void pcibios_allocate_dev_rom_resource(struct pci_dev *dev)
291{ 310{
292 struct pci_dev *dev = NULL;
293 struct resource *r; 311 struct resource *r;
294 312
295 if (!(pci_probe & PCI_ASSIGN_ROMS)) { 313 /*
296 /* 314 * Try to use BIOS settings for ROMs, otherwise let
297 * Try to use BIOS settings for ROMs, otherwise let 315 * pci_assign_unassigned_resources() allocate the new
298 * pci_assign_unassigned_resources() allocate the new 316 * addresses.
299 * addresses. 317 */
300 */ 318 r = &dev->resource[PCI_ROM_RESOURCE];
301 for_each_pci_dev(dev) { 319 if (!r->flags || !r->start)
302 r = &dev->resource[PCI_ROM_RESOURCE]; 320 return;
303 if (!r->flags || !r->start) 321
304 continue; 322 if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
305 if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) { 323 r->end -= r->start;
306 r->end -= r->start; 324 r->start = 0;
307 r->start = 0;
308 }
309 }
310 } 325 }
326}
327static void pcibios_allocate_rom_resources(struct pci_bus *bus)
328{
329 struct pci_dev *dev;
330 struct pci_bus *child;
331
332 list_for_each_entry(dev, &bus->devices, bus_list) {
333 pcibios_allocate_dev_rom_resource(dev);
334
335 child = dev->subordinate;
336 if (child)
337 pcibios_allocate_rom_resources(child);
338 }
339}
340
341static int __init pcibios_assign_resources(void)
342{
343 struct pci_bus *bus;
344
345 if (!(pci_probe & PCI_ASSIGN_ROMS))
346 list_for_each_entry(bus, &pci_root_buses, node)
347 pcibios_allocate_rom_resources(bus);
311 348
312 pci_assign_unassigned_resources(); 349 pci_assign_unassigned_resources();
313 pcibios_fw_addr_list_del(); 350 pcibios_fw_addr_list_del();
@@ -315,12 +352,32 @@ static int __init pcibios_assign_resources(void)
315 return 0; 352 return 0;
316} 353}
317 354
355void pcibios_resource_survey_bus(struct pci_bus *bus)
356{
357 dev_printk(KERN_DEBUG, &bus->dev, "Allocating resources\n");
358
359 pcibios_allocate_bus_resources(bus);
360
361 pcibios_allocate_resources(bus, 0);
362 pcibios_allocate_resources(bus, 1);
363
364 if (!(pci_probe & PCI_ASSIGN_ROMS))
365 pcibios_allocate_rom_resources(bus);
366}
367
318void __init pcibios_resource_survey(void) 368void __init pcibios_resource_survey(void)
319{ 369{
370 struct pci_bus *bus;
371
320 DBG("PCI: Allocating resources\n"); 372 DBG("PCI: Allocating resources\n");
321 pcibios_allocate_bus_resources(&pci_root_buses); 373
322 pcibios_allocate_resources(0); 374 list_for_each_entry(bus, &pci_root_buses, node)
323 pcibios_allocate_resources(1); 375 pcibios_allocate_bus_resources(bus);
376
377 list_for_each_entry(bus, &pci_root_buses, node)
378 pcibios_allocate_resources(bus, 0);
379 list_for_each_entry(bus, &pci_root_buses, node)
380 pcibios_allocate_resources(bus, 1);
324 381
325 e820_reserve_resources_late(); 382 e820_reserve_resources_late();
326 /* 383 /*