[PATCH 11/15] NTB: hw: epf: Parse control-layout version and DMA locator
Koichiro Den <[email protected]> Fri, 13 Mar 2026 01:50:01 +0900
| Newsgroups | dev.linux.lists.ntb,org.kernel.vger.dmaengine,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
pci-epf-vntb can now expose either the historical control layout or a versioned extension that carries per-MW offset/size tuples and an optional DMA locator. Teach ntb_hw_epf to parse the control-layout version first, keep accepting the legacy format, and use the explicit MW size information when version 1 is present. Also parse the DMA locator and cache its BAR, offset, size, ABI, and channel count for the follow-up enumeration step. Finally, reserve the tail of the MSI/MSI-X vector allocation for the exported DMA child so ntb_hw_epf only requests the link and doorbell vectors it owns. Signed-off-by: Koichiro Den <[email protected]> --- drivers/ntb/hw/epf/ntb_hw_epf.c | 112 +++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 8 deletions(-) diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c index d420699ff7d6..6b427577b1bd 100644 --- a/drivers/ntb/hw/epf/ntb_hw_epf.c +++ b/drivers/ntb/hw/epf/ntb_hw_epf.c @@ -31,7 +31,14 @@ #define NTB_EPF_LINK_STATUS 0x0A #define LINK_STATUS_UP BIT(0) -#define NTB_EPF_TOPOLOGY 0x0C +/* + * 0x0C was historically NTB_EPF_TOPOLOGY, but neither ntb_hw_epf nor + * pci-epf-{v,}ntb ever consumed it. Reuse it as a control-layout version + * selector while keeping 0 as the legacy format. + */ +#define NTB_EPF_CTRL_VERSION 0x0C +#define NTB_EPF_CTRL_VERSION_LEGACY 0 +#define NTB_EPF_CTRL_VERSION_V1 1 #define NTB_EPF_LOWER_ADDR 0x10 #define NTB_EPF_UPPER_ADDR 0x14 #define NTB_EPF_LOWER_SIZE 0x18 @@ -39,6 +46,13 @@ #define NTB_EPF_MW_COUNT 0x20 #define NTB_EPF_MW1_OFFSET 0x24 #define NTB_EPF_SPAD_OFFSET 0x28 +#define NTB_EPF_MW_OFFSET(n) (0x134 + (n) * 4) +#define NTB_EPF_MW_SIZE(n) (0x144 + (n) * 4) +#define NTB_EPF_DMA_ABI 0x154 +#define NTB_EPF_DMA_BAR 0x158 +#define NTB_EPF_DMA_OFFSET 0x15C +#define NTB_EPF_DMA_SIZE 0x160 +#define NTB_EPF_DMA_NUM_CHANS 0x164 #define NTB_EPF_SPAD_COUNT 0x2C #define NTB_EPF_DB_ENTRY_SIZE 0x30 #define NTB_EPF_DB_DATA(n) (0x34 + (n) * 4) @@ -101,6 +115,15 @@ struct ntb_epf_dev { unsigned int mw_count; unsigned int spad_count; unsigned int db_count; + u32 ctrl_version; + u32 dma_abi; + u32 dma_offset; + u32 dma_size; + u32 dma_num_chans; + u32 dma_irq_base; + u32 dma_irq_count; + enum pci_barno dma_bar; + bool dma_aux_avail; void __iomem *ctrl_reg; void __iomem *db_reg; @@ -375,6 +398,21 @@ static int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max) argument &= ~MSIX_ENABLE; } + if (irq >= msi_min + ndev->dma_irq_count) { + ndev->dma_aux_avail = true; + + /* + * Reserve the tail of the vector space for the exported DMA + * child. ntb_hw_epf only requests the prefix used for link and + * doorbell events. + */ + ndev->dma_irq_base = irq - ndev->dma_irq_count; + irq = ndev->dma_irq_base; + } else { + ndev->dma_aux_avail = false; + irq = min(NTB_EPF_MAX_DB_COUNT + 1, irq); + } + for (i = 0; i < irq; i++) { ret = request_irq(pci_irq_vector(pdev, i), ntb_epf_vec_isr, 0, "ntb_epf", ndev); @@ -504,21 +542,32 @@ static int ntb_epf_peer_mw_get_addr(struct ntb_dev *ntb, int idx, phys_addr_t *base, resource_size_t *size) { struct ntb_epf_dev *ndev = ntb_ndev(ntb); - u32 offset = 0; + resource_size_t bar_sz, mw_size; + u32 offset; int bar; - if (idx == 0) - offset = readl(ndev->ctrl_reg + NTB_EPF_MW1_OFFSET); - bar = ntb_epf_mw_to_bar(ndev, idx); if (bar < 0) return bar; + bar_sz = pci_resource_len(ndev->ntb.pdev, bar); + + if (ndev->ctrl_version >= NTB_EPF_CTRL_VERSION_V1) { + offset = readl(ndev->ctrl_reg + NTB_EPF_MW_OFFSET(idx)); + mw_size = readl(ndev->ctrl_reg + NTB_EPF_MW_SIZE(idx)); + } else { + offset = idx == 0 ? readl(ndev->ctrl_reg + NTB_EPF_MW1_OFFSET) : 0; + mw_size = bar_sz - offset; + } + + if (!mw_size || offset + mw_size > bar_sz) + return -EINVAL; + if (base) *base = pci_resource_start(ndev->ntb.pdev, bar) + offset; if (size) - *size = pci_resource_len(ndev->ntb.pdev, bar) - offset; + *size = mw_size; return 0; } @@ -610,14 +659,61 @@ static inline void ntb_epf_init_struct(struct ntb_epf_dev *ndev, ndev->ntb.ops = &ntb_epf_ops; } +static int ntb_epf_parse_ctrl_version(struct ntb_epf_dev *ndev) +{ + struct device *dev = ndev->dev; + u32 ver; + + ver = readl(ndev->ctrl_reg + NTB_EPF_CTRL_VERSION); + switch (ver) { + case NTB_EPF_CTRL_VERSION_LEGACY: + case NTB_EPF_CTRL_VERSION_V1: + ndev->ctrl_version = ver; + return 0; + default: + dev_err(dev, "Unsupported NTB EPF control version %u\n", ver); + return -EINVAL; + } +} + +static void ntb_epf_parse_dma_locator(struct ntb_epf_dev *ndev) +{ + if (ndev->ctrl_version < NTB_EPF_CTRL_VERSION_V1) { + ndev->dma_abi = 0; + ndev->dma_bar = NO_BAR; + ndev->dma_offset = 0; + ndev->dma_size = 0; + ndev->dma_irq_count = 0; + return; + } + + ndev->dma_abi = readl(ndev->ctrl_reg + NTB_EPF_DMA_ABI); + ndev->dma_bar = readl(ndev->ctrl_reg + NTB_EPF_DMA_BAR); + ndev->dma_offset = readl(ndev->ctrl_reg + NTB_EPF_DMA_OFFSET); + ndev->dma_size = readl(ndev->ctrl_reg + NTB_EPF_DMA_SIZE); + ndev->dma_num_chans = readl(ndev->ctrl_reg + NTB_EPF_DMA_NUM_CHANS); + if (ndev->dma_abi && !ndev->dma_num_chans) + ndev->dma_num_chans = 1; + ndev->dma_irq_count = ndev->dma_num_chans; +} + static int ntb_epf_init_dev(struct ntb_epf_dev *ndev) { struct device *dev = ndev->dev; int ret; - /* One Link interrupt and rest doorbell interrupt */ + ret = ntb_epf_parse_ctrl_version(ndev); + if (ret) + return ret; + + ntb_epf_parse_dma_locator(ndev); + + /* + * One Link interrupt and rest doorbell interrupt. + * Remote DMA interrupt is best effort. + */ ret = ntb_epf_init_isr(ndev, NTB_EPF_MIN_DB_COUNT + 1, - NTB_EPF_MAX_DB_COUNT + 1); + NTB_EPF_MAX_DB_COUNT + 1 + ndev->dma_irq_count); if (ret) { dev_err(dev, "Failed to init ISR\n"); return ret; -- 2.51.0