diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-12-19 22:54:53 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-12-20 00:18:09 -0500 |
commit | 3fd94c6b1a1158d3e0e505b0a00c3a707b5fcd40 (patch) | |
tree | ad542ce91f44a5aeacf095d2100a831ab6ebf23e /arch/powerpc/kernel/pci_64.c | |
parent | bf5e2ba28f24f82a64524ef4772c9ebe12e2cd2a (diff) |
[POWERPC] Merge PCI resource allocation & assignment
The 32 bits PCI code now uses the generic code for assigning unassigned
resources and an algorithm similar to x86 for claiming existing ones.
This works far better than the 64 bits code which basically can only
claim existing ones (pci_probe_only=1) or would fall apart completely.
This merges them so that the new 32 bits implementation is used for both.
64 bits now gets the new PCI flags for controlling the behaviour, though
the old pci_probe_only global is still there for now to be cleared if you
want to.
I kept a pcibios_claim_one_bus() function mostly based on the old 64
bits code for use by the DLPAR hotplug. This will have to be cleaned
up, thought I hope it will work in the meantime.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/pci_64.c')
-rw-r--r-- | arch/powerpc/kernel/pci_64.c | 118 |
1 files changed, 12 insertions, 106 deletions
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index b9619b9e5e02..794359d8686b 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -91,85 +91,6 @@ static void fixup_broken_pcnet32(struct pci_dev* dev) | |||
91 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); | 91 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); |
92 | 92 | ||
93 | 93 | ||
94 | /* | ||
95 | * We need to avoid collisions with `mirrored' VGA ports | ||
96 | * and other strange ISA hardware, so we always want the | ||
97 | * addresses to be allocated in the 0x000-0x0ff region | ||
98 | * modulo 0x400. | ||
99 | * | ||
100 | * Why? Because some silly external IO cards only decode | ||
101 | * the low 10 bits of the IO address. The 0x00-0xff region | ||
102 | * is reserved for motherboard devices that decode all 16 | ||
103 | * bits, so it's ok to allocate at, say, 0x2800-0x28ff, | ||
104 | * but we want to try to avoid allocating at 0x2900-0x2bff | ||
105 | * which might have be mirrored at 0x0100-0x03ff.. | ||
106 | */ | ||
107 | void pcibios_align_resource(void *data, struct resource *res, | ||
108 | resource_size_t size, resource_size_t align) | ||
109 | { | ||
110 | struct pci_dev *dev = data; | ||
111 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
112 | resource_size_t start = res->start; | ||
113 | unsigned long alignto; | ||
114 | |||
115 | if (res->flags & IORESOURCE_IO) { | ||
116 | unsigned long offset = (unsigned long)hose->io_base_virt - | ||
117 | _IO_BASE; | ||
118 | /* Make sure we start at our min on all hoses */ | ||
119 | if (start - offset < PCIBIOS_MIN_IO) | ||
120 | start = PCIBIOS_MIN_IO + offset; | ||
121 | |||
122 | /* | ||
123 | * Put everything into 0x00-0xff region modulo 0x400 | ||
124 | */ | ||
125 | if (start & 0x300) | ||
126 | start = (start + 0x3ff) & ~0x3ff; | ||
127 | |||
128 | } else if (res->flags & IORESOURCE_MEM) { | ||
129 | /* Make sure we start at our min on all hoses */ | ||
130 | if (start - hose->pci_mem_offset < PCIBIOS_MIN_MEM) | ||
131 | start = PCIBIOS_MIN_MEM + hose->pci_mem_offset; | ||
132 | |||
133 | /* Align to multiple of size of minimum base. */ | ||
134 | alignto = max(0x1000UL, align); | ||
135 | start = ALIGN(start, alignto); | ||
136 | } | ||
137 | |||
138 | res->start = start; | ||
139 | } | ||
140 | |||
141 | void __devinit pcibios_claim_one_bus(struct pci_bus *b) | ||
142 | { | ||
143 | struct pci_dev *dev; | ||
144 | struct pci_bus *child_bus; | ||
145 | |||
146 | list_for_each_entry(dev, &b->devices, bus_list) { | ||
147 | int i; | ||
148 | |||
149 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | ||
150 | struct resource *r = &dev->resource[i]; | ||
151 | |||
152 | if (r->parent || !r->start || !r->flags) | ||
153 | continue; | ||
154 | pci_claim_resource(dev, i); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | list_for_each_entry(child_bus, &b->children, node) | ||
159 | pcibios_claim_one_bus(child_bus); | ||
160 | } | ||
161 | #ifdef CONFIG_HOTPLUG | ||
162 | EXPORT_SYMBOL_GPL(pcibios_claim_one_bus); | ||
163 | #endif | ||
164 | |||
165 | static void __init pcibios_claim_of_setup(void) | ||
166 | { | ||
167 | struct pci_bus *b; | ||
168 | |||
169 | list_for_each_entry(b, &pci_root_buses, node) | ||
170 | pcibios_claim_one_bus(b); | ||
171 | } | ||
172 | |||
173 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) | 94 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) |
174 | { | 95 | { |
175 | const u32 *prop; | 96 | const u32 *prop; |
@@ -440,6 +361,7 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
440 | 361 | ||
441 | DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); | 362 | DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); |
442 | 363 | ||
364 | /* Create an empty bus for the toplevel */ | ||
443 | bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node); | 365 | bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node); |
444 | if (bus == NULL) { | 366 | if (bus == NULL) { |
445 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", | 367 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", |
@@ -449,26 +371,16 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
449 | bus->secondary = hose->first_busno; | 371 | bus->secondary = hose->first_busno; |
450 | hose->bus = bus; | 372 | hose->bus = bus; |
451 | 373 | ||
374 | /* Get some IO space for the new PHB */ | ||
452 | pcibios_map_io_space(bus); | 375 | pcibios_map_io_space(bus); |
453 | 376 | ||
377 | /* Wire up PHB bus resources */ | ||
454 | bus->resource[0] = res = &hose->io_resource; | 378 | bus->resource[0] = res = &hose->io_resource; |
455 | if (res->flags && request_resource(&ioport_resource, res)) { | 379 | for (i = 0; i < 3; ++i) |
456 | printk(KERN_ERR "Failed to request PCI IO region " | 380 | bus->resource[i+1] = &hose->mem_resources[i]; |
457 | "on PCI domain %04x\n", hose->global_number); | ||
458 | DBG("res->start = 0x%016lx, res->end = 0x%016lx\n", | ||
459 | res->start, res->end); | ||
460 | } | ||
461 | |||
462 | for (i = 0; i < 3; ++i) { | ||
463 | res = &hose->mem_resources[i]; | ||
464 | bus->resource[i+1] = res; | ||
465 | if (res->flags && request_resource(&iomem_resource, res)) | ||
466 | printk(KERN_ERR "Failed to request PCI memory region " | ||
467 | "on PCI domain %04x\n", hose->global_number); | ||
468 | } | ||
469 | 381 | ||
382 | /* Get probe mode and perform scan */ | ||
470 | mode = PCI_PROBE_NORMAL; | 383 | mode = PCI_PROBE_NORMAL; |
471 | |||
472 | if (node && ppc_md.pci_probe_mode) | 384 | if (node && ppc_md.pci_probe_mode) |
473 | mode = ppc_md.pci_probe_mode(bus); | 385 | mode = ppc_md.pci_probe_mode(bus); |
474 | DBG(" probe mode: %d\n", mode); | 386 | DBG(" probe mode: %d\n", mode); |
@@ -485,12 +397,15 @@ static int __init pcibios_init(void) | |||
485 | { | 397 | { |
486 | struct pci_controller *hose, *tmp; | 398 | struct pci_controller *hose, *tmp; |
487 | 399 | ||
400 | printk(KERN_INFO "PCI: Probing PCI hardware\n"); | ||
401 | |||
488 | /* For now, override phys_mem_access_prot. If we need it, | 402 | /* For now, override phys_mem_access_prot. If we need it, |
489 | * later, we may move that initialization to each ppc_md | 403 | * later, we may move that initialization to each ppc_md |
490 | */ | 404 | */ |
491 | ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; | 405 | ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; |
492 | 406 | ||
493 | printk(KERN_DEBUG "PCI: Probing PCI hardware\n"); | 407 | if (pci_probe_only) |
408 | ppc_pci_flags |= PPC_PCI_PROBE_ONLY; | ||
494 | 409 | ||
495 | /* Scan all of the recorded PCI controllers. */ | 410 | /* Scan all of the recorded PCI controllers. */ |
496 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | 411 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { |
@@ -498,17 +413,8 @@ static int __init pcibios_init(void) | |||
498 | pci_bus_add_devices(hose->bus); | 413 | pci_bus_add_devices(hose->bus); |
499 | } | 414 | } |
500 | 415 | ||
501 | if (pci_probe_only) | 416 | /* Call common code to handle resource allocation */ |
502 | pcibios_claim_of_setup(); | 417 | pcibios_resource_survey(); |
503 | else | ||
504 | /* FIXME: `else' will be removed when | ||
505 | pci_assign_unassigned_resources() is able to work | ||
506 | correctly with [partially] allocated PCI tree. */ | ||
507 | pci_assign_unassigned_resources(); | ||
508 | |||
509 | /* Call machine dependent final fixup */ | ||
510 | if (ppc_md.pcibios_fixup) | ||
511 | ppc_md.pcibios_fixup(); | ||
512 | 418 | ||
513 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); | 419 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); |
514 | 420 | ||