summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-09-28 10:20:02 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-09-28 10:20:02 +0000
commit7914e90738ff37e6378b37632eb1f05bab7354d5 (patch)
tree6b3d6a6bac4c7a3f82fa212d5f3ed324d81dc8bb
parentedbf5d81f5a635a0db68039554b086f942b3e005 (diff)
downloadrockbox-7914e90738ff37e6378b37632eb1f05bab7354d5.tar.gz
rockbox-7914e90738ff37e6378b37632eb1f05bab7354d5.zip
Commit a subset of the dual core changes that have to do with cache handling, stacks, firmware startup and thread startup. Tested on e200, H10-20GB, iPod Color and 5.5G. Thread function return implemented for all targets. Some changes to plugins to follow shortly.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14879 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs.c4
-rw-r--r--apps/codecs.h24
-rw-r--r--apps/codecs/codec_crt0.c2
-rw-r--r--apps/debug_menu.c66
-rw-r--r--apps/main.c26
-rw-r--r--apps/plugin.c5
-rw-r--r--apps/plugin.h25
-rw-r--r--firmware/app.lds13
-rw-r--r--firmware/backlight.c1
-rw-r--r--firmware/drivers/button.c4
-rw-r--r--firmware/export/config.h8
-rw-r--r--firmware/export/kernel.h8
-rw-r--r--firmware/export/pp5020.h25
-rw-r--r--firmware/export/thread.h57
-rw-r--r--firmware/kernel.c136
-rw-r--r--firmware/pcm_record.c1
-rw-r--r--firmware/rolo.c36
-rw-r--r--firmware/system.c4
-rw-r--r--firmware/target/arm/crt0-pp.S196
-rw-r--r--firmware/target/arm/system-pp502x.c54
-rw-r--r--firmware/target/arm/system-target.h23
-rw-r--r--firmware/thread.c504
-rw-r--r--firmware/usb.c1
23 files changed, 680 insertions, 543 deletions
diff --git a/apps/codecs.c b/apps/codecs.c
index ba9d7392b1..35cce6a861 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -157,6 +157,10 @@ struct codec_api ci = {
157 /* new stuff at the end, sort into place next time 157 /* new stuff at the end, sort into place next time
158 the API gets incompatible */ 158 the API gets incompatible */
159 159
160#ifdef CACHE_FUNCTIONS_AS_CALL
161 flush_icache,
162 invalidate_icache,
163#endif
160}; 164};
161 165
162void codec_get_full_path(char *path, const char *codec_root_fn) 166void codec_get_full_path(char *path, const char *codec_root_fn)
diff --git a/apps/codecs.h b/apps/codecs.h
index 652ae7451a..50bc36baa2 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -80,7 +80,7 @@
80#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ 80#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
81 81
82/* increase this every time the api struct changes */ 82/* increase this every time the api struct changes */
83#define CODEC_API_VERSION 18 83#define CODEC_API_VERSION 19
84 84
85/* update this to latest version if a change to the api struct breaks 85/* update this to latest version if a change to the api struct breaks
86 backwards compatibility (and please take the opportunity to sort in any 86 backwards compatibility (and please take the opportunity to sort in any
@@ -230,6 +230,10 @@ struct codec_api {
230 /* new stuff at the end, sort into place next time 230 /* new stuff at the end, sort into place next time
231 the API gets incompatible */ 231 the API gets incompatible */
232 232
233#ifdef CACHE_FUNCTIONS_AS_CALL
234 void (*flush_icache)(void);
235 void (*invalidate_icache)(void);
236#endif
233}; 237};
234 238
235/* codec header */ 239/* codec header */
@@ -286,4 +290,22 @@ int codec_load_file(const char* codec, struct codec_api *api);
286/* defined by the codec */ 290/* defined by the codec */
287enum codec_status codec_start(struct codec_api* rockbox); 291enum codec_status codec_start(struct codec_api* rockbox);
288 292
293#ifndef CACHE_FUNCTION_WRAPPERS
294
295#ifdef CACHE_FUNCTIONS_AS_CALL
296#define CACHE_FUNCTION_WRAPPERS(api) \
297 void flush_icache(void) \
298 { \
299 (api)->flush_icache(); \
300 } \
301 void invalidate_icache(void) \
302 { \
303 (api)->invalidate_icache(); \
304 }
305#else
306#define CACHE_FUNCTION_WRAPPERS(api)
307#endif /* CACHE_FUNCTIONS_AS_CALL */
308
309#endif /* CACHE_FUNCTION_WRAPPERS */
310
289#endif 311#endif
diff --git a/apps/codecs/codec_crt0.c b/apps/codecs/codec_crt0.c
index c9c2cba370..1c61d84b47 100644
--- a/apps/codecs/codec_crt0.c
+++ b/apps/codecs/codec_crt0.c
@@ -32,6 +32,8 @@ extern unsigned char plugin_end_addr[];
32 32
33extern enum codec_status codec_main(void); 33extern enum codec_status codec_main(void);
34 34
35CACHE_FUNCTION_WRAPPERS(ci);
36
35enum codec_status codec_start(struct codec_api *api) 37enum codec_status codec_start(struct codec_api *api)
36{ 38{
37#ifndef SIMULATOR 39#ifndef SIMULATOR
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 40c0fcc9b0..15c2c93d62 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -180,7 +180,6 @@ static bool dbg_list(struct action_callback_info *info)
180/*---------------------------------------------------*/ 180/*---------------------------------------------------*/
181extern struct thread_entry threads[MAXTHREADS]; 181extern struct thread_entry threads[MAXTHREADS];
182 182
183
184static char thread_status_char(int status) 183static char thread_status_char(int status)
185{ 184{
186 switch (status) 185 switch (status)
@@ -193,42 +192,48 @@ static char thread_status_char(int status)
193 192
194 return '?'; 193 return '?';
195} 194}
196#if NUM_CORES > 1 195
197#define IF_COP2(...) __VA_ARGS__
198#else
199#define IF_COP2(...)
200#endif
201static char* threads_getname(int selected_item, void * data, char *buffer) 196static char* threads_getname(int selected_item, void * data, char *buffer)
202{ 197{
203 (void)data; 198 (void)data;
199 char name[32];
204 struct thread_entry *thread = NULL; 200 struct thread_entry *thread = NULL;
205 int status, usage; 201 unsigned status;
202 int usage;
203
204#if NUM_CORES > 1
205 if (selected_item < (int)NUM_CORES)
206 {
207 usage = idle_stack_usage(selected_item);
208 snprintf(buffer, MAX_PATH, "Idle (%d): %2d%%", selected_item, usage);
209 return buffer;
210 }
211
212 selected_item -= NUM_CORES;
213#endif
214
206 thread = &threads[selected_item]; 215 thread = &threads[selected_item];
216 status = thread_get_status(thread);
207 217
208 if (thread->name == NULL) 218 if (thread->name == NULL)
209 { 219 {
210 snprintf(buffer, MAX_PATH, "%2d: ---", selected_item); 220 snprintf(buffer, MAX_PATH, "%2d: ---", selected_item);
211 return buffer; 221 return buffer;
212 } 222 }
213 223
224 thread_get_name(name, 32, thread);
214 usage = thread_stack_usage(thread); 225 usage = thread_stack_usage(thread);
215 status = thread_get_status(thread); 226 status = thread_get_status(thread);
216#ifdef HAVE_PRIORITY_SCHEDULING 227
217 snprintf(buffer, MAX_PATH, "%2d: " IF_COP2("(%d) ") "%c%c %d %2d%% %s", 228 snprintf(buffer, MAX_PATH,
218 selected_item, 229 "%2d: " IF_COP("(%d) ") "%c%c " IF_PRIO("%d ") "%2d%% %s",
219 IF_COP2(thread->core,)
220 (status == STATE_RUNNING) ? '*' : ' ',
221 thread_status_char(status),
222 thread->priority,
223 usage, thread->name);
224#else
225 snprintf(buffer, MAX_PATH, "%2d: " IF_COP2("(%d) ") "%c%c %2d%% %s",
226 selected_item, 230 selected_item,
227 IF_COP2(thread->core,) 231 IF_COP(thread->core,)
228 (status == STATE_RUNNING) ? '*' : ' ', 232 (status == STATE_RUNNING) ? '*' : ' ',
229 thread_status_char(status), 233 thread_status_char(status),
230 usage, thread->name); 234 IF_PRIO(thread->priority,)
231#endif 235 usage, name);
236
232 return buffer; 237 return buffer;
233} 238}
234static int dbg_threads_action_callback(int action, struct action_callback_info *info) 239static int dbg_threads_action_callback(int action, struct action_callback_info *info)
@@ -236,11 +241,16 @@ static int dbg_threads_action_callback(int action, struct action_callback_info *
236#ifdef ROCKBOX_HAS_LOGF 241#ifdef ROCKBOX_HAS_LOGF
237 if (action == ACTION_STD_OK) 242 if (action == ACTION_STD_OK)
238 { 243 {
239 struct thread_entry *thread = &threads[gui_synclist_get_sel_pos(info->lists)]; 244 int selpos = gui_synclist_get_sel_pos(info->lists);
240 if (thread->name != NULL) 245#if NUM_CORES > 1
241 remove_thread(thread); 246 if (selpos >= NUM_CORES)
242 } 247 remove_thread(&threads[selpos - NUM_CORES]);
248#else
249 remove_thread(&threads[selpos]);
243#endif 250#endif
251 }
252 gui_synclist_hide_selection_marker(info->lists, false);
253#endif /* ROCKBOX_HAS_LOGF */
244 gui_synclist_draw(info->lists); 254 gui_synclist_draw(info->lists);
245 return action; 255 return action;
246} 256}
@@ -248,8 +258,12 @@ static int dbg_threads_action_callback(int action, struct action_callback_info *
248static bool dbg_os(void) 258static bool dbg_os(void)
249{ 259{
250 struct action_callback_info info; 260 struct action_callback_info info;
251 info.title = IF_COP2("Core and ") "Stack usage:"; 261 info.title = IF_COP("Core and ") "Stack usage:";
262#if NUM_CORES == 1
252 info.count = MAXTHREADS; 263 info.count = MAXTHREADS;
264#else
265 info.count = MAXTHREADS+NUM_CORES;
266#endif
253 info.selection_size = 1; 267 info.selection_size = 1;
254 info.action_callback = dbg_threads_action_callback; 268 info.action_callback = dbg_threads_action_callback;
255 info.dbg_getname = threads_getname; 269 info.dbg_getname = threads_getname;
diff --git a/apps/main.c b/apps/main.c
index a27998168c..bc8a12dd4e 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -334,9 +334,7 @@ static void init(void)
334 /* if nobody initialized ATA before, I consider this a cold start */ 334 /* if nobody initialized ATA before, I consider this a cold start */
335 bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */ 335 bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */
336#endif 336#endif
337#ifdef CPU_PP 337
338 COP_CTL = PROC_WAKE;
339#endif
340 system_init(); 338 system_init();
341 kernel_init(); 339 kernel_init();
342 340
@@ -591,25 +589,19 @@ void cop_main(void)
591 so it should not be assumed that the coprocessor be usable even on 589 so it should not be assumed that the coprocessor be usable even on
592 platforms which support it. 590 platforms which support it.
593 591
594 A kernel thread runs on the coprocessor which waits for other threads to be 592 A kernel thread is initially setup on the coprocessor and immediately
595 added, and gracefully handles RoLo */ 593 destroyed for purposes of continuity. The cop sits idle until at least
594 one thread exists on it. */
596 595
597#if CONFIG_CPU == PP5002
598/* 3G doesn't have Rolo or dual core support yet */ 596/* 3G doesn't have Rolo or dual core support yet */
599 while(1) { 597#if NUM_CORES > 1
600 COP_CTL = PROC_SLEEP;
601 }
602#else
603 extern volatile unsigned char cpu_message;
604
605 system_init(); 598 system_init();
606 kernel_init(); 599 kernel_init();
607 600 /* This should never be reached */
608 while(cpu_message != COP_REBOOT) { 601#endif
609 sleep(HZ); 602 while(1) {
603 COP_CTL = PROC_SLEEP;
610 } 604 }
611 rolo_restart_cop();
612#endif /* PP5002 */
613} 605}
614#endif /* CPU_PP */ 606#endif /* CPU_PP */
615 607
diff --git a/apps/plugin.c b/apps/plugin.c
index f56d532537..f0b86c08cb 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -509,6 +509,11 @@ static const struct plugin_api rockbox_api = {
509#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 509#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
510 lcd_yuv_set_options, 510 lcd_yuv_set_options,
511#endif 511#endif
512
513#ifdef CACHE_FUNCTIONS_AS_CALL
514 flush_icache,
515 invalidate_icache,
516#endif
512}; 517};
513 518
514int plugin_load(const char* plugin, void* parameter) 519int plugin_load(const char* plugin, void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index a2e24f88d9..5f868e5654 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -112,7 +112,7 @@
112#define PLUGIN_MAGIC 0x526F634B /* RocK */ 112#define PLUGIN_MAGIC 0x526F634B /* RocK */
113 113
114/* increase this every time the api struct changes */ 114/* increase this every time the api struct changes */
115#define PLUGIN_API_VERSION 77 115#define PLUGIN_API_VERSION 78
116 116
117/* update this to latest version if a change to the api struct breaks 117/* update this to latest version if a change to the api struct breaks
118 backwards compatibility (and please take the opportunity to sort in any 118 backwards compatibility (and please take the opportunity to sort in any
@@ -627,6 +627,11 @@ struct plugin_api {
627#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 627#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
628 void (*lcd_yuv_set_options)(unsigned options); 628 void (*lcd_yuv_set_options)(unsigned options);
629#endif 629#endif
630
631#ifdef CACHE_FUNCTIONS_AS_CALL
632 void (*flush_icache)(void);
633 void (*invalidate_icache)(void);
634#endif
630}; 635};
631 636
632/* plugin header */ 637/* plugin header */
@@ -710,4 +715,22 @@ enum plugin_status plugin_start(struct plugin_api* rockbox, void* parameter)
710 return (api)->memcmp(s1, s2, n); \ 715 return (api)->memcmp(s1, s2, n); \
711 } 716 }
712 717
718#ifndef CACHE_FUNCTION_WRAPPERS
719
720#ifdef CACHE_FUNCTIONS_AS_CALL
721#define CACHE_FUNCTION_WRAPPERS(api) \
722 void flush_icache(void) \
723 { \
724 (api)->flush_icache(); \
725 } \
726 void invalidate_icache(void) \
727 { \
728 (api)->invalidate_icache(); \
729 }
730#else
731#define CACHE_FUNCTION_WRAPPERS(api)
732#endif /* CACHE_FUNCTIONS_AS_CALL */
733
734#endif /* CACHE_FUNCTION_WRAPPERS */
735
713#endif 736#endif
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)
611void backlight_init(void) 611void 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,
153void timeout_cancel(struct timeout *tmo); 150void timeout_cancel(struct timeout *tmo);
154 151
155extern void queue_init(struct event_queue *q, bool register_queue); 152extern void queue_init(struct event_queue *q, bool register_queue);
156#if NUM_CORES > 1
157extern void queue_set_irq_safe(struct event_queue *q, bool state);
158#else
159#define queue_set_irq_safe(q,state)
160#endif
161extern void queue_delete(struct event_queue *q); 153extern void queue_delete(struct event_queue *q);
162extern void queue_wait(struct event_queue *q, struct event *ev); 154extern void queue_wait(struct event_queue *q, struct event *ev);
163extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); 155extern 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
54struct regs 54struct 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
63struct regs 63struct 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)
71struct regs 71struct 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
80struct regs 80struct 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
201inline void lock_cores(void);
202inline void unlock_cores(void);
203#else
204#define lock_cores(...)
205#define unlock_cores(...)
206#endif
207
208struct thread_entry* 200struct 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);
239struct thread_entry * thread_get_current(void); 231struct thread_entry * thread_get_current(void);
240void init_threads(void); 232void init_threads(void);
241int thread_stack_usage(const struct thread_entry *thread); 233int thread_stack_usage(const struct thread_entry *thread);
234#if NUM_CORES > 1
235int idle_stack_usage(unsigned int core);
236#endif
242int thread_get_status(const struct thread_entry *thread); 237int thread_get_status(const struct thread_entry *thread);
238void thread_get_name(char *buffer, int size,
239 struct thread_entry *thread);
243#ifdef RB_PROFILE 240#ifdef RB_PROFILE
244void profile_thread(void); 241void 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;
46void kernel_init(void) 46void 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 */
199void queue_set_irq_safe(struct event_queue *q, bool state)
200{
201 q->irq_safe = state;
202}
203#endif
204
205void queue_delete(struct event_queue *q) 191void 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
278void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) 259void 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 */
397void queue_reply(struct event_queue *q, intptr_t retval) 363void 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
409bool queue_empty(const struct event_queue* q) 373bool 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
427void queue_clear(struct event_queue* q) 378void 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 */
500int queue_count(const struct event_queue *q) 431int 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
522int queue_broadcast(long id, intptr_t data) 436int 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 */
663void tick_start(unsigned int interval_in_ms) 577void 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
923void mutex_unlock(struct mutex *m) 837void 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
935void spinlock_lock(struct mutex *m) 845void 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)
428void pcm_rec_init(void) 428void 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
53volatile unsigned char IDATA_ATTR cpu_message = 0; 54volatile unsigned char IDATA_ATTR cpu_message = 0;
54volatile unsigned char IDATA_ATTR cpu_reply = 0; 55volatile unsigned char IDATA_ATTR cpu_reply = 0;
56#if NUM_CORES > 1
57extern int cop_idlestackbegin[];
58#endif
55 59
56void rolo_restart_cop(void) ICODE_ATTR; 60void rolo_restart_cop(void) ICODE_ATTR;
57void rolo_restart_cop(void) 61void 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 */
182void UIE(unsigned int pc, unsigned int num) __attribute__((noreturn));
182void UIE(unsigned int pc, unsigned int num) 183void 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
62pad_skip: 65pad_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
1011:
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 */
851: 1231:
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
103remap_start: 141remap_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
108L_post_remap: .word remap_end 146L_post_remap:
147 .word remap_end
109remap_end: 148remap_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
132cpu_init: 161cpu_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
1351: 1641:
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
2131:
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
1831: 2221:
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
212cop_init: 261cop_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
2211: 2651:
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
2322: 2792:
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:
300software_int_handler: 346software_int_handler:
301reserved_handler: 347reserved_handler:
302 movs pc, lr 348 movs pc, lr
303
304prefetch_abort_handler: 349prefetch_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
329irq_stack: 377irq_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
88static void ipod_init_cache(void) 86void flush_icache(void) ICODE_ATTR;
87void 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
96void invalidate_icache(void) ICODE_ATTR;
97void 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
109static 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
74unsigned 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
80static inline void invalidate_icache(void) 77void 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
87static inline void flush_icache(void) 80void 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
83unsigned 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
50static const char main_thread_name[] = "main"; 50static const char main_thread_name[] = "main";
51 51
52extern int stackbegin[]; 52extern int stackbegin[];
53extern int stackend[]; 53extern int stackend[];
54 54
55#ifdef CPU_PP
56#ifndef BOOTLOADER
57extern int cop_stackbegin[];
58extern 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 */
62int *cop_stackbegin = stackbegin;
63int *cop_stackend = stackend;
64#endif
65#endif
66
67#if NUM_CORES > 1
68#if 0
69static 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
77inline 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
88inline 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
102static void add_to_list(struct thread_entry **list, 56static 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 */
121static inline void store_context(void* addr) 75static void start_thread(void) __attribute__((naked,used));
76static 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 */
133static void start_thread(void (*thread_func)(void), const void* addr) __attribute__((naked,used)); 101static inline void store_context(void* addr)
134static 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
165static inline void load_context(const void* addr) 117static 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)
178static inline void core_sleep(void) 129
130#if NUM_CORES > 1
131extern int cpu_idlestackbegin[];
132extern int cpu_idlestackend[];
133extern int cop_idlestackbegin[];
134extern int cop_idlestackend[];
135static 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
142extern int cop_stackbegin[];
143extern 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 */
147int *cop_stackbegin = stackbegin;
148int *cop_stackend = stackend;
149#endif /* BOOTLOADER */
150#endif /* NUM_CORES */
181 151
152static 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 */
172static 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
192static inline void core_sleep(void) 182static 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 */
201void start_thread(void); /* Provide C access to ASM label */
202static void __start_thread(void) __attribute__((used));
203static 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 */
211static inline void store_context(void* addr) 237static 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)
224static inline void load_context(const void* addr) 250static 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 */
281void start_thread(void); /* Provide C access to ASM label */
282static void __start_thread(void) __attribute__((used));
283static 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 */
256static inline void store_context(void* addr) 312static 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)
277static inline void load_context(const void* addr) 333static 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
315static void thread_panicf_format_name(char *buffer, struct thread_entry *thread) 368static 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 377static void thread_stkov(struct thread_entry *thread)
328static 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
337static void thread_stkov(void) 386static 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
348static void add_to_list(struct thread_entry **list, struct thread_entry *thread) 399static 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
921void trigger_cpu_boost(void) 947void 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 */
944void remove_thread(struct thread_entry *thread) 966void 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
1071int thread_stack_usage(const struct thread_entry *thread) 1103int 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 */
1124int 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
1086int thread_get_status(const struct thread_entry *thread) 1142int 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 */
1153void 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)