1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Michael Sevakis 2007-09-28 10:20:02 +00:00
parent edbf5d81f5
commit 7914e90738
23 changed files with 684 additions and 547 deletions

View file

@ -157,6 +157,10 @@ struct codec_api ci = {
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
the API gets incompatible */ the API gets incompatible */
#ifdef CACHE_FUNCTIONS_AS_CALL
flush_icache,
invalidate_icache,
#endif
}; };
void codec_get_full_path(char *path, const char *codec_root_fn) void codec_get_full_path(char *path, const char *codec_root_fn)

View file

@ -80,7 +80,7 @@
#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define CODEC_API_VERSION 18 #define CODEC_API_VERSION 19
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
@ -230,6 +230,10 @@ struct codec_api {
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
the API gets incompatible */ the API gets incompatible */
#ifdef CACHE_FUNCTIONS_AS_CALL
void (*flush_icache)(void);
void (*invalidate_icache)(void);
#endif
}; };
/* codec header */ /* codec header */
@ -286,4 +290,22 @@ int codec_load_file(const char* codec, struct codec_api *api);
/* defined by the codec */ /* defined by the codec */
enum codec_status codec_start(struct codec_api* rockbox); enum codec_status codec_start(struct codec_api* rockbox);
#ifndef CACHE_FUNCTION_WRAPPERS
#ifdef CACHE_FUNCTIONS_AS_CALL
#define CACHE_FUNCTION_WRAPPERS(api) \
void flush_icache(void) \
{ \
(api)->flush_icache(); \
} \
void invalidate_icache(void) \
{ \
(api)->invalidate_icache(); \
}
#else
#define CACHE_FUNCTION_WRAPPERS(api)
#endif /* CACHE_FUNCTIONS_AS_CALL */
#endif /* CACHE_FUNCTION_WRAPPERS */
#endif #endif

View file

@ -32,6 +32,8 @@ extern unsigned char plugin_end_addr[];
extern enum codec_status codec_main(void); extern enum codec_status codec_main(void);
CACHE_FUNCTION_WRAPPERS(ci);
enum codec_status codec_start(struct codec_api *api) enum codec_status codec_start(struct codec_api *api)
{ {
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -180,7 +180,6 @@ static bool dbg_list(struct action_callback_info *info)
/*---------------------------------------------------*/ /*---------------------------------------------------*/
extern struct thread_entry threads[MAXTHREADS]; extern struct thread_entry threads[MAXTHREADS];
static char thread_status_char(int status) static char thread_status_char(int status)
{ {
switch (status) switch (status)
@ -193,17 +192,28 @@ static char thread_status_char(int status)
return '?'; return '?';
} }
#if NUM_CORES > 1
#define IF_COP2(...) __VA_ARGS__
#else
#define IF_COP2(...)
#endif
static char* threads_getname(int selected_item, void * data, char *buffer) static char* threads_getname(int selected_item, void * data, char *buffer)
{ {
(void)data; (void)data;
char name[32];
struct thread_entry *thread = NULL; struct thread_entry *thread = NULL;
int status, usage; unsigned status;
int usage;
#if NUM_CORES > 1
if (selected_item < (int)NUM_CORES)
{
usage = idle_stack_usage(selected_item);
snprintf(buffer, MAX_PATH, "Idle (%d): %2d%%", selected_item, usage);
return buffer;
}
selected_item -= NUM_CORES;
#endif
thread = &threads[selected_item]; thread = &threads[selected_item];
status = thread_get_status(thread);
if (thread->name == NULL) if (thread->name == NULL)
{ {
@ -211,24 +221,19 @@ static char* threads_getname(int selected_item, void * data, char *buffer)
return buffer; return buffer;
} }
thread_get_name(name, 32, thread);
usage = thread_stack_usage(thread); usage = thread_stack_usage(thread);
status = thread_get_status(thread); status = thread_get_status(thread);
#ifdef HAVE_PRIORITY_SCHEDULING
snprintf(buffer, MAX_PATH, "%2d: " IF_COP2("(%d) ") "%c%c %d %2d%% %s", snprintf(buffer, MAX_PATH,
"%2d: " IF_COP("(%d) ") "%c%c " IF_PRIO("%d ") "%2d%% %s",
selected_item, selected_item,
IF_COP2(thread->core,) IF_COP(thread->core,)
(status == STATE_RUNNING) ? '*' : ' ', (status == STATE_RUNNING) ? '*' : ' ',
thread_status_char(status), thread_status_char(status),
thread->priority, IF_PRIO(thread->priority,)
usage, thread->name); usage, name);
#else
snprintf(buffer, MAX_PATH, "%2d: " IF_COP2("(%d) ") "%c%c %2d%% %s",
selected_item,
IF_COP2(thread->core,)
(status == STATE_RUNNING) ? '*' : ' ',
thread_status_char(status),
usage, thread->name);
#endif
return buffer; return buffer;
} }
static int dbg_threads_action_callback(int action, struct action_callback_info *info) static 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 *
#ifdef ROCKBOX_HAS_LOGF #ifdef ROCKBOX_HAS_LOGF
if (action == ACTION_STD_OK) if (action == ACTION_STD_OK)
{ {
struct thread_entry *thread = &threads[gui_synclist_get_sel_pos(info->lists)]; int selpos = gui_synclist_get_sel_pos(info->lists);
if (thread->name != NULL) #if NUM_CORES > 1
remove_thread(thread); if (selpos >= NUM_CORES)
} remove_thread(&threads[selpos - NUM_CORES]);
#else
remove_thread(&threads[selpos]);
#endif #endif
}
gui_synclist_hide_selection_marker(info->lists, false);
#endif /* ROCKBOX_HAS_LOGF */
gui_synclist_draw(info->lists); gui_synclist_draw(info->lists);
return action; return action;
} }
@ -248,8 +258,12 @@ static int dbg_threads_action_callback(int action, struct action_callback_info *
static bool dbg_os(void) static bool dbg_os(void)
{ {
struct action_callback_info info; struct action_callback_info info;
info.title = IF_COP2("Core and ") "Stack usage:"; info.title = IF_COP("Core and ") "Stack usage:";
#if NUM_CORES == 1
info.count = MAXTHREADS; info.count = MAXTHREADS;
#else
info.count = MAXTHREADS+NUM_CORES;
#endif
info.selection_size = 1; info.selection_size = 1;
info.action_callback = dbg_threads_action_callback; info.action_callback = dbg_threads_action_callback;
info.dbg_getname = threads_getname; info.dbg_getname = threads_getname;

View file

@ -334,9 +334,7 @@ static void init(void)
/* if nobody initialized ATA before, I consider this a cold start */ /* if nobody initialized ATA before, I consider this a cold start */
bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */ bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */
#endif #endif
#ifdef CPU_PP
COP_CTL = PROC_WAKE;
#endif
system_init(); system_init();
kernel_init(); kernel_init();
@ -591,25 +589,19 @@ void cop_main(void)
so it should not be assumed that the coprocessor be usable even on so it should not be assumed that the coprocessor be usable even on
platforms which support it. platforms which support it.
A kernel thread runs on the coprocessor which waits for other threads to be A kernel thread is initially setup on the coprocessor and immediately
added, and gracefully handles RoLo */ destroyed for purposes of continuity. The cop sits idle until at least
one thread exists on it. */
#if CONFIG_CPU == PP5002
/* 3G doesn't have Rolo or dual core support yet */ /* 3G doesn't have Rolo or dual core support yet */
#if NUM_CORES > 1
system_init();
kernel_init();
/* This should never be reached */
#endif
while(1) { while(1) {
COP_CTL = PROC_SLEEP; COP_CTL = PROC_SLEEP;
} }
#else
extern volatile unsigned char cpu_message;
system_init();
kernel_init();
while(cpu_message != COP_REBOOT) {
sleep(HZ);
}
rolo_restart_cop();
#endif /* PP5002 */
} }
#endif /* CPU_PP */ #endif /* CPU_PP */

View file

@ -509,6 +509,11 @@ static const struct plugin_api rockbox_api = {
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
lcd_yuv_set_options, lcd_yuv_set_options,
#endif #endif
#ifdef CACHE_FUNCTIONS_AS_CALL
flush_icache,
invalidate_icache,
#endif
}; };
int plugin_load(const char* plugin, void* parameter) int plugin_load(const char* plugin, void* parameter)

View file

@ -112,7 +112,7 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 77 #define PLUGIN_API_VERSION 78
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
@ -627,6 +627,11 @@ struct plugin_api {
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
void (*lcd_yuv_set_options)(unsigned options); void (*lcd_yuv_set_options)(unsigned options);
#endif #endif
#ifdef CACHE_FUNCTIONS_AS_CALL
void (*flush_icache)(void);
void (*invalidate_icache)(void);
#endif
}; };
/* plugin header */ /* plugin header */
@ -710,4 +715,22 @@ enum plugin_status plugin_start(struct plugin_api* rockbox, void* parameter)
return (api)->memcmp(s1, s2, n); \ return (api)->memcmp(s1, s2, n); \
} }
#ifndef CACHE_FUNCTION_WRAPPERS
#ifdef CACHE_FUNCTIONS_AS_CALL
#define CACHE_FUNCTION_WRAPPERS(api) \
void flush_icache(void) \
{ \
(api)->flush_icache(); \
} \
void invalidate_icache(void) \
{ \
(api)->invalidate_icache(); \
}
#else
#define CACHE_FUNCTION_WRAPPERS(api)
#endif /* CACHE_FUNCTIONS_AS_CALL */
#endif /* CACHE_FUNCTION_WRAPPERS */
#endif #endif

View file

@ -197,6 +197,18 @@ SECTIONS
} > IRAM } > IRAM
#ifdef CPU_PP #ifdef CPU_PP
#if NUM_CORES > 1
.idle_stacks :
{
*(.idle_stacks)
cpu_idlestackbegin = .;
. += 0x0080;
cpu_idlestackend = .;
cop_idlestackbegin = .;
. += 0x0080;
cop_idlestackend = .;
} > IRAM
#else
.cop_stack : .cop_stack :
{ {
*(.cop_stack) *(.cop_stack)
@ -205,6 +217,7 @@ SECTIONS
cop_stackend = .; cop_stackend = .;
} > IRAM } > IRAM
#endif #endif
#endif
#else #else
/* TRICK ALERT! We want 0x2000 bytes of stack, but we set the section /* TRICK ALERT! We want 0x2000 bytes of stack, but we set the section

View file

@ -611,7 +611,6 @@ static void backlight_tick(void)
void backlight_init(void) void backlight_init(void)
{ {
queue_init(&backlight_queue, true); queue_init(&backlight_queue, true);
queue_set_irq_safe(&backlight_queue, true);
#ifndef SIMULATOR #ifndef SIMULATOR
if (__backlight_init()) if (__backlight_init())

View file

@ -356,10 +356,6 @@ void button_init(void)
queue_init(&button_queue, true); queue_init(&button_queue, true);
/* Enable less protection which would kill IRQ handler. Writing queue is
* no longer core-wise thread safe. */
queue_set_irq_safe(&button_queue, true);
button_read(); button_read();
lastbtn = button_read(); lastbtn = button_read();
tick_add_task(button_tick); tick_add_task(button_tick);

View file

@ -372,10 +372,10 @@
#define NOCACHEBSS_ATTR IBSS_ATTR #define NOCACHEBSS_ATTR IBSS_ATTR
#define NOCACHEDATA_ATTR IDATA_ATTR #define NOCACHEDATA_ATTR IDATA_ATTR
#define IF_COP(empty, x, y) , x, y #define IF_COP(...) __VA_ARGS__
/* Defines for inter-core messaging */ #define IDLE_STACK_SIZE 0x80
#define COP_REBOOT 1 #define IDLE_STACK_WORDS 0x20
#else #else
#define NUM_CORES 1 #define NUM_CORES 1
@ -383,7 +383,7 @@
#define NOCACHEBSS_ATTR #define NOCACHEBSS_ATTR
#define NOCACHEDATA_ATTR #define NOCACHEDATA_ATTR
#define IF_COP(empty, x, y) #define IF_COP(...)
#endif /* Processor specific */ #endif /* Processor specific */

View file

@ -94,9 +94,6 @@ struct event_queue
struct thread_entry *thread; struct thread_entry *thread;
unsigned int read; unsigned int read;
unsigned int write; unsigned int write;
#if NUM_CORES > 1
bool irq_safe;
#endif
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
struct queue_sender_list *send; struct queue_sender_list *send;
#endif #endif
@ -153,11 +150,6 @@ void timeout_register(struct timeout *tmo, timeout_cb_type callback,
void timeout_cancel(struct timeout *tmo); void timeout_cancel(struct timeout *tmo);
extern void queue_init(struct event_queue *q, bool register_queue); extern void queue_init(struct event_queue *q, bool register_queue);
#if NUM_CORES > 1
extern void queue_set_irq_safe(struct event_queue *q, bool state);
#else
#define queue_set_irq_safe(q,state)
#endif
extern void queue_delete(struct event_queue *q); extern void queue_delete(struct event_queue *q);
extern void queue_wait(struct event_queue *q, struct event *ev); extern void queue_wait(struct event_queue *q, struct event *ev);
extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks);

View file

@ -118,18 +118,18 @@
#define DEV_RS (*(volatile unsigned long *)(0x60006004)) #define DEV_RS (*(volatile unsigned long *)(0x60006004))
#define DEV_EN (*(volatile unsigned long *)(0x6000600c)) #define DEV_EN (*(volatile unsigned long *)(0x6000600c))
#define DEV_SYSTEM 0x4 #define DEV_SYSTEM 0x00000004
#define DEV_SER0 0x40 #define DEV_SER0 0x00000040
#define DEV_SER1 0x80 #define DEV_SER1 0x00000080
#define DEV_I2S 0x800 #define DEV_I2S 0x00000800
#define DEV_I2C 0x1000 #define DEV_I2C 0x00001000
#define DEV_ATA 0x4000 #define DEV_ATA 0x00004000
#define DEV_OPTO 0x10000 #define DEV_OPTO 0x00010000
#define DEV_PIEZO 0x10000 #define DEV_PIEZO 0x00010000
#define DEV_USB 0x400000 #define DEV_USB 0x00400000
#define DEV_FIREWIRE 0x800000 #define DEV_FIREWIRE 0x00800000
#define DEV_IDE0 0x2000000 #define DEV_IDE0 0x02000000
#define DEV_LCD 0x4000000 #define DEV_LCD 0x04000000
/* clock control */ /* clock control */
#define CLOCK_SOURCE (*(volatile unsigned long *)(0x60006020)) #define CLOCK_SOURCE (*(volatile unsigned long *)(0x60006020))
@ -174,6 +174,7 @@
#define CACHE_DISABLE 0 #define CACHE_DISABLE 0
#define CACHE_ENABLE 1 #define CACHE_ENABLE 1
#define CACHE_RUN 2
#define CACHE_INIT 4 #define CACHE_INIT 4
/* GPIO Ports */ /* GPIO Ports */

View file

@ -53,29 +53,29 @@
#ifdef CPU_COLDFIRE #ifdef CPU_COLDFIRE
struct regs struct regs
{ {
unsigned int macsr; /* EMAC status register */ unsigned int macsr; /* 0 - EMAC status register */
unsigned int d[6]; /* d2-d7 */ unsigned int d[6]; /* 4-24 - d2-d7 */
unsigned int a[5]; /* a2-a6 */ unsigned int a[5]; /* 28-44 - a2-a6 */
void *sp; /* Stack pointer (a7) */ void *sp; /* 48 - Stack pointer (a7) */
void *start; /* Thread start address, or NULL when started */ void *start; /* 52 - Thread start address, or NULL when started */
}; } __attribute__((packed));
#elif CONFIG_CPU == SH7034 #elif CONFIG_CPU == SH7034
struct regs struct regs
{ {
unsigned int r[7]; /* Registers r8 thru r14 */ unsigned int r[7]; /* 0-24 - Registers r8 thru r14 */
void *sp; /* Stack pointer (r15) */ void *sp; /* 28 - Stack pointer (r15) */
void *pr; /* Procedure register */ void *pr; /* 32 - Procedure register */
void *start; /* Thread start address, or NULL when started */ void *start; /* 36 - Thread start address, or NULL when started */
}; } __attribute__((packed));
#elif defined(CPU_ARM) #elif defined(CPU_ARM)
struct regs struct regs
{ {
unsigned int r[8]; /* Registers r4-r11 */ unsigned int r[8]; /* 0-28 - Registers r4-r11 */
void *sp; /* Stack pointer (r13) */ void *sp; /* 32 - Stack pointer (r13) */
unsigned int lr; /* r14 (lr) */ unsigned int lr; /* 36 - r14 (lr) */
void *start; /* Thread start address, or NULL when started */ void *start; /* 40 - Thread start address, or NULL when started */
}; } __attribute__((packed));
# endif #endif /* CONFIG_CPU */
#else #else
struct regs struct regs
{ {
@ -140,9 +140,9 @@ struct core_entry {
}; };
#ifdef HAVE_PRIORITY_SCHEDULING #ifdef HAVE_PRIORITY_SCHEDULING
#define IF_PRIO(empty, type) , type #define IF_PRIO(...) __VA_ARGS__
#else #else
#define IF_PRIO(empty, type) #define IF_PRIO(...)
#endif #endif
/* PortalPlayer chips have 2 cores, therefore need atomic mutexes /* PortalPlayer chips have 2 cores, therefore need atomic mutexes
@ -197,14 +197,6 @@ struct core_entry {
}) })
#endif #endif
#if NUM_CORES > 1
inline void lock_cores(void);
inline void unlock_cores(void);
#else
#define lock_cores(...)
#define unlock_cores(...)
#endif
struct thread_entry* struct thread_entry*
create_thread(void (*function)(void), void* stack, int stack_size, create_thread(void (*function)(void), void* stack, int stack_size,
const char *name IF_PRIO(, int priority) const char *name IF_PRIO(, int priority)
@ -239,7 +231,12 @@ void priority_yield(void);
struct thread_entry * thread_get_current(void); struct thread_entry * thread_get_current(void);
void init_threads(void); void init_threads(void);
int thread_stack_usage(const struct thread_entry *thread); int thread_stack_usage(const struct thread_entry *thread);
#if NUM_CORES > 1
int idle_stack_usage(unsigned int core);
#endif
int thread_get_status(const struct thread_entry *thread); int thread_get_status(const struct thread_entry *thread);
void thread_get_name(char *buffer, int size,
struct thread_entry *thread);
#ifdef RB_PROFILE #ifdef RB_PROFILE
void profile_thread(void); void profile_thread(void);
#endif #endif

View file

@ -46,16 +46,21 @@ void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR;
void kernel_init(void) void kernel_init(void)
{ {
/* Init the threading API */ /* Init the threading API */
#if NUM_CORES > 1
if (CURRENT_CORE == COP)
{
/* This enables the interrupt but it won't be active until
the timer is actually started and interrupts are unmasked */
tick_start(1000/HZ);
}
#endif
init_threads(); init_threads();
if(CURRENT_CORE == CPU) /* No processor other than the CPU will proceed here */
{
memset(tick_funcs, 0, sizeof(tick_funcs)); memset(tick_funcs, 0, sizeof(tick_funcs));
num_queues = 0; num_queues = 0;
memset(all_queues, 0, sizeof(all_queues)); memset(all_queues, 0, sizeof(all_queues));
}
tick_start(1000/HZ); tick_start(1000/HZ);
} }
@ -172,9 +177,6 @@ void queue_init(struct event_queue *q, bool register_queue)
q->read = 0; q->read = 0;
q->write = 0; q->write = 0;
q->thread = NULL; q->thread = NULL;
#if NUM_CORES > 1
q->irq_safe = false;
#endif
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
q->send = NULL; /* No message sending by default */ q->send = NULL; /* No message sending by default */
#endif #endif
@ -186,29 +188,12 @@ void queue_init(struct event_queue *q, bool register_queue)
} }
} }
#if NUM_CORES > 1
/**
* If IRQ mode is enabled, some core-wise locking mechanisms are disabled
* causing accessing queue to be no longer thread safe from the other core.
* However, that locking mechanism would also kill IRQ handlers.
*
* @param q struct of an event_queue
* @param state enable/disable IRQ mode
* @default state disabled
*/
void queue_set_irq_safe(struct event_queue *q, bool state)
{
q->irq_safe = state;
}
#endif
void queue_delete(struct event_queue *q) void queue_delete(struct event_queue *q)
{ {
int i; int i;
bool found = false; bool found = false;
int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
lock_cores();
/* Release theads waiting on queue */ /* Release theads waiting on queue */
wakeup_thread(&q->thread); wakeup_thread(&q->thread);
@ -241,7 +226,6 @@ void queue_delete(struct event_queue *q)
num_queues--; num_queues--;
} }
unlock_cores();
set_irq_level(oldlevel); set_irq_level(oldlevel);
} }
@ -251,13 +235,11 @@ void queue_wait(struct event_queue *q, struct event *ev)
unsigned int rd; unsigned int rd;
oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
lock_cores();
if (q->read == q->write) if (q->read == q->write)
{ {
set_irq_level_and_block_thread(&q->thread, oldlevel); set_irq_level_and_block_thread(&q->thread, oldlevel);
oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
lock_cores();
} }
rd = q->read++ & QUEUE_LENGTH_MASK; rd = q->read++ & QUEUE_LENGTH_MASK;
@ -271,20 +253,17 @@ void queue_wait(struct event_queue *q, struct event *ev)
} }
#endif #endif
unlock_cores();
set_irq_level(oldlevel); set_irq_level(oldlevel);
} }
void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
{ {
int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
lock_cores();
if (q->read == q->write && ticks > 0) if (q->read == q->write && ticks > 0)
{ {
set_irq_level_and_block_thread_w_tmo(&q->thread, ticks, oldlevel); set_irq_level_and_block_thread_w_tmo(&q->thread, ticks, oldlevel);
oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
lock_cores();
} }
if (q->read != q->write) if (q->read != q->write)
@ -305,7 +284,6 @@ void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
ev->id = SYS_TIMEOUT; ev->id = SYS_TIMEOUT;
} }
unlock_cores();
set_irq_level(oldlevel); set_irq_level(oldlevel);
} }
@ -314,11 +292,6 @@ void queue_post(struct event_queue *q, long id, intptr_t data)
int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
unsigned int wr; unsigned int wr;
#if NUM_CORES > 1
if (!q->irq_safe)
lock_cores();
#endif
wr = q->write++ & QUEUE_LENGTH_MASK; wr = q->write++ & QUEUE_LENGTH_MASK;
q->events[wr].id = id; q->events[wr].id = id;
@ -338,10 +311,6 @@ void queue_post(struct event_queue *q, long id, intptr_t data)
#endif #endif
wakeup_thread_irq_safe(&q->thread); wakeup_thread_irq_safe(&q->thread);
#if NUM_CORES > 1
if (!q->irq_safe)
unlock_cores();
#endif
set_irq_level(oldlevel); set_irq_level(oldlevel);
} }
@ -355,8 +324,6 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data)
int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
unsigned int wr; unsigned int wr;
lock_cores();
wr = q->write++ & QUEUE_LENGTH_MASK; wr = q->write++ & QUEUE_LENGTH_MASK;
q->events[wr].id = id; q->events[wr].id = id;
@ -379,7 +346,6 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data)
/* Function as queue_post if sending is not enabled */ /* Function as queue_post if sending is not enabled */
wakeup_thread(&q->thread); wakeup_thread(&q->thread);
unlock_cores();
set_irq_level(oldlevel); set_irq_level(oldlevel);
return 0; return 0;
@ -396,43 +362,23 @@ bool queue_in_queue_send(struct event_queue *q)
/* Replies with retval to any dequeued message sent with queue_send */ /* Replies with retval to any dequeued message sent with queue_send */
void queue_reply(struct event_queue *q, intptr_t retval) void queue_reply(struct event_queue *q, intptr_t retval)
{ {
lock_cores();
/* No IRQ lock here since IRQs cannot change this */ /* No IRQ lock here since IRQs cannot change this */
if(q->send && q->send->curr_sender) if(q->send && q->send->curr_sender)
{ {
queue_release_sender(&q->send->curr_sender, retval); queue_release_sender(&q->send->curr_sender, retval);
} }
unlock_cores();
} }
#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
bool queue_empty(const struct event_queue* q) bool queue_empty(const struct event_queue* q)
{ {
bool is_empty; return ( q->read == q->write );
#if NUM_CORES > 1
if (!q->irq_safe)
lock_cores();
#endif
is_empty = ( q->read == q->write );
#if NUM_CORES > 1
if (!q->irq_safe)
unlock_cores();
#endif
return is_empty;
} }
void queue_clear(struct event_queue* q) void queue_clear(struct event_queue* q)
{ {
int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
#if NUM_CORES > 1
if (!q->irq_safe)
lock_cores();
#endif
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
/* Release all thread waiting in the queue for a reply - /* Release all thread waiting in the queue for a reply -
dequeued sent message will be handled by owning thread */ dequeued sent message will be handled by owning thread */
@ -442,11 +388,6 @@ void queue_clear(struct event_queue* q)
q->read = 0; q->read = 0;
q->write = 0; q->write = 0;
#if NUM_CORES > 1
if (!q->irq_safe)
unlock_cores();
#endif
set_irq_level(oldlevel); set_irq_level(oldlevel);
} }
@ -454,11 +395,6 @@ void queue_remove_from_head(struct event_queue *q, long id)
{ {
int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
#if NUM_CORES > 1
if (!q->irq_safe)
lock_cores();
#endif
while(q->read != q->write) while(q->read != q->write)
{ {
unsigned int rd = q->read & QUEUE_LENGTH_MASK; unsigned int rd = q->read & QUEUE_LENGTH_MASK;
@ -483,11 +419,6 @@ void queue_remove_from_head(struct event_queue *q, long id)
q->read++; q->read++;
} }
#if NUM_CORES > 1
if (!q->irq_safe)
unlock_cores();
#endif
set_irq_level(oldlevel); set_irq_level(oldlevel);
} }
@ -499,24 +430,7 @@ void queue_remove_from_head(struct event_queue *q, long id)
*/ */
int queue_count(const struct event_queue *q) int queue_count(const struct event_queue *q)
{ {
int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); return q->write - q->read;
int result;
#if NUM_CORES > 1
if (!q->irq_safe)
lock_cores();
#endif
result = q->write - q->read;
#if NUM_CORES > 1
if (!q->irq_safe)
unlock_cores();
#endif
set_irq_level(oldlevel);
return result;
} }
int queue_broadcast(long id, intptr_t data) int queue_broadcast(long id, intptr_t data)
@ -644,9 +558,9 @@ void TIMER1(void)
int i; int i;
TIMER1_VAL; /* Read value to ack IRQ */ TIMER1_VAL; /* Read value to ack IRQ */
/* Run through the list of tick tasks (using main core) */
if (CURRENT_CORE == CPU) /* Run through the list of tick tasks (using main core -
{ COP does not dispatch ticks to this subroutine) */
for (i = 0;i < MAX_NUM_TICK_TASKS;i++) for (i = 0;i < MAX_NUM_TICK_TASKS;i++)
{ {
if (tick_funcs[i]) if (tick_funcs[i])
@ -657,9 +571,9 @@ void TIMER1(void)
current_tick++; current_tick++;
} }
}
#endif #endif
/* Must be last function called init kernel/thread initialization */
void tick_start(unsigned int interval_in_ms) void tick_start(unsigned int interval_in_ms)
{ {
#ifndef BOOTLOADER #ifndef BOOTLOADER
@ -922,14 +836,10 @@ void mutex_lock(struct mutex *m)
void mutex_unlock(struct mutex *m) void mutex_unlock(struct mutex *m)
{ {
lock_cores();
if (m->thread == NULL) if (m->thread == NULL)
m->locked = 0; m->locked = 0;
else else
wakeup_thread(&m->thread); wakeup_thread(&m->thread);
unlock_cores();
} }
void spinlock_lock(struct mutex *m) void spinlock_lock(struct mutex *m)

View file

@ -428,7 +428,6 @@ unsigned long pcm_rec_sample_rate(void)
void pcm_rec_init(void) void pcm_rec_init(void)
{ {
queue_init(&pcmrec_queue, true); queue_init(&pcmrec_queue, true);
queue_set_irq_safe(&pcmrec_queue, true);
queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send); queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send);
pcmrec_thread_p = pcmrec_thread_p =
create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),

View file

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "lcd.h" #include "lcd.h"
#include "lcd-remote.h" #include "lcd-remote.h"
#include "thread.h"
#include "kernel.h" #include "kernel.h"
#include "sprintf.h" #include "sprintf.h"
#include "button.h" #include "button.h"
@ -52,10 +53,24 @@
volatile unsigned char IDATA_ATTR cpu_message = 0; volatile unsigned char IDATA_ATTR cpu_message = 0;
volatile unsigned char IDATA_ATTR cpu_reply = 0; volatile unsigned char IDATA_ATTR cpu_reply = 0;
#if NUM_CORES > 1
extern int cop_idlestackbegin[];
#endif
void rolo_restart_cop(void) ICODE_ATTR; void rolo_restart_cop(void) ICODE_ATTR;
void rolo_restart_cop(void) void rolo_restart_cop(void)
{ {
if (CURRENT_CORE == CPU)
{
/* There should be free thread slots aplenty */
create_thread(rolo_restart_cop, cop_idlestackbegin, IDLE_STACK_SIZE,
"rolo COP" IF_PRIO(, PRIORITY_REALTIME)
IF_COP(, COP, false));
return;
}
COP_INT_CLR = -1;
/* Invalidate cache */ /* Invalidate cache */
invalidate_icache(); invalidate_icache();
@ -63,14 +78,14 @@ void rolo_restart_cop(void)
CACHE_CTL = CACHE_DISABLE; CACHE_CTL = CACHE_DISABLE;
/* Tell the main core that we're ready to reload */ /* Tell the main core that we're ready to reload */
cpu_reply = 2; cpu_reply = 1;
/* Wait while RoLo loads the image into SDRAM */ /* Wait while RoLo loads the image into SDRAM */
/* TODO: Accept checksum failure gracefully */ /* TODO: Accept checksum failure gracefully */
while(cpu_message == 1) {} while(cpu_message != 1);
/* Acknowledge the CPU and then reload */ /* Acknowledge the CPU and then reload */
cpu_reply = 1; cpu_reply = 2;
asm volatile( asm volatile(
"mov r0, #0x10000000 \n" "mov r0, #0x10000000 \n"
@ -127,9 +142,7 @@ void rolo_restart(const unsigned char* source, unsigned char* dest,
: : "a"(dest) : : "a"(dest)
); );
#elif defined(CPU_PP502x) #elif defined(CPU_PP502x)
CPU_INT_CLR = -1;
/* Tell the COP that we've finished loading and started rebooting */
cpu_message = 0;
/* Flush cache */ /* Flush cache */
flush_icache(); flush_icache();
@ -141,8 +154,11 @@ void rolo_restart(const unsigned char* source, unsigned char* dest,
for (i=0;i<8;i++) for (i=0;i<8;i++)
memmapregs[i]=0; memmapregs[i]=0;
/* Tell the COP it's safe to continue rebooting */
cpu_message = 1;
/* Wait for the COP to tell us it is rebooting */ /* Wait for the COP to tell us it is rebooting */
while(cpu_reply != 1) {} while(cpu_reply != 2);
asm volatile( asm volatile(
"mov r0, #0x10000000 \n" "mov r0, #0x10000000 \n"
@ -211,11 +227,11 @@ int rolo_load(const char* filename)
#endif #endif
#ifdef CPU_PP #ifdef CPU_PP
cpu_message = COP_REBOOT;
COP_CTL = PROC_WAKE;
lcd_puts(0, 2, "Waiting for coprocessor..."); lcd_puts(0, 2, "Waiting for coprocessor...");
lcd_update(); lcd_update();
while(cpu_reply != 2) {} rolo_restart_cop();
/* Wait for COP to be in safe code */
while(cpu_reply != 1);
lcd_puts(0, 2, " "); lcd_puts(0, 2, " ");
lcd_update(); lcd_update();
#endif #endif

View file

@ -179,6 +179,7 @@ static const char* const uiename[] = {
/* Unexpected Interrupt or Exception handler. Currently only deals with /* Unexpected Interrupt or Exception handler. Currently only deals with
exceptions, but will deal with interrupts later. exceptions, but will deal with interrupts later.
*/ */
void UIE(unsigned int pc, unsigned int num) __attribute__((noreturn));
void UIE(unsigned int pc, unsigned int num) void UIE(unsigned int pc, unsigned int num)
{ {
char str[32]; char str[32];
@ -188,7 +189,8 @@ void UIE(unsigned int pc, unsigned int num)
lcd_setfont(FONT_SYSFIXED); lcd_setfont(FONT_SYSFIXED);
#endif #endif
lcd_puts(0, 0, uiename[num]); lcd_puts(0, 0, uiename[num]);
snprintf(str, sizeof(str), "at %08x", pc); snprintf(str, sizeof(str), "at %08x" IF_COP(" (%d)"), pc
IF_COP(, CURRENT_CORE));
lcd_puts(0, 1, str); lcd_puts(0, 1, str);
lcd_update(); lcd_update();

View file

@ -34,6 +34,7 @@ start:
#if CONFIG_CPU == PP5002 #if CONFIG_CPU == PP5002
.equ PROC_ID, 0xc4000000 .equ PROC_ID, 0xc4000000
.equ CPU_ICLR, 0xcf001028 .equ CPU_ICLR, 0xcf001028
.equ CPU_CTRL, 0xcf004054
.equ COP_ICLR, 0xcf001038 .equ COP_ICLR, 0xcf001038
.equ COP_CTRL, 0xcf004058 .equ COP_CTRL, 0xcf004058
.equ COP_STATUS, 0xcf004050 .equ COP_STATUS, 0xcf004050
@ -44,6 +45,8 @@ start:
#else #else
.equ PROC_ID, 0x60000000 .equ PROC_ID, 0x60000000
.equ CPU_ICLR, 0x60004028 .equ CPU_ICLR, 0x60004028
.equ CPU_CTRL, 0x60007000
.equ CPU_STATUS, 0x60007000
.equ COP_ICLR, 0x60004038 .equ COP_ICLR, 0x60004038
.equ COP_CTRL, 0x60007004 .equ COP_CTRL, 0x60007004
.equ COP_STATUS, 0x60007004 .equ COP_STATUS, 0x60007004
@ -57,15 +60,16 @@ start:
msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
b pad_skip b pad_skip
.space 60*4 /* (more than enough) space for exception vectors and mi4 magic */ .space 64*4 /* (more than enough) space for exception vectors and mi4 magic */
pad_skip: pad_skip:
#if defined(SANSA_E200) || defined(SANSA_C200) /* Find out which processor we are - r0 should be preserved for the
/* On the Sansa, copying the vectors fails if the cache is initialised */ * duration of the init to avoid constant reloading of the processor ID.
ldr r1, =CACHE_CTRL * For each stage, CPU proceeds first, then COP.
mov r2, #0x0 */
str r2, [r1] ldr r0, =PROC_ID
#endif ldrb r0, [r0]
/* We need to remap memory from wherever SDRAM is mapped natively, to /* We need to remap memory from wherever SDRAM is mapped natively, to
base address 0, so we can put our exception vectors there. We don't base address 0, so we can put our exception vectors there. We don't
want to do this remapping while executing from SDRAM, so we copy the want to do this remapping while executing from SDRAM, so we copy the
@ -73,64 +77,89 @@ pad_skip:
code is compiled for address 0, but is currently executing at either code is compiled for address 0, but is currently executing at either
0x28000000 or 0x10000000, depending on chipset version. Do not use any 0x28000000 or 0x10000000, depending on chipset version. Do not use any
absolute addresses until remapping has been done. */ absolute addresses until remapping has been done. */
ldr r1, =0x40000000
ldr r2, =remap_start
ldr r3, =remap_end
and r5, pc, #0xff000000 /* adjust for execute address */ /* Cores are stepped though the init in turn: CPU then COP. The the remap
orr r2, r2, r5 stage is completed by each core in turn and then the COP waits for the
orr r3, r3, r5 CPU to finish initializing its kernel where the CPU will wake the COP
and wait for the COP to finish. This ensures no threading activity
starts until it is safe. */
cmp r0, #0x55
/* mask all interrupt sources before setting anything up */
ldreq r2, =CPU_ICLR
ldrne r2, =COP_ICLR
mvn r1, #0
str r1, [r2]
/* put us (co-processor) to sleep and wait for CPU to remap */
ldrne r2, =COP_CTRL
movne r1, #SLEEP
strne r1, [r2]
/* wait for co-processor to sleep then CPU can begin its remapping */
ldreq r2, =COP_STATUS
1:
ldreq r1, [r2]
tsteq r1, #SLEEPING
beq 1b
#ifdef CPU_PP502x
/* disable cache and local interrupt vectors - it is really not desireable
to have them enabled here */
ldr r2, =CACHE_CTRL
mov r1, #0
str r1, [r2]
#endif
mov r2, #0x40000000
ldr r3, =remap_start
ldr r4, =remap_end
and r6, pc, #0xff000000 /* adjust for execute address */
orr r3, r3, r6
orr r4, r4, r6
/* copy the code to 0x40000000 */ /* copy the code to 0x40000000 */
1: 1:
ldr r4, [r2], #4 ldr r5, [r3], #4
str r4, [r1], #4 str r5, [r2], #4
cmp r2, r3 cmp r3, r4
ble 1b blo 1b
ldr r3, =0x3f84 /* r3 and r1 values here are magic, don't touch */ ldr r4, =0x3f84 /* r3 and r1 values here are magic, don't touch */
orr r3, r3, r5 /* adjust for execute address */ orr r4, r4, r6 /* adjust for execute address */
ldr r2, =0xf000f014 ldr r3, =0xf000f014
#if MEM > 32 #if MEM > 32
mov r1, #0x7400 /* r1 appears to indicate how much memory (not in mov r2, #0x7400 /* r1 appears to indicate how much memory (not in
bytes) is remapped */ bytes) is remapped */
#else #else
mov r1, #0x3a00 mov r2, #0x3a00
#endif #endif
ldr r0, =0xf000f010 ldr r1, =0xf000f010
mov pc, #0x40000000 mov pc, #0x40000000
remap_start: remap_start:
str r1, [r0] str r2, [r1]
str r3, [r2] str r4, [r3]
ldr r0, L_post_remap ldr r1, L_post_remap
mov pc, r0 mov pc, r1
L_post_remap: .word remap_end L_post_remap:
.word remap_end
remap_end: remap_end:
/* After doing the remapping, send the COP to sleep.
On wakeup it will go to cop_init */
/* Find out which processor we are */
ldr r0, =PROC_ID
ldrb r0, [r0]
cmp r0, #0x55 cmp r0, #0x55
ldr r4, =COP_CTRL
/* Mask all interrupt sources before setting up modes */ /* Wakeup co-processor to let it do remappings */
ldreq r0, =CPU_ICLR moveq r3, #WAKE
ldrne r0, =COP_ICLR /* Sleep us (co-processor) and wait for CPU to do kernel initialization */
mvn r1, #1
str r1, [r0]
/* put us (co-processor) to sleep */
ldrne r4, =COP_CTRL
movne r3, #SLEEP movne r3, #SLEEP
strne r3, [r4] str r3, [r4]
/* Jump to co-processor init */
ldrne pc, =cop_init ldrne pc, =cop_init
cpu_init: cpu_init:
/* Wait for COP to be sleeping */ /* Wait for COP to go to sleep before proceeding */
ldr r4, =COP_STATUS ldr r4, =COP_STATUS
1: 1:
ldr r3, [r4] ldr r3, [r4]
@ -175,15 +204,26 @@ cpu_init:
strhi r4, [r2], #4 strhi r4, [r2], #4
bhi 1b bhi 1b
/* Set up some stack and munge it with 0xdeadbeef */ /* Load stack munge value */
ldr sp, =stackend
mov r3, sp
ldr r2, =stackbegin
ldr r4, =0xdeadbeef ldr r4, =0xdeadbeef
/* Set up some stack and munge it with 0xdeadbeef */
ldr r2, =stackbegin
ldr sp, =stackend
1:
cmp sp, r2
strhi r4, [r2], #4
bhi 1b
#if NUM_CORES > 1
/* Set up idle stack and munge it with 0xdeadbeef */
ldr r2, =cpu_idlestackbegin
ldr r3, =cpu_idlestackend
1: 1:
cmp r3, r2 cmp r3, r2
strhi r4, [r2], #4 strhi r4, [r2], #4
bhi 1b bhi 1b
#endif
/* Set up stack for IRQ mode */ /* Set up stack for IRQ mode */
msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */ msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */
@ -203,34 +243,41 @@ cpu_init:
msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ msr cpsr_c, #0xdb /* IRQ/FIQ disabled */
ldr sp, =irq_stack ldr sp, =irq_stack
/* Switch to supervisor mode */ /* Switch back to supervisor mode */
msr cpsr_c, #0xd3 msr cpsr_c, #0xd3
ldr sp, =stackend
/* Delay waking the COP until thread initialization is complete unless dual-core
support is not enabled in which case the cop_main function does not perform
any kernel or thread initialization. It's just a trivial sleep loop. */
#if NUM_CORES == 1
ldr r4, =COP_CTRL
mov r3, #WAKE
str r3, [r4]
#endif
bl main bl main
/* main() should never return */ /* main() should never return */
cop_init: cop_init:
#if CONFIG_CPU != PP5002 #if NUM_CORES > 1
/* COP: Invalidate cache */ /* Wait for CPU to go to sleep at the end of its kernel init */
ldr r0, =0xf000f044 ldr r4, =CPU_STATUS
ldr r1, [r0]
orr r1, r1, #0x6
str r1, [r0]
ldr r0, =CACHE_CTRL
1: 1:
ldr r1, [r0] ldr r3, [r4]
tst r1, #0x8000 tst r3, #SLEEPING
bne 1b beq 1b
#endif
/* Setup stack for COP */ /* Set up idle stack for COP and munge it with 0xdeadbeef */
ldr sp, =cop_stackend ldr r2, =cop_idlestackbegin
mov r3, sp ldr sp, =cop_idlestackend
#else
/* Setup stack for COP and munge it with 0xdeadbeef */
ldr r2, =cop_stackbegin ldr r2, =cop_stackbegin
ldr sp, =cop_stackend
#endif
ldr r4, =0xdeadbeef ldr r4, =0xdeadbeef
2: 2:
cmp r3, r2 cmp sp, r2
strhi r4, [r2], #4 strhi r4, [r2], #4
bhi 2b bhi 2b
@ -247,9 +294,8 @@ cop_init:
msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ msr cpsr_c, #0xdb /* IRQ/FIQ disabled */
ldr sp, =cop_irq_stack ldr sp, =cop_irq_stack
/* Switch to supervisor mode */ /* Switch back to supervisor mode */
msr cpsr_c, #0xd3 msr cpsr_c, #0xd3
ldr sp, =cop_stackend
/* Run cop_main() in apps/main.c */ /* Run cop_main() in apps/main.c */
bl cop_main bl cop_main
@ -300,7 +346,6 @@ undef_instr_handler:
software_int_handler: software_int_handler:
reserved_handler: reserved_handler:
movs pc, lr movs pc, lr
prefetch_abort_handler: prefetch_abort_handler:
sub r0, lr, #4 sub r0, lr, #4
mov r1, #1 mov r1, #1
@ -324,6 +369,9 @@ UIE:
b UIE b UIE
#endif #endif
/* Align stacks to cache line boundary */
.balign 16
/* 256 words of IRQ stack */ /* 256 words of IRQ stack */
.space 256*4 .space 256*4
irq_stack: irq_stack:

View file

@ -70,9 +70,7 @@ void irq(void)
} }
#endif #endif
} else { } else {
if (COP_INT_STAT & TIMER1_MASK) if (COP_INT_STAT & TIMER2_MASK)
TIMER1();
else if (COP_INT_STAT & TIMER2_MASK)
TIMER2(); TIMER2();
} }
} }
@ -85,25 +83,49 @@ void irq(void)
to extend the funtions to do alternate cache configurations. */ to extend the funtions to do alternate cache configurations. */
#ifndef BOOTLOADER #ifndef BOOTLOADER
static void ipod_init_cache(void) void flush_icache(void) ICODE_ATTR;
void flush_icache(void)
{
if (CACHE_CTL & CACHE_ENABLE)
{
outl(inl(0xf000f044) | 0x2, 0xf000f044);
while ((CACHE_CTL & 0x8000) != 0);
}
}
void invalidate_icache(void) ICODE_ATTR;
void invalidate_icache(void)
{
if (CACHE_CTL & CACHE_ENABLE)
{
unsigned i;
outl(inl(0xf000f044) | 0x6, 0xf000f044);
while ((CACHE_CTL & 0x8000) != 0);
for (i = 0x10000000; i < 0x10002000; i += 16)
inb(i);
}
}
static void init_cache(void)
{ {
/* Initialising the cache in the iPod bootloader prevents Rockbox from starting */ /* Initialising the cache in the iPod bootloader prevents Rockbox from starting */
unsigned i; unsigned i;
/* cache init mode? */ /* cache init mode? */
CACHE_CTL = CACHE_INIT; CACHE_CTL |= CACHE_INIT;
/* PP5002 has 8KB cache */ /* what's this do? */
for (i = 0xf0004000; i < 0xf0006000; i += 16) { outl(inl(0x60006044) | (CURRENT_CORE == CPU ? 0x10 : 0x20),
outl(0x0, i); 0x60006044);
}
outl(0x0, 0xf000f040); outl(0xc00, 0xf000f040);
outl(0x3fc0, 0xf000f044); outl(0xfc0, 0xf000f044);
/* enable cache */ /* enable cache */
CACHE_CTL = CACHE_ENABLE; CACHE_CTL |= CACHE_INIT | CACHE_ENABLE | CACHE_RUN;
/* fill cache from physical address - do we have a better candidate for
an 8KB unchanging memory range? */
for (i = 0x10000000; i < 0x10002000; i += 16) for (i = 0x10000000; i < 0x10002000; i += 16)
inb(i); inb(i);
} }
@ -206,6 +228,12 @@ void system_init(void)
outl(0xffffffff, 0x60006008); outl(0xffffffff, 0x60006008);
DEV_RS = 0; DEV_RS = 0;
outl(0x00000000, 0x60006008); outl(0x00000000, 0x60006008);
#elif defined (IRIVER_H10)
DEV_RS = 0x3ffffef8;
outl(0xffffffff, 0x60006008);
outl(inl(0x70000024) | 0xc0, 0x70000024);
DEV_RS = 0;
outl(0x00000000, 0x60006008);
#endif #endif
/* Remap the flash ROM from 0x00000000 to 0x20000000. */ /* Remap the flash ROM from 0x00000000 to 0x20000000. */
MMAP3_LOGICAL = 0x20000000 | 0x3a00; MMAP3_LOGICAL = 0x20000000 | 0x3a00;
@ -248,8 +276,8 @@ void system_init(void)
pp_set_cpu_frequency(CPUFREQ_MAX); pp_set_cpu_frequency(CPUFREQ_MAX);
#endif #endif
} }
ipod_init_cache();
init_cache();
#endif /* BOOTLOADER */ #endif /* BOOTLOADER */
} }

View file

@ -70,29 +70,20 @@ static inline unsigned int current_core(void)
); );
return core; return core;
} }
#else
unsigned int current_core(void);
#endif
#if CONFIG_CPU != PP5002 #define CACHE_FUNCTIONS_AS_CALL
#define HAVE_INVALIDATE_ICACHE #define HAVE_INVALIDATE_ICACHE
static inline void invalidate_icache(void) void invalidate_icache(void);
{
outl(inl(0xf000f044) | 0x6, 0xf000f044);
while ((CACHE_CTL & 0x8000) != 0);
}
#define HAVE_FLUSH_ICACHE #define HAVE_FLUSH_ICACHE
static inline void flush_icache(void) void flush_icache(void);
{
outl(inl(0xf000f044) | 0x2, 0xf000f044);
while ((CACHE_CTL & 0x8000) != 0);
}
#endif /* CONFIG_CPU */
#else #else
unsigned int current_core(void);
#endif /* CPU_PP502x */
#endif
#endif /* CPU_PP */
#endif /* SYSTEM_TARGET_H */ #endif /* SYSTEM_TARGET_H */

View file

@ -45,59 +45,13 @@ static int boosted_threads IBSS_ATTR;
#endif #endif
/* Define to enable additional checks for blocking violations etc. */ /* Define to enable additional checks for blocking violations etc. */
#define THREAD_EXTRA_CHECKS #define THREAD_EXTRA_CHECKS 0
static const char main_thread_name[] = "main"; static const char main_thread_name[] = "main";
extern int stackbegin[]; extern int stackbegin[];
extern int stackend[]; extern int stackend[];
#ifdef CPU_PP
#ifndef BOOTLOADER
extern int cop_stackbegin[];
extern int cop_stackend[];
#else
/* The coprocessor stack is not set up in the bootloader code, but the threading
* is. No threads are run on the coprocessor, so set up some dummy stack */
int *cop_stackbegin = stackbegin;
int *cop_stackend = stackend;
#endif
#endif
#if NUM_CORES > 1
#if 0
static long cores_locked IBSS_ATTR;
#define LOCK(...) do { } while (test_and_set(&cores_locked, 1))
#define UNLOCK(...) cores_locked = 0
#endif
/* #warning "Core locking mechanism should be fixed on H10/4G!" */
inline void lock_cores(void)
{
#if 0
if (!cores[CURRENT_CORE].lock_issued)
{
LOCK();
cores[CURRENT_CORE].lock_issued = true;
}
#endif
}
inline void unlock_cores(void)
{
#if 0
if (cores[CURRENT_CORE].lock_issued)
{
cores[CURRENT_CORE].lock_issued = false;
UNLOCK();
}
#endif
}
#endif
/* Conserve IRAM /* Conserve IRAM
static void add_to_list(struct thread_entry **list, static void add_to_list(struct thread_entry **list,
struct thread_entry *thread) ICODE_ATTR; struct thread_entry *thread) ICODE_ATTR;
@ -114,6 +68,32 @@ static inline void load_context(const void* addr)
static inline void core_sleep(void) __attribute__((always_inline)); static inline void core_sleep(void) __attribute__((always_inline));
#if defined(CPU_ARM) #if defined(CPU_ARM)
/*---------------------------------------------------------------------------
* Start the thread running and terminate it if it returns
*---------------------------------------------------------------------------
*/
static void start_thread(void) __attribute__((naked,used));
static void start_thread(void)
{
/* r0 = context */
asm volatile (
"ldr sp, [r0, #32] \n" /* Load initial sp */
"ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */
"mov r1, #0 \n" /* Mark thread as running */
"str r1, [r0, #40] \n"
#if NUM_CORES > 1
"ldr r0, =invalidate_icache \n" /* Invalidate this core's cache. */
"mov lr, pc \n" /* This could be the first entry into */
"bx r0 \n" /* plugin or codec code for this core. */
#endif
"mov lr, pc \n" /* Call thread function */
"bx r4 \n"
"mov r0, #0 \n" /* remove_thread(NULL) */
"ldr pc, =remove_thread \n"
".ltorg \n" /* Dump constant pool */
); /* No clobber list - new thread doesn't care */
}
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
* Store non-volatile context. * Store non-volatile context.
*--------------------------------------------------------------------------- *---------------------------------------------------------------------------
@ -126,68 +106,78 @@ static inline void store_context(void* addr)
); );
} }
/*--------------------------------------------------------------------------- /* For startup, place context pointer in r4 slot, start_thread pointer in r5
* Load non-volatile context. * slot, and thread function pointer in context.start. See load_context for
*--------------------------------------------------------------------------- * what happens when thread is initially going to run. */
*/ #define THREAD_STARTUP_INIT(core, thread, function) \
static void start_thread(void (*thread_func)(void), const void* addr) __attribute__((naked,used)); ({ (thread)->context.r[0] = (unsigned int)&(thread)->context, \
static void start_thread(void (*thread_func)(void), const void* addr) (thread)->context.r[1] = (unsigned int)start_thread, \
{ (thread)->context.start = (void *)function; })
/* r0 = thread_func, r1 = addr */
#if NUM_CORES > 1 && CONFIG_CPU != PP5002
asm volatile (
"mov r2, #0 \n"
"str r2, [r1, #40] \n"
"ldr r1, =0xf000f044 \n" /* invalidate this core's cache */
"ldr r2, [r1] \n"
"orr r2, r2, #6 \n"
"str r2, [r1] \n"
"ldr r1, =0x6000c000 \n"
"1: \n"
"ldr r2, [r1] \n"
"tst r2, #0x8000 \n"
"bne 1b \n"
"mov pc, r0 \n"
: : : "r1", "r2"
);
#else
asm volatile (
"mov r2, #0 \n"
"str r2, [r1, #40] \n"
"mov pc, r0 \n"
: : : "r1", "r2"
);
#endif
(void)thread_func;
(void)addr;
}
static inline void load_context(const void* addr) static inline void load_context(const void* addr)
{ {
asm volatile( asm volatile(
"ldmia %0, { r4-r11, sp, lr } \n" /* load regs r4 to r14 from context */ "ldr r0, [%0, #40] \n" /* Load start pointer */
"ldr r0, [%0, #40] \n" /* load start pointer */ "cmp r0, #0 \n" /* Check for NULL */
"cmp r0, #0 \n" /* check for NULL */ "ldmneia %0, { r0, pc } \n" /* If not already running, jump to start */
"movne r1, %0 \n" /* if not already running, jump to start */ "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */
"ldrne pc, =start_thread \n" : : "r" (addr) : "r0" /* only! */
: : "r" (addr) : "r0", "r1"
); );
} }
#if defined (CPU_PP) #if defined (CPU_PP)
#if NUM_CORES > 1
extern int cpu_idlestackbegin[];
extern int cpu_idlestackend[];
extern int cop_idlestackbegin[];
extern int cop_idlestackend[];
static int * const idle_stacks[NUM_CORES] NOCACHEDATA_ATTR =
{
[CPU] = cpu_idlestackbegin,
[COP] = cop_idlestackbegin
};
#else /* NUM_CORES == 1 */
#ifndef BOOTLOADER
extern int cop_stackbegin[];
extern int cop_stackend[];
#else
/* The coprocessor stack is not set up in the bootloader code, but the threading
* is. No threads are run on the coprocessor, so set up some dummy stack */
int *cop_stackbegin = stackbegin;
int *cop_stackend = stackend;
#endif /* BOOTLOADER */
#endif /* NUM_CORES */
static inline void core_sleep(void) static inline void core_sleep(void)
{ {
unlock_cores();
/* This should sleep the CPU. It appears to wake by itself on /* This should sleep the CPU. It appears to wake by itself on
interrupts */ interrupts */
if (CURRENT_CORE == CPU) if (CURRENT_CORE == CPU)
CPU_CTL = PROC_SLEEP; CPU_CTL = PROC_SLEEP;
else else
COP_CTL = PROC_SLEEP; COP_CTL = PROC_SLEEP;
lock_cores();
} }
#if NUM_CORES > 1
/*---------------------------------------------------------------------------
* Switches to a stack that always resides in the Rockbox core.
*
* Needed when a thread suicides on a core other than the main CPU since the
* stack used when idling is the stack of the last thread to run. This stack
* may not reside in the core in which case the core will continue to use a
* stack from an unloaded module until another thread runs on it.
*---------------------------------------------------------------------------
*/
static inline void switch_to_idle_stack(const unsigned int core)
{
asm volatile (
"str sp, [%0] \n" /* save original stack pointer on idle stack */
"mov sp, %0 \n" /* switch stacks */
: : "r"(&idle_stacks[core][IDLE_STACK_WORDS-1]));
}
#endif /* NUM_CORES */
#elif CONFIG_CPU == S3C2440 #elif CONFIG_CPU == S3C2440
static inline void core_sleep(void) static inline void core_sleep(void)
{ {
@ -204,6 +194,42 @@ static inline void core_sleep(void)
#endif #endif
#elif defined(CPU_COLDFIRE) #elif defined(CPU_COLDFIRE)
/*---------------------------------------------------------------------------
* Start the thread running and terminate it if it returns
*---------------------------------------------------------------------------
*/
void start_thread(void); /* Provide C access to ASM label */
static void __start_thread(void) __attribute__((used));
static void __start_thread(void)
{
/* a0=macsr, a1=context */
asm volatile (
"start_thread: \n" /* Start here - no naked attribute */
"move.l %a0, %macsr \n" /* Set initial mac status reg */
"lea.l 48(%a1), %a1 \n"
"move.l (%a1)+, %sp \n" /* Set initial stack */
"move.l (%a1), %a2 \n" /* Fetch thread function pointer */
"clr.l (%a1) \n" /* Mark thread running */
"jsr (%a2) \n" /* Call thread function */
"clr.l -(%sp) \n" /* remove_thread(NULL) */
"jsr remove_thread \n"
);
}
/* Set EMAC unit to fractional mode with saturation for each new thread,
* since that's what'll be the most useful for most things which the dsp
* will do. Codecs should still initialize their preferred modes
* explicitly. Context pointer is placed in d2 slot and start_thread
* pointer in d3 slot. thread function pointer is placed in context.start.
* See load_context for what happens when thread is initially going to
* run.
*/
#define THREAD_STARTUP_INIT(core, thread, function) \
({ (thread)->context.macsr = EMAC_FRACTIONAL | EMAC_SATURATE, \
(thread)->context.d[0] = (unsigned int)&(thread)->context, \
(thread)->context.d[1] = (unsigned int)start_thread, \
(thread)->context.start = (void *)(function); })
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
* Store non-volatile context. * Store non-volatile context.
*--------------------------------------------------------------------------- *---------------------------------------------------------------------------
@ -224,14 +250,13 @@ static inline void store_context(void* addr)
static inline void load_context(const void* addr) static inline void load_context(const void* addr)
{ {
asm volatile ( asm volatile (
"move.l 52(%0), %%d0 \n" /* Get start address */
"beq.b 1f \n" /* NULL -> already running */
"movem.l (%0), %%a0-%%a2 \n" /* a0=macsr, a1=context, a2=start_thread */
"jmp (%%a2) \n" /* Start the thread */
"1: \n"
"movem.l (%0), %%d0/%%d2-%%d7/%%a2-%%a7 \n" /* Load context */ "movem.l (%0), %%d0/%%d2-%%d7/%%a2-%%a7 \n" /* Load context */
"move.l %%d0, %%macsr \n" "move.l %%d0, %%macsr \n"
"move.l (52,%0),%%d0 \n" /* Get start address */
"beq.b 1f \n" /* NULL -> already running */
"clr.l (52,%0) \n" /* Clear start address.. */
"move.l %%d0,%0 \n"
"jmp (%0) \n" /* ..and start the thread */
"1: \n"
: : "a" (addr) : "d0" /* only! */ : : "a" (addr) : "d0" /* only! */
); );
} }
@ -249,6 +274,37 @@ static inline void core_sleep(void)
({ (thread)->context.macsr = EMAC_FRACTIONAL | EMAC_SATURATE; }) ({ (thread)->context.macsr = EMAC_FRACTIONAL | EMAC_SATURATE; })
#elif CONFIG_CPU == SH7034 #elif CONFIG_CPU == SH7034
/*---------------------------------------------------------------------------
* Start the thread running and terminate it if it returns
*---------------------------------------------------------------------------
*/
void start_thread(void); /* Provide C access to ASM label */
static void __start_thread(void) __attribute__((used));
static void __start_thread(void)
{
/* r8 = context */
asm volatile (
"_start_thread: \n" /* Start here - no naked attribute */
"mov.l @(4, r8), r0 \n" /* Fetch thread function pointer */
"mov.l @(28, r8), r15 \n" /* Set initial sp */
"mov #0, r1 \n" /* Start the thread */
"jsr @r0 \n"
"mov.l r1, @(36, r8) \n" /* Clear start address */
"mov.l 1f, r0 \n" /* remove_thread(NULL) */
"jmp @r0 \n"
"mov #0, r4 \n"
"1: \n"
".long _remove_thread \n"
);
}
/* Place context pointer in r8 slot, function pointer in r9 slot, and
* start_thread pointer in context_start */
#define THREAD_STARTUP_INIT(core, thread, function) \
({ (thread)->context.r[0] = (unsigned int)&(thread)->context, \
(thread)->context.r[1] = (unsigned int)(function), \
(thread)->context.start = (void*)start_thread; })
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
* Store non-volatile context. * Store non-volatile context.
*--------------------------------------------------------------------------- *---------------------------------------------------------------------------
@ -256,8 +312,8 @@ static inline void core_sleep(void)
static inline void store_context(void* addr) static inline void store_context(void* addr)
{ {
asm volatile ( asm volatile (
"add #36,%0 \n" "add #36, %0 \n" /* Start at last reg. By the time routine */
"sts.l pr, @-%0 \n" "sts.l pr, @-%0 \n" /* is done, %0 will have the original value */
"mov.l r15,@-%0 \n" "mov.l r15,@-%0 \n"
"mov.l r14,@-%0 \n" "mov.l r14,@-%0 \n"
"mov.l r13,@-%0 \n" "mov.l r13,@-%0 \n"
@ -277,7 +333,12 @@ static inline void store_context(void* addr)
static inline void load_context(const void* addr) static inline void load_context(const void* addr)
{ {
asm volatile ( asm volatile (
"mov.l @%0+,r8 \n" "mov.l @(36, %0), r0 \n" /* Get start address */
"tst r0, r0 \n"
"bt .running \n" /* NULL -> already running */
"jmp @r0 \n" /* r8 = context */
".running: \n"
"mov.l @%0+, r8 \n" /* Executes in delay slot and outside it */
"mov.l @%0+, r9 \n" "mov.l @%0+, r9 \n"
"mov.l @%0+, r10 \n" "mov.l @%0+, r10 \n"
"mov.l @%0+, r11 \n" "mov.l @%0+, r11 \n"
@ -286,14 +347,6 @@ static inline void load_context(const void* addr)
"mov.l @%0+, r14 \n" "mov.l @%0+, r14 \n"
"mov.l @%0+, r15 \n" "mov.l @%0+, r15 \n"
"lds.l @%0+, pr \n" "lds.l @%0+, pr \n"
"mov.l @%0,r0 \n" /* Get start address */
"tst r0,r0 \n"
"bt .running \n" /* NULL -> already running */
"lds r0,pr \n"
"mov #0,r0 \n"
"rts \n" /* Start the thread */
"mov.l r0,@%0 \n" /* Clear start address */
".running: \n"
: : "r" (addr) : "r0" /* only! */ : : "r" (addr) : "r0" /* only! */
); );
} }
@ -311,38 +364,36 @@ static inline void core_sleep(void)
#define THREAD_CPU_INIT(core, thread) #define THREAD_CPU_INIT(core, thread)
#endif #endif
#ifdef THREAD_EXTRA_CHECKS #if THREAD_EXTRA_CHECKS
static void thread_panicf_format_name(char *buffer, struct thread_entry *thread) static void thread_panicf(const char *msg, struct thread_entry *thread)
{ {
*buffer = '\0'; #if NUM_CORES > 1
if (thread) const unsigned int core = thread->core;
#endif
static char name[32];
thread_get_name(name, 32, thread);
panicf ("%s %s" IF_COP(" (%d)"), msg, name IF_COP(, core));
}
static void thread_stkov(struct thread_entry *thread)
{ {
/* Display thread name if one or ID if none */ thread_panicf("Stkov", thread);
const char *fmt = thread->name ? " %s" : " %08lX";
intptr_t name = thread->name ?
(intptr_t)thread->name : (intptr_t)thread;
snprintf(buffer, 16, fmt, name);
}
}
static void thread_panicf(const char *msg,
struct thread_entry *thread1, struct thread_entry *thread2)
{
static char thread1_name[16], thread2_name[16];
thread_panicf_format_name(thread1_name, thread1);
thread_panicf_format_name(thread2_name, thread2);
panicf ("%s%s%s", msg, thread1_name, thread2_name);
} }
#define THREAD_PANICF(msg, thread) \
thread_panicf(msg, thread)
#define THREAD_ASSERT(exp, msg, thread) \
({ if (!({ exp; })) thread_panicf((msg), (thread)); })
#else #else
static void thread_stkov(void) static void thread_stkov(struct thread_entry *thread)
{ {
/* Display thread name if one or ID if none */ #if NUM_CORES > 1
struct thread_entry *current = cores[CURRENT_CORE].running; const unsigned int core = thread->core;
const char *fmt = current->name ? "%s %s" : "%s %08lX"; #endif
intptr_t name = current->name ? static char name[32];
(intptr_t)current->name : (intptr_t)current; thread_get_name(name, 32, thread);
panicf(fmt, "Stkov", name); panicf("Stkov %s" IF_COP(" (%d)"), name IF_COP(, core));
} }
#define THREAD_PANICF(msg, thread)
#define THREAD_ASSERT(exp, msg, thread)
#endif /* THREAD_EXTRA_CHECKS */ #endif /* THREAD_EXTRA_CHECKS */
static void add_to_list(struct thread_entry **list, struct thread_entry *thread) static void add_to_list(struct thread_entry **list, struct thread_entry *thread)
@ -564,8 +615,6 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list)
/* Do nothing */ /* Do nothing */
#else #else
lock_cores();
/* Begin task switching by saving our current context so that we can /* Begin task switching by saving our current context so that we can
* restore the state of the current thread later to the point prior * restore the state of the current thread later to the point prior
* to this call. */ * to this call. */
@ -576,11 +625,7 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list)
/* Check if the current thread stack is overflown */ /* Check if the current thread stack is overflown */
stackptr = cores[core].running->stack; stackptr = cores[core].running->stack;
if(stackptr[0] != DEADBEEF) if(stackptr[0] != DEADBEEF)
#ifdef THREAD_EXTRA_CHECKS thread_stkov(cores[core].running);
thread_panicf("Stkov", cores[core].running, NULL);
#else
thread_stkov();
#endif
/* Rearrange thread lists as needed */ /* Rearrange thread lists as needed */
change_thread_state(blocked_list); change_thread_state(blocked_list);
@ -627,7 +672,6 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list)
#endif #endif
#endif #endif
unlock_cores();
/* And finally give control to the next thread. */ /* And finally give control to the next thread. */
load_context(&cores[core].running->context); load_context(&cores[core].running->context);
@ -641,8 +685,6 @@ void sleep_thread(int ticks)
{ {
struct thread_entry *current; struct thread_entry *current;
lock_cores();
current = cores[CURRENT_CORE].running; current = cores[CURRENT_CORE].running;
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
@ -668,8 +710,6 @@ void block_thread(struct thread_entry **list)
{ {
struct thread_entry *current; struct thread_entry *current;
lock_cores();
/* Get the entry for the current running thread. */ /* Get the entry for the current running thread. */
current = cores[CURRENT_CORE].running; current = cores[CURRENT_CORE].running;
@ -680,11 +720,9 @@ void block_thread(struct thread_entry **list)
unsigned long boost_flag = STATE_IS_BOOSTED(current->statearg); unsigned long boost_flag = STATE_IS_BOOSTED(current->statearg);
#endif #endif
#ifdef THREAD_EXTRA_CHECKS
/* We are not allowed to mix blocking types in one queue. */ /* We are not allowed to mix blocking types in one queue. */
if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO) THREAD_ASSERT(*list != NULL && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO,
thread_panicf("Blocking violation B->*T", current, *list); "Blocking violation B->*T", current);
#endif
/* Set the state to blocked and ask the scheduler to switch tasks, /* Set the state to blocked and ask the scheduler to switch tasks,
* this takes us off of the run queue until we are explicitly woken */ * 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)
/* Get the entry for the current running thread. */ /* Get the entry for the current running thread. */
current = cores[CURRENT_CORE].running; current = cores[CURRENT_CORE].running;
lock_cores();
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
/* A block with a timeout is a sleep situation, whatever we are waiting /* A block with a timeout is a sleep situation, whatever we are waiting
* for _may or may not_ happen, regardless of boost state, (user input * 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)
} }
#endif #endif
#ifdef THREAD_EXTRA_CHECKS
/* We can store only one thread to the "list" if thread is used /* We can store only one thread to the "list" if thread is used
* in other list (such as core's list for sleeping tasks). */ * in other list (such as core's list for sleeping tasks). */
if (*list) THREAD_ASSERT(*list == NULL, "Blocking violation T->*B", current);
thread_panicf("Blocking violation T->*B", current, NULL);
#endif
/* Set the state to blocked with the specified timeout */ /* Set the state to blocked with the specified timeout */
SET_STATE(current->statearg, STATE_BLOCKED_W_TMO, current_tick + timeout); SET_STATE(current->statearg, STATE_BLOCKED_W_TMO, current_tick + timeout);
@ -836,7 +870,6 @@ struct thread_entry*
unsigned int stacklen; unsigned int stacklen;
unsigned int *stackptr; unsigned int *stackptr;
int slot; int slot;
struct regs *regs;
struct thread_entry *thread; struct thread_entry *thread;
/***** /*****
@ -862,12 +895,9 @@ struct thread_entry*
} }
#endif #endif
lock_cores();
slot = find_empty_thread_slot(); slot = find_empty_thread_slot();
if (slot < 0) if (slot < 0)
{ {
unlock_cores();
return NULL; return NULL;
} }
@ -899,17 +929,13 @@ struct thread_entry*
flush_icache(); flush_icache();
#endif #endif
regs = &thread->context;
/* Align stack to an even 32 bit boundary */ /* Align stack to an even 32 bit boundary */
regs->sp = (void*)(((unsigned int)stack + stack_size) & ~3); thread->context.sp = (void*)(((unsigned int)stack + stack_size) & ~3);
regs->start = (void*)function;
/* Do any CPU specific inits after initializing common items /* Load the thread's context structure with needed startup information */
to have access to valid data */ THREAD_STARTUP_INIT(core, thread, function);
THREAD_CPU_INIT(core, thread);
add_to_list(&cores[core].running, thread); add_to_list(&cores[core].running, thread);
unlock_cores();
return thread; return thread;
#if NUM_CORES == 1 #if NUM_CORES == 1
@ -920,8 +946,6 @@ struct thread_entry*
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
void trigger_cpu_boost(void) void trigger_cpu_boost(void)
{ {
lock_cores();
if (!STATE_IS_BOOSTED(cores[CURRENT_CORE].running->statearg)) if (!STATE_IS_BOOSTED(cores[CURRENT_CORE].running->statearg))
{ {
SET_BOOST_STATE(cores[CURRENT_CORE].running->statearg); SET_BOOST_STATE(cores[CURRENT_CORE].running->statearg);
@ -931,8 +955,6 @@ void trigger_cpu_boost(void)
} }
boosted_threads++; boosted_threads++;
} }
unlock_cores();
} }
#endif #endif
@ -943,10 +965,10 @@ void trigger_cpu_boost(void)
*/ */
void remove_thread(struct thread_entry *thread) void remove_thread(struct thread_entry *thread)
{ {
lock_cores(); const unsigned int core = CURRENT_CORE;
if (thread == NULL) if (thread == NULL)
thread = cores[CURRENT_CORE].running; thread = cores[core].running;
/* Free the entry by removing thread name. */ /* Free the entry by removing thread name. */
thread->name = NULL; thread->name = NULL;
@ -957,16 +979,26 @@ void remove_thread(struct thread_entry *thread)
if (thread == cores[IF_COP2(thread->core)].running) if (thread == cores[IF_COP2(thread->core)].running)
{ {
remove_from_list(&cores[IF_COP2(thread->core)].running, thread); remove_from_list(&cores[IF_COP2(thread->core)].running, thread);
#if NUM_CORES > 1
/* Switch to the idle stack if not on the main core (where "main"
* runs) */
if (core != CPU)
{
switch_to_idle_stack(core);
}
flush_icache();
#endif
switch_thread(false, NULL); switch_thread(false, NULL);
return ; /* This should never and must never be reached - if it is, the
* state is corrupted */
THREAD_PANICF("remove_thread->K:*R", thread);
} }
if (thread == cores[IF_COP2(thread->core)].sleeping) if (thread == cores[IF_COP2(thread->core)].sleeping)
remove_from_list(&cores[IF_COP2(thread->core)].sleeping, thread); remove_from_list(&cores[IF_COP2(thread->core)].sleeping, thread);
else else
remove_from_list(NULL, thread); remove_from_list(NULL, thread);
unlock_cores();
} }
#ifdef HAVE_PRIORITY_SCHEDULING #ifdef HAVE_PRIORITY_SCHEDULING
@ -974,14 +1006,12 @@ int thread_set_priority(struct thread_entry *thread, int priority)
{ {
int old_priority; int old_priority;
lock_cores();
if (thread == NULL) if (thread == NULL)
thread = cores[CURRENT_CORE].running; thread = cores[CURRENT_CORE].running;
old_priority = thread->priority; old_priority = thread->priority;
thread->priority = priority; thread->priority = priority;
cores[IF_COP2(thread->core)].highest_priority = 100; cores[IF_COP2(thread->core)].highest_priority = 100;
unlock_cores();
return old_priority; return old_priority;
} }
@ -1013,15 +1043,7 @@ void init_threads(void)
const unsigned int core = CURRENT_CORE; const unsigned int core = CURRENT_CORE;
int slot; int slot;
/* Let main CPU initialize first. */ /* CPU will initialize first and then sleep */
#if NUM_CORES > 1
if (core != CPU)
{
while (!cores[CPU].kernel_running) ;
}
#endif
lock_cores();
slot = find_empty_thread_slot(); slot = find_empty_thread_slot();
cores[core].sleeping = NULL; cores[core].sleeping = NULL;
@ -1041,9 +1063,6 @@ void init_threads(void)
threads[slot].priority = PRIORITY_USER_INTERFACE; threads[slot].priority = PRIORITY_USER_INTERFACE;
threads[slot].priority_x = 0; threads[slot].priority_x = 0;
cores[core].highest_priority = 100; cores[core].highest_priority = 100;
#endif
#ifdef HAVE_SCHEDULER_BOOSTCTRL
boosted_threads = 0;
#endif #endif
add_to_list(&cores[core].running, &threads[slot]); add_to_list(&cores[core].running, &threads[slot]);
@ -1051,21 +1070,34 @@ void init_threads(void)
* probably a much better way to do this. */ * probably a much better way to do this. */
if (core == CPU) if (core == CPU)
{ {
#ifdef HAVE_SCHEDULER_BOOSTCTRL
boosted_threads = 0;
#endif
threads[slot].stack = stackbegin; threads[slot].stack = stackbegin;
threads[slot].stack_size = (int)stackend - (int)stackbegin; threads[slot].stack_size = (int)stackend - (int)stackbegin;
}
#if NUM_CORES > 1 /* This code path will not be run on single core targets */ #if NUM_CORES > 1 /* This code path will not be run on single core targets */
/* Mark CPU initialized */
cores[CPU].kernel_running = true;
/* TODO: HAL interface for this */
/* Wake up coprocessor and let it initialize kernel and threads */
COP_CTL = PROC_WAKE;
/* Sleep until finished */
CPU_CTL = PROC_SLEEP;
}
else else
{ {
threads[slot].stack = cop_stackbegin; /* Initial stack is the COP idle stack */
threads[slot].stack_size = threads[slot].stack = cop_idlestackbegin;
(int)cop_stackend - (int)cop_stackbegin; threads[slot].stack_size = IDLE_STACK_SIZE;
} /* Mark COP initialized */
cores[COP].kernel_running = true;
cores[core].kernel_running = true; /* Get COP safely primed inside switch_thread where it will remain
* until a thread actually exists on it */
CPU_CTL = PROC_WAKE;
set_irq_level(0);
remove_thread(NULL);
#endif #endif
}
unlock_cores();
} }
int thread_stack_usage(const struct thread_entry *thread) int thread_stack_usage(const struct thread_entry *thread)
@ -1083,7 +1115,59 @@ int thread_stack_usage(const struct thread_entry *thread)
thread->stack_size; thread->stack_size;
} }
#if NUM_CORES > 1
/*---------------------------------------------------------------------------
* Returns the maximum percentage of the core's idle stack ever used during
* runtime.
*---------------------------------------------------------------------------
*/
int idle_stack_usage(unsigned int core)
{
unsigned int *stackptr = idle_stacks[core];
int i, usage = 0;
for (i = 0; i < IDLE_STACK_WORDS; i++)
{
if (stackptr[i] != DEADBEEF)
{
usage = ((IDLE_STACK_WORDS - i) * 100) / IDLE_STACK_WORDS;
break;
}
}
return usage;
}
#endif
int thread_get_status(const struct thread_entry *thread) int thread_get_status(const struct thread_entry *thread)
{ {
return GET_STATE(thread->statearg); return GET_STATE(thread->statearg);
} }
/*---------------------------------------------------------------------------
* Fills in the buffer with the specified thread's name. If the name is NULL,
* empty, or the thread is in destruct state a formatted ID is written
* instead.
*---------------------------------------------------------------------------
*/
void thread_get_name(char *buffer, int size,
struct thread_entry *thread)
{
if (size <= 0)
return;
*buffer = '\0';
if (thread)
{
/* Display thread name if one or ID if none */
const char *name = thread->name;
const char *fmt = "%s";
if (name == NULL || *name == '\0')
{
name = (const char *)thread;
fmt = "%08lX";
}
snprintf(buffer, size, fmt, name);
}
}

View file

@ -306,7 +306,6 @@ void usb_init(void)
#ifndef BOOTLOADER #ifndef BOOTLOADER
queue_init(&usb_queue, true); queue_init(&usb_queue, true);
queue_set_irq_safe(&usb_queue, true);
create_thread(usb_thread, usb_stack, sizeof(usb_stack), create_thread(usb_thread, usb_stack, sizeof(usb_stack),
usb_thread_name IF_PRIO(, PRIORITY_SYSTEM) usb_thread_name IF_PRIO(, PRIORITY_SYSTEM)