diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-12-19 22:55:01 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-12-20 00:18:13 -0500 |
commit | 444532d44aa6bc4d6e3ca74d8ad99c36f3b4d9f0 (patch) | |
tree | 334e0e474cadee057ae98220f4d052b49643ef91 /arch/powerpc/platforms/powermac/pci.c | |
parent | bcf988a19458f08950551f66c110e41fac452b2b (diff) |
[POWERPC] Enable self-view of the HT host bridge on PowerMac G5
This enables the PCI code to see the device that represents the
HT host bridge on the PowerMac G5.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/powermac/pci.c')
-rw-r--r-- | arch/powerpc/platforms/powermac/pci.c | 54 |
1 files changed, 35 insertions, 19 deletions
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 73deace0ec01..6c93e7c0da15 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c | |||
@@ -314,10 +314,13 @@ static int u3_ht_skip_device(struct pci_controller *hose, | |||
314 | 314 | ||
315 | /* We only allow config cycles to devices that are in OF device-tree | 315 | /* We only allow config cycles to devices that are in OF device-tree |
316 | * as we are apparently having some weird things going on with some | 316 | * as we are apparently having some weird things going on with some |
317 | * revs of K2 on recent G5s | 317 | * revs of K2 on recent G5s, except for the host bridge itself, which |
318 | * is missing from the tree but we know we can probe. | ||
318 | */ | 319 | */ |
319 | if (bus->self) | 320 | if (bus->self) |
320 | busdn = pci_device_to_OF_node(bus->self); | 321 | busdn = pci_device_to_OF_node(bus->self); |
322 | else if (devfn == 0) | ||
323 | return 0; | ||
321 | else | 324 | else |
322 | busdn = hose->dn; | 325 | busdn = hose->dn; |
323 | for (dn = busdn->child; dn; dn = dn->sibling) | 326 | for (dn = busdn->child; dn; dn = dn->sibling) |
@@ -344,14 +347,15 @@ static int u3_ht_skip_device(struct pci_controller *hose, | |||
344 | + (((unsigned int)bus) << 16) \ | 347 | + (((unsigned int)bus) << 16) \ |
345 | + 0x01000000UL) | 348 | + 0x01000000UL) |
346 | 349 | ||
347 | static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose, | 350 | static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus, |
348 | u8 bus, u8 devfn, u8 offset) | 351 | u8 devfn, u8 offset, int *swap) |
349 | { | 352 | { |
353 | *swap = 1; | ||
350 | if (bus == hose->first_busno) { | 354 | if (bus == hose->first_busno) { |
351 | /* For now, we don't self probe U3 HT bridge */ | 355 | if (devfn != 0) |
352 | if (PCI_SLOT(devfn) == 0) | 356 | return hose->cfg_data + U3_HT_CFA0(devfn, offset); |
353 | return NULL; | 357 | *swap = 0; |
354 | return hose->cfg_data + U3_HT_CFA0(devfn, offset); | 358 | return ((void __iomem *)hose->cfg_addr) + (offset << 2); |
355 | } else | 359 | } else |
356 | return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); | 360 | return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); |
357 | } | 361 | } |
@@ -360,14 +364,15 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, | |||
360 | int offset, int len, u32 *val) | 364 | int offset, int len, u32 *val) |
361 | { | 365 | { |
362 | struct pci_controller *hose; | 366 | struct pci_controller *hose; |
363 | volatile void __iomem *addr; | 367 | void __iomem *addr; |
368 | int swap; | ||
364 | 369 | ||
365 | hose = pci_bus_to_host(bus); | 370 | hose = pci_bus_to_host(bus); |
366 | if (hose == NULL) | 371 | if (hose == NULL) |
367 | return PCIBIOS_DEVICE_NOT_FOUND; | 372 | return PCIBIOS_DEVICE_NOT_FOUND; |
368 | if (offset >= 0x100) | 373 | if (offset >= 0x100) |
369 | return PCIBIOS_BAD_REGISTER_NUMBER; | 374 | return PCIBIOS_BAD_REGISTER_NUMBER; |
370 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | 375 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap); |
371 | if (!addr) | 376 | if (!addr) |
372 | return PCIBIOS_DEVICE_NOT_FOUND; | 377 | return PCIBIOS_DEVICE_NOT_FOUND; |
373 | 378 | ||
@@ -397,10 +402,10 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, | |||
397 | *val = in_8(addr); | 402 | *val = in_8(addr); |
398 | break; | 403 | break; |
399 | case 2: | 404 | case 2: |
400 | *val = in_le16(addr); | 405 | *val = swap ? in_le16(addr) : in_be16(addr); |
401 | break; | 406 | break; |
402 | default: | 407 | default: |
403 | *val = in_le32(addr); | 408 | *val = swap ? in_le32(addr) : in_be32(addr); |
404 | break; | 409 | break; |
405 | } | 410 | } |
406 | return PCIBIOS_SUCCESSFUL; | 411 | return PCIBIOS_SUCCESSFUL; |
@@ -410,14 +415,15 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, | |||
410 | int offset, int len, u32 val) | 415 | int offset, int len, u32 val) |
411 | { | 416 | { |
412 | struct pci_controller *hose; | 417 | struct pci_controller *hose; |
413 | volatile void __iomem *addr; | 418 | void __iomem *addr; |
419 | int swap; | ||
414 | 420 | ||
415 | hose = pci_bus_to_host(bus); | 421 | hose = pci_bus_to_host(bus); |
416 | if (hose == NULL) | 422 | if (hose == NULL) |
417 | return PCIBIOS_DEVICE_NOT_FOUND; | 423 | return PCIBIOS_DEVICE_NOT_FOUND; |
418 | if (offset >= 0x100) | 424 | if (offset >= 0x100) |
419 | return PCIBIOS_BAD_REGISTER_NUMBER; | 425 | return PCIBIOS_BAD_REGISTER_NUMBER; |
420 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | 426 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap); |
421 | if (!addr) | 427 | if (!addr) |
422 | return PCIBIOS_DEVICE_NOT_FOUND; | 428 | return PCIBIOS_DEVICE_NOT_FOUND; |
423 | 429 | ||
@@ -439,10 +445,10 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, | |||
439 | out_8(addr, val); | 445 | out_8(addr, val); |
440 | break; | 446 | break; |
441 | case 2: | 447 | case 2: |
442 | out_le16(addr, val); | 448 | swap ? out_le16(addr, val) : out_be16(addr, val); |
443 | break; | 449 | break; |
444 | default: | 450 | default: |
445 | out_le32((u32 __iomem *)addr, val); | 451 | swap ? out_le32(addr, val) : out_be32(addr, val); |
446 | break; | 452 | break; |
447 | } | 453 | } |
448 | return PCIBIOS_SUCCESSFUL; | 454 | return PCIBIOS_SUCCESSFUL; |
@@ -780,16 +786,26 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
780 | { | 786 | { |
781 | struct device_node *np = hose->dn; | 787 | struct device_node *np = hose->dn; |
782 | struct pci_controller *other = NULL; | 788 | struct pci_controller *other = NULL; |
789 | struct resource cfg_res, self_res; | ||
783 | int i, cur; | 790 | int i, cur; |
784 | 791 | ||
785 | 792 | ||
786 | hose->ops = &u3_ht_pci_ops; | 793 | hose->ops = &u3_ht_pci_ops; |
787 | 794 | ||
788 | /* We hard code the address because of the different size of | 795 | /* Get base addresses from OF tree |
789 | * the reg address cell, we shall fix that by killing struct | 796 | */ |
790 | * reg_property and using some accessor functions instead | 797 | if (of_address_to_resource(np, 0, &cfg_res) || |
798 | of_address_to_resource(np, 1, &self_res)) { | ||
799 | printk(KERN_ERR "PCI: Failed to get U3/U4 HT resources !\n"); | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | /* Map external cfg space access into cfg_data and self registers | ||
804 | * into cfg_addr | ||
791 | */ | 805 | */ |
792 | hose->cfg_data = ioremap(0xf2000000, 0x02000000); | 806 | hose->cfg_data = ioremap(cfg_res.start, 0x02000000); |
807 | hose->cfg_addr = ioremap(self_res.start, | ||
808 | self_res.end - self_res.start + 1); | ||
793 | 809 | ||
794 | /* | 810 | /* |
795 | * /ht node doesn't expose a "ranges" property, so we "remove" | 811 | * /ht node doesn't expose a "ranges" property, so we "remove" |