* [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c
@ 2025-09-25 4:06 Yaxing Guo
2025-09-25 4:06 ` [RFC v1 2/2] uio: Add Kconfig and Makefile support for UIO_PCI_GENERIC_SVA Yaxing Guo
2025-09-25 6:02 ` [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c Greg KH
0 siblings, 2 replies; 4+ messages in thread
From: Yaxing Guo @ 2025-09-25 4:06 UTC (permalink / raw)
To: gregkh; +Cc: linux-kernel, anxu, zhangjian, wangran, guoyaxing
This patch introduces a new UIO driver, uio_pci_generic_sva, which
extends the functionality of uio_pci_generic by adding support for
Shared Virtual Addressing (SVA) when IOMMU is enabled in the system.
The key enhancement allows PCI devices to directly use user-space virtual
addresses for DMA operations, eliminating the need for bounce buffers or
explicit IOVA mapping. This is achieved by leveraging the kernel's IOMMU-SVA
subsystem, including process address space attachment, page fault handling,
and shared context management between CPU and device.
With this driver, userspace applications can perform zero-copy DMA using
native pointers:
void *addr = malloc(N);
set_dma_addr((uint64_t)addr); // Pass user VA directly
start_dma();
The device can now access 'addr' through the IOMMU's PASID-based translation,
provided that the underlying IOMMU hardware (e.g., Intel VT-d 3.1+, AMD-Vi,
ARM SMMU, RISCV IOMMU) and platform support SVA.
Dependencies:
- CONFIG_IOMMU_SVA must be enabled.
- The platform must support PRI (Page Request Interface) and PASID.
- Device drivers/userspace must handle page faults if demand-paging is used.
The implementation reuses core logic from uio_pci_generic.c while adding
PASID setting, and integration with the IOMMU SVA APIs.
Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
---
drivers/uio/uio_pci_generic_sva.c | 188 ++++++++++++++++++++++++++++++
1 file changed, 188 insertions(+)
create mode 100644 drivers/uio/uio_pci_generic_sva.c
diff --git a/drivers/uio/uio_pci_generic_sva.c b/drivers/uio/uio_pci_generic_sva.c
new file mode 100644
index 000000000000..6a20c3487fed
--- /dev/null
+++ b/drivers/uio/uio_pci_generic_sva.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UIO PCI Express sva driver
+ *
+ * Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+#include <linux/iommu.h>
+
+struct uio_pci_sva_dev {
+ struct pci_dev *pdev;
+ struct uio_info info;
+ struct iommu_sva *sva_handle;
+ int pasid;
+};
+
+static ssize_t pasid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct uio_pci_sva_dev *udev = pci_get_drvdata(pdev);
+
+ return sprintf(buf, "%d\n", udev->pasid);
+}
+static DEVICE_ATTR_RO(pasid);
+
+static irqreturn_t irq_handler(int irq, struct uio_info *dev_info)
+{
+ return IRQ_HANDLED;
+}
+
+static int uio_pci_sva_open(struct uio_info *info, struct inode *inode)
+{
+ struct iommu_sva *handle;
+ struct uio_pci_sva_dev *udev = info->priv;
+ struct iommu_domain *domain;
+
+ if (!udev && !udev->pdev)
+ return -ENODEV;
+
+ domain = iommu_get_domain_for_dev(&udev->pdev->dev);
+ if (domain)
+ iommu_detach_device(domain, &udev->pdev->dev);
+
+ handle = iommu_sva_bind_device(&udev->pdev->dev, current->mm);
+ if (IS_ERR(handle))
+ return -EINVAL;
+
+ udev->pasid = iommu_sva_get_pasid(handle);
+
+ udev->sva_handle = handle;
+
+ return 0;
+}
+
+static int uio_pci_sva_release(struct uio_info *info, struct inode *inode)
+{
+ struct uio_pci_sva_dev *udev = info->priv;
+ struct iommu_domain *domain;
+
+ if (!udev && !udev->pdev)
+ return -ENODEV;
+
+ domain = iommu_get_domain_for_dev(&udev->pdev->dev);
+ if (!domain)
+ return -ENODEV;
+
+ iommu_detach_device(domain, &udev->pdev->dev);
+
+ return 0;
+}
+
+static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct uio_pci_sva_dev *udev;
+ int ret, i, irq;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_enable_device failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret)
+ goto out_disable;
+
+ pci_set_master(pdev);
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
+ if (ret) {
+ irq = msi_get_virq(&pdev->dev, 0);
+ if (irq == -ENXIO)
+ ret = UIO_IRQ_NONE;
+ else if (irq < 0) {
+ ret = irq;
+ goto out_disable;
+ }
+ } else {
+ dev_warn(&pdev->dev, "Failed to allocate irq vectors\n");
+ }
+
+ udev = devm_kzalloc(&pdev->dev, sizeof(struct uio_pci_sva_dev),
+ GFP_KERNEL);
+ if (!udev) {
+ ret = -ENOMEM;
+ goto out_disable;
+ }
+
+ udev->pdev = pdev;
+ udev->info.name = "uio_pci_sva";
+ udev->info.version = "0.0.1";
+ udev->info.open = uio_pci_sva_open;
+ udev->info.release = uio_pci_sva_release;
+ udev->info.irq = irq;
+ udev->info.handler = irq_handler;
+ udev->info.priv = udev;
+
+ for (i = 0; i < MAX_UIO_MAPS; i++) {
+ struct resource *r = &pdev->resource[i];
+ struct uio_mem *uiomem = &udev->info.mem[i];
+
+ if (r->flags != (IORESOURCE_SIZEALIGN | IORESOURCE_MEM))
+ continue;
+
+ if (uiomem >= &udev->info.mem[MAX_UIO_MAPS]) {
+ dev_warn(&pdev->dev, "Do not support more than %d iomem\n",
+ MAX_UIO_MAPS);
+ break;
+ }
+
+ uiomem->memtype = UIO_MEM_PHYS;
+ uiomem->addr = r->start & PAGE_MASK;
+ uiomem->offs = r->start & ~PAGE_MASK;
+ uiomem->size =
+ (uiomem->offs + resource_size(r) + PAGE_SIZE - 1) &
+ PAGE_MASK;
+ uiomem->name = r->name;
+ }
+
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_pasid.attr);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to create sysfs file\n");
+ goto out_free;
+ }
+
+ ret = devm_uio_register_device(&pdev->dev, &udev->info);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register uio device\n");
+ goto out_rm_sysfs;
+ }
+
+ pci_set_drvdata(pdev, udev);
+
+ return 0;
+
+out_rm_sysfs:
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pasid.attr);
+out_free:
+ kfree(udev);
+out_disable:
+ pci_disable_device(pdev);
+
+ return ret;
+}
+
+static void remove(struct pci_dev *pdev)
+{
+ struct uio_info *info = pci_get_drvdata(pdev);
+
+ uio_unregister_device(info);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_driver uio_pci_generic_sva_driver = {
+ .name = "uio_pci_sva",
+ .id_table = NULL,
+ .probe = probe,
+ .remove = remove,
+};
+
+module_pci_driver(uio_pci_generic_sva_driver);
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC v1 2/2] uio: Add Kconfig and Makefile support for UIO_PCI_GENERIC_SVA
2025-09-25 4:06 [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c Yaxing Guo
@ 2025-09-25 4:06 ` Yaxing Guo
2025-09-25 6:00 ` Greg KH
2025-09-25 6:02 ` [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c Greg KH
1 sibling, 1 reply; 4+ messages in thread
From: Yaxing Guo @ 2025-09-25 4:06 UTC (permalink / raw)
To: gregkh; +Cc: linux-kernel, anxu, zhangjian, wangran, guoyaxing
Add config symbol and build infrastructure for the UIO PCI generic
driver with SVA (Shared Virtual Addressing) support.
This introduces:
- A new tristate config option 'UIO_PCI_GENERIC_SVA' in Kconfig,
dependent on PCI and IOMMU_SVA.
- Build rule in Makefile to compile uio_pci_generic_sva.o when enabled.
Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
---
drivers/uio/Kconfig | 5 +++++
drivers/uio/Makefile | 1 +
2 files changed, 6 insertions(+)
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index b060dcd7c635..9849e53d1932 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -164,4 +164,9 @@ config UIO_DFL
opae-sdk/tools/libopaeuio/
If you compile this as a module, it will be called uio_dfl.
+
+config UIO_PCI_GENERIC_SVA
+ tristate "Generic driver for PCI Express that supports sva"
+ depends on PCI && IOMMU_SVA
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index 1c5f3b5a95cf..5352e21e918d 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_UIO_MF624) += uio_mf624.o
obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o
obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o
obj-$(CONFIG_UIO_DFL) += uio_dfl.o
+obj-$(CONFIG_UIO_PCI_GENERIC_SVA) += uio_pci_generic_sva.o
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC v1 2/2] uio: Add Kconfig and Makefile support for UIO_PCI_GENERIC_SVA
2025-09-25 4:06 ` [RFC v1 2/2] uio: Add Kconfig and Makefile support for UIO_PCI_GENERIC_SVA Yaxing Guo
@ 2025-09-25 6:00 ` Greg KH
0 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2025-09-25 6:00 UTC (permalink / raw)
To: Yaxing Guo; +Cc: linux-kernel, anxu, zhangjian, wangran
On Thu, Sep 25, 2025 at 12:06:37PM +0800, Yaxing Guo wrote:
> Add config symbol and build infrastructure for the UIO PCI generic
> driver with SVA (Shared Virtual Addressing) support.
>
> This introduces:
> - A new tristate config option 'UIO_PCI_GENERIC_SVA' in Kconfig,
> dependent on PCI and IOMMU_SVA.
> - Build rule in Makefile to compile uio_pci_generic_sva.o when enabled.
This should be part of patch 1, no need to split this apart.
> Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
> ---
> drivers/uio/Kconfig | 5 +++++
> drivers/uio/Makefile | 1 +
> 2 files changed, 6 insertions(+)
>
> diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
> index b060dcd7c635..9849e53d1932 100644
> --- a/drivers/uio/Kconfig
> +++ b/drivers/uio/Kconfig
> @@ -164,4 +164,9 @@ config UIO_DFL
> opae-sdk/tools/libopaeuio/
>
> If you compile this as a module, it will be called uio_dfl.
> +
> +config UIO_PCI_GENERIC_SVA
> + tristate "Generic driver for PCI Express that supports sva"
> + depends on PCI && IOMMU_SVA
> +
Please provide more information here, like the other entries have.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c
2025-09-25 4:06 [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c Yaxing Guo
2025-09-25 4:06 ` [RFC v1 2/2] uio: Add Kconfig and Makefile support for UIO_PCI_GENERIC_SVA Yaxing Guo
@ 2025-09-25 6:02 ` Greg KH
1 sibling, 0 replies; 4+ messages in thread
From: Greg KH @ 2025-09-25 6:02 UTC (permalink / raw)
To: Yaxing Guo; +Cc: linux-kernel, anxu, zhangjian, wangran
On Thu, Sep 25, 2025 at 12:06:36PM +0800, Yaxing Guo wrote:
> This patch introduces a new UIO driver, uio_pci_generic_sva, which
> extends the functionality of uio_pci_generic by adding support for
> Shared Virtual Addressing (SVA) when IOMMU is enabled in the system.
>
> The key enhancement allows PCI devices to directly use user-space virtual
> addresses for DMA operations, eliminating the need for bounce buffers or
> explicit IOVA mapping. This is achieved by leveraging the kernel's IOMMU-SVA
> subsystem, including process address space attachment, page fault handling,
> and shared context management between CPU and device.
>
> With this driver, userspace applications can perform zero-copy DMA using
> native pointers:
>
> void *addr = malloc(N);
> set_dma_addr((uint64_t)addr); // Pass user VA directly
> start_dma();
>
> The device can now access 'addr' through the IOMMU's PASID-based translation,
> provided that the underlying IOMMU hardware (e.g., Intel VT-d 3.1+, AMD-Vi,
> ARM SMMU, RISCV IOMMU) and platform support SVA.
>
> Dependencies:
> - CONFIG_IOMMU_SVA must be enabled.
> - The platform must support PRI (Page Request Interface) and PASID.
> - Device drivers/userspace must handle page faults if demand-paging is used.
>
> The implementation reuses core logic from uio_pci_generic.c while adding
> PASID setting, and integration with the IOMMU SVA APIs.
>
> Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
> ---
> drivers/uio/uio_pci_generic_sva.c | 188 ++++++++++++++++++++++++++++++
> 1 file changed, 188 insertions(+)
> create mode 100644 drivers/uio/uio_pci_generic_sva.c
>
> diff --git a/drivers/uio/uio_pci_generic_sva.c b/drivers/uio/uio_pci_generic_sva.c
> new file mode 100644
> index 000000000000..6a20c3487fed
> --- /dev/null
> +++ b/drivers/uio/uio_pci_generic_sva.c
> @@ -0,0 +1,188 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * UIO PCI Express sva driver
> + *
> + * Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
It is now 2025 :)
> + */
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/uio_driver.h>
> +#include <linux/iommu.h>
> +
> +struct uio_pci_sva_dev {
> + struct pci_dev *pdev;
> + struct uio_info info;
> + struct iommu_sva *sva_handle;
> + int pasid;
> +};
> +
> +static ssize_t pasid_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> + struct uio_pci_sva_dev *udev = pci_get_drvdata(pdev);
> +
> + return sprintf(buf, "%d\n", udev->pasid);
sysfs_emit() please.
> +}
> +static DEVICE_ATTR_RO(pasid);
All sysfs attributes need to be documented in Documentation/ABI/
> +static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> + struct uio_pci_sva_dev *udev;
> + int ret, i, irq;
> +
> + ret = pci_enable_device(pdev);
> + if (ret) {
> + dev_err(&pdev->dev, "pci_enable_device failed: %d\n", ret);
> + return ret;
> + }
> +
> + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
> + if (ret)
> + goto out_disable;
> +
> + pci_set_master(pdev);
> +
> + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
> + if (ret) {
> + irq = msi_get_virq(&pdev->dev, 0);
> + if (irq == -ENXIO)
> + ret = UIO_IRQ_NONE;
> + else if (irq < 0) {
> + ret = irq;
> + goto out_disable;
> + }
> + } else {
> + dev_warn(&pdev->dev, "Failed to allocate irq vectors\n");
Why doesn't this fail probe?
> + }
> +
> + udev = devm_kzalloc(&pdev->dev, sizeof(struct uio_pci_sva_dev),
> + GFP_KERNEL);
> + if (!udev) {
> + ret = -ENOMEM;
> + goto out_disable;
> + }
> +
> + udev->pdev = pdev;
> + udev->info.name = "uio_pci_sva";
> + udev->info.version = "0.0.1";
> + udev->info.open = uio_pci_sva_open;
> + udev->info.release = uio_pci_sva_release;
> + udev->info.irq = irq;
> + udev->info.handler = irq_handler;
> + udev->info.priv = udev;
> +
> + for (i = 0; i < MAX_UIO_MAPS; i++) {
> + struct resource *r = &pdev->resource[i];
> + struct uio_mem *uiomem = &udev->info.mem[i];
> +
> + if (r->flags != (IORESOURCE_SIZEALIGN | IORESOURCE_MEM))
> + continue;
> +
> + if (uiomem >= &udev->info.mem[MAX_UIO_MAPS]) {
> + dev_warn(&pdev->dev, "Do not support more than %d iomem\n",
> + MAX_UIO_MAPS);
> + break;
> + }
> +
> + uiomem->memtype = UIO_MEM_PHYS;
> + uiomem->addr = r->start & PAGE_MASK;
> + uiomem->offs = r->start & ~PAGE_MASK;
> + uiomem->size =
> + (uiomem->offs + resource_size(r) + PAGE_SIZE - 1) &
> + PAGE_MASK;
> + uiomem->name = r->name;
> + }
> +
> + ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_pasid.attr);
You just raced with userspace and lost. Please use the default
attribute list instead.
> +module_pci_driver(uio_pci_generic_sva_driver);
> +MODULE_LICENSE("GPL");
You now also need a MODULE_DESCRIPTION(), didn't you get a build warning
without it?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-09-25 6:02 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-25 4:06 [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c Yaxing Guo
2025-09-25 4:06 ` [RFC v1 2/2] uio: Add Kconfig and Makefile support for UIO_PCI_GENERIC_SVA Yaxing Guo
2025-09-25 6:00 ` Greg KH
2025-09-25 6:02 ` [RFC v1 1/2] uio: Add SVA support for PCI devices via uio_pci_generic_sva.c Greg KH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®