2、GIC driver初始化代码分析
(1)gic_of_init的代码如下:
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *cpu_base;
void __iomem *dist_base;
u32 percpu_offset;
int irq;
dist_base = of_iomap(node, 0);----------------映射GIC Distributor的寄存器地址空间
cpu_base = of_iomap(node, 1);----------------映射GIC CPU interface的寄存器地址空间
if (of_property_read_u32(node, "cpu-offset", &percpu_offset))--------处理cpu-offset属性。
percpu_offset = 0;
gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);))-----主处理过程,后面详述
if (!gic_cnt)
gic_init_physaddr(node); -----对于不支持big.LITTLE switcher(CONFIG_BL_SWITCHER)的系统,该函数为空。
if (parent) {--------处理interrupt级联
irq = irq_of_parse_and_map(node, 0); ---解析second GIC的interrupts属性,并进行mapping,返回IRQ number
gic_cascade_irq(gic_cnt, irq);
}
gic_cnt++;
return 0;
}
我们首先看看这个函数的参数,node参数代表需要初始化的那个interrupt controller的device node,parent参数指向其parent。在映射GIC-400的memory map I/O space的时候,我们只是映射了Distributor和CPU interface的寄存器地址空间,和虚拟化处理相关的寄存器没有映射,因此这个版本的GIC driver应该是不支持虚拟化的(不知道后续版本是否支持,在一个嵌入式平台上支持虚拟化有实际意义吗?最先支持虚拟化的应该是ARM64+GICV3/4这样的平台)。
要了解cpu-offset属性,首先要了解什么是banked register。所谓banked register就是在一个地址上提供多个寄存器副本。比如说系统中有四个CPU,这些CPU访问某个寄存器的时候地址是一样的,但是对于banked register,实际上,不同的CPU访问的是不同的寄存器,虽然它们的地址是一样的。如果GIC没有banked register,那么需要提供根据CPU index给出一系列地址偏移,而地址偏移=cpu-offset * cpu-nr。
interrupt controller可以级联。对于root GIC,其传入的parent是NULL,因此不会执行级联部分的代码。对于second GIC,它是作为其parent(root GIC)的一个普通的irq source,因此,也需要注册该IRQ的handler。由此可见,非root的GIC的初始化分成了两个部分:一部分是作为一个interrupt controller,执行和root GIC一样的初始化代码。另外一方面,GIC又作为一个普通的interrupt generating device,需要象一个普通的设备驱动一样,注册其中断handler。理解irq_of_parse_and_map需要irq domain的知识,请参考linux kernel的中断子系统之(二):irq domain介绍。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shumachanpin/article-76887-7.html
易烊千玺很棒