硬件中断号怎么跟irq映射的?

内核初始化

内核启动由这两个函数,完成中断的的初始化,包括硬件中断号和virq的映射

start_kernel{
    ....
    early_irq_init();
	init_IRQ();
    ....
}

early_irq_init

early_irq_init给前16个核内中断分配irq_desc,并通过arch_early_irq_init初始化;打印如下:NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16

int __init early_irq_init(void)
{
        int i, initcnt, node = first_online_node;
        struct irq_desc *desc;

        init_irq_default_affinity();

        /* Let arch update nr_irqs and return the nr of preallocated irqs */
        initcnt = arch_probe_nr_irqs();
        printk(KERN_INFO "NR_IRQS: %d, nr_irqs: %d, preallocated irqs: %d\n",
               NR_IRQS, nr_irqs, initcnt);

        if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))
                nr_irqs = IRQ_BITMAP_BITS;

        if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
                initcnt = IRQ_BITMAP_BITS;

        if (initcnt > nr_irqs)
                nr_irqs = initcnt;

        for (i = 0; i < initcnt; i++) {
                desc = alloc_desc(i, node, 0, NULL, NULL);
                set_bit(i, allocated_irqs);
                irq_insert_desc(i, desc);
        }
        return arch_early_irq_init();
}

 所以可以看到有些控制器驱动,不去通过map找irq ;而是直接从设备树读出硬件中断号+16,来得出irq;但是建议还是规范的通过platform_get_irq获取映射后的irq

err = of_property_read_u32(node, "interrupts", &(port->irq));
        if (err)
                return err;

#ifndef CONFIG_PCI_MSI
        port->irq += 16;
        err = devm_request_irq(dev, port->irq, pcie_irq_handler,
                                IRQF_SHARED, "pcie", port);
        if (err) {
                dev_err(dev, "failed to request irq %d\n", port->irq);
                return err;
        }
#endif

IRQCHIP_DECLARE

IRQCHIP_DECLARE定义的中断chip跟设备树匹配上,详情见《这篇》  ; set_handle_irq设置中断入口;

static int __init mmp_of_init(struct device_node *node,
                              struct device_node *parent)
{
        int ret;

        ret = mmp_init_bases(node);
        if (ret < 0)
                return ret;

        icu_data[0].conf_enable = mmp_conf.conf_enable;
        icu_data[0].conf_disable = mmp_conf.conf_disable;
        icu_data[0].conf_mask = mmp_conf.conf_mask;
        set_handle_irq(mmp_handle_irq);
        max_icu_nr = 1;
        return 0;
}
IRQCHIP_DECLARE(mmp_intc, "mrvl,mmp-intc", mmp_of_init);

映射virq

mmp_init_bases映射硬件中断跟irq;有多少硬件中断,就调用多少次irq_create_mapping来静态创建映射

static int __init mmp_init_bases(struct device_node *node)
{
        int ret, nr_irqs, irq, i = 0;

        ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
        if (ret) {
                pr_err("Not found mrvl,intc-nr-irqs property\n");
                return ret;
        }
        g_nr_irqs = nr_irqs;

        mmp_icu_base = of_iomap(node, 0);
        if (!mmp_icu_base) {
                pr_err("Failed to get interrupt controller register\n");
                return -ENOMEM;
        }

        if (g_nr_irqs > ICU_BASE1_NR_IRQS)
                icu_data[0].reg_base2 = mmp_icu_base + ICU_CFG2_OFFSET;
        else
                icu_data[0].reg_base2 = 0;

        icu_data[0].virq_base = 0;
        icu_data[0].domain = irq_domain_add_linear(node, nr_irqs,
                                                   &mmp_irq_domain_ops,
                                                   &icu_data[0]);
        for (irq = 0; irq < nr_irqs; irq++) {
                ret = irq_create_mapping(icu_data[0].domain, irq);
                if (!ret) {
                        pr_err("Failed to mapping hwirq\n");
                        goto err;
                }
                if (!irq)
                        icu_data[0].virq_base = ret;
        }
        icu_data[0].nr_irqs = nr_irqs;
        return 0;
err:
        if (icu_data[0].virq_base) {
                for (i = 0; i < irq; i++)
                        irq_dispose_mapping(icu_data[0].virq_base + i);
        }
        irq_domain_remove(icu_data[0].domain);
        iounmap(mmp_icu_base);
        return -EINVAL;
}

irq_create_mapping

上面从从设备树获取当前中断控制器多少个中断,然后通过irq_create_mapping创建映射

static inline unsigned int irq_create_mapping(struct irq_domain *host,
					      irq_hw_number_t hwirq)
{
	return irq_create_mapping_affinity(host, hwirq, NULL);
}

irq_create_mapping_affinity

主要通过irq_domain_alloc_descs分配virq

unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
				       irq_hw_number_t hwirq,
				       const struct irq_affinity_desc *affinity)
{
	struct device_node *of_node;
	int virq;

	pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);

	/* Look for default domain if nececssary */
	if (domain == NULL)
		domain = irq_default_domain;
	if (domain == NULL) {
		WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
		return 0;
	}
	pr_debug("-> using domain @%p\n", domain);

	of_node = irq_domain_get_of_node(domain);

	/* Check if mapping already exists */
	virq = irq_find_mapping(domain, hwirq);
	if (virq) {
		pr_debug("-> existing mapping on virq %d\n", virq);
		return virq;
	}

	/* Allocate a virtual interrupt number */
	virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
				      affinity);
	if (virq <= 0) {
		pr_debug("-> virq allocation failed\n");
		return 0;
	}

	if (irq_domain_associate(domain, virq, hwirq)) {
		irq_free_desc(virq);
		return 0;
	}

	pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
		hwirq, of_node_full_name(of_node), virq);

	return virq;
}

irq_domain_alloc_descs

计算得出偏移hint;一般就是硬件中断号;cnt一般是1 ;按此分配virq

int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,
			   int node, const struct irq_affinity_desc *affinity)
{
	unsigned int hint;

	if (virq >= 0) {
		virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE,
					 affinity);
	} else {
		hint = hwirq % nr_irqs;
		if (hint == 0)
			hint++;
		virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE,
					 affinity);
		if (virq <= 0 && hint > 1) {
			virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE,
						 affinity);
		}
+       printk("hint = %d, hwirq = %ld, nr_irqs = %d virq = %d", hint, hwirq, nr_irqs, virq);
	}

	return virq;

加入的打印如下

[    0.000000] hint = 1, hwirq = 0, nr_irqs = 17 virq = 16
[    0.000000] hint = 1, hwirq = 1, nr_irqs = 18 virq = 17
[    0.000000] hint = 2, hwirq = 2, nr_irqs = 19 virq = 18
[    0.000000] hint = 3, hwirq = 3, nr_irqs = 20 virq = 19
[    0.000000] hint = 4, hwirq = 4, nr_irqs = 21 virq = 20
......
[    0.000000] hint = 62, hwirq = 62, nr_irqs = 79 virq = 78
[    0.000000] hint = 63, hwirq = 63, nr_irqs = 80 virq = 79

__irq_alloc_descs

经过__irq_alloc_descs后,nr_irq就被irq_expand_nr_irqs赋值为上一次irq_domain_alloc_descs的start + cnt

int __ref
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
		  struct module *owner, const struct irq_affinity_desc *affinity)
{
	int start, ret;

	if (!cnt)
		return -EINVAL;

	if (irq >= 0) {
		if (from > irq)
			return -EINVAL;
		from = irq;
	} else {
		/*
		 * For interrupts which are freely allocated the
		 * architecture can force a lower bound to the @from
		 * argument. x86 uses this to exclude the GSI space.
		 */
		from = arch_dynirq_lower_bound(from);
	}

	mutex_lock(&sparse_irq_lock);

	start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,
					   from, cnt, 0);
	ret = -EEXIST;
	if (irq >=0 && start != irq)
		goto unlock;

	if (start + cnt > nr_irqs) {
		ret = irq_expand_nr_irqs(start + cnt);
		if (ret)
			goto unlock;
	}
	ret = alloc_descs(start, cnt, node, affinity, owner);
unlock:
	mutex_unlock(&sparse_irq_lock);
	return ret;
}

中断级联

1.其他控制器,比如gpio控制器的中断控制单元,最终也是用不同的接口调用到__irq_alloc_descs分配irq_des

2.如果有gpio等控制器级联到这个父中断控制器下面;那么gpio控制器的的中断处理函数------会读出是那个gpio的触发的中断,然后找到gpio映射的irq,再去执行irq注册的中断处理函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/771514.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

斯坦福提出首个开源视觉语言动作大模型OpenVLA

OpenVLA&#xff1a;开源视觉语言动作大模型 摘要模型结构训练数据训练设施实验总结和局限性 项目主页 代码链接 论文链接 模型链接 摘要 现有的VLA(Vision-Language-Action )模型具有这些局限性&#xff1a; 1)大多封闭且开放&#xff1b; 2)未能探索高效地为新任务微调VLA的方…

vue3 【提效】使用 CSS 框架 UnoCSS 实用教程

该换种更高效的方式写 CSS 啦&#xff0c;举个例&#xff1a; <div class"flex"> </div>相当于 <div class"flex"> </div> <style> .flex {display: flex; } </style>当然&#xff0c;还有超多强大的功能帮我们提升…

【后端面试题】【中间件】【NoSQL】MongoDB查询过程、ESR规则、覆盖索引的优化

任何中间件的面试说到底都是以高可用、高性能和高并发为主&#xff0c;而高性能和高并发基本是同时存在的。 性能优化一直被看作一个高级面试点&#xff0c;因为只有对原理了解得很透彻的人&#xff0c;在实践中才能找准性能优化的关键点&#xff0c;从而通过各种优化手段解决性…

为什么人员定位系统很有必要性?

人员定位系统在现代社会和企业环境中具有极高的必要性&#xff0c;这主要体现在以下几个方面&#xff1a; 一、安全保障 二、提升效率 三、管理优化 四、增强合规性 综上所述&#xff0c;人员定位系统通过提供实时、准确的位置信息&#xff0c;为企业带来了安全保障、效率提升…

香橙派AIpro实测:YOLOv8便捷检测,算法速度与运行速度结合

香橙派AIpro实测&#xff1a;YOLOv8便捷检测&#xff0c;算法速度与运行速度结合 文章目录 香橙派AIpro实测&#xff1a;YOLOv8便捷检测&#xff0c;算法速度与运行速度结合一、引言二、香橙派AIpro简介三、YOLOv8检测效果3.1 目标检测算法介绍3.1.1 YOLO家族3.1.2 YOLOv8算法理…

500mA、低压差、低噪声、超快、无需旁路电容的CMOS LDO稳压器RT9013

一般描述 RT9013 SOT23-5封装的外观和丝印 RT9013 是一款高性能的 500mA LDO 稳压器&#xff0c;具有极高的 PSRR 和超低压差。非常适合具有苛刻性能和空间要求的便携式射频和无线应用。 RT9013的静态电流低至25μA&#xff0c;进一步延长了电池的使用寿命。RT9013 也适用于低…

Element中的日期时间选择器DateTimePicker和级联选择器Cascader

简述&#xff1a;在Element UI框架中&#xff0c;Cascader&#xff08;级联选择器&#xff09;和DateTimePicker&#xff08;日期时间选择器&#xff09;是两个非常实用且常用的组件&#xff0c;它们分别用于日期选择和多层级选择&#xff0c;提供了丰富的交互体验和便捷的数据…

私域和社群的差别是什么?

社群就是拉很多人建群就可以了&#xff0c;但是私域不是&#xff0c;这里有三点不同 1、私域的用户来源&#xff0c;不仅仅是微信&#xff0c;而是基于一定的联系形成的链接&#xff0c;比如买了商家的货&#xff0c;反复购买觉得好&#xff0c;推荐给亲朋好友的二次开发用户&…

nanodiffusion代码逐行理解之Attention

目录 一、注意力中的QKV二、注意力中的位置嵌入三、注意力中的多头四、注意力和自注意力五、注意力中的encode和decoder 一、注意力中的QKV 简单来说&#xff1a; Q: 要查询的信息 K: 一个索引&#xff0c;要查询的向量 V: 我们查询得到的值 复杂一点的解释&#xff1a; Query…

如何快速选择短剧系统源码:高效构建您的在线短剧平台

在数字化时代&#xff0c;短剧作为一种新兴的娱乐形式&#xff0c;受到了广泛的欢迎。随着市场需求的增长&#xff0c;构建一个在线短剧平台成为了很多创业者和开发者的目标。而选择正确的短剧系统源码则是实现这一目标的关键步骤。本文将为您提供一些实用的指导&#xff0c;帮…

论文解析——Transformer 模型压缩算法研究及硬件加速器实现

作者及发刊详情 邓晗珂&#xff0c;华南理工大学 摘要 正文 实验平台 选取模型&#xff1a; T r a n s f o r m e r b a s e Transformer_{base} Transformerbase​ 训练数据集&#xff1a;WMT-2014 英语-德语翻译数据集、IWSLT-2014 英语-德语互译数据集 Transformer模…

策略模式入门:基本概念与应用

目录 策略模式策略模式结构策略模式应用场景策略模式优缺点练手题目题目描述输入描述输出描述题解 策略模式 策略模式&#xff0c;又称政策模式&#xff0c;是一种行为型设计模式&#xff0c;它能让你定义一系列算法&#xff0c;并将每种算法分别放入独立的类中&#xff0c;以…

基于Spring Boot的高校智慧采购系统

1 项目介绍 1.1 摘要 随着信息技术与网络技术的迅猛发展&#xff0c;人类社会已跨入全新信息化纪元。传统的管理手段因其内在局限&#xff0c;在处理海量信息资源时日渐捉襟见肘&#xff0c;难以匹配不断提升的信息管理效率和便捷化需求。顺应时代发展趋势&#xff0c;各类先…

http数据传输确保完整性和保密性整流程方案(含源码)

往期文章回顾 【深度学习】 【深度学习】物体检测/分割/追踪/姿态估计/图像分类检测演示系统【含源码】【深度学习】YOLOV8数据标注及模型训练方法整体流程介绍及演示【深度学习】行人跌倒行为检测软件系统【深度学习】火灾检测软件系统【深度学习】吸烟行为检测软件系统【深度…

rtpengine_mr12.0 基础建设容器运行

目录 Dockerfile rtpengine.conf 容器内编译安装 RTPEngine 正常提供功能 1. 启动RTPEngine服务 2. 删除 RTPEngine服务 3. 加载内核模块 检查所有进程是否正在运行 上传到仓库 博主wx&#xff1a;yuanlai45_csdn 博主qq&#xff1a;2777137742 后期会创建粉丝群&…

实验二 图像的代数运算

一、实验目的&#xff1a; 1&#xff0e;了解图像的算术运算在数字图像处理中的初步应用。 2&#xff0e;体会图像算术运算处理的过程和处理前后图像的变化。 二、实验内容&#xff1a; 1&#xff0e;图像的加法运算 图像相加一般用于对同一场景的多幅图像求平均效果&…

【QT】概述|对象树模型|两种控件模式|信号和槽|lambda

目录 什么是QT 特点 QT程序 main函数 QT按钮 纯代码模式 图形化模式 对象树模型 信号和槽 连接与断开 自动连接 断开连接 信号的发射 lambda表达式 基本语法 捕获列表 Lambda表达式用于信号与槽的连接 例如 什么是QT Qt是一个跨平台的C图形用户界面应用…

如何在TikTok上获得更多观看量:12个流量秘诀

TikTok作为热门海外社媒&#xff0c;在跨境出海行业中成为新兴的推广渠道&#xff0c;但你知道如何让你的TikTok赢得更多关注次数吗&#xff1f;如果您正在寻找增加 TikTok 观看次数的方法&#xff0c;接下来这12种策略&#xff0c;你需要一一做好&#xff01; 1. 在内容中添加…

女性经济崛起,天润融通用客户感知挖掘市场潜力

每逢一年一度的国际妇女节&#xff0c;“女性”话题都会被郑重地讨论。 从消费市场上来说&#xff0c;最近几年女性群体正在拥有越来越大的影响力&#xff0c;甚至出现了“她经济”这样的专属词汇在最近几年被市场反复讨论。 毫无疑问&#xff0c;女性消费群体的崛起已经成为…

2.8亿东亚五国建筑数据分享

数据是GIS的血液&#xff01; 我们现在为你分享东亚5国的2.8亿条建筑轮廓数据&#xff0c;该数据包括中国、日本、朝鲜、韩国和蒙古5个东亚国家完整、高质量的建筑物轮廓数据&#xff0c;你可以在文末查看领取方法。 数据介绍 虽然开源的全球的建筑数据已经有微软的建筑数据…