1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26#pragma ident "%Z%%M% %I% %E% SMI" 27 28/* 29 * This file is through cpp before being used as 30 * an inline. It contains support routines used 31 * only by DR for the copy-rename sequence. 32 */ 33 34#if defined(lint) 35#include <sys/types.h> 36#else 37#include "assym.h" 38#include "drmach_offsets.h" 39#endif /* lint */ 40 41#include <sys/asm_linkage.h> 42#include <sys/param.h> 43#include <sys/privregs.h> 44#include <sys/spitregs.h> 45#include <sys/mmu.h> 46#include <sys/machthread.h> 47#include <sys/pte.h> 48#include <sys/stack.h> 49#include <sys/vis.h> 50#include <sys/intreg.h> 51#include <sys/cheetahregs.h> 52#include <sys/drmach.h> 53 54#if !defined(lint) 55 56/* 57 * turn off speculative mode to prevent unwanted memory access 58 * when we are in the FMEM loops 59 */ 60 61#define FJSV_SPECULATIVE_OFF(reg, tmp1, tmp2) \ 62 rdpr %pstate, reg ;\ 63 andn reg, PSTATE_IE, tmp1 ;\ 64 wrpr %g0, tmp1, %pstate ;\ 65 ldxa [%g0]ASI_MCNTL, tmp1 ;\ 66 set 1, tmp2 ;\ 67 sllx tmp2, MCNTL_SPECULATIVE_SHIFT, tmp2 ;\ 68 or tmp1, tmp2, tmp1 ;\ 69 stxa tmp1, [%g0]ASI_MCNTL ;\ 70 membar #Sync 71#endif 72 73 74#if defined(lint) 75/*ARGSUSED*/ 76void 77drmach_fmem_loop_script(caddr_t critical, int size, caddr_t stat) 78{ return; } 79#else /* lint */ 80 .align 8 81 ENTRY_NP(drmach_fmem_loop_script) 82 /* turn off speculative mode */ 83 FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); 84 85 /* read the critical region to get everything in the cache */ 86 mov %o0, %o3 870: 88 ldx [%o3], %o4 89 sub %o1, 8, %o1 90 brnz %o1, 0b 91 add %o3, 8, %o3 92 93 /* clear L2_CTRL_UGE_TRAP error bit */ 94 mov ASI_L2_CTRL_RW_ADDR, %o1 95 ldxa [%o1]ASI_L2_CTRL, %o3 96 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 97 btst %o3, %o4 98 bz,pn %xcc, 1f 99 nop 100 stxa %o4, [%o1]ASI_L2_CTRL 101 102 /* now tell the master CPU that we are ready */ 1031: 104 set FMEM_LOOP_FMEM_READY, %o3 105 stb %o3, [%o2] 106 membar #Sync 107 ba 5f 108 nop 109 110 /* 111 * note that we branch to 5f, which branches right back to 2 here. 112 * The trick is that when that branch instruction has already been 113 * patched to a branch to itself - an infinite loop. 114 * The master thread will patch it back to "ba 2b" when it 115 * completes. 116 */ 117 118 /* Once we are back, we first check if there has been any 119 * L2_CTRL_UGE_TRAP errors, if so we have to fail the 120 * operation. This will cause a panic because the system 121 * is already in inconsistent state. 122 */ 1232: 124 mov %g0, %o1 125 mov ASI_L2_CTRL_RW_ADDR, %o3 126 ldxa [%o3]ASI_L2_CTRL, %o3 127 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 128 btst %o3, %o4 129 bz,pn %xcc, 3f 130 mov %g0, %o4 131 set FMEM_HW_ERROR, %o4 132 133 /* set error code and stat code */ 1343: 135 set FMEM_LOOP_DONE, %o3 136 stb %o3, [%o2] 137 138 /* turn on speculative mode again */ 139 ldxa [%g0]ASI_MCNTL, %o0 140 set 1, %o1 141 sllx %o1, MCNTL_SPECULATIVE_SHIFT, %o1 142 andn %o0, %o1, %o0 143 ba 4f 144 nop 145.align 32 1464: 147 stxa %o0, [%g0]ASI_MCNTL 148 membar #Sync 149 wrpr %g0, %o5, %pstate 150 retl 151 mov %o4, %o0 152.align 8 1535: 154 ALTENTRY(drmach_fmem_loop_script_rtn) 155 /* 156 * busy wait will affect sibling strands so 157 * we put sleep instruction in the delay slot 158 */ 159 ba 2b 160.word 0x81b01060 161 nop 162 SET_SIZE(drmach_fmem_loop_script) 163#endif /* lint */ 164 165#if defined(lint) 166/*ARGSUSED*/ 167void 168drmach_flush_icache(void) 169{ return; } 170#else /* lint */ 171 .align 8 172 ENTRY_NP(drmach_flush_icache) 173 stxa %g0, [%g0]ASI_ALL_FLUSH_L1I 174 membar #Sync 175 retl 176 nop 177 SET_SIZE(drmach_flush_icache) 178#endif 179 180#if defined(lint) 181/*ARGSUSED*/ 182int 183drmach_fmem_exec_script(caddr_t critical, int size) 184{ return (0); } 185#else /* lint */ 186.align 32 187 ENTRY_NP(drmach_fmem_exec_script) 188 /* turn off speculative mode */ 189 FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); 190 /* save locals to save area */ 191 add %o0, SAVE_LOCAL, %o2 192 stx %l0, [%o2+8*0] 193 stx %l1, [%o2+8*1] 194 stx %l2, [%o2+8*2] 195 stx %l3, [%o2+8*3] 196 stx %l4, [%o2+8*4] 197 stx %l5, [%o2+8*5] 198 stx %l6, [%o2+8*6] 199 stx %l7, [%o2+8*7] 200 mov %o5, %l6 201 /* l7 is set only when FMEM cmd is issued to SCF */ 202 mov %g0, %l7 203 204 /* read the critical region to put everything in the cache */ 205 mov %o0, %o2 2060: 207 ldx [%o2], %o4 208 sub %o1, 8, %o1 209 brnz %o1, 0b 210 add %o2, 8, %o2 211 ba 4f 212 nop 213 214 /* we branch to 4f but eventually we branch back here to finish up */ 2151: 216 mov %l6, %o5 217 /* 218 * save some registers for debugging 219 * l0 - SCF_REG_BASE 220 * l1 - SCF_TD 221 * l2 - SCF_TD + 8 222 * l5 - DELAY 223 */ 224 add %o0, SAVE_LOG, %o1 225 stx %l0, [%o1+8*0] 226 stx %l1, [%o1+8*1] 227 stx %l2, [%o1+8*2] 228 stx %l5, [%o1+8*3] 229 230 add %o0, FMEM_ISSUED, %o1 231 st %l7, [%o1] 232 233 /* Check for L2_CTRL_UGE_TRAP error */ 234 mov ASI_L2_CTRL_RW_ADDR, %l0 235 ldxa [%l0]ASI_L2_CTRL, %l1 236 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 237 btst %l1, %l2 238 bz,pn %xcc, 2f 239 nop 240 mov FMEM_HW_ERROR, %o4 2412: 242 /* restore all locals */ 243 add %o0, SAVE_LOCAL, %o1 244 ldx [%o1+8*0], %l0 245 ldx [%o1+8*1], %l1 246 ldx [%o1+8*2], %l2 247 ldx [%o1+8*3], %l3 248 ldx [%o1+8*4], %l4 249 ldx [%o1+8*5], %l5 250 ldx [%o1+8*6], %l6 251 ldx [%o1+8*7], %l7 252 253 /* turn on speculative mode */ 254 ldxa [%g0]ASI_MCNTL, %o1 255 set 1, %o2 256 sllx %o2, MCNTL_SPECULATIVE_SHIFT, %o2 257 andn %o1, %o2, %o1 258 ba 3f 259 nop 260.align 32 2613: 262 stxa %o1, [%g0]ASI_MCNTL 263 membar #Sync 264 /* return error code here */ 265 mov %o4, %o0 266 retl 267 wrpr %g0, %o5, %pstate 268 269 /* clear L2_CTRL_UGE_TRAP error bit */ 2704: 271 mov ASI_L2_CTRL_RW_ADDR, %l0 272 ldxa [%l0]ASI_L2_CTRL, %l1 273 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 274 btst %l1, %l2 275 bz,pn %xcc, 5f 276 nop 277 stxa %l2, [%l0]ASI_L2_CTRL 2785: 279 /* set up the register locations and parameters */ 280 ldx [%o0 + SCF_REG_BASE], %l0 281 ldx [%o0 + SCF_TD], %l1 282 ldx [%o0 + SCF_TD+8], %l2 283 ldx [%o0 + DELAY], %l5 284 285 /* check if SCF is busy */ 286 add %l0, SCF_COMMAND, %o1 287 lduha [%o1]ASI_IO, %o2 288 sethi %hi(SCF_CMD_BUSY), %o3 289 btst %o2, %o3 290 be %xcc, 6f 291 nop 292 ba 1b 293 mov FMEM_SCF_BUSY, %o4 294 295 /* clear STATUS bit */ 2966: 297 add %l0, SCF_STATUS, %o1 298 lduha [%o1]ASI_IO, %o2 299 sethi %hi(SCF_STATUS_READY), %o3 300 btst %o2, %o3 301 be %xcc, 7f 302 nop 303 stha %o3, [%o1]ASI_IO 304 305 /* clear CMD_COMPLETE bit */ 3067: 307 mov SCF_STATUS_CMD_COMPLETE, %o3 308 btst %o2, %o3 309 be,a %xcc, 8f 310 nop 311 stha %o3, [%o1]ASI_IO 3128: 313 add %l0, (SCF_TDATA+0xe), %o1 314 mov %l2, %o4 315 mov SCF_RETRY_CNT, %o5 316 317 sethi %hi(0xffff), %l2 318 or %l2, %lo(0xffff), %l2 319 320 and %o4, %l2, %o3 321 322 /* 323 * o1 points to SCFBASE.SCF_TDATA[0xe] 324 * l0 points to SCFBASE 325 * crticial->SCF_TD[0] = source board # 326 * crticial->SCF_TD[1] = target board # 327 * l1 = critical->SCF_TD[0 - 7] 328 * l2 = 0xffff 329 * o4 = critical->SCF_TD[8 - 15] 330 * o3 = (*o4) & 0xffff 331 332 /* 333 * Because there is no parity protection on the ebus 334 * we read the data back after the write to verify 335 * we write 2 bytes at a time. 336 * If the data read is not the same as data written 337 * we retry up to a limit of FMEM_RETRY_OUT 338 */ 3399: 340 stha %o3, [%o1]ASI_IO 341 lduha [%o1]ASI_IO, %o2 342 sub %o5, 1, %o5 343 brz,a %o5, 1b 344 mov FMEM_RETRY_OUT, %o4 345 cmp %o2, %o3 346 bne,a 9b 347 nop 348 349 sub %o1, %l0, %o2 350 cmp %o2, (SCF_TDATA+0x8) 351 bne %xcc, 2f 352 srlx %o4, 16, %o4 353 mov %l1, %o4 354 355 /* if we have reach TDATA+8, we switch to l1 */ 356 /* XXX: Why we need 2 loops??? */ 3572: 358 sub %o1, 2, %o1 359 mov SCF_RETRY_CNT, %o5 360 and %o4, %l2, %o3 361 362 sub %o1, %l0, %o2 363 cmp %o2, (SCF_TDATA) 364 bge,a 9b 365 nop 366 367 /* if we reach TDATA, we are done */ 368 369 /* read from SCF back to our buffer for debugging */ 370 add %l0, (SCF_TDATA), %o1 371 ldxa [%o1]ASI_IO, %o2 372 stx %o2, [%o0+SCF_TD] 373 374 add %l0, (SCF_TDATA+8), %o1 375 ldxa [%o1]ASI_IO, %o2 376 stx %o2, [%o0+SCF_TD+8] 377 378 379 rd STICK, %l1 380 add %l5, %l1, %l5 381 382 /* Now tell SCF to do it */ 383 add %l0, SCF_COMMAND, %o1 384 385 /* 0x10A6 is the magic command */ 386 sethi %hi(0x10A6), %o2 387 or %o2, %lo(0x10A6), %o2 388 stha %o2, [%o1]ASI_IO 389 390 mov 1, %l7 ! FMEM is issued 391 392 add %l0, SCF_STATUS, %o1 393 sethi %hi(SCF_STATUS_READY), %o2 394 mov SCF_STATUS_CMD_COMPLETE, %o3 395 396 /* read STATUS_READY bit and clear it only if it is set */ 397 /* XXX: this STATUS_READY checking seems meaningless */ 3983: 399 lduha [%o1]ASI_IO, %o4 400 btst %o2, %o4 401 be %xcc, 4f ! STATUS_READY is not set 402 nop 403 stha %o2, [%o1]ASI_IO ! Clear if the bit is set 404 405 /* check CMD_COMPLETE bit and clear */ 4064: 407 btst %o3, %o4 408 be %xcc, 5f ! CMD_COMPLETE is not set 409 nop 410 stha %o3, [%o1]ASI_IO ! Now we are done and clear it 411 mov FMEM_NO_ERROR, %o4 412 ba %xcc, 6f 413 nop 414 415 /* timeout delay checking */ 4165: 417 rd STICK, %l2 418 cmp %l5, %l2 419 bge %xcc, 3b 420 nop 421 mov FMEM_TIMEOUT, %o4 422 423 /* we are done or timed out */ 4246: 425 ba,a 1b 426 nop 427 SET_SIZE(drmach_fmem_exec_script) 428#endif /* lint */ 429 430#if defined(lint) 431/*ARGSUSED*/ 432void 433drmach_fmem_exec_script_end(caddr_t critical, int size) 434{ return; } 435#else /* lint */ 436 ENTRY_NP(drmach_fmem_exec_script_end) 437 nop 438 SET_SIZE(drmach_fmem_exec_script_end) 439#endif /* lint */ 440 441#if defined(lint) 442uint64_t 443patch_inst(uint64_t *x, uint64_t y) 444{ 445 *x = y; 446 return (0); 447} 448 449#else /* lint */ 450 451 ENTRY_NP(patch_inst) 452 ldx [%o0], %o2 453 casx [%o0], %o2, %o1 454 flush %o0 455 membar #Sync 456 ldx [%o0], %o2 457 retl 458 mov %o2, %o0 459 SET_SIZE(patch_inst) 460 461#endif /* lint */ 462 463#if defined(lint) 464void 465drmach_sys_trap() 466{ 467} 468#else /* lint */ 469 ENTRY_NP(drmach_sys_trap) 470 mov -1, %g4 471 set sys_trap, %g5 472 jmp %g5 473 nop 474 SET_SIZE(drmach_sys_trap) 475#endif /* lint */ 476 477#if defined(lint) 478uint64_t 479drmach_get_stick() 480{ 481 return (0); 482} 483#else /* lint */ 484 ENTRY_NP(drmach_get_stick) 485 retl 486 rd STICK, %o0 487 SET_SIZE(drmach_get_stick) 488#endif /* lint */ 489 490#if defined(lint) 491/*ARGSUSED*/ 492void 493drmach_flush(void) 494{} 495 496#else /* lint */ 497 ENTRY_NP(drmach_flush) 498 mov %o0, %o2 4990: 500 flush %o2 501 sub %o1, 8, %o1 502 brnz %o1, 0b 503 add %o2, 8, %o2 504 retl 505 nop 506 SET_SIZE(drmach_flush) 507#endif /* lint */ 508