[RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs

Qinxin Xia xiaqinxin at huawei.com
Mon Mar 16 19:14:57 PDT 2026



On 2026/3/16 23:42:36, Robin Murphy <robin.murphy at arm.com> wrote:
> On 2026-03-13 10:43 am, Qinxin Xia wrote:
>> Add Context Descriptor (CD) display functionality to debugfs.
>> This allow inspecting CD contents for all Substream IDs including:
>> - CD validity and translation parameters
>> - TTBR0 and TCR configurations
>> - Raw CD data
>>
>> /sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
>> └── 0000:01:00.0:0/
>>      ├── ste
>>      └── context_descriptors/
>>          └── all
>>
>> Signed-off-by: Qinxin Xia <xiaqinxin at huawei.com>
>> ---
>>   .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 112 ++++++++++++++++++
>>   1 file changed, 112 insertions(+)
>>
>> 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 f62df02847ac..66ae1228c6ad 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
>> @@ -27,6 +27,13 @@
>>    * - Context Pointers: Stage 1 and Stage 2 translation context 
>> addresses
>>    * - Raw Data: Complete 64-bit STE words in hexadecimal
>>    *
>> + * CD Information Displayed:
>> + * - Validity: Active state of the context descriptor
>> + * - T0SZ: Input address space size configuration
>> + * - EPD0/EPD1: Stage 1 translation enable flags
>> + * - TTBR0: Stage 1 translation table base address
>> + * - Raw Data: Complete CD structure in hexadecimal format
>> + *
>>    * Directory Structure:
>>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>>    * └── smmu0/
>> @@ -35,6 +42,8 @@
>>    *     └── stream_table
>>    *       └── 0000:01:00.0:0/                    # PCI device with 
>> Stream ID 0
>>    *             ├── ste                           # Stream Table Entry
>> + *             └── context_descriptors/
>> + *                 └── all                       # All Context 
>> Descriptors
>>    *
>>    * The capabilities file provides detailed information about:
>>    * - Architecture version and translation stage support (Stage1/Stage2)
>> @@ -59,6 +68,8 @@
>>   static struct dentry *smmuv3_root_dir;
>>   static DEFINE_MUTEX(arm_smmu_debugfs_lock);
>> +#define MAX_SSIDS    32    /* Reasonable limit for SSID enumeration */
> 
> Arbitrarily limiting to only 32 out of a potential 2^20 SSIDs seems odd, 
> like it's rather more than needed for basic sanity-checking, but far too 
> few for debugging specific usage.
> 
> FWIW I'd imagine it might be more useful to expose the CDs as individual 
> files by index - and if userspace does want an "all" dump then there's 
> always `cat`. Whether that would be all of them unconditionally based on 
> the current STE.S1CDMAX, or just the "active" ones based on PASID 
> allocations and S1DSS, is probably a question of what people think is 
> most useful (and/or how fiddly it is to actually implement the latter).
> 

I think 'active' may cover most debug scenarios.In the next version,
I'll remove the limit here.

>> +
>>   /**
>>    * smmu_debugfs_capabilities_show() - Display SMMU capabilities
>>    * @seq: seq_file to write to
>> @@ -329,6 +340,90 @@ static int smmu_debugfs_ste_show(struct seq_file 
>> *seq, void *v)
>>   }
>>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
>> +/**
>> + * smmu_debug_dump_cd() - Dump Context Descriptor details to seq_file
>> + * @seq: seq_file to write to
>> + * @dev: device associated with the CD
>> + * @ssid: Substream ID
>> + */
>> +static void smmu_debug_dump_cd(struct seq_file *seq, struct device 
>> *dev, u32 ssid)
>> +{
>> +    struct arm_smmu_master *master = dev_iommu_priv_get(dev);
>> +    struct arm_smmu_cd *cd;
>> +    u64 data;
>> +    int i;
>> +
>> +    if (!master) {
>> +        seq_puts(seq, "No master data\n");
>> +        return;
>> +    }
> 
> If userspace can read these files racily with devices being removed then:
> 
> 1) we should probably return an actual read error if the device has 
> already disappeared such the file is no longer valid.
> 
> 2) how do we know the device isn't going to disappear, and thus "master" 
> become invalid, immediately *after* this check happens to pass?
> 
> Thanks,
> Robin.
> 
Thank you for your review.
In the next version, I'll use lock protection and check the master again
in the lock.

>> +
>> +    cd = arm_smmu_get_cd_ptr(master, ssid);
>> +    if (!cd) {
>> +        seq_printf(seq, "CD not available for SSID %u\n", ssid);
>> +        return;
>> +    }
>> +
>> +    seq_printf(seq, "CD for Substream ID %u:\n", ssid);
>> +
>> +    /* CD 0 */
>> +    data = le64_to_cpu(cd->data[0]);
>> +    seq_printf(seq, "  Valid: %s\n", data & CTXDESC_CD_0_V ? "Yes" : 
>> "No");
>> +    seq_printf(seq, "  T0SZ: 0x%llx\n", data & CTXDESC_CD_0_TCR_T0SZ);
>> +    seq_printf(seq, "  EPD0: %s\n", data & CTXDESC_CD_0_TCR_EPD0 ? 
>> "Yes" : "No");
>> +    seq_printf(seq, "  EPD1: %s\n", data & CTXDESC_CD_0_TCR_EPD1 ? 
>> "Yes" : "No");
>> +
>> +    /* CD 1 */
>> +    data = le64_to_cpu(cd->data[1]);
>> +    seq_printf(seq, "  TTBR0: 0x%016llx\n", data & 
>> CTXDESC_CD_1_TTB0_MASK);
>> +
>> +    /* Display raw CD data */
>> +    seq_puts(seq, "  Raw Data:\n");
>> +    for (i = 0; i < CTXDESC_CD_DWORDS; i++)
>> +        seq_printf(seq, "    CD[%d]: 0x%016llx\n", i,
>> +               le64_to_cpu(cd->data[i]));
>> +}
>> +
>> +/**
>> + * smmu_debug_dump_all_cds() - Dump all valid Context Descriptors for 
>> a device
>> + * @seq: seq_file to write to
>> + * @dev: target device
>> + */
>> +static void smmu_debug_dump_all_cds(struct seq_file *seq, struct 
>> device *dev)
>> +{
>> +    struct arm_smmu_master *master = dev_iommu_priv_get(dev);
>> +    u32 max_ssids, ssid;
>> +
>> +    if (!master) {
>> +        seq_puts(seq, "No master data\n");
>> +        return;
>> +    }
>> +
>> +    max_ssids = min_t(u32, 1 << master->ssid_bits, MAX_SSIDS);
>> +
>> +    seq_printf(seq, "Context Descriptors for device (max SSIDs: %u):\n",
>> +           max_ssids);
>> +
>> +    for (ssid = 0; ssid < max_ssids; ssid++) {
>> +        struct arm_smmu_cd *cd = arm_smmu_get_cd_ptr(master, ssid);
>> +
>> +        if (cd && (le64_to_cpu(cd->data[0]) & CTXDESC_CD_0_V)) {
>> +            seq_printf(seq, "\n--- SSID %u ---\n", ssid);
>> +            smmu_debug_dump_cd(seq, dev, ssid);
>> +        }
>> +    }
>> +}
>> +
>> +/* All CDs debugfs file operations */
>> +static int smmu_debugfs_all_cds_show(struct seq_file *seq, void *v)
>> +{
>> +    struct device *dev = seq->private;
>> +
>> +    smmu_debug_dump_all_cds(seq, dev);
>> +    return 0;
>> +}
>> +DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_all_cds);
>> +
>>   /**
>>    * smmu_debugfs_create_stream_table() - Create debugfs entries for 
>> stream table
>>    * @dev: device to create entries for
>> @@ -388,9 +483,26 @@ int smmu_debugfs_create_stream_table(struct 
>> device *dev,
>>               goto cleanup_dev;
>>           }
>> +        /* Create CD directory */
>> +        cd_dir = debugfs_create_dir("context_descriptors", dev_dir);
>> +        if (!cd_dir) {
>> +            ret = -ENOMEM;
>> +            goto cleanup_dev;
>> +        }
>> +
>> +        /* Create "all" file to show all valid CDs */
>> +        all_cds_file = debugfs_create_file("all", 0444, cd_dir, dev,
>> +                           &smmu_debugfs_all_cds_fops);
>> +        if (!all_cds_file) {
>> +            ret = -ENOMEM;
>> +            goto cleanup_cd;
>> +        }
>> +
>>           /* Success for this stream ID, continue to next */
>>           continue;
>> +cleanup_cd:
>> +        debugfs_remove(cd_dir);
>>   cleanup_dev:
>>           debugfs_remove_recursive(dev_dir);
>>   cleanup:
> 
> 

-- 
Thanks,
Qinxin




More information about the linux-arm-kernel mailing list