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

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)
”及其他章节暂时没有找到具体寄存器与中断号的计算关系,只能从代码上推理)

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

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

相关文章

【cocos creator】2.x,伪3d拖拽,45度视角,60度视角,房屋装扮

伪3d拖拽,45度视角,60度视角 工程下载:(待审核) https://download.csdn.net/download/K86338236/89530812 dragItem2.t s import mapCreat2 from "./mapCreat2";const {ccclass, property } = cc._decorator; /*** 拖拽类,挂在要拖拽的节点上*/ @ccclass export…

电影购票小程序论文(设计)开题报告

一、课题的背景和意义 随着互联网技术的不断发展&#xff0c;人们对于购票的需求也越来越高。传统的购票方式存在着排队时间长、购票流程繁琐等问题&#xff0c;而网上购票则能够有效地解决这些问题。电影购票小程序是网上购票的一种新型应用&#xff0c;它能够让用户随时随地…

MacOS可以玩什么游戏 苹果笔记本电脑能打游戏吗 macbook能打什么游戏

长期以来&#xff0c;Mac电脑在游戏方面的局限性一直是用户关注的问题。在最新的 macOS Sonoma 14 系统中&#xff0c;苹果首次引入了全新的 Game mode&#xff08;游戏模式&#xff09;&#xff0c;将 M 系列芯片的超强能力在游戏中进一步释放&#xff01; Mac 不能玩游戏的难…

Fragment(未完结)

什么是Fragment? 1:具备生命周期,小Activity 2:必须委托在activity中才能运行 Fragment初体验 1、创建fragment_blank.xml <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools&qu…

一进四出学生公寓电表功能对比

一进四出学生公寓对比石家庄光大远通电气有限公司产品使用功能&#xff1a;预收费功能&#xff1a;用户应先到学校购电处购电,售电计算机将在十秒钟内自动将数据发送到控电柜各个用电单元,然后系统会给用户供电,当用户剩余电量为零时,系统可自动切断该单元供电,只有当用户重新购…

MYSQL审批流程判断同一层级审批人是否全部通过审批

在做流程审批的时候&#xff0c;通常会出现某一层有多个审批人的情况&#xff0c;这个时候需要所有人都通过才会进入到下一步 数据结构如下图表格所示 每一个审批申请对应一个apply_id serial_no相同的代表是同一层级审批人 approval_status是审核状态 下面我们可以用一个SQL来…

[leetcode]circular-array-loop 环形数组是否存在循环

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:bool circularArrayLoop(vector<int>& nums) {int n nums.size();auto next [&](int cur) {return ((cur nums[cur]) % n n) % n; // 保证返回值在 [0,n) 中};for (int i 0; i < n; i…

【UE5.1】NPC人工智能——01 准备NPC角色

效果 步骤 1. 之前我们已经创建了“BP_NPC”&#xff08;见&#xff1a;【UE5.1 角色练习】06-角色发射火球-part2&#xff09; 该蓝图继承于角色类 我们在该蓝图中添加了两个方法和两个变量。方法一个是用于修改角色HP值的&#xff0c;另一个是在收到伤害后执行的逻辑。两个…

AIGC爬虫类代码示例:Scrapy和OpenAI API实现抓取内容并生成内容

对于我从事爬虫行业多年的经验来说&#xff0c;编程各种需求代码真是非常吃力且细致的活&#xff0c;随着AI的大火&#xff0c;我在设想有没有可能通过AI自动化程序实现自动抓取生成想要的文本内容。前提我是打算通过结合爬虫技术&#xff08;如Scrapy&#xff09;和生成式AI模…

Affnity 值得购买吗?有Affinity 优惠码?

今年&#xff0c;Affinity 提供了全场 7 折优惠活动&#xff0c;这里包括桌面应用、插件、工作手册等内容&#xff0c;另外针对 iPad 应用提供更为给力的 5 折优惠&#xff01;对于从事图形设计、排版的用户来说&#xff0c;由于 Affinity 的创意设计应用均采用了一次买断制&am…

如何在函数中使用return返回axios的请求结果

使用场景&#xff1a;在添加学生上课记录的时候&#xff0c;需要先获取学生的剩余课时&#xff0c;需要通过接口获取。所以需要封装一个方法&#xff0c;能够通过接口获取学生的课时数量。 解决方案&#xff1a;通过异步解决 封装方法的代码如下&#xff1a; const getStude…

Linux--安装VMware步骤

安装VMware VMware Desktop Hypervisors for Windows, Linux, and Mac 复制链接打开浏览器下载即可 从官网下载软件&#xff0c;完成后为确保后续正常使用&#xff0c;需要检查虚拟网卡是否安装完成 检查虚拟网卡的安装步骤 Windows--设置--高级设置--网络适配器--看是否有显…

浅谈后置处理器组件提取器相关的Apply to

浅谈后置处理器组件提取器相关的Apply to 在Apache JMeter中&#xff0c;“提取器”&#xff08;通常指的是正则表达式提取器、JSON路径提取器或CSS/JQuery提取器等&#xff09;是用来从服务器响应中提取信息的重要组件。这些信息可以是cookies、session IDs、特定的文本或者任…

Nuxt框架中内置组件详解及使用指南(五)

title: Nuxt框架中内置组件详解及使用指南&#xff08;五&#xff09; date: 2024/7/10 updated: 2024/7/10 author: cmdragon excerpt: 摘要&#xff1a;本文详细介绍了Nuxt框架中和组件的使用方法与配置&#xff0c;包括安装、基本用法、属性详解、示例代码以及高级功能如…

纹波电流与ESR:解析电容器重要参数与应用挑战

电解电容纹波电流与ESR&#xff08;Equivalent Series Resistance&#xff09;是电容器的重要参数&#xff0c;用来描述电容器对交流信号的响应能力和能量损耗。电解电容纹波电流是指电容器在工作时承受的交流信号电流&#xff0c;而ESR则是电容器内部等效电阻&#xff0c;影响…

tensorflow1.基础案例2

前言 在TensorFlow 1.x中实现线性回归通常指的是使用静态图的方式&#xff0c;而在TensorFlow 1.x中使用Eager API实现线性回归是在TensorFlow 1.x的晚期版本中引入的&#xff0c;以提供类似于TensorFlow 2.x的编程体验。以下是两种方式的区别、各自的优点以及对比的作用&…

Linux下fcitx框架输入法输入中文标点时为半角(英文)标点符号的解决

目录 引入解决1.打开fcitx设置2.打开全局配置3. 随便找个可以输入地方敲下快捷键 总结 本文由Jzwalliser原创&#xff0c;发布在CSDN平台上&#xff0c;遵循CC 4.0 BY-SA协议。 因此&#xff0c;若需转载/引用本文&#xff0c;请注明作者并附原文链接&#xff0c;且禁止删除/修…

轻松搭建系统,让每个故事都精彩绽放!

"轻松搭建系统&#xff0c;让每个故事都精彩绽放&#xff01;" 这句话传递了一个核心理念&#xff0c;即通过简化、高效的系统搭建过程&#xff0c;让每一个创意故事都能以最佳状态呈现给观众&#xff0c;实现其独特魅力和价值的最大化。 1、模块化设计&#xff1a;系…

CV06_Canny边缘检测算法和python实现

1.1简介 Canny边缘检测算法是计算机视觉和图像处理领域中一种广泛应用的边缘检测技术&#xff0c;由约翰F坎尼&#xff08;John F. Canny&#xff09;于1986年提出。它是基于多级处理的边缘检测方法&#xff0c;旨在实现以下三个优化目标&#xff1a; 好的检测&#xff1a;尽…

机器学习第四十七周周报 CF-LT

文章目录 week47 CF-LT摘要Abstract1. 题目2. Abstract3. 网络结构3.1 CEEMDAN&#xff08;完全自适应噪声集合经验模态分解&#xff09;3.2 CF-LT模型结构3.3 SHAP 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程 5. 结论6.代码复现小结参考文献 week47 CF-LT 摘要 本周…