All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/10] R-Car Gen2 PCIe host driver
@ 2014-03-31 10:30 ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

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


^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 00/10] R-Car Gen2 PCIe host driver
@ 2014-03-31 10:30 ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

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


^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 00/10] R-Car Gen2 PCIe host driver
@ 2014-03-31 10:30 ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 47d46c6..dc627e5 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -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
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..19946f9 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -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
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
new file mode 100644
index 0000000..c22c896
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.c
@@ -0,0 +1,693 @@
+/*
+ * PCIe driver for Renesas R-Car SoCs
+ *  Copyright (C) 2014 Renesas Electronics Europe Ltd
+ *
+ * Based on:
+ *  arch/sh/drivers/pci/pcie-sh7786.c
+ *  arch/sh/drivers/pci/ops-sh7786.c
+ *  Copyright (C) 2009 - 2011  Paul Mundt
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "pcie-rcar.h"
+
+#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 {
+	struct device		*dev;
+	void __iomem		*base;
+	struct resource		res[PCI_MAX_RESOURCES];
+	u8			root_bus_nr;
+	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)
+{
+	writel(val, pcie->base + reg);
+}
+
+static unsigned long
+pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
+{
+	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)
+{
+	int shift = 8 * (where & 3);
+	u32 val = pci_read_reg(pcie, where & ~3);
+	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);
+	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;
+
+	if (bus->number > 255 || dev > 31 || func > 7)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	/*
+	 * While each channel has its own memory-mapped extended config
+	 * space, it's generally only accessible when in endpoint mode.
+	 * When in root complex mode, the controller is unable to target
+	 * itself with either type 0 or type 1 accesses, and indeed, any
+	 * controller initiated target transfer to its own config space
+	 * result in a completer abort.
+	 *
+	 * Each channel effectively only supports a single device, but as
+	 * the same channel <-> device access works for any PCI_SLOT()
+	 * value, we cheat a bit here and bind the controller's config
+	 * space to devfn 0 in order to enable self-enumeration. In this
+	 * case the regular ECAR/ECDR path is sidelined and the mangled
+	 * config access itself is initiated as an internal bus  transaction.
+	 */
+	if (pci_is_root_bus(bus)) {
+		if (dev != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		if (access_type = PCI_ACCESS_READ)
+			*data = pci_read_reg(pcie, PCICONF(index));
+		else
+			pci_write_reg(pcie, *data, PCICONF(index));
+
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	/* 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)) &
+		(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);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
+				int where, int size, u32 *val)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+	int ret;
+
+	if ((size = 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size = 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+				      bus, devfn, where, val);
+	if (ret != PCIBIOS_SUCCESSFUL) {
+		*val = 0xffffffff;
+		return ret;
+	}
+
+	if (size = 1)
+		*val = (*val >> (8 * (where & 3))) & 0xff;
+	else if (size = 2)
+		*val = (*val >> (8 * (where & 2))) & 0xffff;
+
+	dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
+		"where=0x%04x size=%d val=0x%08lx\n", bus->number,
+		devfn, where, size, (unsigned long)*val);
+
+	return ret;
+}
+
+static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 val)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+	int shift, ret;
+	u32 data;
+
+	if ((size = 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size = 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+				      bus, devfn, where, &data);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
+
+	dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
+		"where=0x%04x size=%d val=0x%08lx\n", bus->number,
+		devfn, where, size, (unsigned long)val);
+
+	if (size = 1) {
+		shift = 8 * (where & 3);
+		data &= ~(0xff << shift);
+		data |= ((val & 0xff) << shift);
+	} else if (size = 2) {
+		shift = 8 * (where & 2);
+		data &= ~(0xffff << shift);
+		data |= ((val & 0xffff) << shift);
+	} else
+		data = val;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_WRITE,
+				      bus, devfn, where, &data);
+
+	return ret;
+}
+
+static struct pci_ops rcar_pcie_ops = {
+	.read	= rcar_pcie_read_conf,
+	.write	= rcar_pcie_write_conf,
+};
+
+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;
+	if (res->flags & IORESOURCE_IO)
+		mask |= IO_SPACE;
+
+	pci_write_reg(pcie, mask, PCIEPTCTLR(win));
+
+	return 0;
+}
+
+static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(sys);
+	struct resource *res;
+	int i;
+
+	pcie->root_bus_nr = sys->busnr;
+
+	/* Setup PCI resources */
+	for (i = 0; i < PCI_MAX_RESOURCES; i++) {
+
+		res = &pcie->res[i];
+		if (!res->flags)
+			continue;
+
+		rcar_pcie_setup_window(i, res, pcie);
+
+		if (res->flags & IORESOURCE_IO)
+			pci_ioremap_io(nr * SZ_64K, res->start);
+		else
+			pci_add_resource(&sys->resources, res);
+	}
+
+	return 1;
+}
+
+static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
+{
+	struct platform_device *pdev = to_platform_device(pcie->dev);
+	struct hw_pci hw = {
+		.nr_controllers = 1,
+		.private_data   = (void **)&pcie,
+		.setup          = rcar_pcie_setup,
+		.map_irq        = of_irq_parse_and_map_pci,
+		.ops            = &rcar_pcie_ops,
+	};
+
+	pci_common_init_dev(&pdev->dev, &hw);
+}
+
+static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 100;
+
+	while (timeout--) {
+		if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
+			return 0;
+
+		udelay(100);
+	}
+
+	dev_err(pcie->dev, "Access to PCIe phy timed out\n");
+
+	return -ETIMEDOUT;
+}
+
+static void __init phy_write_reg(struct rcar_pcie *pcie,
+				 unsigned int rate, unsigned int addr,
+				 unsigned int lane, unsigned int data)
+{
+	unsigned long phyaddr;
+
+	phyaddr = WRITE_CMD |
+		((rate & 1) << RATE_POS) |
+		((lane & 0xf) << LANE_POS) |
+		((addr & 0xff) << ADR_POS);
+
+	/* Set write data */
+	pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
+	pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
+
+	/* Ignore errors as they will be dealt with if the data link is down */
+	phy_wait_for_ack(pcie);
+
+	/* Clear command */
+	pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
+	pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
+
+	/* Ignore errors as they will be dealt with if the data link is down */
+	phy_wait_for_ack(pcie);
+}
+
+static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 10;
+
+	while (timeout--) {
+		if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
+			return 0;
+
+		msleep(5);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
+{
+	int err;
+
+	/* Begin initialization */
+	pci_write_reg(pcie, 0, PCIETCTLR);
+
+	/* Set mode */
+	pci_write_reg(pcie, 1, PCIEMSR);
+
+	/*
+	 * Initial header for port config space is type 1, set the device
+	 * class to match. Hardware takes care of propagating the IDSETR
+	 * settings, so there is no need to bother with a quirk.
+	 */
+	pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
+
+	/*
+	 * Setup Secondary Bus Number & Subordinate Bus Number, even though
+	 * they aren't used, to avoid bridge being detected as broken.
+	 */
+	rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
+	rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
+
+	/* Initialize default capabilities. */
+	rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
+		PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
+	rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
+		PCI_HEADER_TYPE_BRIDGE);
+
+	/* Enable data link layer active state reporting */
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0, PCI_EXP_LNKCAP_DLLLARC);
+
+	/* Write out the physical slot number = 0 */
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
+
+	/* Set the completion timer timeout to the maximum 50ms. */
+	rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
+
+	/* Terminate list of capabilities (Next Capability Offset=0) */
+	rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
+
+	/* Enable MAC data scrambling. */
+	rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
+
+	/* Finish initialization - establish a PCI Express link */
+	pci_write_reg(pcie, CFINIT, PCIETCTLR);
+
+	/* This will timeout if we don't have a link. */
+	err = rcar_pcie_wait_for_dl(pcie);
+	if (err)
+		return err;
+
+	/* Enable INTx interrupts */
+	rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
+
+	/* Enable slave Bus Mastering */
+	rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
+		PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+		PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
+
+	wmb();
+
+	return 0;
+}
+
+static int __init rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 10;
+
+	/* Initialize the phy */
+	phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
+	phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180);
+	phy_write_reg(pcie, 0, 0x43, 0x1, 0x00210188);
+	phy_write_reg(pcie, 1, 0x43, 0x1, 0x00210188);
+	phy_write_reg(pcie, 0, 0x44, 0x1, 0x015C0014);
+	phy_write_reg(pcie, 1, 0x44, 0x1, 0x015C0014);
+	phy_write_reg(pcie, 1, 0x4C, 0x1, 0x786174A0);
+	phy_write_reg(pcie, 1, 0x4D, 0x1, 0x048000BB);
+	phy_write_reg(pcie, 0, 0x51, 0x1, 0x079EC062);
+	phy_write_reg(pcie, 0, 0x52, 0x1, 0x20000000);
+	phy_write_reg(pcie, 1, 0x52, 0x1, 0x20000000);
+	phy_write_reg(pcie, 1, 0x56, 0x1, 0x00003806);
+
+	phy_write_reg(pcie, 0, 0x60, 0x1, 0x004B03A5);
+	phy_write_reg(pcie, 0, 0x64, 0x1, 0x3F0F1F0F);
+	phy_write_reg(pcie, 0, 0x66, 0x1, 0x00008000);
+
+	while (timeout--) {
+		if (pci_read_reg(pcie, H1_PCIEPHYSR))
+			return rcar_pcie_hw_init(pcie);
+
+		msleep(5);
+	}
+
+	return -ETIMEDOUT;
+}
+
+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;
+
+	pcie->clk = devm_clk_get(&pdev->dev, "pcie");
+	if (IS_ERR(pcie->clk)) {
+		dev_err(pcie->dev, "cannot get platform clock\n");
+		return PTR_ERR(pcie->clk);
+	}
+	err = clk_prepare_enable(pcie->clk);
+	if (err)
+		goto fail_clk;
+
+	pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
+	if (IS_ERR(pcie->bus_clk)) {
+		dev_err(pcie->dev, "cannot get pcie bus clock\n");
+		err = PTR_ERR(pcie->bus_clk);
+		goto fail_clk;
+	}
+	err = clk_prepare_enable(pcie->bus_clk);
+	if (err)
+		goto err_map_reg;
+
+	pcie->base = devm_ioremap_resource(&pdev->dev, &res);
+	if (IS_ERR(pcie->base)) {
+		err = PTR_ERR(pcie->base);
+		goto err_map_reg;
+	}
+
+	return 0;
+
+err_map_reg:
+	clk_disable_unprepare(pcie->bus_clk);
+fail_clk:
+	clk_disable_unprepare(pcie->clk);
+
+	return err;
+}
+
+static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
+				    struct of_pci_range *range,
+				    int *index)
+{
+	u64 restype = range->flags;
+	u64 cpu_addr = range->cpu_addr;
+	u64 cpu_end = range->cpu_addr + range->size;
+	u64 pci_addr = range->pci_addr;
+	u32 flags = LAM_64BIT | LAR_ENABLE;
+	u64 mask;
+	u64 size;
+	int idx = *index;
+
+	if (restype & IORESOURCE_PREFETCH)
+		flags |= LAM_PREFETCH;
+
+	/*
+	 * If the size of the range is larger than the alignment of the start
+	 * address, we have to use multiple entries to perform the mapping.
+	 */
+	if (cpu_addr > 0) {
+		unsigned long nr_zeros = __ffs64(cpu_addr);
+		u64 alignment = 1ULL << nr_zeros;
+		size = min(range->size, alignment);
+	} else {
+		size = range->size;
+	}
+	/* Hardware supports max 4GiB inbound region */
+	size = min(size, 1ULL << 32);
+
+	mask = roundup_pow_of_two(size) - 1;
+	mask &= ~0xf;
+
+	while (cpu_addr < cpu_end) {
+		/*
+		 * Set up 64-bit inbound regions as the range parser doesn't
+		 * distinguish between 32 and 64-bit types.
+		 */
+		pci_write_reg(pcie, lower_32_bits(pci_addr), PCIEPRAR(idx));
+		pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx));
+		pci_write_reg(pcie, lower_32_bits(mask) | flags, PCIELAMR(idx));
+
+		pci_write_reg(pcie, upper_32_bits(pci_addr), PCIEPRAR(idx+1));
+		pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx+1));
+		pci_write_reg(pcie, 0, PCIELAMR(idx+1));
+
+		pci_addr += size;
+		cpu_addr += size;
+		idx += 2;
+
+		if (idx > MAX_NR_INBOUND_MAPS) {
+			dev_err(pcie->dev, "Failed to map inbound regions!\n");
+			return -EINVAL;
+		}
+	}
+	*index = idx;
+
+	return 0;
+}
+
+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+				     struct device_node *node)
+{
+	const int na = 3, ns = 2;
+	int rlen;
+
+	parser->node = node;
+	parser->pna = of_n_addr_cells(node);
+	parser->np = parser->pna + na + ns;
+
+	parser->range = of_get_property(node, "dma-ranges", &rlen);
+	if (!parser->range)
+		return -ENOENT;
+
+	parser->end = parser->range + rlen / sizeof(__be32);
+	return 0;
+}
+
+static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
+					  struct device_node *np)
+{
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	int index = 0;
+	int err;
+
+	if (pci_dma_range_parser_init(&parser, np))
+		return -EINVAL;
+
+	/* Get the dma-ranges from DT */
+	for_each_of_pci_range(&parser, &range) {
+		u64 end = range.cpu_addr + range.size - 1;
+		dev_dbg(pcie->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
+			range.flags, range.cpu_addr, end, range.pci_addr);
+
+		err = rcar_pcie_inbound_ranges(pcie, &range, &index);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id rcar_pcie_of_match[] = {
+	{ .compatible = "renesas,pcie-r8a7779", .data = rcar_pcie_hw_init_h1 },
+	{ .compatible = "renesas,pcie-r8a7790", .data = rcar_pcie_hw_init },
+	{ .compatible = "renesas,pcie-r8a7791", .data = rcar_pcie_hw_init },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rcar_pcie_of_match);
+
+static int __init rcar_pcie_probe(struct platform_device *pdev)
+{
+	struct rcar_pcie *pcie;
+	unsigned int data;
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	const struct of_device_id *of_id;
+	int err, win = 0;
+	int (*hw_init_fn)(struct rcar_pcie *);
+
+	pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+		return -ENOMEM;
+
+	pcie->dev = &pdev->dev;
+	platform_set_drvdata(pdev, pcie);
+
+	if (of_pci_range_parser_init(&parser, pdev->dev.of_node)) {
+		dev_err(&pdev->dev, "missing ranges property\n");
+		return -EINVAL;
+	}
+
+	err = rcar_pcie_get_resources(pdev, pcie);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to request resources: %d\n", err);
+		return err;
+	}
+
+	for_each_of_pci_range(&parser, &range) {
+		of_pci_range_to_resource(&range, pdev->dev.of_node,
+						&pcie->res[win++]);
+
+		if (win > PCI_MAX_RESOURCES)
+			break;
+	}
+
+	 err = rcar_pcie_parse_map_dma_ranges(pcie, pdev->dev.of_node);
+	 if (err)
+		return err;
+
+	of_id = of_match_device(rcar_pcie_of_match, pcie->dev);
+	if (!of_id || !of_id->data)
+		return -EINVAL;
+	hw_init_fn = of_id->data;
+
+	/* Failure to get a link might just be that no cards are inserted */
+	err = hw_init_fn(pcie);
+	if (err) {
+		dev_info(&pdev->dev, "PCIe link down\n");
+		return 0;
+	}
+
+	data = pci_read_reg(pcie, MACSR);
+	dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
+
+	rcar_pcie_enable(pcie);
+
+	return 0;
+}
+
+static struct platform_driver rcar_pcie_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = rcar_pcie_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = rcar_pcie_probe,
+};
+module_platform_driver(rcar_pcie_driver);
+
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
new file mode 100644
index 0000000..3dc026b
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.h
@@ -0,0 +1,82 @@
+/*
+ * PCI Express definitions for Renesas R-Car SoCs
+ */
+#ifndef __PCI_RCAR_H
+#define __PCI_RCAR_H
+
+#define PCIECAR			0x000010
+#define PCIECCTLR		0x000018
+#define  CONFIG_SEND_ENABLE	(1 << 31)
+#define  TYPE0			(0 << 8)
+#define  TYPE1			(1 << 8)
+#define PCIECDR			0x000020
+#define PCIEMSR			0x000028
+#define PCIEINTXR		0x000400
+#define PCIEPHYSR		0x0007f0
+
+/* Transfer control */
+#define PCIETCTLR		0x02000
+#define  CFINIT			1
+#define PCIETSTR		0x02004
+#define  DATA_LINK_ACTIVE	1
+#define PCIEINTR		0x02008
+#define PCIEINTER		0x0200c
+#define PCIEERRFR		0x02020
+#define  UNSUPPORTED_REQUEST	(1 << 4)
+#define PCIEERRFER		0x02024
+#define PCIEERRFR2		0x02028
+#define PCIEPMSR		0x02034
+#define PCIEPMSCIER		0x02038
+#define PCIEMSIFR		0x02044
+
+/* root port address */
+#define PCIEPRAR(x)		(0x02080 + ((x) * 0x4))
+
+/* local address reg & mask */
+#define PCIELAR(x)		(0x02200 + ((x) * 0x20))
+#define PCIELAMR(x)		(0x02208 + ((x) * 0x20))
+#define  LAM_PMIOLAMnB3		(1 << 3)
+#define  LAM_PMIOLAMnB2		(1 << 2)
+#define  LAM_PREFETCH		(1 << 3)
+#define  LAM_64BIT		(1 << 2)
+#define  LAR_ENABLE		(1 << 1)
+
+/* PCIe address reg & mask */
+#define PCIEPARL(x)		(0x03400 + ((x) * 0x20))
+#define PCIEPARH(x)		(0x03404 + ((x) * 0x20))
+#define PCIEPAMR(x)		(0x03408 + ((x) * 0x20))
+#define PCIEPTCTLR(x)		(0x0340c + ((x) * 0x20))
+#define  PAR_ENABLE		(1 << 31)
+#define  IO_SPACE		(1 << 8)
+
+/* Configuration */
+#define PCICONF(x)		(0x010000 + ((x) * 0x4))
+#define PMCAP(x)		(0x010040 + ((x) * 0x4))
+#define MSICAP(x)		(0x010050 + ((x) * 0x4))
+#define EXPCAP(x)		(0x010070 + ((x) * 0x4))
+#define VCCAP(x)		(0x010100 + ((x) * 0x4))
+#define SERNUMCAP(x)		(0x0101b0 + ((x) * 0x4))
+
+/* link layer */
+#define IDSETR0			0x011000
+#define IDSETR1			0x011004
+#define SUBIDSETR		0x011024
+#define DSERSETR0		0x01102c
+#define DSERSETR1		0x011030
+#define TLCTLR			0x011048
+#define MACSR			0x011054
+#define MACCTLR			0x011058
+#define  SCRAMBLE_DISABLE	(1 << 27)
+
+/* R-Car H1 PHY */
+#define H1_PCIEPHYCTLR		0x040008
+#define H1_PCIEPHYADRR		0x04000c
+#define  WRITE_CMD		(1 << 16)
+#define  PHY_ACK		(1 << 24)
+#define  RATE_POS		12
+#define  LANE_POS		8
+#define  ADR_POS		0
+#define H1_PCIEPHYDOUTR		0x040014
+#define H1_PCIEPHYSR		0x040018
+
+#endif /* __PCI_RCAR_H */
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

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

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 47d46c6..dc627e5 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -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
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..19946f9 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -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
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
new file mode 100644
index 0000000..c22c896
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.c
@@ -0,0 +1,693 @@
+/*
+ * PCIe driver for Renesas R-Car SoCs
+ *  Copyright (C) 2014 Renesas Electronics Europe Ltd
+ *
+ * Based on:
+ *  arch/sh/drivers/pci/pcie-sh7786.c
+ *  arch/sh/drivers/pci/ops-sh7786.c
+ *  Copyright (C) 2009 - 2011  Paul Mundt
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "pcie-rcar.h"
+
+#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 {
+	struct device		*dev;
+	void __iomem		*base;
+	struct resource		res[PCI_MAX_RESOURCES];
+	u8			root_bus_nr;
+	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)
+{
+	writel(val, pcie->base + reg);
+}
+
+static unsigned long
+pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
+{
+	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)
+{
+	int shift = 8 * (where & 3);
+	u32 val = pci_read_reg(pcie, where & ~3);
+	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);
+	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;
+
+	if (bus->number > 255 || dev > 31 || func > 7)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	/*
+	 * While each channel has its own memory-mapped extended config
+	 * space, it's generally only accessible when in endpoint mode.
+	 * When in root complex mode, the controller is unable to target
+	 * itself with either type 0 or type 1 accesses, and indeed, any
+	 * controller initiated target transfer to its own config space
+	 * result in a completer abort.
+	 *
+	 * Each channel effectively only supports a single device, but as
+	 * the same channel <-> device access works for any PCI_SLOT()
+	 * value, we cheat a bit here and bind the controller's config
+	 * space to devfn 0 in order to enable self-enumeration. In this
+	 * case the regular ECAR/ECDR path is sidelined and the mangled
+	 * config access itself is initiated as an internal bus  transaction.
+	 */
+	if (pci_is_root_bus(bus)) {
+		if (dev != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		if (access_type == PCI_ACCESS_READ)
+			*data = pci_read_reg(pcie, PCICONF(index));
+		else
+			pci_write_reg(pcie, *data, PCICONF(index));
+
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	/* 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)) &
+		(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);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
+				int where, int size, u32 *val)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+	int ret;
+
+	if ((size == 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size == 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+				      bus, devfn, where, val);
+	if (ret != PCIBIOS_SUCCESSFUL) {
+		*val = 0xffffffff;
+		return ret;
+	}
+
+	if (size == 1)
+		*val = (*val >> (8 * (where & 3))) & 0xff;
+	else if (size == 2)
+		*val = (*val >> (8 * (where & 2))) & 0xffff;
+
+	dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
+		"where=0x%04x size=%d val=0x%08lx\n", bus->number,
+		devfn, where, size, (unsigned long)*val);
+
+	return ret;
+}
+
+static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 val)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+	int shift, ret;
+	u32 data;
+
+	if ((size == 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size == 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+				      bus, devfn, where, &data);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
+
+	dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
+		"where=0x%04x size=%d val=0x%08lx\n", bus->number,
+		devfn, where, size, (unsigned long)val);
+
+	if (size == 1) {
+		shift = 8 * (where & 3);
+		data &= ~(0xff << shift);
+		data |= ((val & 0xff) << shift);
+	} else if (size == 2) {
+		shift = 8 * (where & 2);
+		data &= ~(0xffff << shift);
+		data |= ((val & 0xffff) << shift);
+	} else
+		data = val;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_WRITE,
+				      bus, devfn, where, &data);
+
+	return ret;
+}
+
+static struct pci_ops rcar_pcie_ops = {
+	.read	= rcar_pcie_read_conf,
+	.write	= rcar_pcie_write_conf,
+};
+
+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;
+	if (res->flags & IORESOURCE_IO)
+		mask |= IO_SPACE;
+
+	pci_write_reg(pcie, mask, PCIEPTCTLR(win));
+
+	return 0;
+}
+
+static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(sys);
+	struct resource *res;
+	int i;
+
+	pcie->root_bus_nr = sys->busnr;
+
+	/* Setup PCI resources */
+	for (i = 0; i < PCI_MAX_RESOURCES; i++) {
+
+		res = &pcie->res[i];
+		if (!res->flags)
+			continue;
+
+		rcar_pcie_setup_window(i, res, pcie);
+
+		if (res->flags & IORESOURCE_IO)
+			pci_ioremap_io(nr * SZ_64K, res->start);
+		else
+			pci_add_resource(&sys->resources, res);
+	}
+
+	return 1;
+}
+
+static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
+{
+	struct platform_device *pdev = to_platform_device(pcie->dev);
+	struct hw_pci hw = {
+		.nr_controllers = 1,
+		.private_data   = (void **)&pcie,
+		.setup          = rcar_pcie_setup,
+		.map_irq        = of_irq_parse_and_map_pci,
+		.ops            = &rcar_pcie_ops,
+	};
+
+	pci_common_init_dev(&pdev->dev, &hw);
+}
+
+static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 100;
+
+	while (timeout--) {
+		if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
+			return 0;
+
+		udelay(100);
+	}
+
+	dev_err(pcie->dev, "Access to PCIe phy timed out\n");
+
+	return -ETIMEDOUT;
+}
+
+static void __init phy_write_reg(struct rcar_pcie *pcie,
+				 unsigned int rate, unsigned int addr,
+				 unsigned int lane, unsigned int data)
+{
+	unsigned long phyaddr;
+
+	phyaddr = WRITE_CMD |
+		((rate & 1) << RATE_POS) |
+		((lane & 0xf) << LANE_POS) |
+		((addr & 0xff) << ADR_POS);
+
+	/* Set write data */
+	pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
+	pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
+
+	/* Ignore errors as they will be dealt with if the data link is down */
+	phy_wait_for_ack(pcie);
+
+	/* Clear command */
+	pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
+	pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
+
+	/* Ignore errors as they will be dealt with if the data link is down */
+	phy_wait_for_ack(pcie);
+}
+
+static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 10;
+
+	while (timeout--) {
+		if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
+			return 0;
+
+		msleep(5);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
+{
+	int err;
+
+	/* Begin initialization */
+	pci_write_reg(pcie, 0, PCIETCTLR);
+
+	/* Set mode */
+	pci_write_reg(pcie, 1, PCIEMSR);
+
+	/*
+	 * Initial header for port config space is type 1, set the device
+	 * class to match. Hardware takes care of propagating the IDSETR
+	 * settings, so there is no need to bother with a quirk.
+	 */
+	pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
+
+	/*
+	 * Setup Secondary Bus Number & Subordinate Bus Number, even though
+	 * they aren't used, to avoid bridge being detected as broken.
+	 */
+	rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
+	rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
+
+	/* Initialize default capabilities. */
+	rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
+		PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
+	rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
+		PCI_HEADER_TYPE_BRIDGE);
+
+	/* Enable data link layer active state reporting */
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0, PCI_EXP_LNKCAP_DLLLARC);
+
+	/* Write out the physical slot number = 0 */
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
+
+	/* Set the completion timer timeout to the maximum 50ms. */
+	rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
+
+	/* Terminate list of capabilities (Next Capability Offset=0) */
+	rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
+
+	/* Enable MAC data scrambling. */
+	rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
+
+	/* Finish initialization - establish a PCI Express link */
+	pci_write_reg(pcie, CFINIT, PCIETCTLR);
+
+	/* This will timeout if we don't have a link. */
+	err = rcar_pcie_wait_for_dl(pcie);
+	if (err)
+		return err;
+
+	/* Enable INTx interrupts */
+	rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
+
+	/* Enable slave Bus Mastering */
+	rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
+		PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+		PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
+
+	wmb();
+
+	return 0;
+}
+
+static int __init rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 10;
+
+	/* Initialize the phy */
+	phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
+	phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180);
+	phy_write_reg(pcie, 0, 0x43, 0x1, 0x00210188);
+	phy_write_reg(pcie, 1, 0x43, 0x1, 0x00210188);
+	phy_write_reg(pcie, 0, 0x44, 0x1, 0x015C0014);
+	phy_write_reg(pcie, 1, 0x44, 0x1, 0x015C0014);
+	phy_write_reg(pcie, 1, 0x4C, 0x1, 0x786174A0);
+	phy_write_reg(pcie, 1, 0x4D, 0x1, 0x048000BB);
+	phy_write_reg(pcie, 0, 0x51, 0x1, 0x079EC062);
+	phy_write_reg(pcie, 0, 0x52, 0x1, 0x20000000);
+	phy_write_reg(pcie, 1, 0x52, 0x1, 0x20000000);
+	phy_write_reg(pcie, 1, 0x56, 0x1, 0x00003806);
+
+	phy_write_reg(pcie, 0, 0x60, 0x1, 0x004B03A5);
+	phy_write_reg(pcie, 0, 0x64, 0x1, 0x3F0F1F0F);
+	phy_write_reg(pcie, 0, 0x66, 0x1, 0x00008000);
+
+	while (timeout--) {
+		if (pci_read_reg(pcie, H1_PCIEPHYSR))
+			return rcar_pcie_hw_init(pcie);
+
+		msleep(5);
+	}
+
+	return -ETIMEDOUT;
+}
+
+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;
+
+	pcie->clk = devm_clk_get(&pdev->dev, "pcie");
+	if (IS_ERR(pcie->clk)) {
+		dev_err(pcie->dev, "cannot get platform clock\n");
+		return PTR_ERR(pcie->clk);
+	}
+	err = clk_prepare_enable(pcie->clk);
+	if (err)
+		goto fail_clk;
+
+	pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
+	if (IS_ERR(pcie->bus_clk)) {
+		dev_err(pcie->dev, "cannot get pcie bus clock\n");
+		err = PTR_ERR(pcie->bus_clk);
+		goto fail_clk;
+	}
+	err = clk_prepare_enable(pcie->bus_clk);
+	if (err)
+		goto err_map_reg;
+
+	pcie->base = devm_ioremap_resource(&pdev->dev, &res);
+	if (IS_ERR(pcie->base)) {
+		err = PTR_ERR(pcie->base);
+		goto err_map_reg;
+	}
+
+	return 0;
+
+err_map_reg:
+	clk_disable_unprepare(pcie->bus_clk);
+fail_clk:
+	clk_disable_unprepare(pcie->clk);
+
+	return err;
+}
+
+static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
+				    struct of_pci_range *range,
+				    int *index)
+{
+	u64 restype = range->flags;
+	u64 cpu_addr = range->cpu_addr;
+	u64 cpu_end = range->cpu_addr + range->size;
+	u64 pci_addr = range->pci_addr;
+	u32 flags = LAM_64BIT | LAR_ENABLE;
+	u64 mask;
+	u64 size;
+	int idx = *index;
+
+	if (restype & IORESOURCE_PREFETCH)
+		flags |= LAM_PREFETCH;
+
+	/*
+	 * If the size of the range is larger than the alignment of the start
+	 * address, we have to use multiple entries to perform the mapping.
+	 */
+	if (cpu_addr > 0) {
+		unsigned long nr_zeros = __ffs64(cpu_addr);
+		u64 alignment = 1ULL << nr_zeros;
+		size = min(range->size, alignment);
+	} else {
+		size = range->size;
+	}
+	/* Hardware supports max 4GiB inbound region */
+	size = min(size, 1ULL << 32);
+
+	mask = roundup_pow_of_two(size) - 1;
+	mask &= ~0xf;
+
+	while (cpu_addr < cpu_end) {
+		/*
+		 * Set up 64-bit inbound regions as the range parser doesn't
+		 * distinguish between 32 and 64-bit types.
+		 */
+		pci_write_reg(pcie, lower_32_bits(pci_addr), PCIEPRAR(idx));
+		pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx));
+		pci_write_reg(pcie, lower_32_bits(mask) | flags, PCIELAMR(idx));
+
+		pci_write_reg(pcie, upper_32_bits(pci_addr), PCIEPRAR(idx+1));
+		pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx+1));
+		pci_write_reg(pcie, 0, PCIELAMR(idx+1));
+
+		pci_addr += size;
+		cpu_addr += size;
+		idx += 2;
+
+		if (idx > MAX_NR_INBOUND_MAPS) {
+			dev_err(pcie->dev, "Failed to map inbound regions!\n");
+			return -EINVAL;
+		}
+	}
+	*index = idx;
+
+	return 0;
+}
+
+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+				     struct device_node *node)
+{
+	const int na = 3, ns = 2;
+	int rlen;
+
+	parser->node = node;
+	parser->pna = of_n_addr_cells(node);
+	parser->np = parser->pna + na + ns;
+
+	parser->range = of_get_property(node, "dma-ranges", &rlen);
+	if (!parser->range)
+		return -ENOENT;
+
+	parser->end = parser->range + rlen / sizeof(__be32);
+	return 0;
+}
+
+static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
+					  struct device_node *np)
+{
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	int index = 0;
+	int err;
+
+	if (pci_dma_range_parser_init(&parser, np))
+		return -EINVAL;
+
+	/* Get the dma-ranges from DT */
+	for_each_of_pci_range(&parser, &range) {
+		u64 end = range.cpu_addr + range.size - 1;
+		dev_dbg(pcie->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
+			range.flags, range.cpu_addr, end, range.pci_addr);
+
+		err = rcar_pcie_inbound_ranges(pcie, &range, &index);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id rcar_pcie_of_match[] = {
+	{ .compatible = "renesas,pcie-r8a7779", .data = rcar_pcie_hw_init_h1 },
+	{ .compatible = "renesas,pcie-r8a7790", .data = rcar_pcie_hw_init },
+	{ .compatible = "renesas,pcie-r8a7791", .data = rcar_pcie_hw_init },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rcar_pcie_of_match);
+
+static int __init rcar_pcie_probe(struct platform_device *pdev)
+{
+	struct rcar_pcie *pcie;
+	unsigned int data;
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	const struct of_device_id *of_id;
+	int err, win = 0;
+	int (*hw_init_fn)(struct rcar_pcie *);
+
+	pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+		return -ENOMEM;
+
+	pcie->dev = &pdev->dev;
+	platform_set_drvdata(pdev, pcie);
+
+	if (of_pci_range_parser_init(&parser, pdev->dev.of_node)) {
+		dev_err(&pdev->dev, "missing ranges property\n");
+		return -EINVAL;
+	}
+
+	err = rcar_pcie_get_resources(pdev, pcie);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to request resources: %d\n", err);
+		return err;
+	}
+
+	for_each_of_pci_range(&parser, &range) {
+		of_pci_range_to_resource(&range, pdev->dev.of_node,
+						&pcie->res[win++]);
+
+		if (win > PCI_MAX_RESOURCES)
+			break;
+	}
+
+	 err = rcar_pcie_parse_map_dma_ranges(pcie, pdev->dev.of_node);
+	 if (err)
+		return err;
+
+	of_id = of_match_device(rcar_pcie_of_match, pcie->dev);
+	if (!of_id || !of_id->data)
+		return -EINVAL;
+	hw_init_fn = of_id->data;
+
+	/* Failure to get a link might just be that no cards are inserted */
+	err = hw_init_fn(pcie);
+	if (err) {
+		dev_info(&pdev->dev, "PCIe link down\n");
+		return 0;
+	}
+
+	data = pci_read_reg(pcie, MACSR);
+	dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
+
+	rcar_pcie_enable(pcie);
+
+	return 0;
+}
+
+static struct platform_driver rcar_pcie_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = rcar_pcie_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = rcar_pcie_probe,
+};
+module_platform_driver(rcar_pcie_driver);
+
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
new file mode 100644
index 0000000..3dc026b
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.h
@@ -0,0 +1,82 @@
+/*
+ * PCI Express definitions for Renesas R-Car SoCs
+ */
+#ifndef __PCI_RCAR_H
+#define __PCI_RCAR_H
+
+#define PCIECAR			0x000010
+#define PCIECCTLR		0x000018
+#define  CONFIG_SEND_ENABLE	(1 << 31)
+#define  TYPE0			(0 << 8)
+#define  TYPE1			(1 << 8)
+#define PCIECDR			0x000020
+#define PCIEMSR			0x000028
+#define PCIEINTXR		0x000400
+#define PCIEPHYSR		0x0007f0
+
+/* Transfer control */
+#define PCIETCTLR		0x02000
+#define  CFINIT			1
+#define PCIETSTR		0x02004
+#define  DATA_LINK_ACTIVE	1
+#define PCIEINTR		0x02008
+#define PCIEINTER		0x0200c
+#define PCIEERRFR		0x02020
+#define  UNSUPPORTED_REQUEST	(1 << 4)
+#define PCIEERRFER		0x02024
+#define PCIEERRFR2		0x02028
+#define PCIEPMSR		0x02034
+#define PCIEPMSCIER		0x02038
+#define PCIEMSIFR		0x02044
+
+/* root port address */
+#define PCIEPRAR(x)		(0x02080 + ((x) * 0x4))
+
+/* local address reg & mask */
+#define PCIELAR(x)		(0x02200 + ((x) * 0x20))
+#define PCIELAMR(x)		(0x02208 + ((x) * 0x20))
+#define  LAM_PMIOLAMnB3		(1 << 3)
+#define  LAM_PMIOLAMnB2		(1 << 2)
+#define  LAM_PREFETCH		(1 << 3)
+#define  LAM_64BIT		(1 << 2)
+#define  LAR_ENABLE		(1 << 1)
+
+/* PCIe address reg & mask */
+#define PCIEPARL(x)		(0x03400 + ((x) * 0x20))
+#define PCIEPARH(x)		(0x03404 + ((x) * 0x20))
+#define PCIEPAMR(x)		(0x03408 + ((x) * 0x20))
+#define PCIEPTCTLR(x)		(0x0340c + ((x) * 0x20))
+#define  PAR_ENABLE		(1 << 31)
+#define  IO_SPACE		(1 << 8)
+
+/* Configuration */
+#define PCICONF(x)		(0x010000 + ((x) * 0x4))
+#define PMCAP(x)		(0x010040 + ((x) * 0x4))
+#define MSICAP(x)		(0x010050 + ((x) * 0x4))
+#define EXPCAP(x)		(0x010070 + ((x) * 0x4))
+#define VCCAP(x)		(0x010100 + ((x) * 0x4))
+#define SERNUMCAP(x)		(0x0101b0 + ((x) * 0x4))
+
+/* link layer */
+#define IDSETR0			0x011000
+#define IDSETR1			0x011004
+#define SUBIDSETR		0x011024
+#define DSERSETR0		0x01102c
+#define DSERSETR1		0x011030
+#define TLCTLR			0x011048
+#define MACSR			0x011054
+#define MACCTLR			0x011058
+#define  SCRAMBLE_DISABLE	(1 << 27)
+
+/* R-Car H1 PHY */
+#define H1_PCIEPHYCTLR		0x040008
+#define H1_PCIEPHYADRR		0x04000c
+#define  WRITE_CMD		(1 << 16)
+#define  PHY_ACK		(1 << 24)
+#define  RATE_POS		12
+#define  LANE_POS		8
+#define  ADR_POS		0
+#define H1_PCIEPHYDOUTR		0x040014
+#define H1_PCIEPHYSR		0x040018
+
+#endif /* __PCI_RCAR_H */
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 47d46c6..dc627e5 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -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
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..19946f9 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -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
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
new file mode 100644
index 0000000..c22c896
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.c
@@ -0,0 +1,693 @@
+/*
+ * PCIe driver for Renesas R-Car SoCs
+ *  Copyright (C) 2014 Renesas Electronics Europe Ltd
+ *
+ * Based on:
+ *  arch/sh/drivers/pci/pcie-sh7786.c
+ *  arch/sh/drivers/pci/ops-sh7786.c
+ *  Copyright (C) 2009 - 2011  Paul Mundt
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "pcie-rcar.h"
+
+#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 {
+	struct device		*dev;
+	void __iomem		*base;
+	struct resource		res[PCI_MAX_RESOURCES];
+	u8			root_bus_nr;
+	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)
+{
+	writel(val, pcie->base + reg);
+}
+
+static unsigned long
+pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
+{
+	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)
+{
+	int shift = 8 * (where & 3);
+	u32 val = pci_read_reg(pcie, where & ~3);
+	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);
+	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;
+
+	if (bus->number > 255 || dev > 31 || func > 7)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	/*
+	 * While each channel has its own memory-mapped extended config
+	 * space, it's generally only accessible when in endpoint mode.
+	 * When in root complex mode, the controller is unable to target
+	 * itself with either type 0 or type 1 accesses, and indeed, any
+	 * controller initiated target transfer to its own config space
+	 * result in a completer abort.
+	 *
+	 * Each channel effectively only supports a single device, but as
+	 * the same channel <-> device access works for any PCI_SLOT()
+	 * value, we cheat a bit here and bind the controller's config
+	 * space to devfn 0 in order to enable self-enumeration. In this
+	 * case the regular ECAR/ECDR path is sidelined and the mangled
+	 * config access itself is initiated as an internal bus  transaction.
+	 */
+	if (pci_is_root_bus(bus)) {
+		if (dev != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		if (access_type == PCI_ACCESS_READ)
+			*data = pci_read_reg(pcie, PCICONF(index));
+		else
+			pci_write_reg(pcie, *data, PCICONF(index));
+
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	/* 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)) &
+		(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);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
+				int where, int size, u32 *val)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+	int ret;
+
+	if ((size == 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size == 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+				      bus, devfn, where, val);
+	if (ret != PCIBIOS_SUCCESSFUL) {
+		*val = 0xffffffff;
+		return ret;
+	}
+
+	if (size == 1)
+		*val = (*val >> (8 * (where & 3))) & 0xff;
+	else if (size == 2)
+		*val = (*val >> (8 * (where & 2))) & 0xffff;
+
+	dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
+		"where=0x%04x size=%d val=0x%08lx\n", bus->number,
+		devfn, where, size, (unsigned long)*val);
+
+	return ret;
+}
+
+static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 val)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+	int shift, ret;
+	u32 data;
+
+	if ((size == 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size == 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+				      bus, devfn, where, &data);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
+
+	dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
+		"where=0x%04x size=%d val=0x%08lx\n", bus->number,
+		devfn, where, size, (unsigned long)val);
+
+	if (size == 1) {
+		shift = 8 * (where & 3);
+		data &= ~(0xff << shift);
+		data |= ((val & 0xff) << shift);
+	} else if (size == 2) {
+		shift = 8 * (where & 2);
+		data &= ~(0xffff << shift);
+		data |= ((val & 0xffff) << shift);
+	} else
+		data = val;
+
+	ret = rcar_pcie_config_access(pcie, PCI_ACCESS_WRITE,
+				      bus, devfn, where, &data);
+
+	return ret;
+}
+
+static struct pci_ops rcar_pcie_ops = {
+	.read	= rcar_pcie_read_conf,
+	.write	= rcar_pcie_write_conf,
+};
+
+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;
+	if (res->flags & IORESOURCE_IO)
+		mask |= IO_SPACE;
+
+	pci_write_reg(pcie, mask, PCIEPTCTLR(win));
+
+	return 0;
+}
+
+static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct rcar_pcie *pcie = sys_to_pcie(sys);
+	struct resource *res;
+	int i;
+
+	pcie->root_bus_nr = sys->busnr;
+
+	/* Setup PCI resources */
+	for (i = 0; i < PCI_MAX_RESOURCES; i++) {
+
+		res = &pcie->res[i];
+		if (!res->flags)
+			continue;
+
+		rcar_pcie_setup_window(i, res, pcie);
+
+		if (res->flags & IORESOURCE_IO)
+			pci_ioremap_io(nr * SZ_64K, res->start);
+		else
+			pci_add_resource(&sys->resources, res);
+	}
+
+	return 1;
+}
+
+static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
+{
+	struct platform_device *pdev = to_platform_device(pcie->dev);
+	struct hw_pci hw = {
+		.nr_controllers = 1,
+		.private_data   = (void **)&pcie,
+		.setup          = rcar_pcie_setup,
+		.map_irq        = of_irq_parse_and_map_pci,
+		.ops            = &rcar_pcie_ops,
+	};
+
+	pci_common_init_dev(&pdev->dev, &hw);
+}
+
+static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 100;
+
+	while (timeout--) {
+		if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
+			return 0;
+
+		udelay(100);
+	}
+
+	dev_err(pcie->dev, "Access to PCIe phy timed out\n");
+
+	return -ETIMEDOUT;
+}
+
+static void __init phy_write_reg(struct rcar_pcie *pcie,
+				 unsigned int rate, unsigned int addr,
+				 unsigned int lane, unsigned int data)
+{
+	unsigned long phyaddr;
+
+	phyaddr = WRITE_CMD |
+		((rate & 1) << RATE_POS) |
+		((lane & 0xf) << LANE_POS) |
+		((addr & 0xff) << ADR_POS);
+
+	/* Set write data */
+	pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
+	pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
+
+	/* Ignore errors as they will be dealt with if the data link is down */
+	phy_wait_for_ack(pcie);
+
+	/* Clear command */
+	pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
+	pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
+
+	/* Ignore errors as they will be dealt with if the data link is down */
+	phy_wait_for_ack(pcie);
+}
+
+static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 10;
+
+	while (timeout--) {
+		if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
+			return 0;
+
+		msleep(5);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
+{
+	int err;
+
+	/* Begin initialization */
+	pci_write_reg(pcie, 0, PCIETCTLR);
+
+	/* Set mode */
+	pci_write_reg(pcie, 1, PCIEMSR);
+
+	/*
+	 * Initial header for port config space is type 1, set the device
+	 * class to match. Hardware takes care of propagating the IDSETR
+	 * settings, so there is no need to bother with a quirk.
+	 */
+	pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
+
+	/*
+	 * Setup Secondary Bus Number & Subordinate Bus Number, even though
+	 * they aren't used, to avoid bridge being detected as broken.
+	 */
+	rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
+	rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
+
+	/* Initialize default capabilities. */
+	rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
+		PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
+	rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
+		PCI_HEADER_TYPE_BRIDGE);
+
+	/* Enable data link layer active state reporting */
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0, PCI_EXP_LNKCAP_DLLLARC);
+
+	/* Write out the physical slot number = 0 */
+	rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
+
+	/* Set the completion timer timeout to the maximum 50ms. */
+	rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
+
+	/* Terminate list of capabilities (Next Capability Offset=0) */
+	rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
+
+	/* Enable MAC data scrambling. */
+	rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
+
+	/* Finish initialization - establish a PCI Express link */
+	pci_write_reg(pcie, CFINIT, PCIETCTLR);
+
+	/* This will timeout if we don't have a link. */
+	err = rcar_pcie_wait_for_dl(pcie);
+	if (err)
+		return err;
+
+	/* Enable INTx interrupts */
+	rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
+
+	/* Enable slave Bus Mastering */
+	rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
+		PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+		PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
+
+	wmb();
+
+	return 0;
+}
+
+static int __init rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)
+{
+	unsigned int timeout = 10;
+
+	/* Initialize the phy */
+	phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
+	phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180);
+	phy_write_reg(pcie, 0, 0x43, 0x1, 0x00210188);
+	phy_write_reg(pcie, 1, 0x43, 0x1, 0x00210188);
+	phy_write_reg(pcie, 0, 0x44, 0x1, 0x015C0014);
+	phy_write_reg(pcie, 1, 0x44, 0x1, 0x015C0014);
+	phy_write_reg(pcie, 1, 0x4C, 0x1, 0x786174A0);
+	phy_write_reg(pcie, 1, 0x4D, 0x1, 0x048000BB);
+	phy_write_reg(pcie, 0, 0x51, 0x1, 0x079EC062);
+	phy_write_reg(pcie, 0, 0x52, 0x1, 0x20000000);
+	phy_write_reg(pcie, 1, 0x52, 0x1, 0x20000000);
+	phy_write_reg(pcie, 1, 0x56, 0x1, 0x00003806);
+
+	phy_write_reg(pcie, 0, 0x60, 0x1, 0x004B03A5);
+	phy_write_reg(pcie, 0, 0x64, 0x1, 0x3F0F1F0F);
+	phy_write_reg(pcie, 0, 0x66, 0x1, 0x00008000);
+
+	while (timeout--) {
+		if (pci_read_reg(pcie, H1_PCIEPHYSR))
+			return rcar_pcie_hw_init(pcie);
+
+		msleep(5);
+	}
+
+	return -ETIMEDOUT;
+}
+
+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;
+
+	pcie->clk = devm_clk_get(&pdev->dev, "pcie");
+	if (IS_ERR(pcie->clk)) {
+		dev_err(pcie->dev, "cannot get platform clock\n");
+		return PTR_ERR(pcie->clk);
+	}
+	err = clk_prepare_enable(pcie->clk);
+	if (err)
+		goto fail_clk;
+
+	pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
+	if (IS_ERR(pcie->bus_clk)) {
+		dev_err(pcie->dev, "cannot get pcie bus clock\n");
+		err = PTR_ERR(pcie->bus_clk);
+		goto fail_clk;
+	}
+	err = clk_prepare_enable(pcie->bus_clk);
+	if (err)
+		goto err_map_reg;
+
+	pcie->base = devm_ioremap_resource(&pdev->dev, &res);
+	if (IS_ERR(pcie->base)) {
+		err = PTR_ERR(pcie->base);
+		goto err_map_reg;
+	}
+
+	return 0;
+
+err_map_reg:
+	clk_disable_unprepare(pcie->bus_clk);
+fail_clk:
+	clk_disable_unprepare(pcie->clk);
+
+	return err;
+}
+
+static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
+				    struct of_pci_range *range,
+				    int *index)
+{
+	u64 restype = range->flags;
+	u64 cpu_addr = range->cpu_addr;
+	u64 cpu_end = range->cpu_addr + range->size;
+	u64 pci_addr = range->pci_addr;
+	u32 flags = LAM_64BIT | LAR_ENABLE;
+	u64 mask;
+	u64 size;
+	int idx = *index;
+
+	if (restype & IORESOURCE_PREFETCH)
+		flags |= LAM_PREFETCH;
+
+	/*
+	 * If the size of the range is larger than the alignment of the start
+	 * address, we have to use multiple entries to perform the mapping.
+	 */
+	if (cpu_addr > 0) {
+		unsigned long nr_zeros = __ffs64(cpu_addr);
+		u64 alignment = 1ULL << nr_zeros;
+		size = min(range->size, alignment);
+	} else {
+		size = range->size;
+	}
+	/* Hardware supports max 4GiB inbound region */
+	size = min(size, 1ULL << 32);
+
+	mask = roundup_pow_of_two(size) - 1;
+	mask &= ~0xf;
+
+	while (cpu_addr < cpu_end) {
+		/*
+		 * Set up 64-bit inbound regions as the range parser doesn't
+		 * distinguish between 32 and 64-bit types.
+		 */
+		pci_write_reg(pcie, lower_32_bits(pci_addr), PCIEPRAR(idx));
+		pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx));
+		pci_write_reg(pcie, lower_32_bits(mask) | flags, PCIELAMR(idx));
+
+		pci_write_reg(pcie, upper_32_bits(pci_addr), PCIEPRAR(idx+1));
+		pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx+1));
+		pci_write_reg(pcie, 0, PCIELAMR(idx+1));
+
+		pci_addr += size;
+		cpu_addr += size;
+		idx += 2;
+
+		if (idx > MAX_NR_INBOUND_MAPS) {
+			dev_err(pcie->dev, "Failed to map inbound regions!\n");
+			return -EINVAL;
+		}
+	}
+	*index = idx;
+
+	return 0;
+}
+
+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+				     struct device_node *node)
+{
+	const int na = 3, ns = 2;
+	int rlen;
+
+	parser->node = node;
+	parser->pna = of_n_addr_cells(node);
+	parser->np = parser->pna + na + ns;
+
+	parser->range = of_get_property(node, "dma-ranges", &rlen);
+	if (!parser->range)
+		return -ENOENT;
+
+	parser->end = parser->range + rlen / sizeof(__be32);
+	return 0;
+}
+
+static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
+					  struct device_node *np)
+{
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	int index = 0;
+	int err;
+
+	if (pci_dma_range_parser_init(&parser, np))
+		return -EINVAL;
+
+	/* Get the dma-ranges from DT */
+	for_each_of_pci_range(&parser, &range) {
+		u64 end = range.cpu_addr + range.size - 1;
+		dev_dbg(pcie->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
+			range.flags, range.cpu_addr, end, range.pci_addr);
+
+		err = rcar_pcie_inbound_ranges(pcie, &range, &index);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id rcar_pcie_of_match[] = {
+	{ .compatible = "renesas,pcie-r8a7779", .data = rcar_pcie_hw_init_h1 },
+	{ .compatible = "renesas,pcie-r8a7790", .data = rcar_pcie_hw_init },
+	{ .compatible = "renesas,pcie-r8a7791", .data = rcar_pcie_hw_init },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rcar_pcie_of_match);
+
+static int __init rcar_pcie_probe(struct platform_device *pdev)
+{
+	struct rcar_pcie *pcie;
+	unsigned int data;
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	const struct of_device_id *of_id;
+	int err, win = 0;
+	int (*hw_init_fn)(struct rcar_pcie *);
+
+	pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+		return -ENOMEM;
+
+	pcie->dev = &pdev->dev;
+	platform_set_drvdata(pdev, pcie);
+
+	if (of_pci_range_parser_init(&parser, pdev->dev.of_node)) {
+		dev_err(&pdev->dev, "missing ranges property\n");
+		return -EINVAL;
+	}
+
+	err = rcar_pcie_get_resources(pdev, pcie);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to request resources: %d\n", err);
+		return err;
+	}
+
+	for_each_of_pci_range(&parser, &range) {
+		of_pci_range_to_resource(&range, pdev->dev.of_node,
+						&pcie->res[win++]);
+
+		if (win > PCI_MAX_RESOURCES)
+			break;
+	}
+
+	 err = rcar_pcie_parse_map_dma_ranges(pcie, pdev->dev.of_node);
+	 if (err)
+		return err;
+
+	of_id = of_match_device(rcar_pcie_of_match, pcie->dev);
+	if (!of_id || !of_id->data)
+		return -EINVAL;
+	hw_init_fn = of_id->data;
+
+	/* Failure to get a link might just be that no cards are inserted */
+	err = hw_init_fn(pcie);
+	if (err) {
+		dev_info(&pdev->dev, "PCIe link down\n");
+		return 0;
+	}
+
+	data = pci_read_reg(pcie, MACSR);
+	dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
+
+	rcar_pcie_enable(pcie);
+
+	return 0;
+}
+
+static struct platform_driver rcar_pcie_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = rcar_pcie_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = rcar_pcie_probe,
+};
+module_platform_driver(rcar_pcie_driver);
+
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
new file mode 100644
index 0000000..3dc026b
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.h
@@ -0,0 +1,82 @@
+/*
+ * PCI Express definitions for Renesas R-Car SoCs
+ */
+#ifndef __PCI_RCAR_H
+#define __PCI_RCAR_H
+
+#define PCIECAR			0x000010
+#define PCIECCTLR		0x000018
+#define  CONFIG_SEND_ENABLE	(1 << 31)
+#define  TYPE0			(0 << 8)
+#define  TYPE1			(1 << 8)
+#define PCIECDR			0x000020
+#define PCIEMSR			0x000028
+#define PCIEINTXR		0x000400
+#define PCIEPHYSR		0x0007f0
+
+/* Transfer control */
+#define PCIETCTLR		0x02000
+#define  CFINIT			1
+#define PCIETSTR		0x02004
+#define  DATA_LINK_ACTIVE	1
+#define PCIEINTR		0x02008
+#define PCIEINTER		0x0200c
+#define PCIEERRFR		0x02020
+#define  UNSUPPORTED_REQUEST	(1 << 4)
+#define PCIEERRFER		0x02024
+#define PCIEERRFR2		0x02028
+#define PCIEPMSR		0x02034
+#define PCIEPMSCIER		0x02038
+#define PCIEMSIFR		0x02044
+
+/* root port address */
+#define PCIEPRAR(x)		(0x02080 + ((x) * 0x4))
+
+/* local address reg & mask */
+#define PCIELAR(x)		(0x02200 + ((x) * 0x20))
+#define PCIELAMR(x)		(0x02208 + ((x) * 0x20))
+#define  LAM_PMIOLAMnB3		(1 << 3)
+#define  LAM_PMIOLAMnB2		(1 << 2)
+#define  LAM_PREFETCH		(1 << 3)
+#define  LAM_64BIT		(1 << 2)
+#define  LAR_ENABLE		(1 << 1)
+
+/* PCIe address reg & mask */
+#define PCIEPARL(x)		(0x03400 + ((x) * 0x20))
+#define PCIEPARH(x)		(0x03404 + ((x) * 0x20))
+#define PCIEPAMR(x)		(0x03408 + ((x) * 0x20))
+#define PCIEPTCTLR(x)		(0x0340c + ((x) * 0x20))
+#define  PAR_ENABLE		(1 << 31)
+#define  IO_SPACE		(1 << 8)
+
+/* Configuration */
+#define PCICONF(x)		(0x010000 + ((x) * 0x4))
+#define PMCAP(x)		(0x010040 + ((x) * 0x4))
+#define MSICAP(x)		(0x010050 + ((x) * 0x4))
+#define EXPCAP(x)		(0x010070 + ((x) * 0x4))
+#define VCCAP(x)		(0x010100 + ((x) * 0x4))
+#define SERNUMCAP(x)		(0x0101b0 + ((x) * 0x4))
+
+/* link layer */
+#define IDSETR0			0x011000
+#define IDSETR1			0x011004
+#define SUBIDSETR		0x011024
+#define DSERSETR0		0x01102c
+#define DSERSETR1		0x011030
+#define TLCTLR			0x011048
+#define MACSR			0x011054
+#define MACCTLR			0x011058
+#define  SCRAMBLE_DISABLE	(1 << 27)
+
+/* R-Car H1 PHY */
+#define H1_PCIEPHYCTLR		0x040008
+#define H1_PCIEPHYADRR		0x04000c
+#define  WRITE_CMD		(1 << 16)
+#define  PHY_ACK		(1 << 24)
+#define  RATE_POS		12
+#define  LANE_POS		8
+#define  ADR_POS		0
+#define H1_PCIEPHYDOUTR		0x040014
+#define H1_PCIEPHYSR		0x040018
+
+#endif /* __PCI_RCAR_H */
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 02/10] PCI: host: rcar: Add MSI support
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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(-)

diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index c22c896..e3ce3d1 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -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;
diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
index 3dc026b..4f0c678 100644
--- a/drivers/pci/host/pcie-rcar.h
+++ b/drivers/pci/host/pcie-rcar.h
@@ -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))
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 02/10] PCI: host: rcar: Add MSI support
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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(-)

diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index c22c896..e3ce3d1 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -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;
diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
index 3dc026b..4f0c678 100644
--- a/drivers/pci/host/pcie-rcar.h
+++ b/drivers/pci/host/pcie-rcar.h
@@ -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))
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 02/10] PCI: host: rcar: Add MSI support
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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(-)

diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index c22c896..e3ce3d1 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -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;
diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
index 3dc026b..4f0c678 100644
--- a/drivers/pci/host/pcie-rcar.h
+++ b/drivers/pci/host/pcie-rcar.h
@@ -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))
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 03/10] ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the device tree clock nodes for PCIe

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
 arch/arm/boot/dts/r8a7790.dtsi            | 7 ++++---
 include/dt-bindings/clock/r8a7790-clock.h | 1 +
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index da69afc..df9ec61 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -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@e6150144 {
 			compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h
index 6548a5f..840dbc8 100644
--- a/include/dt-bindings/clock/r8a7790-clock.h
+++ b/include/dt-bindings/clock/r8a7790-clock.h
@@ -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
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 03/10] ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

This patch adds the device tree clock nodes for PCIe

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
 arch/arm/boot/dts/r8a7790.dtsi            | 7 ++++---
 include/dt-bindings/clock/r8a7790-clock.h | 1 +
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index da69afc..df9ec61 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -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@e6150144 {
 			compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h
index 6548a5f..840dbc8 100644
--- a/include/dt-bindings/clock/r8a7790-clock.h
+++ b/include/dt-bindings/clock/r8a7790-clock.h
@@ -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
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 03/10] ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the device tree clock nodes for PCIe

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
 arch/arm/boot/dts/r8a7790.dtsi            | 7 ++++---
 include/dt-bindings/clock/r8a7790-clock.h | 1 +
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index da69afc..df9ec61 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -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";
diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h
index 6548a5f..840dbc8 100644
--- a/include/dt-bindings/clock/r8a7790-clock.h
+++ b/include/dt-bindings/clock/r8a7790-clock.h
@@ -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
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 04/10] ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the device tree clock nodes for PCIe

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
 arch/arm/boot/dts/r8a7791.dtsi            | 7 +++++--
 include/dt-bindings/clock/r8a7791-clock.h | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 71bac2c..ccfba57 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -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@e6150144 {
 			compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h
index 30f82f2..d3e2cf5 100644
--- a/include/dt-bindings/clock/r8a7791-clock.h
+++ b/include/dt-bindings/clock/r8a7791-clock.h
@@ -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
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 04/10] ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

This patch adds the device tree clock nodes for PCIe

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
 arch/arm/boot/dts/r8a7791.dtsi            | 7 +++++--
 include/dt-bindings/clock/r8a7791-clock.h | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 71bac2c..ccfba57 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -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@e6150144 {
 			compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h
index 30f82f2..d3e2cf5 100644
--- a/include/dt-bindings/clock/r8a7791-clock.h
+++ b/include/dt-bindings/clock/r8a7791-clock.h
@@ -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
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 04/10] ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the device tree clock nodes for PCIe

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
 arch/arm/boot/dts/r8a7791.dtsi            | 7 +++++--
 include/dt-bindings/clock/r8a7791-clock.h | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 71bac2c..ccfba57 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -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";
diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h
index 30f82f2..d3e2cf5 100644
--- a/include/dt-bindings/clock/r8a7791-clock.h
+++ b/include/dt-bindings/clock/r8a7791-clock.h
@@ -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
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 05/10] dt-bindings: pci: rcar pcie device tree bindings
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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

diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt
new file mode 100644
index 0000000..789bd46
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt
@@ -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@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";
+	};
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 05/10] dt-bindings: pci: rcar pcie device tree bindings
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy, devicetree

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

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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

diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt
new file mode 100644
index 0000000..789bd46
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt
@@ -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@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";
+	};
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 05/10] dt-bindings: pci: rcar pcie device tree bindings
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

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

diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt
new file mode 100644
index 0000000..789bd46
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt
@@ -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";
+	};
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 06/10] ARM: shmobile: r8a7790: Add PCIe device nodes
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7790.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index df9ec61..dbcea57 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -821,4 +821,28 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	pcie: pcie@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";
+	};
 };
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 06/10] ARM: shmobile: r8a7790: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7790.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index df9ec61..dbcea57 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -821,4 +821,28 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	pcie: pcie@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";
+	};
 };
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 06/10] ARM: shmobile: r8a7790: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7790.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index df9ec61..dbcea57 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -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";
+	};
 };
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 07/10] ARM: shmobile: lager: Add PCIe device nodes
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7790-lager.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index a55c5f8..bbbcb63 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -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 {
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 07/10] ARM: shmobile: lager: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7790-lager.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index a55c5f8..bbbcb63 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -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 {
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 07/10] ARM: shmobile: lager: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7790-lager.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index a55c5f8..bbbcb63 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -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 {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 08/10] ARM: shmobile: r8a7791: Add PCIe device nodes
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7791.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index ccfba57..7a4be4c 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -836,4 +836,28 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	pcie: pcie@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";
+	};
 };
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 08/10] ARM: shmobile: r8a7791: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7791.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index ccfba57..7a4be4c 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -836,4 +836,28 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	pcie: pcie@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";
+	};
 };
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 08/10] ARM: shmobile: r8a7791: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7791.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index ccfba57..7a4be4c 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -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";
+	};
 };
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 09/10] ARM: shmobile: koelsch: Add PCIe device nodes
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7791-koelsch.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index ee23b7b..3130a0c 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -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";
+};
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 09/10] ARM: shmobile: koelsch: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7791-koelsch.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index ee23b7b..3130a0c 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -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";
+};
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 09/10] ARM: shmobile: koelsch: Add PCIe device nodes
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Split device and board DT changes
---
 arch/arm/boot/dts/r8a7791-koelsch.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index ee23b7b..3130a0c 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -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";
+};
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 10/10] ARM: shmobile: koelsch: Add PCIe to defconfig
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-03-31 10:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Add shmobile to subject
---
 arch/arm/configs/koelsch_defconfig | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig
index 86faab5..ec14547 100644
--- a/arch/arm/configs/koelsch_defconfig
+++ b/arch/arm/configs/koelsch_defconfig
@@ -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
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 10/10] ARM: shmobile: koelsch: Add PCIe to defconfig
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks, Phil Edworthy

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Add shmobile to subject
---
 arch/arm/configs/koelsch_defconfig | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig
index 86faab5..ec14547 100644
--- a/arch/arm/configs/koelsch_defconfig
+++ b/arch/arm/configs/koelsch_defconfig
@@ -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
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH v7 10/10] ARM: shmobile: koelsch: Add PCIe to defconfig
@ 2014-03-31 10:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-03-31 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

v6:
 - Add shmobile to subject
---
 arch/arm/configs/koelsch_defconfig | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig
index 86faab5..ec14547 100644
--- a/arch/arm/configs/koelsch_defconfig
+++ b/arch/arm/configs/koelsch_defconfig
@@ -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
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 00/10] R-Car Gen2 PCIe host driver
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-04-04  8:22   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-04  8:22 UTC (permalink / raw)
  To: linux-arm-kernel

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

On: 31 March 2014 11:31, Phil wrote:
> 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@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 00/10] R-Car Gen2 PCIe host driver
@ 2014-04-04  8:22   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-04  8:22 UTC (permalink / raw)
  To: Arnd Bergmann, Ben Dooks, Sergei Shtylyov, Simon Horman,
	Lucas Stach, Geert Uytterhoeven, Jason Gunthorpe
  Cc: linux-sh, LAKML, Bjorn Helgaas, Valentine Barshak, Magnus Damm,
	linux-pci

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

On: 31 March 2014 11:31, Phil wrote:
> 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@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 00/10] R-Car Gen2 PCIe host driver
@ 2014-04-04  8:22   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-04  8:22 UTC (permalink / raw)
  To: linux-arm-kernel

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

On: 31 March 2014 11:31, Phil wrote:
> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 00/10] R-Car Gen2 PCIe host driver
  2014-03-31 10:30 ` Phil Edworthy
  (?)
@ 2014-04-04  8:30   ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-04  8:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

> -----Original Message-----
> From: linux-sh-owner@vger.kernel.org [mailto:linux-sh-
> owner@vger.kernel.org] On Behalf Of Phil Edworthy
> Sent: 31 March 2014 11:31
> To: linux-pci@vger.kernel.org
> Cc: linux-sh@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@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 00/10] R-Car Gen2 PCIe host driver
@ 2014-04-04  8:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-04  8:30 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-sh, LAKML, Valentine Barshak, Simon Horman, Magnus Damm,
	Ben Dooks, linux-pci

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

> -----Original Message-----
> From: linux-sh-owner@vger.kernel.org [mailto:linux-sh-
> owner@vger.kernel.org] On Behalf Of Phil Edworthy
> Sent: 31 March 2014 11:31
> To: linux-pci@vger.kernel.org
> Cc: linux-sh@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@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 00/10] R-Car Gen2 PCIe host driver
@ 2014-04-04  8:30   ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-04  8:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 02/10] PCI: host: rcar: Add MSI support
  2014-03-31 10:30   ` Phil Edworthy
  (?)
@ 2014-04-04  8:53     ` Lucas Stach
  -1 siblings, 0 replies; 81+ messages in thread
From: Lucas Stach @ 2014-04-04  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> 
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> 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(-)
> 
> diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
> index c22c896..e3ce3d1 100644
> --- a/drivers/pci/host/pcie-rcar.c
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -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;
> diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
> index 3dc026b..4f0c678 100644
> --- a/drivers/pci/host/pcie-rcar.h
> +++ b/drivers/pci/host/pcie-rcar.h
> @@ -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))

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


^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 02/10] PCI: host: rcar: Add MSI support
@ 2014-04-04  8:53     ` Lucas Stach
  0 siblings, 0 replies; 81+ messages in thread
From: Lucas Stach @ 2014-04-04  8:53 UTC (permalink / raw)
  To: Phil Edworthy
  Cc: linux-pci, linux-sh, Magnus Damm, Valentine Barshak,
	Simon Horman, Bjorn Helgaas, Ben Dooks, LAKML

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> 
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> 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(-)
> 
> diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
> index c22c896..e3ce3d1 100644
> --- a/drivers/pci/host/pcie-rcar.c
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -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;
> diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
> index 3dc026b..4f0c678 100644
> --- a/drivers/pci/host/pcie-rcar.h
> +++ b/drivers/pci/host/pcie-rcar.h
> @@ -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))

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


^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 02/10] PCI: host: rcar: Add MSI support
@ 2014-04-04  8:53     ` Lucas Stach
  0 siblings, 0 replies; 81+ messages in thread
From: Lucas Stach @ 2014-04-04  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> 
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> 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(-)
> 
> diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
> index c22c896..e3ce3d1 100644
> --- a/drivers/pci/host/pcie-rcar.c
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -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;
> diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
> index 3dc026b..4f0c678 100644
> --- a/drivers/pci/host/pcie-rcar.h
> +++ b/drivers/pci/host/pcie-rcar.h
> @@ -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))

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 05/10] dt-bindings: pci: rcar pcie device tree bindings
  2014-03-31 10:30   ` Phil Edworthy
  (?)
@ 2014-04-04  9:08     ` Lucas Stach
  -1 siblings, 0 replies; 81+ messages in thread
From: Lucas Stach @ 2014-04-04  9:08 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
> This patch adds the bindings for the R-Car PCIe driver. The driver
> resides under drivers/pci/host/pcie-rcar.c
> 
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

Another nitpick below, otherwise:
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>

If you decide to roll another version with just this changed, feel free
to carry over the my tag.
> 
> 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
> 
> diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt
> new file mode 100644
> index 0000000..789bd46
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt
> @@ -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@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>;

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.

> +		#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";
> +	};

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


^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 05/10] dt-bindings: pci: rcar pcie device tree bindings
@ 2014-04-04  9:08     ` Lucas Stach
  0 siblings, 0 replies; 81+ messages in thread
From: Lucas Stach @ 2014-04-04  9:08 UTC (permalink / raw)
  To: Phil Edworthy
  Cc: linux-pci, devicetree, linux-sh, Magnus Damm, Valentine Barshak,
	Simon Horman, Bjorn Helgaas, Ben Dooks, LAKML

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
> This patch adds the bindings for the R-Car PCIe driver. The driver
> resides under drivers/pci/host/pcie-rcar.c
> 
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

Another nitpick below, otherwise:
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>

If you decide to roll another version with just this changed, feel free
to carry over the my tag.
> 
> 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
> 
> diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt
> new file mode 100644
> index 0000000..789bd46
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt
> @@ -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@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>;

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.

> +		#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";
> +	};

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


^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 05/10] dt-bindings: pci: rcar pcie device tree bindings
@ 2014-04-04  9:08     ` Lucas Stach
  0 siblings, 0 replies; 81+ messages in thread
From: Lucas Stach @ 2014-04-04  9:08 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
> This patch adds the bindings for the R-Car PCIe driver. The driver
> resides under drivers/pci/host/pcie-rcar.c
> 
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>

Another nitpick below, otherwise:
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>

If you decide to roll another version with just this changed, feel free
to carry over the my tag.
> 
> 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
> 
> diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt
> new file mode 100644
> index 0000000..789bd46
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt
> @@ -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>;

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.

> +		#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";
> +	};

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-03-31 10:30   ` Phil Edworthy
  (?)
@ 2014-04-24 19:19     ` Bjorn Helgaas
  -1 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-04-24 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
> This PCIe Host driver currently does not support MSI, so cards
> fall back to INTx interrupts.
> 
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> ...

> --- /dev/null
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -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.

> +#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 {
> +	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.

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

> +{
> +	writel(val, pcie->base + reg);
> +}
> +
> +static unsigned long
> +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> +{
> +	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.

> +{
> +	int shift = 8 * (where & 3);
> +	u32 val = pci_read_reg(pcie, where & ~3);

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

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

> +	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;
> +
> +	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().

> ...
> +	/* 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)) &
> +		(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).

> ...
> +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;
> +	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?

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-24 19:19     ` Bjorn Helgaas
  0 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-04-24 19:19 UTC (permalink / raw)
  To: Phil Edworthy
  Cc: linux-pci, linux-sh, LAKML, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks

On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
> This PCIe Host driver currently does not support MSI, so cards
> fall back to INTx interrupts.
> 
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> ...

> --- /dev/null
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -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.

> +#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 {
> +	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.

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

> +{
> +	writel(val, pcie->base + reg);
> +}
> +
> +static unsigned long
> +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> +{
> +	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.

> +{
> +	int shift = 8 * (where & 3);
> +	u32 val = pci_read_reg(pcie, where & ~3);

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

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

> +	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;
> +
> +	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().

> ...
> +	/* 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)) &
> +		(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).

> ...
> +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;
> +	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?

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-24 19:19     ` Bjorn Helgaas
  0 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-04-24 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
> This PCIe Host driver currently does not support MSI, so cards
> fall back to INTx interrupts.
> 
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> ...

> --- /dev/null
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -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.

> +#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 {
> +	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.

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

> +{
> +	writel(val, pcie->base + reg);
> +}
> +
> +static unsigned long
> +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> +{
> +	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.

> +{
> +	int shift = 8 * (where & 3);
> +	u32 val = pci_read_reg(pcie, where & ~3);

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

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

> +	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;
> +
> +	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().

> ...
> +	/* 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)) &
> +		(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).

> ...
> +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;
> +	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?

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-04-24 19:19     ` Bjorn Helgaas
  (?)
@ 2014-04-28 10:03       ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-28 10:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Bjorn,

Thanks for the review.

On 24 April 2014 20:19, Bjorn wrote:
> On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
> > This PCIe Host driver currently does not support MSI, so cards
> > fall back to INTx interrupts.
> >
> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > ...
> 
> > --- /dev/null
> > +++ b/drivers/pci/host/pcie-rcar.c
> > @@ -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.

> > +#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 {
> > +	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.

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

> > +	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).
Ok
 
> > +{
> > +	writel(val, pcie->base + reg);
> > +}
> > +
> > +static unsigned long
> > +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> > +{
> > +	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.
Sure
 
> > +{
> > +	int shift = 8 * (where & 3);
> > +	u32 val = pci_read_reg(pcie, where & ~3);
> 
> A blank line is typical here (after the local variables).
Ok

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

> > ...
> > +	/* 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)) &
> > +		(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).
Yes, the locking is done at a higher level; I'll add comment for this.

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

> > ...
> > +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.
This means add a DT entry for bus-range, and simply calling pci_add_resource for
the range, right? If so, ok.

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-28 10:03       ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-28 10:03 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-pci, linux-sh, LAKML, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks

Hi Bjorn,

Thanks for the review.

On 24 April 2014 20:19, Bjorn wrote:
> On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
> > This PCIe Host driver currently does not support MSI, so cards
> > fall back to INTx interrupts.
> >
> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > ...
> 
> > --- /dev/null
> > +++ b/drivers/pci/host/pcie-rcar.c
> > @@ -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.

> > +#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 {
> > +	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.

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

> > +	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).
Ok
 
> > +{
> > +	writel(val, pcie->base + reg);
> > +}
> > +
> > +static unsigned long
> > +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> > +{
> > +	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.
Sure
 
> > +{
> > +	int shift = 8 * (where & 3);
> > +	u32 val = pci_read_reg(pcie, where & ~3);
> 
> A blank line is typical here (after the local variables).
Ok

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

> > ...
> > +	/* 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)) &
> > +		(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).
Yes, the locking is done at a higher level; I'll add comment for this.

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

> > ...
> > +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.
This means add a DT entry for bus-range, and simply calling pci_add_resource for
the range, right? If so, ok.

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-28 10:03       ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-28 10:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Bjorn,

Thanks for the review.

On 24 April 2014 20:19, Bjorn wrote:
> On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
> > This PCIe Host driver currently does not support MSI, so cards
> > fall back to INTx interrupts.
> >
> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > ...
> 
> > --- /dev/null
> > +++ b/drivers/pci/host/pcie-rcar.c
> > @@ -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.

> > +#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 {
> > +	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.

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

> > +	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).
Ok
 
> > +{
> > +	writel(val, pcie->base + reg);
> > +}
> > +
> > +static unsigned long
> > +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> > +{
> > +	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.
Sure
 
> > +{
> > +	int shift = 8 * (where & 3);
> > +	u32 val = pci_read_reg(pcie, where & ~3);
> 
> A blank line is typical here (after the local variables).
Ok

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

> > ...
> > +	/* 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)) &
> > +		(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).
Yes, the locking is done at a higher level; I'll add comment for this.

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

> > ...
> > +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.
This means add a DT entry for bus-range, and simply calling pci_add_resource for
the range, right? If so, ok.

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-04-28 10:03       ` Phil Edworthy
  (?)
@ 2014-04-28 19:11         ` Bjorn Helgaas
  -1 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-04-28 19:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 28, 2014 at 4:03 AM, Phil Edworthy
<phil.edworthy@renesas.com> wrote:
> Hi Bjorn,
>
> Thanks for the review.
>
> On 24 April 2014 20:19, Bjorn wrote:
>> On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
>> > This PCIe Host driver currently does not support MSI, so cards
>> > fall back to INTx interrupts.
>> >
>> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
>> > ...
>>
>> > --- /dev/null
>> > +++ b/drivers/pci/host/pcie-rcar.c
>> > @@ -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.
>
>> > +#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 {
>> > +   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.
>
>> 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().

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.

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-28 19:11         ` Bjorn Helgaas
  0 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-04-28 19:11 UTC (permalink / raw)
  To: Phil Edworthy
  Cc: linux-pci, linux-sh, LAKML, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks

On Mon, Apr 28, 2014 at 4:03 AM, Phil Edworthy
<phil.edworthy@renesas.com> wrote:
> Hi Bjorn,
>
> Thanks for the review.
>
> On 24 April 2014 20:19, Bjorn wrote:
>> On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
>> > This PCIe Host driver currently does not support MSI, so cards
>> > fall back to INTx interrupts.
>> >
>> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
>> > ...
>>
>> > --- /dev/null
>> > +++ b/drivers/pci/host/pcie-rcar.c
>> > @@ -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.
>
>> > +#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 {
>> > +   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.
>
>> 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().

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.

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-28 19:11         ` Bjorn Helgaas
  0 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-04-28 19:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 28, 2014 at 4:03 AM, Phil Edworthy
<phil.edworthy@renesas.com> wrote:
> Hi Bjorn,
>
> Thanks for the review.
>
> On 24 April 2014 20:19, Bjorn wrote:
>> On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
>> > This PCIe Host driver currently does not support MSI, so cards
>> > fall back to INTx interrupts.
>> >
>> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
>> > ...
>>
>> > --- /dev/null
>> > +++ b/drivers/pci/host/pcie-rcar.c
>> > @@ -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.
>
>> > +#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 {
>> > +   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.
>
>> 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().

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.

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-04-28 19:11         ` Bjorn Helgaas
  (?)
@ 2014-04-28 20:35           ` Jason Gunthorpe
  -1 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-04-28 20:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 28, 2014 at 01:11:08PM -0600, Bjorn Helgaas wrote:

> >> 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@koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00
[Normal decode])
        Bus: primary\0, secondary\x01, subordinate\x01, 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.

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-28 20:35           ` Jason Gunthorpe
  0 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-04-28 20:35 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Phil Edworthy, linux-sh, linux-pci, Magnus Damm,
	Valentine Barshak, Simon Horman, Ben Dooks, LAKML

On Mon, Apr 28, 2014 at 01:11:08PM -0600, Bjorn Helgaas wrote:

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

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-28 20:35           ` Jason Gunthorpe
  0 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-04-28 20:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 28, 2014 at 01:11:08PM -0600, Bjorn Helgaas wrote:

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

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-04-28 19:11         ` Bjorn Helgaas
  (?)
@ 2014-04-30 10:20           ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-30 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

SGkgQmpvcm4sDQoNCk9uIDI4IEFwcmlsIDIwMTQgMjA6MTEsIEJqb3JuIHdyb3RlOg0KPiBPbiBN
b24sIEFwciAyOCwgMjAxNCBhdCA0OjAzIEFNLCBQaGlsIEVkd29ydGh5DQo+IDxwaGlsLmVkd29y
dGh5QHJlbmVzYXMuY29tPiB3cm90ZToNCj4gPiBIaSBCam9ybiwNCj4gPg0KPiA+IFRoYW5rcyBm
b3IgdGhlIHJldmlldy4NCj4gPg0KPiA+IE9uIDI0IEFwcmlsIDIwMTQgMjA6MTksIEJqb3JuIHdy
b3RlOg0KPiA+PiBPbiBNb24sIE1hciAzMSwgMjAxNCBhdCAxMTozMDo0NkFNICswMTAwLCBQaGls
IEVkd29ydGh5IHdyb3RlOg0KPiA+PiA+IFRoaXMgUENJZSBIb3N0IGRyaXZlciBjdXJyZW50bHkg
ZG9lcyBub3Qgc3VwcG9ydCBNU0ksIHNvIGNhcmRzDQo+ID4+ID4gZmFsbCBiYWNrIHRvIElOVHgg
aW50ZXJydXB0cy4NCj4gPj4gPg0KPiA+PiA+IFNpZ25lZC1vZmYtYnk6IFBoaWwgRWR3b3J0aHkg
PHBoaWwuZWR3b3J0aHlAcmVuZXNhcy5jb20+DQo+ID4+ID4gLi4uDQo+ID4+DQo+ID4+ID4gLS0t
IC9kZXYvbnVsbA0KPiA+PiA+ICsrKyBiL2RyaXZlcnMvcGNpL2hvc3QvcGNpZS1yY2FyLmMNCj4g
Pj4gPiBAQCAtMCwwICsxLDY5MyBAQA0KPiA+PiA+IC4uLg0KPiA+PiA+ICsjaW5jbHVkZSA8bGlu
dXgvc2xhYi5oPg0KPiA+PiA+ICsjaW5jbHVkZSAicGNpZS1yY2FyLmgiDQo+ID4+DQo+ID4+IEl0
IGxvb2tzIGxpa2UgdGhlIHRoaW5ncyBpbiBwY2llLXJjYXIuaCBhcmUgdXNlZCBvbmx5IGluIHRo
aXMgZmlsZQ0KPiA+PiAocGNpZS1yY2FyLmMpLCBzbyB5b3UgbWlnaHQgYXMgd2VsbCBqdXN0IHB1
dCB0aGUgY29udGVudHMgaGVyZSBhbmQgbm90IGhhdmUNCj4gPj4gYSBwY2llLXJjYXIuaCBhdCBh
bGwuICBPZiBjb3Vyc2UsIGlmIHRoZXJlIGFyZSB0aGluZ3MgbmVlZGVkIGJ5IG1vcmUgdGhhbg0K
PiA+PiBvbmUgZmlsZSwgdGhleSBzaG91bGQgc3RheSBpbiBwY2llLXJjYXIuaC4NCj4gPiBOb3Ro
aW5nIGVsc2UgdXNlcyB0aGVtIHNvIEknbGwgcHV0IGluIHRoZSBjIGZpbGUuDQo+ID4NCj4gPj4g
PiArI2RlZmluZSBEUlZfTkFNRSAicmNhci1wY2llIg0KPiA+PiA+ICsNCj4gPj4gPiArI2RlZmlu
ZSBSQ09ORih4KSAgIChQQ0lDT05GKDApKyh4KSkNCj4gPj4gPiArI2RlZmluZSBSUE1DQVAoeCkg
IChQTUNBUCgwKSsoeCkpDQo+ID4+ID4gKyNkZWZpbmUgUkVYUENBUCh4KSAoRVhQQ0FQKDApKyh4
KSkNCj4gPj4gPiArI2RlZmluZSBSVkNDQVAoeCkgIChWQ0NBUCgwKSsoeCkpDQo+ID4+ID4gKw0K
PiA+PiA+ICsjZGVmaW5lICBQQ0lFX0NPTkZfQlVTKGIpICAoKChiKSAmIDB4ZmYpIDw8IDI0KQ0K
PiA+PiA+ICsjZGVmaW5lICBQQ0lFX0NPTkZfREVWKGQpICAoKChkKSAmIDB4MWYpIDw8IDE5KQ0K
PiA+PiA+ICsjZGVmaW5lICBQQ0lFX0NPTkZfRlVOQyhmKSAoKChmKSAmIDB4NykgPDwgMTYpDQo+
ID4+ID4gKw0KPiA+PiA+ICsjZGVmaW5lIFBDSV9NQVhfUkVTT1VSQ0VTIDQNCj4gPj4gPiArI2Rl
ZmluZSBNQVhfTlJfSU5CT1VORF9NQVBTIDYNCj4gPj4gPiArDQo+ID4+ID4gKy8qIFN0cnVjdHVy
ZSByZXByZXNlbnRpbmcgdGhlIFBDSWUgaW50ZXJmYWNlICovDQo+ID4+ID4gK3N0cnVjdCByY2Fy
X3BjaWUgew0KPiA+PiA+ICsgICBzdHJ1Y3QgZGV2aWNlICAgICAgICAgICAqZGV2Ow0KPiA+PiA+
ICsgICB2b2lkIF9faW9tZW0gICAgICAgICAgICAqYmFzZTsNCj4gPj4gPiArICAgc3RydWN0IHJl
c291cmNlICAgICAgICAgcmVzW1BDSV9NQVhfUkVTT1VSQ0VTXTsNCj4gPj4gPiArICAgdTggICAg
ICAgICAgICAgICAgICAgICAgcm9vdF9idXNfbnI7DQo+ID4+DQo+ID4+IEkgZG9uJ3QgdW5kZXJz
dGFuZCBob3cgcm9vdF9idXNfbnIgd29ya3MuICBGcm9tIGl0cyBuYW1lLCBpdCBzb3VuZHMgbGlr
ZQ0KPiA+PiBpdCdzIHRoZSBidXMgbnVtYmVyIG9mIHRoZSBQQ0kgYnVzIG9uIHRoZSBkb3duc3Ry
ZWFtIHNpZGUgb2YgdGhlIGhvc3QNCj4gPj4gYnJpZGdlLg0KPiA+IFRoYXQncyBjb3JyZWN0Lg0K
PiA+DQo+ID4+IFRoYXQgYnVzIG51bWJlciBzaG91bGQgYmUgYSBwcm9wZXJ0eSBvZiB0aGUgaG9z
dCBicmlkZ2UsIGkuZS4sDQo+ID4+IGl0J3MgZWl0aGVyIGhhcmQtd2lyZWQgaW50byB0aGUgYnJp
ZGdlLCBvciBpdCdzIHByb2dyYW1tYWJsZSBzb21ld2hlcmUuDQo+ID4+IEJ1dCByb290X2J1c19u
ciBjb21lcyBmcm9tIHN5cy0+YnVzbnIsIHdoaWNoIGlzIGFwcGFyZW50bHkgZnJvbSBzb21lDQo+
ID4+IGdlbmVyaWMgY29kZSB0aGF0IGtub3dzIG5vdGhpbmcgYWJvdXQgdGhpcyBwYXJ0aWN1bGFy
IGhvc3QgYnJpZGdlLg0KPiA+IFRoZSBtYW51YWwgZm9yIHRoaXMgaGFyZHdhcmUgc2F5cyB0aGF0
IHRoZSBIVyBkb2Vzbid0IGNhcmUgd2hhdCB0aGUgYnVzDQo+IG51bWJlcg0KPiA+IGlzIHNldCB0
by4gVGhlIG9ubHkgdGhpbmcgdGhlIEhXIG5lZWRzIHRvIGtub3cgaXMgdGhhdCB3aGVuIHNlbmRp
bmcgY29uZmlnDQo+ID4gYWNjZXNzZXMsIHdlIG5lZWQgdG8gaW5kaWNhdGUgd2hldGhlciBpdCdz
IGEgVFlQRTAgb3IgVFlQRTEgaGVhZGVyOyBzbyB3ZQ0KPiB1c2UNCj4gPiByb290X2J1c19uciB0
byBkZXRlcm1pbmUgdGhpcy4gVGhlIGdlbmVyaWMgY29kZSB0aGF0IHNldHMgdXAgc3lzLT5idXNu
cg0KPiAoQVJNDQo+ID4gYmlvczMyIGluIHRoaXMgY2FzZSksIGp1c3QgaW5jcmVtZW50cyBidXMg
bnVtYmVyIGZvciBlYWNoIGNvbnRyb2xsZXIuDQo+ID4NCj4gPiBUaGlzIGlzIHZlcnkgc2ltaWxh
ciB0byB0aGUgcGNpZS1kZXNpZ253YXJlIGRyaXZlciwgaW4gZHdfcGNpZV9zY2FuX2J1cygpLg0K
PiANCj4gT0suICBGcm9tIHdoYXQgeW91IHNhaWQgYmVsb3csIGl0IHNvdW5kcyBsaWtlIHlvdSB3
b3VsZCBhZGQgYSBEVCBlbnRyeQ0KPiBmb3IgdGhlIGJ1cyByYW5nZSB5b3Ugd2FudCB0byBoYXZl
IGJlbG93IHRoaXMgYnJpZGdlLCBhbmQgdXNlIFRZUEUwDQo+IGFjY2Vzc2VzIGZvciB0aGUgYmFz
ZSBvZiB0aGF0IHJhbmdlLg0KT2suIFRoZSBkcml2ZXIgYWxyZWFkeSB1c2VzIFRZUEUwIGZvciB0
aGUgYmFzZSwgaS5lLiB0aGF0J3Mgd2hhdCByb290X2J1c19uciBpcyB1c2VkIGZvci4gSSdsbCBh
ZGQgdGhlIHJhbmdlcyBhYmlsaXR5Lg0KDQo+IEknbSBub3Qgc3VyZSBob3cgeW91IHJlY29uY2ls
ZSB0aGlzIHdpdGggdGhlIGlkZWEgdGhhdCB0aGUgYmlvczMyIGNvZGUNCj4ganVzdCBpbmNyZW1l
bnRzIGEgYnVzIG51bWJlciBmb3IgZWFjaCBjb250cm9sbGVyLg0KSSBsb29rZWQgYXQgdGhlIGJp
b3MzMiBjb2RlIGFnYWluLiBJIHdhcyB3cm9uZyB0byBzYXkgdGhhdCBpdCBqdXN0IGluY3JlbWVu
dHMgYSBidXMgbnVtYmVyIGZvciBlYWNoIGNvbnRyb2xsZXIuIFRoZSBmaXJzdCBjb250cm9sbGVy
IGFsd2F5cyBzdGFydHMgd2l0aCBidXNucj0wLCBhbmQgc3Vic2VxdWVudCBjb250cm9sbGVycyBn
ZXQgdGhlIG5leHQgYXZhaWxhYmxlIGJ1cyBudW1iZXIgYWZ0ZXIgc2Nhbm5pbmcgdGhlIGJ1cy4N
Cg0KPiA+PiA+ICtzdGF0aWMgaW50IF9faW5pdCByY2FyX3BjaWVfZ2V0X3Jlc291cmNlcyhzdHJ1
Y3QgcGxhdGZvcm1fZGV2aWNlDQo+ICpwZGV2LA0KPiA+PiA+ICsgICBzdHJ1Y3QgcmNhcl9wY2ll
ICpwY2llKQ0KPiA+PiA+ICt7DQo+ID4+ID4gKyAgIHN0cnVjdCByZXNvdXJjZSByZXM7DQo+ID4+
ID4gKyAgIGludCBlcnI7DQo+ID4+ID4gKw0KPiA+PiA+ICsgICBlcnIgPSBvZl9hZGRyZXNzX3Rv
X3Jlc291cmNlKHBkZXYtPmRldi5vZl9ub2RlLCAwLCAmcmVzKTsNCj4gPj4gPiArICAgaWYgKGVy
cikNCj4gPj4gPiArICAgICAgICAgICByZXR1cm4gZXJyOw0KPiA+Pg0KPiA+PiBJIGRvbid0IHNl
ZSBhbnl3aGVyZSB0aGF0IGZpZ3VyZXMgb3V0IHRoZSBidXMgbnVtYmVyIHJhbmdlIGJlaGluZCB0
aGlzDQo+IGhvc3QNCj4gPj4gYnJpZGdlLiAgVGhlIFBDSSBjb3JlIG5lZWRzIHRvIGtub3cgdGhp
cy4gIEkga25vdyB0aGUgY29yZSBhc3N1bWVzIDAwLWZmIGlmDQo+ID4+IGl0J3Mgbm90IHN1cHBs
aWVkLCBidXQgdGhhdCdzIGp1c3QgdG8gZGVhbCB3aXRoIHRoZSBsZWdhY3kgc2l0dWF0aW9uIHdo
ZXJlDQo+ID4+IHdlIGFzc3VtZWQgb25lIGhvc3QgYnJpZGdlIHdhcyBhbGwgYW55Ym9keSB3b3Vs
ZCBldmVyIG5lZWQuDQo+ID4+DQo+ID4+IEZvciBuZXcgY29kZSwgd2Ugc2hvdWxkIGJlIGV4cGxp
Y2l0IGFib3V0IHRoZSByYW5nZS4NCj4gPiBUaGlzIG1lYW5zIGFkZCBhIERUIGVudHJ5IGZvciBi
dXMtcmFuZ2UsIGFuZCBzaW1wbHkgY2FsbGluZw0KPiBwY2lfYWRkX3Jlc291cmNlIGZvcg0KPiA+
IHRoZSByYW5nZSwgcmlnaHQ/IElmIHNvLCBvay4NCj4gDQo+IFllYWgsIEkgZ3Vlc3MuICBJZiB0
aGUgSFcgcmVhbGx5IGRvZXNuJ3QgbG9vayBhdCB0aGUgYnVzIG51bWJlciBhdA0KPiBhbGwsIGl0
IHNvdW5kcyBsaWtlIHRoZSByYW5nZSBpcyBlZmZlY3RpdmVseSAwMC1mZiwgYW5kIGVhY2ggaG9z
dA0KPiBicmlkZ2Ugc2hvdWxkIGJlIGluIGl0cyBvd24gZG9tYWluLg0KT2suDQoNClRoYW5rcw0K
UGhpbA0K

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-30 10:20           ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-30 10:20 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-pci, linux-sh, LAKML, Valentine Barshak, Simon Horman,
	Magnus Damm, Ben Dooks

SGkgQmpvcm4sDQoNCk9uIDI4IEFwcmlsIDIwMTQgMjA6MTEsIEJqb3JuIHdyb3RlOg0KPiBPbiBN
b24sIEFwciAyOCwgMjAxNCBhdCA0OjAzIEFNLCBQaGlsIEVkd29ydGh5DQo+IDxwaGlsLmVkd29y
dGh5QHJlbmVzYXMuY29tPiB3cm90ZToNCj4gPiBIaSBCam9ybiwNCj4gPg0KPiA+IFRoYW5rcyBm
b3IgdGhlIHJldmlldy4NCj4gPg0KPiA+IE9uIDI0IEFwcmlsIDIwMTQgMjA6MTksIEJqb3JuIHdy
b3RlOg0KPiA+PiBPbiBNb24sIE1hciAzMSwgMjAxNCBhdCAxMTozMDo0NkFNICswMTAwLCBQaGls
IEVkd29ydGh5IHdyb3RlOg0KPiA+PiA+IFRoaXMgUENJZSBIb3N0IGRyaXZlciBjdXJyZW50bHkg
ZG9lcyBub3Qgc3VwcG9ydCBNU0ksIHNvIGNhcmRzDQo+ID4+ID4gZmFsbCBiYWNrIHRvIElOVHgg
aW50ZXJydXB0cy4NCj4gPj4gPg0KPiA+PiA+IFNpZ25lZC1vZmYtYnk6IFBoaWwgRWR3b3J0aHkg
PHBoaWwuZWR3b3J0aHlAcmVuZXNhcy5jb20+DQo+ID4+ID4gLi4uDQo+ID4+DQo+ID4+ID4gLS0t
IC9kZXYvbnVsbA0KPiA+PiA+ICsrKyBiL2RyaXZlcnMvcGNpL2hvc3QvcGNpZS1yY2FyLmMNCj4g
Pj4gPiBAQCAtMCwwICsxLDY5MyBAQA0KPiA+PiA+IC4uLg0KPiA+PiA+ICsjaW5jbHVkZSA8bGlu
dXgvc2xhYi5oPg0KPiA+PiA+ICsjaW5jbHVkZSAicGNpZS1yY2FyLmgiDQo+ID4+DQo+ID4+IEl0
IGxvb2tzIGxpa2UgdGhlIHRoaW5ncyBpbiBwY2llLXJjYXIuaCBhcmUgdXNlZCBvbmx5IGluIHRo
aXMgZmlsZQ0KPiA+PiAocGNpZS1yY2FyLmMpLCBzbyB5b3UgbWlnaHQgYXMgd2VsbCBqdXN0IHB1
dCB0aGUgY29udGVudHMgaGVyZSBhbmQgbm90IGhhdmUNCj4gPj4gYSBwY2llLXJjYXIuaCBhdCBh
bGwuICBPZiBjb3Vyc2UsIGlmIHRoZXJlIGFyZSB0aGluZ3MgbmVlZGVkIGJ5IG1vcmUgdGhhbg0K
PiA+PiBvbmUgZmlsZSwgdGhleSBzaG91bGQgc3RheSBpbiBwY2llLXJjYXIuaC4NCj4gPiBOb3Ro
aW5nIGVsc2UgdXNlcyB0aGVtIHNvIEknbGwgcHV0IGluIHRoZSBjIGZpbGUuDQo+ID4NCj4gPj4g
PiArI2RlZmluZSBEUlZfTkFNRSAicmNhci1wY2llIg0KPiA+PiA+ICsNCj4gPj4gPiArI2RlZmlu
ZSBSQ09ORih4KSAgIChQQ0lDT05GKDApKyh4KSkNCj4gPj4gPiArI2RlZmluZSBSUE1DQVAoeCkg
IChQTUNBUCgwKSsoeCkpDQo+ID4+ID4gKyNkZWZpbmUgUkVYUENBUCh4KSAoRVhQQ0FQKDApKyh4
KSkNCj4gPj4gPiArI2RlZmluZSBSVkNDQVAoeCkgIChWQ0NBUCgwKSsoeCkpDQo+ID4+ID4gKw0K
PiA+PiA+ICsjZGVmaW5lICBQQ0lFX0NPTkZfQlVTKGIpICAoKChiKSAmIDB4ZmYpIDw8IDI0KQ0K
PiA+PiA+ICsjZGVmaW5lICBQQ0lFX0NPTkZfREVWKGQpICAoKChkKSAmIDB4MWYpIDw8IDE5KQ0K
PiA+PiA+ICsjZGVmaW5lICBQQ0lFX0NPTkZfRlVOQyhmKSAoKChmKSAmIDB4NykgPDwgMTYpDQo+
ID4+ID4gKw0KPiA+PiA+ICsjZGVmaW5lIFBDSV9NQVhfUkVTT1VSQ0VTIDQNCj4gPj4gPiArI2Rl
ZmluZSBNQVhfTlJfSU5CT1VORF9NQVBTIDYNCj4gPj4gPiArDQo+ID4+ID4gKy8qIFN0cnVjdHVy
ZSByZXByZXNlbnRpbmcgdGhlIFBDSWUgaW50ZXJmYWNlICovDQo+ID4+ID4gK3N0cnVjdCByY2Fy
X3BjaWUgew0KPiA+PiA+ICsgICBzdHJ1Y3QgZGV2aWNlICAgICAgICAgICAqZGV2Ow0KPiA+PiA+
ICsgICB2b2lkIF9faW9tZW0gICAgICAgICAgICAqYmFzZTsNCj4gPj4gPiArICAgc3RydWN0IHJl
c291cmNlICAgICAgICAgcmVzW1BDSV9NQVhfUkVTT1VSQ0VTXTsNCj4gPj4gPiArICAgdTggICAg
ICAgICAgICAgICAgICAgICAgcm9vdF9idXNfbnI7DQo+ID4+DQo+ID4+IEkgZG9uJ3QgdW5kZXJz
dGFuZCBob3cgcm9vdF9idXNfbnIgd29ya3MuICBGcm9tIGl0cyBuYW1lLCBpdCBzb3VuZHMgbGlr
ZQ0KPiA+PiBpdCdzIHRoZSBidXMgbnVtYmVyIG9mIHRoZSBQQ0kgYnVzIG9uIHRoZSBkb3duc3Ry
ZWFtIHNpZGUgb2YgdGhlIGhvc3QNCj4gPj4gYnJpZGdlLg0KPiA+IFRoYXQncyBjb3JyZWN0Lg0K
PiA+DQo+ID4+IFRoYXQgYnVzIG51bWJlciBzaG91bGQgYmUgYSBwcm9wZXJ0eSBvZiB0aGUgaG9z
dCBicmlkZ2UsIGkuZS4sDQo+ID4+IGl0J3MgZWl0aGVyIGhhcmQtd2lyZWQgaW50byB0aGUgYnJp
ZGdlLCBvciBpdCdzIHByb2dyYW1tYWJsZSBzb21ld2hlcmUuDQo+ID4+IEJ1dCByb290X2J1c19u
ciBjb21lcyBmcm9tIHN5cy0+YnVzbnIsIHdoaWNoIGlzIGFwcGFyZW50bHkgZnJvbSBzb21lDQo+
ID4+IGdlbmVyaWMgY29kZSB0aGF0IGtub3dzIG5vdGhpbmcgYWJvdXQgdGhpcyBwYXJ0aWN1bGFy
IGhvc3QgYnJpZGdlLg0KPiA+IFRoZSBtYW51YWwgZm9yIHRoaXMgaGFyZHdhcmUgc2F5cyB0aGF0
IHRoZSBIVyBkb2Vzbid0IGNhcmUgd2hhdCB0aGUgYnVzDQo+IG51bWJlcg0KPiA+IGlzIHNldCB0
by4gVGhlIG9ubHkgdGhpbmcgdGhlIEhXIG5lZWRzIHRvIGtub3cgaXMgdGhhdCB3aGVuIHNlbmRp
bmcgY29uZmlnDQo+ID4gYWNjZXNzZXMsIHdlIG5lZWQgdG8gaW5kaWNhdGUgd2hldGhlciBpdCdz
IGEgVFlQRTAgb3IgVFlQRTEgaGVhZGVyOyBzbyB3ZQ0KPiB1c2UNCj4gPiByb290X2J1c19uciB0
byBkZXRlcm1pbmUgdGhpcy4gVGhlIGdlbmVyaWMgY29kZSB0aGF0IHNldHMgdXAgc3lzLT5idXNu
cg0KPiAoQVJNDQo+ID4gYmlvczMyIGluIHRoaXMgY2FzZSksIGp1c3QgaW5jcmVtZW50cyBidXMg
bnVtYmVyIGZvciBlYWNoIGNvbnRyb2xsZXIuDQo+ID4NCj4gPiBUaGlzIGlzIHZlcnkgc2ltaWxh
ciB0byB0aGUgcGNpZS1kZXNpZ253YXJlIGRyaXZlciwgaW4gZHdfcGNpZV9zY2FuX2J1cygpLg0K
PiANCj4gT0suICBGcm9tIHdoYXQgeW91IHNhaWQgYmVsb3csIGl0IHNvdW5kcyBsaWtlIHlvdSB3
b3VsZCBhZGQgYSBEVCBlbnRyeQ0KPiBmb3IgdGhlIGJ1cyByYW5nZSB5b3Ugd2FudCB0byBoYXZl
IGJlbG93IHRoaXMgYnJpZGdlLCBhbmQgdXNlIFRZUEUwDQo+IGFjY2Vzc2VzIGZvciB0aGUgYmFz
ZSBvZiB0aGF0IHJhbmdlLg0KT2suIFRoZSBkcml2ZXIgYWxyZWFkeSB1c2VzIFRZUEUwIGZvciB0
aGUgYmFzZSwgaS5lLiB0aGF0J3Mgd2hhdCByb290X2J1c19uciBpcyB1c2VkIGZvci4gSSdsbCBh
ZGQgdGhlIHJhbmdlcyBhYmlsaXR5Lg0KDQo+IEknbSBub3Qgc3VyZSBob3cgeW91IHJlY29uY2ls
ZSB0aGlzIHdpdGggdGhlIGlkZWEgdGhhdCB0aGUgYmlvczMyIGNvZGUNCj4ganVzdCBpbmNyZW1l
bnRzIGEgYnVzIG51bWJlciBmb3IgZWFjaCBjb250cm9sbGVyLg0KSSBsb29rZWQgYXQgdGhlIGJp
b3MzMiBjb2RlIGFnYWluLiBJIHdhcyB3cm9uZyB0byBzYXkgdGhhdCBpdCBqdXN0IGluY3JlbWVu
dHMgYSBidXMgbnVtYmVyIGZvciBlYWNoIGNvbnRyb2xsZXIuIFRoZSBmaXJzdCBjb250cm9sbGVy
IGFsd2F5cyBzdGFydHMgd2l0aCBidXNucj0wLCBhbmQgc3Vic2VxdWVudCBjb250cm9sbGVycyBn
ZXQgdGhlIG5leHQgYXZhaWxhYmxlIGJ1cyBudW1iZXIgYWZ0ZXIgc2Nhbm5pbmcgdGhlIGJ1cy4N
Cg0KPiA+PiA+ICtzdGF0aWMgaW50IF9faW5pdCByY2FyX3BjaWVfZ2V0X3Jlc291cmNlcyhzdHJ1
Y3QgcGxhdGZvcm1fZGV2aWNlDQo+ICpwZGV2LA0KPiA+PiA+ICsgICBzdHJ1Y3QgcmNhcl9wY2ll
ICpwY2llKQ0KPiA+PiA+ICt7DQo+ID4+ID4gKyAgIHN0cnVjdCByZXNvdXJjZSByZXM7DQo+ID4+
ID4gKyAgIGludCBlcnI7DQo+ID4+ID4gKw0KPiA+PiA+ICsgICBlcnIgPSBvZl9hZGRyZXNzX3Rv
X3Jlc291cmNlKHBkZXYtPmRldi5vZl9ub2RlLCAwLCAmcmVzKTsNCj4gPj4gPiArICAgaWYgKGVy
cikNCj4gPj4gPiArICAgICAgICAgICByZXR1cm4gZXJyOw0KPiA+Pg0KPiA+PiBJIGRvbid0IHNl
ZSBhbnl3aGVyZSB0aGF0IGZpZ3VyZXMgb3V0IHRoZSBidXMgbnVtYmVyIHJhbmdlIGJlaGluZCB0
aGlzDQo+IGhvc3QNCj4gPj4gYnJpZGdlLiAgVGhlIFBDSSBjb3JlIG5lZWRzIHRvIGtub3cgdGhp
cy4gIEkga25vdyB0aGUgY29yZSBhc3N1bWVzIDAwLWZmIGlmDQo+ID4+IGl0J3Mgbm90IHN1cHBs
aWVkLCBidXQgdGhhdCdzIGp1c3QgdG8gZGVhbCB3aXRoIHRoZSBsZWdhY3kgc2l0dWF0aW9uIHdo
ZXJlDQo+ID4+IHdlIGFzc3VtZWQgb25lIGhvc3QgYnJpZGdlIHdhcyBhbGwgYW55Ym9keSB3b3Vs
ZCBldmVyIG5lZWQuDQo+ID4+DQo+ID4+IEZvciBuZXcgY29kZSwgd2Ugc2hvdWxkIGJlIGV4cGxp
Y2l0IGFib3V0IHRoZSByYW5nZS4NCj4gPiBUaGlzIG1lYW5zIGFkZCBhIERUIGVudHJ5IGZvciBi
dXMtcmFuZ2UsIGFuZCBzaW1wbHkgY2FsbGluZw0KPiBwY2lfYWRkX3Jlc291cmNlIGZvcg0KPiA+
IHRoZSByYW5nZSwgcmlnaHQ/IElmIHNvLCBvay4NCj4gDQo+IFllYWgsIEkgZ3Vlc3MuICBJZiB0
aGUgSFcgcmVhbGx5IGRvZXNuJ3QgbG9vayBhdCB0aGUgYnVzIG51bWJlciBhdA0KPiBhbGwsIGl0
IHNvdW5kcyBsaWtlIHRoZSByYW5nZSBpcyBlZmZlY3RpdmVseSAwMC1mZiwgYW5kIGVhY2ggaG9z
dA0KPiBicmlkZ2Ugc2hvdWxkIGJlIGluIGl0cyBvd24gZG9tYWluLg0KT2suDQoNClRoYW5rcw0K
UGhpbA0K

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-30 10:20           ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-30 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Bjorn,

On 28 April 2014 20:11, Bjorn wrote:
> On Mon, Apr 28, 2014 at 4:03 AM, Phil Edworthy
> <phil.edworthy@renesas.com> wrote:
> > Hi Bjorn,
> >
> > Thanks for the review.
> >
> > On 24 April 2014 20:19, Bjorn wrote:
> >> On Mon, Mar 31, 2014 at 11:30:46AM +0100, Phil Edworthy wrote:
> >> > This PCIe Host driver currently does not support MSI, so cards
> >> > fall back to INTx interrupts.
> >> >
> >> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> >> > ...
> >>
> >> > --- /dev/null
> >> > +++ b/drivers/pci/host/pcie-rcar.c
> >> > @@ -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.
> >
> >> > +#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 {
> >> > +   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.
> >
> >> 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().
> 
> 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.

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

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

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-04-28 20:35           ` Jason Gunthorpe
  (?)
@ 2014-04-30 10:33             ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-30 10:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jason,

On 28 April 2014 21:35, Jason wrote:
> On Mon, Apr 28, 2014 at 01:11:08PM -0600, Bjorn Helgaas wrote:
> 
> > >> 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@koelsch:~# lspci -vv
> 00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00
> [Normal decode])
>         Bus: primary\0, secondary\x01, subordinate\x01, 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.

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

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-30 10:33             ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-30 10:33 UTC (permalink / raw)
  To: Jason Gunthorpe, Bjorn Helgaas
  Cc: linux-sh, linux-pci, Magnus Damm, Valentine Barshak,
	Simon Horman, Ben Dooks, LAKML

Hi Jason,

On 28 April 2014 21:35, Jason wrote:
> On Mon, Apr 28, 2014 at 01:11:08PM -0600, Bjorn Helgaas wrote:
> 
> > >> 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@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.
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.

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

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-30 10:33             ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-04-30 10:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jason,

On 28 April 2014 21:35, Jason wrote:
> On Mon, Apr 28, 2014 at 01:11:08PM -0600, Bjorn Helgaas wrote:
> 
> > >> 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.
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.

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

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-04-30 10:33             ` Phil Edworthy
  (?)
@ 2014-04-30 15:43               ` Jason Gunthorpe
  -1 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-04-30 15:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 30, 2014 at 10:33:08AM +0000, Phil Edworthy wrote:

> > 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@koelsch:~# lspci -vv
> > 00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00
> > [Normal decode])
> >         Bus: primary\0, secondary\x01, subordinate\x01, 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.

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-30 15:43               ` Jason Gunthorpe
  0 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-04-30 15:43 UTC (permalink / raw)
  To: Phil Edworthy
  Cc: Bjorn Helgaas, linux-sh, linux-pci, Magnus Damm,
	Valentine Barshak, Simon Horman, Ben Dooks, LAKML

On Wed, Apr 30, 2014 at 10:33:08AM +0000, Phil Edworthy wrote:

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

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-04-30 15:43               ` Jason Gunthorpe
  0 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-04-30 15:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 30, 2014 at 10:33:08AM +0000, Phil Edworthy wrote:

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

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-04-30 15:43               ` Jason Gunthorpe
  (?)
@ 2014-05-01  9:50                 ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-01  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jason,

On 30 April 2014 16:44, Jason wrote:
> On Wed, Apr 30, 2014 at 10:33:08AM +0000, Phil Edworthy wrote:
> 
> > > 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@koelsch:~# lspci -vv
> > > 00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00
> > > [Normal decode])
> > >         Bus: primary\0, secondary\x01, subordinate\x01, 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.
> 
> 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.
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?

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

Thanks
Phil


^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-01  9:50                 ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-01  9:50 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Bjorn Helgaas, linux-sh, linux-pci, Magnus Damm,
	Valentine Barshak, Simon Horman, Ben Dooks, LAKML

Hi Jason,

On 30 April 2014 16:44, Jason wrote:
> On Wed, Apr 30, 2014 at 10:33:08AM +0000, Phil Edworthy wrote:
> 
> > > 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@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.
> > 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.
> 
> 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.
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?

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

Thanks
Phil


^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-01  9:50                 ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-01  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jason,

On 30 April 2014 16:44, Jason wrote:
> On Wed, Apr 30, 2014 at 10:33:08AM +0000, Phil Edworthy wrote:
> 
> > > 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.
> > 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.
> 
> 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.
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?

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

Thanks
Phil

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-05-01  9:50                 ` Phil Edworthy
  (?)
@ 2014-05-01 16:50                   ` Jason Gunthorpe
  -1 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-05-01 16:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 01, 2014 at 09:50:56AM +0000, Phil Edworthy wrote:

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

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

> 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 :)

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-01 16:50                   ` Jason Gunthorpe
  0 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-05-01 16:50 UTC (permalink / raw)
  To: Phil Edworthy
  Cc: linux-sh, linux-pci, Magnus Damm, Valentine Barshak,
	Simon Horman, Bjorn Helgaas, Ben Dooks, LAKML

On Thu, May 01, 2014 at 09:50:56AM +0000, Phil Edworthy wrote:

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

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

> 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 :)

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-01 16:50                   ` Jason Gunthorpe
  0 siblings, 0 replies; 81+ messages in thread
From: Jason Gunthorpe @ 2014-05-01 16:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 01, 2014 at 09:50:56AM +0000, Phil Edworthy wrote:

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

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

> 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 :)

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-05-01  9:50                 ` Phil Edworthy
  (?)
@ 2014-05-01 17:31                   ` Bjorn Helgaas
  -1 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-05-01 17:31 UTC (permalink / raw)
  To: linux-arm-kernel

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

On Thu, May 1, 2014 at 3:50 AM, Phil Edworthy <phil.edworthy@renesas.com> wrote:

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-01 17:31                   ` Bjorn Helgaas
  0 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-05-01 17:31 UTC (permalink / raw)
  To: Phil Edworthy
  Cc: Jason Gunthorpe, linux-sh, linux-pci, Magnus Damm,
	Valentine Barshak, Simon Horman, Ben Dooks, LAKML,
	Srikanth Thokala, Michal Simek, Grant Likely

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

On Thu, May 1, 2014 at 3:50 AM, Phil Edworthy <phil.edworthy@renesas.com> wrote:

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-01 17:31                   ` Bjorn Helgaas
  0 siblings, 0 replies; 81+ messages in thread
From: Bjorn Helgaas @ 2014-05-01 17:31 UTC (permalink / raw)
  To: linux-arm-kernel

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

On Thu, May 1, 2014 at 3:50 AM, Phil Edworthy <phil.edworthy@renesas.com> wrote:

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-05-01 16:50                   ` Jason Gunthorpe
  (?)
@ 2014-05-06 10:46                     ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jason,

On 01 May 2014 17:50, Jason wrote:
> On Thu, May 01, 2014 at 09:50:56AM +0000, Phil Edworthy wrote:
> 
> > > 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.
> 
> > 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.
> 
> > 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 :)
> 
> > 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.

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-06 10:46                     ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-06 10:46 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: linux-sh, linux-pci, Magnus Damm, Valentine Barshak,
	Simon Horman, Bjorn Helgaas, Ben Dooks, LAKML

Hi Jason,

On 01 May 2014 17:50, Jason wrote:
> On Thu, May 01, 2014 at 09:50:56AM +0000, Phil Edworthy wrote:
> 
> > > 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.
> 
> > 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.
> 
> > 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 :)
> 
> > 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.

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-06 10:46                     ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jason,

On 01 May 2014 17:50, Jason wrote:
> On Thu, May 01, 2014 at 09:50:56AM +0000, Phil Edworthy wrote:
> 
> > > 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.
> 
> > 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.
> 
> > 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 :)
> 
> > 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.

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

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
  2014-05-01 17:31                   ` Bjorn Helgaas
  (?)
@ 2014-05-06 12:49                     ` Phil Edworthy
  -1 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-06 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

SGkgQmpvcm4sDQoNCk9uIDAxIE1heSAyMDE0IDE4OjMxLCBCam9ybiB3cm90ZToNCj4gWytjYyBT
cmlrYW50aCwgTWljaGFsLCBHcmFudCBiZWNhdXNlIHdlJ3JlIGhhdmluZyB0aGUgc2FtZSBkaXNj
dXNzaW9uDQo+IGFib3V0IHJvb3QgYnVzIG51bWJlcnMgaW4gdGhlIFhpbGlueCBob3N0IGJyaWRn
ZSBkcml2ZXJdDQo+IA0KPiBPbiBUaHUsIE1heSAxLCAyMDE0IGF0IDM6NTAgQU0sIFBoaWwgRWR3
b3J0aHkNCj4gPHBoaWwuZWR3b3J0aHlAcmVuZXNhcy5jb20+IHdyb3RlOg0KPiANCj4gPiBXaGVu
IHdvdWxkIHRoZSBQQ0kgY29yZSBjaGFuZ2UgdGhlIHJvb3QgYnVzIG51bWJlciB0byBzb21ldGhp
bmcgb3RoZXINCj4gdGhhbiBzZXQgaW4gc3lzLT5idXNucj8NCj4gDQo+IFRoZSBQQ0kgY29yZSBu
ZXZlciBjaGFuZ2VzIHRoZSByb290IGJ1cyBudW1iZXIgb2YgYSBob3N0IGJyaWRnZSwgYnV0DQo+
IGl0J3MgaW1wb3J0YW50IGZvciB0aGUgY29yZSB0byBrbm93IGV4YWN0bHkgd2hhdCBidXMgbnVt
YmVycyBhcmUNCj4gYmVoaW5kIGVhY2ggaG9zdCBicmlkZ2Ugc28gd2UgY2FuIGNvcnJlY3RseSBh
c3NpZ24gYnVzIG51bWJlcnMsIE1NSU8sDQo+IGFuZCBJL08gcG9ydCByZXNvdXJjZXMuDQo+IA0K
PiBUaGUgcmVhc29uIGlzIHRoYXQgd2hlbiB3ZSBlbnVtZXJhdGUgYSBQQ0ktdG8tUENJIGJyaWRn
ZSwgd2UgaGF2ZSB0bw0KPiBrbm93IHdoZXRoZXIgYnVzIG51bWJlcnMgYXJlIGF2YWlsYWJsZSBm
b3IgdGhlIHNlY29uZGFyeSBidXMuICBGb3INCj4gZXhhbXBsZSwgYXNzdW1lIHR3byBob3N0IGJy
aWRnZXMgY29uZmlndXJlZCAob3Igd2lyZWQpIGFzIGZvbGxvd3M6DQo+IA0KPiAgIEEgbGVhZHMg
dG8gW2J1cyAwMC0xZl0sIHdpdGggYXBlcnR1cmUgW21lbSAweDgwMDAwMDAwLTB4OGZmZmZmZmZd
DQo+ICAgQiBsZWFkcyB0byBbYnVzIDIwLWZmXSwgd2l0aCBhcGVydHVyZSBbbWVtIDB4OTAwMDAw
MDAtMHg5ZmZmZmZmZl0NCj4gDQo+IEZ1cnRoZXIsIGFzc3VtZSBhIFBDSS10by1QQ0kgYnJpZGdl
IGF0IDFmOjAwLjAuICBJZiB0aGUgaG9zdCBicmlkZ2UNCj4gZHJpdmVyIGRvZXNuJ3QgdGVsbCB1
cyB0aGUgW2J1cyAwMC0xZl0gcmFuZ2UgZm9yIGhvc3QgYnJpZGdlIEEsIHRoZQ0KPiBQQ0kgY29y
ZSB3aWxsIGFzc3VtZSBbYnVzIDAwLWZmXS4gIFdoZW4gdGhlIGNvcmUgZW51bWVyYXRlcyB0aGUN
Cj4gMWY6MDAuMCBicmlkZ2UsIGl0IHdpbGwgYXNzaWduIGJ1cyBudW1iZXIgMjAgdG8gaXRzIHNl
Y29uZGFyeSBidXMuDQo+IE5vdyBpdCBlbnVtZXJhdGVzIGRldmljZXMgb24gYnVzIDIwLiAgVGhl
IGNvcmUgZXhwZWN0cyB0aGlzIHRvIGJlIGRvbmUNCj4gdmlhIGhvc3QgYnJpZGdlIEEsIGJ1dCBl
bnVtZXJhdGlvbiB1c2VzIElELXJvdXRlZCBjb25maWcgdHJhbnNhY3Rpb25zLA0KPiBzbyB0aGV5
IGFyZSBjbGFpbWVkIGJ5IGhvc3QgYnJpZGdlIEIgaW5zdGVhZC4gIElmIHdlIGZpbmQgYSBkZXZp
Y2UNCj4gMjA6MDAuMCwgdGhlIGNvcmUgdGhpbmtzIGl0IGlzIGJlbG93IEEsIGJ1dCBpdCBpcyBy
ZWFsbHkgYmVsb3cgQi4NCj4gDQo+IE5vdyB3ZSBhc3NpZ24gcmVzb3VyY2VzIHRvIDIwOjAwLjAs
IGFuZCBzaW5jZSB3ZSB0aGluayBpdCdzIGJlbG93IEEsDQo+IHdlIGFzc2lnbiB0aGVtIGZyb20g
dGhlIFttZW0gMHg4MDAwMDAwMC0weDhmZmZmZmZmXSBhcGVydHVyZS4gIFRoaXMNCj4gb2J2aW91
c2x5IGRvZXNuJ3Qgd29yaywgYmVjYXVzZSB3aGVuIHRoZSBkcml2ZXIgcGVyZm9ybXMgTU1JTw0K
PiBhY2Nlc3Nlcywgd2hpY2ggYXJlIGFkZHJlc3Mtcm91dGVkLCB0aGV5IGFyZSBjbGFpbWVkIGJ5
IGhvc3QgYnJpZGdlIEEsDQo+IG5vdCBCLCBzbyB0aGUgMjA6MDAuMCBkZXZpY2UgbmV2ZXIgc2Vl
cyB0aGVtLg0KVGhhbmtzIGZvciB0aGUgY2xlYXIgZXhwbGFuYXRpb24uDQoNCj4gSWYgeW91ciBo
b3N0IGJyaWRnZSByZWFsbHkgY2xhaW1zIEFMTCBidXMgbnVtYmVycyAoMDAtZmYpLCB0aGF0J3MN
Cj4gZmluZSwgYW5kIHlvdSBjYW4gdGVsbCB0aGUgUENJIGNvcmUgdGhhdC4gIEJ1dCBpZiB5b3Ug
aGF2ZSBzZXZlcmFsDQo+IHN1Y2ggYnJpZGdlcywgdGhleSBzaG91bGQgYmUgcGxhY2VkIGluIHNl
cGFyYXRlIGRvbWFpbnMuDQpUaGF0IG1ha2VzIHNlbnNlLg0KDQpJbiB0aGUgY2FzZSBvZiB0aGUg
Ui1DYXIgUENJZSBob3N0IGJyaWRnZSwgYXMgZmFyIGFzIEkgY2FuIHRlbGwsIHRoZSBoYXJkd2Fy
ZSBkb2VzbuKAmXQgY2FyZSBhYm91dCBidXMgbnVtYmVycyBhdCBhbGwsIHdpdGggdGhlIGV4Y2Vw
dGlvbiB0aGF0IHRoZSBkcml2ZXIgdXNlcyBvbmUgYnVzIG51bWJlciB0byB0YXJnZXQgdGhlIGJy
aWRnZSBpdHNlbGYuIFdlIGNhbiB1c2UgYXMgbWFueSBvciBhcyBmZXcgYnVzIG51bWJlcnMgZm9y
IHRoZSBzZWNvbmRhcnkgYnVzIGFzIHlvdSBsaWtlLg0KDQpTbywgdGhlIFItQ2FyIFBDSWUgZHJp
dmVyIHNob3VsZCBpbXBsZW1lbnQgYnVzIHJhbmdlcywgYnV0IHNob3VsZCBpdCBhbHNvIHVzZSBz
ZXBhcmF0ZSBQQ0kgZG9tYWlucyBmb3IgbXVsdGlwbGUgY29udHJvbGxlcnM/DQoNCj4gVGhpcyBp
cyBwcm9iYWJseSBtb3JlIGRldGFpbCB0aGFuIHlvdSB3YW50ZWQsIGFuZCBtYXliZSB5b3UgZG9u
J3QgZXZlcg0KPiBleHBlY3QgdG8gaGF2ZSBtdWx0aXBsZSBob3N0IGJyaWRnZXMgb3IgY29tcGxp
Y2F0ZWQgaGllcmFyY2hpZXMgb2YNCj4gZGV2aWNlcy4gIEJ1dCB0aGUgUENJIGNvcmUgaGFzIHRv
IGRlYWwgd2l0aCB0aGVzZSBpc3N1ZXMgb24gb3RoZXINCj4gc3lzdGVtcywgc28gaXQncyBpbXBv
cnRhbnQgdG8gZ2V0IHRoZXNlIGRldGFpbHMgcmlnaHQuDQoNClRoYW5rcw0KUGhpbA0K

^ permalink raw reply	[flat|nested] 81+ messages in thread

* RE: [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-06 12:49                     ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-06 12:49 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Jason Gunthorpe, linux-sh, linux-pci, Magnus Damm,
	Valentine Barshak, Simon Horman, Ben Dooks, LAKML,
	Srikanth Thokala, Michal Simek, Grant Likely

SGkgQmpvcm4sDQoNCk9uIDAxIE1heSAyMDE0IDE4OjMxLCBCam9ybiB3cm90ZToNCj4gWytjYyBT
cmlrYW50aCwgTWljaGFsLCBHcmFudCBiZWNhdXNlIHdlJ3JlIGhhdmluZyB0aGUgc2FtZSBkaXNj
dXNzaW9uDQo+IGFib3V0IHJvb3QgYnVzIG51bWJlcnMgaW4gdGhlIFhpbGlueCBob3N0IGJyaWRn
ZSBkcml2ZXJdDQo+IA0KPiBPbiBUaHUsIE1heSAxLCAyMDE0IGF0IDM6NTAgQU0sIFBoaWwgRWR3
b3J0aHkNCj4gPHBoaWwuZWR3b3J0aHlAcmVuZXNhcy5jb20+IHdyb3RlOg0KPiANCj4gPiBXaGVu
IHdvdWxkIHRoZSBQQ0kgY29yZSBjaGFuZ2UgdGhlIHJvb3QgYnVzIG51bWJlciB0byBzb21ldGhp
bmcgb3RoZXINCj4gdGhhbiBzZXQgaW4gc3lzLT5idXNucj8NCj4gDQo+IFRoZSBQQ0kgY29yZSBu
ZXZlciBjaGFuZ2VzIHRoZSByb290IGJ1cyBudW1iZXIgb2YgYSBob3N0IGJyaWRnZSwgYnV0DQo+
IGl0J3MgaW1wb3J0YW50IGZvciB0aGUgY29yZSB0byBrbm93IGV4YWN0bHkgd2hhdCBidXMgbnVt
YmVycyBhcmUNCj4gYmVoaW5kIGVhY2ggaG9zdCBicmlkZ2Ugc28gd2UgY2FuIGNvcnJlY3RseSBh
c3NpZ24gYnVzIG51bWJlcnMsIE1NSU8sDQo+IGFuZCBJL08gcG9ydCByZXNvdXJjZXMuDQo+IA0K
PiBUaGUgcmVhc29uIGlzIHRoYXQgd2hlbiB3ZSBlbnVtZXJhdGUgYSBQQ0ktdG8tUENJIGJyaWRn
ZSwgd2UgaGF2ZSB0bw0KPiBrbm93IHdoZXRoZXIgYnVzIG51bWJlcnMgYXJlIGF2YWlsYWJsZSBm
b3IgdGhlIHNlY29uZGFyeSBidXMuICBGb3INCj4gZXhhbXBsZSwgYXNzdW1lIHR3byBob3N0IGJy
aWRnZXMgY29uZmlndXJlZCAob3Igd2lyZWQpIGFzIGZvbGxvd3M6DQo+IA0KPiAgIEEgbGVhZHMg
dG8gW2J1cyAwMC0xZl0sIHdpdGggYXBlcnR1cmUgW21lbSAweDgwMDAwMDAwLTB4OGZmZmZmZmZd
DQo+ICAgQiBsZWFkcyB0byBbYnVzIDIwLWZmXSwgd2l0aCBhcGVydHVyZSBbbWVtIDB4OTAwMDAw
MDAtMHg5ZmZmZmZmZl0NCj4gDQo+IEZ1cnRoZXIsIGFzc3VtZSBhIFBDSS10by1QQ0kgYnJpZGdl
IGF0IDFmOjAwLjAuICBJZiB0aGUgaG9zdCBicmlkZ2UNCj4gZHJpdmVyIGRvZXNuJ3QgdGVsbCB1
cyB0aGUgW2J1cyAwMC0xZl0gcmFuZ2UgZm9yIGhvc3QgYnJpZGdlIEEsIHRoZQ0KPiBQQ0kgY29y
ZSB3aWxsIGFzc3VtZSBbYnVzIDAwLWZmXS4gIFdoZW4gdGhlIGNvcmUgZW51bWVyYXRlcyB0aGUN
Cj4gMWY6MDAuMCBicmlkZ2UsIGl0IHdpbGwgYXNzaWduIGJ1cyBudW1iZXIgMjAgdG8gaXRzIHNl
Y29uZGFyeSBidXMuDQo+IE5vdyBpdCBlbnVtZXJhdGVzIGRldmljZXMgb24gYnVzIDIwLiAgVGhl
IGNvcmUgZXhwZWN0cyB0aGlzIHRvIGJlIGRvbmUNCj4gdmlhIGhvc3QgYnJpZGdlIEEsIGJ1dCBl
bnVtZXJhdGlvbiB1c2VzIElELXJvdXRlZCBjb25maWcgdHJhbnNhY3Rpb25zLA0KPiBzbyB0aGV5
IGFyZSBjbGFpbWVkIGJ5IGhvc3QgYnJpZGdlIEIgaW5zdGVhZC4gIElmIHdlIGZpbmQgYSBkZXZp
Y2UNCj4gMjA6MDAuMCwgdGhlIGNvcmUgdGhpbmtzIGl0IGlzIGJlbG93IEEsIGJ1dCBpdCBpcyBy
ZWFsbHkgYmVsb3cgQi4NCj4gDQo+IE5vdyB3ZSBhc3NpZ24gcmVzb3VyY2VzIHRvIDIwOjAwLjAs
IGFuZCBzaW5jZSB3ZSB0aGluayBpdCdzIGJlbG93IEEsDQo+IHdlIGFzc2lnbiB0aGVtIGZyb20g
dGhlIFttZW0gMHg4MDAwMDAwMC0weDhmZmZmZmZmXSBhcGVydHVyZS4gIFRoaXMNCj4gb2J2aW91
c2x5IGRvZXNuJ3Qgd29yaywgYmVjYXVzZSB3aGVuIHRoZSBkcml2ZXIgcGVyZm9ybXMgTU1JTw0K
PiBhY2Nlc3Nlcywgd2hpY2ggYXJlIGFkZHJlc3Mtcm91dGVkLCB0aGV5IGFyZSBjbGFpbWVkIGJ5
IGhvc3QgYnJpZGdlIEEsDQo+IG5vdCBCLCBzbyB0aGUgMjA6MDAuMCBkZXZpY2UgbmV2ZXIgc2Vl
cyB0aGVtLg0KVGhhbmtzIGZvciB0aGUgY2xlYXIgZXhwbGFuYXRpb24uDQoNCj4gSWYgeW91ciBo
b3N0IGJyaWRnZSByZWFsbHkgY2xhaW1zIEFMTCBidXMgbnVtYmVycyAoMDAtZmYpLCB0aGF0J3MN
Cj4gZmluZSwgYW5kIHlvdSBjYW4gdGVsbCB0aGUgUENJIGNvcmUgdGhhdC4gIEJ1dCBpZiB5b3Ug
aGF2ZSBzZXZlcmFsDQo+IHN1Y2ggYnJpZGdlcywgdGhleSBzaG91bGQgYmUgcGxhY2VkIGluIHNl
cGFyYXRlIGRvbWFpbnMuDQpUaGF0IG1ha2VzIHNlbnNlLg0KDQpJbiB0aGUgY2FzZSBvZiB0aGUg
Ui1DYXIgUENJZSBob3N0IGJyaWRnZSwgYXMgZmFyIGFzIEkgY2FuIHRlbGwsIHRoZSBoYXJkd2Fy
ZSBkb2VzbuKAmXQgY2FyZSBhYm91dCBidXMgbnVtYmVycyBhdCBhbGwsIHdpdGggdGhlIGV4Y2Vw
dGlvbiB0aGF0IHRoZSBkcml2ZXIgdXNlcyBvbmUgYnVzIG51bWJlciB0byB0YXJnZXQgdGhlIGJy
aWRnZSBpdHNlbGYuIFdlIGNhbiB1c2UgYXMgbWFueSBvciBhcyBmZXcgYnVzIG51bWJlcnMgZm9y
IHRoZSBzZWNvbmRhcnkgYnVzIGFzIHlvdSBsaWtlLg0KDQpTbywgdGhlIFItQ2FyIFBDSWUgZHJp
dmVyIHNob3VsZCBpbXBsZW1lbnQgYnVzIHJhbmdlcywgYnV0IHNob3VsZCBpdCBhbHNvIHVzZSBz
ZXBhcmF0ZSBQQ0kgZG9tYWlucyBmb3IgbXVsdGlwbGUgY29udHJvbGxlcnM/DQoNCj4gVGhpcyBp
cyBwcm9iYWJseSBtb3JlIGRldGFpbCB0aGFuIHlvdSB3YW50ZWQsIGFuZCBtYXliZSB5b3UgZG9u
J3QgZXZlcg0KPiBleHBlY3QgdG8gaGF2ZSBtdWx0aXBsZSBob3N0IGJyaWRnZXMgb3IgY29tcGxp
Y2F0ZWQgaGllcmFyY2hpZXMgb2YNCj4gZGV2aWNlcy4gIEJ1dCB0aGUgUENJIGNvcmUgaGFzIHRv
IGRlYWwgd2l0aCB0aGVzZSBpc3N1ZXMgb24gb3RoZXINCj4gc3lzdGVtcywgc28gaXQncyBpbXBv
cnRhbnQgdG8gZ2V0IHRoZXNlIGRldGFpbHMgcmlnaHQuDQoNClRoYW5rcw0KUGhpbA0K

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver
@ 2014-05-06 12:49                     ` Phil Edworthy
  0 siblings, 0 replies; 81+ messages in thread
From: Phil Edworthy @ 2014-05-06 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Bjorn,

On 01 May 2014 18:31, Bjorn wrote:
> [+cc Srikanth, Michal, Grant because we're having the same discussion
> about root bus numbers in the Xilinx host bridge driver]
> 
> On Thu, May 1, 2014 at 3:50 AM, Phil Edworthy
> <phil.edworthy@renesas.com> wrote:
> 
> > 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.
Thanks for the clear explanation.

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

> 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

^ permalink raw reply	[flat|nested] 81+ messages in thread

end of thread, other threads:[~2014-05-06 12:49 UTC | newest]

Thread overview: 81+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-31 10:30 [PATCH v7 00/10] R-Car Gen2 PCIe host driver Phil Edworthy
2014-03-31 10:30 ` Phil Edworthy
2014-03-31 10:30 ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 01/10] PCI: host: rcar: Add Renesas R-Car PCIe driver Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-04-24 19:19   ` Bjorn Helgaas
2014-04-24 19:19     ` Bjorn Helgaas
2014-04-24 19:19     ` Bjorn Helgaas
2014-04-28 10:03     ` Phil Edworthy
2014-04-28 10:03       ` Phil Edworthy
2014-04-28 10:03       ` Phil Edworthy
2014-04-28 19:11       ` Bjorn Helgaas
2014-04-28 19:11         ` Bjorn Helgaas
2014-04-28 19:11         ` Bjorn Helgaas
2014-04-28 20:35         ` Jason Gunthorpe
2014-04-28 20:35           ` Jason Gunthorpe
2014-04-28 20:35           ` Jason Gunthorpe
2014-04-30 10:33           ` Phil Edworthy
2014-04-30 10:33             ` Phil Edworthy
2014-04-30 10:33             ` Phil Edworthy
2014-04-30 15:43             ` Jason Gunthorpe
2014-04-30 15:43               ` Jason Gunthorpe
2014-04-30 15:43               ` Jason Gunthorpe
2014-05-01  9:50               ` Phil Edworthy
2014-05-01  9:50                 ` Phil Edworthy
2014-05-01  9:50                 ` Phil Edworthy
2014-05-01 16:50                 ` Jason Gunthorpe
2014-05-01 16:50                   ` Jason Gunthorpe
2014-05-01 16:50                   ` Jason Gunthorpe
2014-05-06 10:46                   ` Phil Edworthy
2014-05-06 10:46                     ` Phil Edworthy
2014-05-06 10:46                     ` Phil Edworthy
2014-05-01 17:31                 ` Bjorn Helgaas
2014-05-01 17:31                   ` Bjorn Helgaas
2014-05-01 17:31                   ` Bjorn Helgaas
2014-05-06 12:49                   ` Phil Edworthy
2014-05-06 12:49                     ` Phil Edworthy
2014-05-06 12:49                     ` Phil Edworthy
2014-04-30 10:20         ` Phil Edworthy
2014-04-30 10:20           ` Phil Edworthy
2014-04-30 10:20           ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 02/10] PCI: host: rcar: Add MSI support Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-04-04  8:53   ` Lucas Stach
2014-04-04  8:53     ` Lucas Stach
2014-04-04  8:53     ` Lucas Stach
2014-03-31 10:30 ` [PATCH v7 03/10] ARM: shmobile: r8a7790: Add PCIe clock device tree nodes Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 04/10] ARM: shmobile: r8a7791: " Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 05/10] dt-bindings: pci: rcar pcie device tree bindings Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-04-04  9:08   ` Lucas Stach
2014-04-04  9:08     ` Lucas Stach
2014-04-04  9:08     ` Lucas Stach
2014-03-31 10:30 ` [PATCH v7 06/10] ARM: shmobile: r8a7790: Add PCIe device nodes Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 07/10] ARM: shmobile: lager: " Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 08/10] ARM: shmobile: r8a7791: " Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 09/10] ARM: shmobile: koelsch: " Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30 ` [PATCH v7 10/10] ARM: shmobile: koelsch: Add PCIe to defconfig Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-03-31 10:30   ` Phil Edworthy
2014-04-04  8:22 ` [PATCH v7 00/10] R-Car Gen2 PCIe host driver Phil Edworthy
2014-04-04  8:22   ` Phil Edworthy
2014-04-04  8:22   ` Phil Edworthy
2014-04-04  8:30 ` Phil Edworthy
2014-04-04  8:30   ` Phil Edworthy
2014-04-04  8:30   ` Phil Edworthy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.