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
This commit is contained in:
parent
4ef33d554a
commit
520ffff83e
@ -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
|
||||
|
@ -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)
|
||||
ioapic_resume(struct pic *pic)
|
||||
{
|
||||
struct ioapic *io = (struct ioapic *)pic;
|
||||
int i;
|
||||
|
||||
TODO;
|
||||
}
|
||||
|
||||
static void
|
||||
ioapic_resume(struct intsrc *isrc)
|
||||
{
|
||||
|
||||
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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
@ -464,6 +461,14 @@ atpic_init(void *dummy __unused)
|
||||
struct atpic_intsrc *ai;
|
||||
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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
ioapic_resume(struct pic *pic)
|
||||
{
|
||||
struct ioapic *io = (struct ioapic *)pic;
|
||||
int i;
|
||||
|
||||
TODO;
|
||||
}
|
||||
|
||||
static void
|
||||
ioapic_resume(struct intsrc *isrc)
|
||||
{
|
||||
|
||||
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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
@ -528,6 +525,14 @@ atpic_init(void *dummy __unused)
|
||||
struct atpic_intsrc *ai;
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user