diff options
author | Dino Li <dino.li@ite.com.tw> | 2015-10-01 11:46:00 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2015-10-01 01:55:26 -0700 |
commit | 692428e1a6676efa7e952b747aac1cee6c503922 (patch) | |
tree | bb4423190b979695733fa41c681945fa1c489fd9 /core | |
parent | 04bb47c32a22bc6b01dc1d03a423a945a74b1c10 (diff) | |
download | chrome-ec-692428e1a6676efa7e952b747aac1cee6c503922.tar.gz |
it8380dev: fix hw timer and related function.
[chip config]
1. No hardware specific udelay().
2. Enable watchdog.
[watchdog]
3. Watchdog period is "CONFIG_WATCHDOG_PERIOD_MS" of config.h.
4. Watchdog auxiliary timer period is "CONFIG_AUX_TIMER_PERIOD_MS".
[task and irq]
5. Write 1 to clear interrupt pending status, no |.
6. A global variable for store interrupt number of software interrupt.
[uart]
7. Always reset UART module before config it.
[hwtimer]
8. Use more external timers for HW timer module.
[task]
9. Fix task profiling.
Signed-off-by: Dino Li <dino.li@ite.com.tw>
BRANCH=none
BUG=none
TEST=[watchdog]
1. console "waitms 1100", only pre-watchdog warning message.
2. console "waitms 1600", warning message and watchdog reset.
[hwtimer]
3. console commands "gettime", "timerinfo", and "forcetime".
4. enable hook debug and there is no delayed by more than 10%
warning message over 48 hours.
5. There is no watchdog reset too.
[task]
6. console 'taskinfo'
Task Ready Name Events Time (s) StkUsed
0 R << idle >> 00000000 32.927724 308/512
1 HOOKS 00000000 0.034267 372/768
2 R CONSOLE 00000000 0.116763 468/768
3 HOSTCMD 00000000 0.000641 372/512
4 KEYPROTO 00000000 0.000042 212/512
5 KEYSCAN 00000000 0.000908 356/512
IRQ counts by type:
38 2932
155 1
158 261
160 67
Service calls: 87
Total exceptions: 3348
Task switches: 167
Task switching started: 0.001999 s
Time in tasks: 33.282819 s
Time in exceptions: 0.164717 s
Change-Id: I234085cec231cd855d2a5e639ea1b0966c61d796
Reviewed-on: https://chromium-review.googlesource.com/296939
Commit-Ready: Dino Li <dino.li@ite.com.tw>
Tested-by: Dino Li <dino.li@ite.com.tw>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'core')
-rw-r--r-- | core/nds32/init.S | 4 | ||||
-rw-r--r-- | core/nds32/irq_chip.h | 5 | ||||
-rw-r--r-- | core/nds32/switch.S | 2 | ||||
-rw-r--r-- | core/nds32/task.c | 132 |
4 files changed, 141 insertions, 2 deletions
diff --git a/core/nds32/init.S b/core/nds32/init.S index a27fcd8d0e..d5d93d299b 100644 --- a/core/nds32/init.S +++ b/core/nds32/init.S @@ -20,6 +20,8 @@ __entry_\()\name: smw.adm $r15, [$sp], $r15, 0xb /* r0-r5 are caller saved */ smw.adm $r0, [$sp], $r5, 0 + /* isr entry */ + jal start_irq_handler /* switch to system stack if we are called from process stack */ la $r3, stack_end mov55 $fp, $sp @@ -30,6 +32,8 @@ __entry_\()\name: /* check whether we need to change the scheduled task */ lwi.gp $r2, [ + need_resched] bnez $r2, __switch_task + /* isr exit */ + jal end_irq_handler /* restore r0-r5 */ lmw.bim $r0, [$fp], $r5, 0 /* restore r15, fp, lp and sp */ diff --git a/core/nds32/irq_chip.h b/core/nds32/irq_chip.h index e7b67317a8..dfbd75ea6f 100644 --- a/core/nds32/irq_chip.h +++ b/core/nds32/irq_chip.h @@ -51,4 +51,9 @@ int chip_trigger_irq(int irq); */ void chip_init_irqs(void); +/** + * Return interrupt number of software interrupt. + */ +int get_sw_int(void); + #endif /* __CROS_EC_IRQ_CHIP_H */ diff --git a/core/nds32/switch.S b/core/nds32/switch.S index 2c4ce0c273..81c0770dea 100644 --- a/core/nds32/switch.S +++ b/core/nds32/switch.S @@ -63,6 +63,8 @@ __switch_task: /* exception frame pointer for the new task */ mov55 $fp, $r3 1: /* un-pile the interruption entry context */ + /* isr exit */ + jal end_irq_handler /* restore r0-r5 */ lmw.bim $r0, [$fp], $r5, 0 /* restore r15, fp, lp and sp */ diff --git a/core/nds32/task.c b/core/nds32/task.c index 3c7358abe6..df7743ed82 100644 --- a/core/nds32/task.c +++ b/core/nds32/task.c @@ -48,6 +48,18 @@ static const char * const task_names[] = { }; #undef TASK +#ifdef CONFIG_TASK_PROFILING +static int task_will_switch; +static uint64_t exc_sub_time; +static uint64_t task_start_time; /* Time task scheduling started */ +static uint64_t exc_start_time; /* Time of task->exception transition */ +static uint64_t exc_end_time; /* Time of exception->task transition */ +static uint64_t exc_total_time; /* Total time in exceptions */ +static uint32_t svc_calls; /* Number of service calls */ +static uint32_t task_switches; /* Number of times active task changed */ +static uint32_t irq_dist[CONFIG_IRQ_COUNT]; /* Distribution of IRQ calls */ +#endif + extern int __task_start(void); #ifndef CONFIG_LOW_POWER_IDLE @@ -168,6 +180,9 @@ static uint32_t tasks_ready = (1 << TASK_ID_HOOKS); static int start_called; /* Has task swapping started */ +/* interrupt number of sw interrupt */ +static int sw_int_num; + static inline task_ *__task_id_to_ptr(task_id_t id) { return tasks + id; @@ -237,6 +252,14 @@ int task_start_called(void) return start_called; } +int get_sw_int(void) +{ + /* If this is a SW interrupt */ + if (get_itype() & 8) + return sw_int_num; + return 0; +} + /** * Scheduling system call * @@ -251,6 +274,7 @@ void syscall_handler(int desched, task_id_t resched, int swirq) set_ipc(get_ipc() + 4); /* call the regular IRQ handler */ handler(); + sw_int_num = 0; return; } @@ -266,13 +290,27 @@ void syscall_handler(int desched, task_id_t resched, int swirq) /* trigger a re-scheduling on exit */ need_resched = 1; +#ifdef CONFIG_TASK_PROFILING + svc_calls++; +#endif + /* adjust IPC to return *after* the syscall instruction */ set_ipc(get_ipc() + 4); } task_ *next_sched_task(void) { - return __task_id_to_ptr(__fls(tasks_ready)); + task_ *new_task = __task_id_to_ptr(__fls(tasks_ready)); + +#ifdef CONFIG_TASK_PROFILING + if (current_task != new_task) { + current_task->runtime += + (exc_start_time - exc_end_time - exc_sub_time); + task_will_switch = 1; + } +#endif + + return new_task; } static inline void __schedule(int desched, int resched, int swirq) @@ -284,6 +322,67 @@ static inline void __schedule(int desched, int resched, int swirq) asm("syscall 0" : : "r"(p0), "r"(p1), "r"(p2)); } +void update_exc_start_time(void) +{ +#ifdef CONFIG_TASK_PROFILING + exc_start_time = get_time().val; +#endif +} + +void start_irq_handler(void) +{ +#ifdef CONFIG_TASK_PROFILING + int irq; + + /* save r0, r1, and r2 for syscall */ + asm volatile ("smw.adm $r0, [$sp], $r2, 0"); + + update_exc_start_time(); + + irq = get_sw_int(); + if (!irq) + irq = IT83XX_INTC_AIVCT - 16; + + /* + * Track IRQ distribution. No need for atomic add, because an IRQ + * can't pre-empt itself. + */ + if ((irq > 0) && (irq < ARRAY_SIZE(irq_dist))) + irq_dist[irq]++; + + /* restore r0, r1, and r2 */ + asm volatile ("lmw.bim $r0, [$sp], $r2, 0"); +#endif +} + +void end_irq_handler(void) +{ +#ifdef CONFIG_TASK_PROFILING + uint64_t t, p; + + /* + * save r0 and fp (fp for restore r0-r5, r15, fp, lp and sp + * while interrupt exit. + */ + asm volatile ("smw.adm $r0, [$sp], $r0, 8"); + + t = get_time().val; + p = t - exc_start_time; + + exc_total_time += p; + exc_sub_time += p; + if (task_will_switch) { + task_will_switch = 0; + exc_sub_time = 0; + exc_end_time = t; + task_switches++; + } + + /* restore r0 and fp */ + asm volatile ("lmw.bim $r0, [$sp], $r0, 8"); +#endif +} + static uint32_t __wait_evt(int timeout_us, task_id_t resched) { task_ *tsk = current_task; @@ -380,8 +479,10 @@ void task_clear_pending_irq(int irq) void task_trigger_irq(int irq) { int cpu_int = chip_trigger_irq(irq); - if (cpu_int > 0) + if (cpu_int > 0) { + sw_int_num = irq; __schedule(0, 0, cpu_int); + } } /* @@ -490,8 +591,32 @@ void task_print_list(void) int command_task_info(int argc, char **argv) { +#ifdef CONFIG_TASK_PROFILING + int total = 0; + int i; +#endif + task_print_list(); +#ifdef CONFIG_TASK_PROFILING + ccputs("IRQ counts by type:\n"); + cflush(); + for (i = 0; i < ARRAY_SIZE(irq_dist); i++) { + if (irq_dist[i]) { + ccprintf("%4d %8d\n", i, irq_dist[i]); + total += irq_dist[i]; + } + } + + ccprintf("Service calls: %11d\n", svc_calls); + ccprintf("Total exceptions: %11d\n", total + svc_calls); + ccprintf("Task switches: %11d\n", task_switches); + ccprintf("Task switching started: %11.6ld s\n", task_start_time); + ccprintf("Time in tasks: %11.6ld s\n", + get_time().val - task_start_time); + ccprintf("Time in exceptions: %11.6ld s\n", exc_total_time); +#endif + return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(taskinfo, command_task_info, @@ -564,6 +689,9 @@ void task_pre_init(void) int task_start(void) { +#ifdef CONFIG_TASK_PROFILING + task_start_time = exc_end_time = get_time().val; +#endif start_called = 1; return __task_start(); |