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/dev/isa/isadma.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 /*      $NetBSD: isadma.c,v 1.52 2003/05/09 23:51:29 fvdl Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Device driver for the ISA on-board DMA controller.
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __KERNEL_RCSID(0, "$NetBSD: isadma.c,v 1.52 2003/05/09 23:51:29 fvdl Exp $");
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/proc.h>
   50 #include <sys/device.h>
   51 #include <sys/malloc.h>
   52 
   53 #include <machine/bus.h>
   54 
   55 #include <uvm/uvm_extern.h>
   56 
   57 #include <dev/isa/isareg.h>
   58 #include <dev/isa/isavar.h>
   59 #include <dev/isa/isadmavar.h>
   60 #include <dev/isa/isadmareg.h>
   61 
   62 struct isa_mem *isa_mem_head;
   63 
   64 /*
   65  * High byte of DMA address is stored in this DMAPG register for
   66  * the Nth DMA channel.
   67  */
   68 static int dmapageport[2][4] = {
   69         {0x7, 0x3, 0x1, 0x2},
   70         {0xf, 0xb, 0x9, 0xa}
   71 };
   72 
   73 static u_int8_t dmamode[] = {
   74         /* write to device/read from device */
   75         DMA37MD_READ | DMA37MD_SINGLE,
   76         DMA37MD_WRITE | DMA37MD_SINGLE,
   77 
   78         /* write to device/read from device */
   79         DMA37MD_READ | DMA37MD_DEMAND,
   80         DMA37MD_WRITE | DMA37MD_DEMAND,
   81 
   82         /* write to device/read from device - DMAMODE_LOOP */
   83         DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP,
   84         DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP,
   85 
   86         /* write to device/read from device - DMAMODE_LOOPDEMAND */
   87         DMA37MD_READ | DMA37MD_DEMAND | DMA37MD_LOOP,
   88         DMA37MD_WRITE | DMA37MD_DEMAND | DMA37MD_LOOP,
   89 };
   90 
   91 static inline void _isa_dmaunmask __P((struct isa_dma_state *, int));
   92 static inline void _isa_dmamask __P((struct isa_dma_state *, int));
   93 
   94 static inline void
   95 _isa_dmaunmask(ids, chan)
   96         struct isa_dma_state *ids;
   97         int chan;
   98 {
   99         int ochan = chan & 3;
  100 
  101         ISA_DMA_MASK_CLR(ids, chan);
  102 
  103         /*
  104          * If DMA is frozen, don't unmask it now.  It will be
  105          * unmasked when DMA is thawed again.
  106          */
  107         if (ids->ids_frozen)
  108                 return;
  109 
  110         /* set dma channel mode, and set dma channel mode */
  111         if ((chan & 4) == 0)
  112                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
  113                     DMA1_SMSK, ochan | DMA37SM_CLEAR);
  114         else
  115                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
  116                     DMA2_SMSK, ochan | DMA37SM_CLEAR);
  117 }
  118 
  119 static inline void
  120 _isa_dmamask(ids, chan)
  121         struct isa_dma_state *ids;
  122         int chan;
  123 {
  124         int ochan = chan & 3;
  125 
  126         ISA_DMA_MASK_SET(ids, chan);
  127 
  128         /*
  129          * XXX Should we avoid masking the channel if DMA is
  130          * XXX frozen?  It seems like what we're doing should
  131          * XXX be safe, and we do need to reset FFC...
  132          */
  133 
  134         /* set dma channel mode, and set dma channel mode */
  135         if ((chan & 4) == 0) {
  136                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
  137                     DMA1_SMSK, ochan | DMA37SM_SET);
  138                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
  139                     DMA1_FFC, 0);
  140         } else {
  141                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
  142                     DMA2_SMSK, ochan | DMA37SM_SET);
  143                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
  144                     DMA2_FFC, 0);
  145         }
  146 }
  147 
  148 /*
  149  * _isa_dmainit(): Initialize the isa_dma_state for this chipset.
  150  */
  151 void
  152 _isa_dmainit(ids, bst, dmat, dev)
  153         struct isa_dma_state *ids;
  154         bus_space_tag_t bst;
  155         bus_dma_tag_t dmat;
  156         struct device *dev;
  157 {
  158         int chan;
  159 
  160         ids->ids_dev = dev;
  161 
  162         if (ids->ids_initialized) {
  163                 /*
  164                  * Some systems may have e.g. `ofisa' (OpenFirmware
  165                  * configuration of ISA bus) and a regular `isa'.
  166                  * We allow both to call the initialization function,
  167                  * and take the device name from the last caller
  168                  * (assuming it will be the indirect ISA bus).  Since
  169                  * `ofisa' and `isa' are the same bus with different
  170                  * configuration mechanisms, the space and dma tags
  171                  * must be the same!
  172                  */
  173                 if (ids->ids_bst != bst || ids->ids_dmat != dmat)
  174                         panic("_isa_dmainit: inconsistent ISA tags");
  175         } else {
  176                 ids->ids_bst = bst;
  177                 ids->ids_dmat = dmat;
  178 
  179                 /*
  180                  * Map the registers used by the ISA DMA controller.
  181                  */
  182                 if (bus_space_map(ids->ids_bst, IO_DMA1, DMA1_IOSIZE, 0,
  183                     &ids->ids_dma1h))
  184                         panic("_isa_dmainit: unable to map DMA controller #1");
  185                 if (bus_space_map(ids->ids_bst, IO_DMA2, DMA2_IOSIZE, 0,
  186                     &ids->ids_dma2h))
  187                         panic("_isa_dmainit: unable to map DMA controller #2");
  188                 if (bus_space_map(ids->ids_bst, IO_DMAPG, 0xf, 0,
  189                     &ids->ids_dmapgh))
  190                         panic("_isa_dmainit: unable to map DMA page registers");
  191 
  192                 /*
  193                  * All 8 DMA channels start out "masked".
  194                  */
  195                 ids->ids_masked = 0xff;
  196 
  197                 /*
  198                  * Initialize the max transfer size for each channel, if
  199                  * it is not initialized already (i.e. by a bus-dependent
  200                  * front-end).
  201                  */
  202                 for (chan = 0; chan < 8; chan++) {
  203                         if (ids->ids_maxsize[chan] == 0)
  204                                 ids->ids_maxsize[chan] =
  205                                     ISA_DMA_MAXSIZE_DEFAULT(chan);
  206                 }
  207 
  208                 ids->ids_initialized = 1;
  209 
  210                 /*
  211                  * DRQ 4 is used to chain the two 8237s together; make
  212                  * sure it's always cascaded, and that it will be unmasked
  213                  * when DMA is thawed.
  214                  */
  215                 _isa_dmacascade(ids, 4);
  216         }
  217 }
  218 
  219 /*
  220  * _isa_dmacascade(): program 8237 DMA controller channel to accept
  221  * external dma control by a board.
  222  */
  223 int
  224 _isa_dmacascade(ids, chan)
  225         struct isa_dma_state *ids;
  226         int chan;
  227 {
  228         int ochan = chan & 3;
  229 
  230         if (chan < 0 || chan > 7) {
  231                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  232                 return (EINVAL);
  233         }
  234 
  235         if (ISA_DMA_DRQ_ISFREE(ids, chan) == 0) {
  236                 printf("%s: DRQ %d is not free\n", ids->ids_dev->dv_xname,
  237                     chan);
  238                 return (EAGAIN);
  239         }
  240 
  241         ISA_DMA_DRQ_ALLOC(ids, chan);
  242 
  243         /* set dma channel mode, and set dma channel mode */
  244         if ((chan & 4) == 0)
  245                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
  246                     DMA1_MODE, ochan | DMA37MD_CASCADE);
  247         else
  248                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
  249                     DMA2_MODE, ochan | DMA37MD_CASCADE);
  250 
  251         _isa_dmaunmask(ids, chan);
  252         return (0);
  253 }
  254 
  255 int
  256 _isa_drq_alloc(ids, chan)
  257         struct isa_dma_state *ids;
  258         int chan;
  259 {
  260         if (ISA_DMA_DRQ_ISFREE(ids, chan) == 0)
  261                 return EBUSY;
  262         ISA_DMA_DRQ_ALLOC(ids, chan);
  263         return 0;
  264 }
  265 
  266 int
  267 _isa_drq_free(ids, chan)
  268         struct isa_dma_state *ids;
  269         int chan;
  270 {
  271         if (ISA_DMA_DRQ_ISFREE(ids, chan))
  272                 return EINVAL;
  273         ISA_DMA_DRQ_FREE(ids, chan);
  274         return 0;
  275 }
  276 
  277 bus_size_t
  278 _isa_dmamaxsize(ids, chan)
  279         struct isa_dma_state *ids;
  280         int chan;
  281 {
  282 
  283         if (chan < 0 || chan > 7) {
  284                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  285                 return (0);
  286         }
  287 
  288         return (ids->ids_maxsize[chan]);
  289 }
  290 
  291 int
  292 _isa_dmamap_create(ids, chan, size, flags)
  293         struct isa_dma_state *ids;
  294         int chan;
  295         bus_size_t size;
  296         int flags;
  297 {
  298         int error;
  299 
  300         if (chan < 0 || chan > 7) {
  301                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  302                 return (EINVAL);
  303         }
  304 
  305         if (size > ids->ids_maxsize[chan])
  306                 return (EINVAL);
  307 
  308         error = bus_dmamap_create(ids->ids_dmat, size, 1, size,
  309             ids->ids_maxsize[chan], flags, &ids->ids_dmamaps[chan]);
  310 
  311         return (error);
  312 }
  313 
  314 void
  315 _isa_dmamap_destroy(ids, chan)
  316         struct isa_dma_state *ids;
  317         int chan;
  318 {
  319 
  320         if (chan < 0 || chan > 7) {
  321                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  322                 goto lose;
  323         }
  324 
  325         bus_dmamap_destroy(ids->ids_dmat, ids->ids_dmamaps[chan]);
  326         return;
  327 
  328  lose:
  329         panic("_isa_dmamap_destroy");
  330 }
  331 
  332 /*
  333  * _isa_dmastart(): program 8237 DMA controller channel and set it
  334  * in motion.
  335  */
  336 int
  337 _isa_dmastart(ids, chan, addr, nbytes, p, flags, busdmaflags)
  338         struct isa_dma_state *ids;
  339         int chan;
  340         void *addr;
  341         bus_size_t nbytes;
  342         struct proc *p;
  343         int flags;
  344         int busdmaflags;
  345 {
  346         bus_dmamap_t dmam;
  347         bus_addr_t dmaaddr;
  348         int waport;
  349         int ochan = chan & 3;
  350         int error;
  351 
  352         if (chan < 0 || chan > 7) {
  353                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  354                 goto lose;
  355         }
  356 
  357 #ifdef ISADMA_DEBUG
  358         printf("_isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, "
  359             "flags 0x%x, dmaflags 0x%x\n",
  360             chan, addr, nbytes, p, flags, busdmaflags);
  361 #endif
  362 
  363         if (ISA_DMA_DRQ_ISFREE(ids, chan)) {
  364                 printf("%s: dma start on free channel %d\n",
  365                     ids->ids_dev->dv_xname, chan);
  366                 goto lose;
  367         }
  368 
  369         if (chan & 4) {
  370                 if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) {
  371                         printf("%s: drq %d, nbytes 0x%lx, addr %p\n",
  372                             ids->ids_dev->dv_xname, chan,
  373                             (unsigned long) nbytes, addr);
  374                         goto lose;
  375                 }
  376         } else {
  377                 if (nbytes > (1 << 16)) {
  378                         printf("%s: drq %d, nbytes 0x%lx\n",
  379                             ids->ids_dev->dv_xname, chan,
  380                             (unsigned long) nbytes);
  381                         goto lose;
  382                 }
  383         }
  384 
  385         dmam = ids->ids_dmamaps[chan];
  386         if (dmam == NULL)
  387                 panic("_isa_dmastart: no DMA map for chan %d", chan);
  388 
  389         error = bus_dmamap_load(ids->ids_dmat, dmam, addr, nbytes,
  390             p, busdmaflags |
  391             ((flags & DMAMODE_READ) ? BUS_DMA_READ : BUS_DMA_WRITE));
  392         if (error)
  393                 return (error);
  394 
  395 #ifdef ISADMA_DEBUG
  396         __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:");
  397 #endif
  398 
  399         if (flags & DMAMODE_READ) {
  400                 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
  401                     BUS_DMASYNC_PREREAD);
  402                 ids->ids_dmareads |= (1 << chan);
  403         } else {
  404                 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
  405                     BUS_DMASYNC_PREWRITE);
  406                 ids->ids_dmareads &= ~(1 << chan);
  407         }
  408 
  409         dmaaddr = dmam->dm_segs[0].ds_addr;
  410 
  411 #ifdef ISADMA_DEBUG
  412         printf("     dmaaddr 0x%lx\n", dmaaddr);
  413 
  414         __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:");
  415 #endif
  416 
  417         ids->ids_dmalength[chan] = nbytes;
  418 
  419         _isa_dmamask(ids, chan);
  420         ids->ids_dmafinished &= ~(1 << chan);
  421 
  422         if ((chan & 4) == 0) {
  423                 /* set dma channel mode */
  424                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, DMA1_MODE,
  425                     ochan | dmamode[flags]);
  426 
  427                 /* send start address */
  428                 waport = DMA1_CHN(ochan);
  429                 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh,
  430                     dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
  431                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
  432                     dmaaddr & 0xff);
  433                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
  434                     (dmaaddr >> 8) & 0xff);
  435 
  436                 /* send count */
  437                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1,
  438                     (--nbytes) & 0xff);
  439                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1,
  440                     (nbytes >> 8) & 0xff);
  441         } else {
  442                 /* set dma channel mode */
  443                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, DMA2_MODE,
  444                     ochan | dmamode[flags]);
  445 
  446                 /* send start address */
  447                 waport = DMA2_CHN(ochan);
  448                 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh,
  449                     dmapageport[1][ochan], (dmaaddr >> 16) & 0xff);
  450                 dmaaddr >>= 1;
  451                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport,
  452                     dmaaddr & 0xff);
  453                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport,
  454                     (dmaaddr >> 8) & 0xff);
  455 
  456                 /* send count */
  457                 nbytes >>= 1;
  458                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2,
  459                     (--nbytes) & 0xff);
  460                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2,
  461                     (nbytes >> 8) & 0xff);
  462         }
  463 
  464         _isa_dmaunmask(ids, chan);
  465         return (0);
  466 
  467  lose:
  468         panic("_isa_dmastart");
  469 }
  470 
  471 void
  472 _isa_dmaabort(ids, chan)
  473         struct isa_dma_state *ids;
  474         int chan;
  475 {
  476 
  477         if (chan < 0 || chan > 7) {
  478                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  479                 panic("_isa_dmaabort");
  480         }
  481 
  482         _isa_dmamask(ids, chan);
  483         bus_dmamap_unload(ids->ids_dmat, ids->ids_dmamaps[chan]);
  484         ids->ids_dmareads &= ~(1 << chan);
  485 }
  486 
  487 bus_size_t
  488 _isa_dmacount(ids, chan)
  489         struct isa_dma_state *ids;
  490         int chan;
  491 {
  492         int waport;
  493         bus_size_t nbytes;
  494         int ochan = chan & 3;
  495 
  496         if (chan < 0 || chan > 7) {
  497                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  498                 panic("isa_dmacount");
  499         }
  500 
  501         _isa_dmamask(ids, chan);
  502 
  503         /*
  504          * We have to shift the byte count by 1.  If we're in auto-initialize
  505          * mode, the count may have wrapped around to the initial value.  We
  506          * can't use the TC bit to check for this case, so instead we compare
  507          * against the original byte count.
  508          * If we're not in auto-initialize mode, then the count will wrap to
  509          * -1, so we also handle that case.
  510          */
  511         if ((chan & 4) == 0) {
  512                 waport = DMA1_CHN(ochan);
  513                 nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma1h,
  514                     waport + 1) + 1;
  515                 nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma1h,
  516                     waport + 1) << 8;
  517                 nbytes &= 0xffff;
  518         } else {
  519                 waport = DMA2_CHN(ochan);
  520                 nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma2h,
  521                     waport + 2) + 1;
  522                 nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma2h,
  523                     waport + 2) << 8;
  524                 nbytes <<= 1;
  525                 nbytes &= 0x1ffff;
  526         }
  527 
  528         if (nbytes == ids->ids_dmalength[chan])
  529                 nbytes = 0;
  530 
  531         _isa_dmaunmask(ids, chan);
  532         return (nbytes);
  533 }
  534 
  535 int
  536 _isa_dmafinished(ids, chan)
  537         struct isa_dma_state *ids;
  538         int chan;
  539 {
  540 
  541         if (chan < 0 || chan > 7) {
  542                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  543                 panic("_isa_dmafinished");
  544         }
  545 
  546         /* check that the terminal count was reached */
  547         if ((chan & 4) == 0)
  548                 ids->ids_dmafinished |= bus_space_read_1(ids->ids_bst,
  549                     ids->ids_dma1h, DMA1_SR) & 0x0f;
  550         else
  551                 ids->ids_dmafinished |= (bus_space_read_1(ids->ids_bst,
  552                     ids->ids_dma2h, DMA2_SR) & 0x0f) << 4;
  553 
  554         return ((ids->ids_dmafinished & (1 << chan)) != 0);
  555 }
  556 
  557 void
  558 _isa_dmadone(ids, chan)
  559         struct isa_dma_state *ids;
  560         int chan;
  561 {
  562         bus_dmamap_t dmam;
  563 
  564         if (chan < 0 || chan > 7) {
  565                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  566                 panic("_isa_dmadone");
  567         }
  568 
  569         dmam = ids->ids_dmamaps[chan];
  570 
  571         _isa_dmamask(ids, chan);
  572 
  573         if (_isa_dmafinished(ids, chan) == 0)
  574                 printf("%s: _isa_dmadone: channel %d not finished\n",
  575                     ids->ids_dev->dv_xname, chan);
  576 
  577         bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
  578             (ids->ids_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD :
  579             BUS_DMASYNC_POSTWRITE);
  580 
  581         bus_dmamap_unload(ids->ids_dmat, dmam);
  582         ids->ids_dmareads &= ~(1 << chan);
  583 }
  584 
  585 void
  586 _isa_dmafreeze(ids)
  587         struct isa_dma_state *ids;
  588 {
  589         int s;
  590 
  591         s = splhigh();
  592 
  593         if (ids->ids_frozen == 0) {
  594                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
  595                     DMA1_MASK, 0x0f);
  596                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
  597                     DMA2_MASK, 0x0f);
  598         }
  599 
  600         ids->ids_frozen++;
  601         if (ids->ids_frozen < 1)
  602                 panic("_isa_dmafreeze: overflow");
  603 
  604         splx(s);
  605 }
  606 
  607 void
  608 _isa_dmathaw(ids)
  609         struct isa_dma_state *ids;
  610 {
  611         int s;
  612 
  613         s = splhigh();
  614 
  615         ids->ids_frozen--;
  616         if (ids->ids_frozen < 0)
  617                 panic("_isa_dmathaw: underflow");
  618 
  619         if (ids->ids_frozen == 0) {
  620                 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
  621                     DMA1_MASK, ids->ids_masked & 0x0f);
  622                 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
  623                     DMA2_MASK, (ids->ids_masked >> 4) & 0x0f);
  624         }
  625 
  626         splx(s);
  627 }
  628 
  629 int
  630 _isa_dmamem_alloc(ids, chan, size, addrp, flags)
  631         struct isa_dma_state *ids;
  632         int chan;
  633         bus_size_t size;
  634         bus_addr_t *addrp;
  635         int flags;
  636 {
  637         bus_dma_segment_t seg;
  638         int error, boundary, rsegs;
  639 
  640         if (chan < 0 || chan > 7) {
  641                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  642                 panic("_isa_dmamem_alloc");
  643         }
  644 
  645         boundary = (chan & 4) ? (1 << 17) : (1 << 16);
  646 
  647         size = round_page(size);
  648 
  649         error = bus_dmamem_alloc(ids->ids_dmat, size, PAGE_SIZE, boundary,
  650             &seg, 1, &rsegs, flags);
  651         if (error)
  652                 return (error);
  653 
  654         *addrp = seg.ds_addr;
  655         return (0);
  656 }
  657 
  658 void
  659 _isa_dmamem_free(ids, chan, addr, size)
  660         struct isa_dma_state *ids;
  661         int chan;
  662         bus_addr_t addr;
  663         bus_size_t size;
  664 {
  665         bus_dma_segment_t seg;
  666 
  667         if (chan < 0 || chan > 7) {
  668                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  669                 panic("_isa_dmamem_free");
  670         }
  671 
  672         seg.ds_addr = addr;
  673         seg.ds_len = size;
  674 
  675         bus_dmamem_free(ids->ids_dmat, &seg, 1);
  676 }
  677 
  678 int
  679 _isa_dmamem_map(ids, chan, addr, size, kvap, flags)
  680         struct isa_dma_state *ids;
  681         int chan;
  682         bus_addr_t addr;
  683         bus_size_t size;
  684         caddr_t *kvap;
  685         int flags;
  686 {
  687         bus_dma_segment_t seg;
  688 
  689         if (chan < 0 || chan > 7) {
  690                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  691                 panic("_isa_dmamem_map");
  692         }
  693 
  694         seg.ds_addr = addr;
  695         seg.ds_len = size;
  696 
  697         return (bus_dmamem_map(ids->ids_dmat, &seg, 1, size, kvap, flags));
  698 }
  699 
  700 void
  701 _isa_dmamem_unmap(ids, chan, kva, size)
  702         struct isa_dma_state *ids;
  703         int chan;
  704         caddr_t kva;
  705         size_t size;
  706 {
  707 
  708         if (chan < 0 || chan > 7) {
  709                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  710                 panic("_isa_dmamem_unmap");
  711         }
  712 
  713         bus_dmamem_unmap(ids->ids_dmat, kva, size);
  714 }
  715 
  716 paddr_t
  717 _isa_dmamem_mmap(ids, chan, addr, size, off, prot, flags)
  718         struct isa_dma_state *ids;
  719         int chan;
  720         bus_addr_t addr;
  721         bus_size_t size;
  722         off_t off;
  723         int prot, flags;
  724 {
  725         bus_dma_segment_t seg;
  726 
  727         if (chan < 0 || chan > 7) {
  728                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  729                 panic("_isa_dmamem_mmap");
  730         }
  731 
  732         if (off < 0)
  733                 return (-1);
  734 
  735         seg.ds_addr = addr;
  736         seg.ds_len = size;
  737 
  738         return (bus_dmamem_mmap(ids->ids_dmat, &seg, 1, off, prot, flags));
  739 }
  740 
  741 int
  742 _isa_drq_isfree(ids, chan)
  743         struct isa_dma_state *ids;
  744         int chan;
  745 {
  746 
  747         if (chan < 0 || chan > 7) {
  748                 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
  749                 panic("_isa_drq_isfree");
  750         }
  751 
  752         return ISA_DMA_DRQ_ISFREE(ids, chan);
  753 }
  754 
  755 void *
  756 _isa_malloc(ids, chan, size, pool, flags)
  757         struct isa_dma_state *ids;
  758         int chan;
  759         size_t size;
  760         struct malloc_type *pool;
  761         int flags;
  762 {
  763         bus_addr_t addr;
  764         caddr_t kva;
  765         int bflags;
  766         struct isa_mem *m;
  767 
  768         bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT;
  769 
  770         if (_isa_dmamem_alloc(ids, chan, size, &addr, bflags))
  771                 return 0;
  772         if (_isa_dmamem_map(ids, chan, addr, size, &kva, bflags)) {
  773                 _isa_dmamem_free(ids, chan, addr, size);
  774                 return 0;
  775         }
  776         m = malloc(sizeof(*m), pool, flags);
  777         if (m == 0) {
  778                 _isa_dmamem_unmap(ids, chan, kva, size);
  779                 _isa_dmamem_free(ids, chan, addr, size);
  780                 return 0;
  781         }
  782         m->ids = ids;
  783         m->chan = chan;
  784         m->size = size;
  785         m->addr = addr;
  786         m->kva = kva;
  787         m->next = isa_mem_head;
  788         isa_mem_head = m;
  789         return (void *)kva;
  790 }
  791 
  792 void
  793 _isa_free(addr, pool)
  794         void *addr;
  795         struct malloc_type *pool;
  796 {
  797         struct isa_mem **mp, *m;
  798         caddr_t kva = (caddr_t)addr;
  799 
  800         for(mp = &isa_mem_head; *mp && (*mp)->kva != kva;
  801             mp = &(*mp)->next)
  802                 ;
  803         m = *mp;
  804         if (!m) {
  805                 printf("_isa_free: freeing unallocted memory\n");
  806                 return;
  807         }
  808         *mp = m->next;
  809         _isa_dmamem_unmap(m->ids, m->chan, kva, m->size);
  810         _isa_dmamem_free(m->ids, m->chan, m->addr, m->size);
  811         free(m, pool);
  812 }
  813 
  814 paddr_t
  815 _isa_mappage(mem, off, prot)
  816         void *mem;
  817         off_t off;
  818         int prot;
  819 {
  820         struct isa_mem *m;
  821 
  822         for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next)
  823                 ;
  824         if (!m) {
  825                 printf("_isa_mappage: mapping unallocted memory\n");
  826                 return -1;
  827         }
  828         return _isa_dmamem_mmap(m->ids, m->chan, m->addr,
  829             m->size, off, prot, BUS_DMA_WAITOK);
  830 }

Cache object: f24513b79715b42a9cce597da27683e1


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