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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This file is through cpp before being used as 29 * an inline. It contains support routines used 30 * only by DR for the copy-rename sequence. 31 */ 32 33 #if defined(lint) 34 #include <sys/types.h> 35 #else 36 #include "assym.h" 37 #include "drmach_offsets.h" 38 #endif /* lint */ 39 40 #include <sys/asm_linkage.h> 41 #include <sys/param.h> 42 #include <sys/privregs.h> 43 #include <sys/spitregs.h> 44 #include <sys/mmu.h> 45 #include <sys/machthread.h> 46 #include <sys/pte.h> 47 #include <sys/stack.h> 48 #include <sys/vis.h> 49 #include <sys/intreg.h> 50 #include <sys/cheetahregs.h> 51 #include <sys/drmach.h> 52 #include <sys/sbd_ioctl.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*/ 76 void 77 drmach_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 87 0: 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 */ 103 1: 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 */ 123 2: 124 mov ASI_L2_CTRL_RW_ADDR, %o3 125 ldxa [%o3]ASI_L2_CTRL, %o3 126 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 127 btst %o3, %o4 128 bz,pn %xcc, 3f 129 mov %g0, %o4 130 set EOPL_FMEM_HW_ERROR, %o4 131 132 /* set error code and stat code */ 133 3: 134 set FMEM_LOOP_DONE, %o3 135 stb %o3, [%o2] 136 137 /* turn on speculative mode again */ 138 ldxa [%g0]ASI_MCNTL, %o0 139 set 1, %o1 140 sllx %o1, MCNTL_SPECULATIVE_SHIFT, %o1 141 andn %o0, %o1, %o0 142 ba 4f 143 nop 144 .align 32 145 4: 146 stxa %o0, [%g0]ASI_MCNTL 147 membar #Sync 148 wrpr %g0, %o5, %pstate 149 retl 150 mov %o4, %o0 151 .align 8 152 5: 153 ALTENTRY(drmach_fmem_loop_script_rtn) 154 /* 155 * busy wait will affect sibling strands so 156 * we put sleep instruction in the delay slot 157 */ 158 ba 2b 159 .word 0x81b01060 160 SET_SIZE(drmach_fmem_loop_script) 161 #endif /* lint */ 162 163 #if defined(lint) 164 /*ARGSUSED*/ 165 void 166 drmach_flush_icache(void) 167 { return; } 168 #else /* lint */ 169 .align 8 170 ENTRY_NP(drmach_flush_icache) 171 stxa %g0, [%g0]ASI_ALL_FLUSH_L1I 172 membar #Sync 173 retl 174 nop 175 SET_SIZE(drmach_flush_icache) 176 #endif 177 178 #if defined(lint) 179 /*ARGSUSED*/ 180 int 181 drmach_fmem_exec_script(caddr_t critical, int size) 182 { return (0); } 183 #else /* lint */ 184 .align 32 185 ENTRY_NP(drmach_fmem_exec_script) 186 /* turn off speculative mode */ 187 FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); 188 /* save locals to save area */ 189 add %o0, SAVE_LOCAL, %o2 190 stx %l0, [%o2+8*0] 191 stx %l1, [%o2+8*1] 192 stx %l2, [%o2+8*2] 193 stx %l3, [%o2+8*3] 194 stx %l4, [%o2+8*4] 195 stx %l5, [%o2+8*5] 196 stx %l6, [%o2+8*6] 197 stx %l7, [%o2+8*7] 198 mov %o5, %l6 199 /* l7 is set only when FMEM cmd is issued to SCF */ 200 mov %g0, %l7 201 202 /* read the critical region to put everything in the cache */ 203 mov %o0, %o2 204 0: 205 ldx [%o2], %o4 206 sub %o1, 8, %o1 207 brnz %o1, 0b 208 add %o2, 8, %o2 209 ba 4f 210 nop 211 212 /* we branch to 4f but eventually we branch back here to finish up */ 213 1: 214 mov %l6, %o5 215 /* 216 * save some registers for debugging 217 * l0 - SCF_REG_BASE 218 * l1 - SCF_TD 219 * l2 - SCF_TD + 8 220 * l5 - DELAY 221 */ 222 add %o0, SAVE_LOG, %o1 223 stx %l0, [%o1+8*0] 224 stx %l1, [%o1+8*1] 225 stx %l2, [%o1+8*2] 226 stx %l5, [%o1+8*3] 227 228 add %o0, FMEM_ISSUED, %o1 229 st %l7, [%o1] 230 231 /* Check for L2_CTRL_UGE_TRAP error */ 232 mov ASI_L2_CTRL_RW_ADDR, %l0 233 ldxa [%l0]ASI_L2_CTRL, %l1 234 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 235 btst %l1, %l2 236 bz,pn %xcc, 2f 237 nop 238 set EOPL_FMEM_HW_ERROR, %o4 239 2: 240 /* restore all locals */ 241 add %o0, SAVE_LOCAL, %o1 242 ldx [%o1+8*0], %l0 243 ldx [%o1+8*1], %l1 244 ldx [%o1+8*2], %l2 245 ldx [%o1+8*3], %l3 246 ldx [%o1+8*4], %l4 247 ldx [%o1+8*5], %l5 248 ldx [%o1+8*6], %l6 249 ldx [%o1+8*7], %l7 250 251 /* turn on speculative mode */ 252 ldxa [%g0]ASI_MCNTL, %o1 253 set 1, %o2 254 sllx %o2, MCNTL_SPECULATIVE_SHIFT, %o2 255 andn %o1, %o2, %o1 256 ba 3f 257 nop 258 .align 32 259 3: 260 stxa %o1, [%g0]ASI_MCNTL 261 membar #Sync 262 /* return error code here */ 263 mov %o4, %o0 264 retl 265 wrpr %g0, %o5, %pstate 266 267 /* clear L2_CTRL_UGE_TRAP error bit */ 268 4: 269 mov ASI_L2_CTRL_RW_ADDR, %l0 270 ldxa [%l0]ASI_L2_CTRL, %l1 271 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 272 btst %l1, %l2 273 bz,pn %xcc, 5f 274 nop 275 stxa %l2, [%l0]ASI_L2_CTRL 276 5: 277 /* set up the register locations and parameters */ 278 ldx [%o0 + SCF_REG_BASE], %l0 279 ldx [%o0 + SCF_TD], %l1 280 ldx [%o0 + SCF_TD+8], %l2 281 ldx [%o0 + DELAY], %l5 282 283 /* check if SCF is ONLINE */ 284 add %l0, SCF_STATUS_EX, %o1 285 lduwa [%o1]ASI_IO, %o2 286 sethi %hi(SCF_STATUS_EX_ONLINE), %o3 287 btst %o2, %o3 288 bne %xcc, 6f 289 nop 290 set EOPL_FMEM_SCF_OFFLINE, %o4 291 ba 1b 292 nop 293 294 /* check if SCF is busy */ 295 add %l0, SCF_COMMAND, %o1 296 lduha [%o1]ASI_IO, %o2 297 sethi %hi(SCF_CMD_BUSY), %o3 298 btst %o2, %o3 299 be %xcc, 6f 300 nop 301 set EOPL_FMEM_SCF_BUSY, %o4 302 ba 1b 303 nop 304 305 /* clear STATUS bit */ 306 6: 307 add %l0, SCF_STATUS, %o1 308 lduha [%o1]ASI_IO, %o2 309 sethi %hi(SCF_STATUS_READY), %o3 310 btst %o2, %o3 311 be %xcc, 7f 312 nop 313 stha %o3, [%o1]ASI_IO 314 315 /* clear CMD_COMPLETE bit */ 316 7: 317 mov SCF_STATUS_CMD_COMPLETE, %o3 318 btst %o2, %o3 319 be,a %xcc, 8f 320 nop 321 stha %o3, [%o1]ASI_IO 322 8: 323 add %l0, (SCF_TDATA+0xe), %o1 324 mov %l2, %o4 325 mov SCF_RETRY_CNT, %o5 326 327 sethi %hi(0xffff), %l2 328 or %l2, %lo(0xffff), %l2 329 330 and %o4, %l2, %o3 331 332 /* 333 * o1 points to SCFBASE.SCF_TDATA[0xe] 334 * l0 points to SCFBASE 335 * crticial->SCF_TD[0] = source board # 336 * crticial->SCF_TD[1] = target board # 337 * l1 = critical->SCF_TD[0 - 7] 338 * l2 = 0xffff 339 * o4 = critical->SCF_TD[8 - 15] 340 * o3 = (*o4) & 0xffff 341 342 /* 343 * Because there is no parity protection on the ebus 344 * we read the data back after the write to verify 345 * we write 2 bytes at a time. 346 * If the data read is not the same as data written 347 * we retry up to a limit of SCF_RETRY_CNT 348 */ 349 9: 350 stha %o3, [%o1]ASI_IO 351 lduha [%o1]ASI_IO, %o2 352 sub %o5, 1, %o5 353 brnz %o5, 7f 354 nop 355 set EOPL_FMEM_RETRY_OUT, %o4 356 ba 1b 357 nop 358 7: 359 cmp %o2, %o3 360 bne,a 9b 361 nop 362 363 sub %o1, %l0, %o2 364 cmp %o2, (SCF_TDATA+0x8) 365 bne %xcc, 2f 366 srlx %o4, 16, %o4 367 mov %l1, %o4 368 369 /* if we have reach TDATA+8, we switch to l1 */ 370 /* XXX: Why we need 2 loops??? */ 371 2: 372 sub %o1, 2, %o1 373 mov SCF_RETRY_CNT, %o5 374 and %o4, %l2, %o3 375 376 sub %o1, %l0, %o2 377 cmp %o2, (SCF_TDATA) 378 bge,a 9b 379 nop 380 381 /* if we reach TDATA, we are done */ 382 383 /* read from SCF back to our buffer for debugging */ 384 add %l0, (SCF_TDATA), %o1 385 ldxa [%o1]ASI_IO, %o2 386 stx %o2, [%o0+SCF_TD] 387 388 add %l0, (SCF_TDATA+8), %o1 389 ldxa [%o1]ASI_IO, %o2 390 stx %o2, [%o0+SCF_TD+8] 391 392 /* The following code conforms to the FMEM 393 sequence (4) as described in the Columbus2 394 logical spec section 4.6 395 */ 396 397 /* read from SCF SB INFO register */ 398 sethi %hi(SCF_SB_INFO_OFFSET), %o2 399 or %o2, %lo(SCF_SB_INFO_OFFSET), %o2 400 add %l0, %o2, %o1 401 lduba [%o1]ASI_IO, %o2 402 403 /* If BUSY bit is set, abort */ 404 or %g0, (SCF_SB_INFO_BUSY), %o1 405 btst %o1, %o2 406 set EOPL_FMEM_SCF_BUSY, %o4 407 bne 1b 408 nop 409 410 rd STICK, %l1 411 add %l5, %l1, %l5 412 413 /* Now tell SCF to do it */ 414 add %l0, SCF_COMMAND, %o1 415 416 /* 0x10A6 is the magic command */ 417 sethi %hi(0x10A6), %o2 418 or %o2, %lo(0x10A6), %o2 419 stha %o2, [%o1]ASI_IO 420 421 mov 1, %l7 ! FMEM is issued 422 423 add %l0, SCF_STATUS, %o1 424 sethi %hi(SCF_STATUS_READY), %o2 425 mov SCF_STATUS_CMD_COMPLETE, %o3 426 427 /* read STATUS_READY bit and clear it only if it is set */ 428 /* XXX: this STATUS_READY checking seems meaningless */ 429 3: 430 lduha [%o1]ASI_IO, %o4 431 btst %o2, %o4 432 be %xcc, 4f ! STATUS_READY is not set 433 nop 434 stha %o2, [%o1]ASI_IO ! Clear if the bit is set 435 436 /* check CMD_COMPLETE bit and clear */ 437 4: 438 btst %o3, %o4 439 be %xcc, 5f ! CMD_COMPLETE is not set 440 nop 441 stha %o3, [%o1]ASI_IO ! Now we are done and clear it 442 ba %xcc, 6f 443 mov ESBD_NOERROR, %o4 444 445 /* timeout delay checking */ 446 5: 447 rd STICK, %l2 448 cmp %l5, %l2 449 bge %xcc, 3b 450 nop 451 set EOPL_FMEM_TIMEOUT, %o4 452 453 /* we are done or timed out */ 454 6: 455 ba,a 1b 456 nop 457 SET_SIZE(drmach_fmem_exec_script) 458 #endif /* lint */ 459 460 #if defined(lint) 461 /*ARGSUSED*/ 462 void 463 drmach_fmem_exec_script_end(caddr_t critical, int size) 464 { return; } 465 #else /* lint */ 466 ENTRY_NP(drmach_fmem_exec_script_end) 467 nop 468 SET_SIZE(drmach_fmem_exec_script_end) 469 #endif /* lint */ 470 471 #if defined(lint) 472 uint64_t 473 patch_inst(uint64_t *x, uint64_t y) 474 { 475 *x = y; 476 return (0); 477 } 478 479 #else /* lint */ 480 481 ENTRY_NP(patch_inst) 482 ldx [%o0], %o2 483 casx [%o0], %o2, %o1 484 flush %o0 485 membar #Sync 486 ldx [%o0], %o2 487 retl 488 mov %o2, %o0 489 SET_SIZE(patch_inst) 490 491 #endif /* lint */ 492 493 #if defined(lint) 494 void 495 drmach_sys_trap() 496 { 497 } 498 #else /* lint */ 499 ENTRY_NP(drmach_sys_trap) 500 mov -1, %g4 501 set sys_trap, %g5 502 jmp %g5 503 nop 504 SET_SIZE(drmach_sys_trap) 505 #endif /* lint */ 506 507 #if defined(lint) 508 uint64_t 509 drmach_get_stick() 510 { 511 return (0); 512 } 513 #else /* lint */ 514 ENTRY_NP(drmach_get_stick) 515 retl 516 rd STICK, %o0 517 SET_SIZE(drmach_get_stick) 518 #endif /* lint */ 519 520 #if defined(lint) 521 /*ARGSUSED*/ 522 void 523 drmach_flush(drmach_copy_rename_critical_t *x, uint_t y) 524 {} 525 526 #else /* lint */ 527 ENTRY_NP(drmach_flush) 528 mov %o0, %o2 529 0: 530 flush %o2 531 sub %o1, 8, %o1 532 brnz %o1, 0b 533 add %o2, 8, %o2 534 retl 535 nop 536 SET_SIZE(drmach_flush) 537 #endif /* lint */