• ARM64 linux -- 软中断


    GIC 架构

    在分析软中断之前,先分析GIC架构,通过GIC 来了解中断处理的宏观逻辑,之后介绍软中断引入原因以及具体的使用方式。

     GIC分成两大部分: distributor 和  CPU interface, distributor 连接外设中断源,而CPU interface 连接CPU。

    Distributor

    Distributor 根据 irq 优先级分发 irq 到 CPU,它有如下特征

    • 整体控制分发interrupt 到 CPU
    • 单独 enable/disable interrupt
    • 设置 interrupt 优先级
    • 设置 irq 的处理 CPU
    • 设置 interrupt 的触发方式: 边缘触发 或者电平触发
    • 设置 interrupt 的 group: group0 或者 group1.

    CPU interfaces

    • enable 处理器的中断请求信号
    • 发送 ack 信号
    • 提示中断处理结束
    • 设置中断优先级
    • 设置处理器的处理竞争策略
    • 设置最高优先级的 pending interrupt

    不同于软件上的理解,我们通常说的中断触发,是先经由中断源通过 distributor 送给GIC,之后经由 GIC 的CPU interface 按照优先级送到CPU 进行处理。而CPU在处理之后需要发送ACK。

    为什么需要软中断

    要解释为什么需要软中断,在 中断架构 中,我们提到中断上下文的概念,在早期的实现中,支持中断嵌套,这带来了不确定性,因此通常在irq 处理上下文中,会关闭中断响应,如果 irq handler 处理时间过长,就会导致进程得不到调度,从而引起一系列问题。为了解决这个问题,linux 提出了中断 top half 和 bottom half 的概念。

    在 top half 中,系统只作对中断的响应,剩下的逻辑会在 irq enable 之后放在 bottom half 中处理。

     中断底半部的实现

    中断底半部有三种实现方式: softirq, tasklet, workqueue. 其目的都是为了解决 irq  disable 问题。对于 softirq 通常是固定好的,比如 timer, 一般作驱动开发不会使用到,所以这里主要列举tasklet 和 workqueue 使用方式。

     tasklet 典型使用

    1. #include
    2. #include
    3. #include
    4. #include
    5. void do_something(unsigned long args)
    6. {
    7. pr_err("%s\n", __func__);
    8. schedule();
    9. }
    10. static struct tasklet_struct task;
    11. static int test_bh_init(void)
    12. {
    13. printk(KERN_ERR "%s\n", __func__);
    14. tasklet_init(&task, do_something, 0);
    15. tasklet_schedule(&task);
    16. return 0;
    17. }
    18. static void test_bh_exit(void)
    19. {
    20. printk(KERN_ERR "%s\n", __func__);
    21. tasklet_kill(&task);
    22. }
    23. module_init(test_bh_init);
    24. module_exit(test_bh_exit);
    25. MODULE_LICENSE("GPL");
    26. MODULE_AUTHOR("xxx");

    workqueue 典型使用

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. typedef struct debug_data {
    11.     int irq;
    12.     struct work_struct worker;
    13. } debug_data_t;
    14. void do_somework(struct work_struct *work)
    15. {
    16.     debug_data_t *data = container_of(work, debug_data_t, worker);
    17.     pr_err("irq:%d\n", data->irq);
    18. }
    19. static debug_data_t *global_data = NULL;
    20. static int debug_workqueue_init(void)
    21. {
    22.     global_data = (debug_data_t *)kmalloc(sizeof(debug_data_t), GFP_KERNEL);
    23.     if (!global_data) {
    24.         pr_err("no memory");
    25.         return -ENOMEM;
    26.     }
    27.     global_data->irq = 102;
    28.     INIT_WORK(&global_data->worker, do_somework);
    29.     schedule_work(&global_data->worker);
    30.     return 0;
    31. }
    32. static void debug_workqueue_exit(void)
    33. {
    34.     if (global_data)
    35.         kfree(global_data);
    36. }
    37. module_init(debug_workqueue_init);
    38. module_exit(debug_workqueue_exit);
    39. MODULE_LICENSE("GPL");
    40. MODULE_LICENSE("xxx");

    小问题

    如果在 irq handler、 softirq handler 中调用 schedule, 会出现异常吗?可以尝试一下。结果可能和常识上有些偏差。

  • 相关阅读:
    2022年零售行业BI商业智能应用白皮书
    计算机毕业设计之社区自行车租赁管理系统
    Excel中身份证号码相关操作详解
    Linux系统编程系列之进程间通信-IPC对象
    SpringMVC之JSON返回及异常处理
    Ribbon负载均衡的深度分析和使用
    CSAPP Attack Lab
    惠普发布最新财报,对AIPC寄予厚望
    2022年5月编程语言排行看看学什么吃香?
    前端混合开发框架大对比:React Native vs. Flutter vs. Ionic
  • 原文地址:https://blog.csdn.net/kakaBack/article/details/126659594