这里我们介绍GICv3驱动的基础框架,后续再介绍GICv4的支持。GICv3驱动在文件drivers/irqchip/irq-gic-v3.c中。同时仅介绍ACPI方式下GICv3驱动。
该驱动由宏
IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, acpi_avalidate_gic_table, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init)
对不同中断控制器版本进行不同的初始化,这里对GICv3驱动通过函数**acpi_avalidate_gic_table()进行版本检查,并获取GICR(GICR是通用中断控制寄存器)数目。检查通过后通过gic_acpi_init()**进行初始化。
1-acpi_avalidate_gic_table
注意在gic_acpi_count_gicr_regions()中可以看出GICC表和GICR表两者仅定义其一,两者都可以表示CPU Interface数目。这里默认MADT表中定义GICR。
函数gic_acpi_init()进行GIC初始化,过程如下:
2-gic_acpi_init
- 对GICD基地址进行映射,以便后续直接进行访问;
- 函数gic_request_region()对GICD申请内存资源;
- 验证GICD版本;
- 分配redist_regs[],并通过函数gic_acpi_collect_gicr_base()解析GICR,并交GICR的基地址及映射后的地址保存在redist_regs[]中;
- 分配gsi_domain_handle,为GIC分配irq domain作准备;
- 调用gic_init_bases()作GIC初始化,该函数作最重要操作,后面对此函数作进一步介绍;
- 调用gic_acpi_setup_kvm_info()作KVM虚拟中断作准备;
这里介绍gic_init_bases(),它的简要介绍如下:
3-gic_init_bases
它简要介绍如下,同时对黄色部分后续分成小节介绍。
- 读取GICD_TYPER寄存器获取特性has_rss/has_vlpis/has_rvpeid/has_direct_lpi
- 根据之前分配的fwnode,分配irq_domain,并设置gic_irq_domain_ops;
- 若支持MBIS(在不支持ITS时可通过设置寄存器产生LPI中断),通过mbi_init()进行初始化;
- 通过函数set_handle_irq()将中断处理函数设置为gic_handle_irq(),在中断的处理里将更详细介绍;
- 通过gic_dist_init()进行GICD初始化;
- 通过gic_cpu_init()进行GICR初始化;
- 通过gic_smp_init()分配并设置SGI中断
- 设置GIC电源相关的初始化;
- 若支持LPI,进行ITS初始化,在下一节进行详细介绍;
- 通过gic_enable_nmi_support()使能GIC NMI中断([后续增加分析]);
这里irq_domain_ops设置为gic_irq_domain_ops,其中.translate = gic_irq_domain_translate,它根据中断类型,获取硬件中断号;.alloc=gic_irq_domain_alloc具体如下所示:
若supports_deactivate_key为真时(即EOI模式),设置为gic_eoimode_chip,使用ICC_EOIR1_EL1进行priority drop,另外需要写ICC_DIR_EL1进行deactivation;若为假时,设置为gic_chip,写ICC_EOIR1_EL1可同时作priority drop和deactivation;
另外对于不同中断类型,设置不同的中断处理函数irqchip。
对于不同IRQCHIP,irq_chip_ops主要是操作寄存器实现相应的功能,如下所示:
1 GICD初始化
2 GICR初始化
3 SGI中断分配及设置
-
(1)分配8个SGI中断
-
(2)申请percpu中断请求,并将中断处理函数设置为ipi_handler
-
(3)使能IPI中断
https://blog.youkuaiyun.com/flyingnosky/article/details/127505076