【Linux 驱动】IMX6ULL interrupt驱动

news2025/4/19 11:28:07

1. GIC驱动初始化

start_kernel (init\main.c)
    init_IRQ (arch\arm\kernel\irq.c)
        irqchip_init (drivers\irqchip\irqchip.c)
            of_irq_init (drivers\of\irq.c)
                desc->irq_init_cb = match->data;

                ret = desc->irq_init_cb(desc->dev,
                            desc->interrupt_parent);

 

 2. 数据结构分析

2.1 irq_desc

/**
 * 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
 * @threads_handled:	stats field for deferred spurious detection of threaded handlers
 * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers
 * @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
 * @nr_actions:		number of installed actions on this descriptor
 * @no_suspend_depth:	number of irqactions on a irq descriptor with
 *			IRQF_NO_SUSPEND set
 * @force_resume_depth:	number of irqactions on a irq descriptor with
 *			IRQF_FORCE_RESUME set
 * @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;
	atomic_t		threads_handled;
	int			threads_handled_last;
	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_PM_SLEEP
	unsigned int		nr_actions;
	unsigned int		no_suspend_depth;
	unsigned int		cond_suspend_depth;
	unsigned int		force_resume_depth;
#endif
#ifdef CONFIG_PROC_FS
	struct proc_dir_entry	*dir;
#endif
	int			parent_irq;
	struct module		*owner;
	const char		*name;
}

 2.2 irq_data

/**
 * struct irq_data - per irq and irq chip data passed down to chip functions
 * @mask:		precomputed bitmask for accessing the chip registers
 * @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.
 * @parent_data:	pointer to parent struct irq_data to support hierarchy
 *			irq_domain
 * @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 {
	u32			mask;
	unsigned int		irq;    /* 中断编号 */
	unsigned long		hwirq;    /* 硬件中断编号 */
	unsigned int		node;
	unsigned int		state_use_accessors;
	struct irq_chip		*chip;    /* 底层的中断操作函数 */
	struct irq_domain	*domain;    /* 负责irq与hwirq之间的转换 */
#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	struct irq_data		*parent_data;
#endif
	void			*handler_data;
	void			*chip_data;
	struct msi_desc		*msi_desc;
	cpumask_var_t		affinity;
};

2.2 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_calc_mask:	Optional function to set irq_data.mask for special cases
 * @irq_print_chip:	optional to print special chip info in show_interrupts
 * @irq_request_resources:	optional to request resources before calling
 *				any other callback related to this irq
 * @irq_release_resources:	optional to release resources acquired with
 *				irq_request_resources
 * @irq_compose_msi_msg:	optional to compose message content for MSI
 * @irq_write_msi_msg:	optional to write message content for MSI
 * @irq_get_irqchip_state:	return the internal state of an interrupt
 * @irq_set_irqchip_state:	set the internal state of a interrupt
 * @flags:		chip specific flags
 */
struct irq_chip {
	struct device	*parent_device;     //指向父设备
	const char	*name;      //  /proc/interrupts中显示的名字
	unsigned int	(*irq_startup)(struct irq_data *data);  //启动中断,如果设置成NULL,则默认为enable
	void		(*irq_shutdown)(struct irq_data *data);     //关闭中断,如果设置成NULL,则默认为disable
	void		(*irq_enable)(struct irq_data *data);   //中断使能,如果设置成NULL,则默认为chip->unmask
	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); //在SMP中设置CPU亲和力
	int		(*irq_retrigger)(struct irq_data *data);    //重新发送中断到CPU
	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_calc_mask)(struct irq_data *data);

	void		(*irq_print_chip)(struct irq_data *data, struct seq_file *p);
	int		(*irq_request_resources)(struct irq_data *data);
	void		(*irq_release_resources)(struct irq_data *data);

	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

	int		(*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state);
	int		(*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state);

	int		(*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info);

	void		(*ipi_send_single)(struct irq_data *data, unsigned int cpu);
	void		(*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);

	unsigned long	flags;
};

struct irq_domain {
	struct list_head link;  //用于添加到全局链表irq_domain_list中
	const char *name;   //IRQ domain的名字
	const struct irq_domain_ops *ops;   //IRQ domain映射操作函数集
	void *host_data;    //在GIC驱动中,指向了irq_gic_data
	unsigned int flags; 
	unsigned int mapcount;  //映射中断的个数

	/* Optional data */
	struct fwnode_handle *fwnode;
	enum irq_domain_bus_token bus_token;
	struct irq_domain_chip_generic *gc;
#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	struct irq_domain *parent;  //支持级联的话,指向父设备
#endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
	struct dentry		*debugfs_file;
#endif

	/* reverse map data. The linear map gets appended to the irq_domain */
	irq_hw_number_t hwirq_max;  //IRQ domain支持中断数量的最大值
	unsigned int revmap_direct_max_irq;
	unsigned int revmap_size;   //线性映射的大小
	struct radix_tree_root revmap_tree; //Radix Tree映射的根节点
	unsigned int linear_revmap[];   //线性映射用到的查找表
};

struct irq_domain_ops {
	int (*match)(struct irq_domain *d, struct device_node *node,
		     enum irq_domain_bus_token bus_token);      // 用于中断控制器设备与IRQ domain的匹配
	int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec,
		      enum irq_domain_bus_token bus_token);
	int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);    //用于硬件中断号与Linux中断号的映射
	void (*unmap)(struct irq_domain *d, unsigned int virq);
	int (*xlate)(struct irq_domain *d, struct device_node *node,
		     const u32 *intspec, unsigned int intsize,
		     unsigned long *out_hwirq, unsigned int *out_type);     //通过device_node,解析硬件中断号和触发方式

#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	/* extended V2 interfaces to support hierarchy irq_domains */
	int (*alloc)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs, void *arg);
	void (*free)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs);
	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
	int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
			 unsigned long *out_hwirq, unsigned int *out_type);
#endif
};

2.3 irq_domain

/**
 * struct irq_domain - Hardware interrupt number translation object
 * @link: Element in global irq_domain list.
 * @name: Name of interrupt domain
 * @ops: pointer to irq_domain methods
 * @host_data: private data pointer for use by owner.  Not touched by irq_domain
 *             core code.
 * @flags: host per irq_domain flags
 *
 * Optional elements
 * @of_node: Pointer to device tree nodes associated with the irq_domain. Used
 *           when decoding device tree interrupt specifiers.
 * @gc: Pointer to a list of generic chips. There is a helper function for
 *      setting up one or more generic chips for interrupt controllers
 *      drivers using the generic chip library which uses this pointer.
 * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
 *
 * Revmap data, used internally by irq_domain
 * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
 *                         support direct mapping
 * @revmap_size: Size of the linear map table @linear_revmap[]
 * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
 * @linear_revmap: Linear table of hwirq->virq reverse mappings
 */
struct irq_domain {
	struct list_head link;
	const char *name;
	const struct irq_domain_ops *ops;
	void *host_data;
	unsigned int flags;

	/* Optional data */
	struct device_node *of_node;
	struct irq_domain_chip_generic *gc;
#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	struct irq_domain *parent;
#endif

	/* reverse map data. The linear map gets appended to the irq_domain */
	irq_hw_number_t hwirq_max;
	unsigned int revmap_direct_max_irq;
	unsigned int revmap_size;
	struct radix_tree_root revmap_tree;
	unsigned int linear_revmap[];
};

2.4 irq_domain_ops

IRQ domain用于将硬件的中断号,转换成Linux系统中的中断号(virtual irq, virq),来张图:

  • 每个中断控制器都对应一个IRQ Domain;
  • 中断控制器驱动通过irq_domain_add_*()接口来创建IRQ Domain;
  • IRQ Domain支持三种映射方式:linear map(线性映射),tree map(树映射),no map(不映射);
    1. linear map:维护固定大小的表,索引是硬件中断号,如果硬件中断最大数量固定,并且数值不大,可以选择线性映射;
    2. tree map:硬件中断号可能很大,可以选择树映射;
    3. no map:硬件中断号直接就是Linux的中断号;

三种映射的方式如下图:

/**
 * struct irq_domain_ops - Methods for irq_domain objects
 * @match: Match an interrupt controller device node to a host, returns
 *         1 on a match
 * @map: Create or update a mapping between a virtual irq number and a hw
 *       irq number. This is called only once for a given mapping.
 * @unmap: Dispose of such a mapping
 * @xlate: Given a device tree node and interrupt specifier, decode
 *         the hardware irq number and linux irq type value.
 *
 * Functions below are provided by the driver and called whenever a new mapping
 * is created or an old mapping is disposed. The driver can then proceed to
 * whatever internal data structures management is required. It also needs
 * to setup the irq_desc when returning from map().
 */
struct irq_domain_ops { irq_desc
    /*********************(树映射)**********************/
	int (*match)(struct irq_domain *d, struct device_node *node);    
	int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);    /* 创建虚拟中断号与硬件中断号的映射关系 */
	void (*unmap)(struct irq_domain *d, unsigned int virq);
	int (*xlate)(struct irq_domain *d, struct device_node *node,
		     const u32 *intspec, unsigned int intsize,
		     unsigned long *out_hwirq, unsigned int *out_type);    /* 从设备树中获取hwirq 与 irq type */

    /*******************(线性映射)*****************/
#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	/* extended V2 interfaces to support hierarchy irq_domains */
	int (*alloc)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs, void *arg);
	void (*free)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs);
	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
#endif
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2094790.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(已开源-CVPR 2024)YOLO-World: Real-Time Open-Vocabulary Object Detection

169期《YOLO-World Real-Time Open-Vocabulary Object Detection》 You Only Look Once (YOLO) 系列检测模型是目前最常用的检测模型之一。然而,它们通常是在预先定义好的目标类别上进行训练,很大程度上限制了它们在开放场景中的可用性。为了解决这一限制…

医学领域实现基于大模型和本地知识库的智能问答系统

在医学领域实现一个基于大模型和本地知识库的智能问答系统,需要考虑医学领域的专业知识和术语。我们将构建一个简单版本的系统,该系统能够处理医学问题,并且能够从本地知识库中检索相关信息来生成答案。 技术栈: 自然语言处理模型…

编译LineageOS模拟器镜像,导出到AndroidStudio

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/ 源码下载 LineageOS官网:https://lineageos.org/ LineageOS源码 github 地址:https://github.com/LineageOS/android LineageOS源码国…

讯鹏科技智慧公厕专业供应商,解读智慧公厕有哪些奥秘

在当今科技日新月异的时代,讯鹏科技作为智慧公厕专业供应商,以其先进的技术和创新的解决方案,为人们带来了全新的公共卫生体验。那么,智慧公厕究竟有哪些奥秘呢?让我们一同解读。 一、智慧公厕硬件 1. 环境监测传感器&…

06:【江科大stm32】:定时器输入捕获功能

定时器输入捕获功能 1、通过定时器的输入捕获功能测量PWM波的频率2、PWMI模式测量频率和占空比 1、通过定时器的输入捕获功能测量PWM波的频率 定时器标准库相关的编程接口: ①PWM.c文件的代码如下: /*通过定时器TIM2生成一个分辨率为10us,频率为1KHz的…

八皇后问题代码实现(java,递归)

简介:著名的八皇后问题是由棋手马克斯贝瑟尔在1848年提出来的,要求在 8 8 的棋盘上摆放8个皇后,使”皇后“们不能互相攻击 ,当任意两个皇后都不处于同一行、同一列或同一条斜线上时就不会相互攻击,即为目标解。 说明…

C语言中的预处理指令的其中之一——#line

目录 开头1.什么是预处理指令——#line?2.预处理指令——#line的实际应用改__FILE__宏改__LINE__宏改__FILE__宏和__LINE__宏…… 下一篇博客要说的东西 开头 大家好,我叫这是我58。今天,我们要学一下关于C语言中的预处理指令的其中之一——#line的一些…

4-6 使用bios 中断 显示字符

1 显示的逻辑 bios 首先通过中断,访问到 最前面的中断向量表,然后 通过中断向量表然后 访问到具体的 bios 的函数,这些函数是bios 自带的,具体的位置 , 我也不知道。只知道有这个函数。 3 显示的原理 ; 主要…

纯蓝图事件

一、创建事件分发器 1、蓝图中可直接添加Event Dispatchers事件分发器 2、还可以设置事件的传递参数 3、直接将创建好的事件分发器拖入EventGraph中会显示出Call、Bind、UnBind、Assign等方法 二、广播事件通知 三、订阅、取消订阅事件通知

算法数学加油站:一元高斯分布(正态分布)Python精美科研绘图(PDF、CDF、PPF、ECDF曲线;QQ图)

这类博客针对算法学习时可能遇到的数学知识补充,但不会太多废话,主要是公式结合Python代码精美绘图理解! 本期重点: 参数:期望、标准差曲线:概率密度曲线PDF、累积概率密度函数CDF、百分点函数PPF应用&am…

14:LDO电源模块的布局

1.器件要和边框相聚5mm的距离作为工艺边,工艺边可以布线,但不能摆放器件 LDO布局原则 ①输出靠近负载端 和DCDC布局一样

Springcloud微服务合并打包,重复路径引发的血案

你好,我是柳岸花开。 在微服务架构的世界里,各种服务之间的接口调用犹如人类的神经系统,构成了整个系统的核心。然而,正是这些看似简单的接口路径,可能会引发一场惊天血案。今天,我们就来揭开一起因“重复路…

Git高手必备:掌握这些指令,轻松玩转版本控制(一)

前言 注:本文下的除非特殊声明,否则一律不作为实际加号,仅表示连接 所有的版本控制系统,只能跟踪文本文件的改动比如txt文件,网页,所有程序的代码等,能清楚的知道改动了什么。但是类似于图片、…

嵌入式全栈开发学习笔记---Linux系统编程(文件编程)

目录 Linux文件概述 系统IO 创建文件creat() 打开文件open() 写文件write() 读文件read() 文件指针---lseek() 系统IO拷贝 标准IO 标准IO和系统IO的区别 缓冲区的分类 行缓存测试 打开文件fopen() 写文件fwrite() 读文件read() 标准IO拷贝 标准IO和系统IO的效…

实践:根据时区显示时间

背景 在数据库中存储时间,不会自动对时区进行处理,要想针对不同时区作时间显示的适配,需要在程序中做适配,本文即为解决这一问题的实践案例。 数据库存 UTC 时间 插入记录时,使用 datetime.utcnow()获取当前 utc 时…

MFCC C++实现与Python库可视化对比

MFCC C实现与Python库对比 MFCC理论基础 在音频、语音信号处理领域,我们需要将信号转换成对应的语谱图(spectrogram),将语谱图上的数据作为信号的特征。语谱图的横轴x为时间,纵轴y为频率,(x,y)对应的数值代表在时间x时频率y的幅…

动作损失 ​ 的定义

动作损失 La是在弱监督时间动作定位(Weakly-Supervised Temporal Action Localization, WSTAL)任务中用于优化模型的一种损失函数。它的主要目标是确保模型能够准确地预测视频中动作发生的时间段,并对视频级别标签进行良好的分类。下面是对动…

【Python系列】 Python 中的枚举使用

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

PyTorch中,动态调整学习率(Learning Rate Scheduling),也可以根据损失函数的损失数值自动调整学习率

在PyTorch中,动态调整学习率(Learning Rate Scheduling)是一种常用的技术, 用于在训练过程中根据一定的策略调整学习率,以优化模型的训练效果和收敛速度。以下是一些常见的学习率调整策略: 1. **固定步长…

金融科技初创企业建设指南

金融科技领域正以前所未有的速度发展,重塑我们与金钱和金融服务的互动方式。随着我们迈向 2025 年,尖端技术的融合、不断变化的消费者期望以及全球对金融包容性的推动正在创造前所未有的机遇。创新者现在有独特的机会在金融科技领域留下自己的印记。 以下几个因素使得即将到…