When working with a PCI-X Mode 2 adapter on a PCI-X Mode 1 PPC64 system, the current code used to determine the config space size of a device results in a PCI Master abort and an EEH error, resulting in the device being taken offline. This patch adds an arch hook so that individual archs can indicate if the underlying system supports expanded config space accesses or not. Signed-off-by: Brian King --- linux-2.6.11-rc2-bk9-bjking1/arch/alpha/kernel/pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/arm/kernel/bios32.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/frv/mb93090-mb00/pci-frv.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/i386/pci/common.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/ia64/pci/pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/m68knommu/kernel/comempci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/mips/pci/pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/mips/pmc-sierra/yosemite/ht.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/parisc/kernel/pci.c | 1 linux-2.6.11-rc2-bk9-bjking1/arch/ppc/kernel/pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/iSeries_pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pci.c | 18 ++++++++++ linux-2.6.11-rc2-bk9-bjking1/arch/sh/boards/mpc1211/pci.c | 1 linux-2.6.11-rc2-bk9-bjking1/arch/sh/boards/overdrive/galileo.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/sh/drivers/pci/pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/sh64/kernel/pcibios.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/sparc/kernel/pcic.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/sparc64/kernel/pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/arch/v850/kernel/rte_mb_a_pci.c | 2 + linux-2.6.11-rc2-bk9-bjking1/drivers/pci/probe.c | 2 + linux-2.6.11-rc2-bk9-bjking1/include/linux/pci.h | 1 21 files changed, 55 insertions(+) diff -puN drivers/pci/probe.c~pci_get_cfg_size_all drivers/pci/probe.c --- linux-2.6.11-rc2-bk9/drivers/pci/probe.c~pci_get_cfg_size_all 2005-01-31 11:16:22.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/drivers/pci/probe.c 2005-01-31 11:22:07.000000000 -0600 @@ -653,6 +653,8 @@ static int pci_cfg_space_size(struct pci goto fail; } + if (!pcibios_exp_cfg_space(dev)) + goto fail; if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL) goto fail; if (status == 0xffffffff) diff -puN arch/alpha/kernel/pci.c~pci_get_cfg_size_all arch/alpha/kernel/pci.c --- linux-2.6.11-rc2-bk9/arch/alpha/kernel/pci.c~pci_get_cfg_size_all 2005-01-31 11:16:33.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/alpha/kernel/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -202,6 +202,8 @@ pcibios_setup(char *str) return str; } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } + #ifdef ALPHA_RESTORE_SRM_SETUP static struct pdev_srm_saved_conf *srm_saved_configs; diff -puN arch/arm/kernel/bios32.c~pci_get_cfg_size_all arch/arm/kernel/bios32.c --- linux-2.6.11-rc2-bk9/arch/arm/kernel/bios32.c~pci_get_cfg_size_all 2005-01-31 11:16:43.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/arm/kernel/bios32.c 2005-01-31 11:22:27.000000000 -0600 @@ -67,6 +67,8 @@ void pcibios_report_status(u_int status_ } } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } + /* * We don't use this to fix the device, but initialisation of it. * It's not the correct use for this, but it works. diff -puN arch/frv/mb93090-mb00/pci-frv.c~pci_get_cfg_size_all arch/frv/mb93090-mb00/pci-frv.c --- linux-2.6.11-rc2-bk9/arch/frv/mb93090-mb00/pci-frv.c~pci_get_cfg_size_all 2005-01-31 11:16:55.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/frv/mb93090-mb00/pci-frv.c 2005-01-31 11:22:27.000000000 -0600 @@ -286,3 +286,5 @@ void pcibios_set_master(struct pci_dev * printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); } + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/i386/pci/common.c~pci_get_cfg_size_all arch/i386/pci/common.c --- linux-2.6.11-rc2-bk9/arch/i386/pci/common.c~pci_get_cfg_size_all 2005-01-31 11:17:01.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/i386/pci/common.c 2005-01-31 11:22:27.000000000 -0600 @@ -249,3 +249,5 @@ int pcibios_enable_device(struct pci_dev return pcibios_enable_irq(dev); } + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/ia64/pci/pci.c~pci_get_cfg_size_all arch/ia64/pci/pci.c --- linux-2.6.11-rc2-bk9/arch/ia64/pci/pci.c~pci_get_cfg_size_all 2005-01-31 11:17:09.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/ia64/pci/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -744,3 +744,5 @@ int pci_vector_resources(int last, int n return count; } + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/m68knommu/kernel/comempci.c~pci_get_cfg_size_all arch/m68knommu/kernel/comempci.c --- linux-2.6.11-rc2-bk9/arch/m68knommu/kernel/comempci.c~pci_get_cfg_size_all 2005-01-31 11:17:23.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/m68knommu/kernel/comempci.c 2005-01-31 11:22:27.000000000 -0600 @@ -987,3 +987,5 @@ void pci_free_consistent(struct pci_dev } /*****************************************************************************/ + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/mips/pci/pci.c~pci_get_cfg_size_all arch/mips/pci/pci.c --- linux-2.6.11-rc2-bk9/arch/mips/pci/pci.c~pci_get_cfg_size_all 2005-01-31 11:17:33.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/mips/pci/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -300,3 +300,5 @@ char *pcibios_setup(char *str) { return str; } + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/mips/pmc-sierra/yosemite/ht.c~pci_get_cfg_size_all arch/mips/pmc-sierra/yosemite/ht.c --- linux-2.6.11-rc2-bk9/arch/mips/pmc-sierra/yosemite/ht.c~pci_get_cfg_size_all 2005-01-31 11:17:44.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/mips/pmc-sierra/yosemite/ht.c 2005-01-31 11:22:27.000000000 -0600 @@ -451,4 +451,6 @@ unsigned __init int pcibios_assign_all_b return 0; } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } + #endif /* CONFIG_HYPERTRANSPORT */ diff -puN arch/parisc/kernel/pci.c~pci_get_cfg_size_all arch/parisc/kernel/pci.c --- linux-2.6.11-rc2-bk9/arch/parisc/kernel/pci.c~pci_get_cfg_size_all 2005-01-31 11:17:50.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/parisc/kernel/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -330,6 +330,7 @@ int pcibios_enable_device(struct pci_dev return 0; } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } /* PA-RISC specific */ void pcibios_register_hba(struct pci_hba_data *hba) diff -puN arch/ppc/kernel/pci.c~pci_get_cfg_size_all arch/ppc/kernel/pci.c --- linux-2.6.11-rc2-bk9/arch/ppc/kernel/pci.c~pci_get_cfg_size_all 2005-01-31 11:18:02.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc/kernel/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -1728,6 +1728,8 @@ void pci_iounmap(struct pci_dev *dev, vo EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } + /* * Null PCI config access functions, for the case when we can't * find a hose. diff -puN arch/ppc64/kernel/iSeries_pci.c~pci_get_cfg_size_all arch/ppc64/kernel/iSeries_pci.c --- linux-2.6.11-rc2-bk9/arch/ppc64/kernel/iSeries_pci.c~pci_get_cfg_size_all 2005-01-31 11:18:09.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/iSeries_pci.c 2005-01-31 11:22:20.000000000 -0600 @@ -348,6 +348,8 @@ void pcibios_fixup_resources(struct pci_ PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev); } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 0; } + /* * Loop through each node function to find usable EADs bridges. */ diff -puN arch/ppc64/kernel/pci.c~pci_get_cfg_size_all arch/ppc64/kernel/pci.c --- linux-2.6.11-rc2-bk9/arch/ppc64/kernel/pci.c~pci_get_cfg_size_all 2005-01-31 11:18:13.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pci.c 2005-01-31 11:22:20.000000000 -0600 @@ -467,6 +467,24 @@ void pcibios_add_platform_entries(struct #ifdef CONFIG_PPC_MULTIPLATFORM +int pcibios_exp_cfg_space(struct pci_dev *dev) +{ + int *type; + struct device_node *dn; + struct pci_controller *hose = pci_bus_to_host(dev->bus); + + if (!hose) + return 0; + + dn = (struct device_node *) hose->arch_data; + type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL); + + if (type && *type == 1) + return 1; + + return 0; +} + #define ISA_SPACE_MASK 0x1 #define ISA_SPACE_IO 0x1 diff -puN arch/sh/boards/mpc1211/pci.c~pci_get_cfg_size_all arch/sh/boards/mpc1211/pci.c --- linux-2.6.11-rc2-bk9/arch/sh/boards/mpc1211/pci.c~pci_get_cfg_size_all 2005-01-31 11:18:24.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/sh/boards/mpc1211/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -294,3 +294,4 @@ void pcibios_align_resource(void *data, } } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/sh/boards/overdrive/galileo.c~pci_get_cfg_size_all arch/sh/boards/overdrive/galileo.c --- linux-2.6.11-rc2-bk9/arch/sh/boards/overdrive/galileo.c~pci_get_cfg_size_all 2005-01-31 11:18:33.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/sh/boards/overdrive/galileo.c 2005-01-31 11:22:27.000000000 -0600 @@ -586,3 +586,5 @@ void pcibios_set_master(struct pci_dev * printk("PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); } + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/sh/drivers/pci/pci.c~pci_get_cfg_size_all arch/sh/drivers/pci/pci.c --- linux-2.6.11-rc2-bk9/arch/sh/drivers/pci/pci.c~pci_get_cfg_size_all 2005-01-31 11:18:49.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/sh/drivers/pci/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -153,3 +153,5 @@ void __init pcibios_update_irq(struct pc { pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/sh64/kernel/pcibios.c~pci_get_cfg_size_all arch/sh64/kernel/pcibios.c --- linux-2.6.11-rc2-bk9/arch/sh64/kernel/pcibios.c~pci_get_cfg_size_all 2005-01-31 11:19:47.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/sh64/kernel/pcibios.c 2005-01-31 11:22:27.000000000 -0600 @@ -166,3 +166,5 @@ void __init pcibios_update_irq(struct pc { pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/sparc/kernel/pcic.c~pci_get_cfg_size_all arch/sparc/kernel/pcic.c --- linux-2.6.11-rc2-bk9/arch/sparc/kernel/pcic.c~pci_get_cfg_size_all 2005-01-31 11:19:52.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/sparc/kernel/pcic.c 2005-01-31 11:22:27.000000000 -0600 @@ -1033,3 +1033,5 @@ void insl(void * __iomem addr, void *dst } subsys_initcall(pcic_init); + +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } diff -puN arch/sparc64/kernel/pci.c~pci_get_cfg_size_all arch/sparc64/kernel/pci.c --- linux-2.6.11-rc2-bk9/arch/sparc64/kernel/pci.c~pci_get_cfg_size_all 2005-01-31 11:20:02.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/sparc64/kernel/pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -809,4 +809,6 @@ int pcibios_prep_mwi(struct pci_dev *dev return 0; } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } + #endif /* !(CONFIG_PCI) */ diff -puN arch/v850/kernel/rte_mb_a_pci.c~pci_get_cfg_size_all arch/v850/kernel/rte_mb_a_pci.c --- linux-2.6.11-rc2-bk9/arch/v850/kernel/rte_mb_a_pci.c~pci_get_cfg_size_all 2005-01-31 11:20:15.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/arch/v850/kernel/rte_mb_a_pci.c 2005-01-31 11:22:27.000000000 -0600 @@ -337,6 +337,8 @@ void pcibios_set_master (struct pci_dev { } +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; } + /* Mother-A SRAM memory allocation. This is a simple first-fit allocator. */ diff -puN include/linux/pci.h~pci_get_cfg_size_all include/linux/pci.h --- linux-2.6.11-rc2-bk9/include/linux/pci.h~pci_get_cfg_size_all 2005-01-31 11:20:30.000000000 -0600 +++ linux-2.6.11-rc2-bk9-bjking1/include/linux/pci.h 2005-01-31 11:22:07.000000000 -0600 @@ -723,6 +723,7 @@ extern struct list_head pci_devices; /* void pcibios_fixup_bus(struct pci_bus *); int pcibios_enable_device(struct pci_dev *, int mask); char *pcibios_setup (char *str); +int pcibios_exp_cfg_space(struct pci_dev *dev); /* Used only when drivers/pci/setup.c is used */ void pcibios_align_resource(void *, struct resource *, _