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 */