diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-21 10:20:32 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-21 10:20:32 -0800 |
| commit | 981361604566a28517a518c317943d9b7c392217 (patch) | |
| tree | 7e3836f811aff8b3dba09914f2142f89412d628c | |
| parent | f9d66e64a2bcb979d47eb7d67aa7e9b454fd5d15 (diff) | |
| parent | 8c1f92ca8bca3ce2d2c085571af89503bc7bc7c4 (diff) | |
Merge tag 'ntb-7.0' of https://github.com/jonmason/ntb
Pull NTB (PCIe non-transparent bridge) updates from Jon Mason:
"NTB updates include debugfs improvements, correctness fixes, cleanups,
and new hardware support:
ntb_transport QP stats are converted to seq_file, a tx_memcpy_offload
module parameter is introduced with associated ordering fixes, and a
debugfs queue name truncation bug is corrected.
Additional fixes address format specifier mismatches in ntb_tool and
boundary conditions in the Switchtec driver, while unused MSI helpers
are removed and the codebase migrates to dma_map_phys().
Intel Gen6 (Diamond Rapids) NTB support is also added"
* tag 'ntb-7.0' of https://github.com/jonmason/ntb:
NTB: ntb_transport: Use seq_file for QP stats debugfs
NTB: ntb_transport: Fix too small buffer for debugfs_name
ntb/ntb_tool: correct sscanf format for u64 and size_t in tool_peer_mw_trans_write
ntb: intel: Add Intel Gen6 NTB support for DiamondRapids
NTB/msi: Remove unused functions
ntb: ntb_hw_switchtec: Increase MAX_MWS limit to 256
ntb: ntb_hw_switchtec: Fix array-index-out-of-bounds access
ntb: ntb_hw_switchtec: Fix shift-out-of-bounds for 0 mw lut
NTB: epf: allow built-in build
ntb: migrate to dma_map_phys instead of map_page
NTB: ntb_transport: Add 'tx_memcpy_offload' module option
NTB: ntb_transport: Remove unused 'retries' field from ntb_queue_entry
| -rw-r--r-- | drivers/ntb/hw/epf/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/ntb/hw/intel/ntb_hw_gen1.c | 14 | ||||
| -rw-r--r-- | drivers/ntb/hw/intel/ntb_hw_gen4.c | 22 | ||||
| -rw-r--r-- | drivers/ntb/hw/intel/ntb_hw_gen4.h | 2 | ||||
| -rw-r--r-- | drivers/ntb/hw/intel/ntb_hw_intel.h | 6 | ||||
| -rw-r--r-- | drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 14 | ||||
| -rw-r--r-- | drivers/ntb/msi.c | 64 | ||||
| -rw-r--r-- | drivers/ntb/ntb_transport.c | 263 | ||||
| -rw-r--r-- | drivers/ntb/test/ntb_tool.c | 2 | ||||
| -rw-r--r-- | include/linux/ntb.h | 14 |
10 files changed, 196 insertions, 206 deletions
diff --git a/drivers/ntb/hw/epf/Kconfig b/drivers/ntb/hw/epf/Kconfig index 6197d1aab344..314485574bf8 100644 --- a/drivers/ntb/hw/epf/Kconfig +++ b/drivers/ntb/hw/epf/Kconfig @@ -1,6 +1,5 @@ config NTB_EPF tristate "Generic EPF Non-Transparent Bridge support" - depends on m help This driver supports EPF NTB on configurable endpoint. If unsure, say N. diff --git a/drivers/ntb/hw/intel/ntb_hw_gen1.c b/drivers/ntb/hw/intel/ntb_hw_gen1.c index 079b8cd79785..944d10b48ae4 100644 --- a/drivers/ntb/hw/intel/ntb_hw_gen1.c +++ b/drivers/ntb/hw/intel/ntb_hw_gen1.c @@ -763,7 +763,8 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, return ndev_ntb_debugfs_read(filp, ubuf, count, offp); else if (pdev_is_gen3(ndev->ntb.pdev)) return ndev_ntb3_debugfs_read(filp, ubuf, count, offp); - else if (pdev_is_gen4(ndev->ntb.pdev) || pdev_is_gen5(ndev->ntb.pdev)) + else if (pdev_is_gen4(ndev->ntb.pdev) || pdev_is_gen5(ndev->ntb.pdev) || + pdev_is_gen6(ndev->ntb.pdev)) return ndev_ntb4_debugfs_read(filp, ubuf, count, offp); return -ENXIO; @@ -1872,7 +1873,8 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, rc = gen3_init_dev(ndev); if (rc) goto err_init_dev; - } else if (pdev_is_gen4(pdev) || pdev_is_gen5(pdev)) { + } else if (pdev_is_gen4(pdev) || pdev_is_gen5(pdev) || + pdev_is_gen6(pdev)) { ndev->ntb.ops = &intel_ntb4_ops; rc = intel_ntb_init_pci(ndev, pdev); if (rc) @@ -1903,7 +1905,8 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, err_register: ndev_deinit_debugfs(ndev); if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev) || - pdev_is_gen4(pdev) || pdev_is_gen5(pdev)) + pdev_is_gen4(pdev) || pdev_is_gen5(pdev) || + pdev_is_gen6(pdev)) xeon_deinit_dev(ndev); err_init_dev: intel_ntb_deinit_pci(ndev); @@ -1920,7 +1923,8 @@ static void intel_ntb_pci_remove(struct pci_dev *pdev) ntb_unregister_device(&ndev->ntb); ndev_deinit_debugfs(ndev); if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev) || - pdev_is_gen4(pdev) || pdev_is_gen5(pdev)) + pdev_is_gen4(pdev) || pdev_is_gen5(pdev) || + pdev_is_gen6(pdev)) xeon_deinit_dev(ndev); intel_ntb_deinit_pci(ndev); kfree(ndev); @@ -2049,6 +2053,8 @@ static const struct pci_device_id intel_ntb_pci_tbl[] = { {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_ICX)}, /* GEN5 PCIe */ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_GNR)}, + /* GEN6 PCIe */ + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_DMR)}, {0} }; MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl); diff --git a/drivers/ntb/hw/intel/ntb_hw_gen4.c b/drivers/ntb/hw/intel/ntb_hw_gen4.c index 22cac7975b3c..a221a978a9d5 100644 --- a/drivers/ntb/hw/intel/ntb_hw_gen4.c +++ b/drivers/ntb/hw/intel/ntb_hw_gen4.c @@ -46,6 +46,16 @@ static const struct intel_ntb_alt_reg gen4_b2b_reg = { .spad = GEN4_EM_SPAD_OFFSET, }; +static u64 get_ppd0(struct pci_dev *pdev) +{ + if (pdev_is_gen4(pdev) || pdev_is_gen5(pdev)) + return GEN4_PPD0_OFFSET; + else if (pdev_is_gen6(pdev)) + return GEN6_PPD0_OFFSET; + + return ULLONG_MAX; +} + static int gen4_poll_link(struct intel_ntb_dev *ndev) { u16 reg_val; @@ -183,7 +193,7 @@ static enum ntb_topo spr_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) int gen4_init_dev(struct intel_ntb_dev *ndev) { struct pci_dev *pdev = ndev->ntb.pdev; - u32 ppd1/*, ppd0*/; + u32 ppd1; u16 lnkctl; int rc; @@ -197,7 +207,7 @@ int gen4_init_dev(struct intel_ntb_dev *ndev) ppd1 = ioread32(ndev->self_mmio + GEN4_PPD1_OFFSET); if (pdev_is_ICX(pdev)) ndev->ntb.topo = gen4_ppd_topo(ndev, ppd1); - else if (pdev_is_SPR(pdev) || pdev_is_gen5(pdev)) + else if (pdev_is_SPR(pdev) || pdev_is_gen5(pdev) || pdev_is_gen6(pdev)) ndev->ntb.topo = spr_ppd_topo(ndev, ppd1); dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd1, ntb_topo_string(ndev->ntb.topo)); @@ -432,10 +442,12 @@ static int intel_ntb4_link_enable(struct ntb_dev *ntb, enum ntb_speed max_speed, enum ntb_width max_width) { struct intel_ntb_dev *ndev; + struct pci_dev *pdev; u32 ntb_ctl, ppd0; u16 lnkctl; ndev = container_of(ntb, struct intel_ntb_dev, ntb); + pdev = ntb->pdev; dev_dbg(&ntb->pdev->dev, "Enabling link with max_speed %d max_width %d\n", @@ -476,12 +488,12 @@ static int intel_ntb4_link_enable(struct ntb_dev *ntb, iowrite16(lnkctl, ndev->self_mmio + GEN4_LINK_CTRL_OFFSET); /* start link training in PPD0 */ - ppd0 = ioread32(ndev->self_mmio + GEN4_PPD0_OFFSET); + ppd0 = ioread32(ndev->self_mmio + get_ppd0(pdev)); ppd0 |= GEN4_PPD_LINKTRN; - iowrite32(ppd0, ndev->self_mmio + GEN4_PPD0_OFFSET); + iowrite32(ppd0, ndev->self_mmio + get_ppd0(pdev)); /* make sure link training has started */ - ppd0 = ioread32(ndev->self_mmio + GEN4_PPD0_OFFSET); + ppd0 = ioread32(ndev->self_mmio + get_ppd0(pdev)); if (!(ppd0 & GEN4_PPD_LINKTRN)) { dev_warn(&ntb->pdev->dev, "Link is not training\n"); return -ENXIO; diff --git a/drivers/ntb/hw/intel/ntb_hw_gen4.h b/drivers/ntb/hw/intel/ntb_hw_gen4.h index f91323eaf5ce..1ba8203d6352 100644 --- a/drivers/ntb/hw/intel/ntb_hw_gen4.h +++ b/drivers/ntb/hw/intel/ntb_hw_gen4.h @@ -103,6 +103,8 @@ #define NTB_LTR_IDLE_LATSCALE 0x0800 /* 1us scale */ #define NTB_LTR_IDLE_REQMNT 0x8000 /* snoop req enable */ +#define GEN6_PPD0_OFFSET 0xf0d4 + ssize_t ndev_ntb4_debugfs_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp); int gen4_init_dev(struct intel_ntb_dev *ndev); diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index da4d5fe55bab..0a3a3677f82a 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -71,6 +71,7 @@ #define PCI_DEVICE_ID_INTEL_NTB_B2B_SKX 0x201C #define PCI_DEVICE_ID_INTEL_NTB_B2B_ICX 0x347e #define PCI_DEVICE_ID_INTEL_NTB_B2B_GNR 0x0db4 +#define PCI_DEVICE_ID_INTEL_NTB_B2B_DMR 0x7868 /* Ntb control and link status */ #define NTB_CTL_CFG_LOCK BIT(0) @@ -235,4 +236,9 @@ static inline int pdev_is_gen5(struct pci_dev *pdev) return pdev->device == PCI_DEVICE_ID_INTEL_NTB_B2B_GNR; } +static inline int pdev_is_gen6(struct pci_dev *pdev) +{ + return pdev->device == PCI_DEVICE_ID_INTEL_NTB_B2B_DMR; +} + #endif diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index f851397b65d6..e38540b92716 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -29,7 +29,7 @@ MODULE_PARM_DESC(use_lut_mws, "Enable the use of the LUT based memory windows"); #define SWITCHTEC_NTB_MAGIC 0x45CC0001 -#define MAX_MWS 128 +#define MAX_MWS 256 struct shared_mw { u32 magic; @@ -1202,7 +1202,8 @@ static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) sndev->mmio_self_ctrl); sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries); - sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); + if (sndev->nr_lut_mw) + sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut\n", sndev->nr_direct_mw, sndev->nr_lut_mw); @@ -1212,7 +1213,8 @@ static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) sndev->peer_nr_lut_mw = ioread16(&sndev->mmio_peer_ctrl->lut_table_entries); - sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); + if (sndev->peer_nr_lut_mw) + sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut\n", sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw); @@ -1314,6 +1316,12 @@ static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) for (i = 0; i < sndev->nr_lut_mw; i++) { int idx = sndev->nr_direct_mw + i; + if (idx >= MAX_MWS) { + dev_err(&sndev->stdev->dev, + "Total number of MW cannot be bigger than %d", MAX_MWS); + break; + } + sndev->self_shared->mw_sizes[idx] = LUT_SIZE; } } diff --git a/drivers/ntb/msi.c b/drivers/ntb/msi.c index 368f6d894bba..6817d504c12a 100644 --- a/drivers/ntb/msi.c +++ b/drivers/ntb/msi.c @@ -315,37 +315,6 @@ int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb, irq_handler_t handler, } EXPORT_SYMBOL(ntbm_msi_request_threaded_irq); -static int ntbm_msi_callback_match(struct device *dev, void *res, void *data) -{ - struct ntb_dev *ntb = dev_ntb(dev); - struct ntb_msi_devres *dr = res; - - return dr->ntb == ntb && dr->entry == data; -} - -/** - * ntbm_msi_free_irq() - free an interrupt - * @ntb: NTB device context - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * This function should be used to manually free IRQs allocated with - * ntbm_request_[threaded_]irq(). - */ -void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq, void *dev_id) -{ - struct msi_desc *entry = irq_get_msi_desc(irq); - - entry->write_msi_msg = NULL; - entry->write_msi_msg_data = NULL; - - WARN_ON(devres_destroy(&ntb->dev, ntbm_msi_callback_release, - ntbm_msi_callback_match, entry)); - - devm_free_irq(&ntb->dev, irq, dev_id); -} -EXPORT_SYMBOL(ntbm_msi_free_irq); - /** * ntb_msi_peer_trigger() - Trigger an interrupt handler on a peer * @ntb: NTB device context @@ -373,36 +342,3 @@ int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer, return 0; } EXPORT_SYMBOL(ntb_msi_peer_trigger); - -/** - * ntb_msi_peer_addr() - Get the DMA address to trigger a peer's MSI interrupt - * @ntb: NTB device context - * @peer: Peer index - * @desc: MSI descriptor data which triggers the interrupt - * @msi_addr: Physical address to trigger the interrupt - * - * This function allows using DMA engines to trigger an interrupt - * (for example, trigger an interrupt to process the data after - * sending it). To trigger the interrupt, write @desc.data to the address - * returned in @msi_addr - * - * Return: Zero on success, otherwise a negative error number. - */ -int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer, - struct ntb_msi_desc *desc, - phys_addr_t *msi_addr) -{ - int peer_widx = ntb_peer_mw_count(ntb) - 1 - peer; - phys_addr_t mw_phys_addr; - int ret; - - ret = ntb_peer_mw_get_addr(ntb, peer_widx, &mw_phys_addr, NULL); - if (ret) - return ret; - - if (msi_addr) - *msi_addr = mw_phys_addr + desc->addr_offset; - - return 0; -} -EXPORT_SYMBOL(ntb_msi_peer_addr); diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 71d4bb25f7fd..78e02fe6caba 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -54,12 +54,15 @@ #include <linux/errno.h> #include <linux/export.h> #include <linux/interrupt.h> +#include <linux/kthread.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> +#include <linux/seq_file.h> #include <linux/types.h> #include <linux/uaccess.h> #include <linux/mutex.h> +#include <linux/wait.h> #include "linux/ntb.h" #include "linux/ntb_transport.h" @@ -100,6 +103,10 @@ module_param(use_msi, bool, 0644); MODULE_PARM_DESC(use_msi, "Use MSI interrupts instead of doorbells"); #endif +static bool tx_memcpy_offload; +module_param(tx_memcpy_offload, bool, 0644); +MODULE_PARM_DESC(tx_memcpy_offload, "Offload TX memcpy_toio() to a kernel thread"); + static struct dentry *nt_debugfs_dir; /* Only two-ports NTB devices are supported */ @@ -113,7 +120,6 @@ struct ntb_queue_entry { void *buf; unsigned int len; unsigned int flags; - int retries; int errors; unsigned int tx_index; unsigned int rx_index; @@ -149,7 +155,9 @@ struct ntb_transport_qp { void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data, void *data, int len); struct list_head tx_free_q; + struct list_head tx_offl_q; spinlock_t ntb_tx_free_q_lock; + spinlock_t ntb_tx_offl_q_lock; void __iomem *tx_mw; phys_addr_t tx_mw_phys; size_t tx_mw_size; @@ -200,6 +208,9 @@ struct ntb_transport_qp { int msi_irq; struct ntb_msi_desc msi_desc; struct ntb_msi_desc peer_msi_desc; + + struct task_struct *tx_offload_thread; + wait_queue_head_t tx_offload_wq; }; struct ntb_transport_mw { @@ -285,7 +296,13 @@ static int ntb_async_tx_submit(struct ntb_transport_qp *qp, static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset); static int ntb_async_rx_submit(struct ntb_queue_entry *entry, void *offset); static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset); +static int ntb_tx_memcpy_kthread(void *data); + +static inline bool ntb_tx_offload_enabled(struct ntb_transport_qp *qp) +{ + return tx_memcpy_offload && qp && qp->tx_offload_thread; +} static int ntb_transport_bus_match(struct device *dev, const struct device_driver *drv) @@ -466,104 +483,49 @@ void ntb_transport_unregister_client(struct ntb_transport_client *drv) } EXPORT_SYMBOL_GPL(ntb_transport_unregister_client); -static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, - loff_t *offp) +static int ntb_qp_debugfs_stats_show(struct seq_file *s, void *v) { - struct ntb_transport_qp *qp; - char *buf; - ssize_t ret, out_offset, out_count; - - qp = filp->private_data; + struct ntb_transport_qp *qp = s->private; if (!qp || !qp->link_is_up) return 0; - out_count = 1000; - - buf = kmalloc(out_count, GFP_KERNEL); - if (!buf) - return -ENOMEM; + seq_puts(s, "\nNTB QP stats:\n\n"); + + seq_printf(s, "rx_bytes - \t%llu\n", qp->rx_bytes); + seq_printf(s, "rx_pkts - \t%llu\n", qp->rx_pkts); + seq_printf(s, "rx_memcpy - \t%llu\n", qp->rx_memcpy); + seq_printf(s, "rx_async - \t%llu\n", qp->rx_async); + seq_printf(s, "rx_ring_empty - %llu\n", qp->rx_ring_empty); + seq_printf(s, "rx_err_no_buf - %llu\n", qp->rx_err_no_buf); + seq_printf(s, "rx_err_oflow - \t%llu\n", qp->rx_err_oflow); + seq_printf(s, "rx_err_ver - \t%llu\n", qp->rx_err_ver); + seq_printf(s, "rx_buff - \t0x%p\n", qp->rx_buff); + seq_printf(s, "rx_index - \t%u\n", qp->rx_index); + seq_printf(s, "rx_max_entry - \t%u\n", qp->rx_max_entry); + seq_printf(s, "rx_alloc_entry - \t%u\n\n", qp->rx_alloc_entry); + + seq_printf(s, "tx_bytes - \t%llu\n", qp->tx_bytes); + seq_printf(s, "tx_pkts - \t%llu\n", qp->tx_pkts); + seq_printf(s, "tx_memcpy - \t%llu\n", qp->tx_memcpy); + seq_printf(s, "tx_async - \t%llu\n", qp->tx_async); + seq_printf(s, "tx_ring_full - \t%llu\n", qp->tx_ring_full); + seq_printf(s, "tx_err_no_buf - %llu\n", qp->tx_err_no_buf); + seq_printf(s, "tx_mw - \t0x%p\n", qp->tx_mw); + seq_printf(s, "tx_index (H) - \t%u\n", qp->tx_index); + seq_printf(s, "RRI (T) - \t%u\n", qp->remote_rx_info->entry); + seq_printf(s, "tx_max_entry - \t%u\n", qp->tx_max_entry); + seq_printf(s, "free tx - \t%u\n", ntb_transport_tx_free_entry(qp)); + seq_putc(s, '\n'); + + seq_printf(s, "Using TX DMA - \t%s\n", qp->tx_dma_chan ? "Yes" : "No"); + seq_printf(s, "Using RX DMA - \t%s\n", qp->rx_dma_chan ? "Yes" : "No"); + seq_printf(s, "QP Link - \t%s\n", qp->link_is_up ? "Up" : "Down"); + seq_putc(s, '\n'); - out_offset = 0; - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "\nNTB QP stats:\n\n"); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_bytes - \t%llu\n", qp->rx_bytes); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_pkts - \t%llu\n", qp->rx_pkts); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_memcpy - \t%llu\n", qp->rx_memcpy); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_async - \t%llu\n", qp->rx_async); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_ring_empty - %llu\n", qp->rx_ring_empty); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_err_no_buf - %llu\n", qp->rx_err_no_buf); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_err_oflow - \t%llu\n", qp->rx_err_oflow); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_err_ver - \t%llu\n", qp->rx_err_ver); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_buff - \t0x%p\n", qp->rx_buff); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_index - \t%u\n", qp->rx_index); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_max_entry - \t%u\n", qp->rx_max_entry); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "rx_alloc_entry - \t%u\n\n", qp->rx_alloc_entry); - - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_bytes - \t%llu\n", qp->tx_bytes); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_pkts - \t%llu\n", qp->tx_pkts); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_memcpy - \t%llu\n", qp->tx_memcpy); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_async - \t%llu\n", qp->tx_async); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_ring_full - \t%llu\n", qp->tx_ring_full); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_err_no_buf - %llu\n", qp->tx_err_no_buf); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_mw - \t0x%p\n", qp->tx_mw); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_index (H) - \t%u\n", qp->tx_index); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "RRI (T) - \t%u\n", - qp->remote_rx_info->entry); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "tx_max_entry - \t%u\n", qp->tx_max_entry); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "free tx - \t%u\n", - ntb_transport_tx_free_entry(qp)); - - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "\n"); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "Using TX DMA - \t%s\n", - qp->tx_dma_chan ? "Yes" : "No"); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "Using RX DMA - \t%s\n", - qp->rx_dma_chan ? "Yes" : "No"); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "QP Link - \t%s\n", - qp->link_is_up ? "Up" : "Down"); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, - "\n"); - - if (out_offset > out_count) - out_offset = out_count; - - ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); - kfree(buf); - return ret; -} - -static const struct file_operations ntb_qp_debugfs_stats = { - .owner = THIS_MODULE, - .open = simple_open, - .read = debugfs_read, -}; + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ntb_qp_debugfs_stats); static void ntb_list_add(spinlock_t *lock, struct list_head *entry, struct list_head *list) @@ -1236,15 +1198,15 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, qp->tx_max_entry = tx_size / qp->tx_max_frame; if (nt->debugfs_node_dir) { - char debugfs_name[4]; + char debugfs_name[8]; - snprintf(debugfs_name, 4, "qp%d", qp_num); + snprintf(debugfs_name, sizeof(debugfs_name), "qp%d", qp_num); qp->debugfs_dir = debugfs_create_dir(debugfs_name, nt->debugfs_node_dir); qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR, qp->debugfs_dir, qp, - &ntb_qp_debugfs_stats); + &ntb_qp_debugfs_stats_fops); } else { qp->debugfs_dir = NULL; qp->debugfs_stats = NULL; @@ -1255,11 +1217,13 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, spin_lock_init(&qp->ntb_rx_q_lock); spin_lock_init(&qp->ntb_tx_free_q_lock); + spin_lock_init(&qp->ntb_tx_offl_q_lock); INIT_LIST_HEAD(&qp->rx_post_q); INIT_LIST_HEAD(&qp->rx_pend_q); INIT_LIST_HEAD(&qp->rx_free_q); INIT_LIST_HEAD(&qp->tx_free_q); + INIT_LIST_HEAD(&qp->tx_offl_q); tasklet_init(&qp->rxc_db_work, ntb_transport_rxc_db, (unsigned long)qp); @@ -1571,15 +1535,15 @@ static int ntb_async_rx_submit(struct ntb_queue_entry *entry, void *offset) goto err; unmap->len = len; - unmap->addr[0] = dma_map_page(device->dev, virt_to_page(offset), - pay_off, len, DMA_TO_DEVICE); + unmap->addr[0] = dma_map_phys(device->dev, virt_to_phys(offset), + len, DMA_TO_DEVICE, 0); if (dma_mapping_error(device->dev, unmap->addr[0])) goto err_get_unmap; unmap->to_cnt = 1; - unmap->addr[1] = dma_map_page(device->dev, virt_to_page(buf), - buff_off, len, DMA_FROM_DEVICE); + unmap->addr[1] = dma_map_phys(device->dev, virt_to_phys(buf), + len, DMA_FROM_DEVICE, 0); if (dma_mapping_error(device->dev, unmap->addr[1])) goto err_get_unmap; @@ -1631,9 +1595,7 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset) if (res < 0) goto err; - if (!entry->retries) - qp->rx_async++; - + qp->rx_async++; return; err: @@ -1788,6 +1750,13 @@ static void ntb_tx_copy_callback(void *data, iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags); + /* + * Make DONE flag visible before DB/MSI. WC + posted MWr may reorder + * across iATU/bridge (platform-dependent). Order and flush here. + */ + dma_mb(); + ioread32(&hdr->flags); + if (qp->use_msi) ntb_msi_peer_trigger(qp->ndev, PIDX, &qp->peer_msi_desc); else @@ -1808,7 +1777,7 @@ static void ntb_tx_copy_callback(void *data, ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry, &qp->tx_free_q); } -static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset) +static void ntb_memcpy_tx_on_stack(struct ntb_queue_entry *entry, void __iomem *offset) { #ifdef ARCH_HAS_NOCACHE_UACCESS /* @@ -1826,6 +1795,54 @@ static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset) ntb_tx_copy_callback(entry, NULL); } +static int ntb_tx_memcpy_kthread(void *data) +{ + struct ntb_transport_qp *qp = data; + struct ntb_queue_entry *entry, *tmp; + const int resched_nr = 64; + LIST_HEAD(local_list); + void __iomem *offset; + int processed = 0; + + while (!kthread_should_stop()) { + spin_lock_irq(&qp->ntb_tx_offl_q_lock); + wait_event_interruptible_lock_irq_timeout(qp->tx_offload_wq, + kthread_should_stop() || + !list_empty(&qp->tx_offl_q), + qp->ntb_tx_offl_q_lock, 5*HZ); + list_splice_tail_init(&qp->tx_offl_q, &local_list); + spin_unlock_irq(&qp->ntb_tx_offl_q_lock); + + list_for_each_entry_safe(entry, tmp, &local_list, entry) { + list_del(&entry->entry); + offset = qp->tx_mw + qp->tx_max_frame * entry->tx_index; + ntb_memcpy_tx_on_stack(entry, offset); + if (++processed >= resched_nr) { + cond_resched(); + processed = 0; + } + } + cond_resched(); + } + + return 0; +} + +static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset) +{ + struct ntb_transport_qp *qp = entry->qp; + + if (WARN_ON_ONCE(!qp)) + return; + + if (ntb_tx_offload_enabled(qp)) { + ntb_list_add(&qp->ntb_tx_offl_q_lock, &entry->entry, + &qp->tx_offl_q); + wake_up(&qp->tx_offload_wq); + } else + ntb_memcpy_tx_on_stack(entry, offset); +} + static int ntb_async_tx_submit(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry) { @@ -1852,8 +1869,8 @@ static int ntb_async_tx_submit(struct ntb_transport_qp *qp, goto err; unmap->len = len; - unmap->addr[0] = dma_map_page(device->dev, virt_to_page(buf), - buff_off, len, DMA_TO_DEVICE); + unmap->addr[0] = dma_map_phys(device->dev, virt_to_phys(buf), + len, DMA_TO_DEVICE, 0); if (dma_mapping_error(device->dev, unmap->addr[0])) goto err_get_unmap; @@ -1898,6 +1915,9 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, hdr = offset + qp->tx_max_frame - sizeof(struct ntb_payload_header); entry->tx_hdr = hdr; + WARN_ON_ONCE(!ntb_transport_tx_free_entry(qp)); + WRITE_ONCE(qp->tx_index, (qp->tx_index + 1) % qp->tx_max_entry); + iowrite32(entry->len, &hdr->len); iowrite32((u32)qp->tx_pkts, &hdr->ver); @@ -1911,9 +1931,7 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, if (res < 0) goto err; - if (!entry->retries) - qp->tx_async++; - + qp->tx_async++; return; err: @@ -1940,9 +1958,6 @@ static int ntb_process_tx(struct ntb_transport_qp *qp, ntb_async_tx(qp, entry); - qp->tx_index++; - qp->tx_index %= qp->tx_max_entry; - qp->tx_pkts++; return 0; @@ -2039,6 +2054,20 @@ ntb_transport_create_queue(void *data, struct device *client_dev, qp->tx_handler = handlers->tx_handler; qp->event_handler = handlers->event_handler; + init_waitqueue_head(&qp->tx_offload_wq); + if (tx_memcpy_offload) { + qp->tx_offload_thread = kthread_run(ntb_tx_memcpy_kthread, qp, + "ntb-txcpy/%s/%u", + pci_name(ndev->pdev), qp->qp_num); + if (IS_ERR(qp->tx_offload_thread)) { + dev_warn(&nt->ndev->dev, + "tx memcpy offload thread creation failed: %ld; falling back to inline copy\n", + PTR_ERR(qp->tx_offload_thread)); + qp->tx_offload_thread = NULL; + } + } else + qp->tx_offload_thread = NULL; + dma_cap_zero(dma_mask); dma_cap_set(DMA_MEMCPY, dma_mask); @@ -2146,6 +2175,11 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) qp->active = false; + if (qp->tx_offload_thread) { + kthread_stop(qp->tx_offload_thread); + qp->tx_offload_thread = NULL; + } + if (qp->tx_dma_chan) { struct dma_chan *chan = qp->tx_dma_chan; /* Putting the dma_chan to NULL will force any new traffic to be @@ -2209,6 +2243,9 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) kfree(entry); + while ((entry = ntb_list_rm(&qp->ntb_tx_offl_q_lock, &qp->tx_offl_q))) + kfree(entry); + qp->transport->qp_bitmap_free |= qp_bit; dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num); @@ -2274,7 +2311,6 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, entry->buf = data; entry->len = len; entry->flags = 0; - entry->retries = 0; entry->errors = 0; entry->rx_index = 0; @@ -2324,7 +2360,6 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, entry->len = len; entry->flags = 0; entry->errors = 0; - entry->retries = 0; entry->tx_index = 0; rc = ntb_process_tx(qp, entry); diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c index 641cb7e05a47..06881047f5bc 100644 --- a/drivers/ntb/test/ntb_tool.c +++ b/drivers/ntb/test/ntb_tool.c @@ -936,7 +936,7 @@ static ssize_t tool_peer_mw_trans_write(struct file *filep, buf[buf_size] = '\0'; - n = sscanf(buf, "%lli:%zi", &addr, &wsize); + n = sscanf(buf, "%llu:%zu", &addr, &wsize); if (n != 2) return -EINVAL; diff --git a/include/linux/ntb.h b/include/linux/ntb.h index 191b524e5c0d..8ff9d663096b 100644 --- a/include/linux/ntb.h +++ b/include/linux/ntb.h @@ -1647,12 +1647,8 @@ int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb, irq_handler_t handler, irq_handler_t thread_fn, const char *name, void *dev_id, struct ntb_msi_desc *msi_desc); -void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq, void *dev_id); int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer, struct ntb_msi_desc *desc); -int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer, - struct ntb_msi_desc *desc, - phys_addr_t *msi_addr); #else /* not CONFIG_NTB_MSI */ @@ -1674,21 +1670,11 @@ static inline int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb, { return -EOPNOTSUPP; } -static inline void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq, - void *dev_id) {} static inline int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer, struct ntb_msi_desc *desc) { return -EOPNOTSUPP; } -static inline int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer, - struct ntb_msi_desc *desc, - phys_addr_t *msi_addr) -{ - return -EOPNOTSUPP; - -} - #endif /* CONFIG_NTB_MSI */ static inline int ntbm_msi_request_irq(struct ntb_dev *ntb, |
