[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <d8b285b10bb888c3687330c529516b415d466686.1736550979.git.nicolinc@nvidia.com>
Date: Fri, 10 Jan 2025 19:32:29 -0800
From: Nicolin Chen <nicolinc@...dia.com>
To: <will@...nel.org>, <robin.murphy@....com>, <jgg@...dia.com>,
<kevin.tian@...el.com>, <tglx@...utronix.de>, <maz@...nel.org>,
<alex.williamson@...hat.com>
CC: <joro@...tes.org>, <shuah@...nel.org>, <reinette.chatre@...el.com>,
<eric.auger@...hat.com>, <yebin10@...wei.com>, <apatel@...tanamicro.com>,
<shivamurthy.shastri@...utronix.de>, <bhelgaas@...gle.com>,
<anna-maria@...utronix.de>, <yury.norov@...il.com>, <nipun.gupta@....com>,
<iommu@...ts.linux.dev>, <linux-kernel@...r.kernel.org>,
<linux-arm-kernel@...ts.infradead.org>, <kvm@...r.kernel.org>,
<linux-kselftest@...r.kernel.org>, <patches@...ts.linux.dev>,
<jean-philippe@...aro.org>, <mdf@...nel.org>, <mshavit@...gle.com>,
<shameerali.kolothum.thodi@...wei.com>, <smostafa@...gle.com>,
<ddutile@...hat.com>
Subject: [PATCH RFCv2 13/13] vfio/pci: Allow preset MSI IOVAs via VFIO_IRQ_SET_ACTION_PREPARE
Add a new VFIO_IRQ_SET_ACTION_PREPARE to set VFIO_IRQ_SET_DATA_MSI_IOVA,
giving user space an interface to forward to kernel the stage-1 IOVA (of
a 2-stage translation: IOVA->IPA->PA) for an MSI doorbell address, since
the ITS hardware needs to be programmed with the top level IOVA address,
in order to work with the IOMMU on ARM64.
Signed-off-by: Nicolin Chen <nicolinc@...dia.com>
---
include/uapi/linux/vfio.h | 8 ++++--
drivers/vfio/pci/vfio_pci_intrs.c | 46 +++++++++++++++++++++++++++++++
drivers/vfio/vfio_main.c | 3 ++
3 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index c8dbf8219c4f..85095e59a3c6 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -590,6 +590,8 @@ struct vfio_irq_set {
#define VFIO_IRQ_SET_ACTION_MASK (1 << 3) /* Mask interrupt */
#define VFIO_IRQ_SET_ACTION_UNMASK (1 << 4) /* Unmask interrupt */
#define VFIO_IRQ_SET_ACTION_TRIGGER (1 << 5) /* Trigger interrupt */
+#define VFIO_IRQ_SET_DATA_MSI_IOVA (1 << 6) /* Data is MSI IOVA (u64) */
+#define VFIO_IRQ_SET_ACTION_PREPARE (1 << 7) /* Prepare interrupt */
__u32 index;
__u32 start;
__u32 count;
@@ -599,10 +601,12 @@ struct vfio_irq_set {
#define VFIO_IRQ_SET_DATA_TYPE_MASK (VFIO_IRQ_SET_DATA_NONE | \
VFIO_IRQ_SET_DATA_BOOL | \
- VFIO_IRQ_SET_DATA_EVENTFD)
+ VFIO_IRQ_SET_DATA_EVENTFD | \
+ VFIO_IRQ_SET_DATA_MSI_IOVA)
#define VFIO_IRQ_SET_ACTION_TYPE_MASK (VFIO_IRQ_SET_ACTION_MASK | \
VFIO_IRQ_SET_ACTION_UNMASK | \
- VFIO_IRQ_SET_ACTION_TRIGGER)
+ VFIO_IRQ_SET_ACTION_TRIGGER | \
+ VFIO_IRQ_SET_ACTION_PREPARE)
/**
* VFIO_DEVICE_RESET - _IO(VFIO_TYPE, VFIO_BASE + 11)
*
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 8382c5834335..80ea6bc1941f 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -685,6 +685,8 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_core_device *vdev,
if (irq_is(vdev, index) && !count && (flags & VFIO_IRQ_SET_DATA_NONE)) {
vfio_msi_disable(vdev, msix);
+ for (i = start; i < start + count; i++)
+ vfio_iommufd_device_unset_msi_iova(&vdev->vdev, i);
return 0;
}
@@ -728,6 +730,47 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_core_device *vdev,
return 0;
}
+static int vfio_pci_set_msi_prepare(struct vfio_pci_core_device *vdev,
+ unsigned int index, unsigned int start,
+ unsigned int count, uint32_t flags,
+ void *data)
+{
+ struct vfio_device *core = &vdev->vdev;
+ uint64_t *iovas = data;
+ unsigned int i;
+ int ret;
+
+ if (!vfio_iommufd_device_ictx(core))
+ return -EOPNOTSUPP;
+ if (!(irq_is(vdev, index) || is_irq_none(vdev)))
+ return -EINVAL;
+
+ if (flags & VFIO_IRQ_SET_DATA_NONE) {
+ if (!count)
+ return -EINVAL;
+ for (i = start; i < start + count; i++)
+ vfio_iommufd_device_unset_msi_iova(core, i);
+ return 0;
+ }
+
+ if (!(flags & VFIO_IRQ_SET_DATA_MSI_IOVA))
+ return -EOPNOTSUPP;
+ if (!IS_ENABLED(CONFIG_IRQ_MSI_IOMMU))
+ return -EOPNOTSUPP;
+
+ ret = vfio_iommufd_device_set_num_msi_iovas(core, start + count);
+ if (ret)
+ return ret;
+
+ for (i = start; i < start + count; i++) {
+ ret = vfio_iommufd_device_set_msi_iova(core, i, iovas[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx,
unsigned int count, uint32_t flags,
void *data)
@@ -837,6 +880,9 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev, uint32_t flags,
case VFIO_IRQ_SET_ACTION_TRIGGER:
func = vfio_pci_set_msi_trigger;
break;
+ case VFIO_IRQ_SET_ACTION_PREPARE:
+ func = vfio_pci_set_msi_prepare;
+ break;
}
break;
case VFIO_PCI_ERR_IRQ_INDEX:
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 1fd261efc582..ad11c8e7da7b 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -1554,6 +1554,9 @@ int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs,
case VFIO_IRQ_SET_DATA_EVENTFD:
size = sizeof(int32_t);
break;
+ case VFIO_IRQ_SET_DATA_MSI_IOVA:
+ size = sizeof(uint64_t);
+ break;
default:
return -EINVAL;
}
--
2.43.0
Powered by blists - more mailing lists