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