【C语言】linux内核pci_set_master

一、__pci_set_master 

static void __pci_set_master(struct pci_dev *dev, bool enable)
{
    u16 old_cmd, cmd;

    pci_read_config_word(dev, PCI_COMMAND, &old_cmd);  // 读取设备的PCI命令寄存器的当前值
    if (enable)
        cmd = old_cmd | PCI_COMMAND_MASTER;  // 如果要启用总线主控,设置命令字相应的位
    else
        cmd = old_cmd & ~PCI_COMMAND_MASTER; // 如果要禁用总线主控,清除命令字相应的位
    if (cmd != old_cmd) {  // 如果命令字有变化,更新PCI命令寄存器
        pci_dbg(dev, "%s bus mastering\n",
            enable ? "enabling" : "disabling");
        pci_write_config_word(dev, PCI_COMMAND, cmd);
    }
    dev->is_busmaster = enable;  // 更新设备的状态,表示总线主控是否被启用
}

这个函数专注于设置或清除PCI命令寄存器中控制总线主控的位。如果启用,它会设置这个位;如果禁用,它会清除这个位。更新操作只会在这个位的状态实际改变时发生。

二、pcibios_set_master 函数和 pci_set_master 函数

// pcibios_set_master函数为PCI设备dev启用总线主控。这是默认实现。如果需要,体系结构特定的实现可以覆盖此函数。
void __weak pcibios_set_master(struct pci_dev *dev)
{
    u8 lat;

    // PCIe设备(无论是Type 0还是Type 1)不适用延迟定时器
    if (pci_is_pcie(dev))
        return;

    pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);  // 读取延迟定时器的当前值
    if (lat < 16)
        lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;// 如果小于16,设置一个默认值或最大值
    else if (lat > pcibios_max_latency)
        lat = pcibios_max_latency;  // 如果大于最大值,降到最大值
    else
        return;

    pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);  // 写回修改后的延迟定时器值
}

// pci_set_master函数用于启用PCI设备dev的总线主控。
void pci_set_master(struct pci_dev *dev)
{
    __pci_set_master(dev, true);  // 启用总线主控
    pcibios_set_master(dev);      // 调用体系结构特定的设置
}
EXPORT_SYMBOL(pci_set_master);

pcibios_set_master 函数是用来做一些体系结构特定的总线主控设置的。它检查并可能会调整PCI设备的延迟定时器值以避免PCI总线拥塞。

pci_set_master 函数则是一个更高级的接口,通常由驱动程序调用以启用设备的总线主控功能,并随后调用`pcibios_set_master`函数完成体系结构相关的设置。通过EXPORT_SYMBOL宏,这个函数被导出,使得其他内核模块可以调用它。

ChatGPT

在 Linux 内核中,`pci_set_master()` 函数用于使能给定 PCI 设备的 Bus Mastering 功能。Bus Mastering 是一种允许连接到总线的设备(如 PCI 设备)直接访问系统内存,无需通过 CPU 的机制。这对于一些需要快速数据传输的设备来说非常重要,比如网络卡或 SCSI 控制器。
当你的驱动程序控制着某个 PCI 设备时,你可能需要调用 pci_set_master() 来允许设备发起 DMA(Direct Memory Access)传输。
函数的声明如下:

void pci_set_master(struct pci_dev *dev);

其中,`struct pci_dev *dev` 是一个指向 PCI 设备的结构。
以下是在驱动程序中如何使用 pci_set_master() 函数的一个简单示例:

#include <linux/pci.h>

int enable_pci_device(struct pci_dev *pdev) {
    int ret;
    
    // 首先,启用 PCI 设备
    ret = pci_enable_device(pdev);
    if (ret) {
        pr_err("Failed to enable PCI device\n");
        return ret;
    }

    // 设置 PCI 设备为 Bus Master
    pci_set_master(pdev);

    // 其他初始化任务...

    return 0;
}

在这个示例里,首先调用 pci_enable_device() 启用 PCI 设备。只有设备被启用后,才能调用 pci_set_master(),后者会设置设备的 COMMAND 寄存器来允许 Bus Mastering。
如果你的 PCI 设备使用 DMA,通常还需要分配并设置 DMA 缓冲区,以及可能的 DMA 映射操作,以确保 DMA 传输能够正确执行。在 Linux 驱动开发中,你可能需要使用更多的 DMA 相关 API 来进行这些操作。

文心一言

在Linux内核中,pci_set_master是一个用于设置PCI设备为主设备的函数。当你希望一个PCI设备能够发起DMA操作到系统内存或其他PCI设备的内存时,你需要将它设置为主设备。

pci_set_master函数通常在PCI驱动程序的初始化部分被调用,以确保设备可以执行DMA操作。

以下是pci_set_master函数的原型:

int pci_set_master(struct pci_dev *dev);

其中,dev是一个指向pci_dev结构的指针,该结构表示一个PCI设备。

如果函数调用成功,它将返回0。如果设置主设备失败,它将返回一个负的错误代码。

下面是一个简单的例子,展示了如何在PCI驱动中使用pci_set_master:

#include <linux/pci.h>  
#include <linux/init.h>  
#include <linux/module.h>  
  
static int __init my_pci_driver_init(void)  
{  
    struct pci_dev *dev;  
    int err;  
  
    /* 查找我们的PCI设备 */  
    dev = pci_get_device(PCI_VENDOR_ID, PCI_DEVICE_ID, NULL);  
    if (!dev) {  
        printk(KERN_ERR "Unable to find PCI device\n");  
        return -ENODEV;  
    }  
  
    /* 使设备成为主设备 */  
    err = pci_set_master(dev);  
    if (err) {  
        printk(KERN_ERR "Failed to set PCI device as master\n");  
        pci_dev_put(dev);  
        return err;  
    }  
  
    /* ... 其他初始化代码 ... */  
  
    return 0;  
}  
  
static void __exit my_pci_driver_exit(void)  
{  
    /* 清理代码 */  
}  
module_init(my_pci_driver_init);  
module_exit(my_pci_driver_exit);  
MODULE_LICENSE("Dual BSD/GPL");

在这个例子中,我们首先使用pci_get_device来查找我们的PCI设备。然后,我们调用pci_set_master来设置该设备为主设备。如果设置失败,我们打印一个错误消息并退出。如果成功,我们可以继续进行其他的初始化操作。

注意:在使用PCI设备时,你还需要处理其他许多事情,如内存映射、中断处理等。上面的代码只是一个简单的示例,用于说明如何使用pci_set_master函数。在实际驱动开发中,你需要确保遵循所有相关的Linux内核编程惯例和最佳实践。

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

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

相关文章

计算机网络基础知识

一、网络概述 1.网络定义与功能 利用通信线路物理地将不同的终端连接起来&#xff0c;按照网络协议相互通信&#xff0c;以共享软件、硬件和数据资源为目标的系统 数据通信&#xff1a;在计算机之间传送各种信息 资源共享&#xff1a;硬件资源共享、软件资源共享 负荷均衡&am…

easyExcel大数据量导出oom

easyExcel大数据量导出 异常信息 com.alibaba.excel.exception.ExcelGenerateException: java.lang.OutOfMemoryError: GC overhead limit exceededat com.alibaba.excel.write.ExcelBuilderImpl.fill(ExcelBuilderImpl.java:84)at com.alibaba.excel.ExcelWriter.fill(Excel…

租用阿里云2核2G服务器配置报价,61元和99元

阿里云2核2G服务器配置优惠价格61元和99元&#xff0c;61元是轻量应用服务器2核2G3M带宽、50G高效云盘&#xff0c;99元服务器是ECS云服务器经济型e实例2核2G、3M固定带宽、40G ESSD entry 系统盘。活动 aliyunfuwuqi.com/go/aliyun 阿里云服务器网aliyunfuwuqi.com根据上面的官…

【光标精灵】让您享受鼠标皮肤多样化快捷更换

鼠标作为我们日常使用频率最高的“小伙伴”&#xff0c;扮演着至关重要的角色。尤其是在女生群体中&#xff0c;对于打造一个个性化、可爱的电脑桌面和软件界面的需求日益增长。然而&#xff0c;尽管电脑默认提供了一些可更换的光标图案&#xff0c;但仍显得有些单调和呆板。想…

[SAP ABAP] SE11查询数据库表中的数据

我们可以通过事务码SE11查询对应数据库表中的详细数据 本次查询使用的数据库表名为MARA&#xff0c;具体操作如下所示: ① 输入事务码SE11进入ABAP字典操作界面&#xff0c;在数据库表搜索框中输入目标表名MARA&#xff0c;并点击【显示】按钮 ② 进入到显示表界面&#xff0…

NIVision-相机图像采集

应用场景 上位机与工业相机通讯&#xff0c;控制相机抓取图像。 工业相机的通讯接口大多为USB口或网口。 USB口则直接将通讯线缆插入上位机USB端口&#xff0c;打开MAX中设备与接口一栏可以看到电脑给相机分配的资源名称&#xff1b;网口则需要将网线连接相机和上位机&#xf…

linux命令详解——uniq,wc,tr

uniq uniq可以对查看内容去重 但在我们使用时会发现&#xff0c;uniq的去重逻辑是&#xff0c;当遇到连续多行内容相同时&#xff0c;去除重复行&#xff0c;而对间隔重复内容&#xff0c;无法实现去重功能 这里想到可以将sort与uniq结合使用&#xff0c;先对文件内容进行排序…

WM8978 —— 带扬声器驱动程序的立体声编解码器(5)

接前一篇文章&#xff1a;WM8978 —— 带扬声器驱动程序的立体声编解码器&#xff08;4&#xff09; 九、寄存器概览与详解 1. 整体概览 WM8978芯片共有58个寄存器&#xff0c;整体总表如下&#xff1a; 2. 详细说明 在此&#xff0c;只介绍WM8978较为常用的那些寄存器。 &…

1Panel应用推荐:DataEase开源数据可视化分析工具

1Panel&#xff08;github.com/1Panel-dev/1Panel&#xff09;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;它致力于通过开源的方式&#xff0c;帮助用户简化建站与运维管理流程。为了方便广大用户快捷安装部署相关软件应用&#xff0c;1Panel特别开通应用商店&am…

SQL Server 文件组详解

数据文件组 SQL Server 数据库最常用的存储文件是数据文件和日志文件。 数据文件用于存储数据&#xff0c;由一个主要数据文件&#xff08;.mdf&#xff09;和若干个次要数据文件&#xff08;.ndf&#xff09;构成&#xff1b;日志文件用于存储事物日志&#xff0c;由.ldf文件…

Android 动态类加载实现免安装更新

随着Html5技术成熟&#xff0c;轻应用越来越受欢迎&#xff0c;特别是其更新成本低的特点。与Native App相比&#xff0c;Web App不依赖于发布下载&#xff0c;也不需要安装使用&#xff0c;兼容多平台。目前也有不少Native App使用原生嵌套WebView的方式开发。但由于Html渲染特…

【C#】C#窗体应用修改窗体的标题和图标

修改窗体顶部的标题和图表&#xff0c;如果不修改则会使用默认的图标&#xff0c;标题默认为Form1&#xff0c;如第一张图&#xff0c;这时候如果想换成和系统有关的内容&#xff0c;如第二张图&#xff0c;可以使用下面的方法进行修改&#xff0c;修改后打开该软件任务栏显示的…

网络安全笔记-day6,NTFS安全权限

文章目录 NTFS安全权限常用文件系统文件安全权限打开文件安全属性修改文件安全权限1.取消父项继承权限2.添加用户访问权限3.修改用户权限4.验证文件权限5.总结权限 强制继承父项权限文件复制移动权限影响跨分区同分区 总结1.权限累加2.管理员最高权限2.管理员最高权限 NTFS安全…

开源数据集 nuScenes 之 3D Occupancy Prediction

数据总体结构 Nuscenes 数据结构 可以看一下我的blog如何下载完整版 mmdetection3d ├── mmdet3d ├── tools ├── configs ├── data │ ├── nuscenes │ │ ├── maps │ │ ├── samples │ │ ├── sweeps │ │ ├── lidarseg (o…

Prometheus Grafana 配置仪表板

#grafana# 其实grafana提供了丰富的Prometheus数据源的仪表板&#xff0c;基本上主流的都有&#xff0c;通过下面官方地址可查阅 Dashboards | Grafana Labs 这里举例说明&#xff0c;配置node_exporter仪表板 首先&#xff0c;在上面的网站搜索 node 可以查到蛮多的仪表板…

【使用redisson完成延迟队列的功能】使用redisson配合线程池完成异步执行功能,延迟队列和不需要延迟的队列

1. 使用redisson完成延迟队列的功能 引入依赖 spring-boot-starter-actuator是Spring Boot提供的一个用于监控和管理应用程序的模块 用于查看应用程序的健康状况、审计信息、指标和其他有用的信息。这些端点可以帮助你监控应用程序的运行状态、性能指标和健康状况。 已经有了…

【现代C++】统一初始化

现代C中的统一初始化&#xff08;Uniform Initialization&#xff09;是C11引入的一项特性&#xff0c;它提供了一种统一的语法来初始化任何类型的对象。统一初始化旨在增强代码的一致性和清晰度&#xff0c;减少传统初始化方式中的歧义。以下是统一初始化的几种用法及相应的示…

Leetcode 226. 翻转二叉树

心路历程&#xff1a; 翻转一瞬间没什么思路&#xff0c;其实就是挨个把每个结点的左右子树都翻转了。主要不要按照左右子树去思考&#xff0c;要按照结点去思考。 翻转既可以从上到下翻转&#xff08;前序遍历&#xff09;&#xff0c;也可以从下到上翻转&#xff08;后序遍历…

张桥社区组织“平安大讲堂”企业应急救护及消防主题培训

为进一步加强园区商户的平安生产意识&#xff0c;提升应急救护能力&#xff0c;在襄阳市民政局的指导和支持下&#xff0c;襄阳市和时代社会工作服务中心依托襄阳市“光明谷”社会组织助力共同缔造项目&#xff0c;联合樊城区红十字会、樊城区点爱志愿者协会在张桥社区“美世界…

基于飞凌嵌入式i.MX6ULL核心板的电梯智能物联网关方案

电梯是现代社会中不可或缺的基础性设施&#xff0c;为人们的生产生活提供了很大的便捷。我国目前正处于城镇化的快速发展阶段&#xff0c;由此带动的城市基础设施建设、楼宇建设、老破小改造等需求也让我国的电梯行业处在了一个高速增长期。截至2023年年底&#xff0c;中国电梯…