linux级联中断控制器的处理流程
创始人
2024-01-29 10:42:35
0

本篇文章是通过学习韦东山老师的中断子系统相关章节而成。

这里写自定义目录标题

  • 1. 下级中断控制器的类别
    • 1.1 链式中断控制器(chained)
    • 1.2 层级中断控制器(hierarchy)
  • 2. 链式(chained)中断控制器的处理流程
  • 3. 层级(hierarchy)中断控制器的处理流程
  • 4. 处理流程对比
    • 4.1 chain的中断控制器级联方式:
    • 4.2 hierarchy的中断控制器级联方式:
  • 5 关键数据结构
    • 5.1 irq_domain
    • 5.1 irq_desc
    • 5.2 irq_data
    • 5.3 irq_chip

1. 下级中断控制器的类别

在后续课程中我们把GIC之下的中断控制器分为两类:链式(chained)、层级(hierarchy)。
这个分类并没有官方定义,是我们根据代码概括出来的(Linux内核本来就缺乏文档)。
在这里插入图片描述

1.1 链式中断控制器(chained)

上图中,左边的"chained intc"就是链式中断控制器。
它底下的4个中断触发时,都会导致GIC的33号中断被触发。
处理中断时,需要分辨:是谁触发了GIC 33号中断?这需要读取"chained intc"中的寄存器。

1.2 层级中断控制器(hierarchy)

上图中,右边边的"hierarchy intc"就是层级中断控制器。
它底下的4个中断,跟GIC中的4个中断一一对应。
处理GIC 100~103号中断时,不需要读取"hierarchy intc"的寄存器来分辨是谁触发了中断。

2. 链式(chained)中断控制器的处理流程

下图中:

  • handleA、irq_dataA均由GIC驱动提供
  • handleB、irq_dataB由GPIO驱动提供,irq_dataA则由GIC提供
  • handleC由GPIO驱动提供
    在这里插入图片描述
  • 假设GPIO模块下有4个引脚,都可以产生中断,都连接到GIC的33号中断
  • GPIO就是一个链式中断控制器,它底下有4个中断
  • 对于GPIO模块中0~3这四个hwirq,分配四个irq_desc
  • 可以一下子分配4个:legacy,老方法
  • 也可以用到时再分配:linear,新方法
  • 假设这4个irq_desc的序号为100~103,在GPIO domain中记录(0,100) (1,101)(2,102) (3,103)
  • 对于KEY,注册中断时就是:request_irq(102, ...)
  • 按下KEY时:
  • 程序从GIC中读取寄存器知道发生了33号中断,通过GIC irq_domain可以知道virq为17
  • 处理virq 17号中断:调用irq_desc[17].handle_irq,即handleB
    • mask/ack中断: 调用irq_desc[17].irq_data->irq_chip的函数,即irq_dataA
    • 分辨中断源、处理
      • 读取GPIO寄存器,确定是GPIO里2号引脚发生中断
      • 通过GPIO irq_domain可以知道virq为102
      • 处理virq 102号中断:调用irq_desc[102].handle_irq,即handleC
        • mask/ack中断: 调用irq_desc[102].irq_data->irq_chip的函数
        • 调用irq_desc[102].action链表中用户注册的函数(通过request_irq注册)
        • unmask中断: 调用irq_desc[102].irq_data->irq_chip的函数
    • unmask中断: 调用irq_desc[17].irq_data->irq_chip的函数

3. 层级(hierarchy)中断控制器的处理流程

下图中:

  • handleA、irq_dataA均由GIC驱动提供
  • irq_dataB由GPIO驱动提供,不需要handleB
    在这里插入图片描述
  • 假设GPIO模块下有4个引脚,都可以产生中断,分别链接到GIC的100~103号中断
  • GPIO就是一个层级中断控制器
  • 对于GPIO模块中0~3这四个hwirq,分配四个irq_desc,用到时再分配
  • 假设这4个irq_desc的序号(virq)为234~237
  • 在GIC domain中记录(100,234) (101,235)(102,236) (103,237)
  • 在GPIO domain中记录(0,234) (1,235)(2,236) (3,237)
  • 对于KEY,注册中断时就是:request_irq(236, ...)
  • 按下KEY时:
  • 程序从GIC中读取寄存器知道发生了102号中断,通过GIC irq_domain可以知道virq为236
  • 处理virq 236号中断:调用irq_desc[236].handle_irq,即handleA
    • mask/ack中断:
      • 调用irq_desc[236].irq_data->irq_chip的函数,即irq_dataB
        • 它会调用父级irq_dataA->irq_chip的函数
    • 调用irq_desc[236].action链表中用户注册的函数
    • unmask中断:
      • 调用irq_desc[236].irq_data->irq_chip的函数,即irq_dataB
        • 它会调用父级irq_dataA->irq_chip的函数

4. 处理流程对比

在这里插入图片描述

4.1 chain的中断控制器级联方式:

  • 通过chain这种级联方式的中断对应关系为(N:1)
  • chain这种方式的中断控制器需要分别当前触发的中断的中断源是谁
  • chain方式和上级中断控制器链接的中断控制器的handler是由当前的中断控制器驱动提供,但是irq_data是由上级的中断控制器驱动程序提供。

4.2 hierarchy的中断控制器级联方式:

  • 当前中断控制器的中断对应关系为(1:1)
  • 当触发中断时所提供的中断控制器的handler是由当前中断控制器的驱动程序提供
  • irq的mask/ack以及unmask采用一次访问父节点中断控制器irq_data的方式去处理的。

5 关键数据结构

5.1 irq_domain

/*** struct irq_domain - Hardware interrupt number translation object* @link: Element in global irq_domain list.* @name: Name of interrupt domain* @ops: pointer to irq_domain methods* @host_data: private data pointer for use by owner.  Not touched by irq_domain*             core code.* @flags: host per irq_domain flags* @mapcount: The number of mapped interrupts** Optional elements* @fwnode: Pointer to firmware node associated with the irq_domain. Pretty easy*          to swap it for the of_node via the irq_domain_get_of_node accessor* @gc: Pointer to a list of generic chips. There is a helper function for*      setting up one or more generic chips for interrupt controllers*      drivers using the generic chip library which uses this pointer.* @parent: Pointer to parent irq_domain to support hierarchy irq_domains* @debugfs_file: dentry for the domain debugfs file** Revmap data, used internally by irq_domain* @revmap_direct_max_irq: The largest hwirq that can be set for controllers that*                         support direct mapping* @revmap_size: Size of the linear map table @linear_revmap[]* @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map* @linear_revmap: Linear table of hwirq->virq reverse mappings*/
struct irq_domain {struct list_head link;const char *name;const struct irq_domain_ops *ops;void *host_data;unsigned int flags;unsigned int mapcount;/* Optional data */struct fwnode_handle *fwnode;enum irq_domain_bus_token bus_token;struct irq_domain_chip_generic *gc;
#ifdef  CONFIG_IRQ_DOMAIN_HIERARCHYstruct irq_domain *parent;
#endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFSstruct dentry           *debugfs_file;
#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;struct mutex revmap_tree_mutex;unsigned int linear_revmap[];
};

5.1 irq_desc

/*** struct irq_desc - interrupt descriptor* @irq_common_data:    per irq and chip data passed down to chip functions* @kstat_irqs:         irq stats per cpu* @handle_irq:         highlevel irq-events handler* @preflow_handler:    handler called before the flow handler (currently used by sparc)* @action:             the irq action chain* @status:             status information* @core_internal_state__do_not_mess_with_it: core internal status information* @depth:              disable-depth, for nested irq_disable() calls* @wake_depth:         enable depth, for multiple irq_set_irq_wake() callers* @irq_count:          stats field to detect stalled irqs* @last_unhandled:     aging timer for unhandled count* @irqs_unhandled:     stats field for spurious unhandled interrupts* @threads_handled:    stats field for deferred spurious detection of threaded handlers* @threads_handled_last: comparator field for deferred spurious detection of theraded handlers* @lock:               locking for SMP* @affinity_hint:      hint to user space for preferred irq affinity* @affinity_notify:    context for notification of affinity changes* @pending_mask:       pending rebalanced interrupts* @threads_oneshot:    bitfield to handle shared oneshot threads* @threads_active:     number of irqaction threads currently running* @wait_for_threads:   wait queue for sync_irq to wait for threaded handlers* @nr_actions:         number of installed actions on this descriptor* @no_suspend_depth:   number of irqactions on a irq descriptor with*                      IRQF_NO_SUSPEND set* @force_resume_depth: number of irqactions on a irq descriptor with*                      IRQF_FORCE_RESUME set* @rcu:                rcu head for delayed free* @kobj:               kobject used to represent this struct in sysfs* @request_mutex:      mutex to protect request/free before locking desc->lock* @dir:                /proc/irq/ procfs entry* @debugfs_file:       dentry for the debugfs file* @name:               flow handler name for /proc/interrupts output*/
struct irq_desc {struct irq_common_data  irq_common_data;struct irq_data         irq_data;unsigned int __percpu   *kstat_irqs;irq_flow_handler_t      handle_irq;
#ifdef CONFIG_IRQ_PREFLOW_FASTEOIirq_preflow_handler_t   preflow_handler;
#endifstruct irqaction        *action;        /* IRQ action list */unsigned int            status_use_accessors;unsigned int            core_internal_state__do_not_mess_with_it;unsigned int            depth;          /* nested irq disables */unsigned int            wake_depth;     /* nested wake enables */unsigned int            irq_count;      /* For detecting broken IRQs */unsigned long           last_unhandled; /* Aging timer for unhandled count */unsigned int            irqs_unhandled;atomic_t                threads_handled;int                     threads_handled_last;raw_spinlock_t          lock;struct cpumask          *percpu_enabled;const struct cpumask    *percpu_affinity;
#ifdef CONFIG_SMPconst struct cpumask    *affinity_hint;struct irq_affinity_notify *affinity_notify;
#ifdef CONFIG_GENERIC_PENDING_IRQcpumask_var_t           pending_mask;
#endif
#endifunsigned long           threads_oneshot;atomic_t                threads_active;wait_queue_head_t       wait_for_threads;
#ifdef CONFIG_PM_SLEEPunsigned int            nr_actions;unsigned int            no_suspend_depth;unsigned int            cond_suspend_depth;unsigned int            force_resume_depth;
#endif
#ifdef CONFIG_PROC_FSstruct proc_dir_entry   *dir;
#endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFSstruct dentry           *debugfs_file;const char              *dev_name;
#endif
#ifdef CONFIG_SPARSE_IRQstruct rcu_head         rcu;struct kobject          kobj;
#endifstruct mutex            request_mutex;int                     parent_irq;struct module           *owner;const char              *name;
} ____cacheline_internodealigned_in_smp;

5.2 irq_data

/*** struct irq_data - per irq chip data passed down to chip functions* @mask:               precomputed bitmask for accessing the chip registers* @irq:                interrupt number* @hwirq:              hardware interrupt number, local to the interrupt domain* @common:             point to data shared by all irqchips* @chip:               low level interrupt hardware access* @domain:             Interrupt translation domain; responsible for mapping*                      between hwirq number and linux irq number.* @parent_data:        pointer to parent struct irq_data to support hierarchy*                      irq_domain* @chip_data:          platform-specific per-chip private data for the chip*                      methods, to allow shared chip implementations*/
struct irq_data {u32                     mask;unsigned int            irq;unsigned long           hwirq;struct irq_common_data  *common;struct irq_chip         *chip;struct irq_domain       *domain;
#ifdef  CONFIG_IRQ_DOMAIN_HIERARCHYstruct irq_data         *parent_data;
#endifvoid                    *chip_data;
};

5.3 irq_chip

/*** struct irq_chip - hardware interrupt chip descriptor** @parent_device:      pointer to parent device for irqchip* @name:               name for /proc/interrupts* @irq_startup:        start up the interrupt (defaults to ->enable if NULL)* @irq_shutdown:       shut down the interrupt (defaults to ->disable if NULL)* @irq_enable:         enable the interrupt (defaults to chip->unmask if NULL)* @irq_disable:        disable the interrupt* @irq_ack:            start of a new interrupt* @irq_mask:           mask an interrupt source* @irq_mask_ack:       ack and mask an interrupt source* @irq_unmask:         unmask an interrupt source* @irq_eoi:            end of interrupt* @irq_set_affinity:   Set the CPU affinity on SMP machines. If the force*                      argument is true, it tells the driver to*                      unconditionally apply the affinity setting. Sanity*                      checks against the supplied affinity mask are not*                      required. This is used for CPU hotplug where the*                      target CPU is not yet set in the cpu_online_mask.* @irq_retrigger:      resend an IRQ to the CPU* @irq_set_type:       set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ* @irq_set_wake:       enable/disable power-management wake-on of an IRQ* @irq_bus_lock:       function to lock access to slow bus (i2c) chips* @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips* @irq_cpu_online:     configure an interrupt source for a secondary CPU* @irq_cpu_offline:    un-configure an interrupt source for a secondary CPU* @irq_suspend:        function called from core code on suspend once per*                      chip, when one or more interrupts are installed* @irq_resume:         function called from core code on resume once per chip,*                      when one ore more interrupts are installed* @irq_pm_shutdown:    function called from core code on shutdown once per chip* @irq_calc_mask:      Optional function to set irq_data.mask for special cases* @irq_print_chip:     optional to print special chip info in show_interrupts* @irq_request_resources:      optional to request resources before calling*                              any other callback related to this irq* @irq_release_resources:      optional to release resources acquired with*                              irq_request_resources* @irq_compose_msi_msg:        optional to compose message content for MSI* @irq_write_msi_msg:  optional to write message content for MSI* @irq_get_irqchip_state:      return the internal state of an interrupt* @irq_set_irqchip_state:      set the internal state of a interrupt* @irq_set_vcpu_affinity:      optional to target a vCPU in a virtual machine* @ipi_send_single:    send a single IPI to destination cpus* @ipi_send_mask:      send an IPI to destination cpus in cpumask* @flags:              chip specific flags*/
struct irq_chip {struct device   *parent_device;const char      *name;unsigned int    (*irq_startup)(struct irq_data *data);void            (*irq_shutdown)(struct irq_data *data);void            (*irq_enable)(struct irq_data *data);void            (*irq_disable)(struct irq_data *data);void            (*irq_ack)(struct irq_data *data);void            (*irq_mask)(struct irq_data *data);void            (*irq_mask_ack)(struct irq_data *data);void            (*irq_unmask)(struct irq_data *data);void            (*irq_eoi)(struct irq_data *data);int             (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);int             (*irq_retrigger)(struct irq_data *data);int             (*irq_set_type)(struct irq_data *data, unsigned int flow_type);int             (*irq_set_wake)(struct irq_data *data, unsigned int on);void            (*irq_bus_lock)(struct irq_data *data);void            (*irq_bus_sync_unlock)(struct irq_data *data);void            (*irq_cpu_online)(struct irq_data *data);void            (*irq_cpu_offline)(struct irq_data *data);void            (*irq_suspend)(struct irq_data *data);void            (*irq_resume)(struct irq_data *data);void            (*irq_pm_shutdown)(struct irq_data *data);void            (*irq_calc_mask)(struct irq_data *data);void            (*irq_print_chip)(struct irq_data *data, struct seq_file *p);int             (*irq_request_resources)(struct irq_data *data);void            (*irq_release_resources)(struct irq_data *data);void            (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);void            (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);int             (*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state);int             (*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state);int             (*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info);void            (*ipi_send_single)(struct irq_data *data, unsigned int cpu);void            (*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);unsigned long   flags;
};

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...