Commit 444532d4 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent bcf988a1
...@@ -314,10 +314,13 @@ static int u3_ht_skip_device(struct pci_controller *hose, ...@@ -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 /* 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 * 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) if (bus->self)
busdn = pci_device_to_OF_node(bus->self); busdn = pci_device_to_OF_node(bus->self);
else if (devfn == 0)
return 0;
else else
busdn = hose->dn; busdn = hose->dn;
for (dn = busdn->child; dn; dn = dn->sibling) for (dn = busdn->child; dn; dn = dn->sibling)
...@@ -344,14 +347,15 @@ static int u3_ht_skip_device(struct pci_controller *hose, ...@@ -344,14 +347,15 @@ static int u3_ht_skip_device(struct pci_controller *hose,
+ (((unsigned int)bus) << 16) \ + (((unsigned int)bus) << 16) \
+ 0x01000000UL) + 0x01000000UL)
static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose, static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus,
u8 bus, u8 devfn, u8 offset) u8 devfn, u8 offset, int *swap)
{ {
*swap = 1;
if (bus == hose->first_busno) { if (bus == hose->first_busno) {
/* For now, we don't self probe U3 HT bridge */ if (devfn != 0)
if (PCI_SLOT(devfn) == 0)
return NULL;
return hose->cfg_data + U3_HT_CFA0(devfn, offset); return hose->cfg_data + U3_HT_CFA0(devfn, offset);
*swap = 0;
return ((void __iomem *)hose->cfg_addr) + (offset << 2);
} else } else
return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); 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, ...@@ -360,14 +364,15 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val) int offset, int len, u32 *val)
{ {
struct pci_controller *hose; struct pci_controller *hose;
volatile void __iomem *addr; void __iomem *addr;
int swap;
hose = pci_bus_to_host(bus); hose = pci_bus_to_host(bus);
if (hose == NULL) if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100) if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER; 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) if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
...@@ -397,10 +402,10 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, ...@@ -397,10 +402,10 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
*val = in_8(addr); *val = in_8(addr);
break; break;
case 2: case 2:
*val = in_le16(addr); *val = swap ? in_le16(addr) : in_be16(addr);
break; break;
default: default:
*val = in_le32(addr); *val = swap ? in_le32(addr) : in_be32(addr);
break; break;
} }
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
...@@ -410,14 +415,15 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -410,14 +415,15 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val) int offset, int len, u32 val)
{ {
struct pci_controller *hose; struct pci_controller *hose;
volatile void __iomem *addr; void __iomem *addr;
int swap;
hose = pci_bus_to_host(bus); hose = pci_bus_to_host(bus);
if (hose == NULL) if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100) if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER; 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) if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
...@@ -439,10 +445,10 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -439,10 +445,10 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
out_8(addr, val); out_8(addr, val);
break; break;
case 2: case 2:
out_le16(addr, val); swap ? out_le16(addr, val) : out_be16(addr, val);
break; break;
default: default:
out_le32((u32 __iomem *)addr, val); swap ? out_le32(addr, val) : out_be32(addr, val);
break; break;
} }
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
...@@ -780,16 +786,26 @@ static void __init setup_u3_ht(struct pci_controller* hose) ...@@ -780,16 +786,26 @@ static void __init setup_u3_ht(struct pci_controller* hose)
{ {
struct device_node *np = hose->dn; struct device_node *np = hose->dn;
struct pci_controller *other = NULL; struct pci_controller *other = NULL;
struct resource cfg_res, self_res;
int i, cur; int i, cur;
hose->ops = &u3_ht_pci_ops; hose->ops = &u3_ht_pci_ops;
/* We hard code the address because of the different size of /* Get base addresses from OF tree
* the reg address cell, we shall fix that by killing struct */
* reg_property and using some accessor functions instead 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" * /ht node doesn't expose a "ranges" property, so we "remove"
......
...@@ -613,9 +613,11 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) ...@@ -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, /* We need to use normal PCI probing for the AGP bus,
* since the device for the AGP bridge isn't in the tree. * 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") || 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_NORMAL;
return PCI_PROBE_DEVTREE; return PCI_PROBE_DEVTREE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment