[PATCH v4 12/22] PCI/TSM: Support connecting to PCIe CMA devices

From: alistair23

Date: Sun Sep 27 2026 - 21:14: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/crypto/ccp/sev-dev-tsm.c | 4 ++--
drivers/pci/doe.c | 3 +++
drivers/pci/tsm.c | 38 +++++++++++++++++++++++++++-----
include/linux/pci-tsm.h | 32 +++++++++++++++++++++++++--
include/linux/pci.h | 1 +
5 files changed, 68 insertions(+), 10 deletions(-)

diff --git a/drivers/crypto/ccp/sev-dev-tsm.c b/drivers/crypto/ccp/sev-dev-tsm.c
index 1d2561628f43..22f2855f397b 100644
--- a/drivers/crypto/ccp/sev-dev-tsm.c
+++ b/drivers/crypto/ccp/sev-dev-tsm.c
@@ -226,7 +226,7 @@ static struct pci_tsm *dsm_probe(struct tsm_dev *tsmdev, struct pci_dev *pdev)
{
struct sev_device *sev = tsm_dev_to_sev(tsmdev);

- if (is_pci_tsm_host(pdev))
+ if (is_pci_tsm_dsm(pdev))
return tio_host_probe(pdev, sev);
return NULL;
}
@@ -237,7 +237,7 @@ static void dsm_remove(struct pci_tsm *tsm)

pci_dbg(pdev, "TSM disabled\n");

- if (is_pci_tsm_host(pdev)) {
+ if (is_pci_tsm_dsm(pdev)) {
struct tio_dsm *dsm = container_of(tsm, struct tio_dsm, tsm.base_tsm);

pci_tsm_host_destructor(&dsm->tsm);
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..03a84630bd69 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);
}
}
@@ -175,6 +175,9 @@ static int probe_fn(struct pci_dev *pdev, void *dsm)
struct pci_dev *dsm_dev = dsm;
const struct pci_tsm_ops *ops = to_pci_tsm_ops(dsm_dev->tsm);

+ if (pdev->tsm)
+ return 0;
+
pdev->tsm = ops->probe(dsm_dev->tsm->tsm_dev, pdev);
pci_dbg(pdev, "setup TSM context: DSM: %s status: %s\n",
pci_name(dsm_dev), pdev->tsm ? "success" : "failed");
@@ -287,6 +290,19 @@ static DEVICE_ATTR_RW(connect);

static int remove_fn(struct pci_dev *pdev, void *data)
{
+ struct pci_dev *host = data;
+ struct pci_tsm_host *tsm_host;
+
+ /*
+ * 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_host = to_pci_tsm_host(pdev->tsm);
+ guard(mutex)(&tsm_host->lock);
tsm_remove(pdev->tsm);
link_sysfs_disable(pdev);
return 0;
@@ -299,6 +315,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 +324,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 +462,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);
}

@@ -451,12 +476,13 @@ static void __pci_tsm_disconnect(struct pci_dev *pdev)

pci_tsm_unbind_all(pdev);

+ pci_tsm_walk_fns_reverse(pdev, remove_fn, pdev);
+
/*
* disconnect() is uninterruptible as it may be called for device
* teardown
*/
guard(mutex)(&tsm_host->lock);
- pci_tsm_walk_fns_reverse(pdev, remove_fn, NULL);
ops->disconnect(pdev);
}

diff --git a/include/linux/pci-tsm.h b/include/linux/pci-tsm.h
index 950e2c36a4ca..ddaec2168c7e 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,8 +131,11 @@ struct pci_tsm_host {
struct pci_doe_mb *doe_mb;
};

-/* physical function0 and capable of 'connect' */
-static inline bool is_pci_tsm_host(struct pci_dev *pdev)
+
+/* device is a Device Security Manager (DSM), similar to
+ * is_pci_tsm_host() but doesnt' support CMA
+ */
+static inline bool is_pci_tsm_dsm(struct pci_dev *pdev)
{
if (!pdev)
return false;
@@ -163,6 +167,30 @@ static inline bool is_pci_tsm_host(struct pci_dev *pdev)
return PCI_FUNC(pdev->devfn) == 0;
}

+/* device is a TSM host and capable of 'connect' */
+static inline bool is_pci_tsm_host(struct pci_dev *pdev)
+{
+ if (!pdev)
+ return false;
+
+ if (!pci_is_pcie(pdev))
+ return false;
+
+ 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
+
+ return is_pci_tsm_dsm(pdev);
+}
+
/**
* enum pci_tsm_req_scope - Scope of guest requests to be validated by TSM
*
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