Commit 33042a9f authored by Chris McDermott's avatar Chris McDermott Committed by Linus Torvalds

[PATCH] x86-64: Fix HPET timer on x460

[description from AK]

The IBM Summit 3 chipset doesn't implement the HPET timer replacement
option.  Since the current Linux code relies on it use a mixed mode with
both PIT for the interrupt and HPET counters for the time keeping.  That
was already implemented, but didn't work properly because it was still
using the last interrupt offset in HPET.  This resulted in x460 not
booting.  Fix this up by using the free running HPET counter.

Shouldn't affect any other machine because they either use full HPET mode
or no HPET at all.

TBD needs a similar 32bit fix.
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Cc: Pallipadi, Venkatesh" <venkatesh.pallipadi@intel.com>
Cc: Bob Picco <bob.picco@hp.com>
Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
Cc: john stultz <johnstul@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e00d82d0
...@@ -708,7 +708,7 @@ static void setup_APIC_timer(unsigned int clocks) ...@@ -708,7 +708,7 @@ static void setup_APIC_timer(unsigned int clocks)
local_irq_save(flags); local_irq_save(flags);
/* wait for irq slice */ /* wait for irq slice */
if (vxtime.hpet_address) { if (vxtime.hpet_address && hpet_use_timer) {
int trigger = hpet_readl(HPET_T0_CMP); int trigger = hpet_readl(HPET_T0_CMP);
while (hpet_readl(HPET_COUNTER) >= trigger) while (hpet_readl(HPET_COUNTER) >= trigger)
/* do nothing */ ; /* do nothing */ ;
......
...@@ -59,7 +59,7 @@ static int notsc __initdata = 0; ...@@ -59,7 +59,7 @@ static int notsc __initdata = 0;
unsigned int cpu_khz; /* TSC clocks / usec, not used here */ unsigned int cpu_khz; /* TSC clocks / usec, not used here */
static unsigned long hpet_period; /* fsecs / HPET clock */ static unsigned long hpet_period; /* fsecs / HPET clock */
unsigned long hpet_tick; /* HPET clocks / interrupt */ unsigned long hpet_tick; /* HPET clocks / interrupt */
static int hpet_use_timer; /* Use counter of hpet for time keeping, otherwise PIT */ int hpet_use_timer; /* Use counter of hpet for time keeping, otherwise PIT */
unsigned long vxtime_hz = PIT_TICK_RATE; unsigned long vxtime_hz = PIT_TICK_RATE;
int report_lost_ticks; /* command line option */ int report_lost_ticks; /* command line option */
unsigned long long monotonic_base; unsigned long long monotonic_base;
...@@ -326,7 +326,10 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs) ...@@ -326,7 +326,10 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs)
print_symbol("rip %s\n", regs->rip); print_symbol("rip %s\n", regs->rip);
if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) { if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) {
printk(KERN_WARNING "Falling back to HPET\n"); printk(KERN_WARNING "Falling back to HPET\n");
vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; if (hpet_use_timer)
vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
else
vxtime.last = hpet_readl(HPET_COUNTER);
vxtime.mode = VXTIME_HPET; vxtime.mode = VXTIME_HPET;
do_gettimeoffset = do_gettimeoffset_hpet; do_gettimeoffset = do_gettimeoffset_hpet;
} }
...@@ -988,7 +991,10 @@ void __init time_init_gtod(void) ...@@ -988,7 +991,10 @@ void __init time_init_gtod(void)
notsc = 1; notsc = 1;
if (vxtime.hpet_address && notsc) { if (vxtime.hpet_address && notsc) {
timetype = hpet_use_timer ? "HPET" : "PIT/HPET"; timetype = hpet_use_timer ? "HPET" : "PIT/HPET";
vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; if (hpet_use_timer)
vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
else
vxtime.last = hpet_readl(HPET_COUNTER);
vxtime.mode = VXTIME_HPET; vxtime.mode = VXTIME_HPET;
do_gettimeoffset = do_gettimeoffset_hpet; do_gettimeoffset = do_gettimeoffset_hpet;
#ifdef CONFIG_X86_PM_TIMER #ifdef CONFIG_X86_PM_TIMER
......
...@@ -55,6 +55,8 @@ extern int is_hpet_enabled(void); ...@@ -55,6 +55,8 @@ extern int is_hpet_enabled(void);
extern int hpet_rtc_timer_init(void); extern int hpet_rtc_timer_init(void);
extern int oem_force_hpet_timer(void); extern int oem_force_hpet_timer(void);
extern int hpet_use_timer;
#ifdef CONFIG_HPET_EMULATE_RTC #ifdef CONFIG_HPET_EMULATE_RTC
extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
extern int hpet_set_rtc_irq_bit(unsigned long bit_mask); extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment