From: Dave Jiang dave.jiang@intel.com
mainline inclusion from mainline-v5.8-rc1 commit 134a86545c6072c049a2c6e77d6843e650df511d category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I47H3V CVE: NA
--------------------------------
commit: 134a86545c6072c049a2c6e77d6843e650df511d upstream.
Backport summary: Backport to kernel 4.19.57 for 4th Gen Intel NTB support
Add NTB_HWERR_BAR_ALIGN hw errata flag to work around issue where the aligment for the XLAT base must be BAR size aligned rather than 4k page aligned. On ICX platform, the XLAT base can be 4k page size aligned rather than BAR size aligned unlike the previous gen Intel NTB. However, a silicon errata prevented this from working as expected and a workaround is introduced to resolve the issue.
Signed-off-by: Dave Jiang dave.jiang@intel.com Signed-off-by: Jon Mason jdmason@kudzu.us Signed-off-by: Zheng Wu wu.zheng@intel.com Signed-off-by: Jackie Liu liuyun01@kylinos.cn Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Reviewed-by: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/ntb/hw/intel/ntb_hw_gen1.h | 1 + drivers/ntb/hw/intel/ntb_hw_gen4.c | 78 +++++++++++++++++++++++++----- drivers/ntb/hw/intel/ntb_hw_gen4.h | 13 +++++ 3 files changed, 79 insertions(+), 13 deletions(-)
diff --git a/drivers/ntb/hw/intel/ntb_hw_gen1.h b/drivers/ntb/hw/intel/ntb_hw_gen1.h index 544cf5c06f4d..1b759942d8af 100644 --- a/drivers/ntb/hw/intel/ntb_hw_gen1.h +++ b/drivers/ntb/hw/intel/ntb_hw_gen1.h @@ -140,6 +140,7 @@ #define NTB_HWERR_SB01BASE_LOCKUP BIT_ULL(1) #define NTB_HWERR_B2BDOORBELL_BIT14 BIT_ULL(2) #define NTB_HWERR_MSIX_VECTOR32_BAD BIT_ULL(3) +#define NTB_HWERR_BAR_ALIGN BIT_ULL(4)
extern struct intel_b2b_addr xeon_b2b_usd_addr; extern struct intel_b2b_addr xeon_b2b_dsd_addr; diff --git a/drivers/ntb/hw/intel/ntb_hw_gen4.c b/drivers/ntb/hw/intel/ntb_hw_gen4.c index 70c759a95bfe..bc4541cbf8c6 100644 --- a/drivers/ntb/hw/intel/ntb_hw_gen4.c +++ b/drivers/ntb/hw/intel/ntb_hw_gen4.c @@ -177,6 +177,9 @@ int gen4_init_dev(struct intel_ntb_dev *ndev)
ndev->reg = &gen4_reg;
+ if (pdev_is_ICX(pdev)) + ndev->hwerr_flags |= NTB_HWERR_BAR_ALIGN; + ppd1 = ioread32(ndev->self_mmio + GEN4_PPD1_OFFSET); ndev->ntb.topo = gen4_ppd_topo(ndev, ppd1); dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd1, @@ -342,9 +345,14 @@ static int intel_ntb4_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, else mw_size = bar_size;
- /* hardware requires that addr is aligned to bar size */ - if (addr & (bar_size - 1)) - return -EINVAL; + if (ndev->hwerr_flags & NTB_HWERR_BAR_ALIGN) { + /* hardware requires that addr is aligned to bar size */ + if (addr & (bar_size - 1)) + return -EINVAL; + } else { + if (addr & (PAGE_SIZE - 1)) + return -EINVAL; + }
/* make sure the range fits in the usable mw size */ if (size > mw_size) @@ -353,7 +361,6 @@ static int intel_ntb4_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, mmio = ndev->self_mmio; xlat_reg = ndev->xlat_reg->bar2_xlat + (idx * 0x10); limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10); - idx_reg = ndev->xlat_reg->bar2_idx + (idx * 0x2); base = pci_resource_start(ndev->ntb.pdev, bar);
/* Set the limit if supported, if size is not mw_size */ @@ -387,16 +394,19 @@ static int intel_ntb4_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dev_dbg(&ntb->pdev->dev, "BAR %d IMXLMT: %#Lx\n", bar, reg_val);
- iowrite16(base_idx, mmio + idx_reg); - reg_val16 = ioread16(mmio + idx_reg); - if (reg_val16 != base_idx) { - iowrite64(base, mmio + limit_reg); - iowrite64(0, mmio + xlat_reg); - iowrite16(0, mmio + idx_reg); - return -EIO; + if (ndev->hwerr_flags & NTB_HWERR_BAR_ALIGN) { + idx_reg = ndev->xlat_reg->bar2_idx + (idx * 0x2); + iowrite16(base_idx, mmio + idx_reg); + reg_val16 = ioread16(mmio + idx_reg); + if (reg_val16 != base_idx) { + iowrite64(base, mmio + limit_reg); + iowrite64(0, mmio + xlat_reg); + iowrite16(0, mmio + idx_reg); + return -EIO; + } + dev_dbg(&ntb->pdev->dev, "BAR %d IMBASEIDX: %#x\n", bar, reg_val16); }
- dev_dbg(&ntb->pdev->dev, "BAR %d IMBASEIDX: %#x\n", bar, reg_val16);
return 0; } @@ -471,9 +481,51 @@ static int intel_ntb4_link_disable(struct ntb_dev *ntb) return 0; }
+static int intel_ntb4_mw_get_align(struct ntb_dev *ntb, int pidx, int idx, + resource_size_t *addr_align, + resource_size_t *size_align, + resource_size_t *size_max) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + resource_size_t bar_size, mw_size; + int bar; + + if (pidx != NTB_DEF_PEER_IDX) + return -EINVAL; + + if (idx >= ndev->b2b_idx && !ndev->b2b_off) + idx += 1; + + bar = ndev_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; + + bar_size = pci_resource_len(ndev->ntb.pdev, bar); + + if (idx == ndev->b2b_idx) + mw_size = bar_size - ndev->b2b_off; + else + mw_size = bar_size; + + if (addr_align) { + if (ndev->hwerr_flags & NTB_HWERR_BAR_ALIGN) + *addr_align = pci_resource_len(ndev->ntb.pdev, bar); + else + *addr_align = PAGE_SIZE; + } + + if (size_align) + *size_align = 1; + + if (size_max) + *size_max = mw_size; + + return 0; +} + const struct ntb_dev_ops intel_ntb4_ops = { .mw_count = intel_ntb_mw_count, - .mw_get_align = intel_ntb_mw_get_align, + .mw_get_align = intel_ntb4_mw_get_align, .mw_set_trans = intel_ntb4_mw_set_trans, .peer_mw_count = intel_ntb_peer_mw_count, .peer_mw_get_addr = intel_ntb_peer_mw_get_addr, diff --git a/drivers/ntb/hw/intel/ntb_hw_gen4.h b/drivers/ntb/hw/intel/ntb_hw_gen4.h index 7d7a82e8518d..a868c788de02 100644 --- a/drivers/ntb/hw/intel/ntb_hw_gen4.h +++ b/drivers/ntb/hw/intel/ntb_hw_gen4.h @@ -5,6 +5,10 @@
#include "ntb_hw_intel.h"
+/* Supported PCI device revision range for ICX */ +#define PCI_DEVICE_REVISION_ICX_MIN 0x2 +#define PCI_DEVICE_REVISION_ICX_MAX 0xF + /* Intel Gen4 NTB hardware */ /* PCIe config space */ #define GEN4_IMBAR23SZ_OFFSET 0x00c4 @@ -84,4 +88,13 @@ ssize_t ndev_ntb4_debugfs_read(struct file *filp, char __user *ubuf,
extern const struct ntb_dev_ops intel_ntb4_ops;
+static inline int pdev_is_ICX(struct pci_dev *pdev) +{ + if (pdev_is_gen4(pdev) && + pdev->revision >= PCI_DEVICE_REVISION_ICX_MIN && + pdev->revision <= PCI_DEVICE_REVISION_ICX_MAX) + return 1; + return 0; +} + #endif