Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35492df5 authored by John Stultz's avatar John Stultz Committed by Linus Torvalds
Browse files

[PATCH] i386: fix hpet for systems that don't support legacy replacement



Currently the i386 HPET code assumes the entire HPET implementation from
the spec is present.  This breaks on boxes that do not implement the
optional legacy timer replacement functionality portion of the spec.

This patch, which is very similar to my x86-64 patch for the same issue,
fixes the problem allowing i386 systems that cannot use the HPET for the
timer interrupt and RTC to still use the HPET as a time source.  I've
tested this patch on a system systems without HPET, with HPET but without
legacy timer replacement, as well as HPET with legacy timer replacement.

Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5b7abc6f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -441,7 +441,7 @@ static void __init hpet_time_init(void)
	set_normalized_timespec(&wall_to_monotonic,
		-xtime.tv_sec, -xtime.tv_nsec);

	if (hpet_enable() >= 0) {
	if ((hpet_enable() >= 0) && hpet_use_timer) {
		printk("Using HPET for base-timer\n");
	}

+27 −21
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
static unsigned long hpet_period;	/* fsecs / HPET clock */
unsigned long hpet_tick;		/* hpet clks count per tick */
unsigned long hpet_address;		/* hpet memory map physical address */
int hpet_use_timer;

static int use_hpet; 		/* can be used for runtime check of hpet */
static int boot_hpet_disable; 	/* boottime override for HPET timer */
@@ -73,6 +74,7 @@ static int hpet_timer_stop_set_go(unsigned long tick)
	hpet_writel(0, HPET_COUNTER);
	hpet_writel(0, HPET_COUNTER + 4);

	if (hpet_use_timer) {
		/*
		 * Set up timer 0, as periodic with first interrupt to happen at
		 * hpet_tick, and period also hpet_tick.
@@ -88,12 +90,14 @@ static int hpet_timer_stop_set_go(unsigned long tick)
		 */
		hpet_writel(tick, HPET_T0_CMP);
		hpet_writel(tick, HPET_T0_CMP);

	}
	/*
 	 * Go!
 	 */
	cfg = hpet_readl(HPET_CFG);
	cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY;
	if (hpet_use_timer)
		cfg |= HPET_CFG_LEGACY;
	cfg |= HPET_CFG_ENABLE;
	hpet_writel(cfg, HPET_CFG);

	return 0;
@@ -128,12 +132,11 @@ int __init hpet_enable(void)
	 * However, we can do with one timer otherwise using the
	 * the single HPET timer for system time.
	 */
	if (
#ifdef CONFIG_HPET_EMULATE_RTC
		!(id & HPET_ID_NUMBER) ||
#endif
	    !(id & HPET_ID_LEGSUP))
	if (!(id & HPET_ID_NUMBER))
		return -1;
#endif


	hpet_period = hpet_readl(HPET_PERIOD);
	if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD))
@@ -152,6 +155,8 @@ int __init hpet_enable(void)
	if (hpet_tick_rem > (hpet_period >> 1))
		hpet_tick++; /* rounding the result */

	hpet_use_timer = id & HPET_ID_LEGSUP;

	if (hpet_timer_stop_set_go(hpet_tick))
		return -1;

@@ -202,6 +207,7 @@ int __init hpet_enable(void)
#endif

#ifdef CONFIG_X86_LOCAL_APIC
	if (hpet_use_timer)
		wait_timer_tick = wait_hpet_tick;
#endif
	return 0;
+7 −4
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ static unsigned long get_offset_hpet(void)

	eax = hpet_readl(HPET_COUNTER);
	eax -= hpet_last;	/* hpet delta */

	eax = min(hpet_tick, eax);
	/*
         * Time offset = (hpet delta) * ( usecs per HPET clock )
	 *             = (hpet delta) * ( usecs per tick / HPET clocks per tick)
@@ -105,9 +105,12 @@ static void mark_offset_hpet(void)
	last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
	rdtsc(last_tsc_low, last_tsc_high);

	if (hpet_use_timer)
		offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
	if (unlikely(((offset - hpet_last) > hpet_tick) && (hpet_last != 0))) {
		int lost_ticks = (offset - hpet_last) / hpet_tick;
	else
		offset = hpet_readl(HPET_COUNTER);
	if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) {
		int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1;
		jiffies_64 += lost_ticks;
	}
	hpet_last = offset;
+1 −1
Original line number Diff line number Diff line
@@ -477,7 +477,7 @@ static int __init init_tsc(char* override)
	if (cpu_has_tsc) {
		unsigned long tsc_quotient;
#ifdef CONFIG_HPET_TIMER
		if (is_hpet_enabled()){
		if (is_hpet_enabled() && hpet_use_timer) {
			unsigned long result, remain;
			printk("Using TSC for gettimeofday\n");
			tsc_quotient = calibrate_tsc_hpet(NULL);
+1 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@

extern unsigned long hpet_tick;  	/* hpet clks count per tick */
extern unsigned long hpet_address;	/* hpet memory map physical address */
extern int hpet_use_timer;

extern int hpet_rtc_timer_init(void);
extern int hpet_enable(void);