//      TITLE ("Memory Fences, Load Acquires and Store Acquires")

/*++

    Copyright (c) 1995  Intel Corporation

    Module Name:

     i64itm.s assembly routines for updating ITM.

    Abstract:

      This module implements the I/O port access routines.

    Author:

      Bernard Lint, M. Jayakumar 17 Sep '97

    Environment:

      Kernel mode

    Revision History:

--*/

#include "ksia64.h"

        .file "i64itm.s"

        .global HalpClockCount
        .global HalpITMUpdateLatency
        .global HalpITCTicksPer100ns


// Temp until compiler fixed


        LEAF_ENTRY(HalpInitLINT)
        LEAF_SETUP(1,0,0,0)
        mov         t0 = 0x10000
        ;;
        mov         cr.lrr0 = t0
        mov         cr.lrr1 = t0
        ;;
        // Clear pending interrupts from irr's
        // read ivr until spurious (0xf)
        // set tpr level to zero to unmask all ints

        mov         t2 = cr.tpr
        ;;
        mov         cr.tpr = zero
        ;;
        srlz.d
        mov         t0 = 0xf
        ;;
Hil_loop:
        mov         t1 = cr.ivr
        ;;
        cmp.ne      pt0 = t0, t1
        ;;
(pt0)   mov         cr.eoi = zero
(pt0)   br.spnt     Hil_loop

        // Restore tpr

        mov         cr.tpr = t2
        ;;
        srlz.d
        LEAF_RETURN
        LEAF_EXIT(HalpInitLINT)

/*++

BOOLEAN
HalpDisableInterrupts (
    )

Routine Description:

     This function disables interrupts.

Arguements:

     None.

Return Value:

     TRUE if interrupts were previously enabled else FALSE

--*/

        LEAF_ENTRY(HalpDisableInterrupts)

        mov       t0 = psr
        mov       v0 = TRUE         // set return value -- TRUE if enabled
        ;;
        tbit.z    pt1 = t0, PSR_I   // pt1 = 1 if disabled
        ;;

        FAST_DISABLE_INTERRUPTS
(pt1)   mov       v0 = FALSE        // FALSE if disabled
        br.ret.sptk brp

        LEAF_EXIT(HalpDisableInterrupts)

/*++

VOID
HalpTurnOffInterrupts (
    VOID
    )

Routine Description:

     This function turns off interrupts and interruption resources collection.

Arguements:

     None.

Return Value:

     None.

--*/

        LEAF_ENTRY(HalpTurnOffInterrupts)
        rsm     1 << PSR_I
        ;;
        rsm     1 << PSR_IC
        ;;
        srlz.d
        LEAF_RETURN
        LEAF_EXIT(HalpTurnOffInterrupts)

/*++

VOID
HalpTurnOnInterrupts (
    VOID
    )

Routine Description:

     This function turns on interruption resources collection and interrupts.

Arguements:

     None.

Return Value:

     None.

--*/

        LEAF_ENTRY(HalpTurnOnInterrupts)
        ssm     1 << PSR_IC             // set PSR.ic bit again
        ;;
        srlz.i                          // serialize
        ;;
        ssm     1 << PSR_I              // set PSR.i bit again

        LEAF_RETURN
        LEAF_EXIT(HalpTurnOnInterrupts)

/*++

VOID
HalpSetNextClockInterrupts (
    VOID
    )

Routine Description:

     This function reads the current ITC and updates accordingly the ITM
     register with interruption resources collection and interrupts off.
     The interruption resources collection and interrupts are turned on
     returning to the caller.

Arguements:

     None.

Return Value:

     currentITCValue - previousITMValue.

--*/

        LEAF_ENTRY(HalpSetNextClockInterrupt)
        .regstk 0, 2, 0, 0

        alloc   r2 = 0, 2, 0, 0
        addl    r31 = @gprel(HalpClockCount),gp
        movl    r9 = KiPcr+PcHalReserved   // CURRENT_ITM_VALUE_INDEX = 0
        addl    r30 = @gprel(HalpITMUpdateLatency),gp
        ;;

        ld8.acq r11 = [r9]   // r11 = currentITMValue
        ld8     r10 = [r31]  // r10 = HalpClockCount
        ;;

// 08/16/2000 TF
// We should check if r11 == cr.itm here...
//

        add     r32 = r11, r10 // r32 = compareITCValue = currentITMValue + HalpClockCount
        ;;

        rsm     1 << PSR_I
        ;;

        rsm     1 << PSR_IC
        ;;
        srlz.d

retry_itm_read:

        mov     cr.itm = r32  // set itm with the most common scenario
        ;;
        mov     r30 = cr.itm

retry_itc_read:
        mov     r33 = ar.itc  // r33 = currentITCValue
        ;;

        cmp.ne  pt2 = r30, r32
(pt2)   br.cond.spnt retry_itm_read // this should not be taken,
                               // this just makes sure itm is actually written
#ifndef DISABLE_ITC_WORKAROUND
        cmp4.eq pt1 = -1, r33 // if lower 32 bits equal 0xffffffff
(pt1)   br.cond.spnt retry_itc_read
        ;;
#endif // DISABLE_ITC_WORKAROUND

        sub     r30 = r32, r33  // calculate a ITM/ITC delta
        ;;
        cmp.lt  pt0 = r30, r0  // if a delta is negative set pt0
        ;;
(pt0)   add     r32 = r32, r10  // r32 = updated currentITMValue + HalpClockCount
(pt0)   br.cond.spnt retry_itm_read
        ;;

        ssm     1 << PSR_IC     // set PSR.ic bit again
        ;;
        srlz.d                  // serialize
        ssm     1 << PSR_I      // set PSR.i bit again
        st8     [r9] = r32
        sub     r8 = r33, r11   // r8 = currentITCValue - previousITMValue

        LEAF_RETURN
        LEAF_EXIT(HalpSetNextClockInterrupt)