IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> linux硬件中断(hwirq)和软件中断号(virq)的映射过程 -> 正文阅读

[系统运维]linux硬件中断(hwirq)和软件中断号(virq)的映射过程


此博文基于对苯叔中断系统视频的学习以及对linux内核源码的理解总结而成

1 硬件中断号获取

在具体的硬件初始化过程,通过会获取到对应的hw_irq,然后转换为virq,最后用于注册对应的中断。
硬件中断号一般是通过解析设备树或者直接用板级数据获取,获取之后通过irq_of_parse_and_map函数转换为virq,然后再去注册中断。

1.1 硬件中断号的获取过程

|- irq_of_parse_and_map
	|- of_irq_parse_one
	|- irq_create_of_mapping
		|- irq_create_fwspec_mapping
			|- irq_domain_translate
				|- d->ops->translate
					|- gic_irq_domain_translate
					
static const struct irq_domain_ops gic_irq_domain_ops = {
	.translate = gic_irq_domain_translate,
	.alloc = gic_irq_domain_alloc,
	.free = gic_irq_domain_free,
	.select = gic_irq_domain_select,
};

1.2 gic_irq_domain_translate

在设备树中,对于中断的描述以k3-am65.dtsi为例来说明,示例如下所示:

 52  a53_timer0: timer-cl0-cpu0 {
 53          compatible = "arm,armv8-timer";
 54          interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* cntpsirq */
 55                       <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* cntpnsirq */
 56                       <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* cntvirq */
 57                       <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* cnthpirq */
 58  };

interrupts域描述了中断的相关属性,分别使用3个属性来描述一个中断,这三个参数是在of_irq_parse_one函数中解析出来的。

  • 1 中断类型,对应于设备树中的GIC_PPI属性,表示是PPI中断,0表示SPI中断。
  • 2 中断ID,对应于设备树中的13、14、11、10这几个中断号,表示的是hw_irq号。
  • 3 中断触发类型,对应于IRQ_TYPE_LEVEL_LOW,表示低电平触发中断,中断触发类型还包括高电平触发,边沿触发等类型。

如何获取硬件终端号:

  • 判断中断类型fwspec->param[0]
    • SPI中断*hwirq = fwspec->param[1] + 32;
    • PPI中断*hwirq = fwspec->param[1] + 16;
    • EPPI中断*hwirq = fwspec->param[1] + ESPI_BASE_INTID;
    • LPI中断*hwirq = fwspec->param[1];
static int gic_irq_domain_translate(struct irq_domain *d,
				    struct irq_fwspec *fwspec,
				    unsigned long *hwirq,
				    unsigned int *type)
{
	if (is_of_node(fwspec->fwnode)) {
		if (fwspec->param_count < 3)
			return -EINVAL;

		switch (fwspec->param[0]) {
		case 0:			/* SPI */
			*hwirq = fwspec->param[1] + 32;
			break;
		case 1:			/* PPI */
			*hwirq = fwspec->param[1] + 16;
			break;
		case 2:			/* ESPI */
			*hwirq = fwspec->param[1] + ESPI_BASE_INTID;
			break;
		case 3:			/* EPPI */
			*hwirq = fwspec->param[1] + EPPI_BASE_INTID;
			break;
		case GIC_IRQ_TYPE_LPI:	/* LPI */
			*hwirq = fwspec->param[1];
			break;
		case GIC_IRQ_TYPE_PARTITION:
			*hwirq = fwspec->param[1];
			if (fwspec->param[1] >= 16)
				*hwirq += EPPI_BASE_INTID - 16;
			else
				*hwirq += 16;
			break;
		default:
			return -EINVAL;
		}

		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;

		/*
		 * Make it clear that broken DTs are... broken.
		 * Partitionned PPIs are an unfortunate exception.
		 */
		WARN_ON(*type == IRQ_TYPE_NONE &&
			fwspec->param[0] != GIC_IRQ_TYPE_PARTITION);
		return 0;
	}

	if (is_fwnode_irqchip(fwspec->fwnode)) {
		if(fwspec->param_count != 2)
			return -EINVAL;

		*hwirq = fwspec->param[0];
		*type = fwspec->param[1];

		WARN_ON(*type == IRQ_TYPE_NONE);
		return 0;
	}

	return -EINVAL;
}

2 hw_irq和virq映射过程

2.1 hw_irq和virq映射的过程

|- irq_of_parse_and_map
	|- of_irq_parse_one
	|- irq_create_of_mapping
		|- irq_create_fwspec_mapping
			|- virq = irq_find_mapping(domain, hwirq);
			|- virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec)
				|- __irq_domain_alloc_irqs
					|- irq_domain_alloc_descs
						|- __irq_alloc_descs
							|- start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, from, cnt, 0);
							|- ret = alloc_descs(start, cnt, node, affinity, owner)
			|- irq_data = irq_get_irq_data(virq);
			|- irqd_set_trigger_type(irq_data, type);

2.2 irq_create_fwspec_mapping

irq_create_fwspec_mapping函数主要功能是由下面五个函数组成的

  • irq_domain_translate(domain, fwspec, &hwirq, &type),获取硬件中断号
  • virq = irq_find_mapping(domain, hwirq);,查看hw_irq是否已经被映射过
  • virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec),申请virq,该函数用于hw_irq和virq的映射处理
  • irq_data = irq_get_irq_data(virq); 根据virq获取irq_data
  • irqd_set_trigger_type(irq_data, type);,注册中断触发类型
unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
{
	struct irq_domain *domain;
	struct irq_data *irq_data;
	irq_hw_number_t hwirq;
	unsigned int type = IRQ_TYPE_NONE;
	int virq;

	if (fwspec->fwnode) {
		domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
		if (!domain)
			domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
	} else {
		domain = irq_default_domain;
	}

	if (!domain) {
		pr_warn("no irq domain found for %s !\n",
			of_node_full_name(to_of_node(fwspec->fwnode)));
		return 0;
	}

	if (irq_domain_translate(domain, fwspec, &hwirq, &type))
		return 0;

	/*
	 * WARN if the irqchip returns a type with bits
	 * outside the sense mask set and clear these bits.
	 */
	if (WARN_ON(type & ~IRQ_TYPE_SENSE_MASK))
		type &= IRQ_TYPE_SENSE_MASK;

	/*
	 * If we've already configured this interrupt,
	 * don't do it again, or hell will break loose.
	 */
	virq = irq_find_mapping(domain, hwirq);
	if (virq) {
		/*
		 * If the trigger type is not specified or matches the
		 * current trigger type then we are done so return the
		 * interrupt number.
		 */
		if (type == IRQ_TYPE_NONE || type == irq_get_trigger_type(virq))
			return virq;

		/*
		 * If the trigger type has not been set yet, then set
		 * it now and return the interrupt number.
		 */
		if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) {
			irq_data = irq_get_irq_data(virq);
			if (!irq_data)
				return 0;

			irqd_set_trigger_type(irq_data, type);
			return virq;
		}

		pr_warn("type mismatch, failed to map hwirq-%lu for %s!\n",
			hwirq, of_node_full_name(to_of_node(fwspec->fwnode)));
		return 0;
	}

	if (irq_domain_is_hierarchy(domain)) {
		virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
		if (virq <= 0)
			return 0;
	} else {
		/* Create mapping */
		virq = irq_create_mapping(domain, hwirq);
		if (!virq)
			return virq;
	}

	irq_data = irq_get_irq_data(virq);
	if (!irq_data) {
		if (irq_domain_is_hierarchy(domain))
			irq_domain_free_irqs(virq, 1);
		else
			irq_dispose_mapping(virq);
		return 0;
	}

	/* Store trigger type */
	irqd_set_trigger_type(irq_data, type);

	return virq;
}
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-24 18:35:01  更:2022-05-24 18:36:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 16:02:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码