pciio_dma(D3)pciio_dma(D3)NAME
pciio_dma: pciio_dmatrans_addr, pciio_dmatrans_list, pciio_dmamap_alloc,
pciio_dmamap_addr, pciio_dmamap_list, pciio_dmamap_done,
pciio_dmamap_free, pciio_dma_addr, pciio_dmamap_drain,
pciio_dmaaddr_drain, pciio_dmalist_drain - manage DMA on PCI bus
SYNOPSIS
#include <sys/PCI/pciio.h>
iopaddr_t
pciio_dmatrans_addr(
vertex_hdl_t vhdl,
device_desc_t desc,
paddr_t addr,
size_t size,
unsigned flags)
alenlist_t
pciio_dmatrans_list(
vertex_hdl_t vhdl,
device_desc_t desc,
alenlist_t list,
unsigned flags)
pciio_dmamap_t
pciio_dmamap_alloc(
vertex_hdl_t vhdl,
device_desc_t desc,
size_t max,
unsigned flags)
iopaddr_t
pciio_dmamap_addr(
pciio_dmamap_t map,
paddr_t addr,
size_t size);
alenlist_t
pciio_dmamap_list(
pciio_dmamap_t map,
alenlist_t list,
unsigned flags);
void
pciio_dmamap_done(pciio_dmamap_t map)
void
pciio_dmamap_free(pciio_dmamap_t map)
iopaddr_t
pciio_dma_addr(
vertex_hdl_t vhdl,
Page 1
pciio_dma(D3)pciio_dma(D3)
device_desc_t desc,
paddr_t addr,
size_t size,
pciio_dmamap_t *mapp,
unsigned flags)
void
pciio_dmamap_drain(
pciio_dmamap_t *map)
void
pciio_dmaaddr_drain(
vertex_hdl_t vhdl,
paddr_t addr,
size_t bytes)
void
pciio_dmalist_drain(
vertex_hdl_t vhdl,
alenlist_t *list)
Arguments
addr The DMA buffer address in system physical address space.
desc A device descriptor, usually zero.
flags
Attributes of the mapping.
list An address/length list as prepared by one of the alenlist
construction functions (see alenlist(D4)).
map A dma map as returned by pciio_dmamap_alloc().
mapp A place to return a map allocated as a side effect of other work;
must be initialized to zero, or to a map that should be used instead
of allocating one.
max The maximum range of addresses this map will cover at any one time.
size The size of the mapped buffer in bytes.
vhdl The device connection point as passed to the attach() entry
point.
DESCRIPTION
When a device driver wishes to use Direct Memory Access (DMA) to
communicate with a device, the system needs to have a chance to set up
any appropriate mapping registers. The work to be done varies with the
available hardware and with the version of IRIX. The functions described
here provide an abstract interface to the creation of DMA mapping objects
that is consistent across most hardware. These functions always do the
Page 2
pciio_dma(D3)pciio_dma(D3)
least possible work given the available hardware.
There are two different models for setting up a DMA map, one simple but
fallible and the other more general. In both models, the final goal is
to retrieve an address in PCI bus address space that can be used by a PCI
device to write into, or read from, system physical memory.
Simple Model
The simple model provides permanent mappings through fixed mapping
resources that may or may not exist in a given system at a given time.
pciio_dmatrans_addr() is the one-stop shopping place for using system
fixed shareable mapping resources to construct a DMA address. This is
not always possible. When it is not, the function returns NULL.
pciio_dmatrans_list() is similar, but operates on a list of blocks of
memory and returns a list of blocks in PCI address space.
When they work, these functions allow the driver to set up DMA with the
fewest complications. Typically the functions always succeed in some
platforms (those having simple hardware mappings of PCI to memory), and
always fail in other platforms (where multiple layers of hardware
mappings must be configured dynamically). However, drivers that use them
should be coded as if the functions could succeed or fail alternately in
the same system (which they could).
General Model
It is not always possible to establish DMA mappings using common shared
system resources, so the concept of a DMA channel that preallocates
scarce mapping resources is provided.
Such a channel is allocated using pciio_dmamap_alloc(), which is given
the maximum size to be mapped. pciio_dmamap_addr() or
pciio_dmamap_list() is then applied to the map to actually establish the
proper mappings for a DMA target. Given the base address and block size
of the buffer for DMA (or a list of buffers), the functions hand back the
base PCI address to use for accessing that buffer (or a list of PCI
addresses).
pciio_dmamap_drain(), pciio_dmaaddr_drain() or pciio_dmalist_drain() are
used (depending on how the mapping was created) after a device reports it
has completed DMA, to ensure that all data along the DMA path has in fact
reached its destination.
When all DMA to a given buffer (or list) is complete, pciio_dmamap_done()
should be called to idle any mapping hardware (and possibly flush out any
pipes or buffers along the path that might do unexpected things when
mapping registers are modified). Later, pciio_dmamap_addr() or
pciio_dmamap_list() can again be called, specifying the same or another
buffer area.
Page 3
pciio_dma(D3)pciio_dma(D3)
When a driver is completely finished with a DMA channel -- because the
channel is used only for initialization of the device, because the
driver's close() entry point is called so it is known that the device
will be idle for some time, or because the device or the driver is being
shut down -- the DMA channel resources should be released using
pciio_dmamap_free().
pciio_dma_addr() combines pciio_dmatrans_addr() and the
pciio_dmamap_alloc() / pciio_dmamap_addr() facilities; it attempts to do
the direct translation, and if that fails, allocates a dmamap and
attempts to map through it. The mapp parameter should point to a
pciio_dmamap_t which has been either set to NULL, or set to a map that
should be used if one is needed. On return, the value will be cleared if
the direct translation worked, or set to the map that was used.
DMA Attribute Flags
The following attributes are specified in the flags argument:
PCIIO_FIXED specifies that all DMA translations are done using fixed
shared resources. The results of those translations remain
valid permanently, even if the map resource is subsequently
used to obtain additional mappings. Fixed shared resources
are not always available.
PCIIO_NOSLEEP
specifies that any resources that are needed from the system
are allocated without sleeping. If any resource allocation
would require the infrastructure to sleep, the service call
returns a failure code.
PCIIO_INPLACE
on a list operation requests that the input list be modified
in place. When this flag is not specified, a new list is
allocated for the translated addresses. Allocating a new
list preserves the contents of the input list. However, it
can take longer, may require sleeping, and may fail
(especially if PCIIO_NOSLEEP is specified).
PCIIO_DMA_CMD
specifies that the DMA channel will be used for command-type
transactions. The channel is set up to optimize short
transactions with frequent changes of direction. Unless a
more specific request is made using one of the other flags,
any prefetch and write-gatherer hardware in the path is
disabled.
PCIIO_DMA_DATA
specifies that the DMA channel will be used for data-type
transactions. The channel is set up to optimize longer
transfers. Unless a more specific request is made using one
of the other flags, any prefetch and write-gatherer hardware
in the path may be enabled.
Page 4
pciio_dma(D3)pciio_dma(D3)
PCIIO_DMA_A64
indicates that the device is capable of using 64-bit PCI
addresses for DMA. If this flag is not specified, only DMA
addresses in the low 4GB of PCI address space can be
generated. On some systems, 32-bit PCI addresses are a
limited resource. The map request fails if a 32-bit region
cannot be allocated.
PCIIO_WRITE_GATHER
indicates that the device driver believes turning on write-
gather hardware for this DMA channel is a good thing. The
flag overrides the write-gather choice from PCIIO_DMA_CMD.
PCIIO_NOWRITE_GATHER
indicates that the device driver believes turning on write-
gather hardware for this DMA channel is a bad thing. The
flag overrides the write gather choice from PCIIO_DMA_DATA.
PCIIO_PREFETCH
indicates that the device driver believes turning on
prefetching hardware for this DMA channel is a good thing.
The flag overrides the prefetch choice from PCIIO_DMA_CMD.
PCIIO_NOPREFETCH
indicates that the device driver believes turning on
prefetching hardware for this DMA channel is a bad thing.
The flag overrides the prefetch settings from PCIIO_DMA_DATA.
PCIIO_BYTE_STREAM
demands that any byte-swapping hardware along this DMA path
be organized so that an ordered stream of bytes from the
device are deposited in order in system memory. This is the
typical setting for data streams. If this endianness cannot
be supplied, then the service call fails.
PCIIO_WORD_VALUES
demands that any byte-swapping hardware along this DMA path
be initialized so that 32-bit quantities on PCI-bus 32-bit
boundaries maintain their binary values. This is the typical
setting for command-type transactions because command words
exchanged with a little-endian PCI device retain their binary
values. If this endianness cannot be supplied, then the
service call fails.
When PCIIO_BYTE_STREAM is used, the bytes of multibyte values embedded in
input data are found at their original offsets. Multibyte values from
little-endian devices may require programmed swapping before use.
When PCIIO_WORD_VALUES is used,
Page 5
pciio_dma(D3)pciio_dma(D3)
o Single bytes in input data are found at the offset the device places
them, exclusive-or with 3.
o 16-bit quantities in input data are found at the offset used by the
device, exclusive-or with 2, and do not need to be byteswapped.
o 32-bit values are found at the expected offset, and do not need to be
byteswapped.
o 64-bit values are found at the expected offset, and their 32-bit
halves need to be swapped before use.
EXAMPLES
Here is one way that a driver might make use of dmamap and dmatrans
calls.
pcifoo_attach(vertex_hdl_t vhdl)
{
pciio_dmamap_t command_map;
iopaddr_t command_dma;
struct pcifoo_regs *reg_pio;
struct pcifoo_ring *command_ring;
...
/*
* This driver has decided to use a dmamap
* to get to its command rings, which contain
* things like DMA addresses and counts; we
* set PCIIO_WORD_VALUES so we don't have to
* byteswap the 32-bit values.
*
* We still have to swap the upper and lower
* halves of the 64-bit values.
*/
/* allocate the channel
*/
command_map = pciio_dmamap_alloc(
vhdl, 0,
RINGBYTES,
PCIIO_DMA_CMD |
PCIIO_WORD_VALUES);
command_dma = pciio_dmamap_addr(
command_map,
kvtophys(command_ring),
RINGBYTES);
/* tell the device where it can find
* it's command rings.
*/
reg_pio->command_dma = command_dma;
...
}
{
caddr_t data_buffer;
Page 6
pciio_dma(D3)pciio_dma(D3)
size_t data_size;
...
data_dma = pciio_dmatrans_addr(
vhdl, 0,
kvtophys(data_buffer), data_size,
PCIIO_DMA_DATA|
PCIIO_DMA_A64|
PCIIO_BYTE_STREAM);
command_ring->data_dma_lo = data_dma & 0xFFFFFFFF;
command_ring->data_dma_hi = data_dma >> 32;
command_ring->data_dma_size = data_size;
command_ring->ready = 1;
}
SEE ALSOalenlist(D3), pcibr_get_dmatrans_node(D3), pciio(D3), pciio_config(D3),
pciio_error(D3), pciio_get(D3), pciio_intr(D3), pciio_pio(D3).
NOTE
Do not point the mapp parameter to the pciio_dma_addr() function at your
only copy of a map pointer, since it will write a NULL through this
pointer when direct translations work.
In IRIX 6.3, pciio_dmatrans_list() is declared and implemented with two
arguments only, taking no flags argument. When porting a driver from
IRIX 6.3, add a third argument of NULL (or other flag values as desired).
DIAGNOSTICSpciio_dmatrans_addr() returns zero if shared (fixed) resources can not be
used to construct a valid PCI address that maps to the desired range of
physical addresses.
pciio_dmatrans_list() returns a null pointer if any of the requested
physical address blocks can not be reached using shared fixed resources,
or if unable to allocate a return list.
pciio_dmamap_alloc() returns a null pointer if resources can not be
allocated to establish DMA mappings of the requested size, or if the
parameters are inconsistent.
pciio_dmamap_addr() returns zero if the specified target address can not
be mapped using the specified DMA channel. This would usually be due to
specifying a target block that is outside the previously specified target
area or is larger than the previously specified maximum mapping size. It
may also return a null pointer if the DMA channel is currently in use and
has not been marked idle by a call to pciio_dmamap_done().
pciio_dmamap_list() can return a null pointer for all the reasons
mentioned above, or if it is unable to allocate the return list.
Page 7