diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 5ad57eb0c8e1f3aff7d01abfad8ed2d16aedccb5..edbf3af85f57339a31238d9fb5be7ed104084b57 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -130,6 +130,12 @@ config SPARC_BOOTMEM_REQUEST_NEW_ON_DEMAND
 	 If unsure, say Y.
 endmenu
 
+config SPARC_NESTED_IRQ
+	bool "Allow nested IRQs"
+	default y
+	help
+	 Allow higher-priority interrupts to preempt interrupt service routines
+	 of lower priority interrupts. If unsure, say Y.
 
 
 endmenu
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index f1b0a439c9d2b88c4c571b8fb80d1edac94a71ce..f127144941f8a955d1444463c5bb888d074338f6 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -193,17 +193,12 @@ static inline unsigned long leon_get_fp(void)
 
 
 __attribute__((unused))
-#ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE
-#include <kernel/printk.h>
-#endif
 static inline void leon_reg_win_flush(void)
 {
-#ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE
-	pr_warn("NOT IMPLEMENTED: leon_reg_win_flush() %s:%d\n", __FILE__, __LINE__);
-#else
-	/* BCC/libgloss provide such functionality via SW trap 3 */
+	/* BCC/libgloss provide such functionality via SW trap 3, so does Linux
+	 * and now we do too...
+	 **/
 	__asm__ __volatile__("ta 3");
-#endif /* CONFIG_ARCH_CUSTOM_BOOT_CODE */
 }
 
 
diff --git a/arch/sparc/include/asm/ttable.h b/arch/sparc/include/asm/ttable.h
index 0700b14112a67cdbd69568a50822fb698c99af99..3f0b939b2fbe9de03c4826bf07eb633b1066b2ba 100644
--- a/arch/sparc/include/asm/ttable.h
+++ b/arch/sparc/include/asm/ttable.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _SPARC_HEAD_H
-#define _SPARC_HEAD_H
+#ifndef _SPARC_TTABLE_H
+#define _SPARC_TTABLE_H
 
 #define SPARC_TRAP_TFLT    0x1          /* Text fault */
 #define SPARC_TRAP_II      0x2          /* Illegal Instruction */
@@ -41,6 +41,13 @@
 
 
 #define PSR_PS	0x00000040         /* previous privilege level */
+#define PSR_S	0x00000080         /* enable supervisor */
+
+#define PSR_ET	0x00000020	   /* enable traps */
+#define PSR_EF	0x00001000         /* enable FPU */
+
+#define PSR_PIL	0x00000f00	/* processor interrupt level */
+#define PSR_PIL_SHIFT	 8	/* PIL field shift */
 
 
 #define TTBL_MASK	0xff0	/* trap type mask from tbr */
@@ -79,4 +86,20 @@
         rd %psr, %l0;
 
 
-#endif /* _SPARC_HEAD_H */
+/* This is the same convention as in leonbare and linux */
+/* All trap entry points _must_ begin with this macro or else you
+ * lose.  It makes sure the kernel has a proper window so that
+ * c-code can be called.
+ */
+#define SAVE_ALL_HEAD \
+	sethi	%hi(trap_setup), %l4; \
+	jmpl	%l4 + %lo(trap_setup), %l6;
+#define SAVE_ALL \
+	SAVE_ALL_HEAD \
+	 nop;
+
+/* All traps low-level code here must end with this macro. */
+#define RESTORE_ALL b ret_trap_entry; clr %l6;
+
+
+#endif /* _SPARC_TTABLE_H */
diff --git a/arch/sparc/include/asm/win.h b/arch/sparc/include/asm/win.h
index bf3ac94ec67c812f644929efd15ce5f97393772b..14d746081395dc206337a366add849865fdac927 100644
--- a/arch/sparc/include/asm/win.h
+++ b/arch/sparc/include/asm/win.h
@@ -44,4 +44,65 @@
 	std	%i6, [%reg + RW_I6];
 
 
+/* LOAD/STORE of trap frame */
+
+#define LOAD_PT_INS(base_reg) \
+        ldd     [%base_reg + STACKFRAME_SZ + PT_I0], %i0; \
+        ldd     [%base_reg + STACKFRAME_SZ + PT_I2], %i2; \
+        ldd     [%base_reg + STACKFRAME_SZ + PT_I4], %i4; \
+        ldd     [%base_reg + STACKFRAME_SZ + PT_I6], %i6;
+
+#define LOAD_PT_GLOBALS(base_reg) \
+        ld      [%base_reg + STACKFRAME_SZ + PT_G1], %g1; \
+        ldd     [%base_reg + STACKFRAME_SZ + PT_G2], %g2; \
+        ldd     [%base_reg + STACKFRAME_SZ + PT_G4], %g4; \
+        ldd     [%base_reg + STACKFRAME_SZ + PT_G6], %g6;
+
+#define LOAD_PT_YREG(base_reg, scratch) \
+        ld      [%base_reg + STACKFRAME_SZ + PT_Y], %scratch; \
+        wr      %scratch, 0x0, %y;
+
+#define LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \
+        ld      [%base_reg + STACKFRAME_SZ + PT_PSR], %pt_psr; \
+        ld      [%base_reg + STACKFRAME_SZ + PT_PC], %pt_pc; \
+        ld      [%base_reg + STACKFRAME_SZ + PT_NPC], %pt_npc;
+
+#define LOAD_PT_ALL(base_reg, pt_psr, pt_pc, pt_npc, scratch) \
+        LOAD_PT_YREG(base_reg, scratch) \
+        LOAD_PT_INS(base_reg) \
+        LOAD_PT_GLOBALS(base_reg) \
+        LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc)
+
+
+
+
+#define STORE_PT_INS(base_reg) \
+        std     %i0, [%base_reg + STACKFRAME_SZ + PT_I0]; \
+        std     %i2, [%base_reg + STACKFRAME_SZ + PT_I2]; \
+        std     %i4, [%base_reg + STACKFRAME_SZ + PT_I4]; \
+        std     %i6, [%base_reg + STACKFRAME_SZ + PT_I6];
+
+#define STORE_PT_GLOBALS(base_reg) \
+        st      %g1, [%base_reg + STACKFRAME_SZ + PT_G1]; \
+        std     %g2, [%base_reg + STACKFRAME_SZ + PT_G2]; \
+        std     %g4, [%base_reg + STACKFRAME_SZ + PT_G4]; \
+        std     %g6, [%base_reg + STACKFRAME_SZ + PT_G6];
+
+#define STORE_PT_YREG(base_reg, scratch) \
+        rd      %y, %scratch; \
+        st      %scratch, [%base_reg + STACKFRAME_SZ + PT_Y];
+
+#define STORE_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \
+        st      %pt_psr, [%base_reg + STACKFRAME_SZ + PT_PSR]; \
+        st      %pt_pc,  [%base_reg + STACKFRAME_SZ + PT_PC]; \
+        st      %pt_npc, [%base_reg + STACKFRAME_SZ + PT_NPC];
+
+#define STORE_PT_ALL(base_reg, reg_psr, reg_pc, reg_npc, g_scratch) \
+        STORE_PT_PRIV(base_reg, reg_psr, reg_pc, reg_npc) \
+        STORE_PT_GLOBALS(base_reg) \
+        STORE_PT_YREG(base_reg, g_scratch) \
+        STORE_PT_INS(base_reg)
+
+
+
 #endif /* _SPARC_WIN_H */
diff --git a/arch/sparc/include/stack.h b/arch/sparc/include/stack.h
index 51386c2aa5d190295984ef2fd731ba8d84a93583..c3038350191b9446c6f4f3dda535d1cf62edee37 100644
--- a/arch/sparc/include/stack.h
+++ b/arch/sparc/include/stack.h
@@ -1,9 +1,13 @@
 #ifndef _SPARC_STACK_H_
 #define _SPARC_STACK_H_
 
+#ifndef __ASSEMBLY__
 #include <kernel/types.h>
+#endif /* !(__ASSEMBLY__) */
+
 #include <asm/win.h>
 
+
 /* stack frame offsets */
 #define SF_L0     0x00
 #define SF_L1     0x04
@@ -75,16 +79,26 @@
 
 
 
+#define STACK_ALIGN 8
+#define STACKFRAME_SZ	96
+#define PTREG_SZ	80
 
+#ifndef __ASSEMBLY__
 
+/* SPARC v8 cpu registers not part of a regular stack frame that we need in
+ * a trap frame to store the state of the CPU at the time of the trap.
+ */
 struct pt_regs {
         uint32_t psr;
         uint32_t pc;
         uint32_t npc;
         uint32_t y;
-        uint32_t u_regs[16]; /* globals and ins */
+        uint32_t u_regs[16]; /* globals and outs */
 };
 
+compile_time_assert(sizeof(struct pt_regs) == PTREG_SZ,
+		    SPARC__CPU_REG_SIZE_INVALID);
+
 struct leon_reg_win {
         uint32_t locals[8];
         uint32_t ins[8];
@@ -102,13 +116,13 @@ struct sparc_stackf {
 	/* everyting allocated on the stack follows here */
 };
 
-
-#define STACKFRAME_SZ	sizeof(struct sparc_stackf)
-
-#define STACK_ALIGN 8
+compile_time_assert(sizeof(struct sparc_stackf) == STACKFRAME_SZ,
+		    SPARC__STACK_FRAME_SIZE_INVALID);
 
 
 int stack_migrate(void *sp, void *stack_top_new);
 
+#endif /* !(__ASSEMBLY__) */
+
 
 #endif /* _SPARC_STACK_H_ */
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 5cfce14d28ff8e86a4fdc8d6e1f9534a54884537..54ce8bb4ad74e4523d65fb6ecfed183834c85287 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -6,6 +6,10 @@ obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += ttable.o
 obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += head.o
 obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += win_uflow.o
 obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += win_oflow.o
+obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += flush_windows.o
+obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += etrap.o
+obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += rtrap.o
+obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += irqtrap.o
 
 obj-y += setup.o
 obj-y += init.o
diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S
new file mode 100644
index 0000000000000000000000000000000000000000..e40ee5e43f7c23ba14366d13f457d516988b5f68
--- /dev/null
+++ b/arch/sparc/kernel/etrap.S
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * etrap.S: Sparc trap window preparation for entry into the
+ *          Linux kernel.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+		 Armin Luntzer <armin.luntzer@univie.ac.at>
+ */
+
+#include <asm/ttable.h>
+#include <stack.h>
+
+
+#ifndef CONFIG_SPARC_CPU_REG_WINDOWS
+#define NWINDOWS 8
+#else
+#define NWINDOWS CONFIG_SPARC_CPU_REG_WINDOWS
+#endif /* CONFIG_SPARC_CPU_REG_WINDOWS */
+
+
+/* Registers to not touch at all. */
+#define t_psr        l0 /* Set by caller */
+#define t_pc         l1 /* Set by caller */
+#define t_npc        l2 /* Set by caller */
+#define t_wim        l3 /* Set by caller */
+#define t_twinmask   l4 /* Set at beginning of this entry routine. */
+#define t_kstack     l5 /* Set right before pt_regs frame is built */
+#define t_retpc      l6 /* If you change this, change winmacro.h header file */
+#define t_systable   l7 /* Never touch this, could be the syscall table ptr. */
+#define curptr       g6 /* Set after pt_regs frame is built */
+
+	.text
+	.align 4
+
+	.globl	trap_setup
+trap_setup:
+	/* Calculate mask of trap window.  See if from user
+	 * or kernel and branch conditionally.
+	 */
+	mov	1, %t_twinmask
+	andcc	%t_psr, PSR_PS, %g0		 ! fromsupv_p = (psr & PSR_PS)
+	be	trap_setup_from_user		 ! nope, from user mode
+	 sll	%t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
+
+	/* From kernel, allocate more kernel stack and
+	 * build a pt_regs trap frame.
+	 */
+	sub	%fp, (STACKFRAME_SZ + PTREG_SZ), %t_kstack
+	STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
+
+	/* See if we hit a window marked invalid, i.e. whether we have
+	 * overflowed/spilled as part of this trap
+	 */
+	andcc	%t_twinmask, %t_wim, %g0
+	bne	trap_setup_kernel_win_oflow	! window overflow 
+	 nop
+
+	/* Trap from kernel with a window available.
+	 * Just do it...
+	 */
+	jmpl	%t_retpc + 0x8, %g0	! return to caller
+	 mov	%t_kstack, %sp		! jump onto new stack
+
+
+trap_setup_kernel_win_oflow:
+	/* here we check whether there are user windows. this is not relevant
+	 * until we do a form of lazy context switching between kernel and
+	 * userspace */
+!	ld	[%curptr + TI_UWINMASK], %g1
+!	orcc	%g0, %g1, %g0
+!	bne	trap_setup_user_spill	! there are some user windows, yuck
+
+
+	/* We hit the invalid window (overflow), but there are no user windows,
+	 * so we do mostly the same thing as in __wim_overflow
+	 */
+
+	/*
+	 * First, we rotate the window invalid mask to the right by one and
+	 * to the left by (NWINDOWS - 1), then OR the results (which is done
+	 * implicitly in the WRPSR instruction), so our WIM rotates modulo
+	 * NWINDOWS just like the CWP in the PSR
+	 */
+
+	srl	%t_wim, 0x1, %g2
+	sll	%t_wim, (NWINDOWS - 1), %t_wim
+	or	%t_wim, %g2, %g2	! store new WIM globally
+	!and	%g2, ((1 << NWINDOWS) - 1), %g2 !not needed, we can always write set bits of unused windows to the wim
+
+
+	save			! move to window
+	wr	%g2, %g0, %wim 	! delayed-branch instruction
+				! delay cycles are covered in store block
+
+	STORE_WINDOW(sp)	! store kernel window to memory stack
+
+	restore			! return to trap window
+
+	jmpl	%t_retpc + 0x8, %g0	! return to caller
+	 mov	%t_kstack, %sp		! and onto new kernel stack
+
+
+trap_setup_user_spill:
+	ta 0	! not implemented, same stuff as in win_oflow.S
+trap_setup_from_user:
+	ta 0	! not implemented
diff --git a/arch/sparc/kernel/flush_windows.S b/arch/sparc/kernel/flush_windows.S
new file mode 100644
index 0000000000000000000000000000000000000000..8ed2fe6ef49c91c28213b9b8e1e308ec01fa0724
--- /dev/null
+++ b/arch/sparc/kernel/flush_windows.S
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef CONFIG_SPARC_CPU_REG_WINDOWS
+#define NWINDOWS 8
+#else
+#define NWINDOWS CONFIG_SPARC_CPU_REG_WINDOWS
+#endif /* CONFIG_SPARC_CPU_REG_WINDOWS */
+
+#include <asm/ttable.h>
+#include <stack.h>
+
+	.align	4
+	.globl	flush_windows
+
+flush_windows:
+	SAVE_ALL
+
+	wr	%l0, PSR_ET, %psr	! delayed-write instruction
+					! no nops needed, the following
+					! compare-and-branch fills all 3 slots
+
+	andcc	%l0, PSR_PS, %g0
+	be	flush_user_windows
+	 nop
+
+flush_windows_kernel_all:
+
+	.rept NWINDOWS
+	save	%sp, -STACKFRAME_SZ, %sp
+	.endr
+
+	.rept NWINDOWS
+	restore
+	.endr
+
+	b flush_windows_done
+	 nop
+
+
+flush_user_windows:
+
+	call	flush_windows_user
+	 nop
+
+
+flush_windows_done:
+	/* Advance over the trap instruction. */
+	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1
+	add	%l1, 0x4, %l2
+	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
+	st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
+
+	RESTORE_ALL
+
+
+
+	.align 4
+	.globl flush_windows_user
+flush_windows_user:
+
+	ta 0	! not implemented,
+
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index f513d8e275b664f9e0ac60a2ae2bbbe59a36f678..768586a28c05e16be8a555d2805727d1fb762533 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,5 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 
+#include <asm/ttable.h>
+
+
+/* It's actually possible to detect windows at runtime, but we don't
+ * care (yet), because this will probably never run on any !8-window SPARC
+ */
+
 #ifndef CONFIG_SPARC_CPU_REG_WINDOWS
 #define NWINDOWS 8
 #else
@@ -74,8 +81,7 @@ zero_bss:
 	 * See the SPARCv8 User Manual pp.28 for the other set bits
 	 */
 
-        sethi   %hi(0x00001fc0), %g1
-        or      %g1, %lo(0x00001fc0 | (NWINDOWS - 2)), %g1
+	set	(PSR_PS | PSR_S | PSR_PIL | PSR_EF) | (NWINDOWS - 2), %g1
         mov     %g1, %psr	! delayed-write instruction
 	nop
 
@@ -90,8 +96,11 @@ zero_bss:
         sub     %fp, 104, %sp	! create a new frame
 
         /* We have a stack now, so we can start handling traps. */
-	or	%g1, 0x00000020, %g1
+	or	%g1, PSR_ET, %g1
         mov     %g1, %psr ! delayed-write instruction
+	nop
+	nop
+	nop
 
 	call do_basic_setup
 	 nop
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 82d3729265f623df543489effd3ee98b2d8d6890..93e6f0ffd77e4bc919b50048a7ef05dfde875a79 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -264,11 +264,36 @@ static struct sobj_attribute *eirl_attributes[] = {
 
 
 #ifndef CONFIG_ARCH_CUSTOM_BOOT_CODE
+
 /* provided by BCC's libgloss  */
 extern int catch_interrupt (int func, int irq);
+extern unsigned int nestedirq;
+
 #endif /* CONFIG_ARCH_CUSTOM_BOOT_CODE */
 
 
+
+/**
+ * @brief enable all interrupts by clearing the PSR PIL field
+ */
+
+static void leon_irq_enable(void)
+{
+        unsigned long tmp;
+
+	__asm__ __volatile__(
+	     "rd     %%psr,%0    \n\t"
+	     "andn   %0, %1,%0   \n\t"
+	     "wr     %0, 0, %%psr\n\t"
+	     "nop\n"
+	     "nop\n"
+	     "nop\n"
+	     : "=&r" (tmp)
+	     : "i" (PSR_PIL)
+	     : "memory");
+}
+
+
 /**
  * @brief clear (acknowledge) a pending IRQ
  *
@@ -462,7 +487,7 @@ void leon_irq_queue_execute(void)
 
 
 /**
- * @brief he central interrupt handling routine
+ * @brief the central interrupt handling routine
  *
  * @param irq an interrupt number
  *
@@ -470,10 +495,9 @@ void leon_irq_queue_execute(void)
  *
  * @note handler return codes ignored for now
  *
- * XXX maybe we want to keep acking IRQs as in eirq_dispatch...
  */
-__attribute__((unused))
-static int leon_irq_dispatch(unsigned int irq)
+
+int leon_irq_dispatch(unsigned int irq)
 {
 	struct irl_vector_elem *p_elem;
 
@@ -631,8 +655,8 @@ int irl_register_handler(unsigned int irq,
 
 	/* here goes the call to whatever the low level handler is */
 #ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE
-	pr_warn("NOT IMPLEMENTED: catch_interrupt() %s:%d\n", __FILE__, __LINE__);
-	return -1;
+	/* call is part of IRQ trap entry in irqtrap.S */
+	return 0;
 #else
 	/* provided by BCC/libgloss */
 	return catch_interrupt(((int) leon_irq_dispatch), irq);
@@ -918,7 +942,8 @@ static void leon_setup_eirq(void)
 
 	leon_eirq = eirq;
 #ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE
-	pr_warn("NOT IMPLEMENTED: catch_interrupt() %s:%d\n", __FILE__, __LINE__);
+	BUG_ON(irl_register_handler(leon_eirq, ISR_PRIORITY_NOW,
+				    (irq_handler_t) leon_eirq_dispatch, NULL));
 #else
 	/* provided by BCC/libgloss */
 	BUG_ON(catch_interrupt((int) leon_eirq_dispatch, leon_eirq));
@@ -1076,6 +1101,22 @@ void leon_irq_init(void)
 
 	BUG_ON(irq_dispatch_init());
 
+#ifndef CONFIG_ARCH_CUSTOM_BOOT_CODE
+
+#ifdef CONFIG_SPARC_NESTED_IRQ
+	nestedirq = 1;
+#else /* !(CONFIG_SPARC_NESTED_IRQ) */
+	nestedirq = 0;
+#endif /* CONFIG_SPARC_NESTED_IRQ */
+
+#endif /* !(CONFIG_ARCH_CUSTOM_BOOT_CODE) */
+
+
+
+
 	/* set up extended interrupt controller if found */
 	leon_setup_eirq();
+
+	/* now set the PIL field to zero to enable all IRLs */
+	leon_irq_enable();
 }
diff --git a/arch/sparc/kernel/irqtrap.S b/arch/sparc/kernel/irqtrap.S
new file mode 100644
index 0000000000000000000000000000000000000000..739133d3d480af2ba2fdab936d391d244136bc2a
--- /dev/null
+++ b/arch/sparc/kernel/irqtrap.S
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <asm/ttable.h>
+#include <stack.h>
+
+
+/* don't touch these */
+#define t_psr        l0 /* set by trap entry */
+#define t_pc         l1
+#define t_npc        l2
+#define t_wim        l3 /* set by trap entry */
+#define t_tmp        l4
+#define t_irqlvl     l7 /* set by trap entry */
+
+
+
+
+	.align	4
+	.globl	__interrupt_entry
+
+__interrupt_entry:
+	SAVE_ALL
+
+#ifdef CONFIG_SPARC_NESTED_IRQ
+	/* The 4 bits of the PSR field set the level above which interrupts
+	 * may occur. If we want ISR preemption, we set the level according
+	 * to the IRQ number that occured...
+	 */
+
+	sll     %t_irqlvl, PSR_PIL_SHIFT, %g1	! shift into place
+	andn    %t_psr, PSR_PIL, %g2		! clear field
+	or      %g1, %g2, %g2			! set new level
+
+#else /* !(CONFIG_SPARC_NESTED_IRQ)
+	/* ... otherwise we just set it to max */
+
+	or      %t_psr, PSR_PIL, %g2
+
+#endif /* CONFIG_SPARC_NESTED_IRQ */
+	wr	%g2, PSR_ET, %psr	! traps are off at this point, so we
+	nop				! xor the bit in the new PSR to re-enable
+	nop				! this is delayed-write, we need only
+					! 2 nops before the call
+
+	mov	%t_irqlvl, %o0		! set arg 1: irq level
+					! nothing else for now
+
+	call	leon_irq_dispatch	! call high-level manager
+#ifndef CONFIG_SPARC_NESTED_IRQ
+	 nop
+#else /* CONFIG_SPARC_NESTED_IRQ */
+	 or %t_psr, PSR_PIL, %t_tmp
+
+	wr	%t_tmp, PSR_ET, %psr	! we can't be preemted here, so set PIL
+					! to max and xor ET to enable
+					! delayed-write; nops not needed if
+                                        ! RESTORE_ALL and rtrap.S is not touced
+#endif /* CONFIG_SPARC_NESTED_IRQ */
+
+	RESTORE_ALL
+
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
new file mode 100644
index 0000000000000000000000000000000000000000..196d68ea79a7bd904a1b3cfe3a07f9d6ca28cd31
--- /dev/null
+++ b/arch/sparc/kernel/rtrap.S
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * etrap.S: Sparc trap window preparation for entry into the
+ *          Linux kernel.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+		 Armin Luntzer <armin.luntzer@univie.ac.at>
+ */
+
+#include <asm/ttable.h>
+#include <stack.h>
+
+
+#ifndef CONFIG_SPARC_CPU_REG_WINDOWS
+#define NWINDOWS 8
+#else
+#define NWINDOWS CONFIG_SPARC_CPU_REG_WINDOWS
+#endif /* CONFIG_SPARC_CPU_REG_WINDOWS */
+
+
+/* Registers to not touch at all. */
+
+#define t_psr     l0
+#define t_pc      l1
+#define t_npc     l2
+#define t_wim     l3
+#define twin_tmp1 l4
+#define glob_tmp  g4
+#define curptr    g6
+
+
+	.globl	ret_trap_entry
+ret_trap_entry:
+
+
+ret_trap_kernel:
+	/* Will the rett land us in the invalid window? */
+	mov	2, %g1
+	sll	%g1, %t_psr, %g1
+	srl	%g1, NWINDOWS, %g2
+	or	%g1, %g2, %g1
+	rd	%wim, %g2
+	andcc	%g2, %g1, %g0
+	be	1f		! Nope, just return from the trap
+	 sll	%g2, 0x1, %g1
+
+	/* window would be invalid, apply rotated mask (same as in win_uflow) */
+	srl	%g2, (NWINDOWS - 1),  %g2
+	or	%g1, %g2, %g1
+
+	/* no need to mask unused bits here, the CPU ignores any unimplemented
+	 * windows
+	*/
+	wr	%g1, 0x0, %wim
+
+	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
+
+	restore
+	LOAD_WINDOW(sp)
+	b	2f
+	 save
+
+	/* Reload the entire frame in case this is from a
+	 * kernel system call or whatever...
+	 */
+1:
+	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
+2:
+	/* no syscall implemented yet */
+!	sethi	%hi(PSR_SYSCALL), %twin_tmp1
+!	andn	%t_psr, %twin_tmp1, %t_psr
+
+	wr	%t_psr, %g0, %psr ! restore PSR, delayed-write instruction
+	nop			  ! need 2 delays, rett modifies CWP
+        nop			  ! 3rd delay cycle is filled by jmp instr
+
+	jmp	%t_pc
+	rett	%t_npc
diff --git a/arch/sparc/kernel/ttable.S b/arch/sparc/kernel/ttable.S
index 04a319a89987110bb5d1f72fc0943f89f8001dad..6d8648114d08f2d9125812fe62177f72fde69217 100644
--- a/arch/sparc/kernel/ttable.S
+++ b/arch/sparc/kernel/ttable.S
@@ -87,7 +87,7 @@ trapbase_cpu0:
 	SYSCALL_TRAP		! 0x80 = SunOS syscall()
 	TRAP_EXCEPTION		! 0x81
 	TRAP_EXCEPTION		! 0x82
-	TRAP_EXCEPTION		! 0x83
+	TRAP_ENTRY(0x83, flush_windows) ! 0x83
 	TRAP_EXCEPTION		! 0x84
 	TRAP_EXCEPTION		! 0x85
 
@@ -113,10 +113,6 @@ trapbase_cpu1:
 
         .global  leonbare_trapsetup
 leonbare_trapsetup:
-	.global catch_interrupt
-catch_interrupt:
-	.global coldboot_reset
-coldboot_reset:
 	.global __exception_entry
 __exception_entry:
 	.global srmmu_fault
@@ -125,8 +121,6 @@ srmmu_fault:
 ill_instruction_trap_handler:
 	.global priv_instruction_trap_handler
 priv_instruction_trap_handler:
-
-
 	.global leonbare_trapreturn
 leonbare_trapreturn:
 	.global fpdis_trap_handler
@@ -147,16 +141,12 @@ cpex_trap_handler:
 fpe_trap_handler:
 	.global hw_div0_trap_handler
 hw_div0_trap_handler:
-	.global __interrupt_entry
-__interrupt_entry:
 	.global nmi_entry
 nmi_entry:
 	.global reg_access_trap_handler
 reg_access_trap_handler:
 	.global strchr
 strchr:
-	.global strtol
-strtol:
 	.global syscall_tbl
 syscall_tbl:
 	.global syscall_trap
diff --git a/arch/sparc/kernel/win_oflow.S b/arch/sparc/kernel/win_oflow.S
index 3cc7fce46db1d3e98732c62a8f39918eda9b7ec6..6d4f94dcb1b94a09dd98ca020d90be828c7a73e3 100644
--- a/arch/sparc/kernel/win_oflow.S
+++ b/arch/sparc/kernel/win_oflow.S
@@ -53,7 +53,6 @@ __wim_overflow:
         srl     %l3, 1, %l4
         sll     %l3, (NWINDOWS - 1), %g5
 	or	%l4, %g5, %g5	! store new WIM globally
-	!and	%g5, ((1 << NWINDOWS) - 1), %g5
 
 	/* At this point, we proceed depending on the state of the previous
 	 * supervisor (PS) bit. The condition code has been set by the trap