[RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure to debugfs
Qinxin Xia
xiaqinxin at huawei.com
Mon Mar 16 19:04:17 PDT 2026
On 2026/3/17 00:01:50, Robin Murphy <robin.murphy at arm.com> wrote:
> On 2026-03-13 10:43 am, Qinxin Xia wrote:
>> Add stream table directory structure creation to debugfs
>> This organizes debugfs entries by device and stream ID:
>>
>> /sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
>> └── 0000:01:00.0:0/
>> └─── ste
>
> Similar to my previous comment on CDs (sorry I'm reading out of order),
> I wonder if it might not be more useful to expose STEs by index, then
> have the name of the associated device as an attribute/link below that.
> Or perhaps even have whole cross-linked "by StreamID" and "by device"
> hierarchies if you want to get really fancy. From userspace it's not
> always easy to know exactly which StreamIDs are owned by which devices,
> and I can say from experience that if you do have to debug things at the
> STE level, the StreamID is often the thing you're starting from. Plus if
> you wanted to, say, check that STEs are correctly disabled after SR-IOV
> VF teardown, then there may not even be a device any more.
>
> Thanks,
> Robin.
>
To quickly obtain the mapping between SIDs and devices, I named the
directory dev_name+sid. Can we keep this naming mode and add a device
link to the directory?
According to Nicolin's suggestion, I plan to release the corresponding
debugfs in release_device in the next version. After VF teardown, users
cannot view information such as ste and cd anymore.
>> Signed-off-by: Qinxin Xia <xiaqinxin at huawei.com>
>> ---
>> .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c | 80 ++++++++++++++++++-
>> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 +
>> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 4 +
>> 3 files changed, 85 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c b/
>> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
>> index d7f3defd94a3..f62df02847ac 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
>> @@ -31,7 +31,10 @@
>> * /sys/kernel/debug/iommu/arm_smmu_v3/
>> * └── smmu0/
>> * ├── capabilities # SMMU feature capabilities and
>> configuration
>> - * └── registers # SMMU Key registers
>> + * ├── registers # SMMU Key registers
>> + * └── stream_table
>> + * └── 0000:01:00.0:0/ # PCI device with
>> Stream ID 0
>> + * ├── ste # Stream Table Entry
>> *
>> * The capabilities file provides detailed information about:
>> * - Architecture version and translation stage support (Stage1/Stage2)
>> @@ -324,5 +327,78 @@ static int smmu_debugfs_ste_show(struct seq_file
>> *seq, void *v)
>> smmu_debug_dump_ste(seq, dev);
>> return 0;
>> }
>> -
>> DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
>> +
>> +/**
>> + * smmu_debugfs_create_stream_table() - Create debugfs entries for
>> stream table
>> + * @dev: device to create entries for
>> + * @smmu: SMMU device
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +int smmu_debugfs_create_stream_table(struct device *dev,
>> + struct arm_smmu_device *smmu)
>> +{
>> + struct dentry *stream_dir, *cd_dir, *dev_dir;
>> + struct dentry *ste_file, *all_cds_file;
>> + struct iommu_fwspec *fwspec;
>> + char name[64];
>> + int i, ret = 0;
>> +
>> + if (!smmu->debugfs->stream_dir) {
>> + stream_dir = debugfs_create_dir("stream_table",
>> + smmu->debugfs->smmu_dir);
>> + if (!stream_dir)
>> + return -ENOMEM;
>> + smmu->debugfs->stream_dir = stream_dir;
>> + } else {
>> + stream_dir = smmu->debugfs->stream_dir;
>> + }
>> +
>> + fwspec = dev_iommu_fwspec_get(dev);
>> + if (!fwspec)
>> + return -ENODEV;
>> +
>> + for (i = 0; i < fwspec->num_ids; i++) {
>> + u32 sid = fwspec->ids[i];
>> +
>> + if (dev_is_pci(dev)) {
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> +
>> + snprintf(name, sizeof(name), "%04x:%02x:%02x.%d:%u",
>> + pci_domain_nr(pdev->bus), pdev->bus->number,
>> + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
>> + sid);
>> + } else {
>> + snprintf(name, sizeof(name), "%s:%u", dev_name(dev),
>> + sid);
>> + }
>> +
>> + dev_dir = debugfs_create_dir(name, stream_dir);
>> + if (!dev_dir) {
>> + ret = -ENOMEM;
>> + goto cleanup;
>> + }
>> +
>> + /* Create STE file */
>> + ste_file = debugfs_create_file("ste", 0444, dev_dir, dev,
>> + &smmu_debugfs_ste_fops);
>> + if (!ste_file) {
>> + ret = -ENOMEM;
>> + goto cleanup_dev;
>> + }
>> +
>> + /* Success for this stream ID, continue to next */
>> + continue;
>> +
>> +cleanup_dev:
>> + debugfs_remove_recursive(dev_dir);
>> +cleanup:
>> + if (ret) {
>> + debugfs_remove_recursive(stream_dir);
>> + break;
>> + }
>> + }
>> +
>> + return ret;
>> +}
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/
>> iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 211a0c87507a..c57897e5f644 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -3133,6 +3133,9 @@ static int arm_smmu_attach_dev(struct
>> iommu_domain *domain, struct device *dev,
>> arm_smmu_attach_commit(&state);
>> mutex_unlock(&arm_smmu_asid_lock);
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> + smmu_debugfs_create_stream_table(dev, smmu);
>> +#endif
>> return 0;
>> }
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/
>> iommu/arm/arm-smmu-v3/arm-smmu-v3.h
>> index 247f27426f6b..e9cd24c1ab3c 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
>> @@ -737,9 +737,13 @@ struct arm_smmu_impl_ops {
>> struct arm_smmu_debugfs {
>> struct dentry *root_dir;
>> struct dentry *smmu_dir;
>> + struct dentry *stream_dir;
>> struct arm_smmu_device *smmu;
>> };
>> +
>> int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t
>> ioaddr);
>> +int smmu_debugfs_create_stream_table(struct device *dev,
>> + struct arm_smmu_device *smmu);
>> #endif
>> /* An SMMUv3 instance */
>
>
--
Thanks,
Qinxin
More information about the linux-arm-kernel
mailing list