diff options
Diffstat (limited to 'arch/powerpc/kernel/pci_32.c')
-rw-r--r-- | arch/powerpc/kernel/pci_32.c | 246 |
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; | |||
35 | unsigned long pci_dram_offset = 0; | 35 | unsigned long pci_dram_offset = 0; |
36 | int pcibios_assign_bus_offset = 1; | 36 | int pcibios_assign_bus_offset = 1; |
37 | 37 | ||
38 | /* Default PCI flags is 0 */ | ||
39 | unsigned int ppc_pci_flags; | ||
40 | |||
41 | void pcibios_make_OF_bus_map(void); | 38 | void pcibios_make_OF_bus_map(void); |
42 | 39 | ||
43 | static void fixup_broken_pcnet32(struct pci_dev* dev); | 40 | static void fixup_broken_pcnet32(struct pci_dev* dev); |
44 | static int reparent_resources(struct resource *parent, struct resource *res); | ||
45 | static void fixup_cpc710_pci64(struct pci_dev* dev); | 41 | static void fixup_cpc710_pci64(struct pci_dev* dev); |
46 | #ifdef CONFIG_PPC_OF | 42 | #ifdef CONFIG_PPC_OF |
47 | static u8* pci_to_OF_bus_map; | 43 | static u8* pci_to_OF_bus_map; |
@@ -97,170 +93,6 @@ fixup_cpc710_pci64(struct pci_dev* dev) | |||
97 | } | 93 | } |
98 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64); | 94 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64); |
99 | 95 | ||
100 | static 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 | */ | ||
121 | void 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 | } | ||
137 | EXPORT_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 | |||
172 | static void __init | ||
173 | pcibios_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 | */ | ||
234 | static int __init | ||
235 | reparent_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 | ||
265 | void __init | 97 | void __init |
266 | update_bridge_resource(struct pci_dev *dev, struct resource *res) | 98 | update_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 | ||
321 | static 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 | |||
341 | static void __init | ||
342 | pcibios_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, ®); | ||
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 | ||
652 | static int __init | 427 | static int __init pcibios_init(void) |
653 | pcibios_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) |