Improve IPI handling:

- make IPI takes two arguments.
- add IPI event counters per-CPU.
- implement IPI functions which were missing or broken.
- insert DELAY while halting primary CPU in IPI handler.
This commit is contained in:
nakayama 2008-03-14 15:38:00 +00:00
parent 607ead0ef4
commit ead4e6f7b9
6 changed files with 363 additions and 111 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.75 2008/03/02 15:28:26 nakayama Exp $ */
/* $NetBSD: cpu.h,v 1.76 2008/03/14 15:38:00 nakayama Exp $ */
/*
* Copyright (c) 1992, 1993
@ -128,7 +128,12 @@ struct cpu_info {
/* Interrupts */
struct intrhand *ci_intrpending[16];
struct intrhand *ci_intrlev0;
/* Event counters */
struct evcnt ci_tick_evcnt;
#ifdef MULTIPROCESSOR
struct evcnt ci_ipi_evcnt[IPI_EVCNT_NUM];
#endif
int ci_flags;
int ci_want_ast;
@ -238,9 +243,9 @@ void cpu_boot_secondary_processors(void);
*/
typedef void (* ipifunc_t)(void *);
void sparc64_multicast_ipi (sparc64_cpuset_t, ipifunc_t, uint64_t);
void sparc64_broadcast_ipi (ipifunc_t, uint64_t);
void sparc64_send_ipi (int, ipifunc_t, uint64_t);
void sparc64_multicast_ipi(sparc64_cpuset_t, ipifunc_t, uint64_t, uint64_t);
void sparc64_broadcast_ipi(ipifunc_t, uint64_t, uint64_t);
void sparc64_send_ipi(int, ipifunc_t, uint64_t, uint64_t);
#endif
/*
@ -320,10 +325,10 @@ int isbad(struct dkbad *bt, int, int, int);
void * reserve_dumppages(void *);
/* clock.c */
struct timeval;
int tickintr(void *); /* level 10 (tick) interrupt code */
int tickintr(void *); /* level 10/14 (tick) interrupt code */
int clockintr(void *); /* level 10 (clock) interrupt code */
int statintr(void *); /* level 14 (statclock) interrupt code */
void tickintr_establish(void);
void tickintr_establish(int, int (*)(void *));
/* locore.s */
struct fpstate64;
void savefpstate(struct fpstate64 *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.21 2008/03/02 22:01:38 martin Exp $ */
/* $NetBSD: intr.h,v 1.22 2008/03/14 15:38:00 nakayama Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -39,7 +39,9 @@
#ifndef _SPARC64_INTR_H_
#define _SPARC64_INTR_H_
#ifndef _LOCORE
#include <machine/cpuset.h>
#endif
/* XXX - arbitrary numbers; no interpretation is defined yet */
#define IPL_NONE 0 /* nothing */
@ -54,13 +56,17 @@
#define IPL_PAUSE 13 /* pause cpu */
#define IPL_FDSOFT PIL_FDSOFT /* floppy */
void save_and_clear_fpstate(struct lwp *);
#ifndef _LOCORE
void fpusave_lwp(struct lwp *, bool);
#endif /* _LOCORE */
#if defined(MULTIPROCESSOR)
#ifndef _LOCORE
void sparc64_ipi_init (void);
int sparc64_ipi_halt_thiscpu (void *);
int sparc64_ipi_pause_thiscpu (void *);
void sparc64_do_pause(void);
void sparc64_ipi_sync_tick (void *);
void sparc64_ipi_drop_fpstate (void *);
void sparc64_ipi_save_fpstate (void *);
void sparc64_ipi_nop (void *);
@ -69,6 +75,16 @@ void mp_pause_cpus (void);
void mp_resume_cpus (void);
int mp_cpu_is_paused (sparc64_cpuset_t);
void mp_resume_cpu(int);
#endif /* _LOCORE */
#define IPI_EVCNT_TLB_PTE 0
#define IPI_EVCNT_TLB_CTX 1
#define IPI_EVCNT_TLB_ALL 2
#define IPI_EVCNT_FPU_SYNCH 3
#define IPI_EVCNT_FPU_FLUSH 4
#define IPI_EVCNT_NUM 5
#define IPI_EVCNT_NAMES { "TLB pte IPI", "TLB ctx IPI", "TLB all IPI", \
"FPU synch IPI", "FPU flush IPI" }
#endif
#endif /* _SPARC64_INTR_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.c,v 1.69 2008/03/06 09:33:03 nakayama Exp $ */
/* $NetBSD: cpu.c,v 1.70 2008/03/14 15:38:00 nakayama Exp $ */
/*
* Copyright (c) 1996
@ -52,7 +52,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.69 2008/03/06 09:33:03 nakayama Exp $");
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.70 2008/03/14 15:38:00 nakayama Exp $");
#include "opt_multiprocessor.h"
@ -90,6 +90,10 @@ char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */
char cpu_model[100]; /* machine model (primary CPU) */
extern char machine_model[];
#ifdef MULTIPROCESSOR
static const char *ipi_evcnt_names[IPI_EVCNT_NUM] = IPI_EVCNT_NAMES;
#endif
static void cpu_reset_fpustate(void);
/* The CPU configuration driver. */
@ -236,6 +240,9 @@ cpu_attach(struct device *parent, struct device *dev, void *aux)
mi_cpu_attach(ci);
ci->ci_cpcb = (struct pcb *)ci->ci_data.cpu_idlelwp->l_addr;
}
for (i = 0; i < IPI_EVCNT_NUM; ++i)
evcnt_attach_dynamic(&ci->ci_ipi_evcnt[i], EVCNT_TYPE_INTR,
NULL, dev->dv_xname, ipi_evcnt_names[i]);
#endif
evcnt_attach_dynamic(&ci->ci_tick_evcnt, EVCNT_TYPE_INTR, NULL,
dev->dv_xname, "timer");
@ -392,6 +399,12 @@ cpu_boot_secondary_processors()
if (!CPUSET_HAS(cpus_active, ci->ci_index))
printf("cpu%d: startup failed\n", ci->ci_cpuid);
}
/*
* Sync %tick register with primary CPU.
* No need this actually since we can use counter-timer as timecounter.
*/
sparc64_broadcast_ipi(sparc64_ipi_sync_tick, tick() + 100, 0);
}
void
@ -408,7 +421,7 @@ cpu_hatch()
cpu_reset_fpustate();
curlwp = curcpu()->ci_data.cpu_idlelwp;
membar_sync();
tickintr_establish();
tickintr_establish(14, statintr);
spl0();
}
#endif /* MULTIPROCESSOR */

View File

@ -1,4 +1,4 @@
# $NetBSD: genassym.cf,v 1.53 2008/03/02 15:28:26 nakayama Exp $
# $NetBSD: genassym.cf,v 1.54 2008/03/14 15:38:00 nakayama Exp $
#
# Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -178,6 +178,9 @@ define CI_INTRLEV0 offsetof(struct cpu_info, ci_intrlev0)
define CI_CTXBUSY offsetof(struct cpu_info, ci_ctxbusy)
define CI_TSB_DMMU offsetof(struct cpu_info, ci_tsb_dmmu)
define CI_TSB_IMMU offsetof(struct cpu_info, ci_tsb_immu)
ifdef MULTIPROCESSOR
define CI_IPIEVC offsetof(struct cpu_info, ci_ipi_evcnt[0].ev_count)
endif
# CPU boot arguments structure
define CBA_NODE offsetof(struct cpu_bootargs, cb_node)

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipifuncs.c,v 1.14 2008/03/02 22:01:38 martin Exp $ */
/* $NetBSD: ipifuncs.c,v 1.15 2008/03/14 15:38:00 nakayama Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.14 2008/03/02 22:01:38 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.15 2008/03/14 15:38:00 nakayama Exp $");
#include "opt_ddb.h"
@ -47,7 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.14 2008/03/02 22:01:38 martin Exp $")
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/pte.h>
#include <machine/pmap.h>
#include <machine/sparc64.h>
#define SPARC64_IPI_RETRIES 10000
@ -89,6 +89,8 @@ sparc64_ipi_halt_thiscpu(void *arg)
printf("cpu%d: shutting down\n", cpu_number());
CPUSET_ADD(cpus_halted, cpu_number());
if (CPU_IS_PRIMARY(curcpu()))
DELAY(1000000); /* XXX - wait for interrupter's halt */
prom_stopself();
return(1);
@ -164,7 +166,8 @@ sparc64_ipi_init()
* Send an IPI to all in the list but ourselves.
*/
void
sparc64_multicast_ipi(sparc64_cpuset_t cpuset, ipifunc_t func, uint64_t arg1)
sparc64_multicast_ipi(sparc64_cpuset_t cpuset, ipifunc_t func, uint64_t arg1,
uint64_t arg2)
{
struct cpu_info *ci;
@ -175,7 +178,7 @@ sparc64_multicast_ipi(sparc64_cpuset_t cpuset, ipifunc_t func, uint64_t arg1)
for (ci = cpus; ci != NULL; ci = ci->ci_next) {
if (CPUSET_HAS(cpuset, ci->ci_index)) {
CPUSET_DEL(cpuset, ci->ci_index);
sparc64_send_ipi(ci->ci_cpuid, func, arg1);
sparc64_send_ipi(ci->ci_cpuid, func, arg1, arg2);
}
}
}
@ -184,18 +187,18 @@ sparc64_multicast_ipi(sparc64_cpuset_t cpuset, ipifunc_t func, uint64_t arg1)
* Broadcast an IPI to all but ourselves.
*/
void
sparc64_broadcast_ipi(ipifunc_t func, uint64_t arg1)
sparc64_broadcast_ipi(ipifunc_t func, uint64_t arg1, uint64_t arg2)
{
sparc64_multicast_ipi(CPUSET_EXCEPT(cpus_active, cpu_number()), func,
arg1);
arg1, arg2);
}
/*
* Send an interprocessor interrupt.
*/
void
sparc64_send_ipi(int upaid, ipifunc_t func, uint64_t arg1)
sparc64_send_ipi(int upaid, ipifunc_t func, uint64_t arg1, uint64_t arg2)
{
int i, ik;
uint64_t intr_func;
@ -209,11 +212,14 @@ sparc64_send_ipi(int upaid, ipifunc_t func, uint64_t arg1)
for (i = 0; i < SPARC64_IPI_RETRIES; i++) {
int s = intr_disable();
stxa(IDDR_0H, ASI_INTERRUPT_DISPATCH, 0);
stxa(IDDR_1H, ASI_INTERRUPT_DISPATCH, intr_func);
stxa(IDDR_2H, ASI_INTERRUPT_DISPATCH, arg1);
stxa(IDDR_0H, ASI_INTERRUPT_DISPATCH, intr_func);
stxa(IDDR_1H, ASI_INTERRUPT_DISPATCH, arg1);
stxa(IDDR_2H, ASI_INTERRUPT_DISPATCH, arg2);
stxa(IDCR(upaid), ASI_INTERRUPT_DISPATCH, 0);
membar_sync();
/* Workaround for SpitFire erratum #54, from FreeBSD */
(void)ldxa(P_DCR_0, ASI_DATAPATH_READ);
membar_sync();
for (ik = 0; ik < 1000000; ik++) {
if (ldxa(0, ASR_IDSR) & IDSR_BUSY)
@ -268,7 +274,7 @@ mp_halt_cpus()
if (CPUSET_EMPTY(cpuset))
return;
sparc64_multicast_ipi(cpuset, sparc64_ipi_halt, 0);
sparc64_multicast_ipi(cpuset, sparc64_ipi_halt, 0, 0);
if (sparc64_ipi_wait(&cpus_halted, cpumask))
sparc64_ipi_error("halt", cpumask, cpus_halted);
}
@ -287,7 +293,7 @@ mp_pause_cpus()
if (CPUSET_EMPTY(cpuset))
return;
sparc64_multicast_ipi(cpuset, sparc64_ipi_pause, 0);
sparc64_multicast_ipi(cpuset, sparc64_ipi_pause, 0, 0);
if (sparc64_ipi_wait(&cpus_paused, cpuset))
sparc64_ipi_error("pause", cpus_paused, cpuset);
}
@ -331,26 +337,72 @@ mp_cpu_is_paused(sparc64_cpuset_t cpunum)
* Flush pte on all active processors.
*/
void
smp_tlb_flush_pte(vaddr_t va, int ctx)
smp_tlb_flush_pte(vaddr_t va, pmap_t pm)
{
sparc64_cpuset_t cpuset;
struct cpu_info *ci;
int ctx;
bool kpm = (pm == pmap_kernel());
/* Flush our own TLB */
sp_tlb_flush_pte(va, ctx);
ctx = pm->pm_ctx[cpu_number()];
KASSERT(ctx >= 0);
if (kpm || ctx > 0)
sp_tlb_flush_pte(va, ctx);
CPUSET_ASSIGN(cpuset, cpus_active);
CPUSET_DEL(cpuset, cpu_number());
if (CPUSET_EMPTY(cpuset))
return;
/* Flush others */
/* sparc64_broadcast_ipi(sparc64_ipi_flush_ctx, ctx); */
for (ci = cpus; ci != NULL; ci = ci->ci_next) {
if (CPUSET_HAS(cpuset, ci->ci_index)) {
CPUSET_DEL(cpuset, ci->ci_index);
ctx = pm->pm_ctx[ci->ci_index];
KASSERT(ctx >= 0);
if (!kpm && ctx == 0)
continue;
sparc64_send_ipi(ci->ci_cpuid, sparc64_ipi_flush_pte,
va, ctx);
}
}
}
/*
* Flush context on all active processors.
*/
void
smp_tlb_flush_ctx(int ctx)
smp_tlb_flush_ctx(pmap_t pm)
{
sparc64_cpuset_t cpuset;
struct cpu_info *ci;
int ctx;
bool kpm = (pm == pmap_kernel());
/* Flush our own TLB */
sp_tlb_flush_ctx(ctx);
ctx = pm->pm_ctx[cpu_number()];
KASSERT(ctx >= 0);
if (kpm || ctx > 0)
sp_tlb_flush_ctx(ctx);
CPUSET_ASSIGN(cpuset, cpus_active);
CPUSET_DEL(cpuset, cpu_number());
if (CPUSET_EMPTY(cpuset))
return;
/* Flush others */
sparc64_broadcast_ipi(sparc64_ipi_flush_ctx, ctx);
for (ci = cpus; ci != NULL; ci = ci->ci_next) {
if (CPUSET_HAS(cpuset, ci->ci_index)) {
CPUSET_DEL(cpuset, ci->ci_index);
ctx = pm->pm_ctx[ci->ci_index];
KASSERT(ctx >= 0);
if (!kpm && ctx == 0)
continue;
sparc64_send_ipi(ci->ci_cpuid, sparc64_ipi_flush_ctx,
ctx, 0);
}
}
}
/*
@ -363,7 +415,7 @@ smp_tlb_flush_all()
sp_tlb_flush_all();
/* Flush others */
sparc64_broadcast_ipi(sparc64_ipi_flush_all, 0);
sparc64_broadcast_ipi(sparc64_ipi_flush_all, 0, 0);
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.s,v 1.269 2008/03/02 15:28:26 nakayama Exp $ */
/* $NetBSD: locore.s,v 1.270 2008/03/14 15:38:00 nakayama Exp $ */
/*
* Copyright (c) 1996-2002 Eduardo Horvath
@ -83,6 +83,7 @@
#include <machine/frame.h>
#include <machine/pte.h>
#include <machine/pmap.h>
#include <machine/intr.h>
#include <machine/asm.h>
#include <sys/syscall.h>
@ -3623,8 +3624,8 @@ interrupt_vector:
stw %g2, [%g1]
#endif
ldxa [%g0] ASI_IRSR, %g1
mov IRDR_0H, %g2
ldxa [%g2] ASI_IRDR, %g2 ! Get interrupt number
mov IRDR_0H, %g7
ldxa [%g7] ASI_IRDR, %g7 ! Get interrupt number
membar #Sync
#if KTR_COMPILE & KTR_INTR
@ -3633,32 +3634,33 @@ interrupt_vector:
rdpr %tl, %g5
stx %g5, [%g3 + KTR_PARM1]
stx %g1, [%g3 + KTR_PARM2]
stx %g2, [%g3 + KTR_PARM3]
stx %g7, [%g3 + KTR_PARM3]
12:
#endif
btst IRSR_BUSY, %g1
bz,pn %icc, 3f ! spurious interrupt
sllx %g2, PTRSHFT, %g5 ! Calculate entry number
sethi %hi(KERNBASE), %g1
brnz,pt %g2, Lsoftint_regular ! interrupt #0 is a fast cross-call
cmp %g2, MAXINTNUM
cmp %g7, %g1
bl,pt %xcc, Lsoftint_regular ! >= KERNBASE is a fast cross-call
cmp %g7, MAXINTNUM
mov IRDR_1H, %g1
ldxa [%g1] ASI_IRDR, %g1 ! Get IPI handler address
brz,pn %g1, ret_from_intr_vector
mov IRDR_2H, %g2
ldxa [%g2] ASI_IRDR, %g2 ! Get IPI handler argument
mov IRDR_1H, %g2
ldxa [%g2] ASI_IRDR, %g2 ! Get IPI handler argument 1
mov IRDR_2H, %g3
ldxa [%g3] ASI_IRDR, %g3 ! Get IPI handler argument 2
stxa %g0, [%g0] ASI_IRSR ! Ack IRQ
membar #Sync ! Should not be needed due to retry
jmpl %g1, %g0
jmpl %g7, %g0
nop
Lsoftint_regular:
stxa %g0, [%g0] ASI_IRSR ! Ack IRQ
membar #Sync ! Should not be needed due to retry
sllx %g7, PTRSHFT, %g5 ! Calculate entry number
sethi %hi(_C_LABEL(intrlev)), %g3
bgeu,pn %xcc, 3f
or %g3, %lo(_C_LABEL(intrlev)), %g3
@ -3704,16 +3706,16 @@ ret_from_intr_vector:
3:
#ifdef NOT_DEBUG
set _C_LABEL(intrdebug), %g7
ld [%g7], %g7
btst INTRDEBUG_SPUR, %g7
set _C_LABEL(intrdebug), %g6
ld [%g6], %g6
btst INTRDEBUG_SPUR, %g6
bz,pt %icc, 97f
nop
#endif
#if 1
STACKFRAME(-CC64FSZ) ! Get a clean register window
LOAD_ASCIZ(%o0, "interrupt_vector: spurious vector %lx at pil %d\r\n")
mov %g2, %o1
mov %g7, %o1
GLOBTOLOC
clr %g4
call prom_printf
@ -3756,13 +3758,42 @@ sparc64_ipi_pause_trap_point:
ba,a ret_from_intr_vector
nop
/*
* IPI handler to sync %tick register.
* void sparc64_ipi_sync_tick(void *);
*
* On entry:
* %g2 = %tick of master CPU
*/
ENTRY(sparc64_ipi_sync_tick)
rdpr %pstate, %g1
andn %g1, PSTATE_IE, %g7 ! disable interrupts
wrpr %g7, 0, %pstate
rdpr %tick, %g3 ! read old tick
rd TICK_CMPR, %g5
sub %g2, %g3, %g3 ! delta btw old and new
add %g5, %g3, %g5 ! add delta to TICK_CMPR
wr %g5, TICK_CMPR
wrpr %g2, 0, %tick ! write new tick
ba ret_from_intr_vector
wrpr %g1, %pstate ! restore interrupts
/*
* Increment IPI event counter, defined in machine/{cpu,intr}.h.
*/
#define IPIEVC_INC(n,r1,r2) \
sethi %hi(CPUINFO_VA+CI_IPIEVC+EVC_SIZE*n), r2; \
ldx [r2 + %lo(CPUINFO_VA+CI_IPIEVC+EVC_SIZE*n)], r1; \
inc r1; \
stx r1, [r2 + %lo(CPUINFO_VA+CI_IPIEVC+EVC_SIZE*n)]
/*
* IPI handler to flush single pte.
* void sparc64_ipi_flush_pte(void *);
*
* On Entry:
*
* %g2 - pointer to 'ipi_tlb_args' structure
* On entry:
* %g2 = vaddr_t va
* %g3 = int ctx
*/
ENTRY(sparc64_ipi_flush_pte)
#if KTR_COMPILE & KTR_PMAP
@ -3770,24 +3801,28 @@ ENTRY(sparc64_ipi_flush_pte)
%g1, %g3, %g4, 10, 11, 12)
12:
#endif
#if 0
! save %o0 - %o5
mov %o0, %g1
mov %o1, %g3
mov %o2, %g4
mov %o3, %g5
mov %o4, %g6
mov %o5, %g7
LDPTR [%g2 + ITA_VADDR], %o0
call sp_tlb_flush_pte
ld [%g2 + ITA_CTX], %o1
! restore %o0 - %o5
mov %g1, %o0
mov %g3, %o1
mov %g4, %o2
mov %g5, %o3
mov %g6, %o4
mov %g7, %o5
#ifdef SPITFIRE
mov CTX_SECONDARY, %g5
andn %g2, 0xfff, %g2 ! drop unused va bits
ldxa [%g5] ASI_DMMU, %g6 ! Save secondary context
sethi %hi(KERNBASE), %g7
membar #LoadStore
stxa %g3, [%g5] ASI_DMMU ! Insert context to demap
membar #Sync
or %g2, DEMAP_PAGE_SECONDARY, %g2 ! Demap page from secondary context only
stxa %g2, [%g2] ASI_DMMU_DEMAP ! Do the demap
stxa %g2, [%g2] ASI_IMMU_DEMAP ! to both TLBs
#ifdef _LP64
srl %g2, 0, %g2 ! and make sure it's both 32- and 64-bit entries
stxa %g2, [%g2] ASI_DMMU_DEMAP ! Do the demap
stxa %g2, [%g2] ASI_IMMU_DEMAP ! Do the demap
#endif
flush %g7
stxa %g6, [%g5] ASI_DMMU ! Restore secondary context
membar #Sync
IPIEVC_INC(IPI_EVCNT_TLB_PTE,%g2,%g3)
#else
! Not yet
#endif
ba,a ret_from_intr_vector
@ -3797,9 +3832,8 @@ ENTRY(sparc64_ipi_flush_pte)
* IPI handler to flush single context.
* void sparc64_ipi_flush_ctx(void *);
*
* On Entry:
*
* %g2 - pointer to 'ipi_tlb_args' structure
* On entry:
* %g2 = int ctx
*/
ENTRY(sparc64_ipi_flush_ctx)
#if KTR_COMPILE & KTR_PMAP
@ -3807,23 +3841,22 @@ ENTRY(sparc64_ipi_flush_ctx)
%g1, %g3, %g4, 10, 11, 12)
12:
#endif
#if 0
! save %o0 - %o5
mov %o0, %g1
mov %o1, %g3
mov %o2, %g4
mov %o3, %g5
mov %o4, %g6
mov %o5, %g7
call sp_tlb_flush_ctx
ld [%g2 + ITA_CTX], %o0
! restore %o0 - %o5
mov %g1, %o0
mov %g3, %o1
mov %g4, %o2
mov %g5, %o3
mov %g6, %o4
mov %g7, %o5
#ifdef SPITFIRE
mov CTX_SECONDARY, %g5
ldxa [%g5] ASI_DMMU, %g6 ! Save secondary context
sethi %hi(KERNBASE), %g7
membar #LoadStore
stxa %g2, [%g5] ASI_DMMU ! Insert context to demap
set DEMAP_CTX_SECONDARY, %g3
membar #Sync
stxa %g3, [%g3] ASI_DMMU_DEMAP ! Do the demap
stxa %g3, [%g3] ASI_IMMU_DEMAP ! Do the demap
flush %g7
stxa %g6, [%g5] ASI_DMMU ! Restore secondary context
membar #Sync
IPIEVC_INC(IPI_EVCNT_TLB_CTX,%g2,%g3)
#else
! Not yet
#endif
ba,a ret_from_intr_vector
@ -5355,7 +5388,8 @@ ENTRY(openfirmware_exit)
flushw ! Flush register windows
wrpr %g0, PIL_HIGH, %pil ! Disable interrupts
set romtba, %l5
sethi %hi(romtba), %l5
LDPTR [%l5 + %lo(romtba)], %l5
wrpr %l5, 0, %tba ! restore the ofw trap table
/* Arrange locked kernel stack as PROM stack */
@ -5368,8 +5402,8 @@ ENTRY(openfirmware_exit)
mov %l5, %sp
flushw
set romp, %l6
LDPTR [%l6], %l6
sethi %hi(romp), %l6
LDPTR [%l6 + %lo(romp)], %l6
mov CTX_PRIMARY, %l3 ! set context 0
stxa %g0, [%l3] ASI_DMMU
@ -5417,9 +5451,14 @@ ENTRY(sp_tlb_flush_pte)
2:
#endif
#ifdef SPITFIRE
#ifdef MULTIPROCESSOR
rdpr %pstate, %o3
andn %o3, PSTATE_IE, %o4 ! disable interrupts
wrpr %o4, 0, %pstate
#endif
mov CTX_SECONDARY, %o2
andn %o0, 0xfff, %o0 ! drop unused va bits
ldxa [%o2] ASI_DMMU, %g1 ! Save secondary context
ldxa [%o2] ASI_DMMU, %o5 ! Save secondary context
sethi %hi(KERNBASE), %o4
membar #LoadStore
stxa %o1, [%o2] ASI_DMMU ! Insert context to demap
@ -5427,14 +5466,20 @@ ENTRY(sp_tlb_flush_pte)
or %o0, DEMAP_PAGE_SECONDARY, %o0 ! Demap page from secondary context only
stxa %o0, [%o0] ASI_DMMU_DEMAP ! Do the demap
stxa %o0, [%o0] ASI_IMMU_DEMAP ! to both TLBs
#ifdef _LP64
srl %o0, 0, %o0 ! and make sure it's both 32- and 64-bit entries
stxa %o0, [%o0] ASI_DMMU_DEMAP ! Do the demap
stxa %o0, [%o0] ASI_IMMU_DEMAP ! Do the demap
#endif
flush %o4
stxa %g1, [%o2] ASI_DMMU ! Restore secondary context
stxa %o5, [%o2] ASI_DMMU ! Restore secondary context
membar #Sync
retl
#ifdef MULTIPROCESSOR
wrpr %o3, %pstate ! restore interrupts
#else
nop
#endif
#else
!!
!! Cheetahs do not support flushing the IMMU from secondary context
@ -5506,6 +5551,11 @@ ENTRY(sp_tlb_flush_ctx)
2:
#endif
#ifdef SPITFIRE
#ifdef MULTIPROCESSOR
rdpr %pstate, %o3
andn %o3, PSTATE_IE, %o4 ! disable interrupts
wrpr %o4, 0, %pstate
#endif
mov CTX_SECONDARY, %o2
ldxa [%o2] ASI_DMMU, %o1 ! Save secondary context
sethi %hi(KERNBASE), %o4
@ -5515,11 +5565,15 @@ ENTRY(sp_tlb_flush_ctx)
membar #Sync
stxa %o5, [%o5] ASI_DMMU_DEMAP ! Do the demap
stxa %o5, [%o5] ASI_IMMU_DEMAP ! Do the demap
membar #Sync
stxa %o1, [%o2] ASI_DMMU ! Restore secondary asi
flush %o4
stxa %o1, [%o2] ASI_DMMU ! Restore secondary context
membar #Sync
retl
#ifdef MULTIPROCESSOR
wrpr %o3, %pstate ! restore interrupts
#else
nop
#endif
#else
rdpr %tl, %o3
mov CTX_PRIMARY, %o2
@ -5554,7 +5608,6 @@ ENTRY(sp_tlb_flush_ctx)
.align 8
ENTRY(sp_tlb_flush_all)
#ifdef SPITFIRE
save %sp, -CC64FSZ, %sp
rdpr %pstate, %o3
andn %o3, PSTATE_IE, %o4 ! disable interrupts
wrpr %o4, 0, %pstate
@ -5616,11 +5669,8 @@ ENTRY(sp_tlb_flush_all)
sethi %hi(KERNBASE), %o4
membar #Sync
flush %o4
! retl
retl
wrpr %o3, %pstate
ret
restore
#else
WRITEME
#endif
@ -9459,23 +9509,136 @@ Lkcerr:
NOTREACHED
#ifdef MULTIPROCESSOR
/*
* IPI handler to store the current FPU state.
* void sparc64_ipi_save_fpstate(void *);
*/
ENTRY(sparc64_ipi_save_fpstate)
save %sp, -CC64FSZ, %sp
sethi %hi(FPLWP), %o0
LDPTR [%o0 + %lo(FPLWP)], %o0
call savefpstate
LDPTR [%o0 + L_FPSTATE], %o0
sethi %hi(FPLWP), %o0
STPTR %g0, [%o0 + %lo(FPLWP)] ! fplwp = NULL
ba ret_from_intr_vector
restore
mov CTX_SECONDARY, %g5
ldxa [%g5] ASI_DMMU, %g6
membar #LoadStore
stxa %g0, [%g5] ASI_DMMU
membar #Sync
sethi %hi(FPLWP), %g1
LDPTR [%g1 + %lo(FPLWP)], %g3
LDPTR [%g3 + L_FPSTATE], %g3
rdpr %pstate, %g2 ! enable FP before we begin
rd %fprs, %g5
wr %g0, FPRS_FEF, %fprs
or %g2, PSTATE_PEF, %g2
wrpr %g2, 0, %pstate
stx %fsr, [%g3 + FS_FSR] ! f->fs_fsr = getfsr();
rd %gsr, %g2 ! Save %gsr
st %g2, [%g3 + FS_GSR]
add %g3, FS_REGS, %g3
btst BLOCK_ALIGN, %g3 ! Needs to be re-executed
bnz,pn %icc, 3f ! Check alignment
st %g0, [%g3 + FS_QSIZE - FS_REGS] ! f->fs_qsize = 0;
btst FPRS_DL, %g5 ! Lower FPU clean?
bz,a,pt %icc, 1f ! Then skip it
add %g3, 128, %g3 ! Skip a block
membar #Sync
stda %f0, [%g3] ASI_BLK_S ! f->fs_f0 = etc;
inc BLOCK_SIZE, %g3
stda %f16, [%g3] ASI_BLK_S
inc BLOCK_SIZE, %g3
1:
btst FPRS_DU, %g5 ! Upper FPU clean?
bz,pt %icc, 2f ! Then skip it
nop
membar #Sync
stda %f32, [%g3] ASI_BLK_S
inc BLOCK_SIZE, %g3
stda %f48, [%g3] ASI_BLK_S
2:
membar #Sync ! Finish operation so we can
wr %g0, FPRS_FEF, %fprs ! Mark FPU clean
mov CTX_SECONDARY, %g5
STPTR %g0, [%g1 + %lo(FPLWP)] ! fplwp = NULL
stxa %g6, [%g5] ASI_DMMU
membar #Sync
IPIEVC_INC(IPI_EVCNT_FPU_SYNCH,%g2,%g3)
ba,a ret_from_intr_vector
nop
3:
#ifdef DIAGONSTIC
btst 7, %g3 ! 32-bit aligned!?!?
bnz,pn %icc, 6f
#endif
btst FPRS_DL, %g5 ! Lower FPU clean?
bz,a,pt %icc, 4f ! Then skip it
add %g3, 128, %g3
membar #Sync
std %f0, [%g3 + FS_REGS + (4*0)] ! f->fs_f0 = etc;
std %f2, [%g3 + FS_REGS + (4*2)]
std %f4, [%g3 + FS_REGS + (4*4)]
std %f6, [%g3 + FS_REGS + (4*6)]
std %f8, [%g3 + FS_REGS + (4*8)]
std %f10, [%g3 + FS_REGS + (4*10)]
std %f12, [%g3 + FS_REGS + (4*12)]
std %f14, [%g3 + FS_REGS + (4*14)]
std %f16, [%g3 + FS_REGS + (4*16)]
std %f18, [%g3 + FS_REGS + (4*18)]
std %f20, [%g3 + FS_REGS + (4*20)]
std %f22, [%g3 + FS_REGS + (4*22)]
std %f24, [%g3 + FS_REGS + (4*24)]
std %f26, [%g3 + FS_REGS + (4*26)]
std %f28, [%g3 + FS_REGS + (4*28)]
std %f30, [%g3 + FS_REGS + (4*30)]
4:
btst FPRS_DU, %g5 ! Upper FPU clean?
bz,pt %icc, 2b ! Then skip it
nop
membar #Sync
std %f32, [%g3 + FS_REGS + (4*32)]
std %f34, [%g3 + FS_REGS + (4*34)]
std %f36, [%g3 + FS_REGS + (4*36)]
std %f38, [%g3 + FS_REGS + (4*38)]
std %f40, [%g3 + FS_REGS + (4*40)]
std %f42, [%g3 + FS_REGS + (4*42)]
std %f44, [%g3 + FS_REGS + (4*44)]
std %f46, [%g3 + FS_REGS + (4*46)]
std %f48, [%g3 + FS_REGS + (4*48)]
std %f50, [%g3 + FS_REGS + (4*50)]
std %f52, [%g3 + FS_REGS + (4*52)]
std %f54, [%g3 + FS_REGS + (4*54)]
std %f56, [%g3 + FS_REGS + (4*56)]
std %f58, [%g3 + FS_REGS + (4*58)]
std %f60, [%g3 + FS_REGS + (4*60)]
ba 2b
std %f62, [%g3 + FS_REGS + (4*62)]
!!
!! Damn thing is *NOT* aligned on a 64-byte boundary
!!
6:
wr %g0, FPRS_FEF, %fprs
ta 1
nop
ba,a ret_from_intr_vector
nop
/*
* IPI handler to drop the current FPU state.
* void sparc64_ipi_drop_fpstate(void *);
*/
ENTRY(sparc64_ipi_drop_fpstate)
rdpr %pstate, %g1
wr %g0, FPRS_FEF, %fprs
or %g1, PSTATE_PEF, %g1
wrpr %g1, 0, %pstate
sethi %hi(FPLWP), %g1
IPIEVC_INC(IPI_EVCNT_FPU_FLUSH,%g2,%g3)
ba ret_from_intr_vector
STPTR %g0, [%g1 + %lo(FPLWP)] ! fplwp = NULL
#endif