* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: svc_common.s
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* - Do no alter or remove copyright notices
* - Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* - Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or maintenance of
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
.ident "@(#)svc_common.s 1.27 07/05/30 SMI"
#ifdef CONFIG_SVC /* { */
#include <sys/asm_linkage.h>
#include <sparcv9/misc.h>
ldub [addr + len], sum ! preload sum with last byte
sub %g0, 1, tmp0 ! this will probably NEVER happen!!
xor sum, tmp0, retval ! as this pkt would be too short
2: srl sum, 16, tmp0 ! get upper 16 bits
srl sum, 16, sum ! chuck upper 16 bits
srl len, 16, len ! 0xffff
* svc_intr_getstate - return a service's current interrupt state
* Get the state, mask with the enable bits, or TX and RX with
* the abort bit, return the result. non-zero means intr pending.
ENTRY_NP(svc_intr_getstate)
ld [%g1 + SVC_CTRL_STATE], %g1
and %g1, (SVC_FLAGS_RE | SVC_FLAGS_TE), %g2 ! XXX FLAGS MASK
and %g1, (SVC_FLAGS_RI | SVC_FLAGS_TI), %g3
srl %g1, ABORT_SHIFT, %g1 ! abort..
SET_SIZE(svc_intr_getstate)
#define FPGA_MBOX_INT_ENABLE(x) \
setx FPGA_INTR_BASE, r_tmp2, r_tmp3 ;\
stb r_tmp2, [r_tmp3 + FPGA_MBOX_INTR_ENABLE]
* svc_isr - The mailbox interrupt service routine..
* we will retry here, as we do not expect to be 'called'
* r_cpu (%g1) comes from the mondo vector handler.
* if (intr_status & IRQ_QUEUE_IN) {
* if (intr_status & IRQ_QUEUE_OUT)
* if (intr_status & IRQ_LDC_OUT)
#ifdef CONFIG_FPGA /* { */
ldx [%g1 + CPU_ROOT], r_root ! root data
setx FPGA_INTR_BASE, r_tmp3, r_tmp2
ldub [r_tmp2 + FPGA_MBOX_INTR_STATUS], %g4
bnz,pt %xcc, svc_ldc_tx_intr
nop ! more intr srcs here!
! XXX enable FPGA interrupts.
FPGA_MBOX_INT_ENABLE(IRQ_QUEUE_IN|IRQ_QUEUE_OUT|IRQ_LDC_OUT)
* Check for a pending non-resumable error. This flag will
* be set if the rx handler queued a non-resumable error
* to force a guest panic. The non-resumable trap must be
* generated only after FPGA interrupts are reenabled, so
* it is performed here after the rx processing is complete.
set STRAND_NRPENDING, %g2
brnz,a,pt %g3, nonresumable_error_trap
ldx [r_root + CONFIG_SVCS], r_svc
ba,a svc_process ! r_root is ptr to root data
#define TX_INTR_DONE(x) \
ldx [r_root + CONFIG_SVCS], r_svc ;\
UNLOCK(r_svc, HV_SVC_DATA_LOCK) ;\
#define RX_INTR_DONE(status,r_chan) \
stb %g1, [r_chan + FPGA_Q_STATUS] ;\
PRINT("Got an SSI FPGA RX Interrupt\r\n")
ldx [r_root + CONFIG_SVCS], r_svc
ldx [r_svc + HV_SVC_DATA_RXCHANNEL], r_chan ! regs
lduh [r_chan + FPGA_Q_SIZE], %g2 ! len
ldx [r_svc + HV_SVC_DATA_RXBASE], %g1 ! buffer
ldx [r_root + CONFIG_SVCS], r_svc
ld [r_svc + HV_SVC_DATA_NUM_SVCS], r_tmp3 ! numsvcs
ldx [r_svc + HV_SVC_DATA_RXBASE], r_tmp1 ! buffer addr
add r_svc, HV_SVC_DATA_SVC, r_svc ! svc base
9: ld [r_tmp1 + SVC_PKT_XID], r_tmp2
ld [r_svc + SVC_CTRL_XID], r_tmp4 ! svc partid
lduh [r_tmp1 + SVC_PKT_SID], r_tmp2
ld [r_svc + SVC_CTRL_SID], r_tmp4
beq,pn %xcc, rxintr_gotone
1: subcc r_tmp3, 1, r_tmp3 ! nsvcs--
add r_svc, SVC_CTRL_SIZE, r_svc ! next
PRINT("Aborted Transport to bad XPID/SVC\r\n")
RX_INTR_DONE(QINTR_ABORT, r_chan)
PRINT("Found: "); PRINTX(r_svc); PRINT("\r\n")
ld [r_svc + SVC_CTRL_CONFIG], r_tmp4 ! check config bits
btst SVC_CFG_RX, r_tmp4 ! can RX ?
ld [r_svc + SVC_CTRL_STATE], r_tmp4
btst SVC_FLAGS_RI, r_tmp4 ! buffer available?
lduh [r_chan + FPGA_Q_SIZE], r_tmp1 ! len
stx r_tmp1, [r_svc + SVC_CTRL_RECV + SVC_LINK_SIZE] ! len
ldx [r_svc + SVC_CTRL_RECV + SVC_LINK_PA], r_tmp3 ! dest
ldx [r_root + CONFIG_SVCS], r_tmp2
ldx [r_tmp2 + HV_SVC_DATA_RXBASE], r_tmp2 ! src
SMALL_COPY_MACRO(r_tmp2, r_tmp1, r_tmp3, r_tmp4)
LOCK(r_svc, SVC_CTRL_LOCK, r_tmp3, r_tmp4)
ld [r_svc + SVC_CTRL_STATE], r_tmp4
btst SVC_CFG_CALLBACK, r_tmp4
#define r_hvrxcallback r_tmp4
or r_tmp4, SVC_FLAGS_RI, r_tmp4
bnz,pn %xcc, do_hvrxcallback ! HV callback
st r_tmp4, [r_svc + SVC_CTRL_STATE] ! RX pending
UNLOCK(r_svc, SVC_CTRL_LOCK)
btst SVC_FLAGS_RE, r_tmp4 ! RECV intr enabled?
ldx [r_svc + SVC_CTRL_INTR_COOKIE], %g1 ! Cookie
PRINT("XXX - SVC INTR SENDING RX PENDING INTR - XXX\r\n")
ba vdev_intr_generate ! deliver??
ldx [r_root + CONFIG_SVCS], r_svc
ldx [r_svc + HV_SVC_DATA_RXCHANNEL], r_chan ! regs
RX_INTR_DONE(QINTR_ACK, r_chan)
PRINT("SVC Buffer Busy\r\n")
RX_INTR_DONE(QINTR_BUSY, r_chan)
PRINT("SVC RX Bad packet: "); PRINTX(%g1); PRINT("\r\n")
RX_INTR_DONE(QINTR_NACK, r_chan)
PRINT("Got an SSI FPGA TX Interrupt: ")
ldx [%g1 + CPU_ROOT], r_root ! data root
ldx [r_root + HV_SVC_DATA_TXCHANNEL], r_chan ! regs
ldub [r_chan + FPGA_Q_STATUS], r_tmp3 ! status
ldx [%g1 + CPU_ROOT], r_root ! data root
ldx [r_root + CONFIG_SVCS], r_root ! svc root
LOCK(r_root, HV_SVC_DATA_LOCK, r_svc, r_chan)
ldx [r_root + HV_SVC_DATA_SENDH], r_svc ! head of tx q
ldx [r_root + HV_SVC_DATA_TXCHANNEL], r_chan ! regs
ldub [r_chan + FPGA_Q_STATUS], r_tmp3 ! status
sth %g0, [r_chan + FPGA_Q_SIZE] ! len=0
bnz,pt %xcc, txpacket_ack
bnz,pt %xcc, txpacket_nack
bnz,pt %xcc, txpacket_busy
bnz,pt %xcc, txpacket_abort
PRINT("XXX unserviced bits in tx status register: ")
TX_INTR_DONE(IRQ_QUEUE_OUT)
PRINT("txSVC NACK!!\r\n")
PRINT("txSVC Abort!!\r\n")
LOCK(r_svc, SVC_CTRL_LOCK, r_tmp2, r_tmp1)
ld [r_svc + SVC_CTRL_STATE], r_tmp2
andn r_tmp2, SVC_FLAGS_TP, r_tmp2
or r_tmp2, SVC_FLAG_ABORT, r_tmp2
st r_tmp2, [r_svc + SVC_CTRL_STATE]
UNLOCK(r_svc, SVC_CTRL_LOCK)
stb r_tmp3, [r_chan + FPGA_Q_STATUS] ! clr status
PRINT("txSVC Busy!!\r\n")
!! %g7 = 1=NACK, 0=BUSY ??? something.
stb r_tmp3, [r_chan + FPGA_Q_STATUS] ! clr status
ldx [r_root + CONFIG_SVCS], r_root ! svc root
* XXX we should delay and resend later or at least put this
* packet on the end of the queue so other packets have a chance.
ldx [r_root + HV_SVC_DATA_SENDH], r_svc ! head of tx q
SEND_SVC_PACKET(r_root, r_svc, r_tmp1, r_tmp2, r_tmp3, r_tmp4)
* Move the current head to the end of the queue:
* if (head->next != NULL) {
ldx [r_root + HV_SVC_DATA_SENDH], r_tmp1
ldx [r_tmp1 + SVC_CTRL_SEND + SVC_LINK_NEXT], r_tmp2
brz,pt r_tmp2, hv_txintr ! only item on list
stx r_tmp2, [r_root + HV_SVC_DATA_SENDH]
stx %g0, [r_tmp1 + SVC_CTRL_SEND + SVC_LINK_NEXT]
ldx [r_root + HV_SVC_DATA_SENDT], r_tmp2
stx r_tmp1, [r_tmp2 + SVC_CTRL_SEND + SVC_LINK_NEXT]
stx r_tmp1, [r_root + HV_SVC_DATA_SENDT]
stb r_tmp3, [r_chan + FPGA_Q_STATUS] ! clr status
LOCK(r_svc, SVC_CTRL_LOCK, r_tmp2, r_tmp1)
/* Mark busy, prevents svc_internal_send from touching fpga */
stw r_tmp2, [r_root + HV_SVC_DATA_SENDBUSY]
/* Remove head from list prior to calling the tx callback */
ldx [r_svc + SVC_CTRL_SEND + SVC_LINK_NEXT], r_tmp2
stx r_tmp2, [r_root + HV_SVC_DATA_SENDH]
stx %g0, [r_root + HV_SVC_DATA_SENDT]
1: stx %g0, [r_svc + SVC_CTRL_SEND + SVC_LINK_NEXT]
ld [r_svc + SVC_CTRL_STATE], r_tmp2
andn r_tmp2, SVC_FLAGS_TP, r_tmp2
or r_tmp2, SVC_FLAGS_TI, r_tmp2
st r_tmp2, [r_svc + SVC_CTRL_STATE]
btst SVC_CFG_CALLBACK, r_tmp2
#define r_hvtxcallback r_tmp2
bnz,pn %xcc, do_hvtxcallback ! HV callback
UNLOCK(r_svc, SVC_CTRL_LOCK)
btst SVC_FLAGS_TE, r_tmp2
ldx [r_svc + SVC_CTRL_INTR_COOKIE], %g1 ! Cookie
ba vdev_intr_generate ! deliver??
! rebuild the regs we care about
ldx [r_root + CONFIG_SVCS], r_root ! svc root
stw %g0, [r_root + HV_SVC_DATA_SENDBUSY]
ldx [r_root + HV_SVC_DATA_SENDH], r_svc ! head of tx q
PRINT("Next Packet: "); PRINTX(r_svc); PRINT("\r\n")
brz,pn r_svc, txintr_done
SEND_SVC_PACKET(r_root, r_svc, r_tmp1, r_tmp2, r_tmp3, r_tmp4)
TX_INTR_DONE(IRQ_QUEUE_OUT)
ldub [r_chan + FPGA_Q_STATUS], r_tmp3 ! get status
stb r_tmp3, [r_chan + FPGA_Q_STATUS] ! clr status
TX_INTR_DONE(IRQ_QUEUE_OUT)
* SAVE/RESTORE_SVCREGS - save/restore all registers except %g7 which
add %g7, CPU_SVCREGS, %g7 ;\
#define RESTORE_SVCREGS \
add %g7, CPU_SVCREGS, %g7 ;\
* Perform a hypervisor callback for a receive channel
* The callback cookie is passed in %g1.
* The svc pointer %g2, state is RI. If the
* packet has been successfully processed then the callback
* routine needs to clear the RI flag.
ENTRY_NP(do_hvrxcallback)
PRINT("do_hvrxcallback\r\n")
UNLOCK(r_svc, SVC_CTRL_LOCK)
ldx [r_svc + SVC_CTRL_CALLBACK + SVC_CALLBACK_RX], %g7
PRINT("HV RX Callback: "); PRINTX(r_svc); PRINT("\r\n")
ldx [r_svc + SVC_CTRL_CALLBACK + SVC_CALLBACK_RX], %g7
ldx [r_svc + SVC_CTRL_CALLBACK + SVC_CALLBACK_COOKIE], %g1
9: RX_INTR_DONE(QINTR_ACK, r_chan)
SET_SIZE(do_hvrxcallback)
ENTRY_NP(do_hvtxcallback)
PRINT("do_hvtxcallback\r\n")
UNLOCK(r_svc, SVC_CTRL_LOCK)
ldx [r_svc + SVC_CTRL_CALLBACK + SVC_CALLBACK_TX], %g1
PRINT("HV TX Callback: "); PRINTX(r_svc); PRINT("\r\n")
ldx [r_svc + SVC_CTRL_CALLBACK + SVC_CALLBACK_TX], %g6
ldx [r_svc + SVC_CTRL_CALLBACK + SVC_CALLBACK_COOKIE], %g1
ldx [r_svc + SVC_CTRL_SEND + SVC_LINK_PA], %g2
add %g2, SVC_PKT_SIZE, %g2 ! skip header
SET_SIZE(do_hvtxcallback)
#endif /* } CONFIG_SVC */