Linux中断管理

1.  中断控制器注册

Linu内核支持多个中断控制器(GIC, gpio),可以用irq_domain来表示一个中断控制器,以ARM GICv3中断控制器来说明注册流程.

1.1 dts中声明

属性" interrupt-controller;",已经定义GIC寄存器地址.#interrupt-cells定义解析中断号,中断类型,中断触发类型的参数个数.

intc: interrupt-controller@9bc0000 {
        compatible = "arm,gic-v3";
        reg = <0x9bc0000 0x10000>,       /* GICD */
              <0x9c00000 0x100000>;      /* GICR * 4 */
        #interrupt-cells = <3>;
        interrupt-controller;  
    };

1.2 GICv3驱动实现

路径:

drivers/irqchip

kernel/irq

驱动中定义中断控制器初始化函数:

IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);

最终会在irqchip_init中调用gic_of_init.  一个中断控制器,需要实现irq_domain_ops和irq_chip函数集

最终调用irq_domain_add添加到系统中.

所有的中断控制都要实现下面两个函数集合

struct irq_chip gic_chip = {
    .name            = "GICv3",
    .irq_mask        = gic_mask_irq, //disable irq
    .irq_unmask        = gic_unmask_irq,//enable irq
    .irq_eoi        = gic_eoi_irq,//当Linux处理完一个中断时,调用eoi告诉GIC中断控制器,中断处理完成.
    .irq_set_type        = gic_set_type,//中断触发类型
    .irq_retrigger        = gic_retrigger,
    .irq_set_affinity    = gic_set_affinity,//设置中断亲和力,也就是绑定中断到某个CPU
    .irq_disable        = gic_disable_irq,
    .irq_set_wake        = gic_set_wake,//设置中断能唤醒系统
    .irq_get_irqchip_state    = gic_irq_get_irqchip_state,
    .irq_set_irqchip_state    = gic_irq_set_irqchip_state,
    .flags            = IRQCHIP_SET_TYPE_MASKED,
};

static const struct irq_domain_ops gic_irq_domain_ops = {
    .translate = gic_irq_domain_translate,//用于解析中断irq号,中断类型,中断触发类型
    .alloc = gic_irq_domain_alloc,// request_irq时,用于设置irq处理函数
    .free = gic_irq_domain_free,
};

GIC中断控制器,IRQ可以分为三种类型

SGI :用于CPU IPI 核间通信,irq0- irq15

PPI : percpu 私有中断,irq16-irq31, 每个中断,只会发送给固定的CPU

SPI ; irq32-irq1024  由中断控制器选择一个CPU执行.

GIC中断控制内部框架

根据中断类型不同,处理函数也不一样:

SGI: irq_desc->handle_irq = handle_percpu_devid_irq

PPI : irq_desc->handle_irq = handle_percpu_devid_irq

SPI : irq_desc->handle_irq = handle_fasteoi_irq

2. 中断的注册

2.1 获取中断号

  dts中,一般有如下定义:

   interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>

在驱动中获取irq号的函数:int of_irq_get(struct device_node *dev, int index)

返回irq的同时,会调用irq_domain 中的alloc和tranlate函数,与中断控制器关联起来,具体就不再分析.

2.2 中断注册

现在内核都实行中断线程化,注册函数:

nt request_threaded_irq(unsigned int irq, irq_handler_t handler,
             irq_handler_t thread_fn, unsigned long irqflags,
             const char *devname, void *dev_id)

hanlder是在关闭本地CPU中断下执行, 返回IRQ_WAKE_THREAD表示唤醒中断对应的线程。

thread_fn在实时线程中执行,本地中断打开,线程处理函数为irq_thread,如果在irqflags中标记中断为IRQF_ONESHOT,那么thread_fn执行完,中断才会unmask.

hanlder和thread_fn必须实现一个

3. 中断的处理流程

ARM32 中断处理流程

在进入软件处理之前,CPU硬件做了如下工作

1. 保存当前CPSR到SPSR_irq寄存器,保存在lr到lr_irq寄存器

2. 修改CPSR的cpu模式,然后cpu进入IRQ 模式,并同时修改I/F标志为,关闭中断

3. 自动把PC指向中断向量表

软件进入中断处理时,需要保存所有寄存器到堆栈,在退出时,要从堆栈恢复到寄存器.

软件处理流程

vector_irq->__irq_svc->irq_handler->handle_arch_irq(gic_handle_irq)

最终调用到GIC 控制器中断处理函数gic_handle_irq,在gic_handle_irq之前都是汇编代码中处理

PPI和SPI中断:gic_handle_irq->handle_domain_irq->generic_handle_irq->generic_handle_irq_desc->hander_irq

SGI中断:gic_handle_irq->handle_IPI->处理各种IPI中断(0-15)

在中断处理函数中使用current->comm一般是被irq抢占的进程名,因为在__irq_svc中,通过修改CPSR寄存器,强制 把CPU模式从IRQ mode切换到SVC mode,也就是中断执行时,都是使用抢占线程的堆栈.

ARM64中断处理:

el1_irq->irq_handler->handle_arch_irq 这里跟arm32处理一致.

arm64中,为每个cpu分配一个irq stack,大小为THREAD_SIZE,这样,irq不使用当前被抢占的进程堆栈.

具体可以看irq_handle的汇编实现,把task stack切换为irq stack .

4. 中断相关函数

使能/禁止本地cpu中断,
local_irq_enable()
local_irq_disable()
使能/禁止本地cpu中断,并同时保存和恢复本地cpu 中断标志,
local_irq_save()
local_irq_restore()
判断本地cpu中断状态
irqs_disabled()
这几个函数都是直接操作CPSR(arm32)/DAIF(arm64)寄存器的中断标志位

local_bh_enable()/local_bh_disable() //软中断控制函数

void disable_irq(unsigned int irq)//等待thread_fn执行完成,然后mask 中断
void disable_irq_nosync(unsigned int irq)//异步mask中断
void enable_irq(unsigned int irq)//umask中断.

in_irq() : 判断是否在hardirq context, //在irq_enter和irq_exit中设置
in_softirq()//判断是否在softirq contex,或者中断下半部是禁止的(local_bh_disable)
in_interrupt()//判断是否在hardirq/softirq/NMI或在中断下半部是否禁止,这个状态时不能休眠的
in_task()//进程上下文,可以休眠

5 软中断实现

可以参考Linux软中断实现

 

6.调试接口

/proc/irq
/proc/interrupts
/d/irq_domain_mapping

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值