diff options
-rw-r--r-- | arch/powerpc/kernel/prom_parse.c | 288 |
1 files changed, 148 insertions, 140 deletions
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 603dff3ad62a..346fb7bf9a05 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c | |||
@@ -25,6 +25,12 @@ | |||
25 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ | 25 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ |
26 | (ns) > 0) | 26 | (ns) > 0) |
27 | 27 | ||
28 | static struct of_bus *of_match_bus(struct device_node *np); | ||
29 | static int __of_address_to_resource(struct device_node *dev, | ||
30 | const u32 *addrp, u64 size, unsigned int flags, | ||
31 | struct resource *r); | ||
32 | |||
33 | |||
28 | /* Debug utility */ | 34 | /* Debug utility */ |
29 | #ifdef DEBUG | 35 | #ifdef DEBUG |
30 | static void of_dump_addr(const char *s, const u32 *addr, int na) | 36 | static void of_dump_addr(const char *s, const u32 *addr, int na) |
@@ -101,6 +107,7 @@ static unsigned int of_bus_default_get_flags(const u32 *addr) | |||
101 | } | 107 | } |
102 | 108 | ||
103 | 109 | ||
110 | #ifdef CONFIG_PCI | ||
104 | /* | 111 | /* |
105 | * PCI bus specific translator | 112 | * PCI bus specific translator |
106 | */ | 113 | */ |
@@ -162,6 +169,145 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr) | |||
162 | return flags; | 169 | return flags; |
163 | } | 170 | } |
164 | 171 | ||
172 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
173 | unsigned int *flags) | ||
174 | { | ||
175 | const u32 *prop; | ||
176 | unsigned int psize; | ||
177 | struct device_node *parent; | ||
178 | struct of_bus *bus; | ||
179 | int onesize, i, na, ns; | ||
180 | |||
181 | /* Get parent & match bus type */ | ||
182 | parent = of_get_parent(dev); | ||
183 | if (parent == NULL) | ||
184 | return NULL; | ||
185 | bus = of_match_bus(parent); | ||
186 | if (strcmp(bus->name, "pci")) { | ||
187 | of_node_put(parent); | ||
188 | return NULL; | ||
189 | } | ||
190 | bus->count_cells(dev, &na, &ns); | ||
191 | of_node_put(parent); | ||
192 | if (!OF_CHECK_COUNTS(na, ns)) | ||
193 | return NULL; | ||
194 | |||
195 | /* Get "reg" or "assigned-addresses" property */ | ||
196 | prop = get_property(dev, bus->addresses, &psize); | ||
197 | if (prop == NULL) | ||
198 | return NULL; | ||
199 | psize /= 4; | ||
200 | |||
201 | onesize = na + ns; | ||
202 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
203 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
204 | if (size) | ||
205 | *size = of_read_number(prop + na, ns); | ||
206 | if (flags) | ||
207 | *flags = bus->get_flags(prop); | ||
208 | return prop; | ||
209 | } | ||
210 | return NULL; | ||
211 | } | ||
212 | EXPORT_SYMBOL(of_get_pci_address); | ||
213 | |||
214 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
215 | struct resource *r) | ||
216 | { | ||
217 | const u32 *addrp; | ||
218 | u64 size; | ||
219 | unsigned int flags; | ||
220 | |||
221 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
222 | if (addrp == NULL) | ||
223 | return -EINVAL; | ||
224 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
225 | } | ||
226 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
227 | |||
228 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
229 | { | ||
230 | return (((pin - 1) + slot) % 4) + 1; | ||
231 | } | ||
232 | |||
233 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
234 | { | ||
235 | struct device_node *dn, *ppnode; | ||
236 | struct pci_dev *ppdev; | ||
237 | u32 lspec; | ||
238 | u32 laddr[3]; | ||
239 | u8 pin; | ||
240 | int rc; | ||
241 | |||
242 | /* Check if we have a device node, if yes, fallback to standard OF | ||
243 | * parsing | ||
244 | */ | ||
245 | dn = pci_device_to_OF_node(pdev); | ||
246 | if (dn) | ||
247 | return of_irq_map_one(dn, 0, out_irq); | ||
248 | |||
249 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
250 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
251 | * for PCI. If you do different, then don't use that routine. | ||
252 | */ | ||
253 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
254 | if (rc != 0) | ||
255 | return rc; | ||
256 | /* No pin, exit */ | ||
257 | if (pin == 0) | ||
258 | return -ENODEV; | ||
259 | |||
260 | /* Now we walk up the PCI tree */ | ||
261 | lspec = pin; | ||
262 | for (;;) { | ||
263 | /* Get the pci_dev of our parent */ | ||
264 | ppdev = pdev->bus->self; | ||
265 | |||
266 | /* Ouch, it's a host bridge... */ | ||
267 | if (ppdev == NULL) { | ||
268 | #ifdef CONFIG_PPC64 | ||
269 | ppnode = pci_bus_to_OF_node(pdev->bus); | ||
270 | #else | ||
271 | struct pci_controller *host; | ||
272 | host = pci_bus_to_host(pdev->bus); | ||
273 | ppnode = host ? host->arch_data : NULL; | ||
274 | #endif | ||
275 | /* No node for host bridge ? give up */ | ||
276 | if (ppnode == NULL) | ||
277 | return -EINVAL; | ||
278 | } else | ||
279 | /* We found a P2P bridge, check if it has a node */ | ||
280 | ppnode = pci_device_to_OF_node(ppdev); | ||
281 | |||
282 | /* Ok, we have found a parent with a device-node, hand over to | ||
283 | * the OF parsing code. | ||
284 | * We build a unit address from the linux device to be used for | ||
285 | * resolution. Note that we use the linux bus number which may | ||
286 | * not match your firmware bus numbering. | ||
287 | * Fortunately, in most cases, interrupt-map-mask doesn't include | ||
288 | * the bus number as part of the matching. | ||
289 | * You should still be careful about that though if you intend | ||
290 | * to rely on this function (you ship a firmware that doesn't | ||
291 | * create device nodes for all PCI devices). | ||
292 | */ | ||
293 | if (ppnode) | ||
294 | break; | ||
295 | |||
296 | /* We can only get here if we hit a P2P bridge with no node, | ||
297 | * let's do standard swizzling and try again | ||
298 | */ | ||
299 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
300 | pdev = ppdev; | ||
301 | } | ||
302 | |||
303 | laddr[0] = (pdev->bus->number << 16) | ||
304 | | (pdev->devfn << 8); | ||
305 | laddr[1] = laddr[2] = 0; | ||
306 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
307 | } | ||
308 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
309 | #endif /* CONFIG_PCI */ | ||
310 | |||
165 | /* | 311 | /* |
166 | * ISA bus specific translator | 312 | * ISA bus specific translator |
167 | */ | 313 | */ |
@@ -223,6 +369,7 @@ static unsigned int of_bus_isa_get_flags(const u32 *addr) | |||
223 | */ | 369 | */ |
224 | 370 | ||
225 | static struct of_bus of_busses[] = { | 371 | static struct of_bus of_busses[] = { |
372 | #ifdef CONFIG_PCI | ||
226 | /* PCI */ | 373 | /* PCI */ |
227 | { | 374 | { |
228 | .name = "pci", | 375 | .name = "pci", |
@@ -233,6 +380,7 @@ static struct of_bus of_busses[] = { | |||
233 | .translate = of_bus_pci_translate, | 380 | .translate = of_bus_pci_translate, |
234 | .get_flags = of_bus_pci_get_flags, | 381 | .get_flags = of_bus_pci_get_flags, |
235 | }, | 382 | }, |
383 | #endif /* CONFIG_PCI */ | ||
236 | /* ISA */ | 384 | /* ISA */ |
237 | { | 385 | { |
238 | .name = "isa", | 386 | .name = "isa", |
@@ -445,48 +593,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, | |||
445 | } | 593 | } |
446 | EXPORT_SYMBOL(of_get_address); | 594 | EXPORT_SYMBOL(of_get_address); |
447 | 595 | ||
448 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
449 | unsigned int *flags) | ||
450 | { | ||
451 | const u32 *prop; | ||
452 | unsigned int psize; | ||
453 | struct device_node *parent; | ||
454 | struct of_bus *bus; | ||
455 | int onesize, i, na, ns; | ||
456 | |||
457 | /* Get parent & match bus type */ | ||
458 | parent = of_get_parent(dev); | ||
459 | if (parent == NULL) | ||
460 | return NULL; | ||
461 | bus = of_match_bus(parent); | ||
462 | if (strcmp(bus->name, "pci")) { | ||
463 | of_node_put(parent); | ||
464 | return NULL; | ||
465 | } | ||
466 | bus->count_cells(dev, &na, &ns); | ||
467 | of_node_put(parent); | ||
468 | if (!OF_CHECK_COUNTS(na, ns)) | ||
469 | return NULL; | ||
470 | |||
471 | /* Get "reg" or "assigned-addresses" property */ | ||
472 | prop = get_property(dev, bus->addresses, &psize); | ||
473 | if (prop == NULL) | ||
474 | return NULL; | ||
475 | psize /= 4; | ||
476 | |||
477 | onesize = na + ns; | ||
478 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
479 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
480 | if (size) | ||
481 | *size = of_read_number(prop + na, ns); | ||
482 | if (flags) | ||
483 | *flags = bus->get_flags(prop); | ||
484 | return prop; | ||
485 | } | ||
486 | return NULL; | ||
487 | } | ||
488 | EXPORT_SYMBOL(of_get_pci_address); | ||
489 | |||
490 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, | 596 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, |
491 | u64 size, unsigned int flags, | 597 | u64 size, unsigned int flags, |
492 | struct resource *r) | 598 | struct resource *r) |
@@ -529,20 +635,6 @@ int of_address_to_resource(struct device_node *dev, int index, | |||
529 | } | 635 | } |
530 | EXPORT_SYMBOL_GPL(of_address_to_resource); | 636 | EXPORT_SYMBOL_GPL(of_address_to_resource); |
531 | 637 | ||
532 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
533 | struct resource *r) | ||
534 | { | ||
535 | const u32 *addrp; | ||
536 | u64 size; | ||
537 | unsigned int flags; | ||
538 | |||
539 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
540 | if (addrp == NULL) | ||
541 | return -EINVAL; | ||
542 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
543 | } | ||
544 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
545 | |||
546 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, | 638 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, |
547 | unsigned long *busno, unsigned long *phys, unsigned long *size) | 639 | unsigned long *busno, unsigned long *phys, unsigned long *size) |
548 | { | 640 | { |
@@ -898,87 +990,3 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq | |||
898 | return res; | 990 | return res; |
899 | } | 991 | } |
900 | EXPORT_SYMBOL_GPL(of_irq_map_one); | 992 | EXPORT_SYMBOL_GPL(of_irq_map_one); |
901 | |||
902 | #ifdef CONFIG_PCI | ||
903 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
904 | { | ||
905 | return (((pin - 1) + slot) % 4) + 1; | ||
906 | } | ||
907 | |||
908 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
909 | { | ||
910 | struct device_node *dn, *ppnode; | ||
911 | struct pci_dev *ppdev; | ||
912 | u32 lspec; | ||
913 | u32 laddr[3]; | ||
914 | u8 pin; | ||
915 | int rc; | ||
916 | |||
917 | /* Check if we have a device node, if yes, fallback to standard OF | ||
918 | * parsing | ||
919 | */ | ||
920 | dn = pci_device_to_OF_node(pdev); | ||
921 | if (dn) | ||
922 | return of_irq_map_one(dn, 0, out_irq); | ||
923 | |||
924 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
925 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
926 | * for PCI. If you do different, then don't use that routine. | ||
927 | */ | ||
928 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
929 | if (rc != 0) | ||
930 | return rc; | ||
931 | /* No pin, exit */ | ||
932 | if (pin == 0) | ||
933 | return -ENODEV; | ||
934 | |||
935 | /* Now we walk up the PCI tree */ | ||
936 | lspec = pin; | ||
937 | for (;;) { | ||
938 | /* Get the pci_dev of our parent */ | ||
939 | ppdev = pdev->bus->self; | ||
940 | |||
941 | /* Ouch, it's a host bridge... */ | ||
942 | if (ppdev == NULL) { | ||
943 | #ifdef CONFIG_PPC64 | ||
944 | ppnode = pci_bus_to_OF_node(pdev->bus); | ||
945 | #else | ||
946 | struct pci_controller *host; | ||
947 | host = pci_bus_to_host(pdev->bus); | ||
948 | ppnode = host ? host->arch_data : NULL; | ||
949 | #endif | ||
950 | /* No node for host bridge ? give up */ | ||
951 | if (ppnode == NULL) | ||
952 | return -EINVAL; | ||
953 | } else | ||
954 | /* We found a P2P bridge, check if it has a node */ | ||
955 | ppnode = pci_device_to_OF_node(ppdev); | ||
956 | |||
957 | /* Ok, we have found a parent with a device-node, hand over to | ||
958 | * the OF parsing code. | ||
959 | * We build a unit address from the linux device to be used for | ||
960 | * resolution. Note that we use the linux bus number which may | ||
961 | * not match your firmware bus numbering. | ||
962 | * Fortunately, in most cases, interrupt-map-mask doesn't include | ||
963 | * the bus number as part of the matching. | ||
964 | * You should still be careful about that though if you intend | ||
965 | * to rely on this function (you ship a firmware that doesn't | ||
966 | * create device nodes for all PCI devices). | ||
967 | */ | ||
968 | if (ppnode) | ||
969 | break; | ||
970 | |||
971 | /* We can only get here if we hit a P2P bridge with no node, | ||
972 | * let's do standard swizzling and try again | ||
973 | */ | ||
974 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
975 | pdev = ppdev; | ||
976 | } | ||
977 | |||
978 | laddr[0] = (pdev->bus->number << 16) | ||
979 | | (pdev->devfn << 8); | ||
980 | laddr[1] = laddr[2] = 0; | ||
981 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
982 | } | ||
983 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
984 | #endif /* CONFIG_PCI */ | ||