Documentation/ABI/testing/sysfs-bus-pci | 29 ++- drivers/iommu/iommu.c | 22 ++ drivers/iommu/iommufd/Makefile | 5 +- drivers/iommu/iommufd/device.c | 7 +- drivers/iommu/iommufd/iommufd_private.h | 32 +++ drivers/iommu/iommufd/main.c | 3 + drivers/iommu/iommufd/selftest.c | 2 +- drivers/iommu/iommufd/tsm.c | 98 ++++++++ drivers/iommu/iommufd/viommu.c | 36 ++- drivers/iommu/iommufd/viommu_provider.c | 160 ++++++++++++ drivers/pci/tsm/core.c | 312 ++++++++++-------------- drivers/s390/crypto/vfio_ap_ops.c | 5 +- drivers/vfio/device_cdev.c | 14 +- drivers/vfio/group.c | 14 +- drivers/vfio/iommufd.c | 3 +- drivers/vfio/pci/vfio_pci_zdev.c | 7 +- drivers/vfio/vfio.h | 16 +- drivers/vfio/vfio_main.c | 81 +++--- drivers/virt/coco/tsm-core.c | 55 ++++- include/linux/iommu.h | 15 ++ include/linux/iommufd.h | 42 +++- include/linux/kvm_host.h | 3 + include/linux/pci-tsm.h | 140 ++++------- include/linux/tsm.h | 38 +++ include/linux/vfio.h | 17 +- include/uapi/linux/iommufd.h | 73 ++++++ samples/devsec/link_tsm.c | 146 ----------- tools/testing/devsec/devsec.sh | 27 +- virt/kvm/kvm_main.c | 2 + 29 files changed, 866 insertions(+), 538 deletions(-) create mode 100644 drivers/iommu/iommufd/tsm.c create mode 100644 drivers/iommu/iommufd/viommu_provider.c
This series adds the IOMMUFD and PCI/TSM infrastructure required for device assignment. It introduces an IOMMUFD-owned vIOMMU provider registry and the IOMMU_VDEVICE_TSM_REQ ioctl. The series adds a vIOMMU provider abstraction that allows a subsystem other than the physical IOMMU driver to implement a vIOMMU type. It groups the vIOMMU operations with their module owner and private data, and makes that implementation discoverable during vIOMMU allocation. External providers are selected by exact vIOMMU type. When no provider matches, vIOMMU creation falls back to the physical IOMMU driver. Once a provider matches, its result is authoritative and failures do not trigger fallback. Guest TSM requests are dispatched through the vdevice. PCI/TSM uses reference-counted contexts to retain the resources needed by providers, without introducing separate IOMMUFD TSM bind or unbind ioctls. Note: Codex was used to assist with commit message formatting and code rearrangement. Changes from v5: https://lore.kernel.org/all/20260525154816.1029642-1-aneesh.kumar@kernel.org * Replace the TSM bind/unbind interface with reference-counted contexts. * Add the IOMMUFD vIOMMU provider abstraction. * Route TSM guest requests through viommu operations. Changes from v4: https://lore.kernel.org/all/20260427061005.901854-1-aneesh.kumar@kernel.org * Switch VFIO/iommufd to use struct file *kvm_file instead of relying on kvm->users_count references. * Define TSM request scope values globally in iommufd. * Rename the ioctl to IOMMU_VDEVICE_TSM_REQ. * Address other review feedback. Changes from v2: https://lore.kernel.org/all/20260309111704.2330479-1-aneesh.kumar@kernel.org * Bump the series revision to v4 to keep it in sync with the dependent CCA DA patchsets. There was no v3 posting. * Drop [PATCH v2 1/3] iommufd/viommu: Allow associating a KVM VM fd with a vIOMMU * Add two new patches to associate a struct kvm * with iommufd objects: iommufd/device: Associate a kvm pointer to iommufd_device iommufd/viommu: Associate a kvm pointer to iommufd_viommu * Address review feedback Changes from v1: https://lore.kernel.org/all/20250728135216.48084-8-aneesh.kumar@kernel.org * Rebase onto the latest kernel * Address review feedback * Drop the TSM map ioctl; the KVM prefault patch will be used instead to ensure that private memory is preallocated Cc: Jason Gunthorpe <jgg@ziepe.ca> Cc: Alexey Kardashevskiy <aik@amd.com> Cc: Bjorn Helgaas <helgaas@kernel.org> Cc: Joerg Roedel <joro@8bytes.org> Cc: Jonathan Cameron <jic23@kernel.org> Cc: Kevin Tian <kevin.tian@intel.com> Cc: Nicolin Chen <nicolinc@nvidia.com> Cc: Samuel Ortiz <sameo@rivosinc.com> Cc: Steven Price <steven.price@arm.com> Cc: Suzuki K Poulose <Suzuki.Poulose@arm.com> Cc: Will Deacon <will@kernel.org> Cc: Xu Yilun <yilun.xu@linux.intel.com> Cc: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Aneesh Kumar K.V (Arm) (9): vfio: cache KVM VM file references instead of raw struct kvm pointers vfio: cdev: Reject duplicate bind before updating KVM file iommu: Add a helper to validate a vIOMMU parent iommu: Add a helper to query vIOMMU hardware parameters coco: tsm: Expose active-user lifetime references iommufd: Add vIOMMU provider support iommufd: Add the vdevice TSM request ioctl PCI/TSM: Remove the legacy guest request interface PCI/TSM: Add reference-counted contexts for vdevice providers Nicolin Chen (1): iommufd/viommu: Keep a reference to the KVM file Shameer Kolothum (1): iommufd/device: Associate KVM file pointer with iommufd_device Documentation/ABI/testing/sysfs-bus-pci | 29 ++- drivers/iommu/iommu.c | 22 ++ drivers/iommu/iommufd/Makefile | 5 +- drivers/iommu/iommufd/device.c | 7 +- drivers/iommu/iommufd/iommufd_private.h | 32 +++ drivers/iommu/iommufd/main.c | 3 + drivers/iommu/iommufd/selftest.c | 2 +- drivers/iommu/iommufd/tsm.c | 98 ++++++++ drivers/iommu/iommufd/viommu.c | 36 ++- drivers/iommu/iommufd/viommu_provider.c | 160 ++++++++++++ drivers/pci/tsm/core.c | 312 ++++++++++-------------- drivers/s390/crypto/vfio_ap_ops.c | 5 +- drivers/vfio/device_cdev.c | 14 +- drivers/vfio/group.c | 14 +- drivers/vfio/iommufd.c | 3 +- drivers/vfio/pci/vfio_pci_zdev.c | 7 +- drivers/vfio/vfio.h | 16 +- drivers/vfio/vfio_main.c | 81 +++--- drivers/virt/coco/tsm-core.c | 55 ++++- include/linux/iommu.h | 15 ++ include/linux/iommufd.h | 42 +++- include/linux/kvm_host.h | 3 + include/linux/pci-tsm.h | 140 ++++------- include/linux/tsm.h | 38 +++ include/linux/vfio.h | 17 +- include/uapi/linux/iommufd.h | 73 ++++++ samples/devsec/link_tsm.c | 146 ----------- tools/testing/devsec/devsec.sh | 27 +- virt/kvm/kvm_main.c | 2 + 29 files changed, 866 insertions(+), 538 deletions(-) create mode 100644 drivers/iommu/iommufd/tsm.c create mode 100644 drivers/iommu/iommufd/viommu_provider.c -- 2.43.0
> From: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org> > Sent: Thursday, September 17, 2026 10:02 PM > > This series adds the IOMMUFD and PCI/TSM infrastructure required for device > assignment. It introduces an IOMMUFD-owned vIOMMU provider registry and > the > IOMMU_VDEVICE_TSM_REQ ioctl. > > The series adds a vIOMMU provider abstraction that allows a subsystem > other than the physical IOMMU driver to implement a vIOMMU type. It groups > the vIOMMU operations with their module owner and private data, and makes > that implementation discoverable during vIOMMU allocation. > > External providers are selected by exact vIOMMU type. When no provider > matches, vIOMMU creation falls back to the physical IOMMU driver. Once a > provider matches, its result is authoritative and failures do not trigger > fallback. > I wonder whether this abstraction is necessary. The underlying IOMMU driver still needs to understand this vIOMMU type to check vendor-specific compatibility and provide the relevant hardware parameters. There may also be further vendor-specific interactions between the IOMMU and TSM drivers. In that case, the abstraction risks becoming little more than a connection between two vendor-specific drivers, while making it harder to maintain a clear scope for its operations. Would it be simpler to provide helper APIs and let the IOMMU driver use its own interface to delegate vIOMMU operations to the TSM driver? From iommufd's perspective, the vIOMMU type and its operations would still be handled by the IOMMU driver.
On Thu, Sep 24, 2026 at 07:48:08AM +0000, Tian, Kevin wrote: > > From: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org> > > Sent: Thursday, September 17, 2026 10:02 PM > > > > This series adds the IOMMUFD and PCI/TSM infrastructure required for device > > assignment. It introduces an IOMMUFD-owned vIOMMU provider registry and > > the > > IOMMU_VDEVICE_TSM_REQ ioctl. > > > > The series adds a vIOMMU provider abstraction that allows a subsystem > > other than the physical IOMMU driver to implement a vIOMMU type. It groups > > the vIOMMU operations with their module owner and private data, and makes > > that implementation discoverable during vIOMMU allocation. > > > > External providers are selected by exact vIOMMU type. When no provider > > matches, vIOMMU creation falls back to the physical IOMMU driver. Once a > > provider matches, its result is authoritative and failures do not trigger > > fallback. > > > > I wonder whether this abstraction is necessary. The main purpose and point would be to keep the TSM code in TSM and out of iommu drivers. And we don't want a module dependency from iommu -> tsm either.. > The underlying IOMMU driver still needs to understand this vIOMMU type > to check vendor-specific compatibility and provide the relevant hardware > parameters. It shouldn't, if the user requestes a TSM iommu type that should go directly to the TSM driver, and the TSM driver should involve its physical iommu as necessary. > There may also be further vendor-specific interactions between > the IOMMU and TSM drivers. This is the big question - how big is the entanglement. ARM's is small. What is Intel like? If Intel and ARM are small, and they should be because the T=1 VIOMMU is entirely handled by TDX/RMM for security, then I feel this is the right way for them. It keeps the code nicely isolated with only a tiny bridge. AMD is probably not like that. > In that case, the abstraction risks becoming little more than a > connection between two vendor-specific drivers, while making it > harder to maintain a clear scope for its operations. Glancing through these patches I think the abstraction may be too big, really the point is to allow TSM to create a viommu, I'm a little confused why there is so much stuff here. > Would it be simpler to provide helper APIs and let the IOMMU driver use > its own interface to delegate vIOMMU operations to the TSM driver? Now iommu driver module depends on TSM, do not want. Jason
On Thu, Sep 17, 2026 at 07:31:48PM +0530, Aneesh Kumar K.V (Arm) wrote: > This series adds the IOMMUFD and PCI/TSM infrastructure required for device > assignment. It introduces an IOMMUFD-owned vIOMMU provider registry and the > IOMMU_VDEVICE_TSM_REQ ioctl. I couldn't guess how to apply this with b4 review. Since it requires the series to apply I can't use it without knowing your base.. .. and for some reason this series doesn't have a base-commit trailer .. nor does it specify a git URL to find it on. I strongly recommend consistently doing both of these, by script, so it happens right every time. Please send all your series in a rigerous way. Make sure you have a script that does all of this stuff, ideally automatically. I have one if you want to see it.. Anyhow, I used a crazy AI prompt to make this apply on top of the last tsm series.. Jason
"Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org> writes:
> This series adds the IOMMUFD and PCI/TSM infrastructure required for device
> assignment. It introduces an IOMMUFD-owned vIOMMU provider registry and the
> IOMMU_VDEVICE_TSM_REQ ioctl.
>
> The series adds a vIOMMU provider abstraction that allows a subsystem
> other than the physical IOMMU driver to implement a vIOMMU type. It groups
> the vIOMMU operations with their module owner and private data, and makes
> that implementation discoverable during vIOMMU allocation.
>
> External providers are selected by exact vIOMMU type. When no provider
> matches, vIOMMU creation falls back to the physical IOMMU driver. Once a
> provider matches, its result is authoritative and failures do not trigger
> fallback.
>
> Guest TSM requests are dispatched through the vdevice. PCI/TSM uses
> reference-counted contexts to retain the resources needed by providers,
> without introducing separate IOMMUFD TSM bind or unbind ioctls.
>
> Note: Codex was used to assist with commit message formatting and code
> rearrangement.
>
[ ... 99 lines skipped ... ]
Related Arm CCA host changes is below
commit 66225895e48fa38b13aea493e1e6e3babab8f6aa
Author: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
Date: Wed Sep 16 14:06:15 2026 +0530
virt: arm-cca-host: Register the Realm vIOMMU provider with IOMMUFD
Register the Realm SMMUv3 provider directly with IOMMUFD. Retain active TSM
resources until the final provider release and remove the registration
before TSM teardown.
Create CCA-owned vdevices using PCI/TSM contexts, balance pSMMU stream-
table lifetime, and mark a function bound only after successful
initialization. Keep the KVM file and active pSMMU alive through the vIOMMU
lifetime.
diff --git a/drivers/virt/coco/arm-cca-host/Kconfig b/drivers/virt/coco/arm-cca-host/Kconfig
index 4a2bc64c2568..d0c636f92d9e 100644
--- a/drivers/virt/coco/arm-cca-host/Kconfig
+++ b/drivers/virt/coco/arm-cca-host/Kconfig
@@ -7,6 +7,7 @@ config ARM_CCA_HOST
depends on ARM64
depends on PCI
depends on ARM_RMM
+ depends on IOMMUFD
depends on HAVE_ARM_SMCCC_DISCOVERY
select PCI_TSM
select KEYS
diff --git a/drivers/virt/coco/arm-cca-host/Makefile b/drivers/virt/coco/arm-cca-host/Makefile
index d48e8940af46..2732352a7ae2 100644
--- a/drivers/virt/coco/arm-cca-host/Makefile
+++ b/drivers/virt/coco/arm-cca-host/Makefile
@@ -2,4 +2,4 @@
#
obj-$(CONFIG_ARM_CCA_HOST) += arm-cca-host.o
-arm-cca-host-y += arm-cca.o rmi-da.o
+arm-cca-host-y += arm-cca.o rmi-da.o viommu.o
diff --git a/drivers/virt/coco/arm-cca-host/arm-cca.c b/drivers/virt/coco/arm-cca-host/arm-cca.c
index 182733e00dfc..b5d50685eaeb 100644
--- a/drivers/virt/coco/arm-cca-host/arm-cca.c
+++ b/drivers/virt/coco/arm-cca-host/arm-cca.c
@@ -5,6 +5,7 @@
#include <linux/arm-smccc.h>
#include <linux/arm-smccc-bus.h>
+#include <linux/iommufd.h>
#include <linux/pci-tsm.h>
#include <linux/pci-ide.h>
#include <linux/module.h>
@@ -427,6 +428,24 @@ static struct pci_tsm_ops cca_link_pci_ops = {
.disconnect = cca_tsm_disconnect,
};
+static void cca_viommu_provider_release(void *data)
+{
+ tsm_put(data);
+}
+
+static const struct iommufd_viommu_provider_ops cca_viommu_provider_ops = {
+ .owner = THIS_MODULE,
+ .type = IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3,
+ .get_size = cca_viommu_get_size,
+ .init = cca_viommu_init,
+ .release = cca_viommu_provider_release,
+};
+
+static void cca_viommu_provider_remove(void *provider)
+{
+ iommufd_unregister_viommu_provider(provider);
+}
+
static void cca_link_tsm_remove(void *tsm_dev)
{
tsm_unregister(tsm_dev);
@@ -439,7 +458,9 @@ static bool rmi_has_reg2_feature(unsigned long feature)
static int cca_link_tsm_probe(struct arm_smccc_device *sdev)
{
+ struct iommufd_viommu_provider *provider;
struct tsm_dev *tsm_dev;
+ int ret;
if (!rmi_has_reg2_feature(RMI_FEATURE_REGISTER_2_DA))
return -ENODEV;
@@ -448,8 +469,22 @@ static int cca_link_tsm_probe(struct arm_smccc_device *sdev)
if (IS_ERR(tsm_dev))
return PTR_ERR(tsm_dev);
- return devm_add_action_or_reset(&sdev->dev, cca_link_tsm_remove,
- tsm_dev);
+ ret = devm_add_action_or_reset(&sdev->dev, cca_link_tsm_remove, tsm_dev);
+ if (ret)
+ return ret;
+
+ /* Retain PCI/TSM resources until the last provider user is released. */
+ tsm_get(tsm_dev);
+ provider = iommufd_register_viommu_provider(&cca_viommu_provider_ops,
+ tsm_dev);
+ if (IS_ERR(provider)) {
+ tsm_put(tsm_dev);
+ return PTR_ERR(provider);
+ }
+
+ /* Remove from lookup before the earlier TSM unregister action runs. */
+ return devm_add_action_or_reset(&sdev->dev, cca_viommu_provider_remove,
+ provider);
}
static const struct arm_smccc_device_id cca_link_tsm_id_table[] = {
diff --git a/drivers/virt/coco/arm-cca-host/rmi-da.h b/drivers/virt/coco/arm-cca-host/rmi-da.h
index 306f64749f26..07642eeb3245 100644
--- a/drivers/virt/coco/arm-cca-host/rmi-da.h
+++ b/drivers/virt/coco/arm-cca-host/rmi-da.h
@@ -16,6 +16,11 @@
#include <linux/atomic.h>
#include <linux/kref.h>
#include <linux/wait.h>
+#include <uapi/linux/iommufd.h>
+
+struct iommufd_viommu;
+struct iommu_domain;
+struct iommu_user_data;
#define MAX_CACHE_OBJ_SIZE SZ_16M
#define CACHE_CHUNK_SIZE SZ_4K
@@ -119,6 +124,11 @@ struct cca_host_fn_dsc {
struct pci_tsm pci;
};
+size_t cca_viommu_get_size(struct device *dev, enum iommu_viommu_type type);
+int cca_viommu_init(struct iommufd_viommu *viommu, struct device *dev,
+ struct iommu_domain *parent,
+ const struct iommu_user_data *user_data);
+
enum dev_comm_type {
PDEV_COMMUNICATE = 0x1,
VDEV_COMMUNICATE = 0x2,
diff --git a/drivers/virt/coco/arm-cca-host/viommu.c b/drivers/virt/coco/arm-cca-host/viommu.c
index 5cd261551b17..9daa3ff3ca1c 100644
--- a/drivers/virt/coco/arm-cca-host/viommu.c
+++ b/drivers/virt/coco/arm-cca-host/viommu.c
@@ -32,6 +32,13 @@ struct cca_viommu {
struct cca_psmmu *psmmu;
};
+struct cca_vdevice {
+ struct iommufd_vdevice core;
+ struct pci_tsm_context *tsm_context;
+ struct cca_host_tdi host_tdi;
+ u32 l2_sid;
+};
+
static LIST_HEAD(cca_psmmus);
static DEFINE_MUTEX(cca_psmmus_lock);
@@ -40,6 +47,11 @@ static struct cca_viommu *to_cca_viommu(struct iommufd_viommu *viommu)
return container_of(viommu, struct cca_viommu, core);
}
+static struct tsm_dev *cca_viommu_tsm_dev(struct iommufd_viommu *viommu)
+{
+ return viommu->provider_data;
+}
+
static struct cca_psmmu *
cca_psmmu_get(const struct arm_smmu_realm_params *params)
{
@@ -99,3 +111,192 @@ static void cca_psmmu_put(struct cca_psmmu *psmmu)
list_del(&psmmu->node);
kfree(psmmu);
}
+
+static void cca_viommu_destroy(struct iommufd_viommu *viommu)
+{
+ struct cca_viommu *cca = to_cca_viommu(viommu);
+
+ if (cca->psmmu)
+ cca_psmmu_put(cca->psmmu);
+}
+
+static int cca_psmmu_create_l2(struct cca_psmmu *psmmu, u32 l2_sid)
+{
+ unsigned long rmi_ret = 0;
+ int ret;
+
+ guard(mutex)(&cca_psmmus_lock);
+ ret = rmi_psmmu_st_l2_create(psmmu->phys, l2_sid, &rmi_ret);
+ if (!ret && !rmi_ret)
+ return 0;
+ if (RMI_RETURN_STATUS(rmi_ret) == RMI_ERROR_PSMMU_ST &&
+ RMI_RETURN_INDEX(rmi_ret) == 2)
+ return 0;
+ return -EIO;
+}
+
+static void cca_psmmu_destroy_l2(struct cca_psmmu *psmmu, u32 l2_sid,
+ struct device *dev)
+{
+ unsigned long rmi_ret = 0;
+ int ret;
+
+ guard(mutex)(&cca_psmmus_lock);
+ ret = rmi_psmmu_st_l2_destroy(psmmu->phys, l2_sid, &rmi_ret);
+ if (!ret && !rmi_ret)
+ return;
+ if (RMI_RETURN_STATUS(rmi_ret) == RMI_ERROR_PSMMU_ST &&
+ RMI_RETURN_INDEX(rmi_ret) == 2)
+ return;
+ dev_warn(dev, "failed to destroy Realm stream mapping\n");
+}
+
+static void cca_vdevice_destroy(struct iommufd_vdevice *vdev)
+{
+ struct cca_vdevice *cca_vdev =
+ container_of(vdev, struct cca_vdevice, core);
+ struct cca_viommu *cca = to_cca_viommu(vdev->viommu);
+ struct device *dev = iommufd_vdevice_to_device(vdev);
+ struct pci_tsm_context *context = cca_vdev->tsm_context;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_tsm_pf0 *pf0 = pci_tsm_context_pf0(context);
+ struct pci_dev *dsm_dev = pci_tsm_context_dsm_dev(context);
+ struct cca_host_tdi *host_tdi = &cca_vdev->host_tdi;
+ struct realm *realm = &host_tdi->kvm->arch.realm;
+
+ scoped_guard(mutex, &pf0->lock) {
+ cca_vdev_destroy(host_tdi, realm, pdev, dsm_dev);
+ kvfree(host_tdi->interface_report);
+ kvfree(host_tdi->measurements);
+ cca_psmmu_destroy_l2(cca->psmmu, cca_vdev->l2_sid, dev);
+ }
+ pci_tsm_context_put(context);
+}
+
+static int cca_vdevice_init(struct iommufd_vdevice *vdev)
+{
+ struct cca_vdevice *cca_vdev =
+ container_of(vdev, struct cca_vdevice, core);
+ struct arm_smmu_realm_params params;
+ struct cca_viommu *cca = to_cca_viommu(vdev->viommu);
+ struct cca_psmmu *psmmu = cca->psmmu;
+ struct device *dev = iommufd_vdevice_to_device(vdev);
+ struct tsm_dev *tsm_dev = cca_viommu_tsm_dev(vdev->viommu);
+ struct pci_tsm_context *context;
+ struct pci_dev *pdev;
+ struct pci_tsm_pf0 *pf0;
+ struct pci_dev *dsm_dev;
+ struct cca_host_tdi *host_tdi = &cca_vdev->host_tdi;
+ struct kvm *kvm = vdev->viommu->kvm_file->private_data;
+ void *rmm_vdev;
+ int ret;
+
+ if (!dev_is_pci(dev))
+ return 0;
+ /* Devices without a Link TSM remain ordinary vdevices. */
+ pdev = to_pci_dev(dev);
+ context = pci_tsm_context_get(pdev);
+ if (IS_ERR(context)) {
+ if (PTR_ERR(context) == -EOPNOTSUPP)
+ return 0;
+ return PTR_ERR(context);
+ }
+ if (pci_tsm_context_tsm_dev(context) != tsm_dev) {
+ ret = -EXDEV;
+ goto out_put_context;
+ }
+
+ ret = iommu_viommu_get_params(dev,
+ IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3, ¶ms,
+ sizeof(params));
+ if (ret)
+ goto out_put_context;
+ if (params.psmmu_phys != psmmu->phys) {
+ ret = -EINVAL;
+ goto out_put_context;
+ }
+
+ host_tdi->kvm = kvm;
+ cca_vdev->l2_sid = params.l2_sid;
+ pf0 = pci_tsm_context_pf0(context);
+ dsm_dev = pci_tsm_context_dsm_dev(context);
+
+ scoped_guard(mutex, &pf0->lock) {
+ ret = cca_psmmu_create_l2(psmmu, params.l2_sid);
+ if (!ret) {
+ rmm_vdev = cca_vdev_create(host_tdi, &kvm->arch.realm,
+ pdev, dsm_dev, vdev->virt_id);
+ if (IS_ERR_OR_NULL(rmm_vdev)) {
+ ret = rmm_vdev ? PTR_ERR(rmm_vdev) : -ENOMEM;
+ cca_psmmu_destroy_l2(psmmu, params.l2_sid, dev);
+ }
+ }
+ if (!ret)
+ pci_tsm_context_mark_bound(context);
+ }
+ if (ret)
+ goto out_put_context;
+ cca_vdev->tsm_context = context;
+ vdev->destroy = cca_vdevice_destroy;
+ return 0;
+
+out_put_context:
+ pci_tsm_context_put(context);
+ return ret;
+}
+
+static const struct iommufd_viommu_ops cca_viommu_ops = {
+ .destroy = cca_viommu_destroy,
+ .vdevice_size = VDEVICE_STRUCT_SIZE(struct cca_vdevice, core),
+ .vdevice_init = cca_vdevice_init,
+};
+
+size_t cca_viommu_get_size(struct device *dev, enum iommu_viommu_type type)
+{
+ struct arm_smmu_realm_params params;
+
+ if (type != IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3)
+ return 0;
+ if (iommu_viommu_get_params(dev, type, ¶ms, sizeof(params)))
+ return 0;
+ return VIOMMU_STRUCT_SIZE(struct cca_viommu, core);
+}
+
+int cca_viommu_init(struct iommufd_viommu *viommu, struct device *dev,
+ struct iommu_domain *parent,
+ const struct iommu_user_data *user_data)
+{
+ struct arm_smmu_realm_params params;
+ struct cca_viommu *cca = to_cca_viommu(viommu);
+ struct cca_psmmu *psmmu;
+ struct kvm *kvm;
+ int ret;
+
+ (void)user_data;
+
+ if (viommu->type != IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3)
+ return -EOPNOTSUPP;
+ if (!viommu->kvm_file)
+ return -EINVAL;
+ kvm = viommu->kvm_file->private_data;
+ ret = kvm_realm_ensure_created(kvm);
+ if (ret)
+ return ret;
+
+ ret = iommu_viommu_validate_parent(dev, viommu->type, parent);
+ if (ret)
+ return ret;
+ ret = iommu_viommu_get_params(dev, viommu->type, ¶ms,
+ sizeof(params));
+ if (ret)
+ return ret;
+
+ psmmu = cca_psmmu_get(¶ms);
+ if (IS_ERR(psmmu))
+ return PTR_ERR(psmmu);
+ cca->psmmu = psmmu;
+ viommu->ops = &cca_viommu_ops;
+ return 0;
+}
+
+MODULE_IMPORT_NS("IOMMUFD");
© 2016 - 2026 Red Hat, Inc.