* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: setup.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 "@(#)setup.s 1.50 07/05/29 SMI"
* Routines that configure the hypervisor
#include <sys/asm_linkage.h>
#include <devices/pc16550.h>
#define HVALLOC(root, size, ptr, tmp) \
ldx [root + CONFIG_BRK], ptr ;\
stx tmp, [root + CONFIG_BRK]
#define STRANDID_2_MAUPID(cpu, mau) \
srlx cpu, STRANDID_2_COREID_SHIFT, mau
* setup_fire: Initialize Fire
* %i0 - global config pointer
mov %g7, %l7 /* save return address */
PRINT("HV:setup_fire\r\n")
* Relocate Fire TSB base pointers
ldx [%i0 + CONFIG_RELOC], %o0
ldx [%o1 + FIRE_COOKIE_IOTSB], %o2
stx %o2, [%o1 + FIRE_COOKIE_IOTSB]
add %o1, FIRE_COOKIE_SIZE, %o1
ldx [%o1 + FIRE_COOKIE_IOTSB], %o2
stx %o2, [%o1 + FIRE_COOKIE_IOTSB]
sub %o1, FIRE_COOKIE_SIZE, %o1
* Relocate Fire MSI EQ base pointers
ldx [%o1 + FIRE_COOKIE_MSIEQBASE], %o2
stx %o2, [%o1 + FIRE_COOKIE_MSIEQBASE]
add %o1, FIRE_COOKIE_SIZE, %o1
ldx [%o1 + FIRE_COOKIE_MSIEQBASE], %o2
stx %o2, [%o1 + FIRE_COOKIE_MSIEQBASE]
sub %o1, FIRE_COOKIE_SIZE, %o1
* Relocate Fire Virtual Interrupt pointer
ldx [%o1 + FIRE_COOKIE_VIRTUAL_INTMAP], %o2
stx %o2, [%o1 + FIRE_COOKIE_VIRTUAL_INTMAP]
add %o1, FIRE_COOKIE_SIZE, %o1
ldx [%o1 + FIRE_COOKIE_VIRTUAL_INTMAP], %o2
stx %o2, [%o1 + FIRE_COOKIE_VIRTUAL_INTMAP]
sub %o1, FIRE_COOKIE_SIZE, %o1
* Relocate Fire MSI and ERR Cookies
ldx [%o1 + FIRE_COOKIE_ERRCOOKIE], %o2
stx %o2, [%o1 + FIRE_COOKIE_ERRCOOKIE]
ldx [%o2 + FIRE_ERR_COOKIE_FIRE], %o4
stx %o4, [%o2 + FIRE_ERR_COOKIE_FIRE]
add %o1, FIRE_COOKIE_SIZE, %o1
ldx [%o1 + FIRE_COOKIE_ERRCOOKIE], %o2
stx %o2, [%o1 + FIRE_COOKIE_ERRCOOKIE]
ldx [%o2 + FIRE_ERR_COOKIE_FIRE], %o4
stx %o4, [%o2 + FIRE_ERR_COOKIE_FIRE]
sub %o1, FIRE_COOKIE_SIZE, %o1
ldx [%o1 + FIRE_COOKIE_MSICOOKIE], %o2
stx %o2, [%o1 + FIRE_COOKIE_MSICOOKIE]
ldx [%o2 + FIRE_MSI_COOKIE_FIRE], %o4
stx %o4, [%o2 + FIRE_MSI_COOKIE_FIRE]
add %o1, FIRE_COOKIE_SIZE, %o1
ldx [%o1 + FIRE_COOKIE_MSICOOKIE], %o2
stx %o2, [%o1 + FIRE_COOKIE_MSICOOKIE]
ldx [%o2 + FIRE_MSI_COOKIE_FIRE], %o4
stx %o4, [%o2 + FIRE_MSI_COOKIE_FIRE]
add %o1, FIRE_MSI_COOKIE_EQ, %o2
ldx [%o2 + FIRE_MSIEQ_BASE], %o4
stx %o4, [%o2 + FIRE_MSIEQ_BASE]
add %o2, FIRE_MSIEQ_SIZE, %o2
add %o1, FIRE_MSI_COOKIE_SIZE, %o1
add %o1, FIRE_MSI_COOKIE_EQ, %o2
ldx [%o2 + FIRE_MSIEQ_BASE], %o4
stx %o4, [%o2 + FIRE_MSIEQ_BASE]
add %o2, FIRE_MSIEQ_SIZE, %o2
* The FPGA interrupt output is an active-low level interrupt.
* The Niagara SSI interrupt input is falling-edge-triggered.
* We can lose an interrupt across a warm reset so workaround
* that by injecting a fake SSI interrupt at start-up time.
#ifdef CONFIG_FPGA /* Don't touch fpga hardware if it isn't there */
ldx [%o2 + INT_MAN + INT_MAN_DEV_OFF(IOBDEV_SSI)], %o1
stx %o1, [%o2 + INT_VEC_DIS]
* dummy tsb for the hypervisor to use
BSS_GLOBAL(dummytsb, DUMMYTSB_SIZE, DUMMYTSB_ALIGN)
* %i0 - global config pointer
ldx [CONFIG + CONFIG_INTRTGT], %g1
! %g1 = intrtgt CPUID array (8-bits per INT_MAN target)
* Clear interrupts for both SSIERR and SSI
* PRM: "After setting the MASK bit, software needs to issue a
* read on the INT_CTL register to guarantee the masking write
stx %g4, [%g2 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSIERR)]
ldx [%g2 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSIERR)], %g0
stx %g4, [%g2 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSI)]
ldx [%g2 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSI)], %g0
* setup the map registers for the SSI
/* SSI Error interrupt */
srl %g1, INTRTGT_DEVSHIFT, %g1 ! get dev1 bits in bottom
and %g1, INTRTGT_CPUMASK, %g3
sllx %g3, INT_MAN_CPU_SHIFT, %g3 ! int_man.cpu
or %g3, VECINTR_SSIERR, %g3 ! int_man.vecnum
stx %g3, [%g2 + INT_MAN + INT_MAN_DEV_OFF(IOBDEV_SSIERR)]
srl %g1, INTRTGT_DEVSHIFT, %g1 ! get dev2 bits in bottom
and %g1, INTRTGT_CPUMASK, %g3
sllx %g3, INT_MAN_CPU_SHIFT, %g3 ! int_man.cpu
or %g3, VECINTR_FPGA, %g3 ! int_man.vecnum
stx %g3, [%g2 + INT_MAN + INT_MAN_DEV_OFF(IOBDEV_SSI)]
stx %g0, [%g2 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSI)]
* Set J_INT_VEC to target all JBus interrupts to vec# VECINTR_DEV
setx IOBBASE + J_INT_VEC, %l2, %l1
* JBI_TRANS_TIMEOUT_VALUE - number of JBus clocks transactions must be
* We need a JBus transaction timeout that's at least as long as Fire's
* transaction timeout. The Fire TLU CTO is currently set to 67.1ms.
* 80ms seems like a fine value.
* This value is dependent on the vpci_fire.s fire_leaf_init_table entry
* for the FIRE_PLC_TLU_CTB_TLR_TLU_CTL register. Changes to either value
* may require the other value to change as well.
#define JBI_TRANS_TIMEOUT_MS 80
#define JBI_FREQUENCY (200 MHZ) /* assumed */
#define JBI_NS_PER_CLOCK (NS_PER_S / JBI_FREQUENCY)
#if JBI_NS_PER_CLOCK == 0
#error "Invalid JBI_FREQUENCY"
#define JBI_TRANS_TIMEOUT_VALUE \
(JBI_TRANS_TIMEOUT_MS * MS_PER_NS / JBI_NS_PER_CLOCK)
* setup_jbi - configure JBI global settings
* %i0 - global config pointer
* The JBI transaction timeout (JBI_TRANS_TIMEOUT) must be at
* least as long as the Fire transaction timeout (TLU CTO).
setx JBI_TRANS_TIMEOUT, %g2, %g1
set JBI_TRANS_TIMEOUT_VALUE, %g2
* Enable JBI error interrupts
* %g1 - errors to be enabled
* %g2 - clear SSIERR mask (true/false)
ENTRY(setup_jbi_err_interrupts)
#ifdef CONFIG_FPGA /* { */
* Enable All JBUS errors which generate an SSI interrupt
ENABLE_JBI_INTR_ERRS(%g1, %g3, %g4)
* Enable interrupts for SSIERR by clearing the MASK bit
stx %g0, [%g4 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSIERR)]
#endif /* } CONFIG_FPGA */
SET_SIZE(setup_jbi_err_interrupts)
#ifdef CONFIG_SVC /* { */
* c_svc_register() requires that we have these 2 null functions
ld [%g2 + SVC_CTRL_STATE], %g5
andn %g5, SVC_FLAGS_RI, %g5
st %g5, [%g2 + SVC_CTRL_STATE] ! clear RECV pending
PRINT("error_svc_rx\r\n")
* cn_svc_tx - error report transmission completion interrupt
* While sram was busy an other error may have occurred. In such case, we
* increase the send pkt counter and mark such packet for delivery.
* In this function, we check to see if there are any packets to be transmitted.
* We search in the following way:
* Look at fire A jbi err buffer
* Look at fire A pcie err buffer
* Look at fire B jbi err buffer
* Look at fire B pcie err buffer
* For each strand in NSTRANDS
* We only send a packet at a time, and in the previously described order.
* Since we are running in the intr completion routing, the svc_internal_send
* has already adquire the locks. For such reason, this routing needs to use
STRAND_PUSH(%g7, %g1, %g2)
PRINT("error_svc_tx\r\n")
VCPU_STRUCT(%g1) /* FIXME: strand */
ldx [%g1 + CPU_ROOT], %g1 /* FIXME: CPU2ROOT */
stx %g0, [%g1 + CONFIG_SRAM_ERPT_BUF_INUSE] ! clear the inuse flag
* See if we need to send more packets
ldx [%g1 + CONFIG_ERRS_TO_SEND], %g2
PRINT("NEED TO SEND ANOTHER PACKET\r\n")
* search vpci to see if we need to send errors
DEVINST2INDEX(%g1, %g2, %g2, %g3, 4f)
DEVINST2COOKIE(%g1, %g2, %g2, %g3, 4f)
add %g1, FIRE_COOKIE_JBC_ERPT, %g5
add %g5, PCI_UNSENT_PKT, %g2 ! %g2 needed at 2f
ldsw [%g5 + PCI_UNSENT_PKT], %g4
mov PCIERPT_SIZE - EPKTSIZE, %g3
/* Look at fire_a pcie */
add %g1, FIRE_COOKIE_PCIE_ERPT, %g1
add %g1, PCI_UNSENT_PKT, %g2 ! %g2 needed at 2f
ldsw [%g1 + PCI_UNSENT_PKT], %g4
mov PCIERPT_SIZE - EPKTSIZE, %g3
DEVINST2INDEX(%g1, %g2, %g2, %g3, 4f)
DEVINST2COOKIE(%g1, %g2, %g2, %g3, 4f)
add %g1, FIRE_COOKIE_JBC_ERPT, %g5
ldsw [%g5 + PCI_UNSENT_PKT], %g4
mov PCIERPT_SIZE - EPKTSIZE, %g3
/* Look at fire_b pcie */
add %g1, FIRE_COOKIE_PCIE_ERPT, %g1
ldsw [%g1 + PCI_UNSENT_PKT], %g4
mov PCIERPT_SIZE - EPKTSIZE, %g3
/* Now look at the strand erpts */
ldx [%g6 + STRAND_CONFIGP], %g6
ldx [%g6 + CONFIG_STRANDS], %g6
set STRAND_SIZE * NSTRANDS, %g5
add %g6, %g5, %g5 ! last cpu ptr
! Check in the CE err buf for marked pkt
add %g6, STRAND_CE_RPT + STRAND_UNSENT_PKT, %g2
add %g6, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g1
! Check in the UE err buf for marked pkt
set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
set STRAND_UE_RPT + STRAND_VBSC_ERPT, %g3
! %g6 = current strand ptr
cmp %g6, %g5 ! new ptr == last ptr?
PRINT("FOUND THE PACKAGE TO SEND\r\n")
! We found it. We have all the args in place, so just sent the pkt
HVCALL(send_diag_erpt_nolock)
! Mark as one less pkt to send
ldx [%g6 + STRAND_CONFIGP], %g6 /* config data */
add %g6, CONFIG_ERRS_TO_SEND, %g6
#endif /* CONFIG_SVC } */
* Clear memory sub-system and other error status registers
* ready to start overall system
ENTRY(clear_error_status_registers)
! XXX need to log the nonzero error status
set (NO_L2_BANKS - 1), %g5 ! bank select
setx L2_ESR_BASE, %g2, %g4 ! access the L2 csr
sllx %g5, L2_BANK_SHIFT, %g2
ldx [%g4], %g3 ! read status
stx %g3, [%g4] ! clear status (RW1C)
! clear the DRAM esr regs
! XXX need to log the nonzero error status
set (NO_DRAM_BANKS - 1), %g5 ! bank select
setx DRAM_ESR_BASE, %g2, %g4 ! access the dram csr
sllx %g5, DRAM_BANK_SHIFT, %g2
ldx [%g4], %g3 ! read status
stx %g3, [%g4] ! clear status (RW1C)
! clear CEs logged in SPARC ESR also
setx SPARC_CE_BITS, %g1, %g2
stxa %g2, [%g0]ASI_SPARC_ERR_STATUS
! enable all errors, UEs should already be enabled
stxa %g1, [%g0]ASI_SPARC_ERR_EN
BSET_L2_BANK_EEN(%g2, %g1, %g3, %g4)
BSET_L2_BANK_EEN(%g2, %g1, %g3, %g4)
BSET_L2_BANK_EEN(%g2, %g1, %g3, %g4)
BSET_L2_BANK_EEN(%g2, %g1, %g3, %g4)
SET_SIZE(clear_error_status_registers)
#ifdef RESETCONFIG_ENABLEHWSCRUBBERS /* { */
#define DEFAULT_L2_SCRUBINTERVAL 0x100
#define DEFAULT_DRAM_SCRUBFREQ 0xfff
* Helper macros which check if the scrubbers should be enabled, if so
* they get enabled with the default scrub rates.
#define DRAM_SCRUB_ENABLE(dram_base, bank, reg1, reg2) \
set DRAM_CHANNEL_DISABLE_REG + ((bank) * DRAM_BANK_STEP), reg1 ;\
ldx [dram_base + reg1], reg1 ;\
set DRAM_SCRUB_ENABLE_REG + ((bank) * DRAM_BANK_STEP), reg1 ;\
mov DEFAULT_DRAM_SCRUBFREQ, reg2 ;\
stx reg2, [dram_base + reg1] ;\
set DRAM_SCRUB_ENABLE_REG + ((bank) * DRAM_BANK_STEP), reg1 ;\
mov DRAM_SCRUB_ENABLE_REG_ENAB, reg2 ;\
stx reg2, [dram_base + reg1] ;\
#define L2_SCRUB_ENABLE(l2cr_base, bank, reg1, reg2) \
set bank << L2_BANK_SHIFT, reg1 ;\
ldx [l2cr_base + reg1], reg2 ;\
btst L2_SCRUBENABLE, reg2 ;\
set L2_SCRUBINTERVAL_MASK, reg1 ;\
set DEFAULT_L2_SCRUBINTERVAL, reg1 ;\
sllx reg1, L2_SCRUBINTERVAL_SHIFT, reg1 ;\
or reg1, L2_SCRUBENABLE, reg1 ;\
set bank << L2_BANK_SHIFT, reg1 ;\
stx reg2, [l2cr_base + reg1] ;\
ENTRY(enable_hw_scrubbers)
* Enable the l2$ scrubber for each of the four l2$ banks
setx L2_CONTROL_REG, %g2, %g1
L2_SCRUB_ENABLE(%g1, /* bank */ 0, %g2, %g3)
L2_SCRUB_ENABLE(%g1, /* bank */ 1, %g2, %g3)
L2_SCRUB_ENABLE(%g1, /* bank */ 2, %g2, %g3)
L2_SCRUB_ENABLE(%g1, /* bank */ 3, %g2, %g3)
* Enable the Niagara memory scrubber for each enabled DRAM
DRAM_SCRUB_ENABLE(%g1, /* bank */ 0, %g2, %g3)
DRAM_SCRUB_ENABLE(%g1, /* bank */ 1, %g2, %g3)
DRAM_SCRUB_ENABLE(%g1, /* bank */ 2, %g2, %g3)
DRAM_SCRUB_ENABLE(%g1, /* bank */ 3, %g2, %g3)
SET_SIZE(enable_hw_scrubbers)