【C语言】InfiniBand 驱动mlx4_ib_init和mlx4_ib_cleanup

一、中文讲解

这两个函数是Linux内核模块中对于Mellanox InfiniBand 驱动程序初始化和清理的函数。
mlx4_ib_init()函数是模块初始化函数,使用__init宏标注,表示该函数只在模块加载时运行一次。
函数执行的步骤如下:
1. 通过alloc_ordered_workqueue创建一个有序的工作队列wq。这个队列用于将工作项按顺序排队执行,WQ_MEM_RECLAIM表示如果系统内存紧张,允许回收。
   如果工作队列创建失败,返回-ENOMEM错误码,表示内存不足。
2. 在编译时,如果定义了CONFIG_MLX4_IB_DEBUG_FS,则会调用mlx4_ib_register_debugfs函数注册调试文件系统(debugfs),这有助于查询和操作驱动程序的内部信息。
3. 调用mlx4_ib_mcg_init函数初始化多播组(multi-cast group)的一些资源,如果初始化失败,则跳转到标签clean_wq进行清理。
4. 执行init_dev_assign函数,这个函数虽然没有代码显示,但从名称上看,它可能用于初始化设备或分配相应资源。
5. 注册InfiniBand接口到Mellanox的InfiniBand核心驱动,使用的函数为mlx4_register_interface。如果注册失败,会跳转到标签clean_mcg进行清理。
6. 如果所有初始化步骤都成功,函数返回0,表示初始化成功。
如果在任何一步发生错误,函数会执行清理操作:
- clean_mcg: 清除通过mlx4_ib_mcg_init初始化的多播组资源。
- clean_wq: 销毁之前创建的工作队列wq。
mlx4_ib_cleanup()函数是模块清理函数,使用__exit宏标注,表示这个函数在模块卸载时调用。
函数的步骤如下:
1. 调用mlx4_unregister_interface来注销之前注册的Mellanox InfiniBand接口。
2. 如果CONFIG_MLX4_IB_DEBUG_FS被定义,则调用mlx4_ib_unregister_debugfs注销调试文件系统。
3. 调用mlx4_ib_mcg_destroy销毁在模块初始化时创建的多播组资源。
4. 销毁之前创建的工作队列wq。
5. 释放dev_num_str_bitmap,这个变量可能用于跟踪设备编号的分配,但代码段中没有展示它的分配过程。
module_init(mlx4_ib_init);和module_exit(mlx4_ib_cleanup);是宏定义,它们告诉内核模块初始化和退出时应该调用哪些函数。

在 Linux 驱动开发中,mlx4_ib_interface 是一个 mlx4_interface 类型的结构体,它实现了 InfiniBand (IB) 协议栈接口的特定函数。这个结构定义了几个回调函数,这些函数是由底层的 Mellanox 网络设备驱动(通常是 mlx4_core 驱动)在特定事件发生时被调用的。
这些回调函数包括:
- add - 当新设备被添加时调用(例如,当一个新的网络适配器被系统探测到时)。
- remove - 用于当设备被移除时做清理工作。
- event - 当设备关联的事件发生时被调用,例如链接状态改变、硬件错误等。
- protocol - 指定这个接口支持哪种协议(在此示例中是 MLX4_PROT_IB_IPV6,代表 InfiniBand 协议的 IPv6 over IB 版本)。
- flags - 提供额外的信息标志,本例中使用了 MLX4_INTFF_BONDING 标志,表示支持网络接口绑定(bonding)功能。
这个结构体被注册到低层的 mlx4_core 驱动,它是 Mellanox 网络设备的一个核心驱动,提供了基础硬件抽象层的功能。注册后,它成为 mlx4_core 驱动和高层驱动(本例中的 mlx4_ib)之间沟通的桥梁。
mlx4_ib_interface 被注册的地方是在 mlx4_ib_init() 函数,这通常是作为模块初始化的一部分。当 mlx4_ib_init() 函数成功执行后,mlx4_ib 成为 mlx4_core 驱动感知到的一个客户端。
以下是 mlx4_ib_interface 回调函数被调用的时机:
- mlx4_ib_add -  当注册 mlx4_ib_interface 到 mlx4_core 后,如果 mlx4_core 驱动发现一个新的设备,mlx4_core 将调用 mlx4_ib 的 add 回调函数。
- mlx4_ib_remove - 当一个设备需要被移除,可能是因为硬件被物理移除或是模块正在被卸载,remove 回调函数将被调用。
- mlx4_ib_event - 当 mlx4_core 检测到某个事件发生并需要通知 mlx4_ib 模块时,event 回调函数会被调用。
在 mlx4_core 的代码中,会在适当的位置调用 mlx4_ib_interface 结构体中指定的函数,以便在上述事件发生时,正确地通知 InfiniBand 协议栈进行相关操作。这种设计允许 mlx4_core 驱动与多个协议栈(如以太网和 InfiniBand)独立协作,同时保持模块间的松耦合。

在 Linux 内核中,mlx4_core 驱动发现新设备的过程通常涉及 Linux 的 PCI 子系统。mlx4_core` 驱动是 PCI 驱动的一个实现,它注册了一系列的回调函数来处理特定于 PCI 设备的事件。下面是一个简化的描述,解释了驱动程序如何发现新的 PCI 设备:
1. PCI 设备枚举: 当系统启动时,或当新的设备被添加到系统中时(如通过热插拔),PCI 子系统将识别并枚举所有的 PCI 设备。它创建代表这些设备的数据结构,并读取它们的配置空间来获取诸如供应商ID、设备ID、类别码等信息。
2. 驱动注册: 一个 PCI 驱动程序,比如 mlx4_core,会在加载时调用 pci_register_driver() 函数来注册自己。这个注册过程包括提供一个 pci_driver 类型的结构体,该结构体包含对应的供应商ID和设备ID,以及针对新设备的回调函数,如 .probe。

    static struct pci_driver mlx4_pci_driver = {.name = DRV_NAME,.id_table = mlx4_pci_table,.probe = mlx4_probe,.remove = mlx4_remove,// ... 其他回调函数};

    这里的 mlx4_pci_table 包含了 mlx4_core 驱动支持的设备对应的供应商ID和设备ID列表。mlx4_probe 和 mlx4_remove 是当设备被探测到或移除时要调用的函数。
3. 设备和驱动匹配: 一旦驱动注册了自己,PCI 子系统就会遍历所有的 PCI 设备,尝试找出设备ID和供应商ID与驱动中 id_table 匹配的设备。对于每个匹配的设备,PCI 子系统会调用对应驱动的 .probe 回调函数。
4. 设备初始化 (mlx4_probe): 用于 mlx4_core 驱动的 probe 函数通常名为 mlx4_probe。当一个与 mlx4_pci_table 匹配的 Mellanox 设备被探测到时,mlx4_probe 会被调用。在 mlx4_probe 函数内部,驱动程序会执行必要的初始化步骤,如申请资源、设置设备、注册网络设备接口,如果有 InfiniBand 部分,也会在这个时候注册 mlx4_ib_interface 接口。
5. 接口注册: 注册过程可能涉及调用 mlx4_register_interface() 函数,这是 mlx4_core 提供的接口,允许常见的 Mellanox InfiniBand 和以太网功能扩展。这个注册函数会存储一个指向 mlx4_interface 结构体的指针,使得在交互式事件中,mlx4_core 驱动能够调用必要的回调函数。
通过上述流程,mlx4_core 驱动能够发现新的设备并与相关的协议接口(如 mlx4_ib_interface)进行通信,完成设备初始化和事件通知。

二、中文注释

这段代码是一个Linux内核模块的初始化和清除函数,在kernel-4.9\drivers\infiniband\hw\mlx4\main.c文件中,涉及到Mellanox技术的InfiniBand驱动的mlx4子系统。

// Linux内核模块的初始化函数
static int __init mlx4_ib_init(void)
{int err;// 为名为"mlx4_ib"的workqueue申请有序工作队列,WQ_MEM_RECLAIM标志表示该工作队列支持内存回收wq = alloc_ordered_workqueue("mlx4_ib", WQ_MEM_RECLAIM);// 如果工作队列创建失败,则返回内存不足的错误代码if (!wq)return -ENOMEM;// 如果定义了CONFIG_MLX4_IB_DEBUG_FS编译选项,注册调试文件系统#ifdef CONFIG_MLX4_IB_DEBUG_FSmlx4_ib_register_debugfs();#endif// 初始化多播组。如果初始化失败,则跳转到clean_wq标签进行清理工作。err = mlx4_ib_mcg_init();// 如果初始化多播组出错,跳到clean_wq的清理流程if (err)goto clean_wq;// 初始化设备分配相关工作。init_dev_assign();// 注册接口到mlx4核心。如果注册失败,则跳转到clean_mcg标签进行多播组清理工作err = mlx4_register_interface(&mlx4_ib_interface);if (err)goto clean_mcg;// 初始化成功,返回0return 0;clean_mcg:// 清理多播组mlx4_ib_mcg_destroy();clean_wq:// 销毁之前创建的工作队列destroy_workqueue(wq);// 返回错误代码return err;
}// Linux内核模块的清除函数,用于在模块卸载时被调用
static void __exit mlx4_ib_cleanup(void)
{// 注销mlx4接口mlx4_unregister_interface(&mlx4_ib_interface);// 如果定义了CONFIG_MLX4_IB_DEBUG_FS编译选项,注销调试文件系统#ifdef CONFIG_MLX4_IB_DEBUG_FSmlx4_ib_unregister_debugfs();#endif// 清理多播组mlx4_ib_mcg_destroy();// 销毁工作队列destroy_workqueue(wq);// 释放之前分配的设备号位图存储空间kfree(dev_num_str_bitmap);
}// 指定模块加载时调用的初始化函数
module_init(mlx4_ib_init);
// 指定模块卸载时调用的清除函数
module_exit(mlx4_ib_cleanup);

这些函数是驱动模块的生命周期钩子,module_init用于表明模块加载时应当调用的函数,而module_exit用于指定模块卸载时的清理函数。__init和__exit宏在内核模块编译时有特殊含义,它们用于优化模块的初始化和退出代码。__init标记的代码在模块加载后不再需要,可以被丢弃;__exit标记的代码在构建内核为非模块支持时丢弃。

三、Linux内核"接口(interface)"机制

在Linux内核中,通过一种称为"接口(interface)"的机制允许不同的驱动程序之间相互沟通。对于Mellanox设备,这可能涉及到mlx4_core模块和mlx4_ib模块之间的交互,分别对应于以太网(Ethernet)和InfiniBand子系统。
在这个上下文中,一个mlx4_core的实例在被PCI子系统探测到后会进行初始化,并且注册到mlx4_core模块的内部数据结构中。这个注册过程中,mlx4_core会公布一系列对于外部模块(如mlx4_ib InfiniBand实现)可以调用的回调函数。
这些回调函数定义在mlx4_interface结构中,如:

static struct mlx4_interface mlx4_ib_interface = {.add = mlx4_ib_add,.remove = mlx4_ib_remove,.event = mlx4_ib_event,.protocol = MLX4_PROT_IB_IPV6,.flags = MLX4_INTFF_BONDING
};

核心思想是,这个结构会被注册到mlx4_core模块中。当mlx4_core模块中的一个设备完成基础初始化后,它会通知所有注册了的mlx4_interface实例。通过这种方式,当设备被添加(add)或被移除(remove)时,能够反过来触发mlx4_ib_add或mlx4_ib_remove函数的调用。

在添加(add)事件发生时,Ethernet驱动调用mlx4_ib_add,这个函数会负责为InfiniBand功能初始化必要的资源,如设置队列对、分配内存等。相应地,当移除(remove)事件发生时,会调用mlx4_ib_remove以清理InfiniBand相关的资源。

这种机制不仅仅限于设备的添加和移除,也可用于处理其他类型的事件,例如设备状态改变、错误处理等。最终,这允许不同的驱动模块能够同步设备的状态,并在多协议硬件上提供一致的服务。

在Linux内核中,"接口"是指允许不同组件或驱动程序之间沟通和交互的一种机制。这种机制通常包括一系列的函数指针、数据结构和协议,定义了组件之间的通信方式。以下是一些Linux内核中用于不同驱动程序之间相互沟通的接口机制:
1. 平台设备和驱动注册: 平台驱动和设备使用平台设备结构struct platform_device和平台驱动结构struct platform_driver,这两者都包含指向描述它们如何交互的数据结构的指针。设备通常注册它们自己的资源,如内存区域、DMA和中断。当平台设备注册时,核心代码会为匹配的驱动程序调用probe()函数,此时可以建立接口。
2. 设备模型(Device Model): Linux内核的设备模型是一种抽象层,允许内核代码以统一的方式来处理硬件设备。它定义了设备、驱动程序和总线(bus)之间的关系,并通过结构体和方法来描述它们的关系。例如,每个设备结构struct device可以关联一组用于设备操作的方法。
3. 文件操作接口:字符和块设备驱动程序使用文件操作结构`truct file_operations,该结构包含指向不同操作的函数指针(如open(), read(), write(), ioctl(), 等)。这样,用户空间应用可以通过标准的系统调用来与内核中的设备文件进行交互。
4. 网络层接口:网络设备使用网络设备结构struct net_device,通过这种结构,它们可以注册自己给网络子系统,并提供一系列操作函数,以进行网络数据包的发送和接收。
5. 总线类型: 内核定义了多种总线类型,比如PCI, USB, I2C等。每种总线类型都有自己的一套方法和协议,用于发现设备、匹配驱动程序、配置资源等。
6. 内核模块与符号导出: 如果驱动程序或内核模块需要让其它部分的内核代码使用它们提供的功能,它们可以通过EXPORT_SYMBOL或EXPORT_SYMBOL_GPL宏来导出符号(函数、变量的名字)。
7. 回调函数: 驱动程序与硬件通信时通常需要中断处理,内核提供注册中断处理函数的接口,允许驱动编写自己的中断服务例程。
通常,在专业的环境下,这些接口的使用都遵循严格的编程接口(API)和编程约定(ABI),确保了内核的模块和组件可以正确地与彼此通信。

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

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

相关文章

数据结构——lesson5栈和队列详解

hellohello~这里是土土数据结构学习笔记🥳🥳 💥个人主页:大耳朵土土垚的博客 💥 所属专栏:数据结构学习笔记 💥对于顺序表链表有疑问的都可以在上面数据结构的专栏进行学习哦~感谢大家的观看与…

ElasticSearch开篇

1.ElasticSearch简介 1.1 ElasticSearch(简称ES) Elasticsearch是用Java开发并且是当前最流行的开源的企业级搜索引擎。能够达到实时搜索,稳定,可靠,快速,安装使用方便。 1.2 ElasticSearch与Lucene的关…

模拟器抓HTTP/S的包时如何绕过单向证书校验(XP框架)

模拟器抓HTTP/S的包时如何绕过单向证书校验(XP框架) 逍遥模拟器无法激活XP框架来绕过单向的证书校验,如下图: ​​ 解决办法: 安装JustMePlush.apk安装Just Trust Me.apk安装RE管理器.apk安装Xposedinstaller_逍遥64位…

智能边缘小站 CloudPond(低延迟、高带宽和更好的数据隐私保护)

智能边缘小站 CloudPond(低延迟、高带宽和更好的数据隐私保护) 边缘小站的主要功能是管理用户在线下部署的整机柜设施,一个边缘小站关联一个华为云指定的区域和一个用户指定的场地,相关的资源运行状况监控等。 边缘计算 迈入5G和AI时代,新…

利用redis实现秒杀功能

6、秒杀优化 这个是 图灵 的redis实战里面的一个案例 6.1 秒杀优化-异步秒杀思路 我们来回顾一下下单流程 当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤…

基于单片机的红外遥控解码程序设计与实现

摘要:该文介绍基于士兰半导体芯片(SC6122)的红外发射遥控器,通过单片机解码程序,实现红外遥控信号的解码和接收。红外接收头与单片机特定的引脚连接,通过设置单片机定时计数器,采样来自红外接收头的高、低电平宽度解码遥控信号。该解码程序设计主要应用在LED数码显示控制…

电机的极数和槽数,机械角度和电角度,霍尔IC,内外转子

什么是电机的极数和槽数? 【第7集】② 正弦波驱动的转矩脉动、正弦电流的时序和相位变化、超前角控制(超前角调整)、正弦波驱动的各种波形 - 电源设计电子电路基础电源技术信息网站_罗姆电源设计R课堂 (rohm.com.cn) 下面为您介绍表示电机…

Java虚拟机(JVM)从入门到实战【上】

Java虚拟机(JVM)从入门到实战【上】,涵盖类加载,双亲委派机制,垃圾回收器及算法等知识点,全系列6万字。 一、基础篇 P1 Java虚拟机导学课程 P2 初识JVM 什么是JVM Java Virtual Machine 是Java虚拟机。…

3.2日-线性模型,基础优化方法,线性回归从零开始实现

3.2日-线性模型,基础优化方法,线性回归从零开始实现 1线性模型衡量预估质量训练数据总结2基础优化方法3 线性回归从零开始实现 1线性模型 衡量预估质量 训练数据 总结 2基础优化方法 梯度下降是一种优化算法,常用于机器学习和深度学习中&…

进程的信号

目录 信号(signal)入门 技术应用角度的信号 注意 用kill -l命令可以察看系统定义的信号列表 信号处理常见方式概览 产生信号 1.通过终端(键盘)按键产生信号 signal函数 2. 调用系统函数向进程发信号 kill 函数 raise 函数 3.由软件条件产生的信号 alarm 函数 4.硬…

(学习日记)2024.03.01:UCOSIII第三节 + 函数指针 (持续更新文件结构)

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…

Kubernetes: 本地部署dashboard

本篇文章主要是介绍如何在本地部署kubernetes dashboard, 部署环境是mac m2 下载dashboard.yaml 官网release地址: kubernetes/dashboard/releases 本篇文章下载的是kubernetes-dashboard-v2.7.0的版本,通过wget命令下载到本地: wget https://raw.githubusercont…

【Python】进阶学习:pandas--isin()用法详解

【Python】进阶学习:pandas–isin()用法详解 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程👈 希望得到您的订阅…

【NDK系列】Android tombstone文件分析

文件位置 data/tombstone/tombstone_xx.txt 获取tombstone文件命令: adb shell cp /data/tombstones ./tombstones 触发时机 NDK程序在发生崩溃时,它会在路径/data/tombstones/下产生导致程序crash的文件tombstone_xx,记录了死亡了进程的…

单细胞Seurat - 细胞聚类(3)

本系列持续更新Seurat单细胞分析教程,欢迎关注! 维度确定 为了克服 scRNA-seq 数据的任何单个特征中广泛的技术噪音,Seurat 根据 PCA 分数对细胞进行聚类,每个 PC 本质上代表一个“元特征”,它结合了相关特征集的信息。…

mysql5*-mysql8 区别

1.Mysql5.7-Mysql8.0 sysbench https://github.com/geekgogie/mysql57_vs_8-benchmark_scripts 1.读、写、删除更新 速度 512 个线程以后才会出现如下的。 2.删除速度 2.事务处理性能 3.CPU利用率 mysql8 利用率高。 4.排序 5.7 只能ASC,不能降序 数据越来越大

牢记于心单独说出来的知识点(后续会加)

第一个 非十进制(八进制,十六进制)写在文件中它本身就是补码,计算机是不用进行内存转换,它直接存入内存。(因为十六进制本身是补码,所以计算机里面我们看到的都是十六进制去存储) …

Qt 简约美观的加载动画 文本风格 第八季

今天和大家分享一个文本风格的加载动画, 有两类,其中一个可以设置文本内容和文本颜色,演示了两份. 共三个动画, 效果如下: 一共三个文件,可以直接编译 , 如果对您有所帮助的话 , 不要忘了点赞呢. //main.cpp #include "LoadingAnimWidget.h" #include <QApplic…

MySQL:开始深入其数据(一)DML

在上一章初识MySQL了解了如何定义数据库和数据表&#xff08;DDL&#xff09;&#xff0c;接下来我们开始开始深入其数据,对其数据进行访问&#xff08;DAL&#xff09;、查询DQL&#xff08;&#xff09;和操作(DML)等。 通过DML语句操作管理数据库数据 DML (数据操作语言) …

计算机网络之传输层 + 应用层

.1 UDP与TCP IP中的检验和只检验IP数据报的首部, 但UDP的检验和检验 伪首部 首部 数据TCP的交互单位是数据块, 但仍说TCP是面向字节流的, 因为TCP仅把应用层传下来的数据看成无结构的字节流, 根据当时的网络环境组装成大小不一的报文段.10秒内有1秒用于发送端发送数据, 信道…