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/i386/isa/isa.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 /*-
    2  * Copyright (c) 1991 The Regents of the University of California.
    3  * All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * William Jolitz.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      from: @(#)isa.c 7.2 (Berkeley) 5/13/91
   37  * $FreeBSD$
   38  */
   39 
   40 /*
   41  * code to manage AT bus
   42  *
   43  * 92/08/18  Frank P. MacLachlan (fpm@crash.cts.com):
   44  * Fixed uninitialized variable problem and added code to deal
   45  * with DMA page boundaries in isa_dmarangecheck().  Fixed word
   46  * mode DMA count compution and reorganized DMA setup code in
   47  * isa_dmastart()
   48  */
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/buf.h>
   53 #include <sys/malloc.h>
   54 #include <machine/ipl.h>
   55 #include <machine/md_var.h>
   56 #ifdef APIC_IO
   57 #include <machine/smp.h>
   58 #endif /* APIC_IO */
   59 #include <vm/vm.h>
   60 #include <vm/vm_param.h>
   61 #include <vm/pmap.h>
   62 #include <i386/isa/isa_device.h>
   63 #include <i386/isa/intr_machdep.h>
   64 #include <i386/isa/isa.h>
   65 #include <i386/isa/ic/i8237.h>
   66 
   67 #include <sys/interrupt.h>
   68 
   69 #include "pnp.h"
   70 #if NPNP > 0
   71 #include <i386/isa/pnp.h>
   72 #endif
   73 
   74 /*
   75 **  Register definitions for DMA controller 1 (channels 0..3):
   76 */
   77 #define DMA1_CHN(c)     (IO_DMA1 + 1*(2*(c)))   /* addr reg for channel c */
   78 #define DMA1_SMSK       (IO_DMA1 + 1*10)        /* single mask register */
   79 #define DMA1_MODE       (IO_DMA1 + 1*11)        /* mode register */
   80 #define DMA1_FFC        (IO_DMA1 + 1*12)        /* clear first/last FF */
   81 
   82 /*
   83 **  Register definitions for DMA controller 2 (channels 4..7):
   84 */
   85 #define DMA2_CHN(c)     (IO_DMA2 + 2*(2*(c)))   /* addr reg for channel c */
   86 #define DMA2_SMSK       (IO_DMA2 + 2*10)        /* single mask register */
   87 #define DMA2_MODE       (IO_DMA2 + 2*11)        /* mode register */
   88 #define DMA2_FFC        (IO_DMA2 + 2*12)        /* clear first/last FF */
   89 
   90 static void config_isadev __P((struct isa_device *isdp, u_int *mp));
   91 static void config_isadev_c __P((struct isa_device *isdp, u_int *mp,
   92                                  int reconfig));
   93 static void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
   94                           int item, char const *whatnot, char const *reason,
   95                           char const *format));
   96 static int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
   97                          u_int checkbits));
   98 static int isa_dmarangecheck __P((caddr_t va, u_int length, int chan));
   99 
  100 /*
  101  * print a conflict message
  102  */
  103 static void
  104 conflict(dvp, tmpdvp, item, whatnot, reason, format)
  105         struct isa_device       *dvp;
  106         struct isa_device       *tmpdvp;
  107         int                     item;
  108         char const              *whatnot;
  109         char const              *reason;
  110         char const              *format;
  111 {
  112         printf("%s%d not %sed due to %s conflict with %s%d at ",
  113                 dvp->id_driver->name, dvp->id_unit, whatnot, reason,
  114                 tmpdvp->id_driver->name, tmpdvp->id_unit);
  115         printf(format, item);
  116         printf("\n");
  117 }
  118 
  119 /*
  120  * Check to see if things are already in use, like IRQ's, I/O addresses
  121  * and Memory addresses.
  122  */
  123 static int
  124 haveseen(dvp, tmpdvp, checkbits)
  125         struct isa_device *dvp;
  126         struct isa_device *tmpdvp;
  127         u_int   checkbits;
  128 {
  129         /*
  130          * Ignore all conflicts except IRQ ones if conflicts are allowed.
  131          */
  132         if (dvp->id_conflicts)
  133                 checkbits &= ~(CC_DRQ | CC_IOADDR | CC_MEMADDR);
  134         /*
  135          * Only check against devices that have already been found.
  136          */
  137         if (tmpdvp->id_alive) {
  138                 char const *whatnot;
  139 
  140                 /*
  141                  * Check for device driver & unit conflict; just drop probing
  142                  * a device which has already probed true.  This is usually
  143                  * not strictly a conflict, but rather the case of somebody
  144                  * having specified several mutually exclusive configurations
  145                  * for a single device.
  146                  */
  147                 if (tmpdvp->id_driver == dvp->id_driver &&
  148                     tmpdvp->id_unit == dvp->id_unit) {
  149                         return 1;
  150                 }
  151 
  152                 whatnot = checkbits & CC_ATTACH ? "attach" : "prob";
  153                 /*
  154                  * Check for I/O address conflict.  We can only check the
  155                  * starting address of the device against the range of the
  156                  * device that has already been probed since we do not
  157                  * know how many I/O addresses this device uses.
  158                  */
  159                 if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) {
  160                         if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
  161                             (dvp->id_iobase <=
  162                                   (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
  163                                 if (!(checkbits & CC_QUIET))
  164                                         conflict(dvp, tmpdvp, dvp->id_iobase,
  165                                             whatnot, "I/O address", "0x%x");
  166                                 return 1;
  167                         }
  168                 }
  169                 /*
  170                  * Check for Memory address conflict.  We can check for
  171                  * range overlap, but it will not catch all cases since the
  172                  * driver may adjust the msize paramater during probe, for
  173                  * now we just check that the starting address does not
  174                  * fall within any allocated region.
  175                  * XXX could add a second check after the probe for overlap,
  176                  * since at that time we would know the full range.
  177                  * XXX KERNBASE is a hack, we should have vaddr in the table!
  178                  */
  179                 if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) {
  180                         if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
  181                             (KERNBASE + dvp->id_maddr <=
  182                              (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
  183                                 if (!(checkbits & CC_QUIET))
  184                                         conflict(dvp, tmpdvp,
  185                                             (int)dvp->id_maddr, whatnot,
  186                                             "maddr", "0x%x");
  187                                 return 1;
  188                         }
  189                 }
  190                 /*
  191                  * Check for IRQ conflicts.
  192                  */
  193                 if (checkbits & CC_IRQ && tmpdvp->id_irq) {
  194                         if (tmpdvp->id_irq == dvp->id_irq) {
  195                                 if (!(checkbits & CC_QUIET))
  196                                         conflict(dvp, tmpdvp,
  197                                             ffs(dvp->id_irq) - 1, whatnot,
  198                                             "irq", "%d");
  199                                 return 1;
  200                         }
  201                 }
  202                 /*
  203                  * Check for DRQ conflicts.
  204                  */
  205                 if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) {
  206                         if (tmpdvp->id_drq == dvp->id_drq) {
  207                                 if (!(checkbits & CC_QUIET))
  208                                         conflict(dvp, tmpdvp, dvp->id_drq,
  209                                             whatnot, "drq", "%d");
  210                                 return 1;
  211                         }
  212                 }
  213         }
  214         return 0;
  215 }
  216 
  217 #ifdef RESOURCE_CHECK
  218 #include <sys/drvresource.h>
  219 
  220 static int
  221 checkone (struct isa_device *dvp, int type, addr_t low, addr_t high, 
  222           char *resname, char *resfmt, int attaching)
  223 {
  224         int result = 0;
  225         if (bootverbose) {
  226                 if (low == high)
  227                         printf("\tcheck %s: 0x%x\n", resname, low);
  228                 else
  229                         printf("\tcheck %s: 0x%x to 0x%x\n", 
  230                                resname, low, high);
  231         }
  232         if (resource_check(type, RESF_NONE, low, high) != NULL) {
  233                 char *whatnot = attaching ? "attach" : "prob";
  234                 static struct isa_device dummydev;
  235                 static struct isa_driver dummydrv;
  236                 struct isa_device *tmpdvp = &dummydev;
  237 
  238                 dummydev.id_driver = &dummydrv;
  239                 dummydev.id_unit = 0;
  240                 dummydrv.name = "pci";
  241                 conflict(dvp, tmpdvp, low, whatnot, resname, resfmt);
  242                 result = 1;
  243         } else if (attaching) {
  244                 if (low == high)
  245                         printf("\tregister %s: 0x%x\n", resname, low);
  246                 else
  247                         printf("\tregister %s: 0x%x to 0x%x\n",
  248                                resname, low, high);
  249                 resource_claim(dvp, type, RESF_NONE, low, high);
  250         }
  251         return (result);
  252 }
  253 
  254 static int 
  255 check_pciconflict(struct isa_device *dvp, int checkbits)
  256 {
  257         int result = 0;
  258         int attaching = (checkbits & CC_ATTACH) != 0;
  259 
  260         if (checkbits & CC_MEMADDR) {
  261                 long maddr = dvp->id_maddr;
  262                 long msize = dvp->id_msize;
  263                 if (msize > 0) {
  264                         if (checkone(dvp, REST_MEM, maddr, maddr + msize - 1,
  265                                      "maddr", "0x%x", attaching) != 0) {
  266                                 result = 1;
  267                                 attaching = 0;
  268                         }
  269                 }
  270         }
  271         if (checkbits & CC_IOADDR) {
  272                 unsigned iobase = dvp->id_iobase;
  273                 unsigned iosize = dvp->id_alive;
  274                 if (iosize == -1)
  275                         iosize = 1; /* XXX can't do much about this ... */
  276                 if (iosize > 0) {
  277                         if (checkone(dvp, REST_PORT, iobase, iobase + iosize -1,
  278                                      "I/O address", "0x%x", attaching) != 0) {
  279                                 result = 1;
  280                                 attaching = 0;
  281                         }
  282                 }
  283         }
  284         if (checkbits & CC_IRQ) {
  285                 int irq = ffs(dvp->id_irq) - 1;
  286                 if (irq >= 0) {
  287                         if (checkone(dvp, REST_INT, irq, irq, 
  288                                      "irq", "%d", attaching) != 0) {
  289                                 result = 1;
  290                                 attaching = 0;
  291                         }
  292                 }
  293         }
  294         if (checkbits & CC_DRQ) {
  295                 int drq = dvp->id_drq;
  296                 if (drq >= 0) {
  297                         if (checkone(dvp, REST_DMA, drq, drq, 
  298                                      "drq", "%d", attaching) != 0) {
  299                                 result = 1;
  300                                 attaching = 0;
  301                         }
  302                 }
  303         }
  304         if (result != 0)
  305                 resource_free (dvp);
  306         return (result);
  307 }
  308 #endif /* RESOURCE_CHECK */
  309 
  310 /*
  311  * Search through all the isa_devtab_* tables looking for anything that
  312  * conflicts with the current device.
  313  */
  314 int
  315 haveseen_isadev(dvp, checkbits)
  316         struct isa_device *dvp;
  317         u_int   checkbits;
  318 {
  319 #if NPNP > 0
  320         struct pnp_dlist_node *nod;
  321 #endif
  322         struct isa_device *tmpdvp;
  323         int     status = 0;
  324 
  325         for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
  326                 status |= haveseen(dvp, tmpdvp, checkbits);
  327                 if (status)
  328                         return status;
  329         }
  330         for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
  331                 status |= haveseen(dvp, tmpdvp, checkbits);
  332                 if (status)
  333                         return status;
  334         }
  335         for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
  336                 status |= haveseen(dvp, tmpdvp, checkbits);
  337                 if (status)
  338                         return status;
  339         }
  340         for (tmpdvp = isa_devtab_cam; tmpdvp->id_driver; tmpdvp++) {
  341                 status |= haveseen(dvp, tmpdvp, checkbits);
  342                 if (status)
  343                         return status;
  344         }
  345         for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
  346                 status |= haveseen(dvp, tmpdvp, checkbits);
  347                 if (status)
  348                         return status;
  349         }
  350 #if NPNP > 0
  351         for (nod = pnp_device_list; nod != NULL; nod = nod->next)
  352                 if (status |= haveseen(dvp, &(nod->dev), checkbits))
  353                         return status;
  354 #endif
  355 #ifdef RESOURCE_CHECK
  356         if (!dvp->id_conflicts)
  357                 status = check_pciconflict(dvp, checkbits);
  358         else if (bootverbose)
  359                 printf("\tnot checking for resource conflicts ...\n");
  360 #endif /* RESOURCE_CHECK */
  361         return(status);
  362 }
  363 
  364 /*
  365  * Configure all ISA devices
  366  */
  367 void
  368 isa_configure()
  369 {
  370         struct isa_device *dvp;
  371 
  372         printf("Probing for devices on the ISA bus:\n");
  373         /* First probe all the sensitive probes */
  374         for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
  375                 if (dvp->id_driver->sensitive_hw)
  376                         config_isadev(dvp, &tty_imask);
  377         for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
  378                 if (dvp->id_driver->sensitive_hw)
  379                         config_isadev(dvp, &bio_imask);
  380         for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
  381                 if (dvp->id_driver->sensitive_hw)
  382                         config_isadev(dvp, &net_imask);
  383         for (dvp = isa_devtab_cam; dvp->id_driver; dvp++)
  384                 if (dvp->id_driver->sensitive_hw)
  385                         config_isadev(dvp, &cam_imask);
  386         for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
  387                 if (dvp->id_driver->sensitive_hw)
  388                         config_isadev(dvp, (u_int *)NULL);
  389 
  390         /* Then all the bad ones */
  391         for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
  392                 if (!dvp->id_driver->sensitive_hw)
  393                         config_isadev(dvp, &tty_imask);
  394         for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
  395                 if (!dvp->id_driver->sensitive_hw)
  396                         config_isadev(dvp, &bio_imask);
  397         for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
  398                 if (!dvp->id_driver->sensitive_hw)
  399                         config_isadev(dvp, &net_imask);
  400         for (dvp = isa_devtab_cam; dvp->id_driver; dvp++)
  401                 if (!dvp->id_driver->sensitive_hw)
  402                         config_isadev(dvp, &cam_imask);
  403         for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
  404                 if (!dvp->id_driver->sensitive_hw)
  405                         config_isadev(dvp, (u_int *)NULL);
  406 
  407         bio_imask |= SWI_CLOCK_MASK;
  408         net_imask |= SWI_NET_MASK;
  409         tty_imask |= SWI_TTY_MASK;
  410 
  411 /*
  412  * XXX we should really add the tty device to net_imask when the line is
  413  * switched to SLIPDISC, and then remove it when it is switched away from
  414  * SLIPDISC.  No need to block out ALL ttys during a splimp when only one
  415  * of them is running slip.
  416  *
  417  * XXX actually, blocking all ttys during a splimp doesn't matter so much
  418  * with sio because the serial interrupt layer doesn't use tty_imask.  Only
  419  * non-serial ttys suffer.  It's more stupid that ALL 'net's are blocked
  420  * during spltty.
  421  */
  422 #include "sl.h"
  423 #if NSL > 0
  424         net_imask |= tty_imask;
  425         tty_imask = net_imask;
  426 #endif
  427 
  428         /* bio_imask |= tty_imask ;  can some tty devices use buffers? */
  429 
  430         if (bootverbose)
  431                 printf("imasks: bio %x, tty %x, net %x\n",
  432                        bio_imask, tty_imask, net_imask);
  433 
  434         /*
  435          * Finish initializing intr_mask[].  Note that the partly
  436          * constructed masks aren't actually used since we're at splhigh.
  437          * For fully dynamic initialization, register_intr() and
  438          * icu_unset() will have to adjust the masks for _all_
  439          * interrupts and for tty_imask, etc.
  440          */
  441         for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
  442                 register_imask(dvp, tty_imask);
  443         for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
  444                 register_imask(dvp, bio_imask);
  445         for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
  446                 register_imask(dvp, net_imask);
  447         for (dvp = isa_devtab_cam; dvp->id_driver; dvp++)
  448                 register_imask(dvp, cam_imask);
  449         for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
  450                 register_imask(dvp, SWI_CLOCK_MASK);
  451 }
  452 
  453 /*
  454  * Configure an ISA device.
  455  */
  456 static void
  457 config_isadev(isdp, mp)
  458         struct isa_device *isdp;
  459         u_int *mp;
  460 {
  461         config_isadev_c(isdp, mp, 0);
  462 }
  463 
  464 void
  465 reconfig_isadev(isdp, mp)
  466         struct isa_device *isdp;
  467         u_int *mp;
  468 {
  469         config_isadev_c(isdp, mp, 1);
  470 }
  471 
  472 static void
  473 config_isadev_c(isdp, mp, reconfig)
  474         struct isa_device *isdp;
  475         u_int *mp;
  476         int reconfig;
  477 {
  478         u_int checkbits;
  479         int id_alive;
  480         int last_alive;
  481         struct isa_driver *dp = isdp->id_driver;
  482 
  483         if (!isdp->id_enabled) {
  484             if (bootverbose)
  485                 printf("%s%d: disabled, not probed.\n", dp->name, isdp->id_unit);
  486             return;
  487         }
  488         checkbits = CC_DRQ | CC_IOADDR | CC_MEMADDR;
  489         if (!reconfig && haveseen_isadev(isdp, checkbits))
  490                 return;
  491         if (!reconfig && isdp->id_maddr) {
  492                 isdp->id_maddr -= ISA_HOLE_START;
  493                 isdp->id_maddr += atdevbase;
  494         }
  495         if (reconfig) {
  496                 last_alive = isdp->id_alive;
  497                 isdp->id_reconfig = 1;
  498         }
  499         else {
  500                 last_alive = 0;
  501                 isdp->id_reconfig = 0;
  502         }
  503         id_alive = (*dp->probe)(isdp);
  504         if (id_alive) {
  505                 /*
  506                  * Only print the I/O address range if id_alive != -1
  507                  * Right now this is a temporary fix just for the new
  508                  * NPX code so that if it finds a 486 that can use trap
  509                  * 16 it will not report I/O addresses.
  510                  * Rod Grimes 04/26/94
  511                  */
  512                 if (!isdp->id_reconfig) {
  513                         printf("%s%d", dp->name, isdp->id_unit);
  514                         if (id_alive != -1) {
  515                                 if (isdp->id_iobase == -1)
  516                                         printf(" at");
  517                                 else {
  518                                         printf(" at 0x%x", isdp->id_iobase);
  519                                         if (isdp->id_iobase + id_alive - 1 !=
  520                                             isdp->id_iobase) {
  521                                                 printf("-0x%x",
  522                                                        isdp->id_iobase + id_alive - 1);
  523                                         }
  524                                 }
  525                         }
  526                         if (isdp->id_irq)
  527                                 printf(" irq %d", ffs(isdp->id_irq) - 1);
  528                         if (isdp->id_drq != -1)
  529                                 printf(" drq %d", isdp->id_drq);
  530                         if (isdp->id_maddr)
  531                                 printf(" maddr 0x%lx", kvtop(isdp->id_maddr));
  532                         if (isdp->id_msize)
  533                                 printf(" msize %d", isdp->id_msize);
  534                         if (isdp->id_flags)
  535                                 printf(" flags 0x%x", isdp->id_flags);
  536                         if (isdp->id_iobase && !(isdp->id_iobase & 0xf300)) {
  537                                 printf(" on motherboard");
  538                         } else if (isdp->id_iobase >= 0x1000 &&
  539                                     !(isdp->id_iobase & 0x300)) {
  540                                 printf (" on eisa slot %d",
  541                                         isdp->id_iobase >> 12);
  542                         } else {
  543                                 printf (" on isa");
  544                         }
  545                         printf("\n");
  546                         /*
  547                          * Check for conflicts again.  The driver may have
  548                          * changed *dvp.  We should weaken the early check
  549                          * since the driver may have been able to change
  550                          * *dvp to avoid conflicts if given a chance.  We
  551                          * already skip the early check for IRQs and force
  552                          * a check for IRQs in the next group of checks.
  553                          */
  554                         checkbits |= CC_ATTACH | CC_IRQ;
  555                         if (haveseen_isadev(isdp, checkbits))
  556                                 return;
  557                         isdp->id_alive = id_alive;
  558                 }
  559                 (*dp->attach)(isdp);
  560                 if (isdp->id_irq != 0 && isdp->id_intr == NULL)
  561                         printf("%s%d: irq with no handler\n",
  562                             dp->name, isdp->id_unit);
  563                 if (isdp->id_irq != 0 && isdp->id_intr != NULL) {
  564 #ifdef APIC_IO
  565                         /*
  566                          * Some motherboards use upper IRQs for traditional
  567                          * ISA INTerrupt sources.  In particular we have
  568                          * seen the secondary IDE connected to IRQ20.
  569                          * This code detects and fixes this situation.
  570                          */
  571                         u_int   apic_mask;
  572                         int     rirq;
  573 
  574                         apic_mask = isa_apic_mask(isdp->id_irq);
  575                         if (apic_mask != isdp->id_irq) {
  576                                 rirq = ffs(isdp->id_irq) - 1;
  577                                 isdp->id_irq = apic_mask;
  578                                 undirect_isa_irq(rirq); /* free for ISA */
  579                         }
  580 #endif /* APIC_IO */
  581                         register_intr(ffs(isdp->id_irq) - 1, isdp->id_id,
  582                                       isdp->id_ri_flags, isdp->id_intr,
  583                                       mp, isdp->id_unit);
  584                 }
  585         } else {
  586                 if (isdp->id_reconfig) {
  587                         (*dp->attach)(isdp); /* reconfiguration attach */
  588                 }
  589                 if (!last_alive) {
  590                         if (!isdp->id_reconfig) {
  591                                 printf("%s%d not found",
  592                                        dp->name, isdp->id_unit);
  593                                 if (isdp->id_iobase != -1)
  594                                         printf(" at 0x%x", isdp->id_iobase);
  595                                 printf("\n");
  596                         }
  597                 } else {
  598 #if 0
  599                         /* This code has not been tested.... */
  600                         if (isdp->id_irq != 0 && isdp->id_intr != NULL) {
  601                                 icu_unset(ffs(isdp->id_irq) - 1,
  602                                                 isdp->id_intr);
  603                                 if (mp)
  604                                         INTRUNMASK(*mp, isdp->id_irq);
  605                         }
  606 #else
  607                         printf ("icu_unset() not supported here ...\n");
  608 #endif
  609                 }
  610         }
  611 }
  612 
  613 static caddr_t  dma_bouncebuf[8];
  614 static u_int    dma_bouncebufsize[8];
  615 static u_int8_t dma_bounced = 0;
  616 static u_int8_t dma_busy = 0;           /* Used in isa_dmastart() */
  617 static u_int8_t dma_inuse = 0;          /* User for acquire/release */
  618 static u_int8_t dma_auto_mode = 0;
  619 
  620 #define VALID_DMA_MASK (7)
  621 
  622 /* high byte of address is stored in this port for i-th dma channel */
  623 static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
  624 
  625 /*
  626  * Setup a DMA channel's bounce buffer.
  627  */
  628 void
  629 isa_dmainit(chan, bouncebufsize)
  630         int chan;
  631         u_int bouncebufsize;
  632 {
  633         void *buf;
  634 
  635 #ifdef DIAGNOSTIC
  636         if (chan & ~VALID_DMA_MASK)
  637                 panic("isa_dmainit: channel out of range");
  638 
  639         if (dma_bouncebuf[chan] != NULL)
  640                 panic("isa_dmainit: impossible request"); 
  641 #endif
  642 
  643         dma_bouncebufsize[chan] = bouncebufsize;
  644 
  645         /* Try malloc() first.  It works better if it works. */
  646         buf = malloc(bouncebufsize, M_DEVBUF, M_NOWAIT);
  647         if (buf != NULL) {
  648                 if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) {
  649                         dma_bouncebuf[chan] = buf;
  650                         return;
  651                 }
  652                 free(buf, M_DEVBUF);
  653         }
  654         buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful,
  655                            1ul, chan & 4 ? 0x20000ul : 0x10000ul);
  656         if (buf == NULL)
  657                 printf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize);
  658         else
  659                 dma_bouncebuf[chan] = buf;
  660 }
  661 
  662 /*
  663  * Register a DMA channel's usage.  Usually called from a device driver
  664  * in open() or during its initialization.
  665  */
  666 int
  667 isa_dma_acquire(chan)
  668         int chan;
  669 {
  670 #ifdef DIAGNOSTIC
  671         if (chan & ~VALID_DMA_MASK)
  672                 panic("isa_dma_acquire: channel out of range");
  673 #endif
  674 
  675         if (dma_inuse & (1 << chan)) {
  676                 printf("isa_dma_acquire: channel %d already in use\n", chan);
  677                 return (EBUSY);
  678         }
  679         dma_inuse |= (1 << chan);
  680         dma_auto_mode &= ~(1 << chan);
  681 
  682         return (0);
  683 }
  684 
  685 /*
  686  * Unregister a DMA channel's usage.  Usually called from a device driver
  687  * during close() or during its shutdown.
  688  */
  689 void
  690 isa_dma_release(chan)
  691         int chan;
  692 {
  693 #ifdef DIAGNOSTIC
  694         if (chan & ~VALID_DMA_MASK)
  695                 panic("isa_dma_release: channel out of range");
  696 
  697         if ((dma_inuse & (1 << chan)) == 0)
  698                 printf("isa_dma_release: channel %d not in use\n", chan);
  699 #endif
  700 
  701         if (dma_busy & (1 << chan)) {
  702                 dma_busy &= ~(1 << chan);
  703                 /* 
  704                  * XXX We should also do "dma_bounced &= (1 << chan);"
  705                  * because we are acting on behalf of isa_dmadone() which
  706                  * was not called to end the last DMA operation.  This does
  707                  * not matter now, but it may in the future.
  708                  */
  709         }
  710 
  711         dma_inuse &= ~(1 << chan);
  712         dma_auto_mode &= ~(1 << chan);
  713 }
  714 
  715 /*
  716  * isa_dmacascade(): program 8237 DMA controller channel to accept
  717  * external dma control by a board.
  718  */
  719 void
  720 isa_dmacascade(chan)
  721         int chan;
  722 {
  723 #ifdef DIAGNOSTIC
  724         if (chan & ~VALID_DMA_MASK)
  725                 panic("isa_dmacascade: channel out of range");
  726 #endif
  727 
  728         /* set dma channel mode, and set dma channel mode */
  729         if ((chan & 4) == 0) {
  730                 outb(DMA1_MODE, DMA37MD_CASCADE | chan);
  731                 outb(DMA1_SMSK, chan);
  732         } else {
  733                 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
  734                 outb(DMA2_SMSK, chan & 3);
  735         }
  736 }
  737 
  738 /*
  739  * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
  740  * problems by using a bounce buffer.
  741  */
  742 void
  743 isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
  744 {
  745         vm_offset_t phys;
  746         int waport;
  747         caddr_t newaddr;
  748 
  749 #ifdef DIAGNOSTIC
  750         if (chan & ~VALID_DMA_MASK)
  751                 panic("isa_dmastart: channel out of range");
  752 
  753         if ((chan < 4 && nbytes > (1<<16))
  754             || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
  755                 panic("isa_dmastart: impossible request");
  756 
  757         if ((dma_inuse & (1 << chan)) == 0)
  758                 printf("isa_dmastart: channel %d not acquired\n", chan);
  759 #endif
  760 
  761 #if 0
  762         /*
  763          * XXX This should be checked, but drivers like ad1848 only call
  764          * isa_dmastart() once because they use Auto DMA mode.  If we
  765          * leave this in, drivers that do this will print this continuously.
  766          */
  767         if (dma_busy & (1 << chan))
  768                 printf("isa_dmastart: channel %d busy\n", chan);
  769 #endif
  770 
  771         dma_busy |= (1 << chan);
  772 
  773         if (isa_dmarangecheck(addr, nbytes, chan)) {
  774                 if (dma_bouncebuf[chan] == NULL
  775                     || dma_bouncebufsize[chan] < nbytes)
  776                         panic("isa_dmastart: bad bounce buffer"); 
  777                 dma_bounced |= (1 << chan);
  778                 newaddr = dma_bouncebuf[chan];
  779 
  780                 /* copy bounce buffer on write */
  781                 if (!(flags & B_READ))
  782                         bcopy(addr, newaddr, nbytes);
  783                 addr = newaddr;
  784         }
  785 
  786         /* translate to physical */
  787         phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
  788 
  789         if (flags & B_RAW) {
  790             dma_auto_mode |= (1 << chan);
  791         } else { 
  792             dma_auto_mode &= ~(1 << chan);
  793         }
  794 
  795         if ((chan & 4) == 0) {
  796                 /*
  797                  * Program one of DMA channels 0..3.  These are
  798                  * byte mode channels.
  799                  */
  800                 /* set dma channel mode, and reset address ff */
  801 
  802                 /* If B_RAW flag is set, then use autoinitialise mode */
  803                 if (flags & B_RAW) {
  804                   if (flags & B_READ)
  805                         outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
  806                   else
  807                         outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
  808                 }
  809                 else
  810                 if (flags & B_READ)
  811                         outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
  812                 else
  813                         outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
  814                 outb(DMA1_FFC, 0);
  815 
  816                 /* send start address */
  817                 waport =  DMA1_CHN(chan);
  818                 outb(waport, phys);
  819                 outb(waport, phys>>8);
  820                 outb(dmapageport[chan], phys>>16);
  821 
  822                 /* send count */
  823                 outb(waport + 1, --nbytes);
  824                 outb(waport + 1, nbytes>>8);
  825 
  826                 /* unmask channel */
  827                 outb(DMA1_SMSK, chan);
  828         } else {
  829                 /*
  830                  * Program one of DMA channels 4..7.  These are
  831                  * word mode channels.
  832                  */
  833                 /* set dma channel mode, and reset address ff */
  834 
  835                 /* If B_RAW flag is set, then use autoinitialise mode */
  836                 if (flags & B_RAW) {
  837                   if (flags & B_READ)
  838                         outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
  839                   else
  840                         outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
  841                 }
  842                 else
  843                 if (flags & B_READ)
  844                         outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
  845                 else
  846                         outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
  847                 outb(DMA2_FFC, 0);
  848 
  849                 /* send start address */
  850                 waport = DMA2_CHN(chan - 4);
  851                 outb(waport, phys>>1);
  852                 outb(waport, phys>>9);
  853                 outb(dmapageport[chan], phys>>16);
  854 
  855                 /* send count */
  856                 nbytes >>= 1;
  857                 outb(waport + 2, --nbytes);
  858                 outb(waport + 2, nbytes>>8);
  859 
  860                 /* unmask channel */
  861                 outb(DMA2_SMSK, chan & 3);
  862         }
  863 }
  864 
  865 void
  866 isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
  867 {  
  868 #ifdef DIAGNOSTIC
  869         if (chan & ~VALID_DMA_MASK)
  870                 panic("isa_dmadone: channel out of range");
  871 
  872         if ((dma_inuse & (1 << chan)) == 0)
  873                 printf("isa_dmadone: channel %d not acquired\n", chan);
  874 #endif
  875 
  876         if (((dma_busy & (1 << chan)) == 0) && 
  877             (dma_auto_mode & (1 << chan)) == 0 )
  878                 printf("isa_dmadone: channel %d not busy\n", chan);
  879 
  880         if ((dma_auto_mode & (1 << chan)) == 0)
  881                 outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4);
  882 
  883         if (dma_bounced & (1 << chan)) {
  884                 /* copy bounce buffer on read */
  885                 if (flags & B_READ)
  886                         bcopy(dma_bouncebuf[chan], addr, nbytes);
  887 
  888                 dma_bounced &= ~(1 << chan);
  889         }
  890         dma_busy &= ~(1 << chan);
  891 }
  892 
  893 /*
  894  * Check for problems with the address range of a DMA transfer
  895  * (non-contiguous physical pages, outside of bus address space,
  896  * crossing DMA page boundaries).
  897  * Return true if special handling needed.
  898  */
  899 
  900 static int
  901 isa_dmarangecheck(caddr_t va, u_int length, int chan)
  902 {
  903         vm_offset_t phys, priorpage = 0, endva;
  904         u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
  905 
  906         endva = (vm_offset_t)round_page((vm_offset_t)va + length);
  907         for (; va < (caddr_t) endva ; va += PAGE_SIZE) {
  908                 phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
  909 #define ISARAM_END      RAM_END
  910                 if (phys == 0)
  911                         panic("isa_dmacheck: no physical page present");
  912                 if (phys >= ISARAM_END)
  913                         return (1);
  914                 if (priorpage) {
  915                         if (priorpage + PAGE_SIZE != phys)
  916                                 return (1);
  917                         /* check if crossing a DMA page boundary */
  918                         if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
  919                                 return (1);
  920                 }
  921                 priorpage = phys;
  922         }
  923         return (0);
  924 }
  925 
  926 /*
  927  * Query the progress of a transfer on a DMA channel.
  928  *
  929  * To avoid having to interrupt a transfer in progress, we sample
  930  * each of the high and low databytes twice, and apply the following
  931  * logic to determine the correct count.
  932  *
  933  * Reads are performed with interrupts disabled, thus it is to be
  934  * expected that the time between reads is very small.  At most
  935  * one rollover in the low count byte can be expected within the
  936  * four reads that are performed.
  937  *
  938  * There are three gaps in which a rollover can occur :
  939  *
  940  * - read low1
  941  *              gap1
  942  * - read high1
  943  *              gap2
  944  * - read low2
  945  *              gap3
  946  * - read high2
  947  *
  948  * If a rollover occurs in gap1 or gap2, the low2 value will be
  949  * greater than the low1 value.  In this case, low2 and high2 are a
  950  * corresponding pair. 
  951  *
  952  * In any other case, low1 and high1 can be considered to be correct.
  953  *
  954  * The function returns the number of bytes remaining in the transfer,
  955  * or -1 if the channel requested is not active.
  956  *
  957  */
  958 int
  959 isa_dmastatus(int chan)
  960 {
  961         u_long  cnt = 0;
  962         int     ffport, waport;
  963         u_long  low1, high1, low2, high2;
  964 
  965         /* channel active? */
  966         if ((dma_inuse & (1 << chan)) == 0) {
  967                 printf("isa_dmastatus: channel %d not active\n", chan);
  968                 return(-1);
  969         }
  970         /* channel busy? */
  971 
  972         if (((dma_busy & (1 << chan)) == 0) &&
  973             (dma_auto_mode & (1 << chan)) == 0 ) {
  974             printf("chan %d not busy\n", chan);
  975             return -2 ;
  976         }       
  977         if (chan < 4) {                 /* low DMA controller */
  978                 ffport = DMA1_FFC;
  979                 waport = DMA1_CHN(chan) + 1;
  980         } else {                        /* high DMA controller */
  981                 ffport = DMA2_FFC;
  982                 waport = DMA2_CHN(chan - 4) + 2;
  983         }
  984 
  985         disable_intr();                 /* no interrupts Mr Jones! */
  986         outb(ffport, 0);                /* clear register LSB flipflop */
  987         low1 = inb(waport);
  988         high1 = inb(waport);
  989         outb(ffport, 0);                /* clear again */
  990         low2 = inb(waport);
  991         high2 = inb(waport);
  992         enable_intr();                  /* enable interrupts again */
  993 
  994         /* 
  995          * Now decide if a wrap has tried to skew our results.
  996          * Note that after TC, the count will read 0xffff, while we want 
  997          * to return zero, so we add and then mask to compensate.
  998          */
  999         if (low1 >= low2) {
 1000                 cnt = (low1 + (high1 << 8) + 1) & 0xffff;
 1001         } else {
 1002                 cnt = (low2 + (high2 << 8) + 1) & 0xffff;
 1003         }
 1004 
 1005         if (chan >= 4)                  /* high channels move words */
 1006                 cnt *= 2;
 1007         return(cnt);
 1008 }
 1009 
 1010 /*
 1011  * Stop a DMA transfer currently in progress.
 1012  */
 1013 int
 1014 isa_dmastop(int chan) 
 1015 {
 1016         if ((dma_inuse & (1 << chan)) == 0)
 1017                 printf("isa_dmastop: channel %d not acquired\n", chan);  
 1018 
 1019         if (((dma_busy & (1 << chan)) == 0) &&
 1020             ((dma_auto_mode & (1 << chan)) == 0)) {
 1021                 printf("chan %d not busy\n", chan);
 1022                 return -2 ;
 1023         }
 1024     
 1025         if ((chan & 4) == 0) {
 1026                 outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */);
 1027         } else {
 1028                 outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */);
 1029         }
 1030         return(isa_dmastatus(chan));
 1031 }
 1032 
 1033 /*
 1034  * Find the highest priority enabled display device.  Since we can't
 1035  * distinguish display devices from ttys, depend on display devices
 1036  * being sensitive and before sensitive non-display devices (if any)
 1037  * in isa_devtab_tty.
 1038  *
 1039  * XXX we should add capability flags IAMDISPLAY and ISUPPORTCONSOLES.
 1040  */
 1041 struct isa_device *
 1042 find_display()
 1043 {
 1044         struct isa_device *dvp;
 1045 
 1046         for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
 1047                 if (dvp->id_driver->sensitive_hw && dvp->id_enabled)
 1048                         return (dvp);
 1049         return (NULL);
 1050 }
 1051 
 1052 /*
 1053  * find an ISA device in a given isa_devtab_* table, given
 1054  * the table to search, the expected id_driver entry, and the unit number.
 1055  *
 1056  * this function is defined in isa_device.h, and this location is debatable;
 1057  * i put it there because it's useless w/o, and directly operates on
 1058  * the other stuff in that file.
 1059  *
 1060  */
 1061 
 1062 struct isa_device *
 1063 find_isadev(table, driverp, unit)
 1064         struct isa_device *table;
 1065         struct isa_driver *driverp;
 1066         int unit;
 1067 {
 1068         if (driverp == NULL) /* sanity check */
 1069                 return (NULL);
 1070 
 1071         while ((table->id_driver != driverp) || (table->id_unit != unit)) {
 1072                 if (table->id_driver == 0)
 1073                         return NULL;
 1074 
 1075                 table++;
 1076         }
 1077 
 1078         return (table);
 1079 }

Cache object: b686ff90b863f4403fa42fd33cc95960


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