diff mbox

[v2,18/27] arm: plat-orion: add more flexible PCI configuration space read/write functions

Message ID 1359399397-29729-19-git-send-email-thomas.petazzoni@free-electrons.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Thomas Petazzoni Jan. 28, 2013, 6:56 p.m. UTC
The existing orion_pcie_rd_conf() and orion_pcie_wr_conf() functions
provided by plat-orion/pcie.c are nice to read and write the PCI
configuration space of a device, but they unfortunately assume that
the bus number and slot number at which a device is visible at the
Linux software level is the same as the bus number and slot number at
the hardware level.

However, with the usage of the emulated PCI host bridge and emulated
PCI-to-PCI bridges, this is not the case: bus number 0 is the emulated
bus on which the emulated PCI-to-PCI bridges sit, so from the Linux
point of view, the real busses start at bus 1, but from a hardware
point of view, they start at bus 0.

So, we cannot use the existing orion_pcie_rd_conf() and
orion_pcie_wr_conf() implementations, which take their bus number
directly from a given pci_bus structure. Instead, we add lower-level
variants, orion_pcie_rd_conf_bus() and orion_pcie_wr_conf_bus() that
take a bus number as argument. The existing orion_pcie_rd_conf() and
orion_pcie_wr_conf() functions are implemented on top of the new
*_bus() variants.

Those *_bus() variants will be used by the Marvell Armada 370/XP PCIe
driver.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 arch/arm/plat-orion/include/plat/pcie.h |    4 ++++
 arch/arm/plat-orion/pcie.c              |   26 ++++++++++++++++++++------
 2 files changed, 24 insertions(+), 6 deletions(-)

Comments

Jason Gunthorpe Jan. 28, 2013, 7:51 p.m. UTC | #1
On Mon, Jan 28, 2013 at 07:56:27PM +0100, Thomas Petazzoni wrote:

> However, with the usage of the emulated PCI host bridge and emulated
> PCI-to-PCI bridges, this is not the case: bus number 0 is the emulated
> bus on which the emulated PCI-to-PCI bridges sit, so from the Linux
> point of view, the real busses start at bus 1, but from a hardware
> point of view, they start at bus 0.

Hum.. This is a bit funny sounding, can you confirm..

The bus number programmed into all the end points must match the Linux
number. Ie the PCI-E Link Description register of end point devices
must report the same bus number as Linux. PCI-E devices learn their
bus number by capturing the bus number from type 0 configuration
transactions.

For the most part config transactions issued to the PCI-E controllers
should be type 0 transactions with a bus number that matches what
Linux is setting.

The only time I think you'd ever see bus number 0 is when accessing
the config space of the Marvell PCI-E controller end port. But, I also
think you can avoid doing these transactions by just accessing the MMIO
versions of those registers..

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Petazzoni Jan. 29, 2013, 8:40 a.m. UTC | #2
Dear Jason Gunthorpe,

On Mon, 28 Jan 2013 12:51:11 -0700, Jason Gunthorpe wrote:
> On Mon, Jan 28, 2013 at 07:56:27PM +0100, Thomas Petazzoni wrote:
> 
> > However, with the usage of the emulated PCI host bridge and emulated
> > PCI-to-PCI bridges, this is not the case: bus number 0 is the emulated
> > bus on which the emulated PCI-to-PCI bridges sit, so from the Linux
> > point of view, the real busses start at bus 1, but from a hardware
> > point of view, they start at bus 0.
> 
> Hum.. This is a bit funny sounding, can you confirm..

Might be yes, but IIRC, when I try to enumerate the devices in the PCIe
interface 0 (from a hardware point of view), passing a bus number of 1
in the PCI configuration space access registers, then it simply doesn't
work.

> The bus number programmed into all the end points must match the Linux
> number. Ie the PCI-E Link Description register of end point devices

What is this PCI-E Link Description register ? Where is it located ?

Thanks,

Thomas
Jason Gunthorpe Jan. 29, 2013, 5:40 p.m. UTC | #3
On Tue, Jan 29, 2013 at 09:40:03AM +0100, Thomas Petazzoni wrote:
> Dear Jason Gunthorpe,
> 
> On Mon, 28 Jan 2013 12:51:11 -0700, Jason Gunthorpe wrote:
> > On Mon, Jan 28, 2013 at 07:56:27PM +0100, Thomas Petazzoni wrote:
> > 
> > > However, with the usage of the emulated PCI host bridge and emulated
> > > PCI-to-PCI bridges, this is not the case: bus number 0 is the emulated
> > > bus on which the emulated PCI-to-PCI bridges sit, so from the Linux
> > > point of view, the real busses start at bus 1, but from a hardware
> > > point of view, they start at bus 0.
> > 
> > Hum.. This is a bit funny sounding, can you confirm..
> 
> Might be yes, but IIRC, when I try to enumerate the devices in the PCIe
> interface 0 (from a hardware point of view), passing a bus number of 1
> in the PCI configuration space access registers, then it simply doesn't
> work.

Hurm. The trick is you need the chip to issue a type 0 request. The
Marvell docs say this happens automatically basd on the 'internal bus
number'

The only other reference to bus number is in the PCI Express Status
Register (41A04), so that probably needs to be set to the subordinate
bus number of the bridge.

> > The bus number programmed into all the end points must match the Linux
> > number. Ie the PCI-E Link Description register of end point devices
> 
> What is this PCI-E Link Description register ? Where is it located ?

Hum, looks like this is only for root complex links not end devices -
PCI-X had a register for this but it seems to have been removed in
PCI-E.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/plat-orion/include/plat/pcie.h b/arch/arm/plat-orion/include/plat/pcie.h
index fe5b9e8..46974c1 100644
--- a/arch/arm/plat-orion/include/plat/pcie.h
+++ b/arch/arm/plat-orion/include/plat/pcie.h
@@ -21,12 +21,16 @@  int orion_pcie_get_local_bus_nr(void __iomem *base);
 void orion_pcie_set_local_bus_nr(void __iomem *base, int nr);
 void orion_pcie_reset(void __iomem *base);
 void orion_pcie_setup(void __iomem *base);
+int orion_pcie_rd_conf_bus(void __iomem *base, u32 busn,
+			   u32 devfn, int where, int size, u32 *val);
 int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
 		       u32 devfn, int where, int size, u32 *val);
 int orion_pcie_rd_conf_tlp(void __iomem *base, struct pci_bus *bus,
 			   u32 devfn, int where, int size, u32 *val);
 int orion_pcie_rd_conf_wa(void __iomem *wa_base, struct pci_bus *bus,
 			  u32 devfn, int where, int size, u32 *val);
+int orion_pcie_wr_conf_bus(void __iomem *base, u32 busn,
+			   u32 devfn, int where, int size, u32 val);
 int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
 		       u32 devfn, int where, int size, u32 val);
 
diff --git a/arch/arm/plat-orion/pcie.c b/arch/arm/plat-orion/pcie.c
index f20a321..0e85bdd 100644
--- a/arch/arm/plat-orion/pcie.c
+++ b/arch/arm/plat-orion/pcie.c
@@ -203,10 +203,10 @@  void __init orion_pcie_setup(void __iomem *base)
 	writel(mask, base + PCIE_MASK_OFF);
 }
 
-int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
-		       u32 devfn, int where, int size, u32 *val)
+int orion_pcie_rd_conf_bus(void __iomem *base, u32 busn, u32 devfn,
+			   int where, int size, u32 *val)
 {
-	writel(PCIE_CONF_BUS(bus->number) |
+	writel(PCIE_CONF_BUS(busn) |
 		PCIE_CONF_DEV(PCI_SLOT(devfn)) |
 		PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
 		PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
@@ -222,6 +222,13 @@  int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
 	return PCIBIOS_SUCCESSFUL;
 }
 
+int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
+		       u32 devfn, int where, int size, u32 *val)
+{
+	return orion_pcie_rd_conf_bus(base, bus->number, devfn,
+				      where, size, val);
+}
+
 int orion_pcie_rd_conf_tlp(void __iomem *base, struct pci_bus *bus,
 			   u32 devfn, int where, int size, u32 *val)
 {
@@ -261,12 +268,12 @@  int orion_pcie_rd_conf_wa(void __iomem *wa_base, struct pci_bus *bus,
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
-		       u32 devfn, int where, int size, u32 val)
+int orion_pcie_wr_conf_bus(void __iomem *base, u32 busn,
+			   u32 devfn, int where, int size, u32 val)
 {
 	int ret = PCIBIOS_SUCCESSFUL;
 
-	writel(PCIE_CONF_BUS(bus->number) |
+	writel(PCIE_CONF_BUS(busn) |
 		PCIE_CONF_DEV(PCI_SLOT(devfn)) |
 		PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
 		PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
@@ -284,3 +291,10 @@  int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
 
 	return ret;
 }
+
+int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
+		       u32 devfn, int where, int size, u32 val)
+{
+	return orion_pcie_wr_conf_bus(base, bus->number, devfn,
+				      where, size, val);
+}