/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Modified by Fujitsu Limited to provide support
 * for Solaris on Fujitsu's hardware platforms
 */

#ifndef	_SYS_MACHTHREAD_H
#define	_SYS_MACHTHREAD_H

#pragma ident	"@(#)machthread.h	1.19	05/06/30 SMI"

#include <sys/asi.h>
#include <sys/sun4asi.h>
#include <sys/machasi.h>
#include <sys/bitmap.h>
#if	defined(FJPLAT_KAISER) || defined(FJPLAT_COLUMBUS)
#include <sys/spitregs.h>
#endif	/* FJPLAT */

#ifdef	__cplusplus
extern "C" {
#endif

#ifdef	_ASM

#define	THREAD_REG	%g7		/* pointer to current thread data */

/*
 * Get the processor implementation from the version register.
 */
#define	GET_CPU_IMPL(out)		\
	rdpr	%ver,	out;		\
	srlx	out, 32, out;		\
	sll	out, 16, out;		\
	srl	out, 16, out;

#ifdef	_STARFIRE
/*
 * CPU_INDEX(r, scr)
 * Returns cpu id in r.
 * On Starfire, this is read from the Port Controller's Port ID
 * register in local space.
 *
 * Need to load the 64 bit address of the PC's PortID reg
 * using only one register. Kludge the 41 bits address constant to
 * be 32bits by shifting it 12 bits to the right first.
 */
#define	LOCAL_PC_PORTID_ADDR_SRL12 0x1FFF4000
#define	PC_PORT_ID 0xD0

#define	CPU_INDEX(r, scr)			\
	rdpr	%pstate, scr;			\
	andn	scr, PSTATE_IE | PSTATE_AM, r;	\
	wrpr	r, 0, %pstate;			\
	set	LOCAL_PC_PORTID_ADDR_SRL12, r;  \
	sllx    r, 12, r;                       \
	or	r, PC_PORT_ID, r;		\
	lduwa	[r]ASI_IO, r;			\
	wrpr	scr, 0, %pstate

#elif defined(FJPLAT_KAISER) || defined(FJPLAT_COLUMBUS)	/* KAISER */
/*
 * CPU_INDEX(r, scr)
 * Returns cpu id in r.
 *
 * On Kaiser, this is read from the Software Scratch Register(ASR25)
 * in alternate space.
 */

#define	CPU_INDEX_BY_GRD(REG)	RD_SCR_ASR(SCR2, REG)

#define	LENGTH(l) .+(l)*4

#define	CPU_INDEX(r, scr)			\
	or		%g6, %g0, scr;		\
	cmp		%g6, r;			\
	bne,a,pt	%xcc, LENGTH(7);	\
	 CPU_INDEX_BY_GRD(G6_REG);		\
	add		%g6, 0x01, %g6;		\
	cmp		%g6, r;			\
	bne,pn		%xcc, LENGTH(3);	\
	 CPU_INDEX_BY_GRD(G6_REG);		\
	ba,pt		%xcc, LENGTH(3);	\
	 or		%g6, %g0, r;		\
	or		scr, %g0, %g6

#else /* _STARFIRE */

/*
 * UPA supports up to 32 devices while Safari supports up to
 * 1024 devices (utilizing the SSM protocol). Based upon the
 * value of NCPU, a 5- or 10-bit mask will be needed for
 * extracting the cpu id.
 */
#if NCPU > 32
#define	CPU_MASK	0x3ff
#else
#define	CPU_MASK	0x1f
#endif	/* NCPU > 32 */

/*
 * CPU_INDEX(r, scr)
 * Returns cpu id in r.
 * For UPA based systems, the cpu id corresponds to the mid field in
 * the UPA config register. For Safari based machines, the cpu id
 * corresponds to the aid field in the Safari config register.
 *
 * XXX - scr reg is not used here.
 */
#define	CPU_INDEX(r, scr)		\
	ldxa	[%g0]ASI_UPA_CONFIG, r;	\
	srlx	r, 17, r;		\
	and	r, CPU_MASK, r

#endif	/* _STARFIRE */

/*
 * Given a cpu id extract the appropriate word
 * in the cpuset mask for this cpu id.
 */
#if CPUSET_SIZE > CLONGSIZE
#define	CPU_INDEXTOSET(base, index, scr)	\
	srl	index, BT_ULSHIFT, scr;		\
	and	index, BT_ULMASK, index;	\
	sll	scr, CLONGSHIFT, scr;		\
	add	base, scr, base
#else
#define	CPU_INDEXTOSET(base, index, scr)
#endif	/* CPUSET_SIZE */


/*
 * Assembly macro to find address of the current CPU.
 * Used when coming in from a user trap - cannot use THREAD_REG.
 * Args are destination register and one scratch register.
 */
#define	CPU_ADDR(reg, scr) 		\
	.global	cpu;			\
	CPU_INDEX(scr, reg);		\
	sll	scr, CPTRSHIFT, scr;	\
	set	cpu, reg;		\
	ldn	[reg + scr], reg

#define	CINT64SHIFT	3

/*
 * Assembly macro to find the physical address of the current CPU.
 * All memory references using VA must be limited to nucleus
 * memory to avoid any MMU side effect.
 */
#define	CPU_PADDR(reg, scr)				\
	.global cpu_pa;					\
	CPU_INDEX(scr, reg);				\
	sll	scr, CINT64SHIFT, scr;			\
	set	cpu_pa, reg;				\
	ldx	[reg + scr], reg

#ifdef FJCPU
/*
 * Stingray/Kila don't have features to flush the particular D-cache line.
 * Instead they keep the cache coherency between D1 and U2 automatically.
 * So here is nothing for the DCACHE_FLISH_LINE.
 * Instead we place here a macro to flush the entire cache on the Kilauea,
 * see UC#2011.
 */
 
#define CACHE_WAYBIT_SHIFT	27
#define FJ_2WAY_CACHE_FLUSH(label, csize, tmp1)		\
	/* Check U2 Cache WAY mode */						;\
	sethi	%hi(ecache_associativity), tmp1					;\
	ld	[tmp1 + %lo(ecache_associativity)], tmp1			;\
        cmp	tmp1, 1					/* 1 WAY mode? */       ;\
	be	%icc, label/**/_1way_flush		/* if 1WAY then jump */	;\
	 srlx	csize, U2_SZ_SHIFT, csize		/* U2-Cache size */	;\
label/**/_2way_flush:	/* Flush WAY0 and WAY1 */				;\
	sub	csize, U2_LINESZ, csize						;\
label/**/_2way_loop:								;\
	/* Flush WAY0 line */							;\
	stxa	%g0, [csize]ASI_L1_FLUSH_UC					;\
	/* Flush WAY1 line */							;\
	set	0x1, tmp1							;\
	sllx	tmp1, CACHE_WAYBIT_SHIFT, tmp1					;\
	or	csize, tmp1, tmp1						;\
	stxa	%g0, [tmp1]ASI_L1_FLUSH_UC					;\
	sub	csize, U2_LINESZ, csize		/* go to prev index */		;\
	brgez,a,pt	csize, label/**/_2way_loop				;\
	 nop									;\
	ba	label/**/_end							;\
	 nop									;\
label/**/_1way_flush:	/* Flush WAY0 only */					;\
	sub	csize, U2_LINESZ, csize						;\
label/**/_1way_loop:								;\
	stxa	%g0, [csize]ASI_L1_FLUSH_UC					;\
	sub	csize, U2_LINESZ, csize		/* go to prev index */		;\
	brgez,a,pt	csize, label/**/_1way_loop				;\
	 nop									;\
label/**/_end:									
#endif	/* FJCPU */

#endif	/* _ASM */

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_MACHTHREAD_H */
