* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: niu.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 "@(#)niu.s 1.9 07/09/06 SMI"
#include <sys/asm_linkage.h>
* N.B. "internally NIU is a little-endian device".
* Map logical devices to logical groups 1:1 according to the
* following 'well-defined' mapping:
* The group number will also function as the "devino".
* Furthermore, give each group number a unique vector ("identifier")
* to use when an interrupt occurs so we know which device needs to
/* logical device #, logical group #, vector identifier/priority # */
.xword NIU_LDN_RX_DMA_CH0, 19, 0,
.xword NIU_LDN_RX_DMA_CH1, 20, 1,
.xword NIU_LDN_RX_DMA_CH2, 21, 2,
.xword NIU_LDN_RX_DMA_CH3, 22, 3,
.xword NIU_LDN_RX_DMA_CH4, 23, 4,
.xword NIU_LDN_RX_DMA_CH5, 24, 5,
.xword NIU_LDN_RX_DMA_CH6, 25, 6,
.xword NIU_LDN_RX_DMA_CH7, 26, 7,
.xword NIU_LDN_RX_DMA_CH8, 36, 8,
.xword NIU_LDN_RX_DMA_CH9, 37, 9,
.xword NIU_LDN_RX_DMA_CH10, 38, 10,
.xword NIU_LDN_RX_DMA_CH11, 39, 11,
.xword NIU_LDN_RX_DMA_CH12, 40, 12,
.xword NIU_LDN_RX_DMA_CH13, 41, 13,
.xword NIU_LDN_RX_DMA_CH14, 42, 14,
.xword NIU_LDN_RX_DMA_CH15, 43, 15,
.xword NIU_LDN_TX_DMA_CH0, 27, 16,
.xword NIU_LDN_TX_DMA_CH1, 28, 17,
.xword NIU_LDN_TX_DMA_CH2, 29, 18,
.xword NIU_LDN_TX_DMA_CH3, 30, 19,
.xword NIU_LDN_TX_DMA_CH4, 31, 20,
.xword NIU_LDN_TX_DMA_CH5, 32, 21,
.xword NIU_LDN_TX_DMA_CH6, 33, 22,
.xword NIU_LDN_TX_DMA_CH7, 34, 23,
.xword NIU_LDN_TX_DMA_CH8, 44, 24,
.xword NIU_LDN_TX_DMA_CH9, 45, 25,
.xword NIU_LDN_TX_DMA_CH10, 46, 26,
.xword NIU_LDN_TX_DMA_CH11, 47, 27,
.xword NIU_LDN_TX_DMA_CH12, 48, 28,
.xword NIU_LDN_TX_DMA_CH13, 49, 29,
.xword NIU_LDN_TX_DMA_CH14, 50, 30,
.xword NIU_LDN_TX_DMA_CH15, 51, 31,
.xword NIU_LDN_MIF, 17, 32,
.xword NIU_LDN_MAC0, 16, 33,
.xword NIU_LDN_MAC1, 35, 34,
.xword NIU_LDN_SYSERR, 18, 35,
.xword -1,-1,-1 /* End of Table */
* NIU logical device group to logical device number table
DATA_GLOBAL(niu_ldg2ldn_table)
.xword -1, -1, -1, -1, -1, -1, -1, -1
.xword -1, -1, -1, -1, -1, -1, -1, -1
.xword NIU_LDN_MAC0, NIU_LDN_MIF
.xword NIU_LDN_SYSERR, NIU_LDN_RX_DMA_CH0,
.xword NIU_LDN_RX_DMA_CH1, NIU_LDN_RX_DMA_CH2,
.xword NIU_LDN_RX_DMA_CH3, NIU_LDN_RX_DMA_CH4
.xword NIU_LDN_RX_DMA_CH5, NIU_LDN_RX_DMA_CH6,
.xword NIU_LDN_RX_DMA_CH7, NIU_LDN_TX_DMA_CH0
.xword NIU_LDN_TX_DMA_CH1, NIU_LDN_TX_DMA_CH2
.xword NIU_LDN_TX_DMA_CH3, NIU_LDN_TX_DMA_CH4
.xword NIU_LDN_TX_DMA_CH5, NIU_LDN_TX_DMA_CH6
.xword NIU_LDN_TX_DMA_CH7, NIU_LDN_MAC1
.xword NIU_LDN_RX_DMA_CH8, NIU_LDN_RX_DMA_CH9
.xword NIU_LDN_RX_DMA_CH10, NIU_LDN_RX_DMA_CH11
.xword NIU_LDN_RX_DMA_CH12, NIU_LDN_RX_DMA_CH13
.xword NIU_LDN_RX_DMA_CH14, NIU_LDN_RX_DMA_CH15
.xword NIU_LDN_TX_DMA_CH8, NIU_LDN_TX_DMA_CH9
.xword NIU_LDN_TX_DMA_CH10, NIU_LDN_TX_DMA_CH11
.xword NIU_LDN_TX_DMA_CH12, NIU_LDN_TX_DMA_CH13
.xword NIU_LDN_TX_DMA_CH14, NIU_LDN_TX_DMA_CH15
.xword -1, -1, -1, -1, -1, -1, -1, -1
SET_SIZE(niu_ldg2ldn_table)
* NIU vector to logical device group table
* Map interrupt vector ("identifier") to logical device group
* number. The logical device group number is the "devino".
DATA_GLOBAL(niu_vec2ldg_table)
.xword 19, 20, 21, 22, 23, 24, 25, 26
.xword 36, 37, 38, 39, 40, 41, 42, 43
.xword 27, 28, 29, 30, 31, 32, 33, 34
.xword 44, 45, 46, 47, 48, 49, 50, 51
.xword 17, 16, 35, 18, -1, -1, -1, -1
.xword -1, -1, -1, -1, -1, -1, -1, -1
.xword -1, -1, -1, -1, -1, -1, -1, -1
.xword -1, -1, -1, -1, -1, -1, -1, -1
SET_SIZE(niu_vec2ldg_table)
* To avoid store buffer collisions keep this struct cacheline aligned by
* passing NIUMAPREG_SIZE as alignment restriction; see comment above
BSS_GLOBAL(niu_state, NIUSTATE_SIZE, NIUMAPREG_SIZE)
* Convert a Logical Group Number to a Logical Device Number.
* (ldn and cookie can be the same register) or
* (ldn and lgn can be the same register)
#define NIU_LGN2LDN(lgn, ldn, cookie, scr1) \
sllx lgn, SHIFT_LONG, scr1 ;\
ldx [cookie + NIU_LDG2LDN_TABLE], ldn ;\
* Convert a Mondo Vector Number to a Logical Group Number.
* (lgn and cookie can be the same register) or
* (lgn and vec can be the same register)
#define NIU_VEC2LDN(vec, lgn, cookie, scr1) \
sllx vec, SHIFT_LONG, scr1 ;\
ldx [cookie + NIU_VEC2LDG_TABLE], lgn ;\
* Get the MAPREG for a logical group number (INO).
* (guest and scr1 can be the same register)
#define NIU_LGN2MAPREG(guest, lgn, mapreg, scr1) \
set GUEST_NIU_STATEP, mapreg ;\
ldn [guest + mapreg], mapreg ;\
add mapreg, NIUSTATE_MAPREG, mapreg ;\
sllx lgn, NIUMAPREG_SHIFT, scr1 ;\
* Get the target VCPU pointer for a logical device group (INO).
#define NIU_LGN2TARGET_VCPUP(lgn, vcpup, scr1) \
NIU_LGN2MAPREG(scr1, lgn, vcpup, scr1) ;\
ldn [vcpup + NIUMAPREG_VCPUP], vcpup
* Get the interrupt status bits for a logical device group (INO).
#define NIU_LGN2STATEBITS(lgn, ldn, bits, scr1, scr2, scr3) \
/* LDN < 64, check the first two state vectors */ ;\
setx NIU_LDSV0_REG, scr2, scr1 ;\
sllx lgn, NIU_LDSV0_REG_SHIFT, bits ;\
ldxa [scr1 + bits]ASI_P_LE, bits ;\
setx NIU_LDSV1_REG, scr2, scr1 ;\
sllx lgn, NIU_LDSV1_REG_SHIFT, scr3 ;\
ldxa [scr1 + scr3]ASI_P_LE, scr3 ;\
0: /* LDN >= 64, check the last state vector */ ;\
setx NIU_LDSV2_REG, scr2, scr1 ;\
sllx lgn, NIU_LDSV2_REG_SHIFT, bits ;\
ldxa [scr1 + bits]ASI_P_LE, bits ;\
* niu_init: Initialize NIU device
* N.B. called from C; use only %g1, %g5, %g6 or %g7.
STRAND_PUSH(%g2, %g6, %g7)
STRAND_PUSH(%g3, %g6, %g7)
STRAND_PUSH(%g4, %g6, %g7)
* Initialize the logical device groups.
setx NIU_LDG_NUM_REG, %g4, %g3
ldx [%g2], %g4 ! %g4 is logical device number
ldx [%g2 + 8], %g5 ! %g5 is logical group number
sllx %g4, NIU_LDG_NUM_REG_SHIFT, %g4
stxa %g5, [%g3 + %g4]ASI_P_LE
* Initialize DMA channel bindings. Don't bind any of the channels to
* virtualization regions.
setx NIU_DMA_BIND_REG, %g3, %g2
inc NIU_DMA_BIND_REG_STEP, %g2
cmp %g1, NIU_DMA_BIND_N_REG
* Initialize the NCU-related interrupt registers.
* INT_MAN index = logical group number + 64
setx NIU_SID_REG, %g3, %g2
inc NIU_SID_REG_STEP, %g2
* niu_intr_init: Initialize NCU-related part of NIU interrupt infrastructure
* %i0 - global config pointer
* %globals, %locals (%l7 preserved)
* Initialize INT_MAN[] vector dispatch priority aka
* ("NIU device identifier").
sllx %g1, INT_MAN_CPU_SHIFT, %g1 ! master cpu is default target
ldx [%i0 + CONFIG_RELOC], %g3
ldx [%g2 + 16], %g4 ! %g4 is "identifier"
ldx [%g2 + 8], %g5 ! %g5 is logical group number
sllx %g5, INT_MAN_SHIFT, %g5
* niu_reset: Reset NIU device
* N.B. called from C; use only %g1, %g5, %g6 or %g7.
setx NIU_XMAC_CFG_REG_0, %g6, %g1
CPU_MSEC_DELAY(100, %g1, %g5, %g6)
setx NIU_XMAC_SM_REG_0, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
btst XMAC_SM_RX_QST_ST, %g5
setx NIU_XMAC_CFG_REG_1, %g6, %g1
CPU_MSEC_DELAY(100, %g1, %g5, %g6)
setx NIU_XMAC_SM_REG_1, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
btst XMAC_SM_RX_QST_ST, %g5
/* stop the RX DMA engines */
setx NIU_RX_CFG1_REG, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
1: ldxa [%g1]ASI_P_LE, %g5
inc NIU_RX_CFG1_REG_STEP, %g1
cmp %g6, NIU_RX_CFG1_N_REG
setx NIU_IPP_CFG_REG_0, %g6, %g1
setx NIU_IPP_CFG_REG_1, %g6, %g1
/* reset the RX DMA engines */
setx NIU_RX_CFG1_REG, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
1: ldxa [%g1]ASI_P_LE, %g5
inc NIU_RX_CFG1_REG_STEP, %g1
cmp %g6, NIU_RX_CFG1_N_REG
/* stop the TX DMA engines */
0: setx NIU_TX_PORT0_REG, %g5, %g1
setx NIU_TX_PORT1_REG, %g5, %g1
setx NIU_TX_CTL_ST_REG, %g5, %g1
sllx %g6, NIU_TX_CTL_ST_REG_SHIFT, %g5
set TX_CTL_STOP_N_GO, %g7
1: ldxa [%g1]ASI_P_LE, %g5
cmp %g6, NIU_TX_CTL_ST_N_REG
setx NIU_XMAC_CFG_REG_0, %g6, %g1
* Should be checking the xMAC State Machine Status register here
* but not sure what the 'final' state is. Instead wait a while.
CPU_MSEC_DELAY(100, %g1, %g5, %g6)
setx NIU_XMAC_CFG_REG_1, %g6, %g1
* Should be checking the xMAC State Machine Status register here
* but not sure what the 'final' state is. Instead wait a while.
CPU_MSEC_DELAY(100, %g1, %g5, %g6)
/* reset the TX DMA engines */
0: setx NIU_TX_PORT0_REG, %g5, %g1
setx NIU_TX_PORT1_REG, %g5, %g1
setx NIU_TX_CTL_ST_REG, %g5, %g1
sllx %g6, NIU_TX_CTL_ST_REG_SHIFT, %g5
1: ldxa [%g1]ASI_P_LE, %g5
set TX_CTL_RESET_STS, %g7
cmp %g6, NIU_TX_CTL_ST_N_REG
!! Rx xMAC port 0 soft reset
setx NIU_XRXMAC_RST_REG_0, %g6, %g1
set (XRXMAC_REG_RST | XRXMAC_SM_RST), %g5
setx NIU_XRXMAC_RST_REG_0, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
!! Rx xMAC port 1 soft reset
setx NIU_XRXMAC_RST_REG_1, %g6, %g1
set (XRXMAC_REG_RST | XRXMAC_SM_RST), %g5
setx NIU_XRXMAC_RST_REG_1, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
!! Tx xMAC port 0 soft reset
setx NIU_XTXMAC_RST_REG_0, %g6, %g1
set (XTXMAC_REG_RST | XTXMAC_SM_RST), %g5
setx NIU_XTXMAC_RST_REG_0, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
!! Tx xMAC port 1 soft reset
setx NIU_XTXMAC_RST_REG_1, %g6, %g1
set (XTXMAC_REG_RST | XTXMAC_SM_RST), %g5
setx NIU_XTXMAC_RST_REG_1, %g6, %g1
0: ldxa [%g1]ASI_P_LE, %g5
setx NIU_IPP_CFG_REG_0, %g6, %g1
setx NIU_IPP_CFG_REG_1, %g6, %g1
/* reset control FIFOs */
setx NIU_CFIFO_RESET_REG, %g6, %g1
set (RESET_CFIFO1 | RESET_CFIFO0), %g5
* Now the NIU ought to be thoroughly quiesced. For completeness
* and to bring all registers back to POR state whack the entire
setx SUBSYS_RESET, %g5, %g1
* niu_mondo - handle an NIU interrrupt.
* N.B. we perform the retry here.
DEVINST2INDEX(%g1, %g3, %g3, %g4, niu_mondo_fail)
DEVINST2COOKIE(%g1, %g3, %g3, %g4, niu_mondo_fail)
NIU_VEC2LDN(%g2, %g2, %g3, %g4) ! %g2 = logical device group
NIU_LGN2MAPREG(%g1, %g2, %g3, %g1)
ld [%g3 + NIUMAPREG_VALID], %g4
brnz %g4, 1f ! interrupt enabled?
add %g3, NIUMAPREG_STATE, %g3
casa [%g3]ASI_P, %g4, %g5
add %g2, (NIU_DEVINST << DEVCFGPA_SHIFT), %g2
HVCALL(insert_device_mondo_r)
* %g1 = logical device number
* %g6 = logical group number
* Check if the logical device has a pending interrupt. If pending,
ENTRY_NP(niu_intr_notify)
NIU_LGN2STATEBITS(%g6, %g1, %g3, %g2, %g5, %g7)
brz %g3, niu_intr_notify_exit
!! %g1 = logical device number
!! %g6 = logical group number
add %g4, NIUMAPREG_STATE, %g4
casa [%g4]ASI_P, %g2, %g5
bne %xcc, niu_intr_notify_exit
! determine the target vcpu and deliver the interrupt
NIU_LGN2TARGET_VCPUP(%g6, %g1, %g2)
add %g6, (NIU_DEVINST << DEVCFGPA_SHIFT), %g3
SET_SIZE(niu_intr_notify)
* niu_intr_redistribution
* Need to invalidate all of the virtual intrs that are
* mapped to the cpu passed in %g1 and retarget to the
ENTRY_NP(niu_intr_redistribution)
SET_SIZE(niu_intr_redistribution)
* arg0 dev config pa (%o0)
ENTRY_NP(niu_devino2vino)
* All validity checks on config pa and dev ino have been
* performed before we get here. Just create the vino and
SET_SIZE(niu_devino2vino)
* %g1 = NIU cookie pointer
* ret1 intr valid state (%o1)
ENTRY_NP(niu_intr_getvalid)
! convert from sysino -> devino (logical group) -> logical device
and %o0, DEVINOMASK, %g2 ! %g2 is logical group number
NIU_LGN2MAPREG(%g3, %g2, %g4, %g3)
ld [%g4 + NIUMAPREG_VALID], %g1
movrz %g1, INTR_DISABLED, %o1
SET_SIZE(niu_intr_getvalid)
* %g1 = NIU cookie pointer
* arg1 intr valid state (%o1) 1: Valid 0: Invalid
ENTRY_NP(niu_intr_setvalid)
! convert from sysino -> devino (logical group) -> logical device
and %o0, DEVINOMASK, %g6 ! %g6 is logical group number
NIU_LGN2MAPREG(%g3, %g6, %g4, %g3)
brz,pn %o1, niu_intr_setvalid_exit ! interrupt VALID?
st %o1, [%g4 + NIUMAPREG_VALID] ! regardless, fill in valid
!! %g6 = logical group number
NIU_LGN2LDN(%g6, %g1, %g1, %g3) ! %g1 is logical device number
brlz %g1, niu_intr_setvalid_fail
! Enable interrupt by clearing mask register.
! Recall there are _two_ different mask regions,
! one for the first 64 devices, the second for the remaining 5.
setx NIU_PIO_IMASK0_BASE, %g3, %g2
set NIU_INTR_MASK0_REG_SHIFT, %g3
setx NIU_PIO_IMASK1_BASE, %g3, %g2
set NIU_INTR_MASK1_REG_SHIFT, %g3
ldxa [%g2 + %g5]ASI_P_LE, %g3
brz %g3, 2f ! already enabled?
stxa %g0, [%g2 + %g5]ASI_P_LE
! check if there is a pending interrupt, if so, notify guest
SET_SIZE(niu_intr_setvalid)
ENTRY_NP(niu_intr_getstate)
!! %g1 = NIU cookie pointer
! convert from sysino -> devino (logical group)
and %o0, DEVINOMASK, %g6 ! %g6 is logical device group
NIU_LGN2MAPREG(%g2, %g6, %g3, %g2)
ld [%g3 + NIUMAPREG_STATE], %o1
SET_SIZE(niu_intr_getstate)
* arg1 (%o1) 1: Pending / 0: Idle XXX
ENTRY_NP(niu_intr_setstate)
!! %g1 = NIU cookie pointer
! convert from sysino -> devino (logical group)
and %o0, DEVINOMASK, %g6 ! %g6 is logical device group
brlz,pn %o1, niu_set_state_fail
bgu,pn %xcc, niu_set_state_fail
NIU_LGN2MAPREG(%g2, %g6, %g4, %g2)
bne,pn %xcc, niu_set_state_exit ! interrupt IDLE?
st %o1, [%g4 + NIUMAPREG_STATE] ! regardless, fill in state
ld [%g4 + NIUMAPREG_VALID], %o1
brz %o1, niu_set_state_exit ! interrupt enabled?
! check if there is a pending interrupt, if so, notify guest
!! %g6 = logical group number
NIU_LGN2LDN(%g6, %g1, %g1, %g3) ! %g1 is logical device number
brlz %g1, niu_set_state_fail
SET_SIZE(niu_intr_setstate)
ENTRY_NP(niu_intr_gettarget)
and %o0, DEVINOMASK, %g1 ! %g1 is logical group number
NIU_LGN2TARGET_VCPUP(%g1, %g2, %g3)
ldub [%g2 + CPU_VID], %o1
SET_SIZE(niu_intr_gettarget)
ENTRY_NP(niu_intr_settarget)
VCPUID2CPUP(%g3, %o1, %g4, herr_nocpu, %g5)
IS_CPU_IN_ERROR(%g4, %g5)
be,pn %xcc, herr_cpuerror
VCPU2STRAND_STRUCT(%g4, %g2)
ldub [%g2 + STRAND_ID], %g2
and %o0, DEVINOMASK, %g1 ! %g1 is logical group number
!! %g1 = logical group number
NIU_LGN2MAPREG(%g3, %g1, %g5, %g6)
stn %g4, [%g5 + NIUMAPREG_VCPUP]
sllx %g1, INT_MAN_SHIFT, %g1
setx (INT_MAN_CPU_MASK << INT_MAN_CPU_SHIFT), %g6, %g5
sllx %g2, INT_MAN_CPU_SHIFT, %g2
SET_SIZE(niu_intr_settarget)
* N.B. this will only work if the guest pa base >= the guest ra base.
ENTRY_NP(hcall_niu_rx_lp_set)
cmp %o1, NIU_RX_LPG_CH_N_REG
sllx %o0, NIU_RX_LPG_REG_SHIFT, %g6
brz %o3, 0f ! deconfiguring?
btst %o3, %g1 ! check that size is a power of two
btst %o2, %g1 ! check for natural alignment
bnz,pn %xcc, herr_badalign
RA2PA_RANGE_CONV(%g1, %o2, %o3, herr_noraddr, %g3, %g2)
srlx %g2, NIU_RX_LPG_SHIFT, %g2
setx NIU_RX_LPG_RELO1_REG, %g4, %g3
setx NIU_RX_LPG_RELO2_REG, %g5, %g4
stxa %g2, [%g3 + %g6]ASI_P_LE
srlx %o2, NIU_RX_LPG_SHIFT, %o2
setx NIU_RX_LPG_VALUE1_REG, %g4, %g3
setx NIU_RX_LPG_VALUE2_REG, %g5, %g4
stxa %o2, [%g3 + %g6]ASI_P_LE
srax %o3, NIU_RX_LPG_SHIFT, %o3
setx NIU_RX_LPG_MASK1_REG, %g4, %g3
setx NIU_RX_LPG_MASK2_REG, %g5, %g4
stxa %o3, [%g3 + %g6]ASI_P_LE
setx NIU_RX_LPG_VALID_REG, %g4, %g3
ldxa [%g3 + %g6]ASI_P_LE, %g1
set NIU_RX_LPG_V_PG0_VALUE, %g4
set NIU_RX_LPG_V_PG1_VALUE, %g5
stxa %g1, [%g3 + %g6]ASI_P_LE
setx NIU_RX_LPG_VALID_REG, %g4, %g3
ldxa [%g3 + %g6]ASI_P_LE, %g1
set NIU_RX_LPG_V_PG0_VALUE, %g4
set NIU_RX_LPG_V_PG1_VALUE, %g5
stxa %g1, [%g3 + %g6]ASI_P_LE
SET_SIZE(hcall_niu_rx_lp_set)
ENTRY_NP(hcall_niu_rx_lp_get)
cmp %o1, NIU_RX_LPG_CH_N_REG
sllx %o0, NIU_RX_LPG_REG_SHIFT, %g6
! is this channel/register setup?
setx NIU_RX_LPG_VALID_REG, %g4, %g3
ldxa [%g3 + %g6]ASI_P_LE, %g2
set NIU_RX_LPG_V_PG0_VALUE, %g4
set NIU_RX_LPG_V_PG1_VALUE, %g5
! retrieve raddr from value register
setx NIU_RX_LPG_VALUE1_REG, %g4, %g3
setx NIU_RX_LPG_VALUE2_REG, %g5, %g4
ldxa [%g3 + %g6]ASI_P_LE, %o1
sllx %o1, NIU_RX_LPG_SHIFT, %o1
! retrieve size from mask register
setx NIU_RX_LPG_MASK1_REG, %g4, %g3
setx NIU_RX_LPG_MASK2_REG, %g5, %g4
ldxa [%g3 + %g6]ASI_P_LE, %o2
sllx %o2, NIU_RX_LPG_SHIFT, %o2
SET_SIZE(hcall_niu_rx_lp_get)
* N.B. this will only work if the guest pa base >= the guest ra base.
ENTRY_NP(hcall_niu_tx_lp_set)
cmp %o1, NIU_TX_LPG_CH_N_REG
sllx %o0, NIU_TX_LPG_REG_SHIFT, %g6
brz %o3, 0f ! deconfiguring?
btst %o3, %g1 ! check that size is a power of two
btst %o2, %g1 ! check for natural alignment
bnz,pn %xcc, herr_badalign
RA2PA_RANGE_CONV(%g1, %o2, %o3, herr_noraddr, %g3, %g2)
srlx %g2, NIU_TX_LPG_SHIFT, %g2
setx NIU_TX_LPG_RELO1_REG, %g4, %g3
setx NIU_TX_LPG_RELO2_REG, %g5, %g4
stxa %g2, [%g3 + %g6]ASI_P_LE
srlx %o2, NIU_TX_LPG_SHIFT, %o2
setx NIU_TX_LPG_VALUE1_REG, %g4, %g3
setx NIU_TX_LPG_VALUE2_REG, %g5, %g4
stxa %o2, [%g3 + %g6]ASI_P_LE
srax %o3, NIU_TX_LPG_SHIFT, %o3
setx NIU_TX_LPG_MASK1_REG, %g4, %g3
setx NIU_TX_LPG_MASK2_REG, %g5, %g4
stxa %o3, [%g3 + %g6]ASI_P_LE
setx NIU_TX_LPG_VALID_REG, %g4, %g3
ldxa [%g3 + %g6]ASI_P_LE, %g1
set NIU_TX_LPG_V_PG0_VALUE, %g4
set NIU_TX_LPG_V_PG1_VALUE, %g5
stxa %g1, [%g3 + %g6]ASI_P_LE
setx NIU_TX_LPG_VALID_REG, %g4, %g3
ldxa [%g3 + %g6]ASI_P_LE, %g1
set NIU_TX_LPG_V_PG0_VALUE, %g4
set NIU_TX_LPG_V_PG1_VALUE, %g5
stxa %g1, [%g3 + %g6]ASI_P_LE
SET_SIZE(hcall_niu_tx_lp_set)
ENTRY_NP(hcall_niu_tx_lp_get)
cmp %o1, NIU_TX_LPG_CH_N_REG
sllx %o0, NIU_TX_LPG_REG_SHIFT, %g6
! is this channel/register setup?
setx NIU_TX_LPG_VALID_REG, %g4, %g3
ldxa [%g3 + %g6]ASI_P_LE, %g2
set NIU_TX_LPG_V_PG0_VALUE, %g4
set NIU_TX_LPG_V_PG1_VALUE, %g5
! retrieve raddr from value register
setx NIU_TX_LPG_VALUE1_REG, %g4, %g3
setx NIU_TX_LPG_VALUE2_REG, %g5, %g4
ldxa [%g3 + %g6]ASI_P_LE, %o1
sllx %o1, NIU_TX_LPG_SHIFT, %o1
! retrieve size from mask register
setx NIU_TX_LPG_MASK1_REG, %g4, %g3
setx NIU_TX_LPG_MASK2_REG, %g5, %g4
ldxa [%g3 + %g6]ASI_P_LE, %o2
sllx %o2, NIU_TX_LPG_SHIFT, %o2
SET_SIZE(hcall_niu_tx_lp_get)
* xaui_reset: Reset XAUI cards
* N.B. called from C; use only %g1, %g5, %g6 or %g7.
setx FPGA_PLATFORM_REGS, %g5, %g1
/* drive xaui slots into reset */
ldub [%g1 + FPGA_DEVICE_PRESENT_OFFSET], %g5
and %g5, FPGA_XAUI_SLOT_RESET_CTRL_MASK, %g5
stb %g5, [%g1 + FPGA_LDOM_SLOT_RESET_CONTROL_OFFSET]
CPU_MSEC_DELAY(300, %g5, %g6, %g7)
/* take xaui slots out of reset */
stb %g0, [%g1 + FPGA_LDOM_SLOT_RESET_CONTROL_OFFSET]
CPU_MSEC_DELAY(300, %g5, %g6, %g7)