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

Cache object: dfa1ca0b864021f5ac4635ac6bf7f1af


[ 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.