马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一、MMIO 基本概念
1. 界说
MMIO(Memory-Mapped I/O)是一种将 设备寄存器映射到处理惩罚器物理地址空间 的机制,CPU通过读写内存地址来访问设备寄存器,而非专用的I/O指令。
2. 核心特点
- 同一地址空间:设备寄存器与内存共享同一地址空间。
- 访问方式:使用平凡内存访问指令(如MOV、LDR/STR)。
- 硬件支持:须要设备支持地址解码和总线响应。
二、MMIO 工作原理
1. 地址空间分配
- 物理地址布局示例:
- 0x00000000-0x3FFFFFFF: DRAM
- 0x40000000-0x4000FFFF: UART 设备寄存器
- 0x40010000-0x4001FFFF: GPIO 控制器
复制代码 - 硬件解码:设备监听特定地址范围,当CPU访问该范围时,设备响应操作。
2. 访问流程
- CPU发出地址 0x40000000 → 内存控制器识别为MMIO区域 → 转发请求到PCIe/SoC总线 → 目标设备响应读写
复制代码 3. 寄存器操作示例
- volatile uint32_t *uart_reg = (uint32_t *)0x40000000;
- *uart_reg = 0x55; // 写入数据寄存器
- uint32_t status = *(uart_reg + 1); // 读取状态寄存器
复制代码 关键点:
- volatile 禁止编译器优化,确保每次访问真实硬件。
- 地址偏移需对齐设备寄存器布局。
三、MMIO 硬件需求
1. 必须硬件支持
组件要求地址解码器识别CPU访问的地址范围(如PCI BAR空间)总线接口支持PCIe/AXI/AHB等协议寄存器文件设备需实现可读写的寄存器,通常为32/64位宽度中断机制可选,但需支持MSI或线中断以通知CPU2. 典型硬件实现(Verilog示例)
- module mmio_device (
- input wire clk,
- input wire [31:0] addr,
- input wire [31:0] wdata,
- output reg [31:0] rdata,
- input wire wr_en
- );
- reg [31:0] reg_file[0:15]; // 16个32位寄存器
- always @(posedge clk) begin
- if (wr_en) begin
- reg_file[addr[5:2]] <= wdata; // 字地址对齐
- end
- rdata <= reg_file[addr[5:2]];
- end
- endmodule
复制代码 四、MMIO 软件实现
1. Linux内核驱动示例
- #include <linux/ioport.h>
- #include <linux/io.h>
- void __iomem *regs;
- static int my_probe(struct pci_dev *dev) {
- // 申请MMIO区域
- regs = pci_iomap(dev, BAR_NUM, 0);
-
- // 读写寄存器
- iowrite32(0x12345678, regs + REG_OFFSET);
- uint32_t val = ioread32(regs + STATUS_REG);
- }
复制代码 2. 用户空间访问(通过/dev/mem)
- int fd = open("/dev/mem", O_RDWR | O_SYNC);
- void *map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, MMIO_BASE_ADDR);
- *(volatile uint32_t *)(map + 0x10) = 0x55AA; // 写寄存器
- munmap(map, PAGE_SIZE);
复制代码 注意:需CAP_SYS_RAWIO权限,生产环境建议使用UIO/VFIO。
五、MMIO 高级特性
1. 原子操作支持
- 需求:设备寄存器需实现硬件级原子性。
- 实现方式:
- // 使用内核原子API
- atomic64_t *reg = (atomic64_t *)(regs + ATOMIC_REG);
- atomic64_add(1, reg);
复制代码 2. 缓存控制
- 非缓存访问:通过ioremap_nocache()制止CPU缓存污染。
- 写归并:使用writel_relaxed()优化频繁写操作。
3. 大端与小端
- 问题:设备大概与CPU字节序不一致。
- 解决方案:
- u32 val = __cpu_to_be32(0x12345678); // 转换字节序
- iowrite32(val, regs);
复制代码
六、MMIO 与 PMIO 对比
特性MMIOPMIO (Port-Mapped I/O)地址空间共享内存地址空间专用I/O地址空间(x86的in/out指令)性能更高(支持突发传输)较低(每次访问需单独指令)硬件复杂度需地址解码逻辑简单,但须要独立I/O总线典型应用当代PCIe设备、SoC外设传统x86设备(如键盘控制器) 七、MMIO 性能优化
1. 减少访问延迟
- 批处理惩罚:归并多个寄存器写入。
- 预取:提前读取状态寄存器。
2. DMA协同
- // 配置DMA源地址为MMIO区域
- dma_src_addr = MMIO_DATA_BUFFER;
- dma_start_transfer();
复制代码 3. NUMA优化
- 确保MMIO设备与CPU在同一NUMA节点:
- numactl --cpunodebind=0 --membind=0 ./mmio_app
复制代码
八、调试与问题排查
1. 常见问题
- 访问挂起:检查设备是否响应(逻辑分析仪抓取总线信号)。
- 数据损坏:确认数据宽度对齐(32位设备需32位访问)。
2. 调试工具
- # 查看已映射的MMIO区域
- cat /proc/iomem
- # 监控
MMIO访问(需CONFIG_IO_STRACE) - perf trace -e ioread*,iowrite*
复制代码 九、当代扩展
1. MMIO over PCIe
- 原子操作:支持PCIe AtomicOps(如FetchAdd、CAS)。
- TLP处理惩罚:利用PCIe事务层包优化传输。
2. CXL设备
- 内存语义:CXL 2.0+设备支持一致性MMIO访问。
MMIO是硬件与CPU高效交互的核心机制,正确使用时能实现纳秒级延迟的设备控制。计划时需综合考虑地址分配、原子性需求和缓存一致性,高性能场景可联合DMA与中断优化。
|