1. PCIe 网卡的基本访问方式
PCIe 设备通过 配置空间(Configuration Space) 和 内存映射寄存器(MMIO) 与主机通信,而非直接使用 io_addr
/io_data
这样的分立寄存器。
关键区别:
特性 | DM9000(传统设备) | PCIe 网卡 |
---|---|---|
寄存器访问方式 | 分立 io_addr /io_data | 统一的内存映射(MMIO) |
地址分配 | 固定或平台指定 | PCIe 配置空间动态分配 |
数据传输 | 通过 io_data 读写缓冲区 | DMA 或 MMIO 缓冲区 |
2. PCIe 网卡的核心寄存器区域
(1)PCI 配置空间(Configuration Space)
-
作用:存放设备的基本信息(厂商ID、设备ID),并分配 MMIO 或 I/O 空间地址。
-
大小:标准 256 字节,扩展(PCIe)可达 4KB。
-
关键寄存器:
-
BAR(Base Address Register):指定 MMIO 或 I/O 空间的基地址。
// Linux 内核中获取 BAR0 的 MMIO 地址 void __iomem *regs = pci_iomap(pdev, BAR0, pci_resource_len(pdev, BAR0));
-
Command Register:启用设备的中断、DMA 等功能。
-
(2)内存映射寄存器(MMIO)
-
作用:替代 DM9000 的
io_addr
/io_data
,通过直接读写内存地址控制网卡。 -
访问方式:
// 写入寄存器 iowrite32(value, regs + REG_CTRL);// 读取寄存器 u32 val = ioread32(regs + REG_STATUS);
-
典型寄存器:
-
控制寄存器(CTRL):启动/停止网卡。
-
状态寄存器(STATUS):查询链路状态、中断标志。
-
MAC 地址寄存器:配置 MAC 地址。
-
DMA 描述符寄存器:管理数据缓冲区。
-
3. 数据传输机制
PCIe 网卡通常使用 DMA(直接内存访问) 传输数据,而非像 DM9000 那样通过 io_data
逐字节读写:
-
发送数据:
-
驱动将数据包存入内存中的 发送描述符环(TX Descriptor Ring)。
-
更新 DMA 描述符寄存器,通知网卡读取内存中的数据。
-
网卡通过 DMA 将数据发送到网络。
-
-
接收数据:
-
驱动预分配内存中的 接收描述符环(RX Descriptor Ring)。
-
网卡通过 DMA 将收到的数据写入内存,触发中断通知驱动。
-
+-------------------+ +-------------------+| TX Descriptor | ----> | Packet Data || Ring | | (in Memory) |+-------------------+ +-------------------+^ || v+-------+ +--------+| DMA | | PCIe || Engine| | NIC |+-------+ +--------+^ || v+-------------------+ +-------------------+| RX Descriptor | <---- | Packet Data || Ring | | (from Wire) |+-------------------+ +-------------------+
4. 对比 DM9000 与 PCIe 网卡
功能 | DM9000 | PCIe 网卡 |
---|---|---|
寄存器访问 | 通过 io_addr /io_data | 直接 MMIO 读写 |
地址分配 | 静态(平台指定) | 动态(PCIe 配置空间分配 BAR) |
数据传输 | 通过 io_data 逐字节读写 | DMA 批量传输 |
性能 | 较低(受 PIO 限制) | 高(DMA + 并行 PCIe 带宽) |
5. 驱动代码示例(PCIe 网卡)
以 Linux 内核中的 igb
驱动(Intel I350 网卡)为例:
// 1. 映射 MMIO 寄存器 void __iomem *hw_addr = pci_iomap(pdev, BAR0, 0);// 2. 写入控制寄存器(启动网卡) iowrite32(IGB_CTRL_START, hw_addr + IGB_REG_CTRL);// 3. 配置 DMA 描述符环 struct dma_desc *tx_ring = dma_alloc_coherent(&pdev->dev, size, &dma_handle, GFP_KERNEL); iowrite32(dma_handle, hw_addr + IGB_REG_TX_DESC);// 4. 收到数据时(中断处理) u32 status = ioread32(hw_addr + IGB_REG_ISR); if (status & IGB_INT_RX) {// 从 RX 描述符环读取数据skb = build_skb(rx_ring[next_rx].data); }
6. 关键点总结
-
PCIe 网卡没有分立
io_addr
/io_data
,而是通过 MMIO 寄存器 和 DMA 实现高效通信。 -
BAR 寄存器 是核心,它决定了 MMIO 或 I/O 空间的基地址。
-
DMA 描述符环 是数据传输的关键,驱动与网卡通过内存中的描述符交互。