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 #include "assym.h" 34 #include "drmach_offsets.h" 35 36 #include <sys/asm_linkage.h> 37 #include <sys/param.h> 38 #include <sys/privregs.h> 39 #include <sys/spitregs.h> 40 #include <sys/mmu.h> 41 #include <sys/machthread.h> 42 #include <sys/pte.h> 43 #include <sys/stack.h> 44 #include <sys/vis.h> 45 #include <sys/intreg.h> 46 #include <sys/cheetahregs.h> 47 #include <sys/drmach.h> 48 #include <sys/sbd_ioctl.h> 49 50 /* 51 * turn off speculative mode to prevent unwanted memory access 52 * when we are in the FMEM loops 53 */ 54 55 #define FJSV_SPECULATIVE_OFF(reg, tmp1, tmp2) \ 56 rdpr %pstate, reg ;\ 57 andn reg, PSTATE_IE, tmp1 ;\ 58 wrpr %g0, tmp1, %pstate ;\ 59 ldxa [%g0]ASI_MCNTL, tmp1 ;\ 60 set 1, tmp2 ;\ 61 sllx tmp2, MCNTL_SPECULATIVE_SHIFT, tmp2 ;\ 62 or tmp1, tmp2, tmp1 ;\ 63 stxa tmp1, [%g0]ASI_MCNTL ;\ 64 membar #Sync 65 66 67 .align 8 68 ENTRY_NP(drmach_fmem_loop_script) 69 /* turn off speculative mode */ 70 FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); 71 72 /* read the critical region to get everything in the cache */ 73 mov %o0, %o3 74 0: 75 ldx [%o3], %o4 76 sub %o1, 8, %o1 77 brnz %o1, 0b 78 add %o3, 8, %o3 79 80 /* clear L2_CTRL_UGE_TRAP error bit */ 81 mov ASI_L2_CTRL_RW_ADDR, %o1 82 ldxa [%o1]ASI_L2_CTRL, %o3 83 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 84 btst %o3, %o4 85 bz,pn %xcc, 1f 86 nop 87 stxa %o4, [%o1]ASI_L2_CTRL 88 89 /* now tell the master CPU that we are ready */ 90 1: 91 set FMEM_LOOP_FMEM_READY, %o3 92 stb %o3, [%o2] 93 membar #Sync 94 ba 5f 95 nop 96 97 /* 98 * note that we branch to 5f, which branches right back to 2 here. 99 * The trick is that when that branch instruction has already been 100 * patched to a branch to itself - an infinite loop. 101 * The master thread will patch it back to "ba 2b" when it 102 * completes. 103 */ 104 105 /* Once we are back, we first check if there has been any 106 * L2_CTRL_UGE_TRAP errors, if so we have to fail the 107 * operation. This will cause a panic because the system 108 * is already in inconsistent state. 109 */ 110 2: 111 mov ASI_L2_CTRL_RW_ADDR, %o3 112 ldxa [%o3]ASI_L2_CTRL, %o3 113 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 114 btst %o3, %o4 115 bz,pn %xcc, 3f 116 mov %g0, %o4 117 set EOPL_FMEM_HW_ERROR, %o4 118 119 /* set error code and stat code */ 120 3: 121 set FMEM_LOOP_DONE, %o3 122 stb %o3, [%o2] 123 124 /* turn on speculative mode again */ 125 ldxa [%g0]ASI_MCNTL, %o0 126 set 1, %o1 127 sllx %o1, MCNTL_SPECULATIVE_SHIFT, %o1 128 andn %o0, %o1, %o0 129 ba 4f 130 nop 131 .align 32 132 4: 133 stxa %o0, [%g0]ASI_MCNTL 134 membar #Sync 135 wrpr %g0, %o5, %pstate 136 retl 137 mov %o4, %o0 138 .align 8 139 5: 140 ALTENTRY(drmach_fmem_loop_script_rtn) 141 /* 142 * busy wait will affect sibling strands so 143 * we put sleep instruction in the delay slot 144 */ 145 ba 2b 146 .word 0x81b01060 147 SET_SIZE(drmach_fmem_loop_script) 148 149 .align 8 150 ENTRY_NP(drmach_flush_icache) 151 stxa %g0, [%g0]ASI_ALL_FLUSH_L1I 152 membar #Sync 153 retl 154 nop 155 SET_SIZE(drmach_flush_icache) 156 157 .align 32 158 ENTRY_NP(drmach_fmem_exec_script) 159 /* turn off speculative mode */ 160 FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); 161 /* save locals to save area */ 162 add %o0, SAVE_LOCAL, %o2 163 stx %l0, [%o2+8*0] 164 stx %l1, [%o2+8*1] 165 stx %l2, [%o2+8*2] 166 stx %l3, [%o2+8*3] 167 stx %l4, [%o2+8*4] 168 stx %l5, [%o2+8*5] 169 stx %l6, [%o2+8*6] 170 stx %l7, [%o2+8*7] 171 mov %o5, %l6 172 /* l7 is set only when FMEM cmd is issued to SCF */ 173 mov %g0, %l7 174 175 /* read the critical region to put everything in the cache */ 176 mov %o0, %o2 177 0: 178 ldx [%o2], %o4 179 sub %o1, 8, %o1 180 brnz %o1, 0b 181 add %o2, 8, %o2 182 ba 4f 183 nop 184 185 /* we branch to 4f but eventually we branch back here to finish up */ 186 1: 187 mov %l6, %o5 188 /* 189 * save some registers for debugging 190 * l0 - SCF_REG_BASE 191 * l1 - SCF_TD 192 * l2 - SCF_TD + 8 193 * l5 - DELAY 194 */ 195 add %o0, SAVE_LOG, %o1 196 stx %l0, [%o1+8*0] 197 stx %l1, [%o1+8*1] 198 stx %l2, [%o1+8*2] 199 stx %l5, [%o1+8*3] 200 201 add %o0, FMEM_ISSUED, %o1 202 st %l7, [%o1] 203 204 /* Check for L2_CTRL_UGE_TRAP error */ 205 mov ASI_L2_CTRL_RW_ADDR, %l0 206 ldxa [%l0]ASI_L2_CTRL, %l1 207 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 208 btst %l1, %l2 209 bz,pn %xcc, 2f 210 nop 211 set EOPL_FMEM_HW_ERROR, %o4 212 2: 213 /* restore all locals */ 214 add %o0, SAVE_LOCAL, %o1 215 ldx [%o1+8*0], %l0 216 ldx [%o1+8*1], %l1 217 ldx [%o1+8*2], %l2 218 ldx [%o1+8*3], %l3 219 ldx [%o1+8*4], %l4 220 ldx [%o1+8*5], %l5 221 ldx [%o1+8*6], %l6 222 ldx [%o1+8*7], %l7 223 224 /* turn on speculative mode */ 225 ldxa [%g0]ASI_MCNTL, %o1 226 set 1, %o2 227 sllx %o2, MCNTL_SPECULATIVE_SHIFT, %o2 228 andn %o1, %o2, %o1 229 ba 3f 230 nop 231 .align 32 232 3: 233 stxa %o1, [%g0]ASI_MCNTL 234 membar #Sync 235 /* return error code here */ 236 mov %o4, %o0 237 retl 238 wrpr %g0, %o5, %pstate 239 240 /* clear L2_CTRL_UGE_TRAP error bit */ 241 4: 242 mov ASI_L2_CTRL_RW_ADDR, %l0 243 ldxa [%l0]ASI_L2_CTRL, %l1 244 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 245 btst %l1, %l2 246 bz,pn %xcc, 5f 247 nop 248 stxa %l2, [%l0]ASI_L2_CTRL 249 5: 250 /* set up the register locations and parameters */ 251 ldx [%o0 + SCF_REG_BASE], %l0 252 ldx [%o0 + SCF_TD], %l1 253 ldx [%o0 + SCF_TD+8], %l2 254 ldx [%o0 + DELAY], %l5 255 256 /* check if SCF is ONLINE */ 257 add %l0, SCF_STATUS_EX, %o1 258 lduwa [%o1]ASI_IO, %o2 259 sethi %hi(SCF_STATUS_EX_ONLINE), %o3 260 btst %o2, %o3 261 bne %xcc, 6f 262 nop 263 set EOPL_FMEM_SCF_OFFLINE, %o4 264 ba 1b 265 nop 266 267 /* check if SCF is busy */ 268 add %l0, SCF_COMMAND, %o1 269 lduha [%o1]ASI_IO, %o2 270 sethi %hi(SCF_CMD_BUSY), %o3 271 btst %o2, %o3 272 be %xcc, 6f 273 nop 274 set EOPL_FMEM_SCF_BUSY, %o4 275 ba 1b 276 nop 277 278 /* clear STATUS bit */ 279 6: 280 add %l0, SCF_STATUS, %o1 281 lduha [%o1]ASI_IO, %o2 282 sethi %hi(SCF_STATUS_READY), %o3 283 btst %o2, %o3 284 be %xcc, 7f 285 nop 286 stha %o3, [%o1]ASI_IO 287 288 /* clear CMD_COMPLETE bit */ 289 7: 290 mov SCF_STATUS_CMD_COMPLETE, %o3 291 btst %o2, %o3 292 be,a %xcc, 8f 293 nop 294 stha %o3, [%o1]ASI_IO 295 8: 296 add %l0, (SCF_TDATA+0xe), %o1 297 mov %l2, %o4 298 mov SCF_RETRY_CNT, %o5 299 300 sethi %hi(0xffff), %l2 301 or %l2, %lo(0xffff), %l2 302 303 and %o4, %l2, %o3 304 305 /* 306 * o1 points to SCFBASE.SCF_TDATA[0xe] 307 * l0 points to SCFBASE 308 * crticial->SCF_TD[0] = source board # 309 * crticial->SCF_TD[1] = target board # 310 * l1 = critical->SCF_TD[0 - 7] 311 * l2 = 0xffff 312 * o4 = critical->SCF_TD[8 - 15] 313 * o3 = (*o4) & 0xffff 314 315 /* 316 * Because there is no parity protection on the ebus 317 * we read the data back after the write to verify 318 * we write 2 bytes at a time. 319 * If the data read is not the same as data written 320 * we retry up to a limit of SCF_RETRY_CNT 321 */ 322 9: 323 stha %o3, [%o1]ASI_IO 324 lduha [%o1]ASI_IO, %o2 325 sub %o5, 1, %o5 326 brnz %o5, 7f 327 nop 328 set EOPL_FMEM_RETRY_OUT, %o4 329 ba 1b 330 nop 331 7: 332 cmp %o2, %o3 333 bne,a 9b 334 nop 335 336 sub %o1, %l0, %o2 337 cmp %o2, (SCF_TDATA+0x8) 338 bne %xcc, 2f 339 srlx %o4, 16, %o4 340 mov %l1, %o4 341 342 /* if we have reach TDATA+8, we switch to l1 */ 343 /* XXX: Why we need 2 loops??? */ 344 2: 345 sub %o1, 2, %o1 346 mov SCF_RETRY_CNT, %o5 347 and %o4, %l2, %o3 348 349 sub %o1, %l0, %o2 350 cmp %o2, (SCF_TDATA) 351 bge,a 9b 352 nop 353 354 /* if we reach TDATA, we are done */ 355 356 /* read from SCF back to our buffer for debugging */ 357 add %l0, (SCF_TDATA), %o1 358 ldxa [%o1]ASI_IO, %o2 359 stx %o2, [%o0+SCF_TD] 360 361 add %l0, (SCF_TDATA+8), %o1 362 ldxa [%o1]ASI_IO, %o2 363 stx %o2, [%o0+SCF_TD+8] 364 365 /* The following code conforms to the FMEM 366 sequence (4) as described in the Columbus2 367 logical spec section 4.6 368 */ 369 370 /* read from SCF SB INFO register */ 371 sethi %hi(SCF_SB_INFO_OFFSET), %o2 372 or %o2, %lo(SCF_SB_INFO_OFFSET), %o2 373 add %l0, %o2, %o1 374 lduba [%o1]ASI_IO, %o2 375 376 /* If BUSY bit is set, abort */ 377 or %g0, (SCF_SB_INFO_BUSY), %o1 378 btst %o1, %o2 379 set EOPL_FMEM_SCF_BUSY, %o4 380 bne 1b 381 nop 382 383 rd STICK, %l1 384 add %l5, %l1, %l5 385 386 /* Now tell SCF to do it */ 387 add %l0, SCF_COMMAND, %o1 388 389 /* 0x10A6 is the magic command */ 390 sethi %hi(0x10A6), %o2 391 or %o2, %lo(0x10A6), %o2 392 stha %o2, [%o1]ASI_IO 393 394 mov 1, %l7 ! FMEM is issued 395 396 add %l0, SCF_STATUS, %o1 397 sethi %hi(SCF_STATUS_READY), %o2 398 mov SCF_STATUS_CMD_COMPLETE, %o3 399 400 /* read STATUS_READY bit and clear it only if it is set */ 401 /* XXX: this STATUS_READY checking seems meaningless */ 402 3: 403 lduha [%o1]ASI_IO, %o4 404 btst %o2, %o4 405 be %xcc, 4f ! STATUS_READY is not set 406 nop 407 stha %o2, [%o1]ASI_IO ! Clear if the bit is set 408 409 /* check CMD_COMPLETE bit and clear */ 410 4: 411 btst %o3, %o4 412 be %xcc, 5f ! CMD_COMPLETE is not set 413 nop 414 stha %o3, [%o1]ASI_IO ! Now we are done and clear it 415 ba %xcc, 6f 416 mov ESBD_NOERROR, %o4 417 418 /* timeout delay checking */ 419 5: 420 rd STICK, %l2 421 cmp %l5, %l2 422 bge %xcc, 3b 423 nop 424 set EOPL_FMEM_TIMEOUT, %o4 425 426 /* we are done or timed out */ 427 6: 428 ba,a 1b 429 nop 430 SET_SIZE(drmach_fmem_exec_script) 431 432 ENTRY_NP(drmach_fmem_exec_script_end) 433 nop 434 SET_SIZE(drmach_fmem_exec_script_end) 435 436 ENTRY_NP(patch_inst) 437 ldx [%o0], %o2 438 casx [%o0], %o2, %o1 439 flush %o0 440 membar #Sync 441 ldx [%o0], %o2 442 retl 443 mov %o2, %o0 444 SET_SIZE(patch_inst) 445 446 ENTRY_NP(drmach_sys_trap) 447 mov -1, %g4 448 set sys_trap, %g5 449 jmp %g5 450 nop 451 SET_SIZE(drmach_sys_trap) 452 453 ENTRY_NP(drmach_get_stick) 454 retl 455 rd STICK, %o0 456 SET_SIZE(drmach_get_stick) 457 458 ENTRY_NP(drmach_flush) 459 mov %o0, %o2 460 0: 461 flush %o2 462 sub %o1, 8, %o1 463 brnz %o1, 0b 464 add %o2, 8, %o2 465 retl 466 nop 467 SET_SIZE(drmach_flush)