本页目录

PCIe 与 USB 驱动模型

覆盖: PCIe 枚举 (BAR/MMIO/MSI) → pci_driver → USB 协议栈 (URB/endpoint) → usb_driver → 热插拔 → 电源管理 内核版本: 2.6 ~ 6.x

PCIe

总线枚举

PCIe 总线自枚举:上电后自动发现拓扑与分配资源 自枚举总线,不需要 DT/ACPI 描述设备 ① 扫描 PCIe 拓扑 BIOS/UEFI(或内核)扫描总线 → bus/device/function ② 读取 configuration space → vendor ID / device ID / class code ③ 分配 BAR(Base Address Register) → MMIO/IO 地址范围 ④ 分配 MSI/MSI-X → 中断向量 每个 PCIe 设备由 BDF(Bus:Device.Function)唯一标识

pci_dev

// include/linux/pci.h
struct pci_dev {
    struct pci_bus  *bus;               // 所在总线
    unsigned int    devfn;              // device + function
    unsigned short  vendor, device;     // 匹配 pci_device_id
    unsigned short  subsystem_vendor, subsystem_device;
    u32             class;              // 设备类 (NVMe, VGA, USB, ...)

    struct resource resource[6];        // BAR 0~5 (MMIO/IO 地址范围)
    unsigned int    irq;                // 中断号 (可能是 MSI 后分配的新号)
    struct pcie_link_state *link_state; // PCIe 链路 (gen, width)

    // DMA
    u64             dma_mask;           // 可寻址范围
    struct device   dev;                // 内嵌 device (设备模型)
};

pci_driver

struct pci_driver {
    const struct pci_device_id *id_table;  // 匹配表
    int (*probe)(struct pci_dev *, const struct pci_device_id *);
    void (*remove)(struct pci_dev *);
    int (*suspend)(struct pci_dev *, pm_message_t);
    int (*resume)(struct pci_dev *);
    struct device_driver driver;           // 内嵌 driver (注册到 PCI bus)
};

// 注册: pci_register_driver(&mydrv)
// 绑定: PCI bus 枚举 → match vendor:device → probe()

MSI/MSI-X

// 基于消息的中断替代 INTx 线中断:
//   MSI: 单个向量或少量向量
//   MSI-X: 最多 2048 个独立向量

// 分配:
int nvec = pci_alloc_irq_vectors(pdev, 1, 16, PCI_IRQ_MSIX);
// → 16 个 MSI-X 向量 → pci_irq_vector(pdev, i) 获取 Linux IRQ 号

// 每个向量独立亲和性 → 可绑到不同 CPU
// NVMe: 每 IO 队列一个 MSI-X → 中断并行处理

USB

USB 协议栈

// drivers/usb/core/
// 分层:
//   USB Core (usbcore): 协议实现, URB 管理
//   Host Controller Driver (HCD): xHCI, EHCI, OHCI
//   Device Driver: usb_driver (如 usb-storage, usbhid)

// USB 设备的描述符层次:
//   Device Descriptor → Config Descriptor → Interface Descriptor → Endpoint Descriptor
//   一个 USB 设备: 1 device, N configs, M interfaces, K endpoints

// Endpoint 类型:
//   Control:     setup packet (配置命令)
//   Bulk:       大块传输 (存储, 打印机)
//   Interrupt:  定时轮询 (HID: 键盘/鼠标)
//   Isochronous: 实时流 (音视频, 无重传)

URB (USB Request Block)

// include/linux/usb.h
struct urb {
    struct usb_device   *dev;       // 目标设备
    unsigned int        pipe;       // endpoint + direction 编码
    void                *transfer_buffer;
    u32                 transfer_buffer_length;
    int                 actual_length;

    usb_complete_t      complete;   // 完成回调

    int                 status;     // 完成状态 (0=OK, -EPROTO, -ETIMEDOUT, ...)
    int                 interval;   // 中断/等时传输的轮询间隔
};

usb_driver

struct usb_driver {
    const struct usb_device_id *id_table;  // VID/PID 匹配
    int (*probe)(struct usb_interface *, const struct usb_device_id *);
    void (*disconnect)(struct usb_interface *);
    struct device_driver drvwrap;          // 内嵌 driver (注册到 USB bus)
};

关键⁠: probe 的对象是 usb_interface,不是 usb_device——因为一个 USB 设备可以有多个接口(如 webcam: video interface + audio interface),不同接口可以绑定不同驱动。


热插拔

热插拔:PCIe 与 USB 事件如何变成可用设备 PCIe 热插拔 物理(服务器):native hotplug → pciehp 虚拟(VM):QEMU device_add(热插拔模拟) USB 热插拔 连接:hub 检测 D+ pull-up → 枚举新设备 断开:D+ pull-down → disconnect() 内核发 uevent udev 处理 模块加载(modalias)+ 设备节点 PCIe 与 USB 触发路径不同,但都收敛到 uevent → udev,统一完成模块加载与设备节点创建

参考

  • 源码⁠: drivers/pci/, drivers/usb/core/, include/linux/pci.h, include/linux/usb.h
  • 内核文档⁠: Documentation/PCI/, Documentation/driver-api/usb/
  • LWN: "The PCI subsystem", "USB in the Linux kernel"

关键词: PCIe, BAR, MSI-X, pci_driver, USB, URB, endpoint, usb_driver, hotplug, udev