Skip to contentSkip to conversation

R-Car Gen2 PCIe host driver

PATCH Superseded Phil Edworthy 4 participants 27 messages Mar 31, 2014 – May 6, 2014

Subsystems (8)

v7 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v7 cover R-Car Gen2 PCIe host driver

This is version 7 of a PCIe Host driver for the R-Car Gen2 devices, i.e. R-Car H2 (r8a7790) and R-Car M2 (r8a7791).

v7:
- Change binding description of clocks to 'clock specifiers'

v6:
- Correct DT bindings description for reg and clocks
- Split device and board DT changes
- Add shmobile to subject for shmobile DT patches
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line
- Remove patch that adds HAVE_ARM_ARCH_TIMER to koelsch defconfig as not needed

v5:
- Use module_platform_driver instead of subsys_initcall
- Use the of_device_id data field for HW init function
- Init hw_pci struct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources
- Return IRQ_NONE from MSI isr when there is no pending MSI
- Add additional interrupt bindings

v4:
- Use runtime PM properly

Phil Edworthy (10):
PCI: host: rcar: Add Renesas R-Car PCIe driver
PCI: host: rcar: Add MSI support
ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
dt-bindings: pci: rcar pcie device tree bindings
ARM: shmobile: r8a7790: Add PCIe device nodes
ARM: shmobile: lager: Add PCIe device nodes
ARM: shmobile: r8a7791: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe to defconfig

 Documentation/devicetree/bindings/pci/rcar-pci.txt |  45 +
 arch/arm/boot/dts/r8a7790-lager.dts                |  10 +
 arch/arm/boot/dts/r8a7790.dtsi                     |  31 +-
 arch/arm/boot/dts/r8a7791-koelsch.dts              |  14 +
 arch/arm/boot/dts/r8a7791.dtsi                     |  31 +-
 arch/arm/configs/koelsch_defconfig                 |   3 +
 drivers/pci/host/Kconfig                           |   6 +
 drivers/pci/host/Makefile                          |   1 +
 drivers/pci/host/pcie-rcar.c                       | 929 +++++++++++++++++++++
 drivers/pci/host/pcie-rcar.h                       |  87 ++
 include/dt-bindings/clock/r8a7790-clock.h          |   1 +
 include/dt-bindings/clock/r8a7791-clock.h          |   1 +
 12 files changed, 1154 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txt
 create mode 100644 drivers/pci/host/pcie-rcar.c
 create mode 100644 drivers/pci/host/pcie-rcar.h
Signature · 1 line
1.9.0
#1 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.

v5:
- Use module_platform_driver instead of subsys_initcall
- Use the of_device_id data field for HW init function
- Init hw_pci struct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources

v4:
- Use runtime PM properly

v3:
- Add DT support
- Use 'of_irq_parse_and_map_pci' for '.map_irq'
- Use pm ops to enable clocks
- Fix checkpatch errors
- Use subsys_initcall to overcome issues with port bus driver
- Adjust Kconfig to match other R-Car drivers

v2:
- Use msleep instead of udelay when waiting for the link
- Use pm_runtime
- Removed unused definition
- Also replaced call to devm_request_and_ioremap with devm_ioremap_resource and fixed a bug with this when reporting errors.

---
 drivers/pci/host/Kconfig     |   6 +
 drivers/pci/host/Makefile    |   1 +
 drivers/pci/host/pcie-rcar.c | 693 +++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/host/pcie-rcar.h |  82 +++++
 4 files changed, 782 insertions(+)
 create mode 100644 drivers/pci/host/pcie-rcar.c
 create mode 100644 drivers/pci/host/pcie-rcar.h
drivers/pci/host/Kconfig +6 -0
index 47d46c6..dc627e5 100644
@@ -33,4 +33,10 @@ config PCI_RCAR_GEN2
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
 
+config PCI_RCAR_GEN2_PCIE
+	bool "Renesas R-Car PCIe controller"
+	depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
+	help
+	  Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
+
 endmenu
drivers/pci/host/Makefile +1 -0
index 13fb333..19946f9 100644
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
+obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
drivers/pci/host/pcie-rcar.c new file +693 -0

693 lines not on this page · raw message

drivers/pci/host/pcie-rcar.h new file +82 -0

82 lines not on this page · raw message

Signature · 1 line
1.9.0
maintainer
#2 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

drivers/pci/host/pcie-rcar.c line 27

Quoted 12 lines · Phil Edworthy

This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.

...

drivers/pci/host/pcie-rcar.c new file +2 -0
@@ -0,0 +1,693 @@
...
+#include <linux/slab.h>
+#include "pcie-rcar.h"

It looks like the things in pcie-rcar.h are used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have a pcie-rcar.h at all. Of course, if there are things needed by more than one file, they should stay in pcie-rcar.h.

Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10 -0
+#define DRV_NAME "rcar-pcie"
+
+#define RCONF(x)	(PCICONF(0)+(x))
+#define RPMCAP(x)	(PMCAP(0)+(x))
+#define REXPCAP(x)	(EXPCAP(0)+(x))
+#define RVCCAP(x)	(VCCAP(0)+(x))
+
+#define  PCIE_CONF_BUS(b)	(((b) & 0xff) << 24)
+#define  PCIE_CONF_DEV(d)	(((d) & 0x1f) << 19)
+#define  PCIE_CONF_FUNC(f)	(((f) & 0x7) << 16)

drivers/pci/host/pcie-rcar.c line 48

Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10 -0
+
+#define PCI_MAX_RESOURCES 4
+#define MAX_NR_INBOUND_MAPS 6
+
+/* Structure representing the PCIe interface */
+struct rcar_pcie {
+	struct device		*dev;
+	void __iomem		*base;
+	struct resource		res[PCI_MAX_RESOURCES];
+	u8			root_bus_nr;

I don't understand how root_bus_nr works. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge. That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But root_bus_nr comes from sys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.

drivers/pci/host/pcie-rcar.c line 59

Quoted 11 lines
drivers/pci/host/pcie-rcar.c new file +11 -0
+	struct clk		*clk;
+	struct clk		*bus_clk;
+};
+
+static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static void
+pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned long reg)

Use this indentation style:

static void pci_write_reg(struct rcar_pcie *pcie, unsigned long val,

and wrap the args as necessary (as you already did with rcar_pcie_read_conf() below).

Quoted 7 lines
drivers/pci/host/pcie-rcar.c new file +7 -0
+{
+	writel(val, pcie->base + reg);
+}
+
+static unsigned long
+pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
+{

drivers/pci/host/pcie-rcar.c line 76

Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10 -0
+	return readl(pcie->base + reg);
+}
+
+enum {
+	PCI_ACCESS_READ,
+	PCI_ACCESS_WRITE,
+};
+
+static void rcar_rmw32(struct rcar_pcie *pcie,
+			    int where, u32 mask, u32 data)

No wrapping necessary here.

drivers/pci/host/pcie-rcar.c line 79

Quoted 3 lines
drivers/pci/host/pcie-rcar.c new file +3 -0
+{
+	int shift = 8 * (where & 3);
+	u32 val = pci_read_reg(pcie, where & ~3);

A blank line is typical here (after the local variables).

drivers/pci/host/pcie-rcar.c line 88

Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9 -0
+	val &= ~(mask << shift);
+	val |= data << shift;
+	pci_write_reg(pcie, val, where & ~3);
+}
+
+static u32 rcar_read_conf(struct rcar_pcie *pcie, int where)
+{
+	int shift = 8 * (where & 3);
+	u32 val = pci_read_reg(pcie, where & ~3);

And here.

Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +6 -0
+	return val >> shift;
+}
+
+static int rcar_pcie_config_access(struct rcar_pcie *pcie,
+		unsigned char access_type, struct pci_bus *bus,
+		unsigned int devfn, int where, u32 *data)

drivers/pci/host/pcie-rcar.c line 104

Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10 -0
+{
+	int dev, func, reg, index;
+
+	dev = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+	reg = where & ~3;
+	index = reg / 4;
+
+	if (bus->number > 255 || dev > 31 || func > 7)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;

I do see one other place in the tree (sh7786_pcie_config_access()) where we test all these, but I don't think it's really necessary. It's actually impossible to satisfy this condition, given the definitions of bus->number, PCI_SLOT(), and PCI_FUNC().

Quoted 20 lines

...

drivers/pci/host/pcie-rcar.c new file +19 -0
+	/* Clear errors */
+	pci_write_reg(pcie, pci_read_reg(pcie, PCIEERRFR), PCIEERRFR);
+
+	/* Set the PIO address */
+	pci_write_reg(pcie, PCIE_CONF_BUS(bus->number) | PCIE_CONF_DEV(dev) |
+				PCIE_CONF_FUNC(func) | reg, PCIECAR);
+
+	/* Enable the configuration access */
+	if (bus->parent->number == pcie->root_bus_nr)
+		pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0, PCIECCTLR);
+	else
+		pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1, PCIECCTLR);
+
+	/* Check for errors */
+	if (pci_read_reg(pcie, PCIEERRFR) & UNSUPPORTED_REQUEST)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* Check for master and target aborts */
+	if (rcar_read_conf(pcie, RCONF(PCI_STATUS)) &

drivers/pci/host/pcie-rcar.c line 161

Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10 -0
+		(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (access_type == PCI_ACCESS_READ)
+		*data = pci_read_reg(pcie, PCIECDR);
+	else
+		pci_write_reg(pcie, *data, PCIECDR);
+
+	/* Disable the configuration access */
+	pci_write_reg(pcie, 0, PCIECCTLR);

It looks like the above all needs to be atomic, so I suppose you're relying on higher-level locking to ensure that. It might be worth a mention of the lock you rely on, just in case that ever changes (I doubt it would, but it's conceivable).

Quoted 19 lines

...

drivers/pci/host/pcie-rcar.c new file +18 -0
+static int rcar_pcie_setup_window(int win, struct resource *res,
+					struct rcar_pcie *pcie)
+{
+	/* Setup PCIe address space mappings for each resource */
+	resource_size_t size;
+	u32 mask;
+
+	pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win));
+
+	/*
+	 * The PAMR mask is calculated in units of 128Bytes, which
+	 * keeps things pretty simple.
+	 */
+	size = resource_size(res);
+	mask = (roundup_pow_of_two(size) / SZ_128) - 1;
+	pci_write_reg(pcie, mask << 7, PCIEPAMR(win));
+
+	pci_write_reg(pcie, upper_32_bits(res->start), PCIEPARH(win));

drivers/pci/host/pcie-rcar.c line 266

Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10 -0
+	pci_write_reg(pcie, lower_32_bits(res->start), PCIEPARL(win));
+
+	/* First resource is for IO */
+	mask = PAR_ENABLE;
+	if (res->flags & IORESOURCE_IO)
+		mask |= IO_SPACE;
+
+	pci_write_reg(pcie, mask, PCIEPTCTLR(win));
+
+	return 0;

Maybe could be a void function, since no error is possible?

drivers/pci/host/pcie-rcar.c line 472

Quoted 10 lines

...

drivers/pci/host/pcie-rcar.c new file +9 -0
+static int __init rcar_pcie_get_resources(struct platform_device *pdev,
+	struct rcar_pcie *pcie)
+{
+	struct resource res;
+	int err;
+
+	err = of_address_to_resource(pdev->dev.of_node, 0, &res);
+	if (err)
+		return err;

I don't see anywhere that figures out the bus number range behind this host bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.

For new code, we should be explicit about the range.

Bjorn

#3 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Hi Bjorn,

Thanks for the review.

Quoted 7 lines · Bjorn
Quoted 5 lines · Phil Edworthy

This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.

...

Quoted 11 lines

drivers/pci/host/pcie-rcar.c line 27

Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +2 -0
@@ -0,0 +1,693 @@
...
+#include <linux/slab.h>
+#include "pcie-rcar.h"

It looks like the things in pcie-rcar.h are used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have a pcie-rcar.h at all. Of course, if there are things needed by more than one file, they should stay in pcie-rcar.h.

Nothing else uses them so I'll put in the c file.

Quoted 16 lines
Quoted 16 lines
drivers/pci/host/pcie-rcar.c new file +16 -0
+#define DRV_NAME "rcar-pcie"
+
+#define RCONF(x)	(PCICONF(0)+(x))
+#define RPMCAP(x)	(PMCAP(0)+(x))
+#define REXPCAP(x)	(EXPCAP(0)+(x))
+#define RVCCAP(x)	(VCCAP(0)+(x))
+
+#define  PCIE_CONF_BUS(b)	(((b) & 0xff) << 24)
+#define  PCIE_CONF_DEV(d)	(((d) & 0x1f) << 19)
+#define  PCIE_CONF_FUNC(f)	(((f) & 0x7) << 16)
+
+#define PCI_MAX_RESOURCES 4
+#define MAX_NR_INBOUND_MAPS 6
+
+/* Structure representing the PCIe interface */
+struct rcar_pcie {
Quoted 8 lines

drivers/pci/host/pcie-rcar.c line 48

Quoted 4 lines
drivers/pci/host/pcie-rcar.c new file +4 -0
+	struct device		*dev;
+	void __iomem		*base;
+	struct resource		res[PCI_MAX_RESOURCES];
+	u8			root_bus_nr;

I don't understand how root_bus_nr works. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge.

That's correct.

Quoted 4 lines

That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But root_bus_nr comes from sys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.

The manual for this hardware says that the HW doesn't care what the bus number is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we use root_bus_nr to determine this. The generic code that sets up sys->busnr (ARM bios32 in this case), just increments bus number for each controller.

This is very similar to the pcie-designware driver, in dw_pcie_scan_bus().

Quoted 13 lines

drivers/pci/host/pcie-rcar.c

Quoted 11 lines
drivers/pci/host/pcie-rcar.c new file +11 -0
+	struct clk		*clk;
+	struct clk		*bus_clk;
+};
+
+static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static void
+pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned long

reg)

Quoted 6 lines

Use this indentation style:

static void pci_write_reg(struct rcar_pcie *pcie, unsigned long val,

and wrap the args as necessary (as you already did with rcar_pcie_read_conf() below).

Ok

Quoted 11 lines
Quoted 11 lines
drivers/pci/host/pcie-rcar.c new file +11 -0
+{
+	writel(val, pcie->base + reg);
+}
+
+static unsigned long
+pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
+{
+	return readl(pcie->base + reg);
+}
+
+enum {
Quoted 8 lines

drivers/pci/host/pcie-rcar.c line 76

Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +6 -0
+	PCI_ACCESS_READ,
+	PCI_ACCESS_WRITE,
+};
+
+static void rcar_rmw32(struct rcar_pcie *pcie,
+			    int where, u32 mask, u32 data)

No wrapping necessary here.

Sure

Quoted 5 lines

drivers/pci/host/pcie-rcar.c line 79

Quoted 3 lines
drivers/pci/host/pcie-rcar.c new file +3 -0
+{
+	int shift = 8 * (where & 3);
+	u32 val = pci_read_reg(pcie, where & ~3);

A blank line is typical here (after the local variables).

Ok

Quoted 11 lines

drivers/pci/host/pcie-rcar.c line 88

Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9 -0
+	val &= ~(mask << shift);
+	val |= data << shift;
+	pci_write_reg(pcie, val, where & ~3);
+}
+
+static u32 rcar_read_conf(struct rcar_pcie *pcie, int where)
+{
+	int shift = 8 * (where & 3);
+	u32 val = pci_read_reg(pcie, where & ~3);

And here.

Ok

Quoted 13 lines
Quoted 13 lines
drivers/pci/host/pcie-rcar.c new file +13 -0
+	return val >> shift;
+}
+
+static int rcar_pcie_config_access(struct rcar_pcie *pcie,
+		unsigned char access_type, struct pci_bus *bus,
+		unsigned int devfn, int where, u32 *data)
+{
+	int dev, func, reg, index;
+
+	dev = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+	reg = where & ~3;
+	index = reg / 4;
Quoted 8 lines

drivers/pci/host/pcie-rcar.c line 104

Quoted 3 lines
drivers/pci/host/pcie-rcar.c new file +3 -0
+
+	if (bus->number > 255 || dev > 31 || func > 7)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;

I do see one other place in the tree (sh7786_pcie_config_access()) where we test all these, but I don't think it's really necessary. It's actually impossible to satisfy this condition, given the definitions of bus->number, PCI_SLOT(), and PCI_FUNC().

Ok, I'll remove them. They were simply copied over from the sh7786 driver.

Quoted 25 lines

drivers/pci/host/pcie-rcar.c

Quoted 6 lines

...

drivers/pci/host/pcie-rcar.c new file +5 -0
+	/* Clear errors */
+	pci_write_reg(pcie, pci_read_reg(pcie, PCIEERRFR), PCIEERRFR);
+
+	/* Set the PIO address */
+	pci_write_reg(pcie, PCIE_CONF_BUS(bus->number) |

PCIE_CONF_DEV(dev) |

drivers/pci/host/pcie-rcar.c

Quoted 5 lines
drivers/pci/host/pcie-rcar.c new file +5 -0
+				PCIE_CONF_FUNC(func) | reg, PCIECAR);
+
+	/* Enable the configuration access */
+	if (bus->parent->number == pcie->root_bus_nr)
+		pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0,

PCIECCTLR);

drivers/pci/host/pcie-rcar.c

Quoted 2 lines
drivers/pci/host/pcie-rcar.c new file +2 -0
+	else
+		pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1,

PCIECCTLR);

drivers/pci/host/pcie-rcar.c

Quoted 8 lines
drivers/pci/host/pcie-rcar.c new file +8 -0
+
+	/* Check for errors */
+	if (pci_read_reg(pcie, PCIEERRFR) & UNSUPPORTED_REQUEST)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* Check for master and target aborts */
+	if (rcar_read_conf(pcie, RCONF(PCI_STATUS)) &
+		(PCI_STATUS_REC_MASTER_ABORT |

PCI_STATUS_REC_TARGET_ABORT))

Quoted 14 lines

drivers/pci/host/pcie-rcar.c line 161

Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9 -0
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (access_type == PCI_ACCESS_READ)
+		*data = pci_read_reg(pcie, PCIECDR);
+	else
+		pci_write_reg(pcie, *data, PCIECDR);
+
+	/* Disable the configuration access */
+	pci_write_reg(pcie, 0, PCIECCTLR);

It looks like the above all needs to be atomic, so I suppose you're relying on higher-level locking to ensure that. It might be worth a mention of the lock you rely on, just in case that ever changes (I doubt it would, but it's conceivable).

Yes, the locking is done at a higher level; I'll add comment for this.

Quoted 23 lines
Quoted 23 lines

...

drivers/pci/host/pcie-rcar.c new file +22 -0
+static int rcar_pcie_setup_window(int win, struct resource *res,
+					struct rcar_pcie *pcie)
+{
+	/* Setup PCIe address space mappings for each resource */
+	resource_size_t size;
+	u32 mask;
+
+	pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win));
+
+	/*
+	 * The PAMR mask is calculated in units of 128Bytes, which
+	 * keeps things pretty simple.
+	 */
+	size = resource_size(res);
+	mask = (roundup_pow_of_two(size) / SZ_128) - 1;
+	pci_write_reg(pcie, mask << 7, PCIEPAMR(win));
+
+	pci_write_reg(pcie, upper_32_bits(res->start), PCIEPARH(win));
+	pci_write_reg(pcie, lower_32_bits(res->start), PCIEPARL(win));
+
+	/* First resource is for IO */
+	mask = PAR_ENABLE;
Quoted 8 lines

drivers/pci/host/pcie-rcar.c line 266

Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +6 -0
+	if (res->flags & IORESOURCE_IO)
+		mask |= IO_SPACE;
+
+	pci_write_reg(pcie, mask, PCIEPTCTLR(win));
+
+	return 0;

Maybe could be a void function, since no error is possible?

Sure

Quoted 16 lines

drivers/pci/host/pcie-rcar.c line 472

Quoted 10 lines

...

drivers/pci/host/pcie-rcar.c new file +9 -0
+static int __init rcar_pcie_get_resources(struct platform_device *pdev,
+	struct rcar_pcie *pcie)
+{
+	struct resource res;
+	int err;
+
+	err = of_address_to_resource(pdev->dev.of_node, 0, &res);
+	if (err)
+		return err;

I don't see anywhere that figures out the bus number range behind this host bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.

Quoted 1 line

For new code, we should be explicit about the range.

This means add a DT entry for bus-range, and simply calling pci_add_resource for the range, right? If so, ok.

Thanks
Phil

maintainer
#4 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Quoted 55 lines · Phil Edworthy

Hi Bjorn,

Thanks for the review.

Quoted 7 lines · Bjorn
Quoted 5 lines · Phil Edworthy

This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.

...

Quoted 11 lines

drivers/pci/host/pcie-rcar.c line 27

Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +2 -0
@@ -0,0 +1,693 @@
...
+#include <linux/slab.h>
+#include "pcie-rcar.h"

It looks like the things in pcie-rcar.h are used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have a pcie-rcar.h at all. Of course, if there are things needed by more than one file, they should stay in pcie-rcar.h.

Nothing else uses them so I'll put in the c file.

Quoted 16 lines
Quoted 16 lines
drivers/pci/host/pcie-rcar.c new file +16 -0
+#define DRV_NAME "rcar-pcie"
+
+#define RCONF(x)   (PCICONF(0)+(x))
+#define RPMCAP(x)  (PMCAP(0)+(x))
+#define REXPCAP(x) (EXPCAP(0)+(x))
+#define RVCCAP(x)  (VCCAP(0)+(x))
+
+#define  PCIE_CONF_BUS(b)  (((b) & 0xff) << 24)
+#define  PCIE_CONF_DEV(d)  (((d) & 0x1f) << 19)
+#define  PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
+
+#define PCI_MAX_RESOURCES 4
+#define MAX_NR_INBOUND_MAPS 6
+
+/* Structure representing the PCIe interface */
+struct rcar_pcie {
Quoted 8 lines

drivers/pci/host/pcie-rcar.c line 48

Quoted 4 lines
drivers/pci/host/pcie-rcar.c new file +4 -0
+   struct device           *dev;
+   void __iomem            *base;
+   struct resource         res[PCI_MAX_RESOURCES];
+   u8                      root_bus_nr;

I don't understand how root_bus_nr works. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge.

That's correct.

Quoted 4 lines

That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But root_bus_nr comes from sys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.

Quoted 7 lines

The manual for this hardware says that the HW doesn't care what the bus number is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we use root_bus_nr to determine this. The generic code that sets up sys->busnr (ARM bios32 in this case), just increments bus number for each controller.

This is very similar to the pcie-designware driver, in dw_pcie_scan_bus().

OK. From what you said below, it sounds like you would add a DT entry for the bus range you want to have below this bridge, and use TYPE0 accesses for the base of that range.

I'm not sure how you reconcile this with the idea that the bios32 code just increments a bus number for each controller.

Quoted 15 lines
Quoted 15 lines

drivers/pci/host/pcie-rcar.c line 472

Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9 -0
+static int __init rcar_pcie_get_resources(struct platform_device *pdev,
+   struct rcar_pcie *pcie)
+{
+   struct resource res;
+   int err;
+
+   err = of_address_to_resource(pdev->dev.of_node, 0, &res);
+   if (err)
+           return err;

I don't see anywhere that figures out the bus number range behind this host bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.

Quoted 3 lines
Quoted 1 line

For new code, we should be explicit about the range.

This means add a DT entry for bus-range, and simply calling pci_add_resource for the range, right? If so, ok.

Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.

Bjorn

#5 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Quoted 10 lines · Bjorn Helgaas
Quoted 10 lines
Quoted 4 lines

That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But root_bus_nr comes from sys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.

The manual for this hardware says that the HW doesn't care what the bus number is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we use root_bus_nr to determine this. The generic code that sets up sys->busnr (ARM bios32 in this case), just increments bus number for each controller.

I went back and looked at the lspci posted for this hardware and this use of busnr is kinda sketch..

You should use use bus 0 as the root complex integrated bus number and ensure every instance of your driver creates a new PCI domain, and generally use 0-> FF as the subordinate bus number range.

FWIW, your HW does care, and does have a programmable field for this.

You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:

root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])

        Bus: primary=00, secondary=01, subordinate=01, sec-latency=0

The value here will be also be exported on-the-wire in certain PCI-E TLPs.

So it is important, and must be set properly.

Quoted 3 lines

Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.

This is where some of the other implementations have used some SW to route config space in a single domain to the proper controller per-port register set.

But, IMHO, that is mainly worth doing if the HW can implement the PCI bridge windows according to the spec, and it looks like rcar requires a 128MB alignment on the bridge windows, which makes it fairly pointless.

Jason

#6 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Hi Jason,

Quoted 35 lines · Jason
Quoted 3 lines · Bjorn Helgaas
Quoted 3 lines
Quoted 3 lines

That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But root_bus_nr comes from sys->busnr, which is apparently from

some

Quoted 3 lines
Quoted 3 lines
Quoted 1 line

generic code that knows nothing about this particular host bridge.

The manual for this hardware says that the HW doesn't care what the bus

number

Quoted 1 line
Quoted 1 line

is set to. The only thing the HW needs to know is that when sending

config

Quoted 1 line
Quoted 1 line

accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so

we use

Quoted 1 line
Quoted 1 line

root_bus_nr to determine this. The generic code that sets up sys->busnr

(ARM

Quoted 1 line
Quoted 1 line

bios32 in this case), just increments bus number for each controller.

I went back and looked at the lspci posted for this hardware and this use of busnr is kinda sketch..

You should use use bus 0 as the root complex integrated bus number and ensure every instance of your driver creates a new PCI domain, and generally use 0-> FF as the subordinate bus number range.

FWIW, your HW does care, and does have a programmable field for this.

You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:

root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])

Quoted 6 lines
        Bus: primary=00, secondary=01, subordinate=01, sec-latency=0

The value here will be also be exported on-the-wire in certain PCI-E TLPs.

So it is important, and must be set properly.

I am not so sure about this...

There are three things we need to consider:
1) talking to the host bridge itself
2) talking to immediate device (connected directly to host bridge)
3) talking to other devices

The PCI standard tells us we use type 1's for 3) and type 0's for 2). The driver uses root_bus_nr to make this decision.
For 1), there is a note in the driver that the hardware cannot target itself. The driver has code in rcar_pcie_config_access() to check if it's an access to the host bridge, and if so, use I/O (readl/writel) to perform the config access.

Quoted 8 lines
Quoted 3 lines

Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.

This is where some of the other implementations have used some SW to route config space in a single domain to the proper controller per-port register set.

Quoted 6 lines

But, IMHO, that is mainly worth doing if the HW can implement the PCI bridge windows according to the spec, and it looks like rcar requires a 128MB alignment on the bridge windows, which makes it fairly pointless.

Jason

Thanks
Phil

#7 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Quoted 20 lines · Phil Edworthy
Quoted 7 lines

You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:

root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])

Quoted 6 lines
        Bus: primary=00, secondary=01, subordinate=01, sec-latency=0

The value here will be also be exported on-the-wire in certain PCI-E TLPs.

So it is important, and must be set properly.

I am not so sure about this...

There are three things we need to consider:
1) talking to the host bridge itself
2) talking to immediate device (connected directly to host bridge)
3) talking to other devices

Quoted 6 lines

The PCI standard tells us we use type 1's for 3) and type 0's for 2). The driver uses root_bus_nr to make this decision. For 1), there is a note in the driver that the hardware cannot target itself. The driver has code in rcar_pcie_config_access() to check if it's an access to the host bridge, and if so, use I/O (readl/writel) to perform the config access.

The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number

Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.

It is just a happy hapenstance that root_bus_nr equals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.

I recommend capturing it on write to the host bridge config space.

Jason

#8 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Hi Jason,

Quoted 42 lines · Jason
Quoted 20 lines · Phil Edworthy
Quoted 7 lines

You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:

root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])

Quoted 6 lines
        Bus: primary=00, secondary=01, subordinate=01, sec-latency=0

The value here will be also be exported on-the-wire in certain PCI-E TLPs.

So it is important, and must be set properly.

I am not so sure about this...

There are three things we need to consider:
1) talking to the host bridge itself
2) talking to immediate device (connected directly to host bridge)
3) talking to other devices

Quoted 6 lines

The PCI standard tells us we use type 1's for 3) and type 0's for 2). The driver uses root_bus_nr to make this decision. For 1), there is a note in the driver that the hardware cannot target itself. The driver has code in rcar_pcie_config_access() to check if it's an access to the host bridge, and if so, use I/O (readl/writel) to perform the config access.

The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number
Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.

Quoted 3 lines

It is just a happy hapenstance that root_bus_nr equals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.

For type0 TLPs, we are not checking that root_bus_nr equals the value the PCI core programmed into secondary, we are checking that the (root_bus_nr == bus->parent->number). The only way this wouldn't work is if root_bus_nr was not the root bus number.

Since the Synopsys DW driver also saves off sys->busnr and later uses this to determine if accesses are for the host bridge, I guess that means it won't always work either, right? Or is it ok because the DW driver saves sys->busnr in its .scan function?

When would the PCI core change the root bus number to something other than set in sys->busnr?

Quoted 2 lines

I recommend capturing it on write to the host bridge config space.

Thanks
Phil

#9 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Quoted 13 lines · Phil Edworthy
Quoted 13 lines

The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number
Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.

Quoted 8 lines
Quoted 3 lines

It is just a happy hapenstance that root_bus_nr equals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.

For type0 TLPs, we are not checking that root_bus_nr equals the value the PCI core programmed into secondary, we are checking that the (root_bus_nr == bus->parent->number). The only way this wouldn't work is if root_bus_nr was not the root bus number.

Okay, that isn't as sketchy, but that process still ignores the subordinate bus number and the failure case as required by PCI.

The goal here is to have the stuff below the drivers implement the PCI spec so that the core code can assume everything below is conformant. Drivers should not introduce gratuitous differences 'just because'

There is no reason drivers should be using PCI core structures to make decisions when the spec says those decisions are driven by config space fields.

This way the PCI core code doesn't have to be aware of any weird non-standard edge cases.. Such as not failing bus numbers beyond the subordinate bus number.

Quoted 4 lines

Since the Synopsys DW driver also saves off sys->busnr and later uses this to determine if accesses are for the host bridge, I guess that means it won't always work either, right? Or is it ok because the DW driver saves sys->busnr in its .scan function?

Sounds like it is making the same mistake, and nobody noticed. This is another reason why it is important to implement correctly so people copying copy the right stuff :)

Quoted 2 lines

When would the PCI core change the root bus number to something other than set in sys->busnr?

I think the more likely scenario is that 'sys' in general is architecture specific and its use is being discouraged so that host drivers are not arch specific.

A domain driver like rcar should always place the root complex integrated bus as bus 0 in the domain.

Jason

#10 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Hi Jason,

Quoted 52 lines · Jason
Quoted 13 lines · Phil Edworthy
Quoted 13 lines

The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number
Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.

Quoted 8 lines
Quoted 3 lines

It is just a happy hapenstance that root_bus_nr equals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.

For type0 TLPs, we are not checking that root_bus_nr equals the value the PCI core programmed into secondary, we are checking that the (root_bus_nr == bus->parent->number). The only way this wouldn't work is if root_bus_nr was not the root bus number.

Okay, that isn't as sketchy, but that process still ignores the subordinate bus number and the failure case as required by PCI.

The goal here is to have the stuff below the drivers implement the PCI spec so that the core code can assume everything below is conformant. Drivers should not introduce gratuitous differences 'just because'

There is no reason drivers should be using PCI core structures to make decisions when the spec says those decisions are driven by config space fields.

This way the PCI core code doesn't have to be aware of any weird non-standard edge cases.. Such as not failing bus numbers beyond the subordinate bus number.

Quoted 4 lines

Since the Synopsys DW driver also saves off sys->busnr and later uses this to determine if accesses are for the host bridge, I guess that means it won't always work either, right? Or is it ok because the DW driver saves sys->busnr in its .scan function?

Sounds like it is making the same mistake, and nobody noticed. This is another reason why it is important to implement correctly so people copying copy the right stuff :)

Quoted 2 lines

When would the PCI core change the root bus number to something other than set in sys->busnr?

Quoted 6 lines

I think the more likely scenario is that 'sys' in general is architecture specific and its use is being discouraged so that host drivers are not arch specific.

A domain driver like rcar should always place the root complex integrated bus as bus 0 in the domain.

Ok, I now understand the reason for removing the dependency on sys->busnr. That makes sense & I'll update the driver for this.

Thanks for your patience :)
Phil

maintainer
#11 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

In reply to Phil Edworthy

[+cc Srikanth, Michal, Grant because we're having the same discussion about root bus numbers in the Xilinx host bridge driver]

Quoted 1 line · Phil Edworthy

When would the PCI core change the root bus number to something other than set in sys->busnr?

The PCI core never changes the root bus number of a host bridge, but it's important for the core to know exactly what bus numbers are behind each host bridge so we can correctly assign bus numbers, MMIO, and I/O port resources.

The reason is that when we enumerate a PCI-to-PCI bridge, we have to know whether bus numbers are available for the secondary bus. For example, assume two host bridges configured (or wired) as follows:

A leads to [bus 00-1f], with aperture [mem 0x80000000-0x8fffffff] B leads to [bus 20-ff], with aperture [mem 0x90000000-0x9fffffff]

Further, assume a PCI-to-PCI bridge at 1f:00.0. If the host bridge driver doesn't tell us the [bus 00-1f] range for host bridge A, the PCI core will assume [bus 00-ff]. When the core enumerates the 1f:00.0 bridge, it will assign bus number 20 to its secondary bus. Now it enumerates devices on bus 20. The core expects this to be done via host bridge A, but enumeration uses ID-routed config transactions, so they are claimed by host bridge B instead. If we find a device 20:00.0, the core thinks it is below A, but it is really below B.

Now we assign resources to 20:00.0, and since we think it's below A, we assign them from the [mem 0x80000000-0x8fffffff] aperture. This obviously doesn't work, because when the driver performs MMIO accesses, which are address-routed, they are claimed by host bridge A, not B, so the 20:00.0 device never sees them.

If your host bridge really claims ALL bus numbers (00-ff), that's fine, and you can tell the PCI core that. But if you have several such bridges, they should be placed in separate domains.

This is probably more detail than you wanted, and maybe you don't ever expect to have multiple host bridges or complicated hierarchies of devices. But the PCI core has to deal with these issues on other systems, so it's important to get these details right.

Bjorn

#12 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

Hi Bjorn,

Quoted 30 lines · Bjorn

[+cc Srikanth, Michal, Grant because we're having the same discussion about root bus numbers in the Xilinx host bridge driver]

Quoted 1 line · Phil Edworthy

When would the PCI core change the root bus number to something other

than set in sys->busnr?

The PCI core never changes the root bus number of a host bridge, but it's important for the core to know exactly what bus numbers are behind each host bridge so we can correctly assign bus numbers, MMIO, and I/O port resources.

The reason is that when we enumerate a PCI-to-PCI bridge, we have to know whether bus numbers are available for the secondary bus. For example, assume two host bridges configured (or wired) as follows:

A leads to [bus 00-1f], with aperture [mem 0x80000000-0x8fffffff] B leads to [bus 20-ff], with aperture [mem 0x90000000-0x9fffffff]

Further, assume a PCI-to-PCI bridge at 1f:00.0. If the host bridge driver doesn't tell us the [bus 00-1f] range for host bridge A, the PCI core will assume [bus 00-ff]. When the core enumerates the 1f:00.0 bridge, it will assign bus number 20 to its secondary bus. Now it enumerates devices on bus 20. The core expects this to be done via host bridge A, but enumeration uses ID-routed config transactions, so they are claimed by host bridge B instead. If we find a device 20:00.0, the core thinks it is below A, but it is really below B.

Quoted 5 lines

Now we assign resources to 20:00.0, and since we think it's below A, we assign them from the [mem 0x80000000-0x8fffffff] aperture. This obviously doesn't work, because when the driver performs MMIO accesses, which are address-routed, they are claimed by host bridge A, not B, so the 20:00.0 device never sees them.

Thanks for the clear explanation.

Quoted 3 lines

If your host bridge really claims ALL bus numbers (00-ff), that's fine, and you can tell the PCI core that. But if you have several such bridges, they should be placed in separate domains.

That makes sense.

In the case of the R-Car PCIe host bridge, as far as I can tell, the hardware doesn?t care about bus numbers at all, with the exception that the driver uses one bus number to target the bridge itself. We can use as many or as few bus numbers for the secondary bus as you like.

So, the R-Car PCIe driver should implement bus ranges, but should it also use separate PCI domains for multiple controllers?

Quoted 4 lines

This is probably more detail than you wanted, and maybe you don't ever expect to have multiple host bridges or complicated hierarchies of devices. But the PCI core has to deal with these issues on other systems, so it's important to get these details right.

Thanks
Phil

#13 lore raw

PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver

In reply to Bjorn Helgaas

Hi Bjorn,

Quoted 63 lines · Bjorn
Quoted 49 lines · Phil Edworthy

Hi Bjorn,

Thanks for the review.

Quoted 7 lines · Bjorn
Quoted 5 lines · Phil Edworthy

This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.

...

Quoted 11 lines

drivers/pci/host/pcie-rcar.c line 27

Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +2 -0
@@ -0,0 +1,693 @@
...
+#include <linux/slab.h>
+#include "pcie-rcar.h"

It looks like the things in pcie-rcar.h are used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have a pcie-rcar.h at all. Of course, if there are things needed by more than one file, they should stay in pcie-rcar.h.

Nothing else uses them so I'll put in the c file.

Quoted 16 lines
Quoted 16 lines
drivers/pci/host/pcie-rcar.c new file +16 -0
+#define DRV_NAME "rcar-pcie"
+
+#define RCONF(x)   (PCICONF(0)+(x))
+#define RPMCAP(x)  (PMCAP(0)+(x))
+#define REXPCAP(x) (EXPCAP(0)+(x))
+#define RVCCAP(x)  (VCCAP(0)+(x))
+
+#define  PCIE_CONF_BUS(b)  (((b) & 0xff) << 24)
+#define  PCIE_CONF_DEV(d)  (((d) & 0x1f) << 19)
+#define  PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
+
+#define PCI_MAX_RESOURCES 4
+#define MAX_NR_INBOUND_MAPS 6
+
+/* Structure representing the PCIe interface */
+struct rcar_pcie {
Quoted 8 lines

drivers/pci/host/pcie-rcar.c line 48

Quoted 4 lines
drivers/pci/host/pcie-rcar.c new file +4 -0
+   struct device           *dev;
+   void __iomem            *base;
+   struct resource         res[PCI_MAX_RESOURCES];
+   u8                      root_bus_nr;

I don't understand how root_bus_nr works. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge.

Quoted 7 lines

That's correct.

Quoted 4 lines

That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But root_bus_nr comes from sys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.

The manual for this hardware says that the HW doesn't care what the bus

number

Quoted 2 lines

is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we

use

Quoted 1 line

root_bus_nr to determine this. The generic code that sets up sys->busnr

Quoted 8 lines

(ARM

Quoted 3 lines

bios32 in this case), just increments bus number for each controller.

This is very similar to the pcie-designware driver, in dw_pcie_scan_bus().

OK. From what you said below, it sounds like you would add a DT entry for the bus range you want to have below this bridge, and use TYPE0 accesses for the base of that range.

Ok. The driver already uses TYPE0 for the base, i.e. that's what root_bus_nr is used for. I'll add the ranges ability.

Quoted 2 lines

I'm not sure how you reconcile this with the idea that the bios32 code just increments a bus number for each controller.

I looked at the bios32 code again. I was wrong to say that it just increments a bus number for each controller. The first controller always starts with busnr=0, and subsequent controllers get the next available bus number after scanning the bus.

Quoted 17 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

+static int __init rcar_pcie_get_resources(struct platform_device

*pdev,

Quoted 10 lines
Quoted 10 lines

drivers/pci/host/pcie-rcar.c line 472

Quoted 8 lines
drivers/pci/host/pcie-rcar.c new file +8 -0
+   struct rcar_pcie *pcie)
+{
+   struct resource res;
+   int err;
+
+   err = of_address_to_resource(pdev->dev.of_node, 0, &res);
+   if (err)
+           return err;

I don't see anywhere that figures out the bus number range behind this

host

Quoted 4 lines
Quoted 4 lines

bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.

Quoted 8 lines
Quoted 2 lines
Quoted 1 line

For new code, we should be explicit about the range.

This means add a DT entry for bus-range, and simply calling

pci_add_resource for

Quoted 1 line

the range, right? If so, ok.

Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.

Ok.

Thanks
Phil

#14 lore raw

PATCH v7 2/10 PCI: host: rcar: Add MSI support

In reply to Phil Edworthy

v6:
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line

v5:
- Return IRQ_NONE from MSI isr when there is no pending MSI
- Add additional interrupt bindings

---
 drivers/pci/host/pcie-rcar.c | 238 ++++++++++++++++++++++++++++++++++++++++++-
 drivers/pci/host/pcie-rcar.h |   5 +
 2 files changed, 242 insertions(+), 1 deletion(-)
drivers/pci/host/pcie-rcar.c +237 -1
index c22c896..e3ce3d1 100644
@@ -15,8 +15,11 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_pci.h>
@@ -28,6 +31,8 @@
 
 #define DRV_NAME "rcar-pcie"
 
+#define INT_PCI_MSI_NR	32
+
 #define RCONF(x)	(PCICONF(0)+(x))
 #define RPMCAP(x)	(PMCAP(0)+(x))
 #define REXPCAP(x)	(EXPCAP(0)+(x))
@@ -40,6 +45,21 @@
 #define PCI_MAX_RESOURCES 4
 #define MAX_NR_INBOUND_MAPS 6
 
+struct rcar_msi {
+	DECLARE_BITMAP(used, INT_PCI_MSI_NR);
+	struct irq_domain *domain;
+	struct msi_chip chip;
+	unsigned long pages;
+	struct mutex lock;
+	int irq1;
+	int irq2;
+};
+
+static inline struct rcar_msi *to_rcar_msi(struct msi_chip *chip)
+{
+	return container_of(chip, struct rcar_msi, chip);
+}
+
 /* Structure representing the PCIe interface */
 struct rcar_pcie {
 	struct device		*dev;
@@ -48,6 +68,7 @@ struct rcar_pcie {
 	u8			root_bus_nr;
 	struct clk		*clk;
 	struct clk		*bus_clk;
+	struct			rcar_msi msi;
 };
 
 static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
@@ -292,6 +313,15 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
 	return 1;
 }
 
+static void rcar_pcie_add_bus(struct pci_bus *bus)
+{
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+
+		bus->msi = &pcie->msi.chip;
+	}
+}
+
 static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
 {
 	struct platform_device *pdev = to_platform_device(pcie->dev);
@@ -301,6 +331,7 @@ static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
 		.setup          = rcar_pcie_setup,
 		.map_irq        = of_irq_parse_and_map_pci,
 		.ops            = &rcar_pcie_ops,
+		.add_bus        = rcar_pcie_add_bus,
 	};
 
 	pci_common_init_dev(&pdev->dev, &hw);
@@ -408,6 +439,10 @@ static int __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
 	/* Enable MAC data scrambling. */
 	rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
 
+	/* Enable MSI */
+	if (IS_ENABLED(CONFIG_PCI_MSI))
+		pci_write_reg(pcie, 0x101f0000, PCIEMSITXR);
+
 	/* Finish initialization - establish a PCI Express link */
 	pci_write_reg(pcie, CFINIT, PCIETCTLR);
 
@@ -461,11 +496,186 @@ static int __init rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)
 	return -ETIMEDOUT;
 }
 
+static int rcar_msi_alloc(struct rcar_msi *chip)
+{
+	int msi;
+
+	mutex_lock(&chip->lock);
+
+	msi = find_first_zero_bit(chip->used, INT_PCI_MSI_NR);
+	if (msi < INT_PCI_MSI_NR)
+		set_bit(msi, chip->used);
+	else
+		msi = -ENOSPC;
+
+	mutex_unlock(&chip->lock);
+
+	return msi;
+}
+
+static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq)
+{
+	struct device *dev = chip->chip.dev;
+
+	mutex_lock(&chip->lock);
+	clear_bit(irq, chip->used);
+	mutex_unlock(&chip->lock);
+}
+
+static irqreturn_t rcar_pcie_msi_irq(int irq, void *data)
+{
+	struct rcar_pcie *pcie = data;
+	struct rcar_msi *msi = &pcie->msi;
+	unsigned long reg;
+
+	reg = pci_read_reg(pcie, PCIEMSIFR);
+
+	/* MSI & INTx share an interrupt - we only handle MSI here */
+	if (!reg)
+		return IRQ_NONE;
+
+	while (reg) {
+		unsigned int index = find_first_bit(&reg, 32);
+		unsigned int irq;
+
+		/* clear the interrupt */
+		pci_write_reg(pcie, 1 << index, PCIEMSIFR);
+
+		irq = irq_find_mapping(msi->domain, index);
+		if (irq) {
+			if (test_bit(index, msi->used))
+				generic_handle_irq(irq);
+			else
+				dev_info(pcie->dev, "unhandled MSI\n");
+		} else {
+			/* Unknown MSI, just clear it */
+			dev_dbg(pcie->dev, "unexpected MSI\n");
+		}
+
+		/* see if there's any more pending in this vector */
+		reg = pci_read_reg(pcie, PCIEMSIFR);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int rcar_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
+			       struct msi_desc *desc)
+{
+	struct rcar_msi *msi = to_rcar_msi(chip);
+	struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip);
+	struct msi_msg msg;
+	unsigned int irq;
+	int hwirq;
+
+	hwirq = rcar_msi_alloc(msi);
+	if (hwirq < 0)
+		return hwirq;
+
+	irq = irq_create_mapping(msi->domain, hwirq);
+	if (!irq) {
+		rcar_msi_free(msi, hwirq);
+		return -EINVAL;
+	}
+
+	irq_set_msi_desc(irq, desc);
+
+	msg.address_lo = pci_read_reg(pcie, PCIEMSIALR) & ~MSIFE;
+	msg.address_hi = pci_read_reg(pcie, PCIEMSIAUR);
+	msg.data = hwirq;
+
+	write_msi_msg(irq, &msg);
+
+	return 0;
+}
+
+static void rcar_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+{
+	struct rcar_msi *msi = to_rcar_msi(chip);
+	struct irq_data *d = irq_get_irq_data(irq);
+
+	rcar_msi_free(msi, d->hwirq);
+}
+
+static struct irq_chip rcar_msi_irq_chip = {
+	.name = "R-Car PCIe MSI",
+	.irq_enable = unmask_msi_irq,
+	.irq_disable = mask_msi_irq,
+	.irq_mask = mask_msi_irq,
+	.irq_unmask = unmask_msi_irq,
+};
+
+static int rcar_msi_map(struct irq_domain *domain, unsigned int irq,
+			 irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &rcar_msi_irq_chip, handle_simple_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static const struct irq_domain_ops msi_domain_ops = {
+	.map = rcar_msi_map,
+};
+
+static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
+{
+	struct platform_device *pdev = to_platform_device(pcie->dev);
+	struct rcar_msi *msi = &pcie->msi;
+	unsigned long base;
+	int err;
+
+	mutex_init(&msi->lock);
+
+	msi->chip.dev = pcie->dev;
+	msi->chip.setup_irq = rcar_msi_setup_irq;
+	msi->chip.teardown_irq = rcar_msi_teardown_irq;
+
+	msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR,
+					    &msi_domain_ops, &msi->chip);
+	if (!msi->domain) {
+		dev_err(&pdev->dev, "failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	/* Two irqs are for MSI, but they are also used for non-MSI irqs */
+	err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq,
+			       IRQF_SHARED, rcar_msi_irq_chip.name, pcie);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
+		goto err;
+	}
+
+	err = devm_request_irq(&pdev->dev, msi->irq2, rcar_pcie_msi_irq,
+			       IRQF_SHARED, rcar_msi_irq_chip.name, pcie);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
+		goto err;
+	}
+
+	/* setup MSI data target */
+	msi->pages = __get_free_pages(GFP_KERNEL, 0);
+	base = virt_to_phys((void *)msi->pages);
+
+	pci_write_reg(pcie, base | MSIFE, PCIEMSIALR);
+	pci_write_reg(pcie, 0, PCIEMSIAUR);
+
+	/* enable all MSI interrupts */
+	pci_write_reg(pcie, 0xffffffff, PCIEMSIIER);
+
+	return 0;
+
+err:
+	irq_domain_remove(msi->domain);
+	return err;
+}
+
 static int __init rcar_pcie_get_resources(struct platform_device *pdev,
 	struct rcar_pcie *pcie)
 {
 	struct resource res;
-	int err;
+	int err, i;
 
 	err = of_address_to_resource(pdev->dev.of_node, 0, &res);
 	if (err)
@@ -490,6 +700,22 @@ static int __init rcar_pcie_get_resources(struct platform_device *pdev,
 	if (err)
 		goto err_map_reg;
 
+	i = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (i < 0) {
+		dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n");
+		err = -ENOENT;
+		goto err_map_reg;
+	}
+	pcie->msi.irq1 = i;
+
+	i = irq_of_parse_and_map(pdev->dev.of_node, 1);
+	if (i < 0) {
+		dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n");
+		err = -ENOENT;
+		goto err_map_reg;
+	}
+	pcie->msi.irq2 = i;
+
 	pcie->base = devm_ioremap_resource(&pdev->dev, &res);
 	if (IS_ERR(pcie->base)) {
 		err = PTR_ERR(pcie->base);
@@ -657,6 +883,16 @@ static int __init rcar_pcie_probe(struct platform_device *pdev)
 	 if (err)
 		return err;
 
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		err = rcar_pcie_enable_msi(pcie);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"failed to enable MSI support: %d\n",
+				err);
+			return err;
+		}
+	}
+
 	of_id = of_match_device(rcar_pcie_of_match, pcie->dev);
 	if (!of_id || !of_id->data)
 		return -EINVAL;
drivers/pci/host/pcie-rcar.h +5 -0
index 3dc026b..4f0c678 100644
@@ -13,6 +13,7 @@
 #define PCIEMSR			0x000028
 #define PCIEINTXR		0x000400
 #define PCIEPHYSR		0x0007f0
+#define PCIEMSITXR		0x000840
 
 /* Transfer control */
 #define PCIETCTLR		0x02000
@@ -28,6 +29,10 @@
 #define PCIEPMSR		0x02034
 #define PCIEPMSCIER		0x02038
 #define PCIEMSIFR		0x02044
+#define PCIEMSIALR		0x02048
+#define  MSIFE			1
+#define PCIEMSIAUR		0x0204c
+#define PCIEMSIIER		0x02050
 
 /* root port address */
 #define PCIEPRAR(x)		(0x02080 + ((x) * 0x4))
Signature · 1 line
1.9.0
#15 lore raw

PATCH v7 2/10 PCI: host: rcar: Add MSI support

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:

Quoted 2 lines
Quoted 354 lines

v6:
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line

v5:
- Return IRQ_NONE from MSI isr when there is no pending MSI
- Add additional interrupt bindings

---
 drivers/pci/host/pcie-rcar.c | 238 ++++++++++++++++++++++++++++++++++++++++++-
 drivers/pci/host/pcie-rcar.h |   5 +
 2 files changed, 242 insertions(+), 1 deletion(-)
drivers/pci/host/pcie-rcar.c +237 -1
index c22c896..e3ce3d1 100644
@@ -15,8 +15,11 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_pci.h>
@@ -28,6 +31,8 @@
 
 #define DRV_NAME "rcar-pcie"
 
+#define INT_PCI_MSI_NR	32
+
 #define RCONF(x)	(PCICONF(0)+(x))
 #define RPMCAP(x)	(PMCAP(0)+(x))
 #define REXPCAP(x)	(EXPCAP(0)+(x))
@@ -40,6 +45,21 @@
 #define PCI_MAX_RESOURCES 4
 #define MAX_NR_INBOUND_MAPS 6
 
+struct rcar_msi {
+	DECLARE_BITMAP(used, INT_PCI_MSI_NR);
+	struct irq_domain *domain;
+	struct msi_chip chip;
+	unsigned long pages;
+	struct mutex lock;
+	int irq1;
+	int irq2;
+};
+
+static inline struct rcar_msi *to_rcar_msi(struct msi_chip *chip)
+{
+	return container_of(chip, struct rcar_msi, chip);
+}
+
 /* Structure representing the PCIe interface */
 struct rcar_pcie {
 	struct device		*dev;
@@ -48,6 +68,7 @@ struct rcar_pcie {
 	u8			root_bus_nr;
 	struct clk		*clk;
 	struct clk		*bus_clk;
+	struct			rcar_msi msi;
 };
 
 static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
@@ -292,6 +313,15 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
 	return 1;
 }
 
+static void rcar_pcie_add_bus(struct pci_bus *bus)
+{
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+
+		bus->msi = &pcie->msi.chip;
+	}
+}
+
 static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
 {
 	struct platform_device *pdev = to_platform_device(pcie->dev);
@@ -301,6 +331,7 @@ static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
 		.setup          = rcar_pcie_setup,
 		.map_irq        = of_irq_parse_and_map_pci,
 		.ops            = &rcar_pcie_ops,
+		.add_bus        = rcar_pcie_add_bus,
 	};
 
 	pci_common_init_dev(&pdev->dev, &hw);
@@ -408,6 +439,10 @@ static int __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
 	/* Enable MAC data scrambling. */
 	rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
 
+	/* Enable MSI */
+	if (IS_ENABLED(CONFIG_PCI_MSI))
+		pci_write_reg(pcie, 0x101f0000, PCIEMSITXR);
+
 	/* Finish initialization - establish a PCI Express link */
 	pci_write_reg(pcie, CFINIT, PCIETCTLR);
 
@@ -461,11 +496,186 @@ static int __init rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)
 	return -ETIMEDOUT;
 }
 
+static int rcar_msi_alloc(struct rcar_msi *chip)
+{
+	int msi;
+
+	mutex_lock(&chip->lock);
+
+	msi = find_first_zero_bit(chip->used, INT_PCI_MSI_NR);
+	if (msi < INT_PCI_MSI_NR)
+		set_bit(msi, chip->used);
+	else
+		msi = -ENOSPC;
+
+	mutex_unlock(&chip->lock);
+
+	return msi;
+}
+
+static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq)
+{
+	struct device *dev = chip->chip.dev;
+
+	mutex_lock(&chip->lock);
+	clear_bit(irq, chip->used);
+	mutex_unlock(&chip->lock);
+}
+
+static irqreturn_t rcar_pcie_msi_irq(int irq, void *data)
+{
+	struct rcar_pcie *pcie = data;
+	struct rcar_msi *msi = &pcie->msi;
+	unsigned long reg;
+
+	reg = pci_read_reg(pcie, PCIEMSIFR);
+
+	/* MSI & INTx share an interrupt - we only handle MSI here */
+	if (!reg)
+		return IRQ_NONE;
+
+	while (reg) {
+		unsigned int index = find_first_bit(&reg, 32);
+		unsigned int irq;
+
+		/* clear the interrupt */
+		pci_write_reg(pcie, 1 << index, PCIEMSIFR);
+
+		irq = irq_find_mapping(msi->domain, index);
+		if (irq) {
+			if (test_bit(index, msi->used))
+				generic_handle_irq(irq);
+			else
+				dev_info(pcie->dev, "unhandled MSI\n");
+		} else {
+			/* Unknown MSI, just clear it */
+			dev_dbg(pcie->dev, "unexpected MSI\n");
+		}
+
+		/* see if there's any more pending in this vector */
+		reg = pci_read_reg(pcie, PCIEMSIFR);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int rcar_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
+			       struct msi_desc *desc)
+{
+	struct rcar_msi *msi = to_rcar_msi(chip);
+	struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip);
+	struct msi_msg msg;
+	unsigned int irq;
+	int hwirq;
+
+	hwirq = rcar_msi_alloc(msi);
+	if (hwirq < 0)
+		return hwirq;
+
+	irq = irq_create_mapping(msi->domain, hwirq);
+	if (!irq) {
+		rcar_msi_free(msi, hwirq);
+		return -EINVAL;
+	}
+
+	irq_set_msi_desc(irq, desc);
+
+	msg.address_lo = pci_read_reg(pcie, PCIEMSIALR) & ~MSIFE;
+	msg.address_hi = pci_read_reg(pcie, PCIEMSIAUR);
+	msg.data = hwirq;
+
+	write_msi_msg(irq, &msg);
+
+	return 0;
+}
+
+static void rcar_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+{
+	struct rcar_msi *msi = to_rcar_msi(chip);
+	struct irq_data *d = irq_get_irq_data(irq);
+
+	rcar_msi_free(msi, d->hwirq);
+}
+
+static struct irq_chip rcar_msi_irq_chip = {
+	.name = "R-Car PCIe MSI",
+	.irq_enable = unmask_msi_irq,
+	.irq_disable = mask_msi_irq,
+	.irq_mask = mask_msi_irq,
+	.irq_unmask = unmask_msi_irq,
+};
+
+static int rcar_msi_map(struct irq_domain *domain, unsigned int irq,
+			 irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &rcar_msi_irq_chip, handle_simple_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static const struct irq_domain_ops msi_domain_ops = {
+	.map = rcar_msi_map,
+};
+
+static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
+{
+	struct platform_device *pdev = to_platform_device(pcie->dev);
+	struct rcar_msi *msi = &pcie->msi;
+	unsigned long base;
+	int err;
+
+	mutex_init(&msi->lock);
+
+	msi->chip.dev = pcie->dev;
+	msi->chip.setup_irq = rcar_msi_setup_irq;
+	msi->chip.teardown_irq = rcar_msi_teardown_irq;
+
+	msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR,
+					    &msi_domain_ops, &msi->chip);
+	if (!msi->domain) {
+		dev_err(&pdev->dev, "failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	/* Two irqs are for MSI, but they are also used for non-MSI irqs */
+	err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq,
+			       IRQF_SHARED, rcar_msi_irq_chip.name, pcie);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
+		goto err;
+	}
+
+	err = devm_request_irq(&pdev->dev, msi->irq2, rcar_pcie_msi_irq,
+			       IRQF_SHARED, rcar_msi_irq_chip.name, pcie);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
+		goto err;
+	}
+
+	/* setup MSI data target */
+	msi->pages = __get_free_pages(GFP_KERNEL, 0);
+	base = virt_to_phys((void *)msi->pages);
+
+	pci_write_reg(pcie, base | MSIFE, PCIEMSIALR);
+	pci_write_reg(pcie, 0, PCIEMSIAUR);
+
+	/* enable all MSI interrupts */
+	pci_write_reg(pcie, 0xffffffff, PCIEMSIIER);
+
+	return 0;
+
+err:
+	irq_domain_remove(msi->domain);
+	return err;
+}
+
 static int __init rcar_pcie_get_resources(struct platform_device *pdev,
 	struct rcar_pcie *pcie)
 {
 	struct resource res;
-	int err;
+	int err, i;
 
 	err = of_address_to_resource(pdev->dev.of_node, 0, &res);
 	if (err)
@@ -490,6 +700,22 @@ static int __init rcar_pcie_get_resources(struct platform_device *pdev,
 	if (err)
 		goto err_map_reg;
 
+	i = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (i < 0) {
+		dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n");
+		err = -ENOENT;
+		goto err_map_reg;
+	}
+	pcie->msi.irq1 = i;
+
+	i = irq_of_parse_and_map(pdev->dev.of_node, 1);
+	if (i < 0) {
+		dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n");
+		err = -ENOENT;
+		goto err_map_reg;
+	}
+	pcie->msi.irq2 = i;
+
 	pcie->base = devm_ioremap_resource(&pdev->dev, &res);
 	if (IS_ERR(pcie->base)) {
 		err = PTR_ERR(pcie->base);
@@ -657,6 +883,16 @@ static int __init rcar_pcie_probe(struct platform_device *pdev)
 	 if (err)
 		return err;
 
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		err = rcar_pcie_enable_msi(pcie);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"failed to enable MSI support: %d\n",
+				err);
+			return err;
+		}
+	}
+
 	of_id = of_match_device(rcar_pcie_of_match, pcie->dev);
 	if (!of_id || !of_id->data)
 		return -EINVAL;
drivers/pci/host/pcie-rcar.h +5 -0
index 3dc026b..4f0c678 100644
@@ -13,6 +13,7 @@
 #define PCIEMSR			0x000028
 #define PCIEINTXR		0x000400
 #define PCIEPHYSR		0x0007f0
+#define PCIEMSITXR		0x000840
 
 /* Transfer control */
 #define PCIETCTLR		0x02000
@@ -28,6 +29,10 @@
 #define PCIEPMSR		0x02034
 #define PCIEPMSCIER		0x02038
 #define PCIEMSIFR		0x02044
+#define PCIEMSIALR		0x02048
+#define  MSIFE			1
+#define PCIEMSIAUR		0x0204c
+#define PCIEMSIIER		0x02050
 
 /* root port address */
 #define PCIEPRAR(x)		(0x02080 + ((x) * 0x4))
Signature · 4 lines
Pengutronix e.K.                           | Lucas Stach                 |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
#16 lore raw

PATCH v7 3/10 ARM: shmobile: r8a7790: Add PCIe clock device tree nodes

In reply to Phil Edworthy

This patch adds the device tree clock nodes for PCIe

---
 arch/arm/boot/dts/r8a7790.dtsi            | 7 ++++---
 include/dt-bindings/clock/r8a7790-clock.h | 1 +
 2 files changed, 5 insertions(+), 3 deletions(-)
arch/arm/boot/dts/r8a7790.dtsi +4 -3
index da69afc..df9ec61 100644
@@ -704,16 +704,17 @@
 			reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
 			clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>,
 				 <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>,
-				 <&mmc0_clk>, <&rclk_clk>;
+				 <&mmc0_clk>, <&rclk_clk>, <&mp_clk>;
 			#clock-cells = <1>;
 			renesas,clock-indices = <
 				R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3
 				R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0
-				R8A7790_CLK_MMCIF0 R8A7790_CLK_CMT1
+				R8A7790_CLK_MMCIF0 R8A7790_CLK_CMT1 R8A7790_CLK_PCIE
 			>;
 			clock-output-names =
 				"tpu0", "mmcif1", "sdhi3", "sdhi2",
-				"sdhi1", "sdhi0", "mmcif0", "cmt1";
+				"sdhi1", "sdhi0", "mmcif0", "cmt1",
+				"pcie";
 		};
 		mstp5_clks: mstp5_clks at e6150144 {
 			compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
include/dt-bindings/clock/r8a7790-clock.h +1 -0
index 6548a5f..840dbc8 100644
@@ -57,6 +57,7 @@
 #define R8A7790_CLK_SDHI1		13
 #define R8A7790_CLK_SDHI0		14
 #define R8A7790_CLK_MMCIF0		15
+#define R8A7790_CLK_PCIE		19
 #define R8A7790_CLK_SSUSB		28
 #define R8A7790_CLK_CMT1		29
 #define R8A7790_CLK_USBDMAC0		30
Signature · 1 line
1.9.0
#17 lore raw

PATCH v7 4/10 ARM: shmobile: r8a7791: Add PCIe clock device tree nodes

In reply to Phil Edworthy

This patch adds the device tree clock nodes for PCIe

---
 arch/arm/boot/dts/r8a7791.dtsi            | 7 +++++--
 include/dt-bindings/clock/r8a7791-clock.h | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)
arch/arm/boot/dts/r8a7791.dtsi +5 -2
index 71bac2c..ccfba57 100644
@@ -717,14 +717,17 @@
 			compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
 			clocks = <&cp_clk>, <&sd2_clk>, <&sd1_clk>,
-				<&cpg_clocks R8A7791_CLK_SD0>, <&mmc0_clk>, <&rclk_clk>;
+				<&cpg_clocks R8A7791_CLK_SD0>, <&mmc0_clk>, <&rclk_clk>,
+				<&mp_clk>;
 			#clock-cells = <1>;
 			renesas,clock-indices = <
 				R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1
 				R8A7791_CLK_SDHI0 R8A7791_CLK_MMCIF0 R8A7791_CLK_CMT1
+				R8A7791_CLK_PCIE
 			>;
 			clock-output-names =
-				"tpu0", "sdhi2", "sdhi1", "sdhi0", "mmcif0", "cmt1";
+				"tpu0", "sdhi2", "sdhi1", "sdhi0", "mmcif0", "cmt1",
+				"pcie";
 		};
 		mstp5_clks: mstp5_clks at e6150144 {
 			compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
include/dt-bindings/clock/r8a7791-clock.h +1 -0
index 30f82f2..d3e2cf5 100644
@@ -51,6 +51,7 @@
 #define R8A7791_CLK_SDHI1		12
 #define R8A7791_CLK_SDHI0		14
 #define R8A7791_CLK_MMCIF0		15
+#define R8A7791_CLK_PCIE		19
 #define R8A7791_CLK_SSUSB		28
 #define R8A7791_CLK_CMT1		29
 #define R8A7791_CLK_USBDMAC0		30
Signature · 1 line
1.9.0
#18 lore raw

PATCH v7 5/10 dt-bindings: pci: rcar pcie device tree bindings

In reply to Phil Edworthy

This patch adds the bindings for the R-Car PCIe driver. The driver resides under drivers/pci/host/pcie-rcar.c

v7:
- Change binding description of clocks to 'clock specifiers'

v6:
- Correct DT bindings description for reg and clocks

v5:
- Add PCIe bus clock reference
- Add additional interrupt bindings
- Use dma-ranges property to specify inbound memory regions

---
 Documentation/devicetree/bindings/pci/rcar-pci.txt | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txt
Documentation/devicetree/bindings/pci/rcar-pci.txt new file +45 -0
new file mode 100644
index 0000000..789bd46
@@ -0,0 +1,45 @@
+* Renesas RCar PCIe interface
+
+Required properties:
+- compatible: should contain one of the following
+	"renesas,pcie-r8a7779", "renesas,pcie-r8a7790", "renesas,pcie-r8a7791"
+- reg: base address and length of the pcie controller registers.
+- #address-cells: set to <3>
+- #size-cells: set to <2>
+- device_type: set to "pci"
+- ranges: ranges for the PCI memory and I/O regions.
+- dma-ranges: ranges for the inbound memory regions.
+- interrupts: two interrupt sources for MSI interrupts, followed by interrupt
+	source for hardware related interrupts (e.g. link speed change).
+- #interrupt-cells: set to <1>
+- interrupt-map-mask and interrupt-map: standard PCI properties
+	to define the mapping of the PCIe interface to interrupt
+	numbers.
+- clocks: from common clock binding: clock specifiers for the PCIe controller
+	and PCIe bus clocks.
+- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
+
+Example:
+
+SoC specific DT Entry:
+
+	pcie: pcie at fe000000 {
+		compatible = "renesas,pcie-r8a7791";
+		reg = <0 0xfe000000 0 0x80000>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		device_type = "pci";
+		ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+			  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+			  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+			  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+		dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000
+			      0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
+		interrupts = <0 116 4 0 117 4 0 118 4>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &gic 0 116 4>;
+		clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>;
+		clock-names = "pcie", "pcie_bus";
+		status = "disabled";
+	};
Signature · 1 line
1.9.0
#19 lore raw

PATCH v7 5/10 dt-bindings: pci: rcar pcie device tree bindings

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:

Quoted 4 lines

This patch adds the bindings for the R-Car PCIe driver. The driver resides under drivers/pci/host/pcie-rcar.c

Another nitpick below, otherwise:

If you decide to roll another version with just this changed, feel free to carry over the my tag.

Quoted 50 lines

v7:
- Change binding description of clocks to 'clock specifiers'

v6:
- Correct DT bindings description for reg and clocks

v5:
- Add PCIe bus clock reference
- Add additional interrupt bindings
- Use dma-ranges property to specify inbound memory regions

---
 Documentation/devicetree/bindings/pci/rcar-pci.txt | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txt
Documentation/devicetree/bindings/pci/rcar-pci.txt new file +28 -0
new file mode 100644
index 0000000..789bd46
@@ -0,0 +1,45 @@
+* Renesas RCar PCIe interface
+
+Required properties:
+- compatible: should contain one of the following
+	"renesas,pcie-r8a7779", "renesas,pcie-r8a7790", "renesas,pcie-r8a7791"
+- reg: base address and length of the pcie controller registers.
+- #address-cells: set to <3>
+- #size-cells: set to <2>
+- device_type: set to "pci"
+- ranges: ranges for the PCI memory and I/O regions.
+- dma-ranges: ranges for the inbound memory regions.
+- interrupts: two interrupt sources for MSI interrupts, followed by interrupt
+	source for hardware related interrupts (e.g. link speed change).
+- #interrupt-cells: set to <1>
+- interrupt-map-mask and interrupt-map: standard PCI properties
+	to define the mapping of the PCIe interface to interrupt
+	numbers.
+- clocks: from common clock binding: clock specifiers for the PCIe controller
+	and PCIe bus clocks.
+- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
+
+Example:
+
+SoC specific DT Entry:
+
+	pcie: pcie at fe000000 {
+		compatible = "renesas,pcie-r8a7791";
+		reg = <0 0xfe000000 0 0x80000>;

Documentation/devicetree/bindings/pci/rcar-pci.txt line 38

Quoted 10 lines
Documentation/devicetree/bindings/pci/rcar-pci.txt new file +10 -0
+		#address-cells = <3>;
+		#size-cells = <2>;
+		device_type = "pci";
+		ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+			  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+			  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+			  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+		dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000
+			      0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
+		interrupts = <0 116 4 0 117 4 0 118 4>;

I think this is confusing, I would rather like to see them in separate cells, like

	interrupts = <0 116 4>, <0 117 4>, <0 118 4>;

Same would be true for the ranges properties, but there it isn't as confusing, so I don't really care.

Quoted 7 lines
Documentation/devicetree/bindings/pci/rcar-pci.txt new file +7 -0
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &gic 0 116 4>;
+		clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>;
+		clock-names = "pcie", "pcie_bus";
+		status = "disabled";
+	};
Signature · 4 lines
Pengutronix e.K.                           | Lucas Stach                 |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
#20 lore raw

PATCH v7 6/10 ARM: shmobile: r8a7790: Add PCIe device nodes

In reply to Phil Edworthy

v6:
- Split device and board DT changes

---
 arch/arm/boot/dts/r8a7790.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
arch/arm/boot/dts/r8a7790.dtsi +24 -0
index df9ec61..dbcea57 100644
@@ -821,4 +821,28 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	pcie: pcie at fe000000 {
+		compatible = "renesas,pcie-r8a7790";
+		reg = <0 0xfe000000 0 0x80000>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		device_type = "pci";
+		ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+			  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+			  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+			  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+		/* Map all possible DDR as inbound ranges */
+		dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
+			      0x43000000 1 0x80000000 1 0x80000000 0 0x80000000>;
+		interrupts = <0 116 IRQ_TYPE_LEVEL_HIGH
+			      0 117 IRQ_TYPE_LEVEL_HIGH
+			      0 118 IRQ_TYPE_LEVEL_HIGH>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &gic 0 116 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks R8A7790_CLK_PCIE>, <&pcie_bus_clk>;
+		clock-names = "pcie", "pcie_bus";
+		status = "disabled";
+	};
 };
Signature · 1 line
1.9.0
#21 lore raw

PATCH v7 7/10 ARM: shmobile: lager: Add PCIe device nodes

In reply to Phil Edworthy

v6:
- Split device and board DT changes

---
 arch/arm/boot/dts/r8a7790-lager.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/arm/boot/dts/r8a7790-lager.dts +10 -0
index a55c5f8..bbbcb63 100644
@@ -139,6 +139,16 @@
 		states = <3300000 1
 			  1800000 0>;
 	};
+
+	clocks {
+		/* External PCIe bus clock - not used */
+		pcie_bus_clk: pcie_bus_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <0>;
+			clock-output-names = "pcie_bus";
+		};
+	};
 };
 
 &extal_clk {
Signature · 1 line
1.9.0
#22 lore raw

PATCH v7 8/10 ARM: shmobile: r8a7791: Add PCIe device nodes

In reply to Phil Edworthy

v6:
- Split device and board DT changes

---
 arch/arm/boot/dts/r8a7791.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
arch/arm/boot/dts/r8a7791.dtsi +24 -0
index ccfba57..7a4be4c 100644
@@ -836,4 +836,28 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	pcie: pcie at fe000000 {
+		compatible = "renesas,pcie-r8a7791";
+		reg = <0 0xfe000000 0 0x80000>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		device_type = "pci";
+		ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+			  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+			  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+			  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+		/* Map all possible DDR as inbound ranges */
+		dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
+			      0x43000000 2 0x00000000 2 0x00000000 1 0x00000000>;
+		interrupts = <0 116 IRQ_TYPE_LEVEL_HIGH
+			      0 117 IRQ_TYPE_LEVEL_HIGH
+			      0 118 IRQ_TYPE_LEVEL_HIGH>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &gic 0 116 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>;
+		clock-names = "pcie", "pcie_bus";
+		status = "disabled";
+	};
 };
Signature · 1 line
1.9.0
#23 lore raw

PATCH v7 9/10 ARM: shmobile: koelsch: Add PCIe device nodes

In reply to Phil Edworthy

v6:
- Split device and board DT changes

---
 arch/arm/boot/dts/r8a7791-koelsch.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
arch/arm/boot/dts/r8a7791-koelsch.dts +14 -0
index ee23b7b..3130a0c 100644
@@ -204,6 +204,16 @@
 		states = <3300000 1
 			  1800000 0>;
 	};
+
+	clocks {
+		/* External PCIe bus clock */
+		pcie_bus_clk: pcie_bus_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <100000000>;
+			clock-output-names = "pcie_bus";
+		};
+	};
 };
 
 &extal_clk {
@@ -382,3 +392,7 @@
 		spi-cpha;
 	};
 };
+
+&pcie {
+	status = "okay";
+};
Signature · 1 line
1.9.0
#24 lore raw

PATCH v7 10/10 ARM: shmobile: koelsch: Add PCIe to defconfig

In reply to Phil Edworthy

v6:
- Add shmobile to subject

---
 arch/arm/configs/koelsch_defconfig | 3 +++
 1 file changed, 3 insertions(+)
arch/arm/configs/koelsch_defconfig +3 -0
index 86faab5..ec14547 100644
@@ -15,6 +15,9 @@ CONFIG_MACH_KOELSCH=y
 CONFIG_CPU_BPREDICT_DISABLE=y
 CONFIG_PL310_ERRATA_588369=y
 CONFIG_ARM_ERRATA_754322=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_RCAR_GEN2_PCIE=y
 CONFIG_SMP=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
Signature · 1 line
1.9.0
#25 lore raw

v7 cover R-Car Gen2 PCIe host driver

In reply to Phil Edworthy

Hi Arnd, Ben, Sergei, Simon, Lucas, Geert, Jason,

Thank you for all your comments - is there anything else, or can I get your reviewed-by on these patches (or at least those that you have looked at)?

Thanks
Phil

Quoted 68 lines · Phil

Subject: [PATCH v7 00/10] R-Car Gen2 PCIe host driver

This is version 7 of a PCIe Host driver for the R-Car Gen2 devices, i.e. R-Car H2 (r8a7790) and R-Car M2 (r8a7791).

v7:
- Change binding description of clocks to 'clock specifiers'

v6:
- Correct DT bindings description for reg and clocks
- Split device and board DT changes
- Add shmobile to subject for shmobile DT patches
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line
- Remove patch that adds HAVE_ARM_ARCH_TIMER to koelsch defconfig as
not needed

v5:
- Use module_platform_driver instead of subsys_initcall
- Use the of_device_id data field for HW init function
- Init hw_pci struct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources
- Return IRQ_NONE from MSI isr when there is no pending MSI
- Add additional interrupt bindings

v4:
- Use runtime PM properly

Phil Edworthy (10):
PCI: host: rcar: Add Renesas R-Car PCIe driver
PCI: host: rcar: Add MSI support
ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
dt-bindings: pci: rcar pcie device tree bindings
ARM: shmobile: r8a7790: Add PCIe device nodes
ARM: shmobile: lager: Add PCIe device nodes
ARM: shmobile: r8a7791: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe to defconfig

 Documentation/devicetree/bindings/pci/rcar-pci.txt |  45 +
 arch/arm/boot/dts/r8a7790-lager.dts                |  10 +
 arch/arm/boot/dts/r8a7790.dtsi                     |  31 +-
 arch/arm/boot/dts/r8a7791-koelsch.dts              |  14 +
 arch/arm/boot/dts/r8a7791.dtsi                     |  31 +-
 arch/arm/configs/koelsch_defconfig                 |   3 +
 drivers/pci/host/Kconfig                           |   6 +
 drivers/pci/host/Makefile                          |   1 +
 drivers/pci/host/pcie-rcar.c                       | 929 +++++++++++++++++++++
 drivers/pci/host/pcie-rcar.h                       |  87 ++
 include/dt-bindings/clock/r8a7790-clock.h          |   1 +
 include/dt-bindings/clock/r8a7791-clock.h          |   1 +
 12 files changed, 1154 insertions(+), 5 deletions(-)  create mode 100644
Documentation/devicetree/bindings/pci/rcar-pci.txt
 create mode 100644 drivers/pci/host/pcie-rcar.c  create mode 100644

drivers/pci/host/pcie-rcar.h

--
1.9.0

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

#26 lore raw

v7 cover R-Car Gen2 PCIe host driver

In reply to Phil Edworthy

Hi Bjorn,

I assume that you'll take the PCI driver patches (0001, 0002 & 0005) through your tree and that the rest are platform specific patches that will go via Simon Horman. Would you like me to split this into two separate patch sets?

Thanks
Phil

Quoted 75 lines

-----Original Message-----
From: linux-sh-owner at vger.kernel.org [mailto:linux-sh- owner at vger.kernel.org] On Behalf Of Phil Edworthy
Sent: 31 March 2014 11:31
To: linux-pci at vger.kernel.org
Cc: linux-sh at vger.kernel.org; LAKML; Bjorn Helgaas; Valentine Barshak; Simon Horman; Magnus Damm; Ben Dooks; Phil Edworthy
Subject: [PATCH v7 00/10] R-Car Gen2 PCIe host driver

This is version 7 of a PCIe Host driver for the R-Car Gen2 devices, i.e. R-Car H2 (r8a7790) and R-Car M2 (r8a7791).

v7:
- Change binding description of clocks to 'clock specifiers'

v6:
- Correct DT bindings description for reg and clocks
- Split device and board DT changes
- Add shmobile to subject for shmobile DT patches
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line
- Remove patch that adds HAVE_ARM_ARCH_TIMER to koelsch defconfig as
not needed

v5:
- Use module_platform_driver instead of subsys_initcall
- Use the of_device_id data field for HW init function
- Init hw_pci struct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources
- Return IRQ_NONE from MSI isr when there is no pending MSI
- Add additional interrupt bindings

v4:
- Use runtime PM properly

Phil Edworthy (10):
PCI: host: rcar: Add Renesas R-Car PCIe driver
PCI: host: rcar: Add MSI support
ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
dt-bindings: pci: rcar pcie device tree bindings
ARM: shmobile: r8a7790: Add PCIe device nodes
ARM: shmobile: lager: Add PCIe device nodes
ARM: shmobile: r8a7791: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe to defconfig

 Documentation/devicetree/bindings/pci/rcar-pci.txt |  45 +
 arch/arm/boot/dts/r8a7790-lager.dts                |  10 +
 arch/arm/boot/dts/r8a7790.dtsi                     |  31 +-
 arch/arm/boot/dts/r8a7791-koelsch.dts              |  14 +
 arch/arm/boot/dts/r8a7791.dtsi                     |  31 +-
 arch/arm/configs/koelsch_defconfig                 |   3 +
 drivers/pci/host/Kconfig                           |   6 +
 drivers/pci/host/Makefile                          |   1 +
 drivers/pci/host/pcie-rcar.c                       | 929 +++++++++++++++++++++
 drivers/pci/host/pcie-rcar.h                       |  87 ++
 include/dt-bindings/clock/r8a7790-clock.h          |   1 +
 include/dt-bindings/clock/r8a7791-clock.h          |   1 +
 12 files changed, 1154 insertions(+), 5 deletions(-)  create mode 100644
Documentation/devicetree/bindings/pci/rcar-pci.txt
 create mode 100644 drivers/pci/host/pcie-rcar.c  create mode 100644

drivers/pci/host/pcie-rcar.h

--
1.9.0

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