From 16f1e35775c972ba8e02bc2d97d7a2eb333eae1b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 12 Oct 2008 19:56:52 +0100 Subject: [PATCH] [timer] Formalise the timer API We now have two implementations for the timer API: one using the time-of-day counter at 40:70 and one using RDTSC. Both make use of timer2_udelay(). --- src/arch/i386/core/rdtsc_timer.c | 87 +++++++++++++++++ src/arch/i386/core/{i386_timer.c => timer2.c} | 22 ++--- src/arch/i386/drivers/timer_bios.c | 57 ----------- src/arch/i386/drivers/timer_rdtsc.c | 69 -------------- src/arch/i386/include/bios.h | 1 - src/arch/i386/include/bits/timer.h | 13 +++ src/arch/i386/include/bits/timer2.h | 8 -- src/arch/i386/include/gpxe/bios_timer.h | 42 +++++++++ src/arch/i386/include/gpxe/rdtsc_timer.h | 37 ++++++++ src/arch/i386/include/gpxe/timer2.h | 12 +++ src/arch/i386/interface/pcbios/bios_timer.c | 63 +++++++++++++ src/config/defaults/pcbios.h | 1 + src/config/timer.h | 15 +++ src/core/monojob.c | 6 +- src/core/timer.c | 91 ++---------------- src/drivers/net/3c90x.c | 4 +- src/drivers/net/eepro100.c | 8 +- src/drivers/net/epic100.c | 4 +- src/drivers/net/via-rhine.c | 14 +-- src/drivers/net/w89c840.c | 4 +- src/include/gpxe/timer.h | 94 +++++++++++++------ src/include/unistd.h | 18 +++- 22 files changed, 386 insertions(+), 284 deletions(-) create mode 100644 src/arch/i386/core/rdtsc_timer.c rename src/arch/i386/core/{i386_timer.c => timer2.c} (86%) delete mode 100644 src/arch/i386/drivers/timer_bios.c delete mode 100644 src/arch/i386/drivers/timer_rdtsc.c create mode 100644 src/arch/i386/include/bits/timer.h delete mode 100644 src/arch/i386/include/bits/timer2.h create mode 100644 src/arch/i386/include/gpxe/bios_timer.h create mode 100644 src/arch/i386/include/gpxe/rdtsc_timer.h create mode 100644 src/arch/i386/include/gpxe/timer2.h create mode 100644 src/arch/i386/interface/pcbios/bios_timer.c create mode 100644 src/config/timer.h diff --git a/src/arch/i386/core/rdtsc_timer.c b/src/arch/i386/core/rdtsc_timer.c new file mode 100644 index 00000000..443c8ada --- /dev/null +++ b/src/arch/i386/core/rdtsc_timer.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * RDTSC timer + * + */ + +#include +#include +#include + +/** + * Number of TSC ticks per microsecond + * + * This is calibrated on the first use of the timer. + */ +static unsigned long rdtsc_ticks_per_usec; + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static void rdtsc_udelay ( unsigned long usecs ) { + unsigned long start; + unsigned long elapsed; + + /* Sanity guard, since we may divide by this */ + if ( ! usecs ) + usecs = 1; + + start = currticks(); + if ( rdtsc_ticks_per_usec ) { + /* Already calibrated; busy-wait until done */ + do { + elapsed = ( currticks() - start ); + } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) ); + } else { + /* Not yet calibrated; use timer2 and calibrate + * based on result. + */ + timer2_udelay ( usecs ); + elapsed = ( currticks() - start ); + rdtsc_ticks_per_usec = ( elapsed / usecs ); + DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs " + "(%ld MHz)\n", elapsed, usecs, + ( rdtsc_ticks_per_usec << TSC_SHIFT ) ); + } +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static unsigned long rdtsc_ticks_per_sec ( void ) { + + /* Calibrate timer, if not already done */ + if ( ! rdtsc_ticks_per_usec ) + udelay ( 1 ); + + /* Sanity check */ + assert ( rdtsc_ticks_per_usec != 0 ); + + return ( rdtsc_ticks_per_usec * 1000 * 1000 ); +} + +PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay ); +PROVIDE_TIMER_INLINE ( rdtsc, currticks ); +PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec ); diff --git a/src/arch/i386/core/i386_timer.c b/src/arch/i386/core/timer2.c similarity index 86% rename from src/arch/i386/core/i386_timer.c rename to src/arch/i386/core/timer2.c index 3325bb0b..bb589ecc 100644 --- a/src/arch/i386/core/i386_timer.c +++ b/src/arch/i386/core/timer2.c @@ -12,12 +12,11 @@ */ #include -#include -#include +#include #include /* Timers tick over at this rate */ -#define TIMER2_TICK_RATE 1193180U +#define TIMER2_TICKS_PER_SEC 1193180U /* Parallel Peripheral Controller Port B */ #define PPC_PORTB 0x61 @@ -52,8 +51,7 @@ #define BINARY_COUNT 0x00 #define BCD_COUNT 0x01 -static void load_timer2(unsigned int ticks) -{ +static void load_timer2 ( unsigned int ticks ) { /* * Now let's take care of PPC channel 2 * @@ -75,15 +73,13 @@ static void load_timer2(unsigned int ticks) outb(ticks >> 8, TIMER2_PORT); } -static int timer2_running(void) -{ +static int timer2_running ( void ) { return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); } -void i386_timer2_udelay(unsigned int usecs) -{ - load_timer2((usecs * TIMER2_TICK_RATE)/USECS_IN_SEC); - while (timer2_running()) - ; +void timer2_udelay ( unsigned long usecs ) { + load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) ); + while (timer2_running()) { + /* Do nothing */ + } } - diff --git a/src/arch/i386/drivers/timer_bios.c b/src/arch/i386/drivers/timer_bios.c deleted file mode 100644 index f9caf8d9..00000000 --- a/src/arch/i386/drivers/timer_bios.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Etherboot routines for PCBIOS firmware. - * - * Body of routines taken from old pcbios.S - */ - -#include -#include -#include -#include -#include -#include - -/* A bit faster actually, but we don't care. */ -#define TIMER2_TICKS_PER_SEC 18 - -/* - * Use direct memory access to BIOS variables, longword 0040:006C (ticks - * today) and byte 0040:0070 (midnight crossover flag) instead of calling - * timeofday BIOS interrupt. - */ - -static tick_t bios_currticks ( void ) { - static int days = 0; - uint32_t ticks; - uint8_t midnight; - - /* Re-enable interrupts so that the timer interrupt can occur */ - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "nop\n\t" - "nop\n\t" - "cli\n\t" ) : : ); - - get_real ( ticks, BDA_SEG, 0x006c ); - get_real ( midnight, BDA_SEG, 0x0070 ); - - if ( midnight ) { - midnight = 0; - put_real ( midnight, BDA_SEG, 0x0070 ); - days += 0x1800b0; - } - - return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) ); -} - -static int bios_ts_init(void) -{ - DBG("BIOS timer installed\n"); - return 0; -} - -struct timer bios_ts __timer ( 02 ) = { - .init = bios_ts_init, - .udelay = i386_timer2_udelay, - .currticks = bios_currticks, -}; - diff --git a/src/arch/i386/drivers/timer_rdtsc.c b/src/arch/i386/drivers/timer_rdtsc.c deleted file mode 100644 index f4ede558..00000000 --- a/src/arch/i386/drivers/timer_rdtsc.c +++ /dev/null @@ -1,69 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include - - -#define rdtsc(low,high) \ - __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) - -#define rdtscll(val) \ - __asm__ __volatile__ ("rdtsc" : "=A" (val)) - - -/* Measure how many clocks we get in one microsecond */ -static inline uint64_t calibrate_tsc(void) -{ - - uint64_t rdtsc_start; - uint64_t rdtsc_end; - - rdtscll(rdtsc_start); - i386_timer2_udelay(USECS_IN_MSEC); - rdtscll(rdtsc_end); - - return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC; -} - -static uint32_t clocks_per_usec = 0; - -/* We measure time in microseconds. */ -static tick_t rdtsc_currticks(void) -{ - uint64_t clocks; - - /* Read the Time Stamp Counter */ - rdtscll(clocks); - - return clocks / clocks_per_usec; -} - -static int rdtsc_ts_init(void) -{ - - struct cpuinfo_x86 cpu_info; - - get_cpuinfo(&cpu_info); - if (cpu_info.features & X86_FEATURE_TSC) { - clocks_per_usec= calibrate_tsc(); - if (clocks_per_usec) { - DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n", - clocks_per_usec); - return 0; - } - } - - DBG("RDTSC ticksource not available on this machine.\n"); - return -ENODEV; -} - -struct timer rdtsc_ts __timer (01) = { - .init = rdtsc_ts_init, - .udelay = generic_currticks_udelay, - .currticks = rdtsc_currticks, -}; - diff --git a/src/arch/i386/include/bios.h b/src/arch/i386/include/bios.h index 630a898b..5f9d6ab0 100644 --- a/src/arch/i386/include/bios.h +++ b/src/arch/i386/include/bios.h @@ -5,7 +5,6 @@ #define BDA_FBMS 0x0013 #define BDA_NUM_DRIVES 0x0075 -extern unsigned long currticks ( void ); extern void cpu_nap ( void ); #endif /* BIOS_H */ diff --git a/src/arch/i386/include/bits/timer.h b/src/arch/i386/include/bits/timer.h new file mode 100644 index 00000000..99666d84 --- /dev/null +++ b/src/arch/i386/include/bits/timer.h @@ -0,0 +1,13 @@ +#ifndef _BITS_TIMER_H +#define _BITS_TIMER_H + +/** @file + * + * i386-specific timer API implementations + * + */ + +#include +#include + +#endif /* _BITS_TIMER_H */ diff --git a/src/arch/i386/include/bits/timer2.h b/src/arch/i386/include/bits/timer2.h deleted file mode 100644 index 83923b29..00000000 --- a/src/arch/i386/include/bits/timer2.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef BITS_TIMER2_H -#define BITS_TIMER2_H - -#include - -void i386_timer2_udelay(unsigned int usecs); - -#endif diff --git a/src/arch/i386/include/gpxe/bios_timer.h b/src/arch/i386/include/gpxe/bios_timer.h new file mode 100644 index 00000000..7e3caa3c --- /dev/null +++ b/src/arch/i386/include/gpxe/bios_timer.h @@ -0,0 +1,42 @@ +#ifndef _GPXE_BIOS_TIMER_H +#define _GPXE_BIOS_TIMER_H + +/** @file + * + * BIOS timer + * + */ + +#ifdef TIMER_PCBIOS +#define TIMER_PREFIX_pcbios +#else +#define TIMER_PREFIX_pcbios __pcbios_ +#endif + +#include + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static inline __always_inline void +TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) { + /* BIOS timer is not high-resolution enough for udelay(), so + * we use timer2 + */ + timer2_udelay ( usecs ); +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static inline __always_inline unsigned long +TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) { + /* BIOS timer ticks over at 18.2 ticks per second */ + return 18; +} + +#endif /* _GPXE_BIOS_TIMER_H */ diff --git a/src/arch/i386/include/gpxe/rdtsc_timer.h b/src/arch/i386/include/gpxe/rdtsc_timer.h new file mode 100644 index 00000000..0e03d707 --- /dev/null +++ b/src/arch/i386/include/gpxe/rdtsc_timer.h @@ -0,0 +1,37 @@ +#ifndef _GPXE_RDTSC_TIMER_H +#define _GPXE_RDTSC_TIMER_H + +/** @file + * + * RDTSC timer + * + */ + +#ifdef TIMER_RDTSC +#define TIMER_PREFIX_rdtsc +#else +#define TIMER_PREFIX_rdtsc __rdtsc_ +#endif + +/** + * RDTSC values can easily overflow an unsigned long. We discard the + * low-order bits in order to obtain sensibly-scaled values. + */ +#define TSC_SHIFT 8 + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +static inline __always_inline unsigned long +TIMER_INLINE ( rdtsc, currticks ) ( void ) { + unsigned long ticks; + + __asm__ __volatile__ ( "rdtsc\n\t" + "shrdl %1, %%edx, %%eax\n\t" + : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" ); + return ticks; +} + +#endif /* _GPXE_RDTSC_TIMER_H */ diff --git a/src/arch/i386/include/gpxe/timer2.h b/src/arch/i386/include/gpxe/timer2.h new file mode 100644 index 00000000..59705fa2 --- /dev/null +++ b/src/arch/i386/include/gpxe/timer2.h @@ -0,0 +1,12 @@ +#ifndef _GPXE_TIMER2_H +#define _GPXE_TIMER2_H + +/** @file + * + * Timer chip control + * + */ + +extern void timer2_udelay ( unsigned long usecs ); + +#endif /* _GPXE_TIMER2_H */ diff --git a/src/arch/i386/interface/pcbios/bios_timer.c b/src/arch/i386/interface/pcbios/bios_timer.c new file mode 100644 index 00000000..0b475ea3 --- /dev/null +++ b/src/arch/i386/interface/pcbios/bios_timer.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * BIOS timer + * + */ + +#include +#include +#include + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + * + * Use direct memory access to BIOS variables, longword 0040:006C + * (ticks today) and byte 0040:0070 (midnight crossover flag) instead + * of calling timeofday BIOS interrupt. + */ +static unsigned long bios_currticks ( void ) { + static int days = 0; + uint32_t ticks; + uint8_t midnight; + + /* Re-enable interrupts so that the timer interrupt can occur */ + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t" ) : : ); + + get_real ( ticks, BDA_SEG, 0x006c ); + get_real ( midnight, BDA_SEG, 0x0070 ); + + if ( midnight ) { + midnight = 0; + put_real ( midnight, BDA_SEG, 0x0070 ); + days += 0x1800b0; + } + + return ( days + ticks ); +} + +PROVIDE_TIMER_INLINE ( pcbios, udelay ); +PROVIDE_TIMER ( pcbios, currticks, bios_currticks ); +PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec ); diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index df6e93ce..4cf2d7e4 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -9,6 +9,7 @@ #define IOAPI_X86 #define PCIAPI_PCBIOS +#define TIMER_PCBIOS #define CONSOLE_PCBIOS #endif /* CONFIG_DEFAULTS_PCBIOS_H */ diff --git a/src/config/timer.h b/src/config/timer.h new file mode 100644 index 00000000..7c3f3521 --- /dev/null +++ b/src/config/timer.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_TIMER_H +#define CONFIG_TIMER_H + +/** @file + * + * Timer configuration. + * + */ + +#include + +//#undef TIMER_PCBIOS +//#define TIMER_RDTSC + +#endif /* CONFIG_TIMER_H */ diff --git a/src/core/monojob.c b/src/core/monojob.c index 2c91e132..a7e83851 100644 --- a/src/core/monojob.c +++ b/src/core/monojob.c @@ -63,7 +63,8 @@ struct job_interface monojob = { int monojob_wait ( const char *string ) { int key; int rc; - tick_t last_progress_dot; + unsigned long last_progress_dot; + unsigned long elapsed; printf ( "%s.", string ); monojob_rc = -EINPROGRESS; @@ -81,7 +82,8 @@ int monojob_wait ( const char *string ) { break; } } - if ( ( currticks() - last_progress_dot ) > TICKS_PER_SEC ) { + elapsed = ( currticks() - last_progress_dot ); + if ( elapsed > TICKS_PER_SEC ) { printf ( "." ); last_progress_dot = currticks(); } diff --git a/src/core/timer.c b/src/core/timer.c index 4e047ea7..d71e3da1 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -1,7 +1,5 @@ /* - * core/timer.c - * - * Copyright (C) 2007 Alexey Zaytsev + * Copyright (C) 2008 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,96 +16,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include - -static struct timer ts_table[0] - __table_start ( struct timer, timers ); -static struct timer ts_table_end[0] - __table_end ( struct timer, timers ); - -/* - * This function may be used in custom timer driver. - * - * This udelay implementation works well if you've got a - * fast currticks(). - */ -void generic_currticks_udelay ( unsigned int usecs ) { - tick_t start; - tick_t elapsed; - - start = currticks(); - do { - /* xxx: Relax the cpu some way. */ - elapsed = ( currticks() - start ); - } while ( elapsed < usecs ); -} +#include /** - * Identify timer source + * Delay for a fixed number of milliseconds * - * @ret timer Timer source + * @v msecs Number of milliseconds for which to delay */ -static struct timer * timer ( void ) { - static struct timer *ts = NULL; - - /* If we have a timer, use it */ - if ( ts ) - return ts; - - /* Scan for a usable timer */ - for ( ts = ts_table ; ts < ts_table_end ; ts++ ) { - if ( ts->init() == 0 ) - return ts; - } - - /* No timer found; we cannot continue */ - assert ( 0 ); - while ( 1 ) {}; -} - -/** - * Read current time - * - * @ret ticks Current time, in ticks - */ -tick_t currticks ( void ) { - tick_t ct; - - ct = timer()->currticks(); - DBG ( "currticks: %ld.%06ld seconds\n", - ct / USECS_IN_SEC, ct % USECS_IN_SEC ); - - return ct; -} - -/** - * Delay - * - * @v usecs Time to delay, in microseconds - */ -void udelay ( unsigned int usecs ) { - timer()->udelay ( usecs ); -} - -/** - * Delay - * - * @v msecs Time to delay, in milliseconds - */ -void mdelay ( unsigned int msecs ) { +void mdelay ( unsigned long msecs ) { while ( msecs-- ) - udelay ( USECS_IN_MSEC ); + udelay ( 1000 ); } /** - * Delay + * Delay for a fixed number of seconds * - * @v secs Time to delay, in seconds + * @v secs Number of seconds for which to delay */ unsigned int sleep ( unsigned int secs ) { while ( secs-- ) - mdelay ( MSECS_IN_SEC ); + mdelay ( 1000 ); return 0; } diff --git a/src/drivers/net/3c90x.c b/src/drivers/net/3c90x.c index 8158239d..a98e6628 100644 --- a/src/drivers/net/3c90x.c +++ b/src/drivers/net/3c90x.c @@ -497,7 +497,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t, unsigned char status; unsigned i, retries; - tick_t ct; + unsigned long ct; for (retries=0; retries < XMIT_RETRIES ; retries++) { @@ -543,7 +543,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t, ct = currticks(); while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) && - ct + 10*USECS_IN_MSEC < currticks()); + ct + 10*1000 < currticks()); ; if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004)) diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index f746976a..e6e7db49 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -407,7 +407,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un } hdr; unsigned short status; int s1, s2; - tick_t ct; + unsigned long ct; status = inw(ioaddr + SCBStatus); /* Acknowledge all of the current interrupt sources ASAP. */ @@ -448,7 +448,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un ct = currticks(); /* timeout 10 ms for transmit */ - while (!txfd.status && ct + 10*USECS_IN_MSEC) + while (!txfd.status && ct + 10*1000) /* Wait */; s2 = inw (ioaddr + SCBStatus); @@ -608,7 +608,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) { int read_cmd, ee_size; int options; int rx_mode; - tick_t ct; + unsigned long ct; /* we cache only the first few words of the EEPROM data be careful not to access beyond this array */ @@ -753,7 +753,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) { whereami ("started TX thingy (config, iasetup)."); ct = currticks(); - while (!txfd.status && ct + 10*USECS_IN_MSEC < currticks()) + while (!txfd.status && ct + 10*1000 < currticks()) /* Wait */; /* Read the status register once to disgard stale data */ diff --git a/src/drivers/net/epic100.c b/src/drivers/net/epic100.c index 67b4f0fb..1e36a680 100644 --- a/src/drivers/net/epic100.c +++ b/src/drivers/net/epic100.c @@ -309,7 +309,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned short nstype; unsigned char *txp; int entry; - tick_t ct; + unsigned long ct; /* Calculate the next Tx descriptor entry. */ entry = cur_tx % TX_RING_SIZE; @@ -352,7 +352,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, ct = currticks(); /* timeout 10 ms for transmit */ while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) && - ct + 10*USECS_IN_MSEC < currticks()) + ct + 10*1000 < currticks()) /* Wait */; if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0) diff --git a/src/drivers/net/via-rhine.c b/src/drivers/net/via-rhine.c index bceaec66..201ebb08 100644 --- a/src/drivers/net/via-rhine.c +++ b/src/drivers/net/via-rhine.c @@ -784,7 +784,7 @@ ReadMII (int byMIIIndex, int ioaddr) char byMIIAdrbak; char byMIICRbak; char byMIItemp; - tick_t ct; + unsigned long ct; byMIIAdrbak = inb (byMIIAD); byMIICRbak = inb (byMIICR); @@ -800,7 +800,7 @@ ReadMII (int byMIIIndex, int ioaddr) byMIItemp = byMIItemp & 0x40; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; @@ -825,7 +825,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) char byMIIAdrbak; char byMIICRbak; char byMIItemp; - tick_t ct; + unsigned long ct; byMIIAdrbak = inb (byMIIAD); @@ -842,7 +842,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) byMIItemp = byMIItemp & 0x40; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; @@ -872,7 +872,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) byMIItemp = byMIItemp & 0x20; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x20; @@ -1346,7 +1346,7 @@ rhine_transmit (struct nic *nic, unsigned char CR1bak; unsigned char CR0bak; unsigned int nstype; - tick_t ct; + unsigned long ct; /*printf ("rhine_transmit\n"); */ @@ -1390,7 +1390,7 @@ rhine_transmit (struct nic *nic, ct = currticks(); /* Wait until transmit is finished or timeout*/ while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) && - ct + 10*USECS_IN_MSEC < currticks()) + ct + 10*1000 < currticks()) ; if(tp->tx_ring[entry].tx_status.bits.terr == 0) diff --git a/src/drivers/net/w89c840.c b/src/drivers/net/w89c840.c index 14497640..5abc0b35 100644 --- a/src/drivers/net/w89c840.c +++ b/src/drivers/net/w89c840.c @@ -112,7 +112,7 @@ static const char *w89c840_version = "driver Version 0.94 - December 12, 2003"; /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (10*USECS_IN_MSEC) +#define TX_TIMEOUT (10*1000) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ @@ -486,7 +486,7 @@ static void w89c840_transmit( /* send the packet to destination */ unsigned entry; int transmit_status; - tick_t ct; + unsigned long ct; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ diff --git a/src/include/gpxe/timer.h b/src/include/gpxe/timer.h index b7057225..e62007ae 100644 --- a/src/include/gpxe/timer.h +++ b/src/include/gpxe/timer.h @@ -1,41 +1,73 @@ -#ifndef GPXE_TIMER_H -#define GPXE_TIMER_H +#ifndef _GPXE_TIMER_H +#define _GPXE_TIMER_H -#include -#include +/** @file + * + * gPXE timer API + * + * The timer API provides udelay() for fixed delays, and currticks() + * for a monotonically increasing tick counter. + */ -typedef unsigned long tick_t; +#include +#include -#define MSECS_IN_SEC (1000) -#define USECS_IN_SEC (1000*1000) -#define USECS_IN_MSEC (1000) +/** + * Calculate static inline timer API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define TIMER_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func ) -#define TICKS_PER_SEC USECS_IN_SEC +/** + * Provide a timer API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_TIMER( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func ) -extern tick_t currticks ( void ); +/** + * Provide a static inline timer API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func ) -extern void generic_currticks_udelay ( unsigned int usecs ); +/* Include all architecture-independent I/O API headers */ -/** A timer */ -struct timer { - /** Initialise timer - * - * @ret rc Return status code - */ - int ( * init ) ( void ); - /** Read current time - * - * @ret ticks Current time, in ticks - */ - tick_t ( * currticks ) ( void ); - /** Delay - * - * @v usecs Time to delay, in microseconds - */ - void ( * udelay ) ( unsigned int usecs ); -}; +/* Include all architecture-dependent I/O API headers */ +#include -#define __timer( order ) __table ( struct timer, timers, order ) +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +void udelay ( unsigned long usecs ); -#endif /* GPXE_TIMER_H */ +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +unsigned long currticks ( void ); +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +unsigned long ticks_per_sec ( void ); + +/** Number of ticks per second */ +#define TICKS_PER_SEC ( ticks_per_sec() ) + +#endif /* _GPXE_TIMER_H */ diff --git a/src/include/unistd.h b/src/include/unistd.h index 7c44a0ce..dc1f67f6 100644 --- a/src/include/unistd.h +++ b/src/include/unistd.h @@ -4,7 +4,6 @@ #include #include -unsigned int sleep ( unsigned int seconds ); extern int execv ( const char *command, char * const argv[] ); /** @@ -22,10 +21,21 @@ extern int execv ( const char *command, char * const argv[] ); rc; \ } ) -void udelay(unsigned int usecs); -void mdelay(unsigned int msecs); +/* Pick up udelay() */ +#include -#define usleep(x) udelay(x) +/* + * sleep() prototype is defined by POSIX.1. usleep() prototype is + * defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to + * be reasonably sensible. + * + */ +extern unsigned int sleep ( unsigned int seconds ); +extern void mdelay ( unsigned long msecs ); + +static inline __always_inline void usleep ( unsigned long usecs ) { + udelay ( usecs ); +} #endif /* _UNISTD_H */