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/atpic.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the author nor the names of any co-contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 /*
   31  * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/7.4/sys/i386/isa/atpic.c 180695 2008-07-22 14:27:47Z rwatson $");
   36 
   37 #include "opt_auto_eoi.h"
   38 #include "opt_isa.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/bus.h>
   43 #include <sys/interrupt.h>
   44 #include <sys/kernel.h>
   45 #include <sys/lock.h>
   46 #include <sys/module.h>
   47 #include <sys/mutex.h>
   48 
   49 #include <machine/cpufunc.h>
   50 #include <machine/frame.h>
   51 #include <machine/intr_machdep.h>
   52 #include <machine/md_var.h>
   53 #include <machine/resource.h>
   54 #include <machine/segments.h>
   55 
   56 #include <dev/ic/i8259.h>
   57 #include <i386/isa/icu.h>
   58 #ifdef PC98
   59 #include <pc98/cbus/cbus.h>
   60 #else
   61 #include <i386/isa/isa.h>
   62 #endif
   63 #include <isa/isavar.h>
   64 
   65 #define MASTER  0
   66 #define SLAVE   1
   67 
   68 /*
   69  * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and
   70  * PC-AT machines wire the slave PIC to pin 2 on the master PIC.
   71  */
   72 #ifdef PC98
   73 #define ICU_SLAVEID     7
   74 #else
   75 #define ICU_SLAVEID     2
   76 #endif
   77 
   78 /*
   79  * Determine the base master and slave modes not including auto EOI support.
   80  * All machines that FreeBSD supports use 8086 mode.
   81  */
   82 #ifdef PC98
   83 /*
   84  * PC-98 machines do not support auto EOI on the second PIC.  Also, it
   85  * seems that PC-98 machine PICs use buffered mode, and the master PIC
   86  * uses special fully nested mode.
   87  */
   88 #define BASE_MASTER_MODE        (ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086)
   89 #define BASE_SLAVE_MODE         (ICW4_BUF | ICW4_8086)
   90 #else
   91 #define BASE_MASTER_MODE        ICW4_8086
   92 #define BASE_SLAVE_MODE         ICW4_8086
   93 #endif
   94 
   95 /* Enable automatic EOI if requested. */
   96 #ifdef AUTO_EOI_1
   97 #define MASTER_MODE             (BASE_MASTER_MODE | ICW4_AEOI)
   98 #else
   99 #define MASTER_MODE             BASE_MASTER_MODE
  100 #endif
  101 #ifdef AUTO_EOI_2
  102 #define SLAVE_MODE              (BASE_SLAVE_MODE | ICW4_AEOI)
  103 #else
  104 #define SLAVE_MODE              BASE_SLAVE_MODE
  105 #endif
  106 
  107 #define IRQ_MASK(irq)           (1 << (irq))
  108 #define IMEN_MASK(ai)           (IRQ_MASK((ai)->at_irq))
  109 
  110 #define NUM_ISA_IRQS            16
  111 
  112 static void     atpic_init(void *dummy);
  113 
  114 unsigned int imen;      /* XXX */
  115 
  116 inthand_t
  117         IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
  118         IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
  119         IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
  120         IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
  121         IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
  122         IDTVEC(atpic_intr15);
  123 
  124 #define IRQ(ap, ai)     ((ap)->at_irqbase + (ai)->at_irq)
  125 
  126 #define ATPIC(io, base, eoi, imenptr)                                   \
  127         { { atpic_enable_source, atpic_disable_source, (eoi),           \
  128             atpic_enable_intr, atpic_disable_intr, atpic_vector,        \
  129             atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\
  130             atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base),     \
  131             (imenptr) }
  132 
  133 #define INTSRC(irq)                                                     \
  134         { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),    \
  135             (irq) % 8 }
  136 
  137 struct atpic {
  138         struct pic at_pic;
  139         int     at_ioaddr;
  140         int     at_irqbase;
  141         uint8_t at_intbase;
  142         uint8_t *at_imen;
  143 };
  144 
  145 struct atpic_intsrc {
  146         struct intsrc at_intsrc;
  147         inthand_t *at_intr;
  148         int     at_irq;                 /* Relative to PIC base. */
  149         enum intr_trigger at_trigger;
  150         u_long  at_count;
  151         u_long  at_straycount;
  152 };
  153 
  154 static void atpic_enable_source(struct intsrc *isrc);
  155 static void atpic_disable_source(struct intsrc *isrc, int eoi);
  156 static void atpic_eoi_master(struct intsrc *isrc);
  157 static void atpic_eoi_slave(struct intsrc *isrc);
  158 static void atpic_enable_intr(struct intsrc *isrc);
  159 static void atpic_disable_intr(struct intsrc *isrc);
  160 static int atpic_vector(struct intsrc *isrc);
  161 static void atpic_resume(struct pic *pic);
  162 static int atpic_source_pending(struct intsrc *isrc);
  163 static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  164     enum intr_polarity pol);
  165 static void atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
  166 static void i8259_init(struct atpic *pic, int slave);
  167 
  168 static struct atpic atpics[] = {
  169         ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
  170         ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
  171 };
  172 
  173 static struct atpic_intsrc atintrs[] = {
  174         INTSRC(0),
  175         INTSRC(1),
  176         INTSRC(2),
  177         INTSRC(3),
  178         INTSRC(4),
  179         INTSRC(5),
  180         INTSRC(6),
  181         INTSRC(7),
  182         INTSRC(8),
  183         INTSRC(9),
  184         INTSRC(10),
  185         INTSRC(11),
  186         INTSRC(12),
  187         INTSRC(13),
  188         INTSRC(14),
  189         INTSRC(15),
  190 };
  191 
  192 CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
  193 
  194 static __inline void
  195 _atpic_eoi_master(struct intsrc *isrc)
  196 {
  197 
  198         KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
  199             ("%s: mismatched pic", __func__));
  200 #ifndef AUTO_EOI_1
  201         outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
  202 #endif
  203 }
  204 
  205 /*
  206  * The data sheet says no auto-EOI on slave, but it sometimes works.
  207  * So, if AUTO_EOI_2 is enabled, we use it.
  208  */
  209 static __inline void
  210 _atpic_eoi_slave(struct intsrc *isrc)
  211 {
  212 
  213         KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
  214             ("%s: mismatched pic", __func__));
  215 #ifndef AUTO_EOI_2
  216         outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
  217 #ifndef AUTO_EOI_1
  218         outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
  219 #endif
  220 #endif
  221 }
  222 
  223 static void
  224 atpic_enable_source(struct intsrc *isrc)
  225 {
  226         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  227         struct atpic *ap = (struct atpic *)isrc->is_pic;
  228 
  229         mtx_lock_spin(&icu_lock);
  230         if (*ap->at_imen & IMEN_MASK(ai)) {
  231                 *ap->at_imen &= ~IMEN_MASK(ai);
  232                 outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
  233         }
  234         mtx_unlock_spin(&icu_lock);
  235 }
  236 
  237 static void
  238 atpic_disable_source(struct intsrc *isrc, int eoi)
  239 {
  240         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  241         struct atpic *ap = (struct atpic *)isrc->is_pic;
  242 
  243         mtx_lock_spin(&icu_lock);
  244         if (ai->at_trigger != INTR_TRIGGER_EDGE) {
  245                 *ap->at_imen |= IMEN_MASK(ai);
  246                 outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
  247         }
  248 
  249         /*
  250          * Take care to call these functions directly instead of through
  251          * a function pointer.  All of the referenced variables should
  252          * still be hot in the cache.
  253          */
  254         if (eoi == PIC_EOI) {
  255                 if (isrc->is_pic == &atpics[MASTER].at_pic)
  256                         _atpic_eoi_master(isrc);
  257                 else
  258                         _atpic_eoi_slave(isrc);
  259         }
  260 
  261         mtx_unlock_spin(&icu_lock);
  262 }
  263 
  264 static void
  265 atpic_eoi_master(struct intsrc *isrc)
  266 {
  267 #ifndef AUTO_EOI_1
  268         mtx_lock_spin(&icu_lock);
  269         _atpic_eoi_master(isrc);
  270         mtx_unlock_spin(&icu_lock);
  271 #endif
  272 }
  273 
  274 static void
  275 atpic_eoi_slave(struct intsrc *isrc)
  276 {
  277 #ifndef AUTO_EOI_2
  278         mtx_lock_spin(&icu_lock);
  279         _atpic_eoi_slave(isrc);
  280         mtx_unlock_spin(&icu_lock);
  281 #endif
  282 }
  283 
  284 static void
  285 atpic_enable_intr(struct intsrc *isrc)
  286 {
  287 }
  288 
  289 static void
  290 atpic_disable_intr(struct intsrc *isrc)
  291 {
  292 }
  293 
  294 
  295 static int
  296 atpic_vector(struct intsrc *isrc)
  297 {
  298         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  299         struct atpic *ap = (struct atpic *)isrc->is_pic;
  300 
  301         return (IRQ(ap, ai));
  302 }
  303 
  304 static int
  305 atpic_source_pending(struct intsrc *isrc)
  306 {
  307         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  308         struct atpic *ap = (struct atpic *)isrc->is_pic;
  309 
  310         return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
  311 }
  312 
  313 static void
  314 atpic_resume(struct pic *pic)
  315 {
  316         struct atpic *ap = (struct atpic *)pic;
  317 
  318         i8259_init(ap, ap == &atpics[SLAVE]);
  319 #ifndef PC98
  320         if (ap == &atpics[SLAVE] && elcr_found)
  321                 elcr_resume();
  322 #endif
  323 }
  324 
  325 static int
  326 atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  327     enum intr_polarity pol)
  328 {
  329         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  330         u_int vector;
  331 
  332         /* Map conforming values to edge/hi and sanity check the values. */
  333         if (trig == INTR_TRIGGER_CONFORM)
  334                 trig = INTR_TRIGGER_EDGE;
  335         if (pol == INTR_POLARITY_CONFORM)
  336                 pol = INTR_POLARITY_HIGH;
  337         vector = atpic_vector(isrc);
  338         if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
  339             (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
  340                 printf(
  341                 "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
  342                     vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
  343                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  344                 return (EINVAL);
  345         }
  346 
  347         /* If there is no change, just return. */
  348         if (ai->at_trigger == trig)
  349                 return (0);
  350 
  351 #ifdef PC98
  352         if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
  353             trig == INTR_TRIGGER_LEVEL) {
  354                 if (bootverbose)
  355                         printf(
  356                 "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
  357                             vector);
  358                 return (EINVAL);
  359         }
  360         return (ENXIO);
  361 #else
  362         /*
  363          * Certain IRQs can never be level/lo, so don't try to set them
  364          * that way if asked.  At least some ELCR registers ignore setting
  365          * these bits as well.
  366          */
  367         if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
  368             trig == INTR_TRIGGER_LEVEL) {
  369                 if (bootverbose)
  370                         printf(
  371                 "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
  372                             vector);
  373                 return (EINVAL);
  374         }
  375         if (!elcr_found) {
  376                 if (bootverbose)
  377                         printf("atpic: No ELCR to configure IRQ%u as %s\n",
  378                             vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
  379                             "level/low");
  380                 return (ENXIO);
  381         }
  382         if (bootverbose)
  383                 printf("atpic: Programming IRQ%u as %s\n", vector,
  384                     trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
  385         mtx_lock_spin(&icu_lock);
  386         elcr_write_trigger(atpic_vector(isrc), trig);
  387         ai->at_trigger = trig;
  388         mtx_unlock_spin(&icu_lock);
  389         return (0);
  390 #endif /* PC98 */
  391 }
  392 
  393 static void
  394 atpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
  395 {
  396 
  397         /*
  398          * 8259A's are only used in UP in which case all interrupts always
  399          * go to the sole CPU and this function shouldn't even be called.
  400          */
  401         panic("%s: bad cookie", __func__);
  402 }
  403 
  404 static void
  405 i8259_init(struct atpic *pic, int slave)
  406 {
  407         int imr_addr;
  408 
  409         /* Reset the PIC and program with next four bytes. */
  410         mtx_lock_spin(&icu_lock);
  411 #ifdef DEV_MCA
  412         /* MCA uses level triggered interrupts. */
  413         if (MCA_system)
  414                 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
  415         else
  416 #endif
  417                 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
  418         imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
  419 
  420         /* Start vector. */
  421         outb(imr_addr, pic->at_intbase);
  422 
  423         /*
  424          * Setup slave links.  For the master pic, indicate what line
  425          * the slave is configured on.  For the slave indicate
  426          * which line on the master we are connected to.
  427          */
  428         if (slave)
  429                 outb(imr_addr, ICU_SLAVEID);
  430         else
  431                 outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
  432 
  433         /* Set mode. */
  434         if (slave)
  435                 outb(imr_addr, SLAVE_MODE);
  436         else
  437                 outb(imr_addr, MASTER_MODE);
  438 
  439         /* Set interrupt enable mask. */
  440         outb(imr_addr, *pic->at_imen);
  441 
  442         /* Reset is finished, default to IRR on read. */
  443         outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
  444 
  445 #ifndef PC98
  446         /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
  447         if (!slave)
  448                 outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
  449 #endif
  450         mtx_unlock_spin(&icu_lock);
  451 }
  452 
  453 void
  454 atpic_startup(void)
  455 {
  456         struct atpic_intsrc *ai;
  457         int i;
  458 
  459         /* Start off with all interrupts disabled. */
  460         imen = 0xffff;
  461         i8259_init(&atpics[MASTER], 0);
  462         i8259_init(&atpics[SLAVE], 1);
  463         atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
  464 
  465         /* Install low-level interrupt handlers for all of our IRQs. */
  466         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  467                 if (i == ICU_SLAVEID)
  468                         continue;
  469                 ai->at_intsrc.is_count = &ai->at_count;
  470                 ai->at_intsrc.is_straycount = &ai->at_straycount;
  471                 setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
  472                     ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
  473                     GSEL(GCODE_SEL, SEL_KPL));
  474         }
  475 
  476 #ifdef DEV_MCA
  477         /* For MCA systems, all interrupts are level triggered. */
  478         if (MCA_system)
  479                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  480                         ai->at_trigger = INTR_TRIGGER_LEVEL;
  481         else
  482 #endif
  483 
  484 #ifdef PC98
  485         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  486                 switch (i) {
  487                 case 0:
  488                 case 1:
  489                 case 7:
  490                 case 8:
  491                         ai->at_trigger = INTR_TRIGGER_EDGE;
  492                         break;
  493                 default:
  494                         ai->at_trigger = INTR_TRIGGER_LEVEL;
  495                         break;
  496                 }
  497 #else
  498         /*
  499          * Look for an ELCR.  If we find one, update the trigger modes.
  500          * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
  501          * edge triggered and that everything else is level triggered.
  502          * We only use the trigger information to reprogram the ELCR if
  503          * we have one and as an optimization to avoid masking edge
  504          * triggered interrupts.  For the case that we don't have an ELCR,
  505          * it doesn't hurt to mask an edge triggered interrupt, so we
  506          * assume level trigger for any interrupt that we aren't sure is
  507          * edge triggered.
  508          */
  509         if (elcr_found) {
  510                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  511                         ai->at_trigger = elcr_read_trigger(i);
  512         } else {
  513                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  514                         switch (i) {
  515                         case 0:
  516                         case 1:
  517                         case 2:
  518                         case 8:
  519                         case 13:
  520                                 ai->at_trigger = INTR_TRIGGER_EDGE;
  521                                 break;
  522                         default:
  523                                 ai->at_trigger = INTR_TRIGGER_LEVEL;
  524                                 break;
  525                         }
  526         }
  527 #endif /* PC98 */
  528 }
  529 
  530 static void
  531 atpic_init(void *dummy __unused)
  532 {
  533         struct atpic_intsrc *ai;
  534         int i;
  535 
  536         /*
  537          * Register our PICs, even if we aren't going to use any of their
  538          * pins so that they are suspended and resumed.
  539          */
  540         if (intr_register_pic(&atpics[0].at_pic) != 0 ||
  541             intr_register_pic(&atpics[1].at_pic) != 0)
  542                 panic("Unable to register ATPICs");
  543 
  544         /*
  545          * If any of the ISA IRQs have an interrupt source already, then
  546          * assume that the APICs are being used and don't register any
  547          * of our interrupt sources.  This makes sure we don't accidentally
  548          * use mixed mode.  The "accidental" use could otherwise occur on
  549          * machines that route the ACPI SCI interrupt to a different ISA
  550          * IRQ (at least one machines routes it to IRQ 13) thus disabling
  551          * that APIC ISA routing and allowing the ATPIC source for that IRQ
  552          * to leak through.  We used to depend on this feature for routing
  553          * IRQ0 via mixed mode, but now we don't use mixed mode at all.
  554          */
  555         for (i = 0; i < NUM_ISA_IRQS; i++)
  556                 if (intr_lookup_source(i) != NULL)
  557                         return;
  558 
  559         /* Loop through all interrupt sources and add them. */
  560         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  561                 if (i == ICU_SLAVEID)
  562                         continue;
  563                 intr_register_source(&ai->at_intsrc);
  564         }
  565 }
  566 SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL);
  567 
  568 void
  569 atpic_handle_intr(u_int vector, struct trapframe *frame)
  570 {
  571         struct intsrc *isrc;
  572 
  573         KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
  574         isrc = &atintrs[vector].at_intsrc;
  575 
  576         /*
  577          * If we don't have an event, see if this is a spurious
  578          * interrupt.
  579          */
  580         if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
  581                 int port, isr;
  582 
  583                 /*
  584                  * Read the ISR register to see if IRQ 7/15 is really
  585                  * pending.  Reset read register back to IRR when done.
  586                  */
  587                 port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
  588                 mtx_lock_spin(&icu_lock);
  589                 outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
  590                 isr = inb(port);
  591                 outb(port, OCW3_SEL | OCW3_RR);
  592                 mtx_unlock_spin(&icu_lock);
  593                 if ((isr & IRQ_MASK(7)) == 0)
  594                         return;
  595         }
  596         intr_execute_handlers(isrc, frame);
  597 }
  598 
  599 #ifdef DEV_ISA
  600 /*
  601  * Bus attachment for the ISA PIC.
  602  */
  603 static struct isa_pnp_id atpic_ids[] = {
  604         { 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
  605         { 0 }
  606 };
  607 
  608 static int
  609 atpic_probe(device_t dev)
  610 {
  611         int result;
  612         
  613         result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
  614         if (result <= 0)
  615                 device_quiet(dev);
  616         return (result);
  617 }
  618 
  619 /*
  620  * We might be granted IRQ 2, as this is typically consumed by chaining
  621  * between the two PIC components.  If we're using the APIC, however,
  622  * this may not be the case, and as such we should free the resource.
  623  * (XXX untested)
  624  *
  625  * The generic ISA attachment code will handle allocating any other resources
  626  * that we don't explicitly claim here.
  627  */
  628 static int
  629 atpic_attach(device_t dev)
  630 {
  631         struct resource *res;
  632         int rid;
  633 
  634         /* Try to allocate our IRQ and then free it. */
  635         rid = 0;
  636         res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
  637         if (res != NULL)
  638                 bus_release_resource(dev, SYS_RES_IRQ, rid, res);
  639         return (0);
  640 }
  641 
  642 static device_method_t atpic_methods[] = {
  643         /* Device interface */
  644         DEVMETHOD(device_probe,         atpic_probe),
  645         DEVMETHOD(device_attach,        atpic_attach),
  646         DEVMETHOD(device_detach,        bus_generic_detach),
  647         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  648         DEVMETHOD(device_suspend,       bus_generic_suspend),
  649         DEVMETHOD(device_resume,        bus_generic_resume),
  650         { 0, 0 }
  651 };
  652 
  653 static driver_t atpic_driver = {
  654         "atpic",
  655         atpic_methods,
  656         1,              /* no softc */
  657 };
  658 
  659 static devclass_t atpic_devclass;
  660 
  661 DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
  662 #ifndef PC98
  663 DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
  664 #endif
  665 
  666 /*
  667  * Return a bitmap of the current interrupt requests.  This is 8259-specific
  668  * and is only suitable for use at probe time.
  669  */
  670 intrmask_t
  671 isa_irq_pending(void)
  672 {
  673         u_char irr1;
  674         u_char irr2;
  675 
  676         irr1 = inb(IO_ICU1);
  677         irr2 = inb(IO_ICU2);
  678         return ((irr2 << 8) | irr1);
  679 }
  680 #endif /* DEV_ISA */

Cache object: d8f6fa3e49764bd419b679f267a1d850


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