mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-03-06 17:23:01 +07:00
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
This commit is contained in:
commit
3bc6d8c155
@ -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) { }
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
(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 @@
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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,7 +1521,8 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
|
|||||||
expires = basem;
|
expires = basem;
|
||||||
base->is_idle = false;
|
base->is_idle = false;
|
||||||
} else {
|
} else {
|
||||||
expires = basem + (nextevt - basej) * TICK_NSEC;
|
if (!is_max_delta)
|
||||||
|
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:
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user