15db2f26eSSascha Wildner /*- 25db2f26eSSascha Wildner * Copyright (c) 2003-2005 Nate Lawson (SDG) 35db2f26eSSascha Wildner * Copyright (c) 2001 Michael Smith 45db2f26eSSascha Wildner * All rights reserved. 55db2f26eSSascha Wildner * 65db2f26eSSascha Wildner * Redistribution and use in source and binary forms, with or without 75db2f26eSSascha Wildner * modification, are permitted provided that the following conditions 85db2f26eSSascha Wildner * are met: 95db2f26eSSascha Wildner * 1. Redistributions of source code must retain the above copyright 105db2f26eSSascha Wildner * notice, this list of conditions and the following disclaimer. 115db2f26eSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 125db2f26eSSascha Wildner * notice, this list of conditions and the following disclaimer in the 135db2f26eSSascha Wildner * documentation and/or other materials provided with the distribution. 145db2f26eSSascha Wildner * 155db2f26eSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 165db2f26eSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 175db2f26eSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 185db2f26eSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 195db2f26eSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 205db2f26eSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 215db2f26eSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 225db2f26eSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 235db2f26eSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 245db2f26eSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 255db2f26eSSascha Wildner * SUCH DAMAGE. 265db2f26eSSascha Wildner * 275db2f26eSSascha Wildner * $FreeBSD: src/sys/dev/acpica/acpi_cpu.c,v 1.72 2008/04/12 12:06:00 rpaulo Exp $ 285db2f26eSSascha Wildner */ 295db2f26eSSascha Wildner 305db2f26eSSascha Wildner #include "opt_acpi.h" 315db2f26eSSascha Wildner #include <sys/param.h> 325db2f26eSSascha Wildner #include <sys/bus.h> 330e4ac8cfSSepherosa Ziehau #include <sys/cpuhelper.h> 345db2f26eSSascha Wildner #include <sys/kernel.h> 355db2f26eSSascha Wildner #include <sys/malloc.h> 365db2f26eSSascha Wildner #include <sys/globaldata.h> 375db2f26eSSascha Wildner #include <sys/power.h> 385db2f26eSSascha Wildner #include <sys/proc.h> 395db2f26eSSascha Wildner #include <sys/sbuf.h> 405db2f26eSSascha Wildner #include <sys/thread2.h> 41b45624acSSepherosa Ziehau #include <sys/serialize.h> 42c241507cSSepherosa Ziehau #include <sys/msgport2.h> 4319f23194SSepherosa Ziehau #include <sys/microtime_pcpu.h> 44daa63909SSepherosa Ziehau #include <sys/cpu_topology.h> 455db2f26eSSascha Wildner 465db2f26eSSascha Wildner #include <bus/pci/pcivar.h> 475db2f26eSSascha Wildner #include <machine/atomic.h> 485db2f26eSSascha Wildner #include <machine/globaldata.h> 495db2f26eSSascha Wildner #include <machine/md_var.h> 505db2f26eSSascha Wildner #include <machine/smp.h> 515db2f26eSSascha Wildner #include <sys/rman.h> 525db2f26eSSascha Wildner 535db2f26eSSascha Wildner #include "acpi.h" 545db2f26eSSascha Wildner #include "acpivar.h" 555db2f26eSSascha Wildner #include "acpi_cpu.h" 569925408fSSepherosa Ziehau #include "acpi_cpu_cstate.h" 575db2f26eSSascha Wildner 585db2f26eSSascha Wildner /* 59a1116831SSepherosa Ziehau * Support for ACPI Processor devices, including C[1-3+] sleep states. 605db2f26eSSascha Wildner */ 615db2f26eSSascha Wildner 625db2f26eSSascha Wildner /* Hooks for the ACPICA debugging infrastructure */ 635db2f26eSSascha Wildner #define _COMPONENT ACPI_PROCESSOR 645db2f26eSSascha Wildner ACPI_MODULE_NAME("PROCESSOR") 655db2f26eSSascha Wildner 665db2f26eSSascha Wildner #define MAX_CX_STATES 8 675db2f26eSSascha Wildner 684eee58faSSepherosa Ziehau struct acpi_cst_softc { 694eee58faSSepherosa Ziehau device_t cst_dev; 7041d9045eSSepherosa Ziehau struct acpi_cpu_softc *cst_parent; 714eee58faSSepherosa Ziehau ACPI_HANDLE cst_handle; 724eee58faSSepherosa Ziehau int cst_cpuid; 7344806d43SSepherosa Ziehau uint32_t cst_flags; /* ACPI_CST_FLAG_ */ 744eee58faSSepherosa Ziehau uint32_t cst_p_blk; /* ACPI P_BLK location */ 754eee58faSSepherosa Ziehau uint32_t cst_p_blk_len; /* P_BLK length (must be 6). */ 76a1116831SSepherosa Ziehau struct acpi_cst_cx cst_cx_states[MAX_CX_STATES]; 774eee58faSSepherosa Ziehau int cst_cx_count; /* Number of valid Cx states. */ 784eee58faSSepherosa Ziehau int cst_prev_sleep; /* Last idle sleep duration. */ 795db2f26eSSascha Wildner /* Runtime state. */ 804eee58faSSepherosa Ziehau int cst_non_c3; /* Index of lowest non-C3 state. */ 814eee58faSSepherosa Ziehau u_long cst_cx_stats[MAX_CX_STATES];/* Cx usage history. */ 825db2f26eSSascha Wildner /* Values for sysctl. */ 834eee58faSSepherosa Ziehau int cst_cx_lowest; /* Current Cx lowest */ 844eee58faSSepherosa Ziehau int cst_cx_lowest_req; /* Requested Cx lowest */ 854eee58faSSepherosa Ziehau char cst_cx_supported[64]; 865db2f26eSSascha Wildner }; 875db2f26eSSascha Wildner 8844806d43SSepherosa Ziehau #define ACPI_CST_FLAG_PROBING 0x1 89daa63909SSepherosa Ziehau #define ACPI_CST_FLAG_ATTACHED 0x2 90daa63909SSepherosa Ziehau /* Match C-states of other hyperthreads on the same core */ 91daa63909SSepherosa Ziehau #define ACPI_CST_FLAG_MATCH_HT 0x4 9244806d43SSepherosa Ziehau 935db2f26eSSascha Wildner #define PCI_VENDOR_INTEL 0x8086 945db2f26eSSascha Wildner #define PCI_DEVICE_82371AB_3 0x7113 /* PIIX4 chipset for quirks. */ 955db2f26eSSascha Wildner #define PCI_REVISION_A_STEP 0 965db2f26eSSascha Wildner #define PCI_REVISION_B_STEP 1 975db2f26eSSascha Wildner #define PCI_REVISION_4E 2 985db2f26eSSascha Wildner #define PCI_REVISION_4M 3 995db2f26eSSascha Wildner #define PIIX4_DEVACTB_REG 0x58 1005db2f26eSSascha Wildner #define PIIX4_BRLD_EN_IRQ0 (1<<0) 1015db2f26eSSascha Wildner #define PIIX4_BRLD_EN_IRQ (1<<1) 1025db2f26eSSascha Wildner #define PIIX4_BRLD_EN_IRQ8 (1<<5) 103a1116831SSepherosa Ziehau #define PIIX4_STOP_BREAK_MASK (PIIX4_BRLD_EN_IRQ0 | \ 104a1116831SSepherosa Ziehau PIIX4_BRLD_EN_IRQ | \ 105a1116831SSepherosa Ziehau PIIX4_BRLD_EN_IRQ8) 1065db2f26eSSascha Wildner #define PIIX4_PCNTRL_BST_EN (1<<10) 1075db2f26eSSascha Wildner 1085db2f26eSSascha Wildner /* Platform hardware resource information. */ 109a1116831SSepherosa Ziehau static uint32_t acpi_cst_smi_cmd; /* Value to write to SMI_CMD. */ 110a1116831SSepherosa Ziehau static uint8_t acpi_cst_ctrl; /* Indicate we are _CST aware. */ 1119925408fSSepherosa Ziehau int acpi_cst_quirks; /* Indicate any hardware bugs. */ 112a1116831SSepherosa Ziehau static boolean_t acpi_cst_use_fadt; 1135db2f26eSSascha Wildner 1145db2f26eSSascha Wildner /* Runtime state. */ 11548272d39SSepherosa Ziehau static boolean_t acpi_cst_disable_idle; 116a1116831SSepherosa Ziehau /* Disable entry to idle function */ 117a1116831SSepherosa Ziehau static int acpi_cst_cx_count; /* Number of valid Cx states */ 1185db2f26eSSascha Wildner 1195db2f26eSSascha Wildner /* Values for sysctl. */ 120a1116831SSepherosa Ziehau static int acpi_cst_cx_lowest; /* Current Cx lowest */ 121a1116831SSepherosa Ziehau static int acpi_cst_cx_lowest_req; /* Requested Cx lowest */ 1225db2f26eSSascha Wildner 123a1116831SSepherosa Ziehau static device_t *acpi_cst_devices; 124a1116831SSepherosa Ziehau static int acpi_cst_ndevices; 125a1116831SSepherosa Ziehau static struct acpi_cst_softc **acpi_cst_softc; 126a1116831SSepherosa Ziehau static struct lwkt_serialize acpi_cst_slize = LWKT_SERIALIZE_INITIALIZER; 1275db2f26eSSascha Wildner 128a1116831SSepherosa Ziehau static int acpi_cst_probe(device_t); 129a1116831SSepherosa Ziehau static int acpi_cst_attach(device_t); 130a1116831SSepherosa Ziehau static int acpi_cst_suspend(device_t); 131a1116831SSepherosa Ziehau static int acpi_cst_resume(device_t); 132a1116831SSepherosa Ziehau static int acpi_cst_shutdown(device_t); 133ac13872aSSepherosa Ziehau 134a1116831SSepherosa Ziehau static void acpi_cst_notify(device_t); 135a1116831SSepherosa Ziehau static void acpi_cst_postattach(void *); 136a1116831SSepherosa Ziehau static void acpi_cst_idle(void); 137daa63909SSepherosa Ziehau static void acpi_cst_copy(struct acpi_cst_softc *, 138daa63909SSepherosa Ziehau const struct acpi_cst_softc *); 1395db2f26eSSascha Wildner 140a1116831SSepherosa Ziehau static void acpi_cst_cx_probe(struct acpi_cst_softc *); 141a1116831SSepherosa Ziehau static void acpi_cst_cx_probe_fadt(struct acpi_cst_softc *); 142a1116831SSepherosa Ziehau static int acpi_cst_cx_probe_cst(struct acpi_cst_softc *, int); 143a1116831SSepherosa Ziehau static int acpi_cst_cx_reprobe_cst(struct acpi_cst_softc *); 144a1116831SSepherosa Ziehau 145a1116831SSepherosa Ziehau static void acpi_cst_startup(struct acpi_cst_softc *); 146a1116831SSepherosa Ziehau static void acpi_cst_support_list(struct acpi_cst_softc *); 147a1116831SSepherosa Ziehau static int acpi_cst_set_lowest(struct acpi_cst_softc *, int); 148a1116831SSepherosa Ziehau static int acpi_cst_set_lowest_oncpu(struct acpi_cst_softc *, int); 149a1116831SSepherosa Ziehau static void acpi_cst_non_c3(struct acpi_cst_softc *); 150a1116831SSepherosa Ziehau static void acpi_cst_global_cx_count(void); 151a1116831SSepherosa Ziehau static int acpi_cst_set_quirks(void); 152a1116831SSepherosa Ziehau static void acpi_cst_c3_bm_rld(struct acpi_cst_softc *); 15318862f87SSepherosa Ziehau static void acpi_cst_free_resource(struct acpi_cst_softc *, int); 15424da862fSSepherosa Ziehau static void acpi_cst_c1_halt(void); 155a1116831SSepherosa Ziehau 156a1116831SSepherosa Ziehau static int acpi_cst_usage_sysctl(SYSCTL_HANDLER_ARGS); 157a1116831SSepherosa Ziehau static int acpi_cst_lowest_sysctl(SYSCTL_HANDLER_ARGS); 158a1116831SSepherosa Ziehau static int acpi_cst_lowest_use_sysctl(SYSCTL_HANDLER_ARGS); 159a1116831SSepherosa Ziehau static int acpi_cst_global_lowest_sysctl(SYSCTL_HANDLER_ARGS); 160a1116831SSepherosa Ziehau static int acpi_cst_global_lowest_use_sysctl(SYSCTL_HANDLER_ARGS); 1615db2f26eSSascha Wildner 1629925408fSSepherosa Ziehau static int acpi_cst_cx_setup(struct acpi_cst_cx *cx); 16324da862fSSepherosa Ziehau static void acpi_cst_c1_halt_enter(const struct acpi_cst_cx *); 16424da862fSSepherosa Ziehau static void acpi_cst_cx_io_enter(const struct acpi_cst_cx *); 16524da862fSSepherosa Ziehau 16690a26aa2SSepherosa Ziehau int acpi_cst_force_bmarb; 16790a26aa2SSepherosa Ziehau TUNABLE_INT("hw.acpi.cpu.cst.force_bmarb", &acpi_cst_force_bmarb); 16890a26aa2SSepherosa Ziehau 16990a26aa2SSepherosa Ziehau int acpi_cst_force_bmsts; 17090a26aa2SSepherosa Ziehau TUNABLE_INT("hw.acpi.cpu.cst.force_bmsts", &acpi_cst_force_bmsts); 17190a26aa2SSepherosa Ziehau 17241e658a2SSepherosa Ziehau static device_method_t acpi_cst_methods[] = { 1735db2f26eSSascha Wildner /* Device interface */ 17492c9201cSSepherosa Ziehau DEVMETHOD(device_probe, acpi_cst_probe), 17592c9201cSSepherosa Ziehau DEVMETHOD(device_attach, acpi_cst_attach), 1765db2f26eSSascha Wildner DEVMETHOD(device_detach, bus_generic_detach), 17792c9201cSSepherosa Ziehau DEVMETHOD(device_shutdown, acpi_cst_shutdown), 17892c9201cSSepherosa Ziehau DEVMETHOD(device_suspend, acpi_cst_suspend), 17992c9201cSSepherosa Ziehau DEVMETHOD(device_resume, acpi_cst_resume), 1805db2f26eSSascha Wildner 1815db2f26eSSascha Wildner /* Bus interface */ 182ac13872aSSepherosa Ziehau DEVMETHOD(bus_add_child, bus_generic_add_child), 183ac13872aSSepherosa Ziehau DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 184ac13872aSSepherosa Ziehau DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list), 1855db2f26eSSascha Wildner DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 1865db2f26eSSascha Wildner DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 1875db2f26eSSascha Wildner DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 1885db2f26eSSascha Wildner DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 1895db2f26eSSascha Wildner DEVMETHOD(bus_driver_added, bus_generic_driver_added), 1905db2f26eSSascha Wildner DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1915db2f26eSSascha Wildner DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1925db2f26eSSascha Wildner DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 1935db2f26eSSascha Wildner DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 194d3c9c58eSSascha Wildner DEVMETHOD_END 1955db2f26eSSascha Wildner }; 1965db2f26eSSascha Wildner 19741e658a2SSepherosa Ziehau static driver_t acpi_cst_driver = { 1985db2f26eSSascha Wildner "cpu_cst", 19941e658a2SSepherosa Ziehau acpi_cst_methods, 2004eee58faSSepherosa Ziehau sizeof(struct acpi_cst_softc), 201*df21e16dSImre Vadász .gpri = KOBJ_GPRI_ACPI+2 2025db2f26eSSascha Wildner }; 2035db2f26eSSascha Wildner 20441e658a2SSepherosa Ziehau static devclass_t acpi_cst_devclass; 20541e658a2SSepherosa Ziehau DRIVER_MODULE(cpu_cst, cpu, acpi_cst_driver, acpi_cst_devclass, NULL, NULL); 2065db2f26eSSascha Wildner MODULE_DEPEND(cpu_cst, acpi, 1, 1, 1); 2075db2f26eSSascha Wildner 2085db2f26eSSascha Wildner static int 20992c9201cSSepherosa Ziehau acpi_cst_probe(device_t dev) 2105db2f26eSSascha Wildner { 2115db2f26eSSascha Wildner int cpu_id; 2125db2f26eSSascha Wildner 2135db2f26eSSascha Wildner if (acpi_disabled("cpu_cst") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR) 2145db2f26eSSascha Wildner return (ENXIO); 2155db2f26eSSascha Wildner 2165db2f26eSSascha Wildner cpu_id = acpi_get_magic(dev); 2175db2f26eSSascha Wildner 218a1116831SSepherosa Ziehau if (acpi_cst_softc == NULL) 219a1116831SSepherosa Ziehau acpi_cst_softc = kmalloc(sizeof(struct acpi_cst_softc *) * 2205db2f26eSSascha Wildner SMP_MAXCPU, M_TEMP /* XXX */, M_INTWAIT | M_ZERO); 2215db2f26eSSascha Wildner 2225db2f26eSSascha Wildner /* 2235db2f26eSSascha Wildner * Check if we already probed this processor. We scan the bus twice 2245db2f26eSSascha Wildner * so it's possible we've already seen this one. 2255db2f26eSSascha Wildner */ 226a1116831SSepherosa Ziehau if (acpi_cst_softc[cpu_id] != NULL) { 2275db2f26eSSascha Wildner device_printf(dev, "CPU%d cstate already exist\n", cpu_id); 2285db2f26eSSascha Wildner return (ENXIO); 2295db2f26eSSascha Wildner } 2305db2f26eSSascha Wildner 2315db2f26eSSascha Wildner /* Mark this processor as in-use and save our derived id for attach. */ 23202bba4e7SSepherosa Ziehau acpi_cst_softc[cpu_id] = device_get_softc(dev); 2335db2f26eSSascha Wildner device_set_desc(dev, "ACPI CPU C-State"); 2345db2f26eSSascha Wildner 2355db2f26eSSascha Wildner return (0); 2365db2f26eSSascha Wildner } 2375db2f26eSSascha Wildner 2385db2f26eSSascha Wildner static int 23992c9201cSSepherosa Ziehau acpi_cst_attach(device_t dev) 2405db2f26eSSascha Wildner { 2415db2f26eSSascha Wildner ACPI_BUFFER buf; 2425db2f26eSSascha Wildner ACPI_OBJECT *obj; 2434eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 2445db2f26eSSascha Wildner ACPI_STATUS status; 2455db2f26eSSascha Wildner 2465db2f26eSSascha Wildner ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 2475db2f26eSSascha Wildner 2485db2f26eSSascha Wildner sc = device_get_softc(dev); 2494eee58faSSepherosa Ziehau sc->cst_dev = dev; 2504eee58faSSepherosa Ziehau sc->cst_parent = device_get_softc(device_get_parent(dev)); 2514eee58faSSepherosa Ziehau sc->cst_handle = acpi_get_handle(dev); 2524eee58faSSepherosa Ziehau sc->cst_cpuid = acpi_get_magic(dev); 253a1116831SSepherosa Ziehau acpi_cst_softc[sc->cst_cpuid] = sc; 254a1116831SSepherosa Ziehau acpi_cst_smi_cmd = AcpiGbl_FADT.SmiCommand; 255a1116831SSepherosa Ziehau acpi_cst_ctrl = AcpiGbl_FADT.CstControl; 2565db2f26eSSascha Wildner 2575db2f26eSSascha Wildner buf.Pointer = NULL; 2585db2f26eSSascha Wildner buf.Length = ACPI_ALLOCATE_BUFFER; 2594eee58faSSepherosa Ziehau status = AcpiEvaluateObject(sc->cst_handle, NULL, NULL, &buf); 2605db2f26eSSascha Wildner if (ACPI_FAILURE(status)) { 2615db2f26eSSascha Wildner device_printf(dev, "attach failed to get Processor obj - %s\n", 2625db2f26eSSascha Wildner AcpiFormatException(status)); 26302bba4e7SSepherosa Ziehau acpi_cst_softc[sc->cst_cpuid] = NULL; 2645db2f26eSSascha Wildner return (ENXIO); 2655db2f26eSSascha Wildner } 2665db2f26eSSascha Wildner obj = (ACPI_OBJECT *)buf.Pointer; 2674eee58faSSepherosa Ziehau sc->cst_p_blk = obj->Processor.PblkAddress; 2684eee58faSSepherosa Ziehau sc->cst_p_blk_len = obj->Processor.PblkLength; 2695db2f26eSSascha Wildner AcpiOsFree(obj); 270a1116831SSepherosa Ziehau ACPI_DEBUG_PRINT((ACPI_DB_INFO, "cpu_cst%d: P_BLK at %#x/%d\n", 2714eee58faSSepherosa Ziehau device_get_unit(dev), sc->cst_p_blk, sc->cst_p_blk_len)); 2725db2f26eSSascha Wildner 2735db2f26eSSascha Wildner /* 2745db2f26eSSascha Wildner * If this is the first cpu we attach, create and initialize the generic 2755db2f26eSSascha Wildner * resources that will be used by all acpi cpu devices. 2765db2f26eSSascha Wildner */ 2775db2f26eSSascha Wildner if (device_get_unit(dev) == 0) { 278a1116831SSepherosa Ziehau /* Assume we won't be using FADT for Cx states by default */ 279a1116831SSepherosa Ziehau acpi_cst_use_fadt = FALSE; 2805db2f26eSSascha Wildner 2815db2f26eSSascha Wildner /* Queue post cpu-probing task handler */ 282a1116831SSepherosa Ziehau AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cst_postattach, NULL); 2835db2f26eSSascha Wildner } 2845db2f26eSSascha Wildner 2855db2f26eSSascha Wildner /* Probe for Cx state support. */ 286a1116831SSepherosa Ziehau acpi_cst_cx_probe(sc); 2875db2f26eSSascha Wildner 288daa63909SSepherosa Ziehau sc->cst_flags |= ACPI_CST_FLAG_ATTACHED; 289daa63909SSepherosa Ziehau 2905db2f26eSSascha Wildner return (0); 2915db2f26eSSascha Wildner } 2925db2f26eSSascha Wildner 2935db2f26eSSascha Wildner /* 2945db2f26eSSascha Wildner * Disable any entry to the idle function during suspend and re-enable it 2955db2f26eSSascha Wildner * during resume. 2965db2f26eSSascha Wildner */ 2975db2f26eSSascha Wildner static int 29892c9201cSSepherosa Ziehau acpi_cst_suspend(device_t dev) 2995db2f26eSSascha Wildner { 3005db2f26eSSascha Wildner int error; 3015db2f26eSSascha Wildner 3025db2f26eSSascha Wildner error = bus_generic_suspend(dev); 3035db2f26eSSascha Wildner if (error) 3045db2f26eSSascha Wildner return (error); 305a1116831SSepherosa Ziehau acpi_cst_disable_idle = TRUE; 3065db2f26eSSascha Wildner return (0); 3075db2f26eSSascha Wildner } 3085db2f26eSSascha Wildner 3095db2f26eSSascha Wildner static int 31092c9201cSSepherosa Ziehau acpi_cst_resume(device_t dev) 3115db2f26eSSascha Wildner { 312a1116831SSepherosa Ziehau acpi_cst_disable_idle = FALSE; 3135db2f26eSSascha Wildner return (bus_generic_resume(dev)); 3145db2f26eSSascha Wildner } 3155db2f26eSSascha Wildner 3165db2f26eSSascha Wildner static int 31792c9201cSSepherosa Ziehau acpi_cst_shutdown(device_t dev) 3185db2f26eSSascha Wildner { 3195db2f26eSSascha Wildner ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 3205db2f26eSSascha Wildner 3215db2f26eSSascha Wildner /* Allow children to shutdown first. */ 3225db2f26eSSascha Wildner bus_generic_shutdown(dev); 3235db2f26eSSascha Wildner 3245db2f26eSSascha Wildner /* 3255db2f26eSSascha Wildner * Disable any entry to the idle function. There is a small race where 3265db2f26eSSascha Wildner * an idle thread have passed this check but not gone to sleep. This 3275db2f26eSSascha Wildner * is ok since device_shutdown() does not free the softc, otherwise 3285db2f26eSSascha Wildner * we'd have to be sure all threads were evicted before returning. 3295db2f26eSSascha Wildner */ 330a1116831SSepherosa Ziehau acpi_cst_disable_idle = TRUE; 3315db2f26eSSascha Wildner 3325db2f26eSSascha Wildner return_VALUE (0); 3335db2f26eSSascha Wildner } 3345db2f26eSSascha Wildner 3355db2f26eSSascha Wildner static void 336a1116831SSepherosa Ziehau acpi_cst_cx_probe(struct acpi_cst_softc *sc) 3375db2f26eSSascha Wildner { 3385db2f26eSSascha Wildner ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 3395db2f26eSSascha Wildner 3405db2f26eSSascha Wildner /* Use initial sleep value of 1 sec. to start with lowest idle state. */ 3414eee58faSSepherosa Ziehau sc->cst_prev_sleep = 1000000; 3424eee58faSSepherosa Ziehau sc->cst_cx_lowest = 0; 3434eee58faSSepherosa Ziehau sc->cst_cx_lowest_req = 0; 3445db2f26eSSascha Wildner 3455db2f26eSSascha Wildner /* 3465db2f26eSSascha Wildner * Check for the ACPI 2.0 _CST sleep states object. If we can't find 347a1116831SSepherosa Ziehau * any, we'll revert to FADT/P_BLK Cx control method which will be 348a1116831SSepherosa Ziehau * handled by acpi_cst_postattach. We need to defer to after having 349a1116831SSepherosa Ziehau * probed all the cpus in the system before probing for Cx states from 350a1116831SSepherosa Ziehau * FADT as we may already have found cpus with valid _CST packages. 3515db2f26eSSascha Wildner */ 352a1116831SSepherosa Ziehau if (!acpi_cst_use_fadt && acpi_cst_cx_probe_cst(sc, 0) != 0) { 3535db2f26eSSascha Wildner /* 3545db2f26eSSascha Wildner * We were unable to find a _CST package for this cpu or there 3555db2f26eSSascha Wildner * was an error parsing it. Switch back to generic mode. 3565db2f26eSSascha Wildner */ 357a1116831SSepherosa Ziehau acpi_cst_use_fadt = TRUE; 3585db2f26eSSascha Wildner if (bootverbose) 359a1116831SSepherosa Ziehau device_printf(sc->cst_dev, "switching to FADT Cx mode\n"); 3605db2f26eSSascha Wildner } 3615db2f26eSSascha Wildner 3625db2f26eSSascha Wildner /* 3635db2f26eSSascha Wildner * TODO: _CSD Package should be checked here. 3645db2f26eSSascha Wildner */ 3655db2f26eSSascha Wildner } 3665db2f26eSSascha Wildner 3675db2f26eSSascha Wildner static void 368a1116831SSepherosa Ziehau acpi_cst_cx_probe_fadt(struct acpi_cst_softc *sc) 3695db2f26eSSascha Wildner { 370a1116831SSepherosa Ziehau struct acpi_cst_cx *cx_ptr; 3719925408fSSepherosa Ziehau int error; 3729925408fSSepherosa Ziehau 37318862f87SSepherosa Ziehau /* 37418862f87SSepherosa Ziehau * Free all previously allocated resources. 37518862f87SSepherosa Ziehau * 37618862f87SSepherosa Ziehau * NITE: 37718862f87SSepherosa Ziehau * It is needed, since we could enter here because of other 37818862f87SSepherosa Ziehau * cpu's _CST probing failure. 37918862f87SSepherosa Ziehau */ 38018862f87SSepherosa Ziehau acpi_cst_free_resource(sc, 0); 3815db2f26eSSascha Wildner 3824eee58faSSepherosa Ziehau sc->cst_cx_count = 0; 3834eee58faSSepherosa Ziehau cx_ptr = sc->cst_cx_states; 3845db2f26eSSascha Wildner 3855db2f26eSSascha Wildner /* Use initial sleep value of 1 sec. to start with lowest idle state. */ 3864eee58faSSepherosa Ziehau sc->cst_prev_sleep = 1000000; 3875db2f26eSSascha Wildner 3885db2f26eSSascha Wildner /* C1 has been required since just after ACPI 1.0 */ 3896df05d3dSSepherosa Ziehau cx_ptr->gas.SpaceId = ACPI_ADR_SPACE_FIXED_HARDWARE; 3905db2f26eSSascha Wildner cx_ptr->type = ACPI_STATE_C1; 3915db2f26eSSascha Wildner cx_ptr->trans_lat = 0; 39224da862fSSepherosa Ziehau cx_ptr->enter = acpi_cst_c1_halt_enter; 3939925408fSSepherosa Ziehau error = acpi_cst_cx_setup(cx_ptr); 3949925408fSSepherosa Ziehau if (error) 3959925408fSSepherosa Ziehau panic("C1 FADT HALT setup failed: %d", error); 3965db2f26eSSascha Wildner cx_ptr++; 3974eee58faSSepherosa Ziehau sc->cst_cx_count++; 3985db2f26eSSascha Wildner 3998621dc6dSSepherosa Ziehau /* C2(+) is not supported on MP system */ 4008621dc6dSSepherosa Ziehau if (ncpus > 1 && (AcpiGbl_FADT.Flags & ACPI_FADT_C2_MP_SUPPORTED) == 0) 4018621dc6dSSepherosa Ziehau return; 4028621dc6dSSepherosa Ziehau 4035db2f26eSSascha Wildner /* 4045db2f26eSSascha Wildner * The spec says P_BLK must be 6 bytes long. However, some systems 4055db2f26eSSascha Wildner * use it to indicate a fractional set of features present so we 4065db2f26eSSascha Wildner * take 5 as C2. Some may also have a value of 7 to indicate 4075db2f26eSSascha Wildner * another C3 but most use _CST for this (as required) and having 4085db2f26eSSascha Wildner * "only" C1-C3 is not a hardship. 4095db2f26eSSascha Wildner */ 4104eee58faSSepherosa Ziehau if (sc->cst_p_blk_len < 5) 4115db2f26eSSascha Wildner return; 4125db2f26eSSascha Wildner 4135db2f26eSSascha Wildner /* Validate and allocate resources for C2 (P_LVL2). */ 4145db2f26eSSascha Wildner if (AcpiGbl_FADT.C2Latency <= 100) { 4151dff7e06SSepherosa Ziehau cx_ptr->gas.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO; 4161dff7e06SSepherosa Ziehau cx_ptr->gas.BitWidth = 8; 4171dff7e06SSepherosa Ziehau cx_ptr->gas.Address = sc->cst_p_blk + 4; 4185db2f26eSSascha Wildner 41941d9045eSSepherosa Ziehau cx_ptr->rid = sc->cst_parent->cpu_next_rid; 4201dff7e06SSepherosa Ziehau acpi_bus_alloc_gas(sc->cst_dev, &cx_ptr->res_type, &cx_ptr->rid, 4219925408fSSepherosa Ziehau &cx_ptr->gas, &cx_ptr->res, RF_SHAREABLE); 4229925408fSSepherosa Ziehau if (cx_ptr->res != NULL) { 42341d9045eSSepherosa Ziehau sc->cst_parent->cpu_next_rid++; 4245db2f26eSSascha Wildner cx_ptr->type = ACPI_STATE_C2; 4255db2f26eSSascha Wildner cx_ptr->trans_lat = AcpiGbl_FADT.C2Latency; 42624da862fSSepherosa Ziehau cx_ptr->enter = acpi_cst_cx_io_enter; 4279925408fSSepherosa Ziehau cx_ptr->btag = rman_get_bustag(cx_ptr->res); 4289925408fSSepherosa Ziehau cx_ptr->bhand = rman_get_bushandle(cx_ptr->res); 4299925408fSSepherosa Ziehau error = acpi_cst_cx_setup(cx_ptr); 4309925408fSSepherosa Ziehau if (error) 4319925408fSSepherosa Ziehau panic("C2 FADT I/O setup failed: %d", error); 4325db2f26eSSascha Wildner cx_ptr++; 4334eee58faSSepherosa Ziehau sc->cst_cx_count++; 4344eee58faSSepherosa Ziehau sc->cst_non_c3 = 1; 4355db2f26eSSascha Wildner } 4365db2f26eSSascha Wildner } 4374eee58faSSepherosa Ziehau if (sc->cst_p_blk_len < 6) 4385db2f26eSSascha Wildner return; 4395db2f26eSSascha Wildner 4405db2f26eSSascha Wildner /* Validate and allocate resources for C3 (P_LVL3). */ 441a1116831SSepherosa Ziehau if (AcpiGbl_FADT.C3Latency <= 1000 && 442a1116831SSepherosa Ziehau !(acpi_cst_quirks & ACPI_CST_QUIRK_NO_C3)) { 4431dff7e06SSepherosa Ziehau cx_ptr->gas.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO; 4441dff7e06SSepherosa Ziehau cx_ptr->gas.BitWidth = 8; 4451dff7e06SSepherosa Ziehau cx_ptr->gas.Address = sc->cst_p_blk + 5; 4465db2f26eSSascha Wildner 44741d9045eSSepherosa Ziehau cx_ptr->rid = sc->cst_parent->cpu_next_rid; 4481dff7e06SSepherosa Ziehau acpi_bus_alloc_gas(sc->cst_dev, &cx_ptr->res_type, &cx_ptr->rid, 4499925408fSSepherosa Ziehau &cx_ptr->gas, &cx_ptr->res, RF_SHAREABLE); 4509925408fSSepherosa Ziehau if (cx_ptr->res != NULL) { 45141d9045eSSepherosa Ziehau sc->cst_parent->cpu_next_rid++; 4525db2f26eSSascha Wildner cx_ptr->type = ACPI_STATE_C3; 4535db2f26eSSascha Wildner cx_ptr->trans_lat = AcpiGbl_FADT.C3Latency; 45424da862fSSepherosa Ziehau cx_ptr->enter = acpi_cst_cx_io_enter; 4559925408fSSepherosa Ziehau cx_ptr->btag = rman_get_bustag(cx_ptr->res); 4569925408fSSepherosa Ziehau cx_ptr->bhand = rman_get_bushandle(cx_ptr->res); 4579925408fSSepherosa Ziehau error = acpi_cst_cx_setup(cx_ptr); 4589925408fSSepherosa Ziehau if (error) 4599925408fSSepherosa Ziehau panic("C3 FADT I/O setup failed: %d", error); 4605db2f26eSSascha Wildner cx_ptr++; 4614eee58faSSepherosa Ziehau sc->cst_cx_count++; 4625db2f26eSSascha Wildner } 4635db2f26eSSascha Wildner } 4645db2f26eSSascha Wildner } 4655db2f26eSSascha Wildner 466daa63909SSepherosa Ziehau static void 467daa63909SSepherosa Ziehau acpi_cst_copy(struct acpi_cst_softc *dst_sc, 468daa63909SSepherosa Ziehau const struct acpi_cst_softc *src_sc) 469daa63909SSepherosa Ziehau { 470daa63909SSepherosa Ziehau dst_sc->cst_non_c3 = src_sc->cst_non_c3; 471daa63909SSepherosa Ziehau dst_sc->cst_cx_count = src_sc->cst_cx_count; 472daa63909SSepherosa Ziehau memcpy(dst_sc->cst_cx_states, src_sc->cst_cx_states, 473daa63909SSepherosa Ziehau sizeof(dst_sc->cst_cx_states)); 474daa63909SSepherosa Ziehau } 475daa63909SSepherosa Ziehau 4765db2f26eSSascha Wildner /* 4775db2f26eSSascha Wildner * Parse a _CST package and set up its Cx states. Since the _CST object 4785db2f26eSSascha Wildner * can change dynamically, our notify handler may call this function 4795db2f26eSSascha Wildner * to clean up and probe the new _CST package. 4805db2f26eSSascha Wildner */ 4815db2f26eSSascha Wildner static int 482a1116831SSepherosa Ziehau acpi_cst_cx_probe_cst(struct acpi_cst_softc *sc, int reprobe) 4835db2f26eSSascha Wildner { 484a1116831SSepherosa Ziehau struct acpi_cst_cx *cx_ptr; 4855db2f26eSSascha Wildner ACPI_STATUS status; 4865db2f26eSSascha Wildner ACPI_BUFFER buf; 4875db2f26eSSascha Wildner ACPI_OBJECT *top; 4885db2f26eSSascha Wildner ACPI_OBJECT *pkg; 4895db2f26eSSascha Wildner uint32_t count; 4905db2f26eSSascha Wildner int i; 4915db2f26eSSascha Wildner 4925db2f26eSSascha Wildner ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 4935db2f26eSSascha Wildner 494f2b1cf25SSepherosa Ziehau if (reprobe) 4950e4ac8cfSSepherosa Ziehau cpuhelper_assert(sc->cst_cpuid, true); 496f2b1cf25SSepherosa Ziehau 4975db2f26eSSascha Wildner buf.Pointer = NULL; 4985db2f26eSSascha Wildner buf.Length = ACPI_ALLOCATE_BUFFER; 4994eee58faSSepherosa Ziehau status = AcpiEvaluateObject(sc->cst_handle, "_CST", NULL, &buf); 5005db2f26eSSascha Wildner if (ACPI_FAILURE(status)) 5015db2f26eSSascha Wildner return (ENXIO); 5025db2f26eSSascha Wildner 5035db2f26eSSascha Wildner /* _CST is a package with a count and at least one Cx package. */ 5045db2f26eSSascha Wildner top = (ACPI_OBJECT *)buf.Pointer; 5055db2f26eSSascha Wildner if (!ACPI_PKG_VALID(top, 2) || acpi_PkgInt32(top, 0, &count) != 0) { 5064eee58faSSepherosa Ziehau device_printf(sc->cst_dev, "invalid _CST package\n"); 5075db2f26eSSascha Wildner AcpiOsFree(buf.Pointer); 5085db2f26eSSascha Wildner return (ENXIO); 5095db2f26eSSascha Wildner } 5105db2f26eSSascha Wildner if (count != top->Package.Count - 1) { 5114eee58faSSepherosa Ziehau device_printf(sc->cst_dev, "invalid _CST state count (%d != %d)\n", 5125db2f26eSSascha Wildner count, top->Package.Count - 1); 5135db2f26eSSascha Wildner count = top->Package.Count - 1; 5145db2f26eSSascha Wildner } 5155db2f26eSSascha Wildner if (count > MAX_CX_STATES) { 5164eee58faSSepherosa Ziehau device_printf(sc->cst_dev, "_CST has too many states (%d)\n", count); 5175db2f26eSSascha Wildner count = MAX_CX_STATES; 5185db2f26eSSascha Wildner } 5195db2f26eSSascha Wildner 520daa63909SSepherosa Ziehau sc->cst_flags |= ACPI_CST_FLAG_PROBING | ACPI_CST_FLAG_MATCH_HT; 52144806d43SSepherosa Ziehau cpu_sfence(); 52244806d43SSepherosa Ziehau 52318862f87SSepherosa Ziehau /* 52418862f87SSepherosa Ziehau * Free all previously allocated resources 52518862f87SSepherosa Ziehau * 52618862f87SSepherosa Ziehau * NOTE: It is needed for _CST reprobing. 52718862f87SSepherosa Ziehau */ 52818862f87SSepherosa Ziehau acpi_cst_free_resource(sc, 0); 529ed3bf55eSSepherosa Ziehau 5305db2f26eSSascha Wildner /* Set up all valid states. */ 5314eee58faSSepherosa Ziehau sc->cst_cx_count = 0; 5324eee58faSSepherosa Ziehau cx_ptr = sc->cst_cx_states; 5335db2f26eSSascha Wildner for (i = 0; i < count; i++) { 5349925408fSSepherosa Ziehau int error; 5359925408fSSepherosa Ziehau 5365db2f26eSSascha Wildner pkg = &top->Package.Elements[i + 1]; 5375db2f26eSSascha Wildner if (!ACPI_PKG_VALID(pkg, 4) || 5385db2f26eSSascha Wildner acpi_PkgInt32(pkg, 1, &cx_ptr->type) != 0 || 5395db2f26eSSascha Wildner acpi_PkgInt32(pkg, 2, &cx_ptr->trans_lat) != 0 || 5405db2f26eSSascha Wildner acpi_PkgInt32(pkg, 3, &cx_ptr->power) != 0) { 5415db2f26eSSascha Wildner 5424eee58faSSepherosa Ziehau device_printf(sc->cst_dev, "skipping invalid Cx state package\n"); 5435db2f26eSSascha Wildner continue; 5445db2f26eSSascha Wildner } 5455db2f26eSSascha Wildner 5465db2f26eSSascha Wildner /* Validate the state to see if we should use it. */ 5475db2f26eSSascha Wildner switch (cx_ptr->type) { 5485db2f26eSSascha Wildner case ACPI_STATE_C1: 5494eee58faSSepherosa Ziehau sc->cst_non_c3 = i; 55024da862fSSepherosa Ziehau cx_ptr->enter = acpi_cst_c1_halt_enter; 5519925408fSSepherosa Ziehau error = acpi_cst_cx_setup(cx_ptr); 5529925408fSSepherosa Ziehau if (error) 5539925408fSSepherosa Ziehau panic("C1 CST HALT setup failed: %d", error); 554daa63909SSepherosa Ziehau if (sc->cst_cx_count != 0) { 555daa63909SSepherosa Ziehau /* 556daa63909SSepherosa Ziehau * C1 is not the first C-state; something really stupid 557daa63909SSepherosa Ziehau * is going on ... 558daa63909SSepherosa Ziehau */ 559daa63909SSepherosa Ziehau sc->cst_flags &= ~ACPI_CST_FLAG_MATCH_HT; 560daa63909SSepherosa Ziehau } 5615db2f26eSSascha Wildner cx_ptr++; 5624eee58faSSepherosa Ziehau sc->cst_cx_count++; 5635db2f26eSSascha Wildner continue; 5645db2f26eSSascha Wildner case ACPI_STATE_C2: 5654eee58faSSepherosa Ziehau sc->cst_non_c3 = i; 5665db2f26eSSascha Wildner break; 5675db2f26eSSascha Wildner case ACPI_STATE_C3: 5685db2f26eSSascha Wildner default: 569a1116831SSepherosa Ziehau if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_C3) != 0) { 5705db2f26eSSascha Wildner ACPI_DEBUG_PRINT((ACPI_DB_INFO, 571a1116831SSepherosa Ziehau "cpu_cst%d: C3[%d] not available.\n", 5724eee58faSSepherosa Ziehau device_get_unit(sc->cst_dev), i)); 5735db2f26eSSascha Wildner continue; 5745db2f26eSSascha Wildner } 5755db2f26eSSascha Wildner break; 5765db2f26eSSascha Wildner } 5775db2f26eSSascha Wildner 5781dff7e06SSepherosa Ziehau /* 5791dff7e06SSepherosa Ziehau * Allocate the control register for C2 or C3(+). 5801dff7e06SSepherosa Ziehau */ 5819925408fSSepherosa Ziehau KASSERT(cx_ptr->res == NULL, ("still has res")); 5821dff7e06SSepherosa Ziehau acpi_PkgRawGas(pkg, 0, &cx_ptr->gas); 5831dff7e06SSepherosa Ziehau 584daa63909SSepherosa Ziehau /* 585daa63909SSepherosa Ziehau * We match number of C2/C3 for hyperthreads, only if the 586daa63909SSepherosa Ziehau * register is "Fixed Hardware", e.g. on most of the Intel 587daa63909SSepherosa Ziehau * CPUs. We don't have much to do for the rest of the 588daa63909SSepherosa Ziehau * register types. 589daa63909SSepherosa Ziehau */ 590daa63909SSepherosa Ziehau if (cx_ptr->gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) 591daa63909SSepherosa Ziehau sc->cst_flags &= ~ACPI_CST_FLAG_MATCH_HT; 592daa63909SSepherosa Ziehau 59341d9045eSSepherosa Ziehau cx_ptr->rid = sc->cst_parent->cpu_next_rid; 5941dff7e06SSepherosa Ziehau acpi_bus_alloc_gas(sc->cst_dev, &cx_ptr->res_type, &cx_ptr->rid, 5959925408fSSepherosa Ziehau &cx_ptr->gas, &cx_ptr->res, RF_SHAREABLE); 5969925408fSSepherosa Ziehau if (cx_ptr->res != NULL) { 59741d9045eSSepherosa Ziehau sc->cst_parent->cpu_next_rid++; 5985db2f26eSSascha Wildner ACPI_DEBUG_PRINT((ACPI_DB_INFO, 599a1116831SSepherosa Ziehau "cpu_cst%d: Got C%d - %d latency\n", 6004eee58faSSepherosa Ziehau device_get_unit(sc->cst_dev), cx_ptr->type, 6015db2f26eSSascha Wildner cx_ptr->trans_lat)); 60224da862fSSepherosa Ziehau cx_ptr->enter = acpi_cst_cx_io_enter; 6039925408fSSepherosa Ziehau cx_ptr->btag = rman_get_bustag(cx_ptr->res); 6049925408fSSepherosa Ziehau cx_ptr->bhand = rman_get_bushandle(cx_ptr->res); 6059925408fSSepherosa Ziehau error = acpi_cst_cx_setup(cx_ptr); 6069925408fSSepherosa Ziehau if (error) 6079925408fSSepherosa Ziehau panic("C%d CST I/O setup failed: %d", cx_ptr->type, error); 6085db2f26eSSascha Wildner cx_ptr++; 6094eee58faSSepherosa Ziehau sc->cst_cx_count++; 6109925408fSSepherosa Ziehau } else { 6119925408fSSepherosa Ziehau error = acpi_cst_cx_setup(cx_ptr); 6129925408fSSepherosa Ziehau if (!error) { 6139925408fSSepherosa Ziehau KASSERT(cx_ptr->enter != NULL, 6149925408fSSepherosa Ziehau ("C%d enter is not set", cx_ptr->type)); 6159925408fSSepherosa Ziehau cx_ptr++; 6169925408fSSepherosa Ziehau sc->cst_cx_count++; 6179925408fSSepherosa Ziehau } 6185db2f26eSSascha Wildner } 6195db2f26eSSascha Wildner } 6205db2f26eSSascha Wildner AcpiOsFree(buf.Pointer); 6215db2f26eSSascha Wildner 622daa63909SSepherosa Ziehau if (sc->cst_flags & ACPI_CST_FLAG_MATCH_HT) { 623daa63909SSepherosa Ziehau cpumask_t mask; 624daa63909SSepherosa Ziehau 625daa63909SSepherosa Ziehau mask = get_cpumask_from_level(sc->cst_cpuid, CORE_LEVEL); 626daa63909SSepherosa Ziehau if (CPUMASK_TESTNZERO(mask)) { 627daa63909SSepherosa Ziehau int cpu; 628daa63909SSepherosa Ziehau 629daa63909SSepherosa Ziehau for (cpu = 0; cpu < ncpus; ++cpu) { 630daa63909SSepherosa Ziehau struct acpi_cst_softc *sc1 = acpi_cst_softc[cpu]; 631daa63909SSepherosa Ziehau 632daa63909SSepherosa Ziehau if (sc1 == NULL || sc1 == sc || 633daa63909SSepherosa Ziehau (sc1->cst_flags & ACPI_CST_FLAG_ATTACHED) == 0 || 634daa63909SSepherosa Ziehau (sc1->cst_flags & ACPI_CST_FLAG_MATCH_HT) == 0) 635daa63909SSepherosa Ziehau continue; 636daa63909SSepherosa Ziehau if (!CPUMASK_TESTBIT(mask, sc1->cst_cpuid)) 637daa63909SSepherosa Ziehau continue; 638daa63909SSepherosa Ziehau 639daa63909SSepherosa Ziehau if (sc1->cst_cx_count != sc->cst_cx_count) { 640daa63909SSepherosa Ziehau struct acpi_cst_softc *src_sc, *dst_sc; 641daa63909SSepherosa Ziehau 642daa63909SSepherosa Ziehau if (bootverbose) { 643daa63909SSepherosa Ziehau device_printf(sc->cst_dev, 644daa63909SSepherosa Ziehau "inconstent C-state count: %d, %s has %d\n", 645daa63909SSepherosa Ziehau sc->cst_cx_count, 646daa63909SSepherosa Ziehau device_get_nameunit(sc1->cst_dev), 647daa63909SSepherosa Ziehau sc1->cst_cx_count); 648daa63909SSepherosa Ziehau } 649daa63909SSepherosa Ziehau if (sc1->cst_cx_count > sc->cst_cx_count) { 650daa63909SSepherosa Ziehau src_sc = sc1; 651daa63909SSepherosa Ziehau dst_sc = sc; 652daa63909SSepherosa Ziehau } else { 653daa63909SSepherosa Ziehau src_sc = sc; 654daa63909SSepherosa Ziehau dst_sc = sc1; 655daa63909SSepherosa Ziehau } 656daa63909SSepherosa Ziehau acpi_cst_copy(dst_sc, src_sc); 657daa63909SSepherosa Ziehau } 658daa63909SSepherosa Ziehau } 659daa63909SSepherosa Ziehau } 660daa63909SSepherosa Ziehau } 661daa63909SSepherosa Ziehau 662ad544345SSepherosa Ziehau if (reprobe) { 6632bfe985fSSepherosa Ziehau /* If there are C3(+) states, always enable bus master wakeup */ 6649925408fSSepherosa Ziehau if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) { 6658b48ec4dSSepherosa Ziehau for (i = 0; i < sc->cst_cx_count; ++i) { 666a1116831SSepherosa Ziehau struct acpi_cst_cx *cx = &sc->cst_cx_states[i]; 6678b48ec4dSSepherosa Ziehau 6688b48ec4dSSepherosa Ziehau if (cx->type >= ACPI_STATE_C3) { 6698b48ec4dSSepherosa Ziehau AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 1); 6708b48ec4dSSepherosa Ziehau break; 6718b48ec4dSSepherosa Ziehau } 6728b48ec4dSSepherosa Ziehau } 6738b48ec4dSSepherosa Ziehau } 6748b48ec4dSSepherosa Ziehau 675ad544345SSepherosa Ziehau /* Fix up the lowest Cx being used */ 676a1116831SSepherosa Ziehau acpi_cst_set_lowest_oncpu(sc, sc->cst_cx_lowest_req); 677ad544345SSepherosa Ziehau } 678f2b1cf25SSepherosa Ziehau 679f2b1cf25SSepherosa Ziehau /* 680f2b1cf25SSepherosa Ziehau * Cache the lowest non-C3 state. 681f2b1cf25SSepherosa Ziehau * NOTE: must after cst_cx_lowest is set. 682f2b1cf25SSepherosa Ziehau */ 683a1116831SSepherosa Ziehau acpi_cst_non_c3(sc); 684f2b1cf25SSepherosa Ziehau 68544806d43SSepherosa Ziehau cpu_sfence(); 68644806d43SSepherosa Ziehau sc->cst_flags &= ~ACPI_CST_FLAG_PROBING; 68744806d43SSepherosa Ziehau 6885db2f26eSSascha Wildner return (0); 6895db2f26eSSascha Wildner } 6905db2f26eSSascha Wildner 69144806d43SSepherosa Ziehau static void 6920e4ac8cfSSepherosa Ziehau acpi_cst_cx_reprobe_cst_handler(struct cpuhelper_msg *msg) 69344806d43SSepherosa Ziehau { 69444806d43SSepherosa Ziehau int error; 69544806d43SSepherosa Ziehau 6960e4ac8cfSSepherosa Ziehau error = acpi_cst_cx_probe_cst(msg->ch_cbarg, 1); 6970e4ac8cfSSepherosa Ziehau cpuhelper_replymsg(msg, error); 69844806d43SSepherosa Ziehau } 69944806d43SSepherosa Ziehau 70044806d43SSepherosa Ziehau static int 701a1116831SSepherosa Ziehau acpi_cst_cx_reprobe_cst(struct acpi_cst_softc *sc) 70244806d43SSepherosa Ziehau { 7030e4ac8cfSSepherosa Ziehau struct cpuhelper_msg msg; 70444806d43SSepherosa Ziehau 7050e4ac8cfSSepherosa Ziehau cpuhelper_initmsg(&msg, &curthread->td_msgport, 7060e4ac8cfSSepherosa Ziehau acpi_cst_cx_reprobe_cst_handler, sc, MSGF_PRIORITY); 7070e4ac8cfSSepherosa Ziehau return (cpuhelper_domsg(&msg, sc->cst_cpuid)); 70844806d43SSepherosa Ziehau } 70944806d43SSepherosa Ziehau 7105db2f26eSSascha Wildner /* 711a1116831SSepherosa Ziehau * Call this *after* all CPUs Cx states have been attached. 7125db2f26eSSascha Wildner */ 7135db2f26eSSascha Wildner static void 714a1116831SSepherosa Ziehau acpi_cst_postattach(void *arg) 7155db2f26eSSascha Wildner { 7164eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 7175db2f26eSSascha Wildner int i; 7185db2f26eSSascha Wildner 719a1116831SSepherosa Ziehau /* Get set of Cx state devices */ 720a1116831SSepherosa Ziehau devclass_get_devices(acpi_cst_devclass, &acpi_cst_devices, 721a1116831SSepherosa Ziehau &acpi_cst_ndevices); 7225db2f26eSSascha Wildner 7235db2f26eSSascha Wildner /* 7245db2f26eSSascha Wildner * Setup any quirks that might necessary now that we have probed 725a1116831SSepherosa Ziehau * all the CPUs' Cx states. 7265db2f26eSSascha Wildner */ 727a1116831SSepherosa Ziehau acpi_cst_set_quirks(); 7285db2f26eSSascha Wildner 729a1116831SSepherosa Ziehau if (acpi_cst_use_fadt) { 7305db2f26eSSascha Wildner /* 731a1116831SSepherosa Ziehau * We are using Cx mode from FADT, probe for available Cx states 7325db2f26eSSascha Wildner * for all processors. 7335db2f26eSSascha Wildner */ 734a1116831SSepherosa Ziehau for (i = 0; i < acpi_cst_ndevices; i++) { 735a1116831SSepherosa Ziehau sc = device_get_softc(acpi_cst_devices[i]); 736a1116831SSepherosa Ziehau acpi_cst_cx_probe_fadt(sc); 7375db2f26eSSascha Wildner } 7385db2f26eSSascha Wildner } else { 7395db2f26eSSascha Wildner /* 7405db2f26eSSascha Wildner * We are using _CST mode, remove C3 state if necessary. 7414cf48621SSepherosa Ziehau * 7425db2f26eSSascha Wildner * As we now know for sure that we will be using _CST mode 7435db2f26eSSascha Wildner * install our notify handler. 7445db2f26eSSascha Wildner */ 745a1116831SSepherosa Ziehau for (i = 0; i < acpi_cst_ndevices; i++) { 746a1116831SSepherosa Ziehau sc = device_get_softc(acpi_cst_devices[i]); 7479925408fSSepherosa Ziehau if (acpi_cst_quirks & ACPI_CST_QUIRK_NO_C3) { 74818862f87SSepherosa Ziehau /* Free part of unused resources */ 74918862f87SSepherosa Ziehau acpi_cst_free_resource(sc, sc->cst_non_c3 + 1); 7504eee58faSSepherosa Ziehau sc->cst_cx_count = sc->cst_non_c3 + 1; 7519925408fSSepherosa Ziehau } 75241d9045eSSepherosa Ziehau sc->cst_parent->cpu_cst_notify = acpi_cst_notify; 7535db2f26eSSascha Wildner } 7545db2f26eSSascha Wildner } 755a1116831SSepherosa Ziehau acpi_cst_global_cx_count(); 7565db2f26eSSascha Wildner 7575db2f26eSSascha Wildner /* Perform Cx final initialization. */ 758a1116831SSepherosa Ziehau for (i = 0; i < acpi_cst_ndevices; i++) { 759a1116831SSepherosa Ziehau sc = device_get_softc(acpi_cst_devices[i]); 760a1116831SSepherosa Ziehau acpi_cst_startup(sc); 7615db2f26eSSascha Wildner 7624eee58faSSepherosa Ziehau if (sc->cst_parent->glob_sysctl_tree != NULL) { 76341d9045eSSepherosa Ziehau struct acpi_cpu_softc *cpu = sc->cst_parent; 7645db2f26eSSascha Wildner 7655db2f26eSSascha Wildner /* Add a sysctl handler to handle global Cx lowest setting */ 76641d9045eSSepherosa Ziehau SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx, 76741d9045eSSepherosa Ziehau SYSCTL_CHILDREN(cpu->glob_sysctl_tree), 7685db2f26eSSascha Wildner OID_AUTO, "cx_lowest", 7695db2f26eSSascha Wildner CTLTYPE_STRING | CTLFLAG_RW, NULL, 0, 770a1116831SSepherosa Ziehau acpi_cst_global_lowest_sysctl, "A", 7711d730338SSepherosa Ziehau "Requested global lowest Cx sleep state"); 77241d9045eSSepherosa Ziehau SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx, 77341d9045eSSepherosa Ziehau SYSCTL_CHILDREN(cpu->glob_sysctl_tree), 7741d730338SSepherosa Ziehau OID_AUTO, "cx_lowest_use", 7751d730338SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, 776a1116831SSepherosa Ziehau acpi_cst_global_lowest_use_sysctl, "A", 7775db2f26eSSascha Wildner "Global lowest Cx sleep state to use"); 7785db2f26eSSascha Wildner } 7795db2f26eSSascha Wildner } 7805db2f26eSSascha Wildner 7815db2f26eSSascha Wildner /* Take over idling from cpu_idle_default(). */ 782a1116831SSepherosa Ziehau acpi_cst_cx_lowest = 0; 783a1116831SSepherosa Ziehau acpi_cst_cx_lowest_req = 0; 784a1116831SSepherosa Ziehau acpi_cst_disable_idle = FALSE; 785e24a50d0SSepherosa Ziehau 786e24a50d0SSepherosa Ziehau cpu_sfence(); 787a1116831SSepherosa Ziehau cpu_idle_hook = acpi_cst_idle; 7885db2f26eSSascha Wildner } 7895db2f26eSSascha Wildner 7905db2f26eSSascha Wildner static void 791a1116831SSepherosa Ziehau acpi_cst_support_list(struct acpi_cst_softc *sc) 7925db2f26eSSascha Wildner { 7935db2f26eSSascha Wildner struct sbuf sb; 7945db2f26eSSascha Wildner int i; 7955db2f26eSSascha Wildner 7965db2f26eSSascha Wildner /* 7975db2f26eSSascha Wildner * Set up the list of Cx states 7985db2f26eSSascha Wildner */ 7994eee58faSSepherosa Ziehau sbuf_new(&sb, sc->cst_cx_supported, sizeof(sc->cst_cx_supported), 8005db2f26eSSascha Wildner SBUF_FIXEDLEN); 8014eee58faSSepherosa Ziehau for (i = 0; i < sc->cst_cx_count; i++) 8024eee58faSSepherosa Ziehau sbuf_printf(&sb, "C%d/%d ", i + 1, sc->cst_cx_states[i].trans_lat); 8035db2f26eSSascha Wildner sbuf_trim(&sb); 8045db2f26eSSascha Wildner sbuf_finish(&sb); 8055db2f26eSSascha Wildner } 8065db2f26eSSascha Wildner 8075db2f26eSSascha Wildner static void 8080e4ac8cfSSepherosa Ziehau acpi_cst_c3_bm_rld_handler(struct cpuhelper_msg *msg) 8098b48ec4dSSepherosa Ziehau { 8108b48ec4dSSepherosa Ziehau 8118b48ec4dSSepherosa Ziehau AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 1); 8120e4ac8cfSSepherosa Ziehau cpuhelper_replymsg(msg, 0); 8138b48ec4dSSepherosa Ziehau } 8148b48ec4dSSepherosa Ziehau 8158b48ec4dSSepherosa Ziehau static void 816a1116831SSepherosa Ziehau acpi_cst_c3_bm_rld(struct acpi_cst_softc *sc) 8178b48ec4dSSepherosa Ziehau { 8180e4ac8cfSSepherosa Ziehau struct cpuhelper_msg msg; 8198b48ec4dSSepherosa Ziehau 8200e4ac8cfSSepherosa Ziehau cpuhelper_initmsg(&msg, &curthread->td_msgport, 8210e4ac8cfSSepherosa Ziehau acpi_cst_c3_bm_rld_handler, sc, MSGF_PRIORITY); 8220e4ac8cfSSepherosa Ziehau cpuhelper_domsg(&msg, sc->cst_cpuid); 8238b48ec4dSSepherosa Ziehau } 8248b48ec4dSSepherosa Ziehau 8258b48ec4dSSepherosa Ziehau static void 826a1116831SSepherosa Ziehau acpi_cst_startup(struct acpi_cst_softc *sc) 8275db2f26eSSascha Wildner { 82841d9045eSSepherosa Ziehau struct acpi_cpu_softc *cpu = sc->cst_parent; 8299925408fSSepherosa Ziehau int i, bm_rld_done = 0; 8308b48ec4dSSepherosa Ziehau 8318b48ec4dSSepherosa Ziehau for (i = 0; i < sc->cst_cx_count; ++i) { 832a1116831SSepherosa Ziehau struct acpi_cst_cx *cx = &sc->cst_cx_states[i]; 8339925408fSSepherosa Ziehau int error; 8348b48ec4dSSepherosa Ziehau 8359925408fSSepherosa Ziehau /* If there are C3(+) states, always enable bus master wakeup */ 8369925408fSSepherosa Ziehau if (cx->type >= ACPI_STATE_C3 && !bm_rld_done && 8379925408fSSepherosa Ziehau (acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) { 838a1116831SSepherosa Ziehau acpi_cst_c3_bm_rld(sc); 8399925408fSSepherosa Ziehau bm_rld_done = 1; 8408b48ec4dSSepherosa Ziehau } 8419925408fSSepherosa Ziehau 8429925408fSSepherosa Ziehau /* Redo the Cx setup, since quirks have been changed */ 8439925408fSSepherosa Ziehau error = acpi_cst_cx_setup(cx); 8449925408fSSepherosa Ziehau if (error) 8459925408fSSepherosa Ziehau panic("C%d startup setup failed: %d", i + 1, error); 8468b48ec4dSSepherosa Ziehau } 8478b48ec4dSSepherosa Ziehau 848a1116831SSepherosa Ziehau acpi_cst_support_list(sc); 8495db2f26eSSascha Wildner 85041d9045eSSepherosa Ziehau SYSCTL_ADD_STRING(&cpu->pcpu_sysctl_ctx, 85141d9045eSSepherosa Ziehau SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree), 8525db2f26eSSascha Wildner OID_AUTO, "cx_supported", CTLFLAG_RD, 8534eee58faSSepherosa Ziehau sc->cst_cx_supported, 0, 8545db2f26eSSascha Wildner "Cx/microsecond values for supported Cx states"); 85541d9045eSSepherosa Ziehau SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx, 85641d9045eSSepherosa Ziehau SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree), 8575db2f26eSSascha Wildner OID_AUTO, "cx_lowest", CTLTYPE_STRING | CTLFLAG_RW, 858a1116831SSepherosa Ziehau (void *)sc, 0, acpi_cst_lowest_sysctl, "A", 8591d730338SSepherosa Ziehau "requested lowest Cx sleep state"); 86041d9045eSSepherosa Ziehau SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx, 86141d9045eSSepherosa Ziehau SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree), 8621d730338SSepherosa Ziehau OID_AUTO, "cx_lowest_use", CTLTYPE_STRING | CTLFLAG_RD, 863a1116831SSepherosa Ziehau (void *)sc, 0, acpi_cst_lowest_use_sysctl, "A", 8645db2f26eSSascha Wildner "lowest Cx sleep state to use"); 86541d9045eSSepherosa Ziehau SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx, 86641d9045eSSepherosa Ziehau SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree), 8675db2f26eSSascha Wildner OID_AUTO, "cx_usage", CTLTYPE_STRING | CTLFLAG_RD, 868a1116831SSepherosa Ziehau (void *)sc, 0, acpi_cst_usage_sysctl, "A", 8695db2f26eSSascha Wildner "percent usage for each Cx state"); 8705db2f26eSSascha Wildner 8715db2f26eSSascha Wildner #ifdef notyet 8725db2f26eSSascha Wildner /* Signal platform that we can handle _CST notification. */ 873a1116831SSepherosa Ziehau if (!acpi_cst_use_fadt && acpi_cst_ctrl != 0) { 8745db2f26eSSascha Wildner ACPI_LOCK(acpi); 875a1116831SSepherosa Ziehau AcpiOsWritePort(acpi_cst_smi_cmd, acpi_cst_ctrl, 8); 8765db2f26eSSascha Wildner ACPI_UNLOCK(acpi); 8775db2f26eSSascha Wildner } 8785db2f26eSSascha Wildner #endif 8795db2f26eSSascha Wildner } 8805db2f26eSSascha Wildner 8815db2f26eSSascha Wildner /* 8825db2f26eSSascha Wildner * Idle the CPU in the lowest state possible. This function is called with 8835db2f26eSSascha Wildner * interrupts disabled. Note that once it re-enables interrupts, a task 8845db2f26eSSascha Wildner * switch can occur so do not access shared data (i.e. the softc) after 8855db2f26eSSascha Wildner * interrupts are re-enabled. 8865db2f26eSSascha Wildner */ 8875db2f26eSSascha Wildner static void 888a1116831SSepherosa Ziehau acpi_cst_idle(void) 8895db2f26eSSascha Wildner { 8904eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 891a1116831SSepherosa Ziehau struct acpi_cst_cx *cx_next; 89219f23194SSepherosa Ziehau union microtime_pcpu start, end; 8939925408fSSepherosa Ziehau int cx_next_idx, i, tdiff, bm_arb_disabled = 0; 8945db2f26eSSascha Wildner 8955db2f26eSSascha Wildner /* If disabled, return immediately. */ 896a1116831SSepherosa Ziehau if (acpi_cst_disable_idle) { 8975db2f26eSSascha Wildner ACPI_ENABLE_IRQS(); 8985db2f26eSSascha Wildner return; 8995db2f26eSSascha Wildner } 9005db2f26eSSascha Wildner 9015db2f26eSSascha Wildner /* 9025db2f26eSSascha Wildner * Look up our CPU id to get our softc. If it's NULL, we'll use C1 903a1116831SSepherosa Ziehau * since there is no Cx state for this processor. 9045db2f26eSSascha Wildner */ 905a1116831SSepherosa Ziehau sc = acpi_cst_softc[mdcpu->mi.gd_cpuid]; 9065db2f26eSSascha Wildner if (sc == NULL) { 907a1116831SSepherosa Ziehau acpi_cst_c1_halt(); 9085db2f26eSSascha Wildner return; 9095db2f26eSSascha Wildner } 9105db2f26eSSascha Wildner 91144806d43SSepherosa Ziehau /* Still probing; use C1 */ 91244806d43SSepherosa Ziehau if (sc->cst_flags & ACPI_CST_FLAG_PROBING) { 913a1116831SSepherosa Ziehau acpi_cst_c1_halt(); 91444806d43SSepherosa Ziehau return; 91544806d43SSepherosa Ziehau } 91644806d43SSepherosa Ziehau 9175db2f26eSSascha Wildner /* Find the lowest state that has small enough latency. */ 9185db2f26eSSascha Wildner cx_next_idx = 0; 9194eee58faSSepherosa Ziehau for (i = sc->cst_cx_lowest; i >= 0; i--) { 9204eee58faSSepherosa Ziehau if (sc->cst_cx_states[i].trans_lat * 3 <= sc->cst_prev_sleep) { 9215db2f26eSSascha Wildner cx_next_idx = i; 9225db2f26eSSascha Wildner break; 9235db2f26eSSascha Wildner } 9245db2f26eSSascha Wildner } 9255db2f26eSSascha Wildner 9265db2f26eSSascha Wildner /* 9279925408fSSepherosa Ziehau * Check for bus master activity if needed for the selected state. 9289925408fSSepherosa Ziehau * If there was activity, clear the bit and use the lowest non-C3 state. 9295db2f26eSSascha Wildner */ 930d1860b0fSSepherosa Ziehau cx_next = &sc->cst_cx_states[cx_next_idx]; 9319925408fSSepherosa Ziehau if (cx_next->flags & ACPI_CST_CX_FLAG_BM_STS) { 9329925408fSSepherosa Ziehau int bm_active; 9339925408fSSepherosa Ziehau 9345db2f26eSSascha Wildner AcpiReadBitRegister(ACPI_BITREG_BUS_MASTER_STATUS, &bm_active); 9355db2f26eSSascha Wildner if (bm_active != 0) { 9365db2f26eSSascha Wildner AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_STATUS, 1); 9377eb26369SSepherosa Ziehau cx_next_idx = sc->cst_non_c3; 9385db2f26eSSascha Wildner } 9395db2f26eSSascha Wildner } 9405db2f26eSSascha Wildner 9415db2f26eSSascha Wildner /* Select the next state and update statistics. */ 9424eee58faSSepherosa Ziehau cx_next = &sc->cst_cx_states[cx_next_idx]; 9434eee58faSSepherosa Ziehau sc->cst_cx_stats[cx_next_idx]++; 944a1116831SSepherosa Ziehau KASSERT(cx_next->type != ACPI_STATE_C0, ("C0 sleep")); 9455db2f26eSSascha Wildner 9465db2f26eSSascha Wildner /* 9475db2f26eSSascha Wildner * Execute HLT (or equivalent) and wait for an interrupt. We can't 9485db2f26eSSascha Wildner * calculate the time spent in C1 since the place we wake up is an 9495db2f26eSSascha Wildner * ISR. Assume we slept half of quantum and return. 9505db2f26eSSascha Wildner */ 9515db2f26eSSascha Wildner if (cx_next->type == ACPI_STATE_C1) { 9524eee58faSSepherosa Ziehau sc->cst_prev_sleep = (sc->cst_prev_sleep * 3 + 500000 / hz) / 4; 95324da862fSSepherosa Ziehau cx_next->enter(cx_next); 9545db2f26eSSascha Wildner return; 9555db2f26eSSascha Wildner } 9565db2f26eSSascha Wildner 9579925408fSSepherosa Ziehau /* Execute the proper preamble before enter the selected state. */ 9589925408fSSepherosa Ziehau if (cx_next->preamble == ACPI_CST_CX_PREAMBLE_BM_ARB) { 9595db2f26eSSascha Wildner AcpiWriteBitRegister(ACPI_BITREG_ARB_DISABLE, 1); 9609925408fSSepherosa Ziehau bm_arb_disabled = 1; 9619925408fSSepherosa Ziehau } else if (cx_next->preamble == ACPI_CST_CX_PREAMBLE_WBINVD) { 9625db2f26eSSascha Wildner ACPI_FLUSH_CPU_CACHE(); 9635db2f26eSSascha Wildner } 9645db2f26eSSascha Wildner 9655db2f26eSSascha Wildner /* 9669925408fSSepherosa Ziehau * Enter the selected state and check time spent asleep. 9675db2f26eSSascha Wildner */ 96819f23194SSepherosa Ziehau microtime_pcpu_get(&start); 96919f23194SSepherosa Ziehau cpu_mfence(); 9705db2f26eSSascha Wildner 97124da862fSSepherosa Ziehau cx_next->enter(cx_next); 97219f23194SSepherosa Ziehau 97319f23194SSepherosa Ziehau cpu_mfence(); 97419f23194SSepherosa Ziehau microtime_pcpu_get(&end); 9755db2f26eSSascha Wildner 9769925408fSSepherosa Ziehau /* Enable bus master arbitration, if it was disabled. */ 9779925408fSSepherosa Ziehau if (bm_arb_disabled) 9785db2f26eSSascha Wildner AcpiWriteBitRegister(ACPI_BITREG_ARB_DISABLE, 0); 9799925408fSSepherosa Ziehau 9805db2f26eSSascha Wildner ACPI_ENABLE_IRQS(); 9815db2f26eSSascha Wildner 9825db2f26eSSascha Wildner /* Find the actual time asleep in microseconds. */ 98319f23194SSepherosa Ziehau tdiff = microtime_pcpu_diff(&start, &end); 98419f23194SSepherosa Ziehau sc->cst_prev_sleep = (sc->cst_prev_sleep * 3 + tdiff) / 4; 9855db2f26eSSascha Wildner } 9865db2f26eSSascha Wildner 9875db2f26eSSascha Wildner /* 9885db2f26eSSascha Wildner * Re-evaluate the _CST object when we are notified that it changed. 9895db2f26eSSascha Wildner */ 9905db2f26eSSascha Wildner static void 991a1116831SSepherosa Ziehau acpi_cst_notify(device_t dev) 9925db2f26eSSascha Wildner { 9934eee58faSSepherosa Ziehau struct acpi_cst_softc *sc = device_get_softc(dev); 9945db2f26eSSascha Wildner 9950e4ac8cfSSepherosa Ziehau cpuhelper_assert(mycpuid, false); 996b45624acSSepherosa Ziehau 997a1116831SSepherosa Ziehau lwkt_serialize_enter(&acpi_cst_slize); 998b45624acSSepherosa Ziehau 9995db2f26eSSascha Wildner /* Update the list of Cx states. */ 1000a1116831SSepherosa Ziehau acpi_cst_cx_reprobe_cst(sc); 1001a1116831SSepherosa Ziehau acpi_cst_support_list(sc); 10025db2f26eSSascha Wildner 10035db2f26eSSascha Wildner /* Update the new lowest useable Cx state for all CPUs. */ 1004a1116831SSepherosa Ziehau acpi_cst_global_cx_count(); 10051d730338SSepherosa Ziehau 10061d730338SSepherosa Ziehau /* 10071d730338SSepherosa Ziehau * Fix up the lowest Cx being used 10081d730338SSepherosa Ziehau */ 1009a1116831SSepherosa Ziehau if (acpi_cst_cx_lowest_req < acpi_cst_cx_count) 1010a1116831SSepherosa Ziehau acpi_cst_cx_lowest = acpi_cst_cx_lowest_req; 1011a1116831SSepherosa Ziehau if (acpi_cst_cx_lowest > acpi_cst_cx_count - 1) 1012a1116831SSepherosa Ziehau acpi_cst_cx_lowest = acpi_cst_cx_count - 1; 10131d730338SSepherosa Ziehau 1014a1116831SSepherosa Ziehau lwkt_serialize_exit(&acpi_cst_slize); 10155db2f26eSSascha Wildner } 10165db2f26eSSascha Wildner 10175db2f26eSSascha Wildner static int 1018a1116831SSepherosa Ziehau acpi_cst_set_quirks(void) 10195db2f26eSSascha Wildner { 10205db2f26eSSascha Wildner device_t acpi_dev; 10215db2f26eSSascha Wildner uint32_t val; 10225db2f26eSSascha Wildner 10235db2f26eSSascha Wildner ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 10245db2f26eSSascha Wildner 10255db2f26eSSascha Wildner /* 10265db2f26eSSascha Wildner * Bus mastering arbitration control is needed to keep caches coherent 10275db2f26eSSascha Wildner * while sleeping in C3. If it's not present but a working flush cache 10285db2f26eSSascha Wildner * instruction is present, flush the caches before entering C3 instead. 10295db2f26eSSascha Wildner * Otherwise, just disable C3 completely. 10305db2f26eSSascha Wildner */ 10315db2f26eSSascha Wildner if (AcpiGbl_FADT.Pm2ControlBlock == 0 || 10325db2f26eSSascha Wildner AcpiGbl_FADT.Pm2ControlLength == 0) { 10335db2f26eSSascha Wildner if ((AcpiGbl_FADT.Flags & ACPI_FADT_WBINVD) && 10345db2f26eSSascha Wildner (AcpiGbl_FADT.Flags & ACPI_FADT_WBINVD_FLUSH) == 0) { 10359925408fSSepherosa Ziehau acpi_cst_quirks |= ACPI_CST_QUIRK_NO_BM; 10365db2f26eSSascha Wildner ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1037a1116831SSepherosa Ziehau "cpu_cst: no BM control, using flush cache method\n")); 10385db2f26eSSascha Wildner } else { 1039a1116831SSepherosa Ziehau acpi_cst_quirks |= ACPI_CST_QUIRK_NO_C3; 10405db2f26eSSascha Wildner ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1041a1116831SSepherosa Ziehau "cpu_cst: no BM control, C3 not available\n")); 10425db2f26eSSascha Wildner } 10435db2f26eSSascha Wildner } 10445db2f26eSSascha Wildner 10455db2f26eSSascha Wildner /* Look for various quirks of the PIIX4 part. */ 10465db2f26eSSascha Wildner acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3); 10475db2f26eSSascha Wildner if (acpi_dev != NULL) { 10485db2f26eSSascha Wildner switch (pci_get_revid(acpi_dev)) { 10495db2f26eSSascha Wildner /* 10505db2f26eSSascha Wildner * Disable C3 support for all PIIX4 chipsets. Some of these parts 10515db2f26eSSascha Wildner * do not report the BMIDE status to the BM status register and 10525db2f26eSSascha Wildner * others have a livelock bug if Type-F DMA is enabled. Linux 10535db2f26eSSascha Wildner * works around the BMIDE bug by reading the BM status directly 10545db2f26eSSascha Wildner * but we take the simpler approach of disabling C3 for these 10555db2f26eSSascha Wildner * parts. 10565db2f26eSSascha Wildner * 10575db2f26eSSascha Wildner * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA 10585db2f26eSSascha Wildner * Livelock") from the January 2002 PIIX4 specification update. 10595db2f26eSSascha Wildner * Applies to all PIIX4 models. 10605db2f26eSSascha Wildner * 10615db2f26eSSascha Wildner * Also, make sure that all interrupts cause a "Stop Break" 10625db2f26eSSascha Wildner * event to exit from C2 state. 10635db2f26eSSascha Wildner * Also, BRLD_EN_BM (ACPI_BITREG_BUS_MASTER_RLD in ACPI-speak) 10645db2f26eSSascha Wildner * should be set to zero, otherwise it causes C2 to short-sleep. 10655db2f26eSSascha Wildner * PIIX4 doesn't properly support C3 and bus master activity 10665db2f26eSSascha Wildner * need not break out of C2. 10675db2f26eSSascha Wildner */ 10685db2f26eSSascha Wildner case PCI_REVISION_A_STEP: 10695db2f26eSSascha Wildner case PCI_REVISION_B_STEP: 10705db2f26eSSascha Wildner case PCI_REVISION_4E: 10715db2f26eSSascha Wildner case PCI_REVISION_4M: 1072a1116831SSepherosa Ziehau acpi_cst_quirks |= ACPI_CST_QUIRK_NO_C3; 10735db2f26eSSascha Wildner ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1074a1116831SSepherosa Ziehau "cpu_cst: working around PIIX4 bug, disabling C3\n")); 10755db2f26eSSascha Wildner 10765db2f26eSSascha Wildner val = pci_read_config(acpi_dev, PIIX4_DEVACTB_REG, 4); 10775db2f26eSSascha Wildner if ((val & PIIX4_STOP_BREAK_MASK) != PIIX4_STOP_BREAK_MASK) { 10785db2f26eSSascha Wildner ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1079a1116831SSepherosa Ziehau "cpu_cst: PIIX4: enabling IRQs to generate Stop Break\n")); 10805db2f26eSSascha Wildner val |= PIIX4_STOP_BREAK_MASK; 10815db2f26eSSascha Wildner pci_write_config(acpi_dev, PIIX4_DEVACTB_REG, val, 4); 10825db2f26eSSascha Wildner } 10835db2f26eSSascha Wildner AcpiReadBitRegister(ACPI_BITREG_BUS_MASTER_RLD, &val); 10845db2f26eSSascha Wildner if (val) { 10855db2f26eSSascha Wildner ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1086a1116831SSepherosa Ziehau "cpu_cst: PIIX4: reset BRLD_EN_BM\n")); 10875db2f26eSSascha Wildner AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 0); 10885db2f26eSSascha Wildner } 10895db2f26eSSascha Wildner break; 10905db2f26eSSascha Wildner default: 10915db2f26eSSascha Wildner break; 10925db2f26eSSascha Wildner } 10935db2f26eSSascha Wildner } 10945db2f26eSSascha Wildner 10955db2f26eSSascha Wildner return (0); 10965db2f26eSSascha Wildner } 10975db2f26eSSascha Wildner 10985db2f26eSSascha Wildner static int 1099a1116831SSepherosa Ziehau acpi_cst_usage_sysctl(SYSCTL_HANDLER_ARGS) 11005db2f26eSSascha Wildner { 11014eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 11025db2f26eSSascha Wildner struct sbuf sb; 11035db2f26eSSascha Wildner char buf[128]; 11045db2f26eSSascha Wildner int i; 11055db2f26eSSascha Wildner uintmax_t fract, sum, whole; 11065db2f26eSSascha Wildner 11074eee58faSSepherosa Ziehau sc = (struct acpi_cst_softc *) arg1; 11085db2f26eSSascha Wildner sum = 0; 11094eee58faSSepherosa Ziehau for (i = 0; i < sc->cst_cx_count; i++) 11104eee58faSSepherosa Ziehau sum += sc->cst_cx_stats[i]; 11115db2f26eSSascha Wildner sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); 11124eee58faSSepherosa Ziehau for (i = 0; i < sc->cst_cx_count; i++) { 11135db2f26eSSascha Wildner if (sum > 0) { 11144eee58faSSepherosa Ziehau whole = (uintmax_t)sc->cst_cx_stats[i] * 100; 11155db2f26eSSascha Wildner fract = (whole % sum) * 100; 11165db2f26eSSascha Wildner sbuf_printf(&sb, "%u.%02u%% ", (u_int)(whole / sum), 11175db2f26eSSascha Wildner (u_int)(fract / sum)); 11185db2f26eSSascha Wildner } else 11195db2f26eSSascha Wildner sbuf_printf(&sb, "0.00%% "); 11205db2f26eSSascha Wildner } 11214eee58faSSepherosa Ziehau sbuf_printf(&sb, "last %dus", sc->cst_prev_sleep); 11225db2f26eSSascha Wildner sbuf_trim(&sb); 11235db2f26eSSascha Wildner sbuf_finish(&sb); 11245db2f26eSSascha Wildner sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 11255db2f26eSSascha Wildner sbuf_delete(&sb); 11265db2f26eSSascha Wildner 11275db2f26eSSascha Wildner return (0); 11285db2f26eSSascha Wildner } 11295db2f26eSSascha Wildner 11305db2f26eSSascha Wildner static int 1131a1116831SSepherosa Ziehau acpi_cst_set_lowest_oncpu(struct acpi_cst_softc *sc, int val) 11325db2f26eSSascha Wildner { 1133de6641b7SSepherosa Ziehau int old_lowest, error = 0, old_lowest_req; 11345db2f26eSSascha Wildner uint32_t old_type, type; 11355db2f26eSSascha Wildner 11364eee58faSSepherosa Ziehau KKASSERT(mycpuid == sc->cst_cpuid); 1137c241507cSSepherosa Ziehau 1138de6641b7SSepherosa Ziehau old_lowest_req = sc->cst_cx_lowest_req; 11394eee58faSSepherosa Ziehau sc->cst_cx_lowest_req = val; 1140de6641b7SSepherosa Ziehau 11414eee58faSSepherosa Ziehau if (val > sc->cst_cx_count - 1) 11424eee58faSSepherosa Ziehau val = sc->cst_cx_count - 1; 11434eee58faSSepherosa Ziehau old_lowest = atomic_swap_int(&sc->cst_cx_lowest, val); 11445db2f26eSSascha Wildner 11454eee58faSSepherosa Ziehau old_type = sc->cst_cx_states[old_lowest].type; 11464eee58faSSepherosa Ziehau type = sc->cst_cx_states[val].type; 1147b42fff25SSepherosa Ziehau if (old_type >= ACPI_STATE_C3 && type < ACPI_STATE_C3) { 1148e80ea409SSepherosa Ziehau cputimer_intr_powersave_remreq(); 1149b42fff25SSepherosa Ziehau } else if (type >= ACPI_STATE_C3 && old_type < ACPI_STATE_C3) { 1150e80ea409SSepherosa Ziehau error = cputimer_intr_powersave_addreq(); 1151e80ea409SSepherosa Ziehau if (error) { 11525db2f26eSSascha Wildner /* Restore */ 1153de6641b7SSepherosa Ziehau sc->cst_cx_lowest_req = old_lowest_req; 11544eee58faSSepherosa Ziehau sc->cst_cx_lowest = old_lowest; 11555db2f26eSSascha Wildner } 11565db2f26eSSascha Wildner } 11575db2f26eSSascha Wildner 11585db2f26eSSascha Wildner if (error) 11595db2f26eSSascha Wildner return error; 11605db2f26eSSascha Wildner 1161febc8c49SSepherosa Ziehau /* Cache the new lowest non-C3 state. */ 1162a1116831SSepherosa Ziehau acpi_cst_non_c3(sc); 11635db2f26eSSascha Wildner 11645db2f26eSSascha Wildner /* Reset the statistics counters. */ 11654eee58faSSepherosa Ziehau bzero(sc->cst_cx_stats, sizeof(sc->cst_cx_stats)); 11665db2f26eSSascha Wildner return (0); 11675db2f26eSSascha Wildner } 11685db2f26eSSascha Wildner 1169c241507cSSepherosa Ziehau static void 11700e4ac8cfSSepherosa Ziehau acpi_cst_set_lowest_handler(struct cpuhelper_msg *msg) 1171c241507cSSepherosa Ziehau { 1172c241507cSSepherosa Ziehau int error; 1173c241507cSSepherosa Ziehau 11740e4ac8cfSSepherosa Ziehau error = acpi_cst_set_lowest_oncpu(msg->ch_cbarg, msg->ch_cbarg1); 11750e4ac8cfSSepherosa Ziehau cpuhelper_replymsg(msg, error); 1176c241507cSSepherosa Ziehau } 1177c241507cSSepherosa Ziehau 1178c241507cSSepherosa Ziehau static int 1179a1116831SSepherosa Ziehau acpi_cst_set_lowest(struct acpi_cst_softc *sc, int val) 1180c241507cSSepherosa Ziehau { 11810e4ac8cfSSepherosa Ziehau struct cpuhelper_msg msg; 1182c241507cSSepherosa Ziehau 11830e4ac8cfSSepherosa Ziehau cpuhelper_initmsg(&msg, &curthread->td_msgport, 11840e4ac8cfSSepherosa Ziehau acpi_cst_set_lowest_handler, sc, MSGF_PRIORITY); 11850e4ac8cfSSepherosa Ziehau msg.ch_cbarg1 = val; 1186c241507cSSepherosa Ziehau 11870e4ac8cfSSepherosa Ziehau return (cpuhelper_domsg(&msg, sc->cst_cpuid)); 1188c241507cSSepherosa Ziehau } 1189c241507cSSepherosa Ziehau 11905db2f26eSSascha Wildner static int 1191a1116831SSepherosa Ziehau acpi_cst_lowest_sysctl(SYSCTL_HANDLER_ARGS) 11925db2f26eSSascha Wildner { 11934eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 11945db2f26eSSascha Wildner char state[8]; 11955db2f26eSSascha Wildner int val, error; 11965db2f26eSSascha Wildner 11974eee58faSSepherosa Ziehau sc = (struct acpi_cst_softc *)arg1; 11984eee58faSSepherosa Ziehau ksnprintf(state, sizeof(state), "C%d", sc->cst_cx_lowest_req + 1); 11995db2f26eSSascha Wildner error = sysctl_handle_string(oidp, state, sizeof(state), req); 12005db2f26eSSascha Wildner if (error != 0 || req->newptr == NULL) 12015db2f26eSSascha Wildner return (error); 12025db2f26eSSascha Wildner if (strlen(state) < 2 || toupper(state[0]) != 'C') 12035db2f26eSSascha Wildner return (EINVAL); 12045db2f26eSSascha Wildner val = (int) strtol(state + 1, NULL, 10) - 1; 12051d730338SSepherosa Ziehau if (val < 0) 12065db2f26eSSascha Wildner return (EINVAL); 12075db2f26eSSascha Wildner 1208a1116831SSepherosa Ziehau lwkt_serialize_enter(&acpi_cst_slize); 1209a1116831SSepherosa Ziehau error = acpi_cst_set_lowest(sc, val); 1210a1116831SSepherosa Ziehau lwkt_serialize_exit(&acpi_cst_slize); 12115db2f26eSSascha Wildner 12125db2f26eSSascha Wildner return error; 12135db2f26eSSascha Wildner } 12145db2f26eSSascha Wildner 12155db2f26eSSascha Wildner static int 1216a1116831SSepherosa Ziehau acpi_cst_lowest_use_sysctl(SYSCTL_HANDLER_ARGS) 12171d730338SSepherosa Ziehau { 12184eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 12191d730338SSepherosa Ziehau char state[8]; 12201d730338SSepherosa Ziehau 12214eee58faSSepherosa Ziehau sc = (struct acpi_cst_softc *)arg1; 12224eee58faSSepherosa Ziehau ksnprintf(state, sizeof(state), "C%d", sc->cst_cx_lowest + 1); 12231d730338SSepherosa Ziehau return sysctl_handle_string(oidp, state, sizeof(state), req); 12241d730338SSepherosa Ziehau } 12251d730338SSepherosa Ziehau 12261d730338SSepherosa Ziehau static int 1227a1116831SSepherosa Ziehau acpi_cst_global_lowest_sysctl(SYSCTL_HANDLER_ARGS) 12285db2f26eSSascha Wildner { 12294eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 12305db2f26eSSascha Wildner char state[8]; 12315db2f26eSSascha Wildner int val, error, i; 12325db2f26eSSascha Wildner 1233a1116831SSepherosa Ziehau ksnprintf(state, sizeof(state), "C%d", acpi_cst_cx_lowest_req + 1); 12345db2f26eSSascha Wildner error = sysctl_handle_string(oidp, state, sizeof(state), req); 12355db2f26eSSascha Wildner if (error != 0 || req->newptr == NULL) 12365db2f26eSSascha Wildner return (error); 12375db2f26eSSascha Wildner if (strlen(state) < 2 || toupper(state[0]) != 'C') 12385db2f26eSSascha Wildner return (EINVAL); 12395db2f26eSSascha Wildner val = (int) strtol(state + 1, NULL, 10) - 1; 12401d730338SSepherosa Ziehau if (val < 0) 12415db2f26eSSascha Wildner return (EINVAL); 12421d730338SSepherosa Ziehau 1243a1116831SSepherosa Ziehau lwkt_serialize_enter(&acpi_cst_slize); 1244b45624acSSepherosa Ziehau 1245a1116831SSepherosa Ziehau acpi_cst_cx_lowest_req = val; 1246a1116831SSepherosa Ziehau acpi_cst_cx_lowest = val; 1247a1116831SSepherosa Ziehau if (acpi_cst_cx_lowest > acpi_cst_cx_count - 1) 1248a1116831SSepherosa Ziehau acpi_cst_cx_lowest = acpi_cst_cx_count - 1; 12495db2f26eSSascha Wildner 12505db2f26eSSascha Wildner /* Update the new lowest useable Cx state for all CPUs. */ 1251a1116831SSepherosa Ziehau for (i = 0; i < acpi_cst_ndevices; i++) { 1252a1116831SSepherosa Ziehau sc = device_get_softc(acpi_cst_devices[i]); 1253a1116831SSepherosa Ziehau error = acpi_cst_set_lowest(sc, val); 12545db2f26eSSascha Wildner if (error) { 12555db2f26eSSascha Wildner KKASSERT(i == 0); 12565db2f26eSSascha Wildner break; 12575db2f26eSSascha Wildner } 12585db2f26eSSascha Wildner } 1259b45624acSSepherosa Ziehau 1260a1116831SSepherosa Ziehau lwkt_serialize_exit(&acpi_cst_slize); 12615db2f26eSSascha Wildner 12625db2f26eSSascha Wildner return error; 12635db2f26eSSascha Wildner } 12645db2f26eSSascha Wildner 12651d730338SSepherosa Ziehau static int 1266a1116831SSepherosa Ziehau acpi_cst_global_lowest_use_sysctl(SYSCTL_HANDLER_ARGS) 12671d730338SSepherosa Ziehau { 12681d730338SSepherosa Ziehau char state[8]; 12691d730338SSepherosa Ziehau 1270a1116831SSepherosa Ziehau ksnprintf(state, sizeof(state), "C%d", acpi_cst_cx_lowest + 1); 12711d730338SSepherosa Ziehau return sysctl_handle_string(oidp, state, sizeof(state), req); 12721d730338SSepherosa Ziehau } 12731d730338SSepherosa Ziehau 12745db2f26eSSascha Wildner /* 12755db2f26eSSascha Wildner * Put the CPU in C1 in a machine-dependant way. 12765db2f26eSSascha Wildner * XXX: shouldn't be here! 12775db2f26eSSascha Wildner */ 12785db2f26eSSascha Wildner static void 1279a1116831SSepherosa Ziehau acpi_cst_c1_halt(void) 12805db2f26eSSascha Wildner { 12815db2f26eSSascha Wildner splz(); 12825db2f26eSSascha Wildner if ((mycpu->gd_reqflags & RQF_IDLECHECK_WK_MASK) == 0) 12835db2f26eSSascha Wildner __asm __volatile("sti; hlt"); 12845db2f26eSSascha Wildner else 12855db2f26eSSascha Wildner __asm __volatile("sti; pause"); 12865db2f26eSSascha Wildner } 1287febc8c49SSepherosa Ziehau 1288febc8c49SSepherosa Ziehau static void 1289a1116831SSepherosa Ziehau acpi_cst_non_c3(struct acpi_cst_softc *sc) 1290febc8c49SSepherosa Ziehau { 1291febc8c49SSepherosa Ziehau int i; 1292febc8c49SSepherosa Ziehau 12934eee58faSSepherosa Ziehau sc->cst_non_c3 = 0; 12944eee58faSSepherosa Ziehau for (i = sc->cst_cx_lowest; i >= 0; i--) { 12954eee58faSSepherosa Ziehau if (sc->cst_cx_states[i].type < ACPI_STATE_C3) { 12964eee58faSSepherosa Ziehau sc->cst_non_c3 = i; 1297febc8c49SSepherosa Ziehau break; 1298febc8c49SSepherosa Ziehau } 1299febc8c49SSepherosa Ziehau } 1300febc8c49SSepherosa Ziehau if (bootverbose) 13014eee58faSSepherosa Ziehau device_printf(sc->cst_dev, "non-C3 %d\n", sc->cst_non_c3); 1302febc8c49SSepherosa Ziehau } 13034cf48621SSepherosa Ziehau 13044cf48621SSepherosa Ziehau /* 1305a1116831SSepherosa Ziehau * Update the largest Cx state supported in the global acpi_cst_cx_count. 13064cf48621SSepherosa Ziehau * It will be used in the global Cx sysctl handler. 13074cf48621SSepherosa Ziehau */ 13084cf48621SSepherosa Ziehau static void 1309a1116831SSepherosa Ziehau acpi_cst_global_cx_count(void) 13104cf48621SSepherosa Ziehau { 13114eee58faSSepherosa Ziehau struct acpi_cst_softc *sc; 13124cf48621SSepherosa Ziehau int i; 13134cf48621SSepherosa Ziehau 1314a1116831SSepherosa Ziehau if (acpi_cst_ndevices == 0) { 1315a1116831SSepherosa Ziehau acpi_cst_cx_count = 0; 13164cf48621SSepherosa Ziehau return; 13174cf48621SSepherosa Ziehau } 13184cf48621SSepherosa Ziehau 1319a1116831SSepherosa Ziehau sc = device_get_softc(acpi_cst_devices[0]); 1320a1116831SSepherosa Ziehau acpi_cst_cx_count = sc->cst_cx_count; 13214cf48621SSepherosa Ziehau 1322a1116831SSepherosa Ziehau for (i = 1; i < acpi_cst_ndevices; i++) { 1323a1116831SSepherosa Ziehau struct acpi_cst_softc *sc = device_get_softc(acpi_cst_devices[i]); 13244cf48621SSepherosa Ziehau 1325a1116831SSepherosa Ziehau if (sc->cst_cx_count < acpi_cst_cx_count) 1326a1116831SSepherosa Ziehau acpi_cst_cx_count = sc->cst_cx_count; 13274cf48621SSepherosa Ziehau } 13284cf48621SSepherosa Ziehau if (bootverbose) 1329a1116831SSepherosa Ziehau kprintf("cpu_cst: global Cx count %d\n", acpi_cst_cx_count); 13304cf48621SSepherosa Ziehau } 133124da862fSSepherosa Ziehau 133224da862fSSepherosa Ziehau static void 133324da862fSSepherosa Ziehau acpi_cst_c1_halt_enter(const struct acpi_cst_cx *cx __unused) 133424da862fSSepherosa Ziehau { 133524da862fSSepherosa Ziehau acpi_cst_c1_halt(); 133624da862fSSepherosa Ziehau } 133724da862fSSepherosa Ziehau 133824da862fSSepherosa Ziehau static void 133924da862fSSepherosa Ziehau acpi_cst_cx_io_enter(const struct acpi_cst_cx *cx) 134024da862fSSepherosa Ziehau { 134124da862fSSepherosa Ziehau uint64_t dummy; 134224da862fSSepherosa Ziehau 13439925408fSSepherosa Ziehau /* 13449925408fSSepherosa Ziehau * Read I/O to enter this Cx state 13459925408fSSepherosa Ziehau */ 134624da862fSSepherosa Ziehau bus_space_read_1(cx->btag, cx->bhand, 0); 134724da862fSSepherosa Ziehau /* 134824da862fSSepherosa Ziehau * Perform a dummy I/O read. Since it may take an arbitrary time 134924da862fSSepherosa Ziehau * to enter the idle state, this read makes sure that we are frozen. 135024da862fSSepherosa Ziehau */ 135124da862fSSepherosa Ziehau AcpiRead(&dummy, &AcpiGbl_FADT.XPmTimerBlock); 135224da862fSSepherosa Ziehau } 13539925408fSSepherosa Ziehau 13549925408fSSepherosa Ziehau static int 13559925408fSSepherosa Ziehau acpi_cst_cx_setup(struct acpi_cst_cx *cx) 13569925408fSSepherosa Ziehau { 13579925408fSSepherosa Ziehau cx->flags &= ~ACPI_CST_CX_FLAG_BM_STS; 13589925408fSSepherosa Ziehau cx->preamble = ACPI_CST_CX_PREAMBLE_NONE; 13599925408fSSepherosa Ziehau 13609925408fSSepherosa Ziehau if (cx->type >= ACPI_STATE_C3) { 13619925408fSSepherosa Ziehau /* 13629925408fSSepherosa Ziehau * Set the required operations for entering C3(+) state. 13639925408fSSepherosa Ziehau * Later acpi_cst_md_cx_setup() may fix them up. 13649925408fSSepherosa Ziehau */ 13659925408fSSepherosa Ziehau 13669925408fSSepherosa Ziehau /* 13679925408fSSepherosa Ziehau * Always check BM_STS. 13689925408fSSepherosa Ziehau */ 13699925408fSSepherosa Ziehau if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) 13709925408fSSepherosa Ziehau cx->flags |= ACPI_CST_CX_FLAG_BM_STS; 13719925408fSSepherosa Ziehau 13729925408fSSepherosa Ziehau /* 13739925408fSSepherosa Ziehau * According to the ACPI specification, bus master arbitration 13749925408fSSepherosa Ziehau * is only available on UP system. For MP system, cache flushing 13759925408fSSepherosa Ziehau * is required. 13769925408fSSepherosa Ziehau */ 13779925408fSSepherosa Ziehau if (ncpus == 1 && (acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) 13789925408fSSepherosa Ziehau cx->preamble = ACPI_CST_CX_PREAMBLE_BM_ARB; 13799925408fSSepherosa Ziehau else 13809925408fSSepherosa Ziehau cx->preamble = ACPI_CST_CX_PREAMBLE_WBINVD; 13819925408fSSepherosa Ziehau } 13829925408fSSepherosa Ziehau return acpi_cst_md_cx_setup(cx); 13839925408fSSepherosa Ziehau } 138418862f87SSepherosa Ziehau 138518862f87SSepherosa Ziehau static void 138618862f87SSepherosa Ziehau acpi_cst_free_resource(struct acpi_cst_softc *sc, int start) 138718862f87SSepherosa Ziehau { 138818862f87SSepherosa Ziehau int i; 138918862f87SSepherosa Ziehau 139018862f87SSepherosa Ziehau for (i = start; i < MAX_CX_STATES; ++i) { 139118862f87SSepherosa Ziehau struct acpi_cst_cx *cx = &sc->cst_cx_states[i]; 139218862f87SSepherosa Ziehau 139318862f87SSepherosa Ziehau if (cx->res != NULL) 139418862f87SSepherosa Ziehau bus_release_resource(sc->cst_dev, cx->res_type, cx->rid, cx->res); 139518862f87SSepherosa Ziehau memset(cx, 0, sizeof(*cx)); 139618862f87SSepherosa Ziehau } 139718862f87SSepherosa Ziehau } 1398