- UID
- 1029342
- 性别
- 男
|
(5)gic_retrigger
这个接口用来resend一个IRQ到CPU。
static int gic_retrigger(struct irq_data *d)
{
if (gic_arch_extn.irq_retrigger)
return gic_arch_extn.irq_retrigger(d);
/* the genirq layer expects 0 if we can't retrigger in hardware */
return 0;
}
看起来这是功能不是通用GIC拥有的功能,各个厂家在集成GIC的时候,有可能进行功能扩展。
(6)gic_set_affinity
在多处理器的环境下,外部设备产生了一个中断就需要送到一个或者多个处理器去,这个设定是通过设定处理器的affinity进行的。具体代码如下:
static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force)
{
void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
u32 val, mask, bit;
if (!force)
cpu = cpumask_any_and(mask_val, cpu_online_mask);---随机选取一个online的cpu
else
cpu = cpumask_first(mask_val); --------选取mask中的第一个cpu,不管是否online
raw_spin_lock(&irq_controller_lock);
mask = 0xff << shift;
bit = gic_cpu_map[cpu] << shift;-------将CPU的逻辑ID转换成要设定的cpu mask
val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg);
raw_spin_unlock(&irq_controller_lock);
return IRQ_SET_MASK_OK;
}
GIC Distributor中有一个寄存器叫做Interrupt Processor Targets Registers,这个寄存器用来设定制定的中断送到哪个process去。由于GIC最大支持8个process,因此每个hw interrupt ID需要8个bit来表示送达的process。每一个Interrupt Processor Targets Registers由32个bit组成,因此每个Interrupt Processor Targets Registers可以表示4个HW interrupt ID的affinity,因此上面的代码中的shift就是计算该HW interrupt ID在寄存器中的偏移。
(7)gic_set_wake
这个接口用来设定唤醒CPU的interrupt source。对于GIC,代码如下:
static int gic_set_wake(struct irq_data *d, unsigned int on)
{
int ret = -ENXIO;
if (gic_arch_extn.irq_set_wake)
ret = gic_arch_extn.irq_set_wake(d, on);
return ret;
}
设定唤醒的interrupt和具体的厂商相关,这里不再赘述。
4、BSP(bootstrap processor)之外,其他CPU的callback函数
对于multi processor系统,不可能初始化代码在所有的processor上都执行一遍,实际上,系统的硬件会选取一个processor作为引导处理器,我们称之BSP。这个processor会首先执行,其他的CPU都是处于reset状态,等到BSP初始化完成之后,release所有的non-BSP,这时候,系统中的各种外设硬件条件和软件条件(例如per CPU变量)都准备好了,各个non-BSP执行自己CPU specific的初始化就OK了。
上面描述的都是BSP的初始化过程,具体包括:
……
gic_dist_init(gic);------初始化GIC的Distributor
gic_cpu_init(gic);------初始化BSP的CPU interface
gic_pm_init(gic);------初始化GIC的Power management
……
对于GIC的Distributor和Power management,这两部分是全局性的,BSP执行初始化一次就OK了。对于CPU interface,每个processor负责初始化自己的连接的那个CPU interface HW block。我们用下面这个图片来描述这个过程:
假设CPUx被选定为BSP,那么第三章描述的初始化过程在该CPU上欢畅的执行。这时候,被初始化的GIC硬件包括:root GIC的Distributor、root GIC CPU Interface x(连接BSP的那个CPU interface)以及其他的级联的非root GIC(上图中绿色block,当然,我偷懒,没有画non-root GIC)。
BSP初始化完成之后,各个其他的CPU运行起来,会发送CPU_STARTING消息给关注该消息的模块。毫无疑问,GIC driver模块当然要关注这样的消息,在初始化过程中会注册callback函数如下:
register_cpu_notifier(&gic_cpu_notifier);
GIC相关的回调函数定义如下:
static struct notifier_block gic_cpu_notifier = {
.notifier_call = gic_secondary_init,
.priority = 100,
};
static int gic_secondary_init(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
gic_cpu_init(&gic_data[0]);---------初始化那些非BSP的CPU interface
return NOTIFY_OK;
}
因此,当non-BSP booting up的时候,发送CPU_STARTING消息,调用GIC的callback函数,对上图中的紫色的CPU Interface HW block进行初始化,这样,就完成了全部GIC硬件的初始化过程。 |
|