x86/apic: Unify duplicated local apic timer clockevent initialization
Local APIC timer clockevent parameters can be calculated based on platform
specific methods. However the code is mostly duplicated with the interrupt
based calibration. The commit which increased the max_delta parameter
updated only one place and made the implementations diverge.
Unify it to prevent further damage.
[ tglx: Rename function to lapic_init_clockevent() and adjust changelog a bit ]
Fixes: 4aed89d6b5
("x86, lapic-timer: Increase the max_delta to 31 bits")
Reported-by: Daniel Drake <drake@endlessm.com>
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/1556213272-63568-1-git-send-email-jacob.jun.pan@linux.intel.com
This commit is contained in:
Родитель
085b775580
Коммит
6eb4f08293
|
@ -802,6 +802,24 @@ calibrate_by_pmtimer(long deltapm, long *delta, long *deltatsc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __init lapic_init_clockevent(void)
|
||||||
|
{
|
||||||
|
if (!lapic_timer_frequency)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Calculate the scaled math multiplication factor */
|
||||||
|
lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
|
||||||
|
TICK_NSEC, lapic_clockevent.shift);
|
||||||
|
lapic_clockevent.max_delta_ns =
|
||||||
|
clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
|
||||||
|
lapic_clockevent.max_delta_ticks = 0x7FFFFFFF;
|
||||||
|
lapic_clockevent.min_delta_ns =
|
||||||
|
clockevent_delta2ns(0xF, &lapic_clockevent);
|
||||||
|
lapic_clockevent.min_delta_ticks = 0xF;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init calibrate_APIC_clock(void)
|
static int __init calibrate_APIC_clock(void)
|
||||||
{
|
{
|
||||||
struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
|
struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
|
||||||
|
@ -810,25 +828,21 @@ static int __init calibrate_APIC_clock(void)
|
||||||
long delta, deltatsc;
|
long delta, deltatsc;
|
||||||
int pm_referenced = 0;
|
int pm_referenced = 0;
|
||||||
|
|
||||||
/**
|
if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
|
||||||
* check if lapic timer has already been calibrated by platform
|
return 0;
|
||||||
* specific routine, such as tsc calibration code. if so, we just fill
|
|
||||||
|
/*
|
||||||
|
* Check if lapic timer has already been calibrated by platform
|
||||||
|
* specific routine, such as tsc calibration code. If so just fill
|
||||||
* in the clockevent structure and return.
|
* in the clockevent structure and return.
|
||||||
*/
|
*/
|
||||||
|
if (!lapic_init_clockevent()) {
|
||||||
if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) {
|
|
||||||
return 0;
|
|
||||||
} else if (lapic_timer_frequency) {
|
|
||||||
apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n",
|
apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n",
|
||||||
lapic_timer_frequency);
|
lapic_timer_frequency);
|
||||||
lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
|
/*
|
||||||
TICK_NSEC, lapic_clockevent.shift);
|
* Direct calibration methods must have an always running
|
||||||
lapic_clockevent.max_delta_ns =
|
* local APIC timer, no need for broadcast timer.
|
||||||
clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
|
*/
|
||||||
lapic_clockevent.max_delta_ticks = 0x7FFFFF;
|
|
||||||
lapic_clockevent.min_delta_ns =
|
|
||||||
clockevent_delta2ns(0xF, &lapic_clockevent);
|
|
||||||
lapic_clockevent.min_delta_ticks = 0xF;
|
|
||||||
lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
|
lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -869,17 +883,8 @@ static int __init calibrate_APIC_clock(void)
|
||||||
pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1,
|
pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1,
|
||||||
&delta, &deltatsc);
|
&delta, &deltatsc);
|
||||||
|
|
||||||
/* Calculate the scaled math multiplication factor */
|
|
||||||
lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS,
|
|
||||||
lapic_clockevent.shift);
|
|
||||||
lapic_clockevent.max_delta_ns =
|
|
||||||
clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
|
|
||||||
lapic_clockevent.max_delta_ticks = 0x7FFFFFFF;
|
|
||||||
lapic_clockevent.min_delta_ns =
|
|
||||||
clockevent_delta2ns(0xF, &lapic_clockevent);
|
|
||||||
lapic_clockevent.min_delta_ticks = 0xF;
|
|
||||||
|
|
||||||
lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
|
lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
|
||||||
|
lapic_init_clockevent();
|
||||||
|
|
||||||
apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
|
apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
|
||||||
apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
|
apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче