diff options
author | peter <peter@FreeBSD.org> | 2004-05-16 20:30:47 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2004-05-16 20:30:47 +0000 |
commit | c6a708cab1fe9ed93c6074b3b8eb8d13d2444714 (patch) | |
tree | ac59674841a63dcc64ad5a52b994c40c72da21fc /sys/amd64/isa | |
parent | 5c28654d4937a2c64c6d99289b78f90d81a8c58a (diff) | |
download | FreeBSD-src-c6a708cab1fe9ed93c6074b3b8eb8d13d2444714.zip FreeBSD-src-c6a708cab1fe9ed93c6074b3b8eb8d13d2444714.tar.gz |
MFi386: numerous interrupt and acpi updates
Diffstat (limited to 'sys/amd64/isa')
-rw-r--r-- | sys/amd64/isa/atpic.c | 158 | ||||
-rw-r--r-- | sys/amd64/isa/atpic_vector.S | 2 | ||||
-rw-r--r-- | sys/amd64/isa/clock.c | 11 | ||||
-rw-r--r-- | sys/amd64/isa/icu.h | 30 | ||||
-rw-r--r-- | sys/amd64/isa/nmi.c | 8 |
5 files changed, 143 insertions, 66 deletions
diff --git a/sys/amd64/isa/atpic.c b/sys/amd64/isa/atpic.c index 6d726eb..98276b7 100644 --- a/sys/amd64/isa/atpic.c +++ b/sys/amd64/isa/atpic.c @@ -63,6 +63,16 @@ __FBSDID("$FreeBSD$"); #define SLAVE 1 /* + * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and + * PC-AT machines wire the slave PIC to pin 2 on the master PIC. + */ +#ifdef PC98 +#define ICU_SLAVEID 7 +#else +#define ICU_SLAVEID 2 +#endif + +/* * Determine the base master and slave modes not including auto EOI support. * All machines that FreeBSD supports use 8086 mode. */ @@ -81,9 +91,15 @@ __FBSDID("$FreeBSD$"); #define SLAVE_MODE BASE_SLAVE_MODE #endif +#define IRQ_MASK(irq) (1 << (irq)) +#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) + +#define NUM_ISA_IRQS 16 + static void atpic_init(void *dummy); unsigned int imen; /* XXX */ +static int using_elcr; inthand_t IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), @@ -95,14 +111,15 @@ inthand_t #define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) -#define ATPIC(io, base, eoi, imenptr) \ +#define ATPIC(io, base, eoi, imenptr) \ { { atpic_enable_source, atpic_disable_source, (eoi), \ atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ - atpic_resume }, (io), (base), IDT_IO_INTS + (base), (imenptr) } + atpic_resume, atpic_config_intr }, (io), (base), \ + IDT_IO_INTS + (base), (imenptr) } #define INTSRC(irq) \ - { { &atpics[(irq) / 8].at_pic }, (irq) % 8, \ - IDTVEC(atpic_intr ## irq ) } + { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ + (irq) % 8 } struct atpic { struct pic at_pic; @@ -114,8 +131,9 @@ struct atpic { struct atpic_intsrc { struct intsrc at_intsrc; - int at_irq; /* Relative to PIC base. */ inthand_t *at_intr; + int at_irq; /* Relative to PIC base. */ + enum intr_trigger at_trigger; u_long at_count; u_long at_straycount; }; @@ -128,6 +146,8 @@ static void atpic_enable_intr(struct intsrc *isrc); static int atpic_vector(struct intsrc *isrc); static void atpic_resume(struct intsrc *isrc); static int atpic_source_pending(struct intsrc *isrc); +static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, + enum intr_polarity pol); static void i8259_init(struct atpic *pic, int slave); static struct atpic atpics[] = { @@ -154,6 +174,8 @@ static struct atpic_intsrc atintrs[] = { INTSRC(15), }; +CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); + static void atpic_enable_source(struct intsrc *isrc) { @@ -161,8 +183,10 @@ atpic_enable_source(struct intsrc *isrc) struct atpic *ap = (struct atpic *)isrc->is_pic; mtx_lock_spin(&icu_lock); - *ap->at_imen &= ~(1 << ai->at_irq); - outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); + if (*ap->at_imen & IMEN_MASK(ai)) { + *ap->at_imen &= ~IMEN_MASK(ai); + outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); + } mtx_unlock_spin(&icu_lock); } @@ -172,8 +196,10 @@ atpic_disable_source(struct intsrc *isrc) struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; struct atpic *ap = (struct atpic *)isrc->is_pic; + if (ai->at_trigger == INTR_TRIGGER_EDGE) + return; mtx_lock_spin(&icu_lock); - *ap->at_imen |= (1 << ai->at_irq); + *ap->at_imen |= IMEN_MASK(ai); outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); mtx_unlock_spin(&icu_lock); } @@ -186,7 +212,7 @@ atpic_eoi_master(struct intsrc *isrc) ("%s: mismatched pic", __func__)); #ifndef AUTO_EOI_1 mtx_lock_spin(&icu_lock); - outb(atpics[MASTER].at_ioaddr, ICU_EOI); + outb(atpics[MASTER].at_ioaddr, OCW2_EOI); mtx_unlock_spin(&icu_lock); #endif } @@ -203,9 +229,9 @@ atpic_eoi_slave(struct intsrc *isrc) ("%s: mismatched pic", __func__)); #ifndef AUTO_EOI_2 mtx_lock_spin(&icu_lock); - outb(atpics[SLAVE].at_ioaddr, ICU_EOI); + outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); #ifndef AUTO_EOI_1 - outb(atpics[MASTER].at_ioaddr, ICU_EOI); + outb(atpics[MASTER].at_ioaddr, OCW2_EOI); #endif mtx_unlock_spin(&icu_lock); #endif @@ -231,7 +257,7 @@ atpic_source_pending(struct intsrc *isrc) struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; struct atpic *ap = (struct atpic *)isrc->is_pic; - return (inb(ap->at_ioaddr) & (1 << ai->at_irq)); + return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); } static void @@ -240,8 +266,67 @@ atpic_resume(struct intsrc *isrc) struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; struct atpic *ap = (struct atpic *)isrc->is_pic; - if (ai->at_irq == 0) + if (ai->at_irq == 0) { i8259_init(ap, ap == &atpics[SLAVE]); + if (ap == &atpics[SLAVE] && using_elcr) + elcr_resume(); + } +} + +static int +atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, + enum intr_polarity pol) +{ + struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; + u_int vector; + + /* Map conforming values to edge/hi and sanity check the values. */ + if (trig == INTR_TRIGGER_CONFORM) + trig = INTR_TRIGGER_EDGE; + if (pol == INTR_POLARITY_CONFORM) + pol = INTR_POLARITY_HIGH; + vector = atpic_vector(isrc); + if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || + (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { + printf( + "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", + vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", + pol == INTR_POLARITY_HIGH ? "high" : "low"); + return (EINVAL); + } + + /* If there is no change, just return. */ + if (ai->at_trigger == trig) + return (0); + + /* + * Certain IRQs can never be level/lo, so don't try to set them + * that way if asked. At least some ELCR registers ignore setting + * these bits as well. + */ + if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && + trig == INTR_TRIGGER_LEVEL) { + if (bootverbose) + printf( + "atpic: Ignoring invalid level/low configuration for IRQ%u\n", + vector); + return (EINVAL); + } + if (!using_elcr) { + if (bootverbose) + printf("atpic: No ELCR to configure IRQ%u as %s\n", + vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : + "level/low"); + return (ENXIO); + } + if (bootverbose) + printf("atpic: Programming IRQ%u as %s\n", vector, + trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); + mtx_lock_spin(&icu_lock); + elcr_write_trigger(atpic_vector(isrc), trig); + ai->at_trigger = trig; + mtx_unlock_spin(&icu_lock); + return (0); } static void @@ -263,9 +348,9 @@ i8259_init(struct atpic *pic, int slave) * which line on the master we are connected to. */ if (slave) - outb(imr_addr, ICU_SLAVEID); /* my slave id is 7 */ + outb(imr_addr, ICU_SLAVEID); else - outb(imr_addr, IRQ_SLAVE); /* slave on line 7 */ + outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); /* Set mode. */ if (slave) @@ -298,27 +383,58 @@ atpic_startup(void) atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); /* Install low-level interrupt handlers for all of our IRQs. */ - for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) { + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { if (i == ICU_SLAVEID) continue; - ai = &atintrs[i]; ai->at_intsrc.is_count = &ai->at_count; ai->at_intsrc.is_straycount = &ai->at_straycount; setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + ai->at_irq, ai->at_intr, SDT_SYSIGT, SEL_KPL, 0); } + + /* + * Look for an ELCR. If we find one, update the trigger modes. + * If we don't find one, assume that IRQs 0, 1, 2, and 13 are + * edge triggered and that everything else is level triggered. + * We only use the trigger information to reprogram the ELCR if + * we have one and as an optimization to avoid masking edge + * triggered interrupts. For the case that we don't have an ELCR, + * it doesn't hurt to mask an edge triggered interrupt, so we + * assume level trigger for any interrupt that we aren't sure is + * edge triggered. + */ + if (elcr_probe() == 0) { + using_elcr = 1; + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) + ai->at_trigger = elcr_read_trigger(i); + } else { + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) + switch (i) { + case 0: + case 1: + case 2: + case 8: + case 13: + ai->at_trigger = INTR_TRIGGER_EDGE; + break; + default: + ai->at_trigger = INTR_TRIGGER_LEVEL; + break; + } + } } static void atpic_init(void *dummy __unused) { + struct atpic_intsrc *ai; int i; /* Loop through all interrupt sources and add them. */ - for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) { + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { if (i == ICU_SLAVEID) continue; - intr_register_source(&atintrs[i].at_intsrc); + intr_register_source(&ai->at_intsrc); } } SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) @@ -329,7 +445,7 @@ atpic_handle_intr(void *cookie, struct intrframe iframe) struct intsrc *isrc; int vec = (uintptr_t)cookie; - KASSERT(vec < ICU_LEN, ("unknown int %d\n", vec)); + KASSERT(vec < NUM_ISA_IRQS, ("unknown int %d\n", vec)); isrc = &atintrs[vec].at_intsrc; /* @@ -349,7 +465,7 @@ atpic_handle_intr(void *cookie, struct intrframe iframe) isr = inb(port); outb(port, OCW3_SEL | OCW3_RR); mtx_unlock_spin(&icu_lock); - if ((isr & IRQ7) == 0) + if ((isr & IRQ_MASK(7)) == 0) return; } intr_execute_handlers(isrc, &iframe); diff --git a/sys/amd64/isa/atpic_vector.S b/sys/amd64/isa/atpic_vector.S index a8e0d83..72f3bed 100644 --- a/sys/amd64/isa/atpic_vector.S +++ b/sys/amd64/isa/atpic_vector.S @@ -37,8 +37,6 @@ */ #include <machine/asmacros.h> -#include <amd64/isa/icu.h> -#include <amd64/isa/isa.h> #include "assym.s" diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index 47ae6da..fca9127 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/isa/clock.c @@ -73,7 +73,6 @@ __FBSDID("$FreeBSD$"); #endif #include <machine/specialreg.h> -#include <amd64/isa/icu.h> #include <amd64/isa/isa.h> #include <isa/rtc.h> #ifdef DEV_ISA @@ -107,10 +106,11 @@ struct mtx clock_lock; static int beeping = 0; static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; static u_int hardclock_max_count; +static struct intsrc *i8254_intsrc; static u_int32_t i8254_lastcount; static u_int32_t i8254_offset; +static int (*i8254_pending)(struct intsrc *); static int i8254_ticked; -static struct intsrc *i8254_intsrc; static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; @@ -741,6 +741,9 @@ cpu_initclocks() /* Finish initializing 8254 timer 0. */ intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL, INTR_TYPE_CLK | INTR_FAST, NULL); + i8254_intsrc = intr_lookup_source(0); + if (i8254_intsrc != NULL) + i8254_pending = i8254_intsrc->is_pic->pic_source_pending; /* Initialize RTC. */ writertc(RTC_STATUSA, rtc_statusa); @@ -754,7 +757,6 @@ cpu_initclocks() intr_add_handler("rtc", 8, (driver_intr_t *)rtcintr, NULL, INTR_TYPE_CLK | INTR_FAST, NULL); - i8254_intsrc = intr_lookup_source(8); writertc(RTC_STATUSB, rtc_statusb); } @@ -821,8 +823,7 @@ i8254_get_timecount(struct timecounter *tc) if (count < i8254_lastcount || (!i8254_ticked && (clkintr_pending || ((count < 20 || (!(rflags & PSL_I) && count < timer0_max_count / 2u)) && - i8254_intsrc != NULL && - i8254_intsrc->is_pic->pic_source_pending(i8254_intsrc))))) { + i8254_intsrc != NULL && i8254_pending(i8254_intsrc))))) { i8254_ticked = 1; i8254_offset += timer0_max_count; } diff --git a/sys/amd64/isa/icu.h b/sys/amd64/isa/icu.h index 17d6931..f25fac6 100644 --- a/sys/amd64/isa/icu.h +++ b/sys/amd64/isa/icu.h @@ -41,39 +41,9 @@ #ifndef _AMD64_ISA_ICU_H_ #define _AMD64_ISA_ICU_H_ -/* - * Interrupt enable bits - in normal order of priority (which we change) - */ -#define IRQ0 0x0001 /* highest priority - timer */ -#define IRQ1 0x0002 -#define IRQ_SLAVE 0x0004 -#define IRQ8 0x0100 -#define IRQ9 0x0200 -#define IRQ2 IRQ9 -#define IRQ10 0x0400 -#define IRQ11 0x0800 -#define IRQ12 0x1000 -#define IRQ13 0x2000 -#define IRQ14 0x4000 -#define IRQ15 0x8000 -#define IRQ3 0x0008 /* this is highest after rotation */ -#define IRQ4 0x0010 -#define IRQ5 0x0020 -#define IRQ6 0x0040 -#define IRQ7 0x0080 /* lowest - parallel printer */ - -/* - * Interrupt Control offset into Interrupt descriptor table (IDT) - */ -#define ICU_OFFSET 32 /* 0-31 are processor exceptions */ -#define ICU_LEN 16 /* 32-47 are ISA interrupts */ #define ICU_IMR_OFFSET 1 -#define ICU_SLAVEID 2 -#define ICU_EOI (OCW2_EOI) /* non-specific EOI */ -#ifndef LOCORE void atpic_handle_intr(void *cookie, struct intrframe iframe); void atpic_startup(void); -#endif #endif /* !_AMD64_ISA_ICU_H_ */ diff --git a/sys/amd64/isa/nmi.c b/sys/amd64/isa/nmi.c index db5550c..887879a 100644 --- a/sys/amd64/isa/nmi.c +++ b/sys/amd64/isa/nmi.c @@ -43,10 +43,6 @@ __FBSDID("$FreeBSD$"); #include <machine/md_var.h> -#ifdef DEV_MCA -#include <i386/bios/mca_machdep.h> -#endif - #define NMI_PARITY (1 << 7) #define NMI_IOCHAN (1 << 6) #define ENMI_WATCHDOG (1 << 7) @@ -65,10 +61,6 @@ isa_nmi(int cd) int eisa_port = inb(0x461); log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port); -#ifdef DEV_MCA - if (MCA_system && mca_bus_nmi()) - return(0); -#endif if (isa_port & NMI_PARITY) { log(LOG_CRIT, "RAM parity error, likely hardware failure."); |