三读内核中断处理(2):中断配置

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

ADSP-BF561

优视BF561EVB开发板

uclinux-2008r1.5-rc3(smp patch)

Visual DSP++ 5.0(update 5)

欢迎转载,但请保留作者信息

1.1 中断入口设置

setup_arch函数的末尾,调用了一个函数进行中断处理函数的配置:

init_exception_vectors();

B核启动时,其调用的第一个函数也是它:

void __cpuinit secondary_start_kernel(void)

{

unsigned int cpu = smp_processor_id();

struct mm_struct *mm = &init_mm;

/*

* We want the D-cache to be enabled early, in case the atomic

* support code emulates cache coherence (see

* __ARCH_SYNC_CORE_DCACHE).

*/

init_exception_vectors();

……………………….

}

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个未设置。如下所示:

EVT0EmulationHighest priority. Vector address is provided by JTAG.

EVT1ResetRead-only.

EVT4ReservedReserved vector.

561内部,每个核都有自己的中断向量表,但是在硬件上可以保证只要往同一个地址写入就可以达到目的,因此在这里ab核可以共用这样一段代码。

Note: Each core has its own separate Event Vector Table MMRs (EVT15–EVT0) but the MMR memory locations are aliased such that each core always accesses only its own set of these registers.

1.2 优先级设置

在内核初始化的时候,会调用一个叫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-634个外部中断是系统保留的)。在默认情况下,内核是这样配置其优先级的:

#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则留做系统功能调用。

1.3 初始化过程

A核执行的start_kernel函数中,调用了

init_IRQ();

进行中断相关结构体的初始化,而B核则不需要这个过程。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,

};

实际上handle_bad_irq总不被执行,因此略过它。此函数的最后调用init_arch_irq进行下一步的设置。

1.4 init_arch_irq

此函数位于arch/blackfin/mach-common/int-priority-dc.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_SICA_IMASK0(SIC_UNMASK_ALL);

bfin_write_SICA_IMASK1(SIC_UNMASK_ALL);

#ifdef CONFIG_SMP

bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);

bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);

#endif

SSYNC();

local_irq_disable();

for (irq = 0; irq < SYS_IRQS; irq++) {

if (irq <= IRQ_CORETMR)

set_irq_chip(irq, &bf561_core_irqchip);

else

set_irq_chip(irq, &bf561_internal_irqchip);

#ifdef CONFIG_IRQCHIP_DEMUX_GPIO

if ((irq == IRQ_PROG0_INTA) ||

(irq == IRQ_PROG1_INTA) || (irq == IRQ_PROG2_INTA))

set_irq_chained_handler(irq, bf561_demux_gpio_irq);

else

#endif

#ifdef CONFIG_TICK_SOURCE_SYSTMR0

if (irq == IRQ_TIMER0)

set_irq_handler(irq, handle_percpu_irq);

else

#endif

set_irq_handler(irq, handle_simple_irq);

}

#ifdef CONFIG_IRQCHIP_DEMUX_GPIO

for (irq = IRQ_PF0; irq <= IRQ_PF47; irq++) {

set_irq_chip(irq, &bf561_gpio_irqchip);

/* if configured as edge, then will be changed to do_edge_IRQ */

set_irq_handler(irq, handle_level_irq);

}

#endif

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_SICA_IWR0(IWR_ENABLE_ALL);

bfin_write_SICA_IWR1(IWR_ENABLE_ALL);

return 0;

}

这个函数完成了中断的基本配置。

你可能感兴趣的:(编程,cache,Blog)