diff options
author | peter <peter@FreeBSD.org> | 2005-01-21 06:01:20 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2005-01-21 06:01:20 +0000 |
commit | 8b5a41aeac62532507fcb39413b9f21bf9ba0166 (patch) | |
tree | fa0a4aa072559100211bd1335297a0fc44a50865 | |
parent | 63c4d6030676332d662005c8750ef471df3e8bfe (diff) | |
download | FreeBSD-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.S | 23 | ||||
-rw-r--r-- | sys/amd64/amd64/intr_machdep.c | 11 | ||||
-rw-r--r-- | sys/amd64/amd64/io_apic.c | 2 | ||||
-rw-r--r-- | sys/amd64/amd64/local_apic.c | 87 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 1 | ||||
-rw-r--r-- | sys/amd64/amd64/mp_machdep.c | 101 | ||||
-rw-r--r-- | sys/amd64/amd64/mptable.c | 124 | ||||
-rw-r--r-- | sys/amd64/include/apicreg.h | 5 | ||||
-rw-r--r-- | sys/amd64/include/apicvar.h | 59 | ||||
-rw-r--r-- | sys/amd64/include/intr_machdep.h | 2 | ||||
-rw-r--r-- | sys/amd64/include/smp.h | 7 | ||||
-rw-r--r-- | sys/amd64/isa/atpic.c | 8 | ||||
-rw-r--r-- | sys/amd64/isa/elcr.c | 6 |
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); } |