0
点赞
收藏
分享

微信扫一扫

【回顾经典AI神作】理解和实现ResNet(最先进的图像分类)

8052cf60ff5c 2023-06-02 阅读 53

【摘要】本文树妖详细讲解了Linux中与中断相关的内核数据结构及其内部联系。

八、中断相关的数据结构

8.1 irq_desc

  • 用于表示IRQ描述符的结构定义如下:\linux-2.6.32.63\include\linux\irq.h
struct irq_desc 
{
    unsigned int        irq;	//中断号
    unsigned int        *kstat_irqs;	//2. irq stats per cpu
#ifdef CONFIG_INTR_REMAP
    struct irq_2_iommu  *irq_2_iommu;    //3. iommu with this irq
#endif
    //4. highlevel irq-events handler [if NULL, __do_IRQ()]
    irq_flow_handler_t    handle_irq;

    //5. low level interrupt hardware access
    struct irq_chip        *chip;

    //6. MSI descriptor
    struct msi_desc        *msi_desc;

    //7. per-IRQ data for the irq_chip methods
    void            *handler_data;

    //8. platform-specific per-chip private data for the chip methods, to allow shared chip implementations
    void            *chip_data;

    /* IRQ action list */
    //9. the irq action chain
    struct irqaction    *action;    

    /* IRQ status */
    //10. status information
    unsigned int        status;        

    /* nested irq disables */
    //11. disable-depth, for nested irq_disable() calls
    unsigned int        depth;        

    /* nested wake enables */
    //12. enable depth, for multiple set_irq_wake() callers
    unsigned int        wake_depth;    

    /* For detecting broken IRQs */
    //13. stats field to detect stalled irqs
    unsigned int        irq_count;    

    /* Aging timer for unhandled count */
    //14. aging timer for unhandled count
    unsigned long        last_unhandled;    

    //15. stats field for spurious unhandled interrupts
    unsigned int        irqs_unhandled;

    //16. locking for SMP
    spinlock_t        lock;
#ifdef CONFIG_SMP
    //17. IRQ affinity on SMP
    cpumask_var_t        affinity;

    //18. node index useful for balancing
    unsigned int        node;
#ifdef CONFIG_GENERIC_PENDING_IRQ
    //19. pending rebalanced interrupts
    cpumask_var_t        pending_mask;
#endif
#endif
    //20. number of irqaction threads currently running
    atomic_t        threads_active;

    //21. wait queue for sync_irq to wait for threaded handlers
    wait_queue_head_t       wait_for_threads;
#ifdef CONFIG_PROC_FS
    //22. /proc/irq/ procfs entry
    struct proc_dir_entry    *dir;
#endif
    //23. flow handler name for /proc/interrupts output
    const char        *name;
} ____cacheline_internodealigned_in_smp;
  • status描述了IRQ的当前状态,irq.h中定义了各种表示当前状态的常数,可用于描述IRQ电路当前的状态。每个常数表示位串中的一个置位的标志位(可以同时设置)
/*
 * IRQ line status.
 *
 * Bits 0-7 are reserved for the IRQF_* bits in linux/interrupt.h
 *
 * IRQ types
 */
#define IRQ_TYPE_NONE        0x00000000    /* Default, unspecified type */
#define IRQ_TYPE_EDGE_RISING    0x00000001    /* Edge rising type */
#define IRQ_TYPE_EDGE_FALLING    0x00000002    /* Edge falling type */
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH    0x00000004    /* Level high type */
#define IRQ_TYPE_LEVEL_LOW    0x00000008    /* Level low type */
#define IRQ_TYPE_SENSE_MASK    0x0000000f    /* Mask of the above */
#define IRQ_TYPE_PROBE        0x00000010    /* Probing in progress */

/* 
IRQ handler active - do not enter! 
与IRQ_DISABLED类似,IRQ_INPROGRESS会阻止其余的内核代码执行该处理程序
*/
#define IRQ_INPROGRESS        0x00000100    

/* 
IRQ disabled - do not enter!  
用户表示被设备驱动程序禁用的IRQ电路,标志通知内核不要进入处理程序
*/
#define IRQ_DISABLED        0x00000200    

/* 
IRQ pending - replay on enable 
当CPU产生一个中断但尚未执行对应的处理程序时,IRQ_PENDING标志位置位
*/
#define IRQ_PENDING        0x00000400    

/* 
IRQ has been replayed but not acked yet 
IRQ_REPLAY意味着该IRQ已经禁用,但此前尚有一个未确认的中断
*/
#define IRQ_REPLAY        0x00000800    
#define IRQ_AUTODETECT    0x00001000    /* IRQ is being autodetected */
#define IRQ_WAITING       0x00002000    /* IRQ not yet seen - for autodetection */

/* 
IRQ level triggered 
用于Alpha和PowerPC系统,用于区分电平触发和边沿触发的IRQ
*/
#define IRQ_LEVEL        0x00004000    

/* 
IRQ masked - shouldn't be seen again 
为正确处理发生在中断处理期间的中断,需要IRQ_MASKED标志位
*/
#define IRQ_MASKED        0x00008000    

/* 
IRQ is per CPU 
某个IRQ只能发生在一个CPU上时,将设置IRQ_PER_CPU标志位,在SMP系统中,该标志使几个用于防止并发访问的保护机制变得多余
*/
#define IRQ_PER_CPU        0x00010000    
#define IRQ_NOPROBE        0x00020000    /* IRQ is not valid for probing */
#define IRQ_NOREQUEST      0x00040000    /* IRQ cannot be requested */
#define IRQ_NOAUTOEN       0x00080000    /* IRQ will not be enabled on request irq */
#define IRQ_WAKEUP         0x00100000    /* IRQ triggers system wakeup */
#define IRQ_MOVE_PENDING   0x00200000    /* need to re-target IRQ destination */
#define IRQ_NO_BALANCING   0x00400000    /* IRQ is excluded from balancing */
#define IRQ_SPURIOUS_DISABLED    0x00800000    /* IRQ was disabled by the spurious trap */
#define IRQ_MOVE_PCNTXT    0x01000000    /* IRQ migration from process context */
#define IRQ_AFFINITY_SET   0x02000000    /* IRQ affinity was set from userspace*/
#define IRQ_SUSPENDED      0x04000000    /* IRQ has gone through suspend sequence */
#define IRQ_ONESHOT        0x08000000    /* IRQ is not unmasked after hardirq */
#define IRQ_NESTED_THREAD  0x10000000    /* IRQ is nested into another, no own handler thread */

#ifdef CONFIG_IRQ_PER_CPU
	#define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
	#define IRQ_NO_BALANCING_MASK    (IRQ_PER_CPU | IRQ_NO_BALANCING)
#else
	#define CHECK_IRQ_PER_CPU(var) 0
	#define IRQ_NO_BALANCING_MASK    IRQ_NO_BALANCING
#endif

8.2 irq_chip

  • \linux-2.6.32.63\include\linux\irq.h
struct irq_chip 
{
    /*
    1. name for /proc/interrupts
    包含一个短的字符串,用于标识硬件控制器
        1) IA-32: XTPIC
        2) AMD64: IO-APIC
    */
    const char    *name;

    //2. start up the interrupt (defaults to ->enable if NULL),用于第一次初始化一个IRQ,startup实际上就是将工作转给enable
    unsigned int    (*startup)(unsigned int irq);

    //3. shut down the interrupt (defaults to ->disable if NULL)
    void        (*shutdown)(unsigned int irq);

    //4. enable the interrupt (defaults to chip->unmask if NULL)
    void        (*enable)(unsigned int irq);

    //5. disable the interrupt (defaults to chip->mask if NULL)
    void        (*disable)(unsigned int irq);

    //6. start of a new interrupt
    void        (*ack)(unsigned int irq);

    //7. mask an interrupt source
    void        (*mask)(unsigned int irq);

    //8. ack and mask an interrupt source
    void        (*mask_ack)(unsigned int irq);

    //9. unmask an interrupt source
    void        (*unmask)(unsigned int irq);

    //10. end of interrupt - chip level
    void        (*eoi)(unsigned int irq);

    //11. end of interrupt - flow level
    void        (*end)(unsigned int irq);

    //12. set the CPU affinity on SMP machines
    int        (*set_affinity)(unsigned int irq, const struct cpumask *dest);

    //13. resend an IRQ to the CPU
    int        (*retrigger)(unsigned int irq);

    //14. set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
    int        (*set_type)(unsigned int irq, unsigned int flow_type);

    //15. enable/disable power-management wake-on of an IRQ
    int        (*set_wake)(unsigned int irq, unsigned int on);

    //16. function to lock access to slow bus (i2c) chips
    void        (*bus_lock)(unsigned int irq);

    //17. function to sync and unlock slow bus (i2c) chips
    void        (*bus_sync_unlock)(unsigned int irq);

    /* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
    //18. release function solely used by UML
    void        (*release)(unsigned int irq, void *dev_id);
#endif
    /*
     * For compatibility, ->typename is copied into ->name.
     * Will disappear.
     */
    //19. obsoleted by name, kept as migration helper
    const char    *typename;
};
  • 该结构需要考虑内核中出现的各个IRQ实现的所有特性。因此,一个该结构的特定实例,通常只定义所有可能方法的一个子集,下面以IO-APIC、i8259A标准中断控制器作为例子:

    • \linux-2.6.32.63\arch\x86\kernel\io_apic.c

      static struct irq_chip ioapic_chip __read_mostly = {
          .name        = "IO-APIC",
          .startup    = startup_ioapic_irq,
          .mask        = mask_IO_APIC_irq,
          .unmask        = unmask_IO_APIC_irq,
          .ack        = ack_apic_edge,
          .eoi        = ack_apic_level,
      #ifdef CONFIG_SMP
          .set_affinity    = set_ioapic_affinity_irq,
      #endif
          .retrigger    = ioapic_retrigger_irq,
      };
      
    • \linux-2.6.32.63\arch\alpha\kernel\irq_i8259.c

      struct irq_chip i8259a_irq_type = {
          .name        = "XT-PIC",
          .startup    = i8259a_startup_irq,
          .shutdown    = i8259a_disable_irq,
          .enable        = i8259a_enable_irq,
          .disable    = i8259a_disable_irq,
          .ack        = i8259a_mask_and_ack_irq,
          .end        = i8259a_end_irq,
      };
      
  • 可以看到,运行该设备,只需要定义所有可能处理程序函数的一个子集

8.3 irqaction

  • struct irqaction结构是struct irq_desc中和IRQ处理函数相关的成员结构
struct irqaction 
{
    //1. name、dev_id唯一地标识一个中断处理程序
    irq_handler_t           handler;
    void                    *dev_id;

    void __percpu           *percpu_dev_id;

    //2. next用于实现共享的IRQ处理程序
    struct irqaction        *next;
    irq_handler_t           thread_fn;
    struct task_struct      *thread;
    unsigned int            irq;

    //3. flags是一个标志变量,通过位图描述了IRQ(和相关的中断)的一些特性,位图中的各个标志位可以通过预定义的常数访问
    unsigned int            flags;
    unsigned long           thread_flags;
    unsigned long           thread_mask;

    //4. name是一个短字符串,用于标识设备
    const char              *name;
    struct proc_dir_entry   *dir;
} ____cacheline_internodealigned_in_smp;
  • 几个irqaction实例聚集到一个链表中,链表的所有元素都必须处理同一个IRQ编号,在发生一个共享中断时,内核扫描该链表找出中断实际上的来源设备

image-20230505233103971

举报

相关推荐

0 条评论