summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2005-01-21 06:01:20 +0000
committerpeter <peter@FreeBSD.org>2005-01-21 06:01:20 +0000
commit8b5a41aeac62532507fcb39413b9f21bf9ba0166 (patch)
treefa0a4aa072559100211bd1335297a0fc44a50865
parent63c4d6030676332d662005c8750ef471df3e8bfe (diff)
downloadFreeBSD-src-8b5a41aeac62532507fcb39413b9f21bf9ba0166.zip
FreeBSD-src-8b5a41aeac62532507fcb39413b9f21bf9ba0166.tar.gz
JumboMFi386: use bitmapped IPI handler. Update elcr and default mptable
config handler. Tidy up various local apic initialization.
-rw-r--r--sys/amd64/amd64/apic_vector.S23
-rw-r--r--sys/amd64/amd64/intr_machdep.c11
-rw-r--r--sys/amd64/amd64/io_apic.c2
-rw-r--r--sys/amd64/amd64/local_apic.c87
-rw-r--r--sys/amd64/amd64/machdep.c1
-rw-r--r--sys/amd64/amd64/mp_machdep.c101
-rw-r--r--sys/amd64/amd64/mptable.c124
-rw-r--r--sys/amd64/include/apicreg.h5
-rw-r--r--sys/amd64/include/apicvar.h59
-rw-r--r--sys/amd64/include/intr_machdep.h2
-rw-r--r--sys/amd64/include/smp.h7
-rw-r--r--sys/amd64/isa/atpic.c8
-rw-r--r--sys/amd64/isa/elcr.c6
13 files changed, 298 insertions, 138 deletions
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index 75d2372..fc3c63b 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -210,31 +210,16 @@ IDTVEC(invlrng)
*/
.text
SUPERALIGN_TEXT
-IDTVEC(hardclock)
+IDTVEC(ipi_intr_bitmap_handler)
+
PUSH_FRAME
movq lapic, %rdx
movl $0, LA_EOI(%rdx) /* End Of Interrupt to APIC */
-
- call forwarded_hardclock
- MEXITCOUNT
- jmp doreti
-
-/*
- * Forward statclock to another CPU. Pushes a clockframe and calls
- * forwarded_statclock().
- */
- .text
- SUPERALIGN_TEXT
-IDTVEC(statclock)
- PUSH_FRAME
-
- movq lapic, %rdx
- movl $0, LA_EOI(%rdx) /* End Of Interrupt to APIC */
-
+
FAKE_MCOUNT(TF_RIP(%rsp))
- call forwarded_statclock
+ call ipi_bitmap_handler
MEXITCOUNT
jmp doreti
diff --git a/sys/amd64/amd64/intr_machdep.c b/sys/amd64/amd64/intr_machdep.c
index 97a3748..0c5f6af 100644
--- a/sys/amd64/amd64/intr_machdep.c
+++ b/sys/amd64/amd64/intr_machdep.c
@@ -286,6 +286,17 @@ intrcnt_register(struct intsrc *is)
is->is_straycount = &intrcnt[is->is_index + 1];
}
+void
+intrcnt_add(const char *name, u_long **countp)
+{
+
+ mtx_lock_spin(&intr_table_lock);
+ *countp = &intrcnt[intrcnt_index];
+ intrcnt_setname(name, intrcnt_index);
+ intrcnt_index++;
+ mtx_unlock_spin(&intr_table_lock);
+}
+
static void
intr_init(void *dummy __unused)
{
diff --git a/sys/amd64/amd64/io_apic.c b/sys/amd64/amd64/io_apic.c
index 8cc14d3..4db0c22 100644
--- a/sys/amd64/amd64/io_apic.c
+++ b/sys/amd64/amd64/io_apic.c
@@ -424,7 +424,7 @@ ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
* them to be set to active low.
*
* XXX: Should we write to the ELCR if the trigger mode changes for
- * an EISA IRQ?
+ * an EISA IRQ or an ISA IRQ with the ELCR present?
*/
if (intpin->io_bus == APIC_BUS_EISA)
pol = INTR_POLARITY_HIGH;
diff --git a/sys/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c
index 5e8d8b1..804a2de 100644
--- a/sys/amd64/amd64/local_apic.c
+++ b/sys/amd64/amd64/local_apic.c
@@ -61,7 +61,9 @@ __FBSDID("$FreeBSD$");
#define MAX_APICID 16
/* Sanity checks on IDT vectors. */
-CTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS <= APIC_LOCAL_INTS);
+CTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS == APIC_TIMER_INT);
+CTASSERT(APIC_TIMER_INT < APIC_LOCAL_INTS);
+CTASSERT(APIC_LOCAL_INTS == 240);
CTASSERT(IPI_STOP < APIC_SPURIOUS_INT);
/*
@@ -96,10 +98,10 @@ struct lapic {
static struct lvt lvts[LVT_MAX + 1] = {
{ 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 }, /* LINT0: masked ExtINT */
{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* LINT1: NMI */
- { 1, 1, 1, 1, APIC_LVT_DM_FIXED, 0 }, /* Timer: needs a vector */
- { 1, 1, 1, 1, APIC_LVT_DM_FIXED, 0 }, /* Error: needs a vector */
+ { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT }, /* Timer */
+ { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, 0 }, /* PMC */
- { 1, 1, 1, 1, APIC_LVT_DM_FIXED, 0 }, /* Thermal: needs a vector */
+ { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT }, /* Thermal */
};
static inthand_t *ioint_handlers[] = {
@@ -115,6 +117,9 @@ static inthand_t *ioint_handlers[] = {
volatile lapic_t *lapic;
+static void lapic_enable(void);
+static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
+
static uint32_t
lvt_mode(struct lapic *la, u_int pin, uint32_t value)
{
@@ -148,11 +153,7 @@ lvt_mode(struct lapic *la, u_int pin, uint32_t value)
/* Use a vector of 0. */
break;
case APIC_LVT_DM_FIXED:
-#if 0
value |= lvt->lvt_vector;
-#else
- panic("Fixed LINT pins not supported");
-#endif
break;
default:
panic("bad APIC LVT delivery mode: %#x\n", value);
@@ -166,7 +167,6 @@ lvt_mode(struct lapic *la, u_int pin, uint32_t value)
void
lapic_init(uintptr_t addr)
{
- u_int32_t value;
/* Map the local APIC and setup the spurious interrupt handler. */
KASSERT(trunc_page(addr) == addr,
@@ -175,10 +175,7 @@ lapic_init(uintptr_t addr)
setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_SYSIGT, SEL_KPL, 0);
/* Perform basic initialization of the BSP's local APIC. */
- value = lapic->svr;
- value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS);
- value |= (APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT);
- lapic->svr = value;
+ lapic_enable();
/* Set BSP's per-CPU local APIC ID. */
PCPU_SET(apic_id, lapic_id());
@@ -231,6 +228,9 @@ lapic_dump(const char* str)
lapic->id, lapic->version, lapic->ldr, lapic->dfr);
printf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr);
+ printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pcm: 0x%08x\n",
+ lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error,
+ lapic->lvt_pcint);
}
void
@@ -257,16 +257,8 @@ lapic_setup(void)
eflags = intr_disable();
maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
- /* Program LINT[01] LVT entries. */
- lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
- lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);
-
- /* XXX: more LVT entries */
-
- /* Clear the TPR. */
- value = lapic->tpr;
- value &= ~APIC_TPR_PRIO;
- lapic->tpr = value;
+ /* Initialize the TPR to allow all interrupts. */
+ lapic_set_tpr(0);
/* Use the cluster model for logical IDs. */
value = lapic->dfr;
@@ -282,10 +274,14 @@ lapic_setup(void)
lapic->ldr = value;
/* Setup spurious vector and enable the local APIC. */
- value = lapic->svr;
- value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS);
- value |= (APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT);
- lapic->svr = value;
+ lapic_enable();
+
+ /* Program LINT[01] LVT entries. */
+ lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
+ lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);
+
+ /* XXX: more LVT entries */
+
intr_restore(eflags);
}
@@ -300,6 +296,18 @@ lapic_disable(void)
lapic->svr = value;
}
+static void
+lapic_enable(void)
+{
+ u_int32_t value;
+
+ /* Program the spurious vector to enable the local APIC. */
+ value = lapic->svr;
+ value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS);
+ value |= (APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT);
+ lapic->svr = value;
+}
+
int
lapic_id(void)
{
@@ -441,7 +449,7 @@ lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
printf("lapic%u:", apic_id);
}
if (bootverbose)
- printf(" LINT%u polarity: active-%s\n", pin,
+ printf(" LINT%u polarity: %s\n", pin,
pol == INTR_POLARITY_HIGH ? "high" : "low");
return (0);
}
@@ -471,6 +479,24 @@ lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger)
return (0);
}
+/*
+ * Adjust the TPR of the current CPU so that it blocks all interrupts below
+ * the passed in vector.
+ */
+void
+lapic_set_tpr(u_int vector)
+{
+#ifdef CHEAP_TPR
+ lapic->tpr = vector;
+#else
+ u_int32_t tpr;
+
+ tpr = lapic->tpr & ~APIC_TPR_PRIO;
+ tpr |= vector;
+ lapic->tpr = tpr;
+#endif
+}
+
void
lapic_eoi(void)
{
@@ -637,10 +663,9 @@ SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_SECOND, apic_setup_io, NULL)
#ifdef SMP
/*
* Inter Processor Interrupt functions. The lapic_ipi_*() functions are
- * private the sys/i386 code. The public interface for the rest of the
+ * private to the sys/i386 code. The public interface for the rest of the
* kernel is defined in mp_machdep.c.
*/
-
int
lapic_ipi_wait(int delay)
{
@@ -745,7 +770,7 @@ lapic_ipi_vectored(u_int vector, int dest)
* the failure with the check above when the next IPI is
* sent.
*
- * We could skiip this wait entirely, EXCEPT it probably
+ * We could skip this wait entirely, EXCEPT it probably
* protects us from other routines that assume that the
* message was delivered and acted upon when this function
* returns.
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index a1ccaf0..16157c1 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1213,6 +1213,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
cninit();
#ifdef DEV_ATPIC
+ elcr_probe();
atpic_startup();
#endif
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 58848a6..cff60ec 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -131,6 +131,9 @@ struct cpu_info {
} static cpu_info[MAXCPU];
static int cpu_apic_ids[MAXCPU];
+/* Holds pending bitmap based IPIs per CPU */
+static volatile u_int cpu_ipi_pending[MAXCPU];
+
static u_int boot_address;
static void set_logical_apic_ids(void);
@@ -296,25 +299,22 @@ cpu_mp_start(void)
int i;
/* Initialize the logical ID to APIC ID table. */
- for (i = 0; i < MAXCPU; i++)
+ for (i = 0; i < MAXCPU; i++) {
cpu_apic_ids[i] = -1;
+ cpu_ipi_pending[i] = 0;
+ }
/* Install an inter-CPU IPI for TLB invalidation */
setidt(IPI_INVLTLB, IDTVEC(invltlb), SDT_SYSIGT, SEL_KPL, 0);
setidt(IPI_INVLPG, IDTVEC(invlpg), SDT_SYSIGT, SEL_KPL, 0);
setidt(IPI_INVLRNG, IDTVEC(invlrng), SDT_SYSIGT, SEL_KPL, 0);
-
- /* Install an inter-CPU IPI for forwarding hardclock() */
- setidt(IPI_HARDCLOCK, IDTVEC(hardclock), SDT_SYSIGT, SEL_KPL, 0);
-
- /* Install an inter-CPU IPI for forwarding statclock() */
- setidt(IPI_STATCLOCK, IDTVEC(statclock), SDT_SYSIGT, SEL_KPL, 0);
/* Install an inter-CPU IPI for all-CPU rendezvous */
setidt(IPI_RENDEZVOUS, IDTVEC(rendezvous), SDT_SYSIGT, SEL_KPL, 0);
- /* Install an inter-CPU IPI for forcing an additional software trap */
- setidt(IPI_AST, IDTVEC(cpuast), SDT_SYSIGT, SEL_KPL, 0);
+ /* Install generic inter-CPU IPI handler */
+ setidt(IPI_BITMAP_VECTOR, IDTVEC(ipi_intr_bitmap_handler),
+ SDT_SYSIGT, SEL_KPL, 0);
/* Install an inter-CPU IPI for CPU stop/restart */
setidt(IPI_STOP, IDTVEC(cpustop), SDT_SYSIGT, SEL_KPL, 0);
@@ -876,20 +876,6 @@ smp_masked_invlpg_range(u_int mask, vm_offset_t addr1, vm_offset_t addr2)
* For statclock, we send an IPI to all CPU's to have them call this
* function.
*/
-void
-forwarded_statclock(struct clockframe frame)
-{
- struct thread *td;
-
- CTR0(KTR_SMP, "forwarded_statclock");
- td = curthread;
- td->td_intr_nesting_level++;
- if (profprocs != 0)
- profclock(&frame);
- if (pscnt == psdiv)
- statclock(&frame);
- td->td_intr_nesting_level--;
-}
void
forward_statclock(void)
@@ -913,17 +899,6 @@ forward_statclock(void)
* state and call hardclock_process() on the CPU receiving the clock interrupt
* and then just use a simple IPI to handle any ast's if needed.
*/
-void
-forwarded_hardclock(struct clockframe frame)
-{
- struct thread *td;
-
- CTR0(KTR_SMP, "forwarded_hardclock");
- td = curthread;
- td->td_intr_nesting_level++;
- hardclock_process(&frame);
- td->td_intr_nesting_level--;
-}
void
forward_hardclock(void)
@@ -940,6 +915,41 @@ forward_hardclock(void)
ipi_selected(map, IPI_HARDCLOCK);
}
+void
+ipi_bitmap_handler(struct clockframe frame)
+{
+ int cpu = PCPU_GET(cpuid);
+ u_int ipi_bitmap;
+ struct thread *td;
+
+ ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]);
+
+ critical_enter();
+
+ /* Nothing to do for AST */
+
+ if (ipi_bitmap & (1 << IPI_HARDCLOCK)) {
+ td = curthread;
+ td->td_intr_nesting_level++;
+ hardclock_process(&frame);
+ td->td_intr_nesting_level--;
+ }
+
+ if (ipi_bitmap & (1 << IPI_STATCLOCK)) {
+ CTR0(KTR_SMP, "forwarded_statclock");
+
+ td = curthread;
+ td->td_intr_nesting_level++;
+ if (profprocs != 0)
+ profclock(&frame);
+ if (pscnt == psdiv)
+ statclock(&frame);
+ td->td_intr_nesting_level--;
+ }
+
+ critical_exit();
+}
+
/*
* send an IPI to a set of cpus.
*/
@@ -947,15 +957,36 @@ void
ipi_selected(u_int32_t cpus, u_int ipi)
{
int cpu;
+ u_int bitmap = 0;
+ u_int old_pending;
+ u_int new_pending;
+
+ if (IPI_IS_BITMAPED(ipi)) {
+ bitmap = 1 << ipi;
+ ipi = IPI_BITMAP_VECTOR;
+ }
CTR3(KTR_SMP, "%s: cpus: %x ipi: %x", __func__, cpus, ipi);
while ((cpu = ffs(cpus)) != 0) {
cpu--;
+ cpus &= ~(1 << cpu);
+
KASSERT(cpu_apic_ids[cpu] != -1,
("IPI to non-existent CPU %d", cpu));
+
+ if (bitmap) {
+ do {
+ old_pending = cpu_ipi_pending[cpu];
+ new_pending = old_pending | bitmap;
+ } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu],old_pending, new_pending));
+
+ if (old_pending)
+ continue;
+ }
+
lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
- cpus &= ~(1 << cpu);
}
+
}
/*
diff --git a/sys/amd64/amd64/mptable.c b/sys/amd64/amd64/mptable.c
index 38088a1..bd1db37 100644
--- a/sys/amd64/amd64/mptable.c
+++ b/sys/amd64/amd64/mptable.c
@@ -157,6 +157,7 @@ static void mptable_hyperthread_fixup(u_int id_mask);
static void mptable_parse_apics_and_busses(void);
static void mptable_parse_apics_and_busses_handler(u_char *entry,
void *arg);
+static void mptable_parse_default_config_ints(void);
static void mptable_parse_ints(void);
static void mptable_parse_ints_handler(u_char *entry, void *arg);
static void mptable_parse_io_int(int_entry_ptr intr);
@@ -246,9 +247,19 @@ found:
mpfps = (mpfps_t)(KERNBASE + x);
/* Map in the configuration table if it exists. */
- if (mpfps->config_type != 0)
+ if (mpfps->config_type != 0) {
+ if (bootverbose)
+ printf(
+ "MP Table version 1.%d found using Default Configuration %d\n",
+ mpfps->spec_rev, mpfps->config_type);
+ if (mpfps->config_type != 5 && mpfps->config_type != 6) {
+ printf(
+ "MP Table Default Configuration %d is unsupported\n",
+ mpfps->config_type);
+ return (ENXIO);
+ }
mpct = NULL;
- else {
+ } else {
if ((uintptr_t)mpfps->pap >= 1024 * 1024) {
printf("%s: Unable to map MP Configuration Table\n",
__func__);
@@ -310,7 +321,7 @@ mptable_setup_local(void)
printf("MPTable: <");
if (mpfps->config_type != 0) {
lapic_init(DEFAULT_APIC_BASE);
- printf("Preset Config %d", mpfps->config_type);
+ printf("Default Configuration %d", mpfps->config_type);
} else {
lapic_init((uintptr_t)mpct->apic_address);
printf("%.*s %.*s", (int)sizeof(mpct->oem_id), mpct->oem_id,
@@ -521,13 +532,13 @@ mptable_parse_apics_and_busses(void)
/* Is this a pre-defined config? */
if (mpfps->config_type != 0) {
- ioapics[0] = ioapic_create(DEFAULT_IO_APIC_BASE, 2, 0);
+ ioapics[2] = ioapic_create(DEFAULT_IO_APIC_BASE, 2, 0);
busses[0].bus_id = 0;
- busses[0].bus_type = default_data[mpfps->config_type][2];
+ busses[0].bus_type = default_data[mpfps->config_type - 1][2];
if (mptable_nbusses > 1) {
busses[1].bus_id = 1;
busses[1].bus_type =
- default_data[mpfps->config_type][4];
+ default_data[mpfps->config_type - 1][4];
}
} else
mptable_walk_table(mptable_parse_apics_and_busses_handler,
@@ -564,11 +575,15 @@ conforming_trigger(u_char src_bus, u_char src_bus_irq)
KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus));
switch (busses[src_bus].bus_type) {
case ISA:
- return (INTR_TRIGGER_EDGE);
+ if (elcr_found)
+ return (elcr_read_trigger(src_bus_irq));
+ else
+ return (INTR_TRIGGER_EDGE);
case PCI:
return (INTR_TRIGGER_LEVEL);
case EISA:
KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq));
+ KASSERT(elcr_found, ("Missing ELCR"));
return (elcr_read_trigger(src_bus_irq));
default:
panic("%s: unknown bus type %d", __func__,
@@ -617,23 +632,38 @@ static void
mptable_parse_io_int(int_entry_ptr intr)
{
void *ioapic;
- u_int pin;
+ u_int pin, apic_id;
+ apic_id = intr->dst_apic_id;
if (intr->dst_apic_id == 0xff) {
- printf("MPTable: Ignoring global interrupt entry for pin %d\n",
- intr->dst_apic_int);
- return;
+ /*
+ * An APIC ID of 0xff means that the interrupt is connected
+ * to the specified pin on all I/O APICs in the system. If
+ * there is only one I/O APIC, then use that APIC to route
+ * the interrupts. If there is more than one I/O APIC, then
+ * punt.
+ */
+ if (mptable_nioapics == 1) {
+ apic_id = 0;
+ while (ioapics[apic_id] == NULL)
+ apic_id++;
+ } else {
+ printf(
+ "MPTable: Ignoring global interrupt entry for pin %d\n",
+ intr->dst_apic_int);
+ return;
+ }
}
- if (intr->dst_apic_id >= NAPICID) {
+ if (apic_id >= NAPICID) {
printf("MPTable: Ignoring interrupt entry for ioapic%d\n",
intr->dst_apic_id);
return;
}
- ioapic = ioapics[intr->dst_apic_id];
+ ioapic = ioapics[apic_id];
if (ioapic == NULL) {
printf(
"MPTable: Ignoring interrupt entry for missing ioapic%d\n",
- intr->dst_apic_id);
+ apic_id);
return;
}
pin = intr->dst_apic_int;
@@ -753,7 +783,58 @@ mptable_parse_ints_handler(u_char *entry, void *arg __unused)
break;
}
}
-
+
+/*
+ * Configure interrupt pins for a default configuration. For details see
+ * Table 5-2 in Section 5 of the MP Table specification.
+ */
+static void
+mptable_parse_default_config_ints(void)
+{
+ struct INTENTRY entry;
+ int pin;
+
+ /*
+ * All default configs route IRQs from bus 0 to the first 16 pins
+ * of the first I/O APIC with an APIC ID of 2.
+ */
+ entry.type = MPCT_ENTRY_INT;
+ entry.int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
+ INTENTRY_FLAGS_TRIGGER_CONFORM;
+ entry.src_bus_id = 0;
+ entry.dst_apic_id = 2;
+
+ /* Run through all 16 pins. */
+ for (pin = 0; pin < 16; pin++) {
+ entry.dst_apic_int = pin;
+ switch (pin) {
+ case 0:
+ /* Pin 0 is an ExtINT pin. */
+ entry.int_type = INTENTRY_TYPE_EXTINT;
+ break;
+ case 2:
+ /* IRQ 0 is routed to pin 2. */
+ entry.int_type = INTENTRY_TYPE_INT;
+ entry.src_bus_irq = 0;
+ break;
+ default:
+ /* All other pins are identity mapped. */
+ entry.int_type = INTENTRY_TYPE_INT;
+ entry.src_bus_irq = pin;
+ break;
+ }
+ mptable_parse_io_int(&entry);
+ }
+
+ /* Certain configs disable certain pins. */
+ if (mpfps->config_type == 7)
+ ioapic_disable_pin(ioapics[2], 0);
+ if (mpfps->config_type == 2) {
+ ioapic_disable_pin(ioapics[2], 2);
+ ioapic_disable_pin(ioapics[2], 13);
+ }
+}
+
/*
* Configure the interrupt pins
*/
@@ -768,16 +849,7 @@ mptable_parse_ints(void)
lapic_set_lvt_mode(APIC_ID_ALL, LVT_LINT1, APIC_LVT_DM_NMI);
/* Configure I/O APIC pins. */
- if (mpfps->config_type != 7)
- ioapic_set_extint(ioapics[0], 0);
- else
- ioapic_disable_pin(ioapics[0], 0);
- if (mpfps->config_type != 2)
- ioapic_remap_vector(ioapics[0], 2, 0);
- else
- ioapic_disable_pin(ioapics[0], 2);
- if (mpfps->config_type == 2)
- ioapic_disable_pin(ioapics[0], 13);
+ mptable_parse_default_config_ints();
} else
mptable_walk_table(mptable_parse_ints_handler, NULL);
}
@@ -887,7 +959,7 @@ mptable_pci_probe_table(int bus)
if (bus < 0)
return (EINVAL);
- if (pci0 == -1 || pci0 + bus > mptable_maxbusid)
+ if (mpct == NULL || pci0 == -1 || pci0 + bus > mptable_maxbusid)
return (ENXIO);
if (busses[pci0 + bus].bus_type != PCI)
return (ENXIO);
diff --git a/sys/amd64/include/apicreg.h b/sys/amd64/include/apicreg.h
index c451b71..d5d5dc3 100644
--- a/sys/amd64/include/apicreg.h
+++ b/sys/amd64/include/apicreg.h
@@ -330,8 +330,13 @@ typedef struct IOAPIC ioapic_t;
#define APIC_LVTT_DS 0x00001000
#define APIC_LVTT_M 0x00010000
#define APIC_LVTT_TM 0x00020000
+# define APIC_LVTT_TM_ONE_SHOT 0x00000000
+# define APIC_LVTT_TM_PERIODIC 0x00020000
+/* APIC timer current count */
+#define APIC_TIMER_MAX_COUNT 0xffffffff
+
/* fields in TDCR */
#define APIC_TDCR_2 0x00
#define APIC_TDCR_4 0x01
diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h
index e6804d7..313aea6 100644
--- a/sys/amd64/include/apicvar.h
+++ b/sys/amd64/include/apicvar.h
@@ -44,7 +44,7 @@
* 0xff (255) +-------------+
* | | 15 (Spurious / IPIs / Local Interrupts)
* 0xf0 (240) +-------------+
- * | | 14 (I/O Interrupts)
+ * | | 14 (I/O Interrupts / Timer)
* 0xe0 (224) +-------------+
* | | 13 (I/O Interrupts)
* 0xd0 (208) +-------------+
@@ -80,24 +80,60 @@
*/
#define APIC_ID_ALL 0xff
+
+/* I/O Interrupts are used for external devices such as ISA, PCI, etc. */
#define APIC_IO_INTS (IDT_IO_INTS + 16)
-#define APIC_NUM_IOINTS 192
+#define APIC_NUM_IOINTS 191
+
+/* The timer interrupt is used for clock handling and drives hardclock, etc. */
+#define APIC_TIMER_INT (APIC_IO_INTS + APIC_NUM_IOINTS)
+
+/*
+ ********************* !!! WARNING !!! ******************************
+ * Each local apic has an interrupt receive fifo that is two entries deep
+ * for each interrupt priority class (higher 4 bits of interrupt vector).
+ * Once the fifo is full the APIC can no longer receive interrupts for this
+ * class and sending IPIs from other CPUs will be blocked.
+ * To avoid deadlocks there should be no more than two IPI interrupts
+ * pending at the same time.
+ * Currently this is guaranteed by dividing the IPIs in two groups that have
+ * each at most one IPI interrupt pending. The first group is protected by the
+ * smp_ipi_mtx and waits for the completion of the IPI (Only one IPI user
+ * at a time) The second group uses a single interrupt and a bitmap to avoid
+ * redundant IPI interrupts.
+ *
+ * Right now IPI_STOP used by kdb shares the interrupt priority class with
+ * the two IPI groups mentioned above. As such IPI_STOP may cause a deadlock.
+ * Eventually IPI_STOP should use NMI IPIs - this would eliminate this and
+ * other deadlocks caused by IPI_STOP.
+ */
+/* Interrupts for local APIC LVT entries other than the timer. */
#define APIC_LOCAL_INTS 240
-#define APIC_TIMER_INT APIC_LOCAL_INTS
-#define APIC_ERROR_INT (APIC_LOCAL_INTS + 1)
-#define APIC_THERMAL_INT (APIC_LOCAL_INTS + 2)
+#define APIC_ERROR_INT APIC_LOCAL_INTS
+#define APIC_THERMAL_INT (APIC_LOCAL_INTS + 1)
-#define APIC_IPI_INTS (APIC_LOCAL_INTS + 3)
-#define IPI_AST APIC_IPI_INTS /* Generate software trap. */
+#define APIC_IPI_INTS (APIC_LOCAL_INTS + 2)
+#define IPI_RENDEZVOUS (APIC_IPI_INTS) /* Inter-CPU rendezvous. */
#define IPI_INVLTLB (APIC_IPI_INTS + 1) /* TLB Shootdown IPIs */
#define IPI_INVLPG (APIC_IPI_INTS + 2)
#define IPI_INVLRNG (APIC_IPI_INTS + 3)
-#define IPI_HARDCLOCK (APIC_IPI_INTS + 8) /* Inter-CPU clock handling. */
-#define IPI_STATCLOCK (APIC_IPI_INTS + 9)
-#define IPI_RENDEZVOUS (APIC_IPI_INTS + 10) /* Inter-CPU rendezvous. */
-#define IPI_STOP (APIC_IPI_INTS + 11) /* Stop CPU until restarted. */
+/* Vector to handle bitmap based IPIs */
+#define IPI_BITMAP_VECTOR (APIC_IPI_INTS + 5)
+
+/* IPIs handled by IPI_BITMAPED_VECTOR (XXX ups is there a better place?) */
+#define IPI_AST 0 /* Generate software trap. */
+#define IPI_HARDCLOCK 1 /* Inter-CPU clock handling. */
+#define IPI_STATCLOCK 2
+#define IPI_BITMAP_LAST IPI_STATCLOCK
+#define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST)
+#define IPI_STOP (APIC_IPI_INTS + 6) /* Stop CPU until restarted. */
+
+/*
+ * The spurious interrupt can share the priority class with the IPIs since
+ * it is not a normal interrupt. (Does not use the APIC's interrupt fifo)
+ */
#define APIC_SPURIOUS_INT 255
#define LVT_LINT0 0
@@ -174,6 +210,7 @@ int lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
enum intr_polarity pol);
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);
#endif /* !LOCORE */
diff --git a/sys/amd64/include/intr_machdep.h b/sys/amd64/include/intr_machdep.h
index af9e672..ff19346 100644
--- a/sys/amd64/include/intr_machdep.h
+++ b/sys/amd64/include/intr_machdep.h
@@ -84,6 +84,7 @@ struct intsrc {
struct intrframe;
extern struct mtx icu_lock;
+extern int elcr_found;
/* XXX: The elcr_* prototypes probably belong somewhere else. */
int elcr_probe(void);
@@ -100,6 +101,7 @@ int intr_register_source(struct intsrc *isrc);
int intr_remove_handler(void *cookie);
void intr_resume(void);
void intr_suspend(void);
+void intrcnt_add(const char *name, u_long **countp);
#endif /* !LOCORE */
#endif /* _KERNEL */
diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h
index 5f510bb..f9057b4 100644
--- a/sys/amd64/include/smp.h
+++ b/sys/amd64/include/smp.h
@@ -40,9 +40,7 @@ inthand_t
IDTVEC(invltlb), /* TLB shootdowns - global */
IDTVEC(invlpg), /* TLB shootdowns - 1 page */
IDTVEC(invlrng), /* TLB shootdowns - page range */
- IDTVEC(hardclock), /* Forward hardclock() */
- IDTVEC(statclock), /* Forward statclock() */
- IDTVEC(cpuast), /* Additional software trap on other cpu */
+ IDTVEC(ipi_intr_bitmap_handler), /* Bitmap based IPIs */
IDTVEC(cpustop), /* CPU stops & waits to be restarted */
IDTVEC(rendezvous); /* handle CPU rendezvous */
@@ -54,9 +52,8 @@ void ipi_all(u_int ipi);
void ipi_all_but_self(u_int ipi);
void ipi_self(u_int ipi);
void forward_statclock(void);
-void forwarded_statclock(struct clockframe frame);
void forward_hardclock(void);
-void forwarded_hardclock(struct clockframe frame);
+void ipi_bitmap_handler(struct clockframe frame);
u_int mp_bootaddress(u_int);
int mp_grab_cpu_hlt(void);
void mp_topology(void);
diff --git a/sys/amd64/isa/atpic.c b/sys/amd64/isa/atpic.c
index 032a803..f6d3fb1 100644
--- a/sys/amd64/isa/atpic.c
+++ b/sys/amd64/isa/atpic.c
@@ -95,7 +95,6 @@ __FBSDID("$FreeBSD$");
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),
@@ -293,7 +292,7 @@ atpic_resume(struct intsrc *isrc)
if (ai->at_irq == 0) {
i8259_init(ap, ap == &atpics[SLAVE]);
- if (ap == &atpics[SLAVE] && using_elcr)
+ if (ap == &atpics[SLAVE] && elcr_found)
elcr_resume();
}
}
@@ -337,7 +336,7 @@ atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
vector);
return (EINVAL);
}
- if (!using_elcr) {
+ if (!elcr_found) {
if (bootverbose)
printf("atpic: No ELCR to configure IRQ%u as %s\n",
vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
@@ -428,8 +427,7 @@ atpic_startup(void)
* assume level trigger for any interrupt that we aren't sure is
* edge triggered.
*/
- if (elcr_probe() == 0) {
- using_elcr = 1;
+ if (elcr_found) {
for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
ai->at_trigger = elcr_read_trigger(i);
} else {
diff --git a/sys/amd64/isa/elcr.c b/sys/amd64/isa/elcr.c
index 2cfcfa4..266d783 100644
--- a/sys/amd64/isa/elcr.c
+++ b/sys/amd64/isa/elcr.c
@@ -57,9 +57,7 @@ __FBSDID("$FreeBSD$");
#define ELCR_MASK(irq) (1 << (irq))
static int elcr_status;
-#ifdef INVARIANTS
-static int elcr_found;
-#endif
+int elcr_found;
/*
* Check to see if we have what looks like a valid ELCR. We do this by
@@ -88,9 +86,7 @@ elcr_probe(void)
}
if (resource_disabled("elcr", 0))
return (ENXIO);
-#ifdef INVARIANTS
elcr_found = 1;
-#endif
return (0);
}
OpenPOWER on IntegriCloud