cpufunc.h revision 181701
150477Speter/*-
211394Sswallace * Copyright (c) 2001 Jake Burkholder.
311394Sswallace * All rights reserved.
411394Sswallace *
511394Sswallace * Redistribution and use in source and binary forms, with or without
611394Sswallace * modification, are permitted provided that the following conditions
7155403Srwatson * are met:
811394Sswallace * 1. Redistributions of source code must retain the above copyright
9146806Srwatson *    notice, this list of conditions and the following disclaimer.
10146806Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11146806Srwatson *    notice, this list of conditions and the following disclaimer in the
12146806Srwatson *    documentation and/or other materials provided with the distribution.
13146806Srwatson *
1411397Sswallace * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1511397Sswallace * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1611397Sswallace * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1711394Sswallace * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1811397Sswallace * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1911397Sswallace * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2011394Sswallace * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2111394Sswallace * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2211394Sswallace * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2311394Sswallace * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2411397Sswallace * SUCH DAMAGE.
2511397Sswallace *
2611394Sswallace * $FreeBSD: head/sys/sparc64/include/cpufunc.h 181701 2008-08-13 20:30:28Z marius $
2711394Sswallace */
2811394Sswallace
2911397Sswallace#ifndef	_MACHINE_CPUFUNC_H_
3011397Sswallace#define	_MACHINE_CPUFUNC_H_
3111397Sswallace
3211397Sswallace#include <machine/asi.h>
3311397Sswallace#include <machine/pstate.h>
3411397Sswallace
3511397Sswallacestruct thread;
3611394Sswallace
3711394Sswallace/*
38147974Sjhb * Membar operand macros for use in other macros when # is a special
39155403Srwatson * character.  Keep these in sync with what the hardware expects.
40146806Srwatson */
41155403Srwatson#define	C_Lookaside	(0)
42146806Srwatson#define	C_MemIssue	(1)
43146806Srwatson#define	C_Sync		(2)
44146806Srwatson#define	M_LoadLoad	(0)
45146806Srwatson#define	M_StoreLoad	(1)
46155403Srwatson#define	M_LoadStore	(2)
47146806Srwatson#define	M_StoreStore	(3)
48155403Srwatson
49155403Srwatson#define	CMASK_SHIFT	(4)
50155403Srwatson#define	MMASK_SHIFT	(0)
51155403Srwatson
52155403Srwatson#define	CMASK_GEN(bit)	((1 << (bit)) << CMASK_SHIFT)
53155403Srwatson#define	MMASK_GEN(bit)	((1 << (bit)) << MMASK_SHIFT)
54155403Srwatson
55147974Sjhb#define	Lookaside	CMASK_GEN(C_Lookaside)
56155403Srwatson#define	MemIssue	CMASK_GEN(C_MemIssue)
57146806Srwatson#define	Sync		CMASK_GEN(C_Sync)
58155403Srwatson#define	LoadLoad	MMASK_GEN(M_LoadLoad)
59155403Srwatson#define	StoreLoad	MMASK_GEN(M_StoreLoad)
60146806Srwatson#define	LoadStore	MMASK_GEN(M_LoadStore)
61147974Sjhb#define	StoreStore	MMASK_GEN(M_StoreStore)
62155403Srwatson
63146806Srwatson#define	casa(rs1, rs2, rd, asi) ({					\
64155403Srwatson	u_int __rd = (uint32_t)(rd);					\
65146806Srwatson	__asm __volatile("casa [%2] %3, %4, %0"				\
66146806Srwatson	    : "+r" (__rd), "=m" (*rs1)					\
67155403Srwatson	    : "r" (rs1), "n" (asi), "r" (rs2), "m" (*rs1));		\
68146806Srwatson	__rd;								\
69146806Srwatson})
70155403Srwatson
71155403Srwatson#define	casxa(rs1, rs2, rd, asi) ({					\
72155403Srwatson	u_long __rd = (uint64_t)(rd);					\
73155403Srwatson	__asm __volatile("casxa [%2] %3, %4, %0"			\
74155403Srwatson	    : "+r" (__rd), "=m" (*rs1)					\
75146806Srwatson	    : "r" (rs1), "n" (asi), "r" (rs2), "m" (*rs1));		\
76147974Sjhb	__rd;								\
77155403Srwatson})
78146806Srwatson
79146806Srwatson#define	flush(va) do {							\
80147974Sjhb	__asm __volatile("flush %0" : : "r" (va));			\
81146806Srwatson} while (0)
82147974Sjhb
83146806Srwatson#define	flushw() do {							\
84147974Sjhb	__asm __volatile("flushw" : :);					\
85146806Srwatson} while (0)
86155403Srwatson
87155403Srwatson#define	mov(val, reg) do {						\
88155403Srwatson	__asm __volatile("mov %0, %" __XSTRING(reg) : : "r" (val));	\
89146806Srwatson} while (0)
90146806Srwatson
91147974Sjhb/* Generate ld*a/st*a functions for non-constant ASIs. */
92155403Srwatson#define	LDNC_GEN(tp, o)							\
93155403Srwatson	static __inline tp						\
94146806Srwatson	o ## _nc(caddr_t va, int asi)					\
95146806Srwatson	{								\
96146806Srwatson		tp r;							\
97146806Srwatson		__asm __volatile("wr %2, 0, %%asi;" #o " [%1] %%asi, %0"\
98147974Sjhb		    : "=r" (r) : "r" (va), "r" (asi));			\
99146806Srwatson		return (r);						\
100146806Srwatson	}
101155403Srwatson
102147974SjhbLDNC_GEN(u_char, lduba);
103155403SrwatsonLDNC_GEN(u_short, lduha);
104146806SrwatsonLDNC_GEN(u_int, lduwa);
105147974SjhbLDNC_GEN(u_long, ldxa);
106155403Srwatson
107155403Srwatson#define	LD_GENERIC(va, asi, op, type) ({				\
108147974Sjhb	type __r;							\
109155403Srwatson	__asm __volatile(#op " [%1] %2, %0"				\
110146806Srwatson	    : "=r" (__r) : "r" (va), "n" (asi));			\
111147974Sjhb	__r;								\
112146806Srwatson})
113155403Srwatson
114146806Srwatson#define	lduba(va, asi)	LD_GENERIC(va, asi, lduba, u_char)
115155403Srwatson#define	lduha(va, asi)	LD_GENERIC(va, asi, lduha, u_short)
116146806Srwatson#define	lduwa(va, asi)	LD_GENERIC(va, asi, lduwa, u_int)
117155403Srwatson#define	ldxa(va, asi)	LD_GENERIC(va, asi, ldxa, u_long)
118146806Srwatson
119147974Sjhb#define	STNC_GEN(tp, o)							\
120146806Srwatson	static __inline void						\
121146806Srwatson	o ## _nc(caddr_t va, int asi, tp val)				\
122147974Sjhb	{								\
123146806Srwatson		__asm __volatile("wr %2, 0, %%asi;" #o " %0, [%1] %%asi"\
124155403Srwatson		    : : "r" (val), "r" (va), "r" (asi));		\
125155403Srwatson	}
126146806Srwatson
127155403SrwatsonSTNC_GEN(u_char, stba);
128155403SrwatsonSTNC_GEN(u_short, stha);
129155403SrwatsonSTNC_GEN(u_int, stwa);
130146806SrwatsonSTNC_GEN(u_long, stxa);
131146806Srwatson
132146806Srwatson#define	ST_GENERIC(va, asi, val, op)					\
133146806Srwatson	__asm __volatile(#op " %0, [%1] %2"				\
134146806Srwatson	    : : "r" (val), "r" (va), "n" (asi));			\
135146806Srwatson
136146806Srwatson#define	stba(va, asi, val)	ST_GENERIC(va, asi, val, stba)
137146806Srwatson#define	stha(va, asi, val)	ST_GENERIC(va, asi, val, stha)
138146806Srwatson#define	stwa(va, asi, val)	ST_GENERIC(va, asi, val, stwa)
139146806Srwatson#define	stxa(va, asi, val)	ST_GENERIC(va, asi, val, stxa)
140146806Srwatson
141146806Srwatson/*
142146806Srwatson * Attempt to read from addr, val.  If a Data Access Error trap happens,
143146806Srwatson * they return -1 and the contents of val is undefined.  A return of 0
144146806Srwatson * means no trap happened, and the contents of val is valid.
145146806Srwatson */
146146806Srwatsonint fasword8(u_long asi, void *addr, uint8_t *val);
147155403Srwatsonint fasword16(u_long asi, void *addr, uint16_t *val);
148155403Srwatsonint fasword32(u_long asi, void *addr, uint32_t *val);
149155403Srwatson
150146806Srwatson#define	membar(mask) do {						\
151146806Srwatson	__asm __volatile("membar %0" : : "n" (mask) : "memory");	\
152146806Srwatson} while (0)
153147974Sjhb
154146806Srwatson#define	rd(name) ({							\
155155403Srwatson	uint64_t __sr;							\
156146806Srwatson	__asm __volatile("rd %%" #name ", %0" : "=r" (__sr) :);		\
157146806Srwatson	__sr;								\
158155403Srwatson})
159146806Srwatson
160146806Srwatson#define	wr(name, val, xor) do {						\
161155403Srwatson	__asm __volatile("wr %0, %1, %%" #name				\
162146806Srwatson	    : : "r" (val), "rI" (xor));					\
163146806Srwatson} while (0)
164147974Sjhb
165146806Srwatson#define	rdpr(name) ({							\
166155403Srwatson	uint64_t __pr;							\
167146806Srwatson	__asm __volatile("rdpr %%" #name", %0" : "=r" (__pr) :);	\
168155403Srwatson	__pr;								\
169146806Srwatson})
170155403Srwatson
171146806Srwatson#define	wrpr(name, val, xor) do {					\
172146806Srwatson	__asm __volatile("wrpr %0, %1, %%" #name			\
173146806Srwatson	    : : "r" (val), "rI" (xor));					\
174146806Srwatson} while (0)
175146806Srwatson
176146806Srwatson/*
177146806Srwatson * Macro intended to be used instead of wr(asr23, val, xor) for writing to
178146806Srwatson * the TICK_COMPARE register in order to avoid a bug in BlackBird CPUs that
179146806Srwatson * can cause these writes to fail under certain condidtions which in turn
180146806Srwatson * causes the hardclock to stop.  The workaround is to perform the write
181146806Srwatson * at the beginning of an I-Cache line directly followed by a dummy read.
182146806Srwatson */
183146806Srwatson#define	wrtickcmpr(val, xor) ({						\
184146806Srwatson	__asm __volatile(						\
185147974Sjhb	"	ba,pt	%%xcc, 1f ;		"			\
186146806Srwatson	"	 nop	 ;			"			\
187146806Srwatson	"	.align	64 ;			"			\
188146806Srwatson	"1:	wr	%0, %1, %%asr23 ;	"			\
189146806Srwatson	"	rd	%%asr23, %%g0 ;		"			\
190146806Srwatson	: : "r" (val), "rI" (xor));					\
191146806Srwatson})
192146806Srwatson
193146806Srwatsonstatic __inline void
194146806Srwatsonbreakpoint(void)
195146806Srwatson{
196146806Srwatson
197146806Srwatson	__asm __volatile("ta %%xcc, 1" : :);
198146806Srwatson}
199146806Srwatson
200146806Srwatsonstatic __inline register_t
201146806Srwatsonintr_disable(void)
202146806Srwatson{
203146806Srwatson	register_t s;
204146806Srwatson
205146806Srwatson	s = rdpr(pstate);
206146806Srwatson	wrpr(pstate, s & ~PSTATE_IE, 0);
207146806Srwatson	return (s);
208}
209#define	intr_restore(s)	wrpr(pstate, (s), 0)
210
211/*
212 * In some places, it is required that the store is directly followed by a
213 * membar #Sync.  Don't trust the compiler to not insert instructions in
214 * between.  We also need to disable interrupts completely.
215 */
216#define	stxa_sync(va, asi, val) do {					\
217	register_t s;							\
218	s = intr_disable();						\
219	__asm __volatile("stxa %0, [%1] %2; membar #Sync"		\
220	    : : "r" (val), "r" (va), "n" (asi));			\
221	intr_restore(s);						\
222} while (0)
223
224void ascopy(u_long asi, vm_offset_t src, vm_offset_t dst, size_t len);
225void ascopyfrom(u_long sasi, vm_offset_t src, caddr_t dst, size_t len);
226void ascopyto(caddr_t src, u_long dasi, vm_offset_t dst, size_t len);
227void aszero(u_long asi, vm_offset_t dst, size_t len);
228
229/*
230 * Ultrasparc II doesn't implement popc in hardware.
231 */
232#if 0
233#define	HAVE_INLINE_FFS
234/*
235 * See page 202 of the SPARC v9 Architecture Manual.
236 */
237static __inline int
238ffs(int mask)
239{
240	int result;
241	int neg;
242	int tmp;
243
244	__asm __volatile(
245	"	neg	%3, %1 ;	"
246	"	xnor	%3, %1, %2 ;	"
247	"	popc	%2, %0 ;	"
248	"	movrz	%3, %%g0, %0 ;	"
249	: "=r" (result), "=r" (neg), "=r" (tmp) : "r" (mask));
250	return (result);
251}
252#endif
253
254#undef LDNC_GEN
255#undef STNC_GEN
256
257#endif /* !_MACHINE_CPUFUNC_H_ */
258