Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm Don't drop to spl0 in cpu_switch/cpu_switchto. ...



details:   https://anonhg.NetBSD.org/src/rev/bb7f5ef34b31
branches:  trunk
changeset: 553942:bb7f5ef34b31
user:      scw <scw%NetBSD.org@localhost>
date:      Thu Oct 23 08:59:10 2003 +0000

description:
Don't drop to spl0 in cpu_switch/cpu_switchto. Do it in the idle loop
instead.

With this change, we no longer need to save the current interrupt level
in the switchframe. This is no great loss since both cpu_switch and
cpu_switchto are always called at splsched, so the process' spl is
effectively saved somewhere in the callstack.

This fixes an evbarm problem reported by Allen Briggs:

        lwp gets into sa_switch -> mi_switch with newl != NULL
            when it's the last element on the runqueue, so it
            hits the second bit of:
                if (newl == NULL) {
                        retval = cpu_switch(l, NULL);
                } else {
                        remrunqueue(newl);
                        cpu_switchto(l, newl);
                        retval = 0;
                }

        mi_switch calls remrunqueue() and cpu_switchto()

        cpu_switchto unlocks the sched lock
        cpu_switchto drops CPU priority
        softclock is received
        schedcpu is called from softclock
        schedcpu hits the first if () {} block here:
                if (l->l_priority >= PUSER) {
                        if (l->l_stat == LSRUN &&
                            (l->l_flag & L_INMEM) &&
                            (l->l_priority / PPQ) != (l->l_usrpri / PPQ)) {
                                remrunqueue(l);
                                l->l_priority = l->l_usrpri;
                                setrunqueue(l);
                        } else
                                l->l_priority = l->l_usrpri;
                }

        Since mi_switch has already run remrunqueue, the LWP has been
            removed, but it's not been put back on any queue, so the
            remrunqueue panics.

diffstat:

 sys/arch/arm/arm32/cpuswitch.S     |  126 ++++++++++++++----------------------
 sys/arch/arm/arm32/vm_machdep.c    |    6 +-
 sys/arch/arm/include/arm32/frame.h |    3 +-
 3 files changed, 54 insertions(+), 81 deletions(-)

diffs (284 lines):

diff -r 3d53dfb4a5ed -r bb7f5ef34b31 sys/arch/arm/arm32/cpuswitch.S
--- a/sys/arch/arm/arm32/cpuswitch.S    Thu Oct 23 08:30:21 2003 +0000
+++ b/sys/arch/arm/arm32/cpuswitch.S    Thu Oct 23 08:59:10 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpuswitch.S,v 1.37 2003/10/13 21:44:27 scw Exp $       */
+/*     $NetBSD: cpuswitch.S,v 1.38 2003/10/23 08:59:10 scw Exp $       */
 
 /*
  * Copyright 2003 Wasabi Systems, Inc.
@@ -195,28 +195,45 @@
 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
        bl      _C_LABEL(sched_unlock_idle)
 #endif
-       ldr     r3, .Lcpu_do_powersave
 
        /* Enable interrupts */
        IRQenable
 
+       ldr     r6, .Lcpu_do_powersave
+
+       /* Lower the spl level to spl0 and get the current spl level. */
+#ifdef __NEWINTR
+       mov     r0, #(IPL_NONE)
+       bl      _C_LABEL(_spllower)
+#else /* ! __NEWINTR */
+       mov     r0, #(_SPL_0)
+       bl      _C_LABEL(splx)
+#endif /* __NEWINTR */
+
+       /* Old interrupt level in r0 */
+
        /* If we don't want to sleep, use a simpler loop. */
-       ldr     r3, [r3]                /* r3 = cpu_do_powersave */
-       teq     r3, #0
+       ldr     r6, [r6]                /* r6 = cpu_do_powersave */
+       teq     r6, #0
        bne     2f
 
        /* Non-powersave idle. */
 1:     /* should maybe do uvm pageidlezero stuff here */
        ldr     r3, [r7]                /* r3 = whichqs */
        teq     r3, #0x00000000
-       bne     .Lswitch_search
-       b       1b
+       beq     1b
+       adr     lr, .Lswitch_search
+       b       _C_LABEL(splx)      /* Restore ipl, return to switch_search */
 
 2:     /* Powersave idle. */
        ldr     r4, .Lcpufuncs
+       mov     r6, r0                  /* Preserve old interrupt level */
+
 3:     ldr     r3, [r7]                /* r3 = whichqs */
        teq     r3, #0x00000000
-       bne     .Lswitch_search
+       moveq   r0, r6
+       adreq   lr, .Lswitch_search
+       beq     _C_LABEL(splx)      /* Restore ipl, return to switch_search */
 
        /* if saving power, don't want to pageidlezero */
        mov     r0, #0
@@ -259,25 +276,7 @@
        /* stash the old proc while we call functions */
        mov     r5, r0
 
-#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
-       /* release the sched_lock before handling interrupts */
-       bl      _C_LABEL(sched_unlock_idle)
-#endif
-
-       /* Lower the spl level to spl0 and get the current spl level. */
-#ifdef __NEWINTR
-       mov     r0, #(IPL_NONE)
-       bl      _C_LABEL(_spllower)
-#else /* ! __NEWINTR */
-       mov     r0, #(_SPL_0)
-       bl      _C_LABEL(splx)
-#endif /* __NEWINTR */
-
-       /* Push the old spl level onto the stack */
-       str     r0, [sp, #-0x0004]!
-
        /* First phase : find a new lwp */
-
        ldr     r7, .Lwhichqs
 
        /* rem: r5 = old lwp */
@@ -285,9 +284,6 @@
 
 .Lswitch_search:
        IRQdisable
-#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
-       bl      _C_LABEL(sched_lock_idle)
-#endif
 
        /* Do we have any active queues  */
        ldr     r3, [r7]
@@ -369,8 +365,8 @@
        str     r0, [r7, #(L_BACK)]
 
        /* Update the RAM copy of the queue not empty flags word. */
-       ldr     r7, .Lwhichqs
-       str     r3, [r7]
+       ldreq   r7, .Lwhichqs
+       streq   r3, [r7]
 
        /* rem: r1 = old lwp */
        /* rem: r3 = whichqs - NOT NEEDED ANY MORE */
@@ -398,7 +394,13 @@
        mov     r1, r7
 #endif
 
+
 .Lswitch_resume:
+       /* rem: r1 = old lwp */
+       /* rem: r4 = return value [not used if came from cpu_switchto()] */
+       /* rem: r6 = new process */
+       /* rem: interrupts are disabled */
+
 #ifdef MULTIPROCESSOR
        /* XXX use curcpu() */
        ldr     r0, .Lcpu_info_store
@@ -745,16 +747,11 @@
         */
 
        ldr     r2, [r5, #(P_NRAS)]
-       ldr     r4, [r7, #(PCB_TF)]     /* r4 = trapframe (used below) */
+       ldr     r1, [r7, #(PCB_TF)]     /* r1 = trapframe (used below) */
        teq     r2, #0                  /* p->p_nras == 0? */
        bne     .Lswitch_do_ras         /* no, check for one */
 
 .Lswitch_return:
-
-       /* Get the spl level from the stack and update the current spl level */
-       ldr     r0, [sp], #0x0004
-       bl      _C_LABEL(splx)
-
        /* cpu_switch returns 1 == switched, 0 == didn't switch */
        mov     r0, r4
 
@@ -765,11 +762,12 @@
        ldmfd   sp!, {r4-r7, pc}
 
 .Lswitch_do_ras:
-       ldr     r1, [r4, #(TF_PC)]      /* second ras_lookup() arg */
+       ldr     r1, [r1, #(TF_PC)]      /* second ras_lookup() arg */
        mov     r0, r5                  /* first ras_lookup() arg */
        bl      _C_LABEL(ras_lookup)
        cmn     r0, #1                  /* -1 means "not in a RAS" */
-       strne   r0, [r4, #(TF_PC)]
+       ldrne   r1, [r7, #(PCB_TF)]
+       strne   r0, [r1, #(TF_PC)]
        b       .Lswitch_return
 
 .Lswitch_exited:
@@ -798,55 +796,25 @@
 ENTRY(cpu_switchto)
        stmfd   sp!, {r4-r7, lr}
 
-       /* Lower the spl level to spl0 and get the current spl level. */
-       mov     r6, r0          /* save old lwp */
-       mov     r5, r1          /* save new lwp */
+       mov     r6, r1          /* save new lwp */
 
 #if defined(LOCKDEBUG)
-       /* release the sched_lock before handling interrupts */
+       mov     r5, r0          /* save old lwp */
        bl      _C_LABEL(sched_unlock_idle)
+       mov     r1, r5
+#else
+       mov     r1, r0
 #endif
 
-#ifdef __NEWINTR
-       mov     r0, #(IPL_NONE)
-       bl      _C_LABEL(_spllower)
-#else /* ! __NEWINTR */
-#ifdef spl0
-       mov     r0, #(_SPL_0)
-       bl      _C_LABEL(splx)
-#else
-       bl      _C_LABEL(spl0)
-#endif /* spl0 */
-#endif /* __NEWINTR */
-
-       /* Push the old spl level onto the stack */
-       str     r0, [sp, #-0x0004]!
-
        IRQdisable
-#if defined(LOCKDEBUG)
-       bl      _C_LABEL(sched_lock_idle)
-#endif
-
-       mov     r0, r6          /* restore old lwp */
-       mov     r1, r5          /* restore new lwp */
-
-       /* rem: r0 = old lwp */
-       /* rem: r1 = new lwp */
-       /* rem: interrupts are disabled */
 
        /*
         * Okay, set up registers the way cpu_switch() wants them,
         * and jump into the middle of it (where we bring up the
         * new process).
+        *
+        * r1 = old lwp (r6 = new lwp)
         */
-       mov     r6, r1                  /* r6 = new lwp */
-#if defined(LOCKDEBUG)
-       mov     r5, r0                  /* preserve old lwp */
-       bl      _C_LABEL(sched_unlock_idle)
-       mov     r1, r5                  /* r1 = old lwp */
-#else
-       mov     r1, r0                  /* r1 = old lwp */
-#endif
        b       .Lswitch_resume
 
 /*
@@ -1007,6 +975,14 @@
        ldmfd   sp!, {r4-r7, pc}
 
 ENTRY(proc_trampoline)
+#ifdef __NEWINTR
+       mov     r0, #(IPL_NONE)
+       bl      _C_LABEL(_spllower)
+#else /* ! __NEWINTR */
+       mov     r0, #(_SPL_0)
+       bl      _C_LABEL(splx)
+#endif /* __NEWINTR */
+
 #ifdef MULTIPROCESSOR
        bl      _C_LABEL(proc_trampoline_mp)
 #endif
diff -r 3d53dfb4a5ed -r bb7f5ef34b31 sys/arch/arm/arm32/vm_machdep.c
--- a/sys/arch/arm/arm32/vm_machdep.c   Thu Oct 23 08:30:21 2003 +0000
+++ b/sys/arch/arm/arm32/vm_machdep.c   Thu Oct 23 08:59:10 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vm_machdep.c,v 1.29 2003/07/15 00:24:42 lukem Exp $    */
+/*     $NetBSD: vm_machdep.c,v 1.30 2003/10/23 08:59:10 scw Exp $      */
 
 /*
  * Copyright (c) 1994-1998 Mark Brinicombe.
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.29 2003/07/15 00:24:42 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.30 2003/10/23 08:59:10 scw Exp $");
 
 #include "opt_armfpe.h"
 #include "opt_pmap_debug.h"
@@ -197,7 +197,6 @@
                tf->tf_usr_sp = (u_int)stack + stacksize;
 
        sf = (struct switchframe *)tf - 1;
-       sf->sf_spl = 0;         /* always equivalent to spl0() */
        sf->sf_r4 = (u_int)func;
        sf->sf_r5 = (u_int)arg;
        sf->sf_pc = (u_int)proc_trampoline;
@@ -211,7 +210,6 @@
        struct trapframe *tf = pcb->pcb_tf;
        struct switchframe *sf = (struct switchframe *)tf - 1;
 
-       sf->sf_spl = 0;         /* always equivalent to spl0() */
        sf->sf_r4 = (u_int)func;
        sf->sf_r5 = (u_int)arg;
        sf->sf_pc = (u_int)proc_trampoline;
diff -r 3d53dfb4a5ed -r bb7f5ef34b31 sys/arch/arm/include/arm32/frame.h
--- a/sys/arch/arm/include/arm32/frame.h        Thu Oct 23 08:30:21 2003 +0000
+++ b/sys/arch/arm/include/arm32/frame.h        Thu Oct 23 08:59:10 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: frame.h,v 1.5 2002/10/19 00:10:54 bjh21 Exp $  */
+/*     $NetBSD: frame.h,v 1.6 2003/10/23 08:59:10 scw Exp $    */
 
 /*
  * Copyright (c) 1994-1997 Mark Brinicombe.
@@ -83,7 +83,6 @@
  */
 
 struct switchframe {
-       int     sf_spl;
        u_int   sf_r4;
        u_int   sf_r5;
        u_int   sf_r6;



Home | Main Index | Thread Index | Old Index