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: 35+ 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:23 ` sashiko-bot
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:27 ` sashiko-bot
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:32 ` sashiko-bot
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:36 ` sashiko-bot
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:40 ` sashiko-bot
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:43 ` sashiko-bot
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:46 ` sashiko-bot
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:54 ` sashiko-bot
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:56 ` sashiko-bot
2026-11-04 16:16 ` [PATCH v8 10/15] PCI/TSM: Add vIOMMU-bound device contexts Aneesh Kumar K.V (Arm)
2026-11-04 17:07 ` sashiko-bot
2026-11-04 16:16 ` [PATCH v8 11/15] iommufd/viommu: Select vIOMMU operations before allocation Aneesh Kumar K.V (Arm)
2026-11-04 17:14 ` sashiko-bot
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 17:19 ` sashiko-bot
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 17:25 ` sashiko-bot
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 17:41 ` sashiko-bot
2026-11-04 16:16 ` [PATCH v8 15/15] PCI/TSM: Wait for users during unregister Aneesh Kumar K.V (Arm)
2026-11-04 18:00 ` sashiko-bot
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.