Linux中断子系统:级联中断控制器驱动
Linux中断子系统
Linux中断子系统是个很大的话题,如下面的思维导图所示,包含硬件、驱动、中断上半部、中断下半部等等。本文着眼于中断控制器(PIC),特别是级联中断控制器驱动部分,对驱动的设计和调试要点进行分析总结。
级联中断控制器驱动
中断控制器的核心对象是irq_chip,其提供了很多接口,一般情况下不需要全部实现。下面是几个类似的接口的差别介绍:
- irq_enable:在中断注册或使能时调用,一般在使能中断前需要清除中断状态。
- irq_disable:在中断注销或关闭时调用,一般在关闭中断前不清除中断状态。
- irq_mask_ack:在进入中断处理函数前调用,一般在屏蔽中断前需要清除中断源信号。
- irq_unmask:在退出中断处理函数后调用,一般在去屏蔽中断前不清除清除中断源信号。
级联中断控制器的初始化流程
中断控制器的级联如上图所示。级联中断控制器的初始化流程分为2部分:根中断控制器的初始化和子中断控制器的初始化。
根中断控制器相关部分
- 根据irq获取根PIC的irt;
- 将irt/irq的映射关系配置到根PIC的IRT表寄存器;
- 初始化根PIC的irq_chip接口对象;
- 调用irq_set_chip_and_handler设置根PIC irq的irq_chip及其handler;
- 调用irq_set_chip_data设置根PIC irq_chip接口调用时的环境对象;
子中断控制器相关部分
- 初始化子PIC的irq_chip接口对象;
- 映射子PIC io mem空间,以便后续访问其寄存器;
- 获取PIC的irq domain的irq基值,并调用irq_domain_add_xxx获取子PIC的中断域空间;
- 调用irq_set_chip_and_handler设置子PIC irq的irq_chip及其handler;
- 调用irq_set_chip_data设置子PIC irq_chip接口调用时的环境对象;
- 获取根PIC的irq;
- 调用irq_set_chained_handler设置根PIC irq handler;
- 调用irq_set_handler_data设置根PIC irq handler调用时的环境对象;
级联中断控制器的中断处理流程
首先,CPU只能感知到root PIC的中断,当root PIC的中断触发后,进入root irq handler,在handler中找到触发中断的sub irq,并调用其handler进行中断处理。换句话说,root irq的handler是root PIC的中断路由功能的软件扩展。
找到sub irq的方法依赖sub PIC具体硬件实现,以GPIO中断控制器的root irq handler为例,其方法如下:
- 调用chained_irq_enter,mask_ack root irq;
- 获取gpio 中断pin脚使能情况;
- 读取gpio interrupt status寄存器,判断此gpio 中断使能pin脚是否触发了中断;
- 通过irq_find_mapping获取此gpio pin对应的irq#;
- 通过generic_handle_irq调用 sub irq handler来进行gpio中断处理;
- 调用chained_irq_exit,unmask root irq。
中断控制器驱动调试要点
- 根据中断控制器特点,仔细设计irq_chip的接口。那么哪些需要实现,哪些又不需要是需要仔细考虑;
- root irq的handler要用chained_irq_enter/chained_irq_exit进行保护;
- 理顺中断触发时序。比如设备、子PIC的中断状态、中断源信号等中断标记清除顺序,以此来决定在哪些irq_chip接口中清除中断标记;
- 一般来说,对于任何中断设备,在使能中断前需要清除中断状态,避免垃圾中断干扰。
附关键数据结构
/**
* struct irq_chip - hardware interrupt chip descriptor
*
* @name: name for /proc/interrupts
* @irq_startup: start up the interrupt (defaults to ->enable if NULL)
* @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL)
* @irq_enable: enable the interrupt (defaults to chip->unmask if NULL)
* @irq_disable: disable the interrupt
* @irq_ack: start of a new interrupt
* @irq_mask: mask an interrupt source
* @irq_mask_ack: ack and mask an interrupt source
* @irq_unmask: unmask an interrupt source
* @irq_eoi: end of interrupt
* @irq_set_affinity: set the CPU affinity on SMP machines
* @irq_retrigger: resend an IRQ to the CPU
* @irq_set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
* @irq_set_wake: enable/disable power-management wake-on of an IRQ
* @irq_bus_lock: function to lock access to slow bus (i2c) chips
* @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips
* @irq_cpu_online: configure an interrupt source for a secondary CPU
* @irq_cpu_offline: un-configure an interrupt source for a secondary CPU
* @irq_suspend: function called from core code on suspend once per chip
* @irq_resume: function called from core code on resume once per chip
* @irq_pm_shutdown: function called from core code on shutdown once per chip
* @irq_print_chip: optional to print special chip info in show_interrupts
* @flags: chip specific flags
*/
struct irq_chip {
const char *name;
unsigned int (*irq_startup)(struct irq_data *data);
void (*irq_shutdown)(struct irq_data *data);
void (*irq_enable)(struct irq_data *data);
void (*irq_disable)(struct irq_data *data); void (*irq_ack)(struct irq_data *data);
void (*irq_mask)(struct irq_data *data);
void (*irq_mask_ack)(struct irq_data *data);
void (*irq_unmask)(struct irq_data *data);
void (*irq_eoi)(struct irq_data *data); int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
int (*irq_retrigger)(struct irq_data *data);
int (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
int (*irq_set_wake)(struct irq_data *data, unsigned int on); void (*irq_bus_lock)(struct irq_data *data);
void (*irq_bus_sync_unlock)(struct irq_data *data); void (*irq_cpu_online)(struct irq_data *data);
void (*irq_cpu_offline)(struct irq_data *data); void (*irq_suspend)(struct irq_data *data);
void (*irq_resume)(struct irq_data *data);
void (*irq_pm_shutdown)(struct irq_data *data); void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); unsigned long flags;
}; /**
* struct irq_data - per irq and irq chip data passed down to chip functions
* @irq: interrupt number
* @hwirq: hardware interrupt number, local to the interrupt domain
* @node: node index useful for balancing
* @state_use_accessors: status information for irq chip functions.
* Use accessor functions to deal with it
* @chip: low level interrupt hardware access
* @domain: Interrupt translation domain; responsible for mapping
* between hwirq number and linux irq number.
* @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
* @msi_desc: MSI descriptor
* @affinity: IRQ affinity on SMP
*
* The fields here need to overlay the ones in irq_desc until we
* cleaned up the direct references and switched everything over to
* irq_data.
*/
struct irq_data {
unsigned int irq;
unsigned long hwirq;
unsigned int node;
unsigned int state_use_accessors;
struct irq_chip *chip;
struct irq_domain *domain;
void *handler_data;
void *chip_data;
struct msi_desc *msi_desc;
cpumask_var_t affinity;
}; /**
* struct irq_desc - interrupt descriptor
* @irq_data: per irq and chip data passed down to chip functions
* @kstat_irqs: irq stats per cpu
* @handle_irq: highlevel irq-events handler
* @preflow_handler: handler called before the flow handler (currently used by sparc)
* @action: the irq action chain
* @status: status information
* @core_internal_state__do_not_mess_with_it: core internal status information
* @depth: disable-depth, for nested irq_disable() calls
* @wake_depth: enable depth, for multiple irq_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_hint: hint to user space for preferred irq affinity
* @affinity_notify: context for notification of affinity changes
* @pending_mask: pending rebalanced interrupts
* @threads_oneshot: bitfield to handle shared oneshot threads
* @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 {
struct irq_data irq_data;
unsigned int __percpu *kstat_irqs;
irq_flow_handler_t handle_irq;
#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
irq_preflow_handler_t preflow_handler;
#endif
struct irqaction *action; /* IRQ action list */
unsigned int status_use_accessors;
unsigned int core_internal_state__do_not_mess_with_it;
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;
u64 random_ip;
raw_spinlock_t lock;
struct cpumask *percpu_enabled;
#ifdef CONFIG_SMP
const struct cpumask *affinity_hint;
struct irq_affinity_notify *affinity_notify;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_t pending_mask;
#endif
#endif
unsigned long threads_oneshot;
atomic_t threads_active;
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
int parent_irq;
struct module *owner;
const char *name;
} ____cacheline_internodealigned_in_smp;
--EOF--
Linux中断子系统:级联中断控制器驱动的更多相关文章
- linux中断子系统:中断号的映射与维护初始化mmap过程
本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前沿: 好久好久没有静下心来整理一些东西了 ...
- 【原创】Linux中断子系统(一)-中断控制器及驱动分析
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- Linux输入子系统详解
input输入子系统框架 linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...
- Linux kernel的中断子系统之(五):驱动申请中断API
返回目录:<ARM-Linux中断系统>. 总结:二重点区分了抢占式内核和非抢占式内核的区别:抢占式内核可以在内核空间进行抢占,通过对中断处理进行线程化可以提高Linux内核实时性. 三介 ...
- Linux kernel中断子系统之(五):驱动申请中断API【转】
转自:http://www.wowotech.net/linux_kenrel/request_threaded_irq.html 一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的 ...
- Linux kernel的中断子系统之(一):综述
返回目录:<ARM-Linux中断系统>. 总结: 一从作为一名驱动工程师角度看,用好中断需要正确认识request_threaded_irq/request_irq关系.中断临界区保护. ...
- Linux kernel的中断子系统之(三):IRQ number和中断描述符
返回目录:<ARM-Linux中断系统>. 总结: 二描述了中断处理示意图,以及关中断.开中断,和IRQ number重要概念. 三介绍了三个重要的结构体,irq_desc.irq_dat ...
- Linux kernel的中断子系统之(二):IRQ Domain介绍
返回目录:<ARM-Linux中断系统>. 总结:一.二概述了软硬件不同角度的IRQ Number和HW Interrupt ID,这就需要他们之间架个桥梁. 三介绍了架设这种桥梁的几种方 ...
- Linux kernel的中断子系统之(四):High level irq event handler
返回目录:<ARM-Linux中断系统>. 总结:从架构相关的汇编处理跳转到Machine/控制器相关的handle_arch_irq,generic_handle_irq作为High l ...
随机推荐
- 高性能JavaScript读书笔记
零.组织结构 根据引言,作者将全书划分为四个部分: 一.页面加载js的最佳方式(开发前准备) 二.改善js代码的编程技巧(开发中) 三.构建与部署(发布) 四.发布后性能检测与问题追踪(线上问题优化) ...
- JS Cookie丢失问题
JS Cookie丢失问题 前些天有人问我vue中使用proxy发送请求,为什么请求时cookie丢失,首先说一下我对cookie的理解: 1.cookie在正常情况下是会在每次请求时自动携带, 2. ...
- OkHttp拆解之调用流程图
- 关于SSDT
百度上比较好的解释是:SSDT的全称是System Services Descriptor Table,系统服务描述符表.这个表就是一个把ring3的Win32 API和ring0的内核API联系起来 ...
- CSS3之background-origin
1.属性简介 background-origin:border|content|padding|!important border:从border区域开始显示背景: content:从content区 ...
- java中JDBC报错(一)
java中JDBC报错(一) 1.具体报错如下 com.mysql.jdbc.MySqlDataTruncation:Data truncation:Data too long for column ...
- Excel 2010高级应用-条状图(五)
Excel 2010高级应用-条状图(五) 基本操作如下: 1.新建一个Excel空白文档,并命名条状图 2.单击"插入",找到条状图的样图 3.选择其中一种类型的条状图样图,在空 ...
- [RPC Fault faultString="Cannot invoke method 'saveOrUpdate'." faultCode="Server.ResourceUnavailable"
1.错误描述 [RPC Fault faultString="Cannot invoke method 'saveOrUpdate'." faultCode="Serve ...
- TCP粘包、拆包及解决
TCP属于传输层的协议,传输层除了有TCP协议外还有UDP协议.那么UDP是否会发生粘包或拆包的现象呢?答案是不会.UDP是基于报文发送的,从UDP的帧结构可以看出,在UDP首部采用了16bit来指示 ...
- hdu2262 Where is the canteen
Where is the canteen Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...