NetBSD/share/doc/papers/bus_dma/3.me

226 lines
11 KiB
Plaintext

.\" $NetBSD: 3.me,v 1.2 2003/02/05 00:02:26 perry Exp $
.\"
.\" Copyright (c) 1998 Jason R. Thorpe.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgements:
.\" This product includes software developed for the NetBSD Project
.\" by Jason R. Thorpe.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.sh 1 "The \fIbus_dma\fB interface"
.pp
What follows is a description of \fIbus_dma\fR, the DMA portion of the
machine-independent bus access interface in NetBSD, commonly referred to
as \fIbus.h\fR\**. The DMA portion of the interface is comprised of
three DMA-specific data types and thirteen function calls. The
\fIbus_dma\fR interface also shares two data types with the
\fIbus_space\fR interface.
.(f
\**The name is derived from the name of the include file that exports
the interface.
.)f
.pp
The \fIbus_dma\fR functional interface is split into two categories:
mapping calls and memory handling calls. The function calls themselves
may be implemented as \fIcpp(1)\fR macros.
.sh 2 "Data types"
.pp
The first of the two data types shared with the \fIbus_space\fR
interface is the \fIbus_addr_t\fR type, which represents device bus
addresses to be used for CPU access or DMA, and must be large enough to
specify the largest possible bus address on the system. The second is
the \fIbus_size_t\fR type, which represents sizes of bus address ranges.
.pp
The implementation of DMA on a given host/bus combination is described
by the \fIbus_dma_tag_t\fR. This opaque type is passed to a bus's
autoconfiguration machinery by machine-dependent code. The bus layer
in turn passes it down to the device drivers. This tag is the first
argument to every function in the interface.
.pp
Individual DMA segments are described by the \fIbus_dma_segment_t\fR.
This type is a structure with two publicly accessible members. The first
member, \fIds_addr\fR, is a \fIbus_addr_t\fR containing the address of a
DMA segment. The second, \fIds_len\fR, is a
\fIbus_size_t\fR containing the length of the segment.
.pp
The third, and probably most important, data type is the \fIbus_dmamap_t\fR.
This type is a pointer to a structure which describes an individual DMA
mapping. The structure has three public members. The first member,
\fIdm_mapsize\fR is a \fIbus_size_t\fR describing the length of the
mapping, when valid. A \fIdm_mapsize\fR of 0 indicates that the
mapping is invalid. The second member, \fIdm_nsegs\fR, is an \fIint\fR
which contains the number of DMA segments that comprise the mapping.
The third public member, \fIdm_segs\fR, is an array or a pointer to
an array of \fIbus_dma_segment_t\fR structures.
.pp
In addition to data types, the \fIbus_dma\fR interface also defines
a set of flags which are passed to some of the interface's functions.
Two of these flags, \fBBUS_DMA_WAITOK\fR and \fBBUS_DMA_NOWAIT\fR,
indicate to the function that waiting for resources to become available
is or is not allowed\**. There
are also four placeholder flags, \fBBUS_DMA_BUS1\fR through
\fBBUS_DMA_BUS4\fR. These flags are reserved for the individual
bus layers, which may need to define special semantics specific to
that bus. An example of this is the ability of VESA local bus
devices to use 32-bit DMA addresses; while the kernel considers
such devices to be logically connected to the ISA bus, they are not
limited to the addressing constraints of other ISA devices.
The placeholder flags allow such special cases to be handled on
a bus-by-bus basis.
.(f
\**Waiting (also called "blocking") is allowed only if the kernel is
running in a process context, as opposed to the interrupt context used
when handling device interrupts.
.)f
.sh 2 "Mapping functions"
.pp
There are eight functions in the \fIbus_dma\fR interface that
operate on DMA maps. These can be sub-categorized into functions
that create and destroy maps, functions that load and unload mappings,
and functions that synchronize maps.
.pp
The first two functions fall into the create/destroy sub-category.
The \fIbus_dmamap_create()\fR function creates a DMA map and initializes
it according to the parameters provided. The parameters include the
maximum DMA transfer size the DMA map will map, the maximum number of
DMA segments, the maximum size of any given segment, and any DMA
boundary limitations. In addition to the standard flags,
\fIbus_dmamap_create()\fR also takes the flag \fBBUS_DMA_ALLOCNOW\fR.
This flag indicates that all resources necessary to map the maximum
size transfer should be allocated when the map is created, and is useful
in case the driver must load the DMA map at a time where blocking is not
allowed, such as in interrupt context. The \fIbus_dmamap_destroy()\fR
function destroys a DMA map, and frees any resources that may be assigned
to it.
.pp
The next five functions fall into the load/unload sub-category. The
two basic functions are \fIbus_dmamap_load()\fR and
\fIbus_dmamap_unload()\fR. The former maps a DMA transfer to or from
a linear buffer. This linear buffer may be mapped into either
kernel or a process's virtual address space.
The latter unloads the mappings previously
loaded into the DMA map. If the \fBBUS_DMA_ALLOCNOW\fR flag was
specified when the map was created, \fIbus_dmamap_load()\fR will not
block or fail on resource allocation. Similarly, when the map is
unloaded, the mapping resources will not be freed.
.pp
In addition to linear buffers handled by the basic \fIbus_dmamap_load()\fR,
there are three alternate data buffer structures handled by the interface.
The \fIbus_dmamap_load_mbuf()\fR function operates on mbuf chains. The
individual data buffers are assumed to be in kernel virtual
address space. The \fIbus_dmamap_load_uio()\fR function operates
on \fIuio\fR structures, from which it extracts information about the
address space in which the data resides. Finally, the
\fIbus_dmamap_load_raw()\fR function operates on raw memory, which
is not mapped into any virtual address space. All DMA maps loaded with
these functions are unloaded with the \fIbus_dmamap_unload()\fR function.
.pp
Finally, the map synchronization sub-category includes one function:
\fIbus_dmamap_sync()\fR. This function performs the four DMA
synchronization operations necessary to handle caches and DMA bouncing.
The four operations are:
.(b
.b
BUS_DMASYNC_PREREAD
BUS_DMASYNC_POSTREAD
BUS_DMASYNC_PREWRITE
BUS_DMASYNC_POSTWRITE
.r
.)b
The direction is expressed from the perspective of the host's memory.
In other words, a device-to-memory transfer is a read, and a
memory-to-device transfer is
a write. The synchronization operations are expressed as flags,
so it is possible to combine \fBREAD\fR and \fBWRITE\fR operations
in a single call. This is especially useful for synchronizing
mappings of device control descriptors. Mixing of \fBPRE\fR and
\fBPOST\fR operations is not allowed.
.pp
In addition to the map and operation arguments, \fIbus_dmamap_sync()\fR
also takes offset and length arguments. This is done in order to
support partial syncs. In the case where a control descriptor
is DMA'd to a device, it may be undesirable to synchronize the entire
mapping, as doing so may be inefficient or even destructive to other
control descriptors. Synchronizing the entire mapping is supported
by passing an offset of 0 and the length specified by the map's
\fIdm_mapsize\fR.
.sh 2 "Memory handling functions"
.pp
There are two sub-categories of functions that handle DMA-safe
memory in the \fIbus_dma\fR interface: memory allocation and
memory mapping.
.pp
The first function in the memory allocation sub-category,
\fIbus_dmamem_alloc()\fR, allocates memory which has the specified
attributes. The attributes that may be specified are: the size of the
memory region to allocate, the alignment of each segment in the
allocation, any boundary limitations, and the maximum number
of DMA segments that may make up the allocation. The function
fills in a provided array of \fIbus_dma_segment_t\fRs and indicates
the number of valid segments in the array. Memory allocated
by this interface is raw memory\**; it is not mapped into any virtual
address space. Once it is no longer in use, it may be freed with
the \fIbus_dmamem_free()\fR function.
.(f
\**This implies that \fIbus_dmamap_load_raw()\fR is an appropriate
interface for mapping a DMA transfer to or from memory allocated by
this interface.
.)f
.pp
In order for the kernel or a user process to access the memory,
it must be mapped either into the kernel address space or the process's
address space. These
operations are performed by the memory mapping sub-category of DMA-safe
memory handling functions.
The \fIbus_dmamem_map()\fR function maps the specified DMA-safe
raw memory into the kernel address space. The address
of the mapping is returned by filling in a pointer passed
by reference. Memory mapped in this manner may be unmapped by
calling \fIbus_dmamem_unmap()\fR.
.pp
DMA-safe raw memory may be mapped into a process's address space via
a device driver's \fImmap()\fR entry point. In order to do this,
the VM system's device pager repeatedly calls the driver,
once for each page that is to be mapped. The driver translates
the user-specified mmap offset into a DMA memory offset, and
calls the \fIbus_dmamem_mmap()\fR function to translate the
memory offset into an opaque value to be interpreted
by the \fIpmap module\**\fR. The device pager invokes the
pmap module to translate the mmap cookie into a physical page
address which is then mapped into the process's address space.
.(f
\**The pmap module is the machine-dependent layer of the NetBSD
virtual memory system.
.)f
.pp
There are currently no methods for the virtual memory system to specify
that an mmap'd area is being unmapped, or for the device driver to specify
to the virtual memory system that a mmap'd region must be forcibly unmapped
(for example, if a hot-swapable device has been removed from the system).
This is widely regarded as a bug, and may be addressed in a future version
of the NetBSD virtual memory system. If a change to this effect is made,
the \fIbus_dma\fR interface will have to be adjusted accordingly.