linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/21] Implement NTB Controller using multiple PCI
@ 2019-09-26 11:29 Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 01/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Bus Kishon Vijay Abraham I
                   ` (21 more replies)
  0 siblings, 22 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

This series is sent as RFC since this series is dependent on
[1] (cannot be merged before that series) and to get early review
comments.

I'll also split this series into smaller chunk when I post the
next revision.

This series is about implementing SW defined NTB using
multiple endpoint instances. This series has been tested using
2 endpoint instances in J7 connected to two DRA7 boards.

This was presented in Linux Plumbers Conference. The presentation
can be found @ [2]

This series:
  *) Add support to define endpoint function using device tree
  *) Add a specification for implementing NTB controller using
     multiple endpoint instances.
  *) Add a NTB endpoint function driver and a NTB host side PCI
     driver that follows the specification.
  *) Add support in PCIe endpoint core to support secondary
     interface.
  *) Add a device tree overlay file to configure J7 as NTB

The test setup is something like below
   +-------------+                                   +-------------+
   |             |                                   |             |
   |    DRA72    |                                   |    DRA76    |
   |             |                                   |             |
   +------^------+                                   +------^------+
          |                                                 |
          |                                                 |
+---------|-------------------------------------------------|---------+
|  +------v------+                                   +------v------+  |
|  |             |                                   |             |  |
|  |     EP      |                                   |     EP      |  |
|  | CONTROLLER1 |                                   | CONTROLLER2 |  |
|  |             <----------------------------------->             |  |
|  |             |                                   |             |  |
|  |             |                                   |             |  |
|  |             |                 J7                |             |  |
|  |             |  (Configured using NTB Function)  |             |  |
|  +-------------+                                   +-------------+  |
+---------------------------------------------------------------------+

Here DRA72 and DRA76 could be replaced with *any* PCI host.

EP side (J7):
=============

In the kernel:
        cd /sys/kernel/config/pci_ep/
        echo 1 > controllers/d800000.pcie-ep/start
        echo 1 > controllers/d000000.pcie-ep/start

RC side (DRA7):
===============
        echo 0000:01:00.0 > /sys/bus/pci/devices/0000\:01\:00.0/driver/unbind
        echo 0000:01:00.0 > /sys/bus/pci/drivers/ntb_hw_epf/bind
        modprobe ntb_transport
        modprobe ntb_netdev

On each of the hosts Ethernet Interface will be created.

Provide an IP address to each of the hosts:
HOST1 (dra72):
ifconfig eth2 192.168.1.2 up

HOST2 (dra76):
ifconfig eth2 192.168.1.1 up

Once this is done standard network utilities like ping or iperf can be
used.

root@dra7xx-evm:~# iperf -c 192.168.1.2
------------------------------------------------------------
Client connecting to 192.168.1.2, TCP port 5001
TCP window size: 2.50 MByte (default)
------------------------------------------------------------
[  3] local 192.168.1.1 port 60814 connected with 192.168.1.2 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec   705 MBytes   591 Mbits/sec

[1] -> http://lore.kernel.org/r/20190604131516.13596-1-kishon@ti.com
[2] -> https://www.linuxplumbersconf.org/event/4/contributions/395/attachments/284/481/Implementing_NTB_Controller_Using_PCIe_Endpoint_-_final.pdf

Kishon Vijay Abraham I (21):
  dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Bus
  dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device
  dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF NTB Device
  Documentation: PCI: Add specification for the *PCI NTB* function
    device
  PCI: endpoint: Add API to get reference to EPC from device-tree
  PCI: endpoint: Add API to create EPF device from device tree
  PCI: endpoint: Add "pci-epf-bus" driver
  PCI: endpoint: Make *_get_first_free_bar() take into account 64 bit
    BAR
  PCI: endpoint: Add helper API to get the 'next' unreserved BAR
  PCI: endpoint: Make pci_epf_driver ops optional
  PCI: endpoint: Add helper API to populate header with values from DT
  PCI: endpoint: Add support to associate secondary EPC with EPF
  PCI: endpoint: Add pci_epc_ops to map MSI irq
  PCI: cadence: Implement ->msi_map_irq() ops
  PCI: endpoint: Remove unused pci_epf_match_device()
  PCI: endpoint: Fix missing mutex_unlock in error case
  PCI: endpoint: *_free_bar() to return error codes on failure
  PCI: endpoint: Add EP function driver to provide NTB functionality
  PCI: Add TI J721E device to pci ids
  NTB: Add support for EPF PCI-Express Non-Transparent Bridge
  NTB: tool: Enable the NTB/PCIe link on the local or remote side of
    bridge

 Documentation/PCI/endpoint/pci-test-ntb.txt   |  315 +++++
 .../bindings/pci/endpoint/pci-epf-bus.txt     |   27 +
 .../bindings/pci/endpoint/pci-epf-ntb.txt     |   31 +
 .../bindings/pci/endpoint/pci-epf.txt         |   28 +
 drivers/ntb/hw/Kconfig                        |    1 +
 drivers/ntb/hw/Makefile                       |    1 +
 drivers/ntb/hw/epf/Kconfig                    |    5 +
 drivers/ntb/hw/epf/Makefile                   |    1 +
 drivers/ntb/hw/epf/ntb_hw_epf.c               |  648 ++++++++++
 drivers/ntb/test/ntb_tool.c                   |    1 +
 drivers/pci/controller/pcie-cadence-ep.c      |   59 +
 drivers/pci/endpoint/Makefile                 |    3 +-
 drivers/pci/endpoint/functions/Kconfig        |   12 +
 drivers/pci/endpoint/functions/Makefile       |    1 +
 drivers/pci/endpoint/functions/pci-epf-ntb.c  | 1143 +++++++++++++++++
 drivers/pci/endpoint/functions/pci-epf-test.c |   12 +-
 drivers/pci/endpoint/pci-ep-cfs.c             |    6 +-
 drivers/pci/endpoint/pci-epc-core.c           |  221 +++-
 drivers/pci/endpoint/pci-epf-bus.c            |   54 +
 drivers/pci/endpoint/pci-epf-core.c           |  133 +-
 include/linux/pci-epc.h                       |   42 +-
 include/linux/pci-epf.h                       |   35 +-
 include/linux/pci_ids.h                       |    1 +
 23 files changed, 2715 insertions(+), 65 deletions(-)
 create mode 100644 Documentation/PCI/endpoint/pci-test-ntb.txt
 create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf-bus.txt
 create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf-ntb.txt
 create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
 create mode 100644 drivers/ntb/hw/epf/Kconfig
 create mode 100644 drivers/ntb/hw/epf/Makefile
 create mode 100644 drivers/ntb/hw/epf/ntb_hw_epf.c
 create mode 100644 drivers/pci/endpoint/functions/pci-epf-ntb.c
 create mode 100644 drivers/pci/endpoint/pci-epf-bus.c

-- 
2.17.1


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

* [RFC PATCH 01/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Bus
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 02/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device Kishon Vijay Abraham I
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add device tree bindings for PCI endpoint function bus to which
endpoint function devices should be attached.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../bindings/pci/endpoint/pci-epf-bus.txt     | 27 +++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf-bus.txt

diff --git a/Documentation/devicetree/bindings/pci/endpoint/pci-epf-bus.txt b/Documentation/devicetree/bindings/pci/endpoint/pci-epf-bus.txt
new file mode 100644
index 000000000000..16727ddf01f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/endpoint/pci-epf-bus.txt
@@ -0,0 +1,27 @@
+PCI Endpoint Function Bus
+
+This describes the bindings for endpoint function bus to which endpoint
+function devices should be attached.
+
+Required Properties:
+ - compatible: Should be "pci-epf-bus"
+
+One or more subnodes representing PCIe endpoint function device exposed
+to the remote host.
+
+Example:
+Following is an example of NTB device exposed to the remote host.
+
+epf_bus {
+	compatible = "pci-epf-bus";
+
+	ntb {
+		compatible = "pci-epf-ntb";
+		epcs = <&pcie0_ep>, <&pcie1_ep>;
+		epc-names = "primary", "secondary";
+		vendor-id = /bits/ 16 <0x104c>;
+		device-id = /bits/ 16 <0xb00d>;
+		num-mws = <4>;
+		mws-size = <0x100000>, <0x100000>, <0x100000>, <0x100000>;
+	};
+};
-- 
2.17.1


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

* [RFC PATCH 02/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 01/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Bus Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-10-15 18:42   ` Rob Herring
  2019-09-26 11:29 ` [RFC PATCH 03/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF NTB Device Kishon Vijay Abraham I
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add device tree bindings for PCI endpoint function device. The
nodes for PCI endpoint function device should be attached to
PCI endpoint function bus.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../bindings/pci/endpoint/pci-epf.txt         | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt

diff --git a/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt b/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
new file mode 100644
index 000000000000..f006395fd526
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
@@ -0,0 +1,28 @@
+PCI Endpoint Function Device
+
+This describes the generic bindings to be used when a device has to be
+exposed to the remote host over PCIe. The device could be an actual
+peripheral in the platform or a virtual device created by the software.
+
+epcs : phandle to the endpoint controller device
+epc-names : the names of the endpoint controller device corresponding
+	    to the EPCs present in the *epcs* phandle
+vendor-id: used to identify device manufacturer
+device-id: used to identify a particular device
+baseclass-code: used to classify the type of function the device performs
+subclass-code: used to identify more specifically the function of the device
+subsys-vendor-id: used to identify vendor of the add-in card or subsystem
+subsys-id: used to specify an id that is specific to a vendor
+
+Example:
+Following is an example of NTB device exposed to the remote host.
+
+ntb {
+	compatible = "pci-epf-ntb";
+	epcs = <&pcie0_ep>, <&pcie1_ep>;
+	epc-names = "primary", "secondary";
+	vendor-id = /bits/ 16 <0x104c>;
+	device-id = /bits/ 16 <0xb00d>;
+	num-mws = <4>;
+	mws-size = <0x100000>, <0x100000>, <0x100000>, <0x100000>;
+};
-- 
2.17.1


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

* [RFC PATCH 03/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF NTB Device
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 01/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Bus Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 02/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 04/21] Documentation: PCI: Add specification for the *PCI NTB* function device Kishon Vijay Abraham I
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add device tree bindings for PCI endpoint NTB function device.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../bindings/pci/endpoint/pci-epf-ntb.txt     | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf-ntb.txt

diff --git a/Documentation/devicetree/bindings/pci/endpoint/pci-epf-ntb.txt b/Documentation/devicetree/bindings/pci/endpoint/pci-epf-ntb.txt
new file mode 100644
index 000000000000..e7896932423e
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/endpoint/pci-epf-ntb.txt
@@ -0,0 +1,31 @@
+PCI Endpoint NTB Function Device
+
+This describes the bindings to be used when a NTB device has to be
+exposed to the remote host over PCIe.
+
+Required Properties:
+ - compatible: Should be "pci-epf-ntb"
+ - epcs: As defined in generic pci-epf bindings defined in pci-epf.txt
+ - epc-names: As defined in generic pci-epf bindings defined in pci-epf.txt
+ - vendor-id: As defined in generic pci-epf bindings defined in pci-epf.txt
+ - device-id: As defined in generic pci-epf bindings defined in pci-epf.txt
+ - num-mws: Specify the number of memory windows. Should not be more than 4.
+ - mws-size: List of 'num-mws' entries containing size of each memory window.
+
+Optional Properties:
+ - spad-count: Specify the number of scratchpad registers to be supported
+ - db-count: Specify the number of doorbell interrupts to be supported. Must
+	     not be greater than 32.
+
+Example:
+Following is an example of NTB device exposed to the remote host.
+
+ntb {
+	compatible = "pci-epf-ntb";
+	epcs = <&pcie0_ep>, <&pcie1_ep>;
+	epc-names = "primary", "secondary";
+	vendor-id = /bits/ 16 <0x104c>;
+	device-id = /bits/ 16 <0xb00d>;
+	num-mws = <4>;
+	mws-size = <0x100000>, <0x100000>, <0x100000>, <0x100000>;
+};
-- 
2.17.1


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

* [RFC PATCH 04/21] Documentation: PCI: Add specification for the *PCI NTB* function device
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (2 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 03/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF NTB Device Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-11-17 23:26   ` Jon Mason
  2019-09-26 11:29 ` [RFC PATCH 05/21] PCI: endpoint: Add API to get reference to EPC from device-tree Kishon Vijay Abraham I
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add specification for the *PCI NTB* function device. The endpoint function
driver and the host PCI driver should be created based on this
specification.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/PCI/endpoint/pci-test-ntb.txt | 315 ++++++++++++++++++++
 1 file changed, 315 insertions(+)
 create mode 100644 Documentation/PCI/endpoint/pci-test-ntb.txt

diff --git a/Documentation/PCI/endpoint/pci-test-ntb.txt b/Documentation/PCI/endpoint/pci-test-ntb.txt
new file mode 100644
index 000000000000..c8bfe9dbfd8b
--- /dev/null
+++ b/Documentation/PCI/endpoint/pci-test-ntb.txt
@@ -0,0 +1,315 @@
+			       PCI NTB FUNCTION
+		    Kishon Vijay Abraham I <kishon@ti.com>
+
+PCI NTB Function allows two different systems (or hosts) to communicate
+with each other by configurig the endpoint instances in such a way that
+transactions from one system is routed to the other system.
+
+In the below diagram, PCI NTB function configures the SoC with multiple
+PCIe Endpoint (EP) instances in such a way that transaction from one EP
+controller is routed to the other EP controller. Once PCI NTB function
+configures the SoC with multiple EP instances, HOST1 and HOST2 can
+communicate with each other using SoC as a bridge.
+
+   +-------------+                                   +-------------+
+   |             |                                   |             |
+   |    HOST1    |                                   |    HOST2    |
+   |             |                                   |             |
+   +------^------+                                   +------^------+
+          |                                                 |
+          |                                                 |
++---------|-------------------------------------------------|---------+
+|  +------v------+                                   +------v------+  |
+|  |             |                                   |             |  |
+|  |     EP      |                                   |     EP      |  |
+|  | CONTROLLER1 |                                   | CONTROLLER2 |  |
+|  |             <----------------------------------->             |  |
+|  |             |                                   |             |  |
+|  |             |                                   |             |  |
+|  |             |  SoC With Multiple EP Instances   |             |  |
+|  |             |  (Configured using NTB Function)  |             |  |
+|  +-------------+                                   +-------------+  |
++---------------------------------------------------------------------+
+
+Constructs used for Implementing NTB:
+
+	*) Config Region
+	*) Self Scratchpad Registers
+	*) Peer Scratchpad Registers
+	*) Doorbell Registers
+	*) Memory Window
+
+Modeling Constructs:
+
+  There are 5 or more distinct regions (config, self scratchpad, peer
+scratchpad, doorbell, one or more memory windows) to be modeled to achieve
+NTB functionality. Atleast one memory window is required while more than
+one is permitted. All these regions should be mapped to BAR for hosts to
+access these regions.
+
+If one 32-bit BAR is allocated for each of these regions, the scheme would
+look like
+	BAR0 -> Config Region
+	BAR1 -> Self Scratchpad
+	BAR2 -> Peer Scratchpad
+	BAR3 -> Doorbell
+	BAR4 -> Memory Window 1
+	BAR5 -> Memory Window 2
+
+However if we allocate a separate BAR for each of the region, there would not
+be enough BARs for all the regions in a platform that supports only 64-bit
+BAR.
+
+In order to be be supported by most of the platforms, the regions should be
+packed and mapped to BARs in a way that provides NTB functionality and
+also making sure the hosts doesn't access any region that it is not supposed
+to.
+
+The following scheme is used in EPF NTB Function
+
+	BAR0 -> Config Region + Self Scratchpad
+	BAR1 -> Peer Scratchpad
+	BAR2 -> Doorbell + Memory Window 1
+	BAR3 -> Memory Window 2
+	BAR4 -> Memory Window 3
+	BAR4 -> Memory Window 4
+
+With this scheme, for the basic NTB functionality 3 BARs should be sufficient.
+
+Modeling Config/Scratchpad Region:
+
++-----------------+------->+------------------+        +-----------------+
+|       BAR0      |        |  CONFIG REGION   |        |       BAR0      |
++-----------------+----+   +------------------+<-------+-----------------+
+|       BAR1      |    |   |SCRATCHPAD REGION |        |       BAR1      |
++-----------------+    +-->+------------------+<-------+-----------------+
+|       BAR2      |            Local Memory            |       BAR2      |
++-----------------+                                    +-----------------+
+|       BAR3      |                                    |       BAR3      |
++-----------------+                                    +-----------------+
+|       BAR4      |                                    |       BAR4      |
++-----------------+                                    +-----------------+
+|       BAR5      |                                    |       BAR5      |
++-----------------+                                    +-----------------+
+  EP CONTROLLER 1                                        EP CONTROLLER 2
+
+Above diagram shows Config region + Scratchpad region for HOST1 (connected to
+EP controller 1) allocated in local memory. The HOST1 can access the config
+region and scratchpad region (self scratchpad) using BAR0 of EP controller 1.
+The peer host (HOST2 connected to EP controller 2) can also access this
+scratchpad region (peer scratchpad) using BAR1 of EP controller 2. This
+diagram shows the case where Config region and Scratchpad region is allocated
+for HOST1, however the same is applicable for HOST2.
+
+Modeling Doorbell/Memory Window 1:
+
++-----------------+    +----->+----------------+-----------+-----------------+
+|       BAR0      |    |      |   Doorbell 1   +-----------> MSI|X ADDRESS 1 |
++-----------------+    |      +----------------+           +-----------------+
+|       BAR1      |    |      |   Doorbell 2   +---------+ |                 |
++-----------------+    |      +----------------+         | |                 |
+|       BAR2      |    |      |   Doorbell 3   +-------+ | +-----------------+
++-----------------+    |      +----------------+       | +-> MSI|X ADDRESS 2 |
+|       BAR3      |    |      |   Doorbell 4   +-----+ |   +-----------------+
++----------------------+      +----------------+     | |   |                 |
+|       BAR4      |           |                |     | |   +-----------------+
++----------------------+      |      MW1       +---+ | +-->+ MSI|X ADDRESS 3||
+|       BAR5      |    |      |                |   | |     +-----------------+
++-----------------+    +----->-----------------+   | |     |                 |
+  EP CONTROLLER 1             |                |   | |     +-----------------+
+                              |                |   | +---->+ MSI|X ADDRESS 4 |
+                              +----------------+   |       +-----------------+
+                               EP CONTROLLER 2     |       |                 |
+                                 (OB SPACE)        |       |                 |
+                                                   +------->      MW1        |
+                                                           |                 |
+                                                           |                 |
+                                                           +-----------------+
+                                                           |                 |
+                                                           |                 |
+                                                           |                 |
+                                                           |                 |
+                                                           |                 |
+                                                           +-----------------+
+							    PCI Address Space
+							    (Managed by HOST2)
+
+Above diagram shows how the doorbell and memory window 1 is mapped so that
+HOST1 can raise doorbell interrupt on HOST2 and also how HOST1 can access
+buffers exposed by HOST2 using memory window1 (MW1). Here doorbell and
+memory window 1 regions are allocated in EP controller 2 outbound (OB) address
+space. Allocating and configuring BARs for doorbell and memory window1
+is done during the initialization phase of NTB endpoint function driver.
+Mapping from EP controller 2 OB space to PCI address space is done when HOST2
+sends CMD_CONFIGURE_MW/CMD_CONFIGURE_DOORBELL. The commands are explained
+below.
+
+Modeling Optional Memory Windows:
+
+This is modeled the same was as MW1 but each of the additional memory windows
+is mapped to separate BARs.
+
+Config Region:
+
+Config Region is a construct that is specific to NTB implemented using NTB
+Endpoint Function Driver. The host and endpoint side NTB function driver will
+exchange informatio with each other using this region. Config Region has
+Control/Status Registers for configuring the Endpoint Controller. Host can
+write into this region for configuring the outbound ATU and to indicate the
+link status. Endpoint can indicate the status of commands issued be host in
+this region. Endpoint can also indicate the scratchpad offset, number of
+memory windows to the host using this region.
+
+The format of Config Region is given below. Each of the fields here are 32
+bits.
+
+	+------------------------+
+	|         COMMAND        |
+	+------------------------+
+	|         ARGUMENT       |
+	+------------------------+
+	|         STATUS         |
+	+------------------------+
+	|         TOPOLOGY       |
+	+------------------------+
+	|    ADDRESS (LOWER 32)  |
+	+------------------------+
+	|    ADDRESS (UPPER 32)  |
+	+------------------------+
+	|           SIZE         |
+	+------------------------+
+	|  MEMORY WINDOW1 OFFSET |
+	+------------------------+
+	|   NO OF MEMORY WINDOW  |
+	+------------------------+
+	|       SPAD OFFSET      |
+	+------------------------+
+	|        SPAD COUNT      |
+	+------------------------+
+	|      DB ENTRY SIZE     |
+	+------------------------+
+	|         DB DATA        |
+	+------------------------+
+	|            :           |
+	+------------------------+
+	|            :           |
+	+------------------------+
+	|         DB DATA        |
+	+------------------------+
+
+
+  COMMAND:
+
+	NTB function supports three commands:
+
+	  CMD_CONFIGURE_DOORBELL (0x1): Command to configure doorbell. Before
+	invoking this command, the host should allocate and initialize
+	MSI/MSI-X vectors (i.e initialize the MSI/MSI-X capability in the
+	Endpoint). The endpoint on receiving this command will configure
+	the outbound ATU such that transaction to DB BAR will be routed
+	to the MSI/MSI-X address programmed by the host. The ARGUMENT
+	register should be populated with number of DBs to configure (in the
+	lower 16 bits) and if MSI or MSI-X should be configured (BIT 16).
+	(TODO: Add support for MSI-X).
+
+	  CMD_CONFIGURE_MW (0x2): Command to configure memory window. The
+	host invokes this command after allocating a buffer that can be
+	accessed by remote host. The allocated address should be programmed
+	in the ADDRESS register (64 bit), the size should be programmed in
+	the SIZE register and the memory window index should be programmed
+	in the ARGUMENT register. The endpoint on receiving this command
+	will configure the outbound ATU such that trasaction to MW BAR
+	will be routed to the address provided by the host.
+
+	  CMD_LINK_UP (0x3): Command to indicate an NTB application is
+	bound to the EP device on the host side. Once the endpoint
+	receives this command from both the hosts, the endpoint will
+	raise an LINK_UP event to both the hosts to indicate the hosts
+	can start communicating with each other.
+
+  ARGUMENT:
+
+	The value of this register is based on the commands issued in
+	command register. See COMMAND section for more information.
+
+  configuring memory window and to indicate the host side NTB application
+  has initialized.
+
+  TOPOLOGY:
+
+	Set to NTB_TOPO_B2B_USD for Primary interface
+	Set to NTB_TOPO_B2B_DSD for Secondary interface
+
+  ADDRESS/SIZE:
+
+	Address and Size to be used while configuring the memory window.
+	See "CMD_CONFIGURE_MW" for more info.
+
+  MEMORY WINDOW1 OFFSET:
+
+	Memory Window 1 and Doorbell registers are packed together in the
+	same BAR. The initial portion of the region will have doorbell
+	registers and the latter portion of the region is for memory window 1.
+	This register will specify the offset of the memory window 1.
+
+  NO OF MEMORY WINDOW:
+
+	Specifies the number of memory windows supported by the NTB device.
+
+  SPAD OFFSET:
+
+	Self scratchpad region and config region are packed together in the
+	same BAR. The initial portion of the will have config region and
+	the latter portion of the region is for self scratchpad. This
+	register will specify the offset of the self scratchpad registers.
+
+  SPAD COUNT:
+
+	Specifies the number of scratchpad registers supported by the NTB
+	device.
+
+  DB ENTRY SIZE:
+
+	Used to determine the offset within the DB BAR that should be written
+	in order to raise doorbell. EPF NTB can use either MSI/MSI-X to
+	ring doorbell (MSI-X support will be added later). MSI uses same
+	address for all the interrupts and MSI-X can provide different
+	addresses for different interrupts. The MSI/MSI-X address is provided
+	by the host and the address it gives is based on the MSI/MSI-X
+	implementation supported by the host. For instance, ARM platform
+	using GIC ITS will have same MSI-X address for all the interrupts.
+	In order to support all the combinations and use the same mechanism
+	for both MSI and MSI-X, EPF NTB allocates separate region in the
+	Outbound Address Space for each of the interrupts. This region will
+	be mapped to the MSI/MSI-X address provided by the host. If a host
+	provides the same address for all the interrupts, all the regions
+	will be translated to the same address. If a host provides different
+	address, the regions will be translated to different address. This
+	will ensure there is no difference while raising the doorbell.
+
+  DB DATA:
+
+	EPF NTB supports 32 interrupts. So there are 32 DB DATA registers.
+	This holds the MSI/MSI-X data that has to be written to MSI address
+	for raising doorbell interrupt. This will be populated by EPF NTB
+	while invoking CMD_CONFIGURE_MW.
+
+Scratchpad Registers:
+
+  Each host has it's own register space allocated in the memory of NTB EPC.
+  They are both readable and writable from both sides of the bridge. They
+  are used by applications built over NTB and can be used to pass control
+  and status information between both sides of a device.
+
+  Scratchpad registers has 2 parts
+	1) Self Scratchpad: Host's own register space
+	2) Peer Scratchpad: Remote host's register space.
+
+Doorbell Registers:
+
+  Registers using which one host can interrupt the other host.
+
+Memory Window:
+
+  Actual transfer of data between the two hosts will happen using the
+  memory window.
-- 
2.17.1


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

* [RFC PATCH 05/21] PCI: endpoint: Add API to get reference to EPC from device-tree
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (3 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 04/21] Documentation: PCI: Add specification for the *PCI NTB* function device Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-11-17 23:28   ` Jon Mason
  2019-09-26 11:29 ` [RFC PATCH 06/21] PCI: endpoint: Add API to create EPF device from device tree Kishon Vijay Abraham I
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add of_pci_epc_get() and of_pci_epc_get_by_name() to get reference
to EPC from device-tree. This is added in preparation to define
an endpoint function from device tree.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epc-core.c | 61 +++++++++++++++++++++++++++++
 include/linux/pci-epc.h             |  4 +-
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 5bc094093a47..0c2fdd39090c 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -83,6 +83,66 @@ struct pci_epc *pci_epc_get(const char *epc_name)
 }
 EXPORT_SYMBOL_GPL(pci_epc_get);
 
+/**
+ * of_pci_epc_get() - get PCI endpoint controller from device node and index
+ * @node: device node which contains the phandle to endpoint controller
+ * @index: index of the endpoint controller in "epcs" property
+ *
+ * Returns the EPC corresponding to the _index_ entry in "epcs" property
+ * present in device node, after getting a refcount  to it or -ENODEV if
+ * there is no such EPC or -EPROBE_DEFER if there is a phandle to the phy,
+ * but the device is not yet loaded.
+ */
+struct pci_epc *of_pci_epc_get(struct device_node *node, int index)
+{
+	struct device_node *epc_node;
+	struct class_dev_iter iter;
+	struct pci_epc *epc;
+	struct device *dev;
+
+	epc_node = of_parse_phandle(node, "epcs", index);
+	if (!epc_node)
+		return ERR_PTR(-ENODEV);
+
+	class_dev_iter_init(&iter, pci_epc_class, NULL, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
+		epc = to_pci_epc(dev);
+		if (epc_node != epc->dev.of_node)
+			continue;
+
+		of_node_put(epc_node);
+		class_dev_iter_exit(&iter);
+		get_device(&epc->dev);
+		return epc;
+	}
+
+	of_node_put(node);
+	class_dev_iter_exit(&iter);
+	return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL_GPL(of_pci_epc_get);
+
+/**
+ * of_pci_epc_get_by_name() - get PCI endpoint controller from device node
+ *                            and string
+ * @node: device node which contains the phandle to endpoint controller
+ * @epc_name: name of endpoint controller as present in "epc-names" property
+ *
+ * Returns the EPC corresponding to the epc_name in "epc-names" property
+ * present in device node.
+ */
+struct pci_epc *of_pci_epc_get_by_name(struct device_node *node,
+				       const char *epc_name)
+{
+	int index = 0;
+
+	if (epc_name)
+		index = of_property_match_string(node, "epc-names", epc_name);
+
+	return of_pci_epc_get(node, index);
+}
+EXPORT_SYMBOL_GPL(of_pci_epc_get_by_name);
+
 /**
  * pci_epc_get_first_free_bar() - helper to get first unreserved BAR
  * @epc_features: pci_epc_features structure that holds the reserved bar bitmap
@@ -661,6 +721,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
 	device_initialize(&epc->dev);
 	epc->dev.class = pci_epc_class;
 	epc->dev.parent = dev;
+	epc->dev.of_node = dev->of_node;
 	epc->ops = ops;
 
 	ret = dev_set_name(&epc->dev, "%s", dev_name(dev));
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 0fff52675a6b..ef6531af6ed2 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -202,7 +202,9 @@ unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
 					*epc_features);
 struct pci_epc *pci_epc_get(const char *epc_name);
 void pci_epc_put(struct pci_epc *epc);
-
+struct pci_epc *of_pci_epc_get(struct device_node *node, int index);
+struct pci_epc *of_pci_epc_get_by_name(struct device_node *node,
+				       const char *epc_name);
 int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size,
 		       size_t page_size);
 void pci_epc_mem_exit(struct pci_epc *epc);
-- 
2.17.1


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

* [RFC PATCH 06/21] PCI: endpoint: Add API to create EPF device from device tree
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (4 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 05/21] PCI: endpoint: Add API to get reference to EPC from device-tree Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 07/21] PCI: endpoint: Add "pci-epf-bus" driver Kishon Vijay Abraham I
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add API to create EPF device from device tree and the device managed
interface corresponding to it. This is added in order to define
an endpoint function completely from device tree.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epf-core.c | 68 +++++++++++++++++++++++++++++
 include/linux/pci-epf.h             |  6 +++
 2 files changed, 74 insertions(+)

diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 16feff8cad50..c74c7cc6d8bd 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -529,6 +529,73 @@ struct pci_epf *pci_epf_create(const char *name)
 }
 EXPORT_SYMBOL_GPL(pci_epf_create);
 
+/**
+ * pci_epf_of_create() - create a new PCI EPF device from device tree node
+ * @node: the device node of the PCI EPF device.
+ *
+ * Invoke to create a new PCI EPF device by providing a device tree node
+ * with compatible property.
+ */
+struct pci_epf *pci_epf_of_create(struct device_node *node)
+{
+	struct pci_epf *epf;
+	const char *compat;
+	int ret;
+
+	of_node_get(node);
+
+	ret = of_property_read_string(node, "compatible", &compat);
+	if (ret) {
+		of_node_put(node);
+		return ERR_PTR(ret);
+	}
+
+	epf = pci_epf_create(compat);
+	if (!IS_ERR(epf))
+		epf->node = node;
+
+	return epf;
+}
+EXPORT_SYMBOL_GPL(pci_epf_of_create);
+
+static void devm_epf_release(struct device *dev, void *res)
+{
+	struct pci_epf *epf = *(struct pci_epf **)res;
+
+	pci_epf_destroy(epf);
+}
+
+/**
+ * devm_pci_epf_of_create() - create a new PCI EPF device from device tree node
+ * @dev: device that is creating the new EPF
+ * @node: the device node of the PCI EPF device.
+ *
+ * Invoke to create a new PCI EPF device by providing a device tree node with
+ * compatible property. While at that, it also associates the device with the
+ * EPF using devres. On driver detach, release function is invoked on the devres
+ * data, where devres data is freed.
+ */
+struct pci_epf *devm_pci_epf_of_create(struct device *dev,
+				       struct device_node *node)
+{
+	struct pci_epf **ptr, *epf;
+
+	ptr = devres_alloc(devm_epf_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	epf = pci_epf_of_create(node);
+	if (!IS_ERR(epf)) {
+		*ptr = epf;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return epf;
+}
+EXPORT_SYMBOL_GPL(devm_pci_epf_of_create);
+
 const struct pci_epf_device_id *
 pci_epf_match_device(const struct pci_epf_device_id *id, struct pci_epf *epf)
 {
@@ -549,6 +616,7 @@ static void pci_epf_dev_release(struct device *dev)
 {
 	struct pci_epf *epf = to_pci_epf(dev);
 
+	of_node_put(epf->node);
 	kfree(epf->name);
 	kfree(epf);
 }
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 02090eb41563..7e997fb656fb 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -11,6 +11,7 @@
 
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
+#include <linux/of.h>
 #include <linux/pci.h>
 
 struct pci_epf;
@@ -101,6 +102,7 @@ struct pci_epf_bar {
 /**
  * struct pci_epf - represents the PCI EPF device
  * @dev: the PCI EPF device
+ * @node: the device tree node of the PCI EPF device
  * @name: the name of the PCI EPF device
  * @header: represents standard configuration header
  * @bar: represents the BAR of EPF device
@@ -125,6 +127,7 @@ struct pci_epf_bar {
  */
 struct pci_epf {
 	struct device		dev;
+	struct device_node	*node;
 	const char		*name;
 	struct pci_epf_header	*header;
 	struct pci_epf_bar	bar[6];
@@ -167,6 +170,9 @@ static inline void *epf_get_drvdata(struct pci_epf *epf)
 const struct pci_epf_device_id *
 pci_epf_match_device(const struct pci_epf_device_id *id, struct pci_epf *epf);
 struct pci_epf *pci_epf_create(const char *name);
+struct pci_epf *pci_epf_of_create(struct device_node *node);
+struct pci_epf *devm_pci_epf_of_create(struct device *dev,
+				       struct device_node *node);
 void pci_epf_destroy(struct pci_epf *epf);
 int __pci_epf_register_driver(struct pci_epf_driver *driver,
 			      struct module *owner);
-- 
2.17.1


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

* [RFC PATCH 07/21] PCI: endpoint: Add "pci-epf-bus" driver
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (5 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 06/21] PCI: endpoint: Add API to create EPF device from device tree Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 08/21] PCI: endpoint: Make *_get_first_free_bar() take into account 64 bit BAR Kishon Vijay Abraham I
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add "pci-epf-bus" driver that helps to create EPF device from
device tree. This is added in order to define an endpoint function
completely from device tree.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/Makefile      |  3 +-
 drivers/pci/endpoint/pci-epf-bus.c | 54 ++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 1 deletion(-)
 create mode 100644 drivers/pci/endpoint/pci-epf-bus.c

diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index 95b2fe47e3b0..36cf33cf975c 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -5,4 +5,5 @@
 
 obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS)	+= pci-ep-cfs.o
 obj-$(CONFIG_PCI_ENDPOINT)		+= pci-epc-core.o pci-epf-core.o\
-					   pci-epc-mem.o functions/
+					   pci-epc-mem.o pci-epf-bus.o \
+					   functions/
diff --git a/drivers/pci/endpoint/pci-epf-bus.c b/drivers/pci/endpoint/pci-epf-bus.c
new file mode 100644
index 000000000000..c47eeae7fe7a
--- /dev/null
+++ b/drivers/pci/endpoint/pci-epf-bus.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * PCI Endpoint *Function* Bus Driver
+ *
+ * Copyright (C) 2019 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pci-epf.h>
+#include <linux/platform_device.h>
+
+static int pci_epf_bus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = of_node_get(dev->of_node);
+	struct device_node *child;
+	struct pci_epf *epf;
+
+	for_each_child_of_node(node, child) {
+		epf = devm_pci_epf_of_create(dev, child);
+		if (IS_ERR(epf)) {
+			dev_err(dev, "Failed to create PCI EPF device %s\n",
+				node->full_name);
+			of_node_put(child);
+			break;
+		}
+	}
+	of_node_put(node);
+
+	return 0;
+}
+
+static const struct of_device_id pci_epf_bus_id_table[] = {
+	{ .compatible = "pci-epf-bus" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, pci_epf_bus_id_table);
+
+static struct platform_driver pci_epf_bus_driver = {
+	.probe		= pci_epf_bus_probe,
+	.driver		= {
+		.name	= "pci-epf-bus",
+		.of_match_table = of_match_ptr(pci_epf_bus_id_table),
+	},
+};
+
+module_platform_driver(pci_epf_bus_driver);
+
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("PCI EPF Bus Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1


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

* [RFC PATCH 08/21] PCI: endpoint: Make *_get_first_free_bar() take into account 64 bit BAR
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (6 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 07/21] PCI: endpoint: Add "pci-epf-bus" driver Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 09/21] PCI: endpoint: Add helper API to get the 'next' unreserved BAR Kishon Vijay Abraham I
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

pci_epc_get_first_free_bar() uses only "reserved_bar" member in
epc_features to get the first unreserved BAR. However if the
reserved BAR is also a 64-bit BAR, then the next BAR shouldn't be
returned (since 64-bit BAR uses two BARs).

Make pci_epc_get_first_free_bar() take into account 64 bit BAR while
returning the first free unreserved BAR.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epc-core.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 0c2fdd39090c..7eae7dcaebf9 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -153,12 +153,20 @@ EXPORT_SYMBOL_GPL(of_pci_epc_get_by_name);
 unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
 					*epc_features)
 {
-	int free_bar;
+	unsigned long free_bar;
 
 	if (!epc_features)
 		return 0;
 
-	free_bar = ffz(epc_features->reserved_bar);
+	/* Find if the reserved BAR is also a 64-bit BAR */
+	free_bar = epc_features->reserved_bar & epc_features->bar_fixed_64bit;
+
+	/* Set the adjacent bit if the reserved BAR is also a 64-bit BAR */
+	free_bar <<= 1;
+	free_bar |= epc_features->reserved_bar;
+
+	/* Now find the free BAR */
+	free_bar = ffz(free_bar);
 	if (free_bar > 5)
 		return 0;
 
-- 
2.17.1


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

* [RFC PATCH 09/21] PCI: endpoint: Add helper API to get the 'next' unreserved BAR
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (7 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 08/21] PCI: endpoint: Make *_get_first_free_bar() take into account 64 bit BAR Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 10/21] PCI: endpoint: Make pci_epf_driver ops optional Kishon Vijay Abraham I
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add an API to get the next unreserved BAR starting from a given BAR
number that can be used by the endpoint function.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epc-core.c | 26 ++++++++++++++++++++++----
 include/linux/pci-epc.h             |  2 ++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 7eae7dcaebf9..49bdff217777 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -147,17 +147,36 @@ EXPORT_SYMBOL_GPL(of_pci_epc_get_by_name);
  * pci_epc_get_first_free_bar() - helper to get first unreserved BAR
  * @epc_features: pci_epc_features structure that holds the reserved bar bitmap
  *
- * Invoke to get the first unreserved BAR that can be used for endpoint
+ * Invoke to get the first unreserved BAR that can be used by the endpoint
  * function. For any incorrect value in reserved_bar return '0'.
  */
 unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
 					*epc_features)
+{
+	return pci_epc_get_next_free_bar(epc_features, BAR_0);
+}
+EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar);
+
+/**
+ * pci_epc_get_next_free_bar() - helper to get unreserved BAR starting from @bar
+ * @epc_features: pci_epc_features structure that holds the reserved bar bitmap
+ * @bar: the starting BAR number from where unreserved BAR should be searched
+ *
+ * Invoke to get the next unreserved BAR starting from @bar that can be used
+ * for endpoint function. For any incorrect value in reserved_bar return '0'.
+ */
+unsigned int pci_epc_get_next_free_bar(const struct pci_epc_features
+				       *epc_features, enum pci_barno bar)
 {
 	unsigned long free_bar;
 
 	if (!epc_features)
 		return 0;
 
+	/* If 'bar - 1' is a 64-bit BAR, move to the next BAR */
+	if ((epc_features->bar_fixed_64bit << 1) & 1 << bar)
+		bar++;
+
 	/* Find if the reserved BAR is also a 64-bit BAR */
 	free_bar = epc_features->reserved_bar & epc_features->bar_fixed_64bit;
 
@@ -165,14 +184,13 @@ unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
 	free_bar <<= 1;
 	free_bar |= epc_features->reserved_bar;
 
-	/* Now find the free BAR */
-	free_bar = ffz(free_bar);
+	free_bar = find_next_zero_bit(&free_bar, 6, bar);
 	if (free_bar > 5)
 		return 0;
 
 	return free_bar;
 }
-EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar);
+EXPORT_SYMBOL_GPL(pci_epc_get_next_free_bar);
 
 /**
  * pci_epc_get_features() - get the features supported by EPC
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index ef6531af6ed2..993b1a55a239 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -200,6 +200,8 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
 						    u8 func_no, u8 vfunc_no);
 unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
 					*epc_features);
+unsigned int pci_epc_get_next_free_bar(const struct pci_epc_features
+				       *epc_features, enum pci_barno bar);
 struct pci_epc *pci_epc_get(const char *epc_name);
 void pci_epc_put(struct pci_epc *epc);
 struct pci_epc *of_pci_epc_get(struct device_node *node, int index);
-- 
2.17.1


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

* [RFC PATCH 10/21] PCI: endpoint: Make pci_epf_driver ops optional
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (8 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 09/21] PCI: endpoint: Add helper API to get the 'next' unreserved BAR Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 11/21] PCI: endpoint: Add helper API to populate header with values from DT Kishon Vijay Abraham I
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

pci_epf_driver had two ops for bind and unbind which will be invoked
when an endpoint controller is bound to an endpoint function (using
configfs). Now that endpoint core has support to define an endpoint
function using device tree alone, the bind and unbind ops can be
optional. Make pci_epf_driver ops optional here.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epf-core.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index c74c7cc6d8bd..67015c66d09f 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -446,11 +446,9 @@ int __pci_epf_register_driver(struct pci_epf_driver *driver,
 {
 	int ret;
 
-	if (!driver->ops)
-		return -EINVAL;
-
-	if (!driver->ops->bind || !driver->ops->unbind)
-		return -EINVAL;
+	if (!driver->ops || !driver->ops->bind || !driver->ops->unbind)
+		pr_debug("%s: Supports only pci_epf device created using DT\n",
+			 driver->driver.name);
 
 	driver->driver.bus = &pci_epf_bus_type;
 	driver->driver.owner = owner;
-- 
2.17.1


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

* [RFC PATCH 11/21] PCI: endpoint: Add helper API to populate header with values from DT
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (9 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 10/21] PCI: endpoint: Make pci_epf_driver ops optional Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 12/21] PCI: endpoint: Add support to associate secondary EPC with EPF Kishon Vijay Abraham I
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add helper API pci_epc_of_parse_header() to populate header with
values from device tree. These values will be written to the
configuration space header in the endpoint controller.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epc-core.c | 23 +++++++++++++++++++++++
 include/linux/pci-epc.h             |  2 ++
 2 files changed, 25 insertions(+)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 49bdff217777..98acadbfc934 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -31,6 +31,29 @@ static int devm_pci_epc_match(struct device *dev, void *res, void *match_data)
 	return *epc == match_data;
 }
 
+/**
+ * pci_epc_of_parse_header() - parse the device tree to get PCI config space
+ *                             header
+ * @node: The device tree node (of endpoint function) which has the PCI config
+ *        space header values
+ * @header: standard configuration space header fields that has to be populated
+ *
+ * Invoke to populate *header* with the PCI configuration space values populated
+ * in device tree.
+ */
+void pci_epc_of_parse_header(struct device_node *node,
+			     struct pci_epf_header *header)
+{
+	of_property_read_u16(node, "vendor-id", &header->vendorid);
+	of_property_read_u16(node, "device-id", &header->deviceid);
+	of_property_read_u8(node, "baseclass-code", &header->baseclass_code);
+	of_property_read_u8(node, "subclass-code", &header->subclass_code);
+	of_property_read_u16(node, "subsys-vendor-id",
+			     &header->subsys_vendor_id);
+	of_property_read_u16(node, "subsys-id", &header->subsys_id);
+}
+EXPORT_SYMBOL_GPL(pci_epc_of_parse_header);
+
 /**
  * pci_epc_put() - release the PCI endpoint controller
  * @epc: epc returned by pci_epc_get()
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 993b1a55a239..18fff589a881 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -196,6 +196,8 @@ int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 		      enum pci_epc_irq_type type, u16 interrupt_num);
 int pci_epc_start(struct pci_epc *epc);
 void pci_epc_stop(struct pci_epc *epc);
+void pci_epc_of_parse_header(struct device_node *node,
+			     struct pci_epf_header *header);
 const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
 						    u8 func_no, u8 vfunc_no);
 unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
-- 
2.17.1


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

* [RFC PATCH 12/21] PCI: endpoint: Add support to associate secondary EPC with EPF
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (10 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 11/21] PCI: endpoint: Add helper API to populate header with values from DT Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 13/21] PCI: endpoint: Add pci_epc_ops to map MSI irq Kishon Vijay Abraham I
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

In the case of standard endpoint functions, only one endpoint
controller (EPC) will be associated with an endpoint function
(EPF). However for providing NTB (non transparent bridge)
functionality, two EPCs should be associated with a single EPF.
Add support to associate secondary EPC with EPF. This is in
preparation for adding NTB endpoint function driver.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/functions/pci-epf-test.c | 12 +++--
 drivers/pci/endpoint/pci-ep-cfs.c             |  6 +--
 drivers/pci/endpoint/pci-epc-core.c           | 47 ++++++++++++----
 drivers/pci/endpoint/pci-epf-core.c           | 53 ++++++++++++++-----
 include/linux/pci-epc.h                       | 24 ++++++++-
 include/linux/pci-epf.h                       | 27 +++++++++-
 6 files changed, 135 insertions(+), 34 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 608545aaf7c8..c7003c2dbbb2 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -484,7 +484,8 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
 		epf_bar = &epf->bar[bar];
 
 		if (epf_test->reg[bar]) {
-			pci_epf_free_space(epf, epf_test->reg[bar], bar);
+			pci_epf_free_space(epf, epf_test->reg[bar], bar,
+					   PRIMARY_INTERFACE);
 			pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no,
 					  epf_bar);
 		}
@@ -514,7 +515,8 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
 		ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no,
 				      epf_bar);
 		if (ret) {
-			pci_epf_free_space(epf, epf_test->reg[bar], bar);
+			pci_epf_free_space(epf, epf_test->reg[bar], bar,
+					   PRIMARY_INTERFACE);
 			dev_err(dev, "Failed to set BAR%d\n", bar);
 			if (bar == test_reg_bar)
 				return ret;
@@ -544,7 +546,8 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
 	epc_features = epf_test->epc_features;
 
 	base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
-				   test_reg_bar, epc_features->align);
+				   test_reg_bar, epc_features->align,
+				   PRIMARY_INTERFACE);
 	if (!base) {
 		dev_err(dev, "Failed to allocated register space\n");
 		return -ENOMEM;
@@ -560,7 +563,8 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
 			continue;
 
 		base = pci_epf_alloc_space(epf, bar_size[bar], bar,
-					   epc_features->align);
+					   epc_features->align,
+					   PRIMARY_INTERFACE);
 		if (!base)
 			dev_err(dev, "Failed to allocate space for BAR%d\n",
 				bar);
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
index c18ef626ada5..f274a5b6ee10 100644
--- a/drivers/pci/endpoint/pci-ep-cfs.c
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -93,13 +93,13 @@ static int pci_epc_epf_link(struct config_item *epc_item,
 	struct pci_epc *epc = epc_group->epc;
 	struct pci_epf *epf = epf_group->epf;
 
-	ret = pci_epc_add_epf(epc, epf);
+	ret = pci_epc_add_epf(epc, epf, PRIMARY_INTERFACE);
 	if (ret)
 		return ret;
 
 	ret = pci_epf_bind(epf);
 	if (ret) {
-		pci_epc_remove_epf(epc, epf);
+		pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
 		return ret;
 	}
 
@@ -119,7 +119,7 @@ static void pci_epc_epf_unlink(struct config_item *epc_item,
 	epc = epc_group->epc;
 	epf = epf_group->epf;
 	pci_epf_unbind(epf);
-	pci_epc_remove_epf(epc, epf);
+	pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
 }
 
 static struct configfs_item_operations pci_epc_item_ops = {
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 98acadbfc934..42085fcc746d 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -634,17 +634,21 @@ EXPORT_SYMBOL_GPL(pci_epc_write_header);
  * pci_epc_add_epf() - bind PCI endpoint function to an endpoint controller
  * @epc: the EPC device to which the endpoint function should be added
  * @epf: the endpoint function to be added
+ * @type: Identifies if the EPC is connected to the primary or secondary
+ *        interface of EPF
  *
  * A PCI endpoint device can have one or more functions. In the case of PCIe,
  * the specification allows up to 8 PCIe endpoint functions. Invoke
  * pci_epc_add_epf() to add a PCI endpoint function to an endpoint controller.
  */
-int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
+int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
+		    enum pci_epc_interface_type type)
 {
+	struct list_head *list;
 	u32 func_no = 0;
 
-	if (epf->epc || epf->is_vf)
-		return -EBUSY;
+	if (epf->is_vf)
+		return -EINVAL;
 
 	if (IS_ERR(epc))
 		return -EINVAL;
@@ -652,6 +656,12 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
 	if (epf->func_no > epc->max_functions - 1)
 		return -EINVAL;
 
+	if (type == PRIMARY_INTERFACE && epf->epc)
+		return -EBUSY;
+
+	if (type == SECONDARY_INTERFACE && epf->sec_epc)
+		return -EBUSY;
+
 	mutex_lock(&epc->lock);
 	func_no = find_first_zero_bit(&epc->function_num_map,
 				      BITS_PER_LONG);
@@ -659,10 +669,17 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
 		return -EINVAL;
 
 	set_bit(func_no, &epc->function_num_map);
-	epf->func_no = func_no;
-	epf->epc = epc;
+	if (type == PRIMARY_INTERFACE) {
+		epf->func_no = func_no;
+		epf->epc = epc;
+		list = &epf->list;
+	} else {
+		epf->sec_epc_func_no = func_no;
+		epf->sec_epc = epc;
+		list = &epf->sec_epc_list;
+	}
 
-	list_add_tail(&epf->list, &epc->pci_epf);
+	list_add_tail(list, &epc->pci_epf);
 	mutex_unlock(&epc->lock);
 
 	return 0;
@@ -676,14 +693,26 @@ EXPORT_SYMBOL_GPL(pci_epc_add_epf);
  *
  * Invoke to remove PCI endpoint function from the endpoint controller.
  */
-void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf)
+void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
+			enum pci_epc_interface_type type)
 {
+	struct list_head *list;
+	u32 func_no = 0;
+
 	if (!epc || IS_ERR(epc))
 		return;
 
+	if (type == PRIMARY_INTERFACE) {
+		func_no = epf->func_no;
+		list = &epf->list;
+	} else {
+		func_no = epf->sec_epc_func_no;
+		list = &epf->sec_epc_list;
+	}
+
 	mutex_lock(&epc->lock);
-	clear_bit(epf->func_no, &epc->function_num_map);
-	list_del(&epf->list);
+	clear_bit(func_no, &epc->function_num_map);
+	list_del(list);
 	mutex_unlock(&epc->lock);
 }
 EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 67015c66d09f..388966faf17a 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -320,23 +320,36 @@ EXPORT_SYMBOL_GPL(pci_epf_remove_vepf);
  * 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
+ * @type: Identifies if the allocated space is for primary EPC or secondary EPC
  *
  * Invoke to free the allocated PCI EPF register space.
  */
-void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar)
+void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
+			enum pci_epc_interface_type type)
 {
 	struct device *dev = epf->epc->dev.parent;
+	struct pci_epf_bar *epf_bar;
+	struct pci_epc *epc;
 
 	if (!addr)
 		return;
 
-	dma_free_coherent(dev, epf->bar[bar].size, addr,
-			  epf->bar[bar].phys_addr);
+	if (type == PRIMARY_INTERFACE) {
+		epc = epf->epc;
+		epf_bar = epf->bar;
+	} else {
+		epc = epf->sec_epc;
+		epf_bar = epf->sec_epc_bar;
+	}
+
+	dev = epc->dev.parent;
+	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;
-	epf->bar[bar].barno = 0;
-	epf->bar[bar].flags = 0;
+	epf_bar[bar].phys_addr = 0;
+	epf_bar[bar].size = 0;
+	epf_bar[bar].barno = 0;
+	epf_bar[bar].flags = 0;
 }
 EXPORT_SYMBOL_GPL(pci_epf_free_space);
 
@@ -345,15 +358,18 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space);
  * @size: the size of the memory that has to be allocated
  * @bar: the BAR number corresponding to the allocated register space
  * @align: alignment size for the allocation region
+ * @type: Identifies if the allocation is for primary EPC or secondary EPC
  *
  * 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,
-			  size_t align)
+			  size_t align, enum pci_epc_interface_type type)
 {
-	void *space;
-	struct device *dev = epf->epc->dev.parent;
+	struct pci_epf_bar *epf_bar;
 	dma_addr_t phys_addr;
+	struct pci_epc *epc;
+	struct device *dev;
+	void *space;
 
 	if (size < 128)
 		size = 128;
@@ -363,16 +379,25 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
 	else
 		size = roundup_pow_of_two(size);
 
+	if (type == PRIMARY_INTERFACE) {
+		epc = epf->epc;
+		epf_bar = epf->bar;
+	} else {
+		epc = epf->sec_epc;
+		epf_bar = epf->sec_epc_bar;
+	}
+
+	dev = epc->dev.parent;
 	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;
-	epf->bar[bar].barno = bar;
-	epf->bar[bar].flags |= upper_32_bits(size) ?
+	epf_bar[bar].phys_addr = phys_addr;
+	epf_bar[bar].size = size;
+	epf_bar[bar].barno = bar;
+	epf_bar[bar].flags |= upper_32_bits(size) ?
 				PCI_BASE_ADDRESS_MEM_TYPE_64 :
 				PCI_BASE_ADDRESS_MEM_TYPE_32;
 
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 18fff589a881..91d5cbaabc8f 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -13,6 +13,11 @@
 
 struct pci_epc;
 
+enum pci_epc_interface_type {
+	PRIMARY_INTERFACE,
+	SECONDARY_INTERFACE,
+};
+
 enum pci_epc_irq_type {
 	PCI_EPC_IRQ_UNKNOWN,
 	PCI_EPC_IRQ_LEGACY,
@@ -20,6 +25,19 @@ enum pci_epc_irq_type {
 	PCI_EPC_IRQ_MSIX,
 };
 
+static inline const char *
+pci_epc_interface_string(enum pci_epc_interface_type type)
+{
+	switch (type) {
+	case PRIMARY_INTERFACE:
+		return "primary";
+	case SECONDARY_INTERFACE:
+		return "secondary";
+	default:
+		return "UNKNOWN interface";
+	}
+}
+
 /**
  * struct pci_epc_ops - set of function pointers for performing EPC operations
  * @epf_init: ops to perform EPC specific initialization
@@ -172,9 +190,11 @@ __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_add_epf(struct pci_epc *epc, struct pci_epf *epf);
+int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
+		    enum pci_epc_interface_type type);
 void pci_epc_linkup(struct pci_epc *epc);
-void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf);
+void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
+			enum pci_epc_interface_type type);
 int pci_epc_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 			 struct pci_epf_header *hdr);
 int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 7e997fb656fb..b5075119f3ad 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -15,6 +15,7 @@
 #include <linux/pci.h>
 
 struct pci_epf;
+enum pci_epc_interface_type;
 
 enum pci_barno {
 	BAR_0,
@@ -124,6 +125,18 @@ struct pci_epf_bar {
  * @is_vf: true - virtual function, false - physical function
  * @vfunction_num_map: bitmap to manage virtual function number
  * @pci_vepf: list of virtual endpoint function associated with this function
+ * @sec_epc: the secondary EPC device to which this EPF device is bound
+ * @sec_epc_list: to add pci_epf as list of PCI endpoint functions to secondary
+ *   EPC device
+ * @sec_epc_bar: represents the BAR of EPF device associated with secondary EPC
+ * @sec_epc_func_no: unique (physical) function number within the secondary EPC
+ * @sec_epc_vfunc_no: unique virtual function number within a physical function
+ *   associated with secondary EPC
+ * @sec_epc_vfunction_num_map: bitmap to manage virtual function number
+ *   associated with the physical function of the
+ *   secondary EPC
+ * @sec_epc_pci_vepf: list of virtual endpoint function associated with the
+ *   physical function of the secondary EPC
  */
 struct pci_epf {
 	struct device		dev;
@@ -150,6 +163,15 @@ struct pci_epf {
 	unsigned int		is_vf;
 	unsigned long		vfunction_num_map;
 	struct list_head	pci_vepf;
+
+	/* Below members are to attach secondary EPC to an endpoint function */
+	struct pci_epc		*sec_epc;
+	struct list_head	sec_epc_list;
+	struct pci_epf_bar	sec_epc_bar[6];
+	u8			sec_epc_func_no;
+	u8			sec_epc_vfunc_no;
+	unsigned long		sec_epc_vfunction_num_map;
+	struct list_head	sec_epc_pci_vepf;
 };
 
 #define to_pci_epf(epf_dev) container_of((epf_dev), struct pci_epf, dev)
@@ -178,8 +200,9 @@ 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,
-			  size_t align);
-void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar);
+			  size_t align, enum pci_epc_interface_type type);
+void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
+			enum pci_epc_interface_type type);
 int pci_epf_bind(struct pci_epf *epf);
 void pci_epf_unbind(struct pci_epf *epf);
 int pci_epf_init_dma_chan(struct pci_epf *epf);
-- 
2.17.1


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

* [RFC PATCH 13/21] PCI: endpoint: Add pci_epc_ops to map MSI irq
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (11 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 12/21] PCI: endpoint: Add support to associate secondary EPC with EPF Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 14/21] PCI: cadence: Implement ->msi_map_irq() ops Kishon Vijay Abraham I
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add pci_epc_ops to map physical address to MSI address and return MSI
data. The physical address is an address in the outbound region. This is
required to implement doorbell functionality of NTB (non transparent
bridge) wherein EPC on either side of the interface (primary and
secondary) can directly write to the physical address (in outbound
region) of the other interface to ring doorbell using MSI.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epc-core.c | 40 +++++++++++++++++++++++++++++
 include/linux/pci-epc.h             |  7 +++++
 2 files changed, 47 insertions(+)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 42085fcc746d..797e5d323998 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -363,6 +363,46 @@ int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 }
 EXPORT_SYMBOL_GPL(pci_epc_raise_irq);
 
+/**
+ * pci_epc_map_msi_irq() - Map physical address to MSI address and return
+ *                         MSI data
+ * @epc: the EPC device which has the MSI capability
+ * @func_no: the physical endpoint function number in the EPC device
+ * @vfunc_no: the virtual endpoint function number in the physical function
+ * @phys_addr: the physical address of the outbound region
+ * @interrupt_num: the MSI interrupt number
+ * @entry_size: Size of Outbound address region for each interrupt
+ * @msi_data: the data that should be written in order to raise MSI interrupt
+ *            with interrupt number as 'interrupt num'
+ *
+ * Invoke to map physical address to MSI address and return MSI data. The
+ * physical address should be an address in the outbound region. This is
+ * required to implement doorbell functionality of NTB wherein EPC on either
+ * side of the interface (primary and secondary) can directly write to the
+ * physical address (in outbound region) of the other interface to ring
+ * doorbell.
+ */
+int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+			phys_addr_t phys_addr, u8 interrupt_num, u32 entry_size,
+			u32 *msi_data)
+{
+	int ret;
+
+	if (IS_ERR_OR_NULL(epc))
+		return -EINVAL;
+
+	if (!epc->ops->map_msi_irq)
+		return -EINVAL;
+
+	mutex_lock(&epc->lock);
+	ret = epc->ops->map_msi_irq(epc, func_no, vfunc_no, phys_addr,
+				    interrupt_num, entry_size, msi_data);
+	mutex_unlock(&epc->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_map_msi_irq);
+
 /**
  * pci_epc_get_msi() - get the number of MSI interrupt numbers allocated
  * @epc: the EPC device to which MSI interrupts was requested
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 91d5cbaabc8f..0632a4d4714d 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -57,6 +57,7 @@ pci_epc_interface_string(enum pci_epc_interface_type type)
  * @get_msix: ops to get the number of MSI-X interrupts allocated by the RC
  *	     from the MSI-X capability register
  * @raise_irq: ops to raise a legacy, MSI or MSI-X interrupt
+ * @map_msi_irq: ops to map physical address to MSI address and return MSI data
  * @start: ops to start the PCI link
  * @stop: ops to stop the PCI link
  * @owner: the module owner containing the ops
@@ -85,6 +86,9 @@ struct pci_epc_ops {
 	int	(*get_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no);
 	int	(*raise_irq)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 			     enum pci_epc_irq_type type, u16 interrupt_num);
+	int	(*map_msi_irq)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+			       phys_addr_t phys_addr, u8 interrupt_num,
+			       u32 entry_size, u32 *msi_data);
 	int	(*start)(struct pci_epc *epc);
 	void	(*stop)(struct pci_epc *epc);
 	const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
@@ -212,6 +216,9 @@ int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no);
 int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 		     u16 interrupts);
 int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no);
+int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+			phys_addr_t phys_addr, u8 interrupt_num,
+			u32 entry_size, u32 *msi_data);
 int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 		      enum pci_epc_irq_type type, u16 interrupt_num);
 int pci_epc_start(struct pci_epc *epc);
-- 
2.17.1


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

* [RFC PATCH 14/21] PCI: cadence: Implement ->msi_map_irq() ops
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (12 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 13/21] PCI: endpoint: Add pci_epc_ops to map MSI irq Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 15/21] PCI: endpoint: Remove unused pci_epf_match_device() Kishon Vijay Abraham I
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Implement ->msi_map_irq() ops in order to map physical address to
MSI address and return MSI data.

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

diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c
index ff4b4b8eb017..5d41c892177f 100644
--- a/drivers/pci/controller/pcie-cadence-ep.c
+++ b/drivers/pci/controller/pcie-cadence-ep.c
@@ -517,6 +517,64 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
 	return 0;
 }
 
+static int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn,
+				    phys_addr_t addr, u8 interrupt_num,
+				    u32 entry_size, u32 *msi_data)
+{
+	u32 sriov_cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET;
+	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+	struct cdns_pcie *pcie = &ep->pcie;
+	u16 flags, mme, data, data_mask;
+	u32 first_vf_offset, stride;
+	u8 msi_count;
+	u64 pci_addr;
+	int ret;
+	int i;
+
+	if (vfn > 0) {
+		first_vf_offset = cdns_pcie_ep_fn_readw(pcie, fn, sriov_cap +
+							PCI_SRIOV_VF_OFFSET);
+		stride = cdns_pcie_ep_fn_readw(pcie, fn, sriov_cap +
+					       PCI_SRIOV_VF_STRIDE);
+		fn = fn + first_vf_offset + ((vfn - 1) * stride);
+	}
+
+	/* Check whether the MSI feature has been enabled by the PCI host. */
+	flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+	if (!(flags & PCI_MSI_FLAGS_ENABLE))
+		return -EINVAL;
+
+	/* Get the number of enabled MSIs */
+	mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
+	msi_count = 1 << mme;
+	if (!interrupt_num || interrupt_num > msi_count)
+		return -EINVAL;
+
+	/* Compute the data value to be written. */
+	data_mask = msi_count - 1;
+	data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
+	data = data & ~data_mask;
+
+	/* Get the PCI address where to write the data into. */
+	pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
+	pci_addr <<= 32;
+	pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
+	pci_addr &= GENMASK_ULL(63, 2);
+
+	for (i = 0; i < interrupt_num; i++) {
+		ret = cdns_pcie_ep_map_addr(epc, fn, vfn, addr, pci_addr,
+					    entry_size);
+		if (ret)
+			return ret;
+		addr = addr + entry_size;
+	}
+
+	*msi_data = data;
+
+	return 0;
+}
+
 static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
 				      u16 interrupt_num)
 {
@@ -678,6 +736,7 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
 	.set_msix	= cdns_pcie_ep_set_msix,
 	.get_msix	= cdns_pcie_ep_get_msix,
 	.raise_irq	= cdns_pcie_ep_raise_irq,
+	.map_msi_irq	= cdns_pcie_ep_map_msi_irq,
 	.start		= cdns_pcie_ep_start,
 	.get_features	= cdns_pcie_ep_get_features,
 };
-- 
2.17.1


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

* [RFC PATCH 15/21] PCI: endpoint: Remove unused pci_epf_match_device()
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (13 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 14/21] PCI: cadence: Implement ->msi_map_irq() ops Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 16/21] PCI: endpoint: Fix missing mutex_unlock in error case Kishon Vijay Abraham I
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Remove unused pci_epf_match_device() function added in pci-epf-core.c

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epf-core.c | 16 ----------------
 include/linux/pci-epf.h             |  2 --
 2 files changed, 18 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 388966faf17a..9fa4d8d4d829 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -619,22 +619,6 @@ struct pci_epf *devm_pci_epf_of_create(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_pci_epf_of_create);
 
-const struct pci_epf_device_id *
-pci_epf_match_device(const struct pci_epf_device_id *id, struct pci_epf *epf)
-{
-	if (!id || !epf)
-		return NULL;
-
-	while (*id->name) {
-		if (strcmp(epf->name, id->name) == 0)
-			return id;
-		id++;
-	}
-
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(pci_epf_match_device);
-
 static void pci_epf_dev_release(struct device *dev)
 {
 	struct pci_epf *epf = to_pci_epf(dev);
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index b5075119f3ad..80505106c770 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -189,8 +189,6 @@ static inline void *epf_get_drvdata(struct pci_epf *epf)
 	return dev_get_drvdata(&epf->dev);
 }
 
-const struct pci_epf_device_id *
-pci_epf_match_device(const struct pci_epf_device_id *id, struct pci_epf *epf);
 struct pci_epf *pci_epf_create(const char *name);
 struct pci_epf *pci_epf_of_create(struct device_node *node);
 struct pci_epf *devm_pci_epf_of_create(struct device *dev,
-- 
2.17.1


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

* [RFC PATCH 16/21] PCI: endpoint: Fix missing mutex_unlock in error case
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (14 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 15/21] PCI: endpoint: Remove unused pci_epf_match_device() Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 17/21] PCI: endpoint: *_free_bar() to return error codes on failure Kishon Vijay Abraham I
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

There is a missing mutex_unlock() in pci_epc_add_epf() in one of the
error scenarios. Fix it here.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epc-core.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 797e5d323998..33c745546a42 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -686,6 +686,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
 {
 	struct list_head *list;
 	u32 func_no = 0;
+	int ret = 0;
 
 	if (epf->is_vf)
 		return -EINVAL;
@@ -705,8 +706,10 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
 	mutex_lock(&epc->lock);
 	func_no = find_first_zero_bit(&epc->function_num_map,
 				      BITS_PER_LONG);
-	if (func_no >= BITS_PER_LONG)
-		return -EINVAL;
+	if (func_no >= BITS_PER_LONG) {
+		ret = -EINVAL;
+		goto err;
+	}
 
 	set_bit(func_no, &epc->function_num_map);
 	if (type == PRIMARY_INTERFACE) {
@@ -720,9 +723,11 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
 	}
 
 	list_add_tail(list, &epc->pci_epf);
+
+err:
 	mutex_unlock(&epc->lock);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(pci_epc_add_epf);
 
-- 
2.17.1


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

* [RFC PATCH 17/21] PCI: endpoint: *_free_bar() to return error codes on failure
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (15 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 16/21] PCI: endpoint: Fix missing mutex_unlock in error case Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 18/21] PCI: endpoint: Add EP function driver to provide NTB functionality Kishon Vijay Abraham I
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Modify pci_epc_get_next_free_bar() and pci_epc_get_first_free_bar() to
return error values if there are no free BARs available.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/pci-epc-core.c | 9 ++++-----
 include/linux/pci-epc.h             | 7 +++----
 2 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 33c745546a42..a93c78488bca 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -173,8 +173,7 @@ EXPORT_SYMBOL_GPL(of_pci_epc_get_by_name);
  * Invoke to get the first unreserved BAR that can be used by the endpoint
  * function. For any incorrect value in reserved_bar return '0'.
  */
-unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
-					*epc_features)
+int pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features)
 {
 	return pci_epc_get_next_free_bar(epc_features, BAR_0);
 }
@@ -188,8 +187,8 @@ EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar);
  * Invoke to get the next unreserved BAR starting from @bar that can be used
  * for endpoint function. For any incorrect value in reserved_bar return '0'.
  */
-unsigned int pci_epc_get_next_free_bar(const struct pci_epc_features
-				       *epc_features, enum pci_barno bar)
+int pci_epc_get_next_free_bar(const struct pci_epc_features
+			      *epc_features, enum pci_barno bar)
 {
 	unsigned long free_bar;
 
@@ -209,7 +208,7 @@ unsigned int pci_epc_get_next_free_bar(const struct pci_epc_features
 
 	free_bar = find_next_zero_bit(&free_bar, 6, bar);
 	if (free_bar > 5)
-		return 0;
+		return -EINVAL;
 
 	return free_bar;
 }
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 0632a4d4714d..ad8021b0efb7 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -227,10 +227,9 @@ void pci_epc_of_parse_header(struct device_node *node,
 			     struct pci_epf_header *header);
 const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
 						    u8 func_no, u8 vfunc_no);
-unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
-					*epc_features);
-unsigned int pci_epc_get_next_free_bar(const struct pci_epc_features
-				       *epc_features, enum pci_barno bar);
+int pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features);
+int pci_epc_get_next_free_bar(const struct pci_epc_features
+			      *epc_features, enum pci_barno bar);
 struct pci_epc *pci_epc_get(const char *epc_name);
 void pci_epc_put(struct pci_epc *epc);
 struct pci_epc *of_pci_epc_get(struct device_node *node, int index);
-- 
2.17.1


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

* [RFC PATCH 18/21] PCI: endpoint: Add EP function driver to provide NTB functionality
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (16 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 17/21] PCI: endpoint: *_free_bar() to return error codes on failure Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 19/21] PCI: Add TI J721E device to pci ids Kishon Vijay Abraham I
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add a new endpoint function driver to provide NTB functionality
using multiple PCIe endpoint instances.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/endpoint/functions/Kconfig       |   12 +
 drivers/pci/endpoint/functions/Makefile      |    1 +
 drivers/pci/endpoint/functions/pci-epf-ntb.c | 1143 ++++++++++++++++++
 3 files changed, 1156 insertions(+)
 create mode 100644 drivers/pci/endpoint/functions/pci-epf-ntb.c

diff --git a/drivers/pci/endpoint/functions/Kconfig b/drivers/pci/endpoint/functions/Kconfig
index 8820d0f7ec77..55ac7bb2d469 100644
--- a/drivers/pci/endpoint/functions/Kconfig
+++ b/drivers/pci/endpoint/functions/Kconfig
@@ -12,3 +12,15 @@ config PCI_EPF_TEST
 	   for PCI Endpoint.
 
 	   If in doubt, say "N" to disable Endpoint test driver.
+
+config PCI_EPF_NTB
+	tristate "PCI Endpoint NTB driver"
+	depends on PCI_ENDPOINT
+	help
+	   Select this configuration option to enable the NTB driver
+	   for PCI Endpoint. NTB driver implements NTB controller
+	   functionality using multiple PCIe endpoint instances. It
+	   can support NTB endpoint function devices created using
+	   device tree.
+
+	   If in doubt, say "N" to disable Endpoint NTB driver.
diff --git a/drivers/pci/endpoint/functions/Makefile b/drivers/pci/endpoint/functions/Makefile
index d6fafff080e2..96ab932a537a 100644
--- a/drivers/pci/endpoint/functions/Makefile
+++ b/drivers/pci/endpoint/functions/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_PCI_EPF_TEST)		+= pci-epf-test.o
+obj-$(CONFIG_PCI_EPF_NTB)		+= pci-epf-ntb.o
diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c
new file mode 100644
index 000000000000..14b3862fc780
--- /dev/null
+++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c
@@ -0,0 +1,1143 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * Endpoint Function Driver to implement Non-Transparent Bridge functionality
+ *
+ * Copyright (C) 2019 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
+static struct workqueue_struct *kpcintb_workqueue;
+
+#define COMMAND_CONFIGURE_DOORBELL	1
+#define COMMAND_CONFIGURE_MW		2
+#define COMMAND_LINK_UP			3
+
+#define COMMAND_STATUS_OK		BIT(0)
+#define LINK_STATUS_UP			BIT(1)
+
+#define SPAD_COUNT			64
+#define DB_COUNT			4
+#define NTB_MW_OFFSET			2
+#define DB_COUNT_MASK			GENMASK(15, 0)
+#define MSIX_ENABLE			BIT(16)
+#define MAX_DB_COUNT			32
+#define MAX_MW				4
+
+enum epf_ntb_bar {
+	BAR_CONFIG,
+	BAR_PEER_SPAD,
+	BAR_DB_MW1,
+	BAR_MW2,
+	BAR_MW3,
+	BAR_MW4,
+};
+
+struct epf_ntb {
+	u32 num_mws;
+	u32 *mws_size;
+	u32 db_count;
+	u32 spad_count;
+	struct pci_epf *epf;
+	struct epf_ntb_epc *epc[2];
+};
+
+struct epf_ntb_epc {
+	u8 func_no;
+	u8 vfunc_no;
+	bool linkup;
+	u32 spad_size;
+	struct pci_epc *epc;
+	struct epf_ntb *epf_ntb;
+	void __iomem *mw_addr[6];
+	struct epf_ntb_ctrl *reg;
+	struct pci_epf_bar *epf_bar;
+	enum pci_barno epf_ntb_bar[6];
+	struct delayed_work cmd_handler;
+	enum pci_epc_interface_type type;
+	const struct pci_epc_features *epc_features;
+};
+
+struct epf_ntb_ctrl {
+	u32	command;
+	u32	argument;
+	u32	status;
+	u32	topology;
+	u64	addr;
+	u32	size;
+	u32	mw1_offset;
+	u32	num_mws;
+	u32	spad_offset;
+	u32	spad_count;
+	u32	db_entry_size;
+	u32	db_data[MAX_DB_COUNT];
+} __packed;
+
+static struct pci_epf_header epf_ntb_header = {
+	.vendorid	= PCI_ANY_ID,
+	.deviceid	= PCI_ANY_ID,
+	.baseclass_code	= PCI_BASE_CLASS_MEMORY,
+	.interrupt_pin	= PCI_INTERRUPT_INTA,
+};
+
+static void epf_ntb_link_up(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct epf_ntb_epc *ntb_epc;
+	struct epf_ntb_ctrl *ctrl;
+	u8 vfunc_no, func_no;
+
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		ntb_epc = ntb->epc[type];
+		func_no = ntb_epc->func_no;
+		vfunc_no = ntb_epc->vfunc_no;
+		ctrl = ntb_epc->reg;
+		ctrl->status |= LINK_STATUS_UP;
+		pci_epc_raise_irq(ntb_epc->epc, func_no, vfunc_no,
+				  PCI_EPC_IRQ_MSI, 1);
+	}
+}
+
+static void
+epf_ntb_configure_mw(struct epf_ntb *ntb, enum pci_epc_interface_type type,
+		     u32 mw)
+{
+	struct epf_ntb_epc *peer_ntb_epc;
+	struct pci_epf_bar *peer_epf_bar;
+	struct epf_ntb_epc *ntb_epc;
+	enum pci_barno peer_barno;
+	struct epf_ntb_ctrl *ctrl;
+	phys_addr_t phys_addr;
+	u8 vfunc_no, func_no;
+	struct pci_epc *epc;
+	u64 addr;
+	u32 size;
+	int ret;
+
+	ntb_epc = ntb->epc[type];
+	epc = ntb_epc->epc;
+
+	peer_ntb_epc = ntb->epc[!type];
+	peer_barno = peer_ntb_epc->epf_ntb_bar[mw + NTB_MW_OFFSET];
+	peer_epf_bar = &peer_ntb_epc->epf_bar[peer_barno];
+
+	phys_addr = peer_epf_bar->phys_addr;
+	ctrl = ntb_epc->reg;
+	addr = ctrl->addr;
+	size = ctrl->size;
+	if (mw + NTB_MW_OFFSET == BAR_DB_MW1)
+		phys_addr += ctrl->mw1_offset;
+
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+
+	ret = pci_epc_map_addr(epc, func_no, vfunc_no, phys_addr, addr, size);
+	WARN(ret < 0, "%s intf: Failed to map memory window %d address\n",
+	     pci_epc_interface_string(type), mw);
+}
+
+static void
+epf_ntb_configure_db(struct epf_ntb *ntb, enum pci_epc_interface_type type,
+		     u16 db_count, bool msix)
+{
+	struct epf_ntb_epc *peer_ntb_epc;
+	struct pci_epf_bar *peer_epf_bar;
+	struct epf_ntb_ctrl *peer_ctrl;
+	struct epf_ntb_epc *ntb_epc;
+	enum pci_barno peer_barno;
+	phys_addr_t phys_addr;
+	u8 vfunc_no, func_no;
+	struct pci_epc *epc;
+	u32 db_entry_size;
+	u32 db_data;
+	int ret, i;
+
+	ntb_epc = ntb->epc[type];
+	epc = ntb_epc->epc;
+
+	peer_ntb_epc = ntb->epc[!type];
+	peer_barno = peer_ntb_epc->epf_ntb_bar[BAR_DB_MW1];
+	peer_epf_bar = &peer_ntb_epc->epf_bar[peer_barno];
+	peer_ctrl = peer_ntb_epc->reg;
+	db_entry_size = peer_ctrl->db_entry_size;
+
+	phys_addr = peer_epf_bar->phys_addr;
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+
+	ret = pci_epc_map_msi_irq(epc, func_no, vfunc_no, phys_addr, db_count,
+				  db_entry_size, &db_data);
+	WARN(ret < 0, "%s intf: Failed to map MSI IRQ\n",
+	     pci_epc_interface_string(type));
+	for (i = 0; i < db_count; i++)
+		peer_ctrl->db_data[i] = db_data | i;
+}
+
+static void epf_ntb_cmd_handler(struct work_struct *work)
+{
+	enum pci_epc_interface_type type;
+	struct epf_ntb_epc *ntb_epc;
+	struct epf_ntb_ctrl *ctrl;
+	u32 command, argument;
+	struct epf_ntb *ntb;
+	struct device *dev;
+	u16 db_count;
+	bool is_msix;
+
+	ntb_epc = container_of(work, struct epf_ntb_epc, cmd_handler.work);
+	ctrl = ntb_epc->reg;
+	command = ctrl->command;
+	if (!command)
+		goto reset_handler;
+	argument = ctrl->argument;
+
+	ctrl->command = 0;
+	ctrl->argument = 0;
+
+	ctrl = ntb_epc->reg;
+	type = ntb_epc->type;
+	ntb = ntb_epc->epf_ntb;
+	dev = &ntb->epf->dev;
+
+	switch (command) {
+	case COMMAND_CONFIGURE_DOORBELL:
+		db_count = argument & DB_COUNT_MASK;
+		is_msix = argument & MSIX_ENABLE;
+		epf_ntb_configure_db(ntb, type, db_count, is_msix);
+		ctrl->status |= COMMAND_STATUS_OK;
+		break;
+	case COMMAND_CONFIGURE_MW:
+		epf_ntb_configure_mw(ntb, type, argument);
+		ctrl->status |= COMMAND_STATUS_OK;
+		break;
+	case COMMAND_LINK_UP:
+		ntb_epc->linkup = true;
+		if (ntb->epc[PRIMARY_INTERFACE]->linkup &&
+		    ntb->epc[SECONDARY_INTERFACE]->linkup)
+			epf_ntb_link_up(ntb);
+		ctrl->status |= COMMAND_STATUS_OK;
+		break;
+	default:
+		dev_err(dev, "UNKNOWN command: %d\n", command);
+		break;
+	}
+
+reset_handler:
+	queue_delayed_work(kpcintb_workqueue, &ntb_epc->cmd_handler,
+			   msecs_to_jiffies(5));
+}
+
+static void epf_ntb_peer_spad_bar_clear(struct epf_ntb_epc *ntb_epc)
+{
+	struct pci_epf_bar *epf_bar;
+	enum pci_barno barno;
+	u8 vfunc_no, func_no;
+	struct pci_epc *epc;
+
+	epc = ntb_epc->epc;
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+	barno = ntb_epc->epf_ntb_bar[BAR_PEER_SPAD];
+	epf_bar = &ntb_epc->epf_bar[barno];
+	pci_epc_clear_bar(epc, func_no, vfunc_no, epf_bar);
+}
+
+static int
+epf_ntb_peer_spad_bar_set(struct epf_ntb *ntb, enum pci_epc_interface_type type)
+{
+	struct epf_ntb_epc *peer_ntb_epc;
+	struct pci_epf_bar *peer_epf_bar;
+	struct epf_ntb_epc *ntb_epc;
+	struct pci_epf_bar *epf_bar;
+	enum pci_barno peer_barno;
+	u32 peer_spad_offset;
+	enum pci_barno barno;
+	u8 vfunc_no, func_no;
+	struct pci_epc *epc;
+	struct device *dev;
+	int ret;
+
+	dev = &ntb->epf->dev;
+
+	peer_ntb_epc = ntb->epc[!type];
+	peer_barno = peer_ntb_epc->epf_ntb_bar[BAR_CONFIG];
+	peer_epf_bar = &peer_ntb_epc->epf_bar[peer_barno];
+
+	ntb_epc = ntb->epc[type];
+	barno = ntb_epc->epf_ntb_bar[BAR_PEER_SPAD];
+	epf_bar = &ntb_epc->epf_bar[barno];
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+	epc = ntb_epc->epc;
+
+	peer_spad_offset = peer_ntb_epc->reg->spad_offset;
+	epf_bar->phys_addr = peer_epf_bar->phys_addr + peer_spad_offset;
+	epf_bar->size = peer_ntb_epc->spad_size;
+	epf_bar->barno = barno;
+	epf_bar->flags = PCI_BASE_ADDRESS_MEM_TYPE_32;
+
+	ret = pci_epc_set_bar(ntb_epc->epc, func_no, vfunc_no, epf_bar);
+	if (ret) {
+		dev_err(dev, "%s intf: peer SPAD BAR set failed\n",
+			pci_epc_interface_string(type));
+		return ret;
+	}
+
+	return 0;
+}
+
+static void epf_ntb_config_sspad_bar_clear(struct epf_ntb_epc *ntb_epc)
+{
+	struct pci_epf_bar *epf_bar;
+	u8 vfunc_no, func_no;
+	enum pci_barno barno;
+	struct pci_epc *epc;
+
+	epc = ntb_epc->epc;
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+	barno = ntb_epc->epf_ntb_bar[BAR_CONFIG];
+	epf_bar = &ntb_epc->epf_bar[barno];
+	pci_epc_clear_bar(epc, func_no, vfunc_no, epf_bar);
+}
+
+static int epf_ntb_config_sspad_bar_set(struct epf_ntb_epc *ntb_epc)
+{
+	struct pci_epf_bar *epf_bar;
+	enum pci_barno barno;
+	u8 vfunc_no, func_no;
+	struct epf_ntb *ntb;
+	struct pci_epc *epc;
+	struct device *dev;
+	int ret;
+
+	ntb = ntb_epc->epf_ntb;
+	dev = &ntb->epf->dev;
+
+	epc = ntb_epc->epc;
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+	barno = ntb_epc->epf_ntb_bar[BAR_CONFIG];
+	epf_bar = &ntb_epc->epf_bar[barno];
+
+	ret = pci_epc_set_bar(epc, func_no, vfunc_no, epf_bar);
+	if (ret) {
+		dev_err(dev, "%s inft: Config/Status/SPAD BAR set failed\n",
+			pci_epc_interface_string(ntb_epc->type));
+		return ret;
+	}
+
+	return 0;
+}
+
+static void epf_ntb_config_spad_bar_free(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct epf_ntb_epc *ntb_epc;
+	enum pci_barno barno;
+	struct pci_epf *epf;
+
+	epf = ntb->epf;
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		ntb_epc = ntb->epc[type];
+		barno = ntb_epc->epf_ntb_bar[BAR_CONFIG];
+		if (ntb_epc->reg)
+			pci_epf_free_space(epf, ntb_epc->reg, barno, type);
+	}
+}
+
+static int
+epf_ntb_config_spad_bar_alloc_interface(struct epf_ntb *ntb,
+					enum pci_epc_interface_type type)
+{
+	const struct pci_epc_features *peer_epc_features;
+	const struct pci_epc_features *epc_features;
+	struct epf_ntb_epc *peer_ntb_epc;
+	struct epf_ntb_epc *ntb_epc;
+	struct epf_ntb_ctrl *ctrl;
+	enum pci_barno peer_barno;
+	struct device_node *node;
+	u32 spad_size, ctrl_size;
+	enum pci_barno barno;
+	u64 size, peer_size;
+	struct pci_epc *epc;
+	struct pci_epf *epf;
+	struct device *dev;
+	u32 spad_count;
+	size_t align;
+	void *base;
+
+	epf = ntb->epf;
+	node = epf->node;
+	dev = &epf->dev;
+	ntb_epc = ntb->epc[type];
+	epc = ntb_epc->epc;
+
+	epc_features = ntb_epc->epc_features;
+	barno = ntb_epc->epf_ntb_bar[BAR_CONFIG];
+	size = epc_features->bar_fixed_size[barno];
+	align = epc_features->align;
+
+	peer_ntb_epc = ntb->epc[!type];
+	peer_epc_features = peer_ntb_epc->epc_features;
+	peer_barno = ntb_epc->epf_ntb_bar[BAR_PEER_SPAD];
+	peer_size = peer_epc_features->bar_fixed_size[barno];
+
+	/* Check if epc_features is populated incorrectly */
+	if ((!IS_ALIGNED(size, align)))
+		return -EINVAL;
+
+	spad_count = SPAD_COUNT;
+	of_property_read_u32(node, "spad-count", &spad_count);
+
+	ctrl_size = sizeof(struct epf_ntb_ctrl);
+	spad_size = spad_count * 4;
+
+	if (!align) {
+		ctrl_size = roundup_pow_of_two(ctrl_size);
+		spad_size = roundup_pow_of_two(spad_size);
+	} else {
+		ctrl_size = ALIGN(ctrl_size, align);
+		spad_size = ALIGN(spad_size, align);
+	}
+
+	if (peer_size) {
+		if (peer_size < spad_size)
+			spad_count = peer_size / 4;
+		spad_size = peer_size;
+	}
+
+	/*
+	 * In order to make sure SPAD offset is aligned to its size,
+	 * expand control region size to the size of SPAD if SPAD size
+	 * is greater than control region size.
+	 */
+	if (spad_size > ctrl_size)
+		ctrl_size = spad_size;
+
+	if (!size)
+		size = ctrl_size + spad_size;
+	else if (size < ctrl_size + spad_size)
+		return -EINVAL;
+
+	base = pci_epf_alloc_space(epf, size, barno, align, type);
+	if (!base) {
+		dev_err(dev, "%s intf: Config/Status/SPAD alloc region fail\n",
+			pci_epc_interface_string(type));
+		return -ENOMEM;
+	}
+
+	ntb_epc->reg = base;
+
+	ctrl = ntb_epc->reg;
+	ctrl->spad_offset = ctrl_size;
+	ctrl->spad_count = spad_count;
+	ctrl->num_mws = ntb->num_mws;
+	ctrl->db_entry_size = align ? align : 4;
+	ntb_epc->spad_size = spad_size;
+
+	return 0;
+}
+
+static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct device *dev;
+	int ret;
+
+	dev = &ntb->epf->dev;
+
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		ret = epf_ntb_config_spad_bar_alloc_interface(ntb, type);
+		if (ret) {
+			dev_err(dev, "%s intf: Config/SPAD BAR alloc failed\n",
+				pci_epc_interface_string(type));
+			goto err_config_spad_bar_alloc;
+		}
+	}
+
+	return 0;
+
+err_config_spad_bar_alloc:
+	epf_ntb_config_spad_bar_free(ntb);
+
+	return ret;
+}
+
+static void epf_ntb_free_peer_mem(struct epf_ntb_epc *ntb_epc)
+{
+	struct pci_epf_bar *epf_bar;
+	void __iomem *mw_addr;
+	phys_addr_t phys_addr;
+	enum epf_ntb_bar bar;
+	enum pci_barno barno;
+	struct pci_epc *epc;
+	size_t size;
+
+	epc = ntb_epc->epc;
+
+	for (bar = BAR_DB_MW1; bar < BAR_MW4; bar++) {
+		barno = ntb_epc->epf_ntb_bar[bar];
+		mw_addr = ntb_epc->mw_addr[barno];
+		epf_bar = &ntb_epc->epf_bar[barno];
+		phys_addr = epf_bar->phys_addr;
+		size = epf_bar->size;
+		if (mw_addr) {
+			pci_epc_mem_free_addr(epc, phys_addr, mw_addr, size);
+			ntb_epc->mw_addr[barno] = NULL;
+		}
+	}
+}
+
+static void epf_ntb_db_mw_bar_clear(struct epf_ntb_epc *ntb_epc)
+{
+	struct pci_epf_bar *epf_bar;
+	enum epf_ntb_bar bar;
+	enum pci_barno barno;
+	u8 vfunc_no, func_no;
+	struct pci_epc *epc;
+
+	epc = ntb_epc->epc;
+
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+
+	for (bar = BAR_DB_MW1; bar < BAR_MW4; bar++) {
+		barno = ntb_epc->epf_ntb_bar[bar];
+		epf_bar = &ntb_epc->epf_bar[barno];
+		pci_epc_clear_bar(epc, func_no, vfunc_no, epf_bar);
+	}
+}
+
+static void epf_ntb_db_mw_bar_cleanup(struct epf_ntb_epc *ntb_epc,
+				      struct epf_ntb_epc *peer_ntb_epc)
+{
+	epf_ntb_db_mw_bar_clear(ntb_epc);
+	epf_ntb_free_peer_mem(peer_ntb_epc);
+}
+
+static int
+epf_ntb_alloc_peer_mem(struct device *dev, struct epf_ntb_epc *ntb_epc,
+		       enum epf_ntb_bar bar, struct epf_ntb_epc *peer_ntb_epc,
+		       size_t size)
+{
+	const struct pci_epc_features *epc_features;
+	struct pci_epf_bar *epf_bar;
+	struct pci_epc *peer_epc;
+	phys_addr_t phys_addr;
+	void __iomem *mw_addr;
+	enum pci_barno barno;
+	size_t align;
+
+	epc_features = ntb_epc->epc_features;
+	align = epc_features->align;
+
+	if (size < 128)
+		size = 128;
+
+	if (align)
+		size = ALIGN(size, align);
+	else
+		size = roundup_pow_of_two(size);
+
+	peer_epc = peer_ntb_epc->epc;
+	mw_addr = pci_epc_mem_alloc_addr(peer_epc, &phys_addr, size);
+	if (!mw_addr) {
+		dev_err(dev, "%s intf: Failed to allocate OB address\n",
+			pci_epc_interface_string(peer_ntb_epc->type));
+		return -ENOMEM;
+	}
+
+	barno = ntb_epc->epf_ntb_bar[bar];
+	epf_bar = &ntb_epc->epf_bar[barno];
+	ntb_epc->mw_addr[barno] = mw_addr;
+
+	epf_bar->phys_addr = phys_addr;
+	epf_bar->size = size;
+	epf_bar->barno = barno;
+	epf_bar->flags = PCI_BASE_ADDRESS_MEM_TYPE_32;
+
+	return 0;
+}
+
+static int epf_ntb_configure_interrupt(struct epf_ntb *ntb,
+				       enum pci_epc_interface_type type)
+{
+	const struct pci_epc_features *epc_features;
+	bool msix_capable, msi_capable;
+	struct epf_ntb_epc *ntb_epc;
+	struct device_node *node;
+	u8 vfunc_no, func_no;
+	struct pci_epc *epc;
+	struct device *dev;
+	u32 db_count;
+	int ret;
+
+	ntb_epc = ntb->epc[type];
+	dev = &ntb->epf->dev;
+	node = ntb->epf->node;
+
+	epc_features = ntb_epc->epc_features;
+	msix_capable = epc_features->msix_capable;
+	msi_capable = epc_features->msi_capable;
+
+	if (!(msix_capable || msi_capable)) {
+		dev_err(dev, "MSI or MSI-X is required for doorbell\n");
+		return -EINVAL;
+	}
+
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+
+	db_count = DB_COUNT;
+	of_property_read_u32(node, "db-count", &db_count);
+	if (db_count > MAX_DB_COUNT) {
+		dev_err(dev, "DB count cannot be more than %d\n", MAX_DB_COUNT);
+		return -EINVAL;
+	}
+
+	ntb->db_count = db_count;
+	epc = ntb_epc->epc;
+
+	if (msi_capable) {
+		ret = pci_epc_set_msi(epc, func_no, vfunc_no, db_count);
+		if (ret) {
+			dev_err(dev, "%s intf: MSI configuration failed\n",
+				pci_epc_interface_string(type));
+			return ret;
+		}
+	}
+
+	if (msix_capable) {
+		ret = pci_epc_set_msix(epc, func_no, vfunc_no, db_count);
+		if (ret) {
+			dev_err(dev, "MSI configuration failed\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int epf_ntb_db_mw_bar_init(struct epf_ntb *ntb,
+				  enum pci_epc_interface_type type)
+{
+	const struct pci_epc_features *epc_features;
+	struct epf_ntb_epc *peer_ntb_epc;
+	struct epf_ntb_epc *ntb_epc;
+	struct pci_epf_bar *epf_bar;
+	struct epf_ntb_ctrl *ctrl;
+	enum epf_ntb_bar bar;
+	u8 vfunc_no, func_no;
+	enum pci_barno barno;
+	struct pci_epc *epc;
+	struct device *dev;
+	u32 num_mws, size;
+	u32 db_count;
+	size_t align;
+	int ret;
+	int i;
+
+	ntb_epc = ntb->epc[type];
+	peer_ntb_epc = ntb->epc[!type];
+
+	dev = &ntb->epf->dev;
+	epc_features = ntb_epc->epc_features;
+	align = epc_features->align;
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+	epc = ntb_epc->epc;
+	num_mws = ntb->num_mws;
+	db_count = ntb->db_count;
+
+	for (bar = BAR_DB_MW1, i = 0; i < num_mws; bar++, i++) {
+		if (bar == BAR_DB_MW1) {
+			align = align ? align : 4;
+			size = db_count * align;
+			size = ALIGN(size, ntb->mws_size[i]);
+			ctrl = ntb_epc->reg;
+			ctrl->mw1_offset = size;
+			size += ntb->mws_size[i];
+		} else {
+			size = ntb->mws_size[i];
+		}
+
+		ret = epf_ntb_alloc_peer_mem(dev, ntb_epc, bar,
+					     peer_ntb_epc, size);
+		if (ret)
+			goto err_alloc_peer_mem;
+
+		barno = ntb_epc->epf_ntb_bar[bar];
+		epf_bar = &ntb_epc->epf_bar[barno];
+
+		ret = pci_epc_set_bar(epc, func_no, vfunc_no, epf_bar);
+		if (ret) {
+			dev_err(dev, "%s intf: DoorBell BAR set failed\n",
+				pci_epc_interface_string(type));
+			goto err_alloc_peer_mem;
+		}
+	}
+
+	return 0;
+
+err_alloc_peer_mem:
+	epf_ntb_db_mw_bar_cleanup(ntb_epc, peer_ntb_epc);
+
+	return ret;
+}
+
+static void epf_ntb_epc_destroy(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct epf_ntb_epc *ntb_epc;
+	struct pci_epc *epc;
+	struct pci_epf *epf;
+
+	epf = ntb->epf;
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		ntb_epc = ntb->epc[type];
+		if (!ntb_epc)
+			return;
+		epc = ntb_epc->epc;
+		pci_epc_remove_epf(epc, epf, type);
+		pci_epc_put(epc);
+	}
+}
+
+static int
+epf_ntb_epc_create_interface(struct epf_ntb *ntb, struct pci_epc *epc,
+			     enum pci_epc_interface_type type)
+{
+	const struct pci_epc_features *epc_features;
+	struct pci_epf_bar *epf_bar;
+	struct epf_ntb_epc *ntb_epc;
+	u8 vfunc_no, func_no;
+	struct pci_epf *epf;
+	struct device *dev;
+
+	dev = &ntb->epf->dev;
+
+	ntb_epc = devm_kzalloc(dev, sizeof(*ntb_epc), GFP_KERNEL);
+	if (!ntb_epc)
+		return -ENOMEM;
+
+	epf = ntb->epf;
+	if (type == PRIMARY_INTERFACE) {
+		func_no = epf->func_no;
+		vfunc_no = epf->vfunc_no;
+		epf_bar = epf->bar;
+	} else {
+		func_no = epf->sec_epc_func_no;
+		vfunc_no = epf->sec_epc_vfunc_no;
+		epf_bar = epf->sec_epc_bar;
+	}
+
+	ntb_epc->linkup = false;
+	ntb_epc->epc = epc;
+	ntb_epc->func_no = func_no;
+	ntb_epc->vfunc_no = vfunc_no;
+	ntb_epc->type = type;
+	ntb_epc->epf_bar = epf_bar;
+	ntb_epc->epf_ntb = ntb;
+
+	epc_features = pci_epc_get_features(epc, func_no, vfunc_no);
+	ntb_epc->epc_features = epc_features;
+
+	ntb->epc[type] = ntb_epc;
+
+	return 0;
+}
+
+static int epf_ntb_epc_create(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct device_node *node;
+	const char *epc_name;
+	struct pci_epc *epc;
+	struct pci_epf *epf;
+	struct device *dev;
+	int ret;
+
+	epf = ntb->epf;
+	node = epf->node;
+	dev = &epf->dev;
+
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		epc_name = pci_epc_interface_string(type);
+
+		epc = of_pci_epc_get_by_name(node, epc_name);
+		if (IS_ERR(epc)) {
+			if (PTR_ERR(epc) != -EPROBE_DEFER)
+				dev_err(dev, "%s intf: Failed to get EPC\n",
+					epc_name);
+			ret = PTR_ERR(epc);
+			goto err_epc_get;
+		}
+
+		ret = pci_epc_add_epf(epc, epf, type);
+		if (ret) {
+			dev_err(dev, "%s intf: Fail to add EPF to EPC\n",
+				epc_name);
+			goto err_epc_get;
+		}
+
+		ret = epf_ntb_epc_create_interface(ntb, epc, type);
+		if (ret) {
+			dev_err(dev, "%s intf: Fail to create NTB EPC\n",
+				epc_name);
+			goto err_epc_get;
+		}
+	}
+
+	return 0;
+
+err_epc_get:
+	epf_ntb_epc_destroy(ntb);
+
+	return ret;
+}
+
+static int epf_ntb_init_epc_bar_interface(struct epf_ntb *ntb,
+					  enum pci_epc_interface_type type)
+{
+	const struct pci_epc_features *epc_features;
+	struct epf_ntb_epc *ntb_epc;
+	enum pci_barno barno;
+	enum epf_ntb_bar bar;
+	struct device *dev;
+	u32 num_mws;
+	int i;
+
+	barno = BAR_0;
+	ntb_epc = ntb->epc[type];
+	num_mws = ntb->num_mws;
+	dev = &ntb->epf->dev;
+	epc_features = ntb_epc->epc_features;
+
+	/* These are required BARs which are mandatory for NTB functionality */
+	for (bar = BAR_CONFIG; bar <= BAR_DB_MW1; bar++, barno++) {
+		barno = pci_epc_get_next_free_bar(epc_features, barno);
+		if (barno < 0) {
+			dev_err(dev, "%s intf: Fail to get NTB function BAR\n",
+				pci_epc_interface_string(type));
+			return barno;
+		}
+		ntb_epc->epf_ntb_bar[bar] = barno;
+	}
+
+	/* These are optional BARs which doesn't impact NTB functionality */
+	for (bar = BAR_MW2, i = 1; i < num_mws; bar++, barno++, i++) {
+		barno = pci_epc_get_next_free_bar(epc_features, barno);
+		if (barno < 0) {
+			ntb->num_mws = i;
+			dev_dbg(dev, "BAR not available for > MW%d\n", i + 1);
+		}
+		ntb_epc->epf_ntb_bar[bar] = barno;
+	}
+
+	return 0;
+}
+
+static int epf_ntb_init_epc_bar(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct device *dev;
+	int ret;
+
+	dev = &ntb->epf->dev;
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		ret = epf_ntb_init_epc_bar_interface(ntb, type);
+		if (ret) {
+			dev_err(dev, "Fail to init EPC bar for %s interface\n",
+				pci_epc_interface_string(type));
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int epf_ntb_epc_init_interface(struct epf_ntb *ntb,
+				      enum pci_epc_interface_type type)
+{
+	struct epf_ntb_epc *ntb_epc;
+	u8 vfunc_no, func_no;
+	struct pci_epc *epc;
+	struct pci_epf *epf;
+	struct device *dev;
+	int ret;
+
+	ntb_epc = ntb->epc[type];
+	epf = ntb->epf;
+	dev = &epf->dev;
+	epc = ntb_epc->epc;
+	func_no = ntb_epc->func_no;
+	vfunc_no = ntb_epc->vfunc_no;
+
+	ret = epf_ntb_config_sspad_bar_set(ntb->epc[type]);
+	if (ret) {
+		dev_err(dev, "%s intf: Config/self SPAD BAR init failed\n",
+			pci_epc_interface_string(type));
+		return ret;
+	}
+
+	ret = epf_ntb_peer_spad_bar_set(ntb, type);
+	if (ret) {
+		dev_err(dev, "%s intf: Peer SPAD BAR init failed\n",
+			pci_epc_interface_string(type));
+		goto err_peer_spad_bar_init;
+	}
+
+	ret = epf_ntb_configure_interrupt(ntb, type);
+	if (ret) {
+		dev_err(dev, "%s intf: Interrupt configuration failed\n",
+			pci_epc_interface_string(type));
+		goto err_peer_spad_bar_init;
+	}
+
+	ret = epf_ntb_db_mw_bar_init(ntb, type);
+	if (ret) {
+		dev_err(dev, "%s intf: DB/MW BAR init failed\n",
+			pci_epc_interface_string(type));
+		goto err_db_mw_bar_init;
+	}
+
+	ret = pci_epc_write_header(epc, func_no, vfunc_no, epf->header);
+	if (ret) {
+		dev_err(dev, "%s intf: Configuration header write failed\n",
+			pci_epc_interface_string(type));
+		goto err_write_header;
+	}
+
+	INIT_DELAYED_WORK(&ntb->epc[type]->cmd_handler, epf_ntb_cmd_handler);
+	queue_work(kpcintb_workqueue, &ntb->epc[type]->cmd_handler.work);
+
+	return 0;
+
+err_write_header:
+	epf_ntb_db_mw_bar_cleanup(ntb->epc[type], ntb->epc[!type]);
+
+err_db_mw_bar_init:
+	epf_ntb_peer_spad_bar_clear(ntb->epc[type]);
+
+err_peer_spad_bar_init:
+	epf_ntb_config_sspad_bar_clear(ntb->epc[type]);
+
+	return ret;
+}
+
+static void epf_ntb_epc_cleanup(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct epf_ntb_epc *peer_ntb_epc;
+	struct epf_ntb_epc *ntb_epc;
+
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		ntb_epc = ntb->epc[type];
+		peer_ntb_epc = ntb->epc[!type];
+		cancel_delayed_work(&ntb_epc->cmd_handler);
+		epf_ntb_db_mw_bar_cleanup(ntb_epc, peer_ntb_epc);
+		epf_ntb_peer_spad_bar_clear(ntb_epc);
+		epf_ntb_config_sspad_bar_clear(ntb_epc);
+	}
+}
+
+static int epf_ntb_epc_init(struct epf_ntb *ntb)
+{
+	enum pci_epc_interface_type type;
+	struct device *dev;
+	int ret;
+
+	dev = &ntb->epf->dev;
+
+	for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++) {
+		ret = epf_ntb_epc_init_interface(ntb, type);
+		if (ret) {
+			dev_err(dev, "%s intf: Failed to initialize\n",
+				pci_epc_interface_string(type));
+			goto err_init_type;
+		}
+	}
+
+	return 0;
+
+err_init_type:
+	epf_ntb_epc_cleanup(ntb);
+
+	return ret;
+}
+
+static int epf_ntb_of_parse_mw(struct epf_ntb *ntb, struct device_node *node)
+{
+	struct device *dev;
+	u32 *mws_size;
+	u32 num_mws;
+	int ret;
+
+	dev = &ntb->epf->dev;
+	ret = of_property_read_u32(node, "num-mws", &num_mws);
+	if (ret) {
+		dev_err(dev, "Failed to get num-mws dt property\n");
+		return ret;
+	}
+
+	if (num_mws > MAX_MW) {
+		dev_err(dev, "Cannot support more than 4 memory window\n");
+		return ret;
+	}
+
+	mws_size = devm_kzalloc(dev, sizeof(*mws_size) * num_mws, GFP_KERNEL);
+	if (!mws_size)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(node, "mws-size", mws_size,
+					 num_mws);
+	if (ret) {
+		dev_err(dev, "Failed to get mws-size dt property\n");
+		return ret;
+	}
+
+	ntb->num_mws = num_mws;
+	ntb->mws_size = mws_size;
+
+	return 0;
+}
+
+static int pci_epf_ntb_of_parse(struct epf_ntb *ntb)
+{
+	struct device_node *node;
+	struct pci_epf *epf;
+	struct device *dev;
+	int ret;
+
+	epf = ntb->epf;
+	node = epf->node;
+	dev = &epf->dev;
+
+	epf->header = &epf_ntb_header;
+	pci_epc_of_parse_header(node, epf->header);
+
+	ret = epf_ntb_of_parse_mw(ntb, node);
+	if (ret) {
+		dev_err(dev, "Invalid memory window configuration in DT\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pci_epf_ntb_probe(struct pci_epf *epf)
+{
+	struct epf_ntb *ntb;
+	struct device *dev;
+	int ret;
+
+	dev = &epf->dev;
+
+	ntb = devm_kzalloc(dev, sizeof(*ntb), GFP_KERNEL);
+	if (!ntb)
+		return -ENOMEM;
+
+	ntb->epf = epf;
+
+	ret = pci_epf_ntb_of_parse(ntb);
+	if (ret) {
+		dev_err(dev, "Failed to parse NTB DT node\n");
+		return ret;
+	}
+
+	ret = epf_ntb_epc_create(ntb);
+	if (ret) {
+		dev_err(dev, "Failed to create NTB EPC\n");
+		return ret;
+	}
+
+	ret = epf_ntb_init_epc_bar(ntb);
+	if (ret) {
+		dev_err(dev, "Failed to create NTB EPC\n");
+		goto err_bar_init;
+	}
+
+	ret = epf_ntb_config_spad_bar_alloc(ntb);
+	if (ret) {
+		dev_err(dev, "Failed to allocate BAR memory\n");
+		goto err_bar_init;
+	}
+
+	ret = epf_ntb_epc_init(ntb);
+	if (ret) {
+		dev_err(dev, "Failed to initialize EPC\n");
+		goto err_epc_init;
+	}
+
+	epf_set_drvdata(epf, ntb);
+
+	return 0;
+
+err_epc_init:
+	epf_ntb_config_spad_bar_free(ntb);
+
+err_bar_init:
+	epf_ntb_epc_destroy(ntb);
+
+	return ret;
+}
+
+static int pci_epf_ntb_remove(struct pci_epf *epf)
+{
+	struct epf_ntb *ntb = epf_get_drvdata(epf);
+
+	epf_ntb_epc_cleanup(ntb);
+	epf_ntb_config_spad_bar_free(ntb);
+	epf_ntb_epc_destroy(ntb);
+
+	return 0;
+}
+
+static const struct pci_epf_device_id pci_epf_ntb_ids[] = {
+	{
+		.name = "pci-epf-ntb",
+	},
+	{},
+};
+
+static struct pci_epf_driver epf_ntb_driver = {
+	.driver.name	= "pci_epf_ntb",
+	.probe		= pci_epf_ntb_probe,
+	.remove		= pci_epf_ntb_remove,
+	.id_table	= pci_epf_ntb_ids,
+	.owner		= THIS_MODULE,
+};
+
+static int __init pci_epf_ntb_init(void)
+{
+	int ret;
+
+	kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM |
+					    WQ_HIGHPRI, 0);
+	ret = pci_epf_register_driver(&epf_ntb_driver);
+	if (ret) {
+		pr_err("Failed to register pci epf ntb driver --> %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+module_init(pci_epf_ntb_init);
+
+static void __exit pci_epf_ntb_exit(void)
+{
+	pci_epf_unregister_driver(&epf_ntb_driver);
+}
+module_exit(pci_epf_ntb_exit);
+
+MODULE_DESCRIPTION("PCI EPF NTB DRIVER");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1


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

* [RFC PATCH 19/21] PCI: Add TI J721E device to pci ids
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (17 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 18/21] PCI: endpoint: Add EP function driver to provide NTB functionality Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-09-26 11:29 ` [RFC PATCH 20/21] NTB: Add support for EPF PCI-Express Non-Transparent Bridge Kishon Vijay Abraham I
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add TI J721E device to the pci id database. Since this device has
a configurable PCIe endpoint, it could be used with different
drivers.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 include/linux/pci_ids.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d157983b84cf..b2820a834a5e 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -868,6 +868,7 @@
 #define PCI_DEVICE_ID_TI_X620		0xac8d
 #define PCI_DEVICE_ID_TI_X420		0xac8e
 #define PCI_DEVICE_ID_TI_XX20_FM	0xac8f
+#define PCI_DEVICE_ID_TI_J721E		0xb00d
 #define PCI_DEVICE_ID_TI_DRA74x		0xb500
 #define PCI_DEVICE_ID_TI_DRA72x		0xb501
 
-- 
2.17.1


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

* [RFC PATCH 20/21] NTB: Add support for EPF PCI-Express Non-Transparent Bridge
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (18 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 19/21] PCI: Add TI J721E device to pci ids Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-11-17 23:40   ` Jon Mason
  2019-09-26 11:29 ` [RFC PATCH 21/21] NTB: tool: Enable the NTB/PCIe link on the local or remote side of bridge Kishon Vijay Abraham I
  2019-11-17 23:43 ` [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Jon Mason
  21 siblings, 1 reply; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Add support for EPF PCI-Express Non-Transparent Bridge (NTB) device.
This driver is platform independent and could be used by any platform
which have multiple PCIe endpoint instances configured using the
pci-epf-ntb driver. The driver connnects to the standard NTB sub-system
interface. The EPF NTB device has configurable number of memory windows
(Max 4), configurable number of doorbell (Max 32), and configurable
number of scratch-pad registers.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/ntb/hw/Kconfig          |   1 +
 drivers/ntb/hw/Makefile         |   1 +
 drivers/ntb/hw/epf/Kconfig      |   5 +
 drivers/ntb/hw/epf/Makefile     |   1 +
 drivers/ntb/hw/epf/ntb_hw_epf.c | 648 ++++++++++++++++++++++++++++++++
 5 files changed, 656 insertions(+)
 create mode 100644 drivers/ntb/hw/epf/Kconfig
 create mode 100644 drivers/ntb/hw/epf/Makefile
 create mode 100644 drivers/ntb/hw/epf/ntb_hw_epf.c

diff --git a/drivers/ntb/hw/Kconfig b/drivers/ntb/hw/Kconfig
index e51b581fd102..623d43a2bec0 100644
--- a/drivers/ntb/hw/Kconfig
+++ b/drivers/ntb/hw/Kconfig
@@ -1,4 +1,5 @@
 source "drivers/ntb/hw/amd/Kconfig"
 source "drivers/ntb/hw/idt/Kconfig"
 source "drivers/ntb/hw/intel/Kconfig"
+source "drivers/ntb/hw/epf/Kconfig"
 source "drivers/ntb/hw/mscc/Kconfig"
diff --git a/drivers/ntb/hw/Makefile b/drivers/ntb/hw/Makefile
index 923c442db750..48f672ca857a 100644
--- a/drivers/ntb/hw/Makefile
+++ b/drivers/ntb/hw/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_NTB_AMD)	+= amd/
 obj-$(CONFIG_NTB_IDT)	+= idt/
 obj-$(CONFIG_NTB_INTEL)	+= intel/
+obj-$(CONFIG_NTB_EPF)	+= epf/
 obj-$(CONFIG_NTB_SWITCHTEC) += mscc/
diff --git a/drivers/ntb/hw/epf/Kconfig b/drivers/ntb/hw/epf/Kconfig
new file mode 100644
index 000000000000..314485574bf8
--- /dev/null
+++ b/drivers/ntb/hw/epf/Kconfig
@@ -0,0 +1,5 @@
+config NTB_EPF
+	tristate "Generic EPF Non-Transparent Bridge support"
+	help
+	  This driver supports EPF NTB on configurable endpoint.
+	  If unsure, say N.
diff --git a/drivers/ntb/hw/epf/Makefile b/drivers/ntb/hw/epf/Makefile
new file mode 100644
index 000000000000..2f560a422bc6
--- /dev/null
+++ b/drivers/ntb/hw/epf/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_NTB_EPF) += ntb_hw_epf.o
diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c
new file mode 100644
index 000000000000..fba3d88886f2
--- /dev/null
+++ b/drivers/ntb/hw/epf/ntb_hw_epf.c
@@ -0,0 +1,648 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * Host side endpoint driver to implement Non-Transparent Bridge functionality
+ *
+ * Copyright (C) 2019 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/ntb.h>
+
+#define NTB_EPF_COMMAND		0x0
+#define CMD_CONFIGURE_DOORBELL	1
+#define CMD_CONFIGURE_MW	2
+#define CMD_LINK_UP		3
+
+#define NTB_EPF_ARGUMENT	0x4
+
+#define NTB_EPF_STATUS		0x8
+#define COMMAND_STATUS_OK	BIT(0)
+#define LINK_STATUS_UP		BIT(1)
+
+#define NTB_EPF_TOPOLOGY	0xc
+#define NTB_EPF_ADDR		0x10
+#define NTB_EPF_SIZE		0x18
+#define NTB_EPF_MW1_OFFSET	0x1c
+#define NTB_EPF_MW_COUNT	0x20
+#define NTB_EPF_SPAD_OFFSET	0x24
+#define NTB_EPF_SPAD_COUNT	0x28
+#define NTB_EPF_DB_ENTRY_SIZE	0x2c
+#define NTB_EPF_DB_DATA(n)	(0x30 + (n) * 4)
+
+#define NTB_MIN_DB_COUNT	2
+#define NTB_MAX_DB_COUNT	32
+#define NTB_MW_OFFSET		2
+
+enum pci_barno {
+	BAR_0,
+	BAR_1,
+	BAR_2,
+	BAR_3,
+	BAR_4,
+	BAR_5,
+};
+
+struct ntb_epf_dev {
+	struct ntb_dev ntb;
+
+	enum pci_barno ctrl_reg_bar;
+	enum pci_barno peer_spad_reg_bar;
+	enum pci_barno db_reg_bar;
+
+	unsigned int mw_count;
+	unsigned int spad_count;
+	unsigned int db_count;
+
+	void __iomem *ctrl_reg;
+	void __iomem *db_reg;
+	void __iomem *peer_spad_reg;
+
+	unsigned int self_spad;
+	unsigned int peer_spad;
+
+	int db_val;
+	u64 db_valid_mask;
+};
+
+#define ntb_ndev(__ntb) container_of(__ntb, struct ntb_epf_dev, ntb)
+
+struct ntb_epf_data {
+	/* BAR that contains both control region and self spad region */
+	enum pci_barno ctrl_reg_bar;
+	/* BAR that contains peer spad region */
+	enum pci_barno peer_spad_reg_bar;
+	/* BAR that contains Doorbell region and Memory window '1' */
+	enum pci_barno db_reg_bar;
+};
+
+static inline u32 ntb_epf_ctrl_readl(struct ntb_epf_dev *ndev, u32 offset)
+{
+	return readl(ndev->ctrl_reg + offset);
+}
+
+static inline void ntb_epf_ctrl_writel(struct ntb_epf_dev *ndev, u32 offset,
+				       u32 val)
+{
+	return writel(val, ndev->ctrl_reg + offset);
+}
+
+static int ntb_epf_send_command(struct ntb_epf_dev *ndev, u32 command,
+				u32 argument)
+{
+	ktime_t timeout;
+	bool timedout;
+	u32 status;
+
+	ntb_epf_ctrl_writel(ndev, NTB_EPF_ARGUMENT, argument);
+	ntb_epf_ctrl_writel(ndev, NTB_EPF_COMMAND, command);
+
+	/* wait 50ms */
+	timeout = ktime_add_ms(ktime_get(), 50);
+	while (1) {
+		timedout = ktime_after(ktime_get(), timeout);
+		status = ntb_epf_ctrl_readl(ndev, NTB_EPF_STATUS);
+
+		if (status & COMMAND_STATUS_OK)
+			break;
+
+		if (WARN_ON(timedout))
+			return -ETIMEDOUT;
+
+		usleep_range(5, 10);
+	}
+
+	ntb_epf_ctrl_writel(ndev, NTB_EPF_STATUS, status & ~COMMAND_STATUS_OK);
+
+	return 0;
+}
+
+static int ntb_epf_mw_to_bar(struct ntb_epf_dev *ndev, int idx)
+{
+	if (idx < 0 || idx > ndev->mw_count)
+		return -EINVAL;
+
+	return idx + 2;
+}
+
+static int ntb_epf_mw_count(struct ntb_dev *ntb, int pidx)
+{
+	if (pidx != NTB_DEF_PEER_IDX)
+		return -EINVAL;
+
+	return ntb_ndev(ntb)->mw_count;
+}
+
+static int ntb_epf_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
+				resource_size_t *addr_align,
+				resource_size_t *size_align,
+				resource_size_t *size_max)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	int bar;
+
+	if (pidx != NTB_DEF_PEER_IDX)
+		return -EINVAL;
+
+	bar = ntb_epf_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
+
+	if (addr_align)
+		*addr_align = SZ_4K;
+
+	if (size_align)
+		*size_align = 1;
+
+	if (size_max)
+		*size_max = pci_resource_len(ndev->ntb.pdev, bar);
+
+	return 0;
+}
+
+static u64 ntb_epf_link_is_up(struct ntb_dev *ntb,
+			      enum ntb_speed *speed,
+			      enum ntb_width *width)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	u32 status;
+
+	status = ntb_epf_ctrl_readl(ndev, NTB_EPF_STATUS);
+
+	return !!(status & LINK_STATUS_UP);
+}
+
+static u32 ntb_epf_spad_read(struct ntb_dev *ntb, int idx)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return 0;
+
+	offset = ntb_epf_ctrl_readl(ndev, NTB_EPF_SPAD_OFFSET);
+	offset += (idx << 2);
+
+	return ntb_epf_ctrl_readl(ndev, offset);
+}
+
+static int ntb_epf_spad_write(struct ntb_dev *ntb,
+			      int idx, u32 val)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	offset = ntb_epf_ctrl_readl(ndev, NTB_EPF_SPAD_OFFSET);
+	offset += (idx << 2);
+	ntb_epf_ctrl_writel(ndev, offset, val);
+
+	return 0;
+}
+
+static u32 ntb_epf_peer_spad_read(struct ntb_dev *ntb, int pidx, int idx)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	offset = (idx << 2);
+	return readl(ndev->peer_spad_reg + offset);
+}
+
+static int ntb_epf_peer_spad_write(struct ntb_dev *ntb, int pidx,
+				   int idx, u32 val)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	offset = (idx << 2);
+	writel(val, ndev->peer_spad_reg + offset);
+
+	return 0;
+}
+
+static int ntb_epf_link_enable(struct ntb_dev *ntb,
+			       enum ntb_speed max_speed,
+			       enum ntb_width max_width)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	struct device *dev = &ntb->pdev->dev;
+	int ret;
+
+	ret = ntb_epf_send_command(ndev, CMD_LINK_UP, 0);
+	if (ret) {
+		dev_err(dev, "Fail to enable link\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ntb_epf_link_disable(struct ntb_dev *ntb)
+{
+	return 0;
+}
+
+static irqreturn_t ndev_vec_isr(int irq, void *dev)
+{
+	struct ntb_epf_dev *ndev = dev;
+	int irq_no;
+
+	irq_no = irq - ndev->ntb.pdev->irq;
+	ndev->db_val = irq_no + 1;
+
+	if (irq_no == 0)
+		ntb_link_event(&ndev->ntb);
+	else
+		ntb_db_event(&ndev->ntb, irq_no);
+
+	return IRQ_HANDLED;
+}
+
+static int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max)
+{
+	struct pci_dev *pdev = ndev->ntb.pdev;
+	struct device *dev = &pdev->dev;
+	int irq;
+	int ret;
+	int i;
+
+	irq = pci_alloc_irq_vectors(pdev, msi_min, msi_max, PCI_IRQ_MSI);
+	if (irq < 0) {
+		dev_err(dev, "Failed to get MSI interrupts\n");
+		return irq;
+	}
+
+	for (i = 0; i < irq; i++) {
+		ret = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, i),
+				       ndev_vec_isr, IRQF_SHARED, "ntb_epf",
+				       ndev);
+		if (ret) {
+			dev_err(dev, "Failed to request irq\n");
+			goto err_request_irq;
+		}
+	}
+
+	ndev->db_count = irq;
+
+	ret = ntb_epf_send_command(ndev, CMD_CONFIGURE_DOORBELL, irq);
+	if (ret) {
+		dev_err(dev, "Failed to configure doorbell\n");
+		goto err_request_irq;
+	}
+
+	return 0;
+
+err_request_irq:
+	pci_free_irq_vectors(pdev);
+
+	return ret;
+}
+
+static int ntb_epf_peer_mw_count(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->mw_count;
+}
+
+static int ntb_epf_spad_count(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->spad_count;
+}
+
+static u64 ntb_epf_db_valid_mask(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->db_valid_mask;
+}
+
+static int ntb_epf_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	return 0;
+}
+
+static int ntb_epf_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
+				dma_addr_t addr, resource_size_t size)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	struct device *dev = &ntb->pdev->dev;
+	resource_size_t mw_size;
+	int bar;
+
+	if (pidx != NTB_DEF_PEER_IDX)
+		return -EINVAL;
+
+	bar = idx + NTB_MW_OFFSET;
+
+	mw_size = pci_resource_len(ntb->pdev, bar);
+
+	if (size > mw_size) {
+		dev_err(dev, "Size is greater than the MW size\n");
+		return -EINVAL;
+	}
+
+	ntb_epf_ctrl_writel(ndev, NTB_EPF_ADDR, addr);
+	ntb_epf_ctrl_writel(ndev, NTB_EPF_SIZE, size);
+	ntb_epf_send_command(ndev, CMD_CONFIGURE_MW, idx);
+
+	return 0;
+}
+
+static int ntb_epf_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+				    phys_addr_t *base, resource_size_t *size)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	u32 offset = 0;
+	int bar;
+
+	if (idx == 0)
+		offset = ntb_epf_ctrl_readl(ndev, NTB_EPF_MW1_OFFSET);
+
+	bar = idx + NTB_MW_OFFSET;
+
+	if (base)
+		*base = pci_resource_start(ndev->ntb.pdev, bar) + offset;
+
+	if (size)
+		*size = pci_resource_len(ndev->ntb.pdev, bar) - offset;
+
+	return 0;
+}
+
+static int ntb_epf_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+	u32 interrupt_num = ffs(db_bits) + 1;
+	u32 db_entry_size;
+	u32 db_data;
+
+	if (interrupt_num > ndev->db_count)
+		return -EINVAL;
+
+	db_entry_size = ntb_epf_ctrl_readl(ndev, NTB_EPF_DB_ENTRY_SIZE);
+
+	db_data = readl(ndev->ctrl_reg + NTB_EPF_DB_DATA(interrupt_num));
+	writel(db_data, ndev->db_reg + (db_entry_size * interrupt_num));
+
+	return 0;
+}
+
+static u64 ntb_epf_db_read(struct ntb_dev *ntb)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+
+	return ndev->db_val;
+}
+
+static int ntb_epf_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	return 0;
+}
+
+static int ntb_epf_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
+
+	ndev->db_val = 0;
+
+	return 0;
+}
+
+static const struct ntb_dev_ops ntb_epf_ops = {
+	.mw_count		= ntb_epf_mw_count,
+	.spad_count		= ntb_epf_spad_count,
+	.peer_mw_count		= ntb_epf_peer_mw_count,
+	.db_valid_mask		= ntb_epf_db_valid_mask,
+	.db_set_mask		= ntb_epf_db_set_mask,
+	.mw_set_trans		= ntb_epf_mw_set_trans,
+	.peer_mw_get_addr	= ntb_epf_peer_mw_get_addr,
+	.link_enable		= ntb_epf_link_enable,
+	.spad_read		= ntb_epf_spad_read,
+	.spad_write		= ntb_epf_spad_write,
+	.peer_spad_read		= ntb_epf_peer_spad_read,
+	.peer_spad_write	= ntb_epf_peer_spad_write,
+	.peer_db_set		= ntb_epf_peer_db_set,
+	.db_read		= ntb_epf_db_read,
+	.mw_get_align		= ntb_epf_mw_get_align,
+	.link_is_up		= ntb_epf_link_is_up,
+	.db_clear_mask		= ntb_epf_db_clear_mask,
+	.db_clear		= ntb_epf_db_clear,
+	.link_disable		= ntb_epf_link_disable,
+};
+
+static inline void ntb_epf_init_struct(struct ntb_epf_dev *ndev,
+				       struct pci_dev *pdev)
+{
+	ndev->ntb.pdev = pdev;
+	ndev->ntb.topo = NTB_TOPO_NONE;
+	ndev->ntb.ops = &ntb_epf_ops;
+}
+
+static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)
+{
+	struct pci_dev *pdev = ndev->ntb.pdev;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	ret = ntb_epf_init_isr(ndev, NTB_MIN_DB_COUNT, NTB_MAX_DB_COUNT);
+	if (ret) {
+		dev_err(dev, "Failed to init ISR\n");
+		return ret;
+	}
+
+	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
+	ndev->mw_count = ntb_epf_ctrl_readl(ndev, NTB_EPF_MW_COUNT);
+	ndev->spad_count = ntb_epf_ctrl_readl(ndev, NTB_EPF_SPAD_COUNT);
+
+	return 0;
+}
+
+static int ntb_epf_init_pci(struct ntb_epf_dev *ndev,
+			    struct pci_dev *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	pci_set_drvdata(pdev, ndev);
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(dev, "Cannot enable PCI device\n");
+		goto err_pci_enable;
+	}
+
+	ret = pci_request_regions(pdev, "ntb");
+	if (ret) {
+		dev_err(dev, "Cannot obtain PCI resources\n");
+		goto err_pci_regions;
+	}
+
+	pci_set_master(pdev);
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+	if (ret) {
+		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+		if (ret) {
+			dev_err(dev, "Cannot set DMA mask\n");
+			goto err_dma_mask;
+		}
+		dev_warn(&pdev->dev, "Cannot DMA highmem\n");
+	}
+
+	ret = dma_coerce_mask_and_coherent(&ndev->ntb.dev,
+					   dma_get_mask(&pdev->dev));
+	if (ret) {
+		dev_err(dev, "Cannot set DMA mask\n");
+		goto err_dma_mask;
+	}
+
+	ndev->ctrl_reg = pci_iomap(pdev, 0, 0);
+	if (!ndev->ctrl_reg) {
+		ret = -EIO;
+		goto err_dma_mask;
+	}
+
+	ndev->peer_spad_reg = pci_iomap(pdev, 1, 0);
+	if (!ndev->peer_spad_reg) {
+		ret = -EIO;
+		goto err_dma_mask;
+	}
+
+	ndev->db_reg = pci_iomap(pdev, 2, 0);
+	if (!ndev->db_reg) {
+		ret = -EIO;
+		goto err_dma_mask;
+	}
+
+	return 0;
+
+err_dma_mask:
+	pci_clear_master(pdev);
+
+err_pci_regions:
+	pci_disable_device(pdev);
+
+err_pci_enable:
+	pci_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static void ntb_epf_deinit_pci(struct ntb_epf_dev *ndev)
+{
+	struct pci_dev *pdev = ndev->ntb.pdev;
+
+	pci_iounmap(pdev, ndev->ctrl_reg);
+	pci_iounmap(pdev, ndev->peer_spad_reg);
+	pci_iounmap(pdev, ndev->db_reg);
+
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int ntb_epf_pci_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *id)
+{
+	enum pci_barno peer_spad_reg_bar = BAR_1;
+	enum pci_barno ctrl_reg_bar = BAR_0;
+	enum pci_barno db_reg_bar = BAR_2;
+	struct device *dev = &pdev->dev;
+	struct ntb_epf_data *data;
+	struct ntb_epf_dev *ndev;
+	int ret;
+
+	ndev = devm_kzalloc(dev, sizeof(*ndev), GFP_KERNEL);
+	if (!ndev)
+		return -ENOMEM;
+
+	data = (struct ntb_epf_data *)id->driver_data;
+	if (data) {
+		if (data->peer_spad_reg_bar)
+			peer_spad_reg_bar = data->peer_spad_reg_bar;
+		if (data->ctrl_reg_bar)
+			ctrl_reg_bar = data->ctrl_reg_bar;
+		if (data->db_reg_bar)
+			db_reg_bar = data->db_reg_bar;
+	}
+
+	ndev->peer_spad_reg_bar = peer_spad_reg_bar;
+	ndev->ctrl_reg_bar = ctrl_reg_bar;
+	ndev->db_reg_bar = db_reg_bar;
+
+	ntb_epf_init_struct(ndev, pdev);
+
+	ret = ntb_epf_init_pci(ndev, pdev);
+	if (ret) {
+		dev_err(dev, "Failed to init PCI\n");
+		return ret;
+	}
+
+	ret = ntb_epf_init_dev(ndev);
+	if (ret) {
+		dev_err(dev, "Failed to init device\n");
+		goto err_init_dev;
+	}
+
+	ret = ntb_register_device(&ndev->ntb);
+	if (ret) {
+		dev_err(dev, "Failed to register NTB device\n");
+		goto err_register_dev;
+	}
+
+	return 0;
+
+err_register_dev:
+	pci_free_irq_vectors(pdev);
+
+err_init_dev:
+	ntb_epf_deinit_pci(ndev);
+
+	return ret;
+}
+
+static void ntb_epf_pci_remove(struct pci_dev *pdev)
+{
+	struct ntb_epf_dev *ndev = pci_get_drvdata(pdev);
+
+	ntb_unregister_device(&ndev->ntb);
+	pci_free_irq_vectors(pdev);
+	kfree(ndev);
+}
+
+static const struct ntb_epf_data j721e_data = {
+	.ctrl_reg_bar = BAR_0,
+	.peer_spad_reg_bar = BAR_1,
+	.db_reg_bar = BAR_2,
+};
+
+static const struct pci_device_id ntb_epf_pci_tbl[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
+		.driver_data = (kernel_ulong_t)&j721e_data,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, ntb_epf_pci_tbl);
+
+static struct pci_driver ntb_epf_pci_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= ntb_epf_pci_tbl,
+	.probe		= ntb_epf_pci_probe,
+	.remove		= ntb_epf_pci_remove,
+};
+module_pci_driver(ntb_epf_pci_driver);
+
+MODULE_DESCRIPTION("PCI ENDPOINT NTB HOST DRIVER");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1


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

* [RFC PATCH 21/21] NTB: tool: Enable the NTB/PCIe link on the local or remote side of bridge
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (19 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 20/21] NTB: Add support for EPF PCI-Express Non-Transparent Bridge Kishon Vijay Abraham I
@ 2019-09-26 11:29 ` Kishon Vijay Abraham I
  2019-11-17 23:43 ` [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Jon Mason
  21 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-09-26 11:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Jon Mason,
	Dave Jiang, Allen Hubbe, Lorenzo Pieralisi
  Cc: Mark Rutland, kishon, linux-pci, linux-doc, linux-kernel,
	devicetree, linux-ntb

Invoke ntb_link_enable() to enable the NTB/PCIe link on the local
or remote side of the bridge.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/ntb/test/ntb_tool.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index d592c0ffbd19..04138e6a371b 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -1638,6 +1638,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
 
 	tool_setup_dbgfs(tc);
 
+	ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
 	return 0;
 
 err_clear_mws:
-- 
2.17.1


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

* Re: [RFC PATCH 02/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device
  2019-09-26 11:29 ` [RFC PATCH 02/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device Kishon Vijay Abraham I
@ 2019-10-15 18:42   ` Rob Herring
  2019-10-16  4:45     ` Kishon Vijay Abraham I
  0 siblings, 1 reply; 28+ messages in thread
From: Rob Herring @ 2019-10-15 18:42 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Bjorn Helgaas, Jonathan Corbet, Jon Mason, Dave Jiang,
	Allen Hubbe, Lorenzo Pieralisi, Mark Rutland, linux-pci,
	linux-doc, linux-kernel, devicetree, linux-ntb

On Thu, Sep 26, 2019 at 04:59:14PM +0530, Kishon Vijay Abraham I wrote:
> Add device tree bindings for PCI endpoint function device. The
> nodes for PCI endpoint function device should be attached to
> PCI endpoint function bus.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  .../bindings/pci/endpoint/pci-epf.txt         | 28 +++++++++++++++++++
>  1 file changed, 28 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt

This and the previous patch for the bus should be combined and please 
convert to a schema.

> 
> diff --git a/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt b/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
> new file mode 100644
> index 000000000000..f006395fd526
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
> @@ -0,0 +1,28 @@
> +PCI Endpoint Function Device
> +
> +This describes the generic bindings to be used when a device has to be
> +exposed to the remote host over PCIe. The device could be an actual
> +peripheral in the platform or a virtual device created by the software.
> +
> +epcs : phandle to the endpoint controller device
> +epc-names : the names of the endpoint controller device corresponding
> +	    to the EPCs present in the *epcs* phandle

Other than the NTB case, I'd expect the parent device to be the 
controller. Let's make NTB the exception...


> +vendor-id: used to identify device manufacturer
> +device-id: used to identify a particular device
> +baseclass-code: used to classify the type of function the device performs
> +subclass-code: used to identify more specifically the function of the device

Are these codes standard?

Powerpc has "class-code" already...

> +subsys-vendor-id: used to identify vendor of the add-in card or subsystem

Powerpc has "subsystem-vendor-id" already...

> +subsys-id: used to specify an id that is specific to a vendor
> +
> +Example:
> +Following is an example of NTB device exposed to the remote host.
> +
> +ntb {

This is going to need some sort of addressing (which implies 'reg')? If 
not, I don't understand why you have 2 levels.

> +	compatible = "pci-epf-ntb";
> +	epcs = <&pcie0_ep>, <&pcie1_ep>;
> +	epc-names = "primary", "secondary";
> +	vendor-id = /bits/ 16 <0x104c>;
> +	device-id = /bits/ 16 <0xb00d>;

These have a long history in OF and should be 32-bits (yes, we've let 
some cases of 16-bit creep in).

> +	num-mws = <4>;

Doesn't this apply to more than NTB?

Can't you just get the length of 'mws-size'?

> +	mws-size = <0x100000>, <0x100000>, <0x100000>, <0x100000>;

Need to support 64-bit sizes?

> +};
> -- 
> 2.17.1
> 

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

* Re: [RFC PATCH 02/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device
  2019-10-15 18:42   ` Rob Herring
@ 2019-10-16  4:45     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 28+ messages in thread
From: Kishon Vijay Abraham I @ 2019-10-16  4:45 UTC (permalink / raw)
  To: Rob Herring
  Cc: Bjorn Helgaas, Jonathan Corbet, Jon Mason, Dave Jiang,
	Allen Hubbe, Lorenzo Pieralisi, Mark Rutland, linux-pci,
	linux-doc, linux-kernel, devicetree, linux-ntb



On 16/10/19 12:12 AM, Rob Herring wrote:
> On Thu, Sep 26, 2019 at 04:59:14PM +0530, Kishon Vijay Abraham I wrote:
>> Add device tree bindings for PCI endpoint function device. The
>> nodes for PCI endpoint function device should be attached to
>> PCI endpoint function bus.
>>
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>  .../bindings/pci/endpoint/pci-epf.txt         | 28 +++++++++++++++++++
>>  1 file changed, 28 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
> 
> This and the previous patch for the bus should be combined and please 
> convert to a schema.

Sure Rob. Thanks for the review.

-Kishon
> 
>>
>> diff --git a/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt b/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
>> new file mode 100644
>> index 000000000000..f006395fd526
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
>> @@ -0,0 +1,28 @@
>> +PCI Endpoint Function Device
>> +
>> +This describes the generic bindings to be used when a device has to be
>> +exposed to the remote host over PCIe. The device could be an actual
>> +peripheral in the platform or a virtual device created by the software.
>> +
>> +epcs : phandle to the endpoint controller device
>> +epc-names : the names of the endpoint controller device corresponding
>> +	    to the EPCs present in the *epcs* phandle
> 
> Other than the NTB case, I'd expect the parent device to be the 
> controller. Let's make NTB the exception...
> 
> 
>> +vendor-id: used to identify device manufacturer
>> +device-id: used to identify a particular device
>> +baseclass-code: used to classify the type of function the device performs
>> +subclass-code: used to identify more specifically the function of the device
> 
> Are these codes standard?
> 
> Powerpc has "class-code" already...
> 
>> +subsys-vendor-id: used to identify vendor of the add-in card or subsystem
> 
> Powerpc has "subsystem-vendor-id" already...
> 
>> +subsys-id: used to specify an id that is specific to a vendor
>> +
>> +Example:
>> +Following is an example of NTB device exposed to the remote host.
>> +
>> +ntb {
> 
> This is going to need some sort of addressing (which implies 'reg')? If 
> not, I don't understand why you have 2 levels.
> 
>> +	compatible = "pci-epf-ntb";
>> +	epcs = <&pcie0_ep>, <&pcie1_ep>;
>> +	epc-names = "primary", "secondary";
>> +	vendor-id = /bits/ 16 <0x104c>;
>> +	device-id = /bits/ 16 <0xb00d>;
> 
> These have a long history in OF and should be 32-bits (yes, we've let 
> some cases of 16-bit creep in).
> 
>> +	num-mws = <4>;
> 
> Doesn't this apply to more than NTB?
> 
> Can't you just get the length of 'mws-size'?
> 
>> +	mws-size = <0x100000>, <0x100000>, <0x100000>, <0x100000>;
> 
> Need to support 64-bit sizes?
> 
>> +};
>> -- 
>> 2.17.1
>>

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

* Re: [RFC PATCH 04/21] Documentation: PCI: Add specification for the *PCI NTB* function device
  2019-09-26 11:29 ` [RFC PATCH 04/21] Documentation: PCI: Add specification for the *PCI NTB* function device Kishon Vijay Abraham I
@ 2019-11-17 23:26   ` Jon Mason
  0 siblings, 0 replies; 28+ messages in thread
From: Jon Mason @ 2019-11-17 23:26 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Dave Jiang,
	Allen Hubbe, Lorenzo Pieralisi, Mark Rutland, linux-pci,
	linux-doc, linux-kernel, devicetree, linux-ntb

On Thu, Sep 26, 2019 at 7:30 AM 'Kishon Vijay Abraham I' via linux-ntb
<linux-ntb@googlegroups.com> wrote:
>
> Add specification for the *PCI NTB* function device. The endpoint function
> driver and the host PCI driver should be created based on this
> specification.
>
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  Documentation/PCI/endpoint/pci-test-ntb.txt | 315 ++++++++++++++++++++
>  1 file changed, 315 insertions(+)
>  create mode 100644 Documentation/PCI/endpoint/pci-test-ntb.txt
>
> diff --git a/Documentation/PCI/endpoint/pci-test-ntb.txt b/Documentation/PCI/endpoint/pci-test-ntb.txt
> new file mode 100644
> index 000000000000..c8bfe9dbfd8b
> --- /dev/null
> +++ b/Documentation/PCI/endpoint/pci-test-ntb.txt
> @@ -0,0 +1,315 @@
> +                              PCI NTB FUNCTION
> +                   Kishon Vijay Abraham I <kishon@ti.com>
> +
> +PCI NTB Function allows two different systems (or hosts) to communicate
> +with each other by configurig the endpoint instances in such a way that
> +transactions from one system is routed to the other system.
> +
> +In the below diagram, PCI NTB function configures the SoC with multiple
> +PCIe Endpoint (EP) instances in such a way that transaction from one EP
> +controller is routed to the other EP controller. Once PCI NTB function
> +configures the SoC with multiple EP instances, HOST1 and HOST2 can
> +communicate with each other using SoC as a bridge.
> +
> +   +-------------+                                   +-------------+
> +   |             |                                   |             |
> +   |    HOST1    |                                   |    HOST2    |
> +   |             |                                   |             |
> +   +------^------+                                   +------^------+
> +          |                                                 |
> +          |                                                 |
> ++---------|-------------------------------------------------|---------+
> +|  +------v------+                                   +------v------+  |
> +|  |             |                                   |             |  |
> +|  |     EP      |                                   |     EP      |  |
> +|  | CONTROLLER1 |                                   | CONTROLLER2 |  |
> +|  |             <----------------------------------->             |  |
> +|  |             |                                   |             |  |
> +|  |             |                                   |             |  |
> +|  |             |  SoC With Multiple EP Instances   |             |  |
> +|  |             |  (Configured using NTB Function)  |             |  |
> +|  +-------------+                                   +-------------+  |
> ++---------------------------------------------------------------------+
> +
> +Constructs used for Implementing NTB:
> +
> +       *) Config Region
> +       *) Self Scratchpad Registers
> +       *) Peer Scratchpad Registers
> +       *) Doorbell Registers
> +       *) Memory Window
> +
> +Modeling Constructs:
> +
> +  There are 5 or more distinct regions (config, self scratchpad, peer
> +scratchpad, doorbell, one or more memory windows) to be modeled to achieve
> +NTB functionality. Atleast one memory window is required while more than
> +one is permitted. All these regions should be mapped to BAR for hosts to
> +access these regions.
> +
> +If one 32-bit BAR is allocated for each of these regions, the scheme would
> +look like
> +       BAR0 -> Config Region
> +       BAR1 -> Self Scratchpad
> +       BAR2 -> Peer Scratchpad
> +       BAR3 -> Doorbell
> +       BAR4 -> Memory Window 1
> +       BAR5 -> Memory Window 2
> +
> +However if we allocate a separate BAR for each of the region, there would not
> +be enough BARs for all the regions in a platform that supports only 64-bit
> +BAR.
> +
> +In order to be be supported by most of the platforms, the regions should be
> +packed and mapped to BARs in a way that provides NTB functionality and
> +also making sure the hosts doesn't access any region that it is not supposed
> +to.
> +
> +The following scheme is used in EPF NTB Function
> +
> +       BAR0 -> Config Region + Self Scratchpad
> +       BAR1 -> Peer Scratchpad
> +       BAR2 -> Doorbell + Memory Window 1
> +       BAR3 -> Memory Window 2
> +       BAR4 -> Memory Window 3
> +       BAR4 -> Memory Window 4
> +
> +With this scheme, for the basic NTB functionality 3 BARs should be sufficient.
> +
> +Modeling Config/Scratchpad Region:
> +
> ++-----------------+------->+------------------+        +-----------------+
> +|       BAR0      |        |  CONFIG REGION   |        |       BAR0      |
> ++-----------------+----+   +------------------+<-------+-----------------+
> +|       BAR1      |    |   |SCRATCHPAD REGION |        |       BAR1      |
> ++-----------------+    +-->+------------------+<-------+-----------------+
> +|       BAR2      |            Local Memory            |       BAR2      |
> ++-----------------+                                    +-----------------+
> +|       BAR3      |                                    |       BAR3      |
> ++-----------------+                                    +-----------------+
> +|       BAR4      |                                    |       BAR4      |
> ++-----------------+                                    +-----------------+
> +|       BAR5      |                                    |       BAR5      |
> ++-----------------+                                    +-----------------+
> +  EP CONTROLLER 1                                        EP CONTROLLER 2
> +
> +Above diagram shows Config region + Scratchpad region for HOST1 (connected to
> +EP controller 1) allocated in local memory. The HOST1 can access the config
> +region and scratchpad region (self scratchpad) using BAR0 of EP controller 1.
> +The peer host (HOST2 connected to EP controller 2) can also access this
> +scratchpad region (peer scratchpad) using BAR1 of EP controller 2. This
> +diagram shows the case where Config region and Scratchpad region is allocated
> +for HOST1, however the same is applicable for HOST2.
> +
> +Modeling Doorbell/Memory Window 1:
> +
> ++-----------------+    +----->+----------------+-----------+-----------------+
> +|       BAR0      |    |      |   Doorbell 1   +-----------> MSI|X ADDRESS 1 |
> ++-----------------+    |      +----------------+           +-----------------+
> +|       BAR1      |    |      |   Doorbell 2   +---------+ |                 |
> ++-----------------+    |      +----------------+         | |                 |
> +|       BAR2      |    |      |   Doorbell 3   +-------+ | +-----------------+
> ++-----------------+    |      +----------------+       | +-> MSI|X ADDRESS 2 |
> +|       BAR3      |    |      |   Doorbell 4   +-----+ |   +-----------------+
> ++----------------------+      +----------------+     | |   |                 |
> +|       BAR4      |           |                |     | |   +-----------------+
> ++----------------------+      |      MW1       +---+ | +-->+ MSI|X ADDRESS 3||
> +|       BAR5      |    |      |                |   | |     +-----------------+
> ++-----------------+    +----->-----------------+   | |     |                 |
> +  EP CONTROLLER 1             |                |   | |     +-----------------+
> +                              |                |   | +---->+ MSI|X ADDRESS 4 |
> +                              +----------------+   |       +-----------------+
> +                               EP CONTROLLER 2     |       |                 |
> +                                 (OB SPACE)        |       |                 |
> +                                                   +------->      MW1        |
> +                                                           |                 |
> +                                                           |                 |
> +                                                           +-----------------+
> +                                                           |                 |
> +                                                           |                 |
> +                                                           |                 |
> +                                                           |                 |
> +                                                           |                 |
> +                                                           +-----------------+
> +                                                           PCI Address Space
> +                                                           (Managed by HOST2)
> +
> +Above diagram shows how the doorbell and memory window 1 is mapped so that
> +HOST1 can raise doorbell interrupt on HOST2 and also how HOST1 can access
> +buffers exposed by HOST2 using memory window1 (MW1). Here doorbell and
> +memory window 1 regions are allocated in EP controller 2 outbound (OB) address
> +space. Allocating and configuring BARs for doorbell and memory window1
> +is done during the initialization phase of NTB endpoint function driver.
> +Mapping from EP controller 2 OB space to PCI address space is done when HOST2
> +sends CMD_CONFIGURE_MW/CMD_CONFIGURE_DOORBELL. The commands are explained
> +below.
> +
> +Modeling Optional Memory Windows:
> +
> +This is modeled the same was as MW1 but each of the additional memory windows
> +is mapped to separate BARs.
> +
> +Config Region:
> +
> +Config Region is a construct that is specific to NTB implemented using NTB
> +Endpoint Function Driver. The host and endpoint side NTB function driver will
> +exchange informatio with each other using this region. Config Region has

s/informatio/information

> +Control/Status Registers for configuring the Endpoint Controller. Host can
> +write into this region for configuring the outbound ATU and to indicate the
> +link status. Endpoint can indicate the status of commands issued be host in
> +this region. Endpoint can also indicate the scratchpad offset, number of
> +memory windows to the host using this region.
> +
> +The format of Config Region is given below. Each of the fields here are 32
> +bits.
> +
> +       +------------------------+
> +       |         COMMAND        |
> +       +------------------------+
> +       |         ARGUMENT       |
> +       +------------------------+
> +       |         STATUS         |
> +       +------------------------+
> +       |         TOPOLOGY       |
> +       +------------------------+
> +       |    ADDRESS (LOWER 32)  |
> +       +------------------------+
> +       |    ADDRESS (UPPER 32)  |
> +       +------------------------+
> +       |           SIZE         |
> +       +------------------------+
> +       |  MEMORY WINDOW1 OFFSET |
> +       +------------------------+
> +       |   NO OF MEMORY WINDOW  |
> +       +------------------------+
> +       |       SPAD OFFSET      |
> +       +------------------------+
> +       |        SPAD COUNT      |
> +       +------------------------+
> +       |      DB ENTRY SIZE     |
> +       +------------------------+
> +       |         DB DATA        |
> +       +------------------------+
> +       |            :           |
> +       +------------------------+
> +       |            :           |
> +       +------------------------+
> +       |         DB DATA        |
> +       +------------------------+

The number should probably come before the MW1 offset.  Also, this
assumes that they are all contiguous and of the same size.  Optimally,
there should be a tuple for each MW with the start and size, and you
could parse this with the num of mw you mention above to find out
where the SPAD information starts.  Worst case, I think you might be
able to get away with them all being the same size, but you'll need to
say what size that is in another field.

Thanks,
Jon

> +
> +
> +  COMMAND:
> +
> +       NTB function supports three commands:
> +
> +         CMD_CONFIGURE_DOORBELL (0x1): Command to configure doorbell. Before
> +       invoking this command, the host should allocate and initialize
> +       MSI/MSI-X vectors (i.e initialize the MSI/MSI-X capability in the
> +       Endpoint). The endpoint on receiving this command will configure
> +       the outbound ATU such that transaction to DB BAR will be routed
> +       to the MSI/MSI-X address programmed by the host. The ARGUMENT
> +       register should be populated with number of DBs to configure (in the
> +       lower 16 bits) and if MSI or MSI-X should be configured (BIT 16).
> +       (TODO: Add support for MSI-X).
> +
> +         CMD_CONFIGURE_MW (0x2): Command to configure memory window. The
> +       host invokes this command after allocating a buffer that can be
> +       accessed by remote host. The allocated address should be programmed
> +       in the ADDRESS register (64 bit), the size should be programmed in
> +       the SIZE register and the memory window index should be programmed
> +       in the ARGUMENT register. The endpoint on receiving this command
> +       will configure the outbound ATU such that trasaction to MW BAR
> +       will be routed to the address provided by the host.
> +
> +         CMD_LINK_UP (0x3): Command to indicate an NTB application is
> +       bound to the EP device on the host side. Once the endpoint
> +       receives this command from both the hosts, the endpoint will
> +       raise an LINK_UP event to both the hosts to indicate the hosts
> +       can start communicating with each other.
> +
> +  ARGUMENT:
> +
> +       The value of this register is based on the commands issued in
> +       command register. See COMMAND section for more information.
> +
> +  configuring memory window and to indicate the host side NTB application
> +  has initialized.
> +
> +  TOPOLOGY:
> +
> +       Set to NTB_TOPO_B2B_USD for Primary interface
> +       Set to NTB_TOPO_B2B_DSD for Secondary interface
> +
> +  ADDRESS/SIZE:
> +
> +       Address and Size to be used while configuring the memory window.
> +       See "CMD_CONFIGURE_MW" for more info.
> +
> +  MEMORY WINDOW1 OFFSET:
> +
> +       Memory Window 1 and Doorbell registers are packed together in the
> +       same BAR. The initial portion of the region will have doorbell
> +       registers and the latter portion of the region is for memory window 1.
> +       This register will specify the offset of the memory window 1.
> +
> +  NO OF MEMORY WINDOW:
> +
> +       Specifies the number of memory windows supported by the NTB device.
> +
> +  SPAD OFFSET:
> +
> +       Self scratchpad region and config region are packed together in the
> +       same BAR. The initial portion of the will have config region and
> +       the latter portion of the region is for self scratchpad. This
> +       register will specify the offset of the self scratchpad registers.
> +
> +  SPAD COUNT:
> +
> +       Specifies the number of scratchpad registers supported by the NTB
> +       device.
> +
> +  DB ENTRY SIZE:
> +
> +       Used to determine the offset within the DB BAR that should be written
> +       in order to raise doorbell. EPF NTB can use either MSI/MSI-X to
> +       ring doorbell (MSI-X support will be added later). MSI uses same
> +       address for all the interrupts and MSI-X can provide different
> +       addresses for different interrupts. The MSI/MSI-X address is provided
> +       by the host and the address it gives is based on the MSI/MSI-X
> +       implementation supported by the host. For instance, ARM platform
> +       using GIC ITS will have same MSI-X address for all the interrupts.
> +       In order to support all the combinations and use the same mechanism
> +       for both MSI and MSI-X, EPF NTB allocates separate region in the
> +       Outbound Address Space for each of the interrupts. This region will
> +       be mapped to the MSI/MSI-X address provided by the host. If a host
> +       provides the same address for all the interrupts, all the regions
> +       will be translated to the same address. If a host provides different
> +       address, the regions will be translated to different address. This
> +       will ensure there is no difference while raising the doorbell.
> +
> +  DB DATA:
> +
> +       EPF NTB supports 32 interrupts. So there are 32 DB DATA registers.
> +       This holds the MSI/MSI-X data that has to be written to MSI address
> +       for raising doorbell interrupt. This will be populated by EPF NTB
> +       while invoking CMD_CONFIGURE_MW.
> +
> +Scratchpad Registers:
> +
> +  Each host has it's own register space allocated in the memory of NTB EPC.
> +  They are both readable and writable from both sides of the bridge. They
> +  are used by applications built over NTB and can be used to pass control
> +  and status information between both sides of a device.
> +
> +  Scratchpad registers has 2 parts
> +       1) Self Scratchpad: Host's own register space
> +       2) Peer Scratchpad: Remote host's register space.
> +
> +Doorbell Registers:
> +
> +  Registers using which one host can interrupt the other host.
> +
> +Memory Window:
> +
> +  Actual transfer of data between the two hosts will happen using the
> +  memory window.
> --
> 2.17.1
>
> --
> You received this message because you are subscribed to the Google Groups "linux-ntb" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-ntb+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/linux-ntb/20190926112933.8922-5-kishon%40ti.com.

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

* Re: [RFC PATCH 05/21] PCI: endpoint: Add API to get reference to EPC from device-tree
  2019-09-26 11:29 ` [RFC PATCH 05/21] PCI: endpoint: Add API to get reference to EPC from device-tree Kishon Vijay Abraham I
@ 2019-11-17 23:28   ` Jon Mason
  0 siblings, 0 replies; 28+ messages in thread
From: Jon Mason @ 2019-11-17 23:28 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Dave Jiang,
	Allen Hubbe, Lorenzo Pieralisi, Mark Rutland, linux-pci,
	linux-doc, linux-kernel, devicetree, linux-ntb

On Thu, Sep 26, 2019 at 7:31 AM 'Kishon Vijay Abraham I' via linux-ntb
<linux-ntb@googlegroups.com> wrote:
>
> Add of_pci_epc_get() and of_pci_epc_get_by_name() to get reference
> to EPC from device-tree. This is added in preparation to define
> an endpoint function from device tree.

I can't get this patch to apply cleanly to my git tree (for the
current or any of the previous kernels I tried).  Please rebase this
series when you send it out as a patch.

Thanks,
Jon


> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/pci/endpoint/pci-epc-core.c | 61 +++++++++++++++++++++++++++++
>  include/linux/pci-epc.h             |  4 +-
>  2 files changed, 64 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> index 5bc094093a47..0c2fdd39090c 100644
> --- a/drivers/pci/endpoint/pci-epc-core.c
> +++ b/drivers/pci/endpoint/pci-epc-core.c
> @@ -83,6 +83,66 @@ struct pci_epc *pci_epc_get(const char *epc_name)
>  }
>  EXPORT_SYMBOL_GPL(pci_epc_get);
>
> +/**
> + * of_pci_epc_get() - get PCI endpoint controller from device node and index
> + * @node: device node which contains the phandle to endpoint controller
> + * @index: index of the endpoint controller in "epcs" property
> + *
> + * Returns the EPC corresponding to the _index_ entry in "epcs" property
> + * present in device node, after getting a refcount  to it or -ENODEV if
> + * there is no such EPC or -EPROBE_DEFER if there is a phandle to the phy,
> + * but the device is not yet loaded.
> + */
> +struct pci_epc *of_pci_epc_get(struct device_node *node, int index)
> +{
> +       struct device_node *epc_node;
> +       struct class_dev_iter iter;
> +       struct pci_epc *epc;
> +       struct device *dev;
> +
> +       epc_node = of_parse_phandle(node, "epcs", index);
> +       if (!epc_node)
> +               return ERR_PTR(-ENODEV);
> +
> +       class_dev_iter_init(&iter, pci_epc_class, NULL, NULL);
> +       while ((dev = class_dev_iter_next(&iter))) {
> +               epc = to_pci_epc(dev);
> +               if (epc_node != epc->dev.of_node)
> +                       continue;
> +
> +               of_node_put(epc_node);
> +               class_dev_iter_exit(&iter);
> +               get_device(&epc->dev);
> +               return epc;
> +       }
> +
> +       of_node_put(node);
> +       class_dev_iter_exit(&iter);
> +       return ERR_PTR(-EPROBE_DEFER);
> +}
> +EXPORT_SYMBOL_GPL(of_pci_epc_get);
> +
> +/**
> + * of_pci_epc_get_by_name() - get PCI endpoint controller from device node
> + *                            and string
> + * @node: device node which contains the phandle to endpoint controller
> + * @epc_name: name of endpoint controller as present in "epc-names" property
> + *
> + * Returns the EPC corresponding to the epc_name in "epc-names" property
> + * present in device node.
> + */
> +struct pci_epc *of_pci_epc_get_by_name(struct device_node *node,
> +                                      const char *epc_name)
> +{
> +       int index = 0;
> +
> +       if (epc_name)
> +               index = of_property_match_string(node, "epc-names", epc_name);
> +
> +       return of_pci_epc_get(node, index);
> +}
> +EXPORT_SYMBOL_GPL(of_pci_epc_get_by_name);
> +
>  /**
>   * pci_epc_get_first_free_bar() - helper to get first unreserved BAR
>   * @epc_features: pci_epc_features structure that holds the reserved bar bitmap
> @@ -661,6 +721,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
>         device_initialize(&epc->dev);
>         epc->dev.class = pci_epc_class;
>         epc->dev.parent = dev;
> +       epc->dev.of_node = dev->of_node;
>         epc->ops = ops;
>
>         ret = dev_set_name(&epc->dev, "%s", dev_name(dev));
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index 0fff52675a6b..ef6531af6ed2 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -202,7 +202,9 @@ unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
>                                         *epc_features);
>  struct pci_epc *pci_epc_get(const char *epc_name);
>  void pci_epc_put(struct pci_epc *epc);
> -
> +struct pci_epc *of_pci_epc_get(struct device_node *node, int index);
> +struct pci_epc *of_pci_epc_get_by_name(struct device_node *node,
> +                                      const char *epc_name);
>  int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size,
>                        size_t page_size);
>  void pci_epc_mem_exit(struct pci_epc *epc);
> --
> 2.17.1
>
> --
> You received this message because you are subscribed to the Google Groups "linux-ntb" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-ntb+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/linux-ntb/20190926112933.8922-6-kishon%40ti.com.

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

* Re: [RFC PATCH 20/21] NTB: Add support for EPF PCI-Express Non-Transparent Bridge
  2019-09-26 11:29 ` [RFC PATCH 20/21] NTB: Add support for EPF PCI-Express Non-Transparent Bridge Kishon Vijay Abraham I
@ 2019-11-17 23:40   ` Jon Mason
  0 siblings, 0 replies; 28+ messages in thread
From: Jon Mason @ 2019-11-17 23:40 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Dave Jiang,
	Allen Hubbe, Lorenzo Pieralisi, Mark Rutland, linux-pci,
	linux-doc, linux-kernel, devicetree, linux-ntb

On Thu, Sep 26, 2019 at 7:32 AM 'Kishon Vijay Abraham I' via linux-ntb
<linux-ntb@googlegroups.com> wrote:
>
> Add support for EPF PCI-Express Non-Transparent Bridge (NTB) device.
> This driver is platform independent and could be used by any platform
> which have multiple PCIe endpoint instances configured using the
> pci-epf-ntb driver. The driver connnects to the standard NTB sub-system
> interface. The EPF NTB device has configurable number of memory windows
> (Max 4), configurable number of doorbell (Max 32), and configurable
> number of scratch-pad registers.
>
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/ntb/hw/Kconfig          |   1 +
>  drivers/ntb/hw/Makefile         |   1 +
>  drivers/ntb/hw/epf/Kconfig      |   5 +
>  drivers/ntb/hw/epf/Makefile     |   1 +
>  drivers/ntb/hw/epf/ntb_hw_epf.c | 648 ++++++++++++++++++++++++++++++++
>  5 files changed, 656 insertions(+)
>  create mode 100644 drivers/ntb/hw/epf/Kconfig
>  create mode 100644 drivers/ntb/hw/epf/Makefile
>  create mode 100644 drivers/ntb/hw/epf/ntb_hw_epf.c
>
> diff --git a/drivers/ntb/hw/Kconfig b/drivers/ntb/hw/Kconfig
> index e51b581fd102..623d43a2bec0 100644
> --- a/drivers/ntb/hw/Kconfig
> +++ b/drivers/ntb/hw/Kconfig
> @@ -1,4 +1,5 @@
>  source "drivers/ntb/hw/amd/Kconfig"
>  source "drivers/ntb/hw/idt/Kconfig"
>  source "drivers/ntb/hw/intel/Kconfig"
> +source "drivers/ntb/hw/epf/Kconfig"
>  source "drivers/ntb/hw/mscc/Kconfig"
> diff --git a/drivers/ntb/hw/Makefile b/drivers/ntb/hw/Makefile
> index 923c442db750..48f672ca857a 100644
> --- a/drivers/ntb/hw/Makefile
> +++ b/drivers/ntb/hw/Makefile
> @@ -1,4 +1,5 @@
>  obj-$(CONFIG_NTB_AMD)  += amd/
>  obj-$(CONFIG_NTB_IDT)  += idt/
>  obj-$(CONFIG_NTB_INTEL)        += intel/
> +obj-$(CONFIG_NTB_EPF)  += epf/
>  obj-$(CONFIG_NTB_SWITCHTEC) += mscc/
> diff --git a/drivers/ntb/hw/epf/Kconfig b/drivers/ntb/hw/epf/Kconfig
> new file mode 100644
> index 000000000000..314485574bf8
> --- /dev/null
> +++ b/drivers/ntb/hw/epf/Kconfig
> @@ -0,0 +1,5 @@
> +config NTB_EPF
> +       tristate "Generic EPF Non-Transparent Bridge support"
> +       help
> +         This driver supports EPF NTB on configurable endpoint.
> +         If unsure, say N.
> diff --git a/drivers/ntb/hw/epf/Makefile b/drivers/ntb/hw/epf/Makefile
> new file mode 100644
> index 000000000000..2f560a422bc6
> --- /dev/null
> +++ b/drivers/ntb/hw/epf/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_NTB_EPF) += ntb_hw_epf.o
> diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c
> new file mode 100644
> index 000000000000..fba3d88886f2
> --- /dev/null
> +++ b/drivers/ntb/hw/epf/ntb_hw_epf.c
> @@ -0,0 +1,648 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/**
> + * Host side endpoint driver to implement Non-Transparent Bridge functionality
> + *
> + * Copyright (C) 2019 Texas Instruments
> + * Author: Kishon Vijay Abraham I <kishon@ti.com>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/ntb.h>
> +
> +#define NTB_EPF_COMMAND                0x0
> +#define CMD_CONFIGURE_DOORBELL 1
> +#define CMD_CONFIGURE_MW       2
> +#define CMD_LINK_UP            3
> +
> +#define NTB_EPF_ARGUMENT       0x4
> +
> +#define NTB_EPF_STATUS         0x8
> +#define COMMAND_STATUS_OK      BIT(0)
> +#define LINK_STATUS_UP         BIT(1)
> +
> +#define NTB_EPF_TOPOLOGY       0xc
> +#define NTB_EPF_ADDR           0x10
> +#define NTB_EPF_SIZE           0x18
> +#define NTB_EPF_MW1_OFFSET     0x1c
> +#define NTB_EPF_MW_COUNT       0x20
> +#define NTB_EPF_SPAD_OFFSET    0x24
> +#define NTB_EPF_SPAD_COUNT     0x28
> +#define NTB_EPF_DB_ENTRY_SIZE  0x2c
> +#define NTB_EPF_DB_DATA(n)     (0x30 + (n) * 4)
> +
> +#define NTB_MIN_DB_COUNT       2
> +#define NTB_MAX_DB_COUNT       32
> +#define NTB_MW_OFFSET          2
> +
> +enum pci_barno {
> +       BAR_0,
> +       BAR_1,
> +       BAR_2,
> +       BAR_3,
> +       BAR_4,
> +       BAR_5,
> +};
> +
> +struct ntb_epf_dev {
> +       struct ntb_dev ntb;
> +
> +       enum pci_barno ctrl_reg_bar;
> +       enum pci_barno peer_spad_reg_bar;
> +       enum pci_barno db_reg_bar;
> +
> +       unsigned int mw_count;
> +       unsigned int spad_count;
> +       unsigned int db_count;
> +
> +       void __iomem *ctrl_reg;
> +       void __iomem *db_reg;
> +       void __iomem *peer_spad_reg;
> +
> +       unsigned int self_spad;
> +       unsigned int peer_spad;
> +
> +       int db_val;
> +       u64 db_valid_mask;
> +};
> +
> +#define ntb_ndev(__ntb) container_of(__ntb, struct ntb_epf_dev, ntb)
> +
> +struct ntb_epf_data {
> +       /* BAR that contains both control region and self spad region */
> +       enum pci_barno ctrl_reg_bar;
> +       /* BAR that contains peer spad region */
> +       enum pci_barno peer_spad_reg_bar;
> +       /* BAR that contains Doorbell region and Memory window '1' */
> +       enum pci_barno db_reg_bar;
> +};
> +
> +static inline u32 ntb_epf_ctrl_readl(struct ntb_epf_dev *ndev, u32 offset)
> +{
> +       return readl(ndev->ctrl_reg + offset);
> +}
> +
> +static inline void ntb_epf_ctrl_writel(struct ntb_epf_dev *ndev, u32 offset,
> +                                      u32 val)
> +{
> +       return writel(val, ndev->ctrl_reg + offset);
> +}

Please no wrappers that hide standard functions.

> +
> +static int ntb_epf_send_command(struct ntb_epf_dev *ndev, u32 command,
> +                               u32 argument)
> +{
> +       ktime_t timeout;
> +       bool timedout;
> +       u32 status;
> +
> +       ntb_epf_ctrl_writel(ndev, NTB_EPF_ARGUMENT, argument);
> +       ntb_epf_ctrl_writel(ndev, NTB_EPF_COMMAND, command);
> +
> +       /* wait 50ms */
> +       timeout = ktime_add_ms(ktime_get(), 50);

Why 50?  Seems arbitrary, and like a good thing to be a #define

> +       while (1) {
> +               timedout = ktime_after(ktime_get(), timeout);
> +               status = ntb_epf_ctrl_readl(ndev, NTB_EPF_STATUS);
> +
> +               if (status & COMMAND_STATUS_OK)
> +                       break;
> +
> +               if (WARN_ON(timedout))
> +                       return -ETIMEDOUT;
> +
> +               usleep_range(5, 10);
> +       }
> +
> +       ntb_epf_ctrl_writel(ndev, NTB_EPF_STATUS, status & ~COMMAND_STATUS_OK);
> +
> +       return 0;
> +}
> +
> +static int ntb_epf_mw_to_bar(struct ntb_epf_dev *ndev, int idx)
> +{
> +       if (idx < 0 || idx > ndev->mw_count)
> +               return -EINVAL;
> +
> +       return idx + 2;
> +}
> +
> +static int ntb_epf_mw_count(struct ntb_dev *ntb, int pidx)
> +{
> +       if (pidx != NTB_DEF_PEER_IDX)
> +               return -EINVAL;
> +
> +       return ntb_ndev(ntb)->mw_count;
> +}
> +
> +static int ntb_epf_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
> +                               resource_size_t *addr_align,
> +                               resource_size_t *size_align,
> +                               resource_size_t *size_max)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       int bar;
> +
> +       if (pidx != NTB_DEF_PEER_IDX)
> +               return -EINVAL;
> +
> +       bar = ntb_epf_mw_to_bar(ndev, idx);
> +       if (bar < 0)
> +               return bar;
> +
> +       if (addr_align)
> +               *addr_align = SZ_4K;
> +
> +       if (size_align)
> +               *size_align = 1;
> +
> +       if (size_max)
> +               *size_max = pci_resource_len(ndev->ntb.pdev, bar);
> +
> +       return 0;
> +}
> +
> +static u64 ntb_epf_link_is_up(struct ntb_dev *ntb,
> +                             enum ntb_speed *speed,
> +                             enum ntb_width *width)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       u32 status;
> +
> +       status = ntb_epf_ctrl_readl(ndev, NTB_EPF_STATUS);
> +
> +       return !!(status & LINK_STATUS_UP);
> +}
> +
> +static u32 ntb_epf_spad_read(struct ntb_dev *ntb, int idx)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       u32 offset;
> +
> +       if (idx < 0 || idx >= ndev->spad_count)
> +               return 0;
> +
> +       offset = ntb_epf_ctrl_readl(ndev, NTB_EPF_SPAD_OFFSET);
> +       offset += (idx << 2);
> +
> +       return ntb_epf_ctrl_readl(ndev, offset);
> +}
> +
> +static int ntb_epf_spad_write(struct ntb_dev *ntb,
> +                             int idx, u32 val)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       u32 offset;
> +
> +       if (idx < 0 || idx >= ndev->spad_count)
> +               return -EINVAL;
> +
> +       offset = ntb_epf_ctrl_readl(ndev, NTB_EPF_SPAD_OFFSET);
> +       offset += (idx << 2);
> +       ntb_epf_ctrl_writel(ndev, offset, val);
> +
> +       return 0;
> +}
> +
> +static u32 ntb_epf_peer_spad_read(struct ntb_dev *ntb, int pidx, int idx)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       u32 offset;
> +
> +       if (idx < 0 || idx >= ndev->spad_count)
> +               return -EINVAL;
> +
> +       offset = (idx << 2);
> +       return readl(ndev->peer_spad_reg + offset);
> +}
> +
> +static int ntb_epf_peer_spad_write(struct ntb_dev *ntb, int pidx,
> +                                  int idx, u32 val)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       u32 offset;
> +
> +       if (idx < 0 || idx >= ndev->spad_count)
> +               return -EINVAL;
> +
> +       offset = (idx << 2);
> +       writel(val, ndev->peer_spad_reg + offset);
> +
> +       return 0;
> +}
> +
> +static int ntb_epf_link_enable(struct ntb_dev *ntb,
> +                              enum ntb_speed max_speed,
> +                              enum ntb_width max_width)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       struct device *dev = &ntb->pdev->dev;
> +       int ret;
> +
> +       ret = ntb_epf_send_command(ndev, CMD_LINK_UP, 0);
> +       if (ret) {
> +               dev_err(dev, "Fail to enable link\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int ntb_epf_link_disable(struct ntb_dev *ntb)
> +{
> +       return 0;
> +}
> +
> +static irqreturn_t ndev_vec_isr(int irq, void *dev)
> +{
> +       struct ntb_epf_dev *ndev = dev;
> +       int irq_no;
> +
> +       irq_no = irq - ndev->ntb.pdev->irq;
> +       ndev->db_val = irq_no + 1;
> +
> +       if (irq_no == 0)
> +               ntb_link_event(&ndev->ntb);
> +       else
> +               ntb_db_event(&ndev->ntb, irq_no);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max)
> +{
> +       struct pci_dev *pdev = ndev->ntb.pdev;
> +       struct device *dev = &pdev->dev;
> +       int irq;
> +       int ret;
> +       int i;
> +
> +       irq = pci_alloc_irq_vectors(pdev, msi_min, msi_max, PCI_IRQ_MSI);
> +       if (irq < 0) {
> +               dev_err(dev, "Failed to get MSI interrupts\n");
> +               return irq;
> +       }
> +
> +       for (i = 0; i < irq; i++) {
> +               ret = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, i),
> +                                      ndev_vec_isr, IRQF_SHARED, "ntb_epf",
> +                                      ndev);
> +               if (ret) {
> +                       dev_err(dev, "Failed to request irq\n");
> +                       goto err_request_irq;
> +               }
> +       }
> +
> +       ndev->db_count = irq;
> +
> +       ret = ntb_epf_send_command(ndev, CMD_CONFIGURE_DOORBELL, irq);
> +       if (ret) {
> +               dev_err(dev, "Failed to configure doorbell\n");
> +               goto err_request_irq;
> +       }
> +
> +       return 0;
> +
> +err_request_irq:
> +       pci_free_irq_vectors(pdev);
> +
> +       return ret;
> +}
> +
> +static int ntb_epf_peer_mw_count(struct ntb_dev *ntb)
> +{
> +       return ntb_ndev(ntb)->mw_count;
> +}
> +
> +static int ntb_epf_spad_count(struct ntb_dev *ntb)
> +{
> +       return ntb_ndev(ntb)->spad_count;
> +}
> +
> +static u64 ntb_epf_db_valid_mask(struct ntb_dev *ntb)
> +{
> +       return ntb_ndev(ntb)->db_valid_mask;
> +}
> +
> +static int ntb_epf_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
> +{
> +       return 0;
> +}
> +
> +static int ntb_epf_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
> +                               dma_addr_t addr, resource_size_t size)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       struct device *dev = &ntb->pdev->dev;
> +       resource_size_t mw_size;
> +       int bar;
> +
> +       if (pidx != NTB_DEF_PEER_IDX)
> +               return -EINVAL;
> +
> +       bar = idx + NTB_MW_OFFSET;
> +
> +       mw_size = pci_resource_len(ntb->pdev, bar);
> +
> +       if (size > mw_size) {
> +               dev_err(dev, "Size is greater than the MW size\n");
> +               return -EINVAL;
> +       }
> +
> +       ntb_epf_ctrl_writel(ndev, NTB_EPF_ADDR, addr);
> +       ntb_epf_ctrl_writel(ndev, NTB_EPF_SIZE, size);
> +       ntb_epf_send_command(ndev, CMD_CONFIGURE_MW, idx);
> +
> +       return 0;
> +}
> +
> +static int ntb_epf_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
> +                                   phys_addr_t *base, resource_size_t *size)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       u32 offset = 0;
> +       int bar;
> +
> +       if (idx == 0)
> +               offset = ntb_epf_ctrl_readl(ndev, NTB_EPF_MW1_OFFSET);
> +
> +       bar = idx + NTB_MW_OFFSET;
> +
> +       if (base)
> +               *base = pci_resource_start(ndev->ntb.pdev, bar) + offset;
> +
> +       if (size)
> +               *size = pci_resource_len(ndev->ntb.pdev, bar) - offset;
> +
> +       return 0;
> +}
> +
> +static int ntb_epf_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +       u32 interrupt_num = ffs(db_bits) + 1;
> +       u32 db_entry_size;
> +       u32 db_data;
> +
> +       if (interrupt_num > ndev->db_count)
> +               return -EINVAL;
> +
> +       db_entry_size = ntb_epf_ctrl_readl(ndev, NTB_EPF_DB_ENTRY_SIZE);
> +
> +       db_data = readl(ndev->ctrl_reg + NTB_EPF_DB_DATA(interrupt_num));
> +       writel(db_data, ndev->db_reg + (db_entry_size * interrupt_num));
> +
> +       return 0;
> +}
> +
> +static u64 ntb_epf_db_read(struct ntb_dev *ntb)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +
> +       return ndev->db_val;
> +}
> +
> +static int ntb_epf_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
> +{
> +       return 0;
> +}
> +
> +static int ntb_epf_db_clear(struct ntb_dev *ntb, u64 db_bits)
> +{
> +       struct ntb_epf_dev *ndev = ntb_ndev(ntb);
> +
> +       ndev->db_val = 0;
> +
> +       return 0;
> +}
> +
> +static const struct ntb_dev_ops ntb_epf_ops = {
> +       .mw_count               = ntb_epf_mw_count,
> +       .spad_count             = ntb_epf_spad_count,
> +       .peer_mw_count          = ntb_epf_peer_mw_count,
> +       .db_valid_mask          = ntb_epf_db_valid_mask,
> +       .db_set_mask            = ntb_epf_db_set_mask,
> +       .mw_set_trans           = ntb_epf_mw_set_trans,
> +       .peer_mw_get_addr       = ntb_epf_peer_mw_get_addr,
> +       .link_enable            = ntb_epf_link_enable,
> +       .spad_read              = ntb_epf_spad_read,
> +       .spad_write             = ntb_epf_spad_write,
> +       .peer_spad_read         = ntb_epf_peer_spad_read,
> +       .peer_spad_write        = ntb_epf_peer_spad_write,
> +       .peer_db_set            = ntb_epf_peer_db_set,
> +       .db_read                = ntb_epf_db_read,
> +       .mw_get_align           = ntb_epf_mw_get_align,
> +       .link_is_up             = ntb_epf_link_is_up,
> +       .db_clear_mask          = ntb_epf_db_clear_mask,
> +       .db_clear               = ntb_epf_db_clear,
> +       .link_disable           = ntb_epf_link_disable,
> +};
> +
> +static inline void ntb_epf_init_struct(struct ntb_epf_dev *ndev,
> +                                      struct pci_dev *pdev)
> +{
> +       ndev->ntb.pdev = pdev;
> +       ndev->ntb.topo = NTB_TOPO_NONE;
> +       ndev->ntb.ops = &ntb_epf_ops;
> +}
> +
> +static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)
> +{
> +       struct pci_dev *pdev = ndev->ntb.pdev;
> +       struct device *dev = &pdev->dev;
> +       int ret;
> +
> +       ret = ntb_epf_init_isr(ndev, NTB_MIN_DB_COUNT, NTB_MAX_DB_COUNT);
> +       if (ret) {
> +               dev_err(dev, "Failed to init ISR\n");
> +               return ret;
> +       }
> +
> +       ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
> +       ndev->mw_count = ntb_epf_ctrl_readl(ndev, NTB_EPF_MW_COUNT);
> +       ndev->spad_count = ntb_epf_ctrl_readl(ndev, NTB_EPF_SPAD_COUNT);
> +
> +       return 0;
> +}
> +
> +static int ntb_epf_init_pci(struct ntb_epf_dev *ndev,
> +                           struct pci_dev *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       int ret;
> +
> +       pci_set_drvdata(pdev, ndev);
> +
> +       ret = pci_enable_device(pdev);
> +       if (ret) {
> +               dev_err(dev, "Cannot enable PCI device\n");
> +               goto err_pci_enable;
> +       }
> +
> +       ret = pci_request_regions(pdev, "ntb");
> +       if (ret) {
> +               dev_err(dev, "Cannot obtain PCI resources\n");
> +               goto err_pci_regions;
> +       }
> +
> +       pci_set_master(pdev);
> +
> +       ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
> +       if (ret) {
> +               ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
> +               if (ret) {
> +                       dev_err(dev, "Cannot set DMA mask\n");
> +                       goto err_dma_mask;
> +               }
> +               dev_warn(&pdev->dev, "Cannot DMA highmem\n");
> +       }
> +
> +       ret = dma_coerce_mask_and_coherent(&ndev->ntb.dev,
> +                                          dma_get_mask(&pdev->dev));
> +       if (ret) {
> +               dev_err(dev, "Cannot set DMA mask\n");
> +               goto err_dma_mask;
> +       }
> +
> +       ndev->ctrl_reg = pci_iomap(pdev, 0, 0);
> +       if (!ndev->ctrl_reg) {
> +               ret = -EIO;
> +               goto err_dma_mask;
> +       }
> +
> +       ndev->peer_spad_reg = pci_iomap(pdev, 1, 0);
> +       if (!ndev->peer_spad_reg) {
> +               ret = -EIO;
> +               goto err_dma_mask;
> +       }
> +
> +       ndev->db_reg = pci_iomap(pdev, 2, 0);
> +       if (!ndev->db_reg) {
> +               ret = -EIO;
> +               goto err_dma_mask;
> +       }
> +
> +       return 0;
> +
> +err_dma_mask:
> +       pci_clear_master(pdev);
> +
> +err_pci_regions:
> +       pci_disable_device(pdev);
> +
> +err_pci_enable:
> +       pci_set_drvdata(pdev, NULL);
> +
> +       return ret;
> +}
> +
> +static void ntb_epf_deinit_pci(struct ntb_epf_dev *ndev)
> +{
> +       struct pci_dev *pdev = ndev->ntb.pdev;
> +
> +       pci_iounmap(pdev, ndev->ctrl_reg);
> +       pci_iounmap(pdev, ndev->peer_spad_reg);
> +       pci_iounmap(pdev, ndev->db_reg);
> +
> +       pci_clear_master(pdev);
> +       pci_release_regions(pdev);
> +       pci_disable_device(pdev);
> +       pci_set_drvdata(pdev, NULL);
> +}
> +
> +static int ntb_epf_pci_probe(struct pci_dev *pdev,
> +                            const struct pci_device_id *id)
> +{
> +       enum pci_barno peer_spad_reg_bar = BAR_1;
> +       enum pci_barno ctrl_reg_bar = BAR_0;
> +       enum pci_barno db_reg_bar = BAR_2;
> +       struct device *dev = &pdev->dev;
> +       struct ntb_epf_data *data;
> +       struct ntb_epf_dev *ndev;
> +       int ret;
> +
> +       ndev = devm_kzalloc(dev, sizeof(*ndev), GFP_KERNEL);
> +       if (!ndev)
> +               return -ENOMEM;
> +
> +       data = (struct ntb_epf_data *)id->driver_data;
> +       if (data) {
> +               if (data->peer_spad_reg_bar)
> +                       peer_spad_reg_bar = data->peer_spad_reg_bar;
> +               if (data->ctrl_reg_bar)
> +                       ctrl_reg_bar = data->ctrl_reg_bar;
> +               if (data->db_reg_bar)
> +                       db_reg_bar = data->db_reg_bar;
> +       }
> +
> +       ndev->peer_spad_reg_bar = peer_spad_reg_bar;
> +       ndev->ctrl_reg_bar = ctrl_reg_bar;
> +       ndev->db_reg_bar = db_reg_bar;
> +
> +       ntb_epf_init_struct(ndev, pdev);
> +
> +       ret = ntb_epf_init_pci(ndev, pdev);
> +       if (ret) {
> +               dev_err(dev, "Failed to init PCI\n");
> +               return ret;
> +       }
> +
> +       ret = ntb_epf_init_dev(ndev);
> +       if (ret) {
> +               dev_err(dev, "Failed to init device\n");
> +               goto err_init_dev;
> +       }
> +
> +       ret = ntb_register_device(&ndev->ntb);
> +       if (ret) {
> +               dev_err(dev, "Failed to register NTB device\n");
> +               goto err_register_dev;
> +       }
> +
> +       return 0;
> +
> +err_register_dev:
> +       pci_free_irq_vectors(pdev);
> +
> +err_init_dev:
> +       ntb_epf_deinit_pci(ndev);
> +
> +       return ret;
> +}
> +
> +static void ntb_epf_pci_remove(struct pci_dev *pdev)
> +{
> +       struct ntb_epf_dev *ndev = pci_get_drvdata(pdev);
> +
> +       ntb_unregister_device(&ndev->ntb);
> +       pci_free_irq_vectors(pdev);
> +       kfree(ndev);
> +}
> +
> +static const struct ntb_epf_data j721e_data = {
> +       .ctrl_reg_bar = BAR_0,
> +       .peer_spad_reg_bar = BAR_1,
> +       .db_reg_bar = BAR_2,
> +};
> +
> +static const struct pci_device_id ntb_epf_pci_tbl[] = {
> +       {
> +               PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
> +               .driver_data = (kernel_ulong_t)&j721e_data,
> +       },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(pci, ntb_epf_pci_tbl);
> +
> +static struct pci_driver ntb_epf_pci_driver = {
> +       .name           = KBUILD_MODNAME,
> +       .id_table       = ntb_epf_pci_tbl,
> +       .probe          = ntb_epf_pci_probe,
> +       .remove         = ntb_epf_pci_remove,
> +};
> +module_pci_driver(ntb_epf_pci_driver);
> +
> +MODULE_DESCRIPTION("PCI ENDPOINT NTB HOST DRIVER");
> +MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
> +MODULE_LICENSE("GPL v2");
> --
> 2.17.1
>
> --
> You received this message because you are subscribed to the Google Groups "linux-ntb" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-ntb+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/linux-ntb/20190926112933.8922-21-kishon%40ti.com.

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

* Re: [RFC PATCH 00/21] Implement NTB Controller using multiple PCI
  2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
                   ` (20 preceding siblings ...)
  2019-09-26 11:29 ` [RFC PATCH 21/21] NTB: tool: Enable the NTB/PCIe link on the local or remote side of bridge Kishon Vijay Abraham I
@ 2019-11-17 23:43 ` Jon Mason
  21 siblings, 0 replies; 28+ messages in thread
From: Jon Mason @ 2019-11-17 23:43 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Bjorn Helgaas, Jonathan Corbet, Rob Herring, Dave Jiang,
	Allen Hubbe, Lorenzo Pieralisi, Mark Rutland, linux-pci,
	linux-doc, linux-kernel, devicetree, linux-ntb

On Thu, Sep 26, 2019 at 7:30 AM 'Kishon Vijay Abraham I' via linux-ntb
<linux-ntb@googlegroups.com> wrote:
>
> This series is sent as RFC since this series is dependent on
> [1] (cannot be merged before that series) and to get early review
> comments.
>
> I'll also split this series into smaller chunk when I post the
> next revision.
>
> This series is about implementing SW defined NTB using
> multiple endpoint instances. This series has been tested using
> 2 endpoint instances in J7 connected to two DRA7 boards.
>
> This was presented in Linux Plumbers Conference. The presentation
> can be found @ [2]
>
> This series:
>   *) Add support to define endpoint function using device tree
>   *) Add a specification for implementing NTB controller using
>      multiple endpoint instances.
>   *) Add a NTB endpoint function driver and a NTB host side PCI
>      driver that follows the specification.
>   *) Add support in PCIe endpoint core to support secondary
>      interface.
>   *) Add a device tree overlay file to configure J7 as NTB
>
> The test setup is something like below
>    +-------------+                                   +-------------+
>    |             |                                   |             |
>    |    DRA72    |                                   |    DRA76    |
>    |             |                                   |             |
>    +------^------+                                   +------^------+
>           |                                                 |
>           |                                                 |
> +---------|-------------------------------------------------|---------+
> |  +------v------+                                   +------v------+  |
> |  |             |                                   |             |  |
> |  |     EP      |                                   |     EP      |  |
> |  | CONTROLLER1 |                                   | CONTROLLER2 |  |
> |  |             <----------------------------------->             |  |
> |  |             |                                   |             |  |
> |  |             |                                   |             |  |
> |  |             |                 J7                |             |  |
> |  |             |  (Configured using NTB Function)  |             |  |
> |  +-------------+                                   +-------------+  |
> +---------------------------------------------------------------------+
>
> Here DRA72 and DRA76 could be replaced with *any* PCI host.
>
> EP side (J7):
> =============
>
> In the kernel:
>         cd /sys/kernel/config/pci_ep/
>         echo 1 > controllers/d800000.pcie-ep/start
>         echo 1 > controllers/d000000.pcie-ep/start
>
> RC side (DRA7):
> ===============
>         echo 0000:01:00.0 > /sys/bus/pci/devices/0000\:01\:00.0/driver/unbind
>         echo 0000:01:00.0 > /sys/bus/pci/drivers/ntb_hw_epf/bind
>         modprobe ntb_transport
>         modprobe ntb_netdev
>
> On each of the hosts Ethernet Interface will be created.
>
> Provide an IP address to each of the hosts:
> HOST1 (dra72):
> ifconfig eth2 192.168.1.2 up
>
> HOST2 (dra76):
> ifconfig eth2 192.168.1.1 up
>
> Once this is done standard network utilities like ping or iperf can be
> used.
>
> root@dra7xx-evm:~# iperf -c 192.168.1.2
> ------------------------------------------------------------
> Client connecting to 192.168.1.2, TCP port 5001
> TCP window size: 2.50 MByte (default)
> ------------------------------------------------------------
> [  3] local 192.168.1.1 port 60814 connected with 192.168.1.2 port 5001
> [ ID] Interval       Transfer     Bandwidth
> [  3]  0.0-10.0 sec   705 MBytes   591 Mbits/sec
>
> [1] -> http://lore.kernel.org/r/20190604131516.13596-1-kishon@ti.com
> [2] -> https://www.linuxplumbersconf.org/event/4/contributions/395/attachments/284/481/Implementing_NTB_Controller_Using_PCIe_Endpoint_-_final.pdf


I had a few nits, but I think this series looks good enough to be sent
out for inclusion.

Thanks,
Jon

> Kishon Vijay Abraham I (21):
>   dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Bus
>   dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device
>   dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF NTB Device
>   Documentation: PCI: Add specification for the *PCI NTB* function
>     device
>   PCI: endpoint: Add API to get reference to EPC from device-tree
>   PCI: endpoint: Add API to create EPF device from device tree
>   PCI: endpoint: Add "pci-epf-bus" driver
>   PCI: endpoint: Make *_get_first_free_bar() take into account 64 bit
>     BAR
>   PCI: endpoint: Add helper API to get the 'next' unreserved BAR
>   PCI: endpoint: Make pci_epf_driver ops optional
>   PCI: endpoint: Add helper API to populate header with values from DT
>   PCI: endpoint: Add support to associate secondary EPC with EPF
>   PCI: endpoint: Add pci_epc_ops to map MSI irq
>   PCI: cadence: Implement ->msi_map_irq() ops
>   PCI: endpoint: Remove unused pci_epf_match_device()
>   PCI: endpoint: Fix missing mutex_unlock in error case
>   PCI: endpoint: *_free_bar() to return error codes on failure
>   PCI: endpoint: Add EP function driver to provide NTB functionality
>   PCI: Add TI J721E device to pci ids
>   NTB: Add support for EPF PCI-Express Non-Transparent Bridge
>   NTB: tool: Enable the NTB/PCIe link on the local or remote side of
>     bridge
>
>  Documentation/PCI/endpoint/pci-test-ntb.txt   |  315 +++++
>  .../bindings/pci/endpoint/pci-epf-bus.txt     |   27 +
>  .../bindings/pci/endpoint/pci-epf-ntb.txt     |   31 +
>  .../bindings/pci/endpoint/pci-epf.txt         |   28 +
>  drivers/ntb/hw/Kconfig                        |    1 +
>  drivers/ntb/hw/Makefile                       |    1 +
>  drivers/ntb/hw/epf/Kconfig                    |    5 +
>  drivers/ntb/hw/epf/Makefile                   |    1 +
>  drivers/ntb/hw/epf/ntb_hw_epf.c               |  648 ++++++++++
>  drivers/ntb/test/ntb_tool.c                   |    1 +
>  drivers/pci/controller/pcie-cadence-ep.c      |   59 +
>  drivers/pci/endpoint/Makefile                 |    3 +-
>  drivers/pci/endpoint/functions/Kconfig        |   12 +
>  drivers/pci/endpoint/functions/Makefile       |    1 +
>  drivers/pci/endpoint/functions/pci-epf-ntb.c  | 1143 +++++++++++++++++
>  drivers/pci/endpoint/functions/pci-epf-test.c |   12 +-
>  drivers/pci/endpoint/pci-ep-cfs.c             |    6 +-
>  drivers/pci/endpoint/pci-epc-core.c           |  221 +++-
>  drivers/pci/endpoint/pci-epf-bus.c            |   54 +
>  drivers/pci/endpoint/pci-epf-core.c           |  133 +-
>  include/linux/pci-epc.h                       |   42 +-
>  include/linux/pci-epf.h                       |   35 +-
>  include/linux/pci_ids.h                       |    1 +
>  23 files changed, 2715 insertions(+), 65 deletions(-)
>  create mode 100644 Documentation/PCI/endpoint/pci-test-ntb.txt
>  create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf-bus.txt
>  create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf-ntb.txt
>  create mode 100644 Documentation/devicetree/bindings/pci/endpoint/pci-epf.txt
>  create mode 100644 drivers/ntb/hw/epf/Kconfig
>  create mode 100644 drivers/ntb/hw/epf/Makefile
>  create mode 100644 drivers/ntb/hw/epf/ntb_hw_epf.c
>  create mode 100644 drivers/pci/endpoint/functions/pci-epf-ntb.c
>  create mode 100644 drivers/pci/endpoint/pci-epf-bus.c
>
> --
> 2.17.1
>
> --
> You received this message because you are subscribed to the Google Groups "linux-ntb" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-ntb+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/linux-ntb/20190926112933.8922-1-kishon%40ti.com.

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

end of thread, other threads:[~2019-11-17 23:43 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-26 11:29 [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 01/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Bus Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 02/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF Device Kishon Vijay Abraham I
2019-10-15 18:42   ` Rob Herring
2019-10-16  4:45     ` Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 03/21] dt-bindings: PCI: Endpoint: Add DT bindings for PCI EPF NTB Device Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 04/21] Documentation: PCI: Add specification for the *PCI NTB* function device Kishon Vijay Abraham I
2019-11-17 23:26   ` Jon Mason
2019-09-26 11:29 ` [RFC PATCH 05/21] PCI: endpoint: Add API to get reference to EPC from device-tree Kishon Vijay Abraham I
2019-11-17 23:28   ` Jon Mason
2019-09-26 11:29 ` [RFC PATCH 06/21] PCI: endpoint: Add API to create EPF device from device tree Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 07/21] PCI: endpoint: Add "pci-epf-bus" driver Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 08/21] PCI: endpoint: Make *_get_first_free_bar() take into account 64 bit BAR Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 09/21] PCI: endpoint: Add helper API to get the 'next' unreserved BAR Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 10/21] PCI: endpoint: Make pci_epf_driver ops optional Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 11/21] PCI: endpoint: Add helper API to populate header with values from DT Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 12/21] PCI: endpoint: Add support to associate secondary EPC with EPF Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 13/21] PCI: endpoint: Add pci_epc_ops to map MSI irq Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 14/21] PCI: cadence: Implement ->msi_map_irq() ops Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 15/21] PCI: endpoint: Remove unused pci_epf_match_device() Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 16/21] PCI: endpoint: Fix missing mutex_unlock in error case Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 17/21] PCI: endpoint: *_free_bar() to return error codes on failure Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 18/21] PCI: endpoint: Add EP function driver to provide NTB functionality Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 19/21] PCI: Add TI J721E device to pci ids Kishon Vijay Abraham I
2019-09-26 11:29 ` [RFC PATCH 20/21] NTB: Add support for EPF PCI-Express Non-Transparent Bridge Kishon Vijay Abraham I
2019-11-17 23:40   ` Jon Mason
2019-09-26 11:29 ` [RFC PATCH 21/21] NTB: tool: Enable the NTB/PCIe link on the local or remote side of bridge Kishon Vijay Abraham I
2019-11-17 23:43 ` [RFC PATCH 00/21] Implement NTB Controller using multiple PCI Jon Mason

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