1*3d8b56d7SYanteng Si.. SPDX-License-Identifier: GPL-2.0 2*3d8b56d7SYanteng Si 3*3d8b56d7SYanteng Si.. include:: ../disclaimer-zh_CN.rst 4*3d8b56d7SYanteng Si 5*3d8b56d7SYanteng Si:Original: Documentation/driver-api/io_ordering.rst 6*3d8b56d7SYanteng Si 7*3d8b56d7SYanteng Si:翻译: 8*3d8b56d7SYanteng Si 9*3d8b56d7SYanteng Si 林永听 Lin Yongting <linyongting@gmail.com> 10*3d8b56d7SYanteng Si 司延腾 Yanteng Si <siyanteng@loongson.cn> 11*3d8b56d7SYanteng Si 12*3d8b56d7SYanteng Si:校译: 13*3d8b56d7SYanteng Si 14*3d8b56d7SYanteng Si=========================== 15*3d8b56d7SYanteng Si对内存映射地址的I/O写入排序 16*3d8b56d7SYanteng Si=========================== 17*3d8b56d7SYanteng Si 18*3d8b56d7SYanteng Si在某些平台上,所谓的内存映射I/O是弱顺序。在这些平台上,驱动开发者有责任 19*3d8b56d7SYanteng Si保证I/O内存映射地址的写操作按程序图意的顺序达到设备。通常读取一个“安全” 20*3d8b56d7SYanteng Si设备寄存器或桥寄存器,触发IO芯片清刷未处理的写操作到达设备后才处理读操作, 21*3d8b56d7SYanteng Si而达到保证目的。驱动程序通常在spinlock保护的临界区退出之前使用这种技术。 22*3d8b56d7SYanteng Si这也可以保证后面的写操作只在前面的写操作之后到达设备(这非常类似于内存 23*3d8b56d7SYanteng Si屏障操作,mb(),不过仅适用于I/O)。 24*3d8b56d7SYanteng Si 25*3d8b56d7SYanteng Si假设一个设备驱动程的具体例子:: 26*3d8b56d7SYanteng Si 27*3d8b56d7SYanteng Si ... 28*3d8b56d7SYanteng Si CPU A: spin_lock_irqsave(&dev_lock, flags) 29*3d8b56d7SYanteng Si CPU A: val = readl(my_status); 30*3d8b56d7SYanteng Si CPU A: ... 31*3d8b56d7SYanteng Si CPU A: writel(newval, ring_ptr); 32*3d8b56d7SYanteng Si CPU A: spin_unlock_irqrestore(&dev_lock, flags) 33*3d8b56d7SYanteng Si ... 34*3d8b56d7SYanteng Si CPU B: spin_lock_irqsave(&dev_lock, flags) 35*3d8b56d7SYanteng Si CPU B: val = readl(my_status); 36*3d8b56d7SYanteng Si CPU B: ... 37*3d8b56d7SYanteng Si CPU B: writel(newval2, ring_ptr); 38*3d8b56d7SYanteng Si CPU B: spin_unlock_irqrestore(&dev_lock, flags) 39*3d8b56d7SYanteng Si ... 40*3d8b56d7SYanteng Si 41*3d8b56d7SYanteng Si上述例子中,设备可能会先接收到newval2的值,然后接收到newval的值,问题就 42*3d8b56d7SYanteng Si发生了。不过很容易通过下面方法来修复:: 43*3d8b56d7SYanteng Si 44*3d8b56d7SYanteng Si ... 45*3d8b56d7SYanteng Si CPU A: spin_lock_irqsave(&dev_lock, flags) 46*3d8b56d7SYanteng Si CPU A: val = readl(my_status); 47*3d8b56d7SYanteng Si CPU A: ... 48*3d8b56d7SYanteng Si CPU A: writel(newval, ring_ptr); 49*3d8b56d7SYanteng Si CPU A: (void)readl(safe_register); /* 配置寄存器?*/ 50*3d8b56d7SYanteng Si CPU A: spin_unlock_irqrestore(&dev_lock, flags) 51*3d8b56d7SYanteng Si ... 52*3d8b56d7SYanteng Si CPU B: spin_lock_irqsave(&dev_lock, flags) 53*3d8b56d7SYanteng Si CPU B: val = readl(my_status); 54*3d8b56d7SYanteng Si CPU B: ... 55*3d8b56d7SYanteng Si CPU B: writel(newval2, ring_ptr); 56*3d8b56d7SYanteng Si CPU B: (void)readl(safe_register); /* 配置寄存器?*/ 57*3d8b56d7SYanteng Si CPU B: spin_unlock_irqrestore(&dev_lock, flags) 58*3d8b56d7SYanteng Si 59*3d8b56d7SYanteng Si在解决方案中,读取safe_register寄存器,触发IO芯片清刷未处理的写操作, 60*3d8b56d7SYanteng Si再处理后面的读操作,防止引发数据不一致问题。 61