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

news/2024/7/8 1:43:59 标签: linux, 驱动开发

内核初始化

内核启动由这两个函数,完成中断的的初始化,包括硬件中断号和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.niftyadmin.cn/n/5535851.html

相关文章

大数据面试题之HBase(2)

列式数据库的适用场景和优势?列式存储的特点? HBase的rowkey设计原则 HBase的rowkey为什么不能超过一定的长度?为什么要唯一?rowkey太长会影响Hfile的存储是吧? HBase的RowKey设置讲究有什么原因 HBase的大合并、小合并是什么? HBase和关系型数据库(传统数据库…

Codeforces Round 955 (Div. 2, with prizes from NEAR!)(A~C题解)

这场比赛怎么说呢&#xff0c;一开始打的还算好&#xff0c;能进前1000&#xff0c;但是后面就被卡住了&#xff0c;这个确实没办法水平还是不够&#xff0c;学过的还是没想起来&#xff0c;后面继续练 A. Soccer 题解&#xff1a;水题一个&#xff0c;想要在过程中出现平局的…

vivado FIFO IP核 中的rd_valid信号

在Vivado中使用FIFO IP核时&#xff0c;valid信号&#xff08;通常称为rd_valid或dout_valid&#xff09;是一个重要的控制信号。让我详细解释它的作用和使用场景。 valid信号的作用&#xff1a; 功能&#xff1a; valid信号是一个输出信号&#xff0c;用于指示FIFO输出数据的…

有哪些AI绘画软件?

以下是一些比较知名的AI绘画软件&#xff1a; 1、DeepArt&#xff1a;基于深度学习技术&#xff0c;可以将照片转换成各种艺术风格的绘画。 2、Artbreeder&#xff1a;通过生成对抗网络&#xff08;GAN&#xff09;&#xff0c;允许用户混合和匹配图像以创建新的艺术作品。 …

数据模型【第二章习题】

基本表中的每一列称为 能够更为直接地描述现实世界的结构数据模型是 在关系数据模型中&#xff0c;一个二维表格的表头称为 以二维表格作为数据结构的数据模型是 根据不同的抽象层次分&#xff0c;数据模型可分为三类&#xff0c;其中用于描述数据在存储介质上的表示方式和存取…

【数据分享】全国乡村旅游重点镇(乡)数据(Excel/Shp格式/免费获取)

之前我们分享过从我国文化和旅游部官网整理的2018-2023年我国50个重点旅游城市星级饭店季度经营状况数据&#xff08;可查看之前发布的文章&#xff09;&#xff01;文化和旅游部官网上也分享有很多与旅游相关的常用数据&#xff0c;我们基于官网发布的名单文件整理得到全国乡村…

高精度定位技术:赋能电网智能化转型的新引擎

在当今社会&#xff0c;电力作为经济发展的血脉&#xff0c;其稳定高效运行对于国家能源安全与社会发展至关重要。随着科技的飞速进步&#xff0c;高精度定位技术正逐步渗透至电网管理的各个环节&#xff0c;成为推动电网智能化转型的关键力量。本文将深入探讨高精度定位技术在…

3-数据提取方法1(json)(6节课学会爬虫)

3-数据提取方法1&#xff08;json&#xff09;&#xff08;6节课学会爬虫&#xff09; 1&#xff0c;Json2&#xff0c;哪里会返回json的数据&#xff08;值得尝试的操作&#xff09;3&#xff0c;Json字符串转换成字典或python类型进行数据提取&#xff08;1&#xff09;Json.…