diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-12-20 14:55:01 +1100 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-12-20 16:18:13 +1100 |
commit | 444532d44aa6bc4d6e3ca74d8ad99c36f3b4d9f0 (patch) | |
tree | 334e0e474cadee057ae98220f4d052b49643ef91 /arch/powerpc | |
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')
-rw-r--r-- | arch/powerpc/platforms/powermac/pci.c | 54 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 4 |
2 files changed, 38 insertions, 20 deletions
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 73deace0ec0..6c93e7c0da1 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, /* We only allow config cycles to devices that are in OF device-tree * as we are apparently having some weird things going on with some - * revs of K2 on recent G5s + * revs of K2 on recent G5s, except for the host bridge itself, which + * is missing from the tree but we know we can probe. */ if (bus->self) busdn = pci_device_to_OF_node(bus->self); + else if (devfn == 0) + return 0; else busdn = hose->dn; for (dn = busdn->child; dn; dn = dn->sibling) @@ -344,14 +347,15 @@ static int u3_ht_skip_device(struct pci_controller *hose, + (((unsigned int)bus) << 16) \ + 0x01000000UL) -static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose, - u8 bus, u8 devfn, u8 offset) +static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus, + u8 devfn, u8 offset, int *swap) { + *swap = 1; if (bus == hose->first_busno) { - /* For now, we don't self probe U3 HT bridge */ - if (PCI_SLOT(devfn) == 0) - return NULL; - return hose->cfg_data + U3_HT_CFA0(devfn, offset); + if (devfn != 0) + return hose->cfg_data + U3_HT_CFA0(devfn, offset); + *swap = 0; + return ((void __iomem *)hose->cfg_addr) + (offset << 2); } else return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); } @@ -360,14 +364,15 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { struct pci_controller *hose; - volatile void __iomem *addr; + void __iomem *addr; + int swap; hose = pci_bus_to_host(bus); if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; if (offset >= 0x100) return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -397,10 +402,10 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, *val = in_8(addr); break; case 2: - *val = in_le16(addr); + *val = swap ? in_le16(addr) : in_be16(addr); break; default: - *val = in_le32(addr); + *val = swap ? in_le32(addr) : in_be32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -410,14 +415,15 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { struct pci_controller *hose; - volatile void __iomem *addr; + void __iomem *addr; + int swap; hose = pci_bus_to_host(bus); if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; if (offset >= 0x100) return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -439,10 +445,10 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, out_8(addr, val); break; case 2: - out_le16(addr, val); + swap ? out_le16(addr, val) : out_be16(addr, val); break; default: - out_le32((u32 __iomem *)addr, val); + swap ? out_le32(addr, val) : out_be32(addr, val); break; } return PCIBIOS_SUCCESSFUL; @@ -780,16 +786,26 @@ static void __init setup_u3_ht(struct pci_controller* hose) { struct device_node *np = hose->dn; struct pci_controller *other = NULL; + struct resource cfg_res, self_res; int i, cur; hose->ops = &u3_ht_pci_ops; - /* We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead + /* Get base addresses from OF tree + */ + if (of_address_to_resource(np, 0, &cfg_res) || + of_address_to_resource(np, 1, &self_res)) { + printk(KERN_ERR "PCI: Failed to get U3/U4 HT resources !\n"); + return; + } + + /* Map external cfg space access into cfg_data and self registers + * into cfg_addr */ - hose->cfg_data = ioremap(0xf2000000, 0x02000000); + hose->cfg_data = ioremap(cfg_res.start, 0x02000000); + hose->cfg_addr = ioremap(self_res.start, + self_res.end - self_res.start + 1); /* * /ht node doesn't expose a "ranges" property, so we "remove" diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 3acb59d5cdf..869ca45cf91 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -613,9 +613,11 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) /* We need to use normal PCI probing for the AGP bus, * since the device for the AGP bridge isn't in the tree. + * Same for the PCIe host on U4 and the HT host bridge. */ if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") || - of_device_is_compatible(node, "u4-pcie"))) + of_device_is_compatible(node, "u4-pcie") || + of_device_is_compatible(node, "u3-ht"))) return PCI_PROBE_NORMAL; return PCI_PROBE_DEVTREE; } |