在setup_arch函数的末尾,调用了一个函数进行中断处理函数的配置:
init_exception_vectors();
这个函数的实现在arch/blackfin/mach-common/ints-priority.c中:
void __init init_exception_vectors(void)
{
SSYNC();
/* cannot program in software:
* evt0 - emulation (jtag)
* evt1 - reset
*/
bfin_write_EVT2(evt_nmi);
bfin_write_EVT3(trap);
bfin_write_EVT5(evt_ivhw);
bfin_write_EVT6(evt_timer);
bfin_write_EVT7(evt_evt7);
bfin_write_EVT8(evt_evt8);
bfin_write_EVT9(evt_evt9);
bfin_write_EVT10(evt_evt10);
bfin_write_EVT11(evt_evt11);
bfin_write_EVT12(evt_evt12);
bfin_write_EVT13(evt_evt13);
bfin_write_EVT14(evt14_softirq);
bfin_write_EVT15(evt_system_call);
CSYNC();
}
从这里可以看出各个中断的中断入口,共13个,其余3个未设置。如下所示:
EVT0:Emulation,Highest priority. Vector address is provided by JTAG.
EVT1:Reset,Read-only.
EVT4:Reserved,Reserved vector.
在内核初始化的时候,会调用一个叫program_IAR的函数:
void program_IAR(void)
{
/* Program the IAR0 Register with the configured priority */
bfin_write_SICA_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
((CONFIG_IRQ_DMA1_ERROR - 7) << IRQ_DMA1_ERROR_POS) |
((CONFIG_IRQ_DMA2_ERROR - 7) << IRQ_DMA2_ERROR_POS) |
((CONFIG_IRQ_IMDMA_ERROR - 7) << IRQ_IMDMA_ERROR_POS) |
((CONFIG_IRQ_PPI0_ERROR - 7) << IRQ_PPI0_ERROR_POS) |
((CONFIG_IRQ_PPI1_ERROR - 7) << IRQ_PPI1_ERROR_POS) |
((CONFIG_IRQ_SPORT0_ERROR - 7) << IRQ_SPORT0_ERROR_POS) |
((CONFIG_IRQ_SPORT1_ERROR - 7) << IRQ_SPORT1_ERROR_POS));
bfin_write_SICA_IAR1(((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS) |
((CONFIG_IRQ_UART_ERROR - 7) << IRQ_UART_ERROR_POS) |
((CONFIG_IRQ_RESERVED_ERROR - 7) << IRQ_RESERVED_ERROR_POS) |
((CONFIG_IRQ_DMA1_0 - 7) << IRQ_DMA1_0_POS) |
((CONFIG_IRQ_DMA1_1 - 7) << IRQ_DMA1_1_POS) |
((CONFIG_IRQ_DMA1_2 - 7) << IRQ_DMA1_2_POS) |
((CONFIG_IRQ_DMA1_3 - 7) << IRQ_DMA1_3_POS) |
((CONFIG_IRQ_DMA1_4 - 7) << IRQ_DMA1_4_POS));
bfin_write_SICA_IAR2(((CONFIG_IRQ_DMA1_5 - 7) << IRQ_DMA1_5_POS) |
((CONFIG_IRQ_DMA1_6 - 7) << IRQ_DMA1_6_POS) |
((CONFIG_IRQ_DMA1_7 - 7) << IRQ_DMA1_7_POS) |
((CONFIG_IRQ_DMA1_8 - 7) << IRQ_DMA1_8_POS) |
((CONFIG_IRQ_DMA1_9 - 7) << IRQ_DMA1_9_POS) |
((CONFIG_IRQ_DMA1_10 - 7) << IRQ_DMA1_10_POS) |
((CONFIG_IRQ_DMA1_11 - 7) << IRQ_DMA1_11_POS) |
((CONFIG_IRQ_DMA2_0 - 7) << IRQ_DMA2_0_POS));
bfin_write_SICA_IAR3(((CONFIG_IRQ_DMA2_1 - 7) << IRQ_DMA2_1_POS) |
((CONFIG_IRQ_DMA2_2 - 7) << IRQ_DMA2_2_POS) |
((CONFIG_IRQ_DMA2_3 - 7) << IRQ_DMA2_3_POS) |
((CONFIG_IRQ_DMA2_4 - 7) << IRQ_DMA2_4_POS) |
((CONFIG_IRQ_DMA2_5 - 7) << IRQ_DMA2_5_POS) |
((CONFIG_IRQ_DMA2_6 - 7) << IRQ_DMA2_6_POS) |
((CONFIG_IRQ_DMA2_7 - 7) << IRQ_DMA2_7_POS) |
((CONFIG_IRQ_DMA2_8 - 7) << IRQ_DMA2_8_POS));
bfin_write_SICA_IAR4(((CONFIG_IRQ_DMA2_9 - 7) << IRQ_DMA2_9_POS) |
((CONFIG_IRQ_DMA2_10 - 7) << IRQ_DMA2_10_POS) |
((CONFIG_IRQ_DMA2_11 - 7) << IRQ_DMA2_11_POS) |
((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) |
((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) |
((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) |
((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) |
((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS));
bfin_write_SICA_IAR5(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) |
((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) |
((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) |
((CONFIG_IRQ_TIMER8 - 7) << IRQ_TIMER8_POS) |
((CONFIG_IRQ_TIMER9 - 7) << IRQ_TIMER9_POS) |
((CONFIG_IRQ_TIMER10 - 7) << IRQ_TIMER10_POS) |
((CONFIG_IRQ_TIMER11 - 7) << IRQ_TIMER11_POS) |
((CONFIG_IRQ_PROG0_INTA - 7) << IRQ_PROG0_INTA_POS));
bfin_write_SICA_IAR6(((CONFIG_IRQ_PROG0_INTB - 7) << IRQ_PROG0_INTB_POS) |
((CONFIG_IRQ_PROG1_INTA - 7) << IRQ_PROG1_INTA_POS) |
((CONFIG_IRQ_PROG1_INTB - 7) << IRQ_PROG1_INTB_POS) |
((CONFIG_IRQ_PROG2_INTA - 7) << IRQ_PROG2_INTA_POS) |
((CONFIG_IRQ_PROG2_INTB - 7) << IRQ_PROG2_INTB_POS) |
((CONFIG_IRQ_DMA1_WRRD0 - 7) << IRQ_DMA1_WRRD0_POS) |
((CONFIG_IRQ_DMA1_WRRD1 - 7) << IRQ_DMA1_WRRD1_POS) |
((CONFIG_IRQ_DMA2_WRRD0 - 7) << IRQ_DMA2_WRRD0_POS));
bfin_write_SICA_IAR7(((CONFIG_IRQ_DMA2_WRRD1 - 7) << IRQ_DMA2_WRRD1_POS) |
((CONFIG_IRQ_IMDMA_WRRD0 - 7) << IRQ_IMDMA_WRRD0_POS) |
((CONFIG_IRQ_IMDMA_WRRD1 - 7) << IRQ_IMDMA_WRRD1_POS) |
((CONFIG_IRQ_WDTIMER - 7) << IRQ_WDTIMER_POS) |
(0 << IRQ_RESERVED_1_POS) | (0 << IRQ_RESERVED_2_POS) |
(0 << IRQ_SUPPLE_0_POS) | (0 << IRQ_SUPPLE_1_POS));
SSYNC();
}
通过对IAR的编程,可以控制64个外部中断的优先级,在此内核使用了60个宏定义来描述它们的优先级(因为60-63这4个外部中断是系统保留的)。在默认情况下,内核是这样配置其优先级的:
#define CONFIG_IRQ_SPI_ERROR 7
#define CONFIG_IRQ_DMA1_ERROR 7
#define CONFIG_IRQ_DMA2_ERROR 7
#define CONFIG_IRQ_PPI0_ERROR 7
#define CONFIG_IRQ_PPI1_ERROR 7
#define CONFIG_IRQ_UART_ERROR 7
#define CONFIG_IRQ_RESERVED_ERROR 7
#define CONFIG_IRQ_IMDMA_ERROR 7
#define CONFIG_IRQ_SPORT0_ERROR 7
#define CONFIG_IRQ_SPORT1_ERROR 7
#define CONFIG_IRQ_PLL_WAKEUP 7
#define CONFIG_IRQ_DMA1_WRRD0 8
#define CONFIG_IRQ_DMA1_WRRD1 8
#define CONFIG_IRQ_DMA1_0 8
#define CONFIG_IRQ_DMA1_1 8
#define CONFIG_IRQ_DMA1_2 8
#define CONFIG_IRQ_DMA1_3 8
#define CONFIG_IRQ_DMA1_4 8
#define CONFIG_IRQ_DMA1_5 8
#define CONFIG_IRQ_DMA1_6 8
#define CONFIG_IRQ_DMA1_7 8
#define CONFIG_IRQ_DMA1_8 8
#define CONFIG_IRQ_DMA1_9 8
#define CONFIG_IRQ_DMA1_10 8
#define CONFIG_IRQ_DMA1_11 8
#define CONFIG_IRQ_DMA2_WRRD0 9
#define CONFIG_IRQ_DMA2_WRRD1 9
#define CONFIG_IRQ_DMA2_0 9
#define CONFIG_IRQ_DMA2_1 9
#define CONFIG_IRQ_DMA2_2 9
#define CONFIG_IRQ_DMA2_3 9
#define CONFIG_IRQ_DMA2_4 9
#define CONFIG_IRQ_DMA2_5 9
#define CONFIG_IRQ_DMA2_6 9
#define CONFIG_IRQ_DMA2_7 9
#define CONFIG_IRQ_DMA2_8 9
#define CONFIG_IRQ_DMA2_9 9
#define CONFIG_IRQ_DMA2_10 9
#define CONFIG_IRQ_DMA2_11 9
#define CONFIG_IRQ_TIMER0 10
#define CONFIG_IRQ_TIMER1 10
#define CONFIG_IRQ_TIMER2 10
#define CONFIG_IRQ_TIMER3 10
#define CONFIG_IRQ_TIMER4 10
#define CONFIG_IRQ_TIMER5 10
#define CONFIG_IRQ_TIMER6 10
#define CONFIG_IRQ_TIMER7 10
#define CONFIG_IRQ_TIMER8 10
#define CONFIG_IRQ_TIMER9 10
#define CONFIG_IRQ_TIMER10 10
#define CONFIG_IRQ_TIMER11 10
#define CONFIG_IRQ_PROG0_INTA 11
#define CONFIG_IRQ_PROG1_INTA 11
#define CONFIG_IRQ_PROG2_INTA 11
#define CONFIG_IRQ_PROG0_INTB 11
#define CONFIG_IRQ_PROG1_INTB 11
#define CONFIG_IRQ_PROG2_INTB 11
#define CONFIG_IRQ_IMDMA_WRRD0 12
#define CONFIG_IRQ_IMDMA_WRRD1 12
#define CONFIG_IRQ_WDTIMER 13
在此只定义了7-13,因为中断14留做软件中断,而中断15则留做系统功能调用。
在start_kernel函数中,调用了
init_IRQ();
进行中断相关结构体的初始化,这个函数在arch/blackfin/kernel/irqchip.c中:
void __init init_IRQ(void)
{
struct irq_desc *desc;
int irq;
spin_lock_init(&irq_controller_lock);
for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
*desc = bad_irq_desc;
}
init_arch_irq();
}
在此函数中对irq_desc这一全局数组赋了一个初值bad_irq_desc,这是一个全局变量:
static struct irq_chip bad_chip = {
.ack = dummy_mask_unmask_irq,
.mask = dummy_mask_unmask_irq,
.unmask = dummy_mask_unmask_irq,
};
static struct irq_desc bad_irq_desc = {
.chip = &bad_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
};
最后调用init_arch_irq进行下一步的设置。
此函数位于arch/blackfin/mach-common/int-priority.c:
/*
* This function should be called during kernel startup to initialize
* the BFin IRQ handling routines.
*/
int __init init_arch_irq(void)
{
int irq;
unsigned long ilat = 0;
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
SSYNC();
local_irq_disable();
init_exception_buff();
for (irq = 0; irq <= SYS_IRQS; irq++) {
if (irq <= IRQ_CORETMR)
set_irq_chip(irq, &bfin_core_irqchip);
else
set_irq_chip(irq, &bfin_internal_irqchip);
switch (irq) {
case IRQ_PROG0_INTA:
set_irq_chained_handler(irq,
bfin_demux_gpio_irq);
break;
case IRQ_PROG1_INTA:
set_irq_chained_handler(irq,
bfin_demux_gpio_irq);
break;
case IRQ_PROG2_INTA:
set_irq_chained_handler(irq,
bfin_demux_gpio_irq);
break;
default:
set_irq_handler(irq, handle_simple_irq);
break;
}
}
for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++) {
set_irq_chip(irq, &bfin_gpio_irqchip);
/* if configured as edge, then will be changed to do_edge_IRQ */
set_irq_handler(irq, handle_level_irq);
}
bfin_write_IMASK(0);
CSYNC();
ilat = bfin_read_ILAT();
CSYNC();
bfin_write_ILAT(ilat);
CSYNC();
printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts/n");
/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
* local_irq_enable()
*/
program_IAR();
/* Therefore it's better to setup IARs before interrupts enabled */
search_IAR();
/* Enable interrupts IVG7-15 */
irq_flags = irq_flags | IMASK_IVG15 |
IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
return 0;
}
这个函数完成了中断的基本配置。
1.2.5 CoreTimer的初始化
在bf561内核中,coretimer的初始化在普通中断初始化完成后进行,同样在start_kernel函数中,调用
time_init();
进行CoreTimer的初始化工作,此函数位于arch/blackfin/kernel/time.c:
void __init time_init(void)
{
time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */
/* Initialize xtime. From now on, xtime is updated with timer interrupts */
xtime.tv_sec = secs_since_1970;
xtime.tv_nsec = 0;
wall_to_monotonic.tv_sec = -xtime.tv_sec;
time_sched_init(timer_interrupt);
}
函数最后调用了time_sched_init(timer_interrupt);进行初始化工作,其中timer_interrupt是一个函数,用于对CoreTimer的中断进行处理。
/*
* The way that the Blackfin core timer works is:
* - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
* - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
*
* If you take the fastest clock (1ns, or 1GHz to make the math work easier)
* 10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
* (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
* to use TSCALE, and program it to zero (which is pass CCLK through).
* If you feel like using it, try to keep HZ * TIMESCALE to some
* value that divides easy (like power of 2).
*/
#define TIME_SCALE 1
static void
time_sched_init(irqreturn_t(*timer_routine) (int, void *))
{
u32 tcount;
/* power up the timer, but don't enable it just yet */
bfin_write_TCNTL(1);
CSYNC();
/*
* the TSCALE prescaler counter.
*/
bfin_write_TSCALE((TIME_SCALE - 1));
tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
bfin_write_TPERIOD(tcount);
bfin_write_TCOUNT(tcount);
/* now enable the timer */
CSYNC();
bfin_write_TCNTL(7);
bfin_timer_irq.handler = (irq_handler_t)timer_routine;
/* call setup_irq instead of request_irq because request_irq calls
* kmalloc which has not been initialized yet
*/
setup_irq(IRQ_CORETMR, &bfin_timer_irq);
}
从这个函数对TPERIOD的设置可以看出,CoreTimer将在HZ分之一秒的时间内中断一次,对于默认配置,HZ的值为250,也就是说CoreTimer每隔4毫秒将产生一个中断。
在这个函数中,同时修改了CoreTimer相应的irq_desc中的action成员。且此action成员的handle将指向timer_interrupt函数。