From f9c780ccc146fd883374f8f89c14c9ce5968ee51 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Wed, 25 Feb 2004 13:00:36 +0000 Subject: The cli()/sti() functions are not safe. We should have removed them long ago. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4314 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/button.c | 5 +++-- firmware/drivers/lcd.c | 22 +++++++++++++--------- firmware/export/kernel.h | 1 - firmware/export/system.h | 29 ++++++++++------------------- firmware/kernel.c | 12 ------------ firmware/system.c | 14 +++++++++++++- 6 files changed, 39 insertions(+), 44 deletions(-) diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index 06c24e0e45..66c7e978fb 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -258,10 +258,11 @@ void button_set_flip(bool flip) { if (flip != flipped) /* not the curent setting */ { - cli(); /* avoid race condition with the button_tick() */ + /* avoid race condition with the button_tick() */ + int oldlevel = set_irq_level(15); lastbtn = button_flip(lastbtn); flipped = flip; - sti(); + set_irq_level(oldlevel); } } diff --git a/firmware/drivers/lcd.c b/firmware/drivers/lcd.c index 5c2c514f10..950f8b5057 100644 --- a/firmware/drivers/lcd.c +++ b/firmware/drivers/lcd.c @@ -188,14 +188,16 @@ void lcd_write_data(unsigned char* p_bytes, int count) { do { - unsigned byte; - unsigned sda1; /* precalculated SC=low,SD=1 */ - unsigned clk0sda0; /* precalculated SC and SD low */ + unsigned int byte; + unsigned int sda1; /* precalculated SC=low,SD=1 */ + unsigned int clk0sda0; /* precalculated SC and SD low */ + unsigned int oldlevel; byte = *p_bytes++ << 24; /* fetch to MSB position */ - cli(); /* make port modifications atomic, in case an IRQ uses PBDRL */ - /* (currently not the case, so this could be optimized away) */ + /* make port modifications atomic, in case an IRQ uses PBDRL */ + /* (currently not the case, so this could be optimized away) */ + oldlevel = set_irq_level(15); /* precalculate the values for later bit toggling, init data write */ asm ( @@ -285,7 +287,7 @@ void lcd_write_data(unsigned char* p_bytes, int count) : "r0" ); - sti(); + set_irq_level(oldlevel); } while (--count); /* tail loop is faster */ } @@ -298,13 +300,15 @@ void lcd_write_data(unsigned char* p_bytes, int count) { unsigned byte; unsigned sda1; /* precalculated SC=low,SD=1 */ + unsigned int oldlevel; /* take inverse data, so I can use the NEGC instruction below, it is the only carry add/sub which does not destroy a source register */ byte = ~(*p_bytes++ << 24); /* fetch to MSB position */ - cli(); /* make port modifications atomic, in case an IRQ uses PBDRL */ - /* (currently not the case, so this could be optimized away) */ + /* make port modifications atomic, in case an IRQ uses PBDRL */ + /* (currently not the case, so this could be optimized away) */ + oldlevel = set_irq_level(15); /* precalculate the values for later bit toggling, init data write */ asm ( @@ -386,7 +390,7 @@ void lcd_write_data(unsigned char* p_bytes, int count) "r0" ); - sti(); /* end of atomic port modifications */ + set_irq_level(oldlevel); } while (--count); /* tail loop is faster */ } diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 0f69f43ec0..6e11baedf6 100644 --- a/firmware/export/kernel.h +++ b/firmware/export/kernel.h @@ -64,7 +64,6 @@ extern long current_tick; extern void kernel_init(void); extern void yield(void); extern void sleep(int ticks); -int set_irq_level(int level); int tick_add_task(void (*f)(void)); int tick_remove_task(void (*f)(void)); diff --git a/firmware/export/system.h b/firmware/export/system.h index 01d2f130d3..5886145d7b 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h @@ -23,6 +23,10 @@ #include "sh7034.h" #include "config.h" +extern void system_reboot (void); +extern void system_init(void); +extern int set_irq_level(int level); + #define FREQ CPU_FREQ #define BAUDRATE 9600 @@ -113,47 +117,34 @@ static inline int tas (volatile int *pointer) return result; } -static inline void sti (void) - { - asm volatile ("ldc\t%0,sr" : : "r"(0<<4)); - } - -static inline void cli (void) - { - asm volatile ("ldc\t%0,sr" : : "r"(15<<4)); - } - /* Compare And Swap */ static inline int cas (volatile int *pointer,int requested_value,int new_value) { - cli(); + unsigned int oldlevel = set_irq_level(15); if (*pointer == requested_value) { *pointer = new_value; - sti (); + set_irq_level(oldlevel); return 1; } - sti (); + set_irq_level(oldlevel); return 0; } static inline int cas2 (volatile int *pointer1,volatile int *pointer2,int requested_value1,int requested_value2,int new_value1,int new_value2) { - cli(); + unsigned int oldlevel = set_irq_level(15); if (*pointer1 == requested_value1 && *pointer2 == requested_value2) { *pointer1 = new_value1; *pointer2 = new_value2; - sti (); + set_irq_level(oldlevel); return 1; } - sti (); + set_irq_level(oldlevel); return 0; } #endif -extern void system_reboot (void); -extern void system_init(void); - #endif diff --git a/firmware/kernel.c b/firmware/kernel.c index 3255ba0b20..1c37f004a4 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c @@ -70,18 +70,6 @@ void yield(void) wake_up_thread(); } -/**************************************************************************** - * Interrupt level setting - ****************************************************************************/ -int set_irq_level(int level) -{ - int i; - /* Read the old level and set the new one */ - asm volatile ("stc sr, %0" : "=r" (i)); - asm volatile ("ldc %0, sr" : : "r" (level << 4)); - return (i >> 4) & 0x0f; -} - /**************************************************************************** * Queue handling stuff ****************************************************************************/ diff --git a/firmware/system.c b/firmware/system.c index 87d3b9dc7d..3ec56f7c15 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -302,7 +302,7 @@ void (*vbr[]) (void) __attribute__ ((section (".vectors"))) = void system_reboot (void) { - cli (); + set_irq_level(15); asm volatile ("ldc\t%0,vbr" : : "r"(0)); @@ -318,6 +318,18 @@ void system_reboot (void) "r"(*(int*)0),"r"(4)); } +/**************************************************************************** + * Interrupt level setting + ****************************************************************************/ +int set_irq_level(int level) +{ + int i; + /* Read the old level and set the new one */ + asm volatile ("stc sr, %0" : "=r" (i)); + asm volatile ("ldc %0, sr" : : "r" (level << 4)); + return (i >> 4) & 0x0f; +} + void UIE (unsigned int pc) /* Unexpected Interrupt or Exception */ { bool state = true; -- cgit v1.2.3