编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

同步内存对象

在访问内存对象的过程中,驱动程序可能需要同步与各种高速缓存有关的内存对象。本节提供了有关何时以及如何同步内存对象的准则。

高速缓存

CPU 高速缓存是位于 CPU 和系统的主内存之间的极高速内存。I/O 高速缓存位于设备和系统的主内存之间,如下图所示。

图 9-1  CPU 和系统 I/O 高速缓存

image:图中显示如何使用高速缓存加快涉及设备的数据传送。

尝试从主内存读取数据时,关联的高速缓存会对请求的数据进行检查。如果数据可用,高速缓存可快速提供这些数据。如果高速缓存中没有数据,则该高速缓存将从主内存中检索数据。然后,高速缓存会将数据传递给请求者并保存数据,以备在后续请求中使用。

类似地,在写循环中,数据会快速存储在高速缓存中。CPU 或设备可以继续执行,即传送数据。将数据存储在高速缓存中所需的时间比等待将数据写入内存所需的时间少得多。

采用此模型,在设备传送完成后,数据仍可位于 I/O 高速缓存中,而主内存中没有数据。如果 CPU 访问内存,CPU 可能会从 CPU 高速缓存中读取错误数据。驱动程序必须调用同步例程,以刷新 I/O 高速缓存中的数据,并使用新数据更新 CPU 高速缓存。此操作可确保内存的情况对于 CPU 而言保持一致。类似地,如果设备要对 CPU 修改的数据进行访问,则需要采用同步步骤。

可在设备和内存之间创建附加的高速缓存和缓冲区,如总线延伸架和桥。使用 ddi_dma_sync(9F) 可以同步所有适用的高速缓存。

ddi_dma_sync() 函数

一个内存对象可能有多个映射,如通过 DMA 句柄用于 CPU 和用于设备的映射。如果使用任何映射来修改内存对象,则具有多个映射的驱动程序需要调用 ddi_dma_sync(9F)。调用 ddi_dma_sync() 可以确保对内存对象的修改在通过不同映射访问该对象之前完成。如果对对象的任何高速缓存引用现在已过时,ddi_dma_sync() 函数还可以通知该对象的其他映射。此外,ddi_dma_sync() 还会根据需要刷新过时的高速缓存引用或使其无效。

通常,当 DMA 传送完成时,驱动程序必须调用 ddi_dma_sync()。此规则的例外情况是如果使用 ddi_dma_unbind_handle(9F) 取消分配 DMA 资源,则会代表驱动程序隐式执行 ddi_dma_sync()ddi_dma_sync() 的语法如下所示:

int ddi_dma_sync(ddi_dma_handle_t handle, off_t off,
size_t length, uint_t type);

如果设备的 DMA 引擎要读取对象,则必须通过将 type 设置为 DDI_DMA_SYNC_FORDEV 来同步该设备看到的对象信息。如果设备的 DMA 引擎已写入内存对象并且 CPU 将读取该对象,则必须通过将 type 设置为 DDI_DMA_SYNC_FORCPU 来同步该 CPU 看到的对象信息。

以下示例说明如何为 CPU 同步 DMA 对象:

if (ddi_dma_sync(xsp->handle, 0, length, DDI_DMA_SYNC_FORCPU)
    == DDI_SUCCESS) {
    /* the CPU can now access the transferred data */
    /* ... */
} else {
    /* error handling */
}

如果唯一的映射是用于内核的,请使用标志 DDI_DMA_SYNC_FORKERNEL,类似于 ddi_dma_mem_alloc(9F) 所分配的内存中的情况。系统会尝试以比同步 CPU 看到的信息更快的速度来同步内核看到的信息。如果系统无法更快地同步内核看到的信息,则系统将按照如同已设置 DDI_DMA_SYNC_FORCPU 标志的情况执行相应的操作。