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

Cache object: fbdc65838646f49ff7fd144ef923d381


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