From: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>
To: linux-coco@lists.linux.dev, iommu@lists.linux.dev,
linux-kernel@vger.kernel.org, kvm@vger.kernel.org
Cc: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
Alexey Kardashevskiy <aik@amd.com>,
Bjorn Helgaas <helgaas@kernel.org>,
Joerg Roedel <joro@8bytes.org>,
Jonathan Cameron <jic23@kernel.org>,
Kevin Tian <kevin.tian@intel.com>,
Nicolin Chen <nicolinc@nvidia.com>,
Samuel Ortiz <sameo@rivosinc.com>,
Steven Price <steven.price@arm.com>,
Suzuki K Poulose <Suzuki.Poulose@arm.com>,
Will Deacon <will@kernel.org>,
Xu Yilun <yilun.xu@linux.intel.com>,
Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>,
Paolo Bonzini <pbonzini@redhat.com>
Subject: [RFC PATCH v6 11/11] PCI/TSM: Add reference-counted contexts for vdevice providers
Date: Thu, 17 Sep 2026 19:31:59 +0530 [thread overview]
Message-ID: <20260917140159.1163281-12-aneesh.kumar@kernel.org> (raw)
In-Reply-To: <20260917140159.1163281-1-aneesh.kumar@kernel.org>
Replace the PCI/TSM bind/unbind interface with reference-counted
contexts that retain the function, DSM device and Link TSM for a vdevice
provider. Reject disconnect while a context is live.
Keep the existing bound sysfs attribute and derive its status from
successful provider binding, with balanced per-function accounting on
context release. Update the ABI documentation and retire the obsolete
sample bind/unbind operations in the same patch.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
Documentation/ABI/testing/sysfs-bus-pci | 29 ++-
drivers/pci/tsm/core.c | 256 +++++++++++++-----------
include/linux/pci-tsm.h | 85 +++++---
samples/devsec/link_tsm.c | 96 ---------
tools/testing/devsec/devsec.sh | 27 +--
5 files changed, 211 insertions(+), 282 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index c2a5c4fe9373..5288ea4ed343 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -657,6 +657,9 @@ Description:
to 'connect' to teardown the connection. This is a
"link" TSM attribute, see
Documentation/ABI/testing/sysfs-class-tsm.
+ The write fails with EBUSY while any vdevice depends on the
+ connection. Userspace must destroy those vdevices before
+ disconnecting the link.
What: /sys/bus/pci/devices/.../tsm/dsm
Contact: linux-coco@lists.linux.dev
@@ -676,17 +679,21 @@ Description: (RO) Return PCI device name of this device's DSM (Device
What: /sys/bus/pci/devices/.../tsm/bound
Contact: linux-coco@lists.linux.dev
-Description: (RO) Return the device name of the TSM when the device is in a
- TDISP (TEE Device Interface Security Protocol) operational state
- (LOCKED, RUN, or ERROR, not UNLOCKED). Bound devices consume
- platform TSM resources and depend on the device's configuration
- (e.g. BME (Bus Master Enable) and MSE (Memory Space Enable)
- among other settings) to remain stable for the duration of the
- bound state. This attribute is only visible for devices that
- support TDISP operation, and it is only populated after
- successful connect and TSM bind. The TSM bind operation is
- initiated by VFIO/IOMMUFD. This is a "link" TSM attribute, see
- Documentation/ABI/testing/sysfs-class-tsm.
+Description: (RO) Return the device name of the TSM when this PCI function
+ has a successfully initialized TSM-backed vdevice binding, or
+ an empty line when no such binding exists. The binding is
+ established through VFIO/IOMMUFD and remains visible until
+ the provider releases its context during vdevice teardown.
+ Merely connecting the device to a TSM or acquiring a context
+ does not establish a binding. Bindings of other functions
+ managed by the same DSM do not affect this attribute.
+
+ This reports the binding lifetime, not the current TDISP
+ (TEE Device Interface Security Protocol) state. A bound vdevice
+ may be UNLOCKED, and TDISP lock/unlock transitions do not
+ change this attribute. This attribute is only visible for
+ devices that support TDISP operation. This is a "link" TSM
+ attribute, see Documentation/ABI/testing/sysfs-class-tsm.
What: /sys/bus/pci/devices/.../authenticated
Contact: linux-pci@vger.kernel.org
diff --git a/drivers/pci/tsm/core.c b/drivers/pci/tsm/core.c
index c7e0d241e55d..667328d1c686 100644
--- a/drivers/pci/tsm/core.c
+++ b/drivers/pci/tsm/core.c
@@ -67,11 +67,10 @@ static struct pci_tsm_pf0 *to_pci_tsm_pf0(struct pci_tsm *tsm)
static inline bool is_devsec(struct pci_dev *pdev)
{
- return pdev->tsm && pdev->tsm->dsm_dev == NULL &&
- pdev->tsm->tdi == NULL;
+ return pdev->tsm && !pdev->tsm->dsm_dev;
}
-/* 'struct pci_tsm_devsec' wraps 'struct pci_tsm' when ->tdi == ->dsm == NULL */
+/* 'struct pci_tsm_devsec' wraps 'struct pci_tsm' when ->dsm_dev == NULL */
struct pci_tsm_devsec *to_pci_tsm_devsec(struct pci_tsm *tsm)
{
struct pci_dev *pdev = tsm->pdev;
@@ -315,96 +314,118 @@ static int remove_fn(struct pci_dev *pdev, void *data)
return 0;
}
-/*
- * Note, this helper only returns an error code and takes an argument for
- * compatibility with the pci_walk_bus() callback prototype. pci_tsm_unbind()
- * always succeeds.
- */
-static int __pci_tsm_unbind(struct pci_dev *pdev, void *data)
+bool pci_tsm_is_configured(struct pci_dev *pdev)
{
- struct pci_tdi *tdi;
- struct pci_tsm_pf0 *tsm_pf0;
-
- lockdep_assert_held(&pci_tsm_rwsem);
+ guard(rwsem_read)(&pci_tsm_rwsem);
- if (!pdev->tsm)
- return 0;
+ return !!pdev->tsm;
+}
+EXPORT_SYMBOL_GPL(pci_tsm_is_configured);
- tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
- guard(mutex)(&tsm_pf0->lock);
+struct pci_tsm_context {
+ struct pci_tsm_pf0 *pf0;
+ struct pci_dev *pdev;
+ struct pci_dev *dsm_dev;
+ struct tsm_dev *tsm_dev;
+ struct list_head bound_node;
+};
- tdi = pdev->tsm->tdi;
- if (!tdi)
- return 0;
+struct pci_tsm_context *pci_tsm_context_get(struct pci_dev *pdev)
+{
+ struct pci_tsm_context *context;
+ struct pci_tsm_pf0 *pf0;
+ struct device *tsm_device;
- to_pci_tsm_ops(pdev->tsm)->unbind(tdi);
- pdev->tsm->tdi = NULL;
+ guard(rwsem_read)(&pci_tsm_rwsem);
+ if (!pdev->tsm || !is_link_tsm(pdev->tsm->tsm_dev))
+ return ERR_PTR(-EOPNOTSUPP);
- return 0;
+ pf0 = to_pci_tsm_pf0(pdev->tsm);
+ if (!pf0)
+ return ERR_PTR(-ENXIO);
+
+ context = kzalloc_obj(*context);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+
+ guard(mutex)(&pf0->lock);
+ pf0->context_users++;
+ context->pf0 = pf0;
+ context->pdev = pci_dev_get(pdev);
+ INIT_LIST_HEAD(&context->bound_node);
+ context->dsm_dev = pci_dev_get(pf0->base_tsm.pdev);
+ tsm_device = get_device(&pdev->tsm->tsm_dev->dev);
+ context->tsm_dev = container_of(tsm_device, struct tsm_dev, dev);
+ return context;
}
+EXPORT_SYMBOL_GPL(pci_tsm_context_get);
-void pci_tsm_unbind(struct pci_dev *pdev)
+void pci_tsm_context_put(struct pci_tsm_context *context)
{
- guard(rwsem_read)(&pci_tsm_rwsem);
- __pci_tsm_unbind(pdev, NULL);
+ struct pci_tsm_pf0 *pf0 = context->pf0;
+
+ down_read(&pci_tsm_rwsem);
+ mutex_lock(&pf0->lock);
+ list_del(&context->bound_node);
+ if (!WARN_ON(!pf0->context_users))
+ pf0->context_users--;
+ mutex_unlock(&pf0->lock);
+ up_read(&pci_tsm_rwsem);
+
+ put_device(&context->tsm_dev->dev);
+ pci_dev_put(context->pdev);
+ pci_dev_put(context->dsm_dev);
+ kfree(context);
}
-EXPORT_SYMBOL_GPL(pci_tsm_unbind);
+EXPORT_SYMBOL_GPL(pci_tsm_context_put);
/**
- * pci_tsm_bind() - Bind @pdev as a TDI for @kvm
- * @pdev: PCI device function to bind
- * @kvm: Private memory attach context
- * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM
+ * pci_tsm_context_mark_bound() - Publish a successful per-function binding
+ * @context: context acquired for the bound PCI function
*
- * Returns 0 on success, or a negative error code on failure.
+ * Call once after the provider has successfully initialized the vdevice.
+ * The binding remains visible in tsm/bound until pci_tsm_context_put(),
+ * independently of the device's TDISP state. Acquiring a context alone
+ * does not establish a binding.
*
- * Context: Caller is responsible for constraining the bind lifetime to the
- * registered state of the device. For example, pci_tsm_bind() /
- * pci_tsm_unbind() limited to the VFIO driver bound state of the device.
+ * Context: Caller holds the context's pci_tsm_pf0::lock.
*/
-int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id)
+void pci_tsm_context_mark_bound(struct pci_tsm_context *context)
{
- struct pci_tsm_pf0 *tsm_pf0;
- struct pci_tdi *tdi;
-
- if (!kvm)
- return -EINVAL;
-
- guard(rwsem_read)(&pci_tsm_rwsem);
-
- if (!pdev->tsm)
- return -EINVAL;
-
- if (!is_link_tsm(pdev->tsm->tsm_dev))
- return -ENXIO;
-
- tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
- guard(mutex)(&tsm_pf0->lock);
-
- /* Resolve races to bind a TDI */
- if (pdev->tsm->tdi) {
- if (pdev->tsm->tdi->kvm != kvm)
- return -EBUSY;
- return 0;
- }
+ lockdep_assert_held(&context->pf0->lock);
+ list_add_tail(&context->bound_node, &context->pf0->bound_contexts);
+}
+EXPORT_SYMBOL_GPL(pci_tsm_context_mark_bound);
- tdi = to_pci_tsm_ops(pdev->tsm)->bind(pdev, kvm, tdi_id);
- if (IS_ERR(tdi))
- return PTR_ERR(tdi);
+struct tsm_dev *pci_tsm_context_tsm_dev(struct pci_tsm_context *context)
+{
+ return context->tsm_dev;
+}
+EXPORT_SYMBOL_GPL(pci_tsm_context_tsm_dev);
- pdev->tsm->tdi = tdi;
+struct pci_tsm_pf0 *pci_tsm_context_pf0(struct pci_tsm_context *context)
+{
+ return context->pf0;
+}
+EXPORT_SYMBOL_GPL(pci_tsm_context_pf0);
- return 0;
+struct pci_dev *pci_tsm_context_dsm_dev(struct pci_tsm_context *context)
+{
+ return context->dsm_dev;
}
-EXPORT_SYMBOL_GPL(pci_tsm_bind);
+EXPORT_SYMBOL_GPL(pci_tsm_context_dsm_dev);
-static void pci_tsm_unbind_all(struct pci_dev *pdev)
+bool pci_tsm_context_match_device(struct pci_tsm_context *context,
+ struct pci_dev *pdev)
{
- pci_tsm_walk_fns_reverse(pdev, __pci_tsm_unbind, NULL);
- __pci_tsm_unbind(pdev, NULL);
+ guard(rwsem_read)(&pci_tsm_rwsem);
+
+ return pdev->tsm && is_link_tsm(pdev->tsm->tsm_dev) &&
+ to_pci_tsm_pf0(pdev->tsm) == context->pf0;
}
+EXPORT_SYMBOL_GPL(pci_tsm_context_match_device);
-static void __pci_tsm_disconnect(struct pci_dev *pdev)
+static int __pci_tsm_disconnect(struct pci_dev *pdev)
{
struct pci_tsm_pf0 *tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
const struct pci_tsm_ops *ops = to_pci_tsm_ops(pdev->tsm);
@@ -412,21 +433,29 @@ static void __pci_tsm_disconnect(struct pci_dev *pdev)
/* disconnect() mutually exclusive with subfunction pci_tsm_init() */
lockdep_assert_held_write(&pci_tsm_rwsem);
- pci_tsm_unbind_all(pdev);
-
/*
- * disconnect() is uninterruptible as it may be called for device
- * teardown
+ * A vdevice holds a context for its lifetime. Refuse to tear down the
+ * link until userspace destroys all dependent vdevices.
+ *
+ * disconnect() is uninterruptible as it may also be called for device
+ * teardown.
*/
- guard(mutex)(&tsm_pf0->lock);
+ scoped_guard(mutex, &tsm_pf0->lock)
+ if (tsm_pf0->context_users)
+ return -EBUSY;
pci_tsm_walk_fns_reverse(pdev, remove_fn, NULL);
ops->disconnect(pdev);
+ return 0;
}
-static void pci_tsm_disconnect(struct pci_dev *pdev)
+static int pci_tsm_disconnect(struct pci_dev *pdev)
{
- __pci_tsm_disconnect(pdev);
+ int ret = __pci_tsm_disconnect(pdev);
+
+ if (ret)
+ return ret;
tsm_remove(pdev->tsm);
+ return 0;
}
static ssize_t disconnect_store(struct device *dev,
@@ -448,35 +477,43 @@ static ssize_t disconnect_store(struct device *dev,
if (!sysfs_streq(buf, dev_name(&tsm_dev->dev)))
return -EINVAL;
- pci_tsm_disconnect(pdev);
+ rc = pci_tsm_disconnect(pdev);
+ if (rc)
+ return rc;
return len;
}
static DEVICE_ATTR_WO(disconnect);
-static ssize_t bound_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t bound_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct pci_tsm_pf0 *tsm_pf0;
- struct pci_tsm *tsm;
+ struct pci_tsm_context *context;
+ struct pci_tsm_pf0 *pf0;
int rc;
ACQUIRE(rwsem_read_intr, lock)(&pci_tsm_rwsem);
- if ((rc = ACQUIRE_ERR(rwsem_read_intr, &lock)))
+ rc = ACQUIRE_ERR(rwsem_read_intr, &lock);
+ if (rc)
return rc;
- tsm = pdev->tsm;
- if (!tsm)
+ if (!pdev->tsm || !is_link_tsm(pdev->tsm->tsm_dev))
return sysfs_emit(buf, "\n");
- tsm_pf0 = to_pci_tsm_pf0(tsm);
+ pf0 = to_pci_tsm_pf0(pdev->tsm);
+ if (!pf0)
+ return -ENXIO;
- ACQUIRE(mutex_intr, ops_lock)(&tsm_pf0->lock);
- if ((rc = ACQUIRE_ERR(mutex_intr, &ops_lock)))
+ ACQUIRE(mutex_intr, ops_lock)(&pf0->lock);
+ rc = ACQUIRE_ERR(mutex_intr, &ops_lock);
+ if (rc)
return rc;
- if (!tsm->tdi)
- return sysfs_emit(buf, "\n");
- return sysfs_emit(buf, "%s\n", dev_name(&tsm->tsm_dev->dev));
+ list_for_each_entry(context, &pf0->bound_contexts, bound_node)
+ if (context->pdev == pdev)
+ return sysfs_emit(buf, "%s\n",
+ dev_name(&context->tsm_dev->dev));
+
+ return sysfs_emit(buf, "\n");
}
static DEVICE_ATTR_RO(bound);
@@ -955,7 +992,8 @@ static umode_t pci_tsm_attr_visible(struct kobject *kobj,
if (attr == &dev_attr_bound.attr) {
if (is_pci_tsm_pf0(pdev) && has_tee(pdev))
return attr->mode;
- if (pdev->tsm && has_tee(pdev->tsm->dsm_dev))
+ if (pdev->tsm && pdev->tsm->dsm_dev &&
+ has_tee(pdev->tsm->dsm_dev))
return attr->mode;
}
@@ -1086,22 +1124,6 @@ static struct pci_dev *find_dsm_dev(struct pci_dev *pdev)
return NULL;
}
-/**
- * pci_tsm_tdi_constructor() - base 'struct pci_tdi' initialization for link TSMs
- * @pdev: PCI device function representing the TDI
- * @tdi: context to initialize
- * @kvm: Private memory attach context
- * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM
- */
-void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi,
- struct kvm *kvm, u32 tdi_id)
-{
- tdi->pdev = pdev;
- tdi->kvm = kvm;
- tdi->tdi_id = tdi_id;
-}
-EXPORT_SYMBOL_GPL(pci_tsm_tdi_constructor);
-
void pci_tsm_init_evidence(struct pci_tsm_evidence *evidence, int slot,
enum hash_algo digest_algo)
{
@@ -1151,7 +1173,6 @@ int pci_tsm_devsec_constructor(struct pci_dev *pdev, struct pci_tsm_devsec *tsm,
return -EINVAL;
pci_tsm->dsm_dev = NULL;
- pci_tsm->tdi = NULL;
pci_tsm->pdev = pdev;
pci_tsm->tsm_dev = tsm_dev;
@@ -1169,6 +1190,7 @@ int pci_tsm_pf0_constructor(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm,
struct tsm_dev *tsm_dev)
{
mutex_init(&tsm->lock);
+ INIT_LIST_HEAD(&tsm->bound_contexts);
/*
* Note, low-level TSM driver responsible for determining if it wants to
* proceed with a device that has no DOE mailbox. TSM may have an
@@ -1224,12 +1246,6 @@ int pci_tsm_register(struct tsm_dev *tsm_dev)
return 0;
}
-static void pci_tsm_fn_exit(struct pci_dev *pdev)
-{
- __pci_tsm_unbind(pdev, NULL);
- tsm_remove(pdev->tsm);
-}
-
/**
* __pci_tsm_destroy() - destroy the TSM context for @pdev
* @pdev: device to cleanup
@@ -1266,12 +1282,14 @@ static void __pci_tsm_destroy(struct pci_dev *pdev, struct tsm_dev *tsm_dev)
else if (tsm_dev != tsm->tsm_dev)
return;
- /* Disconnect DSMs, unlock assigned TDIs, or cleanup DSM subfunctions */
+ /* Disconnect DSMs, unlock assigned TDIs, or clean up DSM subfunctions. */
if (is_link_tsm(tsm_dev)) {
- if (is_pci_tsm_pf0(pdev))
- pci_tsm_disconnect(pdev);
- else
- pci_tsm_fn_exit(pdev);
+ if (is_pci_tsm_pf0(pdev)) {
+ if (pci_tsm_disconnect(pdev))
+ pci_warn(pdev, "TSM connection is still in use\n");
+ } else {
+ tsm_remove(pdev->tsm);
+ }
}
if (is_devsec_tsm(tsm_dev) && has_tee(pdev)) {
diff --git a/include/linux/pci-tsm.h b/include/linux/pci-tsm.h
index 15907bad47b7..e351e1490fd0 100644
--- a/include/linux/pci-tsm.h
+++ b/include/linux/pci-tsm.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PCI_TSM_H
#define __PCI_TSM_H
+#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/rwsem.h>
@@ -8,8 +9,8 @@
#include <uapi/linux/pci-tsm-netlink.h>
struct pci_tsm;
+struct pci_tsm_context;
struct tsm_dev;
-struct kvm;
/*
* struct pci_tsm_ops - manage confidential links and security state
@@ -33,16 +34,11 @@ struct pci_tsm_ops {
* @connect: establish / validate a secure connection (e.g. IDE)
* with the device
* @disconnect: teardown the secure link
- * @bind: bind a TDI in preparation for it to be accepted by a TVM
- * @unbind: remove a TDI from secure operation with a TVM
- *
* Context: @probe, @remove, @connect, and @disconnect run under
* pci_tsm_rwsem held for write to sync with TSM unregistration and
* mutual exclusion of @connect and @disconnect. @connect and
* @disconnect additionally run under the DSM lock (struct
* pci_tsm_pf0::lock) as well as @probe and @remove of the subfunctions.
- * @bind and @unbind run under pci_tsm_rwsem held for read
- * and the DSM lock.
*/
struct_group_tagged(pci_tsm_link_ops, link_ops,
struct pci_tsm *(*probe)(struct tsm_dev *tsm_dev,
@@ -50,9 +46,6 @@ struct pci_tsm_ops {
void (*remove)(struct pci_tsm *tsm);
int (*connect)(struct pci_dev *pdev);
void (*disconnect)(struct pci_dev *pdev);
- struct pci_tdi *(*bind)(struct pci_dev *pdev,
- struct kvm *kvm, u32 tdi_id);
- void (*unbind)(struct pci_tdi *tdi);
);
/*
@@ -81,18 +74,6 @@ struct pci_tsm_ops {
size_t nonce_len);
};
-/**
- * struct pci_tdi - Core TEE I/O Device Interface (TDI) context
- * @pdev: host side representation of guest-side TDI
- * @kvm: TEE VM context of bound TDI
- * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM
- */
-struct pci_tdi {
- struct pci_dev *pdev;
- struct kvm *kvm;
- u32 tdi_id;
-};
-
/**
* struct pci_tsm_evidence_object - General PCI/TSM blob descriptor
* @data: pointer to the evidence data blob
@@ -145,7 +126,6 @@ struct pci_tsm_evidence {
* @dsm_dev: PCI Device Security Manager for link operations on @pdev
* @tsm_dev: PCI TEE Security Manager device for Link Confidentiality or Device
* Function Security operations
- * @tdi: TDI context established by the @bind link operation
* @evidence: cached evidence from SPDM session establishment (connect), or
* TDISP bind (lock)
*
@@ -170,7 +150,6 @@ struct pci_tsm {
struct pci_dev *pdev;
struct pci_dev *dsm_dev;
struct tsm_dev *tsm_dev;
- struct pci_tdi *tdi;
struct pci_tsm_evidence evidence;
};
@@ -178,11 +157,17 @@ struct pci_tsm {
* struct pci_tsm_pf0 - Physical Function 0 TDISP link context
* @base_tsm: generic core "tsm" context
* @lock: mutual exclustion for pci_tsm_ops invocation
+ * @context_users: live per-function contexts on this PF0, including contexts
+ * being initialized and not yet in @bound_contexts; a nonzero count blocks
+ * link disconnect and is independent of TSM and vIOMMU provider lifetimes
+ * @bound_contexts: bound per-function contexts, protected by @lock
* @doe_mb: PCIe Data Object Exchange mailbox
*/
struct pci_tsm_pf0 {
struct pci_tsm base_tsm;
struct mutex lock;
+ unsigned int context_users;
+ struct list_head bound_contexts;
struct pci_doe_mb *doe_mb;
};
@@ -269,10 +254,15 @@ int pci_tsm_devsec_constructor(struct pci_dev *pdev, struct pci_tsm_devsec *tsm,
void pci_tsm_pf0_destructor(struct pci_tsm_pf0 *tsm);
int pci_tsm_doe_transfer(struct pci_dev *pdev, u8 type, const void *req,
size_t req_sz, void *resp, size_t resp_sz);
-int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id);
-void pci_tsm_unbind(struct pci_dev *pdev);
-void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi,
- struct kvm *kvm, u32 tdi_id);
+bool pci_tsm_is_configured(struct pci_dev *pdev);
+struct pci_tsm_context *pci_tsm_context_get(struct pci_dev *pdev);
+void pci_tsm_context_put(struct pci_tsm_context *context);
+void pci_tsm_context_mark_bound(struct pci_tsm_context *context);
+struct tsm_dev *pci_tsm_context_tsm_dev(struct pci_tsm_context *context);
+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 pci_tsm_devsec *to_pci_tsm_devsec(struct pci_tsm *tsm);
void pci_tsm_init_evidence(struct pci_tsm_evidence *evidence, int slot,
enum hash_algo digest_algo);
@@ -288,12 +278,47 @@ static inline int pci_tsm_register(struct tsm_dev *tsm_dev)
static inline void pci_tsm_unregister(struct tsm_dev *tsm_dev)
{
}
-static inline int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u64 tdi_id)
+static inline bool pci_tsm_is_configured(struct pci_dev *pdev)
{
- return -ENXIO;
+ return false;
}
-static inline void pci_tsm_unbind(struct pci_dev *pdev)
+
+static inline struct pci_tsm_context *
+pci_tsm_context_get(struct pci_dev *pdev)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void pci_tsm_context_put(struct pci_tsm_context *context)
+{
+}
+
+static inline void pci_tsm_context_mark_bound(struct pci_tsm_context *context)
+{
+}
+
+static inline struct tsm_dev *
+pci_tsm_context_tsm_dev(struct pci_tsm_context *context)
+{
+ return NULL;
+}
+
+static inline struct pci_tsm_pf0 *
+pci_tsm_context_pf0(struct pci_tsm_context *context)
+{
+ return NULL;
+}
+
+static inline struct pci_dev *
+pci_tsm_context_dsm_dev(struct pci_tsm_context *context)
+{
+ return NULL;
+}
+
+static inline bool
+pci_tsm_context_match_device(struct pci_tsm_context *context, struct pci_dev *pdev)
{
+ return false;
}
#endif
diff --git a/samples/devsec/link_tsm.c b/samples/devsec/link_tsm.c
index 1d102dd9590a..7fee075d7ab3 100644
--- a/samples/devsec/link_tsm.c
+++ b/samples/devsec/link_tsm.c
@@ -20,10 +20,6 @@ struct devsec_tsm_fn {
struct pci_tsm pci;
};
-struct devsec_tsm_tdi {
- struct pci_tdi pci;
-};
-
static struct devsec_tsm_pf0 *to_devsec_tsm_pf0(struct pci_tsm *tsm)
{
return container_of(tsm, struct devsec_tsm_pf0, pci.base_tsm);
@@ -234,39 +230,11 @@ static void devsec_link_tsm_disconnect(struct pci_dev *pdev)
clear_bit(i, devsec_stream_ids);
}
-static struct pci_tdi *devsec_link_tsm_bind(struct pci_dev *pdev,
- struct kvm *kvm, u32 tdi_id)
-{
- struct devsec_tsm_tdi *devsec_tdi =
- kzalloc(sizeof(struct devsec_tsm_tdi), GFP_KERNEL);
-
- dev_dbg(pci_tsm_host(pdev), "%s\n", pci_name(pdev));
-
- if (!devsec_tdi)
- return ERR_PTR(-ENOMEM);
-
- pci_tsm_tdi_constructor(pdev, &devsec_tdi->pci, kvm, tdi_id);
-
- return &devsec_tdi->pci;
-}
-
-static void devsec_link_tsm_unbind(struct pci_tdi *tdi)
-{
- struct devsec_tsm_tdi *devsec_tdi =
- container_of(tdi, struct devsec_tsm_tdi, pci);
-
- dev_dbg(pci_tsm_host(tdi->pdev), "%s\n", pci_name(tdi->pdev));
-
- kfree(devsec_tdi);
-}
-
static struct pci_tsm_ops devsec_link_pci_ops = {
.probe = devsec_link_tsm_pci_probe,
.remove = devsec_link_tsm_pci_remove,
.connect = devsec_link_tsm_connect,
.disconnect = devsec_link_tsm_disconnect,
- .bind = devsec_link_tsm_bind,
- .unbind = devsec_link_tsm_unbind,
};
static void devsec_link_tsm_remove(void *tsm_dev)
@@ -292,71 +260,7 @@ static const struct faux_device_ops devsec_link_device_ops = {
.probe = devsec_link_tsm_probe,
};
-static struct pci_dev *pci_find_device(const char *name)
-{
- struct device *dev = bus_find_device_by_name(&pci_bus_type, NULL, name);
-
- if (dev)
- return to_pci_dev(dev);
- return NULL;
-}
-
-static ssize_t tsm_bind_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct device *host;
- int rc;
-
- struct pci_dev *pdev __free(pci_dev_put) = pci_find_device(buf);
- if (!pdev)
- return -ENODEV;
-
- host = pci_tsm_host(pdev);
- if (!host || host != &devsec_link_tsm->dev)
- return -ENXIO;
-
- rc = pci_tsm_bind(pdev, (struct kvm *)1, pci_dev_id(pdev));
- if (rc)
- return rc;
- return count;
-}
-static DEVICE_ATTR_WO(tsm_bind);
-
-static ssize_t tsm_unbind_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct device *host;
-
- struct pci_dev *pdev __free(pci_dev_put) = pci_find_device(buf);
- if (!pdev)
- return -ENODEV;
-
- host = pci_tsm_host(pdev);
- if (!host || host != &devsec_link_tsm->dev)
- return -ENXIO;
-
- pci_tsm_unbind(pdev);
- return count;
-}
-static DEVICE_ATTR_WO(tsm_unbind);
-
-/*
- * Facilitate testing of the bind flows in lieu of VFIO/IOMMUFD
- * support to exercise these paths.
- */
-static struct attribute *devsec_link_attrs[] = {
- &dev_attr_tsm_bind.attr,
- &dev_attr_tsm_unbind.attr,
- NULL,
-};
-
-static const struct attribute_group devsec_link_group = {
- .attrs = devsec_link_attrs,
-};
-
static const struct attribute_group *devsec_link_groups[] = {
- &devsec_link_group,
&devsec_evidence_group,
NULL,
};
diff --git a/tools/testing/devsec/devsec.sh b/tools/testing/devsec/devsec.sh
index 6a9313e7104f..159b1a6fb133 100755
--- a/tools/testing/devsec/devsec.sh
+++ b/tools/testing/devsec/devsec.sh
@@ -94,14 +94,10 @@ validate_disconnected() {
fn_dev=${FN_DEVS[$1]}
host_bridge=$(dirname $(dirname $(readlink -f $pci_dev)))
- # validate that the dsm is not yet detected and that the sub-function
- # is aware of any TSM capabilities
+ # validate that the dsm is not yet detected
dsm=$(cat $pci_dev/tsm/dsm) || err "$LINENO from $2"
- bound=$(cat $pci_dev/tsm/bound) || err "$LINENO from $2"
[[ -z $dsm ]] || err "$LINENO from $2"
- [[ -z $bound ]] || err "$LINENO from $2"
[[ ! -e $fn_dev/tsm/dsm ]] || err "$LINENO from $2"
- [[ ! -e $fn_dev/tsm/bound ]] || err "$LINENO from $2"
[[ ! -e $fn_dev/tsm/connect ]] || err "$LINENO from $2"
[[ ! -e $fn_dev/tsm/disconnect ]] || err "$LINENO from $2"
}
@@ -197,27 +193,6 @@ ide_test() {
check_evidence $pci_dev
- # bind both functions and validate that they display bound to
- # the TSM device
- echo $(basename $pci_dev) > $tsm_link/device/tsm_bind
- bound=$(cat $pci_dev/tsm/bound)
- [[ $bound == $(basename $tsm_link) ]] || err "$LINENO"
- echo $(basename $fn_dev) > $tsm_link/device/tsm_bind
- bound=$(cat $fn_dev/tsm/bound)
- [[ $bound == $(basename $tsm_link) ]] || err "$LINENO"
-
- # test manual unbind
- echo $(basename $pci_dev) > $tsm_link/device/tsm_unbind
- bound=$(cat $pci_dev/tsm/bound)
- [[ -z $bound ]] || err "$LINENO"
- echo $(basename $fn_dev) > $tsm_link/device/tsm_unbind
- bound=$(cat $fn_dev/tsm/bound)
- [[ -z $bound ]] || err "$LINENO"
-
- # rebind to test automatic unbind at disconnect
- echo $(basename $pci_dev) > $tsm_link/device/tsm_bind
- echo $(basename $fn_dev) > $tsm_link/device/tsm_bind
-
# check that the links disappear at disconnect and the stream
# pool is refilled
echo $(basename $tsm_link) > $pci_dev/tsm/disconnect
--
2.43.0
next prev parent reply other threads:[~2026-09-17 14:04 UTC|newest]
Thread overview: 72+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-17 14:01 [RFC PATCH v6 00/11] iommufd: Infrastructure for vIOMMU creation for confidential guests and guest TSM requests Aneesh Kumar K.V (Arm)
2026-09-17 14:01 ` [RFC PATCH v6 01/11] vfio: cache KVM VM file references instead of raw struct kvm pointers Aneesh Kumar K.V (Arm)
2026-09-24 19:41 ` Jason Gunthorpe
2026-09-30 7:19 ` Aneesh Kumar K.V
2026-09-17 14:01 ` [RFC PATCH v6 02/11] vfio: cdev: Reject duplicate bind before updating KVM file Aneesh Kumar K.V (Arm)
2026-09-24 7:53 ` Tian, Kevin
2026-09-25 5:49 ` Aneesh Kumar K.V
2026-09-17 14:01 ` [RFC PATCH v6 03/11] iommufd/device: Associate KVM file pointer with iommufd_device Aneesh Kumar K.V (Arm)
2026-09-17 14:01 ` [RFC PATCH v6 04/11] iommufd/viommu: Keep a reference to the KVM file Aneesh Kumar K.V (Arm)
2026-09-30 13:28 ` Vasant Hegde
2026-10-02 5:26 ` Aneesh Kumar K.V
2026-09-17 14:01 ` [RFC PATCH v6 05/11] iommu: Add a helper to validate a vIOMMU parent Aneesh Kumar K.V (Arm)
2026-09-24 19:41 ` Jason Gunthorpe
2026-09-25 5:48 ` Aneesh Kumar K.V
2026-09-25 12:23 ` Jason Gunthorpe
2026-09-28 10:36 ` Aneesh Kumar K.V
2026-09-28 12:11 ` Jason Gunthorpe
2026-09-28 15:39 ` Aneesh Kumar K.V
2026-09-28 16:17 ` Jason Gunthorpe
2026-09-28 18:08 ` Jacob Pan
2026-09-28 18:20 ` Jason Gunthorpe
2026-09-28 22:24 ` Jacob Pan
2026-09-28 23:03 ` Jason Gunthorpe
2026-09-29 5:55 ` Jacob Pan
2026-09-29 12:30 ` Jason Gunthorpe
2026-09-29 23:15 ` Jacob Pan
2026-09-29 23:30 ` Jason Gunthorpe
2026-09-17 14:01 ` [RFC PATCH v6 06/11] iommu: Add a helper to query vIOMMU hardware parameters Aneesh Kumar K.V (Arm)
2026-09-24 19:41 ` Jason Gunthorpe
2026-09-25 5:59 ` Aneesh Kumar K.V
2026-09-25 12:29 ` Jason Gunthorpe
2026-09-17 14:01 ` [RFC PATCH v6 07/11] coco: tsm: Expose active-user lifetime references Aneesh Kumar K.V (Arm)
2026-09-17 14:01 ` [RFC PATCH v6 08/11] iommufd: Add vIOMMU provider support Aneesh Kumar K.V (Arm)
2026-09-24 19:41 ` Jason Gunthorpe
2026-09-25 6:08 ` Aneesh Kumar K.V
2026-09-25 12:39 ` Jason Gunthorpe
2026-09-28 3:41 ` Tian, Kevin
2026-09-29 6:14 ` Aneesh Kumar K.V
2026-09-29 12:17 ` Jason Gunthorpe
2026-09-29 12:45 ` Aneesh Kumar K.V
2026-09-29 13:06 ` Jason Gunthorpe
2026-09-29 15:58 ` Aneesh Kumar K.V
2026-09-29 19:10 ` Jason Gunthorpe
2026-09-28 10:51 ` Aneesh Kumar K.V
2026-09-17 14:01 ` [RFC PATCH v6 09/11] iommufd: Add the vdevice TSM request ioctl Aneesh Kumar K.V (Arm)
2026-09-18 13:09 ` Alexey Kardashevskiy
2026-09-18 13:13 ` Jason Gunthorpe
2026-09-24 19:41 ` Jason Gunthorpe
2026-09-30 8:03 ` Aneesh Kumar K.V
2026-09-30 13:26 ` Vasant Hegde
2026-09-30 14:03 ` Jason Gunthorpe
2026-09-30 14:08 ` Jason Gunthorpe
2026-09-17 14:01 ` [RFC PATCH v6 10/11] PCI/TSM: Remove the legacy guest request interface Aneesh Kumar K.V (Arm)
2026-09-17 14:01 ` Aneesh Kumar K.V (Arm) [this message]
2026-09-24 8:17 ` [RFC PATCH v6 11/11] PCI/TSM: Add reference-counted contexts for vdevice providers Tian, Kevin
2026-09-24 19:41 ` Jason Gunthorpe
2026-09-25 8:15 ` Aneesh Kumar K.V
2026-09-28 18:47 ` Sonang Patel
2026-09-28 23:08 ` Jason Gunthorpe
2026-10-02 6:14 ` Aneesh Kumar K.V
2026-10-02 13:06 ` Jason Gunthorpe
2026-09-17 14:17 ` [RFC PATCH v6 00/11] iommufd: Infrastructure for vIOMMU creation for confidential guests and guest TSM requests Aneesh Kumar K.V
2026-09-24 7:48 ` Tian, Kevin
2026-09-24 19:20 ` Jason Gunthorpe
2026-09-28 3:35 ` Tian, Kevin
2026-09-28 13:08 ` Jason Gunthorpe
2026-09-25 8:29 ` Aneesh Kumar K.V
2026-09-28 3:41 ` Tian, Kevin
2026-09-28 3:55 ` Tian, Kevin
2026-09-24 19:09 ` Jason Gunthorpe
2026-09-25 6:46 ` Aneesh Kumar K.V
2026-09-25 12:45 ` Jason Gunthorpe
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=20260917140159.1163281-12-aneesh.kumar@kernel.org \
--to=aneesh.kumar@kernel.org \
--cc=Suzuki.Poulose@arm.com \
--cc=aik@amd.com \
--cc=helgaas@kernel.org \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=jic23@kernel.org \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=nicolinc@nvidia.com \
--cc=pbonzini@redhat.com \
--cc=sameo@rivosinc.com \
--cc=shameerali.kolothum.thodi@huawei.com \
--cc=steven.price@arm.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.