2023.7.16 linux 中断处理

Kernel interrupt handling

中断处理函数执行时间要短,原子操作

typedef irqreturn_t (*irq_handler_t)(int, void *);    安装中断handler需要知道中断线和产生中断的设备的唯一id识别号

 

<linux/interrupt.h>

devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long irqflags, onst char *devname, void *dev_id)    注册中断handler

irqflags有以下选择,多项可以或 |

#define IRQF_SHARED 0x00000080    #共享中断线时,handler要先判断是否是本设备产生的,不是则return IRQ_NONE,正常处理完返回 IRQ_HANDLED

#define IRQF_PROBE_SHARED 0x00000100

#define IRQF_NOBALANCING 0x00000800

 

#define IRQF_IRQPOLL 0x00001000

#define IRQF_ONESHOT 0x00002000

#define IRQF_NO_SUSPEND 0x00004000

#define IRQF_FORCE_RESUME 0x00008000

#define IRQF_NO_THREAD 0x00010000

#define IRQF_EARLY_RESUME 0x000200002

#define IRQF_COND_SUSPEND 0x00040000

IRQF_NOBALANCING excludes the interrupt from IRQ balancing, which is a mechanism that consists of distributing/relocating interrupts across CPUs, with a goal of increasing performance. It is kind of preventing the CPU affinity of that IRQ from being changed. This flag may be useful to provide a flexible setup for clock source or clock event devices, to prevent misattribution of the event to the wrong core. This flag is meaningful on multi-core systems only. Kernel interrupt handling 123 

IRQF_IRQPOLL: This flag allows the implementation of an irqpoll mechanism, intended to fix interrupt problems, meaning this handler should be added to the list of known interrupt handlers that can be looked for when a given interrupt is not handled. •

IRQF_ONESHOT: Normally, the actual interrupt line being serviced is re-enabled after its hardirq handler completes, whether it awakes a threaded handler or not. This flag keeps the interrupt line disabled after the hardirq handler finishes. It must be set on threaded interrupts (we will discuss this later) for which the interrupt line must remain disabled until the threaded handler has completed, after which it will be re-enabled. •

IRQF_NO_SUSPEND does not disable the IRQ during system hibernation/ suspension. It does mean the interrupt is able to wake up the system from a suspended state. Such IRQs may be timer interrupts that may trigger and need to be handled even during system suspension. The whole IRQ line is affected by this flag such that if the IRQ is shared, every registered handler for this shared line will be executed, not only the one that installed this flag. You should avoid as much as possible using IRQF_NO_SUSPEND and IRQF_SHARED at the same time. •

IRQF_FORCE_RESUME enables the IRQ in the system resume path even if IRQF_ NO_SUSPEND is set. •

IRQF_NO_THREAD prevents the interrupt handler from being threaded. This flag overrides the kernel threadirqs command-line option that forces every interrupt to be threaded. This flag has been introduced to address the non-threadability of some interrupts (for example, timers, which cannot be threaded even when all interrupt handlers are forced to be threaded).

IRQF_TIMER marks this handler as being specific to system timer interrupts. It helps not to disable the timer IRQ during system suspension to ensure normal resumption and not thread them when full preemption (that is, PREEMPT_RT) is enabled. It is just an alias for IRQF_NO_SUSPEND | IRQF_NO_THREAD. •

IRQF_EARLY_RESUME resumes IRQ early at resume time of system core (syscore) operations instead of at device resume time. The following link points to the message of the commit introducing its support: https://lkml.org/ lkml/2013/11/20/89. •

IRQF_SHARED allows for the sharing of the interrupt line among several devices. However, each device driver that needs to share the given interrupt line must set with this flag; otherwise, the handler registration will fail. 124 Dealing with Kernel Core Helpers

We must also consider the irqreturn_t return type of interrupt handlers since it may involve further actions after the return of the handler. Possible return values are listed here: •

IRQ_NONE: On a shared interrupt line, once the interrupt occurs, the kernel IRQ core successively walks through handlers registered for this line and executes them in the order they have been registered. The driver then has the responsibility to check whether it is its device that issued the interrupt. If the interrupt does not come from its device, it must return IRQ_NONE to instruct the kernel to call the next registered interrupt handler. This return value is mostly used on shared interrupt lines since it informs the kernel that the interrupt does not come from our device. However, if 99,900 of the previous 100,000 interrupts of a given IRQ line have not been handled, the kernel then assumes that this IRQ is stuck in some manner, drops a diagnostic, and tries to turn the IRQ off. For more information on this, you can have a look at the __report_bad_irq() function in the kernel source tree. •

IRQ_HANDLED: This value should be returned if the interrupt has been handled successfully. On a threaded IRQ, this value does acknowledge the interrupt (at a controller level) without waking the thread handler up. •

IRQ_WAKE_THREAD: On a thread IRQ handler, this value must be returned by the hard-IRQ handler to wake the handler thread. In this case, IRQ_HANDLED must only be returned by that threaded handler, previously registered with devm_ request_threaded_irq(). We will discuss this later in the chapter.

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) 

void free_irq(unsigned int irq, void *dev_id)    #取消注册中断处理服务,比如在其设备拔出后

中断函数里不能睡眠或调用日程,不能从用户空间传送数据,可能引起阻塞,当中断在处理中,其他中断不能进入

Working with threaded IRQ handlers

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);  

#handler处理完返回 IRQ_WAKE_THREAD,启动线程 thread_ fn,thread_ fn处理完应该返回 IRQ_HANDLED;

硬中断处理代码越快越好,其他工作交给一个内核线程

 

Requesting a context-agnostic IRQ

int request_any_context_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev_id)

The advantage of using devm_request_any_context_irq() is that the driver does not need to care about what can be done in the IRQ handler, as the context in which the handler will run depends on the interrupt controller that provides the IRQ line. For example, for a GPIO-IRQ based device driver, if the GPIO belongs to a controller that sits on an I2C or SPI bus (GPIO access may sleep), the handler will be threaded. Otherwise (that is, the GPIO access does not sleep and is memory-mapped as it is part of the SoC), the handler will run in a hard-IRQ handler.

 if the GPIO belongs to a controller sitting on an I2C or SPI bus, the handler will be threaded. Otherwise (memory-mapped), the handler will run in a hard-IRQ context.

 

Using a workqueue to defer the bottom half

 

Locking from within an interrupt handler

posted @   杨大茄子  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示