[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