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: 13+ 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-17 14:01 ` [RFC PATCH v6 02/11] vfio: cdev: Reject duplicate bind before updating KVM file Aneesh Kumar K.V (Arm)
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-17 14:01 ` [RFC PATCH v6 05/11] iommu: Add a helper to validate a vIOMMU parent Aneesh Kumar K.V (Arm)
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-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-17 14:01 ` [RFC PATCH v6 09/11] iommufd: Add the vdevice TSM request ioctl Aneesh Kumar K.V (Arm)
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-17 14:17 ` [RFC PATCH v6 00/11] iommufd: Infrastructure for vIOMMU creation for confidential guests and guest TSM requests Aneesh Kumar K.V
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®