现在的位置: 首页 > 综合 > 正文

重读uclinux-2008r1-rc8(bf561)内核的中断处理(2):中断配置

2013年09月20日 ⁄ 综合 ⁄ 共 11112字 ⁄ 字号 评论关闭
 

在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;
}
这个函数完成了中断的基本配置。
在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函数。
 

抱歉!评论已关闭.