aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/pci_32.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-19 22:54:53 -0500
committerPaul Mackerras <paulus@samba.org>2007-12-20 00:18:09 -0500
commit3fd94c6b1a1158d3e0e505b0a00c3a707b5fcd40 (patch)
treead542ce91f44a5aeacf095d2100a831ab6ebf23e /arch/powerpc/kernel/pci_32.c
parentbf5e2ba28f24f82a64524ef4772c9ebe12e2cd2a (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_32.c')
-rw-r--r--arch/powerpc/kernel/pci_32.c246
1 files changed, 3 insertions, 243 deletions
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 717c554d4658..ce7c20c8191f 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -35,13 +35,9 @@ unsigned long isa_io_base = 0;
35unsigned long pci_dram_offset = 0; 35unsigned long pci_dram_offset = 0;
36int pcibios_assign_bus_offset = 1; 36int pcibios_assign_bus_offset = 1;
37 37
38/* Default PCI flags is 0 */
39unsigned int ppc_pci_flags;
40
41void pcibios_make_OF_bus_map(void); 38void pcibios_make_OF_bus_map(void);
42 39
43static void fixup_broken_pcnet32(struct pci_dev* dev); 40static void fixup_broken_pcnet32(struct pci_dev* dev);
44static int reparent_resources(struct resource *parent, struct resource *res);
45static void fixup_cpc710_pci64(struct pci_dev* dev); 41static void fixup_cpc710_pci64(struct pci_dev* dev);
46#ifdef CONFIG_PPC_OF 42#ifdef CONFIG_PPC_OF
47static u8* pci_to_OF_bus_map; 43static u8* pci_to_OF_bus_map;
@@ -97,170 +93,6 @@ fixup_cpc710_pci64(struct pci_dev* dev)
97} 93}
98DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64); 94DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
99 95
100static int skip_isa_ioresource_align(struct pci_dev *dev)
101{
102 if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) &&
103 !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
104 return 1;
105 return 0;
106}
107
108/*
109 * We need to avoid collisions with `mirrored' VGA ports
110 * and other strange ISA hardware, so we always want the
111 * addresses to be allocated in the 0x000-0x0ff region
112 * modulo 0x400.
113 *
114 * Why? Because some silly external IO cards only decode
115 * the low 10 bits of the IO address. The 0x00-0xff region
116 * is reserved for motherboard devices that decode all 16
117 * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
118 * but we want to try to avoid allocating at 0x2900-0x2bff
119 * which might have be mirrored at 0x0100-0x03ff..
120 */
121void pcibios_align_resource(void *data, struct resource *res,
122 resource_size_t size, resource_size_t align)
123{
124 struct pci_dev *dev = data;
125
126 if (res->flags & IORESOURCE_IO) {
127 resource_size_t start = res->start;
128
129 if (skip_isa_ioresource_align(dev))
130 return;
131 if (start & 0x300) {
132 start = (start + 0x3ff) & ~0x3ff;
133 res->start = start;
134 }
135 }
136}
137EXPORT_SYMBOL(pcibios_align_resource);
138
139/*
140 * Handle resources of PCI devices. If the world were perfect, we could
141 * just allocate all the resource regions and do nothing more. It isn't.
142 * On the other hand, we cannot just re-allocate all devices, as it would
143 * require us to know lots of host bridge internals. So we attempt to
144 * keep as much of the original configuration as possible, but tweak it
145 * when it's found to be wrong.
146 *
147 * Known BIOS problems we have to work around:
148 * - I/O or memory regions not configured
149 * - regions configured, but not enabled in the command register
150 * - bogus I/O addresses above 64K used
151 * - expansion ROMs left enabled (this may sound harmless, but given
152 * the fact the PCI specs explicitly allow address decoders to be
153 * shared between expansion ROMs and other resource regions, it's
154 * at least dangerous)
155 *
156 * Our solution:
157 * (1) Allocate resources for all buses behind PCI-to-PCI bridges.
158 * This gives us fixed barriers on where we can allocate.
159 * (2) Allocate resources for all enabled devices. If there is
160 * a collision, just mark the resource as unallocated. Also
161 * disable expansion ROMs during this step.
162 * (3) Try to allocate resources for disabled devices. If the
163 * resources were assigned correctly, everything goes well,
164 * if they weren't, they won't disturb allocation of other
165 * resources.
166 * (4) Assign new addresses to resources which were either
167 * not configured at all or misconfigured. If explicitly
168 * requested by the user, configure expansion ROM address
169 * as well.
170 */
171
172static void __init
173pcibios_allocate_bus_resources(struct list_head *bus_list)
174{
175 struct pci_bus *bus;
176 int i;
177 struct resource *res, *pr;
178
179 /* Depth-First Search on bus tree */
180 list_for_each_entry(bus, bus_list, node) {
181 for (i = 0; i < 4; ++i) {
182 if ((res = bus->resource[i]) == NULL || !res->flags
183 || res->start > res->end)
184 continue;
185 if (bus->parent == NULL)
186 pr = (res->flags & IORESOURCE_IO)?
187 &ioport_resource : &iomem_resource;
188 else {
189 /* Don't bother with non-root busses when
190 * re-assigning all resources.
191 */
192 if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
193 continue;
194 pr = pci_find_parent_resource(bus->self, res);
195 if (pr == res) {
196 /* this happens when the generic PCI
197 * code (wrongly) decides that this
198 * bridge is transparent -- paulus
199 */
200 continue;
201 }
202 }
203
204 DBG("PCI: dev %s (bus 0x%02x) bridge rsrc %d: %016llx..%016llx "
205 "(f:0x%08lx), parent %p\n",
206 bus->self ? pci_name(bus->self) : "PHB", bus->number, i,
207 (u64)res->start, (u64)res->end, res->flags, pr);
208
209 if (pr && !(pr->flags & IORESOURCE_UNSET)) {
210 if (request_resource(pr, res) == 0)
211 continue;
212 /*
213 * Must be a conflict with an existing entry.
214 * Move that entry (or entries) under the
215 * bridge resource and try again.
216 */
217 if (reparent_resources(pr, res) == 0)
218 continue;
219 }
220 printk(KERN_WARNING
221 "PCI: Cannot allocate resource region "
222 "%d of PCI bridge %d, will remap\n",
223 i, bus->number);
224 res->flags |= IORESOURCE_UNSET;
225 }
226 pcibios_allocate_bus_resources(&bus->children);
227 }
228}
229
230/*
231 * Reparent resource children of pr that conflict with res
232 * under res, and make res replace those children.
233 */
234static int __init
235reparent_resources(struct resource *parent, struct resource *res)
236{
237 struct resource *p, **pp;
238 struct resource **firstpp = NULL;
239
240 for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
241 if (p->end < res->start)
242 continue;
243 if (res->end < p->start)
244 break;
245 if (p->start < res->start || p->end > res->end)
246 return -1; /* not completely contained */
247 if (firstpp == NULL)
248 firstpp = pp;
249 }
250 if (firstpp == NULL)
251 return -1; /* didn't find any conflicting entries? */
252 res->parent = parent;
253 res->child = *firstpp;
254 res->sibling = *pp;
255 *firstpp = res;
256 *pp = NULL;
257 for (p = res->child; p != NULL; p = p->sibling) {
258 p->parent = res;
259 DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
260 p->name, (u64)p->start, (u64)p->end, res->name);
261 }
262 return 0;
263}
264 96
265void __init 97void __init
266update_bridge_resource(struct pci_dev *dev, struct resource *res) 98update_bridge_resource(struct pci_dev *dev, struct resource *res)
@@ -318,63 +150,6 @@ update_bridge_resource(struct pci_dev *dev, struct resource *res)
318 pci_write_config_word(dev, PCI_COMMAND, cmd); 150 pci_write_config_word(dev, PCI_COMMAND, cmd);
319} 151}
320 152
321static inline void alloc_resource(struct pci_dev *dev, int idx)
322{
323 struct resource *pr, *r = &dev->resource[idx];
324
325 DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx (f=%lx)\n",
326 pci_name(dev), idx, (u64)r->start, (u64)r->end, r->flags);
327 pr = pci_find_parent_resource(dev, r);
328 if (!pr || (pr->flags & IORESOURCE_UNSET) || request_resource(pr, r) < 0) {
329 printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
330 " of device %s, will remap\n", idx, pci_name(dev));
331 if (pr)
332 DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n",
333 pr, (u64)pr->start, (u64)pr->end, pr->flags);
334 /* We'll assign a new address later */
335 r->flags |= IORESOURCE_UNSET;
336 r->end -= r->start;
337 r->start = 0;
338 }
339}
340
341static void __init
342pcibios_allocate_resources(int pass)
343{
344 struct pci_dev *dev = NULL;
345 int idx, disabled;
346 u16 command;
347 struct resource *r;
348
349 for_each_pci_dev(dev) {
350 pci_read_config_word(dev, PCI_COMMAND, &command);
351 for (idx = 0; idx < 6; idx++) {
352 r = &dev->resource[idx];
353 if (r->parent) /* Already allocated */
354 continue;
355 if (!r->flags || (r->flags & IORESOURCE_UNSET))
356 continue; /* Not assigned at all */
357 if (r->flags & IORESOURCE_IO)
358 disabled = !(command & PCI_COMMAND_IO);
359 else
360 disabled = !(command & PCI_COMMAND_MEMORY);
361 if (pass == disabled)
362 alloc_resource(dev, idx);
363 }
364 if (pass)
365 continue;
366 r = &dev->resource[PCI_ROM_RESOURCE];
367 if (r->flags & IORESOURCE_ROM_ENABLE) {
368 /* Turn the ROM off, leave the resource region, but keep it unregistered. */
369 u32 reg;
370 DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
371 r->flags &= ~IORESOURCE_ROM_ENABLE;
372 pci_read_config_dword(dev, dev->rom_base_reg, &reg);
373 pci_write_config_dword(dev, dev->rom_base_reg,
374 reg & ~PCI_ROM_ADDRESS_ENABLE);
375 }
376 }
377}
378 153
379#ifdef CONFIG_PPC_OF 154#ifdef CONFIG_PPC_OF
380/* 155/*
@@ -649,8 +424,7 @@ void pcibios_make_OF_bus_map(void)
649} 424}
650#endif /* CONFIG_PPC_OF */ 425#endif /* CONFIG_PPC_OF */
651 426
652static int __init 427static int __init pcibios_init(void)
653pcibios_init(void)
654{ 428{
655 struct pci_controller *hose, *tmp; 429 struct pci_controller *hose, *tmp;
656 struct pci_bus *bus; 430 struct pci_bus *bus;
@@ -683,22 +457,8 @@ pcibios_init(void)
683 if (pci_assign_all_buses && have_of) 457 if (pci_assign_all_buses && have_of)
684 pcibios_make_OF_bus_map(); 458 pcibios_make_OF_bus_map();
685 459
686 /* Call machine dependent fixup */ 460 /* Call common code to handle resource allocation */
687 if (ppc_md.pcibios_fixup) 461 pcibios_resource_survey();
688 ppc_md.pcibios_fixup();
689
690 /* Allocate and assign resources. If we re-assign everything, then
691 * we skip the allocate phase
692 */
693 pcibios_allocate_bus_resources(&pci_root_buses);
694 if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) {
695 pcibios_allocate_resources(0);
696 pcibios_allocate_resources(1);
697 }
698 if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
699 DBG("PCI: Assigning unassigned resouces...\n");
700 pci_assign_unassigned_resources();
701 }
702 462
703 /* Call machine dependent post-init code */ 463 /* Call machine dependent post-init code */
704 if (ppc_md.pcibios_after_init) 464 if (ppc_md.pcibios_after_init)