ARM SMMU v3 队列实现详解
1. 队列结构设计
1.1 核心数据结构
            
            
              490:504:drivers/iommu/arm-smmu-v3.c
              
              
            
          
          struct arm_smmu_ll_queue {
    union {
        u64            val;
        struct {
            u32        prod;
            u32        cons;
        };
        struct {
            atomic_t    prod;
            atomic_t    cons;
        } atomic;
        u8            __pad[SMP_CACHE_BYTES];
    } ____cacheline_aligned_in_smp;
    u32                max_n_shift;
};
        1.2 队列宏定义
            
            
              183:188:drivers/iommu/arm-smmu-v3.c
              
              
            
          
          #define Q_IDX(llq, p)            ((p) & ((1 << (llq)->max_n_shift) - 1)) // 队列索引计算
#define Q_WRP(llq, p)            ((p) & (1 << (llq)->max_n_shift)) // 队列环绕
#define Q_OVERFLOW_FLAG            (1U << 31)
#define Q_OVF(p)            ((p) & Q_OVERFLOW_FLAG) // 溢出检测
#define Q_ENT(q, p)            ((q)->base +            \
                     Q_IDX(&((q)->llq), p) *    \
                     (q)->ent_dwords)  // 队列中某条目的地址  基地址 + 索引 × 条目大小
        2. 队列类型分析
2.1 是环形队列吗?
是的,这是环形队列:
- 使用 
prod(生产者指针) 和cons(消费者指针) - 通过 
Q_IDX宏实现环形索引:(p) & ((1 << max_n_shift) - 1) - 队列大小是2的幂次方,便于位运算优化
 
2.2 支持多生产者多消费者吗?
部分支持:
多生产者:
- 使用 
atomic_t类型的prod和cons - 通过原子操作保证并发安全
 - 支持多个CPU核心同时写入
 
多消费者:
- 命令队列(CMDQ):单消费者(硬件消费)
 - 事件队列(EVTQ):单消费者(软件消费)
 - 优先级队列(PRIQ):单消费者(软件消费)
 
2.3 是无锁队列吗?
不是完全无锁:
无锁部分:
- 使用原子操作进行指针更新
 - 生产者使用 
atomic_t保证并发安全 
有锁部分:
            
            
              527:532:drivers/iommu/arm-smmu-v3.c
              
              
            
          
          struct arm_smmu_cmdq {
    struct arm_smmu_queue        q;
    atomic_long_t            *valid_map;
    atomic_t            owner_prod;
    atomic_t            lock;
};
        3. 队列操作机制
3.1 空间检查
            
            
              713:727:drivers/iommu/arm-smmu-v3.c
              
              
            
          
          static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n)
{
    u32 space, prod, cons;
    prod = Q_IDX(q, q->prod);
    cons = Q_IDX(q, q->cons);
    if (Q_WRP(q, q->prod) == Q_WRP(q, q->cons))
        space = (1 << q->max_n_shift) - (prod - cons);
    else
        space = cons - prod;
    return space >= n;
}
        3.2 状态判断
            
            
              728:736:drivers/iommu/arm-smmu-v3.c
              
              
            
          
          static bool queue_full(struct arm_smmu_ll_queue *q)
{
    return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
           Q_WRP(q, q->prod) != Q_WRP(q, q->cons);
}
static bool queue_empty(struct arm_smmu_ll_queue *q)
{
    return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
           Q_WRP(q, q->prod) == Q_WRP(q, q->cons);
}
        4. 特殊设计特点
4.1 Wrap位机制
- 使用 
Q_WRP宏检测队列是否已环绕一圈 - 通过比较wrap位判断队列状态
 - 避免队列满/空的歧义
 
4.2 溢出检测
- 使用 
Q_OVERFLOW_FLAG(第31位) 检测溢出 - 防止32位计数器溢出问题
 
4.3 缓存行对齐
            
            
              501:502:drivers/iommu/arm-smmu-v3.c
              
              
            
          
                  u8            __pad[SMP_CACHE_BYTES];
    } ____cacheline_aligned_in_smp;
        - 确保队列结构体按缓存行对齐
 - 减少伪共享(false sharing)问题
 
5. 三种队列类型
5.1 命令队列(CMDQ)
- 用途:CPU向SMMU发送命令
 - 特点:多生产者,单消费者(硬件)
 - 同步:需要等待硬件处理完成
 
5.2 事件队列(EVTQ)
- 用途:SMMU向CPU报告事件
 - 特点:单生产者(硬件),单消费者(软件)
 - 处理:通过中断处理
 
5.3 优先级队列(PRIQ)
- 用途:处理页面请求
 - 特点:单生产者(硬件),单消费者(软件)
 - 可选:根据硬件特性决定是否启用
 
6. 总结
ARM SMMU v3的队列实现是一个高性能的环形队列,具有以下特点:
- 环形设计:使用位运算实现高效的环形索引
 - 并发支持:支持多生产者,使用原子操作保证线程安全
 - 硬件协同:与SMMU硬件紧密配合,支持硬件直接访问
 - 性能优化:缓存行对齐,减少内存访问冲突
 - 可靠性:包含溢出检测和wrap位机制,确保队列状态正确
 
这种设计既保证了高性能,又确保了在复杂硬件环境下的可靠性。