<commit_before>/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* Timer module for Chrome EC operating system */

#include "atomic.h"
#include "console.h"
#include "hooks.h"
#include "hwtimer.h"
#include "system.h"
#include "uart.h"
#include "util.h"
#include "task.h"
#include "timer.h"

#define TIMER_SYSJUMP_TAG 0x4d54  /* "TM" */

/* High word of the 64-bit timestamp counter  */
static volatile uint32_t clksrc_high;

/* Bitmap of currently running timers */
static uint32_t timer_running;

/* Deadlines of all timers */
static timestamp_t timer_deadline[TASK_ID_COUNT];
static uint32_t next_deadline = 0xffffffff;

/* Hardware timer routine IRQ number */
static int timer_irq;

static void expire_timer(task_id_t tskid)
{
	/* we are done with this timer */
	atomic_clear(&timer_running, 1 << tskid);
	/* wake up the taks waiting for this timer */
	task_set_event(tskid, TASK_EVENT_TIMER, 0);
}

int timestamp_expired(timestamp_t deadline, const timestamp_t *now)
{
	timestamp_t now_val;

	if (!now) {
		now_val = get_time();
		now = &now_val;
	}

	return ((int64_t)(now->val - deadline.val) >= 0);
}

void process_timers(int overflow)
{
	uint32_t check_timer, running_t0;
	timestamp_t next;
	timestamp_t now;

	if (overflow)
		clksrc_high++;

	do {
		next.val = -1ull;
		now = get_time();
		do {
			/* read atomically the current state of timer running */
			check_timer = running_t0 = timer_running;
			while (check_timer) {
				int tskid = 31 - __builtin_clz(check_timer);

				/* timer has expired ? */
				if (timer_deadline[tskid].val <= now.val)
					expire_timer(tskid);
				else if ((timer_deadline[tskid].le.hi ==
					  now.le.hi) &&
					 (timer_deadline[tskid].le.lo <
					  next.le.lo))
					next.val = timer_deadline[tskid].val;

				check_timer &= ~(1 << tskid);
			}
		/* if there is a new timer, let's retry */
		} while (timer_running & ~running_t0);

		if (next.le.hi == 0xffffffff) {
			/* no deadline to set */
			__hw_clock_event_clear();
			next_deadline = 0xffffffff;
			return;
		}

		__hw_clock_event_set(next.le.lo);
		next_deadline = next.le.lo;
	} while (next.val <= get_time().val);
}

#ifndef CONFIG_HW_SPECIFIC_UDELAY
void udelay(unsigned us)
{
	unsigned t0 = __hw_clock_source_read();

	/*
	 * udelay() may be called with interrupts disabled, so we can't rely on
	 * process_timers() updating the top 32 bits.  So handle wraparound
	 * ourselves rather than calling get_time() and comparing with a
	 * deadline.
	 *
	 * This may fail for delays close to 2^32 us (~4000 sec), because the
	 * subtraction below can overflow.  That's acceptable, because the
	 * watchdog timer would have tripped long before that anyway.
	 */
	while (__hw_clock_source_read() - t0 <= us)
		;
}
#endif

int timer_arm(timestamp_t tstamp, task_id_t tskid)
{
	ASSERT(tskid < TASK_ID_COUNT);

	if (timer_running & (1<<tskid))
		return EC_ERROR_BUSY;

	timer_deadline[tskid] = tstamp;
	atomic_or(&timer_running, 1<<tskid);

	/* Modify the next event if needed */
	if ((tstamp.le.hi < clksrc_high) ||
	    ((tstamp.le.hi == clksrc_high) && (tstamp.le.lo <= next_deadline)))
		task_trigger_irq(timer_irq);

	return EC_SUCCESS;
}

void timer_cancel(task_id_t tskid)
{
	ASSERT(tskid < TASK_ID_COUNT);

	atomic_clear(&timer_running, 1 << tskid);
	/*
	 * Don't need to cancel the interrupt: it would be slow, just do it on
	 * the next IT
	 */
}

void usleep(unsigned us)
{
	uint32_t evt = 0;

	/* If task scheduling has not started, just delay */
	if (!task_start_called()) {
		udelay(us);
		return;
	}

	ASSERT(us);
	do {
		evt |= task_wait_event(us);
	} while (!(evt & TASK_EVENT_TIMER));

	/* Re-queue other events which happened in the meanwhile */
	if (evt)
		atomic_or(task_get_event_bitmap(task_get_current()),
			  evt & ~TASK_EVENT_TIMER);
}

timestamp_t get_time(void)
{
	timestamp_t ts;
	ts.le.hi = clksrc_high;
	ts.le.lo = __hw_clock_source_read();<commit_msg>timer: usleep: Use HW clock to detect elapsed sleep time<commit_after>/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* Timer module for Chrome EC operating system */

#include "atomic.h"
#include "console.h"
#include "hooks.h"
#include "hwtimer.h"
#include "system.h"
#include "uart.h"
#include "util.h"
#include "task.h"
#include "timer.h"

#define TIMER_SYSJUMP_TAG 0x4d54  /* "TM" */

/* High word of the 64-bit timestamp counter  */
static volatile uint32_t clksrc_high;

/* Bitmap of currently running timers */
static uint32_t timer_running;

/* Deadlines of all timers */
static timestamp_t timer_deadline[TASK_ID_COUNT];
static uint32_t next_deadline = 0xffffffff;

/* Hardware timer routine IRQ number */
static int timer_irq;

static void expire_timer(task_id_t tskid)
{
	/* we are done with this timer */
	atomic_clear(&timer_running, 1 << tskid);
	/* wake up the taks waiting for this timer */
	task_set_event(tskid, TASK_EVENT_TIMER, 0);
}

int timestamp_expired(timestamp_t deadline, const timestamp_t *now)
{
	timestamp_t now_val;

	if (!now) {
		now_val = get_time();
		now = &now_val;
	}

	return ((int64_t)(now->val - deadline.val) >= 0);
}

void process_timers(int overflow)
{
	uint32_t check_timer, running_t0;
	timestamp_t next;
	timestamp_t now;

	if (overflow)
		clksrc_high++;

	do {
		next.val = -1ull;
		now = get_time();
		do {
			/* read atomically the current state of timer running */
			check_timer = running_t0 = timer_running;
			while (check_timer) {
				int tskid = 31 - __builtin_clz(check_timer);

				/* timer has expired ? */
				if (timer_deadline[tskid].val <= now.val)
					expire_timer(tskid);
				else if ((timer_deadline[tskid].le.hi ==
					  now.le.hi) &&
					 (timer_deadline[tskid].le.lo <
					  next.le.lo))
					next.val = timer_deadline[tskid].val;

				check_timer &= ~(1 << tskid);
			}
		/* if there is a new timer, let's retry */
		} while (timer_running & ~running_t0);

		if (next.le.hi == 0xffffffff) {
			/* no deadline to set */
			__hw_clock_event_clear();
			next_deadline = 0xffffffff;
			return;
		}

		__hw_clock_event_set(next.le.lo);
		next_deadline = next.le.lo;
	} while (next.val <= get_time().val);
}

#ifndef CONFIG_HW_SPECIFIC_UDELAY
void udelay(unsigned us)
{
	unsigned t0 = __hw_clock_source_read();

	/*
	 * udelay() may be called with interrupts disabled, so we can't rely on
	 * process_timers() updating the top 32 bits.  So handle wraparound
	 * ourselves rather than calling get_time() and comparing with a
	 * deadline.
	 *
	 * This may fail for delays close to 2^32 us (~4000 sec), because the
	 * subtraction below can overflow.  That's acceptable, because the
	 * watchdog timer would have tripped long before that anyway.
	 */
	while (__hw_clock_source_read() - t0 <= us)
		;
}
#endif

int timer_arm(timestamp_t tstamp, task_id_t tskid)
{
	ASSERT(tskid < TASK_ID_COUNT);

	if (timer_running & (1<<tskid))
		return EC_ERROR_BUSY;

	timer_deadline[tskid] = tstamp;
	atomic_or(&timer_running, 1<<tskid);

	/* Modify the next event if needed */
	if ((tstamp.le.hi < clksrc_high) ||
	    ((tstamp.le.hi == clksrc_high) && (tstamp.le.lo <= next_deadline)))
		task_trigger_irq(timer_irq);

	return EC_SUCCESS;
}

void timer_cancel(task_id_t tskid)
{
	ASSERT(tskid < TASK_ID_COUNT);

	atomic_clear(&timer_running, 1 << tskid);
	/*
	 * Don't need to cancel the interrupt: it would be slow, just do it on
	 * the next IT
	 */
}

/*
 * For us < (2^31 - task scheduling latency)(~ 2147 sec), this function will
 * sleep for at least us, and no more than 2*us. As us approaches 2^32-1, the
 * probability of delay longer than 2*us (and possibly infinite delay)
 * increases.
 */
void usleep(unsigned us)
{
	uint32_t evt = 0;
	uint32_t t0 = __hw_clock_source_read();

	/* If task scheduling has not started, just delay */
	if (!task_start_called()) {
		udelay(us);
		return;
	}

	ASSERT(us);
	do {
		evt |= task_wait_event(us);
	} while (!(evt & TASK_EVENT_TIMER) &&
		((__hw_clock_source_read() - t0) < us));

	/* Re-queue other events which happened in the meanwhile */
	if (evt)
		atomic_or(task_get_event_bitmap(task_get_current()),
			  evt & ~TASK_EVENT_TIMER);
}

timestamp_t get_time(void)
{
	timestamp_t ts;
	ts.le.hi = clksrc_high;
	ts.le.lo = __hw_clock_source_read();
{'fraction_non_alphanumeric': 0.12138177486599167, 'fraction_numerical': 0.013936867182846932, 'mean_word_length': 3.803203661327231, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '862159', 'n_tokens_mistral': 3369, 'n_tokens_neox': 3030, 'n_words': 847}