AMD KFD技术分析3-3:event机制-KFD 中断机制

1. 中断注册流程

1.1 KFD 驱动初始化

KFD 驱动在初始化时,会为每个支持的 GPU 节点(kfd_node)注册中断处理类(event_interrupt_class)。每一代 GPU(如 GFX10、GFX11)有不同的 event_interrupt_class 实现,主要区别在于 .interrupt_isr 和 .interrupt_wq 两个回调函数。

struct kfd_event_interrupt_class {
    //中断上半部:快速判定
	bool (*interrupt_isr)(struct kfd_node *dev,
			            const uint32_t *ih_ring_entry,
                        uint32_t *patched_ihre,
			            bool *patched_flag);
    
    //中断下半部:处理中断
	void (*interrupt_wq)(struct kfd_node *dev,
			            const uint32_t *ih_ring_entry);
};

1.2 注册到 AMDGPU 中断框架

KFD 并不直接向 Linux 内核注册硬件中断,而是集成在 AMDGPU 驱动的中断处理体系中。

  • AMDGPU 驱动通过 amdgpu_irq_dispatch() 统一分发所有 GPU 相关的中断(见 amdgpu_ih.c)。

  • KFD 相关的中断(如 VM fault、Fence、SQ interrupt 等)会在分发时被识别,并调用 KFD 的中断处理回调。

2. 中断分发与快速判定(ISR)

2.1 硬件中断到达

GPU 产生中断后,AMDGPU 的中断处理函数(如 amdgpu_ih_process())会被调用。该函数从 IH(Interrupt Handler)ring buffer 读取中断向量(IV),并解析出 client_id、source_id、vmid、pasid 等信息。

2.2 分发到 KFD

amdgpu_irq_dispatch() 根据 IV 的 client_id/source_id 判断是否为 KFD 关心的中断。

如果是,则调用 KFD 注册的 .interrupt_isr 回调(如 event_interrupt_isr_v11())。

2.3 快速判定(ISR)

.interrupt_isr 只做快速判定,判断该中断是否需要 KFD 进一步处理。典型判定逻辑(见 event_interrupt_isr_v11):

  • 检查 client_id/source_id 是否为 KFD 关心的类型(如 SQ_INTERRUPT_MSG、CP_END_OF_PIPE、VM fault 等)。

  • 检查 vmid 是否属于 KFD 管理的范围。

  • 检查 pasid 是否有效。

如果需要处理,返回 true,否则返回 false。

3. 推送到工作队列(Work Queue)

如果 .interrupt_isr 返回 true,AMDGPU 驱动会将该中断信息推送到 KFD 的工作队列(work queue)。这样做的目的是避免在硬件中断上下文中做复杂处理,将耗时操作延后到内核线程上下文。那为什么要用工作队列?因为:
中断上下文限制:硬件中断处理(ISR)运行在中断上下文,不能做阻塞、耗时或复杂的操作,只能做快速判定和简单处理。
复杂事件处理:KFD 需要解析中断、查找进程、上报事件、唤醒用户空间等,这些操作可能阻塞或耗时,必须在进程上下文(内核线程)中完成。
解耦与性能:将复杂处理推迟到工作队列,可以提升中断响应速度,避免影响系统实时性和稳定性。

4. 详细处理(WQ 回调)

4.1 工作队列回调

KFD 的 .interrupt_wq 回调(如 event_interrupt_wq_v11())会在工作队列线程中被调用,进行详细的事件处理。

4.2 事件分类与处理

  • 根据 client_id/source_id/context_id0/context_id1 等,分为不同类型事件:

    • VM Fault/UTCL2 Fault:解析 fault 信息,构造异常数据,上报给用户空间调试工具或 SMI。

    • CP_END_OF_PIPE:信号事件,通知用户空间某个 GPU 队列任务完成。

    • CP_BAD_OPCODE:非法指令,可能需要暂停/重置队列,并上报调试事件。

    • SDMA_TRAP/SDMA_ECC:信号或 ECC 错误,可能触发 poison 消耗和队列重置。

    • SQ_INTERRUPT_MSG:进一步区分为 AUTO、INST、ERROR 类型,分别处理 trace、调试、硬件错误等。

    • Fence:调用 kfd_process_close_interrupt_drain,关闭进程相关队列,防止重复中断。

  • 处理过程中,会调用如下函数:

    • kfd_signal_event_interrupt():向用户空间 signal page 写入信号,唤醒等待的应用。

    • kfd_set_dbg_ev_from_interrupt():上报调试事件。

    • event_interrupt_poison_consumption_v11():处理 ECC/poison 消耗,可能触发 GPU reset。

    • kfd_dqm_suspend_bad_queue_mes():暂停异常队列。

5. 用户空间事件通知

事件处理后,KFD 通过 signal page 或 event fd 等机制通知用户空间应用(如 ROCm runtime、调试器)。用户空间应用可以通过 mmap 的 signal page 轮询事件,或通过 poll/epoll 等机制等待事件 fd。

6. 关键结构与函数关系图

硬件中断
   │
   ▼
amdgpu_ih_process (amdgpu_ih.c)
   │
   ▼
amdgpu_irq_dispatch
   │
   ▼
event_interrupt_isr_v11 (kfd_int_process_v11.c)
   │
   ├─ 返回 false → 忽略
   └─ 返回 true  → 推送到 KFD 工作队列→ schedule_work
                      │
                      ▼
           kfd_interrupt_work_handler (内核线程上下文)
                      │
                      ▼
           event_interrupt_wq_v11
                      │
                      ├─ kfd_signal_event_interrupt
                      |  |---set_event_from_interrupt
                      |       |----set_event
                      ├─ kfd_set_dbg_ev_from_interrupt
                      ├─ event_interrupt_poison_consumption_v11
                      └─ kfd_process_close_interrupt_drain

这里与我们event系列相关的是kfd_signal_event_interrupt下的调用链,其实现如下。在这里实现了event的signal,还有后面我们要涉及的event_age。

static void set_event_from_interrupt(struct kfd_process *p,
					struct kfd_event *ev)
{
	if (ev && event_can_be_gpu_signaled(ev)) {
		acknowledge_signal(p, ev);
		spin_lock(&ev->lock);
		set_event(ev);
		spin_unlock(&ev->lock);
	}
}

static void set_event(struct kfd_event *ev)
{
	struct kfd_event_waiter *waiter;

	/* Auto reset if the list is non-empty and we're waking
	 * someone. waitqueue_active is safe here because we're
	 * protected by the ev->lock, which is also held when
	 * updating the wait queues in kfd_wait_on_events.
	 */
	ev->signaled = !ev->auto_reset || !waitqueue_active(&ev->wq);
	if (!(++ev->event_age)) {
		/* Never wrap back to reserved/default event age 0/1 */
		ev->event_age = 2;
		WARN_ONCE(1, "event_age wrap back!");
	}

	list_for_each_entry(waiter, &ev->wq.head, wait.entry)
		WRITE_ONCE(waiter->activated, true);

	wake_up_all(&ev->wq);
}

7. 总结

  • 注册阶段:KFD 通过 event_interrupt_class 注册中断处理回调,集成到 AMDGPU 的中断分发体系。

  • 快速判定.interrupt_isr 负责判断中断是否需要 KFD 处理,避免无关中断进入工作队列。

  • 详细处理.interrupt_wq 在工作队列中完成事件分类、信号上报、异常处理等复杂逻辑。

  • 用户通知:通过 signal page 或 event fd 通知用户空间,实现高效的 GPU 事件响应。

这种设计既保证了中断处理的实时性和高效性,又避免了在硬件中断上下文中做耗时操作,提升了系统的健壮性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeeplyMind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值