2016-11-29 17:15:57

by Serge Semin

[permalink] [raw]
Subject: [PATCH 00/22] NTB: Alter kernel API to support multi-port devices

There are devices, like IDT PCIe-switches, which have more than just two ports.
Particularly one device can have up to eight ports with NTB-function activated.
In order to support such devices, NTB kernel API should be altered since
currently it's optimized to work with two-ports devices only.

Here are the changes I made to conform the design we discussed a few months ago:

1) Port-index-related methods are added to KAPI
ntb_port_number();
ntb_peer_port_count();
ntb_peer_port_number(pdix);
ntb_peer_port_idx(port);

2) Link state method returns bitfield of link states for each reachable port
u64 ntb_link_is_up();

3) Link enable/disable methods work with local link side of NTB
ntb_link_enable()/ntb_link_disable();

4) NTB memory window related interface does the following things
ntb_mw_count(pidx); - number of inbound memory windows, which can be allocated
for shared buffer with specified peer device.
ntb_mw_get_align(pidx, widx); - get alignment and size restrition parameters
to properly allocate inbound memory region.
ntb_peer_mw_count(); - get number of outbound memory windows.
ntb_peer_mw_get_addr(widx); - get mapping address of an outbound memory window

Inbound MW based hardware:
ntb_mw_set_trans(pidx, widx); - set translation address of allocated inbound
memory window so a peer device could access it.
ntb_mw_clear_trans(pidx, widx); - clear the translation address of an inbound
memory window.

Outbound MW based hardware:
ntb_peer_mw_set_trans(pidx, widx); - set translation address of a memory
window retrieved from a peer device
ntb_peer_mw_clear_trans(pidx, widx); - clear the translation address of an
outbound memory window

5) Scratchpad interface needs to support multi-port devices as well
ntb_spad_count() - return number of Scratchpad per each port
ntb_peer_spad_addr(pidx, sidx) - address of Scratchpad register of the
peer device with pidx-index
ntb_peer_spad_read(pidx, sidx) - read specified Scratchpad register of the
peer with pidx-index
ntb_peer_spad_write(pidx, sidx) - write data to Scratchpad register of the
peer with pidx-index

6) Introduce new messaging interface of NTB KAPI
ntb_msg_count(); - get number of message registers
ntb_msg_inbits(); - get bitfield of inbound message registers status
ntb_msg_outbits(); - get bitfield of outbound message registers status
ntb_msg_read_sts(); - read the inbound and outbound message registers status
ntb_msg_clear_sts(); - clear status bits of message registers
ntb_msg_set_mask(); - mask interrupts raised by status bits of message
registers.
ntb_msg_clear_mask(); - clear interrupts mask bits of message registers
ntb_msg_recv(midx, *pidx); - read message register with specified index,
additionally getting peer port index which data received from
ntb_msg_send(midx, pidx); - write data to the specified message register
sending it to the passed peer device connected over a pidx port
ntb_msg_event(); - notify driver context of a new message event

7) Topology reduced to be either P2P (port-to-port) or B2B (bridge-to-bridge).
Since there is port number introduced to be part of ntb_dev structure, real
port number can be used to determine Primary and Secondary sides. Intel and AMD
driver are altered to support this novation.

8) Standard test drivers: PingPong, Debugging tool and Raw Perf as well as NTB
Transport drivers don't support multi-port devices at the moment.
Since we haven't got any real multi-port hadrware driver, it's dangerous to
make any serious alterations in the debugging tools. So I have made those
drivers to work the way they wokred before, but using the new NTB API.
The situation will change when I finish porting my current IDT NTB driver to
support new API. Then I'll be able to refactor the tools and test them using
real multi-port hardware.

The changes are made on top of the NTB-fork of the kernel:
https://github.com/jonmason/ntb
of "ntb"-branch with last commit:
9c763584b7c8911106bb77af7e648bef09af9d80 Linux 4.9-rc6

Signed-off-by: Serge Semin <[email protected]>

Serge Semin (22):
NTB: Move link state API being first in sources
NTB: Add peer indexed ports NTB API
NTB: Alter NTB API to support both inbound and outbound MW based
interfaces
NTB: Add messaging NTB API
NTB: Alter Scratchpads NTB API to support multi-ports interface
NTB: Slightly alter link state NTB API
NTB: Fix a few ntb.h issues
NTB: Add T-Platforms copyrights to NTB API
NTB Intel: Move link-related methods being first in the driver
NTB Intel: Add port-related NTB API callback methods
NTB Intel: Alter MW interface to fit new NTB API
NTB Intel: Alter Scratchpads interface to fit new NTB API
NTB Intel: Add T-Platforms copyrights to Intel NTB driver
NTB AMD: Move link-related methods being first in the driver
NTB AMD: Add port-related NTB API callback methods
NTB AMD: Alter MW interface to fit new NTB API
NTB AMD: Alter Scratchpads interface to fit new NTB API
NTB AMD: Add T-Platforms copyrights to AMD NTB driver
NTB PingPong: Alter driver to work with two-ports NTB API
NTB Tool: Alter driver to work with two-ports NTB API
NTB Perf: Alter driver to work with two-ports NTB API
NTB Transport: Alter driver to work with two-ports NTB API

drivers/ntb/hw/amd/ntb_hw_amd.c | 310 +++++++++------
drivers/ntb/hw/amd/ntb_hw_amd.h | 12 +
drivers/ntb/hw/intel/ntb_hw_intel.c | 420 ++++++++++++--------
drivers/ntb/hw/intel/ntb_hw_intel.h | 12 +
drivers/ntb/ntb.c | 15 +
drivers/ntb/ntb_transport.c | 43 +-
drivers/ntb/test/ntb_perf.c | 27 +-
drivers/ntb/test/ntb_pingpong.c | 11 +-
drivers/ntb/test/ntb_tool.c | 87 +++--
include/linux/ntb.h | 753 +++++++++++++++++++++++++++++-------
10 files changed, 1221 insertions(+), 469 deletions(-)

--
2.6.6


2016-11-29 17:16:18

by Serge Semin

[permalink] [raw]
Subject: [PATCH 03/22] NTB: Alter NTB API to support both inbound and outbound MW based interfaces

Alter NTB API to support inbound and outbound MW based interfaces.
Additionally I made it supporting multi-port devices as well. Useful
infographics is added right before MW API is declared. It shall help to
better understand how the new API really works and how it can be utilized
within client drivers.

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 290 ++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 245 insertions(+), 45 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 0941a43..4a150b5 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -171,9 +171,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @link_enable: See ntb_link_enable().
* @link_disable: See ntb_link_disable().
* @mw_count: See ntb_mw_count().
- * @mw_get_range: See ntb_mw_get_range().
+ * @mw_get_align: See ntb_mw_get_align().
* @mw_set_trans: See ntb_mw_set_trans().
* @mw_clear_trans: See ntb_mw_clear_trans().
+ * @peer_mw_count: See ntb_peer_mw_count().
+ * @peer_mw_get_addr: See ntb_peer_mw_get_addr().
+ * @peer_mw_set_trans: See ntb_peer_mw_set_trans().
+ * @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
* @db_is_unsafe: See ntb_db_is_unsafe().
* @db_valid_mask: See ntb_db_valid_mask().
* @db_vector_count: See ntb_db_vector_count().
@@ -211,13 +215,20 @@ struct ntb_dev_ops {
enum ntb_speed max_speed, enum ntb_width max_width);
int (*link_disable)(struct ntb_dev *ntb);

- int (*mw_count)(struct ntb_dev *ntb);
- int (*mw_get_range)(struct ntb_dev *ntb, int idx,
- phys_addr_t *base, resource_size_t *size,
- resource_size_t *align, resource_size_t *align_size);
- int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
+ int (*mw_count)(struct ntb_dev *ntb, int pidx);
+ int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
+ resource_size_t *addr_align,
+ resource_size_t *size_align,
+ resource_size_t *size_max);
+ int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size);
- int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
+ int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
+ int (*peer_mw_count)(struct ntb_dev *ntb);
+ int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
+ phys_addr_t *base, resource_size_t *size);
+ int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
+ u64 addr, resource_size_t size);
+ int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);

int (*db_is_unsafe)(struct ntb_dev *ntb);
u64 (*db_valid_mask)(struct ntb_dev *ntb);
@@ -266,9 +277,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->link_enable &&
ops->link_disable &&
ops->mw_count &&
- ops->mw_get_range &&
- ops->mw_set_trans &&
+ ops->mw_get_align &&
+ (ops->mw_set_trans ||
+ ops->peer_mw_set_trans) &&
/* ops->mw_clear_trans && */
+ ops->peer_mw_count &&
+ ops->peer_mw_get_addr &&
+ /* ops->peer_mw_clear_trans && */

/* ops->db_is_unsafe && */
ops->db_valid_mask &&
@@ -555,79 +570,264 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
}

/**
- * ntb_mw_count() - get the number of memory windows
+ * NTB Memory Windows description
+ *
+ * There are two types of memory window interfaces supported by the NTB API:
+ * local and peer side initialization of memory sharing. The first type is
+ * depicted on the next figure:
+ *
+ * Local device: | Peer device:
+ * NTB config |
+ * Physical memory (RAM) __________ | Memory mapped IO
+ * ____________ +-->| addr | | _____________
+ * | | | |----------| | | |
+ * |------------|addr--+ | |-------------|
+ * | Inbound MW | PCI Express + NTB | Outbound MW |
+ * | |<=====================================| |
+ * |------------| |-------------|
+ *
+ * So typical scenario of the first type memory window initialization looks:
+ * 1) allocate a memory region, 2) put translated base address to NTB config,
+ * 3) somehow notify a peer device of performed initialization, 4) peer device
+ * maps corresponding outbound memory window so to have access to the shared
+ * memory region.
+ *
+ * The second type of interface, that implies the shared windows being
+ * initialized by a peer device, is depicted on the figure:
+ *
+ * Local device: | Peer device:
+ * | NTB config
+ * Physical memory (RAM) | __________ Memory mapped IO
+ * ____________ +-------------->| addr | _____________
+ * | | | | |----------| | |
+ * |------------|addr---+ | |-------------|
+ * | Inbound MW | PCI Express + NTB | Outbound MW |
+ * | |<=====================================| |
+ * |------------| |-------------|
+ *
+ * Typical scenario of the second type initialization would be:
+ * 1) allocate a memory region, 2) somehow deliver a translated base address
+ * to a peer device, 3) peer puts the translated base address to NTB config,
+ * 4) peer device maps outbound memory window so to have access to the shared
+ * memory region.
+ *
+ * As one can see the described scenarios can be combined in one portable
+ * algorithm.
+ * Local device:
+ * 1) Allocate memory for a shared window
+ * 2) Initialize memory window by base address of the allocated region
+ * (it may fail if local memory window initialzation is unsupported)
+ * 3) Send translated base address and memory window index to a peer device
+ * Peer device:
+ * 1) Initialize memory window by retrieved base address of the allocated
+ * by another device memory region (it may fail if peer memory window
+ * initialization is unsupported)
+ * 2) Map outbound memory window
+ * 3) Done
+ * In accordance with this scenario, the NTB Memory Window API can be used as
+ * follows:
+ * Local device:
+ * 1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
+ * be allocated for memory windows between local device and peer device
+ * of port with specified index.
+ * 2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
+ * shared memory region alignment and size. Then memory can be properly
+ * allocated.
+ * 3) Allocate physically contiguous memory region in complience with
+ * restrictions retrieved in 2).
+ * 4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
+ * the memory window with specified index for the defined peer device
+ * (it may fail if local translated address setting is not supported)
+ * 5) Send translated base address (usually together with memory window
+ * number) to the peer device using, for instance, scratchpad or message
+ * registers.
+ * Peer device:
+ * 1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
+ * device (related to pidx) translated base address for specified memory
+ * window. It may fail if retrieved address, for instance, exceeds
+ * maximum possible address or isn't properly aligned.
+ * 2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
+ * window so to have an access to the shared memory.
+ *
+ * Also it is worth to note, that method ntb_mw_count(pidx) should return the
+ * same value as ntb_peer_mw_count() of the peer with port index - pidx.
+ */
+
+/**
+ * ntb_mw_count() - get the number of inbound memory windows, which could
+ * be created for a specified peer device
* @ntb: NTB device context.
+ * @pidx: Port index of peer device.
*
* Hardware and topology may support a different number of memory windows.
+ * Moreover different peer devices can support different number of memory
+ * windows. Simply speaking this method returns the number of possible inbound
+ * memory windows to share with specified peer device.
*
* Return: the number of memory windows.
*/
-static inline int ntb_mw_count(struct ntb_dev *ntb)
+static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
- return ntb->ops->mw_count(ntb);
+ return ntb->ops->mw_count(ntb, pidx);
}

/**
- * ntb_mw_get_range() - get the range of a memory window
+ * ntb_mw_get_align() - get the restriction parameters of inbound memory window
* @ntb: NTB device context.
- * @idx: Memory window number.
- * @base: OUT - the base address for mapping the memory window
- * @size: OUT - the size for mapping the memory window
- * @align: OUT - the base alignment for translating the memory window
- * @align_size: OUT - the size alignment for translating the memory window
- *
- * Get the range of a memory window. NULL may be given for any output
- * parameter if the value is not needed. The base and size may be used for
- * mapping the memory window, to access the peer memory. The alignment and
- * size may be used for translating the memory window, for the peer to access
- * memory on the local system.
- *
- * Return: Zero on success, otherwise an error number.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ * @addr_align: OUT - the base alignment for translating the memory window
+ * @size_align: OUT - the size alignment for translating the memory window
+ * @size_max: OUT - the maximum size of the memory window
+ *
+ * Get the alignments of an inbound memory window with specified index.
+ * NULL may be given for any output parameter if the value is not needed.
+ * The alignment and size parameters may be used for allocation of proper
+ * shared memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
*/
-static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base, resource_size_t *size,
- resource_size_t *align, resource_size_t *align_size)
+static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
+ resource_size_t *addr_align,
+ resource_size_t *size_align,
+ resource_size_t *size_max)
{
- return ntb->ops->mw_get_range(ntb, idx, base, size,
- align, align_size);
+ return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
+ size_max);
}

/**
- * ntb_mw_set_trans() - set the translation of a memory window
+ * ntb_mw_set_trans() - set the translation of an inbound memory window
* @ntb: NTB device context.
- * @idx: Memory window number.
- * @addr: The dma address local memory to expose to the peer.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ * @addr: The dma address of local memory to expose to the peer.
* @size: The size of the local memory to expose to the peer.
*
* Set the translation of a memory window. The peer may access local memory
* through the window starting at the address, up to the size. The address
- * must be aligned to the alignment specified by ntb_mw_get_range(). The size
- * must be aligned to the size alignment specified by ntb_mw_get_range().
+ * and size must be aligned in complience with restrictions of
+ * ntb_mw_get_align(). The region size should not exceed the size_max parameter
+ * of that method.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size)
{
- return ntb->ops->mw_set_trans(ntb, idx, addr, size);
+ if (!ntb->ops->mw_set_trans)
+ return -EINVAL;
+
+ return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
}

/**
- * ntb_mw_clear_trans() - clear the translation of a memory window
+ * ntb_mw_clear_trans() - clear the translation address of an inbound memory
+ * window
* @ntb: NTB device context.
- * @idx: Memory window number.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
*
- * Clear the translation of a memory window. The peer may no longer access
- * local memory through the window.
+ * Clear the translation of an inbound memory window. The peer may no longer
+ * access local memory through the window.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
+static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
{
if (!ntb->ops->mw_clear_trans)
- return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
+ return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
+
+ return ntb->ops->mw_clear_trans(ntb, pidx, widx);
+}
+
+/**
+ * ntb_peer_mw_count() - get the number of outbound memory windows, which could
+ * be mapped to access a shared memory
+ * @ntb: NTB device context.
+ *
+ * Hardware and topology may support a different number of memory windows.
+ * This method returns the number of outbound memory windows supported by
+ * local device.
+ *
+ * Return: the number of memory windows.
+ */
+static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ return ntb->ops->peer_mw_count(ntb);
+}
+
+/**
+ * ntb_peer_mw_get_addr() - get map address of an outbound memory window
+ * @ntb: NTB device context.
+ * @widx: Memory window index (within ntb_peer_mw_count() return value).
+ * @base: OUT - the base address of mapping region.
+ * @size: OUT - the size of mapping region.
+ *
+ * Get base and size of memory region to map. NULL may be given for any output
+ * parameter if the value is not needed. The base and size may be used for
+ * mapping the memory window, to access the peer memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
+}
+
+/**
+ * ntb_peer_mw_set_trans() - set a translation address of a memory window
+ * retrieved from a peer device
+ * @ntb: NTB device context.
+ * @pidx: Port index of peer device the translation address received from.
+ * @widx: Memory window index.
+ * @addr: The dma address of the shared memory to access.
+ * @size: The size of the shared memory to access.
+ *
+ * Set the translation of an outbound memory window. The local device may
+ * access shared memory allocated by a peer device sent the address.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface, so a translation address can be only set on the side,
+ * where shared memory (inbound memory windows) is allocated.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
+ u64 addr, resource_size_t size)
+{
+ if (!ntb->ops->peer_mw_set_trans)
+ return -EINVAL;
+
+ return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
+}
+
+/**
+ * ntb_peer_mw_clear_trans() - clear the translation address of an outbound
+ * memory window
+ * @ntb: NTB device context.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ *
+ * Clear the translation of a outbound memory window. The local device may no
+ * longer access a shared memory through the window.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
+ int widx)
+{
+ if (!ntb->ops->peer_mw_clear_trans)
+ return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);

- return ntb->ops->mw_clear_trans(ntb, idx);
+ return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
}

/**
--
2.6.6

2016-11-29 17:16:30

by Serge Semin

[permalink] [raw]
Subject: [PATCH 02/22] NTB: Add peer indexed ports NTB API

Add new port-index NTB API. Additionally lets get rid of Primary and
Secondary topologies, since port-number can be effectively used instead.

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 101 ++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 79 insertions(+), 22 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 5d1f260..0941a43 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -64,37 +64,21 @@ struct pci_dev;
/**
* enum ntb_topo - NTB connection topology
* @NTB_TOPO_NONE: Topology is unknown or invalid.
- * @NTB_TOPO_PRI: On primary side of local ntb.
- * @NTB_TOPO_SEC: On secondary side of remote ntb.
- * @NTB_TOPO_B2B_USD: On primary side of local ntb upstream of remote ntb.
- * @NTB_TOPO_B2B_DSD: On primary side of local ntb downstream of remote ntb.
+ * @NTB_TOPO_P2P: Simple port-to-port NTB topology
+ * @NTB_TOPO_B2B: Bridge-to-bridge NTB topology
*/
enum ntb_topo {
NTB_TOPO_NONE = -1,
- NTB_TOPO_PRI,
- NTB_TOPO_SEC,
- NTB_TOPO_B2B_USD,
- NTB_TOPO_B2B_DSD,
+ NTB_TOPO_P2P,
+ NTB_TOPO_B2B
};

-static inline int ntb_topo_is_b2b(enum ntb_topo topo)
-{
- switch ((int)topo) {
- case NTB_TOPO_B2B_USD:
- case NTB_TOPO_B2B_DSD:
- return 1;
- }
- return 0;
-}
-
static inline char *ntb_topo_string(enum ntb_topo topo)
{
switch (topo) {
case NTB_TOPO_NONE: return "NTB_TOPO_NONE";
- case NTB_TOPO_PRI: return "NTB_TOPO_PRI";
- case NTB_TOPO_SEC: return "NTB_TOPO_SEC";
- case NTB_TOPO_B2B_USD: return "NTB_TOPO_B2B_USD";
- case NTB_TOPO_B2B_DSD: return "NTB_TOPO_B2B_DSD";
+ case NTB_TOPO_P2P: return "NTB_TOPO_P2P";
+ case NTB_TOPO_B2B: return "NTB_TOPO_B2B";
}
return "NTB_TOPO_INVALID";
}
@@ -179,6 +163,10 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)

/**
* struct ntb_ctx_ops - ntb device operations
+ * @port_number: See ntb_port_number().
+ * @peer_port_count: See ntb_peer_port_count().
+ * @peer_port_number: See ntb_peer_port_number().
+ * @peer_port_idx: See ntb_peer_port_idx().
* @link_is_up: See ntb_link_is_up().
* @link_enable: See ntb_link_enable().
* @link_disable: See ntb_link_disable().
@@ -212,6 +200,11 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_write: See ntb_peer_spad_write().
*/
struct ntb_dev_ops {
+ int (*port_number)(struct ntb_dev *ntb);
+ int (*peer_port_count)(struct ntb_dev *ntb);
+ int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
+ int (*peer_port_idx)(struct ntb_dev *ntb, int port);
+
int (*link_is_up)(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width);
int (*link_enable)(struct ntb_dev *ntb,
@@ -265,6 +258,10 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ ops->port_number &&
+ ops->peer_port_count &&
+ ops->peer_port_number &&
+ ops->peer_port_idx &&
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
@@ -319,6 +316,7 @@ struct ntb_client {
* @dev: Linux device object.
* @pdev: Pci device entry of the ntb.
* @topo: Detected topology of the ntb.
+ * @port: Local port of the ntb.
* @ops: See &ntb_dev_ops.
* @ctx: See &ntb_ctx_ops.
* @ctx_ops: See &ntb_ctx_ops.
@@ -327,6 +325,7 @@ struct ntb_dev {
struct device dev;
struct pci_dev *pdev;
enum ntb_topo topo;
+ int port;
const struct ntb_dev_ops *ops;
void *ctx;
const struct ntb_ctx_ops *ctx_ops;
@@ -442,6 +441,64 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_port_number() - get the local port number
+ * @ntb: NTB device context.
+ *
+ * Hardware must support at least simple two-ports topology
+ *
+ * Return: the local port number
+ */
+static inline int ntb_port_number(struct ntb_dev *ntb)
+{
+ return ntb->ops->port_number(ntb);
+}
+
+/**
+ * ntb_peer_port_count() - get the number of peer device ports
+ * @ntb: NTB device context.
+ *
+ * Hardware may support an access to memory of several remote domains
+ * over multi-port NTB devices. This method returns the number of peers,
+ * local device can have shared memory with.
+ *
+ * Return: the number of peer ports
+ */
+static inline int ntb_peer_port_count(struct ntb_dev *ntb)
+{
+ return ntb->ops->peer_port_count(ntb);
+}
+
+/**
+ * ntb_peer_port_number() - get the peer port by given index
+ * @ntb: NTB device context.
+ * @pidx: Peer port index.
+ *
+ * Peer ports are continuously enumerated by NTB API logic, so this methods
+ * lets to retrieve port real number by its index.
+ *
+ * Return: the peer device port or negative value indicating an error
+ */
+static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ return ntb->ops->peer_port_number(ntb, pidx);
+}
+
+/**
+ * ntb_peer_port_idx() - get the peer device port index by given port number
+ * @ntb: NTB device context.
+ * @port: Peer port number.
+ *
+ * Inverse operation of ntb_peer_port_number(), so one can get port index
+ * by its port number.
+ *
+ * Return: the peer port index or negative value indicating an error
+ */
+static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ return ntb->ops->peer_port_idx(ntb, port);
+}
+
+/**
* ntb_link_is_up() - get the current ntb link state
* @ntb: NTB device context.
* @speed: OUT - The link speed expressed as PCIe generation number.
--
2.6.6

2016-11-29 17:16:57

by Serge Semin

[permalink] [raw]
Subject: [PATCH 01/22] NTB: Move link state API being first in sources

Since link operations are usually performed before memory window access
operations, it's logically better to declared link-related API before any
other methods. Additionally it's good practice for readability to declare
NTB device callback methods of hadrware drivers with the same order as it's
done within ntb.h.

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 137 ++++++++++++++++++++++++++--------------------------
1 file changed, 69 insertions(+), 68 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 6f47562..5d1f260 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -179,13 +179,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)

/**
* struct ntb_ctx_ops - ntb device operations
+ * @link_is_up: See ntb_link_is_up().
+ * @link_enable: See ntb_link_enable().
+ * @link_disable: See ntb_link_disable().
* @mw_count: See ntb_mw_count().
* @mw_get_range: See ntb_mw_get_range().
* @mw_set_trans: See ntb_mw_set_trans().
* @mw_clear_trans: See ntb_mw_clear_trans().
- * @link_is_up: See ntb_link_is_up().
- * @link_enable: See ntb_link_enable().
- * @link_disable: See ntb_link_disable().
* @db_is_unsafe: See ntb_db_is_unsafe().
* @db_valid_mask: See ntb_db_valid_mask().
* @db_vector_count: See ntb_db_vector_count().
@@ -212,6 +212,12 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_write: See ntb_peer_spad_write().
*/
struct ntb_dev_ops {
+ int (*link_is_up)(struct ntb_dev *ntb,
+ enum ntb_speed *speed, enum ntb_width *width);
+ int (*link_enable)(struct ntb_dev *ntb,
+ enum ntb_speed max_speed, enum ntb_width max_width);
+ int (*link_disable)(struct ntb_dev *ntb);
+
int (*mw_count)(struct ntb_dev *ntb);
int (*mw_get_range)(struct ntb_dev *ntb, int idx,
phys_addr_t *base, resource_size_t *size,
@@ -220,12 +226,6 @@ struct ntb_dev_ops {
dma_addr_t addr, resource_size_t size);
int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);

- int (*link_is_up)(struct ntb_dev *ntb,
- enum ntb_speed *speed, enum ntb_width *width);
- int (*link_enable)(struct ntb_dev *ntb,
- enum ntb_speed max_speed, enum ntb_width max_width);
- int (*link_disable)(struct ntb_dev *ntb);
-
int (*db_is_unsafe)(struct ntb_dev *ntb);
u64 (*db_valid_mask)(struct ntb_dev *ntb);
int (*db_vector_count)(struct ntb_dev *ntb);
@@ -265,13 +265,14 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ ops->link_is_up &&
+ ops->link_enable &&
+ ops->link_disable &&
ops->mw_count &&
ops->mw_get_range &&
ops->mw_set_trans &&
/* ops->mw_clear_trans && */
- ops->link_is_up &&
- ops->link_enable &&
- ops->link_disable &&
+
/* ops->db_is_unsafe && */
ops->db_valid_mask &&

@@ -441,6 +442,62 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_link_is_up() - get the current ntb link state
+ * @ntb: NTB device context.
+ * @speed: OUT - The link speed expressed as PCIe generation number.
+ * @width: OUT - The link width expressed as the number of PCIe lanes.
+ *
+ * Get the current state of the ntb link. It is recommended to query the link
+ * state once after every link event. It is safe to query the link state in
+ * the context of the link event callback.
+ *
+ * Return: One if the link is up, zero if the link is down, otherwise a
+ * negative value indicating the error number.
+ */
+static inline int ntb_link_is_up(struct ntb_dev *ntb,
+ enum ntb_speed *speed, enum ntb_width *width)
+{
+ return ntb->ops->link_is_up(ntb, speed, width);
+}
+
+/**
+ * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * @ntb: NTB device context.
+ * @max_speed: The maximum link speed expressed as PCIe generation number.
+ * @max_width: The maximum link width expressed as the number of PCIe lanes.
+ *
+ * Enable the link on the secondary side of the ntb. This can only be done
+ * from the primary side of the ntb in primary or b2b topology. The ntb device
+ * should train the link to its maximum speed and width, or the requested speed
+ * and width, whichever is smaller, if supported.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_enable(struct ntb_dev *ntb,
+ enum ntb_speed max_speed,
+ enum ntb_width max_width)
+{
+ return ntb->ops->link_enable(ntb, max_speed, max_width);
+}
+
+/**
+ * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * @ntb: NTB device context.
+ *
+ * Disable the link on the secondary side of the ntb. This can only be
+ * done from the primary side of the ntb in primary or b2b topology. The ntb
+ * device should disable the link. Returning from this call must indicate that
+ * a barrier has passed, though with no more writes may pass in either
+ * direction across the link, except if this call returns an error number.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_disable(struct ntb_dev *ntb)
+{
+ return ntb->ops->link_disable(ntb);
+}
+
+/**
* ntb_mw_count() - get the number of memory windows
* @ntb: NTB device context.
*
@@ -517,62 +574,6 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
}

/**
- * ntb_link_is_up() - get the current ntb link state
- * @ntb: NTB device context.
- * @speed: OUT - The link speed expressed as PCIe generation number.
- * @width: OUT - The link width expressed as the number of PCIe lanes.
- *
- * Get the current state of the ntb link. It is recommended to query the link
- * state once after every link event. It is safe to query the link state in
- * the context of the link event callback.
- *
- * Return: One if the link is up, zero if the link is down, otherwise a
- * negative value indicating the error number.
- */
-static inline int ntb_link_is_up(struct ntb_dev *ntb,
- enum ntb_speed *speed, enum ntb_width *width)
-{
- return ntb->ops->link_is_up(ntb, speed, width);
-}
-
-/**
- * ntb_link_enable() - enable the link on the secondary side of the ntb
- * @ntb: NTB device context.
- * @max_speed: The maximum link speed expressed as PCIe generation number.
- * @max_width: The maximum link width expressed as the number of PCIe lanes.
- *
- * Enable the link on the secondary side of the ntb. This can only be done
- * from the primary side of the ntb in primary or b2b topology. The ntb device
- * should train the link to its maximum speed and width, or the requested speed
- * and width, whichever is smaller, if supported.
- *
- * Return: Zero on success, otherwise an error number.
- */
-static inline int ntb_link_enable(struct ntb_dev *ntb,
- enum ntb_speed max_speed,
- enum ntb_width max_width)
-{
- return ntb->ops->link_enable(ntb, max_speed, max_width);
-}
-
-/**
- * ntb_link_disable() - disable the link on the secondary side of the ntb
- * @ntb: NTB device context.
- *
- * Disable the link on the secondary side of the ntb. This can only be
- * done from the primary side of the ntb in primary or b2b topology. The ntb
- * device should disable the link. Returning from this call must indicate that
- * a barrier has passed, though with no more writes may pass in either
- * direction across the link, except if this call returns an error number.
- *
- * Return: Zero on success, otherwise an error number.
- */
-static inline int ntb_link_disable(struct ntb_dev *ntb)
-{
- return ntb->ops->link_disable(ntb);
-}
-
-/**
* ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
* @ntb: NTB device context.
*
--
2.6.6

2016-11-29 17:17:42

by Serge Semin

[permalink] [raw]
Subject: [PATCH 21/22] NTB Perf: Alter driver to work with two-ports NTB API

The same as for PingPong driver, this driver can't be used with hardware
whithout Scratchpads. Additionally it supports two-ports and inbound MW
based devices only at the moment.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/test/ntb_perf.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index e75d4fd..99f1522 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -76,6 +76,7 @@
#define DMA_RETRIES 20
#define SZ_4G (1ULL << 32)
#define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */
+#define PIDX 0

MODULE_LICENSE(DRIVER_LICENSE);
MODULE_VERSION(DRIVER_VERSION);
@@ -452,7 +453,7 @@ static void perf_free_mw(struct perf_ctx *perf)
if (!mw->virt_addr)
return;

- ntb_mw_clear_trans(perf->ntb, 0);
+ ntb_mw_clear_trans(perf->ntb, PIDX, 0);
dma_free_coherent(&pdev->dev, mw->buf_size,
mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0;
@@ -488,7 +489,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
mw->buf_size = 0;
}

- rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
+ rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size);
if (rc) {
dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
perf_free_mw(perf);
@@ -515,9 +516,9 @@ static void perf_link_work(struct work_struct *work)
if (max_mw_size && size > max_mw_size)
size = max_mw_size;

- ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
- ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
- ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
+ ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION);

/* now read what peer wrote */
val = ntb_spad_read(ndev, VERSION);
@@ -559,8 +560,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)

mw = &perf->mw;

- rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size,
- &mw->xlat_align, &mw->xlat_align_size);
+ rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
+ &mw->xlat_align_size, NULL);
+ if (rc)
+ return rc;
+
+ rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
if (rc)
return rc;

@@ -764,6 +769,14 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
return -EIO;
}

+ if (!ntb->ops->mw_set_trans) {
+ dev_err(&ntb->dev, "Need inbound MW based NTB API\n");
+ return -EINVAL;
+ }
+
+ if (ntb_peer_port_count(ntb) != 1)
+ dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
+
node = dev_to_node(&pdev->dev);

perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node);
--
2.6.6

2016-11-29 17:17:52

by Serge Semin

[permalink] [raw]
Subject: [PATCH 22/22] NTB Transport: Alter driver to work with two-ports NTB API

The same as for PingPong driver, this driver can't be used with hardware
whithout Scratchpads. Additionally it supports two-ports and inbound MW
based devices only at the moment.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/ntb_transport.c | 43 ++++++++++++++++++++++++++++++-------------
1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 4eb8adb..2390c65 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -94,6 +94,9 @@ MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");

static struct dentry *nt_debugfs_dir;

+/* Only two-ports NTB devices are supported */
+#define PIDX 0
+
struct ntb_queue_entry {
/* ntb_queue list reference */
struct list_head entry;
@@ -682,7 +685,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
if (!mw->virt_addr)
return;

- ntb_mw_clear_trans(nt->ndev, num_mw);
+ ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
dma_free_coherent(&pdev->dev, mw->buff_size,
mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0;
@@ -739,7 +742,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
}

/* Notify HW the memory location of the receive buffer */
- rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
+ rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
+ mw->xlat_size);
if (rc) {
dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
ntb_free_mw(nt, num_mw);
@@ -871,17 +875,17 @@ static void ntb_transport_link_work(struct work_struct *work)
size = max_mw_size;

spad = MW0_SZ_HIGH + (i * 2);
- ntb_peer_spad_write(ndev, spad, upper_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, spad, upper_32_bits(size));

spad = MW0_SZ_LOW + (i * 2);
- ntb_peer_spad_write(ndev, spad, lower_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, spad, lower_32_bits(size));
}

- ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count);
+ ntb_peer_spad_write(ndev, PIDX, NUM_MWS, nt->mw_count);

- ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count);
+ ntb_peer_spad_write(ndev, PIDX, NUM_QPS, nt->qp_count);

- ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION);
+ ntb_peer_spad_write(ndev, PIDX, VERSION, NTB_TRANSPORT_VERSION);

/* Query the remote side for its info */
val = ntb_spad_read(ndev, VERSION);
@@ -957,10 +961,10 @@ static void ntb_qp_link_work(struct work_struct *work)

val = ntb_spad_read(nt->ndev, QP_LINKS);

- ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num));
+ ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num));

/* query remote spad for qp ready bits */
- ntb_peer_spad_read(nt->ndev, QP_LINKS);
+ ntb_peer_spad_read(nt->ndev, PIDX, QP_LINKS);
dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);

/* See if the remote side is up */
@@ -1069,13 +1073,21 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
int node;
int rc, i;

- mw_count = ntb_mw_count(ndev);
+ mw_count = ntb_mw_count(ndev, PIDX);
if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) {
dev_err(&ndev->dev, "Not enough scratch pad registers for %s",
NTB_TRANSPORT_NAME);
return -EIO;
}

+ if (!ndev->ops->mw_set_trans) {
+ dev_err(&ndev->dev, "Inbound MW based NTB API is required\n");
+ return -EINVAL;
+ }
+
+ if (ntb_peer_port_count(ndev) != 1)
+ dev_warn(&ndev->dev, "Multi-port NTB devices unsupported\n");
+
if (ntb_db_is_unsafe(ndev))
dev_dbg(&ndev->dev,
"doorbell is unsafe, proceed anyway...\n");
@@ -1103,8 +1115,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
for (i = 0; i < mw_count; i++) {
mw = &nt->mw_vec[i];

- rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
- &mw->xlat_align, &mw->xlat_align_size);
+ rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
+ &mw->xlat_align_size, NULL);
+ if (rc)
+ goto err1;
+
+ rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
+ &mw->phys_size);
if (rc)
goto err1;

@@ -2124,7 +2141,7 @@ void ntb_transport_link_down(struct ntb_transport_qp *qp)

val = ntb_spad_read(qp->ndev, QP_LINKS);

- ntb_peer_spad_write(qp->ndev, QP_LINKS,
+ ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS,
val & ~BIT(qp->qp_num));

if (qp->link_is_up)
--
2.6.6

2016-11-29 17:19:18

by Serge Semin

[permalink] [raw]
Subject: [PATCH 16/22] NTB AMD: Alter MW interface to fit new NTB API

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 66 ++++++++++++++++++++++++++++++-----------
1 file changed, 49 insertions(+), 17 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index b7c9f67..9b3f78c 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -197,40 +197,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
return 1 << idx;
}

-static int amd_ntb_mw_count(struct ntb_dev *ntb)
+static int amd_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
return ntb_ndev(ntb)->mw_count;
}

-static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base,
- resource_size_t *size,
- resource_size_t *align,
- resource_size_t *align_size)
+static int amd_ntb_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 amd_ntb_dev *ndev = ntb_ndev(ntb);
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;

- if (base)
- *base = pci_resource_start(ndev->ntb.pdev, bar);
-
- if (size)
- *size = pci_resource_len(ndev->ntb.pdev, bar);
+ if (addr_align)
+ *addr_align = SZ_4K;

- if (align)
- *align = SZ_4K;
+ if (size_align)
+ *size_align = 1;

- if (align_size)
- *align_size = 1;
+ if (size_max)
+ *size_max = pci_resource_len(ndev->ntb.pdev, bar);

return 0;
}

-static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
@@ -240,6 +242,9 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base_addr, limit, reg_val;
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;
@@ -312,6 +317,31 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

+static int amd_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ /* The same as for inbound MWs */
+ return ntb_ndev(ntb)->mw_count;
+}
+
+static int amd_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ int bar;
+
+ bar = ndev_mw_to_bar(ndev, idx);
+ if (bar < 0)
+ return bar;
+
+ if (base)
+ *base = pci_resource_start(ndev->ntb.pdev, bar);
+
+ if (size)
+ *size = pci_resource_len(ndev->ntb.pdev, bar);
+
+ return 0;
+}
+
static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
{
return ntb_ndev(ntb)->db_valid_mask;
@@ -466,8 +496,10 @@ static const struct ntb_dev_ops amd_ntb_ops = {
.link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable,
.mw_count = amd_ntb_mw_count,
- .mw_get_range = amd_ntb_mw_get_range,
+ .mw_get_align = amd_ntb_mw_get_align,
.mw_set_trans = amd_ntb_mw_set_trans,
+ .peer_mw_count = amd_ntb_peer_mw_count,
+ .peer_mw_get_addr = amd_ntb_peer_mw_get_addr,
.db_valid_mask = amd_ntb_db_valid_mask,
.db_vector_count = amd_ntb_db_vector_count,
.db_vector_mask = amd_ntb_db_vector_mask,
--
2.6.6

2016-11-29 17:19:29

by Serge Semin

[permalink] [raw]
Subject: [PATCH 20/22] NTB Tool: Alter driver to work with two-ports NTB API

The same as for PingPong driver, this driver can't be used with hardware
whithout Scratchpads. Additionally it supports two-ports and inbound MW
based devices only at the moment.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/test/ntb_tool.c | 87 +++++++++++++++++++++++++++++++--------------
1 file changed, 61 insertions(+), 26 deletions(-)

diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index 61bf2ef..f9329c0 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -119,7 +119,10 @@ MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);

-#define MAX_MWS 16
+/* It is rare to have hadrware with greater than six MWs */
+#define MAX_MWS 6
+/* Only two-ports devices are supported */
+#define PIDX 0

static struct dentry *tool_dbgfs;

@@ -261,14 +264,17 @@ static ssize_t tool_dbfn_write(struct tool_ctx *tc,

static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
size_t size, loff_t *offp,
- u32 (*spad_read_fn)(struct ntb_dev *, int))
+ u32 (*spad_read_fn)(struct ntb_dev *, int),
+ u32 (*spad_peer_read_fn)(struct ntb_dev *, int,
+ int))
{
size_t buf_size;
char *buf;
ssize_t pos, rc;
int i, spad_count;
+ u32 data;

- if (!spad_read_fn)
+ if (!spad_read_fn && !spad_peer_read_fn)
return -EINVAL;

spad_count = ntb_spad_count(tc->ntb);
@@ -287,8 +293,12 @@ static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
pos = 0;

for (i = 0; i < spad_count; ++i) {
+ if (spad_read_fn)
+ data = spad_read_fn(tc->ntb, i);
+ else
+ data = spad_peer_read_fn(tc->ntb, PIDX, i);
pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
- i, spad_read_fn(tc->ntb, i));
+ i, data);
}

rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
@@ -302,7 +312,9 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
const char __user *ubuf,
size_t size, loff_t *offp,
int (*spad_write_fn)(struct ntb_dev *,
- int, u32))
+ int, u32),
+ int (*spad_peer_write_fn)(struct ntb_dev *,
+ int, int, u32))
{
int spad_idx;
u32 spad_val;
@@ -310,7 +322,7 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
int pos, n;
ssize_t rc;

- if (!spad_write_fn) {
+ if (!spad_write_fn || !spad_peer_write_fn) {
dev_dbg(&tc->ntb->dev, "no spad write fn\n");
return -EINVAL;
}
@@ -330,7 +342,11 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
while (n == 2) {
buf_ptr += pos;
- rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
+ if (spad_write_fn)
+ rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
+ else
+ rc = spad_peer_write_fn(tc->ntb, PIDX, spad_idx,
+ spad_val);
if (rc)
break;

@@ -443,7 +459,7 @@ static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
struct tool_ctx *tc = filep->private_data;

return tool_spadfn_read(tc, ubuf, size, offp,
- tc->ntb->ops->spad_read);
+ tc->ntb->ops->spad_read, NULL);
}

static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
@@ -452,7 +468,7 @@ static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
struct tool_ctx *tc = filep->private_data;

return tool_spadfn_write(tc, ubuf, size, offp,
- tc->ntb->ops->spad_write);
+ tc->ntb->ops->spad_write, NULL);
}

static TOOL_FOPS_RDWR(tool_spad_fops,
@@ -464,7 +480,7 @@ static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
{
struct tool_ctx *tc = filep->private_data;

- return tool_spadfn_read(tc, ubuf, size, offp,
+ return tool_spadfn_read(tc, ubuf, size, offp, NULL,
tc->ntb->ops->peer_spad_read);
}

@@ -473,7 +489,7 @@ static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
{
struct tool_ctx *tc = filep->private_data;

- return tool_spadfn_write(tc, ubuf, size, offp,
+ return tool_spadfn_write(tc, ubuf, size, offp, NULL,
tc->ntb->ops->peer_spad_write);
}

@@ -668,28 +684,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
{
int rc;
struct tool_mw *mw = &tc->mws[idx];
- phys_addr_t base;
- resource_size_t size, align, align_size;
+ resource_size_t size, align_addr, align_size;
char buf[16];

if (mw->peer)
return 0;

- rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
- &align_size);
+ rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
+ &align_size, &size);
if (rc)
return rc;

mw->size = min_t(resource_size_t, req_size, size);
- mw->size = round_up(mw->size, align);
+ mw->size = round_up(mw->size, align_addr);
mw->size = round_up(mw->size, align_size);
mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
&mw->peer_dma, GFP_KERNEL);

- if (!mw->peer)
+ if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
return -ENOMEM;

- rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
+ rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
if (rc)
goto err_free_dma;

@@ -716,7 +731,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx)
struct tool_mw *mw = &tc->mws[idx];

if (mw->peer) {
- ntb_mw_clear_trans(tc->ntb, idx);
+ ntb_mw_clear_trans(tc->ntb, PIDX, idx);
dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
mw->peer,
mw->peer_dma);
@@ -742,8 +757,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,

phys_addr_t base;
resource_size_t mw_size;
- resource_size_t align;
+ resource_size_t align_addr;
resource_size_t align_size;
+ resource_size_t max_size;

buf_size = min_t(size_t, size, 512);

@@ -751,8 +767,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
if (!buf)
return -ENOMEM;

- ntb_mw_get_range(mw->tc->ntb, mw->idx,
- &base, &mw_size, &align, &align_size);
+ ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
+ &align_addr, &align_size, &max_size);
+ ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);

off += scnprintf(buf + off, buf_size - off,
"Peer MW %d Information:\n", mw->idx);
@@ -767,13 +784,17 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,

off += scnprintf(buf + off, buf_size - off,
"Alignment \t%lld\n",
- (unsigned long long)align);
+ (unsigned long long)align_addr);

off += scnprintf(buf + off, buf_size - off,
"Size Alignment \t%lld\n",
(unsigned long long)align_size);

off += scnprintf(buf + off, buf_size - off,
+ "Size Max \t%lld\n",
+ (unsigned long long)max_size);
+
+ off += scnprintf(buf + off, buf_size - off,
"Ready \t%c\n",
(mw->peer) ? 'Y' : 'N');

@@ -827,8 +848,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx)
phys_addr_t base;
int rc;

- rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
- NULL, NULL);
+ rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size);
if (rc)
return rc;

@@ -919,6 +939,21 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
if (ntb_spad_is_unsafe(ntb))
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");

+ if (ntb_spad_count(ntb) < 1) {
+ dev_dbg(&ntb->dev, "no enough scratchpads\n");
+ rc = -EINVAL;
+ goto err_tc;
+ }
+
+ if (!ntb->ops->mw_set_trans) {
+ dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
+ rc = -EINVAL;
+ goto err_tc;
+ }
+
+ if (ntb_peer_port_count(ntb) != 1)
+ dev_warn(&ntb->dev, "multi-port NTB devices unsupported\n");
+
tc = kzalloc(sizeof(*tc), GFP_KERNEL);
if (!tc) {
rc = -ENOMEM;
@@ -928,7 +963,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
tc->ntb = ntb;
init_waitqueue_head(&tc->link_wq);

- tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
+ tc->mw_count = min(ntb_mw_count(tc->ntb, PIDX), MAX_MWS);
for (i = 0; i < tc->mw_count; i++) {
rc = tool_init_mw(tc, i);
if (rc)
--
2.6.6

2016-11-29 17:19:38

by Serge Semin

[permalink] [raw]
Subject: [PATCH 19/22] NTB PingPong: Alter driver to work with two-ports NTB API

PingPong driver doesn't do much, but it uses Scratchpads, which can be
unsupported by most of IDT hardware. So I restricted the usage of the
driver with hardware, which supports Scratchpads up until the IDT driver
is ported to the NTB API. When it's done I'll alter the pingpong driver to
support message registers as well.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/test/ntb_pingpong.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
index 4358611..90d3281 100644
--- a/drivers/ntb/test/ntb_pingpong.c
+++ b/drivers/ntb/test/ntb_pingpong.c
@@ -90,6 +90,9 @@ static unsigned long db_init = 0x7;
module_param(db_init, ulong, 0644);
MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");

+/* Only two-ports NTB devices are supported */
+#define PIDX 0
+
struct pp_ctx {
struct ntb_dev *ntb;
u64 db_bits;
@@ -135,7 +138,7 @@ static void pp_ping(unsigned long ctx)
"Ping bits %#llx read %#x write %#x\n",
db_bits, spad_rd, spad_wr);

- ntb_peer_spad_write(pp->ntb, 0, spad_wr);
+ ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr);
ntb_peer_db_set(pp->ntb, db_bits);
ntb_db_clear_mask(pp->ntb, db_mask);

@@ -222,6 +225,12 @@ static int pp_probe(struct ntb_client *client,
}
}

+ if (ntb_spad_count(ntb) < 1) {
+ dev_dbg(&ntb->dev, "no enough scratchpads\n");
+ rc = -EINVAL;
+ goto err_pp;
+ }
+
if (ntb_spad_is_unsafe(ntb)) {
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
if (!unsafe) {
--
2.6.6

2016-11-29 17:19:49

by Serge Semin

[permalink] [raw]
Subject: [PATCH 13/22] NTB Intel: Add T-Platforms copyrights to Intel NTB driver

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/intel/ntb_hw_intel.c | 2 ++
drivers/ntb/hw/intel/ntb_hw_intel.h | 2 ++
2 files changed, 4 insertions(+)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index e308fbe..7785e9d 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -6,6 +6,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -15,6 +16,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
index 7f1da03..099cbdd 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.h
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -6,6 +6,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -15,6 +16,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
--
2.6.6

2016-11-29 17:20:00

by Serge Semin

[permalink] [raw]
Subject: [PATCH 18/22] NTB AMD: Add T-Platforms copyrights to AMD NTB driver

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 2 ++
drivers/ntb/hw/amd/ntb_hw_amd.h | 2 ++
2 files changed, 4 insertions(+)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 3479c2b..2e1aefd 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
* BSD LICENSE
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h
index 993e053..6106f50 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.h
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.h
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
* BSD LICENSE
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
--
2.6.6

2016-11-29 17:20:13

by Serge Semin

[permalink] [raw]
Subject: [PATCH 17/22] NTB AMD: Alter Scratchpads interface to fit new NTB API

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 9b3f78c..3479c2b 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -458,30 +458,30 @@ static int amd_ntb_spad_write(struct ntb_dev *ntb,
return 0;
}

-static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
void __iomem *mmio = ndev->self_mmio;
u32 offset;

- if (idx < 0 || idx >= ndev->spad_count)
+ if (sidx < 0 || sidx >= ndev->spad_count)
return -EINVAL;

- offset = ndev->peer_spad + (idx << 2);
+ offset = ndev->peer_spad + (sidx << 2);
return readl(mmio + AMD_SPAD_OFFSET + offset);
}

-static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
- int idx, u32 val)
+static int amd_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+ int sidx, u32 val)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
void __iomem *mmio = ndev->self_mmio;
u32 offset;

- if (idx < 0 || idx >= ndev->spad_count)
+ if (sidx < 0 || sidx >= ndev->spad_count)
return -EINVAL;

- offset = ndev->peer_spad + (idx << 2);
+ offset = ndev->peer_spad + (sidx << 2);
writel(val, mmio + AMD_SPAD_OFFSET + offset);

return 0;
--
2.6.6

2016-11-29 17:20:23

by Serge Semin

[permalink] [raw]
Subject: [PATCH 15/22] NTB AMD: Add port-related NTB API callback methods

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 72 ++++++++++++++++++++++++++++++-----------
drivers/ntb/hw/amd/ntb_hw_amd.h | 10 ++++++
2 files changed, 63 insertions(+), 19 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 6704327..b7c9f67 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -71,6 +71,33 @@ MODULE_AUTHOR("AMD Inc.");
static const struct file_operations amd_ntb_debugfs_info;
static struct dentry *debugfs_dir;

+static int amd_ntb_port_number(struct ntb_dev *ntb)
+{
+ return ntb->port;
+}
+
+static int amd_ntb_peer_port_count(struct ntb_dev *ntb)
+{
+ return NTB_PEER_CNT;
+}
+
+static int amd_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
+ return (ntb->port == NTB_PORT_PRI ? NTB_PORT_SEC : NTB_PORT_PRI);
+}
+
+static int amd_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ if ((ntb->port == NTB_PORT_PRI && port != NTB_PORT_SEC) ||
+ (ntb->port == NTB_PORT_SEC && port != NTB_PORT_PRI))
+ return -EINVAL;
+
+ return 0;
+}
+
static int amd_link_is_up(struct amd_ntb_dev *ndev)
{
if (!ndev->peer_sta)
@@ -90,7 +117,7 @@ static int amd_link_is_up(struct amd_ntb_dev *ndev)
return 0;
}

-static int amd_ntb_link_is_up(struct ntb_dev *ntb,
+static u64 amd_ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed,
enum ntb_width *width)
{
@@ -130,7 +157,7 @@ static int amd_ntb_link_enable(struct ntb_dev *ntb,
ndev->int_mask &= ~AMD_EVENT_INTMASK;
writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);

- if (ndev->ntb.topo == NTB_TOPO_SEC)
+ if (ndev->ntb.port == NTB_PORT_SEC)
return -EINVAL;
dev_dbg(ndev_dev(ndev), "Enabling Link.\n");

@@ -151,7 +178,7 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb)
ndev->int_mask |= AMD_EVENT_INTMASK;
writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);

- if (ndev->ntb.topo == NTB_TOPO_SEC)
+ if (ndev->ntb.port == NTB_PORT_SEC)
return -EINVAL;
dev_dbg(ndev_dev(ndev), "Enabling Link.\n");

@@ -431,6 +458,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
}

static const struct ntb_dev_ops amd_ntb_ops = {
+ .port_number = amd_ntb_port_number,
+ .peer_port_count = amd_ntb_peer_port_count,
+ .peer_port_number = amd_ntb_peer_port_number,
+ .peer_port_idx = amd_ntb_peer_port_idx,
.link_is_up = amd_ntb_link_is_up,
.link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable,
@@ -697,8 +728,8 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
"NTB Device Information:\n");

off += scnprintf(buf + off, buf_size - off,
- "Connection Topology -\t%s\n",
- ntb_topo_string(ndev->ntb.topo));
+ "Connection Topology -\t%s:%d\n",
+ ntb_topo_string(ndev->ntb.topo), ndev->ntb.port);

off += scnprintf(buf + off, buf_size - off,
"LNK STA -\t\t%#06x\n", ndev->lnk_sta);
@@ -797,6 +828,7 @@ static inline void ndev_init_struct(struct amd_ntb_dev *ndev,
{
ndev->ntb.pdev = pdev;
ndev->ntb.topo = NTB_TOPO_NONE;
+ ndev->ntb.port = NTB_PORT_NONE;
ndev->ntb.ops = &amd_ntb_ops;
ndev->int_mask = AMD_EVENT_INTMASK;
spin_lock_init(&ndev->db_mask_lock);
@@ -876,23 +908,23 @@ static int amd_init_ntb(struct amd_ntb_dev *ndev)
ndev->spad_count = AMD_SPADS_CNT;
ndev->db_count = AMD_DB_CNT;

- switch (ndev->ntb.topo) {
- case NTB_TOPO_PRI:
- case NTB_TOPO_SEC:
+ if (ndev->ntb.topo == NTB_TOPO_P2P) {
ndev->spad_count >>= 1;
- if (ndev->ntb.topo == NTB_TOPO_PRI) {
+ if (ndev->ntb.port == NTB_PORT_PRI) {
ndev->self_spad = 0;
ndev->peer_spad = 0x20;
- } else {
+ } else if (ndev->ntb.port == NTB_PORT_SEC) {
ndev->self_spad = 0x20;
ndev->peer_spad = 0;
+ } else {
+ dev_err(ndev_dev(ndev), "Invalid topology port %d.\n",
+ ndev->ntb.port);
+ return -EINVAL;
}

INIT_DELAYED_WORK(&ndev->hb_timer, amd_link_hb);
schedule_delayed_work(&ndev->hb_timer, AMD_LINK_HB_TIMEOUT);
-
- break;
- default:
+ } else {
dev_err(ndev_dev(ndev), "AMD NTB does not support B2B mode.\n");
return -EINVAL;
}
@@ -905,16 +937,18 @@ static int amd_init_ntb(struct amd_ntb_dev *ndev)
return 0;
}

-static enum ntb_topo amd_get_topo(struct amd_ntb_dev *ndev)
+static void amd_init_topo(struct amd_ntb_dev *ndev)
{
void __iomem *mmio = ndev->self_mmio;
u32 info;

+ ndev->ntb.topo = NTB_TOPO_P2P;
+
info = readl(mmio + AMD_SIDEINFO_OFFSET);
if (info & AMD_SIDE_MASK)
- return NTB_TOPO_SEC;
+ ndev->ntb.port = NTB_PORT_SEC;
else
- return NTB_TOPO_PRI;
+ ndev->ntb.port = NTB_PORT_PRI;
}

static int amd_init_dev(struct amd_ntb_dev *ndev)
@@ -924,9 +958,9 @@ static int amd_init_dev(struct amd_ntb_dev *ndev)

pdev = ndev_pdev(ndev);

- ndev->ntb.topo = amd_get_topo(ndev);
- dev_dbg(ndev_dev(ndev), "AMD NTB topo is %s\n",
- ntb_topo_string(ndev->ntb.topo));
+ amd_init_topo(ndev);
+ dev_dbg(ndev_dev(ndev), "AMD NTB topo is %s:%d\n",
+ ntb_topo_string(ndev->ntb.topo), ndev->ntb.port);

rc = amd_init_ntb(ndev);
if (rc)
diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h
index 2eac3cd..993e053 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.h
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.h
@@ -62,6 +62,10 @@
#define NTB_LNK_STA_SPEED(x) (((x) & NTB_LNK_STA_SPEED_MASK) >> 16)
#define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 20)

+/* port related constants */
+#define NTB_PEER_CNT (1)
+#define NTB_PIDX_MAX (0)
+
#ifndef read64
#ifdef readq
#define read64 readq
@@ -167,6 +171,12 @@ enum {
AMD_PEER_OFFSET = 0x400,
};

+enum amd_ntb_port {
+ NTB_PORT_NONE = -1,
+ NTB_PORT_PRI,
+ NTB_PORT_SEC
+};
+
struct amd_ntb_dev;

struct amd_ntb_vec {
--
2.6.6

2016-11-29 17:20:32

by Serge Semin

[permalink] [raw]
Subject: [PATCH 09/22] NTB Intel: Move link-related methods being first in the driver

See patch 01 for reasoning of this movement.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/intel/ntb_hw_intel.c | 162 ++++++++++++++++++------------------
1 file changed, 81 insertions(+), 81 deletions(-)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 7310a26..d3da0ce 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -836,6 +836,84 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
debugfs_remove_recursive(ndev->debugfs_dir);
}

+static int intel_ntb_link_is_up(struct ntb_dev *ntb,
+ enum ntb_speed *speed,
+ enum ntb_width *width)
+{
+ struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+ if (ndev->reg->link_is_up(ndev)) {
+ if (speed)
+ *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
+ if (width)
+ *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
+ return 1;
+ } else {
+ /* TODO MAYBE: is it possible to observe the link speed and
+ * width while link is training? */
+ if (speed)
+ *speed = NTB_SPEED_NONE;
+ if (width)
+ *width = NTB_WIDTH_NONE;
+ return 0;
+ }
+}
+
+static int intel_ntb_link_enable(struct ntb_dev *ntb,
+ enum ntb_speed max_speed,
+ enum ntb_width max_width)
+{
+ struct intel_ntb_dev *ndev;
+ u32 ntb_ctl;
+
+ ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+
+ dev_dbg(ndev_dev(ndev),
+ "Enabling link with max_speed %d max_width %d\n",
+ max_speed, max_width);
+ if (max_speed != NTB_SPEED_AUTO)
+ dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
+ if (max_width != NTB_WIDTH_AUTO)
+ dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
+
+ ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+ ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
+ ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+ ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+ if (ndev->bar4_split)
+ ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
+ iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+ return 0;
+}
+
+static int intel_ntb_link_disable(struct ntb_dev *ntb)
+{
+ struct intel_ntb_dev *ndev;
+ u32 ntb_cntl;
+
+ ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+
+ dev_dbg(ndev_dev(ndev), "Disabling link\n");
+
+ /* Bring NTB link down */
+ ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+ ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
+ ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
+ if (ndev->bar4_split)
+ ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
+ ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
+ iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+ return 0;
+}
+
static int intel_ntb_mw_count(struct ntb_dev *ntb)
{
return ntb_ndev(ntb)->mw_count;
@@ -972,84 +1050,6 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

-static int intel_ntb_link_is_up(struct ntb_dev *ntb,
- enum ntb_speed *speed,
- enum ntb_width *width)
-{
- struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
- if (ndev->reg->link_is_up(ndev)) {
- if (speed)
- *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
- if (width)
- *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
- return 1;
- } else {
- /* TODO MAYBE: is it possible to observe the link speed and
- * width while link is training? */
- if (speed)
- *speed = NTB_SPEED_NONE;
- if (width)
- *width = NTB_WIDTH_NONE;
- return 0;
- }
-}
-
-static int intel_ntb_link_enable(struct ntb_dev *ntb,
- enum ntb_speed max_speed,
- enum ntb_width max_width)
-{
- struct intel_ntb_dev *ndev;
- u32 ntb_ctl;
-
- ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
-
- dev_dbg(ndev_dev(ndev),
- "Enabling link with max_speed %d max_width %d\n",
- max_speed, max_width);
- if (max_speed != NTB_SPEED_AUTO)
- dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
- if (max_width != NTB_WIDTH_AUTO)
- dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
-
- ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
- ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
- ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
- ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
- if (ndev->bar4_split)
- ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
- iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
- return 0;
-}
-
-static int intel_ntb_link_disable(struct ntb_dev *ntb)
-{
- struct intel_ntb_dev *ndev;
- u32 ntb_cntl;
-
- ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
-
- dev_dbg(ndev_dev(ndev), "Disabling link\n");
-
- /* Bring NTB link down */
- ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
- ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
- ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
- if (ndev->bar4_split)
- ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
- ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
- iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
- return 0;
-}
-
static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
{
return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
@@ -2259,12 +2259,12 @@ static struct intel_b2b_addr xeon_b2b_dsd_addr = {

/* operations for primary side of local ntb */
static const struct ntb_dev_ops intel_ntb_ops = {
- .mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
- .mw_set_trans = intel_ntb_mw_set_trans,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable,
+ .mw_count = intel_ntb_mw_count,
+ .mw_get_range = intel_ntb_mw_get_range,
+ .mw_set_trans = intel_ntb_mw_set_trans,
.db_is_unsafe = intel_ntb_db_is_unsafe,
.db_valid_mask = intel_ntb_db_valid_mask,
.db_vector_count = intel_ntb_db_vector_count,
--
2.6.6

2016-11-29 17:20:41

by Serge Semin

[permalink] [raw]
Subject: [PATCH 14/22] NTB AMD: Move link-related methods being first in the driver

See patch 01 for reasoning of this movement.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 188 ++++++++++++++++++++--------------------
1 file changed, 94 insertions(+), 94 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 6ccba0d..6704327 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -71,6 +71,97 @@ MODULE_AUTHOR("AMD Inc.");
static const struct file_operations amd_ntb_debugfs_info;
static struct dentry *debugfs_dir;

+static int amd_link_is_up(struct amd_ntb_dev *ndev)
+{
+ if (!ndev->peer_sta)
+ return NTB_LNK_STA_ACTIVE(ndev->cntl_sta);
+
+ /* If peer_sta is reset or D0 event, the ISR has
+ * started a timer to check link status of hardware.
+ * So here just clear status bit. And if peer_sta is
+ * D3 or PME_TO, D0/reset event will be happened when
+ * system wakeup/poweron, so do nothing here.
+ */
+ if (ndev->peer_sta & AMD_PEER_RESET_EVENT)
+ ndev->peer_sta &= ~AMD_PEER_RESET_EVENT;
+ else if (ndev->peer_sta & AMD_PEER_D0_EVENT)
+ ndev->peer_sta = 0;
+
+ return 0;
+}
+
+static int amd_ntb_link_is_up(struct ntb_dev *ntb,
+ enum ntb_speed *speed,
+ enum ntb_width *width)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ int ret = 0;
+
+ if (amd_link_is_up(ndev)) {
+ if (speed)
+ *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
+ if (width)
+ *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
+
+ dev_dbg(ndev_dev(ndev), "link is up.\n");
+
+ ret = 1;
+ } else {
+ if (speed)
+ *speed = NTB_SPEED_NONE;
+ if (width)
+ *width = NTB_WIDTH_NONE;
+
+ dev_dbg(ndev_dev(ndev), "link is down.\n");
+ }
+
+ return ret;
+}
+
+static int amd_ntb_link_enable(struct ntb_dev *ntb,
+ enum ntb_speed max_speed,
+ enum ntb_width max_width)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ void __iomem *mmio = ndev->self_mmio;
+ u32 ntb_ctl;
+
+ /* Enable event interrupt */
+ ndev->int_mask &= ~AMD_EVENT_INTMASK;
+ writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+ dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+
+ ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
+ ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
+ writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
+
+ return 0;
+}
+
+static int amd_ntb_link_disable(struct ntb_dev *ntb)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ void __iomem *mmio = ndev->self_mmio;
+ u32 ntb_ctl;
+
+ /* Disable event interrupt */
+ ndev->int_mask |= AMD_EVENT_INTMASK;
+ writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+ dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+
+ ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
+ ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
+ writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
+
+ return 0;
+}
+
static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
{
if (idx < 0 || idx > ndev->mw_count)
@@ -194,97 +285,6 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

-static int amd_link_is_up(struct amd_ntb_dev *ndev)
-{
- if (!ndev->peer_sta)
- return NTB_LNK_STA_ACTIVE(ndev->cntl_sta);
-
- /* If peer_sta is reset or D0 event, the ISR has
- * started a timer to check link status of hardware.
- * So here just clear status bit. And if peer_sta is
- * D3 or PME_TO, D0/reset event will be happened when
- * system wakeup/poweron, so do nothing here.
- */
- if (ndev->peer_sta & AMD_PEER_RESET_EVENT)
- ndev->peer_sta &= ~AMD_PEER_RESET_EVENT;
- else if (ndev->peer_sta & AMD_PEER_D0_EVENT)
- ndev->peer_sta = 0;
-
- return 0;
-}
-
-static int amd_ntb_link_is_up(struct ntb_dev *ntb,
- enum ntb_speed *speed,
- enum ntb_width *width)
-{
- struct amd_ntb_dev *ndev = ntb_ndev(ntb);
- int ret = 0;
-
- if (amd_link_is_up(ndev)) {
- if (speed)
- *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
- if (width)
- *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
-
- dev_dbg(ndev_dev(ndev), "link is up.\n");
-
- ret = 1;
- } else {
- if (speed)
- *speed = NTB_SPEED_NONE;
- if (width)
- *width = NTB_WIDTH_NONE;
-
- dev_dbg(ndev_dev(ndev), "link is down.\n");
- }
-
- return ret;
-}
-
-static int amd_ntb_link_enable(struct ntb_dev *ntb,
- enum ntb_speed max_speed,
- enum ntb_width max_width)
-{
- struct amd_ntb_dev *ndev = ntb_ndev(ntb);
- void __iomem *mmio = ndev->self_mmio;
- u32 ntb_ctl;
-
- /* Enable event interrupt */
- ndev->int_mask &= ~AMD_EVENT_INTMASK;
- writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
- dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
-
- ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
- ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
- writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
-
- return 0;
-}
-
-static int amd_ntb_link_disable(struct ntb_dev *ntb)
-{
- struct amd_ntb_dev *ndev = ntb_ndev(ntb);
- void __iomem *mmio = ndev->self_mmio;
- u32 ntb_ctl;
-
- /* Disable event interrupt */
- ndev->int_mask |= AMD_EVENT_INTMASK;
- writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
- dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
-
- ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
- ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
- writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
-
- return 0;
-}
-
static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
{
return ntb_ndev(ntb)->db_valid_mask;
@@ -431,12 +431,12 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
}

static const struct ntb_dev_ops amd_ntb_ops = {
- .mw_count = amd_ntb_mw_count,
- .mw_get_range = amd_ntb_mw_get_range,
- .mw_set_trans = amd_ntb_mw_set_trans,
.link_is_up = amd_ntb_link_is_up,
.link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable,
+ .mw_count = amd_ntb_mw_count,
+ .mw_get_range = amd_ntb_mw_get_range,
+ .mw_set_trans = amd_ntb_mw_set_trans,
.db_valid_mask = amd_ntb_db_valid_mask,
.db_vector_count = amd_ntb_db_vector_count,
.db_vector_mask = amd_ntb_db_vector_mask,
--
2.6.6

2016-11-29 17:20:50

by Serge Semin

[permalink] [raw]
Subject: [PATCH 08/22] NTB: Add T-Platforms copyrights to NTB API

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/ntb.c | 2 ++
include/linux/ntb.h | 2 ++
2 files changed, 4 insertions(+)

diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 4b2cc60..06574f8 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
* BSD LICENSE
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 8b19327..9edd9dc 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
* BSD LICENSE
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
--
2.6.6

2016-11-29 17:21:00

by Serge Semin

[permalink] [raw]
Subject: [PATCH 12/22] NTB Intel: Alter Scratchpads interface to fit new NTB API

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/intel/ntb_hw_intel.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index c41da32..e308fbe 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1235,30 +1235,30 @@ static int intel_ntb_spad_write(struct ntb_dev *ntb,
ndev->self_reg->spad);
}

-static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr,
+ return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
ndev->peer_reg->spad);
}

-static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_read(ndev, idx,
+ return ndev_spad_read(ndev, sidx,
ndev->peer_mmio +
ndev->peer_reg->spad);
}

-static int intel_ntb_peer_spad_write(struct ntb_dev *ntb,
- int idx, u32 val)
+static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+ int sidx, u32 val)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_write(ndev, idx, val,
+ return ndev_spad_write(ndev, sidx, val,
ndev->peer_mmio +
ndev->peer_reg->spad);
}
--
2.6.6

2016-11-29 17:21:11

by Serge Semin

[permalink] [raw]
Subject: [PATCH 11/22] NTB Intel: Alter MW interface to fit new NTB API

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/intel/ntb_hw_intel.c | 79 ++++++++++++++++++++++++++++---------
1 file changed, 61 insertions(+), 18 deletions(-)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 724ccfe..c41da32 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -941,20 +941,26 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
return 0;
}

-static int intel_ntb_mw_count(struct ntb_dev *ntb)
+static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
return ntb_ndev(ntb)->mw_count;
}

-static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base,
- resource_size_t *size,
- resource_size_t *align,
- resource_size_t *align_size)
+static int intel_ntb_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 intel_ntb_dev *ndev = ntb_ndev(ntb);
+ resource_size_t bar_size, mw_size;
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -962,24 +968,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
if (bar < 0)
return bar;

- if (base)
- *base = pci_resource_start(ndev->ntb.pdev, bar) +
- (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+ bar_size = pci_resource_len(ndev->ntb.pdev, bar);

- if (size)
- *size = pci_resource_len(ndev->ntb.pdev, bar) -
- (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+ if (idx == ndev->b2b_idx)
+ mw_size = bar_size - ndev->b2b_off;
+ else
+ mw_size = bar_size;

- if (align)
- *align = pci_resource_len(ndev->ntb.pdev, bar);
+ if (addr_align)
+ *addr_align = pci_resource_len(ndev->ntb.pdev, bar);

- if (align_size)
- *align_size = 1;
+ if (size_align)
+ *size_align = 1;
+
+ if (size_max)
+ *size_max = mw_size;

return 0;
}

-static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);
@@ -989,6 +997,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base, limit, reg_val;
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -1077,6 +1088,36 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

+static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ /* Numbers of inbound and outbound memory windows match */
+ return ntb_ndev(ntb)->mw_count;
+}
+
+static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+ int bar;
+
+ if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+ idx += 1;
+
+ bar = ndev_mw_to_bar(ndev, idx);
+ if (bar < 0)
+ return bar;
+
+ if (base)
+ *base = pci_resource_start(ndev->ntb.pdev, bar) +
+ (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+ if (size)
+ *size = pci_resource_len(ndev->ntb.pdev, bar) -
+ (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+ return 0;
+}
+
static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
{
return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
@@ -2296,8 +2337,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
.link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable,
.mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
+ .mw_get_align = intel_ntb_mw_get_align,
.mw_set_trans = intel_ntb_mw_set_trans,
+ .peer_mw_count = intel_ntb_peer_mw_count,
+ .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
.db_is_unsafe = intel_ntb_db_is_unsafe,
.db_valid_mask = intel_ntb_db_valid_mask,
.db_vector_count = intel_ntb_db_vector_count,
--
2.6.6

2016-11-29 17:22:35

by Serge Semin

[permalink] [raw]
Subject: [PATCH 05/22] NTB: Alter Scratchpads NTB API to support multi-ports interface

Even though there is no any real NTB hardware, which would have both more
than two ports and Scratchpad registers, it is logically correct to have
Scratchpad API accepting a peer port index as well. Intel/AMD drivers used
to utilize Primary and Secondary topology to split Scratchpad between
connected root devices. Since port-index API replaced Primary and Secondary
topology, Intel/AMD NTB hadrware drivers can use device port to determine
which Scratchpad registers actually belong to local and peer devices.
The same approach can be used if some potential hardware in future will be
multi-port and have some set of Scratchpads.

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 46 ++++++++++++++++++++++++++--------------------
1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 59de1f6..fc9d034 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -268,13 +268,14 @@ struct ntb_dev_ops {
int (*spad_is_unsafe)(struct ntb_dev *ntb);
int (*spad_count)(struct ntb_dev *ntb);

- u32 (*spad_read)(struct ntb_dev *ntb, int idx);
- int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+ u32 (*spad_read)(struct ntb_dev *ntb, int sidx);
+ int (*spad_write)(struct ntb_dev *ntb, int sidx, u32 val);

- int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
+ int (*peer_spad_addr)(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr);
- u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
- int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+ u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
+ int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
+ u32 val);

int (*msg_count)(struct ntb_dev *ntb);
u64 (*msg_inbits)(struct ntb_dev *ntb);
@@ -1201,6 +1202,7 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
* @ntb: NTB device context.
*
* Hardware and topology may support a different number of scratchpads.
+ * Although it must be the same for all ports per NTB device.
*
* Return: the number of scratchpads.
*/
@@ -1215,42 +1217,43 @@ static inline int ntb_spad_count(struct ntb_dev *ntb)
/**
* ntb_spad_read() - read the local scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @sidx: Scratchpad index.
*
* Read the local scratchpad register, and return the value.
*
* Return: The value of the local scratchpad register.
*/
-static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_spad_read(struct ntb_dev *ntb, int sidx)
{
if (!ntb->ops->spad_read)
return ~(u32)0;

- return ntb->ops->spad_read(ntb, idx);
+ return ntb->ops->spad_read(ntb, sidx);
}

/**
* ntb_spad_write() - write the local scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @sidx: Scratchpad index.
* @val: Scratchpad value.
*
* Write the value to the local scratchpad register.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
{
if (!ntb->ops->spad_write)
return -EINVAL;

- return ntb->ops->spad_write(ntb, idx, val);
+ return ntb->ops->spad_write(ntb, sidx, val);
}

/**
* ntb_peer_spad_addr() - address of the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
* @spad_addr: OUT - The address of the peer scratchpad register.
*
* Return the address of the peer doorbell register. This may be used, for
@@ -1258,48 +1261,51 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr)
{
if (!ntb->ops->peer_spad_addr)
return -EINVAL;

- return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
+ return ntb->ops->peer_spad_addr(ntb, pidx, sidx, spad_addr);
}

/**
* ntb_peer_spad_read() - read the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
*
* Read the peer scratchpad register, and return the value.
*
* Return: The value of the local scratchpad register.
*/
-static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
if (!ntb->ops->peer_spad_read)
return ~(u32)0;

- return ntb->ops->peer_spad_read(ntb, idx);
+ return ntb->ops->peer_spad_read(ntb, pidx, sidx);
}

/**
* ntb_peer_spad_write() - write the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
* @val: Scratchpad value.
*
* Write the value to the peer scratchpad register.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
+ u32 val)
{
if (!ntb->ops->peer_spad_write)
return -EINVAL;

- return ntb->ops->peer_spad_write(ntb, idx, val);
+ return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
}

/**
--
2.6.6

2016-11-29 17:22:42

by Serge Semin

[permalink] [raw]
Subject: [PATCH 04/22] NTB: Add messaging NTB API

IDT PCIe-switches have message registers to communicate with peer devices.
This patch adds new NTB API callback methods, which can be used to utilize
these registers functionality.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/ntb.c | 13 +++
include/linux/ntb.h | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 241 insertions(+), 8 deletions(-)

diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 2e25307..4b2cc60 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -191,6 +191,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
}
EXPORT_SYMBOL(ntb_db_event);

+void ntb_msg_event(struct ntb_dev *ntb)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+ {
+ if (ntb->ctx_ops && ntb->ctx_ops->msg_event)
+ ntb->ctx_ops->msg_event(ntb->ctx);
+ }
+ spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_msg_event);
+
static int ntb_probe(struct device *dev)
{
struct ntb_dev *ntb;
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 4a150b5..59de1f6 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -146,10 +146,12 @@ static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops)
* struct ntb_ctx_ops - ntb driver context operations
* @link_event: See ntb_link_event().
* @db_event: See ntb_db_event().
+ * @msg_event: See ntb_msg_event().
*/
struct ntb_ctx_ops {
void (*link_event)(void *ctx);
void (*db_event)(void *ctx, int db_vector);
+ void (*msg_event)(void *ctx);
};

static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
@@ -158,6 +160,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
return
/* ops->link_event && */
/* ops->db_event && */
+ /* ops->msg_event && */
1;
}

@@ -202,6 +205,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_addr: See ntb_peer_spad_addr().
* @peer_spad_read: See ntb_peer_spad_read().
* @peer_spad_write: See ntb_peer_spad_write().
+ * @msg_count: See ntb_msg_count().
+ * @msg_inbits: See ntb_msg_inbits().
+ * @msg_outbits: See ntb_msg_outbits().
+ * @msg_read_sts: See ntb_msg_read_sts().
+ * @msg_clear_sts: See ntb_msg_clear_sts().
+ * @msg_set_mask: See ntb_msg_set_mask().
+ * @msg_clear_mask: See ntb_msg_clear_mask().
+ * @msg_read: See ntb_msg_read().
+ * @msg_write: See ntb_msg_write().
*/
struct ntb_dev_ops {
int (*port_number)(struct ntb_dev *ntb);
@@ -263,6 +275,16 @@ struct ntb_dev_ops {
phys_addr_t *spad_addr);
u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+
+ int (*msg_count)(struct ntb_dev *ntb);
+ u64 (*msg_inbits)(struct ntb_dev *ntb);
+ u64 (*msg_outbits)(struct ntb_dev *ntb);
+ u64 (*msg_read_sts)(struct ntb_dev *ntb);
+ int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits);
+ int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg);
+ int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg);
};

static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@@ -304,13 +326,22 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
- /* ops->spad_is_unsafe && */
- ops->spad_count &&
- ops->spad_read &&
- ops->spad_write &&
- /* ops->peer_spad_addr && */
- /* ops->peer_spad_read && */
- ops->peer_spad_write &&
+ ((/* ops->spad_is_unsafe && */
+ ops->spad_count &&
+ ops->spad_read &&
+ ops->spad_write &&
+ /* ops->peer_spad_addr && */
+ /* ops->peer_spad_read && */
+ ops->peer_spad_write) ||
+ (ops->msg_count &&
+ ops->msg_inbits &&
+ ops->msg_outbits &&
+ ops->msg_read_sts &&
+ ops->msg_clear_sts &&
+ /* ops->msg_set_mask && */
+ /* ops->msg_clear_mask && */
+ ops->msg_read &&
+ ops->msg_write)) &&
1;
}

@@ -456,6 +487,18 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_msg_event() - notify driver context of a message event
+ * @ntb: NTB device context.
+ *
+ * Notify the driver context of a message event. If hardware supports
+ * message registers, this event indicates, that a new message arrived in
+ * some incoming message register or last sent message couldn't be delivered.
+ * The events can be masked/unmasked by the methods ntb_msg_set_mask() and
+ * ntb_msg_clear_mask().
+ */
+void ntb_msg_event(struct ntb_dev *ntb);
+
+/**
* ntb_port_number() - get the local port number
* @ntb: NTB device context.
*
@@ -1154,7 +1197,7 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
}

/**
- * ntb_mw_count() - get the number of scratchpads
+ * ntb_spad_count() - get the number of scratchpads
* @ntb: NTB device context.
*
* Hardware and topology may support a different number of scratchpads.
@@ -1163,6 +1206,9 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
*/
static inline int ntb_spad_count(struct ntb_dev *ntb)
{
+ if (!ntb->ops->spad_count)
+ return 0;
+
return ntb->ops->spad_count(ntb);
}

@@ -1177,6 +1223,9 @@ static inline int ntb_spad_count(struct ntb_dev *ntb)
*/
static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
{
+ if (!ntb->ops->spad_read)
+ return ~(u32)0;
+
return ntb->ops->spad_read(ntb, idx);
}

@@ -1192,6 +1241,9 @@ static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
*/
static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
{
+ if (!ntb->ops->spad_write)
+ return -EINVAL;
+
return ntb->ops->spad_write(ntb, idx, val);
}

@@ -1226,6 +1278,9 @@ static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
*/
static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
{
+ if (!ntb->ops->peer_spad_read)
+ return ~(u32)0;
+
return ntb->ops->peer_spad_read(ntb, idx);
}

@@ -1241,7 +1296,172 @@ static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
*/
static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
{
+ if (!ntb->ops->peer_spad_write)
+ return -EINVAL;
+
return ntb->ops->peer_spad_write(ntb, idx, val);
}

+/**
+ * ntb_msg_count() - get the number of message registers
+ * @ntb: NTB device context.
+ *
+ * Hardware may support a different number of messge registers.
+ *
+ * Return: the number of message registers.
+ */
+static inline int ntb_msg_count(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_count)
+ return 0;
+
+ return ntb->ops->msg_count(ntb);
+}
+
+/**
+ * ntb_msg_inbits() - get a bitsfield of inbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitsfield of status and mask registers, which related
+ * to inbound message registers.
+ *
+ * Return: bitsfield of inbound message registers.
+ */
+static inline u64 ntb_msg_inbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_inbits)
+ return 0;
+
+ return ntb->ops->msg_inbits(ntb);
+}
+
+/**
+ * ntb_msg_outbits() - get a bitsfield of outbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitsfield of status and mask registers, which related
+ * to outbound message registers.
+ *
+ * Return: bitsfield of outbound message registers.
+ */
+static inline u64 ntb_msg_outbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_outbits)
+ return 0;
+
+ return ntb->ops->msg_outbits(ntb);
+}
+
+/**
+ * ntb_msg_read_sts() - read the message registers status
+ * @ntb: NTB device context.
+ *
+ * Read the status of message register. Inbound and outbound message registers
+ * related bits can be filetered by masks retrieved from ntb_msg_inbits() and
+ * ntb_msg_outbits().
+ *
+ * Return: status bits of message registers
+ */
+static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_read_sts)
+ return 0;
+
+ return ntb->ops->msg_read_sts(ntb);
+}
+
+/**
+ * ntb_msg_clear_sts() - clear status bits of message registers
+ * @ntb: NTB device context.
+ * @sts_bits: Status bits to clear.
+ *
+ * Clear bits in the status register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
+{
+ if (!ntb->ops->msg_clear_sts)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_sts(ntb, sts_bits);
+}
+
+/**
+ * ntb_msg_set_mask() - set mask of message register status bits
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits.
+ *
+ * Mask the message registers status bits from raising the message event.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_set_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_set_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_clear_mask() - clear message registers mask
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits to clear.
+ *
+ * Clear bits in the message events mask register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_clear_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_read() - read message register with specified index
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: OUT - Port index of peer device a message retrieved from
+ * @msg: OUT - Data
+ *
+ * Read data from the specified message register. Source port index of a
+ * message is retrieved as well.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx,
+ u32 *msg)
+{
+ if (!ntb->ops->msg_read)
+ return -EINVAL;
+
+ return ntb->ops->msg_read(ntb, midx, pidx, msg);
+}
+
+/**
+ * ntb_msg_write() - write data to the specified message register
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: Port index of peer device a message being sent to
+ * @msg: Data to send
+ *
+ * Send data to a specified peer device using the defined message register.
+ * Message event can be raised if the midx registers isn't empty while
+ * calling this method and the corresponding interrupt isn't masked.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx,
+ u32 msg)
+{
+ if (!ntb->ops->msg_write)
+ return -EINVAL;
+
+ return ntb->ops->msg_write(ntb, midx, pidx, msg);
+}
+
#endif
--
2.6.6

2016-11-29 17:22:53

by Serge Semin

[permalink] [raw]
Subject: [PATCH 06/22] NTB: Slightly alter link state NTB API

Some minor changes of link state NTB API. Particularly link_is_up()
method from now shall return a bitfield of link states for all accessible
port indexes.

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index fc9d034..a59a155 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -221,7 +221,7 @@ struct ntb_dev_ops {
int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
int (*peer_port_idx)(struct ntb_dev *ntb, int port);

- int (*link_is_up)(struct ntb_dev *ntb,
+ u64 (*link_is_up)(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width);
int (*link_enable)(struct ntb_dev *ntb,
enum ntb_speed max_speed, enum ntb_width max_width);
@@ -567,25 +567,26 @@ static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
* state once after every link event. It is safe to query the link state in
* the context of the link event callback.
*
- * Return: One if the link is up, zero if the link is down, otherwise a
- * negative value indicating the error number.
+ * Return: bitfield of indexed ports link state: bit is set/cleared if the
+ * link is up/down respectively, otherwise a negative value indicating
+ * an error number.
*/
-static inline int ntb_link_is_up(struct ntb_dev *ntb,
+static inline u64 ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width)
{
return ntb->ops->link_is_up(ntb, speed, width);
}

/**
- * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * ntb_link_enable() - enable the link of the ntb
* @ntb: NTB device context.
* @max_speed: The maximum link speed expressed as PCIe generation number.
* @max_width: The maximum link width expressed as the number of PCIe lanes.
*
- * Enable the link on the secondary side of the ntb. This can only be done
- * from the primary side of the ntb in primary or b2b topology. The ntb device
- * should train the link to its maximum speed and width, or the requested speed
- * and width, whichever is smaller, if supported.
+ * Enable the NTB/PCIe link on the local or remote (for bridge-to-bridge
+ * topology) side of the bridge. The ntb device should train the link to its
+ * maximum speed and width, or the requested speed and width, whichever is
+ * smaller, if supported.
*
* Return: Zero on success, otherwise an error number.
*/
@@ -597,14 +598,14 @@ static inline int ntb_link_enable(struct ntb_dev *ntb,
}

/**
- * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * ntb_link_disable() - disable the link of the ntb
* @ntb: NTB device context.
*
- * Disable the link on the secondary side of the ntb. This can only be
- * done from the primary side of the ntb in primary or b2b topology. The ntb
- * device should disable the link. Returning from this call must indicate that
- * a barrier has passed, though with no more writes may pass in either
- * direction across the link, except if this call returns an error number.
+ * Disable the link on the local or remote (for b2b topology) of the ntb.
+ * The ntb device should disable the link. Returning from this call must
+ * indicate that a barrier has passed, though with no more writes may pass in
+ * either direction across the link, except if this call returns an error
+ * number.
*
* Return: Zero on success, otherwise an error number.
*/
--
2.6.6

2016-11-29 17:23:08

by Serge Semin

[permalink] [raw]
Subject: [PATCH 07/22] NTB: Fix a few ntb.h issues

Fix some minor issues found in ntb.h file.

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index a59a155..8b19327 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -90,6 +90,7 @@ static inline char *ntb_topo_string(enum ntb_topo topo)
* @NTB_SPEED_GEN1: Link is trained to gen1 speed.
* @NTB_SPEED_GEN2: Link is trained to gen2 speed.
* @NTB_SPEED_GEN3: Link is trained to gen3 speed.
+ * @NTB_SPEED_GEN4: Link is trained to gen4 speed.
*/
enum ntb_speed {
NTB_SPEED_AUTO = -1,
@@ -97,6 +98,7 @@ enum ntb_speed {
NTB_SPEED_GEN1 = 1,
NTB_SPEED_GEN2 = 2,
NTB_SPEED_GEN3 = 3,
+ NTB_SPEED_GEN4 = 4
};

/**
@@ -292,13 +294,18 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ /* Port operations are required */
ops->port_number &&
ops->peer_port_count &&
ops->peer_port_number &&
ops->peer_port_idx &&
+
+ /* Link operations are requiered */
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
+
+ /* One or both MW interfaces should be developed */
ops->mw_count &&
ops->mw_get_align &&
(ops->mw_set_trans ||
@@ -308,12 +315,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->peer_mw_get_addr &&
/* ops->peer_mw_clear_trans && */

+ /* Doorbell operations are mostly required */
/* ops->db_is_unsafe && */
ops->db_valid_mask &&
-
/* both set, or both unset */
(!ops->db_vector_count == !ops->db_vector_mask) &&
-
ops->db_read &&
/* ops->db_set && */
ops->db_clear &&
@@ -327,6 +333,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
+
+ /* Scrachpad or messaging interfaces should be developed */
((/* ops->spad_is_unsafe && */
ops->spad_count &&
ops->spad_read &&
@@ -355,13 +363,12 @@ struct ntb_client {
struct device_driver drv;
const struct ntb_client_ops ops;
};
-
#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)

/**
* struct ntb_device - ntb device
* @dev: Linux device object.
- * @pdev: Pci device entry of the ntb.
+ * @pdev: PCI device entry of the ntb.
* @topo: Detected topology of the ntb.
* @port: Local port of the ntb.
* @ops: See &ntb_dev_ops.
@@ -384,7 +391,6 @@ struct ntb_dev {
/* block unregister until device is fully released */
struct completion released;
};
-
#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)

/**
@@ -481,7 +487,7 @@ void ntb_link_event(struct ntb_dev *ntb);
* multiple interrupt vectors for doorbells, the vector number indicates which
* vector received the interrupt. The vector number is relative to the first
* vector used for doorbells, starting at zero, and must be less than
- ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
+ * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
* doorbell bits need service, and ntb_db_vector_mask() to determine which of
* those bits are associated with the vector number.
*/
--
2.6.6

2016-11-29 17:23:17

by Serge Semin

[permalink] [raw]
Subject: [PATCH 10/22] NTB Intel: Add port-related NTB API callback methods

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/intel/ntb_hw_intel.c | 195 +++++++++++++++++++++---------------
drivers/ntb/hw/intel/ntb_hw_intel.h | 10 ++
2 files changed, 124 insertions(+), 81 deletions(-)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index d3da0ce..724ccfe 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -213,7 +213,7 @@ static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev)

/* Only B2B has a workaround to avoid SDOORBELL */
if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP)
- if (!ntb_topo_is_b2b(ndev->ntb.topo))
+ if (ndev->ntb.topo != NTB_TOPO_B2B)
ndev->unsafe_flags |= NTB_UNSAFE_DB;

/* No low level workaround to avoid SB01BASE */
@@ -574,8 +574,8 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
"NTB Device Information:\n");

off += scnprintf(buf + off, buf_size - off,
- "Connection Topology -\t%s\n",
- ntb_topo_string(ndev->ntb.topo));
+ "Connection Topology -\t%s:%d\n",
+ ntb_topo_string(ndev->ntb.topo), ndev->ntb.port);

if (ndev->b2b_idx != UINT_MAX) {
off += scnprintf(buf + off, buf_size - off,
@@ -707,7 +707,7 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
}

if (pdev_is_xeon(pdev)) {
- if (ntb_topo_is_b2b(ndev->ntb.topo)) {
+ if (ndev->ntb.topo == NTB_TOPO_B2B) {
off += scnprintf(buf + off, buf_size - off,
"\nNTB Outgoing B2B XLAT:\n");

@@ -836,7 +836,34 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
debugfs_remove_recursive(ndev->debugfs_dir);
}

-static int intel_ntb_link_is_up(struct ntb_dev *ntb,
+static int intel_ntb_port_number(struct ntb_dev *ntb)
+{
+ return ntb->port;
+}
+
+static int intel_ntb_peer_port_count(struct ntb_dev *ntb)
+{
+ return NTB_PEER_CNT;
+}
+
+static int intel_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
+ return (ntb->port == NTB_PORT_PRI ? NTB_PORT_SEC : NTB_PORT_PRI);
+}
+
+static int intel_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ if ((ntb->port == NTB_PORT_PRI && port != NTB_PORT_SEC) ||
+ (ntb->port == NTB_PORT_SEC && port != NTB_PORT_PRI))
+ return -EINVAL;
+
+ return 0;
+}
+
+static u64 intel_ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed,
enum ntb_width *width)
{
@@ -868,7 +895,7 @@ static int intel_ntb_link_enable(struct ntb_dev *ntb,

ndev = container_of(ntb, struct intel_ntb_dev, ntb);

- if (ndev->ntb.topo == NTB_TOPO_SEC)
+ if (ndev->ntb.topo == NTB_TOPO_P2P && ndev->ntb.port == NTB_PORT_SEC)
return -EINVAL;

dev_dbg(ndev_dev(ndev),
@@ -897,7 +924,7 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)

ndev = container_of(ntb, struct intel_ntb_dev, ntb);

- if (ndev->ntb.topo == NTB_TOPO_SEC)
+ if (ndev->ntb.topo == NTB_TOPO_P2P && ndev->ntb.port == NTB_PORT_SEC)
return -EINVAL;

dev_dbg(ndev_dev(ndev), "Disabling link\n");
@@ -1241,27 +1268,32 @@ static int atom_link_is_err(struct intel_ntb_dev *ndev)
return 0;
}

-static inline enum ntb_topo atom_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd)
+static inline int atom_ppd_init_topo(struct intel_ntb_dev *ndev, u32 ppd)
{
switch (ppd & ATOM_PPD_TOPO_MASK) {
case ATOM_PPD_TOPO_B2B_USD:
dev_dbg(ndev_dev(ndev), "PPD %d B2B USD\n", ppd);
- return NTB_TOPO_B2B_USD;
-
+ ndev->ntb.topo = NTB_TOPO_B2B;
+ ndev->ntb.port = NTB_PORT_PRI;
+ return 0;
case ATOM_PPD_TOPO_B2B_DSD:
dev_dbg(ndev_dev(ndev), "PPD %d B2B DSD\n", ppd);
- return NTB_TOPO_B2B_DSD;
+ ndev->ntb.topo = NTB_TOPO_B2B;
+ ndev->ntb.port = NTB_PORT_SEC;
+ return 0;

case ATOM_PPD_TOPO_PRI_USD:
case ATOM_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */
case ATOM_PPD_TOPO_SEC_USD:
case ATOM_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */
- dev_dbg(ndev_dev(ndev), "PPD %d non B2B disabled\n", ppd);
- return NTB_TOPO_NONE;
+ dev_err(ndev_dev(ndev), "PPD %d non B2B disabled\n", ppd);
+ ndev->ntb.topo = NTB_TOPO_NONE;
+ ndev->ntb.port = NTB_PORT_NONE;
+ return -EINVAL;
}

- dev_dbg(ndev_dev(ndev), "PPD %d invalid\n", ppd);
- return NTB_TOPO_NONE;
+ dev_err(ndev_dev(ndev), "PPD %d invalid\n", ppd);
+ return -EINVAL;
}

static void atom_link_hb(struct work_struct *work)
@@ -1369,9 +1401,7 @@ static int atom_init_ntb(struct intel_ntb_dev *ndev)
ndev->spad_count = ATOM_SPAD_COUNT;
ndev->db_count = ATOM_DB_COUNT;

- switch (ndev->ntb.topo) {
- case NTB_TOPO_B2B_USD:
- case NTB_TOPO_B2B_DSD:
+ if (ndev->ntb.topo == NTB_TOPO_B2B) {
ndev->self_reg = &atom_pri_reg;
ndev->peer_reg = &atom_b2b_reg;
ndev->xlat_reg = &atom_sec_xlat;
@@ -1379,12 +1409,8 @@ static int atom_init_ntb(struct intel_ntb_dev *ndev)
/* Enable Bus Master and Memory Space on the secondary side */
iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
ndev->self_mmio + ATOM_SPCICMD_OFFSET);
-
- break;
-
- default:
+ } else
return -EINVAL;
- }

ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;

@@ -1400,9 +1426,9 @@ static int atom_init_dev(struct intel_ntb_dev *ndev)
if (rc)
return -EIO;

- ndev->ntb.topo = atom_ppd_topo(ndev, ppd);
- if (ndev->ntb.topo == NTB_TOPO_NONE)
- return -EINVAL;
+ rc = atom_ppd_init_topo(ndev, ppd);
+ if (rc)
+ return rc;

rc = atom_init_ntb(ndev);
if (rc)
@@ -1412,7 +1438,7 @@ static int atom_init_dev(struct intel_ntb_dev *ndev)
if (rc)
return rc;

- if (ndev->ntb.topo != NTB_TOPO_SEC) {
+ if (ndev->ntb.port != NTB_PORT_SEC) {
/* Initiate PCI-E link training */
rc = pci_write_config_dword(ndev->ntb.pdev, ATOM_PPD_OFFSET,
ppd | ATOM_PPD_INIT_LINK);
@@ -1464,31 +1490,37 @@ static int xeon_poll_link(struct intel_ntb_dev *ndev)

static int xeon_link_is_up(struct intel_ntb_dev *ndev)
{
- if (ndev->ntb.topo == NTB_TOPO_SEC)
+ if (ndev->ntb.port == NTB_PORT_SEC)
return 1;

return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
}

-static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd)
+static inline int xeon_ppd_init_topo(struct intel_ntb_dev *ndev, u8 ppd)
{
switch (ppd & XEON_PPD_TOPO_MASK) {
case XEON_PPD_TOPO_B2B_USD:
- return NTB_TOPO_B2B_USD;
-
+ ndev->ntb.topo = NTB_TOPO_B2B;
+ ndev->ntb.port = NTB_PORT_PRI;
+ return 0;
case XEON_PPD_TOPO_B2B_DSD:
- return NTB_TOPO_B2B_DSD;
-
+ ndev->ntb.topo = NTB_TOPO_B2B;
+ ndev->ntb.port = NTB_PORT_SEC;
+ return 0;
case XEON_PPD_TOPO_PRI_USD:
case XEON_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */
- return NTB_TOPO_PRI;
-
+ ndev->ntb.topo = NTB_TOPO_P2P;
+ ndev->ntb.port = NTB_PORT_PRI;
+ return 0;
case XEON_PPD_TOPO_SEC_USD:
case XEON_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */
- return NTB_TOPO_SEC;
+ ndev->ntb.topo = NTB_TOPO_P2P;
+ ndev->ntb.port = NTB_PORT_SEC;
+ return 0;
}

- return NTB_TOPO_NONE;
+ dev_err(ndev_dev(ndev), "PPD %d invalid\n", ppd);
+ return -EINVAL;
}

static inline int xeon_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd)
@@ -1776,39 +1808,39 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
ndev->db_count = XEON_DB_COUNT;
ndev->db_link_mask = XEON_DB_LINK_BIT;

- switch (ndev->ntb.topo) {
- case NTB_TOPO_PRI:
- if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
- dev_err(ndev_dev(ndev), "NTB Primary config disabled\n");
- return -EINVAL;
- }
-
- /* enable link to allow secondary side device to appear */
- ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
- ntb_ctl &= ~NTB_CTL_DISABLE;
- iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
- /* use half the spads for the peer */
- ndev->spad_count >>= 1;
- ndev->self_reg = &xeon_pri_reg;
- ndev->peer_reg = &xeon_sec_reg;
- ndev->xlat_reg = &xeon_sec_xlat;
- break;
+ if (ndev->ntb.topo == NTB_TOPO_P2P) {
+ if (ndev->ntb.port == NTB_PORT_PRI) {
+ if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+ dev_err(ndev_dev(ndev),
+ "NTB Primary config disabled\n");
+ return -EINVAL;
+ }

- case NTB_TOPO_SEC:
- if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
- dev_err(ndev_dev(ndev), "NTB Secondary config disabled\n");
- return -EINVAL;
+ /* enable link to allow secondary side dev to appear */
+ ntb_ctl = ioread32(ndev->self_mmio +
+ ndev->reg->ntb_ctl);
+ ntb_ctl &= ~NTB_CTL_DISABLE;
+ iowrite32(ntb_ctl, ndev->self_mmio +
+ ndev->reg->ntb_ctl);
+
+ /* use half the spads for the peer */
+ ndev->spad_count >>= 1;
+ ndev->self_reg = &xeon_pri_reg;
+ ndev->peer_reg = &xeon_sec_reg;
+ ndev->xlat_reg = &xeon_sec_xlat;
+ } else {
+ if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+ dev_err(ndev_dev(ndev),
+ "NTB Secondary config disabled\n");
+ return -EINVAL;
+ }
+ /* use half the spads for the peer */
+ ndev->spad_count >>= 1;
+ ndev->self_reg = &xeon_sec_reg;
+ ndev->peer_reg = &xeon_pri_reg;
+ ndev->xlat_reg = &xeon_pri_xlat;
}
- /* use half the spads for the peer */
- ndev->spad_count >>= 1;
- ndev->self_reg = &xeon_sec_reg;
- ndev->peer_reg = &xeon_pri_reg;
- ndev->xlat_reg = &xeon_pri_xlat;
- break;
-
- case NTB_TOPO_B2B_USD:
- case NTB_TOPO_B2B_DSD:
+ } else {
ndev->self_reg = &xeon_pri_reg;
ndev->peer_reg = &xeon_b2b_reg;
ndev->xlat_reg = &xeon_sec_xlat;
@@ -1833,11 +1865,12 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
b2b_mw_idx, ndev->b2b_idx);

} else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) {
- dev_warn(ndev_dev(ndev), "Reduce doorbell count by 1\n");
+ dev_warn(ndev_dev(ndev),
+ "Reduce doorbell count by 1\n");
ndev->db_count -= 1;
}

- if (ndev->ntb.topo == NTB_TOPO_B2B_USD) {
+ if (ndev->ntb.port == NTB_PORT_PRI) {
rc = xeon_setup_b2b_mw(ndev,
&xeon_b2b_dsd_addr,
&xeon_b2b_usd_addr);
@@ -1852,11 +1885,6 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
/* Enable Bus Master and Memory Space on the secondary side */
iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
ndev->self_mmio + XEON_SPCICMD_OFFSET);
-
- break;
-
- default:
- return -EINVAL;
}

ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
@@ -1949,13 +1977,13 @@ static int xeon_init_dev(struct intel_ntb_dev *ndev)
if (rc)
return -EIO;

- ndev->ntb.topo = xeon_ppd_topo(ndev, ppd);
- dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd,
- ntb_topo_string(ndev->ntb.topo));
- if (ndev->ntb.topo == NTB_TOPO_NONE)
- return -EINVAL;
+ rc = xeon_ppd_init_topo(ndev, ppd);
+ dev_dbg(ndev_dev(ndev), "ppd %#x topo %s:%d\n", ppd,
+ ntb_topo_string(ndev->ntb.topo), ndev->ntb.port);
+ if (rc)
+ return rc;

- if (ndev->ntb.topo != NTB_TOPO_SEC) {
+ if (ndev->ntb.topo != NTB_TOPO_P2P && ndev->ntb.port != NTB_PORT_SEC) {
ndev->bar4_split = xeon_ppd_bar4_split(ndev, ppd);
dev_dbg(ndev_dev(ndev), "ppd %#x bar4_split %d\n",
ppd, ndev->bar4_split);
@@ -2055,6 +2083,7 @@ static inline void ndev_init_struct(struct intel_ntb_dev *ndev,
{
ndev->ntb.pdev = pdev;
ndev->ntb.topo = NTB_TOPO_NONE;
+ ndev->ntb.port = NTB_PORT_NONE;
ndev->ntb.ops = &intel_ntb_ops;

ndev->b2b_off = 0;
@@ -2259,6 +2288,10 @@ static struct intel_b2b_addr xeon_b2b_dsd_addr = {

/* operations for primary side of local ntb */
static const struct ntb_dev_ops intel_ntb_ops = {
+ .port_number = intel_ntb_port_number,
+ .peer_port_count = intel_ntb_peer_port_count,
+ .peer_port_number = intel_ntb_peer_port_number,
+ .peer_port_idx = intel_ntb_peer_port_idx,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable,
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
index 3ec149c..7f1da03 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.h
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -248,6 +248,16 @@
#define NTB_BAR_MASK_64 ~(0xfull)
#define NTB_BAR_MASK_32 ~(0xfu)

+/* port related constants */
+#define NTB_PEER_CNT (1)
+#define NTB_PIDX_MAX (0)
+
+enum intel_ntb_port {
+ NTB_PORT_NONE = -1,
+ NTB_PORT_PRI,
+ NTB_PORT_SEC
+};
+
struct intel_ntb_dev;

struct intel_ntb_reg {
--
2.6.6

2016-11-30 18:40:27

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 02/22] NTB: Add peer indexed ports NTB API

Hi Serge,

[auto build test ERROR on ntb/ntb-next]
[also build test ERROR on v4.9-rc7 next-20161130]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Serge-Semin/NTB-Alter-kernel-API-to-support-multi-port-devices/20161201-014939
base: https://github.com/jonmason/ntb ntb-next
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

All errors (new ones prefixed by >>):

drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'ndev_reset_unsafe_flags':
>> drivers/ntb/hw/intel/ntb_hw_intel.c:232:8: error: implicit declaration of function 'ntb_topo_is_b2b' [-Werror=implicit-function-declaration]
if (!ntb_topo_is_b2b(ndev->ntb.topo))
^~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_enable':
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: note: each undeclared identifier is reported only once for each function it appears in
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_disable':
drivers/ntb/hw/intel/ntb_hw_intel.c:1235:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_ppd_topo':
>> drivers/ntb/hw/intel/ntb_hw_intel.c:1448:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
>> drivers/ntb/hw/intel/ntb_hw_intel.c:1452:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1572:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1573:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_dev':
drivers/ntb/hw/intel/ntb_hw_intel.c:1614:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo != NTB_TOPO_SEC) {
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'skx_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1789:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1790:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_link_is_up':
drivers/ntb/hw/intel/ntb_hw_intel.c:2043:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_ppd_topo':
drivers/ntb/hw/intel/ntb_hw_intel.c:2053:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2056:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2060:10: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
return NTB_TOPO_PRI;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2064:10: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
return NTB_TOPO_SEC;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:2356:7: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
case NTB_TOPO_PRI:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2374:7: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
case NTB_TOPO_SEC:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2386:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2387:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_init_dev':
drivers/ntb/hw/intel/ntb_hw_intel.c:2534:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo != NTB_TOPO_SEC) {
^~~~~~~~~~~~
cc1: some warnings being treated as errors

vim +/ntb_topo_is_b2b +232 drivers/ntb/hw/intel/ntb_hw_intel.c

fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 226 {
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 227 ndev->unsafe_flags = 0;
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 228 ndev->unsafe_flags_ignore = 0;
fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 229
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 230 /* Only B2B has a workaround to avoid SDOORBELL */
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 231 if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP)
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 @232 if (!ntb_topo_is_b2b(ndev->ntb.topo))
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 233 ndev->unsafe_flags |= NTB_UNSAFE_DB;
fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 234
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 235 /* No low level workaround to avoid SB01BASE */

:::::: The code at line 232 was first introduced by commit
:::::: e26a5843f7f5014ae4460030ca4de029a3ac35d3 NTB: Split ntb_hw_intel and ntb_transport drivers

:::::: TO: Allen Hubbe <[email protected]>
:::::: CC: Jon Mason <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (6.45 kB)
.config.gz (55.31 kB)
Download all attachments

2016-11-30 18:54:27

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 03/22] NTB: Alter NTB API to support both inbound and outbound MW based interfaces

Hi Serge,

[auto build test ERROR on ntb/ntb-next]
[also build test ERROR on v4.9-rc7 next-20161130]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Serge-Semin/NTB-Alter-kernel-API-to-support-multi-port-devices/20161201-014939
base: https://github.com/jonmason/ntb ntb-next
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

All errors (new ones prefixed by >>):

drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'ndev_reset_unsafe_flags':
drivers/ntb/hw/intel/ntb_hw_intel.c:232:8: error: implicit declaration of function 'ntb_topo_is_b2b' [-Werror=implicit-function-declaration]
if (!ntb_topo_is_b2b(ndev->ntb.topo))
^~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_enable':
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: note: each undeclared identifier is reported only once for each function it appears in
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_disable':
drivers/ntb/hw/intel/ntb_hw_intel.c:1235:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_ppd_topo':
drivers/ntb/hw/intel/ntb_hw_intel.c:1448:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1452:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1572:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1573:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_dev':
drivers/ntb/hw/intel/ntb_hw_intel.c:1614:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo != NTB_TOPO_SEC) {
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'skx_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1789:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1790:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_link_is_up':
drivers/ntb/hw/intel/ntb_hw_intel.c:2043:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_ppd_topo':
drivers/ntb/hw/intel/ntb_hw_intel.c:2053:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2056:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2060:10: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
return NTB_TOPO_PRI;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2064:10: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
return NTB_TOPO_SEC;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:2356:7: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
case NTB_TOPO_PRI:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2374:7: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
case NTB_TOPO_SEC:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2386:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2387:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_init_dev':
drivers/ntb/hw/intel/ntb_hw_intel.c:2534:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo != NTB_TOPO_SEC) {
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: At top level:
>> drivers/ntb/hw/intel/ntb_hw_intel.c:2886:15: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_count = intel_ntb_mw_count,
^~~~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2886:15: note: (near initialization for 'intel_ntb_ops.mw_count')
>> drivers/ntb/hw/intel/ntb_hw_intel.c:2887:2: error: unknown field 'mw_get_range' specified in initializer
.mw_get_range = intel_ntb_mw_get_range,
^
drivers/ntb/hw/intel/ntb_hw_intel.c:2887:19: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_get_range = intel_ntb_mw_get_range,
^~~~~~~~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2887:19: note: (near initialization for 'intel_ntb_ops.mw_get_align')
drivers/ntb/hw/intel/ntb_hw_intel.c:2888:19: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_set_trans = intel_ntb_mw_set_trans,
^~~~~~~~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2888:19: note: (near initialization for 'intel_ntb_ops.mw_set_trans')
drivers/ntb/hw/intel/ntb_hw_intel.c:2912:15: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_count = intel_ntb_mw_count,
^~~~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2912:15: note: (near initialization for 'intel_ntb3_ops.mw_count')
drivers/ntb/hw/intel/ntb_hw_intel.c:2913:2: error: unknown field 'mw_get_range' specified in initializer
.mw_get_range = intel_ntb_mw_get_range,
^
drivers/ntb/hw/intel/ntb_hw_intel.c:2913:19: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_get_range = intel_ntb_mw_get_range,
^~~~~~~~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2913:19: note: (near initialization for 'intel_ntb3_ops.mw_get_align')
drivers/ntb/hw/intel/ntb_hw_intel.c:2914:19: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_set_trans = intel_ntb3_mw_set_trans,
^~~~~~~~~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2914:19: note: (near initialization for 'intel_ntb3_ops.mw_set_trans')
cc1: some warnings being treated as errors

vim +/mw_get_range +2887 drivers/ntb/hw/intel/ntb_hw_intel.c

89a85cde Dave Jiang 2016-11-16 2880 .bar2_limit = SKX_IMBAR1XLMT_OFFSET,
89a85cde Dave Jiang 2016-11-16 2881 .bar2_xlat = SKX_IMBAR1XBASE_OFFSET,
89a85cde Dave Jiang 2016-11-16 2882 };
89a85cde Dave Jiang 2016-11-16 2883
e26a5843 Allen Hubbe 2015-04-09 2884 /* operations for primary side of local ntb */
e26a5843 Allen Hubbe 2015-04-09 2885 static const struct ntb_dev_ops intel_ntb_ops = {
e26a5843 Allen Hubbe 2015-04-09 @2886 .mw_count = intel_ntb_mw_count,
e26a5843 Allen Hubbe 2015-04-09 @2887 .mw_get_range = intel_ntb_mw_get_range,
e26a5843 Allen Hubbe 2015-04-09 2888 .mw_set_trans = intel_ntb_mw_set_trans,
e26a5843 Allen Hubbe 2015-04-09 2889 .link_is_up = intel_ntb_link_is_up,
e26a5843 Allen Hubbe 2015-04-09 2890 .link_enable = intel_ntb_link_enable,

:::::: The code at line 2887 was first introduced by commit
:::::: e26a5843f7f5014ae4460030ca4de029a3ac35d3 NTB: Split ntb_hw_intel and ntb_transport drivers

:::::: TO: Allen Hubbe <[email protected]>
:::::: CC: Jon Mason <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (8.53 kB)
.config.gz (55.31 kB)
Download all attachments

2016-11-30 19:13:27

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 02/22] NTB: Add peer indexed ports NTB API

Hi Serge,

[auto build test ERROR on ntb/ntb-next]
[also build test ERROR on v4.9-rc7 next-20161130]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Serge-Semin/NTB-Alter-kernel-API-to-support-multi-port-devices/20161201-014939
base: https://github.com/jonmason/ntb ntb-next
config: x86_64-randconfig-s5-12010242 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

Note: the linux-review/Serge-Semin/NTB-Alter-kernel-API-to-support-multi-port-devices/20161201-014939 HEAD ced946cf007084caf9a2ec237c898bbf1940b440 builds fine.
It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_ntb_link_enable':
>> drivers/ntb/hw/amd/ntb_hw_amd.c:256:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:256:24: note: each undeclared identifier is reported only once for each function it appears in
drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_ntb_link_disable':
drivers/ntb/hw/amd/ntb_hw_amd.c:277:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_init_ntb':
>> drivers/ntb/hw/amd/ntb_hw_amd.c:880:7: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
case NTB_TOPO_PRI:
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:881:7: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
case NTB_TOPO_SEC:
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_get_topo':
drivers/ntb/hw/amd/ntb_hw_amd.c:915:10: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
return NTB_TOPO_SEC;
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:917:10: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
return NTB_TOPO_PRI;
^~~~~~~~~~~~
>> drivers/ntb/hw/amd/ntb_hw_amd.c:918:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
--
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'ndev_reset_unsafe_flags':
drivers/ntb/hw/intel/ntb_hw_intel.c:232:8: error: implicit declaration of function 'ntb_topo_is_b2b' [-Werror=implicit-function-declaration]
if (!ntb_topo_is_b2b(ndev->ntb.topo))
^~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_enable':
>> drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: note: each undeclared identifier is reported only once for each function it appears in
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_disable':
drivers/ntb/hw/intel/ntb_hw_intel.c:1235:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_ppd_topo':
drivers/ntb/hw/intel/ntb_hw_intel.c:1448:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1452:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1572:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1573:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_dev':
drivers/ntb/hw/intel/ntb_hw_intel.c:1614:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo != NTB_TOPO_SEC) {
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'skx_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1789:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1790:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_link_is_up':
drivers/ntb/hw/intel/ntb_hw_intel.c:2043:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_ppd_topo':
drivers/ntb/hw/intel/ntb_hw_intel.c:2053:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2056:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
>> drivers/ntb/hw/intel/ntb_hw_intel.c:2060:10: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
return NTB_TOPO_PRI;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2064:10: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
return NTB_TOPO_SEC;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:2356:7: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
case NTB_TOPO_PRI:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2374:7: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
case NTB_TOPO_SEC:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2386:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2387:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_init_dev':
drivers/ntb/hw/intel/ntb_hw_intel.c:2534:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo != NTB_TOPO_SEC) {
^~~~~~~~~~~~
cc1: some warnings being treated as errors

vim +/NTB_TOPO_SEC +256 drivers/ntb/hw/amd/ntb_hw_amd.c

a1b36958 Xiangliang Yu 2016-01-21 250 u32 ntb_ctl;
a1b36958 Xiangliang Yu 2016-01-21 251
a1b36958 Xiangliang Yu 2016-01-21 252 /* Enable event interrupt */
a1b36958 Xiangliang Yu 2016-01-21 253 ndev->int_mask &= ~AMD_EVENT_INTMASK;
a1b36958 Xiangliang Yu 2016-01-21 254 writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
a1b36958 Xiangliang Yu 2016-01-21 255
a1b36958 Xiangliang Yu 2016-01-21 @256 if (ndev->ntb.topo == NTB_TOPO_SEC)
a1b36958 Xiangliang Yu 2016-01-21 257 return -EINVAL;
a1b36958 Xiangliang Yu 2016-01-21 258 dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
a1b36958 Xiangliang Yu 2016-01-21 259

:::::: The code at line 256 was first introduced by commit
:::::: a1b3695820aa490e58915d720a1438069813008b NTB: Add support for AMD PCI-Express Non-Transparent Bridge

:::::: TO: Xiangliang Yu <[email protected]>
:::::: CC: Jon Mason <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (7.76 kB)
.config.gz (22.72 kB)
Download all attachments

2016-11-30 19:47:34

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 03/22] NTB: Alter NTB API to support both inbound and outbound MW based interfaces

Hi Serge,

[auto build test ERROR on ntb/ntb-next]
[also build test ERROR on v4.9-rc7 next-20161130]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Serge-Semin/NTB-Alter-kernel-API-to-support-multi-port-devices/20161201-014939
base: https://github.com/jonmason/ntb ntb-next
config: x86_64-randconfig-s5-12010242 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

Note: the linux-review/Serge-Semin/NTB-Alter-kernel-API-to-support-multi-port-devices/20161201-014939 HEAD ced946cf007084caf9a2ec237c898bbf1940b440 builds fine.
It only hurts bisectibility.

All errors (new ones prefixed by >>):

drivers/ntb/ntb_transport.c: In function 'ntb_free_mw':
>> drivers/ntb/ntb_transport.c:685:2: error: too few arguments to function 'ntb_mw_clear_trans'
ntb_mw_clear_trans(nt->ndev, num_mw);
^~~~~~~~~~~~~~~~~~
In file included from drivers/ntb/ntb_transport.c:62:0:
include/linux/ntb.h:739:19: note: declared here
static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
^~~~~~~~~~~~~~~~~~
drivers/ntb/ntb_transport.c: In function 'ntb_set_mw':
>> drivers/ntb/ntb_transport.c:742:7: error: too few arguments to function 'ntb_mw_set_trans'
rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
^~~~~~~~~~~~~~~~
In file included from drivers/ntb/ntb_transport.c:62:0:
include/linux/ntb.h:718:19: note: declared here
static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
^~~~~~~~~~~~~~~~
drivers/ntb/ntb_transport.c: In function 'ntb_transport_probe':
>> drivers/ntb/ntb_transport.c:1072:13: error: too few arguments to function 'ntb_mw_count'
mw_count = ntb_mw_count(ndev);
^~~~~~~~~~~~
In file included from drivers/ntb/ntb_transport.c:62:0:
include/linux/ntb.h:669:19: note: declared here
static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
^~~~~~~~~~~~
>> drivers/ntb/ntb_transport.c:1106:8: error: implicit declaration of function 'ntb_mw_get_range' [-Werror=implicit-function-declaration]
rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
^~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
--
drivers/ntb/test/ntb_perf.c: In function 'perf_free_mw':
>> drivers/ntb/test/ntb_perf.c:455:2: error: too few arguments to function 'ntb_mw_clear_trans'
ntb_mw_clear_trans(perf->ntb, 0);
^~~~~~~~~~~~~~~~~~
In file included from drivers/ntb/test/ntb_perf.c:60:0:
include/linux/ntb.h:739:19: note: declared here
static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
^~~~~~~~~~~~~~~~~~
drivers/ntb/test/ntb_perf.c: In function 'perf_set_mw':
>> drivers/ntb/test/ntb_perf.c:491:7: error: too few arguments to function 'ntb_mw_set_trans'
rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
^~~~~~~~~~~~~~~~
In file included from drivers/ntb/test/ntb_perf.c:60:0:
include/linux/ntb.h:718:19: note: declared here
static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
^~~~~~~~~~~~~~~~
drivers/ntb/test/ntb_perf.c: In function 'perf_setup_mw':
>> drivers/ntb/test/ntb_perf.c:562:7: error: implicit declaration of function 'ntb_mw_get_range' [-Werror=implicit-function-declaration]
rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size,
^~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
--
drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_ntb_link_enable':
drivers/ntb/hw/amd/ntb_hw_amd.c:256:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:256:24: note: each undeclared identifier is reported only once for each function it appears in
drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_ntb_link_disable':
drivers/ntb/hw/amd/ntb_hw_amd.c:277:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c: At top level:
>> drivers/ntb/hw/amd/ntb_hw_amd.c:434:15: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_count = amd_ntb_mw_count,
^~~~~~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:434:15: note: (near initialization for 'amd_ntb_ops.mw_count')
>> drivers/ntb/hw/amd/ntb_hw_amd.c:435:2: error: unknown field 'mw_get_range' specified in initializer
.mw_get_range = amd_ntb_mw_get_range,
^
drivers/ntb/hw/amd/ntb_hw_amd.c:435:19: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_get_range = amd_ntb_mw_get_range,
^~~~~~~~~~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:435:19: note: (near initialization for 'amd_ntb_ops.mw_get_align')
drivers/ntb/hw/amd/ntb_hw_amd.c:436:19: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.mw_set_trans = amd_ntb_mw_set_trans,
^~~~~~~~~~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:436:19: note: (near initialization for 'amd_ntb_ops.mw_set_trans')
drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_init_ntb':
drivers/ntb/hw/amd/ntb_hw_amd.c:880:7: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
case NTB_TOPO_PRI:
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:881:7: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
case NTB_TOPO_SEC:
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c: In function 'amd_get_topo':
drivers/ntb/hw/amd/ntb_hw_amd.c:915:10: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
return NTB_TOPO_SEC;
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:917:10: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
return NTB_TOPO_PRI;
^~~~~~~~~~~~
drivers/ntb/hw/amd/ntb_hw_amd.c:918:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
cc1: some warnings being treated as errors

vim +/ntb_mw_clear_trans +685 drivers/ntb/ntb_transport.c

e26a5843 Allen Hubbe 2015-04-09 679 struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
e26a5843 Allen Hubbe 2015-04-09 680 struct pci_dev *pdev = nt->ndev->pdev;
b77b2637 Jon Mason 2013-02-01 681
b77b2637 Jon Mason 2013-02-01 682 if (!mw->virt_addr)
b77b2637 Jon Mason 2013-02-01 683 return;
b77b2637 Jon Mason 2013-02-01 684
e26a5843 Allen Hubbe 2015-04-09 @685 ntb_mw_clear_trans(nt->ndev, num_mw);
e26a5843 Allen Hubbe 2015-04-09 686 dma_free_coherent(&pdev->dev, mw->buff_size,
e26a5843 Allen Hubbe 2015-04-09 687 mw->virt_addr, mw->dma_addr);
e26a5843 Allen Hubbe 2015-04-09 688 mw->xlat_size = 0;
e26a5843 Allen Hubbe 2015-04-09 689 mw->buff_size = 0;
b77b2637 Jon Mason 2013-02-01 690 mw->virt_addr = NULL;
b77b2637 Jon Mason 2013-02-01 691 }
b77b2637 Jon Mason 2013-02-01 692
e26a5843 Allen Hubbe 2015-04-09 693 static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
8c9edf63 Allen Hubbe 2015-07-13 694 resource_size_t size)
fce8a7bb Jon Mason 2012-11-16 695 {
e26a5843 Allen Hubbe 2015-04-09 696 struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
e26a5843 Allen Hubbe 2015-04-09 697 struct pci_dev *pdev = nt->ndev->pdev;
8c9edf63 Allen Hubbe 2015-07-13 698 size_t xlat_size, buff_size;
e26a5843 Allen Hubbe 2015-04-09 699 int rc;
e26a5843 Allen Hubbe 2015-04-09 700
8c9edf63 Allen Hubbe 2015-07-13 701 if (!size)
8c9edf63 Allen Hubbe 2015-07-13 702 return -EINVAL;
8c9edf63 Allen Hubbe 2015-07-13 703
e26a5843 Allen Hubbe 2015-04-09 704 xlat_size = round_up(size, mw->xlat_align_size);
e26a5843 Allen Hubbe 2015-04-09 705 buff_size = round_up(size, mw->xlat_align);
fce8a7bb Jon Mason 2012-11-16 706
b77b2637 Jon Mason 2013-02-01 707 /* No need to re-setup */
e26a5843 Allen Hubbe 2015-04-09 708 if (mw->xlat_size == xlat_size)
b77b2637 Jon Mason 2013-02-01 709 return 0;
b77b2637 Jon Mason 2013-02-01 710
e26a5843 Allen Hubbe 2015-04-09 711 if (mw->buff_size)
b77b2637 Jon Mason 2013-02-01 712 ntb_free_mw(nt, num_mw);
b77b2637 Jon Mason 2013-02-01 713
e26a5843 Allen Hubbe 2015-04-09 714 /* Alloc memory for receiving data. Must be aligned */
e26a5843 Allen Hubbe 2015-04-09 715 mw->xlat_size = xlat_size;
e26a5843 Allen Hubbe 2015-04-09 716 mw->buff_size = buff_size;
fce8a7bb Jon Mason 2012-11-16 717
e26a5843 Allen Hubbe 2015-04-09 718 mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size,
e26a5843 Allen Hubbe 2015-04-09 719 &mw->dma_addr, GFP_KERNEL);
fce8a7bb Jon Mason 2012-11-16 720 if (!mw->virt_addr) {
e26a5843 Allen Hubbe 2015-04-09 721 mw->xlat_size = 0;
e26a5843 Allen Hubbe 2015-04-09 722 mw->buff_size = 0;
8c9edf63 Allen Hubbe 2015-07-13 723 dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n",
e26a5843 Allen Hubbe 2015-04-09 724 buff_size);
fce8a7bb Jon Mason 2012-11-16 725 return -ENOMEM;
fce8a7bb Jon Mason 2012-11-16 726 }
fce8a7bb Jon Mason 2012-11-16 727
3cc5ba19 Dave Jiang 2014-08-28 728 /*
3cc5ba19 Dave Jiang 2014-08-28 729 * we must ensure that the memory address allocated is BAR size
3cc5ba19 Dave Jiang 2014-08-28 730 * aligned in order for the XLAT register to take the value. This
3cc5ba19 Dave Jiang 2014-08-28 731 * is a requirement of the hardware. It is recommended to setup CMA
3cc5ba19 Dave Jiang 2014-08-28 732 * for BAR sizes equal or greater than 4MB.
3cc5ba19 Dave Jiang 2014-08-28 733 */
e26a5843 Allen Hubbe 2015-04-09 734 if (!IS_ALIGNED(mw->dma_addr, mw->xlat_align)) {
e26a5843 Allen Hubbe 2015-04-09 735 dev_err(&pdev->dev, "DMA memory %pad is not aligned\n",
3cc5ba19 Dave Jiang 2014-08-28 736 &mw->dma_addr);
3cc5ba19 Dave Jiang 2014-08-28 737 ntb_free_mw(nt, num_mw);
3cc5ba19 Dave Jiang 2014-08-28 738 return -ENOMEM;
3cc5ba19 Dave Jiang 2014-08-28 739 }
3cc5ba19 Dave Jiang 2014-08-28 740
fce8a7bb Jon Mason 2012-11-16 741 /* Notify HW the memory location of the receive buffer */
e26a5843 Allen Hubbe 2015-04-09 @742 rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
e26a5843 Allen Hubbe 2015-04-09 743 if (rc) {
e26a5843 Allen Hubbe 2015-04-09 744 dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
e26a5843 Allen Hubbe 2015-04-09 745 ntb_free_mw(nt, num_mw);

:::::: The code at line 685 was first introduced by commit
:::::: e26a5843f7f5014ae4460030ca4de029a3ac35d3 NTB: Split ntb_hw_intel and ntb_transport drivers

:::::: TO: Allen Hubbe <[email protected]>
:::::: CC: Jon Mason <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (11.02 kB)
.config.gz (22.72 kB)
Download all attachments

2016-11-30 20:04:29

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 02/22] NTB: Add peer indexed ports NTB API

Hi Serge,

[auto build test WARNING on ntb/ntb-next]
[also build test WARNING on v4.9-rc7 next-20161130]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Serge-Semin/NTB-Alter-kernel-API-to-support-multi-port-devices/20161201-014939
base: https://github.com/jonmason/ntb ntb-next
reproduce:
# apt-get install sparse
make ARCH=x86_64 allmodconfig
make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

include/linux/compiler.h:253:8: sparse: attribute 'no_sanitize_address': unknown attribute
drivers/ntb/hw/intel/ntb_hw_intel.c:664:13: sparse: undefined identifier 'ntb_topo_is_b2b'
drivers/ntb/hw/intel/ntb_hw_intel.c:895:21: sparse: undefined identifier 'ntb_topo_is_b2b'
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:31: sparse: undefined identifier 'NTB_TOPO_SEC'
drivers/ntb/hw/intel/ntb_hw_intel.c:1235:31: sparse: undefined identifier 'NTB_TOPO_SEC'
drivers/ntb/hw/intel/ntb_hw_intel.c:1572:14: sparse: undefined identifier 'NTB_TOPO_B2B_USD'
drivers/ntb/hw/intel/ntb_hw_intel.c:1573:14: sparse: undefined identifier 'NTB_TOPO_B2B_DSD'
>> drivers/ntb/hw/intel/ntb_hw_intel.c:1572:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:1573:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:1448:24: sparse: undefined identifier 'NTB_TOPO_B2B_USD'
drivers/ntb/hw/intel/ntb_hw_intel.c:1452:24: sparse: undefined identifier 'NTB_TOPO_B2B_DSD'
drivers/ntb/hw/intel/ntb_hw_intel.c:1614:31: sparse: undefined identifier 'NTB_TOPO_SEC'
drivers/ntb/hw/intel/ntb_hw_intel.c:1789:14: sparse: undefined identifier 'NTB_TOPO_B2B_USD'
drivers/ntb/hw/intel/ntb_hw_intel.c:1790:14: sparse: undefined identifier 'NTB_TOPO_B2B_DSD'
drivers/ntb/hw/intel/ntb_hw_intel.c:1795:39: sparse: undefined identifier 'NTB_TOPO_B2B_USD'
drivers/ntb/hw/intel/ntb_hw_intel.c:1789:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:1790:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2053:24: sparse: undefined identifier 'NTB_TOPO_B2B_USD'
drivers/ntb/hw/intel/ntb_hw_intel.c:2056:24: sparse: undefined identifier 'NTB_TOPO_B2B_DSD'
drivers/ntb/hw/intel/ntb_hw_intel.c:2060:24: sparse: undefined identifier 'NTB_TOPO_PRI'
drivers/ntb/hw/intel/ntb_hw_intel.c:2064:24: sparse: undefined identifier 'NTB_TOPO_SEC'
drivers/ntb/hw/intel/ntb_hw_intel.c:2043:31: sparse: undefined identifier 'NTB_TOPO_SEC'
drivers/ntb/hw/intel/ntb_hw_intel.c:2356:14: sparse: undefined identifier 'NTB_TOPO_PRI'
drivers/ntb/hw/intel/ntb_hw_intel.c:2374:14: sparse: undefined identifier 'NTB_TOPO_SEC'
drivers/ntb/hw/intel/ntb_hw_intel.c:2386:14: sparse: undefined identifier 'NTB_TOPO_B2B_USD'
drivers/ntb/hw/intel/ntb_hw_intel.c:2387:14: sparse: undefined identifier 'NTB_TOPO_B2B_DSD'
drivers/ntb/hw/intel/ntb_hw_intel.c:2416:39: sparse: undefined identifier 'NTB_TOPO_B2B_USD'
drivers/ntb/hw/intel/ntb_hw_intel.c:2356:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2374:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2386:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2387:14: sparse: incompatible types for 'case' statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2534:31: sparse: undefined identifier 'NTB_TOPO_SEC'
drivers/ntb/hw/intel/ntb_hw_intel.c:232:22: sparse: undefined identifier 'ntb_topo_is_b2b'
drivers/ntb/hw/intel/ntb_hw_intel.c:1572:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c:1573:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c:1789:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c:1790:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2356:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2374:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2386:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c:2387:14: sparse: Expected constant expression in case statement
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'ndev_reset_unsafe_flags':
drivers/ntb/hw/intel/ntb_hw_intel.c:232:8: error: implicit declaration of function 'ntb_topo_is_b2b' [-Werror=implicit-function-declaration]
if (!ntb_topo_is_b2b(ndev->ntb.topo))
^~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_enable':
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1206:24: note: each undeclared identifier is reported only once for each function it appears in
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'intel_ntb_link_disable':
drivers/ntb/hw/intel/ntb_hw_intel.c:1235:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_ppd_topo':
drivers/ntb/hw/intel/ntb_hw_intel.c:1448:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1452:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1572:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1573:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'atom_init_dev':
drivers/ntb/hw/intel/ntb_hw_intel.c:1614:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo != NTB_TOPO_SEC) {
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'skx_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:1789:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:1790:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_link_is_up':
drivers/ntb/hw/intel/ntb_hw_intel.c:2043:24: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
if (ndev->ntb.topo == NTB_TOPO_SEC)
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_ppd_topo':
drivers/ntb/hw/intel/ntb_hw_intel.c:2053:10: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
return NTB_TOPO_B2B_USD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2056:10: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
return NTB_TOPO_B2B_DSD;
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2060:10: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
return NTB_TOPO_PRI;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2064:10: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
return NTB_TOPO_SEC;
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c: In function 'xeon_init_ntb':
drivers/ntb/hw/intel/ntb_hw_intel.c:2356:7: error: 'NTB_TOPO_PRI' undeclared (first use in this function)
case NTB_TOPO_PRI:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2374:7: error: 'NTB_TOPO_SEC' undeclared (first use in this function)
case NTB_TOPO_SEC:
^~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2386:7: error: 'NTB_TOPO_B2B_USD' undeclared (first use in this function)
case NTB_TOPO_B2B_USD:
^~~~~~~~~~~~~~~~
drivers/ntb/hw/intel/ntb_hw_intel.c:2387:7: error: 'NTB_TOPO_B2B_DSD' undeclared (first use in this function)
case NTB_TOPO_B2B_DSD:

vim +/case +1572 drivers/ntb/hw/intel/ntb_hw_intel.c

fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 1556 return 0;
fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 1557 }
fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 1558
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1559 static void atom_deinit_isr(struct intel_ntb_dev *ndev)
fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 1560 {
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1561 cancel_delayed_work_sync(&ndev->hb_timer);
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1562 ndev_deinit_isr(ndev);
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1563 }
fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 1564
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1565 static int atom_init_ntb(struct intel_ntb_dev *ndev)
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1566 {
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1567 ndev->mw_count = ATOM_MW_COUNT;
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1568 ndev->spad_count = ATOM_SPAD_COUNT;
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1569 ndev->db_count = ATOM_DB_COUNT;
fce8a7bb drivers/ntb/ntb_hw.c Jon Mason 2012-11-16 1570
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1571 switch (ndev->ntb.topo) {
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 @1572 case NTB_TOPO_B2B_USD:
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1573 case NTB_TOPO_B2B_DSD:
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1574 ndev->self_reg = &atom_pri_reg;
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1575 ndev->peer_reg = &atom_b2b_reg;
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1576 ndev->xlat_reg = &atom_sec_xlat;
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1577
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1578 /* Enable Bus Master and Memory Space on the secondary side */
e26a5843 drivers/ntb/hw/intel/ntb_hw_intel.c Allen Hubbe 2015-04-09 1579 iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
2f887b9a drivers/ntb/hw/intel/ntb_hw_intel.c Dave Jiang 2015-05-20 1580 ndev->self_mmio + ATOM_SPCICMD_OFFSET);

:::::: The code at line 1572 was first introduced by commit
:::::: e26a5843f7f5014ae4460030ca4de029a3ac35d3 NTB: Split ntb_hw_intel and ntb_transport drivers

:::::: TO: Allen Hubbe <[email protected]>
:::::: CC: Jon Mason <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

2016-12-04 00:09:39

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 05/22] NTB: Alter Scratchpads NTB API to support multi-ports interface

From: Serge Semin
> Even though there is no any real NTB hardware, which would have both more
> than two ports and Scratchpad registers, it is logically correct to have
> Scratchpad API accepting a peer port index as well. Intel/AMD drivers used
> to utilize Primary and Secondary topology to split Scratchpad between
> connected root devices. Since port-index API replaced Primary and Secondary
> topology, Intel/AMD NTB hadrware drivers can use device port to determine
> which Scratchpad registers actually belong to local and peer devices.
> The same approach can be used if some potential hardware in future will be
> multi-port and have some set of Scratchpads.
>

I agree with addition of the peer port index, but I don't think s/idx/sidx/ for scratchpad index is necessary.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> include/linux/ntb.h | 46 ++++++++++++++++++++++++++--------------------
> 1 file changed, 26 insertions(+), 20 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 59de1f6..fc9d034 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -268,13 +268,14 @@ struct ntb_dev_ops {
> int (*spad_is_unsafe)(struct ntb_dev *ntb);
> int (*spad_count)(struct ntb_dev *ntb);
>
> - u32 (*spad_read)(struct ntb_dev *ntb, int idx);
> - int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
> + u32 (*spad_read)(struct ntb_dev *ntb, int sidx);
> + int (*spad_write)(struct ntb_dev *ntb, int sidx, u32 val);
>
> - int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
> + int (*peer_spad_addr)(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr);
> - u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
> - int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
> + u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
> + int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
> + u32 val);
>
> int (*msg_count)(struct ntb_dev *ntb);
> u64 (*msg_inbits)(struct ntb_dev *ntb);
> @@ -1201,6 +1202,7 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
> * @ntb: NTB device context.
> *
> * Hardware and topology may support a different number of scratchpads.
> + * Although it must be the same for all ports per NTB device.
> *
> * Return: the number of scratchpads.
> */
> @@ -1215,42 +1217,43 @@ static inline int ntb_spad_count(struct ntb_dev *ntb)
> /**
> * ntb_spad_read() - read the local scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @sidx: Scratchpad index.
> *
> * Read the local scratchpad register, and return the value.
> *
> * Return: The value of the local scratchpad register.
> */
> -static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
> +static inline u32 ntb_spad_read(struct ntb_dev *ntb, int sidx)
> {
> if (!ntb->ops->spad_read)
> return ~(u32)0;
>
> - return ntb->ops->spad_read(ntb, idx);
> + return ntb->ops->spad_read(ntb, sidx);
> }
>
> /**
> * ntb_spad_write() - write the local scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @sidx: Scratchpad index.
> * @val: Scratchpad value.
> *
> * Write the value to the local scratchpad register.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> +static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
> {
> if (!ntb->ops->spad_write)
> return -EINVAL;
>
> - return ntb->ops->spad_write(ntb, idx, val);
> + return ntb->ops->spad_write(ntb, sidx, val);
> }
>
> /**
> * ntb_peer_spad_addr() - address of the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> * @spad_addr: OUT - The address of the peer scratchpad register.
> *
> * Return the address of the peer doorbell register. This may be used, for
> @@ -1258,48 +1261,51 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32
> val)
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
> +static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr)
> {
> if (!ntb->ops->peer_spad_addr)
> return -EINVAL;
>
> - return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
> + return ntb->ops->peer_spad_addr(ntb, pidx, sidx, spad_addr);
> }
>
> /**
> * ntb_peer_spad_read() - read the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> *
> * Read the peer scratchpad register, and return the value.
> *
> * Return: The value of the local scratchpad register.
> */
> -static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> +static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
> {
> if (!ntb->ops->peer_spad_read)
> return ~(u32)0;
>
> - return ntb->ops->peer_spad_read(ntb, idx);
> + return ntb->ops->peer_spad_read(ntb, pidx, sidx);
> }
>
> /**
> * ntb_peer_spad_write() - write the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> * @val: Scratchpad value.
> *
> * Write the value to the peer scratchpad register.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> +static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
> + u32 val)
> {
> if (!ntb->ops->peer_spad_write)
> return -EINVAL;
>
> - return ntb->ops->peer_spad_write(ntb, idx, val);
> + return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
> }
>
> /**
> --
> 2.6.6


2016-12-04 00:09:50

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 01/22] NTB: Move link state API being first in sources

From: Serge Semin
> Since link operations are usually performed before memory window access
> operations, it's logically better to declared link-related API before any
> other methods. Additionally it's good practice for readability to declare
> NTB device callback methods of hadrware drivers with the same order as it's
> done within ntb.h.

No harm. Please spellcheck the description.

I think this and patch 7 can be squashed.

I plan to ack.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> include/linux/ntb.h | 137 ++++++++++++++++++++++++++--------------------------
> 1 file changed, 69 insertions(+), 68 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 6f47562..5d1f260 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -179,13 +179,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops
> *ops)
>
> /**
> * struct ntb_ctx_ops - ntb device operations
> + * @link_is_up: See ntb_link_is_up().
> + * @link_enable: See ntb_link_enable().
> + * @link_disable: See ntb_link_disable().
> * @mw_count: See ntb_mw_count().
> * @mw_get_range: See ntb_mw_get_range().
> * @mw_set_trans: See ntb_mw_set_trans().
> * @mw_clear_trans: See ntb_mw_clear_trans().
> - * @link_is_up: See ntb_link_is_up().
> - * @link_enable: See ntb_link_enable().
> - * @link_disable: See ntb_link_disable().
> * @db_is_unsafe: See ntb_db_is_unsafe().
> * @db_valid_mask: See ntb_db_valid_mask().
> * @db_vector_count: See ntb_db_vector_count().
> @@ -212,6 +212,12 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_write: See ntb_peer_spad_write().
> */
> struct ntb_dev_ops {
> + int (*link_is_up)(struct ntb_dev *ntb,
> + enum ntb_speed *speed, enum ntb_width *width);
> + int (*link_enable)(struct ntb_dev *ntb,
> + enum ntb_speed max_speed, enum ntb_width max_width);
> + int (*link_disable)(struct ntb_dev *ntb);
> +
> int (*mw_count)(struct ntb_dev *ntb);
> int (*mw_get_range)(struct ntb_dev *ntb, int idx,
> phys_addr_t *base, resource_size_t *size,
> @@ -220,12 +226,6 @@ struct ntb_dev_ops {
> dma_addr_t addr, resource_size_t size);
> int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
>
> - int (*link_is_up)(struct ntb_dev *ntb,
> - enum ntb_speed *speed, enum ntb_width *width);
> - int (*link_enable)(struct ntb_dev *ntb,
> - enum ntb_speed max_speed, enum ntb_width max_width);
> - int (*link_disable)(struct ntb_dev *ntb);
> -
> int (*db_is_unsafe)(struct ntb_dev *ntb);
> u64 (*db_valid_mask)(struct ntb_dev *ntb);
> int (*db_vector_count)(struct ntb_dev *ntb);
> @@ -265,13 +265,14 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> {
> /* commented callbacks are not required: */
> return
> + ops->link_is_up &&
> + ops->link_enable &&
> + ops->link_disable &&
> ops->mw_count &&
> ops->mw_get_range &&
> ops->mw_set_trans &&
> /* ops->mw_clear_trans && */
> - ops->link_is_up &&
> - ops->link_enable &&
> - ops->link_disable &&
> +
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
>
> @@ -441,6 +442,62 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_link_is_up() - get the current ntb link state
> + * @ntb: NTB device context.
> + * @speed: OUT - The link speed expressed as PCIe generation number.
> + * @width: OUT - The link width expressed as the number of PCIe lanes.
> + *
> + * Get the current state of the ntb link. It is recommended to query the link
> + * state once after every link event. It is safe to query the link state in
> + * the context of the link event callback.
> + *
> + * Return: One if the link is up, zero if the link is down, otherwise a
> + * negative value indicating the error number.
> + */
> +static inline int ntb_link_is_up(struct ntb_dev *ntb,
> + enum ntb_speed *speed, enum ntb_width *width)
> +{
> + return ntb->ops->link_is_up(ntb, speed, width);
> +}
> +
> +/**
> + * ntb_link_enable() - enable the link on the secondary side of the ntb
> + * @ntb: NTB device context.
> + * @max_speed: The maximum link speed expressed as PCIe generation number.
> + * @max_width: The maximum link width expressed as the number of PCIe lanes.
> + *
> + * Enable the link on the secondary side of the ntb. This can only be done
> + * from the primary side of the ntb in primary or b2b topology. The ntb device
> + * should train the link to its maximum speed and width, or the requested speed
> + * and width, whichever is smaller, if supported.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_link_enable(struct ntb_dev *ntb,
> + enum ntb_speed max_speed,
> + enum ntb_width max_width)
> +{
> + return ntb->ops->link_enable(ntb, max_speed, max_width);
> +}
> +
> +/**
> + * ntb_link_disable() - disable the link on the secondary side of the ntb
> + * @ntb: NTB device context.
> + *
> + * Disable the link on the secondary side of the ntb. This can only be
> + * done from the primary side of the ntb in primary or b2b topology. The ntb
> + * device should disable the link. Returning from this call must indicate that
> + * a barrier has passed, though with no more writes may pass in either
> + * direction across the link, except if this call returns an error number.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_link_disable(struct ntb_dev *ntb)
> +{
> + return ntb->ops->link_disable(ntb);
> +}
> +
> +/**
> * ntb_mw_count() - get the number of memory windows
> * @ntb: NTB device context.
> *
> @@ -517,62 +574,6 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
> }
>
> /**
> - * ntb_link_is_up() - get the current ntb link state
> - * @ntb: NTB device context.
> - * @speed: OUT - The link speed expressed as PCIe generation number.
> - * @width: OUT - The link width expressed as the number of PCIe lanes.
> - *
> - * Get the current state of the ntb link. It is recommended to query the link
> - * state once after every link event. It is safe to query the link state in
> - * the context of the link event callback.
> - *
> - * Return: One if the link is up, zero if the link is down, otherwise a
> - * negative value indicating the error number.
> - */
> -static inline int ntb_link_is_up(struct ntb_dev *ntb,
> - enum ntb_speed *speed, enum ntb_width *width)
> -{
> - return ntb->ops->link_is_up(ntb, speed, width);
> -}
> -
> -/**
> - * ntb_link_enable() - enable the link on the secondary side of the ntb
> - * @ntb: NTB device context.
> - * @max_speed: The maximum link speed expressed as PCIe generation number.
> - * @max_width: The maximum link width expressed as the number of PCIe lanes.
> - *
> - * Enable the link on the secondary side of the ntb. This can only be done
> - * from the primary side of the ntb in primary or b2b topology. The ntb device
> - * should train the link to its maximum speed and width, or the requested speed
> - * and width, whichever is smaller, if supported.
> - *
> - * Return: Zero on success, otherwise an error number.
> - */
> -static inline int ntb_link_enable(struct ntb_dev *ntb,
> - enum ntb_speed max_speed,
> - enum ntb_width max_width)
> -{
> - return ntb->ops->link_enable(ntb, max_speed, max_width);
> -}
> -
> -/**
> - * ntb_link_disable() - disable the link on the secondary side of the ntb
> - * @ntb: NTB device context.
> - *
> - * Disable the link on the secondary side of the ntb. This can only be
> - * done from the primary side of the ntb in primary or b2b topology. The ntb
> - * device should disable the link. Returning from this call must indicate that
> - * a barrier has passed, though with no more writes may pass in either
> - * direction across the link, except if this call returns an error number.
> - *
> - * Return: Zero on success, otherwise an error number.
> - */
> -static inline int ntb_link_disable(struct ntb_dev *ntb)
> -{
> - return ntb->ops->link_disable(ntb);
> -}
> -
> -/**
> * ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
> * @ntb: NTB device context.
> *
> --
> 2.6.6

2016-12-04 00:09:56

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 07/22] NTB: Fix a few ntb.h issues

From: Serge Semin
> Fix some minor issues found in ntb.h file.
>

"Fix a few issues" is not a descriptive commit title or message.

Please split: add NTB_SPEED_GEN4, ntb.h comments.

Changes look good and I will ack.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> include/linux/ntb.h | 18 ++++++++++++------
> 1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index a59a155..8b19327 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -90,6 +90,7 @@ static inline char *ntb_topo_string(enum ntb_topo topo)
> * @NTB_SPEED_GEN1: Link is trained to gen1 speed.
> * @NTB_SPEED_GEN2: Link is trained to gen2 speed.
> * @NTB_SPEED_GEN3: Link is trained to gen3 speed.
> + * @NTB_SPEED_GEN4: Link is trained to gen4 speed.
> */
> enum ntb_speed {
> NTB_SPEED_AUTO = -1,
> @@ -97,6 +98,7 @@ enum ntb_speed {
> NTB_SPEED_GEN1 = 1,
> NTB_SPEED_GEN2 = 2,
> NTB_SPEED_GEN3 = 3,
> + NTB_SPEED_GEN4 = 4
> };
>
> /**
> @@ -292,13 +294,18 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> {
> /* commented callbacks are not required: */
> return
> + /* Port operations are required */
> ops->port_number &&
> ops->peer_port_count &&
> ops->peer_port_number &&
> ops->peer_port_idx &&
> +
> + /* Link operations are requiered */
> ops->link_is_up &&
> ops->link_enable &&
> ops->link_disable &&
> +
> + /* One or both MW interfaces should be developed */
> ops->mw_count &&
> ops->mw_get_align &&
> (ops->mw_set_trans ||
> @@ -308,12 +315,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> ops->peer_mw_get_addr &&
> /* ops->peer_mw_clear_trans && */
>
> + /* Doorbell operations are mostly required */
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
> -
> /* both set, or both unset */
> (!ops->db_vector_count == !ops->db_vector_mask) &&
> -
> ops->db_read &&
> /* ops->db_set && */
> ops->db_clear &&
> @@ -327,6 +333,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* ops->peer_db_read_mask && */
> /* ops->peer_db_set_mask && */
> /* ops->peer_db_clear_mask && */
> +
> + /* Scrachpad or messaging interfaces should be developed */
> ((/* ops->spad_is_unsafe && */
> ops->spad_count &&
> ops->spad_read &&
> @@ -355,13 +363,12 @@ struct ntb_client {
> struct device_driver drv;
> const struct ntb_client_ops ops;
> };
> -
> #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
>
> /**
> * struct ntb_device - ntb device
> * @dev: Linux device object.
> - * @pdev: Pci device entry of the ntb.
> + * @pdev: PCI device entry of the ntb.
> * @topo: Detected topology of the ntb.
> * @port: Local port of the ntb.
> * @ops: See &ntb_dev_ops.
> @@ -384,7 +391,6 @@ struct ntb_dev {
> /* block unregister until device is fully released */
> struct completion released;
> };
> -
> #define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
>
> /**
> @@ -481,7 +487,7 @@ void ntb_link_event(struct ntb_dev *ntb);
> * multiple interrupt vectors for doorbells, the vector number indicates which
> * vector received the interrupt. The vector number is relative to the first
> * vector used for doorbells, starting at zero, and must be less than
> - ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> + * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> * doorbell bits need service, and ntb_db_vector_mask() to determine which of
> * those bits are associated with the vector number.
> */
> --
> 2.6.6


2016-12-04 00:10:45

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 08/22] NTB: Add T-Platforms copyrights to NTB API

> From: Serge Semin
>
> Signed-off-by: Serge Semin <[email protected]>

This patch has no comment, but instead...

This can be squashed with your first commit of significant changes to each file.

>
> ---
> drivers/ntb/ntb.c | 2 ++
> include/linux/ntb.h | 2 ++
> 2 files changed, 4 insertions(+)
>
> diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
> index 4b2cc60..06574f8 100644
> --- a/drivers/ntb/ntb.c
> +++ b/drivers/ntb/ntb.c
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -18,6 +19,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 8b19327..9edd9dc 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -18,6 +19,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> --
> 2.6.6


2016-12-04 00:10:58

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 04/22] NTB: Add messaging NTB API

From: Serge Semin
> IDT PCIe-switches have message registers to communicate with peer devices.
> This patch adds new NTB API callback methods, which can be used to utilize
> these registers functionality.
>

Please split: add msg api; make spads optional.

See comments below on ntb_dev_ops_is_valid.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> drivers/ntb/ntb.c | 13 +++
> include/linux/ntb.h | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 241 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
> index 2e25307..4b2cc60 100644
> --- a/drivers/ntb/ntb.c
> +++ b/drivers/ntb/ntb.c
> @@ -191,6 +191,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
> }
> EXPORT_SYMBOL(ntb_db_event);
>
> +void ntb_msg_event(struct ntb_dev *ntb)
> +{
> + unsigned long irqflags;
> +
> + spin_lock_irqsave(&ntb->ctx_lock, irqflags);
> + {
> + if (ntb->ctx_ops && ntb->ctx_ops->msg_event)
> + ntb->ctx_ops->msg_event(ntb->ctx);
> + }
> + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
> +}
> +EXPORT_SYMBOL(ntb_msg_event);
> +
> static int ntb_probe(struct device *dev)
> {
> struct ntb_dev *ntb;
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 4a150b5..59de1f6 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -146,10 +146,12 @@ static inline int ntb_client_ops_is_valid(const struct
> ntb_client_ops *ops)
> * struct ntb_ctx_ops - ntb driver context operations
> * @link_event: See ntb_link_event().
> * @db_event: See ntb_db_event().
> + * @msg_event: See ntb_msg_event().
> */
> struct ntb_ctx_ops {
> void (*link_event)(void *ctx);
> void (*db_event)(void *ctx, int db_vector);
> + void (*msg_event)(void *ctx);
> };
>
> static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> @@ -158,6 +160,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> return
> /* ops->link_event && */
> /* ops->db_event && */
> + /* ops->msg_event && */
> 1;
> }
>
> @@ -202,6 +205,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_addr: See ntb_peer_spad_addr().
> * @peer_spad_read: See ntb_peer_spad_read().
> * @peer_spad_write: See ntb_peer_spad_write().
> + * @msg_count: See ntb_msg_count().
> + * @msg_inbits: See ntb_msg_inbits().
> + * @msg_outbits: See ntb_msg_outbits().
> + * @msg_read_sts: See ntb_msg_read_sts().
> + * @msg_clear_sts: See ntb_msg_clear_sts().
> + * @msg_set_mask: See ntb_msg_set_mask().
> + * @msg_clear_mask: See ntb_msg_clear_mask().
> + * @msg_read: See ntb_msg_read().
> + * @msg_write: See ntb_msg_write().
> */
> struct ntb_dev_ops {
> int (*port_number)(struct ntb_dev *ntb);
> @@ -263,6 +275,16 @@ struct ntb_dev_ops {
> phys_addr_t *spad_addr);
> u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
> int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
> +
> + int (*msg_count)(struct ntb_dev *ntb);
> + u64 (*msg_inbits)(struct ntb_dev *ntb);
> + u64 (*msg_outbits)(struct ntb_dev *ntb);
> + u64 (*msg_read_sts)(struct ntb_dev *ntb);
> + int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits);
> + int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits);
> + int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
> + int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg);
> + int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg);
> };
>
> static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> @@ -304,13 +326,22 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> /* ops->peer_db_read_mask && */
> /* ops->peer_db_set_mask && */
> /* ops->peer_db_clear_mask && */
> - /* ops->spad_is_unsafe && */
> - ops->spad_count &&
> - ops->spad_read &&
> - ops->spad_write &&
> - /* ops->peer_spad_addr && */
> - /* ops->peer_spad_read && */
> - ops->peer_spad_write &&
> + ((/* ops->spad_is_unsafe && */
> + ops->spad_count &&
> + ops->spad_read &&
> + ops->spad_write &&
> + /* ops->peer_spad_addr && */
> + /* ops->peer_spad_read && */
> + ops->peer_spad_write) ||
> + (ops->msg_count &&
> + ops->msg_inbits &&
> + ops->msg_outbits &&
> + ops->msg_read_sts &&
> + ops->msg_clear_sts &&
> + /* ops->msg_set_mask && */
> + /* ops->msg_clear_mask && */
> + ops->msg_read &&
> + ops->msg_write)) &&

Don't enforce "must have spad or msg" here, leave it to application to check spad_count != 0 or msg_count != 0 else fail. If an ntb doesn't have either, it may be rather limited, but let's not prevent the driver to register that device.

As written above has a subtle bug. We should say, if spad is implemented at all, then the basic spad api is fully implemented; likewise if msg is implemented at all, then the basic msg api is fully implemented.

As written below, the required basic api of spad ops must have the same truth-value of spad_count (and likewise for msg_count).

/* !ops->spad_is_unsafe == !ops->spad_count && */
!ops->spad_read == !ops->spad_count &&
!ops->spad_write == !ops->spad_count &&
/* !ops->peer_spad_addr == !ops->spad_count && */
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&

!ops->msg_inbits == !ops->msg_count &&
!ops->msg_outbits == !ops->msg_count &&
!ops->msg_read_sts == !ops->msg_count &&
!ops->msg_clear_sts == !ops->msg_count &&
/* !ops->msg_set_mask == !ops->msg_count && */
/* !ops->msg_clear_mask == !ops->msg_count && */
!ops->msg_read == !ops->msg_count &&
!ops->msg_write == !ops->msg_count &&

> 1;
> }
>
> @@ -456,6 +487,18 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_msg_event() - notify driver context of a message event
> + * @ntb: NTB device context.
> + *
> + * Notify the driver context of a message event. If hardware supports
> + * message registers, this event indicates, that a new message arrived in
> + * some incoming message register or last sent message couldn't be delivered.
> + * The events can be masked/unmasked by the methods ntb_msg_set_mask() and
> + * ntb_msg_clear_mask().
> + */
> +void ntb_msg_event(struct ntb_dev *ntb);
> +
> +/**
> * ntb_port_number() - get the local port number
> * @ntb: NTB device context.
> *
> @@ -1154,7 +1197,7 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
> }
>
> /**
> - * ntb_mw_count() - get the number of scratchpads
> + * ntb_spad_count() - get the number of scratchpads
> * @ntb: NTB device context.
> *
> * Hardware and topology may support a different number of scratchpads.
> @@ -1163,6 +1206,9 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
> */
> static inline int ntb_spad_count(struct ntb_dev *ntb)
> {
> + if (!ntb->ops->spad_count)
> + return 0;
> +
> return ntb->ops->spad_count(ntb);
> }
>
> @@ -1177,6 +1223,9 @@ static inline int ntb_spad_count(struct ntb_dev *ntb)
> */
> static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
> {
> + if (!ntb->ops->spad_read)
> + return ~(u32)0;
> +
> return ntb->ops->spad_read(ntb, idx);
> }
>
> @@ -1192,6 +1241,9 @@ static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
> */
> static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> {
> + if (!ntb->ops->spad_write)
> + return -EINVAL;
> +
> return ntb->ops->spad_write(ntb, idx, val);
> }
>
> @@ -1226,6 +1278,9 @@ static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
> */
> static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> {
> + if (!ntb->ops->peer_spad_read)
> + return ~(u32)0;
> +
> return ntb->ops->peer_spad_read(ntb, idx);
> }
>
> @@ -1241,7 +1296,172 @@ static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> */
> static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> {
> + if (!ntb->ops->peer_spad_write)
> + return -EINVAL;
> +
> return ntb->ops->peer_spad_write(ntb, idx, val);
> }
>
> +/**
> + * ntb_msg_count() - get the number of message registers
> + * @ntb: NTB device context.
> + *
> + * Hardware may support a different number of messge registers.
> + *
> + * Return: the number of message registers.
> + */
> +static inline int ntb_msg_count(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_count)
> + return 0;
> +
> + return ntb->ops->msg_count(ntb);
> +}
> +
> +/**
> + * ntb_msg_inbits() - get a bitsfield of inbound message registers status
> + * @ntb: NTB device context.
> + *
> + * The method returns the bitsfield of status and mask registers, which related
> + * to inbound message registers.
> + *
> + * Return: bitsfield of inbound message registers.
> + */
> +static inline u64 ntb_msg_inbits(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_inbits)
> + return 0;
> +
> + return ntb->ops->msg_inbits(ntb);
> +}
> +
> +/**
> + * ntb_msg_outbits() - get a bitsfield of outbound message registers status
> + * @ntb: NTB device context.
> + *
> + * The method returns the bitsfield of status and mask registers, which related
> + * to outbound message registers.
> + *
> + * Return: bitsfield of outbound message registers.
> + */
> +static inline u64 ntb_msg_outbits(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_outbits)
> + return 0;
> +
> + return ntb->ops->msg_outbits(ntb);
> +}
> +
> +/**
> + * ntb_msg_read_sts() - read the message registers status
> + * @ntb: NTB device context.
> + *
> + * Read the status of message register. Inbound and outbound message registers
> + * related bits can be filetered by masks retrieved from ntb_msg_inbits() and
> + * ntb_msg_outbits().
> + *
> + * Return: status bits of message registers
> + */
> +static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_read_sts)
> + return 0;
> +
> + return ntb->ops->msg_read_sts(ntb);
> +}
> +
> +/**
> + * ntb_msg_clear_sts() - clear status bits of message registers
> + * @ntb: NTB device context.
> + * @sts_bits: Status bits to clear.
> + *
> + * Clear bits in the status register.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
> +{
> + if (!ntb->ops->msg_clear_sts)
> + return -EINVAL;
> +
> + return ntb->ops->msg_clear_sts(ntb, sts_bits);
> +}
> +
> +/**
> + * ntb_msg_set_mask() - set mask of message register status bits
> + * @ntb: NTB device context.
> + * @mask_bits: Mask bits.
> + *
> + * Mask the message registers status bits from raising the message event.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
> +{
> + if (!ntb->ops->msg_set_mask)
> + return -EINVAL;
> +
> + return ntb->ops->msg_set_mask(ntb, mask_bits);
> +}
> +
> +/**
> + * ntb_msg_clear_mask() - clear message registers mask
> + * @ntb: NTB device context.
> + * @mask_bits: Mask bits to clear.
> + *
> + * Clear bits in the message events mask register.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
> +{
> + if (!ntb->ops->msg_clear_mask)
> + return -EINVAL;
> +
> + return ntb->ops->msg_clear_mask(ntb, mask_bits);
> +}
> +
> +/**
> + * ntb_msg_read() - read message register with specified index
> + * @ntb: NTB device context.
> + * @midx: Message register index
> + * @pidx: OUT - Port index of peer device a message retrieved from
> + * @msg: OUT - Data
> + *
> + * Read data from the specified message register. Source port index of a
> + * message is retrieved as well.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx,
> + u32 *msg)
> +{
> + if (!ntb->ops->msg_read)
> + return -EINVAL;
> +
> + return ntb->ops->msg_read(ntb, midx, pidx, msg);
> +}
> +
> +/**
> + * ntb_msg_write() - write data to the specified message register
> + * @ntb: NTB device context.
> + * @midx: Message register index
> + * @pidx: Port index of peer device a message being sent to
> + * @msg: Data to send
> + *
> + * Send data to a specified peer device using the defined message register.
> + * Message event can be raised if the midx registers isn't empty while
> + * calling this method and the corresponding interrupt isn't masked.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx,
> + u32 msg)
> +{
> + if (!ntb->ops->msg_write)
> + return -EINVAL;
> +
> + return ntb->ops->msg_write(ntb, midx, pidx, msg);
> +}
> +
> #endif
> --
> 2.6.6


2016-12-04 00:13:38

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 03/22] NTB: Alter NTB API to support both inbound and outbound MW based interfaces

From: Serge Semin
> Alter NTB API to support inbound and outbound MW based interfaces.
> Additionally I made it supporting multi-port devices as well. Useful
> infographics is added right before MW API is declared. It shall help to
> better understand how the new API really works and how it can be utilized
> within client drivers.
>

This looks good. I plan to ack.

See comments below on documentation.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> include/linux/ntb.h | 290 ++++++++++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 245 insertions(+), 45 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 0941a43..4a150b5 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -171,9 +171,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @link_enable: See ntb_link_enable().
> * @link_disable: See ntb_link_disable().
> * @mw_count: See ntb_mw_count().
> - * @mw_get_range: See ntb_mw_get_range().
> + * @mw_get_align: See ntb_mw_get_align().
> * @mw_set_trans: See ntb_mw_set_trans().
> * @mw_clear_trans: See ntb_mw_clear_trans().
> + * @peer_mw_count: See ntb_peer_mw_count().
> + * @peer_mw_get_addr: See ntb_peer_mw_get_addr().
> + * @peer_mw_set_trans: See ntb_peer_mw_set_trans().
> + * @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
> * @db_is_unsafe: See ntb_db_is_unsafe().
> * @db_valid_mask: See ntb_db_valid_mask().
> * @db_vector_count: See ntb_db_vector_count().
> @@ -211,13 +215,20 @@ struct ntb_dev_ops {
> enum ntb_speed max_speed, enum ntb_width max_width);
> int (*link_disable)(struct ntb_dev *ntb);
>
> - int (*mw_count)(struct ntb_dev *ntb);
> - int (*mw_get_range)(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base, resource_size_t *size,
> - resource_size_t *align, resource_size_t *align_size);
> - int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
> + int (*mw_count)(struct ntb_dev *ntb, int pidx);
> + int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
> + resource_size_t *addr_align,
> + resource_size_t *size_align,
> + resource_size_t *size_max);
> + int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
> dma_addr_t addr, resource_size_t size);
> - int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
> + int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
> + int (*peer_mw_count)(struct ntb_dev *ntb);
> + int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
> + phys_addr_t *base, resource_size_t *size);
> + int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
> + u64 addr, resource_size_t size);
> + int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
>
> int (*db_is_unsafe)(struct ntb_dev *ntb);
> u64 (*db_valid_mask)(struct ntb_dev *ntb);
> @@ -266,9 +277,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> ops->link_enable &&
> ops->link_disable &&
> ops->mw_count &&
> - ops->mw_get_range &&
> - ops->mw_set_trans &&
> + ops->mw_get_align &&
> + (ops->mw_set_trans ||
> + ops->peer_mw_set_trans) &&
> /* ops->mw_clear_trans && */
> + ops->peer_mw_count &&
> + ops->peer_mw_get_addr &&
> + /* ops->peer_mw_clear_trans && */
>
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
> @@ -555,79 +570,264 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
> }
>
> /**
> - * ntb_mw_count() - get the number of memory windows
> + * NTB Memory Windows description

The two variants could be more succintly described as "inbound translation configured on the local ntb port" and "outbound translation configured by the peer, on the peer ntb port" for a locally allocated dma-mapped range of memory.

Please avoid confusing these concepts in the documentation:
- "Memory" on the system vs. "Memory Window" on the ntb
- "Physical" address vs. "dma-mapped" address of memory
- "Base Address" vs. "Translation Address"

Inbound translation:

Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
____________
| dma-mapped |-ntb_set_xlat_addr(addr) |
| memory | _v____________ | ______________
| (addr) |<======| MW xlat addr |<====| MW base addr |<==== memory-mapped IO
|------------| |--------------| | |--------------|

Outbound translation:

Memory: Local NTB Port: Peer NTB Port: Peer MMIO:

____________ ______________
| dma-mapped | | | MW base addr |<==== memory-mapped IO
| memory | | |--------------|
| (addr) |<===========================| MW xlat addr |<-ntb_peer_set_xlat_addr(addr)
|------------| | |--------------|

> + * There are two types of memory window interfaces supported by the NTB API:
> + * local and peer side initialization of memory sharing. The first type is
> + * depicted on the next figure:
> + *
> + * Local device: | Peer device:
> + * NTB config |
> + * Physical memory (RAM) __________ | Memory mapped IO
> + * ____________ +-->| addr | | _____________
> + * | | | |----------| | | |
> + * |------------|addr--+ | |-------------|
> + * | Inbound MW | PCI Express + NTB | Outbound MW |
> + * | |<=====================================| |
> + * |------------| |-------------|
> + *
> + * So typical scenario of the first type memory window initialization looks:
> + * 1) allocate a memory region, 2) put translated base address to NTB config,
> + * 3) somehow notify a peer device of performed initialization, 4) peer device
> + * maps corresponding outbound memory window so to have access to the shared
> + * memory region.
> + *
> + * The second type of interface, that implies the shared windows being
> + * initialized by a peer device, is depicted on the figure:
> + *
> + * Local device: | Peer device:
> + * | NTB config
> + * Physical memory (RAM) | __________ Memory mapped IO
> + * ____________ +-------------->| addr | _____________
> + * | | | | |----------| | |
> + * |------------|addr---+ | |-------------|
> + * | Inbound MW | PCI Express + NTB | Outbound MW |
> + * | |<=====================================| |
> + * |------------| |-------------|
> + *
> + * Typical scenario of the second type initialization would be:
> + * 1) allocate a memory region, 2) somehow deliver a translated base address
> + * to a peer device, 3) peer puts the translated base address to NTB config,
> + * 4) peer device maps outbound memory window so to have access to the shared
> + * memory region.
> + *
> + * As one can see the described scenarios can be combined in one portable
> + * algorithm.
> + * Local device:
> + * 1) Allocate memory for a shared window
> + * 2) Initialize memory window by base address of the allocated region
> + * (it may fail if local memory window initialzation is unsupported)
> + * 3) Send translated base address and memory window index to a peer device
> + * Peer device:
> + * 1) Initialize memory window by retrieved base address of the allocated
> + * by another device memory region (it may fail if peer memory window
> + * initialization is unsupported)
> + * 2) Map outbound memory window
> + * 3) Done
> + * In accordance with this scenario, the NTB Memory Window API can be used as
> + * follows:
> + * Local device:
> + * 1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
> + * be allocated for memory windows between local device and peer device
> + * of port with specified index.
> + * 2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
> + * shared memory region alignment and size. Then memory can be properly
> + * allocated.
> + * 3) Allocate physically contiguous memory region in complience with
> + * restrictions retrieved in 2).
> + * 4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
> + * the memory window with specified index for the defined peer device
> + * (it may fail if local translated address setting is not supported)
> + * 5) Send translated base address (usually together with memory window
> + * number) to the peer device using, for instance, scratchpad or message
> + * registers.
> + * Peer device:
> + * 1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
> + * device (related to pidx) translated base address for specified memory
> + * window. It may fail if retrieved address, for instance, exceeds
> + * maximum possible address or isn't properly aligned.
> + * 2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
> + * window so to have an access to the shared memory.

The above section belongs in Documentation/ntb.txt. Thanks for describing how to use the api so that portable applications can work with either variant of memory window configuration.

> + *
> + * Also it is worth to note, that method ntb_mw_count(pidx) should return the
> + * same value as ntb_peer_mw_count() of the peer with port index - pidx.
> + */
> +
> +/**
> + * ntb_mw_count() - get the number of inbound memory windows, which could
> + * be created for a specified peer device
> * @ntb: NTB device context.
> + * @pidx: Port index of peer device.
> *
> * Hardware and topology may support a different number of memory windows.
> + * Moreover different peer devices can support different number of memory
> + * windows. Simply speaking this method returns the number of possible inbound
> + * memory windows to share with specified peer device.
> *
> * Return: the number of memory windows.
> */
> -static inline int ntb_mw_count(struct ntb_dev *ntb)
> +static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
> {
> - return ntb->ops->mw_count(ntb);
> + return ntb->ops->mw_count(ntb, pidx);
> }
>
> /**
> - * ntb_mw_get_range() - get the range of a memory window
> + * ntb_mw_get_align() - get the restriction parameters of inbound memory window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> - * @base: OUT - the base address for mapping the memory window
> - * @size: OUT - the size for mapping the memory window
> - * @align: OUT - the base alignment for translating the memory window
> - * @align_size: OUT - the size alignment for translating the memory window
> - *
> - * Get the range of a memory window. NULL may be given for any output
> - * parameter if the value is not needed. The base and size may be used for
> - * mapping the memory window, to access the peer memory. The alignment and
> - * size may be used for translating the memory window, for the peer to access
> - * memory on the local system.
> - *
> - * Return: Zero on success, otherwise an error number.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + * @addr_align: OUT - the base alignment for translating the memory window
> + * @size_align: OUT - the size alignment for translating the memory window
> + * @size_max: OUT - the maximum size of the memory window
> + *
> + * Get the alignments of an inbound memory window with specified index.
> + * NULL may be given for any output parameter if the value is not needed.
> + * The alignment and size parameters may be used for allocation of proper
> + * shared memory.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> */
> -static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base, resource_size_t *size,
> - resource_size_t *align, resource_size_t *align_size)
> +static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
> + resource_size_t *addr_align,
> + resource_size_t *size_align,
> + resource_size_t *size_max)
> {
> - return ntb->ops->mw_get_range(ntb, idx, base, size,
> - align, align_size);
> + return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
> + size_max);
> }
>
> /**
> - * ntb_mw_set_trans() - set the translation of a memory window
> + * ntb_mw_set_trans() - set the translation of an inbound memory window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> - * @addr: The dma address local memory to expose to the peer.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + * @addr: The dma address of local memory to expose to the peer.
> * @size: The size of the local memory to expose to the peer.
> *
> * Set the translation of a memory window. The peer may access local memory
> * through the window starting at the address, up to the size. The address
> - * must be aligned to the alignment specified by ntb_mw_get_range(). The size
> - * must be aligned to the size alignment specified by ntb_mw_get_range().
> + * and size must be aligned in complience with restrictions of
> + * ntb_mw_get_align(). The region size should not exceed the size_max parameter
> + * of that method.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
> dma_addr_t addr, resource_size_t size)
> {
> - return ntb->ops->mw_set_trans(ntb, idx, addr, size);
> + if (!ntb->ops->mw_set_trans)
> + return -EINVAL;
> +
> + return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
> }
>
> /**
> - * ntb_mw_clear_trans() - clear the translation of a memory window
> + * ntb_mw_clear_trans() - clear the translation address of an inbound memory
> + * window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> *
> - * Clear the translation of a memory window. The peer may no longer access
> - * local memory through the window.
> + * Clear the translation of an inbound memory window. The peer may no longer
> + * access local memory through the window.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
> +static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
> {
> if (!ntb->ops->mw_clear_trans)
> - return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
> + return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
> +
> + return ntb->ops->mw_clear_trans(ntb, pidx, widx);
> +}
> +
> +/**
> + * ntb_peer_mw_count() - get the number of outbound memory windows, which could
> + * be mapped to access a shared memory
> + * @ntb: NTB device context.
> + *
> + * Hardware and topology may support a different number of memory windows.
> + * This method returns the number of outbound memory windows supported by
> + * local device.
> + *
> + * Return: the number of memory windows.
> + */
> +static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
> +{
> + return ntb->ops->peer_mw_count(ntb);
> +}
> +
> +/**
> + * ntb_peer_mw_get_addr() - get map address of an outbound memory window
> + * @ntb: NTB device context.
> + * @widx: Memory window index (within ntb_peer_mw_count() return value).
> + * @base: OUT - the base address of mapping region.
> + * @size: OUT - the size of mapping region.
> + *
> + * Get base and size of memory region to map. NULL may be given for any output
> + * parameter if the value is not needed. The base and size may be used for
> + * mapping the memory window, to access the peer memory.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
> + phys_addr_t *base, resource_size_t *size)
> +{
> + return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
> +}
> +
> +/**
> + * ntb_peer_mw_set_trans() - set a translation address of a memory window
> + * retrieved from a peer device
> + * @ntb: NTB device context.
> + * @pidx: Port index of peer device the translation address received from.
> + * @widx: Memory window index.
> + * @addr: The dma address of the shared memory to access.
> + * @size: The size of the shared memory to access.
> + *
> + * Set the translation of an outbound memory window. The local device may
> + * access shared memory allocated by a peer device sent the address.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface, so a translation address can be only set on the side,
> + * where shared memory (inbound memory windows) is allocated.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
> + u64 addr, resource_size_t size)
> +{
> + if (!ntb->ops->peer_mw_set_trans)
> + return -EINVAL;
> +
> + return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
> +}
> +
> +/**
> + * ntb_peer_mw_clear_trans() - clear the translation address of an outbound
> + * memory window
> + * @ntb: NTB device context.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + *
> + * Clear the translation of a outbound memory window. The local device may no
> + * longer access a shared memory through the window.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
> + int widx)
> +{
> + if (!ntb->ops->peer_mw_clear_trans)
> + return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);
>
> - return ntb->ops->mw_clear_trans(ntb, idx);
> + return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
> }
>
> /**
> --
> 2.6.6


2016-12-04 00:17:12

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 06/22] NTB: Slightly alter link state NTB API

From: Serge Semin
> Some minor changes of link state NTB API. Particularly link_is_up()
> method from now shall return a bitfield of link states for all accessible
> port indexes.

Looks good. I plan to ack.

See comment on ntb_link_enable.

>
> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> include/linux/ntb.h | 31 ++++++++++++++++---------------
> 1 file changed, 16 insertions(+), 15 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index fc9d034..a59a155 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -221,7 +221,7 @@ struct ntb_dev_ops {
> int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
> int (*peer_port_idx)(struct ntb_dev *ntb, int port);
>
> - int (*link_is_up)(struct ntb_dev *ntb,
> + u64 (*link_is_up)(struct ntb_dev *ntb,
> enum ntb_speed *speed, enum ntb_width *width);
> int (*link_enable)(struct ntb_dev *ntb,
> enum ntb_speed max_speed, enum ntb_width max_width);
> @@ -567,25 +567,26 @@ static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> * state once after every link event. It is safe to query the link state in
> * the context of the link event callback.
> *
> - * Return: One if the link is up, zero if the link is down, otherwise a
> - * negative value indicating the error number.
> + * Return: bitfield of indexed ports link state: bit is set/cleared if the
> + * link is up/down respectively, otherwise a negative value indicating
> + * an error number.
> */
> -static inline int ntb_link_is_up(struct ntb_dev *ntb,
> +static inline u64 ntb_link_is_up(struct ntb_dev *ntb,
> enum ntb_speed *speed, enum ntb_width *width)
> {
> return ntb->ops->link_is_up(ntb, speed, width);
> }
>
> /**
> - * ntb_link_enable() - enable the link on the secondary side of the ntb
> + * ntb_link_enable() - enable the link of the ntb

Maybe: enable the local port ntb connection. The description that follows is good for B2B topology, but the description including "link training" might not be accurate for multi-port devices.

> * @ntb: NTB device context.
> * @max_speed: The maximum link speed expressed as PCIe generation number.
> * @max_width: The maximum link width expressed as the number of PCIe lanes.
> *
> - * Enable the link on the secondary side of the ntb. This can only be done
> - * from the primary side of the ntb in primary or b2b topology. The ntb device
> - * should train the link to its maximum speed and width, or the requested speed
> - * and width, whichever is smaller, if supported.
> + * Enable the NTB/PCIe link on the local or remote (for bridge-to-bridge
> + * topology) side of the bridge. The ntb device should train the link to its
> + * maximum speed and width, or the requested speed and width, whichever is
> + * smaller, if supported.
> *
> * Return: Zero on success, otherwise an error number.
> */
> @@ -597,14 +598,14 @@ static inline int ntb_link_enable(struct ntb_dev *ntb,
> }
>
> /**
> - * ntb_link_disable() - disable the link on the secondary side of the ntb
> + * ntb_link_disable() - disable the link of the ntb
> * @ntb: NTB device context.
> *
> - * Disable the link on the secondary side of the ntb. This can only be
> - * done from the primary side of the ntb in primary or b2b topology. The ntb
> - * device should disable the link. Returning from this call must indicate that
> - * a barrier has passed, though with no more writes may pass in either
> - * direction across the link, except if this call returns an error number.
> + * Disable the link on the local or remote (for b2b topology) of the ntb.
> + * The ntb device should disable the link. Returning from this call must
> + * indicate that a barrier has passed, though with no more writes may pass in
> + * either direction across the link, except if this call returns an error
> + * number.
> *
> * Return: Zero on success, otherwise an error number.
> */
> --
> 2.6.6


2016-12-04 00:41:31

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 02/22] NTB: Add peer indexed ports NTB API

From: Serge Semin
> Add new port-index NTB API. Additionally lets get rid of Primary and
> Secondary topologies, since port-number can be effectively used instead.

Split into two patches please.

I see no harm to the TOPO changes, though I wonder if they are necessary.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> include/linux/ntb.h | 101 ++++++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 79 insertions(+), 22 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 5d1f260..0941a43 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -64,37 +64,21 @@ struct pci_dev;
> /**
> * enum ntb_topo - NTB connection topology
> * @NTB_TOPO_NONE: Topology is unknown or invalid.
> - * @NTB_TOPO_PRI: On primary side of local ntb.
> - * @NTB_TOPO_SEC: On secondary side of remote ntb.
> - * @NTB_TOPO_B2B_USD: On primary side of local ntb upstream of remote ntb.
> - * @NTB_TOPO_B2B_DSD: On primary side of local ntb downstream of remote ntb.
> + * @NTB_TOPO_P2P: Simple port-to-port NTB topology
> + * @NTB_TOPO_B2B: Bridge-to-bridge NTB topology
> */
> enum ntb_topo {
> NTB_TOPO_NONE = -1,
> - NTB_TOPO_PRI,
> - NTB_TOPO_SEC,
> - NTB_TOPO_B2B_USD,
> - NTB_TOPO_B2B_DSD,
> + NTB_TOPO_P2P,
> + NTB_TOPO_B2B
> };
>
> -static inline int ntb_topo_is_b2b(enum ntb_topo topo)
> -{
> - switch ((int)topo) {
> - case NTB_TOPO_B2B_USD:
> - case NTB_TOPO_B2B_DSD:
> - return 1;
> - }
> - return 0;
> -}
> -
> static inline char *ntb_topo_string(enum ntb_topo topo)
> {
> switch (topo) {
> case NTB_TOPO_NONE: return "NTB_TOPO_NONE";
> - case NTB_TOPO_PRI: return "NTB_TOPO_PRI";
> - case NTB_TOPO_SEC: return "NTB_TOPO_SEC";
> - case NTB_TOPO_B2B_USD: return "NTB_TOPO_B2B_USD";
> - case NTB_TOPO_B2B_DSD: return "NTB_TOPO_B2B_DSD";
> + case NTB_TOPO_P2P: return "NTB_TOPO_P2P";
> + case NTB_TOPO_B2B: return "NTB_TOPO_B2B";
> }
> return "NTB_TOPO_INVALID";
> }
> @@ -179,6 +163,10 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
>
> /**
> * struct ntb_ctx_ops - ntb device operations
> + * @port_number: See ntb_port_number().
> + * @peer_port_count: See ntb_peer_port_count().
> + * @peer_port_number: See ntb_peer_port_number().
> + * @peer_port_idx: See ntb_peer_port_idx().
> * @link_is_up: See ntb_link_is_up().
> * @link_enable: See ntb_link_enable().
> * @link_disable: See ntb_link_disable().
> @@ -212,6 +200,11 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_write: See ntb_peer_spad_write().
> */
> struct ntb_dev_ops {
> + int (*port_number)(struct ntb_dev *ntb);
> + int (*peer_port_count)(struct ntb_dev *ntb);
> + int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
> + int (*peer_port_idx)(struct ntb_dev *ntb, int port);
> +
> int (*link_is_up)(struct ntb_dev *ntb,
> enum ntb_speed *speed, enum ntb_width *width);
> int (*link_enable)(struct ntb_dev *ntb,
> @@ -265,6 +258,10 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> {
> /* commented callbacks are not required: */
> return
> + ops->port_number &&
> + ops->peer_port_count &&
> + ops->peer_port_number &&
> + ops->peer_port_idx &&
> ops->link_is_up &&
> ops->link_enable &&
> ops->link_disable &&
> @@ -319,6 +316,7 @@ struct ntb_client {
> * @dev: Linux device object.
> * @pdev: Pci device entry of the ntb.
> * @topo: Detected topology of the ntb.
> + * @port: Local port of the ntb.
> * @ops: See &ntb_dev_ops.
> * @ctx: See &ntb_ctx_ops.
> * @ctx_ops: See &ntb_ctx_ops.
> @@ -327,6 +325,7 @@ struct ntb_dev {
> struct device dev;
> struct pci_dev *pdev;
> enum ntb_topo topo;
> + int port;
> const struct ntb_dev_ops *ops;
> void *ctx;
> const struct ntb_ctx_ops *ctx_ops;
> @@ -442,6 +441,64 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_port_number() - get the local port number
> + * @ntb: NTB device context.
> + *
> + * Hardware must support at least simple two-ports topology
> + *
> + * Return: the local port number
> + */
> +static inline int ntb_port_number(struct ntb_dev *ntb)
> +{
> + return ntb->ops->port_number(ntb);
> +}
> +
> +/**
> + * ntb_peer_port_count() - get the number of peer device ports
> + * @ntb: NTB device context.
> + *
> + * Hardware may support an access to memory of several remote domains
> + * over multi-port NTB devices. This method returns the number of peers,
> + * local device can have shared memory with.
> + *
> + * Return: the number of peer ports
> + */
> +static inline int ntb_peer_port_count(struct ntb_dev *ntb)
> +{
> + return ntb->ops->peer_port_count(ntb);
> +}
> +
> +/**
> + * ntb_peer_port_number() - get the peer port by given index
> + * @ntb: NTB device context.
> + * @pidx: Peer port index.
> + *
> + * Peer ports are continuously enumerated by NTB API logic, so this methods
> + * lets to retrieve port real number by its index.
> + *
> + * Return: the peer device port or negative value indicating an error
> + */
> +static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
> +{
> + return ntb->ops->peer_port_number(ntb, pidx);
> +}
> +
> +/**
> + * ntb_peer_port_idx() - get the peer device port index by given port number
> + * @ntb: NTB device context.
> + * @port: Peer port number.
> + *
> + * Inverse operation of ntb_peer_port_number(), so one can get port index
> + * by its port number.
> + *
> + * Return: the peer port index or negative value indicating an error
> + */
> +static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> +{
> + return ntb->ops->peer_port_idx(ntb, port);
> +}
> +
> +/**
> * ntb_link_is_up() - get the current ntb link state
> * @ntb: NTB device context.
> * @speed: OUT - The link speed expressed as PCIe generation number.
> --
> 2.6.6


2016-12-07 22:56:25

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 02/22] NTB: Add peer indexed ports NTB API

From: Allen Hubbe
> From: Serge Semin
> > Add new port-index NTB API. Additionally lets get rid of Primary and
> > Secondary topologies, since port-number can be effectively used instead.
>
> Split into two patches please.
>
> I see no harm to the TOPO changes, though I wonder if they are necessary.
>

I am leaning more toward recommending that the topo api be left alone.

The topo changes to the ntb api complicate the Intel driver:
- The changes add second branches where there had been just one before (need to check topo AND port now).
- The changes also cause some complicated merge conflicts with https://github.com/davejiang/linux.git ntb.

See RE: [PATCH 10/22] NTB Intel: Add port-related NTB API callback methods

If we leave the ntb topo api as it was, then on multiport devices, if the local port is not the primary port, let it be one of potentially many secondary ports. Or, if there is no distinction between primary/secondary on some hardware, let them all be primary.

This topo api doesn't have much value for existing drivers (that I know of), except for informative purposes. So, my preference for changing it would be, only if necessary, and to minimize changes otherwise.

Allen

2016-12-07 22:56:31

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH 10/22] NTB Intel: Add port-related NTB API callback methods

From: Serge Semin
>

This needs an actual commit message.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> drivers/ntb/hw/intel/ntb_hw_intel.c | 195 +++++++++++++++++++++---------------
> drivers/ntb/hw/intel/ntb_hw_intel.h | 10 ++
> 2 files changed, 124 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index d3da0ce..724ccfe 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c

I am leaning more toward recommending that the topo api be left alone.

See RE: [PATCH 02/22] NTB: Add peer indexed ports NTB API

This is context for that response, highlighting

> @@ -1464,31 +1490,37 @@ static int xeon_poll_link(struct intel_ntb_dev *ndev)
>
> static int xeon_link_is_up(struct intel_ntb_dev *ndev)
> {
> - if (ndev->ntb.topo == NTB_TOPO_SEC)
> + if (ndev->ntb.port == NTB_PORT_SEC)

Should this also check ntb.topo == P2P? I think just checking ntb.port is incorrect, because ntb.port is also used with ntb.topo == B2B to distinguish "upstream" and "downstream" topologies.

ndev->ntb.topo == NTB_TOPO_P2P && ndev->ntb.port == NTB_PORT_SEC

> return 1;
>
> return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
> }
>

Also, the changes to xeon_link_is_up cause a merge conflict with https://github.com/davejiang/linux ntb.

>
> static inline int xeon_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd)
> @@ -1776,39 +1808,39 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
> ndev->db_count = XEON_DB_COUNT;
> ndev->db_link_mask = XEON_DB_LINK_BIT;
>
> - switch (ndev->ntb.topo) {
> - case NTB_TOPO_PRI:
> - if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
> - dev_err(ndev_dev(ndev), "NTB Primary config disabled\n");
> - return -EINVAL;
> - }
> -
> - /* enable link to allow secondary side device to appear */
> - ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
> - ntb_ctl &= ~NTB_CTL_DISABLE;
> - iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
> -
> - /* use half the spads for the peer */
> - ndev->spad_count >>= 1;
> - ndev->self_reg = &xeon_pri_reg;
> - ndev->peer_reg = &xeon_sec_reg;
> - ndev->xlat_reg = &xeon_sec_xlat;
> - break;
> + if (ndev->ntb.topo == NTB_TOPO_P2P) {
> + if (ndev->ntb.port == NTB_PORT_PRI) {

This was one case in a switch statement, now two branches.

> + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
> + dev_err(ndev_dev(ndev),
> + "NTB Primary config disabled\n");
> + return -EINVAL;
> + }
>
> - case NTB_TOPO_SEC:
> - if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
> - dev_err(ndev_dev(ndev), "NTB Secondary config disabled\n");
> - return -EINVAL;
> + /* enable link to allow secondary side dev to appear */
> + ntb_ctl = ioread32(ndev->self_mmio +
> + ndev->reg->ntb_ctl);
> + ntb_ctl &= ~NTB_CTL_DISABLE;
> + iowrite32(ntb_ctl, ndev->self_mmio +
> + ndev->reg->ntb_ctl);

The nested if has increased the indentation, and lines have had to be further split to conform to coding standards.

The indentation changes here affect many lines of code, and create a complicated merge with https://github.com/davejiang/linux ntb.

> +
> + /* use half the spads for the peer */
> + ndev->spad_count >>= 1;
> + ndev->self_reg = &xeon_pri_reg;
> + ndev->peer_reg = &xeon_sec_reg;
> + ndev->xlat_reg = &xeon_sec_xlat;
> + } else {
> + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
> + dev_err(ndev_dev(ndev),
> + "NTB Secondary config disabled\n");
> + return -EINVAL;
> + }
> + /* use half the spads for the peer */
> + ndev->spad_count >>= 1;
> + ndev->self_reg = &xeon_sec_reg;
> + ndev->peer_reg = &xeon_pri_reg;
> + ndev->xlat_reg = &xeon_pri_xlat;
> }
> - /* use half the spads for the peer */
> - ndev->spad_count >>= 1;
> - ndev->self_reg = &xeon_sec_reg;
> - ndev->peer_reg = &xeon_pri_reg;
> - ndev->xlat_reg = &xeon_pri_xlat;
> - break;
> -
> - case NTB_TOPO_B2B_USD:
> - case NTB_TOPO_B2B_DSD:
> + } else {

This else combines two cases in a switch statement, but is no less complex than what existed previously.

The case labels provided context for readability that is lost with else. Now to understand the context of this else, one must now jump upwards by about a page to find the matching if.

> ndev->self_reg = &xeon_pri_reg;
> ndev->peer_reg = &xeon_b2b_reg;
> ndev->xlat_reg = &xeon_sec_xlat;
> @@ -1833,11 +1865,12 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
> b2b_mw_idx, ndev->b2b_idx);
>
> } else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) {
> - dev_warn(ndev_dev(ndev), "Reduce doorbell count by 1\n");
> + dev_warn(ndev_dev(ndev),
> + "Reduce doorbell count by 1\n");

Please split cleanup changes into a separate patch.

> ndev->db_count -= 1;
> }
>
> - if (ndev->ntb.topo == NTB_TOPO_B2B_USD) {
> + if (ndev->ntb.port == NTB_PORT_PRI) {

This is correct, but it is not obvious. This is in the context of "else" as noted above. At this point we need to jump several pages above to find the matching "if" to understand the context.

Prior to the change, the case labels made it clear that ntb.topo is B2B here.

> rc = xeon_setup_b2b_mw(ndev,
> &xeon_b2b_dsd_addr,
> &xeon_b2b_usd_addr);

2016-12-12 21:09:12

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 0/9] NTB: Alter kernel API to support multi-port devices

There are devices, like IDT PCIe-switches, which have more than just two ports.
Particularly one device can have up to eight ports with NTB-function activated.
In order to support such devices, NTB kernel API should be altered since
currently it's optimized to work with two-ports devices only.

Changelog v2:
- Move comments from cover letter to individual patches
- Combine patches to make code buildable
- Alter patchset to support Intel SKX driver
- Make sure all the API uses the same midx/widx/pidx/sidx arguments notation
- Move new MW API usage description into Documention
- Alter Spad/Msg API checking valid function to make spad and msg interfaces optional
- Alter comments in ntb.h
- Split: add NTB_SPEED_GEN4 and ntb.h comments into separate patches
- Put copyrights into some of the existing patches
- Get rid of TOPO updates

Signed-off-by: Serge Semin <[email protected]>

Serge Semin (9):
NTB: Make link-state API being declared first
NTB: Add indexed ports NTB API
NTB: Alter link-state API to support multi-port devices
NTB: Alter MW API to support multi-ports devices
NTB: Alter Scratchpads API to support multi-ports devices
NTB: Add Messaging NTB API
NTB: Add new Memory Windows API documentation
NTB: Add PCIe Gen4 link speed
NTB: Add ntb.h comments

Documentation/ntb.txt | 99 +++++-
drivers/ntb/hw/amd/ntb_hw_amd.c | 291 ++++++++++------
drivers/ntb/hw/amd/ntb_hw_amd.h | 11 +
drivers/ntb/hw/intel/ntb_hw_intel.c | 296 +++++++++++------
drivers/ntb/hw/intel/ntb_hw_intel.h | 11 +
drivers/ntb/ntb.c | 15 +
drivers/ntb/ntb_transport.c | 44 ++-
drivers/ntb/test/ntb_perf.c | 27 +-
drivers/ntb/test/ntb_pingpong.c | 14 +-
drivers/ntb/test/ntb_tool.c | 93 ++++--
include/linux/ntb.h | 639 ++++++++++++++++++++++++++++++------
11 files changed, 1173 insertions(+), 367 deletions(-)

--
2.6.6

2016-12-12 21:09:18

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 2/9] NTB: Add indexed ports NTB API

There are some NTB hardware, which can combine more than just two domains
over NTB. For instance, some IDT PCIe-switches can have NTB-functions
activated on more than two-ports. The different domains are distinguished
by ports they are connected to. So the new port-related methods are added to
the NTB API:
ntb_port_number() - return local port
ntb_peer_port_count() - return number of peers local port can connect to
ntb_peer_port_number(pdix) - return port number by it index
ntb_peer_port_idx(port) - return port index by it number

Current test-drivers aren't changed much. They still support two-ports devices
for the time being while multi-ports hardware drivers aren't added.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 47 ++++++++++++++++++++++++
drivers/ntb/hw/amd/ntb_hw_amd.h | 9 +++++
drivers/ntb/hw/intel/ntb_hw_intel.c | 52 ++++++++++++++++++++++++++-
drivers/ntb/hw/intel/ntb_hw_intel.h | 9 +++++
drivers/ntb/ntb_transport.c | 6 ++++
drivers/ntb/test/ntb_perf.c | 4 +++
drivers/ntb/test/ntb_pingpong.c | 6 ++++
drivers/ntb/test/ntb_tool.c | 5 +++
include/linux/ntb.h | 71 +++++++++++++++++++++++++++++++++++++
9 files changed, 208 insertions(+), 1 deletion(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 6704327..0b767ef 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -71,6 +71,49 @@ MODULE_AUTHOR("AMD Inc.");
static const struct file_operations amd_ntb_debugfs_info;
static struct dentry *debugfs_dir;

+static int amd_ntb_port_number(struct ntb_dev *ntb)
+{
+ switch (ntb->topo) {
+ case NTB_TOPO_PRI:
+ case NTB_TOPO_B2B_USD:
+ return NTB_PORT_PRI_USD;
+ case NTB_TOPO_SEC:
+ case NTB_TOPO_B2B_DSD:
+ return NTB_PORT_SEC_DSD;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int amd_ntb_peer_port_count(struct ntb_dev *ntb)
+{
+ return NTB_PEER_CNT;
+}
+
+static int amd_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ int local_port = amd_ntb_port_number(ntb);
+
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
+ return (local_port == NTB_PORT_PRI_USD ?
+ NTB_PORT_SEC_DSD : NTB_PORT_PRI_USD);
+}
+
+static int amd_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ int local_port = amd_ntb_port_number(ntb);
+
+ if ((local_port == NTB_PORT_PRI_USD && port != NTB_PORT_SEC_DSD) ||
+ (local_port == NTB_PORT_SEC_DSD && port != NTB_PORT_PRI_USD))
+ return -EINVAL;
+
+ return 0;
+}
+
static int amd_link_is_up(struct amd_ntb_dev *ndev)
{
if (!ndev->peer_sta)
@@ -431,6 +474,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
}

static const struct ntb_dev_ops amd_ntb_ops = {
+ .port_number = amd_ntb_port_number,
+ .peer_port_count = amd_ntb_peer_port_count,
+ .peer_port_number = amd_ntb_peer_port_number,
+ .peer_port_idx = amd_ntb_peer_port_idx,
.link_is_up = amd_ntb_link_is_up,
.link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable,
diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h
index 2eac3cd..1aeb08f 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.h
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.h
@@ -62,6 +62,10 @@
#define NTB_LNK_STA_SPEED(x) (((x) & NTB_LNK_STA_SPEED_MASK) >> 16)
#define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 20)

+/* port related constants */
+#define NTB_PEER_CNT (1)
+#define NTB_PIDX_MAX (0)
+
#ifndef read64
#ifdef readq
#define read64 readq
@@ -91,6 +95,11 @@ static inline void _write64(u64 val, void __iomem *mmio)
#endif
#endif

+enum amd_ntb_port {
+ NTB_PORT_PRI_USD,
+ NTB_PORT_SEC_DSD
+};
+
enum {
/* AMD NTB Capability */
AMD_MW_CNT = 3,
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 68d9908..7e44dc3 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1035,6 +1035,49 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
debugfs_remove_recursive(ndev->debugfs_dir);
}

+static int intel_ntb_port_number(struct ntb_dev *ntb)
+{
+ switch (ntb->topo) {
+ case NTB_TOPO_PRI:
+ case NTB_TOPO_B2B_USD:
+ return NTB_PORT_PRI_USD;
+ case NTB_TOPO_SEC:
+ case NTB_TOPO_B2B_DSD:
+ return NTB_PORT_SEC_DSD;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int intel_ntb_peer_port_count(struct ntb_dev *ntb)
+{
+ return NTB_PEER_CNT;
+}
+
+static int intel_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ int local_port = intel_ntb_port_number(ntb);
+
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
+ return (local_port == NTB_PORT_PRI_USD ?
+ NTB_PORT_SEC_DSD : NTB_PORT_PRI_USD);
+}
+
+static int intel_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ int local_port = intel_ntb_port_number(ntb);
+
+ if ((local_port == NTB_PORT_PRI_USD && port != NTB_PORT_SEC_DSD) ||
+ (local_port == NTB_PORT_SEC_DSD && port != NTB_PORT_PRI_USD))
+ return -EINVAL;
+
+ return 0;
+}
+
static int intel_ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed,
enum ntb_width *width)
@@ -1775,7 +1818,6 @@ static int skx_init_ntb(struct intel_ntb_dev *ndev)
{
int rc;

-
ndev->mw_count = XEON_MW_COUNT;
ndev->spad_count = SKX_SPAD_COUNT;
ndev->db_count = SKX_DB_COUNT;
@@ -2883,6 +2925,10 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {

/* operations for primary side of local ntb */
static const struct ntb_dev_ops intel_ntb_ops = {
+ .port_number = intel_ntb_port_number,
+ .peer_port_count = intel_ntb_peer_port_count,
+ .peer_port_number = intel_ntb_peer_port_number,
+ .peer_port_idx = intel_ntb_peer_port_idx,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable,
@@ -2909,6 +2955,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
};

static const struct ntb_dev_ops intel_ntb3_ops = {
+ .port_number = intel_ntb_port_number,
+ .peer_port_count = intel_ntb_peer_port_count,
+ .peer_port_number = intel_ntb_peer_port_number,
+ .peer_port_idx = intel_ntb_peer_port_idx,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb3_link_enable,
.link_disable = intel_ntb_link_disable,
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
index 6e8c182..f12c960 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.h
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -295,6 +295,15 @@
#define NTB_BAR_MASK_64 ~(0xfull)
#define NTB_BAR_MASK_32 ~(0xfu)

+/* port related constants */
+#define NTB_PEER_CNT (1)
+#define NTB_PIDX_MAX (0)
+
+enum intel_ntb_port {
+ NTB_PORT_PRI_USD,
+ NTB_PORT_SEC_DSD
+};
+
struct intel_ntb_dev;

struct intel_ntb_reg {
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 4eb8adb..37d428d 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -94,6 +94,9 @@ MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");

static struct dentry *nt_debugfs_dir;

+/* Only two-ports NTB devices are supported */
+#define PIDX 0
+
struct ntb_queue_entry {
/* ntb_queue list reference */
struct list_head entry;
@@ -1083,6 +1086,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
dev_dbg(&ndev->dev,
"scratchpad is unsafe, proceed anyway...\n");

+ if (ntb_peer_port_count(ndev) != 1)
+ dev_warn(&ndev->dev, "Multi-port NTB devices unsupported\n");
+
node = dev_to_node(&ndev->dev);

nt = kzalloc_node(sizeof(*nt), GFP_KERNEL, node);
diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index e75d4fd..481827a 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -76,6 +76,7 @@
#define DMA_RETRIES 20
#define SZ_4G (1ULL << 32)
#define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */
+#define PIDX 0

MODULE_LICENSE(DRIVER_LICENSE);
MODULE_VERSION(DRIVER_VERSION);
@@ -764,6 +765,9 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
return -EIO;
}

+ if (ntb_peer_port_count(ntb) != 1)
+ dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
+
node = dev_to_node(&pdev->dev);

perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node);
diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
index 4358611..6dd7582 100644
--- a/drivers/ntb/test/ntb_pingpong.c
+++ b/drivers/ntb/test/ntb_pingpong.c
@@ -90,6 +90,9 @@ static unsigned long db_init = 0x7;
module_param(db_init, ulong, 0644);
MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");

+/* Only two-ports NTB devices are supported */
+#define PIDX 0
+
struct pp_ctx {
struct ntb_dev *ntb;
u64 db_bits;
@@ -230,6 +233,9 @@ static int pp_probe(struct ntb_client *client,
}
}

+ if (ntb_peer_port_count(ntb) != 1)
+ dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
+
pp = kmalloc(sizeof(*pp), GFP_KERNEL);
if (!pp) {
rc = -ENOMEM;
diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index 61bf2ef..85b6417 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -120,6 +120,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);

#define MAX_MWS 16
+/* Only two-ports devices are supported */
+#define PIDX 0

static struct dentry *tool_dbgfs;

@@ -919,6 +921,9 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
if (ntb_spad_is_unsafe(ntb))
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");

+ if (ntb_peer_port_count(ntb) != 1)
+ dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
+
tc = kzalloc(sizeof(*tc), GFP_KERNEL);
if (!tc) {
rc = -ENOMEM;
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 5d1f260..3216689 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -179,6 +179,10 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)

/**
* struct ntb_ctx_ops - ntb device operations
+ * @port_number: See ntb_port_number().
+ * @peer_port_count: See ntb_peer_port_count().
+ * @peer_port_number: See ntb_peer_port_number().
+ * @peer_port_idx: See ntb_peer_port_idx().
* @link_is_up: See ntb_link_is_up().
* @link_enable: See ntb_link_enable().
* @link_disable: See ntb_link_disable().
@@ -212,6 +216,11 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_write: See ntb_peer_spad_write().
*/
struct ntb_dev_ops {
+ int (*port_number)(struct ntb_dev *ntb);
+ int (*peer_port_count)(struct ntb_dev *ntb);
+ int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
+ int (*peer_port_idx)(struct ntb_dev *ntb, int port);
+
int (*link_is_up)(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width);
int (*link_enable)(struct ntb_dev *ntb,
@@ -265,6 +274,10 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ ops->port_number &&
+ ops->peer_port_count &&
+ ops->peer_port_number &&
+ ops->peer_port_idx &&
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
@@ -442,6 +455,64 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_port_number() - get the local port number
+ * @ntb: NTB device context.
+ *
+ * Hardware must support at least simple two-ports ntb connection
+ *
+ * Return: the local port number
+ */
+static inline int ntb_port_number(struct ntb_dev *ntb)
+{
+ return ntb->ops->port_number(ntb);
+}
+
+/**
+ * ntb_peer_port_count() - get the number of peer device ports
+ * @ntb: NTB device context.
+ *
+ * Hardware may support an access to memory of several remote domains
+ * over multi-port NTB devices. This method returns the number of peers,
+ * local device can have shared memory with.
+ *
+ * Return: the number of peer ports
+ */
+static inline int ntb_peer_port_count(struct ntb_dev *ntb)
+{
+ return ntb->ops->peer_port_count(ntb);
+}
+
+/**
+ * ntb_peer_port_number() - get the peer port by given index
+ * @ntb: NTB device context.
+ * @pidx: Peer port index.
+ *
+ * Peer ports are continuously enumerated by NTB API logic, so this methods
+ * lets to retrieve port real number by its index.
+ *
+ * Return: the peer device port or negative value indicating an error
+ */
+static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ return ntb->ops->peer_port_number(ntb, pidx);
+}
+
+/**
+ * ntb_peer_port_idx() - get the peer device port index by given port number
+ * @ntb: NTB device context.
+ * @port: Peer port number.
+ *
+ * Inverse operation of ntb_peer_port_number(), so one can get port index
+ * by specified port number.
+ *
+ * Return: the peer port index or negative value indicating an error
+ */
+static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ return ntb->ops->peer_port_idx(ntb, port);
+}
+
+/**
* ntb_link_is_up() - get the current ntb link state
* @ntb: NTB device context.
* @speed: OUT - The link speed expressed as PCIe generation number.
--
2.6.6

2016-12-12 21:09:25

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 6/9] NTB: Add Messaging NTB API

Some IDT NTB-capable PCIe-switches have message registers to communicate with
peer devices. This patch adds new NTB API callback methods, which can be used
to utilize these registers functionality:
ntb_msg_count(); - get number of message registers
ntb_msg_inbits(); - get bitfield of inbound message registers status
ntb_msg_outbits(); - get bitfield of outbound message registers status
ntb_msg_read_sts(); - read the inbound and outbound message registers status
ntb_msg_clear_sts(); - clear status bits of message registers
ntb_msg_set_mask(); - mask interrupts raised by status bits of message
registers.
ntb_msg_clear_mask(); - clear interrupts mask bits of message registers
ntb_msg_read(midx, *pidx); - read message register with specified index,
additionally getting peer port index which data received from
ntb_msg_write(midx, pidx); - write data to the specified message register
sending it to the passed peer device connected over a pidx port
ntb_msg_event(); - notify driver context of a new message event

Of course there is hadrware which doesn't support Message registers, so
this API is made optional.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/ntb.c | 13 ++++
include/linux/ntb.h | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+)

diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index f6153af..06574f8 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -193,6 +193,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
}
EXPORT_SYMBOL(ntb_db_event);

+void ntb_msg_event(struct ntb_dev *ntb)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+ {
+ if (ntb->ctx_ops && ntb->ctx_ops->msg_event)
+ ntb->ctx_ops->msg_event(ntb->ctx);
+ }
+ spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_msg_event);
+
static int ntb_probe(struct device *dev)
{
struct ntb_dev *ntb;
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index a6bf15d..90746df 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -164,10 +164,12 @@ static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops)
* struct ntb_ctx_ops - ntb driver context operations
* @link_event: See ntb_link_event().
* @db_event: See ntb_db_event().
+ * @msg_event: See ntb_msg_event().
*/
struct ntb_ctx_ops {
void (*link_event)(void *ctx);
void (*db_event)(void *ctx, int db_vector);
+ void (*msg_event)(void *ctx);
};

static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
@@ -176,6 +178,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
return
/* ops->link_event && */
/* ops->db_event && */
+ /* ops->msg_event && */
1;
}

@@ -220,6 +223,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_addr: See ntb_peer_spad_addr().
* @peer_spad_read: See ntb_peer_spad_read().
* @peer_spad_write: See ntb_peer_spad_write().
+ * @msg_count: See ntb_msg_count().
+ * @msg_inbits: See ntb_msg_inbits().
+ * @msg_outbits: See ntb_msg_outbits().
+ * @msg_read_sts: See ntb_msg_read_sts().
+ * @msg_clear_sts: See ntb_msg_clear_sts().
+ * @msg_set_mask: See ntb_msg_set_mask().
+ * @msg_clear_mask: See ntb_msg_clear_mask().
+ * @msg_read: See ntb_msg_read().
+ * @msg_write: See ntb_msg_write().
*/
struct ntb_dev_ops {
int (*port_number)(struct ntb_dev *ntb);
@@ -282,6 +294,16 @@ struct ntb_dev_ops {
u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
u32 val);
+
+ int (*msg_count)(struct ntb_dev *ntb);
+ u64 (*msg_inbits)(struct ntb_dev *ntb);
+ u64 (*msg_outbits)(struct ntb_dev *ntb);
+ u64 (*msg_read_sts)(struct ntb_dev *ntb);
+ int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits);
+ int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg);
+ int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg);
};

static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@@ -329,6 +351,15 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->peer_spad_addr == !ops->spad_count && */
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&
+
+ !ops->msg_inbits == !ops->msg_count &&
+ !ops->msg_outbits == !ops->msg_count &&
+ !ops->msg_read_sts == !ops->msg_count &&
+ !ops->msg_clear_sts == !ops->msg_count &&
+ /* !ops->msg_set_mask == !ops->msg_count && */
+ /* !ops->msg_clear_mask == !ops->msg_count && */
+ !ops->msg_read == !ops->msg_count &&
+ !ops->msg_write == !ops->msg_count &&
1;
}

@@ -472,6 +503,18 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_msg_event() - notify driver context of a message event
+ * @ntb: NTB device context.
+ *
+ * Notify the driver context of a message event. If hardware supports
+ * message registers, this event indicates, that a new message arrived in
+ * some incoming message register or last sent message couldn't be delivered.
+ * The events can be masked/unmasked by the methods ntb_msg_set_mask() and
+ * ntb_msg_clear_mask().
+ */
+void ntb_msg_event(struct ntb_dev *ntb);
+
+/**
* ntb_port_number() - get the local port number
* @ntb: NTB device context.
*
@@ -1197,4 +1240,166 @@ static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
}

+/**
+ * ntb_msg_count() - get the number of message registers
+ * @ntb: NTB device context.
+ *
+ * Hardware may support a different number of messge registers.
+ *
+ * Return: the number of message registers.
+ */
+static inline int ntb_msg_count(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_count)
+ return 0;
+
+ return ntb->ops->msg_count(ntb);
+}
+
+/**
+ * ntb_msg_inbits() - get a bitsfield of inbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitsfield of status and mask registers, which related
+ * to inbound message registers.
+ *
+ * Return: bitsfield of inbound message registers.
+ */
+static inline u64 ntb_msg_inbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_inbits)
+ return 0;
+
+ return ntb->ops->msg_inbits(ntb);
+}
+
+/**
+ * ntb_msg_outbits() - get a bitsfield of outbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitsfield of status and mask registers, which related
+ * to outbound message registers.
+ *
+ * Return: bitsfield of outbound message registers.
+ */
+static inline u64 ntb_msg_outbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_outbits)
+ return 0;
+
+ return ntb->ops->msg_outbits(ntb);
+}
+
+/**
+ * ntb_msg_read_sts() - read the message registers status
+ * @ntb: NTB device context.
+ *
+ * Read the status of message register. Inbound and outbound message registers
+ * related bits can be filetered by masks retrieved from ntb_msg_inbits() and
+ * ntb_msg_outbits().
+ *
+ * Return: status bits of message registers
+ */
+static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_read_sts)
+ return 0;
+
+ return ntb->ops->msg_read_sts(ntb);
+}
+
+/**
+ * ntb_msg_clear_sts() - clear status bits of message registers
+ * @ntb: NTB device context.
+ * @sts_bits: Status bits to clear.
+ *
+ * Clear bits in the status register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
+{
+ if (!ntb->ops->msg_clear_sts)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_sts(ntb, sts_bits);
+}
+
+/**
+ * ntb_msg_set_mask() - set mask of message register status bits
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits.
+ *
+ * Mask the message registers status bits from raising the message event.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_set_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_set_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_clear_mask() - clear message registers mask
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits to clear.
+ *
+ * Clear bits in the message events mask register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_clear_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_read() - read message register with specified index
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: OUT - Port index of peer device a message retrieved from
+ * @msg: OUT - Data
+ *
+ * Read data from the specified message register. Source port index of a
+ * message is retrieved as well.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx,
+ u32 *msg)
+{
+ if (!ntb->ops->msg_read)
+ return -EINVAL;
+
+ return ntb->ops->msg_read(ntb, midx, pidx, msg);
+}
+
+/**
+ * ntb_msg_write() - write data to the specified message register
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: Port index of peer device a message being sent to
+ * @msg: Data to send
+ *
+ * Send data to a specified peer device using the defined message register.
+ * Message event can be raised if the midx registers isn't empty while
+ * calling this method and the corresponding interrupt isn't masked.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx,
+ u32 msg)
+{
+ if (!ntb->ops->msg_write)
+ return -EINVAL;
+
+ return ntb->ops->msg_write(ntb, midx, pidx, msg);
+}
+
#endif
--
2.6.6

2016-12-12 21:09:28

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 9/9] NTB: Add ntb.h comments

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index fe0437c..c5a369c 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -312,13 +312,18 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ /* Port operations are required */
ops->port_number &&
ops->peer_port_count &&
ops->peer_port_number &&
ops->peer_port_idx &&
+
+ /* Link operations are requiered */
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
+
+ /* One or both MW interfaces should be developed */
ops->mw_count &&
ops->mw_get_align &&
(ops->mw_set_trans ||
@@ -328,12 +333,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->peer_mw_get_addr &&
/* ops->peer_mw_clear_trans && */

+ /* Doorbell operations are mostly required */
/* ops->db_is_unsafe && */
ops->db_valid_mask &&
-
/* both set, or both unset */
(!ops->db_vector_count == !ops->db_vector_mask) &&
-
ops->db_read &&
/* ops->db_set && */
ops->db_clear &&
@@ -347,6 +351,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
+
+ /* Scrachpad interface is optional */
/* !ops->spad_is_unsafe == !ops->spad_count && */
!ops->spad_read == !ops->spad_count &&
!ops->spad_write == !ops->spad_count &&
@@ -354,6 +360,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&

+ /* Message registers interface is optional */
!ops->msg_inbits == !ops->msg_count &&
!ops->msg_outbits == !ops->msg_count &&
!ops->msg_read_sts == !ops->msg_count &&
@@ -374,13 +381,12 @@ struct ntb_client {
struct device_driver drv;
const struct ntb_client_ops ops;
};
-
#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)

/**
* struct ntb_device - ntb device
* @dev: Linux device object.
- * @pdev: Pci device entry of the ntb.
+ * @pdev: PCI device entry of the ntb.
* @topo: Detected topology of the ntb.
* @ops: See &ntb_dev_ops.
* @ctx: See &ntb_ctx_ops.
@@ -401,7 +407,6 @@ struct ntb_dev {
/* block unregister until device is fully released */
struct completion released;
};
-
#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)

/**
@@ -498,7 +503,7 @@ void ntb_link_event(struct ntb_dev *ntb);
* multiple interrupt vectors for doorbells, the vector number indicates which
* vector received the interrupt. The vector number is relative to the first
* vector used for doorbells, starting at zero, and must be less than
- ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
+ * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
* doorbell bits need service, and ntb_db_vector_mask() to determine which of
* those bits are associated with the vector number.
*/
--
2.6.6

2016-12-12 21:09:21

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 7/9] NTB: Add new Memory Windows API documentation

Since the new API slightly changes the way a typical NTB client driver
works, the documentation file needs to be appropriately updated.

Signed-off-by: Serge Semin <[email protected]>

---
Documentation/ntb.txt | 99 ++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 91 insertions(+), 8 deletions(-)

diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
index 1d9bbab..d01bb69 100644
--- a/Documentation/ntb.txt
+++ b/Documentation/ntb.txt
@@ -1,14 +1,16 @@
# NTB Drivers

NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
-the separate memory systems of two computers to the same PCI-Express fabric.
-Existing NTB hardware supports a common feature set, including scratchpad
-registers, doorbell registers, and memory translation windows. Scratchpad
-registers are read-and-writable registers that are accessible from either side
-of the device, so that peers can exchange a small amount of information at a
-fixed address. Doorbell registers provide a way for peers to send interrupt
-events. Memory windows allow translated read and write access to the peer
-memory.
+the separate memory systems of two or more computers to the same PCI-Express
+fabric. Existing NTB hardware supports a common feature set: doorbell
+registers and memory translation windows, as well as non common features like
+scratchpad and message registers. Scratchpad registers are read-and-writable
+registers that are accessible from either side of the device, so that peers can
+exchange a small amount of information at a fixed address. Message registers can
+be utialized for the same purpose. Additionally they are provided with with
+special status bits to make sure the information isn't rewritten by another
+peer. Doorbell registers provide a way for peers to send interrupt events.
+Memory windows allow translated read and write access to the peer memory.

## NTB Core Driver (ntb)

@@ -26,6 +28,87 @@ as ntb hardware, or hardware drivers, are inserted and removed. The
registration uses the Linux Device framework, so it should feel familiar to
anyone who has written a pci driver.

+### NTB Typical client driver implementation
+
+Primary purpose of NTB is to share some peace of memory between at least two
+systems. So the NTB device features like Scratchpad/Message regiesters are
+mainly used to perform the proper memory window initialization. Typically
+there are two types of memory window interfaces supported by the NTB API:
+inbound translation configured on the local ntb port and outbound translation
+configured by the peer, on the peer ntb port. The first type is
+depicted on the next figure
+
+Inbound translation:
+ Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
+ ____________
+ | dma-mapped |-ntb_mw_set_trans(addr) |
+ | memory | _v____________ | ______________
+ | (addr) |<======| MW xlat addr |<====| MW base addr |<== memory-mapped IO
+ |------------| |--------------| | |--------------|
+
+So typical scenario of the first type memory window initialization looks:
+1) allocate a memory region, 2) put translated address to NTB config,
+3) somehow notify a peer device of performed initialization, 4) peer device
+maps corresponding outbound memory window so to have access to the shared
+memory region.
+
+The second type of interface, that implies the shared windows being
+initialized by a peer device, is depicted on the figure:
+
+Outbound translation:
+ Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
+ ____________ ______________
+ | dma-mapped | | | MW base addr |<== memory-mapped IO
+ | memory | | |--------------|
+ | (addr) |<===================| MW xlat addr |<-ntb_peer_mw_set_trans(addr)
+ |------------| | |--------------|
+
+Typical scenario of the second type interface initialization would be:
+1) allocate a memory region, 2) somehow deliver a translated address to a peer
+device, 3) peer puts the translated address to NTB config, 4) peer device maps
+outbound memory window so to have access to the shared memory region.
+
+As one can see the described scenarios can be combined in one portable
+algorithm.
+ Local device:
+ 1) Allocate memory for a shared window
+ 2) Initialize memory window by translated address of the allocated region
+ (it may fail if local memory window initialzation is unsupported)
+ 3) Send the translated address and memory window index to a peer device
+ Peer device:
+ 1) Initialize memory window with retrieved address of the allocated
+ by another device memory region (it may fail if peer memory window
+ initialization is unsupported)
+ 2) Map outbound memory window
+
+In accordance with this scenario, the NTB Memory Window API can be used as
+follows:
+ Local device:
+ 1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
+ be allocated for memory windows between local device and peer device
+ of port with specified index.
+ 2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
+ shared memory region alignment and size. Then memory can be properly
+ allocated.
+ 3) Allocate physically contiguous memory region in complience with
+ restrictions retrieved in 2).
+ 4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
+ the memory window with specified index for the defined peer device
+ (it may fail if local translated address setting is not supported)
+ 5) Send translated base address (usually together with memory window
+ number) to the peer device using, for instance, scratchpad or message
+ registers.
+ Peer device:
+ 1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
+ device (related to pidx) translated address for specified memory
+ window. It may fail if retrieved address, for instance, exceeds
+ maximum possible address or isn't properly aligned.
+ 2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
+ window so to have an access to the shared memory.
+
+Also it is worth to note, that method ntb_mw_count(pidx) should return the
+same value as ntb_peer_mw_count() on the peer with port index - pidx.
+
### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)

The primary client for NTB is the Transport client, used in tandem with NTB
--
2.6.6

2016-12-12 21:10:01

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 8/9] NTB: Add PCIe Gen4 link speed

Signed-off-by: Serge Semin <[email protected]>

---
include/linux/ntb.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 90746df..fe0437c 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -108,6 +108,7 @@ static inline char *ntb_topo_string(enum ntb_topo topo)
* @NTB_SPEED_GEN1: Link is trained to gen1 speed.
* @NTB_SPEED_GEN2: Link is trained to gen2 speed.
* @NTB_SPEED_GEN3: Link is trained to gen3 speed.
+ * @NTB_SPEED_GEN4: Link is trained to gen4 speed.
*/
enum ntb_speed {
NTB_SPEED_AUTO = -1,
@@ -115,6 +116,7 @@ enum ntb_speed {
NTB_SPEED_GEN1 = 1,
NTB_SPEED_GEN2 = 2,
NTB_SPEED_GEN3 = 3,
+ NTB_SPEED_GEN4 = 4
};

/**
--
2.6.6

2016-12-12 21:10:33

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 5/9] NTB: Alter Scratchpads API to support multi-ports devices

Even though there is no any real NTB hardware, which would have both more
than two ports and Scratchpad registers, it is logically correct to have
Scratchpad API accepting a peer port index as well. Intel/AMD drivers utilize
Primary and Secondary topology to split Scratchpad between connected root
devices. Since port-index API introduced, Intel/AMD NTB hadrware drivers can
use device port to determine which Scratchpad registers actually belong to
local and peer devices. The same approach can be used if some potential
hardware in future will be multi-port and have some set of Scratchpads.
Here are the brief of changes in the API:
ntb_spad_count() - return number of Scratchpad per each port
ntb_peer_spad_addr(pidx, sidx) - address of Scratchpad register of the
peer device with pidx-index
ntb_peer_spad_read(pidx, sidx) - read specified Scratchpad register of the
peer with pidx-index
ntb_peer_spad_write(pidx, sidx) - write data to Scratchpad register of the
peer with pidx-index

Since there is hardware which doesn't support Scratchpad registers, the
corresponding API methods are now made optional.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 14 +++----
drivers/ntb/hw/intel/ntb_hw_intel.c | 14 +++----
drivers/ntb/ntb_transport.c | 17 ++++-----
drivers/ntb/test/ntb_perf.c | 6 +--
drivers/ntb/test/ntb_pingpong.c | 8 +++-
drivers/ntb/test/ntb_tool.c | 45 +++++++++++++++++-----
include/linux/ntb.h | 76 +++++++++++++++++++++++--------------
7 files changed, 115 insertions(+), 65 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 74fe9b8..a2596ad 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -476,30 +476,30 @@ static int amd_ntb_spad_write(struct ntb_dev *ntb,
return 0;
}

-static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
void __iomem *mmio = ndev->self_mmio;
u32 offset;

- if (idx < 0 || idx >= ndev->spad_count)
+ if (sidx < 0 || sidx >= ndev->spad_count)
return -EINVAL;

- offset = ndev->peer_spad + (idx << 2);
+ offset = ndev->peer_spad + (sidx << 2);
return readl(mmio + AMD_SPAD_OFFSET + offset);
}

-static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
- int idx, u32 val)
+static int amd_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+ int sidx, u32 val)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
void __iomem *mmio = ndev->self_mmio;
u32 offset;

- if (idx < 0 || idx >= ndev->spad_count)
+ if (sidx < 0 || sidx >= ndev->spad_count)
return -EINVAL;

- offset = ndev->peer_spad + (idx << 2);
+ offset = ndev->peer_spad + (sidx << 2);
writel(val, mmio + AMD_SPAD_OFFSET + offset);

return 0;
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 5a57d9e..471b0ba 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1452,30 +1452,30 @@ static int intel_ntb_spad_write(struct ntb_dev *ntb,
ndev->self_reg->spad);
}

-static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr,
+ return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
ndev->peer_reg->spad);
}

-static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_read(ndev, idx,
+ return ndev_spad_read(ndev, sidx,
ndev->peer_mmio +
ndev->peer_reg->spad);
}

-static int intel_ntb_peer_spad_write(struct ntb_dev *ntb,
- int idx, u32 val)
+static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+ int sidx, u32 val)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_write(ndev, idx, val,
+ return ndev_spad_write(ndev, sidx, val,
ndev->peer_mmio +
ndev->peer_reg->spad);
}
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index cb4f99889..b2475f4 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -875,17 +875,17 @@ static void ntb_transport_link_work(struct work_struct *work)
size = max_mw_size;

spad = MW0_SZ_HIGH + (i * 2);
- ntb_peer_spad_write(ndev, spad, upper_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, spad, upper_32_bits(size));

spad = MW0_SZ_LOW + (i * 2);
- ntb_peer_spad_write(ndev, spad, lower_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, spad, lower_32_bits(size));
}

- ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count);
+ ntb_peer_spad_write(ndev, PIDX, NUM_MWS, nt->mw_count);

- ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count);
+ ntb_peer_spad_write(ndev, PIDX, NUM_QPS, nt->qp_count);

- ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION);
+ ntb_peer_spad_write(ndev, PIDX, VERSION, NTB_TRANSPORT_VERSION);

/* Query the remote side for its info */
val = ntb_spad_read(ndev, VERSION);
@@ -961,10 +961,10 @@ static void ntb_qp_link_work(struct work_struct *work)

val = ntb_spad_read(nt->ndev, QP_LINKS);

- ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num));
+ ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num));

/* query remote spad for qp ready bits */
- ntb_peer_spad_read(nt->ndev, QP_LINKS);
+ ntb_peer_spad_read(nt->ndev, PIDX, QP_LINKS);
dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);

/* See if the remote side is up */
@@ -2141,8 +2141,7 @@ void ntb_transport_link_down(struct ntb_transport_qp *qp)

val = ntb_spad_read(qp->ndev, QP_LINKS);

- ntb_peer_spad_write(qp->ndev, QP_LINKS,
- val & ~BIT(qp->qp_num));
+ ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val & ~BIT(qp->qp_num));

if (qp->link_is_up)
ntb_send_link_down(qp);
diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index 3efb5b5..99f1522 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -516,9 +516,9 @@ static void perf_link_work(struct work_struct *work)
if (max_mw_size && size > max_mw_size)
size = max_mw_size;

- ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
- ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
- ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
+ ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION);

/* now read what peer wrote */
val = ntb_spad_read(ndev, VERSION);
diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
index 6dd7582..4ee5c14 100644
--- a/drivers/ntb/test/ntb_pingpong.c
+++ b/drivers/ntb/test/ntb_pingpong.c
@@ -138,7 +138,7 @@ static void pp_ping(unsigned long ctx)
"Ping bits %#llx read %#x write %#x\n",
db_bits, spad_rd, spad_wr);

- ntb_peer_spad_write(pp->ntb, 0, spad_wr);
+ ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr);
ntb_peer_db_set(pp->ntb, db_bits);
ntb_db_clear_mask(pp->ntb, db_mask);

@@ -225,6 +225,12 @@ static int pp_probe(struct ntb_client *client,
}
}

+ if (ntb_spad_count(ntb) < 1) {
+ dev_dbg(&ntb->dev, "no enough scratchpads\n");
+ rc = -EINVAL;
+ goto err_pp;
+ }
+
if (ntb_spad_is_unsafe(ntb)) {
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
if (!unsafe) {
diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index 7aa6018..0f57b2e 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -264,14 +264,17 @@ static ssize_t tool_dbfn_write(struct tool_ctx *tc,

static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
size_t size, loff_t *offp,
- u32 (*spad_read_fn)(struct ntb_dev *, int))
+ u32 (*spad_read_fn)(struct ntb_dev *, int),
+ u32 (*spad_peer_read_fn)(struct ntb_dev *, int,
+ int))
{
size_t buf_size;
char *buf;
ssize_t pos, rc;
int i, spad_count;
+ u32 data;

- if (!spad_read_fn)
+ if (!spad_read_fn && !spad_peer_read_fn)
return -EINVAL;

spad_count = ntb_spad_count(tc->ntb);
@@ -290,8 +293,12 @@ static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
pos = 0;

for (i = 0; i < spad_count; ++i) {
+ if (spad_read_fn)
+ data = spad_read_fn(tc->ntb, i);
+ else
+ data = spad_peer_read_fn(tc->ntb, PIDX, i);
pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
- i, spad_read_fn(tc->ntb, i));
+ i, data);
}

rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
@@ -305,7 +312,9 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
const char __user *ubuf,
size_t size, loff_t *offp,
int (*spad_write_fn)(struct ntb_dev *,
- int, u32))
+ int, u32),
+ int (*spad_peer_write_fn)(struct ntb_dev *,
+ int, int, u32))
{
int spad_idx;
u32 spad_val;
@@ -313,7 +322,7 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
int pos, n;
ssize_t rc;

- if (!spad_write_fn) {
+ if (!spad_write_fn || !spad_peer_write_fn) {
dev_dbg(&tc->ntb->dev, "no spad write fn\n");
return -EINVAL;
}
@@ -333,7 +342,11 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
while (n == 2) {
buf_ptr += pos;
- rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
+ if (spad_write_fn)
+ rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
+ else
+ rc = spad_peer_write_fn(tc->ntb, PIDX, spad_idx,
+ spad_val);
if (rc)
break;

@@ -446,7 +459,7 @@ static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
struct tool_ctx *tc = filep->private_data;

return tool_spadfn_read(tc, ubuf, size, offp,
- tc->ntb->ops->spad_read);
+ tc->ntb->ops->spad_read, NULL);
}

static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
@@ -455,7 +468,7 @@ static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
struct tool_ctx *tc = filep->private_data;

return tool_spadfn_write(tc, ubuf, size, offp,
- tc->ntb->ops->spad_write);
+ tc->ntb->ops->spad_write, NULL);
}

static TOOL_FOPS_RDWR(tool_spad_fops,
@@ -467,7 +480,7 @@ static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
{
struct tool_ctx *tc = filep->private_data;

- return tool_spadfn_read(tc, ubuf, size, offp,
+ return tool_spadfn_read(tc, ubuf, size, offp, NULL,
tc->ntb->ops->peer_spad_read);
}

@@ -476,7 +489,7 @@ static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
{
struct tool_ctx *tc = filep->private_data;

- return tool_spadfn_write(tc, ubuf, size, offp,
+ return tool_spadfn_write(tc, ubuf, size, offp, NULL,
tc->ntb->ops->peer_spad_write);
}

@@ -935,6 +948,18 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
if (ntb_peer_port_count(ntb) != 1)
dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");

+ if (ntb_spad_count(ntb) < 1) {
+ dev_dbg(&ntb->dev, "no enough scratchpads\n");
+ rc = -EINVAL;
+ goto err_tc;
+ }
+
+ if (!ntb->ops->mw_set_trans) {
+ dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
+ rc = -EINVAL;
+ goto err_tc;
+ }
+
tc = kzalloc(sizeof(*tc), GFP_KERNEL);
if (!tc) {
rc = -ENOMEM;
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index fb78663..a6bf15d 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -274,13 +274,14 @@ struct ntb_dev_ops {
int (*spad_is_unsafe)(struct ntb_dev *ntb);
int (*spad_count)(struct ntb_dev *ntb);

- u32 (*spad_read)(struct ntb_dev *ntb, int idx);
- int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+ u32 (*spad_read)(struct ntb_dev *ntb, int sidx);
+ int (*spad_write)(struct ntb_dev *ntb, int sidx, u32 val);

- int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
+ int (*peer_spad_addr)(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr);
- u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
- int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+ u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
+ int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
+ u32 val);
};

static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@@ -322,13 +323,12 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
- /* ops->spad_is_unsafe && */
- ops->spad_count &&
- ops->spad_read &&
- ops->spad_write &&
- /* ops->peer_spad_addr && */
- /* ops->peer_spad_read && */
- ops->peer_spad_write &&
+ /* !ops->spad_is_unsafe == !ops->spad_count && */
+ !ops->spad_read == !ops->spad_count &&
+ !ops->spad_write == !ops->spad_count &&
+ /* !ops->peer_spad_addr == !ops->spad_count && */
+ /* !ops->peer_spad_read == !ops->spad_count && */
+ !ops->peer_spad_write == !ops->spad_count &&
1;
}

@@ -1087,51 +1087,62 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
}

/**
- * ntb_mw_count() - get the number of scratchpads
+ * ntb_spad_count() - get the number of scratchpads
* @ntb: NTB device context.
*
* Hardware and topology may support a different number of scratchpads.
+ * Although it must be the same for all ports per NTB device.
*
* Return: the number of scratchpads.
*/
static inline int ntb_spad_count(struct ntb_dev *ntb)
{
+ if (!ntb->ops->spad_count)
+ return 0;
+
return ntb->ops->spad_count(ntb);
}

/**
* ntb_spad_read() - read the local scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @sidx: Scratchpad index.
*
* Read the local scratchpad register, and return the value.
*
* Return: The value of the local scratchpad register.
*/
-static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_spad_read(struct ntb_dev *ntb, int sidx)
{
- return ntb->ops->spad_read(ntb, idx);
+ if (!ntb->ops->spad_read)
+ return ~(u32)0;
+
+ return ntb->ops->spad_read(ntb, sidx);
}

/**
* ntb_spad_write() - write the local scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @sidx: Scratchpad index.
* @val: Scratchpad value.
*
* Write the value to the local scratchpad register.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
{
- return ntb->ops->spad_write(ntb, idx, val);
+ if (!ntb->ops->spad_write)
+ return -EINVAL;
+
+ return ntb->ops->spad_write(ntb, sidx, val);
}

/**
* ntb_peer_spad_addr() - address of the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
* @spad_addr: OUT - The address of the peer scratchpad register.
*
* Return the address of the peer doorbell register. This may be used, for
@@ -1139,42 +1150,51 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr)
{
if (!ntb->ops->peer_spad_addr)
return -EINVAL;

- return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
+ return ntb->ops->peer_spad_addr(ntb, pidx, sidx, spad_addr);
}

/**
* ntb_peer_spad_read() - read the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
*
* Read the peer scratchpad register, and return the value.
*
* Return: The value of the local scratchpad register.
*/
-static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
- return ntb->ops->peer_spad_read(ntb, idx);
+ if (!ntb->ops->peer_spad_read)
+ return ~(u32)0;
+
+ return ntb->ops->peer_spad_read(ntb, pidx, sidx);
}

/**
* ntb_peer_spad_write() - write the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
* @val: Scratchpad value.
*
* Write the value to the peer scratchpad register.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
+ u32 val)
{
- return ntb->ops->peer_spad_write(ntb, idx, val);
+ if (!ntb->ops->peer_spad_write)
+ return -EINVAL;
+
+ return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
}

#endif
--
2.6.6

2016-12-12 21:09:16

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 1/9] NTB: Make link-state API being declared first

Since link operations are usually performed before memory window access
operations, it's logically better to declared link-related API before any
other methods. Additionally it's good practice for readability to declare
NTB device callback methods of hadrware drivers with the same order as it's
done within ntb.h.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 188 ++++++++++++++++++------------------
drivers/ntb/hw/intel/ntb_hw_intel.c | 168 ++++++++++++++++----------------
include/linux/ntb.h | 137 +++++++++++++-------------
3 files changed, 247 insertions(+), 246 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 6ccba0d..6704327 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -71,6 +71,97 @@ MODULE_AUTHOR("AMD Inc.");
static const struct file_operations amd_ntb_debugfs_info;
static struct dentry *debugfs_dir;

+static int amd_link_is_up(struct amd_ntb_dev *ndev)
+{
+ if (!ndev->peer_sta)
+ return NTB_LNK_STA_ACTIVE(ndev->cntl_sta);
+
+ /* If peer_sta is reset or D0 event, the ISR has
+ * started a timer to check link status of hardware.
+ * So here just clear status bit. And if peer_sta is
+ * D3 or PME_TO, D0/reset event will be happened when
+ * system wakeup/poweron, so do nothing here.
+ */
+ if (ndev->peer_sta & AMD_PEER_RESET_EVENT)
+ ndev->peer_sta &= ~AMD_PEER_RESET_EVENT;
+ else if (ndev->peer_sta & AMD_PEER_D0_EVENT)
+ ndev->peer_sta = 0;
+
+ return 0;
+}
+
+static int amd_ntb_link_is_up(struct ntb_dev *ntb,
+ enum ntb_speed *speed,
+ enum ntb_width *width)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ int ret = 0;
+
+ if (amd_link_is_up(ndev)) {
+ if (speed)
+ *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
+ if (width)
+ *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
+
+ dev_dbg(ndev_dev(ndev), "link is up.\n");
+
+ ret = 1;
+ } else {
+ if (speed)
+ *speed = NTB_SPEED_NONE;
+ if (width)
+ *width = NTB_WIDTH_NONE;
+
+ dev_dbg(ndev_dev(ndev), "link is down.\n");
+ }
+
+ return ret;
+}
+
+static int amd_ntb_link_enable(struct ntb_dev *ntb,
+ enum ntb_speed max_speed,
+ enum ntb_width max_width)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ void __iomem *mmio = ndev->self_mmio;
+ u32 ntb_ctl;
+
+ /* Enable event interrupt */
+ ndev->int_mask &= ~AMD_EVENT_INTMASK;
+ writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+ dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+
+ ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
+ ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
+ writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
+
+ return 0;
+}
+
+static int amd_ntb_link_disable(struct ntb_dev *ntb)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ void __iomem *mmio = ndev->self_mmio;
+ u32 ntb_ctl;
+
+ /* Disable event interrupt */
+ ndev->int_mask |= AMD_EVENT_INTMASK;
+ writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+ dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+
+ ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
+ ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
+ writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
+
+ return 0;
+}
+
static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
{
if (idx < 0 || idx > ndev->mw_count)
@@ -194,97 +285,6 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

-static int amd_link_is_up(struct amd_ntb_dev *ndev)
-{
- if (!ndev->peer_sta)
- return NTB_LNK_STA_ACTIVE(ndev->cntl_sta);
-
- /* If peer_sta is reset or D0 event, the ISR has
- * started a timer to check link status of hardware.
- * So here just clear status bit. And if peer_sta is
- * D3 or PME_TO, D0/reset event will be happened when
- * system wakeup/poweron, so do nothing here.
- */
- if (ndev->peer_sta & AMD_PEER_RESET_EVENT)
- ndev->peer_sta &= ~AMD_PEER_RESET_EVENT;
- else if (ndev->peer_sta & AMD_PEER_D0_EVENT)
- ndev->peer_sta = 0;
-
- return 0;
-}
-
-static int amd_ntb_link_is_up(struct ntb_dev *ntb,
- enum ntb_speed *speed,
- enum ntb_width *width)
-{
- struct amd_ntb_dev *ndev = ntb_ndev(ntb);
- int ret = 0;
-
- if (amd_link_is_up(ndev)) {
- if (speed)
- *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
- if (width)
- *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
-
- dev_dbg(ndev_dev(ndev), "link is up.\n");
-
- ret = 1;
- } else {
- if (speed)
- *speed = NTB_SPEED_NONE;
- if (width)
- *width = NTB_WIDTH_NONE;
-
- dev_dbg(ndev_dev(ndev), "link is down.\n");
- }
-
- return ret;
-}
-
-static int amd_ntb_link_enable(struct ntb_dev *ntb,
- enum ntb_speed max_speed,
- enum ntb_width max_width)
-{
- struct amd_ntb_dev *ndev = ntb_ndev(ntb);
- void __iomem *mmio = ndev->self_mmio;
- u32 ntb_ctl;
-
- /* Enable event interrupt */
- ndev->int_mask &= ~AMD_EVENT_INTMASK;
- writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
- dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
-
- ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
- ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
- writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
-
- return 0;
-}
-
-static int amd_ntb_link_disable(struct ntb_dev *ntb)
-{
- struct amd_ntb_dev *ndev = ntb_ndev(ntb);
- void __iomem *mmio = ndev->self_mmio;
- u32 ntb_ctl;
-
- /* Disable event interrupt */
- ndev->int_mask |= AMD_EVENT_INTMASK;
- writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
- dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
-
- ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
- ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
- writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
-
- return 0;
-}
-
static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
{
return ntb_ndev(ntb)->db_valid_mask;
@@ -431,12 +431,12 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
}

static const struct ntb_dev_ops amd_ntb_ops = {
- .mw_count = amd_ntb_mw_count,
- .mw_get_range = amd_ntb_mw_get_range,
- .mw_set_trans = amd_ntb_mw_set_trans,
.link_is_up = amd_ntb_link_is_up,
.link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable,
+ .mw_count = amd_ntb_mw_count,
+ .mw_get_range = amd_ntb_mw_get_range,
+ .mw_set_trans = amd_ntb_mw_set_trans,
.db_valid_mask = amd_ntb_db_valid_mask,
.db_vector_count = amd_ntb_db_vector_count,
.db_vector_mask = amd_ntb_db_vector_mask,
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index d2ce280..68d9908 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1035,6 +1035,84 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
debugfs_remove_recursive(ndev->debugfs_dir);
}

+static int intel_ntb_link_is_up(struct ntb_dev *ntb,
+ enum ntb_speed *speed,
+ enum ntb_width *width)
+{
+ struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+ if (ndev->reg->link_is_up(ndev)) {
+ if (speed)
+ *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
+ if (width)
+ *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
+ return 1;
+ } else {
+ /* TODO MAYBE: is it possible to observe the link speed and
+ * width while link is training? */
+ if (speed)
+ *speed = NTB_SPEED_NONE;
+ if (width)
+ *width = NTB_WIDTH_NONE;
+ return 0;
+ }
+}
+
+static int intel_ntb_link_enable(struct ntb_dev *ntb,
+ enum ntb_speed max_speed,
+ enum ntb_width max_width)
+{
+ struct intel_ntb_dev *ndev;
+ u32 ntb_ctl;
+
+ ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+
+ dev_dbg(ndev_dev(ndev),
+ "Enabling link with max_speed %d max_width %d\n",
+ max_speed, max_width);
+ if (max_speed != NTB_SPEED_AUTO)
+ dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
+ if (max_width != NTB_WIDTH_AUTO)
+ dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
+
+ ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+ ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
+ ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+ ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+ if (ndev->bar4_split)
+ ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
+ iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+ return 0;
+}
+
+static int intel_ntb_link_disable(struct ntb_dev *ntb)
+{
+ struct intel_ntb_dev *ndev;
+ u32 ntb_cntl;
+
+ ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+ if (ndev->ntb.topo == NTB_TOPO_SEC)
+ return -EINVAL;
+
+ dev_dbg(ndev_dev(ndev), "Disabling link\n");
+
+ /* Bring NTB link down */
+ ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+ ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
+ ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
+ if (ndev->bar4_split)
+ ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
+ ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
+ iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+ return 0;
+}
+
static int intel_ntb_mw_count(struct ntb_dev *ntb)
{
return ntb_ndev(ntb)->mw_count;
@@ -1171,84 +1249,6 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

-static int intel_ntb_link_is_up(struct ntb_dev *ntb,
- enum ntb_speed *speed,
- enum ntb_width *width)
-{
- struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
- if (ndev->reg->link_is_up(ndev)) {
- if (speed)
- *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
- if (width)
- *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
- return 1;
- } else {
- /* TODO MAYBE: is it possible to observe the link speed and
- * width while link is training? */
- if (speed)
- *speed = NTB_SPEED_NONE;
- if (width)
- *width = NTB_WIDTH_NONE;
- return 0;
- }
-}
-
-static int intel_ntb_link_enable(struct ntb_dev *ntb,
- enum ntb_speed max_speed,
- enum ntb_width max_width)
-{
- struct intel_ntb_dev *ndev;
- u32 ntb_ctl;
-
- ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
-
- dev_dbg(ndev_dev(ndev),
- "Enabling link with max_speed %d max_width %d\n",
- max_speed, max_width);
- if (max_speed != NTB_SPEED_AUTO)
- dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
- if (max_width != NTB_WIDTH_AUTO)
- dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
-
- ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
- ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
- ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
- ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
- if (ndev->bar4_split)
- ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
- iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
- return 0;
-}
-
-static int intel_ntb_link_disable(struct ntb_dev *ntb)
-{
- struct intel_ntb_dev *ndev;
- u32 ntb_cntl;
-
- ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
- if (ndev->ntb.topo == NTB_TOPO_SEC)
- return -EINVAL;
-
- dev_dbg(ndev_dev(ndev), "Disabling link\n");
-
- /* Bring NTB link down */
- ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
- ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
- ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
- if (ndev->bar4_split)
- ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
- ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
- iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
- return 0;
-}
-
static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
{
return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
@@ -2883,12 +2883,12 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {

/* operations for primary side of local ntb */
static const struct ntb_dev_ops intel_ntb_ops = {
- .mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
- .mw_set_trans = intel_ntb_mw_set_trans,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable,
+ .mw_count = intel_ntb_mw_count,
+ .mw_get_range = intel_ntb_mw_get_range,
+ .mw_set_trans = intel_ntb_mw_set_trans,
.db_is_unsafe = intel_ntb_db_is_unsafe,
.db_valid_mask = intel_ntb_db_valid_mask,
.db_vector_count = intel_ntb_db_vector_count,
@@ -2909,12 +2909,12 @@ static const struct ntb_dev_ops intel_ntb_ops = {
};

static const struct ntb_dev_ops intel_ntb3_ops = {
- .mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
- .mw_set_trans = intel_ntb3_mw_set_trans,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb3_link_enable,
.link_disable = intel_ntb_link_disable,
+ .mw_count = intel_ntb_mw_count,
+ .mw_get_range = intel_ntb_mw_get_range,
+ .mw_set_trans = intel_ntb3_mw_set_trans,
.db_valid_mask = intel_ntb_db_valid_mask,
.db_vector_count = intel_ntb_db_vector_count,
.db_vector_mask = intel_ntb_db_vector_mask,
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 6f47562..5d1f260 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -179,13 +179,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)

/**
* struct ntb_ctx_ops - ntb device operations
+ * @link_is_up: See ntb_link_is_up().
+ * @link_enable: See ntb_link_enable().
+ * @link_disable: See ntb_link_disable().
* @mw_count: See ntb_mw_count().
* @mw_get_range: See ntb_mw_get_range().
* @mw_set_trans: See ntb_mw_set_trans().
* @mw_clear_trans: See ntb_mw_clear_trans().
- * @link_is_up: See ntb_link_is_up().
- * @link_enable: See ntb_link_enable().
- * @link_disable: See ntb_link_disable().
* @db_is_unsafe: See ntb_db_is_unsafe().
* @db_valid_mask: See ntb_db_valid_mask().
* @db_vector_count: See ntb_db_vector_count().
@@ -212,6 +212,12 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_write: See ntb_peer_spad_write().
*/
struct ntb_dev_ops {
+ int (*link_is_up)(struct ntb_dev *ntb,
+ enum ntb_speed *speed, enum ntb_width *width);
+ int (*link_enable)(struct ntb_dev *ntb,
+ enum ntb_speed max_speed, enum ntb_width max_width);
+ int (*link_disable)(struct ntb_dev *ntb);
+
int (*mw_count)(struct ntb_dev *ntb);
int (*mw_get_range)(struct ntb_dev *ntb, int idx,
phys_addr_t *base, resource_size_t *size,
@@ -220,12 +226,6 @@ struct ntb_dev_ops {
dma_addr_t addr, resource_size_t size);
int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);

- int (*link_is_up)(struct ntb_dev *ntb,
- enum ntb_speed *speed, enum ntb_width *width);
- int (*link_enable)(struct ntb_dev *ntb,
- enum ntb_speed max_speed, enum ntb_width max_width);
- int (*link_disable)(struct ntb_dev *ntb);
-
int (*db_is_unsafe)(struct ntb_dev *ntb);
u64 (*db_valid_mask)(struct ntb_dev *ntb);
int (*db_vector_count)(struct ntb_dev *ntb);
@@ -265,13 +265,14 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ ops->link_is_up &&
+ ops->link_enable &&
+ ops->link_disable &&
ops->mw_count &&
ops->mw_get_range &&
ops->mw_set_trans &&
/* ops->mw_clear_trans && */
- ops->link_is_up &&
- ops->link_enable &&
- ops->link_disable &&
+
/* ops->db_is_unsafe && */
ops->db_valid_mask &&

@@ -441,6 +442,62 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_link_is_up() - get the current ntb link state
+ * @ntb: NTB device context.
+ * @speed: OUT - The link speed expressed as PCIe generation number.
+ * @width: OUT - The link width expressed as the number of PCIe lanes.
+ *
+ * Get the current state of the ntb link. It is recommended to query the link
+ * state once after every link event. It is safe to query the link state in
+ * the context of the link event callback.
+ *
+ * Return: One if the link is up, zero if the link is down, otherwise a
+ * negative value indicating the error number.
+ */
+static inline int ntb_link_is_up(struct ntb_dev *ntb,
+ enum ntb_speed *speed, enum ntb_width *width)
+{
+ return ntb->ops->link_is_up(ntb, speed, width);
+}
+
+/**
+ * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * @ntb: NTB device context.
+ * @max_speed: The maximum link speed expressed as PCIe generation number.
+ * @max_width: The maximum link width expressed as the number of PCIe lanes.
+ *
+ * Enable the link on the secondary side of the ntb. This can only be done
+ * from the primary side of the ntb in primary or b2b topology. The ntb device
+ * should train the link to its maximum speed and width, or the requested speed
+ * and width, whichever is smaller, if supported.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_enable(struct ntb_dev *ntb,
+ enum ntb_speed max_speed,
+ enum ntb_width max_width)
+{
+ return ntb->ops->link_enable(ntb, max_speed, max_width);
+}
+
+/**
+ * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * @ntb: NTB device context.
+ *
+ * Disable the link on the secondary side of the ntb. This can only be
+ * done from the primary side of the ntb in primary or b2b topology. The ntb
+ * device should disable the link. Returning from this call must indicate that
+ * a barrier has passed, though with no more writes may pass in either
+ * direction across the link, except if this call returns an error number.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_disable(struct ntb_dev *ntb)
+{
+ return ntb->ops->link_disable(ntb);
+}
+
+/**
* ntb_mw_count() - get the number of memory windows
* @ntb: NTB device context.
*
@@ -517,62 +574,6 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
}

/**
- * ntb_link_is_up() - get the current ntb link state
- * @ntb: NTB device context.
- * @speed: OUT - The link speed expressed as PCIe generation number.
- * @width: OUT - The link width expressed as the number of PCIe lanes.
- *
- * Get the current state of the ntb link. It is recommended to query the link
- * state once after every link event. It is safe to query the link state in
- * the context of the link event callback.
- *
- * Return: One if the link is up, zero if the link is down, otherwise a
- * negative value indicating the error number.
- */
-static inline int ntb_link_is_up(struct ntb_dev *ntb,
- enum ntb_speed *speed, enum ntb_width *width)
-{
- return ntb->ops->link_is_up(ntb, speed, width);
-}
-
-/**
- * ntb_link_enable() - enable the link on the secondary side of the ntb
- * @ntb: NTB device context.
- * @max_speed: The maximum link speed expressed as PCIe generation number.
- * @max_width: The maximum link width expressed as the number of PCIe lanes.
- *
- * Enable the link on the secondary side of the ntb. This can only be done
- * from the primary side of the ntb in primary or b2b topology. The ntb device
- * should train the link to its maximum speed and width, or the requested speed
- * and width, whichever is smaller, if supported.
- *
- * Return: Zero on success, otherwise an error number.
- */
-static inline int ntb_link_enable(struct ntb_dev *ntb,
- enum ntb_speed max_speed,
- enum ntb_width max_width)
-{
- return ntb->ops->link_enable(ntb, max_speed, max_width);
-}
-
-/**
- * ntb_link_disable() - disable the link on the secondary side of the ntb
- * @ntb: NTB device context.
- *
- * Disable the link on the secondary side of the ntb. This can only be
- * done from the primary side of the ntb in primary or b2b topology. The ntb
- * device should disable the link. Returning from this call must indicate that
- * a barrier has passed, though with no more writes may pass in either
- * direction across the link, except if this call returns an error number.
- *
- * Return: Zero on success, otherwise an error number.
- */
-static inline int ntb_link_disable(struct ntb_dev *ntb)
-{
- return ntb->ops->link_disable(ntb);
-}
-
-/**
* ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
* @ntb: NTB device context.
*
--
2.6.6

2016-12-12 21:10:52

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 4/9] NTB: Alter MW API to support multi-ports devices

Multi-port NTB devices permit to share a memory between all accessible peers.
Memory Windows API is altered to correspondingly initialize and map memory
windows for such devices:
ntb_mw_count(pidx); - number of inbound memory windows, which can be allocated
for shared buffer with specified peer device.
ntb_mw_get_align(pidx, widx); - get alignment and size restrition parameters
to properly allocate inbound memory region.
ntb_peer_mw_count(); - get number of outbound memory windows.
ntb_peer_mw_get_addr(widx); - get mapping address of an outbound memory window

If hardware supports inbound translation configured on the local ntb port:
ntb_mw_set_trans(pidx, widx); - set translation address of allocated inbound
memory window so a peer device could access it.
ntb_mw_clear_trans(pidx, widx); - clear the translation address of an inbound
memory window.

If hadrware supports outbound translation configured on the peer ntb port:
ntb_peer_mw_set_trans(pidx, widx); - set translation address of a memory
window retrieved from a peer device
ntb_peer_mw_clear_trans(pidx, widx); - clear the translation address of an
outbound memory window

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 68 +++++++++---
drivers/ntb/hw/amd/ntb_hw_amd.h | 2 +
drivers/ntb/hw/intel/ntb_hw_intel.c | 90 ++++++++++++----
drivers/ntb/hw/intel/ntb_hw_intel.h | 2 +
drivers/ntb/ntb.c | 2 +
drivers/ntb/ntb_transport.c | 21 +++-
drivers/ntb/test/ntb_perf.c | 17 ++-
drivers/ntb/test/ntb_tool.c | 43 +++++---
include/linux/ntb.h | 208 ++++++++++++++++++++++++++++--------
9 files changed, 346 insertions(+), 107 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index b6a4291..74fe9b8 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
* BSD LICENSE
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -213,40 +215,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
return 1 << idx;
}

-static int amd_ntb_mw_count(struct ntb_dev *ntb)
+static int amd_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
return ntb_ndev(ntb)->mw_count;
}

-static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base,
- resource_size_t *size,
- resource_size_t *align,
- resource_size_t *align_size)
+static int amd_ntb_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 amd_ntb_dev *ndev = ntb_ndev(ntb);
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;

- if (base)
- *base = pci_resource_start(ndev->ntb.pdev, bar);
-
- if (size)
- *size = pci_resource_len(ndev->ntb.pdev, bar);
+ if (addr_align)
+ *addr_align = SZ_4K;

- if (align)
- *align = SZ_4K;
+ if (size_align)
+ *size_align = 1;

- if (align_size)
- *align_size = 1;
+ if (size_max)
+ *size_max = pci_resource_len(ndev->ntb.pdev, bar);

return 0;
}

-static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
@@ -256,6 +260,9 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base_addr, limit, reg_val;
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;
@@ -328,6 +335,31 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

+static int amd_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ /* The same as for inbound MWs */
+ return ntb_ndev(ntb)->mw_count;
+}
+
+static int amd_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ int bar;
+
+ bar = ndev_mw_to_bar(ndev, idx);
+ if (bar < 0)
+ return bar;
+
+ if (base)
+ *base = pci_resource_start(ndev->ntb.pdev, bar);
+
+ if (size)
+ *size = pci_resource_len(ndev->ntb.pdev, bar);
+
+ return 0;
+}
+
static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
{
return ntb_ndev(ntb)->db_valid_mask;
@@ -482,8 +514,10 @@ static const struct ntb_dev_ops amd_ntb_ops = {
.link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable,
.mw_count = amd_ntb_mw_count,
- .mw_get_range = amd_ntb_mw_get_range,
+ .mw_get_align = amd_ntb_mw_get_align,
.mw_set_trans = amd_ntb_mw_set_trans,
+ .peer_mw_count = amd_ntb_peer_mw_count,
+ .peer_mw_get_addr = amd_ntb_peer_mw_get_addr,
.db_valid_mask = amd_ntb_db_valid_mask,
.db_vector_count = amd_ntb_db_vector_count,
.db_vector_mask = amd_ntb_db_vector_mask,
diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h
index 1aeb08f..3296c98 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.h
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.h
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
* BSD LICENSE
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index f37b6fb..5a57d9e 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -6,6 +6,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -15,6 +16,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -1156,20 +1158,26 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
return 0;
}

-static int intel_ntb_mw_count(struct ntb_dev *ntb)
+static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
return ntb_ndev(ntb)->mw_count;
}

-static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base,
- resource_size_t *size,
- resource_size_t *align,
- resource_size_t *align_size)
+static int intel_ntb_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 intel_ntb_dev *ndev = ntb_ndev(ntb);
+ resource_size_t bar_size, mw_size;
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -1177,24 +1185,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
if (bar < 0)
return bar;

- if (base)
- *base = pci_resource_start(ndev->ntb.pdev, bar) +
- (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+ bar_size = pci_resource_len(ndev->ntb.pdev, bar);

- if (size)
- *size = pci_resource_len(ndev->ntb.pdev, bar) -
- (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+ if (idx == ndev->b2b_idx)
+ mw_size = bar_size - ndev->b2b_off;
+ else
+ mw_size = bar_size;
+
+ if (addr_align)
+ *addr_align = pci_resource_len(ndev->ntb.pdev, bar);

- if (align)
- *align = pci_resource_len(ndev->ntb.pdev, bar);
+ if (size_align)
+ *size_align = 1;

- if (align_size)
- *align_size = 1;
+ if (size_max)
+ *size_max = mw_size;

return 0;
}

-static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);
@@ -1204,6 +1214,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base, limit, reg_val;
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -1292,6 +1305,36 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

+static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ /* Numbers of inbound and outbound memory windows match */
+ return ntb_ndev(ntb)->mw_count;
+}
+
+static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+ int bar;
+
+ if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+ idx += 1;
+
+ bar = ndev_mw_to_bar(ndev, idx);
+ if (bar < 0)
+ return bar;
+
+ if (base)
+ *base = pci_resource_start(ndev->ntb.pdev, bar) +
+ (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+ if (size)
+ *size = pci_resource_len(ndev->ntb.pdev, bar) -
+ (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+ return 0;
+}
+
static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
{
return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
@@ -1922,7 +1965,7 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb,

return 0;
}
-static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);
@@ -1932,6 +1975,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base, limit, reg_val;
int bar;

+ if (pidx > NTB_PIDX_MAX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -2933,8 +2979,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
.link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable,
.mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
+ .mw_get_align = intel_ntb_mw_get_align,
.mw_set_trans = intel_ntb_mw_set_trans,
+ .peer_mw_count = intel_ntb_peer_mw_count,
+ .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
.db_is_unsafe = intel_ntb_db_is_unsafe,
.db_valid_mask = intel_ntb_db_valid_mask,
.db_vector_count = intel_ntb_db_vector_count,
@@ -2963,8 +3011,10 @@ static const struct ntb_dev_ops intel_ntb3_ops = {
.link_enable = intel_ntb3_link_enable,
.link_disable = intel_ntb_link_disable,
.mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
+ .mw_get_align = intel_ntb_mw_get_align,
.mw_set_trans = intel_ntb3_mw_set_trans,
+ .peer_mw_count = intel_ntb_peer_mw_count,
+ .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
.db_valid_mask = intel_ntb_db_valid_mask,
.db_vector_count = intel_ntb_db_vector_count,
.db_vector_mask = intel_ntb_db_vector_mask,
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
index f12c960..4fd75a1 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.h
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -6,6 +6,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -15,6 +16,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 2e25307..f6153af 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
* BSD LICENSE
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 37d428d..cb4f99889 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -685,7 +685,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
if (!mw->virt_addr)
return;

- ntb_mw_clear_trans(nt->ndev, num_mw);
+ ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
dma_free_coherent(&pdev->dev, mw->buff_size,
mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0;
@@ -742,7 +742,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
}

/* Notify HW the memory location of the receive buffer */
- rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
+ rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
+ mw->xlat_size);
if (rc) {
dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
ntb_free_mw(nt, num_mw);
@@ -1072,13 +1073,18 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
int node;
int rc, i;

- mw_count = ntb_mw_count(ndev);
+ mw_count = ntb_mw_count(ndev, PIDX);
if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) {
dev_err(&ndev->dev, "Not enough scratch pad registers for %s",
NTB_TRANSPORT_NAME);
return -EIO;
}

+ if (!ndev->ops->mw_set_trans) {
+ dev_err(&ndev->dev, "Inbound MW based NTB API is required\n");
+ return -EINVAL;
+ }
+
if (ntb_db_is_unsafe(ndev))
dev_dbg(&ndev->dev,
"doorbell is unsafe, proceed anyway...\n");
@@ -1109,8 +1115,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
for (i = 0; i < mw_count; i++) {
mw = &nt->mw_vec[i];

- rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
- &mw->xlat_align, &mw->xlat_align_size);
+ rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
+ &mw->xlat_align_size, NULL);
+ if (rc)
+ goto err1;
+
+ rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
+ &mw->phys_size);
if (rc)
goto err1;

diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index 481827a..3efb5b5 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -453,7 +453,7 @@ static void perf_free_mw(struct perf_ctx *perf)
if (!mw->virt_addr)
return;

- ntb_mw_clear_trans(perf->ntb, 0);
+ ntb_mw_clear_trans(perf->ntb, PIDX, 0);
dma_free_coherent(&pdev->dev, mw->buf_size,
mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0;
@@ -489,7 +489,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
mw->buf_size = 0;
}

- rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
+ rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size);
if (rc) {
dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
perf_free_mw(perf);
@@ -560,8 +560,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)

mw = &perf->mw;

- rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size,
- &mw->xlat_align, &mw->xlat_align_size);
+ rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
+ &mw->xlat_align_size, NULL);
+ if (rc)
+ return rc;
+
+ rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
if (rc)
return rc;

@@ -765,6 +769,11 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
return -EIO;
}

+ if (!ntb->ops->mw_set_trans) {
+ dev_err(&ntb->dev, "Need inbound MW based NTB API\n");
+ return -EINVAL;
+ }
+
if (ntb_peer_port_count(ntb) != 1)
dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");

diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index 85b6417..7aa6018 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -119,7 +119,8 @@ MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);

-#define MAX_MWS 16
+/* It is rare to have hadrware with greater than six MWs */
+#define MAX_MWS 6
/* Only two-ports devices are supported */
#define PIDX 0

@@ -670,28 +671,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
{
int rc;
struct tool_mw *mw = &tc->mws[idx];
- phys_addr_t base;
- resource_size_t size, align, align_size;
+ resource_size_t size, align_addr, align_size;
char buf[16];

if (mw->peer)
return 0;

- rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
- &align_size);
+ rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
+ &align_size, &size);
if (rc)
return rc;

mw->size = min_t(resource_size_t, req_size, size);
- mw->size = round_up(mw->size, align);
+ mw->size = round_up(mw->size, align_addr);
mw->size = round_up(mw->size, align_size);
mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
&mw->peer_dma, GFP_KERNEL);

- if (!mw->peer)
+ if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
return -ENOMEM;

- rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
+ rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
if (rc)
goto err_free_dma;

@@ -718,7 +718,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx)
struct tool_mw *mw = &tc->mws[idx];

if (mw->peer) {
- ntb_mw_clear_trans(tc->ntb, idx);
+ ntb_mw_clear_trans(tc->ntb, PIDX, idx);
dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
mw->peer,
mw->peer_dma);
@@ -744,8 +744,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,

phys_addr_t base;
resource_size_t mw_size;
- resource_size_t align;
+ resource_size_t align_addr;
resource_size_t align_size;
+ resource_size_t max_size;

buf_size = min_t(size_t, size, 512);

@@ -753,8 +754,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
if (!buf)
return -ENOMEM;

- ntb_mw_get_range(mw->tc->ntb, mw->idx,
- &base, &mw_size, &align, &align_size);
+ ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
+ &align_addr, &align_size, &max_size);
+ ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);

off += scnprintf(buf + off, buf_size - off,
"Peer MW %d Information:\n", mw->idx);
@@ -769,12 +771,16 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,

off += scnprintf(buf + off, buf_size - off,
"Alignment \t%lld\n",
- (unsigned long long)align);
+ (unsigned long long)align_addr);

off += scnprintf(buf + off, buf_size - off,
"Size Alignment \t%lld\n",
(unsigned long long)align_size);

+ off += scnprintf(buf + off, buf_size - off,
+ "Size Max \t%lld\n",
+ (unsigned long long)max_size);
+
off += scnprintf(buf + off, buf_size - off,
"Ready \t%c\n",
(mw->peer) ? 'Y' : 'N');
@@ -829,8 +835,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx)
phys_addr_t base;
int rc;

- rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
- NULL, NULL);
+ rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size);
if (rc)
return rc;

@@ -915,6 +920,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
int rc;
int i;

+ if (!ntb->ops->mw_set_trans) {
+ dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
+ rc = -EINVAL;
+ goto err_tc;
+ }
+
if (ntb_db_is_unsafe(ntb))
dev_dbg(&ntb->dev, "doorbell is unsafe\n");

@@ -933,7 +944,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
tc->ntb = ntb;
init_waitqueue_head(&tc->link_wq);

- tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
+ tc->mw_count = min(ntb_mw_count(tc->ntb, PIDX), MAX_MWS);
for (i = 0; i < tc->mw_count; i++) {
rc = tool_init_mw(tc, i);
if (rc)
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 47ec611..fb78663 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
* BSD LICENSE
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -187,9 +189,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @link_enable: See ntb_link_enable().
* @link_disable: See ntb_link_disable().
* @mw_count: See ntb_mw_count().
- * @mw_get_range: See ntb_mw_get_range().
+ * @mw_get_align: See ntb_mw_get_align().
* @mw_set_trans: See ntb_mw_set_trans().
* @mw_clear_trans: See ntb_mw_clear_trans().
+ * @peer_mw_count: See ntb_peer_mw_count().
+ * @peer_mw_get_addr: See ntb_peer_mw_get_addr().
+ * @peer_mw_set_trans: See ntb_peer_mw_set_trans().
+ * @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
* @db_is_unsafe: See ntb_db_is_unsafe().
* @db_valid_mask: See ntb_db_valid_mask().
* @db_vector_count: See ntb_db_vector_count().
@@ -227,13 +233,20 @@ struct ntb_dev_ops {
enum ntb_speed max_speed, enum ntb_width max_width);
int (*link_disable)(struct ntb_dev *ntb);

- int (*mw_count)(struct ntb_dev *ntb);
- int (*mw_get_range)(struct ntb_dev *ntb, int idx,
- phys_addr_t *base, resource_size_t *size,
- resource_size_t *align, resource_size_t *align_size);
- int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
+ int (*mw_count)(struct ntb_dev *ntb, int pidx);
+ int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
+ resource_size_t *addr_align,
+ resource_size_t *size_align,
+ resource_size_t *size_max);
+ int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size);
- int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
+ int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
+ int (*peer_mw_count)(struct ntb_dev *ntb);
+ int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
+ phys_addr_t *base, resource_size_t *size);
+ int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
+ u64 addr, resource_size_t size);
+ int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);

int (*db_is_unsafe)(struct ntb_dev *ntb);
u64 (*db_valid_mask)(struct ntb_dev *ntb);
@@ -282,9 +295,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->link_enable &&
ops->link_disable &&
ops->mw_count &&
- ops->mw_get_range &&
- ops->mw_set_trans &&
+ ops->mw_get_align &&
+ (ops->mw_set_trans ||
+ ops->peer_mw_set_trans) &&
/* ops->mw_clear_trans && */
+ ops->peer_mw_count &&
+ ops->peer_mw_get_addr &&
+ /* ops->peer_mw_clear_trans && */

/* ops->db_is_unsafe && */
ops->db_valid_mask &&
@@ -570,79 +587,180 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
}

/**
- * ntb_mw_count() - get the number of memory windows
+ * ntb_mw_count() - get the number of inbound memory windows, which could
+ * be created for a specified peer device
* @ntb: NTB device context.
+ * @pidx: Port index of peer device.
*
* Hardware and topology may support a different number of memory windows.
+ * Moreover different peer devices can support different number of memory
+ * windows. Simply speaking this method returns the number of possible inbound
+ * memory windows to share with specified peer device.
*
* Return: the number of memory windows.
*/
-static inline int ntb_mw_count(struct ntb_dev *ntb)
+static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
- return ntb->ops->mw_count(ntb);
+ return ntb->ops->mw_count(ntb, pidx);
}

/**
- * ntb_mw_get_range() - get the range of a memory window
+ * ntb_mw_get_align() - get the restriction parameters of inbound memory window
* @ntb: NTB device context.
- * @idx: Memory window number.
- * @base: OUT - the base address for mapping the memory window
- * @size: OUT - the size for mapping the memory window
- * @align: OUT - the base alignment for translating the memory window
- * @align_size: OUT - the size alignment for translating the memory window
- *
- * Get the range of a memory window. NULL may be given for any output
- * parameter if the value is not needed. The base and size may be used for
- * mapping the memory window, to access the peer memory. The alignment and
- * size may be used for translating the memory window, for the peer to access
- * memory on the local system.
- *
- * Return: Zero on success, otherwise an error number.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ * @addr_align: OUT - the base alignment for translating the memory window
+ * @size_align: OUT - the size alignment for translating the memory window
+ * @size_max: OUT - the maximum size of the memory window
+ *
+ * Get the alignments of an inbound memory window with specified index.
+ * NULL may be given for any output parameter if the value is not needed.
+ * The alignment and size parameters may be used for allocation of proper
+ * shared memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
*/
-static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base, resource_size_t *size,
- resource_size_t *align, resource_size_t *align_size)
+static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
+ resource_size_t *addr_align,
+ resource_size_t *size_align,
+ resource_size_t *size_max)
{
- return ntb->ops->mw_get_range(ntb, idx, base, size,
- align, align_size);
+ return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
+ size_max);
}

/**
- * ntb_mw_set_trans() - set the translation of a memory window
+ * ntb_mw_set_trans() - set the translation of an inbound memory window
* @ntb: NTB device context.
- * @idx: Memory window number.
- * @addr: The dma address local memory to expose to the peer.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ * @addr: The dma address of local memory to expose to the peer.
* @size: The size of the local memory to expose to the peer.
*
* Set the translation of a memory window. The peer may access local memory
* through the window starting at the address, up to the size. The address
- * must be aligned to the alignment specified by ntb_mw_get_range(). The size
- * must be aligned to the size alignment specified by ntb_mw_get_range().
+ * and size must be aligned in complience with restrictions of
+ * ntb_mw_get_align(). The region size should not exceed the size_max parameter
+ * of that method.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size)
{
- return ntb->ops->mw_set_trans(ntb, idx, addr, size);
+ if (!ntb->ops->mw_set_trans)
+ return -EINVAL;
+
+ return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
}

/**
- * ntb_mw_clear_trans() - clear the translation of a memory window
+ * ntb_mw_clear_trans() - clear the translation address of an inbound memory
+ * window
* @ntb: NTB device context.
- * @idx: Memory window number.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
*
- * Clear the translation of a memory window. The peer may no longer access
- * local memory through the window.
+ * Clear the translation of an inbound memory window. The peer may no longer
+ * access local memory through the window.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
+static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
{
if (!ntb->ops->mw_clear_trans)
- return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
+ return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
+
+ return ntb->ops->mw_clear_trans(ntb, pidx, widx);
+}
+
+/**
+ * ntb_peer_mw_count() - get the number of outbound memory windows, which could
+ * be mapped to access a shared memory
+ * @ntb: NTB device context.
+ *
+ * Hardware and topology may support a different number of memory windows.
+ * This method returns the number of outbound memory windows supported by
+ * local device.
+ *
+ * Return: the number of memory windows.
+ */
+static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ return ntb->ops->peer_mw_count(ntb);
+}
+
+/**
+ * ntb_peer_mw_get_addr() - get map address of an outbound memory window
+ * @ntb: NTB device context.
+ * @widx: Memory window index (within ntb_peer_mw_count() return value).
+ * @base: OUT - the base address of mapping region.
+ * @size: OUT - the size of mapping region.
+ *
+ * Get base and size of memory region to map. NULL may be given for any output
+ * parameter if the value is not needed. The base and size may be used for
+ * mapping the memory window, to access the peer memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
+}
+
+/**
+ * ntb_peer_mw_set_trans() - set a translation address of a memory window
+ * retrieved from a peer device
+ * @ntb: NTB device context.
+ * @pidx: Port index of peer device the translation address received from.
+ * @widx: Memory window index.
+ * @addr: The dma address of the shared memory to access.
+ * @size: The size of the shared memory to access.
+ *
+ * Set the translation of an outbound memory window. The local device may
+ * access shared memory allocated by a peer device sent the address.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface, so a translation address can be only set on the side,
+ * where shared memory (inbound memory windows) is allocated.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
+ u64 addr, resource_size_t size)
+{
+ if (!ntb->ops->peer_mw_set_trans)
+ return -EINVAL;
+
+ return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
+}
+
+/**
+ * ntb_peer_mw_clear_trans() - clear the translation address of an outbound
+ * memory window
+ * @ntb: NTB device context.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ *
+ * Clear the translation of a outbound memory window. The local device may no
+ * longer access a shared memory through the window.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
+ int widx)
+{
+ if (!ntb->ops->peer_mw_clear_trans)
+ return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);

- return ntb->ops->mw_clear_trans(ntb, idx);
+ return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
}

/**
--
2.6.6

2016-12-12 21:11:23

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2 3/9] NTB: Alter link-state API to support multi-port devices

Multi-port devices permit the NTB connections between multiple domains,
so a local device can have NTB link being up with one peer and being
down with another. NTB link-state API is appropriately altered to return
a bitfield of the link-states between the local device and possible peers.

Signed-off-by: Serge Semin <[email protected]>

---
drivers/ntb/hw/amd/ntb_hw_amd.c | 2 +-
drivers/ntb/hw/intel/ntb_hw_intel.c | 2 +-
include/linux/ntb.h | 31 ++++++++++++++++---------------
3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 0b767ef..b6a4291 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -133,7 +133,7 @@ static int amd_link_is_up(struct amd_ntb_dev *ndev)
return 0;
}

-static int amd_ntb_link_is_up(struct ntb_dev *ntb,
+static u64 amd_ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed,
enum ntb_width *width)
{
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 7e44dc3..f37b6fb 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1078,7 +1078,7 @@ static int intel_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
return 0;
}

-static int intel_ntb_link_is_up(struct ntb_dev *ntb,
+static u64 intel_ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed,
enum ntb_width *width)
{
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 3216689..47ec611 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -221,7 +221,7 @@ struct ntb_dev_ops {
int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
int (*peer_port_idx)(struct ntb_dev *ntb, int port);

- int (*link_is_up)(struct ntb_dev *ntb,
+ u64 (*link_is_up)(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width);
int (*link_enable)(struct ntb_dev *ntb,
enum ntb_speed max_speed, enum ntb_width max_width);
@@ -522,25 +522,26 @@ static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
* state once after every link event. It is safe to query the link state in
* the context of the link event callback.
*
- * Return: One if the link is up, zero if the link is down, otherwise a
- * negative value indicating the error number.
+ * Return: bitfield of indexed ports link state: bit is set/cleared if the
+ * link is up/down respectively.
*/
-static inline int ntb_link_is_up(struct ntb_dev *ntb,
+static inline u64 ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width)
{
return ntb->ops->link_is_up(ntb, speed, width);
}

/**
- * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * ntb_link_enable() - enable the local port ntb connection
* @ntb: NTB device context.
* @max_speed: The maximum link speed expressed as PCIe generation number.
* @max_width: The maximum link width expressed as the number of PCIe lanes.
*
- * Enable the link on the secondary side of the ntb. This can only be done
- * from the primary side of the ntb in primary or b2b topology. The ntb device
- * should train the link to its maximum speed and width, or the requested speed
- * and width, whichever is smaller, if supported.
+ * Enable the NTB/PCIe link on the local or remote (for bridge-to-bridge
+ * topology) side of the bridge. If it's supported the ntb device should train
+ * the link to its maximum speed and width, or the requested speed and width,
+ * whichever is smaller. Some hardware doesn't support PCIe link training, so
+ * the last two arguments will be ignored then.
*
* Return: Zero on success, otherwise an error number.
*/
@@ -552,14 +553,14 @@ static inline int ntb_link_enable(struct ntb_dev *ntb,
}

/**
- * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * ntb_link_disable() - disable the local port ntb connection
* @ntb: NTB device context.
*
- * Disable the link on the secondary side of the ntb. This can only be
- * done from the primary side of the ntb in primary or b2b topology. The ntb
- * device should disable the link. Returning from this call must indicate that
- * a barrier has passed, though with no more writes may pass in either
- * direction across the link, except if this call returns an error number.
+ * Disable the link on the local or remote (for b2b topology) of the ntb.
+ * The ntb device should disable the link. Returning from this call must
+ * indicate that a barrier has passed, though with no more writes may pass in
+ * either direction across the link, except if this call returns an error
+ * number.
*
* Return: Zero on success, otherwise an error number.
*/
--
2.6.6

2016-12-13 04:12:19

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 1/9] NTB: Make link-state API being declared first

From: Serge Semin
> Since link operations are usually performed before memory window access
> operations, it's logically better to declared link-related API before any
> other methods. Additionally it's good practice for readability to declare
> NTB device callback methods of hadrware drivers with the same order as it's
> done within ntb.h.

s/hadrware/hardware/

Please limit this change to ntb.h. Leave it to the hardware driver maintainers to rearrange the methods in each driver if they care to. Code movement may conflict with other changes in development.

>
> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> drivers/ntb/hw/amd/ntb_hw_amd.c | 188 ++++++++++++++++++------------------
> drivers/ntb/hw/intel/ntb_hw_intel.c | 168 ++++++++++++++++----------------
> include/linux/ntb.h | 137 +++++++++++++-------------
> 3 files changed, 247 insertions(+), 246 deletions(-)
>
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
> index 6ccba0d..6704327 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.c
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
> @@ -71,6 +71,97 @@ MODULE_AUTHOR("AMD Inc.");
> static const struct file_operations amd_ntb_debugfs_info;
> static struct dentry *debugfs_dir;
>
> +static int amd_link_is_up(struct amd_ntb_dev *ndev)
> +{
> + if (!ndev->peer_sta)
> + return NTB_LNK_STA_ACTIVE(ndev->cntl_sta);
> +
> + /* If peer_sta is reset or D0 event, the ISR has
> + * started a timer to check link status of hardware.
> + * So here just clear status bit. And if peer_sta is
> + * D3 or PME_TO, D0/reset event will be happened when
> + * system wakeup/poweron, so do nothing here.
> + */
> + if (ndev->peer_sta & AMD_PEER_RESET_EVENT)
> + ndev->peer_sta &= ~AMD_PEER_RESET_EVENT;
> + else if (ndev->peer_sta & AMD_PEER_D0_EVENT)
> + ndev->peer_sta = 0;
> +
> + return 0;
> +}
> +
> +static int amd_ntb_link_is_up(struct ntb_dev *ntb,
> + enum ntb_speed *speed,
> + enum ntb_width *width)
> +{
> + struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> + int ret = 0;
> +
> + if (amd_link_is_up(ndev)) {
> + if (speed)
> + *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
> + if (width)
> + *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
> +
> + dev_dbg(ndev_dev(ndev), "link is up.\n");
> +
> + ret = 1;
> + } else {
> + if (speed)
> + *speed = NTB_SPEED_NONE;
> + if (width)
> + *width = NTB_WIDTH_NONE;
> +
> + dev_dbg(ndev_dev(ndev), "link is down.\n");
> + }
> +
> + return ret;
> +}
> +
> +static int amd_ntb_link_enable(struct ntb_dev *ntb,
> + enum ntb_speed max_speed,
> + enum ntb_width max_width)
> +{
> + struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> + void __iomem *mmio = ndev->self_mmio;
> + u32 ntb_ctl;
> +
> + /* Enable event interrupt */
> + ndev->int_mask &= ~AMD_EVENT_INTMASK;
> + writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
> +
> + if (ndev->ntb.topo == NTB_TOPO_SEC)
> + return -EINVAL;
> + dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
> +
> + ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
> + ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
> + writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
> +
> + return 0;
> +}
> +
> +static int amd_ntb_link_disable(struct ntb_dev *ntb)
> +{
> + struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> + void __iomem *mmio = ndev->self_mmio;
> + u32 ntb_ctl;
> +
> + /* Disable event interrupt */
> + ndev->int_mask |= AMD_EVENT_INTMASK;
> + writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
> +
> + if (ndev->ntb.topo == NTB_TOPO_SEC)
> + return -EINVAL;
> + dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
> +
> + ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
> + ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
> + writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
> +
> + return 0;
> +}
> +
> static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
> {
> if (idx < 0 || idx > ndev->mw_count)
> @@ -194,97 +285,6 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> return 0;
> }
>
> -static int amd_link_is_up(struct amd_ntb_dev *ndev)
> -{
> - if (!ndev->peer_sta)
> - return NTB_LNK_STA_ACTIVE(ndev->cntl_sta);
> -
> - /* If peer_sta is reset or D0 event, the ISR has
> - * started a timer to check link status of hardware.
> - * So here just clear status bit. And if peer_sta is
> - * D3 or PME_TO, D0/reset event will be happened when
> - * system wakeup/poweron, so do nothing here.
> - */
> - if (ndev->peer_sta & AMD_PEER_RESET_EVENT)
> - ndev->peer_sta &= ~AMD_PEER_RESET_EVENT;
> - else if (ndev->peer_sta & AMD_PEER_D0_EVENT)
> - ndev->peer_sta = 0;
> -
> - return 0;
> -}
> -
> -static int amd_ntb_link_is_up(struct ntb_dev *ntb,
> - enum ntb_speed *speed,
> - enum ntb_width *width)
> -{
> - struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> - int ret = 0;
> -
> - if (amd_link_is_up(ndev)) {
> - if (speed)
> - *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
> - if (width)
> - *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
> -
> - dev_dbg(ndev_dev(ndev), "link is up.\n");
> -
> - ret = 1;
> - } else {
> - if (speed)
> - *speed = NTB_SPEED_NONE;
> - if (width)
> - *width = NTB_WIDTH_NONE;
> -
> - dev_dbg(ndev_dev(ndev), "link is down.\n");
> - }
> -
> - return ret;
> -}
> -
> -static int amd_ntb_link_enable(struct ntb_dev *ntb,
> - enum ntb_speed max_speed,
> - enum ntb_width max_width)
> -{
> - struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> - void __iomem *mmio = ndev->self_mmio;
> - u32 ntb_ctl;
> -
> - /* Enable event interrupt */
> - ndev->int_mask &= ~AMD_EVENT_INTMASK;
> - writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
> -
> - if (ndev->ntb.topo == NTB_TOPO_SEC)
> - return -EINVAL;
> - dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
> -
> - ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
> - ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
> - writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
> -
> - return 0;
> -}
> -
> -static int amd_ntb_link_disable(struct ntb_dev *ntb)
> -{
> - struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> - void __iomem *mmio = ndev->self_mmio;
> - u32 ntb_ctl;
> -
> - /* Disable event interrupt */
> - ndev->int_mask |= AMD_EVENT_INTMASK;
> - writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
> -
> - if (ndev->ntb.topo == NTB_TOPO_SEC)
> - return -EINVAL;
> - dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
> -
> - ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
> - ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
> - writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
> -
> - return 0;
> -}
> -
> static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
> {
> return ntb_ndev(ntb)->db_valid_mask;
> @@ -431,12 +431,12 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
> }
>
> static const struct ntb_dev_ops amd_ntb_ops = {
> - .mw_count = amd_ntb_mw_count,
> - .mw_get_range = amd_ntb_mw_get_range,
> - .mw_set_trans = amd_ntb_mw_set_trans,
> .link_is_up = amd_ntb_link_is_up,
> .link_enable = amd_ntb_link_enable,
> .link_disable = amd_ntb_link_disable,
> + .mw_count = amd_ntb_mw_count,
> + .mw_get_range = amd_ntb_mw_get_range,
> + .mw_set_trans = amd_ntb_mw_set_trans,
> .db_valid_mask = amd_ntb_db_valid_mask,
> .db_vector_count = amd_ntb_db_vector_count,
> .db_vector_mask = amd_ntb_db_vector_mask,
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index d2ce280..68d9908 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -1035,6 +1035,84 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
> debugfs_remove_recursive(ndev->debugfs_dir);
> }
>
> +static int intel_ntb_link_is_up(struct ntb_dev *ntb,
> + enum ntb_speed *speed,
> + enum ntb_width *width)
> +{
> + struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> +
> + if (ndev->reg->link_is_up(ndev)) {
> + if (speed)
> + *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
> + if (width)
> + *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
> + return 1;
> + } else {
> + /* TODO MAYBE: is it possible to observe the link speed and
> + * width while link is training? */
> + if (speed)
> + *speed = NTB_SPEED_NONE;
> + if (width)
> + *width = NTB_WIDTH_NONE;
> + return 0;
> + }
> +}
> +
> +static int intel_ntb_link_enable(struct ntb_dev *ntb,
> + enum ntb_speed max_speed,
> + enum ntb_width max_width)
> +{
> + struct intel_ntb_dev *ndev;
> + u32 ntb_ctl;
> +
> + ndev = container_of(ntb, struct intel_ntb_dev, ntb);
> +
> + if (ndev->ntb.topo == NTB_TOPO_SEC)
> + return -EINVAL;
> +
> + dev_dbg(ndev_dev(ndev),
> + "Enabling link with max_speed %d max_width %d\n",
> + max_speed, max_width);
> + if (max_speed != NTB_SPEED_AUTO)
> + dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
> + if (max_width != NTB_WIDTH_AUTO)
> + dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
> +
> + ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
> + ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
> + ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
> + ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
> + if (ndev->bar4_split)
> + ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
> + iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
> +
> + return 0;
> +}
> +
> +static int intel_ntb_link_disable(struct ntb_dev *ntb)
> +{
> + struct intel_ntb_dev *ndev;
> + u32 ntb_cntl;
> +
> + ndev = container_of(ntb, struct intel_ntb_dev, ntb);
> +
> + if (ndev->ntb.topo == NTB_TOPO_SEC)
> + return -EINVAL;
> +
> + dev_dbg(ndev_dev(ndev), "Disabling link\n");
> +
> + /* Bring NTB link down */
> + ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
> + ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
> + ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
> + if (ndev->bar4_split)
> + ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
> + ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
> + iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
> +
> + return 0;
> +}
> +
> static int intel_ntb_mw_count(struct ntb_dev *ntb)
> {
> return ntb_ndev(ntb)->mw_count;
> @@ -1171,84 +1249,6 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> return 0;
> }
>
> -static int intel_ntb_link_is_up(struct ntb_dev *ntb,
> - enum ntb_speed *speed,
> - enum ntb_width *width)
> -{
> - struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> -
> - if (ndev->reg->link_is_up(ndev)) {
> - if (speed)
> - *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
> - if (width)
> - *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
> - return 1;
> - } else {
> - /* TODO MAYBE: is it possible to observe the link speed and
> - * width while link is training? */
> - if (speed)
> - *speed = NTB_SPEED_NONE;
> - if (width)
> - *width = NTB_WIDTH_NONE;
> - return 0;
> - }
> -}
> -
> -static int intel_ntb_link_enable(struct ntb_dev *ntb,
> - enum ntb_speed max_speed,
> - enum ntb_width max_width)
> -{
> - struct intel_ntb_dev *ndev;
> - u32 ntb_ctl;
> -
> - ndev = container_of(ntb, struct intel_ntb_dev, ntb);
> -
> - if (ndev->ntb.topo == NTB_TOPO_SEC)
> - return -EINVAL;
> -
> - dev_dbg(ndev_dev(ndev),
> - "Enabling link with max_speed %d max_width %d\n",
> - max_speed, max_width);
> - if (max_speed != NTB_SPEED_AUTO)
> - dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
> - if (max_width != NTB_WIDTH_AUTO)
> - dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
> -
> - ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
> - ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
> - ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
> - ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
> - if (ndev->bar4_split)
> - ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
> - iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
> -
> - return 0;
> -}
> -
> -static int intel_ntb_link_disable(struct ntb_dev *ntb)
> -{
> - struct intel_ntb_dev *ndev;
> - u32 ntb_cntl;
> -
> - ndev = container_of(ntb, struct intel_ntb_dev, ntb);
> -
> - if (ndev->ntb.topo == NTB_TOPO_SEC)
> - return -EINVAL;
> -
> - dev_dbg(ndev_dev(ndev), "Disabling link\n");
> -
> - /* Bring NTB link down */
> - ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
> - ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
> - ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
> - if (ndev->bar4_split)
> - ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
> - ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
> - iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
> -
> - return 0;
> -}
> -
> static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
> {
> return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
> @@ -2883,12 +2883,12 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {
>
> /* operations for primary side of local ntb */
> static const struct ntb_dev_ops intel_ntb_ops = {
> - .mw_count = intel_ntb_mw_count,
> - .mw_get_range = intel_ntb_mw_get_range,
> - .mw_set_trans = intel_ntb_mw_set_trans,
> .link_is_up = intel_ntb_link_is_up,
> .link_enable = intel_ntb_link_enable,
> .link_disable = intel_ntb_link_disable,
> + .mw_count = intel_ntb_mw_count,
> + .mw_get_range = intel_ntb_mw_get_range,
> + .mw_set_trans = intel_ntb_mw_set_trans,
> .db_is_unsafe = intel_ntb_db_is_unsafe,
> .db_valid_mask = intel_ntb_db_valid_mask,
> .db_vector_count = intel_ntb_db_vector_count,
> @@ -2909,12 +2909,12 @@ static const struct ntb_dev_ops intel_ntb_ops = {
> };
>
> static const struct ntb_dev_ops intel_ntb3_ops = {
> - .mw_count = intel_ntb_mw_count,
> - .mw_get_range = intel_ntb_mw_get_range,
> - .mw_set_trans = intel_ntb3_mw_set_trans,
> .link_is_up = intel_ntb_link_is_up,
> .link_enable = intel_ntb3_link_enable,
> .link_disable = intel_ntb_link_disable,
> + .mw_count = intel_ntb_mw_count,
> + .mw_get_range = intel_ntb_mw_get_range,
> + .mw_set_trans = intel_ntb3_mw_set_trans,
> .db_valid_mask = intel_ntb_db_valid_mask,
> .db_vector_count = intel_ntb_db_vector_count,
> .db_vector_mask = intel_ntb_db_vector_mask,
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 6f47562..5d1f260 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -179,13 +179,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops
> *ops)
>
> /**
> * struct ntb_ctx_ops - ntb device operations
> + * @link_is_up: See ntb_link_is_up().
> + * @link_enable: See ntb_link_enable().
> + * @link_disable: See ntb_link_disable().
> * @mw_count: See ntb_mw_count().
> * @mw_get_range: See ntb_mw_get_range().
> * @mw_set_trans: See ntb_mw_set_trans().
> * @mw_clear_trans: See ntb_mw_clear_trans().
> - * @link_is_up: See ntb_link_is_up().
> - * @link_enable: See ntb_link_enable().
> - * @link_disable: See ntb_link_disable().
> * @db_is_unsafe: See ntb_db_is_unsafe().
> * @db_valid_mask: See ntb_db_valid_mask().
> * @db_vector_count: See ntb_db_vector_count().
> @@ -212,6 +212,12 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_write: See ntb_peer_spad_write().
> */
> struct ntb_dev_ops {
> + int (*link_is_up)(struct ntb_dev *ntb,
> + enum ntb_speed *speed, enum ntb_width *width);
> + int (*link_enable)(struct ntb_dev *ntb,
> + enum ntb_speed max_speed, enum ntb_width max_width);
> + int (*link_disable)(struct ntb_dev *ntb);
> +
> int (*mw_count)(struct ntb_dev *ntb);
> int (*mw_get_range)(struct ntb_dev *ntb, int idx,
> phys_addr_t *base, resource_size_t *size,
> @@ -220,12 +226,6 @@ struct ntb_dev_ops {
> dma_addr_t addr, resource_size_t size);
> int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
>
> - int (*link_is_up)(struct ntb_dev *ntb,
> - enum ntb_speed *speed, enum ntb_width *width);
> - int (*link_enable)(struct ntb_dev *ntb,
> - enum ntb_speed max_speed, enum ntb_width max_width);
> - int (*link_disable)(struct ntb_dev *ntb);
> -
> int (*db_is_unsafe)(struct ntb_dev *ntb);
> u64 (*db_valid_mask)(struct ntb_dev *ntb);
> int (*db_vector_count)(struct ntb_dev *ntb);
> @@ -265,13 +265,14 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> {
> /* commented callbacks are not required: */
> return
> + ops->link_is_up &&
> + ops->link_enable &&
> + ops->link_disable &&
> ops->mw_count &&
> ops->mw_get_range &&
> ops->mw_set_trans &&
> /* ops->mw_clear_trans && */
> - ops->link_is_up &&
> - ops->link_enable &&
> - ops->link_disable &&
> +
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
>
> @@ -441,6 +442,62 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_link_is_up() - get the current ntb link state
> + * @ntb: NTB device context.
> + * @speed: OUT - The link speed expressed as PCIe generation number.
> + * @width: OUT - The link width expressed as the number of PCIe lanes.
> + *
> + * Get the current state of the ntb link. It is recommended to query the link
> + * state once after every link event. It is safe to query the link state in
> + * the context of the link event callback.
> + *
> + * Return: One if the link is up, zero if the link is down, otherwise a
> + * negative value indicating the error number.
> + */
> +static inline int ntb_link_is_up(struct ntb_dev *ntb,
> + enum ntb_speed *speed, enum ntb_width *width)
> +{
> + return ntb->ops->link_is_up(ntb, speed, width);
> +}
> +
> +/**
> + * ntb_link_enable() - enable the link on the secondary side of the ntb
> + * @ntb: NTB device context.
> + * @max_speed: The maximum link speed expressed as PCIe generation number.
> + * @max_width: The maximum link width expressed as the number of PCIe lanes.
> + *
> + * Enable the link on the secondary side of the ntb. This can only be done
> + * from the primary side of the ntb in primary or b2b topology. The ntb device
> + * should train the link to its maximum speed and width, or the requested speed
> + * and width, whichever is smaller, if supported.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_link_enable(struct ntb_dev *ntb,
> + enum ntb_speed max_speed,
> + enum ntb_width max_width)
> +{
> + return ntb->ops->link_enable(ntb, max_speed, max_width);
> +}
> +
> +/**
> + * ntb_link_disable() - disable the link on the secondary side of the ntb
> + * @ntb: NTB device context.
> + *
> + * Disable the link on the secondary side of the ntb. This can only be
> + * done from the primary side of the ntb in primary or b2b topology. The ntb
> + * device should disable the link. Returning from this call must indicate that
> + * a barrier has passed, though with no more writes may pass in either
> + * direction across the link, except if this call returns an error number.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_link_disable(struct ntb_dev *ntb)
> +{
> + return ntb->ops->link_disable(ntb);
> +}
> +
> +/**
> * ntb_mw_count() - get the number of memory windows
> * @ntb: NTB device context.
> *
> @@ -517,62 +574,6 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
> }
>
> /**
> - * ntb_link_is_up() - get the current ntb link state
> - * @ntb: NTB device context.
> - * @speed: OUT - The link speed expressed as PCIe generation number.
> - * @width: OUT - The link width expressed as the number of PCIe lanes.
> - *
> - * Get the current state of the ntb link. It is recommended to query the link
> - * state once after every link event. It is safe to query the link state in
> - * the context of the link event callback.
> - *
> - * Return: One if the link is up, zero if the link is down, otherwise a
> - * negative value indicating the error number.
> - */
> -static inline int ntb_link_is_up(struct ntb_dev *ntb,
> - enum ntb_speed *speed, enum ntb_width *width)
> -{
> - return ntb->ops->link_is_up(ntb, speed, width);
> -}
> -
> -/**
> - * ntb_link_enable() - enable the link on the secondary side of the ntb
> - * @ntb: NTB device context.
> - * @max_speed: The maximum link speed expressed as PCIe generation number.
> - * @max_width: The maximum link width expressed as the number of PCIe lanes.
> - *
> - * Enable the link on the secondary side of the ntb. This can only be done
> - * from the primary side of the ntb in primary or b2b topology. The ntb device
> - * should train the link to its maximum speed and width, or the requested speed
> - * and width, whichever is smaller, if supported.
> - *
> - * Return: Zero on success, otherwise an error number.
> - */
> -static inline int ntb_link_enable(struct ntb_dev *ntb,
> - enum ntb_speed max_speed,
> - enum ntb_width max_width)
> -{
> - return ntb->ops->link_enable(ntb, max_speed, max_width);
> -}
> -
> -/**
> - * ntb_link_disable() - disable the link on the secondary side of the ntb
> - * @ntb: NTB device context.
> - *
> - * Disable the link on the secondary side of the ntb. This can only be
> - * done from the primary side of the ntb in primary or b2b topology. The ntb
> - * device should disable the link. Returning from this call must indicate that
> - * a barrier has passed, though with no more writes may pass in either
> - * direction across the link, except if this call returns an error number.
> - *
> - * Return: Zero on success, otherwise an error number.
> - */
> -static inline int ntb_link_disable(struct ntb_dev *ntb)
> -{
> - return ntb->ops->link_disable(ntb);
> -}
> -
> -/**
> * ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
> * @ntb: NTB device context.
> *
> --
> 2.6.6


2016-12-13 04:12:29

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 2/9] NTB: Add indexed ports NTB API

From: Serge Semin
> There are some NTB hardware, which can combine more than just two domains
> over NTB. For instance, some IDT PCIe-switches can have NTB-functions
> activated on more than two-ports. The different domains are distinguished
> by ports they are connected to. So the new port-related methods are added to
> the NTB API:
> ntb_port_number() - return local port
> ntb_peer_port_count() - return number of peers local port can connect to
> ntb_peer_port_number(pdix) - return port number by it index
> ntb_peer_port_idx(port) - return port index by it number
>
> Current test-drivers aren't changed much. They still support two-ports devices
> for the time being while multi-ports hardware drivers aren't added.
>

The port methods are the same for PRI/SEC drivers. Rather than duplicating the code, multiport could be made optional in the api, and default implementations provided by ntb common code.

Some comments below.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> drivers/ntb/hw/amd/ntb_hw_amd.c | 47 ++++++++++++++++++++++++
> drivers/ntb/hw/amd/ntb_hw_amd.h | 9 +++++
> drivers/ntb/hw/intel/ntb_hw_intel.c | 52 ++++++++++++++++++++++++++-
> drivers/ntb/hw/intel/ntb_hw_intel.h | 9 +++++
> drivers/ntb/ntb_transport.c | 6 ++++
> drivers/ntb/test/ntb_perf.c | 4 +++
> drivers/ntb/test/ntb_pingpong.c | 6 ++++
> drivers/ntb/test/ntb_tool.c | 5 +++
> include/linux/ntb.h | 71 +++++++++++++++++++++++++++++++++++++
> 9 files changed, 208 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
> index 6704327..0b767ef 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.c
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
> @@ -71,6 +71,49 @@ MODULE_AUTHOR("AMD Inc.");
> static const struct file_operations amd_ntb_debugfs_info;
> static struct dentry *debugfs_dir;
>
> +static int amd_ntb_port_number(struct ntb_dev *ntb)
> +{
> + switch (ntb->topo) {
> + case NTB_TOPO_PRI:
> + case NTB_TOPO_B2B_USD:
> + return NTB_PORT_PRI_USD;
> + case NTB_TOPO_SEC:
> + case NTB_TOPO_B2B_DSD:
> + return NTB_PORT_SEC_DSD;
> + default:
> + break;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int amd_ntb_peer_port_count(struct ntb_dev *ntb)
> +{
> + return NTB_PEER_CNT;
> +}
> +
> +static int amd_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
> +{
> + int local_port = amd_ntb_port_number(ntb);
> +
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;

pidx may be negative.

> +
> + return (local_port == NTB_PORT_PRI_USD ?
> + NTB_PORT_SEC_DSD : NTB_PORT_PRI_USD);

local_port may be -EINVAL.

It may be simpler to have the same switch statement here as in amd_ntb_port_number(), with the return statements swapped.

> +}
> +
> +static int amd_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> +{
> + int local_port = amd_ntb_port_number(ntb);
> +
> + if ((local_port == NTB_PORT_PRI_USD && port != NTB_PORT_SEC_DSD) ||
> + (local_port == NTB_PORT_SEC_DSD && port != NTB_PORT_PRI_USD))
> + return -EINVAL;
> +

How about:

peer_port = amd_ntb_peer_port_number(ntb, 0);

if (peer_port == -EINVAL || port != peer_port)
return -EINVAL;

return 0;

> + return 0;
> +}
> +
> static int amd_link_is_up(struct amd_ntb_dev *ndev)
> {
> if (!ndev->peer_sta)
> @@ -431,6 +474,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
> }
>
> static const struct ntb_dev_ops amd_ntb_ops = {
> + .port_number = amd_ntb_port_number,
> + .peer_port_count = amd_ntb_peer_port_count,
> + .peer_port_number = amd_ntb_peer_port_number,
> + .peer_port_idx = amd_ntb_peer_port_idx,
> .link_is_up = amd_ntb_link_is_up,
> .link_enable = amd_ntb_link_enable,
> .link_disable = amd_ntb_link_disable,
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h
> index 2eac3cd..1aeb08f 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.h
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.h
> @@ -62,6 +62,10 @@
> #define NTB_LNK_STA_SPEED(x) (((x) & NTB_LNK_STA_SPEED_MASK) >> 16)
> #define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 20)
>
> +/* port related constants */
> +#define NTB_PEER_CNT (1)
> +#define NTB_PIDX_MAX (0)

Just NTB_PEER_CNT is sufficient. Anything that checks if (pidx > NTB_PIDX_MAX) could check if (pidx >= NTB_PEER_CNT).

> +
> #ifndef read64
> #ifdef readq
> #define read64 readq
> @@ -91,6 +95,11 @@ static inline void _write64(u64 val, void __iomem *mmio)
> #endif
> #endif
>
> +enum amd_ntb_port {
> + NTB_PORT_PRI_USD,
> + NTB_PORT_SEC_DSD
> +};

This could be part of ntb.h, since it will likely be the same for any of the PRI/SEC variety of NTB devices. Making it a part of the api will encourage other PRI/SEC drivers to assign port numbers the same way using these values. Or, drivers may be made consistent by sharing common code.

> +
> enum {
> /* AMD NTB Capability */
> AMD_MW_CNT = 3,
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index 68d9908..7e44dc3 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -1035,6 +1035,49 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
> debugfs_remove_recursive(ndev->debugfs_dir);
> }

Apply same comments above to Intel driver.

>
> +static int intel_ntb_port_number(struct ntb_dev *ntb)
> +{
> + switch (ntb->topo) {
> + case NTB_TOPO_PRI:
> + case NTB_TOPO_B2B_USD:
> + return NTB_PORT_PRI_USD;
> + case NTB_TOPO_SEC:
> + case NTB_TOPO_B2B_DSD:
> + return NTB_PORT_SEC_DSD;
> + default:
> + break;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int intel_ntb_peer_port_count(struct ntb_dev *ntb)
> +{
> + return NTB_PEER_CNT;
> +}
> +
> +static int intel_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
> +{
> + int local_port = intel_ntb_port_number(ntb);
> +
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;
> +
> + return (local_port == NTB_PORT_PRI_USD ?
> + NTB_PORT_SEC_DSD : NTB_PORT_PRI_USD);
> +}
> +
> +static int intel_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> +{
> + int local_port = intel_ntb_port_number(ntb);
> +
> + if ((local_port == NTB_PORT_PRI_USD && port != NTB_PORT_SEC_DSD) ||
> + (local_port == NTB_PORT_SEC_DSD && port != NTB_PORT_PRI_USD))
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> static int intel_ntb_link_is_up(struct ntb_dev *ntb,
> enum ntb_speed *speed,
> enum ntb_width *width)
> @@ -1775,7 +1818,6 @@ static int skx_init_ntb(struct intel_ntb_dev *ndev)
> {
> int rc;
>
> -
> ndev->mw_count = XEON_MW_COUNT;
> ndev->spad_count = SKX_SPAD_COUNT;
> ndev->db_count = SKX_DB_COUNT;
> @@ -2883,6 +2925,10 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {
>
> /* operations for primary side of local ntb */
> static const struct ntb_dev_ops intel_ntb_ops = {
> + .port_number = intel_ntb_port_number,
> + .peer_port_count = intel_ntb_peer_port_count,
> + .peer_port_number = intel_ntb_peer_port_number,
> + .peer_port_idx = intel_ntb_peer_port_idx,
> .link_is_up = intel_ntb_link_is_up,
> .link_enable = intel_ntb_link_enable,
> .link_disable = intel_ntb_link_disable,
> @@ -2909,6 +2955,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
> };
>
> static const struct ntb_dev_ops intel_ntb3_ops = {
> + .port_number = intel_ntb_port_number,
> + .peer_port_count = intel_ntb_peer_port_count,
> + .peer_port_number = intel_ntb_peer_port_number,
> + .peer_port_idx = intel_ntb_peer_port_idx,
> .link_is_up = intel_ntb_link_is_up,
> .link_enable = intel_ntb3_link_enable,
> .link_disable = intel_ntb_link_disable,
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
> index 6e8c182..f12c960 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.h
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
> @@ -295,6 +295,15 @@
> #define NTB_BAR_MASK_64 ~(0xfull)
> #define NTB_BAR_MASK_32 ~(0xfu)
>
> +/* port related constants */
> +#define NTB_PEER_CNT (1)
> +#define NTB_PIDX_MAX (0)
> +
> +enum intel_ntb_port {
> + NTB_PORT_PRI_USD,
> + NTB_PORT_SEC_DSD
> +};
> +
> struct intel_ntb_dev;
>
> struct intel_ntb_reg {
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 4eb8adb..37d428d 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -94,6 +94,9 @@ MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");
>
> static struct dentry *nt_debugfs_dir;
>
> +/* Only two-ports NTB devices are supported */
> +#define PIDX 0
> +
> struct ntb_queue_entry {
> /* ntb_queue list reference */
> struct list_head entry;
> @@ -1083,6 +1086,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct
> ntb_dev *ndev)
> dev_dbg(&ndev->dev,
> "scratchpad is unsafe, proceed anyway...\n");
>
> + if (ntb_peer_port_count(ndev) != 1)
> + dev_warn(&ndev->dev, "Multi-port NTB devices unsupported\n");
> +
> node = dev_to_node(&ndev->dev);
>
> nt = kzalloc_node(sizeof(*nt), GFP_KERNEL, node);
> diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
> index e75d4fd..481827a 100644
> --- a/drivers/ntb/test/ntb_perf.c
> +++ b/drivers/ntb/test/ntb_perf.c
> @@ -76,6 +76,7 @@
> #define DMA_RETRIES 20
> #define SZ_4G (1ULL << 32)
> #define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */
> +#define PIDX 0
>
> MODULE_LICENSE(DRIVER_LICENSE);
> MODULE_VERSION(DRIVER_VERSION);
> @@ -764,6 +765,9 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
> return -EIO;
> }
>
> + if (ntb_peer_port_count(ntb) != 1)
> + dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
> +
> node = dev_to_node(&pdev->dev);
>
> perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node);
> diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
> index 4358611..6dd7582 100644
> --- a/drivers/ntb/test/ntb_pingpong.c
> +++ b/drivers/ntb/test/ntb_pingpong.c
> @@ -90,6 +90,9 @@ static unsigned long db_init = 0x7;
> module_param(db_init, ulong, 0644);
> MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");
>
> +/* Only two-ports NTB devices are supported */
> +#define PIDX 0
> +
> struct pp_ctx {
> struct ntb_dev *ntb;
> u64 db_bits;
> @@ -230,6 +233,9 @@ static int pp_probe(struct ntb_client *client,
> }
> }
>
> + if (ntb_peer_port_count(ntb) != 1)
> + dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
> +
> pp = kmalloc(sizeof(*pp), GFP_KERNEL);
> if (!pp) {
> rc = -ENOMEM;
> diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
> index 61bf2ef..85b6417 100644
> --- a/drivers/ntb/test/ntb_tool.c
> +++ b/drivers/ntb/test/ntb_tool.c
> @@ -120,6 +120,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
> MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
>
> #define MAX_MWS 16
> +/* Only two-ports devices are supported */
> +#define PIDX 0
>
> static struct dentry *tool_dbgfs;
>
> @@ -919,6 +921,9 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> if (ntb_spad_is_unsafe(ntb))
> dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
>
> + if (ntb_peer_port_count(ntb) != 1)
> + dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
> +
> tc = kzalloc(sizeof(*tc), GFP_KERNEL);
> if (!tc) {
> rc = -ENOMEM;
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 5d1f260..3216689 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -179,6 +179,10 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
>
> /**
> * struct ntb_ctx_ops - ntb device operations
> + * @port_number: See ntb_port_number().
> + * @peer_port_count: See ntb_peer_port_count().
> + * @peer_port_number: See ntb_peer_port_number().
> + * @peer_port_idx: See ntb_peer_port_idx().
> * @link_is_up: See ntb_link_is_up().
> * @link_enable: See ntb_link_enable().
> * @link_disable: See ntb_link_disable().
> @@ -212,6 +216,11 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_write: See ntb_peer_spad_write().
> */
> struct ntb_dev_ops {
> + int (*port_number)(struct ntb_dev *ntb);
> + int (*peer_port_count)(struct ntb_dev *ntb);
> + int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
> + int (*peer_port_idx)(struct ntb_dev *ntb, int port);
> +
> int (*link_is_up)(struct ntb_dev *ntb,
> enum ntb_speed *speed, enum ntb_width *width);
> int (*link_enable)(struct ntb_dev *ntb,
> @@ -265,6 +274,10 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> {
> /* commented callbacks are not required: */
> return
> + ops->port_number &&
> + ops->peer_port_count &&
> + ops->peer_port_number &&
> + ops->peer_port_idx &&

If these are made optional, then:

!ops->peer_port_count == !ops->port_number &&
!ops->peer_port_number == !ops->port_number &&
!ops->peer_port_idx == !ops->port_number &&

> ops->link_is_up &&
> ops->link_enable &&
> ops->link_disable &&
> @@ -442,6 +455,64 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_port_number() - get the local port number
> + * @ntb: NTB device context.
> + *
> + * Hardware must support at least simple two-ports ntb connection
> + *
> + * Return: the local port number
> + */
> +static inline int ntb_port_number(struct ntb_dev *ntb)
> +{

If these are made optional, then:

if (!ntb->ops->port_number)
return ntb_default_port_number(ntb);

> + return ntb->ops->port_number(ntb);
> +}
> +
> +/**
> + * ntb_peer_port_count() - get the number of peer device ports
> + * @ntb: NTB device context.
> + *
> + * Hardware may support an access to memory of several remote domains
> + * over multi-port NTB devices. This method returns the number of peers,
> + * local device can have shared memory with.
> + *
> + * Return: the number of peer ports
> + */
> +static inline int ntb_peer_port_count(struct ntb_dev *ntb)
> +{
> + return ntb->ops->peer_port_count(ntb);
> +}
> +
> +/**
> + * ntb_peer_port_number() - get the peer port by given index
> + * @ntb: NTB device context.
> + * @pidx: Peer port index.
> + *
> + * Peer ports are continuously enumerated by NTB API logic, so this methods
> + * lets to retrieve port real number by its index.
> + *
> + * Return: the peer device port or negative value indicating an error
> + */
> +static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
> +{
> + return ntb->ops->peer_port_number(ntb, pidx);
> +}
> +
> +/**
> + * ntb_peer_port_idx() - get the peer device port index by given port number
> + * @ntb: NTB device context.
> + * @port: Peer port number.
> + *
> + * Inverse operation of ntb_peer_port_number(), so one can get port index
> + * by specified port number.
> + *
> + * Return: the peer port index or negative value indicating an error
> + */
> +static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> +{
> + return ntb->ops->peer_port_idx(ntb, port);
> +}
> +
> +/**
> * ntb_link_is_up() - get the current ntb link state
> * @ntb: NTB device context.
> * @speed: OUT - The link speed expressed as PCIe generation number.
> --
> 2.6.6


2016-12-13 04:12:35

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 3/9] NTB: Alter link-state API to support multi-port devices

From: Serge Semin
> Multi-port devices permit the NTB connections between multiple domains,
> so a local device can have NTB link being up with one peer and being
> down with another. NTB link-state API is appropriately altered to return
> a bitfield of the link-states between the local device and possible peers.
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

>
> ---
> drivers/ntb/hw/amd/ntb_hw_amd.c | 2 +-
> drivers/ntb/hw/intel/ntb_hw_intel.c | 2 +-
> include/linux/ntb.h | 31 ++++++++++++++++---------------
> 3 files changed, 18 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
> index 0b767ef..b6a4291 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.c
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
> @@ -133,7 +133,7 @@ static int amd_link_is_up(struct amd_ntb_dev *ndev)
> return 0;
> }
>
> -static int amd_ntb_link_is_up(struct ntb_dev *ntb,
> +static u64 amd_ntb_link_is_up(struct ntb_dev *ntb,
> enum ntb_speed *speed,
> enum ntb_width *width)
> {
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index 7e44dc3..f37b6fb 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -1078,7 +1078,7 @@ static int intel_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> return 0;
> }
>
> -static int intel_ntb_link_is_up(struct ntb_dev *ntb,
> +static u64 intel_ntb_link_is_up(struct ntb_dev *ntb,
> enum ntb_speed *speed,
> enum ntb_width *width)
> {
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 3216689..47ec611 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -221,7 +221,7 @@ struct ntb_dev_ops {
> int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
> int (*peer_port_idx)(struct ntb_dev *ntb, int port);
>
> - int (*link_is_up)(struct ntb_dev *ntb,
> + u64 (*link_is_up)(struct ntb_dev *ntb,
> enum ntb_speed *speed, enum ntb_width *width);
> int (*link_enable)(struct ntb_dev *ntb,
> enum ntb_speed max_speed, enum ntb_width max_width);
> @@ -522,25 +522,26 @@ static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> * state once after every link event. It is safe to query the link state in
> * the context of the link event callback.
> *
> - * Return: One if the link is up, zero if the link is down, otherwise a
> - * negative value indicating the error number.
> + * Return: bitfield of indexed ports link state: bit is set/cleared if the
> + * link is up/down respectively.
> */
> -static inline int ntb_link_is_up(struct ntb_dev *ntb,
> +static inline u64 ntb_link_is_up(struct ntb_dev *ntb,
> enum ntb_speed *speed, enum ntb_width *width)
> {
> return ntb->ops->link_is_up(ntb, speed, width);
> }
>
> /**
> - * ntb_link_enable() - enable the link on the secondary side of the ntb
> + * ntb_link_enable() - enable the local port ntb connection
> * @ntb: NTB device context.
> * @max_speed: The maximum link speed expressed as PCIe generation number.
> * @max_width: The maximum link width expressed as the number of PCIe lanes.
> *
> - * Enable the link on the secondary side of the ntb. This can only be done
> - * from the primary side of the ntb in primary or b2b topology. The ntb device
> - * should train the link to its maximum speed and width, or the requested speed
> - * and width, whichever is smaller, if supported.
> + * Enable the NTB/PCIe link on the local or remote (for bridge-to-bridge
> + * topology) side of the bridge. If it's supported the ntb device should train
> + * the link to its maximum speed and width, or the requested speed and width,
> + * whichever is smaller. Some hardware doesn't support PCIe link training, so
> + * the last two arguments will be ignored then.
> *
> * Return: Zero on success, otherwise an error number.
> */
> @@ -552,14 +553,14 @@ static inline int ntb_link_enable(struct ntb_dev *ntb,
> }
>
> /**
> - * ntb_link_disable() - disable the link on the secondary side of the ntb
> + * ntb_link_disable() - disable the local port ntb connection
> * @ntb: NTB device context.
> *
> - * Disable the link on the secondary side of the ntb. This can only be
> - * done from the primary side of the ntb in primary or b2b topology. The ntb
> - * device should disable the link. Returning from this call must indicate that
> - * a barrier has passed, though with no more writes may pass in either
> - * direction across the link, except if this call returns an error number.
> + * Disable the link on the local or remote (for b2b topology) of the ntb.
> + * The ntb device should disable the link. Returning from this call must
> + * indicate that a barrier has passed, though with no more writes may pass in
> + * either direction across the link, except if this call returns an error
> + * number.
> *
> * Return: Zero on success, otherwise an error number.
> */
> --
> 2.6.6
>
> --
> 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-
> [email protected].
> To post to this group, send email to [email protected].
> To view this discussion on the web visit https://groups.google.com/d/msgid/linux-
> ntb/1481576902-21091-4-git-send-email-fancer.lancer%40gmail.com.
> For more options, visit https://groups.google.com/d/optout.

2016-12-13 04:12:53

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 4/9] NTB: Alter MW API to support multi-ports devices

From: Serge Semin
> Multi-port NTB devices permit to share a memory between all accessible peers.
> Memory Windows API is altered to correspondingly initialize and map memory
> windows for such devices:
> ntb_mw_count(pidx); - number of inbound memory windows, which can be allocated
> for shared buffer with specified peer device.
> ntb_mw_get_align(pidx, widx); - get alignment and size restrition parameters
> to properly allocate inbound memory region.
> ntb_peer_mw_count(); - get number of outbound memory windows.
> ntb_peer_mw_get_addr(widx); - get mapping address of an outbound memory window
>
> If hardware supports inbound translation configured on the local ntb port:
> ntb_mw_set_trans(pidx, widx); - set translation address of allocated inbound
> memory window so a peer device could access it.
> ntb_mw_clear_trans(pidx, widx); - clear the translation address of an inbound
> memory window.
>
> If hadrware supports outbound translation configured on the peer ntb port:

s/hadrware/hardware/

> ntb_peer_mw_set_trans(pidx, widx); - set translation address of a memory
> window retrieved from a peer device
> ntb_peer_mw_clear_trans(pidx, widx); - clear the translation address of an
> outbound memory window
>
> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> drivers/ntb/hw/amd/ntb_hw_amd.c | 68 +++++++++---
> drivers/ntb/hw/amd/ntb_hw_amd.h | 2 +
> drivers/ntb/hw/intel/ntb_hw_intel.c | 90 ++++++++++++----
> drivers/ntb/hw/intel/ntb_hw_intel.h | 2 +
> drivers/ntb/ntb.c | 2 +
> drivers/ntb/ntb_transport.c | 21 +++-
> drivers/ntb/test/ntb_perf.c | 17 ++-
> drivers/ntb/test/ntb_tool.c | 43 +++++---
> include/linux/ntb.h | 208 ++++++++++++++++++++++++++++--------
> 9 files changed, 346 insertions(+), 107 deletions(-)
>
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
> index b6a4291..74fe9b8 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.c
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -13,6 +14,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> @@ -213,40 +215,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
> return 1 << idx;
> }
>
> -static int amd_ntb_mw_count(struct ntb_dev *ntb)
> +static int amd_ntb_mw_count(struct ntb_dev *ntb, int pidx)
> {
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;

pidx may be negative. This should be if (pidx != 0) with some named constant for zero, or just if (pidx).

Similarly apply this comment below.

> +
> return ntb_ndev(ntb)->mw_count;
> }
>
> -static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base,
> - resource_size_t *size,
> - resource_size_t *align,
> - resource_size_t *align_size)
> +static int amd_ntb_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 amd_ntb_dev *ndev = ntb_ndev(ntb);
> int bar;
>
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;
> +
> bar = ndev_mw_to_bar(ndev, idx);
> if (bar < 0)
> return bar;
>
> - if (base)
> - *base = pci_resource_start(ndev->ntb.pdev, bar);
> -
> - if (size)
> - *size = pci_resource_len(ndev->ntb.pdev, bar);
> + if (addr_align)
> + *addr_align = SZ_4K;
>
> - if (align)
> - *align = SZ_4K;
> + if (size_align)
> + *size_align = 1;
>
> - if (align_size)
> - *align_size = 1;
> + if (size_max)
> + *size_max = pci_resource_len(ndev->ntb.pdev, bar);
>
> return 0;
> }
>
> -static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
> dma_addr_t addr, resource_size_t size)
> {
> struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> @@ -256,6 +260,9 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> u64 base_addr, limit, reg_val;
> int bar;
>
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;
> +
> bar = ndev_mw_to_bar(ndev, idx);
> if (bar < 0)
> return bar;
> @@ -328,6 +335,31 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> return 0;
> }
>
> +static int amd_ntb_peer_mw_count(struct ntb_dev *ntb)
> +{
> + /* The same as for inbound MWs */
> + return ntb_ndev(ntb)->mw_count;
> +}
> +
> +static int amd_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
> + phys_addr_t *base, resource_size_t *size)
> +{
> + struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> + int bar;
> +
> + bar = ndev_mw_to_bar(ndev, idx);
> + if (bar < 0)
> + return bar;
> +
> + if (base)
> + *base = pci_resource_start(ndev->ntb.pdev, bar);
> +
> + if (size)
> + *size = pci_resource_len(ndev->ntb.pdev, bar);
> +
> + return 0;
> +}
> +
> static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
> {
> return ntb_ndev(ntb)->db_valid_mask;
> @@ -482,8 +514,10 @@ static const struct ntb_dev_ops amd_ntb_ops = {
> .link_enable = amd_ntb_link_enable,
> .link_disable = amd_ntb_link_disable,
> .mw_count = amd_ntb_mw_count,
> - .mw_get_range = amd_ntb_mw_get_range,
> + .mw_get_align = amd_ntb_mw_get_align,
> .mw_set_trans = amd_ntb_mw_set_trans,
> + .peer_mw_count = amd_ntb_peer_mw_count,
> + .peer_mw_get_addr = amd_ntb_peer_mw_get_addr,
> .db_valid_mask = amd_ntb_db_valid_mask,
> .db_vector_count = amd_ntb_db_vector_count,
> .db_vector_mask = amd_ntb_db_vector_mask,
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h
> index 1aeb08f..3296c98 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.h
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.h
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -13,6 +14,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index f37b6fb..5a57d9e 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -6,6 +6,7 @@
> *
> * Copyright(c) 2012 Intel Corporation. All rights reserved.
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -15,6 +16,7 @@
> *
> * Copyright(c) 2012 Intel Corporation. All rights reserved.
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> @@ -1156,20 +1158,26 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
> return 0;
> }
>
> -static int intel_ntb_mw_count(struct ntb_dev *ntb)
> +static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
> {
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;
> +
> return ntb_ndev(ntb)->mw_count;
> }
>
> -static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base,
> - resource_size_t *size,
> - resource_size_t *align,
> - resource_size_t *align_size)
> +static int intel_ntb_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 intel_ntb_dev *ndev = ntb_ndev(ntb);
> + resource_size_t bar_size, mw_size;
> int bar;
>
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;
> +
> if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> idx += 1;
>
> @@ -1177,24 +1185,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> if (bar < 0)
> return bar;
>
> - if (base)
> - *base = pci_resource_start(ndev->ntb.pdev, bar) +
> - (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> + bar_size = pci_resource_len(ndev->ntb.pdev, bar);
>
> - if (size)
> - *size = pci_resource_len(ndev->ntb.pdev, bar) -
> - (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> + if (idx == ndev->b2b_idx)
> + mw_size = bar_size - ndev->b2b_off;
> + else
> + mw_size = bar_size;
> +
> + if (addr_align)
> + *addr_align = pci_resource_len(ndev->ntb.pdev, bar);
>
> - if (align)
> - *align = pci_resource_len(ndev->ntb.pdev, bar);
> + if (size_align)
> + *size_align = 1;
>
> - if (align_size)
> - *align_size = 1;
> + if (size_max)
> + *size_max = mw_size;
>
> return 0;
> }
>
> -static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
> dma_addr_t addr, resource_size_t size)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> @@ -1204,6 +1214,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> u64 base, limit, reg_val;
> int bar;
>
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;
> +
> if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> idx += 1;
>
> @@ -1292,6 +1305,36 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> return 0;
> }
>
> +static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
> +{
> + /* Numbers of inbound and outbound memory windows match */
> + return ntb_ndev(ntb)->mw_count;
> +}
> +
> +static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
> + phys_addr_t *base, resource_size_t *size)
> +{
> + struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> + int bar;
> +
> + if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> + idx += 1;
> +
> + bar = ndev_mw_to_bar(ndev, idx);
> + if (bar < 0)
> + return bar;
> +
> + if (base)
> + *base = pci_resource_start(ndev->ntb.pdev, bar) +
> + (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> +
> + if (size)
> + *size = pci_resource_len(ndev->ntb.pdev, bar) -
> + (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> +
> + return 0;
> +}
> +
> static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
> {
> return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
> @@ -1922,7 +1965,7 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb,
>
> return 0;
> }
> -static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
> dma_addr_t addr, resource_size_t size)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> @@ -1932,6 +1975,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
> u64 base, limit, reg_val;
> int bar;
>
> + if (pidx > NTB_PIDX_MAX)
> + return -EINVAL;
> +
> if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> idx += 1;
>
> @@ -2933,8 +2979,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
> .link_enable = intel_ntb_link_enable,
> .link_disable = intel_ntb_link_disable,
> .mw_count = intel_ntb_mw_count,
> - .mw_get_range = intel_ntb_mw_get_range,
> + .mw_get_align = intel_ntb_mw_get_align,
> .mw_set_trans = intel_ntb_mw_set_trans,
> + .peer_mw_count = intel_ntb_peer_mw_count,
> + .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
> .db_is_unsafe = intel_ntb_db_is_unsafe,
> .db_valid_mask = intel_ntb_db_valid_mask,
> .db_vector_count = intel_ntb_db_vector_count,
> @@ -2963,8 +3011,10 @@ static const struct ntb_dev_ops intel_ntb3_ops = {
> .link_enable = intel_ntb3_link_enable,
> .link_disable = intel_ntb_link_disable,
> .mw_count = intel_ntb_mw_count,
> - .mw_get_range = intel_ntb_mw_get_range,
> + .mw_get_align = intel_ntb_mw_get_align,
> .mw_set_trans = intel_ntb3_mw_set_trans,
> + .peer_mw_count = intel_ntb_peer_mw_count,
> + .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
> .db_valid_mask = intel_ntb_db_valid_mask,
> .db_vector_count = intel_ntb_db_vector_count,
> .db_vector_mask = intel_ntb_db_vector_mask,
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
> index f12c960..4fd75a1 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.h
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
> @@ -6,6 +6,7 @@
> *
> * Copyright(c) 2012 Intel Corporation. All rights reserved.
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -15,6 +16,7 @@
> *
> * Copyright(c) 2012 Intel Corporation. All rights reserved.
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
> index 2e25307..f6153af 100644
> --- a/drivers/ntb/ntb.c
> +++ b/drivers/ntb/ntb.c
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -18,6 +19,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 37d428d..cb4f99889 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -685,7 +685,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
> if (!mw->virt_addr)
> return;
>
> - ntb_mw_clear_trans(nt->ndev, num_mw);
> + ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
> dma_free_coherent(&pdev->dev, mw->buff_size,
> mw->virt_addr, mw->dma_addr);
> mw->xlat_size = 0;
> @@ -742,7 +742,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
> }
>
> /* Notify HW the memory location of the receive buffer */
> - rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
> + rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
> + mw->xlat_size);
> if (rc) {
> dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
> ntb_free_mw(nt, num_mw);
> @@ -1072,13 +1073,18 @@ static int ntb_transport_probe(struct ntb_client *self, struct
> ntb_dev *ndev)
> int node;
> int rc, i;
>
> - mw_count = ntb_mw_count(ndev);
> + mw_count = ntb_mw_count(ndev, PIDX);
> if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) {
> dev_err(&ndev->dev, "Not enough scratch pad registers for %s",
> NTB_TRANSPORT_NAME);
> return -EIO;
> }
>
> + if (!ndev->ops->mw_set_trans) {
> + dev_err(&ndev->dev, "Inbound MW based NTB API is required\n");
> + return -EINVAL;
> + }
> +
> if (ntb_db_is_unsafe(ndev))
> dev_dbg(&ndev->dev,
> "doorbell is unsafe, proceed anyway...\n");
> @@ -1109,8 +1115,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct
> ntb_dev *ndev)
> for (i = 0; i < mw_count; i++) {
> mw = &nt->mw_vec[i];
>
> - rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
> - &mw->xlat_align, &mw->xlat_align_size);
> + rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
> + &mw->xlat_align_size, NULL);
> + if (rc)
> + goto err1;
> +
> + rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
> + &mw->phys_size);
> if (rc)
> goto err1;
>
> diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
> index 481827a..3efb5b5 100644
> --- a/drivers/ntb/test/ntb_perf.c
> +++ b/drivers/ntb/test/ntb_perf.c
> @@ -453,7 +453,7 @@ static void perf_free_mw(struct perf_ctx *perf)
> if (!mw->virt_addr)
> return;
>
> - ntb_mw_clear_trans(perf->ntb, 0);
> + ntb_mw_clear_trans(perf->ntb, PIDX, 0);
> dma_free_coherent(&pdev->dev, mw->buf_size,
> mw->virt_addr, mw->dma_addr);
> mw->xlat_size = 0;
> @@ -489,7 +489,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
> mw->buf_size = 0;
> }
>
> - rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
> + rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size);
> if (rc) {
> dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
> perf_free_mw(perf);
> @@ -560,8 +560,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)
>
> mw = &perf->mw;
>
> - rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size,
> - &mw->xlat_align, &mw->xlat_align_size);
> + rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
> + &mw->xlat_align_size, NULL);
> + if (rc)
> + return rc;
> +
> + rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
> if (rc)
> return rc;
>
> @@ -765,6 +769,11 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
> return -EIO;
> }
>
> + if (!ntb->ops->mw_set_trans) {
> + dev_err(&ntb->dev, "Need inbound MW based NTB API\n");
> + return -EINVAL;
> + }
> +
> if (ntb_peer_port_count(ntb) != 1)
> dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
>
> diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
> index 85b6417..7aa6018 100644
> --- a/drivers/ntb/test/ntb_tool.c
> +++ b/drivers/ntb/test/ntb_tool.c
> @@ -119,7 +119,8 @@ MODULE_VERSION(DRIVER_VERSION);
> MODULE_AUTHOR(DRIVER_AUTHOR);
> MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
>
> -#define MAX_MWS 16
> +/* It is rare to have hadrware with greater than six MWs */
> +#define MAX_MWS 6
> /* Only two-ports devices are supported */
> #define PIDX 0
>
> @@ -670,28 +671,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t
> req_size)
> {
> int rc;
> struct tool_mw *mw = &tc->mws[idx];
> - phys_addr_t base;
> - resource_size_t size, align, align_size;
> + resource_size_t size, align_addr, align_size;
> char buf[16];
>
> if (mw->peer)
> return 0;
>
> - rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
> - &align_size);
> + rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
> + &align_size, &size);
> if (rc)
> return rc;
>
> mw->size = min_t(resource_size_t, req_size, size);
> - mw->size = round_up(mw->size, align);
> + mw->size = round_up(mw->size, align_addr);
> mw->size = round_up(mw->size, align_size);
> mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
> &mw->peer_dma, GFP_KERNEL);
>
> - if (!mw->peer)
> + if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
> return -ENOMEM;
>
> - rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
> + rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
> if (rc)
> goto err_free_dma;
>
> @@ -718,7 +718,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx)
> struct tool_mw *mw = &tc->mws[idx];
>
> if (mw->peer) {
> - ntb_mw_clear_trans(tc->ntb, idx);
> + ntb_mw_clear_trans(tc->ntb, PIDX, idx);
> dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
> mw->peer,
> mw->peer_dma);
> @@ -744,8 +744,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
>
> phys_addr_t base;
> resource_size_t mw_size;
> - resource_size_t align;
> + resource_size_t align_addr;
> resource_size_t align_size;
> + resource_size_t max_size;
>
> buf_size = min_t(size_t, size, 512);
>
> @@ -753,8 +754,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
> if (!buf)
> return -ENOMEM;
>
> - ntb_mw_get_range(mw->tc->ntb, mw->idx,
> - &base, &mw_size, &align, &align_size);
> + ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
> + &align_addr, &align_size, &max_size);
> + ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);
>
> off += scnprintf(buf + off, buf_size - off,
> "Peer MW %d Information:\n", mw->idx);
> @@ -769,12 +771,16 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
>
> off += scnprintf(buf + off, buf_size - off,
> "Alignment \t%lld\n",
> - (unsigned long long)align);
> + (unsigned long long)align_addr);
>
> off += scnprintf(buf + off, buf_size - off,
> "Size Alignment \t%lld\n",
> (unsigned long long)align_size);
>
> + off += scnprintf(buf + off, buf_size - off,
> + "Size Max \t%lld\n",
> + (unsigned long long)max_size);
> +
> off += scnprintf(buf + off, buf_size - off,
> "Ready \t%c\n",
> (mw->peer) ? 'Y' : 'N');
> @@ -829,8 +835,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx)
> phys_addr_t base;
> int rc;
>
> - rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
> - NULL, NULL);
> + rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size);
> if (rc)
> return rc;
>
> @@ -915,6 +920,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> int rc;
> int i;
>
> + if (!ntb->ops->mw_set_trans) {
> + dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
> + rc = -EINVAL;
> + goto err_tc;
> + }
> +
> if (ntb_db_is_unsafe(ntb))
> dev_dbg(&ntb->dev, "doorbell is unsafe\n");
>
> @@ -933,7 +944,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> tc->ntb = ntb;
> init_waitqueue_head(&tc->link_wq);
>
> - tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
> + tc->mw_count = min(ntb_mw_count(tc->ntb, PIDX), MAX_MWS);
> for (i = 0; i < tc->mw_count; i++) {
> rc = tool_init_mw(tc, i);
> if (rc)
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 47ec611..fb78663 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -18,6 +19,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> @@ -187,9 +189,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @link_enable: See ntb_link_enable().
> * @link_disable: See ntb_link_disable().
> * @mw_count: See ntb_mw_count().
> - * @mw_get_range: See ntb_mw_get_range().
> + * @mw_get_align: See ntb_mw_get_align().
> * @mw_set_trans: See ntb_mw_set_trans().
> * @mw_clear_trans: See ntb_mw_clear_trans().
> + * @peer_mw_count: See ntb_peer_mw_count().
> + * @peer_mw_get_addr: See ntb_peer_mw_get_addr().
> + * @peer_mw_set_trans: See ntb_peer_mw_set_trans().
> + * @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
> * @db_is_unsafe: See ntb_db_is_unsafe().
> * @db_valid_mask: See ntb_db_valid_mask().
> * @db_vector_count: See ntb_db_vector_count().
> @@ -227,13 +233,20 @@ struct ntb_dev_ops {
> enum ntb_speed max_speed, enum ntb_width max_width);
> int (*link_disable)(struct ntb_dev *ntb);
>
> - int (*mw_count)(struct ntb_dev *ntb);
> - int (*mw_get_range)(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base, resource_size_t *size,
> - resource_size_t *align, resource_size_t *align_size);
> - int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
> + int (*mw_count)(struct ntb_dev *ntb, int pidx);
> + int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
> + resource_size_t *addr_align,
> + resource_size_t *size_align,
> + resource_size_t *size_max);
> + int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
> dma_addr_t addr, resource_size_t size);
> - int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
> + int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
> + int (*peer_mw_count)(struct ntb_dev *ntb);
> + int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
> + phys_addr_t *base, resource_size_t *size);
> + int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
> + u64 addr, resource_size_t size);
> + int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
>
> int (*db_is_unsafe)(struct ntb_dev *ntb);
> u64 (*db_valid_mask)(struct ntb_dev *ntb);
> @@ -282,9 +295,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> ops->link_enable &&
> ops->link_disable &&
> ops->mw_count &&
> - ops->mw_get_range &&
> - ops->mw_set_trans &&
> + ops->mw_get_align &&
> + (ops->mw_set_trans ||
> + ops->peer_mw_set_trans) &&
> /* ops->mw_clear_trans && */
> + ops->peer_mw_count &&
> + ops->peer_mw_get_addr &&
> + /* ops->peer_mw_clear_trans && */
>
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
> @@ -570,79 +587,180 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
> }
>
> /**
> - * ntb_mw_count() - get the number of memory windows
> + * ntb_mw_count() - get the number of inbound memory windows, which could
> + * be created for a specified peer device
> * @ntb: NTB device context.
> + * @pidx: Port index of peer device.
> *
> * Hardware and topology may support a different number of memory windows.
> + * Moreover different peer devices can support different number of memory
> + * windows. Simply speaking this method returns the number of possible inbound
> + * memory windows to share with specified peer device.
> *
> * Return: the number of memory windows.
> */
> -static inline int ntb_mw_count(struct ntb_dev *ntb)
> +static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
> {
> - return ntb->ops->mw_count(ntb);
> + return ntb->ops->mw_count(ntb, pidx);
> }
>
> /**
> - * ntb_mw_get_range() - get the range of a memory window
> + * ntb_mw_get_align() - get the restriction parameters of inbound memory window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> - * @base: OUT - the base address for mapping the memory window
> - * @size: OUT - the size for mapping the memory window
> - * @align: OUT - the base alignment for translating the memory window
> - * @align_size: OUT - the size alignment for translating the memory window
> - *
> - * Get the range of a memory window. NULL may be given for any output
> - * parameter if the value is not needed. The base and size may be used for
> - * mapping the memory window, to access the peer memory. The alignment and
> - * size may be used for translating the memory window, for the peer to access
> - * memory on the local system.
> - *
> - * Return: Zero on success, otherwise an error number.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + * @addr_align: OUT - the base alignment for translating the memory window
> + * @size_align: OUT - the size alignment for translating the memory window
> + * @size_max: OUT - the maximum size of the memory window
> + *
> + * Get the alignments of an inbound memory window with specified index.
> + * NULL may be given for any output parameter if the value is not needed.
> + * The alignment and size parameters may be used for allocation of proper
> + * shared memory.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> */
> -static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base, resource_size_t *size,
> - resource_size_t *align, resource_size_t *align_size)
> +static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
> + resource_size_t *addr_align,
> + resource_size_t *size_align,
> + resource_size_t *size_max)
> {
> - return ntb->ops->mw_get_range(ntb, idx, base, size,
> - align, align_size);
> + return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
> + size_max);
> }
>
> /**
> - * ntb_mw_set_trans() - set the translation of a memory window
> + * ntb_mw_set_trans() - set the translation of an inbound memory window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> - * @addr: The dma address local memory to expose to the peer.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + * @addr: The dma address of local memory to expose to the peer.
> * @size: The size of the local memory to expose to the peer.
> *
> * Set the translation of a memory window. The peer may access local memory
> * through the window starting at the address, up to the size. The address
> - * must be aligned to the alignment specified by ntb_mw_get_range(). The size
> - * must be aligned to the size alignment specified by ntb_mw_get_range().
> + * and size must be aligned in complience with restrictions of
> + * ntb_mw_get_align(). The region size should not exceed the size_max parameter
> + * of that method.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
> dma_addr_t addr, resource_size_t size)
> {
> - return ntb->ops->mw_set_trans(ntb, idx, addr, size);
> + if (!ntb->ops->mw_set_trans)
> + return -EINVAL;

I think this should return zero if not implemented. We should not confuse a portable client driver that sets translation on both sides. A real error setting the translation should be distinct from no translation necessary.

> +
> + return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
> }
>
> /**
> - * ntb_mw_clear_trans() - clear the translation of a memory window
> + * ntb_mw_clear_trans() - clear the translation address of an inbound memory
> + * window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> *
> - * Clear the translation of a memory window. The peer may no longer access
> - * local memory through the window.
> + * Clear the translation of an inbound memory window. The peer may no longer
> + * access local memory through the window.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
> +static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
> {
> if (!ntb->ops->mw_clear_trans)
> - return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
> + return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
> +
> + return ntb->ops->mw_clear_trans(ntb, pidx, widx);
> +}
> +
> +/**
> + * ntb_peer_mw_count() - get the number of outbound memory windows, which could
> + * be mapped to access a shared memory
> + * @ntb: NTB device context.
> + *
> + * Hardware and topology may support a different number of memory windows.
> + * This method returns the number of outbound memory windows supported by
> + * local device.
> + *
> + * Return: the number of memory windows.
> + */
> +static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
> +{
> + return ntb->ops->peer_mw_count(ntb);
> +}
> +
> +/**
> + * ntb_peer_mw_get_addr() - get map address of an outbound memory window
> + * @ntb: NTB device context.
> + * @widx: Memory window index (within ntb_peer_mw_count() return value).
> + * @base: OUT - the base address of mapping region.
> + * @size: OUT - the size of mapping region.
> + *
> + * Get base and size of memory region to map. NULL may be given for any output
> + * parameter if the value is not needed. The base and size may be used for
> + * mapping the memory window, to access the peer memory.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
> + phys_addr_t *base, resource_size_t *size)
> +{
> + return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
> +}
> +
> +/**
> + * ntb_peer_mw_set_trans() - set a translation address of a memory window
> + * retrieved from a peer device
> + * @ntb: NTB device context.
> + * @pidx: Port index of peer device the translation address received from.
> + * @widx: Memory window index.
> + * @addr: The dma address of the shared memory to access.
> + * @size: The size of the shared memory to access.
> + *
> + * Set the translation of an outbound memory window. The local device may
> + * access shared memory allocated by a peer device sent the address.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface, so a translation address can be only set on the side,
> + * where shared memory (inbound memory windows) is allocated.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
> + u64 addr, resource_size_t size)
> +{
> + if (!ntb->ops->peer_mw_set_trans)
> + return -EINVAL;

Maybe return zero. See above.

> +
> + return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
> +}
> +
> +/**
> + * ntb_peer_mw_clear_trans() - clear the translation address of an outbound
> + * memory window
> + * @ntb: NTB device context.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + *
> + * Clear the translation of a outbound memory window. The local device may no
> + * longer access a shared memory through the window.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
> + int widx)
> +{
> + if (!ntb->ops->peer_mw_clear_trans)
> + return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);
>
> - return ntb->ops->mw_clear_trans(ntb, idx);
> + return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
> }
>
> /**
> --
> 2.6.6

2016-12-13 04:13:48

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 5/9] NTB: Alter Scratchpads API to support multi-ports devices

From: Serge Semin
> Even though there is no any real NTB hardware, which would have both more
> than two ports and Scratchpad registers, it is logically correct to have
> Scratchpad API accepting a peer port index as well. Intel/AMD drivers utilize
> Primary and Secondary topology to split Scratchpad between connected root
> devices. Since port-index API introduced, Intel/AMD NTB hadrware drivers can

s/hadrware/hardware/

> use device port to determine which Scratchpad registers actually belong to
> local and peer devices. The same approach can be used if some potential
> hardware in future will be multi-port and have some set of Scratchpads.
> Here are the brief of changes in the API:
> ntb_spad_count() - return number of Scratchpad per each port
> ntb_peer_spad_addr(pidx, sidx) - address of Scratchpad register of the
> peer device with pidx-index
> ntb_peer_spad_read(pidx, sidx) - read specified Scratchpad register of the
> peer with pidx-index
> ntb_peer_spad_write(pidx, sidx) - write data to Scratchpad register of the
> peer with pidx-index
>
> Since there is hardware which doesn't support Scratchpad registers, the
> corresponding API methods are now made optional.

The api change looks good. See the comment to simplify ntb_tool.

> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> drivers/ntb/hw/amd/ntb_hw_amd.c | 14 +++----
> drivers/ntb/hw/intel/ntb_hw_intel.c | 14 +++----
> drivers/ntb/ntb_transport.c | 17 ++++-----
> drivers/ntb/test/ntb_perf.c | 6 +--
> drivers/ntb/test/ntb_pingpong.c | 8 +++-
> drivers/ntb/test/ntb_tool.c | 45 +++++++++++++++++-----
> include/linux/ntb.h | 76 +++++++++++++++++++++++--------------
> 7 files changed, 115 insertions(+), 65 deletions(-)
>
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
> index 74fe9b8..a2596ad 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.c
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
> @@ -476,30 +476,30 @@ static int amd_ntb_spad_write(struct ntb_dev *ntb,
> return 0;
> }
>
> -static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> +static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
> {
> struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> void __iomem *mmio = ndev->self_mmio;
> u32 offset;
>
> - if (idx < 0 || idx >= ndev->spad_count)
> + if (sidx < 0 || sidx >= ndev->spad_count)
> return -EINVAL;
>
> - offset = ndev->peer_spad + (idx << 2);
> + offset = ndev->peer_spad + (sidx << 2);
> return readl(mmio + AMD_SPAD_OFFSET + offset);
> }
>
> -static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
> - int idx, u32 val)
> +static int amd_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
> + int sidx, u32 val)
> {
> struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> void __iomem *mmio = ndev->self_mmio;
> u32 offset;
>
> - if (idx < 0 || idx >= ndev->spad_count)
> + if (sidx < 0 || sidx >= ndev->spad_count)
> return -EINVAL;
>
> - offset = ndev->peer_spad + (idx << 2);
> + offset = ndev->peer_spad + (sidx << 2);
> writel(val, mmio + AMD_SPAD_OFFSET + offset);
>
> return 0;
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index 5a57d9e..471b0ba 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -1452,30 +1452,30 @@ static int intel_ntb_spad_write(struct ntb_dev *ntb,
> ndev->self_reg->spad);
> }
>
> -static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
> +static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
>
> - return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr,
> + return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
> ndev->peer_reg->spad);
> }
>
> -static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> +static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
>
> - return ndev_spad_read(ndev, idx,
> + return ndev_spad_read(ndev, sidx,
> ndev->peer_mmio +
> ndev->peer_reg->spad);
> }
>
> -static int intel_ntb_peer_spad_write(struct ntb_dev *ntb,
> - int idx, u32 val)
> +static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
> + int sidx, u32 val)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
>
> - return ndev_spad_write(ndev, idx, val,
> + return ndev_spad_write(ndev, sidx, val,
> ndev->peer_mmio +
> ndev->peer_reg->spad);
> }
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index cb4f99889..b2475f4 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -875,17 +875,17 @@ static void ntb_transport_link_work(struct work_struct *work)
> size = max_mw_size;
>
> spad = MW0_SZ_HIGH + (i * 2);
> - ntb_peer_spad_write(ndev, spad, upper_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, spad, upper_32_bits(size));
>
> spad = MW0_SZ_LOW + (i * 2);
> - ntb_peer_spad_write(ndev, spad, lower_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, spad, lower_32_bits(size));
> }
>
> - ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count);
> + ntb_peer_spad_write(ndev, PIDX, NUM_MWS, nt->mw_count);
>
> - ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count);
> + ntb_peer_spad_write(ndev, PIDX, NUM_QPS, nt->qp_count);
>
> - ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION);
> + ntb_peer_spad_write(ndev, PIDX, VERSION, NTB_TRANSPORT_VERSION);
>
> /* Query the remote side for its info */
> val = ntb_spad_read(ndev, VERSION);
> @@ -961,10 +961,10 @@ static void ntb_qp_link_work(struct work_struct *work)
>
> val = ntb_spad_read(nt->ndev, QP_LINKS);
>
> - ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num));
> + ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num));
>
> /* query remote spad for qp ready bits */
> - ntb_peer_spad_read(nt->ndev, QP_LINKS);
> + ntb_peer_spad_read(nt->ndev, PIDX, QP_LINKS);
> dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);
>
> /* See if the remote side is up */
> @@ -2141,8 +2141,7 @@ void ntb_transport_link_down(struct ntb_transport_qp *qp)
>
> val = ntb_spad_read(qp->ndev, QP_LINKS);
>
> - ntb_peer_spad_write(qp->ndev, QP_LINKS,
> - val & ~BIT(qp->qp_num));
> + ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val & ~BIT(qp->qp_num));
>
> if (qp->link_is_up)
> ntb_send_link_down(qp);
> diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
> index 3efb5b5..99f1522 100644
> --- a/drivers/ntb/test/ntb_perf.c
> +++ b/drivers/ntb/test/ntb_perf.c
> @@ -516,9 +516,9 @@ static void perf_link_work(struct work_struct *work)
> if (max_mw_size && size > max_mw_size)
> size = max_mw_size;
>
> - ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
> - ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
> - ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
> + ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION);
>
> /* now read what peer wrote */
> val = ntb_spad_read(ndev, VERSION);
> diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
> index 6dd7582..4ee5c14 100644
> --- a/drivers/ntb/test/ntb_pingpong.c
> +++ b/drivers/ntb/test/ntb_pingpong.c
> @@ -138,7 +138,7 @@ static void pp_ping(unsigned long ctx)
> "Ping bits %#llx read %#x write %#x\n",
> db_bits, spad_rd, spad_wr);
>
> - ntb_peer_spad_write(pp->ntb, 0, spad_wr);
> + ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr);
> ntb_peer_db_set(pp->ntb, db_bits);
> ntb_db_clear_mask(pp->ntb, db_mask);
>
> @@ -225,6 +225,12 @@ static int pp_probe(struct ntb_client *client,
> }
> }
>
> + if (ntb_spad_count(ntb) < 1) {
> + dev_dbg(&ntb->dev, "no enough scratchpads\n");
> + rc = -EINVAL;
> + goto err_pp;
> + }
> +
> if (ntb_spad_is_unsafe(ntb)) {
> dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
> if (!unsafe) {
> diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
> index 7aa6018..0f57b2e 100644
> --- a/drivers/ntb/test/ntb_tool.c
> +++ b/drivers/ntb/test/ntb_tool.c
> @@ -264,14 +264,17 @@ static ssize_t tool_dbfn_write(struct tool_ctx *tc,
>
> static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
> size_t size, loff_t *offp,
> - u32 (*spad_read_fn)(struct ntb_dev *, int))
> + u32 (*spad_read_fn)(struct ntb_dev *, int),
> + u32 (*spad_peer_read_fn)(struct ntb_dev *, int,
> + int))
> {
> size_t buf_size;
> char *buf;
> ssize_t pos, rc;
> int i, spad_count;
> + u32 data;
>
> - if (!spad_read_fn)
> + if (!spad_read_fn && !spad_peer_read_fn)
> return -EINVAL;
>
> spad_count = ntb_spad_count(tc->ntb);
> @@ -290,8 +293,12 @@ static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user
> *ubuf,
> pos = 0;
>
> for (i = 0; i < spad_count; ++i) {
> + if (spad_read_fn)
> + data = spad_read_fn(tc->ntb, i);
> + else
> + data = spad_peer_read_fn(tc->ntb, PIDX, i);

As long as we are just supporting pidx zero for now, the changes in ntb_tool can be simplified.

static u32 ntb_tool_peer_spad_read(struct ntb_dev *ntb, int sidx)
{
return ntb_peer_spad_read(ntb, PIDX, sidx);
}

Then, just pass ntb_tool_peer_spad_read in place of tc->ntb->ops.peer_spad_read.

Similar for peer_spad_write.

> pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
> - i, spad_read_fn(tc->ntb, i));
> + i, data);
> }
>
> rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
> @@ -305,7 +312,9 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
> const char __user *ubuf,
> size_t size, loff_t *offp,
> int (*spad_write_fn)(struct ntb_dev *,
> - int, u32))
> + int, u32),
> + int (*spad_peer_write_fn)(struct ntb_dev *,
> + int, int, u32))
> {
> int spad_idx;
> u32 spad_val;
> @@ -313,7 +322,7 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
> int pos, n;
> ssize_t rc;
>
> - if (!spad_write_fn) {
> + if (!spad_write_fn || !spad_peer_write_fn) {
> dev_dbg(&tc->ntb->dev, "no spad write fn\n");
> return -EINVAL;
> }
> @@ -333,7 +342,11 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
> n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
> while (n == 2) {
> buf_ptr += pos;
> - rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
> + if (spad_write_fn)
> + rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
> + else
> + rc = spad_peer_write_fn(tc->ntb, PIDX, spad_idx,
> + spad_val);
> if (rc)
> break;
>
> @@ -446,7 +459,7 @@ static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
> struct tool_ctx *tc = filep->private_data;
>
> return tool_spadfn_read(tc, ubuf, size, offp,
> - tc->ntb->ops->spad_read);
> + tc->ntb->ops->spad_read, NULL);
> }
>
> static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
> @@ -455,7 +468,7 @@ static ssize_t tool_spad_write(struct file *filep, const char __user
> *ubuf,
> struct tool_ctx *tc = filep->private_data;
>
> return tool_spadfn_write(tc, ubuf, size, offp,
> - tc->ntb->ops->spad_write);
> + tc->ntb->ops->spad_write, NULL);
> }
>
> static TOOL_FOPS_RDWR(tool_spad_fops,
> @@ -467,7 +480,7 @@ static ssize_t tool_peer_spad_read(struct file *filep, char __user
> *ubuf,
> {
> struct tool_ctx *tc = filep->private_data;
>
> - return tool_spadfn_read(tc, ubuf, size, offp,
> + return tool_spadfn_read(tc, ubuf, size, offp, NULL,
> tc->ntb->ops->peer_spad_read);
> }
>
> @@ -476,7 +489,7 @@ static ssize_t tool_peer_spad_write(struct file *filep, const char
> __user *ubuf,
> {
> struct tool_ctx *tc = filep->private_data;
>
> - return tool_spadfn_write(tc, ubuf, size, offp,
> + return tool_spadfn_write(tc, ubuf, size, offp, NULL,
> tc->ntb->ops->peer_spad_write);
> }
>
> @@ -935,6 +948,18 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> if (ntb_peer_port_count(ntb) != 1)
> dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
>
> + if (ntb_spad_count(ntb) < 1) {
> + dev_dbg(&ntb->dev, "no enough scratchpads\n");
> + rc = -EINVAL;
> + goto err_tc;
> + }
> +
> + if (!ntb->ops->mw_set_trans) {
> + dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
> + rc = -EINVAL;
> + goto err_tc;
> + }
> +
> tc = kzalloc(sizeof(*tc), GFP_KERNEL);
> if (!tc) {
> rc = -ENOMEM;
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index fb78663..a6bf15d 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -274,13 +274,14 @@ struct ntb_dev_ops {
> int (*spad_is_unsafe)(struct ntb_dev *ntb);
> int (*spad_count)(struct ntb_dev *ntb);
>
> - u32 (*spad_read)(struct ntb_dev *ntb, int idx);
> - int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
> + u32 (*spad_read)(struct ntb_dev *ntb, int sidx);
> + int (*spad_write)(struct ntb_dev *ntb, int sidx, u32 val);
>
> - int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
> + int (*peer_spad_addr)(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr);
> - u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
> - int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
> + u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
> + int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
> + u32 val);
> };
>
> static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> @@ -322,13 +323,12 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> /* ops->peer_db_read_mask && */
> /* ops->peer_db_set_mask && */
> /* ops->peer_db_clear_mask && */
> - /* ops->spad_is_unsafe && */
> - ops->spad_count &&
> - ops->spad_read &&
> - ops->spad_write &&
> - /* ops->peer_spad_addr && */
> - /* ops->peer_spad_read && */
> - ops->peer_spad_write &&
> + /* !ops->spad_is_unsafe == !ops->spad_count && */
> + !ops->spad_read == !ops->spad_count &&
> + !ops->spad_write == !ops->spad_count &&
> + /* !ops->peer_spad_addr == !ops->spad_count && */
> + /* !ops->peer_spad_read == !ops->spad_count && */
> + !ops->peer_spad_write == !ops->spad_count &&
> 1;
> }
>
> @@ -1087,51 +1087,62 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
> }
>
> /**
> - * ntb_mw_count() - get the number of scratchpads
> + * ntb_spad_count() - get the number of scratchpads
> * @ntb: NTB device context.
> *
> * Hardware and topology may support a different number of scratchpads.
> + * Although it must be the same for all ports per NTB device.
> *
> * Return: the number of scratchpads.
> */
> static inline int ntb_spad_count(struct ntb_dev *ntb)
> {
> + if (!ntb->ops->spad_count)
> + return 0;
> +
> return ntb->ops->spad_count(ntb);
> }
>
> /**
> * ntb_spad_read() - read the local scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @sidx: Scratchpad index.
> *
> * Read the local scratchpad register, and return the value.
> *
> * Return: The value of the local scratchpad register.
> */
> -static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
> +static inline u32 ntb_spad_read(struct ntb_dev *ntb, int sidx)
> {
> - return ntb->ops->spad_read(ntb, idx);
> + if (!ntb->ops->spad_read)
> + return ~(u32)0;
> +
> + return ntb->ops->spad_read(ntb, sidx);
> }
>
> /**
> * ntb_spad_write() - write the local scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @sidx: Scratchpad index.
> * @val: Scratchpad value.
> *
> * Write the value to the local scratchpad register.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> +static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
> {
> - return ntb->ops->spad_write(ntb, idx, val);
> + if (!ntb->ops->spad_write)
> + return -EINVAL;
> +
> + return ntb->ops->spad_write(ntb, sidx, val);
> }
>
> /**
> * ntb_peer_spad_addr() - address of the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> * @spad_addr: OUT - The address of the peer scratchpad register.
> *
> * Return the address of the peer doorbell register. This may be used, for
> @@ -1139,42 +1150,51 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32
> val)
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
> +static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr)
> {
> if (!ntb->ops->peer_spad_addr)
> return -EINVAL;
>
> - return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
> + return ntb->ops->peer_spad_addr(ntb, pidx, sidx, spad_addr);
> }
>
> /**
> * ntb_peer_spad_read() - read the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> *
> * Read the peer scratchpad register, and return the value.
> *
> * Return: The value of the local scratchpad register.
> */
> -static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> +static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
> {
> - return ntb->ops->peer_spad_read(ntb, idx);
> + if (!ntb->ops->peer_spad_read)
> + return ~(u32)0;
> +
> + return ntb->ops->peer_spad_read(ntb, pidx, sidx);
> }
>
> /**
> * ntb_peer_spad_write() - write the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> * @val: Scratchpad value.
> *
> * Write the value to the peer scratchpad register.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> +static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
> + u32 val)
> {
> - return ntb->ops->peer_spad_write(ntb, idx, val);
> + if (!ntb->ops->peer_spad_write)
> + return -EINVAL;
> +
> + return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
> }
>
> #endif
> --
> 2.6.6


2016-12-13 04:14:23

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 6/9] NTB: Add Messaging NTB API

From: Serge Semin
> Some IDT NTB-capable PCIe-switches have message registers to communicate with
> peer devices. This patch adds new NTB API callback methods, which can be used
> to utilize these registers functionality:
> ntb_msg_count(); - get number of message registers
> ntb_msg_inbits(); - get bitfield of inbound message registers status
> ntb_msg_outbits(); - get bitfield of outbound message registers status
> ntb_msg_read_sts(); - read the inbound and outbound message registers status
> ntb_msg_clear_sts(); - clear status bits of message registers
> ntb_msg_set_mask(); - mask interrupts raised by status bits of message
> registers.
> ntb_msg_clear_mask(); - clear interrupts mask bits of message registers
> ntb_msg_read(midx, *pidx); - read message register with specified index,
> additionally getting peer port index which data received from
> ntb_msg_write(midx, pidx); - write data to the specified message register
> sending it to the passed peer device connected over a pidx port
> ntb_msg_event(); - notify driver context of a new message event
>
> Of course there is hadrware which doesn't support Message registers, so

s/hadrware/hardware/

> this API is made optional.
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

>
> ---
> drivers/ntb/ntb.c | 13 ++++
> include/linux/ntb.h | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 218 insertions(+)
>
> diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
> index f6153af..06574f8 100644
> --- a/drivers/ntb/ntb.c
> +++ b/drivers/ntb/ntb.c
> @@ -193,6 +193,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
> }
> EXPORT_SYMBOL(ntb_db_event);
>
> +void ntb_msg_event(struct ntb_dev *ntb)
> +{
> + unsigned long irqflags;
> +
> + spin_lock_irqsave(&ntb->ctx_lock, irqflags);
> + {
> + if (ntb->ctx_ops && ntb->ctx_ops->msg_event)
> + ntb->ctx_ops->msg_event(ntb->ctx);
> + }
> + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
> +}
> +EXPORT_SYMBOL(ntb_msg_event);
> +
> static int ntb_probe(struct device *dev)
> {
> struct ntb_dev *ntb;
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index a6bf15d..90746df 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -164,10 +164,12 @@ static inline int ntb_client_ops_is_valid(const struct
> ntb_client_ops *ops)
> * struct ntb_ctx_ops - ntb driver context operations
> * @link_event: See ntb_link_event().
> * @db_event: See ntb_db_event().
> + * @msg_event: See ntb_msg_event().
> */
> struct ntb_ctx_ops {
> void (*link_event)(void *ctx);
> void (*db_event)(void *ctx, int db_vector);
> + void (*msg_event)(void *ctx);
> };
>
> static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> @@ -176,6 +178,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> return
> /* ops->link_event && */
> /* ops->db_event && */
> + /* ops->msg_event && */
> 1;
> }
>
> @@ -220,6 +223,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_addr: See ntb_peer_spad_addr().
> * @peer_spad_read: See ntb_peer_spad_read().
> * @peer_spad_write: See ntb_peer_spad_write().
> + * @msg_count: See ntb_msg_count().
> + * @msg_inbits: See ntb_msg_inbits().
> + * @msg_outbits: See ntb_msg_outbits().
> + * @msg_read_sts: See ntb_msg_read_sts().
> + * @msg_clear_sts: See ntb_msg_clear_sts().
> + * @msg_set_mask: See ntb_msg_set_mask().
> + * @msg_clear_mask: See ntb_msg_clear_mask().
> + * @msg_read: See ntb_msg_read().
> + * @msg_write: See ntb_msg_write().
> */
> struct ntb_dev_ops {
> int (*port_number)(struct ntb_dev *ntb);
> @@ -282,6 +294,16 @@ struct ntb_dev_ops {
> u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
> int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
> u32 val);
> +
> + int (*msg_count)(struct ntb_dev *ntb);
> + u64 (*msg_inbits)(struct ntb_dev *ntb);
> + u64 (*msg_outbits)(struct ntb_dev *ntb);
> + u64 (*msg_read_sts)(struct ntb_dev *ntb);
> + int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits);
> + int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits);
> + int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
> + int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg);
> + int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg);
> };
>
> static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> @@ -329,6 +351,15 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* !ops->peer_spad_addr == !ops->spad_count && */
> /* !ops->peer_spad_read == !ops->spad_count && */
> !ops->peer_spad_write == !ops->spad_count &&
> +
> + !ops->msg_inbits == !ops->msg_count &&
> + !ops->msg_outbits == !ops->msg_count &&
> + !ops->msg_read_sts == !ops->msg_count &&
> + !ops->msg_clear_sts == !ops->msg_count &&
> + /* !ops->msg_set_mask == !ops->msg_count && */
> + /* !ops->msg_clear_mask == !ops->msg_count && */
> + !ops->msg_read == !ops->msg_count &&
> + !ops->msg_write == !ops->msg_count &&
> 1;
> }
>
> @@ -472,6 +503,18 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_msg_event() - notify driver context of a message event
> + * @ntb: NTB device context.
> + *
> + * Notify the driver context of a message event. If hardware supports
> + * message registers, this event indicates, that a new message arrived in
> + * some incoming message register or last sent message couldn't be delivered.
> + * The events can be masked/unmasked by the methods ntb_msg_set_mask() and
> + * ntb_msg_clear_mask().
> + */
> +void ntb_msg_event(struct ntb_dev *ntb);
> +
> +/**
> * ntb_port_number() - get the local port number
> * @ntb: NTB device context.
> *
> @@ -1197,4 +1240,166 @@ static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int
> pidx, int sidx,
> return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
> }
>
> +/**
> + * ntb_msg_count() - get the number of message registers
> + * @ntb: NTB device context.
> + *
> + * Hardware may support a different number of messge registers.
> + *
> + * Return: the number of message registers.
> + */
> +static inline int ntb_msg_count(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_count)
> + return 0;
> +
> + return ntb->ops->msg_count(ntb);
> +}
> +
> +/**
> + * ntb_msg_inbits() - get a bitsfield of inbound message registers status
> + * @ntb: NTB device context.
> + *
> + * The method returns the bitsfield of status and mask registers, which related
> + * to inbound message registers.
> + *
> + * Return: bitsfield of inbound message registers.
> + */
> +static inline u64 ntb_msg_inbits(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_inbits)
> + return 0;
> +
> + return ntb->ops->msg_inbits(ntb);
> +}
> +
> +/**
> + * ntb_msg_outbits() - get a bitsfield of outbound message registers status
> + * @ntb: NTB device context.
> + *
> + * The method returns the bitsfield of status and mask registers, which related
> + * to outbound message registers.
> + *
> + * Return: bitsfield of outbound message registers.
> + */
> +static inline u64 ntb_msg_outbits(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_outbits)
> + return 0;
> +
> + return ntb->ops->msg_outbits(ntb);
> +}
> +
> +/**
> + * ntb_msg_read_sts() - read the message registers status
> + * @ntb: NTB device context.
> + *
> + * Read the status of message register. Inbound and outbound message registers
> + * related bits can be filetered by masks retrieved from ntb_msg_inbits() and
> + * ntb_msg_outbits().
> + *
> + * Return: status bits of message registers
> + */
> +static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->msg_read_sts)
> + return 0;
> +
> + return ntb->ops->msg_read_sts(ntb);
> +}
> +
> +/**
> + * ntb_msg_clear_sts() - clear status bits of message registers
> + * @ntb: NTB device context.
> + * @sts_bits: Status bits to clear.
> + *
> + * Clear bits in the status register.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
> +{
> + if (!ntb->ops->msg_clear_sts)
> + return -EINVAL;
> +
> + return ntb->ops->msg_clear_sts(ntb, sts_bits);
> +}
> +
> +/**
> + * ntb_msg_set_mask() - set mask of message register status bits
> + * @ntb: NTB device context.
> + * @mask_bits: Mask bits.
> + *
> + * Mask the message registers status bits from raising the message event.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
> +{
> + if (!ntb->ops->msg_set_mask)
> + return -EINVAL;
> +
> + return ntb->ops->msg_set_mask(ntb, mask_bits);
> +}
> +
> +/**
> + * ntb_msg_clear_mask() - clear message registers mask
> + * @ntb: NTB device context.
> + * @mask_bits: Mask bits to clear.
> + *
> + * Clear bits in the message events mask register.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
> +{
> + if (!ntb->ops->msg_clear_mask)
> + return -EINVAL;
> +
> + return ntb->ops->msg_clear_mask(ntb, mask_bits);
> +}
> +
> +/**
> + * ntb_msg_read() - read message register with specified index
> + * @ntb: NTB device context.
> + * @midx: Message register index
> + * @pidx: OUT - Port index of peer device a message retrieved from
> + * @msg: OUT - Data
> + *
> + * Read data from the specified message register. Source port index of a
> + * message is retrieved as well.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx,
> + u32 *msg)
> +{
> + if (!ntb->ops->msg_read)
> + return -EINVAL;
> +
> + return ntb->ops->msg_read(ntb, midx, pidx, msg);
> +}
> +
> +/**
> + * ntb_msg_write() - write data to the specified message register
> + * @ntb: NTB device context.
> + * @midx: Message register index
> + * @pidx: Port index of peer device a message being sent to
> + * @msg: Data to send
> + *
> + * Send data to a specified peer device using the defined message register.
> + * Message event can be raised if the midx registers isn't empty while
> + * calling this method and the corresponding interrupt isn't masked.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx,
> + u32 msg)
> +{
> + if (!ntb->ops->msg_write)
> + return -EINVAL;
> +
> + return ntb->ops->msg_write(ntb, midx, pidx, msg);
> +}
> +
> #endif
> --
> 2.6.6


2016-12-13 04:14:43

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 7/9] NTB: Add new Memory Windows API documentation

From: Serge Semin
> Since the new API slightly changes the way a typical NTB client driver
> works, the documentation file needs to be appropriately updated.
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

>
> ---
> Documentation/ntb.txt | 99 ++++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 91 insertions(+), 8 deletions(-)
>
> diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
> index 1d9bbab..d01bb69 100644
> --- a/Documentation/ntb.txt
> +++ b/Documentation/ntb.txt
> @@ -1,14 +1,16 @@
> # NTB Drivers
>
> NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
> -the separate memory systems of two computers to the same PCI-Express fabric.
> -Existing NTB hardware supports a common feature set, including scratchpad
> -registers, doorbell registers, and memory translation windows. Scratchpad
> -registers are read-and-writable registers that are accessible from either side
> -of the device, so that peers can exchange a small amount of information at a
> -fixed address. Doorbell registers provide a way for peers to send interrupt
> -events. Memory windows allow translated read and write access to the peer
> -memory.
> +the separate memory systems of two or more computers to the same PCI-Express
> +fabric. Existing NTB hardware supports a common feature set: doorbell
> +registers and memory translation windows, as well as non common features like
> +scratchpad and message registers. Scratchpad registers are read-and-writable
> +registers that are accessible from either side of the device, so that peers can
> +exchange a small amount of information at a fixed address. Message registers can
> +be utialized for the same purpose. Additionally they are provided with with
> +special status bits to make sure the information isn't rewritten by another
> +peer. Doorbell registers provide a way for peers to send interrupt events.
> +Memory windows allow translated read and write access to the peer memory.
>
> ## NTB Core Driver (ntb)
>
> @@ -26,6 +28,87 @@ as ntb hardware, or hardware drivers, are inserted and removed. The
> registration uses the Linux Device framework, so it should feel familiar to
> anyone who has written a pci driver.
>
> +### NTB Typical client driver implementation
> +
> +Primary purpose of NTB is to share some peace of memory between at least two
> +systems. So the NTB device features like Scratchpad/Message regiesters are
> +mainly used to perform the proper memory window initialization. Typically
> +there are two types of memory window interfaces supported by the NTB API:
> +inbound translation configured on the local ntb port and outbound translation
> +configured by the peer, on the peer ntb port. The first type is
> +depicted on the next figure
> +
> +Inbound translation:
> + Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
> + ____________
> + | dma-mapped |-ntb_mw_set_trans(addr) |
> + | memory | _v____________ | ______________
> + | (addr) |<======| MW xlat addr |<====| MW base addr |<== memory-mapped IO
> + |------------| |--------------| | |--------------|
> +
> +So typical scenario of the first type memory window initialization looks:
> +1) allocate a memory region, 2) put translated address to NTB config,
> +3) somehow notify a peer device of performed initialization, 4) peer device
> +maps corresponding outbound memory window so to have access to the shared
> +memory region.
> +
> +The second type of interface, that implies the shared windows being
> +initialized by a peer device, is depicted on the figure:
> +
> +Outbound translation:
> + Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
> + ____________ ______________
> + | dma-mapped | | | MW base addr |<== memory-mapped IO
> + | memory | | |--------------|
> + | (addr) |<===================| MW xlat addr |<-ntb_peer_mw_set_trans(addr)
> + |------------| | |--------------|
> +
> +Typical scenario of the second type interface initialization would be:
> +1) allocate a memory region, 2) somehow deliver a translated address to a peer
> +device, 3) peer puts the translated address to NTB config, 4) peer device maps
> +outbound memory window so to have access to the shared memory region.
> +
> +As one can see the described scenarios can be combined in one portable
> +algorithm.
> + Local device:
> + 1) Allocate memory for a shared window
> + 2) Initialize memory window by translated address of the allocated region
> + (it may fail if local memory window initialzation is unsupported)
> + 3) Send the translated address and memory window index to a peer device
> + Peer device:
> + 1) Initialize memory window with retrieved address of the allocated
> + by another device memory region (it may fail if peer memory window
> + initialization is unsupported)
> + 2) Map outbound memory window
> +
> +In accordance with this scenario, the NTB Memory Window API can be used as
> +follows:
> + Local device:
> + 1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
> + be allocated for memory windows between local device and peer device
> + of port with specified index.
> + 2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
> + shared memory region alignment and size. Then memory can be properly
> + allocated.
> + 3) Allocate physically contiguous memory region in complience with
> + restrictions retrieved in 2).
> + 4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
> + the memory window with specified index for the defined peer device
> + (it may fail if local translated address setting is not supported)
> + 5) Send translated base address (usually together with memory window
> + number) to the peer device using, for instance, scratchpad or message
> + registers.
> + Peer device:
> + 1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
> + device (related to pidx) translated address for specified memory
> + window. It may fail if retrieved address, for instance, exceeds
> + maximum possible address or isn't properly aligned.
> + 2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
> + window so to have an access to the shared memory.
> +
> +Also it is worth to note, that method ntb_mw_count(pidx) should return the
> +same value as ntb_peer_mw_count() on the peer with port index - pidx.
> +
> ### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)
>
> The primary client for NTB is the Transport client, used in tandem with NTB
> --
> 2.6.6


2016-12-13 04:14:51

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 8/9] NTB: Add PCIe Gen4 link speed

From: Serge Semin
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

>
> ---
> include/linux/ntb.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 90746df..fe0437c 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -108,6 +108,7 @@ static inline char *ntb_topo_string(enum ntb_topo topo)
> * @NTB_SPEED_GEN1: Link is trained to gen1 speed.
> * @NTB_SPEED_GEN2: Link is trained to gen2 speed.
> * @NTB_SPEED_GEN3: Link is trained to gen3 speed.
> + * @NTB_SPEED_GEN4: Link is trained to gen4 speed.
> */
> enum ntb_speed {
> NTB_SPEED_AUTO = -1,
> @@ -115,6 +116,7 @@ enum ntb_speed {
> NTB_SPEED_GEN1 = 1,
> NTB_SPEED_GEN2 = 2,
> NTB_SPEED_GEN3 = 3,
> + NTB_SPEED_GEN4 = 4
> };
>
> /**
> --
> 2.6.6


2016-12-13 04:15:05

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v2 9/9] NTB: Add ntb.h comments

From: Serge Semin
>
> Signed-off-by: Serge Semin <[email protected]>
>
> ---
> include/linux/ntb.h | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index fe0437c..c5a369c 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -312,13 +312,18 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> {
> /* commented callbacks are not required: */
> return
> + /* Port operations are required */

Maybe: are required for multiport devices.

> ops->port_number &&
> ops->peer_port_count &&
> ops->peer_port_number &&
> ops->peer_port_idx &&
> +
> + /* Link operations are requiered */
> ops->link_is_up &&
> ops->link_enable &&
> ops->link_disable &&

Wasn't the first patch in this series all about making link ops first?

> +
> + /* One or both MW interfaces should be developed */
> ops->mw_count &&
> ops->mw_get_align &&
> (ops->mw_set_trans ||
> @@ -328,12 +333,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> ops->peer_mw_get_addr &&
> /* ops->peer_mw_clear_trans && */
>
> + /* Doorbell operations are mostly required */
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
> -
> /* both set, or both unset */
> (!ops->db_vector_count == !ops->db_vector_mask) &&
> -
> ops->db_read &&
> /* ops->db_set && */
> ops->db_clear &&
> @@ -347,6 +351,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* ops->peer_db_read_mask && */
> /* ops->peer_db_set_mask && */
> /* ops->peer_db_clear_mask && */
> +
> + /* Scrachpad interface is optional */
> /* !ops->spad_is_unsafe == !ops->spad_count && */
> !ops->spad_read == !ops->spad_count &&
> !ops->spad_write == !ops->spad_count &&
> @@ -354,6 +360,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* !ops->peer_spad_read == !ops->spad_count && */
> !ops->peer_spad_write == !ops->spad_count &&
>
> + /* Message registers interface is optional */
> !ops->msg_inbits == !ops->msg_count &&
> !ops->msg_outbits == !ops->msg_count &&
> !ops->msg_read_sts == !ops->msg_count &&
> @@ -374,13 +381,12 @@ struct ntb_client {
> struct device_driver drv;
> const struct ntb_client_ops ops;
> };
> -
> #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
>
> /**
> * struct ntb_device - ntb device
> * @dev: Linux device object.
> - * @pdev: Pci device entry of the ntb.
> + * @pdev: PCI device entry of the ntb.
> * @topo: Detected topology of the ntb.
> * @ops: See &ntb_dev_ops.
> * @ctx: See &ntb_ctx_ops.
> @@ -401,7 +407,6 @@ struct ntb_dev {
> /* block unregister until device is fully released */
> struct completion released;
> };
> -
> #define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
>
> /**
> @@ -498,7 +503,7 @@ void ntb_link_event(struct ntb_dev *ntb);
> * multiple interrupt vectors for doorbells, the vector number indicates which
> * vector received the interrupt. The vector number is relative to the first
> * vector used for doorbells, starting at zero, and must be less than
> - ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> + * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> * doorbell bits need service, and ntb_db_vector_mask() to determine which of
> * those bits are associated with the vector number.
> */
> --
> 2.6.6


2016-12-13 23:50:30

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 7/9] NTB: Add new Memory Windows API documentation

Since the new API slightly changes the way a typical NTB client driver
works, the documentation file needs to be appropriately updated.

Acked-by: Allen Hubbe <[email protected]>
Signed-off-by: Serge Semin <[email protected]>
---
Documentation/ntb.txt | 99 ++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 91 insertions(+), 8 deletions(-)

diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
index 1d9bbab..a5af4f0 100644
--- a/Documentation/ntb.txt
+++ b/Documentation/ntb.txt
@@ -1,14 +1,16 @@
# NTB Drivers

NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
-the separate memory systems of two computers to the same PCI-Express fabric.
-Existing NTB hardware supports a common feature set, including scratchpad
-registers, doorbell registers, and memory translation windows. Scratchpad
-registers are read-and-writable registers that are accessible from either side
-of the device, so that peers can exchange a small amount of information at a
-fixed address. Doorbell registers provide a way for peers to send interrupt
-events. Memory windows allow translated read and write access to the peer
-memory.
+the separate memory systems of two or more computers to the same PCI-Express
+fabric. Existing NTB hardware supports a common feature set: doorbell
+registers and memory translation windows, as well as non common features like
+scratchpad and message registers. Scratchpad registers are read-and-writable
+registers that are accessible from either side of the device, so that peers can
+exchange a small amount of information at a fixed address. Message registers can
+be utilized for the same purpose. Additionally they are provided with with
+special status bits to make sure the information isn't rewritten by another
+peer. Doorbell registers provide a way for peers to send interrupt events.
+Memory windows allow translated read and write access to the peer memory.

## NTB Core Driver (ntb)

@@ -26,6 +28,87 @@ as ntb hardware, or hardware drivers, are inserted and removed. The
registration uses the Linux Device framework, so it should feel familiar to
anyone who has written a pci driver.

+### NTB Typical client driver implementation
+
+Primary purpose of NTB is to share some peace of memory between at least two
+systems. So the NTB device features like Scratchpad/Message registers are
+mainly used to perform the proper memory window initialization. Typically
+there are two types of memory window interfaces supported by the NTB API:
+inbound translation configured on the local ntb port and outbound translation
+configured by the peer, on the peer ntb port. The first type is
+depicted on the next figure
+
+Inbound translation:
+ Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
+ ____________
+ | dma-mapped |-ntb_mw_set_trans(addr) |
+ | memory | _v____________ | ______________
+ | (addr) |<======| MW xlat addr |<====| MW base addr |<== memory-mapped IO
+ |------------| |--------------| | |--------------|
+
+So typical scenario of the first type memory window initialization looks:
+1) allocate a memory region, 2) put translated address to NTB config,
+3) somehow notify a peer device of performed initialization, 4) peer device
+maps corresponding outbound memory window so to have access to the shared
+memory region.
+
+The second type of interface, that implies the shared windows being
+initialized by a peer device, is depicted on the figure:
+
+Outbound translation:
+ Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
+ ____________ ______________
+ | dma-mapped | | | MW base addr |<== memory-mapped IO
+ | memory | | |--------------|
+ | (addr) |<===================| MW xlat addr |<-ntb_peer_mw_set_trans(addr)
+ |------------| | |--------------|
+
+Typical scenario of the second type interface initialization would be:
+1) allocate a memory region, 2) somehow deliver a translated address to a peer
+device, 3) peer puts the translated address to NTB config, 4) peer device maps
+outbound memory window so to have access to the shared memory region.
+
+As one can see the described scenarios can be combined in one portable
+algorithm.
+ Local device:
+ 1) Allocate memory for a shared window
+ 2) Initialize memory window by translated address of the allocated region
+ (it may fail if local memory window initialization is unsupported)
+ 3) Send the translated address and memory window index to a peer device
+ Peer device:
+ 1) Initialize memory window with retrieved address of the allocated
+ by another device memory region (it may fail if peer memory window
+ initialization is unsupported)
+ 2) Map outbound memory window
+
+In accordance with this scenario, the NTB Memory Window API can be used as
+follows:
+ Local device:
+ 1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
+ be allocated for memory windows between local device and peer device
+ of port with specified index.
+ 2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
+ shared memory region alignment and size. Then memory can be properly
+ allocated.
+ 3) Allocate physically contiguous memory region in compliance with
+ restrictions retrieved in 2).
+ 4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
+ the memory window with specified index for the defined peer device
+ (it may fail if local translated address setting is not supported)
+ 5) Send translated base address (usually together with memory window
+ number) to the peer device using, for instance, scratchpad or message
+ registers.
+ Peer device:
+ 1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
+ device (related to pidx) translated address for specified memory
+ window. It may fail if retrieved address, for instance, exceeds
+ maximum possible address or isn't properly aligned.
+ 2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
+ window so to have an access to the shared memory.
+
+Also it is worth to note, that method ntb_mw_count(pidx) should return the
+same value as ntb_peer_mw_count() on the peer with port index - pidx.
+
### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)

The primary client for NTB is the Transport client, used in tandem with NTB
--
2.6.6

2016-12-13 23:50:31

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 4/9] NTB: Alter MW API to support multi-ports devices

Multi-port NTB devices permit to share a memory between all accessible peers.
Memory Windows API is altered to correspondingly initialize and map memory
windows for such devices:
ntb_mw_count(pidx); - number of inbound memory windows, which can be allocated
for shared buffer with specified peer device.
ntb_mw_get_align(pidx, widx); - get alignment and size restriction parameters
to properly allocate inbound memory region.
ntb_peer_mw_count(); - get number of outbound memory windows.
ntb_peer_mw_get_addr(widx); - get mapping address of an outbound memory window

If hardware supports inbound translation configured on the local ntb port:
ntb_mw_set_trans(pidx, widx); - set translation address of allocated inbound
memory window so a peer device could access it.
ntb_mw_clear_trans(pidx, widx); - clear the translation address of an inbound
memory window.

If hardware supports outbound translation configured on the peer ntb port:
ntb_peer_mw_set_trans(pidx, widx); - set translation address of a memory
window retrieved from a peer device
ntb_peer_mw_clear_trans(pidx, widx); - clear the translation address of an
outbound memory window

Signed-off-by: Serge Semin <[email protected]>
---
drivers/ntb/hw/amd/ntb_hw_amd.c | 68 +++++++++---
drivers/ntb/hw/intel/ntb_hw_intel.c | 90 ++++++++++++----
drivers/ntb/ntb.c | 2 +
drivers/ntb/ntb_transport.c | 21 +++-
drivers/ntb/test/ntb_perf.c | 17 ++-
drivers/ntb/test/ntb_tool.c | 43 +++++---
include/linux/ntb.h | 208 ++++++++++++++++++++++++++++--------
7 files changed, 342 insertions(+), 107 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 4d8d0bd..6a41c38 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
* BSD LICENSE
*
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -79,40 +81,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
return 1 << idx;
}

-static int amd_ntb_mw_count(struct ntb_dev *ntb)
+static int amd_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
return ntb_ndev(ntb)->mw_count;
}

-static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base,
- resource_size_t *size,
- resource_size_t *align,
- resource_size_t *align_size)
+static int amd_ntb_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 amd_ntb_dev *ndev = ntb_ndev(ntb);
int bar;

+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;

- if (base)
- *base = pci_resource_start(ndev->ntb.pdev, bar);
-
- if (size)
- *size = pci_resource_len(ndev->ntb.pdev, bar);
+ if (addr_align)
+ *addr_align = SZ_4K;

- if (align)
- *align = SZ_4K;
+ if (size_align)
+ *size_align = 1;

- if (align_size)
- *align_size = 1;
+ if (size_max)
+ *size_max = pci_resource_len(ndev->ntb.pdev, bar);

return 0;
}

-static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
@@ -122,6 +126,9 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base_addr, limit, reg_val;
int bar;

+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;
@@ -285,6 +292,31 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb)
return 0;
}

+static int amd_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ /* The same as for inbound MWs */
+ return ntb_ndev(ntb)->mw_count;
+}
+
+static int amd_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+ int bar;
+
+ bar = ndev_mw_to_bar(ndev, idx);
+ if (bar < 0)
+ return bar;
+
+ if (base)
+ *base = pci_resource_start(ndev->ntb.pdev, bar);
+
+ if (size)
+ *size = pci_resource_len(ndev->ntb.pdev, bar);
+
+ return 0;
+}
+
static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
{
return ntb_ndev(ntb)->db_valid_mask;
@@ -432,8 +464,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,

static const struct ntb_dev_ops amd_ntb_ops = {
.mw_count = amd_ntb_mw_count,
- .mw_get_range = amd_ntb_mw_get_range,
+ .mw_get_align = amd_ntb_mw_get_align,
.mw_set_trans = amd_ntb_mw_set_trans,
+ .peer_mw_count = amd_ntb_peer_mw_count,
+ .peer_mw_get_addr = amd_ntb_peer_mw_get_addr,
.link_is_up = amd_ntb_link_is_up,
.link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable,
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 725ffa4..4b84012 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -6,6 +6,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -15,6 +16,7 @@
*
* Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -1035,20 +1037,26 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
debugfs_remove_recursive(ndev->debugfs_dir);
}

-static int intel_ntb_mw_count(struct ntb_dev *ntb)
+static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
return ntb_ndev(ntb)->mw_count;
}

-static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base,
- resource_size_t *size,
- resource_size_t *align,
- resource_size_t *align_size)
+static int intel_ntb_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 intel_ntb_dev *ndev = ntb_ndev(ntb);
+ resource_size_t bar_size, mw_size;
int bar;

+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -1056,24 +1064,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
if (bar < 0)
return bar;

- if (base)
- *base = pci_resource_start(ndev->ntb.pdev, bar) +
- (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+ bar_size = pci_resource_len(ndev->ntb.pdev, bar);

- if (size)
- *size = pci_resource_len(ndev->ntb.pdev, bar) -
- (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+ if (idx == ndev->b2b_idx)
+ mw_size = bar_size - ndev->b2b_off;
+ else
+ mw_size = bar_size;
+
+ if (addr_align)
+ *addr_align = pci_resource_len(ndev->ntb.pdev, bar);

- if (align)
- *align = pci_resource_len(ndev->ntb.pdev, bar);
+ if (size_align)
+ *size_align = 1;

- if (align_size)
- *align_size = 1;
+ if (size_max)
+ *size_max = mw_size;

return 0;
}

-static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);
@@ -1083,6 +1093,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base, limit, reg_val;
int bar;

+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -1249,6 +1262,36 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
return 0;
}

+static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ /* Numbers of inbound and outbound memory windows match */
+ return ntb_ndev(ntb)->mw_count;
+}
+
+static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+ int bar;
+
+ if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+ idx += 1;
+
+ bar = ndev_mw_to_bar(ndev, idx);
+ if (bar < 0)
+ return bar;
+
+ if (base)
+ *base = pci_resource_start(ndev->ntb.pdev, bar) +
+ (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+ if (size)
+ *size = pci_resource_len(ndev->ntb.pdev, bar) -
+ (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+ return 0;
+}
+
static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
{
return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
@@ -1880,7 +1923,7 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb,

return 0;
}
-static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);
@@ -1890,6 +1933,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base, limit, reg_val;
int bar;

+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;

@@ -2884,8 +2930,10 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {
/* operations for primary side of local ntb */
static const struct ntb_dev_ops intel_ntb_ops = {
.mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
+ .mw_get_align = intel_ntb_mw_get_align,
.mw_set_trans = intel_ntb_mw_set_trans,
+ .peer_mw_count = intel_ntb_peer_mw_count,
+ .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable,
@@ -2910,8 +2958,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {

static const struct ntb_dev_ops intel_ntb3_ops = {
.mw_count = intel_ntb_mw_count,
- .mw_get_range = intel_ntb_mw_get_range,
+ .mw_get_align = intel_ntb_mw_get_align,
.mw_set_trans = intel_ntb3_mw_set_trans,
+ .peer_mw_count = intel_ntb_peer_mw_count,
+ .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
.link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb3_link_enable,
.link_disable = intel_ntb_link_disable,
diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 1e92e52..2551bb2 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
* BSD LICENSE
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 10518b7..4d5b160 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -685,7 +685,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
if (!mw->virt_addr)
return;

- ntb_mw_clear_trans(nt->ndev, num_mw);
+ ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
dma_free_coherent(&pdev->dev, mw->buff_size,
mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0;
@@ -742,7 +742,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
}

/* Notify HW the memory location of the receive buffer */
- rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
+ rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
+ mw->xlat_size);
if (rc) {
dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
ntb_free_mw(nt, num_mw);
@@ -1072,13 +1073,18 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
int node;
int rc, i;

- mw_count = ntb_mw_count(ndev);
+ mw_count = ntb_mw_count(ndev, PIDX);
if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) {
dev_err(&ndev->dev, "Not enough scratch pad registers for %s",
NTB_TRANSPORT_NAME);
return -EIO;
}

+ if (!ndev->ops->mw_set_trans) {
+ dev_err(&ndev->dev, "Inbound MW based NTB API is required\n");
+ return -EINVAL;
+ }
+
if (ntb_db_is_unsafe(ndev))
dev_dbg(&ndev->dev,
"doorbell is unsafe, proceed anyway...\n");
@@ -1109,8 +1115,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
for (i = 0; i < mw_count; i++) {
mw = &nt->mw_vec[i];

- rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
- &mw->xlat_align, &mw->xlat_align_size);
+ rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
+ &mw->xlat_align_size, NULL);
+ if (rc)
+ goto err1;
+
+ rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
+ &mw->phys_size);
if (rc)
goto err1;

diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index c908b3a..cbff0b4 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -453,7 +453,7 @@ static void perf_free_mw(struct perf_ctx *perf)
if (!mw->virt_addr)
return;

- ntb_mw_clear_trans(perf->ntb, 0);
+ ntb_mw_clear_trans(perf->ntb, PIDX, 0);
dma_free_coherent(&pdev->dev, mw->buf_size,
mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0;
@@ -489,7 +489,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
mw->buf_size = 0;
}

- rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
+ rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size);
if (rc) {
dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
perf_free_mw(perf);
@@ -560,8 +560,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)

mw = &perf->mw;

- rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size,
- &mw->xlat_align, &mw->xlat_align_size);
+ rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
+ &mw->xlat_align_size, NULL);
+ if (rc)
+ return rc;
+
+ rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
if (rc)
return rc;

@@ -765,6 +769,11 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
return -EIO;
}

+ if (!ntb->ops->mw_set_trans) {
+ dev_err(&ntb->dev, "Need inbound MW based NTB API\n");
+ return -EINVAL;
+ }
+
if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");

diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index 690862d..cb69247 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -119,7 +119,8 @@ MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);

-#define MAX_MWS 16
+/* It is rare to have hadrware with greater than six MWs */
+#define MAX_MWS 6
/* Only two-ports devices are supported */
#define PIDX NTB_DEF_PEER_IDX

@@ -670,28 +671,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
{
int rc;
struct tool_mw *mw = &tc->mws[idx];
- phys_addr_t base;
- resource_size_t size, align, align_size;
+ resource_size_t size, align_addr, align_size;
char buf[16];

if (mw->peer)
return 0;

- rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
- &align_size);
+ rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
+ &align_size, &size);
if (rc)
return rc;

mw->size = min_t(resource_size_t, req_size, size);
- mw->size = round_up(mw->size, align);
+ mw->size = round_up(mw->size, align_addr);
mw->size = round_up(mw->size, align_size);
mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
&mw->peer_dma, GFP_KERNEL);

- if (!mw->peer)
+ if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
return -ENOMEM;

- rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
+ rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
if (rc)
goto err_free_dma;

@@ -718,7 +718,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx)
struct tool_mw *mw = &tc->mws[idx];

if (mw->peer) {
- ntb_mw_clear_trans(tc->ntb, idx);
+ ntb_mw_clear_trans(tc->ntb, PIDX, idx);
dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
mw->peer,
mw->peer_dma);
@@ -744,8 +744,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,

phys_addr_t base;
resource_size_t mw_size;
- resource_size_t align;
+ resource_size_t align_addr;
resource_size_t align_size;
+ resource_size_t max_size;

buf_size = min_t(size_t, size, 512);

@@ -753,8 +754,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
if (!buf)
return -ENOMEM;

- ntb_mw_get_range(mw->tc->ntb, mw->idx,
- &base, &mw_size, &align, &align_size);
+ ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
+ &align_addr, &align_size, &max_size);
+ ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);

off += scnprintf(buf + off, buf_size - off,
"Peer MW %d Information:\n", mw->idx);
@@ -769,13 +771,17 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,

off += scnprintf(buf + off, buf_size - off,
"Alignment \t%lld\n",
- (unsigned long long)align);
+ (unsigned long long)align_addr);

off += scnprintf(buf + off, buf_size - off,
"Size Alignment \t%lld\n",
(unsigned long long)align_size);

off += scnprintf(buf + off, buf_size - off,
+ "Size Max \t%lld\n",
+ (unsigned long long)max_size);
+
+ off += scnprintf(buf + off, buf_size - off,
"Ready \t%c\n",
(mw->peer) ? 'Y' : 'N');

@@ -829,8 +835,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx)
phys_addr_t base;
int rc;

- rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
- NULL, NULL);
+ rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size);
if (rc)
return rc;

@@ -915,6 +920,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
int rc;
int i;

+ if (!ntb->ops->mw_set_trans) {
+ dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
+ rc = -EINVAL;
+ goto err_tc;
+ }
+
if (ntb_db_is_unsafe(ntb))
dev_dbg(&ntb->dev, "doorbell is unsafe\n");

@@ -933,7 +944,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
tc->ntb = ntb;
init_waitqueue_head(&tc->link_wq);

- tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
+ tc->mw_count = min(ntb_mw_count(tc->ntb, PIDX), MAX_MWS);
for (i = 0; i < tc->mw_count; i++) {
rc = tool_init_mw(tc, i);
if (rc)
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 6eef109..f6ec88f 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
* BSD LICENSE
*
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -201,9 +203,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @link_enable: See ntb_link_enable().
* @link_disable: See ntb_link_disable().
* @mw_count: See ntb_mw_count().
- * @mw_get_range: See ntb_mw_get_range().
+ * @mw_get_align: See ntb_mw_get_align().
* @mw_set_trans: See ntb_mw_set_trans().
* @mw_clear_trans: See ntb_mw_clear_trans().
+ * @peer_mw_count: See ntb_peer_mw_count().
+ * @peer_mw_get_addr: See ntb_peer_mw_get_addr().
+ * @peer_mw_set_trans: See ntb_peer_mw_set_trans().
+ * @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
* @db_is_unsafe: See ntb_db_is_unsafe().
* @db_valid_mask: See ntb_db_valid_mask().
* @db_vector_count: See ntb_db_vector_count().
@@ -241,13 +247,20 @@ struct ntb_dev_ops {
enum ntb_speed max_speed, enum ntb_width max_width);
int (*link_disable)(struct ntb_dev *ntb);

- int (*mw_count)(struct ntb_dev *ntb);
- int (*mw_get_range)(struct ntb_dev *ntb, int idx,
- phys_addr_t *base, resource_size_t *size,
- resource_size_t *align, resource_size_t *align_size);
- int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
+ int (*mw_count)(struct ntb_dev *ntb, int pidx);
+ int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
+ resource_size_t *addr_align,
+ resource_size_t *size_align,
+ resource_size_t *size_max);
+ int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size);
- int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
+ int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
+ int (*peer_mw_count)(struct ntb_dev *ntb);
+ int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
+ phys_addr_t *base, resource_size_t *size);
+ int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
+ u64 addr, resource_size_t size);
+ int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);

int (*db_is_unsafe)(struct ntb_dev *ntb);
u64 (*db_valid_mask)(struct ntb_dev *ntb);
@@ -295,9 +308,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->link_enable &&
ops->link_disable &&
ops->mw_count &&
- ops->mw_get_range &&
- ops->mw_set_trans &&
+ ops->mw_get_align &&
+ (ops->mw_set_trans ||
+ ops->peer_mw_set_trans) &&
/* ops->mw_clear_trans && */
+ ops->peer_mw_count &&
+ ops->peer_mw_get_addr &&
+ /* ops->peer_mw_clear_trans && */

/* ops->db_is_unsafe && */
ops->db_valid_mask &&
@@ -655,79 +672,180 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
}

/**
- * ntb_mw_count() - get the number of memory windows
+ * ntb_mw_count() - get the number of inbound memory windows, which could
+ * be created for a specified peer device
* @ntb: NTB device context.
+ * @pidx: Port index of peer device.
*
* Hardware and topology may support a different number of memory windows.
+ * Moreover different peer devices can support different number of memory
+ * windows. Simply speaking this method returns the number of possible inbound
+ * memory windows to share with specified peer device.
*
* Return: the number of memory windows.
*/
-static inline int ntb_mw_count(struct ntb_dev *ntb)
+static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
{
- return ntb->ops->mw_count(ntb);
+ return ntb->ops->mw_count(ntb, pidx);
}

/**
- * ntb_mw_get_range() - get the range of a memory window
+ * ntb_mw_get_align() - get the restriction parameters of inbound memory window
* @ntb: NTB device context.
- * @idx: Memory window number.
- * @base: OUT - the base address for mapping the memory window
- * @size: OUT - the size for mapping the memory window
- * @align: OUT - the base alignment for translating the memory window
- * @align_size: OUT - the size alignment for translating the memory window
- *
- * Get the range of a memory window. NULL may be given for any output
- * parameter if the value is not needed. The base and size may be used for
- * mapping the memory window, to access the peer memory. The alignment and
- * size may be used for translating the memory window, for the peer to access
- * memory on the local system.
- *
- * Return: Zero on success, otherwise an error number.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ * @addr_align: OUT - the base alignment for translating the memory window
+ * @size_align: OUT - the size alignment for translating the memory window
+ * @size_max: OUT - the maximum size of the memory window
+ *
+ * Get the alignments of an inbound memory window with specified index.
+ * NULL may be given for any output parameter if the value is not needed.
+ * The alignment and size parameters may be used for allocation of proper
+ * shared memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
*/
-static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
- phys_addr_t *base, resource_size_t *size,
- resource_size_t *align, resource_size_t *align_size)
+static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
+ resource_size_t *addr_align,
+ resource_size_t *size_align,
+ resource_size_t *size_max)
{
- return ntb->ops->mw_get_range(ntb, idx, base, size,
- align, align_size);
+ return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
+ size_max);
}

/**
- * ntb_mw_set_trans() - set the translation of a memory window
+ * ntb_mw_set_trans() - set the translation of an inbound memory window
* @ntb: NTB device context.
- * @idx: Memory window number.
- * @addr: The dma address local memory to expose to the peer.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ * @addr: The dma address of local memory to expose to the peer.
* @size: The size of the local memory to expose to the peer.
*
* Set the translation of a memory window. The peer may access local memory
* through the window starting at the address, up to the size. The address
- * must be aligned to the alignment specified by ntb_mw_get_range(). The size
- * must be aligned to the size alignment specified by ntb_mw_get_range().
+ * and size must be aligned in compliance with restrictions of
+ * ntb_mw_get_align(). The region size should not exceed the size_max parameter
+ * of that method.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size)
{
- return ntb->ops->mw_set_trans(ntb, idx, addr, size);
+ if (!ntb->ops->mw_set_trans)
+ return 0;
+
+ return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
}

/**
- * ntb_mw_clear_trans() - clear the translation of a memory window
+ * ntb_mw_clear_trans() - clear the translation address of an inbound memory
+ * window
* @ntb: NTB device context.
- * @idx: Memory window number.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
*
- * Clear the translation of a memory window. The peer may no longer access
- * local memory through the window.
+ * Clear the translation of an inbound memory window. The peer may no longer
+ * access local memory through the window.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
+static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
{
if (!ntb->ops->mw_clear_trans)
- return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
+ return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
+
+ return ntb->ops->mw_clear_trans(ntb, pidx, widx);
+}
+
+/**
+ * ntb_peer_mw_count() - get the number of outbound memory windows, which could
+ * be mapped to access a shared memory
+ * @ntb: NTB device context.
+ *
+ * Hardware and topology may support a different number of memory windows.
+ * This method returns the number of outbound memory windows supported by
+ * local device.
+ *
+ * Return: the number of memory windows.
+ */
+static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+ return ntb->ops->peer_mw_count(ntb);
+}
+
+/**
+ * ntb_peer_mw_get_addr() - get map address of an outbound memory window
+ * @ntb: NTB device context.
+ * @widx: Memory window index (within ntb_peer_mw_count() return value).
+ * @base: OUT - the base address of mapping region.
+ * @size: OUT - the size of mapping region.
+ *
+ * Get base and size of memory region to map. NULL may be given for any output
+ * parameter if the value is not needed. The base and size may be used for
+ * mapping the memory window, to access the peer memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
+ phys_addr_t *base, resource_size_t *size)
+{
+ return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
+}
+
+/**
+ * ntb_peer_mw_set_trans() - set a translation address of a memory window
+ * retrieved from a peer device
+ * @ntb: NTB device context.
+ * @pidx: Port index of peer device the translation address received from.
+ * @widx: Memory window index.
+ * @addr: The dma address of the shared memory to access.
+ * @size: The size of the shared memory to access.
+ *
+ * Set the translation of an outbound memory window. The local device may
+ * access shared memory allocated by a peer device sent the address.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface, so a translation address can be only set on the side,
+ * where shared memory (inbound memory windows) is allocated.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
+ u64 addr, resource_size_t size)
+{
+ if (!ntb->ops->peer_mw_set_trans)
+ return 0;
+
+ return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
+}
+
+/**
+ * ntb_peer_mw_clear_trans() - clear the translation address of an outbound
+ * memory window
+ * @ntb: NTB device context.
+ * @pidx: Port index of peer device.
+ * @widx: Memory window index.
+ *
+ * Clear the translation of a outbound memory window. The local device may no
+ * longer access a shared memory through the window.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
+ int widx)
+{
+ if (!ntb->ops->peer_mw_clear_trans)
+ return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);

- return ntb->ops->mw_clear_trans(ntb, idx);
+ return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
}

/**
--
2.6.6

2016-12-13 23:50:41

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 1/9] NTB: Make link-state API being declared first

Since link operations are usually performed before memory window access
operations, it's logically better to declare link-related API before any
of MW/Doorbell/Scratchpad methods.

Signed-off-by: Serge Semin <[email protected]>
---
include/linux/ntb.h | 137 ++++++++++++++++++++++++++--------------------------
1 file changed, 69 insertions(+), 68 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 6f47562..5d1f260 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -179,13 +179,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)

/**
* struct ntb_ctx_ops - ntb device operations
+ * @link_is_up: See ntb_link_is_up().
+ * @link_enable: See ntb_link_enable().
+ * @link_disable: See ntb_link_disable().
* @mw_count: See ntb_mw_count().
* @mw_get_range: See ntb_mw_get_range().
* @mw_set_trans: See ntb_mw_set_trans().
* @mw_clear_trans: See ntb_mw_clear_trans().
- * @link_is_up: See ntb_link_is_up().
- * @link_enable: See ntb_link_enable().
- * @link_disable: See ntb_link_disable().
* @db_is_unsafe: See ntb_db_is_unsafe().
* @db_valid_mask: See ntb_db_valid_mask().
* @db_vector_count: See ntb_db_vector_count().
@@ -212,6 +212,12 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_write: See ntb_peer_spad_write().
*/
struct ntb_dev_ops {
+ int (*link_is_up)(struct ntb_dev *ntb,
+ enum ntb_speed *speed, enum ntb_width *width);
+ int (*link_enable)(struct ntb_dev *ntb,
+ enum ntb_speed max_speed, enum ntb_width max_width);
+ int (*link_disable)(struct ntb_dev *ntb);
+
int (*mw_count)(struct ntb_dev *ntb);
int (*mw_get_range)(struct ntb_dev *ntb, int idx,
phys_addr_t *base, resource_size_t *size,
@@ -220,12 +226,6 @@ struct ntb_dev_ops {
dma_addr_t addr, resource_size_t size);
int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);

- int (*link_is_up)(struct ntb_dev *ntb,
- enum ntb_speed *speed, enum ntb_width *width);
- int (*link_enable)(struct ntb_dev *ntb,
- enum ntb_speed max_speed, enum ntb_width max_width);
- int (*link_disable)(struct ntb_dev *ntb);
-
int (*db_is_unsafe)(struct ntb_dev *ntb);
u64 (*db_valid_mask)(struct ntb_dev *ntb);
int (*db_vector_count)(struct ntb_dev *ntb);
@@ -265,13 +265,14 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ ops->link_is_up &&
+ ops->link_enable &&
+ ops->link_disable &&
ops->mw_count &&
ops->mw_get_range &&
ops->mw_set_trans &&
/* ops->mw_clear_trans && */
- ops->link_is_up &&
- ops->link_enable &&
- ops->link_disable &&
+
/* ops->db_is_unsafe && */
ops->db_valid_mask &&

@@ -441,6 +442,62 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_link_is_up() - get the current ntb link state
+ * @ntb: NTB device context.
+ * @speed: OUT - The link speed expressed as PCIe generation number.
+ * @width: OUT - The link width expressed as the number of PCIe lanes.
+ *
+ * Get the current state of the ntb link. It is recommended to query the link
+ * state once after every link event. It is safe to query the link state in
+ * the context of the link event callback.
+ *
+ * Return: One if the link is up, zero if the link is down, otherwise a
+ * negative value indicating the error number.
+ */
+static inline int ntb_link_is_up(struct ntb_dev *ntb,
+ enum ntb_speed *speed, enum ntb_width *width)
+{
+ return ntb->ops->link_is_up(ntb, speed, width);
+}
+
+/**
+ * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * @ntb: NTB device context.
+ * @max_speed: The maximum link speed expressed as PCIe generation number.
+ * @max_width: The maximum link width expressed as the number of PCIe lanes.
+ *
+ * Enable the link on the secondary side of the ntb. This can only be done
+ * from the primary side of the ntb in primary or b2b topology. The ntb device
+ * should train the link to its maximum speed and width, or the requested speed
+ * and width, whichever is smaller, if supported.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_enable(struct ntb_dev *ntb,
+ enum ntb_speed max_speed,
+ enum ntb_width max_width)
+{
+ return ntb->ops->link_enable(ntb, max_speed, max_width);
+}
+
+/**
+ * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * @ntb: NTB device context.
+ *
+ * Disable the link on the secondary side of the ntb. This can only be
+ * done from the primary side of the ntb in primary or b2b topology. The ntb
+ * device should disable the link. Returning from this call must indicate that
+ * a barrier has passed, though with no more writes may pass in either
+ * direction across the link, except if this call returns an error number.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_disable(struct ntb_dev *ntb)
+{
+ return ntb->ops->link_disable(ntb);
+}
+
+/**
* ntb_mw_count() - get the number of memory windows
* @ntb: NTB device context.
*
@@ -517,62 +574,6 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
}

/**
- * ntb_link_is_up() - get the current ntb link state
- * @ntb: NTB device context.
- * @speed: OUT - The link speed expressed as PCIe generation number.
- * @width: OUT - The link width expressed as the number of PCIe lanes.
- *
- * Get the current state of the ntb link. It is recommended to query the link
- * state once after every link event. It is safe to query the link state in
- * the context of the link event callback.
- *
- * Return: One if the link is up, zero if the link is down, otherwise a
- * negative value indicating the error number.
- */
-static inline int ntb_link_is_up(struct ntb_dev *ntb,
- enum ntb_speed *speed, enum ntb_width *width)
-{
- return ntb->ops->link_is_up(ntb, speed, width);
-}
-
-/**
- * ntb_link_enable() - enable the link on the secondary side of the ntb
- * @ntb: NTB device context.
- * @max_speed: The maximum link speed expressed as PCIe generation number.
- * @max_width: The maximum link width expressed as the number of PCIe lanes.
- *
- * Enable the link on the secondary side of the ntb. This can only be done
- * from the primary side of the ntb in primary or b2b topology. The ntb device
- * should train the link to its maximum speed and width, or the requested speed
- * and width, whichever is smaller, if supported.
- *
- * Return: Zero on success, otherwise an error number.
- */
-static inline int ntb_link_enable(struct ntb_dev *ntb,
- enum ntb_speed max_speed,
- enum ntb_width max_width)
-{
- return ntb->ops->link_enable(ntb, max_speed, max_width);
-}
-
-/**
- * ntb_link_disable() - disable the link on the secondary side of the ntb
- * @ntb: NTB device context.
- *
- * Disable the link on the secondary side of the ntb. This can only be
- * done from the primary side of the ntb in primary or b2b topology. The ntb
- * device should disable the link. Returning from this call must indicate that
- * a barrier has passed, though with no more writes may pass in either
- * direction across the link, except if this call returns an error number.
- *
- * Return: Zero on success, otherwise an error number.
- */
-static inline int ntb_link_disable(struct ntb_dev *ntb)
-{
- return ntb->ops->link_disable(ntb);
-}
-
-/**
* ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
* @ntb: NTB device context.
*
--
2.6.6

2016-12-13 23:50:44

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 0/9] NTB: Alter kernel API to support multi-port devices

There are devices, like IDT PCIe-switches, which have more than just two ports.
Particularly one device can have up to eight ports with NTB-function activated.
In order to support such devices, NTB kernel API should be altered since
currently it's optimized to work with two-ports devices only.

Changelog v2:
- Move comments from cover letter to individual patches
- Combine patches to make code buildable
- Alter patchset to support Intel SKX driver
- Make sure all the API uses the same midx/widx/pidx/sidx arguments notation
- Move new MW API usage description into Documention
- Alter Spad/Msg API checking valid function to make spad and msg interfaces optional
- Alter comments in ntb.h
- Split: add NTB_SPEED_GEN4 and ntb.h comments into separate patches
- Put copyrights into some of the existing patches
- Get rid of TOPO updates

Changelog v3:
- Get rid of code rearrangements within Intel/AMD drivers
- Make two-ports NTB API being default
- Check pidx argument for negative values
- Translation address methods should return zero in case if not implemented
- Simplify Scratchpad alterations of ntb_tool client driver
- ntb.h comments are altered in compliance with port-related API changes
- Spell check the text

Serge Semin (9):
NTB: Make link-state API being declared first
NTB: Add indexed ports NTB API
NTB: Alter link-state API to support multi-port devices
NTB: Alter MW API to support multi-ports devices
NTB: Alter Scratchpads API to support multi-ports devices
NTB: Add Messaging NTB API
NTB: Add new Memory Windows API documentation
NTB: Add PCIe Gen4 link speed
NTB: Add ntb.h comments

Documentation/ntb.txt | 99 ++++-
drivers/ntb/hw/amd/ntb_hw_amd.c | 84 +++--
drivers/ntb/hw/intel/ntb_hw_intel.c | 106 ++++--
drivers/ntb/ntb.c | 69 ++++
drivers/ntb/ntb_transport.c | 44 ++-
drivers/ntb/test/ntb_perf.c | 27 +-
drivers/ntb/test/ntb_pingpong.c | 14 +-
drivers/ntb/test/ntb_tool.c | 69 +++-
include/linux/ntb.h | 724 ++++++++++++++++++++++++++++++------
9 files changed, 1026 insertions(+), 210 deletions(-)

--
2.6.6

2016-12-13 23:50:39

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 3/9] NTB: Alter link-state API to support multi-port devices

Multi-port devices permit the NTB connections between multiple domains,
so a local device can have NTB link being up with one peer and being
down with another. NTB link-state API is appropriately altered to return
a bitfield of the link-states between the local device and possible peers.

Acked-by: Allen Hubbe <[email protected]>
Signed-off-by: Serge Semin <[email protected]>
---
drivers/ntb/hw/amd/ntb_hw_amd.c | 2 +-
drivers/ntb/hw/intel/ntb_hw_intel.c | 2 +-
include/linux/ntb.h | 31 ++++++++++++++++---------------
3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 6ccba0d..4d8d0bd 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -213,7 +213,7 @@ static int amd_link_is_up(struct amd_ntb_dev *ndev)
return 0;
}

-static int amd_ntb_link_is_up(struct ntb_dev *ntb,
+static u64 amd_ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed,
enum ntb_width *width)
{
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index d2ce280..725ffa4 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1171,7 +1171,7 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
return 0;
}

-static int intel_ntb_link_is_up(struct ntb_dev *ntb,
+static u64 intel_ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed,
enum ntb_width *width)
{
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index fe175c7..6eef109 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -235,7 +235,7 @@ struct ntb_dev_ops {
int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
int (*peer_port_idx)(struct ntb_dev *ntb, int port);

- int (*link_is_up)(struct ntb_dev *ntb,
+ u64 (*link_is_up)(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width);
int (*link_enable)(struct ntb_dev *ntb,
enum ntb_speed max_speed, enum ntb_width max_width);
@@ -607,25 +607,26 @@ static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
* state once after every link event. It is safe to query the link state in
* the context of the link event callback.
*
- * Return: One if the link is up, zero if the link is down, otherwise a
- * negative value indicating the error number.
+ * Return: bitfield of indexed ports link state: bit is set/cleared if the
+ * link is up/down respectively.
*/
-static inline int ntb_link_is_up(struct ntb_dev *ntb,
+static inline u64 ntb_link_is_up(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width)
{
return ntb->ops->link_is_up(ntb, speed, width);
}

/**
- * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * ntb_link_enable() - enable the local port ntb connection
* @ntb: NTB device context.
* @max_speed: The maximum link speed expressed as PCIe generation number.
* @max_width: The maximum link width expressed as the number of PCIe lanes.
*
- * Enable the link on the secondary side of the ntb. This can only be done
- * from the primary side of the ntb in primary or b2b topology. The ntb device
- * should train the link to its maximum speed and width, or the requested speed
- * and width, whichever is smaller, if supported.
+ * Enable the NTB/PCIe link on the local or remote (for bridge-to-bridge
+ * topology) side of the bridge. If it's supported the ntb device should train
+ * the link to its maximum speed and width, or the requested speed and width,
+ * whichever is smaller. Some hardware doesn't support PCIe link training, so
+ * the last two arguments will be ignored then.
*
* Return: Zero on success, otherwise an error number.
*/
@@ -637,14 +638,14 @@ static inline int ntb_link_enable(struct ntb_dev *ntb,
}

/**
- * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * ntb_link_disable() - disable the local port ntb connection
* @ntb: NTB device context.
*
- * Disable the link on the secondary side of the ntb. This can only be
- * done from the primary side of the ntb in primary or b2b topology. The ntb
- * device should disable the link. Returning from this call must indicate that
- * a barrier has passed, though with no more writes may pass in either
- * direction across the link, except if this call returns an error number.
+ * Disable the link on the local or remote (for b2b topology) of the ntb.
+ * The ntb device should disable the link. Returning from this call must
+ * indicate that a barrier has passed, though with no more writes may pass in
+ * either direction across the link, except if this call returns an error
+ * number.
*
* Return: Zero on success, otherwise an error number.
*/
--
2.6.6

2016-12-13 23:50:34

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 8/9] NTB: Add PCIe Gen4 link speed

Acked-by: Allen Hubbe <[email protected]>
Signed-off-by: Serge Semin <[email protected]>
---
include/linux/ntb.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 76c56d5..6d46179 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -108,6 +108,7 @@ static inline char *ntb_topo_string(enum ntb_topo topo)
* @NTB_SPEED_GEN1: Link is trained to gen1 speed.
* @NTB_SPEED_GEN2: Link is trained to gen2 speed.
* @NTB_SPEED_GEN3: Link is trained to gen3 speed.
+ * @NTB_SPEED_GEN4: Link is trained to gen4 speed.
*/
enum ntb_speed {
NTB_SPEED_AUTO = -1,
@@ -115,6 +116,7 @@ enum ntb_speed {
NTB_SPEED_GEN1 = 1,
NTB_SPEED_GEN2 = 2,
NTB_SPEED_GEN3 = 3,
+ NTB_SPEED_GEN4 = 4
};

/**
--
2.6.6

2016-12-13 23:50:37

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 2/9] NTB: Add indexed ports NTB API

There is some NTB hardware, which can combine more than just two domains
over NTB. For instance, some IDT PCIe-switches can have NTB-functions
activated on more than two-ports. The different domains are distinguished
by ports they are connected to. So the new port-related methods are added to
the NTB API:
ntb_port_number() - return local port
ntb_peer_port_count() - return number of peers local port can connect to
ntb_peer_port_number(pdix) - return port number by it index
ntb_peer_port_idx(port) - return port index by it number

Current test-drivers aren't changed much. They still support two-ports devices
for the time being while multi-ports hardware drivers aren't added.

By default port-related API is declared for two-ports hardware.
So corresponding hardware drivers won't need to implement it.

Signed-off-by: Serge Semin <[email protected]>
---
drivers/ntb/ntb.c | 54 ++++++++++++++
drivers/ntb/ntb_transport.c | 6 ++
drivers/ntb/test/ntb_perf.c | 4 ++
drivers/ntb/test/ntb_pingpong.c | 6 ++
drivers/ntb/test/ntb_tool.c | 5 ++
include/linux/ntb.h | 156 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 231 insertions(+)

diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 2e25307..1e92e52 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -191,6 +191,60 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
}
EXPORT_SYMBOL(ntb_db_event);

+int ntb_default_port_number(struct ntb_dev *ntb)
+{
+ switch (ntb->topo) {
+ case NTB_TOPO_PRI:
+ case NTB_TOPO_B2B_USD:
+ return NTB_PORT_PRI_USD;
+ case NTB_TOPO_SEC:
+ case NTB_TOPO_B2B_DSD:
+ return NTB_PORT_SEC_DSD;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ntb_default_port_number);
+
+int ntb_default_peer_port_count(struct ntb_dev *ntb)
+{
+ return NTB_DEF_PEER_CNT;
+}
+EXPORT_SYMBOL(ntb_default_peer_port_count);
+
+int ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ if (pidx != NTB_DEF_PEER_IDX)
+ return -EINVAL;
+
+ switch (ntb->topo) {
+ case NTB_TOPO_PRI:
+ case NTB_TOPO_B2B_USD:
+ return NTB_PORT_SEC_DSD;
+ case NTB_TOPO_SEC:
+ case NTB_TOPO_B2B_DSD:
+ return NTB_PORT_PRI_USD;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ntb_default_peer_port_number);
+
+int ntb_default_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ int peer_port = ntb_default_peer_port_number(ntb, NTB_DEF_PEER_IDX);
+
+ if (peer_port == -EINVAL || port != peer_port)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL(ntb_default_peer_port_idx);
+
static int ntb_probe(struct device *dev)
{
struct ntb_dev *ntb;
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 4eb8adb..10518b7 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -94,6 +94,9 @@ MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");

static struct dentry *nt_debugfs_dir;

+/* Only two-ports NTB devices are supported */
+#define PIDX NTB_DEF_PEER_IDX
+
struct ntb_queue_entry {
/* ntb_queue list reference */
struct list_head entry;
@@ -1083,6 +1086,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
dev_dbg(&ndev->dev,
"scratchpad is unsafe, proceed anyway...\n");

+ if (ntb_peer_port_count(ndev) != NTB_DEF_PEER_CNT)
+ dev_warn(&ndev->dev, "Multi-port NTB devices unsupported\n");
+
node = dev_to_node(&ndev->dev);

nt = kzalloc_node(sizeof(*nt), GFP_KERNEL, node);
diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index e75d4fd..c908b3a 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -76,6 +76,7 @@
#define DMA_RETRIES 20
#define SZ_4G (1ULL << 32)
#define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */
+#define PIDX NTB_DEF_PEER_IDX

MODULE_LICENSE(DRIVER_LICENSE);
MODULE_VERSION(DRIVER_VERSION);
@@ -764,6 +765,9 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
return -EIO;
}

+ if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
+ dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
+
node = dev_to_node(&pdev->dev);

perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node);
diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
index 4358611..12f8b40 100644
--- a/drivers/ntb/test/ntb_pingpong.c
+++ b/drivers/ntb/test/ntb_pingpong.c
@@ -90,6 +90,9 @@ static unsigned long db_init = 0x7;
module_param(db_init, ulong, 0644);
MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");

+/* Only two-ports NTB devices are supported */
+#define PIDX NTB_DEF_PEER_IDX
+
struct pp_ctx {
struct ntb_dev *ntb;
u64 db_bits;
@@ -230,6 +233,9 @@ static int pp_probe(struct ntb_client *client,
}
}

+ if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
+ dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
+
pp = kmalloc(sizeof(*pp), GFP_KERNEL);
if (!pp) {
rc = -ENOMEM;
diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index 61bf2ef..690862d 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -120,6 +120,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);

#define MAX_MWS 16
+/* Only two-ports devices are supported */
+#define PIDX NTB_DEF_PEER_IDX

static struct dentry *tool_dbgfs;

@@ -919,6 +921,9 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
if (ntb_spad_is_unsafe(ntb))
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");

+ if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
+ dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
+
tc = kzalloc(sizeof(*tc), GFP_KERNEL);
if (!tc) {
rc = -ENOMEM;
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 5d1f260..fe175c7 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -140,6 +140,20 @@ enum ntb_width {
};

/**
+ * enum ntb_default_port - NTB default port number
+ * @NTB_PORT_PRI_USD: Default port of the NTB_TOPO_PRI/NTB_TOPO_B2B_USD
+ * topologies
+ * @NTB_PORT_SEC_DSD: Default port of the NTB_TOPO_SEC/NTB_TOPO_B2B_DSD
+ * topologies
+ */
+enum ntb_default_port {
+ NTB_PORT_PRI_USD,
+ NTB_PORT_SEC_DSD
+};
+#define NTB_DEF_PEER_CNT (1)
+#define NTB_DEF_PEER_IDX (0)
+
+/**
* struct ntb_client_ops - ntb client operations
* @probe: Notify client of a new device.
* @remove: Notify client to remove a device.
@@ -179,6 +193,10 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)

/**
* struct ntb_ctx_ops - ntb device operations
+ * @port_number: See ntb_port_number().
+ * @peer_port_count: See ntb_peer_port_count().
+ * @peer_port_number: See ntb_peer_port_number().
+ * @peer_port_idx: See ntb_peer_port_idx().
* @link_is_up: See ntb_link_is_up().
* @link_enable: See ntb_link_enable().
* @link_disable: See ntb_link_disable().
@@ -212,6 +230,11 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_write: See ntb_peer_spad_write().
*/
struct ntb_dev_ops {
+ int (*port_number)(struct ntb_dev *ntb);
+ int (*peer_port_count)(struct ntb_dev *ntb);
+ int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
+ int (*peer_port_idx)(struct ntb_dev *ntb, int port);
+
int (*link_is_up)(struct ntb_dev *ntb,
enum ntb_speed *speed, enum ntb_width *width);
int (*link_enable)(struct ntb_dev *ntb,
@@ -265,6 +288,9 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ !ops->peer_port_count == !ops->port_number &&
+ !ops->peer_port_number == !ops->port_number &&
+ !ops->peer_port_idx == !ops->port_number &&
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
@@ -442,6 +468,136 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_default_port_number() - get the default local port number
+ * @ntb: NTB device context.
+ *
+ * If hardware driver doesn't specify port_number() callback method, the NTB
+ * is considered with just two ports. So this method returns default local
+ * port number in compliance with topology.
+ *
+ * NOTE Don't call this method directly. The ntb_port_number() function should
+ * be used instead.
+ *
+ * Return: the default local port number
+ */
+int ntb_default_port_number(struct ntb_dev *ntb);
+
+/**
+ * ntb_default_port_count() - get the default number of peer device ports
+ * @ntb: NTB device context.
+ *
+ * By default hardware driver supports just one peer device.
+ *
+ * NOTE Don't call this method directly. The ntb_peer_port_count() function
+ * should be used instead.
+ *
+ * Return: the default number of peer ports
+ */
+int ntb_default_peer_port_count(struct ntb_dev *ntb);
+
+/**
+ * ntb_default_peer_port_number() - get the default peer port by given index
+ * @ntb: NTB device context.
+ * @idx: Peer port index (should not differ from zero).
+ *
+ * By default hardware driver supports just one peer device, so this method
+ * shall return the corresponding value from enum ntb_default_port.
+ *
+ * NOTE Don't call this method directly. The ntb_peer_port_number() function
+ * should be used instead.
+ *
+ * Return: the peer device port or negative value indicating an error
+ */
+int ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx);
+
+/**
+ * ntb_default_peer_port_idx() - get the default peer device port index by
+ * given port number
+ * @ntb: NTB device context.
+ * @port: Peer port number (should be one of enum ntb_default_port).
+ *
+ * By default hardware driver supports just one peer device, so while
+ * specified port-argument indicates peer port from enum ntb_default_port,
+ * the return value shall be zero.
+ *
+ * NOTE Don't call this method directly. The ntb_peer_port_idx() function
+ * should be used instead.
+ *
+ * Return: the peer port index or negative value indicating an error
+ */
+int ntb_default_peer_port_idx(struct ntb_dev *ntb, int port);
+
+/**
+ * ntb_port_number() - get the local port number
+ * @ntb: NTB device context.
+ *
+ * Hardware must support at least simple two-ports ntb connection
+ *
+ * Return: the local port number
+ */
+static inline int ntb_port_number(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->port_number)
+ return ntb_default_port_number(ntb);
+
+ return ntb->ops->port_number(ntb);
+}
+
+/**
+ * ntb_peer_port_count() - get the number of peer device ports
+ * @ntb: NTB device context.
+ *
+ * Hardware may support an access to memory of several remote domains
+ * over multi-port NTB devices. This method returns the number of peers,
+ * local device can have shared memory with.
+ *
+ * Return: the number of peer ports
+ */
+static inline int ntb_peer_port_count(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->peer_port_count)
+ return ntb_default_peer_port_count(ntb);
+
+ return ntb->ops->peer_port_count(ntb);
+}
+
+/**
+ * ntb_peer_port_number() - get the peer port by given index
+ * @ntb: NTB device context.
+ * @pidx: Peer port index.
+ *
+ * Peer ports are continuously enumerated by NTB API logic, so this method
+ * lets to retrieve port real number by its index.
+ *
+ * Return: the peer device port or negative value indicating an error
+ */
+static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+ if (!ntb->ops->peer_port_number)
+ return ntb_default_peer_port_number(ntb, pidx);
+
+ return ntb->ops->peer_port_number(ntb, pidx);
+}
+
+/**
+ * ntb_peer_port_idx() - get the peer device port index by given port number
+ * @ntb: NTB device context.
+ * @port: Peer port number.
+ *
+ * Inverse operation of ntb_peer_port_number(), so one can get port index
+ * by specified port number.
+ *
+ * Return: the peer port index or negative value indicating an error
+ */
+static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+ if (!ntb->ops->peer_port_idx)
+ return ntb_default_peer_port_idx(ntb, port);
+
+ return ntb->ops->peer_port_idx(ntb, port);
+}
+
+/**
* ntb_link_is_up() - get the current ntb link state
* @ntb: NTB device context.
* @speed: OUT - The link speed expressed as PCIe generation number.
--
2.6.6

2016-12-13 23:50:36

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 5/9] NTB: Alter Scratchpads API to support multi-ports devices

Even though there is no any real NTB hardware, which would have both more
than two ports and Scratchpad registers, it is logically correct to have
Scratchpad API accepting a peer port index as well. Intel/AMD drivers utilize
Primary and Secondary topology to split Scratchpad between connected root
devices. Since port-index API introduced, Intel/AMD NTB hardware drivers can
use device port to determine which Scratchpad registers actually belong to
local and peer devices. The same approach can be used if some potential
hardware in future will be multi-port and have some set of Scratchpads.
Here are the brief of changes in the API:
ntb_spad_count() - return number of Scratchpads per each port
ntb_peer_spad_addr(pidx, sidx) - address of Scratchpad register of the
peer device with pidx-index
ntb_peer_spad_read(pidx, sidx) - read specified Scratchpad register of the
peer with pidx-index
ntb_peer_spad_write(pidx, sidx) - write data to Scratchpad register of the
peer with pidx-index

Since there is hardware which doesn't support Scratchpad registers, the
corresponding API methods are now made optional.

Signed-off-by: Serge Semin <[email protected]>
---
drivers/ntb/hw/amd/ntb_hw_amd.c | 14 +++----
drivers/ntb/hw/intel/ntb_hw_intel.c | 14 +++----
drivers/ntb/ntb_transport.c | 17 ++++-----
drivers/ntb/test/ntb_perf.c | 6 +--
drivers/ntb/test/ntb_pingpong.c | 8 +++-
drivers/ntb/test/ntb_tool.c | 21 ++++++++--
include/linux/ntb.h | 76 +++++++++++++++++++++++--------------
7 files changed, 98 insertions(+), 58 deletions(-)

diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 6a41c38..bc537aa 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -433,30 +433,30 @@ static int amd_ntb_spad_write(struct ntb_dev *ntb,
return 0;
}

-static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
void __iomem *mmio = ndev->self_mmio;
u32 offset;

- if (idx < 0 || idx >= ndev->spad_count)
+ if (sidx < 0 || sidx >= ndev->spad_count)
return -EINVAL;

- offset = ndev->peer_spad + (idx << 2);
+ offset = ndev->peer_spad + (sidx << 2);
return readl(mmio + AMD_SPAD_OFFSET + offset);
}

-static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
- int idx, u32 val)
+static int amd_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+ int sidx, u32 val)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
void __iomem *mmio = ndev->self_mmio;
u32 offset;

- if (idx < 0 || idx >= ndev->spad_count)
+ if (sidx < 0 || sidx >= ndev->spad_count)
return -EINVAL;

- offset = ndev->peer_spad + (idx << 2);
+ offset = ndev->peer_spad + (sidx << 2);
writel(val, mmio + AMD_SPAD_OFFSET + offset);

return 0;
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 4b84012..7bb14cb 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1409,30 +1409,30 @@ static int intel_ntb_spad_write(struct ntb_dev *ntb,
ndev->self_reg->spad);
}

-static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr,
+ return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
ndev->peer_reg->spad);
}

-static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_read(ndev, idx,
+ return ndev_spad_read(ndev, sidx,
ndev->peer_mmio +
ndev->peer_reg->spad);
}

-static int intel_ntb_peer_spad_write(struct ntb_dev *ntb,
- int idx, u32 val)
+static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+ int sidx, u32 val)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);

- return ndev_spad_write(ndev, idx, val,
+ return ndev_spad_write(ndev, sidx, val,
ndev->peer_mmio +
ndev->peer_reg->spad);
}
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 4d5b160..28aaba3 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -875,17 +875,17 @@ static void ntb_transport_link_work(struct work_struct *work)
size = max_mw_size;

spad = MW0_SZ_HIGH + (i * 2);
- ntb_peer_spad_write(ndev, spad, upper_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, spad, upper_32_bits(size));

spad = MW0_SZ_LOW + (i * 2);
- ntb_peer_spad_write(ndev, spad, lower_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, spad, lower_32_bits(size));
}

- ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count);
+ ntb_peer_spad_write(ndev, PIDX, NUM_MWS, nt->mw_count);

- ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count);
+ ntb_peer_spad_write(ndev, PIDX, NUM_QPS, nt->qp_count);

- ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION);
+ ntb_peer_spad_write(ndev, PIDX, VERSION, NTB_TRANSPORT_VERSION);

/* Query the remote side for its info */
val = ntb_spad_read(ndev, VERSION);
@@ -961,10 +961,10 @@ static void ntb_qp_link_work(struct work_struct *work)

val = ntb_spad_read(nt->ndev, QP_LINKS);

- ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num));
+ ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num));

/* query remote spad for qp ready bits */
- ntb_peer_spad_read(nt->ndev, QP_LINKS);
+ ntb_peer_spad_read(nt->ndev, PIDX, QP_LINKS);
dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);

/* See if the remote side is up */
@@ -2141,8 +2141,7 @@ void ntb_transport_link_down(struct ntb_transport_qp *qp)

val = ntb_spad_read(qp->ndev, QP_LINKS);

- ntb_peer_spad_write(qp->ndev, QP_LINKS,
- val & ~BIT(qp->qp_num));
+ ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val & ~BIT(qp->qp_num));

if (qp->link_is_up)
ntb_send_link_down(qp);
diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index cbff0b4..0a493ba 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -516,9 +516,9 @@ static void perf_link_work(struct work_struct *work)
if (max_mw_size && size > max_mw_size)
size = max_mw_size;

- ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
- ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
- ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
+ ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size));
+ ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION);

/* now read what peer wrote */
val = ntb_spad_read(ndev, VERSION);
diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
index 12f8b40..938a18b 100644
--- a/drivers/ntb/test/ntb_pingpong.c
+++ b/drivers/ntb/test/ntb_pingpong.c
@@ -138,7 +138,7 @@ static void pp_ping(unsigned long ctx)
"Ping bits %#llx read %#x write %#x\n",
db_bits, spad_rd, spad_wr);

- ntb_peer_spad_write(pp->ntb, 0, spad_wr);
+ ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr);
ntb_peer_db_set(pp->ntb, db_bits);
ntb_db_clear_mask(pp->ntb, db_mask);

@@ -225,6 +225,12 @@ static int pp_probe(struct ntb_client *client,
}
}

+ if (ntb_spad_count(ntb) < 1) {
+ dev_dbg(&ntb->dev, "no enough scratchpads\n");
+ rc = -EINVAL;
+ goto err_pp;
+ }
+
if (ntb_spad_is_unsafe(ntb)) {
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
if (!unsafe) {
diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index cb69247..f002bf4 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -462,13 +462,22 @@ static TOOL_FOPS_RDWR(tool_spad_fops,
tool_spad_read,
tool_spad_write);

+static u32 ntb_tool_peer_spad_read(struct ntb_dev *ntb, int sidx)
+{
+ return ntb_peer_spad_read(ntb, PIDX, sidx);
+}
+
static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
size_t size, loff_t *offp)
{
struct tool_ctx *tc = filep->private_data;

- return tool_spadfn_read(tc, ubuf, size, offp,
- tc->ntb->ops->peer_spad_read);
+ return tool_spadfn_read(tc, ubuf, size, offp, ntb_tool_peer_spad_read);
+}
+
+static int ntb_tool_peer_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
+{
+ return ntb_peer_spad_write(ntb, PIDX, sidx, val);
}

static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
@@ -477,7 +486,7 @@ static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
struct tool_ctx *tc = filep->private_data;

return tool_spadfn_write(tc, ubuf, size, offp,
- tc->ntb->ops->peer_spad_write);
+ ntb_tool_peer_spad_write);
}

static TOOL_FOPS_RDWR(tool_peer_spad_fops,
@@ -926,6 +935,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
goto err_tc;
}

+ if (ntb_spad_count(ntb) < 1) {
+ dev_dbg(&ntb->dev, "no enough scratchpads\n");
+ rc = -EINVAL;
+ goto err_tc;
+ }
+
if (ntb_db_is_unsafe(ntb))
dev_dbg(&ntb->dev, "doorbell is unsafe\n");

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index f6ec88f..a54e2be 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -288,13 +288,14 @@ struct ntb_dev_ops {
int (*spad_is_unsafe)(struct ntb_dev *ntb);
int (*spad_count)(struct ntb_dev *ntb);

- u32 (*spad_read)(struct ntb_dev *ntb, int idx);
- int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+ u32 (*spad_read)(struct ntb_dev *ntb, int sidx);
+ int (*spad_write)(struct ntb_dev *ntb, int sidx, u32 val);

- int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
+ int (*peer_spad_addr)(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr);
- u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
- int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+ u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
+ int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
+ u32 val);
};

static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@@ -335,13 +336,12 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
- /* ops->spad_is_unsafe && */
- ops->spad_count &&
- ops->spad_read &&
- ops->spad_write &&
- /* ops->peer_spad_addr && */
- /* ops->peer_spad_read && */
- ops->peer_spad_write &&
+ /* !ops->spad_is_unsafe == !ops->spad_count && */
+ !ops->spad_read == !ops->spad_count &&
+ !ops->spad_write == !ops->spad_count &&
+ /* !ops->peer_spad_addr == !ops->spad_count && */
+ /* !ops->peer_spad_read == !ops->spad_count && */
+ !ops->peer_spad_write == !ops->spad_count &&
1;
}

@@ -1172,51 +1172,62 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
}

/**
- * ntb_mw_count() - get the number of scratchpads
+ * ntb_spad_count() - get the number of scratchpads
* @ntb: NTB device context.
*
* Hardware and topology may support a different number of scratchpads.
+ * Although it must be the same for all ports per NTB device.
*
* Return: the number of scratchpads.
*/
static inline int ntb_spad_count(struct ntb_dev *ntb)
{
+ if (!ntb->ops->spad_count)
+ return 0;
+
return ntb->ops->spad_count(ntb);
}

/**
* ntb_spad_read() - read the local scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @sidx: Scratchpad index.
*
* Read the local scratchpad register, and return the value.
*
* Return: The value of the local scratchpad register.
*/
-static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_spad_read(struct ntb_dev *ntb, int sidx)
{
- return ntb->ops->spad_read(ntb, idx);
+ if (!ntb->ops->spad_read)
+ return ~(u32)0;
+
+ return ntb->ops->spad_read(ntb, sidx);
}

/**
* ntb_spad_write() - write the local scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @sidx: Scratchpad index.
* @val: Scratchpad value.
*
* Write the value to the local scratchpad register.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
{
- return ntb->ops->spad_write(ntb, idx, val);
+ if (!ntb->ops->spad_write)
+ return -EINVAL;
+
+ return ntb->ops->spad_write(ntb, sidx, val);
}

/**
* ntb_peer_spad_addr() - address of the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
* @spad_addr: OUT - The address of the peer scratchpad register.
*
* Return the address of the peer doorbell register. This may be used, for
@@ -1224,42 +1235,51 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
phys_addr_t *spad_addr)
{
if (!ntb->ops->peer_spad_addr)
return -EINVAL;

- return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
+ return ntb->ops->peer_spad_addr(ntb, pidx, sidx, spad_addr);
}

/**
* ntb_peer_spad_read() - read the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
*
* Read the peer scratchpad register, and return the value.
*
* Return: The value of the local scratchpad register.
*/
-static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
{
- return ntb->ops->peer_spad_read(ntb, idx);
+ if (!ntb->ops->peer_spad_read)
+ return ~(u32)0;
+
+ return ntb->ops->peer_spad_read(ntb, pidx, sidx);
}

/**
* ntb_peer_spad_write() - write the peer scratchpad register
* @ntb: NTB device context.
- * @idx: Scratchpad index.
+ * @pidx: Port index of peer device.
+ * @sidx: Scratchpad index.
* @val: Scratchpad value.
*
* Write the value to the peer scratchpad register.
*
* Return: Zero on success, otherwise an error number.
*/
-static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
+ u32 val)
{
- return ntb->ops->peer_spad_write(ntb, idx, val);
+ if (!ntb->ops->peer_spad_write)
+ return -EINVAL;
+
+ return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
}

#endif
--
2.6.6

2016-12-13 23:50:28

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 6/9] NTB: Add Messaging NTB API

Some IDT NTB-capable PCIe-switches have message registers to communicate with
peer devices. This patch adds new NTB API callback methods, which can be used
to utilize these registers functionality:
ntb_msg_count(); - get number of message registers
ntb_msg_inbits(); - get bitfield of inbound message registers status
ntb_msg_outbits(); - get bitfield of outbound message registers status
ntb_msg_read_sts(); - read the inbound and outbound message registers status
ntb_msg_clear_sts(); - clear status bits of message registers
ntb_msg_set_mask(); - mask interrupts raised by status bits of message
registers.
ntb_msg_clear_mask(); - clear interrupts mask bits of message registers
ntb_msg_read(midx, *pidx); - read message register with specified index,
additionally getting peer port index which data received from
ntb_msg_write(midx, pidx); - write data to the specified message register
sending it to the passed peer device connected over a pidx port
ntb_msg_event(); - notify driver context of a new message event

Of course there is hardware which doesn't support Message registers, so
this API is made optional.

Acked-by: Allen Hubbe <[email protected]>
Signed-off-by: Serge Semin <[email protected]>
---
drivers/ntb/ntb.c | 13 ++++
include/linux/ntb.h | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+)

diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 2551bb2..03b80d8 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -193,6 +193,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
}
EXPORT_SYMBOL(ntb_db_event);

+void ntb_msg_event(struct ntb_dev *ntb)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+ {
+ if (ntb->ctx_ops && ntb->ctx_ops->msg_event)
+ ntb->ctx_ops->msg_event(ntb->ctx);
+ }
+ spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_msg_event);
+
int ntb_default_port_number(struct ntb_dev *ntb)
{
switch (ntb->topo) {
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index a54e2be..76c56d5 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -178,10 +178,12 @@ static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops)
* struct ntb_ctx_ops - ntb driver context operations
* @link_event: See ntb_link_event().
* @db_event: See ntb_db_event().
+ * @msg_event: See ntb_msg_event().
*/
struct ntb_ctx_ops {
void (*link_event)(void *ctx);
void (*db_event)(void *ctx, int db_vector);
+ void (*msg_event)(void *ctx);
};

static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
@@ -190,6 +192,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
return
/* ops->link_event && */
/* ops->db_event && */
+ /* ops->msg_event && */
1;
}

@@ -234,6 +237,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_addr: See ntb_peer_spad_addr().
* @peer_spad_read: See ntb_peer_spad_read().
* @peer_spad_write: See ntb_peer_spad_write().
+ * @msg_count: See ntb_msg_count().
+ * @msg_inbits: See ntb_msg_inbits().
+ * @msg_outbits: See ntb_msg_outbits().
+ * @msg_read_sts: See ntb_msg_read_sts().
+ * @msg_clear_sts: See ntb_msg_clear_sts().
+ * @msg_set_mask: See ntb_msg_set_mask().
+ * @msg_clear_mask: See ntb_msg_clear_mask().
+ * @msg_read: See ntb_msg_read().
+ * @msg_write: See ntb_msg_write().
*/
struct ntb_dev_ops {
int (*port_number)(struct ntb_dev *ntb);
@@ -296,6 +308,16 @@ struct ntb_dev_ops {
u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
u32 val);
+
+ int (*msg_count)(struct ntb_dev *ntb);
+ u64 (*msg_inbits)(struct ntb_dev *ntb);
+ u64 (*msg_outbits)(struct ntb_dev *ntb);
+ u64 (*msg_read_sts)(struct ntb_dev *ntb);
+ int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits);
+ int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg);
+ int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg);
};

static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@@ -342,6 +364,15 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->peer_spad_addr == !ops->spad_count && */
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&
+
+ !ops->msg_inbits == !ops->msg_count &&
+ !ops->msg_outbits == !ops->msg_count &&
+ !ops->msg_read_sts == !ops->msg_count &&
+ !ops->msg_clear_sts == !ops->msg_count &&
+ /* !ops->msg_set_mask == !ops->msg_count && */
+ /* !ops->msg_clear_mask == !ops->msg_count && */
+ !ops->msg_read == !ops->msg_count &&
+ !ops->msg_write == !ops->msg_count &&
1;
}

@@ -485,6 +516,18 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_msg_event() - notify driver context of a message event
+ * @ntb: NTB device context.
+ *
+ * Notify the driver context of a message event. If hardware supports
+ * message registers, this event indicates, that a new message arrived in
+ * some incoming message register or last sent message couldn't be delivered.
+ * The events can be masked/unmasked by the methods ntb_msg_set_mask() and
+ * ntb_msg_clear_mask().
+ */
+void ntb_msg_event(struct ntb_dev *ntb);
+
+/**
* ntb_default_port_number() - get the default local port number
* @ntb: NTB device context.
*
@@ -1282,4 +1325,166 @@ static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
}

+/**
+ * ntb_msg_count() - get the number of message registers
+ * @ntb: NTB device context.
+ *
+ * Hardware may support a different number of message registers.
+ *
+ * Return: the number of message registers.
+ */
+static inline int ntb_msg_count(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_count)
+ return 0;
+
+ return ntb->ops->msg_count(ntb);
+}
+
+/**
+ * ntb_msg_inbits() - get a bitfield of inbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitfield of status and mask registers, which related
+ * to inbound message registers.
+ *
+ * Return: bitfield of inbound message registers.
+ */
+static inline u64 ntb_msg_inbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_inbits)
+ return 0;
+
+ return ntb->ops->msg_inbits(ntb);
+}
+
+/**
+ * ntb_msg_outbits() - get a bitfield of outbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitfield of status and mask registers, which related
+ * to outbound message registers.
+ *
+ * Return: bitfield of outbound message registers.
+ */
+static inline u64 ntb_msg_outbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_outbits)
+ return 0;
+
+ return ntb->ops->msg_outbits(ntb);
+}
+
+/**
+ * ntb_msg_read_sts() - read the message registers status
+ * @ntb: NTB device context.
+ *
+ * Read the status of message register. Inbound and outbound message registers
+ * related bits can be filtered by masks retrieved from ntb_msg_inbits() and
+ * ntb_msg_outbits().
+ *
+ * Return: status bits of message registers
+ */
+static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_read_sts)
+ return 0;
+
+ return ntb->ops->msg_read_sts(ntb);
+}
+
+/**
+ * ntb_msg_clear_sts() - clear status bits of message registers
+ * @ntb: NTB device context.
+ * @sts_bits: Status bits to clear.
+ *
+ * Clear bits in the status register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
+{
+ if (!ntb->ops->msg_clear_sts)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_sts(ntb, sts_bits);
+}
+
+/**
+ * ntb_msg_set_mask() - set mask of message register status bits
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits.
+ *
+ * Mask the message registers status bits from raising the message event.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_set_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_set_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_clear_mask() - clear message registers mask
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits to clear.
+ *
+ * Clear bits in the message events mask register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_clear_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_read() - read message register with specified index
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: OUT - Port index of peer device a message retrieved from
+ * @msg: OUT - Data
+ *
+ * Read data from the specified message register. Source port index of a
+ * message is retrieved as well.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx,
+ u32 *msg)
+{
+ if (!ntb->ops->msg_read)
+ return -EINVAL;
+
+ return ntb->ops->msg_read(ntb, midx, pidx, msg);
+}
+
+/**
+ * ntb_msg_write() - write data to the specified message register
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: Port index of peer device a message being sent to
+ * @msg: Data to send
+ *
+ * Send data to a specified peer device using the defined message register.
+ * Message event can be raised if the midx registers isn't empty while
+ * calling this method and the corresponding interrupt isn't masked.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx,
+ u32 msg)
+{
+ if (!ntb->ops->msg_write)
+ return -EINVAL;
+
+ return ntb->ops->msg_write(ntb, midx, pidx, msg);
+}
+
#endif
--
2.6.6

2016-12-13 23:50:26

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 9/9] NTB: Add ntb.h comments

Signed-off-by: Serge Semin <[email protected]>
---
include/linux/ntb.h | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 6d46179..dab0a1b 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -326,12 +326,17 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ /* Port operations are required */
!ops->peer_port_count == !ops->port_number &&
!ops->peer_port_number == !ops->port_number &&
!ops->peer_port_idx == !ops->port_number &&
+
+ /* Link operations are requiered */
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
+
+ /* One or both MW interfaces should be developed */
ops->mw_count &&
ops->mw_get_align &&
(ops->mw_set_trans ||
@@ -341,12 +346,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->peer_mw_get_addr &&
/* ops->peer_mw_clear_trans && */

+ /* Doorbell operations are mostly required */
/* ops->db_is_unsafe && */
ops->db_valid_mask &&
-
/* both set, or both unset */
- (!ops->db_vector_count == !ops->db_vector_mask) &&
-
+ (!ops->db_vector_count == !ops->db_vector_mask) &&
ops->db_read &&
/* ops->db_set && */
ops->db_clear &&
@@ -360,6 +364,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
+
+ /* Scrachpads interface is optional */
/* !ops->spad_is_unsafe == !ops->spad_count && */
!ops->spad_read == !ops->spad_count &&
!ops->spad_write == !ops->spad_count &&
@@ -367,6 +373,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&

+ /* Messaging interface is optional */
!ops->msg_inbits == !ops->msg_count &&
!ops->msg_outbits == !ops->msg_count &&
!ops->msg_read_sts == !ops->msg_count &&
@@ -387,13 +394,12 @@ struct ntb_client {
struct device_driver drv;
const struct ntb_client_ops ops;
};
-
#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)

/**
* struct ntb_device - ntb device
* @dev: Linux device object.
- * @pdev: Pci device entry of the ntb.
+ * @pdev: PCI device entry of the ntb.
* @topo: Detected topology of the ntb.
* @ops: See &ntb_dev_ops.
* @ctx: See &ntb_ctx_ops.
@@ -414,7 +420,6 @@ struct ntb_dev {
/* block unregister until device is fully released */
struct completion released;
};
-
#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)

/**
@@ -511,7 +516,7 @@ void ntb_link_event(struct ntb_dev *ntb);
* multiple interrupt vectors for doorbells, the vector number indicates which
* vector received the interrupt. The vector number is relative to the first
* vector used for doorbells, starting at zero, and must be less than
- ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
+ * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
* doorbell bits need service, and ntb_db_vector_mask() to determine which of
* those bits are associated with the vector number.
*/
--
2.6.6

2016-12-14 07:07:51

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v3 1/9] NTB: Make link-state API being declared first

From: Serge Semin
> Since link operations are usually performed before memory window access
> operations, it's logically better to declare link-related API before any
> of MW/Doorbell/Scratchpad methods.
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

> ---
> include/linux/ntb.h | 137 ++++++++++++++++++++++++++--------------------------
> 1 file changed, 69 insertions(+), 68 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 6f47562..5d1f260 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -179,13 +179,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops
> *ops)
>
> /**
> * struct ntb_ctx_ops - ntb device operations
> + * @link_is_up: See ntb_link_is_up().
> + * @link_enable: See ntb_link_enable().
> + * @link_disable: See ntb_link_disable().
> * @mw_count: See ntb_mw_count().
> * @mw_get_range: See ntb_mw_get_range().
> * @mw_set_trans: See ntb_mw_set_trans().
> * @mw_clear_trans: See ntb_mw_clear_trans().
> - * @link_is_up: See ntb_link_is_up().
> - * @link_enable: See ntb_link_enable().
> - * @link_disable: See ntb_link_disable().
> * @db_is_unsafe: See ntb_db_is_unsafe().
> * @db_valid_mask: See ntb_db_valid_mask().
> * @db_vector_count: See ntb_db_vector_count().
> @@ -212,6 +212,12 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_write: See ntb_peer_spad_write().
> */
> struct ntb_dev_ops {
> + int (*link_is_up)(struct ntb_dev *ntb,
> + enum ntb_speed *speed, enum ntb_width *width);
> + int (*link_enable)(struct ntb_dev *ntb,
> + enum ntb_speed max_speed, enum ntb_width max_width);
> + int (*link_disable)(struct ntb_dev *ntb);
> +
> int (*mw_count)(struct ntb_dev *ntb);
> int (*mw_get_range)(struct ntb_dev *ntb, int idx,
> phys_addr_t *base, resource_size_t *size,
> @@ -220,12 +226,6 @@ struct ntb_dev_ops {
> dma_addr_t addr, resource_size_t size);
> int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
>
> - int (*link_is_up)(struct ntb_dev *ntb,
> - enum ntb_speed *speed, enum ntb_width *width);
> - int (*link_enable)(struct ntb_dev *ntb,
> - enum ntb_speed max_speed, enum ntb_width max_width);
> - int (*link_disable)(struct ntb_dev *ntb);
> -
> int (*db_is_unsafe)(struct ntb_dev *ntb);
> u64 (*db_valid_mask)(struct ntb_dev *ntb);
> int (*db_vector_count)(struct ntb_dev *ntb);
> @@ -265,13 +265,14 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> {
> /* commented callbacks are not required: */
> return
> + ops->link_is_up &&
> + ops->link_enable &&
> + ops->link_disable &&
> ops->mw_count &&
> ops->mw_get_range &&
> ops->mw_set_trans &&
> /* ops->mw_clear_trans && */
> - ops->link_is_up &&
> - ops->link_enable &&
> - ops->link_disable &&
> +
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
>
> @@ -441,6 +442,62 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_link_is_up() - get the current ntb link state
> + * @ntb: NTB device context.
> + * @speed: OUT - The link speed expressed as PCIe generation number.
> + * @width: OUT - The link width expressed as the number of PCIe lanes.
> + *
> + * Get the current state of the ntb link. It is recommended to query the link
> + * state once after every link event. It is safe to query the link state in
> + * the context of the link event callback.
> + *
> + * Return: One if the link is up, zero if the link is down, otherwise a
> + * negative value indicating the error number.
> + */
> +static inline int ntb_link_is_up(struct ntb_dev *ntb,
> + enum ntb_speed *speed, enum ntb_width *width)
> +{
> + return ntb->ops->link_is_up(ntb, speed, width);
> +}
> +
> +/**
> + * ntb_link_enable() - enable the link on the secondary side of the ntb
> + * @ntb: NTB device context.
> + * @max_speed: The maximum link speed expressed as PCIe generation number.
> + * @max_width: The maximum link width expressed as the number of PCIe lanes.
> + *
> + * Enable the link on the secondary side of the ntb. This can only be done
> + * from the primary side of the ntb in primary or b2b topology. The ntb device
> + * should train the link to its maximum speed and width, or the requested speed
> + * and width, whichever is smaller, if supported.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_link_enable(struct ntb_dev *ntb,
> + enum ntb_speed max_speed,
> + enum ntb_width max_width)
> +{
> + return ntb->ops->link_enable(ntb, max_speed, max_width);
> +}
> +
> +/**
> + * ntb_link_disable() - disable the link on the secondary side of the ntb
> + * @ntb: NTB device context.
> + *
> + * Disable the link on the secondary side of the ntb. This can only be
> + * done from the primary side of the ntb in primary or b2b topology. The ntb
> + * device should disable the link. Returning from this call must indicate that
> + * a barrier has passed, though with no more writes may pass in either
> + * direction across the link, except if this call returns an error number.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_link_disable(struct ntb_dev *ntb)
> +{
> + return ntb->ops->link_disable(ntb);
> +}
> +
> +/**
> * ntb_mw_count() - get the number of memory windows
> * @ntb: NTB device context.
> *
> @@ -517,62 +574,6 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
> }
>
> /**
> - * ntb_link_is_up() - get the current ntb link state
> - * @ntb: NTB device context.
> - * @speed: OUT - The link speed expressed as PCIe generation number.
> - * @width: OUT - The link width expressed as the number of PCIe lanes.
> - *
> - * Get the current state of the ntb link. It is recommended to query the link
> - * state once after every link event. It is safe to query the link state in
> - * the context of the link event callback.
> - *
> - * Return: One if the link is up, zero if the link is down, otherwise a
> - * negative value indicating the error number.
> - */
> -static inline int ntb_link_is_up(struct ntb_dev *ntb,
> - enum ntb_speed *speed, enum ntb_width *width)
> -{
> - return ntb->ops->link_is_up(ntb, speed, width);
> -}
> -
> -/**
> - * ntb_link_enable() - enable the link on the secondary side of the ntb
> - * @ntb: NTB device context.
> - * @max_speed: The maximum link speed expressed as PCIe generation number.
> - * @max_width: The maximum link width expressed as the number of PCIe lanes.
> - *
> - * Enable the link on the secondary side of the ntb. This can only be done
> - * from the primary side of the ntb in primary or b2b topology. The ntb device
> - * should train the link to its maximum speed and width, or the requested speed
> - * and width, whichever is smaller, if supported.
> - *
> - * Return: Zero on success, otherwise an error number.
> - */
> -static inline int ntb_link_enable(struct ntb_dev *ntb,
> - enum ntb_speed max_speed,
> - enum ntb_width max_width)
> -{
> - return ntb->ops->link_enable(ntb, max_speed, max_width);
> -}
> -
> -/**
> - * ntb_link_disable() - disable the link on the secondary side of the ntb
> - * @ntb: NTB device context.
> - *
> - * Disable the link on the secondary side of the ntb. This can only be
> - * done from the primary side of the ntb in primary or b2b topology. The ntb
> - * device should disable the link. Returning from this call must indicate that
> - * a barrier has passed, though with no more writes may pass in either
> - * direction across the link, except if this call returns an error number.
> - *
> - * Return: Zero on success, otherwise an error number.
> - */
> -static inline int ntb_link_disable(struct ntb_dev *ntb)
> -{
> - return ntb->ops->link_disable(ntb);
> -}
> -
> -/**
> * ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
> * @ntb: NTB device context.
> *
> --
> 2.6.6


2016-12-14 07:08:12

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v3 2/9] NTB: Add indexed ports NTB API

From: Serge Semin
> There is some NTB hardware, which can combine more than just two domains
> over NTB. For instance, some IDT PCIe-switches can have NTB-functions
> activated on more than two-ports. The different domains are distinguished
> by ports they are connected to. So the new port-related methods are added to
> the NTB API:
> ntb_port_number() - return local port
> ntb_peer_port_count() - return number of peers local port can connect to
> ntb_peer_port_number(pdix) - return port number by it index
> ntb_peer_port_idx(port) - return port index by it number
>
> Current test-drivers aren't changed much. They still support two-ports devices
> for the time being while multi-ports hardware drivers aren't added.
>
> By default port-related API is declared for two-ports hardware.
> So corresponding hardware drivers won't need to implement it.
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

> ---
> drivers/ntb/ntb.c | 54 ++++++++++++++
> drivers/ntb/ntb_transport.c | 6 ++
> drivers/ntb/test/ntb_perf.c | 4 ++
> drivers/ntb/test/ntb_pingpong.c | 6 ++
> drivers/ntb/test/ntb_tool.c | 5 ++
> include/linux/ntb.h | 156 ++++++++++++++++++++++++++++++++++++++++
> 6 files changed, 231 insertions(+)
>
> diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
> index 2e25307..1e92e52 100644
> --- a/drivers/ntb/ntb.c
> +++ b/drivers/ntb/ntb.c
> @@ -191,6 +191,60 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
> }
> EXPORT_SYMBOL(ntb_db_event);
>
> +int ntb_default_port_number(struct ntb_dev *ntb)
> +{
> + switch (ntb->topo) {
> + case NTB_TOPO_PRI:
> + case NTB_TOPO_B2B_USD:
> + return NTB_PORT_PRI_USD;
> + case NTB_TOPO_SEC:
> + case NTB_TOPO_B2B_DSD:
> + return NTB_PORT_SEC_DSD;
> + default:
> + break;
> + }
> +
> + return -EINVAL;
> +}
> +EXPORT_SYMBOL(ntb_default_port_number);
> +
> +int ntb_default_peer_port_count(struct ntb_dev *ntb)
> +{
> + return NTB_DEF_PEER_CNT;
> +}
> +EXPORT_SYMBOL(ntb_default_peer_port_count);
> +
> +int ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx)
> +{
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> + switch (ntb->topo) {
> + case NTB_TOPO_PRI:
> + case NTB_TOPO_B2B_USD:
> + return NTB_PORT_SEC_DSD;
> + case NTB_TOPO_SEC:
> + case NTB_TOPO_B2B_DSD:
> + return NTB_PORT_PRI_USD;
> + default:
> + break;
> + }
> +
> + return -EINVAL;
> +}
> +EXPORT_SYMBOL(ntb_default_peer_port_number);
> +
> +int ntb_default_peer_port_idx(struct ntb_dev *ntb, int port)
> +{
> + int peer_port = ntb_default_peer_port_number(ntb, NTB_DEF_PEER_IDX);
> +
> + if (peer_port == -EINVAL || port != peer_port)
> + return -EINVAL;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(ntb_default_peer_port_idx);
> +
> static int ntb_probe(struct device *dev)
> {
> struct ntb_dev *ntb;
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 4eb8adb..10518b7 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -94,6 +94,9 @@ MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");
>
> static struct dentry *nt_debugfs_dir;
>
> +/* Only two-ports NTB devices are supported */
> +#define PIDX NTB_DEF_PEER_IDX
> +
> struct ntb_queue_entry {
> /* ntb_queue list reference */
> struct list_head entry;
> @@ -1083,6 +1086,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct
> ntb_dev *ndev)
> dev_dbg(&ndev->dev,
> "scratchpad is unsafe, proceed anyway...\n");
>
> + if (ntb_peer_port_count(ndev) != NTB_DEF_PEER_CNT)
> + dev_warn(&ndev->dev, "Multi-port NTB devices unsupported\n");
> +
> node = dev_to_node(&ndev->dev);
>
> nt = kzalloc_node(sizeof(*nt), GFP_KERNEL, node);
> diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
> index e75d4fd..c908b3a 100644
> --- a/drivers/ntb/test/ntb_perf.c
> +++ b/drivers/ntb/test/ntb_perf.c
> @@ -76,6 +76,7 @@
> #define DMA_RETRIES 20
> #define SZ_4G (1ULL << 32)
> #define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */
> +#define PIDX NTB_DEF_PEER_IDX
>
> MODULE_LICENSE(DRIVER_LICENSE);
> MODULE_VERSION(DRIVER_VERSION);
> @@ -764,6 +765,9 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
> return -EIO;
> }
>
> + if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
> + dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
> +
> node = dev_to_node(&pdev->dev);
>
> perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node);
> diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
> index 4358611..12f8b40 100644
> --- a/drivers/ntb/test/ntb_pingpong.c
> +++ b/drivers/ntb/test/ntb_pingpong.c
> @@ -90,6 +90,9 @@ static unsigned long db_init = 0x7;
> module_param(db_init, ulong, 0644);
> MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");
>
> +/* Only two-ports NTB devices are supported */
> +#define PIDX NTB_DEF_PEER_IDX
> +
> struct pp_ctx {
> struct ntb_dev *ntb;
> u64 db_bits;
> @@ -230,6 +233,9 @@ static int pp_probe(struct ntb_client *client,
> }
> }
>
> + if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
> + dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
> +
> pp = kmalloc(sizeof(*pp), GFP_KERNEL);
> if (!pp) {
> rc = -ENOMEM;
> diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
> index 61bf2ef..690862d 100644
> --- a/drivers/ntb/test/ntb_tool.c
> +++ b/drivers/ntb/test/ntb_tool.c
> @@ -120,6 +120,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
> MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
>
> #define MAX_MWS 16
> +/* Only two-ports devices are supported */
> +#define PIDX NTB_DEF_PEER_IDX
>
> static struct dentry *tool_dbgfs;
>
> @@ -919,6 +921,9 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> if (ntb_spad_is_unsafe(ntb))
> dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
>
> + if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
> + dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
> +
> tc = kzalloc(sizeof(*tc), GFP_KERNEL);
> if (!tc) {
> rc = -ENOMEM;
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 5d1f260..fe175c7 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -140,6 +140,20 @@ enum ntb_width {
> };
>
> /**
> + * enum ntb_default_port - NTB default port number
> + * @NTB_PORT_PRI_USD: Default port of the NTB_TOPO_PRI/NTB_TOPO_B2B_USD
> + * topologies
> + * @NTB_PORT_SEC_DSD: Default port of the NTB_TOPO_SEC/NTB_TOPO_B2B_DSD
> + * topologies
> + */
> +enum ntb_default_port {
> + NTB_PORT_PRI_USD,
> + NTB_PORT_SEC_DSD
> +};
> +#define NTB_DEF_PEER_CNT (1)
> +#define NTB_DEF_PEER_IDX (0)
> +
> +/**
> * struct ntb_client_ops - ntb client operations
> * @probe: Notify client of a new device.
> * @remove: Notify client to remove a device.
> @@ -179,6 +193,10 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
>
> /**
> * struct ntb_ctx_ops - ntb device operations
> + * @port_number: See ntb_port_number().
> + * @peer_port_count: See ntb_peer_port_count().
> + * @peer_port_number: See ntb_peer_port_number().
> + * @peer_port_idx: See ntb_peer_port_idx().
> * @link_is_up: See ntb_link_is_up().
> * @link_enable: See ntb_link_enable().
> * @link_disable: See ntb_link_disable().
> @@ -212,6 +230,11 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @peer_spad_write: See ntb_peer_spad_write().
> */
> struct ntb_dev_ops {
> + int (*port_number)(struct ntb_dev *ntb);
> + int (*peer_port_count)(struct ntb_dev *ntb);
> + int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
> + int (*peer_port_idx)(struct ntb_dev *ntb, int port);
> +
> int (*link_is_up)(struct ntb_dev *ntb,
> enum ntb_speed *speed, enum ntb_width *width);
> int (*link_enable)(struct ntb_dev *ntb,
> @@ -265,6 +288,9 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> {
> /* commented callbacks are not required: */
> return
> + !ops->peer_port_count == !ops->port_number &&
> + !ops->peer_port_number == !ops->port_number &&
> + !ops->peer_port_idx == !ops->port_number &&
> ops->link_is_up &&
> ops->link_enable &&
> ops->link_disable &&
> @@ -442,6 +468,136 @@ void ntb_link_event(struct ntb_dev *ntb);
> void ntb_db_event(struct ntb_dev *ntb, int vector);
>
> /**
> + * ntb_default_port_number() - get the default local port number
> + * @ntb: NTB device context.
> + *
> + * If hardware driver doesn't specify port_number() callback method, the NTB
> + * is considered with just two ports. So this method returns default local
> + * port number in compliance with topology.
> + *
> + * NOTE Don't call this method directly. The ntb_port_number() function should
> + * be used instead.
> + *
> + * Return: the default local port number
> + */
> +int ntb_default_port_number(struct ntb_dev *ntb);
> +
> +/**
> + * ntb_default_port_count() - get the default number of peer device ports
> + * @ntb: NTB device context.
> + *
> + * By default hardware driver supports just one peer device.
> + *
> + * NOTE Don't call this method directly. The ntb_peer_port_count() function
> + * should be used instead.
> + *
> + * Return: the default number of peer ports
> + */
> +int ntb_default_peer_port_count(struct ntb_dev *ntb);
> +
> +/**
> + * ntb_default_peer_port_number() - get the default peer port by given index
> + * @ntb: NTB device context.
> + * @idx: Peer port index (should not differ from zero).
> + *
> + * By default hardware driver supports just one peer device, so this method
> + * shall return the corresponding value from enum ntb_default_port.
> + *
> + * NOTE Don't call this method directly. The ntb_peer_port_number() function
> + * should be used instead.
> + *
> + * Return: the peer device port or negative value indicating an error
> + */
> +int ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx);
> +
> +/**
> + * ntb_default_peer_port_idx() - get the default peer device port index by
> + * given port number
> + * @ntb: NTB device context.
> + * @port: Peer port number (should be one of enum ntb_default_port).
> + *
> + * By default hardware driver supports just one peer device, so while
> + * specified port-argument indicates peer port from enum ntb_default_port,
> + * the return value shall be zero.
> + *
> + * NOTE Don't call this method directly. The ntb_peer_port_idx() function
> + * should be used instead.
> + *
> + * Return: the peer port index or negative value indicating an error
> + */
> +int ntb_default_peer_port_idx(struct ntb_dev *ntb, int port);
> +
> +/**
> + * ntb_port_number() - get the local port number
> + * @ntb: NTB device context.
> + *
> + * Hardware must support at least simple two-ports ntb connection
> + *
> + * Return: the local port number
> + */
> +static inline int ntb_port_number(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->port_number)
> + return ntb_default_port_number(ntb);
> +
> + return ntb->ops->port_number(ntb);
> +}
> +
> +/**
> + * ntb_peer_port_count() - get the number of peer device ports
> + * @ntb: NTB device context.
> + *
> + * Hardware may support an access to memory of several remote domains
> + * over multi-port NTB devices. This method returns the number of peers,
> + * local device can have shared memory with.
> + *
> + * Return: the number of peer ports
> + */
> +static inline int ntb_peer_port_count(struct ntb_dev *ntb)
> +{
> + if (!ntb->ops->peer_port_count)
> + return ntb_default_peer_port_count(ntb);
> +
> + return ntb->ops->peer_port_count(ntb);
> +}
> +
> +/**
> + * ntb_peer_port_number() - get the peer port by given index
> + * @ntb: NTB device context.
> + * @pidx: Peer port index.
> + *
> + * Peer ports are continuously enumerated by NTB API logic, so this method
> + * lets to retrieve port real number by its index.
> + *
> + * Return: the peer device port or negative value indicating an error
> + */
> +static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
> +{
> + if (!ntb->ops->peer_port_number)
> + return ntb_default_peer_port_number(ntb, pidx);
> +
> + return ntb->ops->peer_port_number(ntb, pidx);
> +}
> +
> +/**
> + * ntb_peer_port_idx() - get the peer device port index by given port number
> + * @ntb: NTB device context.
> + * @port: Peer port number.
> + *
> + * Inverse operation of ntb_peer_port_number(), so one can get port index
> + * by specified port number.
> + *
> + * Return: the peer port index or negative value indicating an error
> + */
> +static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
> +{
> + if (!ntb->ops->peer_port_idx)
> + return ntb_default_peer_port_idx(ntb, port);
> +
> + return ntb->ops->peer_port_idx(ntb, port);
> +}
> +
> +/**
> * ntb_link_is_up() - get the current ntb link state
> * @ntb: NTB device context.
> * @speed: OUT - The link speed expressed as PCIe generation number.
> --
> 2.6.6

2016-12-14 07:08:26

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v3 4/9] NTB: Alter MW API to support multi-ports devices

From: Serge Semin
> Multi-port NTB devices permit to share a memory between all accessible peers.
> Memory Windows API is altered to correspondingly initialize and map memory
> windows for such devices:
> ntb_mw_count(pidx); - number of inbound memory windows, which can be allocated
> for shared buffer with specified peer device.
> ntb_mw_get_align(pidx, widx); - get alignment and size restriction parameters
> to properly allocate inbound memory region.
> ntb_peer_mw_count(); - get number of outbound memory windows.
> ntb_peer_mw_get_addr(widx); - get mapping address of an outbound memory window
>
> If hardware supports inbound translation configured on the local ntb port:
> ntb_mw_set_trans(pidx, widx); - set translation address of allocated inbound
> memory window so a peer device could access it.
> ntb_mw_clear_trans(pidx, widx); - clear the translation address of an inbound
> memory window.
>
> If hardware supports outbound translation configured on the peer ntb port:
> ntb_peer_mw_set_trans(pidx, widx); - set translation address of a memory
> window retrieved from a peer device
> ntb_peer_mw_clear_trans(pidx, widx); - clear the translation address of an
> outbound memory window
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

> ---
> drivers/ntb/hw/amd/ntb_hw_amd.c | 68 +++++++++---
> drivers/ntb/hw/intel/ntb_hw_intel.c | 90 ++++++++++++----
> drivers/ntb/ntb.c | 2 +
> drivers/ntb/ntb_transport.c | 21 +++-
> drivers/ntb/test/ntb_perf.c | 17 ++-
> drivers/ntb/test/ntb_tool.c | 43 +++++---
> include/linux/ntb.h | 208 ++++++++++++++++++++++++++++--------
> 7 files changed, 342 insertions(+), 107 deletions(-)
>
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
> index 4d8d0bd..6a41c38 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.c
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -13,6 +14,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> @@ -79,40 +81,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
> return 1 << idx;
> }
>
> -static int amd_ntb_mw_count(struct ntb_dev *ntb)
> +static int amd_ntb_mw_count(struct ntb_dev *ntb, int pidx)
> {
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> return ntb_ndev(ntb)->mw_count;
> }
>
> -static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base,
> - resource_size_t *size,
> - resource_size_t *align,
> - resource_size_t *align_size)
> +static int amd_ntb_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 amd_ntb_dev *ndev = ntb_ndev(ntb);
> int bar;
>
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> bar = ndev_mw_to_bar(ndev, idx);
> if (bar < 0)
> return bar;
>
> - if (base)
> - *base = pci_resource_start(ndev->ntb.pdev, bar);
> -
> - if (size)
> - *size = pci_resource_len(ndev->ntb.pdev, bar);
> + if (addr_align)
> + *addr_align = SZ_4K;
>
> - if (align)
> - *align = SZ_4K;
> + if (size_align)
> + *size_align = 1;
>
> - if (align_size)
> - *align_size = 1;
> + if (size_max)
> + *size_max = pci_resource_len(ndev->ntb.pdev, bar);
>
> return 0;
> }
>
> -static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
> dma_addr_t addr, resource_size_t size)
> {
> struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> @@ -122,6 +126,9 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> u64 base_addr, limit, reg_val;
> int bar;
>
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> bar = ndev_mw_to_bar(ndev, idx);
> if (bar < 0)
> return bar;
> @@ -285,6 +292,31 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb)
> return 0;
> }
>
> +static int amd_ntb_peer_mw_count(struct ntb_dev *ntb)
> +{
> + /* The same as for inbound MWs */
> + return ntb_ndev(ntb)->mw_count;
> +}
> +
> +static int amd_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
> + phys_addr_t *base, resource_size_t *size)
> +{
> + struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> + int bar;
> +
> + bar = ndev_mw_to_bar(ndev, idx);
> + if (bar < 0)
> + return bar;
> +
> + if (base)
> + *base = pci_resource_start(ndev->ntb.pdev, bar);
> +
> + if (size)
> + *size = pci_resource_len(ndev->ntb.pdev, bar);
> +
> + return 0;
> +}
> +
> static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
> {
> return ntb_ndev(ntb)->db_valid_mask;
> @@ -432,8 +464,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
>
> static const struct ntb_dev_ops amd_ntb_ops = {
> .mw_count = amd_ntb_mw_count,
> - .mw_get_range = amd_ntb_mw_get_range,
> + .mw_get_align = amd_ntb_mw_get_align,
> .mw_set_trans = amd_ntb_mw_set_trans,
> + .peer_mw_count = amd_ntb_peer_mw_count,
> + .peer_mw_get_addr = amd_ntb_peer_mw_get_addr,
> .link_is_up = amd_ntb_link_is_up,
> .link_enable = amd_ntb_link_enable,
> .link_disable = amd_ntb_link_disable,
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index 725ffa4..4b84012 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -6,6 +6,7 @@
> *
> * Copyright(c) 2012 Intel Corporation. All rights reserved.
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -15,6 +16,7 @@
> *
> * Copyright(c) 2012 Intel Corporation. All rights reserved.
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> @@ -1035,20 +1037,26 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
> debugfs_remove_recursive(ndev->debugfs_dir);
> }
>
> -static int intel_ntb_mw_count(struct ntb_dev *ntb)
> +static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
> {
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> return ntb_ndev(ntb)->mw_count;
> }
>
> -static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base,
> - resource_size_t *size,
> - resource_size_t *align,
> - resource_size_t *align_size)
> +static int intel_ntb_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 intel_ntb_dev *ndev = ntb_ndev(ntb);
> + resource_size_t bar_size, mw_size;
> int bar;
>
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> idx += 1;
>
> @@ -1056,24 +1064,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> if (bar < 0)
> return bar;
>
> - if (base)
> - *base = pci_resource_start(ndev->ntb.pdev, bar) +
> - (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> + bar_size = pci_resource_len(ndev->ntb.pdev, bar);
>
> - if (size)
> - *size = pci_resource_len(ndev->ntb.pdev, bar) -
> - (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> + if (idx == ndev->b2b_idx)
> + mw_size = bar_size - ndev->b2b_off;
> + else
> + mw_size = bar_size;
> +
> + if (addr_align)
> + *addr_align = pci_resource_len(ndev->ntb.pdev, bar);
>
> - if (align)
> - *align = pci_resource_len(ndev->ntb.pdev, bar);
> + if (size_align)
> + *size_align = 1;
>
> - if (align_size)
> - *align_size = 1;
> + if (size_max)
> + *size_max = mw_size;
>
> return 0;
> }
>
> -static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
> dma_addr_t addr, resource_size_t size)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> @@ -1083,6 +1093,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> u64 base, limit, reg_val;
> int bar;
>
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> idx += 1;
>
> @@ -1249,6 +1262,36 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
> return 0;
> }
>
> +static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
> +{
> + /* Numbers of inbound and outbound memory windows match */
> + return ntb_ndev(ntb)->mw_count;
> +}
> +
> +static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
> + phys_addr_t *base, resource_size_t *size)
> +{
> + struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> + int bar;
> +
> + if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> + idx += 1;
> +
> + bar = ndev_mw_to_bar(ndev, idx);
> + if (bar < 0)
> + return bar;
> +
> + if (base)
> + *base = pci_resource_start(ndev->ntb.pdev, bar) +
> + (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> +
> + if (size)
> + *size = pci_resource_len(ndev->ntb.pdev, bar) -
> + (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
> +
> + return 0;
> +}
> +
> static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
> {
> return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
> @@ -1880,7 +1923,7 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb,
>
> return 0;
> }
> -static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
> dma_addr_t addr, resource_size_t size)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
> @@ -1890,6 +1933,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
> u64 base, limit, reg_val;
> int bar;
>
> + if (pidx != NTB_DEF_PEER_IDX)
> + return -EINVAL;
> +
> if (idx >= ndev->b2b_idx && !ndev->b2b_off)
> idx += 1;
>
> @@ -2884,8 +2930,10 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {
> /* operations for primary side of local ntb */
> static const struct ntb_dev_ops intel_ntb_ops = {
> .mw_count = intel_ntb_mw_count,
> - .mw_get_range = intel_ntb_mw_get_range,
> + .mw_get_align = intel_ntb_mw_get_align,
> .mw_set_trans = intel_ntb_mw_set_trans,
> + .peer_mw_count = intel_ntb_peer_mw_count,
> + .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
> .link_is_up = intel_ntb_link_is_up,
> .link_enable = intel_ntb_link_enable,
> .link_disable = intel_ntb_link_disable,
> @@ -2910,8 +2958,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
>
> static const struct ntb_dev_ops intel_ntb3_ops = {
> .mw_count = intel_ntb_mw_count,
> - .mw_get_range = intel_ntb_mw_get_range,
> + .mw_get_align = intel_ntb_mw_get_align,
> .mw_set_trans = intel_ntb3_mw_set_trans,
> + .peer_mw_count = intel_ntb_peer_mw_count,
> + .peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
> .link_is_up = intel_ntb_link_is_up,
> .link_enable = intel_ntb3_link_enable,
> .link_disable = intel_ntb_link_disable,
> diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
> index 1e92e52..2551bb2 100644
> --- a/drivers/ntb/ntb.c
> +++ b/drivers/ntb/ntb.c
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -18,6 +19,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 10518b7..4d5b160 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -685,7 +685,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
> if (!mw->virt_addr)
> return;
>
> - ntb_mw_clear_trans(nt->ndev, num_mw);
> + ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
> dma_free_coherent(&pdev->dev, mw->buff_size,
> mw->virt_addr, mw->dma_addr);
> mw->xlat_size = 0;
> @@ -742,7 +742,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
> }
>
> /* Notify HW the memory location of the receive buffer */
> - rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
> + rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
> + mw->xlat_size);
> if (rc) {
> dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
> ntb_free_mw(nt, num_mw);
> @@ -1072,13 +1073,18 @@ static int ntb_transport_probe(struct ntb_client *self, struct
> ntb_dev *ndev)
> int node;
> int rc, i;
>
> - mw_count = ntb_mw_count(ndev);
> + mw_count = ntb_mw_count(ndev, PIDX);
> if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) {
> dev_err(&ndev->dev, "Not enough scratch pad registers for %s",
> NTB_TRANSPORT_NAME);
> return -EIO;
> }
>
> + if (!ndev->ops->mw_set_trans) {
> + dev_err(&ndev->dev, "Inbound MW based NTB API is required\n");
> + return -EINVAL;
> + }
> +
> if (ntb_db_is_unsafe(ndev))
> dev_dbg(&ndev->dev,
> "doorbell is unsafe, proceed anyway...\n");
> @@ -1109,8 +1115,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct
> ntb_dev *ndev)
> for (i = 0; i < mw_count; i++) {
> mw = &nt->mw_vec[i];
>
> - rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
> - &mw->xlat_align, &mw->xlat_align_size);
> + rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
> + &mw->xlat_align_size, NULL);
> + if (rc)
> + goto err1;
> +
> + rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
> + &mw->phys_size);
> if (rc)
> goto err1;
>
> diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
> index c908b3a..cbff0b4 100644
> --- a/drivers/ntb/test/ntb_perf.c
> +++ b/drivers/ntb/test/ntb_perf.c
> @@ -453,7 +453,7 @@ static void perf_free_mw(struct perf_ctx *perf)
> if (!mw->virt_addr)
> return;
>
> - ntb_mw_clear_trans(perf->ntb, 0);
> + ntb_mw_clear_trans(perf->ntb, PIDX, 0);
> dma_free_coherent(&pdev->dev, mw->buf_size,
> mw->virt_addr, mw->dma_addr);
> mw->xlat_size = 0;
> @@ -489,7 +489,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
> mw->buf_size = 0;
> }
>
> - rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
> + rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size);
> if (rc) {
> dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
> perf_free_mw(perf);
> @@ -560,8 +560,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)
>
> mw = &perf->mw;
>
> - rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size,
> - &mw->xlat_align, &mw->xlat_align_size);
> + rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
> + &mw->xlat_align_size, NULL);
> + if (rc)
> + return rc;
> +
> + rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
> if (rc)
> return rc;
>
> @@ -765,6 +769,11 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
> return -EIO;
> }
>
> + if (!ntb->ops->mw_set_trans) {
> + dev_err(&ntb->dev, "Need inbound MW based NTB API\n");
> + return -EINVAL;
> + }
> +
> if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
> dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
>
> diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
> index 690862d..cb69247 100644
> --- a/drivers/ntb/test/ntb_tool.c
> +++ b/drivers/ntb/test/ntb_tool.c
> @@ -119,7 +119,8 @@ MODULE_VERSION(DRIVER_VERSION);
> MODULE_AUTHOR(DRIVER_AUTHOR);
> MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
>
> -#define MAX_MWS 16
> +/* It is rare to have hadrware with greater than six MWs */
> +#define MAX_MWS 6
> /* Only two-ports devices are supported */
> #define PIDX NTB_DEF_PEER_IDX
>
> @@ -670,28 +671,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t
> req_size)
> {
> int rc;
> struct tool_mw *mw = &tc->mws[idx];
> - phys_addr_t base;
> - resource_size_t size, align, align_size;
> + resource_size_t size, align_addr, align_size;
> char buf[16];
>
> if (mw->peer)
> return 0;
>
> - rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
> - &align_size);
> + rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
> + &align_size, &size);
> if (rc)
> return rc;
>
> mw->size = min_t(resource_size_t, req_size, size);
> - mw->size = round_up(mw->size, align);
> + mw->size = round_up(mw->size, align_addr);
> mw->size = round_up(mw->size, align_size);
> mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
> &mw->peer_dma, GFP_KERNEL);
>
> - if (!mw->peer)
> + if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
> return -ENOMEM;
>
> - rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
> + rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
> if (rc)
> goto err_free_dma;
>
> @@ -718,7 +718,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx)
> struct tool_mw *mw = &tc->mws[idx];
>
> if (mw->peer) {
> - ntb_mw_clear_trans(tc->ntb, idx);
> + ntb_mw_clear_trans(tc->ntb, PIDX, idx);
> dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
> mw->peer,
> mw->peer_dma);
> @@ -744,8 +744,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
>
> phys_addr_t base;
> resource_size_t mw_size;
> - resource_size_t align;
> + resource_size_t align_addr;
> resource_size_t align_size;
> + resource_size_t max_size;
>
> buf_size = min_t(size_t, size, 512);
>
> @@ -753,8 +754,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
> if (!buf)
> return -ENOMEM;
>
> - ntb_mw_get_range(mw->tc->ntb, mw->idx,
> - &base, &mw_size, &align, &align_size);
> + ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
> + &align_addr, &align_size, &max_size);
> + ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);
>
> off += scnprintf(buf + off, buf_size - off,
> "Peer MW %d Information:\n", mw->idx);
> @@ -769,13 +771,17 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
>
> off += scnprintf(buf + off, buf_size - off,
> "Alignment \t%lld\n",
> - (unsigned long long)align);
> + (unsigned long long)align_addr);
>
> off += scnprintf(buf + off, buf_size - off,
> "Size Alignment \t%lld\n",
> (unsigned long long)align_size);
>
> off += scnprintf(buf + off, buf_size - off,
> + "Size Max \t%lld\n",
> + (unsigned long long)max_size);
> +
> + off += scnprintf(buf + off, buf_size - off,
> "Ready \t%c\n",
> (mw->peer) ? 'Y' : 'N');
>
> @@ -829,8 +835,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx)
> phys_addr_t base;
> int rc;
>
> - rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
> - NULL, NULL);
> + rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size);
> if (rc)
> return rc;
>
> @@ -915,6 +920,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> int rc;
> int i;
>
> + if (!ntb->ops->mw_set_trans) {
> + dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
> + rc = -EINVAL;
> + goto err_tc;
> + }
> +
> if (ntb_db_is_unsafe(ntb))
> dev_dbg(&ntb->dev, "doorbell is unsafe\n");
>
> @@ -933,7 +944,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> tc->ntb = ntb;
> init_waitqueue_head(&tc->link_wq);
>
> - tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
> + tc->mw_count = min(ntb_mw_count(tc->ntb, PIDX), MAX_MWS);
> for (i = 0; i < tc->mw_count; i++) {
> rc = tool_init_mw(tc, i);
> if (rc)
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 6eef109..f6ec88f 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -5,6 +5,7 @@
> * GPL LICENSE SUMMARY
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of version 2 of the GNU General Public License as
> @@ -18,6 +19,7 @@
> * BSD LICENSE
> *
> * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
> + * Copyright (C) 2016 T-Platforms. All Rights Reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> @@ -201,9 +203,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
> * @link_enable: See ntb_link_enable().
> * @link_disable: See ntb_link_disable().
> * @mw_count: See ntb_mw_count().
> - * @mw_get_range: See ntb_mw_get_range().
> + * @mw_get_align: See ntb_mw_get_align().
> * @mw_set_trans: See ntb_mw_set_trans().
> * @mw_clear_trans: See ntb_mw_clear_trans().
> + * @peer_mw_count: See ntb_peer_mw_count().
> + * @peer_mw_get_addr: See ntb_peer_mw_get_addr().
> + * @peer_mw_set_trans: See ntb_peer_mw_set_trans().
> + * @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
> * @db_is_unsafe: See ntb_db_is_unsafe().
> * @db_valid_mask: See ntb_db_valid_mask().
> * @db_vector_count: See ntb_db_vector_count().
> @@ -241,13 +247,20 @@ struct ntb_dev_ops {
> enum ntb_speed max_speed, enum ntb_width max_width);
> int (*link_disable)(struct ntb_dev *ntb);
>
> - int (*mw_count)(struct ntb_dev *ntb);
> - int (*mw_get_range)(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base, resource_size_t *size,
> - resource_size_t *align, resource_size_t *align_size);
> - int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
> + int (*mw_count)(struct ntb_dev *ntb, int pidx);
> + int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
> + resource_size_t *addr_align,
> + resource_size_t *size_align,
> + resource_size_t *size_max);
> + int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
> dma_addr_t addr, resource_size_t size);
> - int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
> + int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
> + int (*peer_mw_count)(struct ntb_dev *ntb);
> + int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
> + phys_addr_t *base, resource_size_t *size);
> + int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
> + u64 addr, resource_size_t size);
> + int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
>
> int (*db_is_unsafe)(struct ntb_dev *ntb);
> u64 (*db_valid_mask)(struct ntb_dev *ntb);
> @@ -295,9 +308,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> ops->link_enable &&
> ops->link_disable &&
> ops->mw_count &&
> - ops->mw_get_range &&
> - ops->mw_set_trans &&
> + ops->mw_get_align &&
> + (ops->mw_set_trans ||
> + ops->peer_mw_set_trans) &&
> /* ops->mw_clear_trans && */
> + ops->peer_mw_count &&
> + ops->peer_mw_get_addr &&
> + /* ops->peer_mw_clear_trans && */
>
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
> @@ -655,79 +672,180 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
> }
>
> /**
> - * ntb_mw_count() - get the number of memory windows
> + * ntb_mw_count() - get the number of inbound memory windows, which could
> + * be created for a specified peer device
> * @ntb: NTB device context.
> + * @pidx: Port index of peer device.
> *
> * Hardware and topology may support a different number of memory windows.
> + * Moreover different peer devices can support different number of memory
> + * windows. Simply speaking this method returns the number of possible inbound
> + * memory windows to share with specified peer device.
> *
> * Return: the number of memory windows.
> */
> -static inline int ntb_mw_count(struct ntb_dev *ntb)
> +static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
> {
> - return ntb->ops->mw_count(ntb);
> + return ntb->ops->mw_count(ntb, pidx);
> }
>
> /**
> - * ntb_mw_get_range() - get the range of a memory window
> + * ntb_mw_get_align() - get the restriction parameters of inbound memory window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> - * @base: OUT - the base address for mapping the memory window
> - * @size: OUT - the size for mapping the memory window
> - * @align: OUT - the base alignment for translating the memory window
> - * @align_size: OUT - the size alignment for translating the memory window
> - *
> - * Get the range of a memory window. NULL may be given for any output
> - * parameter if the value is not needed. The base and size may be used for
> - * mapping the memory window, to access the peer memory. The alignment and
> - * size may be used for translating the memory window, for the peer to access
> - * memory on the local system.
> - *
> - * Return: Zero on success, otherwise an error number.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + * @addr_align: OUT - the base alignment for translating the memory window
> + * @size_align: OUT - the size alignment for translating the memory window
> + * @size_max: OUT - the maximum size of the memory window
> + *
> + * Get the alignments of an inbound memory window with specified index.
> + * NULL may be given for any output parameter if the value is not needed.
> + * The alignment and size parameters may be used for allocation of proper
> + * shared memory.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> */
> -static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
> - phys_addr_t *base, resource_size_t *size,
> - resource_size_t *align, resource_size_t *align_size)
> +static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
> + resource_size_t *addr_align,
> + resource_size_t *size_align,
> + resource_size_t *size_max)
> {
> - return ntb->ops->mw_get_range(ntb, idx, base, size,
> - align, align_size);
> + return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
> + size_max);
> }
>
> /**
> - * ntb_mw_set_trans() - set the translation of a memory window
> + * ntb_mw_set_trans() - set the translation of an inbound memory window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> - * @addr: The dma address local memory to expose to the peer.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + * @addr: The dma address of local memory to expose to the peer.
> * @size: The size of the local memory to expose to the peer.
> *
> * Set the translation of a memory window. The peer may access local memory
> * through the window starting at the address, up to the size. The address
> - * must be aligned to the alignment specified by ntb_mw_get_range(). The size
> - * must be aligned to the size alignment specified by ntb_mw_get_range().
> + * and size must be aligned in compliance with restrictions of
> + * ntb_mw_get_align(). The region size should not exceed the size_max parameter
> + * of that method.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
> +static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
> dma_addr_t addr, resource_size_t size)
> {
> - return ntb->ops->mw_set_trans(ntb, idx, addr, size);
> + if (!ntb->ops->mw_set_trans)
> + return 0;
> +
> + return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
> }
>
> /**
> - * ntb_mw_clear_trans() - clear the translation of a memory window
> + * ntb_mw_clear_trans() - clear the translation address of an inbound memory
> + * window
> * @ntb: NTB device context.
> - * @idx: Memory window number.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> *
> - * Clear the translation of a memory window. The peer may no longer access
> - * local memory through the window.
> + * Clear the translation of an inbound memory window. The peer may no longer
> + * access local memory through the window.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
> +static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
> {
> if (!ntb->ops->mw_clear_trans)
> - return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
> + return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
> +
> + return ntb->ops->mw_clear_trans(ntb, pidx, widx);
> +}
> +
> +/**
> + * ntb_peer_mw_count() - get the number of outbound memory windows, which could
> + * be mapped to access a shared memory
> + * @ntb: NTB device context.
> + *
> + * Hardware and topology may support a different number of memory windows.
> + * This method returns the number of outbound memory windows supported by
> + * local device.
> + *
> + * Return: the number of memory windows.
> + */
> +static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
> +{
> + return ntb->ops->peer_mw_count(ntb);
> +}
> +
> +/**
> + * ntb_peer_mw_get_addr() - get map address of an outbound memory window
> + * @ntb: NTB device context.
> + * @widx: Memory window index (within ntb_peer_mw_count() return value).
> + * @base: OUT - the base address of mapping region.
> + * @size: OUT - the size of mapping region.
> + *
> + * Get base and size of memory region to map. NULL may be given for any output
> + * parameter if the value is not needed. The base and size may be used for
> + * mapping the memory window, to access the peer memory.
> + *
> + * Return: Zero on success, otherwise a negative error number.
> + */
> +static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
> + phys_addr_t *base, resource_size_t *size)
> +{
> + return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
> +}
> +
> +/**
> + * ntb_peer_mw_set_trans() - set a translation address of a memory window
> + * retrieved from a peer device
> + * @ntb: NTB device context.
> + * @pidx: Port index of peer device the translation address received from.
> + * @widx: Memory window index.
> + * @addr: The dma address of the shared memory to access.
> + * @size: The size of the shared memory to access.
> + *
> + * Set the translation of an outbound memory window. The local device may
> + * access shared memory allocated by a peer device sent the address.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface, so a translation address can be only set on the side,
> + * where shared memory (inbound memory windows) is allocated.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
> + u64 addr, resource_size_t size)
> +{
> + if (!ntb->ops->peer_mw_set_trans)
> + return 0;
> +
> + return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
> +}
> +
> +/**
> + * ntb_peer_mw_clear_trans() - clear the translation address of an outbound
> + * memory window
> + * @ntb: NTB device context.
> + * @pidx: Port index of peer device.
> + * @widx: Memory window index.
> + *
> + * Clear the translation of a outbound memory window. The local device may no
> + * longer access a shared memory through the window.
> + *
> + * This method may not be implemented due to the hardware specific memory
> + * windows interface.
> + *
> + * Return: Zero on success, otherwise an error number.
> + */
> +static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
> + int widx)
> +{
> + if (!ntb->ops->peer_mw_clear_trans)
> + return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);
>
> - return ntb->ops->mw_clear_trans(ntb, idx);
> + return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
> }
>
> /**
> --
> 2.6.6


2016-12-14 07:08:54

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v3 5/9] NTB: Alter Scratchpads API to support multi-ports devices

From: Serge Semin
> Even though there is no any real NTB hardware, which would have both more
> than two ports and Scratchpad registers, it is logically correct to have
> Scratchpad API accepting a peer port index as well. Intel/AMD drivers utilize
> Primary and Secondary topology to split Scratchpad between connected root
> devices. Since port-index API introduced, Intel/AMD NTB hardware drivers can
> use device port to determine which Scratchpad registers actually belong to
> local and peer devices. The same approach can be used if some potential
> hardware in future will be multi-port and have some set of Scratchpads.
> Here are the brief of changes in the API:
> ntb_spad_count() - return number of Scratchpads per each port
> ntb_peer_spad_addr(pidx, sidx) - address of Scratchpad register of the
> peer device with pidx-index
> ntb_peer_spad_read(pidx, sidx) - read specified Scratchpad register of the
> peer with pidx-index
> ntb_peer_spad_write(pidx, sidx) - write data to Scratchpad register of the
> peer with pidx-index
>
> Since there is hardware which doesn't support Scratchpad registers, the
> corresponding API methods are now made optional.
>
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

> ---
> drivers/ntb/hw/amd/ntb_hw_amd.c | 14 +++----
> drivers/ntb/hw/intel/ntb_hw_intel.c | 14 +++----
> drivers/ntb/ntb_transport.c | 17 ++++-----
> drivers/ntb/test/ntb_perf.c | 6 +--
> drivers/ntb/test/ntb_pingpong.c | 8 +++-
> drivers/ntb/test/ntb_tool.c | 21 ++++++++--
> include/linux/ntb.h | 76 +++++++++++++++++++++++--------------
> 7 files changed, 98 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
> index 6a41c38..bc537aa 100644
> --- a/drivers/ntb/hw/amd/ntb_hw_amd.c
> +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
> @@ -433,30 +433,30 @@ static int amd_ntb_spad_write(struct ntb_dev *ntb,
> return 0;
> }
>
> -static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> +static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
> {
> struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> void __iomem *mmio = ndev->self_mmio;
> u32 offset;
>
> - if (idx < 0 || idx >= ndev->spad_count)
> + if (sidx < 0 || sidx >= ndev->spad_count)
> return -EINVAL;
>
> - offset = ndev->peer_spad + (idx << 2);
> + offset = ndev->peer_spad + (sidx << 2);
> return readl(mmio + AMD_SPAD_OFFSET + offset);
> }
>
> -static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
> - int idx, u32 val)
> +static int amd_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
> + int sidx, u32 val)
> {
> struct amd_ntb_dev *ndev = ntb_ndev(ntb);
> void __iomem *mmio = ndev->self_mmio;
> u32 offset;
>
> - if (idx < 0 || idx >= ndev->spad_count)
> + if (sidx < 0 || sidx >= ndev->spad_count)
> return -EINVAL;
>
> - offset = ndev->peer_spad + (idx << 2);
> + offset = ndev->peer_spad + (sidx << 2);
> writel(val, mmio + AMD_SPAD_OFFSET + offset);
>
> return 0;
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index 4b84012..7bb14cb 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -1409,30 +1409,30 @@ static int intel_ntb_spad_write(struct ntb_dev *ntb,
> ndev->self_reg->spad);
> }
>
> -static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
> +static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
>
> - return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr,
> + return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
> ndev->peer_reg->spad);
> }
>
> -static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> +static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
>
> - return ndev_spad_read(ndev, idx,
> + return ndev_spad_read(ndev, sidx,
> ndev->peer_mmio +
> ndev->peer_reg->spad);
> }
>
> -static int intel_ntb_peer_spad_write(struct ntb_dev *ntb,
> - int idx, u32 val)
> +static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
> + int sidx, u32 val)
> {
> struct intel_ntb_dev *ndev = ntb_ndev(ntb);
>
> - return ndev_spad_write(ndev, idx, val,
> + return ndev_spad_write(ndev, sidx, val,
> ndev->peer_mmio +
> ndev->peer_reg->spad);
> }
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 4d5b160..28aaba3 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -875,17 +875,17 @@ static void ntb_transport_link_work(struct work_struct *work)
> size = max_mw_size;
>
> spad = MW0_SZ_HIGH + (i * 2);
> - ntb_peer_spad_write(ndev, spad, upper_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, spad, upper_32_bits(size));
>
> spad = MW0_SZ_LOW + (i * 2);
> - ntb_peer_spad_write(ndev, spad, lower_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, spad, lower_32_bits(size));
> }
>
> - ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count);
> + ntb_peer_spad_write(ndev, PIDX, NUM_MWS, nt->mw_count);
>
> - ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count);
> + ntb_peer_spad_write(ndev, PIDX, NUM_QPS, nt->qp_count);
>
> - ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION);
> + ntb_peer_spad_write(ndev, PIDX, VERSION, NTB_TRANSPORT_VERSION);
>
> /* Query the remote side for its info */
> val = ntb_spad_read(ndev, VERSION);
> @@ -961,10 +961,10 @@ static void ntb_qp_link_work(struct work_struct *work)
>
> val = ntb_spad_read(nt->ndev, QP_LINKS);
>
> - ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num));
> + ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num));
>
> /* query remote spad for qp ready bits */
> - ntb_peer_spad_read(nt->ndev, QP_LINKS);
> + ntb_peer_spad_read(nt->ndev, PIDX, QP_LINKS);
> dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);
>
> /* See if the remote side is up */
> @@ -2141,8 +2141,7 @@ void ntb_transport_link_down(struct ntb_transport_qp *qp)
>
> val = ntb_spad_read(qp->ndev, QP_LINKS);
>
> - ntb_peer_spad_write(qp->ndev, QP_LINKS,
> - val & ~BIT(qp->qp_num));
> + ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val & ~BIT(qp->qp_num));
>
> if (qp->link_is_up)
> ntb_send_link_down(qp);
> diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
> index cbff0b4..0a493ba 100644
> --- a/drivers/ntb/test/ntb_perf.c
> +++ b/drivers/ntb/test/ntb_perf.c
> @@ -516,9 +516,9 @@ static void perf_link_work(struct work_struct *work)
> if (max_mw_size && size > max_mw_size)
> size = max_mw_size;
>
> - ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
> - ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
> - ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
> + ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size));
> + ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION);
>
> /* now read what peer wrote */
> val = ntb_spad_read(ndev, VERSION);
> diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
> index 12f8b40..938a18b 100644
> --- a/drivers/ntb/test/ntb_pingpong.c
> +++ b/drivers/ntb/test/ntb_pingpong.c
> @@ -138,7 +138,7 @@ static void pp_ping(unsigned long ctx)
> "Ping bits %#llx read %#x write %#x\n",
> db_bits, spad_rd, spad_wr);
>
> - ntb_peer_spad_write(pp->ntb, 0, spad_wr);
> + ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr);
> ntb_peer_db_set(pp->ntb, db_bits);
> ntb_db_clear_mask(pp->ntb, db_mask);
>
> @@ -225,6 +225,12 @@ static int pp_probe(struct ntb_client *client,
> }
> }
>
> + if (ntb_spad_count(ntb) < 1) {
> + dev_dbg(&ntb->dev, "no enough scratchpads\n");
> + rc = -EINVAL;
> + goto err_pp;
> + }
> +
> if (ntb_spad_is_unsafe(ntb)) {
> dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
> if (!unsafe) {
> diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
> index cb69247..f002bf4 100644
> --- a/drivers/ntb/test/ntb_tool.c
> +++ b/drivers/ntb/test/ntb_tool.c
> @@ -462,13 +462,22 @@ static TOOL_FOPS_RDWR(tool_spad_fops,
> tool_spad_read,
> tool_spad_write);
>
> +static u32 ntb_tool_peer_spad_read(struct ntb_dev *ntb, int sidx)
> +{
> + return ntb_peer_spad_read(ntb, PIDX, sidx);
> +}
> +
> static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
> size_t size, loff_t *offp)
> {
> struct tool_ctx *tc = filep->private_data;
>
> - return tool_spadfn_read(tc, ubuf, size, offp,
> - tc->ntb->ops->peer_spad_read);
> + return tool_spadfn_read(tc, ubuf, size, offp, ntb_tool_peer_spad_read);
> +}
> +
> +static int ntb_tool_peer_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
> +{
> + return ntb_peer_spad_write(ntb, PIDX, sidx, val);
> }
>
> static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
> @@ -477,7 +486,7 @@ static ssize_t tool_peer_spad_write(struct file *filep, const char
> __user *ubuf,
> struct tool_ctx *tc = filep->private_data;
>
> return tool_spadfn_write(tc, ubuf, size, offp,
> - tc->ntb->ops->peer_spad_write);
> + ntb_tool_peer_spad_write);
> }
>
> static TOOL_FOPS_RDWR(tool_peer_spad_fops,
> @@ -926,6 +935,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
> goto err_tc;
> }
>
> + if (ntb_spad_count(ntb) < 1) {
> + dev_dbg(&ntb->dev, "no enough scratchpads\n");
> + rc = -EINVAL;
> + goto err_tc;
> + }
> +
> if (ntb_db_is_unsafe(ntb))
> dev_dbg(&ntb->dev, "doorbell is unsafe\n");
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index f6ec88f..a54e2be 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -288,13 +288,14 @@ struct ntb_dev_ops {
> int (*spad_is_unsafe)(struct ntb_dev *ntb);
> int (*spad_count)(struct ntb_dev *ntb);
>
> - u32 (*spad_read)(struct ntb_dev *ntb, int idx);
> - int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
> + u32 (*spad_read)(struct ntb_dev *ntb, int sidx);
> + int (*spad_write)(struct ntb_dev *ntb, int sidx, u32 val);
>
> - int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
> + int (*peer_spad_addr)(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr);
> - u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
> - int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
> + u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
> + int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
> + u32 val);
> };
>
> static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> @@ -335,13 +336,12 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> /* ops->peer_db_read_mask && */
> /* ops->peer_db_set_mask && */
> /* ops->peer_db_clear_mask && */
> - /* ops->spad_is_unsafe && */
> - ops->spad_count &&
> - ops->spad_read &&
> - ops->spad_write &&
> - /* ops->peer_spad_addr && */
> - /* ops->peer_spad_read && */
> - ops->peer_spad_write &&
> + /* !ops->spad_is_unsafe == !ops->spad_count && */
> + !ops->spad_read == !ops->spad_count &&
> + !ops->spad_write == !ops->spad_count &&
> + /* !ops->peer_spad_addr == !ops->spad_count && */
> + /* !ops->peer_spad_read == !ops->spad_count && */
> + !ops->peer_spad_write == !ops->spad_count &&
> 1;
> }
>
> @@ -1172,51 +1172,62 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
> }
>
> /**
> - * ntb_mw_count() - get the number of scratchpads
> + * ntb_spad_count() - get the number of scratchpads
> * @ntb: NTB device context.
> *
> * Hardware and topology may support a different number of scratchpads.
> + * Although it must be the same for all ports per NTB device.
> *
> * Return: the number of scratchpads.
> */
> static inline int ntb_spad_count(struct ntb_dev *ntb)
> {
> + if (!ntb->ops->spad_count)
> + return 0;
> +
> return ntb->ops->spad_count(ntb);
> }
>
> /**
> * ntb_spad_read() - read the local scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @sidx: Scratchpad index.
> *
> * Read the local scratchpad register, and return the value.
> *
> * Return: The value of the local scratchpad register.
> */
> -static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
> +static inline u32 ntb_spad_read(struct ntb_dev *ntb, int sidx)
> {
> - return ntb->ops->spad_read(ntb, idx);
> + if (!ntb->ops->spad_read)
> + return ~(u32)0;
> +
> + return ntb->ops->spad_read(ntb, sidx);
> }
>
> /**
> * ntb_spad_write() - write the local scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @sidx: Scratchpad index.
> * @val: Scratchpad value.
> *
> * Write the value to the local scratchpad register.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> +static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
> {
> - return ntb->ops->spad_write(ntb, idx, val);
> + if (!ntb->ops->spad_write)
> + return -EINVAL;
> +
> + return ntb->ops->spad_write(ntb, sidx, val);
> }
>
> /**
> * ntb_peer_spad_addr() - address of the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> * @spad_addr: OUT - The address of the peer scratchpad register.
> *
> * Return the address of the peer doorbell register. This may be used, for
> @@ -1224,42 +1235,51 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32
> val)
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
> +static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
> phys_addr_t *spad_addr)
> {
> if (!ntb->ops->peer_spad_addr)
> return -EINVAL;
>
> - return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
> + return ntb->ops->peer_spad_addr(ntb, pidx, sidx, spad_addr);
> }
>
> /**
> * ntb_peer_spad_read() - read the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> *
> * Read the peer scratchpad register, and return the value.
> *
> * Return: The value of the local scratchpad register.
> */
> -static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
> +static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
> {
> - return ntb->ops->peer_spad_read(ntb, idx);
> + if (!ntb->ops->peer_spad_read)
> + return ~(u32)0;
> +
> + return ntb->ops->peer_spad_read(ntb, pidx, sidx);
> }
>
> /**
> * ntb_peer_spad_write() - write the peer scratchpad register
> * @ntb: NTB device context.
> - * @idx: Scratchpad index.
> + * @pidx: Port index of peer device.
> + * @sidx: Scratchpad index.
> * @val: Scratchpad value.
> *
> * Write the value to the peer scratchpad register.
> *
> * Return: Zero on success, otherwise an error number.
> */
> -static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
> +static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
> + u32 val)
> {
> - return ntb->ops->peer_spad_write(ntb, idx, val);
> + if (!ntb->ops->peer_spad_write)
> + return -EINVAL;
> +
> + return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
> }
>
> #endif
> --
> 2.6.6


2016-12-14 07:10:04

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v3 9/9] NTB: Add ntb.h comments

From: Serge Semin
> Signed-off-by: Serge Semin <[email protected]>
> ---
> include/linux/ntb.h | 19 ++++++++++++-------
> 1 file changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 6d46179..dab0a1b 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -326,12 +326,17 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> {
> /* commented callbacks are not required: */
> return
> + /* Port operations are required */

... for multiport devices.

> !ops->peer_port_count == !ops->port_number &&
> !ops->peer_port_number == !ops->port_number &&
> !ops->peer_port_idx == !ops->port_number &&
> +
> + /* Link operations are requiered */
> ops->link_is_up &&
> ops->link_enable &&
> ops->link_disable &&
> +
> + /* One or both MW interfaces should be developed */
> ops->mw_count &&
> ops->mw_get_align &&
> (ops->mw_set_trans ||
> @@ -341,12 +346,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> ops->peer_mw_get_addr &&
> /* ops->peer_mw_clear_trans && */
>
> + /* Doorbell operations are mostly required */
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
> -
> /* both set, or both unset */
> - (!ops->db_vector_count == !ops->db_vector_mask) &&
> -
> + (!ops->db_vector_count == !ops->db_vector_mask) &&
> ops->db_read &&
> /* ops->db_set && */
> ops->db_clear &&
> @@ -360,6 +364,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* ops->peer_db_read_mask && */
> /* ops->peer_db_set_mask && */
> /* ops->peer_db_clear_mask && */
> +
> + /* Scrachpads interface is optional */
> /* !ops->spad_is_unsafe == !ops->spad_count && */
> !ops->spad_read == !ops->spad_count &&
> !ops->spad_write == !ops->spad_count &&
> @@ -367,6 +373,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* !ops->peer_spad_read == !ops->spad_count && */
> !ops->peer_spad_write == !ops->spad_count &&
>
> + /* Messaging interface is optional */
> !ops->msg_inbits == !ops->msg_count &&
> !ops->msg_outbits == !ops->msg_count &&
> !ops->msg_read_sts == !ops->msg_count &&
> @@ -387,13 +394,12 @@ struct ntb_client {
> struct device_driver drv;
> const struct ntb_client_ops ops;
> };
> -
> #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
>
> /**
> * struct ntb_device - ntb device
> * @dev: Linux device object.
> - * @pdev: Pci device entry of the ntb.
> + * @pdev: PCI device entry of the ntb.
> * @topo: Detected topology of the ntb.
> * @ops: See &ntb_dev_ops.
> * @ctx: See &ntb_ctx_ops.
> @@ -414,7 +420,6 @@ struct ntb_dev {
> /* block unregister until device is fully released */
> struct completion released;
> };
> -
> #define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
>
> /**
> @@ -511,7 +516,7 @@ void ntb_link_event(struct ntb_dev *ntb);
> * multiple interrupt vectors for doorbells, the vector number indicates which
> * vector received the interrupt. The vector number is relative to the first
> * vector used for doorbells, starting at zero, and must be less than
> - ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> + * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> * doorbell bits need service, and ntb_db_vector_mask() to determine which of
> * those bits are associated with the vector number.
> */
> --
> 2.6.6


2016-12-14 07:19:08

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 9/9] NTB: Add ntb.h comments

Signed-off-by: Serge Semin <[email protected]>
---
include/linux/ntb.h | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 6d46179..dab0a1b 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -326,12 +326,17 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ /* Port operations are required for multiport devices */
!ops->peer_port_count == !ops->port_number &&
!ops->peer_port_number == !ops->port_number &&
!ops->peer_port_idx == !ops->port_number &&
+
+ /* Link operations are required */
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
+
+ /* One or both MW interfaces should be developed */
ops->mw_count &&
ops->mw_get_align &&
(ops->mw_set_trans ||
@@ -341,12 +346,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->peer_mw_get_addr &&
/* ops->peer_mw_clear_trans && */

+ /* Doorbell operations are mostly required */
/* ops->db_is_unsafe && */
ops->db_valid_mask &&
-
/* both set, or both unset */
- (!ops->db_vector_count == !ops->db_vector_mask) &&
-
+ (!ops->db_vector_count == !ops->db_vector_mask) &&
ops->db_read &&
/* ops->db_set && */
ops->db_clear &&
@@ -360,6 +364,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
+
+ /* Scrachpads interface is optional */
/* !ops->spad_is_unsafe == !ops->spad_count && */
!ops->spad_read == !ops->spad_count &&
!ops->spad_write == !ops->spad_count &&
@@ -367,6 +373,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&

+ /* Messaging interface is optional */
!ops->msg_inbits == !ops->msg_count &&
!ops->msg_outbits == !ops->msg_count &&
!ops->msg_read_sts == !ops->msg_count &&
@@ -387,13 +394,12 @@ struct ntb_client {
struct device_driver drv;
const struct ntb_client_ops ops;
};
-
#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)

/**
* struct ntb_device - ntb device
* @dev: Linux device object.
- * @pdev: Pci device entry of the ntb.
+ * @pdev: PCI device entry of the ntb.
* @topo: Detected topology of the ntb.
* @ops: See &ntb_dev_ops.
* @ctx: See &ntb_ctx_ops.
@@ -414,7 +420,6 @@ struct ntb_dev {
/* block unregister until device is fully released */
struct completion released;
};
-
#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)

/**
@@ -511,7 +516,7 @@ void ntb_link_event(struct ntb_dev *ntb);
* multiple interrupt vectors for doorbells, the vector number indicates which
* vector received the interrupt. The vector number is relative to the first
* vector used for doorbells, starting at zero, and must be less than
- ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
+ * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
* doorbell bits need service, and ntb_db_vector_mask() to determine which of
* those bits are associated with the vector number.
*/
--
2.6.6

2016-12-14 07:19:29

by Allen Hubbe

[permalink] [raw]
Subject: RE: [PATCH v3 9/9] NTB: Add ntb.h comments

From: Serge Semin
> Signed-off-by: Serge Semin <[email protected]>

Acked-by: Allen Hubbe <[email protected]>

> ---
> include/linux/ntb.h | 19 ++++++++++++-------
> 1 file changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/ntb.h b/include/linux/ntb.h
> index 6d46179..dab0a1b 100644
> --- a/include/linux/ntb.h
> +++ b/include/linux/ntb.h
> @@ -326,12 +326,17 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> {
> /* commented callbacks are not required: */
> return
> + /* Port operations are required for multiport devices */
> !ops->peer_port_count == !ops->port_number &&
> !ops->peer_port_number == !ops->port_number &&
> !ops->peer_port_idx == !ops->port_number &&
> +
> + /* Link operations are required */
> ops->link_is_up &&
> ops->link_enable &&
> ops->link_disable &&
> +
> + /* One or both MW interfaces should be developed */
> ops->mw_count &&
> ops->mw_get_align &&
> (ops->mw_set_trans ||
> @@ -341,12 +346,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops
> *ops)
> ops->peer_mw_get_addr &&
> /* ops->peer_mw_clear_trans && */
>
> + /* Doorbell operations are mostly required */
> /* ops->db_is_unsafe && */
> ops->db_valid_mask &&
> -
> /* both set, or both unset */
> - (!ops->db_vector_count == !ops->db_vector_mask) &&
> -
> + (!ops->db_vector_count == !ops->db_vector_mask) &&
> ops->db_read &&
> /* ops->db_set && */
> ops->db_clear &&
> @@ -360,6 +364,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* ops->peer_db_read_mask && */
> /* ops->peer_db_set_mask && */
> /* ops->peer_db_clear_mask && */
> +
> + /* Scrachpads interface is optional */
> /* !ops->spad_is_unsafe == !ops->spad_count && */
> !ops->spad_read == !ops->spad_count &&
> !ops->spad_write == !ops->spad_count &&
> @@ -367,6 +373,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
> /* !ops->peer_spad_read == !ops->spad_count && */
> !ops->peer_spad_write == !ops->spad_count &&
>
> + /* Messaging interface is optional */
> !ops->msg_inbits == !ops->msg_count &&
> !ops->msg_outbits == !ops->msg_count &&
> !ops->msg_read_sts == !ops->msg_count &&
> @@ -387,13 +394,12 @@ struct ntb_client {
> struct device_driver drv;
> const struct ntb_client_ops ops;
> };
> -
> #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
>
> /**
> * struct ntb_device - ntb device
> * @dev: Linux device object.
> - * @pdev: Pci device entry of the ntb.
> + * @pdev: PCI device entry of the ntb.
> * @topo: Detected topology of the ntb.
> * @ops: See &ntb_dev_ops.
> * @ctx: See &ntb_ctx_ops.
> @@ -414,7 +420,6 @@ struct ntb_dev {
> /* block unregister until device is fully released */
> struct completion released;
> };
> -
> #define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
>
> /**
> @@ -511,7 +516,7 @@ void ntb_link_event(struct ntb_dev *ntb);
> * multiple interrupt vectors for doorbells, the vector number indicates which
> * vector received the interrupt. The vector number is relative to the first
> * vector used for doorbells, starting at zero, and must be less than
> - ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> + * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
> * doorbell bits need service, and ntb_db_vector_mask() to determine which of
> * those bits are associated with the vector number.
> */
> --
> 2.6.6


2016-12-20 09:48:36

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 6/9] NTB: Add Messaging NTB API

Some IDT NTB-capable PCIe-switches have message registers to communicate with
peer devices. This patch adds new NTB API callback methods, which can be used
to utilize these registers functionality:
ntb_msg_count(); - get number of message registers
ntb_msg_inbits(); - get bitfield of inbound message registers status
ntb_msg_outbits(); - get bitfield of outbound message registers status
ntb_msg_read_sts(); - read the inbound and outbound message registers status
ntb_msg_clear_sts(); - clear status bits of message registers
ntb_msg_set_mask(); - mask interrupts raised by status bits of message
registers.
ntb_msg_clear_mask(); - clear interrupts mask bits of message registers
ntb_msg_read(midx, *pidx); - read message register with specified index,
additionally getting peer port index which data received from
ntb_msg_write(midx, pidx); - write data to the specified message register
sending it to the passed peer device connected over a pidx port
ntb_msg_event(); - notify driver context of a new message event

Of course there is hardware which doesn't support Message registers, so
this API is made optional.

Acked-by: Allen Hubbe <[email protected]>
Signed-off-by: Serge Semin <[email protected]>
---
drivers/ntb/ntb.c | 13 ++++
include/linux/ntb.h | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+)

diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 2551bb2..03b80d8 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -193,6 +193,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
}
EXPORT_SYMBOL(ntb_db_event);

+void ntb_msg_event(struct ntb_dev *ntb)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+ {
+ if (ntb->ctx_ops && ntb->ctx_ops->msg_event)
+ ntb->ctx_ops->msg_event(ntb->ctx);
+ }
+ spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_msg_event);
+
int ntb_default_port_number(struct ntb_dev *ntb)
{
switch (ntb->topo) {
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index a54e2be..76c56d5 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -178,10 +178,12 @@ static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops)
* struct ntb_ctx_ops - ntb driver context operations
* @link_event: See ntb_link_event().
* @db_event: See ntb_db_event().
+ * @msg_event: See ntb_msg_event().
*/
struct ntb_ctx_ops {
void (*link_event)(void *ctx);
void (*db_event)(void *ctx, int db_vector);
+ void (*msg_event)(void *ctx);
};

static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
@@ -190,6 +192,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
return
/* ops->link_event && */
/* ops->db_event && */
+ /* ops->msg_event && */
1;
}

@@ -234,6 +237,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @peer_spad_addr: See ntb_peer_spad_addr().
* @peer_spad_read: See ntb_peer_spad_read().
* @peer_spad_write: See ntb_peer_spad_write().
+ * @msg_count: See ntb_msg_count().
+ * @msg_inbits: See ntb_msg_inbits().
+ * @msg_outbits: See ntb_msg_outbits().
+ * @msg_read_sts: See ntb_msg_read_sts().
+ * @msg_clear_sts: See ntb_msg_clear_sts().
+ * @msg_set_mask: See ntb_msg_set_mask().
+ * @msg_clear_mask: See ntb_msg_clear_mask().
+ * @msg_read: See ntb_msg_read().
+ * @msg_write: See ntb_msg_write().
*/
struct ntb_dev_ops {
int (*port_number)(struct ntb_dev *ntb);
@@ -296,6 +308,16 @@ struct ntb_dev_ops {
u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
u32 val);
+
+ int (*msg_count)(struct ntb_dev *ntb);
+ u64 (*msg_inbits)(struct ntb_dev *ntb);
+ u64 (*msg_outbits)(struct ntb_dev *ntb);
+ u64 (*msg_read_sts)(struct ntb_dev *ntb);
+ int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits);
+ int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
+ int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg);
+ int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg);
};

static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@@ -342,6 +364,15 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->peer_spad_addr == !ops->spad_count && */
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&
+
+ !ops->msg_inbits == !ops->msg_count &&
+ !ops->msg_outbits == !ops->msg_count &&
+ !ops->msg_read_sts == !ops->msg_count &&
+ !ops->msg_clear_sts == !ops->msg_count &&
+ /* !ops->msg_set_mask == !ops->msg_count && */
+ /* !ops->msg_clear_mask == !ops->msg_count && */
+ !ops->msg_read == !ops->msg_count &&
+ !ops->msg_write == !ops->msg_count &&
1;
}

@@ -485,6 +516,18 @@ void ntb_link_event(struct ntb_dev *ntb);
void ntb_db_event(struct ntb_dev *ntb, int vector);

/**
+ * ntb_msg_event() - notify driver context of a message event
+ * @ntb: NTB device context.
+ *
+ * Notify the driver context of a message event. If hardware supports
+ * message registers, this event indicates, that a new message arrived in
+ * some incoming message register or last sent message couldn't be delivered.
+ * The events can be masked/unmasked by the methods ntb_msg_set_mask() and
+ * ntb_msg_clear_mask().
+ */
+void ntb_msg_event(struct ntb_dev *ntb);
+
+/**
* ntb_default_port_number() - get the default local port number
* @ntb: NTB device context.
*
@@ -1282,4 +1325,166 @@ static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
}

+/**
+ * ntb_msg_count() - get the number of message registers
+ * @ntb: NTB device context.
+ *
+ * Hardware may support a different number of message registers.
+ *
+ * Return: the number of message registers.
+ */
+static inline int ntb_msg_count(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_count)
+ return 0;
+
+ return ntb->ops->msg_count(ntb);
+}
+
+/**
+ * ntb_msg_inbits() - get a bitfield of inbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitfield of status and mask registers, which related
+ * to inbound message registers.
+ *
+ * Return: bitfield of inbound message registers.
+ */
+static inline u64 ntb_msg_inbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_inbits)
+ return 0;
+
+ return ntb->ops->msg_inbits(ntb);
+}
+
+/**
+ * ntb_msg_outbits() - get a bitfield of outbound message registers status
+ * @ntb: NTB device context.
+ *
+ * The method returns the bitfield of status and mask registers, which related
+ * to outbound message registers.
+ *
+ * Return: bitfield of outbound message registers.
+ */
+static inline u64 ntb_msg_outbits(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_outbits)
+ return 0;
+
+ return ntb->ops->msg_outbits(ntb);
+}
+
+/**
+ * ntb_msg_read_sts() - read the message registers status
+ * @ntb: NTB device context.
+ *
+ * Read the status of message register. Inbound and outbound message registers
+ * related bits can be filtered by masks retrieved from ntb_msg_inbits() and
+ * ntb_msg_outbits().
+ *
+ * Return: status bits of message registers
+ */
+static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->msg_read_sts)
+ return 0;
+
+ return ntb->ops->msg_read_sts(ntb);
+}
+
+/**
+ * ntb_msg_clear_sts() - clear status bits of message registers
+ * @ntb: NTB device context.
+ * @sts_bits: Status bits to clear.
+ *
+ * Clear bits in the status register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
+{
+ if (!ntb->ops->msg_clear_sts)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_sts(ntb, sts_bits);
+}
+
+/**
+ * ntb_msg_set_mask() - set mask of message register status bits
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits.
+ *
+ * Mask the message registers status bits from raising the message event.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_set_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_set_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_clear_mask() - clear message registers mask
+ * @ntb: NTB device context.
+ * @mask_bits: Mask bits to clear.
+ *
+ * Clear bits in the message events mask register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+ if (!ntb->ops->msg_clear_mask)
+ return -EINVAL;
+
+ return ntb->ops->msg_clear_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_read() - read message register with specified index
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: OUT - Port index of peer device a message retrieved from
+ * @msg: OUT - Data
+ *
+ * Read data from the specified message register. Source port index of a
+ * message is retrieved as well.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx,
+ u32 *msg)
+{
+ if (!ntb->ops->msg_read)
+ return -EINVAL;
+
+ return ntb->ops->msg_read(ntb, midx, pidx, msg);
+}
+
+/**
+ * ntb_msg_write() - write data to the specified message register
+ * @ntb: NTB device context.
+ * @midx: Message register index
+ * @pidx: Port index of peer device a message being sent to
+ * @msg: Data to send
+ *
+ * Send data to a specified peer device using the defined message register.
+ * Message event can be raised if the midx registers isn't empty while
+ * calling this method and the corresponding interrupt isn't masked.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx,
+ u32 msg)
+{
+ if (!ntb->ops->msg_write)
+ return -EINVAL;
+
+ return ntb->ops->msg_write(ntb, midx, pidx, msg);
+}
+
#endif
--
2.6.6

2016-12-20 09:50:26

by Serge Semin

[permalink] [raw]
Subject: [PATCH v3 9/9] NTB: Add ntb.h comments

Acked-by: Allen Hubbe <[email protected]>
Signed-off-by: Serge Semin <[email protected]>
---
include/linux/ntb.h | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 6d46179..dab0a1b 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -326,12 +326,17 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
{
/* commented callbacks are not required: */
return
+ /* Port operations are required for multiport devices */
!ops->peer_port_count == !ops->port_number &&
!ops->peer_port_number == !ops->port_number &&
!ops->peer_port_idx == !ops->port_number &&
+
+ /* Link operations are required */
ops->link_is_up &&
ops->link_enable &&
ops->link_disable &&
+
+ /* One or both MW interfaces should be developed */
ops->mw_count &&
ops->mw_get_align &&
(ops->mw_set_trans ||
@@ -341,12 +346,11 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->peer_mw_get_addr &&
/* ops->peer_mw_clear_trans && */

+ /* Doorbell operations are mostly required */
/* ops->db_is_unsafe && */
ops->db_valid_mask &&
-
/* both set, or both unset */
- (!ops->db_vector_count == !ops->db_vector_mask) &&
-
+ (!ops->db_vector_count == !ops->db_vector_mask) &&
ops->db_read &&
/* ops->db_set && */
ops->db_clear &&
@@ -360,6 +364,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* ops->peer_db_read_mask && */
/* ops->peer_db_set_mask && */
/* ops->peer_db_clear_mask && */
+
+ /* Scrachpads interface is optional */
/* !ops->spad_is_unsafe == !ops->spad_count && */
!ops->spad_read == !ops->spad_count &&
!ops->spad_write == !ops->spad_count &&
@@ -367,6 +373,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->peer_spad_read == !ops->spad_count && */
!ops->peer_spad_write == !ops->spad_count &&

+ /* Messaging interface is optional */
!ops->msg_inbits == !ops->msg_count &&
!ops->msg_outbits == !ops->msg_count &&
!ops->msg_read_sts == !ops->msg_count &&
@@ -387,13 +394,12 @@ struct ntb_client {
struct device_driver drv;
const struct ntb_client_ops ops;
};
-
#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)

/**
* struct ntb_device - ntb device
* @dev: Linux device object.
- * @pdev: Pci device entry of the ntb.
+ * @pdev: PCI device entry of the ntb.
* @topo: Detected topology of the ntb.
* @ops: See &ntb_dev_ops.
* @ctx: See &ntb_ctx_ops.
@@ -414,7 +420,6 @@ struct ntb_dev {
/* block unregister until device is fully released */
struct completion released;
};
-
#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)

/**
@@ -511,7 +516,7 @@ void ntb_link_event(struct ntb_dev *ntb);
* multiple interrupt vectors for doorbells, the vector number indicates which
* vector received the interrupt. The vector number is relative to the first
* vector used for doorbells, starting at zero, and must be less than
- ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
+ * ntb_db_vector_count(). The driver may call ntb_db_read() to check which
* doorbell bits need service, and ntb_db_vector_mask() to determine which of
* those bits are associated with the vector number.
*/
--
2.6.6