OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [src/] [generic/] [time.c] - Rev 7

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * Time.
 *
 * Copyright (C) 2007 Bahadir Balban
 *
 */
#include <l4/types.h>
#include <l4/lib/mutex.h>
#include <l4/lib/printk.h>
#include <l4/generic/irq.h>
#include <l4/generic/scheduler.h>
#include <l4/generic/time.h>
#include <l4/generic/preempt.h>
#include <l4/generic/space.h>
#include INC_ARCH(exception.h)
#include <l4/api/syscall.h>
#include <l4/api/errno.h>
#include INC_GLUE(ipi.h)	/*FIXME: Remove this */
 
/* TODO:
 * 1) Add RTC support.
 * 2) Need to calculate time since EPOCH,
 * 3) Jiffies must be initialised to a reasonable value.
 */
 
volatile u32 jiffies = 0;
 
static inline void increase_jiffies(void)
{
	jiffies++;
}
 
 
/* Internal representation of time since epoch */
struct time_info {
	int reader;
	u32 thz;	/* Ticks in this hertz so far */
	u64 sec;	/* Seconds so far */
};
 
static struct time_info systime = { 0 };
 
/*
 * A very basic (probably erroneous)
 * rule-of-thumb time calculation.
 */
void update_system_time(void)
{
	/* Did we interrupt a reader? Tell it to retry */
	if (systime.reader)
		systime.reader = 0;
 
	/* Increase just like jiffies, but reset every second */
	systime.thz++;
 
	/*
	 * On every 1 second of timer ticks, increase seconds
	 *
	 * TODO: Investigate: how do we make sure timer_irq is
	 * called SCHED_TICKS times per second?
	 */
	if (systime.thz == CONFIG_SCHED_TICKS) {
		systime.thz = 0;
		systime.sec++;
	}
}
 
/* Read system time */
int sys_time(struct timeval *tv, int set)
{
	int retries = 20;
	int err;
 
	if ((err = check_access((unsigned long)tv, sizeof(*tv),
				MAP_USR_RW, 1)) < 0)
		return err;
 
	/* Get time */
	if (!set) {
		while(retries > 0) {
			systime.reader = 1;
			tv->tv_sec = systime.sec;
			tv->tv_usec = 1000000 * systime.thz / CONFIG_SCHED_TICKS;
 
			retries--;
			if (systime.reader)
				break;
		}
 
		/*
		 * No need to reset reader since it will be reset
		 * on next timer. If no retries return busy.
		 */
		if (!retries)
			return -EBUSY;
		else
			return 0;
 
	/* Set */
	} else {
		/*
		 * Setting the time not supported yet.
		 */
		return -ENOSYS;
	}
}
 
void update_process_times(void)
{
	struct ktcb *cur = current;
 
	if (cur->ticks_left == 0) {
		/*
		 * Nested irqs and irqs during non-preemptive
		 * times could try to deduct ticks below zero.
		 * We ignore such states and return.
		 */
		if (in_nested_irq_context() || !preemptive())
			return;
		else /* Otherwise its a bug. */
			BUG();
	}
 
	/*
	 * These are TASK_RUNNABLE times, i.e. exludes sleeps
	 * In the future we may use timestamps for accuracy
	 */
	if (in_kernel())
		cur->kernel_time++;
	else
		cur->user_time++;
 
	cur->ticks_left--;
	cur->sched_granule--;
 
	/* Task has expired its timeslice */
	if (!cur->ticks_left)
		need_resched = 1;
 
	/* Task has expired its schedule granularity */
	if (!cur->sched_granule)
		need_resched = 1;
}
 
int do_timer_irq(void)
{
	increase_jiffies();
	update_process_times();
	update_system_time();
 
#if defined (CONFIG_SMP)
	smp_send_ipi(cpu_mask_others(), IPI_TIMER_EVENT);
#endif
 
	return IRQ_HANDLED;
}
 
/* Secondary cpus call this */
int secondary_timer_irq(void)
{
	update_process_times();
	return IRQ_HANDLED;
}
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.