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)