[PATCH v3 11/21] PCI/TSM: Support connecting to PCIe CMA devices

From: alistair23

Date: Mon Aug 31 2026 - 21:16:28 EST


From: Alistair Francis <alistair.francis@xxxxxxx>

In the next patch we are going to add a PCIe CMA TSM driver, as such we
need to ensure that is_pci_tsm_host() will allow us to connect to CMA
capable devices. These devices don't necessarily has DEVCAP_TEE or IDE
support.

To avoid calling pci_find_doe_mailbox() everytime is_pci_tsm_host() is
called we can cache the CMA support in struct pci_dev and just check
against that.

Signed-off-by: Alistair Francis <alistair.francis@xxxxxxx>
---
drivers/pci/doe.c | 3 +++
drivers/pci/tsm.c | 31 +++++++++++++++++++++++++------
include/linux/pci-tsm.h | 12 +++++++++++-
include/linux/pci.h | 1 +
4 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c
index ac95b1d2d999..6a59969bd52f 100644
--- a/drivers/pci/doe.c
+++ b/drivers/pci/doe.c
@@ -870,6 +870,9 @@ void pci_doe_init(struct pci_dev *pdev)
pci_doe_destroy_mb(doe_mb);
}
}
+
+ pdev->doe_cma = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
+ PCI_DOE_FEATURE_CMA);
}

void pci_doe_destroy(struct pci_dev *pdev)
diff --git a/drivers/pci/tsm.c b/drivers/pci/tsm.c
index 10c9c6696624..440f818ac569 100644
--- a/drivers/pci/tsm.c
+++ b/drivers/pci/tsm.c
@@ -88,8 +88,8 @@ static void pci_tsm_walk_fns(struct pci_dev *pdev,
if (!pf)
continue;

- /* on entry function 0 has already run @cb */
- if (i > 0)
+ /* the caller is responsible for running @cb on the host itself */
+ if (pf != pdev)
cb(pf, data);

/* walk virtual functions of each pf */
@@ -145,8 +145,8 @@ static void pci_tsm_walk_fns_reverse(struct pci_dev *pdev,
cb(vf, data);
}

- /* on exit, caller will run @cb on function 0 */
- if (i > 0)
+ /* the caller is responsible for running @cb on the host itself */
+ if (pf != pdev)
cb(pf, data);
}
}
@@ -287,6 +287,16 @@ static DEVICE_ATTR_RW(connect);

static int remove_fn(struct pci_dev *pdev, void *data)
{
+ struct pci_dev *host = data;
+
+ /*
+ * Only teardown the security context of functions that belong to the
+ * DSM being disconnected, leaving any sibling DSM in the same slot
+ * untouched.
+ */
+ if (!pdev->tsm || pdev->tsm->dsm_dev != host)
+ return 0;
+
tsm_remove(pdev->tsm);
link_sysfs_disable(pdev);
return 0;
@@ -299,6 +309,7 @@ static int remove_fn(struct pci_dev *pdev, void *data)
*/
static int __pci_tsm_unbind(struct pci_dev *pdev, void *data)
{
+ struct pci_dev *host = data;
struct pci_tdi *tdi;
struct pci_tsm_host *tsm_host;

@@ -307,6 +318,14 @@ static int __pci_tsm_unbind(struct pci_dev *pdev, void *data)
if (!pdev->tsm)
return 0;

+ /*
+ * When walking a DSM's dependent functions skip any that belong to a
+ * different DSM in the same slot. A NULL @host is a direct unbind of
+ * @pdev itself.
+ */
+ if (host && pdev->tsm->dsm_dev != host)
+ return 0;
+
tsm_host = to_pci_tsm_host(pdev->tsm);
guard(mutex)(&tsm_host->lock);

@@ -437,7 +456,7 @@ EXPORT_SYMBOL_GPL(pci_tsm_guest_req);

static void pci_tsm_unbind_all(struct pci_dev *pdev)
{
- pci_tsm_walk_fns_reverse(pdev, __pci_tsm_unbind, NULL);
+ pci_tsm_walk_fns_reverse(pdev, __pci_tsm_unbind, pdev);
__pci_tsm_unbind(pdev, NULL);
}

@@ -456,7 +475,7 @@ static void __pci_tsm_disconnect(struct pci_dev *pdev)
* teardown
*/
guard(mutex)(&tsm_host->lock);
- pci_tsm_walk_fns_reverse(pdev, remove_fn, NULL);
+ pci_tsm_walk_fns_reverse(pdev, remove_fn, pdev);
ops->disconnect(pdev);
}

diff --git a/include/linux/pci-tsm.h b/include/linux/pci-tsm.h
index 950e2c36a4ca..f504fa680315 100644
--- a/include/linux/pci-tsm.h
+++ b/include/linux/pci-tsm.h
@@ -3,6 +3,7 @@
#define __PCI_TSM_H
#include <linux/mutex.h>
#include <linux/pci.h>
+#include <linux/pci-doe.h>
#include <linux/sockptr.h>

struct pci_tsm;
@@ -130,7 +131,7 @@ struct pci_tsm_host {
struct pci_doe_mb *doe_mb;
};

-/* physical function0 and capable of 'connect' */
+/* device is a TSM host and capable of 'connect' */
static inline bool is_pci_tsm_host(struct pci_dev *pdev)
{
if (!pdev)
@@ -142,6 +143,15 @@ static inline bool is_pci_tsm_host(struct pci_dev *pdev)
if (pdev->is_virtfn)
return false;

+ /*
+ * Report capable if CMA is supported, which can be supported on any PCIe
+ * device.
+ */
+#ifdef CONFIG_PCI_DOE
+ if (pdev->doe_cma)
+ return true;
+#endif
+
/*
* Allow for a Device Security Manager (DSM) associated with function0
* of an Endpoint to coordinate TDISP requests for other functions
diff --git a/include/linux/pci.h b/include/linux/pci.h
index d31a8d107b1e..cb13b40952b4 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -565,6 +565,7 @@ struct pci_dev {
#endif
#ifdef CONFIG_PCI_DOE
struct xarray doe_mbs; /* Data Object Exchange mailboxes */
+ bool doe_cma; /* A CMA/SPDM DOE mailbox is present */
#endif
#ifdef CONFIG_PCI_NPEM
struct npem *npem; /* Native PCIe Enclosure Management */
--
2.55.0