Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1482930 > unrolled thread

[RFC PATCH 00/11] pci: support for configurable PCI endpoint

Started byKishon Vijay Abraham I <kishon@ti.com>
First post2016-09-14 07:20 +0200
Last post2016-09-22 15:40 +0200
Articles 10 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [RFC PATCH 00/11] pci: support for configurable PCI endpoint Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-14 07:20 +0200
    [RFC PATCH 09/11] misc: add a new host side PCI endpoint test driver Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-14 07:20 +0200
    [RFC PATCH 01/11] pci: endpoint: add EP core layer to enable EP controller and EP functions Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-14 07:20 +0200
    [RFC PATCH 08/11] pci: controller: dra7xx: Add EP mode support Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-14 07:20 +0200
    [RFC PATCH 03/11] Documentation: PCI: guide to use PCI Endpoint Core Layer Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-14 07:20 +0200
    [RFC PATCH 05/11] pci: rename *host* directory to *controller* Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-14 07:20 +0200
    [RFC PATCH 04/11] pci: endpoint: functions: add an EP function to test PCI Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-14 07:20 +0200
    Re: [RFC PATCH 00/11] pci: support for configurable PCI endpoint Arnd Bergmann <arnd@arndb.de> - 2016-09-14 15:30 +0200
      Re: [RFC PATCH 00/11] pci: support for configurable PCI endpoint Kishon Vijay Abraham I <kishon@ti.com> - 2016-09-15 10:40 +0200
        Re: [RFC PATCH 00/11] pci: support for configurable PCI endpoint Arnd Bergmann <arnd@arndb.de> - 2016-09-22 15:40 +0200

#1482930 — [RFC PATCH 00/11] pci: support for configurable PCI endpoint

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-14 07:20 +0200
Subject[RFC PATCH 00/11] pci: support for configurable PCI endpoint
Message-ID<shaM1-4De-3@gated-at.bofh.it>
This patch series
	*) adds PCI endpoint core layer
	*) modifies designware/dra7xx driver to be configured in EP mode
	*) adds a PCI endpoint *test* function driver

Known Limitation:
	*) Does not support multi-function devices

TODO:
	*) access buffers in RC
	*) raise MSI interrupts
	*) Enable user space control for the RC side PCI driver
	*) Adapt all other users of designware to use the new design (only
	   dra7xx has been adapted)

HOW TO:

ON THE EP SIDE:
***************

/* EP function is configured using configfs */
# mount -t configfs none /sys/kernel/config

/* PCI EP core layer creates "pci_ep" entry in configfs */
# cd /sys/kernel/config/pci_ep/

/*
 * This is the 1st step in creating an endpoint function. This
 * creates the endpoint function device *instance*. The string
 * before the .<num> suffix will identify the driver this
 * EP function will bind to.
 * Just pci_epf_test is also valid. The .<num> suffix is used
 * if there are multiple PCI controllers and all of them wants
 * to use the same function.
 */
# mkdir pci_epf_test.0

/*
 * When the above command is given, the function device will
 * also be bound to a function driver. To find the list of
 * function drivers available in the system, use the following
 * command. To create a new driver, the following can be referred
 * drivers/pci/endpoint/functions/pci-epf-test.c
 */
# ls /sys/bus/pci-epf/drivers
pci_epf_test

/* Now configure the endpoint function */
# cd pci_epf_test.0

/* These are the fields that can be configured */
# ls
baseclass_code    function          revid             vendorid
cache_line_size   interrupt_pin     subclass_code
deviceid          peripheral        subsys_id
epc               progif_code       subsys_vendor_id

/* The function driver will populate these fields with default values */
# cat vendorid 
0xffff

# cat interrupt_pin 
0x0001

/* The user can configure any of these fields */
# echo 0x104c > vendorid

/*
 * Next is binding this function driver to the controller driver. In
 * order to find the possible controller drivers that this function
 * driver can be bound to, the following sysfs entry can be used
 */
# ls /sys/class/pci_epc/
51000000.pci

/* Now bind the function driver to the controller driver */
# echo "51000000.pcie" > epc
[  494.743487] dra7-pcie 51000000.pcie: no free inbound window
[  494.749367] pci_epf_test pci_epf_test.0: failed to set BAR4
[  494.755238] dra7-pcie 51000000.pcie: no free inbound window
[  494.761451] pci_epf_test pci_epf_test.0: failed to set BAR5

/*
 * the above error messages are due to non availability of free
 * inbound windows. So the function drivers in dra7xx can use
 * only 4 (BAR0..BAR3) BARs
 */

/****** PCI endpoint is configured ******/

ON THE HOST SIDE:
*****************
# modprobe pci_endpoint_test
[    8.197560] ****** Testing pci-endpoint-test Device ******
[    9.056990] Reset: OKAY
[    9.059753] BAR1 OKAY
[    9.062419] BAR2 OKAY
[    9.069506] BAR3 OKAY
[    9.071880] BAR4 NOT OKAY
[    9.074618] BAR5 NOT OKAY
[    9.379257] Legacy IRQ: OKAY
[    9.382281] ****** End Test ******

/*
 * Rightnow these tests gets executed as soon as the pci_endpoint_test
 * module gets inserted. These will be modified so that user/user script
 * can control this. Once the functionality for EP to access RC buffer
 * is added, more tests can be added including throughput measurement tests.
 */ 

Kishon Vijay Abraham I (11):
  pci: endpoint: add EP core layer to enable EP controller and EP
    functions
  pci: endpoint: introduce configfs entry for configuring EP functions
  Documentation: PCI: guide to use PCI Endpoint Core Layer
  pci: endpoint: functions: add an EP function to test PCI
  pci: rename *host* directory to *controller*
  pci: controller: split designware into *core* and *host*
  pci: controller: designware: Add EP mode support
  pci: controller: dra7xx: Add EP mode support
  misc: add a new host side PCI endpoint test driver
  ARM: dts: DRA7: Modify pcie1 dt node for EP mode
  HACK: pci: controller: dra7xx: disable smart idle

 Documentation/PCI/00-INDEX                         |    5 +
 Documentation/PCI/pci-endpoint.txt                 |  199 ++++++++++
 Documentation/PCI/pci-test.txt                     |   79 ++++
 .../devicetree/bindings/pci/designware-pcie.txt    |   26 +-
 Documentation/devicetree/bindings/pci/ti-pci.txt   |   30 +-
 MAINTAINERS                                        |   50 +--
 arch/arm/boot/dts/dra7.dtsi                        |   43 +--
 drivers/Makefile                                   |    4 +
 drivers/misc/Kconfig                               |    7 +
 drivers/misc/Makefile                              |    1 +
 drivers/misc/pci_endpoint_test.c                   |  291 +++++++++++++++
 drivers/pci/Kconfig                                |    3 +-
 drivers/pci/Makefile                               |    3 -
 drivers/pci/{host => controller}/Kconfig           |  109 +++++-
 drivers/pci/{host => controller}/Makefile          |    2 +
 drivers/pci/{host => controller}/pci-aardvark.c    |    0
 drivers/pci/{host => controller}/pci-dra7xx.c      |  340 +++++++++++++----
 drivers/pci/{host => controller}/pci-exynos.c      |    0
 drivers/pci/{host => controller}/pci-host-common.c |    0
 .../pci/{host => controller}/pci-host-generic.c    |    0
 drivers/pci/{host => controller}/pci-hyperv.c      |    0
 drivers/pci/{host => controller}/pci-imx6.c        |    0
 drivers/pci/{host => controller}/pci-keystone-dw.c |    0
 drivers/pci/{host => controller}/pci-keystone.c    |    0
 drivers/pci/{host => controller}/pci-keystone.h    |    0
 drivers/pci/{host => controller}/pci-layerscape.c  |    0
 drivers/pci/{host => controller}/pci-mvebu.c       |    0
 drivers/pci/{host => controller}/pci-rcar-gen2.c   |    0
 drivers/pci/{host => controller}/pci-tegra.c       |    0
 .../pci/{host => controller}/pci-thunder-ecam.c    |    0
 drivers/pci/{host => controller}/pci-thunder-pem.c |    0
 drivers/pci/{host => controller}/pci-versatile.c   |    0
 drivers/pci/{host => controller}/pci-xgene-msi.c   |    0
 drivers/pci/{host => controller}/pci-xgene.c       |    0
 drivers/pci/{host => controller}/pcie-altera-msi.c |    0
 drivers/pci/{host => controller}/pcie-altera.c     |    0
 drivers/pci/{host => controller}/pcie-armada8k.c   |    0
 drivers/pci/{host => controller}/pcie-artpec6.c    |    0
 drivers/pci/controller/pcie-designware-ep.c        |  228 ++++++++++++
 .../pcie-designware-host.c}                        |  294 +++------------
 .../{host => controller}/pcie-designware-plat.c    |    0
 drivers/pci/controller/pcie-designware.c           |  233 ++++++++++++
 drivers/pci/controller/pcie-designware.h           |  238 ++++++++++++
 drivers/pci/{host => controller}/pcie-hisi.c       |    0
 drivers/pci/{host => controller}/pcie-iproc-bcma.c |    0
 drivers/pci/{host => controller}/pcie-iproc-msi.c  |    0
 .../pci/{host => controller}/pcie-iproc-platform.c |    0
 drivers/pci/{host => controller}/pcie-iproc.c      |    0
 drivers/pci/{host => controller}/pcie-iproc.h      |    0
 drivers/pci/{host => controller}/pcie-qcom.c       |    0
 drivers/pci/{host => controller}/pcie-rcar.c       |    0
 drivers/pci/{host => controller}/pcie-spear13xx.c  |    0
 drivers/pci/{host => controller}/pcie-xilinx-nwl.c |    0
 drivers/pci/{host => controller}/pcie-xilinx.c     |    0
 drivers/pci/endpoint/Kconfig                       |   25 ++
 drivers/pci/endpoint/Makefile                      |    6 +
 drivers/pci/endpoint/functions/Kconfig             |   12 +
 drivers/pci/endpoint/functions/Makefile            |    5 +
 drivers/pci/endpoint/functions/pci-epf-test.c      |  272 ++++++++++++++
 drivers/pci/endpoint/pci-ep-cfs.c                  |  275 ++++++++++++++
 drivers/pci/endpoint/pci-epc-core.c                |  389 ++++++++++++++++++++
 drivers/pci/endpoint/pci-epf-core.c                |  338 +++++++++++++++++
 drivers/pci/host/pcie-designware.h                 |   89 -----
 include/linux/mod_devicetable.h                    |   10 +
 include/linux/pci-epc.h                            |  100 +++++
 include/linux/pci-epf.h                            |  159 ++++++++
 66 files changed, 3373 insertions(+), 492 deletions(-)
 create mode 100644 Documentation/PCI/pci-endpoint.txt
 create mode 100644 Documentation/PCI/pci-test.txt
 create mode 100644 drivers/misc/pci_endpoint_test.c
 rename drivers/pci/{host => controller}/Kconfig (79%)
 rename drivers/pci/{host => controller}/Makefile (93%)
 rename drivers/pci/{host => controller}/pci-aardvark.c (100%)
 rename drivers/pci/{host => controller}/pci-dra7xx.c (62%)
 rename drivers/pci/{host => controller}/pci-exynos.c (100%)
 rename drivers/pci/{host => controller}/pci-host-common.c (100%)
 rename drivers/pci/{host => controller}/pci-host-generic.c (100%)
 rename drivers/pci/{host => controller}/pci-hyperv.c (100%)
 rename drivers/pci/{host => controller}/pci-imx6.c (100%)
 rename drivers/pci/{host => controller}/pci-keystone-dw.c (100%)
 rename drivers/pci/{host => controller}/pci-keystone.c (100%)
 rename drivers/pci/{host => controller}/pci-keystone.h (100%)
 rename drivers/pci/{host => controller}/pci-layerscape.c (100%)
 rename drivers/pci/{host => controller}/pci-mvebu.c (100%)
 rename drivers/pci/{host => controller}/pci-rcar-gen2.c (100%)
 rename drivers/pci/{host => controller}/pci-tegra.c (100%)
 rename drivers/pci/{host => controller}/pci-thunder-ecam.c (100%)
 rename drivers/pci/{host => controller}/pci-thunder-pem.c (100%)
 rename drivers/pci/{host => controller}/pci-versatile.c (100%)
 rename drivers/pci/{host => controller}/pci-xgene-msi.c (100%)
 rename drivers/pci/{host => controller}/pci-xgene.c (100%)
 rename drivers/pci/{host => controller}/pcie-altera-msi.c (100%)
 rename drivers/pci/{host => controller}/pcie-altera.c (100%)
 rename drivers/pci/{host => controller}/pcie-armada8k.c (100%)
 rename drivers/pci/{host => controller}/pcie-artpec6.c (100%)
 create mode 100644 drivers/pci/controller/pcie-designware-ep.c
 rename drivers/pci/{host/pcie-designware.c => controller/pcie-designware-host.c} (64%)
 rename drivers/pci/{host => controller}/pcie-designware-plat.c (100%)
 create mode 100644 drivers/pci/controller/pcie-designware.c
 create mode 100644 drivers/pci/controller/pcie-designware.h
 rename drivers/pci/{host => controller}/pcie-hisi.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc-bcma.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc-msi.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc-platform.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc.h (100%)
 rename drivers/pci/{host => controller}/pcie-qcom.c (100%)
 rename drivers/pci/{host => controller}/pcie-rcar.c (100%)
 rename drivers/pci/{host => controller}/pcie-spear13xx.c (100%)
 rename drivers/pci/{host => controller}/pcie-xilinx-nwl.c (100%)
 rename drivers/pci/{host => controller}/pcie-xilinx.c (100%)
 create mode 100644 drivers/pci/endpoint/Kconfig
 create mode 100644 drivers/pci/endpoint/Makefile
 create mode 100644 drivers/pci/endpoint/functions/Kconfig
 create mode 100644 drivers/pci/endpoint/functions/Makefile
 create mode 100644 drivers/pci/endpoint/functions/pci-epf-test.c
 create mode 100644 drivers/pci/endpoint/pci-ep-cfs.c
 create mode 100644 drivers/pci/endpoint/pci-epc-core.c
 create mode 100644 drivers/pci/endpoint/pci-epf-core.c
 delete mode 100644 drivers/pci/host/pcie-designware.h
 create mode 100644 include/linux/pci-epc.h
 create mode 100644 include/linux/pci-epf.h

-- 
1.7.9.5

[toc] | [next] | [standalone]


#1482931 — [RFC PATCH 09/11] misc: add a new host side PCI endpoint test driver

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-14 07:20 +0200
Subject[RFC PATCH 09/11] misc: add a new host side PCI endpoint test driver
Message-ID<shaM1-4De-13@gated-at.bofh.it>
In reply to#1482930
Add PCI endpoint test driver that can verify base address
register and legacy interrupt. (TODO: buffer tests and
MSI interrupt). The corresponding pci-epf-test function driver
should be used on the EP side.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/misc/Kconfig             |    7 +
 drivers/misc/Makefile            |    1 +
 drivers/misc/pci_endpoint_test.c |  291 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 299 insertions(+)
 create mode 100644 drivers/misc/pci_endpoint_test.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index d002528..c578f97 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -794,6 +794,13 @@ config PANEL_BOOT_MESSAGE
 	  An empty message will only clear the display at driver init time. Any other
 	  printf()-formatted message is valid with newline and escape codes.
 
+config PCI_ENDPOINT_TEST
+	depends on PCI
+	tristate "PCI Endpoint Test driver"
+	---help---
+           Enable this configuration option to enable the host side test driver
+           for PCI Endpoint.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index fb32516..fe6ff69 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PANEL)             += panel.o
+obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
new file mode 100644
index 0000000..221a2ce
--- /dev/null
+++ b/drivers/misc/pci_endpoint_test.c
@@ -0,0 +1,291 @@
+/**
+ * ep_f_test.c - Host side test driver to test endpoint functionality
+ *
+ * Copyright (C) 2016 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@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 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <linux/pci_regs.h>
+
+#define DRV_MODULE_NAME			"pci-endpoint-test"
+
+#define PCI_ENDPOINT_TEST_COMMAND	0x0
+#define COMMAND_RESET			BIT(0)
+#define COMMAND_RAISE_IRQ		BIT(1)
+#define COMMAND_COPY			BIT(2)
+
+#define PCI_ENDPOINT_TEST_STATUS	0x4
+#define STATUS_INITIALIZED		BIT(0)
+#define STATUS_COPY_PROGRESS		BIT(1)
+#define STATUS_COPY_DONE		BIT(2)
+#define STATUS_IRQ_RAISED		BIT(3)
+#define STATUS_SOURCE_ADDR_INVALID	BIT(4)
+#define STATUS_DEST_ADDR_INVALID	BIT(5)
+
+#define PCI_ENDPOINT_TEST_SRC_ADDR	0x8
+#define PCI_ENDPOINT_TEST_DST_ADDR	0x10
+
+enum pci_barno {
+	BAR_0,
+	BAR_1,
+	BAR_2,
+	BAR_3,
+	BAR_4,
+	BAR_5,
+};
+
+struct pci_endpoint_test {
+	struct pci_dev	*pdev;
+	void		*base;
+	void		*bar[5];
+	struct completion irq_raised;
+};
+
+static char *result[] = { "NOT OKAY", "OKAY" };
+static int bar_size[] = { 512, 1024, 16384, 131072, 1048576 };
+
+static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
+					  u32 offset)
+{
+	return readl(test->base + offset);
+}
+
+static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test,
+					    u32 offset, u32 value)
+{
+	writel(value, test->base + offset);
+}
+
+static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test,
+					      int bar, int offset)
+{
+	return readl(test->bar[bar] + offset);
+}
+
+static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test,
+						int bar, u32 offset, u32 value)
+{
+	writel(value, test->bar[bar] + offset);
+}
+
+static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
+{
+	struct pci_endpoint_test *test = dev_id;
+	u32 reg;
+
+	reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+	if (reg & STATUS_IRQ_RAISED) {
+		complete(&test->irq_raised);
+		reg &= ~STATUS_IRQ_RAISED;
+	}
+	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS,
+				 reg);
+
+	return IRQ_HANDLED;
+}
+
+static bool pci_endpoint_test_reset(struct pci_endpoint_test *test)
+{
+	int i;
+	u32 val;
+
+	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+				 COMMAND_RESET);
+	for (i = 0; i < 5; i++) {
+		val = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+		if (val & STATUS_INITIALIZED)
+			return true;
+		usleep_range(100, 200);
+	}
+
+	return false;
+}
+
+static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
+				  enum pci_barno barno)
+{
+	int j;
+	u32 val;
+	int size;
+
+	if (!test->bar[barno - 1])
+		return false;
+
+	size = bar_size[barno - 1];
+
+	for (j = 0; j < size; j += 4)
+		pci_endpoint_test_bar_writel(test, barno - 1, j, 0xA0A0A0A0);
+
+	for (j = 0; j < size; j += 4) {
+		val = pci_endpoint_test_bar_readl(test, barno - 1, j);
+		if (val != 0xA0A0A0A0)
+			return false;
+	}
+
+	return true;
+}
+
+static bool pci_endpoint_test_irq(struct pci_endpoint_test *test)
+{
+	u32 val;
+
+	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+				 COMMAND_RAISE_IRQ);
+	val = wait_for_completion_timeout(&test->irq_raised,
+					  msecs_to_jiffies(1000));
+	if (!val)
+		return false;
+
+	return true;
+}
+
+static int pci_endpoint_test_begin(struct pci_endpoint_test *test)
+{
+	bool ret;
+	enum pci_barno bar;
+
+	pr_info("****** Testing pci-endpoint-test Device ******\n");
+
+	ret = pci_endpoint_test_reset(test);
+	pr_info("Reset: %s\n", result[ret]);
+
+	for (bar = BAR_1; bar <= BAR_5; bar++) {
+		ret = pci_endpoint_test_bar(test, bar);
+		pr_info("BAR%d %s\n", bar, result[ret]);
+	}
+
+	ret = pci_endpoint_test_irq(test);
+	pr_info("Legacy IRQ: %s\n", result[ret]);
+
+	pr_info("****** End Test ******\n");
+
+	return 0;
+}
+
+static int pci_endpoint_test_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *ent)
+{
+	int err;
+	enum pci_barno bar;
+	void __iomem *base;
+	struct device *dev = &pdev->dev;
+	struct pci_endpoint_test *test;
+
+	if (pci_is_bridge(pdev))
+		return -ENODEV;
+
+	test = devm_kzalloc(dev, sizeof(*test), GFP_KERNEL);
+	if (!test)
+		return -ENOMEM;
+
+	test->pdev = pdev;
+	init_completion(&test->irq_raised);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(dev, "Cannot enable PCI device\n");
+		return err;
+	}
+
+	err = pci_request_regions(pdev, DRV_MODULE_NAME);
+	if (err) {
+		dev_err(dev, "Cannot obtain PCI resources\n");
+		goto err_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	base = pci_ioremap_bar(pdev, BAR_0);
+	if (!base) {
+		dev_err(dev, "Cannot map test device registers\n");
+		err = -ENOMEM;
+		goto err_release_region;
+	}
+
+	test->base = base;
+
+	err = request_irq(pdev->irq, pci_endpoint_test_irqhandler, IRQF_SHARED,
+			  DRV_MODULE_NAME, test);
+	if (err) {
+		dev_err(dev, "failed to request irq\n");
+		goto err_iounmap;
+	}
+
+	for (bar = BAR_1; bar <= BAR_5; bar++) {
+		base = pci_ioremap_bar(pdev, bar);
+		if (!base)
+			dev_err(dev, "failed to read BAR%d\n", bar);
+		test->bar[bar - 1] = base;
+	}
+
+	pci_set_drvdata(pdev, test);
+	pci_endpoint_test_begin(test);
+
+	return 0;
+
+err_iounmap:
+	iounmap(test->base);
+
+err_release_region:
+	pci_release_regions(pdev);
+
+err_disable_pdev:
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+static void pci_endpoint_test_remove(struct pci_dev *pdev)
+{
+	struct pci_endpoint_test *test = pci_get_drvdata(pdev);
+	enum pci_barno bar;
+
+	iounmap(test->base);
+
+	for (bar = BAR_1; bar <= BAR_5; bar++) {
+		if (test->bar[bar - 1])
+			iounmap(test->bar[bar - 1]);
+	}
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static const struct pci_device_id pci_endpoint_test_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_ANY_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
+
+static struct pci_driver pci_endpoint_test_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= pci_endpoint_test_tbl,
+	.probe		= pci_endpoint_test_probe,
+	.remove		= pci_endpoint_test_remove,
+};
+module_pci_driver(pci_endpoint_test_driver);
+
+MODULE_DESCRIPTION("PCI ENDPOINT TEST DRIVER");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

[toc] | [prev] | [next] | [standalone]


#1482932 — [RFC PATCH 01/11] pci: endpoint: add EP core layer to enable EP controller and EP functions

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-14 07:20 +0200
Subject[RFC PATCH 01/11] pci: endpoint: add EP core layer to enable EP controller and EP functions
Message-ID<shaM1-4De-1@gated-at.bofh.it>
In reply to#1482930
Introduce a new EP core layer in order to support endpoint functions
in linux kernel. This comprises of EPC library
(Endpoint Controller Library) and EPF library (Endpoint
Function Library). EPC library implements functions that is specific
to an endpoint controller and EPF library implements functions
that is specific to an endpoint function.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/Makefile                    |    1 +
 drivers/pci/Kconfig                 |    1 +
 drivers/pci/endpoint/Kconfig        |   21 ++
 drivers/pci/endpoint/Makefile       |    5 +
 drivers/pci/endpoint/pci-epc-core.c |  389 +++++++++++++++++++++++++++++++++++
 drivers/pci/endpoint/pci-epf-core.c |  338 ++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h     |   10 +
 include/linux/pci-epc.h             |  100 +++++++++
 include/linux/pci-epf.h             |  159 ++++++++++++++
 9 files changed, 1024 insertions(+)
 create mode 100644 drivers/pci/endpoint/Kconfig
 create mode 100644 drivers/pci/endpoint/Makefile
 create mode 100644 drivers/pci/endpoint/pci-epc-core.c
 create mode 100644 drivers/pci/endpoint/pci-epf-core.c
 create mode 100644 include/linux/pci-epc.h
 create mode 100644 include/linux/pci-epf.h

diff --git a/drivers/Makefile b/drivers/Makefile
index 53abb4a..8c070ad 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_GENERIC_PHY)	+= phy/
 obj-$(CONFIG_PINCTRL)		+= pinctrl/
 obj-$(CONFIG_GPIOLIB)		+= gpio/
 obj-y				+= pwm/
+obj-$(CONFIG_PCI_ENDPOINT)	+= pci/endpoint/
 obj-$(CONFIG_PCI)		+= pci/
 obj-$(CONFIG_PARISC)		+= parisc/
 obj-$(CONFIG_RAPIDIO)		+= rapidio/
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 67f9916..5f116a6 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -133,3 +133,4 @@ config PCI_HYPERV
 
 source "drivers/pci/hotplug/Kconfig"
 source "drivers/pci/host/Kconfig"
+source "drivers/pci/endpoint/Kconfig"
diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
new file mode 100644
index 0000000..a6d827c
--- /dev/null
+++ b/drivers/pci/endpoint/Kconfig
@@ -0,0 +1,21 @@
+#
+# PCI Endpoint Support
+#
+
+menu "PCI Endpoint"
+
+config PCI_ENDPOINT
+	tristate "PCI Endpoint Support"
+	help
+	   Enable this configuration option to support configurable PCI
+	   endpoint. This should be enabled if the platform has a PCI
+	   controller that can operate in endpoint mode.
+
+	   Enabling this option will build the endpoint library, which
+	   includes endpoint controller library and endpoint function
+	   library.
+
+	   If in doubt, say "N" to disable Endpoint support.
+
+endmenu
+
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
new file mode 100644
index 0000000..dbc5517
--- /dev/null
+++ b/drivers/pci/endpoint/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for PCI Endpoint Support
+#
+
+obj-$(CONFIG_PCI_ENDPOINT)		:= pci-epc-core.o pci-epf-core.o
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
new file mode 100644
index 0000000..003d2ee
--- /dev/null
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -0,0 +1,389 @@
+/**
+ * pci-epc-core.c - PCI Endpoint *Controller* (EPC) library
+ *
+ * Copyright (C) 2016 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@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 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
+static struct class *pci_epc_class;
+
+static void devm_pci_epc_release(struct device *dev, void *res)
+{
+	struct pci_epc *epc = *(struct pci_epc **)res;
+
+	pci_epc_destroy(epc);
+}
+
+static int devm_pci_epc_match(struct device *dev, void *res, void *match_data)
+{
+	struct pci_epc **epc = res;
+
+	return *epc == match_data;
+}
+
+/**
+ * pci_epc_unbind_epf() - unbind the endpoint function and endpoint controller
+ * @epf: the endpoint function which has requested for unbinding
+ *
+ * Invoke to unbind the endpoint function and endpoint controller
+ */
+void pci_epc_unbind_epf(struct pci_epf *epf)
+{
+	struct pci_epc *epc = epf->epc;
+
+	pci_epf_unbind(epf);
+	module_put(epc->ops->owner);
+	epf->epc = NULL;
+	epc->epf = NULL;
+}
+EXPORT_SYMBOL_GPL(pci_epc_unbind_epf);
+
+/**
+ * pci_epc_bind_epf() - bind the endpoint function with an endpoint controller
+ * @epf: endpoint function which has to be bound to an endpoint controller
+ *
+ * Invoke to bind the endpoint function with an endpoint controller based on
+ * pci_epc_name.
+ */
+int pci_epc_bind_epf(struct pci_epf *epf)
+{
+	int ret = -EINVAL;
+	struct pci_epc *epc;
+	struct device *dev;
+	struct class_dev_iter iter;
+
+	class_dev_iter_init(&iter, pci_epc_class, NULL, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
+		if (strcmp(epf->pci_epc_name, dev_name(dev)))
+			continue;
+
+		epc = to_pci_epc(dev);
+		if (epc->epf) {
+			ret = -EBUSY;
+			goto err;
+		}
+
+		if (!try_module_get(epc->ops->owner)) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		epf->epc = epc;
+		epc->epf = epf;
+
+		dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask);
+		epf->dev.dma_mask = epc->dev.dma_mask;
+
+		pci_epf_bind(epf);
+		class_dev_iter_exit(&iter);
+		return 0;
+	}
+
+err:
+	class_dev_iter_exit(&iter);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_bind_epf);
+
+/**
+ * pci_epc_stop() - stop the PCI link
+ * @epc: the link of the EPC device that has to be stopped
+ *
+ * Invoke to stop the PCI link
+ */
+void pci_epc_stop(struct pci_epc *epc)
+{
+	if (IS_ERR(epc) || !epc->ops->stop)
+		return;
+
+	spin_lock_irq(&epc->irq_lock);
+	epc->ops->stop(epc);
+	spin_unlock_irq(&epc->irq_lock);
+}
+EXPORT_SYMBOL_GPL(pci_epc_stop);
+
+/**
+ * pci_epc_start() - start the PCI link
+ * @epc: the link of the EPC device that has to be started
+ *
+ * Invoke to start the PCI link
+ */
+int pci_epc_start(struct pci_epc *epc)
+{
+	int ret;
+
+	if (IS_ERR(epc))
+		return -EINVAL;
+
+	if (!epc->ops->start)
+		return 0;
+
+	spin_lock_irq(&epc->irq_lock);
+	ret = epc->ops->start(epc);
+	spin_unlock_irq(&epc->irq_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_start);
+
+/**
+ * pci_epc_raise_irq() - interrupt the host system
+ * @epc: the EPC device which has to interrupt the host
+ * @type: specify the type of interrupt; legacy or MSI
+ *
+ * Invoke to raise an MSI or legacy interrupt
+ */
+int pci_epc_raise_irq(struct pci_epc *epc, enum pci_epc_irq_type type)
+{
+	int ret;
+
+	if (IS_ERR(epc))
+		return -EINVAL;
+
+	if (!epc->ops->raise_irq)
+		return 0;
+
+	spin_lock_irq(&epc->irq_lock);
+	ret = epc->ops->raise_irq(epc, type);
+	spin_unlock_irq(&epc->irq_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_raise_irq);
+
+/**
+ * pci_epc_clear_bar() - reset the BAR
+ * @epc: the EPC device for which the BAR has to be cleared
+ * @bar: the bar number that has to be reset
+ *
+ * Invoke to reset the BAR of the endpoint device.
+ */
+void pci_epc_clear_bar(struct pci_epc *epc, int bar)
+{
+	if (IS_ERR(epc))
+		return;
+
+	if (!epc->ops->clear_bar)
+		return;
+
+	spin_lock_irq(&epc->irq_lock);
+	epc->ops->clear_bar(epc, bar);
+	spin_unlock_irq(&epc->irq_lock);
+}
+EXPORT_SYMBOL_GPL(pci_epc_clear_bar);
+
+/**
+ * pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space
+ * @epc: the EPC device on which BAR has to be configured
+ * @bar: the bar number that has to be configured
+ * @size: the size of the addr space
+ * @flags: specify memory allocation/io allocation/32bit address/64 bit address
+ *
+ * Invoke to configure the BAR of the endpoint device.
+ */
+int pci_epc_set_bar(struct pci_epc *epc, enum pci_barno bar,
+		    dma_addr_t bar_phys, size_t size, int flags)
+{
+	int ret;
+
+	if (IS_ERR(epc))
+		return -EINVAL;
+
+	if (!epc->ops->set_bar)
+		return 0;
+
+	spin_lock_irq(&epc->irq_lock);
+	ret = epc->ops->set_bar(epc, bar, bar_phys, size, flags);
+	spin_unlock_irq(&epc->irq_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_set_bar);
+
+/**
+ * pci_epc_write_header() - write standard configuration header
+ * @epc: the EPC device to which the configuration header should be written
+ * @header: standard configuration header fields
+ *
+ * Invoke to write the configuration header to the endpoint controller. Every
+ * endpoint controller will have a dedicated location to which the standard
+ * configuration header would be written. The callback function should write
+ * the header fields to this dedicated location.
+ */
+int pci_epc_write_header(struct pci_epc *epc, struct pci_epf_header *header)
+{
+	int ret;
+
+	if (IS_ERR(epc))
+		return -EINVAL;
+
+	if (!epc->ops->write_header)
+		return 0;
+
+	spin_lock_irq(&epc->irq_lock);
+	ret = epc->ops->write_header(epc, header);
+	spin_unlock_irq(&epc->irq_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_write_header);
+
+/**
+ * pci_epc_destroy() - destroy the EPC device
+ * @epc: the EPC device that has to be destroyed
+ *
+ * Invoke to destroy the PCI EPC device
+ */
+void pci_epc_destroy(struct pci_epc *epc)
+{
+	device_unregister(&epc->dev);
+	kfree(epc);
+}
+EXPORT_SYMBOL_GPL(pci_epc_destroy);
+
+/**
+ * devm_pci_epc_destroy() - destroy the EPC device
+ * @dev: device that wants to destroy the EPC
+ * @epc: the EPC device that has to be destroyed
+ *
+ * Invoke to destroy the devres associated with this
+ * pci_epc and destroy the EPC device.
+ */
+void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc)
+{
+	int r;
+
+	r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match,
+			   epc);
+	dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n");
+}
+EXPORT_SYMBOL_GPL(devm_pci_epc_destroy);
+
+/**
+ * __pci_epc_create() - create a new endpoint controller (EPC) device
+ * @dev: device that is creating the new EPC
+ * @ops: function pointers for performing EPC operations
+ * @owner: the owner of the module that creates the EPC device
+ *
+ * Invoke to create a new EPC device and add it to pci_epc class.
+ */
+struct pci_epc *
+__pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
+		 struct module *owner)
+{
+	int ret;
+	struct pci_epc *epc;
+
+	if (WARN_ON(!dev)) {
+		ret = -EINVAL;
+		goto err_ret;
+	}
+
+	epc = kzalloc(sizeof(*epc), GFP_KERNEL);
+	if (!epc) {
+		ret = -ENOMEM;
+		goto err_ret;
+	}
+
+	spin_lock_init(&epc->irq_lock);
+
+	device_initialize(&epc->dev);
+	dma_set_coherent_mask(&epc->dev, dev->coherent_dma_mask);
+	epc->dev.class = pci_epc_class;
+	epc->dev.dma_mask = dev->dma_mask;
+	epc->ops = ops;
+
+	ret = dev_set_name(&epc->dev, "%s", dev_name(dev));
+	if (ret)
+		goto put_dev;
+
+	ret = device_add(&epc->dev);
+	if (ret)
+		goto put_dev;
+
+	return epc;
+
+put_dev:
+	put_device(&epc->dev);
+	kfree(epc);
+
+err_ret:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(__pci_epc_create);
+
+/**
+ * __devm_pci_epc_create() - create a new endpoint controller (EPC) device
+ * @dev: device that is creating the new EPC
+ * @ops: function pointers for performing EPC operations
+ * @owner: the owner of the module that creates the EPC device
+ *
+ * Invoke to create a new EPC device and add it to pci_epc class.
+ * While at that, it also associates the device with the pci_epc using devres.
+ * On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct pci_epc *
+__devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
+		      struct module *owner)
+{
+	struct pci_epc **ptr, *epc;
+
+	ptr = devres_alloc(devm_pci_epc_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	epc = __pci_epc_create(dev, ops, owner);
+	if (!IS_ERR(epc)) {
+		*ptr = epc;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return epc;
+}
+EXPORT_SYMBOL_GPL(__devm_pci_epc_create);
+
+static int __init pci_epc_init(void)
+{
+	pci_epc_class = class_create(THIS_MODULE, "pci_epc");
+	if (IS_ERR(pci_epc_class)) {
+		pr_err("failed to create pci epc class --> %ld\n",
+		       PTR_ERR(pci_epc_class));
+		return PTR_ERR(pci_epc_class);
+	}
+
+	return 0;
+}
+module_init(pci_epc_init);
+
+static void __exit pci_epc_exit(void)
+{
+	class_destroy(pci_epc_class);
+}
+module_exit(pci_epc_exit);
+
+MODULE_DESCRIPTION("PCI EPC Library");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
new file mode 100644
index 0000000..2802267
--- /dev/null
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -0,0 +1,338 @@
+/**
+ * pci-epf-core.c - PCI Endpoint *Function* (EPF) library
+ *
+ * Copyright (C) 2016 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@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 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
+static struct bus_type pci_epf_bus_type;
+static struct device_type pci_epf_type;
+
+/**
+ * pci_epf_linkup() - Notify the function driver that EPC device has
+ *		      established a connection with the Root Complex.
+ * @epf: the EPF device bound to the EPC device which has established
+ *	 the connection with the host
+ *
+ * Invoke to notify the function driver that EPC device has established
+ * a connection with the Root Complex.
+ */
+void pci_epf_linkup(struct pci_epf *epf)
+{
+	epf->driver->ops->linkup(epf);
+}
+EXPORT_SYMBOL_GPL(pci_epf_linkup);
+
+/**
+ * pci_epf_unbind() - Notify the function driver that the binding between the
+ *		      EPF device and EPC device has been lost
+ * @epf: the EPF device which has lost the binding with the EPC device
+ *
+ * Invoke to notify the function driver that the binding between the EPF device
+ * and EPC device has been lost.
+ */
+void pci_epf_unbind(struct pci_epf *epf)
+{
+	epf->driver->ops->unbind(epf);
+	module_put(epf->driver->owner);
+}
+EXPORT_SYMBOL_GPL(pci_epf_unbind);
+
+/**
+ * pci_epf_bind() - Notify the function driver that the EPF device has been
+ *		    bound to a EPC device
+ * @epf: the EPF device which has been bound to the EPC device
+ *
+ * Invoke to notify the function driver that it has been bound to a EPC device
+ */
+int pci_epf_bind(struct pci_epf *epf)
+{
+	if (!try_module_get(epf->driver->owner))
+		return -EAGAIN;
+
+	return epf->driver->ops->bind(epf);
+}
+EXPORT_SYMBOL_GPL(pci_epf_bind);
+
+/**
+ * pci_epf_free_space() - free the allocated PCI EPF register space
+ * @addr: the virtual address of the PCI EPF register space
+ * @bar: the bar number corresponding to the register space
+ *
+ * Invoke to free the allocated PCI EPF register space.
+ */
+void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar)
+{
+	struct device *dev = &epf->dev;
+
+	if (!addr)
+		return;
+
+	dma_free_coherent(dev, epf->bar[bar].size, addr,
+			  epf->bar[bar].phys_addr);
+
+	epf->bar[bar].phys_addr = 0;
+	epf->bar[bar].size = 0;
+}
+EXPORT_SYMBOL_GPL(pci_epf_free_space);
+
+/**
+ * pci_epf_alloc_space() - allocate memory for the PCI EPF register space
+ * @size: the size of the memory that has to be allocated
+ * @bar: the bar number corresponding to the allocated register space
+ *
+ * Invoke to allocate memory for the PCI EPF register space.
+ */
+void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
+{
+	void *space;
+	struct device *dev = &epf->dev;
+	dma_addr_t phys_addr;
+
+	if (size < 128)
+		size = 128;
+	size = roundup_pow_of_two(size);
+
+	space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
+	if (!space) {
+		dev_err(dev, "failed to allocate mem space\n");
+		return NULL;
+	}
+
+	epf->bar[bar].phys_addr = phys_addr;
+	epf->bar[bar].size = size;
+
+	return space;
+}
+EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
+
+/**
+ * pci_epf_unregister_driver() - unregister the PCI EPF driver
+ * @driver: the PCI EPF driver that has to be unregistered
+ *
+ * Invoke to unregister the PCI EPF driver.
+ */
+void pci_epf_unregister_driver(struct pci_epf_driver *driver)
+{
+	driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(pci_epf_unregister_driver);
+
+/**
+ * __pci_epf_register_driver() - register a new PCI EPF driver
+ * @driver: structure representing PCI EPF driver
+ * @owner: the owner of the module that registers the PCI EPF driver
+ *
+ * Invoke to register a new PCI EPF driver.
+ */
+int __pci_epf_register_driver(struct pci_epf_driver *driver,
+			      struct module *owner)
+{
+	int ret;
+
+	if (!driver->ops)
+		return -EINVAL;
+
+	if (!driver->ops->bind || !driver->ops->unbind || !driver->ops->linkup)
+		return -EINVAL;
+
+	driver->driver.bus = &pci_epf_bus_type;
+	driver->driver.owner = owner;
+
+	ret = driver_register(&driver->driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__pci_epf_register_driver);
+
+/**
+ * pci_epf_destroy() - destroy the created PCI EPF device
+ * @epf: the PCI EPF device that has to be destroyed.
+ *
+ * Invoke to destroy the PCI EPF device created by invoking pci_epf_create().
+ */
+void pci_epf_destroy(struct pci_epf *epf)
+{
+	device_unregister(&epf->dev);
+}
+EXPORT_SYMBOL_GPL(pci_epf_destroy);
+
+/**
+ * pci_epf_create() - create a new PCI EPF device
+ * @name: the name of the PCI EPF device. This name will be used to bind the
+ *	  the EPF device to a EPF driver
+ *
+ * Invoke to create a new PCI EPF device by providing the name of the function
+ * device.
+ */
+struct pci_epf *pci_epf_create(const char *name)
+{
+	int ret;
+	struct pci_epf *epf;
+	struct device *dev;
+	char *func_name;
+	char *buf;
+
+	epf = kzalloc(sizeof(*epf), GFP_KERNEL);
+	if (!epf) {
+		ret = -ENOMEM;
+		goto err_ret;
+	}
+
+	buf = kstrdup(name, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto free_epf;
+	}
+
+	func_name = buf;
+	buf = strchrnul(buf, '.');
+	*buf = '\0';
+
+	epf->name = kstrdup(func_name, GFP_KERNEL);
+	if (!epf->name) {
+		ret = -ENOMEM;
+		goto free_epf;
+	}
+
+	dev = &epf->dev;
+	device_initialize(dev);
+	dev->bus = &pci_epf_bus_type;
+	dev->type = &pci_epf_type;
+
+	ret = dev_set_name(dev, "%s", name);
+	if (ret)
+		goto put_dev;
+
+	ret = device_add(dev);
+	if (ret)
+		goto put_dev;
+
+	kfree(func_name);
+	return epf;
+
+put_dev:
+	put_device(dev);
+	kfree(epf->name);
+	kfree(func_name);
+
+free_epf:
+	kfree(epf);
+
+err_ret:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(pci_epf_create);
+
+static void pci_epf_dev_release(struct device *dev)
+{
+	struct pci_epf *epf = to_pci_epf(dev);
+
+	kfree(epf->name);
+	kfree(epf);
+}
+
+static struct device_type pci_epf_type = {
+	.release	= pci_epf_dev_release,
+};
+
+static const struct pci_epf_device_id *
+pci_epf_match_id(const struct pci_epf_device_id *id, const struct pci_epf *epf)
+{
+	while (id->name[0]) {
+		if (strcmp(epf->name, id->name) == 0)
+			return id;
+		id++;
+	}
+
+	return NULL;
+}
+
+static int pci_epf_device_match(struct device *dev, struct device_driver *drv)
+{
+	struct pci_epf *epf = to_pci_epf(dev);
+	struct pci_epf_driver *driver = to_pci_epf_driver(drv);
+
+	if (driver->id_table)
+		return pci_epf_match_id(driver->id_table, epf) != NULL;
+
+	return !strcmp(epf->name, drv->name);
+}
+
+static int pci_epf_device_probe(struct device *dev)
+{
+	struct pci_epf *epf = to_pci_epf(dev);
+	struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver);
+
+	if (!driver->probe)
+		return -ENODEV;
+
+	epf->driver = driver;
+
+	return driver->probe(epf);
+}
+
+static int pci_epf_device_remove(struct device *dev)
+{
+	int ret;
+	struct pci_epf *epf = to_pci_epf(dev);
+	struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver);
+
+	ret = driver->remove(epf);
+	epf->driver = NULL;
+
+	return ret;
+}
+
+static struct bus_type pci_epf_bus_type = {
+	.name		= "pci-epf",
+	.match		= pci_epf_device_match,
+	.probe		= pci_epf_device_probe,
+	.remove		= pci_epf_device_remove,
+};
+
+static int __init pci_epf_init(void)
+{
+	int ret;
+
+	ret = bus_register(&pci_epf_bus_type);
+	if (ret) {
+		pr_err("failed to register pci epf bus --> %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+module_init(pci_epf_init);
+
+static void __exit pci_epf_exit(void)
+{
+	bus_unregister(&pci_epf_bus_type);
+}
+module_exit(pci_epf_exit);
+
+MODULE_DESCRIPTION("PCI EPF Library");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index ed84c07..946cef1 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -427,6 +427,16 @@ struct i2c_device_id {
 	kernel_ulong_t driver_data;	/* Data private to the driver */
 };
 
+/* pci_epf */
+
+#define PCI_EPF_NAME_SIZE	20
+#define PCI_EPF_MODULE_PREFIX	"pci_epf:"
+
+struct pci_epf_device_id {
+	char name[PCI_EPF_NAME_SIZE];
+	kernel_ulong_t driver_data;
+};
+
 /* spi */
 
 #define SPI_NAME_SIZE	32
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
new file mode 100644
index 0000000..78e4178
--- /dev/null
+++ b/include/linux/pci-epc.h
@@ -0,0 +1,100 @@
+/**
+ * pci-epc.h - PCI Endpoint *Controller* (EPC) header file
+ *
+ * Copyright (C) 2016 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@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 of
+ * the License as published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_PCI_EPC_H
+#define __DRIVERS_PCI_EPC_H
+
+#include <linux/pci-epf.h>
+
+struct pci_epc;
+
+enum pci_epc_irq_type {
+	PCI_EPC_IRQ_UNKNOWN,
+	PCI_EPC_IRQ_LEGACY,
+	PCI_EPC_IRQ_MSI,
+};
+
+/**
+ * struct pci_epc_ops - set of function pointers for performing EPC operations
+ * @write_header: ops to populate configuration space header
+ * @set_bar: ops to configure the BAR
+ * @clear_bar: ops to reset the BAR
+ * @alloc_addr_space: ops to allocate *in* PCI controller address space
+ * @free_addr_space: ops to free the allocated address space
+ * @raise_irq: ops to raise a legacy or MSI interrupt
+ * @start: ops to start the PCI link
+ * @stop: ops to stop the PCI link
+ * @owner: the module owner containing the ops
+ */
+struct pci_epc_ops {
+	int	(*write_header)(struct pci_epc *pci_epc,
+				struct pci_epf_header *hdr);
+	int	(*set_bar)(struct pci_epc *epc, enum pci_barno bar,
+			   dma_addr_t bar_phys, size_t size, int flags);
+	void	(*clear_bar)(struct pci_epc *epc, enum pci_barno bar);
+	void	*(*alloc_addr_space)(struct pci_epc *pci_epc, size_t size);
+	void	(*free_addr_space)(struct pci_epc *pci_epc);
+	int	(*raise_irq)(struct pci_epc *pci_epc,
+			     enum pci_epc_irq_type type);
+	int	(*start)(struct pci_epc *epc);
+	void	(*stop)(struct pci_epc *epc);
+	struct module *owner;
+};
+
+/**
+ * struct pci_epc - represents the PCI EPC device
+ * @dev: PCI EPC device
+ * @ops: function pointers for performing endpoint operations
+ * @mutex: mutex to protect pci_epc ops
+ */
+struct pci_epc {
+	struct device			dev;
+	/* support only single function PCI device for now */
+	struct pci_epf			*epf;
+	const struct pci_epc_ops	*ops;
+	spinlock_t			irq_lock;
+};
+
+#define to_pci_epc(device) container_of((device), struct pci_epc, dev)
+
+#define pci_epc_create(dev, ops)    \
+		__pci_epc_create((dev), (ops), THIS_MODULE)
+#define devm_pci_epc_create(dev, ops)    \
+		__devm_pci_epc_create((dev), (ops), THIS_MODULE)
+
+static inline void epc_set_drvdata(struct pci_epc *epc, void *data)
+{
+	dev_set_drvdata(&epc->dev, data);
+}
+
+static inline void *epc_get_drvdata(struct pci_epc *epc)
+{
+	return dev_get_drvdata(&epc->dev);
+}
+
+struct pci_epc *
+__devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
+		      struct module *owner);
+struct pci_epc *
+__pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
+		 struct module *owner);
+void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc);
+void pci_epc_destroy(struct pci_epc *epc);
+int pci_epc_write_header(struct pci_epc *epc, struct pci_epf_header *hdr);
+int pci_epc_set_bar(struct pci_epc *epc, enum pci_barno bar,
+		    dma_addr_t bar_phys, size_t size, int flags);
+void pci_epc_clear_bar(struct pci_epc *epc, int bar);
+int pci_epc_raise_irq(struct pci_epc *epc, enum pci_epc_irq_type type);
+int pci_epc_start(struct pci_epc *epc);
+void pci_epc_stop(struct pci_epc *epc);
+int pci_epc_bind_epf(struct pci_epf *epf);
+void pci_epc_unbind_epf(struct pci_epf *epf);
+#endif /* __DRIVERS_PCI_EPC_H */
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
new file mode 100644
index 0000000..337e474
--- /dev/null
+++ b/include/linux/pci-epf.h
@@ -0,0 +1,159 @@
+/**
+ * pci-epf.h - PCI Endpoint *Function* (EPF) header file
+ *
+ * Copyright (C) 2016 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@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 of
+ * the License as published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_PCI_EPF_H
+#define __DRIVERS_PCI_EPF_H
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+struct pci_epf;
+
+enum pci_interrupt_pin {
+	PCI_INTERRUPT_UNKNOWN,
+	PCI_INTERRUPT_INTA,
+	PCI_INTERRUPT_INTB,
+	PCI_INTERRUPT_INTC,
+	PCI_INTERRUPT_INTD,
+};
+
+enum pci_barno {
+	BAR_0,
+	BAR_1,
+	BAR_2,
+	BAR_3,
+	BAR_4,
+	BAR_5,
+};
+
+/**
+ * struct pci_epf_header - represents standard configuration header
+ * @vendorid: identifies device manufacturer
+ * @deviceid: identifies a particular device
+ * @revid: specifies a device specific revision identifier
+ * @progif_code: identifies a specific register-level programming interface
+ * @subclass_code: identifies more specifically the function of the device
+ * @baseclass_code: broadly classifies the type of function the device performs
+ * @cache_line_size: specifies the system cacheline size in units of DWORDs
+ * @subsys_vendor_id: vendor of the add-in card or subsystem
+ * @subsys_id: id specific to vendor
+ * @interrupt_pin: interrupt pin the device (or device function) uses
+ */
+struct pci_epf_header {
+	u16	vendorid;
+	u16	deviceid;
+	u8	revid;
+	u8	progif_code;
+	u8	subclass_code;
+	u8	baseclass_code;
+	u8	cache_line_size;
+	u16	subsys_vendor_id;
+	u16	subsys_id;
+	enum pci_interrupt_pin interrupt_pin;
+};
+
+/**
+ * struct pci_epf_ops - set of function pointers for performing EPF operations
+ * @bind: ops to perform when a EPC device has been bound to EPF device
+ * @unbind: ops to perform when a binding has been lost between a EPC device
+ *	    and EPF device
+ * @linkup: ops to perform when the EPC device has established a connection with
+ *	    a host system
+ */
+struct pci_epf_ops {
+	int	(*bind)(struct pci_epf *epf);
+	void	(*unbind)(struct pci_epf *epf);
+	void	(*linkup)(struct pci_epf *epf);
+};
+
+/**
+ * struct pci_epf_driver - represents the PCI EPF driver
+ * @probe: ops to perform when a new EPF device has been bound to the EPF driver
+ * @remove: ops to perform when the binding between the EPF device and EPF
+ *	    driver is broken
+ * @driver: PCI EPF driver
+ * @ops: set of function pointers for performing EPF operations
+ * @owner: the owner of the module that registers the PCI EPF driver
+ * @id_table: identifies EPF devices for probing
+ */
+struct pci_epf_driver {
+	int	(*probe)(struct pci_epf *epf);
+	int	(*remove)(struct pci_epf *epf);
+
+	struct device_driver	driver;
+	struct pci_epf_ops	*ops;
+	struct module		*owner;
+	const struct pci_epf_device_id	*id_table;
+};
+
+#define to_pci_epf_driver(drv) (container_of((drv), struct pci_epf_driver, \
+				driver))
+
+/**
+ * struct pci_epf_bar - represents the BAR of EPF device
+ * @phys_addr: physical address that should be mapped to the BAR
+ * @size: the size of the address space present in BAR
+ */
+struct pci_epf_bar {
+	dma_addr_t	phys_addr;
+	size_t		size;
+};
+
+/**
+ * struct pci_epf - represents the PCI EPF device
+ * @dev: the PCI EPF device
+ * @name: the name of the PCI EPF device
+ * @header: represents standard configuration header
+ * @bar: represents the BAR of EPF device
+ * @epc: the EPC device to which this EPF device is bound
+ * @driver: the EPF driver to which this EPF device is bound
+ * @pci_epc_name: the name of the EPC device to which this EPF device is bound
+ * @hw_devname: the name of the peripheral device associated with this EPF
+ *		device
+ */
+struct pci_epf {
+	struct device		dev;
+	const char		*name;
+	struct pci_epf_header	*header;
+	struct pci_epf_bar	bar[6];
+
+	struct pci_epc		*epc;
+	struct pci_epf_driver	*driver;
+	const char		*pci_epc_name;
+	const char		*hw_devname;
+};
+
+#define to_pci_epf(dev) container_of((dev), struct pci_epf, dev)
+
+#define pci_epf_register_driver(driver)    \
+		__pci_epf_register_driver((driver), THIS_MODULE)
+
+static inline void epf_set_drvdata(struct pci_epf *epf, void *data)
+{
+	dev_set_drvdata(&epf->dev, data);
+}
+
+static inline void *epf_get_drvdata(struct pci_epf *epf)
+{
+	return dev_get_drvdata(&epf->dev);
+}
+
+struct pci_epf *pci_epf_create(const char *name);
+void pci_epf_destroy(struct pci_epf *epf);
+int __pci_epf_register_driver(struct pci_epf_driver *driver,
+			      struct module *owner);
+void pci_epf_unregister_driver(struct pci_epf_driver *driver);
+void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar);
+void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar);
+int pci_epf_bind(struct pci_epf *epf);
+void pci_epf_unbind(struct pci_epf *epf);
+void pci_epf_linkup(struct pci_epf *epf);
+#endif /* __DRIVERS_PCI_EPF_H */
-- 
1.7.9.5

[toc] | [prev] | [next] | [standalone]


#1482933 — [RFC PATCH 08/11] pci: controller: dra7xx: Add EP mode support

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-14 07:20 +0200
Subject[RFC PATCH 08/11] pci: controller: dra7xx: Add EP mode support
Message-ID<shaM2-4De-23@gated-at.bofh.it>
In reply to#1482930
The PCIe controller integrated in dra7xx SoCs is capable of operating
in endpoint mode. Add support for dra7xx SoCs to operate in endpoint
mode.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/devicetree/bindings/pci/ti-pci.txt |   30 ++-
 drivers/pci/controller/Kconfig                   |   21 +++
 drivers/pci/controller/pci-dra7xx.c              |  211 +++++++++++++++++++---
 3 files changed, 225 insertions(+), 37 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt
index 60e2516..b0e76f6 100644
--- a/Documentation/devicetree/bindings/pci/ti-pci.txt
+++ b/Documentation/devicetree/bindings/pci/ti-pci.txt
@@ -1,17 +1,22 @@
 TI PCI Controllers
 
 PCIe Designware Controller
- - compatible: Should be "ti,dra7-pcie""
- - reg : Two register ranges as listed in the reg-names property
- - reg-names : The first entry must be "ti-conf" for the TI specific registers
-	       The second entry must be "rc-dbics" for the designware pcie
-	       registers
-	       The third entry must be "config" for the PCIe configuration space
+ - compatible: Should be "ti,dra7-pcie" for RC
+	       Should be "ti,dra7-pcie-ep" for EP
  - phys : list of PHY specifiers (used by generic PHY framework)
  - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
 	       number of PHYs as specified in *phys* property.
  - ti,hwmods : Name of the hwmod associated to the pcie, "pcie<X>",
 	       where <X> is the instance number of the pcie from the HW spec.
+ - num-lanes as specified in ../designware-pcie.txt
+
+HOST MODE
+=========
+ - reg : Two register ranges as listed in the reg-names property
+ - reg-names : The first entry must be "ti-conf" for the TI specific registers
+	       The second entry must be "rc-dbics" for the designware pcie
+	       registers
+	       The third entry must be "config" for the PCIe configuration space
  - interrupts : Two interrupt entries must be specified. The first one is for
 		main interrupt line and the second for MSI interrupt line.
  - #address-cells,
@@ -19,13 +24,24 @@ PCIe Designware Controller
    #interrupt-cells,
    device_type,
    ranges,
-   num-lanes,
    interrupt-map-mask,
    interrupt-map : as specified in ../designware-pcie.txt
 
 Optional Property:
  - gpios : Should be added if a gpio line is required to drive PERST# line
 
+DEVICE MODE
+===========
+ - reg : Two register ranges as listed in the reg-names property
+ - reg-names : "ti-conf" for the TI specific registers
+	       "ep_dbics" for the standard configuration registers as
+		they are locally accessed within the DIF CS space
+	       "ep_dbics2" for the standard configuration registers as
+		they are locally accessed within the DIF CS2 space
+ - interrupts : one interrupt entries must be specified for main interrupt.
+ - num-ib-windows : number of inbound address translation windows
+ - num-ob-windows : number of outbound address translation windows
+
 Example:
 axi {
 	compatible = "simple-bus";
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 8574828..4d70981 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -23,6 +23,27 @@ config PCI_DRA7XX_HOST
 	 Enables support for the PCIe controller in the DRA7xx SoC to work in
 	 host mode.
 
+config PCI_DRA7XX_EP
+	bool "Endpoint Only Mode"
+	depends on PCI_ENDPOINT
+	select PCIE_DW_EP
+	help
+	 Enables support for the PCIe controller in the DRA7xx SoC to work in
+	 endpoint mode.
+
+config PCI_DRA7XX_HOST_EP
+	bool "Both Host and Endpoint Mode"
+	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
+	depends on PCI_ENDPOINT
+	select PCIE_DW_HOST
+	select PCIE_DW_EP
+	help
+	 Enables support for the PCIe controller in the DRA7xx SoC to work in
+	 both endpoint mode and host mode. If the board has 2 PCIe ports and
+	 one of them has to work in host mode and the other has to work in
+	 EP mode then this option has to be enabled.
+
 endchoice
 
 endif
diff --git a/drivers/pci/controller/pci-dra7xx.c b/drivers/pci/controller/pci-dra7xx.c
index dc5b8ef..5b49367 100644
--- a/drivers/pci/controller/pci-dra7xx.c
+++ b/drivers/pci/controller/pci-dra7xx.c
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -17,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_gpio.h>
+#include <linux/of_device.h>
 #include <linux/pci.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
@@ -56,6 +58,11 @@
 #define	MSI						BIT(4)
 #define	LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD)
 
+#define	PCIECTRL_TI_CONF_DEVICE_TYPE			0x0100
+#define	DEVICE_TYPE_EP					0x0
+#define	DEVICE_TYPE_LEG_EP				0x1
+#define	DEVICE_TYPE_RC					0x4
+
 #define	PCIECTRL_DRA7XX_CONF_DEVICE_CMD			0x0104
 #define	LTSSM_EN					0x1
 
@@ -63,12 +70,20 @@
 #define	LINK_UP						BIT(16)
 #define	DRA7XX_CPU_TO_BUS_ADDR				0x0FFFFFFF
 
+#define	PCIECTRL_TI_CONF_INTX_ASSERT			0x0124
+#define	PCIECTRL_TI_CONF_INTX_DEASSERT			0x0128
+
 struct dra7xx_pcie {
 	void __iomem		*base;
 	struct phy		**phy;
 	int			phy_count;
 	struct device		*dev;
 	struct dw_pcie		*pci;
+	enum dw_pcie_device_mode mode;
+};
+
+struct dra7xx_pcie_of_data {
+	enum dw_pcie_device_mode mode;
 };
 
 #define to_dra7xx_pcie(x)	dev_get_drvdata((x)->dev)
@@ -248,6 +263,8 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
 static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
 {
 	struct dra7xx_pcie *dra7xx = arg;
+	struct dw_pcie *pci = dra7xx->pci;
+	struct dw_pcie_ep *ep = &pci->ep;
 	u32 reg;
 
 	reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN);
@@ -285,8 +302,11 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
 	if (reg & LINK_REQ_RST)
 		dev_dbg(dra7xx->dev, "Link Request Reset\n");
 
-	if (reg & LINK_UP_EVT)
+	if (reg & LINK_UP_EVT) {
+		if (dra7xx->mode == DW_PCIE_EP_TYPE)
+			dw_pcie_ep_linkup(ep);
 		dev_dbg(dra7xx->dev, "Link-up state change\n");
+	}
 
 	if (reg & CFG_BME_EVT)
 		dev_dbg(dra7xx->dev, "CFG 'Bus Master Enable' change\n");
@@ -299,6 +319,82 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
+
+	dra7xx_pcie_enable_wrapper_interrupts(dra7xx);
+}
+
+static void dra7xx_pcie_raise_legacy_irq(struct dra7xx_pcie *dra7xx)
+{
+	dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_INTX_ASSERT, 0x1);
+	mdelay(1);
+	dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_INTX_DEASSERT, 0x1);
+}
+
+void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx)
+{
+	/* TODO */
+}
+
+static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep,
+				 enum pci_epc_irq_type type)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
+
+	switch (type) {
+	case PCI_EPC_IRQ_LEGACY:
+		dra7xx_pcie_raise_legacy_irq(dra7xx);
+		break;
+	case PCI_EPC_IRQ_MSI:
+		dra7xx_pcie_raise_msi_irq(dra7xx);
+		break;
+	default:
+		dev_err(pci->dev, "UNKNOWN IRQ type\n");
+	}
+
+	return 0;
+}
+
+static struct dw_pcie_ep_ops pcie_ep_ops = {
+	.ep_init = dra7xx_pcie_ep_init,
+	.raise_irq = dra7xx_pcie_raise_irq,
+};
+
+static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
+				     struct platform_device *pdev)
+{
+	int ret;
+	struct dw_pcie_ep *ep;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct dw_pcie *pci = dra7xx->pci;
+
+	ep = &pci->ep;
+	ep->ops = &pcie_ep_ops;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ep_dbics");
+	pci->dbi_base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!pci->dbi_base)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ep_dbics2");
+	pci->dbi_base2 = devm_ioremap(dev, res->start, resource_size(res));
+	if (!pci->dbi_base2)
+		return -ENOMEM;
+
+	ret = dw_pcie_ep_init(ep);
+	if (ret) {
+		dev_err(dra7xx->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
 				       struct platform_device *pdev)
 {
@@ -346,12 +442,57 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
 	return 0;
 }
 
+static const struct dra7xx_pcie_of_data dra7xx_pcie_rc_of_data = {
+	.mode = DW_PCIE_RC_TYPE,
+};
+
+static const struct dra7xx_pcie_of_data dra7xx_pcie_ep_of_data = {
+	.mode = DW_PCIE_EP_TYPE,
+};
+
+static const struct of_device_id of_dra7xx_pcie_match[] = {
+	{
+		.compatible = "ti,dra7-pcie",
+		.data = &dra7xx_pcie_rc_of_data,
+	},
+	{
+		.compatible = "ti,dra7-pcie-ep",
+		.data = &dra7xx_pcie_ep_of_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match);
+
 static const struct dw_pcie_ops dw_pcie_ops = {
 	.start_link = dra7xx_pcie_start_link,
 	.stop_link = dra7xx_pcie_stop_link,
 	.link_up = dra7xx_pcie_link_up,
 };
 
+static int dra7xx_pcie_gpio_reset(struct device *dev)
+{
+	int ret;
+	int gpio_sel;
+	enum of_gpio_flags flags;
+	unsigned long gpio_flags;
+
+	gpio_sel = of_get_gpio_flags(dev->of_node, 0, &flags);
+	if (gpio_is_valid(gpio_sel)) {
+		gpio_flags = (flags & OF_GPIO_ACTIVE_LOW) ?
+			      GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
+		ret = devm_gpio_request_one(dev, gpio_sel, gpio_flags,
+					    "pcie_reset");
+		if (ret)
+			dev_err(dev, "gpio%d request failed, ret %d\n",
+				gpio_sel, ret);
+		return ret;
+	}
+	if (gpio_sel == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	return 0;
+}
+
 static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 {
 	u32 reg;
@@ -367,9 +508,16 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	char name[10];
-	int gpio_sel;
-	enum of_gpio_flags flags;
-	unsigned long gpio_flags;
+	const struct of_device_id *match;
+	const struct dra7xx_pcie_of_data *data;
+	enum dw_pcie_device_mode mode;
+
+	match = of_match_device(of_match_ptr(of_dra7xx_pcie_match), dev);
+	if (!match)
+		return -EINVAL;
+
+	data = (struct dra7xx_pcie_of_data *)match->data;
+	mode = (enum dw_pcie_device_mode)data->mode;
 
 	dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
 	if (!dra7xx)
@@ -440,31 +588,34 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 		goto err_get_sync;
 	}
 
-	gpio_sel = of_get_gpio_flags(dev->of_node, 0, &flags);
-	if (gpio_is_valid(gpio_sel)) {
-		gpio_flags = (flags & OF_GPIO_ACTIVE_LOW) ?
-				GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
-		ret = devm_gpio_request_one(dev, gpio_sel, gpio_flags,
-					    "pcie_reset");
-		if (ret) {
-			dev_err(&pdev->dev, "gpio%d request failed, ret %d\n",
-				gpio_sel, ret);
-			goto err_gpio;
-		}
-	} else if (gpio_sel == -EPROBE_DEFER) {
-		ret = -EPROBE_DEFER;
-		goto err_gpio;
-	}
-
 	reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
 	reg &= ~LTSSM_EN;
 	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
 
 	platform_set_drvdata(pdev, dra7xx);
 
-	ret = dra7xx_add_pcie_port(dra7xx, pdev);
-	if (ret < 0)
-		goto err_gpio;
+	switch (mode) {
+	case DW_PCIE_RC_TYPE:
+		ret = dra7xx_pcie_gpio_reset(dev);
+		if (ret)
+			goto err_gpio;
+		dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
+				   DEVICE_TYPE_RC);
+		ret = dra7xx_add_pcie_port(dra7xx, pdev);
+		if (ret < 0)
+			goto err_gpio;
+		break;
+	case DW_PCIE_EP_TYPE:
+		dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
+				   DEVICE_TYPE_EP);
+		ret = dra7xx_add_pcie_ep(dra7xx, pdev);
+		if (ret < 0)
+			goto err_gpio;
+		break;
+	default:
+		dev_err(dev, "INVALID device type %d\n", mode);
+	}
+	dra7xx->mode = mode;
 
 	return 0;
 
@@ -491,7 +642,7 @@ static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	int count = dra7xx->phy_count;
 
-	if (pp->irq_domain)
+	if (dra7xx->mode == DW_PCIE_RC_TYPE && pp->irq_domain)
 		irq_domain_remove(pp->irq_domain);
 	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
@@ -510,6 +661,9 @@ static int dra7xx_pcie_suspend(struct device *dev)
 	struct dw_pcie *pci = dra7xx->pci;
 	u32 val;
 
+	if (dra7xx->mode != DW_PCIE_RC_TYPE)
+		return 0;
+
 	/* clear MSE */
 	val = dra7xx_pcie_readl_dbi(pci->dbi_base, PCI_COMMAND);
 	val &= ~PCI_COMMAND_MEMORY;
@@ -524,6 +678,9 @@ static int dra7xx_pcie_resume(struct device *dev)
 	struct dw_pcie *pci = dra7xx->pci;
 	u32 val;
 
+	if (dra7xx->mode != DW_PCIE_RC_TYPE)
+		return 0;
+
 	/* set MSE */
 	val = dra7xx_pcie_readl_dbi(pci->dbi_base, PCI_COMMAND);
 	val |= PCI_COMMAND_MEMORY;
@@ -582,12 +739,6 @@ static const struct dev_pm_ops dra7xx_pcie_pm_ops = {
 				      dra7xx_pcie_resume_noirq)
 };
 
-static const struct of_device_id of_dra7xx_pcie_match[] = {
-	{ .compatible = "ti,dra7-pcie", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match);
-
 static struct platform_driver dra7xx_pcie_driver = {
 	.remove		= __exit_p(dra7xx_pcie_remove),
 	.driver = {
-- 
1.7.9.5

[toc] | [prev] | [next] | [standalone]


#1482934 — [RFC PATCH 03/11] Documentation: PCI: guide to use PCI Endpoint Core Layer

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-14 07:20 +0200
Subject[RFC PATCH 03/11] Documentation: PCI: guide to use PCI Endpoint Core Layer
Message-ID<shaM1-4De-15@gated-at.bofh.it>
In reply to#1482930
Add Documentation to let users enable endpoint mode in the PCI
controller and add new PCI endpoint function.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/PCI/00-INDEX         |    2 +
 Documentation/PCI/pci-endpoint.txt |  199 ++++++++++++++++++++++++++++++++++++
 2 files changed, 201 insertions(+)
 create mode 100644 Documentation/PCI/pci-endpoint.txt

diff --git a/Documentation/PCI/00-INDEX b/Documentation/PCI/00-INDEX
index 147231f..e422b8151 100644
--- a/Documentation/PCI/00-INDEX
+++ b/Documentation/PCI/00-INDEX
@@ -12,3 +12,5 @@ pci.txt
 	- info on the PCI subsystem for device driver authors
 pcieaer-howto.txt
 	- the PCI Express Advanced Error Reporting Driver Guide HOWTO
+pci-endpoint.txt
+	- guide to add endpoint controller driver and endpoint function driver.
diff --git a/Documentation/PCI/pci-endpoint.txt b/Documentation/PCI/pci-endpoint.txt
new file mode 100644
index 0000000..a453aaa
--- /dev/null
+++ b/Documentation/PCI/pci-endpoint.txt
@@ -0,0 +1,199 @@
+			    PCI ENDPOINT FRAMEWORK
+		    Kishon Vijay Abraham I <kishon@ti.com>
+
+This document is a guide to use the PCI Endpoint Framework in order to create
+endpoint controller driver, endpoint function driver and using configfs
+interface to bind the function driver to the controller driver.
+
+1. Introduction
+
+*Linux* has a comprehensive PCI subsystem to support PCI controllers that
+operates in Root Complex mode. The subsystem has capability to scan PCI bus,
+assign memory resources and irq resources, load PCI driver (based on
+vendorid, deviceid), support other services like hot-plug, power management,
+advanced error reporting and virtual channels.
+
+However PCI controller IPs integrated in certain SoC is capable of operating
+either in Root Complex mode or Endpoint mode. PCI Endpoint Framework will
+add endpoint mode support in *Linux*. This will help to run Linux in an
+EP system which can have a wide variety of use cases from testing or
+validation, co-processor accelerator etc..
+
+2. PCI Endpoint Core
+
+The PCI Endpoint Core layer comprises of 3 components: the Endpoint Controller
+library, the Endpoint Function library and the configfs layer to bind the
+endpoint function with the endpoint controller.
+
+2.1 PCI Endpoint Controller(EPC) Library
+
+The EPC library provides APIs to be used by the controller that can operate
+in endpoint mode. It also provides APIs to be used by function driver/library
+in order to implement a particular endpoint function.
+
+2.1.1 APIs for the PCI controller Driver
+
+This section lists the APIs that the PCI Endpoint core provides to be used
+by the PCI controller driver.
+
+*) devm_pci_epc_create()/pci_epc_create()
+
+   The PCI controller driver should implement the following ops:
+	 * write_header: ops to populate configuration space header
+	 * set_bar: ops to configure the BAR
+	 * clear_bar: ops to reset the BAR
+	 * alloc_addr_space: ops to allocate *in* PCI controller address space
+	 * free_addr_space: ops to free the allocated address space
+	 * raise_irq: ops to raise a legacy or MSI interrupt
+	 * start: ops to start the PCI link
+	 * stop: ops to stop the PCI link
+
+   The PCI controller driver can then create a new EPC device by invoking
+   devm_pci_epc_create/pci_epc_create.
+
+*) devm_pci_epc_destroy()/pci_epc_destroy()
+
+   The PCI controller driver can destroy the EPC device created by either
+   devm_pci_epc_create or pci_epc_create using devm_pci_epc_destroy() or
+   /pci_epc_destroy()
+
+2.1.2 APIs for the PCI Endpoint Function Driver
+
+This section lists the APIs that the PCI Endpoint core provides to be used
+by the PCI endpoint function driver.
+
+*) pci_epc_write_header()
+
+   The PCI endpoint function driver should use pci_epc_write_header() to
+   write the standard configuration header to the endpoint controller.
+
+*) pci_epc_set_bar()
+
+   The PCI endpoint function driver should use pci_epc_set_bar() to configure
+   the Base Address Register in order for the host to assign PCI addr space.
+   Register space of the function driver is usually configured
+   using this API.
+
+*) pci_epc_clear_bar()
+
+   The PCI endpoint function driver should use pci_epc_clear_bar() to reset
+   the BAR.
+
+*) pci_epc_raise_irq()
+
+   The PCI endpoint function driver should use pci_epc_raise_irq() to raise
+   Legacy Interrupt or MSI Interrupt.
+
+*) pci_epc_start()
+
+   The PCI endpoint function driver should invoke pci_epc_start() once it
+   has configured the endpoint function and wants to start the PCI link.
+
+*) pci_epc_stop()
+
+   The PCI endpoint function driver should invoke pci_epc_stop() to stop
+   the PCI LINK.
+
+2.1.3 APIs for the PCI Endpoint Function Library
+
+This section lists the APIs that the PCI Endpoint core provides to be used
+by the PCI endpoint function library.
+
+*) pci_epc_bind_epf()
+
+   The PCI endpoint function library uses pci_epc_bind_epf() to bind the
+   function driver with a controller driver. The binding will be based on
+   the endpoint controller function name (as seen in /sys/class/pci_epc/).
+
+*) pci_epc_unbind_epf()
+
+   The PCI endpoint function library uses pci_epc_unbind_epf() to unbind
+   the function driver from the controller driver. After unbind the controller
+   driver can be bound to any other function driver.
+
+2.2 PCI Endpoint Function(EPF) Library
+
+The EPF library provides APIs to be used by the function driver and the EPC
+library in order to provide endpoint mode functionality.
+
+2.2.1 APIs for the PCI Endpoint Function Driver
+
+This section lists the APIs that the PCI Endpoint core provides to be used
+by the PCI endpoint function driver.
+
+*) pci_epf_register_driver()
+
+   The PCI Endpoint Function driver should implement the following ops:
+	 * bind: ops to perform when a EPC device has been bound to EPF device
+	 * unbind: ops to perform when a binding has been lost between a EPC
+	   device and EPF device
+	 * linkup: ops to perform when the EPC device has established a
+	   connection with a host system
+
+  The PCI Function driver can then register the PCI EPF driver by using
+  pci_epf_register_driver().
+
+*) pci_epf_unregister_driver()
+
+  The PCI Function driver can unregister the PCI EPF driver by using
+  pci_epf_unregister_driver().
+
+*) pci_epf_alloc_space()
+
+  The PCI Function driver can allocate space for a particular BAR using
+  pci_epf_alloc_space().
+
+*) pci_epf_free_space()
+
+  The PCI Function driver can free the allocated space
+  (using pci_epf_alloc_space) by invoking pci_epf_free_space().
+
+2.2.2 APIs for the PCI Endpoint Controller Library
+
+This section lists the APIs that the PCI Endpoint core provides to be used
+by the PCI endpoint controller library.
+
+*) pci_epf_bind()
+
+   The PCI endpoint controller library invokes pci_epf_bind() when the EPF
+   device has been bound to a EPC device.
+
+*) pci_epf_unbind()
+
+   The PCI endpoint controller library invokes pci_epf_unbind() when the
+   binding between EPC device and EPF device is lost.
+
+*) pci_epf_linkup()
+
+   The PCI endpoint controller library invokes pci_epf_linkup() when the
+   EPC device has established the connection to the host.
+
+2.3 CONFIGFS
+
+The PCI Endpoint Core exposes configfs entry (pci_ep) in order to configure the
+PCI Endpoint Function and in order to bind the endpoint function
+with the endpoint controller. Every folder in pci_ep/ represent a PCI
+endpoint function.
+
+The following entries can be used to configure the standard configuration
+header of the endpoint function.
+	vendorid
+	deviceid
+	revid
+	progif_code
+	subclass_code
+	baseclass_code
+	cache_line_size
+	subsys_vendor_id
+	subsys_id
+	interrupt_pin
+
+The following entries has special meaning:
+	function: this readonly entry shows the name using which the function
+		  driver will be bound to this function
+	epc	: the name of the EPC device this function should be bound to.
+		  The name of the EPC device should be from /sys/class/pci_epc.
+
+3. Known Limitations
+
+The Endpoint Core doesn't support adding multi-function devices.
-- 
1.7.9.5

[toc] | [prev] | [next] | [standalone]


#1482935 — [RFC PATCH 05/11] pci: rename *host* directory to *controller*

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-14 07:20 +0200
Subject[RFC PATCH 05/11] pci: rename *host* directory to *controller*
Message-ID<shaM2-4De-19@gated-at.bofh.it>
In reply to#1482930
No functional change. Renamed the *host* directory present inside
drivers/pci to *controller*. Some of the controllers present in
drivers/pci/host is capable of operating in endpoint mode.
So having these drivers in *host* directory might not be appropriate.
This is in preparation for adding endpoint mode support for some of
controller drivers present here.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 MAINTAINERS                                        |   50 ++++++++++----------
 drivers/Makefile                                   |    3 ++
 drivers/pci/Kconfig                                |    2 +-
 drivers/pci/Makefile                               |    3 --
 drivers/pci/{host => controller}/Kconfig           |   35 +++++++++++++-
 drivers/pci/{host => controller}/Makefile          |    0
 drivers/pci/{host => controller}/pci-aardvark.c    |    0
 drivers/pci/{host => controller}/pci-dra7xx.c      |    0
 drivers/pci/{host => controller}/pci-exynos.c      |    0
 drivers/pci/{host => controller}/pci-host-common.c |    0
 .../pci/{host => controller}/pci-host-generic.c    |    0
 drivers/pci/{host => controller}/pci-hyperv.c      |    0
 drivers/pci/{host => controller}/pci-imx6.c        |    0
 drivers/pci/{host => controller}/pci-keystone-dw.c |    0
 drivers/pci/{host => controller}/pci-keystone.c    |    0
 drivers/pci/{host => controller}/pci-keystone.h    |    0
 drivers/pci/{host => controller}/pci-layerscape.c  |    0
 drivers/pci/{host => controller}/pci-mvebu.c       |    0
 drivers/pci/{host => controller}/pci-rcar-gen2.c   |    0
 drivers/pci/{host => controller}/pci-tegra.c       |    0
 .../pci/{host => controller}/pci-thunder-ecam.c    |    0
 drivers/pci/{host => controller}/pci-thunder-pem.c |    0
 drivers/pci/{host => controller}/pci-versatile.c   |    0
 drivers/pci/{host => controller}/pci-xgene-msi.c   |    0
 drivers/pci/{host => controller}/pci-xgene.c       |    0
 drivers/pci/{host => controller}/pcie-altera-msi.c |    0
 drivers/pci/{host => controller}/pcie-altera.c     |    0
 drivers/pci/{host => controller}/pcie-armada8k.c   |    0
 drivers/pci/{host => controller}/pcie-artpec6.c    |    0
 .../{host => controller}/pcie-designware-plat.c    |    0
 drivers/pci/{host => controller}/pcie-designware.c |    0
 drivers/pci/{host => controller}/pcie-designware.h |    0
 drivers/pci/{host => controller}/pcie-hisi.c       |    0
 drivers/pci/{host => controller}/pcie-iproc-bcma.c |    0
 drivers/pci/{host => controller}/pcie-iproc-msi.c  |    0
 .../pci/{host => controller}/pcie-iproc-platform.c |    0
 drivers/pci/{host => controller}/pcie-iproc.c      |    0
 drivers/pci/{host => controller}/pcie-iproc.h      |    0
 drivers/pci/{host => controller}/pcie-qcom.c       |    0
 drivers/pci/{host => controller}/pcie-rcar.c       |    0
 drivers/pci/{host => controller}/pcie-spear13xx.c  |    0
 drivers/pci/{host => controller}/pcie-xilinx-nwl.c |    0
 drivers/pci/{host => controller}/pcie-xilinx.c     |    0
 43 files changed, 62 insertions(+), 31 deletions(-)
 rename drivers/pci/{host => controller}/Kconfig (93%)
 rename drivers/pci/{host => controller}/Makefile (100%)
 rename drivers/pci/{host => controller}/pci-aardvark.c (100%)
 rename drivers/pci/{host => controller}/pci-dra7xx.c (100%)
 rename drivers/pci/{host => controller}/pci-exynos.c (100%)
 rename drivers/pci/{host => controller}/pci-host-common.c (100%)
 rename drivers/pci/{host => controller}/pci-host-generic.c (100%)
 rename drivers/pci/{host => controller}/pci-hyperv.c (100%)
 rename drivers/pci/{host => controller}/pci-imx6.c (100%)
 rename drivers/pci/{host => controller}/pci-keystone-dw.c (100%)
 rename drivers/pci/{host => controller}/pci-keystone.c (100%)
 rename drivers/pci/{host => controller}/pci-keystone.h (100%)
 rename drivers/pci/{host => controller}/pci-layerscape.c (100%)
 rename drivers/pci/{host => controller}/pci-mvebu.c (100%)
 rename drivers/pci/{host => controller}/pci-rcar-gen2.c (100%)
 rename drivers/pci/{host => controller}/pci-tegra.c (100%)
 rename drivers/pci/{host => controller}/pci-thunder-ecam.c (100%)
 rename drivers/pci/{host => controller}/pci-thunder-pem.c (100%)
 rename drivers/pci/{host => controller}/pci-versatile.c (100%)
 rename drivers/pci/{host => controller}/pci-xgene-msi.c (100%)
 rename drivers/pci/{host => controller}/pci-xgene.c (100%)
 rename drivers/pci/{host => controller}/pcie-altera-msi.c (100%)
 rename drivers/pci/{host => controller}/pcie-altera.c (100%)
 rename drivers/pci/{host => controller}/pcie-armada8k.c (100%)
 rename drivers/pci/{host => controller}/pcie-artpec6.c (100%)
 rename drivers/pci/{host => controller}/pcie-designware-plat.c (100%)
 rename drivers/pci/{host => controller}/pcie-designware.c (100%)
 rename drivers/pci/{host => controller}/pcie-designware.h (100%)
 rename drivers/pci/{host => controller}/pcie-hisi.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc-bcma.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc-msi.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc-platform.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc.c (100%)
 rename drivers/pci/{host => controller}/pcie-iproc.h (100%)
 rename drivers/pci/{host => controller}/pcie-qcom.c (100%)
 rename drivers/pci/{host => controller}/pcie-rcar.c (100%)
 rename drivers/pci/{host => controller}/pcie-spear13xx.c (100%)
 rename drivers/pci/{host => controller}/pcie-xilinx-nwl.c (100%)
 rename drivers/pci/{host => controller}/pcie-xilinx.c (100%)

diff --git a/MAINTAINERS b/MAINTAINERS
index a5e1270..3db2531 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5662,7 +5662,7 @@ F:	arch/x86/kernel/cpu/mshyperv.c
 F:	drivers/hid/hid-hyperv.c
 F:	drivers/hv/
 F:	drivers/input/serio/hyperv-keyboard.c
-F:	drivers/pci/host/pci-hyperv.c
+F:	drivers/pci/controller/pci-hyperv.c
 F:	drivers/net/hyperv/
 F:	drivers/scsi/storvsc_drv.c
 F:	drivers/video/fbdev/hyperv_fb.c
@@ -8945,7 +8945,7 @@ L:	rfi@lists.rocketboards.org (moderated for non-subscribers)
 L:	linux-pci@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/pci/altera-pcie.txt
-F:	drivers/pci/host/pcie-altera.c
+F:	drivers/pci/controller/pcie-altera.c
 
 PCI DRIVER FOR ARM VERSATILE PLATFORM
 M:	Rob Herring <robh@kernel.org>
@@ -8953,7 +8953,7 @@ L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pci/versatile.txt
-F:	drivers/pci/host/pci-versatile.c
+F:	drivers/pci/controller/pci-versatile.c
 
 PCI DRIVER FOR APPLIEDMICRO XGENE
 M:	Tanmay Inamdar <tinamdar@apm.com>
@@ -8961,7 +8961,7 @@ L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pci/xgene-pci.txt
-F:	drivers/pci/host/pci-xgene.c
+F:	drivers/pci/controller/pci-xgene.c
 
 PCI DRIVER FOR FREESCALE LAYERSCAPE
 M:	Minghuan Lian <minghuan.Lian@freescale.com>
@@ -8971,7 +8971,7 @@ L:	linuxppc-dev@lists.ozlabs.org
 L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org
 S:	Maintained
-F:	drivers/pci/host/*layerscape*
+F:	drivers/pci/controller/*layerscape*
 
 PCI DRIVER FOR IMX6
 M:	Richard Zhu <Richard.Zhu@freescale.com>
@@ -8979,14 +8979,14 @@ M:	Lucas Stach <l.stach@pengutronix.de>
 L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-F:	drivers/pci/host/*imx6*
+F:	drivers/pci/controller/*imx6*
 
 PCI DRIVER FOR TI KEYSTONE
 M:	Murali Karicheri <m-karicheri2@ti.com>
 L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-F:	drivers/pci/host/*keystone*
+F:	drivers/pci/controller/*keystone*
 
 PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
 M:	Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
@@ -8994,14 +8994,14 @@ M:	Jason Cooper <jason@lakedaemon.net>
 L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-F:	drivers/pci/host/*mvebu*
+F:	drivers/pci/controller/*mvebu*
 
 PCI DRIVER FOR AARDVARK (Marvell Armada 3700)
 M:	Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-F:	drivers/pci/host/pci-aardvark.c
+F:	drivers/pci/controller/pci-aardvark.c
 
 PCI DRIVER FOR NVIDIA TEGRA
 M:	Thierry Reding <thierry.reding@gmail.com>
@@ -9009,7 +9009,7 @@ L:	linux-tegra@vger.kernel.org
 L:	linux-pci@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
-F:	drivers/pci/host/pci-tegra.c
+F:	drivers/pci/controller/pci-tegra.c
 
 PCI DRIVER FOR TI DRA7XX
 M:	Kishon Vijay Abraham I <kishon@ti.com>
@@ -9017,14 +9017,14 @@ L:	linux-omap@vger.kernel.org
 L:	linux-pci@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/pci/ti-pci.txt
-F:	drivers/pci/host/pci-dra7xx.c
+F:	drivers/pci/controller/pci-dra7xx.c
 
 PCI DRIVER FOR RENESAS R-CAR
 M:	Simon Horman <horms@verge.net.au>
 L:	linux-pci@vger.kernel.org
 L:	linux-renesas-soc@vger.kernel.org
 S:	Maintained
-F:	drivers/pci/host/*rcar*
+F:	drivers/pci/controller/*rcar*
 
 PCI DRIVER FOR SAMSUNG EXYNOS
 M:	Jingoo Han <jingoohan1@gmail.com>
@@ -9032,30 +9032,30 @@ L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:	linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:	Maintained
-F:	drivers/pci/host/pci-exynos.c
+F:	drivers/pci/controller/pci-exynos.c
 
 PCI DRIVER FOR SYNOPSIS DESIGNWARE
 M:	Jingoo Han <jingoohan1@gmail.com>
 M:	Pratyush Anand <pratyush.anand@gmail.com>
 L:	linux-pci@vger.kernel.org
 S:	Maintained
-F:	drivers/pci/host/*designware*
+F:	drivers/pci/controller/*designware*
 
 PCI DRIVER FOR SYNOPSYS PROTOTYPING DEVICE
 M:	Joao Pinto <jpinto@synopsys.com>
 L:	linux-pci@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pci/designware-pcie.txt
-F:	drivers/pci/host/pcie-designware-plat.c
+F:	drivers/pci/controller/pcie-designware-plat.c
 
 PCI DRIVER FOR GENERIC OF HOSTS
 M:	Will Deacon <will.deacon@arm.com>
 L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-F:	Documentation/devicetree/bindings/pci/host-generic-pci.txt
-F:	drivers/pci/host/pci-host-common.c
-F:	drivers/pci/host/pci-host-generic.c
+F:	Documentation/devicetree/bindings/pci/controller-generic-pci.txt
+F:	drivers/pci/controller/pci-host-common.c
+F:	drivers/pci/controller/pci-host-generic.c
 
 PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
 M:	Keith Busch <keith.busch@intel.com>
@@ -9067,7 +9067,7 @@ PCIE DRIVER FOR ST SPEAR13XX
 M:	Pratyush Anand <pratyush.anand@gmail.com>
 L:	linux-pci@vger.kernel.org
 S:	Maintained
-F:	drivers/pci/host/*spear*
+F:	drivers/pci/controller/*spear*
 
 PCI MSI DRIVER FOR ALTERA MSI IP
 M:	Ley Foon Tan <lftan@altera.com>
@@ -9075,7 +9075,7 @@ L:	rfi@lists.rocketboards.org (moderated for non-subscribers)
 L:	linux-pci@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/pci/altera-pcie-msi.txt
-F:	drivers/pci/host/pcie-altera-msi.c
+F:	drivers/pci/controller/pcie-altera-msi.c
 
 PCI MSI DRIVER FOR APPLIEDMICRO XGENE
 M:	Duc Dang <dhdang@apm.com>
@@ -9083,7 +9083,7 @@ L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
-F:	drivers/pci/host/pci-xgene-msi.c
+F:	drivers/pci/controller/pci-xgene-msi.c
 
 PCIE DRIVER FOR AXIS ARTPEC
 M:	Niklas Cassel <niklas.cassel@axis.com>
@@ -9092,7 +9092,7 @@ L:	linux-arm-kernel@axis.com
 L:	linux-pci@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pci/axis,artpec*
-F:	drivers/pci/host/*artpec*
+F:	drivers/pci/controller/*artpec*
 
 PCIE DRIVER FOR HISILICON
 M:	Zhou Wang <wangzhou1@hisilicon.com>
@@ -9100,14 +9100,14 @@ M:	Gabriele Paoloni <gabriele.paoloni@huawei.com>
 L:	linux-pci@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
-F:	drivers/pci/host/pcie-hisi.c
+F:	drivers/pci/controller/pcie-hisi.c
 
 PCIE DRIVER FOR QUALCOMM MSM
 M:     Stanimir Varbanov <svarbanov@mm-sol.com>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
-F:     drivers/pci/host/*qcom*
+F:     drivers/pci/controller/*qcom*
 
 PCIE DRIVER FOR CAVIUM THUNDERX
 M:	David Daney <david.daney@cavium.com>
@@ -9115,7 +9115,7 @@ L:	linux-pci@vger.kernel.org
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Supported
 F:	Documentation/devicetree/bindings/pci/pci-thunder-*
-F:	drivers/pci/host/pci-thunder-*
+F:	drivers/pci/controller/pci-thunder-*
 
 PCMCIA SUBSYSTEM
 P:	Linux PCMCIA Team
diff --git a/drivers/Makefile b/drivers/Makefile
index 8c070ad..10cb1ad 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -16,6 +16,9 @@ obj-$(CONFIG_GPIOLIB)		+= gpio/
 obj-y				+= pwm/
 obj-$(CONFIG_PCI_ENDPOINT)	+= pci/endpoint/
 obj-$(CONFIG_PCI)		+= pci/
+# PCI controller drivers
+obj-y				+= pci/controller/
+
 obj-$(CONFIG_PARISC)		+= parisc/
 obj-$(CONFIG_RAPIDIO)		+= rapidio/
 obj-y				+= video/
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 5f116a6..c603a8a 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -132,5 +132,5 @@ config PCI_HYPERV
           PCI devices from a PCI backend to support PCI driver domains.
 
 source "drivers/pci/hotplug/Kconfig"
-source "drivers/pci/host/Kconfig"
+source "drivers/pci/controller/Kconfig"
 source "drivers/pci/endpoint/Kconfig"
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 8db5079..b924cc9 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -65,6 +65,3 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 obj-$(CONFIG_OF) += of.o
 
 ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
-
-# PCI host controller drivers
-obj-y += host/
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/controller/Kconfig
similarity index 93%
rename from drivers/pci/host/Kconfig
rename to drivers/pci/controller/Kconfig
index 9b485d8..4c55c2d 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -1,10 +1,10 @@
-menu "PCI host controller drivers"
-	depends on PCI
+menu "PCI controller drivers"
 
 config PCI_DRA7XX
 	bool "TI DRA7xx PCIe controller"
 	depends on OF && HAS_IOMEM && TI_PIPE3
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIE_DW
 	help
 	 Enables support for the PCIe controller in the DRA7xx SoC.  There
@@ -16,12 +16,14 @@ config PCI_MVEBU
 	depends on ARCH_MVEBU || ARCH_DOVE
 	depends on ARM
 	depends on OF
+	depends on PCI
 
 config PCI_AARDVARK
 	bool "Aardvark PCIe controller"
 	depends on ARCH_MVEBU && ARM64
 	depends on OF
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	help
 	 Add support for Aardvark 64bit PCIe Host Controller. This
 	 controller is part of the South Bridge of the Marvel Armada
@@ -31,6 +33,7 @@ config PCIE_XILINX_NWL
 	bool "NWL PCIe Core"
 	depends on ARCH_ZYNQMP
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	help
 	 Say 'Y' here if you want kernel support for Xilinx
 	 NWL PCIe controller. The controller can act as Root Port
@@ -40,6 +43,7 @@ config PCIE_XILINX_NWL
 config PCIE_DW_PLAT
 	bool "Platform bus based DesignWare PCIe Controller"
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIE_DW
 	---help---
 	 This selects the DesignWare PCIe controller support. Select this if
@@ -52,6 +56,7 @@ config PCIE_DW_PLAT
 config PCIE_DW
 	bool
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 
 config PCI_EXYNOS
 	bool "Samsung Exynos PCIe controller"
@@ -59,17 +64,20 @@ config PCI_EXYNOS
 	depends on PCI_MSI_IRQ_DOMAIN
 	select PCIEPORTBUS
 	select PCIE_DW
+	depends on PCI
 
 config PCI_IMX6
 	bool "Freescale i.MX6 PCIe controller"
 	depends on SOC_IMX6Q
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIEPORTBUS
 	select PCIE_DW
 
 config PCI_TEGRA
 	bool "NVIDIA Tegra PCIe controller"
 	depends on ARCH_TEGRA && !ARM64
+	depends on PCI
 	help
 	  Say Y here if you want support for the PCIe host controller found
 	  on NVIDIA Tegra SoCs.
@@ -78,6 +86,7 @@ config PCI_RCAR_GEN2
 	bool "Renesas R-Car Gen2 Internal PCI controller"
 	depends on ARM
 	depends on ARCH_RENESAS || COMPILE_TEST
+	depends on PCI
 	help
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
@@ -87,16 +96,19 @@ config PCIE_RCAR
 	bool "Renesas R-Car PCIe controller"
 	depends on ARCH_RENESAS || (ARM && COMPILE_TEST)
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	help
 	  Say Y here if you want PCIe controller support on R-Car SoCs.
 
 config PCI_HOST_COMMON
 	bool
+	depends on PCI
 	select PCI_ECAM
 
 config PCI_HOST_GENERIC
 	bool "Generic PCI host controller"
 	depends on (ARM || ARM64) && OF
+	depends on PCI
 	select PCI_HOST_COMMON
 	select IRQ_DOMAIN
 	help
@@ -107,6 +119,7 @@ config PCIE_SPEAR13XX
 	bool "STMicroelectronics SPEAr PCIe controller"
 	depends on ARCH_SPEAR13XX
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIEPORTBUS
 	select PCIE_DW
 	help
@@ -116,6 +129,7 @@ config PCI_KEYSTONE
 	bool "TI Keystone PCIe controller"
 	depends on ARCH_KEYSTONE
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIE_DW
 	select PCIEPORTBUS
 	help
@@ -127,6 +141,7 @@ config PCI_KEYSTONE
 config PCIE_XILINX
 	bool "Xilinx AXI PCIe host bridge support"
 	depends on ARCH_ZYNQ || MICROBLAZE
+	depends on PCI
 	help
 	  Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
 	  Host Bridge driver.
@@ -135,6 +150,7 @@ config PCI_XGENE
 	bool "X-Gene PCIe controller"
 	depends on ARCH_XGENE
 	depends on OF
+	depends on PCI
 	select PCIEPORTBUS
 	help
 	  Say Y here if you want internal PCI support on APM X-Gene SoC.
@@ -145,6 +161,7 @@ config PCI_XGENE_MSI
 	bool "X-Gene v1 PCIe MSI feature"
 	depends on PCI_XGENE
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	default y
 	help
 	  Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC.
@@ -154,6 +171,7 @@ config PCI_LAYERSCAPE
 	bool "Freescale Layerscape PCIe controller"
 	depends on OF && (ARM || ARCH_LAYERSCAPE)
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIE_DW
 	select MFD_SYSCON
 	help
@@ -162,9 +180,11 @@ config PCI_LAYERSCAPE
 config PCI_VERSATILE
 	bool "ARM Versatile PB PCI controller"
 	depends on ARCH_VERSATILE
+	depends on PCI
 
 config PCIE_IPROC
 	tristate
+	depends on PCI
 	help
 	  This enables the iProc PCIe core controller support for Broadcom's
 	  iProc family of SoCs. An appropriate bus interface driver needs
@@ -174,6 +194,7 @@ config PCIE_IPROC_PLATFORM
 	tristate "Broadcom iProc PCIe platform bus driver"
 	depends on ARCH_BCM_IPROC || (ARM && COMPILE_TEST)
 	depends on OF
+	depends on PCI
 	select PCIE_IPROC
 	default ARCH_BCM_IPROC
 	help
@@ -183,6 +204,7 @@ config PCIE_IPROC_PLATFORM
 config PCIE_IPROC_BCMA
 	tristate "Broadcom iProc PCIe BCMA bus driver"
 	depends on ARM && (ARCH_BCM_IPROC || COMPILE_TEST)
+	depends on PCI
 	select PCIE_IPROC
 	select BCMA
 	select PCI_DOMAINS
@@ -195,6 +217,7 @@ config PCIE_IPROC_MSI
 	bool "Broadcom iProc PCIe MSI support"
 	depends on PCIE_IPROC_PLATFORM || PCIE_IPROC_BCMA
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	default ARCH_BCM_IPROC
 	help
 	  Say Y here if you want to enable MSI support for Broadcom's iProc
@@ -204,6 +227,7 @@ config PCIE_ALTERA
 	bool "Altera PCIe controller"
 	depends on ARM || NIOS2
 	depends on OF_PCI
+	depends on PCI
 	select PCI_DOMAINS
 	help
 	  Say Y here if you want to enable PCIe controller support on Altera
@@ -213,6 +237,7 @@ config PCIE_ALTERA_MSI
 	bool "Altera PCIe MSI feature"
 	depends on PCIE_ALTERA
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	help
 	  Say Y here if you want PCIe MSI support for the Altera FPGA.
 	  This MSI driver supports Altera MSI to GIC controller IP.
@@ -221,6 +246,7 @@ config PCI_HISI
 	depends on OF && ARM64
 	bool "HiSilicon Hip05 and Hip06 SoCs PCIe controllers"
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIEPORTBUS
 	select PCIE_DW
 	help
@@ -231,6 +257,7 @@ config PCIE_QCOM
 	bool "Qualcomm PCIe controller"
 	depends on ARCH_QCOM && OF
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIE_DW
 	select PCIEPORTBUS
 	help
@@ -241,6 +268,7 @@ config PCIE_QCOM
 config PCI_HOST_THUNDER_PEM
 	bool "Cavium Thunder PCIe controller to off-chip devices"
 	depends on OF && ARM64
+	depends on PCI
 	select PCI_HOST_COMMON
 	help
 	  Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs.
@@ -248,6 +276,7 @@ config PCI_HOST_THUNDER_PEM
 config PCI_HOST_THUNDER_ECAM
 	bool "Cavium Thunder ECAM controller to on-chip devices on pass-1.x silicon"
 	depends on OF && ARM64
+	depends on PCI
 	select PCI_HOST_COMMON
 	help
 	  Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs.
@@ -256,6 +285,7 @@ config PCIE_ARMADA_8K
 	bool "Marvell Armada-8K PCIe controller"
 	depends on ARCH_MVEBU
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIE_DW
 	select PCIEPORTBUS
 	help
@@ -268,6 +298,7 @@ config PCIE_ARTPEC6
 	bool "Axis ARTPEC-6 PCIe controller"
 	depends on MACH_ARTPEC6
 	depends on PCI_MSI_IRQ_DOMAIN
+	depends on PCI
 	select PCIE_DW
 	select PCIEPORTBUS
 	help
diff --git a/drivers/pci/host/Makefile b/drivers/pci/controller/Makefile
similarity index 100%
rename from drivers/pci/host/Makefile
rename to drivers/pci/controller/Makefile
diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
similarity index 100%
rename from drivers/pci/host/pci-aardvark.c
rename to drivers/pci/controller/pci-aardvark.c
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/controller/pci-dra7xx.c
similarity index 100%
rename from drivers/pci/host/pci-dra7xx.c
rename to drivers/pci/controller/pci-dra7xx.c
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/controller/pci-exynos.c
similarity index 100%
rename from drivers/pci/host/pci-exynos.c
rename to drivers/pci/controller/pci-exynos.c
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/controller/pci-host-common.c
similarity index 100%
rename from drivers/pci/host/pci-host-common.c
rename to drivers/pci/controller/pci-host-common.c
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c
similarity index 100%
rename from drivers/pci/host/pci-host-generic.c
rename to drivers/pci/controller/pci-host-generic.c
diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
similarity index 100%
rename from drivers/pci/host/pci-hyperv.c
rename to drivers/pci/controller/pci-hyperv.c
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/controller/pci-imx6.c
similarity index 100%
rename from drivers/pci/host/pci-imx6.c
rename to drivers/pci/controller/pci-imx6.c
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/controller/pci-keystone-dw.c
similarity index 100%
rename from drivers/pci/host/pci-keystone-dw.c
rename to drivers/pci/controller/pci-keystone-dw.c
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/controller/pci-keystone.c
similarity index 100%
rename from drivers/pci/host/pci-keystone.c
rename to drivers/pci/controller/pci-keystone.c
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/controller/pci-keystone.h
similarity index 100%
rename from drivers/pci/host/pci-keystone.h
rename to drivers/pci/controller/pci-keystone.h
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/controller/pci-layerscape.c
similarity index 100%
rename from drivers/pci/host/pci-layerscape.c
rename to drivers/pci/controller/pci-layerscape.c
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
similarity index 100%
rename from drivers/pci/host/pci-mvebu.c
rename to drivers/pci/controller/pci-mvebu.c
diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/controller/pci-rcar-gen2.c
similarity index 100%
rename from drivers/pci/host/pci-rcar-gen2.c
rename to drivers/pci/controller/pci-rcar-gen2.c
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
similarity index 100%
rename from drivers/pci/host/pci-tegra.c
rename to drivers/pci/controller/pci-tegra.c
diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/controller/pci-thunder-ecam.c
similarity index 100%
rename from drivers/pci/host/pci-thunder-ecam.c
rename to drivers/pci/controller/pci-thunder-ecam.c
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/controller/pci-thunder-pem.c
similarity index 100%
rename from drivers/pci/host/pci-thunder-pem.c
rename to drivers/pci/controller/pci-thunder-pem.c
diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/controller/pci-versatile.c
similarity index 100%
rename from drivers/pci/host/pci-versatile.c
rename to drivers/pci/controller/pci-versatile.c
diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c
similarity index 100%
rename from drivers/pci/host/pci-xgene-msi.c
rename to drivers/pci/controller/pci-xgene-msi.c
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/controller/pci-xgene.c
similarity index 100%
rename from drivers/pci/host/pci-xgene.c
rename to drivers/pci/controller/pci-xgene.c
diff --git a/drivers/pci/host/pcie-altera-msi.c b/drivers/pci/controller/pcie-altera-msi.c
similarity index 100%
rename from drivers/pci/host/pcie-altera-msi.c
rename to drivers/pci/controller/pcie-altera-msi.c
diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/controller/pcie-altera.c
similarity index 100%
rename from drivers/pci/host/pcie-altera.c
rename to drivers/pci/controller/pcie-altera.c
diff --git a/drivers/pci/host/pcie-armada8k.c b/drivers/pci/controller/pcie-armada8k.c
similarity index 100%
rename from drivers/pci/host/pcie-armada8k.c
rename to drivers/pci/controller/pcie-armada8k.c
diff --git a/drivers/pci/host/pcie-artpec6.c b/drivers/pci/controller/pcie-artpec6.c
similarity index 100%
rename from drivers/pci/host/pcie-artpec6.c
rename to drivers/pci/controller/pcie-artpec6.c
diff --git a/drivers/pci/host/pcie-designware-plat.c b/drivers/pci/controller/pcie-designware-plat.c
similarity index 100%
rename from drivers/pci/host/pcie-designware-plat.c
rename to drivers/pci/controller/pcie-designware-plat.c
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/controller/pcie-designware.c
similarity index 100%
rename from drivers/pci/host/pcie-designware.c
rename to drivers/pci/controller/pcie-designware.c
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/controller/pcie-designware.h
similarity index 100%
rename from drivers/pci/host/pcie-designware.h
rename to drivers/pci/controller/pcie-designware.h
diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/controller/pcie-hisi.c
similarity index 100%
rename from drivers/pci/host/pcie-hisi.c
rename to drivers/pci/controller/pcie-hisi.c
diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/controller/pcie-iproc-bcma.c
similarity index 100%
rename from drivers/pci/host/pcie-iproc-bcma.c
rename to drivers/pci/controller/pcie-iproc-bcma.c
diff --git a/drivers/pci/host/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c
similarity index 100%
rename from drivers/pci/host/pcie-iproc-msi.c
rename to drivers/pci/controller/pcie-iproc-msi.c
diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/controller/pcie-iproc-platform.c
similarity index 100%
rename from drivers/pci/host/pcie-iproc-platform.c
rename to drivers/pci/controller/pcie-iproc-platform.c
diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
similarity index 100%
rename from drivers/pci/host/pcie-iproc.c
rename to drivers/pci/controller/pcie-iproc.c
diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/controller/pcie-iproc.h
similarity index 100%
rename from drivers/pci/host/pcie-iproc.h
rename to drivers/pci/controller/pcie-iproc.h
diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/controller/pcie-qcom.c
similarity index 100%
rename from drivers/pci/host/pcie-qcom.c
rename to drivers/pci/controller/pcie-qcom.c
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c
similarity index 100%
rename from drivers/pci/host/pcie-rcar.c
rename to drivers/pci/controller/pcie-rcar.c
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/controller/pcie-spear13xx.c
similarity index 100%
rename from drivers/pci/host/pcie-spear13xx.c
rename to drivers/pci/controller/pcie-spear13xx.c
diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
similarity index 100%
rename from drivers/pci/host/pcie-xilinx-nwl.c
rename to drivers/pci/controller/pcie-xilinx-nwl.c
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
similarity index 100%
rename from drivers/pci/host/pcie-xilinx.c
rename to drivers/pci/controller/pcie-xilinx.c
-- 
1.7.9.5

[toc] | [prev] | [next] | [standalone]


#1482936 — [RFC PATCH 04/11] pci: endpoint: functions: add an EP function to test PCI

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-14 07:20 +0200
Subject[RFC PATCH 04/11] pci: endpoint: functions: add an EP function to test PCI
Message-ID<shaM2-4De-21@gated-at.bofh.it>
In reply to#1482930
This adds a new endpoint function driver (to program the virtual
test device) making use of the EP-core library. The complete
usage of the test function is described in
Documentation/PCI/pci-test.txt (included in this commit).

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/PCI/00-INDEX                    |    3 +
 Documentation/PCI/pci-test.txt                |   79 +++++++
 drivers/pci/endpoint/Kconfig                  |    2 +
 drivers/pci/endpoint/Makefile                 |    2 +-
 drivers/pci/endpoint/functions/Kconfig        |   12 ++
 drivers/pci/endpoint/functions/Makefile       |    5 +
 drivers/pci/endpoint/functions/pci-epf-test.c |  272 +++++++++++++++++++++++++
 7 files changed, 374 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/PCI/pci-test.txt
 create mode 100644 drivers/pci/endpoint/functions/Kconfig
 create mode 100644 drivers/pci/endpoint/functions/Makefile
 create mode 100644 drivers/pci/endpoint/functions/pci-epf-test.c

diff --git a/Documentation/PCI/00-INDEX b/Documentation/PCI/00-INDEX
index e422b8151..e5a583c 100644
--- a/Documentation/PCI/00-INDEX
+++ b/Documentation/PCI/00-INDEX
@@ -14,3 +14,6 @@ pcieaer-howto.txt
 	- the PCI Express Advanced Error Reporting Driver Guide HOWTO
 pci-endpoint.txt
 	- guide to add endpoint controller driver and endpoint function driver.
+pci-test.txt
+	- description of the PCI EP function that can be used to test PCI
+	  functionality
diff --git a/Documentation/PCI/pci-test.txt b/Documentation/PCI/pci-test.txt
new file mode 100644
index 0000000..2bc796b
--- /dev/null
+++ b/Documentation/PCI/pci-test.txt
@@ -0,0 +1,79 @@
+				PCI TEST
+		    Kishon Vijay Abraham I <kishon@ti.com>
+
+Traditionally PCI RC has always been validated by using standard
+PCI cards like ethernet PCI cards or USB PCI cards or SATA PCI cards.
+However with the addition of EP-core in linux kernel, it is possible
+to configure a PCI controller that can operate in EP mode to work as
+a test device.
+
+The PCI endpoint test device is a completely software device used to
+test the endpoint functionality and serve as a sample driver for other
+PCI endpoint devices.
+
+The PCI endpoint test device has four registers:
+
+	1) PCI_ENDPOINT_TEST_COMMAND
+	2) PCI_ENDPOINT_TEST_STATUS
+	3) PCI_ENDPOINT_TEST_SRC_ADDR
+	4) PCI_ENDPOINT_TEST_DST_ADDR
+
+Since this is a virtual device, all these registers will be present
+in RAM and will be allocated using one of the standard memory allocation
+API (in this case dma_alloc_coherent)
+
+*) PCI_ENDPOINT_TEST_COMMAND:
+
+This register will be used by the host driver to indicate the function
+that the endpoint device must perform.
+
+Bitfield Description:
+  Bit 0: reset the PCI endpoint device
+  Bit 1: raise irq
+  Bit 2: Copy the data from source addr to destination address
+
+*) PCI_ENDPOINT_TEST_STATUS
+
+This register reflects the status of the PCI endpoint device.
+
+Bitfield Description:
+  Bit 0: PCI endpoint device is in initialized state
+  Bit 1: Copy is in progress
+  Bit 2: Copy is done
+  Bit 3: IRQ is raised
+  Bit 4: Source address is invalid
+  Bit 5: Destination address is invalid
+
+*) PCI_ENDPOINT_TEST_SRC_ADDR
+
+This register contains the source address for the COPY command.
+
+*) PCI_ENDPOINT_TEST_DST_ADDR
+
+This register contains the destination address for the COPY command.
+
+PCI ENDPOINT TEST DRIVER (EP SIDE)
+==================================
+
+The Endpoint side function driver is present in
+drivers/pci/endpoint/functions/pci-epf-test.c
+
+This function driver creates the PCI endpoint test device and then
+waits for commands from the host driver. If the host driver sets
+Bit 1 (raise irq) in the COMMAND register, the endpoint driver
+will raise an irq. Similarly it resets the device if Bit 0 is set
+and starts copying the data if Bit 2 is set.
+
+The function driver is also responsible for updating the STATUS
+register.
+
+PCI ENDPOINT TEST DRIVER (HOST SIDE)
+====================================
+
+The host side PCI driver is present in
+drivers/misc/pci_endpoint_test.c
+
+The PCI driver for the test device performs 3 tests
+	*) Verifying addresses programmed in BAR
+	*) Raise legacy IRQ
+	*) Copy data from source address to destination address (TODO)
diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
index f1dd206..0e3dc8c 100644
--- a/drivers/pci/endpoint/Kconfig
+++ b/drivers/pci/endpoint/Kconfig
@@ -19,5 +19,7 @@ config PCI_ENDPOINT
 
 	   If in doubt, say "N" to disable Endpoint support.
 
+source "drivers/pci/endpoint/functions/Kconfig"
+
 endmenu
 
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index 67c88bf..89310d1 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -3,4 +3,4 @@
 #
 
 obj-$(CONFIG_PCI_ENDPOINT)		:= pci-epc-core.o pci-epf-core.o \
-					   pci-ep-cfs.o
+					   pci-ep-cfs.o functions/
diff --git a/drivers/pci/endpoint/functions/Kconfig b/drivers/pci/endpoint/functions/Kconfig
new file mode 100644
index 0000000..175edad
--- /dev/null
+++ b/drivers/pci/endpoint/functions/Kconfig
@@ -0,0 +1,12 @@
+#
+# PCI Endpoint Functions
+#
+
+config PCI_EPF_TEST
+	tristate "PCI Endpoint Test driver"
+	depends on PCI_ENDPOINT
+	help
+	   Enable this configuration option to enable the test driver
+	   for PCI Endpoint.
+
+	   If in doubt, say "N" to disable Endpoint test driver.
diff --git a/drivers/pci/endpoint/functions/Makefile b/drivers/pci/endpoint/functions/Makefile
new file mode 100644
index 0000000..53c120e
--- /dev/null
+++ b/drivers/pci/endpoint/functions/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for PCI Endpoint Functions
+#
+
+obj-$(CONFIG_PCI_EPF_TEST)		:= pci-epf-test.o
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
new file mode 100644
index 0000000..a7585b1
--- /dev/null
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -0,0 +1,272 @@
+/**
+ * pci-epf-test.c - Test driver to test endpoint functionality
+ *
+ * Copyright (C) 2016 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@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 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+#include <linux/pci_regs.h>
+
+#define COMMAND_RESET			BIT(0)
+#define COMMAND_RAISE_IRQ		BIT(1)
+#define COMMAND_COPY			BIT(2)
+
+#define STATUS_INITIALIZED		BIT(0)
+#define STATUS_COPY_PROGRESS		BIT(1)
+#define STATUS_COPY_DONE		BIT(2)
+#define STATUS_IRQ_RAISED		BIT(3)
+#define STATUS_SOURCE_ADDR_INVALID	BIT(4)
+#define STATUS_DEST_ADDR_INVALID	BIT(5)
+
+#define TIMER_RESOLUTION		5
+
+struct pci_epf_test {
+	struct timer_list	timer;
+	void			*reg[6];
+	struct pci_epf		*epf;
+};
+
+struct pci_epf_test_reg {
+	u32	command;
+	u32	status;
+	u64	src_addr;
+	u64	dst_addr;
+};
+
+struct pci_epf_header test_header = {
+	.vendorid	= PCI_ANY_ID,
+	.deviceid	= PCI_ANY_ID,
+	.baseclass_code = PCI_CLASS_OTHERS,
+	.interrupt_pin	= PCI_INTERRUPT_INTA,
+};
+
+static int bar_size[] = { 512, 1024, 16384, 131072, 1048576};
+
+static void pci_epf_test_cmd_handler(unsigned long data)
+{
+	struct pci_epf_test *epf_test = (struct pci_epf_test *)data;
+	struct pci_epf *epf = epf_test->epf;
+	struct pci_epc *epc = epf->epc;
+	struct pci_epf_test_reg *reg = epf_test->reg[0];
+	unsigned long timer;
+
+	if (!reg->command)
+		goto reset_handler;
+
+	if (reg->command & COMMAND_RESET)
+		reg->status = STATUS_INITIALIZED;
+
+	if (reg->command & COMMAND_RAISE_IRQ) {
+		reg->status |= STATUS_IRQ_RAISED;
+		pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY);
+	}
+
+	reg->command = 0;
+
+reset_handler:
+	timer = jiffies + msecs_to_jiffies(TIMER_RESOLUTION);
+	mod_timer(&epf_test->timer, timer);
+}
+
+static void pci_epf_test_linkup(struct pci_epf *epf)
+{
+	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+	unsigned long timer;
+
+	setup_timer(&epf_test->timer, pci_epf_test_cmd_handler,
+		    (unsigned long)epf_test);
+	timer = jiffies + msecs_to_jiffies(TIMER_RESOLUTION);
+	mod_timer(&epf_test->timer, timer);
+}
+
+static void pci_epf_test_unbind(struct pci_epf *epf)
+{
+	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+	struct pci_epc *epc = epf->epc;
+	int bar;
+
+	del_timer(&epf_test->timer);
+	pci_epc_stop(epc);
+	for (bar = BAR_0; bar <= BAR_5; bar++) {
+		if (epf_test->reg[bar]) {
+			pci_epf_free_space(epf, epf_test->reg[bar], bar);
+			pci_epc_clear_bar(epc, bar);
+		}
+	}
+
+	epf->pci_epc_name = NULL;
+}
+
+static int pci_epf_test_set_bar(struct pci_epf *epf)
+{
+	int flags;
+	int bar;
+	int ret;
+	struct pci_epf_bar *epf_bar;
+	struct pci_epc *epc = epf->epc;
+	struct device *dev = &epf->dev;
+	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+
+	flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32;
+	if (sizeof(dma_addr_t) == 0x8)
+		flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+
+	for (bar = BAR_0; bar <= BAR_5; bar++) {
+		epf_bar = &epf->bar[bar];
+		ret = pci_epc_set_bar(epc, bar, epf_bar->phys_addr,
+				      epf_bar->size, flags);
+		if (ret) {
+			pci_epf_free_space(epf, epf_test->reg[bar], bar);
+			dev_err(dev, "failed to set BAR%d\n", bar);
+			if (bar == BAR_0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int pci_epf_test_alloc_space(struct pci_epf *epf)
+{
+	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+	struct device *dev = &epf->dev;
+	void *base;
+	int bar;
+
+	base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
+				   BAR_0);
+	if (!base) {
+		dev_err(dev, "failed to allocated register space\n");
+		return -ENOMEM;
+	}
+	epf_test->reg[0] = base;
+
+	for (bar = BAR_1; bar <= BAR_5; bar++) {
+		base = pci_epf_alloc_space(epf, bar_size[bar - 1], bar);
+		if (!base)
+			dev_err(dev, "failed to allocate space for BAR%d\n",
+				bar);
+		epf_test->reg[bar] = base;
+	}
+
+	return 0;
+}
+
+static int pci_epf_test_bind(struct pci_epf *epf)
+{
+	int ret;
+	struct pci_epf_header *header = epf->header;
+	struct pci_epc *epc = epf->epc;
+	struct device *dev = &epf->dev;
+
+	ret = pci_epc_write_header(epc, header);
+	if (ret) {
+		dev_err(dev, "configuration header write failed\n");
+		return ret;
+	}
+
+	ret = pci_epf_test_alloc_space(epf);
+	if (ret)
+		return ret;
+
+	ret = pci_epf_test_set_bar(epf);
+	if (ret)
+		return ret;
+
+	ret = pci_epc_start(epc);
+	if (ret) {
+		dev_err(dev, "failed to start endpoint controller\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pci_epf_test_probe(struct pci_epf *epf)
+{
+	struct pci_epf_test *epf_test;
+	struct device *dev = &epf->dev;
+
+	epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL);
+	if (!epf)
+		return -ENOMEM;
+
+	epf->header = &test_header;
+	epf_test->epf = epf;
+
+	epf_set_drvdata(epf, epf_test);
+	return 0;
+}
+
+static int pci_epf_test_remove(struct pci_epf *epf)
+{
+	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+
+	pci_epc_unbind_epf(epf_test->epf);
+	kfree(epf_test);
+	return 0;
+}
+
+struct pci_epf_ops ops = {
+	.unbind	= pci_epf_test_unbind,
+	.bind	= pci_epf_test_bind,
+	.linkup = pci_epf_test_linkup,
+};
+
+static const struct pci_epf_device_id pci_epf_test_ids[] = {
+	{
+		.name = "pci_epf_test",
+	},
+	{},
+};
+
+static struct pci_epf_driver test_driver = {
+	.driver.name	= "pci_epf_test",
+	.probe		= pci_epf_test_probe,
+	.remove		= pci_epf_test_remove,
+	.id_table	= pci_epf_test_ids,
+	.ops		= &ops,
+	.owner		= THIS_MODULE,
+};
+
+static int __init pci_epf_test_init(void)
+{
+	int ret;
+
+	ret = pci_epf_register_driver(&test_driver);
+	if (ret) {
+		pr_err("failed to register pci epf test driver --> %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+module_init(pci_epf_test_init);
+
+static void __exit pci_epf_test_exit(void)
+{
+	pci_epf_unregister_driver(&test_driver);
+}
+module_exit(pci_epf_test_exit);
+
+MODULE_DESCRIPTION("PCI EPF TEST DRIVER");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

[toc] | [prev] | [next] | [standalone]


#1483287

FromArnd Bergmann <arnd@arndb.de>
Date2016-09-14 15:30 +0200
Message-ID<shiqe-1oQ-23@gated-at.bofh.it>
In reply to#1482930
On Wednesday, September 14, 2016 10:41:56 AM CEST Kishon Vijay Abraham I wrote:
> This patch series
> 	*) adds PCI endpoint core layer
> 	*) modifies designware/dra7xx driver to be configured in EP mode
> 	*) adds a PCI endpoint *test* function driver

Hi Kishon,

I think this is a great start, thanks for posting early with a clear
list of limitations and TODO items.

I've added the drivers/ntb maintainers to Cc, given that there is
a certain degree of overlap between your work and the existing
code, I think they should be part of the discussion.
 
> Known Limitation:
> 	*) Does not support multi-function devices

If I understand it right, this was a problem for USB and adding
it later made it somewhat inconsistent. Maybe we can at least
try to come up with an idea of how multi-function devices
could be handled even if we don't implement it until someone
actually needs it.

Is your hardware able to make the PCIe endpoint look like
a device with multiple PCI functions, or would one have to
do this in software inside of a single PCI function if we
ever need it?

> TODO:
> 	*) access buffers in RC
> 	*) raise MSI interrupts
> 	*) Enable user space control for the RC side PCI driver

The user space control would end up just being one of several
gadget drivers, right? E.g. gadget drivers for standard hardware
(8250 uart, ATA, NVMe, some ethernet) could be done as kernel
drivers while a user space driver can be used for things that
are more unusual and that don't need to interface to another
part of the kernel?

> 	*) Adapt all other users of designware to use the new design (only
> 	   dra7xx has been adapted)

I don't fully understand this part. Does every designware based
driver need modifications, or are the changes to the
generic parts of the designware driver enough to make it
work for the simpler platforms?

> HOW TO:
> 
> ON THE EP SIDE:
> ***************
> 
> /* EP function is configured using configfs */
> # mount -t configfs none /sys/kernel/config
> 
> /* PCI EP core layer creates "pci_ep" entry in configfs */
> # cd /sys/kernel/config/pci_ep/
> 
> /*
>  * This is the 1st step in creating an endpoint function. This
>  * creates the endpoint function device *instance*. The string
>  * before the .<num> suffix will identify the driver this
>  * EP function will bind to.
>  * Just pci_epf_test is also valid. The .<num> suffix is used
>  * if there are multiple PCI controllers and all of them wants
>  * to use the same function.
>  */
> # mkdir pci_epf_test.0

I haven't used USB gadgets, but I assume this is modeled around
the same interface. If there are notable differences, please mention
what they are. Otherwise the general concept seems rather nice to me.

>  drivers/pci/{host => controller}/Kconfig           |  109 +++++-
>  drivers/pci/{host => controller}/Makefile          |    2 +
>  drivers/pci/{host => controller}/pci-aardvark.c    |    0
>  drivers/pci/{host => controller}/pci-dra7xx.c      |  340 +++++++++++++----
>  drivers/pci/{host => controller}/pci-exynos.c      |    0
>  drivers/pci/{host => controller}/pci-host-common.c |    0
>  .../pci/{host => controller}/pci-host-generic.c    |    0
>  drivers/pci/{host => controller}/pci-hyperv.c      |    0
>  drivers/pci/{host => controller}/pci-imx6.c        |    0
>  drivers/pci/{host => controller}/pci-keystone-dw.c |    0
>  drivers/pci/{host => controller}/pci-keystone.c    |    0
>  drivers/pci/{host => controller}/pci-keystone.h    |    0

Maybe it's better to wait before moving it around, this will make
it harder for you to rebase the patch series while you are working on
it and other people are working on the existing code.

I'd suggest dropping the rename patches for the moment and just work
in drivers/pci/host.

Let's talk (high-level) about the DT binding. I see that the way
you have done it here, one will need to have a different .dtb file
for a machine depending on whether the PCIe is used in host or
endpoint mode. The advantage of this way is that it's a much
cleaner binding (PCIe host bindings are a mess, and adding more
options to it will only make it worse), the downside is that
you can't decide at runtime what you want to use it for. E.g.
connecting two identical machines over PCIe requires deciding
in the bootloader which one is the endpoint, or using DT
overlays, which may be awkward for some users. Is this a realistic
use case, or do you expect that all machines will only ever be
used in one of the two ways?

	Arnd

[toc] | [prev] | [next] | [standalone]


#1483916

FromKishon Vijay Abraham I <kishon@ti.com>
Date2016-09-15 10:40 +0200
Message-ID<shAn7-4EW-13@gated-at.bofh.it>
In reply to#1483287
Hi Arnd,

On Wednesday 14 September 2016 06:55 PM, Arnd Bergmann wrote:
> On Wednesday, September 14, 2016 10:41:56 AM CEST Kishon Vijay Abraham I wrote:
>> This patch series
>> 	*) adds PCI endpoint core layer
>> 	*) modifies designware/dra7xx driver to be configured in EP mode
>> 	*) adds a PCI endpoint *test* function driver
> 
> Hi Kishon,
> 
> I think this is a great start, thanks for posting early with a clear
> list of limitations and TODO items.

Thank you :-)
> 
> I've added the drivers/ntb maintainers to Cc, given that there is
> a certain degree of overlap between your work and the existing
> code, I think they should be part of the discussion.
>  
>> Known Limitation:
>> 	*) Does not support multi-function devices
> 
> If I understand it right, this was a problem for USB and adding
> it later made it somewhat inconsistent. Maybe we can at least
> try to come up with an idea of how multi-function devices
> could be handled even if we don't implement it until someone
> actually needs it.

Actually IMO multi-function device in PCI should be much simpler than it is for
USB. In the case of USB, all the functions in a multi-function device will
share the same *usb configuration* . (USB device can have multiple
configuration but only one can be enabled at a time). A multi-function USB
device will still have a single vendor-id/product-id/class... So I think a
separate library (composite.c) in USB makes sense.

But in the case of PCI, every function can be treated independently since all
the functions have it's own 4KB configuration space. Each function can be
configured independently. Each can have it's own vendor-id/product-id/class..
I'm not sure if we'll need a separate library for PCI like we have for USB.

Now the restriction for not allowing multi-function device is because of the
following structure definition.

struct pci_epc {
	..
        struct pci_epf *epf;
	..
};

EPC has a single reference to EPF and it is used *only* to notify the function
driver when the link is up. (If this can be changed to use notification
mechanism, multi-function devices can be supported here)

One more place where this restriction arises is in designware driver

struct dw_pcie_ep {
	..
        u8 bar_to_atu[6];
	..
};

We use single ATU window to configure a BAR (in BAR). If there are multiple
functions, then this should also be modified since each function has 6 BARs.

This can be fixed without much effort unless some other issue props up.

> 
> Is your hardware able to make the PCIe endpoint look like
> a device with multiple PCI functions, or would one have to
> do this in software inside of a single PCI function if we
> ever need it?

The hardware I have doesn't support multiple PCI functions (like having a
separate configuration space for each function). It has a dedicated space for
configuration space supporting only one function. [Section 24.9.7.3.2
PCIe_SS_EP_CFG_DBICS Register Description in  [1]].

yeah, it has to be done in software (but that won't be multi-function device in
PCI terms).

[1] -> http://www.ti.com/lit/ug/spruhz6g/spruhz6g.pdf
> 
>> TODO:
>> 	*) access buffers in RC
>> 	*) raise MSI interrupts
>> 	*) Enable user space control for the RC side PCI driver
> 
> The user space control would end up just being one of several
> gadget drivers, right? E.g. gadget drivers for standard hardware
> (8250 uart, ATA, NVMe, some ethernet) could be done as kernel
> drivers while a user space driver can be used for things that
> are more unusual and that don't need to interface to another
> part of the kernel?

Actually I didn't mean that. It was more with respect to the host side PCI test
driver (drivers/misc/pci_endpoint_test.c). Right now it validates BAR, irq
itself. I wanted to change this so that the user controls which tests to run.
(Like for USB gadget zero tests, testusb.c invokes ioctls to perform various
tests). Similarly I want to have a userspace program invoke pci_endpoint_test
to perform various PCI tests.
> 
>> 	*) Adapt all other users of designware to use the new design (only
>> 	   dra7xx has been adapted)
> 
> I don't fully understand this part. Does every designware based
> driver need modifications, or are the changes to the
> generic parts of the designware driver enough to make it
> work for the simpler platforms?

I have changed the core designware driver structures (like previously the
platform drivers will only use pcie_port, but now I introduced struct dw_pcie
to support both host and endpoint). This will break (compilation failure) all
the designware based drivers (except dra7xx). All these drivers should be
adapted to the new change (even if they work only in host mode these has to be
adapted).
> 
>> HOW TO:
>>
>> ON THE EP SIDE:
>> ***************
>>
>> /* EP function is configured using configfs */
>> # mount -t configfs none /sys/kernel/config
>>
>> /* PCI EP core layer creates "pci_ep" entry in configfs */
>> # cd /sys/kernel/config/pci_ep/
>>
>> /*
>>  * This is the 1st step in creating an endpoint function. This
>>  * creates the endpoint function device *instance*. The string
>>  * before the .<num> suffix will identify the driver this
>>  * EP function will bind to.
>>  * Just pci_epf_test is also valid. The .<num> suffix is used
>>  * if there are multiple PCI controllers and all of them wants
>>  * to use the same function.
>>  */
>> # mkdir pci_epf_test.0
> 
> I haven't used USB gadgets, but I assume this is modeled around
> the same interface. If there are notable differences, please mention
> what they are. Otherwise the general concept seems rather nice to me.

Yeah, both USB gadget and PCI endpoint use configfs interface but the semantics
are quite different.

Every directory in *usb_gadget* corresponds to a gadget device, and the gadget
device has a functions sub-directory which has the USB functions. And these
directories have fields or attributes specific to USB.

But in the case of PCI, every directory in *pci_ep* corresponds to a PCI
function and it has fields or attributes specific to PCI function.

The main reason for using configfs for PCI endpoint is to give the users to
control "which function has to be bound to which controller". The same concept
is used for USB gadget as well but there it is "which gadget device has to be
bound to which controller".
> 
>>  drivers/pci/{host => controller}/Kconfig           |  109 +++++-
>>  drivers/pci/{host => controller}/Makefile          |    2 +
>>  drivers/pci/{host => controller}/pci-aardvark.c    |    0
>>  drivers/pci/{host => controller}/pci-dra7xx.c      |  340 +++++++++++++----
>>  drivers/pci/{host => controller}/pci-exynos.c      |    0
>>  drivers/pci/{host => controller}/pci-host-common.c |    0
>>  .../pci/{host => controller}/pci-host-generic.c    |    0
>>  drivers/pci/{host => controller}/pci-hyperv.c      |    0
>>  drivers/pci/{host => controller}/pci-imx6.c        |    0
>>  drivers/pci/{host => controller}/pci-keystone-dw.c |    0
>>  drivers/pci/{host => controller}/pci-keystone.c    |    0
>>  drivers/pci/{host => controller}/pci-keystone.h    |    0
> 
> Maybe it's better to wait before moving it around, this will make
> it harder for you to rebase the patch series while you are working on
> it and other people are working on the existing code.

These patches just do "mv drivers/pci/host  drivers/pci/controller", so I guess
irrespective of the changes in the existing driver it should just move. Anyways
I have to check this.
> 
> I'd suggest dropping the rename patches for the moment and just work
> in drivers/pci/host.

Okay.
> 
> Let's talk (high-level) about the DT binding. I see that the way
> you have done it here, one will need to have a different .dtb file
> for a machine depending on whether the PCIe is used in host or
> endpoint mode. The advantage of this way is that it's a much
> cleaner binding (PCIe host bindings are a mess, and adding more
> options to it will only make it worse), the downside is that
> you can't decide at runtime what you want to use it for. E.g.
> connecting two identical machines over PCIe requires deciding
> in the bootloader which one is the endpoint, or using DT
> overlays, which may be awkward for some users. Is this a realistic
> use case, or do you expect that all machines will only ever be
> used in one of the two ways?

It would definitely be nice to select the mode at runtime. Even for this patch
series, I added a temporary dtsi patch to configure the pci controller in EP
mode (which can't be merged since the same controller is also used to test RC).

Thanks
Kishon

[toc] | [prev] | [next] | [standalone]


#1488883

FromArnd Bergmann <arnd@arndb.de>
Date2016-09-22 15:40 +0200
Message-ID<skcoh-6Y0-17@gated-at.bofh.it>
In reply to#1483916
On Thursday, September 15, 2016 2:03:05 PM CEST Kishon Vijay Abraham I wrote:
> On Wednesday 14 September 2016 06:55 PM, Arnd Bergmann wrote:
> > On Wednesday, September 14, 2016 10:41:56 AM CEST Kishon Vijay Abraham I wrote:
> > I've added the drivers/ntb maintainers to Cc, given that there is
> > a certain degree of overlap between your work and the existing
> > code, I think they should be part of the discussion.
> >  
> >> Known Limitation:
> >> 	*) Does not support multi-function devices
> > 
> > If I understand it right, this was a problem for USB and adding
> > it later made it somewhat inconsistent. Maybe we can at least
> > try to come up with an idea of how multi-function devices
> > could be handled even if we don't implement it until someone
> > actually needs it.
> 
> Actually IMO multi-function device in PCI should be much simpler than it is for
> USB. In the case of USB, all the functions in a multi-function device will
> share the same *usb configuration* . (USB device can have multiple
> configuration but only one can be enabled at a time). A multi-function USB
> device will still have a single vendor-id/product-id/class... So I think a
> separate library (composite.c) in USB makes sense.

Ok, makes sense.

> But in the case of PCI, every function can be treated independently since all
> the functions have it's own 4KB configuration space. Each function can be
> configured independently. Each can have it's own vendor-id/product-id/class..
> I'm not sure if we'll need a separate library for PCI like we have for USB.

I think it depends on whether we want to add the software multi-function
support you mention.

> Now the restriction for not allowing multi-function device is because of the
> following structure definition.
> 
> struct pci_epc {
> 	..
>         struct pci_epf *epf;
> 	..
> };
> 
> EPC has a single reference to EPF and it is used *only* to notify the function
> driver when the link is up. (If this can be changed to use notification
> mechanism, multi-function devices can be supported here)
> 
> One more place where this restriction arises is in designware driver
> 
> struct dw_pcie_ep {
> 	..
>         u8 bar_to_atu[6];
> 	..
> };
> 
> We use single ATU window to configure a BAR (in BAR). If there are multiple
> functions, then this should also be modified since each function has 6 BARs.
> 
> This can be fixed without much effort unless some other issue props up.

Ok.

> > 
> > Is your hardware able to make the PCIe endpoint look like
> > a device with multiple PCI functions, or would one have to
> > do this in software inside of a single PCI function if we
> > ever need it?
> 
> The hardware I have doesn't support multiple PCI functions (like having a
> separate configuration space for each function). It has a dedicated space for
> configuration space supporting only one function. [Section 24.9.7.3.2
> PCIe_SS_EP_CFG_DBICS Register Description in  [1]].
> 
> yeah, it has to be done in software (but that won't be multi-function device in
> PCI terms).
> 
> [1] -> http://www.ti.com/lit/ug/spruhz6g/spruhz6g.pdf

Ok, so in theory there can be other hardware (and quite likely is)
that supports multiple functions, and we can extend the framework
to support them without major obstacles, but your hardware doesn't,
so you kept it simple with one hardcoded function, right?

Seems completely reasonable to me.

> >> TODO:
> >> 	*) access buffers in RC
> >> 	*) raise MSI interrupts
> >> 	*) Enable user space control for the RC side PCI driver
> > 
> > The user space control would end up just being one of several
> > gadget drivers, right? E.g. gadget drivers for standard hardware
> > (8250 uart, ATA, NVMe, some ethernet) could be done as kernel
> > drivers while a user space driver can be used for things that
> > are more unusual and that don't need to interface to another
> > part of the kernel?
> 
> Actually I didn't mean that. It was more with respect to the host side PCI test
> driver (drivers/misc/pci_endpoint_test.c). Right now it validates BAR, irq
> itself. I wanted to change this so that the user controls which tests to run.
> (Like for USB gadget zero tests, testusb.c invokes ioctls to perform various
> tests). Similarly I want to have a userspace program invoke pci_endpoint_test
> to perform various PCI tests.

Ok, I see. So what I described above would be yet another function
driver that can be implemented, but so far, you have not planned
to do that because there was not need, right?

> > 
> >> 	*) Adapt all other users of designware to use the new design (only
> >> 	   dra7xx has been adapted)
> > 
> > I don't fully understand this part. Does every designware based
> > driver need modifications, or are the changes to the
> > generic parts of the designware driver enough to make it
> > work for the simpler platforms?
> 
> I have changed the core designware driver structures (like previously the
> platform drivers will only use pcie_port, but now I introduced struct dw_pcie
> to support both host and endpoint). This will break (compilation failure) all
> the designware based drivers (except dra7xx). All these drivers should be
> adapted to the new change (even if they work only in host mode these has to be
> adapted).

Ah, so we have to do two separate modifications to each designware driver:

a) make it work with your patch (mandatory)
b) make it support endpoint mode (optional)

> >> HOW TO:
> >>
> >> ON THE EP SIDE:
> >> ***************
> >>
> >> /* EP function is configured using configfs */
> >> # mount -t configfs none /sys/kernel/config
> >>
> >> /* PCI EP core layer creates "pci_ep" entry in configfs */
> >> # cd /sys/kernel/config/pci_ep/
> >>
> >> /*
> >>  * This is the 1st step in creating an endpoint function. This
> >>  * creates the endpoint function device *instance*. The string
> >>  * before the .<num> suffix will identify the driver this
> >>  * EP function will bind to.
> >>  * Just pci_epf_test is also valid. The .<num> suffix is used
> >>  * if there are multiple PCI controllers and all of them wants
> >>  * to use the same function.
> >>  */
> >> # mkdir pci_epf_test.0
> > 
> > I haven't used USB gadgets, but I assume this is modeled around
> > the same interface. If there are notable differences, please mention
> > what they are. Otherwise the general concept seems rather nice to me.
> 
> Yeah, both USB gadget and PCI endpoint use configfs interface but the semantics
> are quite different.
> 
> Every directory in *usb_gadget* corresponds to a gadget device, and the gadget
> device has a functions sub-directory which has the USB functions. And these
> directories have fields or attributes specific to USB.
> 
> But in the case of PCI, every directory in *pci_ep* corresponds to a PCI
> function and it has fields or attributes specific to PCI function.

Ok, I see.

> The main reason for using configfs for PCI endpoint is to give the users to
> control "which function has to be bound to which controller". The same concept
> is used for USB gadget as well but there it is "which gadget device has to be
> bound to which controller".

We should still find out whether it's important that you can have
a single PCI function with a software multi-function support of some
sort. We'd still be limited to six BARs in total, and would also need
something to identify those sub-functions, so implementing that might
get quite hairy.

Possibly this could be done at a higher level, e.g. by implementing
a PCI-virtio multiplexer that can host multiple virtio based devices
inside of a single PCI function. If we think that would be a good idea,
we should make sure the configfs interface is extensible enough to
handle that.

One use case I have in mind for this is to have a PCI function that
can use virtio to provide rootfs (virtio-blk or 9pfs), network
and console to the system that implements the PCI function (note
that this is the opposite direction of what almost everyone else
uses PCI devices for).

> > Let's talk (high-level) about the DT binding. I see that the way
> > you have done it here, one will need to have a different .dtb file
> > for a machine depending on whether the PCIe is used in host or
> > endpoint mode. The advantage of this way is that it's a much
> > cleaner binding (PCIe host bindings are a mess, and adding more
> > options to it will only make it worse), the downside is that
> > you can't decide at runtime what you want to use it for. E.g.
> > connecting two identical machines over PCIe requires deciding
> > in the bootloader which one is the endpoint, or using DT
> > overlays, which may be awkward for some users. Is this a realistic
> > use case, or do you expect that all machines will only ever be
> > used in one of the two ways?
> 
> It would definitely be nice to select the mode at runtime. Even for this patch
> series, I added a temporary dtsi patch to configure the pci controller in EP
> mode (which can't be merged since the same controller is also used to test RC).

I think it should be possible to have two bindings that define a
distinct set of properties, and have one node that is marked
as "compatible" with both of them in order to let the OS choose
one or the other mode.

	Arnd

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web