(六) 中断机制

中断通常分为同步中断和异步中断:

  同步中断:是当指令执行时由CPU控制单元产生,之所以称之为同步,是因为只有在一条指令终止执行后CPU才会发出中断

  异步中断:是由其它硬件设备依照CPU时钟信号随机产生。

  通常把同步中断称之为异常,把异步中断称之为中断 

异步中断可能为以下两种:  

  可屏蔽中断:I/O设备发出的所有中断请求(IRQ)都产生可屏蔽中断。

  非屏蔽中断:只有几个危急的事件(如硬件故障)才引起非屏蔽中断。非屏蔽中断总是由CPU辩认的。 

异常(fault):根据CPU控制单元产生异常时保存在内核态堆栈eip寄存器的值分为以下三种:

  故障:通常是可以纠正的,一旦纠正,程序就可以在不失连贯性的情况下重新开始。保存在eip中的值是引起故障的指令地址。因此,当异常处理程序终止时,那系着指令会被重新执行。(比如缺页)。  

  陷阱(trap):在陷阱指令执行后立即报告;内核把控制权返回给程序后就可以继续它的执行而不失连贯性何存在eip中的值是一个随后要执行地址。只有当没有必要重新执行已终止的指令时,才触发陷阱。

  异常终止:发生一个严重的错误,控制单元出了问题,不能在eip寄存器中保存引起异常指令所在的确切位置。异常中止用于报告严重的错误,如硬件故障或系统中无效的值或不一致的值。 

  与Linux设备驱动中中断处理相关的首先是申请与释放IRQ的API request_irq()和freeirq()。

int request_irq(unsigned int irq, void (handler)(int irq, void dev_id, struct pt_regs regs), unsigned long irqflags, const char * devname, void dev_id);

void free_irq(unsigned int irq,void dev_id);

  irq是要申请的硬件中断号;

  handler是向系统登记的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,devid参数将被传递;

  irqflags是中断处理的属性,若设置SAINTERRUPT,标明中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程 序不屏蔽;若设置SASHIRQ,则多个设备共享中断,devid在中断共享时会用到,一般设置为这个设备的device结构本身或者NULL。

  devname设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。

  dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

 

  下面详细介绍linux 内核中断机制处理过程。 

  1.Linux定义了名字为irq_desc的中断例程描述符表:(include/linux/irq.h)

     struct irqdesc irq_desc[NR_IRQS];

    NR_IRQS表示中断源的数目。 

  2. irq_desc[]是一个指向irq_desc结构的数组, irq_desc结构是各个设备中断服务例程的描述符。  

struct irq_desc {
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
void *handler_data;
void *chip_data;
struct irqaction *action;
unsigned int status;

unsigned intdepth;
unsigned int wake_depth;
unsigned int irq_count;
unsigned int irqs_unhandled;
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry*dir;
#endif
const char *name;
} ____cacheline_aligned;

    Irq_desc结构体中的成员action指向该中断号对应的irqaction结构体链表。Irqaction结构体定义如下:  

// include/linux/interrupt.h
struct irqaction{
irq_handler_t handler; // 指向中断服务程序
unsigned long flags; // 中断标志
unsigned long mask; // 中断掩码
const char *name;// I/O设备名

void *dev_id;// 设备标识
struct irqaction*next;// 指向下一个描述符

int irq;// IRQ线
struct proc_dir_entry *dir; // 指向IRQn相关的/proc/irq/n目录的描述符
};

   其中关键的handler成员指向了该设备的中断服务程序,由执行request_irq时建立。 

  3. 在驱动程序初始化时,若使用到中断,通常调用函数request_irq()建立该驱动程序对应的irqaction结构体,并把它登记到irq_desc [irq_num]->action链表中。Iqr_num为驱动程序申请的中断号。

  4. 共享中断的不同设备的iqraction结构体都会添加进该中断号对应的irq_desc结构体的action成员所指向的irqaction链表内。当内核发生中断时,它会依次调用该链表内所有的handler函数。因此,若驱动程序需要使用共享中断机制,其中断处理函数必须有能力识别是否是自己的硬件产生了中断。通常是通过读取该硬件设备提供的中断flag标志位进行判断。

 

  

 

 

posted @ 2013-08-30 14:58  皁仩腄覺  阅读(308)  评论(0)    收藏  举报