1、irq_set_chained_handler_and_data一般用来设置中断级联处理函数(一般GPIO控制器驱动上用的多,需要级联判断具体哪个gpio触发的中断,一组gpio共享一个硬件中断号)
函数声明
void irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle, void *data)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
if (!desc)
return;
desc->irq_common_data.handler_data = data;
__irq_do_set_handler(desc, handle, 1, NULL);//这函数里面赋值
irq_put_desc_busunlock(desc, flags);
}
irq_set_chained_handler_and_data直接赋值 desc->handle_irq = handle;
中断来的时候会调用以下函数
int generic_handle_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
if (!desc)
return -EINVAL;
generic_handle_irq_desc(desc);
return 0;
}
static inline void generic_handle_irq_desc(struct irq_desc *desc)
{
desc->handle_irq(desc);//这里直接调用通过该函数注册的中断处理函数
}
2 devm_request_irq注册中断处理函数治最后通过action->handler(irq, action->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);
}
调用request_threaded_irq赋值 action->handler = handler;
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)
{
struct irqaction *action;
struct irq_desc *desc;
int retval;
<...>
action->handler = handler;//赋值中断处理函数
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;
<...>
}
//中断发生的时候调用的地方
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
irqreturn_t retval = IRQ_NONE;
unsigned int irq = desc->irq_data.irq;
struct irqaction *action;
//通过irq_desc找到对应action
for_each_action_of_desc(desc, action) {
irqreturn_t res;
trace_irq_handler_entry(irq, action);
res = action->handler(irq, action->dev_id);//执行中断处理函数
trace_irq_handler_exit(irq, action, res);
if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
irq, action->handler))
local_irq_disable();
switch (res) {
case IRQ_WAKE_THREAD:
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
__irq_wake_thread(desc, action);
/* Fall through to add to randomness */
case IRQ_HANDLED:
*flags |= action->flags;
break;
default:
break;
}
retval |= res;
}
return retval;
}
这里直接调用devm_request_irq注册中断处理函数,第一个gpio控制器调用的desc->handle_irq(desc)这个就用中断控制器注册的函数handle_fasteoi_irqs
gpio中断处理函数中调用的handle_edge_irq是在初始化的时候注册struct irq_chip指定的irq_set_type函数设置desc->handle_irq,request_irq的时候会调用该函数设置desc->handle_irq
static struct irq_chip pl061_irqchip = {
.name = "pl061",
.irq_ack = pl061_irq_ack,
.irq_mask = pl061_irq_mask,
.irq_unmask = pl061_irq_unmask,
.irq_set_type = pl061_irq_type,
.irq_set_wake = pl061_irq_set_wake,
};
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061_gpio *chip = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(d);
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
u8 bit = BIT(offset);
《。。。。irq_set_handler_locked(d, handle_edge_irq);通过该函数赋值》
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
/* Disable edge detection */
gpioibe &= ~bit;
/* Enable level detection */
gpiois |= bit;
/* Select polarity */
if (polarity)
gpioiev |= bit;
else
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_level_irq);
dev_dbg(gc->parent, "line %d: IRQ on %s level\n",
offset,
polarity ? "HIGH" : "LOW");
} else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
/* Disable level detection */
gpiois &= ~bit;
/* Select both edges, setting this makes GPIOEV be ignored */
gpioibe |= bit;
irq_set_handler_locked(d, handle_edge_irq);
dev_dbg(gc->parent, "line %d: IRQ on both edges\n", offset);
} else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
(trigger & IRQ_TYPE_EDGE_FALLING)) {
bool rising = trigger & IRQ_TYPE_EDGE_RISING;
/* Disable level detection */
gpiois &= ~bit;
/* Clear detection on both edges */
gpioibe &= ~bit;
/* Select edge */
if (rising)
gpioiev |= bit;
else
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_edge_irq);
dev_dbg(gc->parent, "line %d: IRQ on %s edge\n",
offset,
rising ? "RISING" : "FALLING");
} else {
/* No trigger: disable everything */
gpiois &= ~bit;
gpioibe &= ~bit;
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_bad_irq);
dev_warn(gc->parent, "no trigger selected for line %d\n",
offset);
}
《。。。。》
}
中断流处理程序(无论是预定义的还是架构特定的)由架构在启动期间或设备初始化期间分配给 特定中断。
handle_level_irq()
handle_edge_irq()
handle_fasteoi_irq()
handle_simple_irq()
handle_percpu_irq()
handle_edge_eoi_irq()
handle_bad_irq()
电平触发型IRQ流处理器
handle_level_irq为电平触发型的中断提供了一个通用实现。
实现的控制流如下(简化摘录):
desc->irq_data.chip->irq_mask_ack();
handle_irq_event(desc->action);
desc->irq_data.chip->irq_unmask();
默认的需回应IRQ流处理器
handle_fasteoi_irq为中断提供了一个通用的实现,它只需要在处理程序的末端有一个EOI。
实现的控制流如下(简化摘录):
handle_irq_event(desc->action);
desc->irq_data.chip->irq_eoi();
默认的边沿触发型IRQ流处理器
handle_edge_irq为边沿触发型的中断提供了一个通用的实现。
实现的控制流如下(简化摘录):
if (desc->status & running) {
desc->irq_data.chip->irq_mask_ack();
desc->status |= pending | masked;
return;
}
desc->irq_data.chip->irq_ack();
desc->status |= running;
do {
if (desc->status & masked)
desc->irq_data.chip->irq_unmask();
desc->status &= ~pending;
handle_irq_event(desc->action);
} while (status & pending);
desc->status &= ~running;
默认的简单型IRQ流处理器
handle_simple_irq提供了一个简单型中断的通用实现。(简单型的流处理程序不调用任何处理程序/芯片基元。)