diff options
author | Dave Jones <davej@redhat.com> | 2006-12-12 17:41:41 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-12-12 17:41:41 -0500 |
commit | c4366889dda8110247be59ca41fddb82951a8c26 (patch) | |
tree | 705c1a996bed8fd48ce94ff33ec9fd00f9b94875 /arch/powerpc/kernel/prom_parse.c | |
parent | db2fb9db5735cc532fd4fc55e94b9a3c3750378e (diff) | |
parent | e1036502e5263851259d147771226161e5ccc85a (diff) |
Merge ../linus
Conflicts:
drivers/cpufreq/cpufreq.c
Diffstat (limited to 'arch/powerpc/kernel/prom_parse.c')
-rw-r--r-- | arch/powerpc/kernel/prom_parse.c | 290 |
1 files changed, 150 insertions, 140 deletions
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 603dff3ad62a..0dfbe1cd28eb 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 | */ |
@@ -153,15 +160,156 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr) | |||
153 | switch((w >> 24) & 0x03) { | 160 | switch((w >> 24) & 0x03) { |
154 | case 0x01: | 161 | case 0x01: |
155 | flags |= IORESOURCE_IO; | 162 | flags |= IORESOURCE_IO; |
163 | break; | ||
156 | case 0x02: /* 32 bits */ | 164 | case 0x02: /* 32 bits */ |
157 | case 0x03: /* 64 bits */ | 165 | case 0x03: /* 64 bits */ |
158 | flags |= IORESOURCE_MEM; | 166 | flags |= IORESOURCE_MEM; |
167 | break; | ||
159 | } | 168 | } |
160 | if (w & 0x40000000) | 169 | if (w & 0x40000000) |
161 | flags |= IORESOURCE_PREFETCH; | 170 | flags |= IORESOURCE_PREFETCH; |
162 | return flags; | 171 | return flags; |
163 | } | 172 | } |
164 | 173 | ||
174 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
175 | unsigned int *flags) | ||
176 | { | ||
177 | const u32 *prop; | ||
178 | unsigned int psize; | ||
179 | struct device_node *parent; | ||
180 | struct of_bus *bus; | ||
181 | int onesize, i, na, ns; | ||
182 | |||
183 | /* Get parent & match bus type */ | ||
184 | parent = of_get_parent(dev); | ||
185 | if (parent == NULL) | ||
186 | return NULL; | ||
187 | bus = of_match_bus(parent); | ||
188 | if (strcmp(bus->name, "pci")) { | ||
189 | of_node_put(parent); | ||
190 | return NULL; | ||
191 | } | ||
192 | bus->count_cells(dev, &na, &ns); | ||
193 | of_node_put(parent); | ||
194 | if (!OF_CHECK_COUNTS(na, ns)) | ||
195 | return NULL; | ||
196 | |||
197 | /* Get "reg" or "assigned-addresses" property */ | ||
198 | prop = get_property(dev, bus->addresses, &psize); | ||
199 | if (prop == NULL) | ||
200 | return NULL; | ||
201 | psize /= 4; | ||
202 | |||
203 | onesize = na + ns; | ||
204 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
205 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
206 | if (size) | ||
207 | *size = of_read_number(prop + na, ns); | ||
208 | if (flags) | ||
209 | *flags = bus->get_flags(prop); | ||
210 | return prop; | ||
211 | } | ||
212 | return NULL; | ||
213 | } | ||
214 | EXPORT_SYMBOL(of_get_pci_address); | ||
215 | |||
216 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
217 | struct resource *r) | ||
218 | { | ||
219 | const u32 *addrp; | ||
220 | u64 size; | ||
221 | unsigned int flags; | ||
222 | |||
223 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
224 | if (addrp == NULL) | ||
225 | return -EINVAL; | ||
226 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
227 | } | ||
228 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
229 | |||
230 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
231 | { | ||
232 | return (((pin - 1) + slot) % 4) + 1; | ||
233 | } | ||
234 | |||
235 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
236 | { | ||
237 | struct device_node *dn, *ppnode; | ||
238 | struct pci_dev *ppdev; | ||
239 | u32 lspec; | ||
240 | u32 laddr[3]; | ||
241 | u8 pin; | ||
242 | int rc; | ||
243 | |||
244 | /* Check if we have a device node, if yes, fallback to standard OF | ||
245 | * parsing | ||
246 | */ | ||
247 | dn = pci_device_to_OF_node(pdev); | ||
248 | if (dn) | ||
249 | return of_irq_map_one(dn, 0, out_irq); | ||
250 | |||
251 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
252 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
253 | * for PCI. If you do different, then don't use that routine. | ||
254 | */ | ||
255 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
256 | if (rc != 0) | ||
257 | return rc; | ||
258 | /* No pin, exit */ | ||
259 | if (pin == 0) | ||
260 | return -ENODEV; | ||
261 | |||
262 | /* Now we walk up the PCI tree */ | ||
263 | lspec = pin; | ||
264 | for (;;) { | ||
265 | /* Get the pci_dev of our parent */ | ||
266 | ppdev = pdev->bus->self; | ||
267 | |||
268 | /* Ouch, it's a host bridge... */ | ||
269 | if (ppdev == NULL) { | ||
270 | #ifdef CONFIG_PPC64 | ||
271 | ppnode = pci_bus_to_OF_node(pdev->bus); | ||
272 | #else | ||
273 | struct pci_controller *host; | ||
274 | host = pci_bus_to_host(pdev->bus); | ||
275 | ppnode = host ? host->arch_data : NULL; | ||
276 | #endif | ||
277 | /* No node for host bridge ? give up */ | ||
278 | if (ppnode == NULL) | ||
279 | return -EINVAL; | ||
280 | } else | ||
281 | /* We found a P2P bridge, check if it has a node */ | ||
282 | ppnode = pci_device_to_OF_node(ppdev); | ||
283 | |||
284 | /* Ok, we have found a parent with a device-node, hand over to | ||
285 | * the OF parsing code. | ||
286 | * We build a unit address from the linux device to be used for | ||
287 | * resolution. Note that we use the linux bus number which may | ||
288 | * not match your firmware bus numbering. | ||
289 | * Fortunately, in most cases, interrupt-map-mask doesn't include | ||
290 | * the bus number as part of the matching. | ||
291 | * You should still be careful about that though if you intend | ||
292 | * to rely on this function (you ship a firmware that doesn't | ||
293 | * create device nodes for all PCI devices). | ||
294 | */ | ||
295 | if (ppnode) | ||
296 | break; | ||
297 | |||
298 | /* We can only get here if we hit a P2P bridge with no node, | ||
299 | * let's do standard swizzling and try again | ||
300 | */ | ||
301 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
302 | pdev = ppdev; | ||
303 | } | ||
304 | |||
305 | laddr[0] = (pdev->bus->number << 16) | ||
306 | | (pdev->devfn << 8); | ||
307 | laddr[1] = laddr[2] = 0; | ||
308 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
309 | } | ||
310 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
311 | #endif /* CONFIG_PCI */ | ||
312 | |||
165 | /* | 313 | /* |
166 | * ISA bus specific translator | 314 | * ISA bus specific translator |
167 | */ | 315 | */ |
@@ -223,6 +371,7 @@ static unsigned int of_bus_isa_get_flags(const u32 *addr) | |||
223 | */ | 371 | */ |
224 | 372 | ||
225 | static struct of_bus of_busses[] = { | 373 | static struct of_bus of_busses[] = { |
374 | #ifdef CONFIG_PCI | ||
226 | /* PCI */ | 375 | /* PCI */ |
227 | { | 376 | { |
228 | .name = "pci", | 377 | .name = "pci", |
@@ -233,6 +382,7 @@ static struct of_bus of_busses[] = { | |||
233 | .translate = of_bus_pci_translate, | 382 | .translate = of_bus_pci_translate, |
234 | .get_flags = of_bus_pci_get_flags, | 383 | .get_flags = of_bus_pci_get_flags, |
235 | }, | 384 | }, |
385 | #endif /* CONFIG_PCI */ | ||
236 | /* ISA */ | 386 | /* ISA */ |
237 | { | 387 | { |
238 | .name = "isa", | 388 | .name = "isa", |
@@ -445,48 +595,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, | |||
445 | } | 595 | } |
446 | EXPORT_SYMBOL(of_get_address); | 596 | EXPORT_SYMBOL(of_get_address); |
447 | 597 | ||
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, | 598 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, |
491 | u64 size, unsigned int flags, | 599 | u64 size, unsigned int flags, |
492 | struct resource *r) | 600 | struct resource *r) |
@@ -529,20 +637,6 @@ int of_address_to_resource(struct device_node *dev, int index, | |||
529 | } | 637 | } |
530 | EXPORT_SYMBOL_GPL(of_address_to_resource); | 638 | EXPORT_SYMBOL_GPL(of_address_to_resource); |
531 | 639 | ||
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, | 640 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, |
547 | unsigned long *busno, unsigned long *phys, unsigned long *size) | 641 | unsigned long *busno, unsigned long *phys, unsigned long *size) |
548 | { | 642 | { |
@@ -898,87 +992,3 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq | |||
898 | return res; | 992 | return res; |
899 | } | 993 | } |
900 | EXPORT_SYMBOL_GPL(of_irq_map_one); | 994 | 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 */ | ||