延迟 IO¶
延迟 IO 是一种延迟和重新利用 IO 的方法。它使用主机内存作为缓冲区,并使用 MMU 页面错误作为何时执行设备 IO 的预触发。以下示例可能是一个有用的解释,说明这种设置是如何工作的
用户空间应用程序(如 Xfbdev)mmap 帧缓冲
延迟 IO 和驱动程序设置错误和 page_mkwrite 处理程序
用户空间应用程序尝试写入 mmapped 虚拟地址
我们得到页面错误并到达错误处理程序
错误处理程序找到并返回物理页面
我们得到 page_mkwrite,其中我们将此页面添加到列表中
安排一个工作队列任务在延迟后运行
应用程序继续写入该页面,而无需额外成本。这是关键的好处。
工作队列任务进入并清理列表上的页面,然后完成与更新帧缓冲相关的任务。这是与设备通信的实际工作。
应用程序尝试写入该地址(现在已清理)
获取页面错误,并再次发生上述序列
从上面可以看出,一个好处是允许以最小的成本发生突发帧缓冲写入。然后在一段时间后,当事情平静下来时,我们真正去更新帧缓冲,这将是一个相对更昂贵的操作。
对于某些类型的非易失性高延迟显示器,所需的图像是最终图像,而不是中间阶段,这就是为什么对于发生的每次写入都不需要更新的原因。
这种情况可能在其他场景中也很有用。Paul Mundt 提到了一个案例,其中使用页面计数来决定是否合并并发出 SG DMA 或执行内存突发是有益的。
另一种可能是,如果有一个格式不寻常的设备帧缓冲(例如对角线偏移的 RGB),那么这可能是一种机制,允许应用程序假装拥有一个正常的帧缓冲,但在 VSync 时间根据触摸的页面列表重新调整设备帧缓冲。
如何使用它:(对于应用程序)¶
无需更改。像平常一样 mmap 帧缓冲并使用它即可。
如何使用它:(对于 fbdev 驱动程序)¶
以下示例可能有所帮助。
设置您的结构。例如
static struct fb_deferred_io hecubafb_defio = { .delay = HZ, .deferred_io = hecubafb_dpy_deferred_io, };
延迟是 page_mkwrite 触发发生和调用 deferred_io 回调之间的最小延迟。deferred_io 回调在下面解释。
设置您的延迟 IO 回调。例如
static void hecubafb_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist)
deferred_io 回调是您执行所有到显示设备的 IO 的地方。您会收到 pagelist,它是延迟期间写入的页面列表。您不得修改此列表。此回调从工作队列中调用。
调用 init
info->fbdefio = &hecubafb_defio; fb_deferred_io_init(info);
调用 cleanup
fb_deferred_io_cleanup(info);