/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * This file is through cpp before being used as * an inline. It contains support routines used * only by DR for the copy-rename sequence. */ #if defined(lint) #include #else #include "assym.h" #include "drmach_offsets.h" #endif /* lint */ #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(lint) /* * turn off speculative mode to prevent unwanted memory access * when we are in the FMEM loops */ #define FJSV_SPECULATIVE_OFF(reg, tmp1, tmp2) \ rdpr %pstate, reg ;\ andn reg, PSTATE_IE, tmp1 ;\ wrpr %g0, tmp1, %pstate ;\ ldxa [%g0]ASI_MCNTL, tmp1 ;\ set 1, tmp2 ;\ sllx tmp2, MCNTL_SPECULATIVE_SHIFT, tmp2 ;\ or tmp1, tmp2, tmp1 ;\ stxa tmp1, [%g0]ASI_MCNTL ;\ membar #Sync #endif #if defined(lint) /*ARGSUSED*/ void drmach_fmem_loop_script(caddr_t critical, int size, caddr_t stat) { return; } #else /* lint */ .align 8 ENTRY_NP(drmach_fmem_loop_script) /* turn off speculative mode */ FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); /* read the critical region to get everything in the cache */ mov %o0, %o3 0: ldx [%o3], %o4 sub %o1, 8, %o1 brnz %o1, 0b add %o3, 8, %o3 /* clear L2_CTRL_UGE_TRAP error bit */ mov ASI_L2_CTRL_RW_ADDR, %o1 ldxa [%o1]ASI_L2_CTRL, %o3 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 btst %o3, %o4 bz,pn %xcc, 1f nop stxa %o4, [%o1]ASI_L2_CTRL /* now tell the master CPU that we are ready */ 1: set FMEM_LOOP_FMEM_READY, %o3 stb %o3, [%o2] membar #Sync ba 5f nop /* * note that we branch to 5f, which branches right back to 2 here. * The trick is that when that branch instruction has already been * patched to a branch to itself - an infinite loop. * The master thread will patch it back to "ba 2b" when it * completes. */ /* Once we are back, we first check if there has been any * L2_CTRL_UGE_TRAP errors, if so we have to fail the * operation. This will cause a panic because the system * is already in inconsistent state. */ 2: mov %g0, %o1 mov ASI_L2_CTRL_RW_ADDR, %o3 ldxa [%o3]ASI_L2_CTRL, %o3 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 btst %o3, %o4 bz,pn %xcc, 3f mov %g0, %o4 set FMEM_HW_ERROR, %o4 /* set error code and stat code */ 3: set FMEM_LOOP_DONE, %o3 stb %o3, [%o2] /* turn on speculative mode again */ ldxa [%g0]ASI_MCNTL, %o0 set 1, %o1 sllx %o1, MCNTL_SPECULATIVE_SHIFT, %o1 andn %o0, %o1, %o0 ba 4f nop .align 32 4: stxa %o0, [%g0]ASI_MCNTL membar #Sync wrpr %g0, %o5, %pstate retl mov %o4, %o0 .align 8 5: ALTENTRY(drmach_fmem_loop_script_rtn) /* * busy wait will affect sibling strands so * we put sleep instruction in the delay slot */ ba 2b .word 0x81b01060 nop SET_SIZE(drmach_fmem_loop_script) #endif /* lint */ #if defined(lint) /*ARGSUSED*/ void drmach_flush_icache(void) { return; } #else /* lint */ .align 8 ENTRY_NP(drmach_flush_icache) stxa %g0, [%g0]ASI_ALL_FLUSH_L1I membar #Sync retl nop SET_SIZE(drmach_flush_icache) #endif #if defined(lint) /*ARGSUSED*/ int drmach_fmem_exec_script(caddr_t critical, int size) { return (0); } #else /* lint */ .align 32 ENTRY_NP(drmach_fmem_exec_script) /* turn off speculative mode */ FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); /* save locals to save area */ add %o0, SAVE_LOCAL, %o2 stx %l0, [%o2+8*0] stx %l1, [%o2+8*1] stx %l2, [%o2+8*2] stx %l3, [%o2+8*3] stx %l4, [%o2+8*4] stx %l5, [%o2+8*5] stx %l6, [%o2+8*6] stx %l7, [%o2+8*7] mov %o5, %l6 /* l7 is set only when FMEM cmd is issued to SCF */ mov %g0, %l7 /* read the critical region to put everything in the cache */ mov %o0, %o2 0: ldx [%o2], %o4 sub %o1, 8, %o1 brnz %o1, 0b add %o2, 8, %o2 ba 4f nop /* we branch to 4f but eventually we branch back here to finish up */ 1: mov %l6, %o5 /* * save some registers for debugging * l0 - SCF_REG_BASE * l1 - SCF_TD * l2 - SCF_TD + 8 * l5 - DELAY */ add %o0, SAVE_LOG, %o1 stx %l0, [%o1+8*0] stx %l1, [%o1+8*1] stx %l2, [%o1+8*2] stx %l5, [%o1+8*3] add %o0, FMEM_ISSUED, %o1 st %l7, [%o1] /* Check for L2_CTRL_UGE_TRAP error */ mov ASI_L2_CTRL_RW_ADDR, %l0 ldxa [%l0]ASI_L2_CTRL, %l1 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 btst %l1, %l2 bz,pn %xcc, 2f nop mov FMEM_HW_ERROR, %o4 2: /* restore all locals */ add %o0, SAVE_LOCAL, %o1 ldx [%o1+8*0], %l0 ldx [%o1+8*1], %l1 ldx [%o1+8*2], %l2 ldx [%o1+8*3], %l3 ldx [%o1+8*4], %l4 ldx [%o1+8*5], %l5 ldx [%o1+8*6], %l6 ldx [%o1+8*7], %l7 /* turn on speculative mode */ ldxa [%g0]ASI_MCNTL, %o1 set 1, %o2 sllx %o2, MCNTL_SPECULATIVE_SHIFT, %o2 andn %o1, %o2, %o1 ba 3f nop .align 32 3: stxa %o1, [%g0]ASI_MCNTL membar #Sync /* return error code here */ mov %o4, %o0 retl wrpr %g0, %o5, %pstate /* clear L2_CTRL_UGE_TRAP error bit */ 4: mov ASI_L2_CTRL_RW_ADDR, %l0 ldxa [%l0]ASI_L2_CTRL, %l1 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 btst %l1, %l2 bz,pn %xcc, 5f nop stxa %l2, [%l0]ASI_L2_CTRL 5: /* set up the register locations and parameters */ ldx [%o0 + SCF_REG_BASE], %l0 ldx [%o0 + SCF_TD], %l1 ldx [%o0 + SCF_TD+8], %l2 ldx [%o0 + DELAY], %l5 /* check if SCF is busy */ add %l0, SCF_COMMAND, %o1 lduha [%o1]ASI_IO, %o2 sethi %hi(SCF_CMD_BUSY), %o3 btst %o2, %o3 be %xcc, 6f nop ba 1b mov FMEM_SCF_BUSY, %o4 /* clear STATUS bit */ 6: add %l0, SCF_STATUS, %o1 lduha [%o1]ASI_IO, %o2 sethi %hi(SCF_STATUS_READY), %o3 btst %o2, %o3 be %xcc, 7f nop stha %o3, [%o1]ASI_IO /* clear CMD_COMPLETE bit */ 7: mov SCF_STATUS_CMD_COMPLETE, %o3 btst %o2, %o3 be,a %xcc, 8f nop stha %o3, [%o1]ASI_IO 8: add %l0, (SCF_TDATA+0xe), %o1 mov %l2, %o4 mov SCF_RETRY_CNT, %o5 sethi %hi(0xffff), %l2 or %l2, %lo(0xffff), %l2 and %o4, %l2, %o3 /* * o1 points to SCFBASE.SCF_TDATA[0xe] * l0 points to SCFBASE * crticial->SCF_TD[0] = source board # * crticial->SCF_TD[1] = target board # * l1 = critical->SCF_TD[0 - 7] * l2 = 0xffff * o4 = critical->SCF_TD[8 - 15] * o3 = (*o4) & 0xffff /* * Because there is no parity protection on the ebus * we read the data back after the write to verify * we write 2 bytes at a time. * If the data read is not the same as data written * we retry up to a limit of FMEM_RETRY_OUT */ 9: stha %o3, [%o1]ASI_IO lduha [%o1]ASI_IO, %o2 sub %o5, 1, %o5 brz,a %o5, 1b mov FMEM_RETRY_OUT, %o4 cmp %o2, %o3 bne,a 9b nop sub %o1, %l0, %o2 cmp %o2, (SCF_TDATA+0x8) bne %xcc, 2f srlx %o4, 16, %o4 mov %l1, %o4 /* if we have reach TDATA+8, we switch to l1 */ /* XXX: Why we need 2 loops??? */ 2: sub %o1, 2, %o1 mov SCF_RETRY_CNT, %o5 and %o4, %l2, %o3 sub %o1, %l0, %o2 cmp %o2, (SCF_TDATA) bge,a 9b nop /* if we reach TDATA, we are done */ /* read from SCF back to our buffer for debugging */ add %l0, (SCF_TDATA), %o1 ldxa [%o1]ASI_IO, %o2 stx %o2, [%o0+SCF_TD] add %l0, (SCF_TDATA+8), %o1 ldxa [%o1]ASI_IO, %o2 stx %o2, [%o0+SCF_TD+8] rd STICK, %l1 add %l5, %l1, %l5 /* Now tell SCF to do it */ add %l0, SCF_COMMAND, %o1 /* 0x10A6 is the magic command */ sethi %hi(0x10A6), %o2 or %o2, %lo(0x10A6), %o2 stha %o2, [%o1]ASI_IO mov 1, %l7 ! FMEM is issued add %l0, SCF_STATUS, %o1 sethi %hi(SCF_STATUS_READY), %o2 mov SCF_STATUS_CMD_COMPLETE, %o3 /* read STATUS_READY bit and clear it only if it is set */ /* XXX: this STATUS_READY checking seems meaningless */ 3: lduha [%o1]ASI_IO, %o4 btst %o2, %o4 be %xcc, 4f ! STATUS_READY is not set nop stha %o2, [%o1]ASI_IO ! Clear if the bit is set /* check CMD_COMPLETE bit and clear */ 4: btst %o3, %o4 be %xcc, 5f ! CMD_COMPLETE is not set nop stha %o3, [%o1]ASI_IO ! Now we are done and clear it mov FMEM_NO_ERROR, %o4 ba %xcc, 6f nop /* timeout delay checking */ 5: rd STICK, %l2 cmp %l5, %l2 bge %xcc, 3b nop mov FMEM_TIMEOUT, %o4 /* we are done or timed out */ 6: ba,a 1b nop SET_SIZE(drmach_fmem_exec_script) #endif /* lint */ #if defined(lint) /*ARGSUSED*/ void drmach_fmem_exec_script_end(caddr_t critical, int size) { return; } #else /* lint */ ENTRY_NP(drmach_fmem_exec_script_end) nop SET_SIZE(drmach_fmem_exec_script_end) #endif /* lint */ #if defined(lint) uint64_t patch_inst(uint64_t *x, uint64_t y) { *x = y; return (0); } #else /* lint */ ENTRY_NP(patch_inst) ldx [%o0], %o2 casx [%o0], %o2, %o1 flush %o0 membar #Sync ldx [%o0], %o2 retl mov %o2, %o0 SET_SIZE(patch_inst) #endif /* lint */ #if defined(lint) void drmach_sys_trap() { } #else /* lint */ ENTRY_NP(drmach_sys_trap) mov -1, %g4 set sys_trap, %g5 jmp %g5 nop SET_SIZE(drmach_sys_trap) #endif /* lint */ #if defined(lint) uint64_t drmach_get_stick() { return (0); } #else /* lint */ ENTRY_NP(drmach_get_stick) retl rd STICK, %o0 SET_SIZE(drmach_get_stick) #endif /* lint */ #if defined(lint) /*ARGSUSED*/ void drmach_flush(void) {} #else /* lint */ ENTRY_NP(drmach_flush) mov %o0, %o2 0: flush %o2 sub %o1, 8, %o1 brnz %o1, 0b add %o2, 8, %o2 retl nop SET_SIZE(drmach_flush) #endif /* lint */