Commit 3bc6d8c1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer fixes from Ingo Molnar:
 "Misc fixes: a /dev/rtc regression fix, two APIC timer period
  calibration fixes, an ARM clocksource driver fix and a NOHZ
  power use regression fix"

* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/hpet: Fix /dev/rtc breakage caused by RTC cleanup
  x86/timers/apic: Inform TSC deadline clockevent device about recalibration
  x86/timers/apic: Fix imprecise timer interrupts by eliminating TSC clockevents frequency roundoff error
  timers: Fix get_next_timer_interrupt() computation
  clocksource/arm_arch_timer: Force per-CPU interrupt to be level-triggered
parents e6e7214f 22cc1ca3
...@@ -135,6 +135,7 @@ extern void init_apic_mappings(void); ...@@ -135,6 +135,7 @@ extern void init_apic_mappings(void);
void register_lapic_address(unsigned long address); void register_lapic_address(unsigned long address);
extern void setup_boot_APIC_clock(void); extern void setup_boot_APIC_clock(void);
extern void setup_secondary_APIC_clock(void); extern void setup_secondary_APIC_clock(void);
extern void lapic_update_tsc_freq(void);
extern int APIC_init_uniprocessor(void); extern int APIC_init_uniprocessor(void);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
...@@ -170,6 +171,7 @@ static inline void init_apic_mappings(void) { } ...@@ -170,6 +171,7 @@ static inline void init_apic_mappings(void) { }
static inline void disable_local_APIC(void) { } static inline void disable_local_APIC(void) { }
# define setup_boot_APIC_clock x86_init_noop # define setup_boot_APIC_clock x86_init_noop
# define setup_secondary_APIC_clock x86_init_noop # define setup_secondary_APIC_clock x86_init_noop
static inline void lapic_update_tsc_freq(void) { }
#endif /* !CONFIG_X86_LOCAL_APIC */ #endif /* !CONFIG_X86_LOCAL_APIC */
#ifdef CONFIG_X86_X2APIC #ifdef CONFIG_X86_X2APIC
......
...@@ -313,7 +313,7 @@ int lapic_get_maxlvt(void) ...@@ -313,7 +313,7 @@ int lapic_get_maxlvt(void)
/* Clock divisor */ /* Clock divisor */
#define APIC_DIVISOR 16 #define APIC_DIVISOR 16
#define TSC_DIVISOR 32 #define TSC_DIVISOR 8
/* /*
* This function sets up the local APIC timer, with a timeout of * This function sets up the local APIC timer, with a timeout of
...@@ -565,12 +565,36 @@ static void setup_APIC_timer(void) ...@@ -565,12 +565,36 @@ static void setup_APIC_timer(void)
CLOCK_EVT_FEAT_DUMMY); CLOCK_EVT_FEAT_DUMMY);
levt->set_next_event = lapic_next_deadline; levt->set_next_event = lapic_next_deadline;
clockevents_config_and_register(levt, clockevents_config_and_register(levt,
(tsc_khz / TSC_DIVISOR) * 1000, tsc_khz * (1000 / TSC_DIVISOR),
0xF, ~0UL); 0xF, ~0UL);
} else } else
clockevents_register_device(levt); clockevents_register_device(levt);
} }
/*
* Install the updated TSC frequency from recalibration at the TSC
* deadline clockevent devices.
*/
static void __lapic_update_tsc_freq(void *info)
{
struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
if (!this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
return;
clockevents_update_freq(levt, tsc_khz * (1000 / TSC_DIVISOR));
}
void lapic_update_tsc_freq(void)
{
/*
* The clockevent device's ->mult and ->shift can both be
* changed. In order to avoid races, schedule the frequency
* update code on each CPU.
*/
on_each_cpu(__lapic_update_tsc_freq, NULL, 0);
}
/* /*
* In this functions we calibrate APIC bus clocks to the external timer. * In this functions we calibrate APIC bus clocks to the external timer.
* *
......
...@@ -1242,7 +1242,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) ...@@ -1242,7 +1242,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
memset(&curr_time, 0, sizeof(struct rtc_time)); memset(&curr_time, 0, sizeof(struct rtc_time));
if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) if (hpet_rtc_flags & (RTC_UIE | RTC_AIE))
mc146818_set_time(&curr_time); mc146818_get_time(&curr_time);
if (hpet_rtc_flags & RTC_UIE && if (hpet_rtc_flags & RTC_UIE &&
curr_time.tm_sec != hpet_prev_update_sec) { curr_time.tm_sec != hpet_prev_update_sec) {
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/x86_init.h> #include <asm/x86_init.h>
#include <asm/geode.h> #include <asm/geode.h>
#include <asm/apic.h>
unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */ unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */
EXPORT_SYMBOL(cpu_khz); EXPORT_SYMBOL(cpu_khz);
...@@ -1249,6 +1250,9 @@ static void tsc_refine_calibration_work(struct work_struct *work) ...@@ -1249,6 +1250,9 @@ static void tsc_refine_calibration_work(struct work_struct *work)
(unsigned long)tsc_khz / 1000, (unsigned long)tsc_khz / 1000,
(unsigned long)tsc_khz % 1000); (unsigned long)tsc_khz % 1000);
/* Inform the TSC deadline clockevent devices about the recalibration */
lapic_update_tsc_freq();
out: out:
if (boot_cpu_has(X86_FEATURE_ART)) if (boot_cpu_has(X86_FEATURE_ART))
art_related_clocksource = &clocksource_tsc; art_related_clocksource = &clocksource_tsc;
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) "arm_arch_timer: " fmt
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/device.h> #include <linux/device.h>
...@@ -370,16 +373,33 @@ static bool arch_timer_has_nonsecure_ppi(void) ...@@ -370,16 +373,33 @@ static bool arch_timer_has_nonsecure_ppi(void)
arch_timer_ppi[PHYS_NONSECURE_PPI]); arch_timer_ppi[PHYS_NONSECURE_PPI]);
} }
static u32 check_ppi_trigger(int irq)
{
u32 flags = irq_get_trigger_type(irq);
if (flags != IRQF_TRIGGER_HIGH && flags != IRQF_TRIGGER_LOW) {
pr_warn("WARNING: Invalid trigger for IRQ%d, assuming level low\n", irq);
pr_warn("WARNING: Please fix your firmware\n");
flags = IRQF_TRIGGER_LOW;
}
return flags;
}
static int arch_timer_starting_cpu(unsigned int cpu) static int arch_timer_starting_cpu(unsigned int cpu)
{ {
struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt); struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt);
u32 flags;
__arch_timer_setup(ARCH_CP15_TIMER, clk); __arch_timer_setup(ARCH_CP15_TIMER, clk);
enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], 0); flags = check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]);
enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], flags);
if (arch_timer_has_nonsecure_ppi()) if (arch_timer_has_nonsecure_ppi()) {
enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0); flags = check_ppi_trigger(arch_timer_ppi[PHYS_NONSECURE_PPI]);
enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], flags);
}
arch_counter_set_user_access(); arch_counter_set_user_access();
if (evtstrm_enable) if (evtstrm_enable)
......
...@@ -1496,6 +1496,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) ...@@ -1496,6 +1496,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
u64 expires = KTIME_MAX; u64 expires = KTIME_MAX;
unsigned long nextevt; unsigned long nextevt;
bool is_max_delta;
/* /*
* Pretend that there is no timer pending if the cpu is offline. * Pretend that there is no timer pending if the cpu is offline.
...@@ -1506,6 +1507,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) ...@@ -1506,6 +1507,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
spin_lock(&base->lock); spin_lock(&base->lock);
nextevt = __next_timer_interrupt(base); nextevt = __next_timer_interrupt(base);
is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA);
base->next_expiry = nextevt; base->next_expiry = nextevt;
/* /*
* We have a fresh next event. Check whether we can forward the base: * We have a fresh next event. Check whether we can forward the base:
...@@ -1519,6 +1521,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) ...@@ -1519,6 +1521,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
expires = basem; expires = basem;
base->is_idle = false; base->is_idle = false;
} else { } else {
if (!is_max_delta)
expires = basem + (nextevt - basej) * TICK_NSEC; expires = basem + (nextevt - basej) * TICK_NSEC;
/* /*
* If we expect to sleep more than a tick, mark the base idle: * If we expect to sleep more than a tick, mark the base idle:
......
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