PCI/TSM: Add 'dsm' and 'bound' attributes for dependent functions

PCI/TSM sysfs for physical function 0 devices, i.e. the "DSM" (Device
Security Manager), contains the 'connect' and 'disconnect' attributes.
After a successful 'connect' operation the DSM, its dependent functions
(SR-IOV virtual functions, non-zero multi-functions, or downstream
endpoints of a switch DSM) are candidates for being transitioned into a
TDISP (TEE Device Interface Security Protocol) operational state, via
pci_tsm_bind(). At present sysfs is blind to which devices are capable of
TDISP operation and it is ambiguous which functions are serviced by which
DSMs.

Add a 'dsm' attribute to identify a function's DSM device, and add a
'bound' attribute to identify when a function has entered a TDISP
operational state.

Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Lukas Wunner <lukas@wunner.de>
Cc: Samuel Ortiz <sameo@rivosinc.com>
Cc: Alexey Kardashevskiy <aik@amd.com>
Cc: Xu Yilun <yilun.xu@linux.intel.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Link: https://patch.msgid.link/20251113021446.436830-9-dan.j.williams@intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Dan Williams
2025-11-12 18:14:46 -08:00
parent c316c75d57
commit f7ae6d4ec6
2 changed files with 140 additions and 20 deletions

View File

@@ -655,6 +655,36 @@ Description:
(WO) Write the name of the TSM device that was specified
to 'connect' to teardown the connection.
What: /sys/bus/pci/devices/.../tsm/dsm
Contact: linux-coco@lists.linux.dev
Description: (RO) Return PCI device name of this device's DSM (Device
Security Manager). When a device is in the connected state it
indicates that the platform TSM (TEE Security Manager) has made
a secure-session connection with a device's DSM. A DSM is always
physical function 0 and when the device supports TDISP (TEE
Device Interface Security Protocol) its managed functions also
populate this tsm/dsm attribute. The managed functions of a DSM
are SR-IOV (Single Root I/O Virtualization) virtual functions,
non-zero functions of a multi-function device, or downstream
endpoints depending on whether the DSM is an SR-IOV physical
function, function0 of a multi-function device, or an upstream
PCIe switch port. This is a "link" TSM attribute, see
Documentation/ABI/testing/sysfs-class-tsm.
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.
What: /sys/bus/pci/devices/.../authenticated
Contact: linux-pci@vger.kernel.org
Description:

View File

@@ -151,6 +151,25 @@ static void pci_tsm_walk_fns_reverse(struct pci_dev *pdev,
}
}
static void link_sysfs_disable(struct pci_dev *pdev)
{
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group);
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
}
static void link_sysfs_enable(struct pci_dev *pdev)
{
bool tee = has_tee(pdev);
pci_dbg(pdev, "%s Security Manager detected (%s%s%s)\n",
pdev->tsm ? "Device" : "Platform TEE",
pdev->ide_cap ? "IDE" : "", pdev->ide_cap && tee ? " " : "",
tee ? "TEE" : "");
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group);
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
}
static int probe_fn(struct pci_dev *pdev, void *dsm)
{
struct pci_dev *dsm_dev = dsm;
@@ -159,6 +178,8 @@ static int probe_fn(struct pci_dev *pdev, void *dsm)
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");
if (pdev->tsm)
link_sysfs_enable(pdev);
return 0;
}
@@ -267,6 +288,7 @@ static DEVICE_ATTR_RW(connect);
static int remove_fn(struct pci_dev *pdev, void *data)
{
tsm_remove(pdev->tsm);
link_sysfs_disable(pdev);
return 0;
}
@@ -468,12 +490,74 @@ static ssize_t disconnect_store(struct device *dev,
}
static DEVICE_ATTR_WO(disconnect);
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;
int rc;
ACQUIRE(rwsem_read_intr, lock)(&pci_tsm_rwsem);
if ((rc = ACQUIRE_ERR(rwsem_read_intr, &lock)))
return rc;
tsm = pdev->tsm;
if (!tsm)
return sysfs_emit(buf, "\n");
tsm_pf0 = to_pci_tsm_pf0(tsm);
ACQUIRE(mutex_intr, ops_lock)(&tsm_pf0->lock);
if ((rc = ACQUIRE_ERR(mutex_intr, &ops_lock)))
return rc;
if (!tsm->tdi)
return sysfs_emit(buf, "\n");
return sysfs_emit(buf, "%s\n", dev_name(&tsm->tsm_dev->dev));
}
static DEVICE_ATTR_RO(bound);
static ssize_t dsm_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_tsm *tsm;
int rc;
ACQUIRE(rwsem_read_intr, lock)(&pci_tsm_rwsem);
if ((rc = ACQUIRE_ERR(rwsem_read_intr, &lock)))
return rc;
tsm = pdev->tsm;
if (!tsm)
return sysfs_emit(buf, "\n");
return sysfs_emit(buf, "%s\n", pci_name(tsm->dsm_dev));
}
static DEVICE_ATTR_RO(dsm);
/* The 'authenticated' attribute is exclusive to the presence of a 'link' TSM */
static bool pci_tsm_link_group_visible(struct kobject *kobj)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
return pci_tsm_link_count && is_pci_tsm_pf0(pdev);
if (!pci_tsm_link_count)
return false;
if (!pci_is_pcie(pdev))
return false;
if (is_pci_tsm_pf0(pdev))
return true;
/*
* Show 'authenticated' and other attributes for the managed
* sub-functions of a DSM.
*/
if (pdev->tsm)
return true;
return false;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(pci_tsm_link);
@@ -485,9 +569,27 @@ static umode_t pci_tsm_attr_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
if (pci_tsm_link_group_visible(kobj)) {
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(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))
return attr->mode;
}
if (attr == &dev_attr_dsm.attr) {
if (is_pci_tsm_pf0(pdev))
return attr->mode;
if (pdev->tsm && has_tee(pdev->tsm->dsm_dev))
return attr->mode;
}
if (attr == &dev_attr_connect.attr ||
attr == &dev_attr_disconnect.attr)
return attr->mode;
attr == &dev_attr_disconnect.attr) {
if (is_pci_tsm_pf0(pdev))
return attr->mode;
}
}
return 0;
@@ -502,6 +604,8 @@ DEFINE_SYSFS_GROUP_VISIBLE(pci_tsm);
static struct attribute *pci_tsm_attrs[] = {
&dev_attr_connect.attr,
&dev_attr_disconnect.attr,
&dev_attr_bound.attr,
&dev_attr_dsm.attr,
NULL
};
@@ -657,18 +761,6 @@ void pci_tsm_pf0_destructor(struct pci_tsm_pf0 *pf0_tsm)
}
EXPORT_SYMBOL_GPL(pci_tsm_pf0_destructor);
static void pf0_sysfs_enable(struct pci_dev *pdev)
{
bool tee = has_tee(pdev);
pci_dbg(pdev, "Device Security Manager detected (%s%s%s)\n",
pdev->ide_cap ? "IDE" : "", pdev->ide_cap && tee ? " " : "",
tee ? "TEE" : "");
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group);
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
}
int pci_tsm_register(struct tsm_dev *tsm_dev)
{
struct pci_dev *pdev = NULL;
@@ -689,7 +781,7 @@ int pci_tsm_register(struct tsm_dev *tsm_dev)
if (is_link_tsm(tsm_dev) && pci_tsm_link_count++ == 0) {
for_each_pci_dev(pdev)
if (is_pci_tsm_pf0(pdev))
pf0_sysfs_enable(pdev);
link_sysfs_enable(pdev);
} else if (is_devsec_tsm(tsm_dev)) {
pci_tsm_devsec_count++;
}
@@ -723,10 +815,8 @@ static void __pci_tsm_destroy(struct pci_dev *pdev, struct tsm_dev *tsm_dev)
* skipped if the device itself is being removed since sysfs goes away
* naturally at that point
*/
if (is_link_tsm(tsm_dev) && is_pci_tsm_pf0(pdev) && !pci_tsm_link_count) {
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group);
sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
}
if (is_link_tsm(tsm_dev) && is_pci_tsm_pf0(pdev) && !pci_tsm_link_count)
link_sysfs_disable(pdev);
/* Nothing else to do if this device never attached to the departing TSM */
if (!tsm)