【C语言】linux内核pci_set_master

173 篇文章 1 订阅
67 篇文章 0 订阅

一、__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内核编程惯例和最佳实践。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

109702008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值