home | help
BUS_DMA(9)		    Kernel Developer's Manual		      BUS_DMA(9)

NAME
     bus_dma,	 bus_dma_tag_create,   bus_dma_tag_destroy,   bus_dmamap_create,
     bus_dmamap_destroy,	 bus_dmamap_load,	   bus_dmamap_load_mbuf,
     bus_dmamap_load_uio,  bus_dmamap_unload, bus_dmamap_sync, bus_dmamem_alloc,
     bus_dmamem_free -- Bus and Machine Independent DMA Mapping Interface

SYNOPSIS
     #include <machine/bus.h>

     int
     bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
	 bus_size_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
	 bus_dma_filter_t *filtfunc, void *filtfuncarg, bus_size_t maxsize,
	 int nsegments, bus_size_t maxsegsz, int flags,
	 bus_dma_lock_t *lockfunc, void *lockfuncarg, bus_dma_tag_t *dmat);

     int
     bus_dma_tag_destroy(bus_dma_tag_t dmat);

     int
     bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp);

     int
     bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map);

     int
     bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
	 bus_size_t buflen, bus_dmamap_callback_t *callback, void *callback_arg,
	 int flags);

     int
     bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map,
	 struct mbuf *mbuf, bus_dmamap_callback2_t *callback,
	 void *callback_arg, int flags);

     int
     bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
	 bus_dmamap_callback2_t *callback, void *callback_arg, int flags);

     int
     bus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags,
	 bus_dmamap_t *mapp);

     void
     bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map);

     void
     bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, op);

     void
     bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map);

DESCRIPTION
     Direct Memory Access (DMA) is a method of transferring data without involv-
     ing the CPU, thus providing higher performance.  A DMA transaction  can  be
     achieved between device to memory, device to device, or memory to memory.

     The bus_dma API is a bus, device, and machine-independent (MI) interface to
     DMA  mechanisms.  It provides the client with flexibility and simplicity by
     abstracting machine dependent issues like setting up DMA mappings, handling
     cache issues, bus specific features and limitations.

STRUCTURES AND TYPES
     bus_dma_tag_t
	      A machine-dependent (MD) opaque type that describes the character-
	      istics of DMA transactions.  DMA tags are organized into a hierar-
	      chy, with each child tag inheriting the restrictions of  its  par-
	      ent.   This  allows all devices along the path of DMA transactions
	      to contribute to the constraints of those transactions.

     bus_dma_filter_t
	      Client specified address filter having the format:

	      int      client_filter(void *filtarg, bus_addr_t testaddr)

	      Address filters can be specified during tag creation to allow  for
	      devices  who's  DMA  address restrictions cannot be specified by a
	      single window.  The filtarg is client specified  during  tag  cre-
	      ation  to  be  passed  to  all  invocations  of the callback.  The
	      testaddr argument contains a potential starting address of  a  DMA
	      mapping.	 The  filter  function	operates on the set of addresses
	      from testaddr to `trunc_page(testaddr) + PAGE_SIZE  -  1',  inclu-
	      sive.   The  filter function should return zero for any mapping in
	      this range that can be accommodated by  the  device  and	non-zero
	      otherwise.

     bus_dma_segment_t
	      A machine-dependent type that describes individual DMA segments.

		      bus_addr_t      ds_addr;
		      bus_size_t      ds_len;

	      The  ds_addr  field contains the device visible address of the DMA
	      segment, and ds_len contains the length of the DMA  segment.   Al-
	      though  the DMA segments returned by a mapping call will adhere to
	      all restrictions necessary for a successful  DMA	operation,  some
	      conversion (e.g. a conversion from host byte order to the device's
	      byte  order) is almost always required when presenting segment in-
	      formation to the device.

     bus_dmamap_t
	      A machine-dependent opaque type describing an individual	mapping.
	      Multiple DMA maps can be associated with one DMA tag.

     bus_dmamap_callback_t
	      Client  specified  callback  for receiving mapping information re-
	      sulting from the load of	a  bus_dmamap_t  via  bus_dmamap_load().
	      Callbacks are of the format:

	      void     client_callback(void   *callback_arg,   bus_dma_segment_t
		       *segs, int nseg, int error)

	      The callback_arg is the callback argument passed	to  dmamap  load
	      functions.   The	segs  and  nseg  parameters describe an array of
	      bus_dma_segment_t structures that represent the mapping.	This ar-
	      ray is only valid within the scope of the callback function.   The
	      success  or failure of the mapping is indicated by the error para-
	      meter.  More information on the use of callbacks can be  found  in
	      the description of the individual dmamap load functions.

     bus_dmamap_callback2_t
	      Client  specified  callback  for receiving mapping information re-
	      sulting from the load of a bus_dmamap_t via  bus_dmamap_load_uio()
	      or bus_dmamap_load_mbuf().

	      Callback2s are of the format:

	      void     client_callback2(void   *callback_arg,  bus_dma_segment_t
		       *segs, int nseg, bus_size_t mapsize, int error)

	      Callback2's behavior is the same as bus_dmamap_callback_t with the
	      addition that the length	of  the  data  mapped  is  provided  via
	      mapsize.

     bus_dmasync_op_t
	      Memory  synchronization operation specifier.  Bus DMA requires ex-
	      plicit synchronization of memory with it's device visible  mapping
	      in  order to guarantee memory coherency.	The bus_dmasync_op_t al-
	      lows the type of DMA operation that will be or has been  performed
	      to  be  communicated  to	the system so that the correct coherency
	      measures are taken.  All operations specified below are  performed
	      from  the CPU's point of view (for a complete description, see the
	      bus_dmamap_sync() description below):

	      BUS_DMASYNC_PREREAD    Perform any synchronization required  after
				     an update of memory by the CPU but prior to
				     DMA read operations.

	      BUS_DMASYNC_PREWRITE   Perform  any synchronization required after
				     an update of memory by the CPU but prior to
				     DMA write operations.

	      BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE
				     Perform any synchronization required  prior
				     to  a combination of DMA read and write op-
				     erations.

	      BUS_DMASYNC_POSTREAD   Perform any synchronization required  after
				     DMA  read	operations, but prior to CPU ac-
				     cess of the memory.

	      BUS_DMASYNC_POSTWRITE  Perform any synchronization required  after
				     DMA  write operations, but prior to CPU ac-
				     cess of the memory.

	      BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE
				     Perform any synchronization required  after
				     a	combination of DMA read and write opera-
				     tions.

     bus_dma_lock_t
	      Client specified lock/mutex manipulation	method.   This	will  be
	      called  from  within busdma whenever a client lock needs to be ma-
	      nipulated.  This method is of the format:

	      void     lockfunc(void *lockfunc_arg, bus_dma_lock_op_t op)

	      Two lockfunc implementations are provided for  convenience.   bus-
	      dma_lock_mutex()	performs  standard mutex operations on the sleep
	      mutex provided via the lockfuncarg.  passed into	bus_dma_tag_cre-
	      ate().   dflt_lock() will generate a system panic if it is called.
	      It is substituted into the tag when lockfunc is passed as NULL  to
	      bus_dma_tag_create().

     bus_dma_lock_op_t
	      Operations to be performed by the client-specified lockfunc().

	      BUS_DMA_LOCK    Acquires	and/or	locks  the client locking primi-
			      tive.

	      BUS_DMA_UNLOCK  Releases and/or unlocks the client locking  primi-
			      tive.

FUNCTIONS
     bus_dma_tag_create(parent,  alignment,  boundary, lowaddr, highaddr, *filt-
	      func, *filtfuncarg, maxsize, nsegments, maxsegsz, flags, lockfunc,
	      lockfuncarg, *dmat)
	      Allocates a device specific DMA tag, and initializes it  according
	      to the arguments provided:
	      parent	    Indicates  restrictions  between  the parent bridge,
			    CPU memory, and the device.  May be NULL, if no  DMA
			    restrictions are to be inherited.
	      alignment     Alignment constraint, in bytes, of any mappings cre-
			    ated  using this tag.  The alignment must be a power
			    of 2.  Hardware that can DMA starting at any address
			    would specify 1 for byte  alignment.   Hardware  re-
			    quiring  DMA  transfers to start on a multiple of 4K
			    would specify 4096.
	      boundary	    Boundary constraint, in bytes,  of	the  target  DMA
			    memory  region.   The  boundary indicates the set of
			    addresses, all multiples of the  boundary  argument,
			    that    cannot    be    crossed    by    a	  single
			    bus_dma_segment_t.	The boundary must be a power  of
			    2  and  must  be no smaller that the maximum segment
			    size.  `0' indicates that there are no boundary  re-
			    strictions.
	      lowaddr
	      highaddr	    Bounds  of	the  window  of  bus  address space that
			    cannot be directly accessed by the device.	The win-
			    dow contains all address greater  than  lowaddr  and
			    less  than or equal to highaddr.  For example, a de-
			    vice incapable of DMA above  4GB,  would  specify  a
			    highaddr  of  BUS_SPACE_MAXADDR  and  a  lowaddr  of
			    BUS_SPACE_MAXADDR_32BIT.  Similarly  a  device  that
			    can  only dma to addresses bellow 16MB would specify
			    a highaddr of BUS_SPACE_MAXADDR  and  a  lowaddr  of
			    BUS_SPACE_MAXADDR_24BIT.   Some  implementations re-
			    quires that some region of	device	visible  address
			    space, overlapping available host memory, be outside
			    the  window.   This area of `safe memory' is used to
			    bounce requests that would otherwise  conflict  with
			    the exclusion window.
	      filtfunc	    Optional  filter function (may be NULL) to be called
			    for any attempt to map memory into	the  window  de-
			    scribed  by  lowaddr and highaddr. A filter function
			    is only required when the single window described by
			    lowaddr and highaddr cannot adequately describe  the
			    constraints of the device.	The filter function will
			    be	called	for every machine page that overlaps the
			    exclusion window.
	      filtfuncarg   Argument passed to all calls to the filter	function
			    for this tag.  May be NULL.
	      maxsize	    Maximum  size,  in	bytes, of the sum of all segment
			    lengths in a given DMA mapping associated with  this
			    tag.
	      nsegments     Number  of discontinuities (scatter/gather segments)
			    allowed in a DMA mapped region.  If there is no  re-
			    striction, BUS_SPACE_UNRESTRICTED may be specified.
	      maxsegsz	    Maximum  size,  in	bytes,	of  a segment in any DMA
			    mapped region associated with dmat.
	      flags	    Are as follows:
			    BUS_DMA_ALLOCNOW  Allocate the  resources  necessary
					      to guarantee that all map load op-
					      erations	associated with this tag
					      will not block.  If sufficient re-
					      sources are not available,  ENOMEM
					      is returned.
	      lockfunc	    Optional lock manipulation function (may be NULL) to
			    be	called when busdma needs to manipulate a lock on
			    behalf  of	the  client.   If  NULL  is   specified,
			    dflt_lock() is used.
	      lockfuncarg   Optional argument to be passed to the function spec-
			    ified by lockfunc.
	      dmat	    Pointer  to  a bus_dma_tag_t where the resulting DMA
			    tag will be stored.

	      Returns ENOMEM if sufficient memory is not available for tag  cre-
	      ation or allocating mapping resources.

     bus_dma_tag_destroy(dmat)
	      Deallocate  the  DMA tag dmat that was created by bus_dma_tag_cre-
	      ate().

	      Returns EBUSY if any DMA maps remain associated with dmat  or  `0'
	      on success.

     bus_dmamap_create(dmat, flags, *mapp)
	      Allocates and initializes a DMA map.  Arguments are as follows:
	      dmat	 DMA tag.
	      flags	 The  value  of this argument is currently undefined and
			 should be specified as `0'.
	      mapp	 Pointer to a bus_dmamap_t where the resulting	DMA  map
			 will be stored.

	      Returns  ENOMEM if sufficient memory is not available for creating
	      the map or allocating mapping resources.

     bus_dmamap_destroy(dmat, map)
	      Frees all resources associated with a given  DMA	map.   Arguments
	      are as follows:
	      dmat  DMA tag used to allocate map.
	      map   The DMA map to destroy.

	      Returns EBUSY if a mapping is still active for map.

     bus_dmamap_load(dmat, map, buf, buflen, *callback, ...)
	      Creates  a mapping in device visible address space of buflen bytes
	      of buf, associated with the DMA map map. Arguments are as follows:
	      dmat    DMA tag used to allocate map.
	      map     A DMA map without a currently active mapping.
	      buf     A kernel virtual address pointer to a contiguous (in  KVA)
		      buffer, to be mapped into device visible address space.
	      buflen  The size of the buffer.
	      callback callback_arg
		      The callback function, and its argument.
	      flags   The  value  of  this  argument is currently undefined, and
		      should be specified as `0'.

	      Return values to the caller are as follows:
	      0 	   The callback has been called and completed.	The sta-
			   tus of the mapping has been delivered  to  the  call-
			   back.
	      EINPROGRESS  The	mapping has been deferred for lack of resources.
			   The callback will be called as soon as resources  are
			   available.	Callbacks  are	serviced  in FIFO order.
			   DMA maps created from DMA  tags  that  are  allocated
			   with the BUS_DMA_ALLOCNOW flag will never return this
			   status for a load operation.
	      EINVAL	   The	load request was invalid.  The callback has not,
			   and will not be called.  This error value  may  indi-
			   cate  that  dmat, map, buf, or callback were invalid,
			   or buslen was larger than the maxsize  argument  used
			   to create the dma tag dmat.

	      When  the  callback is called, it is presented with an error value
	      indicating the disposition of the mapping.  Error may  be  one  of
	      the following:
	      0 	   The	mapping  was successful and the dm_segs callback
			   argument contains an array of bus_dma_segment_t  ele-
			   ments  describing  the  mapping.   This array is only
			   valid during the scope of the callback function.
	      EFBIG	   A mapping could not be achieved  within  the  segment
			   constraints	provided  in the tag even though the re-
			   quested allocation size was less than maxsize.

     bus_dmamap_load_mbuf(dmat, map, mbuf, callback2, callback_arg, flags)
	      This is a variation of bus_dmamap_load() which  maps  mbuf  chains
	      for  DMA	transfers.   A bus_size_t argument is also passed to the
	      callback routine, which contains the mbuf  chain's  packet  header
	      length.

	      Mbuf chains are assumed to be in kernel virtual address space.

	      Returns  EINVAL  if the size of the mbuf chain exceeds the maximum
	      limit of the DMA tag.

     bus_dmamap_load_uio(dmat, map, uio, callback2, callback_arg, flags)
	      This is  a  variation  of  bus_dmamap_load()  which  maps  buffers
	      pointed  to  by  uio  for DMA transfers.	A bus_size_t argument is
	      also passed to the callback routine, which contains  the	size  of
	      uio, i.e.  uio->uio_resid.

	      If  uio->uio_segflg  is UIO_USERSPACE, then it is assumed that the
	      buffer, uio is  in  uio->uio_td->td_proc's  address  space.   User
	      space  memory  must be in-core and wired prior to attempting a map
	      load operation.

     bus_dmamap_unload(dmat, map)
	      Unloads a DMA map.  Arguments are as follows:
	      dmat  DMA tag used to allocate map.
	      map   The DMA map that is to be unloaded.

	      bus_dmamap_unload() will not perform any implicit  synchronization
	      of  DMA  buffers.   This	must  be  done	explicitly  by a call to
	      bus_dmamap_sync() prior to unloading the map.

     bus_dmamap_sync(dmat, map, op)
	      Performs synchronization of a device visible mapping with the  CPU
	      visible  memory referenced by that mapping.  Arguments are as fol-
	      lows:
	      dmat  DMA tag used to allocate map.
	      map   The DMA mapping to be synchronized.
	      op    Type of synchronization operation to perform.  See the defi-
		    nition of bus_dmasync_op_t for a description of the  accept-
		    able values for op.

	      bus_dmamap_sync() is the method used to ensure that CPU and device
	      DMA  access  to  shared  memory is coherent.  For example, the CPU
	      might be used to setup the contents of a	buffer	that  is  to  be
	      DMA'ed into a device.  To ensure that the data are visible via the
	      device's	mapping  of that memory, the buffer must be loaded and a
	      dma sync operation of BUS_DMASYNC_PREREAD must be performed.   Ad-
	      ditional	sync  operations must be performed after every CPU write
	      to this memory if additional DMA reads are to be performed.   Con-
	      versely,	for the DMA write case, the buffer must be loaded, and a
	      dma sync operation of BUS_DMASYNC_PREWRITE must be performed.  The
	      CPU will only be able to see the results of this	DMA  write  once
	      the  DMA	has  completed and a BUS_DMASYNC_POSTWRITE operation has
	      been performed.

	      If DMA read and write operations are not preceded and followed  by
	      the appropriate synchronization operations, behavior is undefined.

     bus_dmamem_alloc(dmat, **vaddr, flags, mapp)
	      Allocates  memory  that is mapped into KVA at the address returned
	      in vaddr	that  is  permanently  loaded  into  the  newly  created
	      bus_dmamap_t returned via mapp.  Arguments are as follows:
	      dmat	 DMA tag describing the constraints of the DMA mapping.
	      vaddr	 Pointer  to  a  pointer that will hold the returned KVA
			 mapping of the allocated region.
	      flags	 Flags are defined as follows:
			 BUS_DMA_WAITOK  The routine can safely wait (sleep) for
					 resources.
			 BUS_DMA_NOWAIT  The routine is not allowed to wait  for
					 resources.  If resources are not avail-
					 able, ENOMEM is returned.
			 BUS_DMA_COHERENT
					 Attempt  to  map  this memory such that
					 cache sync operations are as  cheap  as
					 possible.   This  flag is typically set
					 on memory that will be accessed by both
					 a CPU and  a  DMA  engine,  frequently.
					 Use  of  this	flag does not remove the
					 requirement of  using	bus_dmamap_sync,
					 but  it may reduce the cost of perform-
					 ing these operations.
			 BUS_DMA_ZERO	 Causes the allocated memory to  be  set
					 to all zeros.
	      mapp	 Pointer to storage for the returned DMA map.

	      The  size  of  memory  to  be allocated is maxsize as specified in
	      dmat.

	      The current implementation of bus_dmamem_alloc() will allocate all
	      requests as a single segment.

	      Although no explicit loading is required to access the memory ref-
	      erenced by the returned map, the synchronization	requirements  as
	      described in the bus_dmamap_sync() section still apply.

	      Returns  ENOMEM if sufficient memory is not available for complet-
	      ing the operation.

     bus_dmamem_free(dmat, *vaddr, map)
	      Frees memory previously allocated by bus_dmamem_alloc().	Any map-
	      pings will be invalidated.  Arguments are as follows:
	      dmat   DMA tag.
	      vaddr  Kernel virtual address of the memory.
	      map    DMA map to be invalidated.

RETURN VALUES
     Behavior is undefined if invalid arguments are passed to any of  the  above
     functions.   If sufficient resources cannot be allocated for a given trans-
     action, ENOMEM is returned.  All routines that are not of type, void,  will
     return 0 on success or an error code, as discussed above.

     All void routines will succeed if provided with valid arguments.

SEE ALSO
     devclass(9), device(9), driver(9), rman(9)

     Jason R. Thorpe, "A Machine-Independent DMA Framework for NetBSD", Proceed-
     ings  of  the  Summer 1998 USENIX Technical Conference, USENIX Association,
     June 1998.

HISTORY
     The bus_dma interface first appeared in NetBSD 1.3.

     The bus_dma API was adopted from NetBSD for use in the CAM SCSI  subsystem.
     The  alterations  to  the	original API were aimed to remove the need for a
     bus_dma_segment_t array stored in each bus_dmamap_t while allowing  callers
     to queue up on scarce resources.

AUTHORS
     The  bus_dma  interface  was designed and implemented by Jason R. Thorpe of
     the Numerical Aerospace Simulation Facility,  NASA  Ames  Research  Center.
     Additional  input	on  the  bus_dma design was provided by Chris Demetriou,
     Charles Hannum, Ross  Harvey,  Matthew  Jacob,  Jonathan  Stone,  and  Matt
     Thomas.

     The  bus_dma interface in FreeBSD benefits from the contributions of Justin
     T. Gibbs, Peter Wemm, Doug Rabson, Matthew N.  Dodd,  Sam	Leffler,  Maxime
     Henrion, Jake Burkholder, Takahashi Yoshihiro, Scott Long and many others.

     This manual page was written by Hiten M. Pandya and Justin T. Gibbs.

FreeBSD 5.3			  May 28, 2003			      BUS_DMA(9)

home | help