【C语言】Infiniband驱动mlx4_init_one

news2024/11/17 4:25:46

一、注释

这是Linux内核中Mellanox Ethernet网卡驱动程序mlx4模块的一部分代码,主要用于初始化一个PCI设备。以下是其注释:

// 驱动的主结构体,包含了供PCI核心使用的勾子(hooks)
static struct pci_driver mlx4_driver = {
    .name        = DRV_NAME,                 // 驱动名称
    .id_table    = mlx4_pci_table,          // 支持的PCI设备ID表
    .probe        = mlx4_init_one,           // 初始化一个PCI设备时调用的函数
    .shutdown    = mlx4_shutdown,           // 关闭设备时调用的函数
    .remove        = mlx4_remove_one,         // 移除设备时调用的函数
    .suspend    = mlx4_suspend,            // 暂停设备时调用的函数
    .resume        = mlx4_resume,             // 恢复设备时调用的函数
    .err_handler    = &mlx4_err_handler,      // 错误处理程序(一些PCI错误处理函数)
};

// 初始化PCI设备的函数
static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
    // 下面的宏定义是用来处理不同内核版本之间的兼容性问题

#ifdef HAVE_DEVLINK_H
    struct devlink *devlink;
#endif
    struct mlx4_priv *priv;
    struct mlx4_dev *dev;
    int ret;

    printk_once(KERN_INFO "%s", mlx4_version);  // 打印驱动版本信息

#ifdef HAVE_DEVLINK_H
    // devlink相关的初始化。如果支持devlink,则使用devlink相应的API分配内存以及初始化
    ...
    priv = devlink_priv(devlink);
#else
    priv = kzalloc(sizeof(*priv), GFP_KERNEL);  // 分配内存
    if (!priv)
        return -ENOMEM;  // 如果内存分配失败,则返回错误
#endif
    dev       = &priv->dev;
    dev->persist = kzalloc(sizeof(*dev->persist), GFP_KERNEL);  // 分配持久化的设备结构
    if (!dev->persist) {
        // 如果分配失败,执行相应的清理工作然后返回错误
        ...
    }
    dev->persist->pdev = pdev;
    dev->persist->dev = dev;
    pci_set_drvdata(pdev, dev->persist);  // 设置PCI设备的驱动程序数据

    priv->pci_dev_data = id->driver_data;  // 设置设备私有数据
    // 初始化互斥锁
    mutex_init(&dev->persist->device_state_mutex);
    mutex_init(&dev->persist->interface_state_mutex);
    mutex_init(&dev->persist->pci_status_mutex);

#ifdef HAVE_DEVLINK_H
    // 如果支持devlink,则继续进行devlink的设置和注册
    ...
#endif

    ret =  __mlx4_init_one(pdev, id->driver_data, priv);  // 调用内部初始化函数
#ifdef HAVE_DEVLINK_H
    // 处理可能的devlink初始化错误,并注册devlink参数
    ...
#endif

    if (ret) {
        // 如果有错误发生,进行清理工作
        ...
    } else {
        pci_save_state(pdev);  // 保存PCI设备状态
    }

#ifdef HAVE_DEVLINK_H
    // 如果支持devlink,处理错误时的清理工作
    ...
#endif
    return ret;  // 返回初始化结果,成功或失败的错误码
}

以上代码是在内核代码中的一个PCI驱动程序的初始化函数。在该函数中,驱动程序初始化PCI设备并为其分配必要的资源(比如内存)。如果启用了`devlink`配置选项(用于一些设备的配置和监控功能),它会额外处理`devlink`相关的注册和初始化。该函数最后将返回一个错误码,表示初始化操作的成功或失败状态。

完整代码的中文注释:

// 驱动的主结构体,包含了供PCI核心使用的勾子(hooks)
static struct pci_driver mlx4_driver = {
    .name        = DRV_NAME,                   // 驱动名称
    .id_table    = mlx4_pci_table,             // 支持的PCI设备ID表
    .probe        = mlx4_init_one,              // 初始化一个PCI设备时调用的函数
    .shutdown    = mlx4_shutdown,              // 关闭设备时调用的函数
    .remove        = mlx4_remove_one,            // 移除设备时调用的函数
    .suspend    = mlx4_suspend,               // 暂停设备时调用的函数
    .resume        = mlx4_resume,                // 恢复设备时调用的函数
    .err_handler    = &mlx4_err_handler,         // 错误处理程序(一些PCI错误处理函数)
};
// 初始化一个PCI设备的函数
static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
#ifdef HAVE_DEVLINK_H
    struct devlink *devlink;
#endif
    struct mlx4_priv *priv;
    struct mlx4_dev *dev;
    int ret;
    // 仅打印一次驱动版本信息
    printk_once(KERN_INFO "%s", mlx4_version);
#ifdef HAVE_DEVLINK_H
    // 根据编译时的设置,以不同的方式分配并初始化devlink
#ifdef HAVE_DEVLINK_ALLOC_GET_3_PARAMS
    devlink = devlink_alloc(&mlx4_devlink_ops, sizeof(*priv), &pdev->dev);
#else
    devlink = devlink_alloc(&mlx4_devlink_ops, sizeof(*priv));
#endif
    if (!devlink)
        return -ENOMEM;   // 内存分配失败时返回错误
    priv = devlink_priv(devlink); // 从devlink得到私有结构体的引用
#else
    priv = kzalloc(sizeof(*priv), GFP_KERNEL); // 在没有devlink的情况下分配内存
    if (!priv)
        return -ENOMEM;   // 内存分配失败时返回错误
#endif
    dev = &priv->dev;
    dev->persist = kzalloc(sizeof(*dev->persist), GFP_KERNEL); // 分配持久化设备结构
    if (!dev->persist) {
#ifdef HAVE_DEVLINK_H
        ret = -ENOMEM;
        goto err_devlink_free;   // 在devlink设置中,如果内存分配失败则跳转到相应清理环节
#else
        kfree(priv);            // 在非devlink设置中清理分配的内存
        return -ENOMEM;
#endif
    }
    // 初始化pdev和dev之间的引用
    dev->persist->pdev = pdev;
    dev->persist->dev = dev;
    pci_set_drvdata(pdev, dev->persist);     // 将持久化的dev结构与pci设备关联起来
    priv->pci_dev_data = id->driver_data;    // 设置设备特定的数据
    // 初始化多个mutex
    mutex_init(&dev->persist->device_state_mutex);
    mutex_init(&dev->persist->interface_state_mutex);
    mutex_init(&dev->persist->pci_status_mutex);
#ifdef HAVE_DEVLINK_H
    // 如果支持devlink,根据编译时的配置注册devlink实例
#ifdef HAVE_DEVLINK_REGISTER_GET_1_PARAMS
    devlink_register(devlink);
#else
    ret = devlink_register(devlink, &pdev->dev);
    if (ret)
        goto err_persist_free;  // 注册失败时清理并返回
#endif
#if defined(HAVE_DEVLINK_PARAM) && defined(HAVE_DEVLINK_PARAMS_PUBLISHED)
    // 如果支持devlink参数,注册设备的参数
    ret = devlink_params_register(devlink, mlx4_devlink_params,
                      ARRAY_SIZE(mlx4_devlink_params));
    if (ret)
        goto err_devlink_unregister;  // 注册失败时清理并返回
    // 设置初始化时的参数值
    mlx4_devlink_set_params_init_values(devlink);
#endif
#endif
    ret =  __mlx4_init_one(pdev, id->driver_data, priv);  // 调用内部的初始化函数
    if (ret) {
        goto err_handling;  // 如果初始化失败,处理错误
    }
#ifdef HAVE_DEVLINK_H
#if defined(HAVE_DEVLINK_PARAM) && defined(HAVE_DEVLINK_PARAMS_PUBLISHED)
    // 如果支持devlink参数并且已经发布,发布参数设置
#ifdef HAVE_DEVLINK_PARAMS_PUBLISHED
    devlink_params_publish(devlink);
#endif
#ifdef HAVE_DEVLINK_RELOAD_ENABLE
    // 如果支持devlink重载,使能devlink的重载操作
    devlink_reload_enable(devlink);
#endif
#endif
#endif
    pci_save_state(pdev);   // 保存当前的PCI设备状态,这样在需要恢复设备时(比如从挂起状态恢复时)可以用到
    return 0;               // 返回0表示成功
#ifdef HAVE_DEVLINK_H
#if defined(HAVE_DEVLINK_PARAM) && defined(HAVE_DEVLINK_PARAMS_PUBLISHED)
    // 如果支持devlink参数和发布功能,以下是失败时的清理过程
err_params_unregister:
    // 取消注册之前注册的devlink参数
    devlink_params_unregister(devlink, mlx4_devlink_params,
                  ARRAY_SIZE(mlx4_devlink_params));
#endif
    // 错误处理部分:如果devlink注册失败,则取消注册
err_devlink_unregister:
    devlink_unregister(devlink);
#ifndef HAVE_DEVLINK_REGISTER_GET_1_PARAMS
    // 如果出现错误且版本不支持单参数devlink注册,则需要释放持久化设备结构内存
err_persist_free:
#endif
    kfree(dev->persist);  // 释放持久化设备结构内存
    // 如果devlink分配失败,则执行以下代码来释放内存
err_devlink_free:
    devlink_free(devlink);  // 释放devlink结构体所占用的内存
#endif
    return ret;  // 返回错误码。如果初始化过程中的某个步骤失败,则返回相应的错误码
}

上面的 pci_save_state(pdev) 函数调用负责保存当前PCI设备的核心配置寄存器。这在系统休眠或PCI设备电源管理事件中是必要的,因为在这样的事件中,设备的PCI配置可能会丢失或被重置,系统在恢复时需要这信息重新对设备进行配置。

return 0; 表明函数执行成功,返回值0符合Linux内核中处理成功操作的返回值约定。在C语言中,返回状态通常使用整形返回,而0通常表示成功,非0值表示某种形式的错误。

备注:此代码段涉及到了错误处理和内存清理部分。在初始化一个PCI设备时,如果过程中遇到错误,代码会跳转到相应的错误处理标签进行清理。这些清理工作可能包括注销注册的devlink参数、释放分配的内存、取消注册devlink设备等,以确保在发生错误时不会泄露资源。一旦完成清理,函数将返回一个表示错误状态的负值错误码。如果初始化成功,代码则将保存PCI设备的状态,并且返回0表示初始化成功。

二、讲解

这段代码主体是一个`mlx4_init_one`函数,它是Mellanox公司网络设备驱动的初始化函数,用于对PCI网络设备进行初始化。这段代码来自Linux内核的Mellanox网络驱动,其中的`mlx4_driver`结构体是PCI驱动的注册信息。`mlx4_init_one`函数是在PCI设备开始初始化时由内核调用的。函数主体涉及资源分配、设备注册和错误处理。
代码以及注释的大致意思如下:
- mlx4_driver:一个PCI驱动结构体,提供驱动的基本信息和回调函数。
- mlx4_init_one:驱动的初始化函数,它会针对每个被发现的PCI设备被调用。
  - 输出一次版本信息到内核日志。
  - 分配`devlink`资源,作为网络设备到devlink层的接口。
  - 分配`mlx4_priv`结构体以存储私有数据。
  - 分配`mlx4_dev`结构体中的`persist`字段,存储设备持续性状态。
  - 设置PCI设备与驱动数据的关联。
  - 初始化一些互斥锁,保护设备状态和PCI状态。
  - 在devlink层注册该设备,以及设备参数。
  - 调用`__mlx4_init_one`进行进一步的设备初始化工作。
  - 最后,保存PCI设备的状态以便恢复时使用。
- 如果初始化失败,函数会逐步释放已分配的资源,并且返回错误代码。
这段代码展示了复杂PCI设备驱动初始化流程的一部分,包括资源的分配和初始化,以及设备在系统内的注册。如果在初始化过程中遇到任何错误,它会回滚已经执行的步骤,释放资源,确保系统稳定。

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

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

相关文章

<QT基础(2)>QScrollArea使用笔记

项目需要设置单个检查的序列图像预览窗口,采用QScrollArea中加入QWidget窗口,每个窗口里面用Qlabel实现图像预览。 过程涉及两部分内容 引入QWidget 引入label插入图像(resize) 引入布局 组织 scrollArea内部自带Qwidget&#…

Floyd算法:浅显外表下的动态规划内核

很久没遇到Floyd算法的题目了,2642. 设计可以求最短路径的图类刚好是一个典型。在实现核心算法之余,顺便整理一下算法的内核。 Floyd-Warshall’s Algorithm Floyd-Warshall算法,简称Floyd算法,是“有向图非负权图的多源最短路”…

【爬虫基础】第5讲 AJAX动态页面的数据获取

静态:访问地址栏里的数据就可以获取到想要的数据 动态:访问地址栏里的数据获取不到想要的数据 解决方案:抓包 打开浏览器的开发者工具-network-xhr,找到可以获取到数据的URL访问即可 获取url地址 代码实现: from urllib.request…

Python接口自动化pytest框架安装

1、创建一个requirements.txt文件夹 2、输入内容:如下图 pytest pytest-html pytest-xdist pytest-ordering pytest-rerunfailures pytest-base-url allure-pytest3、在terminal中输入安装命令:pip install -r requirements.txt 安装成功 4、在termina…

模板方法模式(继承的优雅使用)

目录 前言 UML plantuml 类图 实战代码 AbstractRoutingDataSource DynamicDataSource DynamicDataSourceContextHolder 前言 在设计类时,一般优先考虑使用组合来替代继承,能够让程序更加的灵活,但这并不意味着要完全抛弃掉继承。 …

MySQL高级SQL2

一、表连接 二、视图 三、null值和空值区别 四、存储过程 五、函数 六、字符串函数 七、日期时间函数

迅雷拉新关键词怎么申请?

在这个日新月异、竞争激烈的时代,网盘项目的寻找与对接已成为众多团队谋求突破的关键。那么,如何在茫茫项目海中筛选出既靠谱又有潜力的明珠呢?经过深度挖掘和全网搜索,我为大家精心整理了优质接单渠道,助力网盘拉新团…

大模型prompt工程学习(一)

目录 调prompt的方法 prompt时好时不好 大模型本质是没有记忆的 划重点:我们发给大模型的 prompt,不会改变大模型的参数 ГLets think step by step」 一步步分析一下 自洽性,同时跑多次,来减少幻觉 逻辑,基本能力来是要有…

Android卡顿掉帧问题分析之实战篇

本文将结合典型实战案例,分析常见的造成卡顿等性能问题的原因。从系统工程师的总体角度来看 ,造成卡顿等性能问题的原因总体上大致分为三个大类:一类是流程执行异常;二是系统负载异常;三是编译问题引起。 1 流程执行异…

web全栈架构师第16期教程

教程介绍 互联网时代已进入后半场,行业环境发生了显著变化。互联网人,尤其是技术人员,如何在加速更迭的技术浪潮中持续充电,提升自身价值,是当下必须面对的挑战。课程涉及了现下前端实际开发时所需要的各块内容&#…

Java Web-HTTP协议

概念: Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。 特点: 1.基于TCP协议:面向连接,安全 2. 基于请求-响应模型的:一次请求对应一次响应 3. HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。 缺点:多…

MBR4060DC-ASEMI肖特基二极管MBR4060DC

编辑:ll MBR4060DC-ASEMI肖特基二极管MBR4060DC 型号:MBR4060DC 品牌:ASEMI 封装:TO-263 最大平均正向电流(IF):40A 最大循环峰值反向电压(VRRM):60V …

小红的炸砖块

题目描述 小红正在玩一个“炸砖块”游戏,游戏的规则如下: 初始有一个n∗m的砖块矩阵。小红会炸k次,每次会向一个位置投炸弹,如果这个位置有一个砖块,则砖块消失,上方的砖块向下落。 小红希望你画出最终砖块…

Android Studio Iguana | 2023.2.1 补丁 1

Android Studio Iguana | 2023.2.1 Canary 3 已修复的问题Android Gradle 插件 问题 295205663 将 AGP 从 8.0.2 更新到 8.1.0 后,任务“:app:mergeReleaseClasses”执行失败 问题 298008231 [Gradle 8.4][升级] 由于使用 kotlin gradle 插件中已废弃的功能&#…

程序员也写歌啦

我的第一首AI原创歌曲《旅途的歌声》 身为 AI 重度患者的我,时刻关注着每天发布的各种 AI 产品。面对这些雨后春笋般的 AI 产品,我也早就没那么敏感了。 但是今天尝试着用 AI 生成了一个音乐,真的震惊到了我! 不到一分钟&#…

2024年第六届机器人系统与自动化工程国际会议(RSAE 2024)即将召开!

2024年第六届机器人系统与自动化工程国际会议(RSAE 2024)将于2024年6月21-23日在日本东京召开。RSAE 2024 的主要目标是加强合作,并为院士、专业人士和研究人员提供一个论坛,交流他们的研究成果、创新理念和解决方案,包…

算法打卡day29|贪心算法篇03|Leetcode 1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果

算法题 Leetcode 1005.K次取反后最大化的数组和 题目链接:1005.K次取反后最大化的数组和 大佬视频讲解:K次取反后最大化的数组和视频讲解 个人思路 思路清晰,因为是取反当然是取越小的负数越好,那么先按绝对值排序。如果是负数就取反&#…

Tomcat 下载以及安装

Tomcat安装及配置教程主要分为四步: 步骤一:首先确认自己是否已经安装JDK 1. cmd:查看java的版本 步骤二:下载安装Tomcat 1. 下载tomcat :Apache Tomcat - Welcome! 2. 选择对应的tomcat版本: 3. 进行安装&#…

左值引用、右值引用及移动语义

个人主页:Lei宝啊 愿所有美好如期而遇 左值 概念 可以取到地址的值就是左值,并且一般情况下可以修改(const类型左值不可修改)。 左值举例: //左值 int a 0; const int b 1; int* p &a; 右值 概念 不能…

虚拟ECU:汽车空调压缩机控制系统

2024年是“十四五”的“关键一年”,在中国居民生活水平不断上升的趋势下,人们对汽车的需求已不再局限于简单的代步工具,而对其整体的舒适度和体验度也有着越来越高的要求。作为提升驾车与乘车体验的重要部分,汽车的空调系统在电动…