All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/5] Add Keystone PCIe controller driver
@ 2014-05-15 16:01 ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-kernel, linux-pci, linux-arm-kernel
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas

This patch adds a PCIe controller driver for Keystone SoCs. This
is based on the origin RFC patch that I had sent earlier. I have
incorporated following comments:-

 - Add a interrupt controller node for Legacy irq chip and use
   interrupt map/map-mask property to map legacy IRQs A/B/C/D
 - Add a Phy driver to replace the original serdes driver
 - Move common applicaiton register handling code to a separate
   file to allow re-use across other platforms that use older
   DW PCIe h/w
 - PCI quirk for maximum read request size. Check and override only
   if the maximum is higher than what controller can handle.
 - Converted to a module platform driver.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>


Murali Karicheri (5):
  ARM: keystone: add pcie related options
  pci: designware: enhancements to support keystone pcie
  phy: pci serdes phy driver for keystone
  pci: dw: add common functions to support old hw based pci driver
  pci: keystone: add pcie driver based on designware core driver

 .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
 arch/arm/mach-keystone/Kconfig                     |    2 +
 drivers/pci/host/Kconfig                           |   12 +
 drivers/pci/host/Makefile                          |    2 +
 drivers/pci/host/pci-dw-old-msi.c                  |  150 ++++++++
 drivers/pci/host/pci-dw-old.c                      |  371 ++++++++++++++++++
 drivers/pci/host/pci-dw-old.h                      |   30 ++
 drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
 drivers/pci/host/pcie-designware.c                 |  101 +++--
 drivers/pci/host/pcie-designware.h                 |   42 +-
 drivers/pci/quirks.c                               |   13 +
 drivers/phy/Kconfig                                |    6 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-keystone.c                         |  230 +++++++++++
 14 files changed, 1388 insertions(+), 40 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
 create mode 100644 drivers/pci/host/pci-dw-old-msi.c
 create mode 100644 drivers/pci/host/pci-dw-old.c
 create mode 100644 drivers/pci/host/pci-dw-old.h
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/phy/phy-keystone.c

-- 
1.7.9.5


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

* [PATCH v1 0/5] Add Keystone PCIe controller driver
@ 2014-05-15 16:01 ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a PCIe controller driver for Keystone SoCs. This
is based on the origin RFC patch that I had sent earlier. I have
incorporated following comments:-

 - Add a interrupt controller node for Legacy irq chip and use
   interrupt map/map-mask property to map legacy IRQs A/B/C/D
 - Add a Phy driver to replace the original serdes driver
 - Move common applicaiton register handling code to a separate
   file to allow re-use across other platforms that use older
   DW PCIe h/w
 - PCI quirk for maximum read request size. Check and override only
   if the maximum is higher than what controller can handle.
 - Converted to a module platform driver.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>


Murali Karicheri (5):
  ARM: keystone: add pcie related options
  pci: designware: enhancements to support keystone pcie
  phy: pci serdes phy driver for keystone
  pci: dw: add common functions to support old hw based pci driver
  pci: keystone: add pcie driver based on designware core driver

 .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
 arch/arm/mach-keystone/Kconfig                     |    2 +
 drivers/pci/host/Kconfig                           |   12 +
 drivers/pci/host/Makefile                          |    2 +
 drivers/pci/host/pci-dw-old-msi.c                  |  150 ++++++++
 drivers/pci/host/pci-dw-old.c                      |  371 ++++++++++++++++++
 drivers/pci/host/pci-dw-old.h                      |   30 ++
 drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
 drivers/pci/host/pcie-designware.c                 |  101 +++--
 drivers/pci/host/pcie-designware.h                 |   42 +-
 drivers/pci/quirks.c                               |   13 +
 drivers/phy/Kconfig                                |    6 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-keystone.c                         |  230 +++++++++++
 14 files changed, 1388 insertions(+), 40 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
 create mode 100644 drivers/pci/host/pci-dw-old-msi.c
 create mode 100644 drivers/pci/host/pci-dw-old.c
 create mode 100644 drivers/pci/host/pci-dw-old.h
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/phy/phy-keystone.c

-- 
1.7.9.5

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

* [PATCH v1 1/5] ARM: keystone: add pcie related options
  2014-05-15 16:01 ` Murali Karicheri
@ 2014-05-15 16:01   ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-kernel, linux-pci, linux-arm-kernel
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King

Add pcie related options by default for keystone architecture

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 arch/arm/mach-keystone/Kconfig |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index f50bc93..f87844d 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -8,6 +8,8 @@ config ARCH_KEYSTONE
 	select COMMON_CLK_KEYSTONE
 	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ZONE_DMA if ARM_LPAE
+	select MIGHT_HAVE_PCI
+	select ARCH_SUPPORTS_MSI
 	help
 	  Support for boards based on the Texas Instruments Keystone family of
 	  SoCs.
-- 
1.7.9.5


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

* [PATCH v1 1/5] ARM: keystone: add pcie related options
@ 2014-05-15 16:01   ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

Add pcie related options by default for keystone architecture

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 arch/arm/mach-keystone/Kconfig |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index f50bc93..f87844d 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -8,6 +8,8 @@ config ARCH_KEYSTONE
 	select COMMON_CLK_KEYSTONE
 	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ZONE_DMA if ARM_LPAE
+	select MIGHT_HAVE_PCI
+	select ARCH_SUPPORTS_MSI
 	help
 	  Support for boards based on the Texas Instruments Keystone family of
 	  SoCs.
-- 
1.7.9.5

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

* [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
  2014-05-15 16:01 ` Murali Karicheri
@ 2014-05-15 16:01   ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-kernel, linux-pci, linux-arm-kernel
  Cc: Murali Karicheri, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Santosh Shilimkar

keystone pcie hardware is based on designware hw version 3.65.
There is no support for ATU port and has registers in
application space to configure inbound/outbound access. Also
doesn't support PCI PVM option. The MSI IRQ registers available
in application space is used to mask/unmask/enable the MSI IRQs.

DW core driver is a set of common functions that are abstracted
to support DW pci drivers. To allow re-use of these functions for
keystone pci driver, core driver is to be enhanced.

Following are done to allow re-use of the functions on keystone pci
driver.

 1. Some of the variables in pcie_port struct is folded inside
    a union that now contains both new DW hw related variables as well
    as old hardware related variables such as application reg base.
 2. Added a dw_pcie_common_host_init() function that holds common
    host initialization code for old and new hw.
 3. dw_pcie_parse_resource() is used for parsing resource related
    information from DT bindings.
 4. dw_pcie_host_init() is called by new DW hw drivers as before.
    Added dw_old_pcie_host_init() is it's counter part on old dw hw.
    Both these functions now call dw_pcie_common_host_init().
 5. Some of the static functions are made global to allow use from
    dw old pci drivers such as pci-keystone.

CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Santosh Shilimkar <santosh.shilimkar@ti.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
 drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
 2 files changed, 103 insertions(+), 40 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index c4e3732..9ea8e79 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 		}
 		set_bit(pos0 + i, pp->msi_irq_in_use);
 		/*Enable corresponding interrupt in MSI interrupt controller */
-		res = ((pos0 + i) / 32) * 12;
-		bit = (pos0 + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val |= 1 << bit;
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (!(pp->version & DW_VERSION_OLD)) {
+			res = ((pos0 + i) / 32) * 12;
+			bit = (pos0 + i) % 32;
+			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
+						 4, &val);
+			val |= 1 << bit;
+			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
+						 4, val);
+		}
 	}
 
 	*pos = pos0;
@@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
 	 */
 	desc->msi_attrib.multiple = msgvec;
 
-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
+	if (pp->ops->get_msi_data)
+		msg.address_lo = pp->ops->get_msi_data(pp);
+	else
+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
 	msg.address_hi = 0x0;
 	msg.data = pos;
 	write_msi_msg(irq, &msg);
@@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
 	.map = dw_pcie_msi_map,
 };
 
-int __init dw_pcie_host_init(struct pcie_port *pp)
+int __init dw_pcie_parse_resource(struct pcie_port *pp)
 {
 	struct device_node *np = pp->dev->of_node;
-	struct of_pci_range range;
 	struct of_pci_range_parser parser;
-	u32 val;
-	int i;
+	struct of_pci_range range;
 
 	if (of_pci_range_parser_init(&parser, np)) {
 		dev_err(pp->dev, "missing ranges property\n");
@@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 			return -ENOMEM;
 		}
 	}
-
-	pp->cfg0_base = pp->cfg.start;
-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
 	pp->mem_base = pp->mem.start;
 
-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
-					pp->config.cfg0_size);
-	if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "error with ioremap in function\n");
-		return -ENOMEM;
-	}
-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
-					pp->config.cfg1_size);
-	if (!pp->va_cfg1_base) {
-		dev_err(pp->dev, "error with ioremap\n");
-		return -ENOMEM;
-	}
+	return 0;
+}
+
+int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
+				const struct irq_domain_ops *irq_msi_ops)
+{
+	struct device_node *np = pp->dev->of_node;
+	u32 val;
+	int i;
 
 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
 		dev_err(pp->dev, "Failed to parse the number of lanes\n");
@@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
-					MAX_MSI_IRQS, &msi_domain_ops,
+					MAX_MSI_IRQS, irq_msi_ops,
 					&dw_pcie_msi_chip);
 		if (!pp->irq_domain) {
 			dev_err(pp->dev, "irq domain init failed\n");
@@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	val |= PORT_LOGIC_SPEED_CHANGE;
 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
 
-	dw_pci.nr_controllers = 1;
-	dw_pci.private_data = (void **)&pp;
+	hw->nr_controllers = 1;
+	hw->private_data = (void **)&pp;
 
-	pci_common_init_dev(pp->dev, &dw_pci);
+	pci_common_init_dev(pp->dev, hw);
 	pci_assign_unassigned_resources();
 #ifdef CONFIG_PCI_DOMAINS
 	dw_pci.domain++;
@@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	return 0;
 }
 
+int __init dw_pcie_host_init(struct pcie_port *pp)
+{
+	int ret;
+
+	ret = dw_pcie_parse_resource(pp);
+	if (ret)
+		return ret;
+
+	pp->cfg0_base = pp->cfg.start;
+	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+					pp->config.cfg0_size);
+	if (!pp->va_cfg0_base) {
+		dev_err(pp->dev, "error with ioremap in function\n");
+		return -ENOMEM;
+	}
+	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+					pp->config.cfg1_size);
+	if (!pp->va_cfg1_base) {
+		dev_err(pp->dev, "error with ioremap\n");
+		return -ENOMEM;
+	}
+
+	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
+}
+
 static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
 {
 	/* Program viewport 0 : OUTBOUND : CFG0 */
@@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 
 	spin_lock_irqsave(&pp->conf_lock, flags);
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+		if (pp->ops->rd_other_conf)
+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 
 	spin_lock_irqsave(&pp->conf_lock, flags);
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+		if (pp->ops->wr_other_conf)
+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
@@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
 	.write = dw_pcie_wr_conf,
 };
 
-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 {
 	struct pcie_port *pp;
 
@@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 	return 1;
 }
 
-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 {
 	struct pci_bus *bus;
 	struct pcie_port *pp = sys_to_pcie(sys);
@@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 	return irq;
 }
 
-static void dw_pcie_add_bus(struct pci_bus *bus)
+void dw_pcie_add_bus(struct pci_bus *bus)
 {
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 3063b35..e97f4d7 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -35,21 +35,39 @@ struct pcie_port {
 	struct device		*dev;
 	u8			root_bus_nr;
 	void __iomem		*dbi_base;
-	u64			cfg0_base;
-	void __iomem		*va_cfg0_base;
-	u64			cfg1_base;
-	void __iomem		*va_cfg1_base;
+	/*
+	 * Old DW version implement application register space for
+	 * MSI and has no ATU view port
+	 */
+#define DW_VERSION_OLD	BIT(0)
+	u32			version;
+	union {
+		/* new dw core specific */
+		struct {
+			u64		cfg0_base;
+			void __iomem	*va_cfg0_base;
+			u64		cfg1_base;
+			void __iomem	*va_cfg1_base;
+			int		msi_irq;
+		};
+
+		/* old dw core specific */
+		struct  {
+			struct irq_domain	*legacy_irq_domain;
+			void __iomem		*va_app_base;
+			u64			app_base;
+		};
+	};
 	u64			io_base;
 	u64			mem_base;
 	spinlock_t		conf_lock;
-	struct resource		cfg;
 	struct resource		io;
 	struct resource		mem;
+	struct resource		cfg;
 	struct pcie_port_info	config;
 	int			irq;
 	u32			lanes;
 	struct pcie_host_ops	*ops;
-	int			msi_irq;
 	struct irq_domain	*irq_domain;
 	unsigned long		msi_data;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
@@ -62,8 +80,13 @@ struct pcie_host_ops {
 			u32 val, void __iomem *dbi_base);
 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 *val);
+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
+	u32 (*get_msi_data)(struct pcie_port *pp);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
@@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_setup(int nr, struct pci_sys_data *sys);
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
+void dw_pcie_add_bus(struct pci_bus *bus);
+int dw_pcie_parse_resource(struct pcie_port *pp);
 
+/* internal to dw core */
+int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
+			const struct irq_domain_ops *irq_ops);
 #endif /* _PCIE_DESIGNWARE_H */
-- 
1.7.9.5


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

* [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
@ 2014-05-15 16:01   ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

keystone pcie hardware is based on designware hw version 3.65.
There is no support for ATU port and has registers in
application space to configure inbound/outbound access. Also
doesn't support PCI PVM option. The MSI IRQ registers available
in application space is used to mask/unmask/enable the MSI IRQs.

DW core driver is a set of common functions that are abstracted
to support DW pci drivers. To allow re-use of these functions for
keystone pci driver, core driver is to be enhanced.

Following are done to allow re-use of the functions on keystone pci
driver.

 1. Some of the variables in pcie_port struct is folded inside
    a union that now contains both new DW hw related variables as well
    as old hardware related variables such as application reg base.
 2. Added a dw_pcie_common_host_init() function that holds common
    host initialization code for old and new hw.
 3. dw_pcie_parse_resource() is used for parsing resource related
    information from DT bindings.
 4. dw_pcie_host_init() is called by new DW hw drivers as before.
    Added dw_old_pcie_host_init() is it's counter part on old dw hw.
    Both these functions now call dw_pcie_common_host_init().
 5. Some of the static functions are made global to allow use from
    dw old pci drivers such as pci-keystone.

CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Santosh Shilimkar <santosh.shilimkar@ti.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
 drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
 2 files changed, 103 insertions(+), 40 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index c4e3732..9ea8e79 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 		}
 		set_bit(pos0 + i, pp->msi_irq_in_use);
 		/*Enable corresponding interrupt in MSI interrupt controller */
-		res = ((pos0 + i) / 32) * 12;
-		bit = (pos0 + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val |= 1 << bit;
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (!(pp->version & DW_VERSION_OLD)) {
+			res = ((pos0 + i) / 32) * 12;
+			bit = (pos0 + i) % 32;
+			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
+						 4, &val);
+			val |= 1 << bit;
+			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
+						 4, val);
+		}
 	}
 
 	*pos = pos0;
@@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
 	 */
 	desc->msi_attrib.multiple = msgvec;
 
-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
+	if (pp->ops->get_msi_data)
+		msg.address_lo = pp->ops->get_msi_data(pp);
+	else
+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
 	msg.address_hi = 0x0;
 	msg.data = pos;
 	write_msi_msg(irq, &msg);
@@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
 	.map = dw_pcie_msi_map,
 };
 
-int __init dw_pcie_host_init(struct pcie_port *pp)
+int __init dw_pcie_parse_resource(struct pcie_port *pp)
 {
 	struct device_node *np = pp->dev->of_node;
-	struct of_pci_range range;
 	struct of_pci_range_parser parser;
-	u32 val;
-	int i;
+	struct of_pci_range range;
 
 	if (of_pci_range_parser_init(&parser, np)) {
 		dev_err(pp->dev, "missing ranges property\n");
@@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 			return -ENOMEM;
 		}
 	}
-
-	pp->cfg0_base = pp->cfg.start;
-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
 	pp->mem_base = pp->mem.start;
 
-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
-					pp->config.cfg0_size);
-	if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "error with ioremap in function\n");
-		return -ENOMEM;
-	}
-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
-					pp->config.cfg1_size);
-	if (!pp->va_cfg1_base) {
-		dev_err(pp->dev, "error with ioremap\n");
-		return -ENOMEM;
-	}
+	return 0;
+}
+
+int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
+				const struct irq_domain_ops *irq_msi_ops)
+{
+	struct device_node *np = pp->dev->of_node;
+	u32 val;
+	int i;
 
 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
 		dev_err(pp->dev, "Failed to parse the number of lanes\n");
@@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
-					MAX_MSI_IRQS, &msi_domain_ops,
+					MAX_MSI_IRQS, irq_msi_ops,
 					&dw_pcie_msi_chip);
 		if (!pp->irq_domain) {
 			dev_err(pp->dev, "irq domain init failed\n");
@@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	val |= PORT_LOGIC_SPEED_CHANGE;
 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
 
-	dw_pci.nr_controllers = 1;
-	dw_pci.private_data = (void **)&pp;
+	hw->nr_controllers = 1;
+	hw->private_data = (void **)&pp;
 
-	pci_common_init_dev(pp->dev, &dw_pci);
+	pci_common_init_dev(pp->dev, hw);
 	pci_assign_unassigned_resources();
 #ifdef CONFIG_PCI_DOMAINS
 	dw_pci.domain++;
@@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	return 0;
 }
 
+int __init dw_pcie_host_init(struct pcie_port *pp)
+{
+	int ret;
+
+	ret = dw_pcie_parse_resource(pp);
+	if (ret)
+		return ret;
+
+	pp->cfg0_base = pp->cfg.start;
+	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+					pp->config.cfg0_size);
+	if (!pp->va_cfg0_base) {
+		dev_err(pp->dev, "error with ioremap in function\n");
+		return -ENOMEM;
+	}
+	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+					pp->config.cfg1_size);
+	if (!pp->va_cfg1_base) {
+		dev_err(pp->dev, "error with ioremap\n");
+		return -ENOMEM;
+	}
+
+	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
+}
+
 static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
 {
 	/* Program viewport 0 : OUTBOUND : CFG0 */
@@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 
 	spin_lock_irqsave(&pp->conf_lock, flags);
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+		if (pp->ops->rd_other_conf)
+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 
 	spin_lock_irqsave(&pp->conf_lock, flags);
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+		if (pp->ops->wr_other_conf)
+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
@@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
 	.write = dw_pcie_wr_conf,
 };
 
-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 {
 	struct pcie_port *pp;
 
@@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 	return 1;
 }
 
-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 {
 	struct pci_bus *bus;
 	struct pcie_port *pp = sys_to_pcie(sys);
@@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 	return irq;
 }
 
-static void dw_pcie_add_bus(struct pci_bus *bus)
+void dw_pcie_add_bus(struct pci_bus *bus)
 {
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 3063b35..e97f4d7 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -35,21 +35,39 @@ struct pcie_port {
 	struct device		*dev;
 	u8			root_bus_nr;
 	void __iomem		*dbi_base;
-	u64			cfg0_base;
-	void __iomem		*va_cfg0_base;
-	u64			cfg1_base;
-	void __iomem		*va_cfg1_base;
+	/*
+	 * Old DW version implement application register space for
+	 * MSI and has no ATU view port
+	 */
+#define DW_VERSION_OLD	BIT(0)
+	u32			version;
+	union {
+		/* new dw core specific */
+		struct {
+			u64		cfg0_base;
+			void __iomem	*va_cfg0_base;
+			u64		cfg1_base;
+			void __iomem	*va_cfg1_base;
+			int		msi_irq;
+		};
+
+		/* old dw core specific */
+		struct  {
+			struct irq_domain	*legacy_irq_domain;
+			void __iomem		*va_app_base;
+			u64			app_base;
+		};
+	};
 	u64			io_base;
 	u64			mem_base;
 	spinlock_t		conf_lock;
-	struct resource		cfg;
 	struct resource		io;
 	struct resource		mem;
+	struct resource		cfg;
 	struct pcie_port_info	config;
 	int			irq;
 	u32			lanes;
 	struct pcie_host_ops	*ops;
-	int			msi_irq;
 	struct irq_domain	*irq_domain;
 	unsigned long		msi_data;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
@@ -62,8 +80,13 @@ struct pcie_host_ops {
 			u32 val, void __iomem *dbi_base);
 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 *val);
+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
+	u32 (*get_msi_data)(struct pcie_port *pp);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
@@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_setup(int nr, struct pci_sys_data *sys);
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
+void dw_pcie_add_bus(struct pci_bus *bus);
+int dw_pcie_parse_resource(struct pcie_port *pp);
 
+/* internal to dw core */
+int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
+			const struct irq_domain_ops *irq_ops);
 #endif /* _PCIE_DESIGNWARE_H */
-- 
1.7.9.5

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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-05-15 16:01 ` Murali Karicheri
@ 2014-05-15 16:01   ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-kernel, linux-pci, linux-arm-kernel
  Cc: Murali Karicheri, Grant Likely, Rob Herring, Mohit Kumar,
	Jingoo Han, Bjorn Helgaas

This phy driver is used by keystone PCI driver. The hw vendor that
provides the phy hw published only registers and their values. So
this driver uses these hard coded values to initialize the phy.

CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 drivers/phy/Kconfig        |    6 ++
 drivers/phy/Makefile       |    1 +
 drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 237 insertions(+)
 create mode 100644 drivers/phy/phy-keystone.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 4906c27..e5f4b5a 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -167,4 +167,10 @@ config PHY_XGENE
 	help
 	  This option enables support for APM X-Gene SoC multi-purpose PHY.
 
+config PHY_TI_KEYSTONE
+	bool "TI Keystone PHY support"
+	depends on ARCH_KEYSTONE
+	select GENERIC_PHY
+	help
+	  This option enables support for TI Keystone PHY (serdes).
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 7728518..bd306a7 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
 phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
 obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
+obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
new file mode 100644
index 0000000..ba1b9fa
--- /dev/null
+++ b/drivers/phy/phy-keystone.c
@@ -0,0 +1,230 @@
+/*
+ * PCIe Keystone platform specific driver code
+ *
+ * Copyright (C) 2013-2014 Texas Instruments, Inc.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#define reg_dump(addr, mask) \
+		pr_debug("reg %p has value %x\n", (void *)addr, \
+			(readl(addr) & ~mask))
+
+/* mask bits point to bits being modified */
+#define reg_rmw(addr, value, mask) \
+		writel(((readl(addr) & (~(mask))) | \
+			(value & (mask))), (addr))
+struct serdes_config {
+	u32 reg;
+	u32 val;
+	u32 mask;
+};
+
+struct phy_keystone {
+	struct device *dev;
+	void __iomem *base;
+};
+
+static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
+	{0x0000, 0x00000800, 0x0000ff00},
+	{0x0060, 0x00041c5c, 0x00ffffff},
+	{0x0064, 0x0343c700, 0xffffff00},
+	{0x006c, 0x00000012, 0x000000ff},
+	{0x0068, 0x00070000, 0x00ff0000},
+	{0x0078, 0x0000c000, 0x0000ff00},
+
+	{0x0200, 0x00000000, 0x000000ff},
+	{0x0204, 0x5e000080, 0xff0000ff},
+	{0x0208, 0x00000006, 0x000000ff},
+	{0x0210, 0x00000023, 0x000000ff},
+	{0x0214, 0x2e003060, 0xff00ffff},
+	{0x0218, 0x76000000, 0xff000000},
+	{0x022c, 0x00200002, 0x00ff00ff},
+	{0x02a0, 0xffee0000, 0xffff0000},
+	{0x02a4, 0x0000000f, 0x000000ff},
+	{0x0204, 0x5e000000, 0xff000000},
+	{0x0208, 0x00000006, 0x000000ff},
+	{0x0278, 0x00002000, 0x0000ff00},
+	{0x0280, 0x00280028, 0x00ff00ff},
+	{0x0284, 0x2d0f0385, 0xffffffff},
+	{0x0250, 0xd0000000, 0xff000000},
+	{0x0284, 0x00000085, 0x000000ff},
+	{0x0294, 0x20000000, 0xff000000},
+
+	{0x0400, 0x00000000, 0x000000ff},
+	{0x0404, 0x5e000080, 0xff0000ff},
+	{0x0408, 0x00000006, 0x000000ff},
+	{0x0410, 0x00000023, 0x000000ff},
+	{0x0414, 0x2e003060, 0xff00ffff},
+	{0x0418, 0x76000000, 0xff000000},
+	{0x042c, 0x00200002, 0x00ff00ff},
+	{0x04a0, 0xffee0000, 0xffff0000},
+	{0x04a4, 0x0000000f, 0x000000ff},
+	{0x0404, 0x5e000000, 0xff000000},
+	{0x0408, 0x00000006, 0x000000ff},
+	{0x0478, 0x00002000, 0x0000ff00},
+	{0x0480, 0x00280028, 0x00ff00ff},
+	{0x0484, 0x2d0f0385, 0xffffffff},
+	{0x0450, 0xd0000000, 0xff000000},
+	{0x0494, 0x20000000, 0xff000000},
+
+	{0x0604, 0x00000080, 0x000000ff},
+	{0x0600, 0x00000000, 0x000000ff},
+	{0x0604, 0x5e000000, 0xff000000},
+	{0x0608, 0x00000006, 0x000000ff},
+	{0x0610, 0x00000023, 0x000000ff},
+	{0x0614, 0x2e003060, 0xff00ffff},
+	{0x0618, 0x76000000, 0xff000000},
+	{0x062c, 0x00200002, 0x00ff00ff},
+	{0x06a0, 0xffee0000, 0xffff0000},
+	{0x06a4, 0x0000000f, 0x000000ff},
+	{0x0604, 0x5e000000, 0xff000000},
+	{0x0608, 0x00000006, 0x000000ff},
+	{0x0678, 0x00002000, 0x0000ff00},
+	{0x0680, 0x00280028, 0x00ff00ff},
+	{0x0684, 0x2d0f0385, 0xffffffff},
+	{0x0650, 0xd0000000, 0xff000000},
+	{0x0694, 0x20000000, 0xff000000},
+
+	{0x0800, 0x00000000, 0x000000ff},
+	{0x0804, 0x5e000080, 0xff0000ff},
+	{0x0808, 0x00000006, 0x000000ff},
+	{0x0810, 0x00000023, 0x000000ff},
+	{0x0814, 0x2e003060, 0xff00ffff},
+	{0x0818, 0x76000000, 0xff000000},
+	{0x082c, 0x00200002, 0x00ff00ff},
+	{0x08a0, 0xffee0000, 0xffff0000},
+	{0x08a4, 0x0000000f, 0x000000ff},
+	{0x0804, 0x5e000000, 0xff000000},
+	{0x0808, 0x00000006, 0x000000ff},
+	{0x0878, 0x00002000, 0x0000ff00},
+	{0x0880, 0x00280028, 0x00ff00ff},
+	{0x0884, 0x2d0f0385, 0xffffffff},
+	{0x0850, 0xd0000000, 0xff000000},
+	{0x0894, 0x20000000, 0xff000000},
+
+	{0x0a00, 0x00000100, 0x0000ff00},
+	{0x0a08, 0x00e12c08, 0x00ffffff},
+	{0x0a0c, 0x00000081, 0x000000ff},
+	{0x0a18, 0x00e80000, 0x00ff0000},
+	{0x0a30, 0x002f2f00, 0x00ffff00},
+	{0x0a4c, 0xac820000, 0xffff0000},
+	{0x0a54, 0xc0000000, 0xff000000},
+	{0x0a58, 0x00001441, 0x0000ffff},
+	{0x0a84, 0x00000301, 0x0000ffff},
+
+	{0x0a8c, 0x81030000, 0xffff0000},
+	{0x0a90, 0x00006001, 0x0000ffff},
+	{0x0a94, 0x01000000, 0xff000000},
+	{0x0aa0, 0x81000000, 0xff000000},
+	{0x0abc, 0xff000000, 0xff000000},
+	{0x0ac0, 0x0000008b, 0x000000ff},
+
+	{0x0000, 0x00000003, 0x000000ff},
+	{0x0a00, 0x0000009f, 0x000000ff},
+
+	{0x0a44, 0x5f733d00, 0xffffff00},
+	{0x0a48, 0x00fdca00, 0x00ffff00},
+	{0x0a5c, 0x00000000, 0xffff0000},
+	{0x0a60, 0x00008000, 0xffffffff},
+	{0x0a64, 0x0c581220, 0xffffffff},
+	{0x0a68, 0xe13b0602, 0xffffffff},
+	{0x0a6c, 0xb8074cc1, 0xffffffff},
+	{0x0a70, 0x3f02e989, 0xffffffff},
+	{0x0a74, 0x00000001, 0x000000ff},
+	{0x0b14, 0x00370000, 0x00ff0000},
+	{0x0b10, 0x37000000, 0xff000000},
+	{0x0b14, 0x0000005d, 0x000000ff},
+};
+
+static int ks_phy_init(struct phy *phy)
+{
+	struct serdes_config *p;
+	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
+
+	int i;
+
+	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
+		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
+		i++, p++) {
+		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
+		reg_dump((ks_phy->base + p->reg), p->mask);
+	}
+	udelay(2000);
+
+	return 0;
+}
+
+static struct phy_ops ks_phy_ops = {
+	.init		= ks_phy_init,
+	.owner		= THIS_MODULE,
+};
+
+static int ks_phy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct phy_keystone *ks_phy;
+	struct phy *phy;
+	struct resource *res;
+
+	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
+	if (!ks_phy)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
+	ks_phy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ks_phy->base))
+		return PTR_ERR(ks_phy->base);
+
+	ks_phy->dev = dev;
+	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
+	if (IS_ERR(phy))
+		return PTR_ERR(phy);
+
+	phy_set_drvdata(phy, ks_phy);
+	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
+				of_phy_simple_xlate);
+
+	if (IS_ERR(phy_provider))
+		return PTR_ERR(phy_provider);
+
+	dev_info(dev, "keystone phy initialized\n");
+	return 0;
+}
+
+static const struct of_device_id ks_phy_of_match[] = {
+	{ .compatible = "ti,keystone-phy" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_phy_of_match);
+
+static struct platform_driver ks_phy_driver = {
+	.probe	= ks_phy_probe,
+	.driver = {
+		.of_match_table	= ks_phy_of_match,
+		.name  = "ti,keystone-phy",
+		.owner = THIS_MODULE,
+	}
+};
+module_platform_driver(ks_phy_driver);
+
+MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
+MODULE_LICENSE("GPL V2");
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
-- 
1.7.9.5


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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-15 16:01   ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

This phy driver is used by keystone PCI driver. The hw vendor that
provides the phy hw published only registers and their values. So
this driver uses these hard coded values to initialize the phy.

CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 drivers/phy/Kconfig        |    6 ++
 drivers/phy/Makefile       |    1 +
 drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 237 insertions(+)
 create mode 100644 drivers/phy/phy-keystone.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 4906c27..e5f4b5a 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -167,4 +167,10 @@ config PHY_XGENE
 	help
 	  This option enables support for APM X-Gene SoC multi-purpose PHY.
 
+config PHY_TI_KEYSTONE
+	bool "TI Keystone PHY support"
+	depends on ARCH_KEYSTONE
+	select GENERIC_PHY
+	help
+	  This option enables support for TI Keystone PHY (serdes).
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 7728518..bd306a7 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
 phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
 obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
+obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
new file mode 100644
index 0000000..ba1b9fa
--- /dev/null
+++ b/drivers/phy/phy-keystone.c
@@ -0,0 +1,230 @@
+/*
+ * PCIe Keystone platform specific driver code
+ *
+ * Copyright (C) 2013-2014 Texas Instruments, Inc.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#define reg_dump(addr, mask) \
+		pr_debug("reg %p has value %x\n", (void *)addr, \
+			(readl(addr) & ~mask))
+
+/* mask bits point to bits being modified */
+#define reg_rmw(addr, value, mask) \
+		writel(((readl(addr) & (~(mask))) | \
+			(value & (mask))), (addr))
+struct serdes_config {
+	u32 reg;
+	u32 val;
+	u32 mask;
+};
+
+struct phy_keystone {
+	struct device *dev;
+	void __iomem *base;
+};
+
+static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
+	{0x0000, 0x00000800, 0x0000ff00},
+	{0x0060, 0x00041c5c, 0x00ffffff},
+	{0x0064, 0x0343c700, 0xffffff00},
+	{0x006c, 0x00000012, 0x000000ff},
+	{0x0068, 0x00070000, 0x00ff0000},
+	{0x0078, 0x0000c000, 0x0000ff00},
+
+	{0x0200, 0x00000000, 0x000000ff},
+	{0x0204, 0x5e000080, 0xff0000ff},
+	{0x0208, 0x00000006, 0x000000ff},
+	{0x0210, 0x00000023, 0x000000ff},
+	{0x0214, 0x2e003060, 0xff00ffff},
+	{0x0218, 0x76000000, 0xff000000},
+	{0x022c, 0x00200002, 0x00ff00ff},
+	{0x02a0, 0xffee0000, 0xffff0000},
+	{0x02a4, 0x0000000f, 0x000000ff},
+	{0x0204, 0x5e000000, 0xff000000},
+	{0x0208, 0x00000006, 0x000000ff},
+	{0x0278, 0x00002000, 0x0000ff00},
+	{0x0280, 0x00280028, 0x00ff00ff},
+	{0x0284, 0x2d0f0385, 0xffffffff},
+	{0x0250, 0xd0000000, 0xff000000},
+	{0x0284, 0x00000085, 0x000000ff},
+	{0x0294, 0x20000000, 0xff000000},
+
+	{0x0400, 0x00000000, 0x000000ff},
+	{0x0404, 0x5e000080, 0xff0000ff},
+	{0x0408, 0x00000006, 0x000000ff},
+	{0x0410, 0x00000023, 0x000000ff},
+	{0x0414, 0x2e003060, 0xff00ffff},
+	{0x0418, 0x76000000, 0xff000000},
+	{0x042c, 0x00200002, 0x00ff00ff},
+	{0x04a0, 0xffee0000, 0xffff0000},
+	{0x04a4, 0x0000000f, 0x000000ff},
+	{0x0404, 0x5e000000, 0xff000000},
+	{0x0408, 0x00000006, 0x000000ff},
+	{0x0478, 0x00002000, 0x0000ff00},
+	{0x0480, 0x00280028, 0x00ff00ff},
+	{0x0484, 0x2d0f0385, 0xffffffff},
+	{0x0450, 0xd0000000, 0xff000000},
+	{0x0494, 0x20000000, 0xff000000},
+
+	{0x0604, 0x00000080, 0x000000ff},
+	{0x0600, 0x00000000, 0x000000ff},
+	{0x0604, 0x5e000000, 0xff000000},
+	{0x0608, 0x00000006, 0x000000ff},
+	{0x0610, 0x00000023, 0x000000ff},
+	{0x0614, 0x2e003060, 0xff00ffff},
+	{0x0618, 0x76000000, 0xff000000},
+	{0x062c, 0x00200002, 0x00ff00ff},
+	{0x06a0, 0xffee0000, 0xffff0000},
+	{0x06a4, 0x0000000f, 0x000000ff},
+	{0x0604, 0x5e000000, 0xff000000},
+	{0x0608, 0x00000006, 0x000000ff},
+	{0x0678, 0x00002000, 0x0000ff00},
+	{0x0680, 0x00280028, 0x00ff00ff},
+	{0x0684, 0x2d0f0385, 0xffffffff},
+	{0x0650, 0xd0000000, 0xff000000},
+	{0x0694, 0x20000000, 0xff000000},
+
+	{0x0800, 0x00000000, 0x000000ff},
+	{0x0804, 0x5e000080, 0xff0000ff},
+	{0x0808, 0x00000006, 0x000000ff},
+	{0x0810, 0x00000023, 0x000000ff},
+	{0x0814, 0x2e003060, 0xff00ffff},
+	{0x0818, 0x76000000, 0xff000000},
+	{0x082c, 0x00200002, 0x00ff00ff},
+	{0x08a0, 0xffee0000, 0xffff0000},
+	{0x08a4, 0x0000000f, 0x000000ff},
+	{0x0804, 0x5e000000, 0xff000000},
+	{0x0808, 0x00000006, 0x000000ff},
+	{0x0878, 0x00002000, 0x0000ff00},
+	{0x0880, 0x00280028, 0x00ff00ff},
+	{0x0884, 0x2d0f0385, 0xffffffff},
+	{0x0850, 0xd0000000, 0xff000000},
+	{0x0894, 0x20000000, 0xff000000},
+
+	{0x0a00, 0x00000100, 0x0000ff00},
+	{0x0a08, 0x00e12c08, 0x00ffffff},
+	{0x0a0c, 0x00000081, 0x000000ff},
+	{0x0a18, 0x00e80000, 0x00ff0000},
+	{0x0a30, 0x002f2f00, 0x00ffff00},
+	{0x0a4c, 0xac820000, 0xffff0000},
+	{0x0a54, 0xc0000000, 0xff000000},
+	{0x0a58, 0x00001441, 0x0000ffff},
+	{0x0a84, 0x00000301, 0x0000ffff},
+
+	{0x0a8c, 0x81030000, 0xffff0000},
+	{0x0a90, 0x00006001, 0x0000ffff},
+	{0x0a94, 0x01000000, 0xff000000},
+	{0x0aa0, 0x81000000, 0xff000000},
+	{0x0abc, 0xff000000, 0xff000000},
+	{0x0ac0, 0x0000008b, 0x000000ff},
+
+	{0x0000, 0x00000003, 0x000000ff},
+	{0x0a00, 0x0000009f, 0x000000ff},
+
+	{0x0a44, 0x5f733d00, 0xffffff00},
+	{0x0a48, 0x00fdca00, 0x00ffff00},
+	{0x0a5c, 0x00000000, 0xffff0000},
+	{0x0a60, 0x00008000, 0xffffffff},
+	{0x0a64, 0x0c581220, 0xffffffff},
+	{0x0a68, 0xe13b0602, 0xffffffff},
+	{0x0a6c, 0xb8074cc1, 0xffffffff},
+	{0x0a70, 0x3f02e989, 0xffffffff},
+	{0x0a74, 0x00000001, 0x000000ff},
+	{0x0b14, 0x00370000, 0x00ff0000},
+	{0x0b10, 0x37000000, 0xff000000},
+	{0x0b14, 0x0000005d, 0x000000ff},
+};
+
+static int ks_phy_init(struct phy *phy)
+{
+	struct serdes_config *p;
+	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
+
+	int i;
+
+	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
+		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
+		i++, p++) {
+		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
+		reg_dump((ks_phy->base + p->reg), p->mask);
+	}
+	udelay(2000);
+
+	return 0;
+}
+
+static struct phy_ops ks_phy_ops = {
+	.init		= ks_phy_init,
+	.owner		= THIS_MODULE,
+};
+
+static int ks_phy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct phy_keystone *ks_phy;
+	struct phy *phy;
+	struct resource *res;
+
+	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
+	if (!ks_phy)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
+	ks_phy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ks_phy->base))
+		return PTR_ERR(ks_phy->base);
+
+	ks_phy->dev = dev;
+	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
+	if (IS_ERR(phy))
+		return PTR_ERR(phy);
+
+	phy_set_drvdata(phy, ks_phy);
+	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
+				of_phy_simple_xlate);
+
+	if (IS_ERR(phy_provider))
+		return PTR_ERR(phy_provider);
+
+	dev_info(dev, "keystone phy initialized\n");
+	return 0;
+}
+
+static const struct of_device_id ks_phy_of_match[] = {
+	{ .compatible = "ti,keystone-phy" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_phy_of_match);
+
+static struct platform_driver ks_phy_driver = {
+	.probe	= ks_phy_probe,
+	.driver = {
+		.of_match_table	= ks_phy_of_match,
+		.name  = "ti,keystone-phy",
+		.owner = THIS_MODULE,
+	}
+};
+module_platform_driver(ks_phy_driver);
+
+MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
+MODULE_LICENSE("GPL V2");
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
-- 
1.7.9.5

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

* [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
  2014-05-15 16:01 ` Murali Karicheri
@ 2014-05-15 16:01   ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-kernel, linux-pci, linux-arm-kernel
  Cc: Murali Karicheri, Santosh Shilimkar, Mohit Kumar, Jingoo Han,
	Bjorn Helgaas

The older version of DW hw has application space registers for MSI
controller and inbound/outbound access configuration. Also the legacy
interrupt has registers in the application space. Drivers such as
keystone pci uses these common functions to implement the driver.
These are re-factored from the original driver to separate files
to allow re-use for the next driver that is based on old dw pci hw such
as that found on keystone.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 drivers/pci/host/Kconfig          |    6 +-
 drivers/pci/host/Makefile         |    1 +
 drivers/pci/host/pci-dw-old-msi.c |  150 +++++++++++++++
 drivers/pci/host/pci-dw-old.c     |  371 +++++++++++++++++++++++++++++++++++++
 drivers/pci/host/pci-dw-old.h     |   30 +++
 5 files changed, 557 insertions(+), 1 deletion(-)
 create mode 100644 drivers/pci/host/pci-dw-old-msi.c
 create mode 100644 drivers/pci/host/pci-dw-old.c
 create mode 100644 drivers/pci/host/pci-dw-old.h

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index a6f67ec..c4f4732 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -9,6 +9,11 @@ config PCI_MVEBU
 config PCIE_DW
 	bool
 
+config PCI_DW_OLD
+	bool "Designware Old PCIe h/w"
+	help
+	   Say Y here if the DW h/w is old version (3.65)
+
 config PCI_EXYNOS
 	bool "Samsung Exynos PCIe controller"
 	depends on SOC_EXYNOS5440
@@ -32,5 +37,4 @@ config PCI_RCAR_GEN2
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
-
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..be5d939 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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
diff --git a/drivers/pci/host/pci-dw-old-msi.c b/drivers/pci/host/pci-dw-old-msi.c
new file mode 100644
index 0000000..450bb2f
--- /dev/null
+++ b/drivers/pci/host/pci-dw-old-msi.c
@@ -0,0 +1,150 @@
+/*
+ * Designware(dw) old MSI controller (v3.65 or similar)
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of_irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+
+#include "pcie-designware.h"
+#include "pci-dw-old.h"
+
+#define MSI_IRQ				0x054
+#define MSI0_IRQ_STATUS			0x104
+#define MSI0_IRQ_ENABLE_SET		0x108
+#define MSI0_IRQ_ENABLE_CLR		0x10c
+#define IRQ_STATUS			0x184
+#define IRQ_EOI                         0x050
+#define MSI_IRQ_OFFSET			4
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
+					u32 *bit_pos)
+{
+	*reg_offset = offset % 8;
+	*bit_pos = offset >> 3;
+}
+
+inline u32 dw_old_get_msi_data(struct pcie_port *pp)
+{
+	return pp->app_base + MSI_IRQ;
+}
+
+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset)
+{
+	u32 pending, vector;
+	int src, virq;
+
+	pending = readl(pp->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
+	/*
+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+	 * shows 1, 9, 17, 25 and so forth
+	 */
+	for (src = 0; src < 4; src++) {
+		if (BIT(src) & pending) {
+			vector = offset + (src << 3);
+			virq = irq_linear_revmap(pp->irq_domain, vector);
+			dev_dbg(pp->dev,
+				"irq: bit %d, vector %d, virq %d\n",
+				 src, vector, virq);
+			generic_handle_irq(virq);
+		}
+	}
+}
+
+static void dw_old_msi_irq_ack(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	writel(BIT(bit_pos),
+		pp->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
+	writel(reg_offset + MSI_IRQ_OFFSET, pp->va_app_base + IRQ_EOI);
+}
+
+static void dw_old_msi_irq_mask(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			mask_msi_irq(d);
+	}
+
+	writel(BIT(bit_pos),
+		pp->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
+}
+
+static void dw_old_msi_irq_unmask(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			unmask_msi_irq(d);
+	}
+
+	writel(BIT(bit_pos),
+		pp->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
+}
+
+static struct irq_chip dw_old_msi_chip = {
+	.name = "PCI-DW-MSI-OLD",
+	.irq_ack = dw_old_msi_irq_ack,
+	.irq_mask = dw_old_msi_irq_mask,
+	.irq_unmask = dw_old_msi_irq_unmask,
+};
+
+static int dw_old_msi_map(struct irq_domain *domain, unsigned int irq,
+			irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &dw_old_msi_chip, handle_level_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+const struct irq_domain_ops dw_old_msi_domain_ops = {
+	.map = dw_old_msi_map,
+};
diff --git a/drivers/pci/host/pci-dw-old.c b/drivers/pci/host/pci-dw-old.c
new file mode 100644
index 0000000..b805013
--- /dev/null
+++ b/drivers/pci/host/pci-dw-old.c
@@ -0,0 +1,371 @@
+/*
+ * Designware(dw) old common functions (v3.65 or similar)
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+
+#include "pcie-designware.h"
+#include "pci-dw-old.h"
+
+/* Application register defines */
+#define LTSSM_EN_VAL		        BIT(0)
+#define LTSSM_STATE_MASK	        0x1f
+#define LTSSM_STATE_L0		        0x11
+#define DIR_SPD				(1 << 17)
+#define DBI_CS2_EN_VAL		        BIT(5)
+#define OB_XLAT_EN_VAL		        BIT(1)
+
+/* Application registers */
+#define CMD_STATUS			0x004
+#define CFG_SETUP			0x008
+#define OB_SIZE				0x030
+#define CFG_PCIM_WIN_SZ_IDX	        3
+#define CFG_PCIM_WIN_CNT	        32
+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
+#define IRQ_EOI                         0x050
+#define IRQ_STATUS			0x184
+#define IRQ_ENABLE_SET			0x188
+#define IRQ_ENABLE_CLR			0x18c
+
+/* Config space registers */
+#define DEBUG0			        0x728
+#define PL_GEN2			        0x80c
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+void dw_old_enable_legacy_irqs(struct pcie_port *pp)
+{
+	int i;
+
+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
+		writel(0x1, pp->va_app_base + IRQ_ENABLE_SET + (i << 4));
+}
+
+void dw_old_handle_legacy_irq(struct pcie_port *pp, int offset)
+{
+	u32 pending;
+	int virq;
+
+	pending = readl(pp->va_app_base + IRQ_STATUS + (offset << 4));
+
+	if (BIT(0) & pending) {
+		virq = irq_linear_revmap(pp->legacy_irq_domain, offset);
+		dev_dbg(pp->dev,
+			": irq: irq_offset %d, virq %d\n", offset, virq);
+		generic_handle_irq(virq);
+	}
+
+	/* EOI the INTx interrupt */
+	writel(offset, pp->va_app_base + IRQ_EOI);
+}
+
+static void dw_old_ack_irq(struct irq_data *d)
+{
+}
+
+static void dw_old_mask_irq(struct irq_data *d)
+{
+}
+
+static void dw_old_unmask_irq(struct irq_data *d)
+{
+}
+
+struct irq_chip dw_old_legacy_irq_chip = {
+	.name = "PCI-DW-LEGACY-old-irq",
+	.irq_ack = dw_old_ack_irq,
+	.irq_mask = dw_old_mask_irq,
+	.irq_unmask = dw_old_unmask_irq,
+};
+
+static int dw_old_init_legacy_irq_map(struct irq_domain *d, unsigned int irq,
+				      irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(irq, &dw_old_legacy_irq_chip,
+				handle_level_irq);
+	irq_set_chip_data(irq, d->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static const struct irq_domain_ops dw_old_legacy_irq_domian_ops = {
+	.map = dw_old_init_legacy_irq_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+/**
+ * dw_old_set_outbound_trans() - Set PHYADDR <-> BUSADDR
+ * mapping for outbound
+ */
+void dw_old_setup_ob_regs(struct pcie_port *pp)
+{
+	u32 start = pp->mem.start, end = pp->mem.end;
+	int i, tr_size;
+
+	dev_dbg(pp->dev, "Setting outbound translation for %#x-%#x\n",
+		start, end);
+
+	/* Set outbound translation size per window division */
+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, pp->va_app_base + OB_SIZE);
+
+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
+
+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
+		writel(start | 1, pp->va_app_base + OB_OFFSET_INDEX(i));
+		writel(0, pp->va_app_base + OB_OFFSET_HI(i));
+		start += tr_size;
+	}
+
+	/* Enable OB translation */
+	writel(OB_XLAT_EN_VAL | readl(pp->va_app_base + CMD_STATUS),
+		pp->va_app_base + CMD_STATUS);
+}
+
+/**
+ * dw_old_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void dw_old_set_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (!(val & DBI_CS2_EN_VAL));
+}
+
+/**
+ * dw_old_clear_dbi_mode() - Disable DBI mode
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void dw_old_clear_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (val & DBI_CS2_EN_VAL);
+}
+
+void dw_old_disable_bars(struct pcie_port *pp)
+{
+	dw_old_set_dbi_mode(pp->va_app_base);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
+	dw_old_clear_dbi_mode(pp->va_app_base);
+}
+
+/**
+ * dw_old_setup_config_addr() - Set up configuration space address for a
+ * device
+ *
+ * @pp: ptr to pcie_port structure
+ * @bus: Bus number the device is residing on
+ * @device: Device number
+ * @function: Function number in device
+ *
+ * Forms and returns the address of configuration space mapped in PCIESS
+ * address space 0. Also configures CFG_SETUP for remote configuration space
+ * access.
+ *
+ * The address space has two regions to access configuration - local and remote.
+ * We access local region for bus 0 (as RC is attached on bus 0) and remote
+ * region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
+ * CFG_SETUP is needed only for remote configuration access.
+ */
+static inline void __iomem *
+dw_old_setup_config_addr(struct pcie_port *pp, u8 bus, u8 device, u8 function)
+{
+	u32 regval;
+
+	if (bus == 0)
+		return pp->dbi_base;
+
+	regval = (bus << 16) | (device << 8) | function;
+	/*
+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
+	 * access only.
+	 * TYPE 1
+	 */
+	if (bus != 1)
+		regval |= BIT(24);
+
+	writel(regval, pp->va_app_base + CFG_SETUP);
+
+	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
+}
+
+int dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+	int ret;
+
+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
+				 PCI_FUNC(devfn));
+
+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+
+	return ret;
+}
+
+int dw_old_wr_other_conf(struct pcie_port *pp,
+		struct pci_bus *bus, unsigned int devfn, int where,
+		int size, u32 val)
+{
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+
+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
+				PCI_FUNC(devfn));
+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+}
+
+/**
+ * dw_old_set_ib_access() - Setup inbound access
+ *
+ * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
+ * access to PCIESS application register space and just needs to set up
+ * inbound address (mainly used for MSI).
+ */
+static void dw_old_set_ib_access(struct pcie_port *pp)
+{
+	/* Configure and set up BAR0 */
+	dw_old_set_dbi_mode(pp->va_app_base);
+
+	/* Enable BAR0 */
+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+
+	dw_old_clear_dbi_mode(pp->va_app_base);
+	 /*
+	  * For BAR0, just setting bus address for inbound writes (MSI) should
+	  * be sufficient. Use physical address to avoid any conflicts.
+	  */
+	writel(pp->app_base, pp->dbi_base + PCI_BASE_ADDRESS_0);
+}
+
+/**
+ * dw_old_pcie_scan_bus() - common function to scan bus
+ *
+ * common functin to scan old dw based pci bus. This also sets inbound access
+ * after scan.
+ */
+static struct pci_bus *dw_old_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	struct pcie_port *pp = sys_to_pcie(sys);
+	struct pci_bus *bus;
+
+	bus = dw_pcie_scan_bus(nr, sys);
+	if (bus)
+		dw_old_set_ib_access(pp);
+
+	return bus;
+}
+
+/**
+ * dw_old_pcie_link_up() - Check if link up
+ *
+ * optionally enable link train using link_train option and check if link is up.
+ */
+int dw_old_pcie_link_up(struct pcie_port *pp, int link_train)
+{
+	u32 val;
+
+	if (link_train) {
+		/*
+		 * KeyStone devices do not support h/w autonomous
+		 * link up-training to GEN2 from GEN1 in either EP/RC modes.
+		 * The software needs to initiate speed change.
+		 */
+		val = readl(pp->dbi_base + PL_GEN2);
+		writel(val | DIR_SPD, pp->dbi_base + PL_GEN2);
+		/*
+		 * Initiate Link Training. We will delay for L0 as specified by
+		 * standard, but will still proceed and return success
+		 * irrespective of L0 status as this will be handled by explicit
+		 * L0 state checks during enumeration.
+		 */
+		val = readl(pp->va_app_base + CMD_STATUS);
+		writel(LTSSM_EN_VAL | val,  pp->va_app_base + CMD_STATUS);
+
+	}
+
+	val = readl(pp->dbi_base + DEBUG0);
+
+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
+}
+
+static struct hw_pci dw_old_pcie_hw = {
+	.nr_controllers	= 1,
+	.setup		= dw_pcie_setup,
+	.scan		= dw_old_pcie_scan_bus,
+	.swizzle        = pci_common_swizzle,
+	.add_bus	= dw_pcie_add_bus,
+	.map_irq	= of_irq_parse_and_map_pci,
+};
+
+
+/**
+ * dw_old_pcie_host_init() - initialize host for old dw hardware
+ *
+ * Parse the pcie resources from DT bindings and then call common
+ * dw function to do host initialization.
+ */
+int __init dw_old_pcie_host_init(struct pcie_port *pp, struct device_node *np)
+{
+	int ret;
+
+	if (!pp->va_app_base)
+		return -EINVAL;
+
+	/* create legacy domain */
+	pp->legacy_irq_domain = irq_domain_add_linear(np,
+				MAX_LEGACY_IRQS,
+				&dw_old_legacy_irq_domian_ops, NULL);
+
+	if (!pp->legacy_irq_domain) {
+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
+		return -EINVAL;
+	}
+
+	ret = dw_pcie_parse_resource(pp);
+	if (ret)
+		return ret;
+
+	return dw_pcie_common_host_init(pp, &dw_old_pcie_hw,
+					&dw_old_msi_domain_ops);
+}
diff --git a/drivers/pci/host/pci-dw-old.h b/drivers/pci/host/pci-dw-old.h
new file mode 100644
index 0000000..6e1af50
--- /dev/null
+++ b/drivers/pci/host/pci-dw-old.h
@@ -0,0 +1,30 @@
+/*
+ * Designware(dw) old MSI controller (v3.65 or similar) common includes
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define MAX_LEGACY_IRQS		4
+
+extern const struct irq_domain_ops dw_old_msi_domain_ops;
+
+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset);
+u32 dw_old_get_msi_data(struct pcie_port *pp);
+void dw_old_enable_legacy_irqs(struct pcie_port *pp);
+void dw_old_handle_legacy_irq(struct pcie_port *pp, int offset);
+int  dw_old_pcie_host_init(struct pcie_port *pp, struct device_node *np);
+int dw_old_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 val);
+int dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val);
+void dw_old_disable_bars(struct pcie_port *pp);
+void dw_old_setup_ob_regs(struct pcie_port *pp);
+int dw_old_pcie_link_up(struct pcie_port *pp, int link_train);
-- 
1.7.9.5


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

* [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
@ 2014-05-15 16:01   ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

The older version of DW hw has application space registers for MSI
controller and inbound/outbound access configuration. Also the legacy
interrupt has registers in the application space. Drivers such as
keystone pci uses these common functions to implement the driver.
These are re-factored from the original driver to separate files
to allow re-use for the next driver that is based on old dw pci hw such
as that found on keystone.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 drivers/pci/host/Kconfig          |    6 +-
 drivers/pci/host/Makefile         |    1 +
 drivers/pci/host/pci-dw-old-msi.c |  150 +++++++++++++++
 drivers/pci/host/pci-dw-old.c     |  371 +++++++++++++++++++++++++++++++++++++
 drivers/pci/host/pci-dw-old.h     |   30 +++
 5 files changed, 557 insertions(+), 1 deletion(-)
 create mode 100644 drivers/pci/host/pci-dw-old-msi.c
 create mode 100644 drivers/pci/host/pci-dw-old.c
 create mode 100644 drivers/pci/host/pci-dw-old.h

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index a6f67ec..c4f4732 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -9,6 +9,11 @@ config PCI_MVEBU
 config PCIE_DW
 	bool
 
+config PCI_DW_OLD
+	bool "Designware Old PCIe h/w"
+	help
+	   Say Y here if the DW h/w is old version (3.65)
+
 config PCI_EXYNOS
 	bool "Samsung Exynos PCIe controller"
 	depends on SOC_EXYNOS5440
@@ -32,5 +37,4 @@ config PCI_RCAR_GEN2
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
-
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..be5d939 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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
diff --git a/drivers/pci/host/pci-dw-old-msi.c b/drivers/pci/host/pci-dw-old-msi.c
new file mode 100644
index 0000000..450bb2f
--- /dev/null
+++ b/drivers/pci/host/pci-dw-old-msi.c
@@ -0,0 +1,150 @@
+/*
+ * Designware(dw) old MSI controller (v3.65 or similar)
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of_irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+
+#include "pcie-designware.h"
+#include "pci-dw-old.h"
+
+#define MSI_IRQ				0x054
+#define MSI0_IRQ_STATUS			0x104
+#define MSI0_IRQ_ENABLE_SET		0x108
+#define MSI0_IRQ_ENABLE_CLR		0x10c
+#define IRQ_STATUS			0x184
+#define IRQ_EOI                         0x050
+#define MSI_IRQ_OFFSET			4
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
+					u32 *bit_pos)
+{
+	*reg_offset = offset % 8;
+	*bit_pos = offset >> 3;
+}
+
+inline u32 dw_old_get_msi_data(struct pcie_port *pp)
+{
+	return pp->app_base + MSI_IRQ;
+}
+
+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset)
+{
+	u32 pending, vector;
+	int src, virq;
+
+	pending = readl(pp->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
+	/*
+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+	 * shows 1, 9, 17, 25 and so forth
+	 */
+	for (src = 0; src < 4; src++) {
+		if (BIT(src) & pending) {
+			vector = offset + (src << 3);
+			virq = irq_linear_revmap(pp->irq_domain, vector);
+			dev_dbg(pp->dev,
+				"irq: bit %d, vector %d, virq %d\n",
+				 src, vector, virq);
+			generic_handle_irq(virq);
+		}
+	}
+}
+
+static void dw_old_msi_irq_ack(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	writel(BIT(bit_pos),
+		pp->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
+	writel(reg_offset + MSI_IRQ_OFFSET, pp->va_app_base + IRQ_EOI);
+}
+
+static void dw_old_msi_irq_mask(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			mask_msi_irq(d);
+	}
+
+	writel(BIT(bit_pos),
+		pp->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
+}
+
+static void dw_old_msi_irq_unmask(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			unmask_msi_irq(d);
+	}
+
+	writel(BIT(bit_pos),
+		pp->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
+}
+
+static struct irq_chip dw_old_msi_chip = {
+	.name = "PCI-DW-MSI-OLD",
+	.irq_ack = dw_old_msi_irq_ack,
+	.irq_mask = dw_old_msi_irq_mask,
+	.irq_unmask = dw_old_msi_irq_unmask,
+};
+
+static int dw_old_msi_map(struct irq_domain *domain, unsigned int irq,
+			irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &dw_old_msi_chip, handle_level_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+const struct irq_domain_ops dw_old_msi_domain_ops = {
+	.map = dw_old_msi_map,
+};
diff --git a/drivers/pci/host/pci-dw-old.c b/drivers/pci/host/pci-dw-old.c
new file mode 100644
index 0000000..b805013
--- /dev/null
+++ b/drivers/pci/host/pci-dw-old.c
@@ -0,0 +1,371 @@
+/*
+ * Designware(dw) old common functions (v3.65 or similar)
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+
+#include "pcie-designware.h"
+#include "pci-dw-old.h"
+
+/* Application register defines */
+#define LTSSM_EN_VAL		        BIT(0)
+#define LTSSM_STATE_MASK	        0x1f
+#define LTSSM_STATE_L0		        0x11
+#define DIR_SPD				(1 << 17)
+#define DBI_CS2_EN_VAL		        BIT(5)
+#define OB_XLAT_EN_VAL		        BIT(1)
+
+/* Application registers */
+#define CMD_STATUS			0x004
+#define CFG_SETUP			0x008
+#define OB_SIZE				0x030
+#define CFG_PCIM_WIN_SZ_IDX	        3
+#define CFG_PCIM_WIN_CNT	        32
+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
+#define IRQ_EOI                         0x050
+#define IRQ_STATUS			0x184
+#define IRQ_ENABLE_SET			0x188
+#define IRQ_ENABLE_CLR			0x18c
+
+/* Config space registers */
+#define DEBUG0			        0x728
+#define PL_GEN2			        0x80c
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+void dw_old_enable_legacy_irqs(struct pcie_port *pp)
+{
+	int i;
+
+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
+		writel(0x1, pp->va_app_base + IRQ_ENABLE_SET + (i << 4));
+}
+
+void dw_old_handle_legacy_irq(struct pcie_port *pp, int offset)
+{
+	u32 pending;
+	int virq;
+
+	pending = readl(pp->va_app_base + IRQ_STATUS + (offset << 4));
+
+	if (BIT(0) & pending) {
+		virq = irq_linear_revmap(pp->legacy_irq_domain, offset);
+		dev_dbg(pp->dev,
+			": irq: irq_offset %d, virq %d\n", offset, virq);
+		generic_handle_irq(virq);
+	}
+
+	/* EOI the INTx interrupt */
+	writel(offset, pp->va_app_base + IRQ_EOI);
+}
+
+static void dw_old_ack_irq(struct irq_data *d)
+{
+}
+
+static void dw_old_mask_irq(struct irq_data *d)
+{
+}
+
+static void dw_old_unmask_irq(struct irq_data *d)
+{
+}
+
+struct irq_chip dw_old_legacy_irq_chip = {
+	.name = "PCI-DW-LEGACY-old-irq",
+	.irq_ack = dw_old_ack_irq,
+	.irq_mask = dw_old_mask_irq,
+	.irq_unmask = dw_old_unmask_irq,
+};
+
+static int dw_old_init_legacy_irq_map(struct irq_domain *d, unsigned int irq,
+				      irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(irq, &dw_old_legacy_irq_chip,
+				handle_level_irq);
+	irq_set_chip_data(irq, d->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static const struct irq_domain_ops dw_old_legacy_irq_domian_ops = {
+	.map = dw_old_init_legacy_irq_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+/**
+ * dw_old_set_outbound_trans() - Set PHYADDR <-> BUSADDR
+ * mapping for outbound
+ */
+void dw_old_setup_ob_regs(struct pcie_port *pp)
+{
+	u32 start = pp->mem.start, end = pp->mem.end;
+	int i, tr_size;
+
+	dev_dbg(pp->dev, "Setting outbound translation for %#x-%#x\n",
+		start, end);
+
+	/* Set outbound translation size per window division */
+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, pp->va_app_base + OB_SIZE);
+
+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
+
+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
+		writel(start | 1, pp->va_app_base + OB_OFFSET_INDEX(i));
+		writel(0, pp->va_app_base + OB_OFFSET_HI(i));
+		start += tr_size;
+	}
+
+	/* Enable OB translation */
+	writel(OB_XLAT_EN_VAL | readl(pp->va_app_base + CMD_STATUS),
+		pp->va_app_base + CMD_STATUS);
+}
+
+/**
+ * dw_old_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void dw_old_set_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (!(val & DBI_CS2_EN_VAL));
+}
+
+/**
+ * dw_old_clear_dbi_mode() - Disable DBI mode
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void dw_old_clear_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (val & DBI_CS2_EN_VAL);
+}
+
+void dw_old_disable_bars(struct pcie_port *pp)
+{
+	dw_old_set_dbi_mode(pp->va_app_base);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
+	dw_old_clear_dbi_mode(pp->va_app_base);
+}
+
+/**
+ * dw_old_setup_config_addr() - Set up configuration space address for a
+ * device
+ *
+ * @pp: ptr to pcie_port structure
+ * @bus: Bus number the device is residing on
+ * @device: Device number
+ * @function: Function number in device
+ *
+ * Forms and returns the address of configuration space mapped in PCIESS
+ * address space 0. Also configures CFG_SETUP for remote configuration space
+ * access.
+ *
+ * The address space has two regions to access configuration - local and remote.
+ * We access local region for bus 0 (as RC is attached on bus 0) and remote
+ * region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
+ * CFG_SETUP is needed only for remote configuration access.
+ */
+static inline void __iomem *
+dw_old_setup_config_addr(struct pcie_port *pp, u8 bus, u8 device, u8 function)
+{
+	u32 regval;
+
+	if (bus == 0)
+		return pp->dbi_base;
+
+	regval = (bus << 16) | (device << 8) | function;
+	/*
+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
+	 * access only.
+	 * TYPE 1
+	 */
+	if (bus != 1)
+		regval |= BIT(24);
+
+	writel(regval, pp->va_app_base + CFG_SETUP);
+
+	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
+}
+
+int dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+	int ret;
+
+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
+				 PCI_FUNC(devfn));
+
+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+
+	return ret;
+}
+
+int dw_old_wr_other_conf(struct pcie_port *pp,
+		struct pci_bus *bus, unsigned int devfn, int where,
+		int size, u32 val)
+{
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+
+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
+				PCI_FUNC(devfn));
+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+}
+
+/**
+ * dw_old_set_ib_access() - Setup inbound access
+ *
+ * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
+ * access to PCIESS application register space and just needs to set up
+ * inbound address (mainly used for MSI).
+ */
+static void dw_old_set_ib_access(struct pcie_port *pp)
+{
+	/* Configure and set up BAR0 */
+	dw_old_set_dbi_mode(pp->va_app_base);
+
+	/* Enable BAR0 */
+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+
+	dw_old_clear_dbi_mode(pp->va_app_base);
+	 /*
+	  * For BAR0, just setting bus address for inbound writes (MSI) should
+	  * be sufficient. Use physical address to avoid any conflicts.
+	  */
+	writel(pp->app_base, pp->dbi_base + PCI_BASE_ADDRESS_0);
+}
+
+/**
+ * dw_old_pcie_scan_bus() - common function to scan bus
+ *
+ * common functin to scan old dw based pci bus. This also sets inbound access
+ * after scan.
+ */
+static struct pci_bus *dw_old_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	struct pcie_port *pp = sys_to_pcie(sys);
+	struct pci_bus *bus;
+
+	bus = dw_pcie_scan_bus(nr, sys);
+	if (bus)
+		dw_old_set_ib_access(pp);
+
+	return bus;
+}
+
+/**
+ * dw_old_pcie_link_up() - Check if link up
+ *
+ * optionally enable link train using link_train option and check if link is up.
+ */
+int dw_old_pcie_link_up(struct pcie_port *pp, int link_train)
+{
+	u32 val;
+
+	if (link_train) {
+		/*
+		 * KeyStone devices do not support h/w autonomous
+		 * link up-training to GEN2 from GEN1 in either EP/RC modes.
+		 * The software needs to initiate speed change.
+		 */
+		val = readl(pp->dbi_base + PL_GEN2);
+		writel(val | DIR_SPD, pp->dbi_base + PL_GEN2);
+		/*
+		 * Initiate Link Training. We will delay for L0 as specified by
+		 * standard, but will still proceed and return success
+		 * irrespective of L0 status as this will be handled by explicit
+		 * L0 state checks during enumeration.
+		 */
+		val = readl(pp->va_app_base + CMD_STATUS);
+		writel(LTSSM_EN_VAL | val,  pp->va_app_base + CMD_STATUS);
+
+	}
+
+	val = readl(pp->dbi_base + DEBUG0);
+
+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
+}
+
+static struct hw_pci dw_old_pcie_hw = {
+	.nr_controllers	= 1,
+	.setup		= dw_pcie_setup,
+	.scan		= dw_old_pcie_scan_bus,
+	.swizzle        = pci_common_swizzle,
+	.add_bus	= dw_pcie_add_bus,
+	.map_irq	= of_irq_parse_and_map_pci,
+};
+
+
+/**
+ * dw_old_pcie_host_init() - initialize host for old dw hardware
+ *
+ * Parse the pcie resources from DT bindings and then call common
+ * dw function to do host initialization.
+ */
+int __init dw_old_pcie_host_init(struct pcie_port *pp, struct device_node *np)
+{
+	int ret;
+
+	if (!pp->va_app_base)
+		return -EINVAL;
+
+	/* create legacy domain */
+	pp->legacy_irq_domain = irq_domain_add_linear(np,
+				MAX_LEGACY_IRQS,
+				&dw_old_legacy_irq_domian_ops, NULL);
+
+	if (!pp->legacy_irq_domain) {
+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
+		return -EINVAL;
+	}
+
+	ret = dw_pcie_parse_resource(pp);
+	if (ret)
+		return ret;
+
+	return dw_pcie_common_host_init(pp, &dw_old_pcie_hw,
+					&dw_old_msi_domain_ops);
+}
diff --git a/drivers/pci/host/pci-dw-old.h b/drivers/pci/host/pci-dw-old.h
new file mode 100644
index 0000000..6e1af50
--- /dev/null
+++ b/drivers/pci/host/pci-dw-old.h
@@ -0,0 +1,30 @@
+/*
+ * Designware(dw) old MSI controller (v3.65 or similar) common includes
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define MAX_LEGACY_IRQS		4
+
+extern const struct irq_domain_ops dw_old_msi_domain_ops;
+
+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset);
+u32 dw_old_get_msi_data(struct pcie_port *pp);
+void dw_old_enable_legacy_irqs(struct pcie_port *pp);
+void dw_old_handle_legacy_irq(struct pcie_port *pp, int offset);
+int  dw_old_pcie_host_init(struct pcie_port *pp, struct device_node *np);
+int dw_old_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 val);
+int dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val);
+void dw_old_disable_bars(struct pcie_port *pp);
+void dw_old_setup_ob_regs(struct pcie_port *pp);
+int dw_old_pcie_link_up(struct pcie_port *pp, int link_train);
-- 
1.7.9.5

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 16:01 ` Murali Karicheri
@ 2014-05-15 16:01   ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-kernel, linux-pci, linux-arm-kernel
  Cc: Murali Karicheri, Santosh Shilimkar, Mohit Kumar, Jingoo Han,
	Bjorn Helgaas, Grygorii Strashko

keystone pcie hardware is based on designware version 3.65.
This driver make use of the functions from pci-dw-old.c and
pci-dw-old-msi.c to implement the driver.

Driver mainly handle the platform specific part of the PCI
driver and depends on DW Old driver to configure application
specific registers. Also routes the irq events and ack the
interrupt after the same is acked by the end point device
driver. This requires irqchip implementation for legacy and MSI
irq handling. This patch adds a quirks to override the max read
request size as PCI controller has a limit of 256 bytes.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
 drivers/pci/host/Kconfig                           |    8 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
 drivers/pci/quirks.c                               |   13 +
 5 files changed, 490 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone.c

diff --git a/Documentation/devicetree/bindings/pci/pcie-keystone.txt b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
new file mode 100644
index 0000000..17cf261
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
@@ -0,0 +1,68 @@
+Keystone PCIE Root complex device tree bindings
+-----------------------------------------------
+
+Sample bindings shown below:-
+
+ - Remove ti,enable-linktrain if boot loader already does Link training and do EP
+   configuration.
+ - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
+   link
+
+		pcie0_phy: pciephy@2320000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#phy-cells = <0>;
+			compatible = "ti,keystone-phy";
+			reg = <0x02320000 0x4000>;
+			reg-names = "reg_serdes";
+		};
+
+		pcie@21800000 {
+			compatible = "ti,keystone-pcie";
+			device_type = "pci";
+			clocks = <&clkpcie>;
+			clock-names = "pcie";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			reg =  <0x21800000 0x1000>, <0x0262014c 4>;
+			reg-names = "reg_rc_app", "reg_devcfg";
+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
+
+			ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
+				  0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
+				  0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
+
+			num-lanes = <2>;
+			ti,enable-linktrain;
+			ti,init-phy;
+
+			/* PCIE phy */
+			phys = <&pcie0_phy>;
+			phy-names = "pcie-phy";
+
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
+					<0 0 0 2 &pcie_intc 2>, // INT B
+					<0 0 0 3 &pcie_intc 3>, // INT C
+					<0 0 0 4 &pcie_intc 4>; // INT D
+
+			pcie_intc: legacy-interrupt-controller {
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				interrupt-parent = <&gic>;
+				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+			};
+		};
+
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index c4f4732..066d611 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -37,4 +37,12 @@ config PCI_RCAR_GEN2
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
+
+config PCI_KEYSTONE
+	bool "TI Keystone PCIe controller"
+	depends on ARCH_KEYSTONE
+	select PCIE_DW
+	select PCI_DW_OLD
+	select PCIEPORTBUS
+	select PHY_TI_KEYSTONE
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index be5d939..10e02f9 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -5,3 +5,4 @@ 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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
new file mode 100644
index 0000000..2636717
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.c
@@ -0,0 +1,400 @@
+/*
+ * PCIe host controller driver for Texas Instruments Keystone SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ * Implementation based on pci-exynos.c and pcie-designware.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irqchip/chained_irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+
+#include "pcie-designware.h"
+#include "pci-dw-old.h"
+
+#define DRIVER_NAME	"keystone-pcie"
+
+/* driver specific constants */
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+/* RC mode settings */
+#define PCIE_RC_MODE		(BIT(2))
+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+struct keystone_pcie {
+	struct	clk		*clk;
+	int			en_link_train;
+	struct	pcie_port	pp;
+
+	int			num_legacy_host_irqs;
+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
+	struct			device_node *np_intc;
+
+	int			num_msi_host_irqs;
+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
+};
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int count = 200;
+
+	dw_pcie_setup_rc(pp);
+
+	/* check if the link is up or not */
+	while (!dw_pcie_link_up(pp)) {
+		usleep_range(100, 1000);
+		if (--count)
+			continue;
+		dev_err(pp->dev, "phy link never came up\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, "ks_pcie_msi_irq_handler, irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	dw_old_handle_msi_irq(pp, offset);
+	chained_irq_exit(chip, desc);
+}
+
+/**
+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
+ * @irq: IRQ line for legacy interrupts
+ * @desc: Pointer to irq descriptor
+ *
+ * Traverse through pending legacy interrupts and invoke handler for each. Also
+ * takes care of interrupt controller level mask/ack operation.
+ */
+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct pcie_port *pp = &ks_pcie->pp;
+
+	dev_dbg(ks_pcie->pp.dev, ": Handling legacy irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	dw_old_handle_legacy_irq(pp, irq_offset);
+	chained_irq_exit(chip, desc);
+}
+
+static int ks_pcie_init_legacy_irqs(struct keystone_pcie *ks_pcie)
+{
+	struct device *dev = ks_pcie->pp.dev;
+	struct device_node *np_pcie = dev->of_node;
+	int num_legacy_irqs;
+	int ret = 0;
+	int i;
+
+	/* get node */
+	ks_pcie->np_intc = of_find_node_by_name(np_pcie,
+						"legacy-interrupt-controller");
+	if (!ks_pcie->np_intc) {
+		dev_err(dev,
+			"Node for legacy-interrupt-controller is absent\n");
+		goto out;
+	}
+
+	/* get number of IRQs */
+	num_legacy_irqs = of_irq_count(ks_pcie->np_intc);
+	if (!num_legacy_irqs)
+		goto out;
+
+	if (num_legacy_irqs > MAX_LEGACY_HOST_IRQS) {
+		dev_err(dev, "Too many legacy interrupts defined %u\n",
+			num_legacy_irqs);
+		num_legacy_irqs = MAX_LEGACY_HOST_IRQS;
+	}
+	/*
+	 * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
+	 * In dt from index 0 to 3
+	 */
+	for (i = 0; i < num_legacy_irqs; i++) {
+		ks_pcie->legacy_host_irqs[i] =
+			irq_of_parse_and_map(ks_pcie->np_intc, i);
+		if (ks_pcie->legacy_host_irqs[i] < 0)
+			break;
+		ks_pcie->num_legacy_host_irqs++;
+	}
+
+	if (!ks_pcie->num_legacy_host_irqs) {
+		dev_err(dev, "Failed to get legacy interrupts\n");
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static void ks_pcie_enable_interrupts(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int i;
+
+	/* Legacy IRQ */
+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
+					ks_pcie_legacy_irq_handler);
+	}
+	dw_old_enable_legacy_irqs(pp);
+
+	/* MSI IRQ */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
+				ks_pcie_msi_irq_handler);
+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
+						ks_pcie);
+
+		}
+	}
+
+	return;
+}
+
+static int
+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
+		struct pt_regs *regs)
+{
+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+	}
+
+	return 0;
+}
+
+static void __init ks_pcie_host_init(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	ks_pcie_establish_link(ks_pcie);
+	dw_old_disable_bars(pp);
+	dw_old_setup_ob_regs(pp);
+	ks_pcie_enable_interrupts(ks_pcie);
+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
+			pp->dbi_base + PCI_IO_BASE);
+	/*
+	 * PCIe access errors that result into OCP errors are caught by ARM as
+	 * "External aborts" (Precise).
+	 */
+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
+			"external abort on linefetch");
+}
+
+int ks_pcie_link_up(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	return dw_old_pcie_link_up(pp, ks_pcie->en_link_train);
+}
+
+static struct pcie_host_ops keystone_pcie_host_ops = {
+	.rd_other_conf = dw_old_rd_other_conf,
+	.wr_other_conf = dw_old_wr_other_conf,
+	.link_up = ks_pcie_link_up,
+	.host_init = ks_pcie_host_init,
+	.get_msi_data = dw_old_get_msi_data,
+};
+
+static int add_pcie_port(struct keystone_pcie *ks_pcie,
+			 struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct resource *res;
+	int ret, i;
+
+	ret = ks_pcie_init_legacy_irqs(ks_pcie);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		/*
+		 * support upto 32 MSI irqs mapped to 8 host IRQs.
+		 * In dt from index 4 to 11
+		 */
+		for (i = 0; i < MAX_MSI_HOST_IRQS; i++) {
+			ks_pcie->msi_host_irqs[i] = irq_of_parse_and_map(np, i);
+			if (ks_pcie->msi_host_irqs[i] < 0)
+				break;
+			ks_pcie->num_msi_host_irqs++;
+		}
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_rc_app");
+	pp->va_app_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pp->va_app_base))
+		return PTR_ERR(pp->va_app_base);
+	pp->app_base = res->start;
+
+	pp->root_bus_nr = -1;
+	pp->version = DW_VERSION_OLD;
+	pp->ops = &keystone_pcie_host_ops;
+	spin_lock_init(&pp->conf_lock);
+	ret = dw_old_pcie_host_init(pp, ks_pcie->np_intc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id ks_pcie_of_match[] = {
+	{
+		.type = "pci",
+		.compatible = "ti,keystone-pcie",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
+
+static int __exit ks_pcie_remove(struct platform_device *pdev)
+{
+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return 0;
+}
+
+static int __init ks_pcie_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct keystone_pcie *ks_pcie;
+	void __iomem *devstat;
+	struct pcie_port *pp;
+	struct resource *res;
+	struct phy *phy;
+	int ret = 0;
+	u32 val;
+
+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
+				GFP_KERNEL);
+	if (!ks_pcie) {
+		dev_err(dev, "no memory for keystone pcie\n");
+		return -ENOMEM;
+	}
+
+	/* check if serdes phy needs to be enabled */
+	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
+		phy = devm_phy_get(dev, "pcie-phy");
+			if (IS_ERR(phy))
+				return PTR_ERR(phy);
+
+		ret = phy_init(phy);
+		if (ret < 0)
+			return ret;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   "reg_devcfg");
+	devstat = devm_ioremap_resource(dev, res);
+	if (IS_ERR(devstat))
+		return PTR_ERR(devstat);
+
+	/* enable RC mode in devcfg */
+	val = readl(devstat);
+	val &= ~PCIE_MODE_MASK;
+	val |= PCIE_RC_MODE;
+	writel(val, devstat);
+
+	/* check if we need to enable link training */
+	ks_pcie->en_link_train =
+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
+
+	pp = &ks_pcie->pp;
+	pp->dev = dev;
+
+	ks_pcie->clk = devm_clk_get(dev, "pcie");
+	if (IS_ERR(ks_pcie->clk)) {
+		dev_err(dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(ks_pcie->clk);
+	}
+	ret = clk_prepare_enable(ks_pcie->clk);
+	if (ret)
+		return ret;
+
+	ret = add_pcie_port(ks_pcie, pdev);
+	if (ret < 0)
+		goto fail_clk;
+
+	platform_set_drvdata(pdev, ks_pcie);
+	dev_info(dev, "pcie rc probe success\n");
+
+	return 0;
+
+fail_clk:
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return ret;
+}
+
+static struct platform_driver ks_pcie_driver __refdata = {
+	.probe  = ks_pcie_probe,
+	.remove = __exit_p(ks_pcie_remove),
+	.driver = {
+		.name	= "keystone-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ks_pcie_of_match),
+	},
+};
+
+module_platform_driver(ks_pcie_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e729206..b3e12c2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3651,3 +3651,16 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
 		}
 	}
 }
+#ifdef CONFIG_PCI_KEYSTONE
+/*
+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
+ */
+static void quirk_limit_readrequest(struct pci_dev *dev)
+{
+	int readrq = pcie_get_readrq(dev);
+
+	if (readrq > 256)
+		pcie_set_readrq(dev, 256);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
+#endif /* CONFIG_PCI_KEYSTONE */
-- 
1.7.9.5


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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 16:01   ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

keystone pcie hardware is based on designware version 3.65.
This driver make use of the functions from pci-dw-old.c and
pci-dw-old-msi.c to implement the driver.

Driver mainly handle the platform specific part of the PCI
driver and depends on DW Old driver to configure application
specific registers. Also routes the irq events and ack the
interrupt after the same is acked by the end point device
driver. This requires irqchip implementation for legacy and MSI
irq handling. This patch adds a quirks to override the max read
request size as PCI controller has a limit of 256 bytes.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
 drivers/pci/host/Kconfig                           |    8 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
 drivers/pci/quirks.c                               |   13 +
 5 files changed, 490 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone.c

diff --git a/Documentation/devicetree/bindings/pci/pcie-keystone.txt b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
new file mode 100644
index 0000000..17cf261
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
@@ -0,0 +1,68 @@
+Keystone PCIE Root complex device tree bindings
+-----------------------------------------------
+
+Sample bindings shown below:-
+
+ - Remove ti,enable-linktrain if boot loader already does Link training and do EP
+   configuration.
+ - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
+   link
+
+		pcie0_phy: pciephy at 2320000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#phy-cells = <0>;
+			compatible = "ti,keystone-phy";
+			reg = <0x02320000 0x4000>;
+			reg-names = "reg_serdes";
+		};
+
+		pcie at 21800000 {
+			compatible = "ti,keystone-pcie";
+			device_type = "pci";
+			clocks = <&clkpcie>;
+			clock-names = "pcie";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			reg =  <0x21800000 0x1000>, <0x0262014c 4>;
+			reg-names = "reg_rc_app", "reg_devcfg";
+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
+
+			ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
+				  0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
+				  0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
+
+			num-lanes = <2>;
+			ti,enable-linktrain;
+			ti,init-phy;
+
+			/* PCIE phy */
+			phys = <&pcie0_phy>;
+			phy-names = "pcie-phy";
+
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
+					<0 0 0 2 &pcie_intc 2>, // INT B
+					<0 0 0 3 &pcie_intc 3>, // INT C
+					<0 0 0 4 &pcie_intc 4>; // INT D
+
+			pcie_intc: legacy-interrupt-controller {
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				interrupt-parent = <&gic>;
+				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+			};
+		};
+
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index c4f4732..066d611 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -37,4 +37,12 @@ config PCI_RCAR_GEN2
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
+
+config PCI_KEYSTONE
+	bool "TI Keystone PCIe controller"
+	depends on ARCH_KEYSTONE
+	select PCIE_DW
+	select PCI_DW_OLD
+	select PCIEPORTBUS
+	select PHY_TI_KEYSTONE
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index be5d939..10e02f9 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -5,3 +5,4 @@ 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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
new file mode 100644
index 0000000..2636717
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.c
@@ -0,0 +1,400 @@
+/*
+ * PCIe host controller driver for Texas Instruments Keystone SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ * Implementation based on pci-exynos.c and pcie-designware.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irqchip/chained_irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+
+#include "pcie-designware.h"
+#include "pci-dw-old.h"
+
+#define DRIVER_NAME	"keystone-pcie"
+
+/* driver specific constants */
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+/* RC mode settings */
+#define PCIE_RC_MODE		(BIT(2))
+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+struct keystone_pcie {
+	struct	clk		*clk;
+	int			en_link_train;
+	struct	pcie_port	pp;
+
+	int			num_legacy_host_irqs;
+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
+	struct			device_node *np_intc;
+
+	int			num_msi_host_irqs;
+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
+};
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int count = 200;
+
+	dw_pcie_setup_rc(pp);
+
+	/* check if the link is up or not */
+	while (!dw_pcie_link_up(pp)) {
+		usleep_range(100, 1000);
+		if (--count)
+			continue;
+		dev_err(pp->dev, "phy link never came up\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, "ks_pcie_msi_irq_handler, irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	dw_old_handle_msi_irq(pp, offset);
+	chained_irq_exit(chip, desc);
+}
+
+/**
+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
+ * @irq: IRQ line for legacy interrupts
+ * @desc: Pointer to irq descriptor
+ *
+ * Traverse through pending legacy interrupts and invoke handler for each. Also
+ * takes care of interrupt controller level mask/ack operation.
+ */
+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct pcie_port *pp = &ks_pcie->pp;
+
+	dev_dbg(ks_pcie->pp.dev, ": Handling legacy irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	dw_old_handle_legacy_irq(pp, irq_offset);
+	chained_irq_exit(chip, desc);
+}
+
+static int ks_pcie_init_legacy_irqs(struct keystone_pcie *ks_pcie)
+{
+	struct device *dev = ks_pcie->pp.dev;
+	struct device_node *np_pcie = dev->of_node;
+	int num_legacy_irqs;
+	int ret = 0;
+	int i;
+
+	/* get node */
+	ks_pcie->np_intc = of_find_node_by_name(np_pcie,
+						"legacy-interrupt-controller");
+	if (!ks_pcie->np_intc) {
+		dev_err(dev,
+			"Node for legacy-interrupt-controller is absent\n");
+		goto out;
+	}
+
+	/* get number of IRQs */
+	num_legacy_irqs = of_irq_count(ks_pcie->np_intc);
+	if (!num_legacy_irqs)
+		goto out;
+
+	if (num_legacy_irqs > MAX_LEGACY_HOST_IRQS) {
+		dev_err(dev, "Too many legacy interrupts defined %u\n",
+			num_legacy_irqs);
+		num_legacy_irqs = MAX_LEGACY_HOST_IRQS;
+	}
+	/*
+	 * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
+	 * In dt from index 0 to 3
+	 */
+	for (i = 0; i < num_legacy_irqs; i++) {
+		ks_pcie->legacy_host_irqs[i] =
+			irq_of_parse_and_map(ks_pcie->np_intc, i);
+		if (ks_pcie->legacy_host_irqs[i] < 0)
+			break;
+		ks_pcie->num_legacy_host_irqs++;
+	}
+
+	if (!ks_pcie->num_legacy_host_irqs) {
+		dev_err(dev, "Failed to get legacy interrupts\n");
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static void ks_pcie_enable_interrupts(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int i;
+
+	/* Legacy IRQ */
+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
+					ks_pcie_legacy_irq_handler);
+	}
+	dw_old_enable_legacy_irqs(pp);
+
+	/* MSI IRQ */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
+				ks_pcie_msi_irq_handler);
+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
+						ks_pcie);
+
+		}
+	}
+
+	return;
+}
+
+static int
+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
+		struct pt_regs *regs)
+{
+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+	}
+
+	return 0;
+}
+
+static void __init ks_pcie_host_init(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	ks_pcie_establish_link(ks_pcie);
+	dw_old_disable_bars(pp);
+	dw_old_setup_ob_regs(pp);
+	ks_pcie_enable_interrupts(ks_pcie);
+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
+			pp->dbi_base + PCI_IO_BASE);
+	/*
+	 * PCIe access errors that result into OCP errors are caught by ARM as
+	 * "External aborts" (Precise).
+	 */
+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
+			"external abort on linefetch");
+}
+
+int ks_pcie_link_up(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	return dw_old_pcie_link_up(pp, ks_pcie->en_link_train);
+}
+
+static struct pcie_host_ops keystone_pcie_host_ops = {
+	.rd_other_conf = dw_old_rd_other_conf,
+	.wr_other_conf = dw_old_wr_other_conf,
+	.link_up = ks_pcie_link_up,
+	.host_init = ks_pcie_host_init,
+	.get_msi_data = dw_old_get_msi_data,
+};
+
+static int add_pcie_port(struct keystone_pcie *ks_pcie,
+			 struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct resource *res;
+	int ret, i;
+
+	ret = ks_pcie_init_legacy_irqs(ks_pcie);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		/*
+		 * support upto 32 MSI irqs mapped to 8 host IRQs.
+		 * In dt from index 4 to 11
+		 */
+		for (i = 0; i < MAX_MSI_HOST_IRQS; i++) {
+			ks_pcie->msi_host_irqs[i] = irq_of_parse_and_map(np, i);
+			if (ks_pcie->msi_host_irqs[i] < 0)
+				break;
+			ks_pcie->num_msi_host_irqs++;
+		}
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_rc_app");
+	pp->va_app_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pp->va_app_base))
+		return PTR_ERR(pp->va_app_base);
+	pp->app_base = res->start;
+
+	pp->root_bus_nr = -1;
+	pp->version = DW_VERSION_OLD;
+	pp->ops = &keystone_pcie_host_ops;
+	spin_lock_init(&pp->conf_lock);
+	ret = dw_old_pcie_host_init(pp, ks_pcie->np_intc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id ks_pcie_of_match[] = {
+	{
+		.type = "pci",
+		.compatible = "ti,keystone-pcie",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
+
+static int __exit ks_pcie_remove(struct platform_device *pdev)
+{
+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return 0;
+}
+
+static int __init ks_pcie_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct keystone_pcie *ks_pcie;
+	void __iomem *devstat;
+	struct pcie_port *pp;
+	struct resource *res;
+	struct phy *phy;
+	int ret = 0;
+	u32 val;
+
+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
+				GFP_KERNEL);
+	if (!ks_pcie) {
+		dev_err(dev, "no memory for keystone pcie\n");
+		return -ENOMEM;
+	}
+
+	/* check if serdes phy needs to be enabled */
+	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
+		phy = devm_phy_get(dev, "pcie-phy");
+			if (IS_ERR(phy))
+				return PTR_ERR(phy);
+
+		ret = phy_init(phy);
+		if (ret < 0)
+			return ret;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   "reg_devcfg");
+	devstat = devm_ioremap_resource(dev, res);
+	if (IS_ERR(devstat))
+		return PTR_ERR(devstat);
+
+	/* enable RC mode in devcfg */
+	val = readl(devstat);
+	val &= ~PCIE_MODE_MASK;
+	val |= PCIE_RC_MODE;
+	writel(val, devstat);
+
+	/* check if we need to enable link training */
+	ks_pcie->en_link_train =
+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
+
+	pp = &ks_pcie->pp;
+	pp->dev = dev;
+
+	ks_pcie->clk = devm_clk_get(dev, "pcie");
+	if (IS_ERR(ks_pcie->clk)) {
+		dev_err(dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(ks_pcie->clk);
+	}
+	ret = clk_prepare_enable(ks_pcie->clk);
+	if (ret)
+		return ret;
+
+	ret = add_pcie_port(ks_pcie, pdev);
+	if (ret < 0)
+		goto fail_clk;
+
+	platform_set_drvdata(pdev, ks_pcie);
+	dev_info(dev, "pcie rc probe success\n");
+
+	return 0;
+
+fail_clk:
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return ret;
+}
+
+static struct platform_driver ks_pcie_driver __refdata = {
+	.probe  = ks_pcie_probe,
+	.remove = __exit_p(ks_pcie_remove),
+	.driver = {
+		.name	= "keystone-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ks_pcie_of_match),
+	},
+};
+
+module_platform_driver(ks_pcie_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e729206..b3e12c2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3651,3 +3651,16 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
 		}
 	}
 }
+#ifdef CONFIG_PCI_KEYSTONE
+/*
+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
+ */
+static void quirk_limit_readrequest(struct pci_dev *dev)
+{
+	int readrq = pcie_get_readrq(dev);
+
+	if (readrq > 256)
+		pcie_set_readrq(dev, 256);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
+#endif /* CONFIG_PCI_KEYSTONE */
-- 
1.7.9.5

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-05-15 16:01   ` Murali Karicheri
@ 2014-05-15 16:14     ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 16:14 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, linux-kernel, linux-pci, Mohit Kumar,
	Jingoo Han, Rob Herring, Bjorn Helgaas, Grant Likely

On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> +       {0x0000, 0x00000800, 0x0000ff00},
> +       {0x0060, 0x00041c5c, 0x00ffffff},
> +       {0x0064, 0x0343c700, 0xffffff00},
> +       {0x006c, 0x00000012, 0x000000ff},
> +       {0x0068, 0x00070000, 0x00ff0000},
> +       {0x0078, 0x0000c000, 0x0000ff00},

It looks like the PHY is generic, but the configuration above is
PCI specific. If this is true, you should have #phy-cells=<1>
and document the possible modes, adding a lookup table here to
pick the configuration based on the argument. It's fine to just
implement pcie-5ghz initially, but the binding should list all
the modes that the PHY can support.

Also, please list the exact name of the phy if you can find it
out. You mention that you don't know the register descriptions,
but you should at least be able to let us know what phy this
is, in case some other SoC reuses the same thing.

> +static int ks_phy_init(struct phy *phy)
> +{
> +       struct serdes_config *p;
> +       struct phy_keystone *ks_phy = phy_get_drvdata(phy);
> +
> +       int i;
> +
> +       for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
> +               i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
> +               i++, p++) {
> +               reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
> +               reg_dump((ks_phy->base + p->reg), p->mask);
> +       }
> +       udelay(2000);

This should probably be msleep(2);

	Arnd

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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-15 16:14     ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 16:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> +       {0x0000, 0x00000800, 0x0000ff00},
> +       {0x0060, 0x00041c5c, 0x00ffffff},
> +       {0x0064, 0x0343c700, 0xffffff00},
> +       {0x006c, 0x00000012, 0x000000ff},
> +       {0x0068, 0x00070000, 0x00ff0000},
> +       {0x0078, 0x0000c000, 0x0000ff00},

It looks like the PHY is generic, but the configuration above is
PCI specific. If this is true, you should have #phy-cells=<1>
and document the possible modes, adding a lookup table here to
pick the configuration based on the argument. It's fine to just
implement pcie-5ghz initially, but the binding should list all
the modes that the PHY can support.

Also, please list the exact name of the phy if you can find it
out. You mention that you don't know the register descriptions,
but you should at least be able to let us know what phy this
is, in case some other SoC reuses the same thing.

> +static int ks_phy_init(struct phy *phy)
> +{
> +       struct serdes_config *p;
> +       struct phy_keystone *ks_phy = phy_get_drvdata(phy);
> +
> +       int i;
> +
> +       for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
> +               i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
> +               i++, p++) {
> +               reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
> +               reg_dump((ks_phy->base + p->reg), p->mask);
> +       }
> +       udelay(2000);

This should probably be msleep(2);

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 16:01   ` Murali Karicheri
@ 2014-05-15 16:23     ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 16:23 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, linux-kernel, linux-pci, Grygorii Strashko,
	Mohit Kumar, Jingoo Han, Santosh Shilimkar, Bjorn Helgaas

On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:

> +static int
> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
> +		struct pt_regs *regs)
> +{
> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
> +
> +	if ((instr & 0x0e100090) == 0x00100090) {
> +		int reg = (instr >> 12) & 15;
> +
> +		regs->uregs[reg] = -1;
> +		regs->ARM_pc += 4;
> +	}
> +
> +	return 0;
> +}

This needs to check in the PCI host registers what happened and do
some appropriate action. If the fault was not caused by PCIe, it
should not be ignored here but get passed on to the next handler.

> +static int __init ks_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device *dev = &pdev->dev;
> +	struct keystone_pcie *ks_pcie;
> +	void __iomem *devstat;
> +	struct pcie_port *pp;
> +	struct resource *res;
> +	struct phy *phy;
> +	int ret = 0;
> +	u32 val;
> +
> +	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
> +				GFP_KERNEL);
> +	if (!ks_pcie) {
> +		dev_err(dev, "no memory for keystone pcie\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* check if serdes phy needs to be enabled */
> +	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
> +		phy = devm_phy_get(dev, "pcie-phy");
> +			if (IS_ERR(phy))
> +				return PTR_ERR(phy);
> +
> +		ret = phy_init(phy);
> +		if (ret < 0)
> +			return ret;
> +	}

I think you can just call devm_phy_get() unconditionally here and
get rid of the ti,init-phy property. If there is no phy, don't
initialize it.

> +
> +	ret = add_pcie_port(ks_pcie, pdev);
> +	if (ret < 0)
> +		goto fail_clk;
> +
> +	platform_set_drvdata(pdev, ks_pcie);

Set the platform data first, then add the port.

> +	dev_info(dev, "pcie rc probe success\n");

Remove this.

> +#ifdef CONFIG_PCI_KEYSTONE
> +/*
> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> + */
> +static void quirk_limit_readrequest(struct pci_dev *dev)
> +{
> +	int readrq = pcie_get_readrq(dev);
> +
> +	if (readrq > 256)
> +		pcie_set_readrq(dev, 256);
> +}
> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> +#endif /* CONFIG_PCI_KEYSTONE */

This doesn't work: you can't just limit do this for all devices just based
on PCI_KEYSTONE being enabled, you have to check if you are actually using
this controller.

	Arnd

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 16:23     ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 16:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:

> +static int
> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
> +		struct pt_regs *regs)
> +{
> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
> +
> +	if ((instr & 0x0e100090) == 0x00100090) {
> +		int reg = (instr >> 12) & 15;
> +
> +		regs->uregs[reg] = -1;
> +		regs->ARM_pc += 4;
> +	}
> +
> +	return 0;
> +}

This needs to check in the PCI host registers what happened and do
some appropriate action. If the fault was not caused by PCIe, it
should not be ignored here but get passed on to the next handler.

> +static int __init ks_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device *dev = &pdev->dev;
> +	struct keystone_pcie *ks_pcie;
> +	void __iomem *devstat;
> +	struct pcie_port *pp;
> +	struct resource *res;
> +	struct phy *phy;
> +	int ret = 0;
> +	u32 val;
> +
> +	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
> +				GFP_KERNEL);
> +	if (!ks_pcie) {
> +		dev_err(dev, "no memory for keystone pcie\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* check if serdes phy needs to be enabled */
> +	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
> +		phy = devm_phy_get(dev, "pcie-phy");
> +			if (IS_ERR(phy))
> +				return PTR_ERR(phy);
> +
> +		ret = phy_init(phy);
> +		if (ret < 0)
> +			return ret;
> +	}

I think you can just call devm_phy_get() unconditionally here and
get rid of the ti,init-phy property. If there is no phy, don't
initialize it.

> +
> +	ret = add_pcie_port(ks_pcie, pdev);
> +	if (ret < 0)
> +		goto fail_clk;
> +
> +	platform_set_drvdata(pdev, ks_pcie);

Set the platform data first, then add the port.

> +	dev_info(dev, "pcie rc probe success\n");

Remove this.

> +#ifdef CONFIG_PCI_KEYSTONE
> +/*
> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> + */
> +static void quirk_limit_readrequest(struct pci_dev *dev)
> +{
> +	int readrq = pcie_get_readrq(dev);
> +
> +	if (readrq > 256)
> +		pcie_set_readrq(dev, 256);
> +}
> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> +#endif /* CONFIG_PCI_KEYSTONE */

This doesn't work: you can't just limit do this for all devices just based
on PCI_KEYSTONE being enabled, you have to check if you are actually using
this controller.

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 16:01   ` Murali Karicheri
@ 2014-05-15 16:28     ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 16:28 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, linux-kernel, linux-pci, Grygorii Strashko,
	Mohit Kumar, Jingoo Han, Santosh Shilimkar, Bjorn Helgaas

On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
> +Sample bindings shown below:-
> +
> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
> +   configuration.
> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
> +   link

You actually have to document all the properties. Have a look at the
other bindings for what this means.

> +
> +               pcie@21800000 {
> +                       compatible = "ti,keystone-pcie";
> +                       device_type = "pci";
> +                       clocks = <&clkpcie>;
> +                       clock-names = "pcie";

The dw-pcie binding lists two clocks.

> +                       #address-cells = >;
> +                       #size-cells = <2>;
> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
> +                       reg-names = "reg_rc_app", "reg_devcfg";

There should be standard names that are documented in the binding.

> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */

What are all these interrupts?

> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */

Please move the config space into 'reg' now instead of 'ranges'.
This was a mistake earlier, and there are already other front-ends
doing the same thing.

> +                       num-lanes = <2>;
> +                       ti,enable-linktrain;
> +                       ti,init-phy;
> +
> +                       /* PCIE phy */
> +                       phys = <&pcie0_phy>;
> +                       phy-names = "pcie-phy";
> +
> +                       #interrupt-cells = <1>;
> +                       interrupt-map-mask = <0 0 0 0>;
> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
> +                                       <0 0 0 4 &pcie_intc 4>; // INT D

I think this is the wrong map-mask.

	Arnd

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 16:28     ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 16:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
> +Sample bindings shown below:-
> +
> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
> +   configuration.
> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
> +   link

You actually have to document all the properties. Have a look at the
other bindings for what this means.

> +
> +               pcie at 21800000 {
> +                       compatible = "ti,keystone-pcie";
> +                       device_type = "pci";
> +                       clocks = <&clkpcie>;
> +                       clock-names = "pcie";

The dw-pcie binding lists two clocks.

> +                       #address-cells = >;
> +                       #size-cells = <2>;
> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
> +                       reg-names = "reg_rc_app", "reg_devcfg";

There should be standard names that are documented in the binding.

> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */

What are all these interrupts?

> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */

Please move the config space into 'reg' now instead of 'ranges'.
This was a mistake earlier, and there are already other front-ends
doing the same thing.

> +                       num-lanes = <2>;
> +                       ti,enable-linktrain;
> +                       ti,init-phy;
> +
> +                       /* PCIE phy */
> +                       phys = <&pcie0_phy>;
> +                       phy-names = "pcie-phy";
> +
> +                       #interrupt-cells = <1>;
> +                       interrupt-map-mask = <0 0 0 0>;
> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
> +                                       <0 0 0 4 &pcie_intc 4>; // INT D

I think this is the wrong map-mask.

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 16:23     ` Arnd Bergmann
  (?)
@ 2014-05-15 17:45       ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 17:45 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, Strashko, Grygorii,
	Mohit Kumar, Jingoo Han, Shilimkar, Santosh, Bjorn Helgaas

Arnd,


Thanks for the review. I may have more questions as I digest the 
comments. Here is the
immediate one.

>> +#ifdef CONFIG_PCI_KEYSTONE
>> +/*
>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>> + */
>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>> +{
>> +	int readrq = pcie_get_readrq(dev);
>> +
>> +	if (readrq > 256)
>> +		pcie_set_readrq(dev, 256);
>> +}
>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>> +#endif /* CONFIG_PCI_KEYSTONE */
> This doesn't work: you can't just limit do this for all devices just based
> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> this controller.
>
> 	Arnd
  I assume, I need to check if PCI controller's vendor ID/ device ID 
match with the keystone
  PCI controller's ID and call pcie_set_readrq() for all of the slave 
PCI devices and do this fixup.
Is this correct understanding?  If you can point me to an example code 
for this that will be
really helpful so that I can avoid re-inventing the wheel.

Murali


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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 17:45       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 17:45 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, Strashko, Grygorii,
	Mohit Kumar, Jingoo Han, Shilimkar, Santosh, Bjorn Helgaas

Arnd,


Thanks for the review. I may have more questions as I digest the 
comments. Here is the
immediate one.

>> +#ifdef CONFIG_PCI_KEYSTONE
>> +/*
>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>> + */
>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>> +{
>> +	int readrq = pcie_get_readrq(dev);
>> +
>> +	if (readrq > 256)
>> +		pcie_set_readrq(dev, 256);
>> +}
>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>> +#endif /* CONFIG_PCI_KEYSTONE */
> This doesn't work: you can't just limit do this for all devices just based
> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> this controller.
>
> 	Arnd
  I assume, I need to check if PCI controller's vendor ID/ device ID 
match with the keystone
  PCI controller's ID and call pcie_set_readrq() for all of the slave 
PCI devices and do this fixup.
Is this correct understanding?  If you can point me to an example code 
for this that will be
really helpful so that I can avoid re-inventing the wheel.

Murali


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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 17:45       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Arnd,


Thanks for the review. I may have more questions as I digest the 
comments. Here is the
immediate one.

>> +#ifdef CONFIG_PCI_KEYSTONE
>> +/*
>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>> + */
>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>> +{
>> +	int readrq = pcie_get_readrq(dev);
>> +
>> +	if (readrq > 256)
>> +		pcie_set_readrq(dev, 256);
>> +}
>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>> +#endif /* CONFIG_PCI_KEYSTONE */
> This doesn't work: you can't just limit do this for all devices just based
> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> this controller.
>
> 	Arnd
  I assume, I need to check if PCI controller's vendor ID/ device ID 
match with the keystone
  PCI controller's ID and call pcie_set_readrq() for all of the slave 
PCI devices and do this fixup.
Is this correct understanding?  If you can point me to an example code 
for this that will be
really helpful so that I can avoid re-inventing the wheel.

Murali

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 17:45       ` Murali Karicheri
@ 2014-05-15 18:20         ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 18:20 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas

On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >> +#ifdef CONFIG_PCI_KEYSTONE
> >> +/*
> >> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >> + */
> >> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >> +{
> >> +    int readrq = pcie_get_readrq(dev);
> >> +
> >> +    if (readrq > 256)
> >> +            pcie_set_readrq(dev, 256);
> >> +}
> >> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >> +#endif /* CONFIG_PCI_KEYSTONE */
> > This doesn't work: you can't just limit do this for all devices just based
> > on PCI_KEYSTONE being enabled, you have to check if you are actually using
> > this controller.
> >
> >       Arnd
>   I assume, I need to check if PCI controller's vendor ID/ device ID 
> match with the keystone
>   PCI controller's ID and call pcie_set_readrq() for all of the slave 
> PCI devices and do this fixup.
> Is this correct understanding?  If you can point me to an example code 
> for this that will be
> really helpful so that I can avoid re-inventing the wheel.

I think it would be best to move the quirk into the keystone pci driver
and compare compare the dev->driver pointer of the PCI controller device.

	Arnd

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 18:20         ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-15 18:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >> +#ifdef CONFIG_PCI_KEYSTONE
> >> +/*
> >> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >> + */
> >> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >> +{
> >> +    int readrq = pcie_get_readrq(dev);
> >> +
> >> +    if (readrq > 256)
> >> +            pcie_set_readrq(dev, 256);
> >> +}
> >> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >> +#endif /* CONFIG_PCI_KEYSTONE */
> > This doesn't work: you can't just limit do this for all devices just based
> > on PCI_KEYSTONE being enabled, you have to check if you are actually using
> > this controller.
> >
> >       Arnd
>   I assume, I need to check if PCI controller's vendor ID/ device ID 
> match with the keystone
>   PCI controller's ID and call pcie_set_readrq() for all of the slave 
> PCI devices and do this fixup.
> Is this correct understanding?  If you can point me to an example code 
> for this that will be
> really helpful so that I can avoid re-inventing the wheel.

I think it would be best to move the quirk into the keystone pci driver
and compare compare the dev->driver pointer of the PCI controller device.

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 18:20         ` Arnd Bergmann
@ 2014-05-15 18:39           ` Jason Gunthorpe
  -1 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-15 18:39 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Murali Karicheri, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Thu, May 15, 2014 at 08:20:13PM +0200, Arnd Bergmann wrote:
> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> > >> +#ifdef CONFIG_PCI_KEYSTONE
> > >> +/*
> > >> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> > >> + */
> > >> +static void quirk_limit_readrequest(struct pci_dev *dev)
> > >> +{
> > >> +    int readrq = pcie_get_readrq(dev);
> > >> +
> > >> +    if (readrq > 256)
> > >> +            pcie_set_readrq(dev, 256);
> > >> +}
> > >> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> > >> +#endif /* CONFIG_PCI_KEYSTONE */
> > > This doesn't work: you can't just limit do this for all devices just based
> > > on PCI_KEYSTONE being enabled, you have to check if you are actually using
> > > this controller.
> > >
> > >       Arnd
> >   I assume, I need to check if PCI controller's vendor ID/ device ID 
> > match with the keystone
> >   PCI controller's ID and call pcie_set_readrq() for all of the slave 
> > PCI devices and do this fixup.
> > Is this correct understanding?  If you can point me to an example code 
> > for this that will be
> > really helpful so that I can avoid re-inventing the wheel.
> 
> I think it would be best to move the quirk into the keystone pci driver
> and compare compare the dev->driver pointer of the PCI controller device.

The PCI core handles setting the maximum read request size already,
can you figure out why the core code isn't doing what you need and
correct the root problem?

I'm guessing the values in the root port bridge config space are not
correct or something like that??

Jason

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 18:39           ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-15 18:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 15, 2014 at 08:20:13PM +0200, Arnd Bergmann wrote:
> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> > >> +#ifdef CONFIG_PCI_KEYSTONE
> > >> +/*
> > >> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> > >> + */
> > >> +static void quirk_limit_readrequest(struct pci_dev *dev)
> > >> +{
> > >> +    int readrq = pcie_get_readrq(dev);
> > >> +
> > >> +    if (readrq > 256)
> > >> +            pcie_set_readrq(dev, 256);
> > >> +}
> > >> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> > >> +#endif /* CONFIG_PCI_KEYSTONE */
> > > This doesn't work: you can't just limit do this for all devices just based
> > > on PCI_KEYSTONE being enabled, you have to check if you are actually using
> > > this controller.
> > >
> > >       Arnd
> >   I assume, I need to check if PCI controller's vendor ID/ device ID 
> > match with the keystone
> >   PCI controller's ID and call pcie_set_readrq() for all of the slave 
> > PCI devices and do this fixup.
> > Is this correct understanding?  If you can point me to an example code 
> > for this that will be
> > really helpful so that I can avoid re-inventing the wheel.
> 
> I think it would be best to move the quirk into the keystone pci driver
> and compare compare the dev->driver pointer of the PCI controller device.

The PCI core handles setting the maximum read request size already,
can you figure out why the core code isn't doing what you need and
correct the root problem?

I'm guessing the values in the root port bridge config space are not
correct or something like that??

Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 18:39           ` Jason Gunthorpe
  (?)
@ 2014-05-15 20:04             ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 20:04 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On 5/15/2014 2:39 PM, Jason Gunthorpe wrote:
> On Thu, May 15, 2014 at 08:20:13PM +0200, Arnd Bergmann wrote:
>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>> +/*
>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>> + */
>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>> +{
>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>> +
>>>>> +    if (readrq > 256)
>>>>> +            pcie_set_readrq(dev, 256);
>>>>> +}
>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>> This doesn't work: you can't just limit do this for all devices just based
>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>> this controller.
>>>>
>>>>        Arnd
>>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>>> match with the keystone
>>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>>> PCI devices and do this fixup.
>>> Is this correct understanding?  If you can point me to an example code
>>> for this that will be
>>> really helpful so that I can avoid re-inventing the wheel.
>> I think it would be best to move the quirk into the keystone pci driver
>> and compare compare the dev->driver pointer of the PCI controller device.
> The PCI core handles setting the maximum read request size already,
> can you figure out why the core code isn't doing what you need and
> correct the root problem?
>
> I'm guessing the values in the root port bridge config space are not
> correct or something like that??
>
> Jason
What you mean by "The PCI core handles setting the maximum read request 
size already"
I see there is function pcie_write_mrrs() in the drivers/pci/probe.c 
that reads the mps
using pcie_get_mps() and then set mrrs to mps. But this function is 
called only from
pcie_bus_configure_set() that is called by pcie_bus_configure_settings()

pcie_bus_configure_settings() is called by

0 pci-common.c pcibios_scan_phb             1676 
pcie_bus_configure_settings(child);
1 pci_gx.c     fixup_read_and_payload_sizes  606 
pcie_bus_configure_settings(child);
2 acpi.c       pci_acpi_scan_root            556 
pcie_bus_configure_settings(child);
3 pcihp_slot.c pci_configure_slot            164 
pcie_bus_configure_settings(dev->bus);

None of them gets called on ARM platform.

What is needed for Keystone PCI is that we need to limit mrrs to 256 
bytes for all
of the downstream devices that talks to PCIe controller. This needs to 
be enforced
through a quirk. Or Is there something missing that Keystone or DW 
driver is not
making use of that reads the mrrs value of the RC and set the same on 
all of the
downstream devices connected to the bus that the controller is connected to?

Murali


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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 20:04             ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 20:04 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On 5/15/2014 2:39 PM, Jason Gunthorpe wrote:
> On Thu, May 15, 2014 at 08:20:13PM +0200, Arnd Bergmann wrote:
>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>> +/*
>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>> + */
>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>> +{
>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>> +
>>>>> +    if (readrq > 256)
>>>>> +            pcie_set_readrq(dev, 256);
>>>>> +}
>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>> This doesn't work: you can't just limit do this for all devices just based
>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>> this controller.
>>>>
>>>>        Arnd
>>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>>> match with the keystone
>>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>>> PCI devices and do this fixup.
>>> Is this correct understanding?  If you can point me to an example code
>>> for this that will be
>>> really helpful so that I can avoid re-inventing the wheel.
>> I think it would be best to move the quirk into the keystone pci driver
>> and compare compare the dev->driver pointer of the PCI controller device.
> The PCI core handles setting the maximum read request size already,
> can you figure out why the core code isn't doing what you need and
> correct the root problem?
>
> I'm guessing the values in the root port bridge config space are not
> correct or something like that??
>
> Jason
What you mean by "The PCI core handles setting the maximum read request 
size already"
I see there is function pcie_write_mrrs() in the drivers/pci/probe.c 
that reads the mps
using pcie_get_mps() and then set mrrs to mps. But this function is 
called only from
pcie_bus_configure_set() that is called by pcie_bus_configure_settings()

pcie_bus_configure_settings() is called by

0 pci-common.c pcibios_scan_phb             1676 
pcie_bus_configure_settings(child);
1 pci_gx.c     fixup_read_and_payload_sizes  606 
pcie_bus_configure_settings(child);
2 acpi.c       pci_acpi_scan_root            556 
pcie_bus_configure_settings(child);
3 pcihp_slot.c pci_configure_slot            164 
pcie_bus_configure_settings(dev->bus);

None of them gets called on ARM platform.

What is needed for Keystone PCI is that we need to limit mrrs to 256 
bytes for all
of the downstream devices that talks to PCIe controller. This needs to 
be enforced
through a quirk. Or Is there something missing that Keystone or DW 
driver is not
making use of that reads the mrrs value of the RC and set the same on 
all of the
downstream devices connected to the bus that the controller is connected to?

Murali


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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 20:04             ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-15 20:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/15/2014 2:39 PM, Jason Gunthorpe wrote:
> On Thu, May 15, 2014 at 08:20:13PM +0200, Arnd Bergmann wrote:
>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>> +/*
>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>> + */
>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>> +{
>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>> +
>>>>> +    if (readrq > 256)
>>>>> +            pcie_set_readrq(dev, 256);
>>>>> +}
>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>> This doesn't work: you can't just limit do this for all devices just based
>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>> this controller.
>>>>
>>>>        Arnd
>>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>>> match with the keystone
>>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>>> PCI devices and do this fixup.
>>> Is this correct understanding?  If you can point me to an example code
>>> for this that will be
>>> really helpful so that I can avoid re-inventing the wheel.
>> I think it would be best to move the quirk into the keystone pci driver
>> and compare compare the dev->driver pointer of the PCI controller device.
> The PCI core handles setting the maximum read request size already,
> can you figure out why the core code isn't doing what you need and
> correct the root problem?
>
> I'm guessing the values in the root port bridge config space are not
> correct or something like that??
>
> Jason
What you mean by "The PCI core handles setting the maximum read request 
size already"
I see there is function pcie_write_mrrs() in the drivers/pci/probe.c 
that reads the mps
using pcie_get_mps() and then set mrrs to mps. But this function is 
called only from
pcie_bus_configure_set() that is called by pcie_bus_configure_settings()

pcie_bus_configure_settings() is called by

0 pci-common.c pcibios_scan_phb             1676 
pcie_bus_configure_settings(child);
1 pci_gx.c     fixup_read_and_payload_sizes  606 
pcie_bus_configure_settings(child);
2 acpi.c       pci_acpi_scan_root            556 
pcie_bus_configure_settings(child);
3 pcihp_slot.c pci_configure_slot            164 
pcie_bus_configure_settings(dev->bus);

None of them gets called on ARM platform.

What is needed for Keystone PCI is that we need to limit mrrs to 256 
bytes for all
of the downstream devices that talks to PCIe controller. This needs to 
be enforced
through a quirk. Or Is there something missing that Keystone or DW 
driver is not
making use of that reads the mrrs value of the RC and set the same on 
all of the
downstream devices connected to the bus that the controller is connected to?

Murali

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 20:04             ` Murali Karicheri
  (?)
@ 2014-05-15 20:52               ` Jason Gunthorpe
  -1 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-15 20:52 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:

> Jason What you mean by "The PCI core handles setting the maximum
> read request size already" I see there is function pcie_write_mrrs()
> in the drivers/pci/probe.c that reads the mps using pcie_get_mps()
> and then set mrrs to mps. But this function is called only from
> pcie_bus_configure_set() that is called by
> pcie_bus_configure_settings()

Right, that is the common code that correctly sets the MRRS that you
should be using instead of quirks.

> None of them gets called on ARM platform.

Hmm, a cursory glance tells me the same as well.

That seems to be the root problem here, ARM needs to do the PCIE
setup just as much as any other arch.

So, I would prefer to see you fix ARM common code to call
pcie_bus_configure_settings() properly, that seems very simple and is
obviously needed for any PCI-E host driver on ARM.

Thoughts? Arnd? Bjorn?

Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 20:52               ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-15 20:52 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:

> Jason What you mean by "The PCI core handles setting the maximum
> read request size already" I see there is function pcie_write_mrrs()
> in the drivers/pci/probe.c that reads the mps using pcie_get_mps()
> and then set mrrs to mps. But this function is called only from
> pcie_bus_configure_set() that is called by
> pcie_bus_configure_settings()

Right, that is the common code that correctly sets the MRRS that you
should be using instead of quirks.

> None of them gets called on ARM platform.

Hmm, a cursory glance tells me the same as well.

That seems to be the root problem here, ARM needs to do the PCIE
setup just as much as any other arch.

So, I would prefer to see you fix ARM common code to call
pcie_bus_configure_settings() properly, that seems very simple and is
obviously needed for any PCI-E host driver on ARM.

Thoughts? Arnd? Bjorn?

Jason

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-15 20:52               ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-15 20:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:

> Jason What you mean by "The PCI core handles setting the maximum
> read request size already" I see there is function pcie_write_mrrs()
> in the drivers/pci/probe.c that reads the mps using pcie_get_mps()
> and then set mrrs to mps. But this function is called only from
> pcie_bus_configure_set() that is called by
> pcie_bus_configure_settings()

Right, that is the common code that correctly sets the MRRS that you
should be using instead of quirks.

> None of them gets called on ARM platform.

Hmm, a cursory glance tells me the same as well.

That seems to be the root problem here, ARM needs to do the PCIE
setup just as much as any other arch.

So, I would prefer to see you fix ARM common code to call
pcie_bus_configure_settings() properly, that seems very simple and is
obviously needed for any PCI-E host driver on ARM.

Thoughts? Arnd? Bjorn?

Jason

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

* Re: [PATCH v1 1/5] ARM: keystone: add pcie related options
  2014-05-15 16:01   ` Murali Karicheri
@ 2014-05-16  0:27     ` Jingoo Han
  -1 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-05-16  0:27 UTC (permalink / raw)
  To: 'Murali Karicheri'
  Cc: linux-kernel, linux-pci, linux-arm-kernel,
	'Santosh Shilimkar', 'Russell King',
	'Jingoo Han'

On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
> 
> Add pcie related options by default for keystone architecture
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
>  arch/arm/mach-keystone/Kconfig |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
> index f50bc93..f87844d 100644
> --- a/arch/arm/mach-keystone/Kconfig
> +++ b/arch/arm/mach-keystone/Kconfig
> @@ -8,6 +8,8 @@ config ARCH_KEYSTONE
>  	select COMMON_CLK_KEYSTONE
>  	select ARCH_SUPPORTS_BIG_ENDIAN
>  	select ZONE_DMA if ARM_LPAE
> +	select MIGHT_HAVE_PCI
> +	select ARCH_SUPPORTS_MSI

Please, don't select ARCH_SUPPORTS_MSI, because this kconfig
option was already removed in v3.12 by the commit ebd97be635
('PCI: remove ARCH_SUPPORTS_MSI kconfig option'). So. there is
NO need to select 'ARCH_SUPPORTS_MSI'.

Best regards,
Jingoo Han

>  	help
>  	  Support for boards based on the Texas Instruments Keystone family of
>  	  SoCs.
> --
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH v1 1/5] ARM: keystone: add pcie related options
@ 2014-05-16  0:27     ` Jingoo Han
  0 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-05-16  0:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
> 
> Add pcie related options by default for keystone architecture
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
>  arch/arm/mach-keystone/Kconfig |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
> index f50bc93..f87844d 100644
> --- a/arch/arm/mach-keystone/Kconfig
> +++ b/arch/arm/mach-keystone/Kconfig
> @@ -8,6 +8,8 @@ config ARCH_KEYSTONE
>  	select COMMON_CLK_KEYSTONE
>  	select ARCH_SUPPORTS_BIG_ENDIAN
>  	select ZONE_DMA if ARM_LPAE
> +	select MIGHT_HAVE_PCI
> +	select ARCH_SUPPORTS_MSI

Please, don't select ARCH_SUPPORTS_MSI, because this kconfig
option was already removed in v3.12 by the commit ebd97be635
('PCI: remove ARCH_SUPPORTS_MSI kconfig option'). So. there is
NO need to select 'ARCH_SUPPORTS_MSI'.

Best regards,
Jingoo Han

>  	help
>  	  Support for boards based on the Texas Instruments Keystone family of
>  	  SoCs.
> --
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" 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] 116+ messages in thread

* Re: [PATCH v1 0/5] Add Keystone PCIe controller driver
  2014-05-15 16:01 ` Murali Karicheri
@ 2014-05-16  0:48   ` Jingoo Han
  -1 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-05-16  0:48 UTC (permalink / raw)
  To: 'Murali Karicheri'
  Cc: linux-kernel, linux-pci, linux-arm-kernel,
	'Santosh Shilimkar', 'Russell King',
	'Grant Likely', 'Rob Herring',
	'Mohit Kumar', 'Bjorn Helgaas',
	'Jingoo Han', 'Pratyush Anand',
	'Richard Zhu', 'Kishon Vijay Abraham I',
	'Marek Vasut'

On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
> 
> This patch adds a PCIe controller driver for Keystone SoCs. This
> is based on the origin RFC patch that I had sent earlier. I have
> incorporated following comments:-
> 
>  - Add a interrupt controller node for Legacy irq chip and use
>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>  - Add a Phy driver to replace the original serdes driver
>  - Move common applicaiton register handling code to a separate
>    file to allow re-use across other platforms that use older
>    DW PCIe h/w
>  - PCI quirk for maximum read request size. Check and override only
>    if the maximum is higher than what controller can handle.
>  - Converted to a module platform driver.
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> 

Your patches modify 'pcie-designware.c', and affects other PCIe
drivers using designware PCIe Core IP. Please add the following
people to CC list. They are also related to the designware PCIe.

  Pratyush Anand <pratyush.anand@st.com>
  Richard Zhu <r65037@freescale.com>
  Kishon Vijay Abraham I <kishon@ti.com>
  Marek Vasut <marex@denx.de>

Best regards,
Jingoo Han

> 
> Murali Karicheri (5):
>   ARM: keystone: add pcie related options
>   pci: designware: enhancements to support keystone pcie
>   phy: pci serdes phy driver for keystone
>   pci: dw: add common functions to support old hw based pci driver
>   pci: keystone: add pcie driver based on designware core driver
> 
>  .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
>  arch/arm/mach-keystone/Kconfig                     |    2 +
>  drivers/pci/host/Kconfig                           |   12 +
>  drivers/pci/host/Makefile                          |    2 +
>  drivers/pci/host/pci-dw-old-msi.c                  |  150 ++++++++
>  drivers/pci/host/pci-dw-old.c                      |  371 ++++++++++++++++++
>  drivers/pci/host/pci-dw-old.h                      |   30 ++
>  drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
>  drivers/pci/host/pcie-designware.c                 |  101 +++--
>  drivers/pci/host/pcie-designware.h                 |   42 +-
>  drivers/pci/quirks.c                               |   13 +
>  drivers/phy/Kconfig                                |    6 +
>  drivers/phy/Makefile                               |    1 +
>  drivers/phy/phy-keystone.c                         |  230 +++++++++++
>  14 files changed, 1388 insertions(+), 40 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
>  create mode 100644 drivers/pci/host/pci-dw-old-msi.c
>  create mode 100644 drivers/pci/host/pci-dw-old.c
>  create mode 100644 drivers/pci/host/pci-dw-old.h
>  create mode 100644 drivers/pci/host/pci-keystone.c
>  create mode 100644 drivers/phy/phy-keystone.c
> 
> --
> 1.7.9.5


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

* [PATCH v1 0/5] Add Keystone PCIe controller driver
@ 2014-05-16  0:48   ` Jingoo Han
  0 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-05-16  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
> 
> This patch adds a PCIe controller driver for Keystone SoCs. This
> is based on the origin RFC patch that I had sent earlier. I have
> incorporated following comments:-
> 
>  - Add a interrupt controller node for Legacy irq chip and use
>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>  - Add a Phy driver to replace the original serdes driver
>  - Move common applicaiton register handling code to a separate
>    file to allow re-use across other platforms that use older
>    DW PCIe h/w
>  - PCI quirk for maximum read request size. Check and override only
>    if the maximum is higher than what controller can handle.
>  - Converted to a module platform driver.
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> 

Your patches modify 'pcie-designware.c', and affects other PCIe
drivers using designware PCIe Core IP. Please add the following
people to CC list. They are also related to the designware PCIe.

  Pratyush Anand <pratyush.anand@st.com>
  Richard Zhu <r65037@freescale.com>
  Kishon Vijay Abraham I <kishon@ti.com>
  Marek Vasut <marex@denx.de>

Best regards,
Jingoo Han

> 
> Murali Karicheri (5):
>   ARM: keystone: add pcie related options
>   pci: designware: enhancements to support keystone pcie
>   phy: pci serdes phy driver for keystone
>   pci: dw: add common functions to support old hw based pci driver
>   pci: keystone: add pcie driver based on designware core driver
> 
>  .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
>  arch/arm/mach-keystone/Kconfig                     |    2 +
>  drivers/pci/host/Kconfig                           |   12 +
>  drivers/pci/host/Makefile                          |    2 +
>  drivers/pci/host/pci-dw-old-msi.c                  |  150 ++++++++
>  drivers/pci/host/pci-dw-old.c                      |  371 ++++++++++++++++++
>  drivers/pci/host/pci-dw-old.h                      |   30 ++
>  drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
>  drivers/pci/host/pcie-designware.c                 |  101 +++--
>  drivers/pci/host/pcie-designware.h                 |   42 +-
>  drivers/pci/quirks.c                               |   13 +
>  drivers/phy/Kconfig                                |    6 +
>  drivers/phy/Makefile                               |    1 +
>  drivers/phy/phy-keystone.c                         |  230 +++++++++++
>  14 files changed, 1388 insertions(+), 40 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
>  create mode 100644 drivers/pci/host/pci-dw-old-msi.c
>  create mode 100644 drivers/pci/host/pci-dw-old.c
>  create mode 100644 drivers/pci/host/pci-dw-old.h
>  create mode 100644 drivers/pci/host/pci-keystone.c
>  create mode 100644 drivers/phy/phy-keystone.c
> 
> --
> 1.7.9.5

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

* Re: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
  2014-05-15 16:01   ` Murali Karicheri
@ 2014-05-16  2:40     ` Jingoo Han
  -1 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-05-16  2:40 UTC (permalink / raw)
  To: 'Murali Karicheri'
  Cc: linux-kernel, linux-pci, linux-arm-kernel, 'Mohit Kumar',
	'Bjorn Helgaas', 'Santosh Shilimkar',
	'Jingoo Han', 'Pratyush Anand',
	'Richard Zhu', 'Kishon Vijay Abraham I',
	'Marek Vasut'

On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
> 
> keystone pcie hardware is based on designware hw version 3.65.
> There is no support for ATU port and has registers in
> application space to configure inbound/outbound access. Also
> doesn't support PCI PVM option. The MSI IRQ registers available
> in application space is used to mask/unmask/enable the MSI IRQs.
> 
> DW core driver is a set of common functions that are abstracted
> to support DW pci drivers. To allow re-use of these functions for
> keystone pci driver, core driver is to be enhanced.
> 
> Following are done to allow re-use of the functions on keystone pci
> driver.
> 
>  1. Some of the variables in pcie_port struct is folded inside
>     a union that now contains both new DW hw related variables as well
>     as old hardware related variables such as application reg base.
>  2. Added a dw_pcie_common_host_init() function that holds common
>     host initialization code for old and new hw.
>  3. dw_pcie_parse_resource() is used for parsing resource related
>     information from DT bindings.
>  4. dw_pcie_host_init() is called by new DW hw drivers as before.
>     Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>     Both these functions now call dw_pcie_common_host_init().
>  5. Some of the static functions are made global to allow use from
>     dw old pci drivers such as pci-keystone.
> 
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
>  drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
>  drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
>  2 files changed, 103 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index c4e3732..9ea8e79 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
>  		}
>  		set_bit(pos0 + i, pp->msi_irq_in_use);
>  		/*Enable corresponding interrupt in MSI interrupt controller */
> -		res = ((pos0 + i) / 32) * 12;
> -		bit = (pos0 + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> -		val |= 1 << bit;
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
> +		if (!(pp->version & DW_VERSION_OLD)) {

(+cc Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut)

DW_VERSION_OLD?
I don't this name. What is OLD? It is too general.
There should be the proper feature name between your 3.65 version
and other newer versions. This feature name can be defined as DT
property. Also, this code should be selected by DT property.


> +			res = ((pos0 + i) / 32) * 12;
> +			bit = (pos0 + i) % 32;
> +			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, &val);
> +			val |= 1 << bit;
> +			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, val);
> +		}
>  	}
> 
>  	*pos = pos0;
> @@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
>  	 */
>  	desc->msi_attrib.multiple = msgvec;
> 
> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
> +	if (pp->ops->get_msi_data)
> +		msg.address_lo = pp->ops->get_msi_data(pp);
> +	else
> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>  	msg.address_hi = 0x0;
>  	msg.data = pos;
>  	write_msi_msg(irq, &msg);
> @@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
>  	.map = dw_pcie_msi_map,
>  };
> 
> -int __init dw_pcie_host_init(struct pcie_port *pp)
> +int __init dw_pcie_parse_resource(struct pcie_port *pp)
>  {
>  	struct device_node *np = pp->dev->of_node;
> -	struct of_pci_range range;
>  	struct of_pci_range_parser parser;
> -	u32 val;
> -	int i;
> +	struct of_pci_range range;
> 
>  	if (of_pci_range_parser_init(&parser, np)) {
>  		dev_err(pp->dev, "missing ranges property\n");
> @@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>  			return -ENOMEM;
>  		}
>  	}
> -
> -	pp->cfg0_base = pp->cfg.start;
> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>  	pp->mem_base = pp->mem.start;
> 
> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> -					pp->config.cfg0_size);
> -	if (!pp->va_cfg0_base) {
> -		dev_err(pp->dev, "error with ioremap in function\n");
> -		return -ENOMEM;
> -	}
> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> -					pp->config.cfg1_size);
> -	if (!pp->va_cfg1_base) {
> -		dev_err(pp->dev, "error with ioremap\n");
> -		return -ENOMEM;
> -	}
> +	return 0;
> +}
> +
> +int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +				const struct irq_domain_ops *irq_msi_ops)
> +{
> +	struct device_node *np = pp->dev->of_node;
> +	u32 val;
> +	int i;
> 
>  	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
>  		dev_err(pp->dev, "Failed to parse the number of lanes\n");
> @@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 
>  	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>  		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
> -					MAX_MSI_IRQS, &msi_domain_ops,
> +					MAX_MSI_IRQS, irq_msi_ops,
>  					&dw_pcie_msi_chip);
>  		if (!pp->irq_domain) {
>  			dev_err(pp->dev, "irq domain init failed\n");
> @@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>  	val |= PORT_LOGIC_SPEED_CHANGE;
>  	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
> 
> -	dw_pci.nr_controllers = 1;
> -	dw_pci.private_data = (void **)&pp;
> +	hw->nr_controllers = 1;
> +	hw->private_data = (void **)&pp;
> 
> -	pci_common_init_dev(pp->dev, &dw_pci);
> +	pci_common_init_dev(pp->dev, hw);
>  	pci_assign_unassigned_resources();
>  #ifdef CONFIG_PCI_DOMAINS
>  	dw_pci.domain++;
> @@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>  	return 0;
>  }
> 
> +int __init dw_pcie_host_init(struct pcie_port *pp)
> +{
> +	int ret;
> +
> +	ret = dw_pcie_parse_resource(pp);
> +	if (ret)
> +		return ret;
> +
> +	pp->cfg0_base = pp->cfg.start;
> +	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> +	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> +					pp->config.cfg0_size);
> +	if (!pp->va_cfg0_base) {
> +		dev_err(pp->dev, "error with ioremap in function\n");
> +		return -ENOMEM;
> +	}
> +	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> +					pp->config.cfg1_size);
> +	if (!pp->va_cfg1_base) {
> +		dev_err(pp->dev, "error with ioremap\n");
> +		return -ENOMEM;
> +	}
> +
> +	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
> +}
> +
>  static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
>  {
>  	/* Program viewport 0 : OUTBOUND : CFG0 */
> @@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
> 
>  	spin_lock_irqsave(&pp->conf_lock, flags);
>  	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> +		if (pp->ops->rd_other_conf)
> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>  						where, size, val);
>  	else
>  		ret = dw_pcie_rd_own_conf(pp, where, size, val);
> @@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
> 
>  	spin_lock_irqsave(&pp->conf_lock, flags);
>  	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> +		if (pp->ops->wr_other_conf)
> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>  						where, size, val);
>  	else
>  		ret = dw_pcie_wr_own_conf(pp, where, size, val);
> @@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
>  	.write = dw_pcie_wr_conf,
>  };
> 
> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)

You removed 'static'; however, this modification is related
to another patch. ([PATCH v1 4/5] pci: dw: add common functions
to support old hw based pci driver)

Please don't mix the modification. So, move this fix to the 4th
patch.

>  {
>  	struct pcie_port *pp;
> 
> @@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>  	return 1;
>  }
> 
> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>  {
>  	struct pci_bus *bus;
>  	struct pcie_port *pp = sys_to_pcie(sys);
> @@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>  	return irq;
>  }
> 
> -static void dw_pcie_add_bus(struct pci_bus *bus)
> +void dw_pcie_add_bus(struct pci_bus *bus)
>  {
>  	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>  		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index 3063b35..e97f4d7 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -35,21 +35,39 @@ struct pcie_port {
>  	struct device		*dev;
>  	u8			root_bus_nr;
>  	void __iomem		*dbi_base;
> -	u64			cfg0_base;
> -	void __iomem		*va_cfg0_base;
> -	u64			cfg1_base;
> -	void __iomem		*va_cfg1_base;
> +	/*
> +	 * Old DW version implement application register space for
> +	 * MSI and has no ATU view port
> +	 */

ATU can be defined as DT property. It can be selected by
this DT property.

> +#define DW_VERSION_OLD	BIT(0)
> +	u32			version;
> +	union {
> +		/* new dw core specific */
> +		struct {
> +			u64		cfg0_base;
> +			void __iomem	*va_cfg0_base;
> +			u64		cfg1_base;
> +			void __iomem	*va_cfg1_base;
> +			int		msi_irq;
> +		};
> +
> +		/* old dw core specific */
> +		struct  {
> +			struct irq_domain	*legacy_irq_domain;
> +			void __iomem		*va_app_base;
> +			u64			app_base;
> +		};
> +	};
>  	u64			io_base;
>  	u64			mem_base;
>  	spinlock_t		conf_lock;
> -	struct resource		cfg;
>  	struct resource		io;
>  	struct resource		mem;
> +	struct resource		cfg;

Please don't move this variable, without the reason.
Keep in mind that this code is shared with other SoC
drivers. So, without special reason, please don't modify
it.

>  	struct pcie_port_info	config;
>  	int			irq;
>  	u32			lanes;
>  	struct pcie_host_ops	*ops;
> -	int			msi_irq;
>  	struct irq_domain	*irq_domain;
>  	unsigned long		msi_data;
>  	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
> @@ -62,8 +80,13 @@ struct pcie_host_ops {
>  			u32 val, void __iomem *dbi_base);
>  	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
>  	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 *val);
> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 val);
>  	int (*link_up)(struct pcie_port *pp);
>  	void (*host_init)(struct pcie_port *pp);
> +	u32 (*get_msi_data)(struct pcie_port *pp);
>  };
> 
>  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
> @@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>  int dw_pcie_link_up(struct pcie_port *pp);
>  void dw_pcie_setup_rc(struct pcie_port *pp);
>  int dw_pcie_host_init(struct pcie_port *pp);
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
> +void dw_pcie_add_bus(struct pci_bus *bus);
> +int dw_pcie_parse_resource(struct pcie_port *pp);
> 
> +/* internal to dw core */
> +int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +			const struct irq_domain_ops *irq_ops);
>  #endif /* _PCIE_DESIGNWARE_H */
> --
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
@ 2014-05-16  2:40     ` Jingoo Han
  0 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-05-16  2:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
> 
> keystone pcie hardware is based on designware hw version 3.65.
> There is no support for ATU port and has registers in
> application space to configure inbound/outbound access. Also
> doesn't support PCI PVM option. The MSI IRQ registers available
> in application space is used to mask/unmask/enable the MSI IRQs.
> 
> DW core driver is a set of common functions that are abstracted
> to support DW pci drivers. To allow re-use of these functions for
> keystone pci driver, core driver is to be enhanced.
> 
> Following are done to allow re-use of the functions on keystone pci
> driver.
> 
>  1. Some of the variables in pcie_port struct is folded inside
>     a union that now contains both new DW hw related variables as well
>     as old hardware related variables such as application reg base.
>  2. Added a dw_pcie_common_host_init() function that holds common
>     host initialization code for old and new hw.
>  3. dw_pcie_parse_resource() is used for parsing resource related
>     information from DT bindings.
>  4. dw_pcie_host_init() is called by new DW hw drivers as before.
>     Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>     Both these functions now call dw_pcie_common_host_init().
>  5. Some of the static functions are made global to allow use from
>     dw old pci drivers such as pci-keystone.
> 
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
>  drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
>  drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
>  2 files changed, 103 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index c4e3732..9ea8e79 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
>  		}
>  		set_bit(pos0 + i, pp->msi_irq_in_use);
>  		/*Enable corresponding interrupt in MSI interrupt controller */
> -		res = ((pos0 + i) / 32) * 12;
> -		bit = (pos0 + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> -		val |= 1 << bit;
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
> +		if (!(pp->version & DW_VERSION_OLD)) {

(+cc Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut)

DW_VERSION_OLD?
I don't this name. What is OLD? It is too general.
There should be the proper feature name between your 3.65 version
and other newer versions. This feature name can be defined as DT
property. Also, this code should be selected by DT property.


> +			res = ((pos0 + i) / 32) * 12;
> +			bit = (pos0 + i) % 32;
> +			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, &val);
> +			val |= 1 << bit;
> +			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, val);
> +		}
>  	}
> 
>  	*pos = pos0;
> @@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
>  	 */
>  	desc->msi_attrib.multiple = msgvec;
> 
> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
> +	if (pp->ops->get_msi_data)
> +		msg.address_lo = pp->ops->get_msi_data(pp);
> +	else
> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>  	msg.address_hi = 0x0;
>  	msg.data = pos;
>  	write_msi_msg(irq, &msg);
> @@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
>  	.map = dw_pcie_msi_map,
>  };
> 
> -int __init dw_pcie_host_init(struct pcie_port *pp)
> +int __init dw_pcie_parse_resource(struct pcie_port *pp)
>  {
>  	struct device_node *np = pp->dev->of_node;
> -	struct of_pci_range range;
>  	struct of_pci_range_parser parser;
> -	u32 val;
> -	int i;
> +	struct of_pci_range range;
> 
>  	if (of_pci_range_parser_init(&parser, np)) {
>  		dev_err(pp->dev, "missing ranges property\n");
> @@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>  			return -ENOMEM;
>  		}
>  	}
> -
> -	pp->cfg0_base = pp->cfg.start;
> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>  	pp->mem_base = pp->mem.start;
> 
> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> -					pp->config.cfg0_size);
> -	if (!pp->va_cfg0_base) {
> -		dev_err(pp->dev, "error with ioremap in function\n");
> -		return -ENOMEM;
> -	}
> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> -					pp->config.cfg1_size);
> -	if (!pp->va_cfg1_base) {
> -		dev_err(pp->dev, "error with ioremap\n");
> -		return -ENOMEM;
> -	}
> +	return 0;
> +}
> +
> +int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +				const struct irq_domain_ops *irq_msi_ops)
> +{
> +	struct device_node *np = pp->dev->of_node;
> +	u32 val;
> +	int i;
> 
>  	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
>  		dev_err(pp->dev, "Failed to parse the number of lanes\n");
> @@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 
>  	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>  		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
> -					MAX_MSI_IRQS, &msi_domain_ops,
> +					MAX_MSI_IRQS, irq_msi_ops,
>  					&dw_pcie_msi_chip);
>  		if (!pp->irq_domain) {
>  			dev_err(pp->dev, "irq domain init failed\n");
> @@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>  	val |= PORT_LOGIC_SPEED_CHANGE;
>  	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
> 
> -	dw_pci.nr_controllers = 1;
> -	dw_pci.private_data = (void **)&pp;
> +	hw->nr_controllers = 1;
> +	hw->private_data = (void **)&pp;
> 
> -	pci_common_init_dev(pp->dev, &dw_pci);
> +	pci_common_init_dev(pp->dev, hw);
>  	pci_assign_unassigned_resources();
>  #ifdef CONFIG_PCI_DOMAINS
>  	dw_pci.domain++;
> @@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>  	return 0;
>  }
> 
> +int __init dw_pcie_host_init(struct pcie_port *pp)
> +{
> +	int ret;
> +
> +	ret = dw_pcie_parse_resource(pp);
> +	if (ret)
> +		return ret;
> +
> +	pp->cfg0_base = pp->cfg.start;
> +	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> +	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> +					pp->config.cfg0_size);
> +	if (!pp->va_cfg0_base) {
> +		dev_err(pp->dev, "error with ioremap in function\n");
> +		return -ENOMEM;
> +	}
> +	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> +					pp->config.cfg1_size);
> +	if (!pp->va_cfg1_base) {
> +		dev_err(pp->dev, "error with ioremap\n");
> +		return -ENOMEM;
> +	}
> +
> +	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
> +}
> +
>  static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
>  {
>  	/* Program viewport 0 : OUTBOUND : CFG0 */
> @@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
> 
>  	spin_lock_irqsave(&pp->conf_lock, flags);
>  	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> +		if (pp->ops->rd_other_conf)
> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>  						where, size, val);
>  	else
>  		ret = dw_pcie_rd_own_conf(pp, where, size, val);
> @@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
> 
>  	spin_lock_irqsave(&pp->conf_lock, flags);
>  	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> +		if (pp->ops->wr_other_conf)
> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>  						where, size, val);
>  	else
>  		ret = dw_pcie_wr_own_conf(pp, where, size, val);
> @@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
>  	.write = dw_pcie_wr_conf,
>  };
> 
> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)

You removed 'static'; however, this modification is related
to another patch. ([PATCH v1 4/5] pci: dw: add common functions
to support old hw based pci driver)

Please don't mix the modification. So, move this fix to the 4th
patch.

>  {
>  	struct pcie_port *pp;
> 
> @@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>  	return 1;
>  }
> 
> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>  {
>  	struct pci_bus *bus;
>  	struct pcie_port *pp = sys_to_pcie(sys);
> @@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>  	return irq;
>  }
> 
> -static void dw_pcie_add_bus(struct pci_bus *bus)
> +void dw_pcie_add_bus(struct pci_bus *bus)
>  {
>  	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>  		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index 3063b35..e97f4d7 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -35,21 +35,39 @@ struct pcie_port {
>  	struct device		*dev;
>  	u8			root_bus_nr;
>  	void __iomem		*dbi_base;
> -	u64			cfg0_base;
> -	void __iomem		*va_cfg0_base;
> -	u64			cfg1_base;
> -	void __iomem		*va_cfg1_base;
> +	/*
> +	 * Old DW version implement application register space for
> +	 * MSI and has no ATU view port
> +	 */

ATU can be defined as DT property. It can be selected by
this DT property.

> +#define DW_VERSION_OLD	BIT(0)
> +	u32			version;
> +	union {
> +		/* new dw core specific */
> +		struct {
> +			u64		cfg0_base;
> +			void __iomem	*va_cfg0_base;
> +			u64		cfg1_base;
> +			void __iomem	*va_cfg1_base;
> +			int		msi_irq;
> +		};
> +
> +		/* old dw core specific */
> +		struct  {
> +			struct irq_domain	*legacy_irq_domain;
> +			void __iomem		*va_app_base;
> +			u64			app_base;
> +		};
> +	};
>  	u64			io_base;
>  	u64			mem_base;
>  	spinlock_t		conf_lock;
> -	struct resource		cfg;
>  	struct resource		io;
>  	struct resource		mem;
> +	struct resource		cfg;

Please don't move this variable, without the reason.
Keep in mind that this code is shared with other SoC
drivers. So, without special reason, please don't modify
it.

>  	struct pcie_port_info	config;
>  	int			irq;
>  	u32			lanes;
>  	struct pcie_host_ops	*ops;
> -	int			msi_irq;
>  	struct irq_domain	*irq_domain;
>  	unsigned long		msi_data;
>  	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
> @@ -62,8 +80,13 @@ struct pcie_host_ops {
>  			u32 val, void __iomem *dbi_base);
>  	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
>  	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 *val);
> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 val);
>  	int (*link_up)(struct pcie_port *pp);
>  	void (*host_init)(struct pcie_port *pp);
> +	u32 (*get_msi_data)(struct pcie_port *pp);
>  };
> 
>  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
> @@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>  int dw_pcie_link_up(struct pcie_port *pp);
>  void dw_pcie_setup_rc(struct pcie_port *pp);
>  int dw_pcie_host_init(struct pcie_port *pp);
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
> +void dw_pcie_add_bus(struct pci_bus *bus);
> +int dw_pcie_parse_resource(struct pcie_port *pp);
> 
> +/* internal to dw core */
> +int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +			const struct irq_domain_ops *irq_ops);
>  #endif /* _PCIE_DESIGNWARE_H */
> --
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" 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] 116+ messages in thread

* RE: [PATCH v1 1/5] ARM: keystone: add pcie related options
  2014-05-16  0:27     ` Jingoo Han
  (?)
@ 2014-05-16 14:36       ` Karicheri, Muralidharan
  -1 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 14:36 UTC (permalink / raw)
  To: Jingoo Han
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Shilimkar, Santosh,
	'Russell King'

>-----Original Message-----
>From: Jingoo Han [mailto:jg1.han@samsung.com]
>Sent: Thursday, May 15, 2014 8:28 PM
>To: Karicheri, Muralidharan
>Cc: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org; Shilimkar, Santosh; 'Russell King'; 'Jingoo Han'
>Subject: Re: [PATCH v1 1/5] ARM: keystone: add pcie related options
>
>On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
>>
>> Add pcie related options by default for keystone architecture
>>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> CC: Russell King <linux@arm.linux.org.uk>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>  arch/arm/mach-keystone/Kconfig |    2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/arch/arm/mach-keystone/Kconfig
>> b/arch/arm/mach-keystone/Kconfig index f50bc93..f87844d 100644
>> --- a/arch/arm/mach-keystone/Kconfig
>> +++ b/arch/arm/mach-keystone/Kconfig
>> @@ -8,6 +8,8 @@ config ARCH_KEYSTONE
>>  	select COMMON_CLK_KEYSTONE
>>  	select ARCH_SUPPORTS_BIG_ENDIAN
>>  	select ZONE_DMA if ARM_LPAE
>> +	select MIGHT_HAVE_PCI
>> +	select ARCH_SUPPORTS_MSI
>
>Please, don't select ARCH_SUPPORTS_MSI, because this kconfig option was already
>removed in v3.12 by the commit ebd97be635
>('PCI: remove ARCH_SUPPORTS_MSI kconfig option'). So. there is NO need to select
>'ARCH_SUPPORTS_MSI'.
>

Will do. Thanks.

>Best regards,
>Jingoo Han
>
>>  	help
>>  	  Support for boards based on the Texas Instruments Keystone family of
>>  	  SoCs.
>> --
>> 1.7.9.5
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pci"
>> in the body of a message to majordomo@vger.kernel.org More majordomo
>> info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH v1 1/5] ARM: keystone: add pcie related options
@ 2014-05-16 14:36       ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 14:36 UTC (permalink / raw)
  To: Jingoo Han
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Shilimkar, Santosh,
	'Russell King'

>-----Original Message-----
>From: Jingoo Han [mailto:jg1.han@samsung.com]
>Sent: Thursday, May 15, 2014 8:28 PM
>To: Karicheri, Muralidharan
>Cc: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org; Shilimkar, Santosh; 'Russell King'; 'Jingoo Han'
>Subject: Re: [PATCH v1 1/5] ARM: keystone: add pcie related options
>
>On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
>>
>> Add pcie related options by default for keystone architecture
>>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> CC: Russell King <linux@arm.linux.org.uk>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>  arch/arm/mach-keystone/Kconfig |    2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/arch/arm/mach-keystone/Kconfig
>> b/arch/arm/mach-keystone/Kconfig index f50bc93..f87844d 100644
>> --- a/arch/arm/mach-keystone/Kconfig
>> +++ b/arch/arm/mach-keystone/Kconfig
>> @@ -8,6 +8,8 @@ config ARCH_KEYSTONE
>>  	select COMMON_CLK_KEYSTONE
>>  	select ARCH_SUPPORTS_BIG_ENDIAN
>>  	select ZONE_DMA if ARM_LPAE
>> +	select MIGHT_HAVE_PCI
>> +	select ARCH_SUPPORTS_MSI
>
>Please, don't select ARCH_SUPPORTS_MSI, because this kconfig option was already
>removed in v3.12 by the commit ebd97be635
>('PCI: remove ARCH_SUPPORTS_MSI kconfig option'). So. there is NO need to select
>'ARCH_SUPPORTS_MSI'.
>

Will do. Thanks.

>Best regards,
>Jingoo Han
>
>>  	help
>>  	  Support for boards based on the Texas Instruments Keystone family of
>>  	  SoCs.
>> --
>> 1.7.9.5
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pci"
>> in the body of a message to majordomo@vger.kernel.org More majordomo
>> info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH v1 1/5] ARM: keystone: add pcie related options
@ 2014-05-16 14:36       ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

>-----Original Message-----
>From: Jingoo Han [mailto:jg1.han at samsung.com]
>Sent: Thursday, May 15, 2014 8:28 PM
>To: Karicheri, Muralidharan
>Cc: linux-kernel at vger.kernel.org; linux-pci at vger.kernel.org; linux-arm-
>kernel at lists.infradead.org; Shilimkar, Santosh; 'Russell King'; 'Jingoo Han'
>Subject: Re: [PATCH v1 1/5] ARM: keystone: add pcie related options
>
>On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
>>
>> Add pcie related options by default for keystone architecture
>>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> CC: Russell King <linux@arm.linux.org.uk>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>  arch/arm/mach-keystone/Kconfig |    2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/arch/arm/mach-keystone/Kconfig
>> b/arch/arm/mach-keystone/Kconfig index f50bc93..f87844d 100644
>> --- a/arch/arm/mach-keystone/Kconfig
>> +++ b/arch/arm/mach-keystone/Kconfig
>> @@ -8,6 +8,8 @@ config ARCH_KEYSTONE
>>  	select COMMON_CLK_KEYSTONE
>>  	select ARCH_SUPPORTS_BIG_ENDIAN
>>  	select ZONE_DMA if ARM_LPAE
>> +	select MIGHT_HAVE_PCI
>> +	select ARCH_SUPPORTS_MSI
>
>Please, don't select ARCH_SUPPORTS_MSI, because this kconfig option was already
>removed in v3.12 by the commit ebd97be635
>('PCI: remove ARCH_SUPPORTS_MSI kconfig option'). So. there is NO need to select
>'ARCH_SUPPORTS_MSI'.
>

Will do. Thanks.

>Best regards,
>Jingoo Han
>
>>  	help
>>  	  Support for boards based on the Texas Instruments Keystone family of
>>  	  SoCs.
>> --
>> 1.7.9.5
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pci"
>> 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] 116+ messages in thread

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 18:20         ` Arnd Bergmann
  (?)
@ 2014-05-16 20:26           ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 20:26 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas

On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>> +/*
>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>> + */
>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>> +{
>>>> +    int readrq = pcie_get_readrq(dev);
>>>> +
>>>> +    if (readrq > 256)
>>>> +            pcie_set_readrq(dev, 256);
>>>> +}
>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>> This doesn't work: you can't just limit do this for all devices just based
>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>> this controller.
>>>
>>>        Arnd
>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>> match with the keystone
>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>> PCI devices and do this fixup.
>> Is this correct understanding?  If you can point me to an example code
>> for this that will be
>> really helpful so that I can avoid re-inventing the wheel.
> I think it would be best to move the quirk into the keystone pci driver
> and compare compare the dev->driver pointer of the PCI controller device.
>
> 	Arnd
Arnd,

I will move this quirk to keystone pci driver. So in that case, I guess 
your original comment
is not applicable as  this quirk gets enabled only with PCI keystone 
driver enabled. Right?

Murali

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 20:26           ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 20:26 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas

On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>> +/*
>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>> + */
>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>> +{
>>>> +    int readrq = pcie_get_readrq(dev);
>>>> +
>>>> +    if (readrq > 256)
>>>> +            pcie_set_readrq(dev, 256);
>>>> +}
>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>> This doesn't work: you can't just limit do this for all devices just based
>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>> this controller.
>>>
>>>        Arnd
>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>> match with the keystone
>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>> PCI devices and do this fixup.
>> Is this correct understanding?  If you can point me to an example code
>> for this that will be
>> really helpful so that I can avoid re-inventing the wheel.
> I think it would be best to move the quirk into the keystone pci driver
> and compare compare the dev->driver pointer of the PCI controller device.
>
> 	Arnd
Arnd,

I will move this quirk to keystone pci driver. So in that case, I guess 
your original comment
is not applicable as  this quirk gets enabled only with PCI keystone 
driver enabled. Right?

Murali

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 20:26           ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 20:26 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>> +/*
>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>> + */
>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>> +{
>>>> +    int readrq = pcie_get_readrq(dev);
>>>> +
>>>> +    if (readrq > 256)
>>>> +            pcie_set_readrq(dev, 256);
>>>> +}
>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>> This doesn't work: you can't just limit do this for all devices just based
>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>> this controller.
>>>
>>>        Arnd
>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>> match with the keystone
>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>> PCI devices and do this fixup.
>> Is this correct understanding?  If you can point me to an example code
>> for this that will be
>> really helpful so that I can avoid re-inventing the wheel.
> I think it would be best to move the quirk into the keystone pci driver
> and compare compare the dev->driver pointer of the PCI controller device.
>
> 	Arnd
Arnd,

I will move this quirk to keystone pci driver. So in that case, I guess 
your original comment
is not applicable as  this quirk gets enabled only with PCI keystone 
driver enabled. Right?

Murali

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

* RE: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 20:52               ` Jason Gunthorpe
  (?)
@ 2014-05-16 20:29                 ` Karicheri, Muralidharan
  -1 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:29 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

>-----Original Message-----
>From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
>Sent: Thursday, May 15, 2014 4:52 PM
>To: Karicheri, Muralidharan
>Cc: Arnd Bergmann; linux-arm-kernel@lists.infradead.org; Strashko, Grygorii; linux-
>pci@vger.kernel.org; Jingoo Han; linux-kernel@vger.kernel.org; Shilimkar, Santosh; Mohit
>Kumar; Bjorn Helgaas
>Subject: Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core
>driver
>
>On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:
>
>> Jason What you mean by "The PCI core handles setting the maximum read
>> request size already" I see there is function pcie_write_mrrs() in the
>> drivers/pci/probe.c that reads the mps using pcie_get_mps() and then
>> set mrrs to mps. But this function is called only from
>> pcie_bus_configure_set() that is called by
>> pcie_bus_configure_settings()
>
>Right, that is the common code that correctly sets the MRRS that you should be using
>instead of quirks.
>
>> None of them gets called on ARM platform.
>
>Hmm, a cursory glance tells me the same as well.
>
>That seems to be the root problem here, ARM needs to do the PCIE setup just as much as
>any other arch.
>
>So, I would prefer to see you fix ARM common code to call
>pcie_bus_configure_settings() properly, that seems very simple and is obviously needed for
>any PCI-E host driver on ARM.
>

But pcie_bus_configure_settings just make sure the mrrs for a device is not greater than
the max payload size. But the quirk that I need is to limit the size of mrr to 256 as required
by the keystone PCI controller. So I still need to implement a quirk to enforce this limit.

In my reply to Arnd, I have agreed to move the quirk to keystone driver.

Murali
>Thoughts? Arnd? Bjorn?
>
>Jason

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

* RE: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 20:29                 ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:29 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

>-----Original Message-----
>From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
>Sent: Thursday, May 15, 2014 4:52 PM
>To: Karicheri, Muralidharan
>Cc: Arnd Bergmann; linux-arm-kernel@lists.infradead.org; Strashko, Grygorii; linux-
>pci@vger.kernel.org; Jingoo Han; linux-kernel@vger.kernel.org; Shilimkar, Santosh; Mohit
>Kumar; Bjorn Helgaas
>Subject: Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core
>driver
>
>On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:
>
>> Jason What you mean by "The PCI core handles setting the maximum read
>> request size already" I see there is function pcie_write_mrrs() in the
>> drivers/pci/probe.c that reads the mps using pcie_get_mps() and then
>> set mrrs to mps. But this function is called only from
>> pcie_bus_configure_set() that is called by
>> pcie_bus_configure_settings()
>
>Right, that is the common code that correctly sets the MRRS that you should be using
>instead of quirks.
>
>> None of them gets called on ARM platform.
>
>Hmm, a cursory glance tells me the same as well.
>
>That seems to be the root problem here, ARM needs to do the PCIE setup just as much as
>any other arch.
>
>So, I would prefer to see you fix ARM common code to call
>pcie_bus_configure_settings() properly, that seems very simple and is obviously needed for
>any PCI-E host driver on ARM.
>

But pcie_bus_configure_settings just make sure the mrrs for a device is not greater than
the max payload size. But the quirk that I need is to limit the size of mrr to 256 as required
by the keystone PCI controller. So I still need to implement a quirk to enforce this limit.

In my reply to Arnd, I have agreed to move the quirk to keystone driver.

Murali
>Thoughts? Arnd? Bjorn?
>
>Jason

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 20:29                 ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:29 UTC (permalink / raw)
  To: linux-arm-kernel

>-----Original Message-----
>From: Jason Gunthorpe [mailto:jgunthorpe at obsidianresearch.com]
>Sent: Thursday, May 15, 2014 4:52 PM
>To: Karicheri, Muralidharan
>Cc: Arnd Bergmann; linux-arm-kernel at lists.infradead.org; Strashko, Grygorii; linux-
>pci at vger.kernel.org; Jingoo Han; linux-kernel at vger.kernel.org; Shilimkar, Santosh; Mohit
>Kumar; Bjorn Helgaas
>Subject: Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core
>driver
>
>On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:
>
>> Jason What you mean by "The PCI core handles setting the maximum read
>> request size already" I see there is function pcie_write_mrrs() in the
>> drivers/pci/probe.c that reads the mps using pcie_get_mps() and then
>> set mrrs to mps. But this function is called only from
>> pcie_bus_configure_set() that is called by
>> pcie_bus_configure_settings()
>
>Right, that is the common code that correctly sets the MRRS that you should be using
>instead of quirks.
>
>> None of them gets called on ARM platform.
>
>Hmm, a cursory glance tells me the same as well.
>
>That seems to be the root problem here, ARM needs to do the PCIE setup just as much as
>any other arch.
>
>So, I would prefer to see you fix ARM common code to call
>pcie_bus_configure_settings() properly, that seems very simple and is obviously needed for
>any PCI-E host driver on ARM.
>

But pcie_bus_configure_settings just make sure the mrrs for a device is not greater than
the max payload size. But the quirk that I need is to limit the size of mrr to 256 as required
by the keystone PCI controller. So I still need to implement a quirk to enforce this limit.

In my reply to Arnd, I have agreed to move the quirk to keystone driver.

Murali
>Thoughts? Arnd? Bjorn?
>
>Jason

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

* RE: [PATCH v1 0/5] Add Keystone PCIe controller driver
  2014-05-16  0:48   ` Jingoo Han
  (?)
@ 2014-05-16 20:40     ` Karicheri, Muralidharan
  -1 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:40 UTC (permalink / raw)
  To: Jingoo Han
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Shilimkar, Santosh,
	'Russell King', 'Grant Likely',
	'Rob Herring', 'Mohit Kumar',
	'Bjorn Helgaas', 'Pratyush Anand',
	'Richard Zhu',
	ABRAHAM, KISHON VIJAY, 'Marek Vasut'

>-----Original Message-----
>From: Jingoo Han [mailto:jg1.han@samsung.com]
>Sent: Thursday, May 15, 2014 8:49 PM
>To: Karicheri, Muralidharan
>Cc: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org; Shilimkar, Santosh; 'Russell King'; 'Grant Likely'; 'Rob Herring';
>'Mohit Kumar'; 'Bjorn Helgaas'; 'Jingoo Han'; 'Pratyush Anand'; 'Richard Zhu'; ABRAHAM,
>KISHON VIJAY; 'Marek Vasut'
>Subject: Re: [PATCH v1 0/5] Add Keystone PCIe controller driver
>
>On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
>>
>> This patch adds a PCIe controller driver for Keystone SoCs. This is
>> based on the origin RFC patch that I had sent earlier. I have
>> incorporated following comments:-
>>
>>  - Add a interrupt controller node for Legacy irq chip and use
>>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>>  - Add a Phy driver to replace the original serdes driver
>>  - Move common applicaiton register handling code to a separate
>>    file to allow re-use across other platforms that use older
>>    DW PCIe h/w
>>  - PCI quirk for maximum read request size. Check and override only
>>    if the maximum is higher than what controller can handle.
>>  - Converted to a module platform driver.
>>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> CC: Russell King <linux@arm.linux.org.uk>
>> CC: Grant Likely <grant.likely@linaro.org>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>>
>
>Your patches modify 'pcie-designware.c', and affects other PCIe drivers using designware
>PCIe Core IP. Please add the following people to CC list. They are also related to the
>designware PCIe.
>
>  Pratyush Anand <pratyush.anand@st.com>
>  Richard Zhu <r65037@freescale.com>
>  Kishon Vijay Abraham I <kishon@ti.com>
>  Marek Vasut <marex@denx.de>
>
Will forward the patches to the above list as well.

Thanks

Murali
>Best regards,
>Jingoo Han
>
>>
>> Murali Karicheri (5):
>>   ARM: keystone: add pcie related options
>>   pci: designware: enhancements to support keystone pcie
>>   phy: pci serdes phy driver for keystone
>>   pci: dw: add common functions to support old hw based pci driver
>>   pci: keystone: add pcie driver based on designware core driver
>>
>>  .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
>>  arch/arm/mach-keystone/Kconfig                     |    2 +
>>  drivers/pci/host/Kconfig                           |   12 +
>>  drivers/pci/host/Makefile                          |    2 +
>>  drivers/pci/host/pci-dw-old-msi.c                  |  150 ++++++++
>>  drivers/pci/host/pci-dw-old.c                      |  371 ++++++++++++++++++
>>  drivers/pci/host/pci-dw-old.h                      |   30 ++
>>  drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
>>  drivers/pci/host/pcie-designware.c                 |  101 +++--
>>  drivers/pci/host/pcie-designware.h                 |   42 +-
>>  drivers/pci/quirks.c                               |   13 +
>>  drivers/phy/Kconfig                                |    6 +
>>  drivers/phy/Makefile                               |    1 +
>>  drivers/phy/phy-keystone.c                         |  230 +++++++++++
>>  14 files changed, 1388 insertions(+), 40 deletions(-)  create mode
>> 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
>>  create mode 100644 drivers/pci/host/pci-dw-old-msi.c  create mode
>> 100644 drivers/pci/host/pci-dw-old.c  create mode 100644
>> drivers/pci/host/pci-dw-old.h  create mode 100644
>> drivers/pci/host/pci-keystone.c  create mode 100644
>> drivers/phy/phy-keystone.c
>>
>> --
>> 1.7.9.5


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

* RE: [PATCH v1 0/5] Add Keystone PCIe controller driver
@ 2014-05-16 20:40     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:40 UTC (permalink / raw)
  To: Jingoo Han
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Shilimkar, Santosh,
	'Russell King', 'Grant Likely',
	'Rob Herring', 'Mohit Kumar',
	'Bjorn Helgaas', 'Pratyush Anand',
	'Richard Zhu',
	ABRAHAM, KISHON VIJAY, 'Marek Vasut'

>-----Original Message-----
>From: Jingoo Han [mailto:jg1.han@samsung.com]
>Sent: Thursday, May 15, 2014 8:49 PM
>To: Karicheri, Muralidharan
>Cc: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org; Shilimkar, Santosh; 'Russell King'; 'Grant Likely'; 'Rob Herring';
>'Mohit Kumar'; 'Bjorn Helgaas'; 'Jingoo Han'; 'Pratyush Anand'; 'Richard Zhu'; ABRAHAM,
>KISHON VIJAY; 'Marek Vasut'
>Subject: Re: [PATCH v1 0/5] Add Keystone PCIe controller driver
>
>On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
>>
>> This patch adds a PCIe controller driver for Keystone SoCs. This is
>> based on the origin RFC patch that I had sent earlier. I have
>> incorporated following comments:-
>>
>>  - Add a interrupt controller node for Legacy irq chip and use
>>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>>  - Add a Phy driver to replace the original serdes driver
>>  - Move common applicaiton register handling code to a separate
>>    file to allow re-use across other platforms that use older
>>    DW PCIe h/w
>>  - PCI quirk for maximum read request size. Check and override only
>>    if the maximum is higher than what controller can handle.
>>  - Converted to a module platform driver.
>>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> CC: Russell King <linux@arm.linux.org.uk>
>> CC: Grant Likely <grant.likely@linaro.org>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>>
>
>Your patches modify 'pcie-designware.c', and affects other PCIe drivers using designware
>PCIe Core IP. Please add the following people to CC list. They are also related to the
>designware PCIe.
>
>  Pratyush Anand <pratyush.anand@st.com>
>  Richard Zhu <r65037@freescale.com>
>  Kishon Vijay Abraham I <kishon@ti.com>
>  Marek Vasut <marex@denx.de>
>
Will forward the patches to the above list as well.

Thanks

Murali
>Best regards,
>Jingoo Han
>
>>
>> Murali Karicheri (5):
>>   ARM: keystone: add pcie related options
>>   pci: designware: enhancements to support keystone pcie
>>   phy: pci serdes phy driver for keystone
>>   pci: dw: add common functions to support old hw based pci driver
>>   pci: keystone: add pcie driver based on designware core driver
>>
>>  .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
>>  arch/arm/mach-keystone/Kconfig                     |    2 +
>>  drivers/pci/host/Kconfig                           |   12 +
>>  drivers/pci/host/Makefile                          |    2 +
>>  drivers/pci/host/pci-dw-old-msi.c                  |  150 ++++++++
>>  drivers/pci/host/pci-dw-old.c                      |  371 ++++++++++++++++++
>>  drivers/pci/host/pci-dw-old.h                      |   30 ++
>>  drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
>>  drivers/pci/host/pcie-designware.c                 |  101 +++--
>>  drivers/pci/host/pcie-designware.h                 |   42 +-
>>  drivers/pci/quirks.c                               |   13 +
>>  drivers/phy/Kconfig                                |    6 +
>>  drivers/phy/Makefile                               |    1 +
>>  drivers/phy/phy-keystone.c                         |  230 +++++++++++
>>  14 files changed, 1388 insertions(+), 40 deletions(-)  create mode
>> 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
>>  create mode 100644 drivers/pci/host/pci-dw-old-msi.c  create mode
>> 100644 drivers/pci/host/pci-dw-old.c  create mode 100644
>> drivers/pci/host/pci-dw-old.h  create mode 100644
>> drivers/pci/host/pci-keystone.c  create mode 100644
>> drivers/phy/phy-keystone.c
>>
>> --
>> 1.7.9.5


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

* [PATCH v1 0/5] Add Keystone PCIe controller driver
@ 2014-05-16 20:40     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:40 UTC (permalink / raw)
  To: linux-arm-kernel

>-----Original Message-----
>From: Jingoo Han [mailto:jg1.han at samsung.com]
>Sent: Thursday, May 15, 2014 8:49 PM
>To: Karicheri, Muralidharan
>Cc: linux-kernel at vger.kernel.org; linux-pci at vger.kernel.org; linux-arm-
>kernel at lists.infradead.org; Shilimkar, Santosh; 'Russell King'; 'Grant Likely'; 'Rob Herring';
>'Mohit Kumar'; 'Bjorn Helgaas'; 'Jingoo Han'; 'Pratyush Anand'; 'Richard Zhu'; ABRAHAM,
>KISHON VIJAY; 'Marek Vasut'
>Subject: Re: [PATCH v1 0/5] Add Keystone PCIe controller driver
>
>On Friday, May 16, 2014 1:01 AM, Murali Karicheri wrote:
>>
>> This patch adds a PCIe controller driver for Keystone SoCs. This is
>> based on the origin RFC patch that I had sent earlier. I have
>> incorporated following comments:-
>>
>>  - Add a interrupt controller node for Legacy irq chip and use
>>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>>  - Add a Phy driver to replace the original serdes driver
>>  - Move common applicaiton register handling code to a separate
>>    file to allow re-use across other platforms that use older
>>    DW PCIe h/w
>>  - PCI quirk for maximum read request size. Check and override only
>>    if the maximum is higher than what controller can handle.
>>  - Converted to a module platform driver.
>>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> CC: Russell King <linux@arm.linux.org.uk>
>> CC: Grant Likely <grant.likely@linaro.org>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>>
>
>Your patches modify 'pcie-designware.c', and affects other PCIe drivers using designware
>PCIe Core IP. Please add the following people to CC list. They are also related to the
>designware PCIe.
>
>  Pratyush Anand <pratyush.anand@st.com>
>  Richard Zhu <r65037@freescale.com>
>  Kishon Vijay Abraham I <kishon@ti.com>
>  Marek Vasut <marex@denx.de>
>
Will forward the patches to the above list as well.

Thanks

Murali
>Best regards,
>Jingoo Han
>
>>
>> Murali Karicheri (5):
>>   ARM: keystone: add pcie related options
>>   pci: designware: enhancements to support keystone pcie
>>   phy: pci serdes phy driver for keystone
>>   pci: dw: add common functions to support old hw based pci driver
>>   pci: keystone: add pcie driver based on designware core driver
>>
>>  .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
>>  arch/arm/mach-keystone/Kconfig                     |    2 +
>>  drivers/pci/host/Kconfig                           |   12 +
>>  drivers/pci/host/Makefile                          |    2 +
>>  drivers/pci/host/pci-dw-old-msi.c                  |  150 ++++++++
>>  drivers/pci/host/pci-dw-old.c                      |  371 ++++++++++++++++++
>>  drivers/pci/host/pci-dw-old.h                      |   30 ++
>>  drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
>>  drivers/pci/host/pcie-designware.c                 |  101 +++--
>>  drivers/pci/host/pcie-designware.h                 |   42 +-
>>  drivers/pci/quirks.c                               |   13 +
>>  drivers/phy/Kconfig                                |    6 +
>>  drivers/phy/Makefile                               |    1 +
>>  drivers/phy/phy-keystone.c                         |  230 +++++++++++
>>  14 files changed, 1388 insertions(+), 40 deletions(-)  create mode
>> 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
>>  create mode 100644 drivers/pci/host/pci-dw-old-msi.c  create mode
>> 100644 drivers/pci/host/pci-dw-old.c  create mode 100644
>> drivers/pci/host/pci-dw-old.h  create mode 100644
>> drivers/pci/host/pci-keystone.c  create mode 100644
>> drivers/phy/phy-keystone.c
>>
>> --
>> 1.7.9.5

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

* RE: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
  2014-05-15 16:01   ` Murali Karicheri
  (?)
@ 2014-05-16 20:46     ` Karicheri, Muralidharan
  -1 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:46 UTC (permalink / raw)
  To: Karicheri, Muralidharan, linux-kernel, linux-pci,
	linux-arm-kernel, pratyush.anand, r65037, ABRAHAM, KISHON VIJAY,
	marex
  Cc: Mohit Kumar, Jingoo Han, Bjorn Helgaas, Shilimkar, Santosh

Adding more to list.

>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:01 PM
>To: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org
>Cc: Karicheri, Muralidharan; Mohit Kumar; Jingoo Han; Bjorn Helgaas; Shilimkar, Santosh
>Subject: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
>
>keystone pcie hardware is based on designware hw version 3.65.
>There is no support for ATU port and has registers in application space to configure
>inbound/outbound access. Also doesn't support PCI PVM option. The MSI IRQ registers
>available in application space is used to mask/unmask/enable the MSI IRQs.
>
>DW core driver is a set of common functions that are abstracted to support DW pci drivers.
>To allow re-use of these functions for keystone pci driver, core driver is to be enhanced.
>
>Following are done to allow re-use of the functions on keystone pci driver.
>
> 1. Some of the variables in pcie_port struct is folded inside
>    a union that now contains both new DW hw related variables as well
>    as old hardware related variables such as application reg base.
> 2. Added a dw_pcie_common_host_init() function that holds common
>    host initialization code for old and new hw.
> 3. dw_pcie_parse_resource() is used for parsing resource related
>    information from DT bindings.
> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>    Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>    Both these functions now call dw_pcie_common_host_init().
> 5. Some of the static functions are made global to allow use from
>    dw old pci drivers such as pci-keystone.
>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>---
> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
> 2 files changed, 103 insertions(+), 40 deletions(-)
>
>diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
>index c4e3732..9ea8e79 100644
>--- a/drivers/pci/host/pcie-designware.c
>+++ b/drivers/pci/host/pcie-designware.c
>@@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
> 		}
> 		set_bit(pos0 + i, pp->msi_irq_in_use);
> 		/*Enable corresponding interrupt in MSI interrupt controller */
>-		res = ((pos0 + i) / 32) * 12;
>-		bit = (pos0 + i) % 32;
>-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>-		val |= 1 << bit;
>-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>+		if (!(pp->version & DW_VERSION_OLD)) {
>+			res = ((pos0 + i) / 32) * 12;
>+			bit = (pos0 + i) % 32;
>+			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>+						 4, &val);
>+			val |= 1 << bit;
>+			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>+						 4, val);
>+		}
> 	}
>
> 	*pos = pos0;
>@@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev
>*pdev,
> 	 */
> 	desc->msi_attrib.multiple = msgvec;
>
>-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
>+	if (pp->ops->get_msi_data)
>+		msg.address_lo = pp->ops->get_msi_data(pp);
>+	else
>+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
> 	msg.address_hi = 0x0;
> 	msg.data = pos;
> 	write_msi_msg(irq, &msg);
>@@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
> 	.map = dw_pcie_msi_map,
> };
>
>-int __init dw_pcie_host_init(struct pcie_port *pp)
>+int __init dw_pcie_parse_resource(struct pcie_port *pp)
> {
> 	struct device_node *np = pp->dev->of_node;
>-	struct of_pci_range range;
> 	struct of_pci_range_parser parser;
>-	u32 val;
>-	int i;
>+	struct of_pci_range range;
>
> 	if (of_pci_range_parser_init(&parser, np)) {
> 		dev_err(pp->dev, "missing ranges property\n"); @@ -440,23 +445,17 @@ int
>__init dw_pcie_host_init(struct pcie_port *pp)
> 			return -ENOMEM;
> 		}
> 	}
>-
>-	pp->cfg0_base = pp->cfg.start;
>-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> 	pp->mem_base = pp->mem.start;
>
>-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>-					pp->config.cfg0_size);
>-	if (!pp->va_cfg0_base) {
>-		dev_err(pp->dev, "error with ioremap in function\n");
>-		return -ENOMEM;
>-	}
>-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>-					pp->config.cfg1_size);
>-	if (!pp->va_cfg1_base) {
>-		dev_err(pp->dev, "error with ioremap\n");
>-		return -ENOMEM;
>-	}
>+	return 0;
>+}
>+
>+int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>+				const struct irq_domain_ops *irq_msi_ops) {
>+	struct device_node *np = pp->dev->of_node;
>+	u32 val;
>+	int i;
>
> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
> 		dev_err(pp->dev, "Failed to parse the number of lanes\n"); @@ -465,7 +464,7
>@@ int __init dw_pcie_host_init(struct pcie_port *pp)
>
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
>-					MAX_MSI_IRQS, &msi_domain_ops,
>+					MAX_MSI_IRQS, irq_msi_ops,
> 					&dw_pcie_msi_chip);
> 		if (!pp->irq_domain) {
> 			dev_err(pp->dev, "irq domain init failed\n"); @@ -488,10 +487,10 @@
>int __init dw_pcie_host_init(struct pcie_port *pp)
> 	val |= PORT_LOGIC_SPEED_CHANGE;
> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>
>-	dw_pci.nr_controllers = 1;
>-	dw_pci.private_data = (void **)&pp;
>+	hw->nr_controllers = 1;
>+	hw->private_data = (void **)&pp;
>
>-	pci_common_init_dev(pp->dev, &dw_pci);
>+	pci_common_init_dev(pp->dev, hw);
> 	pci_assign_unassigned_resources();
> #ifdef CONFIG_PCI_DOMAINS
> 	dw_pci.domain++;
>@@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 	return 0;
> }
>
>+int __init dw_pcie_host_init(struct pcie_port *pp) {
>+	int ret;
>+
>+	ret = dw_pcie_parse_resource(pp);
>+	if (ret)
>+		return ret;
>+
>+	pp->cfg0_base = pp->cfg.start;
>+	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>+	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>+					pp->config.cfg0_size);
>+	if (!pp->va_cfg0_base) {
>+		dev_err(pp->dev, "error with ioremap in function\n");
>+		return -ENOMEM;
>+	}
>+	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>+					pp->config.cfg1_size);
>+	if (!pp->va_cfg1_base) {
>+		dev_err(pp->dev, "error with ioremap\n");
>+		return -ENOMEM;
>+	}
>+
>+	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops); }
>+
> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)  {
> 	/* Program viewport 0 : OUTBOUND : CFG0 */ @@ -654,7 +679,11 @@ static int
>dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
>
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
>-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>+		if (pp->ops->rd_other_conf)
>+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
>+						where, size, val);
>+		else
>+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_rd_own_conf(pp, where, size, val); @@ -680,7 +709,11 @@
>static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
>
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
>-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>+		if (pp->ops->wr_other_conf)
>+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
>+						where, size, val);
>+		else
>+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_wr_own_conf(pp, where, size, val); @@ -694,7 +727,7 @@
>static struct pci_ops dw_pcie_ops = {
> 	.write = dw_pcie_wr_conf,
> };
>
>-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> {
> 	struct pcie_port *pp;
>
>@@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> 	return 1;
> }
>
>-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> {
> 	struct pci_bus *bus;
> 	struct pcie_port *pp = sys_to_pcie(sys); @@ -746,7 +779,7 @@ static int
>dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> 	return irq;
> }
>
>-static void dw_pcie_add_bus(struct pci_bus *bus)
>+void dw_pcie_add_bus(struct pci_bus *bus)
> {
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata); diff --git
>a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
>index 3063b35..e97f4d7 100644
>--- a/drivers/pci/host/pcie-designware.h
>+++ b/drivers/pci/host/pcie-designware.h
>@@ -35,21 +35,39 @@ struct pcie_port {
> 	struct device		*dev;
> 	u8			root_bus_nr;
> 	void __iomem		*dbi_base;
>-	u64			cfg0_base;
>-	void __iomem		*va_cfg0_base;
>-	u64			cfg1_base;
>-	void __iomem		*va_cfg1_base;
>+	/*
>+	 * Old DW version implement application register space for
>+	 * MSI and has no ATU view port
>+	 */
>+#define DW_VERSION_OLD	BIT(0)
>+	u32			version;
>+	union {
>+		/* new dw core specific */
>+		struct {
>+			u64		cfg0_base;
>+			void __iomem	*va_cfg0_base;
>+			u64		cfg1_base;
>+			void __iomem	*va_cfg1_base;
>+			int		msi_irq;
>+		};
>+
>+		/* old dw core specific */
>+		struct  {
>+			struct irq_domain	*legacy_irq_domain;
>+			void __iomem		*va_app_base;
>+			u64			app_base;
>+		};
>+	};
> 	u64			io_base;
> 	u64			mem_base;
> 	spinlock_t		conf_lock;
>-	struct resource		cfg;
> 	struct resource		io;
> 	struct resource		mem;
>+	struct resource		cfg;
> 	struct pcie_port_info	config;
> 	int			irq;
> 	u32			lanes;
> 	struct pcie_host_ops	*ops;
>-	int			msi_irq;
> 	struct irq_domain	*irq_domain;
> 	unsigned long		msi_data;
> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); @@ -62,8 +80,13 @@ struct
>pcie_host_ops {
> 			u32 val, void __iomem *dbi_base);
> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
>+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>+			unsigned int devfn, int where, int size, u32 *val);
>+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>+			unsigned int devfn, int where, int size, u32 val);
> 	int (*link_up)(struct pcie_port *pp);
> 	void (*host_init)(struct pcie_port *pp);
>+	u32 (*get_msi_data)(struct pcie_port *pp);
> };
>
> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); @@ -73,5
>+96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);  int dw_pcie_link_up(struct
>pcie_port *pp);  void dw_pcie_setup_rc(struct pcie_port *pp);  int dw_pcie_host_init(struct
>pcie_port *pp);
>+int dw_pcie_setup(int nr, struct pci_sys_data *sys); struct pci_bus
>+*dw_pcie_scan_bus(int nr, struct pci_sys_data *sys); void
>+dw_pcie_add_bus(struct pci_bus *bus); int dw_pcie_parse_resource(struct
>+pcie_port *pp);
>
>+/* internal to dw core */
>+int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>+			const struct irq_domain_ops *irq_ops);
> #endif /* _PCIE_DESIGNWARE_H */
>--
>1.7.9.5


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

* RE: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
@ 2014-05-16 20:46     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:46 UTC (permalink / raw)
  To: Karicheri, Muralidharan, linux-kernel, linux-pci,
	linux-arm-kernel, pratyush.anand, r65037, ABRAHAM, KISHON VIJAY,
	marex
  Cc: Mohit Kumar, Jingoo Han, Bjorn Helgaas, Shilimkar, Santosh

Adding more to list.

>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:01 PM
>To: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org
>Cc: Karicheri, Muralidharan; Mohit Kumar; Jingoo Han; Bjorn Helgaas; Shilimkar, Santosh
>Subject: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
>
>keystone pcie hardware is based on designware hw version 3.65.
>There is no support for ATU port and has registers in application space to configure
>inbound/outbound access. Also doesn't support PCI PVM option. The MSI IRQ registers
>available in application space is used to mask/unmask/enable the MSI IRQs.
>
>DW core driver is a set of common functions that are abstracted to support DW pci drivers.
>To allow re-use of these functions for keystone pci driver, core driver is to be enhanced.
>
>Following are done to allow re-use of the functions on keystone pci driver.
>
> 1. Some of the variables in pcie_port struct is folded inside
>    a union that now contains both new DW hw related variables as well
>    as old hardware related variables such as application reg base.
> 2. Added a dw_pcie_common_host_init() function that holds common
>    host initialization code for old and new hw.
> 3. dw_pcie_parse_resource() is used for parsing resource related
>    information from DT bindings.
> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>    Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>    Both these functions now call dw_pcie_common_host_init().
> 5. Some of the static functions are made global to allow use from
>    dw old pci drivers such as pci-keystone.
>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>---
> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
> 2 files changed, 103 insertions(+), 40 deletions(-)
>
>diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
>index c4e3732..9ea8e79 100644
>--- a/drivers/pci/host/pcie-designware.c
>+++ b/drivers/pci/host/pcie-designware.c
>@@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
> 		}
> 		set_bit(pos0 + i, pp->msi_irq_in_use);
> 		/*Enable corresponding interrupt in MSI interrupt controller */
>-		res = ((pos0 + i) / 32) * 12;
>-		bit = (pos0 + i) % 32;
>-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>-		val |= 1 << bit;
>-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>+		if (!(pp->version & DW_VERSION_OLD)) {
>+			res = ((pos0 + i) / 32) * 12;
>+			bit = (pos0 + i) % 32;
>+			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>+						 4, &val);
>+			val |= 1 << bit;
>+			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>+						 4, val);
>+		}
> 	}
>
> 	*pos = pos0;
>@@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev
>*pdev,
> 	 */
> 	desc->msi_attrib.multiple = msgvec;
>
>-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
>+	if (pp->ops->get_msi_data)
>+		msg.address_lo = pp->ops->get_msi_data(pp);
>+	else
>+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
> 	msg.address_hi = 0x0;
> 	msg.data = pos;
> 	write_msi_msg(irq, &msg);
>@@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
> 	.map = dw_pcie_msi_map,
> };
>
>-int __init dw_pcie_host_init(struct pcie_port *pp)
>+int __init dw_pcie_parse_resource(struct pcie_port *pp)
> {
> 	struct device_node *np = pp->dev->of_node;
>-	struct of_pci_range range;
> 	struct of_pci_range_parser parser;
>-	u32 val;
>-	int i;
>+	struct of_pci_range range;
>
> 	if (of_pci_range_parser_init(&parser, np)) {
> 		dev_err(pp->dev, "missing ranges property\n"); @@ -440,23 +445,17 @@ int
>__init dw_pcie_host_init(struct pcie_port *pp)
> 			return -ENOMEM;
> 		}
> 	}
>-
>-	pp->cfg0_base = pp->cfg.start;
>-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> 	pp->mem_base = pp->mem.start;
>
>-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>-					pp->config.cfg0_size);
>-	if (!pp->va_cfg0_base) {
>-		dev_err(pp->dev, "error with ioremap in function\n");
>-		return -ENOMEM;
>-	}
>-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>-					pp->config.cfg1_size);
>-	if (!pp->va_cfg1_base) {
>-		dev_err(pp->dev, "error with ioremap\n");
>-		return -ENOMEM;
>-	}
>+	return 0;
>+}
>+
>+int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>+				const struct irq_domain_ops *irq_msi_ops) {
>+	struct device_node *np = pp->dev->of_node;
>+	u32 val;
>+	int i;
>
> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
> 		dev_err(pp->dev, "Failed to parse the number of lanes\n"); @@ -465,7 +464,7
>@@ int __init dw_pcie_host_init(struct pcie_port *pp)
>
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
>-					MAX_MSI_IRQS, &msi_domain_ops,
>+					MAX_MSI_IRQS, irq_msi_ops,
> 					&dw_pcie_msi_chip);
> 		if (!pp->irq_domain) {
> 			dev_err(pp->dev, "irq domain init failed\n"); @@ -488,10 +487,10 @@
>int __init dw_pcie_host_init(struct pcie_port *pp)
> 	val |= PORT_LOGIC_SPEED_CHANGE;
> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>
>-	dw_pci.nr_controllers = 1;
>-	dw_pci.private_data = (void **)&pp;
>+	hw->nr_controllers = 1;
>+	hw->private_data = (void **)&pp;
>
>-	pci_common_init_dev(pp->dev, &dw_pci);
>+	pci_common_init_dev(pp->dev, hw);
> 	pci_assign_unassigned_resources();
> #ifdef CONFIG_PCI_DOMAINS
> 	dw_pci.domain++;
>@@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 	return 0;
> }
>
>+int __init dw_pcie_host_init(struct pcie_port *pp) {
>+	int ret;
>+
>+	ret = dw_pcie_parse_resource(pp);
>+	if (ret)
>+		return ret;
>+
>+	pp->cfg0_base = pp->cfg.start;
>+	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>+	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>+					pp->config.cfg0_size);
>+	if (!pp->va_cfg0_base) {
>+		dev_err(pp->dev, "error with ioremap in function\n");
>+		return -ENOMEM;
>+	}
>+	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>+					pp->config.cfg1_size);
>+	if (!pp->va_cfg1_base) {
>+		dev_err(pp->dev, "error with ioremap\n");
>+		return -ENOMEM;
>+	}
>+
>+	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops); }
>+
> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)  {
> 	/* Program viewport 0 : OUTBOUND : CFG0 */ @@ -654,7 +679,11 @@ static int
>dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
>
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
>-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>+		if (pp->ops->rd_other_conf)
>+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
>+						where, size, val);
>+		else
>+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_rd_own_conf(pp, where, size, val); @@ -680,7 +709,11 @@
>static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
>
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
>-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>+		if (pp->ops->wr_other_conf)
>+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
>+						where, size, val);
>+		else
>+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_wr_own_conf(pp, where, size, val); @@ -694,7 +727,7 @@
>static struct pci_ops dw_pcie_ops = {
> 	.write = dw_pcie_wr_conf,
> };
>
>-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> {
> 	struct pcie_port *pp;
>
>@@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> 	return 1;
> }
>
>-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> {
> 	struct pci_bus *bus;
> 	struct pcie_port *pp = sys_to_pcie(sys); @@ -746,7 +779,7 @@ static int
>dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> 	return irq;
> }
>
>-static void dw_pcie_add_bus(struct pci_bus *bus)
>+void dw_pcie_add_bus(struct pci_bus *bus)
> {
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata); diff --git
>a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
>index 3063b35..e97f4d7 100644
>--- a/drivers/pci/host/pcie-designware.h
>+++ b/drivers/pci/host/pcie-designware.h
>@@ -35,21 +35,39 @@ struct pcie_port {
> 	struct device		*dev;
> 	u8			root_bus_nr;
> 	void __iomem		*dbi_base;
>-	u64			cfg0_base;
>-	void __iomem		*va_cfg0_base;
>-	u64			cfg1_base;
>-	void __iomem		*va_cfg1_base;
>+	/*
>+	 * Old DW version implement application register space for
>+	 * MSI and has no ATU view port
>+	 */
>+#define DW_VERSION_OLD	BIT(0)
>+	u32			version;
>+	union {
>+		/* new dw core specific */
>+		struct {
>+			u64		cfg0_base;
>+			void __iomem	*va_cfg0_base;
>+			u64		cfg1_base;
>+			void __iomem	*va_cfg1_base;
>+			int		msi_irq;
>+		};
>+
>+		/* old dw core specific */
>+		struct  {
>+			struct irq_domain	*legacy_irq_domain;
>+			void __iomem		*va_app_base;
>+			u64			app_base;
>+		};
>+	};
> 	u64			io_base;
> 	u64			mem_base;
> 	spinlock_t		conf_lock;
>-	struct resource		cfg;
> 	struct resource		io;
> 	struct resource		mem;
>+	struct resource		cfg;
> 	struct pcie_port_info	config;
> 	int			irq;
> 	u32			lanes;
> 	struct pcie_host_ops	*ops;
>-	int			msi_irq;
> 	struct irq_domain	*irq_domain;
> 	unsigned long		msi_data;
> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); @@ -62,8 +80,13 @@ struct
>pcie_host_ops {
> 			u32 val, void __iomem *dbi_base);
> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
>+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>+			unsigned int devfn, int where, int size, u32 *val);
>+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>+			unsigned int devfn, int where, int size, u32 val);
> 	int (*link_up)(struct pcie_port *pp);
> 	void (*host_init)(struct pcie_port *pp);
>+	u32 (*get_msi_data)(struct pcie_port *pp);
> };
>
> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); @@ -73,5
>+96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);  int dw_pcie_link_up(struct
>pcie_port *pp);  void dw_pcie_setup_rc(struct pcie_port *pp);  int dw_pcie_host_init(struct
>pcie_port *pp);
>+int dw_pcie_setup(int nr, struct pci_sys_data *sys); struct pci_bus
>+*dw_pcie_scan_bus(int nr, struct pci_sys_data *sys); void
>+dw_pcie_add_bus(struct pci_bus *bus); int dw_pcie_parse_resource(struct
>+pcie_port *pp);
>
>+/* internal to dw core */
>+int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>+			const struct irq_domain_ops *irq_ops);
> #endif /* _PCIE_DESIGNWARE_H */
>--
>1.7.9.5


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

* [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
@ 2014-05-16 20:46     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:46 UTC (permalink / raw)
  To: linux-arm-kernel

Adding more to list.

>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:01 PM
>To: linux-kernel at vger.kernel.org; linux-pci at vger.kernel.org; linux-arm-
>kernel at lists.infradead.org
>Cc: Karicheri, Muralidharan; Mohit Kumar; Jingoo Han; Bjorn Helgaas; Shilimkar, Santosh
>Subject: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
>
>keystone pcie hardware is based on designware hw version 3.65.
>There is no support for ATU port and has registers in application space to configure
>inbound/outbound access. Also doesn't support PCI PVM option. The MSI IRQ registers
>available in application space is used to mask/unmask/enable the MSI IRQs.
>
>DW core driver is a set of common functions that are abstracted to support DW pci drivers.
>To allow re-use of these functions for keystone pci driver, core driver is to be enhanced.
>
>Following are done to allow re-use of the functions on keystone pci driver.
>
> 1. Some of the variables in pcie_port struct is folded inside
>    a union that now contains both new DW hw related variables as well
>    as old hardware related variables such as application reg base.
> 2. Added a dw_pcie_common_host_init() function that holds common
>    host initialization code for old and new hw.
> 3. dw_pcie_parse_resource() is used for parsing resource related
>    information from DT bindings.
> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>    Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>    Both these functions now call dw_pcie_common_host_init().
> 5. Some of the static functions are made global to allow use from
>    dw old pci drivers such as pci-keystone.
>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>---
> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
> 2 files changed, 103 insertions(+), 40 deletions(-)
>
>diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
>index c4e3732..9ea8e79 100644
>--- a/drivers/pci/host/pcie-designware.c
>+++ b/drivers/pci/host/pcie-designware.c
>@@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
> 		}
> 		set_bit(pos0 + i, pp->msi_irq_in_use);
> 		/*Enable corresponding interrupt in MSI interrupt controller */
>-		res = ((pos0 + i) / 32) * 12;
>-		bit = (pos0 + i) % 32;
>-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>-		val |= 1 << bit;
>-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>+		if (!(pp->version & DW_VERSION_OLD)) {
>+			res = ((pos0 + i) / 32) * 12;
>+			bit = (pos0 + i) % 32;
>+			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>+						 4, &val);
>+			val |= 1 << bit;
>+			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>+						 4, val);
>+		}
> 	}
>
> 	*pos = pos0;
>@@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev
>*pdev,
> 	 */
> 	desc->msi_attrib.multiple = msgvec;
>
>-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
>+	if (pp->ops->get_msi_data)
>+		msg.address_lo = pp->ops->get_msi_data(pp);
>+	else
>+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
> 	msg.address_hi = 0x0;
> 	msg.data = pos;
> 	write_msi_msg(irq, &msg);
>@@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
> 	.map = dw_pcie_msi_map,
> };
>
>-int __init dw_pcie_host_init(struct pcie_port *pp)
>+int __init dw_pcie_parse_resource(struct pcie_port *pp)
> {
> 	struct device_node *np = pp->dev->of_node;
>-	struct of_pci_range range;
> 	struct of_pci_range_parser parser;
>-	u32 val;
>-	int i;
>+	struct of_pci_range range;
>
> 	if (of_pci_range_parser_init(&parser, np)) {
> 		dev_err(pp->dev, "missing ranges property\n"); @@ -440,23 +445,17 @@ int
>__init dw_pcie_host_init(struct pcie_port *pp)
> 			return -ENOMEM;
> 		}
> 	}
>-
>-	pp->cfg0_base = pp->cfg.start;
>-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> 	pp->mem_base = pp->mem.start;
>
>-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>-					pp->config.cfg0_size);
>-	if (!pp->va_cfg0_base) {
>-		dev_err(pp->dev, "error with ioremap in function\n");
>-		return -ENOMEM;
>-	}
>-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>-					pp->config.cfg1_size);
>-	if (!pp->va_cfg1_base) {
>-		dev_err(pp->dev, "error with ioremap\n");
>-		return -ENOMEM;
>-	}
>+	return 0;
>+}
>+
>+int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>+				const struct irq_domain_ops *irq_msi_ops) {
>+	struct device_node *np = pp->dev->of_node;
>+	u32 val;
>+	int i;
>
> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
> 		dev_err(pp->dev, "Failed to parse the number of lanes\n"); @@ -465,7 +464,7
>@@ int __init dw_pcie_host_init(struct pcie_port *pp)
>
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
>-					MAX_MSI_IRQS, &msi_domain_ops,
>+					MAX_MSI_IRQS, irq_msi_ops,
> 					&dw_pcie_msi_chip);
> 		if (!pp->irq_domain) {
> 			dev_err(pp->dev, "irq domain init failed\n"); @@ -488,10 +487,10 @@
>int __init dw_pcie_host_init(struct pcie_port *pp)
> 	val |= PORT_LOGIC_SPEED_CHANGE;
> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>
>-	dw_pci.nr_controllers = 1;
>-	dw_pci.private_data = (void **)&pp;
>+	hw->nr_controllers = 1;
>+	hw->private_data = (void **)&pp;
>
>-	pci_common_init_dev(pp->dev, &dw_pci);
>+	pci_common_init_dev(pp->dev, hw);
> 	pci_assign_unassigned_resources();
> #ifdef CONFIG_PCI_DOMAINS
> 	dw_pci.domain++;
>@@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 	return 0;
> }
>
>+int __init dw_pcie_host_init(struct pcie_port *pp) {
>+	int ret;
>+
>+	ret = dw_pcie_parse_resource(pp);
>+	if (ret)
>+		return ret;
>+
>+	pp->cfg0_base = pp->cfg.start;
>+	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>+	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>+					pp->config.cfg0_size);
>+	if (!pp->va_cfg0_base) {
>+		dev_err(pp->dev, "error with ioremap in function\n");
>+		return -ENOMEM;
>+	}
>+	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>+					pp->config.cfg1_size);
>+	if (!pp->va_cfg1_base) {
>+		dev_err(pp->dev, "error with ioremap\n");
>+		return -ENOMEM;
>+	}
>+
>+	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops); }
>+
> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)  {
> 	/* Program viewport 0 : OUTBOUND : CFG0 */ @@ -654,7 +679,11 @@ static int
>dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
>
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
>-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>+		if (pp->ops->rd_other_conf)
>+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
>+						where, size, val);
>+		else
>+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_rd_own_conf(pp, where, size, val); @@ -680,7 +709,11 @@
>static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
>
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
>-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>+		if (pp->ops->wr_other_conf)
>+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
>+						where, size, val);
>+		else
>+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_wr_own_conf(pp, where, size, val); @@ -694,7 +727,7 @@
>static struct pci_ops dw_pcie_ops = {
> 	.write = dw_pcie_wr_conf,
> };
>
>-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> {
> 	struct pcie_port *pp;
>
>@@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> 	return 1;
> }
>
>-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> {
> 	struct pci_bus *bus;
> 	struct pcie_port *pp = sys_to_pcie(sys); @@ -746,7 +779,7 @@ static int
>dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> 	return irq;
> }
>
>-static void dw_pcie_add_bus(struct pci_bus *bus)
>+void dw_pcie_add_bus(struct pci_bus *bus)
> {
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata); diff --git
>a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
>index 3063b35..e97f4d7 100644
>--- a/drivers/pci/host/pcie-designware.h
>+++ b/drivers/pci/host/pcie-designware.h
>@@ -35,21 +35,39 @@ struct pcie_port {
> 	struct device		*dev;
> 	u8			root_bus_nr;
> 	void __iomem		*dbi_base;
>-	u64			cfg0_base;
>-	void __iomem		*va_cfg0_base;
>-	u64			cfg1_base;
>-	void __iomem		*va_cfg1_base;
>+	/*
>+	 * Old DW version implement application register space for
>+	 * MSI and has no ATU view port
>+	 */
>+#define DW_VERSION_OLD	BIT(0)
>+	u32			version;
>+	union {
>+		/* new dw core specific */
>+		struct {
>+			u64		cfg0_base;
>+			void __iomem	*va_cfg0_base;
>+			u64		cfg1_base;
>+			void __iomem	*va_cfg1_base;
>+			int		msi_irq;
>+		};
>+
>+		/* old dw core specific */
>+		struct  {
>+			struct irq_domain	*legacy_irq_domain;
>+			void __iomem		*va_app_base;
>+			u64			app_base;
>+		};
>+	};
> 	u64			io_base;
> 	u64			mem_base;
> 	spinlock_t		conf_lock;
>-	struct resource		cfg;
> 	struct resource		io;
> 	struct resource		mem;
>+	struct resource		cfg;
> 	struct pcie_port_info	config;
> 	int			irq;
> 	u32			lanes;
> 	struct pcie_host_ops	*ops;
>-	int			msi_irq;
> 	struct irq_domain	*irq_domain;
> 	unsigned long		msi_data;
> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); @@ -62,8 +80,13 @@ struct
>pcie_host_ops {
> 			u32 val, void __iomem *dbi_base);
> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
>+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>+			unsigned int devfn, int where, int size, u32 *val);
>+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>+			unsigned int devfn, int where, int size, u32 val);
> 	int (*link_up)(struct pcie_port *pp);
> 	void (*host_init)(struct pcie_port *pp);
>+	u32 (*get_msi_data)(struct pcie_port *pp);
> };
>
> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); @@ -73,5
>+96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);  int dw_pcie_link_up(struct
>pcie_port *pp);  void dw_pcie_setup_rc(struct pcie_port *pp);  int dw_pcie_host_init(struct
>pcie_port *pp);
>+int dw_pcie_setup(int nr, struct pci_sys_data *sys); struct pci_bus
>+*dw_pcie_scan_bus(int nr, struct pci_sys_data *sys); void
>+dw_pcie_add_bus(struct pci_bus *bus); int dw_pcie_parse_resource(struct
>+pcie_port *pp);
>
>+/* internal to dw core */
>+int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>+			const struct irq_domain_ops *irq_ops);
> #endif /* _PCIE_DESIGNWARE_H */
>--
>1.7.9.5

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

* RE: [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
  2014-05-15 16:01   ` Murali Karicheri
  (?)
@ 2014-05-16 20:47     ` Karicheri, Muralidharan
  -1 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:47 UTC (permalink / raw)
  To: Karicheri, Muralidharan, linux-kernel, linux-pci,
	linux-arm-kernel, pratyush.anand, r65037, ABRAHAM, KISHON VIJAY,
	marex
  Cc: Shilimkar, Santosh, Mohit Kumar, Jingoo Han, Bjorn Helgaas

Adding more people to the list for review.
>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:02 PM
>To: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org
>Cc: Karicheri, Muralidharan; Shilimkar, Santosh; Mohit Kumar; Jingoo Han; Bjorn Helgaas
>Subject: [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
>
>The older version of DW hw has application space registers for MSI controller and
>inbound/outbound access configuration. Also the legacy interrupt has registers in the
>application space. Drivers such as keystone pci uses these common functions to implement
>the driver.
>These are re-factored from the original driver to separate files to allow re-use for the next
>driver that is based on old dw pci hw such as that found on keystone.
>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>---
> drivers/pci/host/Kconfig          |    6 +-
> drivers/pci/host/Makefile         |    1 +
> drivers/pci/host/pci-dw-old-msi.c |  150 +++++++++++++++
> drivers/pci/host/pci-dw-old.c     |  371
>+++++++++++++++++++++++++++++++++++++
> drivers/pci/host/pci-dw-old.h     |   30 +++
> 5 files changed, 557 insertions(+), 1 deletion(-)  create mode 100644 drivers/pci/host/pci-
>dw-old-msi.c  create mode 100644 drivers/pci/host/pci-dw-old.c  create mode 100644
>drivers/pci/host/pci-dw-old.h
>
>diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index a6f67ec..c4f4732
>100644
>--- a/drivers/pci/host/Kconfig
>+++ b/drivers/pci/host/Kconfig
>@@ -9,6 +9,11 @@ config PCI_MVEBU
> config PCIE_DW
> 	bool
>
>+config PCI_DW_OLD
>+	bool "Designware Old PCIe h/w"
>+	help
>+	   Say Y here if the DW h/w is old version (3.65)
>+
> config PCI_EXYNOS
> 	bool "Samsung Exynos PCIe controller"
> 	depends on SOC_EXYNOS5440
>@@ -32,5 +37,4 @@ config PCI_RCAR_GEN2
> 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
> 	  There are 3 internal PCI controllers available with a single
> 	  built-in EHCI/OHCI host controller present on each one.
>-
> endmenu
>diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 13fb333..be5d939
>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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
>diff --git a/drivers/pci/host/pci-dw-old-msi.c b/drivers/pci/host/pci-dw-old-msi.c
>new file mode 100644
>index 0000000..450bb2f
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old-msi.c
>@@ -0,0 +1,150 @@
>+/*
>+ * Designware(dw) old MSI controller (v3.65 or similar)
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/of_irq.h>
>+#include <linux/kernel.h>
>+#include <linux/msi.h>
>+#include <linux/pci.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+#define MSI_IRQ				0x054
>+#define MSI0_IRQ_STATUS			0x104
>+#define MSI0_IRQ_ENABLE_SET		0x108
>+#define MSI0_IRQ_ENABLE_CLR		0x10c
>+#define IRQ_STATUS			0x184
>+#define IRQ_EOI                         0x050
>+#define MSI_IRQ_OFFSET			4
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
>+					u32 *bit_pos)
>+{
>+	*reg_offset = offset % 8;
>+	*bit_pos = offset >> 3;
>+}
>+
>+inline u32 dw_old_get_msi_data(struct pcie_port *pp) {
>+	return pp->app_base + MSI_IRQ;
>+}
>+
>+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset) {
>+	u32 pending, vector;
>+	int src, virq;
>+
>+	pending = readl(pp->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
>+	/*
>+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
>+	 * shows 1, 9, 17, 25 and so forth
>+	 */
>+	for (src = 0; src < 4; src++) {
>+		if (BIT(src) & pending) {
>+			vector = offset + (src << 3);
>+			virq = irq_linear_revmap(pp->irq_domain, vector);
>+			dev_dbg(pp->dev,
>+				"irq: bit %d, vector %d, virq %d\n",
>+				 src, vector, virq);
>+			generic_handle_irq(virq);
>+		}
>+	}
>+}
>+
>+static void dw_old_msi_irq_ack(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
>+	writel(reg_offset + MSI_IRQ_OFFSET, pp->va_app_base + IRQ_EOI); }
>+
>+static void dw_old_msi_irq_mask(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	/* mask the end point if PVM implemented */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		if (msi->msi_attrib.maskbit)
>+			mask_msi_irq(d);
>+	}
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4)); }
>+
>+static void dw_old_msi_irq_unmask(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	/* mask the end point if PVM implemented */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		if (msi->msi_attrib.maskbit)
>+			unmask_msi_irq(d);
>+	}
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4)); }
>+
>+static struct irq_chip dw_old_msi_chip = {
>+	.name = "PCI-DW-MSI-OLD",
>+	.irq_ack = dw_old_msi_irq_ack,
>+	.irq_mask = dw_old_msi_irq_mask,
>+	.irq_unmask = dw_old_msi_irq_unmask,
>+};
>+
>+static int dw_old_msi_map(struct irq_domain *domain, unsigned int irq,
>+			irq_hw_number_t hwirq)
>+{
>+	irq_set_chip_and_handler(irq, &dw_old_msi_chip, handle_level_irq);
>+	irq_set_chip_data(irq, domain->host_data);
>+	set_irq_flags(irq, IRQF_VALID);
>+
>+	return 0;
>+}
>+
>+const struct irq_domain_ops dw_old_msi_domain_ops = {
>+	.map = dw_old_msi_map,
>+};
>diff --git a/drivers/pci/host/pci-dw-old.c b/drivers/pci/host/pci-dw-old.c new file mode
>100644 index 0000000..b805013
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old.c
>@@ -0,0 +1,371 @@
>+/*
>+ * Designware(dw) old common functions (v3.65 or similar)
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/irq.h>
>+#include <linux/irqdomain.h>
>+#include <linux/module.h>
>+#include <linux/of_pci.h>
>+#include <linux/pci.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+/* Application register defines */
>+#define LTSSM_EN_VAL		        BIT(0)
>+#define LTSSM_STATE_MASK	        0x1f
>+#define LTSSM_STATE_L0		        0x11
>+#define DIR_SPD				(1 << 17)
>+#define DBI_CS2_EN_VAL		        BIT(5)
>+#define OB_XLAT_EN_VAL		        BIT(1)
>+
>+/* Application registers */
>+#define CMD_STATUS			0x004
>+#define CFG_SETUP			0x008
>+#define OB_SIZE				0x030
>+#define CFG_PCIM_WIN_SZ_IDX	        3
>+#define CFG_PCIM_WIN_CNT	        32
>+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
>+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
>+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
>+#define IRQ_EOI                         0x050
>+#define IRQ_STATUS			0x184
>+#define IRQ_ENABLE_SET			0x188
>+#define IRQ_ENABLE_CLR			0x18c
>+
>+/* Config space registers */
>+#define DEBUG0			        0x728
>+#define PL_GEN2			        0x80c
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+void dw_old_enable_legacy_irqs(struct pcie_port *pp) {
>+	int i;
>+
>+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
>+		writel(0x1, pp->va_app_base + IRQ_ENABLE_SET + (i << 4)); }
>+
>+void dw_old_handle_legacy_irq(struct pcie_port *pp, int offset) {
>+	u32 pending;
>+	int virq;
>+
>+	pending = readl(pp->va_app_base + IRQ_STATUS + (offset << 4));
>+
>+	if (BIT(0) & pending) {
>+		virq = irq_linear_revmap(pp->legacy_irq_domain, offset);
>+		dev_dbg(pp->dev,
>+			": irq: irq_offset %d, virq %d\n", offset, virq);
>+		generic_handle_irq(virq);
>+	}
>+
>+	/* EOI the INTx interrupt */
>+	writel(offset, pp->va_app_base + IRQ_EOI); }
>+
>+static void dw_old_ack_irq(struct irq_data *d) { }
>+
>+static void dw_old_mask_irq(struct irq_data *d) { }
>+
>+static void dw_old_unmask_irq(struct irq_data *d) { }
>+
>+struct irq_chip dw_old_legacy_irq_chip = {
>+	.name = "PCI-DW-LEGACY-old-irq",
>+	.irq_ack = dw_old_ack_irq,
>+	.irq_mask = dw_old_mask_irq,
>+	.irq_unmask = dw_old_unmask_irq,
>+};
>+
>+static int dw_old_init_legacy_irq_map(struct irq_domain *d, unsigned int irq,
>+				      irq_hw_number_t hw)
>+{
>+	irq_set_chip_and_handler(irq, &dw_old_legacy_irq_chip,
>+				handle_level_irq);
>+	irq_set_chip_data(irq, d->host_data);
>+	set_irq_flags(irq, IRQF_VALID);
>+
>+	return 0;
>+}
>+
>+static const struct irq_domain_ops dw_old_legacy_irq_domian_ops = {
>+	.map = dw_old_init_legacy_irq_map,
>+	.xlate = irq_domain_xlate_onetwocell,
>+};
>+
>+/**
>+ * dw_old_set_outbound_trans() - Set PHYADDR <-> BUSADDR
>+ * mapping for outbound
>+ */
>+void dw_old_setup_ob_regs(struct pcie_port *pp) {
>+	u32 start = pp->mem.start, end = pp->mem.end;
>+	int i, tr_size;
>+
>+	dev_dbg(pp->dev, "Setting outbound translation for %#x-%#x\n",
>+		start, end);
>+
>+	/* Set outbound translation size per window division */
>+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, pp->va_app_base + OB_SIZE);
>+
>+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
>+
>+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
>+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
>+		writel(start | 1, pp->va_app_base + OB_OFFSET_INDEX(i));
>+		writel(0, pp->va_app_base + OB_OFFSET_HI(i));
>+		start += tr_size;
>+	}
>+
>+	/* Enable OB translation */
>+	writel(OB_XLAT_EN_VAL | readl(pp->va_app_base + CMD_STATUS),
>+		pp->va_app_base + CMD_STATUS);
>+}
>+
>+/**
>+ * dw_old_set_dbi_mode() - Set DBI mode to access overlaid BAR mask
>+registers
>+ *
>+ * Since modification of dbi_cs2 involves different clock domain, read
>+the
>+ * status back to ensure the transition is complete.
>+ */
>+static inline void dw_old_set_dbi_mode(void __iomem *reg_virt) {
>+	u32 val;
>+
>+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
>+		     reg_virt + CMD_STATUS);
>+
>+	do {
>+		val = readl(reg_virt + CMD_STATUS);
>+	} while (!(val & DBI_CS2_EN_VAL));
>+}
>+
>+/**
>+ * dw_old_clear_dbi_mode() - Disable DBI mode
>+ *
>+ * Since modification of dbi_cs2 involves different clock domain, read
>+the
>+ * status back to ensure the transition is complete.
>+ */
>+static inline void dw_old_clear_dbi_mode(void __iomem *reg_virt) {
>+	u32 val;
>+
>+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
>+		     reg_virt + CMD_STATUS);
>+
>+	do {
>+		val = readl(reg_virt + CMD_STATUS);
>+	} while (val & DBI_CS2_EN_VAL);
>+}
>+
>+void dw_old_disable_bars(struct pcie_port *pp) {
>+	dw_old_set_dbi_mode(pp->va_app_base);
>+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
>+	dw_old_clear_dbi_mode(pp->va_app_base);
>+}
>+
>+/**
>+ * dw_old_setup_config_addr() - Set up configuration space address for
>+a
>+ * device
>+ *
>+ * @pp: ptr to pcie_port structure
>+ * @bus: Bus number the device is residing on
>+ * @device: Device number
>+ * @function: Function number in device
>+ *
>+ * Forms and returns the address of configuration space mapped in
>+PCIESS
>+ * address space 0. Also configures CFG_SETUP for remote configuration
>+space
>+ * access.
>+ *
>+ * The address space has two regions to access configuration - local and remote.
>+ * We access local region for bus 0 (as RC is attached on bus 0) and
>+remote
>+ * region for others with TYPE 1 access when bus > 1. As for device on
>+bus = 1,
>+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
>+ * CFG_SETUP is needed only for remote configuration access.
>+ */
>+static inline void __iomem *
>+dw_old_setup_config_addr(struct pcie_port *pp, u8 bus, u8 device, u8
>+function) {
>+	u32 regval;
>+
>+	if (bus == 0)
>+		return pp->dbi_base;
>+
>+	regval = (bus << 16) | (device << 8) | function;
>+	/*
>+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
>+	 * access only.
>+	 * TYPE 1
>+	 */
>+	if (bus != 1)
>+		regval |= BIT(24);
>+
>+	writel(regval, pp->va_app_base + CFG_SETUP);
>+
>+	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET; }
>+
>+int dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 *val) {
>+	u8 bus_num = bus->number;
>+	void __iomem *addr;
>+	int ret;
>+
>+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
>+				 PCI_FUNC(devfn));
>+
>+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
>+
>+	return ret;
>+}
>+
>+int dw_old_wr_other_conf(struct pcie_port *pp,
>+		struct pci_bus *bus, unsigned int devfn, int where,
>+		int size, u32 val)
>+{
>+	u8 bus_num = bus->number;
>+	void __iomem *addr;
>+
>+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
>+				PCI_FUNC(devfn));
>+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val); }
>+
>+/**
>+ * dw_old_set_ib_access() - Setup inbound access
>+ *
>+ * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
>+ * access to PCIESS application register space and just needs to set up
>+ * inbound address (mainly used for MSI).
>+ */
>+static void dw_old_set_ib_access(struct pcie_port *pp) {
>+	/* Configure and set up BAR0 */
>+	dw_old_set_dbi_mode(pp->va_app_base);
>+
>+	/* Enable BAR0 */
>+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+
>+	dw_old_clear_dbi_mode(pp->va_app_base);
>+	 /*
>+	  * For BAR0, just setting bus address for inbound writes (MSI) should
>+	  * be sufficient. Use physical address to avoid any conflicts.
>+	  */
>+	writel(pp->app_base, pp->dbi_base + PCI_BASE_ADDRESS_0); }
>+
>+/**
>+ * dw_old_pcie_scan_bus() - common function to scan bus
>+ *
>+ * common functin to scan old dw based pci bus. This also sets inbound
>+access
>+ * after scan.
>+ */
>+static struct pci_bus *dw_old_pcie_scan_bus(int nr, struct pci_sys_data
>+*sys) {
>+	struct pcie_port *pp = sys_to_pcie(sys);
>+	struct pci_bus *bus;
>+
>+	bus = dw_pcie_scan_bus(nr, sys);
>+	if (bus)
>+		dw_old_set_ib_access(pp);
>+
>+	return bus;
>+}
>+
>+/**
>+ * dw_old_pcie_link_up() - Check if link up
>+ *
>+ * optionally enable link train using link_train option and check if link is up.
>+ */
>+int dw_old_pcie_link_up(struct pcie_port *pp, int link_train) {
>+	u32 val;
>+
>+	if (link_train) {
>+		/*
>+		 * KeyStone devices do not support h/w autonomous
>+		 * link up-training to GEN2 from GEN1 in either EP/RC modes.
>+		 * The software needs to initiate speed change.
>+		 */
>+		val = readl(pp->dbi_base + PL_GEN2);
>+		writel(val | DIR_SPD, pp->dbi_base + PL_GEN2);
>+		/*
>+		 * Initiate Link Training. We will delay for L0 as specified by
>+		 * standard, but will still proceed and return success
>+		 * irrespective of L0 status as this will be handled by explicit
>+		 * L0 state checks during enumeration.
>+		 */
>+		val = readl(pp->va_app_base + CMD_STATUS);
>+		writel(LTSSM_EN_VAL | val,  pp->va_app_base + CMD_STATUS);
>+
>+	}
>+
>+	val = readl(pp->dbi_base + DEBUG0);
>+
>+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; }
>+
>+static struct hw_pci dw_old_pcie_hw = {
>+	.nr_controllers	= 1,
>+	.setup		= dw_pcie_setup,
>+	.scan		= dw_old_pcie_scan_bus,
>+	.swizzle        = pci_common_swizzle,
>+	.add_bus	= dw_pcie_add_bus,
>+	.map_irq	= of_irq_parse_and_map_pci,
>+};
>+
>+
>+/**
>+ * dw_old_pcie_host_init() - initialize host for old dw hardware
>+ *
>+ * Parse the pcie resources from DT bindings and then call common
>+ * dw function to do host initialization.
>+ */
>+int __init dw_old_pcie_host_init(struct pcie_port *pp, struct
>+device_node *np) {
>+	int ret;
>+
>+	if (!pp->va_app_base)
>+		return -EINVAL;
>+
>+	/* create legacy domain */
>+	pp->legacy_irq_domain = irq_domain_add_linear(np,
>+				MAX_LEGACY_IRQS,
>+				&dw_old_legacy_irq_domian_ops, NULL);
>+
>+	if (!pp->legacy_irq_domain) {
>+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
>+		return -EINVAL;
>+	}
>+
>+	ret = dw_pcie_parse_resource(pp);
>+	if (ret)
>+		return ret;
>+
>+	return dw_pcie_common_host_init(pp, &dw_old_pcie_hw,
>+					&dw_old_msi_domain_ops);
>+}
>diff --git a/drivers/pci/host/pci-dw-old.h b/drivers/pci/host/pci-dw-old.h new file mode
>100644 index 0000000..6e1af50
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old.h
>@@ -0,0 +1,30 @@
>+/*
>+ * Designware(dw) old MSI controller (v3.65 or similar) common includes
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#define MAX_LEGACY_IRQS		4
>+
>+extern const struct irq_domain_ops dw_old_msi_domain_ops;
>+
>+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset);
>+u32 dw_old_get_msi_data(struct pcie_port *pp); void
>+dw_old_enable_legacy_irqs(struct pcie_port *pp); void
>+dw_old_handle_legacy_irq(struct pcie_port *pp, int offset); int
>+dw_old_pcie_host_init(struct pcie_port *pp, struct device_node *np);
>+int dw_old_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 val); int
>+dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 *val); void
>+dw_old_disable_bars(struct pcie_port *pp); void
>+dw_old_setup_ob_regs(struct pcie_port *pp); int
>+dw_old_pcie_link_up(struct pcie_port *pp, int link_train);
>--
>1.7.9.5


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

* RE: [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
@ 2014-05-16 20:47     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:47 UTC (permalink / raw)
  To: Karicheri, Muralidharan, linux-kernel, linux-pci,
	linux-arm-kernel, pratyush.anand, r65037, ABRAHAM, KISHON VIJAY,
	marex
  Cc: Shilimkar, Santosh, Mohit Kumar, Jingoo Han, Bjorn Helgaas

Adding more people to the list for review.
>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:02 PM
>To: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org
>Cc: Karicheri, Muralidharan; Shilimkar, Santosh; Mohit Kumar; Jingoo Han; Bjorn Helgaas
>Subject: [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
>
>The older version of DW hw has application space registers for MSI controller and
>inbound/outbound access configuration. Also the legacy interrupt has registers in the
>application space. Drivers such as keystone pci uses these common functions to implement
>the driver.
>These are re-factored from the original driver to separate files to allow re-use for the next
>driver that is based on old dw pci hw such as that found on keystone.
>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>---
> drivers/pci/host/Kconfig          |    6 +-
> drivers/pci/host/Makefile         |    1 +
> drivers/pci/host/pci-dw-old-msi.c |  150 +++++++++++++++
> drivers/pci/host/pci-dw-old.c     |  371
>+++++++++++++++++++++++++++++++++++++
> drivers/pci/host/pci-dw-old.h     |   30 +++
> 5 files changed, 557 insertions(+), 1 deletion(-)  create mode 100644 drivers/pci/host/pci-
>dw-old-msi.c  create mode 100644 drivers/pci/host/pci-dw-old.c  create mode 100644
>drivers/pci/host/pci-dw-old.h
>
>diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index a6f67ec..c4f4732
>100644
>--- a/drivers/pci/host/Kconfig
>+++ b/drivers/pci/host/Kconfig
>@@ -9,6 +9,11 @@ config PCI_MVEBU
> config PCIE_DW
> 	bool
>
>+config PCI_DW_OLD
>+	bool "Designware Old PCIe h/w"
>+	help
>+	   Say Y here if the DW h/w is old version (3.65)
>+
> config PCI_EXYNOS
> 	bool "Samsung Exynos PCIe controller"
> 	depends on SOC_EXYNOS5440
>@@ -32,5 +37,4 @@ config PCI_RCAR_GEN2
> 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
> 	  There are 3 internal PCI controllers available with a single
> 	  built-in EHCI/OHCI host controller present on each one.
>-
> endmenu
>diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 13fb333..be5d939
>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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
>diff --git a/drivers/pci/host/pci-dw-old-msi.c b/drivers/pci/host/pci-dw-old-msi.c
>new file mode 100644
>index 0000000..450bb2f
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old-msi.c
>@@ -0,0 +1,150 @@
>+/*
>+ * Designware(dw) old MSI controller (v3.65 or similar)
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/of_irq.h>
>+#include <linux/kernel.h>
>+#include <linux/msi.h>
>+#include <linux/pci.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+#define MSI_IRQ				0x054
>+#define MSI0_IRQ_STATUS			0x104
>+#define MSI0_IRQ_ENABLE_SET		0x108
>+#define MSI0_IRQ_ENABLE_CLR		0x10c
>+#define IRQ_STATUS			0x184
>+#define IRQ_EOI                         0x050
>+#define MSI_IRQ_OFFSET			4
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
>+					u32 *bit_pos)
>+{
>+	*reg_offset = offset % 8;
>+	*bit_pos = offset >> 3;
>+}
>+
>+inline u32 dw_old_get_msi_data(struct pcie_port *pp) {
>+	return pp->app_base + MSI_IRQ;
>+}
>+
>+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset) {
>+	u32 pending, vector;
>+	int src, virq;
>+
>+	pending = readl(pp->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
>+	/*
>+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
>+	 * shows 1, 9, 17, 25 and so forth
>+	 */
>+	for (src = 0; src < 4; src++) {
>+		if (BIT(src) & pending) {
>+			vector = offset + (src << 3);
>+			virq = irq_linear_revmap(pp->irq_domain, vector);
>+			dev_dbg(pp->dev,
>+				"irq: bit %d, vector %d, virq %d\n",
>+				 src, vector, virq);
>+			generic_handle_irq(virq);
>+		}
>+	}
>+}
>+
>+static void dw_old_msi_irq_ack(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
>+	writel(reg_offset + MSI_IRQ_OFFSET, pp->va_app_base + IRQ_EOI); }
>+
>+static void dw_old_msi_irq_mask(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	/* mask the end point if PVM implemented */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		if (msi->msi_attrib.maskbit)
>+			mask_msi_irq(d);
>+	}
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4)); }
>+
>+static void dw_old_msi_irq_unmask(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	/* mask the end point if PVM implemented */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		if (msi->msi_attrib.maskbit)
>+			unmask_msi_irq(d);
>+	}
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4)); }
>+
>+static struct irq_chip dw_old_msi_chip = {
>+	.name = "PCI-DW-MSI-OLD",
>+	.irq_ack = dw_old_msi_irq_ack,
>+	.irq_mask = dw_old_msi_irq_mask,
>+	.irq_unmask = dw_old_msi_irq_unmask,
>+};
>+
>+static int dw_old_msi_map(struct irq_domain *domain, unsigned int irq,
>+			irq_hw_number_t hwirq)
>+{
>+	irq_set_chip_and_handler(irq, &dw_old_msi_chip, handle_level_irq);
>+	irq_set_chip_data(irq, domain->host_data);
>+	set_irq_flags(irq, IRQF_VALID);
>+
>+	return 0;
>+}
>+
>+const struct irq_domain_ops dw_old_msi_domain_ops = {
>+	.map = dw_old_msi_map,
>+};
>diff --git a/drivers/pci/host/pci-dw-old.c b/drivers/pci/host/pci-dw-old.c new file mode
>100644 index 0000000..b805013
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old.c
>@@ -0,0 +1,371 @@
>+/*
>+ * Designware(dw) old common functions (v3.65 or similar)
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/irq.h>
>+#include <linux/irqdomain.h>
>+#include <linux/module.h>
>+#include <linux/of_pci.h>
>+#include <linux/pci.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+/* Application register defines */
>+#define LTSSM_EN_VAL		        BIT(0)
>+#define LTSSM_STATE_MASK	        0x1f
>+#define LTSSM_STATE_L0		        0x11
>+#define DIR_SPD				(1 << 17)
>+#define DBI_CS2_EN_VAL		        BIT(5)
>+#define OB_XLAT_EN_VAL		        BIT(1)
>+
>+/* Application registers */
>+#define CMD_STATUS			0x004
>+#define CFG_SETUP			0x008
>+#define OB_SIZE				0x030
>+#define CFG_PCIM_WIN_SZ_IDX	        3
>+#define CFG_PCIM_WIN_CNT	        32
>+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
>+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
>+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
>+#define IRQ_EOI                         0x050
>+#define IRQ_STATUS			0x184
>+#define IRQ_ENABLE_SET			0x188
>+#define IRQ_ENABLE_CLR			0x18c
>+
>+/* Config space registers */
>+#define DEBUG0			        0x728
>+#define PL_GEN2			        0x80c
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+void dw_old_enable_legacy_irqs(struct pcie_port *pp) {
>+	int i;
>+
>+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
>+		writel(0x1, pp->va_app_base + IRQ_ENABLE_SET + (i << 4)); }
>+
>+void dw_old_handle_legacy_irq(struct pcie_port *pp, int offset) {
>+	u32 pending;
>+	int virq;
>+
>+	pending = readl(pp->va_app_base + IRQ_STATUS + (offset << 4));
>+
>+	if (BIT(0) & pending) {
>+		virq = irq_linear_revmap(pp->legacy_irq_domain, offset);
>+		dev_dbg(pp->dev,
>+			": irq: irq_offset %d, virq %d\n", offset, virq);
>+		generic_handle_irq(virq);
>+	}
>+
>+	/* EOI the INTx interrupt */
>+	writel(offset, pp->va_app_base + IRQ_EOI); }
>+
>+static void dw_old_ack_irq(struct irq_data *d) { }
>+
>+static void dw_old_mask_irq(struct irq_data *d) { }
>+
>+static void dw_old_unmask_irq(struct irq_data *d) { }
>+
>+struct irq_chip dw_old_legacy_irq_chip = {
>+	.name = "PCI-DW-LEGACY-old-irq",
>+	.irq_ack = dw_old_ack_irq,
>+	.irq_mask = dw_old_mask_irq,
>+	.irq_unmask = dw_old_unmask_irq,
>+};
>+
>+static int dw_old_init_legacy_irq_map(struct irq_domain *d, unsigned int irq,
>+				      irq_hw_number_t hw)
>+{
>+	irq_set_chip_and_handler(irq, &dw_old_legacy_irq_chip,
>+				handle_level_irq);
>+	irq_set_chip_data(irq, d->host_data);
>+	set_irq_flags(irq, IRQF_VALID);
>+
>+	return 0;
>+}
>+
>+static const struct irq_domain_ops dw_old_legacy_irq_domian_ops = {
>+	.map = dw_old_init_legacy_irq_map,
>+	.xlate = irq_domain_xlate_onetwocell,
>+};
>+
>+/**
>+ * dw_old_set_outbound_trans() - Set PHYADDR <-> BUSADDR
>+ * mapping for outbound
>+ */
>+void dw_old_setup_ob_regs(struct pcie_port *pp) {
>+	u32 start = pp->mem.start, end = pp->mem.end;
>+	int i, tr_size;
>+
>+	dev_dbg(pp->dev, "Setting outbound translation for %#x-%#x\n",
>+		start, end);
>+
>+	/* Set outbound translation size per window division */
>+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, pp->va_app_base + OB_SIZE);
>+
>+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
>+
>+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
>+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
>+		writel(start | 1, pp->va_app_base + OB_OFFSET_INDEX(i));
>+		writel(0, pp->va_app_base + OB_OFFSET_HI(i));
>+		start += tr_size;
>+	}
>+
>+	/* Enable OB translation */
>+	writel(OB_XLAT_EN_VAL | readl(pp->va_app_base + CMD_STATUS),
>+		pp->va_app_base + CMD_STATUS);
>+}
>+
>+/**
>+ * dw_old_set_dbi_mode() - Set DBI mode to access overlaid BAR mask
>+registers
>+ *
>+ * Since modification of dbi_cs2 involves different clock domain, read
>+the
>+ * status back to ensure the transition is complete.
>+ */
>+static inline void dw_old_set_dbi_mode(void __iomem *reg_virt) {
>+	u32 val;
>+
>+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
>+		     reg_virt + CMD_STATUS);
>+
>+	do {
>+		val = readl(reg_virt + CMD_STATUS);
>+	} while (!(val & DBI_CS2_EN_VAL));
>+}
>+
>+/**
>+ * dw_old_clear_dbi_mode() - Disable DBI mode
>+ *
>+ * Since modification of dbi_cs2 involves different clock domain, read
>+the
>+ * status back to ensure the transition is complete.
>+ */
>+static inline void dw_old_clear_dbi_mode(void __iomem *reg_virt) {
>+	u32 val;
>+
>+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
>+		     reg_virt + CMD_STATUS);
>+
>+	do {
>+		val = readl(reg_virt + CMD_STATUS);
>+	} while (val & DBI_CS2_EN_VAL);
>+}
>+
>+void dw_old_disable_bars(struct pcie_port *pp) {
>+	dw_old_set_dbi_mode(pp->va_app_base);
>+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
>+	dw_old_clear_dbi_mode(pp->va_app_base);
>+}
>+
>+/**
>+ * dw_old_setup_config_addr() - Set up configuration space address for
>+a
>+ * device
>+ *
>+ * @pp: ptr to pcie_port structure
>+ * @bus: Bus number the device is residing on
>+ * @device: Device number
>+ * @function: Function number in device
>+ *
>+ * Forms and returns the address of configuration space mapped in
>+PCIESS
>+ * address space 0. Also configures CFG_SETUP for remote configuration
>+space
>+ * access.
>+ *
>+ * The address space has two regions to access configuration - local and remote.
>+ * We access local region for bus 0 (as RC is attached on bus 0) and
>+remote
>+ * region for others with TYPE 1 access when bus > 1. As for device on
>+bus = 1,
>+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
>+ * CFG_SETUP is needed only for remote configuration access.
>+ */
>+static inline void __iomem *
>+dw_old_setup_config_addr(struct pcie_port *pp, u8 bus, u8 device, u8
>+function) {
>+	u32 regval;
>+
>+	if (bus == 0)
>+		return pp->dbi_base;
>+
>+	regval = (bus << 16) | (device << 8) | function;
>+	/*
>+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
>+	 * access only.
>+	 * TYPE 1
>+	 */
>+	if (bus != 1)
>+		regval |= BIT(24);
>+
>+	writel(regval, pp->va_app_base + CFG_SETUP);
>+
>+	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET; }
>+
>+int dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 *val) {
>+	u8 bus_num = bus->number;
>+	void __iomem *addr;
>+	int ret;
>+
>+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
>+				 PCI_FUNC(devfn));
>+
>+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
>+
>+	return ret;
>+}
>+
>+int dw_old_wr_other_conf(struct pcie_port *pp,
>+		struct pci_bus *bus, unsigned int devfn, int where,
>+		int size, u32 val)
>+{
>+	u8 bus_num = bus->number;
>+	void __iomem *addr;
>+
>+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
>+				PCI_FUNC(devfn));
>+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val); }
>+
>+/**
>+ * dw_old_set_ib_access() - Setup inbound access
>+ *
>+ * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
>+ * access to PCIESS application register space and just needs to set up
>+ * inbound address (mainly used for MSI).
>+ */
>+static void dw_old_set_ib_access(struct pcie_port *pp) {
>+	/* Configure and set up BAR0 */
>+	dw_old_set_dbi_mode(pp->va_app_base);
>+
>+	/* Enable BAR0 */
>+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+
>+	dw_old_clear_dbi_mode(pp->va_app_base);
>+	 /*
>+	  * For BAR0, just setting bus address for inbound writes (MSI) should
>+	  * be sufficient. Use physical address to avoid any conflicts.
>+	  */
>+	writel(pp->app_base, pp->dbi_base + PCI_BASE_ADDRESS_0); }
>+
>+/**
>+ * dw_old_pcie_scan_bus() - common function to scan bus
>+ *
>+ * common functin to scan old dw based pci bus. This also sets inbound
>+access
>+ * after scan.
>+ */
>+static struct pci_bus *dw_old_pcie_scan_bus(int nr, struct pci_sys_data
>+*sys) {
>+	struct pcie_port *pp = sys_to_pcie(sys);
>+	struct pci_bus *bus;
>+
>+	bus = dw_pcie_scan_bus(nr, sys);
>+	if (bus)
>+		dw_old_set_ib_access(pp);
>+
>+	return bus;
>+}
>+
>+/**
>+ * dw_old_pcie_link_up() - Check if link up
>+ *
>+ * optionally enable link train using link_train option and check if link is up.
>+ */
>+int dw_old_pcie_link_up(struct pcie_port *pp, int link_train) {
>+	u32 val;
>+
>+	if (link_train) {
>+		/*
>+		 * KeyStone devices do not support h/w autonomous
>+		 * link up-training to GEN2 from GEN1 in either EP/RC modes.
>+		 * The software needs to initiate speed change.
>+		 */
>+		val = readl(pp->dbi_base + PL_GEN2);
>+		writel(val | DIR_SPD, pp->dbi_base + PL_GEN2);
>+		/*
>+		 * Initiate Link Training. We will delay for L0 as specified by
>+		 * standard, but will still proceed and return success
>+		 * irrespective of L0 status as this will be handled by explicit
>+		 * L0 state checks during enumeration.
>+		 */
>+		val = readl(pp->va_app_base + CMD_STATUS);
>+		writel(LTSSM_EN_VAL | val,  pp->va_app_base + CMD_STATUS);
>+
>+	}
>+
>+	val = readl(pp->dbi_base + DEBUG0);
>+
>+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; }
>+
>+static struct hw_pci dw_old_pcie_hw = {
>+	.nr_controllers	= 1,
>+	.setup		= dw_pcie_setup,
>+	.scan		= dw_old_pcie_scan_bus,
>+	.swizzle        = pci_common_swizzle,
>+	.add_bus	= dw_pcie_add_bus,
>+	.map_irq	= of_irq_parse_and_map_pci,
>+};
>+
>+
>+/**
>+ * dw_old_pcie_host_init() - initialize host for old dw hardware
>+ *
>+ * Parse the pcie resources from DT bindings and then call common
>+ * dw function to do host initialization.
>+ */
>+int __init dw_old_pcie_host_init(struct pcie_port *pp, struct
>+device_node *np) {
>+	int ret;
>+
>+	if (!pp->va_app_base)
>+		return -EINVAL;
>+
>+	/* create legacy domain */
>+	pp->legacy_irq_domain = irq_domain_add_linear(np,
>+				MAX_LEGACY_IRQS,
>+				&dw_old_legacy_irq_domian_ops, NULL);
>+
>+	if (!pp->legacy_irq_domain) {
>+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
>+		return -EINVAL;
>+	}
>+
>+	ret = dw_pcie_parse_resource(pp);
>+	if (ret)
>+		return ret;
>+
>+	return dw_pcie_common_host_init(pp, &dw_old_pcie_hw,
>+					&dw_old_msi_domain_ops);
>+}
>diff --git a/drivers/pci/host/pci-dw-old.h b/drivers/pci/host/pci-dw-old.h new file mode
>100644 index 0000000..6e1af50
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old.h
>@@ -0,0 +1,30 @@
>+/*
>+ * Designware(dw) old MSI controller (v3.65 or similar) common includes
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#define MAX_LEGACY_IRQS		4
>+
>+extern const struct irq_domain_ops dw_old_msi_domain_ops;
>+
>+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset);
>+u32 dw_old_get_msi_data(struct pcie_port *pp); void
>+dw_old_enable_legacy_irqs(struct pcie_port *pp); void
>+dw_old_handle_legacy_irq(struct pcie_port *pp, int offset); int
>+dw_old_pcie_host_init(struct pcie_port *pp, struct device_node *np);
>+int dw_old_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 val); int
>+dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 *val); void
>+dw_old_disable_bars(struct pcie_port *pp); void
>+dw_old_setup_ob_regs(struct pcie_port *pp); int
>+dw_old_pcie_link_up(struct pcie_port *pp, int link_train);
>--
>1.7.9.5


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

* [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
@ 2014-05-16 20:47     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:47 UTC (permalink / raw)
  To: linux-arm-kernel

Adding more people to the list for review.
>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:02 PM
>To: linux-kernel at vger.kernel.org; linux-pci at vger.kernel.org; linux-arm-
>kernel at lists.infradead.org
>Cc: Karicheri, Muralidharan; Shilimkar, Santosh; Mohit Kumar; Jingoo Han; Bjorn Helgaas
>Subject: [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver
>
>The older version of DW hw has application space registers for MSI controller and
>inbound/outbound access configuration. Also the legacy interrupt has registers in the
>application space. Drivers such as keystone pci uses these common functions to implement
>the driver.
>These are re-factored from the original driver to separate files to allow re-use for the next
>driver that is based on old dw pci hw such as that found on keystone.
>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>---
> drivers/pci/host/Kconfig          |    6 +-
> drivers/pci/host/Makefile         |    1 +
> drivers/pci/host/pci-dw-old-msi.c |  150 +++++++++++++++
> drivers/pci/host/pci-dw-old.c     |  371
>+++++++++++++++++++++++++++++++++++++
> drivers/pci/host/pci-dw-old.h     |   30 +++
> 5 files changed, 557 insertions(+), 1 deletion(-)  create mode 100644 drivers/pci/host/pci-
>dw-old-msi.c  create mode 100644 drivers/pci/host/pci-dw-old.c  create mode 100644
>drivers/pci/host/pci-dw-old.h
>
>diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index a6f67ec..c4f4732
>100644
>--- a/drivers/pci/host/Kconfig
>+++ b/drivers/pci/host/Kconfig
>@@ -9,6 +9,11 @@ config PCI_MVEBU
> config PCIE_DW
> 	bool
>
>+config PCI_DW_OLD
>+	bool "Designware Old PCIe h/w"
>+	help
>+	   Say Y here if the DW h/w is old version (3.65)
>+
> config PCI_EXYNOS
> 	bool "Samsung Exynos PCIe controller"
> 	depends on SOC_EXYNOS5440
>@@ -32,5 +37,4 @@ config PCI_RCAR_GEN2
> 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
> 	  There are 3 internal PCI controllers available with a single
> 	  built-in EHCI/OHCI host controller present on each one.
>-
> endmenu
>diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 13fb333..be5d939
>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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
>diff --git a/drivers/pci/host/pci-dw-old-msi.c b/drivers/pci/host/pci-dw-old-msi.c
>new file mode 100644
>index 0000000..450bb2f
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old-msi.c
>@@ -0,0 +1,150 @@
>+/*
>+ * Designware(dw) old MSI controller (v3.65 or similar)
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/of_irq.h>
>+#include <linux/kernel.h>
>+#include <linux/msi.h>
>+#include <linux/pci.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+#define MSI_IRQ				0x054
>+#define MSI0_IRQ_STATUS			0x104
>+#define MSI0_IRQ_ENABLE_SET		0x108
>+#define MSI0_IRQ_ENABLE_CLR		0x10c
>+#define IRQ_STATUS			0x184
>+#define IRQ_EOI                         0x050
>+#define MSI_IRQ_OFFSET			4
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
>+					u32 *bit_pos)
>+{
>+	*reg_offset = offset % 8;
>+	*bit_pos = offset >> 3;
>+}
>+
>+inline u32 dw_old_get_msi_data(struct pcie_port *pp) {
>+	return pp->app_base + MSI_IRQ;
>+}
>+
>+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset) {
>+	u32 pending, vector;
>+	int src, virq;
>+
>+	pending = readl(pp->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
>+	/*
>+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
>+	 * shows 1, 9, 17, 25 and so forth
>+	 */
>+	for (src = 0; src < 4; src++) {
>+		if (BIT(src) & pending) {
>+			vector = offset + (src << 3);
>+			virq = irq_linear_revmap(pp->irq_domain, vector);
>+			dev_dbg(pp->dev,
>+				"irq: bit %d, vector %d, virq %d\n",
>+				 src, vector, virq);
>+			generic_handle_irq(virq);
>+		}
>+	}
>+}
>+
>+static void dw_old_msi_irq_ack(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
>+	writel(reg_offset + MSI_IRQ_OFFSET, pp->va_app_base + IRQ_EOI); }
>+
>+static void dw_old_msi_irq_mask(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	/* mask the end point if PVM implemented */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		if (msi->msi_attrib.maskbit)
>+			mask_msi_irq(d);
>+	}
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4)); }
>+
>+static void dw_old_msi_irq_unmask(struct irq_data *d) {
>+	u32 offset, reg_offset, bit_pos;
>+	unsigned int irq = d->irq;
>+	struct msi_desc *msi;
>+	struct pcie_port *pp;
>+
>+	msi = irq_get_msi_desc(irq);
>+	pp = sys_to_pcie(msi->dev->bus->sysdata);
>+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
>+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
>+
>+	/* mask the end point if PVM implemented */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		if (msi->msi_attrib.maskbit)
>+			unmask_msi_irq(d);
>+	}
>+
>+	writel(BIT(bit_pos),
>+		pp->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4)); }
>+
>+static struct irq_chip dw_old_msi_chip = {
>+	.name = "PCI-DW-MSI-OLD",
>+	.irq_ack = dw_old_msi_irq_ack,
>+	.irq_mask = dw_old_msi_irq_mask,
>+	.irq_unmask = dw_old_msi_irq_unmask,
>+};
>+
>+static int dw_old_msi_map(struct irq_domain *domain, unsigned int irq,
>+			irq_hw_number_t hwirq)
>+{
>+	irq_set_chip_and_handler(irq, &dw_old_msi_chip, handle_level_irq);
>+	irq_set_chip_data(irq, domain->host_data);
>+	set_irq_flags(irq, IRQF_VALID);
>+
>+	return 0;
>+}
>+
>+const struct irq_domain_ops dw_old_msi_domain_ops = {
>+	.map = dw_old_msi_map,
>+};
>diff --git a/drivers/pci/host/pci-dw-old.c b/drivers/pci/host/pci-dw-old.c new file mode
>100644 index 0000000..b805013
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old.c
>@@ -0,0 +1,371 @@
>+/*
>+ * Designware(dw) old common functions (v3.65 or similar)
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/irq.h>
>+#include <linux/irqdomain.h>
>+#include <linux/module.h>
>+#include <linux/of_pci.h>
>+#include <linux/pci.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+/* Application register defines */
>+#define LTSSM_EN_VAL		        BIT(0)
>+#define LTSSM_STATE_MASK	        0x1f
>+#define LTSSM_STATE_L0		        0x11
>+#define DIR_SPD				(1 << 17)
>+#define DBI_CS2_EN_VAL		        BIT(5)
>+#define OB_XLAT_EN_VAL		        BIT(1)
>+
>+/* Application registers */
>+#define CMD_STATUS			0x004
>+#define CFG_SETUP			0x008
>+#define OB_SIZE				0x030
>+#define CFG_PCIM_WIN_SZ_IDX	        3
>+#define CFG_PCIM_WIN_CNT	        32
>+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
>+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
>+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
>+#define IRQ_EOI                         0x050
>+#define IRQ_STATUS			0x184
>+#define IRQ_ENABLE_SET			0x188
>+#define IRQ_ENABLE_CLR			0x18c
>+
>+/* Config space registers */
>+#define DEBUG0			        0x728
>+#define PL_GEN2			        0x80c
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+void dw_old_enable_legacy_irqs(struct pcie_port *pp) {
>+	int i;
>+
>+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
>+		writel(0x1, pp->va_app_base + IRQ_ENABLE_SET + (i << 4)); }
>+
>+void dw_old_handle_legacy_irq(struct pcie_port *pp, int offset) {
>+	u32 pending;
>+	int virq;
>+
>+	pending = readl(pp->va_app_base + IRQ_STATUS + (offset << 4));
>+
>+	if (BIT(0) & pending) {
>+		virq = irq_linear_revmap(pp->legacy_irq_domain, offset);
>+		dev_dbg(pp->dev,
>+			": irq: irq_offset %d, virq %d\n", offset, virq);
>+		generic_handle_irq(virq);
>+	}
>+
>+	/* EOI the INTx interrupt */
>+	writel(offset, pp->va_app_base + IRQ_EOI); }
>+
>+static void dw_old_ack_irq(struct irq_data *d) { }
>+
>+static void dw_old_mask_irq(struct irq_data *d) { }
>+
>+static void dw_old_unmask_irq(struct irq_data *d) { }
>+
>+struct irq_chip dw_old_legacy_irq_chip = {
>+	.name = "PCI-DW-LEGACY-old-irq",
>+	.irq_ack = dw_old_ack_irq,
>+	.irq_mask = dw_old_mask_irq,
>+	.irq_unmask = dw_old_unmask_irq,
>+};
>+
>+static int dw_old_init_legacy_irq_map(struct irq_domain *d, unsigned int irq,
>+				      irq_hw_number_t hw)
>+{
>+	irq_set_chip_and_handler(irq, &dw_old_legacy_irq_chip,
>+				handle_level_irq);
>+	irq_set_chip_data(irq, d->host_data);
>+	set_irq_flags(irq, IRQF_VALID);
>+
>+	return 0;
>+}
>+
>+static const struct irq_domain_ops dw_old_legacy_irq_domian_ops = {
>+	.map = dw_old_init_legacy_irq_map,
>+	.xlate = irq_domain_xlate_onetwocell,
>+};
>+
>+/**
>+ * dw_old_set_outbound_trans() - Set PHYADDR <-> BUSADDR
>+ * mapping for outbound
>+ */
>+void dw_old_setup_ob_regs(struct pcie_port *pp) {
>+	u32 start = pp->mem.start, end = pp->mem.end;
>+	int i, tr_size;
>+
>+	dev_dbg(pp->dev, "Setting outbound translation for %#x-%#x\n",
>+		start, end);
>+
>+	/* Set outbound translation size per window division */
>+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, pp->va_app_base + OB_SIZE);
>+
>+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
>+
>+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
>+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
>+		writel(start | 1, pp->va_app_base + OB_OFFSET_INDEX(i));
>+		writel(0, pp->va_app_base + OB_OFFSET_HI(i));
>+		start += tr_size;
>+	}
>+
>+	/* Enable OB translation */
>+	writel(OB_XLAT_EN_VAL | readl(pp->va_app_base + CMD_STATUS),
>+		pp->va_app_base + CMD_STATUS);
>+}
>+
>+/**
>+ * dw_old_set_dbi_mode() - Set DBI mode to access overlaid BAR mask
>+registers
>+ *
>+ * Since modification of dbi_cs2 involves different clock domain, read
>+the
>+ * status back to ensure the transition is complete.
>+ */
>+static inline void dw_old_set_dbi_mode(void __iomem *reg_virt) {
>+	u32 val;
>+
>+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
>+		     reg_virt + CMD_STATUS);
>+
>+	do {
>+		val = readl(reg_virt + CMD_STATUS);
>+	} while (!(val & DBI_CS2_EN_VAL));
>+}
>+
>+/**
>+ * dw_old_clear_dbi_mode() - Disable DBI mode
>+ *
>+ * Since modification of dbi_cs2 involves different clock domain, read
>+the
>+ * status back to ensure the transition is complete.
>+ */
>+static inline void dw_old_clear_dbi_mode(void __iomem *reg_virt) {
>+	u32 val;
>+
>+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
>+		     reg_virt + CMD_STATUS);
>+
>+	do {
>+		val = readl(reg_virt + CMD_STATUS);
>+	} while (val & DBI_CS2_EN_VAL);
>+}
>+
>+void dw_old_disable_bars(struct pcie_port *pp) {
>+	dw_old_set_dbi_mode(pp->va_app_base);
>+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
>+	dw_old_clear_dbi_mode(pp->va_app_base);
>+}
>+
>+/**
>+ * dw_old_setup_config_addr() - Set up configuration space address for
>+a
>+ * device
>+ *
>+ * @pp: ptr to pcie_port structure
>+ * @bus: Bus number the device is residing on
>+ * @device: Device number
>+ * @function: Function number in device
>+ *
>+ * Forms and returns the address of configuration space mapped in
>+PCIESS
>+ * address space 0. Also configures CFG_SETUP for remote configuration
>+space
>+ * access.
>+ *
>+ * The address space has two regions to access configuration - local and remote.
>+ * We access local region for bus 0 (as RC is attached on bus 0) and
>+remote
>+ * region for others with TYPE 1 access when bus > 1. As for device on
>+bus = 1,
>+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
>+ * CFG_SETUP is needed only for remote configuration access.
>+ */
>+static inline void __iomem *
>+dw_old_setup_config_addr(struct pcie_port *pp, u8 bus, u8 device, u8
>+function) {
>+	u32 regval;
>+
>+	if (bus == 0)
>+		return pp->dbi_base;
>+
>+	regval = (bus << 16) | (device << 8) | function;
>+	/*
>+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
>+	 * access only.
>+	 * TYPE 1
>+	 */
>+	if (bus != 1)
>+		regval |= BIT(24);
>+
>+	writel(regval, pp->va_app_base + CFG_SETUP);
>+
>+	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET; }
>+
>+int dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 *val) {
>+	u8 bus_num = bus->number;
>+	void __iomem *addr;
>+	int ret;
>+
>+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
>+				 PCI_FUNC(devfn));
>+
>+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
>+
>+	return ret;
>+}
>+
>+int dw_old_wr_other_conf(struct pcie_port *pp,
>+		struct pci_bus *bus, unsigned int devfn, int where,
>+		int size, u32 val)
>+{
>+	u8 bus_num = bus->number;
>+	void __iomem *addr;
>+
>+	addr = dw_old_setup_config_addr(pp, bus_num, PCI_SLOT(devfn),
>+				PCI_FUNC(devfn));
>+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val); }
>+
>+/**
>+ * dw_old_set_ib_access() - Setup inbound access
>+ *
>+ * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
>+ * access to PCIESS application register space and just needs to set up
>+ * inbound address (mainly used for MSI).
>+ */
>+static void dw_old_set_ib_access(struct pcie_port *pp) {
>+	/* Configure and set up BAR0 */
>+	dw_old_set_dbi_mode(pp->va_app_base);
>+
>+	/* Enable BAR0 */
>+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
>+
>+	dw_old_clear_dbi_mode(pp->va_app_base);
>+	 /*
>+	  * For BAR0, just setting bus address for inbound writes (MSI) should
>+	  * be sufficient. Use physical address to avoid any conflicts.
>+	  */
>+	writel(pp->app_base, pp->dbi_base + PCI_BASE_ADDRESS_0); }
>+
>+/**
>+ * dw_old_pcie_scan_bus() - common function to scan bus
>+ *
>+ * common functin to scan old dw based pci bus. This also sets inbound
>+access
>+ * after scan.
>+ */
>+static struct pci_bus *dw_old_pcie_scan_bus(int nr, struct pci_sys_data
>+*sys) {
>+	struct pcie_port *pp = sys_to_pcie(sys);
>+	struct pci_bus *bus;
>+
>+	bus = dw_pcie_scan_bus(nr, sys);
>+	if (bus)
>+		dw_old_set_ib_access(pp);
>+
>+	return bus;
>+}
>+
>+/**
>+ * dw_old_pcie_link_up() - Check if link up
>+ *
>+ * optionally enable link train using link_train option and check if link is up.
>+ */
>+int dw_old_pcie_link_up(struct pcie_port *pp, int link_train) {
>+	u32 val;
>+
>+	if (link_train) {
>+		/*
>+		 * KeyStone devices do not support h/w autonomous
>+		 * link up-training to GEN2 from GEN1 in either EP/RC modes.
>+		 * The software needs to initiate speed change.
>+		 */
>+		val = readl(pp->dbi_base + PL_GEN2);
>+		writel(val | DIR_SPD, pp->dbi_base + PL_GEN2);
>+		/*
>+		 * Initiate Link Training. We will delay for L0 as specified by
>+		 * standard, but will still proceed and return success
>+		 * irrespective of L0 status as this will be handled by explicit
>+		 * L0 state checks during enumeration.
>+		 */
>+		val = readl(pp->va_app_base + CMD_STATUS);
>+		writel(LTSSM_EN_VAL | val,  pp->va_app_base + CMD_STATUS);
>+
>+	}
>+
>+	val = readl(pp->dbi_base + DEBUG0);
>+
>+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; }
>+
>+static struct hw_pci dw_old_pcie_hw = {
>+	.nr_controllers	= 1,
>+	.setup		= dw_pcie_setup,
>+	.scan		= dw_old_pcie_scan_bus,
>+	.swizzle        = pci_common_swizzle,
>+	.add_bus	= dw_pcie_add_bus,
>+	.map_irq	= of_irq_parse_and_map_pci,
>+};
>+
>+
>+/**
>+ * dw_old_pcie_host_init() - initialize host for old dw hardware
>+ *
>+ * Parse the pcie resources from DT bindings and then call common
>+ * dw function to do host initialization.
>+ */
>+int __init dw_old_pcie_host_init(struct pcie_port *pp, struct
>+device_node *np) {
>+	int ret;
>+
>+	if (!pp->va_app_base)
>+		return -EINVAL;
>+
>+	/* create legacy domain */
>+	pp->legacy_irq_domain = irq_domain_add_linear(np,
>+				MAX_LEGACY_IRQS,
>+				&dw_old_legacy_irq_domian_ops, NULL);
>+
>+	if (!pp->legacy_irq_domain) {
>+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
>+		return -EINVAL;
>+	}
>+
>+	ret = dw_pcie_parse_resource(pp);
>+	if (ret)
>+		return ret;
>+
>+	return dw_pcie_common_host_init(pp, &dw_old_pcie_hw,
>+					&dw_old_msi_domain_ops);
>+}
>diff --git a/drivers/pci/host/pci-dw-old.h b/drivers/pci/host/pci-dw-old.h new file mode
>100644 index 0000000..6e1af50
>--- /dev/null
>+++ b/drivers/pci/host/pci-dw-old.h
>@@ -0,0 +1,30 @@
>+/*
>+ * Designware(dw) old MSI controller (v3.65 or similar) common includes
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ *
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#define MAX_LEGACY_IRQS		4
>+
>+extern const struct irq_domain_ops dw_old_msi_domain_ops;
>+
>+void dw_old_handle_msi_irq(struct pcie_port *pp, int offset);
>+u32 dw_old_get_msi_data(struct pcie_port *pp); void
>+dw_old_enable_legacy_irqs(struct pcie_port *pp); void
>+dw_old_handle_legacy_irq(struct pcie_port *pp, int offset); int
>+dw_old_pcie_host_init(struct pcie_port *pp, struct device_node *np);
>+int dw_old_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 val); int
>+dw_old_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>+		unsigned int devfn, int where, int size, u32 *val); void
>+dw_old_disable_bars(struct pcie_port *pp); void
>+dw_old_setup_ob_regs(struct pcie_port *pp); int
>+dw_old_pcie_link_up(struct pcie_port *pp, int link_train);
>--
>1.7.9.5

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

* RE: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 16:01   ` Murali Karicheri
  (?)
@ 2014-05-16 20:47     ` Karicheri, Muralidharan
  -1 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:47 UTC (permalink / raw)
  To: Karicheri, Muralidharan, linux-kernel, linux-pci,
	linux-arm-kernel, pratyush.anand, r65037, ABRAHAM, KISHON VIJAY,
	marex
  Cc: Shilimkar, Santosh, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Strashko, Grygorii

Adding more people to the list for review.

>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:02 PM
>To: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org
>Cc: Karicheri, Muralidharan; Shilimkar, Santosh; Mohit Kumar; Jingoo Han; Bjorn Helgaas;
>Strashko, Grygorii
>Subject: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
>
>keystone pcie hardware is based on designware version 3.65.
>This driver make use of the functions from pci-dw-old.c and pci-dw-old-msi.c to implement
>the driver.
>
>Driver mainly handle the platform specific part of the PCI driver and depends on DW Old
>driver to configure application specific registers. Also routes the irq events and ack the
>interrupt after the same is acked by the end point device driver. This requires irqchip
>implementation for legacy and MSI irq handling. This patch adds a quirks to override the
>max read request size as PCI controller has a limit of 256 bytes.
>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>---
> .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
> drivers/pci/host/Kconfig                           |    8 +
> drivers/pci/host/Makefile                          |    1 +
> drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
> drivers/pci/quirks.c                               |   13 +
> 5 files changed, 490 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
> create mode 100644 drivers/pci/host/pci-keystone.c
>
>diff --git a/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>new file mode 100644
>index 0000000..17cf261
>--- /dev/null
>+++ b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>@@ -0,0 +1,68 @@
>+Keystone PCIE Root complex device tree bindings
>+-----------------------------------------------
>+
>+Sample bindings shown below:-
>+
>+ - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>+   configuration.
>+ - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>+   link
>+
>+		pcie0_phy: pciephy@2320000 {
>+			#address-cells = <1>;
>+			#size-cells = <1>;
>+			#phy-cells = <0>;
>+			compatible = "ti,keystone-phy";
>+			reg = <0x02320000 0x4000>;
>+			reg-names = "reg_serdes";
>+		};
>+
>+		pcie@21800000 {
>+			compatible = "ti,keystone-pcie";
>+			device_type = "pci";
>+			clocks = <&clkpcie>;
>+			clock-names = "pcie";
>+			#address-cells = <3>;
>+			#size-cells = <2>;
>+			reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>+			reg-names = "reg_rc_app", "reg_devcfg";
>+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
>+
>+			ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /*
>Configuration space */
>+				  0x81000000 0 0          0x24000000 0 0x4000       /* downstream
>I/O */
>+				  0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /*
>+non-prefetchable memory */
>+
>+			num-lanes = <2>;
>+			ti,enable-linktrain;
>+			ti,init-phy;
>+
>+			/* PCIE phy */
>+			phys = <&pcie0_phy>;
>+			phy-names = "pcie-phy";
>+
>+			#interrupt-cells = <1>;
>+			interrupt-map-mask = <0 0 0 0>;
>+			interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>+					<0 0 0 2 &pcie_intc 2>, // INT B
>+					<0 0 0 3 &pcie_intc 3>, // INT C
>+					<0 0 0 4 &pcie_intc 4>; // INT D
>+
>+			pcie_intc: legacy-interrupt-controller {
>+				interrupt-controller;
>+				#interrupt-cells = <1>;
>+				interrupt-parent = <&gic>;
>+				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
>+			};
>+		};
>+
>diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index c4f4732..066d611
>100644
>--- a/drivers/pci/host/Kconfig
>+++ b/drivers/pci/host/Kconfig
>@@ -37,4 +37,12 @@ config PCI_RCAR_GEN2
> 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
> 	  There are 3 internal PCI controllers available with a single
> 	  built-in EHCI/OHCI host controller present on each one.
>+
>+config PCI_KEYSTONE
>+	bool "TI Keystone PCIe controller"
>+	depends on ARCH_KEYSTONE
>+	select PCIE_DW
>+	select PCI_DW_OLD
>+	select PCIEPORTBUS
>+	select PHY_TI_KEYSTONE
> endmenu
>diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index be5d939..10e02f9
>100644
>--- a/drivers/pci/host/Makefile
>+++ b/drivers/pci/host/Makefile
>@@ -5,3 +5,4 @@ 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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
>+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
>diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c new file mode
>100644 index 0000000..2636717
>--- /dev/null
>+++ b/drivers/pci/host/pci-keystone.c
>@@ -0,0 +1,400 @@
>+/*
>+ * PCIe host controller driver for Texas Instruments Keystone SoCs
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ * Implementation based on pci-exynos.c and pcie-designware.c
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/irqchip/chained_irq.h>
>+#include <linux/clk.h>
>+#include <linux/delay.h>
>+#include <linux/irqdomain.h>
>+#include <linux/module.h>
>+#include <linux/msi.h>
>+#include <linux/of_irq.h>
>+#include <linux/of.h>
>+#include <linux/of_pci.h>
>+#include <linux/platform_device.h>
>+#include <linux/phy/phy.h>
>+#include <linux/resource.h>
>+#include <linux/signal.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+#define DRIVER_NAME	"keystone-pcie"
>+
>+/* driver specific constants */
>+#define MAX_MSI_HOST_IRQS		8
>+#define MAX_LEGACY_HOST_IRQS		4
>+
>+/* RC mode settings */
>+#define PCIE_RC_MODE		(BIT(2))
>+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+struct keystone_pcie {
>+	struct	clk		*clk;
>+	int			en_link_train;
>+	struct	pcie_port	pp;
>+
>+	int			num_legacy_host_irqs;
>+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
>+	struct			device_node *np_intc;
>+
>+	int			num_msi_host_irqs;
>+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
>+};
>+
>+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
>+
>+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int count = 200;
>+
>+	dw_pcie_setup_rc(pp);
>+
>+	/* check if the link is up or not */
>+	while (!dw_pcie_link_up(pp)) {
>+		usleep_range(100, 1000);
>+		if (--count)
>+			continue;
>+		dev_err(pp->dev, "phy link never came up\n");
>+		return -EINVAL;
>+	}
>+
>+	return 0;
>+}
>+
>+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc
>+*desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+
>+	dev_dbg(pp->dev, "ks_pcie_msi_irq_handler, irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_msi_irq(pp, offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+/**
>+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
>+ * @irq: IRQ line for legacy interrupts
>+ * @desc: Pointer to irq descriptor
>+ *
>+ * Traverse through pending legacy interrupts and invoke handler for
>+each. Also
>+ * takes care of interrupt controller level mask/ack operation.
>+ */
>+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct
>+irq_desc *desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+	struct pcie_port *pp = &ks_pcie->pp;
>+
>+	dev_dbg(ks_pcie->pp.dev, ": Handling legacy irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_legacy_irq(pp, irq_offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+static int ks_pcie_init_legacy_irqs(struct keystone_pcie *ks_pcie) {
>+	struct device *dev = ks_pcie->pp.dev;
>+	struct device_node *np_pcie = dev->of_node;
>+	int num_legacy_irqs;
>+	int ret = 0;
>+	int i;
>+
>+	/* get node */
>+	ks_pcie->np_intc = of_find_node_by_name(np_pcie,
>+						"legacy-interrupt-controller");
>+	if (!ks_pcie->np_intc) {
>+		dev_err(dev,
>+			"Node for legacy-interrupt-controller is absent\n");
>+		goto out;
>+	}
>+
>+	/* get number of IRQs */
>+	num_legacy_irqs = of_irq_count(ks_pcie->np_intc);
>+	if (!num_legacy_irqs)
>+		goto out;
>+
>+	if (num_legacy_irqs > MAX_LEGACY_HOST_IRQS) {
>+		dev_err(dev, "Too many legacy interrupts defined %u\n",
>+			num_legacy_irqs);
>+		num_legacy_irqs = MAX_LEGACY_HOST_IRQS;
>+	}
>+	/*
>+	 * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
>+	 * In dt from index 0 to 3
>+	 */
>+	for (i = 0; i < num_legacy_irqs; i++) {
>+		ks_pcie->legacy_host_irqs[i] =
>+			irq_of_parse_and_map(ks_pcie->np_intc, i);
>+		if (ks_pcie->legacy_host_irqs[i] < 0)
>+			break;
>+		ks_pcie->num_legacy_host_irqs++;
>+	}
>+
>+	if (!ks_pcie->num_legacy_host_irqs) {
>+		dev_err(dev, "Failed to get legacy interrupts\n");
>+		goto out;
>+	}
>+
>+out:
>+	return ret;
>+}
>+
>+static void ks_pcie_enable_interrupts(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int i;
>+
>+	/* Legacy IRQ */
>+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
>+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
>+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
>+					ks_pcie_legacy_irq_handler);
>+	}
>+	dw_old_enable_legacy_irqs(pp);
>+
>+	/* MSI IRQ */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
>+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
>+				ks_pcie_msi_irq_handler);
>+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
>+						ks_pcie);
>+
>+		}
>+	}
>+
>+	return;
>+}
>+
>+static int
>+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>+		struct pt_regs *regs)
>+{
>+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>+
>+	if ((instr & 0x0e100090) == 0x00100090) {
>+		int reg = (instr >> 12) & 15;
>+
>+		regs->uregs[reg] = -1;
>+		regs->ARM_pc += 4;
>+	}
>+
>+	return 0;
>+}
>+
>+static void __init ks_pcie_host_init(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	ks_pcie_establish_link(ks_pcie);
>+	dw_old_disable_bars(pp);
>+	dw_old_setup_ob_regs(pp);
>+	ks_pcie_enable_interrupts(ks_pcie);
>+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
>+			pp->dbi_base + PCI_IO_BASE);
>+	/*
>+	 * PCIe access errors that result into OCP errors are caught by ARM as
>+	 * "External aborts" (Precise).
>+	 */
>+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
>+			"external abort on linefetch");
>+}
>+
>+int ks_pcie_link_up(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	return dw_old_pcie_link_up(pp, ks_pcie->en_link_train); }
>+
>+static struct pcie_host_ops keystone_pcie_host_ops = {
>+	.rd_other_conf = dw_old_rd_other_conf,
>+	.wr_other_conf = dw_old_wr_other_conf,
>+	.link_up = ks_pcie_link_up,
>+	.host_init = ks_pcie_host_init,
>+	.get_msi_data = dw_old_get_msi_data,
>+};
>+
>+static int add_pcie_port(struct keystone_pcie *ks_pcie,
>+			 struct platform_device *pdev)
>+{
>+	struct device_node *np = pdev->dev.of_node;
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct resource *res;
>+	int ret, i;
>+
>+	ret = ks_pcie_init_legacy_irqs(ks_pcie);
>+	if (ret)
>+		return ret;
>+
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		/*
>+		 * support upto 32 MSI irqs mapped to 8 host IRQs.
>+		 * In dt from index 4 to 11
>+		 */
>+		for (i = 0; i < MAX_MSI_HOST_IRQS; i++) {
>+			ks_pcie->msi_host_irqs[i] = irq_of_parse_and_map(np, i);
>+			if (ks_pcie->msi_host_irqs[i] < 0)
>+				break;
>+			ks_pcie->num_msi_host_irqs++;
>+		}
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_rc_app");
>+	pp->va_app_base = devm_ioremap_resource(&pdev->dev, res);
>+	if (IS_ERR(pp->va_app_base))
>+		return PTR_ERR(pp->va_app_base);
>+	pp->app_base = res->start;
>+
>+	pp->root_bus_nr = -1;
>+	pp->version = DW_VERSION_OLD;
>+	pp->ops = &keystone_pcie_host_ops;
>+	spin_lock_init(&pp->conf_lock);
>+	ret = dw_old_pcie_host_init(pp, ks_pcie->np_intc);
>+	if (ret) {
>+		dev_err(&pdev->dev, "failed to initialize host\n");
>+		return ret;
>+	}
>+
>+	return ret;
>+}
>+
>+static const struct of_device_id ks_pcie_of_match[] = {
>+	{
>+		.type = "pci",
>+		.compatible = "ti,keystone-pcie",
>+	},
>+	{ },
>+};
>+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
>+
>+static int __exit ks_pcie_remove(struct platform_device *pdev) {
>+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
>+
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return 0;
>+}
>+
>+static int __init ks_pcie_probe(struct platform_device *pdev) {
>+	struct device_node *np = pdev->dev.of_node;
>+	struct device *dev = &pdev->dev;
>+	struct keystone_pcie *ks_pcie;
>+	void __iomem *devstat;
>+	struct pcie_port *pp;
>+	struct resource *res;
>+	struct phy *phy;
>+	int ret = 0;
>+	u32 val;
>+
>+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
>+				GFP_KERNEL);
>+	if (!ks_pcie) {
>+		dev_err(dev, "no memory for keystone pcie\n");
>+		return -ENOMEM;
>+	}
>+
>+	/* check if serdes phy needs to be enabled */
>+	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
>+		phy = devm_phy_get(dev, "pcie-phy");
>+			if (IS_ERR(phy))
>+				return PTR_ERR(phy);
>+
>+		ret = phy_init(phy);
>+		if (ret < 0)
>+			return ret;
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>+					   "reg_devcfg");
>+	devstat = devm_ioremap_resource(dev, res);
>+	if (IS_ERR(devstat))
>+		return PTR_ERR(devstat);
>+
>+	/* enable RC mode in devcfg */
>+	val = readl(devstat);
>+	val &= ~PCIE_MODE_MASK;
>+	val |= PCIE_RC_MODE;
>+	writel(val, devstat);
>+
>+	/* check if we need to enable link training */
>+	ks_pcie->en_link_train =
>+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
>+
>+	pp = &ks_pcie->pp;
>+	pp->dev = dev;
>+
>+	ks_pcie->clk = devm_clk_get(dev, "pcie");
>+	if (IS_ERR(ks_pcie->clk)) {
>+		dev_err(dev, "Failed to get pcie rc clock\n");
>+		return PTR_ERR(ks_pcie->clk);
>+	}
>+	ret = clk_prepare_enable(ks_pcie->clk);
>+	if (ret)
>+		return ret;
>+
>+	ret = add_pcie_port(ks_pcie, pdev);
>+	if (ret < 0)
>+		goto fail_clk;
>+
>+	platform_set_drvdata(pdev, ks_pcie);
>+	dev_info(dev, "pcie rc probe success\n");
>+
>+	return 0;
>+
>+fail_clk:
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return ret;
>+}
>+
>+static struct platform_driver ks_pcie_driver __refdata = {
>+	.probe  = ks_pcie_probe,
>+	.remove = __exit_p(ks_pcie_remove),
>+	.driver = {
>+		.name	= "keystone-pcie",
>+		.owner	= THIS_MODULE,
>+		.of_match_table = of_match_ptr(ks_pcie_of_match),
>+	},
>+};
>+
>+module_platform_driver(ks_pcie_driver);
>+
>+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
>+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
>+MODULE_LICENSE("GPL v2");
>diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e729206..b3e12c2 100644
>--- a/drivers/pci/quirks.c
>+++ b/drivers/pci/quirks.c
>@@ -3651,3 +3651,16 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
> 		}
> 	}
> }
>+#ifdef CONFIG_PCI_KEYSTONE
>+/*
>+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>+ */
>+static void quirk_limit_readrequest(struct pci_dev *dev) {
>+	int readrq = pcie_get_readrq(dev);
>+
>+	if (readrq > 256)
>+		pcie_set_readrq(dev, 256);
>+}
>+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID,
>+quirk_limit_readrequest); #endif /* CONFIG_PCI_KEYSTONE */
>--
>1.7.9.5


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

* RE: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 20:47     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:47 UTC (permalink / raw)
  To: Karicheri, Muralidharan, linux-kernel, linux-pci,
	linux-arm-kernel, pratyush.anand, r65037, ABRAHAM, KISHON VIJAY,
	marex
  Cc: Shilimkar, Santosh, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Strashko, Grygorii

Adding more people to the list for review.

>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:02 PM
>To: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org
>Cc: Karicheri, Muralidharan; Shilimkar, Santosh; Mohit Kumar; Jingoo Han; Bjorn Helgaas;
>Strashko, Grygorii
>Subject: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
>
>keystone pcie hardware is based on designware version 3.65.
>This driver make use of the functions from pci-dw-old.c and pci-dw-old-msi.c to implement
>the driver.
>
>Driver mainly handle the platform specific part of the PCI driver and depends on DW Old
>driver to configure application specific registers. Also routes the irq events and ack the
>interrupt after the same is acked by the end point device driver. This requires irqchip
>implementation for legacy and MSI irq handling. This patch adds a quirks to override the
>max read request size as PCI controller has a limit of 256 bytes.
>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>---
> .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
> drivers/pci/host/Kconfig                           |    8 +
> drivers/pci/host/Makefile                          |    1 +
> drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
> drivers/pci/quirks.c                               |   13 +
> 5 files changed, 490 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
> create mode 100644 drivers/pci/host/pci-keystone.c
>
>diff --git a/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>new file mode 100644
>index 0000000..17cf261
>--- /dev/null
>+++ b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>@@ -0,0 +1,68 @@
>+Keystone PCIE Root complex device tree bindings
>+-----------------------------------------------
>+
>+Sample bindings shown below:-
>+
>+ - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>+   configuration.
>+ - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>+   link
>+
>+		pcie0_phy: pciephy@2320000 {
>+			#address-cells = <1>;
>+			#size-cells = <1>;
>+			#phy-cells = <0>;
>+			compatible = "ti,keystone-phy";
>+			reg = <0x02320000 0x4000>;
>+			reg-names = "reg_serdes";
>+		};
>+
>+		pcie@21800000 {
>+			compatible = "ti,keystone-pcie";
>+			device_type = "pci";
>+			clocks = <&clkpcie>;
>+			clock-names = "pcie";
>+			#address-cells = <3>;
>+			#size-cells = <2>;
>+			reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>+			reg-names = "reg_rc_app", "reg_devcfg";
>+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
>+
>+			ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /*
>Configuration space */
>+				  0x81000000 0 0          0x24000000 0 0x4000       /* downstream
>I/O */
>+				  0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /*
>+non-prefetchable memory */
>+
>+			num-lanes = <2>;
>+			ti,enable-linktrain;
>+			ti,init-phy;
>+
>+			/* PCIE phy */
>+			phys = <&pcie0_phy>;
>+			phy-names = "pcie-phy";
>+
>+			#interrupt-cells = <1>;
>+			interrupt-map-mask = <0 0 0 0>;
>+			interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>+					<0 0 0 2 &pcie_intc 2>, // INT B
>+					<0 0 0 3 &pcie_intc 3>, // INT C
>+					<0 0 0 4 &pcie_intc 4>; // INT D
>+
>+			pcie_intc: legacy-interrupt-controller {
>+				interrupt-controller;
>+				#interrupt-cells = <1>;
>+				interrupt-parent = <&gic>;
>+				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
>+			};
>+		};
>+
>diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index c4f4732..066d611
>100644
>--- a/drivers/pci/host/Kconfig
>+++ b/drivers/pci/host/Kconfig
>@@ -37,4 +37,12 @@ config PCI_RCAR_GEN2
> 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
> 	  There are 3 internal PCI controllers available with a single
> 	  built-in EHCI/OHCI host controller present on each one.
>+
>+config PCI_KEYSTONE
>+	bool "TI Keystone PCIe controller"
>+	depends on ARCH_KEYSTONE
>+	select PCIE_DW
>+	select PCI_DW_OLD
>+	select PCIEPORTBUS
>+	select PHY_TI_KEYSTONE
> endmenu
>diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index be5d939..10e02f9
>100644
>--- a/drivers/pci/host/Makefile
>+++ b/drivers/pci/host/Makefile
>@@ -5,3 +5,4 @@ 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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
>+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
>diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c new file mode
>100644 index 0000000..2636717
>--- /dev/null
>+++ b/drivers/pci/host/pci-keystone.c
>@@ -0,0 +1,400 @@
>+/*
>+ * PCIe host controller driver for Texas Instruments Keystone SoCs
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ * Implementation based on pci-exynos.c and pcie-designware.c
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/irqchip/chained_irq.h>
>+#include <linux/clk.h>
>+#include <linux/delay.h>
>+#include <linux/irqdomain.h>
>+#include <linux/module.h>
>+#include <linux/msi.h>
>+#include <linux/of_irq.h>
>+#include <linux/of.h>
>+#include <linux/of_pci.h>
>+#include <linux/platform_device.h>
>+#include <linux/phy/phy.h>
>+#include <linux/resource.h>
>+#include <linux/signal.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+#define DRIVER_NAME	"keystone-pcie"
>+
>+/* driver specific constants */
>+#define MAX_MSI_HOST_IRQS		8
>+#define MAX_LEGACY_HOST_IRQS		4
>+
>+/* RC mode settings */
>+#define PCIE_RC_MODE		(BIT(2))
>+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+struct keystone_pcie {
>+	struct	clk		*clk;
>+	int			en_link_train;
>+	struct	pcie_port	pp;
>+
>+	int			num_legacy_host_irqs;
>+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
>+	struct			device_node *np_intc;
>+
>+	int			num_msi_host_irqs;
>+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
>+};
>+
>+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
>+
>+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int count = 200;
>+
>+	dw_pcie_setup_rc(pp);
>+
>+	/* check if the link is up or not */
>+	while (!dw_pcie_link_up(pp)) {
>+		usleep_range(100, 1000);
>+		if (--count)
>+			continue;
>+		dev_err(pp->dev, "phy link never came up\n");
>+		return -EINVAL;
>+	}
>+
>+	return 0;
>+}
>+
>+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc
>+*desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+
>+	dev_dbg(pp->dev, "ks_pcie_msi_irq_handler, irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_msi_irq(pp, offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+/**
>+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
>+ * @irq: IRQ line for legacy interrupts
>+ * @desc: Pointer to irq descriptor
>+ *
>+ * Traverse through pending legacy interrupts and invoke handler for
>+each. Also
>+ * takes care of interrupt controller level mask/ack operation.
>+ */
>+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct
>+irq_desc *desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+	struct pcie_port *pp = &ks_pcie->pp;
>+
>+	dev_dbg(ks_pcie->pp.dev, ": Handling legacy irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_legacy_irq(pp, irq_offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+static int ks_pcie_init_legacy_irqs(struct keystone_pcie *ks_pcie) {
>+	struct device *dev = ks_pcie->pp.dev;
>+	struct device_node *np_pcie = dev->of_node;
>+	int num_legacy_irqs;
>+	int ret = 0;
>+	int i;
>+
>+	/* get node */
>+	ks_pcie->np_intc = of_find_node_by_name(np_pcie,
>+						"legacy-interrupt-controller");
>+	if (!ks_pcie->np_intc) {
>+		dev_err(dev,
>+			"Node for legacy-interrupt-controller is absent\n");
>+		goto out;
>+	}
>+
>+	/* get number of IRQs */
>+	num_legacy_irqs = of_irq_count(ks_pcie->np_intc);
>+	if (!num_legacy_irqs)
>+		goto out;
>+
>+	if (num_legacy_irqs > MAX_LEGACY_HOST_IRQS) {
>+		dev_err(dev, "Too many legacy interrupts defined %u\n",
>+			num_legacy_irqs);
>+		num_legacy_irqs = MAX_LEGACY_HOST_IRQS;
>+	}
>+	/*
>+	 * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
>+	 * In dt from index 0 to 3
>+	 */
>+	for (i = 0; i < num_legacy_irqs; i++) {
>+		ks_pcie->legacy_host_irqs[i] =
>+			irq_of_parse_and_map(ks_pcie->np_intc, i);
>+		if (ks_pcie->legacy_host_irqs[i] < 0)
>+			break;
>+		ks_pcie->num_legacy_host_irqs++;
>+	}
>+
>+	if (!ks_pcie->num_legacy_host_irqs) {
>+		dev_err(dev, "Failed to get legacy interrupts\n");
>+		goto out;
>+	}
>+
>+out:
>+	return ret;
>+}
>+
>+static void ks_pcie_enable_interrupts(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int i;
>+
>+	/* Legacy IRQ */
>+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
>+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
>+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
>+					ks_pcie_legacy_irq_handler);
>+	}
>+	dw_old_enable_legacy_irqs(pp);
>+
>+	/* MSI IRQ */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
>+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
>+				ks_pcie_msi_irq_handler);
>+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
>+						ks_pcie);
>+
>+		}
>+	}
>+
>+	return;
>+}
>+
>+static int
>+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>+		struct pt_regs *regs)
>+{
>+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>+
>+	if ((instr & 0x0e100090) == 0x00100090) {
>+		int reg = (instr >> 12) & 15;
>+
>+		regs->uregs[reg] = -1;
>+		regs->ARM_pc += 4;
>+	}
>+
>+	return 0;
>+}
>+
>+static void __init ks_pcie_host_init(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	ks_pcie_establish_link(ks_pcie);
>+	dw_old_disable_bars(pp);
>+	dw_old_setup_ob_regs(pp);
>+	ks_pcie_enable_interrupts(ks_pcie);
>+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
>+			pp->dbi_base + PCI_IO_BASE);
>+	/*
>+	 * PCIe access errors that result into OCP errors are caught by ARM as
>+	 * "External aborts" (Precise).
>+	 */
>+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
>+			"external abort on linefetch");
>+}
>+
>+int ks_pcie_link_up(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	return dw_old_pcie_link_up(pp, ks_pcie->en_link_train); }
>+
>+static struct pcie_host_ops keystone_pcie_host_ops = {
>+	.rd_other_conf = dw_old_rd_other_conf,
>+	.wr_other_conf = dw_old_wr_other_conf,
>+	.link_up = ks_pcie_link_up,
>+	.host_init = ks_pcie_host_init,
>+	.get_msi_data = dw_old_get_msi_data,
>+};
>+
>+static int add_pcie_port(struct keystone_pcie *ks_pcie,
>+			 struct platform_device *pdev)
>+{
>+	struct device_node *np = pdev->dev.of_node;
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct resource *res;
>+	int ret, i;
>+
>+	ret = ks_pcie_init_legacy_irqs(ks_pcie);
>+	if (ret)
>+		return ret;
>+
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		/*
>+		 * support upto 32 MSI irqs mapped to 8 host IRQs.
>+		 * In dt from index 4 to 11
>+		 */
>+		for (i = 0; i < MAX_MSI_HOST_IRQS; i++) {
>+			ks_pcie->msi_host_irqs[i] = irq_of_parse_and_map(np, i);
>+			if (ks_pcie->msi_host_irqs[i] < 0)
>+				break;
>+			ks_pcie->num_msi_host_irqs++;
>+		}
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_rc_app");
>+	pp->va_app_base = devm_ioremap_resource(&pdev->dev, res);
>+	if (IS_ERR(pp->va_app_base))
>+		return PTR_ERR(pp->va_app_base);
>+	pp->app_base = res->start;
>+
>+	pp->root_bus_nr = -1;
>+	pp->version = DW_VERSION_OLD;
>+	pp->ops = &keystone_pcie_host_ops;
>+	spin_lock_init(&pp->conf_lock);
>+	ret = dw_old_pcie_host_init(pp, ks_pcie->np_intc);
>+	if (ret) {
>+		dev_err(&pdev->dev, "failed to initialize host\n");
>+		return ret;
>+	}
>+
>+	return ret;
>+}
>+
>+static const struct of_device_id ks_pcie_of_match[] = {
>+	{
>+		.type = "pci",
>+		.compatible = "ti,keystone-pcie",
>+	},
>+	{ },
>+};
>+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
>+
>+static int __exit ks_pcie_remove(struct platform_device *pdev) {
>+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
>+
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return 0;
>+}
>+
>+static int __init ks_pcie_probe(struct platform_device *pdev) {
>+	struct device_node *np = pdev->dev.of_node;
>+	struct device *dev = &pdev->dev;
>+	struct keystone_pcie *ks_pcie;
>+	void __iomem *devstat;
>+	struct pcie_port *pp;
>+	struct resource *res;
>+	struct phy *phy;
>+	int ret = 0;
>+	u32 val;
>+
>+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
>+				GFP_KERNEL);
>+	if (!ks_pcie) {
>+		dev_err(dev, "no memory for keystone pcie\n");
>+		return -ENOMEM;
>+	}
>+
>+	/* check if serdes phy needs to be enabled */
>+	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
>+		phy = devm_phy_get(dev, "pcie-phy");
>+			if (IS_ERR(phy))
>+				return PTR_ERR(phy);
>+
>+		ret = phy_init(phy);
>+		if (ret < 0)
>+			return ret;
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>+					   "reg_devcfg");
>+	devstat = devm_ioremap_resource(dev, res);
>+	if (IS_ERR(devstat))
>+		return PTR_ERR(devstat);
>+
>+	/* enable RC mode in devcfg */
>+	val = readl(devstat);
>+	val &= ~PCIE_MODE_MASK;
>+	val |= PCIE_RC_MODE;
>+	writel(val, devstat);
>+
>+	/* check if we need to enable link training */
>+	ks_pcie->en_link_train =
>+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
>+
>+	pp = &ks_pcie->pp;
>+	pp->dev = dev;
>+
>+	ks_pcie->clk = devm_clk_get(dev, "pcie");
>+	if (IS_ERR(ks_pcie->clk)) {
>+		dev_err(dev, "Failed to get pcie rc clock\n");
>+		return PTR_ERR(ks_pcie->clk);
>+	}
>+	ret = clk_prepare_enable(ks_pcie->clk);
>+	if (ret)
>+		return ret;
>+
>+	ret = add_pcie_port(ks_pcie, pdev);
>+	if (ret < 0)
>+		goto fail_clk;
>+
>+	platform_set_drvdata(pdev, ks_pcie);
>+	dev_info(dev, "pcie rc probe success\n");
>+
>+	return 0;
>+
>+fail_clk:
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return ret;
>+}
>+
>+static struct platform_driver ks_pcie_driver __refdata = {
>+	.probe  = ks_pcie_probe,
>+	.remove = __exit_p(ks_pcie_remove),
>+	.driver = {
>+		.name	= "keystone-pcie",
>+		.owner	= THIS_MODULE,
>+		.of_match_table = of_match_ptr(ks_pcie_of_match),
>+	},
>+};
>+
>+module_platform_driver(ks_pcie_driver);
>+
>+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
>+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
>+MODULE_LICENSE("GPL v2");
>diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e729206..b3e12c2 100644
>--- a/drivers/pci/quirks.c
>+++ b/drivers/pci/quirks.c
>@@ -3651,3 +3651,16 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
> 		}
> 	}
> }
>+#ifdef CONFIG_PCI_KEYSTONE
>+/*
>+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>+ */
>+static void quirk_limit_readrequest(struct pci_dev *dev) {
>+	int readrq = pcie_get_readrq(dev);
>+
>+	if (readrq > 256)
>+		pcie_set_readrq(dev, 256);
>+}
>+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID,
>+quirk_limit_readrequest); #endif /* CONFIG_PCI_KEYSTONE */
>--
>1.7.9.5


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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 20:47     ` Karicheri, Muralidharan
  0 siblings, 0 replies; 116+ messages in thread
From: Karicheri, Muralidharan @ 2014-05-16 20:47 UTC (permalink / raw)
  To: linux-arm-kernel

Adding more people to the list for review.

>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:02 PM
>To: linux-kernel at vger.kernel.org; linux-pci at vger.kernel.org; linux-arm-
>kernel at lists.infradead.org
>Cc: Karicheri, Muralidharan; Shilimkar, Santosh; Mohit Kumar; Jingoo Han; Bjorn Helgaas;
>Strashko, Grygorii
>Subject: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
>
>keystone pcie hardware is based on designware version 3.65.
>This driver make use of the functions from pci-dw-old.c and pci-dw-old-msi.c to implement
>the driver.
>
>Driver mainly handle the platform specific part of the PCI driver and depends on DW Old
>driver to configure application specific registers. Also routes the irq events and ack the
>interrupt after the same is acked by the end point device driver. This requires irqchip
>implementation for legacy and MSI irq handling. This patch adds a quirks to override the
>max read request size as PCI controller has a limit of 256 bytes.
>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>---
> .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
> drivers/pci/host/Kconfig                           |    8 +
> drivers/pci/host/Makefile                          |    1 +
> drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
> drivers/pci/quirks.c                               |   13 +
> 5 files changed, 490 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
> create mode 100644 drivers/pci/host/pci-keystone.c
>
>diff --git a/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>new file mode 100644
>index 0000000..17cf261
>--- /dev/null
>+++ b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>@@ -0,0 +1,68 @@
>+Keystone PCIE Root complex device tree bindings
>+-----------------------------------------------
>+
>+Sample bindings shown below:-
>+
>+ - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>+   configuration.
>+ - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>+   link
>+
>+		pcie0_phy: pciephy at 2320000 {
>+			#address-cells = <1>;
>+			#size-cells = <1>;
>+			#phy-cells = <0>;
>+			compatible = "ti,keystone-phy";
>+			reg = <0x02320000 0x4000>;
>+			reg-names = "reg_serdes";
>+		};
>+
>+		pcie at 21800000 {
>+			compatible = "ti,keystone-pcie";
>+			device_type = "pci";
>+			clocks = <&clkpcie>;
>+			clock-names = "pcie";
>+			#address-cells = <3>;
>+			#size-cells = <2>;
>+			reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>+			reg-names = "reg_rc_app", "reg_devcfg";
>+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
>+
>+			ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /*
>Configuration space */
>+				  0x81000000 0 0          0x24000000 0 0x4000       /* downstream
>I/O */
>+				  0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /*
>+non-prefetchable memory */
>+
>+			num-lanes = <2>;
>+			ti,enable-linktrain;
>+			ti,init-phy;
>+
>+			/* PCIE phy */
>+			phys = <&pcie0_phy>;
>+			phy-names = "pcie-phy";
>+
>+			#interrupt-cells = <1>;
>+			interrupt-map-mask = <0 0 0 0>;
>+			interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>+					<0 0 0 2 &pcie_intc 2>, // INT B
>+					<0 0 0 3 &pcie_intc 3>, // INT C
>+					<0 0 0 4 &pcie_intc 4>; // INT D
>+
>+			pcie_intc: legacy-interrupt-controller {
>+				interrupt-controller;
>+				#interrupt-cells = <1>;
>+				interrupt-parent = <&gic>;
>+				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
>+			};
>+		};
>+
>diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index c4f4732..066d611
>100644
>--- a/drivers/pci/host/Kconfig
>+++ b/drivers/pci/host/Kconfig
>@@ -37,4 +37,12 @@ config PCI_RCAR_GEN2
> 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
> 	  There are 3 internal PCI controllers available with a single
> 	  built-in EHCI/OHCI host controller present on each one.
>+
>+config PCI_KEYSTONE
>+	bool "TI Keystone PCIe controller"
>+	depends on ARCH_KEYSTONE
>+	select PCIE_DW
>+	select PCI_DW_OLD
>+	select PCIEPORTBUS
>+	select PHY_TI_KEYSTONE
> endmenu
>diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index be5d939..10e02f9
>100644
>--- a/drivers/pci/host/Makefile
>+++ b/drivers/pci/host/Makefile
>@@ -5,3 +5,4 @@ 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_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
>+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
>diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c new file mode
>100644 index 0000000..2636717
>--- /dev/null
>+++ b/drivers/pci/host/pci-keystone.c
>@@ -0,0 +1,400 @@
>+/*
>+ * PCIe host controller driver for Texas Instruments Keystone SoCs
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ * Implementation based on pci-exynos.c and pcie-designware.c
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#include <linux/irqchip/chained_irq.h>
>+#include <linux/clk.h>
>+#include <linux/delay.h>
>+#include <linux/irqdomain.h>
>+#include <linux/module.h>
>+#include <linux/msi.h>
>+#include <linux/of_irq.h>
>+#include <linux/of.h>
>+#include <linux/of_pci.h>
>+#include <linux/platform_device.h>
>+#include <linux/phy/phy.h>
>+#include <linux/resource.h>
>+#include <linux/signal.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+#define DRIVER_NAME	"keystone-pcie"
>+
>+/* driver specific constants */
>+#define MAX_MSI_HOST_IRQS		8
>+#define MAX_LEGACY_HOST_IRQS		4
>+
>+/* RC mode settings */
>+#define PCIE_RC_MODE		(BIT(2))
>+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+struct keystone_pcie {
>+	struct	clk		*clk;
>+	int			en_link_train;
>+	struct	pcie_port	pp;
>+
>+	int			num_legacy_host_irqs;
>+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
>+	struct			device_node *np_intc;
>+
>+	int			num_msi_host_irqs;
>+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
>+};
>+
>+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
>+
>+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int count = 200;
>+
>+	dw_pcie_setup_rc(pp);
>+
>+	/* check if the link is up or not */
>+	while (!dw_pcie_link_up(pp)) {
>+		usleep_range(100, 1000);
>+		if (--count)
>+			continue;
>+		dev_err(pp->dev, "phy link never came up\n");
>+		return -EINVAL;
>+	}
>+
>+	return 0;
>+}
>+
>+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc
>+*desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+
>+	dev_dbg(pp->dev, "ks_pcie_msi_irq_handler, irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_msi_irq(pp, offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+/**
>+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
>+ * @irq: IRQ line for legacy interrupts
>+ * @desc: Pointer to irq descriptor
>+ *
>+ * Traverse through pending legacy interrupts and invoke handler for
>+each. Also
>+ * takes care of interrupt controller level mask/ack operation.
>+ */
>+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct
>+irq_desc *desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+	struct pcie_port *pp = &ks_pcie->pp;
>+
>+	dev_dbg(ks_pcie->pp.dev, ": Handling legacy irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_legacy_irq(pp, irq_offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+static int ks_pcie_init_legacy_irqs(struct keystone_pcie *ks_pcie) {
>+	struct device *dev = ks_pcie->pp.dev;
>+	struct device_node *np_pcie = dev->of_node;
>+	int num_legacy_irqs;
>+	int ret = 0;
>+	int i;
>+
>+	/* get node */
>+	ks_pcie->np_intc = of_find_node_by_name(np_pcie,
>+						"legacy-interrupt-controller");
>+	if (!ks_pcie->np_intc) {
>+		dev_err(dev,
>+			"Node for legacy-interrupt-controller is absent\n");
>+		goto out;
>+	}
>+
>+	/* get number of IRQs */
>+	num_legacy_irqs = of_irq_count(ks_pcie->np_intc);
>+	if (!num_legacy_irqs)
>+		goto out;
>+
>+	if (num_legacy_irqs > MAX_LEGACY_HOST_IRQS) {
>+		dev_err(dev, "Too many legacy interrupts defined %u\n",
>+			num_legacy_irqs);
>+		num_legacy_irqs = MAX_LEGACY_HOST_IRQS;
>+	}
>+	/*
>+	 * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
>+	 * In dt from index 0 to 3
>+	 */
>+	for (i = 0; i < num_legacy_irqs; i++) {
>+		ks_pcie->legacy_host_irqs[i] =
>+			irq_of_parse_and_map(ks_pcie->np_intc, i);
>+		if (ks_pcie->legacy_host_irqs[i] < 0)
>+			break;
>+		ks_pcie->num_legacy_host_irqs++;
>+	}
>+
>+	if (!ks_pcie->num_legacy_host_irqs) {
>+		dev_err(dev, "Failed to get legacy interrupts\n");
>+		goto out;
>+	}
>+
>+out:
>+	return ret;
>+}
>+
>+static void ks_pcie_enable_interrupts(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int i;
>+
>+	/* Legacy IRQ */
>+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
>+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
>+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
>+					ks_pcie_legacy_irq_handler);
>+	}
>+	dw_old_enable_legacy_irqs(pp);
>+
>+	/* MSI IRQ */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
>+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
>+				ks_pcie_msi_irq_handler);
>+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
>+						ks_pcie);
>+
>+		}
>+	}
>+
>+	return;
>+}
>+
>+static int
>+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>+		struct pt_regs *regs)
>+{
>+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>+
>+	if ((instr & 0x0e100090) == 0x00100090) {
>+		int reg = (instr >> 12) & 15;
>+
>+		regs->uregs[reg] = -1;
>+		regs->ARM_pc += 4;
>+	}
>+
>+	return 0;
>+}
>+
>+static void __init ks_pcie_host_init(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	ks_pcie_establish_link(ks_pcie);
>+	dw_old_disable_bars(pp);
>+	dw_old_setup_ob_regs(pp);
>+	ks_pcie_enable_interrupts(ks_pcie);
>+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
>+			pp->dbi_base + PCI_IO_BASE);
>+	/*
>+	 * PCIe access errors that result into OCP errors are caught by ARM as
>+	 * "External aborts" (Precise).
>+	 */
>+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
>+			"external abort on linefetch");
>+}
>+
>+int ks_pcie_link_up(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	return dw_old_pcie_link_up(pp, ks_pcie->en_link_train); }
>+
>+static struct pcie_host_ops keystone_pcie_host_ops = {
>+	.rd_other_conf = dw_old_rd_other_conf,
>+	.wr_other_conf = dw_old_wr_other_conf,
>+	.link_up = ks_pcie_link_up,
>+	.host_init = ks_pcie_host_init,
>+	.get_msi_data = dw_old_get_msi_data,
>+};
>+
>+static int add_pcie_port(struct keystone_pcie *ks_pcie,
>+			 struct platform_device *pdev)
>+{
>+	struct device_node *np = pdev->dev.of_node;
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct resource *res;
>+	int ret, i;
>+
>+	ret = ks_pcie_init_legacy_irqs(ks_pcie);
>+	if (ret)
>+		return ret;
>+
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		/*
>+		 * support upto 32 MSI irqs mapped to 8 host IRQs.
>+		 * In dt from index 4 to 11
>+		 */
>+		for (i = 0; i < MAX_MSI_HOST_IRQS; i++) {
>+			ks_pcie->msi_host_irqs[i] = irq_of_parse_and_map(np, i);
>+			if (ks_pcie->msi_host_irqs[i] < 0)
>+				break;
>+			ks_pcie->num_msi_host_irqs++;
>+		}
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_rc_app");
>+	pp->va_app_base = devm_ioremap_resource(&pdev->dev, res);
>+	if (IS_ERR(pp->va_app_base))
>+		return PTR_ERR(pp->va_app_base);
>+	pp->app_base = res->start;
>+
>+	pp->root_bus_nr = -1;
>+	pp->version = DW_VERSION_OLD;
>+	pp->ops = &keystone_pcie_host_ops;
>+	spin_lock_init(&pp->conf_lock);
>+	ret = dw_old_pcie_host_init(pp, ks_pcie->np_intc);
>+	if (ret) {
>+		dev_err(&pdev->dev, "failed to initialize host\n");
>+		return ret;
>+	}
>+
>+	return ret;
>+}
>+
>+static const struct of_device_id ks_pcie_of_match[] = {
>+	{
>+		.type = "pci",
>+		.compatible = "ti,keystone-pcie",
>+	},
>+	{ },
>+};
>+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
>+
>+static int __exit ks_pcie_remove(struct platform_device *pdev) {
>+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
>+
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return 0;
>+}
>+
>+static int __init ks_pcie_probe(struct platform_device *pdev) {
>+	struct device_node *np = pdev->dev.of_node;
>+	struct device *dev = &pdev->dev;
>+	struct keystone_pcie *ks_pcie;
>+	void __iomem *devstat;
>+	struct pcie_port *pp;
>+	struct resource *res;
>+	struct phy *phy;
>+	int ret = 0;
>+	u32 val;
>+
>+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
>+				GFP_KERNEL);
>+	if (!ks_pcie) {
>+		dev_err(dev, "no memory for keystone pcie\n");
>+		return -ENOMEM;
>+	}
>+
>+	/* check if serdes phy needs to be enabled */
>+	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
>+		phy = devm_phy_get(dev, "pcie-phy");
>+			if (IS_ERR(phy))
>+				return PTR_ERR(phy);
>+
>+		ret = phy_init(phy);
>+		if (ret < 0)
>+			return ret;
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>+					   "reg_devcfg");
>+	devstat = devm_ioremap_resource(dev, res);
>+	if (IS_ERR(devstat))
>+		return PTR_ERR(devstat);
>+
>+	/* enable RC mode in devcfg */
>+	val = readl(devstat);
>+	val &= ~PCIE_MODE_MASK;
>+	val |= PCIE_RC_MODE;
>+	writel(val, devstat);
>+
>+	/* check if we need to enable link training */
>+	ks_pcie->en_link_train =
>+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
>+
>+	pp = &ks_pcie->pp;
>+	pp->dev = dev;
>+
>+	ks_pcie->clk = devm_clk_get(dev, "pcie");
>+	if (IS_ERR(ks_pcie->clk)) {
>+		dev_err(dev, "Failed to get pcie rc clock\n");
>+		return PTR_ERR(ks_pcie->clk);
>+	}
>+	ret = clk_prepare_enable(ks_pcie->clk);
>+	if (ret)
>+		return ret;
>+
>+	ret = add_pcie_port(ks_pcie, pdev);
>+	if (ret < 0)
>+		goto fail_clk;
>+
>+	platform_set_drvdata(pdev, ks_pcie);
>+	dev_info(dev, "pcie rc probe success\n");
>+
>+	return 0;
>+
>+fail_clk:
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return ret;
>+}
>+
>+static struct platform_driver ks_pcie_driver __refdata = {
>+	.probe  = ks_pcie_probe,
>+	.remove = __exit_p(ks_pcie_remove),
>+	.driver = {
>+		.name	= "keystone-pcie",
>+		.owner	= THIS_MODULE,
>+		.of_match_table = of_match_ptr(ks_pcie_of_match),
>+	},
>+};
>+
>+module_platform_driver(ks_pcie_driver);
>+
>+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
>+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
>+MODULE_LICENSE("GPL v2");
>diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e729206..b3e12c2 100644
>--- a/drivers/pci/quirks.c
>+++ b/drivers/pci/quirks.c
>@@ -3651,3 +3651,16 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
> 		}
> 	}
> }
>+#ifdef CONFIG_PCI_KEYSTONE
>+/*
>+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>+ */
>+static void quirk_limit_readrequest(struct pci_dev *dev) {
>+	int readrq = pcie_get_readrq(dev);
>+
>+	if (readrq > 256)
>+		pcie_set_readrq(dev, 256);
>+}
>+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID,
>+quirk_limit_readrequest); #endif /* CONFIG_PCI_KEYSTONE */
>--
>1.7.9.5

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

* Re: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
  2014-05-15 16:01   ` Murali Karicheri
@ 2014-05-16 22:15     ` Kumar Gala
  -1 siblings, 0 replies; 116+ messages in thread
From: Kumar Gala @ 2014-05-16 22:15 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Jingoo Han,
	Mohit Kumar, Bjorn Helgaas, Santosh Shilimkar


On May 15, 2014, at 11:01 AM, Murali Karicheri <m-karicheri2@ti.com> wrote:

> keystone pcie hardware is based on designware hw version 3.65.
> There is no support for ATU port and has registers in
> application space to configure inbound/outbound access. Also
> doesn't support PCI PVM option. The MSI IRQ registers available
> in application space is used to mask/unmask/enable the MSI IRQs.
> 
> DW core driver is a set of common functions that are abstracted
> to support DW pci drivers. To allow re-use of these functions for
> keystone pci driver, core driver is to be enhanced.
> 
> Following are done to allow re-use of the functions on keystone pci
> driver.
> 
> 1. Some of the variables in pcie_port struct is folded inside
>    a union that now contains both new DW hw related variables as well
>    as old hardware related variables such as application reg base.
> 2. Added a dw_pcie_common_host_init() function that holds common
>    host initialization code for old and new hw.
> 3. dw_pcie_parse_resource() is used for parsing resource related
>    information from DT bindings.
> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>    Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>    Both these functions now call dw_pcie_common_host_init().
> 5. Some of the static functions are made global to allow use from
>    dw old pci drivers such as pci-keystone.

Can we split this into patches that do these 5 things?

Also, using OLD seems like a bad choice, what happens when we have NEW NEW in the future?

> 
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
> 2 files changed, 103 insertions(+), 40 deletions(-)
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index c4e3732..9ea8e79 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
> 		}
> 		set_bit(pos0 + i, pp->msi_irq_in_use);
> 		/*Enable corresponding interrupt in MSI interrupt controller */
> -		res = ((pos0 + i) / 32) * 12;
> -		bit = (pos0 + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> -		val |= 1 << bit;
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
> +		if (!(pp->version & DW_VERSION_OLD)) {
> +			res = ((pos0 + i) / 32) * 12;
> +			bit = (pos0 + i) % 32;
> +			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, &val);
> +			val |= 1 << bit;
> +			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, val);
> +		}
> 	}
> 
> 	*pos = pos0;
> @@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
> 	 */
> 	desc->msi_attrib.multiple = msgvec;
> 
> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
> +	if (pp->ops->get_msi_data)
> +		msg.address_lo = pp->ops->get_msi_data(pp);
> +	else
> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
> 	msg.address_hi = 0x0;
> 	msg.data = pos;
> 	write_msi_msg(irq, &msg);
> @@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
> 	.map = dw_pcie_msi_map,
> };
> 
> -int __init dw_pcie_host_init(struct pcie_port *pp)
> +int __init dw_pcie_parse_resource(struct pcie_port *pp)
> {
> 	struct device_node *np = pp->dev->of_node;
> -	struct of_pci_range range;
> 	struct of_pci_range_parser parser;
> -	u32 val;
> -	int i;
> +	struct of_pci_range range;
> 
> 	if (of_pci_range_parser_init(&parser, np)) {
> 		dev_err(pp->dev, "missing ranges property\n");
> @@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 			return -ENOMEM;
> 		}
> 	}
> -
> -	pp->cfg0_base = pp->cfg.start;
> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> 	pp->mem_base = pp->mem.start;
> 
> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> -					pp->config.cfg0_size);
> -	if (!pp->va_cfg0_base) {
> -		dev_err(pp->dev, "error with ioremap in function\n");
> -		return -ENOMEM;
> -	}
> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> -					pp->config.cfg1_size);
> -	if (!pp->va_cfg1_base) {
> -		dev_err(pp->dev, "error with ioremap\n");
> -		return -ENOMEM;
> -	}
> +	return 0;
> +}
> +
> +int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +				const struct irq_domain_ops *irq_msi_ops)
> +{
> +	struct device_node *np = pp->dev->of_node;
> +	u32 val;
> +	int i;
> 
> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
> 		dev_err(pp->dev, "Failed to parse the number of lanes\n");
> @@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
> -					MAX_MSI_IRQS, &msi_domain_ops,
> +					MAX_MSI_IRQS, irq_msi_ops,
> 					&dw_pcie_msi_chip);
> 		if (!pp->irq_domain) {
> 			dev_err(pp->dev, "irq domain init failed\n");
> @@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 	val |= PORT_LOGIC_SPEED_CHANGE;
> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
> 
> -	dw_pci.nr_controllers = 1;
> -	dw_pci.private_data = (void **)&pp;
> +	hw->nr_controllers = 1;
> +	hw->private_data = (void **)&pp;
> 
> -	pci_common_init_dev(pp->dev, &dw_pci);
> +	pci_common_init_dev(pp->dev, hw);
> 	pci_assign_unassigned_resources();
> #ifdef CONFIG_PCI_DOMAINS
> 	dw_pci.domain++;
> @@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 	return 0;
> }
> 
> +int __init dw_pcie_host_init(struct pcie_port *pp)
> +{
> +	int ret;
> +
> +	ret = dw_pcie_parse_resource(pp);
> +	if (ret)
> +		return ret;
> +
> +	pp->cfg0_base = pp->cfg.start;
> +	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> +	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> +					pp->config.cfg0_size);
> +	if (!pp->va_cfg0_base) {
> +		dev_err(pp->dev, "error with ioremap in function\n");
> +		return -ENOMEM;
> +	}
> +	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> +					pp->config.cfg1_size);
> +	if (!pp->va_cfg1_base) {
> +		dev_err(pp->dev, "error with ioremap\n");
> +		return -ENOMEM;
> +	}
> +
> +	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
> +}
> +
> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
> {
> 	/* Program viewport 0 : OUTBOUND : CFG0 */
> @@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
> 
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> +		if (pp->ops->rd_other_conf)
> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
> @@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
> 
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> +		if (pp->ops->wr_other_conf)
> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
> @@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
> 	.write = dw_pcie_wr_conf,
> };
> 
> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> {
> 	struct pcie_port *pp;
> 
> @@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> 	return 1;
> }
> 
> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> {
> 	struct pci_bus *bus;
> 	struct pcie_port *pp = sys_to_pcie(sys);
> @@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> 	return irq;
> }
> 
> -static void dw_pcie_add_bus(struct pci_bus *bus)
> +void dw_pcie_add_bus(struct pci_bus *bus)
> {
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index 3063b35..e97f4d7 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -35,21 +35,39 @@ struct pcie_port {
> 	struct device		*dev;
> 	u8			root_bus_nr;
> 	void __iomem		*dbi_base;
> -	u64			cfg0_base;
> -	void __iomem		*va_cfg0_base;
> -	u64			cfg1_base;
> -	void __iomem		*va_cfg1_base;
> +	/*
> +	 * Old DW version implement application register space for
> +	 * MSI and has no ATU view port
> +	 */
> +#define DW_VERSION_OLD	BIT(0)
> +	u32			version;
> +	union {
> +		/* new dw core specific */
> +		struct {
> +			u64		cfg0_base;
> +			void __iomem	*va_cfg0_base;
> +			u64		cfg1_base;
> +			void __iomem	*va_cfg1_base;
> +			int		msi_irq;
> +		};
> +
> +		/* old dw core specific */
> +		struct  {
> +			struct irq_domain	*legacy_irq_domain;
> +			void __iomem		*va_app_base;
> +			u64			app_base;
> +		};
> +	};
> 	u64			io_base;
> 	u64			mem_base;
> 	spinlock_t		conf_lock;
> -	struct resource		cfg;
> 	struct resource		io;
> 	struct resource		mem;
> +	struct resource		cfg;
> 	struct pcie_port_info	config;
> 	int			irq;
> 	u32			lanes;
> 	struct pcie_host_ops	*ops;
> -	int			msi_irq;
> 	struct irq_domain	*irq_domain;
> 	unsigned long		msi_data;
> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
> @@ -62,8 +80,13 @@ struct pcie_host_ops {
> 			u32 val, void __iomem *dbi_base);
> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 *val);
> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 val);
> 	int (*link_up)(struct pcie_port *pp);
> 	void (*host_init)(struct pcie_port *pp);
> +	u32 (*get_msi_data)(struct pcie_port *pp);
> };
> 
> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
> @@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
> int dw_pcie_link_up(struct pcie_port *pp);
> void dw_pcie_setup_rc(struct pcie_port *pp);
> int dw_pcie_host_init(struct pcie_port *pp);
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
> +void dw_pcie_add_bus(struct pci_bus *bus);
> +int dw_pcie_parse_resource(struct pcie_port *pp);
> 
> +/* internal to dw core */
> +int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +			const struct irq_domain_ops *irq_ops);
> #endif /* _PCIE_DESIGNWARE_H */
> -- 
> 1.7.9.5
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


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

* [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
@ 2014-05-16 22:15     ` Kumar Gala
  0 siblings, 0 replies; 116+ messages in thread
From: Kumar Gala @ 2014-05-16 22:15 UTC (permalink / raw)
  To: linux-arm-kernel


On May 15, 2014, at 11:01 AM, Murali Karicheri <m-karicheri2@ti.com> wrote:

> keystone pcie hardware is based on designware hw version 3.65.
> There is no support for ATU port and has registers in
> application space to configure inbound/outbound access. Also
> doesn't support PCI PVM option. The MSI IRQ registers available
> in application space is used to mask/unmask/enable the MSI IRQs.
> 
> DW core driver is a set of common functions that are abstracted
> to support DW pci drivers. To allow re-use of these functions for
> keystone pci driver, core driver is to be enhanced.
> 
> Following are done to allow re-use of the functions on keystone pci
> driver.
> 
> 1. Some of the variables in pcie_port struct is folded inside
>    a union that now contains both new DW hw related variables as well
>    as old hardware related variables such as application reg base.
> 2. Added a dw_pcie_common_host_init() function that holds common
>    host initialization code for old and new hw.
> 3. dw_pcie_parse_resource() is used for parsing resource related
>    information from DT bindings.
> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>    Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>    Both these functions now call dw_pcie_common_host_init().
> 5. Some of the static functions are made global to allow use from
>    dw old pci drivers such as pci-keystone.

Can we split this into patches that do these 5 things?

Also, using OLD seems like a bad choice, what happens when we have NEW NEW in the future?

> 
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
> 2 files changed, 103 insertions(+), 40 deletions(-)
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index c4e3732..9ea8e79 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
> 		}
> 		set_bit(pos0 + i, pp->msi_irq_in_use);
> 		/*Enable corresponding interrupt in MSI interrupt controller */
> -		res = ((pos0 + i) / 32) * 12;
> -		bit = (pos0 + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> -		val |= 1 << bit;
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
> +		if (!(pp->version & DW_VERSION_OLD)) {
> +			res = ((pos0 + i) / 32) * 12;
> +			bit = (pos0 + i) % 32;
> +			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, &val);
> +			val |= 1 << bit;
> +			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> +						 4, val);
> +		}
> 	}
> 
> 	*pos = pos0;
> @@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
> 	 */
> 	desc->msi_attrib.multiple = msgvec;
> 
> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
> +	if (pp->ops->get_msi_data)
> +		msg.address_lo = pp->ops->get_msi_data(pp);
> +	else
> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
> 	msg.address_hi = 0x0;
> 	msg.data = pos;
> 	write_msi_msg(irq, &msg);
> @@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
> 	.map = dw_pcie_msi_map,
> };
> 
> -int __init dw_pcie_host_init(struct pcie_port *pp)
> +int __init dw_pcie_parse_resource(struct pcie_port *pp)
> {
> 	struct device_node *np = pp->dev->of_node;
> -	struct of_pci_range range;
> 	struct of_pci_range_parser parser;
> -	u32 val;
> -	int i;
> +	struct of_pci_range range;
> 
> 	if (of_pci_range_parser_init(&parser, np)) {
> 		dev_err(pp->dev, "missing ranges property\n");
> @@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 			return -ENOMEM;
> 		}
> 	}
> -
> -	pp->cfg0_base = pp->cfg.start;
> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> 	pp->mem_base = pp->mem.start;
> 
> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> -					pp->config.cfg0_size);
> -	if (!pp->va_cfg0_base) {
> -		dev_err(pp->dev, "error with ioremap in function\n");
> -		return -ENOMEM;
> -	}
> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> -					pp->config.cfg1_size);
> -	if (!pp->va_cfg1_base) {
> -		dev_err(pp->dev, "error with ioremap\n");
> -		return -ENOMEM;
> -	}
> +	return 0;
> +}
> +
> +int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +				const struct irq_domain_ops *irq_msi_ops)
> +{
> +	struct device_node *np = pp->dev->of_node;
> +	u32 val;
> +	int i;
> 
> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
> 		dev_err(pp->dev, "Failed to parse the number of lanes\n");
> @@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
> -					MAX_MSI_IRQS, &msi_domain_ops,
> +					MAX_MSI_IRQS, irq_msi_ops,
> 					&dw_pcie_msi_chip);
> 		if (!pp->irq_domain) {
> 			dev_err(pp->dev, "irq domain init failed\n");
> @@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 	val |= PORT_LOGIC_SPEED_CHANGE;
> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
> 
> -	dw_pci.nr_controllers = 1;
> -	dw_pci.private_data = (void **)&pp;
> +	hw->nr_controllers = 1;
> +	hw->private_data = (void **)&pp;
> 
> -	pci_common_init_dev(pp->dev, &dw_pci);
> +	pci_common_init_dev(pp->dev, hw);
> 	pci_assign_unassigned_resources();
> #ifdef CONFIG_PCI_DOMAINS
> 	dw_pci.domain++;
> @@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> 	return 0;
> }
> 
> +int __init dw_pcie_host_init(struct pcie_port *pp)
> +{
> +	int ret;
> +
> +	ret = dw_pcie_parse_resource(pp);
> +	if (ret)
> +		return ret;
> +
> +	pp->cfg0_base = pp->cfg.start;
> +	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> +	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> +					pp->config.cfg0_size);
> +	if (!pp->va_cfg0_base) {
> +		dev_err(pp->dev, "error with ioremap in function\n");
> +		return -ENOMEM;
> +	}
> +	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> +					pp->config.cfg1_size);
> +	if (!pp->va_cfg1_base) {
> +		dev_err(pp->dev, "error with ioremap\n");
> +		return -ENOMEM;
> +	}
> +
> +	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
> +}
> +
> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
> {
> 	/* Program viewport 0 : OUTBOUND : CFG0 */
> @@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
> 
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> +		if (pp->ops->rd_other_conf)
> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
> @@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
> 
> 	spin_lock_irqsave(&pp->conf_lock, flags);
> 	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> +		if (pp->ops->wr_other_conf)
> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> 						where, size, val);
> 	else
> 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
> @@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
> 	.write = dw_pcie_wr_conf,
> };
> 
> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> {
> 	struct pcie_port *pp;
> 
> @@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> 	return 1;
> }
> 
> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> {
> 	struct pci_bus *bus;
> 	struct pcie_port *pp = sys_to_pcie(sys);
> @@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> 	return irq;
> }
> 
> -static void dw_pcie_add_bus(struct pci_bus *bus)
> +void dw_pcie_add_bus(struct pci_bus *bus)
> {
> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index 3063b35..e97f4d7 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -35,21 +35,39 @@ struct pcie_port {
> 	struct device		*dev;
> 	u8			root_bus_nr;
> 	void __iomem		*dbi_base;
> -	u64			cfg0_base;
> -	void __iomem		*va_cfg0_base;
> -	u64			cfg1_base;
> -	void __iomem		*va_cfg1_base;
> +	/*
> +	 * Old DW version implement application register space for
> +	 * MSI and has no ATU view port
> +	 */
> +#define DW_VERSION_OLD	BIT(0)
> +	u32			version;
> +	union {
> +		/* new dw core specific */
> +		struct {
> +			u64		cfg0_base;
> +			void __iomem	*va_cfg0_base;
> +			u64		cfg1_base;
> +			void __iomem	*va_cfg1_base;
> +			int		msi_irq;
> +		};
> +
> +		/* old dw core specific */
> +		struct  {
> +			struct irq_domain	*legacy_irq_domain;
> +			void __iomem		*va_app_base;
> +			u64			app_base;
> +		};
> +	};
> 	u64			io_base;
> 	u64			mem_base;
> 	spinlock_t		conf_lock;
> -	struct resource		cfg;
> 	struct resource		io;
> 	struct resource		mem;
> +	struct resource		cfg;
> 	struct pcie_port_info	config;
> 	int			irq;
> 	u32			lanes;
> 	struct pcie_host_ops	*ops;
> -	int			msi_irq;
> 	struct irq_domain	*irq_domain;
> 	unsigned long		msi_data;
> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
> @@ -62,8 +80,13 @@ struct pcie_host_ops {
> 			u32 val, void __iomem *dbi_base);
> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 *val);
> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 val);
> 	int (*link_up)(struct pcie_port *pp);
> 	void (*host_init)(struct pcie_port *pp);
> +	u32 (*get_msi_data)(struct pcie_port *pp);
> };
> 
> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
> @@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
> int dw_pcie_link_up(struct pcie_port *pp);
> void dw_pcie_setup_rc(struct pcie_port *pp);
> int dw_pcie_host_init(struct pcie_port *pp);
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
> +void dw_pcie_add_bus(struct pci_bus *bus);
> +int dw_pcie_parse_resource(struct pcie_port *pp);
> 
> +/* internal to dw core */
> +int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +			const struct irq_domain_ops *irq_ops);
> #endif /* _PCIE_DESIGNWARE_H */
> -- 
> 1.7.9.5
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 16:28     ` Arnd Bergmann
  (?)
@ 2014-05-16 22:44       ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 22:44 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, xobs, Strashko,
	Grygorii, Mohit Kumar, Jingoo Han, Shilimkar, Santosh,
	Bjorn Helgaas

On 5/15/2014 12:28 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>> +Sample bindings shown below:-
>> +
>> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>> +   configuration.
>> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>> +   link
> You actually have to document all the properties. Have a look at the
> other bindings for what this means.

Actually this is dw pcie variant. So I will document if there are any 
deviations from the dw-designware
bindings. Based on comments from Jingo, I think I need to add a new DT 
property for old hw that we
use in keystone. May be a compatibility string for older dw h/w like 
"snps ,dw-pcie-v3.65" is that we
could use and do things differently in the common code.

So I will update the Documentation of dw bindings  once we agree on this.
>> +
>> +               pcie@21800000 {
>> +                       compatible = "ti,keystone-pcie";
>> +                       device_type = "pci";
>> +                       clocks = <&clkpcie>;
>> +                       clock-names = "pcie";
> The dw-pcie binding lists two clocks.
Ok. As per dw documentation, pcie and pcie_bus are the clocks. But 
pci-imx6 is currently not using pcie_bus. So the pcie_bus
clock is actually optional. In the case of keystone pcie, bus clock is 
provided by the phy hardware and if I need to provide
a clock for bus, it has to be a dummy or change documentation to make 
pcie_bus an optional clock. I prefer later, but want
to know if this is true for pci-imx6. There is also a plan to move the 
pcie clock API call to designware core. So making pcie_bus
clock optional looks correct to me.

Seen/Jingoo,  any comments?

>> +                       #address-cells = >;
>> +                       #size-cells = <2>;
>> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>> +                       reg-names = "reg_rc_app", "reg_devcfg";
> There should be standard names that are documented in the binding.

Currently  Documentation says

- reg: base addresses and lengths of the pcie controller,
     the phy controller, additional register for the phy controller.

And following dw drivers defines as

samsung,exynos5440-pcie

         reg = <0x290000 0x1000
             0x270000 0x1000
             0x271000 0x40>;

fsl,imx6q-pcie"
         reg = <0x01ffc000 0x4000>; /* DBI */

There are no names used for registers. So this needs to be documented in 
the dw-designware
bindings. reg_dbi is what is common to pci controller assuming at index 
0 of the both above drivers use
reg_dbi address for config space. Shall I modify the documentation to 
include optional reg name
reg_dbi  for config space base address registers? Additional registers 
are optional and varies from
platform to platform. Phy registers are actually part of Phy driver and 
should be removed from
the dw-documentation bindings. Agree?

>
>> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
> What are all these interrupts?
These are MSI interrupts tied to the GIC over which MSI interrupts are 
multiplexed.  I will document
it in the keystone PCI DT bindings.
>> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
>> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
>> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
> Please move the config space into 'reg' now instead of 'ranges'.
> This was a mistake earlier, and there are already other front-ends
> doing the same thing.
  This has to be coordinated with other drivers when DW core makes the 
change.

Jingoo, Sean,

What is the plan for this change? I  have to defer this currently.

>
>> +                       num-lanes = <2>;
>> +                       ti,enable-linktrain;
>> +                       ti,init-phy;
>> +
>> +                       /* PCIE phy */
>> +                       phys = <&pcie0_phy>;
>> +                       phy-names = "pcie-phy";
>> +
>> +                       #interrupt-cells = <1>;
>> +                       interrupt-map-mask = <0 0 0 0>;
>> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
>> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
>> +                                       <0 0 0 4 &pcie_intc 4>; // INT D
> I think this is the wrong map-mask.
I think this should be changed to

interrupt-map-mask = <0 0 0 0x7> ?

>
> 	Arnd


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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 22:44       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 22:44 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, xobs, Strashko,
	Grygorii, Mohit Kumar, Jingoo Han, Shilimkar, Santosh,
	Bjorn Helgaas

On 5/15/2014 12:28 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>> +Sample bindings shown below:-
>> +
>> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>> +   configuration.
>> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>> +   link
> You actually have to document all the properties. Have a look at the
> other bindings for what this means.

Actually this is dw pcie variant. So I will document if there are any 
deviations from the dw-designware
bindings. Based on comments from Jingo, I think I need to add a new DT 
property for old hw that we
use in keystone. May be a compatibility string for older dw h/w like 
"snps ,dw-pcie-v3.65" is that we
could use and do things differently in the common code.

So I will update the Documentation of dw bindings  once we agree on this.
>> +
>> +               pcie@21800000 {
>> +                       compatible = "ti,keystone-pcie";
>> +                       device_type = "pci";
>> +                       clocks = <&clkpcie>;
>> +                       clock-names = "pcie";
> The dw-pcie binding lists two clocks.
Ok. As per dw documentation, pcie and pcie_bus are the clocks. But 
pci-imx6 is currently not using pcie_bus. So the pcie_bus
clock is actually optional. In the case of keystone pcie, bus clock is 
provided by the phy hardware and if I need to provide
a clock for bus, it has to be a dummy or change documentation to make 
pcie_bus an optional clock. I prefer later, but want
to know if this is true for pci-imx6. There is also a plan to move the 
pcie clock API call to designware core. So making pcie_bus
clock optional looks correct to me.

Seen/Jingoo,  any comments?

>> +                       #address-cells = >;
>> +                       #size-cells = <2>;
>> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>> +                       reg-names = "reg_rc_app", "reg_devcfg";
> There should be standard names that are documented in the binding.

Currently  Documentation says

- reg: base addresses and lengths of the pcie controller,
     the phy controller, additional register for the phy controller.

And following dw drivers defines as

samsung,exynos5440-pcie

         reg = <0x290000 0x1000
             0x270000 0x1000
             0x271000 0x40>;

fsl,imx6q-pcie"
         reg = <0x01ffc000 0x4000>; /* DBI */

There are no names used for registers. So this needs to be documented in 
the dw-designware
bindings. reg_dbi is what is common to pci controller assuming at index 
0 of the both above drivers use
reg_dbi address for config space. Shall I modify the documentation to 
include optional reg name
reg_dbi  for config space base address registers? Additional registers 
are optional and varies from
platform to platform. Phy registers are actually part of Phy driver and 
should be removed from
the dw-documentation bindings. Agree?

>
>> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
> What are all these interrupts?
These are MSI interrupts tied to the GIC over which MSI interrupts are 
multiplexed.  I will document
it in the keystone PCI DT bindings.
>> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
>> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
>> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
> Please move the config space into 'reg' now instead of 'ranges'.
> This was a mistake earlier, and there are already other front-ends
> doing the same thing.
  This has to be coordinated with other drivers when DW core makes the 
change.

Jingoo, Sean,

What is the plan for this change? I  have to defer this currently.

>
>> +                       num-lanes = <2>;
>> +                       ti,enable-linktrain;
>> +                       ti,init-phy;
>> +
>> +                       /* PCIE phy */
>> +                       phys = <&pcie0_phy>;
>> +                       phy-names = "pcie-phy";
>> +
>> +                       #interrupt-cells = <1>;
>> +                       interrupt-map-mask = <0 0 0 0>;
>> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
>> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
>> +                                       <0 0 0 4 &pcie_intc 4>; // INT D
> I think this is the wrong map-mask.
I think this should be changed to

interrupt-map-mask = <0 0 0 0x7> ?

>
> 	Arnd


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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-16 22:44       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 22:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/15/2014 12:28 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>> +Sample bindings shown below:-
>> +
>> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>> +   configuration.
>> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>> +   link
> You actually have to document all the properties. Have a look at the
> other bindings for what this means.

Actually this is dw pcie variant. So I will document if there are any 
deviations from the dw-designware
bindings. Based on comments from Jingo, I think I need to add a new DT 
property for old hw that we
use in keystone. May be a compatibility string for older dw h/w like 
"snps ,dw-pcie-v3.65" is that we
could use and do things differently in the common code.

So I will update the Documentation of dw bindings  once we agree on this.
>> +
>> +               pcie at 21800000 {
>> +                       compatible = "ti,keystone-pcie";
>> +                       device_type = "pci";
>> +                       clocks = <&clkpcie>;
>> +                       clock-names = "pcie";
> The dw-pcie binding lists two clocks.
Ok. As per dw documentation, pcie and pcie_bus are the clocks. But 
pci-imx6 is currently not using pcie_bus. So the pcie_bus
clock is actually optional. In the case of keystone pcie, bus clock is 
provided by the phy hardware and if I need to provide
a clock for bus, it has to be a dummy or change documentation to make 
pcie_bus an optional clock. I prefer later, but want
to know if this is true for pci-imx6. There is also a plan to move the 
pcie clock API call to designware core. So making pcie_bus
clock optional looks correct to me.

Seen/Jingoo,  any comments?

>> +                       #address-cells = >;
>> +                       #size-cells = <2>;
>> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>> +                       reg-names = "reg_rc_app", "reg_devcfg";
> There should be standard names that are documented in the binding.

Currently  Documentation says

- reg: base addresses and lengths of the pcie controller,
     the phy controller, additional register for the phy controller.

And following dw drivers defines as

samsung,exynos5440-pcie

         reg = <0x290000 0x1000
             0x270000 0x1000
             0x271000 0x40>;

fsl,imx6q-pcie"
         reg = <0x01ffc000 0x4000>; /* DBI */

There are no names used for registers. So this needs to be documented in 
the dw-designware
bindings. reg_dbi is what is common to pci controller assuming at index 
0 of the both above drivers use
reg_dbi address for config space. Shall I modify the documentation to 
include optional reg name
reg_dbi  for config space base address registers? Additional registers 
are optional and varies from
platform to platform. Phy registers are actually part of Phy driver and 
should be removed from
the dw-documentation bindings. Agree?

>
>> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
> What are all these interrupts?
These are MSI interrupts tied to the GIC over which MSI interrupts are 
multiplexed.  I will document
it in the keystone PCI DT bindings.
>> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
>> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
>> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
> Please move the config space into 'reg' now instead of 'ranges'.
> This was a mistake earlier, and there are already other front-ends
> doing the same thing.
  This has to be coordinated with other drivers when DW core makes the 
change.

Jingoo, Sean,

What is the plan for this change? I  have to defer this currently.

>
>> +                       num-lanes = <2>;
>> +                       ti,enable-linktrain;
>> +                       ti,init-phy;
>> +
>> +                       /* PCIE phy */
>> +                       phys = <&pcie0_phy>;
>> +                       phy-names = "pcie-phy";
>> +
>> +                       #interrupt-cells = <1>;
>> +                       interrupt-map-mask = <0 0 0 0>;
>> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
>> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
>> +                                       <0 0 0 4 &pcie_intc 4>; // INT D
> I think this is the wrong map-mask.
I think this should be changed to

interrupt-map-mask = <0 0 0 0x7> ?

>
> 	Arnd

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

* Re: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
  2014-05-16 22:15     ` Kumar Gala
  (?)
@ 2014-05-16 22:49       ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 22:49 UTC (permalink / raw)
  To: Kumar Gala
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Jingoo Han,
	Mohit Kumar, Bjorn Helgaas, Shilimkar, Santosh

On 5/16/2014 6:15 PM, Kumar Gala wrote:
> On May 15, 2014, at 11:01 AM, Murali Karicheri <m-karicheri2@ti.com> wrote:
>
>> keystone pcie hardware is based on designware hw version 3.65.
>> There is no support for ATU port and has registers in
>> application space to configure inbound/outbound access. Also
>> doesn't support PCI PVM option. The MSI IRQ registers available
>> in application space is used to mask/unmask/enable the MSI IRQs.
>>
>> DW core driver is a set of common functions that are abstracted
>> to support DW pci drivers. To allow re-use of these functions for
>> keystone pci driver, core driver is to be enhanced.
>>
>> Following are done to allow re-use of the functions on keystone pci
>> driver.
>>
>> 1. Some of the variables in pcie_port struct is folded inside
>>     a union that now contains both new DW hw related variables as well
>>     as old hardware related variables such as application reg base.
>> 2. Added a dw_pcie_common_host_init() function that holds common
>>     host initialization code for old and new hw.
>> 3. dw_pcie_parse_resource() is used for parsing resource related
>>     information from DT bindings.
>> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>>     Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>>     Both these functions now call dw_pcie_common_host_init().
>> 5. Some of the static functions are made global to allow use from
>>     dw old pci drivers such as pci-keystone.
> Can we split this into patches that do these 5 things?
>
> Also, using OLD seems like a bad choice, what happens when we have NEW NEW in the future?
I suggested using a compatibility  that includes v3.65 version string to 
differentiate and treat
the code differently for the dw hw that is used on keystone SoC.

>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
>> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
>> 2 files changed, 103 insertions(+), 40 deletions(-)
>> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
>> index c4e3732..9ea8e79 100644
>> --- a/drivers/pci/host/pcie-designware.c
>> +++ b/drivers/pci/host/pcie-designware.c
>> @@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
>> 		}
>> 		set_bit(pos0 + i, pp->msi_irq_in_use);
>> 		/*Enable corresponding interrupt in MSI interrupt controller */
>> -		res = ((pos0 + i) / 32) * 12;
>> -		bit = (pos0 + i) % 32;
>> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>> -		val |= 1 << bit;
>> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>> +		if (!(pp->version & DW_VERSION_OLD)) {
>> +			res = ((pos0 + i) / 32) * 12;
>> +			bit = (pos0 + i) % 32;
>> +			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> +						 4, &val);
>> +			val |= 1 << bit;
>> +			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> +						 4, val);
>> +		}
>> 	}
>>
>> 	*pos = pos0;
>> @@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
>> 	 */
>> 	desc->msi_attrib.multiple = msgvec;
>>
>> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
>> +	if (pp->ops->get_msi_data)
>> +		msg.address_lo = pp->ops->get_msi_data(pp);
>> +	else
>> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>> 	msg.address_hi = 0x0;
>> 	msg.data = pos;
>> 	write_msi_msg(irq, &msg);
>> @@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
>> 	.map = dw_pcie_msi_map,
>> };
>>
>> -int __init dw_pcie_host_init(struct pcie_port *pp)
>> +int __init dw_pcie_parse_resource(struct pcie_port *pp)
>> {
>> 	struct device_node *np = pp->dev->of_node;
>> -	struct of_pci_range range;
>> 	struct of_pci_range_parser parser;
>> -	u32 val;
>> -	int i;
>> +	struct of_pci_range range;
>>
>> 	if (of_pci_range_parser_init(&parser, np)) {
>> 		dev_err(pp->dev, "missing ranges property\n");
>> @@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 			return -ENOMEM;
>> 		}
>> 	}
>> -
>> -	pp->cfg0_base = pp->cfg.start;
>> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>> 	pp->mem_base = pp->mem.start;
>>
>> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>> -					pp->config.cfg0_size);
>> -	if (!pp->va_cfg0_base) {
>> -		dev_err(pp->dev, "error with ioremap in function\n");
>> -		return -ENOMEM;
>> -	}
>> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>> -					pp->config.cfg1_size);
>> -	if (!pp->va_cfg1_base) {
>> -		dev_err(pp->dev, "error with ioremap\n");
>> -		return -ENOMEM;
>> -	}
>> +	return 0;
>> +}
>> +
>> +int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>> +				const struct irq_domain_ops *irq_msi_ops)
>> +{
>> +	struct device_node *np = pp->dev->of_node;
>> +	u32 val;
>> +	int i;
>>
>> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
>> 		dev_err(pp->dev, "Failed to parse the number of lanes\n");
>> @@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>>
>> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
>> -					MAX_MSI_IRQS, &msi_domain_ops,
>> +					MAX_MSI_IRQS, irq_msi_ops,
>> 					&dw_pcie_msi_chip);
>> 		if (!pp->irq_domain) {
>> 			dev_err(pp->dev, "irq domain init failed\n");
>> @@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 	val |= PORT_LOGIC_SPEED_CHANGE;
>> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>>
>> -	dw_pci.nr_controllers = 1;
>> -	dw_pci.private_data = (void **)&pp;
>> +	hw->nr_controllers = 1;
>> +	hw->private_data = (void **)&pp;
>>
>> -	pci_common_init_dev(pp->dev, &dw_pci);
>> +	pci_common_init_dev(pp->dev, hw);
>> 	pci_assign_unassigned_resources();
>> #ifdef CONFIG_PCI_DOMAINS
>> 	dw_pci.domain++;
>> @@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 	return 0;
>> }
>>
>> +int __init dw_pcie_host_init(struct pcie_port *pp)
>> +{
>> +	int ret;
>> +
>> +	ret = dw_pcie_parse_resource(pp);
>> +	if (ret)
>> +		return ret;
>> +
>> +	pp->cfg0_base = pp->cfg.start;
>> +	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>> +	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>> +					pp->config.cfg0_size);
>> +	if (!pp->va_cfg0_base) {
>> +		dev_err(pp->dev, "error with ioremap in function\n");
>> +		return -ENOMEM;
>> +	}
>> +	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>> +					pp->config.cfg1_size);
>> +	if (!pp->va_cfg1_base) {
>> +		dev_err(pp->dev, "error with ioremap\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
>> +}
>> +
>> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
>> {
>> 	/* Program viewport 0 : OUTBOUND : CFG0 */
>> @@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
>>
>> 	spin_lock_irqsave(&pp->conf_lock, flags);
>> 	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>> +		if (pp->ops->rd_other_conf)
>> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>> 						where, size, val);
>> 	else
>> 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
>> @@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
>>
>> 	spin_lock_irqsave(&pp->conf_lock, flags);
>> 	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>> +		if (pp->ops->wr_other_conf)
>> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>> 						where, size, val);
>> 	else
>> 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
>> @@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
>> 	.write = dw_pcie_wr_conf,
>> };
>>
>> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> {
>> 	struct pcie_port *pp;
>>
>> @@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> 	return 1;
>> }
>>
>> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> {
>> 	struct pci_bus *bus;
>> 	struct pcie_port *pp = sys_to_pcie(sys);
>> @@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>> 	return irq;
>> }
>>
>> -static void dw_pcie_add_bus(struct pci_bus *bus)
>> +void dw_pcie_add_bus(struct pci_bus *bus)
>> {
>> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
>> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
>> index 3063b35..e97f4d7 100644
>> --- a/drivers/pci/host/pcie-designware.h
>> +++ b/drivers/pci/host/pcie-designware.h
>> @@ -35,21 +35,39 @@ struct pcie_port {
>> 	struct device		*dev;
>> 	u8			root_bus_nr;
>> 	void __iomem		*dbi_base;
>> -	u64			cfg0_base;
>> -	void __iomem		*va_cfg0_base;
>> -	u64			cfg1_base;
>> -	void __iomem		*va_cfg1_base;
>> +	/*
>> +	 * Old DW version implement application register space for
>> +	 * MSI and has no ATU view port
>> +	 */
>> +#define DW_VERSION_OLD	BIT(0)
>> +	u32			version;
>> +	union {
>> +		/* new dw core specific */
>> +		struct {
>> +			u64		cfg0_base;
>> +			void __iomem	*va_cfg0_base;
>> +			u64		cfg1_base;
>> +			void __iomem	*va_cfg1_base;
>> +			int		msi_irq;
>> +		};
>> +
>> +		/* old dw core specific */
>> +		struct  {
>> +			struct irq_domain	*legacy_irq_domain;
>> +			void __iomem		*va_app_base;
>> +			u64			app_base;
>> +		};
>> +	};
>> 	u64			io_base;
>> 	u64			mem_base;
>> 	spinlock_t		conf_lock;
>> -	struct resource		cfg;
>> 	struct resource		io;
>> 	struct resource		mem;
>> +	struct resource		cfg;
>> 	struct pcie_port_info	config;
>> 	int			irq;
>> 	u32			lanes;
>> 	struct pcie_host_ops	*ops;
>> -	int			msi_irq;
>> 	struct irq_domain	*irq_domain;
>> 	unsigned long		msi_data;
>> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
>> @@ -62,8 +80,13 @@ struct pcie_host_ops {
>> 			u32 val, void __iomem *dbi_base);
>> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
>> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
>> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 *val);
>> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 val);
>> 	int (*link_up)(struct pcie_port *pp);
>> 	void (*host_init)(struct pcie_port *pp);
>> +	u32 (*get_msi_data)(struct pcie_port *pp);
>> };
>>
>> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
>> @@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>> int dw_pcie_link_up(struct pcie_port *pp);
>> void dw_pcie_setup_rc(struct pcie_port *pp);
>> int dw_pcie_host_init(struct pcie_port *pp);
>> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
>> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
>> +void dw_pcie_add_bus(struct pci_bus *bus);
>> +int dw_pcie_parse_resource(struct pcie_port *pp);
>>
>> +/* internal to dw core */
>> +int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>> +			const struct irq_domain_ops *irq_ops);
>> #endif /* _PCIE_DESIGNWARE_H */
>> -- 
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


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

* Re: [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
@ 2014-05-16 22:49       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 22:49 UTC (permalink / raw)
  To: Kumar Gala
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Jingoo Han,
	Mohit Kumar, Bjorn Helgaas, Shilimkar, Santosh

On 5/16/2014 6:15 PM, Kumar Gala wrote:
> On May 15, 2014, at 11:01 AM, Murali Karicheri <m-karicheri2@ti.com> wrote:
>
>> keystone pcie hardware is based on designware hw version 3.65.
>> There is no support for ATU port and has registers in
>> application space to configure inbound/outbound access. Also
>> doesn't support PCI PVM option. The MSI IRQ registers available
>> in application space is used to mask/unmask/enable the MSI IRQs.
>>
>> DW core driver is a set of common functions that are abstracted
>> to support DW pci drivers. To allow re-use of these functions for
>> keystone pci driver, core driver is to be enhanced.
>>
>> Following are done to allow re-use of the functions on keystone pci
>> driver.
>>
>> 1. Some of the variables in pcie_port struct is folded inside
>>     a union that now contains both new DW hw related variables as well
>>     as old hardware related variables such as application reg base.
>> 2. Added a dw_pcie_common_host_init() function that holds common
>>     host initialization code for old and new hw.
>> 3. dw_pcie_parse_resource() is used for parsing resource related
>>     information from DT bindings.
>> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>>     Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>>     Both these functions now call dw_pcie_common_host_init().
>> 5. Some of the static functions are made global to allow use from
>>     dw old pci drivers such as pci-keystone.
> Can we split this into patches that do these 5 things?
>
> Also, using OLD seems like a bad choice, what happens when we have NEW NEW in the future?
I suggested using a compatibility  that includes v3.65 version string to 
differentiate and treat
the code differently for the dw hw that is used on keystone SoC.

>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
>> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
>> 2 files changed, 103 insertions(+), 40 deletions(-)
>> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
>> index c4e3732..9ea8e79 100644
>> --- a/drivers/pci/host/pcie-designware.c
>> +++ b/drivers/pci/host/pcie-designware.c
>> @@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
>> 		}
>> 		set_bit(pos0 + i, pp->msi_irq_in_use);
>> 		/*Enable corresponding interrupt in MSI interrupt controller */
>> -		res = ((pos0 + i) / 32) * 12;
>> -		bit = (pos0 + i) % 32;
>> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>> -		val |= 1 << bit;
>> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>> +		if (!(pp->version & DW_VERSION_OLD)) {
>> +			res = ((pos0 + i) / 32) * 12;
>> +			bit = (pos0 + i) % 32;
>> +			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> +						 4, &val);
>> +			val |= 1 << bit;
>> +			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> +						 4, val);
>> +		}
>> 	}
>>
>> 	*pos = pos0;
>> @@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
>> 	 */
>> 	desc->msi_attrib.multiple = msgvec;
>>
>> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
>> +	if (pp->ops->get_msi_data)
>> +		msg.address_lo = pp->ops->get_msi_data(pp);
>> +	else
>> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>> 	msg.address_hi = 0x0;
>> 	msg.data = pos;
>> 	write_msi_msg(irq, &msg);
>> @@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
>> 	.map = dw_pcie_msi_map,
>> };
>>
>> -int __init dw_pcie_host_init(struct pcie_port *pp)
>> +int __init dw_pcie_parse_resource(struct pcie_port *pp)
>> {
>> 	struct device_node *np = pp->dev->of_node;
>> -	struct of_pci_range range;
>> 	struct of_pci_range_parser parser;
>> -	u32 val;
>> -	int i;
>> +	struct of_pci_range range;
>>
>> 	if (of_pci_range_parser_init(&parser, np)) {
>> 		dev_err(pp->dev, "missing ranges property\n");
>> @@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 			return -ENOMEM;
>> 		}
>> 	}
>> -
>> -	pp->cfg0_base = pp->cfg.start;
>> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>> 	pp->mem_base = pp->mem.start;
>>
>> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>> -					pp->config.cfg0_size);
>> -	if (!pp->va_cfg0_base) {
>> -		dev_err(pp->dev, "error with ioremap in function\n");
>> -		return -ENOMEM;
>> -	}
>> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>> -					pp->config.cfg1_size);
>> -	if (!pp->va_cfg1_base) {
>> -		dev_err(pp->dev, "error with ioremap\n");
>> -		return -ENOMEM;
>> -	}
>> +	return 0;
>> +}
>> +
>> +int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>> +				const struct irq_domain_ops *irq_msi_ops)
>> +{
>> +	struct device_node *np = pp->dev->of_node;
>> +	u32 val;
>> +	int i;
>>
>> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
>> 		dev_err(pp->dev, "Failed to parse the number of lanes\n");
>> @@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>>
>> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
>> -					MAX_MSI_IRQS, &msi_domain_ops,
>> +					MAX_MSI_IRQS, irq_msi_ops,
>> 					&dw_pcie_msi_chip);
>> 		if (!pp->irq_domain) {
>> 			dev_err(pp->dev, "irq domain init failed\n");
>> @@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 	val |= PORT_LOGIC_SPEED_CHANGE;
>> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>>
>> -	dw_pci.nr_controllers = 1;
>> -	dw_pci.private_data = (void **)&pp;
>> +	hw->nr_controllers = 1;
>> +	hw->private_data = (void **)&pp;
>>
>> -	pci_common_init_dev(pp->dev, &dw_pci);
>> +	pci_common_init_dev(pp->dev, hw);
>> 	pci_assign_unassigned_resources();
>> #ifdef CONFIG_PCI_DOMAINS
>> 	dw_pci.domain++;
>> @@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 	return 0;
>> }
>>
>> +int __init dw_pcie_host_init(struct pcie_port *pp)
>> +{
>> +	int ret;
>> +
>> +	ret = dw_pcie_parse_resource(pp);
>> +	if (ret)
>> +		return ret;
>> +
>> +	pp->cfg0_base = pp->cfg.start;
>> +	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>> +	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>> +					pp->config.cfg0_size);
>> +	if (!pp->va_cfg0_base) {
>> +		dev_err(pp->dev, "error with ioremap in function\n");
>> +		return -ENOMEM;
>> +	}
>> +	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>> +					pp->config.cfg1_size);
>> +	if (!pp->va_cfg1_base) {
>> +		dev_err(pp->dev, "error with ioremap\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
>> +}
>> +
>> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
>> {
>> 	/* Program viewport 0 : OUTBOUND : CFG0 */
>> @@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
>>
>> 	spin_lock_irqsave(&pp->conf_lock, flags);
>> 	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>> +		if (pp->ops->rd_other_conf)
>> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>> 						where, size, val);
>> 	else
>> 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
>> @@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
>>
>> 	spin_lock_irqsave(&pp->conf_lock, flags);
>> 	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>> +		if (pp->ops->wr_other_conf)
>> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>> 						where, size, val);
>> 	else
>> 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
>> @@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
>> 	.write = dw_pcie_wr_conf,
>> };
>>
>> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> {
>> 	struct pcie_port *pp;
>>
>> @@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> 	return 1;
>> }
>>
>> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> {
>> 	struct pci_bus *bus;
>> 	struct pcie_port *pp = sys_to_pcie(sys);
>> @@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>> 	return irq;
>> }
>>
>> -static void dw_pcie_add_bus(struct pci_bus *bus)
>> +void dw_pcie_add_bus(struct pci_bus *bus)
>> {
>> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
>> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
>> index 3063b35..e97f4d7 100644
>> --- a/drivers/pci/host/pcie-designware.h
>> +++ b/drivers/pci/host/pcie-designware.h
>> @@ -35,21 +35,39 @@ struct pcie_port {
>> 	struct device		*dev;
>> 	u8			root_bus_nr;
>> 	void __iomem		*dbi_base;
>> -	u64			cfg0_base;
>> -	void __iomem		*va_cfg0_base;
>> -	u64			cfg1_base;
>> -	void __iomem		*va_cfg1_base;
>> +	/*
>> +	 * Old DW version implement application register space for
>> +	 * MSI and has no ATU view port
>> +	 */
>> +#define DW_VERSION_OLD	BIT(0)
>> +	u32			version;
>> +	union {
>> +		/* new dw core specific */
>> +		struct {
>> +			u64		cfg0_base;
>> +			void __iomem	*va_cfg0_base;
>> +			u64		cfg1_base;
>> +			void __iomem	*va_cfg1_base;
>> +			int		msi_irq;
>> +		};
>> +
>> +		/* old dw core specific */
>> +		struct  {
>> +			struct irq_domain	*legacy_irq_domain;
>> +			void __iomem		*va_app_base;
>> +			u64			app_base;
>> +		};
>> +	};
>> 	u64			io_base;
>> 	u64			mem_base;
>> 	spinlock_t		conf_lock;
>> -	struct resource		cfg;
>> 	struct resource		io;
>> 	struct resource		mem;
>> +	struct resource		cfg;
>> 	struct pcie_port_info	config;
>> 	int			irq;
>> 	u32			lanes;
>> 	struct pcie_host_ops	*ops;
>> -	int			msi_irq;
>> 	struct irq_domain	*irq_domain;
>> 	unsigned long		msi_data;
>> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
>> @@ -62,8 +80,13 @@ struct pcie_host_ops {
>> 			u32 val, void __iomem *dbi_base);
>> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
>> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
>> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 *val);
>> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 val);
>> 	int (*link_up)(struct pcie_port *pp);
>> 	void (*host_init)(struct pcie_port *pp);
>> +	u32 (*get_msi_data)(struct pcie_port *pp);
>> };
>>
>> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
>> @@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>> int dw_pcie_link_up(struct pcie_port *pp);
>> void dw_pcie_setup_rc(struct pcie_port *pp);
>> int dw_pcie_host_init(struct pcie_port *pp);
>> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
>> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
>> +void dw_pcie_add_bus(struct pci_bus *bus);
>> +int dw_pcie_parse_resource(struct pcie_port *pp);
>>
>> +/* internal to dw core */
>> +int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>> +			const struct irq_domain_ops *irq_ops);
>> #endif /* _PCIE_DESIGNWARE_H */
>> -- 
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


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

* [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie
@ 2014-05-16 22:49       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-16 22:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/16/2014 6:15 PM, Kumar Gala wrote:
> On May 15, 2014, at 11:01 AM, Murali Karicheri <m-karicheri2@ti.com> wrote:
>
>> keystone pcie hardware is based on designware hw version 3.65.
>> There is no support for ATU port and has registers in
>> application space to configure inbound/outbound access. Also
>> doesn't support PCI PVM option. The MSI IRQ registers available
>> in application space is used to mask/unmask/enable the MSI IRQs.
>>
>> DW core driver is a set of common functions that are abstracted
>> to support DW pci drivers. To allow re-use of these functions for
>> keystone pci driver, core driver is to be enhanced.
>>
>> Following are done to allow re-use of the functions on keystone pci
>> driver.
>>
>> 1. Some of the variables in pcie_port struct is folded inside
>>     a union that now contains both new DW hw related variables as well
>>     as old hardware related variables such as application reg base.
>> 2. Added a dw_pcie_common_host_init() function that holds common
>>     host initialization code for old and new hw.
>> 3. dw_pcie_parse_resource() is used for parsing resource related
>>     information from DT bindings.
>> 4. dw_pcie_host_init() is called by new DW hw drivers as before.
>>     Added dw_old_pcie_host_init() is it's counter part on old dw hw.
>>     Both these functions now call dw_pcie_common_host_init().
>> 5. Some of the static functions are made global to allow use from
>>     dw old pci drivers such as pci-keystone.
> Can we split this into patches that do these 5 things?
>
> Also, using OLD seems like a bad choice, what happens when we have NEW NEW in the future?
I suggested using a compatibility  that includes v3.65 version string to 
differentiate and treat
the code differently for the dw hw that is used on keystone SoC.

>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>> drivers/pci/host/pcie-designware.c |  101 ++++++++++++++++++++++++------------
>> drivers/pci/host/pcie-designware.h |   42 ++++++++++++---
>> 2 files changed, 103 insertions(+), 40 deletions(-)
>> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
>> index c4e3732..9ea8e79 100644
>> --- a/drivers/pci/host/pcie-designware.c
>> +++ b/drivers/pci/host/pcie-designware.c
>> @@ -277,11 +277,15 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
>> 		}
>> 		set_bit(pos0 + i, pp->msi_irq_in_use);
>> 		/*Enable corresponding interrupt in MSI interrupt controller */
>> -		res = ((pos0 + i) / 32) * 12;
>> -		bit = (pos0 + i) % 32;
>> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>> -		val |= 1 << bit;
>> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>> +		if (!(pp->version & DW_VERSION_OLD)) {
>> +			res = ((pos0 + i) / 32) * 12;
>> +			bit = (pos0 + i) % 32;
>> +			dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> +						 4, &val);
>> +			val |= 1 << bit;
>> +			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> +						 4, val);
>> +		}
>> 	}
>>
>> 	*pos = pos0;
>> @@ -349,7 +353,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
>> 	 */
>> 	desc->msi_attrib.multiple = msgvec;
>>
>> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
>> +	if (pp->ops->get_msi_data)
>> +		msg.address_lo = pp->ops->get_msi_data(pp);
>> +	else
>> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>> 	msg.address_hi = 0x0;
>> 	msg.data = pos;
>> 	write_msi_msg(irq, &msg);
>> @@ -389,13 +396,11 @@ static const struct irq_domain_ops msi_domain_ops = {
>> 	.map = dw_pcie_msi_map,
>> };
>>
>> -int __init dw_pcie_host_init(struct pcie_port *pp)
>> +int __init dw_pcie_parse_resource(struct pcie_port *pp)
>> {
>> 	struct device_node *np = pp->dev->of_node;
>> -	struct of_pci_range range;
>> 	struct of_pci_range_parser parser;
>> -	u32 val;
>> -	int i;
>> +	struct of_pci_range range;
>>
>> 	if (of_pci_range_parser_init(&parser, np)) {
>> 		dev_err(pp->dev, "missing ranges property\n");
>> @@ -440,23 +445,17 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 			return -ENOMEM;
>> 		}
>> 	}
>> -
>> -	pp->cfg0_base = pp->cfg.start;
>> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>> 	pp->mem_base = pp->mem.start;
>>
>> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>> -					pp->config.cfg0_size);
>> -	if (!pp->va_cfg0_base) {
>> -		dev_err(pp->dev, "error with ioremap in function\n");
>> -		return -ENOMEM;
>> -	}
>> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>> -					pp->config.cfg1_size);
>> -	if (!pp->va_cfg1_base) {
>> -		dev_err(pp->dev, "error with ioremap\n");
>> -		return -ENOMEM;
>> -	}
>> +	return 0;
>> +}
>> +
>> +int __init dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>> +				const struct irq_domain_ops *irq_msi_ops)
>> +{
>> +	struct device_node *np = pp->dev->of_node;
>> +	u32 val;
>> +	int i;
>>
>> 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
>> 		dev_err(pp->dev, "Failed to parse the number of lanes\n");
>> @@ -465,7 +464,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>>
>> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> 		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
>> -					MAX_MSI_IRQS, &msi_domain_ops,
>> +					MAX_MSI_IRQS, irq_msi_ops,
>> 					&dw_pcie_msi_chip);
>> 		if (!pp->irq_domain) {
>> 			dev_err(pp->dev, "irq domain init failed\n");
>> @@ -488,10 +487,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 	val |= PORT_LOGIC_SPEED_CHANGE;
>> 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>>
>> -	dw_pci.nr_controllers = 1;
>> -	dw_pci.private_data = (void **)&pp;
>> +	hw->nr_controllers = 1;
>> +	hw->private_data = (void **)&pp;
>>
>> -	pci_common_init_dev(pp->dev, &dw_pci);
>> +	pci_common_init_dev(pp->dev, hw);
>> 	pci_assign_unassigned_resources();
>> #ifdef CONFIG_PCI_DOMAINS
>> 	dw_pci.domain++;
>> @@ -500,6 +499,32 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>> 	return 0;
>> }
>>
>> +int __init dw_pcie_host_init(struct pcie_port *pp)
>> +{
>> +	int ret;
>> +
>> +	ret = dw_pcie_parse_resource(pp);
>> +	if (ret)
>> +		return ret;
>> +
>> +	pp->cfg0_base = pp->cfg.start;
>> +	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>> +	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
>> +					pp->config.cfg0_size);
>> +	if (!pp->va_cfg0_base) {
>> +		dev_err(pp->dev, "error with ioremap in function\n");
>> +		return -ENOMEM;
>> +	}
>> +	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
>> +					pp->config.cfg1_size);
>> +	if (!pp->va_cfg1_base) {
>> +		dev_err(pp->dev, "error with ioremap\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	return dw_pcie_common_host_init(pp, &dw_pci, &msi_domain_ops);
>> +}
>> +
>> static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
>> {
>> 	/* Program viewport 0 : OUTBOUND : CFG0 */
>> @@ -654,7 +679,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
>>
>> 	spin_lock_irqsave(&pp->conf_lock, flags);
>> 	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>> +		if (pp->ops->rd_other_conf)
>> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>> 						where, size, val);
>> 	else
>> 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
>> @@ -680,7 +709,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
>>
>> 	spin_lock_irqsave(&pp->conf_lock, flags);
>> 	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>> +		if (pp->ops->wr_other_conf)
>> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>> 						where, size, val);
>> 	else
>> 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
>> @@ -694,7 +727,7 @@ static struct pci_ops dw_pcie_ops = {
>> 	.write = dw_pcie_wr_conf,
>> };
>>
>> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> {
>> 	struct pcie_port *pp;
>>
>> @@ -717,7 +750,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>> 	return 1;
>> }
>>
>> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> {
>> 	struct pci_bus *bus;
>> 	struct pcie_port *pp = sys_to_pcie(sys);
>> @@ -746,7 +779,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>> 	return irq;
>> }
>>
>> -static void dw_pcie_add_bus(struct pci_bus *bus)
>> +void dw_pcie_add_bus(struct pci_bus *bus)
>> {
>> 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
>> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
>> index 3063b35..e97f4d7 100644
>> --- a/drivers/pci/host/pcie-designware.h
>> +++ b/drivers/pci/host/pcie-designware.h
>> @@ -35,21 +35,39 @@ struct pcie_port {
>> 	struct device		*dev;
>> 	u8			root_bus_nr;
>> 	void __iomem		*dbi_base;
>> -	u64			cfg0_base;
>> -	void __iomem		*va_cfg0_base;
>> -	u64			cfg1_base;
>> -	void __iomem		*va_cfg1_base;
>> +	/*
>> +	 * Old DW version implement application register space for
>> +	 * MSI and has no ATU view port
>> +	 */
>> +#define DW_VERSION_OLD	BIT(0)
>> +	u32			version;
>> +	union {
>> +		/* new dw core specific */
>> +		struct {
>> +			u64		cfg0_base;
>> +			void __iomem	*va_cfg0_base;
>> +			u64		cfg1_base;
>> +			void __iomem	*va_cfg1_base;
>> +			int		msi_irq;
>> +		};
>> +
>> +		/* old dw core specific */
>> +		struct  {
>> +			struct irq_domain	*legacy_irq_domain;
>> +			void __iomem		*va_app_base;
>> +			u64			app_base;
>> +		};
>> +	};
>> 	u64			io_base;
>> 	u64			mem_base;
>> 	spinlock_t		conf_lock;
>> -	struct resource		cfg;
>> 	struct resource		io;
>> 	struct resource		mem;
>> +	struct resource		cfg;
>> 	struct pcie_port_info	config;
>> 	int			irq;
>> 	u32			lanes;
>> 	struct pcie_host_ops	*ops;
>> -	int			msi_irq;
>> 	struct irq_domain	*irq_domain;
>> 	unsigned long		msi_data;
>> 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
>> @@ -62,8 +80,13 @@ struct pcie_host_ops {
>> 			u32 val, void __iomem *dbi_base);
>> 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
>> 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
>> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 *val);
>> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 val);
>> 	int (*link_up)(struct pcie_port *pp);
>> 	void (*host_init)(struct pcie_port *pp);
>> +	u32 (*get_msi_data)(struct pcie_port *pp);
>> };
>>
>> int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
>> @@ -73,5 +96,12 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>> int dw_pcie_link_up(struct pcie_port *pp);
>> void dw_pcie_setup_rc(struct pcie_port *pp);
>> int dw_pcie_host_init(struct pcie_port *pp);
>> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
>> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
>> +void dw_pcie_add_bus(struct pci_bus *bus);
>> +int dw_pcie_parse_resource(struct pcie_port *pp);
>>
>> +/* internal to dw core */
>> +int dw_pcie_common_host_init(struct pcie_port *pp, struct hw_pci *hw,
>> +			const struct irq_domain_ops *irq_ops);
>> #endif /* _PCIE_DESIGNWARE_H */
>> -- 
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-16 20:26           ` Murali Karicheri
@ 2014-05-19 12:06             ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-19 12:06 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas

On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >>>> +#ifdef CONFIG_PCI_KEYSTONE
> >>>> +/*
> >>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >>>> + */
> >>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >>>> +{
> >>>> +    int readrq = pcie_get_readrq(dev);
> >>>> +
> >>>> +    if (readrq > 256)
> >>>> +            pcie_set_readrq(dev, 256);
> >>>> +}
> >>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >>>> +#endif /* CONFIG_PCI_KEYSTONE */
> >>> This doesn't work: you can't just limit do this for all devices just based
> >>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> >>> this controller.
> >>>
> >>>        Arnd
> >>    I assume, I need to check if PCI controller's vendor ID/ device ID
> >> match with the keystone
> >>    PCI controller's ID and call pcie_set_readrq() for all of the slave
> >> PCI devices and do this fixup.
> >> Is this correct understanding?  If you can point me to an example code
> >> for this that will be
> >> really helpful so that I can avoid re-inventing the wheel.
> > I think it would be best to move the quirk into the keystone pci driver
> > and compare compare the dev->driver pointer of the PCI controller device.
> >
> >       Arnd
> Arnd,
> 
> I will move this quirk to keystone pci driver. So in that case, I guess 
> your original comment
> is not applicable as  this quirk gets enabled only with PCI keystone 
> driver enabled. Right?

Of course you still have to fix the bug, not just move the code into
the driver. Otherwise it's still broken for every machine after the keystone
driver is enabled.

I also agree with Jason that changing the PCI core to call
pcie_bus_configure_settings() would be a better way of dealing with this
if it solves the problem.

	Arnd

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-19 12:06             ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-19 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >>>> +#ifdef CONFIG_PCI_KEYSTONE
> >>>> +/*
> >>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >>>> + */
> >>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >>>> +{
> >>>> +    int readrq = pcie_get_readrq(dev);
> >>>> +
> >>>> +    if (readrq > 256)
> >>>> +            pcie_set_readrq(dev, 256);
> >>>> +}
> >>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >>>> +#endif /* CONFIG_PCI_KEYSTONE */
> >>> This doesn't work: you can't just limit do this for all devices just based
> >>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> >>> this controller.
> >>>
> >>>        Arnd
> >>    I assume, I need to check if PCI controller's vendor ID/ device ID
> >> match with the keystone
> >>    PCI controller's ID and call pcie_set_readrq() for all of the slave
> >> PCI devices and do this fixup.
> >> Is this correct understanding?  If you can point me to an example code
> >> for this that will be
> >> really helpful so that I can avoid re-inventing the wheel.
> > I think it would be best to move the quirk into the keystone pci driver
> > and compare compare the dev->driver pointer of the PCI controller device.
> >
> >       Arnd
> Arnd,
> 
> I will move this quirk to keystone pci driver. So in that case, I guess 
> your original comment
> is not applicable as  this quirk gets enabled only with PCI keystone 
> driver enabled. Right?

Of course you still have to fix the bug, not just move the code into
the driver. Otherwise it's still broken for every machine after the keystone
driver is enabled.

I also agree with Jason that changing the PCI core to call
pcie_bus_configure_settings() would be a better way of dealing with this
if it solves the problem.

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-16 22:44       ` Murali Karicheri
@ 2014-05-19 12:12         ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-19 12:12 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas,
	xobs

On Friday 16 May 2014 18:44:44 Murali Karicheri wrote:
> On 5/15/2014 12:28 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
> >> +Sample bindings shown below:-
> >> +
> >> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
> >> +   configuration.
> >> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
> >> +   link
> > You actually have to document all the properties. Have a look at the
> > other bindings for what this means.
> 
> Actually this is dw pcie variant. So I will document if there are any 
> deviations from the dw-designware
> bindings. Based on comments from Jingo, I think I need to add a new DT 
> property for old hw that we
> use in keystone. May be a compatibility string for older dw h/w like 
> "snps ,dw-pcie-v3.65" is that we
> could use and do things differently in the common code.

A compatible string with the exact version sounds like a good idea, yes.

> So I will update the Documentation of dw bindings  once we agree on this.
> >> +
> >> +               pcie@21800000 {
> >> +                       compatible = "ti,keystone-pcie";
> >> +                       device_type = "pci";
> >> +                       clocks = <&clkpcie>;
> >> +                       clock-names = "pcie";
> > The dw-pcie binding lists two clocks.
>
> Ok. As per dw documentation, pcie and pcie_bus are the clocks. But 
> pci-imx6 is currently not using pcie_bus. So the pcie_bus
> clock is actually optional. In the case of keystone pcie, bus clock is 
> provided by the phy hardware and if I need to provide
> a clock for bus, it has to be a dummy or change documentation to make 
> pcie_bus an optional clock. I prefer later, but want
> to know if this is true for pci-imx6. There is also a plan to move the 
> pcie clock API call to designware core. So making pcie_bus
> clock optional looks correct to me.

A documentation change sounds fine to me. How about documenting that
there should be either a "pcie_bus" clock or a phy reference?

> >> +                       #address-cells = >;
> >> +                       #size-cells = <2>;
> >> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
> >> +                       reg-names = "reg_rc_app", "reg_devcfg";
> > There should be standard names that are documented in the binding.
> 
> Currently  Documentation says
> 
> - reg: base addresses and lengths of the pcie controller,
>      the phy controller, additional register for the phy controller.
> 
> And following dw drivers defines as
> 
> samsung,exynos5440-pcie
> 
>          reg = <0x290000 0x1000
>              0x270000 0x1000
>              0x271000 0x40>;
> 
> fsl,imx6q-pcie"
>          reg = <0x01ffc000 0x4000>; /* DBI */
> 
> There are no names used for registers. So this needs to be documented in 
> the dw-designware
> bindings. reg_dbi is what is common to pci controller assuming at index 
> 0 of the both above drivers use
> reg_dbi address for config space. Shall I modify the documentation to 
> include optional reg name
> reg_dbi  for config space base address registers? Additional registers 
> are optional and varies from
> platform to platform. Phy registers are actually part of Phy driver and 
> should be removed from
> the dw-documentation bindings. Agree?

It makes sense to remove the phy registers if there is always a separate
phy driver. Regarding the names, it's probably easier to remove them
completely than to document them.

If the register names are optional, you can't rely on them anyway
and have to uses the indexes/

> >
> >> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
> > What are all these interrupts?
> These are MSI interrupts tied to the GIC over which MSI interrupts are 
> multiplexed.  I will document
> it in the keystone PCI DT bindings.

Maybe they should be moved into the subnode that has the LSI interrupts,
or perhaps a separate node? I don't know how the other dw-pcie variants
do it, but it always seems like a good idea to keep MSI separate because
you might not want to use it if there is also an MSI capable GIC in the
system.

> >> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
> >> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
> >> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
> > Please move the config space into 'reg' now instead of 'ranges'.
> > This was a mistake earlier, and there are already other front-ends
> > doing the same thing.
>   This has to be coordinated with other drivers when DW core makes the 
> change.
> 
> Jingoo, Sean,
> 
> What is the plan for this change? I  have to defer this currently.

> >> +                       #interrupt-cells = <1>;
> >> +                       interrupt-map-mask = <0 0 0 0>;
> >> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
> >> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
> >> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
> >> +                                       <0 0 0 4 &pcie_intc 4>; // INT D
> > I think this is the wrong map-mask.
> I think this should be changed to
> 
> interrupt-map-mask = <0 0 0 0x7> ?

That sounds reasonable. Is that what your hardware implements?

	Arnd

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-19 12:12         ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-19 12:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 16 May 2014 18:44:44 Murali Karicheri wrote:
> On 5/15/2014 12:28 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
> >> +Sample bindings shown below:-
> >> +
> >> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
> >> +   configuration.
> >> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
> >> +   link
> > You actually have to document all the properties. Have a look at the
> > other bindings for what this means.
> 
> Actually this is dw pcie variant. So I will document if there are any 
> deviations from the dw-designware
> bindings. Based on comments from Jingo, I think I need to add a new DT 
> property for old hw that we
> use in keystone. May be a compatibility string for older dw h/w like 
> "snps ,dw-pcie-v3.65" is that we
> could use and do things differently in the common code.

A compatible string with the exact version sounds like a good idea, yes.

> So I will update the Documentation of dw bindings  once we agree on this.
> >> +
> >> +               pcie at 21800000 {
> >> +                       compatible = "ti,keystone-pcie";
> >> +                       device_type = "pci";
> >> +                       clocks = <&clkpcie>;
> >> +                       clock-names = "pcie";
> > The dw-pcie binding lists two clocks.
>
> Ok. As per dw documentation, pcie and pcie_bus are the clocks. But 
> pci-imx6 is currently not using pcie_bus. So the pcie_bus
> clock is actually optional. In the case of keystone pcie, bus clock is 
> provided by the phy hardware and if I need to provide
> a clock for bus, it has to be a dummy or change documentation to make 
> pcie_bus an optional clock. I prefer later, but want
> to know if this is true for pci-imx6. There is also a plan to move the 
> pcie clock API call to designware core. So making pcie_bus
> clock optional looks correct to me.

A documentation change sounds fine to me. How about documenting that
there should be either a "pcie_bus" clock or a phy reference?

> >> +                       #address-cells = >;
> >> +                       #size-cells = <2>;
> >> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
> >> +                       reg-names = "reg_rc_app", "reg_devcfg";
> > There should be standard names that are documented in the binding.
> 
> Currently  Documentation says
> 
> - reg: base addresses and lengths of the pcie controller,
>      the phy controller, additional register for the phy controller.
> 
> And following dw drivers defines as
> 
> samsung,exynos5440-pcie
> 
>          reg = <0x290000 0x1000
>              0x270000 0x1000
>              0x271000 0x40>;
> 
> fsl,imx6q-pcie"
>          reg = <0x01ffc000 0x4000>; /* DBI */
> 
> There are no names used for registers. So this needs to be documented in 
> the dw-designware
> bindings. reg_dbi is what is common to pci controller assuming at index 
> 0 of the both above drivers use
> reg_dbi address for config space. Shall I modify the documentation to 
> include optional reg name
> reg_dbi  for config space base address registers? Additional registers 
> are optional and varies from
> platform to platform. Phy registers are actually part of Phy driver and 
> should be removed from
> the dw-documentation bindings. Agree?

It makes sense to remove the phy registers if there is always a separate
phy driver. Regarding the names, it's probably easier to remove them
completely than to document them.

If the register names are optional, you can't rely on them anyway
and have to uses the indexes/

> >
> >> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
> > What are all these interrupts?
> These are MSI interrupts tied to the GIC over which MSI interrupts are 
> multiplexed.  I will document
> it in the keystone PCI DT bindings.

Maybe they should be moved into the subnode that has the LSI interrupts,
or perhaps a separate node? I don't know how the other dw-pcie variants
do it, but it always seems like a good idea to keep MSI separate because
you might not want to use it if there is also an MSI capable GIC in the
system.

> >> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
> >> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
> >> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
> > Please move the config space into 'reg' now instead of 'ranges'.
> > This was a mistake earlier, and there are already other front-ends
> > doing the same thing.
>   This has to be coordinated with other drivers when DW core makes the 
> change.
> 
> Jingoo, Sean,
> 
> What is the plan for this change? I  have to defer this currently.

> >> +                       #interrupt-cells = <1>;
> >> +                       interrupt-map-mask = <0 0 0 0>;
> >> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
> >> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
> >> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
> >> +                                       <0 0 0 4 &pcie_intc 4>; // INT D
> > I think this is the wrong map-mask.
> I think this should be changed to
> 
> interrupt-map-mask = <0 0 0 0x7> ?

That sounds reasonable. Is that what your hardware implements?

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-19 12:06             ` Arnd Bergmann
  (?)
@ 2014-05-19 21:10               ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-19 21:10 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas

On 5/19/2014 8:06 AM, Arnd Bergmann wrote:
> On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
>> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
>>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>>> +/*
>>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>>> + */
>>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>>> +{
>>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>>> +
>>>>>> +    if (readrq > 256)
>>>>>> +            pcie_set_readrq(dev, 256);
>>>>>> +}
>>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>>> This doesn't work: you can't just limit do this for all devices just based
>>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>>> this controller.
>>>>>
>>>>>         Arnd
>>>>     I assume, I need to check if PCI controller's vendor ID/ device ID
>>>> match with the keystone
>>>>     PCI controller's ID and call pcie_set_readrq() for all of the slave
>>>> PCI devices and do this fixup.
>>>> Is this correct understanding?  If you can point me to an example code
>>>> for this that will be
>>>> really helpful so that I can avoid re-inventing the wheel.
>>> I think it would be best to move the quirk into the keystone pci driver
>>> and compare compare the dev->driver pointer of the PCI controller device.
>>>
>>>        Arnd
>> Arnd,
>>
>> I will move this quirk to keystone pci driver. So in that case, I guess
>> your original comment
>> is not applicable as  this quirk gets enabled only with PCI keystone
>> driver enabled. Right?
> Of course you still have to fix the bug, not just move the code into
> the driver. Otherwise it's still broken for every machine after the keystone
> driver is enabled.

Agree. I have tried following to get this work so that the quirk gets 
applied only for
keystone pci controller.

#define KS_K2HK_PCI_DEVICE_ID    0xb008
#define KS_K2E_PCI_DEVICE_ID    0xb009
#define KS_K2L_PCI_DEVICE_ID    0xb00a

static u16 root_pci_ids[] =
     {KS_K2HK_PCI_DEVICE_ID, KS_K2E_PCI_DEVICE_ID, KS_K2L_PCI_DEVICE_ID, 
0 };
/*
  * The KeyStone PCIe controller has maximum read request size of 256 bytes.
  */
static void quirk_limit_readrequest(struct pci_dev *dev)
{
     struct pci_dev *root_dev;
     int i = 0;

     /* Apply quirk only if this bridge device is keystone */
     while (root_pci_ids[i]) {
         root_dev = pci_get_device(PCI_VENDOR_ID_TI, root_pci_ids[i], NULL);
         if ((root_dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
             int readrq;

             readrq = pcie_get_readrq(dev);
             if (pcie_get_readrq(dev) > 256) {
                 pcie_set_readrq(dev, 256);
                 printk("Applied quirk\n");
             }
             break;
         };
     }
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);

>
> I also agree with Jason that changing the PCI core to call
> pcie_bus_configure_settings() would be a better way of dealing with this
> if it solves the problem.

I tried following piece of code added to bios32.c

void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
{
         struct pci_sys_data *sys;
         LIST_HEAD(head);

         pci_add_flags(PCI_REASSIGN_ALL_RSRC);
         if (hw->preinit)
                 hw->preinit();

          ........
          ....

          list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 if (!pci_has_flag(PCI_PROBE_ONLY)) {
                         /*
                          * Size the bridge windows.
                          */
                         pci_bus_size_bridges(bus);

                         /*
                          * Assign resources.
                          */
                         pci_bus_assign_resources(bus);
                 }
                 /*
                  * Tell drivers about devices found.
                  */
                 pci_bus_add_devices(bus);
         }

// New code starts here
         list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 /* Configure PCI Express settings */
                 if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
                         struct pci_bus *child;

                         list_for_each_entry(child, &bus->children, node)
                         pcie_bus_configure_settings(child);
                 }
         }
// New code ends.

This seems to do different things based on the pci bootargs. The key 
requirement for Keystone PCI controller
is that the MRRS can't be more than 256 bytes.  The only option that 
works for keystone PCI controller
is with pci=pcie_bus_perf.   I see following logs:-

[    3.382747] pcie_bus_configure_settings, config 2
[    3.382753] pcie_bus_configure_set
[    3.382781] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    3.382788] pcie_bus_configure_set
[    3.382846] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    3.382852] pcie_bus_configure_set
[    3.382909] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

On ARM, by default pci_bus_config seems to be set to 0 
(PCIE_BUS_TUNE_OFF). So the code doesn't get
executed for this default. But for PCIE_BUS_SAFE, it doesn't change the 
mrrs at the EP and is not
good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it 
seems to increase the payload
size as well and Keystone Payload size is limited to 128 bytes. So it is 
not safe to increase the payload
size to 256 based on the log.

On other platforms, Why the PCI core try to set the payload size equal 
to mrrs? Is this explained in any
PCI spec?  Looks like this is done for performance? Let me know if you 
want me to send a patch for
review to add the pcie_bus_configure_settings() code to 
arch/arm/kernel/bios32.c

For the Keystone PCI driver, I believe. it is safe to have the quirk so 
that controller can handle the
read requests properly. Let me know if the quirk code above looks good 
to go.

Murali

> 	Arnd


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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-19 21:10               ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-19 21:10 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas

On 5/19/2014 8:06 AM, Arnd Bergmann wrote:
> On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
>> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
>>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>>> +/*
>>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>>> + */
>>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>>> +{
>>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>>> +
>>>>>> +    if (readrq > 256)
>>>>>> +            pcie_set_readrq(dev, 256);
>>>>>> +}
>>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>>> This doesn't work: you can't just limit do this for all devices just based
>>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>>> this controller.
>>>>>
>>>>>         Arnd
>>>>     I assume, I need to check if PCI controller's vendor ID/ device ID
>>>> match with the keystone
>>>>     PCI controller's ID and call pcie_set_readrq() for all of the slave
>>>> PCI devices and do this fixup.
>>>> Is this correct understanding?  If you can point me to an example code
>>>> for this that will be
>>>> really helpful so that I can avoid re-inventing the wheel.
>>> I think it would be best to move the quirk into the keystone pci driver
>>> and compare compare the dev->driver pointer of the PCI controller device.
>>>
>>>        Arnd
>> Arnd,
>>
>> I will move this quirk to keystone pci driver. So in that case, I guess
>> your original comment
>> is not applicable as  this quirk gets enabled only with PCI keystone
>> driver enabled. Right?
> Of course you still have to fix the bug, not just move the code into
> the driver. Otherwise it's still broken for every machine after the keystone
> driver is enabled.

Agree. I have tried following to get this work so that the quirk gets 
applied only for
keystone pci controller.

#define KS_K2HK_PCI_DEVICE_ID    0xb008
#define KS_K2E_PCI_DEVICE_ID    0xb009
#define KS_K2L_PCI_DEVICE_ID    0xb00a

static u16 root_pci_ids[] =
     {KS_K2HK_PCI_DEVICE_ID, KS_K2E_PCI_DEVICE_ID, KS_K2L_PCI_DEVICE_ID, 
0 };
/*
  * The KeyStone PCIe controller has maximum read request size of 256 bytes.
  */
static void quirk_limit_readrequest(struct pci_dev *dev)
{
     struct pci_dev *root_dev;
     int i = 0;

     /* Apply quirk only if this bridge device is keystone */
     while (root_pci_ids[i]) {
         root_dev = pci_get_device(PCI_VENDOR_ID_TI, root_pci_ids[i], NULL);
         if ((root_dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
             int readrq;

             readrq = pcie_get_readrq(dev);
             if (pcie_get_readrq(dev) > 256) {
                 pcie_set_readrq(dev, 256);
                 printk("Applied quirk\n");
             }
             break;
         };
     }
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);

>
> I also agree with Jason that changing the PCI core to call
> pcie_bus_configure_settings() would be a better way of dealing with this
> if it solves the problem.

I tried following piece of code added to bios32.c

void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
{
         struct pci_sys_data *sys;
         LIST_HEAD(head);

         pci_add_flags(PCI_REASSIGN_ALL_RSRC);
         if (hw->preinit)
                 hw->preinit();

          ........
          ....

          list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 if (!pci_has_flag(PCI_PROBE_ONLY)) {
                         /*
                          * Size the bridge windows.
                          */
                         pci_bus_size_bridges(bus);

                         /*
                          * Assign resources.
                          */
                         pci_bus_assign_resources(bus);
                 }
                 /*
                  * Tell drivers about devices found.
                  */
                 pci_bus_add_devices(bus);
         }

// New code starts here
         list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 /* Configure PCI Express settings */
                 if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
                         struct pci_bus *child;

                         list_for_each_entry(child, &bus->children, node)
                         pcie_bus_configure_settings(child);
                 }
         }
// New code ends.

This seems to do different things based on the pci bootargs. The key 
requirement for Keystone PCI controller
is that the MRRS can't be more than 256 bytes.  The only option that 
works for keystone PCI controller
is with pci=pcie_bus_perf.   I see following logs:-

[    3.382747] pcie_bus_configure_settings, config 2
[    3.382753] pcie_bus_configure_set
[    3.382781] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    3.382788] pcie_bus_configure_set
[    3.382846] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    3.382852] pcie_bus_configure_set
[    3.382909] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

On ARM, by default pci_bus_config seems to be set to 0 
(PCIE_BUS_TUNE_OFF). So the code doesn't get
executed for this default. But for PCIE_BUS_SAFE, it doesn't change the 
mrrs at the EP and is not
good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it 
seems to increase the payload
size as well and Keystone Payload size is limited to 128 bytes. So it is 
not safe to increase the payload
size to 256 based on the log.

On other platforms, Why the PCI core try to set the payload size equal 
to mrrs? Is this explained in any
PCI spec?  Looks like this is done for performance? Let me know if you 
want me to send a patch for
review to add the pcie_bus_configure_settings() code to 
arch/arm/kernel/bios32.c

For the Keystone PCI driver, I believe. it is safe to have the quirk so 
that controller can handle the
read requests properly. Let me know if the quirk code above looks good 
to go.

Murali

> 	Arnd


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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-19 21:10               ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-19 21:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/19/2014 8:06 AM, Arnd Bergmann wrote:
> On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
>> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
>>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>>> +/*
>>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>>> + */
>>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>>> +{
>>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>>> +
>>>>>> +    if (readrq > 256)
>>>>>> +            pcie_set_readrq(dev, 256);
>>>>>> +}
>>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>>> This doesn't work: you can't just limit do this for all devices just based
>>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>>> this controller.
>>>>>
>>>>>         Arnd
>>>>     I assume, I need to check if PCI controller's vendor ID/ device ID
>>>> match with the keystone
>>>>     PCI controller's ID and call pcie_set_readrq() for all of the slave
>>>> PCI devices and do this fixup.
>>>> Is this correct understanding?  If you can point me to an example code
>>>> for this that will be
>>>> really helpful so that I can avoid re-inventing the wheel.
>>> I think it would be best to move the quirk into the keystone pci driver
>>> and compare compare the dev->driver pointer of the PCI controller device.
>>>
>>>        Arnd
>> Arnd,
>>
>> I will move this quirk to keystone pci driver. So in that case, I guess
>> your original comment
>> is not applicable as  this quirk gets enabled only with PCI keystone
>> driver enabled. Right?
> Of course you still have to fix the bug, not just move the code into
> the driver. Otherwise it's still broken for every machine after the keystone
> driver is enabled.

Agree. I have tried following to get this work so that the quirk gets 
applied only for
keystone pci controller.

#define KS_K2HK_PCI_DEVICE_ID    0xb008
#define KS_K2E_PCI_DEVICE_ID    0xb009
#define KS_K2L_PCI_DEVICE_ID    0xb00a

static u16 root_pci_ids[] =
     {KS_K2HK_PCI_DEVICE_ID, KS_K2E_PCI_DEVICE_ID, KS_K2L_PCI_DEVICE_ID, 
0 };
/*
  * The KeyStone PCIe controller has maximum read request size of 256 bytes.
  */
static void quirk_limit_readrequest(struct pci_dev *dev)
{
     struct pci_dev *root_dev;
     int i = 0;

     /* Apply quirk only if this bridge device is keystone */
     while (root_pci_ids[i]) {
         root_dev = pci_get_device(PCI_VENDOR_ID_TI, root_pci_ids[i], NULL);
         if ((root_dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
             int readrq;

             readrq = pcie_get_readrq(dev);
             if (pcie_get_readrq(dev) > 256) {
                 pcie_set_readrq(dev, 256);
                 printk("Applied quirk\n");
             }
             break;
         };
     }
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);

>
> I also agree with Jason that changing the PCI core to call
> pcie_bus_configure_settings() would be a better way of dealing with this
> if it solves the problem.

I tried following piece of code added to bios32.c

void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
{
         struct pci_sys_data *sys;
         LIST_HEAD(head);

         pci_add_flags(PCI_REASSIGN_ALL_RSRC);
         if (hw->preinit)
                 hw->preinit();

          ........
          ....

          list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 if (!pci_has_flag(PCI_PROBE_ONLY)) {
                         /*
                          * Size the bridge windows.
                          */
                         pci_bus_size_bridges(bus);

                         /*
                          * Assign resources.
                          */
                         pci_bus_assign_resources(bus);
                 }
                 /*
                  * Tell drivers about devices found.
                  */
                 pci_bus_add_devices(bus);
         }

// New code starts here
         list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 /* Configure PCI Express settings */
                 if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
                         struct pci_bus *child;

                         list_for_each_entry(child, &bus->children, node)
                         pcie_bus_configure_settings(child);
                 }
         }
// New code ends.

This seems to do different things based on the pci bootargs. The key 
requirement for Keystone PCI controller
is that the MRRS can't be more than 256 bytes.  The only option that 
works for keystone PCI controller
is with pci=pcie_bus_perf.   I see following logs:-

[    3.382747] pcie_bus_configure_settings, config 2
[    3.382753] pcie_bus_configure_set
[    3.382781] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    3.382788] pcie_bus_configure_set
[    3.382846] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    3.382852] pcie_bus_configure_set
[    3.382909] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

On ARM, by default pci_bus_config seems to be set to 0 
(PCIE_BUS_TUNE_OFF). So the code doesn't get
executed for this default. But for PCIE_BUS_SAFE, it doesn't change the 
mrrs at the EP and is not
good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it 
seems to increase the payload
size as well and Keystone Payload size is limited to 128 bytes. So it is 
not safe to increase the payload
size to 256 based on the log.

On other platforms, Why the PCI core try to set the payload size equal 
to mrrs? Is this explained in any
PCI spec?  Looks like this is done for performance? Let me know if you 
want me to send a patch for
review to add the pcie_bus_configure_settings() code to 
arch/arm/kernel/bios32.c

For the Keystone PCI driver, I believe. it is safe to have the quirk so 
that controller can handle the
read requests properly. Let me know if the quirk code above looks good 
to go.

Murali

> 	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-19 21:10               ` Murali Karicheri
@ 2014-05-20  7:55                 ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-20  7:55 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, Strashko, Grygorii, linux-pci, Jingoo Han,
	linux-kernel, Shilimkar, Santosh, Mohit Kumar, Bjorn Helgaas

On Monday 19 May 2014 17:10:50 Murali Karicheri wrote:
> On 5/19/2014 8:06 AM, Arnd Bergmann wrote:
> > On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
> >> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> >>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >>>>>> +#ifdef CONFIG_PCI_KEYSTONE
> >>>>>> +/*
> >>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >>>>>> + */
> >>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >>>>>> +{
> >>>>>> +    int readrq = pcie_get_readrq(dev);
> >>>>>> +
> >>>>>> +    if (readrq > 256)
> >>>>>> +            pcie_set_readrq(dev, 256);
> >>>>>> +}
> >>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
> >>>>> This doesn't work: you can't just limit do this for all devices just based
> >>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> >>>>> this controller.
> >>>>>
> >>>>>         Arnd
> >>>>     I assume, I need to check if PCI controller's vendor ID/ device ID
> >>>> match with the keystone
> >>>>     PCI controller's ID and call pcie_set_readrq() for all of the slave
> >>>> PCI devices and do this fixup.
> >>>> Is this correct understanding?  If you can point me to an example code
> >>>> for this that will be
> >>>> really helpful so that I can avoid re-inventing the wheel.
> >>> I think it would be best to move the quirk into the keystone pci driver
> >>> and compare compare the dev->driver pointer of the PCI controller device.
> >>>
> >>>        Arnd
> >> Arnd,
> >>
> >> I will move this quirk to keystone pci driver. So in that case, I guess
> >> your original comment
> >> is not applicable as  this quirk gets enabled only with PCI keystone
> >> driver enabled. Right?
> > Of course you still have to fix the bug, not just move the code into
> > the driver. Otherwise it's still broken for every machine after the keystone
> > driver is enabled.
> 
> Agree. I have tried following to get this work so that the quirk gets 
> applied only for
> keystone pci controller.
> 
> #define KS_K2HK_PCI_DEVICE_ID    0xb008
> #define KS_K2E_PCI_DEVICE_ID    0xb009
> #define KS_K2L_PCI_DEVICE_ID    0xb00a
> 
> static u16 root_pci_ids[] =
>      {KS_K2HK_PCI_DEVICE_ID, KS_K2E_PCI_DEVICE_ID, KS_K2L_PCI_DEVICE_ID, 
> 0 };
> /*
>   * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>   */
> static void quirk_limit_readrequest(struct pci_dev *dev)
> {
>      struct pci_dev *root_dev;
>      int i = 0;
> 
>      /* Apply quirk only if this bridge device is keystone */
>      while (root_pci_ids[i]) {
>          root_dev = pci_get_device(PCI_VENDOR_ID_TI, root_pci_ids[i], NULL);
>          if ((root_dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
>              int readrq;
> 
>              readrq = pcie_get_readrq(dev);
>              if (pcie_get_readrq(dev) > 256) {
>                  pcie_set_readrq(dev, 256);
>                  printk("Applied quirk\n");
>              }
>              break;
>          };
>      }
> }
> DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);

Why not compare the driver pointer as I suggested?

> > I also agree with Jason that changing the PCI core to call
> > pcie_bus_configure_settings() would be a better way of dealing with this
> > if it solves the problem.
> 
> I tried following piece of code added to bios32.c
> 
> void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
> {
>          struct pci_sys_data *sys;
>          LIST_HEAD(head);
> 
>          pci_add_flags(PCI_REASSIGN_ALL_RSRC);
>          if (hw->preinit)
>                  hw->preinit();
> 
>           ........
>           ....
> 
>           list_for_each_entry(sys, &head, node) {
>                  struct pci_bus *bus = sys->bus;
> 
>                  if (!pci_has_flag(PCI_PROBE_ONLY)) {
>                          /*
>                           * Size the bridge windows.
>                           */
>                          pci_bus_size_bridges(bus);
> 
>                          /*
>                           * Assign resources.
>                           */
>                          pci_bus_assign_resources(bus);
>                  }
>                  /*
>                   * Tell drivers about devices found.
>                   */
>                  pci_bus_add_devices(bus);
>          }
> 
> // New code starts here
>          list_for_each_entry(sys, &head, node) {
>                  struct pci_bus *bus = sys->bus;
> 
>                  /* Configure PCI Express settings */
>                  if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
>                          struct pci_bus *child;
> 
>                          list_for_each_entry(child, &bus->children, node)
>                          pcie_bus_configure_settings(child);
>                  }
>          }
> // New code ends.

This is the ARM specific part of the PCI code. I think it would be
better to do this independent of the architecture.

> This seems to do different things based on the pci bootargs. The key 
> requirement for Keystone PCI controller
> is that the MRRS can't be more than 256 bytes.  The only option that 
> works for keystone PCI controller
> is with pci=pcie_bus_perf.   I see following logs:-
> 
> [    3.382747] pcie_bus_configure_settings, config 2
> [    3.382753] pcie_bus_configure_set
> [    3.382781] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
> (was  128), Max Read Rq  256
> [    3.382788] pcie_bus_configure_set
> [    3.382846] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
> 128), Max Read Rq  256
> [    3.382852] pcie_bus_configure_set
> [    3.382909] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
> 128), Max Read Rq  256
> 
> On ARM, by default pci_bus_config seems to be set to 0 
> (PCIE_BUS_TUNE_OFF). So the code doesn't get
> executed for this default. But for PCIE_BUS_SAFE, it doesn't change the 
> mrrs at the EP and is not
> good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it 
> seems to increase the payload
> size as well and Keystone Payload size is limited to 128 bytes. So it is 
> not safe to increase the payload
> size to 256 based on the log.
> 
> On other platforms, Why the PCI core try to set the payload size equal 
> to mrrs? Is this explained in any
> PCI spec?  Looks like this is done for performance? Let me know if you 
> want me to send a patch for
> review to add the pcie_bus_configure_settings() code to 
> arch/arm/kernel/bios32.c
> 
> For the Keystone PCI driver, I believe. it is safe to have the quirk so 
> that controller can handle the
> read requests properly. Let me know if the quirk code above looks good 
> to go.

I don't know enough about these to give you a definite answer, but
I'd still prefer to handle this in generic code. A quirk seems to
be the wrong answer here. If this isn't something we can do in generic
fashion, can you do it in the add_bus() callback perhaps?

Maybe Jason or Bjorn have a better idea.

	Arnd

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20  7:55                 ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-20  7:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 19 May 2014 17:10:50 Murali Karicheri wrote:
> On 5/19/2014 8:06 AM, Arnd Bergmann wrote:
> > On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
> >> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> >>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >>>>>> +#ifdef CONFIG_PCI_KEYSTONE
> >>>>>> +/*
> >>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >>>>>> + */
> >>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >>>>>> +{
> >>>>>> +    int readrq = pcie_get_readrq(dev);
> >>>>>> +
> >>>>>> +    if (readrq > 256)
> >>>>>> +            pcie_set_readrq(dev, 256);
> >>>>>> +}
> >>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
> >>>>> This doesn't work: you can't just limit do this for all devices just based
> >>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> >>>>> this controller.
> >>>>>
> >>>>>         Arnd
> >>>>     I assume, I need to check if PCI controller's vendor ID/ device ID
> >>>> match with the keystone
> >>>>     PCI controller's ID and call pcie_set_readrq() for all of the slave
> >>>> PCI devices and do this fixup.
> >>>> Is this correct understanding?  If you can point me to an example code
> >>>> for this that will be
> >>>> really helpful so that I can avoid re-inventing the wheel.
> >>> I think it would be best to move the quirk into the keystone pci driver
> >>> and compare compare the dev->driver pointer of the PCI controller device.
> >>>
> >>>        Arnd
> >> Arnd,
> >>
> >> I will move this quirk to keystone pci driver. So in that case, I guess
> >> your original comment
> >> is not applicable as  this quirk gets enabled only with PCI keystone
> >> driver enabled. Right?
> > Of course you still have to fix the bug, not just move the code into
> > the driver. Otherwise it's still broken for every machine after the keystone
> > driver is enabled.
> 
> Agree. I have tried following to get this work so that the quirk gets 
> applied only for
> keystone pci controller.
> 
> #define KS_K2HK_PCI_DEVICE_ID    0xb008
> #define KS_K2E_PCI_DEVICE_ID    0xb009
> #define KS_K2L_PCI_DEVICE_ID    0xb00a
> 
> static u16 root_pci_ids[] =
>      {KS_K2HK_PCI_DEVICE_ID, KS_K2E_PCI_DEVICE_ID, KS_K2L_PCI_DEVICE_ID, 
> 0 };
> /*
>   * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>   */
> static void quirk_limit_readrequest(struct pci_dev *dev)
> {
>      struct pci_dev *root_dev;
>      int i = 0;
> 
>      /* Apply quirk only if this bridge device is keystone */
>      while (root_pci_ids[i]) {
>          root_dev = pci_get_device(PCI_VENDOR_ID_TI, root_pci_ids[i], NULL);
>          if ((root_dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
>              int readrq;
> 
>              readrq = pcie_get_readrq(dev);
>              if (pcie_get_readrq(dev) > 256) {
>                  pcie_set_readrq(dev, 256);
>                  printk("Applied quirk\n");
>              }
>              break;
>          };
>      }
> }
> DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);

Why not compare the driver pointer as I suggested?

> > I also agree with Jason that changing the PCI core to call
> > pcie_bus_configure_settings() would be a better way of dealing with this
> > if it solves the problem.
> 
> I tried following piece of code added to bios32.c
> 
> void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
> {
>          struct pci_sys_data *sys;
>          LIST_HEAD(head);
> 
>          pci_add_flags(PCI_REASSIGN_ALL_RSRC);
>          if (hw->preinit)
>                  hw->preinit();
> 
>           ........
>           ....
> 
>           list_for_each_entry(sys, &head, node) {
>                  struct pci_bus *bus = sys->bus;
> 
>                  if (!pci_has_flag(PCI_PROBE_ONLY)) {
>                          /*
>                           * Size the bridge windows.
>                           */
>                          pci_bus_size_bridges(bus);
> 
>                          /*
>                           * Assign resources.
>                           */
>                          pci_bus_assign_resources(bus);
>                  }
>                  /*
>                   * Tell drivers about devices found.
>                   */
>                  pci_bus_add_devices(bus);
>          }
> 
> // New code starts here
>          list_for_each_entry(sys, &head, node) {
>                  struct pci_bus *bus = sys->bus;
> 
>                  /* Configure PCI Express settings */
>                  if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
>                          struct pci_bus *child;
> 
>                          list_for_each_entry(child, &bus->children, node)
>                          pcie_bus_configure_settings(child);
>                  }
>          }
> // New code ends.

This is the ARM specific part of the PCI code. I think it would be
better to do this independent of the architecture.

> This seems to do different things based on the pci bootargs. The key 
> requirement for Keystone PCI controller
> is that the MRRS can't be more than 256 bytes.  The only option that 
> works for keystone PCI controller
> is with pci=pcie_bus_perf.   I see following logs:-
> 
> [    3.382747] pcie_bus_configure_settings, config 2
> [    3.382753] pcie_bus_configure_set
> [    3.382781] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
> (was  128), Max Read Rq  256
> [    3.382788] pcie_bus_configure_set
> [    3.382846] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
> 128), Max Read Rq  256
> [    3.382852] pcie_bus_configure_set
> [    3.382909] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
> 128), Max Read Rq  256
> 
> On ARM, by default pci_bus_config seems to be set to 0 
> (PCIE_BUS_TUNE_OFF). So the code doesn't get
> executed for this default. But for PCIE_BUS_SAFE, it doesn't change the 
> mrrs at the EP and is not
> good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it 
> seems to increase the payload
> size as well and Keystone Payload size is limited to 128 bytes. So it is 
> not safe to increase the payload
> size to 256 based on the log.
> 
> On other platforms, Why the PCI core try to set the payload size equal 
> to mrrs? Is this explained in any
> PCI spec?  Looks like this is done for performance? Let me know if you 
> want me to send a patch for
> review to add the pcie_bus_configure_settings() code to 
> arch/arm/kernel/bios32.c
> 
> For the Keystone PCI driver, I believe. it is safe to have the quirk so 
> that controller can handle the
> read requests properly. Let me know if the quirk code above looks good 
> to go.

I don't know enough about these to give you a definite answer, but
I'd still prefer to handle this in generic code. A quirk seems to
be the wrong answer here. If this isn't something we can do in generic
fashion, can you do it in the add_bus() callback perhaps?

Maybe Jason or Bjorn have a better idea.

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-16 20:29                 ` Karicheri, Muralidharan
  (?)
@ 2014-05-20 17:02                   ` Jason Gunthorpe
  -1 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-20 17:02 UTC (permalink / raw)
  To: Karicheri, Muralidharan
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:

> But pcie_bus_configure_settings just make sure the mrrs for a device
> is not greater than the max payload size. 

Not quite, it first scans the network checking the Maximum Payload Size
Supported (MPSS) for each device, and chooses the highest supported by
all as the MPS for all.

PCI-E requires that an end point support all packets up to the MPS, so
if your bridge can't generate a 512 byte read response packet, then it
must not advertise a MPSS greater than 256 bytes.

Setting your MPSS to 128, 256, then using the
pcie_bus_configure_settings to run the standard algorithm should
properly limit the readrq to 256 and be able to properly support all
the fun edge cases like hot plug.

If the config space in your root port bridge is correct and already
declares a MPSS of 256 then you have nothing else to do but make sure
pcie_bus_configure_settings gets calls.

If it is broken and claims a higher MPSS than it can support then you
need to use a quirk only for the root port bridge or edit the config
reply in the driver only to fix the MPSS.

Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20 17:02                   ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-20 17:02 UTC (permalink / raw)
  To: Karicheri, Muralidharan
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:

> But pcie_bus_configure_settings just make sure the mrrs for a device
> is not greater than the max payload size. 

Not quite, it first scans the network checking the Maximum Payload Size
Supported (MPSS) for each device, and chooses the highest supported by
all as the MPS for all.

PCI-E requires that an end point support all packets up to the MPS, so
if your bridge can't generate a 512 byte read response packet, then it
must not advertise a MPSS greater than 256 bytes.

Setting your MPSS to 128, 256, then using the
pcie_bus_configure_settings to run the standard algorithm should
properly limit the readrq to 256 and be able to properly support all
the fun edge cases like hot plug.

If the config space in your root port bridge is correct and already
declares a MPSS of 256 then you have nothing else to do but make sure
pcie_bus_configure_settings gets calls.

If it is broken and claims a higher MPSS than it can support then you
need to use a quirk only for the root port bridge or edit the config
reply in the driver only to fix the MPSS.

Jason

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20 17:02                   ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-20 17:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:

> But pcie_bus_configure_settings just make sure the mrrs for a device
> is not greater than the max payload size. 

Not quite, it first scans the network checking the Maximum Payload Size
Supported (MPSS) for each device, and chooses the highest supported by
all as the MPS for all.

PCI-E requires that an end point support all packets up to the MPS, so
if your bridge can't generate a 512 byte read response packet, then it
must not advertise a MPSS greater than 256 bytes.

Setting your MPSS to 128, 256, then using the
pcie_bus_configure_settings to run the standard algorithm should
properly limit the readrq to 256 and be able to properly support all
the fun edge cases like hot plug.

If the config space in your root port bridge is correct and already
declares a MPSS of 256 then you have nothing else to do but make sure
pcie_bus_configure_settings gets calls.

If it is broken and claims a higher MPSS than it can support then you
need to use a quirk only for the root port bridge or edit the config
reply in the driver only to fix the MPSS.

Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-20  7:55                 ` Arnd Bergmann
@ 2014-05-20 17:17                   ` Bjorn Helgaas
  -1 siblings, 0 replies; 116+ messages in thread
From: Bjorn Helgaas @ 2014-05-20 17:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm, Murali Karicheri, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar

On Tue, May 20, 2014 at 1:55 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 19 May 2014 17:10:50 Murali Karicheri wrote:

>> On ARM, by default pci_bus_config seems to be set to 0
>> (PCIE_BUS_TUNE_OFF). So the code doesn't get
>> executed for this default. But for PCIE_BUS_SAFE, it doesn't change the
>> mrrs at the EP and is not
>> good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it
>> seems to increase the payload
>> size as well and Keystone Payload size is limited to 128 bytes. So it is
>> not safe to increase the payload
>> size to 256 based on the log.
>>
>> On other platforms, Why the PCI core try to set the payload size equal
>> to mrrs? Is this explained in any
>> PCI spec?  Looks like this is done for performance? Let me know if you
>> want me to send a patch for
>> review to add the pcie_bus_configure_settings() code to
>> arch/arm/kernel/bios32.c
>>
>> For the Keystone PCI driver, I believe. it is safe to have the quirk so
>> that controller can handle the
>> read requests properly. Let me know if the quirk code above looks good
>> to go.
>
> I don't know enough about these to give you a definite answer, but
> I'd still prefer to handle this in generic code. A quirk seems to
> be the wrong answer here. If this isn't something we can do in generic
> fashion, can you do it in the add_bus() callback perhaps?

I definitely prefer a more generic approach than a quirk.
Unfortunately the MPS management was implemented originally just for
x86, not because there's anything arch-specific about it, but because
the author was only concerned about x86.  Making that more generic has
been an open issue all along.

Bjorn

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20 17:17                   ` Bjorn Helgaas
  0 siblings, 0 replies; 116+ messages in thread
From: Bjorn Helgaas @ 2014-05-20 17:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 20, 2014 at 1:55 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 19 May 2014 17:10:50 Murali Karicheri wrote:

>> On ARM, by default pci_bus_config seems to be set to 0
>> (PCIE_BUS_TUNE_OFF). So the code doesn't get
>> executed for this default. But for PCIE_BUS_SAFE, it doesn't change the
>> mrrs at the EP and is not
>> good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it
>> seems to increase the payload
>> size as well and Keystone Payload size is limited to 128 bytes. So it is
>> not safe to increase the payload
>> size to 256 based on the log.
>>
>> On other platforms, Why the PCI core try to set the payload size equal
>> to mrrs? Is this explained in any
>> PCI spec?  Looks like this is done for performance? Let me know if you
>> want me to send a patch for
>> review to add the pcie_bus_configure_settings() code to
>> arch/arm/kernel/bios32.c
>>
>> For the Keystone PCI driver, I believe. it is safe to have the quirk so
>> that controller can handle the
>> read requests properly. Let me know if the quirk code above looks good
>> to go.
>
> I don't know enough about these to give you a definite answer, but
> I'd still prefer to handle this in generic code. A quirk seems to
> be the wrong answer here. If this isn't something we can do in generic
> fashion, can you do it in the add_bus() callback perhaps?

I definitely prefer a more generic approach than a quirk.
Unfortunately the MPS management was implemented originally just for
x86, not because there's anything arch-specific about it, but because
the author was only concerned about x86.  Making that more generic has
been an open issue all along.

Bjorn

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-20 17:02                   ` Jason Gunthorpe
  (?)
@ 2014-05-20 17:22                     ` Bjorn Helgaas
  -1 siblings, 0 replies; 116+ messages in thread
From: Bjorn Helgaas @ 2014-05-20 17:22 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Karicheri, Muralidharan, Arnd Bergmann, linux-arm-kernel,
	Strashko, Grygorii, linux-pci, Jingoo Han, linux-kernel,
	Shilimkar, Santosh, Mohit Kumar

On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
<jgunthorpe@obsidianresearch.com> wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
>
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.

The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
wrinkles by setting MRRS in ways that allow some devices to have
larger MPS than others.  I don't think this is exactly what was
envisioned in the spec, and it is not guaranteed to work if there is
peer-to-peer DMA.  This isn't documented very well; the best I know of
is the changelogs for:

  a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
  b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Bjorn

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20 17:22                     ` Bjorn Helgaas
  0 siblings, 0 replies; 116+ messages in thread
From: Bjorn Helgaas @ 2014-05-20 17:22 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Karicheri, Muralidharan, Arnd Bergmann, linux-arm-kernel,
	Strashko, Grygorii, linux-pci, Jingoo Han, linux-kernel,
	Shilimkar, Santosh, Mohit Kumar

On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
<jgunthorpe@obsidianresearch.com> wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
>
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.

The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
wrinkles by setting MRRS in ways that allow some devices to have
larger MPS than others.  I don't think this is exactly what was
envisioned in the spec, and it is not guaranteed to work if there is
peer-to-peer DMA.  This isn't documented very well; the best I know of
is the changelogs for:

  a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
  b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Bjorn

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20 17:22                     ` Bjorn Helgaas
  0 siblings, 0 replies; 116+ messages in thread
From: Bjorn Helgaas @ 2014-05-20 17:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
<jgunthorpe@obsidianresearch.com> wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
>
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.

The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
wrinkles by setting MRRS in ways that allow some devices to have
larger MPS than others.  I don't think this is exactly what was
envisioned in the spec, and it is not guaranteed to work if there is
peer-to-peer DMA.  This isn't documented very well; the best I know of
is the changelogs for:

  a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
  b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Bjorn

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-20 17:22                     ` Bjorn Helgaas
  (?)
@ 2014-05-20 17:42                       ` Jason Gunthorpe
  -1 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-20 17:42 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Karicheri, Muralidharan, Arnd Bergmann, linux-arm-kernel,
	Strashko, Grygorii, linux-pci, Jingoo Han, linux-kernel,
	Shilimkar, Santosh, Mohit Kumar

On Tue, May 20, 2014 at 11:22:22AM -0600, Bjorn Helgaas wrote:
> On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
> <jgunthorpe@obsidianresearch.com> wrote:
> > On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
> >
> >> But pcie_bus_configure_settings just make sure the mrrs for a device
> >> is not greater than the max payload size.
> >
> > Not quite, it first scans the network checking the Maximum Payload Size
> > Supported (MPSS) for each device, and chooses the highest supported by
> > all as the MPS for all.
> 
> The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
> wrinkles by setting MRRS in ways that allow some devices to have
> larger MPS than others.  I don't think this is exactly what was
> envisioned in the spec, and it is not guaranteed to work if there is
> peer-to-peer DMA.  This isn't documented very well; the best I know of
> is the changelogs for:
> 
>   a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
>   b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Neat, and does pretty much confirm that setting the host bridge MPSS
properly is necessary to support all drivers, particularly the ones
that call pcie_set_readrq with any old value.

The 'performance' setting is a bit scary, it isn't just peer-to-peer
DMA that would be impacted but also CPU initiated burst writes. Eg
InfiniBand drivers burst a WQE to the NIC via the CPU. The MPS on the
root port bridge is used to segment the write. Probably not a problem
in practice because I think this is rare, and even rarer that a burst
would be > 128 bytes - but as you say, not really what the spec
intended..

Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20 17:42                       ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-20 17:42 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Karicheri, Muralidharan, Arnd Bergmann, linux-arm-kernel,
	Strashko, Grygorii, linux-pci, Jingoo Han, linux-kernel,
	Shilimkar, Santosh, Mohit Kumar

On Tue, May 20, 2014 at 11:22:22AM -0600, Bjorn Helgaas wrote:
> On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
> <jgunthorpe@obsidianresearch.com> wrote:
> > On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
> >
> >> But pcie_bus_configure_settings just make sure the mrrs for a device
> >> is not greater than the max payload size.
> >
> > Not quite, it first scans the network checking the Maximum Payload Size
> > Supported (MPSS) for each device, and chooses the highest supported by
> > all as the MPS for all.
> 
> The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
> wrinkles by setting MRRS in ways that allow some devices to have
> larger MPS than others.  I don't think this is exactly what was
> envisioned in the spec, and it is not guaranteed to work if there is
> peer-to-peer DMA.  This isn't documented very well; the best I know of
> is the changelogs for:
> 
>   a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
>   b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Neat, and does pretty much confirm that setting the host bridge MPSS
properly is necessary to support all drivers, particularly the ones
that call pcie_set_readrq with any old value.

The 'performance' setting is a bit scary, it isn't just peer-to-peer
DMA that would be impacted but also CPU initiated burst writes. Eg
InfiniBand drivers burst a WQE to the NIC via the CPU. The MPS on the
root port bridge is used to segment the write. Probably not a problem
in practice because I think this is rare, and even rarer that a burst
would be > 128 bytes - but as you say, not really what the spec
intended..

Jason

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-20 17:42                       ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-20 17:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 20, 2014 at 11:22:22AM -0600, Bjorn Helgaas wrote:
> On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
> <jgunthorpe@obsidianresearch.com> wrote:
> > On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
> >
> >> But pcie_bus_configure_settings just make sure the mrrs for a device
> >> is not greater than the max payload size.
> >
> > Not quite, it first scans the network checking the Maximum Payload Size
> > Supported (MPSS) for each device, and chooses the highest supported by
> > all as the MPS for all.
> 
> The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
> wrinkles by setting MRRS in ways that allow some devices to have
> larger MPS than others.  I don't think this is exactly what was
> envisioned in the spec, and it is not guaranteed to work if there is
> peer-to-peer DMA.  This isn't documented very well; the best I know of
> is the changelogs for:
> 
>   a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
>   b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Neat, and does pretty much confirm that setting the host bridge MPSS
properly is necessary to support all drivers, particularly the ones
that call pcie_set_readrq with any old value.

The 'performance' setting is a bit scary, it isn't just peer-to-peer
DMA that would be impacted but also CPU initiated burst writes. Eg
InfiniBand drivers burst a WQE to the NIC via the CPU. The MPS on the
root port bridge is used to segment the write. Probably not a problem
in practice because I think this is rare, and even rarer that a burst
would be > 128 bytes - but as you say, not really what the spec
intended..

Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-20 17:02                   ` Jason Gunthorpe
  (?)
@ 2014-05-21 23:32                     ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-21 23:32 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On 5/20/2014 1:02 PM, Jason Gunthorpe wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.
Why highest? It should be lowest so that all on the bus can handle it??
>
> PCI-E requires that an end point support all packets up to the MPS, so
> if your bridge can't generate a 512 byte read response packet, then it
> must not advertise a MPSS greater than 256 bytes.
What is MPSS? Is it the payload size in a message TLP? I read the PCIe 
spec and find
MRSS is the maxumum read request size. So memory reads completion data 
size is limited
to this size, right? So for DMA from EP to RC can't be greater than what 
RC publishes.
Not sure how they are related?

I have checked that root port is advertising 256 bytes for mrrs and 128 
bytes for mps
in the config space. So keystone pcie bridge is doing as expected.

In Keystone case, what I see is after  adding 
pcie_bus_configure_settings() with pci=pcie_bus_safe,
I get following log.

[    1.988851] pcie_bus_configure_settings, config 1
[    1.988860] pcie_bus_configure_set
[    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  512
[    1.988887] pcie_bus_configure_set
[    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512
[    1.988928] pcie_bus_configure_set
[    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512

So it is not limiting MRRS to 256 bytes.

With pci=pcie_bus_perf

[    1.985777] pcie_bus_configure_settings, config 2
[    1.985783] pcie_bus_configure_set
[    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    1.985818] pcie_bus_configure_set
[    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    1.985882] pcie_bus_configure_set
[    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

Is this log what you expect?

>
> Setting your MPSS to 128, 256, then using the
> pcie_bus_configure_settings to run the standard algorithm should
> properly limit the readrq to 256 and be able to properly support all
> the fun edge cases like hot plug.

> If the config space in your root port bridge is correct and already
> declares a MPSS of 256 then you have nothing else to do but make sure
> pcie_bus_configure_settings gets calls.
>
> If it is broken and claims a higher MPSS than it can support then you
> need to use a quirk only for the root port bridge or edit the config
> reply in the driver only to fix the MPSS
If MRSS is clamped to lowest, then this would work with out a quirk, and 
has to
be unconditional (all cases, safe, performance etc).

I would like to go with the quirk approach until this discussion 
concludes the next
step to fix this issue. May be someone can take owner ship of this 
change at PCI
core level?

My quirk can be removed once the fix is accepted into the tree. Is that 
an acceptable path forward?

Murali
>
> Jason


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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-21 23:32                     ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-21 23:32 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On 5/20/2014 1:02 PM, Jason Gunthorpe wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.
Why highest? It should be lowest so that all on the bus can handle it??
>
> PCI-E requires that an end point support all packets up to the MPS, so
> if your bridge can't generate a 512 byte read response packet, then it
> must not advertise a MPSS greater than 256 bytes.
What is MPSS? Is it the payload size in a message TLP? I read the PCIe 
spec and find
MRSS is the maxumum read request size. So memory reads completion data 
size is limited
to this size, right? So for DMA from EP to RC can't be greater than what 
RC publishes.
Not sure how they are related?

I have checked that root port is advertising 256 bytes for mrrs and 128 
bytes for mps
in the config space. So keystone pcie bridge is doing as expected.

In Keystone case, what I see is after  adding 
pcie_bus_configure_settings() with pci=pcie_bus_safe,
I get following log.

[    1.988851] pcie_bus_configure_settings, config 1
[    1.988860] pcie_bus_configure_set
[    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  512
[    1.988887] pcie_bus_configure_set
[    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512
[    1.988928] pcie_bus_configure_set
[    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512

So it is not limiting MRRS to 256 bytes.

With pci=pcie_bus_perf

[    1.985777] pcie_bus_configure_settings, config 2
[    1.985783] pcie_bus_configure_set
[    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    1.985818] pcie_bus_configure_set
[    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    1.985882] pcie_bus_configure_set
[    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

Is this log what you expect?

>
> Setting your MPSS to 128, 256, then using the
> pcie_bus_configure_settings to run the standard algorithm should
> properly limit the readrq to 256 and be able to properly support all
> the fun edge cases like hot plug.

> If the config space in your root port bridge is correct and already
> declares a MPSS of 256 then you have nothing else to do but make sure
> pcie_bus_configure_settings gets calls.
>
> If it is broken and claims a higher MPSS than it can support then you
> need to use a quirk only for the root port bridge or edit the config
> reply in the driver only to fix the MPSS
If MRSS is clamped to lowest, then this would work with out a quirk, and 
has to
be unconditional (all cases, safe, performance etc).

I would like to go with the quirk approach until this discussion 
concludes the next
step to fix this issue. May be someone can take owner ship of this 
change at PCI
core level?

My quirk can be removed once the fix is accepted into the tree. Is that 
an acceptable path forward?

Murali
>
> Jason


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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-21 23:32                     ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-21 23:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/20/2014 1:02 PM, Jason Gunthorpe wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.
Why highest? It should be lowest so that all on the bus can handle it??
>
> PCI-E requires that an end point support all packets up to the MPS, so
> if your bridge can't generate a 512 byte read response packet, then it
> must not advertise a MPSS greater than 256 bytes.
What is MPSS? Is it the payload size in a message TLP? I read the PCIe 
spec and find
MRSS is the maxumum read request size. So memory reads completion data 
size is limited
to this size, right? So for DMA from EP to RC can't be greater than what 
RC publishes.
Not sure how they are related?

I have checked that root port is advertising 256 bytes for mrrs and 128 
bytes for mps
in the config space. So keystone pcie bridge is doing as expected.

In Keystone case, what I see is after  adding 
pcie_bus_configure_settings() with pci=pcie_bus_safe,
I get following log.

[    1.988851] pcie_bus_configure_settings, config 1
[    1.988860] pcie_bus_configure_set
[    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  512
[    1.988887] pcie_bus_configure_set
[    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512
[    1.988928] pcie_bus_configure_set
[    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512

So it is not limiting MRRS to 256 bytes.

With pci=pcie_bus_perf

[    1.985777] pcie_bus_configure_settings, config 2
[    1.985783] pcie_bus_configure_set
[    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    1.985818] pcie_bus_configure_set
[    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    1.985882] pcie_bus_configure_set
[    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

Is this log what you expect?

>
> Setting your MPSS to 128, 256, then using the
> pcie_bus_configure_settings to run the standard algorithm should
> properly limit the readrq to 256 and be able to properly support all
> the fun edge cases like hot plug.

> If the config space in your root port bridge is correct and already
> declares a MPSS of 256 then you have nothing else to do but make sure
> pcie_bus_configure_settings gets calls.
>
> If it is broken and claims a higher MPSS than it can support then you
> need to use a quirk only for the root port bridge or edit the config
> reply in the driver only to fix the MPSS
If MRSS is clamped to lowest, then this would work with out a quirk, and 
has to
be unconditional (all cases, safe, performance etc).

I would like to go with the quirk approach until this discussion 
concludes the next
step to fix this issue. May be someone can take owner ship of this 
change at PCI
core level?

My quirk can be removed once the fix is accepted into the tree. Is that 
an acceptable path forward?

Murali
>
> Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-21 23:32                     ` Murali Karicheri
  (?)
@ 2014-05-22  0:55                       ` Jason Gunthorpe
  -1 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-22  0:55 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Wed, May 21, 2014 at 07:32:58PM -0400, Murali Karicheri wrote:

> >Not quite, it first scans the network checking the Maximum Payload Size
> >Supported (MPSS) for each device, and chooses the highest supported by
> >all as the MPS for all.

> Why highest? It should be lowest so that all on the bus can handle
> it??

Right, that is what 'chooses the highest supported by all' means.

> >PCI-E requires that an end point support all packets up to the MPS, so
> >if your bridge can't generate a 512 byte read response packet, then it
> >must not advertise a MPSS greater than 256 bytes.

> What is MPSS? Is it the payload size in a message TLP? I read the
> PCIe spec and find MRSS is the maxumum read request size. So memory
> reads completion data size is limited to this size, right? So for
> DMA from EP to RC can't be greater than what RC publishes.  Not sure
> how they are related?

MPSS is the maximum packet size supported for send or receive, it is
the absolute max capability of the port:

		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s <64ns, L1 unlimited
MPSS                      ^^^^^^^^^^^^^^^^^^^^^^^

MPS is then the largest packet the port will send or receive.

MRSS is the largest read the port will request.

		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			MaxPayload 128 bytes, MaxReadReq 512 bytes
MPS                   ^^^^^^^^^^^^^^^^^^^^^^^
MRSS                                          ^^^^^^^^^^^^^^^^^^^^


It is a little confusing what MRSS > MPS means exactly, but at a
minimum if MRSS > MPS then the responding port must segment the read
reply into MPS sized TLPs.

> I have checked that root port is advertising 256 bytes for mrrs and
> 128 bytes for mps in the config space. So keystone pcie bridge is
> doing as expected.

What is the MPSS?

> In Keystone case, what I see is after  adding
> pcie_bus_configure_settings() with pci=pcie_bus_safe,
> I get following log.
> 
> [    1.988851] pcie_bus_configure_settings, config 1
> [    1.988860] pcie_bus_configure_set
> [    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  512
> [    1.988887] pcie_bus_configure_set
> [    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> [    1.988928] pcie_bus_configure_set
> [    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> 
> So it is not limiting MRRS to 256 bytes.

Right, pcie_bus_safe is the option that doesn't really change
too much, it is assuming the firmware set everything up properly.

> With pci=pcie_bus_perf
> 
> [    1.985777] pcie_bus_configure_settings, config 2
> [    1.985783] pcie_bus_configure_set
> [    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  256
> [    1.985818] pcie_bus_configure_set
> [    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> [    1.985882] pcie_bus_configure_set
> [    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> 
> Is this log what you expect?

Yes, that matches what the code seems to do.

> If MRSS is clamped to lowest, then this would work with out a quirk,
> and has to be unconditional (all cases, safe, performance etc).

Well, except in this is working around a defect in Keystone. There are
going to be potential problems no matter which route you take because
some drivers do blindly alter the MRRS, and when the core ARM code
starts calling pcie_bus_configure_settings() it will alter the MRRS as
well.

So, the quirk solution is only going to work in some cases.

Adding pci=pcie_bus_perf to the command line in the DTS as a work
around for the defect might be the most comprehensive option?

> I would like to go with the quirk approach until this discussion
> concludes the next step to fix this issue. May be someone can take
> owner ship of this change at PCI core level?

Well, the core code isn't wrong, it just isn't designed to address this
sort of HW defect.

Regards,
Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-22  0:55                       ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-22  0:55 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Wed, May 21, 2014 at 07:32:58PM -0400, Murali Karicheri wrote:

> >Not quite, it first scans the network checking the Maximum Payload Size
> >Supported (MPSS) for each device, and chooses the highest supported by
> >all as the MPS for all.

> Why highest? It should be lowest so that all on the bus can handle
> it??

Right, that is what 'chooses the highest supported by all' means.

> >PCI-E requires that an end point support all packets up to the MPS, so
> >if your bridge can't generate a 512 byte read response packet, then it
> >must not advertise a MPSS greater than 256 bytes.

> What is MPSS? Is it the payload size in a message TLP? I read the
> PCIe spec and find MRSS is the maxumum read request size. So memory
> reads completion data size is limited to this size, right? So for
> DMA from EP to RC can't be greater than what RC publishes.  Not sure
> how they are related?

MPSS is the maximum packet size supported for send or receive, it is
the absolute max capability of the port:

		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s <64ns, L1 unlimited
MPSS                      ^^^^^^^^^^^^^^^^^^^^^^^

MPS is then the largest packet the port will send or receive.

MRSS is the largest read the port will request.

		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			MaxPayload 128 bytes, MaxReadReq 512 bytes
MPS                   ^^^^^^^^^^^^^^^^^^^^^^^
MRSS                                          ^^^^^^^^^^^^^^^^^^^^


It is a little confusing what MRSS > MPS means exactly, but at a
minimum if MRSS > MPS then the responding port must segment the read
reply into MPS sized TLPs.

> I have checked that root port is advertising 256 bytes for mrrs and
> 128 bytes for mps in the config space. So keystone pcie bridge is
> doing as expected.

What is the MPSS?

> In Keystone case, what I see is after  adding
> pcie_bus_configure_settings() with pci=pcie_bus_safe,
> I get following log.
> 
> [    1.988851] pcie_bus_configure_settings, config 1
> [    1.988860] pcie_bus_configure_set
> [    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  512
> [    1.988887] pcie_bus_configure_set
> [    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> [    1.988928] pcie_bus_configure_set
> [    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> 
> So it is not limiting MRRS to 256 bytes.

Right, pcie_bus_safe is the option that doesn't really change
too much, it is assuming the firmware set everything up properly.

> With pci=pcie_bus_perf
> 
> [    1.985777] pcie_bus_configure_settings, config 2
> [    1.985783] pcie_bus_configure_set
> [    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  256
> [    1.985818] pcie_bus_configure_set
> [    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> [    1.985882] pcie_bus_configure_set
> [    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> 
> Is this log what you expect?

Yes, that matches what the code seems to do.

> If MRSS is clamped to lowest, then this would work with out a quirk,
> and has to be unconditional (all cases, safe, performance etc).

Well, except in this is working around a defect in Keystone. There are
going to be potential problems no matter which route you take because
some drivers do blindly alter the MRRS, and when the core ARM code
starts calling pcie_bus_configure_settings() it will alter the MRRS as
well.

So, the quirk solution is only going to work in some cases.

Adding pci=pcie_bus_perf to the command line in the DTS as a work
around for the defect might be the most comprehensive option?

> I would like to go with the quirk approach until this discussion
> concludes the next step to fix this issue. May be someone can take
> owner ship of this change at PCI core level?

Well, the core code isn't wrong, it just isn't designed to address this
sort of HW defect.

Regards,
Jason

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-22  0:55                       ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-22  0:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 21, 2014 at 07:32:58PM -0400, Murali Karicheri wrote:

> >Not quite, it first scans the network checking the Maximum Payload Size
> >Supported (MPSS) for each device, and chooses the highest supported by
> >all as the MPS for all.

> Why highest? It should be lowest so that all on the bus can handle
> it??

Right, that is what 'chooses the highest supported by all' means.

> >PCI-E requires that an end point support all packets up to the MPS, so
> >if your bridge can't generate a 512 byte read response packet, then it
> >must not advertise a MPSS greater than 256 bytes.

> What is MPSS? Is it the payload size in a message TLP? I read the
> PCIe spec and find MRSS is the maxumum read request size. So memory
> reads completion data size is limited to this size, right? So for
> DMA from EP to RC can't be greater than what RC publishes.  Not sure
> how they are related?

MPSS is the maximum packet size supported for send or receive, it is
the absolute max capability of the port:

		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s <64ns, L1 unlimited
MPSS                      ^^^^^^^^^^^^^^^^^^^^^^^

MPS is then the largest packet the port will send or receive.

MRSS is the largest read the port will request.

		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			MaxPayload 128 bytes, MaxReadReq 512 bytes
MPS                   ^^^^^^^^^^^^^^^^^^^^^^^
MRSS                                          ^^^^^^^^^^^^^^^^^^^^


It is a little confusing what MRSS > MPS means exactly, but at a
minimum if MRSS > MPS then the responding port must segment the read
reply into MPS sized TLPs.

> I have checked that root port is advertising 256 bytes for mrrs and
> 128 bytes for mps in the config space. So keystone pcie bridge is
> doing as expected.

What is the MPSS?

> In Keystone case, what I see is after  adding
> pcie_bus_configure_settings() with pci=pcie_bus_safe,
> I get following log.
> 
> [    1.988851] pcie_bus_configure_settings, config 1
> [    1.988860] pcie_bus_configure_set
> [    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  512
> [    1.988887] pcie_bus_configure_set
> [    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> [    1.988928] pcie_bus_configure_set
> [    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> 
> So it is not limiting MRRS to 256 bytes.

Right, pcie_bus_safe is the option that doesn't really change
too much, it is assuming the firmware set everything up properly.

> With pci=pcie_bus_perf
> 
> [    1.985777] pcie_bus_configure_settings, config 2
> [    1.985783] pcie_bus_configure_set
> [    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  256
> [    1.985818] pcie_bus_configure_set
> [    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> [    1.985882] pcie_bus_configure_set
> [    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> 
> Is this log what you expect?

Yes, that matches what the code seems to do.

> If MRSS is clamped to lowest, then this would work with out a quirk,
> and has to be unconditional (all cases, safe, performance etc).

Well, except in this is working around a defect in Keystone. There are
going to be potential problems no matter which route you take because
some drivers do blindly alter the MRRS, and when the core ARM code
starts calling pcie_bus_configure_settings() it will alter the MRRS as
well.

So, the quirk solution is only going to work in some cases.

Adding pci=pcie_bus_perf to the command line in the DTS as a work
around for the defect might be the most comprehensive option?

> I would like to go with the quirk approach until this discussion
> concludes the next step to fix this issue. May be someone can take
> owner ship of this change at PCI core level?

Well, the core code isn't wrong, it just isn't designed to address this
sort of HW defect.

Regards,
Jason

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-05-15 16:14     ` Arnd Bergmann
  (?)
@ 2014-05-23 17:14       ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-23 17:14 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, Mohit Kumar,
	Jingoo Han, Rob Herring, Bjorn Helgaas, Grant Likely

On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>> +       {0x0000, 0x00000800, 0x0000ff00},
>> +       {0x0060, 0x00041c5c, 0x00ffffff},
>> +       {0x0064, 0x0343c700, 0xffffff00},
>> +       {0x006c, 0x00000012, 0x000000ff},
>> +       {0x0068, 0x00070000, 0x00ff0000},
>> +       {0x0078, 0x0000c000, 0x0000ff00},
> It looks like the PHY is generic, but the configuration above is
> PCI specific. If this is true, you should have #phy-cells=<1>
> and document the possible modes, adding a lookup table here to
> pick the configuration based on the argument. It's fine to just
> implement pcie-5ghz initially, but the binding should list all
> the modes that the PHY can support.

The PCIE name needs to be dropped and as you correctly guessed, this SERDES
is generic.
>
> Also, please list the exact name of the phy if you can find it
> out. You mention that you don't know the register descriptions,
> but you should at least be able to let us know what phy this
> is, in case some other SoC reuses the same thing.
Unfortunately there is a NDA restriction that prevents us from using the
actual Phy name and keystone phy is the name what we can usel at the 
moment. I am checking
this with our IP team and if original name can  be used, I will update 
the driver to reflect the same.
>> +static int ks_phy_init(struct phy *phy)
>> +{
>> +       struct serdes_config *p;
>> +       struct phy_keystone *ks_phy = phy_get_drvdata(phy);
>> +
>> +       int i;
>> +
>> +       for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
>> +               i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
>> +               i++, p++) {
>> +               reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
>> +               reg_dump((ks_phy->base + p->reg), p->mask);
>> +       }
>> +       udelay(2000);
> This should probably be msleep(2);
Fine.

Murali
>
> 	Arnd


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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-23 17:14       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-23 17:14 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, Mohit Kumar,
	Jingoo Han, Rob Herring, Bjorn Helgaas, Grant Likely

On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>> +       {0x0000, 0x00000800, 0x0000ff00},
>> +       {0x0060, 0x00041c5c, 0x00ffffff},
>> +       {0x0064, 0x0343c700, 0xffffff00},
>> +       {0x006c, 0x00000012, 0x000000ff},
>> +       {0x0068, 0x00070000, 0x00ff0000},
>> +       {0x0078, 0x0000c000, 0x0000ff00},
> It looks like the PHY is generic, but the configuration above is
> PCI specific. If this is true, you should have #phy-cells=<1>
> and document the possible modes, adding a lookup table here to
> pick the configuration based on the argument. It's fine to just
> implement pcie-5ghz initially, but the binding should list all
> the modes that the PHY can support.

The PCIE name needs to be dropped and as you correctly guessed, this SERDES
is generic.
>
> Also, please list the exact name of the phy if you can find it
> out. You mention that you don't know the register descriptions,
> but you should at least be able to let us know what phy this
> is, in case some other SoC reuses the same thing.
Unfortunately there is a NDA restriction that prevents us from using the
actual Phy name and keystone phy is the name what we can usel at the 
moment. I am checking
this with our IP team and if original name can  be used, I will update 
the driver to reflect the same.
>> +static int ks_phy_init(struct phy *phy)
>> +{
>> +       struct serdes_config *p;
>> +       struct phy_keystone *ks_phy = phy_get_drvdata(phy);
>> +
>> +       int i;
>> +
>> +       for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
>> +               i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
>> +               i++, p++) {
>> +               reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
>> +               reg_dump((ks_phy->base + p->reg), p->mask);
>> +       }
>> +       udelay(2000);
> This should probably be msleep(2);
Fine.

Murali
>
> 	Arnd


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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-23 17:14       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-23 17:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>> +       {0x0000, 0x00000800, 0x0000ff00},
>> +       {0x0060, 0x00041c5c, 0x00ffffff},
>> +       {0x0064, 0x0343c700, 0xffffff00},
>> +       {0x006c, 0x00000012, 0x000000ff},
>> +       {0x0068, 0x00070000, 0x00ff0000},
>> +       {0x0078, 0x0000c000, 0x0000ff00},
> It looks like the PHY is generic, but the configuration above is
> PCI specific. If this is true, you should have #phy-cells=<1>
> and document the possible modes, adding a lookup table here to
> pick the configuration based on the argument. It's fine to just
> implement pcie-5ghz initially, but the binding should list all
> the modes that the PHY can support.

The PCIE name needs to be dropped and as you correctly guessed, this SERDES
is generic.
>
> Also, please list the exact name of the phy if you can find it
> out. You mention that you don't know the register descriptions,
> but you should at least be able to let us know what phy this
> is, in case some other SoC reuses the same thing.
Unfortunately there is a NDA restriction that prevents us from using the
actual Phy name and keystone phy is the name what we can usel at the 
moment. I am checking
this with our IP team and if original name can  be used, I will update 
the driver to reflect the same.
>> +static int ks_phy_init(struct phy *phy)
>> +{
>> +       struct serdes_config *p;
>> +       struct phy_keystone *ks_phy = phy_get_drvdata(phy);
>> +
>> +       int i;
>> +
>> +       for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
>> +               i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
>> +               i++, p++) {
>> +               reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
>> +               reg_dump((ks_phy->base + p->reg), p->mask);
>> +       }
>> +       udelay(2000);
> This should probably be msleep(2);
Fine.

Murali
>
> 	Arnd

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-05-23 17:14       ` Murali Karicheri
@ 2014-05-23 19:23         ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-23 19:23 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Murali Karicheri, linux-pci, Jingoo Han, linux-kernel,
	Grant Likely, Rob Herring, Mohit Kumar, Bjorn Helgaas

On Friday 23 May 2014 13:14:00 Murali Karicheri wrote:
> On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
> >> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> >> +       {0x0000, 0x00000800, 0x0000ff00},
> >> +       {0x0060, 0x00041c5c, 0x00ffffff},
> >> +       {0x0064, 0x0343c700, 0xffffff00},
> >> +       {0x006c, 0x00000012, 0x000000ff},
> >> +       {0x0068, 0x00070000, 0x00ff0000},
> >> +       {0x0078, 0x0000c000, 0x0000ff00},
> > It looks like the PHY is generic, but the configuration above is
> > PCI specific. If this is true, you should have #phy-cells=<1>
> > and document the possible modes, adding a lookup table here to
> > pick the configuration based on the argument. It's fine to just
> > implement pcie-5ghz initially, but the binding should list all
> > the modes that the PHY can support.
> 
> The PCIE name needs to be dropped and as you correctly guessed, this SERDES
> is generic.

Ok, good.

> > Also, please list the exact name of the phy if you can find it
> > out. You mention that you don't know the register descriptions,
> > but you should at least be able to let us know what phy this
> > is, in case some other SoC reuses the same thing.
>
> Unfortunately there is a NDA restriction that prevents us from using the
> actual Phy name and keystone phy is the name what we can usel at the 
> moment. I am checking
> this with our IP team and if original name can  be used, I will update 
> the driver to reflect the same.

Can you please check the phy drivers that we already have in linux-next
to see if any of those are for the same hardware then?

I guess it's our best hope to catch duplications by inspecting all
other phy drivers as they get merged then.

	Arnd

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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-23 19:23         ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-23 19:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 23 May 2014 13:14:00 Murali Karicheri wrote:
> On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
> >> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> >> +       {0x0000, 0x00000800, 0x0000ff00},
> >> +       {0x0060, 0x00041c5c, 0x00ffffff},
> >> +       {0x0064, 0x0343c700, 0xffffff00},
> >> +       {0x006c, 0x00000012, 0x000000ff},
> >> +       {0x0068, 0x00070000, 0x00ff0000},
> >> +       {0x0078, 0x0000c000, 0x0000ff00},
> > It looks like the PHY is generic, but the configuration above is
> > PCI specific. If this is true, you should have #phy-cells=<1>
> > and document the possible modes, adding a lookup table here to
> > pick the configuration based on the argument. It's fine to just
> > implement pcie-5ghz initially, but the binding should list all
> > the modes that the PHY can support.
> 
> The PCIE name needs to be dropped and as you correctly guessed, this SERDES
> is generic.

Ok, good.

> > Also, please list the exact name of the phy if you can find it
> > out. You mention that you don't know the register descriptions,
> > but you should at least be able to let us know what phy this
> > is, in case some other SoC reuses the same thing.
>
> Unfortunately there is a NDA restriction that prevents us from using the
> actual Phy name and keystone phy is the name what we can usel at the 
> moment. I am checking
> this with our IP team and if original name can  be used, I will update 
> the driver to reflect the same.

Can you please check the phy drivers that we already have in linux-next
to see if any of those are for the same hardware then?

I guess it's our best hope to catch duplications by inspecting all
other phy drivers as they get merged then.

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
       [not found]                       ` <537E7823.5060609@ti.com>
  2014-05-26 23:31                           ` Jason Gunthorpe
@ 2014-05-26 23:31                           ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-26 23:31 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Thu, May 22, 2014 at 06:20:19PM -0400, Murali Karicheri wrote:

>> What is the MPSS?
> 
>    MPS published in DEV CAP is 1 (256 bytes). In our IP for some reason,
>    mrss is set to 2 though IP
>    support only 256 bytes. I am trying to resolve this with IP team. If
>    this is an IP issue, then
>    software will overwrite this to 1.

The MRSS of the root port bridge is very rarely used, it is OK to be
larger than the MPS, but I'm not sure it makes much sense as a
default.

>    So the mps  will not get written to mrss for performance mode. So the
>    check seems not right. It should be changed to

So, looking at this more closely, the MRRS does not *have* to be
smaller than the MPS, but it probably performs better if it is.

I think that reflects what the code is doing.

The fact your root complex can't segment replies is a serious defect,
and there is no infrastructure to support that in the kernel.

Adding something to this generic code might be your best option to
cover the majority of cases.

It would also be good to know for sure that it can correctly segment a
256 byte read into 128 byte packets, and that only 512 is mishandled.

Jason

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-26 23:31                           ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-26 23:31 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: Arnd Bergmann, linux-arm-kernel, Strashko, Grygorii, linux-pci,
	Jingoo Han, linux-kernel, Shilimkar, Santosh, Mohit Kumar,
	Bjorn Helgaas

On Thu, May 22, 2014 at 06:20:19PM -0400, Murali Karicheri wrote:

>> What is the MPSS?
> 
>    MPS published in DEV CAP is 1 (256 bytes). In our IP for some reason,
>    mrss is set to 2 though IP
>    support only 256 bytes. I am trying to resolve this with IP team. If
>    this is an IP issue, then
>    software will overwrite this to 1.

The MRSS of the root port bridge is very rarely used, it is OK to be
larger than the MPS, but I'm not sure it makes much sense as a
default.

>    So the mps  will not get written to mrss for performance mode. So the
>    check seems not right. It should be changed to

So, looking at this more closely, the MRRS does not *have* to be
smaller than the MPS, but it probably performs better if it is.

I think that reflects what the code is doing.

The fact your root complex can't segment replies is a serious defect,
and there is no infrastructure to support that in the kernel.

Adding something to this generic code might be your best option to
cover the majority of cases.

It would also be good to know for sure that it can correctly segment a
256 byte read into 128 byte packets, and that only 512 is mishandled.

Jason

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-26 23:31                           ` Jason Gunthorpe
  0 siblings, 0 replies; 116+ messages in thread
From: Jason Gunthorpe @ 2014-05-26 23:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 22, 2014 at 06:20:19PM -0400, Murali Karicheri wrote:

>> What is the MPSS?
> 
>    MPS published in DEV CAP is 1 (256 bytes). In our IP for some reason,
>    mrss is set to 2 though IP
>    support only 256 bytes. I am trying to resolve this with IP team. If
>    this is an IP issue, then
>    software will overwrite this to 1.

The MRSS of the root port bridge is very rarely used, it is OK to be
larger than the MPS, but I'm not sure it makes much sense as a
default.

>    So the mps  will not get written to mrss for performance mode. So the
>    check seems not right. It should be changed to

So, looking at this more closely, the MRRS does not *have* to be
smaller than the MPS, but it probably performs better if it is.

I think that reflects what the code is doing.

The fact your root complex can't segment replies is a serious defect,
and there is no infrastructure to support that in the kernel.

Adding something to this generic code might be your best option to
cover the majority of cases.

It would also be good to know for sure that it can correctly segment a
256 byte read into 128 byte packets, and that only 512 is mishandled.

Jason

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-05-23 19:23         ` Arnd Bergmann
  (?)
@ 2014-05-27 16:46           ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-27 16:46 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-pci, Jingoo Han, linux-kernel,
	Grant Likely, Rob Herring, Mohit Kumar, Bjorn Helgaas

On 5/23/2014 3:23 PM, Arnd Bergmann wrote:
> On Friday 23 May 2014 13:14:00 Murali Karicheri wrote:
>> On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
>>> On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
>>>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>>>> +       {0x0000, 0x00000800, 0x0000ff00},
>>>> +       {0x0060, 0x00041c5c, 0x00ffffff},
>>>> +       {0x0064, 0x0343c700, 0xffffff00},
>>>> +       {0x006c, 0x00000012, 0x000000ff},
>>>> +       {0x0068, 0x00070000, 0x00ff0000},
>>>> +       {0x0078, 0x0000c000, 0x0000ff00},
>>> It looks like the PHY is generic, but the configuration above is
>>> PCI specific. If this is true, you should have #phy-cells=<1>
>>> and document the possible modes, adding a lookup table here to
>>> pick the configuration based on the argument. It's fine to just
>>> implement pcie-5ghz initially, but the binding should list all
>>> the modes that the PHY can support.
>> The PCIE name needs to be dropped and as you correctly guessed, this SERDES
>> is generic.
> Ok, good.
>
>>> Also, please list the exact name of the phy if you can find it
>>> out. You mention that you don't know the register descriptions,
>>> but you should at least be able to let us know what phy this
>>> is, in case some other SoC reuses the same thing.
>> Unfortunately there is a NDA restriction that prevents us from using the
>> actual Phy name and keystone phy is the name what we can usel at the
>> moment. I am checking
>> this with our IP team and if original name can  be used, I will update
>> the driver to reflect the same.
> Can you please check the phy drivers that we already have in linux-next
> to see if any of those are for the same hardware then?
>
> I guess it's our best hope to catch duplications by inspecting all
> other phy drivers as they get merged then.
>
> 	Arnd
Arnd,

I have checked the register set of the following drivers under 
drivers/phy from the
master branch (v3.15-rc6) using the registers set available with us 
internally and
I can't find a match.

phy-exynos5250-sata.c  phy-exynos-mipi-video.c  phy-omap-usb2.c 
phy-sun4i-usb.c
phy-xgene.c phy-exynos4210-usb2.c  phy-exynos5250-usb2.c phy-mvebu-sata.c
phy-samsung-usb2.c  phy-ti-pipe3.c phy-bcm-kona-usb2.c phy-exynos4x12-usb2.c
  phy-exynos-dp-video.c  phy-omap-control.c  phy-twl4030-usb.c

So there is no duplication.

Murali


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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-27 16:46           ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-27 16:46 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-pci, Jingoo Han, linux-kernel,
	Grant Likely, Rob Herring, Mohit Kumar, Bjorn Helgaas

On 5/23/2014 3:23 PM, Arnd Bergmann wrote:
> On Friday 23 May 2014 13:14:00 Murali Karicheri wrote:
>> On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
>>> On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
>>>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>>>> +       {0x0000, 0x00000800, 0x0000ff00},
>>>> +       {0x0060, 0x00041c5c, 0x00ffffff},
>>>> +       {0x0064, 0x0343c700, 0xffffff00},
>>>> +       {0x006c, 0x00000012, 0x000000ff},
>>>> +       {0x0068, 0x00070000, 0x00ff0000},
>>>> +       {0x0078, 0x0000c000, 0x0000ff00},
>>> It looks like the PHY is generic, but the configuration above is
>>> PCI specific. If this is true, you should have #phy-cells=<1>
>>> and document the possible modes, adding a lookup table here to
>>> pick the configuration based on the argument. It's fine to just
>>> implement pcie-5ghz initially, but the binding should list all
>>> the modes that the PHY can support.
>> The PCIE name needs to be dropped and as you correctly guessed, this SERDES
>> is generic.
> Ok, good.
>
>>> Also, please list the exact name of the phy if you can find it
>>> out. You mention that you don't know the register descriptions,
>>> but you should at least be able to let us know what phy this
>>> is, in case some other SoC reuses the same thing.
>> Unfortunately there is a NDA restriction that prevents us from using the
>> actual Phy name and keystone phy is the name what we can usel at the
>> moment. I am checking
>> this with our IP team and if original name can  be used, I will update
>> the driver to reflect the same.
> Can you please check the phy drivers that we already have in linux-next
> to see if any of those are for the same hardware then?
>
> I guess it's our best hope to catch duplications by inspecting all
> other phy drivers as they get merged then.
>
> 	Arnd
Arnd,

I have checked the register set of the following drivers under 
drivers/phy from the
master branch (v3.15-rc6) using the registers set available with us 
internally and
I can't find a match.

phy-exynos5250-sata.c  phy-exynos-mipi-video.c  phy-omap-usb2.c 
phy-sun4i-usb.c
phy-xgene.c phy-exynos4210-usb2.c  phy-exynos5250-usb2.c phy-mvebu-sata.c
phy-samsung-usb2.c  phy-ti-pipe3.c phy-bcm-kona-usb2.c phy-exynos4x12-usb2.c
  phy-exynos-dp-video.c  phy-omap-control.c  phy-twl4030-usb.c

So there is no duplication.

Murali


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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-27 16:46           ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-27 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/23/2014 3:23 PM, Arnd Bergmann wrote:
> On Friday 23 May 2014 13:14:00 Murali Karicheri wrote:
>> On 5/15/2014 12:14 PM, Arnd Bergmann wrote:
>>> On Thursday 15 May 2014 12:01:30 Murali Karicheri wrote:
>>>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>>>> +       {0x0000, 0x00000800, 0x0000ff00},
>>>> +       {0x0060, 0x00041c5c, 0x00ffffff},
>>>> +       {0x0064, 0x0343c700, 0xffffff00},
>>>> +       {0x006c, 0x00000012, 0x000000ff},
>>>> +       {0x0068, 0x00070000, 0x00ff0000},
>>>> +       {0x0078, 0x0000c000, 0x0000ff00},
>>> It looks like the PHY is generic, but the configuration above is
>>> PCI specific. If this is true, you should have #phy-cells=<1>
>>> and document the possible modes, adding a lookup table here to
>>> pick the configuration based on the argument. It's fine to just
>>> implement pcie-5ghz initially, but the binding should list all
>>> the modes that the PHY can support.
>> The PCIE name needs to be dropped and as you correctly guessed, this SERDES
>> is generic.
> Ok, good.
>
>>> Also, please list the exact name of the phy if you can find it
>>> out. You mention that you don't know the register descriptions,
>>> but you should at least be able to let us know what phy this
>>> is, in case some other SoC reuses the same thing.
>> Unfortunately there is a NDA restriction that prevents us from using the
>> actual Phy name and keystone phy is the name what we can usel at the
>> moment. I am checking
>> this with our IP team and if original name can  be used, I will update
>> the driver to reflect the same.
> Can you please check the phy drivers that we already have in linux-next
> to see if any of those are for the same hardware then?
>
> I guess it's our best hope to catch duplications by inspecting all
> other phy drivers as they get merged then.
>
> 	Arnd
Arnd,

I have checked the register set of the following drivers under 
drivers/phy from the
master branch (v3.15-rc6) using the registers set available with us 
internally and
I can't find a match.

phy-exynos5250-sata.c  phy-exynos-mipi-video.c  phy-omap-usb2.c 
phy-sun4i-usb.c
phy-xgene.c phy-exynos4210-usb2.c  phy-exynos5250-usb2.c phy-mvebu-sata.c
phy-samsung-usb2.c  phy-ti-pipe3.c phy-bcm-kona-usb2.c phy-exynos4x12-usb2.c
  phy-exynos-dp-video.c  phy-omap-control.c  phy-twl4030-usb.c

So there is no duplication.

Murali

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-05-27 16:46           ` Murali Karicheri
  (?)
@ 2014-05-27 18:36             ` Arnd Bergmann
  -1 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-27 18:36 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-arm-kernel, linux-pci, Jingoo Han, linux-kernel,
	Grant Likely, Rob Herring, Mohit Kumar, Bjorn Helgaas

On Tuesday 27 May 2014 12:46:54 Murali Karicheri wrote:
> I have checked the register set of the following drivers under 
> drivers/phy from the
> master branch (v3.15-rc6) using the registers set available with us 
> internally and
> I can't find a match.
> 
> phy-exynos5250-sata.c  phy-exynos-mipi-video.c  phy-omap-usb2.c 
> phy-sun4i-usb.c
> phy-xgene.c phy-exynos4210-usb2.c  phy-exynos5250-usb2.c phy-mvebu-sata.c
> phy-samsung-usb2.c  phy-ti-pipe3.c phy-bcm-kona-usb2.c phy-exynos4x12-usb2.c
>   phy-exynos-dp-video.c  phy-omap-control.c  phy-twl4030-usb.c
> 
> So there is no duplication.

Ok, thanks a lot for checking!

	Arnd

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-27 18:36             ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-27 18:36 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-arm-kernel, linux-pci, Jingoo Han, linux-kernel,
	Grant Likely, Rob Herring, Mohit Kumar, Bjorn Helgaas

On Tuesday 27 May 2014 12:46:54 Murali Karicheri wrote:
> I have checked the register set of the following drivers under 
> drivers/phy from the
> master branch (v3.15-rc6) using the registers set available with us 
> internally and
> I can't find a match.
> 
> phy-exynos5250-sata.c  phy-exynos-mipi-video.c  phy-omap-usb2.c 
> phy-sun4i-usb.c
> phy-xgene.c phy-exynos4210-usb2.c  phy-exynos5250-usb2.c phy-mvebu-sata.c
> phy-samsung-usb2.c  phy-ti-pipe3.c phy-bcm-kona-usb2.c phy-exynos4x12-usb2.c
>   phy-exynos-dp-video.c  phy-omap-control.c  phy-twl4030-usb.c
> 
> So there is no duplication.

Ok, thanks a lot for checking!

	Arnd

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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-05-27 18:36             ` Arnd Bergmann
  0 siblings, 0 replies; 116+ messages in thread
From: Arnd Bergmann @ 2014-05-27 18:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 27 May 2014 12:46:54 Murali Karicheri wrote:
> I have checked the register set of the following drivers under 
> drivers/phy from the
> master branch (v3.15-rc6) using the registers set available with us 
> internally and
> I can't find a match.
> 
> phy-exynos5250-sata.c  phy-exynos-mipi-video.c  phy-omap-usb2.c 
> phy-sun4i-usb.c
> phy-xgene.c phy-exynos4210-usb2.c  phy-exynos5250-usb2.c phy-mvebu-sata.c
> phy-samsung-usb2.c  phy-ti-pipe3.c phy-bcm-kona-usb2.c phy-exynos4x12-usb2.c
>   phy-exynos-dp-video.c  phy-omap-control.c  phy-twl4030-usb.c
> 
> So there is no duplication.

Ok, thanks a lot for checking!

	Arnd

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
  2014-05-15 16:23     ` Arnd Bergmann
  (?)
@ 2014-05-29 15:34       ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-29 15:34 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, Strashko, Grygorii,
	Mohit Kumar, Jingoo Han, Shilimkar, Santosh, Bjorn Helgaas

On 5/15/2014 12:23 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>
>> +static int
>> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>> +		struct pt_regs *regs)
>> +{
>> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>> +
>> +	if ((instr & 0x0e100090) == 0x00100090) {
>> +		int reg = (instr >> 12) & 15;
>> +
>> +		regs->uregs[reg] = -1;
>> +		regs->ARM_pc += 4;
>> +	}
>> +
>> +	return 0;
>> +}
> This needs to check in the PCI host registers what happened and do
> some appropriate action. If the fault was not caused by PCIe, it
> should not be ignored here but get passed on to the next handler.
>
>
Arnd,

The PCI controller is not able to detect the abort error from the EP and 
this gets
reported to ARM as an Asynchronous external abort. PCI fault handler 
needs to
consume this fault, otherwise it can't work on the Keystone h/w.

For example pci-imx6.c has

/*  Added for PCI abort handling */
static int imx6q_pcie_abort_handler(unsigned long addr,
                 unsigned int fsr, struct pt_regs *regs)
{
         return 0;
}

Other examples are

1) arch/arm/mach-cns3xxx/pci.c
static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
                                       struct pt_regs *regs)
{
         if (fsr & (1 << 10))
                 regs->ARM_pc += 4;
         return 0;
}
2) arch/.arm/plat-iop/pci.c
/*
  * When a PCI device does not exist during config cycles, the 80200 gets a
  * bus error instead of returning 0xffffffff. This handler simply returns.
  */
static int
iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
         DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR 
= 0x%08lx\n",
                 addr, fsr, regs->ARM_pc, regs->ARM_lr);

         /*
          * If it was an imprecise abort, then we need to correct the
          * return address to be _after_ the instruction.
          */
         if (fsr & (1 << 10))
                 regs->ARM_pc += 4;

         return 0;
}

I suggest we document this as done in plat-iop. Let me know as I need to 
post my
v2 of the patch this week that incorporates all the comments so far on v1.

Murali

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

* Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-29 15:34       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-29 15:34 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-kernel, linux-pci, Strashko, Grygorii,
	Mohit Kumar, Jingoo Han, Shilimkar, Santosh, Bjorn Helgaas

On 5/15/2014 12:23 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>
>> +static int
>> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>> +		struct pt_regs *regs)
>> +{
>> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>> +
>> +	if ((instr & 0x0e100090) == 0x00100090) {
>> +		int reg = (instr >> 12) & 15;
>> +
>> +		regs->uregs[reg] = -1;
>> +		regs->ARM_pc += 4;
>> +	}
>> +
>> +	return 0;
>> +}
> This needs to check in the PCI host registers what happened and do
> some appropriate action. If the fault was not caused by PCIe, it
> should not be ignored here but get passed on to the next handler.
>
>
Arnd,

The PCI controller is not able to detect the abort error from the EP and 
this gets
reported to ARM as an Asynchronous external abort. PCI fault handler 
needs to
consume this fault, otherwise it can't work on the Keystone h/w.

For example pci-imx6.c has

/*  Added for PCI abort handling */
static int imx6q_pcie_abort_handler(unsigned long addr,
                 unsigned int fsr, struct pt_regs *regs)
{
         return 0;
}

Other examples are

1) arch/arm/mach-cns3xxx/pci.c
static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
                                       struct pt_regs *regs)
{
         if (fsr & (1 << 10))
                 regs->ARM_pc += 4;
         return 0;
}
2) arch/.arm/plat-iop/pci.c
/*
  * When a PCI device does not exist during config cycles, the 80200 gets a
  * bus error instead of returning 0xffffffff. This handler simply returns.
  */
static int
iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
         DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR 
= 0x%08lx\n",
                 addr, fsr, regs->ARM_pc, regs->ARM_lr);

         /*
          * If it was an imprecise abort, then we need to correct the
          * return address to be _after_ the instruction.
          */
         if (fsr & (1 << 10))
                 regs->ARM_pc += 4;

         return 0;
}

I suggest we document this as done in plat-iop. Let me know as I need to 
post my
v2 of the patch this week that incorporates all the comments so far on v1.

Murali

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

* [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
@ 2014-05-29 15:34       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-05-29 15:34 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/15/2014 12:23 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>
>> +static int
>> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>> +		struct pt_regs *regs)
>> +{
>> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>> +
>> +	if ((instr & 0x0e100090) == 0x00100090) {
>> +		int reg = (instr >> 12) & 15;
>> +
>> +		regs->uregs[reg] = -1;
>> +		regs->ARM_pc += 4;
>> +	}
>> +
>> +	return 0;
>> +}
> This needs to check in the PCI host registers what happened and do
> some appropriate action. If the fault was not caused by PCIe, it
> should not be ignored here but get passed on to the next handler.
>
>
Arnd,

The PCI controller is not able to detect the abort error from the EP and 
this gets
reported to ARM as an Asynchronous external abort. PCI fault handler 
needs to
consume this fault, otherwise it can't work on the Keystone h/w.

For example pci-imx6.c has

/*  Added for PCI abort handling */
static int imx6q_pcie_abort_handler(unsigned long addr,
                 unsigned int fsr, struct pt_regs *regs)
{
         return 0;
}

Other examples are

1) arch/arm/mach-cns3xxx/pci.c
static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
                                       struct pt_regs *regs)
{
         if (fsr & (1 << 10))
                 regs->ARM_pc += 4;
         return 0;
}
2) arch/.arm/plat-iop/pci.c
/*
  * When a PCI device does not exist during config cycles, the 80200 gets a
  * bus error instead of returning 0xffffffff. This handler simply returns.
  */
static int
iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
         DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR 
= 0x%08lx\n",
                 addr, fsr, regs->ARM_pc, regs->ARM_lr);

         /*
          * If it was an imprecise abort, then we need to correct the
          * return address to be _after_ the instruction.
          */
         if (fsr & (1 << 10))
                 regs->ARM_pc += 4;

         return 0;
}

I suggest we document this as done in plat-iop. Let me know as I need to 
post my
v2 of the patch this week that incorporates all the comments so far on v1.

Murali

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-05-15 16:01   ` Murali Karicheri
@ 2014-06-02  6:16     ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 116+ messages in thread
From: Kishon Vijay Abraham I @ 2014-06-02  6:16 UTC (permalink / raw)
  To: Murali Karicheri, linux-kernel, linux-pci, linux-arm-kernel
  Cc: Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas

Hi,

On Thursday 15 May 2014 09:31 PM, Murali Karicheri wrote:
> This phy driver is used by keystone PCI driver. The hw vendor that
> provides the phy hw published only registers and their values. So
> this driver uses these hard coded values to initialize the phy.
> 
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
>  drivers/phy/Kconfig        |    6 ++
>  drivers/phy/Makefile       |    1 +
>  drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 237 insertions(+)
>  create mode 100644 drivers/phy/phy-keystone.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 4906c27..e5f4b5a 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -167,4 +167,10 @@ config PHY_XGENE
>  	help
>  	  This option enables support for APM X-Gene SoC multi-purpose PHY.
>  
> +config PHY_TI_KEYSTONE
> +	bool "TI Keystone PHY support"
> +	depends on ARCH_KEYSTONE
> +	select GENERIC_PHY
> +	help
> +	  This option enables support for TI Keystone PHY (serdes).
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 7728518..bd306a7 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
>  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
>  obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
> +obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
> diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
> new file mode 100644
> index 0000000..ba1b9fa
> --- /dev/null
> +++ b/drivers/phy/phy-keystone.c
> @@ -0,0 +1,230 @@
> +/*
> + * PCIe Keystone platform specific driver code
> + *
> + * Copyright (C) 2013-2014 Texas Instruments, Inc.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri <m-karicheri2@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +
> +#define reg_dump(addr, mask) \
> +		pr_debug("reg %p has value %x\n", (void *)addr, \
> +			(readl(addr) & ~mask))
> +
> +/* mask bits point to bits being modified */
> +#define reg_rmw(addr, value, mask) \
> +		writel(((readl(addr) & (~(mask))) | \
> +			(value & (mask))), (addr))
> +struct serdes_config {
> +	u32 reg;
> +	u32 val;
> +	u32 mask;
> +};
> +
> +struct phy_keystone {
> +	struct device *dev;
> +	void __iomem *base;
> +};
> +
> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> +	{0x0000, 0x00000800, 0x0000ff00},
> +	{0x0060, 0x00041c5c, 0x00ffffff},
> +	{0x0064, 0x0343c700, 0xffffff00},
> +	{0x006c, 0x00000012, 0x000000ff},
> +	{0x0068, 0x00070000, 0x00ff0000},
> +	{0x0078, 0x0000c000, 0x0000ff00},
> +
> +	{0x0200, 0x00000000, 0x000000ff},
> +	{0x0204, 0x5e000080, 0xff0000ff},
> +	{0x0208, 0x00000006, 0x000000ff},
> +	{0x0210, 0x00000023, 0x000000ff},
> +	{0x0214, 0x2e003060, 0xff00ffff},
> +	{0x0218, 0x76000000, 0xff000000},
> +	{0x022c, 0x00200002, 0x00ff00ff},
> +	{0x02a0, 0xffee0000, 0xffff0000},
> +	{0x02a4, 0x0000000f, 0x000000ff},
> +	{0x0204, 0x5e000000, 0xff000000},
> +	{0x0208, 0x00000006, 0x000000ff},
> +	{0x0278, 0x00002000, 0x0000ff00},
> +	{0x0280, 0x00280028, 0x00ff00ff},
> +	{0x0284, 0x2d0f0385, 0xffffffff},
> +	{0x0250, 0xd0000000, 0xff000000},
> +	{0x0284, 0x00000085, 0x000000ff},
> +	{0x0294, 0x20000000, 0xff000000},
> +
> +	{0x0400, 0x00000000, 0x000000ff},
> +	{0x0404, 0x5e000080, 0xff0000ff},
> +	{0x0408, 0x00000006, 0x000000ff},
> +	{0x0410, 0x00000023, 0x000000ff},
> +	{0x0414, 0x2e003060, 0xff00ffff},
> +	{0x0418, 0x76000000, 0xff000000},
> +	{0x042c, 0x00200002, 0x00ff00ff},
> +	{0x04a0, 0xffee0000, 0xffff0000},
> +	{0x04a4, 0x0000000f, 0x000000ff},
> +	{0x0404, 0x5e000000, 0xff000000},
> +	{0x0408, 0x00000006, 0x000000ff},
> +	{0x0478, 0x00002000, 0x0000ff00},
> +	{0x0480, 0x00280028, 0x00ff00ff},
> +	{0x0484, 0x2d0f0385, 0xffffffff},
> +	{0x0450, 0xd0000000, 0xff000000},
> +	{0x0494, 0x20000000, 0xff000000},
> +
> +	{0x0604, 0x00000080, 0x000000ff},
> +	{0x0600, 0x00000000, 0x000000ff},
> +	{0x0604, 0x5e000000, 0xff000000},
> +	{0x0608, 0x00000006, 0x000000ff},
> +	{0x0610, 0x00000023, 0x000000ff},
> +	{0x0614, 0x2e003060, 0xff00ffff},
> +	{0x0618, 0x76000000, 0xff000000},
> +	{0x062c, 0x00200002, 0x00ff00ff},
> +	{0x06a0, 0xffee0000, 0xffff0000},
> +	{0x06a4, 0x0000000f, 0x000000ff},
> +	{0x0604, 0x5e000000, 0xff000000},
> +	{0x0608, 0x00000006, 0x000000ff},
> +	{0x0678, 0x00002000, 0x0000ff00},
> +	{0x0680, 0x00280028, 0x00ff00ff},
> +	{0x0684, 0x2d0f0385, 0xffffffff},
> +	{0x0650, 0xd0000000, 0xff000000},
> +	{0x0694, 0x20000000, 0xff000000},
> +
> +	{0x0800, 0x00000000, 0x000000ff},
> +	{0x0804, 0x5e000080, 0xff0000ff},
> +	{0x0808, 0x00000006, 0x000000ff},
> +	{0x0810, 0x00000023, 0x000000ff},
> +	{0x0814, 0x2e003060, 0xff00ffff},
> +	{0x0818, 0x76000000, 0xff000000},
> +	{0x082c, 0x00200002, 0x00ff00ff},
> +	{0x08a0, 0xffee0000, 0xffff0000},
> +	{0x08a4, 0x0000000f, 0x000000ff},
> +	{0x0804, 0x5e000000, 0xff000000},
> +	{0x0808, 0x00000006, 0x000000ff},
> +	{0x0878, 0x00002000, 0x0000ff00},
> +	{0x0880, 0x00280028, 0x00ff00ff},
> +	{0x0884, 0x2d0f0385, 0xffffffff},
> +	{0x0850, 0xd0000000, 0xff000000},
> +	{0x0894, 0x20000000, 0xff000000},
> +
> +	{0x0a00, 0x00000100, 0x0000ff00},
> +	{0x0a08, 0x00e12c08, 0x00ffffff},
> +	{0x0a0c, 0x00000081, 0x000000ff},
> +	{0x0a18, 0x00e80000, 0x00ff0000},
> +	{0x0a30, 0x002f2f00, 0x00ffff00},
> +	{0x0a4c, 0xac820000, 0xffff0000},
> +	{0x0a54, 0xc0000000, 0xff000000},
> +	{0x0a58, 0x00001441, 0x0000ffff},
> +	{0x0a84, 0x00000301, 0x0000ffff},
> +
> +	{0x0a8c, 0x81030000, 0xffff0000},
> +	{0x0a90, 0x00006001, 0x0000ffff},
> +	{0x0a94, 0x01000000, 0xff000000},
> +	{0x0aa0, 0x81000000, 0xff000000},
> +	{0x0abc, 0xff000000, 0xff000000},
> +	{0x0ac0, 0x0000008b, 0x000000ff},
> +
> +	{0x0000, 0x00000003, 0x000000ff},
> +	{0x0a00, 0x0000009f, 0x000000ff},
> +
> +	{0x0a44, 0x5f733d00, 0xffffff00},
> +	{0x0a48, 0x00fdca00, 0x00ffff00},
> +	{0x0a5c, 0x00000000, 0xffff0000},
> +	{0x0a60, 0x00008000, 0xffffffff},
> +	{0x0a64, 0x0c581220, 0xffffffff},
> +	{0x0a68, 0xe13b0602, 0xffffffff},
> +	{0x0a6c, 0xb8074cc1, 0xffffffff},
> +	{0x0a70, 0x3f02e989, 0xffffffff},
> +	{0x0a74, 0x00000001, 0x000000ff},
> +	{0x0b14, 0x00370000, 0x00ff0000},
> +	{0x0b10, 0x37000000, 0xff000000},
> +	{0x0b14, 0x0000005d, 0x000000ff},

Which of these is powering on/off the PHY? Which of these is for clocks? Which
of these is for TX or RX? Which of these is for lane configuration?...

Imagining how would it be if all peripherals are programmed this way in linux..

-Kishon

> +};
> +
> +static int ks_phy_init(struct phy *phy)
> +{
> +	struct serdes_config *p;
> +	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
> +
> +	int i;
> +
> +	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
> +		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
> +		i++, p++) {
> +		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
> +		reg_dump((ks_phy->base + p->reg), p->mask);
> +	}
> +	udelay(2000);
> +
> +	return 0;
> +}
> +
> +static struct phy_ops ks_phy_ops = {
> +	.init		= ks_phy_init,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static int ks_phy_probe(struct platform_device *pdev)
> +{
> +	struct phy_provider *phy_provider;
> +	struct device *dev = &pdev->dev;
> +	struct phy_keystone *ks_phy;
> +	struct phy *phy;
> +	struct resource *res;
> +
> +	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
> +	if (!ks_phy)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
> +	ks_phy->base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ks_phy->base))
> +		return PTR_ERR(ks_phy->base);
> +
> +	ks_phy->dev = dev;
> +	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
> +	if (IS_ERR(phy))
> +		return PTR_ERR(phy);
> +
> +	phy_set_drvdata(phy, ks_phy);
> +	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
> +				of_phy_simple_xlate);
> +
> +	if (IS_ERR(phy_provider))
> +		return PTR_ERR(phy_provider);
> +
> +	dev_info(dev, "keystone phy initialized\n");
> +	return 0;
> +}
> +
> +static const struct of_device_id ks_phy_of_match[] = {
> +	{ .compatible = "ti,keystone-phy" },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ks_phy_of_match);
> +
> +static struct platform_driver ks_phy_driver = {
> +	.probe	= ks_phy_probe,
> +	.driver = {
> +		.of_match_table	= ks_phy_of_match,
> +		.name  = "ti,keystone-phy",
> +		.owner = THIS_MODULE,
> +	}
> +};
> +module_platform_driver(ks_phy_driver);
> +
> +MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
> +MODULE_LICENSE("GPL V2");
> +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
> 

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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-06-02  6:16     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 116+ messages in thread
From: Kishon Vijay Abraham I @ 2014-06-02  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Thursday 15 May 2014 09:31 PM, Murali Karicheri wrote:
> This phy driver is used by keystone PCI driver. The hw vendor that
> provides the phy hw published only registers and their values. So
> this driver uses these hard coded values to initialize the phy.
> 
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---
>  drivers/phy/Kconfig        |    6 ++
>  drivers/phy/Makefile       |    1 +
>  drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 237 insertions(+)
>  create mode 100644 drivers/phy/phy-keystone.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 4906c27..e5f4b5a 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -167,4 +167,10 @@ config PHY_XGENE
>  	help
>  	  This option enables support for APM X-Gene SoC multi-purpose PHY.
>  
> +config PHY_TI_KEYSTONE
> +	bool "TI Keystone PHY support"
> +	depends on ARCH_KEYSTONE
> +	select GENERIC_PHY
> +	help
> +	  This option enables support for TI Keystone PHY (serdes).
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 7728518..bd306a7 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
>  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
>  obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
> +obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
> diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
> new file mode 100644
> index 0000000..ba1b9fa
> --- /dev/null
> +++ b/drivers/phy/phy-keystone.c
> @@ -0,0 +1,230 @@
> +/*
> + * PCIe Keystone platform specific driver code
> + *
> + * Copyright (C) 2013-2014 Texas Instruments, Inc.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri <m-karicheri2@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +
> +#define reg_dump(addr, mask) \
> +		pr_debug("reg %p has value %x\n", (void *)addr, \
> +			(readl(addr) & ~mask))
> +
> +/* mask bits point to bits being modified */
> +#define reg_rmw(addr, value, mask) \
> +		writel(((readl(addr) & (~(mask))) | \
> +			(value & (mask))), (addr))
> +struct serdes_config {
> +	u32 reg;
> +	u32 val;
> +	u32 mask;
> +};
> +
> +struct phy_keystone {
> +	struct device *dev;
> +	void __iomem *base;
> +};
> +
> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> +	{0x0000, 0x00000800, 0x0000ff00},
> +	{0x0060, 0x00041c5c, 0x00ffffff},
> +	{0x0064, 0x0343c700, 0xffffff00},
> +	{0x006c, 0x00000012, 0x000000ff},
> +	{0x0068, 0x00070000, 0x00ff0000},
> +	{0x0078, 0x0000c000, 0x0000ff00},
> +
> +	{0x0200, 0x00000000, 0x000000ff},
> +	{0x0204, 0x5e000080, 0xff0000ff},
> +	{0x0208, 0x00000006, 0x000000ff},
> +	{0x0210, 0x00000023, 0x000000ff},
> +	{0x0214, 0x2e003060, 0xff00ffff},
> +	{0x0218, 0x76000000, 0xff000000},
> +	{0x022c, 0x00200002, 0x00ff00ff},
> +	{0x02a0, 0xffee0000, 0xffff0000},
> +	{0x02a4, 0x0000000f, 0x000000ff},
> +	{0x0204, 0x5e000000, 0xff000000},
> +	{0x0208, 0x00000006, 0x000000ff},
> +	{0x0278, 0x00002000, 0x0000ff00},
> +	{0x0280, 0x00280028, 0x00ff00ff},
> +	{0x0284, 0x2d0f0385, 0xffffffff},
> +	{0x0250, 0xd0000000, 0xff000000},
> +	{0x0284, 0x00000085, 0x000000ff},
> +	{0x0294, 0x20000000, 0xff000000},
> +
> +	{0x0400, 0x00000000, 0x000000ff},
> +	{0x0404, 0x5e000080, 0xff0000ff},
> +	{0x0408, 0x00000006, 0x000000ff},
> +	{0x0410, 0x00000023, 0x000000ff},
> +	{0x0414, 0x2e003060, 0xff00ffff},
> +	{0x0418, 0x76000000, 0xff000000},
> +	{0x042c, 0x00200002, 0x00ff00ff},
> +	{0x04a0, 0xffee0000, 0xffff0000},
> +	{0x04a4, 0x0000000f, 0x000000ff},
> +	{0x0404, 0x5e000000, 0xff000000},
> +	{0x0408, 0x00000006, 0x000000ff},
> +	{0x0478, 0x00002000, 0x0000ff00},
> +	{0x0480, 0x00280028, 0x00ff00ff},
> +	{0x0484, 0x2d0f0385, 0xffffffff},
> +	{0x0450, 0xd0000000, 0xff000000},
> +	{0x0494, 0x20000000, 0xff000000},
> +
> +	{0x0604, 0x00000080, 0x000000ff},
> +	{0x0600, 0x00000000, 0x000000ff},
> +	{0x0604, 0x5e000000, 0xff000000},
> +	{0x0608, 0x00000006, 0x000000ff},
> +	{0x0610, 0x00000023, 0x000000ff},
> +	{0x0614, 0x2e003060, 0xff00ffff},
> +	{0x0618, 0x76000000, 0xff000000},
> +	{0x062c, 0x00200002, 0x00ff00ff},
> +	{0x06a0, 0xffee0000, 0xffff0000},
> +	{0x06a4, 0x0000000f, 0x000000ff},
> +	{0x0604, 0x5e000000, 0xff000000},
> +	{0x0608, 0x00000006, 0x000000ff},
> +	{0x0678, 0x00002000, 0x0000ff00},
> +	{0x0680, 0x00280028, 0x00ff00ff},
> +	{0x0684, 0x2d0f0385, 0xffffffff},
> +	{0x0650, 0xd0000000, 0xff000000},
> +	{0x0694, 0x20000000, 0xff000000},
> +
> +	{0x0800, 0x00000000, 0x000000ff},
> +	{0x0804, 0x5e000080, 0xff0000ff},
> +	{0x0808, 0x00000006, 0x000000ff},
> +	{0x0810, 0x00000023, 0x000000ff},
> +	{0x0814, 0x2e003060, 0xff00ffff},
> +	{0x0818, 0x76000000, 0xff000000},
> +	{0x082c, 0x00200002, 0x00ff00ff},
> +	{0x08a0, 0xffee0000, 0xffff0000},
> +	{0x08a4, 0x0000000f, 0x000000ff},
> +	{0x0804, 0x5e000000, 0xff000000},
> +	{0x0808, 0x00000006, 0x000000ff},
> +	{0x0878, 0x00002000, 0x0000ff00},
> +	{0x0880, 0x00280028, 0x00ff00ff},
> +	{0x0884, 0x2d0f0385, 0xffffffff},
> +	{0x0850, 0xd0000000, 0xff000000},
> +	{0x0894, 0x20000000, 0xff000000},
> +
> +	{0x0a00, 0x00000100, 0x0000ff00},
> +	{0x0a08, 0x00e12c08, 0x00ffffff},
> +	{0x0a0c, 0x00000081, 0x000000ff},
> +	{0x0a18, 0x00e80000, 0x00ff0000},
> +	{0x0a30, 0x002f2f00, 0x00ffff00},
> +	{0x0a4c, 0xac820000, 0xffff0000},
> +	{0x0a54, 0xc0000000, 0xff000000},
> +	{0x0a58, 0x00001441, 0x0000ffff},
> +	{0x0a84, 0x00000301, 0x0000ffff},
> +
> +	{0x0a8c, 0x81030000, 0xffff0000},
> +	{0x0a90, 0x00006001, 0x0000ffff},
> +	{0x0a94, 0x01000000, 0xff000000},
> +	{0x0aa0, 0x81000000, 0xff000000},
> +	{0x0abc, 0xff000000, 0xff000000},
> +	{0x0ac0, 0x0000008b, 0x000000ff},
> +
> +	{0x0000, 0x00000003, 0x000000ff},
> +	{0x0a00, 0x0000009f, 0x000000ff},
> +
> +	{0x0a44, 0x5f733d00, 0xffffff00},
> +	{0x0a48, 0x00fdca00, 0x00ffff00},
> +	{0x0a5c, 0x00000000, 0xffff0000},
> +	{0x0a60, 0x00008000, 0xffffffff},
> +	{0x0a64, 0x0c581220, 0xffffffff},
> +	{0x0a68, 0xe13b0602, 0xffffffff},
> +	{0x0a6c, 0xb8074cc1, 0xffffffff},
> +	{0x0a70, 0x3f02e989, 0xffffffff},
> +	{0x0a74, 0x00000001, 0x000000ff},
> +	{0x0b14, 0x00370000, 0x00ff0000},
> +	{0x0b10, 0x37000000, 0xff000000},
> +	{0x0b14, 0x0000005d, 0x000000ff},

Which of these is powering on/off the PHY? Which of these is for clocks? Which
of these is for TX or RX? Which of these is for lane configuration?...

Imagining how would it be if all peripherals are programmed this way in linux..

-Kishon

> +};
> +
> +static int ks_phy_init(struct phy *phy)
> +{
> +	struct serdes_config *p;
> +	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
> +
> +	int i;
> +
> +	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
> +		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
> +		i++, p++) {
> +		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
> +		reg_dump((ks_phy->base + p->reg), p->mask);
> +	}
> +	udelay(2000);
> +
> +	return 0;
> +}
> +
> +static struct phy_ops ks_phy_ops = {
> +	.init		= ks_phy_init,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static int ks_phy_probe(struct platform_device *pdev)
> +{
> +	struct phy_provider *phy_provider;
> +	struct device *dev = &pdev->dev;
> +	struct phy_keystone *ks_phy;
> +	struct phy *phy;
> +	struct resource *res;
> +
> +	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
> +	if (!ks_phy)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
> +	ks_phy->base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ks_phy->base))
> +		return PTR_ERR(ks_phy->base);
> +
> +	ks_phy->dev = dev;
> +	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
> +	if (IS_ERR(phy))
> +		return PTR_ERR(phy);
> +
> +	phy_set_drvdata(phy, ks_phy);
> +	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
> +				of_phy_simple_xlate);
> +
> +	if (IS_ERR(phy_provider))
> +		return PTR_ERR(phy_provider);
> +
> +	dev_info(dev, "keystone phy initialized\n");
> +	return 0;
> +}
> +
> +static const struct of_device_id ks_phy_of_match[] = {
> +	{ .compatible = "ti,keystone-phy" },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ks_phy_of_match);
> +
> +static struct platform_driver ks_phy_driver = {
> +	.probe	= ks_phy_probe,
> +	.driver = {
> +		.of_match_table	= ks_phy_of_match,
> +		.name  = "ti,keystone-phy",
> +		.owner = THIS_MODULE,
> +	}
> +};
> +module_platform_driver(ks_phy_driver);
> +
> +MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
> +MODULE_LICENSE("GPL V2");
> +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
> 

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-06-02  6:16     ` Kishon Vijay Abraham I
@ 2014-06-02  6:45       ` Jingoo Han
  -1 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-06-02  6:45 UTC (permalink / raw)
  To: 'Murali Karicheri', 'Kishon Vijay Abraham I'
  Cc: 'Grant Likely', 'Rob Herring',
	'Mohit Kumar', 'Bjorn Helgaas',
	linux-kernel, linux-pci, linux-arm-kernel, 'Jingoo Han'

On Monday, June 02, 2014 3:17 PM, Kishon Vijay Abraham I wrote:
> On Thursday 15 May 2014 09:31 PM, Murali Karicheri wrote:
> > This phy driver is used by keystone PCI driver. The hw vendor that
> > provides the phy hw published only registers and their values. So
> > this driver uses these hard coded values to initialize the phy.
> >
> > CC: Grant Likely <grant.likely@linaro.org>
> > CC: Rob Herring <robh+dt@kernel.org>
> > CC: Mohit Kumar <mohit.kumar@st.com>
> > CC: Jingoo Han <jg1.han@samsung.com>
> > CC: Bjorn Helgaas <bhelgaas@google.com>
> >
> > Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> > ---
> >  drivers/phy/Kconfig        |    6 ++
> >  drivers/phy/Makefile       |    1 +
> >  drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 237 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone.c
> >
> > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> > index 4906c27..e5f4b5a 100644
> > --- a/drivers/phy/Kconfig
> > +++ b/drivers/phy/Kconfig
> > @@ -167,4 +167,10 @@ config PHY_XGENE
> >  	help
> >  	  This option enables support for APM X-Gene SoC multi-purpose PHY.
> >
> > +config PHY_TI_KEYSTONE
> > +	bool "TI Keystone PHY support"
> > +	depends on ARCH_KEYSTONE
> > +	select GENERIC_PHY
> > +	help
> > +	  This option enables support for TI Keystone PHY (serdes).
> >  endmenu
> > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> > index 7728518..bd306a7 100644
> > --- a/drivers/phy/Makefile
> > +++ b/drivers/phy/Makefile
> > @@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> >  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
> >  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
> >  obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
> > +obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
> > diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
> > new file mode 100644
> > index 0000000..ba1b9fa
> > --- /dev/null
> > +++ b/drivers/phy/phy-keystone.c
> > @@ -0,0 +1,230 @@
> > +/*
> > + * PCIe Keystone platform specific driver code
> > + *
> > + * Copyright (C) 2013-2014 Texas Instruments, Inc.
> > + *		http://www.ti.com
> > + *
> > + * Author: Murali Karicheri <m-karicheri2@ti.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +
> > +#define reg_dump(addr, mask) \
> > +		pr_debug("reg %p has value %x\n", (void *)addr, \
> > +			(readl(addr) & ~mask))
> > +
> > +/* mask bits point to bits being modified */
> > +#define reg_rmw(addr, value, mask) \
> > +		writel(((readl(addr) & (~(mask))) | \
> > +			(value & (mask))), (addr))
> > +struct serdes_config {
> > +	u32 reg;
> > +	u32 val;
> > +	u32 mask;
> > +};
> > +
> > +struct phy_keystone {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +};
> > +
> > +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> > +	{0x0000, 0x00000800, 0x0000ff00},
> > +	{0x0060, 0x00041c5c, 0x00ffffff},
> > +	{0x0064, 0x0343c700, 0xffffff00},
> > +	{0x006c, 0x00000012, 0x000000ff},
> > +	{0x0068, 0x00070000, 0x00ff0000},
> > +	{0x0078, 0x0000c000, 0x0000ff00},
> > +
> > +	{0x0200, 0x00000000, 0x000000ff},
> > +	{0x0204, 0x5e000080, 0xff0000ff},
> > +	{0x0208, 0x00000006, 0x000000ff},
> > +	{0x0210, 0x00000023, 0x000000ff},
> > +	{0x0214, 0x2e003060, 0xff00ffff},
> > +	{0x0218, 0x76000000, 0xff000000},
> > +	{0x022c, 0x00200002, 0x00ff00ff},
> > +	{0x02a0, 0xffee0000, 0xffff0000},
> > +	{0x02a4, 0x0000000f, 0x000000ff},
> > +	{0x0204, 0x5e000000, 0xff000000},
> > +	{0x0208, 0x00000006, 0x000000ff},
> > +	{0x0278, 0x00002000, 0x0000ff00},
> > +	{0x0280, 0x00280028, 0x00ff00ff},
> > +	{0x0284, 0x2d0f0385, 0xffffffff},
> > +	{0x0250, 0xd0000000, 0xff000000},
> > +	{0x0284, 0x00000085, 0x000000ff},
> > +	{0x0294, 0x20000000, 0xff000000},
> > +
> > +	{0x0400, 0x00000000, 0x000000ff},
> > +	{0x0404, 0x5e000080, 0xff0000ff},
> > +	{0x0408, 0x00000006, 0x000000ff},
> > +	{0x0410, 0x00000023, 0x000000ff},
> > +	{0x0414, 0x2e003060, 0xff00ffff},
> > +	{0x0418, 0x76000000, 0xff000000},
> > +	{0x042c, 0x00200002, 0x00ff00ff},
> > +	{0x04a0, 0xffee0000, 0xffff0000},
> > +	{0x04a4, 0x0000000f, 0x000000ff},
> > +	{0x0404, 0x5e000000, 0xff000000},
> > +	{0x0408, 0x00000006, 0x000000ff},
> > +	{0x0478, 0x00002000, 0x0000ff00},
> > +	{0x0480, 0x00280028, 0x00ff00ff},
> > +	{0x0484, 0x2d0f0385, 0xffffffff},
> > +	{0x0450, 0xd0000000, 0xff000000},
> > +	{0x0494, 0x20000000, 0xff000000},
> > +
> > +	{0x0604, 0x00000080, 0x000000ff},
> > +	{0x0600, 0x00000000, 0x000000ff},
> > +	{0x0604, 0x5e000000, 0xff000000},
> > +	{0x0608, 0x00000006, 0x000000ff},
> > +	{0x0610, 0x00000023, 0x000000ff},
> > +	{0x0614, 0x2e003060, 0xff00ffff},
> > +	{0x0618, 0x76000000, 0xff000000},
> > +	{0x062c, 0x00200002, 0x00ff00ff},
> > +	{0x06a0, 0xffee0000, 0xffff0000},
> > +	{0x06a4, 0x0000000f, 0x000000ff},
> > +	{0x0604, 0x5e000000, 0xff000000},
> > +	{0x0608, 0x00000006, 0x000000ff},
> > +	{0x0678, 0x00002000, 0x0000ff00},
> > +	{0x0680, 0x00280028, 0x00ff00ff},
> > +	{0x0684, 0x2d0f0385, 0xffffffff},
> > +	{0x0650, 0xd0000000, 0xff000000},
> > +	{0x0694, 0x20000000, 0xff000000},
> > +
> > +	{0x0800, 0x00000000, 0x000000ff},
> > +	{0x0804, 0x5e000080, 0xff0000ff},
> > +	{0x0808, 0x00000006, 0x000000ff},
> > +	{0x0810, 0x00000023, 0x000000ff},
> > +	{0x0814, 0x2e003060, 0xff00ffff},
> > +	{0x0818, 0x76000000, 0xff000000},
> > +	{0x082c, 0x00200002, 0x00ff00ff},
> > +	{0x08a0, 0xffee0000, 0xffff0000},
> > +	{0x08a4, 0x0000000f, 0x000000ff},
> > +	{0x0804, 0x5e000000, 0xff000000},
> > +	{0x0808, 0x00000006, 0x000000ff},
> > +	{0x0878, 0x00002000, 0x0000ff00},
> > +	{0x0880, 0x00280028, 0x00ff00ff},
> > +	{0x0884, 0x2d0f0385, 0xffffffff},
> > +	{0x0850, 0xd0000000, 0xff000000},
> > +	{0x0894, 0x20000000, 0xff000000},
> > +
> > +	{0x0a00, 0x00000100, 0x0000ff00},
> > +	{0x0a08, 0x00e12c08, 0x00ffffff},
> > +	{0x0a0c, 0x00000081, 0x000000ff},
> > +	{0x0a18, 0x00e80000, 0x00ff0000},
> > +	{0x0a30, 0x002f2f00, 0x00ffff00},
> > +	{0x0a4c, 0xac820000, 0xffff0000},
> > +	{0x0a54, 0xc0000000, 0xff000000},
> > +	{0x0a58, 0x00001441, 0x0000ffff},
> > +	{0x0a84, 0x00000301, 0x0000ffff},
> > +
> > +	{0x0a8c, 0x81030000, 0xffff0000},
> > +	{0x0a90, 0x00006001, 0x0000ffff},
> > +	{0x0a94, 0x01000000, 0xff000000},
> > +	{0x0aa0, 0x81000000, 0xff000000},
> > +	{0x0abc, 0xff000000, 0xff000000},
> > +	{0x0ac0, 0x0000008b, 0x000000ff},
> > +
> > +	{0x0000, 0x00000003, 0x000000ff},
> > +	{0x0a00, 0x0000009f, 0x000000ff},
> > +
> > +	{0x0a44, 0x5f733d00, 0xffffff00},
> > +	{0x0a48, 0x00fdca00, 0x00ffff00},
> > +	{0x0a5c, 0x00000000, 0xffff0000},
> > +	{0x0a60, 0x00008000, 0xffffffff},
> > +	{0x0a64, 0x0c581220, 0xffffffff},
> > +	{0x0a68, 0xe13b0602, 0xffffffff},
> > +	{0x0a6c, 0xb8074cc1, 0xffffffff},
> > +	{0x0a70, 0x3f02e989, 0xffffffff},
> > +	{0x0a74, 0x00000001, 0x000000ff},
> > +	{0x0b14, 0x00370000, 0x00ff0000},
> > +	{0x0b10, 0x37000000, 0xff000000},
> > +	{0x0b14, 0x0000005d, 0x000000ff},
> 
> Which of these is powering on/off the PHY? Which of these is for clocks? Which
> of these is for TX or RX? Which of these is for lane configuration?...
> 
> Imagining how would it be if all peripherals are programmed this way in linux..

+111

I agree with Kishon's comment. The mainline linux kernel is
the Open source that can be shared with a lot of people. So,
readability and manageability are important.

Please split this HUGE chunk 'ks_100mhz_pcie_5gbps_serdes[]'
into several chunks, according to what they do.

For example,
static struct serdes_config init_phy_clocks[]
static struct serdes_config power_on_phy[]
static struct serdes_config reset_phy_core[]
....

Then, if possible, covert hardcoded 'reg' values into macro
names.

For example,
#define 0x0000	SERDES_PLL_CONTROL
#define 0x0004	SERDES_PLL_STATUS
....

Best regards,
Jingoo Han

> 
> -Kishon
> 
> > +};
> > +
> > +static int ks_phy_init(struct phy *phy)
> > +{
> > +	struct serdes_config *p;
> > +	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
> > +
> > +	int i;
> > +
> > +	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
> > +		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
> > +		i++, p++) {
> > +		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
> > +		reg_dump((ks_phy->base + p->reg), p->mask);
> > +	}
> > +	udelay(2000);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct phy_ops ks_phy_ops = {
> > +	.init		= ks_phy_init,
> > +	.owner		= THIS_MODULE,
> > +};
> > +
> > +static int ks_phy_probe(struct platform_device *pdev)
> > +{
> > +	struct phy_provider *phy_provider;
> > +	struct device *dev = &pdev->dev;
> > +	struct phy_keystone *ks_phy;
> > +	struct phy *phy;
> > +	struct resource *res;
> > +
> > +	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
> > +	if (!ks_phy)
> > +		return -ENOMEM;
> > +
> > +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
> > +	ks_phy->base = devm_ioremap_resource(dev, res);
> > +	if (IS_ERR(ks_phy->base))
> > +		return PTR_ERR(ks_phy->base);
> > +
> > +	ks_phy->dev = dev;
> > +	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
> > +	if (IS_ERR(phy))
> > +		return PTR_ERR(phy);
> > +
> > +	phy_set_drvdata(phy, ks_phy);
> > +	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
> > +				of_phy_simple_xlate);
> > +
> > +	if (IS_ERR(phy_provider))
> > +		return PTR_ERR(phy_provider);
> > +
> > +	dev_info(dev, "keystone phy initialized\n");
> > +	return 0;
> > +}
> > +
> > +static const struct of_device_id ks_phy_of_match[] = {
> > +	{ .compatible = "ti,keystone-phy" },
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(of, ks_phy_of_match);
> > +
> > +static struct platform_driver ks_phy_driver = {
> > +	.probe	= ks_phy_probe,
> > +	.driver = {
> > +		.of_match_table	= ks_phy_of_match,
> > +		.name  = "ti,keystone-phy",
> > +		.owner = THIS_MODULE,
> > +	}
> > +};
> > +module_platform_driver(ks_phy_driver);
> > +
> > +MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
> > +MODULE_LICENSE("GPL V2");
> > +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
> >


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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-06-02  6:45       ` Jingoo Han
  0 siblings, 0 replies; 116+ messages in thread
From: Jingoo Han @ 2014-06-02  6:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday, June 02, 2014 3:17 PM, Kishon Vijay Abraham I wrote:
> On Thursday 15 May 2014 09:31 PM, Murali Karicheri wrote:
> > This phy driver is used by keystone PCI driver. The hw vendor that
> > provides the phy hw published only registers and their values. So
> > this driver uses these hard coded values to initialize the phy.
> >
> > CC: Grant Likely <grant.likely@linaro.org>
> > CC: Rob Herring <robh+dt@kernel.org>
> > CC: Mohit Kumar <mohit.kumar@st.com>
> > CC: Jingoo Han <jg1.han@samsung.com>
> > CC: Bjorn Helgaas <bhelgaas@google.com>
> >
> > Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> > ---
> >  drivers/phy/Kconfig        |    6 ++
> >  drivers/phy/Makefile       |    1 +
> >  drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 237 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone.c
> >
> > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> > index 4906c27..e5f4b5a 100644
> > --- a/drivers/phy/Kconfig
> > +++ b/drivers/phy/Kconfig
> > @@ -167,4 +167,10 @@ config PHY_XGENE
> >  	help
> >  	  This option enables support for APM X-Gene SoC multi-purpose PHY.
> >
> > +config PHY_TI_KEYSTONE
> > +	bool "TI Keystone PHY support"
> > +	depends on ARCH_KEYSTONE
> > +	select GENERIC_PHY
> > +	help
> > +	  This option enables support for TI Keystone PHY (serdes).
> >  endmenu
> > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> > index 7728518..bd306a7 100644
> > --- a/drivers/phy/Makefile
> > +++ b/drivers/phy/Makefile
> > @@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> >  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
> >  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
> >  obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
> > +obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
> > diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
> > new file mode 100644
> > index 0000000..ba1b9fa
> > --- /dev/null
> > +++ b/drivers/phy/phy-keystone.c
> > @@ -0,0 +1,230 @@
> > +/*
> > + * PCIe Keystone platform specific driver code
> > + *
> > + * Copyright (C) 2013-2014 Texas Instruments, Inc.
> > + *		http://www.ti.com
> > + *
> > + * Author: Murali Karicheri <m-karicheri2@ti.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +
> > +#define reg_dump(addr, mask) \
> > +		pr_debug("reg %p has value %x\n", (void *)addr, \
> > +			(readl(addr) & ~mask))
> > +
> > +/* mask bits point to bits being modified */
> > +#define reg_rmw(addr, value, mask) \
> > +		writel(((readl(addr) & (~(mask))) | \
> > +			(value & (mask))), (addr))
> > +struct serdes_config {
> > +	u32 reg;
> > +	u32 val;
> > +	u32 mask;
> > +};
> > +
> > +struct phy_keystone {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +};
> > +
> > +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
> > +	{0x0000, 0x00000800, 0x0000ff00},
> > +	{0x0060, 0x00041c5c, 0x00ffffff},
> > +	{0x0064, 0x0343c700, 0xffffff00},
> > +	{0x006c, 0x00000012, 0x000000ff},
> > +	{0x0068, 0x00070000, 0x00ff0000},
> > +	{0x0078, 0x0000c000, 0x0000ff00},
> > +
> > +	{0x0200, 0x00000000, 0x000000ff},
> > +	{0x0204, 0x5e000080, 0xff0000ff},
> > +	{0x0208, 0x00000006, 0x000000ff},
> > +	{0x0210, 0x00000023, 0x000000ff},
> > +	{0x0214, 0x2e003060, 0xff00ffff},
> > +	{0x0218, 0x76000000, 0xff000000},
> > +	{0x022c, 0x00200002, 0x00ff00ff},
> > +	{0x02a0, 0xffee0000, 0xffff0000},
> > +	{0x02a4, 0x0000000f, 0x000000ff},
> > +	{0x0204, 0x5e000000, 0xff000000},
> > +	{0x0208, 0x00000006, 0x000000ff},
> > +	{0x0278, 0x00002000, 0x0000ff00},
> > +	{0x0280, 0x00280028, 0x00ff00ff},
> > +	{0x0284, 0x2d0f0385, 0xffffffff},
> > +	{0x0250, 0xd0000000, 0xff000000},
> > +	{0x0284, 0x00000085, 0x000000ff},
> > +	{0x0294, 0x20000000, 0xff000000},
> > +
> > +	{0x0400, 0x00000000, 0x000000ff},
> > +	{0x0404, 0x5e000080, 0xff0000ff},
> > +	{0x0408, 0x00000006, 0x000000ff},
> > +	{0x0410, 0x00000023, 0x000000ff},
> > +	{0x0414, 0x2e003060, 0xff00ffff},
> > +	{0x0418, 0x76000000, 0xff000000},
> > +	{0x042c, 0x00200002, 0x00ff00ff},
> > +	{0x04a0, 0xffee0000, 0xffff0000},
> > +	{0x04a4, 0x0000000f, 0x000000ff},
> > +	{0x0404, 0x5e000000, 0xff000000},
> > +	{0x0408, 0x00000006, 0x000000ff},
> > +	{0x0478, 0x00002000, 0x0000ff00},
> > +	{0x0480, 0x00280028, 0x00ff00ff},
> > +	{0x0484, 0x2d0f0385, 0xffffffff},
> > +	{0x0450, 0xd0000000, 0xff000000},
> > +	{0x0494, 0x20000000, 0xff000000},
> > +
> > +	{0x0604, 0x00000080, 0x000000ff},
> > +	{0x0600, 0x00000000, 0x000000ff},
> > +	{0x0604, 0x5e000000, 0xff000000},
> > +	{0x0608, 0x00000006, 0x000000ff},
> > +	{0x0610, 0x00000023, 0x000000ff},
> > +	{0x0614, 0x2e003060, 0xff00ffff},
> > +	{0x0618, 0x76000000, 0xff000000},
> > +	{0x062c, 0x00200002, 0x00ff00ff},
> > +	{0x06a0, 0xffee0000, 0xffff0000},
> > +	{0x06a4, 0x0000000f, 0x000000ff},
> > +	{0x0604, 0x5e000000, 0xff000000},
> > +	{0x0608, 0x00000006, 0x000000ff},
> > +	{0x0678, 0x00002000, 0x0000ff00},
> > +	{0x0680, 0x00280028, 0x00ff00ff},
> > +	{0x0684, 0x2d0f0385, 0xffffffff},
> > +	{0x0650, 0xd0000000, 0xff000000},
> > +	{0x0694, 0x20000000, 0xff000000},
> > +
> > +	{0x0800, 0x00000000, 0x000000ff},
> > +	{0x0804, 0x5e000080, 0xff0000ff},
> > +	{0x0808, 0x00000006, 0x000000ff},
> > +	{0x0810, 0x00000023, 0x000000ff},
> > +	{0x0814, 0x2e003060, 0xff00ffff},
> > +	{0x0818, 0x76000000, 0xff000000},
> > +	{0x082c, 0x00200002, 0x00ff00ff},
> > +	{0x08a0, 0xffee0000, 0xffff0000},
> > +	{0x08a4, 0x0000000f, 0x000000ff},
> > +	{0x0804, 0x5e000000, 0xff000000},
> > +	{0x0808, 0x00000006, 0x000000ff},
> > +	{0x0878, 0x00002000, 0x0000ff00},
> > +	{0x0880, 0x00280028, 0x00ff00ff},
> > +	{0x0884, 0x2d0f0385, 0xffffffff},
> > +	{0x0850, 0xd0000000, 0xff000000},
> > +	{0x0894, 0x20000000, 0xff000000},
> > +
> > +	{0x0a00, 0x00000100, 0x0000ff00},
> > +	{0x0a08, 0x00e12c08, 0x00ffffff},
> > +	{0x0a0c, 0x00000081, 0x000000ff},
> > +	{0x0a18, 0x00e80000, 0x00ff0000},
> > +	{0x0a30, 0x002f2f00, 0x00ffff00},
> > +	{0x0a4c, 0xac820000, 0xffff0000},
> > +	{0x0a54, 0xc0000000, 0xff000000},
> > +	{0x0a58, 0x00001441, 0x0000ffff},
> > +	{0x0a84, 0x00000301, 0x0000ffff},
> > +
> > +	{0x0a8c, 0x81030000, 0xffff0000},
> > +	{0x0a90, 0x00006001, 0x0000ffff},
> > +	{0x0a94, 0x01000000, 0xff000000},
> > +	{0x0aa0, 0x81000000, 0xff000000},
> > +	{0x0abc, 0xff000000, 0xff000000},
> > +	{0x0ac0, 0x0000008b, 0x000000ff},
> > +
> > +	{0x0000, 0x00000003, 0x000000ff},
> > +	{0x0a00, 0x0000009f, 0x000000ff},
> > +
> > +	{0x0a44, 0x5f733d00, 0xffffff00},
> > +	{0x0a48, 0x00fdca00, 0x00ffff00},
> > +	{0x0a5c, 0x00000000, 0xffff0000},
> > +	{0x0a60, 0x00008000, 0xffffffff},
> > +	{0x0a64, 0x0c581220, 0xffffffff},
> > +	{0x0a68, 0xe13b0602, 0xffffffff},
> > +	{0x0a6c, 0xb8074cc1, 0xffffffff},
> > +	{0x0a70, 0x3f02e989, 0xffffffff},
> > +	{0x0a74, 0x00000001, 0x000000ff},
> > +	{0x0b14, 0x00370000, 0x00ff0000},
> > +	{0x0b10, 0x37000000, 0xff000000},
> > +	{0x0b14, 0x0000005d, 0x000000ff},
> 
> Which of these is powering on/off the PHY? Which of these is for clocks? Which
> of these is for TX or RX? Which of these is for lane configuration?...
> 
> Imagining how would it be if all peripherals are programmed this way in linux..

+111

I agree with Kishon's comment. The mainline linux kernel is
the Open source that can be shared with a lot of people. So,
readability and manageability are important.

Please split this HUGE chunk 'ks_100mhz_pcie_5gbps_serdes[]'
into several chunks, according to what they do.

For example,
static struct serdes_config init_phy_clocks[]
static struct serdes_config power_on_phy[]
static struct serdes_config reset_phy_core[]
....

Then, if possible, covert hardcoded 'reg' values into macro
names.

For example,
#define 0x0000	SERDES_PLL_CONTROL
#define 0x0004	SERDES_PLL_STATUS
....

Best regards,
Jingoo Han

> 
> -Kishon
> 
> > +};
> > +
> > +static int ks_phy_init(struct phy *phy)
> > +{
> > +	struct serdes_config *p;
> > +	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
> > +
> > +	int i;
> > +
> > +	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
> > +		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
> > +		i++, p++) {
> > +		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
> > +		reg_dump((ks_phy->base + p->reg), p->mask);
> > +	}
> > +	udelay(2000);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct phy_ops ks_phy_ops = {
> > +	.init		= ks_phy_init,
> > +	.owner		= THIS_MODULE,
> > +};
> > +
> > +static int ks_phy_probe(struct platform_device *pdev)
> > +{
> > +	struct phy_provider *phy_provider;
> > +	struct device *dev = &pdev->dev;
> > +	struct phy_keystone *ks_phy;
> > +	struct phy *phy;
> > +	struct resource *res;
> > +
> > +	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
> > +	if (!ks_phy)
> > +		return -ENOMEM;
> > +
> > +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
> > +	ks_phy->base = devm_ioremap_resource(dev, res);
> > +	if (IS_ERR(ks_phy->base))
> > +		return PTR_ERR(ks_phy->base);
> > +
> > +	ks_phy->dev = dev;
> > +	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
> > +	if (IS_ERR(phy))
> > +		return PTR_ERR(phy);
> > +
> > +	phy_set_drvdata(phy, ks_phy);
> > +	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
> > +				of_phy_simple_xlate);
> > +
> > +	if (IS_ERR(phy_provider))
> > +		return PTR_ERR(phy_provider);
> > +
> > +	dev_info(dev, "keystone phy initialized\n");
> > +	return 0;
> > +}
> > +
> > +static const struct of_device_id ks_phy_of_match[] = {
> > +	{ .compatible = "ti,keystone-phy" },
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(of, ks_phy_of_match);
> > +
> > +static struct platform_driver ks_phy_driver = {
> > +	.probe	= ks_phy_probe,
> > +	.driver = {
> > +		.of_match_table	= ks_phy_of_match,
> > +		.name  = "ti,keystone-phy",
> > +		.owner = THIS_MODULE,
> > +	}
> > +};
> > +module_platform_driver(ks_phy_driver);
> > +
> > +MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
> > +MODULE_LICENSE("GPL V2");
> > +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
> >

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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
  2014-06-02  6:16     ` Kishon Vijay Abraham I
  (?)
@ 2014-06-02 14:28       ` Murali Karicheri
  -1 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-06-02 14:28 UTC (permalink / raw)
  To: ABRAHAM, KISHON VIJAY
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas

On 6/2/2014 2:16 AM, ABRAHAM, KISHON VIJAY wrote:
> Hi,
>
> On Thursday 15 May 2014 09:31 PM, Murali Karicheri wrote:
>> This phy driver is used by keystone PCI driver. The hw vendor that
>> provides the phy hw published only registers and their values. So
>> this driver uses these hard coded values to initialize the phy.
>>
>> CC: Grant Likely <grant.likely@linaro.org>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>   drivers/phy/Kconfig        |    6 ++
>>   drivers/phy/Makefile       |    1 +
>>   drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 237 insertions(+)
>>   create mode 100644 drivers/phy/phy-keystone.c
>>
>> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
>> index 4906c27..e5f4b5a 100644
>> --- a/drivers/phy/Kconfig
>> +++ b/drivers/phy/Kconfig
>> @@ -167,4 +167,10 @@ config PHY_XGENE
>>   	help
>>   	  This option enables support for APM X-Gene SoC multi-purpose PHY.
>>   
>> +config PHY_TI_KEYSTONE
>> +	bool "TI Keystone PHY support"
>> +	depends on ARCH_KEYSTONE
>> +	select GENERIC_PHY
>> +	help
>> +	  This option enables support for TI Keystone PHY (serdes).
>>   endmenu
>> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
>> index 7728518..bd306a7 100644
>> --- a/drivers/phy/Makefile
>> +++ b/drivers/phy/Makefile
>> @@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>>   phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
>>   phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
>>   obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>> +obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
>> diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
>> new file mode 100644
>> index 0000000..ba1b9fa
>> --- /dev/null
>> +++ b/drivers/phy/phy-keystone.c
>> @@ -0,0 +1,230 @@
>> +/*
>> + * PCIe Keystone platform specific driver code
>> + *
>> + * Copyright (C) 2013-2014 Texas Instruments, Inc.
>> + *		http://www.ti.com
>> + *
>> + * Author: Murali Karicheri <m-karicheri2@ti.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/platform_device.h>
>> +
>> +#define reg_dump(addr, mask) \
>> +		pr_debug("reg %p has value %x\n", (void *)addr, \
>> +			(readl(addr) & ~mask))
>> +
>> +/* mask bits point to bits being modified */
>> +#define reg_rmw(addr, value, mask) \
>> +		writel(((readl(addr) & (~(mask))) | \
>> +			(value & (mask))), (addr))
>> +struct serdes_config {
>> +	u32 reg;
>> +	u32 val;
>> +	u32 mask;
>> +};
>> +
>> +struct phy_keystone {
>> +	struct device *dev;
>> +	void __iomem *base;
>> +};
>> +
>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>> +	{0x0000, 0x00000800, 0x0000ff00},
>> +	{0x0060, 0x00041c5c, 0x00ffffff},
>> +	{0x0064, 0x0343c700, 0xffffff00},
>> +	{0x006c, 0x00000012, 0x000000ff},
>> +	{0x0068, 0x00070000, 0x00ff0000},
>> +	{0x0078, 0x0000c000, 0x0000ff00},
>> +
>> +	{0x0200, 0x00000000, 0x000000ff},
>> +	{0x0204, 0x5e000080, 0xff0000ff},
>> +	{0x0208, 0x00000006, 0x000000ff},
>> +	{0x0210, 0x00000023, 0x000000ff},
>> +	{0x0214, 0x2e003060, 0xff00ffff},
>> +	{0x0218, 0x76000000, 0xff000000},
>> +	{0x022c, 0x00200002, 0x00ff00ff},
>> +	{0x02a0, 0xffee0000, 0xffff0000},
>> +	{0x02a4, 0x0000000f, 0x000000ff},
>> +	{0x0204, 0x5e000000, 0xff000000},
>> +	{0x0208, 0x00000006, 0x000000ff},
>> +	{0x0278, 0x00002000, 0x0000ff00},
>> +	{0x0280, 0x00280028, 0x00ff00ff},
>> +	{0x0284, 0x2d0f0385, 0xffffffff},
>> +	{0x0250, 0xd0000000, 0xff000000},
>> +	{0x0284, 0x00000085, 0x000000ff},
>> +	{0x0294, 0x20000000, 0xff000000},
>> +
>> +	{0x0400, 0x00000000, 0x000000ff},
>> +	{0x0404, 0x5e000080, 0xff0000ff},
>> +	{0x0408, 0x00000006, 0x000000ff},
>> +	{0x0410, 0x00000023, 0x000000ff},
>> +	{0x0414, 0x2e003060, 0xff00ffff},
>> +	{0x0418, 0x76000000, 0xff000000},
>> +	{0x042c, 0x00200002, 0x00ff00ff},
>> +	{0x04a0, 0xffee0000, 0xffff0000},
>> +	{0x04a4, 0x0000000f, 0x000000ff},
>> +	{0x0404, 0x5e000000, 0xff000000},
>> +	{0x0408, 0x00000006, 0x000000ff},
>> +	{0x0478, 0x00002000, 0x0000ff00},
>> +	{0x0480, 0x00280028, 0x00ff00ff},
>> +	{0x0484, 0x2d0f0385, 0xffffffff},
>> +	{0x0450, 0xd0000000, 0xff000000},
>> +	{0x0494, 0x20000000, 0xff000000},
>> +
>> +	{0x0604, 0x00000080, 0x000000ff},
>> +	{0x0600, 0x00000000, 0x000000ff},
>> +	{0x0604, 0x5e000000, 0xff000000},
>> +	{0x0608, 0x00000006, 0x000000ff},
>> +	{0x0610, 0x00000023, 0x000000ff},
>> +	{0x0614, 0x2e003060, 0xff00ffff},
>> +	{0x0618, 0x76000000, 0xff000000},
>> +	{0x062c, 0x00200002, 0x00ff00ff},
>> +	{0x06a0, 0xffee0000, 0xffff0000},
>> +	{0x06a4, 0x0000000f, 0x000000ff},
>> +	{0x0604, 0x5e000000, 0xff000000},
>> +	{0x0608, 0x00000006, 0x000000ff},
>> +	{0x0678, 0x00002000, 0x0000ff00},
>> +	{0x0680, 0x00280028, 0x00ff00ff},
>> +	{0x0684, 0x2d0f0385, 0xffffffff},
>> +	{0x0650, 0xd0000000, 0xff000000},
>> +	{0x0694, 0x20000000, 0xff000000},
>> +
>> +	{0x0800, 0x00000000, 0x000000ff},
>> +	{0x0804, 0x5e000080, 0xff0000ff},
>> +	{0x0808, 0x00000006, 0x000000ff},
>> +	{0x0810, 0x00000023, 0x000000ff},
>> +	{0x0814, 0x2e003060, 0xff00ffff},
>> +	{0x0818, 0x76000000, 0xff000000},
>> +	{0x082c, 0x00200002, 0x00ff00ff},
>> +	{0x08a0, 0xffee0000, 0xffff0000},
>> +	{0x08a4, 0x0000000f, 0x000000ff},
>> +	{0x0804, 0x5e000000, 0xff000000},
>> +	{0x0808, 0x00000006, 0x000000ff},
>> +	{0x0878, 0x00002000, 0x0000ff00},
>> +	{0x0880, 0x00280028, 0x00ff00ff},
>> +	{0x0884, 0x2d0f0385, 0xffffffff},
>> +	{0x0850, 0xd0000000, 0xff000000},
>> +	{0x0894, 0x20000000, 0xff000000},
>> +
>> +	{0x0a00, 0x00000100, 0x0000ff00},
>> +	{0x0a08, 0x00e12c08, 0x00ffffff},
>> +	{0x0a0c, 0x00000081, 0x000000ff},
>> +	{0x0a18, 0x00e80000, 0x00ff0000},
>> +	{0x0a30, 0x002f2f00, 0x00ffff00},
>> +	{0x0a4c, 0xac820000, 0xffff0000},
>> +	{0x0a54, 0xc0000000, 0xff000000},
>> +	{0x0a58, 0x00001441, 0x0000ffff},
>> +	{0x0a84, 0x00000301, 0x0000ffff},
>> +
>> +	{0x0a8c, 0x81030000, 0xffff0000},
>> +	{0x0a90, 0x00006001, 0x0000ffff},
>> +	{0x0a94, 0x01000000, 0xff000000},
>> +	{0x0aa0, 0x81000000, 0xff000000},
>> +	{0x0abc, 0xff000000, 0xff000000},
>> +	{0x0ac0, 0x0000008b, 0x000000ff},
>> +
>> +	{0x0000, 0x00000003, 0x000000ff},
>> +	{0x0a00, 0x0000009f, 0x000000ff},
>> +
>> +	{0x0a44, 0x5f733d00, 0xffffff00},
>> +	{0x0a48, 0x00fdca00, 0x00ffff00},
>> +	{0x0a5c, 0x00000000, 0xffff0000},
>> +	{0x0a60, 0x00008000, 0xffffffff},
>> +	{0x0a64, 0x0c581220, 0xffffffff},
>> +	{0x0a68, 0xe13b0602, 0xffffffff},
>> +	{0x0a6c, 0xb8074cc1, 0xffffffff},
>> +	{0x0a70, 0x3f02e989, 0xffffffff},
>> +	{0x0a74, 0x00000001, 0x000000ff},
>> +	{0x0b14, 0x00370000, 0x00ff0000},
>> +	{0x0b10, 0x37000000, 0xff000000},
>> +	{0x0b14, 0x0000005d, 0x000000ff},
> Which of these is powering on/off the PHY? Which of these is for clocks? Which
> of these is for TX or RX? Which of these is for lane configuration?...
>
> Imagining how would it be if all peripherals are programmed this way in linux..
>
> -Kishon
Kishon, Jingoo,

You are right and I also agree with you. This was originally discussed 
with Arnd on the list.
There is a NDA between TI and owner of the IP not to disclose the 
register details. So we
have to keep the driver the way it is. Once we have permission to 
disclose the details, this
driver will be updated. As per Arnd's request I have also checked the 
existing drivers for
similar register map and couldn't find any. So there is no duplication.

Murali
>> +};
>> +
>> +static int ks_phy_init(struct phy *phy)
>> +{
>> +	struct serdes_config *p;
>> +	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
>> +
>> +	int i;
>> +
>> +	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
>> +		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
>> +		i++, p++) {
>> +		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
>> +		reg_dump((ks_phy->base + p->reg), p->mask);
>> +	}
>> +	udelay(2000);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct phy_ops ks_phy_ops = {
>> +	.init		= ks_phy_init,
>> +	.owner		= THIS_MODULE,
>> +};
>> +
>> +static int ks_phy_probe(struct platform_device *pdev)
>> +{
>> +	struct phy_provider *phy_provider;
>> +	struct device *dev = &pdev->dev;
>> +	struct phy_keystone *ks_phy;
>> +	struct phy *phy;
>> +	struct resource *res;
>> +
>> +	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
>> +	if (!ks_phy)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
>> +	ks_phy->base = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(ks_phy->base))
>> +		return PTR_ERR(ks_phy->base);
>> +
>> +	ks_phy->dev = dev;
>> +	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
>> +	if (IS_ERR(phy))
>> +		return PTR_ERR(phy);
>> +
>> +	phy_set_drvdata(phy, ks_phy);
>> +	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
>> +				of_phy_simple_xlate);
>> +
>> +	if (IS_ERR(phy_provider))
>> +		return PTR_ERR(phy_provider);
>> +
>> +	dev_info(dev, "keystone phy initialized\n");
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id ks_phy_of_match[] = {
>> +	{ .compatible = "ti,keystone-phy" },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, ks_phy_of_match);
>> +
>> +static struct platform_driver ks_phy_driver = {
>> +	.probe	= ks_phy_probe,
>> +	.driver = {
>> +		.of_match_table	= ks_phy_of_match,
>> +		.name  = "ti,keystone-phy",
>> +		.owner = THIS_MODULE,
>> +	}
>> +};
>> +module_platform_driver(ks_phy_driver);
>> +
>> +MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
>> +MODULE_LICENSE("GPL V2");
>> +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
>>


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

* Re: [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-06-02 14:28       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-06-02 14:28 UTC (permalink / raw)
  To: ABRAHAM, KISHON VIJAY
  Cc: linux-kernel, linux-pci, linux-arm-kernel, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas

On 6/2/2014 2:16 AM, ABRAHAM, KISHON VIJAY wrote:
> Hi,
>
> On Thursday 15 May 2014 09:31 PM, Murali Karicheri wrote:
>> This phy driver is used by keystone PCI driver. The hw vendor that
>> provides the phy hw published only registers and their values. So
>> this driver uses these hard coded values to initialize the phy.
>>
>> CC: Grant Likely <grant.likely@linaro.org>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>   drivers/phy/Kconfig        |    6 ++
>>   drivers/phy/Makefile       |    1 +
>>   drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 237 insertions(+)
>>   create mode 100644 drivers/phy/phy-keystone.c
>>
>> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
>> index 4906c27..e5f4b5a 100644
>> --- a/drivers/phy/Kconfig
>> +++ b/drivers/phy/Kconfig
>> @@ -167,4 +167,10 @@ config PHY_XGENE
>>   	help
>>   	  This option enables support for APM X-Gene SoC multi-purpose PHY.
>>   
>> +config PHY_TI_KEYSTONE
>> +	bool "TI Keystone PHY support"
>> +	depends on ARCH_KEYSTONE
>> +	select GENERIC_PHY
>> +	help
>> +	  This option enables support for TI Keystone PHY (serdes).
>>   endmenu
>> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
>> index 7728518..bd306a7 100644
>> --- a/drivers/phy/Makefile
>> +++ b/drivers/phy/Makefile
>> @@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>>   phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
>>   phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
>>   obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>> +obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
>> diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
>> new file mode 100644
>> index 0000000..ba1b9fa
>> --- /dev/null
>> +++ b/drivers/phy/phy-keystone.c
>> @@ -0,0 +1,230 @@
>> +/*
>> + * PCIe Keystone platform specific driver code
>> + *
>> + * Copyright (C) 2013-2014 Texas Instruments, Inc.
>> + *		http://www.ti.com
>> + *
>> + * Author: Murali Karicheri <m-karicheri2@ti.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/platform_device.h>
>> +
>> +#define reg_dump(addr, mask) \
>> +		pr_debug("reg %p has value %x\n", (void *)addr, \
>> +			(readl(addr) & ~mask))
>> +
>> +/* mask bits point to bits being modified */
>> +#define reg_rmw(addr, value, mask) \
>> +		writel(((readl(addr) & (~(mask))) | \
>> +			(value & (mask))), (addr))
>> +struct serdes_config {
>> +	u32 reg;
>> +	u32 val;
>> +	u32 mask;
>> +};
>> +
>> +struct phy_keystone {
>> +	struct device *dev;
>> +	void __iomem *base;
>> +};
>> +
>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>> +	{0x0000, 0x00000800, 0x0000ff00},
>> +	{0x0060, 0x00041c5c, 0x00ffffff},
>> +	{0x0064, 0x0343c700, 0xffffff00},
>> +	{0x006c, 0x00000012, 0x000000ff},
>> +	{0x0068, 0x00070000, 0x00ff0000},
>> +	{0x0078, 0x0000c000, 0x0000ff00},
>> +
>> +	{0x0200, 0x00000000, 0x000000ff},
>> +	{0x0204, 0x5e000080, 0xff0000ff},
>> +	{0x0208, 0x00000006, 0x000000ff},
>> +	{0x0210, 0x00000023, 0x000000ff},
>> +	{0x0214, 0x2e003060, 0xff00ffff},
>> +	{0x0218, 0x76000000, 0xff000000},
>> +	{0x022c, 0x00200002, 0x00ff00ff},
>> +	{0x02a0, 0xffee0000, 0xffff0000},
>> +	{0x02a4, 0x0000000f, 0x000000ff},
>> +	{0x0204, 0x5e000000, 0xff000000},
>> +	{0x0208, 0x00000006, 0x000000ff},
>> +	{0x0278, 0x00002000, 0x0000ff00},
>> +	{0x0280, 0x00280028, 0x00ff00ff},
>> +	{0x0284, 0x2d0f0385, 0xffffffff},
>> +	{0x0250, 0xd0000000, 0xff000000},
>> +	{0x0284, 0x00000085, 0x000000ff},
>> +	{0x0294, 0x20000000, 0xff000000},
>> +
>> +	{0x0400, 0x00000000, 0x000000ff},
>> +	{0x0404, 0x5e000080, 0xff0000ff},
>> +	{0x0408, 0x00000006, 0x000000ff},
>> +	{0x0410, 0x00000023, 0x000000ff},
>> +	{0x0414, 0x2e003060, 0xff00ffff},
>> +	{0x0418, 0x76000000, 0xff000000},
>> +	{0x042c, 0x00200002, 0x00ff00ff},
>> +	{0x04a0, 0xffee0000, 0xffff0000},
>> +	{0x04a4, 0x0000000f, 0x000000ff},
>> +	{0x0404, 0x5e000000, 0xff000000},
>> +	{0x0408, 0x00000006, 0x000000ff},
>> +	{0x0478, 0x00002000, 0x0000ff00},
>> +	{0x0480, 0x00280028, 0x00ff00ff},
>> +	{0x0484, 0x2d0f0385, 0xffffffff},
>> +	{0x0450, 0xd0000000, 0xff000000},
>> +	{0x0494, 0x20000000, 0xff000000},
>> +
>> +	{0x0604, 0x00000080, 0x000000ff},
>> +	{0x0600, 0x00000000, 0x000000ff},
>> +	{0x0604, 0x5e000000, 0xff000000},
>> +	{0x0608, 0x00000006, 0x000000ff},
>> +	{0x0610, 0x00000023, 0x000000ff},
>> +	{0x0614, 0x2e003060, 0xff00ffff},
>> +	{0x0618, 0x76000000, 0xff000000},
>> +	{0x062c, 0x00200002, 0x00ff00ff},
>> +	{0x06a0, 0xffee0000, 0xffff0000},
>> +	{0x06a4, 0x0000000f, 0x000000ff},
>> +	{0x0604, 0x5e000000, 0xff000000},
>> +	{0x0608, 0x00000006, 0x000000ff},
>> +	{0x0678, 0x00002000, 0x0000ff00},
>> +	{0x0680, 0x00280028, 0x00ff00ff},
>> +	{0x0684, 0x2d0f0385, 0xffffffff},
>> +	{0x0650, 0xd0000000, 0xff000000},
>> +	{0x0694, 0x20000000, 0xff000000},
>> +
>> +	{0x0800, 0x00000000, 0x000000ff},
>> +	{0x0804, 0x5e000080, 0xff0000ff},
>> +	{0x0808, 0x00000006, 0x000000ff},
>> +	{0x0810, 0x00000023, 0x000000ff},
>> +	{0x0814, 0x2e003060, 0xff00ffff},
>> +	{0x0818, 0x76000000, 0xff000000},
>> +	{0x082c, 0x00200002, 0x00ff00ff},
>> +	{0x08a0, 0xffee0000, 0xffff0000},
>> +	{0x08a4, 0x0000000f, 0x000000ff},
>> +	{0x0804, 0x5e000000, 0xff000000},
>> +	{0x0808, 0x00000006, 0x000000ff},
>> +	{0x0878, 0x00002000, 0x0000ff00},
>> +	{0x0880, 0x00280028, 0x00ff00ff},
>> +	{0x0884, 0x2d0f0385, 0xffffffff},
>> +	{0x0850, 0xd0000000, 0xff000000},
>> +	{0x0894, 0x20000000, 0xff000000},
>> +
>> +	{0x0a00, 0x00000100, 0x0000ff00},
>> +	{0x0a08, 0x00e12c08, 0x00ffffff},
>> +	{0x0a0c, 0x00000081, 0x000000ff},
>> +	{0x0a18, 0x00e80000, 0x00ff0000},
>> +	{0x0a30, 0x002f2f00, 0x00ffff00},
>> +	{0x0a4c, 0xac820000, 0xffff0000},
>> +	{0x0a54, 0xc0000000, 0xff000000},
>> +	{0x0a58, 0x00001441, 0x0000ffff},
>> +	{0x0a84, 0x00000301, 0x0000ffff},
>> +
>> +	{0x0a8c, 0x81030000, 0xffff0000},
>> +	{0x0a90, 0x00006001, 0x0000ffff},
>> +	{0x0a94, 0x01000000, 0xff000000},
>> +	{0x0aa0, 0x81000000, 0xff000000},
>> +	{0x0abc, 0xff000000, 0xff000000},
>> +	{0x0ac0, 0x0000008b, 0x000000ff},
>> +
>> +	{0x0000, 0x00000003, 0x000000ff},
>> +	{0x0a00, 0x0000009f, 0x000000ff},
>> +
>> +	{0x0a44, 0x5f733d00, 0xffffff00},
>> +	{0x0a48, 0x00fdca00, 0x00ffff00},
>> +	{0x0a5c, 0x00000000, 0xffff0000},
>> +	{0x0a60, 0x00008000, 0xffffffff},
>> +	{0x0a64, 0x0c581220, 0xffffffff},
>> +	{0x0a68, 0xe13b0602, 0xffffffff},
>> +	{0x0a6c, 0xb8074cc1, 0xffffffff},
>> +	{0x0a70, 0x3f02e989, 0xffffffff},
>> +	{0x0a74, 0x00000001, 0x000000ff},
>> +	{0x0b14, 0x00370000, 0x00ff0000},
>> +	{0x0b10, 0x37000000, 0xff000000},
>> +	{0x0b14, 0x0000005d, 0x000000ff},
> Which of these is powering on/off the PHY? Which of these is for clocks? Which
> of these is for TX or RX? Which of these is for lane configuration?...
>
> Imagining how would it be if all peripherals are programmed this way in linux..
>
> -Kishon
Kishon, Jingoo,

You are right and I also agree with you. This was originally discussed 
with Arnd on the list.
There is a NDA between TI and owner of the IP not to disclose the 
register details. So we
have to keep the driver the way it is. Once we have permission to 
disclose the details, this
driver will be updated. As per Arnd's request I have also checked the 
existing drivers for
similar register map and couldn't find any. So there is no duplication.

Murali
>> +};
>> +
>> +static int ks_phy_init(struct phy *phy)
>> +{
>> +	struct serdes_config *p;
>> +	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
>> +
>> +	int i;
>> +
>> +	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
>> +		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
>> +		i++, p++) {
>> +		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
>> +		reg_dump((ks_phy->base + p->reg), p->mask);
>> +	}
>> +	udelay(2000);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct phy_ops ks_phy_ops = {
>> +	.init		= ks_phy_init,
>> +	.owner		= THIS_MODULE,
>> +};
>> +
>> +static int ks_phy_probe(struct platform_device *pdev)
>> +{
>> +	struct phy_provider *phy_provider;
>> +	struct device *dev = &pdev->dev;
>> +	struct phy_keystone *ks_phy;
>> +	struct phy *phy;
>> +	struct resource *res;
>> +
>> +	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
>> +	if (!ks_phy)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
>> +	ks_phy->base = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(ks_phy->base))
>> +		return PTR_ERR(ks_phy->base);
>> +
>> +	ks_phy->dev = dev;
>> +	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
>> +	if (IS_ERR(phy))
>> +		return PTR_ERR(phy);
>> +
>> +	phy_set_drvdata(phy, ks_phy);
>> +	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
>> +				of_phy_simple_xlate);
>> +
>> +	if (IS_ERR(phy_provider))
>> +		return PTR_ERR(phy_provider);
>> +
>> +	dev_info(dev, "keystone phy initialized\n");
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id ks_phy_of_match[] = {
>> +	{ .compatible = "ti,keystone-phy" },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, ks_phy_of_match);
>> +
>> +static struct platform_driver ks_phy_driver = {
>> +	.probe	= ks_phy_probe,
>> +	.driver = {
>> +		.of_match_table	= ks_phy_of_match,
>> +		.name  = "ti,keystone-phy",
>> +		.owner = THIS_MODULE,
>> +	}
>> +};
>> +module_platform_driver(ks_phy_driver);
>> +
>> +MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
>> +MODULE_LICENSE("GPL V2");
>> +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
>>


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

* [PATCH v1 3/5] phy: pci serdes phy driver for keystone
@ 2014-06-02 14:28       ` Murali Karicheri
  0 siblings, 0 replies; 116+ messages in thread
From: Murali Karicheri @ 2014-06-02 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 6/2/2014 2:16 AM, ABRAHAM, KISHON VIJAY wrote:
> Hi,
>
> On Thursday 15 May 2014 09:31 PM, Murali Karicheri wrote:
>> This phy driver is used by keystone PCI driver. The hw vendor that
>> provides the phy hw published only registers and their values. So
>> this driver uses these hard coded values to initialize the phy.
>>
>> CC: Grant Likely <grant.likely@linaro.org>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: Mohit Kumar <mohit.kumar@st.com>
>> CC: Jingoo Han <jg1.han@samsung.com>
>> CC: Bjorn Helgaas <bhelgaas@google.com>
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>   drivers/phy/Kconfig        |    6 ++
>>   drivers/phy/Makefile       |    1 +
>>   drivers/phy/phy-keystone.c |  230 ++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 237 insertions(+)
>>   create mode 100644 drivers/phy/phy-keystone.c
>>
>> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
>> index 4906c27..e5f4b5a 100644
>> --- a/drivers/phy/Kconfig
>> +++ b/drivers/phy/Kconfig
>> @@ -167,4 +167,10 @@ config PHY_XGENE
>>   	help
>>   	  This option enables support for APM X-Gene SoC multi-purpose PHY.
>>   
>> +config PHY_TI_KEYSTONE
>> +	bool "TI Keystone PHY support"
>> +	depends on ARCH_KEYSTONE
>> +	select GENERIC_PHY
>> +	help
>> +	  This option enables support for TI Keystone PHY (serdes).
>>   endmenu
>> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
>> index 7728518..bd306a7 100644
>> --- a/drivers/phy/Makefile
>> +++ b/drivers/phy/Makefile
>> @@ -19,3 +19,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>>   phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
>>   phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
>>   obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>> +obj-$(CONFIG_PHY_TI_KEYSTONE)		+= phy-keystone.o
>> diff --git a/drivers/phy/phy-keystone.c b/drivers/phy/phy-keystone.c
>> new file mode 100644
>> index 0000000..ba1b9fa
>> --- /dev/null
>> +++ b/drivers/phy/phy-keystone.c
>> @@ -0,0 +1,230 @@
>> +/*
>> + * PCIe Keystone platform specific driver code
>> + *
>> + * Copyright (C) 2013-2014 Texas Instruments, Inc.
>> + *		http://www.ti.com
>> + *
>> + * Author: Murali Karicheri <m-karicheri2@ti.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/platform_device.h>
>> +
>> +#define reg_dump(addr, mask) \
>> +		pr_debug("reg %p has value %x\n", (void *)addr, \
>> +			(readl(addr) & ~mask))
>> +
>> +/* mask bits point to bits being modified */
>> +#define reg_rmw(addr, value, mask) \
>> +		writel(((readl(addr) & (~(mask))) | \
>> +			(value & (mask))), (addr))
>> +struct serdes_config {
>> +	u32 reg;
>> +	u32 val;
>> +	u32 mask;
>> +};
>> +
>> +struct phy_keystone {
>> +	struct device *dev;
>> +	void __iomem *base;
>> +};
>> +
>> +static struct serdes_config ks_100mhz_pcie_5gbps_serdes[] = {
>> +	{0x0000, 0x00000800, 0x0000ff00},
>> +	{0x0060, 0x00041c5c, 0x00ffffff},
>> +	{0x0064, 0x0343c700, 0xffffff00},
>> +	{0x006c, 0x00000012, 0x000000ff},
>> +	{0x0068, 0x00070000, 0x00ff0000},
>> +	{0x0078, 0x0000c000, 0x0000ff00},
>> +
>> +	{0x0200, 0x00000000, 0x000000ff},
>> +	{0x0204, 0x5e000080, 0xff0000ff},
>> +	{0x0208, 0x00000006, 0x000000ff},
>> +	{0x0210, 0x00000023, 0x000000ff},
>> +	{0x0214, 0x2e003060, 0xff00ffff},
>> +	{0x0218, 0x76000000, 0xff000000},
>> +	{0x022c, 0x00200002, 0x00ff00ff},
>> +	{0x02a0, 0xffee0000, 0xffff0000},
>> +	{0x02a4, 0x0000000f, 0x000000ff},
>> +	{0x0204, 0x5e000000, 0xff000000},
>> +	{0x0208, 0x00000006, 0x000000ff},
>> +	{0x0278, 0x00002000, 0x0000ff00},
>> +	{0x0280, 0x00280028, 0x00ff00ff},
>> +	{0x0284, 0x2d0f0385, 0xffffffff},
>> +	{0x0250, 0xd0000000, 0xff000000},
>> +	{0x0284, 0x00000085, 0x000000ff},
>> +	{0x0294, 0x20000000, 0xff000000},
>> +
>> +	{0x0400, 0x00000000, 0x000000ff},
>> +	{0x0404, 0x5e000080, 0xff0000ff},
>> +	{0x0408, 0x00000006, 0x000000ff},
>> +	{0x0410, 0x00000023, 0x000000ff},
>> +	{0x0414, 0x2e003060, 0xff00ffff},
>> +	{0x0418, 0x76000000, 0xff000000},
>> +	{0x042c, 0x00200002, 0x00ff00ff},
>> +	{0x04a0, 0xffee0000, 0xffff0000},
>> +	{0x04a4, 0x0000000f, 0x000000ff},
>> +	{0x0404, 0x5e000000, 0xff000000},
>> +	{0x0408, 0x00000006, 0x000000ff},
>> +	{0x0478, 0x00002000, 0x0000ff00},
>> +	{0x0480, 0x00280028, 0x00ff00ff},
>> +	{0x0484, 0x2d0f0385, 0xffffffff},
>> +	{0x0450, 0xd0000000, 0xff000000},
>> +	{0x0494, 0x20000000, 0xff000000},
>> +
>> +	{0x0604, 0x00000080, 0x000000ff},
>> +	{0x0600, 0x00000000, 0x000000ff},
>> +	{0x0604, 0x5e000000, 0xff000000},
>> +	{0x0608, 0x00000006, 0x000000ff},
>> +	{0x0610, 0x00000023, 0x000000ff},
>> +	{0x0614, 0x2e003060, 0xff00ffff},
>> +	{0x0618, 0x76000000, 0xff000000},
>> +	{0x062c, 0x00200002, 0x00ff00ff},
>> +	{0x06a0, 0xffee0000, 0xffff0000},
>> +	{0x06a4, 0x0000000f, 0x000000ff},
>> +	{0x0604, 0x5e000000, 0xff000000},
>> +	{0x0608, 0x00000006, 0x000000ff},
>> +	{0x0678, 0x00002000, 0x0000ff00},
>> +	{0x0680, 0x00280028, 0x00ff00ff},
>> +	{0x0684, 0x2d0f0385, 0xffffffff},
>> +	{0x0650, 0xd0000000, 0xff000000},
>> +	{0x0694, 0x20000000, 0xff000000},
>> +
>> +	{0x0800, 0x00000000, 0x000000ff},
>> +	{0x0804, 0x5e000080, 0xff0000ff},
>> +	{0x0808, 0x00000006, 0x000000ff},
>> +	{0x0810, 0x00000023, 0x000000ff},
>> +	{0x0814, 0x2e003060, 0xff00ffff},
>> +	{0x0818, 0x76000000, 0xff000000},
>> +	{0x082c, 0x00200002, 0x00ff00ff},
>> +	{0x08a0, 0xffee0000, 0xffff0000},
>> +	{0x08a4, 0x0000000f, 0x000000ff},
>> +	{0x0804, 0x5e000000, 0xff000000},
>> +	{0x0808, 0x00000006, 0x000000ff},
>> +	{0x0878, 0x00002000, 0x0000ff00},
>> +	{0x0880, 0x00280028, 0x00ff00ff},
>> +	{0x0884, 0x2d0f0385, 0xffffffff},
>> +	{0x0850, 0xd0000000, 0xff000000},
>> +	{0x0894, 0x20000000, 0xff000000},
>> +
>> +	{0x0a00, 0x00000100, 0x0000ff00},
>> +	{0x0a08, 0x00e12c08, 0x00ffffff},
>> +	{0x0a0c, 0x00000081, 0x000000ff},
>> +	{0x0a18, 0x00e80000, 0x00ff0000},
>> +	{0x0a30, 0x002f2f00, 0x00ffff00},
>> +	{0x0a4c, 0xac820000, 0xffff0000},
>> +	{0x0a54, 0xc0000000, 0xff000000},
>> +	{0x0a58, 0x00001441, 0x0000ffff},
>> +	{0x0a84, 0x00000301, 0x0000ffff},
>> +
>> +	{0x0a8c, 0x81030000, 0xffff0000},
>> +	{0x0a90, 0x00006001, 0x0000ffff},
>> +	{0x0a94, 0x01000000, 0xff000000},
>> +	{0x0aa0, 0x81000000, 0xff000000},
>> +	{0x0abc, 0xff000000, 0xff000000},
>> +	{0x0ac0, 0x0000008b, 0x000000ff},
>> +
>> +	{0x0000, 0x00000003, 0x000000ff},
>> +	{0x0a00, 0x0000009f, 0x000000ff},
>> +
>> +	{0x0a44, 0x5f733d00, 0xffffff00},
>> +	{0x0a48, 0x00fdca00, 0x00ffff00},
>> +	{0x0a5c, 0x00000000, 0xffff0000},
>> +	{0x0a60, 0x00008000, 0xffffffff},
>> +	{0x0a64, 0x0c581220, 0xffffffff},
>> +	{0x0a68, 0xe13b0602, 0xffffffff},
>> +	{0x0a6c, 0xb8074cc1, 0xffffffff},
>> +	{0x0a70, 0x3f02e989, 0xffffffff},
>> +	{0x0a74, 0x00000001, 0x000000ff},
>> +	{0x0b14, 0x00370000, 0x00ff0000},
>> +	{0x0b10, 0x37000000, 0xff000000},
>> +	{0x0b14, 0x0000005d, 0x000000ff},
> Which of these is powering on/off the PHY? Which of these is for clocks? Which
> of these is for TX or RX? Which of these is for lane configuration?...
>
> Imagining how would it be if all peripherals are programmed this way in linux..
>
> -Kishon
Kishon, Jingoo,

You are right and I also agree with you. This was originally discussed 
with Arnd on the list.
There is a NDA between TI and owner of the IP not to disclose the 
register details. So we
have to keep the driver the way it is. Once we have permission to 
disclose the details, this
driver will be updated. As per Arnd's request I have also checked the 
existing drivers for
similar register map and couldn't find any. So there is no duplication.

Murali
>> +};
>> +
>> +static int ks_phy_init(struct phy *phy)
>> +{
>> +	struct serdes_config *p;
>> +	struct phy_keystone *ks_phy = phy_get_drvdata(phy);
>> +
>> +	int i;
>> +
>> +	for (i = 0, p = &ks_100mhz_pcie_5gbps_serdes[0];
>> +		i < ARRAY_SIZE(ks_100mhz_pcie_5gbps_serdes);
>> +		i++, p++) {
>> +		reg_rmw((ks_phy->base + p->reg), p->val, p->mask);
>> +		reg_dump((ks_phy->base + p->reg), p->mask);
>> +	}
>> +	udelay(2000);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct phy_ops ks_phy_ops = {
>> +	.init		= ks_phy_init,
>> +	.owner		= THIS_MODULE,
>> +};
>> +
>> +static int ks_phy_probe(struct platform_device *pdev)
>> +{
>> +	struct phy_provider *phy_provider;
>> +	struct device *dev = &pdev->dev;
>> +	struct phy_keystone *ks_phy;
>> +	struct phy *phy;
>> +	struct resource *res;
>> +
>> +	ks_phy = devm_kzalloc(dev, sizeof(*ks_phy), GFP_KERNEL);
>> +	if (!ks_phy)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_serdes");
>> +	ks_phy->base = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(ks_phy->base))
>> +		return PTR_ERR(ks_phy->base);
>> +
>> +	ks_phy->dev = dev;
>> +	phy = devm_phy_create(dev, &ks_phy_ops, NULL);
>> +	if (IS_ERR(phy))
>> +		return PTR_ERR(phy);
>> +
>> +	phy_set_drvdata(phy, ks_phy);
>> +	phy_provider = devm_of_phy_provider_register(ks_phy->dev,
>> +				of_phy_simple_xlate);
>> +
>> +	if (IS_ERR(phy_provider))
>> +		return PTR_ERR(phy_provider);
>> +
>> +	dev_info(dev, "keystone phy initialized\n");
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id ks_phy_of_match[] = {
>> +	{ .compatible = "ti,keystone-phy" },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, ks_phy_of_match);
>> +
>> +static struct platform_driver ks_phy_driver = {
>> +	.probe	= ks_phy_probe,
>> +	.driver = {
>> +		.of_match_table	= ks_phy_of_match,
>> +		.name  = "ti,keystone-phy",
>> +		.owner = THIS_MODULE,
>> +	}
>> +};
>> +module_platform_driver(ks_phy_driver);
>> +
>> +MODULE_DESCRIPTION("TI Keystone SerDes PHY driver");
>> +MODULE_LICENSE("GPL V2");
>> +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
>>

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

end of thread, other threads:[~2014-06-02 14:28 UTC | newest]

Thread overview: 116+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-15 16:01 [PATCH v1 0/5] Add Keystone PCIe controller driver Murali Karicheri
2014-05-15 16:01 ` Murali Karicheri
2014-05-15 16:01 ` [PATCH v1 1/5] ARM: keystone: add pcie related options Murali Karicheri
2014-05-15 16:01   ` Murali Karicheri
2014-05-16  0:27   ` Jingoo Han
2014-05-16  0:27     ` Jingoo Han
2014-05-16 14:36     ` Karicheri, Muralidharan
2014-05-16 14:36       ` Karicheri, Muralidharan
2014-05-16 14:36       ` Karicheri, Muralidharan
2014-05-15 16:01 ` [PATCH v1 2/5] pci: designware: enhancements to support keystone pcie Murali Karicheri
2014-05-15 16:01   ` Murali Karicheri
2014-05-16  2:40   ` Jingoo Han
2014-05-16  2:40     ` Jingoo Han
2014-05-16 20:46   ` Karicheri, Muralidharan
2014-05-16 20:46     ` Karicheri, Muralidharan
2014-05-16 20:46     ` Karicheri, Muralidharan
2014-05-16 22:15   ` Kumar Gala
2014-05-16 22:15     ` Kumar Gala
2014-05-16 22:49     ` Murali Karicheri
2014-05-16 22:49       ` Murali Karicheri
2014-05-16 22:49       ` Murali Karicheri
2014-05-15 16:01 ` [PATCH v1 3/5] phy: pci serdes phy driver for keystone Murali Karicheri
2014-05-15 16:01   ` Murali Karicheri
2014-05-15 16:14   ` Arnd Bergmann
2014-05-15 16:14     ` Arnd Bergmann
2014-05-23 17:14     ` Murali Karicheri
2014-05-23 17:14       ` Murali Karicheri
2014-05-23 17:14       ` Murali Karicheri
2014-05-23 19:23       ` Arnd Bergmann
2014-05-23 19:23         ` Arnd Bergmann
2014-05-27 16:46         ` Murali Karicheri
2014-05-27 16:46           ` Murali Karicheri
2014-05-27 16:46           ` Murali Karicheri
2014-05-27 18:36           ` Arnd Bergmann
2014-05-27 18:36             ` Arnd Bergmann
2014-05-27 18:36             ` Arnd Bergmann
2014-06-02  6:16   ` Kishon Vijay Abraham I
2014-06-02  6:16     ` Kishon Vijay Abraham I
2014-06-02  6:45     ` Jingoo Han
2014-06-02  6:45       ` Jingoo Han
2014-06-02 14:28     ` Murali Karicheri
2014-06-02 14:28       ` Murali Karicheri
2014-06-02 14:28       ` Murali Karicheri
2014-05-15 16:01 ` [PATCH v1 4/5] pci: dw: add common functions to support old hw based pci driver Murali Karicheri
2014-05-15 16:01   ` Murali Karicheri
2014-05-16 20:47   ` Karicheri, Muralidharan
2014-05-16 20:47     ` Karicheri, Muralidharan
2014-05-16 20:47     ` Karicheri, Muralidharan
2014-05-15 16:01 ` [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver Murali Karicheri
2014-05-15 16:01   ` Murali Karicheri
2014-05-15 16:23   ` Arnd Bergmann
2014-05-15 16:23     ` Arnd Bergmann
2014-05-15 17:45     ` Murali Karicheri
2014-05-15 17:45       ` Murali Karicheri
2014-05-15 17:45       ` Murali Karicheri
2014-05-15 18:20       ` Arnd Bergmann
2014-05-15 18:20         ` Arnd Bergmann
2014-05-15 18:39         ` Jason Gunthorpe
2014-05-15 18:39           ` Jason Gunthorpe
2014-05-15 20:04           ` Murali Karicheri
2014-05-15 20:04             ` Murali Karicheri
2014-05-15 20:04             ` Murali Karicheri
2014-05-15 20:52             ` Jason Gunthorpe
2014-05-15 20:52               ` Jason Gunthorpe
2014-05-15 20:52               ` Jason Gunthorpe
2014-05-16 20:29               ` Karicheri, Muralidharan
2014-05-16 20:29                 ` Karicheri, Muralidharan
2014-05-16 20:29                 ` Karicheri, Muralidharan
2014-05-20 17:02                 ` Jason Gunthorpe
2014-05-20 17:02                   ` Jason Gunthorpe
2014-05-20 17:02                   ` Jason Gunthorpe
2014-05-20 17:22                   ` Bjorn Helgaas
2014-05-20 17:22                     ` Bjorn Helgaas
2014-05-20 17:22                     ` Bjorn Helgaas
2014-05-20 17:42                     ` Jason Gunthorpe
2014-05-20 17:42                       ` Jason Gunthorpe
2014-05-20 17:42                       ` Jason Gunthorpe
2014-05-21 23:32                   ` Murali Karicheri
2014-05-21 23:32                     ` Murali Karicheri
2014-05-21 23:32                     ` Murali Karicheri
2014-05-22  0:55                     ` Jason Gunthorpe
2014-05-22  0:55                       ` Jason Gunthorpe
2014-05-22  0:55                       ` Jason Gunthorpe
     [not found]                       ` <537E7823.5060609@ti.com>
2014-05-26 23:31                         ` Jason Gunthorpe
2014-05-26 23:31                           ` Jason Gunthorpe
2014-05-26 23:31                           ` Jason Gunthorpe
2014-05-16 20:26         ` Murali Karicheri
2014-05-16 20:26           ` Murali Karicheri
2014-05-16 20:26           ` Murali Karicheri
2014-05-19 12:06           ` Arnd Bergmann
2014-05-19 12:06             ` Arnd Bergmann
2014-05-19 21:10             ` Murali Karicheri
2014-05-19 21:10               ` Murali Karicheri
2014-05-19 21:10               ` Murali Karicheri
2014-05-20  7:55               ` Arnd Bergmann
2014-05-20  7:55                 ` Arnd Bergmann
2014-05-20 17:17                 ` Bjorn Helgaas
2014-05-20 17:17                   ` Bjorn Helgaas
2014-05-29 15:34     ` Murali Karicheri
2014-05-29 15:34       ` Murali Karicheri
2014-05-29 15:34       ` Murali Karicheri
2014-05-15 16:28   ` Arnd Bergmann
2014-05-15 16:28     ` Arnd Bergmann
2014-05-16 22:44     ` Murali Karicheri
2014-05-16 22:44       ` Murali Karicheri
2014-05-16 22:44       ` Murali Karicheri
2014-05-19 12:12       ` Arnd Bergmann
2014-05-19 12:12         ` Arnd Bergmann
2014-05-16 20:47   ` Karicheri, Muralidharan
2014-05-16 20:47     ` Karicheri, Muralidharan
2014-05-16 20:47     ` Karicheri, Muralidharan
2014-05-16  0:48 ` [PATCH v1 0/5] Add Keystone PCIe controller driver Jingoo Han
2014-05-16  0:48   ` Jingoo Han
2014-05-16 20:40   ` Karicheri, Muralidharan
2014-05-16 20:40     ` Karicheri, Muralidharan
2014-05-16 20:40     ` Karicheri, Muralidharan

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.