linux 2.6.28之关于dm9000网卡中断号与中断引脚(s3c6410)
转载博客原文:
http://blog.chinaunix.net/uid-26009923-id-3918956.html
有一个问题:
在datasheet中清楚的说明s3c6410一共有64个中断,
但是dm9000的驱动中request_irq()的中断号却是108.
如下图所示: cat /proc/interrupts
为什么申请出来的中断号是108呢? ?
从中断引脚的定义可以看出:
-
#define IRQ_EINT(x) S3C_EINT(x)
-
#define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE)
-
#define S3C_IRQ_EINT_BASE S3C_IRQ(64+5)
-
#define S3C_IRQ(x) ((x) + S3C_IRQ_OFFSET)
-
#define S3C_IRQ_OFFSET (32)
EINT(7) = 7+EINT_BASE
EINT_BASE=64+5+32=101
7+64+5+32=108,里面各个数值都是什么意思呢?
要弄明白这个需要详细的了解一下arm中断的各个流程.
1. 系统中断的初始化.
2. 中断产生并进入中断处理函数
/////////////////////////////////////////////////////////////////////////
#define DM9000_ETH_IRQ_EINT0 IRQ_EINT(7)
static struct resource dm9000_resources_cs1[] = {
[0] = {
.start = S3C64XX_VA_DM9000,
.end = S3C64XX_VA_DM9000 + S3C64XX_SZ_DM9000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_EINT(7),
.end = IRQ_EINT(7),
.flags = IORESOURCE_IRQ,
},
};
///////////////
//////////
//////////////////////////////////////////////////////////////////////////
一. 中断初始化
从start_kernel开始看起,下面有四个函数跟中断初始化有关系
-
asmlinkage void __init start_kernel(void)
-
{
-
setup_arch(); --> early_trap_init(); //1.中断向量表与中断函数的copy
-
trap_init(); //空函数,不管它
-
early_irq_init(); //2.初始化irq_desc数组
-
init_IRQ(); //3.s3c6410内部64个中断的初始化
-
rest_init(); //4. do_initcalls() --> s3c64xx_init_irq_eint();外部中断的初始化
-
}
1. 中断向量与中断函数的拷贝
在arch/arm/kernel/traps.c中
-
void __init early_trap_init(void)
-
{
-
//这儿定义了CONFIG_CPU_USE_DOMAINS
-
unsigned long vectors = CONFIG_VECTORS_BASE; //BASE=0xffff0000
-
extern char __stubs_start[], __stubs_end[];
-
extern char __vectors_start[], __vectors_end[];
-
extern char __kuser_helper_start[], __kuser_helper_end[];
-
int kuser_sz = __kuser_helper_end - __kuser_helper_start;
-
//copy中断向量表到0xffff000
-
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
-
//copy中量函数到0xffff000+0x200
-
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
-
//copy中断向量表到0xffff000
-
memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
-
-
kuser_get_tls_init(vectors);
-
-
memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
-
sigreturn_codes, sizeof(sigreturn_codes));
-
memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
-
syscall_restart_code, sizeof(syscall_restart_code));
-
-
flush_icache_range(vectors, vectors + PAGE_SIZE);
-
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
-
}
2.初始化irq_desc结构体数组
在kernel/irq/irqdesc.c中,其中NR_IRQS=246
start_kernel
--> early_irq_init
-
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
-
[0 ... NR_IRQS-1] = {
-
.handle_irq = handle_bad_irq,
-
.depth = 1,
-
.lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
-
}
-
};
-
int __init early_irq_init(void)
-
{
-
int count, i, node = first_online_node;
-
struct irq_desc *desc;
-
init_irq_default_affinity();
-
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);
-
}
-
return arch_early_irq_init();
-
}
#define ARCH_IRQ_INIT_FLAGS (IRQ_NOREQUEST | IRQ_NOPROBE)
start_kernel
--> early_irq_init
--> desc_set_defaults
-
static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
-
{
-
int cpu;
-
desc->irq_data.irq = irq;
-
desc->irq_data.chip = &no_irq_chip;
-
desc->irq_data.chip_data = NULL;
-
desc->irq_data.handler_data = NULL;
-
desc->irq_data.msi_desc = NULL;
-
irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); //初始化为IRQ_NOREQUEST | IRQ_NOPROBE
-
irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
-
desc->handle_irq = handle_bad_irq;
-
desc->depth = 1;
-
desc->irq_count = 0;
-
desc->irqs_unhandled = 0;
-
desc->name = NULL;
-
for_each_possible_cpu(cpu)
-
*per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
-
desc_smp_init(desc, node);
-
}
3. s3c6410内部64 个中断初始化
-
在arch/arm/kernel/iqr.c中
-
void __init init_IRQ(void)
-
{
-
machine_desc->init_irq();
-
}
-
-
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
-
MACHINE_START(SMDK6410, "SMDK6410")
-
.boot_params = S3C64XX_PA_SDRAM + 0x100,
-
.init_irq = s3c6410_init_irq,
-
.map_io = smdk6410_map_io,
-
.init_machine = smdk6410_machine_init,
-
.timer = &s3c24xx_timer,
-
MACHINE_END
-
-
在arch/arm/mach-s3c64xx/s3c6410.c中
-
void __init s3c6410_init_irq(void)
-
{
-
/* VIC0 is missing IRQ7, VIC1 is fully populated. */
-
s3c64xx_init_irq(~0 & ~(1 << 7), ~0);
-
}
-
-
//VIC0中的第7号中断是保留的,
-
-
在arch/arm/mach-s3c64xx/iqr.c中
-
void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
-
{
-
/* initialise the pair of VICs */
-
vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, 0);
-
vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0);
-
-
/* add the timer sub-irqs */
-
s3c_init_vic_timer_irq(5, IRQ_TIMER0);
-
-
s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
-
}
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[55]: vic0_valid=0xffffff7f, vic1_valid=0xffffffff
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[56]: VA_VIC0=0xf6000000, IRQ_VIC0_BASE=0x20
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[57]: VA_VIC1=0xf6010000, IRQ_VIC1_BASE=0x40
#define VA_VIC0 (S3C_VA_IRQ + 0x00)
#define S3C_VA_IRQ S3C_ADDR(0x00000000) /* irq controller(s) */
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#define S3C_ADDR_BASE 0xF6000000
-
void __init vic_init(void __iomem *base, unsigned int irq_start,
-
u32 vic_sources, u32 resume_sources)
-
{
-
//读取vid,没有找到0xfe0这个是代表什么,不知道也没有多大影响
-
for (i = 0; i < 4; i++) {
-
u32 addr = ((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
-
cellid |= (readl(addr) & 0xff) << (8 * i);
-
}
-
//VIC @f6000000: id 0x00041192, vendor 0x41
-
vendor = (cellid >> 12) & 0xff;
-
switch(vendor) {
-
case AMBA_VENDOR_ST:
-
vic_init_st(base, irq_start, vic_sources);
-
return;
-
default:
-
printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
-
case AMBA_VENDOR_ARM:
-
break;
-
}
-
vic_disable(base); //3.1 禁止所有的中断
-
-
vic_clear_interrupts(base); //PL190???这TMD是什么玩意?
-
-
vic_init2(base); //又有PL190?我准备放弃搞懂这个函数
-
-
vic_set_irq_sources(base, irq_start, vic_sources); //3.2 设置irq_desc中标志为可用
-
-
vic_pm_register(base, irq_start, resume_sources); //3.3
-
}
3.1 禁止所有的中断
-
static void __init vic_disable(void __iomem *base)
-
{
-
//32位的寄存器,每一位代表一个中断
-
writel(0, base + VIC_INT_SELECT); //将所有的中断都设为IRQ,不是FIQ
-
writel(0, base + VIC_INT_ENABLE); //所有的中断都为disable状态
-
writel(~0, base + VIC_INT_ENABLE_CLEAR); //写1是要清除VIC_INT_ENABLE的中断使能
-
writel(0, base + VIC_IRQ_STATUS); //清除状态寄存器
-
writel(0, base + VIC_ITCR); //TMD,VIC test control reg??
-
writel(~0, base + VIC_INT_SOFT_CLEAR); //写1是要清除VICSOFTINT寄存器
-
}
3.2 对64个内部中断的irq_desc重新设置其标志位
-
static void __init vic_set_irq_sources(void __iomem *base, unsigned int irq_start, u32 vic_sources)
-
{
-
//vic_source是32bit,其中每1位置1的代表启用一个中断源
-
//调用时vic0=~0 & ~(1 << 7),即不添加中断源7
-
for (i = 0; i < 32; i++) {
-
if (vic_sources & (1 << i)) { //只对置1的中断源进行处理
-
unsigned int irq = irq_start + i; //vic的中断号是从iqr_start=32或64开始
-
//通过中断号找到irq_desc结构体,并设置irq_desc的irq_data.chip与handle_irq
-
irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq);
-
irq_set_chip_data(irq, base);
-
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); //1.2.1重新设置irq_desc中的标志位为IRQF_VALID
-
}
-
}
-
}
vic0的中断号是32-64;
vic1的中断号是65-96;
3.2.1初始化irq_desc中的标志位state_use_accessors为IRQF_VALID|IRQF_PROBE
-
void set_irq_flags(unsigned int irq, unsigned int iflags)
-
{
-
unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
-
-
if (irq >= nr_irqs) {
-
printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
-
return;
-
}
-
//清除在early_irq_init中设置的IRQ_NOREQUEST|IRQ_NOPROBE标志,重新设为
-
//IRQ_VALID|IRQ_PROBE
-
if (iflags & IRQF_VALID)
-
clr |= IRQ_NOREQUEST;
-
if (iflags & IRQF_PROBE)
-
clr |= IRQ_NOPROBE;
-
if (!(iflags & IRQF_NOAUTOEN))
-
clr |= IRQ_NOAUTOEN;
-
-
irq_modify_status(irq, clr, set & ~clr);
-
}
4. 外部中断的初始化
start_kernel
-->
do_initcalls()
--> s3c64xx_init_irq_eint()
-
static int __init s3c64xx_init_irq_eint(void)
-
{
-
int irq;
-
//6410的外部中断号是从IRQ_EINT(0)=101 到 IRQ_EINT(27)=128
-
//对101-128的外部中断,初始化其irq_desc结构体,
-
//其中断处理函数是handle_level_irq
-
for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
-
irq_set_chip_and_handler(irq, &s3c_irq_eint, handle_level_irq);
-
irq_set_chip_data(irq, (void *)eint_irq_to_bit(irq));
-
set_irq_flags(irq, IRQF_VALID);
-
}
-
//对未映射之前的中断号为(0,1,32,33)-->现在的(32,33,64,65)
-
//对这四个中断注册其中断处理函数
-
irq_set_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3);
-
irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
-
irq_set_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19);
-
irq_set_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27);
-
-
return 0;
-
}
在include/linux/irq.h中
start_kernel
--> do_initcalls()
--> s3c64xx_init_irq_eint()
--> irq_set_chained_handler
irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
-
static inline void
-
irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)
-
{
-
__irq_set_handler(irq, handle, 1, NULL); //irq=33(33-32=1即INT_EINT1)
-
}
start_kernel
-->
do_initcalls()
--> s3c64xx_init_irq_eint()
--> irq_set_handler
在kernel/irq/chip.c中
-
void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, const char *name)
-
{
-
//其它的省略只看办正事的地方
-
desc->handle_irq = handle; //注册中断处理函数
-
desc->name = name; //name=NULL
-
}
二.以usr_irq为例分析中断调用过程
1. 中断向量表
中断向量表在arch/arm/kernel/entry-armv.S中
-
.globl __vectors_start
-
__vectors_start:
-
ARM( swi SYS_ERROR0 )
-
THUMB( svc #0 )
-
THUMB( nop )
-
W(b) vector_und + stubs_offset
-
W(ldr) pc, .LCvswi + stubs_offset
-
W(b) vector_pabt + stubs_offset
-
W(b) vector_dabt + stubs_offset
-
W(b) vector_addrexcptn + stubs_offset
-
W(b) vector_irq + stubs_offset
-
W(b) vector_fiq + stubs_offset
-
-
.globl __vectors_end
-
__vectors_end:
a. 当有irq中断发生时,就会调用vector_irq.但是vector_irq在哪呢?
搜一下linux源代码也没有找到一个vector_irq,难道是弄错了?
实际上vector_irq是通过vector_stub这个宏来定义的.
b. 跳转的地址是怎么确定的呢?
以 b vector_irq + stubs_offset 为例
在entry-armv.S中有:
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start
所以 vector_irq + stubs_offset =
vector_irq + __vectors_start + 0x200 - __stubs_start =
(vecor_irq - __stubs_start) + (__vectors_start + 0x200)
即: 相对于中断函数首地址的偏移 + 中断函数首地址
在arch/arm/kernel/entry-armv.S中有
-
__stubs_start:
-
vector_stub irq, IRQ_MODE, 4 ;马上分析这个宏的作用
-
.long __irq_usr @ 0 (USR_26 / USR_32)
-
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
-
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
-
.long __irq_svc @ 3 (SVC_26 / SVC_32)
-
.long __irq_invalid @ 4
-
.long __irq_invalid @ 5
2. 用vector_stub 产生中断函数
把vector_stub irq, IRQ_MODE, 4展开后是:
在arch/arm/kernel/entry-armv.S中
-
vector_stub irq, IRQ_MODE, 4
-
.macro vector_stub, name, mode, correction=0
-
vector_irq: ;看到没有vector_irq,它老人家终于出来了
-
.if 4
-
sub lr, lr, #4
-
.endif
-
-
;将r0,lr,spsr压栈
-
stmia sp, {r0, lr} ;将r0,lr寄存器压栈
-
mrs lr, spsr ;将spsr保存在lr中
-
str lr, [sp, #8] ;将lr压栈,即保存spsr
-
-
;将SVC_MODE保存到spsr中,准备切换到svc
-
mrs r0, cpsr ;读取cpsr到r0
-
eor r0, r0, #(IRQ_MODE ^ SVC_MODE | PSR_ISETSTATE) ;将r0设为SVC_MODE
-
msr spsr_cxsf, r0 ;将r0中的SVC_MODE写到spsr中,通过movs就可以切换到SVC模式了
-
-
and lr, lr, #0x0f ;usr模式(10000)的低4位==0,SVC模式(10011)的低4位==3,
-
THUMB( adr r0, 1f ) ;这几句没有完全弄明白
-
THUMB( ldr lr, [r0, lr, lsl #2] ) ;
-
mov r0, sp ;
-
ARM( ldr lr, [pc, lr, lsl #2] ) ;感觉是要跳到这个宏的下几句进行
-
movs pc, lr ;跳转到下一条指令,并cpsr会被spsr覆盖即切换到SVC模式
-
ENDPROC(vector_irq)
-
-
.align 2
-
1:
-
.endm
以spsr中的低四位为索引,对pc值进行调整:
如果上述是从user模式进入,则会跳到__irq_users处执行
如果上述是从svc模式进入,则会跳到 __irq_svc处执行
3. 进入irq_usr
从中断向量表中查找到中断函数,然后进入中断函数的处理过程__irq_usr
在arhc/arm/kernel/entry-armv.S中
-
.align 5
-
__irq_usr:
-
usr_entry
-
kuser_cmpxchg_check
-
get_thread_info tsk
-
irq_handler ;irq_handler继续调用
-
mov why, #0
-
b ret_to_user_from_irq
-
UNWIND(.fnend )
-
ENDPROC(__irq_usr)
__irq_usr
--> irq_handler
-
在arch/arm/kernel/entry-armv.S中
-
.macro irq_handler
-
arch_irq_handler_default
-
9997:
-
.endm
__irq_usr
--> irq_handler
--> arch_irq_handler_default
-
在arm/include/asm/entry-macro-multi.S中
-
.macro arch_irq_handler_default
-
get_irqnr_preamble r5, lr
-
1: get_irqnr_and_base r0, r6, r5, lr ;3.1获取中断号
-
movne r1, sp
-
adrne lr, BSYM(1b)
-
bne asm_do_IRQ ;3.2进入中断处理函数
-
9997:
-
.endm
3.1 获取中断号
从寄存器中读取的中断号的范围是(0-64),但是实际上这儿把中断号读取出来之后,都加了一个固定值32
所以真正的中断号的取值范围是(0-64)+32.
在arch/arm/include/asm/entry-macro-vic2.S中
.macro get_irqnr_preamble
, base
, tmp
-
ldr \base, =VA_VIC0
-
.endm
-
-
@base是VA_VIC0
-
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-
mov \irqnr, #IRQ_VIC0_BASE + 31 //为什么这儿要加上31呢?是因为clz这个指令
-
ldr \irqstat, [ \base, # VIC_IRQ_STATUS ] //读取VIC_IRQ_STATUS的值,也就是中断号的值(加上"的值"比较确切)
-
teq \irqstat, #0 //看irqstat是不是0,如果是0,标志位Z=1
-
-
@ otherwise try vic1 //下面的一串eq执行说明vic0没有产生中断irqstat==0
-
addeq \tmp, \base, #(VA_VIC1 - VA_VIC0) //
-
addeq \irqnr, \irqnr, #(IRQ_VIC1_BASE - IRQ_VIC0_BASE)
-
ldreq \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
-
teqeq \irqstat, #0 //看irqstat是不是0,如果是0,标志位Z=1
-
//下面两句ne执行说明Z=0, 即irqstat不为0,再即有中断产生
-
clzne \irqstat, \irqstat //判断是哪一位产生了中断,但是clz是从高向低计数的,实际的中断号是(32-highnr)
-
subne \irqnr, \irqnr, \irqstat //irqnr = (IRQ_BASE+31)-highnr = IRQ_BASE+(31-high_nr)也就是加上实际的中断号
-
.endm
注意:
a. teq \irqstat
, #0 判断irqstat是不是等于0,如果等于0,则cpsr中Z置位.
后面的指令都代着eq,如果Z=1则执行,反之则不执行
b. clz {cond} Rd, Rm
对Rm中leading zeros的个数进行计数,将结果存在Rd中P { margin-bottom: 0.08in;
direction: ltr; color: rgb(0, 0, 0); text-align: justify; }P.western {
font-family: "細明體","MingLiU",monospace; font-size: 12pt; }P.cjk {
font-family: "細明體","MingLiU",monospace; font-size: 12pt; }P.ctl {
font-family: "細明體","MingLiU",monospace; font-size: 12pt; }
(leading zeros: Rm中从高位向低位进行查找,直至遇到1为止,将0的个数统计出来)
例: 0x0000 0000 --> 32;
0x0000 000F --> 24;
0x0F00 0000 --> 4 ;
0x8000 0000 --> 0;
c. 总结一下上面的代码:
如果vic0产生了中断, 读取中断号的值,判断中断号是不是0,不是0,则跳到clz句判断中断号;
3.2 进入c语言的中断处理函数asm_do_IRQ
在arch/arm/kernel/irq.c中
__irq_usr
--> irq_handler
--> arch_irq_handler_default
--> asm_do_IRQ
-
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
-
{
-
struct pt_regs *old_regs = set_irq_regs(regs);
-
irq_enter();
-
-
if (unlikely(irq >= nr_irqs)) { //判断中断号是否超出范围
-
if (printk_ratelimit())
-
printk(KERN_WARNING "Bad IRQ%u\n", irq);
-
ack_bad_irq(irq);
-
} else {
-
generic_handle_irq(irq); //封装,继续调用
-
}
-
-
/* AT91 specific workaround */
-
irq_finish(irq);
-
-
irq_exit();
-
set_irq_regs(old_regs);
-
}
__irq_usr
--> irq_handler
--> arch_irq_handler_default
--> asm_do_IRQ
--> generic_handler_irq
-
int generic_handle_irq(unsigned int irq)
-
{
-
struct irq_desc *desc = irq_to_desc(irq);
-
-
if (!desc)
-
return -EINVAL;
-
generic_handle_irq_desc(irq, desc); //封装,继续调用
-
return 0;
-
}
-
EXPORT_SYMBOL_GPL(generic_handle_irq);
--> asm_do_IRQ
--> generic_handler_irq
--> generic_handler_irq_desc
-
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
-
{
-
desc->handle_irq(irq, desc); //调用每个中断的中断处理函数
-
}
注意,上面的desc->handle_irq是在 s3c64xx_init_irq_eint() 中注册的,
以dm9000的eint(7)为例说明一下:
irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
即注册 desc->handle_irq= s3c_irq_demux_eint4_11
3.3 分发外部中断
--> asm_do_IRQ
--> generic_handler_irq
--> generic_handler_irq_desc
-->
s3c_irq_demux_eint4_11
在arch/arm/mach-s3c64xx/irq-eint.c中
-
static void s3c_irq_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
-
{
-
s3c_irq_demux_eint(4, 11);
-
}
--> asm_do_IRQ
--> generic_handler_irq
--> generic_handler_irq_desc
-->
s3c_irq_demux_eint4_11
-->
s3c_irq_demux_eint
在arch/arm/mach-s3c64xx/irq-eint.c中
-
static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
-
{
-
u32 status = __raw_readl(S3C64XX_EINT0PEND);
-
u32 mask = __raw_readl(S3C64XX_EINT0MASK);
-
unsigned int irq;
-
status &= ~mask;
-
status >>= start;
-
status &= (1 << (end - start + 1)) - 1;
-
//当dm9000发生中断时,这儿的status=8=1000b,start=4,end=11
-
for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
-
if (status & 1)
-
generic_handle_irq(irq); //irq=IRQ_EINT(7)
-
status >>= 1;
-
}
-
}
从IRQ_EINT(4)开始stauts向右移1位,当status==1时,正好是IRQ_EINT(7)
IRQ_EINT(7)正好是在dm9000注册的中断号
3.4 第二次调用generic_handle_irq
-
int generic_handle_irq(unsigned int irq)
-
{
-
struct irq_desc *desc = irq_to_desc(irq);
-
-
if (!desc)
-
return -EINVAL;
-
generic_handle_irq_desc(irq, desc);
-
return 0;
-
}
-
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
-
{
-
desc->handle_irq(irq, desc);
-
}
这次的desc
->handle_irq
是谁呢?
注意,上面的desc->handle_irq也是在 s3c64xx_init_irq_eint() 中注册的,
但这次不一样的,要不成死循环了,这次是
desc->handle_irq= handle_level_irq
三.驱动调用request_irq申请中断
dm9000申请中断:
request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev);
其中: dev->irq=EINT(7)=108, irqflags=0x84=IRQF_SAMPLE_RANDOM|IRQF_SHARED
在include/linux/interrupt.h中
-
static inline int __must_check
-
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
-
const char *name, void *dev)
-
{
-
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
-
}
在kernel/irq/maage.c中
-
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
-
irq_handler_t thread_fn, unsigned long irqflags,
-
const char *devname, void *dev_id)
-
{
-
struct irqaction *action;
-
struct irq_desc *desc;
-
int retval;
-
-
if ((irqflags & IRQF_SHARED) && !dev_id) //如果是共享中断,缺没有定义dev_id返回错误
-
return -EINVAL;
-
-
desc = irq_to_desc(irq); //根据中断号在irq_desc数组中找到对应的irq_desc结构体
-
-
//这个东东在哪初始化的呢?
-
if (!irq_settings_can_request(desc)) //!(status_use_accessors & _IRQ_NOREQUEST)
-
return -EINVAL;
-
-
if (!handler) { //检查有没有指定中断处理函数
-
if (!thread_fn)
-
return -EINVAL;
-
handler = irq_default_primary_handler;
-
}
-
-
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
-
-
action->handler = handler;
-
action->thread_fn = thread_fn;
-
action->flags = irqflags;
-
action->name = devname;
-
action->dev_id = dev_id;
-
-
chip_bus_lock(desc);
-
retval = __setup_irq(irq, desc, action);
-
chip_bus_sync_unlock(desc);
-
-
if (retval)
-
kfree(action);
-
return retval;
-
}
附录:
1. s3c6410的外部中断
section 12.3
s3c6410的外部中断eint0-4,共5个
-
NO
SOURCES
Description
Group
-
0 INT_EINT0 External interrupt 0-3 VIC0
-
1 INT_EINT1 External interrupt 4-11 VIC0
-
32 INT_EINT2 External interrupt 12-19 VIC1
-
33 INT_EINT3 External interrupt 20-27 VIC1
-
53 INT_EINT4 External interrupt Group 1-9 VIC1
外部中断0-3会触发0号中断
外部中断4-11会触发1号中断
外部中断12-19会触发32号中断
外部中断20-27会触发33号中断
-
XEINT0/GPN0 XEINT1/GPN1 XEINT2/GPN2 XEINT3/GPN3
-
XEINT4/GPN4 XEINT5/GPN5 XEINT6/GPN6 XEINT7/GPN7
-
XINT8/GPN8 XINT9/GPN9 XEINT10/GPN10 XINT11/GPN11
-
XEINT12/GPN12 XEINT13/GPN13 XEINT14/GPN14 XEINT15/GPN15
-
EINT16/GPL8 EINT17/GPL9 EINT18/GPL10 EINT19/GPL11
-
EINT20/GPL12 EINT21/GPL13 EINT22/GPL14 EINT23/GPM0
-
EINT24/GPM1 EINT25/GPM2 EINT26/GPM3 EINT27/GPM4
2. 总结一下s3c6410的中断
-
以IRQ_EINT(7)为例:
-
7+64+5+32 = 108
-
32: 起始偏移
-
64: s3c6410的中断号顺次排列
-
5: 时钟中断
-
7: 外部中断
/////////////////////////////////////////////////////////////////////
arch\arm\mach-s3c64xx\include\mach\Irqs.h
IRQ_EINT(x) 第0组
IRQ_EINT_GROUP(group,no) 第1-9组
///////////////////////////////////////////////////////////////////////////////////////////
arch\arm\mach-s3c64xx\include\mach\Irqs.h
/* Next the external interrupt groups. These are similar to the IRQ_EINT(x)
* that they are sourced from the GPIO pins but with a different scheme for
* priority and source indication.
*
* The IRQ_EINT(x) can be thought of as 'group 0' of the available GPIO
* interrupts, but for historical reasons they are kept apart from these
* next interrupts. IRQ_EINT(x)可以用在0组中断,不能用在其他组外部中断
*
* Use IRQ_EINT_GROUP(group, offset) to get the number for use in the
* machine specific support files.
*/
#define IRQ_EINT_GROUP1_NR (15)
#define IRQ_EINT_GROUP2_NR (8)
#define IRQ_EINT_GROUP3_NR (5)
#define IRQ_EINT_GROUP4_NR (14)
#define IRQ_EINT_GROUP5_NR (7)
#define IRQ_EINT_GROUP6_NR (10)
#define IRQ_EINT_GROUP7_NR (16)
#define IRQ_EINT_GROUP8_NR (15)
#define IRQ_EINT_GROUP9_NR (9)
#define IRQ_EINT_GROUP_BASE S3C_EINT(28)
#define IRQ_EINT_GROUP1_BASE (IRQ_EINT_GROUP_BASE + 0x00)
#define IRQ_EINT_GROUP2_BASE (IRQ_EINT_GROUP1_BASE + IRQ_EINT_GROUP1_NR)
#define IRQ_EINT_GROUP3_BASE (IRQ_EINT_GROUP2_BASE + IRQ_EINT_GROUP2_NR)
#define IRQ_EINT_GROUP4_BASE (IRQ_EINT_GROUP3_BASE + IRQ_EINT_GROUP3_NR)
#define IRQ_EINT_GROUP5_BASE (IRQ_EINT_GROUP4_BASE + IRQ_EINT_GROUP4_NR)
#define IRQ_EINT_GROUP6_BASE (IRQ_EINT_GROUP5_BASE + IRQ_EINT_GROUP5_NR)
#define IRQ_EINT_GROUP7_BASE (IRQ_EINT_GROUP6_BASE + IRQ_EINT_GROUP6_NR)
#define IRQ_EINT_GROUP8_BASE (IRQ_EINT_GROUP7_BASE + IRQ_EINT_GROUP7_NR)
#define IRQ_EINT_GROUP9_BASE (IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR)
#define IRQ_EINT_GROUP(group, no) (IRQ_EINT_GROUP##group##_BASE + (no))
依据我根据它的注释的理解是,只有第0组的可以使用IRQ_EINT(x)这个宏来表示中断号,所以这里的x应该取0~27。而后面的1~9组就要用到IRQ_EINT_GROUP(group, no)这个宏来找到中断号了。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
阅读(362) | 评论(0) | 转发(0) |