summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2006-10-10 23:23:12 +0000
committerjhb <jhb@FreeBSD.org>2006-10-10 23:23:12 +0000
commit920b219fcf73ff01950bf272923fd4b46e75fb62 (patch)
treeeb9c93770a076684865872d673c762161b0390f7 /sys
parent98af27d199c605e0cfa80eee1e631093cf1bf30a (diff)
downloadFreeBSD-src-920b219fcf73ff01950bf272923fd4b46e75fb62.zip
FreeBSD-src-920b219fcf73ff01950bf272923fd4b46e75fb62.tar.gz
Change the x86 interrupt code to suspend/resume interrupt controllers
(PICs) rather than interrupt sources. This allows interrupt controllers with no interrupt pics (such as the 8259As when APIC is in use) to participate in suspend/resume. - Always register the 8259A PICs even if we don't use any of their pins. - Explicitly reset the 8259As on resume on amd64 if 'device atpic' isn't included. - Add a "dummy" PIC for the local APIC on the BSP to reset the local APIC on resume. This gets suspend/resume working with APIC on UP systems. SMP still needs more work to bring the APs back to life. The MFC after is tentative. Tested by: anholt (i386) Submitted by: Andrea Bittau <a.bittau at cs.ucl.ac.uk> (3) MFC after: 1 week
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/amd64/intr_machdep.c84
-rw-r--r--sys/amd64/amd64/io_apic.c23
-rw-r--r--sys/amd64/amd64/local_apic.c26
-rw-r--r--sys/amd64/amd64/machdep.c14
-rw-r--r--sys/amd64/amd64/mp_machdep.c2
-rw-r--r--sys/amd64/include/apicvar.h2
-rw-r--r--sys/amd64/include/intr_machdep.h9
-rw-r--r--sys/amd64/isa/atpic.c23
-rw-r--r--sys/i386/i386/intr_machdep.c58
-rw-r--r--sys/i386/i386/io_apic.c22
-rw-r--r--sys/i386/i386/local_apic.c26
-rw-r--r--sys/i386/i386/mp_machdep.c2
-rw-r--r--sys/i386/include/apicvar.h2
-rw-r--r--sys/i386/include/intr_machdep.h6
-rw-r--r--sys/i386/isa/atpic.c23
15 files changed, 224 insertions, 98 deletions
diff --git a/sys/amd64/amd64/intr_machdep.c b/sys/amd64/amd64/intr_machdep.c
index 9a4eaca..65dd827 100644
--- a/sys/amd64/amd64/intr_machdep.c
+++ b/sys/amd64/amd64/intr_machdep.c
@@ -37,6 +37,7 @@
* that source.
*/
+#include "opt_atpic.h"
#include "opt_ddb.h"
#include <sys/param.h>
@@ -62,6 +63,7 @@ typedef void (*mask_fn)(void *);
static int intrcnt_index;
static struct intsrc *interrupt_sources[NUM_IO_INTS];
static struct mtx intr_table_lock;
+static STAILQ_HEAD(, pic) pics;
#ifdef SMP
static int assign_cpu;
@@ -70,10 +72,45 @@ static void intr_assign_next_cpu(struct intsrc *isrc);
#endif
static void intr_init(void *__dummy);
+static int intr_pic_registered(struct pic *pic);
static void intrcnt_setname(const char *name, int index);
static void intrcnt_updatename(struct intsrc *is);
static void intrcnt_register(struct intsrc *is);
+static int
+intr_pic_registered(struct pic *pic)
+{
+ struct pic *p;
+
+ STAILQ_FOREACH(p, &pics, pics) {
+ if (p == pic)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Register a new interrupt controller (PIC). This is to support suspend
+ * and resume where we suspend/resume controllers rather than individual
+ * sources. This also allows controllers with no active sources (such as
+ * 8259As in a system using the APICs) to participate in suspend and resume.
+ */
+int
+intr_register_pic(struct pic *pic)
+{
+ int error;
+
+ mtx_lock_spin(&intr_table_lock);
+ if (intr_pic_registered(pic))
+ error = EBUSY;
+ else {
+ STAILQ_INSERT_TAIL(&pics, pic, pics);
+ error = 0;
+ }
+ mtx_unlock_spin(&intr_table_lock);
+ return (error);
+}
+
/*
* Register a new interrupt source with the global interrupt system.
* The global interrupts need to be disabled when this function is
@@ -84,6 +121,7 @@ intr_register_source(struct intsrc *isrc)
{
int error, vector;
+ KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC"));
vector = isrc->is_pic->pic_vector(isrc);
if (interrupt_sources[vector] != NULL)
return (EEXIST);
@@ -255,26 +293,29 @@ intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
void
intr_resume(void)
{
- struct intsrc **isrc;
- int i;
+ struct pic *pic;
+#ifndef DEV_ATPIC
+ atpic_reset();
+#endif
mtx_lock_spin(&intr_table_lock);
- for (i = 0, isrc = interrupt_sources; i < NUM_IO_INTS; i++, isrc++)
- if (*isrc != NULL && (*isrc)->is_pic->pic_resume != NULL)
- (*isrc)->is_pic->pic_resume(*isrc);
+ STAILQ_FOREACH(pic, &pics, pics) {
+ if (pic->pic_resume != NULL)
+ pic->pic_resume(pic);
+ }
mtx_unlock_spin(&intr_table_lock);
}
void
intr_suspend(void)
{
- struct intsrc **isrc;
- int i;
+ struct pic *pic;
mtx_lock_spin(&intr_table_lock);
- for (i = 0, isrc = interrupt_sources; i < NUM_IO_INTS; i++, isrc++)
- if (*isrc != NULL && (*isrc)->is_pic->pic_suspend != NULL)
- (*isrc)->is_pic->pic_suspend(*isrc);
+ STAILQ_FOREACH(pic, &pics, pics) {
+ if (pic->pic_suspend != NULL)
+ pic->pic_suspend(pic);
+ }
mtx_unlock_spin(&intr_table_lock);
}
@@ -327,10 +368,33 @@ intr_init(void *dummy __unused)
intrcnt_setname("???", 0);
intrcnt_index = 1;
+ STAILQ_INIT(&pics);
mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
}
SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL)
+#ifndef DEV_ATPIC
+/* Initialize the two 8259A's to a known-good shutdown state. */
+void
+atpic_reset(void)
+{
+
+ outb(IO_ICU1, ICW1_RESET | ICW1_IC4);
+ outb(IO_ICU1 + ICU_IMR_OFFSET, IDT_IO_INTS);
+ outb(IO_ICU1 + ICU_IMR_OFFSET, 1 << 2);
+ outb(IO_ICU1 + ICU_IMR_OFFSET, ICW4_8086);
+ outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff);
+ outb(IO_ICU1, OCW3_SEL | OCW3_RR);
+
+ outb(IO_ICU2, ICW1_RESET | ICW1_IC4);
+ outb(IO_ICU2 + ICU_IMR_OFFSET, IDT_IO_INTS + 8);
+ outb(IO_ICU2 + ICU_IMR_OFFSET, 2);
+ outb(IO_ICU2 + ICU_IMR_OFFSET, ICW4_8086);
+ outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff);
+ outb(IO_ICU2, OCW3_SEL | OCW3_RR);
+}
+#endif
+
#ifdef DDB
/*
* Dump data about interrupt handlers
diff --git a/sys/amd64/amd64/io_apic.c b/sys/amd64/amd64/io_apic.c
index be88bbd..3a893cd 100644
--- a/sys/amd64/amd64/io_apic.c
+++ b/sys/amd64/amd64/io_apic.c
@@ -30,7 +30,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_atpic.h"
#include "opt_isa.h"
#include <sys/param.h>
@@ -61,8 +60,6 @@ __FBSDID("$FreeBSD$");
#define IRQ_SMI (NUM_IO_INTS + 3)
#define IRQ_DISABLED (NUM_IO_INTS + 4)
-#define TODO printf("%s: not implemented!\n", __func__)
-
static MALLOC_DEFINE(M_IOAPIC, "io_apic", "I/O APIC structures");
/*
@@ -115,8 +112,7 @@ static int ioapic_vector(struct intsrc *isrc);
static int ioapic_source_pending(struct intsrc *isrc);
static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
enum intr_polarity pol);
-static void ioapic_suspend(struct intsrc *isrc);
-static void ioapic_resume(struct intsrc *isrc);
+static void ioapic_resume(struct pic *pic);
static void ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id);
static void ioapic_program_intpin(struct ioapic_intsrc *intpin);
@@ -124,7 +120,7 @@ static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
ioapic_eoi_source, ioapic_enable_intr,
ioapic_vector, ioapic_source_pending,
- ioapic_suspend, ioapic_resume,
+ NULL, ioapic_resume,
ioapic_config_intr, ioapic_assign_cpu };
static int next_ioapic_base;
@@ -419,17 +415,13 @@ ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
}
static void
-ioapic_suspend(struct intsrc *isrc)
-{
-
- TODO;
-}
-
-static void
-ioapic_resume(struct intsrc *isrc)
+ioapic_resume(struct pic *pic)
{
+ struct ioapic *io = (struct ioapic *)pic;
+ int i;
- ioapic_program_intpin((struct ioapic_intsrc *)isrc);
+ for (i = 0; i < io->io_numintr; i++)
+ ioapic_program_intpin(&io->io_pins[i]);
}
/*
@@ -727,6 +719,7 @@ ioapic_register(void *cookie)
io->io_intbase + io->io_numintr - 1);
/* Register valid pins as interrupt sources. */
+ intr_register_pic(&io->io_pic);
for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++)
if (pin->io_irq < NUM_IO_INTS)
intr_register_source(&pin->io_intsrc);
diff --git a/sys/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c
index 3fb31b5..a38d43c 100644
--- a/sys/amd64/amd64/local_apic.c
+++ b/sys/amd64/amd64/local_apic.c
@@ -151,12 +151,15 @@ volatile lapic_t *lapic;
static u_long lapic_timer_divisor, lapic_timer_period, lapic_timer_hz;
static void lapic_enable(void);
+static void lapic_resume(struct pic *pic);
static void lapic_timer_enable_intr(void);
static void lapic_timer_oneshot(u_int count);
static void lapic_timer_periodic(u_int count);
static void lapic_timer_set_divisor(u_int divisor);
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
+struct pic lapic_pic = { .pic_resume = lapic_resume };
+
static uint32_t
lvt_mode(struct lapic *la, u_int pin, uint32_t value)
{
@@ -277,7 +280,7 @@ lapic_dump(const char* str)
}
void
-lapic_setup(void)
+lapic_setup(int boot)
{
struct lapic *la;
u_int32_t maxlvt;
@@ -306,9 +309,13 @@ lapic_setup(void)
/* Program timer LVT and setup handler. */
lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
- snprintf(buf, sizeof(buf), "cpu%d: timer", PCPU_GET(cpuid));
- intrcnt_add(buf, &la->la_timer_count);
- if (PCPU_GET(cpuid) != 0) {
+ if (boot) {
+ snprintf(buf, sizeof(buf), "cpu%d: timer", PCPU_GET(cpuid));
+ intrcnt_add(buf, &la->la_timer_count);
+ }
+
+ /* We don't setup the timer during boot on the BSP until later. */
+ if (!(boot && PCPU_GET(cpuid) == 0)) {
KASSERT(lapic_timer_period != 0, ("lapic%u: zero divisor",
lapic_id()));
lapic_timer_set_divisor(lapic_timer_divisor);
@@ -398,6 +405,14 @@ lapic_enable(void)
lapic->svr = value;
}
+/* Reset the local APIC on the BSP during resume. */
+static void
+lapic_resume(struct pic *pic)
+{
+
+ lapic_setup(0);
+}
+
int
lapic_id(void)
{
@@ -983,7 +998,8 @@ apic_setup_io(void *dummy __unused)
* Finish setting up the local APIC on the BSP once we know how to
* properly program the LINT pins.
*/
- lapic_setup();
+ lapic_setup(1);
+ intr_register_pic(&lapic_pic);
if (bootverbose)
lapic_dump("BSP");
}
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index bdbeeb6..6be2c82 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1212,19 +1212,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
atpic_startup();
#else
/* Reset and mask the atpics and leave them shut down. */
- outb(IO_ICU1, ICW1_RESET | ICW1_IC4);
- outb(IO_ICU1 + ICU_IMR_OFFSET, IDT_IO_INTS);
- outb(IO_ICU1 + ICU_IMR_OFFSET, 1 << 2);
- outb(IO_ICU1 + ICU_IMR_OFFSET, ICW4_8086);
- outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff);
- outb(IO_ICU1, OCW3_SEL | OCW3_RR);
-
- outb(IO_ICU2, ICW1_RESET | ICW1_IC4);
- outb(IO_ICU2 + ICU_IMR_OFFSET, IDT_IO_INTS + 8);
- outb(IO_ICU2 + ICU_IMR_OFFSET, 2);
- outb(IO_ICU2 + ICU_IMR_OFFSET, ICW4_8086);
- outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff);
- outb(IO_ICU2, OCW3_SEL | OCW3_RR);
+ atpic_reset();
/*
* Point the ICU spurious interrupt vectors at the APIC spurious
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 2172c17..dbd1e44 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -543,7 +543,7 @@ init_secondary(void)
mtx_lock_spin(&ap_boot_mtx);
/* Init local apic for irq's */
- lapic_setup();
+ lapic_setup(1);
/* Set memory range attributes for this CPU to match the BSP */
mem_range_AP_init();
diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h
index 98cf3a3..ebd8f04 100644
--- a/sys/amd64/include/apicvar.h
+++ b/sys/amd64/include/apicvar.h
@@ -211,7 +211,7 @@ int lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
enum intr_trigger trigger);
void lapic_set_tpr(u_int vector);
-void lapic_setup(void);
+void lapic_setup(int boot);
int lapic_setup_clock(void);
#endif /* !LOCORE */
diff --git a/sys/amd64/include/intr_machdep.h b/sys/amd64/include/intr_machdep.h
index 886811c..5043774 100644
--- a/sys/amd64/include/intr_machdep.h
+++ b/sys/amd64/include/intr_machdep.h
@@ -81,11 +81,12 @@ struct pic {
void (*pic_enable_intr)(struct intsrc *);
int (*pic_vector)(struct intsrc *);
int (*pic_source_pending)(struct intsrc *);
- void (*pic_suspend)(struct intsrc *);
- void (*pic_resume)(struct intsrc *);
+ void (*pic_suspend)(struct pic *);
+ void (*pic_resume)(struct pic *);
int (*pic_config_intr)(struct intsrc *, enum intr_trigger,
enum intr_polarity);
void (*pic_assign_cpu)(struct intsrc *, u_int apic_id);
+ STAILQ_ENTRY(pic) pics;
};
/* Flags for pic_disable_source() */
@@ -114,6 +115,9 @@ struct trapframe;
extern struct mtx icu_lock;
extern int elcr_found;
+#ifndef DEV_ATPIC
+void atpic_reset(void);
+#endif
/* XXX: The elcr_* prototypes probably belong somewhere else. */
int elcr_probe(void);
enum intr_trigger elcr_read_trigger(u_int irq);
@@ -130,6 +134,7 @@ int intr_config_intr(int vector, enum intr_trigger trig,
enum intr_polarity pol);
void intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame);
struct intsrc *intr_lookup_source(int vector);
+int intr_register_pic(struct pic *pic);
int intr_register_source(struct intsrc *isrc);
int intr_remove_handler(void *cookie);
void intr_resume(void);
diff --git a/sys/amd64/isa/atpic.c b/sys/amd64/isa/atpic.c
index 1398e47..1115c92 100644
--- a/sys/amd64/isa/atpic.c
+++ b/sys/amd64/isa/atpic.c
@@ -138,7 +138,7 @@ static void atpic_eoi_master(struct intsrc *isrc);
static void atpic_eoi_slave(struct intsrc *isrc);
static void atpic_enable_intr(struct intsrc *isrc);
static int atpic_vector(struct intsrc *isrc);
-static void atpic_resume(struct intsrc *isrc);
+static void atpic_resume(struct pic *pic);
static int atpic_source_pending(struct intsrc *isrc);
static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
enum intr_polarity pol);
@@ -285,16 +285,13 @@ atpic_source_pending(struct intsrc *isrc)
}
static void
-atpic_resume(struct intsrc *isrc)
+atpic_resume(struct pic *pic)
{
- struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
- struct atpic *ap = (struct atpic *)isrc->is_pic;
+ struct atpic *ap = (struct atpic *)pic;
- if (ai->at_irq == 0) {
- i8259_init(ap, ap == &atpics[SLAVE]);
- if (ap == &atpics[SLAVE] && elcr_found)
- elcr_resume();
- }
+ i8259_init(ap, ap == &atpics[SLAVE]);
+ if (ap == &atpics[SLAVE] && elcr_found)
+ elcr_resume();
}
static int
@@ -465,6 +462,14 @@ atpic_init(void *dummy __unused)
int i;
/*
+ * Register our PICs, even if we aren't going to use any of their
+ * pins so that they are suspended and resumed.
+ */
+ if (intr_register_pic(&atpics[0].at_pic) != 0 ||
+ intr_register_pic(&atpics[1].at_pic) != 0)
+ panic("Unable to register ATPICs");
+
+ /*
* If any of the ISA IRQs have an interrupt source already, then
* assume that the APICs are being used and don't register any
* of our interrupt sources. This makes sure we don't accidentally
diff --git a/sys/i386/i386/intr_machdep.c b/sys/i386/i386/intr_machdep.c
index fe41cc6..da94c69 100644
--- a/sys/i386/i386/intr_machdep.c
+++ b/sys/i386/i386/intr_machdep.c
@@ -62,6 +62,7 @@ typedef void (*mask_fn)(void *);
static int intrcnt_index;
static struct intsrc *interrupt_sources[NUM_IO_INTS];
static struct mtx intr_table_lock;
+static STAILQ_HEAD(, pic) pics;
#ifdef SMP
static int assign_cpu;
@@ -70,10 +71,45 @@ static void intr_assign_next_cpu(struct intsrc *isrc);
#endif
static void intr_init(void *__dummy);
+static int intr_pic_registered(struct pic *pic);
static void intrcnt_setname(const char *name, int index);
static void intrcnt_updatename(struct intsrc *is);
static void intrcnt_register(struct intsrc *is);
+static int
+intr_pic_registered(struct pic *pic)
+{
+ struct pic *p;
+
+ STAILQ_FOREACH(p, &pics, pics) {
+ if (p == pic)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Register a new interrupt controller (PIC). This is to support suspend
+ * and resume where we suspend/resume controllers rather than individual
+ * sources. This also allows controllers with no active sources (such as
+ * 8259As in a system using the APICs) to participate in suspend and resume.
+ */
+int
+intr_register_pic(struct pic *pic)
+{
+ int error;
+
+ mtx_lock_spin(&intr_table_lock);
+ if (intr_pic_registered(pic))
+ error = EBUSY;
+ else {
+ STAILQ_INSERT_TAIL(&pics, pic, pics);
+ error = 0;
+ }
+ mtx_unlock_spin(&intr_table_lock);
+ return (error);
+}
+
/*
* Register a new interrupt source with the global interrupt system.
* The global interrupts need to be disabled when this function is
@@ -84,6 +120,7 @@ intr_register_source(struct intsrc *isrc)
{
int error, vector;
+ KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC"));
vector = isrc->is_pic->pic_vector(isrc);
if (interrupt_sources[vector] != NULL)
return (EEXIST);
@@ -255,26 +292,26 @@ intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
void
intr_resume(void)
{
- struct intsrc **isrc;
- int i;
+ struct pic *pic;
mtx_lock_spin(&intr_table_lock);
- for (i = 0, isrc = interrupt_sources; i < NUM_IO_INTS; i++, isrc++)
- if (*isrc != NULL && (*isrc)->is_pic->pic_resume != NULL)
- (*isrc)->is_pic->pic_resume(*isrc);
+ STAILQ_FOREACH(pic, &pics, pics) {
+ if (pic->pic_resume != NULL)
+ pic->pic_resume(pic);
+ }
mtx_unlock_spin(&intr_table_lock);
}
void
intr_suspend(void)
{
- struct intsrc **isrc;
- int i;
+ struct pic *pic;
mtx_lock_spin(&intr_table_lock);
- for (i = 0, isrc = interrupt_sources; i < NUM_IO_INTS; i++, isrc++)
- if (*isrc != NULL && (*isrc)->is_pic->pic_suspend != NULL)
- (*isrc)->is_pic->pic_suspend(*isrc);
+ STAILQ_FOREACH(pic, &pics, pics) {
+ if (pic->pic_suspend != NULL)
+ pic->pic_suspend(pic);
+ }
mtx_unlock_spin(&intr_table_lock);
}
@@ -327,6 +364,7 @@ intr_init(void *dummy __unused)
intrcnt_setname("???", 0);
intrcnt_index = 1;
+ STAILQ_INIT(&pics);
mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
}
SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL)
diff --git a/sys/i386/i386/io_apic.c b/sys/i386/i386/io_apic.c
index 30c2234..3a893cd 100644
--- a/sys/i386/i386/io_apic.c
+++ b/sys/i386/i386/io_apic.c
@@ -60,8 +60,6 @@ __FBSDID("$FreeBSD$");
#define IRQ_SMI (NUM_IO_INTS + 3)
#define IRQ_DISABLED (NUM_IO_INTS + 4)
-#define TODO printf("%s: not implemented!\n", __func__)
-
static MALLOC_DEFINE(M_IOAPIC, "io_apic", "I/O APIC structures");
/*
@@ -114,8 +112,7 @@ static int ioapic_vector(struct intsrc *isrc);
static int ioapic_source_pending(struct intsrc *isrc);
static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
enum intr_polarity pol);
-static void ioapic_suspend(struct intsrc *isrc);
-static void ioapic_resume(struct intsrc *isrc);
+static void ioapic_resume(struct pic *pic);
static void ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id);
static void ioapic_program_intpin(struct ioapic_intsrc *intpin);
@@ -123,7 +120,7 @@ static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
ioapic_eoi_source, ioapic_enable_intr,
ioapic_vector, ioapic_source_pending,
- ioapic_suspend, ioapic_resume,
+ NULL, ioapic_resume,
ioapic_config_intr, ioapic_assign_cpu };
static int next_ioapic_base;
@@ -418,17 +415,13 @@ ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
}
static void
-ioapic_suspend(struct intsrc *isrc)
-{
-
- TODO;
-}
-
-static void
-ioapic_resume(struct intsrc *isrc)
+ioapic_resume(struct pic *pic)
{
+ struct ioapic *io = (struct ioapic *)pic;
+ int i;
- ioapic_program_intpin((struct ioapic_intsrc *)isrc);
+ for (i = 0; i < io->io_numintr; i++)
+ ioapic_program_intpin(&io->io_pins[i]);
}
/*
@@ -726,6 +719,7 @@ ioapic_register(void *cookie)
io->io_intbase + io->io_numintr - 1);
/* Register valid pins as interrupt sources. */
+ intr_register_pic(&io->io_pic);
for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++)
if (pin->io_irq < NUM_IO_INTS)
intr_register_source(&pin->io_intsrc);
diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c
index 8c9b085..596f236 100644
--- a/sys/i386/i386/local_apic.c
+++ b/sys/i386/i386/local_apic.c
@@ -151,12 +151,15 @@ volatile lapic_t *lapic;
static u_long lapic_timer_divisor, lapic_timer_period, lapic_timer_hz;
static void lapic_enable(void);
+static void lapic_resume(struct pic *pic);
static void lapic_timer_enable_intr(void);
static void lapic_timer_oneshot(u_int count);
static void lapic_timer_periodic(u_int count);
static void lapic_timer_set_divisor(u_int divisor);
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
+struct pic lapic_pic = { .pic_resume = lapic_resume };
+
static uint32_t
lvt_mode(struct lapic *la, u_int pin, uint32_t value)
{
@@ -279,7 +282,7 @@ lapic_dump(const char* str)
}
void
-lapic_setup(void)
+lapic_setup(int boot)
{
struct lapic *la;
u_int32_t maxlvt;
@@ -308,9 +311,13 @@ lapic_setup(void)
/* Program timer LVT and setup handler. */
lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
- snprintf(buf, sizeof(buf), "cpu%d: timer", PCPU_GET(cpuid));
- intrcnt_add(buf, &la->la_timer_count);
- if (PCPU_GET(cpuid) != 0) {
+ if (boot) {
+ snprintf(buf, sizeof(buf), "cpu%d: timer", PCPU_GET(cpuid));
+ intrcnt_add(buf, &la->la_timer_count);
+ }
+
+ /* We don't setup the timer during boot on the BSP until later. */
+ if (!(boot && PCPU_GET(cpuid) == 0)) {
KASSERT(lapic_timer_period != 0, ("lapic%u: zero divisor",
lapic_id()));
lapic_timer_set_divisor(lapic_timer_divisor);
@@ -400,6 +407,14 @@ lapic_enable(void)
lapic->svr = value;
}
+/* Reset the local APIC on the BSP during resume. */
+static void
+lapic_resume(struct pic *pic)
+{
+
+ lapic_setup(0);
+}
+
int
lapic_id(void)
{
@@ -986,7 +1001,8 @@ apic_setup_io(void *dummy __unused)
* Finish setting up the local APIC on the BSP once we know how to
* properly program the LINT pins.
*/
- lapic_setup();
+ lapic_setup(1);
+ intr_register_pic(&lapic_pic);
if (bootverbose)
lapic_dump("BSP");
}
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 8b88117..1933511 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -594,7 +594,7 @@ init_secondary(void)
mtx_lock_spin(&ap_boot_mtx);
/* Init local apic for irq's */
- lapic_setup();
+ lapic_setup(1);
/* Set memory range attributes for this CPU to match the BSP */
mem_range_AP_init();
diff --git a/sys/i386/include/apicvar.h b/sys/i386/include/apicvar.h
index bca7bb1..99c3028 100644
--- a/sys/i386/include/apicvar.h
+++ b/sys/i386/include/apicvar.h
@@ -210,7 +210,7 @@ int lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
enum intr_trigger trigger);
void lapic_set_tpr(u_int vector);
-void lapic_setup(void);
+void lapic_setup(int boot);
int lapic_setup_clock(void);
#endif /* !LOCORE */
diff --git a/sys/i386/include/intr_machdep.h b/sys/i386/include/intr_machdep.h
index 886811c..4884fd5 100644
--- a/sys/i386/include/intr_machdep.h
+++ b/sys/i386/include/intr_machdep.h
@@ -81,11 +81,12 @@ struct pic {
void (*pic_enable_intr)(struct intsrc *);
int (*pic_vector)(struct intsrc *);
int (*pic_source_pending)(struct intsrc *);
- void (*pic_suspend)(struct intsrc *);
- void (*pic_resume)(struct intsrc *);
+ void (*pic_suspend)(struct pic *);
+ void (*pic_resume)(struct pic *);
int (*pic_config_intr)(struct intsrc *, enum intr_trigger,
enum intr_polarity);
void (*pic_assign_cpu)(struct intsrc *, u_int apic_id);
+ STAILQ_ENTRY(pic) pics;
};
/* Flags for pic_disable_source() */
@@ -130,6 +131,7 @@ int intr_config_intr(int vector, enum intr_trigger trig,
enum intr_polarity pol);
void intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame);
struct intsrc *intr_lookup_source(int vector);
+int intr_register_pic(struct pic *pic);
int intr_register_source(struct intsrc *isrc);
int intr_remove_handler(void *cookie);
void intr_resume(void);
diff --git a/sys/i386/isa/atpic.c b/sys/i386/isa/atpic.c
index c73e253..9dfaf0c 100644
--- a/sys/i386/isa/atpic.c
+++ b/sys/i386/isa/atpic.c
@@ -156,7 +156,7 @@ static void atpic_eoi_master(struct intsrc *isrc);
static void atpic_eoi_slave(struct intsrc *isrc);
static void atpic_enable_intr(struct intsrc *isrc);
static int atpic_vector(struct intsrc *isrc);
-static void atpic_resume(struct intsrc *isrc);
+static void atpic_resume(struct pic *pic);
static int atpic_source_pending(struct intsrc *isrc);
static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
enum intr_polarity pol);
@@ -303,18 +303,15 @@ atpic_source_pending(struct intsrc *isrc)
}
static void
-atpic_resume(struct intsrc *isrc)
+atpic_resume(struct pic *pic)
{
- struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
- struct atpic *ap = (struct atpic *)isrc->is_pic;
+ struct atpic *ap = (struct atpic *)pic;
- if (ai->at_irq == 0) {
- i8259_init(ap, ap == &atpics[SLAVE]);
+ i8259_init(ap, ap == &atpics[SLAVE]);
#ifndef PC98
- if (ap == &atpics[SLAVE] && elcr_found)
- elcr_resume();
+ if (ap == &atpics[SLAVE] && elcr_found)
+ elcr_resume();
#endif
- }
}
static int
@@ -529,6 +526,14 @@ atpic_init(void *dummy __unused)
int i;
/*
+ * Register our PICs, even if we aren't going to use any of their
+ * pins so that they are suspended and resumed.
+ */
+ if (intr_register_pic(&atpics[0].at_pic) != 0 ||
+ intr_register_pic(&atpics[1].at_pic) != 0)
+ panic("Unable to register ATPICs");
+
+ /*
* If any of the ISA IRQs have an interrupt source already, then
* assume that the APICs are being used and don't register any
* of our interrupt sources. This makes sure we don't accidentally
OpenPOWER on IntegriCloud