remarkable-linux/arch/metag/tbx/tbidefr.S
James Hogan 95281171a7 metag: handle low level kicks directly
Kick interrupts trigger the LWK (low level kick) signal, usually handled
by the __TBIDoStdLWK() function which is the only handler inherited from
the bootloader. The LWK signal is converted either to a SWK (plain
software kick) or a SWS (software kick with an attached message).

Linux has kick_handler() to handle SWK and call registered kick handlers
(IPIs and inter-thread comms), but SWS is as far as I'm aware unused
with Linux.

Therefore remove that abstraction and have Linux handle LWK directly.
This will reduce kick latency slightly, and reduce our dependence on the
bootloader, which makes it easier to directly boot a kernel in QEMU
(particularly for SMP).

Signed-off-by: James Hogan <james.hogan@imgtec.com>
2013-11-06 10:40:02 +00:00

176 lines
5.2 KiB
ArmAsm

/*
* tbidefr.S
*
* Copyright (C) 2009, 2012 Imagination Technologies.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*
* Routing deferred exceptions
*/
#include <asm/metag_regs.h>
#include <asm/tbx.h>
.text
.balign 4
.global ___TBIHandleDFR
.type ___TBIHandleDFR,function
/* D1Ar1:D0Ar2 -- State
* D0Ar3 -- SigNum
* D0Ar4 -- Triggers
* D1Ar5 -- Inst
* D0Ar6 -- pTBI (volatile)
*/
___TBIHandleDFR:
#ifdef META_BUG_MBN100212
MSETL [A0StP++], D0FrT, D0.5
/* D1Ar1,D0Ar2,D1Ar5,D0Ar6 -- Arguments to handler, must be preserved
* D0Ar4 -- The deferred exceptions
* D1Ar3 -- As per D0Ar4 but just the trigger bits
* D0.5 -- The bgnd deferred exceptions
* D1.5 -- TXDEFR with bgnd re-added
*/
/* - Collect the pending deferred exceptions using TXSTAT,
* (ack's the bgnd exceptions as a side-effect)
* - Manually collect remaining (interrupt) deferred exceptions
* using TXDEFR
* - Replace the triggers (from TXSTATI) with the int deferred
* exceptions DEFR ..., TXSTATI would have returned if it was valid
* from bgnd code
* - Reconstruct TXDEFR by or'ing bgnd deferred exceptions (except
* the DEFER bit) and the int deferred exceptions. This will be
* restored later
*/
DEFR D0.5, TXSTAT
MOV D1.5, TXDEFR
ANDT D0.5, D0.5, #HI(0xFFFF0000)
MOV D1Ar3, D1.5
ANDT D1Ar3, D1Ar3, #HI(0xFFFF0000)
OR D0Ar4, D1Ar3, #TXSTAT_DEFER_BIT
OR D1.5, D1.5, D0.5
/* Mask off anything unrelated to the deferred exception triggers */
ANDT D1Ar3, D1Ar3, #HI(TXSTAT_BUSERR_BIT | TXSTAT_FPE_BITS)
/* Can assume that at least one exception happened since this
* handler wouldnt have been called otherwise.
*
* Replace the signal number and at the same time, prepare
* the mask to acknowledge the exception
*
* D1Re0 -- The bits to acknowledge
* D1Ar3 -- The signal number
* D1RtP -- Scratch to deal with non-conditional insns
*/
MOVT D1Re0, #HI(TXSTAT_FPE_BITS & ~TXSTAT_FPE_DENORMAL_BIT)
MOV D1RtP, #TXSTAT_FPE_INVALID_S
FFB D1Ar3, D1Ar3
CMP D1Ar3, #TXSTAT_FPE_INVALID_S
MOVLE D1Ar3, D1RtP /* Collapse FPE triggers to a single signal */
MOV D1RtP, #1
LSLGT D1Re0, D1RtP, D1Ar3
/* Get the handler using the signal number
*
* D1Ar3 -- The signal number
* D0Re0 -- Offset into TBI struct containing handler address
* D1Re0 -- Mask of triggers to keep
* D1RtP -- Address of handler
*/
SUB D1Ar3, D1Ar3, #(TXSTAT_FPE_INVALID_S - TBID_SIGNUM_FPE)
LSL D0Re0, D1Ar3, #2
XOR D1Re0, D1Re0, #-1 /* Prepare mask for acknowledge (avoids stall) */
ADD D0Re0,D0Re0,#TBI_fnSigs
GETD D1RtP, [D0Ar6+D0Re0]
/* Acknowledge triggers */
AND D1.5, D1.5, D1Re0
/* Restore remaining exceptions
* Do this here in case the handler enables nested interrupts
*
* D1.5 -- TXDEFR with this exception ack'd
*/
MOV TXDEFR, D1.5
/* Call the handler */
SWAP D1RtP, PC
GETL D0.5, D1.5, [--A0StP]
GETL D0FrT, D1RtP, [--A0StP]
MOV PC,D1RtP
#else /* META_BUG_MBN100212 */
/* D1Ar1,D0Ar2,D1Ar5,D0Ar6 -- Arguments to handler, must be preserved
* D0Ar4 -- The deferred exceptions
* D1Ar3 -- As per D0Ar4 but just the trigger bits
*/
/* - Collect the pending deferred exceptions using TXSTAT,
* (ack's the interrupt exceptions as a side-effect)
*/
DEFR D0Ar4, TXSTATI
/* Mask off anything unrelated to the deferred exception triggers */
MOV D1Ar3, D0Ar4
ANDT D1Ar3, D1Ar3, #HI(TXSTAT_BUSERR_BIT | TXSTAT_FPE_BITS)
/* Can assume that at least one exception happened since this
* handler wouldnt have been called otherwise.
*
* Replace the signal number and at the same time, prepare
* the mask to acknowledge the exception
*
* The unusual code for 1<<D1Ar3 may need explanation.
* Normally this would be done using 'MOV rs,#1' and 'LSL rd,rs,D1Ar3'
* but only D1Re0 is available in D1 and no crossunit insns are available
* Even worse, there is no conditional 'MOV r,#uimm8'.
* Since the CMP proves that D1Ar3 >= 20, we can reuse the bottom 12-bits
* of D1Re0 (using 'ORGT r,#1') in the knowledge that the top 20-bits will
* be discarded without affecting the result.
*
* D1Re0 -- The bits to acknowledge
* D1Ar3 -- The signal number
*/
MOVT D1Re0, #HI(TXSTAT_FPE_BITS & ~TXSTAT_FPE_DENORMAL_BIT)
MOV D0Re0, #TXSTAT_FPE_INVALID_S
FFB D1Ar3, D1Ar3
CMP D1Ar3, #TXSTAT_FPE_INVALID_S
MOVLE D1Ar3, D0Re0 /* Collapse FPE triggers to a single signal */
ORGT D1Re0, D1Re0, #1
LSLGT D1Re0, D1Re0, D1Ar3
SUB D1Ar3, D1Ar3, #(TXSTAT_FPE_INVALID_S - TBID_SIGNUM_FPE)
/* Acknowledge triggers and restore remaining exceptions
* Do this here in case the handler enables nested interrupts
*
* (x | y) ^ y == x & ~y. It avoids the restrictive XOR ...,#-1 insn
* and is the same length
*/
MOV D0Re0, TXDEFR
OR D0Re0, D0Re0, D1Re0
XOR TXDEFR, D0Re0, D1Re0
/* Get the handler using the signal number
*
* D1Ar3 -- The signal number
* D0Re0 -- Address of handler
*/
LSL D0Re0, D1Ar3, #2
ADD D0Re0,D0Re0,#TBI_fnSigs
GETD D0Re0, [D0Ar6+D0Re0]
/* Tailcall the handler */
MOV PC,D0Re0
#endif /* META_BUG_MBN100212 */
.size ___TBIHandleDFR,.-___TBIHandleDFR
/*
* End of tbidefr.S
*/