struct irq_domain {这个数据结构是属于linux kernel通用中断子系统的一部分,我们这里只是描述相关的数据成员。host_data成员是底层interrupt controller的私有数据,linux kernel通用中断子系统不应该修改它。对于GIC而言,host_data成员指向一个struct gic_chip_data的数据结构,定义如下:
……
const struct irq_domain_ops *ops;
void *host_data;
……
};
struct gic_chip_data {对于GIC支持的IRQ的数目,这里还要赘述几句。实际上并非GIC支持多少个HW interrupt ID,其就支持多少个IRQ。对于SGI,其处理比较特别,并不归入IRQ number中。因此,对于GIC而言,其SGI(从0到15的那些HW interrupt ID)不需要irq domain进行映射处理,也就是说SGI没有对应的IRQ number。如果系统越来越复杂,一个GIC不能支持所有的interrupt source(目前GIC支持1020个中断源,这个数目已经非常的大了),那么系统还需要引入secondary GIC,这个GIC主要负责扩展外设相关的interrupt source,也就是说,secondary GIC的SGI和PPI都变得冗余了(这些功能,primary GIC已经提供了)。这些信息可以协助理解代码中的hwirq_base的设定。
union gic_base dist_base;------------------GIC Distributor的基地址空间
union gic_base cpu_base;------------------GIC CPU interface的基地址空间
#ifdef CONFIG_CPU_PM--------------------GIC 电源管理相关的成员
u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
u32 __percpu *saved_ppi_enable;
u32 __percpu *saved_ppi_conf;
#endif
struct irq_domain *domain;-----------------该GIC对应的irq domain数据结构
unsigned int gic_irqs;-------------------GIC支持的IRQ的数目
#ifdef CONFIG_GIC_NON_BANKED
void __iomem *(*get_base)(union gic_base *);
#endif
};
static const struct irq_domain_ops gic_irq_domain_ops = {irq domain的概念是一个通用中断子系统的概念,在具体的irq chip driver这个层次,我们需要一些解析GIC binding,创建IRQ number和HW interrupt ID的mapping的callback函数,更具体的解析参考后文的描述。
.map = gic_irq_domain_map,
.unmap = gic_irq_domain_unmap,
.xlate = gic_irq_domain_xlate,
};
static void __init gic_dist_init(struct gic_chip_data *gic)(a)Distributor Control Register用来控制全局的中断forward情况。写入0表示Distributor不向CPU interface发送中断请求信号,也就disable了全部的中断请求(group 0和group 1),CPU interace再也收不到中断请求信号了。在初始化的最后,step(f)那里会进行enable的动作(这里只是enable了group 0的中断)。在初始化代码中,并没有设定interrupt source的group(寄存器是GIC_DIST_IGROUP),我相信缺省值就是设定为group 0的。
{
unsigned int i;
u32 cpumask;
unsigned int gic_irqs = gic->gic_irqs;---------获取该GIC支持的IRQ的数目
void __iomem *base = gic_data_dist_base(gic); ----获取该GIC对应的Distributor基地址
writel_relaxed(0, base + GIC_DIST_CTRL); -----------(a)
cpumask = gic_get_cpumask(gic);---------------(b)
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;------------------(c)
for (i = 32; i < gic_irqs; i += 4)
writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); --(d)
gic_dist_config(base, gic_irqs, NULL); ---------------(e)
writel_relaxed(1, base + GIC_DIST_CTRL);-------------(f)
}
static u8 gic_get_cpumask(struct gic_chip_data *gic)这里操作的寄存器是Interrupt Processor Targets Registers,该寄存器组中,每个GIC上的interrupt ID都有8个bit来控制送达的target CPU。我们来看看下面的图片:
{
void __iomem *base = gic_data_dist_base(gic);
u32 mask, i;
for (i = mask = 0; i < 32; i += 4) {
mask = readl_relaxed(base + GIC_DIST_TARGET + i);
mask |= mask >> 16;
mask |= mask >> 8;
if (mask)
break;
}
return mask;
}
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) | Powered by Discuz! 7.0.0 |