summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2012-01-08 22:29:25 +0000
committerMichael Sevakis <jethead71@rockbox.org>2012-01-08 22:29:25 +0000
commit307cb049485cc20140b85aa78f8e2677e8df5851 (patch)
treeeaadfd7266e4e97e69bccd68655140dd9f1ef061 /firmware
parent5e21bbf5757163725f4bd2909fc7aaa548f61fc3 (diff)
downloadrockbox-307cb049485cc20140b85aa78f8e2677e8df5851.tar.gz
rockbox-307cb049485cc20140b85aa78f8e2677e8df5851.zip
AS3525v1/2: Enable nested handling of interrupts
Mostly for the sake of reducing latency for audio servicing where other service routines can take a long time to complete, leading to occasional drops of a few samples, especially in recording, where they are fairly frequent. One mystery that remains is GPIOA IRQ being interrupted causes strange undefined instruction exceptions, most easily produced on my Fuze V2 with a scrollwheel. Making GPIOA the top ISR for now, thus not interruptible, cures it. SVC mode is used during the actual calls. Hopefully the SVC stack size is sufficient. Prologue and epilogue code only uses the IRQ stack and is large enough. Any routine code that should not be interrupted should disable IRQ itself from here on in. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31642 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/kernel.c14
-rw-r--r--firmware/target/arm/as3525/fmradio-i2c-as3525.c2
-rw-r--r--firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c34
-rw-r--r--firmware/target/arm/as3525/sd-as3525.c6
-rw-r--r--firmware/target/arm/as3525/sd-as3525v2.c6
-rw-r--r--firmware/target/arm/as3525/system-as3525.c52
-rw-r--r--firmware/target/arm/crt0.S29
-rw-r--r--firmware/target/arm/system-arm.h10
8 files changed, 105 insertions, 48 deletions
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 155205749f..0b39e29126 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -1195,9 +1195,7 @@ int semaphore_wait(struct semaphore *s, int timeout)
1195 * in 'semaphore_init'. */ 1195 * in 'semaphore_init'. */
1196void semaphore_release(struct semaphore *s) 1196void semaphore_release(struct semaphore *s)
1197{ 1197{
1198#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval)
1199 unsigned int result = THREAD_NONE; 1198 unsigned int result = THREAD_NONE;
1200#endif
1201 int oldlevel; 1199 int oldlevel;
1202 1200
1203 oldlevel = disable_irq_save(); 1201 oldlevel = disable_irq_save();
@@ -1209,11 +1207,7 @@ void semaphore_release(struct semaphore *s)
1209 KERNEL_ASSERT(s->count == 0, 1207 KERNEL_ASSERT(s->count == 0,
1210 "semaphore_release->threads queued but count=%d!\n", s->count); 1208 "semaphore_release->threads queued but count=%d!\n", s->count);
1211 s->queue->retval = OBJ_WAIT_SUCCEEDED; /* indicate explicit wake */ 1209 s->queue->retval = OBJ_WAIT_SUCCEEDED; /* indicate explicit wake */
1212#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval)
1213 result = wakeup_thread(&s->queue); 1210 result = wakeup_thread(&s->queue);
1214#else
1215 wakeup_thread(&s->queue);
1216#endif
1217 } 1211 }
1218 else 1212 else
1219 { 1213 {
@@ -1228,11 +1222,11 @@ void semaphore_release(struct semaphore *s)
1228 corelock_unlock(&s->cl); 1222 corelock_unlock(&s->cl);
1229 restore_irq(oldlevel); 1223 restore_irq(oldlevel);
1230 1224
1231#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval) 1225#if defined(HAVE_PRIORITY_SCHEDULING) && defined(is_thread_context)
1232 /* No thread switch if IRQ disabled - it's probably called via ISR. 1226 /* No thread switch if not thread context */
1233 * switch_thread would as well enable them anyway. */ 1227 if((result & THREAD_SWITCH) && is_thread_context())
1234 if((result & THREAD_SWITCH) && irq_enabled_checkval(oldlevel))
1235 switch_thread(); 1228 switch_thread();
1236#endif 1229#endif
1230 (void)result;
1237} 1231}
1238#endif /* HAVE_SEMAPHORE_OBJECTS */ 1232#endif /* HAVE_SEMAPHORE_OBJECTS */
diff --git a/firmware/target/arm/as3525/fmradio-i2c-as3525.c b/firmware/target/arm/as3525/fmradio-i2c-as3525.c
index 3da42e31b2..5d05956799 100644
--- a/firmware/target/arm/as3525/fmradio-i2c-as3525.c
+++ b/firmware/target/arm/as3525/fmradio-i2c-as3525.c
@@ -195,8 +195,8 @@ void tuner_isr(void)
195 /* read and clear the interrupt */ 195 /* read and clear the interrupt */
196 if (GPIOA_MIS & (1<<4)) { 196 if (GPIOA_MIS & (1<<4)) {
197 semaphore_release(&rds_sema); 197 semaphore_release(&rds_sema);
198 GPIOA_IC = (1<<4);
198 } 199 }
199 GPIOA_IC = (1<<4);
200} 200}
201 201
202/* Captures RDS data and processes it */ 202/* Captures RDS data and processes it */
diff --git a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
index 7f82b692c7..8244c475fa 100644
--- a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
+++ b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
@@ -30,6 +30,7 @@ static bool hold_button = false;
30 30
31#ifdef HAVE_SCROLLWHEEL 31#ifdef HAVE_SCROLLWHEEL
32#define SCROLLWHEEL_BITS (1<<7|1<<6) 32#define SCROLLWHEEL_BITS (1<<7|1<<6)
33#define SCROLLWHEEL_BITS_POS 6
33 /* TIMER units */ 34 /* TIMER units */
34#define TIMER_TICK (KERNEL_TIMER_FREQ/HZ)/* how long a tick lasts */ 35#define TIMER_TICK (KERNEL_TIMER_FREQ/HZ)/* how long a tick lasts */
35#define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */ 36#define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */
@@ -78,10 +79,17 @@ static void scrollwheel(unsigned int wheel_value)
78 79
79 unsigned int btn = BUTTON_NONE; 80 unsigned int btn = BUTTON_NONE;
80 81
81 if (old_wheel_value == wheel_tbl[0][wheel_value]) 82 if (hold_button)
83 {
84 }
85 else if (old_wheel_value == wheel_tbl[0][wheel_value])
86 {
82 btn = BUTTON_SCROLL_FWD; 87 btn = BUTTON_SCROLL_FWD;
88 }
83 else if (old_wheel_value == wheel_tbl[1][wheel_value]) 89 else if (old_wheel_value == wheel_tbl[1][wheel_value])
90 {
84 btn = BUTTON_SCROLL_BACK; 91 btn = BUTTON_SCROLL_BACK;
92 }
85 93
86 if (btn == BUTTON_NONE) 94 if (btn == BUTTON_NONE)
87 { 95 {
@@ -200,11 +208,13 @@ void button_gpioa_isr(void)
200{ 208{
201#if defined(HAVE_SCROLLWHEEL) 209#if defined(HAVE_SCROLLWHEEL)
202 /* scroll wheel handling */ 210 /* scroll wheel handling */
203 if (GPIOA_MIS & SCROLLWHEEL_BITS) 211 unsigned long bits = GPIOA_MIS & SCROLLWHEEL_BITS;
204 scrollwheel(GPIOA_PIN_MASK(0xc0) >> 6);
205 212
206 /* ack interrupt */ 213 if (bits)
207 GPIOA_IC = SCROLLWHEEL_BITS; 214 {
215 scrollwheel(GPIOA_PIN_MASK(SCROLLWHEEL_BITS) >> SCROLLWHEEL_BITS_POS);
216 GPIOA_IC = bits; /* ack interrupt */
217 }
208#endif 218#endif
209} 219}
210 220
@@ -225,8 +235,10 @@ int button_read_device(void)
225 int delay = 30; 235 int delay = 30;
226 while(delay--) nop; 236 while(delay--) nop;
227 237
238 disable_irq();
239
228 bool ccu_io_bit12 = CCU_IO & (1<<12); 240 bool ccu_io_bit12 = CCU_IO & (1<<12);
229 bitclr32(&CCU_IO, 1<<12); 241 CCU_IO &= ~(1<<12);
230 242
231 /* B1 is shared with FM i2c */ 243 /* B1 is shared with FM i2c */
232 bool gpiob_pin0_dir = GPIOB_DIR & (1<<1); 244 bool gpiob_pin0_dir = GPIOB_DIR & (1<<1);
@@ -256,7 +268,9 @@ int button_read_device(void)
256 GPIOB_DIR |= 1<<1; 268 GPIOB_DIR |= 1<<1;
257 269
258 if(ccu_io_bit12) 270 if(ccu_io_bit12)
259 bitset32(&CCU_IO, 1<<12); 271 CCU_IO |= (1<<12);
272
273 enable_irq();
260 274
261#ifdef HAS_BUTTON_HOLD 275#ifdef HAS_BUTTON_HOLD
262#ifndef BOOTLOADER 276#ifndef BOOTLOADER
@@ -265,12 +279,6 @@ int button_read_device(void)
265 { 279 {
266 hold_button = hold; 280 hold_button = hold;
267 backlight_hold_changed(hold); 281 backlight_hold_changed(hold);
268 /* mask scrollwheel irq so we don't need to check for
269 * the hold button in the isr */
270 if (hold)
271 GPIOA_IE &= ~SCROLLWHEEL_BITS;
272 else
273 GPIOA_IE |= SCROLLWHEEL_BITS;
274 } 282 }
275#else 283#else
276 hold_button = hold; 284 hold_button = hold;
diff --git a/firmware/target/arm/as3525/sd-as3525.c b/firmware/target/arm/as3525/sd-as3525.c
index 17f1bfa11d..5bed36e51e 100644
--- a/firmware/target/arm/as3525/sd-as3525.c
+++ b/firmware/target/arm/as3525/sd-as3525.c
@@ -178,10 +178,12 @@ static int sd1_oneshot_callback(struct timeout *tmo)
178void sd_gpioa_isr(void) 178void sd_gpioa_isr(void)
179{ 179{
180 static struct timeout sd1_oneshot; 180 static struct timeout sd1_oneshot;
181
181 if (GPIOA_MIS & EXT_SD_BITS) 182 if (GPIOA_MIS & EXT_SD_BITS)
183 {
182 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); 184 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
183 /* acknowledge interrupt */ 185 GPIOA_IC = EXT_SD_BITS; /* acknowledge interrupt */
184 GPIOA_IC = EXT_SD_BITS; 186 }
185} 187}
186#endif /* HAVE_HOTSWAP */ 188#endif /* HAVE_HOTSWAP */
187 189
diff --git a/firmware/target/arm/as3525/sd-as3525v2.c b/firmware/target/arm/as3525/sd-as3525v2.c
index 717d5dd744..9edc598edf 100644
--- a/firmware/target/arm/as3525/sd-as3525v2.c
+++ b/firmware/target/arm/as3525/sd-as3525v2.c
@@ -1041,10 +1041,12 @@ static int sd1_oneshot_callback(struct timeout *tmo)
1041void sd_gpioa_isr(void) 1041void sd_gpioa_isr(void)
1042{ 1042{
1043 static struct timeout sd1_oneshot; 1043 static struct timeout sd1_oneshot;
1044
1044 if (GPIOA_MIS & EXT_SD_BITS) 1045 if (GPIOA_MIS & EXT_SD_BITS)
1046 {
1045 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); 1047 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
1046 /* acknowledge interrupt */ 1048 GPIOA_IC = EXT_SD_BITS; /* acknowledge interrupt */
1047 GPIOA_IC = EXT_SD_BITS; 1049 }
1048} 1050}
1049#endif /* HAVE_HOTSWAP */ 1051#endif /* HAVE_HOTSWAP */
1050 1052
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c
index 01aaeaccbe..f0ed75d2bd 100644
--- a/firmware/target/arm/as3525/system-as3525.c
+++ b/firmware/target/arm/as3525/system-as3525.c
@@ -51,7 +51,7 @@
51 extern __attribute__((weak,alias("UIRQ"))) void name (void) 51 extern __attribute__((weak,alias("UIRQ"))) void name (void)
52 52
53static void UIRQ (void) __attribute__((interrupt ("IRQ"))); 53static void UIRQ (void) __attribute__((interrupt ("IRQ")));
54void irq_handler(void) __attribute__((interrupt ("IRQ"))); 54void irq_handler(void) __attribute__((naked, interrupt ("IRQ")));
55void fiq_handler(void) __attribute__((interrupt ("FIQ"))); 55void fiq_handler(void) __attribute__((interrupt ("FIQ")));
56 56
57default_interrupt(INT_WATCHDOG); 57default_interrupt(INT_WATCHDOG);
@@ -121,6 +121,11 @@ static void UIRQ(void)
121static const struct { int source; void (*isr) (void); } vec_int_srcs[] = 121static const struct { int source; void (*isr) (void); } vec_int_srcs[] =
122{ 122{
123 /* Highest priority at the top of the list */ 123 /* Highest priority at the top of the list */
124#if defined(HAVE_HOTSWAP) || defined(HAVE_RDS_CAP) || \
125 (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING)
126 /* If GPIOA ISR is interrupted, things seem to go wonky ?? */
127 { INT_SRC_GPIOA, INT_GPIOA },
128#endif
124#ifdef HAVE_RECORDING 129#ifdef HAVE_RECORDING
125 { INT_SRC_I2SIN, INT_I2SIN }, /* For recording */ 130 { INT_SRC_I2SIN, INT_I2SIN }, /* For recording */
126#endif 131#endif
@@ -134,29 +139,26 @@ static const struct { int source; void (*isr) (void); } vec_int_srcs[] =
134 { INT_SRC_TIMER2, INT_TIMER2 }, 139 { INT_SRC_TIMER2, INT_TIMER2 },
135 { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO }, 140 { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO },
136 { INT_SRC_AUDIO, INT_AUDIO }, 141 { INT_SRC_AUDIO, INT_AUDIO },
137#if defined(HAVE_HOTSWAP) || \
138 (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING)
139 { INT_SRC_GPIOA, INT_GPIOA, },
140#endif
141 /* Lowest priority at the end of the list */ 142 /* Lowest priority at the end of the list */
142}; 143};
143 144
144static void setup_vic(void) 145static void setup_vic(void)
145{ 146{
146 const unsigned int n = sizeof(vec_int_srcs)/sizeof(vec_int_srcs[0]);
147 unsigned int i;
148
149 CGU_PERI |= CGU_VIC_CLOCK_ENABLE; /* enable VIC */ 147 CGU_PERI |= CGU_VIC_CLOCK_ENABLE; /* enable VIC */
150 VIC_INT_EN_CLEAR = 0xffffffff; /* disable all interrupt lines */ 148 VIC_INT_EN_CLEAR = 0xffffffff; /* disable all interrupt lines */
151 VIC_INT_SELECT = 0; /* only IRQ, no FIQ */ 149 VIC_INT_SELECT = 0; /* only IRQ, no FIQ */
152 150
153 *VIC_DEF_VECT_ADDR = UIRQ; 151 *VIC_DEF_VECT_ADDR = UIRQ;
154 152
155 for(i = 0; i < n; i++) 153 for(unsigned int i = 0; i < ARRAYLEN(vec_int_srcs); i++)
156 { 154 {
157 VIC_VECT_ADDRS[i] = vec_int_srcs[i].isr; 155 VIC_VECT_ADDRS[i] = vec_int_srcs[i].isr;
158 VIC_VECT_CNTLS[i] = (1<<5) | vec_int_srcs[i].source; 156 VIC_VECT_CNTLS[i] = (1<<5) | vec_int_srcs[i].source;
159 } 157 }
158
159 /* Reset priority hardware */
160 for(unsigned int i = 0; i < 32; i++)
161 *VIC_VECT_ADDR = 0;
160} 162}
161 163
162void INT_GPIOA(void) 164void INT_GPIOA(void)
@@ -177,8 +179,36 @@ void INT_GPIOA(void)
177 179
178void irq_handler(void) 180void irq_handler(void)
179{ 181{
180 (*VIC_VECT_ADDR)(); /* call the isr */ 182 /* Worst-case IRQ stack usage with 10 vectors:
181 *VIC_VECT_ADDR = (void*)VIC_VECT_ADDR; /* any write will ack the irq */ 183 * 10*4*10 = 400 bytes (100 words)
184 *
185 * No SVC stack is used by pro/epi-logue code
186 */
187 asm volatile (
188 "sub lr, lr, #4 \n" /* Create return address */
189 "stmfd sp!, { r0-r5, r12, lr } \n" /* Save what gets clobbered */
190 "ldr r0, =0xc6010030 \n" /* Obtain VIC address (before SPSR read!) */
191 "ldr r12, [r0] \n" /* Load Vector */
192 "mrs r1, spsr \n" /* Save SPSR_irq */
193 "stmfd sp!, { r0-r1 } \n" /* Must have something bet. mrs and msr */
194 "msr cpsr_c, #0x13 \n" /* Switch to SVC mode, enable IRQ */
195 "and r4, sp, #4 \n" /* Align SVC stack to 8 bytes, save */
196 "sub sp, sp, r4 \n"
197 "mov r5, lr \n" /* Save lr_SVC */
198#if ARM_ARCH >= 5
199 "blx r12 \n" /* Call handler */
200#else
201 "mov lr, pc \n"
202 "bx r12 \n"
203#endif
204 "add sp, sp, r4 \n" /* Undo alignment fudge */
205 "mov lr, r5 \n" /* Restore lr_SVC */
206 "msr cpsr_c, #0x92 \n" /* Mask IRQ, return to IRQ mode */
207 "ldmfd sp!, { r0-r1 } \n" /* Pop VIC address, SPSR_irq */
208 "str r0, [r0] \n" /* Ack end of ISR to VIC */
209 "msr spsr_cxsf, r1 \n" /* Restore SPSR_irq */
210 "ldmfd sp!, { r0-r5, r12, pc }^ \n" /* Restore regs, and RFE */
211 );
182} 212}
183 213
184void fiq_handler(void) 214void fiq_handler(void)
diff --git a/firmware/target/arm/crt0.S b/firmware/target/arm/crt0.S
index f75f37006d..7befecb593 100644
--- a/firmware/target/arm/crt0.S
+++ b/firmware/target/arm/crt0.S
@@ -100,17 +100,23 @@ newstart:
100 strhi r4, [r2], #4 100 strhi r4, [r2], #4
101 bhi 1b 101 bhi 1b
102 102
103 /* Set up stack for IRQ mode */ 103 /* Set up stack for IRQ mode */
104 msr cpsr_c, #0xd2 104 msr cpsr_c, #0xd2
105 ldr sp, =irq_stack 105 ldr sp, =irq_stack
106 106
107 /* Set up stack for FIQ mode */
108 msr cpsr_c, #0xd1
109 ldr sp, =fiq_stack
110
111 /* Let svc, abort and undefined modes use irq stack */
112 msr cpsr_c, #0xd3 107 msr cpsr_c, #0xd3
108#if CONFIG_CPU == AS3525 || CONFIG_CPU == AS3525v2
109 /* Let abort and undefined modes use irq stack */
110 /* svc stack is for interrupt processing */
111 ldr sp, =svc_stack
112#else
113 /* Let svc, abort and undefined modes use irq stack */
113 ldr sp, =irq_stack 114 ldr sp, =irq_stack
115
116 /* Set up stack for FIQ mode */
117 msr cpsr_c, #0xd1
118 ldr sp, =fiq_stack
119#endif
114 msr cpsr_c, #0xd7 120 msr cpsr_c, #0xd7
115 ldr sp, =irq_stack 121 ldr sp, =irq_stack
116 msr cpsr_c, #0xdb 122 msr cpsr_c, #0xdb
@@ -159,15 +165,20 @@ prefetch_abort_handler:
159 b UIE 165 b UIE
160 166
161data_abort_handler: 167data_abort_handler:
162 sub r0, lr, #8 168 sub r0, lr, #8
163 mov r1, #2 169 mov r1, #2
164 b UIE 170 b UIE
165 171
172/* Cache-align interrupt stacks */
173.balign 32
174
166/* 256 words of IRQ stack */ 175/* 256 words of IRQ stack */
167 .space 256*4 176 .space 256*4
168irq_stack: 177irq_stack:
169 178
170/* 256 words of FIQ stack */ 179/* 256 words of FIQ/SVC stack */
171 .space 256*4 180 .space 256*4
172fiq_stack: 181fiq_stack:
173end: 182svc_stack:
183
184end: \ No newline at end of file
diff --git a/firmware/target/arm/system-arm.h b/firmware/target/arm/system-arm.h
index b3630a8473..ffce77a176 100644
--- a/firmware/target/arm/system-arm.h
+++ b/firmware/target/arm/system-arm.h
@@ -76,6 +76,9 @@ void __div0(void);
76#define ints_enabled_checkval(val) \ 76#define ints_enabled_checkval(val) \
77 (((val) & IRQ_FIQ_STATUS) == 0) 77 (((val) & IRQ_FIQ_STATUS) == 0)
78 78
79/* We run in SYS mode */
80#define is_thread_context() \
81 (get_processor_mode() == 0x1f)
79 82
80/* Core-level interrupt masking */ 83/* Core-level interrupt masking */
81 84
@@ -109,6 +112,13 @@ static inline bool interrupt_enabled(int status)
109 return (cpsr & status) == 0; 112 return (cpsr & status) == 0;
110} 113}
111 114
115static inline unsigned long get_processor_mode(void)
116{
117 unsigned long cpsr;
118 asm ("mrs %0, cpsr" : "=r"(cpsr));
119 return cpsr & 0x1f;
120}
121
112/* ARM_ARCH version section for architecture*/ 122/* ARM_ARCH version section for architecture*/
113 123
114#if ARM_ARCH >= 6 124#if ARM_ARCH >= 6