2005-01-28 14:56:38

by Brian King

[permalink] [raw]
Subject: [PATCH 1/2] pci: Arch hook to determine config space size


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 the ability for
arch specific code to override part of the config space size
determination to fix this.

Signed-off-by: Brian King <[email protected]>
---

linux-2.6.11-rc2-bk5-bjking1/drivers/pci/probe.c | 4 ++++
1 files changed, 4 insertions(+)

diff -puN drivers/pci/probe.c~pci_arch_cfg_space_size drivers/pci/probe.c
--- linux-2.6.11-rc2-bk5/drivers/pci/probe.c~pci_arch_cfg_space_size 2005-01-27 16:56:46.000000000 -0600
+++ linux-2.6.11-rc2-bk5-bjking1/drivers/pci/probe.c 2005-01-27 16:56:46.000000000 -0600
@@ -627,6 +627,8 @@ static void pci_release_dev(struct devic
kfree(pci_dev);
}

+int __attribute__ ((weak)) pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; }
+
/**
* pci_cfg_space_size - get the configuration space size of the PCI device.
*
@@ -653,6 +655,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)
_


2005-01-28 18:59:27

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 1/2] pci: Arch hook to determine config space size

> +int __attribute__ ((weak)) pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; }

- prototypes belong to headers
- weak linkage is the perfect way for total obsfucation

please make this a regular arch hook
> Please read the FAQ at http://www.tux.org/lkml/
---end quoted text---

2005-01-29 04:33:55

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 1/2] pci: Arch hook to determine config space size

On Fri, Jan 28, 2005 at 06:52:34PM +0000, Christoph Hellwig wrote:
> > +int __attribute__ ((weak)) pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; }
>
> - prototypes belong to headers
> - weak linkage is the perfect way for total obsfucation
>
> please make this a regular arch hook

I agree. Also, when sending PCI related patches, please cc the
linux-pci mailing list.

thanks,

greg k-h

2005-01-31 19:13:38

by Brian King

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size


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 <[email protected]>
---

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 *,
_


Attachments:
pci_get_cfg_size_all.patch (12.54 kB)

2005-01-31 19:16:44

by Greg KH

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Mon, Jan 31, 2005 at 01:10:46PM -0600, Brian King wrote:
> +int pcibios_exp_cfg_space(struct pci_dev *dev) { return 1; }
> +

Kernel functions traditionally return 0 for success and -ESOMETHING for
error. Care to fix this up to match that convention?

thanks,

greg k-h

2005-01-31 19:32:11

by Matthew Wilcox

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Mon, Jan 31, 2005 at 01:10:46PM -0600, Brian King wrote:
> Greg KH wrote:
> >On Fri, Jan 28, 2005 at 06:52:34PM +0000, Christoph Hellwig wrote:
> >
> >>>+int __attribute__ ((weak)) pcibios_exp_cfg_space(struct pci_dev *dev) {
> >>>return 1; }
> >>
> >>- prototypes belong to headers
> >>- weak linkage is the perfect way for total obsfucation
> >>
> >>please make this a regular arch hook
> >
> >
> >I agree. Also, when sending PCI related patches, please cc the
> >linux-pci mailing list.
>
> How about this?

Thanks for copying linux-pci. I hate this patch.

Basically, ppc64's config ops are broken and need to check the offset
being read. Here's i386:

static int pci_conf1_write (int seg, int bus, int devfn, int reg, int len, u32 v
alue)
{
unsigned long flags;

if ((bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;

I think all the config ops in ppc64 are broken and need to check for these
limits. Also, it does some checks that are already performed by upper layers:

if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;

is checked for in drivers/pci/access.c

--
"Next the statesmen will invent cheap lies, putting the blame upon
the nation that is attacked, and every man will be glad of those
conscience-soothing falsities, and will diligently study them, and refuse
to examine any refutations of them; and thus he will by and by convince
himself that the war is just, and will thank God for the better sleep
he enjoys after this process of grotesque self-deception." -- Mark Twain

2005-01-31 19:43:41

by Brian King

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

Brian King wrote:
> Greg KH wrote:
>
>> On Fri, Jan 28, 2005 at 06:52:34PM +0000, Christoph Hellwig wrote:
>>
>>>> +int __attribute__ ((weak)) pcibios_exp_cfg_space(struct pci_dev
>>>> *dev) { return 1; }
>>>
>>>
>>> - prototypes belong to headers
>>> - weak linkage is the perfect way for total obsfucation
>>>
>>> please make this a regular arch hook
>>
>>
>>
>> I agree. Also, when sending PCI related patches, please cc the
>> linux-pci mailing list.

CC'ing the linux-pci mailing list...

-brian

> How about this?
>
>
> ------------------------------------------------------------------------
>
>
> 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 <[email protected]>
> ---
>
> 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 *,
> _


--
Brian King
eServer Storage I/O
IBM Linux Technology Center

2005-01-31 21:08:49

by Arnd Bergmann

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Maandag 31 Januar 2005 20:29, Matthew Wilcox wrote:
> Thanks for copying linux-pci. ?I hate this patch.
>
> Basically, ppc64's config ops are broken and need to check the offset
> being read.

To make things worse, simply allowing the larger config space will
silently access the wrong device. The least that needs to be done
is to pass the correct address to the firmware.
This patch should do the right thing, though I don't have any PCIe
card to test with.

Note that at least for the rtas pci config access, the bus/devfn
values come from the device tree, which makes it somewhat harder
to screw them up, and rtas ought to check for obviously wrong
addresses as well.

Signed-off-by: Arnd Bergmann <[email protected]>

--- linux-mm.orig/arch/ppc64/kernel/pSeries_pci.c 2005-01-28 07:21:15.000000000 -0500
+++ linux-mm/arch/ppc64/kernel/pSeries_pci.c 2005-01-31 15:56:10.244983464 -0500
@@ -63,7 +63,8 @@
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;

- addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+ addr = ((where & 0xf00) << 20) | (dn->busno << 16)
+ | (dn->devfn << 8) | (where & 0x0ff);
buid = dn->phb->buid;
if (buid) {
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
@@ -111,7 +112,8 @@
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;

- addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+ addr = ((where & 0xf00) << 20) | (dn->busno << 16)
+ | (dn->devfn << 8) | (where & 0x0ff);
buid = dn->phb->buid;
if (buid) {
ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);



Attachments:
(No filename) (1.58 kB)
(No filename) (189.00 B)
signature
Download all attachments

2005-01-31 21:36:05

by Brian King

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size



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/pSeries_pci.c | 25 +++++++++++
linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/prom.h | 1
2 files changed, 26 insertions(+)

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-01-31 14:32:01.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pSeries_pci.c 2005-01-31 15:09:53.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)
+{
+ struct device_node *hose_dn = dn->phb->arch_data;
+
+ if (where < 256 || hose_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;
@@ -62,6 +72,8 @@ static int rtas_read_config(struct devic
return PCIBIOS_DEVICE_NOT_FOUND;
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (!config_access_valid(dn, where))
+ return PCIBIOS_BAD_REGISTER_NUMBER;

addr = (dn->busno << 16) | (dn->devfn << 8) | where;
buid = dn->phb->buid;
@@ -110,6 +122,8 @@ static int rtas_write_config(struct devi
return PCIBIOS_DEVICE_NOT_FOUND;
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (!config_access_valid(dn, where))
+ return PCIBIOS_BAD_REGISTER_NUMBER;

addr = (dn->busno << 16) | (dn->devfn << 8) | where;
buid = dn->phb->buid;
@@ -270,6 +284,16 @@ static int phb_set_bus_ranges(struct dev
return 0;
}

+static void __devinit get_phb_config_space_type(struct device_node *dn)
+{
+ int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
+
+ if (type && *type == 1)
+ dn->pci_ext_config_space = 1;
+ else
+ dn->pci_ext_config_space = 0;
+}
+
static int __devinit setup_phb(struct device_node *dev,
struct pci_controller *phb,
unsigned int addr_size_words)
@@ -285,6 +309,7 @@ static int __devinit setup_phb(struct de
phb->arch_data = dev;
phb->ops = &rtas_pci_ops;
phb->buid = get_phb_buid(dev);
+ get_phb_config_space_type(dev);

return 0;
}
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-01-31 14:32:01.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/prom.h 2005-01-31 14:32:01.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 phb's or bridges */
struct pci_controller *phb; /* for pci devices */
struct iommu_table *iommu_table; /* for phb's or bridges */

_


Attachments:
ppc64_pcix_mode2_cfg.patch (3.16 kB)

2005-01-31 22:07:52

by Arnd Bergmann

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Maandag 31 Januar 2005 22:35, Brian King wrote:
> Matthew Wilcox wrote:
> > Basically, ppc64's config ops are broken and need to check the offset
> > being read. ?Here's i386:
> >
> > static int pci_conf1_write (int seg, int bus, int devfn, int reg, int len, u32 v
> > alue)
> > {
> > ? ? ? ? unsigned long flags;
> >
> > ? ? ? ? if ((bus > 255) || (devfn > 255) || (reg > 255))
> > ? ? ? ? ? ? ? ? return -EINVAL;
>
> Here is a pure ppc64 implementation that does this.

Actually, it doesn't:

> +static int config_access_valid(struct device_node *dn, int where)
> +{
> +???????struct device_node *hose_dn = dn->phb->arch_data;
> +
> +???????if (where < 256 || hose_dn->pci_ext_config_space)
> +???????????????return 1;

This needs a check for (where < 4096) in case of PCIe or PCI-X.

> @@ -62,6 +72,8 @@ static int rtas_read_config(struct devic
> ????????????????return PCIBIOS_DEVICE_NOT_FOUND;
> ????????if (where & (size - 1))
> ????????????????return PCIBIOS_BAD_REGISTER_NUMBER;
> +???????if (!config_access_valid(dn, where))
> +???????????????return PCIBIOS_BAD_REGISTER_NUMBER;
> ?
> ????????addr = (dn->busno << 16) | (dn->devfn << 8) | where;

addr is still wrong, see my previous mail.

> @@ -110,6 +122,8 @@ static int rtas_write_config(struct devi
> ????????????????return PCIBIOS_DEVICE_NOT_FOUND;
> ????????if (where & (size - 1))
> ????????????????return PCIBIOS_BAD_REGISTER_NUMBER;
> +???????if (!config_access_valid(dn, where))
> +???????????????return PCIBIOS_BAD_REGISTER_NUMBER;
> ?
> ????????addr = (dn->busno << 16) | (dn->devfn << 8) | where;

same here

> @@ -285,6 +309,7 @@ static int __devinit setup_phb(struct de
> ????????phb->arch_data = dev;
> ????????phb->ops = &rtas_pci_ops;
> ????????phb->buid = get_phb_buid(dev);
> +???????get_phb_config_space_type(dev);
> ?
> ????????return 0;
> ?}

Isn't the config space size a property of the PCI device instead of the
host bridge? For a PCI device behind a PCIe host bridge, this could
still lead to an incorrect config space accesses.

Arnd <><

PS: I got a permanent fatal error from <[email protected]>, does
that list actually exist?


Attachments:
(No filename) (2.08 kB)
(No filename) (189.00 B)
signature
Download all attachments

2005-01-31 22:21:56

by Greg KH

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Mon, Jan 31, 2005 at 10:56:44PM +0100, Arnd Bergmann wrote:
> PS: I got a permanent fatal error from <[email protected]>, does
> that list actually exist?

No, that is not the email address for the linux-pci mailing list. I
don't know who put that in this thread, but next time, someone might
want to actually look the address up before blindly guessing...

thanks,

greg k-h

2005-01-31 22:44:09

by Brian King

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size



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/pSeries_pci.c | 33 ++++++++++-
linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/prom.h | 1
2 files changed, 32 insertions(+), 2 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-01-31 14:32:01.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pSeries_pci.c 2005-01-31 16:17:08.000000000 -0600
@@ -52,6 +52,18 @@ static int s7a_workaround;

extern struct mpic *pSeries_mpic;

+static int config_access_valid(struct device_node *dn, int where)
+{
+ struct device_node *hose_dn = dn->phb->arch_data;
+
+ if (where < 256)
+ return 1;
+ if (where < 4096 && hose_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;
@@ -62,8 +74,11 @@ static int rtas_read_config(struct devic
return PCIBIOS_DEVICE_NOT_FOUND;
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;
+ 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,
@@ -110,8 +125,11 @@ static int rtas_write_config(struct devi
return PCIBIOS_DEVICE_NOT_FOUND;
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;
+ 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);
@@ -270,6 +288,16 @@ static int phb_set_bus_ranges(struct dev
return 0;
}

+static void __devinit get_phb_config_space_type(struct device_node *dn)
+{
+ int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
+
+ if (type && *type == 1)
+ dn->pci_ext_config_space = 1;
+ else
+ dn->pci_ext_config_space = 0;
+}
+
static int __devinit setup_phb(struct device_node *dev,
struct pci_controller *phb,
unsigned int addr_size_words)
@@ -285,6 +313,7 @@ static int __devinit setup_phb(struct de
phb->arch_data = dev;
phb->ops = &rtas_pci_ops;
phb->buid = get_phb_buid(dev);
+ get_phb_config_space_type(dev);

return 0;
}
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-01-31 14:32:01.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/prom.h 2005-01-31 14:32:01.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 phb's or bridges */
struct pci_controller *phb; /* for pci devices */
struct iommu_table *iommu_table; /* for phb's or bridges */

_


Attachments:
ppc64_pcix_mode2_cfg.patch (3.58 kB)

2005-02-01 03:18:07

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Mon, 2005-01-31 at 16:43 -0600, Brian King wrote:

> 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-01-31 14:32:01.000000000 -0600
> +++ linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/prom.h 2005-01-31 14:32:01.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 phb's or bridges */
> struct pci_controller *phb; /* for pci devices */
> struct iommu_table *iommu_table; /* for phb's or bridges */

Grrr... more crap added to the device-node, I don't like that ...

This is a PHB only field, can't it be in struct pci_controller instead ?

Ben.


2005-02-01 04:52:47

by Brian King

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size


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.


---

linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pSeries_pci.c | 31 ++++++++++-
linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/pci-bridge.h | 1
2 files changed, 30 insertions(+), 2 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-01-31 22:27:49.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/arch/ppc64/kernel/pSeries_pci.c 2005-01-31 22:31:04.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->phb->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;
@@ -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;
+ 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,
@@ -110,8 +123,11 @@ static int rtas_write_config(struct devi
return PCIBIOS_DEVICE_NOT_FOUND;
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;
+ 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);
@@ -270,6 +286,16 @@ static int phb_set_bus_ranges(struct dev
return 0;
}

+static char __devinit get_phb_config_space_type(struct pci_controller *phb)
+{
+ int *type = (int *)get_property(phb->arch_data,
+ "ibm,pci-config-space-type", NULL);
+
+ if (type && *type == 1)
+ return 1;
+ return 0;
+}
+
static int __devinit setup_phb(struct device_node *dev,
struct pci_controller *phb,
unsigned int addr_size_words)
@@ -285,6 +311,7 @@ static int __devinit setup_phb(struct de
phb->arch_data = dev;
phb->ops = &rtas_pci_ops;
phb->buid = get_phb_buid(dev);
+ phb->pci_ext_config_space = get_phb_config_space_type(phb);

return 0;
}
diff -puN include/asm-ppc64/pci-bridge.h~ppc64_pcix_mode2_cfg include/asm-ppc64/pci-bridge.h
--- linux-2.6.11-rc2-bk9/include/asm-ppc64/pci-bridge.h~ppc64_pcix_mode2_cfg 2005-01-31 22:27:49.000000000 -0600
+++ linux-2.6.11-rc2-bk9-bjking1/include/asm-ppc64/pci-bridge.h 2005-01-31 22:27:49.000000000 -0600
@@ -17,6 +17,7 @@
struct pci_controller {
struct pci_bus *bus;
char is_dynamic;
+ char pci_ext_config_space;
void *arch_data;
struct list_head list_node;


_


Attachments:
ppc64_pcix_mode2_cfg.patch (3.35 kB)

2005-02-01 04:59:57

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Mon, 2005-01-31 at 22:52 -0600, Brian King wrote:

> Assuming I am reading the spec correctly, this is only a property of the
> PHB, so I could move it into the pci_controller struct instead.

Note that Arnd seems to imply the opposite ...

BTW. I'm thinking about moving all those PCI/VIO related fields out of
struct device_node to their own structure and keep only a pointer to
that structure in device_node. That way, we avoid the bloat for every
single non-pci node in the system, and we can have different structures
for different bus types (along with proper iommu function pointers and
that sort-of-thing).

So if you think you really need a per-device info here, feel free to
add it to device_node for now, and I'll move it to the new structure
along with the rest of the stuff once I find time to do this patch.

Ben.


2005-02-01 07:50:16

by Grant Grundler

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Mon, Jan 31, 2005 at 01:40:04PM -0600, Brian King wrote:
> CC'ing the linux-pci mailing list...

thanks...

> > This patch adds an arch hook so
> > that individual archs can indicate if the underlying system supports
> > expanded config space accesses or not.

> >@@ -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;

pci_read_config_dword lands in arch specific code.
See drivers/pci/access.c:PCI_OP_READ() macro.

I'm missing what pcibios_exp_cfg_space() does that can't be handled by
the bus_ops supplied by pci_scan_bus().

I would expect the pci_read_config_dword to fail for being out of bounds.
Is that wrong?
Or is bus_ops not feasible in this case because pcibios needs access
to pci_dev?

If it's feasible, maybe the right place to add this hook is to
pci_read_config_dword which is also handed the pci_dev. And add
another function pointer to bus_ops (which could be NULL) to check
chipset support for Expanded Config space before calling
pci_bus_read_config_dword. Thats cleaner than adding a hook
before each use of pci_read_config_dword.

hth,
grant

2005-02-01 12:33:01

by Matthew Wilcox

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

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 ...

> + 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,

--
"Next the statesmen will invent cheap lies, putting the blame upon
the nation that is attacked, and every man will be glad of those
conscience-soothing falsities, and will diligently study them, and refuse
to examine any refutations of them; and thus he will by and by convince
himself that the war is just, and will thank God for the better sleep
he enjoys after this process of grotesque self-deception." -- Mark Twain

2005-02-01 15:23:50

by Brian King

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

Grant Grundler wrote:
> On Mon, Jan 31, 2005 at 01:40:04PM -0600, Brian King wrote:
>
>>CC'ing the linux-pci mailing list...
>
>
> thanks...
>
>
>>>This patch adds an arch hook so
>>>that individual archs can indicate if the underlying system supports
>>>expanded config space accesses or not.
>
>
>>>@@ -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;
>
>
> pci_read_config_dword lands in arch specific code.
> See drivers/pci/access.c:PCI_OP_READ() macro.
>
> I'm missing what pcibios_exp_cfg_space() does that can't be handled by
> the bus_ops supplied by pci_scan_bus().
>
> I would expect the pci_read_config_dword to fail for being out of bounds.
> Is that wrong?
> Or is bus_ops not feasible in this case because pcibios needs access
> to pci_dev?

The current patch for this has become essentially that. It is now a
PPC64 specific patch that adds bounds checking in the PPC64 PCI config
access functions.

-Brian


--
Brian King
eServer Storage I/O
IBM Linux Technology Center

2005-02-01 20:17:44

by Brian King

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size


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);
_


Attachments:
ppc64_pcix_mode2_cfg.patch (4.61 kB)

2005-02-02 10:16:57

by Arnd Bergmann

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Dinsdag 01 Februar 2005 05:57, Benjamin Herrenschmidt wrote:
> BTW. I'm thinking about moving all those PCI/VIO related fields out of
> struct device_node to their own structure and keep only a pointer to
> that structure in device_node. That way, we avoid the bloat for every
> single non-pci node in the system, and we can have different structures
> for different bus types (along with proper iommu function pointers and
> that sort-of-thing).

How about something along the lines of this patch? Instead of adding a
pointer to the pci data from the device node, it embeds the node inside
a new struct pci_device_node. The patch is not complete and therefore
not expected to work as is, but maybe you want to reuse it.

The interesting part that is missing is creating and destroying
pci_device_nodes in prom.c, maybe you have an idea how to do that.

I'm also not sure about eeh. Are the eeh functions known to be called
only for device_nodes of PCI devices? If not, eeh_mode and
eeh_config_addr might have to stay inside of device_node.

Arnd <><

Signed-off-by: Arnd Bergmann <[email protected]>

Index: linux-2.6-64/arch/ppc64/kernel/pci.h
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/pci.h 2005-01-24 23:46:37.000000000 +0100
+++ linux-2.6-64/arch/ppc64/kernel/pci.h 2005-02-02 00:11:01.485740824 +0100
@@ -29,8 +29,8 @@

/* PCI device_node operations */
struct device_node;
-typedef void *(*traverse_func)(struct device_node *me, void *data);
-void *traverse_pci_devices(struct device_node *start, traverse_func pre,
+typedef void *(*traverse_func)(struct pci_device_node *me, void *data);
+void *traverse_pci_devices(struct pci_device_node *start, traverse_func pre,
void *data);

void pci_devs_phb_init(void);
Index: linux-2.6-64/arch/ppc64/kernel/pSeries_iommu.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/pSeries_iommu.c 2005-02-01 22:53:00.673332472 +0100
+++ linux-2.6-64/arch/ppc64/kernel/pSeries_iommu.c 2005-02-02 00:11:01.486740672 +0100
@@ -48,7 +48,7 @@

#define DBG(fmt...)

-extern int is_python(struct device_node *);
+extern int is_python(struct pci_device_node *);

static void tce_build_pSeries(struct iommu_table *tbl, long index,
long npages, unsigned long uaddr,
@@ -289,7 +289,7 @@
* Currently we hard code these sizes (more or less).
*/
static void iommu_table_setparms_lpar(struct pci_controller *phb,
- struct device_node *dn,
+ struct pci_device_node *dn,
struct iommu_table *tbl,
unsigned int *dma_window)
{
@@ -308,7 +308,7 @@

static void iommu_bus_setup_pSeries(struct pci_bus *bus)
{
- struct device_node *dn, *pdn;
+ struct pci_device_node *dn, *pdn;

DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self);

@@ -331,7 +331,7 @@

DBG("Python root bus %s\n", bus->name);

- iohole = (unsigned int *)get_property(dn, "io-hole", 0);
+ iohole = (unsigned int *)get_property(&dn->node, "io-hole", 0);

if (iohole) {
/* On first bus we need to leave room for the
@@ -349,7 +349,7 @@

tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);

- iommu_table_setparms(dn->phb, dn, tbl);
+ iommu_table_setparms(dn->phb, &dn->node, tbl);
dn->iommu_table = iommu_init_table(tbl);
} else {
/* 256 MB window by default */
@@ -368,7 +368,7 @@

tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);

- iommu_table_setparms(dn->phb, dn, tbl);
+ iommu_table_setparms(dn->phb, &dn->node, tbl);

dn->iommu_table = iommu_init_table(tbl);
} else {
@@ -382,17 +382,19 @@
static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
{
struct iommu_table *tbl;
- struct device_node *dn, *pdn;
+ struct pci_device_node *dn, *pdn;
+ struct device_node *n;
unsigned int *dma_window = NULL;

dn = pci_bus_to_OF_node(bus);

/* Find nearest ibm,dma-window, walking up the device tree */
- for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
- dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);
+ for (n = &dn->node; n; n = n->parent) {
+ dma_window = (unsigned int *)get_property(n, "ibm,dma-window", NULL);
if (dma_window != NULL)
break;
}
+ pdn = to_pci_node(n);

if (dma_window == NULL) {
DBG("iommu_bus_setup_pSeriesLP: bus %s seems to have no ibm,dma-window property\n", dn->full_name);
@@ -420,7 +422,7 @@

static void iommu_dev_setup_pSeries(struct pci_dev *dev)
{
- struct device_node *dn, *mydn;
+ struct pci_device_node *dn, *mydn;

DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, dev->pretty_name);
/* Now copy the iommu_table ptr from the bus device down to the
@@ -430,7 +432,7 @@
mydn = dn = pci_device_to_OF_node(dev);

while (dn && dn->iommu_table == NULL)
- dn = dn->parent;
+ dn = to_pci_node(dn->node.parent);

if (dn) {
mydn->iommu_table = dn->iommu_table;
Index: linux-2.6-64/include/asm-ppc64/pci-bridge.h
===================================================================
--- linux-2.6-64.orig/include/asm-ppc64/pci-bridge.h 2005-01-24 23:47:11.000000000 +0100
+++ linux-2.6-64/include/asm-ppc64/pci-bridge.h 2005-02-02 00:11:01.486740672 +0100
@@ -53,22 +53,23 @@
/* Get a device_node from a pci_dev. This code must be fast except in the case
* where the sysdata is incorrect and needs to be fixed up (hopefully just once)
*/
-static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
+static inline struct pci_device_node *pci_device_to_OF_node(struct pci_dev *dev)
{
struct device_node *dn = dev->sysdata;
+ struct pci_device_node *pdn = to_pci_node(dn);

- if (dn->devfn == dev->devfn && dn->busno == dev->bus->number)
- return dn; /* fast path. sysdata is good */
+ if (pdn->devfn == dev->devfn && pdn->busno == dev->bus->number)
+ return pdn; /* fast path. sysdata is good */
else
- return fetch_dev_dn(dev);
+ return to_pci_node(fetch_dev_dn(dev));
}

-static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
+static inline struct pci_device_node *pci_bus_to_OF_node(struct pci_bus *bus)
{
if (bus->self)
return pci_device_to_OF_node(bus->self);
else
- return bus->sysdata; /* Must be root bus (PHB) */
+ return to_pci_node(bus->sysdata); /* Must be root bus (PHB) */
}

extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
@@ -83,7 +84,7 @@
struct device_node *busdn = bus->sysdata;

BUG_ON(busdn == NULL);
- return busdn->phb;
+ return to_pci_node(busdn)->phb;
}

#endif
Index: linux-2.6-64/include/asm-ppc64/eeh.h
===================================================================
--- linux-2.6-64.orig/include/asm-ppc64/eeh.h 2005-02-01 22:32:12.361104776 +0100
+++ linux-2.6-64/include/asm-ppc64/eeh.h 2005-02-02 00:11:01.487740520 +0100
@@ -27,7 +27,7 @@

struct pci_dev;
struct device_node;
-struct device_node;
+struct pci_device_node;
struct notifier_block;

#ifdef CONFIG_EEH
@@ -40,7 +40,7 @@
void __init eeh_init(void);
unsigned long eeh_check_failure(const volatile void __iomem *token,
unsigned long val);
-int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev);
+int eeh_dn_check_failure(struct pci_device_node *dn, struct pci_dev *dev);
void __init pci_addr_cache_build(void);

/**
@@ -52,7 +52,7 @@
* device (including config space i/o). Call eeh_add_device_late
* to finish the eeh setup for this device.
*/
-void eeh_add_device_early(struct device_node *);
+void eeh_add_device_early(struct pci_device_node *);
void eeh_add_device_late(struct pci_dev *);

/**
Index: linux-2.6-64/arch/ppc64/kernel/sys_ppc32.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/sys_ppc32.c 2005-02-01 22:53:00.673332472 +0100
+++ linux-2.6-64/arch/ppc64/kernel/sys_ppc32.c 2005-02-02 00:11:01.487740520 +0100
@@ -744,7 +744,7 @@
struct pci_controller* hose;
struct list_head *ln;
struct pci_bus *bus = NULL;
- struct device_node *hose_node;
+ struct pci_device_node *hose_node;

/* Argh ! Please forgive me for that hack, but that's the
* simplest way to get existing XFree to not lockup on some
@@ -771,7 +771,7 @@
if (bus == NULL || bus->sysdata == NULL)
return -ENODEV;

- hose_node = (struct device_node *)bus->sysdata;
+ hose_node = to_pci_node(bus->sysdata);
hose = hose_node->phb;

switch (which) {
Index: linux-2.6-64/arch/ppc64/kernel/iommu.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/iommu.c 2005-01-24 23:46:37.000000000 +0100
+++ linux-2.6-64/arch/ppc64/kernel/iommu.c 2005-02-02 00:11:01.488740368 +0100
@@ -432,7 +432,7 @@
return tbl;
}

-void iommu_free_table(struct device_node *dn)
+void iommu_free_table(struct pci_device_node *dn)
{
struct iommu_table *tbl = dn->iommu_table;
unsigned long bitmap_sz, i;
@@ -440,7 +440,7 @@

if (!tbl || !tbl->it_map) {
printk(KERN_ERR "%s: expected TCE map for %s\n", __FUNCTION__,
- dn->full_name);
+ dn->node.full_name);
return;
}

@@ -449,7 +449,7 @@
for (i = 0; i < (tbl->it_size/64); i++) {
if (tbl->it_map[i] != 0) {
printk(KERN_WARNING "%s: Unexpected TCEs for %s\n",
- __FUNCTION__, dn->full_name);
+ __FUNCTION__, dn->node.full_name);
break;
}
}
Index: linux-2.6-64/include/asm-ppc64/iommu.h
===================================================================
--- linux-2.6-64.orig/include/asm-ppc64/iommu.h 2005-01-24 23:47:11.000000000 +0100
+++ linux-2.6-64/include/asm-ppc64/iommu.h 2005-02-02 00:11:01.488740368 +0100
@@ -101,6 +101,7 @@
#endif /* CONFIG_PPC_ISERIES */

struct scatterlist;
+struct pci_device_node;

#ifdef CONFIG_PPC_MULTIPLATFORM

@@ -109,14 +110,14 @@
extern void iommu_setup_u3(void);

/* Frees table for an individual device node */
-extern void iommu_free_table(struct device_node *dn);
+extern void iommu_free_table(struct pci_device_node *dn);

#endif /* CONFIG_PPC_MULTIPLATFORM */

#ifdef CONFIG_PPC_PSERIES

/* Creates table for an individual device node */
-extern void iommu_devnode_init_pSeries(struct device_node *dn);
+extern void iommu_devnode_init_pSeries(struct pci_device_node *dn);

#endif /* CONFIG_PPC_PSERIES */

Index: linux-2.6-64/arch/ppc64/kernel/pci.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/pci.c 2005-01-24 23:46:36.000000000 +0100
+++ linux-2.6-64/arch/ppc64/kernel/pci.c 2005-02-02 00:11:01.489740216 +0100
@@ -447,13 +447,13 @@
static ssize_t pci_show_devspec(struct device *dev, char *buf)
{
struct pci_dev *pdev;
- struct device_node *np;
+ struct pci_device_node *np;

pdev = to_pci_dev (dev);
np = pci_device_to_OF_node(pdev);
- if (np == NULL || np->full_name == NULL)
+ if (np == NULL || np->node.full_name == NULL)
return 0;
- return sprintf(buf, "%s", np->full_name);
+ return sprintf(buf, "%s", np->node.full_name);
}
static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
#endif /* CONFIG_PPC_MULTIPLATFORM */
@@ -734,7 +734,8 @@
*/
int pcibios_scan_all_fns(struct pci_bus *bus, int devfn)
{
- struct device_node *busdn, *dn;
+ struct pci_device_node *busdn;
+ struct device_node *dn;

if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
@@ -749,8 +750,8 @@
* device tree. If they are then we need to scan all the
* functions of this slot.
*/
- for (dn = busdn->child; dn; dn = dn->sibling)
- if ((dn->devfn >> 3) == (devfn >> 3))
+ for (dn = busdn->node.child; dn; dn = dn->sibling)
+ if ((to_pci_node(dn)->devfn >> 3) == (devfn >> 3))
return 1;

return 0;
@@ -851,7 +852,7 @@
int pci_read_irq_line(struct pci_dev *pci_dev)
{
u8 intpin;
- struct device_node *node;
+ struct pci_device_node *node;

pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin);
if (intpin == 0)
@@ -861,10 +862,10 @@
if (node == NULL)
return -1;

- if (node->n_intrs == 0)
+ if (node->node.n_intrs == 0)
return -1;

- pci_dev->irq = node->intrs[0].line;
+ pci_dev->irq = node->node.intrs[0].line;

pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq);

Index: linux-2.6-64/include/asm-ppc64/prom.h
===================================================================
--- linux-2.6-64.orig/include/asm-ppc64/prom.h 2005-02-01 22:32:12.365104168 +0100
+++ linux-2.6-64/include/asm-ppc64/prom.h 2005-02-02 00:11:01.490740064 +0100
@@ -131,15 +131,6 @@
struct interrupt_info *intrs;
char *full_name;

- /* PCI stuff probably doesn't belong here */
- int busno; /* for pci devices */
- int bussubno; /* for pci devices */
- int devfn; /* for pci devices */
- int eeh_mode; /* See eeh.h for possible EEH_MODEs */
- int eeh_config_addr;
- struct pci_controller *phb; /* for pci devices */
- struct iommu_table *iommu_table; /* for phb's or bridges */
-
struct property *properties;
struct device_node *parent;
struct device_node *child;
@@ -153,6 +144,22 @@
unsigned long _flags;
};

+struct pci_device_node {
+ int busno;
+ int bussubno;
+ int devfn;
+ int eeh_mode; /* See eeh.h for possible EEH_MODEs */
+ int eeh_config_addr;
+ struct pci_controller *phb;
+ struct iommu_table *iommu_table; /* for phb's or bridges */
+ struct device_node node;
+};
+
+static inline struct pci_device_node *to_pci_node(struct device_node *n)
+{
+ return n ? container_of(n, struct pci_device_node, node) : NULL;
+}
+
extern struct device_node *of_chosen;

/* flag descriptions */
Index: linux-2.6-64/arch/ppc64/kernel/pci_iommu.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/pci_iommu.c 2005-01-24 23:46:37.000000000 +0100
+++ linux-2.6-64/arch/ppc64/kernel/pci_iommu.c 2005-02-02 00:11:01.490740064 +0100
@@ -48,7 +48,7 @@
* pci_device_to_OF_node since ->sysdata will have been initialised
* in the iommu init code for all devices.
*/
-#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
+#define PCI_GET_DN(dev) (to_pci_node(((dev)->sysdata)))

static inline struct iommu_table *devnode_table(struct pci_dev *dev)
{
Index: linux-2.6-64/arch/ppc64/kernel/pci_dn.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/pci_dn.c 2005-01-24 23:46:37.000000000 +0100
+++ linux-2.6-64/arch/ppc64/kernel/pci_dn.c 2005-02-02 00:11:01.490740064 +0100
@@ -34,13 +34,13 @@
* Traverse_func that inits the PCI fields of the device node.
* NOTE: this *must* be done before read/write config to the device.
*/
-static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
+static void * __devinit update_dn_pci_info(struct pci_device_node *dn, void *data)
{
struct pci_controller *phb = data;
u32 *regs;

dn->phb = phb;
- regs = (u32 *)get_property(dn, "reg", NULL);
+ regs = (u32 *)get_property(&dn->node, "reg", NULL);
if (regs) {
/* First register entry is addr (00BBSS00) */
dn->busno = (regs[0] >> 16) & 0xff;
@@ -67,21 +67,21 @@
* one of these nodes we also assume its siblings are non-pci for
* performance.
*/
-void *traverse_pci_devices(struct device_node *start, traverse_func pre,
+void *traverse_pci_devices(struct pci_device_node *start, traverse_func pre,
void *data)
{
struct device_node *dn, *nextdn;
void *ret;

/* We started with a phb, iterate all childs */
- for (dn = start->child; dn; dn = nextdn) {
+ for (dn = start->node.child; dn; dn = nextdn) {
u32 *classp, class;

nextdn = NULL;
classp = (u32 *)get_property(dn, "class-code", NULL);
class = classp ? *classp : 0;

- if (pre && ((ret = pre(dn, data)) != NULL))
+ if (pre && ((ret = pre(to_pci_node(dn), data)) != NULL))
return ret;

/* If we are a PCI bridge, go down */
@@ -96,7 +96,7 @@
/* Walk up to next valid sibling. */
do {
dn = dn->parent;
- if (dn == start)
+ if (dn == &start->node)
return NULL;
} while (dn->sibling == NULL);
nextdn = dn->sibling;
@@ -107,7 +107,7 @@

void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
{
- struct device_node * dn = (struct device_node *) phb->arch_data;
+ struct pci_device_node *dn = to_pci_node(phb->arch_data);

/* PHB nodes themselves must not match */
dn->devfn = dn->busno = -1;
@@ -121,7 +121,7 @@
* Traversal func that looks for a <busno,devfcn> value.
* If found, the device_node is returned (thus terminating the traversal).
*/
-static void *is_devfn_node(struct device_node *dn, void *data)
+static void *is_devfn_node(struct pci_device_node *dn, void *data)
{
int busno = ((unsigned long)data >> 8) & 0xff;
int devfn = ((unsigned long)data) & 0xff;
@@ -144,13 +144,13 @@
*/
struct device_node *fetch_dev_dn(struct pci_dev *dev)
{
- struct device_node *orig_dn = dev->sysdata;
+ struct pci_device_node *orig_dn = to_pci_node(dev->sysdata);
struct pci_controller *phb = orig_dn->phb; /* assume same phb as orig_dn */
- struct device_node *phb_dn;
+ struct pci_device_node *phb_dn;
struct device_node *dn;
unsigned long searchval = (dev->bus->number << 8) | dev->devfn;

- phb_dn = phb->arch_data;
+ phb_dn = to_pci_node(phb->arch_data);
dn = traverse_pci_devices(phb_dn, is_devfn_node, (void *)searchval);
if (dn)
dev->sysdata = dn;
Index: linux-2.6-64/arch/ppc64/kernel/eeh.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/eeh.c 2005-02-02 00:10:53.126011696 +0100
+++ linux-2.6-64/arch/ppc64/kernel/eeh.c 2005-02-02 00:11:06.039048616 +0100
@@ -254,7 +254,7 @@

static void __pci_addr_cache_insert_device(struct pci_dev *dev)
{
- struct device_node *dn;
+ struct pci_device_node *dn;
int i;
int inserted = 0;

@@ -413,7 +413,7 @@
* @dn: device node to read
* @rets: array to return results in
*/
-static int read_slot_reset_state(struct device_node *dn, int rets[])
+static int read_slot_reset_state(struct pci_device_node *dn, int rets[])
{
int token, outputs;

@@ -528,7 +528,7 @@
*
* It is safe to call this routine in an interrupt context.
*/
-int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
+int eeh_dn_check_failure(struct pci_device_node *dn, struct pci_dev *dev)
{
int ret;
int rets[3];
@@ -603,7 +603,7 @@
spin_unlock_irqrestore(&slot_errbuf_lock, flags);

printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n",
- rets[0], dn->name, dn->full_name);
+ rets[0], dn->node.name, dn->node.full_name);
event = kmalloc(sizeof(*event), GFP_ATOMIC);
if (event == NULL) {
eeh_panic(dev, reset_state);
@@ -611,7 +611,7 @@
}

event->dev = dev;
- event->dn = dn;
+ event->dn = &dn->node;
event->reset_state = reset_state;

/* We may or may not be called in an interrupt context */
@@ -647,7 +647,7 @@
{
unsigned long addr;
struct pci_dev *dev;
- struct device_node *dn;
+ struct pci_device_node *dn;

/* Finding the phys addr + pci device; this is pretty quick. */
addr = eeh_token_to_phys((unsigned long __force) token);
@@ -670,8 +670,9 @@
};

/* Enable eeh for the given device node. */
-static void *early_enable_eeh(struct device_node *dn, void *data)
+static void *early_enable_eeh(struct pci_device_node *pdn, void *data)
{
+ struct device_node *dn = &pdn->node;
struct eeh_early_enable_info *info = data;
int ret;
char *status = get_property(dn, "status", NULL);
@@ -681,7 +682,7 @@
u32 *regs;
int enable;

- dn->eeh_mode = 0;
+ pdn->eeh_mode = 0;

if (status && strcmp(status, "ok") != 0)
return NULL; /* ignore devices with bad status */
@@ -692,7 +693,7 @@

/* There is nothing to check on PCI to ISA bridges */
if (dn->type && !strcmp(dn->type, "isa")) {
- dn->eeh_mode |= EEH_MODE_NOCHECK;
+ pdn->eeh_mode |= EEH_MODE_NOCHECK;
return NULL;
}

@@ -709,7 +710,7 @@
enable = 0;

if (!enable)
- dn->eeh_mode |= EEH_MODE_NOCHECK;
+ pdn->eeh_mode |= EEH_MODE_NOCHECK;

/* Ok... see if this device supports EEH. Some do, some don't,
* and the only way to find out is to check each and every one. */
@@ -722,8 +723,8 @@
EEH_ENABLE);
if (ret == 0) {
eeh_subsystem_enabled = 1;
- dn->eeh_mode |= EEH_MODE_SUPPORTED;
- dn->eeh_config_addr = regs[0];
+ pdn->eeh_mode |= EEH_MODE_SUPPORTED;
+ pdn->eeh_config_addr = regs[0];
#ifdef DEBUG
printk(KERN_DEBUG "EEH: %s: eeh enabled\n", dn->full_name);
#endif
@@ -731,10 +732,12 @@

/* This device doesn't support EEH, but it may have an
* EEH parent, in which case we mark it as supported. */
- if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
+ if (dn->parent && (to_pci_node(dn->parent)->eeh_mode
+ & EEH_MODE_SUPPORTED)) {
/* Parent supports EEH. */
- dn->eeh_mode |= EEH_MODE_SUPPORTED;
- dn->eeh_config_addr = dn->parent->eeh_config_addr;
+ pdn->eeh_mode |= EEH_MODE_SUPPORTED;
+ pdn->eeh_config_addr =
+ to_pci_node(dn->parent)->eeh_config_addr;
return NULL;
}
}
@@ -798,7 +801,7 @@

info.buid_lo = BUID_LO(buid);
info.buid_hi = BUID_HI(buid);
- traverse_pci_devices(phb, early_enable_eeh, &info);
+ traverse_pci_devices(to_pci_node(phb), early_enable_eeh, &info);
}

if (eeh_subsystem_enabled)
@@ -819,7 +822,7 @@
* on the CEC architecture, type of the device, on earlier boot
* command-line arguments & etc.
*/
-void eeh_add_device_early(struct device_node *dn)
+void eeh_add_device_early(struct pci_device_node *dn)
{
struct pci_controller *phb;
struct eeh_early_enable_info info;
Index: linux-2.6-64/arch/ppc64/kernel/prom.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/prom.c 2005-02-02 00:10:53.129011240 +0100
+++ linux-2.6-64/arch/ppc64/kernel/prom.c 2005-02-02 00:11:06.041048312 +0100
@@ -1802,8 +1802,11 @@
*/
static void of_cleanup_node(struct device_node *np)
{
- if (np->iommu_table && get_property(np, "ibm,dma-window", NULL))
- iommu_free_table(np);
+ if (get_property(np, "ibm,dma-window", NULL)) {
+ struct pci_device_node *p = to_pci_node(np);
+ if (p->iommu_table)
+ iommu_free_table(p);
+ }
}

/*
Index: linux-2.6-64/arch/ppc64/kernel/pSeries_pci.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/pSeries_pci.c 2005-02-02 00:10:53.127011544 +0100
+++ linux-2.6-64/arch/ppc64/kernel/pSeries_pci.c 2005-02-02 00:11:06.040048464 +0100
@@ -52,14 +52,12 @@

extern struct mpic *pSeries_mpic;

-static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
+static int rtas_read_config(struct pci_device_node *dn, int where, int size, u32 *val)
{
int returnval = -1;
unsigned long buid, addr;
int ret;

- if (!dn)
- return PCIBIOS_DEVICE_NOT_FOUND;
if (where & (size - 1))
return PCIBIOS_BAD_REGISTER_NUMBER;

@@ -87,7 +85,8 @@
unsigned int devfn,
int where, int size, u32 *val)
{
- struct device_node *busdn, *dn;
+ struct pci_device_node *busdn;
+ struct device_node *dn;

if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
@@ -95,13 +94,15 @@
busdn = bus->sysdata; /* must be a phb */

/* Search only direct children of the bus */
- for (dn = busdn->child; dn; dn = dn->sibling)
- if (dn->devfn == devfn)
- return rtas_read_config(dn, where, size, val);
+ for (dn = busdn->node.child; dn; dn = dn->sibling) {
+ struct pci_device_node *pdn = to_pci_node(dn);
+ if (pdn->devfn == devfn)
+ return rtas_read_config(pdn, where, size, val);
+ }
return PCIBIOS_DEVICE_NOT_FOUND;
}

-static int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
+static int rtas_write_config(struct pci_device_node *dn, int where, int size, u32 val)
{
unsigned long buid, addr;
int ret;
@@ -129,7 +130,8 @@
unsigned int devfn,
int where, int size, u32 val)
{
- struct device_node *busdn, *dn;
+ struct pci_device_node *busdn;
+ struct device_node *dn;

if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
@@ -137,9 +139,11 @@
busdn = bus->sysdata; /* must be a phb */

/* Search only direct children of the bus */
- for (dn = busdn->child; dn; dn = dn->sibling)
- if (dn->devfn == devfn)
- return rtas_write_config(dn, where, size, val);
+ for (dn = busdn->node.child; dn; dn = dn->sibling) {
+ struct pci_device_node *pdn = to_pci_node(dn);
+ if (pdn->devfn == devfn)
+ return rtas_write_config(pdn, where, size, val);
+ }
return PCIBIOS_DEVICE_NOT_FOUND;
}



Attachments:
(No filename) (24.02 kB)
(No filename) (189.00 B)
signature
Download all attachments

2005-02-03 01:14:10

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: pci: Arch hook to determine config space size

On Wed, 2005-02-02 at 11:05 +0100, Arnd Bergmann wrote:

> How about something along the lines of this patch? Instead of adding a
> pointer to the pci data from the device node, it embeds the node inside
> a new struct pci_device_node. The patch is not complete and therefore
> not expected to work as is, but maybe you want to reuse it.
>
> The interesting part that is missing is creating and destroying
> pci_device_nodes in prom.c, maybe you have an idea how to do that.
>
> I'm also not sure about eeh. Are the eeh functions known to be called
> only for device_nodes of PCI devices? If not, eeh_mode and
> eeh_config_addr might have to stay inside of device_node.

I'd rather not go that way for now. There are at least PCI and VIO
devices concerned by this, and maybe more (depending on how I deal
with macio devices for example). We also want, ultimately, to have
the DMA routines be function pointers in this auxilliary structure.

Ben.