diff options
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rw-r--r-- | drivers/ntb/hw/amd/ntb_hw_amd.c | 4 | ||||
-rw-r--r-- | drivers/ntb/hw/idt/ntb_hw_idt.c | 37 | ||||
-rw-r--r-- | drivers/ntb/hw/intel/ntb_hw_intel.c | 313 | ||||
-rw-r--r-- | drivers/ntb/hw/intel/ntb_hw_intel.h | 58 | ||||
-rw-r--r-- | drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 603 | ||||
-rw-r--r-- | drivers/ntb/ntb.c | 4 | ||||
-rw-r--r-- | drivers/ntb/ntb_transport.c | 3 | ||||
-rw-r--r-- | drivers/ntb/test/ntb_perf.c | 1824 | ||||
-rw-r--r-- | drivers/ntb/test/ntb_pingpong.c | 450 | ||||
-rw-r--r-- | drivers/ntb/test/ntb_tool.c | 1825 | ||||
-rw-r--r-- | include/linux/ntb.h | 51 | ||||
-rw-r--r-- | include/linux/switchtec.h | 23 | ||||
-rwxr-xr-x | tools/testing/selftests/ntb/ntb_test.sh | 307 |
14 files changed, 3550 insertions, 1954 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index e15f4e201471..b59a8cdfbe66 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9801,7 +9801,7 @@ F: drivers/ntb/hw/amd/ NTB DRIVER CORE M: Jon Mason <jdmason@kudzu.us> M: Dave Jiang <dave.jiang@intel.com> -M: Allen Hubbe <Allen.Hubbe@emc.com> +M: Allen Hubbe <allenbh@gmail.com> L: linux-ntb@googlegroups.com S: Supported W: https://github.com/jonmason/ntb/wiki diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c index f0788aae05c9..3cfa46876239 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.c +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c @@ -1020,6 +1020,10 @@ static int amd_ntb_init_pci(struct amd_ntb_dev *ndev, goto err_dma_mask; dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); } + rc = dma_coerce_mask_and_coherent(&ndev->ntb.dev, + dma_get_mask(&pdev->dev)); + if (rc) + goto err_dma_mask; ndev->self_mmio = pci_iomap(pdev, 0, 0); if (!ndev->self_mmio) { diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index 0cd79f367f7c..8d98872d0983 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -1744,20 +1744,19 @@ static int idt_ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits) * idt_ntb_msg_read() - read message register with specified index * (NTB API callback) * @ntb: NTB device context. - * @midx: Message register index * @pidx: OUT - Port index of peer device a message retrieved from - * @msg: OUT - Data + * @midx: Message register index * * Read data from the specified message register and source register. * - * Return: zero on success, negative error if invalid argument passed. + * Return: inbound message register value. */ -static int idt_ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg) +static u32 idt_ntb_msg_read(struct ntb_dev *ntb, int *pidx, int midx) { struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); if (midx < 0 || IDT_MSG_CNT <= midx) - return -EINVAL; + return ~(u32)0; /* Retrieve source port index of the message */ if (pidx != NULL) { @@ -1772,18 +1771,15 @@ static int idt_ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg) } /* Retrieve data of the corresponding message register */ - if (msg != NULL) - *msg = idt_nt_read(ndev, ntdata_tbl.msgs[midx].in); - - return 0; + return idt_nt_read(ndev, ntdata_tbl.msgs[midx].in); } /* - * idt_ntb_msg_write() - write data to the specified message register - * (NTB API callback) + * idt_ntb_peer_msg_write() - write data to the specified message register + * (NTB API callback) * @ntb: NTB device context. - * @midx: Message register index * @pidx: Port index of peer device a message being sent to + * @midx: Message register index * @msg: Data to send * * Just try to send data to a peer. Message status register should be @@ -1791,7 +1787,8 @@ static int idt_ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg) * * Return: zero on success, negative error if invalid argument passed. */ -static int idt_ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx, u32 msg) +static int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx, + u32 msg) { struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); unsigned long irqflags; @@ -2058,7 +2055,7 @@ static const struct ntb_dev_ops idt_ntb_ops = { .msg_set_mask = idt_ntb_msg_set_mask, .msg_clear_mask = idt_ntb_msg_clear_mask, .msg_read = idt_ntb_msg_read, - .msg_write = idt_ntb_msg_write + .peer_msg_write = idt_ntb_peer_msg_write }; /* @@ -2073,7 +2070,7 @@ static int idt_register_device(struct idt_ntb_dev *ndev) /* Initialize the rest of NTB device structure and register it */ ndev->ntb.ops = &idt_ntb_ops; - ndev->ntb.topo = NTB_TOPO_PRI; + ndev->ntb.topo = NTB_TOPO_SWITCH; ret = ntb_register_device(&ndev->ntb); if (ret != 0) { @@ -2269,7 +2266,7 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf, "Message data:\n"); for (idx = 0; idx < IDT_MSG_CNT; idx++) { int src; - (void)idt_ntb_msg_read(&ndev->ntb, idx, &src, &data); + data = idt_ntb_msg_read(&ndev->ntb, &src, idx); off += scnprintf(strbuf + off, size - off, "\t%hhu. 0x%08x from peer %hhu (Port %hhu)\n", idx, data, src, ndev->peers[src].port); @@ -2429,7 +2426,7 @@ static int idt_init_pci(struct idt_ntb_dev *ndev) struct pci_dev *pdev = ndev->ntb.pdev; int ret; - /* Initialize the bit mask of DMA */ + /* Initialize the bit mask of PCI/NTB DMA */ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (ret != 0) { ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); @@ -2450,6 +2447,12 @@ static int idt_init_pci(struct idt_ntb_dev *ndev) dev_warn(&pdev->dev, "Cannot set consistent DMA highmem bit mask\n"); } + ret = dma_coerce_mask_and_coherent(&ndev->ntb.dev, + dma_get_mask(&pdev->dev)); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to set NTB device DMA bit mask\n"); + return ret; + } /* * Enable the device advanced error reporting. It's not critical to diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 4de074a86073..156b45cd4a19 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -74,12 +74,6 @@ MODULE_AUTHOR("Intel Corporation"); #define bar0_off(base, bar) ((base) + ((bar) << 2)) #define bar2_off(base, bar) bar0_off(base, (bar) - 2) -static const struct intel_ntb_reg atom_reg; -static const struct intel_ntb_alt_reg atom_pri_reg; -static const struct intel_ntb_alt_reg atom_sec_reg; -static const struct intel_ntb_alt_reg atom_b2b_reg; -static const struct intel_ntb_xlat_reg atom_pri_xlat; -static const struct intel_ntb_xlat_reg atom_sec_xlat; static const struct intel_ntb_reg xeon_reg; static const struct intel_ntb_alt_reg xeon_pri_reg; static const struct intel_ntb_alt_reg xeon_sec_reg; @@ -184,15 +178,6 @@ static inline void _iowrite64(u64 val, void __iomem *mmio) #endif #endif -static inline int pdev_is_atom(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: - return 1; - } - return 0; -} - static inline int pdev_is_xeon(struct pci_dev *pdev) { switch (pdev->device) { @@ -1006,8 +991,7 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, { struct intel_ntb_dev *ndev = filp->private_data; - if (pdev_is_xeon(ndev->ntb.pdev) || - pdev_is_atom(ndev->ntb.pdev)) + if (pdev_is_xeon(ndev->ntb.pdev)) return ndev_ntb_debugfs_read(filp, ubuf, count, offp); else if (pdev_is_skx_xeon(ndev->ntb.pdev)) return ndev_ntb3_debugfs_read(filp, ubuf, count, offp); @@ -1439,242 +1423,6 @@ static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, ndev->peer_reg->spad); } -/* ATOM */ - -static u64 atom_db_ioread(void __iomem *mmio) -{ - return ioread64(mmio); -} - -static void atom_db_iowrite(u64 bits, void __iomem *mmio) -{ - iowrite64(bits, mmio); -} - -static int atom_poll_link(struct intel_ntb_dev *ndev) -{ - u32 ntb_ctl; - - ntb_ctl = ioread32(ndev->self_mmio + ATOM_NTBCNTL_OFFSET); - - if (ntb_ctl == ndev->ntb_ctl) - return 0; - - ndev->ntb_ctl = ntb_ctl; - - ndev->lnk_sta = ioread32(ndev->self_mmio + ATOM_LINK_STATUS_OFFSET); - - return 1; -} - -static int atom_link_is_up(struct intel_ntb_dev *ndev) -{ - return ATOM_NTB_CTL_ACTIVE(ndev->ntb_ctl); -} - -static int atom_link_is_err(struct intel_ntb_dev *ndev) -{ - if (ioread32(ndev->self_mmio + ATOM_LTSSMSTATEJMP_OFFSET) - & ATOM_LTSSMSTATEJMP_FORCEDETECT) - return 1; - - if (ioread32(ndev->self_mmio + ATOM_IBSTERRRCRVSTS0_OFFSET) - & ATOM_IBIST_ERR_OFLOW) - return 1; - - return 0; -} - -static inline enum ntb_topo atom_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) -{ - struct device *dev = &ndev->ntb.pdev->dev; - - switch (ppd & ATOM_PPD_TOPO_MASK) { - case ATOM_PPD_TOPO_B2B_USD: - dev_dbg(dev, "PPD %d B2B USD\n", ppd); - return NTB_TOPO_B2B_USD; - - case ATOM_PPD_TOPO_B2B_DSD: - dev_dbg(dev, "PPD %d B2B DSD\n", ppd); - return NTB_TOPO_B2B_DSD; - - case ATOM_PPD_TOPO_PRI_USD: - case ATOM_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ - case ATOM_PPD_TOPO_SEC_USD: - case ATOM_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ - dev_dbg(dev, "PPD %d non B2B disabled\n", ppd); - return NTB_TOPO_NONE; - } - - dev_dbg(dev, "PPD %d invalid\n", ppd); - return NTB_TOPO_NONE; -} - -static void atom_link_hb(struct work_struct *work) -{ - struct intel_ntb_dev *ndev = hb_ndev(work); - struct device *dev = &ndev->ntb.pdev->dev; - unsigned long poll_ts; - void __iomem *mmio; - u32 status32; - - poll_ts = ndev->last_ts + ATOM_LINK_HB_TIMEOUT; - - /* Delay polling the link status if an interrupt was received, - * unless the cached link status says the link is down. - */ - if (time_after(poll_ts, jiffies) && atom_link_is_up(ndev)) { - schedule_delayed_work(&ndev->hb_timer, poll_ts - jiffies); - return; - } - - if (atom_poll_link(ndev)) - ntb_link_event(&ndev->ntb); - - if (atom_link_is_up(ndev) || !atom_link_is_err(ndev)) { - schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_HB_TIMEOUT); - return; - } - - /* Link is down with error: recover the link! */ - - mmio = ndev->self_mmio; - - /* Driver resets the NTB ModPhy lanes - magic! */ - iowrite8(0xe0, mmio + ATOM_MODPHY_PCSREG6); - iowrite8(0x40, mmio + ATOM_MODPHY_PCSREG4); - iowrite8(0x60, mmio + ATOM_MODPHY_PCSREG4); - iowrite8(0x60, mmio + ATOM_MODPHY_PCSREG6); - - /* Driver waits 100ms to allow the NTB ModPhy to settle */ - msleep(100); - - /* Clear AER Errors, write to clear */ - status32 = ioread32(mmio + ATOM_ERRCORSTS_OFFSET); - dev_dbg(dev, "ERRCORSTS = %x\n", status32); - status32 &= PCI_ERR_COR_REP_ROLL; - iowrite32(status32, mmio + ATOM_ERRCORSTS_OFFSET); - - /* Clear unexpected electrical idle event in LTSSM, write to clear */ - status32 = ioread32(mmio + ATOM_LTSSMERRSTS0_OFFSET); - dev_dbg(dev, "LTSSMERRSTS0 = %x\n", status32); - status32 |= ATOM_LTSSMERRSTS0_UNEXPECTEDEI; - iowrite32(status32, mmio + ATOM_LTSSMERRSTS0_OFFSET); - - /* Clear DeSkew Buffer error, write to clear */ - status32 = ioread32(mmio + ATOM_DESKEWSTS_OFFSET); - dev_dbg(dev, "DESKEWSTS = %x\n", status32); - status32 |= ATOM_DESKEWSTS_DBERR; - iowrite32(status32, mmio + ATOM_DESKEWSTS_OFFSET); - - status32 = ioread32(mmio + ATOM_IBSTERRRCRVSTS0_OFFSET); - dev_dbg(dev, "IBSTERRRCRVSTS0 = %x\n", status32); - status32 &= ATOM_IBIST_ERR_OFLOW; - iowrite32(status32, mmio + ATOM_IBSTERRRCRVSTS0_OFFSET); - - /* Releases the NTB state machine to allow the link to retrain */ - status32 = ioread32(mmio + ATOM_LTSSMSTATEJMP_OFFSET); - dev_dbg(dev, "LTSSMSTATEJMP = %x\n", status32); - status32 &= ~ATOM_LTSSMSTATEJMP_FORCEDETECT; - iowrite32(status32, mmio + ATOM_LTSSMSTATEJMP_OFFSET); - - /* There is a potential race between the 2 NTB devices recovering at the - * same time. If the times are the same, the link will not recover and - * the driver will be stuck in this loop forever. Add a random interval - * to the recovery time to prevent this race. - */ - schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_RECOVERY_TIME - + prandom_u32() % ATOM_LINK_RECOVERY_TIME); -} - -static int atom_init_isr(struct intel_ntb_dev *ndev) -{ - int rc; - - rc = ndev_init_isr(ndev, 1, ATOM_DB_MSIX_VECTOR_COUNT, - ATOM_DB_MSIX_VECTOR_SHIFT, ATOM_DB_TOTAL_SHIFT); - if (rc) - return rc; - - /* ATOM doesn't have link status interrupt, poll on that platform */ - ndev->last_ts = jiffies; - INIT_DELAYED_WORK(&ndev->hb_timer, atom_link_hb); - schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_HB_TIMEOUT); - - return 0; -} - -static void atom_deinit_isr(struct intel_ntb_dev *ndev) -{ - cancel_delayed_work_sync(&ndev->hb_timer); - ndev_deinit_isr(ndev); -} - -static int atom_init_ntb(struct intel_ntb_dev *ndev) -{ - ndev->mw_count = ATOM_MW_COUNT; - ndev->spad_count = ATOM_SPAD_COUNT; - ndev->db_count = ATOM_DB_COUNT; - - switch (ndev->ntb.topo) { - case NTB_TOPO_B2B_USD: - case NTB_TOPO_B2B_DSD: - ndev->self_reg = &atom_pri_reg; - ndev->peer_reg = &atom_b2b_reg; - ndev->xlat_reg = &atom_sec_xlat; - - /* Enable Bus Master and Memory Space on the secondary side */ - iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->self_mmio + ATOM_SPCICMD_OFFSET); - - break; - - default: - return -EINVAL; - } - - ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; - - return 0; -} - -static int atom_init_dev(struct intel_ntb_dev *ndev) -{ - u32 ppd; - int rc; - - rc = pci_read_config_dword(ndev->ntb.pdev, ATOM_PPD_OFFSET, &ppd); - if (rc) - return -EIO; - - ndev->ntb.topo = atom_ppd_topo(ndev, ppd); - if (ndev->ntb.topo == NTB_TOPO_NONE) - return -EINVAL; - - rc = atom_init_ntb(ndev); - if (rc) - return rc; - - rc = atom_init_isr(ndev); - if (rc) - return rc; - - if (ndev->ntb.topo != NTB_TOPO_SEC) { - /* Initiate PCI-E link training */ - rc = pci_write_config_dword(ndev->ntb.pdev, ATOM_PPD_OFFSET, - ppd | ATOM_PPD_INIT_LINK); - if (rc) - return rc; - } - - return 0; -} - -static void atom_deinit_dev(struct intel_ntb_dev *ndev) -{ - atom_deinit_isr(ndev); -} - /* Skylake Xeon NTB */ static int skx_poll_link(struct intel_ntb_dev *ndev) @@ -2586,6 +2334,10 @@ static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev) goto err_dma_mask; dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); } + rc = dma_coerce_mask_and_coherent(&ndev->ntb.dev, + dma_get_mask(&pdev->dev)); + if (rc) + goto err_dma_mask; ndev->self_mmio = pci_iomap(pdev, 0, 0); if (!ndev->self_mmio) { @@ -2658,24 +2410,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, node = dev_to_node(&pdev->dev); - if (pdev_is_atom(pdev)) { - ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); - if (!ndev) { - rc = -ENOMEM; - goto err_ndev; - } - - ndev_init_struct(ndev, pdev); - - rc = intel_ntb_init_pci(ndev, pdev); - if (rc) - goto err_init_pci; - - rc = atom_init_dev(ndev); - if (rc) - goto err_init_dev; - - } else if (pdev_is_xeon(pdev)) { + if (pdev_is_xeon(pdev)) { ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; @@ -2731,9 +2466,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, err_register: ndev_deinit_debugfs(ndev); - if (pdev_is_atom(pdev)) - atom_deinit_dev(ndev); - else if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) + if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) xeon_deinit_dev(ndev); err_init_dev: intel_ntb_deinit_pci(ndev); @@ -2749,41 +2482,12 @@ static void intel_ntb_pci_remove(struct pci_dev *pdev) ntb_unregister_device(&ndev->ntb); ndev_deinit_debugfs(ndev); - if (pdev_is_atom(pdev)) - atom_deinit_dev(ndev); - else if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) + if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) xeon_deinit_dev(ndev); intel_ntb_deinit_pci(ndev); kfree(ndev); } -static const struct intel_ntb_reg atom_reg = { - .poll_link = atom_poll_link, - .link_is_up = atom_link_is_up, - .db_ioread = atom_db_ioread, - .db_iowrite = atom_db_iowrite, - .db_size = sizeof(u64), - .ntb_ctl = ATOM_NTBCNTL_OFFSET, - .mw_bar = {2, 4}, -}; - -static const struct intel_ntb_alt_reg atom_pri_reg = { - .db_bell = ATOM_PDOORBELL_OFFSET, - .db_mask = ATOM_PDBMSK_OFFSET, - .spad = ATOM_SPAD_OFFSET, -}; - -static const struct intel_ntb_alt_reg atom_b2b_reg = { - .db_bell = ATOM_B2B_DOORBELL_OFFSET, - .spad = ATOM_B2B_SPAD_OFFSET, -}; - -static const struct intel_ntb_xlat_reg atom_sec_xlat = { - /* FIXME : .bar0_base = ATOM_SBAR0BASE_OFFSET, */ - /* FIXME : .bar2_limit = ATOM_SBAR2LMT_OFFSET, */ - .bar2_xlat = ATOM_SBAR2XLAT_OFFSET, -}; - static const struct intel_ntb_reg xeon_reg = { .poll_link = xeon_poll_link, .link_is_up = xeon_link_is_up, @@ -2940,7 +2644,6 @@ static const struct file_operations intel_ntb_debugfs_info = { }; static const struct pci_device_id intel_ntb_pci_tbl[] = { - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 2d6c38afb128..4415aa7ea775 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -66,7 +66,6 @@ #define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D #define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E #define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E #define PCI_DEVICE_ID_INTEL_NTB_B2B_BDX 0x6F0D #define PCI_DEVICE_ID_INTEL_NTB_PS_BDX 0x6F0E #define PCI_DEVICE_ID_INTEL_NTB_SS_BDX 0x6F0F @@ -196,63 +195,6 @@ #define SKX_DB_TOTAL_SHIFT 33 #define SKX_SPAD_COUNT 16 -/* Intel Atom hardware */ - -#define ATOM_SBAR2XLAT_OFFSET 0x0008 -#define ATOM_PDOORBELL_OFFSET 0x0020 -#define ATOM_PDBMSK_OFFSET 0x0028 -#define ATOM_NTBCNTL_OFFSET 0x0060 -#define ATOM_SPAD_OFFSET 0x0080 -#define ATOM_PPD_OFFSET 0x00d4 -#define ATOM_PBAR2XLAT_OFFSET 0x8008 -#define ATOM_B2B_DOORBELL_OFFSET 0x8020 -#define ATOM_B2B_SPAD_OFFSET 0x8080 -#define ATOM_SPCICMD_OFFSET 0xb004 -#define ATOM_LINK_STATUS_OFFSET 0xb052 -#define ATOM_ERRCORSTS_OFFSET 0xb110 -#define ATOM_IP_BASE 0xc000 -#define ATOM_DESKEWSTS_OFFSET (ATOM_IP_BASE + 0x3024) -#define ATOM_LTSSMERRSTS0_OFFSET (ATOM_IP_BASE + 0x3180) -#define ATOM_LTSSMSTATEJMP_OFFSET (ATOM_IP_BASE + 0x3040) -#define ATOM_IBSTERRRCRVSTS0_OFFSET (ATOM_IP_BASE + 0x3324) -#define ATOM_MODPHY_PCSREG4 0x1c004 -#define ATOM_MODPHY_PCSREG6 0x1c006 - -#define ATOM_PPD_INIT_LINK 0x0008 -#define ATOM_PPD_CONN_MASK 0x0300 -#define ATOM_PPD_CONN_TRANSPARENT 0x0000 -#define ATOM_PPD_CONN_B2B 0x0100 -#define ATOM_PPD_CONN_RP 0x0200 -#define ATOM_PPD_DEV_MASK 0x1000 -#define ATOM_PPD_DEV_USD 0x0000 -#define ATOM_PPD_DEV_DSD 0x1000 -#define ATOM_PPD_TOPO_MASK (ATOM_PPD_CONN_MASK | ATOM_PPD_DEV_MASK) -#define ATOM_PPD_TOPO_PRI_USD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_USD) -#define ATOM_PPD_TOPO_PRI_DSD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_DSD) -#define ATOM_PPD_TOPO_SEC_USD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_USD) -#define ATOM_PPD_TOPO_SEC_DSD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_DSD) -#define ATOM_PPD_TOPO_B2B_USD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_USD) -#define ATOM_PPD_TOPO_B2B_DSD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_DSD) - -#define ATOM_MW_COUNT 2 -#define ATOM_DB_COUNT 34 -#define ATOM_DB_VALID_MASK (BIT_ULL(ATOM_DB_COUNT) - 1) -#define ATOM_DB_MSIX_VECTOR_COUNT 34 -#define ATOM_DB_MSIX_VECTOR_SHIFT 1 -#define ATOM_DB_TOTAL_SHIFT 34 -#define ATOM_SPAD_COUNT 16 - -#define ATOM_NTB_CTL_DOWN_BIT BIT(16) -#define ATOM_NTB_CTL_ACTIVE(x) !(x & ATOM_NTB_CTL_DOWN_BIT) - -#define ATOM_DESKEWSTS_DBERR BIT(15) -#define ATOM_LTSSMERRSTS0_UNEXPECTEDEI BIT(20) -#define ATOM_LTSSMSTATEJMP_FORCEDETECT BIT(2) -#define ATOM_IBIST_ERR_OFLOW 0x7FFF7FFF - -#define ATOM_LINK_HB_TIMEOUT msecs_to_jiffies(1000) -#define ATOM_LINK_RECOVERY_TIME msecs_to_jiffies(500) - /* Ntb control and link status */ #define NTB_CTL_CFG_LOCK BIT(0) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index afe8ed6f3b23..f624ae27eabe 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -94,6 +94,9 @@ struct switchtec_ntb { struct ntb_ctrl_regs __iomem *mmio_self_ctrl; struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; + struct ntb_dbmsg_regs __iomem *mmio_peer_dbmsg; + + void __iomem *mmio_xlink_win; struct shared_mw *self_shared; struct shared_mw __iomem *peer_shared; @@ -109,6 +112,7 @@ struct switchtec_ntb { int nr_direct_mw; int nr_lut_mw; + int nr_rsvd_luts; int direct_mw_to_bar[MAX_DIRECT_MW]; int peer_nr_direct_mw; @@ -118,6 +122,7 @@ struct switchtec_ntb { bool link_is_up; enum ntb_speed link_speed; enum ntb_width link_width; + struct work_struct link_reinit_work; }; static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) @@ -172,7 +177,7 @@ static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, if (ps == status) { dev_err(&sndev->stdev->dev, - "Timed out while peforming %s (%d). (%08x)", + "Timed out while performing %s (%d). (%08x)\n", op_text[op], op, ioread32(&ctl->partition_status)); @@ -185,10 +190,10 @@ static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, u32 val) { - if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg)) + if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_peer_dbmsg->omsg)) return -EINVAL; - iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg); + iowrite32(val, &sndev->mmio_peer_dbmsg->omsg[idx].msg); return 0; } @@ -197,7 +202,7 @@ static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) { struct switchtec_ntb *sndev = ntb_sndev(ntb); int nr_direct_mw = sndev->peer_nr_direct_mw; - int nr_lut_mw = sndev->peer_nr_lut_mw - 1; + int nr_lut_mw = sndev->peer_nr_lut_mw - sndev->nr_rsvd_luts; if (pidx != NTB_DEF_PEER_IDX) return -EINVAL; @@ -210,12 +215,12 @@ static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) static int lut_index(struct switchtec_ntb *sndev, int mw_idx) { - return mw_idx - sndev->nr_direct_mw + 1; + return mw_idx - sndev->nr_direct_mw + sndev->nr_rsvd_luts; } static int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx) { - return mw_idx - sndev->peer_nr_direct_mw + 1; + return mw_idx - sndev->peer_nr_direct_mw + sndev->nr_rsvd_luts; } static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, @@ -306,7 +311,7 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, if (pidx != NTB_DEF_PEER_IDX) return -EINVAL; - dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap", + dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap\n", widx, pidx, &addr, &size); if (widx >= switchtec_ntb_mw_count(ntb, pidx)) @@ -315,6 +320,19 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, if (xlate_pos < 12) return -EINVAL; + if (!IS_ALIGNED(addr, BIT_ULL(xlate_pos))) { + /* + * In certain circumstances we can get a buffer that is + * not aligned to its size. (Most of the time + * dma_alloc_coherent ensures this). This can happen when + * using large buffers allocated by the CMA + * (see CMA_CONFIG_ALIGNMENT) + */ + dev_err(&sndev->stdev->dev, + "ERROR: Memory window address is not aligned to it's size!\n"); + return -EINVAL; + } + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, NTB_CTRL_PART_STATUS_LOCKED); if (rc) @@ -337,7 +355,7 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, if (rc == -EIO) { dev_err(&sndev->stdev->dev, - "Hardware reported an error configuring mw %d: %08x", + "Hardware reported an error configuring mw %d: %08x\n", widx, ioread32(&ctl->bar_error)); if (widx < nr_direct_mw) @@ -355,8 +373,9 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) { struct switchtec_ntb *sndev = ntb_sndev(ntb); + int nr_lut_mw = sndev->nr_lut_mw - sndev->nr_rsvd_luts; - return sndev->nr_direct_mw + (use_lut_mws ? sndev->nr_lut_mw - 1 : 0); + return sndev->nr_direct_mw + (use_lut_mws ? nr_lut_mw : 0); } static int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev, @@ -463,18 +482,69 @@ static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev) sndev->link_width = min(self_width, peer_width); } -enum { +static int crosslink_is_enabled(struct switchtec_ntb *sndev) +{ + struct ntb_info_regs __iomem *inf = sndev->mmio_ntb; + + return ioread8(&inf->ntp_info[sndev->peer_partition].xlink_enabled); +} + +static void crosslink_init_dbmsgs(struct switchtec_ntb *sndev) +{ + int i; + u32 msg_map = 0; + + if (!crosslink_is_enabled(sndev)) + return; + + for (i = 0; i < ARRAY_SIZE(sndev->mmio_peer_dbmsg->imsg); i++) { + int m = i | sndev->self_partition << 2; + + msg_map |= m << i * 8; + } + + iowrite32(msg_map, &sndev->mmio_peer_dbmsg->msg_map); + iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, + &sndev->mmio_peer_dbmsg->odb_mask); +} + +enum switchtec_msg { LINK_MESSAGE = 0, MSG_LINK_UP = 1, MSG_LINK_DOWN = 2, MSG_CHECK_LINK = 3, + MSG_LINK_FORCE_DOWN = 4, }; -static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) +static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); + +static void link_reinit_work(struct work_struct *work) +{ + struct switchtec_ntb *sndev; + + sndev = container_of(work, struct switchtec_ntb, link_reinit_work); + + switchtec_ntb_reinit_peer(sndev); +} + +static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, + enum switchtec_msg msg) { int link_sta; int old = sndev->link_is_up; + if (msg == MSG_LINK_FORCE_DOWN) { + schedule_work(&sndev->link_reinit_work); + + if (sndev->link_is_up) { + sndev->link_is_up = 0; + ntb_link_event(&sndev->ntb); + dev_info(&sndev->stdev->dev, "ntb link forced down\n"); + } + + return; + } + link_sta = sndev->self_shared->link_sta; if (link_sta) { u64 peer = ioread64(&sndev->peer_shared->magic); @@ -491,8 +561,11 @@ static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) if (link_sta != old) { switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK); ntb_link_event(&sndev->ntb); - dev_info(&sndev->stdev->dev, "ntb link %s", + dev_info(&sndev->stdev->dev, "ntb link %s\n", link_sta ? "up" : "down"); + + if (link_sta) + crosslink_init_dbmsgs(sndev); } } @@ -500,7 +573,7 @@ static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) { struct switchtec_ntb *sndev = stdev->sndev; - switchtec_ntb_check_link(sndev); + switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); } static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, @@ -523,12 +596,12 @@ static int switchtec_ntb_link_enable(struct ntb_dev *ntb, { struct switchtec_ntb *sndev = ntb_sndev(ntb); - dev_dbg(&sndev->stdev->dev, "enabling link"); + dev_dbg(&sndev->stdev->dev, "enabling link\n"); sndev->self_shared->link_sta = 1; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); - switchtec_ntb_check_link(sndev); + switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); return 0; } @@ -537,12 +610,12 @@ static int switchtec_ntb_link_disable(struct ntb_dev *ntb) { struct switchtec_ntb *sndev = ntb_sndev(ntb); - dev_dbg(&sndev->stdev->dev, "disabling link"); + dev_dbg(&sndev->stdev->dev, "disabling link\n"); sndev->self_shared->link_sta = 0; - switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); + switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); - switchtec_ntb_check_link(sndev); + switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); return 0; } @@ -638,7 +711,7 @@ static int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb, struct switchtec_ntb *sndev = ntb_sndev(ntb); unsigned long offset; - offset = (unsigned long)sndev->mmio_self_dbmsg->odb - + offset = (unsigned long)sndev->mmio_peer_dbmsg->odb - (unsigned long)sndev->stdev->mmio; offset += sndev->db_shift / 8; @@ -656,7 +729,7 @@ static int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) struct switchtec_ntb *sndev = ntb_sndev(ntb); iowrite64(db_bits << sndev->db_peer_shift, - &sndev->mmio_self_dbmsg->odb); + &sndev->mmio_peer_dbmsg->odb); return 0; } @@ -777,24 +850,63 @@ static const struct ntb_dev_ops switchtec_ntb_ops = { .peer_spad_addr = switchtec_ntb_peer_spad_addr, }; -static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) +static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) { + u64 tpart_vec; + int self; u64 part_map; + int bit; sndev->ntb.pdev = sndev->stdev->pdev; sndev->ntb.topo = NTB_TOPO_SWITCH; sndev->ntb.ops = &switchtec_ntb_ops; + INIT_WORK(&sndev->link_reinit_work, link_reinit_work); + sndev->self_partition = sndev->stdev->partition; sndev->mmio_ntb = sndev->stdev->mmio_ntb; + + self = sndev->self_partition; + tpart_vec = ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_high); + tpart_vec <<= 32; + tpart_vec |= ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_low); + part_map = ioread64(&sndev->mmio_ntb->ep_map); part_map &= ~(1 << sndev->self_partition); - sndev->peer_partition = ffs(part_map) - 1; - dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)", - sndev->self_partition, sndev->stdev->partition_count, - part_map); + if (!ffs(tpart_vec)) { + if (sndev->stdev->partition_count != 2) { + dev_err(&sndev->stdev->dev, + "ntb target partition not defined\n"); + return -ENODEV; + } + + bit = ffs(part_map); + if (!bit) { + dev_err(&sndev->stdev->dev, + "peer partition is not NT partition\n"); + return -ENODEV; + } + + sndev->peer_partition = bit - 1; + } else { + if (ffs(tpart_vec) != fls(tpart_vec)) { + dev_err(&sndev->stdev->dev, + "ntb driver only supports 1 pair of 1-1 ntb mapping\n"); + return -ENODEV; + } + + sndev->peer_partition = ffs(tpart_vec) - 1; + if (!(part_map & (1 << sndev->peer_partition))) { + dev_err(&sndev->stdev->dev, + "ntb target partition is not NT partition\n"); + return -ENODEV; + } + } + + dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d\n", + sndev->self_partition, sndev->stdev->partition_count); sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb + SWITCHTEC_NTB_REG_CTRL_OFFSET; @@ -804,6 +916,283 @@ static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; + sndev->mmio_peer_dbmsg = sndev->mmio_self_dbmsg; + + return 0; +} + +static int config_rsvd_lut_win(struct switchtec_ntb *sndev, + struct ntb_ctrl_regs __iomem *ctl, + int lut_idx, int partition, u64 addr) +{ + int peer_bar = sndev->peer_direct_mw_to_bar[0]; + u32 ctl_val; + int rc; + + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, + NTB_CTRL_PART_STATUS_LOCKED); + if (rc) + return rc; + + ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl); + ctl_val &= 0xFF; + ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; + ctl_val |= ilog2(LUT_SIZE) << 8; + ctl_val |= (sndev->nr_lut_mw - 1) << 14; + iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl); + + iowrite64((NTB_CTRL_LUT_EN | (partition << 1) | addr), + &ctl->lut_entry[lut_idx]); + + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, + NTB_CTRL_PART_STATUS_NORMAL); + if (rc) { + u32 bar_error, lut_error; + + bar_error = ioread32(&ctl->bar_error); + lut_error = ioread32(&ctl->lut_error); + dev_err(&sndev->stdev->dev, + "Error setting up reserved lut window: %08x / %08x\n", + |