From 8aad93579025896f709dbf6fcddb19ff74b73640 Mon Sep 17 00:00:00 2001 From: jhb Date: Thu, 23 Dec 2004 19:47:59 +0000 Subject: [PATCH] - Add a function to set the Task Priority Register (TPR) of the local APIC. Currently this is only used to initiailize the TPR to 0 during initial setup. - Reallocate vectors for the local APIC timer, error, and thermal LVT entries. The timer entry is allocated from the top of the I/O interrupt range reducing the number of vectors available for hardware interrupts to 191. Linux happens to use the same exact vector for its timer interrupt as well. If the timer vector shared the same priority queue as the IPI handlers, then the frequency that the timer vector will eventually be firing at can interact badly with the IPIs resulting in the queue filling and the dreaded IPI stuck panics, hence it being located at the top of the previous priority queue instead. - Fixup various minor nits in comments. --- sys/i386/i386/local_apic.c | 33 +++++++++++++++++++++++++-------- sys/i386/include/apicvar.h | 24 ++++++++++++++---------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c index 9c3d97be60d3..f7e5d2836752 100644 --- a/sys/i386/i386/local_apic.c +++ b/sys/i386/i386/local_apic.c @@ -60,7 +60,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); /* @@ -264,10 +266,8 @@ lapic_setup(void) /* 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; @@ -472,6 +472,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 +655,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 +762,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/i386/include/apicvar.h b/sys/i386/include/apicvar.h index a680b0de1098..a0f06ba93db1 100644 --- a/sys/i386/include/apicvar.h +++ b/sys/i386/include/apicvar.h @@ -42,7 +42,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) +-------------+ @@ -78,8 +78,13 @@ */ #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 !!! ****************************** @@ -101,15 +106,12 @@ * other deadlocks caused by IPI_STOP. */ +/* Interrupts for local APIC LVT entries other than the timer. */ #define APIC_LOCAL_INTS 240 +#define APIC_ERROR_INT APIC_LOCAL_INTS +#define APIC_THERMAL_INT (APIC_LOCAL_INTS + 1) -#if 0 -#define APIC_TIMER_INT (APIC_LOCAL_INTS + X) -#define APIC_ERROR_INT (APIC_LOCAL_INTS + X) -#define APIC_THERMAL_INT (APIC_LOCAL_INTS + X) -#endif - -#define APIC_IPI_INTS (APIC_LOCAL_INTS + 0) +#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) @@ -127,7 +129,8 @@ #define IPI_STOP (APIC_IPI_INTS + 6) /* Stop CPU until restarted. */ -/* The spurious interrupt can share the priority class with the IPIs since +/* + * 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 @@ -206,6 +209,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 */