[RFC PATCH 06/11] iommufd: Plumb dma-buf memory-type (RAM vs MMIO) through the phys map
From: David Woodhouse
Date: Thu Jul 16 2026 - 12:34:13 EST
From: David Woodhouse <dwmw@xxxxxxxxxxxx>
iommufd's dma-buf import path programmed the IOMMU unconditionally with
BATCH_MMIO (IOMMU_MMIO set, IOMMU_CACHE cleared). This is correct for
the VFIO PCI dma-buf exporter -- its phys is PCI BAR (MMIO) memory --
but it is the wrong prot for a dma-buf whose phys is RAM: on AMD-Vi the
device DMA silently misroutes (Identify Controller against a
gmem-provider-backed target completes with status=0 but the target
region is not written).
Carry the exporter's memory type through to the fill routine:
- Add is_cpu_ram to iopt_pages_dmabuf and pfn_reader_dmabuf.
- Make sym_vfio_pci_dma_buf_iommufd_map() also fill *is_cpu_ram.
VFIO PCI's exporter is MMIO (false); the sample gmem provider's
exporter is CPU RAM (true).
- pfn_reader_fill_dmabuf() picks BATCH_CPU_MEMORY vs BATCH_MMIO based
on the captured kind.
The eventual formal negotiated exporter op should return phys and
memory type together in one call, replacing both symbol_get() lookups.
Signed-off-by: David Woodhouse (Kiro) <dwmw@xxxxxxxxxxxx>
---
drivers/iommu/iommufd/io_pagetable.h | 7 ++++++
drivers/iommu/iommufd/pages.c | 33 +++++++++++++++++++++++-----
2 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/iommufd/io_pagetable.h b/drivers/iommu/iommufd/io_pagetable.h
index 27e3e311d395..887ed94474c7 100644
--- a/drivers/iommu/iommufd/io_pagetable.h
+++ b/drivers/iommu/iommufd/io_pagetable.h
@@ -206,6 +206,13 @@ struct iopt_pages_dmabuf {
/* Always PAGE_SIZE aligned */
unsigned long start;
struct list_head tracker;
+ /*
+ * true if the exporter's phys is CPU RAM (map with IOMMU_CACHE, no
+ * IOMMU_MMIO); false for MMIO/BAR memory (map with IOMMU_MMIO). Set
+ * by the exporter dispatch at map time; consulted by
+ * pfn_reader_fill_dmabuf() to pick BATCH_CPU_MEMORY vs BATCH_MMIO.
+ */
+ bool is_cpu_ram;
};
/*
diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c
index 2d4ea41460fd..f9b2ae6d7e96 100644
--- a/drivers/iommu/iommufd/pages.c
+++ b/drivers/iommu/iommufd/pages.c
@@ -1080,6 +1080,7 @@ static int pfn_reader_user_update_pinned(struct pfn_reader_user *user,
struct pfn_reader_dmabuf {
struct phys_vec phys;
unsigned long start_offset;
+ bool is_cpu_ram;
};
static int pfn_reader_dmabuf_init(struct pfn_reader_dmabuf *dmabuf,
@@ -1091,6 +1092,7 @@ static int pfn_reader_dmabuf_init(struct pfn_reader_dmabuf *dmabuf,
dmabuf->phys = pages->dmabuf.phys;
dmabuf->start_offset = pages->dmabuf.start;
+ dmabuf->is_cpu_ram = pages->dmabuf.is_cpu_ram;
return 0;
}
@@ -1106,9 +1108,15 @@ static int pfn_reader_fill_dmabuf(struct pfn_reader_dmabuf *dmabuf,
* always filled using page size aligned PFNs just like the other types.
* If the dmabuf has been sliced on a sub page offset then the common
* batch to domain code will adjust it before mapping to the domain.
+ *
+ * The exporter's memory type (CPU RAM vs MMIO/BAR) selects the batch
+ * kind so downstream iommu_map sets IOMMU_CACHE for cache-coherent RAM
+ * or IOMMU_MMIO for BAR memory. The kind was captured at map time by
+ * the exporter dispatch.
*/
batch_add_pfn_num(batch, PHYS_PFN(dmabuf->phys.paddr + start),
- last_index - start_index + 1, BATCH_MMIO);
+ last_index - start_index + 1,
+ dmabuf->is_cpu_ram ? BATCH_CPU_MEMORY : BATCH_MMIO);
return 0;
}
@@ -1459,22 +1467,31 @@ static const struct dma_buf_attach_ops iopt_dmabuf_attach_revoke_ops = {
* iommufd and vfio have a circular dependency. Future work for a phys
* based private interconnect will remove this.
*/
+/*
+ * Look up the exporter's phys accessor for iommufd's private-interconnect
+ * path. Also fills *is_cpu_ram: true if the exporter's memory is normal
+ * cache-coherent RAM (needs BATCH_CPU_MEMORY / IOMMU_CACHE), false for MMIO
+ * (needs BATCH_MMIO / IOMMU_MMIO). This will be replaced by a formal
+ * exporter op that returns phys + memory type together.
+ */
static int
sym_vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,
- struct phys_vec *phys)
+ struct phys_vec *phys, bool *is_cpu_ram)
{
typeof(&vfio_pci_dma_buf_iommufd_map) fn;
int rc;
rc = iommufd_test_dma_buf_iommufd_map(attachment, phys);
- if (rc != -EOPNOTSUPP)
+ if (rc != -EOPNOTSUPP) {
+ *is_cpu_ram = false; /* test hook mimics VFIO MMIO */
return rc;
+ }
/*
* Prototype: try the sample gmem provider's dma-buf exporter. This
* mirrors the vfio-pci private-interconnect hook, and (like it) is
* meant to be replaced by a formal negotiated exporter op returning
- * phys for iommufd.
+ * phys + memory type. The provider serves RAM, so mark it CPU_RAM.
*/
{
extern int gmem_provider_dma_buf_iommufd_map(
@@ -1485,8 +1502,10 @@ sym_vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,
if (gfn) {
rc = gfn(attachment, phys);
symbol_put(gmem_provider_dma_buf_iommufd_map);
- if (rc != -EOPNOTSUPP)
+ if (rc != -EOPNOTSUPP) {
+ *is_cpu_ram = true;
return rc;
+ }
}
}
@@ -1498,6 +1517,7 @@ sym_vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,
return -EOPNOTSUPP;
rc = fn(attachment, phys);
symbol_put(vfio_pci_dma_buf_iommufd_map);
+ *is_cpu_ram = false; /* VFIO PCI dma-buf carries BAR (MMIO) memory */
return rc;
}
@@ -1526,7 +1546,8 @@ static int iopt_map_dmabuf(struct iommufd_ctx *ictx, struct iopt_pages *pages,
if (rc)
goto err_detach;
- rc = sym_vfio_pci_dma_buf_iommufd_map(attach, &pages->dmabuf.phys);
+ rc = sym_vfio_pci_dma_buf_iommufd_map(attach, &pages->dmabuf.phys,
+ &pages->dmabuf.is_cpu_ram);
if (rc)
goto err_unpin;
--
2.54.0