• [Fw]初探linux中断系统(1)


    1. 重要接口

    LDD上说,“内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表。模块在使用中断前要先请求一个中断通道(或者中断请求IRQ),然后在使用后释放该通道。”

    撇开系统如何遍历各个设备进行初始化,上面两句话说的实际上就是指两个接口函数:

    externint __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, constchar*name, void*dev);
      externvoid free_irq(unsigned int, void*);

    顾名思义,以上两个函数分别用于申请和释放IRQ。

    而再一看,会发现其实request_irq是个“皮包”函数,它的定义是这样的:

    static inline int __must_check
    request_irq(unsigned
    int irq, irq_handler_t handler, unsigned long flags,
    constchar*name, void*dev)
    {
    return request_threaded_irq(irq, handler, NULL, flags, name, dev);
    }

    所以实际上起到申请IRQ作用的,正是这个request_threaded_irq函数。一查,它位于/kernel/irq/manage.c中。

    2.追随request_threaded_irq

    先贴上request_threaded_irq全文

    复制代码
    int request_threaded_irq(unsigned int irq, irq_handler_t handler,
    irq_handler_t thread_fn, unsigned
    long irqflags,
    constchar*devname, void*dev_id)
    {
    struct irqaction *action;
    struct irq_desc *desc;
    int retval;

    /*
    * Sanity-check: shared interrupts must pass in a real dev-ID,
    * otherwise we'll have trouble later trying to figure out
    * which interrupt is which (messes up the interrupt freeing
    * logic etc).
    */
    if ((irqflags & IRQF_SHARED) &&!dev_id)
    return-EINVAL;

    desc
    = irq_to_desc(irq);
    if (!desc)
    return-EINVAL;

    if (desc->status & IRQ_NOREQUEST)
    return-EINVAL;

    if (!handler) {
    if (!thread_fn)
    return-EINVAL;
    handler
    = irq_default_primary_handler;
    }

    action
    = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
    if (!action)
    return-ENOMEM;

    action
    ->handler = handler;
    action
    ->thread_fn = thread_fn;
    action
    ->flags = irqflags;
    action
    ->name = devname;
    action
    ->dev_id = dev_id;

    chip_bus_lock(irq, desc);
    retval
    = __setup_irq(irq, desc, action);
    chip_bus_sync_unlock(irq, desc);

    if (retval)
    kfree(action);

    #ifdef CONFIG_DEBUG_SHIRQ
    if (!retval && (irqflags & IRQF_SHARED)) {
    /*
    * It's a shared IRQ -- the driver ought to be prepared for it
    * to happen immediately, so let's make sure....
    * We disable the irq to make sure that a 'real' IRQ doesn't
    * run in parallel with our fake.
    */
    unsigned
    long flags;

    disable_irq(irq);
    local_irq_save(flags);

    handler(irq, dev_id);

    local_irq_restore(flags);
    enable_irq(irq);
    }
    #endif
    return retval;
    }
    复制代码

    可以看到除去一些验证的语句,整个函数主要完成的任务是初始化了一个irqaction类型的struct和一个irq_desc类型的struct,接着对这两个struct进一步赋值和处理,便实现了IRQ申请。至此,我们有理由认为这两个struct是kernel管理IRQ的核心数据结构。因此不妨看看他们都是什么样的。

    复制代码
    struct irq_desc {
    unsigned
    int irq;
    struct timer_rand_state *timer_rand_state;
    unsigned
    int*kstat_irqs;
    #ifdef CONFIG_INTR_REMAP
    struct irq_2_iommu *irq_2_iommu;
    #endif
    irq_flow_handler_t handle_irq;
    struct irq_chip *chip;
    struct msi_desc *msi_desc;
    void*handler_data;
    void*chip_data;
    struct irqaction *action; /* IRQ action list */
    unsigned
    int status; /* IRQ status */

    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;
    raw_spinlock_t
    lock;
    #ifdef CONFIG_SMP
    cpumask_var_t affinity;
    conststruct cpumask *affinity_hint;
    unsigned
    int node;
    #ifdef CONFIG_GENERIC_PENDING_IRQ
    cpumask_var_t pending_mask;
    #endif
    #endif
    atomic_t threads_active;
    wait_queue_head_t wait_for_threads;
    #ifdef CONFIG_PROC_FS
    struct proc_dir_entry *dir;
    #endif
    constchar*name;
    } ____cacheline_internodealigned_in_smp;
    复制代码

    irq_desc实际是个用于构成数组的数据结构。这里irq就是我们熟悉的irq号,每个设备申请到一个IRQ,就需要填充一个irq_desc,并由kernel放入所维护的数组中进行管理。在这些需要填充的内容里,irq_chip和irqaction是两个比较有助于理解数据结构的struct。

    复制代码
    struct irq_chip {
    constchar*name;
    unsigned
    int (*startup)(unsigned int irq);
    void (*shutdown)(unsigned int irq);
    void (*enable)(unsigned int irq);
    void (*disable)(unsigned int irq);

    void (*ack)(unsigned int irq);
    void (*mask)(unsigned int irq);
    void (*mask_ack)(unsigned int irq);
    void (*unmask)(unsigned int irq);
    void (*eoi)(unsigned int irq);

    void (*end)(unsigned int irq);
    int (*set_affinity)(unsigned int irq,
    conststruct cpumask *dest);
    int (*retrigger)(unsigned int irq);
    int (*set_type)(unsigned int irq, unsigned int flow_type);
    int (*set_wake)(unsigned int irq, unsigned int on);

    void (*bus_lock)(unsigned int irq);
    void (*bus_sync_unlock)(unsigned int irq);

    /* Currently used only by UML, might disappear one day.*/
    #ifdef CONFIG_IRQ_RELEASE_METHOD
    void (*release)(unsigned int irq, void*dev_id);
    #endif
    /*
    * For compatibility, ->typename is copied into ->name.
    * Will disappear.
    */
    constchar*typename;
    };
    复制代码

    这个struct里主要定义了硬件层面上一个系统对一个IRQ的管理接口。

    复制代码
    struct irqaction {
    irq_handler_t handler;
    unsigned
    long flags;
    constchar*name;
    void*dev_id;
    struct irqaction *next;
    int irq;
    struct proc_dir_entry *dir;
    irq_handler_t thread_fn;
    struct task_struct *thread;
    unsigned
    long thread_flags;
    };
    复制代码

    这个struct中handler定义了中断处理函数, *next指向了下一个irqaction,也就是说irqaction是以链表的形式存在的。也就是说,每一个IRQ对应一个irq_desc,而irq_desc维护着irq_chip管理了硬件层面的中断使能,同时irq_desc也维护了一个irqaction链表。

    根据所查的资料,实际上,系统在处理一个中断时,会根据中断号调用irq_desc数组中的handle_irq, handle_irq再使用chip控制硬件的使能,接着调用irqaction链表,逐个调用中断处理函数。

    回过头来,request一个IRQ的过程实际上就是构造irqaction项,free的过程就是移除不需要的irqaction项。

    http://www.cnblogs.com/garychen2272/archive/2011/02/25/1964176.html

  • 相关阅读:
    edgedb 内部pg 数据存储的探索 (四) 源码编译
    edgedb 内部pg 数据存储的探索 (二) 创建数据库命令说明
    edgedb 内部pg 数据存储的探索 (三) 源码包setup.py 文件
    python 集成cython && push 测试pip 仓库
    python 集成cython 简单测试
    click python cli 开发包
    转载一篇阿里云Terraform 开发指南
    zabbix 4.2 支持 timescledb 了
    edgedb 内部pg 数据存储的探索 (一)基本环境搭建
    Podman and Buildah for Docker users
  • 原文地址:https://www.cnblogs.com/bittorrent/p/3373578.html
Copyright © 2020-2023  润新知