延迟 IO

延迟 IO 是一种延迟和重新利用 IO 的方法。它使用主机内存作为缓冲区,并使用 MMU 页面错误作为何时执行设备 IO 的预触发。以下示例可能是一个有用的解释,说明这种设置是如何工作的

  • 用户空间应用程序(如 Xfbdev)mmap 帧缓冲

  • 延迟 IO 和驱动程序设置错误和 page_mkwrite 处理程序

  • 用户空间应用程序尝试写入 mmapped 虚拟地址

  • 我们得到页面错误并到达错误处理程序

  • 错误处理程序找到并返回物理页面

  • 我们得到 page_mkwrite,其中我们将此页面添加到列表中

  • 安排一个工作队列任务在延迟后运行

  • 应用程序继续写入该页面,而无需额外成本。这是关键的好处。

  • 工作队列任务进入并清理列表上的页面,然后完成与更新帧缓冲相关的任务。这是与设备通信的实际工作。

  • 应用程序尝试写入该地址(现在已清理)

  • 获取页面错误,并再次发生上述序列

从上面可以看出,一个好处是允许以最小的成本发生突发帧缓冲写入。然后在一段时间后,当事情平静下来时,我们真正去更新帧缓冲,这将是一个相对更昂贵的操作。

对于某些类型的非易失性高延迟显示器,所需的图像是最终图像,而不是中间阶段,这就是为什么对于发生的每次写入都不需要更新的原因。

这种情况可能在其他场景中也很有用。Paul Mundt 提到了一个案例,其中使用页面计数来决定是否合并并发出 SG DMA 或执行内存突发是有益的。

另一种可能是,如果有一个格式不寻常的设备帧缓冲(例如对角线偏移的 RGB),那么这可能是一种机制,允许应用程序假装拥有一个正常的帧缓冲,但在 VSync 时间根据触摸的页面列表重新调整设备帧缓冲。

如何使用它:(对于应用程序)

无需更改。像平常一样 mmap 帧缓冲并使用它即可。

如何使用它:(对于 fbdev 驱动程序)

以下示例可能有所帮助。

  1. 设置您的结构。例如

    static struct fb_deferred_io hecubafb_defio = {
            .delay          = HZ,
            .deferred_io    = hecubafb_dpy_deferred_io,
    };
    

延迟是 page_mkwrite 触发发生和调用 deferred_io 回调之间的最小延迟。deferred_io 回调在下面解释。

  1. 设置您的延迟 IO 回调。例如

    static void hecubafb_dpy_deferred_io(struct fb_info *info,
                                         struct list_head *pagelist)
    

deferred_io 回调是您执行所有到显示设备的 IO 的地方。您会收到 pagelist,它是延迟期间写入的页面列表。您不得修改此列表。此回调从工作队列中调用。

  1. 调用 init

    info->fbdefio = &hecubafb_defio;
    fb_deferred_io_init(info);
    
  2. 调用 cleanup

    fb_deferred_io_cleanup(info);