diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2015-04-22 12:32:14 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2015-04-22 12:32:14 +0000 |
commit | dfe7b3bfbc2ab48792576631a937004db3e9452d (patch) | |
tree | 8f4768562e25957dffef340ac5d8b66b354f76c7 /sys/i386/i386 | |
parent | 6c2d9cea22f4ea40769350c93408d023413e0bc6 (diff) | |
download | src-dfe7b3bfbc2ab48792576631a937004db3e9452d.tar.gz src-dfe7b3bfbc2ab48792576631a937004db3e9452d.zip |
Move some common code from sys/amd64/amd64/machdep.c and
sys/i386/i386/machdep.c to new file sys/x86/x86/cpu_machdep.c. Most
of the code is related to the idle handling.
Discussed with: pluknet
Sponsored by: The FreeBSD Foundation
Notes
Notes:
svn path=/head/; revision=281851
Diffstat (limited to 'sys/i386/i386')
-rw-r--r-- | sys/i386/i386/machdep.c | 421 |
1 files changed, 0 insertions, 421 deletions
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 123db4ed4cbe..72f76850b7c0 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -1176,427 +1176,6 @@ sys_sigreturn(td, uap) } /* - * Machine dependent boot() routine - * - * I haven't seen anything to put here yet - * Possibly some stuff might be grafted back here from boot() - */ -void -cpu_boot(int howto) -{ -} - -/* - * Flush the D-cache for non-DMA I/O so that the I-cache can - * be made coherent later. - */ -void -cpu_flush_dcache(void *ptr, size_t len) -{ - /* Not applicable */ -} - -/* Get current clock frequency for the given cpu id. */ -int -cpu_est_clockrate(int cpu_id, uint64_t *rate) -{ - uint64_t tsc1, tsc2; - uint64_t acnt, mcnt, perf; - register_t reg; - - if (pcpu_find(cpu_id) == NULL || rate == NULL) - return (EINVAL); - if ((cpu_feature & CPUID_TSC) == 0) - return (EOPNOTSUPP); - - /* - * If TSC is P-state invariant and APERF/MPERF MSRs do not exist, - * DELAY(9) based logic fails. - */ - if (tsc_is_invariant && !tsc_perf_stat) - return (EOPNOTSUPP); - -#ifdef SMP - if (smp_cpus > 1) { - /* Schedule ourselves on the indicated cpu. */ - thread_lock(curthread); - sched_bind(curthread, cpu_id); - thread_unlock(curthread); - } -#endif - - /* Calibrate by measuring a short delay. */ - reg = intr_disable(); - if (tsc_is_invariant) { - wrmsr(MSR_MPERF, 0); - wrmsr(MSR_APERF, 0); - tsc1 = rdtsc(); - DELAY(1000); - mcnt = rdmsr(MSR_MPERF); - acnt = rdmsr(MSR_APERF); - tsc2 = rdtsc(); - intr_restore(reg); - perf = 1000 * acnt / mcnt; - *rate = (tsc2 - tsc1) * perf; - } else { - tsc1 = rdtsc(); - DELAY(1000); - tsc2 = rdtsc(); - intr_restore(reg); - *rate = (tsc2 - tsc1) * 1000; - } - -#ifdef SMP - if (smp_cpus > 1) { - thread_lock(curthread); - sched_unbind(curthread); - thread_unlock(curthread); - } -#endif - - return (0); -} - -#ifdef XEN - -static void -idle_block(void) -{ - - HYPERVISOR_sched_op(SCHEDOP_block, 0); -} - -void -cpu_halt(void) -{ - HYPERVISOR_shutdown(SHUTDOWN_poweroff); -} - -int scheduler_running; - -static void -cpu_idle_hlt(sbintime_t sbt) -{ - - scheduler_running = 1; - enable_intr(); - idle_block(); -} - -#else -/* - * Shutdown the CPU as much as possible - */ -void -cpu_halt(void) -{ - for (;;) - halt(); -} - -#endif - -void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */ -static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */ -static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ -SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RWTUN, &idle_mwait, - 0, "Use MONITOR/MWAIT for short idle"); - -#define STATE_RUNNING 0x0 -#define STATE_MWAIT 0x1 -#define STATE_SLEEPING 0x2 - -#ifndef PC98 -static void -cpu_idle_acpi(sbintime_t sbt) -{ - int *state; - - state = (int *)PCPU_PTR(monitorbuf); - *state = STATE_SLEEPING; - - /* See comments in cpu_idle_hlt(). */ - disable_intr(); - if (sched_runnable()) - enable_intr(); - else if (cpu_idle_hook) - cpu_idle_hook(sbt); - else - __asm __volatile("sti; hlt"); - *state = STATE_RUNNING; -} -#endif /* !PC98 */ - -#ifndef XEN -static void -cpu_idle_hlt(sbintime_t sbt) -{ - int *state; - - state = (int *)PCPU_PTR(monitorbuf); - *state = STATE_SLEEPING; - - /* - * Since we may be in a critical section from cpu_idle(), if - * an interrupt fires during that critical section we may have - * a pending preemption. If the CPU halts, then that thread - * may not execute until a later interrupt awakens the CPU. - * To handle this race, check for a runnable thread after - * disabling interrupts and immediately return if one is - * found. Also, we must absolutely guarentee that hlt is - * the next instruction after sti. This ensures that any - * interrupt that fires after the call to disable_intr() will - * immediately awaken the CPU from hlt. Finally, please note - * that on x86 this works fine because of interrupts enabled only - * after the instruction following sti takes place, while IF is set - * to 1 immediately, allowing hlt instruction to acknowledge the - * interrupt. - */ - disable_intr(); - if (sched_runnable()) - enable_intr(); - else - __asm __volatile("sti; hlt"); - *state = STATE_RUNNING; -} -#endif - -static void -cpu_idle_mwait(sbintime_t sbt) -{ - int *state; - - state = (int *)PCPU_PTR(monitorbuf); - *state = STATE_MWAIT; - - /* See comments in cpu_idle_hlt(). */ - disable_intr(); - if (sched_runnable()) { - enable_intr(); - *state = STATE_RUNNING; - return; - } - cpu_monitor(state, 0, 0); - if (*state == STATE_MWAIT) - __asm __volatile("sti; mwait" : : "a" (MWAIT_C1), "c" (0)); - else - enable_intr(); - *state = STATE_RUNNING; -} - -static void -cpu_idle_spin(sbintime_t sbt) -{ - int *state; - int i; - - state = (int *)PCPU_PTR(monitorbuf); - *state = STATE_RUNNING; - - /* - * The sched_runnable() call is racy but as long as there is - * a loop missing it one time will have just a little impact if any - * (and it is much better than missing the check at all). - */ - for (i = 0; i < 1000; i++) { - if (sched_runnable()) - return; - cpu_spinwait(); - } -} - -/* - * C1E renders the local APIC timer dead, so we disable it by - * reading the Interrupt Pending Message register and clearing - * both C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27). - * - * Reference: - * "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors" - * #32559 revision 3.00+ - */ -#define MSR_AMDK8_IPM 0xc0010055 -#define AMDK8_SMIONCMPHALT (1ULL << 27) -#define AMDK8_C1EONCMPHALT (1ULL << 28) -#define AMDK8_CMPHALT (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT) - -static void -cpu_probe_amdc1e(void) -{ - - /* - * Detect the presence of C1E capability mostly on latest - * dual-cores (or future) k8 family. - */ - if (cpu_vendor_id == CPU_VENDOR_AMD && - (cpu_id & 0x00000f00) == 0x00000f00 && - (cpu_id & 0x0fff0000) >= 0x00040000) { - cpu_ident_amdc1e = 1; - } -} - -#if defined(PC98) || defined(XEN) -void (*cpu_idle_fn)(sbintime_t) = cpu_idle_hlt; -#else -void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi; -#endif - -void -cpu_idle(int busy) -{ -#ifndef XEN - uint64_t msr; -#endif - sbintime_t sbt = -1; - - CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", - busy, curcpu); -#if defined(MP_WATCHDOG) && !defined(XEN) - ap_watchdog(PCPU_GET(cpuid)); -#endif -#ifndef XEN - /* If we are busy - try to use fast methods. */ - if (busy) { - if ((cpu_feature2 & CPUID2_MON) && idle_mwait) { - cpu_idle_mwait(busy); - goto out; - } - } -#endif - - /* If we have time - switch timers into idle mode. */ - if (!busy) { - critical_enter(); - sbt = cpu_idleclock(); - } - -#ifndef XEN - /* Apply AMD APIC timer C1E workaround. */ - if (cpu_ident_amdc1e && cpu_disable_c3_sleep) { - msr = rdmsr(MSR_AMDK8_IPM); - if (msr & AMDK8_CMPHALT) - wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); - } -#endif - - /* Call main idle method. */ - cpu_idle_fn(sbt); - - /* Switch timers back into active mode. */ - if (!busy) { - cpu_activeclock(); - critical_exit(); - } -#ifndef XEN -out: -#endif - CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", - busy, curcpu); -} - -int -cpu_idle_wakeup(int cpu) -{ - struct pcpu *pcpu; - int *state; - - pcpu = pcpu_find(cpu); - state = (int *)pcpu->pc_monitorbuf; - /* - * This doesn't need to be atomic since missing the race will - * simply result in unnecessary IPIs. - */ - if (*state == STATE_SLEEPING) - return (0); - if (*state == STATE_MWAIT) - *state = STATE_RUNNING; - return (1); -} - -/* - * Ordered by speed/power consumption. - */ -struct { - void *id_fn; - char *id_name; -} idle_tbl[] = { - { cpu_idle_spin, "spin" }, - { cpu_idle_mwait, "mwait" }, - { cpu_idle_hlt, "hlt" }, -#ifndef PC98 - { cpu_idle_acpi, "acpi" }, -#endif - { NULL, NULL } -}; - -static int -idle_sysctl_available(SYSCTL_HANDLER_ARGS) -{ - char *avail, *p; - int error; - int i; - - avail = malloc(256, M_TEMP, M_WAITOK); - p = avail; - for (i = 0; idle_tbl[i].id_name != NULL; i++) { - if (strstr(idle_tbl[i].id_name, "mwait") && - (cpu_feature2 & CPUID2_MON) == 0) - continue; -#ifndef PC98 - if (strcmp(idle_tbl[i].id_name, "acpi") == 0 && - cpu_idle_hook == NULL) - continue; -#endif - p += sprintf(p, "%s%s", p != avail ? ", " : "", - idle_tbl[i].id_name); - } - error = sysctl_handle_string(oidp, avail, 0, req); - free(avail, M_TEMP); - return (error); -} - -SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD, - 0, 0, idle_sysctl_available, "A", "list of available idle functions"); - -static int -idle_sysctl(SYSCTL_HANDLER_ARGS) -{ - char buf[16]; - int error; - char *p; - int i; - - p = "unknown"; - for (i = 0; idle_tbl[i].id_name != NULL; i++) { - if (idle_tbl[i].id_fn == cpu_idle_fn) { - p = idle_tbl[i].id_name; - break; - } - } - strncpy(buf, p, sizeof(buf)); - error = sysctl_handle_string(oidp, buf, sizeof(buf), req); - if (error != 0 || req->newptr == NULL) - return (error); - for (i = 0; idle_tbl[i].id_name != NULL; i++) { - if (strstr(idle_tbl[i].id_name, "mwait") && - (cpu_feature2 & CPUID2_MON) == 0) - continue; -#ifndef PC98 - if (strcmp(idle_tbl[i].id_name, "acpi") == 0 && - cpu_idle_hook == NULL) - continue; -#endif - if (strcmp(idle_tbl[i].id_name, buf)) - continue; - cpu_idle_fn = idle_tbl[i].id_fn; - return (0); - } - return (EINVAL); -} - -SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, - idle_sysctl, "A", "currently selected idle function"); - -/* * Reset registers to default values on exec. */ void |