linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH] pci: support for configurable PCI endpoint
@ 2016-09-13 17:10 Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: add EP core layer to enable EP controller and EP functions Kishon Vijay Abraham I
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

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
	*) MSI interrupts
	*) Enable user space control for the RC side PCI driver
	*) Adapt all other users of designware to use the new design

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

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

* [RFC PATCH] pci: endpoint: add EP core layer to enable EP controller and EP functions
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: introduce configfs entry for configuring " Kishon Vijay Abraham I
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

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

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

* [RFC PATCH] pci: endpoint: introduce configfs entry for configuring EP functions
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: add EP core layer to enable EP controller and EP functions Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] Documentation: PCI: guide to use PCI Endpoint Core Layer Kishon Vijay Abraham I
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

Introduce a new configfs entry to configure the EP function (like
configuring the standard configuration header entries) and to
bind the function with a controller.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/Kconfig      |    4 +-
 drivers/pci/endpoint/Makefile     |    3 +-
 drivers/pci/endpoint/pci-ep-cfs.c |  275 +++++++++++++++++++++++++++++++++++++
 3 files changed, 280 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pci/endpoint/pci-ep-cfs.c

diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
index a6d827c..f1dd206 100644
--- a/drivers/pci/endpoint/Kconfig
+++ b/drivers/pci/endpoint/Kconfig
@@ -13,7 +13,9 @@ config PCI_ENDPOINT
 
 	   Enabling this option will build the endpoint library, which
 	   includes endpoint controller library and endpoint function
-	   library.
+	   library. This will also enable the configfs entry required to
+	   configure the endpoint function and used to bind the
+	   function with a endpoint controller.
 
 	   If in doubt, say "N" to disable Endpoint support.
 
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index dbc5517..67c88bf 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -2,4 +2,5 @@
 # Makefile for PCI Endpoint Support
 #
 
-obj-$(CONFIG_PCI_ENDPOINT)		:= pci-epc-core.o pci-epf-core.o
+obj-$(CONFIG_PCI_ENDPOINT)		:= pci-epc-core.o pci-epf-core.o \
+					   pci-ep-cfs.o
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
new file mode 100644
index 0000000..d11ae34
--- /dev/null
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -0,0 +1,275 @@
+/**
+ * pci-ep-cfs.c - configfs to configure the PCI endpoint
+ *
+ * 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/configfs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
+struct pci_epf_info {
+	struct config_item pci_epf;
+	struct pci_epf *epf;
+};
+
+static inline struct pci_epf_info *to_pci_epf_info(struct config_item *item)
+{
+	return container_of(item, struct pci_epf_info, pci_epf);
+}
+
+#define PCI_EPF_HEADER_R(_name)	\
+static ssize_t pci_epf_##_name##_show(struct config_item *item,		\
+			char *page)					       \
+{									       \
+	return sprintf(page, "0x%04x\n",				       \
+		       to_pci_epf_info(item)->epf->header->_name);	       \
+}
+
+#define PCI_EPF_HEADER_W_u32(_name)	\
+static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
+					     const char *page, size_t len)     \
+{									       \
+	u32 val;							       \
+	int ret;							       \
+	ret = kstrtou32(page, 0, &val);					       \
+	if (ret)							       \
+		return ret;						       \
+	to_pci_epf_info(item)->epf->header->_name = val;		       \
+	return len;							       \
+}
+
+#define PCI_EPF_HEADER_W_u16(_name)	\
+static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
+					     const char *page, size_t len)     \
+{									       \
+	u16 val;							       \
+	int ret;							       \
+	ret = kstrtou16(page, 0, &val);					       \
+	if (ret)							       \
+		return ret;						       \
+	to_pci_epf_info(item)->epf->header->_name = val;		       \
+	return len;							       \
+}
+
+#define PCI_EPF_HEADER_W_u8(_name)	\
+static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
+					     const char *page, size_t len)     \
+{									       \
+	u8 val;								       \
+	int ret;							       \
+	ret = kstrtou8(page, 0, &val);					       \
+	if (ret)							       \
+		return ret;						       \
+	to_pci_epf_info(item)->epf->header->_name = val;		       \
+	return len;							       \
+}
+
+#define PCI_EPF_HEADER_RW(_name, _type)	\
+	PCI_EPF_HEADER_R(_name)		\
+	PCI_EPF_HEADER_W_##_type(_name)
+
+static ssize_t pci_epf_peripheral_store(struct config_item *item,
+					    const char *page, size_t len)
+{
+	struct pci_epf_info *epf_info = to_pci_epf_info(item);
+	char *dev_name;
+
+	dev_name = kstrdup(page, GFP_KERNEL);
+	if (!dev_name)
+		return -ENOMEM;
+	if (dev_name[len - 1] == '\n')
+		dev_name[len - 1] = '\0';
+
+	epf_info->epf->hw_devname = dev_name;
+	return len;
+}
+
+static ssize_t pci_epf_peripheral_show(struct config_item *item,
+					   char *page)
+{
+	return sprintf(page, "%s\n",
+		       to_pci_epf_info(item)->epf->hw_devname);
+}
+
+static ssize_t pci_epf_function_show(struct config_item *item,
+					   char *page)
+{
+	return sprintf(page, "%s\n",
+		       to_pci_epf_info(item)->epf->name);
+}
+
+static ssize_t pci_epf_epc_store(struct config_item *item,
+					    const char *page, size_t len)
+{
+	int ret;
+	struct pci_epf_info *epf_info = to_pci_epf_info(item);
+	char *epc_name;
+
+	epc_name = kstrdup(page, GFP_KERNEL);
+	if (!epc_name)
+		return -ENOMEM;
+	if (epc_name[len - 1] == '\n')
+		epc_name[len - 1] = '\0';
+
+	if (epf_info->epf->epc)
+		pci_epc_unbind_epf(epf_info->epf);
+
+	epf_info->epf->pci_epc_name = epc_name;
+	ret = pci_epc_bind_epf(epf_info->epf);
+	if (ret)
+		return -EINVAL;
+
+	return len;
+}
+
+static ssize_t pci_epf_epc_show(struct config_item *item,
+					   char *page)
+{
+	return sprintf(page, "%s\n",
+		       to_pci_epf_info(item)->epf->pci_epc_name);
+}
+
+PCI_EPF_HEADER_RW(vendorid, u16);
+PCI_EPF_HEADER_RW(deviceid, u16);
+PCI_EPF_HEADER_RW(revid, u16);
+PCI_EPF_HEADER_RW(progif_code, u16);
+PCI_EPF_HEADER_RW(subclass_code, u16);
+PCI_EPF_HEADER_RW(baseclass_code, u16);
+PCI_EPF_HEADER_RW(cache_line_size, u16);
+PCI_EPF_HEADER_RW(subsys_vendor_id, u16);
+PCI_EPF_HEADER_RW(subsys_id, u16);
+PCI_EPF_HEADER_RW(interrupt_pin, u16);
+
+CONFIGFS_ATTR(pci_epf_, vendorid);
+CONFIGFS_ATTR(pci_epf_, deviceid);
+CONFIGFS_ATTR(pci_epf_, revid);
+CONFIGFS_ATTR(pci_epf_, progif_code);
+CONFIGFS_ATTR(pci_epf_, subclass_code);
+CONFIGFS_ATTR(pci_epf_, baseclass_code);
+CONFIGFS_ATTR(pci_epf_, cache_line_size);
+CONFIGFS_ATTR(pci_epf_, subsys_vendor_id);
+CONFIGFS_ATTR(pci_epf_, subsys_id);
+CONFIGFS_ATTR(pci_epf_, interrupt_pin);
+CONFIGFS_ATTR(pci_epf_, peripheral);
+CONFIGFS_ATTR_RO(pci_epf_, function);
+CONFIGFS_ATTR(pci_epf_, epc);
+
+static struct configfs_attribute *pci_epf_attrs[] = {
+	&pci_epf_attr_vendorid,
+	&pci_epf_attr_deviceid,
+	&pci_epf_attr_revid,
+	&pci_epf_attr_progif_code,
+	&pci_epf_attr_subclass_code,
+	&pci_epf_attr_baseclass_code,
+	&pci_epf_attr_cache_line_size,
+	&pci_epf_attr_subsys_vendor_id,
+	&pci_epf_attr_subsys_id,
+	&pci_epf_attr_interrupt_pin,
+	&pci_epf_attr_peripheral,
+	&pci_epf_attr_function,
+	&pci_epf_attr_epc,
+	NULL,
+};
+
+static void pci_epf_release(struct config_item *item)
+{
+	struct pci_epf_info *epf_info = to_pci_epf_info(item);
+
+	pci_epf_destroy(epf_info->epf);
+	kfree(epf_info);
+}
+
+static struct configfs_item_operations pci_epf_ops = {
+	.release		= pci_epf_release,
+};
+
+static struct config_item_type pci_epf_type = {
+	.ct_item_ops	= &pci_epf_ops,
+	.ct_attrs	= pci_epf_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_item *pci_epf_make(struct config_group *group,
+					const char *name)
+{
+	struct pci_epf_info *epf_info;
+	struct pci_epf *epf;
+
+	epf_info = kzalloc(sizeof(*epf_info), GFP_KERNEL);
+	if (!epf_info)
+		return ERR_PTR(-ENOMEM);
+
+	epf = pci_epf_create(name);
+	if (IS_ERR(epf)) {
+		pr_err("failed to create endpoint function device\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	epf_info->epf = epf;
+
+	config_item_init_type_name(&epf_info->pci_epf, name,
+				   &pci_epf_type);
+
+	return &epf_info->pci_epf;
+}
+
+static struct configfs_group_operations pci_ep_ops = {
+	.make_item	= pci_epf_make,
+};
+
+static struct config_item_type pci_ep_type = {
+	.ct_group_ops	= &pci_ep_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct configfs_subsystem pci_ep_cfs_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "pci_ep",
+			.ci_type = &pci_ep_type,
+		},
+	},
+	.su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex),
+};
+
+static int __init pci_ep_cfs_init(void)
+{
+	int ret;
+
+	config_group_init(&pci_ep_cfs_subsys.su_group);
+
+	ret = configfs_register_subsystem(&pci_ep_cfs_subsys);
+	if (ret)
+		pr_err("Error %d while registering subsystem %s\n",
+		       ret, pci_ep_cfs_subsys.su_group.cg_item.ci_namebuf);
+
+	return ret;
+}
+module_init(pci_ep_cfs_init);
+
+static void __exit pci_ep_cfs_exit(void)
+{
+	configfs_unregister_subsystem(&pci_ep_cfs_subsys);
+}
+module_exit(pci_ep_cfs_exit);
+
+MODULE_DESCRIPTION("PCI EP CONFIGFS");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

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

* [RFC PATCH] Documentation: PCI: guide to use PCI Endpoint Core Layer
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: add EP core layer to enable EP controller and EP functions Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: introduce configfs entry for configuring " Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: functions: add an EP function to test PCI Kishon Vijay Abraham I
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

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

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

* [RFC PATCH] pci: endpoint: functions: add an EP function to test PCI
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (2 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] Documentation: PCI: guide to use PCI Endpoint Core Layer Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: rename *host* directory to *controller* Kishon Vijay Abraham I
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

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

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

* [RFC PATCH] pci: rename *host* directory to *controller*
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (3 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: functions: add an EP function to test PCI Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: controller: split designware into *core* and *host* Kishon Vijay Abraham I
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

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

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

* [RFC PATCH] pci: controller: split designware into *core* and *host*
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (4 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] pci: rename *host* directory to *controller* Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: controller: designware: Add EP mode support Kishon Vijay Abraham I
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

No functional change. Split the designware core driver into
*core* driver and *host* only driver. This is in preparation
to add endpoint support in designware. The *endpoint* driver will
reuse the *core* driver.

This also modifies the dra7xx code to use the new architecture.
TODO: All other platforms using designware core should also
be modified accordingly.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/Kconfig                     |   48 +-
 drivers/pci/controller/Makefile                    |    1 +
 drivers/pci/controller/pci-dra7xx.c                |  117 +++-
 .../{pcie-designware.c => pcie-designware-host.c}  |  294 ++------
 drivers/pci/controller/pcie-designware.c           |  741 ++------------------
 drivers/pci/controller/pcie-designware.h           |  158 ++++-
 6 files changed, 367 insertions(+), 992 deletions(-)
 copy drivers/pci/controller/{pcie-designware.c => pcie-designware-host.c} (64%)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 4c55c2d..249db74 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -3,13 +3,29 @@ menu "PCI controller drivers"
 config PCI_DRA7XX
 	bool "TI DRA7xx PCIe controller"
 	depends on OF && HAS_IOMEM && TI_PIPE3
+	help
+	 Enables support for the PCIe controller in the DRA7xx SoC. There
+	 are two instances of PCIe controller in DRA7xx. This controller can
+	 work either as EP or RC. In order to enable host specific features
+	 PCI_DRA7XX_HOST must be selected. This reuses the Designware core.
+
+if PCI_DRA7XX
+
+choice
+	bool "PCIe Mode"
+
+config PCI_DRA7XX_HOST
+	bool "Host Only Mode"
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
-	select PCIE_DW
+	select PCIE_DW_HOST
 	help
-	 Enables support for the PCIe controller in the DRA7xx SoC.  There
-	 are two instances of PCIe controller in DRA7xx.  This controller can
-	 act both as EP and RC.  This reuses the Designware core.
+	 Enables support for the PCIe controller in the DRA7xx SoC to work in
+	 host mode.
+
+endchoice
+
+endif
 
 config PCI_MVEBU
 	bool "Marvell EBU PCIe controller"
@@ -44,7 +60,7 @@ config PCIE_DW_PLAT
 	bool "Platform bus based DesignWare PCIe Controller"
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
-	select PCIE_DW
+	select PCIE_DW_HOST
 	---help---
 	 This selects the DesignWare PCIe controller support. Select this if
 	 you have a PCIe controller on Platform bus.
@@ -55,16 +71,20 @@ config PCIE_DW_PLAT
 
 config PCIE_DW
 	bool
+
+config PCIE_DW_HOST
+	bool
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
+	select PCIE_DW
 
 config PCI_EXYNOS
 	bool "Samsung Exynos PCIe controller"
 	depends on SOC_EXYNOS5440
 	depends on PCI_MSI_IRQ_DOMAIN
 	select PCIEPORTBUS
-	select PCIE_DW
 	depends on PCI
+	select PCIE_DW_HOST
 
 config PCI_IMX6
 	bool "Freescale i.MX6 PCIe controller"
@@ -72,7 +92,7 @@ config PCI_IMX6
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
 	select PCIEPORTBUS
-	select PCIE_DW
+	select PCIE_DW_HOST
 
 config PCI_TEGRA
 	bool "NVIDIA Tegra PCIe controller"
@@ -121,7 +141,7 @@ config PCIE_SPEAR13XX
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
 	select PCIEPORTBUS
-	select PCIE_DW
+	select PCIE_DW_HOST
 	help
 	  Say Y here if you want PCIe support on SPEAr13XX SoCs.
 
@@ -130,7 +150,7 @@ config PCI_KEYSTONE
 	depends on ARCH_KEYSTONE
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
-	select PCIE_DW
+	select PCIE_DW_HOST
 	select PCIEPORTBUS
 	help
 	  Say Y here if you want to enable PCI controller support on Keystone
@@ -172,7 +192,7 @@ config PCI_LAYERSCAPE
 	depends on OF && (ARM || ARCH_LAYERSCAPE)
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
-	select PCIE_DW
+	select PCIE_DW_HOST
 	select MFD_SYSCON
 	help
 	  Say Y here if you want PCIe controller support on Layerscape SoCs.
@@ -248,7 +268,7 @@ config PCI_HISI
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
 	select PCIEPORTBUS
-	select PCIE_DW
+	select PCIE_DW_HOST
 	help
 	  Say Y here if you want PCIe controller support on HiSilicon
 	  Hip05 and Hip06 SoCs
@@ -258,7 +278,7 @@ config PCIE_QCOM
 	depends on ARCH_QCOM && OF
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
-	select PCIE_DW
+	select PCIE_DW_HOST
 	select PCIEPORTBUS
 	help
 	  Say Y here to enable PCIe controller support on Qualcomm SoCs. The
@@ -286,7 +306,7 @@ config PCIE_ARMADA_8K
 	depends on ARCH_MVEBU
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
-	select PCIE_DW
+	select PCIE_DW_HOST
 	select PCIEPORTBUS
 	help
 	  Say Y here if you want to enable PCIe controller support on
@@ -299,7 +319,7 @@ config PCIE_ARTPEC6
 	depends on MACH_ARTPEC6
 	depends on PCI_MSI_IRQ_DOMAIN
 	depends on PCI
-	select PCIE_DW
+	select PCIE_DW_HOST
 	select PCIEPORTBUS
 	help
 	  Say Y here to enable PCIe controller support on Axis ARTPEC-6
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 8843410..ee6bb85 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o
 obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
 obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
diff --git a/drivers/pci/controller/pci-dra7xx.c b/drivers/pci/controller/pci-dra7xx.c
index 81b3949..dc5b8ef 100644
--- a/drivers/pci/controller/pci-dra7xx.c
+++ b/drivers/pci/controller/pci-dra7xx.c
@@ -68,10 +68,10 @@ struct dra7xx_pcie {
 	struct phy		**phy;
 	int			phy_count;
 	struct device		*dev;
-	struct pcie_port	pp;
+	struct dw_pcie		*pci;
 };
 
-#define to_dra7xx_pcie(x)	container_of((x), struct dra7xx_pcie, pp)
+#define to_dra7xx_pcie(x)	dev_get_drvdata((x)->dev)
 
 static inline u32 dra7xx_pcie_readl(struct dra7xx_pcie *pcie, u32 offset)
 {
@@ -84,50 +84,54 @@ static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset,
 	writel(value, pcie->base + offset);
 }
 
-static inline u32 dra7xx_pcie_readl_rc(struct pcie_port *pp, u32 offset)
+static inline u32 dra7xx_pcie_readl_dbi(void __iomem *base, u32 offset)
 {
-	return readl(pp->dbi_base + offset);
+	return readl(base + offset);
 }
 
-static inline void dra7xx_pcie_writel_rc(struct pcie_port *pp, u32 offset,
-					 u32 value)
+static inline void dra7xx_pcie_writel_dbi(void __iomem *base, u32 offset,
+					  u32 value)
 {
-	writel(value, pp->dbi_base + offset);
+	writel(value, base + offset);
 }
 
-static int dra7xx_pcie_link_up(struct pcie_port *pp)
+static int dra7xx_pcie_link_up(struct dw_pcie *pci)
 {
-	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
 	u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS);
 
 	return !!(reg & LINK_UP);
 }
 
-static int dra7xx_pcie_establish_link(struct pcie_port *pp)
+static int dra7xx_pcie_start_link(struct dw_pcie *pci)
 {
-	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
 	u32 reg;
 
-	if (dw_pcie_link_up(pp)) {
-		dev_err(pp->dev, "link is already up\n");
-		return 0;
+	if (dw_pcie_link_up(pci)) {
+		dev_err(pci->dev, "link is already up\n");
+		return -EBUSY;
 	}
 
 	reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
 	reg |= LTSSM_EN;
 	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
 
-	return dw_pcie_wait_for_link(pp);
+	return 0;
 }
 
-static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
+static void dra7xx_pcie_stop_link(struct dw_pcie *pci)
 {
-	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
+	u32 reg;
 
-	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN,
-			   ~INTERRUPTS);
-	dra7xx_pcie_writel(dra7xx,
-			   PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS);
+	reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
+	reg &= ~LTSSM_EN;
+	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
+}
+
+static void dra7xx_pcie_enable_msi_interrupts(struct dra7xx_pcie *dra7xx)
+{
 	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI,
 			   ~LEG_EP_INTERRUPTS & ~MSI);
 
@@ -140,8 +144,25 @@ static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
 				   LEG_EP_INTERRUPTS);
 }
 
+static void dra7xx_pcie_enable_wrapper_interrupts(struct dra7xx_pcie *dra7xx)
+{
+	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN,
+			   ~INTERRUPTS);
+	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN,
+			   INTERRUPTS);
+}
+
+static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx)
+{
+	dra7xx_pcie_enable_wrapper_interrupts(dra7xx);
+	dra7xx_pcie_enable_msi_interrupts(dra7xx);
+}
+
 static void dra7xx_pcie_host_init(struct pcie_port *pp)
 {
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
+
 	pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR;
 	pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR;
 	pp->cfg0_base &= DRA7XX_CPU_TO_BUS_ADDR;
@@ -149,14 +170,16 @@ static void dra7xx_pcie_host_init(struct pcie_port *pp)
 
 	dw_pcie_setup_rc(pp);
 
-	dra7xx_pcie_establish_link(pp);
+	dra7xx_pcie_start_link(pci);
+	dw_pcie_wait_for_link(pci);
+
 	if (IS_ENABLED(CONFIG_PCI_MSI))
 		dw_pcie_msi_init(pp);
-	dra7xx_pcie_enable_interrupts(pp);
+
+	dra7xx_pcie_enable_interrupts(dra7xx);
 }
 
-static struct pcie_host_ops dra7xx_pcie_host_ops = {
-	.link_up = dra7xx_pcie_link_up,
+static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
 	.host_init = dra7xx_pcie_host_init,
 };
 
@@ -175,7 +198,8 @@ static const struct irq_domain_ops intx_domain_ops = {
 
 static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
 {
-	struct device *dev = pp->dev;
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	struct device *dev = pci->dev;
 	struct device_node *node = dev->of_node;
 	struct device_node *pcie_intc_node =  of_get_next_child(node, NULL);
 
@@ -197,7 +221,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
 static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
 {
 	struct pcie_port *pp = arg;
-	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
 	u32 reg;
 
 	reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI);
@@ -281,9 +306,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
 	struct pcie_port *pp;
 	struct resource *res;
 	struct device *dev = &pdev->dev;
+	struct dw_pcie *pci = dra7xx->pci;
 
-	pp = &dra7xx->pp;
-	pp->dev = dev;
+	pp = &pci->pp;
 	pp->ops = &dra7xx_pcie_host_ops;
 
 	pp->irq = platform_get_irq(pdev, 1);
@@ -308,8 +333,8 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics");
-	pp->dbi_base = devm_ioremap(dev, res->start, resource_size(res));
-	if (!pp->dbi_base)
+	pci->dbi_base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!pci->dbi_base)
 		return -ENOMEM;
 
 	ret = dw_pcie_host_init(pp);
@@ -321,6 +346,12 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
 	return 0;
 }
 
+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 __init dra7xx_pcie_probe(struct platform_device *pdev)
 {
 	u32 reg;
@@ -331,6 +362,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 	struct phy **phy;
 	void __iomem *base;
 	struct resource *res;
+	struct dw_pcie *pci;
 	struct dra7xx_pcie *dra7xx;
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
@@ -343,6 +375,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 	if (!dra7xx)
 		return -ENOMEM;
 
+	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+	if (!pci)
+		return -ENOMEM;
+
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		dev_err(dev, "missing IRQ resource\n");
@@ -388,8 +424,12 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 		}
 	}
 
+	pci->dev = dev;
+	pci->ops = &dw_pcie_ops;
+
 	dra7xx->base = base;
 	dra7xx->phy = phy;
+	dra7xx->pci = pci;
 	dra7xx->dev = dev;
 	dra7xx->phy_count = phy_count;
 
@@ -446,7 +486,8 @@ err_phy:
 static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
 {
 	struct dra7xx_pcie *dra7xx = platform_get_drvdata(pdev);
-	struct pcie_port *pp = &dra7xx->pp;
+	struct dw_pcie *pci = dra7xx->pci;
+	struct pcie_port *pp = &pci->pp;
 	struct device *dev = &pdev->dev;
 	int count = dra7xx->phy_count;
 
@@ -466,13 +507,13 @@ static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
 static int dra7xx_pcie_suspend(struct device *dev)
 {
 	struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
-	struct pcie_port *pp = &dra7xx->pp;
+	struct dw_pcie *pci = dra7xx->pci;
 	u32 val;
 
 	/* clear MSE */
-	val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND);
+	val = dra7xx_pcie_readl_dbi(pci->dbi_base, PCI_COMMAND);
 	val &= ~PCI_COMMAND_MEMORY;
-	dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val);
+	dra7xx_pcie_writel_dbi(pci->dbi_base, PCI_COMMAND, val);
 
 	return 0;
 }
@@ -480,13 +521,13 @@ static int dra7xx_pcie_suspend(struct device *dev)
 static int dra7xx_pcie_resume(struct device *dev)
 {
 	struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
-	struct pcie_port *pp = &dra7xx->pp;
+	struct dw_pcie *pci = dra7xx->pci;
 	u32 val;
 
 	/* set MSE */
-	val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND);
+	val = dra7xx_pcie_readl_dbi(pci->dbi_base, PCI_COMMAND);
 	val |= PCI_COMMAND_MEMORY;
-	dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val);
+	dra7xx_pcie_writel_dbi(pci->dbi_base, PCI_COMMAND, val);
 
 	return 0;
 }
diff --git a/drivers/pci/controller/pcie-designware.c b/drivers/pci/controller/pcie-designware-host.c
similarity index 64%
copy from drivers/pci/controller/pcie-designware.c
copy to drivers/pci/controller/pcie-designware-host.c
index 12afce1..8a21ccb 100644
--- a/drivers/pci/controller/pcie-designware.c
+++ b/drivers/pci/controller/pcie-designware-host.c
@@ -11,165 +11,39 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/irq.h>
 #include <linux/irqdomain.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
-#include <linux/pci.h>
 #include <linux/pci_regs.h>
 #include <linux/platform_device.h>
-#include <linux/types.h>
-#include <linux/delay.h>
 
 #include "pcie-designware.h"
 
-/* Synopsis specific PCIE configuration registers */
-#define PCIE_PORT_LINK_CONTROL		0x710
-#define PORT_LINK_MODE_MASK		(0x3f << 16)
-#define PORT_LINK_MODE_1_LANES		(0x1 << 16)
-#define PORT_LINK_MODE_2_LANES		(0x3 << 16)
-#define PORT_LINK_MODE_4_LANES		(0x7 << 16)
-#define PORT_LINK_MODE_8_LANES		(0xf << 16)
-
-#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
-#define PORT_LOGIC_SPEED_CHANGE		(0x1 << 17)
-#define PORT_LOGIC_LINK_WIDTH_MASK	(0x1f << 8)
-#define PORT_LOGIC_LINK_WIDTH_1_LANES	(0x1 << 8)
-#define PORT_LOGIC_LINK_WIDTH_2_LANES	(0x2 << 8)
-#define PORT_LOGIC_LINK_WIDTH_4_LANES	(0x4 << 8)
-#define PORT_LOGIC_LINK_WIDTH_8_LANES	(0x8 << 8)
-
-#define PCIE_MSI_ADDR_LO		0x820
-#define PCIE_MSI_ADDR_HI		0x824
-#define PCIE_MSI_INTR0_ENABLE		0x828
-#define PCIE_MSI_INTR0_MASK		0x82C
-#define PCIE_MSI_INTR0_STATUS		0x830
-
-#define PCIE_ATU_VIEWPORT		0x900
-#define PCIE_ATU_REGION_INBOUND		(0x1 << 31)
-#define PCIE_ATU_REGION_OUTBOUND	(0x0 << 31)
-#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
-#define PCIE_ATU_CR1			0x904
-#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
-#define PCIE_ATU_TYPE_IO		(0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
-#define PCIE_ATU_CR2			0x908
-#define PCIE_ATU_ENABLE			(0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
-#define PCIE_ATU_LOWER_BASE		0x90C
-#define PCIE_ATU_UPPER_BASE		0x910
-#define PCIE_ATU_LIMIT			0x914
-#define PCIE_ATU_LOWER_TARGET		0x918
-#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
-#define PCIE_ATU_UPPER_TARGET		0x91C
-
-/* PCIe Port Logic registers */
-#define PLR_OFFSET			0x700
-#define PCIE_PHY_DEBUG_R1		(PLR_OFFSET + 0x2c)
-#define PCIE_PHY_DEBUG_R1_LINK_UP	0x00000010
-
 static struct pci_ops dw_pcie_ops;
 
-int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
-{
-	if ((uintptr_t)addr & (size - 1)) {
-		*val = 0;
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	}
-
-	if (size == 4)
-		*val = readl(addr);
-	else if (size == 2)
-		*val = readw(addr);
-	else if (size == 1)
-		*val = readb(addr);
-	else {
-		*val = 0;
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	}
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
-{
-	if ((uintptr_t)addr & (size - 1))
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-
-	if (size == 4)
-		writel(val, addr);
-	else if (size == 2)
-		writew(val, addr);
-	else if (size == 1)
-		writeb(val, addr);
-	else
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static inline void dw_pcie_readl_rc(struct pcie_port *pp, u32 reg, u32 *val)
-{
-	if (pp->ops->readl_rc)
-		pp->ops->readl_rc(pp, pp->dbi_base + reg, val);
-	else
-		*val = readl(pp->dbi_base + reg);
-}
-
-static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
-{
-	if (pp->ops->writel_rc)
-		pp->ops->writel_rc(pp, val, pp->dbi_base + reg);
-	else
-		writel(val, pp->dbi_base + reg);
-}
-
 static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
 			       u32 *val)
 {
+	struct dw_pcie *pci;
+
 	if (pp->ops->rd_own_conf)
 		return pp->ops->rd_own_conf(pp, where, size, val);
 
-	return dw_pcie_cfg_read(pp->dbi_base + where, size, val);
+	pci = to_dw_pcie_from_pp(pp);
+	return dw_pcie_read(pci->dbi_base + where, size, val);
 }
 
 static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
 			       u32 val)
 {
+	struct dw_pcie *pci;
+
 	if (pp->ops->wr_own_conf)
 		return pp->ops->wr_own_conf(pp, where, size, val);
 
-	return dw_pcie_cfg_write(pp->dbi_base + where, size, val);
-}
-
-static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
-		int type, u64 cpu_addr, u64 pci_addr, u32 size)
-{
-	u32 val;
-
-	dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,
-			  PCIE_ATU_VIEWPORT);
-	dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE);
-	dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE);
-	dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),
-			  PCIE_ATU_LIMIT);
-	dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET);
-	dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET);
-	dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);
-	dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
-
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	dw_pcie_readl_rc(pp, PCIE_ATU_CR2, &val);
+	pci = to_dw_pcie_from_pp(pp);
+	return dw_pcie_write(pci->dbi_base + where, size, val);
 }
 
 static struct irq_chip dw_msi_irq_chip = {
@@ -386,35 +260,6 @@ static struct msi_controller dw_pcie_msi_chip = {
 	.teardown_irq = dw_msi_teardown_irq,
 };
 
-int dw_pcie_wait_for_link(struct pcie_port *pp)
-{
-	int retries;
-
-	/* check if the link is up or not */
-	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-		if (dw_pcie_link_up(pp)) {
-			dev_info(pp->dev, "link up\n");
-			return 0;
-		}
-		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-	}
-
-	dev_err(pp->dev, "phy link never came up\n");
-
-	return -ETIMEDOUT;
-}
-
-int dw_pcie_link_up(struct pcie_port *pp)
-{
-	u32 val;
-
-	if (pp->ops->link_up)
-		return pp->ops->link_up(pp);
-
-	val = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
-	return val & PCIE_PHY_DEBUG_R1_LINK_UP;
-}
-
 static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
 			irq_hw_number_t hwirq)
 {
@@ -430,8 +275,10 @@ static const struct irq_domain_ops msi_domain_ops = {
 
 int dw_pcie_host_init(struct pcie_port *pp)
 {
-	struct device_node *np = pp->dev->of_node;
-	struct platform_device *pdev = to_platform_device(pp->dev);
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	struct device *dev = pci->dev;
+	struct device_node *np = dev->of_node;
+	struct platform_device *pdev = to_platform_device(pci->dev);
 	struct pci_bus *bus, *child;
 	struct resource *cfg_res;
 	int i, ret;
@@ -445,14 +292,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
 		pp->cfg0_base = cfg_res->start;
 		pp->cfg1_base = cfg_res->start + pp->cfg0_size;
 	} else if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "missing *config* reg space\n");
+		dev_err(dev, "missing *config* reg space\n");
 	}
 
 	ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &pp->io_base);
 	if (ret)
 		return ret;
 
-	ret = devm_request_pci_bus_resources(&pdev->dev, &res);
+	ret = devm_request_pci_bus_resources(dev, &res);
 	if (ret)
 		goto error;
 
@@ -466,7 +313,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 			pp->io_bus_addr = pp->io->start - win->offset;
 			ret = pci_remap_iospace(pp->io, pp->io_base);
 			if (ret)
-				dev_warn(pp->dev, "error %d: failed to map resource %pR\n",
+				dev_warn(dev, "error %d: failed to map resource %pR\n",
 					 ret, pp->io);
 			break;
 		case IORESOURCE_MEM:
@@ -488,11 +335,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
 		}
 	}
 
-	if (!pp->dbi_base) {
-		pp->dbi_base = devm_ioremap(pp->dev, pp->cfg->start,
-					resource_size(pp->cfg));
-		if (!pp->dbi_base) {
-			dev_err(pp->dev, "error with ioremap\n");
+	if (!pci->dbi_base) {
+		pci->dbi_base = devm_ioremap(dev, pp->cfg->start,
+					    resource_size(pp->cfg));
+		if (!pci->dbi_base) {
+			dev_err(dev, "error with ioremap\n");
 			ret = -ENOMEM;
 			goto error;
 		}
@@ -501,36 +348,36 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	pp->mem_base = pp->mem->start;
 
 	if (!pp->va_cfg0_base) {
-		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+		pp->va_cfg0_base = devm_ioremap(dev, pp->cfg0_base,
 						pp->cfg0_size);
 		if (!pp->va_cfg0_base) {
-			dev_err(pp->dev, "error with ioremap in function\n");
+			dev_err(dev, "error with ioremap in function\n");
 			ret = -ENOMEM;
 			goto error;
 		}
 	}
 
 	if (!pp->va_cfg1_base) {
-		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+		pp->va_cfg1_base = devm_ioremap(dev, pp->cfg1_base,
 						pp->cfg1_size);
 		if (!pp->va_cfg1_base) {
-			dev_err(pp->dev, "error with ioremap\n");
+			dev_err(dev, "error with ioremap\n");
 			ret = -ENOMEM;
 			goto error;
 		}
 	}
 
-	ret = of_property_read_u32(np, "num-lanes", &pp->lanes);
+	ret = of_property_read_u32(np, "num-lanes", &pci->lanes);
 	if (ret)
-		pp->lanes = 0;
+		pci->lanes = 0;
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		if (!pp->ops->msi_host_init) {
-			pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
+			pp->irq_domain = irq_domain_add_linear(np,
 						MAX_MSI_IRQS, &msi_domain_ops,
 						&dw_pcie_msi_chip);
 			if (!pp->irq_domain) {
-				dev_err(pp->dev, "irq domain init failed\n");
+				dev_err(dev, "irq domain init failed\n");
 				ret = -ENXIO;
 				goto error;
 			}
@@ -549,12 +396,12 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 	pp->root_bus_nr = pp->busn->start;
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		bus = pci_scan_root_bus_msi(pp->dev, pp->root_bus_nr,
+		bus = pci_scan_root_bus_msi(dev, pp->root_bus_nr,
 					    &dw_pcie_ops, pp, &res,
 					    &dw_pcie_msi_chip);
-		dw_pcie_msi_chip.dev = pp->dev;
+		dw_pcie_msi_chip.dev = dev;
 	} else
-		bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops,
+		bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
 					pp, &res);
 	if (!bus) {
 		ret = -ENOMEM;
@@ -590,6 +437,7 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 	u32 busdev, cfg_size;
 	u64 cpu_addr;
 	void __iomem *va_cfg_base;
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
 	if (pp->ops->rd_other_conf)
 		return pp->ops->rd_other_conf(pp, bus, devfn, where, size, val);
@@ -609,11 +457,11 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 		va_cfg_base = pp->va_cfg1_base;
 	}
 
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+	dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
 				  type, cpu_addr,
 				  busdev, cfg_size);
-	ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+	ret = dw_pcie_read(va_cfg_base + where, size, val);
+	dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
 				  PCIE_ATU_TYPE_IO, pp->io_base,
 				  pp->io_bus_addr, pp->io_size);
 
@@ -627,6 +475,7 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 	u32 busdev, cfg_size;
 	u64 cpu_addr;
 	void __iomem *va_cfg_base;
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
 	if (pp->ops->wr_other_conf)
 		return pp->ops->wr_other_conf(pp, bus, devfn, where, size, val);
@@ -646,11 +495,11 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 		va_cfg_base = pp->va_cfg1_base;
 	}
 
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+	dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
 				  type, cpu_addr,
 				  busdev, cfg_size);
-	ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+	ret = dw_pcie_write(va_cfg_base + where, size, val);
+	dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
 				  PCIE_ATU_TYPE_IO, pp->io_base,
 				  pp->io_bus_addr, pp->io_size);
 
@@ -660,9 +509,11 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 static int dw_pcie_valid_config(struct pcie_port *pp,
 				struct pci_bus *bus, int dev)
 {
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
 	/* If there is no link, then there is no device */
 	if (bus->number != pp->root_bus_nr) {
-		if (!dw_pcie_link_up(pp))
+		if (!dw_pcie_link_up(pci))
 			return 0;
 	}
 
@@ -718,70 +569,33 @@ static struct pci_ops dw_pcie_ops = {
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
 	u32 val;
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	void __iomem *base = pci->dbi_base;
 
-	/* set the number of lanes */
-	dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val);
-	val &= ~PORT_LINK_MODE_MASK;
-	switch (pp->lanes) {
-	case 1:
-		val |= PORT_LINK_MODE_1_LANES;
-		break;
-	case 2:
-		val |= PORT_LINK_MODE_2_LANES;
-		break;
-	case 4:
-		val |= PORT_LINK_MODE_4_LANES;
-		break;
-	case 8:
-		val |= PORT_LINK_MODE_8_LANES;
-		break;
-	default:
-		dev_err(pp->dev, "num-lanes %u: invalid value\n", pp->lanes);
-		return;
-	}
-	dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL);
-
-	/* set link width speed control register */
-	dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, &val);
-	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
-	switch (pp->lanes) {
-	case 1:
-		val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
-		break;
-	case 2:
-		val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
-		break;
-	case 4:
-		val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
-		break;
-	case 8:
-		val |= PORT_LOGIC_LINK_WIDTH_8_LANES;
-		break;
-	}
-	dw_pcie_writel_rc(pp, val, PCIE_LINK_WIDTH_SPEED_CONTROL);
+	dw_pcie_setup(pci);
 
 	/* setup RC BARs */
-	dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0);
-	dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1);
+	dw_pcie_write_dbi(pci, base, PCI_BASE_ADDRESS_0, 0x4, 0x00000004);
+	dw_pcie_write_dbi(pci, base, PCI_BASE_ADDRESS_1, 0x4, 0x00000000);
 
 	/* setup interrupt pins */
-	dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val);
+	dw_pcie_read_dbi(pci, base, PCI_INTERRUPT_LINE, 0x4, &val);
 	val &= 0xffff00ff;
 	val |= 0x00000100;
-	dw_pcie_writel_rc(pp, val, PCI_INTERRUPT_LINE);
+	dw_pcie_write_dbi(pci, base, PCI_INTERRUPT_LINE, 0x4, val);
 
 	/* setup bus numbers */
-	dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS, &val);
+	dw_pcie_read_dbi(pci, base, PCI_PRIMARY_BUS, 0x4, &val);
 	val &= 0xff000000;
 	val |= 0x00010100;
-	dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
+	dw_pcie_write_dbi(pci, base, PCI_PRIMARY_BUS, 0x4, val);
 
 	/* setup command register */
-	dw_pcie_readl_rc(pp, PCI_COMMAND, &val);
+	dw_pcie_read_dbi(pci, base, PCI_COMMAND, 0x4, &val);
 	val &= 0xffff0000;
 	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
 		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-	dw_pcie_writel_rc(pp, val, PCI_COMMAND);
+	dw_pcie_write_dbi(pci, base, PCI_COMMAND, 0x4, val);
 
 	/*
 	 * If the platform provides ->rd_other_conf, it means the platform
@@ -789,7 +603,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 	 * we should not program the ATU here.
 	 */
 	if (!pp->ops->rd_other_conf)
-		dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
+		dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
 					  PCIE_ATU_TYPE_MEM, pp->mem_base,
 					  pp->mem_bus_addr, pp->mem_size);
 
diff --git a/drivers/pci/controller/pcie-designware.c b/drivers/pci/controller/pcie-designware.c
index 12afce1..e52a020 100644
--- a/drivers/pci/controller/pcie-designware.c
+++ b/drivers/pci/controller/pcie-designware.c
@@ -1,5 +1,5 @@
 /*
- * Synopsys Designware PCIe host controller driver
+ * Synopsys Designware PCIe controller driver
  *
  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
@@ -11,73 +11,14 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/msi.h>
-#include <linux/of_address.h>
-#include <linux/of_pci.h>
+#include <linux/of.h>
 #include <linux/pci.h>
-#include <linux/pci_regs.h>
-#include <linux/platform_device.h>
-#include <linux/types.h>
 #include <linux/delay.h>
 
 #include "pcie-designware.h"
 
-/* Synopsis specific PCIE configuration registers */
-#define PCIE_PORT_LINK_CONTROL		0x710
-#define PORT_LINK_MODE_MASK		(0x3f << 16)
-#define PORT_LINK_MODE_1_LANES		(0x1 << 16)
-#define PORT_LINK_MODE_2_LANES		(0x3 << 16)
-#define PORT_LINK_MODE_4_LANES		(0x7 << 16)
-#define PORT_LINK_MODE_8_LANES		(0xf << 16)
-
-#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
-#define PORT_LOGIC_SPEED_CHANGE		(0x1 << 17)
-#define PORT_LOGIC_LINK_WIDTH_MASK	(0x1f << 8)
-#define PORT_LOGIC_LINK_WIDTH_1_LANES	(0x1 << 8)
-#define PORT_LOGIC_LINK_WIDTH_2_LANES	(0x2 << 8)
-#define PORT_LOGIC_LINK_WIDTH_4_LANES	(0x4 << 8)
-#define PORT_LOGIC_LINK_WIDTH_8_LANES	(0x8 << 8)
-
-#define PCIE_MSI_ADDR_LO		0x820
-#define PCIE_MSI_ADDR_HI		0x824
-#define PCIE_MSI_INTR0_ENABLE		0x828
-#define PCIE_MSI_INTR0_MASK		0x82C
-#define PCIE_MSI_INTR0_STATUS		0x830
-
-#define PCIE_ATU_VIEWPORT		0x900
-#define PCIE_ATU_REGION_INBOUND		(0x1 << 31)
-#define PCIE_ATU_REGION_OUTBOUND	(0x0 << 31)
-#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
-#define PCIE_ATU_CR1			0x904
-#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
-#define PCIE_ATU_TYPE_IO		(0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
-#define PCIE_ATU_CR2			0x908
-#define PCIE_ATU_ENABLE			(0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
-#define PCIE_ATU_LOWER_BASE		0x90C
-#define PCIE_ATU_UPPER_BASE		0x910
-#define PCIE_ATU_LIMIT			0x914
-#define PCIE_ATU_LOWER_TARGET		0x918
-#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
-#define PCIE_ATU_UPPER_TARGET		0x91C
-
-/* PCIe Port Logic registers */
-#define PLR_OFFSET			0x700
-#define PCIE_PHY_DEBUG_R1		(PLR_OFFSET + 0x2c)
-#define PCIE_PHY_DEBUG_R1_LINK_UP	0x00000010
-
-static struct pci_ops dw_pcie_ops;
-
-int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
+int dw_pcie_read(void __iomem *addr, int size, u32 *val)
 {
 	if ((uintptr_t)addr & (size - 1)) {
 		*val = 0;
@@ -98,7 +39,7 @@ int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
+int dw_pcie_write(void __iomem *addr, int size, u32 val)
 {
 	if ((uintptr_t)addr & (size - 1))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
@@ -115,614 +56,110 @@ int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static inline void dw_pcie_readl_rc(struct pcie_port *pp, u32 reg, u32 *val)
-{
-	if (pp->ops->readl_rc)
-		pp->ops->readl_rc(pp, pp->dbi_base + reg, val);
-	else
-		*val = readl(pp->dbi_base + reg);
-}
-
-static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
-{
-	if (pp->ops->writel_rc)
-		pp->ops->writel_rc(pp, val, pp->dbi_base + reg);
-	else
-		writel(val, pp->dbi_base + reg);
-}
-
-static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
-			       u32 *val)
-{
-	if (pp->ops->rd_own_conf)
-		return pp->ops->rd_own_conf(pp, where, size, val);
-
-	return dw_pcie_cfg_read(pp->dbi_base + where, size, val);
-}
-
-static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
-			       u32 val)
+void dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
+		      u32 reg, int size, u32 *val)
 {
-	if (pp->ops->wr_own_conf)
-		return pp->ops->wr_own_conf(pp, where, size, val);
-
-	return dw_pcie_cfg_write(pp->dbi_base + where, size, val);
-}
-
-static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
-		int type, u64 cpu_addr, u64 pci_addr, u32 size)
-{
-	u32 val;
-
-	dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,
-			  PCIE_ATU_VIEWPORT);
-	dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE);
-	dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE);
-	dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),
-			  PCIE_ATU_LIMIT);
-	dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET);
-	dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET);
-	dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);
-	dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+	int ret;
 
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	dw_pcie_readl_rc(pp, PCIE_ATU_CR2, &val);
-}
-
-static struct irq_chip dw_msi_irq_chip = {
-	.name = "PCI-MSI",
-	.irq_enable = pci_msi_unmask_irq,
-	.irq_disable = pci_msi_mask_irq,
-	.irq_mask = pci_msi_mask_irq,
-	.irq_unmask = pci_msi_unmask_irq,
-};
-
-/* MSI int handler */
-irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
-{
-	unsigned long val;
-	int i, pos, irq;
-	irqreturn_t ret = IRQ_NONE;
-
-	for (i = 0; i < MAX_MSI_CTRLS; i++) {
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
-				(u32 *)&val);
-		if (val) {
-			ret = IRQ_HANDLED;
-			pos = 0;
-			while ((pos = find_next_bit(&val, 32, pos)) != 32) {
-				irq = irq_find_mapping(pp->irq_domain,
-						i * 32 + pos);
-				dw_pcie_wr_own_conf(pp,
-						PCIE_MSI_INTR0_STATUS + i * 12,
-						4, 1 << pos);
-				generic_handle_irq(irq);
-				pos++;
-			}
-		}
+	if (pci->ops->read_dbi) {
+		pci->ops->read_dbi(pci, base + reg, size, val);
+		return;
 	}
 
-	return ret;
-}
-
-void dw_pcie_msi_init(struct pcie_port *pp)
-{
-	u64 msi_target;
-
-	pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
-	msi_target = virt_to_phys((void *)pp->msi_data);
-
-	/* program the msi_data */
-	dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
-			    (u32)(msi_target & 0xffffffff));
-	dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
-			    (u32)(msi_target >> 32 & 0xffffffff));
-}
-
-static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
-{
-	unsigned int res, bit, val;
-
-	res = (irq / 32) * 12;
-	bit = irq % 32;
-	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-	val &= ~(1 << bit);
-	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+	ret = dw_pcie_read(base + reg, size, val);
+	if (ret)
+		dev_err(pci->dev, "read DBI address failed\n");
 }
 
-static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
-			    unsigned int nvec, unsigned int pos)
+void dw_pcie_write_dbi(struct dw_pcie *pci, void *base, u32 reg,
+		       int size, u32 val)
 {
-	unsigned int i;
+	int ret;
 
-	for (i = 0; i < nvec; i++) {
-		irq_set_msi_desc_off(irq_base, i, NULL);
-		/* Disable corresponding interrupt on MSI controller */
-		if (pp->ops->msi_clear_irq)
-			pp->ops->msi_clear_irq(pp, pos + i);
-		else
-			dw_pcie_msi_clear_irq(pp, pos + i);
+	if (pci->ops->write_dbi) {
+		pci->ops->write_dbi(pci, base + reg, size, val);
+		return;
 	}
 
-	bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec));
-}
-
-static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
-{
-	unsigned int res, bit, val;
-
-	res = (irq / 32) * 12;
-	bit = irq % 32;
-	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-	val |= 1 << bit;
-	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+	ret = dw_pcie_write(base + reg, size, val);
+	if (ret)
+		dev_err(pci->dev, "write DBI address failed\n");
 }
 
-static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
+void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
+			       int type, u64 cpu_addr, u64 pci_addr,
+			       u32 size)
 {
-	int irq, pos0, i;
-	struct pcie_port *pp = (struct pcie_port *) msi_desc_to_pci_sysdata(desc);
-
-	pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS,
-				       order_base_2(no_irqs));
-	if (pos0 < 0)
-		goto no_valid_irq;
-
-	irq = irq_find_mapping(pp->irq_domain, pos0);
-	if (!irq)
-		goto no_valid_irq;
+	u32 val;
+	void __iomem *base = pci->dbi_base;
+
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_VIEWPORT, 0x4,
+			  PCIE_ATU_REGION_OUTBOUND | index);
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_LOWER_BASE, 0x4,
+			  lower_32_bits(cpu_addr));
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_UPPER_BASE, 0x4,
+			  upper_32_bits(cpu_addr));
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_LIMIT, 0x4,
+			  lower_32_bits(cpu_addr + size - 1));
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_LOWER_TARGET, 0x4,
+			  lower_32_bits(pci_addr));
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_UPPER_TARGET, 0x4,
+			  upper_32_bits(pci_addr));
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_CR1, 0x4, type);
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_CR2, 0x4, PCIE_ATU_ENABLE);
 
 	/*
-	 * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
-	 * descs so there is no need to allocate descs here. We can therefore
-	 * assume that if irq_find_mapping above returns non-zero, then the
-	 * descs are also successfully allocated.
+	 * Make sure ATU enable takes effect before any subsequent config
+	 * and I/O accesses.
 	 */
-
-	for (i = 0; i < no_irqs; i++) {
-		if (irq_set_msi_desc_off(irq, i, desc) != 0) {
-			clear_irq_range(pp, irq, i, pos0);
-			goto no_valid_irq;
-		}
-		/*Enable corresponding interrupt in MSI interrupt controller */
-		if (pp->ops->msi_set_irq)
-			pp->ops->msi_set_irq(pp, pos0 + i);
-		else
-			dw_pcie_msi_set_irq(pp, pos0 + i);
-	}
-
-	*pos = pos0;
-	desc->nvec_used = no_irqs;
-	desc->msi_attrib.multiple = order_base_2(no_irqs);
-
-	return irq;
-
-no_valid_irq:
-	*pos = pos0;
-	return -ENOSPC;
-}
-
-static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
-{
-	struct msi_msg msg;
-	u64 msi_target;
-
-	if (pp->ops->get_msi_addr)
-		msi_target = pp->ops->get_msi_addr(pp);
-	else
-		msi_target = virt_to_phys((void *)pp->msi_data);
-
-	msg.address_lo = (u32)(msi_target & 0xffffffff);
-	msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
-
-	if (pp->ops->get_msi_data)
-		msg.data = pp->ops->get_msi_data(pp, pos);
-	else
-		msg.data = pos;
-
-	pci_write_msi_msg(irq, &msg);
-}
-
-static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
-			struct msi_desc *desc)
-{
-	int irq, pos;
-	struct pcie_port *pp = pdev->bus->sysdata;
-
-	if (desc->msi_attrib.is_msix)
-		return -EINVAL;
-
-	irq = assign_irq(1, desc, &pos);
-	if (irq < 0)
-		return irq;
-
-	dw_msi_setup_msg(pp, irq, pos);
-
-	return 0;
+	dw_pcie_read_dbi(pci, base, PCIE_ATU_CR2, 0x4, &val);
 }
 
-static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
-			     int nvec, int type)
-{
-#ifdef CONFIG_PCI_MSI
-	int irq, pos;
-	struct msi_desc *desc;
-	struct pcie_port *pp = pdev->bus->sysdata;
-
-	/* MSI-X interrupts are not supported */
-	if (type == PCI_CAP_ID_MSIX)
-		return -EINVAL;
-
-	WARN_ON(!list_is_singular(&pdev->dev.msi_list));
-	desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
-
-	irq = assign_irq(nvec, desc, &pos);
-	if (irq < 0)
-		return irq;
-
-	dw_msi_setup_msg(pp, irq, pos);
-
-	return 0;
-#else
-	return -EINVAL;
-#endif
-}
-
-static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
-{
-	struct irq_data *data = irq_get_irq_data(irq);
-	struct msi_desc *msi = irq_data_get_msi_desc(data);
-	struct pcie_port *pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
-
-	clear_irq_range(pp, irq, 1, data->hwirq);
-}
-
-static struct msi_controller dw_pcie_msi_chip = {
-	.setup_irq = dw_msi_setup_irq,
-	.setup_irqs = dw_msi_setup_irqs,
-	.teardown_irq = dw_msi_teardown_irq,
-};
-
-int dw_pcie_wait_for_link(struct pcie_port *pp)
+int dw_pcie_wait_for_link(struct dw_pcie *pci)
 {
 	int retries;
 
 	/* check if the link is up or not */
 	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-		if (dw_pcie_link_up(pp)) {
-			dev_info(pp->dev, "link up\n");
+		if (dw_pcie_link_up(pci)) {
+			dev_info(pci->dev, "link up\n");
 			return 0;
 		}
 		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
 	}
 
-	dev_err(pp->dev, "phy link never came up\n");
+	dev_err(pci->dev, "phy link never came up\n");
 
 	return -ETIMEDOUT;
 }
 
-int dw_pcie_link_up(struct pcie_port *pp)
+int dw_pcie_link_up(struct dw_pcie *pci)
 {
 	u32 val;
 
-	if (pp->ops->link_up)
-		return pp->ops->link_up(pp);
+	if (pci->ops->link_up)
+		return pci->ops->link_up(pci);
 
-	val = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
+	val = readl(pci->dbi_base + PCIE_PHY_DEBUG_R1);
 	return val & PCIE_PHY_DEBUG_R1_LINK_UP;
 }
 
-static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
-			irq_hw_number_t hwirq)
+void dw_pcie_setup(struct dw_pcie *pci)
 {
-	irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
-	irq_set_chip_data(irq, domain->host_data);
-
-	return 0;
-}
-
-static const struct irq_domain_ops msi_domain_ops = {
-	.map = dw_pcie_msi_map,
-};
-
-int dw_pcie_host_init(struct pcie_port *pp)
-{
-	struct device_node *np = pp->dev->of_node;
-	struct platform_device *pdev = to_platform_device(pp->dev);
-	struct pci_bus *bus, *child;
-	struct resource *cfg_res;
-	int i, ret;
-	LIST_HEAD(res);
-	struct resource_entry *win;
-
-	cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
-	if (cfg_res) {
-		pp->cfg0_size = resource_size(cfg_res)/2;
-		pp->cfg1_size = resource_size(cfg_res)/2;
-		pp->cfg0_base = cfg_res->start;
-		pp->cfg1_base = cfg_res->start + pp->cfg0_size;
-	} else if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "missing *config* reg space\n");
-	}
-
-	ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &pp->io_base);
-	if (ret)
-		return ret;
-
-	ret = devm_request_pci_bus_resources(&pdev->dev, &res);
-	if (ret)
-		goto error;
-
-	/* Get the I/O and memory ranges from DT */
-	resource_list_for_each_entry(win, &res) {
-		switch (resource_type(win->res)) {
-		case IORESOURCE_IO:
-			pp->io = win->res;
-			pp->io->name = "I/O";
-			pp->io_size = resource_size(pp->io);
-			pp->io_bus_addr = pp->io->start - win->offset;
-			ret = pci_remap_iospace(pp->io, pp->io_base);
-			if (ret)
-				dev_warn(pp->dev, "error %d: failed to map resource %pR\n",
-					 ret, pp->io);
-			break;
-		case IORESOURCE_MEM:
-			pp->mem = win->res;
-			pp->mem->name = "MEM";
-			pp->mem_size = resource_size(pp->mem);
-			pp->mem_bus_addr = pp->mem->start - win->offset;
-			break;
-		case 0:
-			pp->cfg = win->res;
-			pp->cfg0_size = resource_size(pp->cfg)/2;
-			pp->cfg1_size = resource_size(pp->cfg)/2;
-			pp->cfg0_base = pp->cfg->start;
-			pp->cfg1_base = pp->cfg->start + pp->cfg0_size;
-			break;
-		case IORESOURCE_BUS:
-			pp->busn = win->res;
-			break;
-		}
-	}
-
-	if (!pp->dbi_base) {
-		pp->dbi_base = devm_ioremap(pp->dev, pp->cfg->start,
-					resource_size(pp->cfg));
-		if (!pp->dbi_base) {
-			dev_err(pp->dev, "error with ioremap\n");
-			ret = -ENOMEM;
-			goto error;
-		}
-	}
-
-	pp->mem_base = pp->mem->start;
-
-	if (!pp->va_cfg0_base) {
-		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
-						pp->cfg0_size);
-		if (!pp->va_cfg0_base) {
-			dev_err(pp->dev, "error with ioremap in function\n");
-			ret = -ENOMEM;
-			goto error;
-		}
-	}
-
-	if (!pp->va_cfg1_base) {
-		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
-						pp->cfg1_size);
-		if (!pp->va_cfg1_base) {
-			dev_err(pp->dev, "error with ioremap\n");
-			ret = -ENOMEM;
-			goto error;
-		}
-	}
+	u32 val;
+	int ret;
+	void __iomem *base = pci->dbi_base;
+	struct device *dev = pci->dev;
+	struct device_node *np = dev->of_node;
 
-	ret = of_property_read_u32(np, "num-lanes", &pp->lanes);
+	ret = of_property_read_u32(np, "num-lanes", &pci->lanes);
 	if (ret)
-		pp->lanes = 0;
-
-	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		if (!pp->ops->msi_host_init) {
-			pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
-						MAX_MSI_IRQS, &msi_domain_ops,
-						&dw_pcie_msi_chip);
-			if (!pp->irq_domain) {
-				dev_err(pp->dev, "irq domain init failed\n");
-				ret = -ENXIO;
-				goto error;
-			}
-
-			for (i = 0; i < MAX_MSI_IRQS; i++)
-				irq_create_mapping(pp->irq_domain, i);
-		} else {
-			ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
-			if (ret < 0)
-				goto error;
-		}
-	}
-
-	if (pp->ops->host_init)
-		pp->ops->host_init(pp);
-
-	pp->root_bus_nr = pp->busn->start;
-	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		bus = pci_scan_root_bus_msi(pp->dev, pp->root_bus_nr,
-					    &dw_pcie_ops, pp, &res,
-					    &dw_pcie_msi_chip);
-		dw_pcie_msi_chip.dev = pp->dev;
-	} else
-		bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops,
-					pp, &res);
-	if (!bus) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	if (pp->ops->scan_bus)
-		pp->ops->scan_bus(pp);
-
-#ifdef CONFIG_ARM
-	/* support old dtbs that incorrectly describe IRQs */
-	pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
-#endif
-
-	pci_bus_size_bridges(bus);
-	pci_bus_assign_resources(bus);
-
-	list_for_each_entry(child, &bus->children, node)
-		pcie_bus_configure_settings(child);
-
-	pci_bus_add_devices(bus);
-	return 0;
-
-error:
-	pci_free_resource_list(&res);
-	return ret;
-}
-
-static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-		u32 devfn, int where, int size, u32 *val)
-{
-	int ret, type;
-	u32 busdev, cfg_size;
-	u64 cpu_addr;
-	void __iomem *va_cfg_base;
-
-	if (pp->ops->rd_other_conf)
-		return pp->ops->rd_other_conf(pp, bus, devfn, where, size, val);
-
-	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
-		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-
-	if (bus->parent->number == pp->root_bus_nr) {
-		type = PCIE_ATU_TYPE_CFG0;
-		cpu_addr = pp->cfg0_base;
-		cfg_size = pp->cfg0_size;
-		va_cfg_base = pp->va_cfg0_base;
-	} else {
-		type = PCIE_ATU_TYPE_CFG1;
-		cpu_addr = pp->cfg1_base;
-		cfg_size = pp->cfg1_size;
-		va_cfg_base = pp->va_cfg1_base;
-	}
-
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
-				  type, cpu_addr,
-				  busdev, cfg_size);
-	ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
-				  PCIE_ATU_TYPE_IO, pp->io_base,
-				  pp->io_bus_addr, pp->io_size);
-
-	return ret;
-}
-
-static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-		u32 devfn, int where, int size, u32 val)
-{
-	int ret, type;
-	u32 busdev, cfg_size;
-	u64 cpu_addr;
-	void __iomem *va_cfg_base;
-
-	if (pp->ops->wr_other_conf)
-		return pp->ops->wr_other_conf(pp, bus, devfn, where, size, val);
-
-	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
-		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-
-	if (bus->parent->number == pp->root_bus_nr) {
-		type = PCIE_ATU_TYPE_CFG0;
-		cpu_addr = pp->cfg0_base;
-		cfg_size = pp->cfg0_size;
-		va_cfg_base = pp->va_cfg0_base;
-	} else {
-		type = PCIE_ATU_TYPE_CFG1;
-		cpu_addr = pp->cfg1_base;
-		cfg_size = pp->cfg1_size;
-		va_cfg_base = pp->va_cfg1_base;
-	}
-
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
-				  type, cpu_addr,
-				  busdev, cfg_size);
-	ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
-	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
-				  PCIE_ATU_TYPE_IO, pp->io_base,
-				  pp->io_bus_addr, pp->io_size);
-
-	return ret;
-}
-
-static int dw_pcie_valid_config(struct pcie_port *pp,
-				struct pci_bus *bus, int dev)
-{
-	/* If there is no link, then there is no device */
-	if (bus->number != pp->root_bus_nr) {
-		if (!dw_pcie_link_up(pp))
-			return 0;
-	}
-
-	/* access only one slot on each root port */
-	if (bus->number == pp->root_bus_nr && dev > 0)
-		return 0;
-
-	/*
-	 * do not read more than one device on the bus directly attached
-	 * to RC's (Virtual Bridge's) DS side.
-	 */
-	if (bus->primary == pp->root_bus_nr && dev > 0)
-		return 0;
-
-	return 1;
-}
-
-static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
-			int size, u32 *val)
-{
-	struct pcie_port *pp = bus->sysdata;
-
-	if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
-		*val = 0xffffffff;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-
-	if (bus->number == pp->root_bus_nr)
-		return dw_pcie_rd_own_conf(pp, where, size, val);
-
-	return dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val);
-}
-
-static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
-			int where, int size, u32 val)
-{
-	struct pcie_port *pp = bus->sysdata;
-
-	if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	if (bus->number == pp->root_bus_nr)
-		return dw_pcie_wr_own_conf(pp, where, size, val);
-
-	return dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val);
-}
-
-static struct pci_ops dw_pcie_ops = {
-	.read = dw_pcie_rd_conf,
-	.write = dw_pcie_wr_conf,
-};
-
-void dw_pcie_setup_rc(struct pcie_port *pp)
-{
-	u32 val;
+		pci->lanes = 0;
 
 	/* set the number of lanes */
-	dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val);
+	dw_pcie_read_dbi(pci, base, PCIE_PORT_LINK_CONTROL, 0x4, &val);
 	val &= ~PORT_LINK_MODE_MASK;
-	switch (pp->lanes) {
+	switch (pci->lanes) {
 	case 1:
 		val |= PORT_LINK_MODE_1_LANES;
 		break;
@@ -736,15 +173,15 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 		val |= PORT_LINK_MODE_8_LANES;
 		break;
 	default:
-		dev_err(pp->dev, "num-lanes %u: invalid value\n", pp->lanes);
+		dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->lanes);
 		return;
 	}
-	dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL);
+	dw_pcie_write_dbi(pci, base, PCIE_PORT_LINK_CONTROL, 0x4, val);
 
 	/* set link width speed control register */
-	dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, &val);
+	dw_pcie_read_dbi(pci, base, PCIE_LINK_WIDTH_SPEED_CONTROL, 0x4, &val);
 	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
-	switch (pp->lanes) {
+	switch (pci->lanes) {
 	case 1:
 		val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
 		break;
@@ -758,49 +195,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 		val |= PORT_LOGIC_LINK_WIDTH_8_LANES;
 		break;
 	}
-	dw_pcie_writel_rc(pp, val, PCIE_LINK_WIDTH_SPEED_CONTROL);
-
-	/* setup RC BARs */
-	dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0);
-	dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1);
-
-	/* setup interrupt pins */
-	dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val);
-	val &= 0xffff00ff;
-	val |= 0x00000100;
-	dw_pcie_writel_rc(pp, val, PCI_INTERRUPT_LINE);
-
-	/* setup bus numbers */
-	dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS, &val);
-	val &= 0xff000000;
-	val |= 0x00010100;
-	dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
-
-	/* setup command register */
-	dw_pcie_readl_rc(pp, PCI_COMMAND, &val);
-	val &= 0xffff0000;
-	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-	dw_pcie_writel_rc(pp, val, PCI_COMMAND);
-
-	/*
-	 * If the platform provides ->rd_other_conf, it means the platform
-	 * uses its own address translation component rather than ATU, so
-	 * we should not program the ATU here.
-	 */
-	if (!pp->ops->rd_other_conf)
-		dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
-					  PCIE_ATU_TYPE_MEM, pp->mem_base,
-					  pp->mem_bus_addr, pp->mem_size);
-
-	dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
-
-	/* program correct class for RC */
-	dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
-
-	dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
-	val |= PORT_LOGIC_SPEED_CHANGE;
-	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
+	dw_pcie_write_dbi(pci, base, PCIE_LINK_WIDTH_SPEED_CONTROL, 0x4, val);
 }
 
 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
diff --git a/drivers/pci/controller/pcie-designware.h b/drivers/pci/controller/pcie-designware.h
index f437f9b..53eaa50 100644
--- a/drivers/pci/controller/pcie-designware.h
+++ b/drivers/pci/controller/pcie-designware.h
@@ -14,6 +14,59 @@
 #ifndef _PCIE_DESIGNWARE_H
 #define _PCIE_DESIGNWARE_H
 
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+
+/* Synopsis specific PCIE configuration registers */
+#define PCIE_PORT_LINK_CONTROL		0x710
+#define PORT_LINK_MODE_MASK		(0x3f << 16)
+#define PORT_LINK_MODE_1_LANES		(0x1 << 16)
+#define PORT_LINK_MODE_2_LANES		(0x3 << 16)
+#define PORT_LINK_MODE_4_LANES		(0x7 << 16)
+#define PORT_LINK_MODE_8_LANES		(0xf << 16)
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
+#define PORT_LOGIC_SPEED_CHANGE		(0x1 << 17)
+#define PORT_LOGIC_LINK_WIDTH_MASK	(0x1f << 8)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES	(0x1 << 8)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES	(0x2 << 8)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES	(0x4 << 8)
+#define PORT_LOGIC_LINK_WIDTH_8_LANES	(0x8 << 8)
+
+#define PCIE_MSI_ADDR_LO		0x820
+#define PCIE_MSI_ADDR_HI		0x824
+#define PCIE_MSI_INTR0_ENABLE		0x828
+#define PCIE_MSI_INTR0_MASK		0x82C
+#define PCIE_MSI_INTR0_STATUS		0x830
+
+#define PCIE_ATU_VIEWPORT		0x900
+#define PCIE_ATU_REGION_INBOUND		(0x1 << 31)
+#define PCIE_ATU_REGION_OUTBOUND	(0x0 << 31)
+#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
+#define PCIE_ATU_CR1			0x904
+#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
+#define PCIE_ATU_TYPE_IO		(0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
+#define PCIE_ATU_CR2			0x908
+#define PCIE_ATU_ENABLE			(0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
+#define PCIE_ATU_LOWER_BASE		0x90C
+#define PCIE_ATU_UPPER_BASE		0x910
+#define PCIE_ATU_LIMIT			0x914
+#define PCIE_ATU_LOWER_TARGET		0x918
+#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
+#define PCIE_ATU_UPPER_TARGET		0x91C
+
+/* PCIe Port Logic registers */
+#define PLR_OFFSET			0x700
+#define PCIE_PHY_DEBUG_R1		(PLR_OFFSET + 0x2c)
+#define PCIE_PHY_DEBUG_R1_LINK_UP	0x00000010
+
 /*
  * Maximum number of MSI IRQs can be 256 per controller. But keep
  * it 32 as of now. Probably we will never need more than 32. If needed,
@@ -27,10 +80,34 @@
 #define LINK_WAIT_USLEEP_MIN		90000
 #define LINK_WAIT_USLEEP_MAX		100000
 
+struct dw_pcie;
+struct pcie_port;
+
+enum dw_pcie_device_mode {
+	DW_PCIE_UNKNOWN_TYPE,
+	DW_PCIE_EP_TYPE,
+	DW_PCIE_LEG_EP_TYPE,
+	DW_PCIE_RC_TYPE,
+};
+
+struct dw_pcie_host_ops {
+	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
+	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			     unsigned int devfn, int where, int size, u32 *val);
+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			    unsigned int devfn, int where, int size, u32 val);
+	void (*host_init)(struct pcie_port *pp);
+	void (*msi_set_irq)(struct pcie_port *pp, int irq);
+	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
+	phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
+	u32 (*get_msi_data)(struct pcie_port *pp, int pos);
+	void (*scan_bus)(struct pcie_port *pp);
+	int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
+};
+
 struct pcie_port {
-	struct device		*dev;
 	u8			root_bus_nr;
-	void __iomem		*dbi_base;
 	u64			cfg0_base;
 	void __iomem		*va_cfg0_base;
 	u32			cfg0_size;
@@ -48,42 +125,69 @@ struct pcie_port {
 	struct resource		*mem;
 	struct resource		*busn;
 	int			irq;
-	u32			lanes;
-	struct pcie_host_ops	*ops;
+	const struct dw_pcie_host_ops *ops;
 	int			msi_irq;
 	struct irq_domain	*irq_domain;
 	unsigned long		msi_data;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
-struct pcie_host_ops {
-	void (*readl_rc)(struct pcie_port *pp,
-			void __iomem *dbi_base, u32 *val);
-	void (*writel_rc)(struct pcie_port *pp,
-			u32 val, void __iomem *dbi_base);
-	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
-	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
-	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
-			unsigned int devfn, int where, int size, u32 *val);
-	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
-			unsigned int devfn, int where, int size, u32 val);
-	int (*link_up)(struct pcie_port *pp);
-	void (*host_init)(struct pcie_port *pp);
-	void (*msi_set_irq)(struct pcie_port *pp, int irq);
-	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
-	phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
-	u32 (*get_msi_data)(struct pcie_port *pp, int pos);
-	void (*scan_bus)(struct pcie_port *pp);
-	int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
+struct dw_pcie_ops {
+	void	(*read_dbi)(struct dw_pcie *pcie, void __iomem *base, int size,
+			    u32 *val);
+	void	(*write_dbi)(struct dw_pcie *pcie, void __iomem *base,
+			     int size, u32 val);
+	int	(*link_up)(struct dw_pcie *pcie);
+	int	(*start_link)(struct dw_pcie *pcie);
+	void	(*stop_link)(struct dw_pcie *pcie);
 };
 
-int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
-int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
+struct dw_pcie {
+	struct device		*dev;
+	void __iomem		*dbi_base;
+	void __iomem		*dbi_base2;
+	u32			lanes;
+	const struct dw_pcie_ops *ops;
+	struct pcie_port	pp;
+};
+
+#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
+
+int dw_pcie_wait_for_link(struct dw_pcie *pci);
+int dw_pcie_link_up(struct dw_pcie *pci);
+void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
+			       int type, u64 cpu_addr, u64 pci_addr,
+			       u32 size);
+int dw_pcie_read(void __iomem *addr, int size, u32 *val);
+int dw_pcie_write(void __iomem *addr, int size, u32 val);
+void dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
+		      u32 reg, int size, u32 *val);
+void dw_pcie_write_dbi(struct dw_pcie *pci, void *base, u32 reg,
+		       int size, u32 val);
+void dw_pcie_setup(struct dw_pcie *pci);
+
+#ifdef CONFIG_PCIE_DW_HOST
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
-int dw_pcie_wait_for_link(struct pcie_port *pp);
-int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
+#else
+static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
+{
+	return IRQ_NONE;
+}
+
+static inline void dw_pcie_msi_init(struct pcie_port *pp)
+{
+}
+
+static inline void dw_pcie_setup_rc(struct pcie_port *pp)
+{
+}
 
+static inline int dw_pcie_host_init(struct pcie_port *pp)
+{
+	return 0;
+}
+#endif
 #endif /* _PCIE_DESIGNWARE_H */
-- 
1.7.9.5

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

* [RFC PATCH] pci: controller: designware: Add EP mode support
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (5 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] pci: controller: split designware into *core* and *host* Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] pci: controller: dra7xx: " Kishon Vijay Abraham I
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

Add endpoint mode support to designware driver. This uses the
EP Core layer introduced recently to add endpoint mode support.
*Any* function driver can now use this designware device
to achieve the EP functionality.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../devicetree/bindings/pci/designware-pcie.txt    |   26 ++-
 drivers/pci/controller/Kconfig                     |    5 +
 drivers/pci/controller/Makefile                    |    1 +
 drivers/pci/controller/pcie-designware-ep.c        |  228 ++++++++++++++++++++
 drivers/pci/controller/pcie-designware.c           |   30 +++
 drivers/pci/controller/pcie-designware.h           |   45 ++++
 6 files changed, 324 insertions(+), 11 deletions(-)
 create mode 100644 drivers/pci/controller/pcie-designware-ep.c

diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
index 6c5322c..bb0b789 100644
--- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
@@ -6,23 +6,27 @@ Required properties:
 - reg-names: Must be "config" for the PCIe configuration space.
     (The old way of getting the configuration address space from "ranges"
     is deprecated and should be avoided.)
-- #address-cells: set to <3>
-- #size-cells: set to <2>
-- device_type: set to "pci"
-- ranges: ranges for the PCI memory and I/O regions
-- #interrupt-cells: set to <1>
-- interrupt-map-mask and interrupt-map: standard PCI properties
-	to define the mapping of the PCIe interface to interrupt
+- #address-cells (only for host mode): set to <3>
+- #size-cells (only for host mode): set to <2>
+- device_type (only for host mode): set to "pci"
+- ranges (only for host mode): ranges for the PCI memory and I/O regions
+- num-ib-windows (only for EP mode): number of inbound address translation
+	windows
+- num-ob-windows (only for EP mode): number of outbound address translation
+	windows
+- #interrupt-cells (only for host mode): set to <1>
+- interrupt-map-mask and interrupt-map (only for host mode): standard PCI
+	properties to define the mapping of the PCIe interface to interrupt
 	numbers.
 - num-lanes: number of lanes to use
 
 Optional properties:
 - num-lanes: number of lanes to use (this property should be specified unless
   the link is brought already up in BIOS)
-- reset-gpio: gpio pin number of power good signal
-- bus-range: PCI bus numbers covered (it is recommended for new devicetrees to
-  specify this property, to keep backwards compatibility a range of 0x00-0xff
-  is assumed if not present)
+- reset-gpio (only for host mode): gpio pin number of power good signal
+- bus-range (only for host mode): PCI bus numbers covered (it is recommended
+  for new devicetrees to specify this property, to keep backwards compatibility
+  a range of 0x00-0xff is assumed if not present)
 - clocks: Must contain an entry for each entry in clock-names.
 	See ../clocks/clock-bindings.txt for details.
 - clock-names: Must include the following entries:
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 249db74..8574828 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -78,6 +78,11 @@ config PCIE_DW_HOST
 	depends on PCI
 	select PCIE_DW
 
+config PCIE_DW_EP
+	bool
+	depends on PCI_ENDPOINT
+	select PCIE_DW
+
 config PCI_EXYNOS
 	bool "Samsung Exynos PCIe controller"
 	depends on SOC_EXYNOS5440
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index ee6bb85..11ef1e6 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o
 obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o
+obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o
 obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
 obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
diff --git a/drivers/pci/controller/pcie-designware-ep.c b/drivers/pci/controller/pcie-designware-ep.c
new file mode 100644
index 0000000..f683be9
--- /dev/null
+++ b/drivers/pci/controller/pcie-designware-ep.c
@@ -0,0 +1,228 @@
+/**
+ * pci-designware-ep.c - Synopsys Designware PCIe Endpoint controller driver
+ *
+ * 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/of.h>
+
+#include "pcie-designware.h"
+
+static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
+{
+	u32 reg;
+
+	reg = PCI_BASE_ADDRESS_0 + (4 * bar);
+	dw_pcie_write_dbi(pci, pci->dbi_base2, reg, 0x4, 0x0);
+	dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x4, 0x0);
+}
+
+static int dw_pcie_ep_write_header(struct pci_epc *epc,
+				   struct pci_epf_header *hdr)
+{
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	void __iomem *base = pci->dbi_base;
+
+	dw_pcie_write_dbi(pci, base, PCI_VENDOR_ID, 0x2, hdr->vendorid);
+	dw_pcie_write_dbi(pci, base, PCI_DEVICE_ID, 0x2, hdr->deviceid);
+	dw_pcie_write_dbi(pci, base, PCI_REVISION_ID, 0x1, hdr->revid);
+	dw_pcie_write_dbi(pci, base, PCI_CLASS_PROG, 0x1, hdr->progif_code);
+	dw_pcie_write_dbi(pci, base, PCI_CLASS_DEVICE, 0x2,
+			  hdr->subclass_code | hdr->baseclass_code << 8);
+	dw_pcie_write_dbi(pci, base, PCI_CACHE_LINE_SIZE, 0x1,
+			  hdr->cache_line_size);
+	dw_pcie_write_dbi(pci, base, PCI_SUBSYSTEM_VENDOR_ID, 0x2,
+			  hdr->subsys_vendor_id);
+	dw_pcie_write_dbi(pci, base, PCI_SUBSYSTEM_ID, 0x2, hdr->subsys_id);
+	dw_pcie_write_dbi(pci, base, PCI_INTERRUPT_PIN, 0x1,
+			  hdr->interrupt_pin);
+
+	return 0;
+}
+
+static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
+				  dma_addr_t cpu_addr,
+				  enum dw_pcie_as_type as_type)
+{
+	int ret;
+	u32 free_win;
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+	free_win = find_first_zero_bit(&ep->ib_window_map,
+				       sizeof(ep->ib_window_map));
+	if (free_win >= ep->num_ib_windows) {
+		dev_err(pci->dev, "no free inbound window\n");
+		return -EINVAL;
+	}
+
+	ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr,
+				       as_type);
+	if (ret < 0) {
+		dev_err(pci->dev, "Failed to program IB window\n");
+		return ret;
+	}
+
+	ep->bar_to_atu[bar] = free_win;
+	set_bit(free_win, &ep->ib_window_map);
+
+	return 0;
+}
+
+static int dw_pcie_ep_set_bar(struct pci_epc *epc, enum pci_barno bar,
+			      dma_addr_t bar_phys, size_t size, int flags)
+{
+	int ret;
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	enum dw_pcie_as_type as_type;
+	u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
+
+	if (!(flags & PCI_BASE_ADDRESS_SPACE))
+		as_type = DW_PCIE_AS_MEM;
+	else
+		as_type = DW_PCIE_AS_IO;
+
+	ret = dw_pcie_ep_inbound_atu(ep, bar, bar_phys, as_type);
+	if (ret)
+		return ret;
+
+	dw_pcie_write_dbi(pci, pci->dbi_base2, reg, 0x4, size - 1);
+	dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x4, flags);
+
+	return 0;
+}
+
+static void dw_pcie_ep_clear_bar(struct pci_epc *epc, enum pci_barno bar)
+{
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	void __iomem *base = pci->dbi_base;
+
+	dw_pcie_ep_reset_bar(pci, bar);
+
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_VIEWPORT, 0x4,
+			  PCIE_ATU_REGION_INBOUND | ep->bar_to_atu[bar]);
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_CR2, 0x4, ~PCIE_ATU_ENABLE);
+}
+
+static void *dw_pcie_ep_alloc_addr(struct pci_epc *epc, size_t size)
+{
+	/* TODO */
+	return NULL;
+}
+
+static void dw_pcie_ep_free_addr(struct pci_epc *epc)
+{
+	/* TODO */
+}
+
+static int dw_pcie_ep_raise_irq(struct pci_epc *epc,
+				enum pci_epc_irq_type type)
+{
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+
+	if (!ep->ops->raise_irq)
+		return -EINVAL;
+
+	return ep->ops->raise_irq(ep, type);
+}
+
+static int dw_pcie_ep_start(struct pci_epc *epc)
+{
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+	if (!pci->ops->start_link)
+		return -EINVAL;
+
+	return pci->ops->start_link(pci);
+}
+
+static void dw_pcie_ep_stop(struct pci_epc *epc)
+{
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+	if (!pci->ops->stop_link)
+		return;
+
+	pci->ops->stop_link(pci);
+}
+
+void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
+{
+	struct pci_epc *epc = ep->epc;
+	struct pci_epf *epf = epc->epf;
+
+	pci_epf_linkup(epf);
+}
+
+const struct pci_epc_ops epc_ops = {
+	.write_header		= dw_pcie_ep_write_header,
+	.set_bar		= dw_pcie_ep_set_bar,
+	.clear_bar		= dw_pcie_ep_clear_bar,
+	.alloc_addr_space	= dw_pcie_ep_alloc_addr,
+	.free_addr_space	= dw_pcie_ep_free_addr,
+	.raise_irq		= dw_pcie_ep_raise_irq,
+	.start			= dw_pcie_ep_start,
+	.stop			= dw_pcie_ep_stop,
+};
+
+int dw_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+	int ret;
+	enum pci_barno bar;
+	struct pci_epc *epc;
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	struct device *dev = pci->dev;
+	struct device_node *np = dev->of_node;
+
+	ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
+	if (ret < 0) {
+		dev_err(dev, "unable to read *num-ib-windows* property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows);
+	if (ret < 0) {
+		dev_err(dev, "unable to read *num-ob-windows* property\n");
+		return ret;
+	}
+
+	for (bar = BAR_0; bar <= BAR_5; bar++)
+		dw_pcie_ep_reset_bar(pci, bar);
+
+	if (ep->ops->ep_init)
+		ep->ops->ep_init(ep);
+
+	epc = devm_pci_epc_create(dev, &epc_ops);
+	if (IS_ERR(epc)) {
+		dev_err(dev, "failed to create epc device\n");
+		return PTR_ERR(epc);
+	}
+
+	ep->epc = epc;
+	epc_set_drvdata(epc, ep);
+	dw_pcie_setup(pci);
+
+	return 0;
+}
+
+MODULE_DESCRIPTION("Designware PCIe endpoint controller driver");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/pcie-designware.c b/drivers/pci/controller/pcie-designware.c
index e52a020..4c091ff 100644
--- a/drivers/pci/controller/pcie-designware.c
+++ b/drivers/pci/controller/pcie-designware.c
@@ -115,6 +115,36 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
 	dw_pcie_read_dbi(pci, base, PCIE_ATU_CR2, 0x4, &val);
 }
 
+int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
+			     u64 cpu_addr, enum dw_pcie_as_type as_type)
+{
+	int type;
+	void __iomem *base = pci->dbi_base;
+
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_VIEWPORT, 0x4,
+			  PCIE_ATU_REGION_INBOUND | index);
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_LOWER_TARGET, 0x4,
+			  lower_32_bits(cpu_addr));
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_UPPER_TARGET, 0x4,
+			   upper_32_bits(cpu_addr));
+
+	switch (as_type) {
+	case DW_PCIE_AS_MEM:
+		type = PCIE_ATU_TYPE_MEM;
+		break;
+	case DW_PCIE_AS_IO:
+		type = PCIE_ATU_TYPE_IO;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_CR1, 0x4, type);
+	dw_pcie_write_dbi(pci, base, PCIE_ATU_CR2, 0x4, PCIE_ATU_ENABLE |
+			  PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
+	return 0;
+}
+
 int dw_pcie_wait_for_link(struct dw_pcie *pci)
 {
 	int retries;
diff --git a/drivers/pci/controller/pcie-designware.h b/drivers/pci/controller/pcie-designware.h
index 53eaa50..773bd35 100644
--- a/drivers/pci/controller/pcie-designware.h
+++ b/drivers/pci/controller/pcie-designware.h
@@ -18,6 +18,9 @@
 #include <linux/msi.h>
 #include <linux/pci.h>
 
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
 /* Synopsis specific PCIE configuration registers */
 #define PCIE_PORT_LINK_CONTROL		0x710
 #define PORT_LINK_MODE_MASK		(0x3f << 16)
@@ -82,6 +85,7 @@
 
 struct dw_pcie;
 struct pcie_port;
+struct dw_pcie_ep;
 
 enum dw_pcie_device_mode {
 	DW_PCIE_UNKNOWN_TYPE,
@@ -132,6 +136,27 @@ struct pcie_port {
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
+enum dw_pcie_as_type {
+	DW_PCIE_AS_UNKNOWN,
+	DW_PCIE_AS_MEM,
+	DW_PCIE_AS_IO,
+};
+
+struct dw_pcie_ep_ops {
+	void	(*ep_init)(struct dw_pcie_ep *ep);
+	int	(*raise_irq)(struct dw_pcie_ep *ep, enum pci_epc_irq_type type);
+};
+
+struct dw_pcie_ep {
+	struct pci_epc		*epc;
+	struct dw_pcie_ep_ops	*ops;
+	u8			bar_to_atu[6];
+	unsigned long		ib_window_map;
+	unsigned long		ob_window_map;
+	u32			num_ib_windows;
+	u32			num_ob_windows;
+};
+
 struct dw_pcie_ops {
 	void	(*read_dbi)(struct dw_pcie *pcie, void __iomem *base, int size,
 			    u32 *val);
@@ -149,15 +174,21 @@ struct dw_pcie {
 	u32			lanes;
 	const struct dw_pcie_ops *ops;
 	struct pcie_port	pp;
+	struct dw_pcie_ep	ep;
 };
 
 #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
 
+#define to_dw_pcie_from_ep(endpoint)   \
+		container_of((endpoint), struct dw_pcie, ep)
+
 int dw_pcie_wait_for_link(struct dw_pcie *pci);
 int dw_pcie_link_up(struct dw_pcie *pci);
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
 			       int type, u64 cpu_addr, u64 pci_addr,
 			       u32 size);
+int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
+			     u64 cpu_addr, enum dw_pcie_as_type as_type);
 int dw_pcie_read(void __iomem *addr, int size, u32 *val);
 int dw_pcie_write(void __iomem *addr, int size, u32 val);
 void dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
@@ -166,6 +197,20 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, void *base, u32 reg,
 		       int size, u32 val);
 void dw_pcie_setup(struct dw_pcie *pci);
 
+#ifdef CONFIG_PCIE_DW_EP
+void dw_pcie_ep_linkup(struct dw_pcie_ep *ep);
+int dw_pcie_ep_init(struct dw_pcie_ep *ep);
+#else
+static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
+{
+}
+
+static inline int dw_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_PCIE_DW_HOST
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
-- 
1.7.9.5

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

* [RFC PATCH] pci: controller: dra7xx: Add EP mode support
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (6 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] pci: controller: designware: Add EP mode support Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] misc: add a new host side PCI endpoint test driver Kishon Vijay Abraham I
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

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

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

* [RFC PATCH] misc: add a new host side PCI endpoint test driver
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (7 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] pci: controller: dra7xx: " Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] ARM: dts: DRA7: Modify pcie1 dt node for EP mode Kishon Vijay Abraham I
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

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

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

* [RFC PATCH] ARM: dts: DRA7: Modify pcie1 dt node for EP mode
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (8 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] misc: add a new host side PCI endpoint test driver Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-13 17:10 ` [RFC PATCH] HACK: pci: controller: dra7xx: disable smart idle Kishon Vijay Abraham I
  2016-09-14  5:06 ` [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

Modify pcie1 dt node in order for the controller to operate in
endpoint mode. This is used only for testing EP mode.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 arch/arm/boot/dts/dra7.dtsi |   43 +++++++++++--------------------------------
 1 file changed, 11 insertions(+), 32 deletions(-)

diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index d9bfb94..73f63d1 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -283,38 +283,17 @@
 			};
 		};
 
-		axi@0 {
-			compatible = "simple-bus";
-			#size-cells = <1>;
-			#address-cells = <1>;
-			ranges = <0x51000000 0x51000000 0x3000
-				  0x0	     0x20000000 0x10000000>;
-			pcie1: pcie@51000000 {
-				compatible = "ti,dra7-pcie";
-				reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>;
-				reg-names = "rc_dbics", "ti_conf", "config";
-				interrupts = <0 232 0x4>, <0 233 0x4>;
-				#address-cells = <3>;
-				#size-cells = <2>;
-				device_type = "pci";
-				ranges = <0x81000000 0 0          0x03000 0 0x00010000
-					  0x82000000 0 0x20013000 0x13000 0 0xffed000>;
-				#interrupt-cells = <1>;
-				num-lanes = <1>;
-				ti,hwmods = "pcie1";
-				phys = <&pcie1_phy>;
-				phy-names = "pcie-phy0";
-				interrupt-map-mask = <0 0 0 7>;
-				interrupt-map = <0 0 0 1 &pcie1_intc 1>,
-						<0 0 0 2 &pcie1_intc 2>,
-						<0 0 0 3 &pcie1_intc 3>,
-						<0 0 0 4 &pcie1_intc 4>;
-				pcie1_intc: interrupt-controller {
-					interrupt-controller;
-					#address-cells = <0>;
-					#interrupt-cells = <1>;
-				};
-			};
+		pcie1: pcie@51000000 {
+			compatible = "ti,dra7-pcie-ep";
+			reg = <0x51000000 0x28>, <0x51002000 0x14c>, <0x51001000 0x28>;
+			reg-names = "ep_dbics", "ti_conf", "ep_dbics2";
+			interrupts = <0 232 0x4>;
+			num-lanes = <1>;
+			num-ib-windows = <4>;
+			num-ob-windows = <16>;
+			ti,hwmods = "pcie1";
+			phys = <&pcie1_phy>;
+			phy-names = "pcie-phy0";
 		};
 
 		axi@1 {
-- 
1.7.9.5

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

* [RFC PATCH] HACK: pci: controller: dra7xx: disable smart idle
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (9 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] ARM: dts: DRA7: Modify pcie1 dt node for EP mode Kishon Vijay Abraham I
@ 2016-09-13 17:10 ` Kishon Vijay Abraham I
  2016-09-14  5:06 ` [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-13 17:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, kishon, nsekhar

Smart idle prevents RC to access the memory space of this
controller. Set the idle mode to smart idle wakeup. This
should ideally be done in hwmod. Till it's figured out how
to configure it in hwmod, mark this as HACK.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/pci-dra7xx.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/pci/controller/pci-dra7xx.c b/drivers/pci/controller/pci-dra7xx.c
index 5b49367..31211e6 100644
--- a/drivers/pci/controller/pci-dra7xx.c
+++ b/drivers/pci/controller/pci-dra7xx.c
@@ -30,6 +30,14 @@
 
 /* PCIe controller wrapper DRA7XX configuration registers */
 
+#define	PCIECTRL_DRA7XX_CONF_SYSCONFIG			0x0010
+#define SIDLE_MASK					3
+#define SIDLE_SHIFT					2
+#define SIDLE_FORCE					0x0
+#define SIDLE_NO					0x1
+#define SIDLE_SMART					0x2
+#define SIDLE_SMART_WKUP				0x3
+
 #define	PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN		0x0024
 #define	PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN		0x0028
 #define	ERR_SYS						BIT(0)
@@ -606,6 +614,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 			goto err_gpio;
 		break;
 	case DW_PCIE_EP_TYPE:
+		reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_SYSCONFIG);
+		reg &= ~(SIDLE_MASK << SIDLE_SHIFT);
+		reg |= SIDLE_SMART_WKUP << SIDLE_SHIFT;
+		dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_SYSCONFIG, reg);
 		dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
 				   DEVICE_TYPE_EP);
 		ret = dra7xx_add_pcie_ep(dra7xx, pdev);
-- 
1.7.9.5

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

* Re: [RFC PATCH] pci: support for configurable PCI endpoint
  2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
                   ` (10 preceding siblings ...)
  2016-09-13 17:10 ` [RFC PATCH] HACK: pci: controller: dra7xx: disable smart idle Kishon Vijay Abraham I
@ 2016-09-14  5:06 ` Kishon Vijay Abraham I
  11 siblings, 0 replies; 13+ messages in thread
From: Kishon Vijay Abraham I @ 2016-09-14  5:06 UTC (permalink / raw)
  To: Bjorn Helgaas, Arnd Bergmann, Jingoo Han, hch, Joao.Pinto,
	mingkai.hu, m-karicheri2, Pratyush Anand
  Cc: linux-pci, linux-doc, linux-kernel, devicetree, linux-omap,
	linux-arm-kernel, Joao Pinto, Rob Herring, nsekhar

Hi,

Will resend the series with patch numbering.

Thanks
Kishon

On Tuesday 13 September 2016 10:40 PM, 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
> 
> Known Limitation:
> 	*) Does not support multi-function devices
> 
> TODO:
> 	*) access buffers in RC
> 	*) MSI interrupts
> 	*) Enable user space control for the RC side PCI driver
> 	*) Adapt all other users of designware to use the new design
> 
> 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
> 

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

end of thread, other threads:[~2016-09-14  5:07 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-13 17:10 [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: add EP core layer to enable EP controller and EP functions Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: introduce configfs entry for configuring " Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] Documentation: PCI: guide to use PCI Endpoint Core Layer Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] pci: endpoint: functions: add an EP function to test PCI Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] pci: rename *host* directory to *controller* Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] pci: controller: split designware into *core* and *host* Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] pci: controller: designware: Add EP mode support Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] pci: controller: dra7xx: " Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] misc: add a new host side PCI endpoint test driver Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] ARM: dts: DRA7: Modify pcie1 dt node for EP mode Kishon Vijay Abraham I
2016-09-13 17:10 ` [RFC PATCH] HACK: pci: controller: dra7xx: disable smart idle Kishon Vijay Abraham I
2016-09-14  5:06 ` [RFC PATCH] pci: support for configurable PCI endpoint Kishon Vijay Abraham I

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).