x86/apic: Allow use of lapic timer early calibration result
lapic timer calibration can be combined with tsc in platform specific calibration functions. if such calibration result is obtained early, we can skip the redundant calibration loops. Signed-off-by: Jacob Pan <jacob.jun.pan@intel.com> Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
bb84ac2d3a
commit
1ade93efd0
|
@ -49,6 +49,7 @@ extern unsigned int apic_verbosity;
|
|||
extern int local_apic_timer_c2_ok;
|
||||
|
||||
extern int disable_apic;
|
||||
extern unsigned int lapic_timer_frequency;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern void __inquire_remote_apic(int apicid);
|
||||
|
|
|
@ -186,7 +186,7 @@ static struct resource lapic_resource = {
|
|||
.flags = IORESOURCE_MEM | IORESOURCE_BUSY,
|
||||
};
|
||||
|
||||
static unsigned int calibration_result;
|
||||
unsigned int lapic_timer_frequency = 0;
|
||||
|
||||
static void apic_pm_activate(void);
|
||||
|
||||
|
@ -454,7 +454,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
|
|||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
__setup_APIC_LVTT(calibration_result,
|
||||
__setup_APIC_LVTT(lapic_timer_frequency,
|
||||
mode != CLOCK_EVT_MODE_PERIODIC, 1);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
|
@ -638,6 +638,25 @@ static int __init calibrate_APIC_clock(void)
|
|||
long delta, deltatsc;
|
||||
int pm_referenced = 0;
|
||||
|
||||
/**
|
||||
* check if lapic timer has already been calibrated by platform
|
||||
* specific routine, such as tsc calibration code. if so, we just fill
|
||||
* in the clockevent structure and return.
|
||||
*/
|
||||
|
||||
if (lapic_timer_frequency) {
|
||||
apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n",
|
||||
lapic_timer_frequency);
|
||||
lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
|
||||
TICK_NSEC, lapic_clockevent.shift);
|
||||
lapic_clockevent.max_delta_ns =
|
||||
clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
|
||||
lapic_clockevent.min_delta_ns =
|
||||
clockevent_delta2ns(0xF, &lapic_clockevent);
|
||||
lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
/* Replace the global interrupt handler */
|
||||
|
@ -679,12 +698,12 @@ static int __init calibrate_APIC_clock(void)
|
|||
lapic_clockevent.min_delta_ns =
|
||||
clockevent_delta2ns(0xF, &lapic_clockevent);
|
||||
|
||||
calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
|
||||
lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
|
||||
|
||||
apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
|
||||
apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
|
||||
apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
|
||||
calibration_result);
|
||||
lapic_timer_frequency);
|
||||
|
||||
if (cpu_has_tsc) {
|
||||
apic_printk(APIC_VERBOSE, "..... CPU clock speed is "
|
||||
|
@ -695,13 +714,13 @@ static int __init calibrate_APIC_clock(void)
|
|||
|
||||
apic_printk(APIC_VERBOSE, "..... host bus clock speed is "
|
||||
"%u.%04u MHz.\n",
|
||||
calibration_result / (1000000 / HZ),
|
||||
calibration_result % (1000000 / HZ));
|
||||
lapic_timer_frequency / (1000000 / HZ),
|
||||
lapic_timer_frequency % (1000000 / HZ));
|
||||
|
||||
/*
|
||||
* Do a sanity check on the APIC calibration result
|
||||
*/
|
||||
if (calibration_result < (1000000 / HZ)) {
|
||||
if (lapic_timer_frequency < (1000000 / HZ)) {
|
||||
local_irq_enable();
|
||||
pr_warning("APIC frequency too slow, disabling apic timer\n");
|
||||
return -1;
|
||||
|
|
Loading…
Reference in New Issue