Linux kernel IOMMU代码分析笔记(5)——Interrupt Remapping初始化相关部分

irq_remap_ops定义在drivers\iommu\irq_remapping.h中:

struct irq_remap_ops {
    /* Check whether Interrupt Remapping is supported */
    int (*supported)(void);

    /* Initializes hardware and makes it ready for remapping interrupts */
    int  (*prepare)(void);

    /* Enables the remapping hardware */
    int  (*enable)(void);

    /* Disables the remapping hardware */
    void (*disable)(void);

    /* Reenables the remapping hardware */
    int  (*reenable)(int);

    /* Enable fault handling */
    int  (*enable_faulting)(void);

    /* IO-APIC setup routine */
    int (*setup_ioapic_entry)(int irq, struct IO_APIC_route_entry *,
                  unsigned int, int,
                  struct io_apic_irq_attr *);

    /* Set the CPU affinity of a remapped interrupt */
    int (*set_affinity)(struct irq_data *data, const struct cpumask *mask,
                bool force);

    /* Free an IRQ */
    int (*free_irq)(int);

    /* Create MSI msg to use for interrupt remapping */
    void (*compose_msi_msg)(struct pci_dev *,
                unsigned int, unsigned int,
                struct msi_msg *, u8);

    /* Allocate remapping resources for MSI */
    int (*msi_alloc_irq)(struct pci_dev *, int, int);

    /* Setup the remapped MSI irq */
    int (*msi_setup_irq)(struct pci_dev *, unsigned int, int, int);

    /* Setup interrupt remapping for an HPET MSI */
    int (*setup_hpet_msi)(unsigned int, unsigned int);
};

extern struct irq_remap_ops intel_irq_remap_ops;
extern struct irq_remap_ops amd_iommu_irq_ops;

可以看到,在结构体中定义了一系列的函数指针,每个函数的作用都写得很清楚。

针对intel处理器的结构体定义在drivers\iommu\intel_irq_remapping.c

struct irq_remap_ops intel_irq_remap_ops = {
    .supported      = intel_irq_remapping_supported,
    .prepare        = dmar_table_init,
    .enable         = intel_enable_irq_remapping,
    .disable        = disable_irq_remapping,
    .reenable       = reenable_irq_remapping,
    .enable_faulting    = enable_drhd_fault_handling,
    .setup_ioapic_entry = intel_setup_ioapic_entry,
    .set_affinity       = intel_ioapic_set_affinity,
    .free_irq       = free_irte,
    .compose_msi_msg    = intel_compose_msi_msg,
    .msi_alloc_irq      = intel_msi_alloc_irq,
    .msi_setup_irq      = intel_msi_setup_irq,
    .setup_hpet_msi     = intel_setup_hpet_msi,
};

AMD相关的暂不讨论。

enable_IR_x2apic函数(arch\x86\kernel\apic)中,包含着irq_remap_ops中初始化相关函数的调用:

void __init enable_IR_x2apic(void)
{
    ......
    /* Make sure irq_remap_ops are initialized */
    setup_irq_remapping_ops();

    hardware_init_ret = irq_remapping_prepare();
    if (hardware_init_ret && !x2apic_supported())
        return;

    ......   
    if (hardware_init_ret)
        ret = -1;
    else
        ret = enable_IR();

    ......
}

(1)

void __init setup_irq_remapping_ops(void)
{
    remap_ops = &intel_irq_remap_ops;

#ifdef CONFIG_AMD_IOMMU
    if (amd_iommu_irq_ops.prepare() == 0)
        remap_ops = &amd_iommu_irq_ops;
#endif
}

这个函数会让全局变量remap_ops这个指针指向intel_irq_remap_opsamd_iommu_irq_ops

(2)

int __init irq_remapping_prepare(void)
{
    if (!remap_ops || !remap_ops->prepare)
        return -ENODEV;

    return remap_ops->prepare();
}

irq_remapping_prepare会调用prepare函数(Intel平台即dmar_table_init)。

(3)

int __init enable_IR(void)
{
#ifdef CONFIG_IRQ_REMAP
    if (!irq_remapping_supported()) {
        pr_debug("intr-remapping not supported\n");
        return -1;
    }

    if (!x2apic_preenabled && skip_ioapic_setup) {
        pr_info("Skipped enabling intr-remap because of skipping "
            "io-apic setup\n");
        return -1;
    }

    return irq_remapping_enable();
#endif
    return -1;
}

enable_IR中会调用irq_remapping_supportedirq_remapping_enable

int irq_remapping_supported(void)
{
    if (disable_irq_remap)
        return 0;

    if (!remap_ops || !remap_ops->supported)
        return 0;

    return remap_ops->supported();
}

int __init irq_remapping_enable(void)
{
    int ret;

    if (!remap_ops || !remap_ops->enable)
        return -ENODEV;

    ret = remap_ops->enable();

    if (irq_remapping_enabled)
        irq_remapping_modify_x86_ops();

    return ret;
}

会先后调用supportedIntel平台即为intel_irq_remapping_supported)和enable函数(Intel平台即为intel_enable_irq_remapping)。

irq_remapping_modify_x86_ops会把其它函数赋值给相应的全局函数指针:

static void __init irq_remapping_modify_x86_ops(void)
{
    x86_io_apic_ops.disable     = irq_remapping_disable_io_apic;
    x86_io_apic_ops.set_affinity    = set_remapped_irq_affinity;
    x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry;
    x86_io_apic_ops.eoi_ioapic_pin  = eoi_ioapic_pin_remapped;
    x86_msi.setup_msi_irqs      = irq_remapping_setup_msi_irqs;
    x86_msi.setup_hpet_msi      = setup_hpet_msi_remapped;
    x86_msi.compose_msi_msg     = compose_remapped_msi_msg;
}

《Linux kernel IOMMU代码分析笔记(5)——Interrupt Remapping初始化相关部分》有2个想法

  1. 您好,请教个问题,关于enable iommu后 MSI message 会改变的原因,目前在研究vt-d,对一些零散概念还不能串联到一块, 感谢指导

发表评论

邮箱地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.