226 lines
11 KiB
Plaintext
226 lines
11 KiB
Plaintext
|
.\" $NetBSD: 3.me,v 1.1 1998/07/15 00:34:54 thorpej 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 utilize 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.
|