zoukankan      html  css  js  c++  java
  • iommu分析之intel irq remap框架实现

    背景介绍:

    IRQ域层级结构:
    在某些架构上,可能有多个中断控制器参与将一个中断从设备传送到目标CPU。
    让我们来看看x86平台上典型的中断传递路径吧

    Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU

    涉及到的中断控制器有三个:

    1. IOAPIC 控制器
    2. 中断重映射控制器
    3. Local APIC 控制器

    如果是之前就对x86的中断控制器比较熟悉的同学,并且细心的话,会发现我们将 中断重映射控制器 的顺序排在了 Local APIC 控制器 之前。

    为了支持这样的硬件拓扑结构,使软件架构与硬件架构相匹配,为每个中断控制器建立一
    个irq_domain数据结构,并将这些irq_domain组织成层次结构。linux中断处理子系统有两个很重要的概念就是irq_chip和irq_domain,IOMMU为了支持interrupt remapping也增加了这两个东西。
    理解这点非常重要,irq_remap 模块必须按照irq 的子系统方式来实现 irq_chip 和irq_domain.

    在建立irq_domain层次结构时,靠近设备的irq_domain为子域,靠近CPU的
    irq_domain为父域。所以在上面的例子中,将建立如下的层次结构。
    ::

        CPU Vector irq_domain (root irq_domain to manage CPU vectors)
                ^
                |
        Interrupt Remapping irq_domain (manage irq_remapping entries)
                ^
                |
        IOAPIC irq_domain (manage IOAPIC delivery entries/pins)
    

    使用irq_domain层次结构的主要接口有四个:

    1. irq_domain_alloc_irqs(): 分配IRQ描述符和与中断控制器相关的资源来传递这些中断。
    2. irq_domain_free_irqs(): 释放IRQ描述符和与这些中断相关的中断控制器资源。
    3. irq_domain_activate_irq(): 激活中断控制器硬件以传递中断。
    4. irq_domain_deactivate_irq(): 停用中断控制器硬件,停止传递中断。

    为了支持irq_domain层次结构,需要做如下修改:

    1. 一个新的字段 'parent' 被添加到irq_domain结构中;它用于维护irq_domain的层次信息。
    2. 一个新的字段 'parent_data' 被添加到irq_data结构中;它用于建立层次结构irq_data以
      匹配irq_domain层次结构。irq_data用于存储irq_domain指针和硬件irq号。
    3. 新的回调被添加到irq_domain_ops结构中,以支持层次结构的irq_domain操作。

    在支持分层irq_domain和分层irq_data准备就绪后,为每个中断控制器建立一个irq_domain结
    构,并为每个与IRQ相关联的irq_domain分配一个irq_data结构。现在我们可以再进一步支持堆
    栈式(层次结构)的irq_chip。也就是说,一个irq_chip与层次结构中的每个irq_data相关联。
    一个子irq_chip可以自己或通过与它的父irq_chip合作来实现一个所需的操作。

    通过堆栈式的irq_chip,中断控制器驱动只需要处理自己管理的硬件,在需要的时候可以向其父
    irq_chip请求服务。所以我们可以实现更简洁的软件架构。

    为了让中断控制器驱动程序支持irq_domain层次结构,它需要做到以下几点:

    1. 实现 irq_domain_ops.alloc 和 irq_domain_ops.free
    2. 可选择地实现 irq_domain_ops.activate 和 irq_domain_ops.deactivate.
    3. 可选择地实现一个irq_chip来管理中断控制器硬件。
    4. 不需要实现irq_domain_ops.map和irq_domain_ops.unmap,它们在层次结构
      irq_domain中是不用的。

    irq_domain层次结构绝不是x86特有的,大量用于支持其他架构,如ARM、ARM64等。

    ir 模块,ir就是interrupt remapping的简写,下同。

    //caq:既然是中断ir,那么既要完成irq_domain_ops的实现,又要完成irq_chip的实现,如同背景介绍单元
    static struct irq_chip intel_ir_chip = {
    	.name			= "INTEL-IR",
    	.irq_ack		= apic_ack_irq,
    	.irq_set_affinity	= intel_ir_set_affinity,//caq:ir 对irq_chip只实现了部分函数
    	.irq_compose_msi_msg	= intel_ir_compose_msi_msg,
    	.irq_set_vcpu_affinity	= intel_ir_set_vcpu_affinity,
    };
    

    而irq_domain的实现如下:

    //caq:主要完成irq_domain相关的ops操作
    static const struct irq_domain_ops intel_ir_domain_ops = {
    	.alloc = intel_irq_remapping_alloc,//caq:在某个irq_domain中申请一段irqs
    	.free = intel_irq_remapping_free,
    	.activate = intel_irq_remapping_activate,
    	.deactivate = intel_irq_remapping_deactivate,
    };
    

    kvm的物理中断号来自于vfio,vfio_msi_set_vector_signal向系统申请物理中断号,传递给kvm,当外设触发中断后,
    IOMMU先处理,再给vcpu所在的物理cpu发起一个物理中断,物理cpu从not-root exit出来,
    vfio的vfio_msihandler进行中断处理,通过eventfd给kvm一个信号,
    kvm更新VMCS中虚拟中断字段,物理cpu重新enter non-root模式把虚拟中断中断注入。

    Interrupt Posting是在Interrupt Remapping的基础上进一步提升了直通设备的中断处理效率,使用Posting模式时,
    vcpu可以直接在non-root模式下处理中断而不会被vm-exit到宿主机。

    struct pi_desc {
        u32 pir[8];//caq:每个bit代表一个vector,一共表示32*8个vector,posting哪个vector,对应bit就置1
        union {
            struct {
                u16 on : 1;//caq:有中断Posting事件
                u16 sn : 1;//caq:非紧急中断,是否要立即通知
                u16 rsvd_1 : 14;
                u8 nv;//caq:nv的值为如下两个
    //#define POSTED_INTR_VECTOR		0xf2//caq:当前vcpu正在执行
    #define POSTED_INTR_WAKEUP_VECTOR	0xf1//caq:当前vcpu是休眠状态,硬件通知的中断是通知的vcpu所在的物理cpu,物理cpu收到中断事件后需要唤醒vcpu。
                u8 rsvd_2;
                u32 ndst;
            };
            u64 control;
        };
        u32 rsvd[6];
    }
    SIZE: 64
    
    

    中断虚拟化的芯片发展路径可以看做:
    1、8259虚拟实现,pic/apic虚拟实现,msi/msix的虚拟实现
    伴随着的是,用户空间实现中断虚拟化,kvm实现中断虚拟化,最后是在硬件层面实现中断虚拟化。(也就是virtual apic page 来替代 apic-access page 的过程)

    调试功能:
    打开CONFIG_GENERIC_IRQ_DEBUGFS,可让IRQ子系统的大部分内部结构都在debugfs中暴露出来。

    参考资料《Documentation/translations/zh_CN/core-api/irq/irq-domain.rst》

    水平有限,如果有错误,请帮忙提醒我。如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。版权所有,需要转发请带上本文源地址,博客一直在更新,欢迎 关注 。
  • 相关阅读:
    启用div作为编辑器 添加contentEditalbe属性
    AngularJs 通过 ocLazyLoad 实现动态(懒)加载模块和依赖-转
    angularjs的懒加载
    JavaScript 中的this指向问题
    Project Euler:Problem 41 Pandigital prime
    Android 消息机制
    新西兰天维网登录发送明文password
    使用Reveal来查看别人的APP界面+白苹果不刷机解决方式
    Android中List循环遍历性能对照
    2016年最新苹果开发人员账号注冊申请流程最强具体解释!
  • 原文地址:https://www.cnblogs.com/10087622blog/p/15508783.html
Copyright © 2011-2022 走看看