diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2007-10-10 15:53:54 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2007-10-10 15:53:54 +0000 |
commit | e51062c8cca21a333603b567563e3b84f74ddac0 (patch) | |
tree | dccf12b7d5ef806260203fe60b2bcaf94260c651 /sys/arch/sparc64 | |
parent | 34c540de32da6090afdcdd6fee481f9a2df345fd (diff) |
Make context switching much more MI:
- Move the functionality of choosing a process from cpu_switch into
a much simpler function: cpu_switchto. Instead of having the locore
code walk the run queues, let the MI code choose the process we
want to run and only implement the context switching itself in MD
code.
- Let MD context switching run without worrying about spls or locks.
- Instead of having the idle loop implemented with special contexts
in MD code, implement one idle proc for each cpu. make the idle
loop MI with MD hooks.
- Change the proc lists from the old style vax queues to TAILQs.
- Change the sleep queue from vax queues to TAILQs. This makes
wakeup() go from O(n^2) to O(n)
there will be some MD fallout, but it will be fixed shortly.
There's also a few cleanups to be done after this.
deraadt@, kettenis@ ok
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r-- | sys/arch/sparc64/conf/files.sparc64 | 3 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/locore.s | 382 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/vm_machdep.c | 10 |
3 files changed, 38 insertions, 357 deletions
diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64 index f3463fa8aa8..c9150465f13 100644 --- a/sys/arch/sparc64/conf/files.sparc64 +++ b/sys/arch/sparc64/conf/files.sparc64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.sparc64,v 1.89 2007/09/10 21:33:16 kettenis Exp $ +# $OpenBSD: files.sparc64,v 1.90 2007/10/10 15:53:53 art Exp $ # $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $ # maxpartitions must be first item in files.${ARCH} @@ -243,7 +243,6 @@ file arch/sparc64/sparc64/ipifuncs.c multiprocessor file arch/sparc64/sparc64/kgdb_machdep.c kgdb # sparc64/sparc64/locore.s is handled specially in the makefile, # because it must come first in the "ld" command line. -file arch/sparc64/sparc64/locore2.c file arch/sparc64/sparc64/machdep.c file arch/sparc64/sparc64/mem.c file arch/sparc64/sparc64/mutex.S diff --git a/sys/arch/sparc64/sparc64/locore.s b/sys/arch/sparc64/sparc64/locore.s index 07767d70bc5..2456810258e 100644 --- a/sys/arch/sparc64/sparc64/locore.s +++ b/sys/arch/sparc64/sparc64/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.83 2007/09/30 21:34:20 kettenis Exp $ */ +/* $OpenBSD: locore.s,v 1.84 2007/10/10 15:53:53 art Exp $ */ /* $NetBSD: locore.s,v 1.137 2001/08/13 06:10:10 jdolecek Exp $ */ /* @@ -5573,350 +5573,39 @@ Lcopyfault: retl mov EFAULT, %o0 - - .data - _ALIGN -/* - * Switch statistics (for later tweaking): - * nswitchdiff = p1 => p2 (i.e., chose different process) - * nswitchexit = number of calls to switchexit() - * _cnt.v_swtch = total calls to swtch+swtchexit - */ - .comm _C_LABEL(nswitchdiff), 4 - .comm _C_LABEL(nswitchexit), 4 - .text -/* - * REGISTER USAGE IN cpu_switch AND switchexit: - * This is split into two phases, more or less - * `before we locate a new proc' and `after'. - * Some values are the same in both phases. - * Note that the %o0-registers are not preserved across - * the psr change when entering a new process, since this - * usually changes the CWP field (hence heavy usage of %g's). - * - * %l1 = <free>; newpcb - * %l2 = %hi(_whichqs); newpsr - * %l3 = p - * %l4 = lastproc - * %l5 = oldpsr (excluding ipl bits) - * %l6 = %hi(cpcb) - * %l7 = %hi(curproc) - * %o0 = tmp 1 - * %o1 = tmp 2 - * %o2 = tmp 3 - * %o3 = tmp 4; whichqs; vm - * %o4 = tmp 4; which; sswap - * %o5 = tmp 5; q; <free> - */ - -/* - * switchexit is called only from cpu_exit() before the current process - * has freed its vmspace and kernel stack; we must schedule them to be - * freed. (curproc is already NULL.) - * - * We lay the process to rest by changing to the `idle' kernel stack, - * and note that the `last loaded process' is nonexistent. - */ -ENTRY(switchexit) - /* - * Since we're exiting we don't need to save locals or ins, so - * we won't need the next instruction. - */ -! save %sp, -CC64FSZ, %sp - flushw ! We don't have anything else to run, so why not -#ifdef DEBUG - save %sp, -CC64FSZ, %sp - flushw - restore -#endif /* DEBUG */ - wrpr %g0, PSTATE_KERN, %pstate ! Make sure we're on the right globals - mov %o0, %l2 ! save proc arg for exit2() call XXXXX - - /* - * Change pcb to idle u. area, i.e., set %sp to top of stack - * and %psr to PSR_S|PSR_ET, and set cpcb to point to _idle_u. - * Once we have left the old stack, we can call kmem_free to - * destroy it. Call it any sooner and the register windows - * go bye-bye. - */ - set _C_LABEL(idle_u), %l1 - sethi %hi(CPCB), %l6 -#if 0 - /* Get rid of the stack */ - rdpr %ver, %o0 - wrpr %g0, 0, %canrestore ! Fixup window state regs - and %o0, 0x0f, %o0 - wrpr %g0, 0, %otherwin - wrpr %g0, %o0, %cleanwin ! kernel don't care, but user does - dec 1, %o0 ! What happens if we don't subtract 2? - wrpr %g0, %o0, %cansave - flushw ! DEBUG -#endif /* 0 */ - - stx %l1, [%l6 + %lo(CPCB)] ! cpcb = &idle_u - set _C_LABEL(idle_u) + USPACE - CC64FSZ, %o0 ! set new %sp - sub %o0, BIAS, %sp ! Maybe this should be a save? - wrpr %g0, 0, %canrestore - wrpr %g0, 0, %otherwin - rdpr %ver, %l7 - and %l7, CWP, %l7 - wrpr %l7, 0, %cleanwin - dec 1, %l7 ! NWINDOWS-1-1 - wrpr %l7, %cansave - clr %fp ! End of stack. -#ifdef DEBUG - flushw ! DEBUG - set _C_LABEL(idle_u), %l6 - SET_SP_REDZONE %l6, %l5 -#endif /* DEBUG */ - wrpr %g0, PSTATE_INTR, %pstate ! and then enable traps - call _C_LABEL(exit2) ! exit2(p) - mov %l2, %o0 - -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) - call _C_LABEL(sched_lock_idle) ! Acquire sched_lock -#endif /* defined(MULTIPROCESSOR) || defined(LOCKDEBUG) */ - wrpr %g0, PIL_SCHED, %pil ! Set splsched() - - /* - * Now fall through to `the last switch'. %g6 was set to - * %hi(cpcb), but may have been clobbered in kmem_free, - * so all the registers described below will be set here. - * - * Since the process has exited we can blow its context - * out of the MMUs now to free up those TLB entries rather - * than have more useful ones replaced. - * - * REGISTER USAGE AT THIS POINT: - * %l2 = %hi(_whichqs) - * %l4 = lastproc - * %l5 = oldpsr (excluding ipl bits) - * %l6 = %hi(cpcb) - * %l7 = %hi(curproc) - * %o0 = tmp 1 - * %o1 = tmp 2 - * %o3 = whichqs - */ - - INCR _C_LABEL(nswitchexit) ! nswitchexit++; - INCR _C_LABEL(uvmexp)+V_SWTCH ! cnt.v_switch++; - - mov CTX_SECONDARY, %o0 - sethi %hi(_C_LABEL(whichqs)), %l2 - sethi %hi(CPCB), %l6 - sethi %hi(CURPROC), %l7 - ldxa [%o0] ASI_DMMU, %l1 ! Don't demap the kernel - ldx [%l6 + %lo(CPCB)], %l5 - clr %l4 ! lastproc = NULL; - brz,pn %l1, 1f - set DEMAP_CTX_SECONDARY, %l1 ! Demap secondary context - stxa %g1, [%l1] ASI_DMMU_DEMAP - stxa %g1, [%l1] ASI_IMMU_DEMAP - membar #Sync -1: - stxa %g0, [%o0] ASI_DMMU ! Clear out our context - membar #Sync - /* FALLTHROUGH */ - -/* - * When no processes are on the runq, switch - * idles here waiting for something to come ready. - * The registers are set up as noted above. - */ - .globl idle -idle: -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) - call _C_LABEL(sched_unlock_idle) ! Release sched_lock -#endif /* defined(MULTIPROCESSOR) || defined(LOCKDEBUG) */ - stx %g0, [%l7 + %lo(CURPROC)] ! curproc = NULL; -1: ! spin reading _whichqs until nonzero - wrpr %g0, PSTATE_INTR, %pstate ! Make sure interrupts are enabled - wrpr %g0, 0, %pil ! (void) spl0(); - ld [%l2 + %lo(_C_LABEL(whichqs))], %o3 - brnz,pt %o3, notidle ! Something to run - nop -#ifdef UVM_PAGE_IDLE_ZERO - ! Check uvm.page_idle_zero - sethi %hi(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO), %o3 - ld [%o3 + %lo(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO)], %o3 - brz,pn %o3, 1b - nop - - ! zero some pages - call _C_LABEL(uvm_pageidlezero) - nop -#endif /* UVM_PAGE_IDLE_ZERO */ - ba,a,pt %xcc, 1b - nop ! spitfire bug -notidle: - wrpr %g0, PIL_SCHED, %pil ! (void) splhigh(); -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) - call _C_LABEL(sched_lock_idle) ! Grab sched_lock - add %o7, (Lsw_scan-.-4), %o7 ! Return to Lsw_scan directly -#endif /* defined(MULTIPROCESSOR) || defined(LOCKDEBUG) */ - ba,a,pt %xcc, Lsw_scan - nop ! spitfire bug - -Lsw_panic_rq: - sethi %hi(1f), %o0 - call _C_LABEL(panic) - or %lo(1f), %o0, %o0 Lsw_panic_wchan: - sethi %hi(2f), %o0 - call _C_LABEL(panic) - or %lo(2f), %o0, %o0 + sethi %hi(1f), %o0 + call _C_LABEL(panic) + or %lo(1f), %o0, %o0 Lsw_panic_srun: - sethi %hi(3f), %o0 - call _C_LABEL(panic) - or %lo(3f), %o0, %o0 - .data -1: .asciz "switch rq" -2: .asciz "switch wchan" -3: .asciz "switch SRUN" -idlemsg: .asciz "idle %x %x %x %x" -idlemsg1: .asciz " %x %x %x\r\n" - _ALIGN + sethi %hi(2f), %o0 + call _C_LABEL(panic) + or %lo(2f), %o0, %o0 + .data +1: .asciz "switch wchan" +2: .asciz "switch SRUN" + .text /* - * cpu_switch() picks a process to run and runs it, saving the current - * one away. On the assumption that (since most workstations are - * single user machines) the chances are quite good that the new - * process will turn out to be the current process, we defer saving - * it here until we have found someone to load. If that someone - * is the current process we avoid both store and load. + * cpu_switchto(struct proc *old, struct proc *new) * - * cpu_switch() is always entered at splstatclock or splhigh. - * - * IT MIGHT BE WORTH SAVING BEFORE ENTERING idle TO AVOID HAVING TO - * SAVE LATER WHEN SOMEONE ELSE IS READY ... MUST MEASURE! - * - * Apparently cpu_switch() is called with curproc as the first argument, - * but no port seems to make use of that parameter. + * Save the context of "old" and switch to "new". */ - .globl _C_LABEL(time) -ENTRY(cpu_switch) +ENTRY(cpu_switchto) save %sp, -CC64FSZ, %sp - /* - * REGISTER USAGE AT THIS POINT: - * %l1 = tmp 0 - * %l2 = %hi(_C_LABEL(whichqs)) - * %l3 = p - * %l4 = lastproc - * %l5 = cpcb - * %l6 = %hi(CPCB) - * %l7 = %hi(CURPROC) - * %o0 = tmp 1 - * %o1 = tmp 2 - * %o2 = tmp 3 - * %o3 = tmp 4, then at Lsw_scan, whichqs - * %o4 = tmp 5, then at Lsw_scan, which - * %o5 = tmp 6, then at Lsw_scan, q - */ -#ifdef DEBUG - set swdebug, %o1 - ld [%o1], %o1 - brz,pt %o1, 2f - set 1f, %o0 - call printf - nop - .data -1: .asciz "s" - _ALIGN - .globl swdebug -swdebug: .word 0 - .text -2: -#endif /* DEBUG */ flushw ! We don't have anything else to run, so why not flush -#ifdef DEBUG - save %sp, -CC64FSZ, %sp - flushw - restore -#endif /* DEBUG */ rdpr %pstate, %o1 ! oldpstate = %pstate; wrpr %g0, PSTATE_INTR, %pstate ! make sure we're on normal globals + + mov %i0, %l4 ! oldproc + mov %i1, %l3 ! newproc + sethi %hi(CPCB), %l6 - sethi %hi(_C_LABEL(whichqs)), %l2 ! set up addr regs ldx [%l6 + %lo(CPCB)], %l5 - sethi %hi(CURPROC), %l7 + sethi %hi(CURPROC), %l7 stx %o7, [%l5 + PCB_PC] ! cpcb->pcb_pc = pc; - ldx [%l7 + %lo(CURPROC)], %l4 ! lastproc = curproc; sth %o1, [%l5 + PCB_PSTATE] ! cpcb->pcb_pstate = oldpstate; - stx %g0, [%l7 + %lo(CURPROC)] ! curproc = NULL; - -Lsw_scan: - ld [%l2 + %lo(_C_LABEL(whichqs))], %o3 - -#ifndef POPC - .globl _C_LABEL(__ffstab) - /* - * Optimized inline expansion of `which = ffs(whichqs) - 1'; - * branches to idle if ffs(whichqs) was 0. - */ - set _C_LABEL(__ffstab), %o2 - andcc %o3, 0xff, %o1 ! byte 0 zero? - bz,a,pn %icc, 1f ! yes, try byte 1 - srl %o3, 8, %o0 - ba,pt %icc, 2f ! ffs = ffstab[byte0]; which = ffs - 1; - ldsb [%o2 + %o1], %o0 -1: andcc %o0, 0xff, %o1 ! byte 1 zero? - bz,a,pn %icc, 1f ! yes, try byte 2 - srl %o0, 8, %o0 - ldsb [%o2 + %o1], %o0 ! which = ffstab[byte1] + 7; - ba,pt %icc, 3f - add %o0, 7, %o4 -1: andcc %o0, 0xff, %o1 ! byte 2 zero? - bz,a,pn %icc, 1f ! yes, try byte 3 - srl %o0, 8, %o0 - ldsb [%o2 + %o1], %o0 ! which = ffstab[byte2] + 15; - ba,pt %icc, 3f - add %o0, 15, %o4 -1: ldsb [%o2 + %o0], %o0 ! ffs = ffstab[byte3] + 24 - addcc %o0, 24, %o0 ! (note that ffstab[0] == -24) - bz,pn %icc, idle ! if answer was 0, go idle -! XXX check no delay slot -2: sub %o0, 1, %o4 -3: /* end optimized inline expansion */ - -#else /* POPC */ - /* - * Optimized inline expansion of `which = ffs(whichqs) - 1'; - * branches to idle if ffs(whichqs) was 0. - * - * This version uses popc. - * - * XXXX spitfires and blackbirds don't implement popc. - * - */ - brz,pn %o3, idle ! Don't bother if queues are empty - neg %o3, %o1 ! %o1 = -zz - xnor %o3, %o1, %o2 ! %o2 = zz ^ ~ -zz - popc %o2, %o4 ! which = popc(whichqs) - dec %o4 ! which = ffs(whichqs) - 1 - -#endif /* POPC */ - /* - * We found a nonempty run queue. Take its first process. - */ - set _C_LABEL(qs), %o5 ! q = &qs[which]; - sll %o4, 3+1, %o0 - add %o0, %o5, %o5 - ldx [%o5], %l3 ! p = q->ph_link; - cmp %l3, %o5 ! if (p == q) - be,pn %icc, Lsw_panic_rq ! panic("switch rq"); -! XXX check no delay slot - ldx [%l3], %o0 ! tmp0 = p->p_forw; - stx %o0, [%o5] ! q->ph_link = tmp0; - stx %o5, [%o0 + 8] ! tmp0->p_back = q; - cmp %o0, %o5 ! if (tmp0 == q) - bne 1f -! XXX check no delay slot - mov 1, %o1 ! whichqs &= ~(1 << which); - sll %o1, %o4, %o1 - andn %o3, %o1, %o3 - st %o3, [%l2 + %lo(_C_LABEL(whichqs))] -1: /* * PHASE TWO: NEW REGISTER USAGE: * %l1 = newpcb @@ -5945,7 +5634,6 @@ Lsw_scan: /* * Committed to running process p. - * It may be the same as the one we were running before. */ #if defined(MULTIPROCESSOR) /* @@ -5958,19 +5646,7 @@ Lsw_scan: sethi %hi(CPUINFO_VA+CI_WANT_RESCHED), %o0 st %g0, [%o0 + %lo(CPUINFO_VA+CI_WANT_RESCHED)] ! want_resched = 0; ldx [%l3 + P_ADDR], %l1 ! newpcb = p->p_addr; - stx %g0, [%l3 + 8] ! p->p_back = NULL; -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) - /* - * Done mucking with the run queues, release the - * scheduler lock, but keep interrupts out. - */ - call _C_LABEL(sched_unlock_idle) -#endif /* defined(MULTIPROCESSOR) || defined(LOCKDEBUG) */ - stx %l4, [%l7 + %lo(CURPROC)] ! restore old proc so we can save it - - cmp %l3, %l4 ! p == lastproc? - be,pt %xcc, Lsw_sameproc ! yes, go return 0 - nop + stx %l4, [%l7 + %lo(CURPROC)] ! restore old proc so we can save it /* * Not the old process. Save the old process, if any; @@ -5980,7 +5656,6 @@ Lsw_scan: brz,pn %l4, Lsw_load ! if no old process, go load wrpr %g0, PSTATE_KERN, %pstate - INCR _C_LABEL(nswitchdiff) ! clobbers %o0,%o1,%o2 wb1: flushw ! save all register windows except this one stx %i7, [%l5 + PCB_PC] ! Save rpc @@ -6060,11 +5735,6 @@ Lsw_havectx: membar #Sync ! Maybe we should use flush here? flush %sp -Lsw_sameproc: - /* - * We are resuming the process that was running at the - * call to switch(). Just set psr ipl and return. - */ ! wrpr %g0, 0, %cleanwin ! DEBUG clr %g4 ! This needs to point to the base of the data segment wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore default ASI @@ -6072,6 +5742,18 @@ Lsw_sameproc: ret restore +ENTRY(cpu_idle_enter) + retl + nop + +ENTRY(cpu_idle_cycle) + retl + nop + +ENTRY(cpu_idle_leave) + retl + nop + /* * Snapshot the current process so that stack frames are up to date. * Only used just before a crash dump. diff --git a/sys/arch/sparc64/sparc64/vm_machdep.c b/sys/arch/sparc64/sparc64/vm_machdep.c index 5d46c9eb715..88ba247878a 100644 --- a/sys/arch/sparc64/sparc64/vm_machdep.c +++ b/sys/arch/sparc64/sparc64/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.15 2007/06/20 17:29:36 miod Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.16 2007/10/10 15:53:53 art Exp $ */ /* $NetBSD: vm_machdep.c,v 1.38 2001/06/30 00:02:20 eeh Exp $ */ /* @@ -316,8 +316,7 @@ cpu_fork(p1, p2, stack, stacksize, func, arg) * run. */ void -cpu_exit(p) - struct proc *p; +cpu_exit(struct proc *p) { register struct fpstate64 *fs; @@ -328,8 +327,9 @@ cpu_exit(p) } free((void *)fs, M_SUBPROC); } - switchexit(p); - /* NOTREACHED */ + + pmap_deactivate(p); + sched_exit(p); } /* |