linux内核笔记之SMMU代码分析

linux内核笔记之SMMU代码分析
2020/06/10: first version, 主要介绍smmu驱动的初始化流程
在前⼀篇博⽂中, 介绍了SMMU的⼀些基本概念以及SMMU地址转换的基本流程,本⽂主要分析linux kernel中SMMUv3的代码() linux kernel版本是linux 5.7, 体系结构是aarch64
smmu的位置
SMMU的作⽤是把CPU提交给设备的VA地址,直接作为设备发出的地址,变成正确的物理地址,访问到物理内存上。
和mmu不同的是,⼀个smmu可以有多个设备连着,他们的页表不可能复⽤,SMMU ⽤stream id作区分。
⼀个设备有多个进程,所以smmu单元也要⽀持多页表,smmu使⽤substream id区分多进程的页表。
smmu的设备节点定义
在讨论smmu的代码前,先看下smmu的设备节点是怎么定义的:
Example:
smmu@2b400000 {
朗文交互compatible ="arm,smmu-v3";
reg =<0x00x2b4000000x00x20000>;
interrupts =<GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 77 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 79 IRQ_TYPE_EDGE_RISING>;
interrupt-names ="eventq","priq","cmdq-sync","gerror";
dma-coherent;
#iommu-cells =<1>;
msi-parent =<&its 0xff0000>;
};
compatible: ⽤于匹配smmu驱动。
reg:smmu设备的物理基地址。
interrupts: 描述与中断名称对应的smmu中断源,上述分别对应中断类型,中断号以及中断触发⽅式。
interrupt-names: 中断名称。
eventq,当event queue从空变为⾮空状态时上报中断。
priq, 当pri queue从空变为⾮空状态时上报中断。
cmdq-sync, command queue中CMDQ_SYNC命令完成时产⽣中断。
gerror,event记录到event queue过程中产⽣的错误会记录在SMMU_GERROR寄存器中,并产⽣中断。
combined,组合中断,需要硬件⽀持,如果提供了组合中断,则将优先使⽤组合中断。
dma-coherent:表⽰设备通过smmu进⾏的DMA访问是否cache coherent的,假设DMA把外设的数据搬运到内存的某个位置,cpu去读那段地址,因为cache命中了,读到的还是旧的值,这就是cache的不coherent。
#iommu-cells: ⼀个cell代表⼀个streamid, smmu-v3必须定义为1。
msi-parent:指定msi中断控制器。
SMMU结构体
struct arm_smmu_domain {
struct arm_smmu_device  *smmu;
struct mutex  init_mutex;/* Protects smmu pointer */
struct io_pgtable_ops  *pgtbl_ops;
bool    non_strict;
爱八卦
atomic_t  nr_ats_masters;
enum arm_smmu_domain_stage stage;
union {
struct arm_smmu_s1_cfg s1_cfg;
struct arm_smmu_s2_cfg s2_cfg;
};
struct iommu_domain  domain;
struct list_head  devices;
spinlock_t  devices_lock;
};
arm_smmu_device: 指定smmu设备
io_pgtable_ops: io页表映射定义的⼀系列操作
阿富汗将有新宪法
non_strict: smmu non-strict模式,在该补丁集中引⼊ ,
主要是为了解决开启smmu后,频繁的unmap,需要频繁的invalid tlb带来的性能损失, 所以不在每⼀次unmap后都进⾏tlb invalidate操作,⽽是累计⼀定次数或者时间后执⾏invalid all操作,但这样是有⼀定的安全风险(页表虽然释放了但是还是在tlb中有残留,可能被利⽤到)。可以通过启动参数控制。
nr_ats_masters: ats的设备数量,enable_ats时数量+1, disable ats时数量减1
arm_smmu_domain_stage: 代表smmu⽀持的⽅式,⽀持stage1的转换,stage2的转换,stage1 + stage2的转换,以及bypass模式。
arm_smmu_s1_cfg: stage1转换需要的数据结构
arm_smmu_s2_cfg: stage2转换需要的数据结构
smmu驱动初始化
从smmu驱动的probe函数开始分析
+->arm_smmu_device_probe()//smmu设备驱动probe⼊⼝函数
+->arm_smmu_device_dt_probe()//smmu设备树解析
+->platform_get_irq_byname()// smmu设备中断解析
+->arm_smmu_device_hw_probe()// smmu硬件规格探测
+->arm_smmu_init_structures()//smmu 数据结构初始化
+->arm_smmu_device_reset()// smmu设备复位, 硬件初始化配置
+->iommu_device_register()// iommu设备注册
+->arm_smmu_set_bus_ops()// 给⽀持的总线设置bus->iommu_ops
对probe中调⽤的这些函数进⾏详细分析
(1)arm_smmu_device_dt_probe
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
struct arm_smmu_device *smmu)
{
int ret =-EINVAL;
if(of_property_read_u32(dev->of_node,"#iommu-cells",&cells))----(a)
dev_err(dev,"missing #iommu-cells property\n");
else if(cells !=1)
人口结构dev_err(dev,"invalid #iommu-cells value (%d)\n", cells);
else
ret =0;
parse_driver_options(smmu);-----(b)
if(of_dma_is_coherent(dev->of_node))----(c)
smmu->features |= ARM_SMMU_FEAT_COHERENCY;
return ret;
}
a. 读取设备树,看smmu的设备节点定义中#iommu-cells是否为1, 如果不为1则直接bypass 掉smmu
b. parse_driver_options, 主要解析smmu是否有需要规避的硬件bug
c. 解析smmu设备中的dma-coherent属性
(2) platform_get_irq_byname
/* Interrupt lines */乳品论坛
irq =platform_get_irq_byname_optional(pdev,"combined");
if(irq >0)
smmu->combined_irq = irq;
else{
irq =platform_get_irq_byname_optional(pdev,"eventq");
if(irq >0)
smmu->evtq.q.irq = irq;
irq =platform_get_irq_byname_optional(pdev,"priq");
if(irq >0)
smmu->priq.q.irq = irq;
irq =platform_get_irq_byname_optional(pdev,"gerror");
if(irq >0)
smmu->gerr_irq = irq;
}
分别获取dts节点中定义的"combined", “eventq”, “priq”, "gerror"中断号
(3) arm_smmu_device_hw_probe
该函数主要探测smmu设备的硬件规格,主要是通过读SMMU的IDR0,IDR1,IDR5寄存器确认
SMMU_IDR0:
域段offset作⽤
ST_LEVEL28: 27确认stream table格式是线性table还是2-level table
TERM_MODEL26fault的处理⽅式,
STALL_MODEL25: 24确认是否是stall mode。 该模式下smmu会暂停引发stall的transaction, 然后stall,之后根据软件的commad是resume还是stall_term来决定stall命令是retry还是terminate。当前只允许4种fault类型被stall: F_TRANSLATION, F_ACCESS,
F_ADDR_SIZE. F_PERMISSION.【spec 5.5 Fault configuration (A,R,S bits)】
TTENDIAN22: 21确认traslation table⽀持的⼤⼩端模式CD2L19确认是否⽀持2-level 的CD table
VMW17⽤于控制vmid wildcards的功能和范围。 vmid wildcard, vmid的模糊匹配,是为了⽅便tlb⽆
效化, 两种tlb⽆效化的⽅式:command和⼴播tlb⽆效都会使⽤到vmid wildcards
VMID1618确认是否⽀持16bit VMID。 每⼀个虚拟机都被分配⼀个ID号,这个ID号⽤于标记某个特定的TLB项属于哪⼀个VM。每⼀个VM有它⾃⼰的ASID空间。例如两个不同的VMs同时使⽤ASID 5,但指的是不同的东西。对于虚拟机⽽⾔,通常VMID会结合ASID同时使⽤。
PRI16确认是否⽀持page request interface。 属于pcie 硬件特性,PCIe设备可以发出缺页请求,SMMU硬件在解析到缺页请求后可以直接将缺页请求写⼊PRI queueu, 软件在建⽴好页表后,可以通过CMD queue发送PRI response给PCIe设备。
SEV14确认是否⽀持WFE wake-up事件的产⽣。 当SEV == 1时,command queue从满到⾮满状态会触发WFE wake-up event。 此外,当CMD_SYNC完成且要求SIG_SEV时也会产⽣WFE wake-up event
MSI13确认是否⽀持MSI消息中断
ASID1612确认是否⽀持16bit ASID.。 在TLB的表项中,每个项都有⼀个ASID,当切换进程的时候,TLB中可以存在多个进程的页表项, 不再需要清空TLB,因为B进程⽤不了⾥⾯A进程的页表项,可以带来性能提升。
ATS10Address Translation Service, 也是pcie的硬件特性,有ATS能⼒的PCIE,⾃带地址翻译功能,如果它要发出⼀个地址,进⼊PCIE总线的时候,⼀定程度上可以认为就是物理地址。ats会在设备中缓存va对应的pa, 设备随后使⽤pa做内存访问时⽆需经过SMMU页表转换,可以提⾼性能。 【】
HTTU7:6Hardware Translation Table Update,在访问或写⼊相关页⾯后,硬件⾃动更新相关页⾯的Access flag、Dirty state。该特性和armv8.1的tthm特性⼀样,在没有tthm 特性之前,软件去更新页表的young和dirty page, 会有⼀定的开销。
S1P1确认是否⽀持stage1转换,va->pa
S2P0确认是否⽀持stage2转换,ipa->pa
域段offset作⽤
SMMU_IDR1:
域段offset作⽤
TABLES_PRESET30确认smmu_strtab_base和smmu_strtab_base_cfg的基地址是否固定, smmu_strtab_base是stream table的物理基地址,smmu_strtab_base_cfg是stream table的配置寄存器
QUEUES_PRESET29确认smmu queue的基地址是否固定,queue指的是smmu event queue, smmu cmd queue, smmu pri queue CMDQS25:21cmd queue 最⼤entry数⽬, 等于log2(entries), 最⼤是19
EVENTQS20:16event queue的最⼤entry数⽬,等于log2(entries), 最⼤是19
PRIQS15:11pri queue 最⼤entry数⽬,等于log2(entries), 最⼤是19
SSIDSIZE10:6确认硬件⽀持substreamID的bit数,范围为【0,20】, 0表⽰不⽀持substreamid
SIDSIZE5:0确认硬件⽀持streamID的bit数,范围为【0,32】, 0表⽰⽀持⼀个stream
IDR1主要⽤来设置smmu 各个queue的entry数量, 设置ssid和sid的size.
SMMU_IDR5:
域段offset作⽤
STALL_MAX31:16smmu⽀持的最⼤未完成stall 事务数
VAX11:10表⽰smmu⽀持的va地址是48bit还是52bit
GRAN64K6⽀持64KB翻译粒度, Translation Granule表⽰translation table的size⼤⼩, 页表粒度是smmu管理的最⼩地址空间GRAN16K5⽀持16KB翻译粒度
GRAN4K4⽀持4KB翻译粒度
OAS2:0表⽰output address size, 32bit ~ 52bit
域段offset作⽤
IDR5主要设置smmu ias(input address size) 和 oas (output address size), ias代表IPA,oas代表PA。
(4)arm_smmu_init_structures()
smmu相关的数据结构的内存申请和初始化
static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
{
int ret;
ret =arm_smmu_init_queues(smmu);-----------------(a)
if(ret)
return ret;
return arm_smmu_init_strtab(smmu);-----------------(b)
}
(a) arm_smmu_init_queues() 会初始化三个queue, 分别为cmd queue, event queue, pri queue.
SMMU使⽤这3个队列做基本的事件管理。
event queue⽤于记录软件配置错误的状态信息,smmu将配置错误信息记录到event queue中,软件会通过从event queue读取配置错误信息,然后进⾏相应的配置错误处理。
软件使⽤command queue和smmu 硬件进⾏交互,软件写命令发送到command queue中,smmu会从command queue中读取命令进⾏处理。
pri queue需要硬件⽀持pri 特性,和event queue类似,当有相应硬件事件发⽣时,硬件把相应的描述符写⼊pri queue, 然后上报中断。
(b) arm_smmu_init_strtab
static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
{
u64 reg;
int ret;
if(smmu->features &ARM_SMMU_FEAT_2_LVL_STRTAB)
ret =arm_smmu_init_strtab_2lvl(smmu);
else
ret =arm_smmu_init_strtab_linear(smmu);
if(ret)
return ret;
/
* Set the strtab base address */
reg  = smmu->strtab_cfg.strtab_dma &STRTAB_BASE_ADDR_MASK;
reg |=STRTAB_BASE_RA;
smmu->strtab_cfg.strtab_base = reg;
/* Allocate the first VMID for stage-2 bypass STEs */
set_bit(0, smmu->vmid_map);
return0;
}辐照度

本文发布于:2024-09-22 06:46:44,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/231410.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:设备   中断   硬件   地址   页表   是否
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议