JJJ-3 gic_of_init 和 imx_gpc_init

1、gic_of_init

static int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
    void __iomem *dist_base;
    struct redist_region *rdist_regs;
    u64 redist_stride;
    u32 nr_redist_regions;
    u32 typer;
    u32 reg;
    int gic_irqs;
    int err;
    int i;

    dist_base = of_iomap(node, 0);
    if (!dist_base) {
        pr_err("%s: unable to map gic dist registers\n",
            node->full_name);
        return -ENXIO;
    }

    reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
    if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
        pr_err("%s: no distributor detected, giving up\n",
            node->full_name);
        err = -ENODEV;
        goto out_unmap_dist;
    }

    if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions)) {
        pr_err("irq_test:%s:%d:nr_redist_regions=%d\n", __func__, __LINE__, nr_redist_regions);
	}

	rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL);
    if (!rdist_regs) {
        err = -ENOMEM;
        goto out_unmap_dist;
    }

    for (i = 0; i < nr_redist_regions; i++) {
        struct resource res;
        int ret;

        ret = of_address_to_resource(node, 1 + i, &res);
        rdist_regs[i].redist_base = of_iomap(node, 1 + i);
        if (ret || !rdist_regs[i].redist_base) {
            pr_err("%s: couldn't map region %d\n",
                   node->full_name, i);
            err = -ENODEV;
            goto out_unmap_rdist;
        }
        rdist_regs[i].phys_base = res.start;
    }

    if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
        redist_stride = 0;

    gic_data.dist_base = dist_base;
    gic_data.redist_regions = rdist_regs;
    gic_data.nr_redist_regions = nr_redist_regions;

	/*
     * Find out how many interrupts are supported.
     * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
     */
    typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
    gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
    gic_irqs = GICD_TYPER_IRQS(typer);
    if (gic_irqs > 1020)
        gic_irqs = 1020;
    gic_data.irq_nr = gic_irqs;

    gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
                          &gic_data);
    gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));

    if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
        err = -ENOMEM;
        goto out_free;
    }

    set_handle_irq(gic_handle_irq);

	// 这个if不会走到
    if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
        its_init(node, &gic_data.rdists, gic_data.domain);

    gic_smp_init();
    gic_dist_init();
    gic_cpu_init();
	gic_cpu_pm_init();

    return 0;

out_free:
    if (gic_data.domain)
        irq_domain_remove(gic_data.domain);
    free_percpu(gic_data.rdists.rdist);
out_unmap_rdist:
    for (i = 0; i < nr_redist_regions; i++)
        if (rdist_regs[i].redist_base)
            iounmap(rdist_regs[i].redist_base);
    kfree(rdist_regs);
out_unmap_dist:
    iounmap(dist_base);
    return err;
}

关于asmlinkage:
看一下/usr/include/asm/linkage.h里面的定义:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
__attribute__ 是关键字,是gcc的C语言扩展,regparm(0)表示不从寄存器传递参数

如果是 __attribute__((regparm(3))),那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从寄存器取参数

还有一种是:

#define fastcall __attribute__((regparm(3)))
#define asmlinkage __attribute__((regparm(0)))
函数定义前加宏asmlinkage ,表示这些函数通过堆栈而不是通过寄存器传递参数。
gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器。缺省时采用寄存器,假如你要在你的汇编过程中调用c语言函数,并且想通过堆栈传递参数,你定义的c函数时要在函数前加上宏asmlinkage

看 set_handle_irq

完成一个函数指针赋值的操作
void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
{
    if (handle_arch_irq)
        return;

    handle_arch_irq = handle_irq;
}

看gic_smp_init

static void gic_smp_init(void)
{
	// 设置__smp_cross_call这个函数指针
    set_smp_cross_call(gic_raise_softirq);
    register_cpu_notifier(&gic_cpu_notifier);
}

看gic_dist_init
在gic初始化的gic_dist_init这个函数中,
要让上送cpu的中断负载均衡,可以将cpumask改为想上送的cpu的bit位,
比如cpu有四个核,可以奖cpumask改为oxf;

在 KVM(Kernel-based Virtual Machine)中,`vgic_v4_enable()` 是用于 **ARM GICv4** 架构下的虚拟中断控制器初始化函数之一。它负责启用并配置虚拟 GICv4 控制器,使得虚拟机(Guest VM)可以使用现代的中断管理机制,包括对 **Interrupt Translation Service (ITS)** 的支持。 --- ## 📌 函数原型 ```c int vgic_v4_enable(struct kvm *kvm); ``` ### 参数说明: - `kvm`: 指向当前虚拟机实例的指针,包含所有与该虚拟机相关的状态配置信息。 --- ## 🔧 功能详解 `vgic_v4_enable()` 主要执行以下操作: 1. **为每个 vCPU 初始化其对应的 VGICv4 状态结构体 (`struct vgic_vcpu_irq_state`)** 2. **分配并映射 ITS 设备表、中断重映射表等硬件资源** 3. **将虚拟 ITS 与物理 ITS 关联起来** 4. **注册相关中断处理函数** 5. **设置 GICv4 特有的寄存器接口(如 LPI 配置)** --- ## 📂 内核源码位置(Linux) 你可以在如下路径找到该函数的实现: ``` virt/kvm/arm/vgic/vgic-v4.c ``` --- ## 🧩 示例代码片段(简化版) 下面是一个简化版本的 `vgic_v4_enable()` 流程示例: ```c int vgic_v4_enable(struct kvm *kvm) { int ret; struct vgic_dist *dist = &kvm->arch.vgic; if (!vgic_has_its(dist)) { kvm_err("ITS not available for GICv4\n"); return -ENODEV; } /* Step 1: Allocate per-VPU interrupt state */ ret = vgic_v4_allocate_vcpu_irq_states(kvm); if (ret) return ret; /* Step 2: Initialize the ITS structures */ ret = its_setup_all(kvm); if (ret) goto free_irq_states; /* Step 3: Enable LPIs (Locality-specific Peripheral Interrupts) */ ret = enable_lpis_for_all_vcpus(kvm); if (ret) goto teardown_its; pr_info("VGICv4 enabled for KVM guest\n"); return 0; teardown_its: its_teardown_all(kvm); free_irq_states: vgic_v4_free_vcpu_irq_states(kvm); return ret; } ``` > ⚠️ 注意:以上是伪代码,实际 Linux 内核中的逻辑更复杂,涉及大量平台相关操作内存映射。 --- ## 📈 GICv4 的关键特性支持 GICv4 是 ARM GIC(Generic Interrupt Controller)架构的一个重要扩展,主要新增了以下功能: | 功能 | 描述 | |------|------| | **ITS(Interrupt Translation Service)** | 支持 MSI/MSI-X 中断的设备直接注入到 Guest,无需 Host 转发 | | **LPI(Locality-specific Peripheral Interrupt)** | 支持低优先级、边缘触发的中断类型 | | **Delegated Configuration** | 允许虚拟机自行配置部分中断属性 | | **Improved Scalability** | 更多的中断号支持,适合大规模虚拟化环境 | --- ## 🛠️ 如何调试? 你可以通过以下方式调试 `vgic_v4_enable()` 相关的问题: 1. **查看 dmesg 日志**: ```bash dmesg | grep -i vgic ``` 2. **检查是否启用了 CONFIG_KVM_ARM_VGIC_V4**: ```bash grep CONFIG_KVM_ARM_VGIC_V4 /boot/config-$(uname -r) ``` 3. **使用 tracepoint 或 ftrace 进行动态追踪**: ```bash echo &#39;vgic:*&#39; > /sys/kernel/debug/tracing/set_event cat /sys/kernel/debug/tracing/trace_pipe ``` --- ## ✅ 使用场景举例 当你运行一个支持 PCI Express 设备直通(VFIO)的 ARM64 虚拟机时,启用 `vgic_v4_enable()` 是必要的,因为: - 它允许 VFIO 设备直接发送 MSI 到虚拟机。 - 提高了中断处理性能,减少了 Host 的介入。 - 实现了高效的中断虚拟化模型。 --- ##
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值