From cf9f3aab5b47708cfe92ee8cd916445d9301ecd9 Mon Sep 17 00:00:00 2001 From: Amit Mahajan Date: Tue, 1 Dec 2009 23:31:23 +0530 Subject: [PATCH] Timer service enhanced for sleep --- conts/baremetal/timer_service/include/timer.h | 36 +++++++++ conts/baremetal/timer_service/main.c | 76 ++++++++++++++++--- .../libdev/timer/sp804/include/sp804_timer.h | 4 - conts/libdev/timer/sp804/src/sp804_timer.c | 3 + 4 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 conts/baremetal/timer_service/include/timer.h diff --git a/conts/baremetal/timer_service/include/timer.h b/conts/baremetal/timer_service/include/timer.h new file mode 100644 index 0000000..260b57b --- /dev/null +++ b/conts/baremetal/timer_service/include/timer.h @@ -0,0 +1,36 @@ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +/* + * Timer specific things are here + */ +#include +#include + +/* + * Structure representing the sleeping tasks, + * tgid: tgid of sleeping task + * wait_count: time left, in microseconds, after which task + * will be signalled to get out of sleep + */ +struct timer_task { + struct link list; + l4id_t tgid; + unsigned int wait_count; +}; + +/* + * Timer structure, + * base: base address of sp804 timer encapsulated + * count: Count in microseconds from the start of this timer + * tasklist: list of tasks sleeping for some value of count + * lock: lock protecting the corruption of tasklist + */ +struct sp804_timer { + unsigned int base; + unsigned int count; + struct link tasklist; + struct l4_mutex lock; +}; + +#endif /* __TIMER_H__ */ diff --git a/conts/baremetal/timer_service/main.c b/conts/baremetal/timer_service/main.c index c95c7f8..02f53df 100644 --- a/conts/baremetal/timer_service/main.c +++ b/conts/baremetal/timer_service/main.c @@ -9,11 +9,12 @@ #include #include +#include #include #include #include "sp804_timer.h" #include - +#include /* Frequency of timer in MHz */ #define TIMER_FREQUENCY 1 @@ -148,11 +149,31 @@ int timer_probe_devices(void) static struct sp804_timer timer[TIMERS_TOTAL]; +struct timer_task *get_timer_task(l4id_t tgid) +{ + /* May be we can prepare a cache for timer_task structs */ + struct timer_task *task = (struct timer_task *)kzalloc(sizeof(struct timer_task)); + + link_init(&task->list); + task->tgid = tgid; + task->wait_count = timer[0].count; + + return task; +} + +void free_timer_task(struct timer_task *task) +{ + kfree(task); +} + int timer_setup_devices(void) { for (int i = 0; i < TIMERS_TOTAL; i++) { /* Get one page from address pool */ timer[i].base = (unsigned long)l4_new_virtual(1); + timer[i].count = 0; + link_init(&timer[i].tasklist); + l4_mutex_init(&timer[i].lock); /* Map timers to a virtual address region */ if (IS_ERR(l4_map((void *)__pfn_to_addr(timer_cap[i].start), @@ -166,10 +187,12 @@ int timer_setup_devices(void) } /* Initialise timer */ - sp804_init(timer[i].base, SP804_TIMER_RUNMODE_FREERUN, \ + sp804_init(timer[i].base, SP804_TIMER_RUNMODE_PERIODIC, \ SP804_TIMER_WRAPMODE_WRAPPING, SP804_TIMER_WIDTH32BIT, \ SP804_TIMER_IRQDISABLE); + /* Request IRQ for this timer */ + /* Enable Timer */ sp804_enable(timer[i].base, 1); } @@ -226,18 +249,48 @@ void *l4_new_virtual(int npages) return address_new(&device_vaddr_pool, npages, PAGE_SIZE); } -int timer_gettime(int devno) +void timer_irq_handler(void) { - return sp804_read_value(timer[devno].base); + struct timer_task *struct_ptr, *temp_ptr; + + timer[0].count += 1; + + /* + * FIXME: + * Traverse through the sleeping process list and + * wake any process if required, we need to put this part in bottom half + */ + list_foreach_removable_struct(struct_ptr, temp_ptr, &timer[0].tasklist, list) + if (struct_ptr->wait_count == timer[0].count) { + + /* Remove task from list */ + l4_mutex_lock(&timer[0].lock); + list_remove(&struct_ptr->list); + l4_mutex_unlock(&timer[0].lock); + + /* wake the sleeping process, send wake ipc */ + + free_timer_task(struct_ptr); + } } -void timer_sleep(int sec) +int timer_gettime(void) { - /* - * TODO: We need to have a timer struct already present to be used - * as reference for us. to implement this call - */ + return timer[0].count; } + +void timer_sleep(l4id_t tgid, int sec) +{ + struct timer_task *task = get_timer_task(tgid); + + /* Check for overflow */ + task->wait_count += (sec * 1000000); + + l4_mutex_lock(&timer[0].lock); + list_insert_tail(&task->list, &timer[0].tasklist); + l4_mutex_unlock(&timer[0].lock); +} + void handle_requests(void) { u32 mr[MR_UNUSED_TOTAL]; @@ -273,11 +326,12 @@ void handle_requests(void) */ switch (tag) { case L4_IPC_TAG_TIMER_GETTIME: - timer_gettime(1); + mr[0] = timer_gettime(); break; case L4_IPC_TAG_TIMER_SLEEP: - timer_sleep(mr[0]); + timer_sleep(senderid, mr[0]); + /* TODO: Halt the caller for mr[0] seconds */ break; default: diff --git a/conts/libdev/timer/sp804/include/sp804_timer.h b/conts/libdev/timer/sp804/include/sp804_timer.h index 0da6d15..d7929a0 100644 --- a/conts/libdev/timer/sp804/include/sp804_timer.h +++ b/conts/libdev/timer/sp804/include/sp804_timer.h @@ -56,10 +56,6 @@ #define SP804_TIMERMIS 0x14 #define SP804_TIMERBGLOAD 0x18 -struct sp804_timer { - unsigned int base; -}; - void sp804_init(unsigned int timer_base, int runmode, int wrapmode, \ int width, int irq_enable); void sp804_irq_handler(unsigned int timer_base); diff --git a/conts/libdev/timer/sp804/src/sp804_timer.c b/conts/libdev/timer/sp804/src/sp804_timer.c index cbb8c11..690fb9a 100644 --- a/conts/libdev/timer/sp804/src/sp804_timer.c +++ b/conts/libdev/timer/sp804/src/sp804_timer.c @@ -10,6 +10,8 @@ #define setbit(bit, a) write(read(a) | bit, a) #define clrbit(bit, a) write(read(a) & ~bit, a) +extern void timer_irq_handler(void); + void sp804_irq_handler(unsigned int timer_base) { /* @@ -17,6 +19,7 @@ void sp804_irq_handler(unsigned int timer_base) * as it automatically reloads and wraps */ write(1, (timer_base + SP804_TIMERINTCLR)); + timer_irq_handler(); } static inline void sp804_control(unsigned int timer_base, int bit, int setclr)