☆ 中断体系的建立
中断体系的建立对应的函数是在 arch/arm/mach-s5pv210/mach-x210.c 中结构体struct machine_desc
的元素 .init_irq = s5pv210_init_irq
开机如何被调用可以参考前面博客的 静态映射表的建立
而且中断体系用到了静态映射表的内容;查看struct map_desc结构体数组得出映射关系
虚拟地址 硬件地址 映射长度
VA_VIC(0) 0xF2000000 0x00004000
VA_VIC(1) 0xF2100000 0x00004000
VA_VIC(2) 0xF2200000 0x00004000
VA_VIC(3) 0xF2300000 0x00004000
VA_VIC(0) ==> S3C_VA_IRQ ==> S3C_ADDR(0x00000000) ==> S3C_ADDR_BASE ==> 0xF6000000
VA_VIC(1) ==> S3C_VA_IRQ + 0x10000
VA_VIC(2) ==> S3C_VA_IRQ + 0x20000
VA_VIC(3) ==> S3C_VA_IRQ + 0x30000
下面主要来分析s5pv210_init_irq如何建立中断体系的
☆ s5pv210_init_irq的分析:
s5pv210_init_irq 函数中定义了 u32 vic[4]; 然后通过vic[0/1/2/3] = ~0; 的方式把vic的四个元素的所有位全部置1;
首先vic[0] 是一个int型,有32位,分别代表了32个中断,vic数组4个元素就可以表示 4 X 32=128个中断号,
如果某一位为1说明有此中断号,如果某一位为0说明没有此中断号;x210这里vic数组的四个元素全为1,说明有128个连续的中断号
然后调用s5p_init_irq函数
↓
s5p_init_irq 函数中对vic数组的四个元素调用了 vic_init
传入的参数(虚拟地址,物理地址,数组元素,中断掩码),
vic_init调用四次,每次操作一组(32个)中断号
↓
vic_init 函数主要调用了vic_set_irq_sources(虚拟地址,物理地址,数组元素)
↓
vic_set_irq_sources 针对每一组(32个)中断号做以下处理
==> set_irq_chip(irq, &vic_chip);
vic_chip结构体定义了某些中断操作,irq_chip_set_defaults()函数定了剩余的操作为默认操作,这样每个中断号都有对应的设置操作函数
(操作时通过irq可以找到irq_desc结构体,irq_desc结构体中的chip就包含了操作函数)
==> set_irq_chip_data(irq, base);
把irq 和基地址对应起来了
(操作时通过irq可以找到irq_desc结构体,irq_desc结构体中的chip_data就是基地址)
==> set_irq_handler(irq, handle_level_irq);
看样子应该是设置 中断对应的中断函数
==> set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
设置某些标志位,暂不清楚作用
通过上面分析,发现有个关键点是 通过irq可以找到irq_desc结构体,也就是肯定在其他地方定义了irq_desc结构体数组,我们这里才可以这样找
查看代码获知:set_irq_handler(irq) 是从irq_desc数组查找irq 对应的irq_desc结构体
irq_desc数组被定义在kernel/irq/handle.c文件中
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = { //这个用法比较高级呀
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
};
这个结构体会被early_irq_init进行第一次初始化先,调用关系是 start_kernel-->early_irq_init()
第一次初始化先初始一些特定的东西
然后根据不同的板级函数进行第二次初始化,x210也就是s5pv210_init_irq,调用关系是 start_kernel-->init_IRQ()
第二次初始化设置和板级芯片有关的东西
这样内核启动之后start_kernel通过调用early_irq_init() + init_IRQ()就成功的搭建起来了中断体系~~~
我们真正调用的时候
request_irq(....) 像内核申请irq,内核有一套管理系统告诉你,申请是否成功
enable_irq(unsigned int irq)
desc = irq_to_desc(irq);
__enable_irq(desc, irq, false)
check_irq_resend(desc, irq);
desc->chip->enable(irq); 这里调用到了我们真正的设置函数
disable_irq(unsigned int irq)
desc = irq_to_desc(irq);
disable_irq_nosync(irq);
desc = irq_to_desc(irq);
__disable_irq(desc, irq, false);
desc->chip->disable(irq); 这里调用到了我们真正的设置函数
最终的调用其实会调用到上面分析的 set_irq_chip(irq, &vic_chip); 的vic_chip结构体,
这里面才是真正的操作硬件的函数,关键就是实现下面三个函数
.ack = vic_ack_irq,
.mask = vic_mask_irq,
.unmask = vic_unmask_irq,
里面肯定是通过irq 找到base地址 然后做真正的硬件操作~~~~
中断体系的建立对应的函数是在 arch/arm/mach-s5pv210/mach-x210.c 中结构体struct machine_desc
的元素 .init_irq = s5pv210_init_irq
开机如何被调用可以参考前面博客的 静态映射表的建立
而且中断体系用到了静态映射表的内容;查看struct map_desc结构体数组得出映射关系
虚拟地址 硬件地址 映射长度
VA_VIC(0) 0xF2000000 0x00004000
VA_VIC(1) 0xF2100000 0x00004000
VA_VIC(2) 0xF2200000 0x00004000
VA_VIC(3) 0xF2300000 0x00004000
VA_VIC(0) ==> S3C_VA_IRQ ==> S3C_ADDR(0x00000000) ==> S3C_ADDR_BASE ==> 0xF6000000
VA_VIC(1) ==> S3C_VA_IRQ + 0x10000
VA_VIC(2) ==> S3C_VA_IRQ + 0x20000
VA_VIC(3) ==> S3C_VA_IRQ + 0x30000
下面主要来分析s5pv210_init_irq如何建立中断体系的
☆ s5pv210_init_irq的分析:
s5pv210_init_irq 函数中定义了 u32 vic[4]; 然后通过vic[0/1/2/3] = ~0; 的方式把vic的四个元素的所有位全部置1;
首先vic[0] 是一个int型,有32位,分别代表了32个中断,vic数组4个元素就可以表示 4 X 32=128个中断号,
如果某一位为1说明有此中断号,如果某一位为0说明没有此中断号;x210这里vic数组的四个元素全为1,说明有128个连续的中断号
然后调用s5p_init_irq函数
↓
s5p_init_irq 函数中对vic数组的四个元素调用了 vic_init
传入的参数(虚拟地址,物理地址,数组元素,中断掩码),
vic_init调用四次,每次操作一组(32个)中断号
↓
vic_init 函数主要调用了vic_set_irq_sources(虚拟地址,物理地址,数组元素)
↓
vic_set_irq_sources 针对每一组(32个)中断号做以下处理
==> set_irq_chip(irq, &vic_chip);
vic_chip结构体定义了某些中断操作,irq_chip_set_defaults()函数定了剩余的操作为默认操作,这样每个中断号都有对应的设置操作函数
(操作时通过irq可以找到irq_desc结构体,irq_desc结构体中的chip就包含了操作函数)
==> set_irq_chip_data(irq, base);
把irq 和基地址对应起来了
(操作时通过irq可以找到irq_desc结构体,irq_desc结构体中的chip_data就是基地址)
==> set_irq_handler(irq, handle_level_irq);
看样子应该是设置 中断对应的中断函数
==> set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
设置某些标志位,暂不清楚作用
通过上面分析,发现有个关键点是 通过irq可以找到irq_desc结构体,也就是肯定在其他地方定义了irq_desc结构体数组,我们这里才可以这样找
查看代码获知:set_irq_handler(irq) 是从irq_desc数组查找irq 对应的irq_desc结构体
irq_desc数组被定义在kernel/irq/handle.c文件中
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = { //这个用法比较高级呀
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
};
这个结构体会被early_irq_init进行第一次初始化先,调用关系是 start_kernel-->early_irq_init()
第一次初始化先初始一些特定的东西
然后根据不同的板级函数进行第二次初始化,x210也就是s5pv210_init_irq,调用关系是 start_kernel-->init_IRQ()
第二次初始化设置和板级芯片有关的东西
这样内核启动之后start_kernel通过调用early_irq_init() + init_IRQ()就成功的搭建起来了中断体系~~~
我们真正调用的时候
request_irq(....) 像内核申请irq,内核有一套管理系统告诉你,申请是否成功
enable_irq(unsigned int irq)
desc = irq_to_desc(irq);
__enable_irq(desc, irq, false)
check_irq_resend(desc, irq);
desc->chip->enable(irq); 这里调用到了我们真正的设置函数
disable_irq(unsigned int irq)
desc = irq_to_desc(irq);
disable_irq_nosync(irq);
desc = irq_to_desc(irq);
__disable_irq(desc, irq, false);
desc->chip->disable(irq); 这里调用到了我们真正的设置函数
最终的调用其实会调用到上面分析的 set_irq_chip(irq, &vic_chip); 的vic_chip结构体,
这里面才是真正的操作硬件的函数,关键就是实现下面三个函数
.ack = vic_ack_irq,
.mask = vic_mask_irq,
.unmask = vic_unmask_irq,
里面肯定是通过irq 找到base地址 然后做真正的硬件操作~~~~