From: Jacob Pan <jacob.pan@linux.microsoft.com>
To: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>
Cc: iommu@lists.linux.dev, Alex Williamson <alex@shazbot.org>,
Alexey Kardashevskiy <aik@amd.com>,
Bjorn Helgaas <bhelgaas@google.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Jason Gunthorpe <jgg@ziepe.ca>, Joerg Roedel <joro@8bytes.org>,
Jonathan Cameron <jic23@kernel.org>,
Jonathan Hunter <jonathanh@nvidia.com>,
Kevin Tian <kevin.tian@intel.com>,
Krishna Reddy <vdumpa@nvidia.com>, Lukas Wunner <lukas@wunner.de>,
Nicolin Chen <nicolinc@nvidia.com>,
Robin Murphy <robin.murphy@arm.com>,
Samuel Ortiz <sameo@rivosinc.com>,
Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>,
Steven Price <steven.price@arm.com>,
Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Thierry Reding <thierry.reding@kernel.org>,
Vasant Hegde <vasant.hegde@amd.com>,
Will Deacon <will@kernel.org>,
Xu Yilun <yilun.xu@linux.intel.com>,
kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-coco@lists.linux.dev, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org, linux-tegra@vger.kernel.org,
jacob.pan@linux.microsoft.com
Subject: Re: [PATCH v8 12/15] iommufd/viommu: Allow PCI TSM backends to provide vIOMMU operations
Date: Wed, 4 Nov 2026 15:23:51 -0800 [thread overview]
Message-ID: <20261104152351.00002565@linux.microsoft.com> (raw)
In-Reply-To: <20261104161632.3547423-13-aneesh.kumar@kernel.org>
Hi Aneesh,
On Wed, 4 Nov 2026 21:46:29 +0530
"Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org> wrote:
> In confidential-computing configurations, a vIOMMU may be implemented
> by a TEE Security Manager rather than by the physical IOMMU driver.
> Such an implementation also needs the TSM identity when creating and
> validating vdevices.
>
> Allow VIOMMU_ALLOC to first query the TSM associated with the target
> PCI device for vIOMMU operations. Fall back to the physical IOMMU
> driver when the TSM does not provide operations for the requested
> vIOMMU type.
>
> Resolve the PCI TSM association under pci_tsm_rwsem, pin the module
> providing the operations, and take a TSM device reference. Store the
> TSM device in the vIOMMU and release both references on allocation
> failure, fallback to the physical IOMMU driver, or vIOMMU
> destruction. Keep the module pinned until after dropping the device
> reference, since the final put may release the TSM device.
>
> The device reference preserves the TSM allocation. Backends providing
> vIOMMU operations must not unregister their TSM while the module is
> pinned, since the reference does not prevent backend resource
> teardown.
>
> This enables the Realm vIOMMU implementation to provide its operations
> through the PCI TSM backend and retain the TSM identity needed by its
> vdevices.
>
> Cc: Jason Gunthorpe <jgg@ziepe.ca>
> Cc: Kevin Tian <kevin.tian@intel.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: Will Deacon <will@kernel.org>
> Cc: Robin Murphy <robin.murphy@arm.com>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: iommu@lists.linux.dev
> Cc: linux-pci@vger.kernel.org
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
> drivers/iommu/iommufd/viommu.c | 35 +++++++++++++++++++++++++++-----
> drivers/pci/tsm/core.c | 22 ++++++++++++++++++++
> drivers/virt/coco/tsm-core.c | 37
> ++++++++++++++++++++++++++++++++++ include/linux/iommufd.h |
> 2 ++ include/linux/pci-tsm.h | 24 ++++++++++++++++++++++
> include/linux/tsm.h | 25 +++++++++++++++++++++++
> 6 files changed, 140 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iommu/iommufd/viommu.c
> b/drivers/iommu/iommufd/viommu.c index 16e8b6421f1f..1686f19c5060
> 100644 --- a/drivers/iommu/iommufd/viommu.c
> +++ b/drivers/iommu/iommufd/viommu.c
> @@ -15,6 +15,8 @@ void iommufd_viommu_destroy(struct iommufd_object
> *obj)
> if (viommu->ops && viommu->ops->destroy)
> viommu->ops->destroy(viommu);
> + if (viommu->tsm_dev)
> + tsm_put_device(viommu->tsm_dev);
> refcount_dec(&viommu->hwpt->common.obj.users);
> if (viommu->kvm_file)
> fput(viommu->kvm_file);
> @@ -30,6 +32,7 @@ int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd
> *ucmd) .len = cmd->data_len,
> };
> struct iommufd_hwpt_paging *hwpt_paging;
> + struct tsm_dev *tsm_dev = NULL;
> struct iommufd_viommu *viommu;
> struct iommufd_device *idev;
> struct iommu_device *iommu_dev;
> @@ -49,15 +52,33 @@ int iommufd_viommu_alloc_ioctl(struct
> iommufd_ucmd *ucmd) rc = -EOPNOTSUPP;
> goto out_put_idev;
> }
> - if (!iommu_dev->ops->get_viommu_ops) {
> - rc = -EOPNOTSUPP;
> + tsm_dev = tsm_get_device(idev->dev);
So I want to reuse this flow for MSHV since tsm already does module
pinning and locking for backend providers. Once MSHV supports TDISP, it
could register a link TSM similarly to the CCA cca_link_pci_ops.
However, we also want to use the same viommu/vdevice flow to support
non-confidential device assignment with Hypervisor managed S2 mapping.
I belive pKVM has the same need.[1]
I am thinking MSHV/pKVM can register an assignment-only tsm_dev to
leverage this? Could PCI/TSM support this role without device-security?
Something like:
@@ -48,7 +41,13 @@ struct pci_tsm_ops {
struct module *owner;
const struct iommufd_viommu_ops *(*viommu_get_ops)(
struct device *dev, enum iommu_viommu_type type);
+
+ struct pci_tsm_assignment_ops {
+ bool (*match)(struct pci_dev *pdev);
+ struct pci_tsm *(*probe)(struct tsm_dev *tsm_dev,
+ struct pci_dev *pdev);
+ void (*remove)(struct pci_tsm *tsm);
+ } assignment_ops;
[1] https://lore.kernel.org/linux-iommu/atiaKG86qcifKzBT@google.com/
> + if (IS_ERR(tsm_dev)) {
> + rc = PTR_ERR(tsm_dev);
> + tsm_dev = NULL;
> goto out_put_idev;
> }
> - ops = iommu_dev->ops->get_viommu_ops(idev->dev, cmd->type);
> - if (!ops) {
> - rc = -EOPNOTSUPP;
> + ops = tsm_dev ? tsm_viommu_get_ops(tsm_dev, idev->dev,
> cmd->type) : NULL;
> + if (IS_ERR(ops)) {
> + rc = PTR_ERR(ops);
> goto out_put_idev;
> }
> + if (!ops) {
> + if (tsm_dev) {
> + tsm_put_device(tsm_dev);
> + tsm_dev = NULL;
> + }
> + if (!iommu_dev->ops->get_viommu_ops) {
> + rc = -EOPNOTSUPP;
> + goto out_put_idev;
> + }
> + ops = iommu_dev->ops->get_viommu_ops(idev->dev,
> cmd->type);
> + if (!ops) {
> + rc = -EOPNOTSUPP;
> + goto out_put_idev;
> + }
> + }
> +
> /*
> * It is a driver bug to omit the required operations or
> provide a size
> * smaller than the core vIOMMU structure.
> @@ -95,6 +116,8 @@ int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd
> *ucmd) viommu->kvm_file = get_file(idev->kvm_file);
> viommu->type = cmd->type;
> viommu->ictx = ucmd->ictx;
> + viommu->tsm_dev = tsm_dev;
> + tsm_dev = NULL;
> viommu->hwpt = hwpt_paging;
> refcount_inc(&viommu->hwpt->common.obj.users);
> INIT_LIST_HEAD(&viommu->veventqs);
> @@ -119,6 +142,8 @@ int iommufd_viommu_alloc_ioctl(struct
> iommufd_ucmd *ucmd) out_put_hwpt:
> iommufd_put_object(ucmd->ictx, &hwpt_paging->common.obj);
> out_put_idev:
> + if (tsm_dev)
> + tsm_put_device(tsm_dev);
> iommufd_put_object(ucmd->ictx, &idev->obj);
> return rc;
> }
> diff --git a/drivers/pci/tsm/core.c b/drivers/pci/tsm/core.c
> index 96ba5a8be8af..5ded1a5a4f7e 100644
> --- a/drivers/pci/tsm/core.c
> +++ b/drivers/pci/tsm/core.c
> @@ -9,6 +9,8 @@
> #define dev_fmt(fmt) "PCI/TSM: " fmt
>
> #include <linux/bitfield.h>
> +#include <linux/iommufd.h>
> +#include <linux/module.h>
> #include <linux/pci.h>
> #include <linux/pci-doe.h>
> #include <linux/pci-tsm.h>
> @@ -36,6 +38,26 @@ static const struct pci_tsm_ops
> *to_pci_tsm_ops(struct pci_tsm *tsm) return tsm->tsm_dev->pci_ops;
> }
>
> +struct tsm_dev *pci_tsm_get_device(struct pci_dev *pdev)
> +{
> + const struct pci_tsm_ops *ops;
> + struct tsm_dev *tsm_dev;
> +
> + guard(rwsem_read)(&pci_tsm_rwsem);
> + if (!pdev->tsm)
> + return NULL;
> +
> + tsm_dev = pdev->tsm->tsm_dev;
> + ops = tsm_dev->pci_ops;
> + if (!ops->viommu_get_ops)
> + return NULL;
> + if (!try_module_get(ops->owner))
> + return ERR_PTR(-ENODEV);
> + get_device(&tsm_dev->dev);
> + return tsm_dev;
> +}
> +EXPORT_SYMBOL_GPL(pci_tsm_get_device);
> +
> static inline bool is_dsm(struct pci_dev *pdev)
> {
> return pdev->tsm && pdev->tsm->dsm_dev == pdev;
> diff --git a/drivers/virt/coco/tsm-core.c
> b/drivers/virt/coco/tsm-core.c index e7807dc94807..92ce3337f1ea 100644
> --- a/drivers/virt/coco/tsm-core.c
> +++ b/drivers/virt/coco/tsm-core.c
> @@ -9,6 +9,16 @@
> #include <linux/cleanup.h>
> #include <linux/pci-tsm.h>
>
> +/* The caller must hold a tsm_get_device() reference for the entire
> use. */ +const struct iommufd_viommu_ops *tsm_viommu_get_ops(struct
> tsm_dev *tsm_dev,
> + struct device *dev, enum iommu_viommu_type type)
> +{
> + if (!tsm_dev->pci_ops->viommu_get_ops)
> + return NULL;
> + return tsm_dev->pci_ops->viommu_get_ops(dev, type);
> +}
> +EXPORT_SYMBOL_GPL(tsm_viommu_get_ops);
> +
> static void tsm_release(struct device *);
> static const struct class tsm_class = {
> .name = "tsm",
> @@ -16,6 +26,33 @@ static const struct class tsm_class = {
> };
> static DEFINE_IDA(tsm_ida);
>
> +/**
> + * tsm_get_device() - Pin the TSM attached to a device
> + * @dev: device whose TSM is to be pinned
> + *
> + * A successful lookup takes a TSM device reference and pins the
> backend
> + * module. Release both with tsm_put_device(). Backends providing
> vIOMMU
> + * operations must not unregister their TSM independently of module
> unload.
> + * Return: NULL if no vIOMMU-capable TSM is attached, an error if
> the module
> + * cannot be pinned, or the TSM device associated with the pinned
> backend.
> + */
> +struct tsm_dev *tsm_get_device(struct device *dev)
> +{
> + if (!dev_is_pci(dev))
> + return NULL;
> + return pci_tsm_get_device(to_pci_dev(dev));
> +}
> +EXPORT_SYMBOL_GPL(tsm_get_device);
> +
> +void tsm_put_device(struct tsm_dev *tsm_dev)
> +{
> + struct module *owner = tsm_dev->pci_ops->owner;
> +
> + put_device(&tsm_dev->dev);
> + module_put(owner);
> +}
> +EXPORT_SYMBOL_GPL(tsm_put_device);
> +
> static int match_id(struct device *dev, const void *data)
> {
> struct tsm_dev *tsm_dev = container_of(dev, struct tsm_dev,
> dev); diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h
> index 5f5c67b24134..a4b29915d0ca 100644
> --- a/include/linux/iommufd.h
> +++ b/include/linux/iommufd.h
> @@ -23,6 +23,7 @@ struct iommufd_access;
> struct iommufd_ctx;
> struct iommufd_device;
> struct iommufd_viommu_ops;
> +struct tsm_dev;
> struct page;
>
> enum iommufd_object_type {
> @@ -104,6 +105,7 @@ struct iommufd_viommu {
> struct iommu_device *iommu_dev;
> struct iommufd_hwpt_paging *hwpt;
> struct file *kvm_file;
> + struct tsm_dev *tsm_dev;
>
> const struct iommufd_viommu_ops *ops;
>
> diff --git a/include/linux/pci-tsm.h b/include/linux/pci-tsm.h
> index eaf0199d01f7..19e9e0ef3bbb 100644
> --- a/include/linux/pci-tsm.h
> +++ b/include/linux/pci-tsm.h
> @@ -3,7 +3,10 @@
> #define __PCI_TSM_H
> #include <linux/mutex.h>
> #include <linux/pci.h>
> +#include <uapi/linux/iommufd.h>
>
> +struct iommufd_viommu_ops;
> +struct module;
> struct pci_tsm;
> struct pci_tsm_context;
> struct tsm_dev;
> @@ -16,12 +19,27 @@ struct tsm_dev;
> * @devsec_ops: Lock, unlock, and interrogate the security state of
> the
> * function via the platform TSM (typically virtual
> function
> * operations).
> + * @viommu_get_ops: Return operations for a supported TSM-owned
> vIOMMU type,
> + * or NULL if unsupported
> + * @owner: Module providing the vIOMMU operations, if built as a
> module
> + *
> + * The vIOMMU owner holds a TSM device reference and pins the
> backend module
> + * before querying @viommu_get_ops, releasing both after vIOMMU
> destruction.
> + * A backend providing this callback must not unregister its TSM
> while the
> + * module is pinned.
> *
> * This operations are mutually exclusive either a tsm_dev instance
> * manages physical link properties or it manages function security
> * states like TDISP lock/unlock.
> + *
> + * @viommu_get_ops runs with the backend module pinned. The PCI/TSM
> + * association is checked during acquisition under pci_tsm_rwsem.
> */
> struct pci_tsm_ops {
> + struct module *owner;
> + const struct iommufd_viommu_ops *(*viommu_get_ops)(
> + struct device *dev, enum iommu_viommu_type type);
> +
> /*
> * struct pci_tsm_link_ops - Manage physical link and the
> TSM/DSM session
> * @probe: establish context with the TSM (allocate / wrap
> 'struct @@ -151,6 +169,7 @@ struct pci_tsm_pf0
> *pci_tsm_context_pf0(struct pci_tsm_context *context); struct pci_dev
> *pci_tsm_context_dsm_dev(struct pci_tsm_context *context); bool
> pci_tsm_context_match_device(struct pci_tsm_context *context, struct
> pci_dev *pdev); +struct tsm_dev *pci_tsm_get_device(struct pci_dev
> *pdev); #else
> static inline int pci_tsm_register(struct tsm_dev *tsm_dev)
> {
> @@ -165,6 +184,11 @@ static inline bool pci_tsm_is_configured(struct
> pci_dev *pdev) return false;
> }
>
> +static inline struct tsm_dev *pci_tsm_get_device(struct pci_dev
> *pdev) +{
> + return NULL;
> +}
> +
> static inline struct pci_tsm_context *
> pci_tsm_context_get(struct pci_dev *pdev, struct tsm_dev
> *viommu_tsm_dev) {
> diff --git a/include/linux/tsm.h b/include/linux/tsm.h
> index 19dedf971f14..3d5286aeaa42 100644
> --- a/include/linux/tsm.h
> +++ b/include/linux/tsm.h
> @@ -110,6 +110,8 @@ struct tsm_report_ops {
> };
>
> struct pci_tsm_ops;
> +struct iommufd_viommu_ops;
> +
> struct tsm_dev {
> struct device dev;
> int id;
> @@ -124,4 +126,27 @@ int tsm_report_unregister(const struct
> tsm_report_ops *ops); struct tsm_dev *tsm_register(struct device
> *parent, struct pci_tsm_ops *ops); void tsm_unregister(struct tsm_dev
> *tsm_dev); struct tsm_dev *find_tsm_dev(int id);
> +
> +#ifdef CONFIG_TSM
> +struct tsm_dev *tsm_get_device(struct device *dev);
> +void tsm_put_device(struct tsm_dev *tsm_dev);
> +const struct iommufd_viommu_ops *tsm_viommu_get_ops(struct tsm_dev
> *tsm_dev,
> + struct device *dev, enum iommu_viommu_type type);
> +#else
> +static inline struct tsm_dev *tsm_get_device(struct device *dev)
> +{
> + return NULL;
> +}
> +
> +static inline void tsm_put_device(struct tsm_dev *tsm_dev)
> +{
> +}
> +
> +static inline const struct iommufd_viommu_ops *
> +tsm_viommu_get_ops(struct tsm_dev *tsm_dev, struct device *dev,
> + enum iommu_viommu_type type)
> +{
> + return NULL;
> +}
> +#endif
> #endif /* __TSM_H */
next prev parent reply other threads:[~2026-11-04 23:24 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 16:16 [PATCH v8 00/15] iommufd: TSM-backed virtual IOMMUs for confidential guests Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 01/15] PCI/TSM: Move core code into its own directory Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 02/15] virt: coco: tsm: Remove the device from lookup before PCI teardown Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 03/15] virt: coco: tsm: Complete PCI registration before publishing the device Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 04/15] virt: coco: tsm: Require PCI operations when registering a TSM Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 05/15] iommufd/device: Associate KVM file pointer with iommufd_device Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 06/15] iommufd/device: Hold a KVM file reference for the device lifetime Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 07/15] iommufd/viommu: Keep a reference to the KVM file Aneesh Kumar K.V (Arm)
2026-11-04 16:35 ` Jacob Pan
2026-11-04 16:16 ` [PATCH v8 08/15] iommufd: Add a vDEVICE operation ioctl framework Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 09/15] PCI/TSM: Remove the legacy guest request interface Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 10/15] PCI/TSM: Add vIOMMU-bound device contexts Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 11/15] iommufd/viommu: Select vIOMMU operations before allocation Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 12/15] iommufd/viommu: Allow PCI TSM backends to provide vIOMMU operations Aneesh Kumar K.V (Arm)
2026-11-04 23:23 ` Jacob Pan [this message]
2026-11-04 16:16 ` [PATCH v8 13/15] iommufd/viommu: Allow vIOMMUs without a parent HWPT Aneesh Kumar K.V (Arm)
2026-11-04 19:03 ` Nicolin Chen
2026-11-04 19:31 ` Jason Gunthorpe
2026-11-04 16:16 ` [PATCH v8 14/15] PCI/TSM: Wait for device contexts before removing a DSM Aneesh Kumar K.V (Arm)
2026-11-04 16:16 ` [PATCH v8 15/15] PCI/TSM: Wait for users during unregister Aneesh Kumar K.V (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261104152351.00002565@linux.microsoft.com \
--to=jacob.pan@linux.microsoft.com \
--cc=aik@amd.com \
--cc=alex@shazbot.org \
--cc=aneesh.kumar@kernel.org \
--cc=bhelgaas@google.com \
--cc=catalin.marinas@arm.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=jic23@kernel.org \
--cc=jonathanh@nvidia.com \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=nicolinc@nvidia.com \
--cc=robin.murphy@arm.com \
--cc=sameo@rivosinc.com \
--cc=shameerali.kolothum.thodi@huawei.com \
--cc=steven.price@arm.com \
--cc=suravee.suthikulpanit@amd.com \
--cc=suzuki.poulose@arm.com \
--cc=thierry.reding@kernel.org \
--cc=vasant.hegde@amd.com \
--cc=vdumpa@nvidia.com \
--cc=will@kernel.org \
--cc=yilun.xu@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox