分析irq service
dal: Data Access Layer 数据访问层
-
在irq_service中的irq_service_interface.h头文件中可以看出,irq_service是向外提供中断源操作函数函数,在内部实现寄存器操作
-
在irq_service.h又知道这个头文件是让client进行数据注册
以上,我们就可以了解到。irq_service想为了以后实现一个中间层,抽象出后续寄存器操作。
中断的操作,其主要分dal_irq_service_set,dal_irq_service_ack,dal_irq_service_to_irq_source
- dal_irq_service_set设置对应的source是不是enbale
- dal_irq_service_ack获取对应source有没有触发
- dal_irq_service_to_irq_source 通过中断处理函数,知道对应的中断source是谁
初始化以dal_irq_service_dce110_create为例
dal_irq_service_dce110_create注册了info,info是存储service对应的结构体数组const struct irq_source_info
这个info的大小是可变长,目的是最大个数是和dc_irq_source这个枚举对应的
当我们注册了我们的info到irq_service.我们在dm中的动作基本完事了,剩下的就是对接amdgpu_ih部分的中断了
列举部分irq_service相关的代码
enum dc_irq_source {
....
....//总共多少个中断源的寄存器info
};
enum dc_irq_source dal_irq_service_to_irq_source(
struct irq_service *irq_service,
uint32_t src_id,
uint32_t ext_id)
{
return irq_service->funcs->to_dal_irq_source(
irq_service,
src_id,
ext_id);
}
bool dal_irq_service_set(
struct irq_service *irq_service,
enum dc_irq_source source,
bool enable)
{
const struct irq_source_info *info =
find_irq_source_info(irq_service, source);
if (!info) {
DC_LOG_ERROR("%s: cannot find irq info table entry for %d\n",
__func__,
source);
return false;
}
dal_irq_service_ack(irq_service, source);
if (info->funcs->set)
return info->funcs->set(irq_service, info, enable);
dal_irq_service_set_generic(irq_service, info, enable);
return true;
}
//amdgpu_dm 层进行注册ih处理服务
static int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
//中断souce信息返回
static const struct irq_service_funcs irq_service_funcs_dce110 = {
.to_dal_irq_source = to_dal_irq_source_dce110
};
//初始化中断info和中断信息处理函数
static void construct(struct irq_service *irq_service,
struct irq_service_init_data *init_data)
{
dal_irq_service_construct(irq_service, init_data);
irq_service->info = irq_source_info_dce110;
irq_service->funcs = &irq_service_funcs_dce110;
}
//中断info的寄存器信息
static const struct irq_source_info
irq_source_info_dce110[DAL_IRQ_SOURCES_NUMBER] = {
[DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
hpd_int_entry(0),
hpd_int_entry(1),
hpd_int_entry(2),
hpd_int_entry(3),
hpd_int_entry(4),
hpd_int_entry(5),
hpd_rx_int_entry(0),
......处理函数和访问寄存器,如果没有set函数就使用通用寄存器,如果有则使用set多好,这他没实现好
}
//dc core对外关于irq的操作
enum dc_irq_source dc_interrupt_to_irq_source(
struct dc *dc,
uint32_t src_id,
uint32_t ext_id)
{
return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id);
}
bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable)
{
if (dc == NULL)
return false;
return dal_irq_service_set(dc->res_pool->irqs, src, enable);
}
void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src)
{
dal_irq_service_ack(dc->res_pool->irqs, src);
}
//dm中对irq_service(dc core)的访问接口
dm_set_vblank
剩下的都是在drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c中
开始讲一下amdgpu_dm_irq的处理了
dm的irq处理,将irq分为两档, high,low
/* the number of contexts may be expanded in the future based on needs */
enum dc_interrupt_context {
INTERRUPT_LOW_IRQ_CONTEXT = 0,
INTERRUPT_HIGH_IRQ_CONTEXT,
INTERRUPT_CONTEXT_NUMBER
};
high是需要立即进行相应的,low就在work中进行处理了
amdgpu_dm_irq_handler
是总的对接ih的处理processor
其中的代码就是对应的处理方式。
amdgpu_dm.c通过调用amdgpu_dm_irq_register_interrupt注册high和low的处理。
case INTERRUPT_LOW_IRQ_CONTEXT:
handle_hpd_irq()
handle_hpd_rx_irq()
case INTERRUPT_HIGH_IRQ_CONTEXT:
dm_crtc_high_irq() //vblank
dm_pflip_high_irq() //pflip ---头疼,整了好几层