diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/app.lds | 13 | ||||
-rw-r--r-- | firmware/backlight.c | 1 | ||||
-rw-r--r-- | firmware/drivers/button.c | 4 | ||||
-rw-r--r-- | firmware/export/config.h | 8 | ||||
-rw-r--r-- | firmware/export/kernel.h | 8 | ||||
-rw-r--r-- | firmware/export/pp5020.h | 25 | ||||
-rw-r--r-- | firmware/export/thread.h | 57 | ||||
-rw-r--r-- | firmware/kernel.c | 136 | ||||
-rw-r--r-- | firmware/pcm_record.c | 1 | ||||
-rw-r--r-- | firmware/rolo.c | 36 | ||||
-rw-r--r-- | firmware/system.c | 4 | ||||
-rw-r--r-- | firmware/target/arm/crt0-pp.S | 196 | ||||
-rw-r--r-- | firmware/target/arm/system-pp502x.c | 54 | ||||
-rw-r--r-- | firmware/target/arm/system-target.h | 23 | ||||
-rw-r--r-- | firmware/thread.c | 504 | ||||
-rw-r--r-- | firmware/usb.c | 1 |
16 files changed, 573 insertions, 498 deletions
diff --git a/firmware/app.lds b/firmware/app.lds index 6c67a96481..8df9aaf8e3 100644 --- a/firmware/app.lds +++ b/firmware/app.lds | |||
@@ -197,6 +197,18 @@ SECTIONS | |||
197 | } > IRAM | 197 | } > IRAM |
198 | 198 | ||
199 | #ifdef CPU_PP | 199 | #ifdef CPU_PP |
200 | #if NUM_CORES > 1 | ||
201 | .idle_stacks : | ||
202 | { | ||
203 | *(.idle_stacks) | ||
204 | cpu_idlestackbegin = .; | ||
205 | . += 0x0080; | ||
206 | cpu_idlestackend = .; | ||
207 | cop_idlestackbegin = .; | ||
208 | . += 0x0080; | ||
209 | cop_idlestackend = .; | ||
210 | } > IRAM | ||
211 | #else | ||
200 | .cop_stack : | 212 | .cop_stack : |
201 | { | 213 | { |
202 | *(.cop_stack) | 214 | *(.cop_stack) |
@@ -205,6 +217,7 @@ SECTIONS | |||
205 | cop_stackend = .; | 217 | cop_stackend = .; |
206 | } > IRAM | 218 | } > IRAM |
207 | #endif | 219 | #endif |
220 | #endif | ||
208 | 221 | ||
209 | #else | 222 | #else |
210 | /* TRICK ALERT! We want 0x2000 bytes of stack, but we set the section | 223 | /* TRICK ALERT! We want 0x2000 bytes of stack, but we set the section |
diff --git a/firmware/backlight.c b/firmware/backlight.c index ca8ffd1847..a0d08f1e83 100644 --- a/firmware/backlight.c +++ b/firmware/backlight.c | |||
@@ -611,7 +611,6 @@ static void backlight_tick(void) | |||
611 | void backlight_init(void) | 611 | void backlight_init(void) |
612 | { | 612 | { |
613 | queue_init(&backlight_queue, true); | 613 | queue_init(&backlight_queue, true); |
614 | queue_set_irq_safe(&backlight_queue, true); | ||
615 | 614 | ||
616 | #ifndef SIMULATOR | 615 | #ifndef SIMULATOR |
617 | if (__backlight_init()) | 616 | if (__backlight_init()) |
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index 862b02dcb8..7ab78f6cb0 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c | |||
@@ -356,10 +356,6 @@ void button_init(void) | |||
356 | 356 | ||
357 | queue_init(&button_queue, true); | 357 | queue_init(&button_queue, true); |
358 | 358 | ||
359 | /* Enable less protection which would kill IRQ handler. Writing queue is | ||
360 | * no longer core-wise thread safe. */ | ||
361 | queue_set_irq_safe(&button_queue, true); | ||
362 | |||
363 | button_read(); | 359 | button_read(); |
364 | lastbtn = button_read(); | 360 | lastbtn = button_read(); |
365 | tick_add_task(button_tick); | 361 | tick_add_task(button_tick); |
diff --git a/firmware/export/config.h b/firmware/export/config.h index 40d1c168a3..9346abbdc9 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -372,10 +372,10 @@ | |||
372 | #define NOCACHEBSS_ATTR IBSS_ATTR | 372 | #define NOCACHEBSS_ATTR IBSS_ATTR |
373 | #define NOCACHEDATA_ATTR IDATA_ATTR | 373 | #define NOCACHEDATA_ATTR IDATA_ATTR |
374 | 374 | ||
375 | #define IF_COP(empty, x, y) , x, y | 375 | #define IF_COP(...) __VA_ARGS__ |
376 | 376 | ||
377 | /* Defines for inter-core messaging */ | 377 | #define IDLE_STACK_SIZE 0x80 |
378 | #define COP_REBOOT 1 | 378 | #define IDLE_STACK_WORDS 0x20 |
379 | 379 | ||
380 | #else | 380 | #else |
381 | #define NUM_CORES 1 | 381 | #define NUM_CORES 1 |
@@ -383,7 +383,7 @@ | |||
383 | #define NOCACHEBSS_ATTR | 383 | #define NOCACHEBSS_ATTR |
384 | #define NOCACHEDATA_ATTR | 384 | #define NOCACHEDATA_ATTR |
385 | 385 | ||
386 | #define IF_COP(empty, x, y) | 386 | #define IF_COP(...) |
387 | 387 | ||
388 | #endif /* Processor specific */ | 388 | #endif /* Processor specific */ |
389 | 389 | ||
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 50c9bdc0ae..8d7ca95184 100644 --- a/firmware/export/kernel.h +++ b/firmware/export/kernel.h | |||
@@ -94,9 +94,6 @@ struct event_queue | |||
94 | struct thread_entry *thread; | 94 | struct thread_entry *thread; |
95 | unsigned int read; | 95 | unsigned int read; |
96 | unsigned int write; | 96 | unsigned int write; |
97 | #if NUM_CORES > 1 | ||
98 | bool irq_safe; | ||
99 | #endif | ||
100 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | 97 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME |
101 | struct queue_sender_list *send; | 98 | struct queue_sender_list *send; |
102 | #endif | 99 | #endif |
@@ -153,11 +150,6 @@ void timeout_register(struct timeout *tmo, timeout_cb_type callback, | |||
153 | void timeout_cancel(struct timeout *tmo); | 150 | void timeout_cancel(struct timeout *tmo); |
154 | 151 | ||
155 | extern void queue_init(struct event_queue *q, bool register_queue); | 152 | extern void queue_init(struct event_queue *q, bool register_queue); |
156 | #if NUM_CORES > 1 | ||
157 | extern void queue_set_irq_safe(struct event_queue *q, bool state); | ||
158 | #else | ||
159 | #define queue_set_irq_safe(q,state) | ||
160 | #endif | ||
161 | extern void queue_delete(struct event_queue *q); | 153 | extern void queue_delete(struct event_queue *q); |
162 | extern void queue_wait(struct event_queue *q, struct event *ev); | 154 | extern void queue_wait(struct event_queue *q, struct event *ev); |
163 | extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); | 155 | extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); |
diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h index b2c7f4d0d2..5da2061798 100644 --- a/firmware/export/pp5020.h +++ b/firmware/export/pp5020.h | |||
@@ -118,18 +118,18 @@ | |||
118 | #define DEV_RS (*(volatile unsigned long *)(0x60006004)) | 118 | #define DEV_RS (*(volatile unsigned long *)(0x60006004)) |
119 | #define DEV_EN (*(volatile unsigned long *)(0x6000600c)) | 119 | #define DEV_EN (*(volatile unsigned long *)(0x6000600c)) |
120 | 120 | ||
121 | #define DEV_SYSTEM 0x4 | 121 | #define DEV_SYSTEM 0x00000004 |
122 | #define DEV_SER0 0x40 | 122 | #define DEV_SER0 0x00000040 |
123 | #define DEV_SER1 0x80 | 123 | #define DEV_SER1 0x00000080 |
124 | #define DEV_I2S 0x800 | 124 | #define DEV_I2S 0x00000800 |
125 | #define DEV_I2C 0x1000 | 125 | #define DEV_I2C 0x00001000 |
126 | #define DEV_ATA 0x4000 | 126 | #define DEV_ATA 0x00004000 |
127 | #define DEV_OPTO 0x10000 | 127 | #define DEV_OPTO 0x00010000 |
128 | #define DEV_PIEZO 0x10000 | 128 | #define DEV_PIEZO 0x00010000 |
129 | #define DEV_USB 0x400000 | 129 | #define DEV_USB 0x00400000 |
130 | #define DEV_FIREWIRE 0x800000 | 130 | #define DEV_FIREWIRE 0x00800000 |
131 | #define DEV_IDE0 0x2000000 | 131 | #define DEV_IDE0 0x02000000 |
132 | #define DEV_LCD 0x4000000 | 132 | #define DEV_LCD 0x04000000 |
133 | 133 | ||
134 | /* clock control */ | 134 | /* clock control */ |
135 | #define CLOCK_SOURCE (*(volatile unsigned long *)(0x60006020)) | 135 | #define CLOCK_SOURCE (*(volatile unsigned long *)(0x60006020)) |
@@ -174,6 +174,7 @@ | |||
174 | 174 | ||
175 | #define CACHE_DISABLE 0 | 175 | #define CACHE_DISABLE 0 |
176 | #define CACHE_ENABLE 1 | 176 | #define CACHE_ENABLE 1 |
177 | #define CACHE_RUN 2 | ||
177 | #define CACHE_INIT 4 | 178 | #define CACHE_INIT 4 |
178 | 179 | ||
179 | /* GPIO Ports */ | 180 | /* GPIO Ports */ |
diff --git a/firmware/export/thread.h b/firmware/export/thread.h index 19bf9e12fc..e16baa2256 100644 --- a/firmware/export/thread.h +++ b/firmware/export/thread.h | |||
@@ -50,32 +50,32 @@ | |||
50 | #ifndef SIMULATOR | 50 | #ifndef SIMULATOR |
51 | /* Need to keep structures inside the header file because debug_menu | 51 | /* Need to keep structures inside the header file because debug_menu |
52 | * needs them. */ | 52 | * needs them. */ |
53 | # ifdef CPU_COLDFIRE | 53 | #ifdef CPU_COLDFIRE |
54 | struct regs | 54 | struct regs |
55 | { | 55 | { |
56 | unsigned int macsr; /* EMAC status register */ | 56 | unsigned int macsr; /* 0 - EMAC status register */ |
57 | unsigned int d[6]; /* d2-d7 */ | 57 | unsigned int d[6]; /* 4-24 - d2-d7 */ |
58 | unsigned int a[5]; /* a2-a6 */ | 58 | unsigned int a[5]; /* 28-44 - a2-a6 */ |
59 | void *sp; /* Stack pointer (a7) */ | 59 | void *sp; /* 48 - Stack pointer (a7) */ |
60 | void *start; /* Thread start address, or NULL when started */ | 60 | void *start; /* 52 - Thread start address, or NULL when started */ |
61 | }; | 61 | } __attribute__((packed)); |
62 | # elif CONFIG_CPU == SH7034 | 62 | #elif CONFIG_CPU == SH7034 |
63 | struct regs | 63 | struct regs |
64 | { | 64 | { |
65 | unsigned int r[7]; /* Registers r8 thru r14 */ | 65 | unsigned int r[7]; /* 0-24 - Registers r8 thru r14 */ |
66 | void *sp; /* Stack pointer (r15) */ | 66 | void *sp; /* 28 - Stack pointer (r15) */ |
67 | void *pr; /* Procedure register */ | 67 | void *pr; /* 32 - Procedure register */ |
68 | void *start; /* Thread start address, or NULL when started */ | 68 | void *start; /* 36 - Thread start address, or NULL when started */ |
69 | }; | 69 | } __attribute__((packed)); |
70 | # elif defined(CPU_ARM) | 70 | #elif defined(CPU_ARM) |
71 | struct regs | 71 | struct regs |
72 | { | 72 | { |
73 | unsigned int r[8]; /* Registers r4-r11 */ | 73 | unsigned int r[8]; /* 0-28 - Registers r4-r11 */ |
74 | void *sp; /* Stack pointer (r13) */ | 74 | void *sp; /* 32 - Stack pointer (r13) */ |
75 | unsigned int lr; /* r14 (lr) */ | 75 | unsigned int lr; /* 36 - r14 (lr) */ |
76 | void *start; /* Thread start address, or NULL when started */ | 76 | void *start; /* 40 - Thread start address, or NULL when started */ |
77 | }; | 77 | } __attribute__((packed)); |
78 | # endif | 78 | #endif /* CONFIG_CPU */ |
79 | #else | 79 | #else |
80 | struct regs | 80 | struct regs |
81 | { | 81 | { |
@@ -140,9 +140,9 @@ struct core_entry { | |||
140 | }; | 140 | }; |
141 | 141 | ||
142 | #ifdef HAVE_PRIORITY_SCHEDULING | 142 | #ifdef HAVE_PRIORITY_SCHEDULING |
143 | #define IF_PRIO(empty, type) , type | 143 | #define IF_PRIO(...) __VA_ARGS__ |
144 | #else | 144 | #else |
145 | #define IF_PRIO(empty, type) | 145 | #define IF_PRIO(...) |
146 | #endif | 146 | #endif |
147 | 147 | ||
148 | /* PortalPlayer chips have 2 cores, therefore need atomic mutexes | 148 | /* PortalPlayer chips have 2 cores, therefore need atomic mutexes |
@@ -197,14 +197,6 @@ struct core_entry { | |||
197 | }) | 197 | }) |
198 | #endif | 198 | #endif |
199 | 199 | ||
200 | #if NUM_CORES > 1 | ||
201 | inline void lock_cores(void); | ||
202 | inline void unlock_cores(void); | ||
203 | #else | ||
204 | #define lock_cores(...) | ||
205 | #define unlock_cores(...) | ||
206 | #endif | ||
207 | |||
208 | struct thread_entry* | 200 | struct thread_entry* |
209 | create_thread(void (*function)(void), void* stack, int stack_size, | 201 | create_thread(void (*function)(void), void* stack, int stack_size, |
210 | const char *name IF_PRIO(, int priority) | 202 | const char *name IF_PRIO(, int priority) |
@@ -239,7 +231,12 @@ void priority_yield(void); | |||
239 | struct thread_entry * thread_get_current(void); | 231 | struct thread_entry * thread_get_current(void); |
240 | void init_threads(void); | 232 | void init_threads(void); |
241 | int thread_stack_usage(const struct thread_entry *thread); | 233 | int thread_stack_usage(const struct thread_entry *thread); |
234 | #if NUM_CORES > 1 | ||
235 | int idle_stack_usage(unsigned int core); | ||
236 | #endif | ||
242 | int thread_get_status(const struct thread_entry *thread); | 237 | int thread_get_status(const struct thread_entry *thread); |
238 | void thread_get_name(char *buffer, int size, | ||
239 | struct thread_entry *thread); | ||
243 | #ifdef RB_PROFILE | 240 | #ifdef RB_PROFILE |
244 | void profile_thread(void); | 241 | void profile_thread(void); |
245 | #endif | 242 | #endif |
diff --git a/firmware/kernel.c b/firmware/kernel.c index 11b10e287e..77b0c6ffef 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c | |||
@@ -46,16 +46,21 @@ void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR; | |||
46 | void kernel_init(void) | 46 | void kernel_init(void) |
47 | { | 47 | { |
48 | /* Init the threading API */ | 48 | /* Init the threading API */ |
49 | init_threads(); | 49 | #if NUM_CORES > 1 |
50 | 50 | if (CURRENT_CORE == COP) | |
51 | if(CURRENT_CORE == CPU) | ||
52 | { | 51 | { |
53 | memset(tick_funcs, 0, sizeof(tick_funcs)); | 52 | /* This enables the interrupt but it won't be active until |
54 | 53 | the timer is actually started and interrupts are unmasked */ | |
55 | num_queues = 0; | 54 | tick_start(1000/HZ); |
56 | memset(all_queues, 0, sizeof(all_queues)); | ||
57 | } | 55 | } |
56 | #endif | ||
57 | |||
58 | init_threads(); | ||
58 | 59 | ||
60 | /* No processor other than the CPU will proceed here */ | ||
61 | memset(tick_funcs, 0, sizeof(tick_funcs)); | ||
62 | num_queues = 0; | ||
63 | memset(all_queues, 0, sizeof(all_queues)); | ||
59 | tick_start(1000/HZ); | 64 | tick_start(1000/HZ); |
60 | } | 65 | } |
61 | 66 | ||
@@ -172,9 +177,6 @@ void queue_init(struct event_queue *q, bool register_queue) | |||
172 | q->read = 0; | 177 | q->read = 0; |
173 | q->write = 0; | 178 | q->write = 0; |
174 | q->thread = NULL; | 179 | q->thread = NULL; |
175 | #if NUM_CORES > 1 | ||
176 | q->irq_safe = false; | ||
177 | #endif | ||
178 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | 180 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME |
179 | q->send = NULL; /* No message sending by default */ | 181 | q->send = NULL; /* No message sending by default */ |
180 | #endif | 182 | #endif |
@@ -186,29 +188,12 @@ void queue_init(struct event_queue *q, bool register_queue) | |||
186 | } | 188 | } |
187 | } | 189 | } |
188 | 190 | ||
189 | #if NUM_CORES > 1 | ||
190 | /** | ||
191 | * If IRQ mode is enabled, some core-wise locking mechanisms are disabled | ||
192 | * causing accessing queue to be no longer thread safe from the other core. | ||
193 | * However, that locking mechanism would also kill IRQ handlers. | ||
194 | * | ||
195 | * @param q struct of an event_queue | ||
196 | * @param state enable/disable IRQ mode | ||
197 | * @default state disabled | ||
198 | */ | ||
199 | void queue_set_irq_safe(struct event_queue *q, bool state) | ||
200 | { | ||
201 | q->irq_safe = state; | ||
202 | } | ||
203 | #endif | ||
204 | |||
205 | void queue_delete(struct event_queue *q) | 191 | void queue_delete(struct event_queue *q) |
206 | { | 192 | { |
207 | int i; | 193 | int i; |
208 | bool found = false; | 194 | bool found = false; |
209 | 195 | ||
210 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 196 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
211 | lock_cores(); | ||
212 | 197 | ||
213 | /* Release theads waiting on queue */ | 198 | /* Release theads waiting on queue */ |
214 | wakeup_thread(&q->thread); | 199 | wakeup_thread(&q->thread); |
@@ -241,7 +226,6 @@ void queue_delete(struct event_queue *q) | |||
241 | num_queues--; | 226 | num_queues--; |
242 | } | 227 | } |
243 | 228 | ||
244 | unlock_cores(); | ||
245 | set_irq_level(oldlevel); | 229 | set_irq_level(oldlevel); |
246 | } | 230 | } |
247 | 231 | ||
@@ -251,13 +235,11 @@ void queue_wait(struct event_queue *q, struct event *ev) | |||
251 | unsigned int rd; | 235 | unsigned int rd; |
252 | 236 | ||
253 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 237 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
254 | lock_cores(); | ||
255 | 238 | ||
256 | if (q->read == q->write) | 239 | if (q->read == q->write) |
257 | { | 240 | { |
258 | set_irq_level_and_block_thread(&q->thread, oldlevel); | 241 | set_irq_level_and_block_thread(&q->thread, oldlevel); |
259 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 242 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
260 | lock_cores(); | ||
261 | } | 243 | } |
262 | 244 | ||
263 | rd = q->read++ & QUEUE_LENGTH_MASK; | 245 | rd = q->read++ & QUEUE_LENGTH_MASK; |
@@ -271,20 +253,17 @@ void queue_wait(struct event_queue *q, struct event *ev) | |||
271 | } | 253 | } |
272 | #endif | 254 | #endif |
273 | 255 | ||
274 | unlock_cores(); | ||
275 | set_irq_level(oldlevel); | 256 | set_irq_level(oldlevel); |
276 | } | 257 | } |
277 | 258 | ||
278 | void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) | 259 | void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) |
279 | { | 260 | { |
280 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 261 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
281 | lock_cores(); | ||
282 | 262 | ||
283 | if (q->read == q->write && ticks > 0) | 263 | if (q->read == q->write && ticks > 0) |
284 | { | 264 | { |
285 | set_irq_level_and_block_thread_w_tmo(&q->thread, ticks, oldlevel); | 265 | set_irq_level_and_block_thread_w_tmo(&q->thread, ticks, oldlevel); |
286 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 266 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
287 | lock_cores(); | ||
288 | } | 267 | } |
289 | 268 | ||
290 | if (q->read != q->write) | 269 | if (q->read != q->write) |
@@ -305,7 +284,6 @@ void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) | |||
305 | ev->id = SYS_TIMEOUT; | 284 | ev->id = SYS_TIMEOUT; |
306 | } | 285 | } |
307 | 286 | ||
308 | unlock_cores(); | ||
309 | set_irq_level(oldlevel); | 287 | set_irq_level(oldlevel); |
310 | } | 288 | } |
311 | 289 | ||
@@ -314,11 +292,6 @@ void queue_post(struct event_queue *q, long id, intptr_t data) | |||
314 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 292 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
315 | unsigned int wr; | 293 | unsigned int wr; |
316 | 294 | ||
317 | #if NUM_CORES > 1 | ||
318 | if (!q->irq_safe) | ||
319 | lock_cores(); | ||
320 | #endif | ||
321 | |||
322 | wr = q->write++ & QUEUE_LENGTH_MASK; | 295 | wr = q->write++ & QUEUE_LENGTH_MASK; |
323 | 296 | ||
324 | q->events[wr].id = id; | 297 | q->events[wr].id = id; |
@@ -338,10 +311,6 @@ void queue_post(struct event_queue *q, long id, intptr_t data) | |||
338 | #endif | 311 | #endif |
339 | 312 | ||
340 | wakeup_thread_irq_safe(&q->thread); | 313 | wakeup_thread_irq_safe(&q->thread); |
341 | #if NUM_CORES > 1 | ||
342 | if (!q->irq_safe) | ||
343 | unlock_cores(); | ||
344 | #endif | ||
345 | set_irq_level(oldlevel); | 314 | set_irq_level(oldlevel); |
346 | 315 | ||
347 | } | 316 | } |
@@ -355,8 +324,6 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data) | |||
355 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 324 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
356 | unsigned int wr; | 325 | unsigned int wr; |
357 | 326 | ||
358 | lock_cores(); | ||
359 | |||
360 | wr = q->write++ & QUEUE_LENGTH_MASK; | 327 | wr = q->write++ & QUEUE_LENGTH_MASK; |
361 | 328 | ||
362 | q->events[wr].id = id; | 329 | q->events[wr].id = id; |
@@ -379,7 +346,6 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data) | |||
379 | 346 | ||
380 | /* Function as queue_post if sending is not enabled */ | 347 | /* Function as queue_post if sending is not enabled */ |
381 | wakeup_thread(&q->thread); | 348 | wakeup_thread(&q->thread); |
382 | unlock_cores(); | ||
383 | set_irq_level(oldlevel); | 349 | set_irq_level(oldlevel); |
384 | 350 | ||
385 | return 0; | 351 | return 0; |
@@ -396,43 +362,23 @@ bool queue_in_queue_send(struct event_queue *q) | |||
396 | /* Replies with retval to any dequeued message sent with queue_send */ | 362 | /* Replies with retval to any dequeued message sent with queue_send */ |
397 | void queue_reply(struct event_queue *q, intptr_t retval) | 363 | void queue_reply(struct event_queue *q, intptr_t retval) |
398 | { | 364 | { |
399 | lock_cores(); | ||
400 | /* No IRQ lock here since IRQs cannot change this */ | 365 | /* No IRQ lock here since IRQs cannot change this */ |
401 | if(q->send && q->send->curr_sender) | 366 | if(q->send && q->send->curr_sender) |
402 | { | 367 | { |
403 | queue_release_sender(&q->send->curr_sender, retval); | 368 | queue_release_sender(&q->send->curr_sender, retval); |
404 | } | 369 | } |
405 | unlock_cores(); | ||
406 | } | 370 | } |
407 | #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ | 371 | #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ |
408 | 372 | ||
409 | bool queue_empty(const struct event_queue* q) | 373 | bool queue_empty(const struct event_queue* q) |
410 | { | 374 | { |
411 | bool is_empty; | 375 | return ( q->read == q->write ); |
412 | |||
413 | #if NUM_CORES > 1 | ||
414 | if (!q->irq_safe) | ||
415 | lock_cores(); | ||
416 | #endif | ||
417 | |||
418 | is_empty = ( q->read == q->write ); | ||
419 | #if NUM_CORES > 1 | ||
420 | if (!q->irq_safe) | ||
421 | unlock_cores(); | ||
422 | #endif | ||
423 | |||
424 | return is_empty; | ||
425 | } | 376 | } |
426 | 377 | ||
427 | void queue_clear(struct event_queue* q) | 378 | void queue_clear(struct event_queue* q) |
428 | { | 379 | { |
429 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 380 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
430 | 381 | ||
431 | #if NUM_CORES > 1 | ||
432 | if (!q->irq_safe) | ||
433 | lock_cores(); | ||
434 | #endif | ||
435 | |||
436 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | 382 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME |
437 | /* Release all thread waiting in the queue for a reply - | 383 | /* Release all thread waiting in the queue for a reply - |
438 | dequeued sent message will be handled by owning thread */ | 384 | dequeued sent message will be handled by owning thread */ |
@@ -442,11 +388,6 @@ void queue_clear(struct event_queue* q) | |||
442 | q->read = 0; | 388 | q->read = 0; |
443 | q->write = 0; | 389 | q->write = 0; |
444 | 390 | ||
445 | #if NUM_CORES > 1 | ||
446 | if (!q->irq_safe) | ||
447 | unlock_cores(); | ||
448 | #endif | ||
449 | |||
450 | set_irq_level(oldlevel); | 391 | set_irq_level(oldlevel); |
451 | } | 392 | } |
452 | 393 | ||
@@ -454,11 +395,6 @@ void queue_remove_from_head(struct event_queue *q, long id) | |||
454 | { | 395 | { |
455 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 396 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
456 | 397 | ||
457 | #if NUM_CORES > 1 | ||
458 | if (!q->irq_safe) | ||
459 | lock_cores(); | ||
460 | #endif | ||
461 | |||
462 | while(q->read != q->write) | 398 | while(q->read != q->write) |
463 | { | 399 | { |
464 | unsigned int rd = q->read & QUEUE_LENGTH_MASK; | 400 | unsigned int rd = q->read & QUEUE_LENGTH_MASK; |
@@ -483,11 +419,6 @@ void queue_remove_from_head(struct event_queue *q, long id) | |||
483 | q->read++; | 419 | q->read++; |
484 | } | 420 | } |
485 | 421 | ||
486 | #if NUM_CORES > 1 | ||
487 | if (!q->irq_safe) | ||
488 | unlock_cores(); | ||
489 | #endif | ||
490 | |||
491 | set_irq_level(oldlevel); | 422 | set_irq_level(oldlevel); |
492 | } | 423 | } |
493 | 424 | ||
@@ -499,24 +430,7 @@ void queue_remove_from_head(struct event_queue *q, long id) | |||
499 | */ | 430 | */ |
500 | int queue_count(const struct event_queue *q) | 431 | int queue_count(const struct event_queue *q) |
501 | { | 432 | { |
502 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 433 | return q->write - q->read; |
503 | int result; | ||
504 | |||
505 | #if NUM_CORES > 1 | ||
506 | if (!q->irq_safe) | ||
507 | lock_cores(); | ||
508 | #endif | ||
509 | |||
510 | result = q->write - q->read; | ||
511 | |||
512 | #if NUM_CORES > 1 | ||
513 | if (!q->irq_safe) | ||
514 | unlock_cores(); | ||
515 | #endif | ||
516 | |||
517 | set_irq_level(oldlevel); | ||
518 | |||
519 | return result; | ||
520 | } | 434 | } |
521 | 435 | ||
522 | int queue_broadcast(long id, intptr_t data) | 436 | int queue_broadcast(long id, intptr_t data) |
@@ -644,22 +558,22 @@ void TIMER1(void) | |||
644 | int i; | 558 | int i; |
645 | 559 | ||
646 | TIMER1_VAL; /* Read value to ack IRQ */ | 560 | TIMER1_VAL; /* Read value to ack IRQ */ |
647 | /* Run through the list of tick tasks (using main core) */ | 561 | |
648 | if (CURRENT_CORE == CPU) | 562 | /* Run through the list of tick tasks (using main core - |
563 | COP does not dispatch ticks to this subroutine) */ | ||
564 | for (i = 0;i < MAX_NUM_TICK_TASKS;i++) | ||
649 | { | 565 | { |
650 | for (i = 0;i < MAX_NUM_TICK_TASKS;i++) | 566 | if (tick_funcs[i]) |
651 | { | 567 | { |
652 | if (tick_funcs[i]) | 568 | tick_funcs[i](); |
653 | { | ||
654 | tick_funcs[i](); | ||
655 | } | ||
656 | } | 569 | } |
657 | |||
658 | current_tick++; | ||
659 | } | 570 | } |
571 | |||
572 | current_tick++; | ||
660 | } | 573 | } |
661 | #endif | 574 | #endif |
662 | 575 | ||
576 | /* Must be last function called init kernel/thread initialization */ | ||
663 | void tick_start(unsigned int interval_in_ms) | 577 | void tick_start(unsigned int interval_in_ms) |
664 | { | 578 | { |
665 | #ifndef BOOTLOADER | 579 | #ifndef BOOTLOADER |
@@ -922,14 +836,10 @@ void mutex_lock(struct mutex *m) | |||
922 | 836 | ||
923 | void mutex_unlock(struct mutex *m) | 837 | void mutex_unlock(struct mutex *m) |
924 | { | 838 | { |
925 | lock_cores(); | ||
926 | |||
927 | if (m->thread == NULL) | 839 | if (m->thread == NULL) |
928 | m->locked = 0; | 840 | m->locked = 0; |
929 | else | 841 | else |
930 | wakeup_thread(&m->thread); | 842 | wakeup_thread(&m->thread); |
931 | |||
932 | unlock_cores(); | ||
933 | } | 843 | } |
934 | 844 | ||
935 | void spinlock_lock(struct mutex *m) | 845 | void spinlock_lock(struct mutex *m) |
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 1430100a09..8a6b08ef62 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -428,7 +428,6 @@ unsigned long pcm_rec_sample_rate(void) | |||
428 | void pcm_rec_init(void) | 428 | void pcm_rec_init(void) |
429 | { | 429 | { |
430 | queue_init(&pcmrec_queue, true); | 430 | queue_init(&pcmrec_queue, true); |
431 | queue_set_irq_safe(&pcmrec_queue, true); | ||
432 | queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send); | 431 | queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send); |
433 | pcmrec_thread_p = | 432 | pcmrec_thread_p = |
434 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), | 433 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), |
diff --git a/firmware/rolo.c b/firmware/rolo.c index 7ff5195318..1e9fc45984 100644 --- a/firmware/rolo.c +++ b/firmware/rolo.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "config.h" | 20 | #include "config.h" |
21 | #include "lcd.h" | 21 | #include "lcd.h" |
22 | #include "lcd-remote.h" | 22 | #include "lcd-remote.h" |
23 | #include "thread.h" | ||
23 | #include "kernel.h" | 24 | #include "kernel.h" |
24 | #include "sprintf.h" | 25 | #include "sprintf.h" |
25 | #include "button.h" | 26 | #include "button.h" |
@@ -52,10 +53,24 @@ | |||
52 | 53 | ||
53 | volatile unsigned char IDATA_ATTR cpu_message = 0; | 54 | volatile unsigned char IDATA_ATTR cpu_message = 0; |
54 | volatile unsigned char IDATA_ATTR cpu_reply = 0; | 55 | volatile unsigned char IDATA_ATTR cpu_reply = 0; |
56 | #if NUM_CORES > 1 | ||
57 | extern int cop_idlestackbegin[]; | ||
58 | #endif | ||
55 | 59 | ||
56 | void rolo_restart_cop(void) ICODE_ATTR; | 60 | void rolo_restart_cop(void) ICODE_ATTR; |
57 | void rolo_restart_cop(void) | 61 | void rolo_restart_cop(void) |
58 | { | 62 | { |
63 | if (CURRENT_CORE == CPU) | ||
64 | { | ||
65 | /* There should be free thread slots aplenty */ | ||
66 | create_thread(rolo_restart_cop, cop_idlestackbegin, IDLE_STACK_SIZE, | ||
67 | "rolo COP" IF_PRIO(, PRIORITY_REALTIME) | ||
68 | IF_COP(, COP, false)); | ||
69 | return; | ||
70 | } | ||
71 | |||
72 | COP_INT_CLR = -1; | ||
73 | |||
59 | /* Invalidate cache */ | 74 | /* Invalidate cache */ |
60 | invalidate_icache(); | 75 | invalidate_icache(); |
61 | 76 | ||
@@ -63,14 +78,14 @@ void rolo_restart_cop(void) | |||
63 | CACHE_CTL = CACHE_DISABLE; | 78 | CACHE_CTL = CACHE_DISABLE; |
64 | 79 | ||
65 | /* Tell the main core that we're ready to reload */ | 80 | /* Tell the main core that we're ready to reload */ |
66 | cpu_reply = 2; | 81 | cpu_reply = 1; |
67 | 82 | ||
68 | /* Wait while RoLo loads the image into SDRAM */ | 83 | /* Wait while RoLo loads the image into SDRAM */ |
69 | /* TODO: Accept checksum failure gracefully */ | 84 | /* TODO: Accept checksum failure gracefully */ |
70 | while(cpu_message == 1) {} | 85 | while(cpu_message != 1); |
71 | 86 | ||
72 | /* Acknowledge the CPU and then reload */ | 87 | /* Acknowledge the CPU and then reload */ |
73 | cpu_reply = 1; | 88 | cpu_reply = 2; |
74 | 89 | ||
75 | asm volatile( | 90 | asm volatile( |
76 | "mov r0, #0x10000000 \n" | 91 | "mov r0, #0x10000000 \n" |
@@ -127,9 +142,7 @@ void rolo_restart(const unsigned char* source, unsigned char* dest, | |||
127 | : : "a"(dest) | 142 | : : "a"(dest) |
128 | ); | 143 | ); |
129 | #elif defined(CPU_PP502x) | 144 | #elif defined(CPU_PP502x) |
130 | 145 | CPU_INT_CLR = -1; | |
131 | /* Tell the COP that we've finished loading and started rebooting */ | ||
132 | cpu_message = 0; | ||
133 | 146 | ||
134 | /* Flush cache */ | 147 | /* Flush cache */ |
135 | flush_icache(); | 148 | flush_icache(); |
@@ -141,8 +154,11 @@ void rolo_restart(const unsigned char* source, unsigned char* dest, | |||
141 | for (i=0;i<8;i++) | 154 | for (i=0;i<8;i++) |
142 | memmapregs[i]=0; | 155 | memmapregs[i]=0; |
143 | 156 | ||
157 | /* Tell the COP it's safe to continue rebooting */ | ||
158 | cpu_message = 1; | ||
159 | |||
144 | /* Wait for the COP to tell us it is rebooting */ | 160 | /* Wait for the COP to tell us it is rebooting */ |
145 | while(cpu_reply != 1) {} | 161 | while(cpu_reply != 2); |
146 | 162 | ||
147 | asm volatile( | 163 | asm volatile( |
148 | "mov r0, #0x10000000 \n" | 164 | "mov r0, #0x10000000 \n" |
@@ -211,11 +227,11 @@ int rolo_load(const char* filename) | |||
211 | #endif | 227 | #endif |
212 | 228 | ||
213 | #ifdef CPU_PP | 229 | #ifdef CPU_PP |
214 | cpu_message = COP_REBOOT; | ||
215 | COP_CTL = PROC_WAKE; | ||
216 | lcd_puts(0, 2, "Waiting for coprocessor..."); | 230 | lcd_puts(0, 2, "Waiting for coprocessor..."); |
217 | lcd_update(); | 231 | lcd_update(); |
218 | while(cpu_reply != 2) {} | 232 | rolo_restart_cop(); |
233 | /* Wait for COP to be in safe code */ | ||
234 | while(cpu_reply != 1); | ||
219 | lcd_puts(0, 2, " "); | 235 | lcd_puts(0, 2, " "); |
220 | lcd_update(); | 236 | lcd_update(); |
221 | #endif | 237 | #endif |
diff --git a/firmware/system.c b/firmware/system.c index 3fcf37d297..6ff0dbb5d1 100644 --- a/firmware/system.c +++ b/firmware/system.c | |||
@@ -179,6 +179,7 @@ static const char* const uiename[] = { | |||
179 | /* Unexpected Interrupt or Exception handler. Currently only deals with | 179 | /* Unexpected Interrupt or Exception handler. Currently only deals with |
180 | exceptions, but will deal with interrupts later. | 180 | exceptions, but will deal with interrupts later. |
181 | */ | 181 | */ |
182 | void UIE(unsigned int pc, unsigned int num) __attribute__((noreturn)); | ||
182 | void UIE(unsigned int pc, unsigned int num) | 183 | void UIE(unsigned int pc, unsigned int num) |
183 | { | 184 | { |
184 | char str[32]; | 185 | char str[32]; |
@@ -188,7 +189,8 @@ void UIE(unsigned int pc, unsigned int num) | |||
188 | lcd_setfont(FONT_SYSFIXED); | 189 | lcd_setfont(FONT_SYSFIXED); |
189 | #endif | 190 | #endif |
190 | lcd_puts(0, 0, uiename[num]); | 191 | lcd_puts(0, 0, uiename[num]); |
191 | snprintf(str, sizeof(str), "at %08x", pc); | 192 | snprintf(str, sizeof(str), "at %08x" IF_COP(" (%d)"), pc |
193 | IF_COP(, CURRENT_CORE)); | ||
192 | lcd_puts(0, 1, str); | 194 | lcd_puts(0, 1, str); |
193 | lcd_update(); | 195 | lcd_update(); |
194 | 196 | ||
diff --git a/firmware/target/arm/crt0-pp.S b/firmware/target/arm/crt0-pp.S index c1ced11cec..971b9e0ac5 100644 --- a/firmware/target/arm/crt0-pp.S +++ b/firmware/target/arm/crt0-pp.S | |||
@@ -34,6 +34,7 @@ start: | |||
34 | #if CONFIG_CPU == PP5002 | 34 | #if CONFIG_CPU == PP5002 |
35 | .equ PROC_ID, 0xc4000000 | 35 | .equ PROC_ID, 0xc4000000 |
36 | .equ CPU_ICLR, 0xcf001028 | 36 | .equ CPU_ICLR, 0xcf001028 |
37 | .equ CPU_CTRL, 0xcf004054 | ||
37 | .equ COP_ICLR, 0xcf001038 | 38 | .equ COP_ICLR, 0xcf001038 |
38 | .equ COP_CTRL, 0xcf004058 | 39 | .equ COP_CTRL, 0xcf004058 |
39 | .equ COP_STATUS, 0xcf004050 | 40 | .equ COP_STATUS, 0xcf004050 |
@@ -44,6 +45,8 @@ start: | |||
44 | #else | 45 | #else |
45 | .equ PROC_ID, 0x60000000 | 46 | .equ PROC_ID, 0x60000000 |
46 | .equ CPU_ICLR, 0x60004028 | 47 | .equ CPU_ICLR, 0x60004028 |
48 | .equ CPU_CTRL, 0x60007000 | ||
49 | .equ CPU_STATUS, 0x60007000 | ||
47 | .equ COP_ICLR, 0x60004038 | 50 | .equ COP_ICLR, 0x60004038 |
48 | .equ COP_CTRL, 0x60007004 | 51 | .equ COP_CTRL, 0x60007004 |
49 | .equ COP_STATUS, 0x60007004 | 52 | .equ COP_STATUS, 0x60007004 |
@@ -57,15 +60,16 @@ start: | |||
57 | msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ | 60 | msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ |
58 | b pad_skip | 61 | b pad_skip |
59 | 62 | ||
60 | .space 60*4 /* (more than enough) space for exception vectors and mi4 magic */ | 63 | .space 64*4 /* (more than enough) space for exception vectors and mi4 magic */ |
61 | 64 | ||
62 | pad_skip: | 65 | pad_skip: |
63 | #if defined(SANSA_E200) || defined(SANSA_C200) | 66 | /* Find out which processor we are - r0 should be preserved for the |
64 | /* On the Sansa, copying the vectors fails if the cache is initialised */ | 67 | * duration of the init to avoid constant reloading of the processor ID. |
65 | ldr r1, =CACHE_CTRL | 68 | * For each stage, CPU proceeds first, then COP. |
66 | mov r2, #0x0 | 69 | */ |
67 | str r2, [r1] | 70 | ldr r0, =PROC_ID |
68 | #endif | 71 | ldrb r0, [r0] |
72 | |||
69 | /* We need to remap memory from wherever SDRAM is mapped natively, to | 73 | /* We need to remap memory from wherever SDRAM is mapped natively, to |
70 | base address 0, so we can put our exception vectors there. We don't | 74 | base address 0, so we can put our exception vectors there. We don't |
71 | want to do this remapping while executing from SDRAM, so we copy the | 75 | want to do this remapping while executing from SDRAM, so we copy the |
@@ -73,70 +77,95 @@ pad_skip: | |||
73 | code is compiled for address 0, but is currently executing at either | 77 | code is compiled for address 0, but is currently executing at either |
74 | 0x28000000 or 0x10000000, depending on chipset version. Do not use any | 78 | 0x28000000 or 0x10000000, depending on chipset version. Do not use any |
75 | absolute addresses until remapping has been done. */ | 79 | absolute addresses until remapping has been done. */ |
76 | ldr r1, =0x40000000 | ||
77 | ldr r2, =remap_start | ||
78 | ldr r3, =remap_end | ||
79 | 80 | ||
80 | and r5, pc, #0xff000000 /* adjust for execute address */ | 81 | /* Cores are stepped though the init in turn: CPU then COP. The the remap |
81 | orr r2, r2, r5 | 82 | stage is completed by each core in turn and then the COP waits for the |
82 | orr r3, r3, r5 | 83 | CPU to finish initializing its kernel where the CPU will wake the COP |
84 | and wait for the COP to finish. This ensures no threading activity | ||
85 | starts until it is safe. */ | ||
86 | cmp r0, #0x55 | ||
87 | |||
88 | /* mask all interrupt sources before setting anything up */ | ||
89 | ldreq r2, =CPU_ICLR | ||
90 | ldrne r2, =COP_ICLR | ||
91 | mvn r1, #0 | ||
92 | str r1, [r2] | ||
93 | |||
94 | /* put us (co-processor) to sleep and wait for CPU to remap */ | ||
95 | ldrne r2, =COP_CTRL | ||
96 | movne r1, #SLEEP | ||
97 | strne r1, [r2] | ||
98 | |||
99 | /* wait for co-processor to sleep then CPU can begin its remapping */ | ||
100 | ldreq r2, =COP_STATUS | ||
101 | 1: | ||
102 | ldreq r1, [r2] | ||
103 | tsteq r1, #SLEEPING | ||
104 | beq 1b | ||
105 | |||
106 | #ifdef CPU_PP502x | ||
107 | /* disable cache and local interrupt vectors - it is really not desireable | ||
108 | to have them enabled here */ | ||
109 | ldr r2, =CACHE_CTRL | ||
110 | mov r1, #0 | ||
111 | str r1, [r2] | ||
112 | #endif | ||
113 | |||
114 | mov r2, #0x40000000 | ||
115 | ldr r3, =remap_start | ||
116 | ldr r4, =remap_end | ||
117 | |||
118 | and r6, pc, #0xff000000 /* adjust for execute address */ | ||
119 | orr r3, r3, r6 | ||
120 | orr r4, r4, r6 | ||
83 | 121 | ||
84 | /* copy the code to 0x40000000 */ | 122 | /* copy the code to 0x40000000 */ |
85 | 1: | 123 | 1: |
86 | ldr r4, [r2], #4 | 124 | ldr r5, [r3], #4 |
87 | str r4, [r1], #4 | 125 | str r5, [r2], #4 |
88 | cmp r2, r3 | 126 | cmp r3, r4 |
89 | ble 1b | 127 | blo 1b |
90 | 128 | ||
91 | ldr r3, =0x3f84 /* r3 and r1 values here are magic, don't touch */ | 129 | ldr r4, =0x3f84 /* r3 and r1 values here are magic, don't touch */ |
92 | orr r3, r3, r5 /* adjust for execute address */ | 130 | orr r4, r4, r6 /* adjust for execute address */ |
93 | ldr r2, =0xf000f014 | 131 | ldr r3, =0xf000f014 |
94 | #if MEM > 32 | 132 | #if MEM > 32 |
95 | mov r1, #0x7400 /* r1 appears to indicate how much memory (not in | 133 | mov r2, #0x7400 /* r1 appears to indicate how much memory (not in |
96 | bytes) is remapped */ | 134 | bytes) is remapped */ |
97 | #else | 135 | #else |
98 | mov r1, #0x3a00 | 136 | mov r2, #0x3a00 |
99 | #endif | 137 | #endif |
100 | ldr r0, =0xf000f010 | 138 | ldr r1, =0xf000f010 |
101 | mov pc, #0x40000000 | 139 | mov pc, #0x40000000 |
102 | 140 | ||
103 | remap_start: | 141 | remap_start: |
104 | str r1, [r0] | 142 | str r2, [r1] |
105 | str r3, [r2] | 143 | str r4, [r3] |
106 | ldr r0, L_post_remap | 144 | ldr r1, L_post_remap |
107 | mov pc, r0 | 145 | mov pc, r1 |
108 | L_post_remap: .word remap_end | 146 | L_post_remap: |
147 | .word remap_end | ||
109 | remap_end: | 148 | remap_end: |
110 | 149 | ||
111 | /* After doing the remapping, send the COP to sleep. | ||
112 | On wakeup it will go to cop_init */ | ||
113 | |||
114 | /* Find out which processor we are */ | ||
115 | ldr r0, =PROC_ID | ||
116 | ldrb r0, [r0] | ||
117 | cmp r0, #0x55 | 150 | cmp r0, #0x55 |
118 | 151 | ldr r4, =COP_CTRL | |
119 | /* Mask all interrupt sources before setting up modes */ | 152 | /* Wakeup co-processor to let it do remappings */ |
120 | ldreq r0, =CPU_ICLR | 153 | moveq r3, #WAKE |
121 | ldrne r0, =COP_ICLR | 154 | /* Sleep us (co-processor) and wait for CPU to do kernel initialization */ |
122 | mvn r1, #1 | ||
123 | str r1, [r0] | ||
124 | |||
125 | /* put us (co-processor) to sleep */ | ||
126 | ldrne r4, =COP_CTRL | ||
127 | movne r3, #SLEEP | 155 | movne r3, #SLEEP |
128 | strne r3, [r4] | 156 | str r3, [r4] |
129 | 157 | ||
158 | /* Jump to co-processor init */ | ||
130 | ldrne pc, =cop_init | 159 | ldrne pc, =cop_init |
131 | 160 | ||
132 | cpu_init: | 161 | cpu_init: |
133 | /* Wait for COP to be sleeping */ | 162 | /* Wait for COP to go to sleep before proceeding */ |
134 | ldr r4, =COP_STATUS | 163 | ldr r4, =COP_STATUS |
135 | 1: | 164 | 1: |
136 | ldr r3, [r4] | 165 | ldr r3, [r4] |
137 | tst r3, #SLEEPING | 166 | tst r3, #SLEEPING |
138 | beq 1b | 167 | beq 1b |
139 | 168 | ||
140 | /* Copy exception handler code to address 0 */ | 169 | /* Copy exception handler code to address 0 */ |
141 | ldr r2, =_vectorsstart | 170 | ldr r2, =_vectorsstart |
142 | ldr r3, =_vectorsend | 171 | ldr r3, =_vectorsend |
@@ -174,17 +203,28 @@ cpu_init: | |||
174 | cmp r3, r2 | 203 | cmp r3, r2 |
175 | strhi r4, [r2], #4 | 204 | strhi r4, [r2], #4 |
176 | bhi 1b | 205 | bhi 1b |
177 | 206 | ||
207 | /* Load stack munge value */ | ||
208 | ldr r4, =0xdeadbeef | ||
209 | |||
178 | /* Set up some stack and munge it with 0xdeadbeef */ | 210 | /* Set up some stack and munge it with 0xdeadbeef */ |
179 | ldr sp, =stackend | ||
180 | mov r3, sp | ||
181 | ldr r2, =stackbegin | 211 | ldr r2, =stackbegin |
182 | ldr r4, =0xdeadbeef | 212 | ldr sp, =stackend |
213 | 1: | ||
214 | cmp sp, r2 | ||
215 | strhi r4, [r2], #4 | ||
216 | bhi 1b | ||
217 | |||
218 | #if NUM_CORES > 1 | ||
219 | /* Set up idle stack and munge it with 0xdeadbeef */ | ||
220 | ldr r2, =cpu_idlestackbegin | ||
221 | ldr r3, =cpu_idlestackend | ||
183 | 1: | 222 | 1: |
184 | cmp r3, r2 | 223 | cmp r3, r2 |
185 | strhi r4, [r2], #4 | 224 | strhi r4, [r2], #4 |
186 | bhi 1b | 225 | bhi 1b |
187 | 226 | #endif | |
227 | |||
188 | /* Set up stack for IRQ mode */ | 228 | /* Set up stack for IRQ mode */ |
189 | msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */ | 229 | msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */ |
190 | ldr sp, =irq_stack | 230 | ldr sp, =irq_stack |
@@ -203,34 +243,41 @@ cpu_init: | |||
203 | msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ | 243 | msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ |
204 | ldr sp, =irq_stack | 244 | ldr sp, =irq_stack |
205 | 245 | ||
206 | /* Switch to supervisor mode */ | 246 | /* Switch back to supervisor mode */ |
207 | msr cpsr_c, #0xd3 | 247 | msr cpsr_c, #0xd3 |
208 | ldr sp, =stackend | 248 | |
249 | /* Delay waking the COP until thread initialization is complete unless dual-core | ||
250 | support is not enabled in which case the cop_main function does not perform | ||
251 | any kernel or thread initialization. It's just a trivial sleep loop. */ | ||
252 | #if NUM_CORES == 1 | ||
253 | ldr r4, =COP_CTRL | ||
254 | mov r3, #WAKE | ||
255 | str r3, [r4] | ||
256 | #endif | ||
257 | |||
209 | bl main | 258 | bl main |
210 | /* main() should never return */ | 259 | /* main() should never return */ |
211 | 260 | ||
212 | cop_init: | 261 | cop_init: |
213 | #if CONFIG_CPU != PP5002 | 262 | #if NUM_CORES > 1 |
214 | /* COP: Invalidate cache */ | 263 | /* Wait for CPU to go to sleep at the end of its kernel init */ |
215 | ldr r0, =0xf000f044 | 264 | ldr r4, =CPU_STATUS |
216 | ldr r1, [r0] | ||
217 | orr r1, r1, #0x6 | ||
218 | str r1, [r0] | ||
219 | |||
220 | ldr r0, =CACHE_CTRL | ||
221 | 1: | 265 | 1: |
222 | ldr r1, [r0] | 266 | ldr r3, [r4] |
223 | tst r1, #0x8000 | 267 | tst r3, #SLEEPING |
224 | bne 1b | 268 | beq 1b |
225 | #endif | ||
226 | 269 | ||
227 | /* Setup stack for COP */ | 270 | /* Set up idle stack for COP and munge it with 0xdeadbeef */ |
228 | ldr sp, =cop_stackend | 271 | ldr r2, =cop_idlestackbegin |
229 | mov r3, sp | 272 | ldr sp, =cop_idlestackend |
273 | #else | ||
274 | /* Setup stack for COP and munge it with 0xdeadbeef */ | ||
230 | ldr r2, =cop_stackbegin | 275 | ldr r2, =cop_stackbegin |
276 | ldr sp, =cop_stackend | ||
277 | #endif | ||
231 | ldr r4, =0xdeadbeef | 278 | ldr r4, =0xdeadbeef |
232 | 2: | 279 | 2: |
233 | cmp r3, r2 | 280 | cmp sp, r2 |
234 | strhi r4, [r2], #4 | 281 | strhi r4, [r2], #4 |
235 | bhi 2b | 282 | bhi 2b |
236 | 283 | ||
@@ -247,13 +294,12 @@ cop_init: | |||
247 | msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ | 294 | msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ |
248 | ldr sp, =cop_irq_stack | 295 | ldr sp, =cop_irq_stack |
249 | 296 | ||
250 | /* Switch to supervisor mode */ | 297 | /* Switch back to supervisor mode */ |
251 | msr cpsr_c, #0xd3 | 298 | msr cpsr_c, #0xd3 |
252 | ldr sp, =cop_stackend | ||
253 | 299 | ||
254 | /* Run cop_main() in apps/main.c */ | 300 | /* Run cop_main() in apps/main.c */ |
255 | bl cop_main | 301 | bl cop_main |
256 | 302 | ||
257 | /* Exception handlers. Will be copied to address 0 after memory remapping */ | 303 | /* Exception handlers. Will be copied to address 0 after memory remapping */ |
258 | .section .vectors,"aw" | 304 | .section .vectors,"aw" |
259 | ldr pc, [pc, #24] | 305 | ldr pc, [pc, #24] |
@@ -300,7 +346,6 @@ undef_instr_handler: | |||
300 | software_int_handler: | 346 | software_int_handler: |
301 | reserved_handler: | 347 | reserved_handler: |
302 | movs pc, lr | 348 | movs pc, lr |
303 | |||
304 | prefetch_abort_handler: | 349 | prefetch_abort_handler: |
305 | sub r0, lr, #4 | 350 | sub r0, lr, #4 |
306 | mov r1, #1 | 351 | mov r1, #1 |
@@ -324,6 +369,9 @@ UIE: | |||
324 | b UIE | 369 | b UIE |
325 | #endif | 370 | #endif |
326 | 371 | ||
372 | /* Align stacks to cache line boundary */ | ||
373 | .balign 16 | ||
374 | |||
327 | /* 256 words of IRQ stack */ | 375 | /* 256 words of IRQ stack */ |
328 | .space 256*4 | 376 | .space 256*4 |
329 | irq_stack: | 377 | irq_stack: |
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c index c84c9ce7a1..6f556c07cc 100644 --- a/firmware/target/arm/system-pp502x.c +++ b/firmware/target/arm/system-pp502x.c | |||
@@ -70,9 +70,7 @@ void irq(void) | |||
70 | } | 70 | } |
71 | #endif | 71 | #endif |
72 | } else { | 72 | } else { |
73 | if (COP_INT_STAT & TIMER1_MASK) | 73 | if (COP_INT_STAT & TIMER2_MASK) |
74 | TIMER1(); | ||
75 | else if (COP_INT_STAT & TIMER2_MASK) | ||
76 | TIMER2(); | 74 | TIMER2(); |
77 | } | 75 | } |
78 | } | 76 | } |
@@ -85,25 +83,49 @@ void irq(void) | |||
85 | to extend the funtions to do alternate cache configurations. */ | 83 | to extend the funtions to do alternate cache configurations. */ |
86 | 84 | ||
87 | #ifndef BOOTLOADER | 85 | #ifndef BOOTLOADER |
88 | static void ipod_init_cache(void) | 86 | void flush_icache(void) ICODE_ATTR; |
87 | void flush_icache(void) | ||
88 | { | ||
89 | if (CACHE_CTL & CACHE_ENABLE) | ||
90 | { | ||
91 | outl(inl(0xf000f044) | 0x2, 0xf000f044); | ||
92 | while ((CACHE_CTL & 0x8000) != 0); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | void invalidate_icache(void) ICODE_ATTR; | ||
97 | void invalidate_icache(void) | ||
98 | { | ||
99 | if (CACHE_CTL & CACHE_ENABLE) | ||
100 | { | ||
101 | unsigned i; | ||
102 | outl(inl(0xf000f044) | 0x6, 0xf000f044); | ||
103 | while ((CACHE_CTL & 0x8000) != 0); | ||
104 | for (i = 0x10000000; i < 0x10002000; i += 16) | ||
105 | inb(i); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static void init_cache(void) | ||
89 | { | 110 | { |
90 | /* Initialising the cache in the iPod bootloader prevents Rockbox from starting */ | 111 | /* Initialising the cache in the iPod bootloader prevents Rockbox from starting */ |
91 | unsigned i; | 112 | unsigned i; |
92 | 113 | ||
93 | /* cache init mode? */ | 114 | /* cache init mode? */ |
94 | CACHE_CTL = CACHE_INIT; | 115 | CACHE_CTL |= CACHE_INIT; |
95 | 116 | ||
96 | /* PP5002 has 8KB cache */ | 117 | /* what's this do? */ |
97 | for (i = 0xf0004000; i < 0xf0006000; i += 16) { | 118 | outl(inl(0x60006044) | (CURRENT_CORE == CPU ? 0x10 : 0x20), |
98 | outl(0x0, i); | 119 | 0x60006044); |
99 | } | ||
100 | 120 | ||
101 | outl(0x0, 0xf000f040); | 121 | outl(0xc00, 0xf000f040); |
102 | outl(0x3fc0, 0xf000f044); | 122 | outl(0xfc0, 0xf000f044); |
103 | 123 | ||
104 | /* enable cache */ | 124 | /* enable cache */ |
105 | CACHE_CTL = CACHE_ENABLE; | 125 | CACHE_CTL |= CACHE_INIT | CACHE_ENABLE | CACHE_RUN; |
106 | 126 | ||
127 | /* fill cache from physical address - do we have a better candidate for | ||
128 | an 8KB unchanging memory range? */ | ||
107 | for (i = 0x10000000; i < 0x10002000; i += 16) | 129 | for (i = 0x10000000; i < 0x10002000; i += 16) |
108 | inb(i); | 130 | inb(i); |
109 | } | 131 | } |
@@ -206,6 +228,12 @@ void system_init(void) | |||
206 | outl(0xffffffff, 0x60006008); | 228 | outl(0xffffffff, 0x60006008); |
207 | DEV_RS = 0; | 229 | DEV_RS = 0; |
208 | outl(0x00000000, 0x60006008); | 230 | outl(0x00000000, 0x60006008); |
231 | #elif defined (IRIVER_H10) | ||
232 | DEV_RS = 0x3ffffef8; | ||
233 | outl(0xffffffff, 0x60006008); | ||
234 | outl(inl(0x70000024) | 0xc0, 0x70000024); | ||
235 | DEV_RS = 0; | ||
236 | outl(0x00000000, 0x60006008); | ||
209 | #endif | 237 | #endif |
210 | /* Remap the flash ROM from 0x00000000 to 0x20000000. */ | 238 | /* Remap the flash ROM from 0x00000000 to 0x20000000. */ |
211 | MMAP3_LOGICAL = 0x20000000 | 0x3a00; | 239 | MMAP3_LOGICAL = 0x20000000 | 0x3a00; |
@@ -248,8 +276,8 @@ void system_init(void) | |||
248 | pp_set_cpu_frequency(CPUFREQ_MAX); | 276 | pp_set_cpu_frequency(CPUFREQ_MAX); |
249 | #endif | 277 | #endif |
250 | } | 278 | } |
251 | ipod_init_cache(); | ||
252 | 279 | ||
280 | init_cache(); | ||
253 | #endif /* BOOTLOADER */ | 281 | #endif /* BOOTLOADER */ |
254 | } | 282 | } |
255 | 283 | ||
diff --git a/firmware/target/arm/system-target.h b/firmware/target/arm/system-target.h index 7533f5da76..4811f7e2d6 100644 --- a/firmware/target/arm/system-target.h +++ b/firmware/target/arm/system-target.h | |||
@@ -70,29 +70,20 @@ static inline unsigned int current_core(void) | |||
70 | ); | 70 | ); |
71 | return core; | 71 | return core; |
72 | } | 72 | } |
73 | #else | ||
74 | unsigned int current_core(void); | ||
75 | #endif | ||
76 | 73 | ||
77 | #if CONFIG_CPU != PP5002 | 74 | #define CACHE_FUNCTIONS_AS_CALL |
78 | 75 | ||
79 | #define HAVE_INVALIDATE_ICACHE | 76 | #define HAVE_INVALIDATE_ICACHE |
80 | static inline void invalidate_icache(void) | 77 | void invalidate_icache(void); |
81 | { | ||
82 | outl(inl(0xf000f044) | 0x6, 0xf000f044); | ||
83 | while ((CACHE_CTL & 0x8000) != 0); | ||
84 | } | ||
85 | 78 | ||
86 | #define HAVE_FLUSH_ICACHE | 79 | #define HAVE_FLUSH_ICACHE |
87 | static inline void flush_icache(void) | 80 | void flush_icache(void); |
88 | { | ||
89 | outl(inl(0xf000f044) | 0x2, 0xf000f044); | ||
90 | while ((CACHE_CTL & 0x8000) != 0); | ||
91 | } | ||
92 | 81 | ||
93 | #endif /* CONFIG_CPU */ | ||
94 | #else | 82 | #else |
83 | unsigned int current_core(void); | ||
84 | #endif /* CPU_PP502x */ | ||
95 | 85 | ||
96 | #endif | 86 | |
87 | #endif /* CPU_PP */ | ||
97 | 88 | ||
98 | #endif /* SYSTEM_TARGET_H */ | 89 | #endif /* SYSTEM_TARGET_H */ |
diff --git a/firmware/thread.c b/firmware/thread.c index 86b90f4f0d..d0a0229430 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -45,59 +45,13 @@ static int boosted_threads IBSS_ATTR; | |||
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | /* Define to enable additional checks for blocking violations etc. */ | 47 | /* Define to enable additional checks for blocking violations etc. */ |
48 | #define THREAD_EXTRA_CHECKS | 48 | #define THREAD_EXTRA_CHECKS 0 |
49 | 49 | ||
50 | static const char main_thread_name[] = "main"; | 50 | static const char main_thread_name[] = "main"; |
51 | 51 | ||
52 | extern int stackbegin[]; | 52 | extern int stackbegin[]; |
53 | extern int stackend[]; | 53 | extern int stackend[]; |
54 | 54 | ||
55 | #ifdef CPU_PP | ||
56 | #ifndef BOOTLOADER | ||
57 | extern int cop_stackbegin[]; | ||
58 | extern int cop_stackend[]; | ||
59 | #else | ||
60 | /* The coprocessor stack is not set up in the bootloader code, but the threading | ||
61 | * is. No threads are run on the coprocessor, so set up some dummy stack */ | ||
62 | int *cop_stackbegin = stackbegin; | ||
63 | int *cop_stackend = stackend; | ||
64 | #endif | ||
65 | #endif | ||
66 | |||
67 | #if NUM_CORES > 1 | ||
68 | #if 0 | ||
69 | static long cores_locked IBSS_ATTR; | ||
70 | |||
71 | #define LOCK(...) do { } while (test_and_set(&cores_locked, 1)) | ||
72 | #define UNLOCK(...) cores_locked = 0 | ||
73 | #endif | ||
74 | |||
75 | /* #warning "Core locking mechanism should be fixed on H10/4G!" */ | ||
76 | |||
77 | inline void lock_cores(void) | ||
78 | { | ||
79 | #if 0 | ||
80 | if (!cores[CURRENT_CORE].lock_issued) | ||
81 | { | ||
82 | LOCK(); | ||
83 | cores[CURRENT_CORE].lock_issued = true; | ||
84 | } | ||
85 | #endif | ||
86 | } | ||
87 | |||
88 | inline void unlock_cores(void) | ||
89 | { | ||
90 | #if 0 | ||
91 | if (cores[CURRENT_CORE].lock_issued) | ||
92 | { | ||
93 | cores[CURRENT_CORE].lock_issued = false; | ||
94 | UNLOCK(); | ||
95 | } | ||
96 | #endif | ||
97 | } | ||
98 | |||
99 | #endif | ||
100 | |||
101 | /* Conserve IRAM | 55 | /* Conserve IRAM |
102 | static void add_to_list(struct thread_entry **list, | 56 | static void add_to_list(struct thread_entry **list, |
103 | struct thread_entry *thread) ICODE_ATTR; | 57 | struct thread_entry *thread) ICODE_ATTR; |
@@ -115,79 +69,115 @@ static inline void core_sleep(void) __attribute__((always_inline)); | |||
115 | 69 | ||
116 | #if defined(CPU_ARM) | 70 | #if defined(CPU_ARM) |
117 | /*--------------------------------------------------------------------------- | 71 | /*--------------------------------------------------------------------------- |
118 | * Store non-volatile context. | 72 | * Start the thread running and terminate it if it returns |
119 | *--------------------------------------------------------------------------- | 73 | *--------------------------------------------------------------------------- |
120 | */ | 74 | */ |
121 | static inline void store_context(void* addr) | 75 | static void start_thread(void) __attribute__((naked,used)); |
76 | static void start_thread(void) | ||
122 | { | 77 | { |
123 | asm volatile( | 78 | /* r0 = context */ |
124 | "stmia %0, { r4-r11, sp, lr }\n" | 79 | asm volatile ( |
125 | : : "r" (addr) | 80 | "ldr sp, [r0, #32] \n" /* Load initial sp */ |
126 | ); | 81 | "ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */ |
82 | "mov r1, #0 \n" /* Mark thread as running */ | ||
83 | "str r1, [r0, #40] \n" | ||
84 | #if NUM_CORES > 1 | ||
85 | "ldr r0, =invalidate_icache \n" /* Invalidate this core's cache. */ | ||
86 | "mov lr, pc \n" /* This could be the first entry into */ | ||
87 | "bx r0 \n" /* plugin or codec code for this core. */ | ||
88 | #endif | ||
89 | "mov lr, pc \n" /* Call thread function */ | ||
90 | "bx r4 \n" | ||
91 | "mov r0, #0 \n" /* remove_thread(NULL) */ | ||
92 | "ldr pc, =remove_thread \n" | ||
93 | ".ltorg \n" /* Dump constant pool */ | ||
94 | ); /* No clobber list - new thread doesn't care */ | ||
127 | } | 95 | } |
128 | 96 | ||
129 | /*--------------------------------------------------------------------------- | 97 | /*--------------------------------------------------------------------------- |
130 | * Load non-volatile context. | 98 | * Store non-volatile context. |
131 | *--------------------------------------------------------------------------- | 99 | *--------------------------------------------------------------------------- |
132 | */ | 100 | */ |
133 | static void start_thread(void (*thread_func)(void), const void* addr) __attribute__((naked,used)); | 101 | static inline void store_context(void* addr) |
134 | static void start_thread(void (*thread_func)(void), const void* addr) | ||
135 | { | 102 | { |
136 | /* r0 = thread_func, r1 = addr */ | 103 | asm volatile( |
137 | #if NUM_CORES > 1 && CONFIG_CPU != PP5002 | 104 | "stmia %0, { r4-r11, sp, lr } \n" |
138 | asm volatile ( | 105 | : : "r" (addr) |
139 | "mov r2, #0 \n" | ||
140 | "str r2, [r1, #40] \n" | ||
141 | "ldr r1, =0xf000f044 \n" /* invalidate this core's cache */ | ||
142 | "ldr r2, [r1] \n" | ||
143 | "orr r2, r2, #6 \n" | ||
144 | "str r2, [r1] \n" | ||
145 | "ldr r1, =0x6000c000 \n" | ||
146 | "1: \n" | ||
147 | "ldr r2, [r1] \n" | ||
148 | "tst r2, #0x8000 \n" | ||
149 | "bne 1b \n" | ||
150 | "mov pc, r0 \n" | ||
151 | : : : "r1", "r2" | ||
152 | ); | ||
153 | #else | ||
154 | asm volatile ( | ||
155 | "mov r2, #0 \n" | ||
156 | "str r2, [r1, #40] \n" | ||
157 | "mov pc, r0 \n" | ||
158 | : : : "r1", "r2" | ||
159 | ); | 106 | ); |
160 | #endif | ||
161 | (void)thread_func; | ||
162 | (void)addr; | ||
163 | } | 107 | } |
164 | 108 | ||
109 | /* For startup, place context pointer in r4 slot, start_thread pointer in r5 | ||
110 | * slot, and thread function pointer in context.start. See load_context for | ||
111 | * what happens when thread is initially going to run. */ | ||
112 | #define THREAD_STARTUP_INIT(core, thread, function) \ | ||
113 | ({ (thread)->context.r[0] = (unsigned int)&(thread)->context, \ | ||
114 | (thread)->context.r[1] = (unsigned int)start_thread, \ | ||
115 | (thread)->context.start = (void *)function; }) | ||
116 | |||
165 | static inline void load_context(const void* addr) | 117 | static inline void load_context(const void* addr) |
166 | { | 118 | { |
167 | asm volatile( | 119 | asm volatile( |
168 | "ldmia %0, { r4-r11, sp, lr } \n" /* load regs r4 to r14 from context */ | 120 | "ldr r0, [%0, #40] \n" /* Load start pointer */ |
169 | "ldr r0, [%0, #40] \n" /* load start pointer */ | 121 | "cmp r0, #0 \n" /* Check for NULL */ |
170 | "cmp r0, #0 \n" /* check for NULL */ | 122 | "ldmneia %0, { r0, pc } \n" /* If not already running, jump to start */ |
171 | "movne r1, %0 \n" /* if not already running, jump to start */ | 123 | "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */ |
172 | "ldrne pc, =start_thread \n" | 124 | : : "r" (addr) : "r0" /* only! */ |
173 | : : "r" (addr) : "r0", "r1" | ||
174 | ); | 125 | ); |
175 | } | 126 | } |
176 | 127 | ||
177 | #if defined (CPU_PP) | 128 | #if defined (CPU_PP) |
178 | static inline void core_sleep(void) | 129 | |
130 | #if NUM_CORES > 1 | ||
131 | extern int cpu_idlestackbegin[]; | ||
132 | extern int cpu_idlestackend[]; | ||
133 | extern int cop_idlestackbegin[]; | ||
134 | extern int cop_idlestackend[]; | ||
135 | static int * const idle_stacks[NUM_CORES] NOCACHEDATA_ATTR = | ||
179 | { | 136 | { |
180 | unlock_cores(); | 137 | [CPU] = cpu_idlestackbegin, |
138 | [COP] = cop_idlestackbegin | ||
139 | }; | ||
140 | #else /* NUM_CORES == 1 */ | ||
141 | #ifndef BOOTLOADER | ||
142 | extern int cop_stackbegin[]; | ||
143 | extern int cop_stackend[]; | ||
144 | #else | ||
145 | /* The coprocessor stack is not set up in the bootloader code, but the threading | ||
146 | * is. No threads are run on the coprocessor, so set up some dummy stack */ | ||
147 | int *cop_stackbegin = stackbegin; | ||
148 | int *cop_stackend = stackend; | ||
149 | #endif /* BOOTLOADER */ | ||
150 | #endif /* NUM_CORES */ | ||
181 | 151 | ||
152 | static inline void core_sleep(void) | ||
153 | { | ||
182 | /* This should sleep the CPU. It appears to wake by itself on | 154 | /* This should sleep the CPU. It appears to wake by itself on |
183 | interrupts */ | 155 | interrupts */ |
184 | if (CURRENT_CORE == CPU) | 156 | if (CURRENT_CORE == CPU) |
185 | CPU_CTL = PROC_SLEEP; | 157 | CPU_CTL = PROC_SLEEP; |
186 | else | 158 | else |
187 | COP_CTL = PROC_SLEEP; | 159 | COP_CTL = PROC_SLEEP; |
160 | } | ||
188 | 161 | ||
189 | lock_cores(); | 162 | #if NUM_CORES > 1 |
163 | /*--------------------------------------------------------------------------- | ||
164 | * Switches to a stack that always resides in the Rockbox core. | ||
165 | * | ||
166 | * Needed when a thread suicides on a core other than the main CPU since the | ||
167 | * stack used when idling is the stack of the last thread to run. This stack | ||
168 | * may not reside in the core in which case the core will continue to use a | ||
169 | * stack from an unloaded module until another thread runs on it. | ||
170 | *--------------------------------------------------------------------------- | ||
171 | */ | ||
172 | static inline void switch_to_idle_stack(const unsigned int core) | ||
173 | { | ||
174 | asm volatile ( | ||
175 | "str sp, [%0] \n" /* save original stack pointer on idle stack */ | ||
176 | "mov sp, %0 \n" /* switch stacks */ | ||
177 | : : "r"(&idle_stacks[core][IDLE_STACK_WORDS-1])); | ||
190 | } | 178 | } |
179 | #endif /* NUM_CORES */ | ||
180 | |||
191 | #elif CONFIG_CPU == S3C2440 | 181 | #elif CONFIG_CPU == S3C2440 |
192 | static inline void core_sleep(void) | 182 | static inline void core_sleep(void) |
193 | { | 183 | { |
@@ -205,14 +195,50 @@ static inline void core_sleep(void) | |||
205 | 195 | ||
206 | #elif defined(CPU_COLDFIRE) | 196 | #elif defined(CPU_COLDFIRE) |
207 | /*--------------------------------------------------------------------------- | 197 | /*--------------------------------------------------------------------------- |
198 | * Start the thread running and terminate it if it returns | ||
199 | *--------------------------------------------------------------------------- | ||
200 | */ | ||
201 | void start_thread(void); /* Provide C access to ASM label */ | ||
202 | static void __start_thread(void) __attribute__((used)); | ||
203 | static void __start_thread(void) | ||
204 | { | ||
205 | /* a0=macsr, a1=context */ | ||
206 | asm volatile ( | ||
207 | "start_thread: \n" /* Start here - no naked attribute */ | ||
208 | "move.l %a0, %macsr \n" /* Set initial mac status reg */ | ||
209 | "lea.l 48(%a1), %a1 \n" | ||
210 | "move.l (%a1)+, %sp \n" /* Set initial stack */ | ||
211 | "move.l (%a1), %a2 \n" /* Fetch thread function pointer */ | ||
212 | "clr.l (%a1) \n" /* Mark thread running */ | ||
213 | "jsr (%a2) \n" /* Call thread function */ | ||
214 | "clr.l -(%sp) \n" /* remove_thread(NULL) */ | ||
215 | "jsr remove_thread \n" | ||
216 | ); | ||
217 | } | ||
218 | |||
219 | /* Set EMAC unit to fractional mode with saturation for each new thread, | ||
220 | * since that's what'll be the most useful for most things which the dsp | ||
221 | * will do. Codecs should still initialize their preferred modes | ||
222 | * explicitly. Context pointer is placed in d2 slot and start_thread | ||
223 | * pointer in d3 slot. thread function pointer is placed in context.start. | ||
224 | * See load_context for what happens when thread is initially going to | ||
225 | * run. | ||
226 | */ | ||
227 | #define THREAD_STARTUP_INIT(core, thread, function) \ | ||
228 | ({ (thread)->context.macsr = EMAC_FRACTIONAL | EMAC_SATURATE, \ | ||
229 | (thread)->context.d[0] = (unsigned int)&(thread)->context, \ | ||
230 | (thread)->context.d[1] = (unsigned int)start_thread, \ | ||
231 | (thread)->context.start = (void *)(function); }) | ||
232 | |||
233 | /*--------------------------------------------------------------------------- | ||
208 | * Store non-volatile context. | 234 | * Store non-volatile context. |
209 | *--------------------------------------------------------------------------- | 235 | *--------------------------------------------------------------------------- |
210 | */ | 236 | */ |
211 | static inline void store_context(void* addr) | 237 | static inline void store_context(void* addr) |
212 | { | 238 | { |
213 | asm volatile ( | 239 | asm volatile ( |
214 | "move.l %%macsr,%%d0 \n" | 240 | "move.l %%macsr,%%d0 \n" |
215 | "movem.l %%d0/%%d2-%%d7/%%a2-%%a7,(%0) \n" | 241 | "movem.l %%d0/%%d2-%%d7/%%a2-%%a7,(%0) \n" |
216 | : : "a" (addr) : "d0" /* only! */ | 242 | : : "a" (addr) : "d0" /* only! */ |
217 | ); | 243 | ); |
218 | } | 244 | } |
@@ -224,14 +250,13 @@ static inline void store_context(void* addr) | |||
224 | static inline void load_context(const void* addr) | 250 | static inline void load_context(const void* addr) |
225 | { | 251 | { |
226 | asm volatile ( | 252 | asm volatile ( |
227 | "movem.l (%0),%%d0/%%d2-%%d7/%%a2-%%a7 \n" /* Load context */ | 253 | "move.l 52(%0), %%d0 \n" /* Get start address */ |
228 | "move.l %%d0,%%macsr \n" | 254 | "beq.b 1f \n" /* NULL -> already running */ |
229 | "move.l (52,%0),%%d0 \n" /* Get start address */ | 255 | "movem.l (%0), %%a0-%%a2 \n" /* a0=macsr, a1=context, a2=start_thread */ |
230 | "beq.b 1f \n" /* NULL -> already running */ | 256 | "jmp (%%a2) \n" /* Start the thread */ |
231 | "clr.l (52,%0) \n" /* Clear start address.. */ | 257 | "1: \n" |
232 | "move.l %%d0,%0 \n" | 258 | "movem.l (%0), %%d0/%%d2-%%d7/%%a2-%%a7 \n" /* Load context */ |
233 | "jmp (%0) \n" /* ..and start the thread */ | 259 | "move.l %%d0, %%macsr \n" |
234 | "1: \n" | ||
235 | : : "a" (addr) : "d0" /* only! */ | 260 | : : "a" (addr) : "d0" /* only! */ |
236 | ); | 261 | ); |
237 | } | 262 | } |
@@ -250,14 +275,45 @@ static inline void core_sleep(void) | |||
250 | 275 | ||
251 | #elif CONFIG_CPU == SH7034 | 276 | #elif CONFIG_CPU == SH7034 |
252 | /*--------------------------------------------------------------------------- | 277 | /*--------------------------------------------------------------------------- |
278 | * Start the thread running and terminate it if it returns | ||
279 | *--------------------------------------------------------------------------- | ||
280 | */ | ||
281 | void start_thread(void); /* Provide C access to ASM label */ | ||
282 | static void __start_thread(void) __attribute__((used)); | ||
283 | static void __start_thread(void) | ||
284 | { | ||
285 | /* r8 = context */ | ||
286 | asm volatile ( | ||
287 | "_start_thread: \n" /* Start here - no naked attribute */ | ||
288 | "mov.l @(4, r8), r0 \n" /* Fetch thread function pointer */ | ||
289 | "mov.l @(28, r8), r15 \n" /* Set initial sp */ | ||
290 | "mov #0, r1 \n" /* Start the thread */ | ||
291 | "jsr @r0 \n" | ||
292 | "mov.l r1, @(36, r8) \n" /* Clear start address */ | ||
293 | "mov.l 1f, r0 \n" /* remove_thread(NULL) */ | ||
294 | "jmp @r0 \n" | ||
295 | "mov #0, r4 \n" | ||
296 | "1: \n" | ||
297 | ".long _remove_thread \n" | ||
298 | ); | ||
299 | } | ||
300 | |||
301 | /* Place context pointer in r8 slot, function pointer in r9 slot, and | ||
302 | * start_thread pointer in context_start */ | ||
303 | #define THREAD_STARTUP_INIT(core, thread, function) \ | ||
304 | ({ (thread)->context.r[0] = (unsigned int)&(thread)->context, \ | ||
305 | (thread)->context.r[1] = (unsigned int)(function), \ | ||
306 | (thread)->context.start = (void*)start_thread; }) | ||
307 | |||
308 | /*--------------------------------------------------------------------------- | ||
253 | * Store non-volatile context. | 309 | * Store non-volatile context. |
254 | *--------------------------------------------------------------------------- | 310 | *--------------------------------------------------------------------------- |
255 | */ | 311 | */ |
256 | static inline void store_context(void* addr) | 312 | static inline void store_context(void* addr) |
257 | { | 313 | { |
258 | asm volatile ( | 314 | asm volatile ( |
259 | "add #36,%0 \n" | 315 | "add #36, %0 \n" /* Start at last reg. By the time routine */ |
260 | "sts.l pr, @-%0 \n" | 316 | "sts.l pr, @-%0 \n" /* is done, %0 will have the original value */ |
261 | "mov.l r15,@-%0 \n" | 317 | "mov.l r15,@-%0 \n" |
262 | "mov.l r14,@-%0 \n" | 318 | "mov.l r14,@-%0 \n" |
263 | "mov.l r13,@-%0 \n" | 319 | "mov.l r13,@-%0 \n" |
@@ -277,23 +333,20 @@ static inline void store_context(void* addr) | |||
277 | static inline void load_context(const void* addr) | 333 | static inline void load_context(const void* addr) |
278 | { | 334 | { |
279 | asm volatile ( | 335 | asm volatile ( |
280 | "mov.l @%0+,r8 \n" | 336 | "mov.l @(36, %0), r0 \n" /* Get start address */ |
281 | "mov.l @%0+,r9 \n" | 337 | "tst r0, r0 \n" |
282 | "mov.l @%0+,r10 \n" | 338 | "bt .running \n" /* NULL -> already running */ |
283 | "mov.l @%0+,r11 \n" | 339 | "jmp @r0 \n" /* r8 = context */ |
284 | "mov.l @%0+,r12 \n" | 340 | ".running: \n" |
285 | "mov.l @%0+,r13 \n" | 341 | "mov.l @%0+, r8 \n" /* Executes in delay slot and outside it */ |
286 | "mov.l @%0+,r14 \n" | 342 | "mov.l @%0+, r9 \n" |
287 | "mov.l @%0+,r15 \n" | 343 | "mov.l @%0+, r10 \n" |
288 | "lds.l @%0+,pr \n" | 344 | "mov.l @%0+, r11 \n" |
289 | "mov.l @%0,r0 \n" /* Get start address */ | 345 | "mov.l @%0+, r12 \n" |
290 | "tst r0,r0 \n" | 346 | "mov.l @%0+, r13 \n" |
291 | "bt .running \n" /* NULL -> already running */ | 347 | "mov.l @%0+, r14 \n" |
292 | "lds r0,pr \n" | 348 | "mov.l @%0+, r15 \n" |
293 | "mov #0,r0 \n" | 349 | "lds.l @%0+, pr \n" |
294 | "rts \n" /* Start the thread */ | ||
295 | "mov.l r0,@%0 \n" /* Clear start address */ | ||
296 | ".running: \n" | ||
297 | : : "r" (addr) : "r0" /* only! */ | 350 | : : "r" (addr) : "r0" /* only! */ |
298 | ); | 351 | ); |
299 | } | 352 | } |
@@ -311,38 +364,36 @@ static inline void core_sleep(void) | |||
311 | #define THREAD_CPU_INIT(core, thread) | 364 | #define THREAD_CPU_INIT(core, thread) |
312 | #endif | 365 | #endif |
313 | 366 | ||
314 | #ifdef THREAD_EXTRA_CHECKS | 367 | #if THREAD_EXTRA_CHECKS |
315 | static void thread_panicf_format_name(char *buffer, struct thread_entry *thread) | 368 | static void thread_panicf(const char *msg, struct thread_entry *thread) |
316 | { | 369 | { |
317 | *buffer = '\0'; | 370 | #if NUM_CORES > 1 |
318 | if (thread) | 371 | const unsigned int core = thread->core; |
319 | { | 372 | #endif |
320 | /* Display thread name if one or ID if none */ | 373 | static char name[32]; |
321 | const char *fmt = thread->name ? " %s" : " %08lX"; | 374 | thread_get_name(name, 32, thread); |
322 | intptr_t name = thread->name ? | 375 | panicf ("%s %s" IF_COP(" (%d)"), msg, name IF_COP(, core)); |
323 | (intptr_t)thread->name : (intptr_t)thread; | ||
324 | snprintf(buffer, 16, fmt, name); | ||
325 | } | ||
326 | } | 376 | } |
327 | 377 | static void thread_stkov(struct thread_entry *thread) | |
328 | static void thread_panicf(const char *msg, | ||
329 | struct thread_entry *thread1, struct thread_entry *thread2) | ||
330 | { | 378 | { |
331 | static char thread1_name[16], thread2_name[16]; | 379 | thread_panicf("Stkov", thread); |
332 | thread_panicf_format_name(thread1_name, thread1); | ||
333 | thread_panicf_format_name(thread2_name, thread2); | ||
334 | panicf ("%s%s%s", msg, thread1_name, thread2_name); | ||
335 | } | 380 | } |
381 | #define THREAD_PANICF(msg, thread) \ | ||
382 | thread_panicf(msg, thread) | ||
383 | #define THREAD_ASSERT(exp, msg, thread) \ | ||
384 | ({ if (!({ exp; })) thread_panicf((msg), (thread)); }) | ||
336 | #else | 385 | #else |
337 | static void thread_stkov(void) | 386 | static void thread_stkov(struct thread_entry *thread) |
338 | { | 387 | { |
339 | /* Display thread name if one or ID if none */ | 388 | #if NUM_CORES > 1 |
340 | struct thread_entry *current = cores[CURRENT_CORE].running; | 389 | const unsigned int core = thread->core; |
341 | const char *fmt = current->name ? "%s %s" : "%s %08lX"; | 390 | #endif |
342 | intptr_t name = current->name ? | 391 | static char name[32]; |
343 | (intptr_t)current->name : (intptr_t)current; | 392 | thread_get_name(name, 32, thread); |
344 | panicf(fmt, "Stkov", name); | 393 | panicf("Stkov %s" IF_COP(" (%d)"), name IF_COP(, core)); |
345 | } | 394 | } |
395 | #define THREAD_PANICF(msg, thread) | ||
396 | #define THREAD_ASSERT(exp, msg, thread) | ||
346 | #endif /* THREAD_EXTRA_CHECKS */ | 397 | #endif /* THREAD_EXTRA_CHECKS */ |
347 | 398 | ||
348 | static void add_to_list(struct thread_entry **list, struct thread_entry *thread) | 399 | static void add_to_list(struct thread_entry **list, struct thread_entry *thread) |
@@ -564,8 +615,6 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list) | |||
564 | /* Do nothing */ | 615 | /* Do nothing */ |
565 | #else | 616 | #else |
566 | 617 | ||
567 | lock_cores(); | ||
568 | |||
569 | /* Begin task switching by saving our current context so that we can | 618 | /* Begin task switching by saving our current context so that we can |
570 | * restore the state of the current thread later to the point prior | 619 | * restore the state of the current thread later to the point prior |
571 | * to this call. */ | 620 | * to this call. */ |
@@ -576,11 +625,7 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list) | |||
576 | /* Check if the current thread stack is overflown */ | 625 | /* Check if the current thread stack is overflown */ |
577 | stackptr = cores[core].running->stack; | 626 | stackptr = cores[core].running->stack; |
578 | if(stackptr[0] != DEADBEEF) | 627 | if(stackptr[0] != DEADBEEF) |
579 | #ifdef THREAD_EXTRA_CHECKS | 628 | thread_stkov(cores[core].running); |
580 | thread_panicf("Stkov", cores[core].running, NULL); | ||
581 | #else | ||
582 | thread_stkov(); | ||
583 | #endif | ||
584 | 629 | ||
585 | /* Rearrange thread lists as needed */ | 630 | /* Rearrange thread lists as needed */ |
586 | change_thread_state(blocked_list); | 631 | change_thread_state(blocked_list); |
@@ -627,7 +672,6 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list) | |||
627 | #endif | 672 | #endif |
628 | 673 | ||
629 | #endif | 674 | #endif |
630 | unlock_cores(); | ||
631 | 675 | ||
632 | /* And finally give control to the next thread. */ | 676 | /* And finally give control to the next thread. */ |
633 | load_context(&cores[core].running->context); | 677 | load_context(&cores[core].running->context); |
@@ -641,8 +685,6 @@ void sleep_thread(int ticks) | |||
641 | { | 685 | { |
642 | struct thread_entry *current; | 686 | struct thread_entry *current; |
643 | 687 | ||
644 | lock_cores(); | ||
645 | |||
646 | current = cores[CURRENT_CORE].running; | 688 | current = cores[CURRENT_CORE].running; |
647 | 689 | ||
648 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | 690 | #ifdef HAVE_SCHEDULER_BOOSTCTRL |
@@ -668,8 +710,6 @@ void block_thread(struct thread_entry **list) | |||
668 | { | 710 | { |
669 | struct thread_entry *current; | 711 | struct thread_entry *current; |
670 | 712 | ||
671 | lock_cores(); | ||
672 | |||
673 | /* Get the entry for the current running thread. */ | 713 | /* Get the entry for the current running thread. */ |
674 | current = cores[CURRENT_CORE].running; | 714 | current = cores[CURRENT_CORE].running; |
675 | 715 | ||
@@ -680,11 +720,9 @@ void block_thread(struct thread_entry **list) | |||
680 | unsigned long boost_flag = STATE_IS_BOOSTED(current->statearg); | 720 | unsigned long boost_flag = STATE_IS_BOOSTED(current->statearg); |
681 | #endif | 721 | #endif |
682 | 722 | ||
683 | #ifdef THREAD_EXTRA_CHECKS | ||
684 | /* We are not allowed to mix blocking types in one queue. */ | 723 | /* We are not allowed to mix blocking types in one queue. */ |
685 | if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO) | 724 | THREAD_ASSERT(*list != NULL && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO, |
686 | thread_panicf("Blocking violation B->*T", current, *list); | 725 | "Blocking violation B->*T", current); |
687 | #endif | ||
688 | 726 | ||
689 | /* Set the state to blocked and ask the scheduler to switch tasks, | 727 | /* Set the state to blocked and ask the scheduler to switch tasks, |
690 | * this takes us off of the run queue until we are explicitly woken */ | 728 | * this takes us off of the run queue until we are explicitly woken */ |
@@ -707,7 +745,6 @@ void block_thread_w_tmo(struct thread_entry **list, int timeout) | |||
707 | /* Get the entry for the current running thread. */ | 745 | /* Get the entry for the current running thread. */ |
708 | current = cores[CURRENT_CORE].running; | 746 | current = cores[CURRENT_CORE].running; |
709 | 747 | ||
710 | lock_cores(); | ||
711 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | 748 | #ifdef HAVE_SCHEDULER_BOOSTCTRL |
712 | /* A block with a timeout is a sleep situation, whatever we are waiting | 749 | /* A block with a timeout is a sleep situation, whatever we are waiting |
713 | * for _may or may not_ happen, regardless of boost state, (user input | 750 | * for _may or may not_ happen, regardless of boost state, (user input |
@@ -722,12 +759,9 @@ void block_thread_w_tmo(struct thread_entry **list, int timeout) | |||
722 | } | 759 | } |
723 | #endif | 760 | #endif |
724 | 761 | ||
725 | #ifdef THREAD_EXTRA_CHECKS | ||
726 | /* We can store only one thread to the "list" if thread is used | 762 | /* We can store only one thread to the "list" if thread is used |
727 | * in other list (such as core's list for sleeping tasks). */ | 763 | * in other list (such as core's list for sleeping tasks). */ |
728 | if (*list) | 764 | THREAD_ASSERT(*list == NULL, "Blocking violation T->*B", current); |
729 | thread_panicf("Blocking violation T->*B", current, NULL); | ||
730 | #endif | ||
731 | 765 | ||
732 | /* Set the state to blocked with the specified timeout */ | 766 | /* Set the state to blocked with the specified timeout */ |
733 | SET_STATE(current->statearg, STATE_BLOCKED_W_TMO, current_tick + timeout); | 767 | SET_STATE(current->statearg, STATE_BLOCKED_W_TMO, current_tick + timeout); |
@@ -836,7 +870,6 @@ struct thread_entry* | |||
836 | unsigned int stacklen; | 870 | unsigned int stacklen; |
837 | unsigned int *stackptr; | 871 | unsigned int *stackptr; |
838 | int slot; | 872 | int slot; |
839 | struct regs *regs; | ||
840 | struct thread_entry *thread; | 873 | struct thread_entry *thread; |
841 | 874 | ||
842 | /***** | 875 | /***** |
@@ -862,12 +895,9 @@ struct thread_entry* | |||
862 | } | 895 | } |
863 | #endif | 896 | #endif |
864 | 897 | ||
865 | lock_cores(); | ||
866 | |||
867 | slot = find_empty_thread_slot(); | 898 | slot = find_empty_thread_slot(); |
868 | if (slot < 0) | 899 | if (slot < 0) |
869 | { | 900 | { |
870 | unlock_cores(); | ||
871 | return NULL; | 901 | return NULL; |
872 | } | 902 | } |
873 | 903 | ||
@@ -899,17 +929,13 @@ struct thread_entry* | |||
899 | flush_icache(); | 929 | flush_icache(); |
900 | #endif | 930 | #endif |
901 | 931 | ||
902 | regs = &thread->context; | ||
903 | /* Align stack to an even 32 bit boundary */ | 932 | /* Align stack to an even 32 bit boundary */ |
904 | regs->sp = (void*)(((unsigned int)stack + stack_size) & ~3); | 933 | thread->context.sp = (void*)(((unsigned int)stack + stack_size) & ~3); |
905 | regs->start = (void*)function; | 934 | |
935 | /* Load the thread's context structure with needed startup information */ | ||
936 | THREAD_STARTUP_INIT(core, thread, function); | ||
906 | 937 | ||
907 | /* Do any CPU specific inits after initializing common items | ||
908 | to have access to valid data */ | ||
909 | THREAD_CPU_INIT(core, thread); | ||
910 | |||
911 | add_to_list(&cores[core].running, thread); | 938 | add_to_list(&cores[core].running, thread); |
912 | unlock_cores(); | ||
913 | 939 | ||
914 | return thread; | 940 | return thread; |
915 | #if NUM_CORES == 1 | 941 | #if NUM_CORES == 1 |
@@ -920,8 +946,6 @@ struct thread_entry* | |||
920 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | 946 | #ifdef HAVE_SCHEDULER_BOOSTCTRL |
921 | void trigger_cpu_boost(void) | 947 | void trigger_cpu_boost(void) |
922 | { | 948 | { |
923 | lock_cores(); | ||
924 | |||
925 | if (!STATE_IS_BOOSTED(cores[CURRENT_CORE].running->statearg)) | 949 | if (!STATE_IS_BOOSTED(cores[CURRENT_CORE].running->statearg)) |
926 | { | 950 | { |
927 | SET_BOOST_STATE(cores[CURRENT_CORE].running->statearg); | 951 | SET_BOOST_STATE(cores[CURRENT_CORE].running->statearg); |
@@ -931,8 +955,6 @@ void trigger_cpu_boost(void) | |||
931 | } | 955 | } |
932 | boosted_threads++; | 956 | boosted_threads++; |
933 | } | 957 | } |
934 | |||
935 | unlock_cores(); | ||
936 | } | 958 | } |
937 | #endif | 959 | #endif |
938 | 960 | ||
@@ -943,10 +965,10 @@ void trigger_cpu_boost(void) | |||
943 | */ | 965 | */ |
944 | void remove_thread(struct thread_entry *thread) | 966 | void remove_thread(struct thread_entry *thread) |
945 | { | 967 | { |
946 | lock_cores(); | 968 | const unsigned int core = CURRENT_CORE; |
947 | 969 | ||
948 | if (thread == NULL) | 970 | if (thread == NULL) |
949 | thread = cores[CURRENT_CORE].running; | 971 | thread = cores[core].running; |
950 | 972 | ||
951 | /* Free the entry by removing thread name. */ | 973 | /* Free the entry by removing thread name. */ |
952 | thread->name = NULL; | 974 | thread->name = NULL; |
@@ -957,16 +979,26 @@ void remove_thread(struct thread_entry *thread) | |||
957 | if (thread == cores[IF_COP2(thread->core)].running) | 979 | if (thread == cores[IF_COP2(thread->core)].running) |
958 | { | 980 | { |
959 | remove_from_list(&cores[IF_COP2(thread->core)].running, thread); | 981 | remove_from_list(&cores[IF_COP2(thread->core)].running, thread); |
982 | #if NUM_CORES > 1 | ||
983 | /* Switch to the idle stack if not on the main core (where "main" | ||
984 | * runs) */ | ||
985 | if (core != CPU) | ||
986 | { | ||
987 | switch_to_idle_stack(core); | ||
988 | } | ||
989 | |||
990 | flush_icache(); | ||
991 | #endif | ||
960 | switch_thread(false, NULL); | 992 | switch_thread(false, NULL); |
961 | return ; | 993 | /* This should never and must never be reached - if it is, the |
994 | * state is corrupted */ | ||
995 | THREAD_PANICF("remove_thread->K:*R", thread); | ||
962 | } | 996 | } |
963 | 997 | ||
964 | if (thread == cores[IF_COP2(thread->core)].sleeping) | 998 | if (thread == cores[IF_COP2(thread->core)].sleeping) |
965 | remove_from_list(&cores[IF_COP2(thread->core)].sleeping, thread); | 999 | remove_from_list(&cores[IF_COP2(thread->core)].sleeping, thread); |
966 | else | 1000 | else |
967 | remove_from_list(NULL, thread); | 1001 | remove_from_list(NULL, thread); |
968 | |||
969 | unlock_cores(); | ||
970 | } | 1002 | } |
971 | 1003 | ||
972 | #ifdef HAVE_PRIORITY_SCHEDULING | 1004 | #ifdef HAVE_PRIORITY_SCHEDULING |
@@ -974,14 +1006,12 @@ int thread_set_priority(struct thread_entry *thread, int priority) | |||
974 | { | 1006 | { |
975 | int old_priority; | 1007 | int old_priority; |
976 | 1008 | ||
977 | lock_cores(); | ||
978 | if (thread == NULL) | 1009 | if (thread == NULL) |
979 | thread = cores[CURRENT_CORE].running; | 1010 | thread = cores[CURRENT_CORE].running; |
980 | 1011 | ||
981 | old_priority = thread->priority; | 1012 | old_priority = thread->priority; |
982 | thread->priority = priority; | 1013 | thread->priority = priority; |
983 | cores[IF_COP2(thread->core)].highest_priority = 100; | 1014 | cores[IF_COP2(thread->core)].highest_priority = 100; |
984 | unlock_cores(); | ||
985 | 1015 | ||
986 | return old_priority; | 1016 | return old_priority; |
987 | } | 1017 | } |
@@ -1013,15 +1043,7 @@ void init_threads(void) | |||
1013 | const unsigned int core = CURRENT_CORE; | 1043 | const unsigned int core = CURRENT_CORE; |
1014 | int slot; | 1044 | int slot; |
1015 | 1045 | ||
1016 | /* Let main CPU initialize first. */ | 1046 | /* CPU will initialize first and then sleep */ |
1017 | #if NUM_CORES > 1 | ||
1018 | if (core != CPU) | ||
1019 | { | ||
1020 | while (!cores[CPU].kernel_running) ; | ||
1021 | } | ||
1022 | #endif | ||
1023 | |||
1024 | lock_cores(); | ||
1025 | slot = find_empty_thread_slot(); | 1047 | slot = find_empty_thread_slot(); |
1026 | 1048 | ||
1027 | cores[core].sleeping = NULL; | 1049 | cores[core].sleeping = NULL; |
@@ -1042,30 +1064,40 @@ void init_threads(void) | |||
1042 | threads[slot].priority_x = 0; | 1064 | threads[slot].priority_x = 0; |
1043 | cores[core].highest_priority = 100; | 1065 | cores[core].highest_priority = 100; |
1044 | #endif | 1066 | #endif |
1045 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | ||
1046 | boosted_threads = 0; | ||
1047 | #endif | ||
1048 | add_to_list(&cores[core].running, &threads[slot]); | 1067 | add_to_list(&cores[core].running, &threads[slot]); |
1049 | 1068 | ||
1050 | /* In multiple core setups, each core has a different stack. There is | 1069 | /* In multiple core setups, each core has a different stack. There is |
1051 | * probably a much better way to do this. */ | 1070 | * probably a much better way to do this. */ |
1052 | if (core == CPU) | 1071 | if (core == CPU) |
1053 | { | 1072 | { |
1073 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | ||
1074 | boosted_threads = 0; | ||
1075 | #endif | ||
1054 | threads[slot].stack = stackbegin; | 1076 | threads[slot].stack = stackbegin; |
1055 | threads[slot].stack_size = (int)stackend - (int)stackbegin; | 1077 | threads[slot].stack_size = (int)stackend - (int)stackbegin; |
1056 | } | ||
1057 | #if NUM_CORES > 1 /* This code path will not be run on single core targets */ | 1078 | #if NUM_CORES > 1 /* This code path will not be run on single core targets */ |
1079 | /* Mark CPU initialized */ | ||
1080 | cores[CPU].kernel_running = true; | ||
1081 | /* TODO: HAL interface for this */ | ||
1082 | /* Wake up coprocessor and let it initialize kernel and threads */ | ||
1083 | COP_CTL = PROC_WAKE; | ||
1084 | /* Sleep until finished */ | ||
1085 | CPU_CTL = PROC_SLEEP; | ||
1086 | } | ||
1058 | else | 1087 | else |
1059 | { | 1088 | { |
1060 | threads[slot].stack = cop_stackbegin; | 1089 | /* Initial stack is the COP idle stack */ |
1061 | threads[slot].stack_size = | 1090 | threads[slot].stack = cop_idlestackbegin; |
1062 | (int)cop_stackend - (int)cop_stackbegin; | 1091 | threads[slot].stack_size = IDLE_STACK_SIZE; |
1063 | } | 1092 | /* Mark COP initialized */ |
1064 | 1093 | cores[COP].kernel_running = true; | |
1065 | cores[core].kernel_running = true; | 1094 | /* Get COP safely primed inside switch_thread where it will remain |
1095 | * until a thread actually exists on it */ | ||
1096 | CPU_CTL = PROC_WAKE; | ||
1097 | set_irq_level(0); | ||
1098 | remove_thread(NULL); | ||
1066 | #endif | 1099 | #endif |
1067 | 1100 | } | |
1068 | unlock_cores(); | ||
1069 | } | 1101 | } |
1070 | 1102 | ||
1071 | int thread_stack_usage(const struct thread_entry *thread) | 1103 | int thread_stack_usage(const struct thread_entry *thread) |
@@ -1083,7 +1115,59 @@ int thread_stack_usage(const struct thread_entry *thread) | |||
1083 | thread->stack_size; | 1115 | thread->stack_size; |
1084 | } | 1116 | } |
1085 | 1117 | ||
1118 | #if NUM_CORES > 1 | ||
1119 | /*--------------------------------------------------------------------------- | ||
1120 | * Returns the maximum percentage of the core's idle stack ever used during | ||
1121 | * runtime. | ||
1122 | *--------------------------------------------------------------------------- | ||
1123 | */ | ||
1124 | int idle_stack_usage(unsigned int core) | ||
1125 | { | ||
1126 | unsigned int *stackptr = idle_stacks[core]; | ||
1127 | int i, usage = 0; | ||
1128 | |||
1129 | for (i = 0; i < IDLE_STACK_WORDS; i++) | ||
1130 | { | ||
1131 | if (stackptr[i] != DEADBEEF) | ||
1132 | { | ||
1133 | usage = ((IDLE_STACK_WORDS - i) * 100) / IDLE_STACK_WORDS; | ||
1134 | break; | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | return usage; | ||
1139 | } | ||
1140 | #endif | ||
1141 | |||
1086 | int thread_get_status(const struct thread_entry *thread) | 1142 | int thread_get_status(const struct thread_entry *thread) |
1087 | { | 1143 | { |
1088 | return GET_STATE(thread->statearg); | 1144 | return GET_STATE(thread->statearg); |
1089 | } | 1145 | } |
1146 | |||
1147 | /*--------------------------------------------------------------------------- | ||
1148 | * Fills in the buffer with the specified thread's name. If the name is NULL, | ||
1149 | * empty, or the thread is in destruct state a formatted ID is written | ||
1150 | * instead. | ||
1151 | *--------------------------------------------------------------------------- | ||
1152 | */ | ||
1153 | void thread_get_name(char *buffer, int size, | ||
1154 | struct thread_entry *thread) | ||
1155 | { | ||
1156 | if (size <= 0) | ||
1157 | return; | ||
1158 | |||
1159 | *buffer = '\0'; | ||
1160 | |||
1161 | if (thread) | ||
1162 | { | ||
1163 | /* Display thread name if one or ID if none */ | ||
1164 | const char *name = thread->name; | ||
1165 | const char *fmt = "%s"; | ||
1166 | if (name == NULL || *name == '\0') | ||
1167 | { | ||
1168 | name = (const char *)thread; | ||
1169 | fmt = "%08lX"; | ||
1170 | } | ||
1171 | snprintf(buffer, size, fmt, name); | ||
1172 | } | ||
1173 | } | ||
diff --git a/firmware/usb.c b/firmware/usb.c index 876a5e4ec2..af09aecff9 100644 --- a/firmware/usb.c +++ b/firmware/usb.c | |||
@@ -306,7 +306,6 @@ void usb_init(void) | |||
306 | 306 | ||
307 | #ifndef BOOTLOADER | 307 | #ifndef BOOTLOADER |
308 | queue_init(&usb_queue, true); | 308 | queue_init(&usb_queue, true); |
309 | queue_set_irq_safe(&usb_queue, true); | ||
310 | 309 | ||
311 | create_thread(usb_thread, usb_stack, sizeof(usb_stack), | 310 | create_thread(usb_thread, usb_stack, sizeof(usb_stack), |
312 | usb_thread_name IF_PRIO(, PRIORITY_SYSTEM) | 311 | usb_thread_name IF_PRIO(, PRIORITY_SYSTEM) |