The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/dma.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 
    7 typedef struct DMAport  DMAport;
    8 typedef struct DMA      DMA;
    9 typedef struct DMAxfer  DMAxfer;
   10 
   11 /*
   12  *  state of a dma transfer
   13  */
   14 struct DMAxfer
   15 {
   16         ulong   bpa;            /* bounce buffer physical address */
   17         void*   bva;            /* bounce buffer virtual address */
   18         int     blen;           /* bounce buffer length */
   19         void*   va;             /* virtual address destination/src */
   20         long    len;            /* bytes to be transferred */
   21         int     isread;
   22 };
   23 
   24 /*
   25  *  the dma controllers.  the first half of this structure specifies
   26  *  the I/O ports used by the DMA controllers.
   27  */
   28 struct DMAport
   29 {
   30         uchar   addr[4];        /* current address (4 channels) */
   31         uchar   count[4];       /* current count (4 channels) */
   32         uchar   page[4];        /* page registers (4 channels) */
   33         uchar   cmd;            /* command status register */
   34         uchar   req;            /* request registers */
   35         uchar   sbm;            /* single bit mask register */
   36         uchar   mode;           /* mode register */
   37         uchar   cbp;            /* clear byte pointer */
   38         uchar   mc;             /* master clear */
   39         uchar   cmask;          /* clear mask register */
   40         uchar   wam;            /* write all mask register bit */
   41 };
   42 
   43 struct DMA
   44 {
   45         DMAport;
   46         int     shift;
   47         Lock;
   48         DMAxfer x[4];
   49 };
   50 
   51 DMA dma[2] = {
   52         { 0x00, 0x02, 0x04, 0x06,
   53           0x01, 0x03, 0x05, 0x07,
   54           0x87, 0x83, 0x81, 0x82,
   55           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   56          0 },
   57 
   58         { 0xc0, 0xc4, 0xc8, 0xcc,
   59           0xc2, 0xc6, 0xca, 0xce,
   60           0x8f, 0x8b, 0x89, 0x8a,
   61           0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
   62          1 },
   63 };
   64 
   65 extern int i8237dma;
   66 static void* i8237bva[2];
   67 static int i8237used;
   68 
   69 /*
   70  *  DMA must be in the first 16MB.  This gets called early by the
   71  *  initialisation routines of any devices which require DMA to ensure
   72  *  the allocated bounce buffers are below the 16MB limit.
   73  */
   74 void
   75 _i8237alloc(void)
   76 {
   77         void* bva;
   78 
   79         if(i8237dma <= 0)
   80                 return;
   81         if(i8237dma > 2)
   82                 i8237dma = 2;
   83 
   84         bva = xspanalloc(64*1024*i8237dma, BY2PG, 64*1024);
   85         if(bva == nil || PADDR(bva)+64*1024*i8237dma > 16*MB){
   86                 /*
   87                  * This will panic with the current
   88                  * implementation of xspanalloc().
   89                 if(bva != nil)
   90                         xfree(bva);
   91                  */
   92                 return;
   93         }
   94 
   95         i8237bva[0] = bva;
   96         if(i8237dma == 2)
   97                 i8237bva[1] = ((uchar*)i8237bva[0])+64*1024;
   98 }
   99 
  100 /*
  101  *  DMA must be in the first 16MB.  This gets called early by the
  102  *  initialisation routines of any devices which require DMA to ensure
  103  *  the allocated bounce buffers are below the 16MB limit.
  104  */
  105 int
  106 dmainit(int chan, int maxtransfer)
  107 {
  108         DMA *dp;
  109         DMAxfer *xp;
  110         static int once;
  111 
  112         if(once == 0){
  113                 if(ioalloc(0x00, 0x10, 0, "dma") < 0
  114                 || ioalloc(0x80, 0x10, 0, "dma") < 0
  115                 || ioalloc(0xd0, 0x10, 0, "dma") < 0)
  116                         panic("dmainit");
  117                 once = 1;
  118         }
  119 
  120         if(maxtransfer > 64*1024)
  121                 maxtransfer = 64*1024;
  122 
  123         dp = &dma[(chan>>2)&1];
  124         chan = chan & 3;
  125         xp = &dp->x[chan];
  126         if(xp->bva != nil){
  127                 if(xp->blen < maxtransfer)
  128                         return 1;
  129                 return 0;
  130         }
  131 
  132         if(i8237used >= i8237dma || i8237bva[i8237used] == nil){
  133                 print("no i8237 DMA bounce buffer < 16MB\n");
  134                 return 1;
  135         }
  136         xp->bva = i8237bva[i8237used++];
  137         xp->bpa = PADDR(xp->bva);
  138         xp->blen = maxtransfer;
  139         xp->len = 0;
  140         xp->isread = 0;
  141 
  142         return 0;
  143 }
  144 
  145 /*
  146  *  setup a dma transfer.  if the destination is not in kernel
  147  *  memory, allocate a page for the transfer.
  148  *
  149  *  we assume BIOS has set up the command register before we
  150  *  are booted.
  151  *
  152  *  return the updated transfer length (we can't transfer across 64k
  153  *  boundaries)
  154  */
  155 long
  156 dmasetup(int chan, void *va, long len, int isread)
  157 {
  158         DMA *dp;
  159         ulong pa;
  160         uchar mode;
  161         DMAxfer *xp;
  162 
  163         dp = &dma[(chan>>2)&1];
  164         chan = chan & 3;
  165         xp = &dp->x[chan];
  166 
  167         /*
  168          *  if this isn't kernel memory or crossing 64k boundary or above 16 meg
  169          *  use the bounce buffer.
  170          */
  171         if((ulong)va < KZERO 
  172         || ((pa=PADDR(va))&0xFFFF0000) != ((pa+len)&0xFFFF0000)
  173         || pa >= 16*MB){
  174                 if(xp->bva == nil)
  175                         return -1;
  176                 if(len > xp->blen)
  177                         len = xp->blen;
  178                 if(!isread)
  179                         memmove(xp->bva, va, len);
  180                 xp->va = va;
  181                 xp->len = len;
  182                 xp->isread = isread;
  183                 pa = xp->bpa;
  184         }
  185         else
  186                 xp->len = 0;
  187 
  188         /*
  189          * this setup must be atomic
  190          */
  191         ilock(dp);
  192         mode = (isread ? 0x44 : 0x48) | chan;
  193         outb(dp->mode, mode);   /* single mode dma (give CPU a chance at mem) */
  194         outb(dp->page[chan], pa>>16);
  195         outb(dp->cbp, 0);               /* set count & address to their first byte */
  196         outb(dp->addr[chan], pa>>dp->shift);            /* set address */
  197         outb(dp->addr[chan], pa>>(8+dp->shift));
  198         outb(dp->count[chan], (len>>dp->shift)-1);              /* set count */
  199         outb(dp->count[chan], ((len>>dp->shift)-1)>>8);
  200         outb(dp->sbm, chan);            /* enable the channel */
  201         iunlock(dp);
  202 
  203         return len;
  204 }
  205 
  206 int
  207 dmadone(int chan)
  208 {
  209         DMA *dp;
  210 
  211         dp = &dma[(chan>>2)&1];
  212         chan = chan & 3;
  213 
  214         return inb(dp->cmd) & (1<<chan);
  215 }
  216 
  217 /*
  218  *  this must be called after a dma has been completed.
  219  *
  220  *  if a page has been allocated for the dma,
  221  *  copy the data into the actual destination
  222  *  and free the page.
  223  */
  224 void
  225 dmaend(int chan)
  226 {
  227         DMA *dp;
  228         DMAxfer *xp;
  229 
  230         dp = &dma[(chan>>2)&1];
  231         chan = chan & 3;
  232 
  233         /*
  234          *  disable the channel
  235          */
  236         ilock(dp);
  237         outb(dp->sbm, 4|chan);
  238         iunlock(dp);
  239 
  240         xp = &dp->x[chan];
  241         if(xp->len == 0 || !xp->isread)
  242                 return;
  243 
  244         /*
  245          *  copy out of temporary page
  246          */
  247         memmove(xp->va, xp->bva, xp->len);
  248         xp->len = 0;
  249 }
  250 
  251 /*
  252 int
  253 dmacount(int chan)
  254 {
  255         int     retval;
  256         DMA     *dp;
  257  
  258         dp = &dma[(chan>>2)&1];
  259         outb(dp->cbp, 0);
  260         retval = inb(dp->count[chan]);
  261         retval |= inb(dp->count[chan]) << 8;
  262         return((retval<<dp->shift)+1);
  263 }
  264  */

Cache object: 9f8564943e9d2d35e1f7982330f754a7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.