[2/6] raw/ntb: add intel ntb support
Checks
Commit Message
Add in the list of registers for the device. And enable ntb device
ops for intel skylake platform.
Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
---
drivers/raw/ntb_rawdev/Makefile | 1 +
drivers/raw/ntb_rawdev/meson.build | 3 +-
drivers/raw/ntb_rawdev/ntb_hw_intel.c | 373 ++++++++++++++++++++++++++
drivers/raw/ntb_rawdev/ntb_hw_intel.h | 85 ++++++
drivers/raw/ntb_rawdev/ntb_rawdev.c | 7 +
5 files changed, 468 insertions(+), 1 deletion(-)
create mode 100644 drivers/raw/ntb_rawdev/ntb_hw_intel.c
create mode 100644 drivers/raw/ntb_rawdev/ntb_hw_intel.h
Comments
On 06/03, Xiaoyun Li wrote:
>Add in the list of registers for the device. And enable ntb device
>ops for intel skylake platform.
>
>Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
>---
> drivers/raw/ntb_rawdev/Makefile | 1 +
> drivers/raw/ntb_rawdev/meson.build | 3 +-
> drivers/raw/ntb_rawdev/ntb_hw_intel.c | 373 ++++++++++++++++++++++++++
> drivers/raw/ntb_rawdev/ntb_hw_intel.h | 85 ++++++
> drivers/raw/ntb_rawdev/ntb_rawdev.c | 7 +
> 5 files changed, 468 insertions(+), 1 deletion(-)
> create mode 100644 drivers/raw/ntb_rawdev/ntb_hw_intel.c
> create mode 100644 drivers/raw/ntb_rawdev/ntb_hw_intel.h
>
>diff --git a/drivers/raw/ntb_rawdev/Makefile b/drivers/raw/ntb_rawdev/Makefile
>index 852b16c77..fc50f7a4f 100644
>--- a/drivers/raw/ntb_rawdev/Makefile
>+++ b/drivers/raw/ntb_rawdev/Makefile
>@@ -23,5 +23,6 @@ LIBABIVER := 1
> # all source are stored in SRCS-y
> #
> SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += ntb_rawdev.c
>+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += ntb_hw_intel.c
>
> include $(RTE_SDK)/mk/rte.lib.mk
>diff --git a/drivers/raw/ntb_rawdev/meson.build b/drivers/raw/ntb_rawdev/meson.build
>index ca905049d..c696f60b3 100644
>--- a/drivers/raw/ntb_rawdev/meson.build
>+++ b/drivers/raw/ntb_rawdev/meson.build
>@@ -3,5 +3,6 @@
>
> deps += ['rawdev', 'mbuf', 'mempool',
> 'pci', 'bus_pci']
>-sources = files('ntb_rawdev.c')
>+sources = files('ntb_rawdev.c',
>+ 'ntb_hw_intel.c')
> allow_experimental_apis = true
>diff --git a/drivers/raw/ntb_rawdev/ntb_hw_intel.c b/drivers/raw/ntb_rawdev/ntb_hw_intel.c
>new file mode 100644
>index 000000000..f8174916d
>--- /dev/null
>+++ b/drivers/raw/ntb_rawdev/ntb_hw_intel.c
>@@ -0,0 +1,373 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2019 Intel Corporation.
>+ */
>+#include <stdint.h>
>+#include <stdio.h>
>+#include <errno.h>
>+
>+#include <rte_eal.h>
>+#include <rte_pci.h>
>+#include <rte_bus_pci.h>
>+#include <rte_rawdev.h>
>+#include <rte_rawdev_pmd.h>
>+
>+#include "ntb_rawdev.h"
>+#include "ntb_hw_intel.h"
>+
>+enum xeon_ntb_bar {
>+ XEON_NTB_BAR23 = 2,
>+ XEON_NTB_BAR45 = 4,
>+};
>+
>+static enum xeon_ntb_bar intel_ntb_bar[] = {
>+ XEON_NTB_BAR23,
>+ XEON_NTB_BAR45,
>+};
>+
>+static int
>+intel_ntb_dev_init(struct rte_rawdev *dev)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint8_t reg_val, bar;
>+ int ret = 0;
>+ int i = 0;
No need to do above initializations.
>+
>+ if (!hw) {
1.8.1
>+ NTB_LOG(ERR, "Invalid device.");
>+ return -EINVAL;
>+ }
>+
>+ ret = rte_pci_read_config(hw->pci_dev, ®_val,
>+ sizeof(reg_val), XEON_PPD_OFFSET);
>+ if (ret < 0) {
>+ NTB_LOG(ERR, "Cannot get NTB PPD (PCIe port definition).");
>+ return -EIO;
>+ }
>+
>+ /* Check connection topo type. Only support B2B. */
>+ switch (reg_val & XEON_PPD_CONN_MASK) {
>+ case XEON_PPD_CONN_B2B:
>+ NTB_LOG(INFO, "Topo B2B (back to back) is using.");
>+ break;
>+ case XEON_PPD_CONN_TRANSPARENT:
>+ case XEON_PPD_CONN_RP:
>+ NTB_LOG(ERR, "Not supported conn topo. Please use B2B.");
>+ return -EINVAL;
>+ }
>+
>+ /* Check device type. */
>+ if (reg_val & XEON_PPD_DEV_DSD) {
>+ NTB_LOG(INFO, "DSD, Downstream Device.");
>+ hw->topo = NTB_TOPO_B2B_DSD;
>+ } else {
>+ NTB_LOG(INFO, "USD, Upstream device.");
>+ hw->topo = NTB_TOPO_B2B_USD;
>+ }
>+
>+ /* Check if bar4 is split. Do not support split bar. */
>+ if (reg_val & XEON_PPD_SPLIT_BAR_MASK) {
>+ NTB_LOG(ERR, "Do not support split bar.");
>+ return -EINVAL;
>+ }
>+
>+ hw->mw_cnt = XEON_MW_COUNT;
>+ hw->db_cnt = XEON_DB_COUNT;
>+ hw->spad_cnt = XEON_SPAD_COUNT;
>+
>+ hw->mw_size = rte_zmalloc("uint64_t",
>+ hw->mw_cnt * sizeof(uint64_t), 0);
>+ for (i = 0; i < hw->mw_cnt; i++) {
>+ bar = intel_ntb_bar[i];
>+ hw->mw_size[i] = hw->pci_dev->mem_resource[bar].len;
>+ }
>+
>+ return 0;
>+}
>+
>+static uint64_t
>+intel_ntb_get_peer_mw_addr(struct rte_rawdev *dev, int mw_idx)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint8_t bar;
>+
>+ bar = intel_ntb_bar[mw_idx];
Do we need a sanity check for mw_idx here?
>+
>+ return (uint64_t)(hw->pci_dev->mem_resource[bar].addr);
>+}
>+
>+static int
>+intel_ntb_mw_set_trans(struct rte_rawdev *dev, int mw_idx,
>+ uint64_t addr, uint64_t size)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ void *xlat_addr, *limit_addr;
>+ uint64_t xlat_off, limit_off;
>+ uint64_t base, limit;
>+ uint8_t bar;
>+
>+ if (!hw) {
1.8.1
>+ NTB_LOG(ERR, "Invalid device.");
>+ return -EINVAL;
>+ }
>+
>+ if (mw_idx < 0 || mw_idx > hw->mw_cnt) {
>+ NTB_LOG(ERR, "Invalid memory window index (0 - %u).",
>+ hw->mw_cnt - 1);
>+ return -EINVAL;
>+ }
>+
>+ bar = intel_ntb_bar[mw_idx];
>+
>+ xlat_off = XEON_IMBAR1XBASE_OFFSET + mw_idx * 0x10;
>+ limit_off = XEON_IMBAR1XLMT_OFFSET + mw_idx * 0x10;
Use Marco for the magical 0x10 ?
>+ xlat_addr = (char *)hw->pci_dev->mem_resource[0].addr + xlat_off;
>+ limit_addr = (char *)hw->pci_dev->mem_resource[0].addr + limit_off;
>+
>+ /* Limit reg val should be EMBAR base address plus MW size. */
>+ base = addr;
>+ limit = hw->pci_dev->mem_resource[bar].phys_addr + size;
>+ *((volatile uint64_t *)xlat_addr) = base;
>+ *((volatile uint64_t *)limit_addr) = limit;
>+
>+ /* Setup the external point so that remote can access. */
>+ xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
>+ xlat_addr = (char *)hw->pci_dev->mem_resource[0].addr + xlat_off;
>+ limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx * 0x10;
>+ limit_addr = (char *)hw->pci_dev->mem_resource[0].addr + limit_off;
>+ base = *((volatile uint64_t *)xlat_addr);
>+ base &= ~0xf;
>+ limit = base + size;
>+ *((volatile uint64_t *)limit_addr) = limit;
>+
>+ return 0;
>+}
>+
>+static int
>+intel_ntb_get_link_status(struct rte_rawdev *dev)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint16_t reg_val;
>+ int ret = 0;
>+
>+ if (!hw) {
1.8.1
>+ NTB_LOG(ERR, "Invalid device.");
>+ return -EINVAL;
>+ }
>+
>+ ret = rte_pci_read_config(hw->pci_dev, ®_val,
>+ sizeof(reg_val), XEON_LINK_STATUS_OFFSET);
>+ if (ret < 0) {
>+ NTB_LOG(ERR, "Unable to get link status.");
>+ return -EIO;
>+ }
>+
>+ hw->link_status = NTB_LNK_STA_ACTIVE(reg_val);
>+
>+ if (hw->link_status) {
>+ hw->link_speed = NTB_LNK_STA_SPEED(reg_val);
>+ hw->link_width = NTB_LNK_STA_WIDTH(reg_val);
>+ } else {
>+ hw->link_speed = NTB_SPEED_NONE;
>+ hw->link_width = NTB_WIDTH_NONE;
>+ }
>+
>+ return 0;
>+}
>+
>+static int
>+intel_ntb_set_link_up(struct rte_rawdev *dev)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint32_t ntb_ctrl, reg_off;
>+ void *reg_addr;
>+
>+ reg_off = XEON_NTBCNTL_OFFSET;
>+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr + reg_off;
>+ ntb_ctrl = *((volatile uint32_t *)reg_addr);
>+
>+ ntb_ctrl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
>+ ntb_ctrl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
>+ ntb_ctrl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
>+
>+ *((volatile uint32_t *)reg_addr) = ntb_ctrl;
>+
>+ return 0;
>+}
>+
>+static int
>+intel_ntb_set_link_down(struct rte_rawdev *dev)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint32_t ntb_ctrl, reg_off;
>+ void *reg_addr;
>+
>+ reg_off = XEON_NTBCNTL_OFFSET;
>+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr + reg_off;
>+ ntb_ctrl = *((volatile uint32_t *)reg_addr);
>+
>+ ntb_ctrl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
>+ ntb_ctrl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
>+ ntb_ctrl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
>+
>+ *((volatile uint32_t *)reg_addr) = ntb_ctrl;
>+
>+ return 0;
>+}
Above two functions share most of the code, can consider to extract the common
part into one internal function.
>+
>+static uint32_t
>+intel_ntb_spad_read(struct rte_rawdev *dev, int spad, int peer)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint32_t spad_v, reg_off;
>+ void *reg_addr;
>+
>+ if (spad < 0 || spad >= hw->spad_cnt) {
>+ NTB_LOG(ERR, "Invalid spad reg index.");
>+ return 0;
>+ }
>+
>+ /* When peer is non-zero, read peer spad reg */
>+ if (peer)
>+ reg_off = XEON_B2B_SPAD_OFFSET;
>+ else
>+ reg_off = XEON_IM_SPAD_OFFSET;
>+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr +
>+ reg_off + (spad << 2);
>+ spad_v = *((volatile uint32_t *)reg_addr);
>+
>+ return spad_v;
>+}
>+
>+static int
>+intel_ntb_spad_write(struct rte_rawdev *dev, int spad,
>+ int peer, uint32_t spad_v)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint32_t reg_off;
>+ void *reg_addr;
>+
>+ if (spad < 0 || spad >= hw->spad_cnt) {
>+ NTB_LOG(ERR, "Invalid spad reg index.");
>+ return -EINVAL;
>+ }
>+
>+ /* When peer is non-zero, write peer spad reg */
>+ if (peer)
>+ reg_off = XEON_B2B_SPAD_OFFSET;
>+ else
>+ reg_off = XEON_IM_SPAD_OFFSET;
>+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr +
>+ reg_off + (spad << 2);
>+
>+ *((volatile uint32_t *)reg_addr) = spad_v;
>+
>+ return 0;
>+}
>+
>+static uint64_t
>+intel_ntb_db_read(struct rte_rawdev *dev)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint64_t db_off, db_bits;
>+ void *db_addr;
>+
>+ db_off = XEON_IM_INT_STATUS_OFFSET;
>+ db_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_off;
>+
>+ db_bits = *((volatile uint64_t *)db_addr);
>+
>+ return db_bits;
>+}
>+
>+static int
>+intel_ntb_db_clear(struct rte_rawdev *dev, uint64_t db_bits)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint64_t db_off;
>+ void *db_addr;
>+
>+ db_off = XEON_IM_INT_STATUS_OFFSET;
>+ db_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_off;
>+
>+ *((volatile uint64_t *)db_addr) = db_bits;
>+
>+ return 0;
>+}
>+
>+static int
>+intel_ntb_db_set_mask(struct rte_rawdev *dev, uint64_t db_mask)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint64_t db_m_off;
>+ void *db_m_addr;
>+
>+ db_m_off = XEON_IM_INT_DISABLE_OFFSET;
>+ db_m_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_m_off;
>+
>+ db_mask |= hw->db_mask;
>+
>+ *((volatile uint64_t *)db_m_addr) = db_mask;
>+
>+ hw->db_mask = db_mask;
>+
>+ return 0;
>+}
>+
>+static int
>+intel_ntb_peer_db_set(struct rte_rawdev *dev, uint8_t db_idx)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint32_t db_off;
>+ void *db_addr;
>+
>+ if (((uint64_t)1 << db_idx) & ~hw->db_valid_mask) {
>+ NTB_LOG(ERR, "Invalid doorbell.");
>+ return -EINVAL;
>+ }
>+
>+ db_off = XEON_IM_DOORBELL_OFFSET + db_idx * 4;
>+ db_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_off;
>+
>+ *((volatile uint32_t *)db_addr) = 1;
>+
>+ return 0;
>+}
>+
>+static int
>+intel_ntb_vector_bind(struct rte_rawdev *dev, uint8_t intr, uint8_t msix)
>+{
>+ struct ntb_hw *hw = dev->dev_private;
>+ uint8_t reg_off;
>+ void *reg_addr;
>+
>+ if (intr >= hw->db_cnt) {
>+ NTB_LOG(ERR, "Invalid intr source.");
>+ return -EINVAL;
>+ }
>+
>+ /* Bind intr source to msix vector */
>+ reg_off = XEON_INTVEC_OFFSET;
>+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr +
>+ reg_off + intr;
>+
>+ *((volatile uint8_t *)reg_addr) = msix;
>+
>+ return 0;
>+}
>+
>+/* operations for primary side of local ntb */
>+const struct ntb_dev_ops intel_ntb_ops = {
>+ .ntb_dev_init = intel_ntb_dev_init,
>+ .get_peer_mw_addr = intel_ntb_get_peer_mw_addr,
>+ .mw_set_trans = intel_ntb_mw_set_trans,
>+ .get_link_status = intel_ntb_get_link_status,
>+ .set_link_up = intel_ntb_set_link_up,
>+ .set_link_down = intel_ntb_set_link_down,
>+ .spad_read = intel_ntb_spad_read,
>+ .spad_write = intel_ntb_spad_write,
>+ .db_read = intel_ntb_db_read,
>+ .db_clear = intel_ntb_db_clear,
>+ .db_set_mask = intel_ntb_db_set_mask,
>+ .peer_db_set = intel_ntb_peer_db_set,
>+ .vector_bind = intel_ntb_vector_bind,
>+};
>diff --git a/drivers/raw/ntb_rawdev/ntb_hw_intel.h b/drivers/raw/ntb_rawdev/ntb_hw_intel.h
>new file mode 100644
>index 000000000..eb798b1de
>--- /dev/null
>+++ b/drivers/raw/ntb_rawdev/ntb_hw_intel.h
>@@ -0,0 +1,85 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2019 Intel Corporation.
>+ */
>+
>+#ifndef _NTB_HW_INTEL_H_
>+#define _NTB_HW_INTEL_H_
>+
>+/* Ntb control and link status */
>+#define NTB_CTL_CFG_LOCK 1
>+#define NTB_CTL_DISABLE 2
>+#define NTB_CTL_S2P_BAR2_SNOOP (1 << 2)
>+#define NTB_CTL_P2S_BAR2_SNOOP (1 << 4)
>+#define NTB_CTL_S2P_BAR4_SNOOP (1 << 6)
>+#define NTB_CTL_P2S_BAR4_SNOOP (1 << 8)
>+#define NTB_CTL_S2P_BAR5_SNOOP (1 << 12)
>+#define NTB_CTL_P2S_BAR5_SNOOP (1 << 14)
>+
>+#define NTB_LNK_STA_ACTIVE_BIT 0x2000
>+#define NTB_LNK_STA_SPEED_MASK 0x000f
>+#define NTB_LNK_STA_WIDTH_MASK 0x03f0
>+#define NTB_LNK_STA_ACTIVE(x) (!!((x) & NTB_LNK_STA_ACTIVE_BIT))
>+#define NTB_LNK_STA_SPEED(x) ((x) & NTB_LNK_STA_SPEED_MASK)
>+#define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 4)
>+
>+/* Intel Skylake Xeon hardware */
>+#define XEON_IMBAR1SZ_OFFSET 0x00d0
>+#define XEON_IMBAR2SZ_OFFSET 0x00d1
>+#define XEON_EMBAR1SZ_OFFSET 0x00d2
>+#define XEON_EMBAR2SZ_OFFSET 0x00d3
>+#define XEON_DEVCTRL_OFFSET 0x0098
>+#define XEON_DEVSTS_OFFSET 0x009a
>+#define XEON_UNCERRSTS_OFFSET 0x014c
>+#define XEON_CORERRSTS_OFFSET 0x0158
>+#define XEON_LINK_STATUS_OFFSET 0x01a2
>+
>+#define XEON_NTBCNTL_OFFSET 0x0000
>+#define XEON_IMBAR1XBASE_OFFSET 0x0010 /* SBAR2XLAT */
>+#define XEON_IMBAR1XLMT_OFFSET 0x0018 /* SBAR2LMT */
>+#define XEON_IMBAR2XBASE_OFFSET 0x0020 /* SBAR4XLAT */
>+#define XEON_IMBAR2XLMT_OFFSET 0x0028 /* SBAR4LMT */
>+#define XEON_IM_INT_STATUS_OFFSET 0x0040
>+#define XEON_IM_INT_DISABLE_OFFSET 0x0048
>+#define XEON_IM_SPAD_OFFSET 0x0080 /* SPAD */
>+#define XEON_USMEMMISS_OFFSET 0x0070
>+#define XEON_INTVEC_OFFSET 0x00d0
>+#define XEON_IM_DOORBELL_OFFSET 0x0100 /* SDOORBELL0 */
>+#define XEON_B2B_SPAD_OFFSET 0x0180 /* B2B SPAD */
>+#define XEON_EMBAR0XBASE_OFFSET 0x4008 /* B2B_XLAT */
>+#define XEON_EMBAR1XBASE_OFFSET 0x4010 /* PBAR2XLAT */
>+#define XEON_EMBAR1XLMT_OFFSET 0x4018 /* PBAR2LMT */
>+#define XEON_EMBAR2XBASE_OFFSET 0x4020 /* PBAR4XLAT */
>+#define XEON_EMBAR2XLMT_OFFSET 0x4028 /* PBAR4LMT */
>+#define XEON_EM_INT_STATUS_OFFSET 0x4040
>+#define XEON_EM_INT_DISABLE_OFFSET 0x4048
>+#define XEON_EM_SPAD_OFFSET 0x4080 /* remote SPAD */
>+#define XEON_EM_DOORBELL_OFFSET 0x4100 /* PDOORBELL0 */
>+#define XEON_SPCICMD_OFFSET 0x4504 /* SPCICMD */
>+#define XEON_EMBAR0_OFFSET 0x4510 /* SBAR0BASE */
>+#define XEON_EMBAR1_OFFSET 0x4518 /* SBAR23BASE */
>+#define XEON_EMBAR2_OFFSET 0x4520 /* SBAR45BASE */
>+
>+#define XEON_PPD_OFFSET 0x00d4
>+#define XEON_PPD_CONN_MASK 0x03
>+#define XEON_PPD_CONN_TRANSPARENT 0x00
>+#define XEON_PPD_CONN_B2B 0x01
>+#define XEON_PPD_CONN_RP 0x02
>+#define XEON_PPD_DEV_MASK 0x10
>+#define XEON_PPD_DEV_USD 0x00
>+#define XEON_PPD_DEV_DSD 0x10
>+#define XEON_PPD_SPLIT_BAR_MASK 0x40
>+
>+
>+#define XEON_MW_COUNT 2
>+
>+#define XEON_DB_COUNT 32
>+#define XEON_DB_LINK 32
>+#define XEON_DB_LINK_BIT (1ULL << XEON_DB_LINK)
>+#define XEON_DB_MSIX_VECTOR_COUNT 33
>+#define XEON_DB_MSIX_VECTOR_SHIFT 1
>+#define XEON_DB_TOTAL_SHIFT 33
>+#define XEON_SPAD_COUNT 16
>+
>+extern const struct ntb_dev_ops intel_ntb_ops;
>+
>+#endif /* _NTB_HW_INTEL_H_ */
>diff --git a/drivers/raw/ntb_rawdev/ntb_rawdev.c b/drivers/raw/ntb_rawdev/ntb_rawdev.c
>index 4634c9ef9..54c52a340 100644
>--- a/drivers/raw/ntb_rawdev/ntb_rawdev.c
>+++ b/drivers/raw/ntb_rawdev/ntb_rawdev.c
>@@ -18,11 +18,13 @@
> #include <rte_rawdev.h>
> #include <rte_rawdev_pmd.h>
>
>+#include "ntb_hw_intel.h"
> #include "ntb_rawdev.h"
>
> int ntb_logtype;
>
> static const struct rte_pci_id pci_id_ntb_map[] = {
>+ { RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_SKX) },
> { .vendor_id = 0, /* sentinel */ },
> };
>
>@@ -146,6 +148,7 @@ static int
> ntb_dev_start(struct rte_rawdev *dev)
> {
> /* TODO: init queues and start queues. */
>+
Remove this extra empty line.
> dev->started = 1;
>
> return 0;
>@@ -155,6 +158,7 @@ static void
> ntb_dev_stop(struct rte_rawdev *dev)
> {
> /* TODO: stop rx/tx queues. */
>+
Ditto.
> dev->started = 0;
> }
>
>@@ -355,6 +359,9 @@ ntb_init_hw(struct rte_rawdev *dev, struct rte_pci_device *pci_dev)
> hw->link_width = NTB_WIDTH_NONE;
>
> switch (pci_dev->id.device_id) {
>+ case NTB_INTEL_DEV_ID_B2B_SKX:
>+ hw->ntb_ops = &intel_ntb_ops;
>+ break;
> default:
> NTB_LOG(ERR, "Not supported device.");
> return -EINVAL;
>--
>2.17.1
>
@@ -23,5 +23,6 @@ LIBABIVER := 1
# all source are stored in SRCS-y
#
SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += ntb_rawdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += ntb_hw_intel.c
include $(RTE_SDK)/mk/rte.lib.mk
@@ -3,5 +3,6 @@
deps += ['rawdev', 'mbuf', 'mempool',
'pci', 'bus_pci']
-sources = files('ntb_rawdev.c')
+sources = files('ntb_rawdev.c',
+ 'ntb_hw_intel.c')
allow_experimental_apis = true
new file mode 100644
@@ -0,0 +1,373 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation.
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <rte_eal.h>
+#include <rte_pci.h>
+#include <rte_bus_pci.h>
+#include <rte_rawdev.h>
+#include <rte_rawdev_pmd.h>
+
+#include "ntb_rawdev.h"
+#include "ntb_hw_intel.h"
+
+enum xeon_ntb_bar {
+ XEON_NTB_BAR23 = 2,
+ XEON_NTB_BAR45 = 4,
+};
+
+static enum xeon_ntb_bar intel_ntb_bar[] = {
+ XEON_NTB_BAR23,
+ XEON_NTB_BAR45,
+};
+
+static int
+intel_ntb_dev_init(struct rte_rawdev *dev)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint8_t reg_val, bar;
+ int ret = 0;
+ int i = 0;
+
+ if (!hw) {
+ NTB_LOG(ERR, "Invalid device.");
+ return -EINVAL;
+ }
+
+ ret = rte_pci_read_config(hw->pci_dev, ®_val,
+ sizeof(reg_val), XEON_PPD_OFFSET);
+ if (ret < 0) {
+ NTB_LOG(ERR, "Cannot get NTB PPD (PCIe port definition).");
+ return -EIO;
+ }
+
+ /* Check connection topo type. Only support B2B. */
+ switch (reg_val & XEON_PPD_CONN_MASK) {
+ case XEON_PPD_CONN_B2B:
+ NTB_LOG(INFO, "Topo B2B (back to back) is using.");
+ break;
+ case XEON_PPD_CONN_TRANSPARENT:
+ case XEON_PPD_CONN_RP:
+ NTB_LOG(ERR, "Not supported conn topo. Please use B2B.");
+ return -EINVAL;
+ }
+
+ /* Check device type. */
+ if (reg_val & XEON_PPD_DEV_DSD) {
+ NTB_LOG(INFO, "DSD, Downstream Device.");
+ hw->topo = NTB_TOPO_B2B_DSD;
+ } else {
+ NTB_LOG(INFO, "USD, Upstream device.");
+ hw->topo = NTB_TOPO_B2B_USD;
+ }
+
+ /* Check if bar4 is split. Do not support split bar. */
+ if (reg_val & XEON_PPD_SPLIT_BAR_MASK) {
+ NTB_LOG(ERR, "Do not support split bar.");
+ return -EINVAL;
+ }
+
+ hw->mw_cnt = XEON_MW_COUNT;
+ hw->db_cnt = XEON_DB_COUNT;
+ hw->spad_cnt = XEON_SPAD_COUNT;
+
+ hw->mw_size = rte_zmalloc("uint64_t",
+ hw->mw_cnt * sizeof(uint64_t), 0);
+ for (i = 0; i < hw->mw_cnt; i++) {
+ bar = intel_ntb_bar[i];
+ hw->mw_size[i] = hw->pci_dev->mem_resource[bar].len;
+ }
+
+ return 0;
+}
+
+static uint64_t
+intel_ntb_get_peer_mw_addr(struct rte_rawdev *dev, int mw_idx)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint8_t bar;
+
+ bar = intel_ntb_bar[mw_idx];
+
+ return (uint64_t)(hw->pci_dev->mem_resource[bar].addr);
+}
+
+static int
+intel_ntb_mw_set_trans(struct rte_rawdev *dev, int mw_idx,
+ uint64_t addr, uint64_t size)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ void *xlat_addr, *limit_addr;
+ uint64_t xlat_off, limit_off;
+ uint64_t base, limit;
+ uint8_t bar;
+
+ if (!hw) {
+ NTB_LOG(ERR, "Invalid device.");
+ return -EINVAL;
+ }
+
+ if (mw_idx < 0 || mw_idx > hw->mw_cnt) {
+ NTB_LOG(ERR, "Invalid memory window index (0 - %u).",
+ hw->mw_cnt - 1);
+ return -EINVAL;
+ }
+
+ bar = intel_ntb_bar[mw_idx];
+
+ xlat_off = XEON_IMBAR1XBASE_OFFSET + mw_idx * 0x10;
+ limit_off = XEON_IMBAR1XLMT_OFFSET + mw_idx * 0x10;
+ xlat_addr = (char *)hw->pci_dev->mem_resource[0].addr + xlat_off;
+ limit_addr = (char *)hw->pci_dev->mem_resource[0].addr + limit_off;
+
+ /* Limit reg val should be EMBAR base address plus MW size. */
+ base = addr;
+ limit = hw->pci_dev->mem_resource[bar].phys_addr + size;
+ *((volatile uint64_t *)xlat_addr) = base;
+ *((volatile uint64_t *)limit_addr) = limit;
+
+ /* Setup the external point so that remote can access. */
+ xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
+ xlat_addr = (char *)hw->pci_dev->mem_resource[0].addr + xlat_off;
+ limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx * 0x10;
+ limit_addr = (char *)hw->pci_dev->mem_resource[0].addr + limit_off;
+ base = *((volatile uint64_t *)xlat_addr);
+ base &= ~0xf;
+ limit = base + size;
+ *((volatile uint64_t *)limit_addr) = limit;
+
+ return 0;
+}
+
+static int
+intel_ntb_get_link_status(struct rte_rawdev *dev)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint16_t reg_val;
+ int ret = 0;
+
+ if (!hw) {
+ NTB_LOG(ERR, "Invalid device.");
+ return -EINVAL;
+ }
+
+ ret = rte_pci_read_config(hw->pci_dev, ®_val,
+ sizeof(reg_val), XEON_LINK_STATUS_OFFSET);
+ if (ret < 0) {
+ NTB_LOG(ERR, "Unable to get link status.");
+ return -EIO;
+ }
+
+ hw->link_status = NTB_LNK_STA_ACTIVE(reg_val);
+
+ if (hw->link_status) {
+ hw->link_speed = NTB_LNK_STA_SPEED(reg_val);
+ hw->link_width = NTB_LNK_STA_WIDTH(reg_val);
+ } else {
+ hw->link_speed = NTB_SPEED_NONE;
+ hw->link_width = NTB_WIDTH_NONE;
+ }
+
+ return 0;
+}
+
+static int
+intel_ntb_set_link_up(struct rte_rawdev *dev)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint32_t ntb_ctrl, reg_off;
+ void *reg_addr;
+
+ reg_off = XEON_NTBCNTL_OFFSET;
+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr + reg_off;
+ ntb_ctrl = *((volatile uint32_t *)reg_addr);
+
+ ntb_ctrl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
+ ntb_ctrl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+ ntb_ctrl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+
+ *((volatile uint32_t *)reg_addr) = ntb_ctrl;
+
+ return 0;
+}
+
+static int
+intel_ntb_set_link_down(struct rte_rawdev *dev)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint32_t ntb_ctrl, reg_off;
+ void *reg_addr;
+
+ reg_off = XEON_NTBCNTL_OFFSET;
+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr + reg_off;
+ ntb_ctrl = *((volatile uint32_t *)reg_addr);
+
+ ntb_ctrl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
+ ntb_ctrl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
+ ntb_ctrl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
+
+ *((volatile uint32_t *)reg_addr) = ntb_ctrl;
+
+ return 0;
+}
+
+static uint32_t
+intel_ntb_spad_read(struct rte_rawdev *dev, int spad, int peer)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint32_t spad_v, reg_off;
+ void *reg_addr;
+
+ if (spad < 0 || spad >= hw->spad_cnt) {
+ NTB_LOG(ERR, "Invalid spad reg index.");
+ return 0;
+ }
+
+ /* When peer is non-zero, read peer spad reg */
+ if (peer)
+ reg_off = XEON_B2B_SPAD_OFFSET;
+ else
+ reg_off = XEON_IM_SPAD_OFFSET;
+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr +
+ reg_off + (spad << 2);
+ spad_v = *((volatile uint32_t *)reg_addr);
+
+ return spad_v;
+}
+
+static int
+intel_ntb_spad_write(struct rte_rawdev *dev, int spad,
+ int peer, uint32_t spad_v)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint32_t reg_off;
+ void *reg_addr;
+
+ if (spad < 0 || spad >= hw->spad_cnt) {
+ NTB_LOG(ERR, "Invalid spad reg index.");
+ return -EINVAL;
+ }
+
+ /* When peer is non-zero, write peer spad reg */
+ if (peer)
+ reg_off = XEON_B2B_SPAD_OFFSET;
+ else
+ reg_off = XEON_IM_SPAD_OFFSET;
+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr +
+ reg_off + (spad << 2);
+
+ *((volatile uint32_t *)reg_addr) = spad_v;
+
+ return 0;
+}
+
+static uint64_t
+intel_ntb_db_read(struct rte_rawdev *dev)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint64_t db_off, db_bits;
+ void *db_addr;
+
+ db_off = XEON_IM_INT_STATUS_OFFSET;
+ db_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_off;
+
+ db_bits = *((volatile uint64_t *)db_addr);
+
+ return db_bits;
+}
+
+static int
+intel_ntb_db_clear(struct rte_rawdev *dev, uint64_t db_bits)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint64_t db_off;
+ void *db_addr;
+
+ db_off = XEON_IM_INT_STATUS_OFFSET;
+ db_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_off;
+
+ *((volatile uint64_t *)db_addr) = db_bits;
+
+ return 0;
+}
+
+static int
+intel_ntb_db_set_mask(struct rte_rawdev *dev, uint64_t db_mask)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint64_t db_m_off;
+ void *db_m_addr;
+
+ db_m_off = XEON_IM_INT_DISABLE_OFFSET;
+ db_m_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_m_off;
+
+ db_mask |= hw->db_mask;
+
+ *((volatile uint64_t *)db_m_addr) = db_mask;
+
+ hw->db_mask = db_mask;
+
+ return 0;
+}
+
+static int
+intel_ntb_peer_db_set(struct rte_rawdev *dev, uint8_t db_idx)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint32_t db_off;
+ void *db_addr;
+
+ if (((uint64_t)1 << db_idx) & ~hw->db_valid_mask) {
+ NTB_LOG(ERR, "Invalid doorbell.");
+ return -EINVAL;
+ }
+
+ db_off = XEON_IM_DOORBELL_OFFSET + db_idx * 4;
+ db_addr = (char *)hw->pci_dev->mem_resource[0].addr + db_off;
+
+ *((volatile uint32_t *)db_addr) = 1;
+
+ return 0;
+}
+
+static int
+intel_ntb_vector_bind(struct rte_rawdev *dev, uint8_t intr, uint8_t msix)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ uint8_t reg_off;
+ void *reg_addr;
+
+ if (intr >= hw->db_cnt) {
+ NTB_LOG(ERR, "Invalid intr source.");
+ return -EINVAL;
+ }
+
+ /* Bind intr source to msix vector */
+ reg_off = XEON_INTVEC_OFFSET;
+ reg_addr = (char *)hw->pci_dev->mem_resource[0].addr +
+ reg_off + intr;
+
+ *((volatile uint8_t *)reg_addr) = msix;
+
+ return 0;
+}
+
+/* operations for primary side of local ntb */
+const struct ntb_dev_ops intel_ntb_ops = {
+ .ntb_dev_init = intel_ntb_dev_init,
+ .get_peer_mw_addr = intel_ntb_get_peer_mw_addr,
+ .mw_set_trans = intel_ntb_mw_set_trans,
+ .get_link_status = intel_ntb_get_link_status,
+ .set_link_up = intel_ntb_set_link_up,
+ .set_link_down = intel_ntb_set_link_down,
+ .spad_read = intel_ntb_spad_read,
+ .spad_write = intel_ntb_spad_write,
+ .db_read = intel_ntb_db_read,
+ .db_clear = intel_ntb_db_clear,
+ .db_set_mask = intel_ntb_db_set_mask,
+ .peer_db_set = intel_ntb_peer_db_set,
+ .vector_bind = intel_ntb_vector_bind,
+};
new file mode 100644
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation.
+ */
+
+#ifndef _NTB_HW_INTEL_H_
+#define _NTB_HW_INTEL_H_
+
+/* Ntb control and link status */
+#define NTB_CTL_CFG_LOCK 1
+#define NTB_CTL_DISABLE 2
+#define NTB_CTL_S2P_BAR2_SNOOP (1 << 2)
+#define NTB_CTL_P2S_BAR2_SNOOP (1 << 4)
+#define NTB_CTL_S2P_BAR4_SNOOP (1 << 6)
+#define NTB_CTL_P2S_BAR4_SNOOP (1 << 8)
+#define NTB_CTL_S2P_BAR5_SNOOP (1 << 12)
+#define NTB_CTL_P2S_BAR5_SNOOP (1 << 14)
+
+#define NTB_LNK_STA_ACTIVE_BIT 0x2000
+#define NTB_LNK_STA_SPEED_MASK 0x000f
+#define NTB_LNK_STA_WIDTH_MASK 0x03f0
+#define NTB_LNK_STA_ACTIVE(x) (!!((x) & NTB_LNK_STA_ACTIVE_BIT))
+#define NTB_LNK_STA_SPEED(x) ((x) & NTB_LNK_STA_SPEED_MASK)
+#define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 4)
+
+/* Intel Skylake Xeon hardware */
+#define XEON_IMBAR1SZ_OFFSET 0x00d0
+#define XEON_IMBAR2SZ_OFFSET 0x00d1
+#define XEON_EMBAR1SZ_OFFSET 0x00d2
+#define XEON_EMBAR2SZ_OFFSET 0x00d3
+#define XEON_DEVCTRL_OFFSET 0x0098
+#define XEON_DEVSTS_OFFSET 0x009a
+#define XEON_UNCERRSTS_OFFSET 0x014c
+#define XEON_CORERRSTS_OFFSET 0x0158
+#define XEON_LINK_STATUS_OFFSET 0x01a2
+
+#define XEON_NTBCNTL_OFFSET 0x0000
+#define XEON_IMBAR1XBASE_OFFSET 0x0010 /* SBAR2XLAT */
+#define XEON_IMBAR1XLMT_OFFSET 0x0018 /* SBAR2LMT */
+#define XEON_IMBAR2XBASE_OFFSET 0x0020 /* SBAR4XLAT */
+#define XEON_IMBAR2XLMT_OFFSET 0x0028 /* SBAR4LMT */
+#define XEON_IM_INT_STATUS_OFFSET 0x0040
+#define XEON_IM_INT_DISABLE_OFFSET 0x0048
+#define XEON_IM_SPAD_OFFSET 0x0080 /* SPAD */
+#define XEON_USMEMMISS_OFFSET 0x0070
+#define XEON_INTVEC_OFFSET 0x00d0
+#define XEON_IM_DOORBELL_OFFSET 0x0100 /* SDOORBELL0 */
+#define XEON_B2B_SPAD_OFFSET 0x0180 /* B2B SPAD */
+#define XEON_EMBAR0XBASE_OFFSET 0x4008 /* B2B_XLAT */
+#define XEON_EMBAR1XBASE_OFFSET 0x4010 /* PBAR2XLAT */
+#define XEON_EMBAR1XLMT_OFFSET 0x4018 /* PBAR2LMT */
+#define XEON_EMBAR2XBASE_OFFSET 0x4020 /* PBAR4XLAT */
+#define XEON_EMBAR2XLMT_OFFSET 0x4028 /* PBAR4LMT */
+#define XEON_EM_INT_STATUS_OFFSET 0x4040
+#define XEON_EM_INT_DISABLE_OFFSET 0x4048
+#define XEON_EM_SPAD_OFFSET 0x4080 /* remote SPAD */
+#define XEON_EM_DOORBELL_OFFSET 0x4100 /* PDOORBELL0 */
+#define XEON_SPCICMD_OFFSET 0x4504 /* SPCICMD */
+#define XEON_EMBAR0_OFFSET 0x4510 /* SBAR0BASE */
+#define XEON_EMBAR1_OFFSET 0x4518 /* SBAR23BASE */
+#define XEON_EMBAR2_OFFSET 0x4520 /* SBAR45BASE */
+
+#define XEON_PPD_OFFSET 0x00d4
+#define XEON_PPD_CONN_MASK 0x03
+#define XEON_PPD_CONN_TRANSPARENT 0x00
+#define XEON_PPD_CONN_B2B 0x01
+#define XEON_PPD_CONN_RP 0x02
+#define XEON_PPD_DEV_MASK 0x10
+#define XEON_PPD_DEV_USD 0x00
+#define XEON_PPD_DEV_DSD 0x10
+#define XEON_PPD_SPLIT_BAR_MASK 0x40
+
+
+#define XEON_MW_COUNT 2
+
+#define XEON_DB_COUNT 32
+#define XEON_DB_LINK 32
+#define XEON_DB_LINK_BIT (1ULL << XEON_DB_LINK)
+#define XEON_DB_MSIX_VECTOR_COUNT 33
+#define XEON_DB_MSIX_VECTOR_SHIFT 1
+#define XEON_DB_TOTAL_SHIFT 33
+#define XEON_SPAD_COUNT 16
+
+extern const struct ntb_dev_ops intel_ntb_ops;
+
+#endif /* _NTB_HW_INTEL_H_ */
@@ -18,11 +18,13 @@
#include <rte_rawdev.h>
#include <rte_rawdev_pmd.h>
+#include "ntb_hw_intel.h"
#include "ntb_rawdev.h"
int ntb_logtype;
static const struct rte_pci_id pci_id_ntb_map[] = {
+ { RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_SKX) },
{ .vendor_id = 0, /* sentinel */ },
};
@@ -146,6 +148,7 @@ static int
ntb_dev_start(struct rte_rawdev *dev)
{
/* TODO: init queues and start queues. */
+
dev->started = 1;
return 0;
@@ -155,6 +158,7 @@ static void
ntb_dev_stop(struct rte_rawdev *dev)
{
/* TODO: stop rx/tx queues. */
+
dev->started = 0;
}
@@ -355,6 +359,9 @@ ntb_init_hw(struct rte_rawdev *dev, struct rte_pci_device *pci_dev)
hw->link_width = NTB_WIDTH_NONE;
switch (pci_dev->id.device_id) {
+ case NTB_INTEL_DEV_ID_B2B_SKX:
+ hw->ntb_ops = &intel_ntb_ops;
+ break;
default:
NTB_LOG(ERR, "Not supported device.");
return -EINVAL;