platform_msi使用

以下代码是OpenEuler/olk-6.6分支的,和linux实现有区别

1.为设备绑定irq_domain(可选)

如果设备是通过dts/acpi上报的,创建设备的时候就已经绑过了,不需要自己手动绑,只需要设置msi之前判断一下就行

c 复制代码
if (!dev->msi.domain) {
	dev_err(dev, "msi_domain absent\n");
	return;
}

如果不是通过这两种方式上报的,就比较麻烦。当前项目是通过其他方式上报的,需要自己手动查irq_domain。gic在初始化的时候已经把its注册到了iort里,详见irq-gic-v3-its.c: gic_acpi_parse_madt_its,该函数是解析madt表项的。(当前鲲鹏所有上报都是走acpi,所以没研究dts的,应该也有类似注册its的行为)

c 复制代码
static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, const unsigned long end)
{
	struct acpi_madt_generic_translator *its_entry;
	struct fwnode_handle *dom_handle;
	struct its_node *its;
	struct resourse res;
	int err;
	...
	// 分配its的fwnode_handle
	dom_handle = irq_domain_alloc_fwnode(&res.start);
	// 将its信息注册到iort的链表中
	err = iort_register_domain_token(its_entry->translation_id, res.start, dom_handle);
	...
}

所以设备初始化的时候,就可以通过下面的方式绑定irq_domain

c 复制代码
struct irq_domain *domain;
struct fwnode_handle *fwnode;

// its_index就是上面注册的translation_id,设备上报的时候要传上来
// bus_token就是DOMAIN_BUS_PLATFORM_MSI,这是platform_msi_create_irq_domain时更新的bus_token.
// 必须保持一致,不然可能找到别的irq_domain
fwnode = iort_find_domain_token(its_index);
domain = irq_find_matching_fwnode(fwnode, bus_token);
dev_set_msi_domain(dev, domain);

2.申请中断号

其中nvec是设备需要申请的中断数量,由硬件决定,write_msi_msg是把在os中申请到的msi资源写入设备寄存器的函数。在第二步irq_domain_activate_irq的时候就会调用write_msi_msg函数。在此之前,需要手动关设备中断,一般写设备某个寄存器就行。

The whole process to setup an IRQ has been split into two steps. The first step, __irq_domain_alloc_irqs() is to allocate IRQ descriptor and required hw resource. The second step, irq_domain_active_irq() is to program the hw with preallocated resources.

platform_msi_domain_alloc_irqs(dev, nvec, write_msi_msg);

3.设备释irq回调

c 复制代码
static void free_msis(void *data)
{
	struct device *dev = (struct device *)data;
	platform_msi_domain_free_irqs(dev);
}
devm_add_action(dev, free_msis, dev);

4. 获取virq

c 复制代码
int virq = msi_get_virq(dev, XXX_MSI_INDEX);

5.设置irq_handler

c 复制代码
devm_request_threaded_irq(dev, virq, NULL, intr_proc_thread, IRQF_ONESHOT, "xxx-intr_proc", data);

不需要上半部处理函数传NULL就行,如果需要注意不要有休眠行为。下半部是内核线程,可以休眠。然后手动开设备中断。

相关推荐
Evan芙4 小时前
Linux常见的日志服务管理的常见日志服务
linux·运维·服务器
hkhkhkhkh1236 小时前
Linux设备节点基础知识
linux·服务器·驱动开发
HZero.chen7 小时前
Linux字符串处理
linux·string
张童瑶7 小时前
Linux SSH隧道代理转发及多层转发
linux·运维·ssh
汪汪队立大功1237 小时前
什么是SELinux
linux
石小千7 小时前
Linux安装OpenProject
linux·运维
柏木乃一8 小时前
进程(2)进程概念与基本操作
linux·服务器·开发语言·性能优化·shell·进程
Lime-30908 小时前
制作Ubuntu 24.04-GPU服务器测试系统盘
linux·运维·ubuntu
百年渔翁_肯肯8 小时前
Linux 与 Unix 的核心区别(清晰对比版)
linux·运维·unix
胡闹548 小时前
Linux查询防火墙放过的端口并额外增加需要通过的端口命令
linux·运维·windows