Stream ID(SID)不是某条总线标准里"天然存在"的字段,而是 SMMU/系统互连层面用来标识"这次 DMA 是谁发起的"的实现定义 ID。
一句话:
Stream ID 由系统/SoC/Root Complex 设计者根据上游事务的标识信息生成;对 PCIe 来说通常就是 Requester ID,对片上总线来说通常是 AXI ID / Master ID / 端口号等 sideband 信号。
1. ARM SMMU 里 Stream ID 的本质
ARM 规范原话:
StreamID encoding is IMPLEMENTATION DEFINED。
SMMU 不关心设备叫什么名字,只看事务带进来的 Stream ID,然后:
Stream ID → Stream Table Entry (STE) → 翻译上下文 / 页表 / VM / 权限
所以 Stream ID 就是 SMMU 的"设备身份证"。
2. PCIe 场景:Stream ID ≈ Requester ID
PCIe TLP 里没有"Stream ID",只有:
Requester ID = Segment : Bus : Device : Function
ARM 的推荐做法是:
-
低 16 位:
StreamID[15:0] == RequesterID[15:0] -
多个 PCI segment / Root Complex 时,高位再拼:
StreamID[17:0] = { pci_domain[1:0], RequesterID[15:0] }
也就是:
PCIe 设备的 Stream ID,通常由 Root Complex 把 Requester ID 映射/拼接到 SMMU 的 Stream ID 空间。
Substream ID 则对应 PCIe PASID。
3. 片上总线(AXI / ACE / DTI / 自研互连):由 SoC 硬连线或固件分配
对 GPU、NPU、ISP、DMA、Codec 这类非 PCIe 主设备:
Stream ID 可能来自:
- AXI
AWID/ARID - Master ID
- 端口号
- 安全状态 NS bit
- 读写方向
- 设备内部 channel / queue 编号
例如某个 SoC:
StreamID = { TBU_ID[14:10], MasterID[9:6], AXI_ID[5:0] }
或者更简单:
GPU -> StreamID 0x10
NPU -> StreamID 0x11
ISP -> StreamID 0x12
DMA0 -> StreamID 0x20
这些关系不是设备自己随便发的,而是:
- RTL 里把主设备端口接到互连时定好
- 再通过 Device Tree / ACPI 告诉 OS: 这个 device node 对应哪个 SMMU 的哪个 Stream ID
4. Stream ID 的几个关键性质
① 每个 SMMU 独立命名空间
不同 SMMU 下 Stream ID=5 是两个不同设备。
② 一个设备可以用多个 Stream ID
比如:
- 控制流用一个 SID
- 数据流用另一个 SID
- 安全世界 / 非安全世界不同 SID
③ Stream ID ≠ PASID / Substream ID
Stream ID :哪个设备
Substream ID :该设备里的哪个地址空间(通常 = PASID)
④ Secure / Non-secure 会再限定一次
同一个数值 SID,在 Secure 和 Non-secure 命名空间里可以对应不同 STE。
5. 和 Intel VT-d 的对照
Intel VT-d 没有 Stream ID 这个概念,它直接用:
PCIe Requester ID (BDF)
→ Root Table
→ Context Table
→ PASID Table(Scalable Mode)
所以:
| 架构 | 设备标识 | 细粒度标识 |
|---|---|---|
| ARM SMMU | Stream ID | Substream ID = PASID |
| Intel VT-d | Requester ID (BDF) | PASID |
| AMD-Vi | Device Table Index(常由 BDF 算) | PASID |
6. 一句话总结
Stream ID 不是协议标准字段,而是"系统给 DMA 事务贴的标签":
- PCIe 系统里通常 = Requester ID
- SoC 里通常 = AXI/Master/Port ID
- 具体怎么拼、怎么分配,由硬件设计 + 固件(DT/ACPI)决定