[PATCH v10 10/10] NTB: ntb_hw_epf: Support DMA and MW sharing a BAR
From: Koichiro Den
Date: Fri Nov 13 2026 - 14:41:02 EST
A vNTB endpoint can place DMA resources after an MW in the same BAR.
Limit the MW to the advertised boundary so clients cannot overwrite
those resources.
Advertise this support in LINK_UP, including when DMA is unavailable.
Older endpoints ignore the argument.
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Changes since v8:
- No changes.
drivers/ntb/hw/epf/ntb_hw_epf.c | 46 +++++++++++++++++++++++++++------
1 file changed, 38 insertions(+), 8 deletions(-)
diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c
index a70da2b4f187..0b4ae28d30e5 100644
--- a/drivers/ntb/hw/epf/ntb_hw_epf.c
+++ b/drivers/ntb/hw/epf/ntb_hw_epf.c
@@ -377,6 +377,23 @@ static int ntb_epf_mw_to_bar(struct ntb_epf_dev *ndev, int idx)
return ndev->barno_map[BAR_MW1 + idx];
}
+static resource_size_t ntb_epf_mw_offset(struct ntb_epf_dev *ndev, int idx)
+{
+ return !idx ? readl(ndev->ctrl_reg + NTB_EPF_CTRL(mw1_offset)) : 0;
+}
+
+static resource_size_t ntb_epf_mw_size(struct ntb_epf_dev *ndev, int bar)
+{
+ resource_size_t end;
+
+ end = pci_resource_len(ndev->ntb.pdev, bar);
+ /* The DMA submap offset marks the end of an MW sharing this BAR. */
+ if (ndev->dma.submap.size && ndev->dma.submap.bar == bar)
+ end = min(end, ndev->dma.submap.offset);
+
+ return end;
+}
+
static int ntb_epf_mw_count(struct ntb_dev *ntb, int pidx)
{
struct ntb_epf_dev *ndev = ntb_ndev(ntb);
@@ -415,7 +432,7 @@ static int ntb_epf_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
*size_align = 1;
if (size_max)
- *size_max = pci_resource_len(ndev->ntb.pdev, bar);
+ *size_max = ntb_epf_mw_size(ndev, bar);
return 0;
}
@@ -519,7 +536,8 @@ static int ntb_epf_link_enable(struct ntb_dev *ntb,
struct device *dev = ndev->dev;
int ret;
- ret = ntb_epf_send_command(ndev, EPF_NTB_COMMAND_LINK_UP, 0);
+ ret = ntb_epf_send_command(ndev, EPF_NTB_COMMAND_LINK_UP,
+ EPF_NTB_LINK_UP_DMA_MW_SUPPORTED);
if (ret) {
dev_err(dev, "Fail to enable link\n");
return ret;
@@ -696,7 +714,7 @@ static int ntb_epf_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
if (bar < 0)
return bar;
- mw_size = pci_resource_len(ntb->pdev, bar);
+ mw_size = ntb_epf_mw_size(ndev, bar);
if (size > mw_size) {
dev_err(dev, "Size:%pa is greater than the MW size %pa\n",
@@ -728,21 +746,20 @@ 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 offset;
int bar;
- if (idx == 0)
- offset = readl(ndev->ctrl_reg + NTB_EPF_CTRL(mw1_offset));
-
bar = ntb_epf_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;
+ offset = ntb_epf_mw_offset(ndev, idx);
+
if (base)
*base = pci_resource_start(ndev->ntb.pdev, bar) + offset;
if (size)
- *size = pci_resource_len(ndev->ntb.pdev, bar) - offset;
+ *size = ntb_epf_mw_size(ndev, bar) - offset;
return 0;
}
@@ -840,6 +857,7 @@ static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)
{
struct device *dev = ndev->dev;
int ret;
+ int i;
ndev->mw_count = readl(ndev->ctrl_reg + NTB_EPF_CTRL(num_mws));
if (ndev->mw_count > NTB_EPF_MAX_MW_COUNT) {
@@ -851,6 +869,18 @@ static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)
dev_err(dev, "Invalid endpoint DMA layout\n");
return ret;
}
+ if (ndev->dma.submap.size) {
+ for (i = 0; i < ndev->mw_count; i++) {
+ int bar = ntb_epf_mw_to_bar(ndev, i);
+
+ if (bar == ndev->dma.submap.bar &&
+ ntb_epf_mw_size(ndev, bar) <=
+ ntb_epf_mw_offset(ndev, i)) {
+ dev_err(dev, "Invalid DMA/MW boundary\n");
+ return -EINVAL;
+ }
+ }
+ }
/* One Link interrupt and rest doorbell interrupt */
ret = ntb_epf_init_isr(ndev, NTB_EPF_MIN_DB_COUNT + 1,
--
2.54.0