PCIe【9】Linux内核 PCI驱动

1. PCI驱动的架构层次

共分为4个核心层次:

  1. PCI/PCIe核心层(PCI Core)

    1. driver/pci目录,负责总线枚举、资源配置、设备发现和通用驱动框架。

    2. 功能:扫描PCIe拓扑结构、分配内存和中断资源、管理设备配置空间(如BAR、Capability结构)。

  2. 主机控制器驱动(Host Controller Driver)

    1. 位于drivers/pci/controllerdrivers/pci/host目录,负责与硬件SoC/芯片组的PCIe RC交互。

    2. 功能:初始化Root Complex、处理总线扫描触发(如通过ACPI或设备树)。

  3. PCIe设备驱动(Device Driver)

    1. 用户编写的具体设备驱动,如网卡、GPU、量子密码卡驱动等。

    2. 关键操作:映射BAR空间、配置DMA、注册中断处理函数。

  4. 用户空间接口,提供/sys/bus/pci下的sysfs节点。

2. PCI驱动的结构体

PCI层负责大部分的设备探测工作。当探测到一个PCI设备时,将通过pci_register_driver()进行初始化。初始化主要包含以下工作:

  1. 启用设备 pci_enable_device()
    1. 从休眠状态切换到工作状态;此外,如果BIOS没有做,pci_enable_device()会分配设备的I/O和内存区域,以及分配一个IRQ
  • 请求MMIO/IOP资源(Memory-Mapped I/O; I/O Port)

  • 设置DMA掩码大小(对于流式和一致的DMA)

  • 分配和初始化共享控制数据(pci_allocate_coherent()

  • 访问设备配置空间(如果需要)

  • 注册IRQ处理程序(request_irq())

  • 初始化非PCI(即芯片的LAN/SCSI/等部分)

  • 启用DMA/处理引擎

当使用完设备后,如果需要卸载模块,那采取以下步骤:

  • 禁用设备产生的IRQ

  • 释放IRQ(`free_irq())

  • 停止所有DMA活动

  • 释放DMA缓冲区(包括一致性和数据流式)

  • 从其他子系统(例如scsi或netdev)上取消注册

  • 释放MMIO/IOP资源

  • 禁用设备

当驱动退出时,它只是调用pci_unregister_driver(),PCI层会自动调用驱动处理的所有设备的移除钩子。

  1. __init 标记
    含义:__init 是一个宏,它将一个函数标记为“仅在初始化期间使用”。
    作用:
    内存优化:被 __init 标记的函数(及其使用的数据,用 __initdata 标记)的代码会被编译器放置到一个特殊的内存段中(通常是 .init.text)。
    初始化后释放:当内核启动完成(对于内建驱动)或模块加载成功(对于可加载模块)后,内核会认为这些初始化代码不再需要。此时,内核会释放这个 .init.text 段所占用的内存,将其归还给系统。这可以节省宝贵的内核内存空间。
    使用场景:用于 module_init() 指定的初始化函数,以及所有只在初始化过程中被调用一次的函数。一旦初始化完成,这些函数的代码就不再需要了。
    示例:
static int __init my_driver_init(void)
{
    printk(KERN_INFO "My driver initializing...\n");
    // 执行各种初始化操作,如注册设备、申请资源等
    return 0; // 成功
}
module_init(my_driver_init); // 告诉内核哪个函数是初始化入口
posted @ 2025-08-12 19:02  midorii  阅读(21)  评论(0)    收藏  举报