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就行,如果需要注意不要有休眠行为。下半部是内核线程,可以休眠。然后手动开设备中断。

相关推荐
susplus38 分钟前
【ARM 裸机开发 (IMX6ULL-mini)】GNU工具、Makefile 工程构建、链接脚本详解|C 语言点灯 + 蜂鸣器驱动
linux·arm·makefile·imx6ull
Shadow(⊙o⊙)38 分钟前
Linux进阶知识1.0
linux·运维·服务器
>Andre<1 小时前
UFS5.0标准中文全译·卷一:范围、术语与架构
android·linux·嵌入式硬件
用户0510122572961 小时前
Linux下有关QT显示环境变量设置
linux·嵌入式
闲云自留地1 小时前
告别命令恐惧症,openEuler 基础操作 + 文本 + 网络管理实战
linux·运维·云计算
剑指offer.2 小时前
ARM裸机开发-点亮LED灯
linux·服务器·嵌入式硬件
GeW2 小时前
工作忙.基础弱,也能快速拿RHCE?这套方法亲测有效
linux
Julien20043 小时前
自动挂载网络附加存储
linux·服务器·网络
codigger3 小时前
服务器又卡了?一篇讲透 Linux 性能排查(基础四件套 + perf/strace/火焰图)
linux·后端·性能优化
顶点多余3 小时前
9.18 面试题总结 --- 绿盟
linux·面试