[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[microblaze-uclinux] [patch] msrset/msrclr support
Hi folks,
The latest version of the microblaze core in EDK6.2 SP1
(microblaze_v2_10_a) has optional support for a new pair of instructions:
msrset rd, IMM and msrclr rd, IMM
this pair of instructions are basically an atomic test-and-set on the
microblaze status register. We lobbied Xilinx to add these on the
grounds of the code size reduction:
mfs rd, rmsr
andi rd, rd, ~2
mts rmsr, rd
becomes
msrclr r0, ~2
to clear interrupts, and similarly for enable interrupts (and caches
too). Also you no longer need a scratch register when doing these
manipulations on the MSR.
Even better (well, in fact by design!), the msrclr instruction maps
directly onto the very common save_flags_cli() macro, that is sprinkled
liberally throughout the kernel and drivers.
The attached patch (David or Greg would you please apply?) adds optional
support for these new instructions. It is selectable from the
configuration menu (processor options, in kernel config).
Using this option saves roughly 15kbytes of code in a typical kernel
image, or about 1.5 percent. I expect there's a small performance
improvement as well, but haven't tried to measure it yet.
The only catch is that a gremlin in EDK6.2 (and also SP1 alas) means
that you have to twiddle your microblaze.mpd file to allow you to set
the C_USE_MSR_INSTR parameter. It's trivial:
edit
/edk6.2/hw/XilinxProcessorIPLib/pcores/microblaze_v2_10_a/data/microblaze_v2_1_0.mpd
add a new line (somewhere around line 50, among the other PARAMETER
declarations, doesn't matter):
PARAMETER C_USE_MSR_INSTR = 0, DT = integer
Finally, edit the system.mhs file of your favourite mbvanilla target,
and add the following in the microblaze_0 block:
PARAMETER C_USE_MSR_INSTR = 1
Enable support in the kernel as described above, make dep etc, and off
you go!
Congratulations if you are still reading! Any feedback welcome.
Cheers,
John
Index: include/asm-microblaze/system.h
===================================================================
RCS file: /var/cvs/uClinux-2.4.x/include/asm-microblaze/system.h,v
retrieving revision 1.5
diff -u -b -B -w -p -r1.5 system.h
--- include/asm-microblaze/system.h 10 Dec 2003 02:39:03 -0000 1.5
+++ include/asm-microblaze/system.h 18 May 2004 02:14:38 -0000
@@ -37,10 +37,46 @@ extern void *switch_thread (struct threa
} \
} while (0)
+#ifdef CONFIG_MICROBLAZE_MSRSETCLR
+/* the msrset/msrclr instructions are available, let's use them! */
/* Enable/disable interrupts. */
#define __sti() \
{ \
+ __asm__ __volatile__ ("msrset r0, 0x2;" \
+ : \
+ : \
+ : "memory"); \
+}
+
+#define __cli() \
+{ \
+ __asm__ __volatile__ ("msrclr r0, 0x2;" \
+ : \
+ : \
+ : "memory"); \
+}
+
+#define __save_flags_cli(flags) \
+{ \
+ __asm__ __volatile__ ("msrclr %0, 0x2;" \
+ : "=r" (flags) \
+ : \
+ : "memory"); \
+}
+
+#define __save_flags_sti(flags) \
+{ \
+ __asm__ __volatile__ ("msrset %0, 0x2;" \
+ : "=r" (flags) \
+ : \
+ : "memory"); \
+}
+
+#else /* MICROBLAZE_CONFIG_MSRSETCLR not set */
+/* Enable/disable interrupts. */
+#define __sti() \
+{ \
register unsigned tmp; \
__asm__ __volatile__ (" \
mfs %0, rmsr; \
@@ -63,11 +99,6 @@ extern void *switch_thread (struct threa
: "memory"); \
}
-#define __save_flags(flags) \
- __asm__ __volatile__ ("mfs %0, rmsr" : "=r" (flags))
-#define __restore_flags(flags) \
- __asm__ __volatile__ ("mts rmsr, %0" :: "r" (flags))
-
#define __save_flags_cli(flags) \
{ \
register unsigned tmp; \
@@ -91,6 +122,13 @@ extern void *switch_thread (struct threa
: \
: "memory"); \
}
+
+#endif
+
+#define __save_flags(flags) \
+ __asm__ __volatile__ ("mfs %0, rmsr" : "=r" (flags))
+#define __restore_flags(flags) \
+ __asm__ __volatile__ ("mts rmsr, %0" :: "r" (flags))
/* For spinlocks etc */
#define local_irq_save(flags) __save_flags_cli (flags)
Index: include/asm-microblaze/cache.h
===================================================================
RCS file: /var/cvs/uClinux-2.4.x/include/asm-microblaze/cache.h,v
retrieving revision 1.3
diff -u -b -B -w -p -r1.3 cache.h
--- include/asm-microblaze/cache.h 22 Sep 2003 04:34:25 -0000 1.3
+++ include/asm-microblaze/cache.h 18 May 2004 02:14:41 -0000
@@ -24,7 +24,23 @@
#define ICACHE_MSR_BIT (1 << 5)
#define DCACHE_MSR_BIT (1 << 7)
-#ifdef CONFIG_MICROBLAZE_ICACHE
+#ifdef CONFIG_MICROBLAZE_ICACHE /* Cache support? */
+
+#ifdef CONFIG_MICROBLAZE_MSRSETCLR
+#define __enable_icache() \
+ __asm__ __volatile__ (" msrset r0, %0;" \
+ : \
+ : "i" (ICACHE_MSR_BIT) \
+ : "memory")
+
+#define __disable_icache() \
+ __asm__ __volatile__ (" msrclr r0, %0;" \
+ : \
+ : "i" (ICACHE_MSR_BIT) \
+ : "memory")
+
+
+#else /* !CONFIG_MICROBLAZE_MSRSETCLR */
#define __enable_icache() \
__asm__ __volatile__ (" \
mfs r12, rmsr; \
@@ -44,6 +60,8 @@
: "memory", "r12")
+#endif /* CONFIG_MICROBLAZE_MSRSETCLR */
+
#define __invalidate_icache(addr) \
__asm__ __volatile__ (" \
wic %0, r0" \
@@ -56,6 +74,21 @@
#endif
#ifdef CONFIG_MICROBLAZE_DCACHE
+
+#ifdef CONFIG_MICROBLAZE_MSRSETCLR
+#define __enable_dcache() \
+ __asm__ __volatile__ (" msrset r0, %0;" \
+ : \
+ : "i" (DCACHE_MSR_BIT) \
+ : "memory")
+
+#define __disable_dcache() \
+ __asm__ __volatile__ (" msrclr r0, %0;" \
+ : \
+ : "i" (DCACHE_MSR_BIT) \
+ : "memory")
+
+#else /* !CONFIG_MICROBLAZE_MSRSETCLR */
#define __enable_dcache() \
__asm__ __volatile__ (" \
mfs r12, rmsr; \
@@ -73,6 +106,8 @@
: \
: "i" (DCACHE_MSR_BIT) \
: "memory", "r12")
+
+#endif /* CONFIG_MICROBLAZE_MSRSETCLR */
#define __invalidate_dcache(addr) \
__asm__ __volatile__ (" \
Index: arch/microblaze/kernel/entry.S
===================================================================
RCS file: /var/cvs/uClinux-2.4.x/arch/microblaze/kernel/entry.S,v
retrieving revision 1.7
diff -u -b -B -w -p -r1.7 entry.S
--- arch/microblaze/kernel/entry.S 4 Mar 2004 03:47:35 -0000 1.7
+++ arch/microblaze/kernel/entry.S 18 May 2004 02:14:51 -0000
@@ -31,6 +31,25 @@
/* The offset of the struct pt_regs in a `state save frame' on the stack. */
#define PTO STATE_SAVE_PT_OFFSET
+/* Standard way of enabling and disabling interrupts in entry.S */
+#ifdef CONFIG_MICROBLAZE_MSRSETCLR
+#define ENTRY_CLI(scratch_reg) \
+ msrclr scratch_reg, 0x2;
+
+#define ENTRY_EI(scratch_reg) \
+ msrset scratch_reg, 0x2;
+#else
+#define ENTRY_CLI(scratch_reg) \
+ mfs scratch_reg, rmsr; \
+ andi scratch_reg, scratch_reg, ~2; \
+ mts rmsr, scratch_reg;
+
+#define ENTRY_EI(scratch_reg) \
+ mfs scratch_reg, rmsr; \
+ ori scratch_reg, scratch_reg, 2; \
+ mts rmsr, scratch_reg;
+#endif
+
/* Standard macros to save and restore regs in the pt_regs struct pointed
to by the stack pointer (r1) */
#define SAVE_REG(reg_num) \
@@ -469,9 +488,7 @@
the C compiler are restored (that is, R1(sp), R2(gp), R15(lp), and
anything restored by EXTRA_STATE_RESTORER). */
#define RETURN(type) \
- mfs r11, rmsr; /* Disable interrupts */ \
- andi r11, r11, ~2; \
- mts rmsr, r11; \
+ ENTRY_CLI(r11); \
lwi r11, r1, PTO+PT_KERNEL_MODE; \
bnei r11, 2f; /* See if returning to kernel mode, */\
/* ... if so, skip resched &c. */ \
@@ -511,9 +528,7 @@
3: SAVE_EXTRA_STATE_FOR_FUNCALL(type); /* Prepare for funcall. */ \
bralid r15, CSYM(schedule); /* Call scheduler */ \
nop; /* delay slot */ \
- mfs r11, rmsr; /* The scheduler enables interrupts */ \
- andi r11, r11, ~2; \
- mts rmsr, r11; \
+ ENTRY_CLI(r11); /* The scheduler enables interrupts */ \
RESTORE_EXTRA_STATE_FOR_FUNCALL(type); \
brid 5b; /* Back to continue return processing */ \
nop; \
@@ -532,9 +547,7 @@
add r6, r0, r0; /* Arg 2: sigset_t *oldset */ \
bralid r15, CSYM(do_signal); /* Handle any signals */ \
nop; \
- mfs r11, rmsr; /* Sig handling enables interrupts */ \
- andi r11, r11, ~2; \
- mts rmsr, r11; \
+ ENTRY_CLI(r11); /* Sig handling enables interrupts */ \
RESTORE_EXTRA_STATE(type); /* Restore extra regs. */ \
brid 1b; \
nop;
@@ -584,16 +597,12 @@ CSYM(_shift_temp_loc):
* Return value in r3
*/
G_ENTRY(trap):
- mfs r11, rmsr; // disable interrupts
- andi r11, r11, ~2;
- mts rmsr, r11;
+ ENTRY_CLI(r11);
swi r1, r0, ENTRY_SP; // save stack (emulate v850)
SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers.
// No need to enable intrs here because microblaze
// traps just implemented as a branch, not a hardware trap
- mfs r11, rmsr; // Enable interrupts
- ori r11, r11, 2;
- mts rmsr, r11;
+ ENTRY_EI(r11);
la r15, r0, ret_from_trap-8// where the trap should return
// need -8 to adjust for rtsd r15, 8
@@ -813,10 +822,7 @@ END(nmi0)
G_ENTRY(illegal_instruction):
swi r1, r0, ENTRY_SP; // Save stack (emulate v850)
SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers.
- mfs r5, rmsr; // Enable interrupts
- ori r5, r5, 2;
- mts rmsr, r5;
-
+ ENTRY_EI(r11);
addi r5, r0, SIGILL; // Arg 0: signal number
RETRIEVE_CURRENT_TASK(r6); // Arg 1: task
la r15, r0, ret_from_irq-8 // where the handler should return
@@ -836,14 +842,10 @@ G_ENTRY(dbtrap):
rtbd r16, dbtrap_o;
nop;
dbtrap_o:
- mfs r11, rmsr; // disable interrupts
- andi r11, r11, ~2;
- mts rmsr, r11;
+ ENTRY_CLI(r11);
swi r1, r0, ENTRY_SP; // Save stack (emulate v850)
SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers.
- mfs r11, rmsr; // Enable interrupts
- ori r11, r11, 2;
- mts rmsr, r11;
+ ENTRY_EI(r11);
// Must insert code to detect illegal traps etc
Index: arch/microblaze/config.in
===================================================================
RCS file: /var/cvs/uClinux-2.4.x/arch/microblaze/config.in,v
retrieving revision 1.10
diff -u -b -B -w -p -r1.10 config.in
--- arch/microblaze/config.in 12 Mar 2004 05:27:26 -0000 1.10
+++ arch/microblaze/config.in 18 May 2004 02:14:52 -0000
@@ -51,6 +51,7 @@ mainmenu_option next_comment
#### Microblaze processor-specific config
#bool 'Reset Guard' CONFIG_RESET_GUARD
+ bool 'Use msrset/msrclr insns' CONFIG_MICROBLAZE_MSRSETCLR
bool 'Hardware Multiplier' CONFIG_MICROBLAZE_HARD_MULT
bool 'Hardware Divider' CONFIG_MICROBLAZE_HARD_DIV
bool 'Hardware Barrel Shift' CONFIG_MICROBLAZE_HARD_BARREL