DMA

Version 4 by Alta
on Feb 26, 2008 23:35.

compared with
Current by Alta
on Feb 27, 2008 11:46.

Key
This line was removed.
This word was removed. This word was added.
This line was added.

Changes (28)

View page history
h5. Figure 9-1 CPU and System I/O Caches
When an attempt is made to read data from main memory, the associated cache checks for the requested data. If so, the cache supplies the data quickly. If the cache does not have the data, the cache retrieves the data from main memory. The cache then passes the data on to the requester and saves the data in case of a subsequent request.
!http://docs.sun.com/source/819-3196/images/dma.cpucache.gif!
 
When an attempt is made to read data from main memory, the associated cache checks for the requested data. If the data is available, the cache supplies the data quickly. If the cache does not have the data, the cache retrieves the data from main memory. The cache then passes the data on to the requester and saves the data in case of a subsequent request.
Similarly, on a write cycle, the data is stored in the cache quickly. The CPU or device is allowed to continue executing, that is, transferring data. Storing data in a cache takes much less time than waiting for the data to be written to memory.

With this model, after a device transfer is complete, the data can still be in the I/O cache with no data in main memory. If the CPU accesses the memory, the CPU might read the wrong data from the CPU cache. The driver must call a synchronization routine to flush the data from the I/O cache and update the CPU cache with the new data. This action ensures a consistent view of the memory for the CPU. Similarly, a synchronization step is required if data modified by the CPU is to be accessed by a device.
You can create additional caches and buffers between the device and memory, such as bus extenders and bridges. Use {{ddi_dma_sync(9F)}} to synchronize *all* applicable caches.{anchor:dma-27}

h4. {{ddi_dma_sync()}} Function
A memory object might have multiple mappings, such as for the CPU and for a device, by means of a DMA handle. A driver with multiple mappings needs to call <a href="http://docs.sun.com/doc/819-2256/ddi-dma-sync-9f?a=view">{{ddi_dma_sync}}(9F)</a> {{ddi_dma_sync}}(9F) if any mappings are used to modify the memory object. Calling {{ddi_dma_sync()}} ensures that the modification of the memory object is complete before the object is accessed through a different mapping. The {{ddi_dma_sync()}} function can also inform other mappings of the object if any cached references to the object are now stale. Additionally, {{ddi_dma_sync()}} flushes or invalidates stale cache references as necessary.
 
Generally, the driver has to must call {{ddi_dma_sync()}} when a DMA transfer completes. The exception to this rule is if deallocating the DMA resources with <a href="http://docs.sun.com/doc/819-2256/ddi-dma-unbind-handle-9f?a=view">{{ddi_dma_unbind_handle}}(9F)</a> {{ddi_dma_unbind_handle}}(9F) does an implicit {{ddi_dma_sync()}} on behalf of the driver. The syntax for {{ddi_dma_sync()}} is as follows:
{code}
int ddi_dma_sync(ddi_dma_handle_t handle, off_t off,
{code}
If the object is going to be read by the DMA engine of the device, the device's view of the object must be synchronized by setting _type_ to {{DDI_DMA_SYNC_FORDEV}}. If the DMA engine of the device has written to the memory object and the object is going to be read by the CPU, the CPU's view of the object must be synchronized by setting _type_ to {{DDI_DMA_SYNC_FORCPU}}.
view of the object must be synchronized by setting _type_ to {{DDI_DMA_SYNC_FORDEV}}. If the DMA engine of the device has written to the memory object and the object is going to be read by the CPU, the CPU's view of the object must be synchronized by setting _type_ to {{DDI_DMA_SYNC_FORCPU}}.

The following example demonstrates synchronizing a DMA object for the CPU:
== DDI_SUCCESS) {
/* the CPU can now access the transferred data */
[...] /* ... */
} else {
/* error handling */
}
{code}
Use the flag {{DDI_DMA_SYNC_FORKERNEL}} if the only mapping is for the kernel, as in the case of memory that is allocated by <a href="http://docs.sun.com/doc/819-2256/ddi-dma-mem-alloc-9f?a=view">{{ddi_dma_mem_alloc}}(9F)</a>. {{ddi_dma_mem_alloc}}(9F). The system tries to synchronize the kernel's view more quickly than the CPU's view. If the system cannot synchronize the kernel view faster, the system acts as if the {{DDI_DMA_SYNC_FORCPU}} flag were set.

h2. DMA Windows{anchor:windows}
{anchor:gbgtz} {anchor:indexterm-16} If an object does not fit within the limitations of the DMA engine, the transfer must be broken into a series of smaller transfers. The driver can break up the transfer itself. Alternatively, the driver can allow the system to allocate resources for only part of the object, thereby creating a series of DMA *windows*. Allowing the system to allocate resources is the preferred solution, because the system can manage the resources more effectively than the driver can manage the resources.
can allow the system to allocate resources for only part of the object, thereby
creating a series of DMA *windows*. Allowing the system to allocate resources is the preferred solution, because the system can manage the resources more effectively than the driver can manage the resources.

A DMA window has two attributes. The _offset_ attribute is measured from the beginning of the object. The _length_ attribute is the number of bytes of memory to be allocated. After a partial allocation, only a range of _length_ bytes that starts at _offset_ has allocated resources.
A DMA window is requested by specifying the {{DDI_DMA_PARTIAL}} flag as a parameter to <a href="http://docs.sun.com/doc/819-2256/ddi-dma-buf-bind-handle-9f?a=view">{{ddi_dma_buf_bind_handle}}(9F)</a> {{ddi_dma_buf_bind_handle}}(9F) or <a href="http://docs.sun.com/doc/819-2256/ddi-dma-addr-bind-handle-9f?a=view">{{ddi_dma_addr_bind_handle}}(9F)</a>. {{ddi_dma_addr_bind_handle}}(9F). Both functions return {{DDI_DMA_PARTIAL_MAP}} if a window can be established. However, the system might allocate resources for the entire object, in which case {{DDI_DMA_MAPPED}} is returned. The driver should check the return value to determine whether DMA windows are in use. See the following example.
 
h5. {anchor:dma-23815} Example&nbsp;9-7 Setting Up DMA Windows
{code}
static int
struct device_reg *regp = xsp->reg;
ddi_dma_cookie_t cookie;
int status;
mutex_enter(&amp;xsp->mu);
if (xsp->busy) {
xsp->partial = 0;
}
[...] /* ... program the DMA engine ... */
program the DMA engine
[...]
return (DDI_DMA_CALLBACK_DONE);
}
{code}
Two functions operate with DMA windows. The first, <a href="http://docs.sun.com/doc/819-2256/ddi-dma-numwin-9f?a=view">{{ddi_dma_numwin}}(9F)</a>, {{ddi_dma_numwin}}(9F), returns the number of DMA windows for a particular DMA object. The other function, <a href="http://docs.sun.com/doc/819-2256/ddi-dma-getwin-9f?a=view">{{ddi_dma_getwin}}(9F)</a>, {{ddi_dma_getwin}}(9F), allows repositioning within the object, that is, reallocation of system resources. The {{ddi_dma_getwin()}} function shifts the current window to a new window within the object. Because {{ddi_dma_getwin()}} reallocates system resources to the new window, the previous window becomes invalid.*Caution - *
 
{note:title=Caution}Do not move the DMA windows with a call to {{ddi_dma_getwin()}} before transfers into the current window are complete. Wait until the transfer to the current window is complete, which is when the interrupt arrives. Then call {{ddi_dma_getwin()}} to avoid data corruption.{note}
 
The {{ddi_dma_getwin()}} function is normally called from an interrupt routine, as shown in [Example&nbsp;9-8|#dma-41452]. Example&nbsp;9-8. The first DMA transfer is initiated as a result of a call to the driver. Subsequent transfers are started from the interrupt routine.
 
The interrupt routine examines the status of the device to determine whether the device completes the transfer successfully. If not, normal error recovery occurs. If the transfer is successful, the routine must determine whether the logical transfer is complete. A complete transfer includes the entire object as specified by the <a href="http://docs.sun.com/doc/819-2257/buf-9s?a=view">{{buf}}(9S)</a> {{buf}}(9S) structure. In a partial transfer, only one DMA window is moved. In a partial transfer, the interrupt routine moves the window with {{ddi_dma_getwin}}(9F), retrieves a new cookie, and starts another DMA transfer.
transfer, the interrupt routine moves the window with <a href="http://docs.sun.com/doc/819-2256/ddi-dma-getwin-9f?a=view">{{ddi_dma_getwin}}(9F)</a>, retrieves
a new cookie, and starts another DMA transfer.
 
If the logical request has been completed, the interrupt routine checks for pending requests. If necessary, the interrupt routine starts a transfer. Otherwise, the routine returns without invoking another DMA transfer. The following example illustrates the usual flow control.
the routine returns without invoking another DMA transfer. The following example illustrates the usual flow control.
 
h5. {anchor:dma-41452} Example&nbsp;9-8 Interrupt Handler Using DMA Windows
{code}
static uint_t
(void) ddi_dma_getwin(xsp->handle, xsp->windex,
&amp;offset, &amp;len, &amp;cookie, &amp;ccount);
/* program the DMA engine with the new cookie(s) ... */
[...]
return (DDI_INTR_CLAIMED);
}

The individuals who post here are part of the extended Sun Microsystems community and they might not be employed or in any way formally affiliated with Sun Microsystems. The opinions expressed here are their own, are not necessarily reviewed in advance by anyone but the individual authors, and neither Sun nor any other party necessarily agrees with them.

Copyright 1994-2009 Sun Microsystems, Inc.
Powered by Atlassian Confluence
Sun Guidelines on Public Discourse Privacy Policy Terms of Use Trademarks Site Map Employment Investor Relations Contact