Timer service enhanced for sleep

This commit is contained in:
Amit Mahajan
2009-12-01 23:31:23 +05:30
parent 3caa43d756
commit cf9f3aab5b
4 changed files with 104 additions and 15 deletions

View File

@@ -0,0 +1,36 @@
#ifndef __TIMER_H__
#define __TIMER_H__
/*
* Timer specific things are here
*/
#include <l4lib/mutex.h>
#include <l4/lib/list.h>
/*
* 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__ */

View File

@@ -9,11 +9,12 @@
#include <l4/api/errno.h>
#include <l4/api/space.h>
#include <malloc/malloc.h>
#include <capability.h>
#include <container.h>
#include "sp804_timer.h"
#include <linker.h>
#include <timer.h>
/* 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:

View File

@@ -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);

View File

@@ -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)