ARM Linux对中断的处理Word文档格式.docx
《ARM Linux对中断的处理Word文档格式.docx》由会员分享,可在线阅读,更多相关《ARM Linux对中断的处理Word文档格式.docx(67页珍藏版)》请在冰豆网上搜索。
*chip_data;
structirqaction
*action;
/*IRQactionlist*/
status;
/*IRQstatus*/
depth;
/*nestedirqdisables*/
wake_depth;
/*nestedwakeenables*/
irq_count;
/*FordetectingbrokenIRQs*/
unsignedlong
last_unhandled;
/*Agingtimerforunhandledcount*/
irqs_unhandled;
spinlock_t
lock;
#ifdefCONFIG_SMP
cpumask_var_t
affinity;
node;
#ifdefCONFIG_GENERIC_PENDING_IRQ
pending_mask;
atomic_t
threads_active;
wait_queue_head_t
wait_for_threads;
#ifdefCONFIG_PROC_FS
structproc_dir_entry*dir;
constchar
*name;
}____cacheline_internodealigned_in_smp;
irq_desc结构体(中断描述符)中各个字段说明:
irq:
中断描述符的中断号
timer_rand_state:
pointertotimerrandstatestruct
kstat_irqs:
irqstatspercpu
irq_2_iommu:
iommuwiththisirq
handle_irq:
高层的irq时间处理程序(如果为NULL,则默认调用__do_IRQ())
chip:
底层的中断硬件访问,指向PIC对象(irq_chip结构),它服务于IRQ线,Linux中断管理系统使用该成员来进行中断控制器的访问。
msi_desc:
MSIdescriptor
handler_data:
irq_chip方法使用的per-IRQ数据
chip_data:
chip方法使用的特定平台的per-chip私有数据,以允许共享chip的实现
action:
标识当出现IRQ时要调用的中断服务例程。
该字段指向IRQ的irqaction链表的第一个元素。
我们用request_irq()注册的中断处理方法,会被用来创建相关的irqaction结构体,对于同一个中断号注册的各个中断方法会被链接在该中断号的中断描述符的该字段上。
status:
描述IRQ线状态的一组标志
depth:
disable-depth用于嵌套的irq_disable()调用,如果IRQ线被激活,则显示0,如果IRQ线被禁止了不止一次,则显示一个正数。
wake_depth:
enabledepth,formultipleset_irq_wake()callers
irq_count:
中断计数器,统计IRQ线上发生的中断的次数(仅在诊断时使用)
last_unhandled:
agingtimerforunhandledcount
irqs_unhandled:
对在IRQ线上发生的无法处理的中断进行计数
lock:
lockingforSMP。
用于串行访问IRQ描述符和PIC的自旋锁。
affinity:
IRQaffinityonSMP
node:
nodeindexusefulforbalancing
pending_mask:
pendingrebalancedinterrupts
threads_active:
numberofirqactionthreadscurrentlyrunning
wait_for_threads:
waitqueueforsync_irqtowaitfor
threadedhandlers
dir:
/proc/irq/procfs入口
name:
flowhandlernamefor/proc/interruptsoutput
在具体的ARMSoC芯片中会有很多的中断线,每一个中断线都会用一个irq_desc结构体来描述。
如果一个中断内核没有处理,那么这个中断就是意外中断,也就是说,与某个IRQ线相关的中断处理例程(ISR)不存在,或者与某个中断线相关的所有例程都识别不出是否是自己的硬件设备发出的中断。
通常,内核检查从IRQ线接收的意外中断的数量,当这条IRQ线的有故障设备没完没了的发中断时,就禁用这条IRQ线,内核不会在每监测到一个意外中断时就立刻禁用IRQ线。
由于几个设备可能共享IRQ线,更合适的办法是:
内核把中断和意外中断的总次数分别放在irq_desc描述符的irq_count和irqs_unhandled字段中,当第100000次中断产生时,如果意外中断的次数超过99900次内核才禁用这条IRQ线。
描述IRQ线状态的标志:
IRQ_INPROGRESS
/*IRQhandleractive-donotenter!
*/
IRQ_DISABLED
/*IRQdisabled-donotenter!
IRQ_PENDING
/*IRQpending-replayonenable*/
IRQ_REPLAY
/*IRQhasbeenreplayedbutnotackedyet*/
IRQ_AUTODETECT
/*IRQisbeingautodetected*/
IRQ_WAITING
/*IRQnotyetseen-forautodetection*/
IRQ_LEVEL
/*IRQleveltriggered*/
IRQ_MASKED
/*IRQmasked-shouldn'
tbeseenagain*/
IRQ_PER_CPU
/*IRQisperCPU*/
IRQ_NOPROBE
/*IRQisnotvalidforprobing*/
IRQ_NOREQUEST
/*IRQcannotberequested*/
IRQ_NOAUTOEN
/*IRQwillnotbeenabledonrequestirq*/
IRQ_WAKEUP
/*IRQtriggerssystemwakeup*/
IRQ_MOVE_PENDING
/*needtore-targetIRQdestination*/
IRQ_NO_BALANCING
/*IRQisexcludedfrombalancing*/
IRQ_SPURIOUS_DISABLED/*IRQwasdisabledbythespurioustrap*/
IRQ_MOVE_PCNTXT
/*IRQmigrationfromprocesscontext*/
IRQ_AFFINITY_SET
/*IRQaffinitywassetfromuserspace*/
IRQ_SUSPENDED
/*IRQhasgonethroughsuspendsequence*/
IRQ_ONESHOT
/*IRQisnotunmaskedafterhardirq*/
IRQ_NESTED_THREAD/*IRQisnestedintoanother,noownhandlerthread*/
irq_desc描述符的depth字段和IRQ_DISABLED标志表示IRQ线是否被禁用。
每次调用disable_irq()和disable_irq_nosync()函数,depth字段的值增加,如果depth等于0,函数禁用IRQ线并设置它的IRQ_DISABLED标志。
相反,每当调用enable_irq()函数,depth字段的值减少,如果depth变为0,函数激活IRQ线并清除IRQ_DISABLED标志。
Linux支持许多种类的PIC电路,如PC机的8259A、APIC等。
为了以统一的方法处理所有这样的设备,Linux用了一个“PIC对象”,由PIC名字和17个标准方法组成。
这种面向对象的方法的优点是,驱动程序不必关注安装在系统中的PIC种类。
每个驱动程序可见的中断源透明地连接到适当的控制器。
定义PIC对象的数据结构叫irq_chip。
内核使用irq_chip结构的成员来完成实际的对于PIC控制器的操作,禁用中断,启用中断等。
structirq_chip{
unsignedint(*startup)(unsignedintirq);
(*shutdown)(unsignedintirq);
(*enable)(unsignedintirq);
(*disable)(unsignedintirq);
(*ack)(unsignedintirq);
(*mask)(unsignedintirq);
(*mask_ack)(unsignedintirq);
(*unmask)(unsignedintirq);
(*eoi)(unsignedintirq);
(*end)(unsignedintirq);
int
(*set_affinity)(unsignedintirq,
conststructcpumask*dest);
(*retrigger)(unsignedintirq);
(*set_type)(unsignedintirq,unsignedintflow_type);
(*set_wake)(unsignedintirq,unsignedinton);
(*bus_lock)(unsignedintirq);
(*bus_sync_unlock)(unsignedintirq);
/*CurrentlyusedonlybyUML,mightdisappearoneday.*/
#ifdefCONFIG_IRQ_RELEASE_METHOD
(*release)(unsignedintirq,void*dev_id);
/*
*Forcompatibility,->
typenameiscopiedinto->
name.
*Willdisappear.
*/
*typename;
};
irq_chip结构体(硬件中断芯片描述符)各个字段说明:
namefor/proc/interrupts
startup:
启动中断(如果为NULL,则默认情况下其与->
enable相同)
shutdown:
关闭中断(如果为NULL,则默认情况下其与->
disable相同)
enable:
使能中断(如果为NULL,则默认情况下其与chip->
unmask相同)
disable:
禁用中断(如果为NULL,则默认情况下其与chip->
mask相同)
ack:
开始一个新的中断,即给予中断控制器以确认,以允许中断的发生
mask:
屏蔽一个中断源
mask_ack:
确认并屏蔽一个中断源
unmask:
取消屏蔽一个中断源
eoi:
endofinterrupt-chiplevel
end:
endofinterrupt-flowlevel
set_affinity:
settheCPUaffinityonSMPmachines
retrigger:
重新发送一个IRQ给CPU
set_type:
settheflowtype(IRQ_TYPE_LEVEL/etc.)ofanIRQ
set_wake:
enable/disablepower-managementwake-onofanIRQ
bus_lock:
functiontolockaccesstoslowbus(i2c)chips
bus_sync_unlock:
functiontosyncandunlockslowbus(i2c)chips
release:
releasefunctionsolelyusedbyUML
typename:
obsoletedbyname,keptasmigrationhelper
多个设备能共享一个单独的IRQ。
因此,内核要维护多个irqaction描述符,其中的每个描述符涉及一个特定的硬件设备和一个特定的中断。
这个结构在文件include/interrupt.h中定义:
structirqaction{
irq_handler_thandler;
unsignedlongflags;
constchar*name;
void*dev_id;
structirqaction*next;
intirq;
irq_handler_tthread_fn;
structtask_struct*thread;
unsignedlongthread_flags;
structirqaction(中断行为描述符)各字段说明:
handler:
中断处理函数,指向一个I/O设备的中断服务例程。
这是允许多个设备共享同一个IRQ的关键字段。
flags:
标志(参考下面的IRQF_*),描述IRQ与I/O设备之间的关系。
I/O设备名(通过读/proc/interrupts文件,在列出所服务的IRQ时也显示设备名)。
dev_id:
I/O设备的私有数据字段。
典型情况下,它标识I/O设备本身(例如,它可能等于其主设备号和此设备号),或者它指向设备驱动程序的数据
next:
共享中断情况下,指向irqaction链表的下一个元素。
链表中的元素指向共享同一个IRQ的硬件设备
中断号
指向proc/irq/NN/name入口的指针,指向proc文件系统中IRQn相关的目录项。
thread_fn:
用于线程化中断的中断处理函数
thread:
用于线程化中断的线程指针
thread_flags:
与thread有关的标志
irqaction描述符的标志,只是被作为irq处理例程的一部分来使用的,各个标志的说明如下:
IRQF_DISABLED–当调用actionhandler时保持irqs禁用
IRQF_SAMPLE_RANDOM–设备可以被看作是事件随机的发生源,一次,内核可以用它做随机数产生器
IRQF_SHARED–允许在多个设备间共享中断
IRQF_PROBE_SHARED-setbycallerswhentheyexpectsharing
mismatchestooccur
IRQF_TIMER–标记该中断为时钟中断的标志
IRQF_PERCPU-Interruptispercpu
IRQF_NOBALANCING-Flagtoexcludethisinterruptfromirqbalancing
IRQF_IRQPOLL-Interruptisusedforpolling(onlytheinterrupt
thatisregisteredfirstinansharedinterruptisconsideredfor
performancereasons)
IRQF_ONESHOT-Interruptisnotreenabledafterthehardirq
handlerfinished.Usedbythreadedinterruptswhichneedtokeepthe
irqlinedisableduntilthethreadedhandlerhasbeenrun.
最后,irq_stat数组包含NR_CPUS个元素,系统中的每个CPU对应一个元素(kernel/softirq.c文件中):
#ifndef__ARCH_IRQ_STAT
irq_cpustat_tirq_stat[NR_CPUS]____cacheline_aligned;
EXPORT_SYMBOL(irq_stat);
每个元素的类型为irq_cpustat_t,该类型包含几个计数器和内核记录CPU正在做什么的标志,该结构体的定义因体系结构而已,对于我们的ARM平台,这个结构在arch/arm/include/asm/hardirq.h文件中定义:
typedefstruct{
unsignedint__softirq_pending;
unsignedintlocal_timer_irqs;
}____cacheline_alignedirq_cpustat_t;
irq_cpustat_t结构的字段
__softirq_pending:
表示挂起的软中断
local_timer_irqs:
本地时钟中断发生的次数
在kernel/irq/handle.c中还有定义了一个全局irq_desc结构体数组,用来表示系统中的所有中断:
structirq_descirq_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=__SPIN_LOCK_UNLOCKED(irq_desc->
lock),
}
上面的__cacheline_aligned_in_smp在include/linux/cache.h中定义,它是一个宏,在非SMP系统中是空的:
#define__cacheline_aligned_in_smp__cacheline_aligned
#else
#define__cacheline_aligned_in_smp
#endif/*CONFIG_SMP*/
用于描述结构体的属性,cache行对齐。
内核用结构数组irq_desc[NR_IRQS]来管理中断处理,每一个成员对应于一个中断线。
NR_IRQS是一个因平台而异的宏,对于我们的mini2440来说,该宏在arch/arm/mach-s3c2440/include/mach/irqs.h中定义:
#ifdefCONFIG_CPU_S3C2443
#defineNR_IRQS(IRQ_S3C2443_AC97+1)
#defineNR_IRQS(IRQ_S3C2440_AC97+1)
这个宏代表平台上最大的中断号。
ARMLinux对中断的处理--中断管理系统的初始化
中断管理系统的初始化
我们先来看一下Linux系统中,中断管理系统的初始化。
中断系统的初始化主要由几个函数来完成。
在系统初始化