diff options
Diffstat (limited to 'arch/powerpc/platforms/powermac/pci.c')
| -rw-r--r-- | arch/powerpc/platforms/powermac/pci.c | 127 |
1 files changed, 88 insertions, 39 deletions
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 1c58db9d42c..cf7009b8c7b 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/bootmem.h> #include <linux/irq.h> +#include <linux/of_pci.h> #include <asm/sections.h> #include <asm/io.h> @@ -235,7 +236,7 @@ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) if (offset >= 0x100) return PCIBIOS_BAD_REGISTER_NUMBER; - np = pci_busdev_to_OF_node(bus, devfn); + np = of_pci_find_child_device(bus->dev.of_node, devfn); if (np == NULL) return PCIBIOS_DEVICE_NOT_FOUND; @@ -299,10 +300,10 @@ static void __init setup_chaos(struct pci_controller *hose, * This function deals with some "special cases" devices. * * 0 -> No special case - * 1 -> Skip the device but act as if the access was successfull + * 1 -> Skip the device but act as if the access was successful * (return 0xff's on reads, eventually, cache config space * accesses in a later version) - * -1 -> Hide the device (unsuccessful acess) + * -1 -> Hide the device (unsuccessful access) */ static int u3_ht_skip_device(struct pci_controller *hose, struct pci_bus *bus, unsigned int devfn) @@ -560,6 +561,20 @@ static struct pci_ops u4_pcie_pci_ops = .write = u4_pcie_write_config, }; +static void pmac_pci_fixup_u4_of_node(struct pci_dev *dev) +{ + /* Apple's device-tree "hides" the root complex virtual P2P bridge + * on U4. However, Linux sees it, causing the PCI <-> OF matching + * code to fail to properly match devices below it. This works around + * it by setting the node of the bridge to point to the PHB node, + * which is not entirely correct but fixes the matching code and + * doesn't break anything else. It's also the simplest possible fix. + */ + if (dev->dev.of_node == NULL) + dev->dev.of_node = pcibios_get_phb_of_node(dev->bus); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, 0x5b, pmac_pci_fixup_u4_of_node); + #endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC32 @@ -661,6 +676,7 @@ static void __init init_second_ohare(void) pci_find_hose_for_OF_device(np); if (!hose) { printk(KERN_ERR "Can't find PCI hose for OHare2 !\n"); + of_node_put(np); return; } early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd); @@ -669,6 +685,7 @@ static void __init init_second_ohare(void) early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd); } has_second_ohare = 1; + of_node_put(np); } /* @@ -729,7 +746,7 @@ static void __init setup_bandit(struct pci_controller *hose, static int __init setup_uninorth(struct pci_controller *hose, struct resource *addr) { - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + pci_add_flags(PCI_REASSIGN_ALL_BUS); has_uninorth = 1; hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000); @@ -807,6 +824,7 @@ static void __init parse_region_decode(struct pci_controller *hose, hose->mem_resources[cur].name = hose->dn->full_name; hose->mem_resources[cur].start = base; hose->mem_resources[cur].end = end; + hose->mem_offset[cur] = 0; DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end); } else { DBG(" : -0x%08lx\n", end); @@ -836,8 +854,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) * into cfg_addr */ hose->cfg_data = ioremap(cfg_res.start, 0x02000000); - hose->cfg_addr = ioremap(self_res.start, - self_res.end - self_res.start + 1); + hose->cfg_addr = ioremap(self_res.start, resource_size(&self_res)); /* * /ht node doesn't expose a "ranges" property, we read the register @@ -850,7 +867,6 @@ static void __init setup_u3_ht(struct pci_controller* hose) hose->io_resource.start = 0; hose->io_resource.end = 0x003fffff; hose->io_resource.flags = IORESOURCE_IO; - hose->pci_mem_offset = 0; hose->first_busno = 0; hose->last_busno = 0xef; @@ -972,7 +988,7 @@ static int __init pmac_add_bridge(struct device_node *dev) return 0; } -void __devinit pmac_pci_irq_fixup(struct pci_dev *dev) +void pmac_pci_irq_fixup(struct pci_dev *dev) { #ifdef CONFIG_PPC32 /* Fixup interrupt for the modem/ethernet combo controller. @@ -986,7 +1002,7 @@ void __devinit pmac_pci_irq_fixup(struct pci_dev *dev) dev->vendor == PCI_VENDOR_ID_DEC && dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS) { dev->irq = irq_create_mapping(NULL, 60); - set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); } #endif /* CONFIG_PPC32 */ } @@ -996,7 +1012,7 @@ void __init pmac_pci_init(void) struct device_node *np, *root; struct device_node *ht = NULL; - ppc_pci_flags = PPC_PCI_CAN_SKIP_ISA_ALIGN; + pci_set_flags(PCI_CAN_SKIP_ISA_ALIGN); root = of_find_node_by_path("/"); if (root == NULL) { @@ -1043,9 +1059,6 @@ void __init pmac_pci_init(void) } /* pmac_check_ht_link(); */ - /* We can allocate missing resources if any */ - pci_probe_only = 0; - #else /* CONFIG_PPC64 */ init_p2pbridge(); init_second_ohare(); @@ -1055,7 +1068,7 @@ void __init pmac_pci_init(void) * some offset between bus number and domains for now when we * assign all busses should help for now */ - if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_BUS) + if (pci_has_flag(PCI_REASSIGN_ALL_BUS)) pcibios_assign_bus_offset = 0x10; #endif } @@ -1125,7 +1138,7 @@ int pmac_pci_enable_device_hook(struct pci_dev *dev) return 0; } -void __devinit pmac_pci_fixup_ohci(struct pci_dev *dev) +void pmac_pci_fixup_ohci(struct pci_dev *dev) { struct device_node *node = pci_device_to_OF_node(dev); @@ -1144,28 +1157,6 @@ void __init pmac_pcibios_after_init(void) { struct device_node* nd; -#ifdef CONFIG_BLK_DEV_IDE - struct pci_dev *dev = NULL; - - /* OF fails to initialize IDE controllers on macs - * (and maybe other machines) - * - * Ideally, this should be moved to the IDE layer, but we need - * to check specifically with Andre Hedrick how to do it cleanly - * since the common IDE code seem to care about the fact that the - * BIOS may have disabled a controller. - * - * -- BenH - */ - for_each_pci_dev(dev) { - if ((dev->class >> 16) != PCI_BASE_CLASS_STORAGE) - continue; - if (pci_enable_device(dev)) - printk(KERN_WARNING - "pci: Failed to enable %s\n", pci_name(dev)); - } -#endif /* CONFIG_BLK_DEV_IDE */ - for_each_node_by_name(nd, "firewire") { if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") || of_device_is_compatible(nd, "pci106b,30") || @@ -1175,13 +1166,11 @@ void __init pmac_pcibios_after_init(void) pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); } } - of_node_put(nd); for_each_node_by_name(nd, "ethernet") { if (nd->parent && of_device_is_compatible(nd, "gmac") && of_device_is_compatible(nd->parent, "uni-north")) pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); } - of_node_put(nd); } void pmac_pci_fixup_cardbus(struct pci_dev* dev) @@ -1306,3 +1295,63 @@ static void fixup_k2_sata(struct pci_dev* dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata); +/* + * On U4 (aka CPC945) the PCIe root complex "P2P" bridge resource ranges aren't + * configured by the firmware. The bridge itself seems to ignore them but it + * causes problems with Linux which then re-assigns devices below the bridge, + * thus changing addresses of those devices from what was in the device-tree, + * which sucks when those are video cards using offb + * + * We could just mark it transparent but I prefer fixing up the resources to + * properly show what's going on here, as I have some doubts about having them + * badly configured potentially being an issue for DMA. + * + * We leave PIO alone, it seems to be fine + * + * Oh and there's another funny bug. The OF properties advertize the region + * 0xf1000000..0xf1ffffff as being forwarded as memory space. But that's + * actually not true, this region is the memory mapped config space. So we + * also need to filter it out or we'll map things in the wrong place. + */ +static void fixup_u4_pcie(struct pci_dev* dev) +{ + struct pci_controller *host = pci_bus_to_host(dev->bus); + struct resource *region = NULL; + u32 reg; + int i; + + /* Only do that on PowerMac */ + if (!machine_is(powermac)) + return; + + /* Find the largest MMIO region */ + for (i = 0; i < 3; i++) { + struct resource *r = &host->mem_resources[i]; + if (!(r->flags & IORESOURCE_MEM)) + continue; + /* Skip the 0xf0xxxxxx..f2xxxxxx regions, we know they + * are reserved by HW for other things + */ + if (r->start >= 0xf0000000 && r->start < 0xf3000000) + continue; + if (!region || resource_size(r) > resource_size(region)) + region = r; + } + /* Nothing found, bail */ + if (region == 0) + return; + + /* Print things out */ + printk(KERN_INFO "PCI: Fixup U4 PCIe bridge range: %pR\n", region); + + /* Fixup bridge config space. We know it's a Mac, resource aren't + * offset so let's just blast them as-is. We also know that they + * fit in 32 bits + */ + reg = ((region->start >> 16) & 0xfff0) | (region->end & 0xfff00000); + pci_write_config_dword(dev, PCI_MEMORY_BASE, reg); + pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0); + pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0); + pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_U4_PCIE, fixup_u4_pcie); |
