1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1772 jl139090 * Common Development and Distribution License (the "License"). 6 1772 jl139090 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8803 Jonathan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #if !defined(lint) 27 0 stevel #include "assym.h" 28 0 stevel #endif /* !lint */ 29 0 stevel 30 0 stevel /* 31 0 stevel * General assembly language routines. 32 0 stevel * It is the intent of this file to contain routines that are 33 0 stevel * specific to cpu architecture. 34 0 stevel */ 35 0 stevel 36 0 stevel /* 37 0 stevel * WARNING: If you add a fast trap handler which can be invoked by a 38 0 stevel * non-privileged user, you may have to use the FAST_TRAP_DONE macro 39 0 stevel * instead of "done" instruction to return back to the user mode. See 40 0 stevel * comments for the "fast_trap_done" entry point for more information. 41 0 stevel */ 42 0 stevel #define FAST_TRAP_DONE \ 43 0 stevel ba,a fast_trap_done 44 0 stevel 45 0 stevel /* 46 0 stevel * Override GET_NATIVE_TIME for the cpu module code. This is not 47 0 stevel * guaranteed to be exactly one instruction, be careful of using 48 0 stevel * the macro in delay slots. 49 0 stevel * 50 0 stevel * Do not use any instruction that modifies condition codes as the 51 0 stevel * caller may depend on these to remain unchanged across the macro. 52 0 stevel */ 53 1772 jl139090 #if defined(CHEETAH) || defined(OLYMPUS_C) 54 0 stevel 55 0 stevel #define GET_NATIVE_TIME(out, scr1, scr2) \ 56 0 stevel rd STICK, out 57 0 stevel #define DELTA_NATIVE_TIME(delta, reg, scr1, scr2, scr3) \ 58 0 stevel rd STICK, reg; \ 59 0 stevel add reg, delta, reg; \ 60 0 stevel wr reg, STICK 61 0 stevel #define RD_TICKCMPR(out, scr) \ 62 0 stevel rd STICK_COMPARE, out 63 0 stevel #define WR_TICKCMPR(in, scr1, scr2, label) \ 64 0 stevel wr in, STICK_COMPARE 65 0 stevel 66 0 stevel #elif defined(HUMMINGBIRD) 67 0 stevel #include <sys/spitregs.h> 68 0 stevel 69 0 stevel /* 70 0 stevel * the current hummingbird version of %stick and %stick_cmp 71 0 stevel * were both implemented as (2) 32-bit locations in ASI_IO space; 72 0 stevel * the hdwr should support atomic r/w; meanwhile: ugly alert! ... 73 0 stevel * 74 0 stevel * 64-bit opcodes are required, but move only 32-bits: 75 0 stevel * 76 0 stevel * ldxa [phys]ASI_IO, %dst reads the low 32-bits from phys into %dst 77 0 stevel * stxa %src, [phys]ASI_IO writes the low 32-bits from %src into phys 78 0 stevel * 79 0 stevel * reg equivalent [phys]ASI_IO 80 0 stevel * ------------------ --------------- 81 0 stevel * %stick_cmp low-32 0x1FE.0000.F060 82 0 stevel * %stick_cmp high-32 0x1FE.0000.F068 83 0 stevel * %stick low-32 0x1FE.0000.F070 84 0 stevel * %stick high-32 0x1FE.0000.F078 85 0 stevel */ 86 0 stevel #define HSTC_LOW 0x60 /* stick_cmp low 32-bits */ 87 0 stevel #define HSTC_HIGH 0x68 /* stick_cmp high 32-bits */ 88 0 stevel #define HST_LOW 0x70 /* stick low 32-bits */ 89 0 stevel #define HST_HIGH 0x78 /* stick high 32-bits */ 90 0 stevel #define HST_DIFF 0x08 /* low<-->high diff */ 91 0 stevel 92 0 stevel /* 93 0 stevel * Any change in the number of instructions in SETL41() 94 0 stevel * will affect SETL41_OFF 95 0 stevel */ 96 0 stevel #define SETL41(reg, byte) \ 97 0 stevel sethi %hi(0x1FE00000), reg; /* 0000.0000.1FE0.0000 */ \ 98 0 stevel or reg, 0xF, reg; /* 0000.0000.1FE0.000F */ \ 99 0 stevel sllx reg, 12, reg; /* 0000.01FE.0000.F000 */ \ 100 0 stevel or reg, byte, reg; /* 0000.01FE.0000.F0xx */ 101 0 stevel 102 0 stevel /* 103 0 stevel * SETL41_OFF is used to calulate the relative PC value when a 104 0 stevel * branch instruction needs to go over SETL41() macro 105 0 stevel */ 106 0 stevel #define SETL41_OFF 16 107 0 stevel 108 0 stevel /* 109 0 stevel * reading stick requires 2 loads, and there could be an intervening 110 0 stevel * low-to-high 32-bit rollover resulting in a return value that is 111 0 stevel * off by about (2 ^ 32); this rare case is prevented by re-reading 112 0 stevel * the low-32 bits after the high-32 and verifying the "after" value 113 0 stevel * is >= the "before" value; if not, increment the high-32 value. 114 0 stevel * 115 0 stevel * this method is limited to 1 rollover, and based on the fixed 116 0 stevel * stick-frequency (5555555), requires the loads to complete within 117 0 stevel * 773 seconds; incrementing the high-32 value will not overflow for 118 0 stevel * about 52644 years. 119 0 stevel * 120 0 stevel * writing stick requires 2 stores; if the old/new low-32 value is 121 0 stevel * near 0xffffffff, there could be another rollover (also rare). 122 0 stevel * to prevent this, we first write a 0 to the low-32, then write 123 0 stevel * new values to the high-32 then the low-32. 124 0 stevel * 125 0 stevel * When we detect a carry in the lower %stick register, we need to 126 0 stevel * read HST_HIGH again. However at the point where we detect this, 127 0 stevel * we need to rebuild the register address HST_HIGH.This involves more 128 0 stevel * than one instructions and a branch is unavoidable. However, most of 129 0 stevel * the time, there is no carry. So we take the penalty of a branch 130 0 stevel * instruction only when there is carry (less frequent). 131 0 stevel * 132 0 stevel * For GET_NATIVE_TIME(), we start afresh and branch to SETL41(). 133 0 stevel * For DELTA_NATIVE_TIME(), we branch to just after SETL41() since 134 0 stevel * addr already points to HST_LOW. 135 0 stevel * 136 0 stevel * NOTE: this method requires disabling interrupts before using 137 0 stevel * DELTA_NATIVE_TIME. 138 0 stevel */ 139 0 stevel #define GET_NATIVE_TIME(out, scr, tmp) \ 140 0 stevel SETL41(scr, HST_LOW); \ 141 0 stevel ldxa [scr]ASI_IO, tmp; \ 142 0 stevel inc HST_DIFF, scr; \ 143 0 stevel ldxa [scr]ASI_IO, out; \ 144 0 stevel dec HST_DIFF, scr; \ 145 0 stevel ldxa [scr]ASI_IO, scr; \ 146 0 stevel sub scr, tmp, tmp; \ 147 0 stevel brlz,pn tmp, .-(SETL41_OFF+24); \ 148 0 stevel sllx out, 32, out; \ 149 0 stevel or out, scr, out 150 0 stevel #define DELTA_NATIVE_TIME(delta, addr, high, low, tmp) \ 151 0 stevel SETL41(addr, HST_LOW); \ 152 0 stevel ldxa [addr]ASI_IO, tmp; \ 153 0 stevel inc HST_DIFF, addr; \ 154 0 stevel ldxa [addr]ASI_IO, high; \ 155 0 stevel dec HST_DIFF, addr; \ 156 0 stevel ldxa [addr]ASI_IO, low; \ 157 0 stevel sub low, tmp, tmp; \ 158 0 stevel brlz,pn tmp, .-24; \ 159 0 stevel sllx high, 32, high; \ 160 0 stevel or high, low, high; \ 161 0 stevel add high, delta, high; \ 162 0 stevel srl high, 0, low; \ 163 0 stevel srlx high, 32, high; \ 164 0 stevel stxa %g0, [addr]ASI_IO; \ 165 0 stevel inc HST_DIFF, addr; \ 166 0 stevel stxa high, [addr]ASI_IO; \ 167 0 stevel dec HST_DIFF, addr; \ 168 0 stevel stxa low, [addr]ASI_IO 169 0 stevel #define RD_TICKCMPR(out, scr) \ 170 0 stevel SETL41(scr, HSTC_LOW); \ 171 0 stevel ldxa [scr]ASI_IO, out; \ 172 0 stevel inc HST_DIFF, scr; \ 173 0 stevel ldxa [scr]ASI_IO, scr; \ 174 0 stevel sllx scr, 32, scr; \ 175 0 stevel or scr, out, out 176 0 stevel #define WR_TICKCMPR(in, scra, scrd, label) \ 177 0 stevel SETL41(scra, HSTC_HIGH); \ 178 0 stevel srlx in, 32, scrd; \ 179 0 stevel stxa scrd, [scra]ASI_IO; \ 180 0 stevel dec HST_DIFF, scra; \ 181 0 stevel stxa in, [scra]ASI_IO 182 0 stevel 183 0 stevel #else /* !CHEETAH && !HUMMINGBIRD */ 184 0 stevel 185 0 stevel #define GET_NATIVE_TIME(out, scr1, scr2) \ 186 0 stevel rdpr %tick, out 187 0 stevel #define DELTA_NATIVE_TIME(delta, reg, scr1, scr2, scr3) \ 188 0 stevel rdpr %tick, reg; \ 189 0 stevel add reg, delta, reg; \ 190 0 stevel wrpr reg, %tick 191 0 stevel #define RD_TICKCMPR(out, scr) \ 192 0 stevel rd TICK_COMPARE, out 193 0 stevel #ifdef BB_ERRATA_1 /* writes to TICK_COMPARE may fail */ 194 0 stevel /* 195 0 stevel * Writes to the TICK_COMPARE register sometimes fail on blackbird modules. 196 0 stevel * The failure occurs only when the following instruction decodes to wr or 197 0 stevel * wrpr. The workaround is to immediately follow writes to TICK_COMPARE 198 0 stevel * with a read, thus stalling the pipe and keeping following instructions 199 0 stevel * from causing data corruption. Aligning to a quadword will ensure these 200 0 stevel * two instructions are not split due to i$ misses. 201 0 stevel */ 202 0 stevel #define WR_TICKCMPR(cmpr,scr1,scr2,label) \ 203 0 stevel ba,a .bb_errata_1.label ;\ 204 0 stevel .align 64 ;\ 205 0 stevel .bb_errata_1.label: ;\ 206 0 stevel wr cmpr, TICK_COMPARE ;\ 207 0 stevel rd TICK_COMPARE, %g0 208 0 stevel #else /* BB_ERRATA_1 */ 209 0 stevel #define WR_TICKCMPR(in,scr1,scr2,label) \ 210 0 stevel wr in, TICK_COMPARE 211 0 stevel #endif /* BB_ERRATA_1 */ 212 0 stevel 213 0 stevel #endif /* !CHEETAH && !HUMMINGBIRD */ 214 0 stevel 215 0 stevel #include <sys/clock.h> 216 0 stevel 217 0 stevel #if defined(lint) 218 0 stevel #include <sys/types.h> 219 0 stevel #include <sys/scb.h> 220 0 stevel #include <sys/systm.h> 221 0 stevel #include <sys/regset.h> 222 0 stevel #include <sys/sunddi.h> 223 0 stevel #include <sys/lockstat.h> 224 0 stevel #endif /* lint */ 225 0 stevel 226 0 stevel 227 0 stevel #include <sys/asm_linkage.h> 228 0 stevel #include <sys/privregs.h> 229 0 stevel #include <sys/machparam.h> /* To get SYSBASE and PAGESIZE */ 230 0 stevel #include <sys/machthread.h> 231 0 stevel #include <sys/clock.h> 232 0 stevel #include <sys/intreg.h> 233 0 stevel #include <sys/psr_compat.h> 234 0 stevel #include <sys/isa_defs.h> 235 0 stevel #include <sys/dditypes.h> 236 0 stevel #include <sys/intr.h> 237 0 stevel 238 0 stevel #if !defined(lint) 239 0 stevel #include "assym.h" 240 0 stevel #endif /* !lint */ 241 0 stevel 242 0 stevel #if defined(lint) 243 0 stevel 244 0 stevel uint_t 245 0 stevel get_impl(void) 246 0 stevel { return (0); } 247 0 stevel 248 0 stevel #else /* lint */ 249 0 stevel 250 0 stevel ENTRY(get_impl) 251 0 stevel GET_CPU_IMPL(%o0) 252 0 stevel retl 253 0 stevel nop 254 0 stevel SET_SIZE(get_impl) 255 0 stevel 256 0 stevel #endif /* lint */ 257 0 stevel 258 0 stevel #if defined(lint) 259 0 stevel /* 260 0 stevel * Softint generated when counter field of tick reg matches value field 261 0 stevel * of tick_cmpr reg 262 0 stevel */ 263 0 stevel /*ARGSUSED*/ 264 0 stevel void 265 0 stevel tickcmpr_set(uint64_t clock_cycles) 266 0 stevel {} 267 0 stevel 268 0 stevel #else /* lint */ 269 0 stevel 270 0 stevel ENTRY_NP(tickcmpr_set) 271 0 stevel ! get 64-bit clock_cycles interval 272 0 stevel mov %o0, %o2 273 0 stevel mov 8, %o3 ! A reasonable initial step size 274 0 stevel 1: 275 0 stevel WR_TICKCMPR(%o2,%o4,%o5,__LINE__) ! Write to TICK_CMPR 276 0 stevel 277 0 stevel GET_NATIVE_TIME(%o0, %o4, %o5) ! Read %tick to confirm the 278 0 stevel sllx %o0, 1, %o0 ! value we wrote was in the future. 279 0 stevel srlx %o0, 1, %o0 280 0 stevel 281 0 stevel cmp %o2, %o0 ! If the value we wrote was in the 282 0 stevel bg,pt %xcc, 2f ! future, then blow out of here. 283 0 stevel sllx %o3, 1, %o3 ! If not, then double our step size, 284 0 stevel ba,pt %xcc, 1b ! and take another lap. 285 0 stevel add %o0, %o3, %o2 ! 286 0 stevel 2: 287 0 stevel retl 288 0 stevel nop 289 0 stevel SET_SIZE(tickcmpr_set) 290 0 stevel 291 0 stevel #endif /* lint */ 292 0 stevel 293 0 stevel #if defined(lint) 294 0 stevel 295 0 stevel void 296 0 stevel tickcmpr_disable(void) 297 0 stevel {} 298 0 stevel 299 0 stevel #else /* lint */ 300 0 stevel 301 0 stevel ENTRY_NP(tickcmpr_disable) 302 0 stevel mov 1, %g1 303 0 stevel sllx %g1, TICKINT_DIS_SHFT, %o0 304 0 stevel WR_TICKCMPR(%o0,%o4,%o5,__LINE__) ! Write to TICK_CMPR 305 0 stevel retl 306 0 stevel nop 307 0 stevel SET_SIZE(tickcmpr_disable) 308 0 stevel 309 0 stevel #endif /* lint */ 310 0 stevel 311 0 stevel #if defined(lint) 312 0 stevel 313 0 stevel /* 314 0 stevel * tick_write_delta() increments %tick by the specified delta. This should 315 0 stevel * only be called after a CPR event to assure that gethrtime() continues to 316 0 stevel * increase monotonically. Obviously, writing %tick needs to de done very 317 0 stevel * carefully to avoid introducing unnecessary %tick skew across CPUs. For 318 0 stevel * this reason, we make sure we're i-cache hot before actually writing to 319 0 stevel * %tick. 320 0 stevel */ 321 0 stevel /*ARGSUSED*/ 322 0 stevel void 323 0 stevel tick_write_delta(uint64_t delta) 324 0 stevel {} 325 0 stevel 326 0 stevel #else /* lint */ 327 0 stevel 328 0 stevel #ifdef DEBUG 329 0 stevel .seg ".text" 330 0 stevel tick_write_panic: 331 0 stevel .asciz "tick_write_delta: interrupts already disabled on entry" 332 0 stevel #endif /* DEBUG */ 333 0 stevel 334 0 stevel ENTRY_NP(tick_write_delta) 335 0 stevel rdpr %pstate, %g1 336 0 stevel #ifdef DEBUG 337 0 stevel andcc %g1, PSTATE_IE, %g0 ! If DEBUG, check that interrupts 338 0 stevel bnz 0f ! aren't already disabled. 339 0 stevel sethi %hi(tick_write_panic), %o1 340 0 stevel save %sp, -SA(MINFRAME), %sp ! get a new window to preserve caller 341 0 stevel call panic 342 0 stevel or %i1, %lo(tick_write_panic), %o0 343 0 stevel #endif /* DEBUG */ 344 0 stevel 0: wrpr %g1, PSTATE_IE, %pstate ! Disable interrupts 345 0 stevel mov %o0, %o2 346 0 stevel ba 0f ! Branch to cache line-aligned instr. 347 0 stevel nop 348 0 stevel .align 16 349 0 stevel 0: nop ! The next 3 instructions are now hot. 350 0 stevel DELTA_NATIVE_TIME(%o2, %o3, %o4, %o5, %g2) ! read/inc/write %tick 351 0 stevel 352 0 stevel retl ! Return 353 0 stevel wrpr %g0, %g1, %pstate ! delay: Re-enable interrupts 354 0 stevel #endif /* lint */ 355 0 stevel 356 0 stevel #if defined(lint) 357 0 stevel /* 358 0 stevel * return 1 if disabled 359 0 stevel */ 360 0 stevel 361 0 stevel int 362 0 stevel tickcmpr_disabled(void) 363 0 stevel { return (0); } 364 0 stevel 365 0 stevel #else /* lint */ 366 0 stevel 367 0 stevel ENTRY_NP(tickcmpr_disabled) 368 0 stevel RD_TICKCMPR(%g1, %o0) 369 0 stevel retl 370 0 stevel srlx %g1, TICKINT_DIS_SHFT, %o0 371 0 stevel SET_SIZE(tickcmpr_disabled) 372 0 stevel 373 0 stevel #endif /* lint */ 374 0 stevel 375 0 stevel /* 376 0 stevel * Get current tick 377 0 stevel */ 378 0 stevel #if defined(lint) 379 0 stevel 380 0 stevel u_longlong_t 381 0 stevel gettick(void) 382 0 stevel { return (0); } 383 0 stevel 384 0 stevel #else /* lint */ 385 0 stevel 386 0 stevel ENTRY(gettick) 387 0 stevel GET_NATIVE_TIME(%o0, %o2, %o3) 388 0 stevel retl 389 0 stevel nop 390 0 stevel SET_SIZE(gettick) 391 0 stevel 392 0 stevel #endif /* lint */ 393 0 stevel 394 0 stevel 395 0 stevel /* 396 0 stevel * Return the counter portion of the tick register. 397 0 stevel */ 398 0 stevel 399 0 stevel #if defined(lint) 400 0 stevel 401 0 stevel uint64_t 402 0 stevel gettick_counter(void) 403 0 stevel { return(0); } 404 0 stevel 405 0 stevel #else /* lint */ 406 0 stevel 407 0 stevel ENTRY_NP(gettick_counter) 408 0 stevel rdpr %tick, %o0 409 0 stevel sllx %o0, 1, %o0 410 0 stevel retl 411 0 stevel srlx %o0, 1, %o0 ! shake off npt bit 412 0 stevel SET_SIZE(gettick_counter) 413 0 stevel #endif /* lint */ 414 0 stevel 415 0 stevel /* 416 0 stevel * Provide a C callable interface to the trap that reads the hi-res timer. 417 0 stevel * Returns 64-bit nanosecond timestamp in %o0 and %o1. 418 0 stevel */ 419 0 stevel 420 0 stevel #if defined(lint) 421 0 stevel 422 0 stevel hrtime_t 423 0 stevel gethrtime(void) 424 0 stevel { 425 0 stevel return ((hrtime_t)0); 426 0 stevel } 427 0 stevel 428 0 stevel hrtime_t 429 0 stevel gethrtime_unscaled(void) 430 0 stevel { 431 0 stevel return ((hrtime_t)0); 432 0 stevel } 433 0 stevel 434 0 stevel hrtime_t 435 0 stevel gethrtime_max(void) 436 0 stevel { 437 0 stevel return ((hrtime_t)0); 438 0 stevel } 439 0 stevel 440 0 stevel void 441 0 stevel scalehrtime(hrtime_t *hrt) 442 0 stevel { 443 0 stevel *hrt = 0; 444 0 stevel } 445 0 stevel 446 0 stevel void 447 0 stevel gethrestime(timespec_t *tp) 448 0 stevel { 449 0 stevel tp->tv_sec = 0; 450 0 stevel tp->tv_nsec = 0; 451 0 stevel } 452 0 stevel 453 0 stevel time_t 454 0 stevel gethrestime_sec(void) 455 0 stevel { 456 0 stevel return (0); 457 0 stevel } 458 0 stevel 459 0 stevel void 460 0 stevel gethrestime_lasttick(timespec_t *tp) 461 0 stevel { 462 0 stevel tp->tv_sec = 0; 463 0 stevel tp->tv_nsec = 0; 464 0 stevel } 465 0 stevel 466 0 stevel /*ARGSUSED*/ 467 0 stevel void 468 0 stevel hres_tick(void) 469 0 stevel { 470 0 stevel } 471 0 stevel 472 0 stevel void 473 0 stevel panic_hres_tick(void) 474 0 stevel { 475 0 stevel } 476 0 stevel 477 0 stevel #else /* lint */ 478 0 stevel 479 0 stevel ENTRY_NP(gethrtime) 480 0 stevel GET_HRTIME(%g1, %o0, %o1, %o2, %o3, %o4, %o5, %g2) 481 0 stevel ! %g1 = hrtime 482 0 stevel retl 483 0 stevel mov %g1, %o0 484 0 stevel SET_SIZE(gethrtime) 485 0 stevel 486 0 stevel ENTRY_NP(gethrtime_unscaled) 487 0 stevel GET_NATIVE_TIME(%g1, %o2, %o3) ! %g1 = native time 488 0 stevel retl 489 0 stevel mov %g1, %o0 490 0 stevel SET_SIZE(gethrtime_unscaled) 491 0 stevel 492 0 stevel ENTRY_NP(gethrtime_waitfree) 493 0 stevel ALTENTRY(dtrace_gethrtime) 494 0 stevel GET_NATIVE_TIME(%g1, %o2, %o3) ! %g1 = native time 495 0 stevel NATIVE_TIME_TO_NSEC(%g1, %o2, %o3) 496 0 stevel retl 497 0 stevel mov %g1, %o0 498 0 stevel SET_SIZE(dtrace_gethrtime) 499 0 stevel SET_SIZE(gethrtime_waitfree) 500 0 stevel 501 0 stevel ENTRY(gethrtime_max) 502 0 stevel NATIVE_TIME_MAX(%g1) 503 0 stevel NATIVE_TIME_TO_NSEC(%g1, %o0, %o1) 504 0 stevel 505 0 stevel ! hrtime_t's are signed, max hrtime_t must be positive 506 0 stevel mov -1, %o2 507 0 stevel brlz,a %g1, 1f 508 0 stevel srlx %o2, 1, %g1 509 0 stevel 1: 510 0 stevel retl 511 0 stevel mov %g1, %o0 512 0 stevel SET_SIZE(gethrtime_max) 513 0 stevel 514 0 stevel ENTRY(scalehrtime) 515 0 stevel ldx [%o0], %o1 516 0 stevel NATIVE_TIME_TO_NSEC(%o1, %o2, %o3) 517 0 stevel retl 518 0 stevel stx %o1, [%o0] 519 0 stevel SET_SIZE(scalehrtime) 520 0 stevel 521 0 stevel /* 522 0 stevel * Fast trap to return a timestamp, uses trap window, leaves traps 523 0 stevel * disabled. Returns a 64-bit nanosecond timestamp in %o0 and %o1. 524 0 stevel * 525 0 stevel * This is the handler for the ST_GETHRTIME trap. 526 0 stevel */ 527 0 stevel 528 0 stevel ENTRY_NP(get_timestamp) 529 0 stevel GET_HRTIME(%g1, %g2, %g3, %g4, %g5, %o0, %o1, %o2) ! %g1 = hrtime 530 0 stevel srlx %g1, 32, %o0 ! %o0 = hi32(%g1) 531 0 stevel srl %g1, 0, %o1 ! %o1 = lo32(%g1) 532 0 stevel FAST_TRAP_DONE 533 0 stevel SET_SIZE(get_timestamp) 534 0 stevel 535 0 stevel /* 536 0 stevel * Macro to convert GET_HRESTIME() bits into a timestamp. 537 0 stevel * 538 0 stevel * We use two separate macros so that the platform-dependent GET_HRESTIME() 539 0 stevel * can be as small as possible; CONV_HRESTIME() implements the generic part. 540 0 stevel */ 541 0 stevel #define CONV_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano) \ 542 0 stevel brz,pt adj, 3f; /* no adjustments, it's easy */ \ 543 0 stevel add hrestnsec, nslt, hrestnsec; /* hrest.tv_nsec += nslt */ \ 544 0 stevel brlz,pn adj, 2f; /* if hrestime_adj negative */ \ 545 2399 cth srlx nslt, ADJ_SHIFT, nslt; /* delay: nslt >>= 4 */ \ 546 0 stevel subcc adj, nslt, %g0; /* hrestime_adj - nslt/16 */ \ 547 0 stevel movg %xcc, nslt, adj; /* adj by min(adj, nslt/16) */ \ 548 0 stevel ba 3f; /* go convert to sec/nsec */ \ 549 0 stevel add hrestnsec, adj, hrestnsec; /* delay: apply adjustment */ \ 550 0 stevel 2: addcc adj, nslt, %g0; /* hrestime_adj + nslt/16 */ \ 551 0 stevel bge,a,pt %xcc, 3f; /* is adj less negative? */ \ 552 0 stevel add hrestnsec, adj, hrestnsec; /* yes: hrest.nsec += adj */ \ 553 0 stevel sub hrestnsec, nslt, hrestnsec; /* no: hrest.nsec -= nslt/16 */ \ 554 0 stevel 3: cmp hrestnsec, nano; /* more than a billion? */ \ 555 0 stevel bl,pt %xcc, 4f; /* if not, we're done */ \ 556 0 stevel nop; /* delay: do nothing :( */ \ 557 0 stevel add hrestsec, 1, hrestsec; /* hrest.tv_sec++; */ \ 558 0 stevel sub hrestnsec, nano, hrestnsec; /* hrest.tv_nsec -= NANOSEC; */ \ 559 2399 cth ba,a 3b; /* check >= billion again */ \ 560 0 stevel 4: 561 0 stevel 562 0 stevel ENTRY_NP(gethrestime) 563 0 stevel GET_HRESTIME(%o1, %o2, %o3, %o4, %o5, %g1, %g2, %g3, %g4) 564 0 stevel CONV_HRESTIME(%o1, %o2, %o3, %o4, %o5) 565 0 stevel stn %o1, [%o0] 566 0 stevel retl 567 0 stevel stn %o2, [%o0 + CLONGSIZE] 568 0 stevel SET_SIZE(gethrestime) 569 0 stevel 570 0 stevel /* 571 0 stevel * Similar to gethrestime(), but gethrestime_sec() returns current hrestime 572 0 stevel * seconds. 573 0 stevel */ 574 0 stevel ENTRY_NP(gethrestime_sec) 575 0 stevel GET_HRESTIME(%o0, %o2, %o3, %o4, %o5, %g1, %g2, %g3, %g4) 576 0 stevel CONV_HRESTIME(%o0, %o2, %o3, %o4, %o5) 577 0 stevel retl ! %o0 current hrestime seconds 578 0 stevel nop 579 0 stevel SET_SIZE(gethrestime_sec) 580 0 stevel 581 0 stevel /* 582 0 stevel * Returns the hrestime on the last tick. This is simpler than gethrestime() 583 0 stevel * and gethrestime_sec(): no conversion is required. gethrestime_lasttick() 584 0 stevel * follows the same locking algorithm as GET_HRESTIME and GET_HRTIME, 585 0 stevel * outlined in detail in clock.h. (Unlike GET_HRESTIME/GET_HRTIME, we don't 586 0 stevel * rely on load dependencies to effect the membar #LoadLoad, instead declaring 587 0 stevel * it explicitly.) 588 0 stevel */ 589 0 stevel ENTRY_NP(gethrestime_lasttick) 590 0 stevel sethi %hi(hres_lock), %o1 591 0 stevel 0: 592 0 stevel lduw [%o1 + %lo(hres_lock)], %o2 ! Load lock value 593 0 stevel membar #LoadLoad ! Load of lock must complete 594 0 stevel andn %o2, 1, %o2 ! Mask off lowest bit 595 0 stevel ldn [%o1 + %lo(hrestime)], %g1 ! Seconds. 596 0 stevel add %o1, %lo(hrestime), %o4 597 0 stevel ldn [%o4 + CLONGSIZE], %g2 ! Nanoseconds. 598 0 stevel membar #LoadLoad ! All loads must complete 599 0 stevel lduw [%o1 + %lo(hres_lock)], %o3 ! Reload lock value 600 0 stevel cmp %o3, %o2 ! If lock is locked or has 601 0 stevel bne 0b ! changed, retry. 602 0 stevel stn %g1, [%o0] ! Delay: store seconds 603 0 stevel retl 604 0 stevel stn %g2, [%o0 + CLONGSIZE] ! Delay: store nanoseconds 605 0 stevel SET_SIZE(gethrestime_lasttick) 606 0 stevel 607 0 stevel /* 608 0 stevel * Fast trap for gettimeofday(). Returns a timestruc_t in %o0 and %o1. 609 0 stevel * 610 0 stevel * This is the handler for the ST_GETHRESTIME trap. 611 0 stevel */ 612 0 stevel 613 0 stevel ENTRY_NP(get_hrestime) 614 0 stevel GET_HRESTIME(%o0, %o1, %g1, %g2, %g3, %g4, %g5, %o2, %o3) 615 0 stevel CONV_HRESTIME(%o0, %o1, %g1, %g2, %g3) 616 0 stevel FAST_TRAP_DONE 617 0 stevel SET_SIZE(get_hrestime) 618 0 stevel 619 0 stevel /* 620 0 stevel * Fast trap to return lwp virtual time, uses trap window, leaves traps 621 0 stevel * disabled. Returns a 64-bit number in %o0:%o1, which is the number 622 0 stevel * of nanoseconds consumed. 623 0 stevel * 624 0 stevel * This is the handler for the ST_GETHRVTIME trap. 625 0 stevel * 626 0 stevel * Register usage: 627 0 stevel * %o0, %o1 = return lwp virtual time 628 0 stevel * %o2 = CPU/thread 629 0 stevel * %o3 = lwp 630 0 stevel * %g1 = scratch 631 0 stevel * %g5 = scratch 632 0 stevel */ 633 0 stevel ENTRY_NP(get_virtime) 634 0 stevel GET_NATIVE_TIME(%g5, %g1, %g2) ! %g5 = native time in ticks 635 0 stevel CPU_ADDR(%g2, %g3) ! CPU struct ptr to %g2 636 0 stevel ldn [%g2 + CPU_THREAD], %g2 ! thread pointer to %g2 637 0 stevel ldn [%g2 + T_LWP], %g3 ! lwp pointer to %g3 638 0 stevel 639 0 stevel /* 640 0 stevel * Subtract start time of current microstate from time 641 0 stevel * of day to get increment for lwp virtual time. 642 0 stevel */ 643 0 stevel ldx [%g3 + LWP_STATE_START], %g1 ! ms_state_start 644 0 stevel sub %g5, %g1, %g5 645 0 stevel 646 0 stevel /* 647 0 stevel * Add current value of ms_acct[LMS_USER] 648 0 stevel */ 649 0 stevel ldx [%g3 + LWP_ACCT_USER], %g1 ! ms_acct[LMS_USER] 650 0 stevel add %g5, %g1, %g5 651 0 stevel NATIVE_TIME_TO_NSEC(%g5, %g1, %o0) 652 0 stevel 653 0 stevel srl %g5, 0, %o1 ! %o1 = lo32(%g5) 654 0 stevel srlx %g5, 32, %o0 ! %o0 = hi32(%g5) 655 0 stevel 656 0 stevel FAST_TRAP_DONE 657 0 stevel SET_SIZE(get_virtime) 658 0 stevel 659 0 stevel 660 0 stevel 661 0 stevel .seg ".text" 662 0 stevel hrtime_base_panic: 663 0 stevel .asciz "hrtime_base stepping back" 664 0 stevel 665 0 stevel 666 0 stevel ENTRY_NP(hres_tick) 667 0 stevel save %sp, -SA(MINFRAME), %sp ! get a new window 668 0 stevel 669 0 stevel sethi %hi(hrestime), %l4 670 0 stevel ldstub [%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5 ! try locking 671 0 stevel 7: tst %l5 672 0 stevel bz,pt %xcc, 8f ! if we got it, drive on 673 0 stevel ld [%l4 + %lo(nsec_scale)], %l5 ! delay: %l5 = scaling factor 674 0 stevel ldub [%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5 675 0 stevel 9: tst %l5 676 0 stevel bz,a,pn %xcc, 7b 677 0 stevel ldstub [%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5 678 0 stevel ba,pt %xcc, 9b 679 0 stevel ldub [%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5 680 0 stevel 8: 681 0 stevel membar #StoreLoad|#StoreStore 682 0 stevel 683 0 stevel ! 684 0 stevel ! update hres_last_tick. %l5 has the scaling factor (nsec_scale). 685 0 stevel ! 686 0 stevel ldx [%l4 + %lo(hrtime_base)], %g1 ! load current hrtime_base 687 0 stevel GET_NATIVE_TIME(%l0, %l3, %l6) ! current native time 688 0 stevel stx %l0, [%l4 + %lo(hres_last_tick)]! prev = current 689 0 stevel ! convert native time to nsecs 690 0 stevel NATIVE_TIME_TO_NSEC_SCALE(%l0, %l5, %l2, NSEC_SHIFT) 691 0 stevel 692 0 stevel sub %l0, %g1, %i1 ! get accurate nsec delta 693 0 stevel 694 0 stevel ldx [%l4 + %lo(hrtime_base)], %l1 695 0 stevel cmp %l1, %l0 696 0 stevel bg,pn %xcc, 9f 697 0 stevel nop 698 0 stevel 699 0 stevel stx %l0, [%l4 + %lo(hrtime_base)] ! update hrtime_base 700 0 stevel 701 0 stevel ! 702 0 stevel ! apply adjustment, if any 703 0 stevel ! 704 0 stevel ldx [%l4 + %lo(hrestime_adj)], %l0 ! %l0 = hrestime_adj 705 0 stevel brz %l0, 2f 706 0 stevel ! hrestime_adj == 0 ? 707 0 stevel ! yes, skip adjustments 708 0 stevel clr %l5 ! delay: set adj to zero 709 0 stevel tst %l0 ! is hrestime_adj >= 0 ? 710 0 stevel bge,pt %xcc, 1f ! yes, go handle positive case 711 0 stevel srl %i1, ADJ_SHIFT, %l5 ! delay: %l5 = adj 712 0 stevel 713 0 stevel addcc %l0, %l5, %g0 ! hrestime_adj < -adj ? 714 0 stevel bl,pt %xcc, 2f ! yes, use current adj 715 0 stevel neg %l5 ! delay: %l5 = -adj 716 0 stevel ba,pt %xcc, 2f 717 0 stevel mov %l0, %l5 ! no, so set adj = hrestime_adj 718 0 stevel 1: 719 0 stevel subcc %l0, %l5, %g0 ! hrestime_adj < adj ? 720 0 stevel bl,a,pt %xcc, 2f ! yes, set adj = hrestime_adj 721 0 stevel mov %l0, %l5 ! delay: adj = hrestime_adj 722 0 stevel 2: 723 0 stevel ldx [%l4 + %lo(timedelta)], %l0 ! %l0 = timedelta 724 0 stevel sub %l0, %l5, %l0 ! timedelta -= adj 725 0 stevel 726 0 stevel stx %l0, [%l4 + %lo(timedelta)] ! store new timedelta 727 0 stevel stx %l0, [%l4 + %lo(hrestime_adj)] ! hrestime_adj = timedelta 728 0 stevel 729 0 stevel or %l4, %lo(hrestime), %l2 730 0 stevel ldn [%l2], %i2 ! %i2:%i3 = hrestime sec:nsec 731 0 stevel ldn [%l2 + CLONGSIZE], %i3 732 0 stevel add %i3, %l5, %i3 ! hrestime.nsec += adj 733 0 stevel add %i3, %i1, %i3 ! hrestime.nsec += nslt 734 0 stevel 735 0 stevel set NANOSEC, %l5 ! %l5 = NANOSEC 736 0 stevel cmp %i3, %l5 737 0 stevel bl,pt %xcc, 5f ! if hrestime.tv_nsec < NANOSEC 738 0 stevel sethi %hi(one_sec), %i1 ! delay 739 0 stevel add %i2, 0x1, %i2 ! hrestime.tv_sec++ 740 0 stevel sub %i3, %l5, %i3 ! hrestime.tv_nsec - NANOSEC 741 0 stevel mov 0x1, %l5 742 0 stevel st %l5, [%i1 + %lo(one_sec)] 743 0 stevel 5: 744 0 stevel stn %i2, [%l2] 745 0 stevel stn %i3, [%l2 + CLONGSIZE] ! store the new hrestime 746 0 stevel 747 0 stevel membar #StoreStore 748 0 stevel 749 0 stevel ld [%l4 + %lo(hres_lock)], %i1 750 0 stevel inc %i1 ! release lock 751 0 stevel st %i1, [%l4 + %lo(hres_lock)] ! clear hres_lock 752 0 stevel 753 0 stevel ret 754 0 stevel restore 755 0 stevel 756 0 stevel 9: 757 0 stevel ! 758 0 stevel ! release hres_lock 759 0 stevel ! 760 0 stevel ld [%l4 + %lo(hres_lock)], %i1 761 0 stevel inc %i1 762 0 stevel st %i1, [%l4 + %lo(hres_lock)] 763 0 stevel 764 0 stevel sethi %hi(hrtime_base_panic), %o0 765 0 stevel call panic 766 0 stevel or %o0, %lo(hrtime_base_panic), %o0 767 0 stevel 768 0 stevel SET_SIZE(hres_tick) 769 0 stevel 770 0 stevel #endif /* lint */ 771 0 stevel 772 0 stevel #if !defined(lint) && !defined(__lint) 773 0 stevel 774 0 stevel .seg ".text" 775 0 stevel kstat_q_panic_msg: 776 0 stevel .asciz "kstat_q_exit: qlen == 0" 777 0 stevel 778 0 stevel ENTRY(kstat_q_panic) 779 0 stevel save %sp, -SA(MINFRAME), %sp 780 0 stevel sethi %hi(kstat_q_panic_msg), %o0 781 0 stevel call panic 782 0 stevel or %o0, %lo(kstat_q_panic_msg), %o0 783 0 stevel /*NOTREACHED*/ 784 0 stevel SET_SIZE(kstat_q_panic) 785 0 stevel 786 0 stevel #define BRZPN brz,pn 787 0 stevel #define BRZPT brz,pt 788 0 stevel 789 0 stevel #define KSTAT_Q_UPDATE(QOP, QBR, QZERO, QRETURN, QTYPE) \ 790 0 stevel ld [%o0 + QTYPE/**/CNT], %o1; /* %o1 = old qlen */ \ 791 0 stevel QOP %o1, 1, %o2; /* %o2 = new qlen */ \ 792 0 stevel QBR %o1, QZERO; /* done if qlen == 0 */ \ 793 0 stevel st %o2, [%o0 + QTYPE/**/CNT]; /* delay: save qlen */ \ 794 0 stevel ldx [%o0 + QTYPE/**/LASTUPDATE], %o3; \ 795 0 stevel ldx [%o0 + QTYPE/**/TIME], %o4; /* %o4 = old time */ \ 796 0 stevel ldx [%o0 + QTYPE/**/LENTIME], %o5; /* %o5 = old lentime */ \ 797 0 stevel sub %g1, %o3, %o2; /* %o2 = time delta */ \ 798 0 stevel mulx %o1, %o2, %o3; /* %o3 = cur lentime */ \ 799 0 stevel add %o4, %o2, %o4; /* %o4 = new time */ \ 800 0 stevel add %o5, %o3, %o5; /* %o5 = new lentime */ \ 801 0 stevel stx %o4, [%o0 + QTYPE/**/TIME]; /* save time */ \ 802 0 stevel stx %o5, [%o0 + QTYPE/**/LENTIME]; /* save lentime */ \ 803 0 stevel QRETURN; \ 804 0 stevel stx %g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */ 805 0 stevel 806 0 stevel .align 16 807 0 stevel ENTRY(kstat_waitq_enter) 808 0 stevel GET_NATIVE_TIME(%g1, %g2, %g3) 809 0 stevel KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W) 810 0 stevel SET_SIZE(kstat_waitq_enter) 811 0 stevel 812 0 stevel .align 16 813 0 stevel ENTRY(kstat_waitq_exit) 814 0 stevel GET_NATIVE_TIME(%g1, %g2, %g3) 815 0 stevel KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_W) 816 0 stevel SET_SIZE(kstat_waitq_exit) 817 0 stevel 818 0 stevel .align 16 819 0 stevel ENTRY(kstat_runq_enter) 820 0 stevel GET_NATIVE_TIME(%g1, %g2, %g3) 821 0 stevel KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R) 822 0 stevel SET_SIZE(kstat_runq_enter) 823 0 stevel 824 0 stevel .align 16 825 0 stevel ENTRY(kstat_runq_exit) 826 0 stevel GET_NATIVE_TIME(%g1, %g2, %g3) 827 0 stevel KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_R) 828 0 stevel SET_SIZE(kstat_runq_exit) 829 0 stevel 830 0 stevel .align 16 831 0 stevel ENTRY(kstat_waitq_to_runq) 832 0 stevel GET_NATIVE_TIME(%g1, %g2, %g3) 833 0 stevel KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_W) 834 0 stevel KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R) 835 0 stevel SET_SIZE(kstat_waitq_to_runq) 836 0 stevel 837 0 stevel .align 16 838 0 stevel ENTRY(kstat_runq_back_to_waitq) 839 0 stevel GET_NATIVE_TIME(%g1, %g2, %g3) 840 0 stevel KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_R) 841 0 stevel KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W) 842 0 stevel SET_SIZE(kstat_runq_back_to_waitq) 843 0 stevel 844 0 stevel #endif /* !(lint || __lint) */ 845 0 stevel 846 0 stevel #ifdef lint 847 0 stevel 848 0 stevel int64_t timedelta; 849 0 stevel hrtime_t hres_last_tick; 850 4551 sudheer volatile timestruc_t hrestime; 851 0 stevel int64_t hrestime_adj; 852 4551 sudheer volatile int hres_lock; 853 0 stevel uint_t nsec_scale; 854 0 stevel hrtime_t hrtime_base; 855 0 stevel int traptrace_use_stick; 856 0 stevel 857 0 stevel #else /* lint */ 858 0 stevel /* 859 0 stevel * -- WARNING -- 860 0 stevel * 861 0 stevel * The following variables MUST be together on a 128-byte boundary. 862 0 stevel * In addition to the primary performance motivation (having them all 863 0 stevel * on the same cache line(s)), code here and in the GET*TIME() macros 864 0 stevel * assumes that they all have the same high 22 address bits (so 865 0 stevel * there's only one sethi). 866 0 stevel */ 867 0 stevel .seg ".data" 868 0 stevel .global timedelta, hres_last_tick, hrestime, hrestime_adj 869 0 stevel .global hres_lock, nsec_scale, hrtime_base, traptrace_use_stick 870 0 stevel .global nsec_shift, adj_shift 871 0 stevel 872 0 stevel /* XXX - above comment claims 128-bytes is necessary */ 873 0 stevel .align 64 874 0 stevel timedelta: 875 0 stevel .word 0, 0 /* int64_t */ 876 0 stevel hres_last_tick: 877 0 stevel .word 0, 0 /* hrtime_t */ 878 0 stevel hrestime: 879 0 stevel .nword 0, 0 /* 2 longs */ 880 0 stevel hrestime_adj: 881 0 stevel .word 0, 0 /* int64_t */ 882 0 stevel hres_lock: 883 0 stevel .word 0 884 0 stevel nsec_scale: 885 0 stevel .word 0 886 0 stevel hrtime_base: 887 0 stevel .word 0, 0 888 0 stevel traptrace_use_stick: 889 0 stevel .word 0 890 0 stevel nsec_shift: 891 0 stevel .word NSEC_SHIFT 892 0 stevel adj_shift: 893 0 stevel .word ADJ_SHIFT 894 0 stevel 895 0 stevel #endif /* lint */ 896 0 stevel 897 0 stevel 898 0 stevel /* 899 0 stevel * drv_usecwait(clock_t n) [DDI/DKI - section 9F] 900 0 stevel * usec_delay(int n) [compatibility - should go one day] 901 0 stevel * Delay by spinning. 902 0 stevel * 903 0 stevel * delay for n microseconds. numbers <= 0 delay 1 usec 904 0 stevel * 905 0 stevel * With UltraSPARC-III the combination of supporting mixed-speed CPUs 906 0 stevel * and variable clock rate for power management requires that we 907 0 stevel * use %stick to implement this routine. 908 1772 jl139090 * 909 1772 jl139090 * For OPL platforms that support the "sleep" instruction, we 910 1772 jl139090 * conditionally (ifdef'ed) insert a "sleep" instruction in 911 1772 jl139090 * the loop. Note that theoritically we should have move (duplicated) 912 1772 jl139090 * the code down to spitfire/us3/opl specific asm files - but this 913 1772 jl139090 * is alot of code duplication just to add one "sleep" instruction. 914 1772 jl139090 * We chose less code duplication for this. 915 0 stevel */ 916 0 stevel 917 0 stevel #if defined(lint) 918 0 stevel 919 0 stevel /*ARGSUSED*/ 920 0 stevel void 921 0 stevel drv_usecwait(clock_t n) 922 0 stevel {} 923 0 stevel 924 0 stevel /*ARGSUSED*/ 925 0 stevel void 926 0 stevel usec_delay(int n) 927 0 stevel {} 928 0 stevel 929 0 stevel #else /* lint */ 930 0 stevel 931 0 stevel ENTRY(drv_usecwait) 932 0 stevel ALTENTRY(usec_delay) 933 0 stevel brlez,a,pn %o0, 0f 934 0 stevel mov 1, %o0 935 0 stevel 0: 936 0 stevel sethi %hi(sticks_per_usec), %o1 937 0 stevel lduw [%o1 + %lo(sticks_per_usec)], %o1 938 0 stevel mulx %o1, %o0, %o1 ! Scale usec to ticks 939 0 stevel inc %o1 ! We don't start on a tick edge 940 0 stevel GET_NATIVE_TIME(%o2, %o3, %o4) 941 0 stevel add %o1, %o2, %o1 942 0 stevel 943 1772 jl139090 1: 944 1772 jl139090 #ifdef _OPL 945 1772 jl139090 .word 0x81b01060 ! insert "sleep" instruction 946 1772 jl139090 #endif /* _OPL */ ! use byte code for now 947 1772 jl139090 cmp %o1, %o2 948 0 stevel GET_NATIVE_TIME(%o2, %o3, %o4) 949 0 stevel bgeu,pt %xcc, 1b 950 0 stevel nop 951 0 stevel retl 952 0 stevel nop 953 0 stevel SET_SIZE(usec_delay) 954 0 stevel SET_SIZE(drv_usecwait) 955 0 stevel #endif /* lint */ 956 0 stevel 957 0 stevel #if defined(lint) 958 0 stevel 959 0 stevel /* ARGSUSED */ 960 0 stevel void 961 0 stevel pil14_interrupt(int level) 962 0 stevel {} 963 0 stevel 964 0 stevel #else /* lint */ 965 0 stevel 966 0 stevel /* 967 0 stevel * Level-14 interrupt prologue. 968 0 stevel */ 969 0 stevel ENTRY_NP(pil14_interrupt) 970 0 stevel CPU_ADDR(%g1, %g2) 971 0 stevel rdpr %pil, %g6 ! %g6 = interrupted PIL 972 0 stevel stn %g6, [%g1 + CPU_PROFILE_PIL] ! record interrupted PIL 973 0 stevel rdpr %tstate, %g6 974 0 stevel rdpr %tpc, %g5 975 0 stevel btst TSTATE_PRIV, %g6 ! trap from supervisor mode? 976 0 stevel bnz,a,pt %xcc, 1f 977 0 stevel stn %g5, [%g1 + CPU_PROFILE_PC] ! if so, record kernel PC 978 0 stevel stn %g5, [%g1 + CPU_PROFILE_UPC] ! if not, record user PC 979 0 stevel ba pil_interrupt_common ! must be large-disp branch 980 0 stevel stn %g0, [%g1 + CPU_PROFILE_PC] ! zero kernel PC 981 0 stevel 1: ba pil_interrupt_common ! must be large-disp branch 982 0 stevel stn %g0, [%g1 + CPU_PROFILE_UPC] ! zero user PC 983 0 stevel SET_SIZE(pil14_interrupt) 984 0 stevel 985 0 stevel ENTRY_NP(tick_rtt) 986 0 stevel ! 987 0 stevel ! Load TICK_COMPARE into %o5; if bit 63 is set, then TICK_COMPARE is 988 0 stevel ! disabled. If TICK_COMPARE is enabled, we know that we need to 989 0 stevel ! reenqueue the interrupt request structure. We'll then check TICKINT 990 0 stevel ! in SOFTINT; if it's set, then we know that we were in a TICK_COMPARE 991 0 stevel ! interrupt. In this case, TICK_COMPARE may have been rewritten 992 0 stevel ! recently; we'll compare %o5 to the current time to verify that it's 993 0 stevel ! in the future. 994 0 stevel ! 995 0 stevel ! Note that %o5 is live until after 1f. 996 0 stevel ! XXX - there is a subroutine call while %o5 is live! 997 0 stevel ! 998 0 stevel RD_TICKCMPR(%o5, %g1) 999 0 stevel srlx %o5, TICKINT_DIS_SHFT, %g1 1000 0 stevel brnz,pt %g1, 2f 1001 0 stevel nop 1002 0 stevel 1003 0 stevel rdpr %pstate, %g5 1004 0 stevel andn %g5, PSTATE_IE, %g1 1005 0 stevel wrpr %g0, %g1, %pstate ! Disable vec interrupts 1006 0 stevel 1007 0 stevel sethi %hi(cbe_level14_inum), %o1 1008 2973 govinda ldx [%o1 + %lo(cbe_level14_inum)], %o1 1009 0 stevel call intr_enqueue_req ! preserves %o5 and %g5 1010 0 stevel mov PIL_14, %o0 1011 0 stevel 1012 0 stevel ! Check SOFTINT for TICKINT/STICKINT 1013 0 stevel rd SOFTINT, %o4 1014 0 stevel set (TICK_INT_MASK | STICK_INT_MASK), %o0 1015 0 stevel andcc %o4, %o0, %g0 1016 0 stevel bz,a,pn %icc, 2f 1017 0 stevel wrpr %g0, %g5, %pstate ! Enable vec interrupts 1018 0 stevel 1019 0 stevel ! clear TICKINT/STICKINT 1020 0 stevel wr %o0, CLEAR_SOFTINT 1021 0 stevel 1022 0 stevel ! 1023 0 stevel ! Now that we've cleared TICKINT, we can reread %tick and confirm 1024 0 stevel ! that the value we programmed is still in the future. If it isn't, 1025 0 stevel ! we need to reprogram TICK_COMPARE to fire as soon as possible. 1026 0 stevel ! 1027 0 stevel GET_NATIVE_TIME(%o0, %g1, %g2) ! %o0 = tick 1028 0 stevel sllx %o0, 1, %o0 ! Clear the DIS bit 1029 0 stevel srlx %o0, 1, %o0 1030 0 stevel cmp %o5, %o0 ! In the future? 1031 0 stevel bg,a,pt %xcc, 2f ! Yes, drive on. 1032 0 stevel wrpr %g0, %g5, %pstate ! delay: enable vec intr 1033 0 stevel 1034 0 stevel ! 1035 0 stevel ! If we're here, then we have programmed TICK_COMPARE with a %tick 1036 0 stevel ! which is in the past; we'll now load an initial step size, and loop 1037 0 stevel ! until we've managed to program TICK_COMPARE to fire in the future. 1038 0 stevel ! 1039 0 stevel mov 8, %o4 ! 8 = arbitrary inital step 1040 0 stevel 1: add %o0, %o4, %o5 ! Add the step 1041 0 stevel WR_TICKCMPR(%o5,%g1,%g2,__LINE__) ! Write to TICK_CMPR 1042 0 stevel GET_NATIVE_TIME(%o0, %g1, %g2) ! %o0 = tick 1043 0 stevel sllx %o0, 1, %o0 ! Clear the DIS bit 1044 0 stevel srlx %o0, 1, %o0 1045 0 stevel cmp %o5, %o0 ! In the future? 1046 0 stevel bg,a,pt %xcc, 2f ! Yes, drive on. 1047 0 stevel wrpr %g0, %g5, %pstate ! delay: enable vec intr 1048 0 stevel ba 1b ! No, try again. 1049 0 stevel sllx %o4, 1, %o4 ! delay: double step size 1050 0 stevel 1051 0 stevel 2: ba current_thread_complete 1052 0 stevel nop 1053 0 stevel SET_SIZE(tick_rtt) 1054 0 stevel 1055 0 stevel #endif /* lint */ 1056 8803 Jonathan 1057 8803 Jonathan #if defined(lint) 1058 8803 Jonathan 1059 8803 Jonathan /* ARGSUSED */ 1060 8803 Jonathan void 1061 8803 Jonathan pil15_interrupt(int level) 1062 8803 Jonathan {} 1063 8803 Jonathan 1064 8803 Jonathan #else /* lint */ 1065 8803 Jonathan 1066 8803 Jonathan /* 1067 8803 Jonathan * Level-15 interrupt prologue. 1068 8803 Jonathan */ 1069 8803 Jonathan ENTRY_NP(pil15_interrupt) 1070 8803 Jonathan CPU_ADDR(%g1, %g2) 1071 8803 Jonathan rdpr %tstate, %g6 1072 8803 Jonathan rdpr %tpc, %g5 1073 8803 Jonathan btst TSTATE_PRIV, %g6 ! trap from supervisor mode? 1074 8803 Jonathan bnz,a,pt %xcc, 1f 1075 8803 Jonathan stn %g5, [%g1 + CPU_CPCPROFILE_PC] ! if so, record kernel PC 1076 8803 Jonathan stn %g5, [%g1 + CPU_CPCPROFILE_UPC] ! if not, record user PC 1077 8803 Jonathan ba pil15_epilogue ! must be large-disp branch 1078 8803 Jonathan stn %g0, [%g1 + CPU_CPCPROFILE_PC] ! zero kernel PC 1079 8803 Jonathan 1: ba pil15_epilogue ! must be large-disp branch 1080 8803 Jonathan stn %g0, [%g1 + CPU_CPCPROFILE_UPC] ! zero user PC 1081 8803 Jonathan SET_SIZE(pil15_interrupt) 1082 8803 Jonathan 1083 8803 Jonathan #endif /* lint */ 1084 0 stevel 1085 0 stevel #if defined(lint) || defined(__lint) 1086 0 stevel 1087 0 stevel /* ARGSUSED */ 1088 0 stevel uint64_t 1089 0 stevel find_cpufrequency(volatile uchar_t *clock_ptr) 1090 0 stevel { 1091 0 stevel return (0); 1092 0 stevel } 1093 0 stevel 1094 0 stevel #else /* lint */ 1095 0 stevel 1096 0 stevel #ifdef DEBUG 1097 0 stevel .seg ".text" 1098 0 stevel find_cpufreq_panic: 1099 0 stevel .asciz "find_cpufrequency: interrupts already disabled on entry" 1100 0 stevel #endif /* DEBUG */ 1101 0 stevel 1102 0 stevel ENTRY_NP(find_cpufrequency) 1103 0 stevel rdpr %pstate, %g1 1104 0 stevel 1105 0 stevel #ifdef DEBUG 1106 0 stevel andcc %g1, PSTATE_IE, %g0 ! If DEBUG, check that interrupts 1107 0 stevel bnz 0f ! are currently enabled 1108 0 stevel sethi %hi(find_cpufreq_panic), %o1 1109 0 stevel call panic 1110 0 stevel or %o1, %lo(find_cpufreq_panic), %o0 1111 0 stevel #endif /* DEBUG */ 1112 0 stevel 1113 0 stevel 0: 1114 0 stevel wrpr %g1, PSTATE_IE, %pstate ! Disable interrupts 1115 0 stevel 3: 1116 0 stevel ldub [%o0], %o1 ! Read the number of seconds 1117 0 stevel mov %o1, %o2 ! remember initial value in %o2 1118 0 stevel 1: 1119 0 stevel GET_NATIVE_TIME(%o3, %g4, %g5) 1120 0 stevel cmp %o1, %o2 ! did the seconds register roll over? 1121 0 stevel be,pt %icc, 1b ! branch back if unchanged 1122 0 stevel ldub [%o0], %o2 ! delay: load the new seconds val 1123 0 stevel 1124 0 stevel brz,pn %o2, 3b ! if the minutes just rolled over, 1125 0 stevel ! the last second could have been 1126 0 stevel ! inaccurate; try again. 1127 0 stevel mov %o2, %o4 ! delay: store init. val. in %o2 1128 0 stevel 2: 1129 0 stevel GET_NATIVE_TIME(%o5, %g4, %g5) 1130 0 stevel cmp %o2, %o4 ! did the seconds register roll over? 1131 0 stevel be,pt %icc, 2b ! branch back if unchanged 1132 0 stevel ldub [%o0], %o4 ! delay: load the new seconds val 1133 0 stevel 1134 0 stevel brz,pn %o4, 0b ! if the minutes just rolled over, 1135 0 stevel ! the last second could have been 1136 0 stevel ! inaccurate; try again. 1137 0 stevel wrpr %g0, %g1, %pstate ! delay: re-enable interrupts 1138 0 stevel 1139 0 stevel retl 1140 0 stevel sub %o5, %o3, %o0 ! return the difference in ticks 1141 0 stevel SET_SIZE(find_cpufrequency) 1142 0 stevel 1143 0 stevel #endif /* lint */ 1144 0 stevel 1145 0 stevel #if defined(lint) 1146 0 stevel /* 1147 0 stevel * Prefetch a page_t for write or read, this assumes a linear 1148 0 stevel * scan of sequential page_t's. 1149 0 stevel */ 1150 0 stevel /*ARGSUSED*/ 1151 0 stevel void 1152 0 stevel prefetch_page_w(void *pp) 1153 0 stevel {} 1154 0 stevel 1155 0 stevel /*ARGSUSED*/ 1156 0 stevel void 1157 0 stevel prefetch_page_r(void *pp) 1158 0 stevel {} 1159 0 stevel #else /* lint */ 1160 0 stevel 1161 0 stevel #if defined(CHEETAH) || defined(CHEETAH_PLUS) || defined(JALAPENO) || \ 1162 0 stevel defined(SERRANO) 1163 0 stevel ! 1164 0 stevel ! On US-III, the prefetch instruction queue is 8 entries deep. 1165 0 stevel ! Also, prefetches for write put data in the E$, which has 1166 0 stevel ! lines of 512 bytes for an 8MB cache. Each E$ line is further 1167 0 stevel ! subblocked into 64 byte chunks. 1168 0 stevel ! 1169 0 stevel ! Since prefetch can only bring in 64 bytes at a time (See Sparc 1170 0 stevel ! v9 Architecture Manual pp.204) and a page_t is 128 bytes, 1171 0 stevel ! then 2 prefetches are required in order to bring an entire 1172 0 stevel ! page into the E$. 1173 0 stevel ! 1174 0 stevel ! Since the prefetch queue is 8 entries deep, we currently can 1175 0 stevel ! only have 4 prefetches for page_t's outstanding. Thus, we 1176 0 stevel ! prefetch n+4 ahead of where we are now: 1177 0 stevel ! 1178 0 stevel ! 4 * sizeof(page_t) -> 512 1179 0 stevel ! 4 * sizeof(page_t) +64 -> 576 1180 0 stevel ! 1181 0 stevel ! Example 1182 0 stevel ! ======= 1183 0 stevel ! contiguous page array in memory... 1184 0 stevel ! 1185 0 stevel ! |AAA1|AAA2|BBB1|BBB2|CCC1|CCC2|DDD1|DDD2|XXX1|XXX2|YYY1|YYY2|... 1186 0 stevel ! ^ ^ ^ ^ ^ ^ 1187 0 stevel ! pp | pp+4*sizeof(page)+64 1188 0 stevel ! | 1189 0 stevel ! pp+4*sizeof(page) 1190 0 stevel ! 1191 0 stevel ! Prefetch 1192 0 stevel ! Queue 1193 0 stevel ! +-------+<--- In this iteration, we're working with pp (AAA1), 1194 0 stevel ! |Preftch| but we enqueue prefetch for addr = XXX1 1195 0 stevel ! | XXX1 | 1196 0 stevel ! +-------+<--- this queue slot will be a prefetch instruction for 1197 0 stevel ! |Preftch| for addr = pp + 4*sizeof(page_t) + 64 (or second 1198 0 stevel ! | XXX2 | half of page XXX) 1199 0 stevel ! +-------+ 1200 0 stevel ! |Preftch|<-+- The next time around this function, we'll be 1201 0 stevel ! | YYY1 | | working with pp = BBB1, but will be enqueueing 1202 0 stevel ! +-------+ | prefetches to for both halves of page YYY, 1203 0 stevel ! |Preftch| | while both halves of page XXX are in transit 1204 0 stevel ! | YYY2 |<-+ make their way into the E$. 1205 0 stevel ! +-------+ 1206 0 stevel ! |Preftch| 1207 0 stevel ! | ZZZ1 | 1208 0 stevel ! +-------+ 1209 0 stevel ! . . 1210 0 stevel ! : : 1211 0 stevel ! 1212 0 stevel ! E$ 1213 0 stevel ! +============================================... 1214 0 stevel ! | XXX1 | XXX2 | YYY1 | YYY2 | ZZZ1 | ZZZ2 | 1215 0 stevel ! +============================================... 1216 0 stevel ! | | | | | | | 1217 0 stevel ! +============================================... 1218 0 stevel ! . 1219 0 stevel ! : 1220 0 stevel ! 1221 0 stevel ! So we should expect the first four page accesses to stall 1222 0 stevel ! while we warm up the cache, afterwhich, most of the pages 1223 0 stevel ! will have their pp ready in the E$. 1224 0 stevel ! 1225 0 stevel ! Also note that if sizeof(page_t) grows beyond 128, then 1226 0 stevel ! we'll need an additional prefetch to get an entire page 1227 0 stevel ! into the E$, thus reducing the number of outstanding page 1228 0 stevel ! prefetches to 2 (ie. 3 prefetches/page = 6 queue slots) 1229 0 stevel ! etc. 1230 0 stevel ! 1231 0 stevel ! Cheetah+ 1232 0 stevel ! ======== 1233 0 stevel ! On Cheetah+ we use "#n_write" prefetches as these avoid 1234 0 stevel ! unnecessary RTS->RTO bus transaction state change, and 1235 0 stevel ! just issues RTO transaction. (See pp.77 of Cheetah+ Delta 1236 0 stevel ! PRM). On Cheetah, #n_write prefetches are reflected with 1237 0 stevel ! RTS->RTO state transition regardless. 1238 0 stevel ! 1239 0 stevel #define STRIDE1 512 1240 0 stevel #define STRIDE2 576 1241 0 stevel 1242 0 stevel #if STRIDE1 != (PAGE_SIZE * 4) 1243 0 stevel #error "STRIDE1 != (PAGE_SIZE * 4)" 1244 0 stevel #endif /* STRIDE1 != (PAGE_SIZE * 4) */ 1245 0 stevel 1246 0 stevel ENTRY(prefetch_page_w) 1247 0 stevel prefetch [%o0+STRIDE1], #n_writes 1248 0 stevel retl 1249 0 stevel prefetch [%o0+STRIDE2], #n_writes 1250 0 stevel SET_SIZE(prefetch_page_w) 1251 0 stevel 1252 0 stevel ! 1253 0 stevel ! Note on CHEETAH to prefetch for read, we really use #one_write. 1254 0 stevel ! This fetches to E$ (general use) rather than P$ (floating point use). 1255 0 stevel ! 1256 0 stevel ENTRY(prefetch_page_r) 1257 0 stevel prefetch [%o0+STRIDE1], #one_write 1258 0 stevel retl 1259 0 stevel prefetch [%o0+STRIDE2], #one_write 1260 0 stevel SET_SIZE(prefetch_page_r) 1261 0 stevel 1262 0 stevel #elif defined(SPITFIRE) || defined(HUMMINGBIRD) 1263 0 stevel 1264 0 stevel ! 1265 0 stevel ! UltraSparcII can have up to 3 prefetches outstanding. 1266 0 stevel ! A page_t is 128 bytes (2 prefetches of 64 bytes each) 1267 0 stevel ! So prefetch for pp + 1, which is 1268 0 stevel ! 1269 0 stevel ! pp + sizeof(page_t) 1270 0 stevel ! and 1271 0 stevel ! pp + sizeof(page_t) + 64 1272 0 stevel ! 1273 0 stevel #define STRIDE1 128 1274 0 stevel #define STRIDE2 192 1275 0 stevel 1276 0 stevel #if STRIDE1 != PAGE_SIZE 1277 0 stevel #error "STRIDE1 != PAGE_SIZE" 1278 0 stevel #endif /* STRIDE1 != PAGE_SIZE */ 1279 0 stevel 1280 0 stevel ENTRY(prefetch_page_w) 1281 0 stevel prefetch [%o0+STRIDE1], #n_writes 1282 0 stevel retl 1283 0 stevel prefetch [%o0+STRIDE2], #n_writes 1284 0 stevel SET_SIZE(prefetch_page_w) 1285 0 stevel 1286 0 stevel ENTRY(prefetch_page_r) 1287 0 stevel prefetch [%o0+STRIDE1], #n_reads 1288 0 stevel retl 1289 0 stevel prefetch [%o0+STRIDE2], #n_reads 1290 0 stevel SET_SIZE(prefetch_page_r) 1291 1772 jl139090 1292 1772 jl139090 #elif defined(OLYMPUS_C) 1293 1772 jl139090 ! 1294 1856 hyw ! Prefetch strides for Olympus-C 1295 1772 jl139090 ! 1296 1772 jl139090 1297 1856 hyw #define STRIDE1 0x440 1298 1856 hyw #define STRIDE2 0x640 1299 1772 jl139090 1300 1772 jl139090 ENTRY(prefetch_page_w) 1301 1772 jl139090 prefetch [%o0+STRIDE1], #n_writes 1302 1772 jl139090 retl 1303 1772 jl139090 prefetch [%o0+STRIDE2], #n_writes 1304 1772 jl139090 SET_SIZE(prefetch_page_w) 1305 1772 jl139090 1306 1772 jl139090 ENTRY(prefetch_page_r) 1307 1772 jl139090 prefetch [%o0+STRIDE1], #n_writes 1308 1772 jl139090 retl 1309 1772 jl139090 prefetch [%o0+STRIDE2], #n_writes 1310 1772 jl139090 SET_SIZE(prefetch_page_r) 1311 1772 jl139090 #else /* OLYMPUS_C */ 1312 0 stevel 1313 0 stevel #error "You need to fix this for your new cpu type." 1314 0 stevel 1315 1772 jl139090 #endif /* OLYMPUS_C */ 1316 0 stevel 1317 0 stevel #endif /* lint */ 1318 0 stevel 1319 0 stevel #if defined(lint) 1320 0 stevel /* 1321 0 stevel * Prefetch struct smap for write. 1322 0 stevel */ 1323 0 stevel /*ARGSUSED*/ 1324 0 stevel void 1325 0 stevel prefetch_smap_w(void *smp) 1326 0 stevel {} 1327 0 stevel #else /* lint */ 1328 0 stevel 1329 0 stevel #if defined(CHEETAH) || defined(CHEETAH_PLUS) || defined(JALAPENO) || \ 1330 0 stevel defined(SERRANO) 1331 0 stevel 1332 0 stevel #define PREFETCH_Q_LEN 8 1333 0 stevel 1334 0 stevel #elif defined(SPITFIRE) || defined(HUMMINGBIRD) 1335 0 stevel 1336 0 stevel #define PREFETCH_Q_LEN 3 1337 0 stevel 1338 1772 jl139090 #elif defined(OLYMPUS_C) 1339 1772 jl139090 ! 1340 1856 hyw ! Use length of one for now. 1341 1856 hyw ! 1342 1772 jl139090 #define PREFETCH_Q_LEN 1 1343 1772 jl139090 1344 1772 jl139090 #else /* OLYMPUS_C */ 1345 0 stevel 1346 0 stevel #error You need to fix this for your new cpu type. 1347 0 stevel 1348 1772 jl139090 #endif /* OLYMPUS_C */ 1349 0 stevel 1350 0 stevel #include <vm/kpm.h> 1351 0 stevel 1352 0 stevel #ifdef SEGKPM_SUPPORT 1353 0 stevel 1354 0 stevel #define SMAP_SIZE 72 1355 0 stevel #define SMAP_STRIDE (((PREFETCH_Q_LEN * 64) / SMAP_SIZE) * 64) 1356 0 stevel 1357 0 stevel #else /* SEGKPM_SUPPORT */ 1358 0 stevel 1359 0 stevel ! 1360 0 stevel ! The hardware will prefetch the 64 byte cache aligned block 1361 0 stevel ! that contains the address specified in the prefetch instruction. 1362 0 stevel ! Since the size of the smap struct is 48 bytes, issuing 1 prefetch 1363 0 stevel ! per pass will suffice as long as we prefetch far enough ahead to 1364 0 stevel ! make sure we don't stall for the cases where the smap object 1365 0 stevel ! spans multiple hardware prefetch blocks. Let's prefetch as far 1366 0 stevel ! ahead as the hardware will allow. 1367 0 stevel ! 1368 0 stevel ! The smap array is processed with decreasing address pointers. 1369 0 stevel ! 1370 0 stevel #define SMAP_SIZE 48 1371 0 stevel #define SMAP_STRIDE (PREFETCH_Q_LEN * SMAP_SIZE) 1372 0 stevel 1373 0 stevel #endif /* SEGKPM_SUPPORT */ 1374 0 stevel 1375 0 stevel ENTRY(prefetch_smap_w) 1376 0 stevel retl 1377 0 stevel prefetch [%o0-SMAP_STRIDE], #n_writes 1378 0 stevel SET_SIZE(prefetch_smap_w) 1379 0 stevel 1380 0 stevel #endif /* lint */ 1381 0 stevel 1382 0 stevel #if defined(lint) || defined(__lint) 1383 0 stevel 1384 0 stevel /* ARGSUSED */ 1385 0 stevel uint64_t 1386 0 stevel getidsr(void) 1387 0 stevel { return 0; } 1388 0 stevel 1389 0 stevel #else /* lint */ 1390 0 stevel 1391 0 stevel ENTRY_NP(getidsr) 1392 0 stevel retl 1393 0 stevel ldxa [%g0]ASI_INTR_DISPATCH_STATUS, %o0 1394 0 stevel SET_SIZE(getidsr) 1395 0 stevel 1396 0 stevel #endif /* lint */ 1397