Matthew Wilcox wrote:
On Mon, Jan 31, 2005 at 10:52:29PM -0600, Brian King wrote:

@@ -62,8 +72,11 @@ static int rtas_read_config(struct devic
                return PCIBIOS_DEVICE_NOT_FOUND;
        if (where & (size - 1))
                return PCIBIOS_BAD_REGISTER_NUMBER;


You should probably delete this redundant test at the same time ...

Done. The new patch below also adds some address checking to iSeries config accessor functions. Additionally, this patch should address Arnd's concern, as it now looks for the "ibm,pci-config-space-type" property on the device itself rather than on the bridge.



-- Brian King eServer Storage I/O IBM Linux Technology Center
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 checks OF to see if
the PCI bridge supports PCI-X Mode 2 and fails config accesses beyond
256 bytes if it does not.

Signed-off-by: Brian King <[EMAIL PROTECTED]>
---

 linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/iSeries_pci.c |    6 +++
 linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pSeries_pci.c |   20 ++++++++---
 linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pci_dn.c      |    6 +++
 linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/prom.h        |    1 
 4 files changed, 29 insertions(+), 4 deletions(-)

diff -puN arch/ppc64/kernel/pSeries_pci.c~ppc64_pcix_mode2_cfg 
arch/ppc64/kernel/pSeries_pci.c
--- linux-2.6.11-rc2-bk9/arch/ppc64/kernel/pSeries_pci.c~ppc64_pcix_mode2_cfg   
2005-02-01 13:31:46.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pSeries_pci.c        
2005-02-01 13:39:32.000000000 -0600
@@ -52,6 +52,16 @@ static int s7a_workaround;
 
 extern struct mpic *pSeries_mpic;
 
+static int config_access_valid(struct device_node *dn, int where)
+{
+       if (where < 256)
+               return 1;
+       if (where < 4096 && dn->pci_ext_config_space)
+               return 1;
+
+       return 0;
+}
+
 static int rtas_read_config(struct device_node *dn, int where, int size, u32 
*val)
 {
        int returnval = -1;
@@ -60,10 +70,11 @@ static int rtas_read_config(struct devic
 
        if (!dn)
                return PCIBIOS_DEVICE_NOT_FOUND;
-       if (where & (size - 1))
+       if (!config_access_valid(dn, where))
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
-       addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+       addr = ((where & 0xf00) << 20) | (dn->busno << 16) |
+               (dn->devfn << 8) | (where & 0xff);
        buid = dn->phb->buid;
        if (buid) {
                ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
@@ -108,10 +119,11 @@ static int rtas_write_config(struct devi
 
        if (!dn)
                return PCIBIOS_DEVICE_NOT_FOUND;
-       if (where & (size - 1))
+       if (!config_access_valid(dn, where))
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
-       addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+       addr = ((where & 0xf00) << 20) | (dn->busno << 16) |
+               (dn->devfn << 8) | (where & 0xff);
        buid = dn->phb->buid;
        if (buid) {
                ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 
32, buid & 0xffffffff, size, (ulong) val);
diff -puN include/asm-ppc64/prom.h~ppc64_pcix_mode2_cfg include/asm-ppc64/prom.h
--- linux-2.6.11-rc2-bk9/include/asm-ppc64/prom.h~ppc64_pcix_mode2_cfg  
2005-02-01 13:31:46.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/prom.h       2005-02-01 
13:31:46.000000000 -0600
@@ -137,6 +137,7 @@ struct device_node {
        int     devfn;                  /* for pci devices */
        int     eeh_mode;               /* See eeh.h for possible EEH_MODEs */
        int     eeh_config_addr;
+       int     pci_ext_config_space;   /* for pci devices */
        struct  pci_controller *phb;    /* for pci devices */
        struct  iommu_table *iommu_table;       /* for phb's or bridges */
 
diff -puN arch/ppc64/kernel/pci_dn.c~ppc64_pcix_mode2_cfg 
arch/ppc64/kernel/pci_dn.c
--- linux-2.6.11-rc2-bk9/arch/ppc64/kernel/pci_dn.c~ppc64_pcix_mode2_cfg        
2005-02-01 13:31:46.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pci_dn.c     2005-02-01 
13:31:46.000000000 -0600
@@ -37,6 +37,7 @@
 static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
 {
        struct pci_controller *phb = data;
+       int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
        u32 *regs;
 
        dn->phb = phb;
@@ -46,6 +47,11 @@ static void * __devinit update_dn_pci_in
                dn->busno = (regs[0] >> 16) & 0xff;
                dn->devfn = (regs[0] >> 8) & 0xff;
        }
+
+       if (type && *type == 1)
+               dn->pci_ext_config_space = 1;
+       else
+               dn->pci_ext_config_space = 0;
        return NULL;
 }
 
diff -puN arch/ppc64/kernel/iSeries_pci.c~ppc64_pcix_mode2_cfg 
arch/ppc64/kernel/iSeries_pci.c
--- linux-2.6.11-rc2-bk9/arch/ppc64/kernel/iSeries_pci.c~ppc64_pcix_mode2_cfg   
2005-02-01 13:43:04.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/iSeries_pci.c        
2005-02-01 13:44:49.000000000 -0600
@@ -610,6 +610,10 @@ static int iSeries_pci_read_config(struc
 
        if (node == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
+       if (offset > 255) {
+               *val = ~0;
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
 
        fn = hv_cfg_read_func[(size - 1) & 3];
        HvCall3Ret16(fn, &ret, node->DsaAddr.DsaAddr, offset, 0);
@@ -636,6 +640,8 @@ static int iSeries_pci_write_config(stru
 
        if (node == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
+       if (offset > 255)
+               return PCIBIOS_BAD_REGISTER_NUMBER;
 
        fn = hv_cfg_write_func[(size - 1) & 3];
        ret = HvCall4(fn, node->DsaAddr.DsaAddr, offset, val, 0);
_

Reply via email to