首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux中PowerPC的中断原理分析

Linux中PowerPC的中断原理分析

在了解中断处理机制前,先看一下PowerPC的中断源,这里使用的是e300c3的内核,从E300核的角度,中断源可分为异常和外部中断,异常是e300内核产生的,如出现非法指令,或者是访问存储器时出现TLB Miss等情况。这种情况太复杂了,没有深究,这里所说的中断为外部中断。所谓外部中断,就是通过e300外部引脚产生的中断。E300的外部中断主要有:int#, cint#, mcp#. 这三根pin分别对应一般中断,critical中断和machine check中断。
在设备驱动过程中,用户可以使用request_irq函数将外设的中断服务例程挂载到外部中断处理程序中。外部中断处理程序,可以直接处理硬件中断,但是request_irq函数试用软件中断号进行挂载,因此linux必然采用了某种方式进行软硬件中断的映射。
这里需要了解下中断向量表的概念,就是它将软件中断号与硬件中断号联系起来,在系统中,中断源有很多,当某一种中断发生时,处理器最早进入的是处理函数的地址,就是中断向量。每种类型对应一个中断向量号,一系列的中断号构成中断向量表。比如驱动程序关心的外部中断,当这种中断发生时,处理器内核(e300)就会到指定寄存器中去取得中断处理函数的入口地址。
硬件中断号是当中断发生时,处理器从外部的PIC(Programable Interrupt Controller)上读到的数值。因为在PowerPC Linux中有dts的概念,驱动程序员需要知道自己所负责的设备对应的device node上的interrupt项如何写的问题,这里的interrupt上的数字就是硬件中断号。在Linux系统初始化期间,通过对PIC的配置,可以将硬件的连接转化成相应的硬件中断号,例如,8315上的8根外设中断线IRQ0~IRQ7,可以通过PIC的配置,分别映射成的硬件中断号为10~18,那么当IRQ0上有中断请求时,处理器通过读取PIC,就得到P1所对应的硬件中断号为10。这些都是硬件层面的东西,当驱动程序安装它们的中断处理程序时,是基于软件中断号的,也就是内核函数request_irq中的参数irq是个软件中断号。
软件中断号是Linux下的概念,为了支持多平台的关系,Linux不直接用硬件中断号索引irq_desc。所以当外部中断发生时,在外部中断入口函数中会通过读取PIC来获得本次中断的硬件中断号,获得硬件中断号后,会将其映射成对应的软件中断号来索引irq_desc数组,从而获得该软件中断号上的中断处理函数。显然,这种硬件中断号到软件中断号的映射关系,应该在设备可以处理中断前就要建立好了。在Linux PowerPC中,这种映射关系是由函数irq_of_parse_and_map(struct device_node *dev, int index)来完成的。
注意:在8315中,关于MSI的硬件中断号,可以在系统全局中断向量寄存器SIVCR中查询。另外,其实,如果没有软件中断号,设备驱动程序也能以硬件中断号作索引挂载处理程序,从功能上说没有任何问题。软件中断号的引入,是为了硬件中断号对OS透明。这样处理能减少OS对硬件平台的依赖性。
下面贴些内核的代码,方便细细分析:
linux使用结构体struct irq_map_entry irq_map[NR_IRQS]完成软件与硬件的中断号映射,一般系统自动查找可用的软件号以对应请求的硬件中断号。
在使用open firmware的系统中,驱动程序在执行ruquest_irq之前要先进行软硬件中断号的映射,具体通过函数:
irq_of_parse_and_map(struct device_node * dev, int index);
实现,具体函数调用过程如下:
irq_create_of_mapping(struct device_node * controller, u32 * inspec, unsigned int intsize);
irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq);
程序除了进行软硬件中断号的映射外还需要初始后相应结构。
下面看看与中断相关的另外几个主要数据结构:
1、结构体:struct irq_desc(include/linux/irq.h)
  • struct irq_desc {  
  •     unsigned int        irq;  

  • struct timer_rand_state *timer_rand_state;  
  •     unsigned int            *kstat_irqs;  

  • #ifdef CONFIG_INTR_REMAP

  • struct irq_2_iommu      *irq_2_iommu;  

  • #endif
  •     irq_flow_handler_t  handle_irq;  

  • struct irq_chip     *chip;  

  • struct msi_desc     *msi_desc;  

  • void            *handler_data;  

  • void            *chip_data;  

  • struct irqaction    *action;    /* IRQ action list */
  •     unsigned int        status;     /* IRQ status */

  •     unsigned int        depth;      /* nested irq disables */
  •     unsigned int        wake_depth; /* nested wake enables */
  •     unsigned int        irq_count;  /* For detecting broken IRQs */
  •     unsigned long       last_unhandled; /* Aging timer for unhandled count */
  •     unsigned int        irqs_unhandled;  
  •     raw_spinlock_t      lock;  

  • #ifdef CONFIG_SMP
  •     cpumask_var_t       affinity;  

  • const
    struct cpumask    *affinity_hint;  
  •     unsigned int        node;  

  • #ifdef CONFIG_GENERIC_PENDING_IRQ
  •     cpumask_var_t       pending_mask;  

  • #endif

  • #endif
  •     atomic_t        threads_active;  
  •     wait_queue_head_t       wait_for_threads;  

  • #ifdef CONFIG_PROC_FS

  • struct proc_dir_entry   *dir;  

  • #endif

  • const
    char      *name;  
  • } ____cacheline_internodealigned_in_smp;  
这个结构体用来描述中断源,是用来连接硬件中断和驱动程序中通过request_irq注册的中断处理函数之间的桥梁。数组irq_desc[NR_IRQS](NR_IRQS=225)中每一项都对应一个相应的中断源,他的每一项对应着中断向量表中的一项,即该数组的第一项对应着中断向量表中的第32项(中断向量号为0x20),往下依次对应。中断向量表一共有256项。
继承事业,薪火相传
返回列表