sh: Cleanup and document register bank usage.
authorPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 07:01:12 +0000 (16:01 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 07:01:12 +0000 (16:01 +0900)
Initial register bank cleanup. Make SR.RB configurable, and add some
preliminary documentation on register bank usage within the kernel.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Documentation/sh/register-banks.txt [new file with mode: 0644]
include/asm-sh/system.h
include/asm-sh/thread_info.h

diff --git a/Documentation/sh/register-banks.txt b/Documentation/sh/register-banks.txt
new file mode 100644 (file)
index 0000000..a6719f2
--- /dev/null
@@ -0,0 +1,33 @@
+       Notes on register bank usage in the kernel
+       ==========================================
+
+Introduction
+------------
+
+The SH-3 and SH-4 CPU families traditionally include a single partial register
+bank (selected by SR.RB, only r0 ... r7 are banked), whereas other families
+may have more full-featured banking or simply no such capabilities at all.
+
+SR.RB banking
+-------------
+
+In the case of this type of banking, banked registers are mapped directly to
+r0 ... r7 if SR.RB is set to the bank we are interested in, otherwise ldc/stc
+can still be used to reference the banked registers (as r0_bank ... r7_bank)
+when in the context of another bank. The developer must keep the SR.RB value
+in mind when writing code that utilizes these banked registers, for obvious
+reasons. Userspace is also not able to poke at the bank1 values, so these can
+be used rather effectively as scratch registers by the kernel.
+
+Presently the kernel uses several of these registers.
+
+       - r0_bank, r1_bank (referenced as k0 and k1, used for scratch
+         registers when doing exception handling).
+       - r2_bank (used to track the EXPEVT/INTEVT code)
+               - Used by do_IRQ() and friends for doing irq mapping based off
+                 of the interrupt exception vector jump table offset
+       - r6_bank (global interrupt mask)
+               - The SR.IMASK interrupt handler makes use of this to set the
+                 interrupt priority level (used by local_irq_enable())
+       - r7_bank (current)
+
index 1630a54..198d17e 100644 (file)
@@ -136,7 +136,8 @@ extern void __xchg_called_with_bad_pointer(void);
 #define set_mb(var, value) do { xchg(&var, value); } while (0)
 
 /* Interrupt Control */
-static __inline__ void local_irq_enable(void)
+#ifdef CONFIG_CPU_HAS_SR_RB
+static inline void local_irq_enable(void)
 {
        unsigned long __dummy0, __dummy1;
 
@@ -149,6 +150,20 @@ static __inline__ void local_irq_enable(void)
                             : "1" (~0x000000f0)
                             : "memory");
 }
+#else
+static inline void local_irq_enable(void)
+{
+       unsigned long __dummy0, __dummy1;
+
+       __asm__ __volatile__ (
+               "stc    sr, %0\n\t"
+               "and    %1, %0\n\t"
+               "ldc    %0, sr\n\t"
+               : "=&r" (__dummy0), "=r" (__dummy1)
+               : "1" (~0x000000f0)
+               : "memory");
+}
+#endif
 
 static __inline__ void local_irq_disable(void)
 {
index 7345350..f64dd80 100644 (file)
@@ -48,16 +48,29 @@ struct thread_info {
 #define init_thread_info       (init_thread_union.thread_info)
 #define init_stack             (init_thread_union.stack)
 
+#define THREAD_SIZE (2*PAGE_SIZE)
+
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
        struct thread_info *ti;
+#ifdef CONFIG_CPU_HAS_SR_RB
        __asm__("stc    r7_bank, %0" : "=r" (ti));
+#else
+       unsigned long __dummy;
+
+       __asm__ __volatile__ (
+               "mov    r15, %0\n\t"
+               "and    %1, %0\n\t"
+               : "=&r" (ti), "=r" (__dummy)
+               : "1" (~(THREAD_SIZE - 1))
+               : "memory");
+#endif
+
        return ti;
 }
 
 /* thread information allocation */
-#define THREAD_SIZE (2*PAGE_SIZE)
 #define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
 #define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
 
@@ -65,7 +78,7 @@ static inline struct thread_info *current_thread_info(void)
 
 /* how to get the thread information struct from ASM */
 #define GET_THREAD_INFO(reg) \
-       stc     r7_bank, reg
+       stc     r7_bank, reg
 
 #endif