rk3288 Linux中断系统中的重要数据结构

可以从 request_irq(include/linux/interrupt.h)函数一路分析得到

irq_desc结构体(中断描述符)

irq_desc处理流程

  1. 中断信号告知CPU流程
    外部设备1和外部设备n共享一个GPIO的中断号B,多个GPIO的中断又汇聚到GIC中,GIC去告知CPU发生了GPIO分类的中断。
  2. CPU处理中断信号流程
    CPU收到GIC的GPIO分类的中断A后,调用irq_desc[A].handle_irq去,查询哪组GPIO引起了中断,如果多个GPIO发生了中断,我想应该是都一起处理的?然后找到GPIO中中断号为B的irq_desc[B].handle_irq来处理组里的中断,这个组里包含多个GPIO触发情况,所以要去硬件里读取那个引脚发生的。最后才是调用action链表里对应的用户中断函数处理。
//include/linux/irqdesc.h
struct irq_desc {
    //...
    struct irq_data     irq_data;
    //...
    irq_flow_handler_t  handle_irq;             			//中断处理函数
    //...
    struct irqaction    *action;    /* IRQ action list */ 	//驱动注册的处理函数
    //...
    const char      *name;
} ____cacheline_internodealigned_in_smp;

irqaction结构体

当调用request_irq、request_threaded_irq注册中断处理函数时,内核就会构造一个irqaction结构体。
handler: 该指针所指向的函数就是在中断服务程序,当中断发生时内核便会调用这个指针指向的函数。
dev_id: 当存在共享中断号时,即flags = SA_SHIRQ,用以区分不同的成员。

//include/linux/interrupt.h
struct irqaction {
    irq_handler_t       handler;                //中断处理上半部函数,处理紧急事情
    void            *dev_id;                    //作用:中断处理函数执行时,可以调用dev_id,卸载函数时用dev_id区分函数
    void __percpu       *percpu_dev_id;
    struct irqaction    *next;					//是一个链表
    irq_handler_t       thread_fn;              //handler执行完毕,linux唤醒对应内核线程,里面调用thread_fn
    											//handler和thread_fn可以只一个或两个都调用。
    struct task_struct  *thread;
    struct irqaction    *secondary;
    unsigned int        irq;					//中断号
    unsigned int        flags;					//设置一些标志位,如SA_SHIRQ共享中断号
    unsigned long       thread_flags;
    unsigned long       thread_mask;
    const char      *name;
    struct proc_dir_entry   *dir;
} ____cacheline_internodealigned_in_smp;

irq_data结构体

irq_data是一个中转站,包含irq_chip指针、irq_domain指针。
irq是软件中断号,hwirq是硬件中断号。irq_desc[B]的B是软件中断号
irq和hwirq之前的转换和建立是在irq_domain中建立的。

//include/linux/irq.h
struct irq_data {
    u32         mask;
    unsigned int        irq;                //软件中断号
    unsigned long       hwirq;              //硬件中断号
    struct irq_common_data  *common;
    struct irq_chip     *chip;              //硬件函数
    struct irq_domain   *domain;            //建立irq、hwirq之间的联系
#ifdef  CONFIG_IRQ_DOMAIN_HIERARCHY
    struct irq_data     *parent_data;
#endif
    void            *chip_data;
};

irq_domain结构体

struct irq_domain与中断控制器对应,完成的工作是硬件中断号到Linux irq的映射

//include/linux/irqdomain.h
struct irq_domain {
    struct list_head link;
    const char *name;
    const struct irq_domain_ops *ops;       //各类操作函数,
                                            //xlate解析设备树中断属性,提取hwirq、type>等信息
                                            //map把hwirq转换为irq
    void *host_data;
    unsigned int flags;

    /* 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

    /* 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[];
};

irq_chip结构体

struct irq_chip用于对中断控制器的硬件操作

//include/linux/irq.h
struct irq_chip {
    const char  *name;
    // @irq_startup:    start up the interrupt (defaults to ->enable if NULL)
    unsigned int    (*irq_startup)(struct irq_data *data);
    // @irq_shutdown:   shut down the interrupt (defaults to ->disable if NULL)
    void        (*irq_shutdown)(struct irq_data *data);
    // @irq_enable:     enable the interrupt (defaults to chip->unmask if NULL)
    void        (*irq_enable)(struct irq_data *data);
    // @irq_disable:    disable the interrupt
    void        (*irq_disable)(struct irq_data *data);
    // @irq_ack:        start of a new interrupt
    void        (*irq_ack)(struct irq_data *data);
    // @irq_mask:       mask an interrupt source
    void        (*irq_mask)(struct irq_data *data);
    // @irq_mask_ack:   ack and mask an interrupt source 
    void        (*irq_mask_ack)(struct irq_data *data);
    // @irq_unmask:     unmask an interrupt source
    void        (*irq_unmask)(struct irq_data *data);
    // @irq_eoi:        end of interrupt
    void        (*irq_eoi)(struct irq_data *data);
    //...
};

一些个人理解

既然上面说了可以从request_irq来分析,那我确实去看了一下,大概是这样:
这个函数似乎只涉及了irqactionirq_desc
在这里插入图片描述

至于irq_data似乎是一个糅合的结构体,包含了irq_domainirq_chip、软硬件的中断号。
irq_domain是BSP开发工程师提供的,会把irq的中断号映射成。
irq_chip则是对中断寄存器的操作函数,似乎也是BSP工程师提供的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

习惯就好zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值