目录
2 ls2K1000 在 linux3.10 内核下的中断初始化过程
2.4.3 arch_init_irq()——平台中断初始化函数
2.4.4 mips_cpu_irq_init()——设置IP0~IP7的irq_chip和irq_desc->handler_irq
2.4.5 setup_irq_default()——设置64个I/O中断的irq_chip和irq_desc->handle_irq
2.6.1 每个中断的irq_desc和irq_chip的设置
3 ls2k1000在linux3.10内核下的中断的处理过程
1 基本知识
1.1 ls2k1000的中断组成
龙芯 2K1000 处理器片内集成 2 个 GS264 处理器核。
GS264处理器核支持32种异常,其中0号异常用来处理中断。而GS264有8个中断(IP0~IP7)。
ls2k1000的中断控制器支持64个I/O中断,这64个I/O中断对应64个中断路由寄存器,可以单独控制每个外部中断路由到GS264的IP2~IP5。
龙芯 2K1000 的 PCIE 控制器支持 MSI 中断类型。分 配 给 MSI 的 地 址 有 两 个 , 分 别 对 应 寄 存 器INT_MSI_ADDR_0 (0x1fe114b0)和 INT_MSI_ADDR_1(0x1fe114f0),每个地址可以接受 32 个中断消息,分别与现有的中断引脚低 32 位和高 32 位复用(通过变量ls_msi_irq_mask决定复用功能,ls_msi_irq_mask的值在dts文件里设置,请看2.5.2小节)。
GS264的0号异常 | GS264的 IP7 | |
GS264的 IP6 | ||
GS264的 IP2~IP5 | LS2K1000的64个I/O中断 | |
GS264的 IP0~IP1 |
1.2 GS264中断相关的寄存器
EBase 寄存器 (CP0 Register 15, Select 1):例外入口地址
Cause.IP:待处理软件中断标识
Status.IM:中断屏蔽位
Cause.ExcCode:例外编码
2 ls2K1000 在 linux3.10 内核下的中断初始化过程
2.1 大致过程
start_kernel(); //init/main.c
-> trap_init(); //arch/mips/kernel/traps.c
-> set_handler(); //arch/mips/kernel/traps.c
-> set_except_vector(); //arch/mips/kernel/traps.c
-> early_irq_init(); //kernel/irq/irqdesc.c
-> init_IRQ(); //arch/mips/kernel/irq.c
-> arch_init_irq(); //arch/mips/loongson2/irq.c
-> mips_cpu_irq_init(); //arch/mips/kernel/irq_cpu.c
-> irq_set_chip_and_handler(); //include/linux/irq.h
-> setup_irq_default(); //arch/mips/loongson2/irq.c
-> irq_set_chip_and_handler(); //include/linux/irq.h
-> setup_irq_mode(); //arch/mips/loongson2/irq.c
2.2 函数具体分析:trap_init();
2.2.1 函数说明
体系相关,将异常向量处理函数except_vec3_generic加载到地址BASE+0x180处,并为exception_handles[]中的32种异常设置处理函数。
其中,0号异常是所有中断的入口。在trap_init()函数中,将0号异常的处理函数设置为handle_init()函数,这是一个汇编函数。handle_init()函数的代码请看3.1小节。
2.2.2 trap_init()函数关键代码
//arch/mips/kernel/traps.c
void __init trap_init(void)
{
......
set_except_vector(0, using_rollback_handler() ? rollback_handle_int
: handle_int);
set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
......
}
2.3 函数具体分析:early_irq_init();
2.3.1 函数说明
体系平台无关,主要用来设置每个中断默认的irq_desc。
2.3.2 early_irq_init()函数的代码
//kernel/irq/irqdesc.c
int __init early_irq_init(void)
{
int count, i, node = first_online_node;
struct irq_desc *desc;
init_irq_default_affinity();
printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS);
desc = irq_desc;
count = ARRAY_SIZE(irq_desc);
for (i = 0; i < count; i++) {
desc[i].kstat_irqs = alloc_percpu(unsigned int);
alloc_masks(&desc[i], GFP_KERNEL, node);
raw_spin_lock_init(&desc[i].lock);
lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
desc_set_defaults(i, &desc[i], node, NULL);
}
return arch_early_irq_init();
}
2.4
函数具体分析:init_IRQ();
2.4.1 函数说明
init_IRQ()函数的主要功能是调用平台相关的中断初始化函数:arch_init_irq();
2.4.2 init_IRQ()
函数的代码
//arch/mips/kernel/irq.c
void __init init_IRQ(void)
{
int i;
#ifdef CONFIG_KGDB
if (kgdb_early_setup)
return;
#endif
for (i = 0; i < NR_IRQS; i++)
irq_set_noprobe(i);
arch_init_irq(); //
#ifdef CONFIG_KGDB
if (!kgdb_early_setup)
kgdb_early_setup = 1;
#endif
}
2.4.3 arch_init_irq()——平台中断初始化函数
//arch/mips/loongson2/irq.c
void __init arch_init_irq(void)
{
mips_cpu_irq_init();
set_c0_status(STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6); //使能GS264的4、5和6号中断。
setup_irq_default();
setup_irq_mode();
}
2.4.4 mips_cpu_irq_init()——设置IP0~IP7的irq_chip和irq_desc->handler_irq
GS264处理器核的IP0~IP7中断的处理函数(irq_desc->handler_irq)都是handle_percpu_irq();
//arch/mips/kernel/irq_cpu.c
void __init mips_cpu_irq_init(void)
{
int irq_base = MIPS_CPU_IRQ_BASE;
int i;
/* Mask interrupts. */
clear_c0_status(ST0_IM);
clear_c0_cause(CAUSEF_IP);
/* Software interrupts are used for MT/CMT IPI */
for (i = irq_base; i < irq_base + 2; i++)
irq_set_chip_and_handler(i, cpu_has_mipsmt ?
&mips_mt_cpu_irq_controller :
&mips_cpu_irq_controller,
handle_percpu_irq);
for (i = irq_base + 2; i < irq_base + 8; i++)
irq_set_chip_and_handler(i, &mips_cpu_irq_controller,
handle_percpu_irq);
}
2.4.5 setup_irq_default()——设置64个I/O中断的irq_chip和irq_desc->handle_irq
ls2k1000的64个I/O中断的处理函数(irq_desc->handler_irq)都是handle_level_irq();
//arch/mips/loongson2/irq.c
void __init setup_irq_default(void)
{
unsigned int i;
int core_id = (read_c0_ebase() & 0x3ff);
for (i = LS2K_IRQ_BASE; i < LS2K_IRQ_BASE + 64; i++) {
irq_set_chip_and_handler(i, &ls64_irq_chip, handle_level_irq);
set_irq_attr(i, 1 << (STATUSB_IP4 - 10), 1 << core_id, 0); //set_irq_attr ()函数设置中断路由到core_id决定的处理器的IP4,同时设置路由模式。
}
ls64_conf_write32(ls_msi_irq_mask, (void *)(CKSEG1ADDR(CONF_BASE) + INT_LO_OFF + INT_EDG_OFF ));
ls64_conf_write32((ls_msi_irq_mask >> 32)|(0x1f << 12), (void *)(CKSEG1ADDR(CONF_BASE) + INT_LO_OFF + INT_EDG_OFF + 0x40));
}
2.5 PCIE MSI中断的初始化设置
2.5.1 说明
龙芯 2K1000 的 PCIE 控制器支持 MSI 中断类型。分 配 给 MSI 的 地 址 有 两 个 , 分 别 对 应 寄 存 器INT_MSI_ADDR_0 (0x1fe114b0)和 INT_MSI_ADDR_1(0x1fe114f0),每个地址可以接受 32 个中断消息,分别与现有的中断引脚低 32 位和高 32 位复用。
2.5.2 MSI初始化代码
从dts文件里获取ls_msi_irq_mask的值,并设置MSI中断路由到GS264处理器核的IP5。
//arch/mips/loongson2/pci_msi.c
static int ls_pci_msi_probe(struct platform_device *dev)
{
......
mask_p = (__be32 *)of_get_property(np, "msi-mask", NULL);
if (mask_p == NULL){
pr_info("No msi-mask property !\n");
return -ENXIO;
}else{
ls_msi_irq_mask = of_read_number(mask_p,2);
}
......
for (i = LS64_MSI_IRQ_BASE ; i < LS64_MSI_IRQ_BASE + 64; i++) {
if((1UL << (i - LS64_MSI_IRQ_BASE)) & ls_msi_irq_mask){
set_irq_attr(i, 1 << (STATUSB_IP5 - 10), 1 << core_id, 0);
}
}
......
}
2.6 初始化过程总结
2.6.1 每个中断的irq_desc和irq_chip的设置
每个中断的初始irq_desc变量在kernel/irq/irqdesc.c 文件的early_irq_init()函数里设置,
GS264处理器核的8个中断(IP0~IP7)最后在arch/mips/kernel/irq_cpu.c 文件的mips_cpu_irq_init()函数里通过函数irq_set_chip_and_handler()来设置最终的irq_chip和irq_desc->handle_irq。8个中断(IP0~IP7)设置的irq_desc->handle_irq都是handle_percpu_irq();
ls2k1000的64个I/O中断最后在arch/mips/loongson2/irq.c文件的setup_irq_default()函数里通过函数irq_set_chip_and_handler()来设置最终的irq_chip和irq_desc->handle_irq。64个I/O中断设置的irq_desc->handle_irq都是handle_level_irq();
2.6.2 ls2k1000的64个I/O中断的路由设置
ls2k1000的64个I/O中断和64个MSI中断复用中断线。
当作为I/O中断时,被路由到GS264处理器核的IP4。设置过程如下:
start_kernel(); //init/main.c
-> init_IRQ(); //arch/mips/kernel/irq.c
-> arch_init_irq(); //arch/mips/loongson2/irq.c
-> setup_irq_default(); //arch/mips/loongson2/irq.c
-> set_irq_attr(); //arch/mips/loongson2/irq.c
当作为MSI中断时,被路由到GS264处理器核的IP5。设置过程如下:
ls_pci_msi_probe(); //arch/mips/loongson2/pci_msi.c
-> set_irq_attr();
3 ls2k1000在linux3.10内核下的中断的处理过程
3.1 主要流程
handle_int(); //arch/mips/kernel/genex.S
-> plat_irq_dispatch(); //arch/mips/loongson2/irq.c
-> ip7_dispatch(); //arch/mips/loongson2/irq.c 计时器中断和性能计数器中断
-> do_IRQ(); //arch/mips/kernel/irq.c
-> ip6_dispatch(); //arch/mips/loongson2/irq.c 处理IPI中断
-> ls64_ipi_interrupt(); //arch/mips/loongson2/smp.c
-> ip5_dispatch(); //arch/mips/loongson2/irq.c; 处理MSI中断
-> do_IRQ; //arch/mips/kernel/irq.c
-> ip4_dispatch(); //arch/mips/loongson2/irq.c 处理I/O中断
-> do_IRQ; //arch/mips/kernel/irq.c
参考资料
LoongsonGS264_user(2018年7月,http://www.loongson.cn/product/dc/)
Loongson2K1000_user(2020年4月,http://www.loongson.cn/product/dc/)