diff options
-rw-r--r-- | sys/amd64/amd64/apic_vector.S | 343 | ||||
-rw-r--r-- | sys/amd64/amd64/mp_machdep.c | 61 | ||||
-rw-r--r-- | sys/amd64/amd64/mptable.c | 61 | ||||
-rw-r--r-- | sys/amd64/include/mptable.h | 61 | ||||
-rw-r--r-- | sys/amd64/include/smp.h | 5 | ||||
-rw-r--r-- | sys/amd64/isa/intr_machdep.c | 38 | ||||
-rw-r--r-- | sys/amd64/isa/intr_machdep.h | 6 | ||||
-rw-r--r-- | sys/amd64/isa/nmi.c | 38 | ||||
-rw-r--r-- | sys/i386/i386/apic_vector.s | 343 | ||||
-rw-r--r-- | sys/i386/i386/mp_apicdefs.s | 7 | ||||
-rw-r--r-- | sys/i386/i386/mp_machdep.c | 61 | ||||
-rw-r--r-- | sys/i386/i386/mptable.c | 61 | ||||
-rw-r--r-- | sys/i386/include/mptable.h | 61 | ||||
-rw-r--r-- | sys/i386/include/smp.h | 5 | ||||
-rw-r--r-- | sys/i386/include/smptests.h | 33 | ||||
-rw-r--r-- | sys/i386/isa/apic_ipl.s | 5 | ||||
-rw-r--r-- | sys/i386/isa/apic_vector.s | 343 | ||||
-rw-r--r-- | sys/i386/isa/intr_machdep.c | 38 | ||||
-rw-r--r-- | sys/i386/isa/intr_machdep.h | 6 | ||||
-rw-r--r-- | sys/i386/isa/ipl.s | 26 | ||||
-rw-r--r-- | sys/i386/isa/nmi.c | 38 | ||||
-rw-r--r-- | sys/kern/subr_smp.c | 61 | ||||
-rw-r--r-- | sys/sys/smp.h | 5 |
23 files changed, 1520 insertions, 186 deletions
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S index 4603440..05cf190 100644 --- a/sys/amd64/amd64/apic_vector.S +++ b/sys/amd64/amd64/apic_vector.S @@ -1,6 +1,6 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: apic_vector.s,v 1.25 1998/01/15 07:33:58 gibbs Exp $ + * $Id: apic_vector.s,v 1.26 1998/03/03 20:55:24 tegge Exp $ */ @@ -166,43 +166,64 @@ IDTVEC(vec_name) ; \ popal ; \ addl $4+4,%esp -/* - * Test to see whether we are handling an edge or level triggered INT. - * Level-triggered INTs must still be masked as we don't clear the source, - * and the EOI cycle would cause redundant INTs to occur. - */ -#define MASK_LEVEL_IRQ(irq_num) \ - testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ - jz 8f ; /* edge, don't mask */ \ +#define MASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ + testl $IRQ_BIT(irq_num), _apic_imen ; \ + jne 7f ; /* masked, don't mask */ \ orl $IRQ_BIT(irq_num), _apic_imen ; /* set the mask bit */ \ movl _ioapic, %ecx ; /* ioapic[0] addr */ \ movl $REDTBL_IDX(irq_num), (%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx), %eax ; /* current value */ \ orl $IOART_INTMASK, %eax ; /* set the mask */ \ movl %eax, IOAPIC_WINDOW(%ecx) ; /* new value */ \ - IMASK_UNLOCK ; \ -8: +7: ; /* already masked */ \ + IMASK_UNLOCK +/* + * Test to see whether we are handling an edge or level triggered INT. + * Level-triggered INTs must still be masked as we don't clear the source, + * and the EOI cycle would cause redundant INTs to occur. + */ +#define MASK_LEVEL_IRQ(irq_num) \ + testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ + jz 9f ; /* edge, don't mask */ \ + MASK_IRQ(irq_num) ; \ +9: + +#ifdef APIC_INTR_REORDER +#define EOI_IRQ(irq_num) \ + movl _apic_isrbit_location + 8 * (irq_num), %eax ; \ + movl (%eax), %eax ; \ + testl _apic_isrbit_location + 4 + 8 * (irq_num), %eax ; \ + jz 9f ; /* not active */ \ + movl $0, lapic_eoi ; \ + APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ +9: + +#else +#define EOI_IRQ(irq_num) \ + testl $IRQ_BIT(irq_num), lapic_isr1; \ + jz 9f ; /* not active */ \ + movl $0, lapic_eoi; \ + APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ +9: +#endif + + /* * Test to see if the source is currntly masked, clear if so. */ #define UNMASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ - jne 7f ; /* bit set, masked */ \ - testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ - jz 9f ; /* edge, don't EOI */ \ - movl $0, lapic_eoi ; /* should be safe */ \ - jmp 9f ; /* skip unmasking */ \ -7: \ + je 7f ; /* bit clear, not masked */ \ andl $~IRQ_BIT(irq_num), _apic_imen ;/* clear mask bit */ \ movl _ioapic,%ecx ; /* ioapic[0]addr */ \ movl $REDTBL_IDX(irq_num),(%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx),%eax ; /* current value */ \ andl $~IOART_INTMASK,%eax ; /* clear the mask */ \ movl %eax,IOAPIC_WINDOW(%ecx) ; /* new value */ \ -9: ; \ +7: ; \ IMASK_UNLOCK #ifdef INTR_SIMPLELOCK @@ -213,11 +234,75 @@ IDTVEC(vec_name) ; \ #define ENLOCK \ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ - jz 1f + jz 3f #define DELOCK ISR_RELLOCK #define LATELOCK #endif +#ifdef APIC_INTR_DIAGNOSTIC +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +log_intr_event: + pushf + cli + pushl $CNAME(apic_itrace_debuglock) + call _s_lock_np + addl $4, %esp + movl CNAME(apic_itrace_debugbuffer_idx), %ecx + andl $32767, %ecx + movl _cpuid, %eax + shll $8, %eax + orl 8(%esp), %eax + movw %ax, CNAME(apic_itrace_debugbuffer)(,%ecx,2) + incl %ecx + andl $32767, %ecx + movl %ecx, CNAME(apic_itrace_debugbuffer_idx) + pushl $CNAME(apic_itrace_debuglock) + call _s_unlock_np + addl $4, %esp + popf + ret + + +#define APIC_ITRACE(name, irq_num, id) \ + lock ; /* MP-safe */ \ + incl CNAME(name) + (irq_num) * 4 ; \ + pushl %eax ; \ + pushl %ecx ; \ + pushl %edx ; \ + movl $(irq_num), %eax ; \ + cmpl $APIC_INTR_DIAGNOSTIC_IRQ, %eax ; \ + jne 7f ; \ + pushl $id ; \ + call log_intr_event ; \ + addl $4, %esp ; \ +7: ; \ + popl %edx ; \ + popl %ecx ; \ + popl %eax +#else +#define APIC_ITRACE(name, irq_num, id) \ + lock ; /* MP-safe */ \ + incl CNAME(name) + (irq_num) * 4 +#endif + +#define APIC_ITRACE_ENTER 1 +#define APIC_ITRACE_EOI 2 +#define APIC_ITRACE_TRYISRLOCK 3 +#define APIC_ITRACE_GOTISRLOCK 4 +#define APIC_ITRACE_ENTER2 5 +#define APIC_ITRACE_LEAVE 6 +#define APIC_ITRACE_UNMASK 7 +#define APIC_ITRACE_ACTIVE 8 +#define APIC_ITRACE_MASKED 9 +#define APIC_ITRACE_NOISRLOCK 10 +#define APIC_ITRACE_MASKED2 11 +#define APIC_ITRACE_SPLZ 12 +#define APIC_ITRACE_DORETI 13 + +#else +#define APIC_ITRACE(name, irq_num, id) +#endif + #ifdef CPL_AND_CML #define INTR(irq_num, vec_name) \ @@ -230,12 +315,18 @@ IDTVEC(vec_name) ; \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ + APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ + MASK_LEVEL_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ +0: ; \ + APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ENLOCK ; \ ; \ + APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ @@ -244,7 +335,6 @@ IDTVEC(vec_name) ; \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ ; \ -;;; movl $0, lapic_eoi ; /* XXX too soon? */ \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ @@ -263,39 +353,67 @@ __CONCAT(Xresume,irq_num): ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ incl _inside_intr ; \ + APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ + APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ decl _inside_intr ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ lock ; andl $~IRQ_BIT(irq_num), _cil ; \ UNMASK_IRQ(irq_num) ; \ + APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ LATELOCK ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ -1: ; /* active or locked */ \ - MASK_LEVEL_IRQ(irq_num) ; \ - movl $0, lapic_eoi ; /* do the EOI */ \ -; \ +1: ; /* active */ \ + APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ -; \ + MASK_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ + btsl $(irq_num), iactive ; /* still active */ \ + jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; /* masked by cpl|cml */ \ + APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ + orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ DELOCK ; /* XXX this is going away... */ \ - jmp 1b + POP_FRAME ; \ + iret ; \ + ALIGN_TEXT ; \ +3: ; /* other cpu has isr lock */ \ + APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ + AVCPL_LOCK ; /* MP-safe */ \ + orl $IRQ_BIT(irq_num), _ipending ; \ + testl $IRQ_BIT(irq_num), _cpl ; \ + jne 4f ; /* this INT masked */ \ + testl $IRQ_BIT(irq_num), _cml ; \ + jne 4f ; /* this INT masked */ \ + orl $IRQ_BIT(irq_num), _cil ; \ + AVCPL_UNLOCK ; \ + call forward_irq ; /* forward irq to lock holder */ \ + POP_FRAME ; /* and return */ \ + iret ; \ + ALIGN_TEXT ; \ +4: ; /* blocked */ \ + APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ + AVCPL_UNLOCK ; \ + POP_FRAME ; /* and return */ \ + iret #else /* CPL_AND_CML */ + #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ @@ -306,20 +424,25 @@ IDTVEC(vec_name) ; \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ + APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ + MASK_LEVEL_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ +0: ; \ + APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ - jz 1f ; /* no */ \ + jz 3f ; /* no */ \ ; \ + APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ ; \ -;;; movl $0, lapic_eoi ; /* XXX too soon? */ \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ @@ -334,36 +457,60 @@ __CONCAT(Xresume,irq_num): ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cpl ; \ + andl $~IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ + APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ + APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ UNMASK_IRQ(irq_num) ; \ + APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ -1: ; /* active or locked */ \ - MASK_LEVEL_IRQ(irq_num) ; \ - movl $0, lapic_eoi ; /* do the EOI */ \ -; \ +1: ; /* active */ \ + APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ -; \ + MASK_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ + btsl $(irq_num), iactive ; /* still active */ \ + jnc 0b ; /* retry */ \ POP_FRAME ; \ - iret ; \ -; \ + iret ; /* XXX: iactive bit might be 0 now */ \ ALIGN_TEXT ; \ -2: ; /* masked by cpl */ \ +2: ; /* masked by cpl, leave iactive set */ \ + APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ + orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ISR_RELLOCK ; /* XXX this is going away... */ \ - jmp 1b + POP_FRAME ; \ + iret ; \ + ALIGN_TEXT ; \ +3: ; /* other cpu has isr lock */ \ + APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ + AVCPL_LOCK ; /* MP-safe */ \ + orl $IRQ_BIT(irq_num), _ipending ; \ + testl $IRQ_BIT(irq_num), _cpl ; \ + jne 4f ; /* this INT masked */ \ + AVCPL_UNLOCK ; \ + call forward_irq ; /* forward irq to lock holder */ \ + POP_FRAME ; /* and return */ \ + iret ; \ + ALIGN_TEXT ; \ +4: ; /* blocked */ \ + APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ + AVCPL_UNLOCK ; \ + POP_FRAME ; /* and return */ \ + iret #endif /* CPL_AND_CML */ @@ -515,6 +662,8 @@ _Xcpuast: movl _cpl, %eax #endif pushl %eax + lock + orl $SWI_AST_PENDING, _ipending AVCPL_UNLOCK lock incb _intr_nesting_level @@ -522,9 +671,6 @@ _Xcpuast: pushl $0 - lock - orl $SWI_AST_PENDING, _ipending - movl _cpuid, %eax lock btrl %eax, _checkstate_pending_ast @@ -536,6 +682,113 @@ _Xcpuast: POP_FRAME iret + +/* + * Executed by a CPU when it receives an XFORWARD_IRQ IPI. + */ + + .text + SUPERALIGN_TEXT + .globl _Xforward_irq +_Xforward_irq: + PUSH_FRAME + movl $KDSEL, %eax + movl %ax, %ds /* use KERNEL data segment */ + movl %ax, %es + + movl $0, lapic_eoi /* End Of Interrupt to APIC */ + + FAKE_MCOUNT(12*4(%esp)) + + ISR_TRYLOCK + testl %eax,%eax /* Did we get the lock ? */ + jz 1f /* No */ + + lock + incl CNAME(forward_irq_hitcnt) + cmpb $4, _intr_nesting_level + jae 2f + + jmp 3f + + AVCPL_LOCK +#ifdef CPL_AND_CML + movl _cml, %eax +#else + movl _cpl, %eax +#endif + pushl %eax + AVCPL_UNLOCK + lock + incb _intr_nesting_level + sti + + pushl $0 + + MEXITCOUNT + jmp _doreti /* Handle forwarded interrupt */ +4: + lock + decb _intr_nesting_level + ISR_RELLOCK + MEXITCOUNT + addl $8, %esp + POP_FRAME + iret +1: + lock + incl CNAME(forward_irq_misscnt) + call forward_irq /* Oops, we've lost the isr lock */ + MEXITCOUNT + POP_FRAME + iret +2: + lock + incl CNAME(forward_irq_toodeepcnt) +3: + ISR_RELLOCK + MEXITCOUNT + POP_FRAME + iret + +/* + * + */ +forward_irq: + MCOUNT + cmpl $0,_invltlb_ok + jz 4f + + cmpl $0, CNAME(forward_irq_enabled) + jz 4f + + movl _mp_lock,%eax + cmpl $FREE_LOCK,%eax + jne 1f + movl $0, %eax /* Pick CPU #0 if noone has lock */ +1: + shrl $24,%eax + movl _cpu_num_to_apic_id(,%eax,4),%ecx + shll $24,%ecx + movl lapic_icr_hi, %eax + andl $~APIC_ID_MASK, %eax + orl %ecx, %eax + movl %eax, lapic_icr_hi + +2: + movl lapic_icr_lo, %eax + andl $APIC_DELSTAT_MASK,%eax + jnz 2b + movl lapic_icr_lo, %eax + andl $APIC_RESV2_MASK, %eax + orl $(APIC_DEST_DESTFLD|APIC_DELMODE_FIXED|XFORWARD_IRQ_OFFSET), %eax + movl %eax, lapic_icr_lo +3: + movl lapic_icr_lo, %eax + andl $APIC_DELSTAT_MASK,%eax + jnz 3b +4: + ret /* * Executed by a CPU when it receives an Xcpustop IPI from another CPU, @@ -702,6 +955,16 @@ _checkstate_need_ast: .long 0 _checkstate_pending_ast: .long 0 + .globl CNAME(forward_irq_misscnt) + .globl CNAME(forward_irq_toodeepcnt) + .globl CNAME(forward_irq_hitcnt) +CNAME(forward_irq_misscnt): + .long 0 +CNAME(forward_irq_hitcnt): + .long 0 +CNAME(forward_irq_toodeepcnt): + .long 0 + .globl _apic_pin_trigger _apic_pin_trigger: diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 82ae434..d5bfeeb 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_machdep.c,v 1.67 1998/03/03 20:09:14 tegge Exp $ + * $Id: mp_machdep.c,v 1.68 1998/03/03 20:55:25 tegge Exp $ */ #include "opt_smp.h" @@ -246,6 +246,35 @@ extern int nkpt; u_int32_t cpu_apic_versions[NCPU]; u_int32_t io_apic_versions[NAPIC]; +#ifdef APIC_INTR_DIAGNOSTIC +int apic_itrace_enter[32]; +int apic_itrace_tryisrlock[32]; +int apic_itrace_gotisrlock[32]; +int apic_itrace_active[32]; +int apic_itrace_masked[32]; +int apic_itrace_noisrlock[32]; +int apic_itrace_masked2[32]; +int apic_itrace_unmask[32]; +int apic_itrace_noforward[32]; +int apic_itrace_leave[32]; +int apic_itrace_enter2[32]; +int apic_itrace_doreti[32]; +int apic_itrace_splz[32]; +int apic_itrace_eoi[32]; +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +unsigned short apic_itrace_debugbuffer[32768]; +int apic_itrace_debugbuffer_idx; +struct simplelock apic_itrace_debuglock; +#endif +#endif + +#ifdef APIC_INTR_REORDER +struct { + volatile int *location; + int bit; +} apic_isrbit_location[32]; +#endif + /* * APIC ID logical/physical mapping structures. * We oversize these to simplify boot-time config. @@ -575,6 +604,10 @@ mp_enable(u_int boot_addr) setidt(XCPUAST_OFFSET, Xcpuast, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for interrupt forwarding */ + setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -1537,6 +1570,10 @@ init_locks(void) /* ISR uses its own "giant lock" */ isr_lock = FREE_LOCK; +#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) + s_lock_init((struct simplelock*)&apic_itrace_debuglock); +#endif + s_lock_init((struct simplelock*)&mpintr_lock); s_lock_init((struct simplelock*)&mcount_lock); @@ -1995,6 +2032,11 @@ int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, &do_page_zero_idle, 0, ""); +/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ +int forward_irq_enabled = 1; +SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, + &forward_irq_enabled, 0, ""); + /* Enable forwarding of a signal to a process running on a different CPU */ int forward_signal_enabled = 1; SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, @@ -2438,3 +2480,20 @@ forward_signal(struct proc *p) return; } } + + +#ifdef APIC_INTR_REORDER +/* + * Maintain mapping from softintr vector to isr bit in local apic. + */ +void +set_lapic_isrloc(int intr, int vector) +{ + if (intr < 0 || intr > 32) + panic("set_apic_isrloc: bad intr argument: %d",intr); + if (vector < ICU_OFFSET || vector > 255) + panic("set_apic_isrloc: bad vector argument: %d",vector); + apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); + apic_isrbit_location[intr].bit = (1<<(vector & 31)); +} +#endif diff --git a/sys/amd64/amd64/mptable.c b/sys/amd64/amd64/mptable.c index 82ae434..d5bfeeb 100644 --- a/sys/amd64/amd64/mptable.c +++ b/sys/amd64/amd64/mptable.c @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_machdep.c,v 1.67 1998/03/03 20:09:14 tegge Exp $ + * $Id: mp_machdep.c,v 1.68 1998/03/03 20:55:25 tegge Exp $ */ #include "opt_smp.h" @@ -246,6 +246,35 @@ extern int nkpt; u_int32_t cpu_apic_versions[NCPU]; u_int32_t io_apic_versions[NAPIC]; +#ifdef APIC_INTR_DIAGNOSTIC +int apic_itrace_enter[32]; +int apic_itrace_tryisrlock[32]; +int apic_itrace_gotisrlock[32]; +int apic_itrace_active[32]; +int apic_itrace_masked[32]; +int apic_itrace_noisrlock[32]; +int apic_itrace_masked2[32]; +int apic_itrace_unmask[32]; +int apic_itrace_noforward[32]; +int apic_itrace_leave[32]; +int apic_itrace_enter2[32]; +int apic_itrace_doreti[32]; +int apic_itrace_splz[32]; +int apic_itrace_eoi[32]; +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +unsigned short apic_itrace_debugbuffer[32768]; +int apic_itrace_debugbuffer_idx; +struct simplelock apic_itrace_debuglock; +#endif +#endif + +#ifdef APIC_INTR_REORDER +struct { + volatile int *location; + int bit; +} apic_isrbit_location[32]; +#endif + /* * APIC ID logical/physical mapping structures. * We oversize these to simplify boot-time config. @@ -575,6 +604,10 @@ mp_enable(u_int boot_addr) setidt(XCPUAST_OFFSET, Xcpuast, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for interrupt forwarding */ + setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -1537,6 +1570,10 @@ init_locks(void) /* ISR uses its own "giant lock" */ isr_lock = FREE_LOCK; +#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) + s_lock_init((struct simplelock*)&apic_itrace_debuglock); +#endif + s_lock_init((struct simplelock*)&mpintr_lock); s_lock_init((struct simplelock*)&mcount_lock); @@ -1995,6 +2032,11 @@ int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, &do_page_zero_idle, 0, ""); +/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ +int forward_irq_enabled = 1; +SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, + &forward_irq_enabled, 0, ""); + /* Enable forwarding of a signal to a process running on a different CPU */ int forward_signal_enabled = 1; SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, @@ -2438,3 +2480,20 @@ forward_signal(struct proc *p) return; } } + + +#ifdef APIC_INTR_REORDER +/* + * Maintain mapping from softintr vector to isr bit in local apic. + */ +void +set_lapic_isrloc(int intr, int vector) +{ + if (intr < 0 || intr > 32) + panic("set_apic_isrloc: bad intr argument: %d",intr); + if (vector < ICU_OFFSET || vector > 255) + panic("set_apic_isrloc: bad vector argument: %d",vector); + apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); + apic_isrbit_location[intr].bit = (1<<(vector & 31)); +} +#endif diff --git a/sys/amd64/include/mptable.h b/sys/amd64/include/mptable.h index 82ae434..d5bfeeb 100644 --- a/sys/amd64/include/mptable.h +++ b/sys/amd64/include/mptable.h @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_machdep.c,v 1.67 1998/03/03 20:09:14 tegge Exp $ + * $Id: mp_machdep.c,v 1.68 1998/03/03 20:55:25 tegge Exp $ */ #include "opt_smp.h" @@ -246,6 +246,35 @@ extern int nkpt; u_int32_t cpu_apic_versions[NCPU]; u_int32_t io_apic_versions[NAPIC]; +#ifdef APIC_INTR_DIAGNOSTIC +int apic_itrace_enter[32]; +int apic_itrace_tryisrlock[32]; +int apic_itrace_gotisrlock[32]; +int apic_itrace_active[32]; +int apic_itrace_masked[32]; +int apic_itrace_noisrlock[32]; +int apic_itrace_masked2[32]; +int apic_itrace_unmask[32]; +int apic_itrace_noforward[32]; +int apic_itrace_leave[32]; +int apic_itrace_enter2[32]; +int apic_itrace_doreti[32]; +int apic_itrace_splz[32]; +int apic_itrace_eoi[32]; +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +unsigned short apic_itrace_debugbuffer[32768]; +int apic_itrace_debugbuffer_idx; +struct simplelock apic_itrace_debuglock; +#endif +#endif + +#ifdef APIC_INTR_REORDER +struct { + volatile int *location; + int bit; +} apic_isrbit_location[32]; +#endif + /* * APIC ID logical/physical mapping structures. * We oversize these to simplify boot-time config. @@ -575,6 +604,10 @@ mp_enable(u_int boot_addr) setidt(XCPUAST_OFFSET, Xcpuast, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for interrupt forwarding */ + setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -1537,6 +1570,10 @@ init_locks(void) /* ISR uses its own "giant lock" */ isr_lock = FREE_LOCK; +#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) + s_lock_init((struct simplelock*)&apic_itrace_debuglock); +#endif + s_lock_init((struct simplelock*)&mpintr_lock); s_lock_init((struct simplelock*)&mcount_lock); @@ -1995,6 +2032,11 @@ int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, &do_page_zero_idle, 0, ""); +/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ +int forward_irq_enabled = 1; +SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, + &forward_irq_enabled, 0, ""); + /* Enable forwarding of a signal to a process running on a different CPU */ int forward_signal_enabled = 1; SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, @@ -2438,3 +2480,20 @@ forward_signal(struct proc *p) return; } } + + +#ifdef APIC_INTR_REORDER +/* + * Maintain mapping from softintr vector to isr bit in local apic. + */ +void +set_lapic_isrloc(int intr, int vector) +{ + if (intr < 0 || intr > 32) + panic("set_apic_isrloc: bad intr argument: %d",intr); + if (vector < ICU_OFFSET || vector > 255) + panic("set_apic_isrloc: bad vector argument: %d",vector); + apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); + apic_isrbit_location[intr].bit = (1<<(vector & 31)); +} +#endif diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h index 482b860..d921d23 100644 --- a/sys/amd64/include/smp.h +++ b/sys/amd64/include/smp.h @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: smp.h,v 1.36 1998/03/03 19:44:34 tegge Exp $ + * $Id: smp.h,v 1.37 1998/03/03 20:55:23 tegge Exp $ * */ @@ -137,6 +137,9 @@ void forward_statclock __P((int pscnt)); void forward_hardclock __P((int pscnt)); #endif /* BETTER_CLOCK */ void forward_signal __P((struct proc *)); +#ifdef APIC_INTR_REORDER +void set_lapic_isrloc __P((int, int)); +#endif /* APIC_INTR_REORDER */ /* global data in mpapic.c */ extern volatile lapic_t lapic; diff --git a/sys/amd64/isa/intr_machdep.c b/sys/amd64/isa/intr_machdep.c index 4a593ea7..0cdbfc0 100644 --- a/sys/amd64/isa/intr_machdep.c +++ b/sys/amd64/isa/intr_machdep.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.7 1997/09/28 15:48:34 mckay Exp $ + * $Id: intr_machdep.c,v 1.8 1998/02/09 06:08:30 eivind Exp $ */ #include "opt_auto_eoi.h" @@ -444,19 +444,30 @@ icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags) vector = TPR_FAST_INTS + intr; setidt(vector, fastintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* - * XXX MULTIPLE_IOAPICSXXX - * Reprogram the vector in the IO APIC. - */ - select = (intr * 2) + IOAPIC_REDTBL0; - value = io_apic_read(0, select) & ~IOART_INTVEC; - io_apic_write(0, select, value | vector); } - else - setidt(TPR_SLOW_INTS + intr, slowintr[intr], + else { + vector = TPR_SLOW_INTS + intr; +#ifdef APIC_INTR_REORDER +#ifdef APIC_INTR_HIGHPRI_CLOCK + /* XXX: Hack (kludge?) for more accurate clock. */ + if (intr == 0 || intr == 8) { + vector = TPR_FAST_INTS + intr; + } +#endif +#endif + setidt(vector, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - + } +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, vector); +#endif + /* + * XXX MULTIPLE_IOAPICSXXX + * Reprogram the vector in the IO APIC. + */ + select = (intr * 2) + IOAPIC_REDTBL0; + value = io_apic_read(0, select) & ~IOART_INTVEC; + io_apic_write(0, select, value | vector); #else setidt(ICU_OFFSET + intr, flags & INTR_FAST ? fastintr[intr] : slowintr[intr], @@ -505,6 +516,9 @@ icu_unset(intr, handler) setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #else /* FAST_HI */ +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, ICU_OFFSET + intr); +#endif setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #endif /* FAST_HI */ diff --git a/sys/amd64/isa/intr_machdep.h b/sys/amd64/isa/intr_machdep.h index 7714c0d..97122e6 100644 --- a/sys/amd64/isa/intr_machdep.h +++ b/sys/amd64/isa/intr_machdep.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * $Id: intr_machdep.h,v 1.9 1998/02/13 06:59:22 bde Exp $ + * $Id: intr_machdep.h,v 1.10 1998/03/03 20:55:24 tegge Exp $ */ #ifndef _I386_ISA_INTR_MACHDEP_H_ @@ -116,6 +116,9 @@ /* IPI to generate an additional software trap at the target CPU */ #define XCPUAST_OFFSET (ICU_OFFSET + 48) +/* IPI to signal the CPU holding the ISR lock that another IRQ has appeared */ +#define XFORWARD_IRQ_OFFSET (ICU_OFFSET + 49) + /* IPI to signal CPUs to stop and wait for another CPU to restart them */ #define XCPUSTOP_OFFSET (ICU_OFFSET + 128) @@ -174,6 +177,7 @@ inthand_t Xcpucheckstate, /* Check cpu state */ #endif Xcpuast, /* Additional software trap on other cpu */ + Xforward_irq, /* Forward irq to cpu holding ISR lock */ Xcpustop, /* CPU stops & waits for another CPU to restart it */ Xspuriousint; /* handle APIC "spurious INTs" */ diff --git a/sys/amd64/isa/nmi.c b/sys/amd64/isa/nmi.c index 4a593ea7..0cdbfc0 100644 --- a/sys/amd64/isa/nmi.c +++ b/sys/amd64/isa/nmi.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.7 1997/09/28 15:48:34 mckay Exp $ + * $Id: intr_machdep.c,v 1.8 1998/02/09 06:08:30 eivind Exp $ */ #include "opt_auto_eoi.h" @@ -444,19 +444,30 @@ icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags) vector = TPR_FAST_INTS + intr; setidt(vector, fastintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* - * XXX MULTIPLE_IOAPICSXXX - * Reprogram the vector in the IO APIC. - */ - select = (intr * 2) + IOAPIC_REDTBL0; - value = io_apic_read(0, select) & ~IOART_INTVEC; - io_apic_write(0, select, value | vector); } - else - setidt(TPR_SLOW_INTS + intr, slowintr[intr], + else { + vector = TPR_SLOW_INTS + intr; +#ifdef APIC_INTR_REORDER +#ifdef APIC_INTR_HIGHPRI_CLOCK + /* XXX: Hack (kludge?) for more accurate clock. */ + if (intr == 0 || intr == 8) { + vector = TPR_FAST_INTS + intr; + } +#endif +#endif + setidt(vector, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - + } +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, vector); +#endif + /* + * XXX MULTIPLE_IOAPICSXXX + * Reprogram the vector in the IO APIC. + */ + select = (intr * 2) + IOAPIC_REDTBL0; + value = io_apic_read(0, select) & ~IOART_INTVEC; + io_apic_write(0, select, value | vector); #else setidt(ICU_OFFSET + intr, flags & INTR_FAST ? fastintr[intr] : slowintr[intr], @@ -505,6 +516,9 @@ icu_unset(intr, handler) setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #else /* FAST_HI */ +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, ICU_OFFSET + intr); +#endif setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #endif /* FAST_HI */ diff --git a/sys/i386/i386/apic_vector.s b/sys/i386/i386/apic_vector.s index 4603440..05cf190 100644 --- a/sys/i386/i386/apic_vector.s +++ b/sys/i386/i386/apic_vector.s @@ -1,6 +1,6 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: apic_vector.s,v 1.25 1998/01/15 07:33:58 gibbs Exp $ + * $Id: apic_vector.s,v 1.26 1998/03/03 20:55:24 tegge Exp $ */ @@ -166,43 +166,64 @@ IDTVEC(vec_name) ; \ popal ; \ addl $4+4,%esp -/* - * Test to see whether we are handling an edge or level triggered INT. - * Level-triggered INTs must still be masked as we don't clear the source, - * and the EOI cycle would cause redundant INTs to occur. - */ -#define MASK_LEVEL_IRQ(irq_num) \ - testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ - jz 8f ; /* edge, don't mask */ \ +#define MASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ + testl $IRQ_BIT(irq_num), _apic_imen ; \ + jne 7f ; /* masked, don't mask */ \ orl $IRQ_BIT(irq_num), _apic_imen ; /* set the mask bit */ \ movl _ioapic, %ecx ; /* ioapic[0] addr */ \ movl $REDTBL_IDX(irq_num), (%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx), %eax ; /* current value */ \ orl $IOART_INTMASK, %eax ; /* set the mask */ \ movl %eax, IOAPIC_WINDOW(%ecx) ; /* new value */ \ - IMASK_UNLOCK ; \ -8: +7: ; /* already masked */ \ + IMASK_UNLOCK +/* + * Test to see whether we are handling an edge or level triggered INT. + * Level-triggered INTs must still be masked as we don't clear the source, + * and the EOI cycle would cause redundant INTs to occur. + */ +#define MASK_LEVEL_IRQ(irq_num) \ + testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ + jz 9f ; /* edge, don't mask */ \ + MASK_IRQ(irq_num) ; \ +9: + +#ifdef APIC_INTR_REORDER +#define EOI_IRQ(irq_num) \ + movl _apic_isrbit_location + 8 * (irq_num), %eax ; \ + movl (%eax), %eax ; \ + testl _apic_isrbit_location + 4 + 8 * (irq_num), %eax ; \ + jz 9f ; /* not active */ \ + movl $0, lapic_eoi ; \ + APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ +9: + +#else +#define EOI_IRQ(irq_num) \ + testl $IRQ_BIT(irq_num), lapic_isr1; \ + jz 9f ; /* not active */ \ + movl $0, lapic_eoi; \ + APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ +9: +#endif + + /* * Test to see if the source is currntly masked, clear if so. */ #define UNMASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ - jne 7f ; /* bit set, masked */ \ - testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ - jz 9f ; /* edge, don't EOI */ \ - movl $0, lapic_eoi ; /* should be safe */ \ - jmp 9f ; /* skip unmasking */ \ -7: \ + je 7f ; /* bit clear, not masked */ \ andl $~IRQ_BIT(irq_num), _apic_imen ;/* clear mask bit */ \ movl _ioapic,%ecx ; /* ioapic[0]addr */ \ movl $REDTBL_IDX(irq_num),(%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx),%eax ; /* current value */ \ andl $~IOART_INTMASK,%eax ; /* clear the mask */ \ movl %eax,IOAPIC_WINDOW(%ecx) ; /* new value */ \ -9: ; \ +7: ; \ IMASK_UNLOCK #ifdef INTR_SIMPLELOCK @@ -213,11 +234,75 @@ IDTVEC(vec_name) ; \ #define ENLOCK \ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ - jz 1f + jz 3f #define DELOCK ISR_RELLOCK #define LATELOCK #endif +#ifdef APIC_INTR_DIAGNOSTIC +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +log_intr_event: + pushf + cli + pushl $CNAME(apic_itrace_debuglock) + call _s_lock_np + addl $4, %esp + movl CNAME(apic_itrace_debugbuffer_idx), %ecx + andl $32767, %ecx + movl _cpuid, %eax + shll $8, %eax + orl 8(%esp), %eax + movw %ax, CNAME(apic_itrace_debugbuffer)(,%ecx,2) + incl %ecx + andl $32767, %ecx + movl %ecx, CNAME(apic_itrace_debugbuffer_idx) + pushl $CNAME(apic_itrace_debuglock) + call _s_unlock_np + addl $4, %esp + popf + ret + + +#define APIC_ITRACE(name, irq_num, id) \ + lock ; /* MP-safe */ \ + incl CNAME(name) + (irq_num) * 4 ; \ + pushl %eax ; \ + pushl %ecx ; \ + pushl %edx ; \ + movl $(irq_num), %eax ; \ + cmpl $APIC_INTR_DIAGNOSTIC_IRQ, %eax ; \ + jne 7f ; \ + pushl $id ; \ + call log_intr_event ; \ + addl $4, %esp ; \ +7: ; \ + popl %edx ; \ + popl %ecx ; \ + popl %eax +#else +#define APIC_ITRACE(name, irq_num, id) \ + lock ; /* MP-safe */ \ + incl CNAME(name) + (irq_num) * 4 +#endif + +#define APIC_ITRACE_ENTER 1 +#define APIC_ITRACE_EOI 2 +#define APIC_ITRACE_TRYISRLOCK 3 +#define APIC_ITRACE_GOTISRLOCK 4 +#define APIC_ITRACE_ENTER2 5 +#define APIC_ITRACE_LEAVE 6 +#define APIC_ITRACE_UNMASK 7 +#define APIC_ITRACE_ACTIVE 8 +#define APIC_ITRACE_MASKED 9 +#define APIC_ITRACE_NOISRLOCK 10 +#define APIC_ITRACE_MASKED2 11 +#define APIC_ITRACE_SPLZ 12 +#define APIC_ITRACE_DORETI 13 + +#else +#define APIC_ITRACE(name, irq_num, id) +#endif + #ifdef CPL_AND_CML #define INTR(irq_num, vec_name) \ @@ -230,12 +315,18 @@ IDTVEC(vec_name) ; \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ + APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ + MASK_LEVEL_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ +0: ; \ + APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ENLOCK ; \ ; \ + APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ @@ -244,7 +335,6 @@ IDTVEC(vec_name) ; \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ ; \ -;;; movl $0, lapic_eoi ; /* XXX too soon? */ \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ @@ -263,39 +353,67 @@ __CONCAT(Xresume,irq_num): ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ incl _inside_intr ; \ + APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ + APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ decl _inside_intr ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ lock ; andl $~IRQ_BIT(irq_num), _cil ; \ UNMASK_IRQ(irq_num) ; \ + APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ LATELOCK ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ -1: ; /* active or locked */ \ - MASK_LEVEL_IRQ(irq_num) ; \ - movl $0, lapic_eoi ; /* do the EOI */ \ -; \ +1: ; /* active */ \ + APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ -; \ + MASK_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ + btsl $(irq_num), iactive ; /* still active */ \ + jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; /* masked by cpl|cml */ \ + APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ + orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ DELOCK ; /* XXX this is going away... */ \ - jmp 1b + POP_FRAME ; \ + iret ; \ + ALIGN_TEXT ; \ +3: ; /* other cpu has isr lock */ \ + APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ + AVCPL_LOCK ; /* MP-safe */ \ + orl $IRQ_BIT(irq_num), _ipending ; \ + testl $IRQ_BIT(irq_num), _cpl ; \ + jne 4f ; /* this INT masked */ \ + testl $IRQ_BIT(irq_num), _cml ; \ + jne 4f ; /* this INT masked */ \ + orl $IRQ_BIT(irq_num), _cil ; \ + AVCPL_UNLOCK ; \ + call forward_irq ; /* forward irq to lock holder */ \ + POP_FRAME ; /* and return */ \ + iret ; \ + ALIGN_TEXT ; \ +4: ; /* blocked */ \ + APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ + AVCPL_UNLOCK ; \ + POP_FRAME ; /* and return */ \ + iret #else /* CPL_AND_CML */ + #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ @@ -306,20 +424,25 @@ IDTVEC(vec_name) ; \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ + APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ + MASK_LEVEL_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ +0: ; \ + APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ - jz 1f ; /* no */ \ + jz 3f ; /* no */ \ ; \ + APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ ; \ -;;; movl $0, lapic_eoi ; /* XXX too soon? */ \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ @@ -334,36 +457,60 @@ __CONCAT(Xresume,irq_num): ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cpl ; \ + andl $~IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ + APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ + APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ UNMASK_IRQ(irq_num) ; \ + APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ -1: ; /* active or locked */ \ - MASK_LEVEL_IRQ(irq_num) ; \ - movl $0, lapic_eoi ; /* do the EOI */ \ -; \ +1: ; /* active */ \ + APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ -; \ + MASK_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ + btsl $(irq_num), iactive ; /* still active */ \ + jnc 0b ; /* retry */ \ POP_FRAME ; \ - iret ; \ -; \ + iret ; /* XXX: iactive bit might be 0 now */ \ ALIGN_TEXT ; \ -2: ; /* masked by cpl */ \ +2: ; /* masked by cpl, leave iactive set */ \ + APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ + orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ISR_RELLOCK ; /* XXX this is going away... */ \ - jmp 1b + POP_FRAME ; \ + iret ; \ + ALIGN_TEXT ; \ +3: ; /* other cpu has isr lock */ \ + APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ + AVCPL_LOCK ; /* MP-safe */ \ + orl $IRQ_BIT(irq_num), _ipending ; \ + testl $IRQ_BIT(irq_num), _cpl ; \ + jne 4f ; /* this INT masked */ \ + AVCPL_UNLOCK ; \ + call forward_irq ; /* forward irq to lock holder */ \ + POP_FRAME ; /* and return */ \ + iret ; \ + ALIGN_TEXT ; \ +4: ; /* blocked */ \ + APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ + AVCPL_UNLOCK ; \ + POP_FRAME ; /* and return */ \ + iret #endif /* CPL_AND_CML */ @@ -515,6 +662,8 @@ _Xcpuast: movl _cpl, %eax #endif pushl %eax + lock + orl $SWI_AST_PENDING, _ipending AVCPL_UNLOCK lock incb _intr_nesting_level @@ -522,9 +671,6 @@ _Xcpuast: pushl $0 - lock - orl $SWI_AST_PENDING, _ipending - movl _cpuid, %eax lock btrl %eax, _checkstate_pending_ast @@ -536,6 +682,113 @@ _Xcpuast: POP_FRAME iret + +/* + * Executed by a CPU when it receives an XFORWARD_IRQ IPI. + */ + + .text + SUPERALIGN_TEXT + .globl _Xforward_irq +_Xforward_irq: + PUSH_FRAME + movl $KDSEL, %eax + movl %ax, %ds /* use KERNEL data segment */ + movl %ax, %es + + movl $0, lapic_eoi /* End Of Interrupt to APIC */ + + FAKE_MCOUNT(12*4(%esp)) + + ISR_TRYLOCK + testl %eax,%eax /* Did we get the lock ? */ + jz 1f /* No */ + + lock + incl CNAME(forward_irq_hitcnt) + cmpb $4, _intr_nesting_level + jae 2f + + jmp 3f + + AVCPL_LOCK +#ifdef CPL_AND_CML + movl _cml, %eax +#else + movl _cpl, %eax +#endif + pushl %eax + AVCPL_UNLOCK + lock + incb _intr_nesting_level + sti + + pushl $0 + + MEXITCOUNT + jmp _doreti /* Handle forwarded interrupt */ +4: + lock + decb _intr_nesting_level + ISR_RELLOCK + MEXITCOUNT + addl $8, %esp + POP_FRAME + iret +1: + lock + incl CNAME(forward_irq_misscnt) + call forward_irq /* Oops, we've lost the isr lock */ + MEXITCOUNT + POP_FRAME + iret +2: + lock + incl CNAME(forward_irq_toodeepcnt) +3: + ISR_RELLOCK + MEXITCOUNT + POP_FRAME + iret + +/* + * + */ +forward_irq: + MCOUNT + cmpl $0,_invltlb_ok + jz 4f + + cmpl $0, CNAME(forward_irq_enabled) + jz 4f + + movl _mp_lock,%eax + cmpl $FREE_LOCK,%eax + jne 1f + movl $0, %eax /* Pick CPU #0 if noone has lock */ +1: + shrl $24,%eax + movl _cpu_num_to_apic_id(,%eax,4),%ecx + shll $24,%ecx + movl lapic_icr_hi, %eax + andl $~APIC_ID_MASK, %eax + orl %ecx, %eax + movl %eax, lapic_icr_hi + +2: + movl lapic_icr_lo, %eax + andl $APIC_DELSTAT_MASK,%eax + jnz 2b + movl lapic_icr_lo, %eax + andl $APIC_RESV2_MASK, %eax + orl $(APIC_DEST_DESTFLD|APIC_DELMODE_FIXED|XFORWARD_IRQ_OFFSET), %eax + movl %eax, lapic_icr_lo +3: + movl lapic_icr_lo, %eax + andl $APIC_DELSTAT_MASK,%eax + jnz 3b +4: + ret /* * Executed by a CPU when it receives an Xcpustop IPI from another CPU, @@ -702,6 +955,16 @@ _checkstate_need_ast: .long 0 _checkstate_pending_ast: .long 0 + .globl CNAME(forward_irq_misscnt) + .globl CNAME(forward_irq_toodeepcnt) + .globl CNAME(forward_irq_hitcnt) +CNAME(forward_irq_misscnt): + .long 0 +CNAME(forward_irq_hitcnt): + .long 0 +CNAME(forward_irq_toodeepcnt): + .long 0 + .globl _apic_pin_trigger _apic_pin_trigger: diff --git a/sys/i386/i386/mp_apicdefs.s b/sys/i386/i386/mp_apicdefs.s index 9da62bf..e27839b 100644 --- a/sys/i386/i386/mp_apicdefs.s +++ b/sys/i386/i386/mp_apicdefs.s @@ -23,23 +23,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_apicdefs.s,v 1.1 1997/06/22 16:03:16 peter Exp $ + * $Id: mp_apicdefs.s,v 1.2 1997/10/24 14:27:23 phk Exp $ */ .globl lapic_eoi, lapic_svr, lapic_tpr, lapic_irr1, lapic_ver + .globl lapic_icr_lo,lapic_icr_hi,lapic_isr1 /* * Do not clutter our namespace with these unless we need them * outside the scope of locore.s */ #if 0 .globl lapic_id,lapic_ver,lapic_tpr,lapic_apr,lapic_ppr,lapic_eoi - .globl lapic_ldr,lapic_dfr,lapic_svr,lapic_isr,lapic_isr0,lapic_isr1 + .globl lapic_ldr,lapic_dfr,lapic_svr,lapic_isr,lapic_isr0 .globl lapic_isr2,lapic_isr3,lapic_isr4,lapic_isr5,lapic_isr6 .globl lapic_isr7,lapic_tmr,lapic_tmr0,lapic_tmr1,lapic_tmr2 .globl lapic_tmr3,lapic_tmr4,lapic_tmr5,lapic_tmr6,lapic_tmr7 .globl lapic_irr,lapic_irr0,lapic_irr1,lapic_irr2,lapic_irr3 .globl lapic_irr4,lapic_irr5,lapic_irr6,lapic_irr7,lapic_esr - .globl lapic_icr_lo,lapic_icr_hi,lapic_lvtt,lapic_pcint,lapic_lvt1 + .globl lapic_lvtt,lapic_pcint,lapic_lvt1 .globl lapic_lvt2,lapic_lvt3,lapic_ticr,lapic_tccr,lapic_tdcr #endif .set lapic_id, _lapic + 0x020 diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index 82ae434..d5bfeeb 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_machdep.c,v 1.67 1998/03/03 20:09:14 tegge Exp $ + * $Id: mp_machdep.c,v 1.68 1998/03/03 20:55:25 tegge Exp $ */ #include "opt_smp.h" @@ -246,6 +246,35 @@ extern int nkpt; u_int32_t cpu_apic_versions[NCPU]; u_int32_t io_apic_versions[NAPIC]; +#ifdef APIC_INTR_DIAGNOSTIC +int apic_itrace_enter[32]; +int apic_itrace_tryisrlock[32]; +int apic_itrace_gotisrlock[32]; +int apic_itrace_active[32]; +int apic_itrace_masked[32]; +int apic_itrace_noisrlock[32]; +int apic_itrace_masked2[32]; +int apic_itrace_unmask[32]; +int apic_itrace_noforward[32]; +int apic_itrace_leave[32]; +int apic_itrace_enter2[32]; +int apic_itrace_doreti[32]; +int apic_itrace_splz[32]; +int apic_itrace_eoi[32]; +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +unsigned short apic_itrace_debugbuffer[32768]; +int apic_itrace_debugbuffer_idx; +struct simplelock apic_itrace_debuglock; +#endif +#endif + +#ifdef APIC_INTR_REORDER +struct { + volatile int *location; + int bit; +} apic_isrbit_location[32]; +#endif + /* * APIC ID logical/physical mapping structures. * We oversize these to simplify boot-time config. @@ -575,6 +604,10 @@ mp_enable(u_int boot_addr) setidt(XCPUAST_OFFSET, Xcpuast, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for interrupt forwarding */ + setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -1537,6 +1570,10 @@ init_locks(void) /* ISR uses its own "giant lock" */ isr_lock = FREE_LOCK; +#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) + s_lock_init((struct simplelock*)&apic_itrace_debuglock); +#endif + s_lock_init((struct simplelock*)&mpintr_lock); s_lock_init((struct simplelock*)&mcount_lock); @@ -1995,6 +2032,11 @@ int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, &do_page_zero_idle, 0, ""); +/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ +int forward_irq_enabled = 1; +SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, + &forward_irq_enabled, 0, ""); + /* Enable forwarding of a signal to a process running on a different CPU */ int forward_signal_enabled = 1; SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, @@ -2438,3 +2480,20 @@ forward_signal(struct proc *p) return; } } + + +#ifdef APIC_INTR_REORDER +/* + * Maintain mapping from softintr vector to isr bit in local apic. + */ +void +set_lapic_isrloc(int intr, int vector) +{ + if (intr < 0 || intr > 32) + panic("set_apic_isrloc: bad intr argument: %d",intr); + if (vector < ICU_OFFSET || vector > 255) + panic("set_apic_isrloc: bad vector argument: %d",vector); + apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); + apic_isrbit_location[intr].bit = (1<<(vector & 31)); +} +#endif diff --git a/sys/i386/i386/mptable.c b/sys/i386/i386/mptable.c index 82ae434..d5bfeeb 100644 --- a/sys/i386/i386/mptable.c +++ b/sys/i386/i386/mptable.c @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_machdep.c,v 1.67 1998/03/03 20:09:14 tegge Exp $ + * $Id: mp_machdep.c,v 1.68 1998/03/03 20:55:25 tegge Exp $ */ #include "opt_smp.h" @@ -246,6 +246,35 @@ extern int nkpt; u_int32_t cpu_apic_versions[NCPU]; u_int32_t io_apic_versions[NAPIC]; +#ifdef APIC_INTR_DIAGNOSTIC +int apic_itrace_enter[32]; +int apic_itrace_tryisrlock[32]; +int apic_itrace_gotisrlock[32]; +int apic_itrace_active[32]; +int apic_itrace_masked[32]; +int apic_itrace_noisrlock[32]; +int apic_itrace_masked2[32]; +int apic_itrace_unmask[32]; +int apic_itrace_noforward[32]; +int apic_itrace_leave[32]; +int apic_itrace_enter2[32]; +int apic_itrace_doreti[32]; +int apic_itrace_splz[32]; +int apic_itrace_eoi[32]; +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +unsigned short apic_itrace_debugbuffer[32768]; +int apic_itrace_debugbuffer_idx; +struct simplelock apic_itrace_debuglock; +#endif +#endif + +#ifdef APIC_INTR_REORDER +struct { + volatile int *location; + int bit; +} apic_isrbit_location[32]; +#endif + /* * APIC ID logical/physical mapping structures. * We oversize these to simplify boot-time config. @@ -575,6 +604,10 @@ mp_enable(u_int boot_addr) setidt(XCPUAST_OFFSET, Xcpuast, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for interrupt forwarding */ + setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -1537,6 +1570,10 @@ init_locks(void) /* ISR uses its own "giant lock" */ isr_lock = FREE_LOCK; +#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) + s_lock_init((struct simplelock*)&apic_itrace_debuglock); +#endif + s_lock_init((struct simplelock*)&mpintr_lock); s_lock_init((struct simplelock*)&mcount_lock); @@ -1995,6 +2032,11 @@ int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, &do_page_zero_idle, 0, ""); +/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ +int forward_irq_enabled = 1; +SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, + &forward_irq_enabled, 0, ""); + /* Enable forwarding of a signal to a process running on a different CPU */ int forward_signal_enabled = 1; SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, @@ -2438,3 +2480,20 @@ forward_signal(struct proc *p) return; } } + + +#ifdef APIC_INTR_REORDER +/* + * Maintain mapping from softintr vector to isr bit in local apic. + */ +void +set_lapic_isrloc(int intr, int vector) +{ + if (intr < 0 || intr > 32) + panic("set_apic_isrloc: bad intr argument: %d",intr); + if (vector < ICU_OFFSET || vector > 255) + panic("set_apic_isrloc: bad vector argument: %d",vector); + apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); + apic_isrbit_location[intr].bit = (1<<(vector & 31)); +} +#endif diff --git a/sys/i386/include/mptable.h b/sys/i386/include/mptable.h index 82ae434..d5bfeeb 100644 --- a/sys/i386/include/mptable.h +++ b/sys/i386/include/mptable.h @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_machdep.c,v 1.67 1998/03/03 20:09:14 tegge Exp $ + * $Id: mp_machdep.c,v 1.68 1998/03/03 20:55:25 tegge Exp $ */ #include "opt_smp.h" @@ -246,6 +246,35 @@ extern int nkpt; u_int32_t cpu_apic_versions[NCPU]; u_int32_t io_apic_versions[NAPIC]; +#ifdef APIC_INTR_DIAGNOSTIC +int apic_itrace_enter[32]; +int apic_itrace_tryisrlock[32]; +int apic_itrace_gotisrlock[32]; +int apic_itrace_active[32]; +int apic_itrace_masked[32]; +int apic_itrace_noisrlock[32]; +int apic_itrace_masked2[32]; +int apic_itrace_unmask[32]; +int apic_itrace_noforward[32]; +int apic_itrace_leave[32]; +int apic_itrace_enter2[32]; +int apic_itrace_doreti[32]; +int apic_itrace_splz[32]; +int apic_itrace_eoi[32]; +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +unsigned short apic_itrace_debugbuffer[32768]; +int apic_itrace_debugbuffer_idx; +struct simplelock apic_itrace_debuglock; +#endif +#endif + +#ifdef APIC_INTR_REORDER +struct { + volatile int *location; + int bit; +} apic_isrbit_location[32]; +#endif + /* * APIC ID logical/physical mapping structures. * We oversize these to simplify boot-time config. @@ -575,6 +604,10 @@ mp_enable(u_int boot_addr) setidt(XCPUAST_OFFSET, Xcpuast, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for interrupt forwarding */ + setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -1537,6 +1570,10 @@ init_locks(void) /* ISR uses its own "giant lock" */ isr_lock = FREE_LOCK; +#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) + s_lock_init((struct simplelock*)&apic_itrace_debuglock); +#endif + s_lock_init((struct simplelock*)&mpintr_lock); s_lock_init((struct simplelock*)&mcount_lock); @@ -1995,6 +2032,11 @@ int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, &do_page_zero_idle, 0, ""); +/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ +int forward_irq_enabled = 1; +SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, + &forward_irq_enabled, 0, ""); + /* Enable forwarding of a signal to a process running on a different CPU */ int forward_signal_enabled = 1; SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, @@ -2438,3 +2480,20 @@ forward_signal(struct proc *p) return; } } + + +#ifdef APIC_INTR_REORDER +/* + * Maintain mapping from softintr vector to isr bit in local apic. + */ +void +set_lapic_isrloc(int intr, int vector) +{ + if (intr < 0 || intr > 32) + panic("set_apic_isrloc: bad intr argument: %d",intr); + if (vector < ICU_OFFSET || vector > 255) + panic("set_apic_isrloc: bad vector argument: %d",vector); + apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); + apic_isrbit_location[intr].bit = (1<<(vector & 31)); +} +#endif diff --git a/sys/i386/include/smp.h b/sys/i386/include/smp.h index 482b860..d921d23 100644 --- a/sys/i386/include/smp.h +++ b/sys/i386/include/smp.h @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: smp.h,v 1.36 1998/03/03 19:44:34 tegge Exp $ + * $Id: smp.h,v 1.37 1998/03/03 20:55:23 tegge Exp $ * */ @@ -137,6 +137,9 @@ void forward_statclock __P((int pscnt)); void forward_hardclock __P((int pscnt)); #endif /* BETTER_CLOCK */ void forward_signal __P((struct proc *)); +#ifdef APIC_INTR_REORDER +void set_lapic_isrloc __P((int, int)); +#endif /* APIC_INTR_REORDER */ /* global data in mpapic.c */ extern volatile lapic_t lapic; diff --git a/sys/i386/include/smptests.h b/sys/i386/include/smptests.h index da80b72..60a8588 100644 --- a/sys/i386/include/smptests.h +++ b/sys/i386/include/smptests.h @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: smptests.h,v 1.27 1997/09/07 23:06:15 fsmp Exp $ + * $Id: smptests.h,v 1.28 1997/12/08 22:56:49 fsmp Exp $ */ #ifndef _MACHINE_SMPTESTS_H_ @@ -250,6 +250,37 @@ */ #define GIANT_LOCK +#ifdef APIC_IO +/* + * Enable extra counters for some selected locations in the interrupt handlers. + * Look in apic_vector.s, apic_ipl.s and ipl.s for APIC_ITRACE or + * APIC_INTR_DIAGNOSTIC. + */ +#undef APIC_INTR_DIAGNOSTIC + +/* + * Add extra tracking of a specific interrupt. Look in apic_vector.s, + * apic_ipl.s and ipl.s for APIC_ITRACE and log_intr_event. + * APIC_INTR_DIAGNOSTIC must be defined for this to work. + */ +#ifdef APIC_INTR_DIAGNOSTIC +#define APIC_INTR_DIAGNOSTIC_IRQ 17 +#endif + +/* + * Don't assume that slow interrupt handler X is called from vector + * X + ICU_OFFSET. + */ +#define APIC_INTR_REORDER + +/* + * Redirect clock interrupts to a higher priority (fast intr) vector, + * while still using the slow interrupt handler. Only effective when + * APIC_INTR_REORDER is defined. + */ +#define APIC_INTR_HIGHPRI_CLOCK + +#endif /* APIC_IO */ /* * Misc. counters. diff --git a/sys/i386/isa/apic_ipl.s b/sys/i386/isa/apic_ipl.s index 7635445..bc38b47 100644 --- a/sys/i386/isa/apic_ipl.s +++ b/sys/i386/isa/apic_ipl.s @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: apic_ipl.s,v 1.16 1997/09/07 22:02:28 fsmp Exp $ + * $Id: apic_ipl.s,v 1.17 1997/12/15 02:18:33 tegge Exp $ */ @@ -195,6 +195,7 @@ _vec8254: lock /* MP-safe */ andl %eax, iactive MEXITCOUNT + APIC_ITRACE(apic_itrace_splz, 0, APIC_ITRACE_SPLZ) movl _Xintr8254, %eax jmp %eax /* XXX might need _Xfastintr# */ @@ -212,6 +213,7 @@ vec8: lock /* MP-safe */ andl $~IRQ_BIT(8), iactive /* lazy masking */ MEXITCOUNT + APIC_ITRACE(apic_itrace_splz, 8, APIC_ITRACE_SPLZ) jmp _Xintr8 /* XXX might need _Xfastintr8 */ /* @@ -229,6 +231,7 @@ __CONCAT(vec,irq_num): ; \ lock ; /* MP-safe */ \ andl $~IRQ_BIT(irq_num), iactive ; /* lazy masking */ \ MEXITCOUNT ; \ + APIC_ITRACE(apic_itrace_splz, irq_num, APIC_ITRACE_SPLZ) ; \ jmp __CONCAT(_Xintr,irq_num) diff --git a/sys/i386/isa/apic_vector.s b/sys/i386/isa/apic_vector.s index 4603440..05cf190 100644 --- a/sys/i386/isa/apic_vector.s +++ b/sys/i386/isa/apic_vector.s @@ -1,6 +1,6 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: apic_vector.s,v 1.25 1998/01/15 07:33:58 gibbs Exp $ + * $Id: apic_vector.s,v 1.26 1998/03/03 20:55:24 tegge Exp $ */ @@ -166,43 +166,64 @@ IDTVEC(vec_name) ; \ popal ; \ addl $4+4,%esp -/* - * Test to see whether we are handling an edge or level triggered INT. - * Level-triggered INTs must still be masked as we don't clear the source, - * and the EOI cycle would cause redundant INTs to occur. - */ -#define MASK_LEVEL_IRQ(irq_num) \ - testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ - jz 8f ; /* edge, don't mask */ \ +#define MASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ + testl $IRQ_BIT(irq_num), _apic_imen ; \ + jne 7f ; /* masked, don't mask */ \ orl $IRQ_BIT(irq_num), _apic_imen ; /* set the mask bit */ \ movl _ioapic, %ecx ; /* ioapic[0] addr */ \ movl $REDTBL_IDX(irq_num), (%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx), %eax ; /* current value */ \ orl $IOART_INTMASK, %eax ; /* set the mask */ \ movl %eax, IOAPIC_WINDOW(%ecx) ; /* new value */ \ - IMASK_UNLOCK ; \ -8: +7: ; /* already masked */ \ + IMASK_UNLOCK +/* + * Test to see whether we are handling an edge or level triggered INT. + * Level-triggered INTs must still be masked as we don't clear the source, + * and the EOI cycle would cause redundant INTs to occur. + */ +#define MASK_LEVEL_IRQ(irq_num) \ + testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ + jz 9f ; /* edge, don't mask */ \ + MASK_IRQ(irq_num) ; \ +9: + +#ifdef APIC_INTR_REORDER +#define EOI_IRQ(irq_num) \ + movl _apic_isrbit_location + 8 * (irq_num), %eax ; \ + movl (%eax), %eax ; \ + testl _apic_isrbit_location + 4 + 8 * (irq_num), %eax ; \ + jz 9f ; /* not active */ \ + movl $0, lapic_eoi ; \ + APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ +9: + +#else +#define EOI_IRQ(irq_num) \ + testl $IRQ_BIT(irq_num), lapic_isr1; \ + jz 9f ; /* not active */ \ + movl $0, lapic_eoi; \ + APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ +9: +#endif + + /* * Test to see if the source is currntly masked, clear if so. */ #define UNMASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ - jne 7f ; /* bit set, masked */ \ - testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ - jz 9f ; /* edge, don't EOI */ \ - movl $0, lapic_eoi ; /* should be safe */ \ - jmp 9f ; /* skip unmasking */ \ -7: \ + je 7f ; /* bit clear, not masked */ \ andl $~IRQ_BIT(irq_num), _apic_imen ;/* clear mask bit */ \ movl _ioapic,%ecx ; /* ioapic[0]addr */ \ movl $REDTBL_IDX(irq_num),(%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx),%eax ; /* current value */ \ andl $~IOART_INTMASK,%eax ; /* clear the mask */ \ movl %eax,IOAPIC_WINDOW(%ecx) ; /* new value */ \ -9: ; \ +7: ; \ IMASK_UNLOCK #ifdef INTR_SIMPLELOCK @@ -213,11 +234,75 @@ IDTVEC(vec_name) ; \ #define ENLOCK \ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ - jz 1f + jz 3f #define DELOCK ISR_RELLOCK #define LATELOCK #endif +#ifdef APIC_INTR_DIAGNOSTIC +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +log_intr_event: + pushf + cli + pushl $CNAME(apic_itrace_debuglock) + call _s_lock_np + addl $4, %esp + movl CNAME(apic_itrace_debugbuffer_idx), %ecx + andl $32767, %ecx + movl _cpuid, %eax + shll $8, %eax + orl 8(%esp), %eax + movw %ax, CNAME(apic_itrace_debugbuffer)(,%ecx,2) + incl %ecx + andl $32767, %ecx + movl %ecx, CNAME(apic_itrace_debugbuffer_idx) + pushl $CNAME(apic_itrace_debuglock) + call _s_unlock_np + addl $4, %esp + popf + ret + + +#define APIC_ITRACE(name, irq_num, id) \ + lock ; /* MP-safe */ \ + incl CNAME(name) + (irq_num) * 4 ; \ + pushl %eax ; \ + pushl %ecx ; \ + pushl %edx ; \ + movl $(irq_num), %eax ; \ + cmpl $APIC_INTR_DIAGNOSTIC_IRQ, %eax ; \ + jne 7f ; \ + pushl $id ; \ + call log_intr_event ; \ + addl $4, %esp ; \ +7: ; \ + popl %edx ; \ + popl %ecx ; \ + popl %eax +#else +#define APIC_ITRACE(name, irq_num, id) \ + lock ; /* MP-safe */ \ + incl CNAME(name) + (irq_num) * 4 +#endif + +#define APIC_ITRACE_ENTER 1 +#define APIC_ITRACE_EOI 2 +#define APIC_ITRACE_TRYISRLOCK 3 +#define APIC_ITRACE_GOTISRLOCK 4 +#define APIC_ITRACE_ENTER2 5 +#define APIC_ITRACE_LEAVE 6 +#define APIC_ITRACE_UNMASK 7 +#define APIC_ITRACE_ACTIVE 8 +#define APIC_ITRACE_MASKED 9 +#define APIC_ITRACE_NOISRLOCK 10 +#define APIC_ITRACE_MASKED2 11 +#define APIC_ITRACE_SPLZ 12 +#define APIC_ITRACE_DORETI 13 + +#else +#define APIC_ITRACE(name, irq_num, id) +#endif + #ifdef CPL_AND_CML #define INTR(irq_num, vec_name) \ @@ -230,12 +315,18 @@ IDTVEC(vec_name) ; \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ + APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ + MASK_LEVEL_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ +0: ; \ + APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ENLOCK ; \ ; \ + APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ @@ -244,7 +335,6 @@ IDTVEC(vec_name) ; \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ ; \ -;;; movl $0, lapic_eoi ; /* XXX too soon? */ \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ @@ -263,39 +353,67 @@ __CONCAT(Xresume,irq_num): ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ incl _inside_intr ; \ + APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ + APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ decl _inside_intr ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ lock ; andl $~IRQ_BIT(irq_num), _cil ; \ UNMASK_IRQ(irq_num) ; \ + APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ LATELOCK ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ -1: ; /* active or locked */ \ - MASK_LEVEL_IRQ(irq_num) ; \ - movl $0, lapic_eoi ; /* do the EOI */ \ -; \ +1: ; /* active */ \ + APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ -; \ + MASK_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ + btsl $(irq_num), iactive ; /* still active */ \ + jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; /* masked by cpl|cml */ \ + APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ + orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ DELOCK ; /* XXX this is going away... */ \ - jmp 1b + POP_FRAME ; \ + iret ; \ + ALIGN_TEXT ; \ +3: ; /* other cpu has isr lock */ \ + APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ + AVCPL_LOCK ; /* MP-safe */ \ + orl $IRQ_BIT(irq_num), _ipending ; \ + testl $IRQ_BIT(irq_num), _cpl ; \ + jne 4f ; /* this INT masked */ \ + testl $IRQ_BIT(irq_num), _cml ; \ + jne 4f ; /* this INT masked */ \ + orl $IRQ_BIT(irq_num), _cil ; \ + AVCPL_UNLOCK ; \ + call forward_irq ; /* forward irq to lock holder */ \ + POP_FRAME ; /* and return */ \ + iret ; \ + ALIGN_TEXT ; \ +4: ; /* blocked */ \ + APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ + AVCPL_UNLOCK ; \ + POP_FRAME ; /* and return */ \ + iret #else /* CPL_AND_CML */ + #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ @@ -306,20 +424,25 @@ IDTVEC(vec_name) ; \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ + APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ + MASK_LEVEL_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ +0: ; \ + APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ - jz 1f ; /* no */ \ + jz 3f ; /* no */ \ ; \ + APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ ; \ -;;; movl $0, lapic_eoi ; /* XXX too soon? */ \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ @@ -334,36 +457,60 @@ __CONCAT(Xresume,irq_num): ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cpl ; \ + andl $~IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ + APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ + APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ UNMASK_IRQ(irq_num) ; \ + APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ -1: ; /* active or locked */ \ - MASK_LEVEL_IRQ(irq_num) ; \ - movl $0, lapic_eoi ; /* do the EOI */ \ -; \ +1: ; /* active */ \ + APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ -; \ + MASK_IRQ(irq_num) ; \ + EOI_IRQ(irq_num) ; \ + btsl $(irq_num), iactive ; /* still active */ \ + jnc 0b ; /* retry */ \ POP_FRAME ; \ - iret ; \ -; \ + iret ; /* XXX: iactive bit might be 0 now */ \ ALIGN_TEXT ; \ -2: ; /* masked by cpl */ \ +2: ; /* masked by cpl, leave iactive set */ \ + APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ + orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ISR_RELLOCK ; /* XXX this is going away... */ \ - jmp 1b + POP_FRAME ; \ + iret ; \ + ALIGN_TEXT ; \ +3: ; /* other cpu has isr lock */ \ + APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ + AVCPL_LOCK ; /* MP-safe */ \ + orl $IRQ_BIT(irq_num), _ipending ; \ + testl $IRQ_BIT(irq_num), _cpl ; \ + jne 4f ; /* this INT masked */ \ + AVCPL_UNLOCK ; \ + call forward_irq ; /* forward irq to lock holder */ \ + POP_FRAME ; /* and return */ \ + iret ; \ + ALIGN_TEXT ; \ +4: ; /* blocked */ \ + APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ + AVCPL_UNLOCK ; \ + POP_FRAME ; /* and return */ \ + iret #endif /* CPL_AND_CML */ @@ -515,6 +662,8 @@ _Xcpuast: movl _cpl, %eax #endif pushl %eax + lock + orl $SWI_AST_PENDING, _ipending AVCPL_UNLOCK lock incb _intr_nesting_level @@ -522,9 +671,6 @@ _Xcpuast: pushl $0 - lock - orl $SWI_AST_PENDING, _ipending - movl _cpuid, %eax lock btrl %eax, _checkstate_pending_ast @@ -536,6 +682,113 @@ _Xcpuast: POP_FRAME iret + +/* + * Executed by a CPU when it receives an XFORWARD_IRQ IPI. + */ + + .text + SUPERALIGN_TEXT + .globl _Xforward_irq +_Xforward_irq: + PUSH_FRAME + movl $KDSEL, %eax + movl %ax, %ds /* use KERNEL data segment */ + movl %ax, %es + + movl $0, lapic_eoi /* End Of Interrupt to APIC */ + + FAKE_MCOUNT(12*4(%esp)) + + ISR_TRYLOCK + testl %eax,%eax /* Did we get the lock ? */ + jz 1f /* No */ + + lock + incl CNAME(forward_irq_hitcnt) + cmpb $4, _intr_nesting_level + jae 2f + + jmp 3f + + AVCPL_LOCK +#ifdef CPL_AND_CML + movl _cml, %eax +#else + movl _cpl, %eax +#endif + pushl %eax + AVCPL_UNLOCK + lock + incb _intr_nesting_level + sti + + pushl $0 + + MEXITCOUNT + jmp _doreti /* Handle forwarded interrupt */ +4: + lock + decb _intr_nesting_level + ISR_RELLOCK + MEXITCOUNT + addl $8, %esp + POP_FRAME + iret +1: + lock + incl CNAME(forward_irq_misscnt) + call forward_irq /* Oops, we've lost the isr lock */ + MEXITCOUNT + POP_FRAME + iret +2: + lock + incl CNAME(forward_irq_toodeepcnt) +3: + ISR_RELLOCK + MEXITCOUNT + POP_FRAME + iret + +/* + * + */ +forward_irq: + MCOUNT + cmpl $0,_invltlb_ok + jz 4f + + cmpl $0, CNAME(forward_irq_enabled) + jz 4f + + movl _mp_lock,%eax + cmpl $FREE_LOCK,%eax + jne 1f + movl $0, %eax /* Pick CPU #0 if noone has lock */ +1: + shrl $24,%eax + movl _cpu_num_to_apic_id(,%eax,4),%ecx + shll $24,%ecx + movl lapic_icr_hi, %eax + andl $~APIC_ID_MASK, %eax + orl %ecx, %eax + movl %eax, lapic_icr_hi + +2: + movl lapic_icr_lo, %eax + andl $APIC_DELSTAT_MASK,%eax + jnz 2b + movl lapic_icr_lo, %eax + andl $APIC_RESV2_MASK, %eax + orl $(APIC_DEST_DESTFLD|APIC_DELMODE_FIXED|XFORWARD_IRQ_OFFSET), %eax + movl %eax, lapic_icr_lo +3: + movl lapic_icr_lo, %eax + andl $APIC_DELSTAT_MASK,%eax + jnz 3b +4: + ret /* * Executed by a CPU when it receives an Xcpustop IPI from another CPU, @@ -702,6 +955,16 @@ _checkstate_need_ast: .long 0 _checkstate_pending_ast: .long 0 + .globl CNAME(forward_irq_misscnt) + .globl CNAME(forward_irq_toodeepcnt) + .globl CNAME(forward_irq_hitcnt) +CNAME(forward_irq_misscnt): + .long 0 +CNAME(forward_irq_hitcnt): + .long 0 +CNAME(forward_irq_toodeepcnt): + .long 0 + .globl _apic_pin_trigger _apic_pin_trigger: diff --git a/sys/i386/isa/intr_machdep.c b/sys/i386/isa/intr_machdep.c index 4a593ea7..0cdbfc0 100644 --- a/sys/i386/isa/intr_machdep.c +++ b/sys/i386/isa/intr_machdep.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.7 1997/09/28 15:48:34 mckay Exp $ + * $Id: intr_machdep.c,v 1.8 1998/02/09 06:08:30 eivind Exp $ */ #include "opt_auto_eoi.h" @@ -444,19 +444,30 @@ icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags) vector = TPR_FAST_INTS + intr; setidt(vector, fastintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* - * XXX MULTIPLE_IOAPICSXXX - * Reprogram the vector in the IO APIC. - */ - select = (intr * 2) + IOAPIC_REDTBL0; - value = io_apic_read(0, select) & ~IOART_INTVEC; - io_apic_write(0, select, value | vector); } - else - setidt(TPR_SLOW_INTS + intr, slowintr[intr], + else { + vector = TPR_SLOW_INTS + intr; +#ifdef APIC_INTR_REORDER +#ifdef APIC_INTR_HIGHPRI_CLOCK + /* XXX: Hack (kludge?) for more accurate clock. */ + if (intr == 0 || intr == 8) { + vector = TPR_FAST_INTS + intr; + } +#endif +#endif + setidt(vector, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - + } +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, vector); +#endif + /* + * XXX MULTIPLE_IOAPICSXXX + * Reprogram the vector in the IO APIC. + */ + select = (intr * 2) + IOAPIC_REDTBL0; + value = io_apic_read(0, select) & ~IOART_INTVEC; + io_apic_write(0, select, value | vector); #else setidt(ICU_OFFSET + intr, flags & INTR_FAST ? fastintr[intr] : slowintr[intr], @@ -505,6 +516,9 @@ icu_unset(intr, handler) setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #else /* FAST_HI */ +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, ICU_OFFSET + intr); +#endif setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #endif /* FAST_HI */ diff --git a/sys/i386/isa/intr_machdep.h b/sys/i386/isa/intr_machdep.h index 7714c0d..97122e6 100644 --- a/sys/i386/isa/intr_machdep.h +++ b/sys/i386/isa/intr_machdep.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * $Id: intr_machdep.h,v 1.9 1998/02/13 06:59:22 bde Exp $ + * $Id: intr_machdep.h,v 1.10 1998/03/03 20:55:24 tegge Exp $ */ #ifndef _I386_ISA_INTR_MACHDEP_H_ @@ -116,6 +116,9 @@ /* IPI to generate an additional software trap at the target CPU */ #define XCPUAST_OFFSET (ICU_OFFSET + 48) +/* IPI to signal the CPU holding the ISR lock that another IRQ has appeared */ +#define XFORWARD_IRQ_OFFSET (ICU_OFFSET + 49) + /* IPI to signal CPUs to stop and wait for another CPU to restart them */ #define XCPUSTOP_OFFSET (ICU_OFFSET + 128) @@ -174,6 +177,7 @@ inthand_t Xcpucheckstate, /* Check cpu state */ #endif Xcpuast, /* Additional software trap on other cpu */ + Xforward_irq, /* Forward irq to cpu holding ISR lock */ Xcpustop, /* CPU stops & waits for another CPU to restart it */ Xspuriousint; /* handle APIC "spurious INTs" */ diff --git a/sys/i386/isa/ipl.s b/sys/i386/isa/ipl.s index 38e6934..bd586ee 100644 --- a/sys/i386/isa/ipl.s +++ b/sys/i386/isa/ipl.s @@ -36,7 +36,7 @@ * * @(#)ipl.s * - * $Id: ipl.s,v 1.18 1997/10/13 00:01:53 fsmp Exp $ + * $Id: ipl.s,v 1.19 1997/12/15 02:18:35 tegge Exp $ */ @@ -263,6 +263,9 @@ doreti_unpend: cli #ifdef SMP pushl %edx /* preserve %edx */ +#ifdef APIC_INTR_DIAGNOSTIC + pushl %ecx +#endif pushl %eax /* preserve %eax */ ICPL_LOCK #ifdef CPL_AND_CML @@ -271,11 +274,32 @@ doreti_unpend: popl _cpl #endif FAST_ICPL_UNLOCK +#ifdef APIC_INTR_DIAGNOSTIC + popl %ecx +#endif popl %edx #else movl %eax,_cpl #endif MEXITCOUNT +#ifdef APIC_INTR_DIAGNOSTIC + lock + incl CNAME(apic_itrace_doreti)(,%ecx,4) +#ifdef APIC_INTR_DIAGNOSTIC_IRQ + cmpl $APIC_INTR_DIAGNOSTIC_IRQ,%ecx + jne 9f + pushl %eax + pushl %ecx + pushl %edx + pushl $APIC_ITRACE_DORETI + call log_intr_event + addl $4,%esp + popl %edx + popl %ecx + popl %eax +9: +#endif +#endif jmp %edx ALIGN_TEXT diff --git a/sys/i386/isa/nmi.c b/sys/i386/isa/nmi.c index 4a593ea7..0cdbfc0 100644 --- a/sys/i386/isa/nmi.c +++ b/sys/i386/isa/nmi.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.7 1997/09/28 15:48:34 mckay Exp $ + * $Id: intr_machdep.c,v 1.8 1998/02/09 06:08:30 eivind Exp $ */ #include "opt_auto_eoi.h" @@ -444,19 +444,30 @@ icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags) vector = TPR_FAST_INTS + intr; setidt(vector, fastintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* - * XXX MULTIPLE_IOAPICSXXX - * Reprogram the vector in the IO APIC. - */ - select = (intr * 2) + IOAPIC_REDTBL0; - value = io_apic_read(0, select) & ~IOART_INTVEC; - io_apic_write(0, select, value | vector); } - else - setidt(TPR_SLOW_INTS + intr, slowintr[intr], + else { + vector = TPR_SLOW_INTS + intr; +#ifdef APIC_INTR_REORDER +#ifdef APIC_INTR_HIGHPRI_CLOCK + /* XXX: Hack (kludge?) for more accurate clock. */ + if (intr == 0 || intr == 8) { + vector = TPR_FAST_INTS + intr; + } +#endif +#endif + setidt(vector, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - + } +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, vector); +#endif + /* + * XXX MULTIPLE_IOAPICSXXX + * Reprogram the vector in the IO APIC. + */ + select = (intr * 2) + IOAPIC_REDTBL0; + value = io_apic_read(0, select) & ~IOART_INTVEC; + io_apic_write(0, select, value | vector); #else setidt(ICU_OFFSET + intr, flags & INTR_FAST ? fastintr[intr] : slowintr[intr], @@ -505,6 +516,9 @@ icu_unset(intr, handler) setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #else /* FAST_HI */ +#ifdef APIC_INTR_REORDER + set_lapic_isrloc(intr, ICU_OFFSET + intr); +#endif setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); #endif /* FAST_HI */ diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c index 82ae434..d5bfeeb 100644 --- a/sys/kern/subr_smp.c +++ b/sys/kern/subr_smp.c @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mp_machdep.c,v 1.67 1998/03/03 20:09:14 tegge Exp $ + * $Id: mp_machdep.c,v 1.68 1998/03/03 20:55:25 tegge Exp $ */ #include "opt_smp.h" @@ -246,6 +246,35 @@ extern int nkpt; u_int32_t cpu_apic_versions[NCPU]; u_int32_t io_apic_versions[NAPIC]; +#ifdef APIC_INTR_DIAGNOSTIC +int apic_itrace_enter[32]; +int apic_itrace_tryisrlock[32]; +int apic_itrace_gotisrlock[32]; +int apic_itrace_active[32]; +int apic_itrace_masked[32]; +int apic_itrace_noisrlock[32]; +int apic_itrace_masked2[32]; +int apic_itrace_unmask[32]; +int apic_itrace_noforward[32]; +int apic_itrace_leave[32]; +int apic_itrace_enter2[32]; +int apic_itrace_doreti[32]; +int apic_itrace_splz[32]; +int apic_itrace_eoi[32]; +#ifdef APIC_INTR_DIAGNOSTIC_IRQ +unsigned short apic_itrace_debugbuffer[32768]; +int apic_itrace_debugbuffer_idx; +struct simplelock apic_itrace_debuglock; +#endif +#endif + +#ifdef APIC_INTR_REORDER +struct { + volatile int *location; + int bit; +} apic_isrbit_location[32]; +#endif + /* * APIC ID logical/physical mapping structures. * We oversize these to simplify boot-time config. @@ -575,6 +604,10 @@ mp_enable(u_int boot_addr) setidt(XCPUAST_OFFSET, Xcpuast, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for interrupt forwarding */ + setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -1537,6 +1570,10 @@ init_locks(void) /* ISR uses its own "giant lock" */ isr_lock = FREE_LOCK; +#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) + s_lock_init((struct simplelock*)&apic_itrace_debuglock); +#endif + s_lock_init((struct simplelock*)&mpintr_lock); s_lock_init((struct simplelock*)&mcount_lock); @@ -1995,6 +2032,11 @@ int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, &do_page_zero_idle, 0, ""); +/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ +int forward_irq_enabled = 1; +SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, + &forward_irq_enabled, 0, ""); + /* Enable forwarding of a signal to a process running on a different CPU */ int forward_signal_enabled = 1; SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, @@ -2438,3 +2480,20 @@ forward_signal(struct proc *p) return; } } + + +#ifdef APIC_INTR_REORDER +/* + * Maintain mapping from softintr vector to isr bit in local apic. + */ +void +set_lapic_isrloc(int intr, int vector) +{ + if (intr < 0 || intr > 32) + panic("set_apic_isrloc: bad intr argument: %d",intr); + if (vector < ICU_OFFSET || vector > 255) + panic("set_apic_isrloc: bad vector argument: %d",vector); + apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); + apic_isrbit_location[intr].bit = (1<<(vector & 31)); +} +#endif diff --git a/sys/sys/smp.h b/sys/sys/smp.h index 482b860..d921d23 100644 --- a/sys/sys/smp.h +++ b/sys/sys/smp.h @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: smp.h,v 1.36 1998/03/03 19:44:34 tegge Exp $ + * $Id: smp.h,v 1.37 1998/03/03 20:55:23 tegge Exp $ * */ @@ -137,6 +137,9 @@ void forward_statclock __P((int pscnt)); void forward_hardclock __P((int pscnt)); #endif /* BETTER_CLOCK */ void forward_signal __P((struct proc *)); +#ifdef APIC_INTR_REORDER +void set_lapic_isrloc __P((int, int)); +#endif /* APIC_INTR_REORDER */ /* global data in mpapic.c */ extern volatile lapic_t lapic; |