xref: /titanic_50/usr/src/uts/sun4u/cpu/common_asm.s (revision 6e7bd6722c43b5bb4fa3bfb4961472f546ec2a6a)
17c478bd9Sstevel@tonic-gate/*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
525cf1a30Sjl139090 * Common Development and Distribution License (the "License").
625cf1a30Sjl139090 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate/*
22b52a336eSPavel Tatashin * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate#if !defined(lint)
267c478bd9Sstevel@tonic-gate#include "assym.h"
277c478bd9Sstevel@tonic-gate#endif	/* !lint */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate/*
307c478bd9Sstevel@tonic-gate * General assembly language routines.
317c478bd9Sstevel@tonic-gate * It is the intent of this file to contain routines that are
327c478bd9Sstevel@tonic-gate * specific to cpu architecture.
337c478bd9Sstevel@tonic-gate */
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate/*
367c478bd9Sstevel@tonic-gate * WARNING: If you add a fast trap handler which can be invoked by a
377c478bd9Sstevel@tonic-gate * non-privileged user, you may have to use the FAST_TRAP_DONE macro
387c478bd9Sstevel@tonic-gate * instead of "done" instruction to return back to the user mode. See
397c478bd9Sstevel@tonic-gate * comments for the "fast_trap_done" entry point for more information.
407c478bd9Sstevel@tonic-gate */
417c478bd9Sstevel@tonic-gate#define	FAST_TRAP_DONE	\
427c478bd9Sstevel@tonic-gate	ba,a	fast_trap_done
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate/*
457c478bd9Sstevel@tonic-gate * Override GET_NATIVE_TIME for the cpu module code.  This is not
467c478bd9Sstevel@tonic-gate * guaranteed to be exactly one instruction, be careful of using
477c478bd9Sstevel@tonic-gate * the macro in delay slots.
487c478bd9Sstevel@tonic-gate *
497c478bd9Sstevel@tonic-gate * Do not use any instruction that modifies condition codes as the
507c478bd9Sstevel@tonic-gate * caller may depend on these to remain unchanged across the macro.
517c478bd9Sstevel@tonic-gate */
5225cf1a30Sjl139090#if defined(CHEETAH) || defined(OLYMPUS_C)
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate#define	GET_NATIVE_TIME(out, scr1, scr2) \
557c478bd9Sstevel@tonic-gate	rd	STICK, out
567c478bd9Sstevel@tonic-gate#define	DELTA_NATIVE_TIME(delta, reg, scr1, scr2, scr3) \
577c478bd9Sstevel@tonic-gate	rd	STICK, reg;		\
587c478bd9Sstevel@tonic-gate	add	reg, delta, reg;	\
597c478bd9Sstevel@tonic-gate	wr	reg, STICK
607c478bd9Sstevel@tonic-gate#define	RD_TICKCMPR(out, scr)		\
617c478bd9Sstevel@tonic-gate	rd	STICK_COMPARE, out
627c478bd9Sstevel@tonic-gate#define	WR_TICKCMPR(in, scr1, scr2, label) \
637c478bd9Sstevel@tonic-gate	wr	in, STICK_COMPARE
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate#elif defined(HUMMINGBIRD)
667c478bd9Sstevel@tonic-gate#include <sys/spitregs.h>
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate/*
697c478bd9Sstevel@tonic-gate * the current hummingbird version of %stick and %stick_cmp
707c478bd9Sstevel@tonic-gate * were both implemented as (2) 32-bit locations in ASI_IO space;
717c478bd9Sstevel@tonic-gate * the hdwr should support atomic r/w; meanwhile: ugly alert! ...
727c478bd9Sstevel@tonic-gate *
737c478bd9Sstevel@tonic-gate * 64-bit opcodes are required, but move only 32-bits:
747c478bd9Sstevel@tonic-gate *
757c478bd9Sstevel@tonic-gate * ldxa [phys]ASI_IO, %dst 	reads  the low 32-bits from phys into %dst
767c478bd9Sstevel@tonic-gate * stxa %src, [phys]ASI_IO 	writes the low 32-bits from %src into phys
777c478bd9Sstevel@tonic-gate *
787c478bd9Sstevel@tonic-gate * reg equivalent		[phys]ASI_IO
797c478bd9Sstevel@tonic-gate * ------------------		---------------
807c478bd9Sstevel@tonic-gate * %stick_cmp  low-32		0x1FE.0000.F060
817c478bd9Sstevel@tonic-gate * %stick_cmp high-32		0x1FE.0000.F068
827c478bd9Sstevel@tonic-gate * %stick      low-32		0x1FE.0000.F070
837c478bd9Sstevel@tonic-gate * %stick     high-32		0x1FE.0000.F078
847c478bd9Sstevel@tonic-gate */
857c478bd9Sstevel@tonic-gate#define	HSTC_LOW	0x60			/* stick_cmp low  32-bits */
867c478bd9Sstevel@tonic-gate#define	HSTC_HIGH	0x68			/* stick_cmp high 32-bits */
877c478bd9Sstevel@tonic-gate#define	HST_LOW		0x70			/* stick low  32-bits */
887c478bd9Sstevel@tonic-gate#define	HST_HIGH	0x78			/* stick high 32-bits */
897c478bd9Sstevel@tonic-gate#define	HST_DIFF	0x08			/* low<-->high diff */
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate/*
927c478bd9Sstevel@tonic-gate * Any change in the number of instructions in SETL41()
937c478bd9Sstevel@tonic-gate * will affect SETL41_OFF
947c478bd9Sstevel@tonic-gate */
957c478bd9Sstevel@tonic-gate#define	SETL41(reg, byte) \
967c478bd9Sstevel@tonic-gate	sethi	%hi(0x1FE00000), reg;		/* 0000.0000.1FE0.0000 */ \
977c478bd9Sstevel@tonic-gate	or	reg, 0xF, reg;			/* 0000.0000.1FE0.000F */ \
987c478bd9Sstevel@tonic-gate	sllx	reg, 12, reg;			/* 0000.01FE.0000.F000 */ \
997c478bd9Sstevel@tonic-gate	or	reg, byte, reg;			/* 0000.01FE.0000.F0xx */
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate/*
1027c478bd9Sstevel@tonic-gate * SETL41_OFF is used to calulate the relative PC value when a
1037c478bd9Sstevel@tonic-gate * branch instruction needs to go over SETL41() macro
1047c478bd9Sstevel@tonic-gate */
1057c478bd9Sstevel@tonic-gate#define SETL41_OFF  16
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate/*
1087c478bd9Sstevel@tonic-gate * reading stick requires 2 loads, and there could be an intervening
1097c478bd9Sstevel@tonic-gate * low-to-high 32-bit rollover resulting in a return value that is
1107c478bd9Sstevel@tonic-gate * off by about (2 ^ 32); this rare case is prevented by re-reading
1117c478bd9Sstevel@tonic-gate * the low-32 bits after the high-32 and verifying the "after" value
1127c478bd9Sstevel@tonic-gate * is >= the "before" value; if not, increment the high-32 value.
1137c478bd9Sstevel@tonic-gate *
1147c478bd9Sstevel@tonic-gate * this method is limited to 1 rollover, and based on the fixed
1157c478bd9Sstevel@tonic-gate * stick-frequency (5555555), requires the loads to complete within
1167c478bd9Sstevel@tonic-gate * 773 seconds; incrementing the high-32 value will not overflow for
1177c478bd9Sstevel@tonic-gate * about 52644 years.
1187c478bd9Sstevel@tonic-gate *
1197c478bd9Sstevel@tonic-gate * writing stick requires 2 stores; if the old/new low-32 value is
1207c478bd9Sstevel@tonic-gate * near 0xffffffff, there could be another rollover (also rare).
1217c478bd9Sstevel@tonic-gate * to prevent this, we first write a 0 to the low-32, then write
1227c478bd9Sstevel@tonic-gate * new values to the high-32 then the low-32.
1237c478bd9Sstevel@tonic-gate *
1247c478bd9Sstevel@tonic-gate * When we detect a carry in the lower %stick register, we need to
1257c478bd9Sstevel@tonic-gate * read HST_HIGH again. However at the point where we detect this,
1267c478bd9Sstevel@tonic-gate * we need to rebuild the register address HST_HIGH.This involves more
1277c478bd9Sstevel@tonic-gate * than one instructions and a branch is unavoidable. However, most of
1287c478bd9Sstevel@tonic-gate * the time, there is no carry. So we take the penalty of a branch
1297c478bd9Sstevel@tonic-gate * instruction only when there is carry (less frequent).
1307c478bd9Sstevel@tonic-gate *
1317c478bd9Sstevel@tonic-gate * For GET_NATIVE_TIME(), we start afresh and branch to SETL41().
1327c478bd9Sstevel@tonic-gate * For DELTA_NATIVE_TIME(), we branch to just after SETL41() since
1337c478bd9Sstevel@tonic-gate * addr already points to HST_LOW.
1347c478bd9Sstevel@tonic-gate *
1357c478bd9Sstevel@tonic-gate * NOTE: this method requires disabling interrupts before using
1367c478bd9Sstevel@tonic-gate * DELTA_NATIVE_TIME.
1377c478bd9Sstevel@tonic-gate */
1387c478bd9Sstevel@tonic-gate#define	GET_NATIVE_TIME(out, scr, tmp)	\
1397c478bd9Sstevel@tonic-gate	SETL41(scr, HST_LOW);		\
1407c478bd9Sstevel@tonic-gate	ldxa	[scr]ASI_IO, tmp;	\
1417c478bd9Sstevel@tonic-gate	inc	HST_DIFF, scr;		\
1427c478bd9Sstevel@tonic-gate	ldxa	[scr]ASI_IO, out;	\
1437c478bd9Sstevel@tonic-gate	dec	HST_DIFF, scr;		\
1447c478bd9Sstevel@tonic-gate	ldxa	[scr]ASI_IO, scr;	\
1457c478bd9Sstevel@tonic-gate	sub	scr, tmp, tmp;		\
1467c478bd9Sstevel@tonic-gate	brlz,pn tmp, .-(SETL41_OFF+24); \
1477c478bd9Sstevel@tonic-gate	sllx	out, 32, out;		\
1487c478bd9Sstevel@tonic-gate	or	out, scr, out
1497c478bd9Sstevel@tonic-gate#define	DELTA_NATIVE_TIME(delta, addr, high, low, tmp) \
1507c478bd9Sstevel@tonic-gate	SETL41(addr, HST_LOW);		\
1517c478bd9Sstevel@tonic-gate	ldxa	[addr]ASI_IO, tmp;	\
1527c478bd9Sstevel@tonic-gate	inc	HST_DIFF, addr;		\
1537c478bd9Sstevel@tonic-gate	ldxa	[addr]ASI_IO, high;	\
1547c478bd9Sstevel@tonic-gate	dec	HST_DIFF, addr;		\
1557c478bd9Sstevel@tonic-gate	ldxa	[addr]ASI_IO, low;	\
1567c478bd9Sstevel@tonic-gate	sub	low, tmp, tmp;		\
1577c478bd9Sstevel@tonic-gate	brlz,pn tmp, .-24;		\
1587c478bd9Sstevel@tonic-gate	sllx	high, 32, high;		\
1597c478bd9Sstevel@tonic-gate	or	high, low, high;	\
1607c478bd9Sstevel@tonic-gate	add	high, delta, high;	\
1617c478bd9Sstevel@tonic-gate	srl	high, 0, low;		\
1627c478bd9Sstevel@tonic-gate	srlx	high, 32, high;		\
1637c478bd9Sstevel@tonic-gate	stxa	%g0, [addr]ASI_IO;	\
1647c478bd9Sstevel@tonic-gate	inc	HST_DIFF, addr;		\
1657c478bd9Sstevel@tonic-gate	stxa	high, [addr]ASI_IO;	\
1667c478bd9Sstevel@tonic-gate	dec	HST_DIFF, addr;		\
1677c478bd9Sstevel@tonic-gate	stxa	low, [addr]ASI_IO
1687c478bd9Sstevel@tonic-gate#define RD_TICKCMPR(out, scr)		\
1697c478bd9Sstevel@tonic-gate	SETL41(scr, HSTC_LOW);		\
1707c478bd9Sstevel@tonic-gate	ldxa	[scr]ASI_IO, out;	\
1717c478bd9Sstevel@tonic-gate	inc	HST_DIFF, scr;		\
1727c478bd9Sstevel@tonic-gate	ldxa	[scr]ASI_IO, scr;	\
1737c478bd9Sstevel@tonic-gate	sllx	scr, 32, scr;		\
1747c478bd9Sstevel@tonic-gate	or	scr, out, out
1757c478bd9Sstevel@tonic-gate#define WR_TICKCMPR(in, scra, scrd, label) \
1767c478bd9Sstevel@tonic-gate	SETL41(scra, HSTC_HIGH);	\
1777c478bd9Sstevel@tonic-gate	srlx	in, 32, scrd;		\
1787c478bd9Sstevel@tonic-gate	stxa	scrd, [scra]ASI_IO;	\
1797c478bd9Sstevel@tonic-gate	dec	HST_DIFF, scra;		\
1807c478bd9Sstevel@tonic-gate	stxa	in, [scra]ASI_IO
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate#else	/* !CHEETAH && !HUMMINGBIRD */
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate#define	GET_NATIVE_TIME(out, scr1, scr2) \
1857c478bd9Sstevel@tonic-gate	rdpr	%tick, out
1867c478bd9Sstevel@tonic-gate#define	DELTA_NATIVE_TIME(delta, reg, scr1, scr2, scr3) \
1877c478bd9Sstevel@tonic-gate	rdpr	%tick, reg;		\
1887c478bd9Sstevel@tonic-gate	add	reg, delta, reg;	\
1897c478bd9Sstevel@tonic-gate	wrpr	reg, %tick
1907c478bd9Sstevel@tonic-gate#define	RD_TICKCMPR(out, scr)		\
1917c478bd9Sstevel@tonic-gate	rd	TICK_COMPARE, out
1927c478bd9Sstevel@tonic-gate#ifdef BB_ERRATA_1 /* writes to TICK_COMPARE may fail */
1937c478bd9Sstevel@tonic-gate/*
1947c478bd9Sstevel@tonic-gate * Writes to the TICK_COMPARE register sometimes fail on blackbird modules.
1957c478bd9Sstevel@tonic-gate * The failure occurs only when the following instruction decodes to wr or
1967c478bd9Sstevel@tonic-gate * wrpr.  The workaround is to immediately follow writes to TICK_COMPARE
1977c478bd9Sstevel@tonic-gate * with a read, thus stalling the pipe and keeping following instructions
1987c478bd9Sstevel@tonic-gate * from causing data corruption.  Aligning to a quadword will ensure these
1997c478bd9Sstevel@tonic-gate * two instructions are not split due to i$ misses.
2007c478bd9Sstevel@tonic-gate */
2017c478bd9Sstevel@tonic-gate#define WR_TICKCMPR(cmpr,scr1,scr2,label)	\
2027c478bd9Sstevel@tonic-gate	ba,a	.bb_errata_1.label		;\
2037c478bd9Sstevel@tonic-gate	.align	64				;\
2047c478bd9Sstevel@tonic-gate.bb_errata_1.label:				;\
2057c478bd9Sstevel@tonic-gate	wr	cmpr, TICK_COMPARE		;\
2067c478bd9Sstevel@tonic-gate	rd	TICK_COMPARE, %g0
2077c478bd9Sstevel@tonic-gate#else	/* BB_ERRATA_1 */
2087c478bd9Sstevel@tonic-gate#define	WR_TICKCMPR(in,scr1,scr2,label)		\
2097c478bd9Sstevel@tonic-gate	wr	in, TICK_COMPARE
2107c478bd9Sstevel@tonic-gate#endif	/* BB_ERRATA_1 */
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate#endif	/* !CHEETAH && !HUMMINGBIRD */
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate#include <sys/clock.h>
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate#if defined(lint)
2177c478bd9Sstevel@tonic-gate#include <sys/types.h>
2187c478bd9Sstevel@tonic-gate#include <sys/scb.h>
2197c478bd9Sstevel@tonic-gate#include <sys/systm.h>
2207c478bd9Sstevel@tonic-gate#include <sys/regset.h>
2217c478bd9Sstevel@tonic-gate#include <sys/sunddi.h>
2227c478bd9Sstevel@tonic-gate#include <sys/lockstat.h>
2237c478bd9Sstevel@tonic-gate#endif	/* lint */
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h>
2277c478bd9Sstevel@tonic-gate#include <sys/privregs.h>
2287c478bd9Sstevel@tonic-gate#include <sys/machparam.h>	/* To get SYSBASE and PAGESIZE */
2297c478bd9Sstevel@tonic-gate#include <sys/machthread.h>
2307c478bd9Sstevel@tonic-gate#include <sys/clock.h>
2317c478bd9Sstevel@tonic-gate#include <sys/intreg.h>
2327c478bd9Sstevel@tonic-gate#include <sys/psr_compat.h>
2337c478bd9Sstevel@tonic-gate#include <sys/isa_defs.h>
2347c478bd9Sstevel@tonic-gate#include <sys/dditypes.h>
2357c478bd9Sstevel@tonic-gate#include <sys/intr.h>
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate#if !defined(lint)
2387c478bd9Sstevel@tonic-gate#include "assym.h"
2397c478bd9Sstevel@tonic-gate#endif	/* !lint */
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate#if defined(lint)
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gateuint_t
2447c478bd9Sstevel@tonic-gateget_impl(void)
2457c478bd9Sstevel@tonic-gate{ return (0); }
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate#else	/* lint */
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate	ENTRY(get_impl)
2507c478bd9Sstevel@tonic-gate	GET_CPU_IMPL(%o0)
2517c478bd9Sstevel@tonic-gate	retl
2527c478bd9Sstevel@tonic-gate	nop
2537c478bd9Sstevel@tonic-gate	SET_SIZE(get_impl)
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate#endif	/* lint */
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate#if defined(lint)
2587c478bd9Sstevel@tonic-gate/*
2597c478bd9Sstevel@tonic-gate * Softint generated when counter field of tick reg matches value field
2607c478bd9Sstevel@tonic-gate * of tick_cmpr reg
2617c478bd9Sstevel@tonic-gate */
2627c478bd9Sstevel@tonic-gate/*ARGSUSED*/
2637c478bd9Sstevel@tonic-gatevoid
2647c478bd9Sstevel@tonic-gatetickcmpr_set(uint64_t clock_cycles)
2657c478bd9Sstevel@tonic-gate{}
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate#else	/* lint */
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate	ENTRY_NP(tickcmpr_set)
2707c478bd9Sstevel@tonic-gate	! get 64-bit clock_cycles interval
2717c478bd9Sstevel@tonic-gate	mov	%o0, %o2
2727c478bd9Sstevel@tonic-gate	mov	8, %o3			! A reasonable initial step size
2737c478bd9Sstevel@tonic-gate1:
2747c478bd9Sstevel@tonic-gate	WR_TICKCMPR(%o2,%o4,%o5,__LINE__)	! Write to TICK_CMPR
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o0, %o4, %o5)	! Read %tick to confirm the
2777c478bd9Sstevel@tonic-gate	sllx	%o0, 1, %o0		!   value we wrote was in the future.
2787c478bd9Sstevel@tonic-gate	srlx	%o0, 1, %o0
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate	cmp	%o2, %o0		! If the value we wrote was in the
2817c478bd9Sstevel@tonic-gate	bg,pt	%xcc, 2f		!   future, then blow out of here.
2827c478bd9Sstevel@tonic-gate	sllx	%o3, 1, %o3		! If not, then double our step size,
2837c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 1b		!   and take another lap.
2847c478bd9Sstevel@tonic-gate	add	%o0, %o3, %o2		!
2857c478bd9Sstevel@tonic-gate2:
2867c478bd9Sstevel@tonic-gate	retl
2877c478bd9Sstevel@tonic-gate	nop
2887c478bd9Sstevel@tonic-gate	SET_SIZE(tickcmpr_set)
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate#endif	/* lint */
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate#if defined(lint)
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gatevoid
2957c478bd9Sstevel@tonic-gatetickcmpr_disable(void)
2967c478bd9Sstevel@tonic-gate{}
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate#else	/* lint */
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate	ENTRY_NP(tickcmpr_disable)
3017c478bd9Sstevel@tonic-gate	mov	1, %g1
3027c478bd9Sstevel@tonic-gate	sllx	%g1, TICKINT_DIS_SHFT, %o0
3037c478bd9Sstevel@tonic-gate	WR_TICKCMPR(%o0,%o4,%o5,__LINE__)	! Write to TICK_CMPR
3047c478bd9Sstevel@tonic-gate	retl
3057c478bd9Sstevel@tonic-gate	nop
3067c478bd9Sstevel@tonic-gate	SET_SIZE(tickcmpr_disable)
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate#endif	/* lint */
3097c478bd9Sstevel@tonic-gate
3107c478bd9Sstevel@tonic-gate#if defined(lint)
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate/*
3137c478bd9Sstevel@tonic-gate * tick_write_delta() increments %tick by the specified delta.  This should
3147c478bd9Sstevel@tonic-gate * only be called after a CPR event to assure that gethrtime() continues to
3157c478bd9Sstevel@tonic-gate * increase monotonically.  Obviously, writing %tick needs to de done very
3167c478bd9Sstevel@tonic-gate * carefully to avoid introducing unnecessary %tick skew across CPUs.  For
3177c478bd9Sstevel@tonic-gate * this reason, we make sure we're i-cache hot before actually writing to
3187c478bd9Sstevel@tonic-gate * %tick.
3197c478bd9Sstevel@tonic-gate */
3207c478bd9Sstevel@tonic-gate/*ARGSUSED*/
3217c478bd9Sstevel@tonic-gatevoid
3227c478bd9Sstevel@tonic-gatetick_write_delta(uint64_t delta)
3237c478bd9Sstevel@tonic-gate{}
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate#else	/* lint */
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate#ifdef DEBUG
3287c478bd9Sstevel@tonic-gate	.seg	".text"
3297c478bd9Sstevel@tonic-gatetick_write_panic:
3307c478bd9Sstevel@tonic-gate	.asciz	"tick_write_delta: interrupts already disabled on entry"
3317c478bd9Sstevel@tonic-gate#endif	/* DEBUG */
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate	ENTRY_NP(tick_write_delta)
3347c478bd9Sstevel@tonic-gate	rdpr	%pstate, %g1
3357c478bd9Sstevel@tonic-gate#ifdef DEBUG
3367c478bd9Sstevel@tonic-gate	andcc	%g1, PSTATE_IE, %g0	! If DEBUG, check that interrupts
3377c478bd9Sstevel@tonic-gate	bnz	0f			! aren't already disabled.
3387c478bd9Sstevel@tonic-gate	sethi	%hi(tick_write_panic), %o1
3397c478bd9Sstevel@tonic-gate        save    %sp, -SA(MINFRAME), %sp ! get a new window to preserve caller
3407c478bd9Sstevel@tonic-gate	call	panic
3417c478bd9Sstevel@tonic-gate	or	%i1, %lo(tick_write_panic), %o0
3427c478bd9Sstevel@tonic-gate#endif	/* DEBUG */
3437c478bd9Sstevel@tonic-gate0:	wrpr	%g1, PSTATE_IE, %pstate	! Disable interrupts
3447c478bd9Sstevel@tonic-gate	mov	%o0, %o2
3457c478bd9Sstevel@tonic-gate	ba	0f			! Branch to cache line-aligned instr.
3467c478bd9Sstevel@tonic-gate	nop
3477c478bd9Sstevel@tonic-gate	.align	16
3487c478bd9Sstevel@tonic-gate0:	nop				! The next 3 instructions are now hot.
3497c478bd9Sstevel@tonic-gate	DELTA_NATIVE_TIME(%o2, %o3, %o4, %o5, %g2)	! read/inc/write %tick
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate	retl				! Return
3527c478bd9Sstevel@tonic-gate	wrpr	%g0, %g1, %pstate	!     delay: Re-enable interrupts
3537c478bd9Sstevel@tonic-gate#endif	/* lint */
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate#if defined(lint)
3567c478bd9Sstevel@tonic-gate/*
3577c478bd9Sstevel@tonic-gate *  return 1 if disabled
3587c478bd9Sstevel@tonic-gate */
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gateint
3617c478bd9Sstevel@tonic-gatetickcmpr_disabled(void)
3627c478bd9Sstevel@tonic-gate{ return (0); }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate#else	/* lint */
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate	ENTRY_NP(tickcmpr_disabled)
3677c478bd9Sstevel@tonic-gate	RD_TICKCMPR(%g1, %o0)
3687c478bd9Sstevel@tonic-gate	retl
3697c478bd9Sstevel@tonic-gate	srlx	%g1, TICKINT_DIS_SHFT, %o0
3707c478bd9Sstevel@tonic-gate	SET_SIZE(tickcmpr_disabled)
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate#endif	/* lint */
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate/*
3757c478bd9Sstevel@tonic-gate * Get current tick
3767c478bd9Sstevel@tonic-gate */
3777c478bd9Sstevel@tonic-gate#if defined(lint)
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gateu_longlong_t
3807c478bd9Sstevel@tonic-gategettick(void)
3817c478bd9Sstevel@tonic-gate{ return (0); }
3827c478bd9Sstevel@tonic-gate
383b52a336eSPavel Tatashinu_longlong_t
384b52a336eSPavel Tatashinrandtick(void)
385b52a336eSPavel Tatashin{ return (0); }
386b52a336eSPavel Tatashin
3877c478bd9Sstevel@tonic-gate#else	/* lint */
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate	ENTRY(gettick)
390b52a336eSPavel Tatashin	ALTENTRY(randtick)
3917c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o0, %o2, %o3)
3927c478bd9Sstevel@tonic-gate	retl
3937c478bd9Sstevel@tonic-gate	nop
394b52a336eSPavel Tatashin	SET_SIZE(randtick)
3957c478bd9Sstevel@tonic-gate	SET_SIZE(gettick)
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate#endif	/* lint */
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate/*
4017c478bd9Sstevel@tonic-gate * Return the counter portion of the tick register.
4027c478bd9Sstevel@tonic-gate */
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate#if defined(lint)
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gateuint64_t
4077c478bd9Sstevel@tonic-gategettick_counter(void)
4087c478bd9Sstevel@tonic-gate{ return(0); }
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate#else	/* lint */
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate	ENTRY_NP(gettick_counter)
4137c478bd9Sstevel@tonic-gate	rdpr	%tick, %o0
4147c478bd9Sstevel@tonic-gate	sllx	%o0, 1, %o0
4157c478bd9Sstevel@tonic-gate	retl
4167c478bd9Sstevel@tonic-gate	srlx	%o0, 1, %o0		! shake off npt bit
4177c478bd9Sstevel@tonic-gate	SET_SIZE(gettick_counter)
4187c478bd9Sstevel@tonic-gate#endif	/* lint */
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate/*
4217c478bd9Sstevel@tonic-gate * Provide a C callable interface to the trap that reads the hi-res timer.
4227c478bd9Sstevel@tonic-gate * Returns 64-bit nanosecond timestamp in %o0 and %o1.
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate#if defined(lint)
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gatehrtime_t
4287c478bd9Sstevel@tonic-gategethrtime(void)
4297c478bd9Sstevel@tonic-gate{
4307c478bd9Sstevel@tonic-gate	return ((hrtime_t)0);
4317c478bd9Sstevel@tonic-gate}
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gatehrtime_t
4347c478bd9Sstevel@tonic-gategethrtime_unscaled(void)
4357c478bd9Sstevel@tonic-gate{
4367c478bd9Sstevel@tonic-gate	return ((hrtime_t)0);
4377c478bd9Sstevel@tonic-gate}
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gatehrtime_t
4407c478bd9Sstevel@tonic-gategethrtime_max(void)
4417c478bd9Sstevel@tonic-gate{
4427c478bd9Sstevel@tonic-gate	return ((hrtime_t)0);
4437c478bd9Sstevel@tonic-gate}
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gatevoid
4467c478bd9Sstevel@tonic-gatescalehrtime(hrtime_t *hrt)
4477c478bd9Sstevel@tonic-gate{
4487c478bd9Sstevel@tonic-gate	*hrt = 0;
4497c478bd9Sstevel@tonic-gate}
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gatevoid
4527c478bd9Sstevel@tonic-gategethrestime(timespec_t *tp)
4537c478bd9Sstevel@tonic-gate{
4547c478bd9Sstevel@tonic-gate	tp->tv_sec = 0;
4557c478bd9Sstevel@tonic-gate	tp->tv_nsec = 0;
4567c478bd9Sstevel@tonic-gate}
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gatetime_t
4597c478bd9Sstevel@tonic-gategethrestime_sec(void)
4607c478bd9Sstevel@tonic-gate{
4617c478bd9Sstevel@tonic-gate	return (0);
4627c478bd9Sstevel@tonic-gate}
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gatevoid
4657c478bd9Sstevel@tonic-gategethrestime_lasttick(timespec_t *tp)
4667c478bd9Sstevel@tonic-gate{
4677c478bd9Sstevel@tonic-gate	tp->tv_sec = 0;
4687c478bd9Sstevel@tonic-gate	tp->tv_nsec = 0;
4697c478bd9Sstevel@tonic-gate}
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate/*ARGSUSED*/
4727c478bd9Sstevel@tonic-gatevoid
4737c478bd9Sstevel@tonic-gatehres_tick(void)
4747c478bd9Sstevel@tonic-gate{
4757c478bd9Sstevel@tonic-gate}
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gatevoid
4787c478bd9Sstevel@tonic-gatepanic_hres_tick(void)
4797c478bd9Sstevel@tonic-gate{
4807c478bd9Sstevel@tonic-gate}
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate#else	/* lint */
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate	ENTRY_NP(gethrtime)
4857c478bd9Sstevel@tonic-gate	GET_HRTIME(%g1, %o0, %o1, %o2, %o3, %o4, %o5, %g2)
4867c478bd9Sstevel@tonic-gate							! %g1 = hrtime
4877c478bd9Sstevel@tonic-gate	retl
4887c478bd9Sstevel@tonic-gate	mov	%g1, %o0
4897c478bd9Sstevel@tonic-gate	SET_SIZE(gethrtime)
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate	ENTRY_NP(gethrtime_unscaled)
4927c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %o2, %o3)			! %g1 = native time
4937c478bd9Sstevel@tonic-gate	retl
4947c478bd9Sstevel@tonic-gate	mov	%g1, %o0
4957c478bd9Sstevel@tonic-gate	SET_SIZE(gethrtime_unscaled)
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate	ENTRY_NP(gethrtime_waitfree)
4987c478bd9Sstevel@tonic-gate	ALTENTRY(dtrace_gethrtime)
4997c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %o2, %o3)			! %g1 = native time
5007c478bd9Sstevel@tonic-gate	NATIVE_TIME_TO_NSEC(%g1, %o2, %o3)
5017c478bd9Sstevel@tonic-gate	retl
5027c478bd9Sstevel@tonic-gate	mov	%g1, %o0
5037c478bd9Sstevel@tonic-gate	SET_SIZE(dtrace_gethrtime)
5047c478bd9Sstevel@tonic-gate	SET_SIZE(gethrtime_waitfree)
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate	ENTRY(gethrtime_max)
5077c478bd9Sstevel@tonic-gate	NATIVE_TIME_MAX(%g1)
5087c478bd9Sstevel@tonic-gate	NATIVE_TIME_TO_NSEC(%g1, %o0, %o1)
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate	! hrtime_t's are signed, max hrtime_t must be positive
5117c478bd9Sstevel@tonic-gate	mov	-1, %o2
5127c478bd9Sstevel@tonic-gate	brlz,a	%g1, 1f
5137c478bd9Sstevel@tonic-gate	srlx	%o2, 1, %g1
5147c478bd9Sstevel@tonic-gate1:
5157c478bd9Sstevel@tonic-gate	retl
5167c478bd9Sstevel@tonic-gate	mov	%g1, %o0
5177c478bd9Sstevel@tonic-gate	SET_SIZE(gethrtime_max)
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate	ENTRY(scalehrtime)
5207c478bd9Sstevel@tonic-gate	ldx	[%o0], %o1
5217c478bd9Sstevel@tonic-gate	NATIVE_TIME_TO_NSEC(%o1, %o2, %o3)
5227c478bd9Sstevel@tonic-gate	retl
5237c478bd9Sstevel@tonic-gate	stx	%o1, [%o0]
5247c478bd9Sstevel@tonic-gate	SET_SIZE(scalehrtime)
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate/*
5277c478bd9Sstevel@tonic-gate * Fast trap to return a timestamp, uses trap window, leaves traps
5287c478bd9Sstevel@tonic-gate * disabled.  Returns a 64-bit nanosecond timestamp in %o0 and %o1.
5297c478bd9Sstevel@tonic-gate *
5307c478bd9Sstevel@tonic-gate * This is the handler for the ST_GETHRTIME trap.
5317c478bd9Sstevel@tonic-gate */
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate	ENTRY_NP(get_timestamp)
5347c478bd9Sstevel@tonic-gate	GET_HRTIME(%g1, %g2, %g3, %g4, %g5, %o0, %o1, %o2)	! %g1 = hrtime
5357c478bd9Sstevel@tonic-gate	srlx	%g1, 32, %o0				! %o0 = hi32(%g1)
5367c478bd9Sstevel@tonic-gate	srl	%g1, 0, %o1				! %o1 = lo32(%g1)
5377c478bd9Sstevel@tonic-gate	FAST_TRAP_DONE
5387c478bd9Sstevel@tonic-gate	SET_SIZE(get_timestamp)
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate/*
5417c478bd9Sstevel@tonic-gate * Macro to convert GET_HRESTIME() bits into a timestamp.
5427c478bd9Sstevel@tonic-gate *
5437c478bd9Sstevel@tonic-gate * We use two separate macros so that the platform-dependent GET_HRESTIME()
5447c478bd9Sstevel@tonic-gate * can be as small as possible; CONV_HRESTIME() implements the generic part.
5457c478bd9Sstevel@tonic-gate */
5467c478bd9Sstevel@tonic-gate#define	CONV_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano) \
5477c478bd9Sstevel@tonic-gate	brz,pt	adj, 3f;		/* no adjustments, it's easy */	\
5487c478bd9Sstevel@tonic-gate	add	hrestnsec, nslt, hrestnsec; /* hrest.tv_nsec += nslt */	\
5497c478bd9Sstevel@tonic-gate	brlz,pn	adj, 2f;		/* if hrestime_adj negative */	\
550646e55b6Scth	srlx	nslt, ADJ_SHIFT, nslt;	/* delay: nslt >>= 4 */		\
5517c478bd9Sstevel@tonic-gate	subcc	adj, nslt, %g0;		/* hrestime_adj - nslt/16 */	\
5527c478bd9Sstevel@tonic-gate	movg	%xcc, nslt, adj;	/* adj by min(adj, nslt/16) */	\
5537c478bd9Sstevel@tonic-gate	ba	3f;			/* go convert to sec/nsec */	\
5547c478bd9Sstevel@tonic-gate	add	hrestnsec, adj, hrestnsec; /* delay: apply adjustment */ \
5557c478bd9Sstevel@tonic-gate2:	addcc	adj, nslt, %g0;		/* hrestime_adj + nslt/16 */	\
5567c478bd9Sstevel@tonic-gate	bge,a,pt %xcc, 3f;		/* is adj less negative? */	\
5577c478bd9Sstevel@tonic-gate	add	hrestnsec, adj, hrestnsec; /* yes: hrest.nsec += adj */	\
5587c478bd9Sstevel@tonic-gate	sub	hrestnsec, nslt, hrestnsec; /* no: hrest.nsec -= nslt/16 */ \
5597c478bd9Sstevel@tonic-gate3:	cmp	hrestnsec, nano;	/* more than a billion? */	\
5607c478bd9Sstevel@tonic-gate	bl,pt	%xcc, 4f;		/* if not, we're done */	\
5617c478bd9Sstevel@tonic-gate	nop;				/* delay: do nothing :( */	\
5627c478bd9Sstevel@tonic-gate	add	hrestsec, 1, hrestsec;	/* hrest.tv_sec++; */		\
5637c478bd9Sstevel@tonic-gate	sub	hrestnsec, nano, hrestnsec; /* hrest.tv_nsec -= NANOSEC; */ \
564646e55b6Scth	ba,a	3b;			/* check >= billion again */	\
5657c478bd9Sstevel@tonic-gate4:
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate	ENTRY_NP(gethrestime)
5687c478bd9Sstevel@tonic-gate	GET_HRESTIME(%o1, %o2, %o3, %o4, %o5, %g1, %g2, %g3, %g4)
5697c478bd9Sstevel@tonic-gate	CONV_HRESTIME(%o1, %o2, %o3, %o4, %o5)
5707c478bd9Sstevel@tonic-gate	stn	%o1, [%o0]
5717c478bd9Sstevel@tonic-gate	retl
5727c478bd9Sstevel@tonic-gate	stn	%o2, [%o0 + CLONGSIZE]
5737c478bd9Sstevel@tonic-gate	SET_SIZE(gethrestime)
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate/*
5767c478bd9Sstevel@tonic-gate * Similar to gethrestime(), but gethrestime_sec() returns current hrestime
5777c478bd9Sstevel@tonic-gate * seconds.
5787c478bd9Sstevel@tonic-gate */
5797c478bd9Sstevel@tonic-gate	ENTRY_NP(gethrestime_sec)
5807c478bd9Sstevel@tonic-gate	GET_HRESTIME(%o0, %o2, %o3, %o4, %o5, %g1, %g2, %g3, %g4)
5817c478bd9Sstevel@tonic-gate	CONV_HRESTIME(%o0, %o2, %o3, %o4, %o5)
5827c478bd9Sstevel@tonic-gate	retl					! %o0 current hrestime seconds
5837c478bd9Sstevel@tonic-gate	nop
5847c478bd9Sstevel@tonic-gate	SET_SIZE(gethrestime_sec)
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate/*
5877c478bd9Sstevel@tonic-gate * Returns the hrestime on the last tick.  This is simpler than gethrestime()
5887c478bd9Sstevel@tonic-gate * and gethrestime_sec():  no conversion is required.  gethrestime_lasttick()
5897c478bd9Sstevel@tonic-gate * follows the same locking algorithm as GET_HRESTIME and GET_HRTIME,
5907c478bd9Sstevel@tonic-gate * outlined in detail in clock.h.  (Unlike GET_HRESTIME/GET_HRTIME, we don't
5917c478bd9Sstevel@tonic-gate * rely on load dependencies to effect the membar #LoadLoad, instead declaring
5927c478bd9Sstevel@tonic-gate * it explicitly.)
5937c478bd9Sstevel@tonic-gate */
5947c478bd9Sstevel@tonic-gate	ENTRY_NP(gethrestime_lasttick)
5957c478bd9Sstevel@tonic-gate	sethi	%hi(hres_lock), %o1
5967c478bd9Sstevel@tonic-gate0:
5977c478bd9Sstevel@tonic-gate	lduw	[%o1 + %lo(hres_lock)], %o2	! Load lock value
5987c478bd9Sstevel@tonic-gate	membar	#LoadLoad			! Load of lock must complete
5997c478bd9Sstevel@tonic-gate	andn	%o2, 1, %o2			! Mask off lowest bit
6007c478bd9Sstevel@tonic-gate	ldn	[%o1 + %lo(hrestime)], %g1	! Seconds.
6017c478bd9Sstevel@tonic-gate	add	%o1, %lo(hrestime), %o4
6027c478bd9Sstevel@tonic-gate	ldn	[%o4 + CLONGSIZE], %g2		! Nanoseconds.
6037c478bd9Sstevel@tonic-gate	membar	#LoadLoad			! All loads must complete
6047c478bd9Sstevel@tonic-gate	lduw	[%o1 + %lo(hres_lock)], %o3	! Reload lock value
6057c478bd9Sstevel@tonic-gate	cmp	%o3, %o2			! If lock is locked or has
6067c478bd9Sstevel@tonic-gate	bne	0b				!   changed, retry.
6077c478bd9Sstevel@tonic-gate	stn	%g1, [%o0]			! Delay: store seconds
6087c478bd9Sstevel@tonic-gate	retl
6097c478bd9Sstevel@tonic-gate	stn	%g2, [%o0 + CLONGSIZE]		! Delay: store nanoseconds
6107c478bd9Sstevel@tonic-gate	SET_SIZE(gethrestime_lasttick)
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate/*
6137c478bd9Sstevel@tonic-gate * Fast trap for gettimeofday().  Returns a timestruc_t in %o0 and %o1.
6147c478bd9Sstevel@tonic-gate *
6157c478bd9Sstevel@tonic-gate * This is the handler for the ST_GETHRESTIME trap.
6167c478bd9Sstevel@tonic-gate */
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate	ENTRY_NP(get_hrestime)
6197c478bd9Sstevel@tonic-gate	GET_HRESTIME(%o0, %o1, %g1, %g2, %g3, %g4, %g5, %o2, %o3)
6207c478bd9Sstevel@tonic-gate	CONV_HRESTIME(%o0, %o1, %g1, %g2, %g3)
6217c478bd9Sstevel@tonic-gate	FAST_TRAP_DONE
6227c478bd9Sstevel@tonic-gate	SET_SIZE(get_hrestime)
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate/*
6257c478bd9Sstevel@tonic-gate * Fast trap to return lwp virtual time, uses trap window, leaves traps
6267c478bd9Sstevel@tonic-gate * disabled.  Returns a 64-bit number in %o0:%o1, which is the number
6277c478bd9Sstevel@tonic-gate * of nanoseconds consumed.
6287c478bd9Sstevel@tonic-gate *
6297c478bd9Sstevel@tonic-gate * This is the handler for the ST_GETHRVTIME trap.
6307c478bd9Sstevel@tonic-gate *
6317c478bd9Sstevel@tonic-gate * Register usage:
6327c478bd9Sstevel@tonic-gate *	%o0, %o1 = return lwp virtual time
6337c478bd9Sstevel@tonic-gate * 	%o2 = CPU/thread
6347c478bd9Sstevel@tonic-gate * 	%o3 = lwp
6357c478bd9Sstevel@tonic-gate * 	%g1 = scratch
6367c478bd9Sstevel@tonic-gate * 	%g5 = scratch
6377c478bd9Sstevel@tonic-gate */
6387c478bd9Sstevel@tonic-gate	ENTRY_NP(get_virtime)
6397c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g5, %g1, %g2)	! %g5 = native time in ticks
6407c478bd9Sstevel@tonic-gate	CPU_ADDR(%g2, %g3)			! CPU struct ptr to %g2
6417c478bd9Sstevel@tonic-gate	ldn	[%g2 + CPU_THREAD], %g2		! thread pointer to %g2
6427c478bd9Sstevel@tonic-gate	ldn	[%g2 + T_LWP], %g3		! lwp pointer to %g3
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate	/*
6457c478bd9Sstevel@tonic-gate	 * Subtract start time of current microstate from time
6467c478bd9Sstevel@tonic-gate	 * of day to get increment for lwp virtual time.
6477c478bd9Sstevel@tonic-gate	 */
6487c478bd9Sstevel@tonic-gate	ldx	[%g3 + LWP_STATE_START], %g1	! ms_state_start
6497c478bd9Sstevel@tonic-gate	sub	%g5, %g1, %g5
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate	/*
6527c478bd9Sstevel@tonic-gate	 * Add current value of ms_acct[LMS_USER]
6537c478bd9Sstevel@tonic-gate	 */
6547c478bd9Sstevel@tonic-gate	ldx	[%g3 + LWP_ACCT_USER], %g1	! ms_acct[LMS_USER]
6557c478bd9Sstevel@tonic-gate	add	%g5, %g1, %g5
6567c478bd9Sstevel@tonic-gate	NATIVE_TIME_TO_NSEC(%g5, %g1, %o0)
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate	srl	%g5, 0, %o1			! %o1 = lo32(%g5)
6597c478bd9Sstevel@tonic-gate	srlx	%g5, 32, %o0			! %o0 = hi32(%g5)
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate	FAST_TRAP_DONE
6627c478bd9Sstevel@tonic-gate	SET_SIZE(get_virtime)
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate	.seg	".text"
6677c478bd9Sstevel@tonic-gatehrtime_base_panic:
6687c478bd9Sstevel@tonic-gate	.asciz	"hrtime_base stepping back"
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate	ENTRY_NP(hres_tick)
6727c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp	! get a new window
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate	sethi	%hi(hrestime), %l4
6757c478bd9Sstevel@tonic-gate	ldstub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5	! try locking
6767c478bd9Sstevel@tonic-gate7:	tst	%l5
6777c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 8f			! if we got it, drive on
6787c478bd9Sstevel@tonic-gate	ld	[%l4 + %lo(nsec_scale)], %l5	! delay: %l5 = scaling factor
6797c478bd9Sstevel@tonic-gate	ldub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5
6807c478bd9Sstevel@tonic-gate9:	tst	%l5
6817c478bd9Sstevel@tonic-gate	bz,a,pn	%xcc, 7b
6827c478bd9Sstevel@tonic-gate	ldstub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5
6837c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 9b
6847c478bd9Sstevel@tonic-gate	ldub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5
6857c478bd9Sstevel@tonic-gate8:
6867c478bd9Sstevel@tonic-gate	membar	#StoreLoad|#StoreStore
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate	!
6897c478bd9Sstevel@tonic-gate	! update hres_last_tick.  %l5 has the scaling factor (nsec_scale).
6907c478bd9Sstevel@tonic-gate	!
6917c478bd9Sstevel@tonic-gate	ldx	[%l4 + %lo(hrtime_base)], %g1	! load current hrtime_base
6927c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%l0, %l3, %l6)		! current native time
6937c478bd9Sstevel@tonic-gate	stx	%l0, [%l4 + %lo(hres_last_tick)]! prev = current
6947c478bd9Sstevel@tonic-gate	! convert native time to nsecs
6957c478bd9Sstevel@tonic-gate	NATIVE_TIME_TO_NSEC_SCALE(%l0, %l5, %l2, NSEC_SHIFT)
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate	sub	%l0, %g1, %i1			! get accurate nsec delta
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate	ldx	[%l4 + %lo(hrtime_base)], %l1
7007c478bd9Sstevel@tonic-gate	cmp	%l1, %l0
7017c478bd9Sstevel@tonic-gate	bg,pn	%xcc, 9f
7027c478bd9Sstevel@tonic-gate	nop
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate	stx	%l0, [%l4 + %lo(hrtime_base)]	! update hrtime_base
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate	!
7077c478bd9Sstevel@tonic-gate	! apply adjustment, if any
7087c478bd9Sstevel@tonic-gate	!
7097c478bd9Sstevel@tonic-gate	ldx	[%l4 + %lo(hrestime_adj)], %l0	! %l0 = hrestime_adj
7107c478bd9Sstevel@tonic-gate	brz	%l0, 2f
7117c478bd9Sstevel@tonic-gate						! hrestime_adj == 0 ?
7127c478bd9Sstevel@tonic-gate						! yes, skip adjustments
7137c478bd9Sstevel@tonic-gate	clr	%l5				! delay: set adj to zero
7147c478bd9Sstevel@tonic-gate	tst	%l0				! is hrestime_adj >= 0 ?
7157c478bd9Sstevel@tonic-gate	bge,pt	%xcc, 1f			! yes, go handle positive case
7167c478bd9Sstevel@tonic-gate	srl	%i1, ADJ_SHIFT, %l5		! delay: %l5 = adj
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate	addcc	%l0, %l5, %g0			! hrestime_adj < -adj ?
7197c478bd9Sstevel@tonic-gate	bl,pt	%xcc, 2f			! yes, use current adj
7207c478bd9Sstevel@tonic-gate	neg	%l5				! delay: %l5 = -adj
7217c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 2f
7227c478bd9Sstevel@tonic-gate	mov	%l0, %l5			! no, so set adj = hrestime_adj
7237c478bd9Sstevel@tonic-gate1:
7247c478bd9Sstevel@tonic-gate	subcc	%l0, %l5, %g0			! hrestime_adj < adj ?
7257c478bd9Sstevel@tonic-gate	bl,a,pt	%xcc, 2f			! yes, set adj = hrestime_adj
7267c478bd9Sstevel@tonic-gate	mov	%l0, %l5			! delay: adj = hrestime_adj
7277c478bd9Sstevel@tonic-gate2:
7287c478bd9Sstevel@tonic-gate	ldx	[%l4 + %lo(timedelta)], %l0	! %l0 = timedelta
7297c478bd9Sstevel@tonic-gate	sub	%l0, %l5, %l0			! timedelta -= adj
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate	stx	%l0, [%l4 + %lo(timedelta)]	! store new timedelta
7327c478bd9Sstevel@tonic-gate	stx	%l0, [%l4 + %lo(hrestime_adj)]	! hrestime_adj = timedelta
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate	or	%l4, %lo(hrestime), %l2
7357c478bd9Sstevel@tonic-gate	ldn	[%l2], %i2			! %i2:%i3 = hrestime sec:nsec
7367c478bd9Sstevel@tonic-gate	ldn	[%l2 + CLONGSIZE], %i3
7377c478bd9Sstevel@tonic-gate	add	%i3, %l5, %i3			! hrestime.nsec += adj
7387c478bd9Sstevel@tonic-gate	add	%i3, %i1, %i3			! hrestime.nsec += nslt
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate	set	NANOSEC, %l5			! %l5 = NANOSEC
7417c478bd9Sstevel@tonic-gate	cmp	%i3, %l5
7427c478bd9Sstevel@tonic-gate	bl,pt	%xcc, 5f			! if hrestime.tv_nsec < NANOSEC
7437c478bd9Sstevel@tonic-gate	sethi	%hi(one_sec), %i1		! delay
7447c478bd9Sstevel@tonic-gate	add	%i2, 0x1, %i2			! hrestime.tv_sec++
7457c478bd9Sstevel@tonic-gate	sub	%i3, %l5, %i3			! hrestime.tv_nsec - NANOSEC
7467c478bd9Sstevel@tonic-gate	mov	0x1, %l5
7477c478bd9Sstevel@tonic-gate	st	%l5, [%i1 + %lo(one_sec)]
7487c478bd9Sstevel@tonic-gate5:
7497c478bd9Sstevel@tonic-gate	stn	%i2, [%l2]
7507c478bd9Sstevel@tonic-gate	stn	%i3, [%l2 + CLONGSIZE]		! store the new hrestime
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate	membar	#StoreStore
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate	ld	[%l4 + %lo(hres_lock)], %i1
7557c478bd9Sstevel@tonic-gate	inc	%i1				! release lock
7567c478bd9Sstevel@tonic-gate	st	%i1, [%l4 + %lo(hres_lock)]	! clear hres_lock
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate	ret
7597c478bd9Sstevel@tonic-gate	restore
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate9:
7627c478bd9Sstevel@tonic-gate	!
7637c478bd9Sstevel@tonic-gate	! release hres_lock
7647c478bd9Sstevel@tonic-gate	!
7657c478bd9Sstevel@tonic-gate	ld	[%l4 + %lo(hres_lock)], %i1
7667c478bd9Sstevel@tonic-gate	inc	%i1
7677c478bd9Sstevel@tonic-gate	st	%i1, [%l4 + %lo(hres_lock)]
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate	sethi	%hi(hrtime_base_panic), %o0
7707c478bd9Sstevel@tonic-gate	call	panic
7717c478bd9Sstevel@tonic-gate	or	%o0, %lo(hrtime_base_panic), %o0
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate	SET_SIZE(hres_tick)
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate#endif	/* lint */
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate#if !defined(lint) && !defined(__lint)
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate	.seg	".text"
7807c478bd9Sstevel@tonic-gatekstat_q_panic_msg:
7817c478bd9Sstevel@tonic-gate	.asciz	"kstat_q_exit: qlen == 0"
7827c478bd9Sstevel@tonic-gate
7837c478bd9Sstevel@tonic-gate	ENTRY(kstat_q_panic)
7847c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp
7857c478bd9Sstevel@tonic-gate	sethi	%hi(kstat_q_panic_msg), %o0
7867c478bd9Sstevel@tonic-gate	call	panic
7877c478bd9Sstevel@tonic-gate	or	%o0, %lo(kstat_q_panic_msg), %o0
7887c478bd9Sstevel@tonic-gate	/*NOTREACHED*/
7897c478bd9Sstevel@tonic-gate	SET_SIZE(kstat_q_panic)
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate#define	BRZPN	brz,pn
7927c478bd9Sstevel@tonic-gate#define	BRZPT	brz,pt
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate#define	KSTAT_Q_UPDATE(QOP, QBR, QZERO, QRETURN, QTYPE) \
7957c478bd9Sstevel@tonic-gate	ld	[%o0 + QTYPE/**/CNT], %o1;	/* %o1 = old qlen */	\
7967c478bd9Sstevel@tonic-gate	QOP	%o1, 1, %o2;			/* %o2 = new qlen */	\
7977c478bd9Sstevel@tonic-gate	QBR	%o1, QZERO;			/* done if qlen == 0 */	\
7987c478bd9Sstevel@tonic-gate	st	%o2, [%o0 + QTYPE/**/CNT];	/* delay: save qlen */	\
7997c478bd9Sstevel@tonic-gate	ldx	[%o0 + QTYPE/**/LASTUPDATE], %o3;			\
8007c478bd9Sstevel@tonic-gate	ldx	[%o0 + QTYPE/**/TIME], %o4;	/* %o4 = old time */	\
8017c478bd9Sstevel@tonic-gate	ldx	[%o0 + QTYPE/**/LENTIME], %o5;	/* %o5 = old lentime */	\
8027c478bd9Sstevel@tonic-gate	sub	%g1, %o3, %o2;			/* %o2 = time delta */	\
8037c478bd9Sstevel@tonic-gate	mulx	%o1, %o2, %o3;			/* %o3 = cur lentime */	\
8047c478bd9Sstevel@tonic-gate	add	%o4, %o2, %o4;			/* %o4 = new time */	\
8057c478bd9Sstevel@tonic-gate	add	%o5, %o3, %o5;			/* %o5 = new lentime */	\
8067c478bd9Sstevel@tonic-gate	stx	%o4, [%o0 + QTYPE/**/TIME];	/* save time */		\
8077c478bd9Sstevel@tonic-gate	stx	%o5, [%o0 + QTYPE/**/LENTIME];	/* save lentime */	\
8087c478bd9Sstevel@tonic-gateQRETURN;								\
8097c478bd9Sstevel@tonic-gate	stx	%g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */
8107c478bd9Sstevel@tonic-gate
811*6e7bd672SToomas Soome#if !defined(DEBUG)
812*6e7bd672SToomas Soome/*
813*6e7bd672SToomas Soome * same as KSTAT_Q_UPDATE but without:
814*6e7bd672SToomas Soome * QBR     %o1, QZERO;
815*6e7bd672SToomas Soome * to be used only with non-debug build. mimics ASSERT() behaviour.
816*6e7bd672SToomas Soome */
817*6e7bd672SToomas Soome#define	KSTAT_Q_UPDATE_ND(QOP, QRETURN, QTYPE) \
818*6e7bd672SToomas Soome	ld	[%o0 + QTYPE/**/CNT], %o1;	/* %o1 = old qlen */	\
819*6e7bd672SToomas Soome	QOP	%o1, 1, %o2;			/* %o2 = new qlen */	\
820*6e7bd672SToomas Soome	st	%o2, [%o0 + QTYPE/**/CNT];	/* delay: save qlen */	\
821*6e7bd672SToomas Soome	ldx	[%o0 + QTYPE/**/LASTUPDATE], %o3;			\
822*6e7bd672SToomas Soome	ldx	[%o0 + QTYPE/**/TIME], %o4;	/* %o4 = old time */	\
823*6e7bd672SToomas Soome	ldx	[%o0 + QTYPE/**/LENTIME], %o5;	/* %o5 = old lentime */	\
824*6e7bd672SToomas Soome	sub	%g1, %o3, %o2;			/* %o2 = time delta */	\
825*6e7bd672SToomas Soome	mulx	%o1, %o2, %o3;			/* %o3 = cur lentime */	\
826*6e7bd672SToomas Soome	add	%o4, %o2, %o4;			/* %o4 = new time */	\
827*6e7bd672SToomas Soome	add	%o5, %o3, %o5;			/* %o5 = new lentime */	\
828*6e7bd672SToomas Soome	stx	%o4, [%o0 + QTYPE/**/TIME];	/* save time */		\
829*6e7bd672SToomas Soome	stx	%o5, [%o0 + QTYPE/**/LENTIME];	/* save lentime */	\
830*6e7bd672SToomas SoomeQRETURN;								\
831*6e7bd672SToomas Soome	stx	%g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */
832*6e7bd672SToomas Soome#endif
833*6e7bd672SToomas Soome
8347c478bd9Sstevel@tonic-gate	.align 16
8357c478bd9Sstevel@tonic-gate	ENTRY(kstat_waitq_enter)
8367c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %g2, %g3)
8377c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W)
8387c478bd9Sstevel@tonic-gate	SET_SIZE(kstat_waitq_enter)
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate	.align 16
8417c478bd9Sstevel@tonic-gate	ENTRY(kstat_waitq_exit)
8427c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %g2, %g3)
843*6e7bd672SToomas Soome#if defined(DEBUG)
8447c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_W)
845*6e7bd672SToomas Soome#else
846*6e7bd672SToomas Soome	KSTAT_Q_UPDATE_ND(sub, retl, KSTAT_IO_W)
847*6e7bd672SToomas Soome#endif
8487c478bd9Sstevel@tonic-gate	SET_SIZE(kstat_waitq_exit)
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate	.align 16
8517c478bd9Sstevel@tonic-gate	ENTRY(kstat_runq_enter)
8527c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %g2, %g3)
8537c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R)
8547c478bd9Sstevel@tonic-gate	SET_SIZE(kstat_runq_enter)
8557c478bd9Sstevel@tonic-gate
8567c478bd9Sstevel@tonic-gate	.align 16
8577c478bd9Sstevel@tonic-gate	ENTRY(kstat_runq_exit)
8587c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %g2, %g3)
859*6e7bd672SToomas Soome#if defined(DEBUG)
8607c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_R)
861*6e7bd672SToomas Soome#else
862*6e7bd672SToomas Soome	KSTAT_Q_UPDATE_ND(sub, retl, KSTAT_IO_R)
863*6e7bd672SToomas Soome#endif
8647c478bd9Sstevel@tonic-gate	SET_SIZE(kstat_runq_exit)
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate	.align 16
8677c478bd9Sstevel@tonic-gate	ENTRY(kstat_waitq_to_runq)
8687c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %g2, %g3)
869*6e7bd672SToomas Soome#if defined(DEBUG)
8707c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_W)
871*6e7bd672SToomas Soome#else
872*6e7bd672SToomas Soome	KSTAT_Q_UPDATE_ND(sub, 1:, KSTAT_IO_W)
873*6e7bd672SToomas Soome#endif
8747c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R)
8757c478bd9Sstevel@tonic-gate	SET_SIZE(kstat_waitq_to_runq)
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate	.align 16
8787c478bd9Sstevel@tonic-gate	ENTRY(kstat_runq_back_to_waitq)
8797c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%g1, %g2, %g3)
880*6e7bd672SToomas Soome#if defined(DEBUG)
8817c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_R)
882*6e7bd672SToomas Soome#else
883*6e7bd672SToomas Soome	KSTAT_Q_UPDATE_ND(sub, 1:, KSTAT_IO_R)
884*6e7bd672SToomas Soome#endif
8857c478bd9Sstevel@tonic-gate	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W)
8867c478bd9Sstevel@tonic-gate	SET_SIZE(kstat_runq_back_to_waitq)
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate#endif	/* !(lint || __lint) */
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate#ifdef lint
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gateint64_t timedelta;
8937c478bd9Sstevel@tonic-gatehrtime_t hres_last_tick;
894b5b48cc1Ssudheervolatile timestruc_t hrestime;
8957c478bd9Sstevel@tonic-gateint64_t hrestime_adj;
896b5b48cc1Ssudheervolatile int hres_lock;
8977c478bd9Sstevel@tonic-gateuint_t nsec_scale;
8987c478bd9Sstevel@tonic-gatehrtime_t hrtime_base;
8997c478bd9Sstevel@tonic-gateint traptrace_use_stick;
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate#else	/* lint */
9027c478bd9Sstevel@tonic-gate	/*
9037c478bd9Sstevel@tonic-gate	 *  -- WARNING --
9047c478bd9Sstevel@tonic-gate	 *
9057c478bd9Sstevel@tonic-gate	 * The following variables MUST be together on a 128-byte boundary.
9067c478bd9Sstevel@tonic-gate	 * In addition to the primary performance motivation (having them all
9077c478bd9Sstevel@tonic-gate	 * on the same cache line(s)), code here and in the GET*TIME() macros
9087c478bd9Sstevel@tonic-gate	 * assumes that they all have the same high 22 address bits (so
9097c478bd9Sstevel@tonic-gate	 * there's only one sethi).
9107c478bd9Sstevel@tonic-gate	 */
9117c478bd9Sstevel@tonic-gate	.seg	".data"
9127c478bd9Sstevel@tonic-gate	.global	timedelta, hres_last_tick, hrestime, hrestime_adj
9137c478bd9Sstevel@tonic-gate	.global	hres_lock, nsec_scale, hrtime_base, traptrace_use_stick
9147c478bd9Sstevel@tonic-gate	.global	nsec_shift, adj_shift
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate	/* XXX - above comment claims 128-bytes is necessary */
9177c478bd9Sstevel@tonic-gate	.align	64
9187c478bd9Sstevel@tonic-gatetimedelta:
9197c478bd9Sstevel@tonic-gate	.word	0, 0		/* int64_t */
9207c478bd9Sstevel@tonic-gatehres_last_tick:
9217c478bd9Sstevel@tonic-gate	.word	0, 0		/* hrtime_t */
9227c478bd9Sstevel@tonic-gatehrestime:
9237c478bd9Sstevel@tonic-gate	.nword	0, 0		/* 2 longs */
9247c478bd9Sstevel@tonic-gatehrestime_adj:
9257c478bd9Sstevel@tonic-gate	.word	0, 0		/* int64_t */
9267c478bd9Sstevel@tonic-gatehres_lock:
9277c478bd9Sstevel@tonic-gate	.word	0
9287c478bd9Sstevel@tonic-gatensec_scale:
9297c478bd9Sstevel@tonic-gate	.word	0
9307c478bd9Sstevel@tonic-gatehrtime_base:
9317c478bd9Sstevel@tonic-gate	.word	0, 0
9327c478bd9Sstevel@tonic-gatetraptrace_use_stick:
9337c478bd9Sstevel@tonic-gate	.word	0
9347c478bd9Sstevel@tonic-gatensec_shift:
9357c478bd9Sstevel@tonic-gate	.word	NSEC_SHIFT
9367c478bd9Sstevel@tonic-gateadj_shift:
9377c478bd9Sstevel@tonic-gate	.word	ADJ_SHIFT
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate#endif	/* lint */
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate/*
9437c478bd9Sstevel@tonic-gate * drv_usecwait(clock_t n)	[DDI/DKI - section 9F]
9447c478bd9Sstevel@tonic-gate * usec_delay(int n)		[compatibility - should go one day]
9457c478bd9Sstevel@tonic-gate * Delay by spinning.
9467c478bd9Sstevel@tonic-gate *
9477c478bd9Sstevel@tonic-gate * delay for n microseconds.  numbers <= 0 delay 1 usec
9487c478bd9Sstevel@tonic-gate *
9497c478bd9Sstevel@tonic-gate * With UltraSPARC-III the combination of supporting mixed-speed CPUs
9507c478bd9Sstevel@tonic-gate * and variable clock rate for power management requires that we
9517c478bd9Sstevel@tonic-gate * use %stick to implement this routine.
95225cf1a30Sjl139090 *
95325cf1a30Sjl139090 * For OPL platforms that support the "sleep" instruction, we
95425cf1a30Sjl139090 * conditionally (ifdef'ed) insert a "sleep" instruction in
95525cf1a30Sjl139090 * the loop. Note that theoritically we should have move (duplicated)
95625cf1a30Sjl139090 * the code down to spitfire/us3/opl specific asm files - but this
95725cf1a30Sjl139090 * is alot of code duplication just to add one "sleep" instruction.
95825cf1a30Sjl139090 * We chose less code duplication for this.
9597c478bd9Sstevel@tonic-gate */
9607c478bd9Sstevel@tonic-gate
9617c478bd9Sstevel@tonic-gate#if defined(lint)
9627c478bd9Sstevel@tonic-gate
9637c478bd9Sstevel@tonic-gate/*ARGSUSED*/
9647c478bd9Sstevel@tonic-gatevoid
9657c478bd9Sstevel@tonic-gatedrv_usecwait(clock_t n)
9667c478bd9Sstevel@tonic-gate{}
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate/*ARGSUSED*/
9697c478bd9Sstevel@tonic-gatevoid
9707c478bd9Sstevel@tonic-gateusec_delay(int n)
9717c478bd9Sstevel@tonic-gate{}
9727c478bd9Sstevel@tonic-gate
9737c478bd9Sstevel@tonic-gate#else	/* lint */
9747c478bd9Sstevel@tonic-gate
9757c478bd9Sstevel@tonic-gate	ENTRY(drv_usecwait)
9767c478bd9Sstevel@tonic-gate	ALTENTRY(usec_delay)
9777c478bd9Sstevel@tonic-gate	brlez,a,pn %o0, 0f
9787c478bd9Sstevel@tonic-gate	mov	1, %o0
9797c478bd9Sstevel@tonic-gate0:
9807c478bd9Sstevel@tonic-gate	sethi	%hi(sticks_per_usec), %o1
9817c478bd9Sstevel@tonic-gate	lduw	[%o1 + %lo(sticks_per_usec)], %o1
9827c478bd9Sstevel@tonic-gate	mulx	%o1, %o0, %o1		! Scale usec to ticks
9837c478bd9Sstevel@tonic-gate	inc	%o1			! We don't start on a tick edge
9847c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o2, %o3, %o4)
9857c478bd9Sstevel@tonic-gate	add	%o1, %o2, %o1
9867c478bd9Sstevel@tonic-gate
98725cf1a30Sjl1390901:
98825cf1a30Sjl139090#ifdef	_OPL
98925cf1a30Sjl139090	.word 0x81b01060		! insert "sleep" instruction
99025cf1a30Sjl139090#endif /* _OPL */			! use byte code for now
99125cf1a30Sjl139090	cmp	%o1, %o2
9927c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o2, %o3, %o4)
9937c478bd9Sstevel@tonic-gate	bgeu,pt	%xcc, 1b
9947c478bd9Sstevel@tonic-gate	nop
9957c478bd9Sstevel@tonic-gate	retl
9967c478bd9Sstevel@tonic-gate	nop
9977c478bd9Sstevel@tonic-gate	SET_SIZE(usec_delay)
9987c478bd9Sstevel@tonic-gate	SET_SIZE(drv_usecwait)
9997c478bd9Sstevel@tonic-gate#endif	/* lint */
10007c478bd9Sstevel@tonic-gate
10017c478bd9Sstevel@tonic-gate#if defined(lint)
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate/* ARGSUSED */
10047c478bd9Sstevel@tonic-gatevoid
10057c478bd9Sstevel@tonic-gatepil14_interrupt(int level)
10067c478bd9Sstevel@tonic-gate{}
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate#else	/* lint */
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate/*
10117c478bd9Sstevel@tonic-gate * Level-14 interrupt prologue.
10127c478bd9Sstevel@tonic-gate */
10137c478bd9Sstevel@tonic-gate	ENTRY_NP(pil14_interrupt)
10147c478bd9Sstevel@tonic-gate	CPU_ADDR(%g1, %g2)
10157c478bd9Sstevel@tonic-gate	rdpr	%pil, %g6			! %g6 = interrupted PIL
10167c478bd9Sstevel@tonic-gate	stn	%g6, [%g1 + CPU_PROFILE_PIL]	! record interrupted PIL
10177c478bd9Sstevel@tonic-gate	rdpr	%tstate, %g6
10187c478bd9Sstevel@tonic-gate	rdpr	%tpc, %g5
10197c478bd9Sstevel@tonic-gate	btst	TSTATE_PRIV, %g6		! trap from supervisor mode?
10207c478bd9Sstevel@tonic-gate	bnz,a,pt %xcc, 1f
10217c478bd9Sstevel@tonic-gate	stn	%g5, [%g1 + CPU_PROFILE_PC]	! if so, record kernel PC
10227c478bd9Sstevel@tonic-gate	stn	%g5, [%g1 + CPU_PROFILE_UPC]	! if not, record user PC
10237c478bd9Sstevel@tonic-gate	ba	pil_interrupt_common		! must be large-disp branch
10247c478bd9Sstevel@tonic-gate	stn	%g0, [%g1 + CPU_PROFILE_PC]	! zero kernel PC
10257c478bd9Sstevel@tonic-gate1:	ba	pil_interrupt_common		! must be large-disp branch
10267c478bd9Sstevel@tonic-gate	stn	%g0, [%g1 + CPU_PROFILE_UPC]	! zero user PC
10277c478bd9Sstevel@tonic-gate	SET_SIZE(pil14_interrupt)
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate	ENTRY_NP(tick_rtt)
10307c478bd9Sstevel@tonic-gate	!
10317c478bd9Sstevel@tonic-gate	! Load TICK_COMPARE into %o5; if bit 63 is set, then TICK_COMPARE is
10327c478bd9Sstevel@tonic-gate	! disabled.  If TICK_COMPARE is enabled, we know that we need to
10337c478bd9Sstevel@tonic-gate	! reenqueue the interrupt request structure.  We'll then check TICKINT
10347c478bd9Sstevel@tonic-gate	! in SOFTINT; if it's set, then we know that we were in a TICK_COMPARE
10357c478bd9Sstevel@tonic-gate	! interrupt.  In this case, TICK_COMPARE may have been rewritten
10367c478bd9Sstevel@tonic-gate	! recently; we'll compare %o5 to the current time to verify that it's
10377c478bd9Sstevel@tonic-gate	! in the future.
10387c478bd9Sstevel@tonic-gate	!
10397c478bd9Sstevel@tonic-gate	! Note that %o5 is live until after 1f.
10407c478bd9Sstevel@tonic-gate	! XXX - there is a subroutine call while %o5 is live!
10417c478bd9Sstevel@tonic-gate	!
10427c478bd9Sstevel@tonic-gate	RD_TICKCMPR(%o5, %g1)
10437c478bd9Sstevel@tonic-gate	srlx	%o5, TICKINT_DIS_SHFT, %g1
10447c478bd9Sstevel@tonic-gate	brnz,pt	%g1, 2f
10457c478bd9Sstevel@tonic-gate	nop
10467c478bd9Sstevel@tonic-gate
10477c478bd9Sstevel@tonic-gate	rdpr 	%pstate, %g5
10487c478bd9Sstevel@tonic-gate	andn	%g5, PSTATE_IE, %g1
10497c478bd9Sstevel@tonic-gate	wrpr	%g0, %g1, %pstate		! Disable vec interrupts
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate	sethi	%hi(cbe_level14_inum), %o1
1052b0fc0e77Sgovinda	ldx	[%o1 + %lo(cbe_level14_inum)], %o1
10537c478bd9Sstevel@tonic-gate	call	intr_enqueue_req ! preserves %o5 and %g5
10547c478bd9Sstevel@tonic-gate	mov	PIL_14, %o0
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate	! Check SOFTINT for TICKINT/STICKINT
10577c478bd9Sstevel@tonic-gate	rd	SOFTINT, %o4
10587c478bd9Sstevel@tonic-gate	set	(TICK_INT_MASK | STICK_INT_MASK), %o0
10597c478bd9Sstevel@tonic-gate	andcc	%o4, %o0, %g0
10607c478bd9Sstevel@tonic-gate	bz,a,pn	%icc, 2f
10617c478bd9Sstevel@tonic-gate	wrpr	%g0, %g5, %pstate		! Enable vec interrupts
10627c478bd9Sstevel@tonic-gate
10637c478bd9Sstevel@tonic-gate	! clear TICKINT/STICKINT
10647c478bd9Sstevel@tonic-gate	wr	%o0, CLEAR_SOFTINT
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate	!
10677c478bd9Sstevel@tonic-gate	! Now that we've cleared TICKINT, we can reread %tick and confirm
10687c478bd9Sstevel@tonic-gate	! that the value we programmed is still in the future.  If it isn't,
10697c478bd9Sstevel@tonic-gate	! we need to reprogram TICK_COMPARE to fire as soon as possible.
10707c478bd9Sstevel@tonic-gate	!
10717c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o0, %g1, %g2)		! %o0 = tick
10727c478bd9Sstevel@tonic-gate	sllx	%o0, 1, %o0			! Clear the DIS bit
10737c478bd9Sstevel@tonic-gate	srlx	%o0, 1, %o0
10747c478bd9Sstevel@tonic-gate	cmp	%o5, %o0			! In the future?
10757c478bd9Sstevel@tonic-gate	bg,a,pt	%xcc, 2f			! Yes, drive on.
10767c478bd9Sstevel@tonic-gate	wrpr	%g0, %g5, %pstate		!   delay: enable vec intr
10777c478bd9Sstevel@tonic-gate
10787c478bd9Sstevel@tonic-gate	!
10797c478bd9Sstevel@tonic-gate	! If we're here, then we have programmed TICK_COMPARE with a %tick
10807c478bd9Sstevel@tonic-gate	! which is in the past; we'll now load an initial step size, and loop
10817c478bd9Sstevel@tonic-gate	! until we've managed to program TICK_COMPARE to fire in the future.
10827c478bd9Sstevel@tonic-gate	!
10837c478bd9Sstevel@tonic-gate	mov	8, %o4				! 8 = arbitrary inital step
10847c478bd9Sstevel@tonic-gate1:	add	%o0, %o4, %o5			! Add the step
10857c478bd9Sstevel@tonic-gate	WR_TICKCMPR(%o5,%g1,%g2,__LINE__)	! Write to TICK_CMPR
10867c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o0, %g1, %g2)		! %o0 = tick
10877c478bd9Sstevel@tonic-gate	sllx	%o0, 1, %o0			! Clear the DIS bit
10887c478bd9Sstevel@tonic-gate	srlx	%o0, 1, %o0
10897c478bd9Sstevel@tonic-gate	cmp	%o5, %o0			! In the future?
10907c478bd9Sstevel@tonic-gate	bg,a,pt	%xcc, 2f			! Yes, drive on.
10917c478bd9Sstevel@tonic-gate	wrpr	%g0, %g5, %pstate		!    delay: enable vec intr
10927c478bd9Sstevel@tonic-gate	ba	1b				! No, try again.
10937c478bd9Sstevel@tonic-gate	sllx	%o4, 1, %o4			!    delay: double step size
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate2:	ba	current_thread_complete
10967c478bd9Sstevel@tonic-gate	nop
10977c478bd9Sstevel@tonic-gate	SET_SIZE(tick_rtt)
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate#endif	/* lint */
11007c478bd9Sstevel@tonic-gate
1101b9e93c10SJonathan Haslam#if defined(lint)
1102b9e93c10SJonathan Haslam
1103b9e93c10SJonathan Haslam/* ARGSUSED */
1104b9e93c10SJonathan Haslamvoid
1105b9e93c10SJonathan Haslampil15_interrupt(int level)
1106b9e93c10SJonathan Haslam{}
1107b9e93c10SJonathan Haslam
1108b9e93c10SJonathan Haslam#else  /* lint */
1109b9e93c10SJonathan Haslam
1110b9e93c10SJonathan Haslam/*
1111b9e93c10SJonathan Haslam * Level-15 interrupt prologue.
1112b9e93c10SJonathan Haslam */
1113b9e93c10SJonathan Haslam       ENTRY_NP(pil15_interrupt)
1114b9e93c10SJonathan Haslam       CPU_ADDR(%g1, %g2)
1115b9e93c10SJonathan Haslam       rdpr    %tstate, %g6
1116b9e93c10SJonathan Haslam       rdpr    %tpc, %g5
1117b9e93c10SJonathan Haslam       btst    TSTATE_PRIV, %g6                ! trap from supervisor mode?
1118b9e93c10SJonathan Haslam       bnz,a,pt %xcc, 1f
1119b9e93c10SJonathan Haslam       stn     %g5, [%g1 + CPU_CPCPROFILE_PC]  ! if so, record kernel PC
1120b9e93c10SJonathan Haslam       stn     %g5, [%g1 + CPU_CPCPROFILE_UPC] ! if not, record user PC
1121b9e93c10SJonathan Haslam       ba      pil15_epilogue                  ! must be large-disp branch
1122b9e93c10SJonathan Haslam       stn     %g0, [%g1 + CPU_CPCPROFILE_PC]  ! zero kernel PC
1123b9e93c10SJonathan Haslam1:     ba      pil15_epilogue                  ! must be large-disp branch
1124b9e93c10SJonathan Haslam       stn     %g0, [%g1 + CPU_CPCPROFILE_UPC] ! zero user PC
1125b9e93c10SJonathan Haslam       SET_SIZE(pil15_interrupt)
1126b9e93c10SJonathan Haslam
1127b9e93c10SJonathan Haslam#endif /* lint */
1128b9e93c10SJonathan Haslam
11297c478bd9Sstevel@tonic-gate#if defined(lint) || defined(__lint)
11307c478bd9Sstevel@tonic-gate
11317c478bd9Sstevel@tonic-gate/* ARGSUSED */
11327c478bd9Sstevel@tonic-gateuint64_t
11337c478bd9Sstevel@tonic-gatefind_cpufrequency(volatile uchar_t *clock_ptr)
11347c478bd9Sstevel@tonic-gate{
11357c478bd9Sstevel@tonic-gate	return (0);
11367c478bd9Sstevel@tonic-gate}
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate#else	/* lint */
11397c478bd9Sstevel@tonic-gate
11407c478bd9Sstevel@tonic-gate#ifdef DEBUG
11417c478bd9Sstevel@tonic-gate	.seg	".text"
11427c478bd9Sstevel@tonic-gatefind_cpufreq_panic:
11437c478bd9Sstevel@tonic-gate	.asciz	"find_cpufrequency: interrupts already disabled on entry"
11447c478bd9Sstevel@tonic-gate#endif	/* DEBUG */
11457c478bd9Sstevel@tonic-gate
11467c478bd9Sstevel@tonic-gate	ENTRY_NP(find_cpufrequency)
11477c478bd9Sstevel@tonic-gate	rdpr	%pstate, %g1
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate#ifdef DEBUG
11507c478bd9Sstevel@tonic-gate	andcc	%g1, PSTATE_IE, %g0	! If DEBUG, check that interrupts
11517c478bd9Sstevel@tonic-gate	bnz	0f			! are currently enabled
11527c478bd9Sstevel@tonic-gate	sethi	%hi(find_cpufreq_panic), %o1
11537c478bd9Sstevel@tonic-gate	call	panic
11547c478bd9Sstevel@tonic-gate	or	%o1, %lo(find_cpufreq_panic), %o0
11557c478bd9Sstevel@tonic-gate#endif	/* DEBUG */
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate0:
11587c478bd9Sstevel@tonic-gate	wrpr	%g1, PSTATE_IE, %pstate	! Disable interrupts
11597c478bd9Sstevel@tonic-gate3:
11607c478bd9Sstevel@tonic-gate	ldub	[%o0], %o1		! Read the number of seconds
11617c478bd9Sstevel@tonic-gate	mov	%o1, %o2		! remember initial value in %o2
11627c478bd9Sstevel@tonic-gate1:
11637c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o3, %g4, %g5)
11647c478bd9Sstevel@tonic-gate	cmp	%o1, %o2		! did the seconds register roll over?
11657c478bd9Sstevel@tonic-gate	be,pt	%icc, 1b		! branch back if unchanged
11667c478bd9Sstevel@tonic-gate	ldub	[%o0], %o2		!   delay: load the new seconds val
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate	brz,pn	%o2, 3b			! if the minutes just rolled over,
11697c478bd9Sstevel@tonic-gate					! the last second could have been
11707c478bd9Sstevel@tonic-gate					! inaccurate; try again.
11717c478bd9Sstevel@tonic-gate	mov	%o2, %o4		!   delay: store init. val. in %o2
11727c478bd9Sstevel@tonic-gate2:
11737c478bd9Sstevel@tonic-gate	GET_NATIVE_TIME(%o5, %g4, %g5)
11747c478bd9Sstevel@tonic-gate	cmp	%o2, %o4		! did the seconds register roll over?
11757c478bd9Sstevel@tonic-gate	be,pt	%icc, 2b		! branch back if unchanged
11767c478bd9Sstevel@tonic-gate	ldub	[%o0], %o4		!   delay: load the new seconds val
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate	brz,pn	%o4, 0b			! if the minutes just rolled over,
11797c478bd9Sstevel@tonic-gate					! the last second could have been
11807c478bd9Sstevel@tonic-gate					! inaccurate; try again.
11817c478bd9Sstevel@tonic-gate	wrpr	%g0, %g1, %pstate	!   delay: re-enable interrupts
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate	retl
11847c478bd9Sstevel@tonic-gate	sub	%o5, %o3, %o0		! return the difference in ticks
11857c478bd9Sstevel@tonic-gate	SET_SIZE(find_cpufrequency)
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate#endif	/* lint */
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate#if defined(lint)
11907c478bd9Sstevel@tonic-gate/*
11917c478bd9Sstevel@tonic-gate * Prefetch a page_t for write or read, this assumes a linear
11927c478bd9Sstevel@tonic-gate * scan of sequential page_t's.
11937c478bd9Sstevel@tonic-gate */
11947c478bd9Sstevel@tonic-gate/*ARGSUSED*/
11957c478bd9Sstevel@tonic-gatevoid
11967c478bd9Sstevel@tonic-gateprefetch_page_w(void *pp)
11977c478bd9Sstevel@tonic-gate{}
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate/*ARGSUSED*/
12007c478bd9Sstevel@tonic-gatevoid
12017c478bd9Sstevel@tonic-gateprefetch_page_r(void *pp)
12027c478bd9Sstevel@tonic-gate{}
12037c478bd9Sstevel@tonic-gate#else	/* lint */
12047c478bd9Sstevel@tonic-gate
12057c478bd9Sstevel@tonic-gate#if defined(CHEETAH) || defined(CHEETAH_PLUS) || defined(JALAPENO) || \
12067c478bd9Sstevel@tonic-gate	defined(SERRANO)
12077c478bd9Sstevel@tonic-gate	!
12087c478bd9Sstevel@tonic-gate	! On US-III, the prefetch instruction queue is 8 entries deep.
12097c478bd9Sstevel@tonic-gate	! Also, prefetches for write put data in the E$, which has
12107c478bd9Sstevel@tonic-gate	! lines of 512 bytes for an 8MB cache. Each E$ line is further
12117c478bd9Sstevel@tonic-gate	! subblocked into 64 byte chunks.
12127c478bd9Sstevel@tonic-gate	!
12137c478bd9Sstevel@tonic-gate	! Since prefetch can only bring in 64 bytes at a time (See Sparc
12147c478bd9Sstevel@tonic-gate	! v9 Architecture Manual pp.204) and a page_t is 128 bytes,
12157c478bd9Sstevel@tonic-gate	! then 2 prefetches are required in order to bring an entire
12167c478bd9Sstevel@tonic-gate	! page into the E$.
12177c478bd9Sstevel@tonic-gate	!
12187c478bd9Sstevel@tonic-gate	! Since the prefetch queue is 8 entries deep, we currently can
12197c478bd9Sstevel@tonic-gate	! only have 4 prefetches for page_t's outstanding. Thus, we
12207c478bd9Sstevel@tonic-gate	! prefetch n+4 ahead of where we are now:
12217c478bd9Sstevel@tonic-gate	!
12227c478bd9Sstevel@tonic-gate	!      4 * sizeof(page_t)     -> 512
12237c478bd9Sstevel@tonic-gate	!      4 * sizeof(page_t) +64 -> 576
12247c478bd9Sstevel@tonic-gate	!
12257c478bd9Sstevel@tonic-gate	! Example
12267c478bd9Sstevel@tonic-gate	! =======
12277c478bd9Sstevel@tonic-gate	! contiguous page array in memory...
12287c478bd9Sstevel@tonic-gate	!
12297c478bd9Sstevel@tonic-gate	! |AAA1|AAA2|BBB1|BBB2|CCC1|CCC2|DDD1|DDD2|XXX1|XXX2|YYY1|YYY2|...
12307c478bd9Sstevel@tonic-gate	! ^         ^         ^         ^         ^    ^
12317c478bd9Sstevel@tonic-gate	! pp                                      |    pp+4*sizeof(page)+64
12327c478bd9Sstevel@tonic-gate	!                                         |
12337c478bd9Sstevel@tonic-gate	!                                         pp+4*sizeof(page)
12347c478bd9Sstevel@tonic-gate	!
12357c478bd9Sstevel@tonic-gate	!  Prefetch
12367c478bd9Sstevel@tonic-gate	!   Queue
12377c478bd9Sstevel@tonic-gate	! +-------+<--- In this iteration, we're working with pp (AAA1),
12387c478bd9Sstevel@tonic-gate	! |Preftch|     but we enqueue prefetch for addr = XXX1
12397c478bd9Sstevel@tonic-gate	! | XXX1  |
12407c478bd9Sstevel@tonic-gate	! +-------+<--- this queue slot will be a prefetch instruction for
12417c478bd9Sstevel@tonic-gate	! |Preftch|     for addr = pp + 4*sizeof(page_t) + 64 (or second
12427c478bd9Sstevel@tonic-gate	! | XXX2  |     half of page XXX)
12437c478bd9Sstevel@tonic-gate	! +-------+
12447c478bd9Sstevel@tonic-gate	! |Preftch|<-+- The next time around this function, we'll be
12457c478bd9Sstevel@tonic-gate	! | YYY1  |  |  working with pp = BBB1, but will be enqueueing
12467c478bd9Sstevel@tonic-gate	! +-------+  |  prefetches to for both halves of page YYY,
12477c478bd9Sstevel@tonic-gate	! |Preftch|  |  while both halves of page XXX are in transit
12487c478bd9Sstevel@tonic-gate	! | YYY2  |<-+  make their way into the E$.
12497c478bd9Sstevel@tonic-gate	! +-------+
12507c478bd9Sstevel@tonic-gate	! |Preftch|
12517c478bd9Sstevel@tonic-gate	! | ZZZ1  |
12527c478bd9Sstevel@tonic-gate	! +-------+
12537c478bd9Sstevel@tonic-gate	! .       .
12547c478bd9Sstevel@tonic-gate	! :       :
12557c478bd9Sstevel@tonic-gate	!
12567c478bd9Sstevel@tonic-gate	!  E$
12577c478bd9Sstevel@tonic-gate	! +============================================...
12587c478bd9Sstevel@tonic-gate	! | XXX1 | XXX2 | YYY1 | YYY2 | ZZZ1 | ZZZ2 |
12597c478bd9Sstevel@tonic-gate	! +============================================...
12607c478bd9Sstevel@tonic-gate	! |      |      |      |      |      |      |
12617c478bd9Sstevel@tonic-gate	! +============================================...
12627c478bd9Sstevel@tonic-gate	! .
12637c478bd9Sstevel@tonic-gate	! :
12647c478bd9Sstevel@tonic-gate	!
12657c478bd9Sstevel@tonic-gate	! So we should expect the first four page accesses to stall
12667c478bd9Sstevel@tonic-gate	! while we warm up the cache, afterwhich, most of the pages
12677c478bd9Sstevel@tonic-gate	! will have their pp ready in the E$.
12687c478bd9Sstevel@tonic-gate	!
12697c478bd9Sstevel@tonic-gate	! Also note that if sizeof(page_t) grows beyond 128, then
12707c478bd9Sstevel@tonic-gate	! we'll need an additional prefetch to get an entire page
12717c478bd9Sstevel@tonic-gate	! into the E$, thus reducing the number of outstanding page
12727c478bd9Sstevel@tonic-gate	! prefetches to 2 (ie. 3 prefetches/page = 6 queue slots)
12737c478bd9Sstevel@tonic-gate	! etc.
12747c478bd9Sstevel@tonic-gate	!
12757c478bd9Sstevel@tonic-gate	! Cheetah+
12767c478bd9Sstevel@tonic-gate	! ========
12777c478bd9Sstevel@tonic-gate	! On Cheetah+ we use "#n_write" prefetches as these avoid
12787c478bd9Sstevel@tonic-gate	! unnecessary RTS->RTO bus transaction state change, and
12797c478bd9Sstevel@tonic-gate	! just issues RTO transaction. (See pp.77 of Cheetah+ Delta
12807c478bd9Sstevel@tonic-gate	! PRM). On Cheetah, #n_write prefetches are reflected with
12817c478bd9Sstevel@tonic-gate	! RTS->RTO state transition regardless.
12827c478bd9Sstevel@tonic-gate	!
12837c478bd9Sstevel@tonic-gate#define STRIDE1 512
12847c478bd9Sstevel@tonic-gate#define STRIDE2 576
12857c478bd9Sstevel@tonic-gate
12867c478bd9Sstevel@tonic-gate#if	STRIDE1 != (PAGE_SIZE * 4)
12877c478bd9Sstevel@tonic-gate#error	"STRIDE1 != (PAGE_SIZE * 4)"
12887c478bd9Sstevel@tonic-gate#endif	/* STRIDE1 != (PAGE_SIZE * 4) */
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate        ENTRY(prefetch_page_w)
12917c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE1], #n_writes
12927c478bd9Sstevel@tonic-gate        retl
12937c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE2], #n_writes
12947c478bd9Sstevel@tonic-gate        SET_SIZE(prefetch_page_w)
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate	!
12977c478bd9Sstevel@tonic-gate	! Note on CHEETAH to prefetch for read, we really use #one_write.
12987c478bd9Sstevel@tonic-gate	! This fetches to E$ (general use) rather than P$ (floating point use).
12997c478bd9Sstevel@tonic-gate	!
13007c478bd9Sstevel@tonic-gate        ENTRY(prefetch_page_r)
13017c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE1], #one_write
13027c478bd9Sstevel@tonic-gate        retl
13037c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE2], #one_write
13047c478bd9Sstevel@tonic-gate        SET_SIZE(prefetch_page_r)
13057c478bd9Sstevel@tonic-gate
13067c478bd9Sstevel@tonic-gate#elif defined(SPITFIRE) || defined(HUMMINGBIRD)
13077c478bd9Sstevel@tonic-gate
13087c478bd9Sstevel@tonic-gate	!
13097c478bd9Sstevel@tonic-gate	! UltraSparcII can have up to 3 prefetches outstanding.
13107c478bd9Sstevel@tonic-gate	! A page_t is 128 bytes (2 prefetches of 64 bytes each)
13117c478bd9Sstevel@tonic-gate	! So prefetch for pp + 1, which is
13127c478bd9Sstevel@tonic-gate	!
13137c478bd9Sstevel@tonic-gate	!       pp + sizeof(page_t)
13147c478bd9Sstevel@tonic-gate	! and
13157c478bd9Sstevel@tonic-gate	!       pp + sizeof(page_t) + 64
13167c478bd9Sstevel@tonic-gate	!
13177c478bd9Sstevel@tonic-gate#define STRIDE1	128
13187c478bd9Sstevel@tonic-gate#define STRIDE2	192
13197c478bd9Sstevel@tonic-gate
13207c478bd9Sstevel@tonic-gate#if	STRIDE1 != PAGE_SIZE
13217c478bd9Sstevel@tonic-gate#error	"STRIDE1 != PAGE_SIZE"
13227c478bd9Sstevel@tonic-gate#endif	/* STRIDE1 != PAGE_SIZE */
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate        ENTRY(prefetch_page_w)
13257c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE1], #n_writes
13267c478bd9Sstevel@tonic-gate        retl
13277c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE2], #n_writes
13287c478bd9Sstevel@tonic-gate        SET_SIZE(prefetch_page_w)
13297c478bd9Sstevel@tonic-gate
13307c478bd9Sstevel@tonic-gate        ENTRY(prefetch_page_r)
13317c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE1], #n_reads
13327c478bd9Sstevel@tonic-gate        retl
13337c478bd9Sstevel@tonic-gate        prefetch        [%o0+STRIDE2], #n_reads
13347c478bd9Sstevel@tonic-gate        SET_SIZE(prefetch_page_r)
133525cf1a30Sjl139090
133625cf1a30Sjl139090#elif defined(OLYMPUS_C)
133725cf1a30Sjl139090	!
133825cf1a30Sjl139090	! Prefetch strides for Olympus-C
133925cf1a30Sjl139090	!
134025cf1a30Sjl139090
1341e4896ad2Shyw#define STRIDE1	0x440
1342e4896ad2Shyw#define STRIDE2	0x640
134325cf1a30Sjl139090
134425cf1a30Sjl139090	ENTRY(prefetch_page_w)
134525cf1a30Sjl139090        prefetch        [%o0+STRIDE1], #n_writes
134625cf1a30Sjl139090	retl
134725cf1a30Sjl139090        prefetch        [%o0+STRIDE2], #n_writes
134825cf1a30Sjl139090	SET_SIZE(prefetch_page_w)
134925cf1a30Sjl139090
135025cf1a30Sjl139090	ENTRY(prefetch_page_r)
135125cf1a30Sjl139090        prefetch        [%o0+STRIDE1], #n_writes
135225cf1a30Sjl139090	retl
135325cf1a30Sjl139090        prefetch        [%o0+STRIDE2], #n_writes
135425cf1a30Sjl139090	SET_SIZE(prefetch_page_r)
135525cf1a30Sjl139090#else	/* OLYMPUS_C */
13567c478bd9Sstevel@tonic-gate
13577c478bd9Sstevel@tonic-gate#error "You need to fix this for your new cpu type."
13587c478bd9Sstevel@tonic-gate
135925cf1a30Sjl139090#endif	/* OLYMPUS_C */
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate#endif	/* lint */
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate#if defined(lint)
13647c478bd9Sstevel@tonic-gate/*
13657c478bd9Sstevel@tonic-gate * Prefetch struct smap for write.
13667c478bd9Sstevel@tonic-gate */
13677c478bd9Sstevel@tonic-gate/*ARGSUSED*/
13687c478bd9Sstevel@tonic-gatevoid
13697c478bd9Sstevel@tonic-gateprefetch_smap_w(void *smp)
13707c478bd9Sstevel@tonic-gate{}
13717c478bd9Sstevel@tonic-gate#else	/* lint */
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate#if defined(CHEETAH) || defined(CHEETAH_PLUS) || defined(JALAPENO) || \
13747c478bd9Sstevel@tonic-gate	defined(SERRANO)
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate#define	PREFETCH_Q_LEN 8
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate#elif defined(SPITFIRE) || defined(HUMMINGBIRD)
13797c478bd9Sstevel@tonic-gate
13807c478bd9Sstevel@tonic-gate#define	PREFETCH_Q_LEN 3
13817c478bd9Sstevel@tonic-gate
138225cf1a30Sjl139090#elif defined(OLYMPUS_C)
138325cf1a30Sjl139090	!
1384e4896ad2Shyw	! Use length of one for now.
1385e4896ad2Shyw	!
138625cf1a30Sjl139090#define	PREFETCH_Q_LEN	1
138725cf1a30Sjl139090
138825cf1a30Sjl139090#else 	/* OLYMPUS_C */
13897c478bd9Sstevel@tonic-gate
13907c478bd9Sstevel@tonic-gate#error You need to fix this for your new cpu type.
13917c478bd9Sstevel@tonic-gate
139225cf1a30Sjl139090#endif	/* OLYMPUS_C */
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate#include <vm/kpm.h>
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate#ifdef	SEGKPM_SUPPORT
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate#define	SMAP_SIZE 72
13997c478bd9Sstevel@tonic-gate#define SMAP_STRIDE (((PREFETCH_Q_LEN * 64) / SMAP_SIZE) * 64)
14007c478bd9Sstevel@tonic-gate
14017c478bd9Sstevel@tonic-gate#else	/* SEGKPM_SUPPORT */
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate	!
14047c478bd9Sstevel@tonic-gate	! The hardware will prefetch the 64 byte cache aligned block
14057c478bd9Sstevel@tonic-gate	! that contains the address specified in the prefetch instruction.
14067c478bd9Sstevel@tonic-gate	! Since the size of the smap struct is 48 bytes, issuing 1 prefetch
14077c478bd9Sstevel@tonic-gate	! per pass will suffice as long as we prefetch far enough ahead to
14087c478bd9Sstevel@tonic-gate	! make sure we don't stall for the cases where the smap object
14097c478bd9Sstevel@tonic-gate	! spans multiple hardware prefetch blocks.  Let's prefetch as far
14107c478bd9Sstevel@tonic-gate	! ahead as the hardware will allow.
14117c478bd9Sstevel@tonic-gate	!
14127c478bd9Sstevel@tonic-gate	! The smap array is processed with decreasing address pointers.
14137c478bd9Sstevel@tonic-gate	!
14147c478bd9Sstevel@tonic-gate#define	SMAP_SIZE 48
14157c478bd9Sstevel@tonic-gate#define	SMAP_STRIDE (PREFETCH_Q_LEN * SMAP_SIZE)
14167c478bd9Sstevel@tonic-gate
14177c478bd9Sstevel@tonic-gate#endif	/* SEGKPM_SUPPORT */
14187c478bd9Sstevel@tonic-gate
14197c478bd9Sstevel@tonic-gate	ENTRY(prefetch_smap_w)
14207c478bd9Sstevel@tonic-gate	retl
14217c478bd9Sstevel@tonic-gate	prefetch	[%o0-SMAP_STRIDE], #n_writes
14227c478bd9Sstevel@tonic-gate	SET_SIZE(prefetch_smap_w)
14237c478bd9Sstevel@tonic-gate
14247c478bd9Sstevel@tonic-gate#endif	/* lint */
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate#if defined(lint) || defined(__lint)
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate/* ARGSUSED */
14297c478bd9Sstevel@tonic-gateuint64_t
14307c478bd9Sstevel@tonic-gategetidsr(void)
14317c478bd9Sstevel@tonic-gate{ return 0; }
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate#else	/* lint */
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate	ENTRY_NP(getidsr)
14367c478bd9Sstevel@tonic-gate	retl
14377c478bd9Sstevel@tonic-gate	ldxa	[%g0]ASI_INTR_DISPATCH_STATUS, %o0
14387c478bd9Sstevel@tonic-gate	SET_SIZE(getidsr)
14397c478bd9Sstevel@tonic-gate
14407c478bd9Sstevel@tonic-gate#endif	/* lint */
1441