Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/x86/local_apic.c
Show First 20 Lines • Show All 996 Lines • ▼ Show 20 Lines | |||||
#ifdef SMP | #ifdef SMP | ||||
/* The APs should always be started when hwpmc is unloaded. */ | /* The APs should always be started when hwpmc is unloaded. */ | ||||
KASSERT(mp_ncpus == 1 || smp_started, ("hwpmc unloaded too early")); | KASSERT(mp_ncpus == 1 || smp_started, ("hwpmc unloaded too early")); | ||||
#endif | #endif | ||||
smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL); | smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL); | ||||
#endif | #endif | ||||
} | } | ||||
static int | |||||
lapic_calibrate_initcount_cpuid_vm(void) | |||||
{ | |||||
u_int regs[4]; | |||||
uint64_t freq; | |||||
/* Get value from CPUID leaf if possible. */ | |||||
if (vm_guest == VM_GUEST_NO) | |||||
return (false); | |||||
if (hv_high < 0x40000010) | |||||
return (false); | |||||
do_cpuid(0x40000010, regs); | |||||
freq = (uint64_t)(regs[1]) * 1000; | |||||
markj: Can this multiplication overflow? I suspect `value` should be uint64_t too. | |||||
Done Inline ActionsThanks, fixed! cperciva: Thanks, fixed! | |||||
/* Pick timer divisor. */ | |||||
lapic_timer_divisor = 2; | |||||
do { | |||||
if (freq / lapic_timer_divisor < APIC_TIMER_MAX_COUNT) | |||||
break; | |||||
lapic_timer_divisor <<= 1; | |||||
} while (lapic_timer_divisor <= 128); | |||||
if (lapic_timer_divisor > 128) | |||||
return (false); | |||||
/* Record divided frequency. */ | |||||
count_freq = freq / lapic_timer_divisor; | |||||
return (true); | |||||
} | |||||
static uint64_t | static uint64_t | ||||
cb_lapic_getcount(void) | cb_lapic_getcount(void) | ||||
{ | { | ||||
return (APIC_TIMER_MAX_COUNT - lapic_read32(LAPIC_CCR_TIMER)); | return (APIC_TIMER_MAX_COUNT - lapic_read32(LAPIC_CCR_TIMER)); | ||||
} | } | ||||
static void | static void | ||||
lapic_calibrate_initcount(struct lapic *la) | lapic_calibrate_initcount(struct lapic *la) | ||||
{ | { | ||||
uint64_t freq; | uint64_t freq; | ||||
if (lapic_calibrate_initcount_cpuid_vm()) | |||||
goto done; | |||||
/* Calibrate the APIC timer frequency. */ | /* Calibrate the APIC timer frequency. */ | ||||
lapic_timer_set_divisor(2); | lapic_timer_set_divisor(2); | ||||
lapic_timer_oneshot_nointr(la, APIC_TIMER_MAX_COUNT); | lapic_timer_oneshot_nointr(la, APIC_TIMER_MAX_COUNT); | ||||
fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); | fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); | ||||
freq = clockcalib(cb_lapic_getcount, "lapic"); | freq = clockcalib(cb_lapic_getcount, "lapic"); | ||||
fpu_kern_leave(curthread, NULL); | fpu_kern_leave(curthread, NULL); | ||||
/* Pick a different divisor if necessary. */ | /* Pick a different divisor if necessary. */ | ||||
lapic_timer_divisor = 2; | lapic_timer_divisor = 2; | ||||
do { | do { | ||||
if (freq * 2 / lapic_timer_divisor < APIC_TIMER_MAX_COUNT) | if (freq * 2 / lapic_timer_divisor < APIC_TIMER_MAX_COUNT) | ||||
break; | break; | ||||
lapic_timer_divisor <<= 1; | lapic_timer_divisor <<= 1; | ||||
} while (lapic_timer_divisor <= 128); | } while (lapic_timer_divisor <= 128); | ||||
if (lapic_timer_divisor > 128) | if (lapic_timer_divisor > 128) | ||||
panic("lapic: Divisor too big"); | panic("lapic: Divisor too big"); | ||||
count_freq = freq * 2 / lapic_timer_divisor; | count_freq = freq * 2 / lapic_timer_divisor; | ||||
done: | |||||
if (bootverbose) { | if (bootverbose) { | ||||
printf("lapic: Divisor %lu, Frequency %lu Hz\n", | printf("lapic: Divisor %lu, Frequency %lu Hz\n", | ||||
lapic_timer_divisor, count_freq); | lapic_timer_divisor, count_freq); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
lapic_change_mode(struct eventtimer *et, struct lapic *la, | lapic_change_mode(struct eventtimer *et, struct lapic *la, | ||||
▲ Show 20 Lines • Show All 1,178 Lines • Show Last 20 Lines |
Can this multiplication overflow? I suspect value should be uint64_t too.