Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / diag / assembly / include / interrupt0x60_handler.s.pal
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: interrupt0x60_handler.s.pal
* Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
* 4150 Network Circle, Santa Clara, California 95054, U.S.A.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For the avoidance of doubt, and except that if any non-GPL license
* choice is available it will apply instead, Sun elects to use only
* the General Public License version 2 (GPLv2) at this time for any
* software where a choice of GPL license versions is made
* available with the language indicating that GPLv2 or any later version
* may be used, or where a choice of which version of the GPL is applied is
* otherwise unspecified.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*
* ========== Copyright Header End ============================================
*/
start_perl
# $Id: interrupt0x60_handler.s.pal,v 1.14 2006/12/01 19:20:42 granvold Exp $
print "/* \$Id\$ */\n";
# Hardware constraints:
$hw_num_ivs = 64; $hw_max_ivn = $hw_num_ivs - 1;
$hw_num_threads = 64; $hw_max_thread_num = $hw_num_threads - 1;
# interrupt0x60 constraints:
$max_cc_ivns = 48; $max_cc_ivns_m1 = $max_cc_ivns - 1;
$max_niu_ivns = 16; $max_niu_ivns_m1 = $max_niu_ivns - 1;
$max_msi_idx = 8; $max_msi_idx_m1 = $max_msi_idx - 1;
start_text(>)
/* Shared trap handler for interrupts (TT=0x60) */
/*>>>>>> ONLY EDIT THE .pal VERSION OF THIS FILE <<<<<<<<*/
/*
* This is tightly linked with interrupt0x60_defines.h and
* interrupt0x60_sys_init.s
*
* There are several different consumers of interrupt information:
* 1. random test generators which stimulate interrupts
* 2. boot code that initializes interrupt-related registers
* 3. the shared interrupt trap handler
*/
#ifdef USE_BOBO
#include "bobo_defines.h"
#endif /* USE_BOBO */
SECTION .HTRAPS
.text
.global intr0x60_handler
intr0x60_handler:
mov %g7, %o7 ! Restore %o7
ldxa [%g0] ASI_INTR_ID, %g1 ! Get the thread number
ldxa [%g0] ASI_INTR_R, %g2 ! Get the interrupt vector number
setx intr0x60_ivn_to_ig, %g4, %g3
ldub [%g3+%g2], %g4
cmp %g4, INTR0x60_IG_CC
be intr0x60_handle_cc
nop
#ifdef INTR0x60_NIU_TX_IV_0
cmp %g4, INTR0x60_IG_NIU_TX
be intr0x60_handle_niu_tx
nop
#endif /* INTR0x60_NIU_TX_IV_0 */
#ifdef INTR0x60_NIU_RX_IV_0
cmp %g4, INTR0x60_IG_NIU_RX
be intr0x60_handle_niu_rx
nop
#endif /* INTR0x60_NIU_RX_IV_0 */
#ifdef INTR0x60_MONDO_IV
cmp %g4, INTR0x60_IG_PIU
be intr0x60_handle_piu
nop
#endif /* INTR0x60_MONDO_IV */
#if (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV)
cmp %g4, INTR0x60_IG_SSI_ERR
be intr0x60_handle_ssi_err
nop
#endif /* (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV) */
#if (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV)
cmp %g4, INTR0x60_IG_SSI_INT
be intr0x60_handle_ssi_int
nop
#endif /* (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV) */
/* If we get here, we got an unexpected vector number */
intr0x60_bad_ivn:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_bad_ivn)) -> printf("ERROR: Bad interrupt vector number",*,1)
EXIT_BAD
/************************************************************************/
/* Handle cross-call interrupts */
intr0x60_handle_cc:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_cc)) -> printf("INFO: Cross-call interrupt received",*,1)
#ifndef INTR0x60_CC_DEST_ALL
/* Make sure that this thread is allowed to receive cross-calls */
setx intr0x60_handle_cc_thread_table, %g5, %g4
#ifdef PORTABLE_CORE
and %g1, 0x7, %g5
ldub [%g4+%g5], %g4
#else
ldub [%g4+%g1], %g4
#endif
brz %g4, intr0x60_handle_cc_bad_thread
nop
#endif /* INTR0x60_CC_DEST_ALL */
/* Include any extra cross-call handler from the user */
/* The code can assume that %g1 is the thread and %g2 is the vector */
#ifdef INTR0x60_CC_EXTRA_HANDLER
intr0x60_handle_cc_extra_handler:
INTR0x60_CC_EXTRA_HANDLER
#endif /* INTR0x60_CC_EXTRA_HANDLER */
intr0x60_handle_cc_retry:
/* Retry the instruction that was trapped */
retry
#ifndef INTR0x60_CC_DEST_ALL
intr0x60_handle_cc_bad_thread:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_cc_bad_thread)) -> printf("ERROR: Cross-call received on unexpected thread",*,1)
EXIT_BAD
.data
intr0x60_handle_cc_thread_table:
>for ($thread = 0; $thread < $hw_num_threads; $thread++) {
#if defined(INTR0x60_CC_DEST_${thread})
.byte 1
#else
.byte 0
#endif
>}
.text
#endif /* INTR0x60_CC_DEST_ALL */
#ifdef INTR0x60_NIU_TX_IV_0
/************************************************************************/
/* Handle NIU TX interrupts */
intr0x60_handle_niu_tx:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_tx)) -> printf("INFO: NIU TX interrupt received",*,1)
/* Make sure that this thread is the right one for this NIU interrupt */
>for ($ivn = 0; $ivn < $max_niu_ivns; $ivn++) {
#ifdef INTR0x60_NIU_TX_IV_${ivn}
intr0x60_handle_niu_tx_check_thread_${ivn}:
cmp %g2, INTR0x60_NIU_TX_IV_${ivn}
bnz 1f
#ifdef PORTABLE_CORE
and %g1, 0x7, %g7
cmp %g7, INTR0x60_NIU_TX_THREAD_${ivn}
#else
cmp %g1, INTR0x60_NIU_TX_THREAD_${ivn}
#endif
bnz intr0x60_handle_niu_tx_bad_thread
best_set_reg(INTR0x60_NIU_TX_DMA_${ivn}, %g7, %g3)
ba intr0x60_handle_niu_tx_good_thread
nop
1:
#endif /* INTR0x60_NIU_TX_IV_${ivn} */
>}
/* If we get here, we have an unknown vector */
intr0x60_handle_niu_tx_bad_vector:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_tx_bad_vector)) -> printf("interrupt0x60_handler.s ERROR: intr0x60_iv_to_ig said this is an NIU TX interrupt, but it is not defined in INTR0x60_NIU_TX_IV_x",*,1)
EXIT_BAD
/* If we get here, we know we have the right thread for this vector */
intr0x60_handle_niu_tx_good_thread:
/* Clear the source of the interrupt */
! Re-enable the interrupt in the transmit DMA channel
best_set_reg(TX_CS, %g7, %g4) ! TX_CS
best_set_reg(TDMC_STEP, %g7, %g5)
mulx %g5, %g3, %g5 ! %g3 is the DMA TX channel
add %g4, %g5, %g4
ldxa [%g4]ASI_PRIMARY_LITTLE, %g0 ! Reset MK
! Re-enable the interrupt in the NIU
best_set_reg(LDGIMGN, %g7, %g4) ! LDGIMGN
best_set_reg(LDGIMGN_STEP, %g7, %g5)
mulx %g5, %g2, %g5
add %g4, %g5, %g4
best_set_reg(0x80000001, %g7, %g5)
stxa %g5, [%g4]ASI_PRIMARY_LITTLE
nop
/* Include any extra NIU handler from the user */
/* The code can assume that %g1 is the thread, %g2 is the vector,
* and %g3 is the TX DMA channel */
#ifdef INTR0x60_NIU_TX_EXTRA_HANDLER
intr0x60_handle_niu_tx_extra_handler:
INTR0x60_NIU_TX_EXTRA_HANDLER
#endif /* INTR0x60_NIU_TX_EXTRA_HANDLER */
intr0x60_handle_niu_tx_retry:
/* Retry the instruction that was trapped */
retry
intr0x60_handle_niu_tx_bad_thread:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_tx_bad_thread)) -> printf("ERROR: NIU TX interrupt received on unexpected thread",*,1)
EXIT_BAD
#endif /* INTR0x60_NIU_TX_IV_0 */
#ifdef INTR0x60_NIU_RX_IV_0
/************************************************************************/
/* Handle NIU RX interrupts */
intr0x60_handle_niu_rx:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx)) -> printf("INFO: NIU RX interrupt received",*,1)
/* Make sure that this thread is the right one for this NIU interrupt */
>for ($ivn = 0; $ivn < $max_niu_ivns; $ivn++) {
#ifdef INTR0x60_NIU_RX_IV_${ivn}
intr0x60_handle_niu_rx_check_thread_${ivn}:
cmp %g2, INTR0x60_NIU_RX_IV_${ivn}
bnz 1f
#ifdef PORTABLE_CORE
and %g1, 0x7, %g7
cmp %g7, INTR0x60_NIU_RX_THREAD_${ivn}
#else
cmp %g1, INTR0x60_NIU_RX_THREAD_${ivn}
#endif
bnz intr0x60_handle_niu_rx_bad_thread
best_set_reg(INTR0x60_NIU_RX_DMA_${ivn}, %g7, %g3)
ba intr0x60_handle_niu_rx_good_thread
nop
1:
#endif /* INTR0x60_NIU_RX_IV_${ivn} */
>}
/* If we get here, we have an unknown vector */
intr0x60_handle_niu_rx_bad_vector:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_bad_vector)) -> printf("interrupt0x60_handler.s ERROR: intr0x60_iv_to_ig said this is an NIU RX interrupt, but it is not defined in INTR0x60_NIU_RX_IV_x",*,1)
EXIT_BAD
/* If we get here, we know we have the right thread for this vector */
intr0x60_handle_niu_rx_good_thread:
/* Clear the source of the interrupt */
best_set_reg(RX_DMA_CTL_STAT, %g7, %g4)
mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
add %g4, %g7, %g4 ! Addr of RX DMA Ctl/stat for this channel
intr0x60_handle_niu_rx_get_rx_dma_ctl_stat:
ldxa [%g4]ASI_PRIMARY_LITTLE, %g5 ! Get status
mov 0x7, %g7
sllx %g7, 32, %g7 ! Mask for clear-on-reset error bits
and %g5, %g7, %g7
brz %g7, intr0x60_handle_niu_rx_nonfatal
nop
intr0x60_handle_niu_rx_fatal_error:
#ifdef INTR0x60_NIU_RX_FATAL_HANDLER
INTR0x60_NIU_RX_FATAL_HANDLER
#else /* INTR0x60_NIU_RX_FATAL_HANDLER */
#ifdef INTR0x60_NIU_RX_CLEAR_FATAL_FOR_TSOTOOL
/* This code does what is needed for tsotool NIU RX fatal error interrupts */
best_set_reg(RXDMA_CFIG1, %g7, %g4)
mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
add %g4, %g7, %g4
intr0x60_handle_niu_rx_fatal_error_disable_dma_channel:
stxa %g0, [%g4]ASI_PRIMARY_LITTLE
membar #Sync
mov 1, %g7
sllx %g7, 30, %g7 ! RST bit in RXDMA_CFIG1
intr0x60_handle_niu_rx_fatal_error_reset_dma_channel:
stxa %g7, [%g4]ASI_PRIMARY_LITTLE
srlx %g7, 1, %g7 ! QST bit in RXDMA_CFIG1
mov 10, %g6 ! Timeout
intr0x60_handle_niu_rx_fatal_error_wait_for_dma_channel:
ldxa [%g4]ASI_PRIMARY_LITTLE, %g5 ! Get the status
cmp %g5, %g7
beq intr0x60_handle_niu_rx_fatal_error_enable_intr_for_dma_channel
dec %g6
brnz %g6, intr0x60_handle_niu_rx_fatal_error_wait_for_dma_channel
nop
intr0x60_handle_niu_rx_fatal_error_timeout_wait_for_dma_channel:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_fatal_error_timeout_wait_for_dma_channel)) -> printf("ERROR: NIU RX interrupt received for fatal error and DMA channel reset never completed",*,1)
EXIT_BAD
intr0x60_handle_niu_rx_fatal_error_enable_intr_for_dma_channel:
best_set_reg(RX_DMA_ENT_MSK, %g7, %g5)
mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
add %g5, %g7, %g5
stxa %g0, [%g5]ASI_PRIMARY_LITTLE
ba intr0x60_handle_niu_rx_reenable_ldg
membar #Sync
#else /* INTR0x60_NIU_RX_CLEAR_FATAL_FOR_TSOTOOL */
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_fatal_error)) -> printf("ERROR: NIU RX interrupt received for fatal error",*,1)
EXIT_BAD
#endif /* INTR0x60_NIU_RX_CLEAR_FATAL_FOR_TSOTOOL */
#endif /* INTR0x60_NIU_RX_FATAL_HANDLER */
intr0x60_handle_niu_rx_nonfatal:
best_set_reg(0xffffffffffff0000, %g7, %g6)
and %g5, %g6, %g5 ! Only preserve error bits, for RW1C
best_set_reg(RCR_STAT_A, %g7, %g6)
mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
add %g6, %g7, %g6
intr0x60_handle_niu_rx_get_rcr_stat_a:
ldxa [%g6]ASI_PRIMARY_LITTLE, %g6 ! Get the number of pkts received
or %g6, %g5, %g6
best_set_reg(THRES_INT, %g7, %g5) ! Bit to enable mailbox (MEX in PRM)
or %g6, %g5, %g6
intr0x60_handle_niu_rx_reset_rx_dma_ctl_stat:
stxa %g6, [%g4]ASI_PRIMARY_LITTLE ! RW1C on RCRTHRES, RCRTO, etc., plus
! set MEX, decrement QLEN by pkt read
intr0x60_handle_niu_rx_reenable_ldg:
! Re-enable the interrupt in the NIU LDG
best_set_reg(LDGIMGN, %g7, %g4) ! LDGIMGN
best_set_reg(LDGIMGN_STEP, %g7, %g5)
mulx %g5, %g2, %g5
add %g4, %g5, %g4
best_set_reg(0x80000001, %g7, %g5)
stxa %g5, [%g4]ASI_PRIMARY_LITTLE ! Arm LDGI, set timer to 1
nop
/* Include any extra NIU handler from the user */
/* The code can assume that %g1 is the thread, %g2 is the vector,
* and %g3 is the RX DMA channel */
#ifdef INTR0x60_NIU_RX_EXTRA_HANDLER
intr0x60_handle_niu_rx_extra_handler:
INTR0x60_NIU_RX_EXTRA_HANDLER
#endif /* INTR0x60_NIU_RX_EXTRA_HANDLER */
intr0x60_handle_niu_rx_retry:
/* Retry the instruction that was trapped */
retry
intr0x60_handle_niu_rx_bad_thread:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_bad_thread)) -> printf("ERROR: NIU RX interrupt received on unexpected thread",*,1)
EXIT_BAD
#endif /* INTR0x60_NIU_RX_IV_0 */
#ifdef INTR0x60_MONDO_IV
/************************************************************************/
/* Handle PIU interrupts */
intr0x60_handle_piu:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu)) -> printf("INFO: PIU interrupt received",*,1)
#ifndef INTR0x60_DO_NOT_READ_ADATA1
/* To reach coverage goals, do a dummy read from ADATA1 */
best_set_reg(MONDO_INT_ADATA1, %g4, %g3)
ldx [%g3], %g3
#endif /* INTR0x60_DO_NOT_READ_ADATA1 */
best_set_reg(MONDO_INT_ADATA0, %g4, %g3)
ldx [%g3], %g3
and %g3, 0x3f, %g3 /* WIP: Mask to get INO */
#if INTR0x60_MONDO_20_V
cmp %g3, 20
be intr0x60_handle_piu_inta
nop
#endif /* INTR0x60_MONDO_20_V */
#if INTR0x60_MONDO_21_V
cmp %g3, 21
be intr0x60_handle_piu_intb
nop
#endif /* INTR0x60_MONDO_21_V */
#if INTR0x60_MONDO_22_V
cmp %g3, 22
be intr0x60_handle_piu_intc
nop
#endif /* INTR0x60_MONDO_22_V */
#if INTR0x60_MONDO_23_V
cmp %g3, 23
be intr0x60_handle_piu_intd
nop
#endif /* INTR0x60_MONDO_23_V */
>for $idx (0 .. $max_msi_idx_m1) {
#ifdef INTR0x60_MSI_${idx}_NUM
intr0x60_handle_piu_check_msi_${idx}:
cmp %g3, mpeval(INTR0x60_MSI_${idx}_EQN+24)
be intr0x60_handle_piu_msi_${idx}
mov ${idx}, %g4
#endif /* INTR0x60_MSI_${idx}_NUM */
>}
#ifdef INTR0x60_PM_PME_EQN
intr0x60_handle_piu_check_pm_pme:
cmp %g3, mpeval(INTR0x60_PM_PME_EQN+24)
be intr0x60_handle_piu_pm_pme
nop
#endif /* INTR0x60_PM_PME_EQN */
#ifdef INTR0x60_PME_TO_ACK_EQN
intr0x60_handle_piu_check_pme_to_ack:
cmp %g3, mpeval(INTR0x60_PME_TO_ACK_EQN+24)
be intr0x60_handle_piu_pme_to_ack
nop
#endif /* INTR0x60_PME_TO_ACK_EQN */
/* If we get here, we got an unexpected INO */
intr0x60_bad_mondo_INO:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_bad_mondo_INO)) -> printf("ERROR: Bad mondo INO",*,1)
EXIT_BAD
>@intx_letters = ("A", "B", "C", "D");
>for ($intx = 0; $intx < 4; $intx++) {
> $ino = 20 + $intx;
> $uc = $intx_letters[$intx];
> $lc = lc $uc;
#if INTR0x60_MONDO_${ino}_V
/************ Handle INT${uc} ***********/
intr0x60_handle_piu_int${lc}:
/* Check whether this thread matches this INO */
#ifdef PORTABLE_CORE
and %g1, 0x7, %g7
cmp %g7/*tid*/, INTR0x60_MONDO_${ino}_THREAD
#else
cmp %g1/*tid*/, INTR0x60_MONDO_${ino}_THREAD
#endif
bne intr0x60_handle_piu_bad_thread
nop
/* Clear the interrupt */
intr0x60_handle_piu_int${lc}_deassert:
#ifdef FC_NO_PEU_VERA
#ifdef USE_BOBO
! Offset accesses by PCIE_MEM64_OFFSET since
! BAR is set that way. Physical addresses generated via TSB
! have this offset so mimic that when accessing directly, as here.
best_set_reg(mpeval(N2_PCIE_BASE_ADDR
+ MEM64_OFFSET_BASE_REG_DATA
+ PCIE_MEM64_OFFSET
+ BOBO_INTR_VECT_STATUS_OFFSET), %g7, %g4)
! Interrupt type
mov eval(1 << $intx), %g5
#else /* USE_BOBO */
! Offset accesses by PCIE_MEM64_OFFSET since
! BAR is set that way. Physical addresses generated via TSB
! have this offset so mimic that when accessing directly, as here.
best_set_reg(mpeval(N2_PCIE_BASE_ADDR
+ MEM64_OFFSET_BASE_REG_DATA
+ PCIE_MEM64_OFFSET
+ (INTR0x60_MONDO_${ino}_DMAEPT_ENGINE << 8)
+ DMAEPT_INTERRUPT_ACK), %g7, %g4)
! Interrupt type
best_set_reg(DMAEPT_INTERRUPT_ACK_INT${uc}, %g7, %g5)
#endif /* USE_BOBO */
stwa %g5, [%g4] ASI_NL
#else /* FC_NO_PEU_VERA */
! \$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu_int${lc}_deassert)) -> EnablePCIeIgCmd ("INT${uc}", 0, 0, "DEASSERT", 1, *, 1 )
#endif /* FC_NO_PEU_VERA */
/* Loop on the INTX Status Register until the deassert message
* has arrived and been processed. */
best_set_reg(PCI_E_INTX_STATUS_ADDR, %g5, %g4)
best_set_reg(INTR0x60_INTX_DEASSERT_TIMEOUT, %g5, %g6)
intr0x60_handle_piu_int${lc}_deassert_loop:
brz %g6, intr0x60_handle_piu_int${lc}_deassert_timeout
dec %g6
ldx [%g4], %g3
>$bit = 1 << (3-$intx);
and %g3, ${bit}, %g3 ! ${bit} == bit for INT${uc}
brnz %g3, intr0x60_handle_piu_int${lc}_deassert_loop
set 1, %g3
intr0x60_handle_piu_int${lc}_clear:
best_set_reg(PCI_E_INT_${uc}_CLEAR_ADDR, %g5, %g4)
stx %g3, [%g4]
best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR+${intx}*PCI_E_INT_CLEAR_STEP), %g5, %g4)
stx %g0, [%g4]
best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
stx %g0, [%g4]
/* Include any extra INT${uc} handler from the user */
/* The code can assume that %g1 is the thread and %g2 is the vector */
#ifdef INTR0x60_INT${uc}_EXTRA_HANDLER
intr0x60_handle_int${lc}_extra_handler:
INTR0x60_INT${uc}_EXTRA_HANDLER
#endif /* INTR0x60_INT${uc}_EXTRA_HANDLER */
intr0x60_handle_piu_int${lc}_retry:
/* Retry the instruction that was trapped */
retry
#endif /* INTR0x60_MONDO_${ino}_V */
/* If we get here, the interrupt status bit didn't deassert */
intr0x60_handle_piu_int${lc}_deassert_timeout:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu_int${lc}_deassert_timeout)) -> printf("ERROR: INT${uc} status bit did not deassert within INTR0x60_INTX_DEASSERT_TIMEOUT iterations",*,1)
EXIT_BAD
>}
>for $idx (0 .. $max_msi_idx_m1) {
#ifdef INTR0x60_MSI_${idx}_NUM
/************ Handle MSI ${idx} ***********/
intr0x60_handle_piu_msi_${idx}:
!WIP: /* Check whether this thread matches this INO */
!WIP: cmp %g1/*tid*/, INTR0x60_MONDO_XXX_THREAD
!WIP: bne intr0x60_handle_piu_bad_thread
!WIP: nop
/* Clear the interrupt */
/* MSI Clear reg. */
intr0x60_handle_piu_msi_${idx}_clear_eqwr:
set 1, %g4
sllx %g4, 62, %g4 ! EQWR_N is bit 62
best_set_reg(mpeval(PCI_E_MSI_CLEAR_ADDR
+PCI_E_MSI_CLEAR_STEP*INTR0x60_MSI_${idx}_NUM),
%g7, %g5)
stx %g4, [%g5] ! clear EQWR in MSI map reg.
membar #Sync
intr0x60_handle_piu_msi_${idx}_disable_eq:
set 1, %g4
sllx %g4, 44, %g4 ! DIS is bit 44
best_set_reg(mpeval(PCI_E_EV_QUE_CTL_CLEAR_ADDR
+PCI_E_EV_QUE_CTL_CLEAR_STEP*INTR0x60_MSI_${idx}_EQN),
%g7, %g5)
stx %g4, [%g5]
! Set Event Queue Head = Event Queue Tail
intr0x60_handle_piu_msi_${idx}_reset_eq_head:
best_set_reg(mpeval(PCI_E_EV_QUE_TAIL_ADDR
+PCI_E_EV_QUE_TAIL_STEP*INTR0x60_MSI_${idx}_EQN),
%g7, %g5)
ldx [%g5], %g6
best_set_reg(mpeval(PCI_E_EV_QUE_HEAD_ADDR
+PCI_E_EV_QUE_HEAD_STEP*INTR0x60_MSI_${idx}_EQN),
%g7, %g5)
stx %g6, [%g5]
intr0x60_handle_piu_msi_${idx}_clear_int:
best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR
+(4+INTR0x60_MSI_${idx}_EQN)*PCI_E_INT_CLEAR_STEP),
%g5, %g4)
stx %g0, [%g4]
/* Include any extra MSI handler from the user that needs to be
* executed while the mondo busy flag is still asserted. */
/* The code can assume that %g1 is the thread,
* %g2 is the vector, and
* %g3 is the INO */
#ifdef INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY
intr0x60_handle_msi_${idx}_extra_handler_while_busy:
INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY
#endif /* INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY */
intr0x60_handle_piu_msi_${idx}_clear_mondo_busy:
best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
stx %g0, [%g4]
/* Include any extra MSI handler from the user that needs to be
* executed while the event queue is disabled. */
/* The code can assume that %g1 is the thread,
* %g2 is the vector, and
* %g3 is the INO */
#ifdef INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED
intr0x60_handle_msi_extra_handler_while_eq_disabled_${idx}:
INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED
#endif /* INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED */
intr0x60_handle_piu_msi_${idx}_enable_eq:
set 1, %g4
sllx %g4, 44, %g4 ! EN is bit 44
best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_ADDR
+PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_MSI_${idx}_EQN),
%g7, %g5)
stx %g4, [%g5]
ba intr0x60_handle_msi_extra_handler
nop
#endif /* INTR0x60_MSI_${idx}_NUM */
>}
/* Include any extra MSI handler from the user */
/* The code can assume that %g1 is the thread,
* %g2 is the vector, and
* %g3 is the INO */
intr0x60_handle_msi_extra_handler:
#ifdef INTR0x60_MSI_EXTRA_HANDLER
INTR0x60_MSI_EXTRA_HANDLER
#endif /* INTR0x60_MSI_EXTRA_HANDLER */
intr0x60_handle_piu_msi_retry:
/* Retry the instruction that was trapped */
retry
#ifdef INTR0x60_PM_PME_EQN
/************ Handle PM_PME ***********/
intr0x60_handle_piu_pm_pme:
!WIP: /* Check whether this thread matches this INO */
!WIP: cmp %g1/*tid*/, INTR0x60_MONDO_XXX_THREAD
!WIP: bne intr0x60_handle_piu_bad_thread
!WIP: nop
/* Clear the interrupt */
intr0x60_handle_piu_pm_pme_disable_eq:
set 1, %g4
sllx %g4, 44, %g4 ! DIS is bit 44
best_set_reg(mpeval(PCI_E_EV_QUE_CTL_CLEAR_ADDR
+PCI_E_EV_QUE_CTL_CLEAR_STEP*INTR0x60_PM_PME_EQN),
%g7, %g5)
stx %g4, [%g5]
! Set Event Queue Head = Event Queue Tail
intr0x60_handle_piu_pm_pme_reset_eq_head:
best_set_reg(mpeval(PCI_E_EV_QUE_TAIL_ADDR
+PCI_E_EV_QUE_TAIL_STEP*INTR0x60_PM_PME_EQN),
%g7, %g5)
ldx [%g5], %g6
best_set_reg(mpeval(PCI_E_EV_QUE_HEAD_ADDR
+PCI_E_EV_QUE_HEAD_STEP*INTR0x60_PM_PME_EQN),
%g7, %g5)
stx %g6, [%g5]
intr0x60_handle_piu_pm_pme_clear_int:
best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR
+(4+INTR0x60_PM_PME_EQN)*PCI_E_INT_CLEAR_STEP),
%g5, %g4)
stx %g0, [%g4]
intr0x60_handle_piu_pm_pme_clear_mondo_busy:
best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
stx %g0, [%g4]
/* Include any extra PM_PME handler from the user that needs to be
* executed while the event queue is disabled. */
/* The code can assume that %g1 is the thread,
* %g2 is the vector, and
* %g3 is the INO */
#ifdef INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED
intr0x60_handle_pm_pme_extra_handler_while_eq_disabled:
INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED
#endif /* INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED */
intr0x60_handle_piu_pm_pme_enable_eq:
set 1, %g4
sllx %g4, 44, %g4 ! EN is bit 44
best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_ADDR
+PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_PM_PME_EQN),
%g7, %g5)
stx %g4, [%g5]
/* Include any extra PM_PME handler from the user */
/* The code can assume that %g1 is the thread,
* %g2 is the vector, and
* %g3 is the INO */
intr0x60_handle_pm_pme_extra_handler:
#ifdef INTR0x60_PM_PME_EXTRA_HANDLER
INTR0x60_PM_PME_EXTRA_HANDLER
#endif /* INTR0x60_PM_PME_EXTRA_HANDLER */
intr0x60_handle_piu_pm_pme_retry:
/* Retry the instruction that was trapped */
retry
#endif /* INTR0x60_PM_PME_EQN */
#ifdef INTR0x60_PME_TO_ACK_EQN
/************ Handle PME_TO_ACK ***********/
intr0x60_handle_piu_pme_to_ack:
!WIP: /* Check whether this thread matches this INO */
!WIP: cmp %g1/*tid*/, INTR0x60_MONDO_XXX_THREAD
!WIP: bne intr0x60_handle_piu_bad_thread
!WIP: nop
/* Clear the interrupt */
intr0x60_handle_piu_pme_to_ack_disable_eq:
set 1, %g4
sllx %g4, 44, %g4 ! DIS is bit 44
best_set_reg(mpeval(PCI_E_EV_QUE_CTL_CLEAR_ADDR
+PCI_E_EV_QUE_CTL_CLEAR_STEP*INTR0x60_PME_TO_ACK_EQN),
%g7, %g5)
stx %g4, [%g5]
! Set Event Queue Head = Event Queue Tail
intr0x60_handle_piu_pme_to_ack_reset_eq_head:
best_set_reg(mpeval(PCI_E_EV_QUE_TAIL_ADDR
+PCI_E_EV_QUE_TAIL_STEP*INTR0x60_PME_TO_ACK_EQN),
%g7, %g5)
ldx [%g5], %g6
best_set_reg(mpeval(PCI_E_EV_QUE_HEAD_ADDR
+PCI_E_EV_QUE_HEAD_STEP*INTR0x60_PME_TO_ACK_EQN),
%g7, %g5)
stx %g6, [%g5]
intr0x60_handle_piu_pme_to_ack_clear_int:
best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR
+(4+INTR0x60_PME_TO_ACK_EQN)*PCI_E_INT_CLEAR_STEP),
%g5, %g4)
stx %g0, [%g4]
intr0x60_handle_piu_pme_to_ack_clear_mondo_busy:
best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
stx %g0, [%g4]
/* Include any extra PME_TO_ACK handler from the user that needs to be
* executed while the event queue is disabled. */
/* The code can assume that %g1 is the thread,
* %g2 is the vector, and
* %g3 is the INO */
#ifdef INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED
intr0x60_handle_pme_to_ack_extra_handler_while_eq_disabled:
INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED
#endif /* INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED */
intr0x60_handle_piu_pme_to_ack_enable_eq:
set 1, %g4
sllx %g4, 44, %g4 ! EN is bit 44
best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_ADDR
+PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_PME_TO_ACK_EQN),
%g7, %g5)
stx %g4, [%g5]
/* Include any extra PME_TO_ACK handler from the user */
/* The code can assume that %g1 is the thread,
* %g2 is the vector, and
* %g3 is the INO */
intr0x60_handle_pme_to_ack_extra_handler:
#ifdef INTR0x60_PME_TO_ACK_EXTRA_HANDLER
INTR0x60_PME_TO_ACK_EXTRA_HANDLER
#endif /* INTR0x60_PME_TO_ACK_EXTRA_HANDLER */
intr0x60_handle_piu_pme_to_ack_retry:
/* Retry the instruction that was trapped */
retry
#endif /* INTR0x60_PME_TO_ACK_EQN */
intr0x60_handle_piu_bad_thread:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu_bad_thread)) -> printf("ERROR: Mondo delivered to wrong thread",*,1)
EXIT_BAD
#endif /* INTR0x60_MONDO_IV */
#if (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV)
/************************************************************************/
/* Handle SSI parity error interrupts */
intr0x60_handle_ssi_err:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_err)) -> printf("INFO: SSI parity error interrupt received",*,1)
/* Make sure that this thread is the right one */
best_set_reg(INTR0x60_SSI_ERR_THREAD, %g7, %g4)
#ifdef PORTABLE_CORE
and %g1, 0x7, %g7
cmp %g7, %g4
#else
cmp %g1, %g4
#endif
bne intr0x60_handle_ssi_err_bad_thread
nop
/* Include any extra SSI parity error handler from the user */
/* The code can assume that %g1 is the thread and %g2 is the vector */
#ifdef INTR0x60_SSI_ERR_EXTRA_HANDLER
intr0x60_handle_ssi_err_extra_handler:
INTR0x60_SSI_ERR_EXTRA_HANDLER
#endif /* INTR0x60_SSI_ERR_EXTRA_HANDLER */
intr0x60_handle_ssi_err_retry:
/* Retry the instruction that was trapped */
retry
intr0x60_handle_ssi_err_bad_thread:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_err_bad_thread)) -> printf("ERROR: SSI parity error interrupt received on unexpected thread",*,1)
EXIT_BAD
#endif /* (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV) */
#if (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV)
/************************************************************************/
/* Handle SSI_EXT_INT_L interrupts */
intr0x60_handle_ssi_int:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_int)) -> printf("INFO: SSI_EXT_INT_L interrupt received",*,1)
/* Make sure that this thread is the right one */
best_set_reg(INTR0x60_SSI_INT_THREAD, %g7, %g4)
#ifdef PORTABLE_CORE
and %g1, 0x7, %g7
cmp %g7, %g4
#else
cmp %g1, %g4
#endif
bne intr0x60_handle_ssi_int_bad_thread
nop
/* Include any extra SSI_EXT_INT_L handler from the user */
/* The code can assume that %g1 is the thread and %g2 is the vector */
#ifdef INTR0x60_SSI_INT_EXTRA_HANDLER
intr0x60_handle_ssi_int_extra_handler:
INTR0x60_SSI_INT_EXTRA_HANDLER
#endif /* INTR0x60_SSI_INT_EXTRA_HANDLER */
intr0x60_handle_ssi_int_retry:
/* Retry the instruction that was trapped */
retry
intr0x60_handle_ssi_int_bad_thread:
!\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_int_bad_thread)) -> printf("ERROR: SSI_EXT_INT_L interrupt received on unexpected thread",*,1)
EXIT_BAD
#endif /* (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV) */
/*
* Need to have some tables to identify the source of the interrupt
* and whether it is expected for this thread.
*
* intr0x60_ivn_to_ig has one byte per interrupt vector number (0-63),
* which indicates the interrupt group, encoded as
* 0 - unused (error)
* 1 - cross-call
* 2 - SSI error
* 3 - SSI_EXT_INT_L
* 4 - NIU
* 5 - PIU mondo
*/
.data
intr0x60_ivn_to_ig:
>for ($count = 0; $count < $max_cc_ivns; $count++) {
#ifdef INTR0x60_CC_IV_${count}
#define INTR0x60_CC_IV_${count}_CHECK (INTR0x60_CC_IV_${count} == `\$1')
#else
#define INTR0x60_CC_IV_${count}_CHECK (0)
#endif
>}
>for ($count = 0; $count < $max_niu_ivns; $count++) {
#ifdef INTR0x60_NIU_RX_IV_${count}
#define INTR0x60_NIU_RX_IV_${count}_CHECK (INTR0x60_NIU_RX_IV_${count} == `\$1')
#else
#define INTR0x60_NIU_RX_IV_${count}_CHECK (0)
#endif
>}
>for ($count = 0; $count < $max_niu_ivns; $count++) {
#ifdef INTR0x60_NIU_TX_IV_${count}
#define INTR0x60_NIU_TX_IV_${count}_CHECK (INTR0x60_NIU_TX_IV_${count} == `\$1')
#else
#define INTR0x60_NIU_TX_IV_${count}_CHECK (0)
#endif
>}
#if (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV)
#define INTR0x60_SSI_ERR_IV_CHECK (INTR0x60_SSI_ERR_IV == `\$1')
#else
#define INTR0x60_SSI_ERR_IV_CHECK (0)
#endif
#if (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV)
#define INTR0x60_SSI_INT_IV_CHECK (INTR0x60_SSI_INT_IV == `\$1')
#else
#define INTR0x60_SSI_INT_IV_CHECK (0)
#endif
#ifdef INTR0x60_MONDO_IV
#define INTR0x60_MONDO_IV_CHECK (INTR0x60_MONDO_IV == `\$1')
#else
#define INTR0x60_MONDO_IV_CHECK (0)
#endif
/* Note: Need to put INTR0x60_IG_* names on a separate line
* because the *_CHECK macros may contain a half-quote which
* would prevent cpp from doing the macro replacement */
define(`INTR0x60_IVN_TO_IG',
`ifelse(eval( INTR0x60_CC_IV_0_CHECK
>for ($count = 1; $count < $max_cc_ivns-1; $count++) {
|| INTR0x60_CC_IV_${count}_CHECK
>}
|| INTR0x60_CC_IV_${count}_CHECK), 1,
INTR0x60_IG_CC,
eval( INTR0x60_SSI_ERR_IV_CHECK ), 1,
INTR0x60_IG_SSI_ERR,
eval( INTR0x60_SSI_INT_IV_CHECK ), 1,
INTR0x60_IG_SSI_INT,
eval( INTR0x60_MONDO_IV_CHECK ), 1,
INTR0x60_IG_PIU,
eval( INTR0x60_NIU_RX_IV_0_CHECK
>for ($count = 1; $count < $max_niu_ivns-1; $count++) {
|| INTR0x60_NIU_RX_IV_${count}_CHECK
>}
|| INTR0x60_NIU_RX_IV_${count}_CHECK), 1,
INTR0x60_IG_NIU_RX,
eval( INTR0x60_NIU_TX_IV_0_CHECK
>for ($count = 1; $count < $max_niu_ivns-1; $count++) {
|| INTR0x60_NIU_TX_IV_${count}_CHECK
>}
|| INTR0x60_NIU_TX_IV_${count}_CHECK), 1,
INTR0x60_IG_NIU_TX,
INTR0x60_IG_UNUSED)'
)dnl
>for ($ivn = 0; $ivn < $hw_num_ivs; $ivn++) {
.byte INTR0x60_IVN_TO_IG(${ivn})
>}
undefine(`INTR0x60_IVN_TO_IG')dnl