summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Ankers <dan@weirdo.org.uk>2007-03-04 20:06:41 +0000
committerDaniel Ankers <dan@weirdo.org.uk>2007-03-04 20:06:41 +0000
commit82f9056988331572e01231d70fadc64b7ab76c6f (patch)
tree9f1d33b904516fd5eeac2067e4afb32ce5e990df
parent74e572c9d600247ee795b206da3715f6af442a25 (diff)
downloadrockbox-82f9056988331572e01231d70fadc64b7ab76c6f.tar.gz
rockbox-82f9056988331572e01231d70fadc64b7ab76c6f.tar.bz2
rockbox-82f9056988331572e01231d70fadc64b7ab76c6f.zip
Dual core support for PP502x players (iPod G4 and later, iriver h10, Sansa - iPod G3 will be coming soon.) This allows threads to be run on either core provided that all communications between the cores is done using uncached memory. There should be no significant change in battery life from doing this. Documentation (on the RockboxKernel wiki page) will follow shortly.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12601 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs.c2
-rw-r--r--apps/codecs.h5
-rw-r--r--apps/main.c14
-rw-r--r--apps/playback.c24
-rw-r--r--apps/playlist.c3
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h8
-rw-r--r--apps/plugins/alpine_cdc.c3
-rw-r--r--apps/plugins/battery_bench.c3
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c10
-rw-r--r--apps/tagcache.c3
-rw-r--r--docs/PLUGIN_API3
-rw-r--r--firmware/backlight.c3
-rw-r--r--firmware/common/dircache.c3
-rw-r--r--firmware/drivers/ata.c3
-rw-r--r--firmware/drivers/ata_mmc.c3
-rw-r--r--firmware/drivers/lcd-16bit.c3
-rw-r--r--firmware/drivers/lcd-1bit-vert.c3
-rw-r--r--firmware/drivers/lcd-2bit-horz.c3
-rw-r--r--firmware/drivers/lcd-2bit-vert.c3
-rw-r--r--firmware/drivers/lcd-player.c3
-rw-r--r--firmware/drivers/lcd-remote-1bit-v.c3
-rw-r--r--firmware/drivers/lcd-remote-2bit-vi.c3
-rw-r--r--firmware/export/config.h39
-rw-r--r--firmware/export/pp5002.h3
-rw-r--r--firmware/export/pp5020.h9
-rw-r--r--firmware/export/thread.h9
-rw-r--r--firmware/kernel.c67
-rw-r--r--firmware/mpeg.c3
-rw-r--r--firmware/pcm_record.c3
-rw-r--r--firmware/powermgmt.c3
-rw-r--r--firmware/system.c237
-rw-r--r--firmware/target/arm/crt0-pp.S17
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/ata-e200.c3
-rw-r--r--firmware/thread.c78
-rw-r--r--firmware/usb.c3
-rw-r--r--uisimulator/common/stubs.c6
-rw-r--r--uisimulator/sdl/thread-sdl.c6
38 files changed, 383 insertions, 215 deletions
diff --git a/apps/codecs.c b/apps/codecs.c
index 0c6ddd0422..ccfa449d51 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -123,7 +123,7 @@ struct codec_api ci = {
&current_tick,
default_event_handler,
default_event_handler_ex,
- create_thread_on_core,
+ create_thread,
remove_thread,
reset_poweroff_timer,
#ifndef SIMULATOR
diff --git a/apps/codecs.h b/apps/codecs.h
index 6710afdc8e..3c2b754dac 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -199,9 +199,10 @@ struct codec_api {
long* current_tick;
long (*default_event_handler)(long event);
long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
- struct thread_entry* (*create_thread)(unsigned int core, void (*function)(void),
+ struct thread_entry* (*create_thread)(void (*function)(void),
void* stack, int stack_size, const char *name
- IF_PRIO(, int priority));
+ IF_PRIO(, int priority)
+ IF_COP(, unsigned int core, bool fallback));
void (*remove_thread)(struct thread_entry *thread);
void (*reset_poweroff_timer)(void);
#ifndef SIMULATOR
diff --git a/apps/main.c b/apps/main.c
index 6286b68ed1..e4d90bce61 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -297,6 +297,9 @@ static void init(void)
/* if nobody initialized ATA before, I consider this a cold start */
bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */
#endif
+#ifdef CPU_PP
+ COP_CTL = PROC_WAKE;
+#endif
system_init();
kernel_init();
@@ -549,19 +552,22 @@ void cop_main(void)
so it should not be assumed that the coprocessor be usable even on
platforms which support it.
- At present the COP sleeps unless it receives a message from the CPU telling
- it that we are loading a new kernel, so must reboot */
+ A kernel thread runs on the coprocessor which waits for other threads to be
+ added, and gracefully handles RoLo */
#if CONFIG_CPU == PP5002
-/* 3G doesn't have Rolo support yet */
+/* 3G doesn't have Rolo or dual core support yet */
while(1) {
COP_CTL = PROC_SLEEP;
}
#else
extern volatile unsigned char cpu_message;
+ system_init();
+ kernel_init();
+
while(cpu_message != COP_REBOOT) {
- COP_CTL = PROC_SLEEP;
+ sleep(HZ);
}
rolo_restart_cop();
#endif /* PP5002 */
diff --git a/apps/playback.c b/apps/playback.c
index fe7a9f6ab1..89caec92aa 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -194,9 +194,9 @@ static bool audio_is_initialized = false;
/* TBD: Split out "audio" and "playback" (ie. calling) threads */
/* Main state control */
-static volatile bool audio_codec_loaded; /* Is codec loaded? (C/A-) */
-static volatile bool playing; /* Is audio playing? (A) */
-static volatile bool paused; /* Is audio paused? (A/C-) */
+static volatile bool audio_codec_loaded NOCACHEBSS_ATTR;/* Codec loaded? (C/A-) */
+static volatile bool playing NOCACHEBSS_ATTR; /* Is audio playing? (A) */
+static volatile bool paused NOCACHEBSS_ATTR; /* Is audio paused? (A/C-) */
static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */
/* Ring buffer where compressed audio and codecs are loaded */
@@ -290,7 +290,7 @@ static void audio_reset_buffer(size_t pcmbufsize);
/* Codec thread */
extern struct codec_api ci;
-static struct event_queue codec_queue;
+static struct event_queue codec_queue NOCACHEBSS_ATTR;
static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
IBSS_ATTR;
static const char codec_thread_name[] = "codec";
@@ -304,7 +304,7 @@ static volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */
extern struct codec_api ci_voice;
static struct thread_entry *voice_thread_p = NULL;
-static struct event_queue voice_queue;
+static struct event_queue voice_queue NOCACHEBSS_ATTR;
static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
IBSS_ATTR_VOICE_STACK;
static const char voice_thread_name[] = "voice codec";
@@ -324,12 +324,12 @@ static unsigned char *iram_buf[2] = { NULL, NULL };
/* Pointer to DRAM buffers for normal/voice codecs */
static unsigned char *dram_buf[2] = { NULL, NULL };
/* Mutex to control which codec (normal/voice) is running */
-static struct mutex mutex_codecthread;
+static struct mutex mutex_codecthread NOCACHEBSS_ATTR;
/* Voice state */
static volatile bool voice_thread_start; /* Triggers voice playback (A/V) */
-static volatile bool voice_is_playing; /* Is voice currently playing? (V) */
-static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */
+static volatile bool voice_is_playing NOCACHEBSS_ATTR; /* Is voice currently playing? (V) */
+static volatile bool voice_codec_loaded NOCACHEBSS_ATTR; /* Is voice codec loaded (V/A-) */
static char *voicebuf;
static size_t voice_remaining;
@@ -863,7 +863,8 @@ void audio_preinit(void)
queue_init(&codec_queue, true);
create_thread(audio_thread, audio_stack, sizeof(audio_stack),
- audio_thread_name IF_PRIO(, PRIORITY_BUFFERING));
+ audio_thread_name IF_PRIO(, PRIORITY_BUFFERING)
+ IF_COP(, CPU, false));
}
void audio_init(void)
@@ -888,7 +889,7 @@ void voice_init(void)
queue_init(&voice_queue, true);
voice_thread_p = create_thread(voice_thread, voice_stack,
sizeof(voice_stack), voice_thread_name
- IF_PRIO(, PRIORITY_PLAYBACK));
+ IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU, false));
while (!voice_codec_loaded)
yield();
@@ -3533,7 +3534,8 @@ static void audio_playback_init(void)
codec_thread_p = create_thread(
codec_thread, codec_stack, sizeof(codec_stack),
- codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK));
+ codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
+ IF_COP(, COP, true));
while (1)
{
diff --git a/apps/playlist.c b/apps/playlist.c
index 6997b12675..0358b6adc4 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -1873,7 +1873,8 @@ void playlist_init(void)
memset(playlist->filenames, 0,
playlist->max_playlist_size * sizeof(int));
create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack),
- playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND));
+ playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
+ IF_COP(, CPU, false));
queue_init(&playlist_queue, true);
#endif
}
diff --git a/apps/plugin.c b/apps/plugin.c
index 5bbff96b04..230b62b819 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -481,7 +481,6 @@ static const struct plugin_api rockbox_api = {
sound_default,
pcm_record_more,
#endif
- create_thread_on_core,
#ifdef IRIVER_H100_SERIES
/* Routines for the iriver_flash -plugin. */
diff --git a/apps/plugin.h b/apps/plugin.h
index 48e9c40196..1d161783a1 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -327,7 +327,8 @@ struct plugin_api {
long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
struct thread_entry* (*create_thread)(void (*function)(void), void* stack,
int stack_size, const char *name
- IF_PRIO(, int priority));
+ IF_PRIO(, int priority)
+ IF_COP(, unsigned int core, bool fallback));
void (*remove_thread)(struct thread_entry *thread);
void (*reset_poweroff_timer)(void);
#ifndef SIMULATOR
@@ -595,11 +596,6 @@ struct plugin_api {
void (*pcm_record_more)(void *start, size_t size);
#endif
- struct thread_entry*(*create_thread_on_core)(
- unsigned int core, void (*function)(void),
- void* stack, int stack_size,
- const char *name IF_PRIO(, int priority));
-
#ifdef IRIVER_H100_SERIES
/* Routines for the iriver_flash -plugin. */
bool (*detect_original_firmware)(void);
diff --git a/apps/plugins/alpine_cdc.c b/apps/plugins/alpine_cdc.c
index 9c1bc8bd0b..9cc1f9cde4 100644
--- a/apps/plugins/alpine_cdc.c
+++ b/apps/plugins/alpine_cdc.c
@@ -1171,7 +1171,8 @@ int main(void* parameter)
rb->memset(&gTread, 0, sizeof(gTread));
gTread.foreground = true;
rb->create_thread(thread, stack, stacksize, "CDC"
- IF_PRIO(, PRIORITY_BACKGROUND));
+ IF_PRIO(, PRIORITY_BACKGROUND)
+ IF_COP(, CPU, false));
#ifdef DEBUG
do
diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c
index fff3c2fa57..6e3178237f 100644
--- a/apps/plugins/battery_bench.c
+++ b/apps/plugins/battery_bench.c
@@ -479,7 +479,8 @@ int main(void)
rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
if(rb->create_thread(thread, thread_stack,
sizeof(thread_stack), "Battery Benchmark"
- IF_PRIO(, PRIORITY_BACKGROUND)) == NULL)
+ IF_PRIO(, PRIORITY_BACKGROUND)
+ IF_COP(, CPU, false)) == NULL)
{
rb->splash(HZ,true,"Cannot create thread!");
return PLUGIN_ERROR;
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 36f54dc224..684a491872 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -909,19 +909,17 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
videostatus = STREAM_PLAYING;
/* We put the video thread on the second processor for multi-core targets. */
-#if NUM_CORES > 1
- if ((videothread_id = rb->create_thread_on_core(COP,decode_mpeg2,
-#else
if ((videothread_id = rb->create_thread(decode_mpeg2,
-#endif
- (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK))) == NULL)
+ (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK)
+ IF_COP(, COP, true))) == NULL)
{
rb->splash(HZ,true,"Cannot create video thread!");
return PLUGIN_ERROR;
}
if ((audiothread_id = rb->create_thread(mad_decode,
- (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK))) == NULL)
+ (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK)
+ IF_COP(, CPU, false))) == NULL)
{
rb->splash(HZ,true,"Cannot create audio thread!");
rb->remove_thread(videothread_id);
diff --git a/apps/tagcache.c b/apps/tagcache.c
index a6a0168353..6b891f1011 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -3941,7 +3941,8 @@ void tagcache_init(void)
queue_init(&tagcache_queue, true);
create_thread(tagcache_thread, tagcache_stack,
sizeof(tagcache_stack), tagcache_thread_name
- IF_PRIO(, PRIORITY_BACKGROUND));
+ IF_PRIO(, PRIORITY_BACKGROUND)
+ IF_COP(, CPU, false));
#else
tc_stat.initialized = true;
allocate_tempbuf();
diff --git a/docs/PLUGIN_API b/docs/PLUGIN_API
index e24d70fece..feba0868fb 100644
--- a/docs/PLUGIN_API
+++ b/docs/PLUGIN_API
@@ -431,7 +431,8 @@ Kernel
SYS_USB_CONNECTED. Else do nothing and return 0.
int create_thread(void* function, void* stack, int stack_size,
- const char *name);
+ const char *name IF_PRIO(int priority)
+ IF_COP(, unsigned int core, bool fallback));
Create a thread.
??? (see firmware/thread.c:145)
diff --git a/firmware/backlight.c b/firmware/backlight.c
index a273b94a38..1e8dd46b2d 100644
--- a/firmware/backlight.c
+++ b/firmware/backlight.c
@@ -582,7 +582,8 @@ void backlight_init(void)
create_thread(backlight_thread, backlight_stack,
sizeof(backlight_stack), backlight_thread_name
- IF_PRIO(, PRIORITY_SYSTEM));
+ IF_PRIO(, PRIORITY_SYSTEM)
+ IF_COP(, CPU, false));
tick_add_task(backlight_tick);
}
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index fd9796c0d8..f78fa2d0cf 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -701,7 +701,8 @@ void dircache_init(void)
queue_init(&dircache_queue, true);
create_thread(dircache_thread, dircache_stack,
- sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND));
+ sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
+ IF_COP(, CPU, false));
}
/**
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 21376ab9a7..76c0090a12 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -991,7 +991,8 @@ int ata_init(void)
last_disk_activity = current_tick;
create_thread(ata_thread, ata_stack,
sizeof(ata_stack), ata_thread_name
- IF_PRIO(, PRIORITY_SYSTEM));
+ IF_PRIO(, PRIORITY_SYSTEM)
+ IF_COP(, CPU, false));
initialized = true;
}
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index a549624b2c..377d2444bf 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -1173,7 +1173,8 @@ int ata_init(void)
queue_init(&mmc_queue, true);
create_thread(mmc_thread, mmc_stack,
- sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM));
+ sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM)
+ IF_COP(, CPU, false));
tick_add_task(mmc_tick);
initialized = true;
}
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index d545bf3fe4..7269e54dcd 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -89,7 +89,8 @@ void lcd_init(void)
create_thread(scroll_thread, scroll_stack,
sizeof(scroll_stack), scroll_name
- IF_PRIO(, PRIORITY_USER_INTERFACE));
+ IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU, false));
}
/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c
index 62dfab0180..64c1ace292 100644
--- a/firmware/drivers/lcd-1bit-vert.c
+++ b/firmware/drivers/lcd-1bit-vert.c
@@ -68,7 +68,8 @@ void lcd_init(void)
/* Call device specific init */
lcd_init_device();
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU, false));
}
/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index 9ba52e1ba9..475e466c42 100644
--- a/firmware/drivers/lcd-2bit-horz.c
+++ b/firmware/drivers/lcd-2bit-horz.c
@@ -79,7 +79,8 @@ void lcd_init(void)
/* Call device specific init */
lcd_init_device();
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU, false));
}
/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c
index 7b3352b9d6..7a49f35312 100644
--- a/firmware/drivers/lcd-2bit-vert.c
+++ b/firmware/drivers/lcd-2bit-vert.c
@@ -82,7 +82,8 @@ void lcd_init(void)
/* Call device specific init */
lcd_init_device();
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU, false));
}
/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c
index 8ca81473fc..c863c9f188 100644
--- a/firmware/drivers/lcd-player.c
+++ b/firmware/drivers/lcd-player.c
@@ -610,7 +610,8 @@ void lcd_init (void)
lcd_set_contrast(lcd_default_contrast());
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU, false));
}
void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
diff --git a/firmware/drivers/lcd-remote-1bit-v.c b/firmware/drivers/lcd-remote-1bit-v.c
index c81ccc83c9..0aa3d890f7 100644
--- a/firmware/drivers/lcd-remote-1bit-v.c
+++ b/firmware/drivers/lcd-remote-1bit-v.c
@@ -903,5 +903,6 @@ void lcd_remote_init(void)
queue_init(&remote_scroll_queue, false);
#endif
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU, false));
}
diff --git a/firmware/drivers/lcd-remote-2bit-vi.c b/firmware/drivers/lcd-remote-2bit-vi.c
index 281cbc2189..e0f6b35004 100644
--- a/firmware/drivers/lcd-remote-2bit-vi.c
+++ b/firmware/drivers/lcd-remote-2bit-vi.c
@@ -1241,5 +1241,6 @@ void lcd_remote_init(void)
queue_init(&remote_scroll_queue, false);
#endif
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU, false));
}
diff --git a/firmware/export/config.h b/firmware/export/config.h
index d848d16155..13fb77661d 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -273,21 +273,6 @@
/* define for all cpus from PP family */
#if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) || (CONFIG_CPU == PP5024)
#define CPU_PP
-
-/* PP family has dual cores */
-#if 0
-/* Keep it as single core until dual core support is ready */
-#define NUM_CORES 2
-#define CURRENT_CORE current_core()
-#endif
-
-#define NUM_CORES 1
-#define CURRENT_CORE 0
-
-#define COP_REBOOT 0x00000001
-#else
-#define NUM_CORES 1
-#define CURRENT_CORE 0
#endif
/* define for all cpus from ARM family */
@@ -348,4 +333,28 @@
#define IRAM_LCDFRAMEBUFFER
#endif
+/* Dual core support - not yet working on the 3G iPod */
+#if defined(CPU_PP) && CONFIG_CPU != PP5002
+#define NUM_CORES 2
+#define CURRENT_CORE current_core()
+/* Hopefully at some point we will learn how to mark areas of main memory as
+ * not to be cached. Until then, use IRAM for variables shared across cores */
+#define NOCACHEBSS_ATTR IBSS_ATTR
+#define NOCACHEDATA_ATTR IDATA_ATTR
+
+#define IF_COP(empty, x, y) , x, y
+
+/* Defines for inter-core messaging */
+#define COP_REBOOT 1
+
+#else
+#define NUM_CORES 1
+#define CURRENT_CORE CPU
+#define NOCACHEBSS_ATTR
+#define NOCACHEDATA_ATTR
+
+#define IF_COP(empty, x, y)
+
+#endif /* Processor specific */
+
#endif
diff --git a/firmware/export/pp5002.h b/firmware/export/pp5002.h
index ef131fe6d6..9636313390 100644
--- a/firmware/export/pp5002.h
+++ b/firmware/export/pp5002.h
@@ -73,6 +73,9 @@
#define CPU_INT_STAT (*(volatile unsigned long*)(0xcf001000))
#define CPU_INT_EN (*(volatile unsigned long*)(0xcf001024))
#define CPU_INT_CLR (*(volatile unsigned long*)(0xcf001028))
+#define COP_INT_STAT (*(volatile unsigned long*)(0xcf001010)) /* A guess */
+#define COP_INT_EN (*(volatile unsigned long*)(0xcf001034))
+#define COP_INT_CLR (*(volatile unsigned long*)(0xcf001038))
#define USB2D_IDENT (*(volatile unsigned long*)(0xc5000000))
#define USB_STATUS (*(volatile unsigned long*)(0xc50001a4))
diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h
index 3d205a0ea1..a34f1251c9 100644
--- a/firmware/export/pp5020.h
+++ b/firmware/export/pp5020.h
@@ -30,6 +30,15 @@
#define PROC_ID_CPU 0x55
#define PROC_ID_COP 0xaa
+/* Mailboxes */
+/* Each processor has two mailboxes it can write to and two which
+ it can read from. We define the first to be for sending messages
+ and the second for replying to messages */
+#define CPU_MESSAGE (*(volatile unsigned long *)(0x60001000))
+#define COP_MESSAGE (*(volatile unsigned long *)(0x60001004))
+#define CPU_REPLY (*(volatile unsigned long *)(0x60001008))
+#define COP_REPLY (*(volatile unsigned long *)(0x6000100c))
+
/* Interrupts */
#define CPU_INT_STAT (*(volatile unsigned long*)(0x64004000))
#define COP_INT_STAT (*(volatile unsigned long*)(0x60004004))
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index bced98ea23..2ff4694159 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -124,13 +124,8 @@ struct core_entry {
struct thread_entry*
create_thread(void (*function)(void), void* stack, int stack_size,
- const char *name IF_PRIO(, int priority));
-
-struct thread_entry*
- create_thread_on_core(unsigned int core, void (*function)(void),
- void* stack, int stack_size,
- const char *name
- IF_PRIO(, int priority));
+ const char *name IF_PRIO(, int priority)
+ IF_COP(, unsigned int core, bool fallback));
#ifdef HAVE_SCHEDULER_BOOSTCTRL
void trigger_cpu_boost(void);
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 75c6604682..313530ffba 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -26,7 +26,7 @@
#include "panic.h"
#if !defined(CPU_PP) || !defined(BOOTLOADER)
-long current_tick = 0;
+long current_tick NOCACHEDATA_ATTR = 0;
#endif
static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
@@ -45,10 +45,13 @@ void kernel_init(void)
/* Init the threading API */
init_threads();
- memset(tick_funcs, 0, sizeof(tick_funcs));
+ if(CURRENT_CORE == CPU)
+ {
+ memset(tick_funcs, 0, sizeof(tick_funcs));
- num_queues = 0;
- memset(all_queues, 0, sizeof(all_queues));
+ num_queues = 0;
+ memset(all_queues, 0, sizeof(all_queues));
+ }
tick_start(1000/HZ);
}
@@ -496,28 +499,36 @@ void TIMER1(void)
int i;
TIMER1_VAL; /* Read value to ack IRQ */
- /* Run through the list of tick tasks */
- for (i = 0;i < MAX_NUM_TICK_TASKS;i++)
+ /* Run through the list of tick tasks (using main core) */
+ if (CURRENT_CORE == CPU)
{
- if (tick_funcs[i])
+ for (i = 0;i < MAX_NUM_TICK_TASKS;i++)
{
- tick_funcs[i]();
+ if (tick_funcs[i])
+ {
+ tick_funcs[i]();
+ }
}
- }
- current_tick++;
+ current_tick++;
+ }
}
#endif
void tick_start(unsigned int interval_in_ms)
{
#ifndef BOOTLOADER
- TIMER1_CFG = 0x0;
- TIMER1_VAL;
- /* enable timer */
- TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1);
- /* unmask interrupt source */
- CPU_INT_EN = TIMER1_MASK;
+ if(CURRENT_CORE == CPU)
+ {
+ TIMER1_CFG = 0x0;
+ TIMER1_VAL;
+ /* enable timer */
+ TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1);
+ /* unmask interrupt source */
+ CPU_INT_EN = TIMER1_MASK;
+ } else {
+ COP_INT_EN = TIMER1_MASK;
+ }
#else
/* We don't enable interrupts in the bootloader */
(void)interval_in_ms;
@@ -645,6 +656,29 @@ void mutex_init(struct mutex *m)
m->thread = NULL;
}
+#ifdef CPU_PP
+/* PortalPlayer chips have 2 cores, therefore need atomic mutexes */
+
+static inline bool test_and_set(bool *x, bool v)
+{
+ asm volatile (
+ "swpb %0, %0, [%1]\n"
+ : "+r"(v)
+ : "r"(x)
+ );
+ return v;
+}
+
+void mutex_lock(struct mutex *m)
+{
+ if (test_and_set(&m->locked,true))
+ {
+ /* Wait until the lock is open... */
+ block_thread(&m->thread);
+ }
+}
+
+#else
void mutex_lock(struct mutex *m)
{
if (m->locked)
@@ -656,6 +690,7 @@ void mutex_lock(struct mutex *m)
/* ...and lock it */
m->locked = true;
}
+#endif
void mutex_unlock(struct mutex *m)
{
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 9afa8a20bd..909a21dcda 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -2905,7 +2905,8 @@ void audio_init(void)
queue_init(&mpeg_queue, true);
#endif /* !SIMULATOR */
create_thread(mpeg_thread, mpeg_stack,
- sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM));
+ sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM)
+ IF_COP(, CPU, false));
memset(trackdata, sizeof(trackdata), 0);
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 270bb354d2..3f4abc7be3 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -418,7 +418,8 @@ void pcm_rec_init(void)
queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send);
pcmrec_thread_p =
create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),
- pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING));
+ pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)
+ IF_COP(, CPU, false));
} /* pcm_rec_init */
/** audio_* group **/
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index c2f9ca0bca..1492c80bc4 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -1245,7 +1245,8 @@ void powermgmt_init(void)
/* init history to 0 */
memset(power_history, 0x00, sizeof(power_history));
create_thread(power_thread, power_stack, sizeof(power_stack),
- power_thread_name IF_PRIO(, PRIORITY_SYSTEM));
+ power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
+ IF_COP(, CPU, false));
}
#endif /* SIMULATOR */
diff --git a/firmware/system.c b/firmware/system.c
index a86d945093..a9c9d9e350 100644
--- a/firmware/system.c
+++ b/firmware/system.c
@@ -612,12 +612,22 @@ extern void ipod_mini_button_int(void);
void irq(void)
{
- if (CPU_INT_STAT & TIMER1_MASK)
- TIMER1();
- else if (CPU_INT_STAT & TIMER2_MASK)
- TIMER2();
- else if (CPU_HI_INT_STAT & GPIO_MASK)
- ipod_mini_button_int();
+ if(CURRENT_CORE == CPU)
+ {
+ if (CPU_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (CPU_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ else if (CPU_HI_INT_STAT & GPIO_MASK)
+ ipod_mini_button_int();
+ } else {
+ if (COP_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (COP_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ else if (COP_HI_INT_STAT & GPIO_MASK)
+ ipod_mini_button_int();
+ }
}
#elif (defined IRIVER_H10) || (defined IRIVER_H10_5GB) || defined(ELIO_TPJ1022) \
|| (defined SANSA_E200)
@@ -626,22 +636,40 @@ void irq(void)
/* TODO: Even if it isn't in the target tree, this should be the default case */
void irq(void)
{
- if (CPU_INT_STAT & TIMER1_MASK)
- TIMER1();
- else if (CPU_INT_STAT & TIMER2_MASK)
- TIMER2();
+ if(CURRENT_CORE == CPU)
+ {
+ if (CPU_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (CPU_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ } else {
+ if (COP_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (COP_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ }
}
#else
extern void ipod_4g_button_int(void);
void irq(void)
{
- if (CPU_INT_STAT & TIMER1_MASK)
- TIMER1();
- else if (CPU_INT_STAT & TIMER2_MASK)
- TIMER2();
- else if (CPU_HI_INT_STAT & I2C_MASK)
- ipod_4g_button_int();
+ if(CURRENT_CORE == CPU)
+ {
+ if (CPU_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (CPU_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ else if (CPU_HI_INT_STAT & I2C_MASK)
+ ipod_4g_button_int();
+ } else {
+ if (COP_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (COP_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ else if (COP_HI_INT_STAT & I2C_MASK)
+ ipod_4g_button_int();
+ }
}
#endif
#endif /* BOOTLOADER */
@@ -694,43 +722,47 @@ void set_cpu_frequency(long frequency)
{
unsigned long postmult;
- if (frequency == CPUFREQ_NORMAL)
- postmult = CPUFREQ_NORMAL_MULT;
- else if (frequency == CPUFREQ_MAX)
- postmult = CPUFREQ_MAX_MULT;
- else
- postmult = CPUFREQ_DEFAULT_MULT;
- cpu_frequency = frequency;
+ if (CURRENT_CORE == CPU)
+ {
+ if (frequency == CPUFREQ_NORMAL)
+ postmult = CPUFREQ_NORMAL_MULT;
+ else if (frequency == CPUFREQ_MAX)
+ postmult = CPUFREQ_MAX_MULT;
+ else
+ postmult = CPUFREQ_DEFAULT_MULT;
+ cpu_frequency = frequency;
- /* Enable PLL? */
- outl(inl(0x70000020) | (1<<30), 0x70000020);
+ /* Enable PLL? */
+ outl(inl(0x70000020) | (1<<30), 0x70000020);
- /* Select 24MHz crystal as clock source? */
- outl((inl(0x60006020) & 0x0fffff0f) | 0x20000020, 0x60006020);
+ /* Select 24MHz crystal as clock source? */
+ outl((inl(0x60006020) & 0x0fffff0f) | 0x20000020, 0x60006020);
- /* Clock frequency = (24/8)*postmult */
- outl(0xaa020000 | 8 | (postmult << 8), 0x60006034);
+ /* Clock frequency = (24/8)*postmult */
+ outl(0xaa020000 | 8 | (postmult << 8), 0x60006034);
- /* Wait for PLL relock? */
- udelay(2000);
+ /* Wait for PLL relock? */
+ udelay(2000);
- /* Select PLL as clock source? */
- outl((inl(0x60006020) & 0x0fffff0f) | 0x20000070, 0x60006020);
+ /* Select PLL as clock source? */
+ outl((inl(0x60006020) & 0x0fffff0f) | 0x20000070, 0x60006020);
#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
- /* We don't know why the timer interrupt gets disabled on the PP5020
- based ipods, but without the following line, the 4Gs will freeze
- when CPU frequency changing is enabled.
+ /* We don't know why the timer interrupt gets disabled on the PP5020
+ based ipods, but without the following line, the 4Gs will freeze
+ when CPU frequency changing is enabled.
- Note also that a simple "CPU_INT_EN = TIMER1_MASK;" (as used
- elsewhere to enable interrupts) doesn't work, we need "|=".
+ Note also that a simple "CPU_INT_EN = TIMER1_MASK;" (as used
+ elsewhere to enable interrupts) doesn't work, we need "|=".
- It's not needed on the PP5021 and PP5022 ipods.
- */
+ It's not needed on the PP5021 and PP5022 ipods.
+ */
- /* unmask interrupt source */
- CPU_INT_EN |= TIMER1_MASK;
+ /* unmask interrupt source */
+ CPU_INT_EN |= TIMER1_MASK;
+ COP_INT_EN |= TIMER1_MASK;
#endif
+ }
}
#elif !defined(BOOTLOADER)
void ipod_set_cpu_frequency(void)
@@ -754,24 +786,33 @@ void ipod_set_cpu_frequency(void)
void system_init(void)
{
#ifndef BOOTLOADER
- /* Remap the flash ROM from 0x00000000 to 0x20000000. */
- MMAP3_LOGICAL = 0x20000000 | 0x3a00;
- MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
-
- /* The hw revision is written to the last 4 bytes of SDRAM by the
- bootloader - we save it before Rockbox overwrites it. */
- ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc)));
-
- /* disable all irqs */
- outl(-1, 0x60001138);
- outl(-1, 0x60001128);
- outl(-1, 0x6000111c);
-
- outl(-1, 0x60001038);
- outl(-1, 0x60001028);
- outl(-1, 0x6000101c);
-#ifndef HAVE_ADJUSTABLE_CPU_FREQ
- ipod_set_cpu_frequency();
+ if (CURRENT_CORE == CPU)
+ {
+ /* Remap the flash ROM from 0x00000000 to 0x20000000. */
+ MMAP3_LOGICAL = 0x20000000 | 0x3a00;
+ MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
+
+ /* The hw revision is written to the last 4 bytes of SDRAM by the
+ bootloader - we save it before Rockbox overwrites it. */
+ ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc)));
+
+ /* disable all irqs */
+ outl(-1, 0x60001138);
+ outl(-1, 0x60001128);
+ outl(-1, 0x6000111c);
+
+ outl(-1, 0x60001038);
+ outl(-1, 0x60001028);
+ outl(-1, 0x6000101c);
+#if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES == 1)
+ ipod_set_cpu_frequency();
+#endif
+ }
+#if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1)
+ else
+ {
+ ipod_set_cpu_frequency();
+ }
#endif
ipod_init_cache();
#endif
@@ -796,10 +837,18 @@ extern void TIMER2(void);
void irq(void)
{
- if (CPU_INT_STAT & TIMER1_MASK)
- TIMER1();
- else if (CPU_INT_STAT & TIMER2_MASK)
- TIMER2();
+ if(CURRENT_CORE == CPU)
+ {
+ if (CPU_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (CPU_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ } else {
+ if (COP_INT_STAT & TIMER1_MASK)
+ TIMER1();
+ else if (COP_INT_STAT & TIMER2_MASK)
+ TIMER2();
+ }
}
#endif
@@ -848,29 +897,32 @@ void set_cpu_frequency(long frequency)
{
unsigned long postmult;
- if (frequency == CPUFREQ_NORMAL)
- postmult = CPUFREQ_NORMAL_MULT;
- else if (frequency == CPUFREQ_MAX)
- postmult = CPUFREQ_MAX_MULT;
- else
- postmult = CPUFREQ_DEFAULT_MULT;
- cpu_frequency = frequency;
+ if (CURRENT_CORE == CPU)
+ {
+ if (frequency == CPUFREQ_NORMAL)
+ postmult = CPUFREQ_NORMAL_MULT;
+ else if (frequency == CPUFREQ_MAX)
+ postmult = CPUFREQ_MAX_MULT;
+ else
+ postmult = CPUFREQ_DEFAULT_MULT;
+ cpu_frequency = frequency;
- outl(0x02, 0xcf005008);
- outl(0x55, 0xcf00500c);
- outl(0x6000, 0xcf005010);
+ outl(0x02, 0xcf005008);
+ outl(0x55, 0xcf00500c);
+ outl(0x6000, 0xcf005010);
- /* Clock frequency = (24/8)*postmult */
- outl(8, 0xcf005018);
- outl(postmult, 0xcf00501c);
+ /* Clock frequency = (24/8)*postmult */
+ outl(8, 0xcf005018);
+ outl(postmult, 0xcf00501c);
- outl(0xe000, 0xcf005010);
+ outl(0xe000, 0xcf005010);
- /* Wait for PLL relock? */
- udelay(2000);
+ /* Wait for PLL relock? */
+ udelay(2000);
- /* Select PLL as clock source? */
- outl(0xa8, 0xcf00500c);
+ /* Select PLL as clock source? */
+ outl(0xa8, 0xcf00500c);
+ }
}
#elif !defined(BOOTLOADER)
static void ipod_set_cpu_speed(void)
@@ -901,17 +953,20 @@ static void ipod_set_cpu_speed(void)
void system_init(void)
{
#ifndef BOOTLOADER
- /* Remap the flash ROM from 0x00000000 to 0x20000000. */
- MMAP3_LOGICAL = 0x20000000 | 0x3a00;
- MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
-
- ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc)));
- outl(-1, 0xcf00101c);
- outl(-1, 0xcf001028);
- outl(-1, 0xcf001038);
+ if (CURRENT_CORE == CPU)
+ {
+ /* Remap the flash ROM from 0x00000000 to 0x20000000. */
+ MMAP3_LOGICAL = 0x20000000 | 0x3a00;
+ MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
+
+ ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc)));
+ outl(-1, 0xcf00101c);
+ outl(-1, 0xcf001028);
+ outl(-1, 0xcf001038);
#ifndef HAVE_ADJUSTABLE_CPU_FREQ
- ipod_set_cpu_speed();
+ ipod_set_cpu_speed();
#endif
+ }
ipod_init_cache();
#endif
}
diff --git a/firmware/target/arm/crt0-pp.S b/firmware/target/arm/crt0-pp.S
index e0d1034f74..bbeace1b60 100644
--- a/firmware/target/arm/crt0-pp.S
+++ b/firmware/target/arm/crt0-pp.S
@@ -222,6 +222,19 @@ cop_init:
strhi r4, [r2], #4
bhi 2b
+ /* Set up stack for IRQ mode */
+ msr cpsr_c, #0xd2
+ ldr sp, =cop_irq_stack
+ /* Set up stack for FIQ mode */
+ msr cpsr_c, #0xd1
+ ldr sp, =fiq_stack
+
+ /* Let abort and undefined modes use IRQ stack */
+ msr cpsr_c, #0xd7
+ ldr sp, =cop_irq_stack
+ msr cpsr_c, #0xdb
+ ldr sp, =cop_irq_stack
+
ldr sp, =cop_stackend
/* Run cop_main() in apps/main.c */
@@ -307,6 +320,10 @@ UIE:
.space 256*4
irq_stack:
+/* 256 words of COP IRQ stack */
+ .space 256*4
+cop_irq_stack:
+
/* 256 words of FIQ stack */
.space 256*4
fiq_stack:
diff --git a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c
index cf05397a78..73a67d1ee6 100644
--- a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c
+++ b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c
@@ -687,7 +687,8 @@ int ata_init(void)
{
queue_init(&sd_queue, true);
create_thread(sd_thread, sd_stack,
- sizeof(sd_stack), sd_thread_name IF_PRIO(, PRIORITY_SYSTEM));
+ sizeof(sd_stack), sd_thread_name IF_PRIO(, PRIORITY_SYSTEM)
+ IF_COP(, CPU, false));
initialized = true;
}
diff --git a/firmware/thread.c b/firmware/thread.c
index 2281f43e53..281ab0fa54 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -64,6 +64,10 @@ int *cop_stackend = stackend;
#endif
#endif
+#if (NUM_CORES > 1)
+bool IDATA_ATTR kernel_running_on_cop = false;
+#endif
+
/* Conserve IRAM
static void add_to_list(struct thread_entry **list,
struct thread_entry *thread) ICODE_ATTR;
@@ -316,10 +320,13 @@ static inline void sleep_core(void)
#elif CONFIG_CPU == SH7034
and_b(0x7F, &SBYCR);
asm volatile ("sleep");
-#elif CONFIG_CPU == PP5020
+#elif defined (CPU_PP)
/* This should sleep the CPU. It appears to wake by itself on
interrupts */
- CPU_CTL = 0x80000000;
+ if (CURRENT_CORE == CPU)
+ CPU_CTL = PROC_SLEEP;
+ else
+ COP_CTL = PROC_SLEEP;
#elif CONFIG_CPU == S3C2440
CLKCON |= (1 << 2); /* set IDLE bit */
for(i=0; i<10; i++); /* wait for IDLE */
@@ -608,27 +615,16 @@ void wakeup_thread(struct thread_entry **list)
}
/*---------------------------------------------------------------------------
- * Create thread on the current core.
- * Return ID if context area could be allocated, else -1.
+ * Create a thread
+ * If using a dual core architecture, specify which core to start the thread
+ * on, and whether to fall back to the other core if it can't be created
+ * Return ID if context area could be allocated, else NULL.
*---------------------------------------------------------------------------
*/
struct thread_entry*
create_thread(void (*function)(void), void* stack, int stack_size,
- const char *name IF_PRIO(, int priority))
-{
- return create_thread_on_core(CURRENT_CORE, function, stack, stack_size,
- name IF_PRIO(, priority));
-}
-
-/*---------------------------------------------------------------------------
- * Create thread on a specific core.
- * Return ID if context area could be allocated, else -1.
- *---------------------------------------------------------------------------
- */
-struct thread_entry*
- create_thread_on_core(unsigned int core, void (*function)(void),
- void* stack, int stack_size,
- const char *name IF_PRIO(, int priority))
+ const char *name IF_PRIO(, int priority)
+ IF_COP(, unsigned int core, bool fallback))
{
unsigned int i;
unsigned int stacklen;
@@ -637,6 +633,29 @@ struct thread_entry*
struct regs *regs;
struct thread_entry *thread;
+/*****
+ * Ugly code alert!
+ * To prevent ifdef hell while keeping the binary size down, we define
+ * core here if it hasn't been passed as a parameter
+ *****/
+#if NUM_CORES == 1
+#define core CPU
+#endif
+
+#if NUM_CORES > 1
+/* If the kernel hasn't initialised on the COP (most likely due to an old
+ * bootloader) then refuse to start threads on the COP
+ */
+ if((core == COP) && !kernel_running_on_cop)
+ {
+ if (fallback)
+ return create_thread(function, stack, stack_size, name
+ IF_PRIO(, priority) IF_COP(, CPU, false));
+ else
+ return NULL;
+ }
+#endif
+
for (n = 0; n < MAXTHREADS; n++)
{
if (cores[core].threads[n].name == NULL)
@@ -644,8 +663,15 @@ struct thread_entry*
}
if (n == MAXTHREADS)
- return NULL;
-
+ {
+#if NUM_CORES > 1
+ if (fallback)
+ return create_thread(function, stack, stack_size, name
+ IF_PRIO(, priority) IF_COP(, 1 - core, fallback));
+ else
+#endif
+ return NULL;
+ }
/* Munge the stack to make it easy to spot stack overflows */
stacklen = stack_size / sizeof(int);
@@ -677,6 +703,9 @@ struct thread_entry*
THREAD_CPU_INIT(core, thread);
return thread;
+#if NUM_CORES == 1
+#undef core
+#endif
}
#ifdef HAVE_SCHEDULER_BOOSTCTRL
@@ -751,7 +780,8 @@ void init_threads(void)
{
unsigned int core = CURRENT_CORE;
- memset(cores, 0, sizeof cores);
+ if (core == CPU)
+ memset(cores, 0, sizeof cores);
cores[core].sleeping = NULL;
cores[core].running = NULL;
cores[core].threads[0].name = main_thread_name;
@@ -779,6 +809,10 @@ void init_threads(void)
#endif
}
cores[core].threads[0].context.start = 0; /* thread 0 already running */
+#if NUM_CORES > 1
+ if(core == COP)
+ kernel_running_on_cop = true; /* can we use context.start for this? */
+#endif
}
int thread_stack_usage(const struct thread_entry *thread)
diff --git a/firmware/usb.c b/firmware/usb.c
index ee08b04caa..cf4641950e 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -428,7 +428,8 @@ void usb_init(void)
#ifndef BOOTLOADER
queue_init(&usb_queue, true);
create_thread(usb_thread, usb_stack, sizeof(usb_stack),
- usb_thread_name IF_PRIO(, PRIORITY_SYSTEM));
+ usb_thread_name IF_PRIO(, PRIORITY_SYSTEM)
+ IF_COP(, CPU, false));
tick_add_task(usb_tick);
#endif
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index a993a9e0e8..8ea46824ce 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -258,12 +258,6 @@ void remove_thread(int threadnum)
(void)threadnum;
}
-void remove_thread_on_core(unsigned int core, int threadnum)
-{
- (void)core;
- (void)threadnum;
-}
-
/* assure an unused place to direct virtual pointers to */
#define VIRT_SIZE 0xFFFF /* more than enough for our string ID range */
unsigned char vp_dummy[VIRT_SIZE];
diff --git a/uisimulator/sdl/thread-sdl.c b/uisimulator/sdl/thread-sdl.c
index 041ca3153d..21697699a5 100644
--- a/uisimulator/sdl/thread-sdl.c
+++ b/uisimulator/sdl/thread-sdl.c
@@ -75,12 +75,6 @@ int create_thread(void (*fp)(void), void* sp, int stk_size)
return 0;
}
-int create_thread_on_core(void (*core)(void), void (*fp)(void), void* sp, int stk_size)
-{
- (void)core;
- return create_thread(fp, sp, stk_size);
-}
-
void init_threads(void)
{
m = SDL_CreateMutex();