blob: 93687af5156c58e639db33d69cc43d0419c7b315 [file]
/*
* Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Time-of-Day (TOD) Clock
*
*/
#include <errno.h>
#include <ipxe/time.h>
#include <ipxe/timer.h>
#include <ipxe/facility.h>
#include <ipxe/tod.h>
#include <config/time.h>
#ifdef TIME_TOD
#define TIME_PREFIX_tod
#else
#define TIME_PREFIX_tod __tod_
#endif
struct timer tod_timer __timer ( TIMER_PREFERRED );
/** Colour for debug messages */
#define colour &tod_timer
/**
* Get current wall-clock time in seconds since the Epoch
*
* @ret time Time, in seconds
*/
static time_t tod_now ( void ) {
unsigned long ticks;
/* Get current time in TOD ticks */
ticks = tod_ticks();
/* Convert (exactly) to seconds since the Epoch */
return ( ( ticks - TOD_EPOCH ) / ( 1000000 * TOD_TICKS_PER_US ) );
}
/**
* Get current system time in ticks
*
* @ret ticks Current time, in ticks
*/
static unsigned long tod_currticks ( void ) {
unsigned long ticks;
/* Get current time in TOD ticks */
ticks = tod_ticks();
/* Convert (approximately) to system ticks */
return ( ticks / ( TOD_TICKS_PER_MS / TICKS_PER_MS ) );
}
/**
* Delay for a fixed number of microseconds
*
* @v usecs Number of microseconds for which to delay
*/
static void tod_udelay ( unsigned long usecs ) {
unsigned long start;
unsigned long elapsed;
unsigned long threshold;
/* Delay until sufficient time has elapsed */
start = tod_ticks();
threshold = ( usecs * TOD_TICKS_PER_US );
do {
elapsed = ( tod_ticks() - start );
} while ( elapsed < threshold );
}
/**
* Probe timer
*
* @ret rc Return status code
*/
static int tod_probe ( void ) {
enum tod_state state;
int multiple;
/* Check multiple-epoch facility (for debugging only) */
multiple = facility_is_installed ( FACILITY_MULTIPLE_EPOCH );
DBGC ( colour, "TOD multiple epoch facility is%s installed\n",
( multiple ? "" : " not" ) );
/* Get clock state */
state = tod_state();
DBGC ( colour, "TOD clock is in %s state\n",
tod_state_name ( state ) );
/* Check clock is running */
if ( ! tod_is_running ( state ) )
return -ENODEV;
return 0;
}
/** Time-of-day interval timer */
struct timer tod_timer __timer ( TIMER_PREFERRED ) = {
.name = "tod",
.probe = tod_probe,
.currticks = tod_currticks,
.udelay = tod_udelay,
};
PROVIDE_TIME ( tod, time_now, tod_now );