Subject: ISA bounce buffer/DMA interface
To: None <tech-kern@NetBSD.ORG>
From: Juergen Hannken-Illjes <>
List: tech-kern
Date: 09/14/1995 10:54:47
I'm about to implement the ISA bounce buffer & DMA interface ironed out by
Chris Demetriou on the i386 port. I have modified his last interface
specification (dated Sun, 04 Jun 1995) a little bit.

Main change is the introduction of a 'sizes' array to hold the size
for each 'mappings' entry. The result will be an array of (phys addr, size)
pairs. This is a more general representation for scattered DMA segments.


Juergen Hannken-Illjes - - TU Braunschweig (W Germany)

Here comes sys/dev/isa/isadmavar.h (changes flagged by '|' in first column):
   * Machine-independent functions to manipulate the DMA controllers.
  /* Enable the use of a DMA channel by a bus master. */
  void    isadma_cascade __P((int chan));
          This is the same as the old isa_dma_cascade; renamed for
  /* Start/abort/finish a DMAC-controlled DMA transfer. */
  void    isadma_start __P((caddr_t addr, vm_size_t size, int chan, int flags));
  void    isadma_abort __P((int chan));
  void    isadma_done __P((int chan));
          Flags below (which just specify read/write).  (I didn't
          particularly like the old use of B_READ.  Also didn't want
          anybody to not get caught when quickly converting their code.)
          DMAs started with isadma_start() _MUST_ be finished by a call
          to either isadma_abort() or isadma_done().  The MI ISA DMA
          code keeps track of per channel resources, and will panic
          if the protocol isn't followed.  This is necessary because
          some machines must allocate resources to enable the DMA
          (in addition to the DMA channel itself), and those resource
          must be freed.
          If a DMA transfer would cross a 64k/128k boundary (for 8/16
          bit transfers, respectively), it will be bounce buffered.
          (8/16 bit transfer size is determined by channel number.)
   * Machine-dependent functions to do mappings from virtual addresses
   * to physical addresses, bounce buffering, and DMA buffer copying.
   * Used by drivers for bus-mastering ISA devices and by the functions
   * which do DMAC-controlled DMA.
  int     isadma_map __P((caddr_t addr, vm_size_t size, vm_offset_t *mappings,
|             vm_offset_t *sizes, int flags));
  void    isadma_unmap __P((caddr_t addr, vm_size_t size, int nmappings,
|             vm_offset_t *mappings, vm_offset_t *sizes));
  void    isadma_copytobuf __P((caddr_t addr, vm_size_t size, int nmappings,
|             vm_offset_t *mappings, vm_offset_t *sizes));
  void    isadma_copyfrombuf __P((caddr_t addr, vm_size_t size, int nmappings,
|             vm_offset_t *mappings, vm_offset_t *sizes));
          These functions do what I indicated before: virtual ->
          physical mapping, disposal of that mapping, and any copying
          to or from the mapped buffers.  isadma_map() flags explained
          'mappings' is an array of physical addresses.  later, the type
          will be changed to isa_addr_t or something similar -- a 32
          bit quantity.  (24 bits would be better, but i dunno if one
          can get the compiler to do that reasonably...  8-)  The pointer
          given to isadma_map() must be large enough to hold
|                 roundup(size,PAGE_SIZE)+1
|         elements.  'sizes' is an array of sizes corresponding to 'mappings'.
|         ? Would it be better to use a 'struct isadma_seg' instead ?
|         ? What about an initial array size parameter to 'isadma_map' ?
|	  If ISADMA_MAP_CONTIG is specified, only one (addr,size) pair
|	  will be used.
          isadma_map() returns the number of mappings filled in,
          and that number must be passed (along with the mappings
          array) to the rest of the functions.  If isadma_map()
          fails, it returns 0.
          Regions that are mapped with isadma_map() must be unmapped
          with isadma_unmap() when the driver is finished with them.
          As before, they may be consuming host resources.
          isadma_copytobuffer() and isadma_copyfrombuffer() should
          copy efficiently, i.e. only copy when the data has been
          isadma_start(), etc., are implemented in a machine-independent
          fashion with these functions.
   * Flags passed to isadma_start().  (Note that ISADMA_START_WRITE
   * is a pseudo-flag.)
  #define ISADMA_START_READ       0x0001  /* DMA data from the device */
| #define ISADMA_START_WRITE      000002  /* DMA data to the device */
          pretty obvious.
|         ISADMA_START_WRITE set to '2' to detect missing direction.
|  * Flags passed to isadma_map().
  #define ISADMA_MAP_WAITOK       0x0001  /* OK for isadma_map to sleep */
          pretty obvious.  former to be used when isadma_map() not called
          at interrupt time.  it's likely (but not guaranteed) that
          isadma_map() will only sleep when/if creating a bounce buffer.
          (Note that it may sleep at any time, if ISADMA_MAP_WAITOK is
          specified.)  isadma_map() will fail of it needs to sleep but
          ISADMA_MAP_NOWAIT is specified.
  #define ISADMA_MAP_BOUNCE       0x0002  /* use bounce buffer if necessary */
          pretty obvious.  The latter should be used if a driver is
          likely to hold the buffer for an extended period of time
          (e.g. if it's trying to map a kernel variable, or something.)
          Note that on some systems, ISADMA_MAP_NOBOUNCE may not
          completely supported, and if used may cause isadma_map()
          to fail on an otherwise-reasonable request.
  #define ISADMA_MAP_CONTIG       0x0004  /* must be physically contiguous */
          ISADMA_MAP_CONTIG is used by the isadma_start(), and may
          be used by drivers.
          specified, the buffer must be contiguous and mappable without
          bounce buffering, or the request will fail.
  #define ISADMA_MAP_16BIT        0x0008  /* 16-bit DMA (channels 4-7) */
| #define ISADMA_MAP_8BIT         0x0010  /* 8-bit DMA (channels 0-3) */
          These are provided to select the address constraints on the
          DMA buffer.  8-bit DMA tranfers can be no longer than 64k
          and cannot cross a 64k boundary.  16-bit transfers can be
          no longer than 128k, must start and end on a two-byte
          boundary, and must not cross a 128k boundary.
|         ISADMA_MAP_CONTIG must be set with this modifiers.
|         ISADMA_MAP_8BIT is not zero to allow a request with no constrains.
|	  All #define XXX 0 have been removed. Simply use '0 | FLAG1 | ...'