参考文档
Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
dts 信息
ex:
提供了两个interrupt file M-mode 和 S-mode的.
1 | imsic_mlevel: interrupt-controller@24000000 { |
下面对上述dts的相关属性做一个大概的介绍
- interrupts-extended
对应cpu1-4, 每个cpu都有这两个interrupt file M-mode和S-mode的
M的对应中断位为11, 代表 Machine external interrupt
S的对应中断位为9, 代表 Supervisor external interrupt - riscv,num-ids
Number of interrupt identities supported by IMSIC interrupt file.
外部中断数量, 反映到eip和eie中, 最小63 最大 2047 - riscv,group-index-bits
Number of group index bits in the MSI target address. When not specified it is assumed to be 0.
总的group index bits - riscv,group-index-shift
The least significant bit position of the group index bits in the MSI target address. When not specified it is assumed to be 24. - reg
Base address of each IMSIC group.
关于MSI target address:
从第24 bit 开始, 上述group-index-bits 表示在Group Index中总共有几个bit 被使用
riscv,group-index-shift 表示Group Index中当前interrupt file 占位开始的那个bit位, 如其占了两个bit位 26-27, shift表示最开始的bit位 26.
1 | XLEN-1 >=24 12 0 |
guest os相关
guest external interrupt 相关的dts信息
- riscv,num-guest-ids
Number of interrupt identities are supported by IMSIC guest interrupt
file. When not specified it is assumed to be same as specified by the
riscv,num-ids property.
guest external 硬件中断号 最小63 最大2047 - riscv,hart-index-bits
Number of HART index bits in the MSI target address. When not
specified it is estimated based on the interrupts-extended property.
MSI target address 中 Hart Index 总共使用了几个bit位.
最小0 最大 15 - riscv,guest-index-bits
Number of HART index bits in the MSI target address. When not
specified it is estimated based on the interrupts-extended property.
MSI target address 中 Guest Index 总共使用了几个bit位.
最小0 最大 7
下面开始大概分析 imsic 的代码
代码部分
imsic_init
dts 相关封装的接口
1 | struct imsic_fwnode_ops ops = { |
1 | -+ imsic_init(struct imsic_fwnode_ops *fwops, struct fwnode_handle *fwnode, void *fwopaque) |
比较重要的数据:
global->base_addr
handler->local.msi_pa / handler->local.msi_va
imsic_handle_irq
S external interrupt 中断来了之后, 会由 imsic_handle_irq 函数进行处理, 简单看一下外部中断处理的流程
1 | -+ imsic_handle_irq(struct irq_desc *desc) |
还是大体上是这个结构, 这个上面也有loop, 代表需要多次处理stopei, 从高优先级->低优先级依次处理完本次来的所有的S-mode的外部中断.
chip imsic 相关hook
1 | static struct irq_chip imsic_irq_base_chip = { |
imsic_irq_set_affinity
在外设驱动注册hwirq 中断时, 会走到 irq_set_affinity, 进而调用chip的 irq_set_affinity 钩子.
对于imsic来说, 调用 imsic_irq_set_affinity 函数设置cpu亲和性, 即该外部中断由哪个cpu进行处理
简单分析下这个函数
1 | -+ imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) |
说明与hwirq 开启需要设置的csr 操作并未在这个函数中
- of_irq_get -> irq_create_of_mapping -> irq_domain_alloc_irqs -> irq_domain_alloc_irqs_hierarchy -> domain->ops->alloc(domain, irq_base, nr_irqs, arg)
- request_irq -> request_threaded_irq -> irq_startup ->
__irq_startup
-> irq_enable -> unmask_irq(desc) -> chip->irq_unmask(&desc->irq_data);
.alloc = imsic_irq_domain_alloc
1 | static const struct irq_domain_ops imsic_base_domain_ops = { |
相关堆栈
1 | #1 0xffffffff8006a134 in irq_domain_alloc_irqs_hierarchy (arg=0xff2000000060b728, nr_irqs=1, irq_base=2, domain=0xff6000007fe0c800) at ../kernel/irq/irqdomain.c:1426 |
unmask_irq 相关堆栈
1 | #0 plic_irq_unmask (d=0xff6000007fefec20) at ../drivers/irqchip/irq-sifive-plic.c:122 |
imsic_irq_domain_alloc
1 | -+ imsic_irq_domain_alloc(struct irq_domain *domain, |
unmask_irq -> imsic_irq_unmask
1 | -+ imsic_irq_unmask(struct irq_data *d) |
最终由unmask_irq -> imsic_irq_unmask 打开中断, 最后设置了该hart的 siselct 和 sireg csr, 将对应的eipx/eiex 置位.
小结与思考
从上面中断注册和中断处理过程中, 可以看到每个 hart 对应的MSI的mmio
对于S-mode来说, 外部中断设置的最终是__imsic_id_enable(id)
该函数最终设置的是 eipx/eiex, 通过siselct 与 sireg 这两个csr 选择对应的 eipx/eiex, 再设置对应的值, 即可开关对应的pending/中断使能, csr 是hart 专属的, 每一个hart 都由一组csr.
imsic_irq_mask
imsic_irq_unmask
最终关联 __imsic_id_enable
__imsic_id_disable
这一组函数
irq_mask 中断屏蔽
irq_unmask 中断打开
但这其中并未发现直接的mmio 地址关联
上述中断开关最终都是操作的siselect/sireg 寄存器, 猜测最终都是设置的该hart的 S-mode interrupt file的mmio region.
与guest interrupt file 相关的设置在哪里呢, 怀疑的地方是msi相关的函数 imsic_irq_compose_msi_msg
该提交中看起来并没有涉及到 guest 相关的设置.
除了初始化函数中与guest_index 相关的内容外, 并没有其他的.