xref: /dragonfly/sys/dev/acpica/acpi_cpu_cstate.c (revision fcf6efef)
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>
40b45624acSSepherosa Ziehau #include <sys/serialize.h>
41c241507cSSepherosa Ziehau #include <sys/msgport2.h>
4219f23194SSepherosa Ziehau #include <sys/microtime_pcpu.h>
43daa63909SSepherosa Ziehau #include <sys/cpu_topology.h>
445db2f26eSSascha Wildner 
455db2f26eSSascha Wildner #include <bus/pci/pcivar.h>
465db2f26eSSascha Wildner #include <machine/atomic.h>
475db2f26eSSascha Wildner #include <machine/globaldata.h>
485db2f26eSSascha Wildner #include <machine/md_var.h>
495db2f26eSSascha Wildner #include <machine/smp.h>
505db2f26eSSascha Wildner #include <sys/rman.h>
515db2f26eSSascha Wildner 
525db2f26eSSascha Wildner #include "acpi.h"
535db2f26eSSascha Wildner #include "acpivar.h"
545db2f26eSSascha Wildner #include "acpi_cpu.h"
559925408fSSepherosa Ziehau #include "acpi_cpu_cstate.h"
565db2f26eSSascha Wildner 
575db2f26eSSascha Wildner /*
58a1116831SSepherosa Ziehau  * Support for ACPI Processor devices, including C[1-3+] sleep states.
595db2f26eSSascha Wildner  */
605db2f26eSSascha Wildner 
615db2f26eSSascha Wildner /* Hooks for the ACPICA debugging infrastructure */
625db2f26eSSascha Wildner #define _COMPONENT	ACPI_PROCESSOR
635db2f26eSSascha Wildner ACPI_MODULE_NAME("PROCESSOR")
645db2f26eSSascha Wildner 
655db2f26eSSascha Wildner #define MAX_CX_STATES	 8
665db2f26eSSascha Wildner 
674eee58faSSepherosa Ziehau struct acpi_cst_softc {
684eee58faSSepherosa Ziehau     device_t		cst_dev;
6941d9045eSSepherosa Ziehau     struct acpi_cpu_softc *cst_parent;
704eee58faSSepherosa Ziehau     ACPI_HANDLE		cst_handle;
714eee58faSSepherosa Ziehau     int			cst_cpuid;
7244806d43SSepherosa Ziehau     uint32_t		cst_flags;	/* ACPI_CST_FLAG_ */
734eee58faSSepherosa Ziehau     uint32_t		cst_p_blk;	/* ACPI P_BLK location */
744eee58faSSepherosa Ziehau     uint32_t		cst_p_blk_len;	/* P_BLK length (must be 6). */
75a1116831SSepherosa Ziehau     struct acpi_cst_cx	cst_cx_states[MAX_CX_STATES];
764eee58faSSepherosa Ziehau     int			cst_cx_count;	/* Number of valid Cx states. */
774eee58faSSepherosa Ziehau     int			cst_prev_sleep;	/* Last idle sleep duration. */
785db2f26eSSascha Wildner     /* Runtime state. */
794eee58faSSepherosa Ziehau     int			cst_non_c3;	/* Index of lowest non-C3 state. */
804eee58faSSepherosa Ziehau     u_long		cst_cx_stats[MAX_CX_STATES];/* Cx usage history. */
815db2f26eSSascha Wildner     /* Values for sysctl. */
824eee58faSSepherosa Ziehau     int			cst_cx_lowest;	/* Current Cx lowest */
834eee58faSSepherosa Ziehau     int			cst_cx_lowest_req; /* Requested Cx lowest */
844eee58faSSepherosa Ziehau     char 		cst_cx_supported[64];
855db2f26eSSascha Wildner };
865db2f26eSSascha Wildner 
8744806d43SSepherosa Ziehau #define ACPI_CST_FLAG_PROBING	0x1
88daa63909SSepherosa Ziehau #define ACPI_CST_FLAG_ATTACHED	0x2
89daa63909SSepherosa Ziehau /* Match C-states of other hyperthreads on the same core */
90daa63909SSepherosa Ziehau #define ACPI_CST_FLAG_MATCH_HT	0x4
9144806d43SSepherosa Ziehau 
925db2f26eSSascha Wildner #define PCI_VENDOR_INTEL	0x8086
935db2f26eSSascha Wildner #define PCI_DEVICE_82371AB_3	0x7113	/* PIIX4 chipset for quirks. */
945db2f26eSSascha Wildner #define PCI_REVISION_A_STEP	0
955db2f26eSSascha Wildner #define PCI_REVISION_B_STEP	1
965db2f26eSSascha Wildner #define PCI_REVISION_4E		2
975db2f26eSSascha Wildner #define PCI_REVISION_4M		3
985db2f26eSSascha Wildner #define PIIX4_DEVACTB_REG	0x58
995db2f26eSSascha Wildner #define PIIX4_BRLD_EN_IRQ0	(1<<0)
1005db2f26eSSascha Wildner #define PIIX4_BRLD_EN_IRQ	(1<<1)
1015db2f26eSSascha Wildner #define PIIX4_BRLD_EN_IRQ8	(1<<5)
102a1116831SSepherosa Ziehau #define PIIX4_STOP_BREAK_MASK	(PIIX4_BRLD_EN_IRQ0 | \
103a1116831SSepherosa Ziehau 				 PIIX4_BRLD_EN_IRQ | \
104a1116831SSepherosa Ziehau 				 PIIX4_BRLD_EN_IRQ8)
1055db2f26eSSascha Wildner #define PIIX4_PCNTRL_BST_EN	(1<<10)
1065db2f26eSSascha Wildner 
1075db2f26eSSascha Wildner /* Platform hardware resource information. */
108a1116831SSepherosa Ziehau static uint32_t		 acpi_cst_smi_cmd; /* Value to write to SMI_CMD. */
109a1116831SSepherosa Ziehau static uint8_t		 acpi_cst_ctrl;	/* Indicate we are _CST aware. */
1109925408fSSepherosa Ziehau int		 	 acpi_cst_quirks; /* Indicate any hardware bugs. */
111a1116831SSepherosa Ziehau static boolean_t	 acpi_cst_use_fadt;
1125db2f26eSSascha Wildner 
1135db2f26eSSascha Wildner /* Runtime state. */
11448272d39SSepherosa Ziehau static boolean_t	 acpi_cst_disable_idle;
115a1116831SSepherosa Ziehau 					/* Disable entry to idle function */
116a1116831SSepherosa Ziehau static int		 acpi_cst_cx_count; /* Number of valid Cx states */
1175db2f26eSSascha Wildner 
1185db2f26eSSascha Wildner /* Values for sysctl. */
119a1116831SSepherosa Ziehau static int		 acpi_cst_cx_lowest; /* Current Cx lowest */
120a1116831SSepherosa Ziehau static int		 acpi_cst_cx_lowest_req; /* Requested Cx lowest */
1215db2f26eSSascha Wildner 
122a1116831SSepherosa Ziehau static device_t		*acpi_cst_devices;
123a1116831SSepherosa Ziehau static int		 acpi_cst_ndevices;
124a1116831SSepherosa Ziehau static struct acpi_cst_softc **acpi_cst_softc;
125a1116831SSepherosa Ziehau static struct lwkt_serialize acpi_cst_slize = LWKT_SERIALIZE_INITIALIZER;
1265db2f26eSSascha Wildner 
127a1116831SSepherosa Ziehau static int	acpi_cst_probe(device_t);
128a1116831SSepherosa Ziehau static int	acpi_cst_attach(device_t);
129a1116831SSepherosa Ziehau static int	acpi_cst_suspend(device_t);
130a1116831SSepherosa Ziehau static int	acpi_cst_resume(device_t);
131a1116831SSepherosa Ziehau static int	acpi_cst_shutdown(device_t);
132ac13872aSSepherosa Ziehau 
133a1116831SSepherosa Ziehau static void	acpi_cst_notify(device_t);
134a1116831SSepherosa Ziehau static void	acpi_cst_postattach(void *);
135a1116831SSepherosa Ziehau static void	acpi_cst_idle(void);
136daa63909SSepherosa Ziehau static void	acpi_cst_copy(struct acpi_cst_softc *,
137daa63909SSepherosa Ziehau 		    const struct acpi_cst_softc *);
1385db2f26eSSascha Wildner 
139a1116831SSepherosa Ziehau static void	acpi_cst_cx_probe(struct acpi_cst_softc *);
140a1116831SSepherosa Ziehau static void	acpi_cst_cx_probe_fadt(struct acpi_cst_softc *);
141a1116831SSepherosa Ziehau static int	acpi_cst_cx_probe_cst(struct acpi_cst_softc *, int);
142a1116831SSepherosa Ziehau static int	acpi_cst_cx_reprobe_cst(struct acpi_cst_softc *);
143a1116831SSepherosa Ziehau 
144a1116831SSepherosa Ziehau static void	acpi_cst_startup(struct acpi_cst_softc *);
145a1116831SSepherosa Ziehau static void	acpi_cst_support_list(struct acpi_cst_softc *);
146a1116831SSepherosa Ziehau static int	acpi_cst_set_lowest(struct acpi_cst_softc *, int);
147a1116831SSepherosa Ziehau static int	acpi_cst_set_lowest_oncpu(struct acpi_cst_softc *, int);
148a1116831SSepherosa Ziehau static void	acpi_cst_non_c3(struct acpi_cst_softc *);
149a1116831SSepherosa Ziehau static void	acpi_cst_global_cx_count(void);
150a1116831SSepherosa Ziehau static int	acpi_cst_set_quirks(void);
151a1116831SSepherosa Ziehau static void	acpi_cst_c3_bm_rld(struct acpi_cst_softc *);
15218862f87SSepherosa Ziehau static void	acpi_cst_free_resource(struct acpi_cst_softc *, int);
15324da862fSSepherosa Ziehau static void	acpi_cst_c1_halt(void);
154a1116831SSepherosa Ziehau 
155a1116831SSepherosa Ziehau static int	acpi_cst_usage_sysctl(SYSCTL_HANDLER_ARGS);
156a1116831SSepherosa Ziehau static int	acpi_cst_lowest_sysctl(SYSCTL_HANDLER_ARGS);
157a1116831SSepherosa Ziehau static int	acpi_cst_lowest_use_sysctl(SYSCTL_HANDLER_ARGS);
158a1116831SSepherosa Ziehau static int	acpi_cst_global_lowest_sysctl(SYSCTL_HANDLER_ARGS);
159a1116831SSepherosa Ziehau static int	acpi_cst_global_lowest_use_sysctl(SYSCTL_HANDLER_ARGS);
1605db2f26eSSascha Wildner 
1619925408fSSepherosa Ziehau static int	acpi_cst_cx_setup(struct acpi_cst_cx *cx);
16224da862fSSepherosa Ziehau static void	acpi_cst_c1_halt_enter(const struct acpi_cst_cx *);
16324da862fSSepherosa Ziehau static void	acpi_cst_cx_io_enter(const struct acpi_cst_cx *);
16424da862fSSepherosa Ziehau 
16590a26aa2SSepherosa Ziehau int		acpi_cst_force_bmarb;
16690a26aa2SSepherosa Ziehau TUNABLE_INT("hw.acpi.cpu.cst.force_bmarb", &acpi_cst_force_bmarb);
16790a26aa2SSepherosa Ziehau 
16890a26aa2SSepherosa Ziehau int		acpi_cst_force_bmsts;
16990a26aa2SSepherosa Ziehau TUNABLE_INT("hw.acpi.cpu.cst.force_bmsts", &acpi_cst_force_bmsts);
17090a26aa2SSepherosa Ziehau 
17141e658a2SSepherosa Ziehau static device_method_t acpi_cst_methods[] = {
1725db2f26eSSascha Wildner     /* Device interface */
17392c9201cSSepherosa Ziehau     DEVMETHOD(device_probe,	acpi_cst_probe),
17492c9201cSSepherosa Ziehau     DEVMETHOD(device_attach,	acpi_cst_attach),
1755db2f26eSSascha Wildner     DEVMETHOD(device_detach,	bus_generic_detach),
17692c9201cSSepherosa Ziehau     DEVMETHOD(device_shutdown,	acpi_cst_shutdown),
17792c9201cSSepherosa Ziehau     DEVMETHOD(device_suspend,	acpi_cst_suspend),
17892c9201cSSepherosa Ziehau     DEVMETHOD(device_resume,	acpi_cst_resume),
1795db2f26eSSascha Wildner 
1805db2f26eSSascha Wildner     /* Bus interface */
181ac13872aSSepherosa Ziehau     DEVMETHOD(bus_add_child,	bus_generic_add_child),
182ac13872aSSepherosa Ziehau     DEVMETHOD(bus_read_ivar,	bus_generic_read_ivar),
183ac13872aSSepherosa Ziehau     DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list),
1845db2f26eSSascha Wildner     DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
1855db2f26eSSascha Wildner     DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
1865db2f26eSSascha Wildner     DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
1875db2f26eSSascha Wildner     DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
1885db2f26eSSascha Wildner     DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
1895db2f26eSSascha Wildner     DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
1905db2f26eSSascha Wildner     DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
1915db2f26eSSascha Wildner     DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
1925db2f26eSSascha Wildner     DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
193d3c9c58eSSascha Wildner     DEVMETHOD_END
1945db2f26eSSascha Wildner };
1955db2f26eSSascha Wildner 
19641e658a2SSepherosa Ziehau static driver_t acpi_cst_driver = {
1975db2f26eSSascha Wildner     "cpu_cst",
19841e658a2SSepherosa Ziehau     acpi_cst_methods,
1994eee58faSSepherosa Ziehau     sizeof(struct acpi_cst_softc),
200df21e16dSImre Vadász     .gpri = KOBJ_GPRI_ACPI+2
2015db2f26eSSascha Wildner };
2025db2f26eSSascha Wildner 
20341e658a2SSepherosa Ziehau static devclass_t acpi_cst_devclass;
20441e658a2SSepherosa Ziehau DRIVER_MODULE(cpu_cst, cpu, acpi_cst_driver, acpi_cst_devclass, NULL, NULL);
2055db2f26eSSascha Wildner MODULE_DEPEND(cpu_cst, acpi, 1, 1, 1);
2065db2f26eSSascha Wildner 
2075db2f26eSSascha Wildner static int
acpi_cst_probe(device_t dev)20892c9201cSSepherosa Ziehau acpi_cst_probe(device_t dev)
2095db2f26eSSascha Wildner {
2105db2f26eSSascha Wildner     int cpu_id;
2115db2f26eSSascha Wildner 
2125db2f26eSSascha Wildner     if (acpi_disabled("cpu_cst") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
2135db2f26eSSascha Wildner 	return (ENXIO);
2145db2f26eSSascha Wildner 
2155db2f26eSSascha Wildner     cpu_id = acpi_get_magic(dev);
2165db2f26eSSascha Wildner 
217a1116831SSepherosa Ziehau     if (acpi_cst_softc == NULL)
218a1116831SSepherosa Ziehau 	acpi_cst_softc = kmalloc(sizeof(struct acpi_cst_softc *) *
2195db2f26eSSascha Wildner 	    SMP_MAXCPU, M_TEMP /* XXX */, M_INTWAIT | M_ZERO);
2205db2f26eSSascha Wildner 
2215db2f26eSSascha Wildner     /*
2225db2f26eSSascha Wildner      * Check if we already probed this processor.  We scan the bus twice
2235db2f26eSSascha Wildner      * so it's possible we've already seen this one.
2245db2f26eSSascha Wildner      */
225a1116831SSepherosa Ziehau     if (acpi_cst_softc[cpu_id] != NULL) {
2265db2f26eSSascha Wildner 	device_printf(dev, "CPU%d cstate already exist\n", cpu_id);
2275db2f26eSSascha Wildner 	return (ENXIO);
2285db2f26eSSascha Wildner     }
2295db2f26eSSascha Wildner 
2305db2f26eSSascha Wildner     /* Mark this processor as in-use and save our derived id for attach. */
23102bba4e7SSepherosa Ziehau     acpi_cst_softc[cpu_id] = device_get_softc(dev);
2325db2f26eSSascha Wildner     device_set_desc(dev, "ACPI CPU C-State");
2335db2f26eSSascha Wildner 
2345db2f26eSSascha Wildner     return (0);
2355db2f26eSSascha Wildner }
2365db2f26eSSascha Wildner 
2375db2f26eSSascha Wildner static int
acpi_cst_attach(device_t dev)23892c9201cSSepherosa Ziehau acpi_cst_attach(device_t dev)
2395db2f26eSSascha Wildner {
2405db2f26eSSascha Wildner     ACPI_BUFFER		   buf;
2415db2f26eSSascha Wildner     ACPI_OBJECT		   *obj;
2424eee58faSSepherosa Ziehau     struct acpi_cst_softc *sc;
2435db2f26eSSascha Wildner     ACPI_STATUS		   status;
2445db2f26eSSascha Wildner 
2455db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
2465db2f26eSSascha Wildner 
2475db2f26eSSascha Wildner     sc = device_get_softc(dev);
2484eee58faSSepherosa Ziehau     sc->cst_dev = dev;
2494eee58faSSepherosa Ziehau     sc->cst_parent = device_get_softc(device_get_parent(dev));
2504eee58faSSepherosa Ziehau     sc->cst_handle = acpi_get_handle(dev);
2514eee58faSSepherosa Ziehau     sc->cst_cpuid = acpi_get_magic(dev);
252a1116831SSepherosa Ziehau     acpi_cst_softc[sc->cst_cpuid] = sc;
253a1116831SSepherosa Ziehau     acpi_cst_smi_cmd = AcpiGbl_FADT.SmiCommand;
254a1116831SSepherosa Ziehau     acpi_cst_ctrl = AcpiGbl_FADT.CstControl;
2555db2f26eSSascha Wildner 
2565db2f26eSSascha Wildner     buf.Pointer = NULL;
2575db2f26eSSascha Wildner     buf.Length = ACPI_ALLOCATE_BUFFER;
2584eee58faSSepherosa Ziehau     status = AcpiEvaluateObject(sc->cst_handle, NULL, NULL, &buf);
2595db2f26eSSascha Wildner     if (ACPI_FAILURE(status)) {
2605db2f26eSSascha Wildner 	device_printf(dev, "attach failed to get Processor obj - %s\n",
2615db2f26eSSascha Wildner 		      AcpiFormatException(status));
26202bba4e7SSepherosa Ziehau 	acpi_cst_softc[sc->cst_cpuid] = NULL;
2635db2f26eSSascha Wildner 	return (ENXIO);
2645db2f26eSSascha Wildner     }
2655db2f26eSSascha Wildner     obj = (ACPI_OBJECT *)buf.Pointer;
2664eee58faSSepherosa Ziehau     sc->cst_p_blk = obj->Processor.PblkAddress;
2674eee58faSSepherosa Ziehau     sc->cst_p_blk_len = obj->Processor.PblkLength;
2685db2f26eSSascha Wildner     AcpiOsFree(obj);
269a1116831SSepherosa Ziehau     ACPI_DEBUG_PRINT((ACPI_DB_INFO, "cpu_cst%d: P_BLK at %#x/%d\n",
2704eee58faSSepherosa Ziehau 		     device_get_unit(dev), sc->cst_p_blk, sc->cst_p_blk_len));
2715db2f26eSSascha Wildner 
2725db2f26eSSascha Wildner     /*
2735db2f26eSSascha Wildner      * If this is the first cpu we attach, create and initialize the generic
2745db2f26eSSascha Wildner      * resources that will be used by all acpi cpu devices.
2755db2f26eSSascha Wildner      */
2765db2f26eSSascha Wildner     if (device_get_unit(dev) == 0) {
277a1116831SSepherosa Ziehau 	/* Assume we won't be using FADT for Cx states by default */
278a1116831SSepherosa Ziehau 	acpi_cst_use_fadt = FALSE;
2795db2f26eSSascha Wildner 
2805db2f26eSSascha Wildner 	/* Queue post cpu-probing task handler */
281a1116831SSepherosa Ziehau 	AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cst_postattach, NULL);
2825db2f26eSSascha Wildner     }
2835db2f26eSSascha Wildner 
2845db2f26eSSascha Wildner     /* Probe for Cx state support. */
285a1116831SSepherosa Ziehau     acpi_cst_cx_probe(sc);
2865db2f26eSSascha Wildner 
287daa63909SSepherosa Ziehau     sc->cst_flags |= ACPI_CST_FLAG_ATTACHED;
288daa63909SSepherosa Ziehau 
2895db2f26eSSascha Wildner     return (0);
2905db2f26eSSascha Wildner }
2915db2f26eSSascha Wildner 
2925db2f26eSSascha Wildner /*
2935db2f26eSSascha Wildner  * Disable any entry to the idle function during suspend and re-enable it
2945db2f26eSSascha Wildner  * during resume.
2955db2f26eSSascha Wildner  */
2965db2f26eSSascha Wildner static int
acpi_cst_suspend(device_t dev)29792c9201cSSepherosa Ziehau acpi_cst_suspend(device_t dev)
2985db2f26eSSascha Wildner {
2995db2f26eSSascha Wildner     int error;
3005db2f26eSSascha Wildner 
3015db2f26eSSascha Wildner     error = bus_generic_suspend(dev);
3025db2f26eSSascha Wildner     if (error)
3035db2f26eSSascha Wildner 	return (error);
304a1116831SSepherosa Ziehau     acpi_cst_disable_idle = TRUE;
3055db2f26eSSascha Wildner     return (0);
3065db2f26eSSascha Wildner }
3075db2f26eSSascha Wildner 
3085db2f26eSSascha Wildner static int
acpi_cst_resume(device_t dev)30992c9201cSSepherosa Ziehau acpi_cst_resume(device_t dev)
3105db2f26eSSascha Wildner {
311a1116831SSepherosa Ziehau     acpi_cst_disable_idle = FALSE;
3125db2f26eSSascha Wildner     return (bus_generic_resume(dev));
3135db2f26eSSascha Wildner }
3145db2f26eSSascha Wildner 
3155db2f26eSSascha Wildner static int
acpi_cst_shutdown(device_t dev)31692c9201cSSepherosa Ziehau acpi_cst_shutdown(device_t dev)
3175db2f26eSSascha Wildner {
3185db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
3195db2f26eSSascha Wildner 
3205db2f26eSSascha Wildner     /* Allow children to shutdown first. */
3215db2f26eSSascha Wildner     bus_generic_shutdown(dev);
3225db2f26eSSascha Wildner 
3235db2f26eSSascha Wildner     /*
3245db2f26eSSascha Wildner      * Disable any entry to the idle function.  There is a small race where
3255db2f26eSSascha Wildner      * an idle thread have passed this check but not gone to sleep.  This
3265db2f26eSSascha Wildner      * is ok since device_shutdown() does not free the softc, otherwise
3275db2f26eSSascha Wildner      * we'd have to be sure all threads were evicted before returning.
3285db2f26eSSascha Wildner      */
329a1116831SSepherosa Ziehau     acpi_cst_disable_idle = TRUE;
3305db2f26eSSascha Wildner 
3315db2f26eSSascha Wildner     return_VALUE (0);
3325db2f26eSSascha Wildner }
3335db2f26eSSascha Wildner 
3345db2f26eSSascha Wildner static void
acpi_cst_cx_probe(struct acpi_cst_softc * sc)335a1116831SSepherosa Ziehau acpi_cst_cx_probe(struct acpi_cst_softc *sc)
3365db2f26eSSascha Wildner {
3375db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
3385db2f26eSSascha Wildner 
3395db2f26eSSascha Wildner     /* Use initial sleep value of 1 sec. to start with lowest idle state. */
3404eee58faSSepherosa Ziehau     sc->cst_prev_sleep = 1000000;
3414eee58faSSepherosa Ziehau     sc->cst_cx_lowest = 0;
3424eee58faSSepherosa Ziehau     sc->cst_cx_lowest_req = 0;
3435db2f26eSSascha Wildner 
3445db2f26eSSascha Wildner     /*
3455db2f26eSSascha Wildner      * Check for the ACPI 2.0 _CST sleep states object.  If we can't find
346a1116831SSepherosa Ziehau      * any, we'll revert to FADT/P_BLK Cx control method which will be
347a1116831SSepherosa Ziehau      * handled by acpi_cst_postattach.  We need to defer to after having
348a1116831SSepherosa Ziehau      * probed all the cpus in the system before probing for Cx states from
349a1116831SSepherosa Ziehau      * FADT as we may already have found cpus with valid _CST packages.
3505db2f26eSSascha Wildner      */
351a1116831SSepherosa Ziehau     if (!acpi_cst_use_fadt && acpi_cst_cx_probe_cst(sc, 0) != 0) {
3525db2f26eSSascha Wildner 	/*
3535db2f26eSSascha Wildner 	 * We were unable to find a _CST package for this cpu or there
3545db2f26eSSascha Wildner 	 * was an error parsing it. Switch back to generic mode.
3555db2f26eSSascha Wildner 	 */
356a1116831SSepherosa Ziehau 	acpi_cst_use_fadt = TRUE;
3575db2f26eSSascha Wildner 	if (bootverbose)
358a1116831SSepherosa Ziehau 	    device_printf(sc->cst_dev, "switching to FADT Cx mode\n");
3595db2f26eSSascha Wildner     }
3605db2f26eSSascha Wildner 
3615db2f26eSSascha Wildner     /*
3625db2f26eSSascha Wildner      * TODO: _CSD Package should be checked here.
3635db2f26eSSascha Wildner      */
3645db2f26eSSascha Wildner }
3655db2f26eSSascha Wildner 
3665db2f26eSSascha Wildner static void
acpi_cst_cx_probe_fadt(struct acpi_cst_softc * sc)367a1116831SSepherosa Ziehau acpi_cst_cx_probe_fadt(struct acpi_cst_softc *sc)
3685db2f26eSSascha Wildner {
369a1116831SSepherosa Ziehau     struct acpi_cst_cx *cx_ptr;
3709925408fSSepherosa Ziehau     int error;
3719925408fSSepherosa Ziehau 
37218862f87SSepherosa Ziehau     /*
37318862f87SSepherosa Ziehau      * Free all previously allocated resources.
37418862f87SSepherosa Ziehau      *
37518862f87SSepherosa Ziehau      * NITE:
37618862f87SSepherosa Ziehau      * It is needed, since we could enter here because of other
37718862f87SSepherosa Ziehau      * cpu's _CST probing failure.
37818862f87SSepherosa Ziehau      */
37918862f87SSepherosa Ziehau     acpi_cst_free_resource(sc, 0);
3805db2f26eSSascha Wildner 
3814eee58faSSepherosa Ziehau     sc->cst_cx_count = 0;
3824eee58faSSepherosa Ziehau     cx_ptr = sc->cst_cx_states;
3835db2f26eSSascha Wildner 
3845db2f26eSSascha Wildner     /* Use initial sleep value of 1 sec. to start with lowest idle state. */
3854eee58faSSepherosa Ziehau     sc->cst_prev_sleep = 1000000;
3865db2f26eSSascha Wildner 
3875db2f26eSSascha Wildner     /* C1 has been required since just after ACPI 1.0 */
3886df05d3dSSepherosa Ziehau     cx_ptr->gas.SpaceId = ACPI_ADR_SPACE_FIXED_HARDWARE;
3895db2f26eSSascha Wildner     cx_ptr->type = ACPI_STATE_C1;
3905db2f26eSSascha Wildner     cx_ptr->trans_lat = 0;
39124da862fSSepherosa Ziehau     cx_ptr->enter = acpi_cst_c1_halt_enter;
3929925408fSSepherosa Ziehau     error = acpi_cst_cx_setup(cx_ptr);
3939925408fSSepherosa Ziehau     if (error)
3949925408fSSepherosa Ziehau 	panic("C1 FADT HALT setup failed: %d", error);
3955db2f26eSSascha Wildner     cx_ptr++;
3964eee58faSSepherosa Ziehau     sc->cst_cx_count++;
3975db2f26eSSascha Wildner 
3988621dc6dSSepherosa Ziehau     /* C2(+) is not supported on MP system */
3998621dc6dSSepherosa Ziehau     if (ncpus > 1 && (AcpiGbl_FADT.Flags & ACPI_FADT_C2_MP_SUPPORTED) == 0)
4008621dc6dSSepherosa Ziehau 	return;
4018621dc6dSSepherosa Ziehau 
4025db2f26eSSascha Wildner     /*
4035db2f26eSSascha Wildner      * The spec says P_BLK must be 6 bytes long.  However, some systems
4045db2f26eSSascha Wildner      * use it to indicate a fractional set of features present so we
4055db2f26eSSascha Wildner      * take 5 as C2.  Some may also have a value of 7 to indicate
4065db2f26eSSascha Wildner      * another C3 but most use _CST for this (as required) and having
4075db2f26eSSascha Wildner      * "only" C1-C3 is not a hardship.
4085db2f26eSSascha Wildner      */
4094eee58faSSepherosa Ziehau     if (sc->cst_p_blk_len < 5)
4105db2f26eSSascha Wildner 	return;
4115db2f26eSSascha Wildner 
4125db2f26eSSascha Wildner     /* Validate and allocate resources for C2 (P_LVL2). */
4135db2f26eSSascha Wildner     if (AcpiGbl_FADT.C2Latency <= 100) {
4141dff7e06SSepherosa Ziehau 	cx_ptr->gas.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
4151dff7e06SSepherosa Ziehau 	cx_ptr->gas.BitWidth = 8;
4161dff7e06SSepherosa Ziehau 	cx_ptr->gas.Address = sc->cst_p_blk + 4;
4175db2f26eSSascha Wildner 
41841d9045eSSepherosa Ziehau 	cx_ptr->rid = sc->cst_parent->cpu_next_rid;
4191dff7e06SSepherosa Ziehau 	acpi_bus_alloc_gas(sc->cst_dev, &cx_ptr->res_type, &cx_ptr->rid,
4209925408fSSepherosa Ziehau 	    &cx_ptr->gas, &cx_ptr->res, RF_SHAREABLE);
4219925408fSSepherosa Ziehau 	if (cx_ptr->res != NULL) {
42241d9045eSSepherosa Ziehau 	    sc->cst_parent->cpu_next_rid++;
4235db2f26eSSascha Wildner 	    cx_ptr->type = ACPI_STATE_C2;
4245db2f26eSSascha Wildner 	    cx_ptr->trans_lat = AcpiGbl_FADT.C2Latency;
42524da862fSSepherosa Ziehau 	    cx_ptr->enter = acpi_cst_cx_io_enter;
4269925408fSSepherosa Ziehau 	    cx_ptr->btag = rman_get_bustag(cx_ptr->res);
4279925408fSSepherosa Ziehau 	    cx_ptr->bhand = rman_get_bushandle(cx_ptr->res);
4289925408fSSepherosa Ziehau 	    error = acpi_cst_cx_setup(cx_ptr);
4299925408fSSepherosa Ziehau 	    if (error)
4309925408fSSepherosa Ziehau 		panic("C2 FADT I/O setup failed: %d", error);
4315db2f26eSSascha Wildner 	    cx_ptr++;
4324eee58faSSepherosa Ziehau 	    sc->cst_cx_count++;
4334eee58faSSepherosa Ziehau 	    sc->cst_non_c3 = 1;
4345db2f26eSSascha Wildner 	}
4355db2f26eSSascha Wildner     }
4364eee58faSSepherosa Ziehau     if (sc->cst_p_blk_len < 6)
4375db2f26eSSascha Wildner 	return;
4385db2f26eSSascha Wildner 
4395db2f26eSSascha Wildner     /* Validate and allocate resources for C3 (P_LVL3). */
440a1116831SSepherosa Ziehau     if (AcpiGbl_FADT.C3Latency <= 1000 &&
441a1116831SSepherosa Ziehau         !(acpi_cst_quirks & ACPI_CST_QUIRK_NO_C3)) {
4421dff7e06SSepherosa Ziehau 	cx_ptr->gas.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
4431dff7e06SSepherosa Ziehau 	cx_ptr->gas.BitWidth = 8;
4441dff7e06SSepherosa Ziehau 	cx_ptr->gas.Address = sc->cst_p_blk + 5;
4455db2f26eSSascha Wildner 
44641d9045eSSepherosa Ziehau 	cx_ptr->rid = sc->cst_parent->cpu_next_rid;
4471dff7e06SSepherosa Ziehau 	acpi_bus_alloc_gas(sc->cst_dev, &cx_ptr->res_type, &cx_ptr->rid,
4489925408fSSepherosa Ziehau 	    &cx_ptr->gas, &cx_ptr->res, RF_SHAREABLE);
4499925408fSSepherosa Ziehau 	if (cx_ptr->res != NULL) {
45041d9045eSSepherosa Ziehau 	    sc->cst_parent->cpu_next_rid++;
4515db2f26eSSascha Wildner 	    cx_ptr->type = ACPI_STATE_C3;
4525db2f26eSSascha Wildner 	    cx_ptr->trans_lat = AcpiGbl_FADT.C3Latency;
45324da862fSSepherosa Ziehau 	    cx_ptr->enter = acpi_cst_cx_io_enter;
4549925408fSSepherosa Ziehau 	    cx_ptr->btag = rman_get_bustag(cx_ptr->res);
4559925408fSSepherosa Ziehau 	    cx_ptr->bhand = rman_get_bushandle(cx_ptr->res);
4569925408fSSepherosa Ziehau 	    error = acpi_cst_cx_setup(cx_ptr);
4579925408fSSepherosa Ziehau 	    if (error)
4589925408fSSepherosa Ziehau 		panic("C3 FADT I/O setup failed: %d", error);
4595db2f26eSSascha Wildner 	    cx_ptr++;
4604eee58faSSepherosa Ziehau 	    sc->cst_cx_count++;
4615db2f26eSSascha Wildner 	}
4625db2f26eSSascha Wildner     }
4635db2f26eSSascha Wildner }
4645db2f26eSSascha Wildner 
465daa63909SSepherosa Ziehau static void
acpi_cst_copy(struct acpi_cst_softc * dst_sc,const struct acpi_cst_softc * src_sc)466daa63909SSepherosa Ziehau acpi_cst_copy(struct acpi_cst_softc *dst_sc,
467daa63909SSepherosa Ziehau     const struct acpi_cst_softc *src_sc)
468daa63909SSepherosa Ziehau {
469daa63909SSepherosa Ziehau     dst_sc->cst_non_c3 = src_sc->cst_non_c3;
470daa63909SSepherosa Ziehau     dst_sc->cst_cx_count = src_sc->cst_cx_count;
471daa63909SSepherosa Ziehau     memcpy(dst_sc->cst_cx_states, src_sc->cst_cx_states,
472daa63909SSepherosa Ziehau         sizeof(dst_sc->cst_cx_states));
473daa63909SSepherosa Ziehau }
474daa63909SSepherosa Ziehau 
4755db2f26eSSascha Wildner /*
4765db2f26eSSascha Wildner  * Parse a _CST package and set up its Cx states.  Since the _CST object
4775db2f26eSSascha Wildner  * can change dynamically, our notify handler may call this function
4785db2f26eSSascha Wildner  * to clean up and probe the new _CST package.
4795db2f26eSSascha Wildner  */
4805db2f26eSSascha Wildner static int
acpi_cst_cx_probe_cst(struct acpi_cst_softc * sc,int reprobe)481a1116831SSepherosa Ziehau acpi_cst_cx_probe_cst(struct acpi_cst_softc *sc, int reprobe)
4825db2f26eSSascha Wildner {
483a1116831SSepherosa Ziehau     struct	 acpi_cst_cx *cx_ptr;
4845db2f26eSSascha Wildner     ACPI_STATUS	 status;
4855db2f26eSSascha Wildner     ACPI_BUFFER	 buf;
4865db2f26eSSascha Wildner     ACPI_OBJECT	*top;
4875db2f26eSSascha Wildner     ACPI_OBJECT	*pkg;
4885db2f26eSSascha Wildner     uint32_t	 count;
4895db2f26eSSascha Wildner     int		 i;
4905db2f26eSSascha Wildner 
4915db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
4925db2f26eSSascha Wildner 
493f2b1cf25SSepherosa Ziehau     if (reprobe)
4940e4ac8cfSSepherosa Ziehau 	cpuhelper_assert(sc->cst_cpuid, true);
495f2b1cf25SSepherosa Ziehau 
4965db2f26eSSascha Wildner     buf.Pointer = NULL;
4975db2f26eSSascha Wildner     buf.Length = ACPI_ALLOCATE_BUFFER;
4984eee58faSSepherosa Ziehau     status = AcpiEvaluateObject(sc->cst_handle, "_CST", NULL, &buf);
4995db2f26eSSascha Wildner     if (ACPI_FAILURE(status))
5005db2f26eSSascha Wildner 	return (ENXIO);
5015db2f26eSSascha Wildner 
5025db2f26eSSascha Wildner     /* _CST is a package with a count and at least one Cx package. */
5035db2f26eSSascha Wildner     top = (ACPI_OBJECT *)buf.Pointer;
5045db2f26eSSascha Wildner     if (!ACPI_PKG_VALID(top, 2) || acpi_PkgInt32(top, 0, &count) != 0) {
5054eee58faSSepherosa Ziehau 	device_printf(sc->cst_dev, "invalid _CST package\n");
5065db2f26eSSascha Wildner 	AcpiOsFree(buf.Pointer);
5075db2f26eSSascha Wildner 	return (ENXIO);
5085db2f26eSSascha Wildner     }
5095db2f26eSSascha Wildner     if (count != top->Package.Count - 1) {
5104eee58faSSepherosa Ziehau 	device_printf(sc->cst_dev, "invalid _CST state count (%d != %d)\n",
5115db2f26eSSascha Wildner 	       count, top->Package.Count - 1);
5125db2f26eSSascha Wildner 	count = top->Package.Count - 1;
5135db2f26eSSascha Wildner     }
5145db2f26eSSascha Wildner     if (count > MAX_CX_STATES) {
5154eee58faSSepherosa Ziehau 	device_printf(sc->cst_dev, "_CST has too many states (%d)\n", count);
5165db2f26eSSascha Wildner 	count = MAX_CX_STATES;
5175db2f26eSSascha Wildner     }
5185db2f26eSSascha Wildner 
519daa63909SSepherosa Ziehau     sc->cst_flags |= ACPI_CST_FLAG_PROBING | ACPI_CST_FLAG_MATCH_HT;
52044806d43SSepherosa Ziehau     cpu_sfence();
52144806d43SSepherosa Ziehau 
52218862f87SSepherosa Ziehau     /*
52318862f87SSepherosa Ziehau      * Free all previously allocated resources
52418862f87SSepherosa Ziehau      *
52518862f87SSepherosa Ziehau      * NOTE: It is needed for _CST reprobing.
52618862f87SSepherosa Ziehau      */
52718862f87SSepherosa Ziehau     acpi_cst_free_resource(sc, 0);
528ed3bf55eSSepherosa Ziehau 
5295db2f26eSSascha Wildner     /* Set up all valid states. */
5304eee58faSSepherosa Ziehau     sc->cst_cx_count = 0;
5314eee58faSSepherosa Ziehau     cx_ptr = sc->cst_cx_states;
5325db2f26eSSascha Wildner     for (i = 0; i < count; i++) {
5339925408fSSepherosa Ziehau 	int error;
5349925408fSSepherosa Ziehau 
5355db2f26eSSascha Wildner 	pkg = &top->Package.Elements[i + 1];
5365db2f26eSSascha Wildner 	if (!ACPI_PKG_VALID(pkg, 4) ||
5375db2f26eSSascha Wildner 	    acpi_PkgInt32(pkg, 1, &cx_ptr->type) != 0 ||
5385db2f26eSSascha Wildner 	    acpi_PkgInt32(pkg, 2, &cx_ptr->trans_lat) != 0 ||
5395db2f26eSSascha Wildner 	    acpi_PkgInt32(pkg, 3, &cx_ptr->power) != 0) {
5405db2f26eSSascha Wildner 
5414eee58faSSepherosa Ziehau 	    device_printf(sc->cst_dev, "skipping invalid Cx state package\n");
5425db2f26eSSascha Wildner 	    continue;
5435db2f26eSSascha Wildner 	}
5445db2f26eSSascha Wildner 
5455db2f26eSSascha Wildner 	/* Validate the state to see if we should use it. */
5465db2f26eSSascha Wildner 	switch (cx_ptr->type) {
5475db2f26eSSascha Wildner 	case ACPI_STATE_C1:
5484eee58faSSepherosa Ziehau 	    sc->cst_non_c3 = i;
54924da862fSSepherosa Ziehau 	    cx_ptr->enter = acpi_cst_c1_halt_enter;
5509925408fSSepherosa Ziehau 	    error = acpi_cst_cx_setup(cx_ptr);
5519925408fSSepherosa Ziehau 	    if (error)
5529925408fSSepherosa Ziehau 		panic("C1 CST HALT setup failed: %d", error);
553daa63909SSepherosa Ziehau 	    if (sc->cst_cx_count != 0) {
554daa63909SSepherosa Ziehau 		/*
555daa63909SSepherosa Ziehau 		 * C1 is not the first C-state; something really stupid
556daa63909SSepherosa Ziehau 		 * is going on ...
557daa63909SSepherosa Ziehau 		 */
558daa63909SSepherosa Ziehau 		sc->cst_flags &= ~ACPI_CST_FLAG_MATCH_HT;
559daa63909SSepherosa Ziehau 	    }
5605db2f26eSSascha Wildner 	    cx_ptr++;
5614eee58faSSepherosa Ziehau 	    sc->cst_cx_count++;
5625db2f26eSSascha Wildner 	    continue;
5635db2f26eSSascha Wildner 	case ACPI_STATE_C2:
5644eee58faSSepherosa Ziehau 	    sc->cst_non_c3 = i;
5655db2f26eSSascha Wildner 	    break;
5665db2f26eSSascha Wildner 	case ACPI_STATE_C3:
5675db2f26eSSascha Wildner 	default:
568a1116831SSepherosa Ziehau 	    if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_C3) != 0) {
5695db2f26eSSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
570a1116831SSepherosa Ziehau 				 "cpu_cst%d: C3[%d] not available.\n",
5714eee58faSSepherosa Ziehau 				 device_get_unit(sc->cst_dev), i));
5725db2f26eSSascha Wildner 		continue;
5735db2f26eSSascha Wildner 	    }
5745db2f26eSSascha Wildner 	    break;
5755db2f26eSSascha Wildner 	}
5765db2f26eSSascha Wildner 
5771dff7e06SSepherosa Ziehau 	/*
5781dff7e06SSepherosa Ziehau 	 * Allocate the control register for C2 or C3(+).
5791dff7e06SSepherosa Ziehau 	 */
5809925408fSSepherosa Ziehau 	KASSERT(cx_ptr->res == NULL, ("still has res"));
5811dff7e06SSepherosa Ziehau 	acpi_PkgRawGas(pkg, 0, &cx_ptr->gas);
5821dff7e06SSepherosa Ziehau 
583daa63909SSepherosa Ziehau 	/*
584daa63909SSepherosa Ziehau 	 * We match number of C2/C3 for hyperthreads, only if the
585daa63909SSepherosa Ziehau 	 * register is "Fixed Hardware", e.g. on most of the Intel
586daa63909SSepherosa Ziehau 	 * CPUs.  We don't have much to do for the rest of the
587daa63909SSepherosa Ziehau 	 * register types.
588daa63909SSepherosa Ziehau 	 */
589daa63909SSepherosa Ziehau 	if (cx_ptr->gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE)
590daa63909SSepherosa Ziehau 	    sc->cst_flags &= ~ACPI_CST_FLAG_MATCH_HT;
591daa63909SSepherosa Ziehau 
59241d9045eSSepherosa Ziehau 	cx_ptr->rid = sc->cst_parent->cpu_next_rid;
5931dff7e06SSepherosa Ziehau 	acpi_bus_alloc_gas(sc->cst_dev, &cx_ptr->res_type, &cx_ptr->rid,
5949925408fSSepherosa Ziehau 	    &cx_ptr->gas, &cx_ptr->res, RF_SHAREABLE);
5959925408fSSepherosa Ziehau 	if (cx_ptr->res != NULL) {
59641d9045eSSepherosa Ziehau 	    sc->cst_parent->cpu_next_rid++;
5975db2f26eSSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_INFO,
598a1116831SSepherosa Ziehau 			     "cpu_cst%d: Got C%d - %d latency\n",
5994eee58faSSepherosa Ziehau 			     device_get_unit(sc->cst_dev), cx_ptr->type,
6005db2f26eSSascha Wildner 			     cx_ptr->trans_lat));
60124da862fSSepherosa Ziehau 	    cx_ptr->enter = acpi_cst_cx_io_enter;
6029925408fSSepherosa Ziehau 	    cx_ptr->btag = rman_get_bustag(cx_ptr->res);
6039925408fSSepherosa Ziehau 	    cx_ptr->bhand = rman_get_bushandle(cx_ptr->res);
6049925408fSSepherosa Ziehau 	    error = acpi_cst_cx_setup(cx_ptr);
6059925408fSSepherosa Ziehau 	    if (error)
6069925408fSSepherosa Ziehau 		panic("C%d CST I/O setup failed: %d", cx_ptr->type, error);
6075db2f26eSSascha Wildner 	    cx_ptr++;
6084eee58faSSepherosa Ziehau 	    sc->cst_cx_count++;
6099925408fSSepherosa Ziehau 	} else {
6109925408fSSepherosa Ziehau 	    error = acpi_cst_cx_setup(cx_ptr);
6119925408fSSepherosa Ziehau 	    if (!error) {
6129925408fSSepherosa Ziehau 		KASSERT(cx_ptr->enter != NULL,
6139925408fSSepherosa Ziehau 		    ("C%d enter is not set", cx_ptr->type));
6149925408fSSepherosa Ziehau 		cx_ptr++;
6159925408fSSepherosa Ziehau 		sc->cst_cx_count++;
6169925408fSSepherosa Ziehau 	    }
6175db2f26eSSascha Wildner 	}
6185db2f26eSSascha Wildner     }
6195db2f26eSSascha Wildner     AcpiOsFree(buf.Pointer);
6205db2f26eSSascha Wildner 
621daa63909SSepherosa Ziehau     if (sc->cst_flags & ACPI_CST_FLAG_MATCH_HT) {
622daa63909SSepherosa Ziehau 	cpumask_t mask;
623daa63909SSepherosa Ziehau 
624daa63909SSepherosa Ziehau 	mask = get_cpumask_from_level(sc->cst_cpuid, CORE_LEVEL);
625daa63909SSepherosa Ziehau 	if (CPUMASK_TESTNZERO(mask)) {
626daa63909SSepherosa Ziehau 	    int cpu;
627daa63909SSepherosa Ziehau 
628daa63909SSepherosa Ziehau 	    for (cpu = 0; cpu < ncpus; ++cpu) {
629daa63909SSepherosa Ziehau 		struct acpi_cst_softc *sc1 = acpi_cst_softc[cpu];
630daa63909SSepherosa Ziehau 
631daa63909SSepherosa Ziehau 		if (sc1 == NULL || sc1 == sc ||
632daa63909SSepherosa Ziehau 		    (sc1->cst_flags & ACPI_CST_FLAG_ATTACHED) == 0 ||
633daa63909SSepherosa Ziehau 		    (sc1->cst_flags & ACPI_CST_FLAG_MATCH_HT) == 0)
634daa63909SSepherosa Ziehau 		    continue;
635daa63909SSepherosa Ziehau 		if (!CPUMASK_TESTBIT(mask, sc1->cst_cpuid))
636daa63909SSepherosa Ziehau 		    continue;
637daa63909SSepherosa Ziehau 
638daa63909SSepherosa Ziehau 		if (sc1->cst_cx_count != sc->cst_cx_count) {
639daa63909SSepherosa Ziehau 		    struct acpi_cst_softc *src_sc, *dst_sc;
640daa63909SSepherosa Ziehau 
641daa63909SSepherosa Ziehau 		    if (bootverbose) {
642daa63909SSepherosa Ziehau 			device_printf(sc->cst_dev,
643daa63909SSepherosa Ziehau 			    "inconstent C-state count: %d, %s has %d\n",
644daa63909SSepherosa Ziehau 			    sc->cst_cx_count,
645daa63909SSepherosa Ziehau 			    device_get_nameunit(sc1->cst_dev),
646daa63909SSepherosa Ziehau 			    sc1->cst_cx_count);
647daa63909SSepherosa Ziehau 		    }
648daa63909SSepherosa Ziehau 		    if (sc1->cst_cx_count > sc->cst_cx_count) {
649daa63909SSepherosa Ziehau 			src_sc = sc1;
650daa63909SSepherosa Ziehau 			dst_sc = sc;
651daa63909SSepherosa Ziehau 		    } else {
652daa63909SSepherosa Ziehau 			src_sc = sc;
653daa63909SSepherosa Ziehau 			dst_sc = sc1;
654daa63909SSepherosa Ziehau 		    }
655daa63909SSepherosa Ziehau 		    acpi_cst_copy(dst_sc, src_sc);
656daa63909SSepherosa Ziehau 		}
657daa63909SSepherosa Ziehau 	    }
658daa63909SSepherosa Ziehau 	}
659daa63909SSepherosa Ziehau     }
660daa63909SSepherosa Ziehau 
661ad544345SSepherosa Ziehau     if (reprobe) {
6622bfe985fSSepherosa Ziehau 	/* If there are C3(+) states, always enable bus master wakeup */
6639925408fSSepherosa Ziehau 	if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) {
6648b48ec4dSSepherosa Ziehau 	    for (i = 0; i < sc->cst_cx_count; ++i) {
665a1116831SSepherosa Ziehau 		struct acpi_cst_cx *cx = &sc->cst_cx_states[i];
6668b48ec4dSSepherosa Ziehau 
6678b48ec4dSSepherosa Ziehau 		if (cx->type >= ACPI_STATE_C3) {
6688b48ec4dSSepherosa Ziehau 		    AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 1);
6698b48ec4dSSepherosa Ziehau 		    break;
6708b48ec4dSSepherosa Ziehau 		}
6718b48ec4dSSepherosa Ziehau 	    }
6728b48ec4dSSepherosa Ziehau 	}
6738b48ec4dSSepherosa Ziehau 
674ad544345SSepherosa Ziehau 	/* Fix up the lowest Cx being used */
675a1116831SSepherosa Ziehau 	acpi_cst_set_lowest_oncpu(sc, sc->cst_cx_lowest_req);
676ad544345SSepherosa Ziehau     }
677f2b1cf25SSepherosa Ziehau 
678f2b1cf25SSepherosa Ziehau     /*
679f2b1cf25SSepherosa Ziehau      * Cache the lowest non-C3 state.
680f2b1cf25SSepherosa Ziehau      * NOTE: must after cst_cx_lowest is set.
681f2b1cf25SSepherosa Ziehau      */
682a1116831SSepherosa Ziehau     acpi_cst_non_c3(sc);
683f2b1cf25SSepherosa Ziehau 
68444806d43SSepherosa Ziehau     cpu_sfence();
68544806d43SSepherosa Ziehau     sc->cst_flags &= ~ACPI_CST_FLAG_PROBING;
68644806d43SSepherosa Ziehau 
6875db2f26eSSascha Wildner     return (0);
6885db2f26eSSascha Wildner }
6895db2f26eSSascha Wildner 
69044806d43SSepherosa Ziehau static void
acpi_cst_cx_reprobe_cst_handler(struct cpuhelper_msg * msg)6910e4ac8cfSSepherosa Ziehau acpi_cst_cx_reprobe_cst_handler(struct cpuhelper_msg *msg)
69244806d43SSepherosa Ziehau {
69344806d43SSepherosa Ziehau     int error;
69444806d43SSepherosa Ziehau 
6950e4ac8cfSSepherosa Ziehau     error = acpi_cst_cx_probe_cst(msg->ch_cbarg, 1);
6960e4ac8cfSSepherosa Ziehau     cpuhelper_replymsg(msg, error);
69744806d43SSepherosa Ziehau }
69844806d43SSepherosa Ziehau 
69944806d43SSepherosa Ziehau static int
acpi_cst_cx_reprobe_cst(struct acpi_cst_softc * sc)700a1116831SSepherosa Ziehau acpi_cst_cx_reprobe_cst(struct acpi_cst_softc *sc)
70144806d43SSepherosa Ziehau {
7020e4ac8cfSSepherosa Ziehau     struct cpuhelper_msg msg;
70344806d43SSepherosa Ziehau 
7040e4ac8cfSSepherosa Ziehau     cpuhelper_initmsg(&msg, &curthread->td_msgport,
7050e4ac8cfSSepherosa Ziehau         acpi_cst_cx_reprobe_cst_handler, sc, MSGF_PRIORITY);
7060e4ac8cfSSepherosa Ziehau     return (cpuhelper_domsg(&msg, sc->cst_cpuid));
70744806d43SSepherosa Ziehau }
70844806d43SSepherosa Ziehau 
7095db2f26eSSascha Wildner /*
710a1116831SSepherosa Ziehau  * Call this *after* all CPUs Cx states have been attached.
7115db2f26eSSascha Wildner  */
7125db2f26eSSascha Wildner static void
acpi_cst_postattach(void * arg)713a1116831SSepherosa Ziehau acpi_cst_postattach(void *arg)
7145db2f26eSSascha Wildner {
7154eee58faSSepherosa Ziehau     struct acpi_cst_softc *sc;
7165db2f26eSSascha Wildner     int i;
7175db2f26eSSascha Wildner 
718a1116831SSepherosa Ziehau     /* Get set of Cx state devices */
719a1116831SSepherosa Ziehau     devclass_get_devices(acpi_cst_devclass, &acpi_cst_devices,
720a1116831SSepherosa Ziehau 	&acpi_cst_ndevices);
7215db2f26eSSascha Wildner 
7225db2f26eSSascha Wildner     /*
7235db2f26eSSascha Wildner      * Setup any quirks that might necessary now that we have probed
724a1116831SSepherosa Ziehau      * all the CPUs' Cx states.
7255db2f26eSSascha Wildner      */
726a1116831SSepherosa Ziehau     acpi_cst_set_quirks();
7275db2f26eSSascha Wildner 
728a1116831SSepherosa Ziehau     if (acpi_cst_use_fadt) {
7295db2f26eSSascha Wildner 	/*
730a1116831SSepherosa Ziehau 	 * We are using Cx mode from FADT, probe for available Cx states
7315db2f26eSSascha Wildner 	 * for all processors.
7325db2f26eSSascha Wildner 	 */
733a1116831SSepherosa Ziehau 	for (i = 0; i < acpi_cst_ndevices; i++) {
734a1116831SSepherosa Ziehau 	    sc = device_get_softc(acpi_cst_devices[i]);
735a1116831SSepherosa Ziehau 	    acpi_cst_cx_probe_fadt(sc);
7365db2f26eSSascha Wildner 	}
7375db2f26eSSascha Wildner     } else {
7385db2f26eSSascha Wildner 	/*
7395db2f26eSSascha Wildner 	 * We are using _CST mode, remove C3 state if necessary.
7404cf48621SSepherosa Ziehau 	 *
7415db2f26eSSascha Wildner 	 * As we now know for sure that we will be using _CST mode
7425db2f26eSSascha Wildner 	 * install our notify handler.
7435db2f26eSSascha Wildner 	 */
744a1116831SSepherosa Ziehau 	for (i = 0; i < acpi_cst_ndevices; i++) {
745a1116831SSepherosa Ziehau 	    sc = device_get_softc(acpi_cst_devices[i]);
7469925408fSSepherosa Ziehau 	    if (acpi_cst_quirks & ACPI_CST_QUIRK_NO_C3) {
74718862f87SSepherosa Ziehau 		/* Free part of unused resources */
74818862f87SSepherosa Ziehau 		acpi_cst_free_resource(sc, sc->cst_non_c3 + 1);
7494eee58faSSepherosa Ziehau 		sc->cst_cx_count = sc->cst_non_c3 + 1;
7509925408fSSepherosa Ziehau 	    }
75141d9045eSSepherosa Ziehau 	    sc->cst_parent->cpu_cst_notify = acpi_cst_notify;
7525db2f26eSSascha Wildner 	}
7535db2f26eSSascha Wildner     }
754a1116831SSepherosa Ziehau     acpi_cst_global_cx_count();
7555db2f26eSSascha Wildner 
7565db2f26eSSascha Wildner     /* Perform Cx final initialization. */
757a1116831SSepherosa Ziehau     for (i = 0; i < acpi_cst_ndevices; i++) {
758a1116831SSepherosa Ziehau 	sc = device_get_softc(acpi_cst_devices[i]);
759a1116831SSepherosa Ziehau 	acpi_cst_startup(sc);
7605db2f26eSSascha Wildner 
7614eee58faSSepherosa Ziehau 	if (sc->cst_parent->glob_sysctl_tree != NULL) {
76241d9045eSSepherosa Ziehau 	    struct acpi_cpu_softc *cpu = sc->cst_parent;
7635db2f26eSSascha Wildner 
7645db2f26eSSascha Wildner 	    /* Add a sysctl handler to handle global Cx lowest setting */
76541d9045eSSepherosa Ziehau 	    SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx,
76641d9045eSSepherosa Ziehau 	    		    SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
7675db2f26eSSascha Wildner 			    OID_AUTO, "cx_lowest",
7685db2f26eSSascha Wildner 			    CTLTYPE_STRING | CTLFLAG_RW, NULL, 0,
769a1116831SSepherosa Ziehau 			    acpi_cst_global_lowest_sysctl, "A",
7701d730338SSepherosa Ziehau 			    "Requested global lowest Cx sleep state");
77141d9045eSSepherosa Ziehau 	    SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx,
77241d9045eSSepherosa Ziehau 	    		    SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
7731d730338SSepherosa Ziehau 			    OID_AUTO, "cx_lowest_use",
7741d730338SSepherosa Ziehau 			    CTLTYPE_STRING | CTLFLAG_RD, NULL, 0,
775a1116831SSepherosa Ziehau 			    acpi_cst_global_lowest_use_sysctl, "A",
7765db2f26eSSascha Wildner 			    "Global lowest Cx sleep state to use");
7775db2f26eSSascha Wildner 	}
7785db2f26eSSascha Wildner     }
7795db2f26eSSascha Wildner 
7805db2f26eSSascha Wildner     /* Take over idling from cpu_idle_default(). */
781a1116831SSepherosa Ziehau     acpi_cst_cx_lowest = 0;
782a1116831SSepherosa Ziehau     acpi_cst_cx_lowest_req = 0;
783a1116831SSepherosa Ziehau     acpi_cst_disable_idle = FALSE;
784e24a50d0SSepherosa Ziehau 
785e24a50d0SSepherosa Ziehau     cpu_sfence();
786a1116831SSepherosa Ziehau     cpu_idle_hook = acpi_cst_idle;
7875db2f26eSSascha Wildner }
7885db2f26eSSascha Wildner 
7895db2f26eSSascha Wildner static void
acpi_cst_support_list(struct acpi_cst_softc * sc)790a1116831SSepherosa Ziehau acpi_cst_support_list(struct acpi_cst_softc *sc)
7915db2f26eSSascha Wildner {
7925db2f26eSSascha Wildner     struct sbuf sb;
7935db2f26eSSascha Wildner     int i;
7945db2f26eSSascha Wildner 
7955db2f26eSSascha Wildner     /*
7965db2f26eSSascha Wildner      * Set up the list of Cx states
7975db2f26eSSascha Wildner      */
7984eee58faSSepherosa Ziehau     sbuf_new(&sb, sc->cst_cx_supported, sizeof(sc->cst_cx_supported),
7995db2f26eSSascha Wildner 	SBUF_FIXEDLEN);
8004eee58faSSepherosa Ziehau     for (i = 0; i < sc->cst_cx_count; i++)
8014eee58faSSepherosa Ziehau 	sbuf_printf(&sb, "C%d/%d ", i + 1, sc->cst_cx_states[i].trans_lat);
8025db2f26eSSascha Wildner     sbuf_trim(&sb);
8035db2f26eSSascha Wildner     sbuf_finish(&sb);
8045db2f26eSSascha Wildner }
8055db2f26eSSascha Wildner 
8065db2f26eSSascha Wildner static void
acpi_cst_c3_bm_rld_handler(struct cpuhelper_msg * msg)8070e4ac8cfSSepherosa Ziehau acpi_cst_c3_bm_rld_handler(struct cpuhelper_msg *msg)
8088b48ec4dSSepherosa Ziehau {
8098b48ec4dSSepherosa Ziehau 
8108b48ec4dSSepherosa Ziehau     AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 1);
8110e4ac8cfSSepherosa Ziehau     cpuhelper_replymsg(msg, 0);
8128b48ec4dSSepherosa Ziehau }
8138b48ec4dSSepherosa Ziehau 
8148b48ec4dSSepherosa Ziehau static void
acpi_cst_c3_bm_rld(struct acpi_cst_softc * sc)815a1116831SSepherosa Ziehau acpi_cst_c3_bm_rld(struct acpi_cst_softc *sc)
8168b48ec4dSSepherosa Ziehau {
8170e4ac8cfSSepherosa Ziehau     struct cpuhelper_msg msg;
8188b48ec4dSSepherosa Ziehau 
8190e4ac8cfSSepherosa Ziehau     cpuhelper_initmsg(&msg, &curthread->td_msgport,
8200e4ac8cfSSepherosa Ziehau 	acpi_cst_c3_bm_rld_handler, sc, MSGF_PRIORITY);
8210e4ac8cfSSepherosa Ziehau     cpuhelper_domsg(&msg, sc->cst_cpuid);
8228b48ec4dSSepherosa Ziehau }
8238b48ec4dSSepherosa Ziehau 
8248b48ec4dSSepherosa Ziehau static void
acpi_cst_startup(struct acpi_cst_softc * sc)825a1116831SSepherosa Ziehau acpi_cst_startup(struct acpi_cst_softc *sc)
8265db2f26eSSascha Wildner {
82741d9045eSSepherosa Ziehau     struct acpi_cpu_softc *cpu = sc->cst_parent;
8289925408fSSepherosa Ziehau     int i, bm_rld_done = 0;
8298b48ec4dSSepherosa Ziehau 
8308b48ec4dSSepherosa Ziehau     for (i = 0; i < sc->cst_cx_count; ++i) {
831a1116831SSepherosa Ziehau 	struct acpi_cst_cx *cx = &sc->cst_cx_states[i];
8329925408fSSepherosa Ziehau 	int error;
8338b48ec4dSSepherosa Ziehau 
8349925408fSSepherosa Ziehau 	/* If there are C3(+) states, always enable bus master wakeup */
8359925408fSSepherosa Ziehau 	if (cx->type >= ACPI_STATE_C3 && !bm_rld_done &&
8369925408fSSepherosa Ziehau 	    (acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) {
837a1116831SSepherosa Ziehau 	    acpi_cst_c3_bm_rld(sc);
8389925408fSSepherosa Ziehau 	    bm_rld_done = 1;
8398b48ec4dSSepherosa Ziehau 	}
8409925408fSSepherosa Ziehau 
8419925408fSSepherosa Ziehau 	/* Redo the Cx setup, since quirks have been changed */
8429925408fSSepherosa Ziehau 	error = acpi_cst_cx_setup(cx);
8439925408fSSepherosa Ziehau 	if (error)
8449925408fSSepherosa Ziehau 	    panic("C%d startup setup failed: %d", i + 1, error);
8458b48ec4dSSepherosa Ziehau     }
8468b48ec4dSSepherosa Ziehau 
847a1116831SSepherosa Ziehau     acpi_cst_support_list(sc);
8485db2f26eSSascha Wildner 
84941d9045eSSepherosa Ziehau     SYSCTL_ADD_STRING(&cpu->pcpu_sysctl_ctx,
85041d9045eSSepherosa Ziehau 		      SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
8515db2f26eSSascha Wildner 		      OID_AUTO, "cx_supported", CTLFLAG_RD,
8524eee58faSSepherosa Ziehau 		      sc->cst_cx_supported, 0,
8535db2f26eSSascha Wildner 		      "Cx/microsecond values for supported Cx states");
85441d9045eSSepherosa Ziehau     SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx,
85541d9045eSSepherosa Ziehau 		    SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
8565db2f26eSSascha Wildner 		    OID_AUTO, "cx_lowest", CTLTYPE_STRING | CTLFLAG_RW,
857a1116831SSepherosa Ziehau 		    (void *)sc, 0, acpi_cst_lowest_sysctl, "A",
8581d730338SSepherosa Ziehau 		    "requested lowest Cx sleep state");
85941d9045eSSepherosa Ziehau     SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx,
86041d9045eSSepherosa Ziehau 		    SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
8611d730338SSepherosa Ziehau 		    OID_AUTO, "cx_lowest_use", CTLTYPE_STRING | CTLFLAG_RD,
862a1116831SSepherosa Ziehau 		    (void *)sc, 0, acpi_cst_lowest_use_sysctl, "A",
8635db2f26eSSascha Wildner 		    "lowest Cx sleep state to use");
86441d9045eSSepherosa Ziehau     SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx,
86541d9045eSSepherosa Ziehau 		    SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
8665db2f26eSSascha Wildner 		    OID_AUTO, "cx_usage", CTLTYPE_STRING | CTLFLAG_RD,
867a1116831SSepherosa Ziehau 		    (void *)sc, 0, acpi_cst_usage_sysctl, "A",
8685db2f26eSSascha Wildner 		    "percent usage for each Cx state");
8695db2f26eSSascha Wildner 
8705db2f26eSSascha Wildner #ifdef notyet
8715db2f26eSSascha Wildner     /* Signal platform that we can handle _CST notification. */
872a1116831SSepherosa Ziehau     if (!acpi_cst_use_fadt && acpi_cst_ctrl != 0) {
8735db2f26eSSascha Wildner 	ACPI_LOCK(acpi);
874a1116831SSepherosa Ziehau 	AcpiOsWritePort(acpi_cst_smi_cmd, acpi_cst_ctrl, 8);
8755db2f26eSSascha Wildner 	ACPI_UNLOCK(acpi);
8765db2f26eSSascha Wildner     }
8775db2f26eSSascha Wildner #endif
8785db2f26eSSascha Wildner }
8795db2f26eSSascha Wildner 
8805db2f26eSSascha Wildner /*
8815db2f26eSSascha Wildner  * Idle the CPU in the lowest state possible.  This function is called with
8825db2f26eSSascha Wildner  * interrupts disabled.  Note that once it re-enables interrupts, a task
8835db2f26eSSascha Wildner  * switch can occur so do not access shared data (i.e. the softc) after
8845db2f26eSSascha Wildner  * interrupts are re-enabled.
8855db2f26eSSascha Wildner  */
8865db2f26eSSascha Wildner static void
acpi_cst_idle(void)887a1116831SSepherosa Ziehau acpi_cst_idle(void)
8885db2f26eSSascha Wildner {
8894eee58faSSepherosa Ziehau     struct	acpi_cst_softc *sc;
890a1116831SSepherosa Ziehau     struct	acpi_cst_cx *cx_next;
89119f23194SSepherosa Ziehau     union microtime_pcpu start, end;
8929925408fSSepherosa Ziehau     int		cx_next_idx, i, tdiff, bm_arb_disabled = 0;
8935db2f26eSSascha Wildner 
8945db2f26eSSascha Wildner     /* If disabled, return immediately. */
895a1116831SSepherosa Ziehau     if (acpi_cst_disable_idle) {
8965db2f26eSSascha Wildner 	ACPI_ENABLE_IRQS();
8975db2f26eSSascha Wildner 	return;
8985db2f26eSSascha Wildner     }
8995db2f26eSSascha Wildner 
9005db2f26eSSascha Wildner     /*
9015db2f26eSSascha Wildner      * Look up our CPU id to get our softc.  If it's NULL, we'll use C1
902a1116831SSepherosa Ziehau      * since there is no Cx state for this processor.
9035db2f26eSSascha Wildner      */
904a1116831SSepherosa Ziehau     sc = acpi_cst_softc[mdcpu->mi.gd_cpuid];
9055db2f26eSSascha Wildner     if (sc == NULL) {
906a1116831SSepherosa Ziehau 	acpi_cst_c1_halt();
9075db2f26eSSascha Wildner 	return;
9085db2f26eSSascha Wildner     }
9095db2f26eSSascha Wildner 
91044806d43SSepherosa Ziehau     /* Still probing; use C1 */
91144806d43SSepherosa Ziehau     if (sc->cst_flags & ACPI_CST_FLAG_PROBING) {
912a1116831SSepherosa Ziehau 	acpi_cst_c1_halt();
91344806d43SSepherosa Ziehau 	return;
91444806d43SSepherosa Ziehau     }
91544806d43SSepherosa Ziehau 
9165db2f26eSSascha Wildner     /* Find the lowest state that has small enough latency. */
9175db2f26eSSascha Wildner     cx_next_idx = 0;
9184eee58faSSepherosa Ziehau     for (i = sc->cst_cx_lowest; i >= 0; i--) {
9194eee58faSSepherosa Ziehau 	if (sc->cst_cx_states[i].trans_lat * 3 <= sc->cst_prev_sleep) {
9205db2f26eSSascha Wildner 	    cx_next_idx = i;
9215db2f26eSSascha Wildner 	    break;
9225db2f26eSSascha Wildner 	}
9235db2f26eSSascha Wildner     }
9245db2f26eSSascha Wildner 
9255db2f26eSSascha Wildner     /*
9269925408fSSepherosa Ziehau      * Check for bus master activity if needed for the selected state.
9279925408fSSepherosa Ziehau      * If there was activity, clear the bit and use the lowest non-C3 state.
9285db2f26eSSascha Wildner      */
929d1860b0fSSepherosa Ziehau     cx_next = &sc->cst_cx_states[cx_next_idx];
9309925408fSSepherosa Ziehau     if (cx_next->flags & ACPI_CST_CX_FLAG_BM_STS) {
9319925408fSSepherosa Ziehau 	int bm_active;
9329925408fSSepherosa Ziehau 
9335db2f26eSSascha Wildner 	AcpiReadBitRegister(ACPI_BITREG_BUS_MASTER_STATUS, &bm_active);
9345db2f26eSSascha Wildner 	if (bm_active != 0) {
9355db2f26eSSascha Wildner 	    AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_STATUS, 1);
9367eb26369SSepherosa Ziehau 	    cx_next_idx = sc->cst_non_c3;
9375db2f26eSSascha Wildner 	}
9385db2f26eSSascha Wildner     }
9395db2f26eSSascha Wildner 
9405db2f26eSSascha Wildner     /* Select the next state and update statistics. */
9414eee58faSSepherosa Ziehau     cx_next = &sc->cst_cx_states[cx_next_idx];
9424eee58faSSepherosa Ziehau     sc->cst_cx_stats[cx_next_idx]++;
943a1116831SSepherosa Ziehau     KASSERT(cx_next->type != ACPI_STATE_C0, ("C0 sleep"));
9445db2f26eSSascha Wildner 
9455db2f26eSSascha Wildner     /*
9465db2f26eSSascha Wildner      * Execute HLT (or equivalent) and wait for an interrupt.  We can't
9475db2f26eSSascha Wildner      * calculate the time spent in C1 since the place we wake up is an
9485db2f26eSSascha Wildner      * ISR.  Assume we slept half of quantum and return.
9495db2f26eSSascha Wildner      */
9505db2f26eSSascha Wildner     if (cx_next->type == ACPI_STATE_C1) {
9514eee58faSSepherosa Ziehau 	sc->cst_prev_sleep = (sc->cst_prev_sleep * 3 + 500000 / hz) / 4;
95224da862fSSepherosa Ziehau 	cx_next->enter(cx_next);
9535db2f26eSSascha Wildner 	return;
9545db2f26eSSascha Wildner     }
9555db2f26eSSascha Wildner 
9569925408fSSepherosa Ziehau     /* Execute the proper preamble before enter the selected state. */
9579925408fSSepherosa Ziehau     if (cx_next->preamble == ACPI_CST_CX_PREAMBLE_BM_ARB) {
9585db2f26eSSascha Wildner 	AcpiWriteBitRegister(ACPI_BITREG_ARB_DISABLE, 1);
9599925408fSSepherosa Ziehau 	bm_arb_disabled = 1;
9609925408fSSepherosa Ziehau     } else if (cx_next->preamble == ACPI_CST_CX_PREAMBLE_WBINVD) {
9615db2f26eSSascha Wildner 	ACPI_FLUSH_CPU_CACHE();
9625db2f26eSSascha Wildner     }
9635db2f26eSSascha Wildner 
9645db2f26eSSascha Wildner     /*
9659925408fSSepherosa Ziehau      * Enter the selected state and check time spent asleep.
9665db2f26eSSascha Wildner      */
96719f23194SSepherosa Ziehau     microtime_pcpu_get(&start);
96819f23194SSepherosa Ziehau     cpu_mfence();
9695db2f26eSSascha Wildner 
97024da862fSSepherosa Ziehau     cx_next->enter(cx_next);
97119f23194SSepherosa Ziehau 
97219f23194SSepherosa Ziehau     cpu_mfence();
97319f23194SSepherosa Ziehau     microtime_pcpu_get(&end);
9745db2f26eSSascha Wildner 
9759925408fSSepherosa Ziehau     /* Enable bus master arbitration, if it was disabled. */
9769925408fSSepherosa Ziehau     if (bm_arb_disabled)
9775db2f26eSSascha Wildner 	AcpiWriteBitRegister(ACPI_BITREG_ARB_DISABLE, 0);
9789925408fSSepherosa Ziehau 
9795db2f26eSSascha Wildner     ACPI_ENABLE_IRQS();
9805db2f26eSSascha Wildner 
9815db2f26eSSascha Wildner     /* Find the actual time asleep in microseconds. */
98219f23194SSepherosa Ziehau     tdiff = microtime_pcpu_diff(&start, &end);
98319f23194SSepherosa Ziehau     sc->cst_prev_sleep = (sc->cst_prev_sleep * 3 + tdiff) / 4;
9845db2f26eSSascha Wildner }
9855db2f26eSSascha Wildner 
9865db2f26eSSascha Wildner /*
9875db2f26eSSascha Wildner  * Re-evaluate the _CST object when we are notified that it changed.
9885db2f26eSSascha Wildner  */
9895db2f26eSSascha Wildner static void
acpi_cst_notify(device_t dev)990a1116831SSepherosa Ziehau acpi_cst_notify(device_t dev)
9915db2f26eSSascha Wildner {
9924eee58faSSepherosa Ziehau     struct acpi_cst_softc *sc = device_get_softc(dev);
9935db2f26eSSascha Wildner 
9940e4ac8cfSSepherosa Ziehau     cpuhelper_assert(mycpuid, false);
995b45624acSSepherosa Ziehau 
996a1116831SSepherosa Ziehau     lwkt_serialize_enter(&acpi_cst_slize);
997b45624acSSepherosa Ziehau 
9985db2f26eSSascha Wildner     /* Update the list of Cx states. */
999a1116831SSepherosa Ziehau     acpi_cst_cx_reprobe_cst(sc);
1000a1116831SSepherosa Ziehau     acpi_cst_support_list(sc);
10015db2f26eSSascha Wildner 
10025db2f26eSSascha Wildner     /* Update the new lowest useable Cx state for all CPUs. */
1003a1116831SSepherosa Ziehau     acpi_cst_global_cx_count();
10041d730338SSepherosa Ziehau 
10051d730338SSepherosa Ziehau     /*
10061d730338SSepherosa Ziehau      * Fix up the lowest Cx being used
10071d730338SSepherosa Ziehau      */
1008a1116831SSepherosa Ziehau     if (acpi_cst_cx_lowest_req < acpi_cst_cx_count)
1009a1116831SSepherosa Ziehau 	acpi_cst_cx_lowest = acpi_cst_cx_lowest_req;
1010a1116831SSepherosa Ziehau     if (acpi_cst_cx_lowest > acpi_cst_cx_count - 1)
1011a1116831SSepherosa Ziehau 	acpi_cst_cx_lowest = acpi_cst_cx_count - 1;
10121d730338SSepherosa Ziehau 
1013a1116831SSepherosa Ziehau     lwkt_serialize_exit(&acpi_cst_slize);
10145db2f26eSSascha Wildner }
10155db2f26eSSascha Wildner 
10165db2f26eSSascha Wildner static int
acpi_cst_set_quirks(void)1017a1116831SSepherosa Ziehau acpi_cst_set_quirks(void)
10185db2f26eSSascha Wildner {
10195db2f26eSSascha Wildner     device_t acpi_dev;
10205db2f26eSSascha Wildner     uint32_t val;
10215db2f26eSSascha Wildner 
10225db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
10235db2f26eSSascha Wildner 
10245db2f26eSSascha Wildner     /*
10255db2f26eSSascha Wildner      * Bus mastering arbitration control is needed to keep caches coherent
10265db2f26eSSascha Wildner      * while sleeping in C3.  If it's not present but a working flush cache
10275db2f26eSSascha Wildner      * instruction is present, flush the caches before entering C3 instead.
10285db2f26eSSascha Wildner      * Otherwise, just disable C3 completely.
10295db2f26eSSascha Wildner      */
10305db2f26eSSascha Wildner     if (AcpiGbl_FADT.Pm2ControlBlock == 0 ||
10315db2f26eSSascha Wildner 	AcpiGbl_FADT.Pm2ControlLength == 0) {
10325db2f26eSSascha Wildner 	if ((AcpiGbl_FADT.Flags & ACPI_FADT_WBINVD) &&
10335db2f26eSSascha Wildner 	    (AcpiGbl_FADT.Flags & ACPI_FADT_WBINVD_FLUSH) == 0) {
10349925408fSSepherosa Ziehau 	    acpi_cst_quirks |= ACPI_CST_QUIRK_NO_BM;
10355db2f26eSSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1036a1116831SSepherosa Ziehau 		"cpu_cst: no BM control, using flush cache method\n"));
10375db2f26eSSascha Wildner 	} else {
1038a1116831SSepherosa Ziehau 	    acpi_cst_quirks |= ACPI_CST_QUIRK_NO_C3;
10395db2f26eSSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1040a1116831SSepherosa Ziehau 		"cpu_cst: no BM control, C3 not available\n"));
10415db2f26eSSascha Wildner 	}
10425db2f26eSSascha Wildner     }
10435db2f26eSSascha Wildner 
10445db2f26eSSascha Wildner     /* Look for various quirks of the PIIX4 part. */
10455db2f26eSSascha Wildner     acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3);
10465db2f26eSSascha Wildner     if (acpi_dev != NULL) {
10475db2f26eSSascha Wildner 	switch (pci_get_revid(acpi_dev)) {
10485db2f26eSSascha Wildner 	/*
10495db2f26eSSascha Wildner 	 * Disable C3 support for all PIIX4 chipsets.  Some of these parts
10505db2f26eSSascha Wildner 	 * do not report the BMIDE status to the BM status register and
10515db2f26eSSascha Wildner 	 * others have a livelock bug if Type-F DMA is enabled.  Linux
10525db2f26eSSascha Wildner 	 * works around the BMIDE bug by reading the BM status directly
10535db2f26eSSascha Wildner 	 * but we take the simpler approach of disabling C3 for these
10545db2f26eSSascha Wildner 	 * parts.
10555db2f26eSSascha Wildner 	 *
10565db2f26eSSascha Wildner 	 * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
10575db2f26eSSascha Wildner 	 * Livelock") from the January 2002 PIIX4 specification update.
10585db2f26eSSascha Wildner 	 * Applies to all PIIX4 models.
10595db2f26eSSascha Wildner 	 *
10605db2f26eSSascha Wildner 	 * Also, make sure that all interrupts cause a "Stop Break"
10615db2f26eSSascha Wildner 	 * event to exit from C2 state.
10625db2f26eSSascha Wildner 	 * Also, BRLD_EN_BM (ACPI_BITREG_BUS_MASTER_RLD in ACPI-speak)
10635db2f26eSSascha Wildner 	 * should be set to zero, otherwise it causes C2 to short-sleep.
10645db2f26eSSascha Wildner 	 * PIIX4 doesn't properly support C3 and bus master activity
10655db2f26eSSascha Wildner 	 * need not break out of C2.
10665db2f26eSSascha Wildner 	 */
10675db2f26eSSascha Wildner 	case PCI_REVISION_A_STEP:
10685db2f26eSSascha Wildner 	case PCI_REVISION_B_STEP:
10695db2f26eSSascha Wildner 	case PCI_REVISION_4E:
10705db2f26eSSascha Wildner 	case PCI_REVISION_4M:
1071a1116831SSepherosa Ziehau 	    acpi_cst_quirks |= ACPI_CST_QUIRK_NO_C3;
10725db2f26eSSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1073a1116831SSepherosa Ziehau 		"cpu_cst: working around PIIX4 bug, disabling C3\n"));
10745db2f26eSSascha Wildner 
10755db2f26eSSascha Wildner 	    val = pci_read_config(acpi_dev, PIIX4_DEVACTB_REG, 4);
10765db2f26eSSascha Wildner 	    if ((val & PIIX4_STOP_BREAK_MASK) != PIIX4_STOP_BREAK_MASK) {
10775db2f26eSSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1078a1116831SSepherosa Ziehau 		    "cpu_cst: PIIX4: enabling IRQs to generate Stop Break\n"));
10795db2f26eSSascha Wildner 	    	val |= PIIX4_STOP_BREAK_MASK;
10805db2f26eSSascha Wildner 		pci_write_config(acpi_dev, PIIX4_DEVACTB_REG, val, 4);
10815db2f26eSSascha Wildner 	    }
10825db2f26eSSascha Wildner 	    AcpiReadBitRegister(ACPI_BITREG_BUS_MASTER_RLD, &val);
10835db2f26eSSascha Wildner 	    if (val) {
10845db2f26eSSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1085a1116831SSepherosa Ziehau 		    "cpu_cst: PIIX4: reset BRLD_EN_BM\n"));
10865db2f26eSSascha Wildner 		AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 0);
10875db2f26eSSascha Wildner 	    }
10885db2f26eSSascha Wildner 	    break;
10895db2f26eSSascha Wildner 	default:
10905db2f26eSSascha Wildner 	    break;
10915db2f26eSSascha Wildner 	}
10925db2f26eSSascha Wildner     }
10935db2f26eSSascha Wildner 
10945db2f26eSSascha Wildner     return (0);
10955db2f26eSSascha Wildner }
10965db2f26eSSascha Wildner 
10975db2f26eSSascha Wildner static int
acpi_cst_usage_sysctl(SYSCTL_HANDLER_ARGS)1098a1116831SSepherosa Ziehau acpi_cst_usage_sysctl(SYSCTL_HANDLER_ARGS)
10995db2f26eSSascha Wildner {
11004eee58faSSepherosa Ziehau     struct acpi_cst_softc *sc;
11015db2f26eSSascha Wildner     struct sbuf	 sb;
11025db2f26eSSascha Wildner     char	 buf[128];
11035db2f26eSSascha Wildner     int		 i;
11045db2f26eSSascha Wildner     uintmax_t	 fract, sum, whole;
11055db2f26eSSascha Wildner 
11064eee58faSSepherosa Ziehau     sc = (struct acpi_cst_softc *) arg1;
11075db2f26eSSascha Wildner     sum = 0;
11084eee58faSSepherosa Ziehau     for (i = 0; i < sc->cst_cx_count; i++)
11094eee58faSSepherosa Ziehau 	sum += sc->cst_cx_stats[i];
11105db2f26eSSascha Wildner     sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
11114eee58faSSepherosa Ziehau     for (i = 0; i < sc->cst_cx_count; i++) {
11125db2f26eSSascha Wildner 	if (sum > 0) {
11134eee58faSSepherosa Ziehau 	    whole = (uintmax_t)sc->cst_cx_stats[i] * 100;
11145db2f26eSSascha Wildner 	    fract = (whole % sum) * 100;
11155db2f26eSSascha Wildner 	    sbuf_printf(&sb, "%u.%02u%% ", (u_int)(whole / sum),
11165db2f26eSSascha Wildner 		(u_int)(fract / sum));
11175db2f26eSSascha Wildner 	} else
11185db2f26eSSascha Wildner 	    sbuf_printf(&sb, "0.00%% ");
11195db2f26eSSascha Wildner     }
11204eee58faSSepherosa Ziehau     sbuf_printf(&sb, "last %dus", sc->cst_prev_sleep);
11215db2f26eSSascha Wildner     sbuf_trim(&sb);
11225db2f26eSSascha Wildner     sbuf_finish(&sb);
11235db2f26eSSascha Wildner     sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
11245db2f26eSSascha Wildner     sbuf_delete(&sb);
11255db2f26eSSascha Wildner 
11265db2f26eSSascha Wildner     return (0);
11275db2f26eSSascha Wildner }
11285db2f26eSSascha Wildner 
11295db2f26eSSascha Wildner static int
acpi_cst_set_lowest_oncpu(struct acpi_cst_softc * sc,int val)1130a1116831SSepherosa Ziehau acpi_cst_set_lowest_oncpu(struct acpi_cst_softc *sc, int val)
11315db2f26eSSascha Wildner {
1132de6641b7SSepherosa Ziehau     int old_lowest, error = 0, old_lowest_req;
11335db2f26eSSascha Wildner     uint32_t old_type, type;
11345db2f26eSSascha Wildner 
11354eee58faSSepherosa Ziehau     KKASSERT(mycpuid == sc->cst_cpuid);
1136c241507cSSepherosa Ziehau 
1137de6641b7SSepherosa Ziehau     old_lowest_req = sc->cst_cx_lowest_req;
11384eee58faSSepherosa Ziehau     sc->cst_cx_lowest_req = val;
1139de6641b7SSepherosa Ziehau 
11404eee58faSSepherosa Ziehau     if (val > sc->cst_cx_count - 1)
11414eee58faSSepherosa Ziehau 	val = sc->cst_cx_count - 1;
11424eee58faSSepherosa Ziehau     old_lowest = atomic_swap_int(&sc->cst_cx_lowest, val);
11435db2f26eSSascha Wildner 
11444eee58faSSepherosa Ziehau     old_type = sc->cst_cx_states[old_lowest].type;
11454eee58faSSepherosa Ziehau     type = sc->cst_cx_states[val].type;
1146b42fff25SSepherosa Ziehau     if (old_type >= ACPI_STATE_C3 && type < ACPI_STATE_C3) {
1147e80ea409SSepherosa Ziehau 	cputimer_intr_powersave_remreq();
1148b42fff25SSepherosa Ziehau     } else if (type >= ACPI_STATE_C3 && old_type < ACPI_STATE_C3) {
1149e80ea409SSepherosa Ziehau 	error = cputimer_intr_powersave_addreq();
1150e80ea409SSepherosa Ziehau 	if (error) {
11515db2f26eSSascha Wildner 	    /* Restore */
1152de6641b7SSepherosa Ziehau 	    sc->cst_cx_lowest_req = old_lowest_req;
11534eee58faSSepherosa Ziehau 	    sc->cst_cx_lowest = old_lowest;
11545db2f26eSSascha Wildner 	}
11555db2f26eSSascha Wildner     }
11565db2f26eSSascha Wildner 
11575db2f26eSSascha Wildner     if (error)
11585db2f26eSSascha Wildner 	return error;
11595db2f26eSSascha Wildner 
1160febc8c49SSepherosa Ziehau     /* Cache the new lowest non-C3 state. */
1161a1116831SSepherosa Ziehau     acpi_cst_non_c3(sc);
11625db2f26eSSascha Wildner 
11635db2f26eSSascha Wildner     /* Reset the statistics counters. */
11644eee58faSSepherosa Ziehau     bzero(sc->cst_cx_stats, sizeof(sc->cst_cx_stats));
11655db2f26eSSascha Wildner     return (0);
11665db2f26eSSascha Wildner }
11675db2f26eSSascha Wildner 
1168c241507cSSepherosa Ziehau static void
acpi_cst_set_lowest_handler(struct cpuhelper_msg * msg)11690e4ac8cfSSepherosa Ziehau acpi_cst_set_lowest_handler(struct cpuhelper_msg *msg)
1170c241507cSSepherosa Ziehau {
1171c241507cSSepherosa Ziehau     int error;
1172c241507cSSepherosa Ziehau 
11730e4ac8cfSSepherosa Ziehau     error = acpi_cst_set_lowest_oncpu(msg->ch_cbarg, msg->ch_cbarg1);
11740e4ac8cfSSepherosa Ziehau     cpuhelper_replymsg(msg, error);
1175c241507cSSepherosa Ziehau }
1176c241507cSSepherosa Ziehau 
1177c241507cSSepherosa Ziehau static int
acpi_cst_set_lowest(struct acpi_cst_softc * sc,int val)1178a1116831SSepherosa Ziehau acpi_cst_set_lowest(struct acpi_cst_softc *sc, int val)
1179c241507cSSepherosa Ziehau {
11800e4ac8cfSSepherosa Ziehau     struct cpuhelper_msg msg;
1181c241507cSSepherosa Ziehau 
11820e4ac8cfSSepherosa Ziehau     cpuhelper_initmsg(&msg, &curthread->td_msgport,
11830e4ac8cfSSepherosa Ziehau 	acpi_cst_set_lowest_handler, sc, MSGF_PRIORITY);
11840e4ac8cfSSepherosa Ziehau     msg.ch_cbarg1 = val;
1185c241507cSSepherosa Ziehau 
11860e4ac8cfSSepherosa Ziehau     return (cpuhelper_domsg(&msg, sc->cst_cpuid));
1187c241507cSSepherosa Ziehau }
1188c241507cSSepherosa Ziehau 
11895db2f26eSSascha Wildner static int
acpi_cst_lowest_sysctl(SYSCTL_HANDLER_ARGS)1190a1116831SSepherosa Ziehau acpi_cst_lowest_sysctl(SYSCTL_HANDLER_ARGS)
11915db2f26eSSascha Wildner {
11924eee58faSSepherosa Ziehau     struct	 acpi_cst_softc *sc;
11935db2f26eSSascha Wildner     char	 state[8];
11945db2f26eSSascha Wildner     int		 val, error;
11955db2f26eSSascha Wildner 
11964eee58faSSepherosa Ziehau     sc = (struct acpi_cst_softc *)arg1;
11974eee58faSSepherosa Ziehau     ksnprintf(state, sizeof(state), "C%d", sc->cst_cx_lowest_req + 1);
11985db2f26eSSascha Wildner     error = sysctl_handle_string(oidp, state, sizeof(state), req);
11995db2f26eSSascha Wildner     if (error != 0 || req->newptr == NULL)
12005db2f26eSSascha Wildner 	return (error);
12015db2f26eSSascha Wildner     if (strlen(state) < 2 || toupper(state[0]) != 'C')
12025db2f26eSSascha Wildner 	return (EINVAL);
12035db2f26eSSascha Wildner     val = (int) strtol(state + 1, NULL, 10) - 1;
12041d730338SSepherosa Ziehau     if (val < 0)
12055db2f26eSSascha Wildner 	return (EINVAL);
12065db2f26eSSascha Wildner 
1207a1116831SSepherosa Ziehau     lwkt_serialize_enter(&acpi_cst_slize);
1208a1116831SSepherosa Ziehau     error = acpi_cst_set_lowest(sc, val);
1209a1116831SSepherosa Ziehau     lwkt_serialize_exit(&acpi_cst_slize);
12105db2f26eSSascha Wildner 
12115db2f26eSSascha Wildner     return error;
12125db2f26eSSascha Wildner }
12135db2f26eSSascha Wildner 
12145db2f26eSSascha Wildner static int
acpi_cst_lowest_use_sysctl(SYSCTL_HANDLER_ARGS)1215a1116831SSepherosa Ziehau acpi_cst_lowest_use_sysctl(SYSCTL_HANDLER_ARGS)
12161d730338SSepherosa Ziehau {
12174eee58faSSepherosa Ziehau     struct	 acpi_cst_softc *sc;
12181d730338SSepherosa Ziehau     char	 state[8];
12191d730338SSepherosa Ziehau 
12204eee58faSSepherosa Ziehau     sc = (struct acpi_cst_softc *)arg1;
12214eee58faSSepherosa Ziehau     ksnprintf(state, sizeof(state), "C%d", sc->cst_cx_lowest + 1);
12221d730338SSepherosa Ziehau     return sysctl_handle_string(oidp, state, sizeof(state), req);
12231d730338SSepherosa Ziehau }
12241d730338SSepherosa Ziehau 
12251d730338SSepherosa Ziehau static int
acpi_cst_global_lowest_sysctl(SYSCTL_HANDLER_ARGS)1226a1116831SSepherosa Ziehau acpi_cst_global_lowest_sysctl(SYSCTL_HANDLER_ARGS)
12275db2f26eSSascha Wildner {
12284eee58faSSepherosa Ziehau     struct	acpi_cst_softc *sc;
12295db2f26eSSascha Wildner     char	state[8];
12305db2f26eSSascha Wildner     int		val, error, i;
12315db2f26eSSascha Wildner 
1232a1116831SSepherosa Ziehau     ksnprintf(state, sizeof(state), "C%d", acpi_cst_cx_lowest_req + 1);
12335db2f26eSSascha Wildner     error = sysctl_handle_string(oidp, state, sizeof(state), req);
12345db2f26eSSascha Wildner     if (error != 0 || req->newptr == NULL)
12355db2f26eSSascha Wildner 	return (error);
12365db2f26eSSascha Wildner     if (strlen(state) < 2 || toupper(state[0]) != 'C')
12375db2f26eSSascha Wildner 	return (EINVAL);
12385db2f26eSSascha Wildner     val = (int) strtol(state + 1, NULL, 10) - 1;
12391d730338SSepherosa Ziehau     if (val < 0)
12405db2f26eSSascha Wildner 	return (EINVAL);
12411d730338SSepherosa Ziehau 
1242a1116831SSepherosa Ziehau     lwkt_serialize_enter(&acpi_cst_slize);
1243b45624acSSepherosa Ziehau 
1244a1116831SSepherosa Ziehau     acpi_cst_cx_lowest_req = val;
1245a1116831SSepherosa Ziehau     acpi_cst_cx_lowest = val;
1246a1116831SSepherosa Ziehau     if (acpi_cst_cx_lowest > acpi_cst_cx_count - 1)
1247a1116831SSepherosa Ziehau 	acpi_cst_cx_lowest = acpi_cst_cx_count - 1;
12485db2f26eSSascha Wildner 
12495db2f26eSSascha Wildner     /* Update the new lowest useable Cx state for all CPUs. */
1250a1116831SSepherosa Ziehau     for (i = 0; i < acpi_cst_ndevices; i++) {
1251a1116831SSepherosa Ziehau 	sc = device_get_softc(acpi_cst_devices[i]);
1252a1116831SSepherosa Ziehau 	error = acpi_cst_set_lowest(sc, val);
12535db2f26eSSascha Wildner 	if (error) {
12545db2f26eSSascha Wildner 	    KKASSERT(i == 0);
12555db2f26eSSascha Wildner 	    break;
12565db2f26eSSascha Wildner 	}
12575db2f26eSSascha Wildner     }
1258b45624acSSepherosa Ziehau 
1259a1116831SSepherosa Ziehau     lwkt_serialize_exit(&acpi_cst_slize);
12605db2f26eSSascha Wildner 
12615db2f26eSSascha Wildner     return error;
12625db2f26eSSascha Wildner }
12635db2f26eSSascha Wildner 
12641d730338SSepherosa Ziehau static int
acpi_cst_global_lowest_use_sysctl(SYSCTL_HANDLER_ARGS)1265a1116831SSepherosa Ziehau acpi_cst_global_lowest_use_sysctl(SYSCTL_HANDLER_ARGS)
12661d730338SSepherosa Ziehau {
12671d730338SSepherosa Ziehau     char	state[8];
12681d730338SSepherosa Ziehau 
1269a1116831SSepherosa Ziehau     ksnprintf(state, sizeof(state), "C%d", acpi_cst_cx_lowest + 1);
12701d730338SSepherosa Ziehau     return sysctl_handle_string(oidp, state, sizeof(state), req);
12711d730338SSepherosa Ziehau }
12721d730338SSepherosa Ziehau 
12735db2f26eSSascha Wildner /*
12745db2f26eSSascha Wildner  * Put the CPU in C1 in a machine-dependant way.
12755db2f26eSSascha Wildner  * XXX: shouldn't be here!
12765db2f26eSSascha Wildner  */
12775db2f26eSSascha Wildner static void
acpi_cst_c1_halt(void)1278a1116831SSepherosa Ziehau acpi_cst_c1_halt(void)
12795db2f26eSSascha Wildner {
1280*704d2129SMatthew Dillon     cpu_idle_halt();
12815db2f26eSSascha Wildner }
1282febc8c49SSepherosa Ziehau 
1283febc8c49SSepherosa Ziehau static void
acpi_cst_non_c3(struct acpi_cst_softc * sc)1284a1116831SSepherosa Ziehau acpi_cst_non_c3(struct acpi_cst_softc *sc)
1285febc8c49SSepherosa Ziehau {
1286febc8c49SSepherosa Ziehau     int i;
1287febc8c49SSepherosa Ziehau 
12884eee58faSSepherosa Ziehau     sc->cst_non_c3 = 0;
12894eee58faSSepherosa Ziehau     for (i = sc->cst_cx_lowest; i >= 0; i--) {
12904eee58faSSepherosa Ziehau 	if (sc->cst_cx_states[i].type < ACPI_STATE_C3) {
12914eee58faSSepherosa Ziehau 	    sc->cst_non_c3 = i;
1292febc8c49SSepherosa Ziehau 	    break;
1293febc8c49SSepherosa Ziehau 	}
1294febc8c49SSepherosa Ziehau     }
1295febc8c49SSepherosa Ziehau     if (bootverbose)
12964eee58faSSepherosa Ziehau 	device_printf(sc->cst_dev, "non-C3 %d\n", sc->cst_non_c3);
1297febc8c49SSepherosa Ziehau }
12984cf48621SSepherosa Ziehau 
12994cf48621SSepherosa Ziehau /*
1300a1116831SSepherosa Ziehau  * Update the largest Cx state supported in the global acpi_cst_cx_count.
13014cf48621SSepherosa Ziehau  * It will be used in the global Cx sysctl handler.
13024cf48621SSepherosa Ziehau  */
13034cf48621SSepherosa Ziehau static void
acpi_cst_global_cx_count(void)1304a1116831SSepherosa Ziehau acpi_cst_global_cx_count(void)
13054cf48621SSepherosa Ziehau {
13064eee58faSSepherosa Ziehau     struct acpi_cst_softc *sc;
13074cf48621SSepherosa Ziehau     int i;
13084cf48621SSepherosa Ziehau 
1309a1116831SSepherosa Ziehau     if (acpi_cst_ndevices == 0) {
1310a1116831SSepherosa Ziehau 	acpi_cst_cx_count = 0;
13114cf48621SSepherosa Ziehau 	return;
13124cf48621SSepherosa Ziehau     }
13134cf48621SSepherosa Ziehau 
1314a1116831SSepherosa Ziehau     sc = device_get_softc(acpi_cst_devices[0]);
1315a1116831SSepherosa Ziehau     acpi_cst_cx_count = sc->cst_cx_count;
13164cf48621SSepherosa Ziehau 
1317a1116831SSepherosa Ziehau     for (i = 1; i < acpi_cst_ndevices; i++) {
1318a1116831SSepherosa Ziehau 	struct acpi_cst_softc *sc = device_get_softc(acpi_cst_devices[i]);
13194cf48621SSepherosa Ziehau 
1320a1116831SSepherosa Ziehau 	if (sc->cst_cx_count < acpi_cst_cx_count)
1321a1116831SSepherosa Ziehau 	    acpi_cst_cx_count = sc->cst_cx_count;
13224cf48621SSepherosa Ziehau     }
13234cf48621SSepherosa Ziehau     if (bootverbose)
1324a1116831SSepherosa Ziehau 	kprintf("cpu_cst: global Cx count %d\n", acpi_cst_cx_count);
13254cf48621SSepherosa Ziehau }
132624da862fSSepherosa Ziehau 
132724da862fSSepherosa Ziehau static void
acpi_cst_c1_halt_enter(const struct acpi_cst_cx * cx __unused)132824da862fSSepherosa Ziehau acpi_cst_c1_halt_enter(const struct acpi_cst_cx *cx __unused)
132924da862fSSepherosa Ziehau {
133024da862fSSepherosa Ziehau     acpi_cst_c1_halt();
133124da862fSSepherosa Ziehau }
133224da862fSSepherosa Ziehau 
133324da862fSSepherosa Ziehau static void
acpi_cst_cx_io_enter(const struct acpi_cst_cx * cx)133424da862fSSepherosa Ziehau acpi_cst_cx_io_enter(const struct acpi_cst_cx *cx)
133524da862fSSepherosa Ziehau {
133624da862fSSepherosa Ziehau     uint64_t dummy;
133724da862fSSepherosa Ziehau 
13389925408fSSepherosa Ziehau     /*
13399925408fSSepherosa Ziehau      * Read I/O to enter this Cx state
13409925408fSSepherosa Ziehau      */
134124da862fSSepherosa Ziehau     bus_space_read_1(cx->btag, cx->bhand, 0);
134224da862fSSepherosa Ziehau     /*
134324da862fSSepherosa Ziehau      * Perform a dummy I/O read.  Since it may take an arbitrary time
134424da862fSSepherosa Ziehau      * to enter the idle state, this read makes sure that we are frozen.
134524da862fSSepherosa Ziehau      */
134624da862fSSepherosa Ziehau     AcpiRead(&dummy, &AcpiGbl_FADT.XPmTimerBlock);
134724da862fSSepherosa Ziehau }
13489925408fSSepherosa Ziehau 
13499925408fSSepherosa Ziehau static int
acpi_cst_cx_setup(struct acpi_cst_cx * cx)13509925408fSSepherosa Ziehau acpi_cst_cx_setup(struct acpi_cst_cx *cx)
13519925408fSSepherosa Ziehau {
13529925408fSSepherosa Ziehau     cx->flags &= ~ACPI_CST_CX_FLAG_BM_STS;
13539925408fSSepherosa Ziehau     cx->preamble = ACPI_CST_CX_PREAMBLE_NONE;
13549925408fSSepherosa Ziehau 
13559925408fSSepherosa Ziehau     if (cx->type >= ACPI_STATE_C3) {
13569925408fSSepherosa Ziehau 	/*
13579925408fSSepherosa Ziehau 	 * Set the required operations for entering C3(+) state.
13589925408fSSepherosa Ziehau 	 * Later acpi_cst_md_cx_setup() may fix them up.
13599925408fSSepherosa Ziehau 	 */
13609925408fSSepherosa Ziehau 
13619925408fSSepherosa Ziehau 	/*
13629925408fSSepherosa Ziehau 	 * Always check BM_STS.
13639925408fSSepherosa Ziehau 	 */
13649925408fSSepherosa Ziehau 	if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0)
13659925408fSSepherosa Ziehau 	    cx->flags |= ACPI_CST_CX_FLAG_BM_STS;
13669925408fSSepherosa Ziehau 
13679925408fSSepherosa Ziehau 	/*
13689925408fSSepherosa Ziehau 	 * According to the ACPI specification, bus master arbitration
13699925408fSSepherosa Ziehau 	 * is only available on UP system.  For MP system, cache flushing
13709925408fSSepherosa Ziehau 	 * is required.
13719925408fSSepherosa Ziehau 	 */
13729925408fSSepherosa Ziehau 	if (ncpus == 1 && (acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0)
13739925408fSSepherosa Ziehau 	    cx->preamble = ACPI_CST_CX_PREAMBLE_BM_ARB;
13749925408fSSepherosa Ziehau 	else
13759925408fSSepherosa Ziehau 	    cx->preamble = ACPI_CST_CX_PREAMBLE_WBINVD;
13769925408fSSepherosa Ziehau     }
13779925408fSSepherosa Ziehau     return acpi_cst_md_cx_setup(cx);
13789925408fSSepherosa Ziehau }
137918862f87SSepherosa Ziehau 
138018862f87SSepherosa Ziehau static void
acpi_cst_free_resource(struct acpi_cst_softc * sc,int start)138118862f87SSepherosa Ziehau acpi_cst_free_resource(struct acpi_cst_softc *sc, int start)
138218862f87SSepherosa Ziehau {
138318862f87SSepherosa Ziehau     int i;
138418862f87SSepherosa Ziehau 
138518862f87SSepherosa Ziehau     for (i = start; i < MAX_CX_STATES; ++i) {
138618862f87SSepherosa Ziehau 	struct acpi_cst_cx *cx = &sc->cst_cx_states[i];
138718862f87SSepherosa Ziehau 
138818862f87SSepherosa Ziehau 	if (cx->res != NULL)
138918862f87SSepherosa Ziehau 	    bus_release_resource(sc->cst_dev, cx->res_type, cx->rid, cx->res);
139018862f87SSepherosa Ziehau 	memset(cx, 0, sizeof(*cx));
139118862f87SSepherosa Ziehau     }
139218862f87SSepherosa Ziehau }
1393