summaryrefslogtreecommitdiffstats
path: root/sys/amd64/isa
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2004-05-16 20:30:47 +0000
committerpeter <peter@FreeBSD.org>2004-05-16 20:30:47 +0000
commitc6a708cab1fe9ed93c6074b3b8eb8d13d2444714 (patch)
treeac59674841a63dcc64ad5a52b994c40c72da21fc /sys/amd64/isa
parent5c28654d4937a2c64c6d99289b78f90d81a8c58a (diff)
downloadFreeBSD-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.c158
-rw-r--r--sys/amd64/isa/atpic_vector.S2
-rw-r--r--sys/amd64/isa/clock.c11
-rw-r--r--sys/amd64/isa/icu.h30
-rw-r--r--sys/amd64/isa/nmi.c8
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.");
OpenPOWER on IntegriCloud