MP Implementation 2/4: Implement a poor-man's IPI messaging subsystem,
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 8 Jul 2003 06:27:28 +0000 (06:27 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 8 Jul 2003 06:27:28 +0000 (06:27 +0000)
get both cpus arbitrating the BGL for interrupts, IPIing foreign
cpu LWKT scheduling requests without crashing, and dealing with the cpl.

The APs are in a slightly less degenerate state now, but hardclock and
statclock distribution is broken, only one user process is being scheduled
at a time, and priorities are all messed up.

67 files changed:
sys/cpu/i386/include/db_machdep.h
sys/ddb/db_ps.c
sys/ddb/ddb.h
sys/i386/apic/apic_vector.s
sys/i386/apic/mpapic.c
sys/i386/i386/exception.s
sys/i386/i386/genassym.c
sys/i386/i386/globals.s
sys/i386/i386/locore.s
sys/i386/i386/machdep.c
sys/i386/i386/mp_machdep.c
sys/i386/i386/mpapic.c
sys/i386/i386/mplock.s
sys/i386/i386/swtch.s
sys/i386/i386/trap.c
sys/i386/i386/vm86.c
sys/i386/i386/vm86bios.s
sys/i386/i386/vm_machdep.c
sys/i386/icu/icu_vector.s
sys/i386/include/apic.h
sys/i386/include/db_machdep.h
sys/i386/include/globaldata.h
sys/i386/include/ipl.h
sys/i386/include/lock.h
sys/i386/include/smp.h
sys/i386/include/thread.h
sys/i386/isa/apic_vector.s
sys/i386/isa/icu_vector.s
sys/i386/isa/intr_machdep.c
sys/i386/isa/intr_machdep.h
sys/i386/isa/ipl.s
sys/i386/isa/npx.c
sys/kern/kern_intr.c
sys/kern/lwkt_thread.c
sys/platform/pc32/apic/apic_vector.s
sys/platform/pc32/apic/mpapic.c
sys/platform/pc32/i386/exception.s
sys/platform/pc32/i386/genassym.c
sys/platform/pc32/i386/globals.s
sys/platform/pc32/i386/locore.s
sys/platform/pc32/i386/machdep.c
sys/platform/pc32/i386/mp_machdep.c
sys/platform/pc32/i386/mpapic.c
sys/platform/pc32/i386/mplock.s
sys/platform/pc32/i386/swtch.s
sys/platform/pc32/i386/trap.c
sys/platform/pc32/i386/vm86.c
sys/platform/pc32/i386/vm86bios.s
sys/platform/pc32/i386/vm_machdep.c
sys/platform/pc32/icu/icu_vector.s
sys/platform/pc32/include/apic.h
sys/platform/pc32/include/globaldata.h
sys/platform/pc32/include/ipl.h
sys/platform/pc32/include/lock.h
sys/platform/pc32/include/smp.h
sys/platform/pc32/include/thread.h
sys/platform/pc32/isa/apic_vector.s
sys/platform/pc32/isa/icu_vector.s
sys/platform/pc32/isa/intr_machdep.c
sys/platform/pc32/isa/intr_machdep.h
sys/platform/pc32/isa/ipl.s
sys/platform/pc32/isa/npx.c
sys/platform/vkernel/i386/genassym.c
sys/sys/globaldata.h
sys/sys/interrupt.h
sys/sys/thread.h
sys/sys/thread2.h

index 5f7887e..9adc353 100644 (file)
@@ -24,7 +24,7 @@
  * the rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/i386/include/db_machdep.h,v 1.16 1999/10/04 13:55:35 marcel Exp $
- * $DragonFly: src/sys/cpu/i386/include/db_machdep.h,v 1.2 2003/06/17 04:28:35 dillon Exp $
+ * $DragonFly: src/sys/cpu/i386/include/db_machdep.h,v 1.3 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_DB_MACHDEP_H_
@@ -33,6 +33,7 @@
 #include <machine/frame.h>
 #include <machine/psl.h>
 #include <machine/trap.h>
+#include <machine/globaldata.h>
 
 #define i386_saved_state trapframe
 
index 482b543..0d3d815 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/ddb/db_ps.c,v 1.20 1999/08/28 00:41:09 peter Exp $
- * $DragonFly: src/sys/ddb/db_ps.c,v 1.5 2003/06/30 19:50:28 dillon Exp $
+ * $DragonFly: src/sys/ddb/db_ps.c,v 1.6 2003/07/08 06:27:23 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -48,6 +48,7 @@ db_ps(dummy1, dummy2, dummy3, dummy4)
        char *          dummy4;
 {
        int np;
+       int cpuidx;
        int nl = 0;
        volatile struct proc *p, *pp;
 
@@ -111,19 +112,40 @@ db_ps(dummy1, dummy2, dummy3, dummy4)
        /*
         * Dump running threads
         */
-       db_printf("cpu %d tdrunqmask %08x\n", mycpu->gd_cpuid, mycpu->gd_runqmask);
-       db_printf("  tdq     thread    pid flags  pri(act)        sp    wmesg comm\n");
-       for (np = 0; np < 32; ++np) {
-               thread_t td;
-               TAILQ_FOREACH(td, &mycpu->gd_tdrunq[np], td_threadq) {
-                       db_printf("  %3d %p %3d %08x %3d(%3d) %p %8.8s %s\n",
-                               np, td, 
-                               (td->td_proc ? td->td_proc->p_pid : -1),
-                               td->td_flags, td->td_pri,
-                               td->td_pri & TDPRI_MASK,
-                               td->td_sp,
-                               td->td_wmesg ? td->td_wmesg : "-",
-                               td->td_proc ? td->td_proc->p_comm : td->td_comm);
+       for (cpuidx = 0; cpuidx < ncpus; ++cpuidx) {
+           thread_t td;
+           struct globaldata *gd = &CPU_prvspace[cpuidx].mdglobaldata.mi;
+
+           db_printf("cpu %d tdrunqmask %08x\n", gd->gd_cpuid, gd->gd_runqmask);
+           db_printf("  tdq     thread    pid flags  pri(act)        sp    wmesg comm\n");
+           for (np = 0; np < 32; ++np) {
+               TAILQ_FOREACH(td, &gd->gd_tdrunq[np], td_threadq) {
+                   db_printf("  %3d %p %3d %08x %3d(%3d) %p %8.8s %s\n",
+                       np, td, 
+                       (td->td_proc ? td->td_proc->p_pid : -1),
+                       td->td_flags, td->td_pri,
+                       td->td_pri & TDPRI_MASK,
+                       td->td_sp,
+                       td->td_wmesg ? td->td_wmesg : "-",
+                       td->td_proc ? td->td_proc->p_comm : td->td_comm);
                }
+           }
+           db_printf("\n");
+           db_printf("  tdq     thread    pid flags  pri(act)        sp    wmesg comm\n");
+           TAILQ_FOREACH(td, &gd->gd_tdallq, td_allq) {
+               db_printf("  %3d %p %3d %08x %3d(%3d) %p %8.8s %s\n",
+                   np, td, 
+                   (td->td_proc ? td->td_proc->p_pid : -1),
+                   td->td_flags, td->td_pri,
+                   td->td_pri & TDPRI_MASK,
+                   td->td_sp,
+                   td->td_wmesg ? td->td_wmesg : "-",
+                   td->td_proc ? td->td_proc->p_comm : td->td_comm);
+           }
        }
+       printf("CURCPU %d CURTHREAD %p (%d)\n",
+           mycpu->gd_cpuid,
+           curthread,
+           (curthread->td_proc ? curthread->td_proc->p_pid : -1)
+       );
 }
index 5850e9d..89fca10 100644 (file)
@@ -28,7 +28,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/ddb/ddb.h,v 1.24.2.2 2002/08/30 22:27:49 gibbs Exp $
- * $DragonFly: src/sys/ddb/ddb.h,v 1.2 2003/06/17 04:28:21 dillon Exp $
+ * $DragonFly: src/sys/ddb/ddb.h,v 1.3 2003/07/08 06:27:23 dillon Exp $
  */
 
 /*
@@ -38,6 +38,7 @@
 #ifndef _DDB_DDB_H_
 #define        _DDB_DDB_H_
 
+#include <sys/queue.h>
 #include <machine/db_machdep.h>                /* type definitions */
 
 typedef void db_cmdfcn_t __P((db_expr_t addr, boolean_t have_addr,
index 6bc664a..ca7208c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/apic_vector.s,v 1.47.2.5 2001/09/01 22:33:38 tegge Exp $
- * $DragonFly: src/sys/i386/apic/Attic/apic_vector.s,v 1.8 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/apic/Attic/apic_vector.s,v 1.9 2003/07/08 06:27:27 dillon Exp $
  */
 
 
@@ -38,7 +38,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -53,7 +53,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define IOAPICADDR(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 8
 #define REDIRIDX(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 12
@@ -165,6 +165,10 @@ IDTVEC(vec_name) ;                                                 \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
+       /* try to get giant */                                          \
+       call    try_mplock ;                                            \
+       testl   %eax,%eax ;                                             \
+       jz      1b ;                                                    \
        /* clear pending bit, run handler */                            \
        addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        andl    $~IRQ_LBIT(irq_num),PCPU(fpending) ;                    \
@@ -175,6 +179,7 @@ IDTVEC(vec_name) ;                                                  \
        incl    PCPU(cnt)+V_INTR ;      /* book-keeping make per cpu YYY */ \
        movl    intr_countp + (irq_num) * 4, %eax ;                     \
        incl    (%eax) ;                                                \
+       call    rel_mplock ;                                            \
        UNMASK_IRQ(irq_num) ;                                           \
 5: ;                                                                   \
        MEXITCOUNT ;                                                    \
@@ -190,6 +195,8 @@ IDTVEC(vec_name) ;                                                  \
  *     - Unmask the interrupt
  *     - Pop the dummy frame and do a normal return
  *
+ *     The BGL is held on call and left held on return.
+ *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
  */
@@ -221,17 +228,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule the thread.  Leave
- *       interrupts masked and doreti.
- *
- *     the interrupt thread will run its handlers and loop if
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule the thread.  Leave interrupts masked and doreti.
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
- *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
+ *     Note that calls to sched_ithd() are made with interrupts enabled
+ *     and outside a critical section.  YYY sched_ithd may preempt us
+ *     synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
@@ -252,25 +254,20 @@ IDTVEC(vec_name) ;                                                        \
        pushl   %eax ;          /* cpl do restore */                    \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num),%eax ;                               \
-       jz      1f ;                                                    \
+       jz      2f ;                                                    \
 1: ;                                                                   \
        /* set the pending bit and return, leave the interrupt masked */ \
        orl     $IRQ_LBIT(irq_num), PCPU(ipending) ;                    \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -281,8 +278,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -291,7 +287,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(irq_num) ;                                           \
        popl %ebp ;                                                     \
        ret ;                                                           \
@@ -455,7 +450,7 @@ Xcpuast:
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
        orl     $AST_PENDING, PCPU(astpending)  /* XXX */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        movl    PCPU(cpuid), %eax
@@ -497,7 +492,7 @@ Xforward_irq:
        movl    PCPU(curthread), %eax
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        MEXITCOUNT
@@ -552,7 +547,7 @@ forward_irq:
        jnz     3b
 4:             
        ret
-       
+
 /*
  * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
  *
@@ -620,6 +615,35 @@ Xcpustop:
        popl    %ebp
        iret
 
+       /*
+        * For now just have one ipiq IPI, but what we really want is
+        * to have one for each source cpu to the APICs don't get stalled
+        * backlogging the requests.
+        */
+       .text
+       SUPERALIGN_TEXT
+       .globl Xipiq
+Xipiq:
+       PUSH_FRAME
+       movl    $0, lapic_eoi           /* End Of Interrupt to APIC */
+       FAKE_MCOUNT(13*4(%esp))
+
+       movl    PCPU(curthread),%ebx
+       cmpl    $TDPRI_CRIT,TD_PRI(%ebx)
+       jge     1f
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
+       call    lwkt_process_ipiq
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
+       pushl   TD_CPL(%ebx)
+       incl    PCPU(intr_nesting_level)
+       MEXITCOUNT
+       jmp     doreti
+1:
+       movl    $TDPRI_CRIT,PCPU(reqpri)
+       orl     $AST_IPIQ,PCPU(astpending)
+       MEXITCOUNT
+       POP_FRAME
+       iret
 
 MCOUNT_LABEL(bintr)
        FAST_INTR(0,fastintr0)
@@ -792,8 +816,6 @@ CNAME(resched_cpus):
 CNAME(cpustop_restartfunc):
        .long 0
                
-
-
        .globl  apic_pin_trigger
 apic_pin_trigger:
        .long   0
index c4e2a9c..638b7a9 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/mpapic.c,v 1.37.2.7 2003/01/25 02:31:47 peter Exp $
- * $DragonFly: src/sys/i386/apic/Attic/mpapic.c,v 1.4 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/apic/Attic/mpapic.c,v 1.5 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -33,6 +33,7 @@
 #include <machine/smp.h>
 #include <machine/mpapic.h>
 #include <machine/segments.h>
+#include <sys/thread2.h>
 
 #include <i386/isa/intr_machdep.h>     /* Xspuriousint() */
 
@@ -79,8 +80,10 @@ apic_initialize(void)
         * Leave the BSP and TPR 0 during boot so it gets all the interrupts,
         * set APs at TPR 0xF0 at boot so they get no ints.
         */
+#if 0
        if (mycpu->gd_cpuid != 0)
                temp |= TPR_IPI_ONLY;   /* disable INTs on this cpu */
+#endif
        lapic.tpr = temp;
 
        /* enable the local APIC */
@@ -484,63 +487,33 @@ imen_dump(void)
  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
  *  vector is any valid SYSTEM INT vector
  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ *
+ * A backlog of requests can create a deadlock between cpus.  To avoid this
+ * we have to be able to accept IPIs at the same time we are trying to send
+ * them.  The critical section prevents us from attempting to send additional
+ * IPIs reentrantly, but also prevents IPIQ processing so we have to call
+ * lwkt_process_ipiq() manually.  It's rather messy and expensive for this
+ * to occur but fortunately it does not happen too often.
  */
-#define DETECT_DEADLOCK
 int
 apic_ipi(int dest_type, int vector, int delivery_mode)
 {
        u_long  icr_lo;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       crit_enter();
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       /* build IRC_LOW */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
-           | dest_type | delivery_mode | vector;
 
-       /* write APIC ICR */
+       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) | dest_type | 
+               delivery_mode | vector;
        lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
+       crit_exit();
        return 0;
 }
 
@@ -549,24 +522,15 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 {
        u_long  icr_lo;
        u_long  icr_hi;
-       u_long  eflags;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       eflags = read_eflags();
-       __asm __volatile("cli" : : : "memory");
        icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
        icr_hi |= (CPU_TO_ID(cpu) << 24);
        lapic.icr_hi = icr_hi;
@@ -577,101 +541,34 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 
        /* write APIC ICR */
        lapic.icr_lo = icr_lo;
-       write_eflags(eflags);
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
        return 0;
 }
 
-
 /*
  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
  *
- *  target contains a bitfield with a bit set for selected APICs.
- *  vector is any valid SYSTEM INT vector
- *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ * target is a bitmask of destination cpus.  Vector is any
+ * valid system INT vector.  Delivery mode may be either
+ * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
  */
 int
 selected_apic_ipi(u_int target, int vector, int delivery_mode)
 {
-       int     x;
-       int     status;
-
-       if (target & ~0x7fff)
-               return -1;      /* only 15 targets allowed */
-
-       for (status = 0, x = 0; x <= 14; ++x)
-               if (target & (1 << x)) {
-
-                       /* send the IPI */
-                       if (apic_ipi_singledest(x, vector, 
-                                               delivery_mode) == -1)
-                               status |= (1 << x);
-               }
-       return status;
-}
-
-
-#if defined(READY)
-/*
- * Send an IPI INTerrupt containing 'vector' to CPU 'target'
- *   NOTE: target is a LOGICAL APIC ID
- */
-int
-selected_proc_ipi(int target, int vector)
-{
-       u_long  icr_lo;
-       u_long  icr_hi;
-
-       /* write the destination field for the target AP */
-       icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) |
-           (cpu_num_to_apic_id[target] << 24);
-       lapic.icr_hi = icr_hi;
-
-       /* write command */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) |
-           APIC_DEST_DESTFLD | APIC_DELMODE_FIXED | vector;
-       lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-               /* spin */ ;
-
-       return 0;       /** XXX FIXME: return result */
+       int status = 0;
+
+       crit_enter();
+       while (target) {
+               int n = bsfl(target);
+               target &= ~(1 << n);
+               if (apic_ipi_singledest(n, vector, delivery_mode) < 0)
+                       status |= 1 << n;
+       }
+       crit_exit();
+       return(status);
 }
-#endif /* READY */
 
 #endif /* APIC_IO */
 
-
 /*
  * Timer code, in development...
  *  - suggested by rgrimes@gndrsh.aac.dev.com
index 03b2a1e..137ae17 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/exception.s,v 1.65.2.3 2001/08/15 01:23:49 peter Exp $
- * $DragonFly: src/sys/i386/i386/Attic/exception.s,v 1.11 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/exception.s,v 1.12 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "npx.h"
@@ -175,7 +175,7 @@ IDTVEC(fpu)
        call    npx_intr                /* note: call might mess w/ argument */
 
        movl    %ebx, (%esp)            /* save cpl for doreti */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        MEXITCOUNT
        jmp     doreti
 #else  /* NNPX > 0 */
@@ -214,7 +214,7 @@ alltraps_with_regs_pushed:
        FAKE_MCOUNT(13*4(%esp))
 calltrap:
        FAKE_MCOUNT(btrap)              /* init "from" _btrap -> calltrap */
-       incl PCPU(cnt)+V_TRAP           /* YYY per-cpu */
+       incl    PCPU(cnt)+V_TRAP
        movl    PCPU(curthread),%eax    /* keep orig cpl here during call */
        movl    TD_CPL(%eax),%ebx
        call    trap
@@ -224,7 +224,7 @@ calltrap:
         * to interrupt frame.
         */
        pushl   %ebx                    /* cpl to restore */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        MEXITCOUNT
        jmp     doreti
 
@@ -308,33 +308,51 @@ IDTVEC(int0x80_syscall)
  * This function is what cpu_heavy_restore jumps to after a new process
  * is created.  We are in a critical section in order to prevent
  * cpu_heavy_restore from being interrupted (especially since it stores
- * its context in a static place!), so the first thing we do is release
- * the critical section.
+ * its context in a static place!).
  *
  * The MP lock is held on entry, but for processes fork_return (esi)
  * releases it.  'doreti' always runs without the MP lock.
+ *
+ * We need to be careful to hold interrupts disabled through until
+ * doreti iret's YYY this is due to the PCB_ storage in the heavy switcher,
+ * fixme!
  */
 ENTRY(fork_trampoline)
+       cli
        movl    PCPU(curthread),%eax
        subl    $TDPRI_CRIT,TD_PRI(%eax)
-       call    spl0
-       call    splz
 
        /*
         * cpu_set_fork_handler intercepts this function call to
         * have this call a non-return function to stay in kernel mode.
-        * initproc has its own fork handler, but it does return.
+        *
+        * initproc has its own fork handler, start_init(), which DOES
+        * return.
         */
        pushl   %ebx                    /* arg1 */
        call    *%esi                   /* function */
        addl    $4,%esp
        /* cut from syscall */
 
+       call    spl0
+       call    splz
+
+#if defined(INVARIANTS) && defined(SMP)
+       movl    PCPU(curthread),%eax
+       cmpl    $0,TD_MPCOUNT(%eax)
+       je      1f
+       pushl   %esi
+       pushl   TD_MPCOUNT(%eax)
+       pushl   $pmsg4
+       call    panic
+pmsg4:  .asciz "fork_trampoline mpcount %d after calling %p"
+1:
+#endif
        /*
         * Return via doreti to handle ASTs.
         */
        pushl   $0                      /* cpl to restore */
-       movb    $1,PCPU(intr_nesting_level)
+       movl    $1,PCPU(intr_nesting_level)
        MEXITCOUNT
        jmp     doreti
 
index 1bda990..a53104e 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)genassym.c    5.11 (Berkeley) 5/10/91
  * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $
- * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.21 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.22 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "opt_user_ldt.h"
@@ -102,6 +102,7 @@ ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner));
 ASSYM(TD_CPL, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_cpl));
 
 ASSYM(TDPRI_CRIT, TDPRI_CRIT);
+ASSYM(TDPRI_INT_SUPPORT, TDPRI_INT_SUPPORT);
 
 ASSYM(SSLEEP, SSLEEP);
 ASSYM(SRUN, SRUN);
@@ -197,7 +198,6 @@ ASSYM(GD_CURRENTLDT, offsetof(struct mdglobaldata, gd_currentldt));
 
 ASSYM(GD_FPENDING, offsetof(struct mdglobaldata, gd_fpending));
 ASSYM(GD_IPENDING, offsetof(struct mdglobaldata, gd_ipending));
-ASSYM(GD_IRUNNING, offsetof(struct mdglobaldata, gd_irunning));
 ASSYM(GD_COMMON_TSS, offsetof(struct mdglobaldata, gd_common_tss));
 ASSYM(GD_COMMON_TSSD, offsetof(struct mdglobaldata, gd_common_tssd));
 ASSYM(GD_TSS_GDT, offsetof(struct mdglobaldata, gd_tss_gdt));
index 2cdbfd9..86b5f57 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/globals.s,v 1.13.2.1 2000/05/16 06:58:06 dillon Exp $
- * $DragonFly: src/sys/i386/i386/Attic/globals.s,v 1.14 2003/07/03 17:24:01 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/globals.s,v 1.15 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "opt_user_ldt.h"
@@ -84,7 +84,7 @@
        .globl  gd_ss_eflags, gd_intr_nesting_level
        .globl  gd_CMAP1, gd_CMAP2, gd_CMAP3, gd_PMAP1
        .globl  gd_CADDR1, gd_CADDR2, gd_CADDR3, gd_PADDR1
-       .globl  gd_irunning, gd_ipending, gd_fpending, gd_cnt
+       .globl  gd_ipending, gd_fpending, gd_cnt
 
        .set    gd_cpuid,globaldata + GD_CPUID
        .set    gd_cpu_lockid,globaldata + GD_CPU_LOCKID
        .set    gd_PADDR1,globaldata + GD_PRV_PADDR1
        .set    gd_fpending,globaldata + GD_FPENDING
        .set    gd_ipending,globaldata + GD_IPENDING
-       .set    gd_irunning,globaldata + GD_IRUNNING
        .set    gd_cnt,globaldata + GD_CNT
 
 #if defined(APIC_IO)
index d5a1baa..09a8f4b 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)locore.s      7.3 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/locore.s,v 1.132.2.10 2003/02/03 20:54:49 jhb Exp $
- * $DragonFly: src/sys/i386/i386/Attic/locore.s,v 1.5 2003/07/01 20:30:40 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/locore.s,v 1.6 2003/07/08 06:27:26 dillon Exp $
  *
  *             originally from: locore.s, by William F. Jolitz
  *
@@ -886,7 +886,7 @@ map_read_write:
 
 #ifdef SMP
 /* Initialize mp lock to allow early traps */
-       movl    $1, R(mp_lock)
+       movl    $0, R(mp_lock)
 #endif /* SMP */
 
 /* install a pde for temporary double map of bottom of VA */
index ceacbc8..47b4560 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)machdep.c     7.4 (Berkeley) 6/3/91
  * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $
- * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.22 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.23 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "apm.h"
@@ -951,7 +951,7 @@ cpu_halt(void)
  * Note on cpu_idle_hlt:  On an SMP system this may cause the system to 
  * halt until the next clock tick, even if a thread is ready YYY
  */
-static int     cpu_idle_hlt = 0;
+static int     cpu_idle_hlt = 1;
 SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW,
     &cpu_idle_hlt, 0, "Idle loop HLT enable");
 
index f60a00a..48953f2 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.115.2.15 2003/03/14 21:22:35 jhb Exp $
- * $DragonFly: src/sys/i386/i386/Attic/mp_machdep.c,v 1.9 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/mp_machdep.c,v 1.10 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "opt_cpu.h"
@@ -588,6 +588,10 @@ mp_enable(u_int boot_addr)
               SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
 #endif
 #endif
+
+       /* install an inter-CPU IPI for IPIQ messaging */
+       setidt(XIPIQ_OFFSET, Xipiq,
+              SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
        
        /* install an inter-CPU IPI for all-CPU rendezvous */
        setidt(XRENDEZVOUS_OFFSET, Xrendezvous,
@@ -2060,6 +2064,8 @@ start_all_aps(u_int boot_addr)
                gd->gd_CADDR2 = CPU_prvspace[x].CPAGE2;
                gd->gd_CADDR3 = CPU_prvspace[x].CPAGE3;
                gd->gd_PADDR1 = (unsigned *)CPU_prvspace[x].PPAGE1;
+               gd->mi.gd_ipiq = (void *)kmem_alloc(kernel_map, sizeof(lwkt_ipiq) * (mp_naps + 1));
+               bzero(gd->mi.gd_ipiq, sizeof(lwkt_ipiq) * (mp_naps + 1));
 
                /* setup a vector to our boot code */
                *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET;
@@ -2095,6 +2101,8 @@ start_all_aps(u_int boot_addr)
 
        /* build our map of 'other' CPUs */
        mycpu->gd_other_cpus = all_cpus & ~(1 << mycpu->gd_cpuid);
+       mycpu->gd_ipiq = (void *)kmem_alloc(kernel_map, sizeof(lwkt_ipiq) * ncpus);
+       bzero(mycpu->gd_ipiq, sizeof(lwkt_ipiq) * ncpus);
 
        /* fill in our (BSP) APIC version */
        cpu_apic_versions[0] = lapic.version;
@@ -2398,10 +2406,12 @@ ap_init(void)
        ++ncpus;
 
        /*
-        * Get the MP lock so we can finish initializing.
+        * Get the MP lock so we can finish initializing.  Note: we are
+        * in a critical section.
         */
        while (cpu_try_mplock() == 0)
            ;
+       ++curthread->td_mpcount;
 
        /* BSP may have changed PTD while we're waiting for the lock */
        cpu_invltlb();
@@ -2456,7 +2466,8 @@ ap_init(void)
         * lwkt_switch() normally cleans things up this is a special case
         * because we returning almost directly into the idle loop.
         */
-       cpu_rel_mplock();
+       KKASSERT(curthread->td_mpcount == 1);
+       rel_mplock();
 }
 
 #ifdef BETTER_CLOCK
@@ -2927,3 +2938,9 @@ smp_rendezvous(void (* setup_func)(void *),
        /* release lock */
        spin_unlock(&smp_rv_spinlock);
 }
+
+void
+cpu_send_ipiq(int dcpu)
+{
+       selected_apic_ipi(1 << dcpu, XIPIQ_OFFSET, APIC_DELMODE_FIXED);
+}
index f2a7bcc..89d8f89 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/mpapic.c,v 1.37.2.7 2003/01/25 02:31:47 peter Exp $
- * $DragonFly: src/sys/i386/i386/Attic/mpapic.c,v 1.4 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/mpapic.c,v 1.5 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -33,6 +33,7 @@
 #include <machine/smp.h>
 #include <machine/mpapic.h>
 #include <machine/segments.h>
+#include <sys/thread2.h>
 
 #include <i386/isa/intr_machdep.h>     /* Xspuriousint() */
 
@@ -79,8 +80,10 @@ apic_initialize(void)
         * Leave the BSP and TPR 0 during boot so it gets all the interrupts,
         * set APs at TPR 0xF0 at boot so they get no ints.
         */
+#if 0
        if (mycpu->gd_cpuid != 0)
                temp |= TPR_IPI_ONLY;   /* disable INTs on this cpu */
+#endif
        lapic.tpr = temp;
 
        /* enable the local APIC */
@@ -484,63 +487,33 @@ imen_dump(void)
  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
  *  vector is any valid SYSTEM INT vector
  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ *
+ * A backlog of requests can create a deadlock between cpus.  To avoid this
+ * we have to be able to accept IPIs at the same time we are trying to send
+ * them.  The critical section prevents us from attempting to send additional
+ * IPIs reentrantly, but also prevents IPIQ processing so we have to call
+ * lwkt_process_ipiq() manually.  It's rather messy and expensive for this
+ * to occur but fortunately it does not happen too often.
  */
-#define DETECT_DEADLOCK
 int
 apic_ipi(int dest_type, int vector, int delivery_mode)
 {
        u_long  icr_lo;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       crit_enter();
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       /* build IRC_LOW */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
-           | dest_type | delivery_mode | vector;
 
-       /* write APIC ICR */
+       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) | dest_type | 
+               delivery_mode | vector;
        lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
+       crit_exit();
        return 0;
 }
 
@@ -549,24 +522,15 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 {
        u_long  icr_lo;
        u_long  icr_hi;
-       u_long  eflags;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       eflags = read_eflags();
-       __asm __volatile("cli" : : : "memory");
        icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
        icr_hi |= (CPU_TO_ID(cpu) << 24);
        lapic.icr_hi = icr_hi;
@@ -577,101 +541,34 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 
        /* write APIC ICR */
        lapic.icr_lo = icr_lo;
-       write_eflags(eflags);
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
        return 0;
 }
 
-
 /*
  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
  *
- *  target contains a bitfield with a bit set for selected APICs.
- *  vector is any valid SYSTEM INT vector
- *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ * target is a bitmask of destination cpus.  Vector is any
+ * valid system INT vector.  Delivery mode may be either
+ * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
  */
 int
 selected_apic_ipi(u_int target, int vector, int delivery_mode)
 {
-       int     x;
-       int     status;
-
-       if (target & ~0x7fff)
-               return -1;      /* only 15 targets allowed */
-
-       for (status = 0, x = 0; x <= 14; ++x)
-               if (target & (1 << x)) {
-
-                       /* send the IPI */
-                       if (apic_ipi_singledest(x, vector, 
-                                               delivery_mode) == -1)
-                               status |= (1 << x);
-               }
-       return status;
-}
-
-
-#if defined(READY)
-/*
- * Send an IPI INTerrupt containing 'vector' to CPU 'target'
- *   NOTE: target is a LOGICAL APIC ID
- */
-int
-selected_proc_ipi(int target, int vector)
-{
-       u_long  icr_lo;
-       u_long  icr_hi;
-
-       /* write the destination field for the target AP */
-       icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) |
-           (cpu_num_to_apic_id[target] << 24);
-       lapic.icr_hi = icr_hi;
-
-       /* write command */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) |
-           APIC_DEST_DESTFLD | APIC_DELMODE_FIXED | vector;
-       lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-               /* spin */ ;
-
-       return 0;       /** XXX FIXME: return result */
+       int status = 0;
+
+       crit_enter();
+       while (target) {
+               int n = bsfl(target);
+               target &= ~(1 << n);
+               if (apic_ipi_singledest(n, vector, delivery_mode) < 0)
+                       status |= 1 << n;
+       }
+       crit_exit();
+       return(status);
 }
-#endif /* READY */
 
 #endif /* APIC_IO */
 
-
 /*
  * Timer code, in development...
  *  - suggested by rgrimes@gndrsh.aac.dev.com
index 207c3d2..086ea48 100644 (file)
@@ -7,7 +7,7 @@
  * ----------------------------------------------------------------------------
  *
  * $FreeBSD: src/sys/i386/i386/mplock.s,v 1.29.2.2 2000/05/16 06:58:06 dillon Exp $
- * $DragonFly: src/sys/i386/i386/Attic/mplock.s,v 1.4 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/mplock.s,v 1.5 2003/07/08 06:27:26 dillon Exp $
  *
  * Functions for locking between CPUs in a SMP system.
  *
@@ -40,7 +40,7 @@ mp_lock:
 
        /*
         * Note on cmpxchgl... exchanges ecx with mem if mem matches eax.
-        * Z=1 (jz) on success. 
+        * Z=1 (jz) on success.   A lock prefix is required for MP.
         */
 NON_GPROF_ENTRY(cpu_get_initial_mplock)
        movl    PCPU(curthread),%ecx
@@ -56,7 +56,7 @@ NON_GPROF_ENTRY(cpu_get_initial_mplock)
 NON_GPROF_ENTRY(cpu_try_mplock)
        movl    PCPU(cpuid),%ecx
        movl    $-1,%eax
-       cmpxchgl %ecx,mp_lock           /* ecx<->mem if eax matches */
+       lock cmpxchgl %ecx,mp_lock      /* ecx<->mem if eax matches */
        jnz     1f
        movl    $1,%eax
        NON_GPROF_RET
@@ -76,16 +76,27 @@ NON_GPROF_ENTRY(get_mplock)
        movl    $1,TD_MPCOUNT(%edx)
        movl    PCPU(cpuid),%ecx
        movl    $-1,%eax
-       cmpxchgl %ecx,mp_lock           /* ecx<->mem & JZ if eax matches */
+       lock cmpxchgl %ecx,mp_lock      /* ecx<->mem & JZ if eax matches */
        jnz     2f
        popfl                           /* success */
        NON_GPROF_RET
 2:
+#ifdef INVARIANTS
        movl    PCPU(cpuid),%eax        /* failure */
        cmpl    %eax,mp_lock
+       je      3f
+#endif
+       addl    $TDPRI_CRIT,TD_PRI(%edx)
+       popfl
+       call    lwkt_switch             /* will be correct on return */
+       movl    PCPU(curthread),%edx
+       subl    $TDPRI_CRIT,TD_PRI(%edx)
+       NON_GPROF_RET
+3:
+       cmpl    $0,panicstr             /* don't double panic */
        je      badmp_get
        popfl
-       jmp     lwkt_switch             /* will be correct on return */
+       NON_GPROF_RET
 
 NON_GPROF_ENTRY(try_mplock)
        movl    PCPU(curthread),%edx
@@ -99,48 +110,74 @@ NON_GPROF_ENTRY(try_mplock)
        cli
        movl    PCPU(cpuid),%ecx
        movl    $-1,%eax
-       cmpxchgl %ecx,mp_lock           /* ecx<->mem & JZ if eax matches */
+       lock cmpxchgl %ecx,mp_lock      /* ecx<->mem & JZ if eax matches */
        jnz     2f
        movl    $1,TD_MPCOUNT(%edx)
        popfl                           /* success */
        movl    $1,%eax
        NON_GPROF_RET
 2:
+#ifdef INVARIANTS
+       cmpl    $0,panicstr
+       jnz     3f
        movl    PCPU(cpuid),%eax        /* failure */
        cmpl    %eax,mp_lock
        je      badmp_get
+3:
+#endif
        popfl
        movl    $0,%eax
        NON_GPROF_RET
 
 NON_GPROF_ENTRY(rel_mplock)
        movl    PCPU(curthread),%edx
-       cmpl    $1,TD_MPCOUNT(%edx)
+       movl    TD_MPCOUNT(%edx),%eax
+       cmpl    $1,%eax
        je      1f
-       subl    $1,TD_MPCOUNT(%edx)
+#ifdef INVARIANTS
+       testl   %eax,%eax
+       jz      badmp_rel
+#endif
+       subl    $1,%eax
+       movl    %eax,TD_MPCOUNT(%edx)
        NON_GPROF_RET
 1:
        pushfl
        cli
+#ifdef INVARIANTS
+       movl    PCPU(cpuid),%ecx
+       cmpl    %ecx,mp_lock
+       jne     badmp_rel2
+#endif
        movl    $0,TD_MPCOUNT(%edx)
        movl    $MP_FREE_LOCK,mp_lock
        popfl
        NON_GPROF_RET
 
+#ifdef INVARIANTS
+
 badmp_get:
        pushl   $bmpsw1
        call    panic
 badmp_rel:
        pushl   $bmpsw2
        call    panic
+badmp_rel2:
+       pushl   $bmpsw2a
+       call    panic
 
        .data
 
 bmpsw1:
-       .asciz  "try/get_mplock(): already have lock!"
+       .asciz  "try/get_mplock(): already have lock! %d %p"
 
 bmpsw2:
-       .asciz  "rel_mplock(): not holding lock!"
+       .asciz  "rel_mplock(): mpcount already 0 @ %p %p %p %p %p %p %p %p!"
+
+bmpsw2a:
+       .asciz  "rel_mplock(): Releasing another cpu's MP lock! %p %p"
+
+#endif
 
 #if 0
 /* after 1st acquire of lock we grab all hardware INTs */
index 4ea5c72..2280439 100644 (file)
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $
- * $DragonFly: src/sys/i386/i386/Attic/swtch.s,v 1.21 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/swtch.s,v 1.22 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "npx.h"
@@ -143,7 +143,7 @@ ENTRY(cpu_heavy_switch)
        addl    $PCB_SAVEFPU,%edx               /* h/w bugs make saving complicated */
        pushl   %edx
        call    npxsave                 /* do it in a big C function */
-       popl    %eax
+       addl    $4,%esp
 1:
        /* %ecx,%edx trashed */
 #endif /* NNPX > 0 */
@@ -224,6 +224,8 @@ ENTRY(cpu_exit_switch)
  *     we restore everything.
  *
  *     YYY STI/CLI sequencing.
+ *     YYY the PCB crap is really crap, it makes startup a bitch because
+ *     we can't switch away.
  *
  *     YYY note: spl check is done in mi_switch when it splx()'s.
  */
index 7c07619..8431b05 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)trap.c        7.4 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $
- * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.18 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.19 2003/07/08 06:27:26 dillon Exp $
  */
 
 /*
@@ -164,7 +164,7 @@ SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW,
  *
  * usertdsw is called from within a critical section, but the BGL will
  * have already been released by lwkt_switch() so only call MP safe functions
- * that don't block!
+ * that don't block and don't require the BGL!
  */
 static void
 usertdsw(struct thread *ntd)
@@ -302,7 +302,15 @@ trap(frame)
        int i = 0, ucode = 0, type, code;
        vm_offset_t eva;
 
+#ifdef SMP
+       if (panicstr == NULL)
+           KASSERT(curthread->td_mpcount >= 0, ("BADX1 AT %08x %08x", frame.tf_eip, frame.tf_esp));
+#endif
        get_mplock();
+#ifdef SMP
+       if (panicstr == NULL)
+           KKASSERT(curthread->td_mpcount > 0);
+#endif
 
 #ifdef DDB
        if (db_active) {
@@ -365,12 +373,19 @@ restart:
        if (in_vm86call) {
                if (frame.tf_eflags & PSL_VM &&
                    (type == T_PROTFLT || type == T_STKFLT)) {
+#ifdef SMP
+                       KKASSERT(curthread->td_mpcount > 0);
+#endif
                        i = vm86_emulate((struct vm86frame *)&frame);
+#ifdef SMP
+                       KKASSERT(curthread->td_mpcount > 0);
+#endif
                        if (i != 0) {
                                /*
                                 * returns to original process
                                 */
                                vm86_trap((struct vm86frame *)&frame);
+                               KKASSERT(0);
                        }
                        goto out2;
                }
@@ -736,6 +751,9 @@ out:
 #endif
        userret(p, &frame, sticks);
 out2:
+#ifdef SMP
+       KKASSERT(curthread->td_mpcount > 0);
+#endif
        rel_mplock();
 }
 
index 133181e..4bfde76 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/vm86.c,v 1.31.2.2 2001/10/05 06:18:55 peter Exp $
- * $DragonFly: src/sys/i386/i386/Attic/vm86.c,v 1.6 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/vm86.c,v 1.7 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -39,6 +39,7 @@
 #include <vm/vm_page.h>
 
 #include <sys/user.h>
+#include <sys/thread2.h>
 
 #include <machine/md_var.h>
 #include <machine/pcb_ext.h>   /* pcb.h included via sys/user.h */
@@ -570,13 +571,18 @@ vm86_trap(struct vm86frame *vmf)
 int
 vm86_intcall(int intnum, struct vm86frame *vmf)
 {
+       int error;
+
        if (intnum < 0 || intnum > 0xff)
                return (EINVAL);
 
+       crit_enter();
        ASSERT_MP_LOCK_HELD();
 
        vmf->vmf_trapno = intnum;
-       return (vm86_bioscall(vmf));
+       error = vm86_bioscall(vmf);
+       crit_exit();
+       return(error);
 }
 
 /*
@@ -595,6 +601,7 @@ vm86_datacall(intnum, vmf, vmc)
        u_int page;
        int i, entry, retval;
 
+       crit_enter();
        ASSERT_MP_LOCK_HELD();
 
        for (i = 0; i < vmc->npages; i++) {
@@ -611,7 +618,7 @@ vm86_datacall(intnum, vmf, vmc)
                entry = vmc->pmap[i].pte_num;
                pte[entry] = vmc->pmap[i].old_pte;
        }
-
+       crit_exit();
        return (retval);
 }
 
index 3edd8a1..daa42ac 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/vm86bios.s,v 1.15.2.1 2000/05/16 06:58:07 dillon Exp $
- * $DragonFly: src/sys/i386/i386/Attic/vm86bios.s,v 1.9 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/vm86bios.s,v 1.10 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <machine/asmacros.h>          /* miscellaneous asm macros */
@@ -138,7 +138,7 @@ ENTRY(vm86_bioscall)
         */
        movl    PCPU(curthread),%eax
        pushl   TD_CPL(%eax)
-       incb    PCPU(intr_nesting_level)/* dummy to match doreti */
+       incl    PCPU(intr_nesting_level)/* dummy to match doreti */
        MEXITCOUNT
        jmp     doreti
 
index d5362a0..42cebf0 100644 (file)
@@ -39,7 +39,7 @@
  *     from: @(#)vm_machdep.c  7.3 (Berkeley) 5/13/91
  *     Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
  * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $
- * $DragonFly: src/sys/i386/i386/Attic/vm_machdep.c,v 1.17 2003/07/04 00:32:24 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/vm_machdep.c,v 1.18 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "npx.h"
@@ -405,7 +405,7 @@ cpu_reset_proxy()
        while (cpu_reset_proxy_active == 1)
                ;        /* Wait for other cpu to disable interupts */
        saved_mp_lock = mp_lock;
-       mp_lock = 1;
+       mp_lock = 0;    /* BSP */
        printf("cpu_reset_proxy: Grabbed mp lock for BSP\n");
        cpu_reset_proxy_active = 3;
        while (cpu_reset_proxy_active == 3)
index f70abd0..79ea6ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/icu_vector.s,v 1.14.2.2 2000/07/18 21:12:42 dfr Exp $
- * $DragonFly: src/sys/i386/icu/Attic/icu_vector.s,v 1.11 2003/07/03 17:24:02 dillon Exp $
+ * $DragonFly: src/sys/i386/icu/Attic/icu_vector.s,v 1.12 2003/07/08 06:27:27 dillon Exp $
  */
 
 /*
@@ -68,7 +68,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -83,7 +83,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define MASK_IRQ(icu, irq_num)                                         \
        movb    imen + IRQ_BYTE(irq_num),%al ;                          \
@@ -188,16 +188,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule its thread.  Leave
- *       interrupts masked and doreti.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule its thread.  Leave interrupts masked and doreti.
  *
- *     The interrupt thread will run its handlers and loop if 
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     sched_ithd() is called with interrupts enabled and outside of a
+ *     critical section (so it can preempt us).
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
  *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
@@ -219,8 +215,6 @@ IDTVEC(vec_name) ;                                                  \
        pushl   %eax ;          /* push CPL for doreti */               \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num), %eax ;                              \
        jz      2f ;                                                    \
 1: ;                                                                   \
@@ -229,15 +223,12 @@ IDTVEC(vec_name) ;                                                        \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -248,8 +239,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -258,7 +248,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(icu, irq_num) ;                                      \
        popl %ebp ;                                                     \
        ret ;                                                           \
index 7a8c823..88d6520 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/apic.h,v 1.14.2.2 2003/03/21 21:46:15 jhb Exp $
- * $DragonFly: src/sys/i386/include/Attic/apic.h,v 1.3 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/apic.h,v 1.4 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_APIC_H_
  * 0310        ICR_HI  | DEST FIELD|           |           |           |
  *             +-----------+-----------+-----------+-----------+
  *
- *                 The interrupt command register 
+ *                 The interrupt command register.  Generally speaking
+ *                 writing to ICR_LO initiates a command.  All fields
+ *                 are R/W except the 'S' (delivery status) field, which
+ *                 is read-only.  When
+ *     
  *
  *                     XX:     Destination Shorthand field:
  *
  *                                     destination field of 0x0F)
  *
  *                     T:      1 = Level 0 = Edge Trigger modde, used for
- *                             the INIT level de-assert delivery mode only.
- *                             Not sure.
+ *                             the INIT level de-assert delivery mode only
+ *                             to de-assert a request.
  *
- *                     L:      0 = De-Assert, 1 = Assert.  Not sure what this
- *                             is.  For INIT mode use 0, for all other modes
- *                             use 1.
+ *                     L:      0 = De-Assert, 1 = Assert.  Always write as
+ *                             1 when initiating a new command.  Can only
+ *                             write as 0 for INIT mode de-assertion of
+ *                             command.
  *
  *                     S:      1 = Send Pending.  Interrupt has been injected
  *                             but APIC has not yet accepted it.
  *                                             Always level.
  *
  *             +-----------+-----------+-----------+-----------+
- * 0380        ICR     |           |           |           |           |
- * 0390        CCR     |           |           |           |           |
+ * 0380        TMR_ICR |           |           |           |           |
+ * 0390        TMR_CCR |           |           |           |           |
  * 03A0                |           |           |           |           |
  * 03B0                |           |           |           |           |
  * 03C0                |           |           |           |           |
  * 03D0                |           |           |           |           |
- * 03E0 DCR    |           |           |           |           |
+ * 03E0 TMR_DCR        |           |           |           |           |
  *             +-----------+-----------+-----------+-----------+
  *
+ *                 Timer control and access registers.
+ *
  *
  *     NOTE ON EOI: Upon receiving an EOI the APIC clears the highest priority
  *     interrupt in the ISR and selects the next highest priority interrupt
  *     triggered the APIC will send an EOI to all I/O APICs.  For the moment
  *     you can write garbage to the EOI register but for future compatibility
  *     0 should be written.
- *
  */
 
 #ifndef LOCORE
index 59552f8..a8c8ec6 100644 (file)
@@ -24,7 +24,7 @@
  * the rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/i386/include/db_machdep.h,v 1.16 1999/10/04 13:55:35 marcel Exp $
- * $DragonFly: src/sys/i386/include/Attic/db_machdep.h,v 1.2 2003/06/17 04:28:35 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/db_machdep.h,v 1.3 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_DB_MACHDEP_H_
@@ -33,6 +33,7 @@
 #include <machine/frame.h>
 #include <machine/psl.h>
 #include <machine/trap.h>
+#include <machine/globaldata.h>
 
 #define i386_saved_state trapframe
 
index 3a7a051..25e4c1f 100644 (file)
@@ -28,7 +28,7 @@
  *     should not include this file.
  *
  * $FreeBSD: src/sys/i386/include/globaldata.h,v 1.11.2.1 2000/05/16 06:58:10 dillon Exp $
- * $DragonFly: src/sys/i386/include/Attic/globaldata.h,v 1.15 2003/07/04 00:25:48 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/globaldata.h,v 1.16 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_GLOBALDATA_H_
 
 /*
  * Note on interrupt control.  Pending interrupts not yet dispatched are
- * marked in gd_fpending or gd_ipending.  Once dispatched an interrupt
- * is marked in irunning and the fpending bit is cleared.  For edge triggered
- * interrupts interrupts may be enabled again at this point and if they
- * occur before the interrupt service routine is complete the ipending bit
- * will be set again and cause the interrupt service to loop.  The current
- * thread's cpl is stored in the thread structure.
+ * marked in gd_fpending or gd_ipending.  Once dispatched the interrupt's
+ * pending bit is cleared and the interrupt is masked.  Upon completion
+ * the interrupt is unmasked.
+ *
+ * For edge triggered interrupts interrupts may be enabled again at this
+ * point and if they occur before the interrupt service routine is complete
+ * the service routine will loop.
+ *
+ * The current thread's cpl is stored in the thread structure.
  */
 struct mdglobaldata {
        struct globaldata mi;
@@ -65,7 +68,6 @@ struct mdglobaldata {
        struct i386tss  gd_common_tss;
        int             gd_fpending;    /* fast interrupt pending */
        int             gd_ipending;    /* normal interrupt pending */
-       int             gd_irunning;    /* normal interrupt in progress */
        int             gd_currentldt;  /* USER_LDT */
        u_int           gd_cpu_lockid;
        u_int           gd_other_cpus;
index cfbdc13..5c10d17 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/ipl.h,v 1.17.2.3 2002/12/17 18:04:02 sam Exp $
- * $DragonFly: src/sys/i386/include/Attic/ipl.h,v 1.3 2003/06/22 08:54:20 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/ipl.h,v 1.4 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_IPL_H_
@@ -97,6 +97,7 @@
  */
 #define        AST_PENDING     0x00000001
 #define        AST_RESCHED     0x00000002
+#define        AST_IPIQ        0x00000004
 
 #ifndef        LOCORE
 
index a8e0070..8fecf9b 100644 (file)
@@ -22,7 +22,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/lock.h,v 1.11.2.2 2000/09/30 02:49:34 ps Exp $
- * $DragonFly: src/sys/i386/include/Attic/lock.h,v 1.3 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/lock.h,v 1.4 2003/07/08 06:27:27 dillon Exp $
  */
 
 #ifndef _MACHINE_LOCK_H_
        orl     $PSL_C,%ecx ;   /* make sure non-zero */        \
 7: ;                                                           \
        movl    $0,%eax ;       /* expected contents of lock */ \
-       cmpxchgl %ecx,mem ;     /* Z=1 (jz) on success */       \
-       jz      8f ;                                            \
-       jmp     7b ;                                            \
-8: ;                                                           \
+       lock cmpxchgl %ecx,mem ; /* Z=1 (jz) on success */      \
+       jnz     7b ;                                            \
 
 #define SPIN_LOCK_PUSH_REGS                                    \
        subl    $8,%esp ;                                       \
index ad3d893..b422a04 100644 (file)
@@ -7,7 +7,7 @@
  * ----------------------------------------------------------------------------
  *
  * $FreeBSD: src/sys/i386/include/smp.h,v 1.50.2.5 2001/02/13 22:32:45 tegge Exp $
- * $DragonFly: src/sys/i386/include/Attic/smp.h,v 1.3 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/smp.h,v 1.4 2003/07/08 06:27:27 dillon Exp $
  *
  */
 
@@ -150,6 +150,7 @@ void        set_io_apic_mask24      __P((int, u_int32_t));
 void   set_apic_timer          __P((int));
 int    read_apic_timer         __P((void));
 void   u_sleep                 __P((int));
+void   cpu_send_ipiq           __P((int));
 
 /* global data in init_smp.c */
 extern int                     invltlb_ok;
index 48959a6..fef5fad 100644 (file)
@@ -24,7 +24,7 @@
  *
  *     Machine independant code should not directly include this file.
  *
- * $DragonFly: src/sys/i386/include/Attic/thread.h,v 1.3 2003/06/28 04:16:03 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/thread.h,v 1.4 2003/07/08 06:27:27 dillon Exp $
  */
 
 #ifndef        _MACHINE_THREAD_H_
@@ -42,8 +42,6 @@ struct md_thread {
 
 #define td_cpl td_mach.mtd_cpl
 
-struct globaldata;
-
 /*
  * mycpu() retrieves the base of the current cpu's globaldata structure.
  * Note that it is *NOT* volatile, meaning that the value may be cached by
@@ -56,6 +54,8 @@ struct globaldata;
  * block.
  */
 
+struct globaldata;
+
 extern int __mycpu__dummy;
 
 static __inline
index 55a4af9..3ad2634 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/apic_vector.s,v 1.47.2.5 2001/09/01 22:33:38 tegge Exp $
- * $DragonFly: src/sys/i386/isa/Attic/apic_vector.s,v 1.8 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/apic_vector.s,v 1.9 2003/07/08 06:27:27 dillon Exp $
  */
 
 
@@ -38,7 +38,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -53,7 +53,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define IOAPICADDR(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 8
 #define REDIRIDX(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 12
@@ -165,6 +165,10 @@ IDTVEC(vec_name) ;                                                 \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
+       /* try to get giant */                                          \
+       call    try_mplock ;                                            \
+       testl   %eax,%eax ;                                             \
+       jz      1b ;                                                    \
        /* clear pending bit, run handler */                            \
        addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        andl    $~IRQ_LBIT(irq_num),PCPU(fpending) ;                    \
@@ -175,6 +179,7 @@ IDTVEC(vec_name) ;                                                  \
        incl    PCPU(cnt)+V_INTR ;      /* book-keeping make per cpu YYY */ \
        movl    intr_countp + (irq_num) * 4, %eax ;                     \
        incl    (%eax) ;                                                \
+       call    rel_mplock ;                                            \
        UNMASK_IRQ(irq_num) ;                                           \
 5: ;                                                                   \
        MEXITCOUNT ;                                                    \
@@ -190,6 +195,8 @@ IDTVEC(vec_name) ;                                                  \
  *     - Unmask the interrupt
  *     - Pop the dummy frame and do a normal return
  *
+ *     The BGL is held on call and left held on return.
+ *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
  */
@@ -221,17 +228,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule the thread.  Leave
- *       interrupts masked and doreti.
- *
- *     the interrupt thread will run its handlers and loop if
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule the thread.  Leave interrupts masked and doreti.
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
- *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
+ *     Note that calls to sched_ithd() are made with interrupts enabled
+ *     and outside a critical section.  YYY sched_ithd may preempt us
+ *     synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
@@ -252,25 +254,20 @@ IDTVEC(vec_name) ;                                                        \
        pushl   %eax ;          /* cpl do restore */                    \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num),%eax ;                               \
-       jz      1f ;                                                    \
+       jz      2f ;                                                    \
 1: ;                                                                   \
        /* set the pending bit and return, leave the interrupt masked */ \
        orl     $IRQ_LBIT(irq_num), PCPU(ipending) ;                    \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -281,8 +278,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -291,7 +287,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(irq_num) ;                                           \
        popl %ebp ;                                                     \
        ret ;                                                           \
@@ -455,7 +450,7 @@ Xcpuast:
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
        orl     $AST_PENDING, PCPU(astpending)  /* XXX */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        movl    PCPU(cpuid), %eax
@@ -497,7 +492,7 @@ Xforward_irq:
        movl    PCPU(curthread), %eax
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        MEXITCOUNT
@@ -552,7 +547,7 @@ forward_irq:
        jnz     3b
 4:             
        ret
-       
+
 /*
  * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
  *
@@ -620,6 +615,35 @@ Xcpustop:
        popl    %ebp
        iret
 
+       /*
+        * For now just have one ipiq IPI, but what we really want is
+        * to have one for each source cpu to the APICs don't get stalled
+        * backlogging the requests.
+        */
+       .text
+       SUPERALIGN_TEXT
+       .globl Xipiq
+Xipiq:
+       PUSH_FRAME
+       movl    $0, lapic_eoi           /* End Of Interrupt to APIC */
+       FAKE_MCOUNT(13*4(%esp))
+
+       movl    PCPU(curthread),%ebx
+       cmpl    $TDPRI_CRIT,TD_PRI(%ebx)
+       jge     1f
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
+       call    lwkt_process_ipiq
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
+       pushl   TD_CPL(%ebx)
+       incl    PCPU(intr_nesting_level)
+       MEXITCOUNT
+       jmp     doreti
+1:
+       movl    $TDPRI_CRIT,PCPU(reqpri)
+       orl     $AST_IPIQ,PCPU(astpending)
+       MEXITCOUNT
+       POP_FRAME
+       iret
 
 MCOUNT_LABEL(bintr)
        FAST_INTR(0,fastintr0)
@@ -792,8 +816,6 @@ CNAME(resched_cpus):
 CNAME(cpustop_restartfunc):
        .long 0
                
-
-
        .globl  apic_pin_trigger
 apic_pin_trigger:
        .long   0
index 4dc50c5..7b3c49b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/icu_vector.s,v 1.14.2.2 2000/07/18 21:12:42 dfr Exp $
- * $DragonFly: src/sys/i386/isa/Attic/icu_vector.s,v 1.11 2003/07/03 17:24:02 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/icu_vector.s,v 1.12 2003/07/08 06:27:27 dillon Exp $
  */
 
 /*
@@ -68,7 +68,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -83,7 +83,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define MASK_IRQ(icu, irq_num)                                         \
        movb    imen + IRQ_BYTE(irq_num),%al ;                          \
@@ -188,16 +188,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule its thread.  Leave
- *       interrupts masked and doreti.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule its thread.  Leave interrupts masked and doreti.
  *
- *     The interrupt thread will run its handlers and loop if 
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     sched_ithd() is called with interrupts enabled and outside of a
+ *     critical section (so it can preempt us).
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
  *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
@@ -219,8 +215,6 @@ IDTVEC(vec_name) ;                                                  \
        pushl   %eax ;          /* push CPL for doreti */               \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num), %eax ;                              \
        jz      2f ;                                                    \
 1: ;                                                                   \
@@ -229,15 +223,12 @@ IDTVEC(vec_name) ;                                                        \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -248,8 +239,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -258,7 +248,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(icu, irq_num) ;                                      \
        popl %ebp ;                                                     \
        ret ;                                                           \
index 11c9685..95cab68 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)isa.c 7.2 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
- * $DragonFly: src/sys/i386/isa/Attic/intr_machdep.c,v 1.6 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/intr_machdep.c,v 1.7 2003/07/08 06:27:27 dillon Exp $
  */
 /*
  * This file contains an aggregated module marked:
@@ -66,8 +66,8 @@
 #include <sys/thread2.h>
 
 #if defined(APIC_IO)
-#include <machine/smp.h>
 #include <machine/smptests.h>                  /** FAST_HI */
+#include <machine/smp.h>
 #endif /* APIC_IO */
 #ifdef PC98
 #include <pc98/pc98/pc98.h>
 
 static inthand2_t isa_strayintr;
 
+void   *intr_unit[ICU_LEN*2];
 u_long *intr_countp[ICU_LEN*2];
 inthand2_t *intr_handler[ICU_LEN*2] = {
        isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
@@ -124,10 +125,13 @@ inthand2_t *intr_handler[ICU_LEN*2] = {
        isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
        isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
 };
-u_int  intr_mask[ICU_LEN*2];
-int    intr_mihandler_installed[ICU_LEN*2];
-static u_int*  intr_mptr[ICU_LEN*2];
-void   *intr_unit[ICU_LEN*2];
+
+static struct md_intr_info {
+    int                irq;
+    u_int      mask;
+    int                mihandler_installed;
+    u_int      *maskp;
+} intr_info[ICU_LEN*2];
 
 static inthand_t *fastintr[ICU_LEN] = {
        &IDTVEC(fastintr0), &IDTVEC(fastintr1),
@@ -381,17 +385,17 @@ update_intr_masks(void)
 #else
                if (intr==ICU_SLAVEID) continue;        /* ignore 8259 SLAVE output */
 #endif /* APIC_IO */
-               maskptr = intr_mptr[intr];
+               maskptr = intr_info[intr].maskp;
                if (!maskptr)
                        continue;
                *maskptr |= SWI_CLOCK_MASK | (1 << intr);
                mask = *maskptr;
-               if (mask != intr_mask[intr]) {
+               if (mask != intr_info[intr].mask) {
 #if 0
                        printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
-                               intr, intr_mask[intr], mask, maskptr);
+                               intr, intr_info[intr].mask, mask, maskptr);
 #endif
-                       intr_mask[intr]=mask;
+                       intr_info[intr].mask = mask;
                        n++;
                }
 
@@ -474,9 +478,13 @@ icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
        ef = read_eflags();
        cpu_disable_intr();     /* YYY */
        intr_handler[intr] = handler;
-       intr_mptr[intr] = maskptr;
-       intr_mask[intr] = mask | SWI_CLOCK_MASK | (1 << intr);
        intr_unit[intr] = arg;
+       intr_info[intr].maskp = maskptr;
+       intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
+#if 0
+       /* YYY  fast ints supported and mp protected but ... */
+       flags &= ~INTR_FAST;
+#endif
 #ifdef FAST_HI
        if (flags & INTR_FAST) {
                vector = TPR_FAST_INTS + intr;
@@ -533,8 +541,8 @@ icu_unset(intr, handler)
        cpu_disable_intr();     /* YYY */
        intr_countp[intr] = &intrcnt[1 + intr];
        intr_handler[intr] = isa_strayintr;
-       intr_mptr[intr] = NULL;
-       intr_mask[intr] = HWI_MASK | SWI_MASK;
+       intr_info[intr].maskp = NULL;
+       intr_info[intr].mask = HWI_MASK | SWI_MASK;
        intr_unit[intr] = &intr_unit[intr];
 #ifdef FAST_HI_XXX
        /* XXX how do I re-create dvp here? */
@@ -697,9 +705,24 @@ update_masks(intrmask_t *maskptr, int irq)
 }
 
 /*
- * Add interrupt handler to linked list hung off of intreclist_head[irq]
- * and install shared interrupt multiplex handler, if necessary
+ * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
+ * and install a shared interrupt multiplex handler, if necessary.  Install
+ * an interrupt thread for each interrupt (though FAST interrupts will not
+ * use it).  The preemption procedure checks the CPL.  lwkt_preempt() will
+ * check relative thread priorities for us as long as we properly pass through
+ * critpri.
+ *
+ * YYY needs work.  At the moment the handler is run inside a critical
+ * section so only the preemption cpl check is used.
  */
+static void
+cpu_intr_preempt(struct thread *td, int critpri)
+{
+       struct md_intr_info *info = td->td_info.intdata;
+
+       if ((curthread->td_cpl & (1 << info->irq)) == 0)
+               lwkt_preempt(td, critpri);
+}
 
 static int
 add_intrdesc(intrec *idesc)
@@ -716,10 +739,15 @@ add_intrdesc(intrec *idesc)
         * temporary hack to run normal interrupts as interrupt threads.
         * YYY FIXME!
         */
-       if (intr_mihandler_installed[irq] == 0) {
-               intr_mihandler_installed[irq] = 1;
-               register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
-               printf("installing MI handler for int %d\n", irq);
+       if (intr_info[irq].mihandler_installed == 0) {
+               struct thread *td;
+
+               intr_info[irq].mihandler_installed = 1;
+               intr_info[irq].irq = irq;
+               td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
+               td->td_info.intdata = &intr_info[irq];
+               td->td_preemptable = cpu_intr_preempt;
+               printf("installed MI handler for int %d\n", irq);
        }
 
        head = intreclist_head[irq];
@@ -913,11 +941,8 @@ inthand_remove(intrec *idesc)
  * ithread_done()
  *
  *     This function is called by an interrupt thread when it has completed
- *     processing a loop.  We interlock with ipending and irunning.  If
- *     a new interrupt is pending for the thread the function clears the
- *     pending bit and returns.  If no new interrupt is pending we 
- *     deschedule and sleep.  If we reschedule and return we have to 
- *     disable the interrupt again or it will keep interrupting us.
+ *     processing a loop.  We re-enable itnerrupts and interlock with
+ *     ipending.
  *
  *     See kern/kern_intr.c for more information.
  */
@@ -928,21 +953,14 @@ ithread_done(int irq)
     int mask = 1 << irq;
 
     KKASSERT(curthread->td_pri >= TDPRI_CRIT);
+    lwkt_deschedule_self();
     INTREN(mask);
     if (gd->gd_ipending & mask) {
        atomic_clear_int(&gd->gd_ipending, mask);
        INTRDIS(mask);
        lwkt_schedule_self();
     } else {
-       lwkt_deschedule_self();
-       if (gd->gd_ipending & mask) {   /* race */
-           atomic_clear_int(&gd->gd_ipending, mask);
-           INTRDIS(mask);
-           lwkt_schedule_self();
-       } else {
-           atomic_clear_int(&gd->gd_irunning, mask);
-           lwkt_switch();
-       }
+       lwkt_switch();
     }
 }
 
index 332eae1..172e234 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/isa/intr_machdep.h,v 1.19.2.2 2001/10/14 20:05:50 luigi Exp $
- * $DragonFly: src/sys/i386/isa/Attic/intr_machdep.h,v 1.4 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/intr_machdep.h,v 1.5 2003/07/08 06:27:27 dillon Exp $
  */
 
 #ifndef _I386_ISA_INTR_MACHDEP_H_
 /* inter-CPU rendezvous */
 #define XRENDEZVOUS_OFFSET     (ICU_OFFSET + 114)
 
+/* IPIQ rendezvous */
+#define XIPIQ_OFFSET           (ICU_OFFSET + 115)
+
 /* IPI to generate an additional software trap at the target CPU */
 #define XCPUAST_OFFSET         (ICU_OFFSET +  48)
 
@@ -205,6 +208,7 @@ inthand_t
        Xforward_irq,   /* Forward irq to cpu holding ISR lock */
        Xcpustop,       /* CPU stops & waits for another CPU to restart it */
        Xspuriousint,   /* handle APIC "spurious INTs" */
+       Xipiq,          /* handle lwkt_send_ipiq() requests */
        Xrendezvous;    /* handle CPU rendezvous */
 
 #ifdef TEST_TEST1
index 4443de0..450a029 100644 (file)
@@ -37,7 +37,7 @@
  *     @(#)ipl.s
  *
  * $FreeBSD: src/sys/i386/isa/ipl.s,v 1.32.2.3 2002/05/16 16:03:56 bde Exp $
- * $DragonFly: src/sys/i386/isa/Attic/ipl.s,v 1.6 2003/07/01 20:31:38 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/ipl.s,v 1.7 2003/07/08 06:27:27 dillon Exp $
  */
 
 
@@ -68,10 +68,6 @@ soft_imask:  .long   SWI_MASK
 softnet_imask: .long   SWI_NET_MASK
        .globl  softtty_imask
 softtty_imask: .long   SWI_TTY_MASK
-       .globl  last_splz
-last_splz:     .long   0
-       .globl  last_splz2
-last_splz2:    .long   0
 
        .text
 
@@ -101,11 +97,12 @@ doreti_next:
        testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
        jne     doreti_fast
 
-       movl    PCPU(irunning),%edx     /* check for an unmasked normal int */
-       notl    %edx                    /* that isn't already running */
-       andl    %edx, %ecx
        testl   PCPU(ipending),%ecx
        jne     doreti_intr
+#ifdef SMP
+       testl   $AST_IPIQ,PCPU(astpending)
+       jnz     doreti_ipiq
+#endif
        testl   $AST_PENDING,PCPU(astpending) /* any pending ASTs? */
        jz      2f
        testl   $PSL_VM,TF_EFLAGS(%esp)
@@ -115,11 +112,11 @@ doreti_next:
 1:
        testb   $SEL_RPL_MASK,TF_CS(%esp)
        jnz     doreti_ast
-
+2:
        /*
         * Nothing left to do, finish up.  Interrupts are still disabled.
         */
-2:
+4:
        subl    $TDPRI_CRIT,TD_PRI(%ebx)        /* interlocked with cli */
 5:
        decl    PCPU(intr_nesting_level)
@@ -168,13 +165,31 @@ doreti_fast:
        bsfl    %ecx, %ecx              /* locate the next dispatchable int */
        btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
        jnc     doreti_next
-       pushl   %eax                    /* YYY cpl */
-       call    *fastunpend(,%ecx,4)
+       pushl   %eax                    /* YYY cpl (expected by frame) */
+#ifdef SMP
+       pushl   %ecx                    /* save ecx */
+       call    try_mplock
+       popl    %ecx
+       testl   %eax,%eax
+       jz      1f
+#endif
+       call    *fastunpend(,%ecx,4)    /* MP lock successful */
+#ifdef SMP
+       call    rel_mplock
+#endif
+       popl    %eax
+       jmp     doreti_next
+1:
+       btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
        popl    %eax
+       orl     PCPU(fpending),%eax
        jmp     doreti_next
 
        /*
         *  INTR interrupt pending
+        *
+        *  Temporarily back-out our critical section to allow the interrupt
+        *  preempt us.
         */
        ALIGN_TEXT
 doreti_intr:
@@ -184,7 +199,9 @@ doreti_intr:
        jnc     doreti_next
        pushl   %eax
        pushl   %ecx
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
        call    sched_ithd              /* YYY must pull in imasks */
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
        addl    $4,%esp
        popl    %eax
        jmp     doreti_next
@@ -195,13 +212,25 @@ doreti_intr:
 doreti_ast:
        andl    $~AST_PENDING,PCPU(astpending)
        sti
+       movl    %eax,%esi               /* save cpl (can't use stack) */
        movl    $T_ASTFLT,TF_TRAPNO(%esp)
        decl    PCPU(intr_nesting_level)
        call    trap
        incl    PCPU(intr_nesting_level)
+       movl    %esi,%eax               /* restore cpl for loop */
+       jmp     doreti_next
+
+#ifdef SMP
+       /*
+        * IPIQ message pending
+        */
+doreti_ipiq:
+       andl    $~AST_IPIQ,PCPU(astpending)
+       call    lwkt_process_ipiq
        movl    TD_CPL(%ebx),%eax       /* retrieve cpl again for loop */
        jmp     doreti_next
 
+#endif
 
        /*
         * SPLZ() a C callable procedure to dispatch any unmasked pending
@@ -227,12 +256,14 @@ splz_next:
        testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
        jne     splz_fast
 
-       movl    PCPU(irunning),%edx     /* check for an unmasked normal int */
-       notl    %edx                    /* that isn't already running */
-       andl    %edx, %ecx
        testl   PCPU(ipending),%ecx
        jne     splz_intr
 
+#ifdef SMP
+       testl   $AST_IPIQ,PCPU(astpending)
+       jnz     splz_ipiq
+#endif
+
        subl    $TDPRI_CRIT,TD_PRI(%ebx)
        popl    %ebx
        popfl
@@ -247,16 +278,31 @@ splz_fast:
        bsfl    %ecx, %ecx              /* locate the next dispatchable int */
        btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
        jnc     splz_next
-       movl    $1,last_splz
-       movl    %ecx,last_splz2
        pushl   %eax
+#ifdef SMP
+       pushl   %ecx
+       call    try_mplock
+       popl    %ecx
+       testl   %eax,%eax
+       jz      1f
+#endif
        call    *fastunpend(,%ecx,4)
+#ifdef SMP
+       call    rel_mplock
+#endif
+       popl    %eax
+       jmp     splz_next
+1:
+       btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
        popl    %eax
-       movl    $-1,last_splz
+       orl     PCPU(fpending),%eax
        jmp     splz_next
 
        /*
         *  INTR interrupt pending
+        *
+        *  Temporarily back-out our critical section to allow the interrupt
+        *  preempt us.
         */
        ALIGN_TEXT
 splz_intr:
@@ -265,16 +311,24 @@ splz_intr:
        btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
        jnc     splz_next
        sti
-       movl    $2,last_splz
        pushl   %eax
        pushl   %ecx
-       movl    %ecx,last_splz2
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
        call    sched_ithd              /* YYY must pull in imasks */
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
        addl    $4,%esp
        popl    %eax
-       movl    $-2,last_splz
        jmp     splz_next
 
+#ifdef SMP
+splz_ipiq:
+       andl    $~AST_IPIQ,PCPU(astpending)
+       pushl   %eax
+       call    lwkt_process_ipiq
+       popl    %eax
+       jmp     splz_next
+#endif
+
        /*
         * APIC/ICU specific ipl functions provide masking and unmasking
         * calls for userland.
index 05526ef..7a6c54e 100644 (file)
@@ -33,7 +33,7 @@
  *
  *     from: @(#)npx.c 7.2 (Berkeley) 5/12/91
  * $FreeBSD: src/sys/i386/isa/npx.c,v 1.80.2.3 2001/10/20 19:04:38 tegge Exp $
- * $DragonFly: src/sys/i386/isa/Attic/npx.c,v 1.7 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/npx.c,v 1.8 2003/07/08 06:27:27 dillon Exp $
  */
 
 #include "opt_cpu.h"
@@ -861,6 +861,11 @@ npxdna()
  * often called at splhigh so it must not use many system services.  In
  * particular, it's much easier to install a special handler than to
  * guarantee that it's safe to use npxintr() and its supporting code.
+ *
+ * WARNING!  This call is made during a switch and the MP lock will be
+ * setup for the new target thread rather then the current thread, so we
+ * cannot do anything here that depends on the *_mplock() functions as
+ * we may trip over their assertions.
  */
 void
 npxsave(addr)
index 5498149..aa11f82 100644 (file)
@@ -24,7 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_intr.c,v 1.24.2.1 2001/10/14 20:05:50 luigi Exp $
- * $DragonFly: src/sys/kern/kern_intr.c,v 1.7 2003/07/04 05:57:27 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_intr.c,v 1.8 2003/07/08 06:27:27 dillon Exp $
  *
  */
 
@@ -54,18 +54,19 @@ static intrec_t     *intlists[NHWI+NSWI];
 static thread_t ithreads[NHWI+NSWI];
 static struct thread ithread_ary[NHWI+NSWI];
 static struct random_softc irandom_ary[NHWI+NSWI];
+static int irunning[NHWI+NSWI];
 
 static void ithread_handler(void *arg);
 
-void
+thread_t
 register_swi(int intr, inthand2_t *handler, void *arg, const char *name)
 {
     if (intr < NHWI || intr >= NHWI + NSWI)
        panic("register_swi: bad intr %d", intr);
-    register_int(intr, handler, arg, name);
+    return(register_int(intr, handler, arg, name));
 }
 
-void
+thread_t
 register_int(int intr, inthand2_t *handler, void *arg, const char *name)
 {
     intrec_t **list;
@@ -110,6 +111,7 @@ register_int(int intr, inthand2_t *handler, void *arg, const char *name)
        list = &(*list)->next;
     *list = rec;
     crit_exit();
+    return(td);
 }
 
 void
@@ -175,7 +177,21 @@ unregister_randintr(int intr)
 /*
  * Dispatch an interrupt.  If there's nothing to do we have a stray
  * interrupt and can just return, leaving the interrupt masked.
+ *
+ * We need to schedule the interrupt and set its irunning[] bit.  If
+ * we are not on the interrupt thread's cpu we have to send a message
+ * to the correct cpu that will issue the desired action (interlocking
+ * with the interrupt thread's critical section).
+ *
+ * We are NOT in a critical section, which will allow the scheduled
+ * interrupt to preempt us.
  */
+static void
+sched_ithd_remote(void *arg)
+{
+    sched_ithd((int)arg);
+}
+
 void
 sched_ithd(int intr)
 {
@@ -185,8 +201,14 @@ sched_ithd(int intr)
        if (intlists[intr] == NULL) {
            printf("sched_ithd: stray interrupt %d\n", intr);
        } else {
-           lwkt_schedule(td);
-           lwkt_preempt(td, intr);
+           if (td->td_cpu == mycpu->gd_cpuid) {
+               irunning[intr] = 1;
+               lwkt_schedule(td);      /* preemption handled internally */
+           } else {
+               crit_enter();
+               lwkt_send_ipiq(td->td_cpu, sched_ithd_remote, (void *)intr);
+               crit_exit();
+           }
        }
     } else {
        printf("sched_ithd: stray interrupt %d\n", intr);
@@ -208,17 +230,18 @@ ithread_handler(void *arg)
 
     KKASSERT(curthread->td_pri >= TDPRI_CRIT);
     for (;;) {
+       irunning[intr] = 0;
        for (rec = *list; rec; rec = nrec) {
            nrec = rec->next;
            rec->handler(rec->argument);
        }
        if (sc->sc_enabled)
-               add_interrupt_randomness(intr);
-       ithread_done(intr);
+           add_interrupt_randomness(intr);
+       if (irunning[intr] == 0)
+           ithread_done(intr);
     }
 }
 
-
 /* 
  * Sysctls used by systat and others: hw.intrnames and hw.intrcnt.
  * The data for this machine dependent, and the declarations are in machine
index b1c0cb6..02d43bc 100644 (file)
  *
  *     Each cpu in a system has its own self-contained light weight kernel
  *     thread scheduler, which means that generally speaking we only need
- *     to use a critical section to prevent hicups.
+ *     to use a critical section to avoid problems.  Foreign thread 
+ *     scheduling is queued via (async) IPIs.
  *
- * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.15 2003/07/06 21:23:51 dillon Exp $
+ * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.16 2003/07/08 06:27:27 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -53,6 +54,9 @@
 #include <vm/vm_zone.h>
 
 #include <machine/stdarg.h>
+#ifdef SMP
+#include <machine/smp.h>
+#endif
 
 static int untimely_switch = 0;
 SYSCTL_INT(_lwkt, OID_AUTO, untimely_switch, CTLFLAG_RW, &untimely_switch, 0, "");
@@ -64,6 +68,10 @@ static quad_t preempt_miss = 0;
 SYSCTL_QUAD(_lwkt, OID_AUTO, preempt_miss, CTLFLAG_RW, &preempt_miss, 0, "");
 static quad_t preempt_weird = 0;
 SYSCTL_QUAD(_lwkt, OID_AUTO, preempt_weird, CTLFLAG_RW, &preempt_weird, 0, "");
+static quad_t ipiq_count = 0;
+SYSCTL_QUAD(_lwkt, OID_AUTO, ipiq_count, CTLFLAG_RW, &ipiq_count, 0, "");
+static quad_t ipiq_fifofull = 0;
+SYSCTL_QUAD(_lwkt, OID_AUTO, ipiq_fifofull, CTLFLAG_RW, &ipiq_fifofull, 0, "");
 
 /*
  * These helper procedures handle the runq, they can only be called from
@@ -262,16 +270,20 @@ lwkt_free_thread(thread_t td)
  * talk to our cpu, so a critical section is all that is needed and
  * the result is very, very fast thread switching.
  *
- * We always 'own' our own thread and the threads on our run queue,l
- * due to TDF_RUNNING or TDF_RUNQ being set.  We can safely clear
- * TDF_RUNNING while in a critical section.
+ * The LWKT scheduler uses a fixed priority model and round-robins at
+ * each priority level.  User process scheduling is a totally
+ * different beast and LWKT priorities should not be confused with
+ * user process priorities.
  *
- * The td_switch() function must be called while in the critical section.
- * This function saves as much state as is appropriate for the type of
- * thread.
- *
- * (self contained on a per cpu basis)
+ * The MP lock may be out of sync with the thread's td_mpcount.  lwkt_switch()
+ * cleans it up.  Note that the td_switch() function cannot do anything that
+ * requires the MP lock since the MP lock will have already been setup for
+ * the target thread (not the current thread).
  */
+
+int swtarg[32][2];
+int swtarg2;
+
 void
 lwkt_switch(void)
 {
@@ -282,8 +294,11 @@ lwkt_switch(void)
     int mpheld;
 #endif
 
-    if (mycpu->gd_intr_nesting_level && td->td_preempted == NULL)
+    if (mycpu->gd_intr_nesting_level && 
+       td->td_preempted == NULL && panicstr == NULL
+    ) {
        panic("lwkt_switch: cannot switch from within an interrupt, yet\n");
+    }
 
     crit_enter();
     ++switch_count;
@@ -309,6 +324,10 @@ lwkt_switch(void)
         */
        KKASSERT(ntd->td_flags & TDF_PREEMPT_LOCK);
 #ifdef SMP
+       if (ntd->td_mpcount && mpheld == 0) {
+           panic("MPLOCK NOT HELD ON RETURN: %p %p %d %d\n",
+              td, ntd, td->td_mpcount, ntd->td_mpcount);
+       }
        if (ntd->td_mpcount) {
            td->td_mpcount -= ntd->td_mpcount;
            KKASSERT(td->td_mpcount >= 0);
@@ -339,7 +358,9 @@ again:
 #ifdef SMP
            if (ntd->td_mpcount && mpheld == 0 && !cpu_try_mplock()) {
                /*
-                * Target needs MP lock and we couldn't get it.
+                * Target needs MP lock and we couldn't get it, try
+                * to locate a thread which does not need the MP lock
+                * to run.
                 */
                u_int32_t rqmask = gd->gd_runqmask;
                while (rqmask) {
@@ -387,21 +408,34 @@ again:
     }
 #endif
 
+       if (mycpu->gd_cpuid == 1) {
+       bcopy(swtarg[0], swtarg[1], sizeof(int)*31*2);
+       swtarg[0][0] = (int)ntd->td_sp;
+       swtarg[0][1] = *(int *)ntd->td_sp;
+       }
+       KKASSERT(td->td_cpu == ntd->td_cpu);
     if (td != ntd) {
        td->td_switch(ntd);
     }
+
     crit_exit();
 }
 
 /*
- * Request that the target thread preempt the current thread.  This only
- * works if:
+ * Request that the target thread preempt the current thread.  Preemption
+ * only works under a specific set of conditions:
  *
- *     + We aren't trying to preempt ourselves (it can happen!)
- *     + We are not currently being preempted
- *     + The target is not currently being preempted
- *     + The target either does not need the MP lock or we can get it
- *       for the target immediately.
+ *     - We are not preempting ourselves
+ *     - The target thread is owned by the current cpu
+ *     - We are not currently being preempted
+ *     - The target is not currently being preempted
+ *     - We are able to satisfy the target's MP lock requirements (if any).
+ *
+ * THE CALLER OF LWKT_PREEMPT() MUST BE IN A CRITICAL SECTION.  Typically
+ * this is called via lwkt_schedule() through the td_preemptable callback.
+ * critpri is the managed critical priority that we should ignore in order
+ * to determine whether preemption is possible (aka usually just the crit
+ * priority of lwkt_schedule() itself).
  *
  * XXX at the moment we run the target thread in a critical section during
  * the preemption in order to prevent the target from taking interrupts
@@ -411,33 +445,42 @@ again:
  * whether or not the source is scheduled (i.e. preemption is supposed to
  * be as transparent as possible).
  *
- * This call is typically made from an interrupt handler like sched_ithd()
- * which will only run if the current thread is not in a critical section,
- * so we optimize the priority check a bit.
- *
- * CAREFUL! either we or the target thread may get interrupted during the
- * switch.
- *
  * The target thread inherits our MP count (added to its own) for the
  * duration of the preemption in order to preserve the atomicy of the
- * preemption.
+ * MP lock during the preemption.  Therefore, any preempting targets must be
+ * careful in regards to MP assertions.  Note that the MP count may be
+ * out of sync with the physical mp_lock.  If we preempt we have to preserve
+ * the expected situation.
  */
 void
-lwkt_preempt(thread_t ntd, int id)
+lwkt_preempt(thread_t ntd, int critpri)
 {
     thread_t td = curthread;
 #ifdef SMP
     int mpheld;
 #endif
+int savecnt;
 
     /*
-     * The caller has put us in a critical section, and in order to have
-     * gotten here in the first place the thread the caller interrupted
-     * cannot have been in a critical section before.
+     * The caller has put us in a critical section.  We can only preempt
+     * if the caller of the caller was not in a critical section (basically
+     * a local interrupt). 
+     *
+     * YYY The target thread must be in a critical section (else it must
+     * inherit our critical section?  I dunno yet).
      */
     KASSERT(ntd->td_pri >= TDPRI_CRIT, ("BADCRIT0 %d", ntd->td_pri));
-    KASSERT((td->td_pri & ~TDPRI_MASK) == TDPRI_CRIT, ("BADPRI %d", td->td_pri));
 
+    if ((td->td_pri & ~TDPRI_MASK) > critpri) {
+       ++preempt_miss;
+       return;
+    }
+#ifdef SMP
+    if (ntd->td_cpu != mycpu->gd_cpuid) {
+       ++preempt_miss;
+       return;
+    }
+#endif
     if (td == ntd || ((td->td_flags | ntd->td_flags) & TDF_PREEMPT_LOCK)) {
        ++preempt_weird;
        return;
@@ -452,6 +495,9 @@ lwkt_preempt(thread_t ntd, int id)
     }
 #ifdef SMP
     mpheld = MP_LOCK_HELD();
+    if (mpheld && td->td_mpcount == 0)
+       panic("lwkt_preempt(): held and no count");
+    savecnt = td->td_mpcount;
     ntd->td_mpcount += td->td_mpcount;
     if (mpheld == 0 && ntd->td_mpcount && !cpu_try_mplock()) {
        ntd->td_mpcount -= td->td_mpcount;
@@ -465,6 +511,13 @@ lwkt_preempt(thread_t ntd, int id)
     td->td_flags |= TDF_PREEMPT_LOCK;
     td->td_switch(ntd);
     KKASSERT(ntd->td_preempted && (td->td_flags & TDF_PREEMPT_DONE));
+#ifdef SMP
+    KKASSERT(savecnt == td->td_mpcount);
+    if (mpheld == 0 && MP_LOCK_HELD())
+       cpu_rel_mplock();
+    else if (mpheld && !MP_LOCK_HELD())
+       panic("lwkt_preempt(): MP lock was not held through");
+#endif
     ntd->td_preempted = NULL;
     td->td_flags &= ~(TDF_PREEMPT_LOCK|TDF_PREEMPT_DONE);
 }
@@ -555,18 +608,14 @@ lwkt_schedule_self(void)
  * Generic schedule.  Possibly schedule threads belonging to other cpus and
  * deal with threads that might be blocked on a wait queue.
  *
- * This function will queue requests asynchronously when possible, but may
- * block if no request structures are available.  Upon return the caller
- * should note that the scheduling request may not yet have been processed
- * by the target cpu.
- *
- * YYY this is one of the best places to implement any load balancing code.
+ * YYY this is one of the best places to implement load balancing code.
  * Load balancing can be accomplished by requesting other sorts of actions
  * for the thread in question.
  */
 void
 lwkt_schedule(thread_t td)
 {
+#ifdef INVARIANTS
     if ((td->td_flags & TDF_PREEMPT_LOCK) == 0 && td->td_proc 
        && td->td_proc->p_stat == SSLEEP
     ) {
@@ -580,6 +629,7 @@ lwkt_schedule(thread_t td)
        );
        panic("SCHED PANIC");
     }
+#endif
     crit_enter();
     if (td == curthread) {
        _lwkt_enqueue(td);
@@ -597,27 +647,20 @@ lwkt_schedule(thread_t td)
         * (remember, wait structures use stable storage)
         */
        if ((w = td->td_wait) != NULL) {
-           if (lwkt_havetoken(&w->wa_token)) {
+           if (lwkt_trytoken(&w->wa_token)) {
                TAILQ_REMOVE(&w->wa_waitq, td, td_threadq);
                --w->wa_count;
                td->td_wait = NULL;
                if (td->td_cpu == mycpu->gd_cpuid) {
                    _lwkt_enqueue(td);
+                   if (td->td_preemptable)
+                       td->td_preemptable(td, TDPRI_CRIT*2); /* YYY +token */
                } else {
-                   panic("lwkt_schedule: cpu mismatch1");
-#if 0
-                   lwkt_cpu_msg_union_t msg = lwkt_getcpumsg();
-                   initScheduleReqMsg_Wait(&msg.mu_SchedReq, td, w);
-                   cpu_sendnormsg(&msg.mu_Msg);
-#endif
+                   lwkt_send_ipiq(td->td_cpu, (ipifunc_t)lwkt_schedule, td);
                }
+               lwkt_reltoken(&w->wa_token);
            } else {
-               panic("lwkt_schedule: cpu mismatch2");
-#if 0
-               lwkt_cpu_msg_union_t msg = lwkt_getcpumsg();
-               initScheduleReqMsg_Wait(&msg.mu_SchedReq, td, w);
-               cpu_sendnormsg(&msg.mu_Msg);
-#endif
+               lwkt_send_ipiq(w->wa_token.t_cpu, (ipifunc_t)lwkt_schedule, td);
            }
        } else {
            /*
@@ -628,13 +671,10 @@ lwkt_schedule(thread_t td)
             */
            if (td->td_cpu == mycpu->gd_cpuid) {
                _lwkt_enqueue(td);
+               if (td->td_preemptable)
+                   td->td_preemptable(td, TDPRI_CRIT);
            } else {
-               panic("lwkt_schedule: cpu mismatch3");
-#if 0
-               lwkt_cpu_msg_union_t msg = lwkt_getcpumsg();
-               initScheduleReqMsg_Thread(&msg.mu_SchedReq, td);
-               cpu_sendnormsg(&msg.mu_Msg);
-#endif
+               lwkt_send_ipiq(td->td_cpu, (ipifunc_t)lwkt_schedule, td);
            }
        }
     }
@@ -674,12 +714,7 @@ lwkt_deschedule(thread_t td)
        if (td->td_cpu == mycpu->gd_cpuid) {
            _lwkt_dequeue(td);
        } else {
-           panic("lwkt_deschedule: cpu mismatch");
-#if 0
-           lwkt_cpu_msg_union_t msg = lwkt_getcpumsg();
-           initDescheduleReqMsg_Thread(&msg.mu_DeschedReq, td);
-           cpu_sendnormsg(&msg.mu_Msg);
-#endif
+           lwkt_send_ipiq(td->td_cpu, (ipifunc_t)lwkt_deschedule, td);
        }
     }
     crit_exit();
@@ -747,6 +782,11 @@ lwkt_preempted_proc(void)
  *
  * Note: wait queue signals normally ping-pong the cpu as an optimization.
  */
+typedef struct lwkt_gettoken_req {
+    lwkt_token_t tok;
+    int        cpu;
+} lwkt_gettoken_req;
+
 void
 lwkt_block(lwkt_wait_t w, const char *wmesg, int *gen)
 {
@@ -792,12 +832,7 @@ lwkt_signal(lwkt_wait_t w)
        if (td->td_cpu == mycpu->gd_cpuid) {
            _lwkt_enqueue(td);
        } else {
-#if 0
-           lwkt_cpu_msg_union_t msg = lwkt_getcpumsg();
-           initScheduleReqMsg_Thread(&msg.mu_SchedReq, td);
-           cpu_sendnormsg(&msg.mu_Msg);
-#endif
-           panic("lwkt_signal: cpu mismatch");
+           lwkt_send_ipiq(td->td_cpu, (ipifunc_t)lwkt_schedule, td);
        }
        lwkt_regettoken(&w->wa_token);
     }
@@ -805,17 +840,35 @@ lwkt_signal(lwkt_wait_t w)
 }
 
 /*
- * Aquire ownership of a token
+ * Acquire ownership of a token
  *
- * Aquire ownership of a token.  The token may have spl and/or critical
+ * Acquire ownership of a token.  The token may have spl and/or critical
  * section side effects, depending on its purpose.  These side effects
  * guarentee that you will maintain ownership of the token as long as you
  * do not block.  If you block you may lose access to the token (but you
  * must still release it even if you lose your access to it).
  *
- * Note that the spl and critical section characteristics of a token
- * may not be changed once the token has been initialized.
+ * YYY for now we use a critical section to prevent IPIs from taking away
+ * a token, but we really only need to disable IPIs ?
+ *
+ * YYY certain tokens could be made to act like mutexes when performance
+ * would be better (e.g. t_cpu == -1).  This is not yet implemented.
+ *
+ * If the token is owned by another cpu we may have to send an IPI to
+ * it and then block.   The IPI causes the token to be given away to the
+ * requesting cpu, unless it has already changed hands.  Since only the
+ * current cpu can give away a token it owns we do not need a memory barrier.
  */
+static
+void
+lwkt_gettoken_remote(void *arg)
+{
+    lwkt_gettoken_req *req = arg;
+    if (req->tok->t_cpu == mycpu->gd_cpuid) {
+       req->tok->t_cpu = req->cpu;
+    }
+}
+
 int
 lwkt_gettoken(lwkt_token_t tok)
 {
@@ -825,12 +878,19 @@ lwkt_gettoken(lwkt_token_t tok)
      * block.  The request will be forwarded as necessary playing catchup
      * to the token.
      */
+    struct lwkt_gettoken_req req;
+    int seq;
+
     crit_enter();
-#if 0
+#ifdef SMP
     while (tok->t_cpu != mycpu->gd_cpuid) {
-       lwkt_cpu_msg_union msg;
-       initTokenReqMsg(&msg.mu_TokenReq);
-       cpu_domsg(&msg);
+       int dcpu;
+
+       req.cpu = mycpu->gd_cpuid;
+       req.tok = tok;
+       dcpu = (volatile int)tok->t_cpu;
+       seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
+       lwkt_wait_ipiq(dcpu, seq);
     }
 #endif
     /*
@@ -840,6 +900,24 @@ lwkt_gettoken(lwkt_token_t tok)
     return(++tok->t_gen);
 }
 
+/*
+ * Attempt to acquire ownership of a token.  Returns 1 on success, 0 on
+ * failure.
+ */
+int
+lwkt_trytoken(lwkt_token_t tok)
+{
+    crit_enter();
+#ifdef SMP
+    if (tok->t_cpu != mycpu->gd_cpuid) {
+       return(0);
+    } 
+#endif
+    /* leave us in the critical section */
+    ++tok->t_gen;
+    return(1);
+}
+
 /*
  * Release your ownership of a token.  Releases must occur in reverse
  * order to aquisitions, eventually so priorities can be unwound properly
@@ -882,21 +960,29 @@ lwkt_gentoken(lwkt_token_t tok, int *gen)
 
 
 /*
- * Reacquire a token that might have been lost.  Returns the generation 
+ * Re-acquire a token that might have been lost.  Returns the generation 
  * number of the token.
  */
 int
 lwkt_regettoken(lwkt_token_t tok)
 {
-#if 0
+    struct lwkt_gettoken_req req;
+    int seq;
+
+    /* assert we are in a critical section */
     if (tok->t_cpu != mycpu->gd_cpuid) {
+#ifdef SMP
        while (tok->t_cpu != mycpu->gd_cpuid) {
-           lwkt_cpu_msg_union msg;
-           initTokenReqMsg(&msg.mu_TokenReq);
-           cpu_domsg(&msg);
+           int dcpu;
+           req.cpu = mycpu->gd_cpuid;
+           req.tok = tok;
+           dcpu = (volatile int)tok->t_cpu;
+           seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
+           lwkt_wait_ipiq(dcpu, seq);
        }
-    }
 #endif
+       ++tok->t_gen;
+    }
     return(tok->t_gen);
 }
 
@@ -1023,3 +1109,128 @@ kthread_exit(void)
     lwkt_exit();
 }
 
+#ifdef SMP
+
+/*
+ * Send a function execution request to another cpu.  The request is queued
+ * on the cpu<->cpu ipiq matrix.  Each cpu owns a unique ipiq FIFO for every
+ * possible target cpu.  The FIFO can be written.
+ *
+ * YYY If the FIFO fills up we have to enable interrupts and process the
+ * IPIQ while waiting for it to empty or we may deadlock with another cpu.
+ * Create a CPU_*() function to do this!
+ *
+ * Must be called from a critical section.
+ */
+int
+lwkt_send_ipiq(int dcpu, ipifunc_t func, void *arg)
+{
+    lwkt_ipiq_t ip;
+    int windex;
+
+    if (dcpu == mycpu->gd_cpuid) {
+       func(arg);
+       return(0);
+    } 
+    KKASSERT(curthread->td_pri >= TDPRI_CRIT);
+    KKASSERT(dcpu >= 0 && dcpu < ncpus);
+    ++ipiq_count;
+    ip = &mycpu->gd_ipiq[dcpu];
+    if (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 2) {
+       unsigned int eflags = read_eflags();
+       cpu_enable_intr();
+       ++ipiq_fifofull;
+       while (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 2) {
+           KKASSERT(ip->ip_windex - ip->ip_rindex != MAXCPUFIFO - 1);
+           lwkt_process_ipiq();
+       }
+       write_eflags(eflags);
+    }
+    KKASSERT(ip->ip_windex - ip->ip_rindex != MAXCPUFIFO - 1);
+    windex = ip->ip_windex & MAXCPUFIFO_MASK;
+    ip->ip_func[windex] = func;
+    ip->ip_arg[windex] = arg;
+    /* YYY memory barrier */
+    ++ip->ip_windex;
+    cpu_send_ipiq(dcpu);       /* issues memory barrier if appropriate */
+    return(ip->ip_windex);
+}
+
+/*
+ * Wait for the remote cpu to finish processing a function.
+ *
+ * YYY we have to enable interrupts and process the IPIQ while waiting
+ * for it to empty or we may deadlock with another cpu.  Create a CPU_*()
+ * function to do this!  YYY we really should 'block' here.
+ *
+ * Must be called from a critical section.  Thsi routine may be called
+ * from an interrupt (for example, if an interrupt wakes a foreign thread
+ * up).
+ */
+void
+lwkt_wait_ipiq(int dcpu, int seq)
+{
+    lwkt_ipiq_t ip;
+
+    if (dcpu != mycpu->gd_cpuid) {
+       KKASSERT(dcpu >= 0 && dcpu < ncpus);
+       ip = &mycpu->gd_ipiq[dcpu];
+       if ((int)(ip->ip_rindex - seq) < 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((int)(ip->ip_rindex - seq) < 0) {
+               lwkt_process_ipiq();
+#if 0
+               lwkt_switch();  /* YYY fixme */
+#endif
+           }
+           write_eflags(eflags);
+       }
+    }
+}
+
+/*
+ * Called from IPI interrupt (like a fast interrupt), which has placed
+ * us in a critical section.  The MP lock may or may not be held.
+ * May also be called from doreti or splz.
+ */
+void
+lwkt_process_ipiq(void)
+{
+    int n;
+    int cpuid = mycpu->gd_cpuid;
+
+    for (n = 0; n < ncpus; ++n) {
+       lwkt_ipiq_t ip;
+       int ri;
+
+       if (n == cpuid)
+           continue;
+       ip = globaldata_find(n)->gd_ipiq;
+       if (ip == NULL)
+           continue;
+       ip = &ip[cpuid];
+       while (ip->ip_rindex != ip->ip_windex) {
+           ri = ip->ip_rindex & MAXCPUFIFO_MASK;
+           ip->ip_func[ri](ip->ip_arg[ri]);
+           ++ip->ip_rindex;
+       }
+    }
+}
+
+#else
+
+int
+lwkt_send_ipiq(int dcpu, ipifunc_t func, void *arg)
+{
+    panic("lwkt_send_ipiq: UP box! (%d,%p,%p)", dcpu, func, arg);
+    return(0); /* NOT REACHED */
+}
+
+void
+lwkt_wait_ipiq(int dcpu, int seq)
+{
+    panic("lwkt_wait_ipiq: UP box! (%d,%d)", dcpu, seq);
+}
+
+#endif
index fab5073..aede11d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/apic_vector.s,v 1.47.2.5 2001/09/01 22:33:38 tegge Exp $
- * $DragonFly: src/sys/platform/pc32/apic/apic_vector.s,v 1.8 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/apic/apic_vector.s,v 1.9 2003/07/08 06:27:27 dillon Exp $
  */
 
 
@@ -38,7 +38,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -53,7 +53,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define IOAPICADDR(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 8
 #define REDIRIDX(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 12
@@ -165,6 +165,10 @@ IDTVEC(vec_name) ;                                                 \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
+       /* try to get giant */                                          \
+       call    try_mplock ;                                            \
+       testl   %eax,%eax ;                                             \
+       jz      1b ;                                                    \
        /* clear pending bit, run handler */                            \
        addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        andl    $~IRQ_LBIT(irq_num),PCPU(fpending) ;                    \
@@ -175,6 +179,7 @@ IDTVEC(vec_name) ;                                                  \
        incl    PCPU(cnt)+V_INTR ;      /* book-keeping make per cpu YYY */ \
        movl    intr_countp + (irq_num) * 4, %eax ;                     \
        incl    (%eax) ;                                                \
+       call    rel_mplock ;                                            \
        UNMASK_IRQ(irq_num) ;                                           \
 5: ;                                                                   \
        MEXITCOUNT ;                                                    \
@@ -190,6 +195,8 @@ IDTVEC(vec_name) ;                                                  \
  *     - Unmask the interrupt
  *     - Pop the dummy frame and do a normal return
  *
+ *     The BGL is held on call and left held on return.
+ *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
  */
@@ -221,17 +228,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule the thread.  Leave
- *       interrupts masked and doreti.
- *
- *     the interrupt thread will run its handlers and loop if
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule the thread.  Leave interrupts masked and doreti.
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
- *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
+ *     Note that calls to sched_ithd() are made with interrupts enabled
+ *     and outside a critical section.  YYY sched_ithd may preempt us
+ *     synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
@@ -252,25 +254,20 @@ IDTVEC(vec_name) ;                                                        \
        pushl   %eax ;          /* cpl do restore */                    \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num),%eax ;                               \
-       jz      1f ;                                                    \
+       jz      2f ;                                                    \
 1: ;                                                                   \
        /* set the pending bit and return, leave the interrupt masked */ \
        orl     $IRQ_LBIT(irq_num), PCPU(ipending) ;                    \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -281,8 +278,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -291,7 +287,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(irq_num) ;                                           \
        popl %ebp ;                                                     \
        ret ;                                                           \
@@ -455,7 +450,7 @@ Xcpuast:
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
        orl     $AST_PENDING, PCPU(astpending)  /* XXX */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        movl    PCPU(cpuid), %eax
@@ -497,7 +492,7 @@ Xforward_irq:
        movl    PCPU(curthread), %eax
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        MEXITCOUNT
@@ -552,7 +547,7 @@ forward_irq:
        jnz     3b
 4:             
        ret
-       
+
 /*
  * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
  *
@@ -620,6 +615,35 @@ Xcpustop:
        popl    %ebp
        iret
 
+       /*
+        * For now just have one ipiq IPI, but what we really want is
+        * to have one for each source cpu to the APICs don't get stalled
+        * backlogging the requests.
+        */
+       .text
+       SUPERALIGN_TEXT
+       .globl Xipiq
+Xipiq:
+       PUSH_FRAME
+       movl    $0, lapic_eoi           /* End Of Interrupt to APIC */
+       FAKE_MCOUNT(13*4(%esp))
+
+       movl    PCPU(curthread),%ebx
+       cmpl    $TDPRI_CRIT,TD_PRI(%ebx)
+       jge     1f
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
+       call    lwkt_process_ipiq
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
+       pushl   TD_CPL(%ebx)
+       incl    PCPU(intr_nesting_level)
+       MEXITCOUNT
+       jmp     doreti
+1:
+       movl    $TDPRI_CRIT,PCPU(reqpri)
+       orl     $AST_IPIQ,PCPU(astpending)
+       MEXITCOUNT
+       POP_FRAME
+       iret
 
 MCOUNT_LABEL(bintr)
        FAST_INTR(0,fastintr0)
@@ -792,8 +816,6 @@ CNAME(resched_cpus):
 CNAME(cpustop_restartfunc):
        .long 0
                
-
-
        .globl  apic_pin_trigger
 apic_pin_trigger:
        .long   0
index 5e141aa..a48c8be 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/mpapic.c,v 1.37.2.7 2003/01/25 02:31:47 peter Exp $
- * $DragonFly: src/sys/platform/pc32/apic/mpapic.c,v 1.4 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/apic/mpapic.c,v 1.5 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -33,6 +33,7 @@
 #include <machine/smp.h>
 #include <machine/mpapic.h>
 #include <machine/segments.h>
+#include <sys/thread2.h>
 
 #include <i386/isa/intr_machdep.h>     /* Xspuriousint() */
 
@@ -79,8 +80,10 @@ apic_initialize(void)
         * Leave the BSP and TPR 0 during boot so it gets all the interrupts,
         * set APs at TPR 0xF0 at boot so they get no ints.
         */
+#if 0
        if (mycpu->gd_cpuid != 0)
                temp |= TPR_IPI_ONLY;   /* disable INTs on this cpu */
+#endif
        lapic.tpr = temp;
 
        /* enable the local APIC */
@@ -484,63 +487,33 @@ imen_dump(void)
  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
  *  vector is any valid SYSTEM INT vector
  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ *
+ * A backlog of requests can create a deadlock between cpus.  To avoid this
+ * we have to be able to accept IPIs at the same time we are trying to send
+ * them.  The critical section prevents us from attempting to send additional
+ * IPIs reentrantly, but also prevents IPIQ processing so we have to call
+ * lwkt_process_ipiq() manually.  It's rather messy and expensive for this
+ * to occur but fortunately it does not happen too often.
  */
-#define DETECT_DEADLOCK
 int
 apic_ipi(int dest_type, int vector, int delivery_mode)
 {
        u_long  icr_lo;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       crit_enter();
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       /* build IRC_LOW */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
-           | dest_type | delivery_mode | vector;
 
-       /* write APIC ICR */
+       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) | dest_type | 
+               delivery_mode | vector;
        lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
+       crit_exit();
        return 0;
 }
 
@@ -549,24 +522,15 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 {
        u_long  icr_lo;
        u_long  icr_hi;
-       u_long  eflags;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       eflags = read_eflags();
-       __asm __volatile("cli" : : : "memory");
        icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
        icr_hi |= (CPU_TO_ID(cpu) << 24);
        lapic.icr_hi = icr_hi;
@@ -577,101 +541,34 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 
        /* write APIC ICR */
        lapic.icr_lo = icr_lo;
-       write_eflags(eflags);
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
        return 0;
 }
 
-
 /*
  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
  *
- *  target contains a bitfield with a bit set for selected APICs.
- *  vector is any valid SYSTEM INT vector
- *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ * target is a bitmask of destination cpus.  Vector is any
+ * valid system INT vector.  Delivery mode may be either
+ * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
  */
 int
 selected_apic_ipi(u_int target, int vector, int delivery_mode)
 {
-       int     x;
-       int     status;
-
-       if (target & ~0x7fff)
-               return -1;      /* only 15 targets allowed */
-
-       for (status = 0, x = 0; x <= 14; ++x)
-               if (target & (1 << x)) {
-
-                       /* send the IPI */
-                       if (apic_ipi_singledest(x, vector, 
-                                               delivery_mode) == -1)
-                               status |= (1 << x);
-               }
-       return status;
-}
-
-
-#if defined(READY)
-/*
- * Send an IPI INTerrupt containing 'vector' to CPU 'target'
- *   NOTE: target is a LOGICAL APIC ID
- */
-int
-selected_proc_ipi(int target, int vector)
-{
-       u_long  icr_lo;
-       u_long  icr_hi;
-
-       /* write the destination field for the target AP */
-       icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) |
-           (cpu_num_to_apic_id[target] << 24);
-       lapic.icr_hi = icr_hi;
-
-       /* write command */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) |
-           APIC_DEST_DESTFLD | APIC_DELMODE_FIXED | vector;
-       lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-               /* spin */ ;
-
-       return 0;       /** XXX FIXME: return result */
+       int status = 0;
+
+       crit_enter();
+       while (target) {
+               int n = bsfl(target);
+               target &= ~(1 << n);
+               if (apic_ipi_singledest(n, vector, delivery_mode) < 0)
+                       status |= 1 << n;
+       }
+       crit_exit();
+       return(status);
 }
-#endif /* READY */
 
 #endif /* APIC_IO */
 
-
 /*
  * Timer code, in development...
  *  - suggested by rgrimes@gndrsh.aac.dev.com
index 233c755..1e43088 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/exception.s,v 1.65.2.3 2001/08/15 01:23:49 peter Exp $
- * $DragonFly: src/sys/platform/pc32/i386/exception.s,v 1.11 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/exception.s,v 1.12 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "npx.h"
@@ -175,7 +175,7 @@ IDTVEC(fpu)
        call    npx_intr                /* note: call might mess w/ argument */
 
        movl    %ebx, (%esp)            /* save cpl for doreti */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        MEXITCOUNT
        jmp     doreti
 #else  /* NNPX > 0 */
@@ -214,7 +214,7 @@ alltraps_with_regs_pushed:
        FAKE_MCOUNT(13*4(%esp))
 calltrap:
        FAKE_MCOUNT(btrap)              /* init "from" _btrap -> calltrap */
-       incl PCPU(cnt)+V_TRAP           /* YYY per-cpu */
+       incl    PCPU(cnt)+V_TRAP
        movl    PCPU(curthread),%eax    /* keep orig cpl here during call */
        movl    TD_CPL(%eax),%ebx
        call    trap
@@ -224,7 +224,7 @@ calltrap:
         * to interrupt frame.
         */
        pushl   %ebx                    /* cpl to restore */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        MEXITCOUNT
        jmp     doreti
 
@@ -308,33 +308,51 @@ IDTVEC(int0x80_syscall)
  * This function is what cpu_heavy_restore jumps to after a new process
  * is created.  We are in a critical section in order to prevent
  * cpu_heavy_restore from being interrupted (especially since it stores
- * its context in a static place!), so the first thing we do is release
- * the critical section.
+ * its context in a static place!).
  *
  * The MP lock is held on entry, but for processes fork_return (esi)
  * releases it.  'doreti' always runs without the MP lock.
+ *
+ * We need to be careful to hold interrupts disabled through until
+ * doreti iret's YYY this is due to the PCB_ storage in the heavy switcher,
+ * fixme!
  */
 ENTRY(fork_trampoline)
+       cli
        movl    PCPU(curthread),%eax
        subl    $TDPRI_CRIT,TD_PRI(%eax)
-       call    spl0
-       call    splz
 
        /*
         * cpu_set_fork_handler intercepts this function call to
         * have this call a non-return function to stay in kernel mode.
-        * initproc has its own fork handler, but it does return.
+        *
+        * initproc has its own fork handler, start_init(), which DOES
+        * return.
         */
        pushl   %ebx                    /* arg1 */
        call    *%esi                   /* function */
        addl    $4,%esp
        /* cut from syscall */
 
+       call    spl0
+       call    splz
+
+#if defined(INVARIANTS) && defined(SMP)
+       movl    PCPU(curthread),%eax
+       cmpl    $0,TD_MPCOUNT(%eax)
+       je      1f
+       pushl   %esi
+       pushl   TD_MPCOUNT(%eax)
+       pushl   $pmsg4
+       call    panic
+pmsg4:  .asciz "fork_trampoline mpcount %d after calling %p"
+1:
+#endif
        /*
         * Return via doreti to handle ASTs.
         */
        pushl   $0                      /* cpl to restore */
-       movb    $1,PCPU(intr_nesting_level)
+       movl    $1,PCPU(intr_nesting_level)
        MEXITCOUNT
        jmp     doreti
 
index c0f416c..93195f6 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)genassym.c    5.11 (Berkeley) 5/10/91
  * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $
- * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.21 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.22 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "opt_user_ldt.h"
@@ -102,6 +102,7 @@ ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner));
 ASSYM(TD_CPL, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_cpl));
 
 ASSYM(TDPRI_CRIT, TDPRI_CRIT);
+ASSYM(TDPRI_INT_SUPPORT, TDPRI_INT_SUPPORT);
 
 ASSYM(SSLEEP, SSLEEP);
 ASSYM(SRUN, SRUN);
@@ -197,7 +198,6 @@ ASSYM(GD_CURRENTLDT, offsetof(struct mdglobaldata, gd_currentldt));
 
 ASSYM(GD_FPENDING, offsetof(struct mdglobaldata, gd_fpending));
 ASSYM(GD_IPENDING, offsetof(struct mdglobaldata, gd_ipending));
-ASSYM(GD_IRUNNING, offsetof(struct mdglobaldata, gd_irunning));
 ASSYM(GD_COMMON_TSS, offsetof(struct mdglobaldata, gd_common_tss));
 ASSYM(GD_COMMON_TSSD, offsetof(struct mdglobaldata, gd_common_tssd));
 ASSYM(GD_TSS_GDT, offsetof(struct mdglobaldata, gd_tss_gdt));
index a584218..d341220 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/globals.s,v 1.13.2.1 2000/05/16 06:58:06 dillon Exp $
- * $DragonFly: src/sys/platform/pc32/i386/globals.s,v 1.14 2003/07/03 17:24:01 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/globals.s,v 1.15 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "opt_user_ldt.h"
@@ -84,7 +84,7 @@
        .globl  gd_ss_eflags, gd_intr_nesting_level
        .globl  gd_CMAP1, gd_CMAP2, gd_CMAP3, gd_PMAP1
        .globl  gd_CADDR1, gd_CADDR2, gd_CADDR3, gd_PADDR1
-       .globl  gd_irunning, gd_ipending, gd_fpending, gd_cnt
+       .globl  gd_ipending, gd_fpending, gd_cnt
 
        .set    gd_cpuid,globaldata + GD_CPUID
        .set    gd_cpu_lockid,globaldata + GD_CPU_LOCKID
        .set    gd_PADDR1,globaldata + GD_PRV_PADDR1
        .set    gd_fpending,globaldata + GD_FPENDING
        .set    gd_ipending,globaldata + GD_IPENDING
-       .set    gd_irunning,globaldata + GD_IRUNNING
        .set    gd_cnt,globaldata + GD_CNT
 
 #if defined(APIC_IO)
index 69c8c56..5080da8 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)locore.s      7.3 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/locore.s,v 1.132.2.10 2003/02/03 20:54:49 jhb Exp $
- * $DragonFly: src/sys/platform/pc32/i386/locore.s,v 1.5 2003/07/01 20:30:40 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/locore.s,v 1.6 2003/07/08 06:27:26 dillon Exp $
  *
  *             originally from: locore.s, by William F. Jolitz
  *
@@ -886,7 +886,7 @@ map_read_write:
 
 #ifdef SMP
 /* Initialize mp lock to allow early traps */
-       movl    $1, R(mp_lock)
+       movl    $0, R(mp_lock)
 #endif /* SMP */
 
 /* install a pde for temporary double map of bottom of VA */
index 57a51ef..9894f72 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)machdep.c     7.4 (Berkeley) 6/3/91
  * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $
- * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.22 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.23 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "apm.h"
@@ -951,7 +951,7 @@ cpu_halt(void)
  * Note on cpu_idle_hlt:  On an SMP system this may cause the system to 
  * halt until the next clock tick, even if a thread is ready YYY
  */
-static int     cpu_idle_hlt = 0;
+static int     cpu_idle_hlt = 1;
 SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW,
     &cpu_idle_hlt, 0, "Idle loop HLT enable");
 
index 07b3ae1..3bdebfd 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.115.2.15 2003/03/14 21:22:35 jhb Exp $
- * $DragonFly: src/sys/platform/pc32/i386/mp_machdep.c,v 1.9 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/mp_machdep.c,v 1.10 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "opt_cpu.h"
@@ -588,6 +588,10 @@ mp_enable(u_int boot_addr)
               SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
 #endif
 #endif
+
+       /* install an inter-CPU IPI for IPIQ messaging */
+       setidt(XIPIQ_OFFSET, Xipiq,
+              SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
        
        /* install an inter-CPU IPI for all-CPU rendezvous */
        setidt(XRENDEZVOUS_OFFSET, Xrendezvous,
@@ -2060,6 +2064,8 @@ start_all_aps(u_int boot_addr)
                gd->gd_CADDR2 = CPU_prvspace[x].CPAGE2;
                gd->gd_CADDR3 = CPU_prvspace[x].CPAGE3;
                gd->gd_PADDR1 = (unsigned *)CPU_prvspace[x].PPAGE1;
+               gd->mi.gd_ipiq = (void *)kmem_alloc(kernel_map, sizeof(lwkt_ipiq) * (mp_naps + 1));
+               bzero(gd->mi.gd_ipiq, sizeof(lwkt_ipiq) * (mp_naps + 1));
 
                /* setup a vector to our boot code */
                *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET;
@@ -2095,6 +2101,8 @@ start_all_aps(u_int boot_addr)
 
        /* build our map of 'other' CPUs */
        mycpu->gd_other_cpus = all_cpus & ~(1 << mycpu->gd_cpuid);
+       mycpu->gd_ipiq = (void *)kmem_alloc(kernel_map, sizeof(lwkt_ipiq) * ncpus);
+       bzero(mycpu->gd_ipiq, sizeof(lwkt_ipiq) * ncpus);
 
        /* fill in our (BSP) APIC version */
        cpu_apic_versions[0] = lapic.version;
@@ -2398,10 +2406,12 @@ ap_init(void)
        ++ncpus;
 
        /*
-        * Get the MP lock so we can finish initializing.
+        * Get the MP lock so we can finish initializing.  Note: we are
+        * in a critical section.
         */
        while (cpu_try_mplock() == 0)
            ;
+       ++curthread->td_mpcount;
 
        /* BSP may have changed PTD while we're waiting for the lock */
        cpu_invltlb();
@@ -2456,7 +2466,8 @@ ap_init(void)
         * lwkt_switch() normally cleans things up this is a special case
         * because we returning almost directly into the idle loop.
         */
-       cpu_rel_mplock();
+       KKASSERT(curthread->td_mpcount == 1);
+       rel_mplock();
 }
 
 #ifdef BETTER_CLOCK
@@ -2927,3 +2938,9 @@ smp_rendezvous(void (* setup_func)(void *),
        /* release lock */
        spin_unlock(&smp_rv_spinlock);
 }
+
+void
+cpu_send_ipiq(int dcpu)
+{
+       selected_apic_ipi(1 << dcpu, XIPIQ_OFFSET, APIC_DELMODE_FIXED);
+}
index d390cff..507f386 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/mpapic.c,v 1.37.2.7 2003/01/25 02:31:47 peter Exp $
- * $DragonFly: src/sys/platform/pc32/i386/Attic/mpapic.c,v 1.4 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/Attic/mpapic.c,v 1.5 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -33,6 +33,7 @@
 #include <machine/smp.h>
 #include <machine/mpapic.h>
 #include <machine/segments.h>
+#include <sys/thread2.h>
 
 #include <i386/isa/intr_machdep.h>     /* Xspuriousint() */
 
@@ -79,8 +80,10 @@ apic_initialize(void)
         * Leave the BSP and TPR 0 during boot so it gets all the interrupts,
         * set APs at TPR 0xF0 at boot so they get no ints.
         */
+#if 0
        if (mycpu->gd_cpuid != 0)
                temp |= TPR_IPI_ONLY;   /* disable INTs on this cpu */
+#endif
        lapic.tpr = temp;
 
        /* enable the local APIC */
@@ -484,63 +487,33 @@ imen_dump(void)
  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
  *  vector is any valid SYSTEM INT vector
  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ *
+ * A backlog of requests can create a deadlock between cpus.  To avoid this
+ * we have to be able to accept IPIs at the same time we are trying to send
+ * them.  The critical section prevents us from attempting to send additional
+ * IPIs reentrantly, but also prevents IPIQ processing so we have to call
+ * lwkt_process_ipiq() manually.  It's rather messy and expensive for this
+ * to occur but fortunately it does not happen too often.
  */
-#define DETECT_DEADLOCK
 int
 apic_ipi(int dest_type, int vector, int delivery_mode)
 {
        u_long  icr_lo;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       crit_enter();
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       /* build IRC_LOW */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
-           | dest_type | delivery_mode | vector;
 
-       /* write APIC ICR */
+       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) | dest_type | 
+               delivery_mode | vector;
        lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
+       crit_exit();
        return 0;
 }
 
@@ -549,24 +522,15 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 {
        u_long  icr_lo;
        u_long  icr_hi;
-       u_long  eflags;
 
-#if defined(DETECT_DEADLOCK)
-#define MAX_SPIN1      10000000
-#define MAX_SPIN2      1000
-       int     x;
-
-       /* "lazy delivery", ie we only barf if they stack up on us... */
-       for (x = MAX_SPIN1; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
+       if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+           unsigned int eflags = read_eflags();
+           cpu_enable_intr();
+           while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
+               lwkt_process_ipiq();
+           }
+           write_eflags(eflags);
        }
-       if (x == 0)
-               panic("apic_ipi was stuck");
-#endif  /* DETECT_DEADLOCK */
-
-       eflags = read_eflags();
-       __asm __volatile("cli" : : : "memory");
        icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
        icr_hi |= (CPU_TO_ID(cpu) << 24);
        lapic.icr_hi = icr_hi;
@@ -577,101 +541,34 @@ apic_ipi_singledest(int cpu, int vector, int delivery_mode)
 
        /* write APIC ICR */
        lapic.icr_lo = icr_lo;
-       write_eflags(eflags);
-
-       /* wait for pending status end */
-#if defined(DETECT_DEADLOCK)
-       for (x = MAX_SPIN2; x; --x) {
-               if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
-                       break;
-       }
-#ifdef needsattention
-/*
- * XXX FIXME:
- *      The above loop waits for the message to actually be delivered.
- *      It breaks out after an arbitrary timout on the theory that it eventually
- *      will be delivered and we will catch a real failure on the next entry to
- *      this function, which would panic().
- *      We could skip this wait entirely, EXCEPT it probably protects us from
- *      other "less robust" routines that assume the message was delivered and
- *      acted upon when this function returns.  TLB shootdowns are one such
- *      "less robust" function.
- */
-       if (x == 0)
-               printf("apic_ipi might be stuck\n");
-#endif
-#undef MAX_SPIN2
-#undef MAX_SPIN1
-#else
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-                /* spin */ ;
-#endif  /* DETECT_DEADLOCK */
-
-       /** XXX FIXME: return result */
        return 0;
 }
 
-
 /*
  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
  *
- *  target contains a bitfield with a bit set for selected APICs.
- *  vector is any valid SYSTEM INT vector
- *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
+ * target is a bitmask of destination cpus.  Vector is any
+ * valid system INT vector.  Delivery mode may be either
+ * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
  */
 int
 selected_apic_ipi(u_int target, int vector, int delivery_mode)
 {
-       int     x;
-       int     status;
-
-       if (target & ~0x7fff)
-               return -1;      /* only 15 targets allowed */
-
-       for (status = 0, x = 0; x <= 14; ++x)
-               if (target & (1 << x)) {
-
-                       /* send the IPI */
-                       if (apic_ipi_singledest(x, vector, 
-                                               delivery_mode) == -1)
-                               status |= (1 << x);
-               }
-       return status;
-}
-
-
-#if defined(READY)
-/*
- * Send an IPI INTerrupt containing 'vector' to CPU 'target'
- *   NOTE: target is a LOGICAL APIC ID
- */
-int
-selected_proc_ipi(int target, int vector)
-{
-       u_long  icr_lo;
-       u_long  icr_hi;
-
-       /* write the destination field for the target AP */
-       icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) |
-           (cpu_num_to_apic_id[target] << 24);
-       lapic.icr_hi = icr_hi;
-
-       /* write command */
-       icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) |
-           APIC_DEST_DESTFLD | APIC_DELMODE_FIXED | vector;
-       lapic.icr_lo = icr_lo;
-
-       /* wait for pending status end */
-       while (lapic.icr_lo & APIC_DELSTAT_MASK)
-               /* spin */ ;
-
-       return 0;       /** XXX FIXME: return result */
+       int status = 0;
+
+       crit_enter();
+       while (target) {
+               int n = bsfl(target);
+               target &= ~(1 << n);
+               if (apic_ipi_singledest(n, vector, delivery_mode) < 0)
+                       status |= 1 << n;
+       }
+       crit_exit();
+       return(status);
 }
-#endif /* READY */
 
 #endif /* APIC_IO */
 
-
 /*
  * Timer code, in development...
  *  - suggested by rgrimes@gndrsh.aac.dev.com
index aa0dbea..2032f3c 100644 (file)
@@ -7,7 +7,7 @@
  * ----------------------------------------------------------------------------
  *
  * $FreeBSD: src/sys/i386/i386/mplock.s,v 1.29.2.2 2000/05/16 06:58:06 dillon Exp $
- * $DragonFly: src/sys/platform/pc32/i386/mplock.s,v 1.4 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/mplock.s,v 1.5 2003/07/08 06:27:26 dillon Exp $
  *
  * Functions for locking between CPUs in a SMP system.
  *
@@ -40,7 +40,7 @@ mp_lock:
 
        /*
         * Note on cmpxchgl... exchanges ecx with mem if mem matches eax.
-        * Z=1 (jz) on success. 
+        * Z=1 (jz) on success.   A lock prefix is required for MP.
         */
 NON_GPROF_ENTRY(cpu_get_initial_mplock)
        movl    PCPU(curthread),%ecx
@@ -56,7 +56,7 @@ NON_GPROF_ENTRY(cpu_get_initial_mplock)
 NON_GPROF_ENTRY(cpu_try_mplock)
        movl    PCPU(cpuid),%ecx
        movl    $-1,%eax
-       cmpxchgl %ecx,mp_lock           /* ecx<->mem if eax matches */
+       lock cmpxchgl %ecx,mp_lock      /* ecx<->mem if eax matches */
        jnz     1f
        movl    $1,%eax
        NON_GPROF_RET
@@ -76,16 +76,27 @@ NON_GPROF_ENTRY(get_mplock)
        movl    $1,TD_MPCOUNT(%edx)
        movl    PCPU(cpuid),%ecx
        movl    $-1,%eax
-       cmpxchgl %ecx,mp_lock           /* ecx<->mem & JZ if eax matches */
+       lock cmpxchgl %ecx,mp_lock      /* ecx<->mem & JZ if eax matches */
        jnz     2f
        popfl                           /* success */
        NON_GPROF_RET
 2:
+#ifdef INVARIANTS
        movl    PCPU(cpuid),%eax        /* failure */
        cmpl    %eax,mp_lock
+       je      3f
+#endif
+       addl    $TDPRI_CRIT,TD_PRI(%edx)
+       popfl
+       call    lwkt_switch             /* will be correct on return */
+       movl    PCPU(curthread),%edx
+       subl    $TDPRI_CRIT,TD_PRI(%edx)
+       NON_GPROF_RET
+3:
+       cmpl    $0,panicstr             /* don't double panic */
        je      badmp_get
        popfl
-       jmp     lwkt_switch             /* will be correct on return */
+       NON_GPROF_RET
 
 NON_GPROF_ENTRY(try_mplock)
        movl    PCPU(curthread),%edx
@@ -99,48 +110,74 @@ NON_GPROF_ENTRY(try_mplock)
        cli
        movl    PCPU(cpuid),%ecx
        movl    $-1,%eax
-       cmpxchgl %ecx,mp_lock           /* ecx<->mem & JZ if eax matches */
+       lock cmpxchgl %ecx,mp_lock      /* ecx<->mem & JZ if eax matches */
        jnz     2f
        movl    $1,TD_MPCOUNT(%edx)
        popfl                           /* success */
        movl    $1,%eax
        NON_GPROF_RET
 2:
+#ifdef INVARIANTS
+       cmpl    $0,panicstr
+       jnz     3f
        movl    PCPU(cpuid),%eax        /* failure */
        cmpl    %eax,mp_lock
        je      badmp_get
+3:
+#endif
        popfl
        movl    $0,%eax
        NON_GPROF_RET
 
 NON_GPROF_ENTRY(rel_mplock)
        movl    PCPU(curthread),%edx
-       cmpl    $1,TD_MPCOUNT(%edx)
+       movl    TD_MPCOUNT(%edx),%eax
+       cmpl    $1,%eax
        je      1f
-       subl    $1,TD_MPCOUNT(%edx)
+#ifdef INVARIANTS
+       testl   %eax,%eax
+       jz      badmp_rel
+#endif
+       subl    $1,%eax
+       movl    %eax,TD_MPCOUNT(%edx)
        NON_GPROF_RET
 1:
        pushfl
        cli
+#ifdef INVARIANTS
+       movl    PCPU(cpuid),%ecx
+       cmpl    %ecx,mp_lock
+       jne     badmp_rel2
+#endif
        movl    $0,TD_MPCOUNT(%edx)
        movl    $MP_FREE_LOCK,mp_lock
        popfl
        NON_GPROF_RET
 
+#ifdef INVARIANTS
+
 badmp_get:
        pushl   $bmpsw1
        call    panic
 badmp_rel:
        pushl   $bmpsw2
        call    panic
+badmp_rel2:
+       pushl   $bmpsw2a
+       call    panic
 
        .data
 
 bmpsw1:
-       .asciz  "try/get_mplock(): already have lock!"
+       .asciz  "try/get_mplock(): already have lock! %d %p"
 
 bmpsw2:
-       .asciz  "rel_mplock(): not holding lock!"
+       .asciz  "rel_mplock(): mpcount already 0 @ %p %p %p %p %p %p %p %p!"
+
+bmpsw2a:
+       .asciz  "rel_mplock(): Releasing another cpu's MP lock! %p %p"
+
+#endif
 
 #if 0
 /* after 1st acquire of lock we grab all hardware INTs */
index d7fd6be..132a0fd 100644 (file)
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $
- * $DragonFly: src/sys/platform/pc32/i386/swtch.s,v 1.21 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/swtch.s,v 1.22 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "npx.h"
@@ -143,7 +143,7 @@ ENTRY(cpu_heavy_switch)
        addl    $PCB_SAVEFPU,%edx               /* h/w bugs make saving complicated */
        pushl   %edx
        call    npxsave                 /* do it in a big C function */
-       popl    %eax
+       addl    $4,%esp
 1:
        /* %ecx,%edx trashed */
 #endif /* NNPX > 0 */
@@ -224,6 +224,8 @@ ENTRY(cpu_exit_switch)
  *     we restore everything.
  *
  *     YYY STI/CLI sequencing.
+ *     YYY the PCB crap is really crap, it makes startup a bitch because
+ *     we can't switch away.
  *
  *     YYY note: spl check is done in mi_switch when it splx()'s.
  */
index cb0b408..b876b91 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)trap.c        7.4 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $
- * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.18 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.19 2003/07/08 06:27:26 dillon Exp $
  */
 
 /*
@@ -164,7 +164,7 @@ SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW,
  *
  * usertdsw is called from within a critical section, but the BGL will
  * have already been released by lwkt_switch() so only call MP safe functions
- * that don't block!
+ * that don't block and don't require the BGL!
  */
 static void
 usertdsw(struct thread *ntd)
@@ -302,7 +302,15 @@ trap(frame)
        int i = 0, ucode = 0, type, code;
        vm_offset_t eva;
 
+#ifdef SMP
+       if (panicstr == NULL)
+           KASSERT(curthread->td_mpcount >= 0, ("BADX1 AT %08x %08x", frame.tf_eip, frame.tf_esp));
+#endif
        get_mplock();
+#ifdef SMP
+       if (panicstr == NULL)
+           KKASSERT(curthread->td_mpcount > 0);
+#endif
 
 #ifdef DDB
        if (db_active) {
@@ -365,12 +373,19 @@ restart:
        if (in_vm86call) {
                if (frame.tf_eflags & PSL_VM &&
                    (type == T_PROTFLT || type == T_STKFLT)) {
+#ifdef SMP
+                       KKASSERT(curthread->td_mpcount > 0);
+#endif
                        i = vm86_emulate((struct vm86frame *)&frame);
+#ifdef SMP
+                       KKASSERT(curthread->td_mpcount > 0);
+#endif
                        if (i != 0) {
                                /*
                                 * returns to original process
                                 */
                                vm86_trap((struct vm86frame *)&frame);
+                               KKASSERT(0);
                        }
                        goto out2;
                }
@@ -736,6 +751,9 @@ out:
 #endif
        userret(p, &frame, sticks);
 out2:
+#ifdef SMP
+       KKASSERT(curthread->td_mpcount > 0);
+#endif
        rel_mplock();
 }
 
index 0958bfe..a691831 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/vm86.c,v 1.31.2.2 2001/10/05 06:18:55 peter Exp $
- * $DragonFly: src/sys/platform/pc32/i386/vm86.c,v 1.6 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/vm86.c,v 1.7 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -39,6 +39,7 @@
 #include <vm/vm_page.h>
 
 #include <sys/user.h>
+#include <sys/thread2.h>
 
 #include <machine/md_var.h>
 #include <machine/pcb_ext.h>   /* pcb.h included via sys/user.h */
@@ -570,13 +571,18 @@ vm86_trap(struct vm86frame *vmf)
 int
 vm86_intcall(int intnum, struct vm86frame *vmf)
 {
+       int error;
+
        if (intnum < 0 || intnum > 0xff)
                return (EINVAL);
 
+       crit_enter();
        ASSERT_MP_LOCK_HELD();
 
        vmf->vmf_trapno = intnum;
-       return (vm86_bioscall(vmf));
+       error = vm86_bioscall(vmf);
+       crit_exit();
+       return(error);
 }
 
 /*
@@ -595,6 +601,7 @@ vm86_datacall(intnum, vmf, vmc)
        u_int page;
        int i, entry, retval;
 
+       crit_enter();
        ASSERT_MP_LOCK_HELD();
 
        for (i = 0; i < vmc->npages; i++) {
@@ -611,7 +618,7 @@ vm86_datacall(intnum, vmf, vmc)
                entry = vmc->pmap[i].pte_num;
                pte[entry] = vmc->pmap[i].old_pte;
        }
-
+       crit_exit();
        return (retval);
 }
 
index ee87325..645a7c1 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/vm86bios.s,v 1.15.2.1 2000/05/16 06:58:07 dillon Exp $
- * $DragonFly: src/sys/platform/pc32/i386/vm86bios.s,v 1.9 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/vm86bios.s,v 1.10 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include <machine/asmacros.h>          /* miscellaneous asm macros */
@@ -138,7 +138,7 @@ ENTRY(vm86_bioscall)
         */
        movl    PCPU(curthread),%eax
        pushl   TD_CPL(%eax)
-       incb    PCPU(intr_nesting_level)/* dummy to match doreti */
+       incl    PCPU(intr_nesting_level)/* dummy to match doreti */
        MEXITCOUNT
        jmp     doreti
 
index 3da4f3a..be9bf6e 100644 (file)
@@ -39,7 +39,7 @@
  *     from: @(#)vm_machdep.c  7.3 (Berkeley) 5/13/91
  *     Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
  * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $
- * $DragonFly: src/sys/platform/pc32/i386/vm_machdep.c,v 1.17 2003/07/04 00:32:24 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/vm_machdep.c,v 1.18 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "npx.h"
@@ -405,7 +405,7 @@ cpu_reset_proxy()
        while (cpu_reset_proxy_active == 1)
                ;        /* Wait for other cpu to disable interupts */
        saved_mp_lock = mp_lock;
-       mp_lock = 1;
+       mp_lock = 0;    /* BSP */
        printf("cpu_reset_proxy: Grabbed mp lock for BSP\n");
        cpu_reset_proxy_active = 3;
        while (cpu_reset_proxy_active == 3)
index 1ae6212..88cc251 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/icu_vector.s,v 1.14.2.2 2000/07/18 21:12:42 dfr Exp $
- * $DragonFly: src/sys/platform/pc32/icu/icu_vector.s,v 1.11 2003/07/03 17:24:02 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/icu/icu_vector.s,v 1.12 2003/07/08 06:27:27 dillon Exp $
  */
 
 /*
@@ -68,7 +68,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -83,7 +83,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define MASK_IRQ(icu, irq_num)                                         \
        movb    imen + IRQ_BYTE(irq_num),%al ;                          \
@@ -188,16 +188,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule its thread.  Leave
- *       interrupts masked and doreti.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule its thread.  Leave interrupts masked and doreti.
  *
- *     The interrupt thread will run its handlers and loop if 
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     sched_ithd() is called with interrupts enabled and outside of a
+ *     critical section (so it can preempt us).
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
  *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
@@ -219,8 +215,6 @@ IDTVEC(vec_name) ;                                                  \
        pushl   %eax ;          /* push CPL for doreti */               \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num), %eax ;                              \
        jz      2f ;                                                    \
 1: ;                                                                   \
@@ -229,15 +223,12 @@ IDTVEC(vec_name) ;                                                        \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -248,8 +239,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -258,7 +248,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(icu, irq_num) ;                                      \
        popl %ebp ;                                                     \
        ret ;                                                           \
index 9f6e032..9aba13a 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/apic.h,v 1.14.2.2 2003/03/21 21:46:15 jhb Exp $
- * $DragonFly: src/sys/platform/pc32/include/Attic/apic.h,v 1.3 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/Attic/apic.h,v 1.4 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_APIC_H_
  * 0310        ICR_HI  | DEST FIELD|           |           |           |
  *             +-----------+-----------+-----------+-----------+
  *
- *                 The interrupt command register 
+ *                 The interrupt command register.  Generally speaking
+ *                 writing to ICR_LO initiates a command.  All fields
+ *                 are R/W except the 'S' (delivery status) field, which
+ *                 is read-only.  When
+ *     
  *
  *                     XX:     Destination Shorthand field:
  *
  *                                     destination field of 0x0F)
  *
  *                     T:      1 = Level 0 = Edge Trigger modde, used for
- *                             the INIT level de-assert delivery mode only.
- *                             Not sure.
+ *                             the INIT level de-assert delivery mode only
+ *                             to de-assert a request.
  *
- *                     L:      0 = De-Assert, 1 = Assert.  Not sure what this
- *                             is.  For INIT mode use 0, for all other modes
- *                             use 1.
+ *                     L:      0 = De-Assert, 1 = Assert.  Always write as
+ *                             1 when initiating a new command.  Can only
+ *                             write as 0 for INIT mode de-assertion of
+ *                             command.
  *
  *                     S:      1 = Send Pending.  Interrupt has been injected
  *                             but APIC has not yet accepted it.
  *                                             Always level.
  *
  *             +-----------+-----------+-----------+-----------+
- * 0380        ICR     |           |           |           |           |
- * 0390        CCR     |           |           |           |           |
+ * 0380        TMR_ICR |           |           |           |           |
+ * 0390        TMR_CCR |           |           |           |           |
  * 03A0                |           |           |           |           |
  * 03B0                |           |           |           |           |
  * 03C0                |           |           |           |           |
  * 03D0                |           |           |           |           |
- * 03E0 DCR    |           |           |           |           |
+ * 03E0 TMR_DCR        |           |           |           |           |
  *             +-----------+-----------+-----------+-----------+
  *
+ *                 Timer control and access registers.
+ *
  *
  *     NOTE ON EOI: Upon receiving an EOI the APIC clears the highest priority
  *     interrupt in the ISR and selects the next highest priority interrupt
  *     triggered the APIC will send an EOI to all I/O APICs.  For the moment
  *     you can write garbage to the EOI register but for future compatibility
  *     0 should be written.
- *
  */
 
 #ifndef LOCORE
index bc15f04..b55a4b0 100644 (file)
@@ -28,7 +28,7 @@
  *     should not include this file.
  *
  * $FreeBSD: src/sys/i386/include/globaldata.h,v 1.11.2.1 2000/05/16 06:58:10 dillon Exp $
- * $DragonFly: src/sys/platform/pc32/include/globaldata.h,v 1.15 2003/07/04 00:25:48 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/globaldata.h,v 1.16 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_GLOBALDATA_H_
 
 /*
  * Note on interrupt control.  Pending interrupts not yet dispatched are
- * marked in gd_fpending or gd_ipending.  Once dispatched an interrupt
- * is marked in irunning and the fpending bit is cleared.  For edge triggered
- * interrupts interrupts may be enabled again at this point and if they
- * occur before the interrupt service routine is complete the ipending bit
- * will be set again and cause the interrupt service to loop.  The current
- * thread's cpl is stored in the thread structure.
+ * marked in gd_fpending or gd_ipending.  Once dispatched the interrupt's
+ * pending bit is cleared and the interrupt is masked.  Upon completion
+ * the interrupt is unmasked.
+ *
+ * For edge triggered interrupts interrupts may be enabled again at this
+ * point and if they occur before the interrupt service routine is complete
+ * the service routine will loop.
+ *
+ * The current thread's cpl is stored in the thread structure.
  */
 struct mdglobaldata {
        struct globaldata mi;
@@ -65,7 +68,6 @@ struct mdglobaldata {
        struct i386tss  gd_common_tss;
        int             gd_fpending;    /* fast interrupt pending */
        int             gd_ipending;    /* normal interrupt pending */
-       int             gd_irunning;    /* normal interrupt in progress */
        int             gd_currentldt;  /* USER_LDT */
        u_int           gd_cpu_lockid;
        u_int           gd_other_cpus;
index d256b22..53cd23c 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/ipl.h,v 1.17.2.3 2002/12/17 18:04:02 sam Exp $
- * $DragonFly: src/sys/platform/pc32/include/ipl.h,v 1.3 2003/06/22 08:54:20 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/ipl.h,v 1.4 2003/07/08 06:27:26 dillon Exp $
  */
 
 #ifndef _MACHINE_IPL_H_
@@ -97,6 +97,7 @@
  */
 #define        AST_PENDING     0x00000001
 #define        AST_RESCHED     0x00000002
+#define        AST_IPIQ        0x00000004
 
 #ifndef        LOCORE
 
index 67ea825..c0db670 100644 (file)
@@ -22,7 +22,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/lock.h,v 1.11.2.2 2000/09/30 02:49:34 ps Exp $
- * $DragonFly: src/sys/platform/pc32/include/lock.h,v 1.3 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/lock.h,v 1.4 2003/07/08 06:27:27 dillon Exp $
  */
 
 #ifndef _MACHINE_LOCK_H_
        orl     $PSL_C,%ecx ;   /* make sure non-zero */        \
 7: ;                                                           \
        movl    $0,%eax ;       /* expected contents of lock */ \
-       cmpxchgl %ecx,mem ;     /* Z=1 (jz) on success */       \
-       jz      8f ;                                            \
-       jmp     7b ;                                            \
-8: ;                                                           \
+       lock cmpxchgl %ecx,mem ; /* Z=1 (jz) on success */      \
+       jnz     7b ;                                            \
 
 #define SPIN_LOCK_PUSH_REGS                                    \
        subl    $8,%esp ;                                       \
index bad7f94..f21735b 100644 (file)
@@ -7,7 +7,7 @@
  * ----------------------------------------------------------------------------
  *
  * $FreeBSD: src/sys/i386/include/smp.h,v 1.50.2.5 2001/02/13 22:32:45 tegge Exp $
- * $DragonFly: src/sys/platform/pc32/include/smp.h,v 1.3 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/smp.h,v 1.4 2003/07/08 06:27:27 dillon Exp $
  *
  */
 
@@ -150,6 +150,7 @@ void        set_io_apic_mask24      __P((int, u_int32_t));
 void   set_apic_timer          __P((int));
 int    read_apic_timer         __P((void));
 void   u_sleep                 __P((int));
+void   cpu_send_ipiq           __P((int));
 
 /* global data in init_smp.c */
 extern int                     invltlb_ok;
index bb240b8..869bd10 100644 (file)
@@ -24,7 +24,7 @@
  *
  *     Machine independant code should not directly include this file.
  *
- * $DragonFly: src/sys/platform/pc32/include/thread.h,v 1.3 2003/06/28 04:16:03 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/thread.h,v 1.4 2003/07/08 06:27:27 dillon Exp $
  */
 
 #ifndef        _MACHINE_THREAD_H_
@@ -42,8 +42,6 @@ struct md_thread {
 
 #define td_cpl td_mach.mtd_cpl
 
-struct globaldata;
-
 /*
  * mycpu() retrieves the base of the current cpu's globaldata structure.
  * Note that it is *NOT* volatile, meaning that the value may be cached by
@@ -56,6 +54,8 @@ struct globaldata;
  * block.
  */
 
+struct globaldata;
+
 extern int __mycpu__dummy;
 
 static __inline
index 2c7e7f7..f966475 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/apic_vector.s,v 1.47.2.5 2001/09/01 22:33:38 tegge Exp $
- * $DragonFly: src/sys/platform/pc32/isa/Attic/apic_vector.s,v 1.8 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/Attic/apic_vector.s,v 1.9 2003/07/08 06:27:27 dillon Exp $
  */
 
 
@@ -38,7 +38,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -53,7 +53,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define IOAPICADDR(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 8
 #define REDIRIDX(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 12
@@ -165,6 +165,10 @@ IDTVEC(vec_name) ;                                                 \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
+       /* try to get giant */                                          \
+       call    try_mplock ;                                            \
+       testl   %eax,%eax ;                                             \
+       jz      1b ;                                                    \
        /* clear pending bit, run handler */                            \
        addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        andl    $~IRQ_LBIT(irq_num),PCPU(fpending) ;                    \
@@ -175,6 +179,7 @@ IDTVEC(vec_name) ;                                                  \
        incl    PCPU(cnt)+V_INTR ;      /* book-keeping make per cpu YYY */ \
        movl    intr_countp + (irq_num) * 4, %eax ;                     \
        incl    (%eax) ;                                                \
+       call    rel_mplock ;                                            \
        UNMASK_IRQ(irq_num) ;                                           \
 5: ;                                                                   \
        MEXITCOUNT ;                                                    \
@@ -190,6 +195,8 @@ IDTVEC(vec_name) ;                                                  \
  *     - Unmask the interrupt
  *     - Pop the dummy frame and do a normal return
  *
+ *     The BGL is held on call and left held on return.
+ *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
  */
@@ -221,17 +228,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule the thread.  Leave
- *       interrupts masked and doreti.
- *
- *     the interrupt thread will run its handlers and loop if
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule the thread.  Leave interrupts masked and doreti.
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
- *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
+ *     Note that calls to sched_ithd() are made with interrupts enabled
+ *     and outside a critical section.  YYY sched_ithd may preempt us
+ *     synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
  *     prefixes.
@@ -252,25 +254,20 @@ IDTVEC(vec_name) ;                                                        \
        pushl   %eax ;          /* cpl do restore */                    \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num),%eax ;                               \
-       jz      1f ;                                                    \
+       jz      2f ;                                                    \
 1: ;                                                                   \
        /* set the pending bit and return, leave the interrupt masked */ \
        orl     $IRQ_LBIT(irq_num), PCPU(ipending) ;                    \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -281,8 +278,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -291,7 +287,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(irq_num) ;                                           \
        popl %ebp ;                                                     \
        ret ;                                                           \
@@ -455,7 +450,7 @@ Xcpuast:
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
        orl     $AST_PENDING, PCPU(astpending)  /* XXX */
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        movl    PCPU(cpuid), %eax
@@ -497,7 +492,7 @@ Xforward_irq:
        movl    PCPU(curthread), %eax
        pushl   TD_CPL(%eax)            /* cpl restored by doreti */
 
-       incb    PCPU(intr_nesting_level)
+       incl    PCPU(intr_nesting_level)
        sti
        
        MEXITCOUNT
@@ -552,7 +547,7 @@ forward_irq:
        jnz     3b
 4:             
        ret
-       
+
 /*
  * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
  *
@@ -620,6 +615,35 @@ Xcpustop:
        popl    %ebp
        iret
 
+       /*
+        * For now just have one ipiq IPI, but what we really want is
+        * to have one for each source cpu to the APICs don't get stalled
+        * backlogging the requests.
+        */
+       .text
+       SUPERALIGN_TEXT
+       .globl Xipiq
+Xipiq:
+       PUSH_FRAME
+       movl    $0, lapic_eoi           /* End Of Interrupt to APIC */
+       FAKE_MCOUNT(13*4(%esp))
+
+       movl    PCPU(curthread),%ebx
+       cmpl    $TDPRI_CRIT,TD_PRI(%ebx)
+       jge     1f
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
+       call    lwkt_process_ipiq
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
+       pushl   TD_CPL(%ebx)
+       incl    PCPU(intr_nesting_level)
+       MEXITCOUNT
+       jmp     doreti
+1:
+       movl    $TDPRI_CRIT,PCPU(reqpri)
+       orl     $AST_IPIQ,PCPU(astpending)
+       MEXITCOUNT
+       POP_FRAME
+       iret
 
 MCOUNT_LABEL(bintr)
        FAST_INTR(0,fastintr0)
@@ -792,8 +816,6 @@ CNAME(resched_cpus):
 CNAME(cpustop_restartfunc):
        .long 0
                
-
-
        .globl  apic_pin_trigger
 apic_pin_trigger:
        .long   0
index a5a6a3f..5c79f47 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     from: vector.s, 386BSD 0.1 unknown origin
  * $FreeBSD: src/sys/i386/isa/icu_vector.s,v 1.14.2.2 2000/07/18 21:12:42 dfr Exp $
- * $DragonFly: src/sys/platform/pc32/isa/Attic/icu_vector.s,v 1.11 2003/07/03 17:24:02 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/Attic/icu_vector.s,v 1.12 2003/07/08 06:27:27 dillon Exp $
  */
 
 /*
@@ -68,7 +68,7 @@
        pushl   12(%esp) ;      /* original caller eip */               \
        pushl   $0 ;            /* dummy error code */                  \
        pushl   $0 ;            /* dummy trap type */                   \
-       subl    $11*4,%esp ;    /* pushal + 3 seg regs (dummy) */       \
+       subl    $12*4,%esp ;    /* pushal + 3 seg regs (dummy) + CPL */ \
 
 /*
  * Warning: POP_FRAME can only be used if there is no chance of a
@@ -83,7 +83,7 @@
        addl    $2*4,%esp ;     /* dummy trap & error codes */          \
 
 #define POP_DUMMY                                                      \
-       addl    $16*4,%esp ;                                            \
+       addl    $17*4,%esp ;                                            \
 
 #define MASK_IRQ(icu, irq_num)                                         \
        movb    imen + IRQ_BYTE(irq_num),%al ;                          \
@@ -188,16 +188,12 @@ IDTVEC(vec_name) ;                                                        \
  *       doreti.  In addition to checking for a critical section
  *       and cpl mask we also check to see if the thread is still
  *       running.
- *     - If we can take the interrupt clear its ipending bit,
- *       set its irunning bit, and schedule its thread.  Leave
- *       interrupts masked and doreti.
+ *     - If we can take the interrupt clear its ipending bit
+ *       and schedule its thread.  Leave interrupts masked and doreti.
  *
- *     The interrupt thread will run its handlers and loop if 
- *     ipending is found to be set.  ipending/irunning interlock
- *     the interrupt thread with the interrupt.  The handler calls
- *     UNPEND when it is through.
+ *     sched_ithd() is called with interrupts enabled and outside of a
+ *     critical section (so it can preempt us).
  *
- *     Note that we do not enable interrupts when calling sched_ithd.
  *     YYY sched_ithd may preempt us synchronously (fix interrupt stacking)
  *
  *     YYY can cache gd base pointer instead of using hidden %fs
@@ -219,8 +215,6 @@ IDTVEC(vec_name) ;                                                  \
        pushl   %eax ;          /* push CPL for doreti */               \
        cmpl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        jge     1f ;                                                    \
-       testl   $IRQ_LBIT(irq_num),PCPU(irunning) ;                     \
-       jnz     1f ;                                                    \
        testl   $IRQ_LBIT(irq_num), %eax ;                              \
        jz      2f ;                                                    \
 1: ;                                                                   \
@@ -229,15 +223,12 @@ IDTVEC(vec_name) ;                                                        \
        movl    $TDPRI_CRIT, PCPU(reqpri) ;                             \
        jmp     5f ;                                                    \
 2: ;                                                                   \
-       addl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        /* set running bit, clear pending bit, run handler */           \
-       orl     $IRQ_LBIT(irq_num), PCPU(irunning) ;                    \
        andl    $~IRQ_LBIT(irq_num), PCPU(ipending) ;                   \
        sti ;                                                           \
        pushl   $irq_num ;                                              \
        call    sched_ithd ;                                            \
        addl    $4,%esp ;                                               \
-       subl    $TDPRI_CRIT,TD_PRI(%ebx) ;                              \
        incl    PCPU(cnt)+V_INTR ; /* book-keeping YYY make per-cpu */  \
        movl    intr_countp + (irq_num) * 4,%eax ;                      \
        incl    (%eax) ;                                                \
@@ -248,8 +239,7 @@ IDTVEC(vec_name) ;                                                  \
 /*
  * Unmask a slow interrupt.  This function is used by interrupt threads
  * after they have descheduled themselves to reenable interrupts and
- * possibly cause a reschedule to occur.  The interrupt's irunning bit
- * is cleared prior to unmasking.
+ * possibly cause a reschedule to occur.
  */
 
 #define INTR_UNMASK(irq_num, vec_name, icu)                            \
@@ -258,7 +248,6 @@ IDTVEC(vec_name) ;                                                  \
 IDTVEC(vec_name) ;                                                     \
        pushl %ebp ;     /* frame for ddb backtrace */                  \
        movl    %esp, %ebp ;                                            \
-       andl    $~IRQ_LBIT(irq_num), PCPU(irunning) ;                   \
        UNMASK_IRQ(icu, irq_num) ;                                      \
        popl %ebp ;                                                     \
        ret ;                                                           \
index d72c4ab..114c6de 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)isa.c 7.2 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
- * $DragonFly: src/sys/platform/pc32/isa/intr_machdep.c,v 1.6 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/intr_machdep.c,v 1.7 2003/07/08 06:27:27 dillon Exp $
  */
 /*
  * This file contains an aggregated module marked:
@@ -66,8 +66,8 @@
 #include <sys/thread2.h>
 
 #if defined(APIC_IO)
-#include <machine/smp.h>
 #include <machine/smptests.h>                  /** FAST_HI */
+#include <machine/smp.h>
 #endif /* APIC_IO */
 #ifdef PC98
 #include <pc98/pc98/pc98.h>
 
 static inthand2_t isa_strayintr;
 
+void   *intr_unit[ICU_LEN*2];
 u_long *intr_countp[ICU_LEN*2];
 inthand2_t *intr_handler[ICU_LEN*2] = {
        isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
@@ -124,10 +125,13 @@ inthand2_t *intr_handler[ICU_LEN*2] = {
        isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
        isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
 };
-u_int  intr_mask[ICU_LEN*2];
-int    intr_mihandler_installed[ICU_LEN*2];
-static u_int*  intr_mptr[ICU_LEN*2];
-void   *intr_unit[ICU_LEN*2];
+
+static struct md_intr_info {
+    int                irq;
+    u_int      mask;
+    int                mihandler_installed;
+    u_int      *maskp;
+} intr_info[ICU_LEN*2];
 
 static inthand_t *fastintr[ICU_LEN] = {
        &IDTVEC(fastintr0), &IDTVEC(fastintr1),
@@ -381,17 +385,17 @@ update_intr_masks(void)
 #else
                if (intr==ICU_SLAVEID) continue;        /* ignore 8259 SLAVE output */
 #endif /* APIC_IO */
-               maskptr = intr_mptr[intr];
+               maskptr = intr_info[intr].maskp;
                if (!maskptr)
                        continue;
                *maskptr |= SWI_CLOCK_MASK | (1 << intr);
                mask = *maskptr;
-               if (mask != intr_mask[intr]) {
+               if (mask != intr_info[intr].mask) {
 #if 0
                        printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
-                               intr, intr_mask[intr], mask, maskptr);
+                               intr, intr_info[intr].mask, mask, maskptr);
 #endif
-                       intr_mask[intr]=mask;
+                       intr_info[intr].mask = mask;
                        n++;
                }
 
@@ -474,9 +478,13 @@ icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
        ef = read_eflags();
        cpu_disable_intr();     /* YYY */
        intr_handler[intr] = handler;
-       intr_mptr[intr] = maskptr;
-       intr_mask[intr] = mask | SWI_CLOCK_MASK | (1 << intr);
        intr_unit[intr] = arg;
+       intr_info[intr].maskp = maskptr;
+       intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
+#if 0
+       /* YYY  fast ints supported and mp protected but ... */
+       flags &= ~INTR_FAST;
+#endif
 #ifdef FAST_HI
        if (flags & INTR_FAST) {
                vector = TPR_FAST_INTS + intr;
@@ -533,8 +541,8 @@ icu_unset(intr, handler)
        cpu_disable_intr();     /* YYY */
        intr_countp[intr] = &intrcnt[1 + intr];
        intr_handler[intr] = isa_strayintr;
-       intr_mptr[intr] = NULL;
-       intr_mask[intr] = HWI_MASK | SWI_MASK;
+       intr_info[intr].maskp = NULL;
+       intr_info[intr].mask = HWI_MASK | SWI_MASK;
        intr_unit[intr] = &intr_unit[intr];
 #ifdef FAST_HI_XXX
        /* XXX how do I re-create dvp here? */
@@ -697,9 +705,24 @@ update_masks(intrmask_t *maskptr, int irq)
 }
 
 /*
- * Add interrupt handler to linked list hung off of intreclist_head[irq]
- * and install shared interrupt multiplex handler, if necessary
+ * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
+ * and install a shared interrupt multiplex handler, if necessary.  Install
+ * an interrupt thread for each interrupt (though FAST interrupts will not
+ * use it).  The preemption procedure checks the CPL.  lwkt_preempt() will
+ * check relative thread priorities for us as long as we properly pass through
+ * critpri.
+ *
+ * YYY needs work.  At the moment the handler is run inside a critical
+ * section so only the preemption cpl check is used.
  */
+static void
+cpu_intr_preempt(struct thread *td, int critpri)
+{
+       struct md_intr_info *info = td->td_info.intdata;
+
+       if ((curthread->td_cpl & (1 << info->irq)) == 0)
+               lwkt_preempt(td, critpri);
+}
 
 static int
 add_intrdesc(intrec *idesc)
@@ -716,10 +739,15 @@ add_intrdesc(intrec *idesc)
         * temporary hack to run normal interrupts as interrupt threads.
         * YYY FIXME!
         */
-       if (intr_mihandler_installed[irq] == 0) {
-               intr_mihandler_installed[irq] = 1;
-               register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
-               printf("installing MI handler for int %d\n", irq);
+       if (intr_info[irq].mihandler_installed == 0) {
+               struct thread *td;
+
+               intr_info[irq].mihandler_installed = 1;
+               intr_info[irq].irq = irq;
+               td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
+               td->td_info.intdata = &intr_info[irq];
+               td->td_preemptable = cpu_intr_preempt;
+               printf("installed MI handler for int %d\n", irq);
        }
 
        head = intreclist_head[irq];
@@ -913,11 +941,8 @@ inthand_remove(intrec *idesc)
  * ithread_done()
  *
  *     This function is called by an interrupt thread when it has completed
- *     processing a loop.  We interlock with ipending and irunning.  If
- *     a new interrupt is pending for the thread the function clears the
- *     pending bit and returns.  If no new interrupt is pending we 
- *     deschedule and sleep.  If we reschedule and return we have to 
- *     disable the interrupt again or it will keep interrupting us.
+ *     processing a loop.  We re-enable itnerrupts and interlock with
+ *     ipending.
  *
  *     See kern/kern_intr.c for more information.
  */
@@ -928,21 +953,14 @@ ithread_done(int irq)
     int mask = 1 << irq;
 
     KKASSERT(curthread->td_pri >= TDPRI_CRIT);
+    lwkt_deschedule_self();
     INTREN(mask);
     if (gd->gd_ipending & mask) {
        atomic_clear_int(&gd->gd_ipending, mask);
        INTRDIS(mask);
        lwkt_schedule_self();
     } else {
-       lwkt_deschedule_self();
-       if (gd->gd_ipending & mask) {   /* race */
-           atomic_clear_int(&gd->gd_ipending, mask);
-           INTRDIS(mask);
-           lwkt_schedule_self();
-       } else {
-           atomic_clear_int(&gd->gd_irunning, mask);
-           lwkt_switch();
-       }
+       lwkt_switch();
     }
 }
 
index 4ff8e53..d4ca6fc 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/isa/intr_machdep.h,v 1.19.2.2 2001/10/14 20:05:50 luigi Exp $
- * $DragonFly: src/sys/platform/pc32/isa/intr_machdep.h,v 1.4 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/intr_machdep.h,v 1.5 2003/07/08 06:27:27 dillon Exp $
  */
 
 #ifndef _I386_ISA_INTR_MACHDEP_H_
 /* inter-CPU rendezvous */
 #define XRENDEZVOUS_OFFSET     (ICU_OFFSET + 114)
 
+/* IPIQ rendezvous */
+#define XIPIQ_OFFSET           (ICU_OFFSET + 115)
+
 /* IPI to generate an additional software trap at the target CPU */
 #define XCPUAST_OFFSET         (ICU_OFFSET +  48)
 
@@ -205,6 +208,7 @@ inthand_t
        Xforward_irq,   /* Forward irq to cpu holding ISR lock */
        Xcpustop,       /* CPU stops & waits for another CPU to restart it */
        Xspuriousint,   /* handle APIC "spurious INTs" */
+       Xipiq,          /* handle lwkt_send_ipiq() requests */
        Xrendezvous;    /* handle CPU rendezvous */
 
 #ifdef TEST_TEST1
index 5bde3e0..b075567 100644 (file)
@@ -37,7 +37,7 @@
  *     @(#)ipl.s
  *
  * $FreeBSD: src/sys/i386/isa/ipl.s,v 1.32.2.3 2002/05/16 16:03:56 bde Exp $
- * $DragonFly: src/sys/platform/pc32/isa/ipl.s,v 1.6 2003/07/01 20:31:38 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/ipl.s,v 1.7 2003/07/08 06:27:27 dillon Exp $
  */
 
 
@@ -68,10 +68,6 @@ soft_imask:  .long   SWI_MASK
 softnet_imask: .long   SWI_NET_MASK
        .globl  softtty_imask
 softtty_imask: .long   SWI_TTY_MASK
-       .globl  last_splz
-last_splz:     .long   0
-       .globl  last_splz2
-last_splz2:    .long   0
 
        .text
 
@@ -101,11 +97,12 @@ doreti_next:
        testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
        jne     doreti_fast
 
-       movl    PCPU(irunning),%edx     /* check for an unmasked normal int */
-       notl    %edx                    /* that isn't already running */
-       andl    %edx, %ecx
        testl   PCPU(ipending),%ecx
        jne     doreti_intr
+#ifdef SMP
+       testl   $AST_IPIQ,PCPU(astpending)
+       jnz     doreti_ipiq
+#endif
        testl   $AST_PENDING,PCPU(astpending) /* any pending ASTs? */
        jz      2f
        testl   $PSL_VM,TF_EFLAGS(%esp)
@@ -115,11 +112,11 @@ doreti_next:
 1:
        testb   $SEL_RPL_MASK,TF_CS(%esp)
        jnz     doreti_ast
-
+2:
        /*
         * Nothing left to do, finish up.  Interrupts are still disabled.
         */
-2:
+4:
        subl    $TDPRI_CRIT,TD_PRI(%ebx)        /* interlocked with cli */
 5:
        decl    PCPU(intr_nesting_level)
@@ -168,13 +165,31 @@ doreti_fast:
        bsfl    %ecx, %ecx              /* locate the next dispatchable int */
        btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
        jnc     doreti_next
-       pushl   %eax                    /* YYY cpl */
-       call    *fastunpend(,%ecx,4)
+       pushl   %eax                    /* YYY cpl (expected by frame) */
+#ifdef SMP
+       pushl   %ecx                    /* save ecx */
+       call    try_mplock
+       popl    %ecx
+       testl   %eax,%eax
+       jz      1f
+#endif
+       call    *fastunpend(,%ecx,4)    /* MP lock successful */
+#ifdef SMP
+       call    rel_mplock
+#endif
+       popl    %eax
+       jmp     doreti_next
+1:
+       btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
        popl    %eax
+       orl     PCPU(fpending),%eax
        jmp     doreti_next
 
        /*
         *  INTR interrupt pending
+        *
+        *  Temporarily back-out our critical section to allow the interrupt
+        *  preempt us.
         */
        ALIGN_TEXT
 doreti_intr:
@@ -184,7 +199,9 @@ doreti_intr:
        jnc     doreti_next
        pushl   %eax
        pushl   %ecx
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
        call    sched_ithd              /* YYY must pull in imasks */
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
        addl    $4,%esp
        popl    %eax
        jmp     doreti_next
@@ -195,13 +212,25 @@ doreti_intr:
 doreti_ast:
        andl    $~AST_PENDING,PCPU(astpending)
        sti
+       movl    %eax,%esi               /* save cpl (can't use stack) */
        movl    $T_ASTFLT,TF_TRAPNO(%esp)
        decl    PCPU(intr_nesting_level)
        call    trap
        incl    PCPU(intr_nesting_level)
+       movl    %esi,%eax               /* restore cpl for loop */
+       jmp     doreti_next
+
+#ifdef SMP
+       /*
+        * IPIQ message pending
+        */
+doreti_ipiq:
+       andl    $~AST_IPIQ,PCPU(astpending)
+       call    lwkt_process_ipiq
        movl    TD_CPL(%ebx),%eax       /* retrieve cpl again for loop */
        jmp     doreti_next
 
+#endif
 
        /*
         * SPLZ() a C callable procedure to dispatch any unmasked pending
@@ -227,12 +256,14 @@ splz_next:
        testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
        jne     splz_fast
 
-       movl    PCPU(irunning),%edx     /* check for an unmasked normal int */
-       notl    %edx                    /* that isn't already running */
-       andl    %edx, %ecx
        testl   PCPU(ipending),%ecx
        jne     splz_intr
 
+#ifdef SMP
+       testl   $AST_IPIQ,PCPU(astpending)
+       jnz     splz_ipiq
+#endif
+
        subl    $TDPRI_CRIT,TD_PRI(%ebx)
        popl    %ebx
        popfl
@@ -247,16 +278,31 @@ splz_fast:
        bsfl    %ecx, %ecx              /* locate the next dispatchable int */
        btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
        jnc     splz_next
-       movl    $1,last_splz
-       movl    %ecx,last_splz2
        pushl   %eax
+#ifdef SMP
+       pushl   %ecx
+       call    try_mplock
+       popl    %ecx
+       testl   %eax,%eax
+       jz      1f
+#endif
        call    *fastunpend(,%ecx,4)
+#ifdef SMP
+       call    rel_mplock
+#endif
+       popl    %eax
+       jmp     splz_next
+1:
+       btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
        popl    %eax
-       movl    $-1,last_splz
+       orl     PCPU(fpending),%eax
        jmp     splz_next
 
        /*
         *  INTR interrupt pending
+        *
+        *  Temporarily back-out our critical section to allow the interrupt
+        *  preempt us.
         */
        ALIGN_TEXT
 splz_intr:
@@ -265,16 +311,24 @@ splz_intr:
        btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
        jnc     splz_next
        sti
-       movl    $2,last_splz
        pushl   %eax
        pushl   %ecx
-       movl    %ecx,last_splz2
+       subl    $TDPRI_CRIT,TD_PRI(%ebx)
        call    sched_ithd              /* YYY must pull in imasks */
+       addl    $TDPRI_CRIT,TD_PRI(%ebx)
        addl    $4,%esp
        popl    %eax
-       movl    $-2,last_splz
        jmp     splz_next
 
+#ifdef SMP
+splz_ipiq:
+       andl    $~AST_IPIQ,PCPU(astpending)
+       pushl   %eax
+       call    lwkt_process_ipiq
+       popl    %eax
+       jmp     splz_next
+#endif
+
        /*
         * APIC/ICU specific ipl functions provide masking and unmasking
         * calls for userland.
index 91e7b2f..38f4407 100644 (file)
@@ -33,7 +33,7 @@
  *
  *     from: @(#)npx.c 7.2 (Berkeley) 5/12/91
  * $FreeBSD: src/sys/i386/isa/npx.c,v 1.80.2.3 2001/10/20 19:04:38 tegge Exp $
- * $DragonFly: src/sys/platform/pc32/isa/npx.c,v 1.7 2003/07/06 21:23:49 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/npx.c,v 1.8 2003/07/08 06:27:27 dillon Exp $
  */
 
 #include "opt_cpu.h"
@@ -861,6 +861,11 @@ npxdna()
  * often called at splhigh so it must not use many system services.  In
  * particular, it's much easier to install a special handler than to
  * guarantee that it's safe to use npxintr() and its supporting code.
+ *
+ * WARNING!  This call is made during a switch and the MP lock will be
+ * setup for the new target thread rather then the current thread, so we
+ * cannot do anything here that depends on the *_mplock() functions as
+ * we may trip over their assertions.
  */
 void
 npxsave(addr)
index eb0203c..6540a45 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)genassym.c    5.11 (Berkeley) 5/10/91
  * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $
- * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.21 2003/07/06 21:23:48 dillon Exp $
+ * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.22 2003/07/08 06:27:26 dillon Exp $
  */
 
 #include "opt_user_ldt.h"
@@ -102,6 +102,7 @@ ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner));
 ASSYM(TD_CPL, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_cpl));
 
 ASSYM(TDPRI_CRIT, TDPRI_CRIT);
+ASSYM(TDPRI_INT_SUPPORT, TDPRI_INT_SUPPORT);
 
 ASSYM(SSLEEP, SSLEEP);
 ASSYM(SRUN, SRUN);
@@ -197,7 +198,6 @@ ASSYM(GD_CURRENTLDT, offsetof(struct mdglobaldata, gd_currentldt));
 
 ASSYM(GD_FPENDING, offsetof(struct mdglobaldata, gd_fpending));
 ASSYM(GD_IPENDING, offsetof(struct mdglobaldata, gd_ipending));
-ASSYM(GD_IRUNNING, offsetof(struct mdglobaldata, gd_irunning));
 ASSYM(GD_COMMON_TSS, offsetof(struct mdglobaldata, gd_common_tss));
 ASSYM(GD_COMMON_TSSD, offsetof(struct mdglobaldata, gd_common_tssd));
 ASSYM(GD_TSS_GDT, offsetof(struct mdglobaldata, gd_tss_gdt));
index 52850fd..3fc415e 100644 (file)
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/globaldata.h,v 1.11.2.1 2000/05/16 06:58:10 dillon Exp $
- * $DragonFly: src/sys/sys/globaldata.h,v 1.7 2003/07/04 00:26:00 dillon Exp $
+ * $DragonFly: src/sys/sys/globaldata.h,v 1.8 2003/07/08 06:27:28 dillon Exp $
  */
 
 #ifndef _SYS_GLOBALDATA_H_
 #define _SYS_GLOBALDATA_H_
 
+#ifndef _SYS_TIME_H_
+#include <sys/time.h>  /* struct timeval */
+#endif
+#ifndef _SYS_VMMETER_H_
+#include <sys/vmmeter.h>
+#endif _SYS_VMMETER_H_
+
 /*
  * This structure maps out the global data that needs to be kept on a
  * per-cpu basis.  genassym uses this to generate offsets for the assembler
  * the LWKT subsystem.
  */
 
-#ifndef _SYS_TIME_H_
-#include <sys/time.h>  /* struct timeval */
-#endif
-#ifndef _SYS_VMMETER_H_
-#include <sys/vmmeter.h>
-#endif _SYS_VMMETER_H_
-
 struct privatespace;
+struct thread;
+struct lwkt_ipiq;
 
 struct globaldata {
        struct privatespace *gd_prvspace;       /* self-reference */
@@ -82,6 +84,7 @@ struct globaldata {
        int             gd_astpending;          /* sorta MD but easier here */
        int             gd_uprocscheduled;
        struct vmmeter  gd_cnt;
+       struct lwkt_ipiq *gd_ipiq;
        /* extended by <machine/pcpu.h> */
 };
 
index bd79a37..b996903 100644 (file)
@@ -24,7 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/sys/interrupt.h,v 1.9.2.1 2001/10/14 20:05:50 luigi Exp $
- * $DragonFly: src/sys/sys/interrupt.h,v 1.5 2003/07/04 05:57:27 dillon Exp $
+ * $DragonFly: src/sys/sys/interrupt.h,v 1.6 2003/07/08 06:27:28 dillon Exp $
  */
 
 #ifndef _SYS_INTERRUPT_H_
 typedef void inthand2_t __P((void *_cookie));
 typedef void ointhand2_t __P((int _device_id));
 
-void register_swi(int intr, inthand2_t *handler, void *arg, const char *name);
-void register_int(int intr, inthand2_t *handler, void *arg, const char *name);
+struct thread;
+
+struct thread *register_swi(int intr, inthand2_t *handler, void *arg,
+                           const char *name);
+struct thread *register_int(int intr, inthand2_t *handler, void *arg,
+                           const char *name);
 void register_randintr(int intr);
+
 void swi_setpriority(int intr, int pri);
 void unregister_swi(int intr, inthand2_t *handler);
 void unregister_int(int intr, inthand2_t *handler);
index f2a3274..e40fee2 100644 (file)
@@ -4,7 +4,7 @@
  *     Implements the architecture independant portion of the LWKT 
  *     subsystem.
  * 
- * $DragonFly: src/sys/sys/thread.h,v 1.19 2003/07/06 21:23:54 dillon Exp $
+ * $DragonFly: src/sys/sys/thread.h,v 1.20 2003/07/08 06:27:28 dillon Exp $
  */
 
 #ifndef _SYS_THREAD_H_
@@ -21,6 +21,7 @@ struct lwkt_queue;
 struct lwkt_token;
 struct lwkt_wait;
 struct lwkt_msg;
+struct lwkt_ipiq;
 struct lwkt_port;
 struct lwkt_cpu_msg;
 struct lwkt_cpu_port;
@@ -34,6 +35,7 @@ typedef struct lwkt_port      *lwkt_port_t;
 typedef struct lwkt_cpu_msg    *lwkt_cpu_msg_t;
 typedef struct lwkt_cpu_port   *lwkt_cpu_port_t;
 typedef struct lwkt_rwlock     *lwkt_rwlock_t;
+typedef struct lwkt_ipiq       *lwkt_ipiq_t;
 typedef struct thread          *thread_t;
 
 typedef TAILQ_HEAD(lwkt_queue, thread) lwkt_queue;
@@ -70,7 +72,7 @@ typedef struct lwkt_wait {
 } lwkt_wait;
 
 /*
- * The standarding message and port structure for communications between
+ * The standard message and port structure for communications between
  * threads.
  */
 typedef struct lwkt_msg {
@@ -92,6 +94,18 @@ typedef struct lwkt_port {
 
 #define mp_token       mp_wait.wa_token
 
+#define MAXCPUFIFO      16     /* power of 2 */
+#define MAXCPUFIFO_MASK        (MAXCPUFIFO - 1)
+
+typedef void (*ipifunc_t)(void *arg);
+
+typedef struct lwkt_ipiq {
+    int                ip_rindex;      /* only written by target cpu */
+    int                ip_windex;      /* only written by source cpu */
+    ipifunc_t  ip_func[MAXCPUFIFO];
+    void       *ip_arg[MAXCPUFIFO];
+} lwkt_ipiq;
+
 /*
  * The standard message and queue structure used for communications between
  * cpus.  Messages are typically queued via a machine-specific non-linked
@@ -128,6 +142,8 @@ typedef struct lwkt_rwlock {
  * NOTE: td_pri is bumped by TDPRI_CRIT when entering a critical section,
  * but this does not effect how the thread is scheduled by LWKT.
  */
+struct md_intr_info;
+
 struct thread {
     TAILQ_ENTRY(thread) td_threadq;
     TAILQ_ENTRY(thread) td_allq;
@@ -140,6 +156,11 @@ struct thread {
     int                td_pri;         /* 0-31, 31=highest priority (note 1) */
     int                td_flags;       /* THF flags */
     int                td_gen;         /* wait queue chasing generation number */
+                               /* maybe preempt */
+    void       (*td_preemptable)(struct thread *td, int critpri);
+    union {
+       struct md_intr_info *intdata;
+    } td_info;
     char       *td_kstack;     /* kernel stack */
     char       *td_sp;         /* kernel stack pointer for LWKT restore */
     void       (*td_switch)(struct thread *ntd);
@@ -222,7 +243,7 @@ extern void lwkt_free_thread(struct thread *td);
 extern void lwkt_init_wait(struct lwkt_wait *w);
 extern void lwkt_gdinit(struct globaldata *gd);
 extern void lwkt_switch(void);
-extern void lwkt_preempt(thread_t ntd, int id);
+extern void lwkt_preempt(thread_t ntd, int critpri);
 extern void lwkt_schedule(thread_t td);
 extern void lwkt_schedule_self(void);
 extern void lwkt_deschedule(thread_t td);
@@ -234,6 +255,7 @@ extern void lwkt_rele(thread_t td);
 
 extern void lwkt_block(lwkt_wait_t w, const char *wmesg, int *gen);
 extern void lwkt_signal(lwkt_wait_t w);
+extern int lwkt_trytoken(lwkt_token_t tok);
 extern int lwkt_gettoken(lwkt_token_t tok);
 extern int lwkt_gentoken(lwkt_token_t tok, int *gen);
 extern void lwkt_reltoken(lwkt_token_t tok);
@@ -246,6 +268,9 @@ extern void lwkt_exunlock(lwkt_rwlock_t lock);
 extern void lwkt_shunlock(lwkt_rwlock_t lock);
 extern void lwkt_setpri(thread_t td, int pri);
 extern void lwkt_setpri_self(int pri);
+extern int  lwkt_send_ipiq(int dcpu, ipifunc_t func, void *arg);
+extern void lwkt_wait_ipiq(int dcpu, int seq);
+extern void lwkt_process_ipiq(void);
 extern void crit_panic(void);
 extern struct proc *lwkt_preempted_proc(void);
 
index 450527f..70ca3e7 100644 (file)
@@ -8,7 +8,7 @@
  *     on a different cpu will not be immediately scheduled by a yield() on
  *     this cpu.
  *
- * $DragonFly: src/sys/sys/thread2.h,v 1.5 2003/07/06 21:23:54 dillon Exp $
+ * $DragonFly: src/sys/sys/thread2.h,v 1.6 2003/07/08 06:27:28 dillon Exp $
  */
 
 #ifndef _SYS_THREAD2_H_
@@ -77,6 +77,10 @@ lwkt_havetoken(lwkt_token_t tok)
     return (tok->t_cpu == mycpu->gd_cpuid);
 }
 
+/*
+ * Return whether any threads are runnable, whether they meet mp_lock
+ * requirements or not.
+ */
 static __inline int
 lwkt_runnable(void)
 {