From 173ab24350c2462fecad6e517ec3e5678b14aaa6 Mon Sep 17 00:00:00 2001 From: "lion.chan" Date: Fri, 22 Apr 2022 00:19:40 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=B8=AD=E6=96=AD=E5=A4=84?= =?UTF-8?q?=E7=90=86=E6=8E=A5=E5=8F=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: lion.chan --- Chapter8_SOC_与_Linux/8.10_中断与时钟.md | 122 ++++++++++++++++++++++- 1 file changed, 118 insertions(+), 4 deletions(-) diff --git a/Chapter8_SOC_与_Linux/8.10_中断与时钟.md b/Chapter8_SOC_与_Linux/8.10_中断与时钟.md index 9ce61f7..b5f8cb3 100644 --- a/Chapter8_SOC_与_Linux/8.10_中断与时钟.md +++ b/Chapter8_SOC_与_Linux/8.10_中断与时钟.md @@ -69,13 +69,62 @@ Err: 0 ## Linux 中断编程 +获取中断信息: + ```cpp /** + * of_irq_get - Decode a node's IRQ and return it as a Linux irq number + * @file drivers/of/irq.c + * @dev: pointer to device tree node + * @index: zero-based index of the irq + * + * Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain + * is not yet created. + * + */ +int of_irq_get(struct device_node *dev, int index); + +/** + * platform_get_irq - get an IRQ for a device + * @file drivers/base/platform.c + * @dev: platform device + * @num: IRQ number index + * @brief 包含 of_irq_get() + */ +int platform_get_irq(struct platform_device *dev, unsigned int num); +``` + +注册中断处理程序: + +```cpp +/** + * @file kernel/irq/manage.c * @param irq 要申请的硬件中断号。 - * @param handler 是向系统登记的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数。 + * @param handler 是向系统登记的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数。为 NULL 时使用默认的处理,这个相当于中断的上半段。 + * @param thread_fn 中断发生时,如果 handler 为 NULL,就直接将 thread_fn 扔到内核线程中去执行。 * @param irqflags 是中断处理的属性 - * SA_INTERRUPT:则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽; - * SA_SHIRQ:表示多个设备共享中断 + * IRQF_SHARED - allow sharing the irq among several devices + * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur + * IRQF_TIMER - Flag to mark this interrupt as timer interrupt + * IRQF_PERCPU - Interrupt is per cpu + * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing + * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is + * registered first in an shared interrupt is considered for + * performance reasons) + * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. + * Used by threaded interrupts which need to keep the + * irq line disabled until the threaded handler has been run. + * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend. Does not guarantee + * that this interrupt will wake the system from a suspended + * state. See Documentation/power/suspend-and-interrupts.txt + * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set + * IRQF_NO_THREAD - Interrupt cannot be threaded + * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device + * resume time. + * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this + * interrupt handler after suspending interrupts. For system + * wakeup devices users need to implement wakeup detection in + * their interrupt handlers. * @param devname An ascii name for the claiming device. 使用cat /proc/interrupt 可以查看中断程序名字。 * @param dev_id 在中断共享时会用到,一般设置为这个设备的设备结构体或者 NULL。 * 注册共享中断时不能为NULL,因为卸载时需要这个做参数,避免卸载其它中断服务函数。 @@ -85,6 +134,10 @@ Err: 0 * -EBUSY:表示中断已经被占用且不能共享。 * @brief 申请 IRQ */ +int request_threaded_irq(unsigned int irq, irq_handler_t handler, + irq_handler_t thread_fn, unsigned long irqflags, + const char *devname, void *dev_id); + int request_irq(unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long irqflags, @@ -102,7 +155,68 @@ void free_irq(unsigned int irq, void *dev_id); 2. 如果采用共享中断方式,所有使用 request_irq 注册的中断时 flags 都要加上 IRQF_SHARED 这个共享参数,表明其实共享中断。 3. 对于共享中断,每一个申请共享的中断,申请和释放时都要给 request_irq 和 free_irq 的最后一个参数 dev 和 id_dev 传递一个指针,将来来中断的时候,将会传递这个指针到每个中断函数中,而中断函数就可以用来区分到底是不是它的中断,是则执行,不是则判断后直接退出中断处理函数即可。同时在 free_irq 时也会使用这个指针,查找这个贡献中断链表上了所有注册的 irq,只有在这个指针能对的上的时候,才会删除它所在的链表节点(如果是最后一个节点还要释放该中断)。所在在编写中断处理函数时该指针必须是唯一的,通常传的这个指针是该设备结构体的地址,这个每个设备不一样所以肯定是唯一的。 -下列 3 个函数用于禁能/使能一个中断源。 +对于资源管理 Linux 内核提供了一组 Devm API。Devm APIs 是一组便捷易用的接口,通过该接口申请的内核资源是跟设备(device)有关的,在设备(device)被 detached 或者驱动(driver)卸载(unloaded)时,会被自动释放。针对以上中断资源管理,有以下 Devm 版本的 API: + +```cpp +/** + * @file kernel/irq/devres.c + * @param dev 设备结构体。 + * @param irq 要申请的硬件中断号。 + * @param handler 是向系统登记的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数(运行于中断上下文), + 函数需要判断是否为自身中断,若是则关闭自身中断并返回 IRQ_WAKE_THREAD。 + 为 NULL 时使用默认的处理。 + * @param thread_fn 中断发生时,如果 handler 为 NULL,thread_fn 将在默认 handler 执行完毕后以内核线程形式运行。 + * 否则待 handler 返回 IRQ_WAKE_THREAD 后以内核线程形式执行。 + * @param irqflags 是中断处理的属性 + * IRQF_SHARED - allow sharing the irq among several devices + * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur + * IRQF_TIMER - Flag to mark this interrupt as timer interrupt + * IRQF_PERCPU - Interrupt is per cpu + * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing + * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is + * registered first in an shared interrupt is considered for + * performance reasons) + * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. + * Used by threaded interrupts which need to keep the + * irq line disabled until the threaded handler has been run. + * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend. Does not guarantee + * that this interrupt will wake the system from a suspended + * state. See Documentation/power/suspend-and-interrupts.txt + * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set + * IRQF_NO_THREAD - Interrupt cannot be threaded + * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device + * resume time. + * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this + * interrupt handler after suspending interrupts. For system + * wakeup devices users need to implement wakeup detection in + * their interrupt handlers. + * @param devname An ascii name for the claiming device. 使用cat /proc/interrupt 可以查看中断程序名字。 + * @param dev_id 在中断共享时会用到,一般设置为这个设备的设备结构体或者 NULL。 + * 注册共享中断时不能为NULL,因为卸载时需要这个做参数,避免卸载其它中断服务函数。 + * @return + * 0:表示成功 + * -INVAL:表示中断号无效或处理函数指针为 NULL + * -EBUSY:表示中断已经被占用且不能共享。 + * @brief 申请 IRQ + */ +extern int __must_check +devm_request_threaded_irq(struct device *dev, unsigned int irq, + irq_handler_t handler, irq_handler_t thread_fn, + unsigned long irqflags, const char *devname, + void *dev_id); + +static inline int __must_check +devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, + unsigned long irqflags, const char *devname, void *dev_id) +{ + return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags, + devname, dev_id); +} + +extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id); +``` + +禁能/使能中断源: ```cpp // 禁能中断源