desc的High level irq event handler和action

desc结构

中断描述符irq_desc的定义如下:

 46 struct irq_desc {                                                               
 47         struct irq_common_data  irq_common_data;                                
 48         struct irq_data         irq_data;                                       
 49         unsigned int __percpu   *kstat_irqs;                                    
 50         irq_flow_handler_t      handle_irq;                                     
 51 #ifdef CONFIG_IRQ_PREFLOW_FASTEOI                                               
 52         irq_preflow_handler_t   preflow_handler;                                
 53 #endif                                                                          
 54         struct irqaction        *action;        /* IRQ action list */           
 55         unsigned int            status_use_accessors;                           
 56         unsigned int            core_internal_state__do_not_mess_with_it;       
 57         unsigned int            depth;          /* nested irq disables */                                                                                                                                
 58         unsigned int            wake_depth;     /* nested wake enables */       
 59         unsigned int            irq_count;      /* For detecting broken IRQs */ 
 60         unsigned long           last_unhandled; /* Aging timer for unhandled count */
 61         unsigned int            irqs_unhandled;                                 
 62         atomic_t                threads_handled;                                
 63         int                     threads_handled_last;                           
 64         raw_spinlock_t          lock;                                           
 65         struct cpumask          *percpu_enabled;                                
 66 #ifdef CONFIG_SMP                                                               
 67         const struct cpumask    *affinity_hint;                                 
 68         struct irq_affinity_notify *affinity_notify;                            
 69 #ifdef CONFIG_GENERIC_PENDING_IRQ                                               
 70         cpumask_var_t           pending_mask;                                   
 71 #endif                                                                          
 72 #endif                                                                          
 73         unsigned long           threads_oneshot;                                
 74         atomic_t                threads_active;                                 
 75         wait_queue_head_t       wait_for_threads;                               
 76 #ifdef CONFIG_PM_SLEEP                                                          
 77         unsigned int            nr_actions;                                     
 78         unsigned int            no_suspend_depth;                               
 79         unsigned int            cond_suspend_depth;                             
 80         unsigned int            force_resume_depth;                             
 81 #endif                                                                          
 82 #ifdef CONFIG_PROC_FS                                                           
 83         struct proc_dir_entry   *dir;                                           
 84 #endif                                                                          
 85         int                     parent_irq;                                     
 86         struct module           *owner;                                         
 87         const char              *name;                                          
 88 } ____cacheline_internodealigned_in_smp;  

结构体中有个成员handle_irq和action。
handle_irq: handle_irq就是highlevel irq-events handler,何谓high level?站在高处自然看不到细节。我认为high level是和specific相对,specific handler处理具体的事务,例如处理一个按键中断、处理一个磁盘中断。而high level则是对处理各种中断交互过程的一个抽象
action: action中的handle进行具体的事务处理。action指向一个struct irqaction的链表。如果一个interrupt request line允许共享,那么该链表中的成员可以是多个,否则,该链表只有一个节点

中断生命周期

vector_irq()->vector_irq()->__irq_svc()

  ->svc_entry()--------------------------------------------------------------------------保护中断现场

  ->irq_handler()->gic_handle_irq()------------------------------------------------具体到GIC中断控制器对应的就是gic_handle_irq(),此处从架构相关进入了GIC相关处理。

    ->GIC_CPU_INTACK--------------------------------------------------------------读取IAR寄存器,响应中断。

    ->handle_domain_irq()

      ->irq_enter()------------------------------------------------------------------------进入硬中断上下文

      ->generic_handle_irq()

        ->generic_handle_irq_desc()->handle_fasteoi_irq()--------------------根据中断号分辨不同类型的中断,对应不同处理函数,这里中断号取大于等于32。

          ->handle_irq_event()->handle_irq_event_percpu()

            ->action->handler()-----------------------------------------------------------对应到特定中断的处理函数,即上半部。

              ->__irq_wake_thread()-----------------------------------------------------如果中断函数处理返回IRQ_WAKE_THREAD,则唤醒中断线程进行处理,但不是立即执行中断线程。

      ->irq_exit()---------------------------------------------------------------------------退出硬中断上下文。视情况处理软中断。

        ->invoke_softirq()-----------------------------------------------------------------处理软中断,超出一定条件任务就会交给软中断线程处理。

    ->GIC_CPU_EOI--------------------------------------------------------------------写EOI寄存器,表示结束中断。至此GIC才会接收新的硬件中断,此前一直是屏蔽硬件中断的。

  ->svc_exit-------------------------------------------------------------------------------恢复中断现场

handle_irq和action赋值

handle_irq的赋值

irq_create_fwspec_mapping
  ----->irq_domain_alloc_irqs
         ------>__irq_domain_alloc_irqs
                ------>irq_domain_alloc_irqs_recursive        
  1. irq_domain_alloc_irqs_recursive
    主要工作是在1138行调用domain->ops->alloc函数,因为domain是GIC,则调用gic_irq_domain_alloc
1128 static int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,                                                                                                                                   
1129                                            unsigned int irq_base,               
1130                                            unsigned int nr_irqs, void *arg)     
1131 {                                                                               
1132         int ret = 0;                                                            
1133         struct irq_domain *parent = domain->parent;                             
1134         bool recursive = irq_domain_is_auto_recursive(domain);                  
1135                                                                                 
1136         BUG_ON(recursive && !parent);                                           
1137         if (recursive)                                                          
1138                 ret = irq_domain_alloc_irqs_recursive(parent, irq_base,         
1139                                                       nr_irqs, arg);            
1140         if (ret >= 0)                                                           
1141                 ret = domain->ops->alloc(domain, irq_base, nr_irqs, arg);       
1142         if (ret < 0 && recursive)                                               
1143                 irq_domain_free_irqs_recursive(parent, irq_base, nr_irqs);      
1144                                                                                 
1145         return ret;                                                             
1146 } 
  1. gic_irq_domain_alloc
1014 static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,   
1015                                 unsigned int nr_irqs, void *arg)                
1016 {                                                                               
1017         int i, ret;                                                             
1018         irq_hw_number_t hwirq;                                                  
1019         unsigned int type = IRQ_TYPE_NONE;                                      
1020         struct irq_fwspec *fwspec = arg;                                        
1021                                                                                 
1022         ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type);          
1023         if (ret)                                                                
1024                 return ret;                                                     
1025                                                                                 
1026         for (i = 0; i < nr_irqs; i++)                                           
1027                 gic_irq_domain_map(domain, virq + i, hwirq + i);                                                                                                                                        
1028                                                                                 
1029         return 0;                                                               
1030 } 

在1027行调用gic_irq_domain_map函数。
3. gic_irq_domain_map

 933 static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,           
 934                                 irq_hw_number_t hw)                             
 935 {                                                                               
 936         struct irq_chip *chip = &gic_chip;                                      
 937                                                                                 
 938         if (static_key_true(&supports_deactivate)) {                            
 939                 if (d->host_data == (void *)&gic_data[0])                       
 940                         chip = &gic_eoimode1_chip;                              
 941         }                                                                       
 942                                                                                 
 943         if (hw < 32) {                                                          
 944                 irq_set_percpu_devid(irq);                                      
 945                 irq_domain_set_info(d, irq, hw, chip, d->host_data,             
 946                                     handle_percpu_devid_irq, NULL, NULL);       
 947                 irq_set_status_flags(irq, IRQ_NOAUTOEN);                        
 948         } else {                                                                
 949                 irq_domain_set_info(d, irq, hw, chip, d->host_data,                                                                                                                                     
 950                                     handle_fasteoi_irq, NULL, NULL);            
 951                 irq_set_probe(irq);                                             
 952         }                                                                       
 953         return 0;                                                               
 954 } 

在949行调用irq_domain_set_info函数,把handle_fasteoi_irq赋值给irq对应的desc中的handle_irq。

4. irq_domain_set_info

1052 void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,          
1053                          irq_hw_number_t hwirq, struct irq_chip *chip,          
1054                          void *chip_data, irq_flow_handler_t handler,           
1055                          void *handler_data, const char *handler_name)          
1056 {                                                                               
1057         irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);                                                                                                                            
1058         __irq_set_handler(virq, handler, 0, handler_name);                      
1059         irq_set_handler_data(virq, handler_data);                               
1060 }  

5. __irq_set_handler

 789 __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,  
 790                   const char *name)                                             
 791 {                                                                               
 792         unsigned long flags;                                                    
 793         struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);           
 794                                                                                 
 795         if (!desc)                                                              
 796                 return;                                                         
 797                                                                                 
 798         __irq_do_set_handler(desc, handle, is_chained, name);                   
 799         irq_put_desc_busunlock(desc, flags);                                    
 800 }  

6. __irq_do_set_handler

 733 void                                                                            
 734 __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,          
 735                      int is_chained, const char *name)                          
 736 {                                                                               
 737         if (!handle) {                                                                                                                                                                                  
 738                 handle = handle_bad_irq;                                        
 739         } else {                                                                
 740                 struct irq_data *irq_data = &desc->irq_data;                    
 741 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY                                              
 742                 /*                                                              
 743                  * With hierarchical domains we might run into a                
 744                  * situation where the outermost chip is not yet set            
 745                  * up, but the inner chips are there.  Instead of               
 746                  * bailing we install the handler, but obviously we             
 747                  * cannot enable/startup the interrupt at this point.           
 748                  */                                                             
 749                 while (irq_data) {                                              
 750                         if (irq_data->chip != &no_irq_chip)                     
 751                                 break;                                          
 752                         /*                                                      
 753                          * Bail out if the outer chip is not set up             
 754                          * and the interrrupt supposed to be started            
 755                          * right away.                                          
 756                          */                                                     
 757                         if (WARN_ON(is_chained))                                
 758                                 return;                                         
 759                         /* Try the parent */                                    
 760                         irq_data = irq_data->parent_data;                       
 761                 }                                                               
 762 #endif                                                                          
 763                 if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))       
 764                         return;                                                 
 765         }                                                                       
 766                                                                                 
 767         /* Uninstall? */                                                        
 768         if (handle == handle_bad_irq) {                                         
 769                 if (desc->irq_data.chip != &no_irq_chip)                        
 770                         mask_ack_irq(desc);                                     
 771                 irq_state_set_disabled(desc);                                   
 772                 if (is_chained)                                                 
 773                         desc->action = NULL;                                    
 774                 desc->depth = 1;                                                
 775         }                                                                       
 776         desc->handle_irq = handle;                                              
 777         desc->name = name;                                                      
 778                                                                                 
 779         if (handle != handle_bad_irq && is_chained) {                           
 780                 irq_settings_set_noprobe(desc);                                 
 781                 irq_settings_set_norequest(desc);                               
 782                 irq_settings_set_nothread(desc);                                
 783                 desc->action = &chained_action;                                 
 784                 irq_startup(desc, true);                                        
 785         }                                                                       
 786 } 

action赋值

以串口节点为例子:

drivers/tty/serial/amba-pl011.c

pl011_startup
       ------>pl011_allocate_irq

pl011_allocate_irq

1586 static int pl011_allocate_irq(struct uart_amba_port *uap)                                                                                                                                               
1587 {                                                                               
1588         writew(uap->im, uap->port.membase + UART011_IMSC);                                                
1590      
1591         return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);     
1592 }  

request_irq

133 static inline int __must_check                                                  
134 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,       
135             const char *name, void *dev)                                        
136 {                                                                               
137         return request_threaded_irq(irq, handler, NULL, flags, name, dev);                                                                                                                               
138 } 

request_threaded_irq

1617 int request_threaded_irq(unsigned int irq, irq_handler_t handler,               
1618                          irq_handler_t thread_fn, unsigned long irqflags,       
1619                          const char *devname, void *dev_id)                     
1620 {                                                                               
1621         struct irqaction *action;                                               
1622         struct irq_desc *desc;                                                  
1623         int retval;                                                             
1624                                                                                 
1625         /*                                                                      
1626          * Sanity-check: shared interrupts must pass in a real dev-ID,          
1627          * otherwise we'll have trouble later trying to figure out              
1628          * which interrupt is which (messes up the interrupt freeing            
1629          * logic etc).                                                          
1630          *                                                                      
1631          * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and    
1632          * it cannot be set along with IRQF_NO_SUSPEND.                         
1633          */                                                                     
1634         if (((irqflags & IRQF_SHARED) && !dev_id) ||                            
1635             (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||    
1636             ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))   
1637                 return -EINVAL;                                                 
1638                                                                                 
1639         desc = irq_to_desc(irq);                                                
1640         if (!desc)                                                              
1641                 return -EINVAL;                                                 
1642                                                                                 
1643         if (!irq_settings_can_request(desc) ||                                  
1644             WARN_ON(irq_settings_is_per_cpu_devid(desc)))                       
1645                 return -EINVAL;                                                 
1646                                                                                 
1647         if (!handler) {                                                         
1648                 if (!thread_fn)                                                 
1649                         return -EINVAL;                                         
1650                 handler = irq_default_primary_handler;                          
1651         }                                                                       
1652                                                                                 
1653         action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);                 
1654         if (!action)                                                            
1655                 return -ENOMEM;                                                 
1656                                                                                 
1657         action->handler = handler;                                              
1658         action->thread_fn = thread_fn;                                          
1659         action->flags = irqflags;                                               
1660         action->name = devname;                                                 
1661         action->dev_id = dev_id;                                                
1662                                                                                 
1663         chip_bus_lock(desc);                                                    
1664         retval = __setup_irq(irq, desc, action);                                
1665         chip_bus_sync_unlock(desc);                                             
1666                                                                                 
1667         if (retval) {                                                           
1668                 kfree(action->secondary);                                       
1669                 kfree(action);                                                  
1670         }                                                                       
1671                                                                                 
1672 #ifdef CONFIG_DEBUG_SHIRQ_FIXME                                                 
1673         if (!retval && (irqflags & IRQF_SHARED)) {                              
1674                 /*                                                              
1675                  * It's a shared IRQ -- the driver ought to be prepared for it  
1676                  * to happen immediately, so let's make sure....                
1677                  * We disable the irq to make sure that a 'real' IRQ doesn't    
1678                  * run in parallel with our fake.                               
1679                  */                                                             
1680                 unsigned long flags;                                            
1681                                                                                 
1682                 disable_irq(irq);                                               
1683                 local_irq_save(flags);                                          
1684                                                                                 
1685                 handler(irq, dev_id);                                           
1686                                                                                 
1687                 local_irq_restore(flags);                                       
1688                 enable_irq(irq);                                                                                                                                                                        
1689         }                                                                       
1690 #endif                                                                          
1691         return retval;                                                          
1692 }  

在1664行使用__setup_irq把这个函数存放到irq对应的desc函数的action链表中。

中断响应流程的打印信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值