Linux mips64r2 PCI中断路由机制分析

本文主要分析mips64r2 PCI设备中断路由原理和irq号分配实现方法,并尝试回答如下问题:

  • PCI设备驱动中断注册(request_irq)时的irq#从哪里来?是硬件相关?还是软件相关?
  • 中断上报时,CPU是如何获得这个irq#的?

本文主要分析PIC(可编程中断控制器)的工作原理,PIC一般集成在CPU中,不同arch、vendor CPU的PIC实现原理也不尽相同。本文基于kerne3.10 + mips64r2 XXX CPU分析。

mips64r2 PCI设备中断路由原理

如上图所示,硬件实现上,PCI中断路由主要涉及3个设备:PCI设备、PIC、CPU。

PIC作为核心器件,其核心功能如下:

  • 160个32位IRT,依次对应160个硬件Interrupt Lines;
  • 64个interrupt vector;
  • 8个128位ITE(Interrupt Thread Enable),包含了4个节点的128个硬件线程使能位;
  • 局部和全局Round-Robin策略分发中断到相应硬件线程;
  • 8个系统定时器,2个看门狗定时器(可配置成NMI看门狗定时器,不同的IRT Entry);
  • 支持IPI。

3个主要中断信号:

  • interrupt pin:PCI设备中断输出信号。PCI设备提供4个中断输出(INTA#, INTB#, INTC#, INTD#),由PCI设备的pci configure space中interrupt pin指定;
  • interrupt line:PIC设备输入信号,与PCI设备中断输出信号相连。由PCI设备的pci configure space中interrupt line指定;
  • interrupt vector:PIC设备输出信号,与CPU中断输入信号相连。这个interrupt vector即PCI设备驱动中断注册的中断号irq#,可通过CPU的EIRR(extended interrupt request register)寄存器读取。由于mips64r2体系架构的限制,EIRR为64bit,每个bit代表一个vector,所以最多64个vector;

软件实现上,抽象出2个表对象来实现中断路由的管理和处理:

  • IRT:interrupt redirection table。硬件表,index为interrupt line#,共160个条目,用于维护interrupt line和interrupt vector的映射关系, interrupt line mask/unmask、enable/disable等控制, interrupt的CPU亲和性设置等;
  • IDT:interrupt description table。软件表,index为interrupt vector#,共64个条目,用与中断处理。

中断处理过程

如上图所示,中断由产生到结束的整个过程:

handle_int

-> plat_irq_dispatch

-> do_nlm_common_IRQ

-> do_IRQ

-> generic_handle_irq

-> generic_handle_irq_desc

-> __do_IRQ

-> handle_IRQ_event

硬件设备产生中断(request & pending);

  1. 不同的设备中断请求可能同时到达,PIC通过仲裁规则(如Round-Robin、优先级等)挑选出一个合适的请求(arbiter);
  2. PIC设置此中断相关的ACK位(assert),分发(delivery)请求到目的硬件线程(通过IRT的配置);
  3. CPU读取EIRR寄存器获取request irq#后写清除;
  4. 根据irq#查询IDT表获得此中断的desc;
  5. 如果是边沿触发中断,为了避免中断丢失,立即调用desc->chip->ack写相关寄存器(INT_ACK)清除本次中断源(de-assert),使相应interrupt line可以再次响应中断;
  6. 遍历desc->action->handler链处理中断请求;
  7. 如果是水平触发中断,在处理完中断后,调用desc->chip->end写相关寄存器(INT_ACK)清除本次中断源(de-assert);
  8. 转2)继续处理下一个中断请求。

IRT配置过程

IRT为PIC控制器的硬件表,主要在pic_init和request_irq中断注册时配置。IRT条目和字段解释如下:

  • EN:IRT条目使能配置字段。在request_irq中断注册时使能;
  • NMI:NMI中断配置字段。在pic_init中设置为非NMI;
  • SCH:中断调度策略配置字段。在pic_init中设为locascheduling;
  • RVEC:irq#配置字段。在pic_init中根据irt_irq_table设置;
  • DT/DB/DTE:CPU亲和性配置字段。在request_irq中断注册时配置,也可以通过/proc/irq/N/smp_affinity设置,由desc->chip->set_affinity/pic_set_affinity实现。

IDT配置过程

IDT为软件表,主要在init_IRQ和request_irq中断注册时根据irq#配置IDT的相应条目的各个字段,如irq, irqaction handler, irq_chip handler等。2个配置过程区分如下:

  • init_IRQ:配置每个条目的desc->chip,设置desc->status为IRQ_NOPROBE;初始化非PIC相关中断IDT条目,如IPI核间中断等。
  • request_irq:初始化PIC相关中断IDT条目;
#define NR_IRQS 64
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[ ... NR_IRQS-] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = ,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
}; /**
* struct irq_desc - interrupt descriptor
* @irq: interrupt number for this descriptor
* @timer_rand_state: pointer to timer rand state struct
* @kstat_irqs: irq stats per cpu
* @irq_2_iommu: iommu with this irq
* @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]
* @chip: low level interrupt hardware access
* @msi_desc: MSI descriptor
* @handler_data: per-IRQ data for the irq_chip methods
* @chip_data: platform-specific per-chip private data for the chip
* methods, to allow shared chip implementations
* @action: the irq action chain
* @status: status information
* @depth: disable-depth, for nested irq_disable() calls
* @wake_depth: enable depth, for multiple set_irq_wake() callers
* @irq_count: stats field to detect stalled irqs
* @last_unhandled: aging timer for unhandled count
* @irqs_unhandled: stats field for spurious unhandled interrupts
* @lock: locking for SMP
* @affinity: IRQ affinity on SMP
* @node: node index useful for balancing
* @pending_mask: pending rebalanced interrupts
* @threads_active: number of irqaction threads currently running
* @wait_for_threads: wait queue for sync_irq to wait for threaded handlers
* @dir: /proc/irq/ procfs entry
* @name: flow handler name for /proc/interrupts output
*/
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;
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_var_t affinity;
unsigned int node;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_t pending_mask;
#endif
#endif
atomic_t threads_active;
#ifdef CONFIG_PREEMPT_HARDIRQS
unsigned long forced_threads_active;
#endif
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char *name;
} ____cacheline_internodealigned_in_smp; struct irq_chip {
const char *name;
unsigned int (*startup)(unsigned int irq);
void (*shutdown)(unsigned int irq);
void (*enable)(unsigned int irq);
void (*disable)(unsigned int irq); void (*ack)(unsigned int irq);
void (*mask)(unsigned int irq);
void (*mask_ack)(unsigned int irq);
void (*unmask)(unsigned int irq);
void (*eoi)(unsigned int irq); void (*end)(unsigned int irq);
int (*set_affinity)(unsigned int irq,
const struct cpumask *dest);
int (*retrigger)(unsigned int irq);
int (*set_type)(unsigned int irq, unsigned int flow_type);
int (*set_wake)(unsigned int irq, unsigned int on); void (*bus_lock)(unsigned int irq);
void (*bus_sync_unlock)(unsigned int irq); /* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
void (*release)(unsigned int irq, void *dev_id);
#endif
/*
* For compatibility, ->typename is copied into ->name.
* Will disappear.
*/
const char *typename;
}; static struct irq_chip nlm_common_pic = {
.unmask = pic_unmask,
.mask = pic_shutdown,
.ack = pic_ack,
.end = pic_end,
.set_affinity = pic_set_affinity
};

--EOF--

Linux mips64r2 PCI中断路由机制分析的更多相关文章

  1. Linux x86_64 APIC中断路由机制分析

    不同CPU体系间的中断控制器工作原理有较大差异,本文是<Linux mips64r2 PCI中断路由机制分析>的姊妹篇,主要分析Broadwell-DE X86_64 APIC中断路由原理 ...

  2. Linux内核中的Workqueue机制分析

    1. 什么是workqueue Linux中的workqueue(工作队列)主要是为了简化在内核创建线程而设计的.通过相应的工作队列接口,可以使开发人员只关心与特定功能相关的处理流程,而不必关心内核线 ...

  3. floodlight路由机制分析

    SDN的出现可以使得各种复杂的路由协议从原本的Device OS中剥离出来,放在SDN Controller中,Controller用一种简单的协议来和所有的Router进行通信,就可以获得网络拓扑, ...

  4. Linux 内核PCI 中断

    对于中断, PCI 是容易处理的. 在 Linux 启动时, 计算机的固件已经分配一个唯一的中 断号给设备, 并且驱动只需要使用它. 中断号被存储于配置寄存器 60 (PCI_INTERRUPT_LI ...

  5. Meandering Through the Maze of MFC Message and Command Routing MFC消息路由机制分析

    Meandering Through the Maze of MFC Message and Command Routing Paul DiLascia Paul DiLascia is a free ...

  6. linux的可中断sleep_on函数分析

    void interruptible_sleep_on (struct task_struct **p)// **p是个全局变量 { struct task_struct *tmp; if (!p)# ...

  7. 【翻译】运行于x86机器上的FreeBSD的PCI中断

    来源 http://people.freebsd.org/~jhb/papers/bsdcan/2007/article/article.html 摘要 在拥有多个独立设备的计算机里一个重要的元素是一 ...

  8. Linux内核NAPI机制分析

    转自:http://blog.chinaunix.net/uid-17150-id-2824051.html 简介:NAPI 是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采用 ...

  9. Linux信号(signal) 机制分析

    Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...

随机推荐

  1. mac 下设置jdk 路径,设置hadoop 路径

    1. touch ~/.bash_profile  创建一个文件 2.vim ~/.bash_profile JAVA_HOME=/Library/Java/JavaVirtualMachines/j ...

  2. 基于Unity3D 的Vuforia SDK开发基础教程

    最新博客地址已转到: http://blog.csdn.net/zzlyw?viewmode=contents   ------------------------------------------ ...

  3. Cookie, LocalStorage 与 SessionStorage

    Cookie, LocalStorage 与 SessionStorage相同点 都是储存在用户本地的数据. 意义在于避免数据在浏览器和服务器间不必要地来回传递. 三者的特点     同属于html5 ...

  4. win7系统下的飞秋发送文件失败问题

    飞秋发送文件失败这个问题大多数是由防火墙引起的1.检查windows自带的防火墙设置,在左侧的"允许程序通过windows防火墙"查看飞秋是否存在,不存在则增加之,公网.专网都勾选 ...

  5. Java:方法的参数是传值还是传引用

    Java中方法的参数总是采用传值的方式. 下列方法欲实现对象的交换,但实际上是不能实现的. public void swap(simpleClass a,simpleClass b){ simpleC ...

  6. POJ 2823 Sliding Window 线段树区间求和问题

    题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...

  7. Ubuntu16.04 VTK7.1.0+QT4.8.6+QtCreator开发环境配置

    VTK需要OpenGL3.0或更高版本的驱动,但虚拟机下的Ubuntu不支持OpenGL3.0,或者自己按网上教程配置之后也能支持,但过程相当繁琐,本人试验失败. 最终决心采用双系统,装好之后,执行g ...

  8. seo优化urlrewrite伪静态技术

    1.下载urlrewrite-3.2.0.jar 2.在WEB-INF下增加urlrewrite.xml <?xml version="1.0" encoding=" ...

  9. 处理Https 异常记录 javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

    http://blog.csdn.net/baidu_18607183/article/details/51595330 https://blogs.oracle.com/java-platform- ...

  10. zend studio 13.5破解以及集成xdebug

    环境说明: 操作系统:Windows 7 Ultimate Edition Service Pack 1 PHP:7.0.11 TS Zend Studio:13.5.0 Xdebug:2.5.0 一 ...