DSP

卷一 内核源代码分析 第二章 异常 2.2.4 OMAP4的中断体系 图书试读版-请勿转载

2019-07-13 20:43发布

作者 crosskernel@gmail.com
2.2.4 OMAP4的中断体系   
  尽管已经宣布推出手机市场,但是作为移动处理器领域曾经的领袖, Ti在相当长的时间里总是抢先发布性能最强的新一代ARM处理器。而且早期还会搭配其强劲的DSP以配合ARM CORE工作。尽管Ti在3G时代遭受专利困境,但是凭借其强大的ARM处理器设计能力在没有Modem的情况下支撑了两代:Omap3是第一款Cortex A8产品,且加入了C64+DSP,当时的性能在业界无出其右。接着随着Neon和硬件编解码的兴起,Omap4里弱化了DSP作用,但依然领导业界进入双核时代。
也许因为OMAP5的功耗实在不能满足手机需求,也许无法集成Modem弱化了Ti的竞争力,也许Ti早已决心转身模拟,以后的手机处理器将不会有Ti的身影。Ti将Omap5的积累转化成其嵌入式产品keystoneII,但是嵌入式处理器的演进由于其市场需求的原因,将不会像手机处理器那样精彩。
本节介绍Omap4中断体系。


初始化:
void __init gic_init_irq(void)
{



//首先map出中断控制器Distributor寄存器空间
gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
BUG_ON(!gic_dist_base_addr);
//对Distributor的初始化
gic_dist_init(0, gic_dist_base_addr, 29);


/* Static mapping, never released */
//map出中断控制器cpu interface寄存器空间


gic_cpu_base_addr = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512);
BUG_ON(!gic_cpu_base_addr);
gic_cpu_init(0, gic_cpu_base_addr);


以上2次map,实际上在就是在页表中建立虚拟地址到物理地址的映射。这个动作只在主处理器初始化时进行,而在第二颗处理器初始化时并未进行map操作。其原因在于:


1 第二颗处理器初始化过程中上拷贝了主处理器的页表页目录
2 从每颗处理器往外看:
Distributor,系统中就一个,其物理地址位于: 
#define OMAP44XX_GIC_DIST_BASE 0x48241000
cpu interface,虽然每个处理器都有自己的空间,但是显然在omap4的实现中将其做成了相同的物理地址,
#define OMAP44XX_GIC_CPU_BASE 0x48240100 


}


void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
{   …
gic_data[gic_nr].cpu_base = base;


//初始化CPU 中断控制信息,这里没有显示的区分对哪颗CPU操作,但是由于上述的虚拟地址的拷贝关系,哪个处理器执行到这里,就对哪颗处理器操作。
writel(0xf0, base + GIC_CPU_PRIMASK);
writel(1, base + GIC_CPU_CTRL);
}


void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, unsigned int irq_start)
{


//这里最关键的是记下Distributor的虚拟地址
gic_data[gic_nr].dist_base = base;
}




第二颗CPU interface的初始化


void __cpuinit platform_secondary_init(unsigned int cpu)
{
trace_hardirqs_off();



//初始化该CPU 中断控制信息
gic_cpu_init(0, gic_cpu_base_addr);



spin_lock(&boot_lock);
spin_unlock(&boot_lock);
}


CPU间中断发射
static inline void smp_cross_call(const struct cpumask *mask)
{
gic_raise_softirq(mask, 1);
}


//mask记录了要向哪些处理器发射中断,irq记录要产生的中断号


#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
unsigned long map = *cpus_addr(*mask);


/* this always happens on GIC0 */
/*Distributor 的Software Generated Interrupt Register (ICDSGIR)用法如下: 
第16位 -–  第23位 :目标处理器
第0 位 -–   第4位 : 中断号
以下语句向mask标记的CPU发射irq号中断*/
writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
}
#endif