ish: save/restore FPU context only for the task uses FPU
Currently we save/retore FPU H/W context for every task on every contxt switch. This hurts overall performance of ISH. This patch allows save and restore FPU H/W context only for a task that declares it uses FPU. BRANCH=none BUG=none TEST=verified in Atlas platform Change-Id: Ic2f0bbf59f655661e2dd788c688edc4e83068c1c Signed-off-by: Hyungwoo Yang <hyungwoo.yang@intel.com> Reviewed-on: https://chromium-review.googlesource.com/1448818 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Hyungwoo Yang <hyungwoo.yang@intel.corp-partner.google.com> Reviewed-by: Jett Rink <jettrink@chromium.org>
This commit is contained in:
parent
0a3f44e4f5
commit
decc9452e9
|
@ -8,15 +8,17 @@
|
|||
*
|
||||
* The first one has the lowest priority.
|
||||
*
|
||||
* For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
|
||||
* TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
|
||||
* For each task, use the macro TASK_ALWAYS(n, r, d, s, f) for base tasks and
|
||||
* TASK_NOTEST(n, r, d, s, f) for tasks that can be excluded in test binaries,
|
||||
* where :
|
||||
* 'n' in the name of the task
|
||||
* 'r' in the main routine of the task
|
||||
* 'd' in an opaque parameter passed to the routine at startup
|
||||
* 's' is the stack size in bytes; must be a multiple of 8
|
||||
* 'f' is the bit flags for the platform specific information
|
||||
* - MIA_TASK_FLAG_USE_FPU : bit 0, task uses FPU H/W
|
||||
*/
|
||||
|
||||
#define CONFIG_TASK_LIST \
|
||||
TASK_ALWAYS(HOOKS, hook_task, NULL, HUGE_TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE)
|
||||
TASK_ALWAYS(HOOKS, hook_task, NULL, HUGE_TASK_STACK_SIZE, 0) \
|
||||
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE, 0)
|
||||
|
|
|
@ -8,17 +8,19 @@
|
|||
*
|
||||
* The first one has the lowest priority.
|
||||
*
|
||||
* For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
|
||||
* TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
|
||||
* For each task, use the macro TASK_ALWAYS(n, r, d, s, f) for base tasks and
|
||||
* TASK_NOTEST(n, r, d, s, f) for tasks that can be excluded in test binaries,
|
||||
* where :
|
||||
* 'n' in the name of the task
|
||||
* 'r' in the main routine of the task
|
||||
* 'd' in an opaque parameter passed to the routine at startup
|
||||
* 's' is the stack size in bytes; must be a multiple of 8
|
||||
* 'f' is the bit flags for the platform specific information
|
||||
* - MIA_TASK_FLAG_USE_FPU : bit 0, task uses FPU H/W
|
||||
*/
|
||||
|
||||
#define CONFIG_TASK_LIST \
|
||||
TASK_ALWAYS(HOOKS, hook_task, NULL, HUGE_TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(HECI_RX, heci_rx_task, NULL, HUGE_TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(IPC_MNG, ipc_mng_task, NULL, LARGER_TASK_STACK_SIZE)
|
||||
TASK_ALWAYS(HOOKS, hook_task, NULL, HUGE_TASK_STACK_SIZE, 0) \
|
||||
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE, 0) \
|
||||
TASK_ALWAYS(HECI_RX, heci_rx_task, NULL, HUGE_TASK_STACK_SIZE, 0) \
|
||||
TASK_ALWAYS(IPC_MNG, ipc_mng_task, NULL, LARGER_TASK_STACK_SIZE, 0)
|
||||
|
|
|
@ -26,4 +26,9 @@
|
|||
#define ASM_LOCK_PREFIX
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flag indicates the task uses FPU H/W
|
||||
*/
|
||||
#define MIA_TASK_FLAG_USE_FPU 0x00000001
|
||||
|
||||
#endif /* __CROS_EC_CONFIG_CORE_H */
|
||||
|
|
|
@ -9,10 +9,20 @@
|
|||
#define __CROS_EC_IRQ_HANDLER_H
|
||||
|
||||
#include "registers.h"
|
||||
#include "task_defs.h"
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
#define save_fpu_ctx "fnsave 20(%eax)\n"
|
||||
#define rstr_fpu_ctx "frstor 20(%eax)\n"
|
||||
#define save_fpu_ctx "movl "USE_FPU_OFFSET_STR"(%eax), %ebx\n" \
|
||||
"test %ebx, %ebx\n" \
|
||||
"jz 9f\n" \
|
||||
"fnsave "FPU_CTX_OFFSET_STR"(%eax)\n" \
|
||||
"9:\n"
|
||||
|
||||
#define rstr_fpu_ctx "movl "USE_FPU_OFFSET_STR"(%eax), %ebx\n" \
|
||||
"test %ebx, %ebx\n" \
|
||||
"jz 9f\n" \
|
||||
"frstor "FPU_CTX_OFFSET_STR"(%eax)\n" \
|
||||
"9:\n"
|
||||
#else
|
||||
#define save_fpu_ctx
|
||||
#define rstr_fpu_ctx
|
||||
|
|
|
@ -33,7 +33,11 @@ __task_start:
|
|||
movl current_task, %eax
|
||||
movl (%eax), %esp
|
||||
#ifdef CONFIG_FPU
|
||||
frstor 20(%eax)
|
||||
movl USE_FPU_OFFSET(%eax), %ebx
|
||||
test %ebx, %ebx
|
||||
jz 1f
|
||||
frstor FPU_CTX_OFFSET(%eax)
|
||||
1:
|
||||
#endif
|
||||
movl $0x1, (%ebx) # first task is ready. set start_called = 1
|
||||
popa
|
||||
|
@ -112,7 +116,11 @@ __switchto:
|
|||
movl current_task, %eax
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
fnsave 20(%eax) # Save current FPU context at current->fp_ctx
|
||||
movl USE_FPU_OFFSET(%eax), %ebx
|
||||
test %ebx, %ebx
|
||||
jz 2f
|
||||
fnsave FPU_CTX_OFFSET(%eax) # Save current FPU context(current->fp_ctx)
|
||||
2:
|
||||
#endif
|
||||
|
||||
# Save SP of current task and switch to new task
|
||||
|
@ -122,7 +130,10 @@ __switchto:
|
|||
movl (%eax), %esp
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
frstor 20(%eax) # Restore next FPU context
|
||||
movl USE_FPU_OFFSET(%eax), %ebx
|
||||
test %ebx, %ebx
|
||||
jz 1f
|
||||
frstor FPU_CTX_OFFSET(%eax) # Restore next FPU context
|
||||
#endif
|
||||
|
||||
1:
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define STACK_UNUSED_VALUE 0xdeadd00d
|
||||
|
||||
/* declare task routine prototypes */
|
||||
#define TASK(n, r, d, s) void r(void *);
|
||||
#define TASK(n, r, d, s, f) void r(void *);
|
||||
void __idle(void);
|
||||
CONFIG_TASK_LIST
|
||||
CONFIG_TEST_TASK_LIST
|
||||
|
@ -36,7 +36,7 @@ CONFIG_TEST_TASK_LIST
|
|||
extern volatile uint32_t __in_isr;
|
||||
|
||||
/* Task names for easier debugging */
|
||||
#define TASK(n, r, d, s) #n,
|
||||
#define TASK(n, r, d, s, f) #n,
|
||||
static const char * const task_names[] = {
|
||||
"<< idle >>",
|
||||
CONFIG_TASK_LIST
|
||||
|
@ -90,17 +90,19 @@ static void task_exit_trap(void)
|
|||
}
|
||||
|
||||
/* Startup parameters for all tasks. */
|
||||
#define TASK(n, r, d, s) { \
|
||||
#define TASK(n, r, d, s, f) { \
|
||||
.r0 = (uint32_t)d, \
|
||||
.pc = (uint32_t)r, \
|
||||
.stack_size = s, \
|
||||
.flags = f, \
|
||||
},
|
||||
static const struct {
|
||||
uint32_t r0;
|
||||
uint32_t pc;
|
||||
uint16_t stack_size;
|
||||
uint32_t flags;
|
||||
} tasks_init[] = {
|
||||
TASK(IDLE, __idle, 0, IDLE_TASK_STACK_SIZE)
|
||||
TASK(IDLE, __idle, 0, IDLE_TASK_STACK_SIZE, 0)
|
||||
CONFIG_TASK_LIST
|
||||
CONFIG_TEST_TASK_LIST
|
||||
};
|
||||
|
@ -115,9 +117,9 @@ BUILD_ASSERT(TASK_ID_COUNT < (1 << (sizeof(task_id_t) * 8)));
|
|||
|
||||
|
||||
/* Stacks for all tasks */
|
||||
#define TASK(n, r, d, s) + s
|
||||
#define TASK(n, r, d, s, f) + s
|
||||
uint8_t task_stacks[0
|
||||
TASK(IDLE, __idle, 0, IDLE_TASK_STACK_SIZE)
|
||||
TASK(IDLE, __idle, 0, IDLE_TASK_STACK_SIZE, 0)
|
||||
CONFIG_TASK_LIST
|
||||
CONFIG_TEST_TASK_LIST
|
||||
] __aligned(8);
|
||||
|
@ -474,10 +476,18 @@ void task_print_list(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
ccputs("Task Ready Name Events Time (s) "
|
||||
" StkUsed UseFPU\n");
|
||||
#else
|
||||
ccputs("Task Ready Name Events Time (s) StkUsed\n");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < TASK_ID_COUNT; i++) {
|
||||
char is_ready = (tasks_ready & (1<<i)) ? 'R' : ' ';
|
||||
#ifdef CONFIG_FPU
|
||||
char use_fpu = tasks[i].use_fpu ? 'Y' : 'N';
|
||||
#endif
|
||||
uint32_t *sp;
|
||||
|
||||
int stackused = tasks_init[i].stack_size;
|
||||
|
@ -487,9 +497,16 @@ void task_print_list(void)
|
|||
sp++)
|
||||
stackused -= sizeof(uint32_t);
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
ccprintf("%4d %c %-16s %08x %11.6ld %3d/%3d %c\n", i, is_ready,
|
||||
task_names[i], tasks[i].events, tasks[i].runtime,
|
||||
stackused, tasks_init[i].stack_size, use_fpu);
|
||||
#else
|
||||
ccprintf("%4d %c %-16s %08x %11.6ld %3d/%3d\n", i, is_ready,
|
||||
task_names[i], tasks[i].events, tasks[i].runtime,
|
||||
stackused, tasks_init[i].stack_size);
|
||||
#endif
|
||||
|
||||
cflush();
|
||||
}
|
||||
}
|
||||
|
@ -606,6 +623,9 @@ void task_pre_init(void)
|
|||
/* Copy default x86 FPU state for each task */
|
||||
memcpy(tasks[i].fp_ctx, default_fp_ctx,
|
||||
sizeof(default_fp_ctx));
|
||||
|
||||
if (tasks_init[i].flags & MIA_TASK_FLAG_USE_FPU)
|
||||
tasks[i].use_fpu = 1;
|
||||
#endif
|
||||
/* Fill unused stack; also used to detect stack overflow. */
|
||||
for (sp = stack_next; sp < (uint32_t *)tasks[i].sp; sp++)
|
||||
|
@ -618,7 +638,6 @@ void task_pre_init(void)
|
|||
|
||||
/* Initialize IRQs */
|
||||
init_interrupts();
|
||||
|
||||
}
|
||||
|
||||
void task_clear_fp_used(void)
|
||||
|
|
|
@ -6,8 +6,21 @@
|
|||
#ifndef __CROS_EC_TASK_DEFS_H
|
||||
#define __CROS_EC_TASK_DEFS_H
|
||||
|
||||
#define FPU_CTX_SZ 108 /* 28 bytes header + 80 bytes registers */
|
||||
#define FPU_CTX_OFFSET 20 /* offsetof(task_, fp_ctx) */
|
||||
#ifdef CONFIG_FPU
|
||||
#define FPU_CTX_SZ 108 /* 28 bytes header + 80 bytes registers */
|
||||
#define USE_FPU_OFFSET 20 /* offsetof(task_, use_fpu */
|
||||
#define FPU_CTX_OFFSET 24 /* offsetof(task_, fp_ctx) */
|
||||
|
||||
/*
|
||||
* defines for inline asm
|
||||
*/
|
||||
#ifndef __ASSEMBLER__
|
||||
#include "common.h"
|
||||
|
||||
#define USE_FPU_OFFSET_STR STRINGIFY(USE_FPU_OFFSET) /* "20" */
|
||||
#define FPU_CTX_OFFSET_STR STRINGIFY(FPU_CTX_OFFSET) /* "24" */
|
||||
#endif
|
||||
#endif /* CONFIG_FPU */
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
typedef union {
|
||||
|
@ -21,6 +34,7 @@ typedef union {
|
|||
uint64_t runtime; /* Time spent in task */
|
||||
uint32_t *stack; /* Start of stack */
|
||||
#ifdef CONFIG_FPU
|
||||
uint32_t use_fpu; /* set if task uses FPU */
|
||||
uint8_t fp_ctx[FPU_CTX_SZ]; /* x87 FPU context */
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -13,21 +13,21 @@
|
|||
#define TASK_NOTEST_RO TASK_NOTEST
|
||||
#define TASK_TEST_RO TASK_TEST
|
||||
#define TASK_ALWAYS_RO TASK_ALWAYS
|
||||
#define TASK_NOTEST_RW(n, r, d, s)
|
||||
#define TASK_TEST_RW(n, r, d, s)
|
||||
#define TASK_ALWAYS_RW(n, r, d, s)
|
||||
#define TASK_NOTEST_RW(...)
|
||||
#define TASK_TEST_RW(...)
|
||||
#define TASK_ALWAYS_RW(...)
|
||||
#else /* SECTION_IS_RW */
|
||||
#define TASK_NOTEST_RW TASK_NOTEST
|
||||
#define TASK_TEST_RW TASK_TEST
|
||||
#define TASK_ALWAYS_RW TASK_ALWAYS
|
||||
#define TASK_NOTEST_RO(n, r, d, s)
|
||||
#define TASK_TEST_RO(n, r, d, s)
|
||||
#define TASK_ALWAYS_RO(n, r, d, s)
|
||||
#define TASK_NOTEST_RO(...)
|
||||
#define TASK_TEST_RO(...)
|
||||
#define TASK_ALWAYS_RO(...)
|
||||
#endif
|
||||
|
||||
/* excludes non-base tasks for test build */
|
||||
#ifdef TEST_BUILD
|
||||
#define TASK_NOTEST(n, r, d, s)
|
||||
#define TASK_NOTEST(...)
|
||||
#define TASK_TEST TASK
|
||||
#else
|
||||
#define TASK_NOTEST TASK
|
||||
|
@ -42,7 +42,7 @@
|
|||
|
||||
/* If included directly from Makefile, dump task list. */
|
||||
#ifdef _MAKEFILE
|
||||
#define TASK(n, r, d, s) n
|
||||
#define TASK(n, ...) n
|
||||
CONFIG_TASK_LIST CONFIG_TEST_TASK_LIST CONFIG_CTS_TASK_LIST
|
||||
#endif
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ typedef uint8_t task_id_t;
|
|||
* TASK_ID_<taskname> where <taskname> is the first parameter passed to the
|
||||
* TASK macro in the TASK_LIST file.
|
||||
*/
|
||||
#define TASK(n, r, d, s) TASK_ID_##n,
|
||||
#define TASK(n, ...) TASK_ID_##n,
|
||||
enum {
|
||||
TASK_ID_IDLE,
|
||||
/* CONFIG_TASK_LIST is a macro coming from the BOARD_TASK_LIST file */
|
||||
|
|
|
@ -25,10 +25,10 @@ struct taskinfo {
|
|||
uint32_t stack_size;
|
||||
};
|
||||
|
||||
#define TASK(n, r, d, s) { \
|
||||
.name = #n, \
|
||||
.routine = #r, \
|
||||
.stack_size = s, \
|
||||
#define TASK(n, r, d, s, ...) { \
|
||||
.name = #n, \
|
||||
.routine = #r, \
|
||||
.stack_size = s, \
|
||||
},
|
||||
static const struct taskinfo taskinfos[] = {
|
||||
CONFIG_TASK_LIST
|
||||
|
|
Loading…
Reference in New Issue