linux-5.10.110内核源码分析 - Freescale ls1012a pcie msi中断

news2024/9/21 4:37:19

1、dts msi控制器描述

1.1、dts描述

msi: msi-controller1@1572000 {
        compatible = "fsl,ls1012a-msi";
        reg = <0x0 0x1572000 0x0 0x8>;
        msi-controller;
        interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>;
};

        ls1012a msi控制器具体介绍可以参考官网手册”25.1.1 PCI Express MSI implementation
“,直接注册账号即可下载芯片手册。

1.2、说明

        msi中断控制器中断号为126(这里需要加上32,具体内核会根据中断类型加上一个32的偏移,前面32个中断号为SGI、PPI,SPI实际中断为128,计算过程可以看内核其他代码)

        有两个寄存器,Shared Message Signaled Interrupt Index Register和Shared Message Signaled Interrupt Register,pcie设备往Shared Message Signaled Interrupt Index Register写数据触发中断,cpu读Shared Message Signaled Interrupt Register清除中断,根据代码Shared Message Signaled Interrupt Register里面还包含中断信息,具体介绍参考芯片手册的“11.2.39 Shared message signaled interrupt register (PEX1MSIR)
”。

        (里面的寄存器地址1571000地址不太清楚是不是写错了,根据调试内核代码以及dts描述,似乎应该是1572000)

2、msi寄存器映射

2.1、msi寄存器映射

        寄存器0x1572000映射调用栈如下,phys_addr也就是0x1572000,msi寄存器的基地址,size为8,与dts描述一致:

2.2、MSI-X Capability查找

        内核调用__pci_bus_find_cap_start获取第一个capability的地址,函数调用栈及代码如下:

        上面函数栈返回PCI_CAPABILITY_LIST,也就如下Capabilities Pointer寄存器在配置空间的偏移34h,Capabilities Pointer指向第一个capability,每个capability有一个指针有个Next Capability Offset,指向下一个capability,Capabilities Pointer即可遍历pcie的所有capability:

        对于msix的Capability ID为PCI_CAP_ID_MSIX,查找msix的capability的过程就是根据前面获取到Capabilities Pointer遍历capability,找到Capability ID为PCI_CAP_ID_MSIX的capability,代码如下:

static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
				   u8 pos, int cap, int *ttl)
{
	u8 id;
	u16 ent;

	pci_bus_read_config_byte(bus, devfn, pos, &pos);

	while ((*ttl)--) {
		if (pos < 0x40)
			break;
		pos &= ~3;
		pci_bus_read_config_word(bus, devfn, pos, &ent);

		id = ent & 0xff;
		if (id == 0xff)
			break;
		if (id == cap)
			return pos;
		pos = (ent >> 8);
	}
	return 0;
}

        ttl参数与网络一样,最多查找次数,超过*ttl指定的次数就接收查找;”pci_bus_read_config_byte(bus, devfn, pos, &pos)“获取capability在配置空间的地址,”pci_bus_read_config_word(bus, devfn, pos, &ent)“读取配置空间,里面包含Capability ID以及下一个capability的在配置空间的偏移,如下所示。

        __pci_find_next_cap_ttl获取到一个capability的Capability ID之后,检查是否是需要查找的,如果不是查找的,则根据当前capability的Next Capability Offset读取下一个capability,直到找到对应Capability ID的capability或者*ttl减为0。找到之后返回capability在配置空间的偏移,结果保存到dev->msix_cap。

2.3、MSI-X Capability配置

        MSI-X Capability Structures结构如下:

MSI-X Table Structure结构如下:

        内核msix_map_region函数将MSI-X Table映射到虚拟地址,从代码看,MSI-X Table是在某个BAR空间里面,bir也就是BAR编号,pci_resource_start也就是获取bir BAR资源的起始地址,也就是cpu域地址,加上MSI-X Table的偏移table_offset即为MSI-X Table的cpu域地址,映射完之后,就可以通过虚拟地址访问MSI-X Table,虚拟地址将保存到msi_desc的mask_base里面,函数及调用栈如下,具体协议相关可以参考《PCI Local Bus Specification Revision 3.0》”6.8.2. MSI-X Capability and Table Structures“:

static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries)
{
	resource_size_t phys_addr;
	u32 table_offset;
	unsigned long flags;
	u8 bir;

	pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE,
			      &table_offset);
	bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
	flags = pci_resource_flags(dev, bir);
	if (!flags || (flags & IORESOURCE_UNSET))
		return NULL;

	table_offset &= PCI_MSIX_TABLE_OFFSET;
	phys_addr = pci_resource_start(dev, bir) + table_offset;

	return ioremap(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
}

2.4、写MSI-X Table

        内核调用__pci_write_msi_msg写MSI-X Table,告诉pcie设备,往哪个地址发送消息,这里就是要把msi控制寄存器的地址写到MSI-X Table里面,函数调用栈如下:

        写MSI-X Table代码如下,其中base通过pci_msix_desc_addr获取,也就是前面msix_map_region映射后的MSI-X Table的虚拟地址;将msi控制器寄存器的高低地址以及Message Data分别写入,MSI-X Table,代码如下:

2.5、MSI-X中断使能

        写Vector Control for MSI-X Table Entries使能/禁止中断,为1时禁止中断,为0时使能中断,Vector Control for MSI-X Table Entries详细说明如下:

        函数代码及调用栈如下:

u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag)
{
	u32 mask_bits = desc->masked;
	void __iomem *desc_addr;

	if (pci_msi_ignore_mask)
		return 0;

	desc_addr = pci_msix_desc_addr(desc);
	if (!desc_addr)
		return 0;

	mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
	if (flag & PCI_MSIX_ENTRY_CTRL_MASKBIT)
		mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;

	writel(mask_bits, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);

	return mask_bits;
}

        简单来说就是根据前面映射的MSI-X Table虚拟地址,找到Vector Control,然后往里面写0或者1。

3、中断处理

3.1、申请中断号ls_scfg_msi_domain_irq_alloc

        首先设备驱动会申请一个虚拟中断号,然后调用ls_scfg_msi_domain_irq_alloc申请一个msi物理中断号,最后调用irq_domain_get_irq_data获取virq对应的irq_data,填充物理中断号等信息,物理中断号信息最终保存在irq_data里面,调用栈如下:

        irq_domain_set_hwirq_and_chip代码如下:

3.2、中断号设置__pci_write_msi_msg

        msi_domain_activate激活中断时,调用ls_scfg_msi_compose_msg设置msg,ls_scfg_msi_compose_msg的data参数也就是前面virq虚拟中断号对应的irq_data,从里面取出物理中断号,写到消息里面,代码如下:

static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
{
	struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data);

	msg->address_hi = upper_32_bits(msi_data->msiir_addr);
	msg->address_lo = lower_32_bits(msi_data->msiir_addr);
	msg->data = data->hwirq;

	if (msi_affinity_flag) {
		const struct cpumask *mask;

		mask = irq_data_get_effective_affinity_mask(data);
		msg->data |= cpumask_first(mask);
	}

	iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
}

        设置好消息之后,需要把消息写MSI-X Table,调用栈及函数代码如下:

        (上面调用栈是初始化时的调用栈,在网卡open的时候,还会设置,过程是一样的)

3.3、 msi中断控制器中断ls_scfg_msi_irq_handler

        msi中断号为158,中断处理函数为ls_scfg_msi_irq_handler,调用栈如下:

        ls_scfg_msi_irq_handler中断处理代码如下,主要就是读msi寄存器,遍历为1的比特位,通过为1的比特位的位置计算对应的硬件中断号,然后根据硬件中断号获取虚拟中断号,最后调用对应的中断处理函数:

        (芯片手册“11.2.39 Shared message signaled interrupt register (PEX1MSIR)
”及其他章节暂时没有找到具体寄存器与中断号的计算关系,只能从代码上推理)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 中的 DDL、DML、DQL 和 DCL

文章目录 1. 数据定义语言&#xff08;DDL&#xff09;2. 数据操作语言&#xff08;DML&#xff09;3. 数据查询语言&#xff08;DQL&#xff09;4. 数据控制语言&#xff08;DCL&#xff09;总结 在 MySQL 数据库管理系统中&#xff0c;SQL 语句可以根据其功能分为不同的类别&…

玫瑰千层烤饼:味蕾的芬芳盛宴

在美食的缤纷世界里&#xff0c;有一种独特的存在&#xff0c;它融合了玫瑰的芬芳与烤饼的酥脆&#xff0c;那便是令人陶醉的甘肃美食玫瑰千层烤饼。食家巷玫瑰千层烤饼&#xff0c;宛如一件精心雕琢的艺术品。每一层薄如纸张的面皮&#xff0c;都承载着制作者的细腻与用心。层…

GD32实战篇-双向数控BUCK-BOOST-BOOST升压理论基础

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 向上代码兼容GD32F450ZGT6中使用 后续项目主要在下面该专栏中发布&#xff1a; https://blog.csdn.net/qq_62316532/category_12608431.html?spm1001.2014.3001.5482 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转…

JavaWeb-【1】HTML

笔记系列持续更新,真正做到详细!!本次系列重点讲解后端,那么第一阶段先讲解前端 目录 1、Javaweb技术体系 2、BS架构说明 3、官方文档 4、网页组成 5、HTML 6、HTML快速入门 7、HTML基本结构 8、HTML标签 ​9、HTML标签使用细节 ①、font标签 ②、字符实体 ③、标…

【在Linux世界中追寻伟大的One Piece】HTTPS协议原理

目录 1 -> HTTPS是什么&#xff1f; 2 -> 相关概念 2.1 -> 什么是"加密" 2.2 -> 为什么要加密 2.3 -> 常见的加密方式 2.4 -> 数据摘要 && 数据指纹 2.5 -> 数字签名 3 -> HTTPS的工作过程 3.1 -> 只使用对称加密 3.2 …

Django之项目开发(一)

一、项目的生命周期介绍 传统Web 项目的生命周期指的是从开始构建一个网站到该网站完成并维护的整个过程。通常情况下,Web 项目的生命周期包括以下几个阶段 需求分析阶段:在这个阶段,项目组会与客户进行沟通,确定网站的功能、内容和设计。 主要由产品经理参与产出思路与方案…

谷粒商城学习笔记-逆向工程错误记录

文章目录 1&#xff0c;Since Maven 3.8.1 http repositories are blocked.1.1 在maven的settings.xml文件中&#xff0c;新增如下配置&#xff1a;1.2&#xff0c;执行clean命令刷新maven配置 2&#xff0c;internal java compiler error3&#xff0c;启动逆向工程报错&#x…

【qt】获取主机信息系统

话不多说,先一睹芳颜! 如果你也想达到这种效果,那咱们就开始吧! 目录 一.登录界面设计1.ui登录设计 二.加载界面1.lineEdit的密码输入模式2.lineEdit按回车跳转的信号3.密码的判断4.创建加载界面5.创建定时器来进行进度条的移动6.定时器执行的槽函数 三.主机信息界面1.主机信息…

软件系统架构的一些常见专业术语

分层架构是逻辑上的&#xff0c;在物理部署上&#xff0c;三层结构可以部署在同一个物理机器上&#xff0c;但是随着网站业务的发展&#xff0c;必然需要对已经分层的模块分离部署&#xff0c;即三层结构分别部署在不同的服务器上&#xff0c;使网站拥有更多的计算资源以应对越…

瑞芯微rk356x TF卡烧写选择指定的屏幕打印烧写的过程

rk356x中TF卡烧写屏幕选择 1、开发环境2、问题描述3、解决办法4、总结5、 图片展示1、开发环境 系统:linux系统 芯片:356x 显示:多屏显示(HDMI, MIPI, LVDS, EDP) 2、问题描述 由于在多屏显示的情况下,HDMI屏在LVDS、MIPI或者EDP协同下,默认情况下,在TF卡烧录过程中…

QT——Excel实现自绘区域选择边框

文章目录 一、自绘区域边框1.1、效果展示2.2、问题整理2.2.1、重绘单元格选择区2.2.2、选择区域的大小 一、自绘区域边框 1.1、效果展示 单选 多选 2.2、问题整理 2.2.1、重绘单元格选择区 误区: 继承QStyledItemDelegate重写paint,测试发现只能在单元格内绘制。 通过继…

秋招力扣刷题——从前序与中序遍历序列构造二叉树

一、题目要求 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 二、解法思路 根据二叉树的遍历结构重构二叉树&#xff0c;至少两种遍历方式结合&…

操作系统智能助手OS Copilot评测报告

背景 如果不是朋友告知&#xff0c;我还不知道阿里云推出了【操作系统智能助手OS Copilot】这样一款产品。 我做系统运维的工作还是挺多的&#xff0c;知道系统运维工作的一些痛点&#xff1b;例如&#xff1a; Linux命令繁杂&#xff0c;想全部记住不太可能&#xff0c;多数…

自注意力 公式解释

公式 (\mathbf{y}_i f(\mathbf{x}_i, (\mathbf{x}_1, \mathbf{x}_1), \ldots, (\mathbf{x}_n, \mathbf{x}_n)) \in \mathbb{R}^d) 描述了自注意力机制中单个词元的输出表示如何生成。我们来逐步解释这个公式&#xff1a; 输入序列 (\mathbf{x}_1, \mathbf{x}_2, \ldots, \math…

MySQL之备份与恢复(八)

备份与恢复 还原逻辑备份 如果还原的是逻辑备份而不是物理备份&#xff0c;则与使用操作系统简单地复制文件到适当位置的方式不同&#xff0c;需要使用MySQL服务器本身来加载数据到表中。在加载导出文件之前&#xff0c;应该先花一点时间考虑文件有多大&#xff0c;需要多久加…

数据结构--二叉树和堆

目录 1.基本概念 2.树的遍历方法 3.满二叉树&&完全二叉树 4.逻辑结构&&物理结构 5.推理公式 6.二叉树应用--堆 7.简单实现堆 1.基本概念 &#xff08;1&#xff09;这个里面的概念还是比较多的&#xff0c;但是大部分我们只需要了解即可&#xff0c;因为…

如何实现一套键盘鼠标控制两台计算机(Mouse Without Borders快速上手教程)

需求背景 当我们需要同时使用一台主机和一台笔记本的时候&#xff0c;如果使用两套键盘和鼠标分别操作各自的系统&#xff0c;非常地不便捷且非常占据桌面空间。那么如何使用一套键盘鼠标控制两台电脑呢&#xff1f; 需求实现 软件说明 我们可以使用微软官方的一款软件Mous…

vscode使用Git的常用操作

主打一个实用 查看此篇之前请先保证电脑安装了Git&#xff0c;安装教程很多&#xff0c;可自行搜索 一.初始化本地仓库&#x1f534; 使用vscode打开项目文件夹如图所使初始化仓库&#xff0c;相当于命令行的git init 二.提交到暂存区&#x1f534; 二.提交到新版本&#x1f…

07浅谈大语言模型可调节参数tempreture

浅谈temperature 什么是temperature&#xff1f; temperature是大预言模型生成文本时常用的两个重要参数。它的作用体现在控制模型输出的确定性和多样性&#xff1a; 控制确定性&#xff1a; temperature参数可以控制模型生成文本的确定性&#xff0c;大部分模型中temperatur…

RabbitMq - Java客户端基础【简单案例 +Work模型】

目录 1、前置知识 1.1、AMQP怎么理解 1.2、Spring AMQP是什么 1.3、为什么要了解Spring-AMQP&#xff1f; 2、使用Spring-AMQP实现一个发消息案例 3、Work模型 问题&#xff1a; 优化&#xff1a; 小结&#xff1a;Work模型的使用&#xff1a; 1、前置知识 1.1、AMQP怎…