DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] raw/ntb: add Icelake support for Intel NTB
@ 2020-08-31  4:59 Xiaoyun Li
  2020-09-07  1:46 ` [dpdk-dev] [PATCH v2] " Xiaoyun Li
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Xiaoyun Li @ 2020-08-31  4:59 UTC (permalink / raw)
  To: jingjing.wu; +Cc: dev, omkar.maslekar, Xiaoyun Li

Add NTB device support (4th generation) for Intel Icelake platform.

Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
---
 doc/guides/rawdevs/ntb.rst             |  11 +-
 doc/guides/rel_notes/release_20_11.rst |   3 +
 drivers/raw/ntb/ntb.c                  |   2 +
 drivers/raw/ntb/ntb.h                  |   1 +
 drivers/raw/ntb/ntb_hw_intel.c         | 236 ++++++++++++++++++++++---
 drivers/raw/ntb/ntb_hw_intel.h         |  28 ++-
 usertools/dpdk-devbind.py              |   4 +-
 7 files changed, 246 insertions(+), 39 deletions(-)

diff --git a/doc/guides/rawdevs/ntb.rst b/doc/guides/rawdevs/ntb.rst
index aa7d80964..f3556113c 100644
--- a/doc/guides/rawdevs/ntb.rst
+++ b/doc/guides/rawdevs/ntb.rst
@@ -14,16 +14,17 @@ allocation for the peer to access and read/write allocated memory from peer.
 Also, the PMD allows to use doorbell registers to notify the peer and share
 some information by using scratchpad registers.
 
-BIOS setting on Intel Skylake
------------------------------
+BIOS setting on Intel Xeon
+--------------------------
 
 Intel Non-transparent Bridge needs special BIOS setting. Since the PMD only
 supports Intel Skylake platform, introduce BIOS setting here. The referencce
 is https://www.intel.com/content/dam/support/us/en/documents/server-products/Intel_Xeon_Processor_Scalable_Family_BIOS_User_Guide.pdf
 
 - Set the needed PCIe port as NTB to NTB mode on both hosts.
-- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (2K-512M)
-  on both hosts. Note that bar size on both hosts should be the same.
+- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (4K-512M)
+  on both hosts (for Icelake, bar size can be set as 12-51, namely 4K-128PB).
+  Note that bar size on both hosts should be the same.
 - Disable split bars for both hosts.
 - Set crosslink control override as DSD/USP on one host, USD/DSP on
   another host.
@@ -151,4 +152,4 @@ like the following:
 Limitation
 ----------
 
-- This PMD only supports Intel Skylake platform.
+- This PMD only supports Intel Skylake and Icelake platforms.
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index df227a177..d13782459 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -55,6 +55,9 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added Icelake (Gen4) support for Intel NTB.**
+
+  Added NTB device support (4th generation) for Intel Icelake platform.
 
 Removed Items
 -------------
diff --git a/drivers/raw/ntb/ntb.c b/drivers/raw/ntb/ntb.c
index e40412bb7..3b59f9a44 100644
--- a/drivers/raw/ntb/ntb.c
+++ b/drivers/raw/ntb/ntb.c
@@ -25,6 +25,7 @@
 
 static const struct rte_pci_id pci_id_ntb_map[] = {
 	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_SKX) },
+	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_ICX) },
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -1333,6 +1334,7 @@ ntb_init_hw(struct rte_rawdev *dev, struct rte_pci_device *pci_dev)
 
 	switch (pci_dev->id.device_id) {
 	case NTB_INTEL_DEV_ID_B2B_SKX:
+	case NTB_INTEL_DEV_ID_B2B_ICX:
 		hw->ntb_ops = &intel_ntb_ops;
 		break;
 	default:
diff --git a/drivers/raw/ntb/ntb.h b/drivers/raw/ntb/ntb.h
index a561c42d1..cdf7667d5 100644
--- a/drivers/raw/ntb/ntb.h
+++ b/drivers/raw/ntb/ntb.h
@@ -18,6 +18,7 @@ extern int ntb_logtype;
 
 /* Device IDs */
 #define NTB_INTEL_DEV_ID_B2B_SKX    0x201C
+#define NTB_INTEL_DEV_ID_B2B_ICX    0x347E
 
 /* Reserved to app to use. */
 #define NTB_SPAD_USER               "spad_user_"
diff --git a/drivers/raw/ntb/ntb_hw_intel.c b/drivers/raw/ntb/ntb_hw_intel.c
index e7f8667cd..76670c96b 100644
--- a/drivers/raw/ntb/ntb_hw_intel.c
+++ b/drivers/raw/ntb/ntb_hw_intel.c
@@ -25,17 +25,29 @@ static enum xeon_ntb_bar intel_ntb_bar[] = {
 	XEON_NTB_BAR45,
 };
 
-static int
-intel_ntb_dev_init(const struct rte_rawdev *dev)
+static inline int
+is_gen3_ntb(const struct ntb_hw *hw)
 {
-	struct ntb_hw *hw = dev->dev_private;
-	uint8_t reg_val, bar;
-	int ret, i;
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_SKX)
+		return 1;
 
-	if (hw == NULL) {
-		NTB_LOG(ERR, "Invalid device.");
-		return -EINVAL;
-	}
+	return 0;
+}
+
+static inline int
+is_gen4_ntb(const struct ntb_hw *hw)
+{
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_ICX)
+		return 1;
+
+	return 0;
+}
+
+static int
+intel_ntb3_check_ppd(struct ntb_hw *hw)
+{
+	uint8_t reg_val;
+	int ret;
 
 	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
 				  sizeof(reg_val), XEON_PPD_OFFSET);
@@ -71,8 +83,73 @@ intel_ntb_dev_init(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
+	return 0;
+}
+
+static int
+intel_ntb4_check_ppd(struct ntb_hw *hw)
+{
+	uint32_t reg_val;
+
+	reg_val = rte_read32(hw->hw_addr + XEON_GEN4_PPD1_OFFSET);
+
+	/* Check connection topo type. Only support B2B. */
+	switch (reg_val & XEON_GEN4_PPD_CONN_MASK) {
+	case XEON_GEN4_PPD_CONN_B2B:
+		NTB_LOG(INFO, "Topo B2B (back to back) is using.");
+		break;
+	default:
+		NTB_LOG(ERR, "Not supported conn topo. Please use B2B.");
+		return -EINVAL;
+	}
+
+	/* Check device type. */
+	if (reg_val & XEON_GEN4_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;
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_dev_init(const struct rte_rawdev *dev)
+{
+	struct ntb_hw *hw = dev->dev_private;
+	uint16_t link_ctrl;
+	void *reg_addr;
+	uint8_t bar;
+	int ret, i;
+
+	if (hw == NULL) {
+		NTB_LOG(ERR, "Invalid device.");
+		return -EINVAL;
+	}
+
 	hw->hw_addr = (char *)hw->pci_dev->mem_resource[0].addr;
 
+	if (is_gen3_ntb(hw)) {
+		ret = intel_ntb3_check_ppd(hw);
+	} else if (is_gen4_ntb(hw)) {
+		/* PPD is in MMIO but not config space for NTB Gen4 */
+		ret = intel_ntb4_check_ppd(hw);
+		if (ret)
+			return ret;
+		/* init link setup */
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl |= XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+	} else {
+		return -ENOTSUP;
+	}
+
+	if (ret)
+		return ret;
+
 	hw->mw_cnt = XEON_MW_COUNT;
 	hw->db_cnt = XEON_DB_COUNT;
 	hw->spad_cnt = XEON_SPAD_COUNT;
@@ -149,15 +226,28 @@ intel_ntb_mw_set_trans(const struct rte_rawdev *dev, int mw_idx,
 	rte_write64(base, xlat_addr);
 	rte_write64(limit, limit_addr);
 
-	/* Setup the external point so that remote can access. */
-	xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
-	xlat_addr = hw->hw_addr + xlat_off;
-	limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx * XEON_BAR_INTERVAL_OFFSET;
-	limit_addr = hw->hw_addr + limit_off;
-	base = rte_read64(xlat_addr);
-	base &= ~0xf;
-	limit = base + size;
-	rte_write64(limit, limit_addr);
+	if (is_gen3_ntb(hw)) {
+		/* Setup the external point so that remote can access. */
+		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
+		xlat_addr = hw->hw_addr + xlat_off;
+		limit_off = XEON_EMBAR1XLMT_OFFSET +
+			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
+		limit_addr = hw->hw_addr + limit_off;
+		base = rte_read64(xlat_addr);
+		base &= ~0xf;
+		limit = base + size;
+		rte_write64(limit, limit_addr);
+	} else if (is_gen4_ntb(hw)) {
+		/* Set translate base address index register */
+		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
+			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
+		xlat_addr = hw->hw_addr + xlat_off;
+		rte_write16(rte_log2_u64(size), xlat_addr);
+	} else {
+		rte_write64(base, limit_addr);
+		rte_write64(0, xlat_addr);
+		return -ENOTSUP;
+	}
 
 	return 0;
 }
@@ -187,7 +277,7 @@ static int
 intel_ntb_get_link_status(const struct rte_rawdev *dev)
 {
 	struct ntb_hw *hw = dev->dev_private;
-	uint16_t reg_val;
+	uint16_t reg_val, reg_off;
 	int ret;
 
 	if (hw == NULL) {
@@ -195,11 +285,19 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
-	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
-				  sizeof(reg_val), XEON_LINK_STATUS_OFFSET);
-	if (ret < 0) {
-		NTB_LOG(ERR, "Unable to get link status.");
-		return -EIO;
+	if (is_gen3_ntb(hw)) {
+		reg_off = XEON_GEN3_LINK_STATUS_OFFSET;
+		ret = rte_pci_read_config(hw->pci_dev, &reg_val,
+					  sizeof(reg_val), reg_off);
+		if (ret < 0) {
+			NTB_LOG(ERR, "Unable to get link status.");
+			return -EIO;
+		}
+	} else if (is_gen4_ntb(hw)) {
+		reg_off = XEON_GEN4_LINK_STATUS_OFFSET;
+		reg_val = rte_read16(hw->hw_addr + reg_off);
+	} else {
+		return -ENOTSUP;
 	}
 
 	hw->link_status = NTB_LNK_STA_ACTIVE(reg_val);
@@ -216,9 +314,8 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 }
 
 static int
-intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+intel_ntb_gen3_set_link(const struct ntb_hw *hw, bool up)
 {
-	struct ntb_hw *hw = dev->dev_private;
 	uint32_t ntb_ctrl, reg_off;
 	void *reg_addr;
 
@@ -241,6 +338,65 @@ intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
 	return 0;
 }
 
+static int
+intel_ntb_gen4_set_link(const struct ntb_hw *hw, bool up)
+{
+	uint32_t ntb_ctrl, ppd0;
+	uint16_t link_ctrl;
+	void *reg_addr;
+
+	if (up) {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+		ntb_ctrl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl &= ~XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+
+		/* start link training */
+		reg_addr = hw->hw_addr + XEON_GEN4_PPD0_OFFSET;
+		ppd0 = rte_read32(reg_addr);
+		ppd0 |= XEON_GEN4_PPD_LINKTRN;
+		rte_write32(ppd0, reg_addr);
+
+		/* make sure link training has started */
+		ppd0 = rte_read32(reg_addr);
+		if (!(ppd0 & XEON_GEN4_PPD_LINKTRN)) {
+			NTB_LOG(ERR, "Link is not training.");
+			return -EINVAL;
+		}
+	} else {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = rte_read32(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);
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl |= XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+{
+	struct ntb_hw *hw = dev->dev_private;
+
+	if (is_gen3_ntb(hw))
+		return intel_ntb_gen3_set_link(hw, up);
+	else if (is_gen4_ntb(hw))
+		return intel_ntb_gen4_set_link(hw, up);
+	else
+		return -ENOTSUP;
+}
+
 static uint32_t
 intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 {
@@ -254,7 +410,14 @@ intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 	}
 
 	/* When peer is true, read peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 	spad_v = rte_read32(reg_addr);
 
@@ -275,7 +438,14 @@ intel_ntb_spad_write(const struct rte_rawdev *dev, int spad,
 	}
 
 	/* When peer is true, write peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 
 	rte_write32(spad_v, reg_addr);
@@ -308,6 +478,9 @@ intel_ntb_db_clear(const struct rte_rawdev *dev, uint64_t db_bits)
 	db_off = XEON_IM_INT_STATUS_OFFSET;
 	db_addr = hw->hw_addr + db_off;
 
+	if (is_gen4_ntb(hw))
+		rte_write16(XEON_GEN4_SLOTSTS_DLLSCS,
+			    hw->hw_addr + XEON_GEN4_SLOTSTS);
 	rte_write64(db_bits, db_addr);
 
 	return 0;
@@ -365,7 +538,12 @@ intel_ntb_vector_bind(const struct rte_rawdev *dev, uint8_t intr, uint8_t msix)
 	}
 
 	/* Bind intr source to msix vector */
-	reg_off = XEON_INTVEC_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = XEON_GEN3_INTVEC_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = XEON_GEN4_INTVEC_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + intr;
 
 	rte_write8(msix, reg_addr);
diff --git a/drivers/raw/ntb/ntb_hw_intel.h b/drivers/raw/ntb/ntb_hw_intel.h
index 4d1e64504..604f7aa7a 100644
--- a/drivers/raw/ntb/ntb_hw_intel.h
+++ b/drivers/raw/ntb/ntb_hw_intel.h
@@ -22,7 +22,7 @@
 #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 */
+/* Intel Xeon hardware */
 #define XEON_IMBAR1SZ_OFFSET		0x00d0
 #define XEON_IMBAR2SZ_OFFSET		0x00d1
 #define XEON_EMBAR1SZ_OFFSET		0x00d2
@@ -31,7 +31,13 @@
 #define XEON_DEVSTS_OFFSET		0x009a
 #define XEON_UNCERRSTS_OFFSET		0x014c
 #define XEON_CORERRSTS_OFFSET		0x0158
-#define XEON_LINK_STATUS_OFFSET		0x01a2
+#define XEON_GEN3_LINK_STATUS_OFFSET	0x01a2
+/* Link status and PPD are in MMIO but not config space for Gen4 NTB */
+#define XEON_GEN4_PPD0_OFFSET		0xb0d4
+#define XEON_GEN4_PPD1_OFFSET		0xb4c0
+#define XEON_GEN4_LINK_CTRL_OFFSET	0xb050
+#define XEON_GEN4_LINK_STATUS_OFFSET	0xb052
+#define XEON_GEN4_LINK_CTRL_LINK_DIS	0x0010
 
 #define XEON_NTBCNTL_OFFSET		0x0000
 #define XEON_BAR_INTERVAL_OFFSET	0x0010
@@ -39,13 +45,18 @@
 #define XEON_IMBAR1XLMT_OFFSET		0x0018		/* SBAR2LMT */
 #define XEON_IMBAR2XBASE_OFFSET		0x0020		/* SBAR4XLAT */
 #define XEON_IMBAR2XLMT_OFFSET		0x0028		/* SBAR4LMT */
+#define XEON_GEN4_XBASEIDX_INTERVAL	0x0002
+#define XEON_GEN4_IM1XBASEIDX_OFFSET	0x0074
+#define XEON_GEN4_IM2XBASEIDX_OFFSET	0x0076
 #define XEON_IM_INT_STATUS_OFFSET	0x0040
 #define XEON_IM_INT_DISABLE_OFFSET	0x0048
 #define XEON_IM_SPAD_OFFSET		0x0080		/* SPAD */
+#define XEON_GEN3_B2B_SPAD_OFFSET	0x0180		/* GEN3 B2B SPAD */
+#define XEON_GEN4_B2B_SPAD_OFFSET	0x8080		/* GEN4 B2B SPAD */
 #define XEON_USMEMMISS_OFFSET		0x0070
-#define XEON_INTVEC_OFFSET		0x00d0
+#define XEON_GEN3_INTVEC_OFFSET		0x00d0
+#define XEON_GEN4_INTVEC_OFFSET		0x0050
 #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 */
@@ -60,6 +71,7 @@
 #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
@@ -70,6 +82,14 @@
 #define XEON_PPD_DEV_DSD		0x10
 #define XEON_PPD_SPLIT_BAR_MASK		0x40
 
+#define XEON_GEN4_PPD_CONN_MASK		0x0300
+#define XEON_GEN4_PPD_CONN_B2B		0x0200
+#define XEON_GEN4_PPD_DEV_MASK		0x1000
+#define XEON_GEN4_PPD_DEV_DSD		0x1000
+#define XEON_GEN4_PPD_DEV_USD		0x0000
+#define XEON_GEN4_PPD_LINKTRN		0x0008
+#define XEON_GEN4_SLOTSTS		0xb05a
+#define XEON_GEN4_SLOTSTS_DLLSCS	0x100
 
 #define XEON_MW_COUNT			2
 
diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py
index 86b6b53c4..081c3bc92 100755
--- a/usertools/dpdk-devbind.py
+++ b/usertools/dpdk-devbind.py
@@ -53,6 +53,8 @@
               'SVendor': None, 'SDevice': None}
 intel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c',
               'SVendor': None, 'SDevice': None}
+intel_ntb_icx = {'Class': '06', 'Vendor': '8086', 'Device': '347e',
+              'SVendor': None, 'SDevice': None}
 
 network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
 baseband_devices = [acceleration_class]
@@ -60,7 +62,7 @@
 eventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso]
 mempool_devices = [cavium_fpa, octeontx2_npa]
 compress_devices = [cavium_zip]
-misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, octeontx2_dma]
+misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, intel_ntb_icx, octeontx2_dma]
 
 # global dict ethernet devices present. Dictionary indexed by PCI address.
 # Each device within this is itself a dictionary of device properties
-- 
2.17.1


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

* [dpdk-dev] [PATCH v2] raw/ntb: add Icelake support for Intel NTB
  2020-08-31  4:59 [dpdk-dev] [PATCH] raw/ntb: add Icelake support for Intel NTB Xiaoyun Li
@ 2020-09-07  1:46 ` Xiaoyun Li
  2020-09-07  2:21 ` [dpdk-dev] [PATCH v3] " Xiaoyun Li
  2020-09-08  3:27 ` [dpdk-dev] [PATCH v4] raw/ntb: add Ice Lake " Xiaoyun Li
  2 siblings, 0 replies; 10+ messages in thread
From: Xiaoyun Li @ 2020-09-07  1:46 UTC (permalink / raw)
  To: jingjing.wu; +Cc: dev, omkar.maslekar, Xiaoyun Li

Add NTB device support (4th generation) for Intel Icelake platform.

Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
---
 doc/guides/rawdevs/ntb.rst             |  16 +-
 doc/guides/rel_notes/release_20_11.rst |   3 +
 drivers/raw/ntb/ntb.c                  |   5 +
 drivers/raw/ntb/ntb.h                  |   1 +
 drivers/raw/ntb/ntb_hw_intel.c         | 229 +++++++++++++++++++++----
 drivers/raw/ntb/ntb_hw_intel.h         |  28 ++-
 usertools/dpdk-devbind.py              |   4 +-
 7 files changed, 244 insertions(+), 42 deletions(-)

diff --git a/doc/guides/rawdevs/ntb.rst b/doc/guides/rawdevs/ntb.rst
index aa7d80964..0f04d3e24 100644
--- a/doc/guides/rawdevs/ntb.rst
+++ b/doc/guides/rawdevs/ntb.rst
@@ -14,16 +14,16 @@ allocation for the peer to access and read/write allocated memory from peer.
 Also, the PMD allows to use doorbell registers to notify the peer and share
 some information by using scratchpad registers.
 
-BIOS setting on Intel Skylake
------------------------------
+BIOS setting on Intel Xeon
+--------------------------
 
-Intel Non-transparent Bridge needs special BIOS setting. Since the PMD only
-supports Intel Skylake platform, introduce BIOS setting here. The referencce
-is https://www.intel.com/content/dam/support/us/en/documents/server-products/Intel_Xeon_Processor_Scalable_Family_BIOS_User_Guide.pdf
+Intel Non-transparent Bridge needs special BIOS setting. The referencce for
+Skylake is https://www.intel.com/content/dam/support/us/en/documents/server-products/Intel_Xeon_Processor_Scalable_Family_BIOS_User_Guide.pdf
 
 - Set the needed PCIe port as NTB to NTB mode on both hosts.
-- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (2K-512M)
-  on both hosts. Note that bar size on both hosts should be the same.
+- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (4K-512M)
+  on both hosts (for Icelake, bar size can be set as 12-51, namely 4K-128PB).
+  Note that bar size on both hosts should be the same.
 - Disable split bars for both hosts.
 - Set crosslink control override as DSD/USP on one host, USD/DSP on
   another host.
@@ -151,4 +151,4 @@ like the following:
 Limitation
 ----------
 
-- This PMD only supports Intel Skylake platform.
+- This PMD only supports Intel Skylake and Icelake platforms.
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index df227a177..d13782459 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -55,6 +55,9 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added Icelake (Gen4) support for Intel NTB.**
+
+  Added NTB device support (4th generation) for Intel Icelake platform.
 
 Removed Items
 -------------
diff --git a/drivers/raw/ntb/ntb.c b/drivers/raw/ntb/ntb.c
index e40412bb7..e29acecef 100644
--- a/drivers/raw/ntb/ntb.c
+++ b/drivers/raw/ntb/ntb.c
@@ -25,6 +25,7 @@
 
 static const struct rte_pci_id pci_id_ntb_map[] = {
 	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_SKX) },
+	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_ICX) },
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -244,6 +245,9 @@ ntb_dev_intr_handler(void *param)
 		hw->peer_dev_up = 0;
 		return;
 	}
+
+	/* Clear other received doorbells. */
+	(*hw->ntb_ops->db_clear)(dev, db_bits);
 }
 
 static void
@@ -1333,6 +1337,7 @@ ntb_init_hw(struct rte_rawdev *dev, struct rte_pci_device *pci_dev)
 
 	switch (pci_dev->id.device_id) {
 	case NTB_INTEL_DEV_ID_B2B_SKX:
+	case NTB_INTEL_DEV_ID_B2B_ICX:
 		hw->ntb_ops = &intel_ntb_ops;
 		break;
 	default:
diff --git a/drivers/raw/ntb/ntb.h b/drivers/raw/ntb/ntb.h
index a561c42d1..cdf7667d5 100644
--- a/drivers/raw/ntb/ntb.h
+++ b/drivers/raw/ntb/ntb.h
@@ -18,6 +18,7 @@ extern int ntb_logtype;
 
 /* Device IDs */
 #define NTB_INTEL_DEV_ID_B2B_SKX    0x201C
+#define NTB_INTEL_DEV_ID_B2B_ICX    0x347E
 
 /* Reserved to app to use. */
 #define NTB_SPAD_USER               "spad_user_"
diff --git a/drivers/raw/ntb/ntb_hw_intel.c b/drivers/raw/ntb/ntb_hw_intel.c
index e7f8667cd..cadceef51 100644
--- a/drivers/raw/ntb/ntb_hw_intel.c
+++ b/drivers/raw/ntb/ntb_hw_intel.c
@@ -25,17 +25,29 @@ static enum xeon_ntb_bar intel_ntb_bar[] = {
 	XEON_NTB_BAR45,
 };
 
-static int
-intel_ntb_dev_init(const struct rte_rawdev *dev)
+static inline int
+is_gen3_ntb(const struct ntb_hw *hw)
 {
-	struct ntb_hw *hw = dev->dev_private;
-	uint8_t reg_val, bar;
-	int ret, i;
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_SKX)
+		return 1;
 
-	if (hw == NULL) {
-		NTB_LOG(ERR, "Invalid device.");
-		return -EINVAL;
-	}
+	return 0;
+}
+
+static inline int
+is_gen4_ntb(const struct ntb_hw *hw)
+{
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_ICX)
+		return 1;
+
+	return 0;
+}
+
+static int
+intel_ntb3_check_ppd(struct ntb_hw *hw)
+{
+	uint8_t reg_val;
+	int ret;
 
 	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
 				  sizeof(reg_val), XEON_PPD_OFFSET);
@@ -71,8 +83,66 @@ intel_ntb_dev_init(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
+	return 0;
+}
+
+static int
+intel_ntb4_check_ppd(struct ntb_hw *hw)
+{
+	uint32_t reg_val;
+
+	reg_val = rte_read32(hw->hw_addr + XEON_GEN4_PPD1_OFFSET);
+
+	/* Check connection topo type. Only support B2B. */
+	switch (reg_val & XEON_GEN4_PPD_CONN_MASK) {
+	case XEON_GEN4_PPD_CONN_B2B:
+		NTB_LOG(INFO, "Topo B2B (back to back) is using.");
+		break;
+	default:
+		NTB_LOG(ERR, "Not supported conn topo. Please use B2B.");
+		return -EINVAL;
+	}
+
+	/* Check device type. */
+	if (reg_val & XEON_GEN4_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;
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_dev_init(const struct rte_rawdev *dev)
+{
+	struct ntb_hw *hw = dev->dev_private;
+	uint8_t bar;
+	int ret, i;
+
+	if (hw == NULL) {
+		NTB_LOG(ERR, "Invalid device.");
+		return -EINVAL;
+	}
+
 	hw->hw_addr = (char *)hw->pci_dev->mem_resource[0].addr;
 
+	if (is_gen3_ntb(hw)) {
+		ret = intel_ntb3_check_ppd(hw);
+	} else if (is_gen4_ntb(hw)) {
+		/* PPD is in MMIO but not config space for NTB Gen4 */
+		ret = intel_ntb4_check_ppd(hw);
+		if (ret)
+			return ret;
+	} else {
+		return -ENOTSUP;
+	}
+
+	if (ret)
+		return ret;
+
 	hw->mw_cnt = XEON_MW_COUNT;
 	hw->db_cnt = XEON_DB_COUNT;
 	hw->spad_cnt = XEON_SPAD_COUNT;
@@ -149,15 +219,28 @@ intel_ntb_mw_set_trans(const struct rte_rawdev *dev, int mw_idx,
 	rte_write64(base, xlat_addr);
 	rte_write64(limit, limit_addr);
 
-	/* Setup the external point so that remote can access. */
-	xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
-	xlat_addr = hw->hw_addr + xlat_off;
-	limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx * XEON_BAR_INTERVAL_OFFSET;
-	limit_addr = hw->hw_addr + limit_off;
-	base = rte_read64(xlat_addr);
-	base &= ~0xf;
-	limit = base + size;
-	rte_write64(limit, limit_addr);
+	if (is_gen3_ntb(hw)) {
+		/* Setup the external point so that remote can access. */
+		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
+		xlat_addr = hw->hw_addr + xlat_off;
+		limit_off = XEON_EMBAR1XLMT_OFFSET +
+			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
+		limit_addr = hw->hw_addr + limit_off;
+		base = rte_read64(xlat_addr);
+		base &= ~0xf;
+		limit = base + size;
+		rte_write64(limit, limit_addr);
+	} else if (is_gen4_ntb(hw)) {
+		/* Set translate base address index register */
+		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
+			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
+		xlat_addr = hw->hw_addr + xlat_off;
+		rte_write16(rte_log2_u64(size), xlat_addr);
+	} else {
+		rte_write64(base, limit_addr);
+		rte_write64(0, xlat_addr);
+		return -ENOTSUP;
+	}
 
 	return 0;
 }
@@ -187,7 +270,7 @@ static int
 intel_ntb_get_link_status(const struct rte_rawdev *dev)
 {
 	struct ntb_hw *hw = dev->dev_private;
-	uint16_t reg_val;
+	uint16_t reg_val, reg_off;
 	int ret;
 
 	if (hw == NULL) {
@@ -195,11 +278,19 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
-	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
-				  sizeof(reg_val), XEON_LINK_STATUS_OFFSET);
-	if (ret < 0) {
-		NTB_LOG(ERR, "Unable to get link status.");
-		return -EIO;
+	if (is_gen3_ntb(hw)) {
+		reg_off = XEON_GEN3_LINK_STATUS_OFFSET;
+		ret = rte_pci_read_config(hw->pci_dev, &reg_val,
+					  sizeof(reg_val), reg_off);
+		if (ret < 0) {
+			NTB_LOG(ERR, "Unable to get link status.");
+			return -EIO;
+		}
+	} else if (is_gen4_ntb(hw)) {
+		reg_off = XEON_GEN4_LINK_STATUS_OFFSET;
+		reg_val = rte_read16(hw->hw_addr + reg_off);
+	} else {
+		return -ENOTSUP;
 	}
 
 	hw->link_status = NTB_LNK_STA_ACTIVE(reg_val);
@@ -216,9 +307,8 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 }
 
 static int
-intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+intel_ntb_gen3_set_link(const struct ntb_hw *hw, bool up)
 {
-	struct ntb_hw *hw = dev->dev_private;
 	uint32_t ntb_ctrl, reg_off;
 	void *reg_addr;
 
@@ -241,6 +331,65 @@ intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
 	return 0;
 }
 
+static int
+intel_ntb_gen4_set_link(const struct ntb_hw *hw, bool up)
+{
+	uint32_t ntb_ctrl, ppd0;
+	uint16_t link_ctrl;
+	void *reg_addr;
+
+	if (up) {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+		ntb_ctrl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl &= ~XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+
+		/* start link training */
+		reg_addr = hw->hw_addr + XEON_GEN4_PPD0_OFFSET;
+		ppd0 = rte_read32(reg_addr);
+		ppd0 |= XEON_GEN4_PPD_LINKTRN;
+		rte_write32(ppd0, reg_addr);
+
+		/* make sure link training has started */
+		ppd0 = rte_read32(reg_addr);
+		if (!(ppd0 & XEON_GEN4_PPD_LINKTRN)) {
+			NTB_LOG(ERR, "Link is not training.");
+			return -EINVAL;
+		}
+	} else {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = rte_read32(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);
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl |= XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+{
+	struct ntb_hw *hw = dev->dev_private;
+
+	if (is_gen3_ntb(hw))
+		return intel_ntb_gen3_set_link(hw, up);
+	else if (is_gen4_ntb(hw))
+		return intel_ntb_gen4_set_link(hw, up);
+	else
+		return -ENOTSUP;
+}
+
 static uint32_t
 intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 {
@@ -254,7 +403,14 @@ intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 	}
 
 	/* When peer is true, read peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 	spad_v = rte_read32(reg_addr);
 
@@ -275,7 +431,14 @@ intel_ntb_spad_write(const struct rte_rawdev *dev, int spad,
 	}
 
 	/* When peer is true, write peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 
 	rte_write32(spad_v, reg_addr);
@@ -308,6 +471,9 @@ intel_ntb_db_clear(const struct rte_rawdev *dev, uint64_t db_bits)
 	db_off = XEON_IM_INT_STATUS_OFFSET;
 	db_addr = hw->hw_addr + db_off;
 
+	if (is_gen4_ntb(hw))
+		rte_write16(XEON_GEN4_SLOTSTS_DLLSCS,
+			    hw->hw_addr + XEON_GEN4_SLOTSTS);
 	rte_write64(db_bits, db_addr);
 
 	return 0;
@@ -365,7 +531,12 @@ intel_ntb_vector_bind(const struct rte_rawdev *dev, uint8_t intr, uint8_t msix)
 	}
 
 	/* Bind intr source to msix vector */
-	reg_off = XEON_INTVEC_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = XEON_GEN3_INTVEC_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = XEON_GEN4_INTVEC_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + intr;
 
 	rte_write8(msix, reg_addr);
diff --git a/drivers/raw/ntb/ntb_hw_intel.h b/drivers/raw/ntb/ntb_hw_intel.h
index 4d1e64504..604f7aa7a 100644
--- a/drivers/raw/ntb/ntb_hw_intel.h
+++ b/drivers/raw/ntb/ntb_hw_intel.h
@@ -22,7 +22,7 @@
 #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 */
+/* Intel Xeon hardware */
 #define XEON_IMBAR1SZ_OFFSET		0x00d0
 #define XEON_IMBAR2SZ_OFFSET		0x00d1
 #define XEON_EMBAR1SZ_OFFSET		0x00d2
@@ -31,7 +31,13 @@
 #define XEON_DEVSTS_OFFSET		0x009a
 #define XEON_UNCERRSTS_OFFSET		0x014c
 #define XEON_CORERRSTS_OFFSET		0x0158
-#define XEON_LINK_STATUS_OFFSET		0x01a2
+#define XEON_GEN3_LINK_STATUS_OFFSET	0x01a2
+/* Link status and PPD are in MMIO but not config space for Gen4 NTB */
+#define XEON_GEN4_PPD0_OFFSET		0xb0d4
+#define XEON_GEN4_PPD1_OFFSET		0xb4c0
+#define XEON_GEN4_LINK_CTRL_OFFSET	0xb050
+#define XEON_GEN4_LINK_STATUS_OFFSET	0xb052
+#define XEON_GEN4_LINK_CTRL_LINK_DIS	0x0010
 
 #define XEON_NTBCNTL_OFFSET		0x0000
 #define XEON_BAR_INTERVAL_OFFSET	0x0010
@@ -39,13 +45,18 @@
 #define XEON_IMBAR1XLMT_OFFSET		0x0018		/* SBAR2LMT */
 #define XEON_IMBAR2XBASE_OFFSET		0x0020		/* SBAR4XLAT */
 #define XEON_IMBAR2XLMT_OFFSET		0x0028		/* SBAR4LMT */
+#define XEON_GEN4_XBASEIDX_INTERVAL	0x0002
+#define XEON_GEN4_IM1XBASEIDX_OFFSET	0x0074
+#define XEON_GEN4_IM2XBASEIDX_OFFSET	0x0076
 #define XEON_IM_INT_STATUS_OFFSET	0x0040
 #define XEON_IM_INT_DISABLE_OFFSET	0x0048
 #define XEON_IM_SPAD_OFFSET		0x0080		/* SPAD */
+#define XEON_GEN3_B2B_SPAD_OFFSET	0x0180		/* GEN3 B2B SPAD */
+#define XEON_GEN4_B2B_SPAD_OFFSET	0x8080		/* GEN4 B2B SPAD */
 #define XEON_USMEMMISS_OFFSET		0x0070
-#define XEON_INTVEC_OFFSET		0x00d0
+#define XEON_GEN3_INTVEC_OFFSET		0x00d0
+#define XEON_GEN4_INTVEC_OFFSET		0x0050
 #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 */
@@ -60,6 +71,7 @@
 #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
@@ -70,6 +82,14 @@
 #define XEON_PPD_DEV_DSD		0x10
 #define XEON_PPD_SPLIT_BAR_MASK		0x40
 
+#define XEON_GEN4_PPD_CONN_MASK		0x0300
+#define XEON_GEN4_PPD_CONN_B2B		0x0200
+#define XEON_GEN4_PPD_DEV_MASK		0x1000
+#define XEON_GEN4_PPD_DEV_DSD		0x1000
+#define XEON_GEN4_PPD_DEV_USD		0x0000
+#define XEON_GEN4_PPD_LINKTRN		0x0008
+#define XEON_GEN4_SLOTSTS		0xb05a
+#define XEON_GEN4_SLOTSTS_DLLSCS	0x100
 
 #define XEON_MW_COUNT			2
 
diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py
index 86b6b53c4..081c3bc92 100755
--- a/usertools/dpdk-devbind.py
+++ b/usertools/dpdk-devbind.py
@@ -53,6 +53,8 @@
               'SVendor': None, 'SDevice': None}
 intel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c',
               'SVendor': None, 'SDevice': None}
+intel_ntb_icx = {'Class': '06', 'Vendor': '8086', 'Device': '347e',
+              'SVendor': None, 'SDevice': None}
 
 network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
 baseband_devices = [acceleration_class]
@@ -60,7 +62,7 @@
 eventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso]
 mempool_devices = [cavium_fpa, octeontx2_npa]
 compress_devices = [cavium_zip]
-misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, octeontx2_dma]
+misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, intel_ntb_icx, octeontx2_dma]
 
 # global dict ethernet devices present. Dictionary indexed by PCI address.
 # Each device within this is itself a dictionary of device properties
-- 
2.17.1


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

* [dpdk-dev] [PATCH v3] raw/ntb: add Icelake support for Intel NTB
  2020-08-31  4:59 [dpdk-dev] [PATCH] raw/ntb: add Icelake support for Intel NTB Xiaoyun Li
  2020-09-07  1:46 ` [dpdk-dev] [PATCH v2] " Xiaoyun Li
@ 2020-09-07  2:21 ` Xiaoyun Li
  2020-09-07  8:34   ` Wu, Jingjing
  2020-09-08  3:27 ` [dpdk-dev] [PATCH v4] raw/ntb: add Ice Lake " Xiaoyun Li
  2 siblings, 1 reply; 10+ messages in thread
From: Xiaoyun Li @ 2020-09-07  2:21 UTC (permalink / raw)
  To: jingjing.wu; +Cc: dev, omkar.maslekar, Xiaoyun Li

Add NTB device support (4th generation) for Intel Icelake platform.

Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
---
v3:
 * Removed a blank line.
 * Added change doc for v2.
v2:
 * Corrected and polished the doc.
 * Fixed a link setup issue.
---
 doc/guides/rawdevs/ntb.rst             |  16 +-
 doc/guides/rel_notes/release_20_11.rst |   3 +
 drivers/raw/ntb/ntb.c                  |   5 +
 drivers/raw/ntb/ntb.h                  |   1 +
 drivers/raw/ntb/ntb_hw_intel.c         | 229 +++++++++++++++++++++----
 drivers/raw/ntb/ntb_hw_intel.h         |  27 ++-
 usertools/dpdk-devbind.py              |   4 +-
 7 files changed, 243 insertions(+), 42 deletions(-)

diff --git a/doc/guides/rawdevs/ntb.rst b/doc/guides/rawdevs/ntb.rst
index aa7d80964..0f04d3e24 100644
--- a/doc/guides/rawdevs/ntb.rst
+++ b/doc/guides/rawdevs/ntb.rst
@@ -14,16 +14,16 @@ allocation for the peer to access and read/write allocated memory from peer.
 Also, the PMD allows to use doorbell registers to notify the peer and share
 some information by using scratchpad registers.
 
-BIOS setting on Intel Skylake
------------------------------
+BIOS setting on Intel Xeon
+--------------------------
 
-Intel Non-transparent Bridge needs special BIOS setting. Since the PMD only
-supports Intel Skylake platform, introduce BIOS setting here. The referencce
-is https://www.intel.com/content/dam/support/us/en/documents/server-products/Intel_Xeon_Processor_Scalable_Family_BIOS_User_Guide.pdf
+Intel Non-transparent Bridge needs special BIOS setting. The referencce for
+Skylake is https://www.intel.com/content/dam/support/us/en/documents/server-products/Intel_Xeon_Processor_Scalable_Family_BIOS_User_Guide.pdf
 
 - Set the needed PCIe port as NTB to NTB mode on both hosts.
-- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (2K-512M)
-  on both hosts. Note that bar size on both hosts should be the same.
+- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (4K-512M)
+  on both hosts (for Icelake, bar size can be set as 12-51, namely 4K-128PB).
+  Note that bar size on both hosts should be the same.
 - Disable split bars for both hosts.
 - Set crosslink control override as DSD/USP on one host, USD/DSP on
   another host.
@@ -151,4 +151,4 @@ like the following:
 Limitation
 ----------
 
-- This PMD only supports Intel Skylake platform.
+- This PMD only supports Intel Skylake and Icelake platforms.
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index df227a177..d13782459 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -55,6 +55,9 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added Icelake (Gen4) support for Intel NTB.**
+
+  Added NTB device support (4th generation) for Intel Icelake platform.
 
 Removed Items
 -------------
diff --git a/drivers/raw/ntb/ntb.c b/drivers/raw/ntb/ntb.c
index e40412bb7..e29acecef 100644
--- a/drivers/raw/ntb/ntb.c
+++ b/drivers/raw/ntb/ntb.c
@@ -25,6 +25,7 @@
 
 static const struct rte_pci_id pci_id_ntb_map[] = {
 	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_SKX) },
+	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_ICX) },
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -244,6 +245,9 @@ ntb_dev_intr_handler(void *param)
 		hw->peer_dev_up = 0;
 		return;
 	}
+
+	/* Clear other received doorbells. */
+	(*hw->ntb_ops->db_clear)(dev, db_bits);
 }
 
 static void
@@ -1333,6 +1337,7 @@ ntb_init_hw(struct rte_rawdev *dev, struct rte_pci_device *pci_dev)
 
 	switch (pci_dev->id.device_id) {
 	case NTB_INTEL_DEV_ID_B2B_SKX:
+	case NTB_INTEL_DEV_ID_B2B_ICX:
 		hw->ntb_ops = &intel_ntb_ops;
 		break;
 	default:
diff --git a/drivers/raw/ntb/ntb.h b/drivers/raw/ntb/ntb.h
index a561c42d1..cdf7667d5 100644
--- a/drivers/raw/ntb/ntb.h
+++ b/drivers/raw/ntb/ntb.h
@@ -18,6 +18,7 @@ extern int ntb_logtype;
 
 /* Device IDs */
 #define NTB_INTEL_DEV_ID_B2B_SKX    0x201C
+#define NTB_INTEL_DEV_ID_B2B_ICX    0x347E
 
 /* Reserved to app to use. */
 #define NTB_SPAD_USER               "spad_user_"
diff --git a/drivers/raw/ntb/ntb_hw_intel.c b/drivers/raw/ntb/ntb_hw_intel.c
index e7f8667cd..cadceef51 100644
--- a/drivers/raw/ntb/ntb_hw_intel.c
+++ b/drivers/raw/ntb/ntb_hw_intel.c
@@ -25,17 +25,29 @@ static enum xeon_ntb_bar intel_ntb_bar[] = {
 	XEON_NTB_BAR45,
 };
 
-static int
-intel_ntb_dev_init(const struct rte_rawdev *dev)
+static inline int
+is_gen3_ntb(const struct ntb_hw *hw)
 {
-	struct ntb_hw *hw = dev->dev_private;
-	uint8_t reg_val, bar;
-	int ret, i;
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_SKX)
+		return 1;
 
-	if (hw == NULL) {
-		NTB_LOG(ERR, "Invalid device.");
-		return -EINVAL;
-	}
+	return 0;
+}
+
+static inline int
+is_gen4_ntb(const struct ntb_hw *hw)
+{
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_ICX)
+		return 1;
+
+	return 0;
+}
+
+static int
+intel_ntb3_check_ppd(struct ntb_hw *hw)
+{
+	uint8_t reg_val;
+	int ret;
 
 	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
 				  sizeof(reg_val), XEON_PPD_OFFSET);
@@ -71,8 +83,66 @@ intel_ntb_dev_init(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
+	return 0;
+}
+
+static int
+intel_ntb4_check_ppd(struct ntb_hw *hw)
+{
+	uint32_t reg_val;
+
+	reg_val = rte_read32(hw->hw_addr + XEON_GEN4_PPD1_OFFSET);
+
+	/* Check connection topo type. Only support B2B. */
+	switch (reg_val & XEON_GEN4_PPD_CONN_MASK) {
+	case XEON_GEN4_PPD_CONN_B2B:
+		NTB_LOG(INFO, "Topo B2B (back to back) is using.");
+		break;
+	default:
+		NTB_LOG(ERR, "Not supported conn topo. Please use B2B.");
+		return -EINVAL;
+	}
+
+	/* Check device type. */
+	if (reg_val & XEON_GEN4_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;
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_dev_init(const struct rte_rawdev *dev)
+{
+	struct ntb_hw *hw = dev->dev_private;
+	uint8_t bar;
+	int ret, i;
+
+	if (hw == NULL) {
+		NTB_LOG(ERR, "Invalid device.");
+		return -EINVAL;
+	}
+
 	hw->hw_addr = (char *)hw->pci_dev->mem_resource[0].addr;
 
+	if (is_gen3_ntb(hw)) {
+		ret = intel_ntb3_check_ppd(hw);
+	} else if (is_gen4_ntb(hw)) {
+		/* PPD is in MMIO but not config space for NTB Gen4 */
+		ret = intel_ntb4_check_ppd(hw);
+		if (ret)
+			return ret;
+	} else {
+		return -ENOTSUP;
+	}
+
+	if (ret)
+		return ret;
+
 	hw->mw_cnt = XEON_MW_COUNT;
 	hw->db_cnt = XEON_DB_COUNT;
 	hw->spad_cnt = XEON_SPAD_COUNT;
@@ -149,15 +219,28 @@ intel_ntb_mw_set_trans(const struct rte_rawdev *dev, int mw_idx,
 	rte_write64(base, xlat_addr);
 	rte_write64(limit, limit_addr);
 
-	/* Setup the external point so that remote can access. */
-	xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
-	xlat_addr = hw->hw_addr + xlat_off;
-	limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx * XEON_BAR_INTERVAL_OFFSET;
-	limit_addr = hw->hw_addr + limit_off;
-	base = rte_read64(xlat_addr);
-	base &= ~0xf;
-	limit = base + size;
-	rte_write64(limit, limit_addr);
+	if (is_gen3_ntb(hw)) {
+		/* Setup the external point so that remote can access. */
+		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
+		xlat_addr = hw->hw_addr + xlat_off;
+		limit_off = XEON_EMBAR1XLMT_OFFSET +
+			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
+		limit_addr = hw->hw_addr + limit_off;
+		base = rte_read64(xlat_addr);
+		base &= ~0xf;
+		limit = base + size;
+		rte_write64(limit, limit_addr);
+	} else if (is_gen4_ntb(hw)) {
+		/* Set translate base address index register */
+		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
+			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
+		xlat_addr = hw->hw_addr + xlat_off;
+		rte_write16(rte_log2_u64(size), xlat_addr);
+	} else {
+		rte_write64(base, limit_addr);
+		rte_write64(0, xlat_addr);
+		return -ENOTSUP;
+	}
 
 	return 0;
 }
@@ -187,7 +270,7 @@ static int
 intel_ntb_get_link_status(const struct rte_rawdev *dev)
 {
 	struct ntb_hw *hw = dev->dev_private;
-	uint16_t reg_val;
+	uint16_t reg_val, reg_off;
 	int ret;
 
 	if (hw == NULL) {
@@ -195,11 +278,19 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
-	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
-				  sizeof(reg_val), XEON_LINK_STATUS_OFFSET);
-	if (ret < 0) {
-		NTB_LOG(ERR, "Unable to get link status.");
-		return -EIO;
+	if (is_gen3_ntb(hw)) {
+		reg_off = XEON_GEN3_LINK_STATUS_OFFSET;
+		ret = rte_pci_read_config(hw->pci_dev, &reg_val,
+					  sizeof(reg_val), reg_off);
+		if (ret < 0) {
+			NTB_LOG(ERR, "Unable to get link status.");
+			return -EIO;
+		}
+	} else if (is_gen4_ntb(hw)) {
+		reg_off = XEON_GEN4_LINK_STATUS_OFFSET;
+		reg_val = rte_read16(hw->hw_addr + reg_off);
+	} else {
+		return -ENOTSUP;
 	}
 
 	hw->link_status = NTB_LNK_STA_ACTIVE(reg_val);
@@ -216,9 +307,8 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 }
 
 static int
-intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+intel_ntb_gen3_set_link(const struct ntb_hw *hw, bool up)
 {
-	struct ntb_hw *hw = dev->dev_private;
 	uint32_t ntb_ctrl, reg_off;
 	void *reg_addr;
 
@@ -241,6 +331,65 @@ intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
 	return 0;
 }
 
+static int
+intel_ntb_gen4_set_link(const struct ntb_hw *hw, bool up)
+{
+	uint32_t ntb_ctrl, ppd0;
+	uint16_t link_ctrl;
+	void *reg_addr;
+
+	if (up) {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+		ntb_ctrl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl &= ~XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+
+		/* start link training */
+		reg_addr = hw->hw_addr + XEON_GEN4_PPD0_OFFSET;
+		ppd0 = rte_read32(reg_addr);
+		ppd0 |= XEON_GEN4_PPD_LINKTRN;
+		rte_write32(ppd0, reg_addr);
+
+		/* make sure link training has started */
+		ppd0 = rte_read32(reg_addr);
+		if (!(ppd0 & XEON_GEN4_PPD_LINKTRN)) {
+			NTB_LOG(ERR, "Link is not training.");
+			return -EINVAL;
+		}
+	} else {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = rte_read32(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);
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl |= XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+{
+	struct ntb_hw *hw = dev->dev_private;
+
+	if (is_gen3_ntb(hw))
+		return intel_ntb_gen3_set_link(hw, up);
+	else if (is_gen4_ntb(hw))
+		return intel_ntb_gen4_set_link(hw, up);
+	else
+		return -ENOTSUP;
+}
+
 static uint32_t
 intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 {
@@ -254,7 +403,14 @@ intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 	}
 
 	/* When peer is true, read peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 	spad_v = rte_read32(reg_addr);
 
@@ -275,7 +431,14 @@ intel_ntb_spad_write(const struct rte_rawdev *dev, int spad,
 	}
 
 	/* When peer is true, write peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 
 	rte_write32(spad_v, reg_addr);
@@ -308,6 +471,9 @@ intel_ntb_db_clear(const struct rte_rawdev *dev, uint64_t db_bits)
 	db_off = XEON_IM_INT_STATUS_OFFSET;
 	db_addr = hw->hw_addr + db_off;
 
+	if (is_gen4_ntb(hw))
+		rte_write16(XEON_GEN4_SLOTSTS_DLLSCS,
+			    hw->hw_addr + XEON_GEN4_SLOTSTS);
 	rte_write64(db_bits, db_addr);
 
 	return 0;
@@ -365,7 +531,12 @@ intel_ntb_vector_bind(const struct rte_rawdev *dev, uint8_t intr, uint8_t msix)
 	}
 
 	/* Bind intr source to msix vector */
-	reg_off = XEON_INTVEC_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = XEON_GEN3_INTVEC_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = XEON_GEN4_INTVEC_OFFSET;
+	else
+		return -ENOTSUP;
 	reg_addr = hw->hw_addr + reg_off + intr;
 
 	rte_write8(msix, reg_addr);
diff --git a/drivers/raw/ntb/ntb_hw_intel.h b/drivers/raw/ntb/ntb_hw_intel.h
index 4d1e64504..c61a2a8a6 100644
--- a/drivers/raw/ntb/ntb_hw_intel.h
+++ b/drivers/raw/ntb/ntb_hw_intel.h
@@ -22,7 +22,7 @@
 #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 */
+/* Intel Xeon hardware */
 #define XEON_IMBAR1SZ_OFFSET		0x00d0
 #define XEON_IMBAR2SZ_OFFSET		0x00d1
 #define XEON_EMBAR1SZ_OFFSET		0x00d2
@@ -31,7 +31,13 @@
 #define XEON_DEVSTS_OFFSET		0x009a
 #define XEON_UNCERRSTS_OFFSET		0x014c
 #define XEON_CORERRSTS_OFFSET		0x0158
-#define XEON_LINK_STATUS_OFFSET		0x01a2
+#define XEON_GEN3_LINK_STATUS_OFFSET	0x01a2
+/* Link status and PPD are in MMIO but not config space for Gen4 NTB */
+#define XEON_GEN4_PPD0_OFFSET		0xb0d4
+#define XEON_GEN4_PPD1_OFFSET		0xb4c0
+#define XEON_GEN4_LINK_CTRL_OFFSET	0xb050
+#define XEON_GEN4_LINK_STATUS_OFFSET	0xb052
+#define XEON_GEN4_LINK_CTRL_LINK_DIS	0x0010
 
 #define XEON_NTBCNTL_OFFSET		0x0000
 #define XEON_BAR_INTERVAL_OFFSET	0x0010
@@ -39,13 +45,18 @@
 #define XEON_IMBAR1XLMT_OFFSET		0x0018		/* SBAR2LMT */
 #define XEON_IMBAR2XBASE_OFFSET		0x0020		/* SBAR4XLAT */
 #define XEON_IMBAR2XLMT_OFFSET		0x0028		/* SBAR4LMT */
+#define XEON_GEN4_XBASEIDX_INTERVAL	0x0002
+#define XEON_GEN4_IM1XBASEIDX_OFFSET	0x0074
+#define XEON_GEN4_IM2XBASEIDX_OFFSET	0x0076
 #define XEON_IM_INT_STATUS_OFFSET	0x0040
 #define XEON_IM_INT_DISABLE_OFFSET	0x0048
 #define XEON_IM_SPAD_OFFSET		0x0080		/* SPAD */
+#define XEON_GEN3_B2B_SPAD_OFFSET	0x0180		/* GEN3 B2B SPAD */
+#define XEON_GEN4_B2B_SPAD_OFFSET	0x8080		/* GEN4 B2B SPAD */
 #define XEON_USMEMMISS_OFFSET		0x0070
-#define XEON_INTVEC_OFFSET		0x00d0
+#define XEON_GEN3_INTVEC_OFFSET		0x00d0
+#define XEON_GEN4_INTVEC_OFFSET		0x0050
 #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 */
@@ -70,6 +81,14 @@
 #define XEON_PPD_DEV_DSD		0x10
 #define XEON_PPD_SPLIT_BAR_MASK		0x40
 
+#define XEON_GEN4_PPD_CONN_MASK		0x0300
+#define XEON_GEN4_PPD_CONN_B2B		0x0200
+#define XEON_GEN4_PPD_DEV_MASK		0x1000
+#define XEON_GEN4_PPD_DEV_DSD		0x1000
+#define XEON_GEN4_PPD_DEV_USD		0x0000
+#define XEON_GEN4_PPD_LINKTRN		0x0008
+#define XEON_GEN4_SLOTSTS		0xb05a
+#define XEON_GEN4_SLOTSTS_DLLSCS	0x100
 
 #define XEON_MW_COUNT			2
 
diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py
index 86b6b53c4..081c3bc92 100755
--- a/usertools/dpdk-devbind.py
+++ b/usertools/dpdk-devbind.py
@@ -53,6 +53,8 @@
               'SVendor': None, 'SDevice': None}
 intel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c',
               'SVendor': None, 'SDevice': None}
+intel_ntb_icx = {'Class': '06', 'Vendor': '8086', 'Device': '347e',
+              'SVendor': None, 'SDevice': None}
 
 network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
 baseband_devices = [acceleration_class]
@@ -60,7 +62,7 @@
 eventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso]
 mempool_devices = [cavium_fpa, octeontx2_npa]
 compress_devices = [cavium_zip]
-misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, octeontx2_dma]
+misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, intel_ntb_icx, octeontx2_dma]
 
 # global dict ethernet devices present. Dictionary indexed by PCI address.
 # Each device within this is itself a dictionary of device properties
-- 
2.17.1


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

* Re: [dpdk-dev] [PATCH v3] raw/ntb: add Icelake support for Intel NTB
  2020-09-07  2:21 ` [dpdk-dev] [PATCH v3] " Xiaoyun Li
@ 2020-09-07  8:34   ` Wu, Jingjing
  2020-09-07  9:18     ` Li, Xiaoyun
  0 siblings, 1 reply; 10+ messages in thread
From: Wu, Jingjing @ 2020-09-07  8:34 UTC (permalink / raw)
  To: Li, Xiaoyun; +Cc: dev, Maslekar, Omkar

> +
> +static int
> +intel_ntb_dev_init(const struct rte_rawdev *dev) {
> +	struct ntb_hw *hw = dev->dev_private;
> +	uint8_t bar;
> +	int ret, i;
> +
> +	if (hw == NULL) {
> +		NTB_LOG(ERR, "Invalid device.");
> +		return -EINVAL;
> +	}
> +
>  	hw->hw_addr = (char *)hw->pci_dev->mem_resource[0].addr;
> 
> +	if (is_gen3_ntb(hw)) {
> +		ret = intel_ntb3_check_ppd(hw);
> +	} else if (is_gen4_ntb(hw)) {
> +		/* PPD is in MMIO but not config space for NTB Gen4 */
> +		ret = intel_ntb4_check_ppd(hw);
> +		if (ret)
> +			return ret;
Above two lines are not necessary.
> +	} else {
> +		return -ENOTSUP;
> +	}
> +
> +	if (ret)
> +		return ret;
> +
>  	hw->mw_cnt = XEON_MW_COUNT;
>  	hw->db_cnt = XEON_DB_COUNT;
>  	hw->spad_cnt = XEON_SPAD_COUNT;
> @@ -149,15 +219,28 @@ intel_ntb_mw_set_trans(const struct rte_rawdev
> *dev, int mw_idx,
>  	rte_write64(base, xlat_addr);
>  	rte_write64(limit, limit_addr);
> 
> -	/* Setup the external point so that remote can access. */
> -	xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
> -	xlat_addr = hw->hw_addr + xlat_off;
> -	limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx *
> XEON_BAR_INTERVAL_OFFSET;
> -	limit_addr = hw->hw_addr + limit_off;
> -	base = rte_read64(xlat_addr);
> -	base &= ~0xf;
> -	limit = base + size;
> -	rte_write64(limit, limit_addr);
> +	if (is_gen3_ntb(hw)) {
> +		/* Setup the external point so that remote can access. */
> +		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
> +		xlat_addr = hw->hw_addr + xlat_off;
> +		limit_off = XEON_EMBAR1XLMT_OFFSET +
> +			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
> +		limit_addr = hw->hw_addr + limit_off;
> +		base = rte_read64(xlat_addr);
> +		base &= ~0xf;
> +		limit = base + size;
> +		rte_write64(limit, limit_addr);
> +	} else if (is_gen4_ntb(hw)) {
Can we use a variable in struct to indicate it's gen4 or gen3 after init instead of check it every time?

> +		/* Set translate base address index register */
> +		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
> +			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
> +		xlat_addr = hw->hw_addr + xlat_off;
> +		rte_write16(rte_log2_u64(size), xlat_addr);
> +	} else {
> +		rte_write64(base, limit_addr);
> +		rte_write64(0, xlat_addr);
> +		return -ENOTSUP;
> +	}
Is the else branch necessary? As if neither gen3 or gen4, the init would fail. Would be better to print an ERR instead of just return NO support.
> 
>  	return 0;
>  }



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

* Re: [dpdk-dev] [PATCH v3] raw/ntb: add Icelake support for Intel NTB
  2020-09-07  8:34   ` Wu, Jingjing
@ 2020-09-07  9:18     ` Li, Xiaoyun
  2020-09-07 16:15       ` Wu, Jingjing
  0 siblings, 1 reply; 10+ messages in thread
From: Li, Xiaoyun @ 2020-09-07  9:18 UTC (permalink / raw)
  To: Wu, Jingjing; +Cc: dev, Maslekar, Omkar

Hi

> -----Original Message-----
> From: Wu, Jingjing <jingjing.wu@intel.com>
> Sent: Monday, September 7, 2020 16:35
> To: Li, Xiaoyun <xiaoyun.li@intel.com>
> Cc: dev@dpdk.org; Maslekar, Omkar <omkar.maslekar@intel.com>
> Subject: RE: [PATCH v3] raw/ntb: add Icelake support for Intel NTB
> 
> > +
> > +static int
> > +intel_ntb_dev_init(const struct rte_rawdev *dev) {
> > +	struct ntb_hw *hw = dev->dev_private;
> > +	uint8_t bar;
> > +	int ret, i;
> > +
> > +	if (hw == NULL) {
> > +		NTB_LOG(ERR, "Invalid device.");
> > +		return -EINVAL;
> > +	}
> > +
> >  	hw->hw_addr = (char *)hw->pci_dev->mem_resource[0].addr;
> >
> > +	if (is_gen3_ntb(hw)) {
> > +		ret = intel_ntb3_check_ppd(hw);
> > +	} else if (is_gen4_ntb(hw)) {
> > +		/* PPD is in MMIO but not config space for NTB Gen4 */
> > +		ret = intel_ntb4_check_ppd(hw);
> > +		if (ret)
> > +			return ret;
> Above two lines are not necessary.

OK.

> > +	} else {
> > +		return -ENOTSUP;
> > +	}
> > +
> > +	if (ret)
> > +		return ret;
> > +
> >  	hw->mw_cnt = XEON_MW_COUNT;
> >  	hw->db_cnt = XEON_DB_COUNT;
> >  	hw->spad_cnt = XEON_SPAD_COUNT;
> > @@ -149,15 +219,28 @@ intel_ntb_mw_set_trans(const struct rte_rawdev
> > *dev, int mw_idx,
> >  	rte_write64(base, xlat_addr);
> >  	rte_write64(limit, limit_addr);
> >
> > -	/* Setup the external point so that remote can access. */
> > -	xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
> > -	xlat_addr = hw->hw_addr + xlat_off;
> > -	limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx *
> > XEON_BAR_INTERVAL_OFFSET;
> > -	limit_addr = hw->hw_addr + limit_off;
> > -	base = rte_read64(xlat_addr);
> > -	base &= ~0xf;
> > -	limit = base + size;
> > -	rte_write64(limit, limit_addr);
> > +	if (is_gen3_ntb(hw)) {
> > +		/* Setup the external point so that remote can access. */
> > +		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
> > +		xlat_addr = hw->hw_addr + xlat_off;
> > +		limit_off = XEON_EMBAR1XLMT_OFFSET +
> > +			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
> > +		limit_addr = hw->hw_addr + limit_off;
> > +		base = rte_read64(xlat_addr);
> > +		base &= ~0xf;
> > +		limit = base + size;
> > +		rte_write64(limit, limit_addr);
> > +	} else if (is_gen4_ntb(hw)) {
> Can we use a variable in struct to indicate it's gen4 or gen3 after init instead of
> check it every time?

What's the difference? It comes from the value in hw->pci_dev->id.device_id.
Checking it in this way is trying to make it easier to extend it for gen2 ntb in the future. It's not either gen3 or gen4.
I don't think it makes sense to have a bool value to indicate it's gen3 or gen4.

> 
> > +		/* Set translate base address index register */
> > +		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
> > +			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
> > +		xlat_addr = hw->hw_addr + xlat_off;
> > +		rte_write16(rte_log2_u64(size), xlat_addr);
> > +	} else {
> > +		rte_write64(base, limit_addr);
> > +		rte_write64(0, xlat_addr);
> > +		return -ENOTSUP;
> > +	}
> Is the else branch necessary? As if neither gen3 or gen4, the init would fail.
> Would be better to print an ERR instead of just return NO support.

I don't think so.
Yes. It will fail in init. Returning err is to stop other following actions like in intel_ntb_vector_bind() since it should be stopped.
And I'd like to keep them in one coding style. As to the print, I think that can be upper layer's job to check the value and print err.
Choosing ENOTSUP is because that in init, if it's not supported hw, it will return -ENOTSUP err.

> >
> >  	return 0;
> >  }
> 


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

* Re: [dpdk-dev] [PATCH v3] raw/ntb: add Icelake support for Intel NTB
  2020-09-07  9:18     ` Li, Xiaoyun
@ 2020-09-07 16:15       ` Wu, Jingjing
  2020-09-08  1:53         ` Li, Xiaoyun
  0 siblings, 1 reply; 10+ messages in thread
From: Wu, Jingjing @ 2020-09-07 16:15 UTC (permalink / raw)
  To: Li, Xiaoyun; +Cc: dev, Maslekar, Omkar

> > > -	rte_write64(limit, limit_addr);
> > > +	if (is_gen3_ntb(hw)) {
> > > +		/* Setup the external point so that remote can access. */
> > > +		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
> > > +		xlat_addr = hw->hw_addr + xlat_off;
> > > +		limit_off = XEON_EMBAR1XLMT_OFFSET +
> > > +			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
> > > +		limit_addr = hw->hw_addr + limit_off;
> > > +		base = rte_read64(xlat_addr);
> > > +		base &= ~0xf;
> > > +		limit = base + size;
> > > +		rte_write64(limit, limit_addr);
> > > +	} else if (is_gen4_ntb(hw)) {
> > Can we use a variable in struct to indicate it's gen4 or gen3 after init instead of
> > check it every time?
> 
> What's the difference? It comes from the value in hw->pci_dev->id.device_id.
> Checking it in this way is trying to make it easier to extend it for gen2 ntb in the future.
> It's not either gen3 or gen4.
> I don't think it makes sense to have a bool value to indicate it's gen3 or gen4.

Understand, as the inline function is very simple, it looks OK.
> 
> >
> > > +		/* Set translate base address index register */
> > > +		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
> > > +			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
> > > +		xlat_addr = hw->hw_addr + xlat_off;
> > > +		rte_write16(rte_log2_u64(size), xlat_addr);
> > > +	} else {
> > > +		rte_write64(base, limit_addr);
> > > +		rte_write64(0, xlat_addr);
> > > +		return -ENOTSUP;
> > > +	}
> > Is the else branch necessary? As if neither gen3 or gen4, the init would fail.
> > Would be better to print an ERR instead of just return NO support.
> 
> I don't think so.
> Yes. It will fail in init. Returning err is to stop other following actions like in
> intel_ntb_vector_bind() since it should be stopped.
> And I'd like to keep them in one coding style. As to the print, I think that can be upper
> layer's job to check the value and print err.
> Choosing ENOTSUP is because that in init, if it's not supported hw, it will return -
> ENOTSUP err.
> 
I cannot say what you did is incorrect. But try to think it like this way:  according current API design, ntb raw device is allocated when driver probe, if init fails, raw device would be free. How the ops be called? 

> > >
> > >  	return 0;
> > >  }
> >


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

* Re: [dpdk-dev] [PATCH v3] raw/ntb: add Icelake support for Intel NTB
  2020-09-07 16:15       ` Wu, Jingjing
@ 2020-09-08  1:53         ` Li, Xiaoyun
  0 siblings, 0 replies; 10+ messages in thread
From: Li, Xiaoyun @ 2020-09-08  1:53 UTC (permalink / raw)
  To: Wu, Jingjing; +Cc: dev, Maslekar, Omkar

Hi

> -----Original Message-----
> From: Wu, Jingjing <jingjing.wu@intel.com>
> Sent: Tuesday, September 8, 2020 00:16
> To: Li, Xiaoyun <xiaoyun.li@intel.com>
> Cc: dev@dpdk.org; Maslekar, Omkar <omkar.maslekar@intel.com>
> Subject: RE: [PATCH v3] raw/ntb: add Icelake support for Intel NTB
> 
> > > > -	rte_write64(limit, limit_addr);
> > > > +	if (is_gen3_ntb(hw)) {
> > > > +		/* Setup the external point so that remote can access. */
> > > > +		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
> > > > +		xlat_addr = hw->hw_addr + xlat_off;
> > > > +		limit_off = XEON_EMBAR1XLMT_OFFSET +
> > > > +			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
> > > > +		limit_addr = hw->hw_addr + limit_off;
> > > > +		base = rte_read64(xlat_addr);
> > > > +		base &= ~0xf;
> > > > +		limit = base + size;
> > > > +		rte_write64(limit, limit_addr);
> > > > +	} else if (is_gen4_ntb(hw)) {
> > > Can we use a variable in struct to indicate it's gen4 or gen3 after
> > > init instead of check it every time?
> >
> > What's the difference? It comes from the value in hw->pci_dev->id.device_id.
> > Checking it in this way is trying to make it easier to extend it for gen2 ntb in the
> future.
> > It's not either gen3 or gen4.
> > I don't think it makes sense to have a bool value to indicate it's gen3 or gen4.
> 
> Understand, as the inline function is very simple, it looks OK.
> >
> > >
> > > > +		/* Set translate base address index register */
> > > > +		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
> > > > +			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
> > > > +		xlat_addr = hw->hw_addr + xlat_off;
> > > > +		rte_write16(rte_log2_u64(size), xlat_addr);
> > > > +	} else {
> > > > +		rte_write64(base, limit_addr);
> > > > +		rte_write64(0, xlat_addr);
> > > > +		return -ENOTSUP;
> > > > +	}
> > > Is the else branch necessary? As if neither gen3 or gen4, the init would fail.
> > > Would be better to print an ERR instead of just return NO support.
> >
> > I don't think so.
> > Yes. It will fail in init. Returning err is to stop other following
> > actions like in
> > intel_ntb_vector_bind() since it should be stopped.
> > And I'd like to keep them in one coding style. As to the print, I
> > think that can be upper layer's job to check the value and print err.
> > Choosing ENOTSUP is because that in init, if it's not supported hw, it
> > will return - ENOTSUP err.
> >
> I cannot say what you did is incorrect. But try to think it like this way:  according
> current API design, ntb raw device is allocated when driver probe, if init fails,
> raw device would be free. How the ops be called?

I'll add a err print later.
> 
> > > >
> > > >  	return 0;
> > > >  }
> > >


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

* [dpdk-dev] [PATCH v4] raw/ntb: add Ice Lake support for Intel NTB
  2020-08-31  4:59 [dpdk-dev] [PATCH] raw/ntb: add Icelake support for Intel NTB Xiaoyun Li
  2020-09-07  1:46 ` [dpdk-dev] [PATCH v2] " Xiaoyun Li
  2020-09-07  2:21 ` [dpdk-dev] [PATCH v3] " Xiaoyun Li
@ 2020-09-08  3:27 ` Xiaoyun Li
  2020-09-08  4:43   ` Wu, Jingjing
  2 siblings, 1 reply; 10+ messages in thread
From: Xiaoyun Li @ 2020-09-08  3:27 UTC (permalink / raw)
  To: jingjing.wu; +Cc: dev, omkar.maslekar, Xiaoyun Li

Add NTB device support (4th generation) for Intel Ice Lake platform.

Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
---
v4:
 * Removed unnecessary return.
 * Added more print log.
 * Replaced "Icelake" with "Ice Lake".
v3:
 * Removed a blank line.
 * Added change doc for v2.
v2:
 * Corrected and polished the doc.
 * Fixed a link setup issue.
---
 doc/guides/rawdevs/ntb.rst             |  16 +-
 doc/guides/rel_notes/release_20_11.rst |   3 +
 drivers/raw/ntb/ntb.c                  |   5 +
 drivers/raw/ntb/ntb.h                  |   1 +
 drivers/raw/ntb/ntb_hw_intel.c         | 241 ++++++++++++++++++++++---
 drivers/raw/ntb/ntb_hw_intel.h         |  27 ++-
 usertools/dpdk-devbind.py              |   4 +-
 7 files changed, 255 insertions(+), 42 deletions(-)

diff --git a/doc/guides/rawdevs/ntb.rst b/doc/guides/rawdevs/ntb.rst
index aa7d80964..39e4d65f8 100644
--- a/doc/guides/rawdevs/ntb.rst
+++ b/doc/guides/rawdevs/ntb.rst
@@ -14,16 +14,16 @@ allocation for the peer to access and read/write allocated memory from peer.
 Also, the PMD allows to use doorbell registers to notify the peer and share
 some information by using scratchpad registers.
 
-BIOS setting on Intel Skylake
------------------------------
+BIOS setting on Intel Xeon
+--------------------------
 
-Intel Non-transparent Bridge needs special BIOS setting. Since the PMD only
-supports Intel Skylake platform, introduce BIOS setting here. The referencce
-is https://www.intel.com/content/dam/support/us/en/documents/server-products/Intel_Xeon_Processor_Scalable_Family_BIOS_User_Guide.pdf
+Intel Non-transparent Bridge needs special BIOS setting. The referencce for
+Skylake is https://www.intel.com/content/dam/support/us/en/documents/server-products/Intel_Xeon_Processor_Scalable_Family_BIOS_User_Guide.pdf
 
 - Set the needed PCIe port as NTB to NTB mode on both hosts.
-- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (2K-512M)
-  on both hosts. Note that bar size on both hosts should be the same.
+- Enable NTB bars and set bar size of bar 23 and bar 45 as 12-29 (4K-512M)
+  on both hosts (for Ice Lake, bar size can be set as 12-51, namely 4K-128PB).
+  Note that bar size on both hosts should be the same.
 - Disable split bars for both hosts.
 - Set crosslink control override as DSD/USP on one host, USD/DSP on
   another host.
@@ -151,4 +151,4 @@ like the following:
 Limitation
 ----------
 
-- This PMD only supports Intel Skylake platform.
+- This PMD only supports Intel Skylake and Ice Lake platforms.
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index df227a177..db9ebc4e7 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -55,6 +55,9 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added Ice Lake (Gen4) support for Intel NTB.**
+
+  Added NTB device support (4th generation) for Intel Ice Lake platform.
 
 Removed Items
 -------------
diff --git a/drivers/raw/ntb/ntb.c b/drivers/raw/ntb/ntb.c
index e40412bb7..e29acecef 100644
--- a/drivers/raw/ntb/ntb.c
+++ b/drivers/raw/ntb/ntb.c
@@ -25,6 +25,7 @@
 
 static const struct rte_pci_id pci_id_ntb_map[] = {
 	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_SKX) },
+	{ RTE_PCI_DEVICE(NTB_INTEL_VENDOR_ID, NTB_INTEL_DEV_ID_B2B_ICX) },
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -244,6 +245,9 @@ ntb_dev_intr_handler(void *param)
 		hw->peer_dev_up = 0;
 		return;
 	}
+
+	/* Clear other received doorbells. */
+	(*hw->ntb_ops->db_clear)(dev, db_bits);
 }
 
 static void
@@ -1333,6 +1337,7 @@ ntb_init_hw(struct rte_rawdev *dev, struct rte_pci_device *pci_dev)
 
 	switch (pci_dev->id.device_id) {
 	case NTB_INTEL_DEV_ID_B2B_SKX:
+	case NTB_INTEL_DEV_ID_B2B_ICX:
 		hw->ntb_ops = &intel_ntb_ops;
 		break;
 	default:
diff --git a/drivers/raw/ntb/ntb.h b/drivers/raw/ntb/ntb.h
index a561c42d1..cdf7667d5 100644
--- a/drivers/raw/ntb/ntb.h
+++ b/drivers/raw/ntb/ntb.h
@@ -18,6 +18,7 @@ extern int ntb_logtype;
 
 /* Device IDs */
 #define NTB_INTEL_DEV_ID_B2B_SKX    0x201C
+#define NTB_INTEL_DEV_ID_B2B_ICX    0x347E
 
 /* Reserved to app to use. */
 #define NTB_SPAD_USER               "spad_user_"
diff --git a/drivers/raw/ntb/ntb_hw_intel.c b/drivers/raw/ntb/ntb_hw_intel.c
index e7f8667cd..4427e1145 100644
--- a/drivers/raw/ntb/ntb_hw_intel.c
+++ b/drivers/raw/ntb/ntb_hw_intel.c
@@ -25,17 +25,29 @@ static enum xeon_ntb_bar intel_ntb_bar[] = {
 	XEON_NTB_BAR45,
 };
 
-static int
-intel_ntb_dev_init(const struct rte_rawdev *dev)
+static inline int
+is_gen3_ntb(const struct ntb_hw *hw)
 {
-	struct ntb_hw *hw = dev->dev_private;
-	uint8_t reg_val, bar;
-	int ret, i;
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_SKX)
+		return 1;
 
-	if (hw == NULL) {
-		NTB_LOG(ERR, "Invalid device.");
-		return -EINVAL;
-	}
+	return 0;
+}
+
+static inline int
+is_gen4_ntb(const struct ntb_hw *hw)
+{
+	if (hw->pci_dev->id.device_id == NTB_INTEL_DEV_ID_B2B_ICX)
+		return 1;
+
+	return 0;
+}
+
+static int
+intel_ntb3_check_ppd(struct ntb_hw *hw)
+{
+	uint8_t reg_val;
+	int ret;
 
 	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
 				  sizeof(reg_val), XEON_PPD_OFFSET);
@@ -71,8 +83,65 @@ intel_ntb_dev_init(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
+	return 0;
+}
+
+static int
+intel_ntb4_check_ppd(struct ntb_hw *hw)
+{
+	uint32_t reg_val;
+
+	reg_val = rte_read32(hw->hw_addr + XEON_GEN4_PPD1_OFFSET);
+
+	/* Check connection topo type. Only support B2B. */
+	switch (reg_val & XEON_GEN4_PPD_CONN_MASK) {
+	case XEON_GEN4_PPD_CONN_B2B:
+		NTB_LOG(INFO, "Topo B2B (back to back) is using.");
+		break;
+	default:
+		NTB_LOG(ERR, "Not supported conn topo. Please use B2B.");
+		return -EINVAL;
+	}
+
+	/* Check device type. */
+	if (reg_val & XEON_GEN4_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;
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_dev_init(const struct rte_rawdev *dev)
+{
+	struct ntb_hw *hw = dev->dev_private;
+	uint8_t bar;
+	int ret, i;
+
+	if (hw == NULL) {
+		NTB_LOG(ERR, "Invalid device.");
+		return -EINVAL;
+	}
+
 	hw->hw_addr = (char *)hw->pci_dev->mem_resource[0].addr;
 
+	if (is_gen3_ntb(hw))
+		ret = intel_ntb3_check_ppd(hw);
+	else if (is_gen4_ntb(hw))
+		/* PPD is in MMIO but not config space for NTB Gen4 */
+		ret = intel_ntb4_check_ppd(hw);
+	else {
+		NTB_LOG(ERR, "Cannot init device for unsupported device.");
+		return -ENOTSUP;
+	}
+
+	if (ret)
+		return ret;
+
 	hw->mw_cnt = XEON_MW_COUNT;
 	hw->db_cnt = XEON_DB_COUNT;
 	hw->spad_cnt = XEON_SPAD_COUNT;
@@ -149,15 +218,29 @@ intel_ntb_mw_set_trans(const struct rte_rawdev *dev, int mw_idx,
 	rte_write64(base, xlat_addr);
 	rte_write64(limit, limit_addr);
 
-	/* Setup the external point so that remote can access. */
-	xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
-	xlat_addr = hw->hw_addr + xlat_off;
-	limit_off = XEON_EMBAR1XLMT_OFFSET + mw_idx * XEON_BAR_INTERVAL_OFFSET;
-	limit_addr = hw->hw_addr + limit_off;
-	base = rte_read64(xlat_addr);
-	base &= ~0xf;
-	limit = base + size;
-	rte_write64(limit, limit_addr);
+	if (is_gen3_ntb(hw)) {
+		/* Setup the external point so that remote can access. */
+		xlat_off = XEON_EMBAR1_OFFSET + 8 * mw_idx;
+		xlat_addr = hw->hw_addr + xlat_off;
+		limit_off = XEON_EMBAR1XLMT_OFFSET +
+			    mw_idx * XEON_BAR_INTERVAL_OFFSET;
+		limit_addr = hw->hw_addr + limit_off;
+		base = rte_read64(xlat_addr);
+		base &= ~0xf;
+		limit = base + size;
+		rte_write64(limit, limit_addr);
+	} else if (is_gen4_ntb(hw)) {
+		/* Set translate base address index register */
+		xlat_off = XEON_GEN4_IM1XBASEIDX_OFFSET +
+			   mw_idx * XEON_GEN4_XBASEIDX_INTERVAL;
+		xlat_addr = hw->hw_addr + xlat_off;
+		rte_write16(rte_log2_u64(size), xlat_addr);
+	} else {
+		NTB_LOG(ERR, "Cannot set translation of memory windows for unsupported device.");
+		rte_write64(base, limit_addr);
+		rte_write64(0, xlat_addr);
+		return -ENOTSUP;
+	}
 
 	return 0;
 }
@@ -187,7 +270,7 @@ static int
 intel_ntb_get_link_status(const struct rte_rawdev *dev)
 {
 	struct ntb_hw *hw = dev->dev_private;
-	uint16_t reg_val;
+	uint16_t reg_val, reg_off;
 	int ret;
 
 	if (hw == NULL) {
@@ -195,11 +278,20 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 		return -EINVAL;
 	}
 
-	ret = rte_pci_read_config(hw->pci_dev, &reg_val,
-				  sizeof(reg_val), XEON_LINK_STATUS_OFFSET);
-	if (ret < 0) {
-		NTB_LOG(ERR, "Unable to get link status.");
-		return -EIO;
+	if (is_gen3_ntb(hw)) {
+		reg_off = XEON_GEN3_LINK_STATUS_OFFSET;
+		ret = rte_pci_read_config(hw->pci_dev, &reg_val,
+					  sizeof(reg_val), reg_off);
+		if (ret < 0) {
+			NTB_LOG(ERR, "Unable to get link status.");
+			return -EIO;
+		}
+	} else if (is_gen4_ntb(hw)) {
+		reg_off = XEON_GEN4_LINK_STATUS_OFFSET;
+		reg_val = rte_read16(hw->hw_addr + reg_off);
+	} else {
+		NTB_LOG(ERR, "Cannot get link status for unsupported device.");
+		return -ENOTSUP;
 	}
 
 	hw->link_status = NTB_LNK_STA_ACTIVE(reg_val);
@@ -216,9 +308,8 @@ intel_ntb_get_link_status(const struct rte_rawdev *dev)
 }
 
 static int
-intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+intel_ntb_gen3_set_link(const struct ntb_hw *hw, bool up)
 {
-	struct ntb_hw *hw = dev->dev_private;
 	uint32_t ntb_ctrl, reg_off;
 	void *reg_addr;
 
@@ -241,6 +332,70 @@ intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
 	return 0;
 }
 
+static int
+intel_ntb_gen4_set_link(const struct ntb_hw *hw, bool up)
+{
+	uint32_t ntb_ctrl, ppd0;
+	uint16_t link_ctrl;
+	void *reg_addr;
+
+	if (up) {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+		ntb_ctrl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl &= ~XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+
+		/* start link training */
+		reg_addr = hw->hw_addr + XEON_GEN4_PPD0_OFFSET;
+		ppd0 = rte_read32(reg_addr);
+		ppd0 |= XEON_GEN4_PPD_LINKTRN;
+		rte_write32(ppd0, reg_addr);
+
+		/* make sure link training has started */
+		ppd0 = rte_read32(reg_addr);
+		if (!(ppd0 & XEON_GEN4_PPD_LINKTRN)) {
+			NTB_LOG(ERR, "Link is not training.");
+			return -EINVAL;
+		}
+	} else {
+		reg_addr = hw->hw_addr + XEON_NTBCNTL_OFFSET;
+		ntb_ctrl = rte_read32(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);
+		rte_write32(ntb_ctrl, reg_addr);
+
+		reg_addr = hw->hw_addr + XEON_GEN4_LINK_CTRL_OFFSET;
+		link_ctrl = rte_read16(reg_addr);
+		link_ctrl |= XEON_GEN4_LINK_CTRL_LINK_DIS;
+		rte_write16(link_ctrl, reg_addr);
+	}
+
+	return 0;
+}
+
+static int
+intel_ntb_set_link(const struct rte_rawdev *dev, bool up)
+{
+	struct ntb_hw *hw = dev->dev_private;
+	int ret = 0;
+
+	if (is_gen3_ntb(hw))
+		ret = intel_ntb_gen3_set_link(hw, up);
+	else if (is_gen4_ntb(hw))
+		ret = intel_ntb_gen4_set_link(hw, up);
+	else {
+		NTB_LOG(ERR, "Cannot set link for unsupported device.");
+		ret = -ENOTSUP;
+	}
+
+	return ret;
+}
+
 static uint32_t
 intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 {
@@ -254,7 +409,16 @@ intel_ntb_spad_read(const struct rte_rawdev *dev, int spad, bool peer)
 	}
 
 	/* When peer is true, read peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else {
+		NTB_LOG(ERR, "Cannot read spad for unsupported device.");
+		return -ENOTSUP;
+	}
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 	spad_v = rte_read32(reg_addr);
 
@@ -275,7 +439,16 @@ intel_ntb_spad_write(const struct rte_rawdev *dev, int spad,
 	}
 
 	/* When peer is true, write peer spad reg */
-	reg_off = peer ? XEON_B2B_SPAD_OFFSET : XEON_IM_SPAD_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = peer ? XEON_GEN3_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = peer ? XEON_GEN4_B2B_SPAD_OFFSET :
+				XEON_IM_SPAD_OFFSET;
+	else {
+		NTB_LOG(ERR, "Cannot write spad for unsupported device.");
+		return -ENOTSUP;
+	}
 	reg_addr = hw->hw_addr + reg_off + (spad << 2);
 
 	rte_write32(spad_v, reg_addr);
@@ -308,6 +481,9 @@ intel_ntb_db_clear(const struct rte_rawdev *dev, uint64_t db_bits)
 	db_off = XEON_IM_INT_STATUS_OFFSET;
 	db_addr = hw->hw_addr + db_off;
 
+	if (is_gen4_ntb(hw))
+		rte_write16(XEON_GEN4_SLOTSTS_DLLSCS,
+			    hw->hw_addr + XEON_GEN4_SLOTSTS);
 	rte_write64(db_bits, db_addr);
 
 	return 0;
@@ -365,7 +541,14 @@ intel_ntb_vector_bind(const struct rte_rawdev *dev, uint8_t intr, uint8_t msix)
 	}
 
 	/* Bind intr source to msix vector */
-	reg_off = XEON_INTVEC_OFFSET;
+	if (is_gen3_ntb(hw))
+		reg_off = XEON_GEN3_INTVEC_OFFSET;
+	else if (is_gen4_ntb(hw))
+		reg_off = XEON_GEN4_INTVEC_OFFSET;
+	else {
+		NTB_LOG(ERR, "Cannot bind vectors for unsupported device.");
+		return -ENOTSUP;
+	}
 	reg_addr = hw->hw_addr + reg_off + intr;
 
 	rte_write8(msix, reg_addr);
diff --git a/drivers/raw/ntb/ntb_hw_intel.h b/drivers/raw/ntb/ntb_hw_intel.h
index 4d1e64504..c61a2a8a6 100644
--- a/drivers/raw/ntb/ntb_hw_intel.h
+++ b/drivers/raw/ntb/ntb_hw_intel.h
@@ -22,7 +22,7 @@
 #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 */
+/* Intel Xeon hardware */
 #define XEON_IMBAR1SZ_OFFSET		0x00d0
 #define XEON_IMBAR2SZ_OFFSET		0x00d1
 #define XEON_EMBAR1SZ_OFFSET		0x00d2
@@ -31,7 +31,13 @@
 #define XEON_DEVSTS_OFFSET		0x009a
 #define XEON_UNCERRSTS_OFFSET		0x014c
 #define XEON_CORERRSTS_OFFSET		0x0158
-#define XEON_LINK_STATUS_OFFSET		0x01a2
+#define XEON_GEN3_LINK_STATUS_OFFSET	0x01a2
+/* Link status and PPD are in MMIO but not config space for Gen4 NTB */
+#define XEON_GEN4_PPD0_OFFSET		0xb0d4
+#define XEON_GEN4_PPD1_OFFSET		0xb4c0
+#define XEON_GEN4_LINK_CTRL_OFFSET	0xb050
+#define XEON_GEN4_LINK_STATUS_OFFSET	0xb052
+#define XEON_GEN4_LINK_CTRL_LINK_DIS	0x0010
 
 #define XEON_NTBCNTL_OFFSET		0x0000
 #define XEON_BAR_INTERVAL_OFFSET	0x0010
@@ -39,13 +45,18 @@
 #define XEON_IMBAR1XLMT_OFFSET		0x0018		/* SBAR2LMT */
 #define XEON_IMBAR2XBASE_OFFSET		0x0020		/* SBAR4XLAT */
 #define XEON_IMBAR2XLMT_OFFSET		0x0028		/* SBAR4LMT */
+#define XEON_GEN4_XBASEIDX_INTERVAL	0x0002
+#define XEON_GEN4_IM1XBASEIDX_OFFSET	0x0074
+#define XEON_GEN4_IM2XBASEIDX_OFFSET	0x0076
 #define XEON_IM_INT_STATUS_OFFSET	0x0040
 #define XEON_IM_INT_DISABLE_OFFSET	0x0048
 #define XEON_IM_SPAD_OFFSET		0x0080		/* SPAD */
+#define XEON_GEN3_B2B_SPAD_OFFSET	0x0180		/* GEN3 B2B SPAD */
+#define XEON_GEN4_B2B_SPAD_OFFSET	0x8080		/* GEN4 B2B SPAD */
 #define XEON_USMEMMISS_OFFSET		0x0070
-#define XEON_INTVEC_OFFSET		0x00d0
+#define XEON_GEN3_INTVEC_OFFSET		0x00d0
+#define XEON_GEN4_INTVEC_OFFSET		0x0050
 #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 */
@@ -70,6 +81,14 @@
 #define XEON_PPD_DEV_DSD		0x10
 #define XEON_PPD_SPLIT_BAR_MASK		0x40
 
+#define XEON_GEN4_PPD_CONN_MASK		0x0300
+#define XEON_GEN4_PPD_CONN_B2B		0x0200
+#define XEON_GEN4_PPD_DEV_MASK		0x1000
+#define XEON_GEN4_PPD_DEV_DSD		0x1000
+#define XEON_GEN4_PPD_DEV_USD		0x0000
+#define XEON_GEN4_PPD_LINKTRN		0x0008
+#define XEON_GEN4_SLOTSTS		0xb05a
+#define XEON_GEN4_SLOTSTS_DLLSCS	0x100
 
 #define XEON_MW_COUNT			2
 
diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py
index 86b6b53c4..081c3bc92 100755
--- a/usertools/dpdk-devbind.py
+++ b/usertools/dpdk-devbind.py
@@ -53,6 +53,8 @@
               'SVendor': None, 'SDevice': None}
 intel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c',
               'SVendor': None, 'SDevice': None}
+intel_ntb_icx = {'Class': '06', 'Vendor': '8086', 'Device': '347e',
+              'SVendor': None, 'SDevice': None}
 
 network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
 baseband_devices = [acceleration_class]
@@ -60,7 +62,7 @@
 eventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso]
 mempool_devices = [cavium_fpa, octeontx2_npa]
 compress_devices = [cavium_zip]
-misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, octeontx2_dma]
+misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_ntb_skx, intel_ntb_icx, octeontx2_dma]
 
 # global dict ethernet devices present. Dictionary indexed by PCI address.
 # Each device within this is itself a dictionary of device properties
-- 
2.17.1


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

* Re: [dpdk-dev] [PATCH v4] raw/ntb: add Ice Lake support for Intel NTB
  2020-09-08  3:27 ` [dpdk-dev] [PATCH v4] raw/ntb: add Ice Lake " Xiaoyun Li
@ 2020-09-08  4:43   ` Wu, Jingjing
  2020-10-05 23:25     ` Thomas Monjalon
  0 siblings, 1 reply; 10+ messages in thread
From: Wu, Jingjing @ 2020-09-08  4:43 UTC (permalink / raw)
  To: Li, Xiaoyun; +Cc: dev, Maslekar, Omkar



> -----Original Message-----
> From: Li, Xiaoyun <xiaoyun.li@intel.com>
> Sent: Tuesday, September 8, 2020 11:28 AM
> To: Wu, Jingjing <jingjing.wu@intel.com>
> Cc: dev@dpdk.org; Maslekar, Omkar <omkar.maslekar@intel.com>; Li,
> Xiaoyun <xiaoyun.li@intel.com>
> Subject: [PATCH v4] raw/ntb: add Ice Lake support for Intel NTB
> 
> Add NTB device support (4th generation) for Intel Ice Lake platform.
> 
> Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>

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

* Re: [dpdk-dev] [PATCH v4] raw/ntb: add Ice Lake support for Intel NTB
  2020-09-08  4:43   ` Wu, Jingjing
@ 2020-10-05 23:25     ` Thomas Monjalon
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Monjalon @ 2020-10-05 23:25 UTC (permalink / raw)
  To: Li, Xiaoyun; +Cc: dev, Maslekar, Omkar, Wu, Jingjing

> > Add NTB device support (4th generation) for Intel Ice Lake platform.
> > 
> > Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
> Acked-by: Jingjing Wu <jingjing.wu@intel.com>

Applied, thanks



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

end of thread, other threads:[~2020-10-05 23:25 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-31  4:59 [dpdk-dev] [PATCH] raw/ntb: add Icelake support for Intel NTB Xiaoyun Li
2020-09-07  1:46 ` [dpdk-dev] [PATCH v2] " Xiaoyun Li
2020-09-07  2:21 ` [dpdk-dev] [PATCH v3] " Xiaoyun Li
2020-09-07  8:34   ` Wu, Jingjing
2020-09-07  9:18     ` Li, Xiaoyun
2020-09-07 16:15       ` Wu, Jingjing
2020-09-08  1:53         ` Li, Xiaoyun
2020-09-08  3:27 ` [dpdk-dev] [PATCH v4] raw/ntb: add Ice Lake " Xiaoyun Li
2020-09-08  4:43   ` Wu, Jingjing
2020-10-05 23:25     ` Thomas Monjalon

DPDK patches and discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://inbox.dpdk.org/dev/0 dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dev dev/ https://inbox.dpdk.org/dev \
		dev@dpdk.org
	public-inbox-index dev

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.dpdk.org/inbox.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git