summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica/acpi_processor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/acpica/acpi_processor.c')
-rw-r--r--sys/dev/acpica/acpi_processor.c640
1 files changed, 640 insertions, 0 deletions
diff --git a/sys/dev/acpica/acpi_processor.c b/sys/dev/acpica/acpi_processor.c
new file mode 100644
index 0000000..627c8f9
--- /dev/null
+++ b/sys/dev/acpica/acpi_processor.c
@@ -0,0 +1,640 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/******************************************************************************
+ *
+ * 1. Copyright Notice
+ *
+ * Some or all of this work - Copyright (c) 1999, Intel Corp. All rights
+ * reserved.
+ *
+ * 2. License
+ *
+ * 2.1. This is your license from Intel Corp. under its intellectual property
+ * rights. You may have additional license terms from the party that provided
+ * you this software, covering your right to use that party's intellectual
+ * property rights.
+ *
+ * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
+ * copy of the source code appearing in this file ("Covered Code") an
+ * irrevocable, perpetual, worldwide license under Intel's copyrights in the
+ * base code distributed originally by Intel ("Original Intel Code") to copy,
+ * make derivatives, distribute, use and display any portion of the Covered
+ * Code in any form, with the right to sublicense such rights; and
+ *
+ * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
+ * license (with the right to sublicense), under only those claims of Intel
+ * patents that are infringed by the Original Intel Code, to make, use, sell,
+ * offer to sell, and import the Covered Code and derivative works thereof
+ * solely to the minimum extent necessary to exercise the above copyright
+ * license, and in no event shall the patent license extend to any additions
+ * to or modifications of the Original Intel Code. No other license or right
+ * is granted directly or by implication, estoppel or otherwise;
+ *
+ * The above copyright and patent license is granted only if the following
+ * conditions are met:
+ *
+ * 3. Conditions
+ *
+ * 3.1. Redistribution of Source with Rights to Further Distribute Source.
+ * Redistribution of source code of any substantial portion of the Covered
+ * Code or modification with rights to further distribute source must include
+ * the above Copyright Notice, the above License, this list of Conditions,
+ * and the following Disclaimer and Export Compliance provision. In addition,
+ * Licensee must cause all Covered Code to which Licensee contributes to
+ * contain a file documenting the changes Licensee made to create that Covered
+ * Code and the date of any change. Licensee must include in that file the
+ * documentation of any changes made by any predecessor Licensee. Licensee
+ * must include a prominent statement that the modification is derived,
+ * directly or indirectly, from Original Intel Code.
+ *
+ * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
+ * Redistribution of source code of any substantial portion of the Covered
+ * Code or modification without rights to further distribute source must
+ * include the following Disclaimer and Export Compliance provision in the
+ * documentation and/or other materials provided with distribution. In
+ * addition, Licensee may not authorize further sublicense of source of any
+ * portion of the Covered Code, and must include terms to the effect that the
+ * license from Licensee to its licensee is limited to the intellectual
+ * property embodied in the software Licensee provides to its licensee, and
+ * not to intellectual property embodied in modifications its licensee may
+ * make.
+ *
+ * 3.3. Redistribution of Executable. Redistribution in executable form of any
+ * substantial portion of the Covered Code or modification must reproduce the
+ * above Copyright Notice, and the following Disclaimer and Export Compliance
+ * provision in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3.4. Intel retains all right, title, and interest in and to the Original
+ * Intel Code.
+ *
+ * 3.5. Neither the name Intel nor any other trademark owned or controlled by
+ * Intel shall be used in advertising or otherwise to promote the sale, use or
+ * other dealings in products derived from or relating to the Covered Code
+ * without prior written authorization from Intel.
+ *
+ * 4. Disclaimer and Export Compliance
+ *
+ * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
+ * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
+ * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
+ * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
+ * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ *
+ * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
+ * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
+ * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
+ * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
+ * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
+ * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
+ * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
+ * LIMITED REMEDY.
+ *
+ * 4.3. Licensee shall not export, either directly or indirectly, any of this
+ * software or system incorporating such software without first obtaining any
+ * required license or other approval from the U. S. Department of Commerce or
+ * any other agency or department of the United States Government. In the
+ * event Licensee exports any such software from the United States or
+ * re-exports any such software from a foreign destination, Licensee shall
+ * ensure that the distribution and export/re-export of the software is in
+ * compliance with all laws, regulations, orders, or other restrictions of the
+ * U.S. Export Administration Regulations. Licensee agrees that neither it nor
+ * any of its subsidiaries will export/re-export any technical data, process,
+ * software, or service, directly or indirectly, to any country for which the
+ * United States government or any agency thereof requires an export license,
+ * other governmental approval, or letter of assurance, without first obtaining
+ * such license, approval or letter.
+ *
+ *****************************************************************************/
+
+/*
+ * Processor driver.
+ *
+ * XXX Note that the power state code here is almost certainly suboptimal.
+ * We should go raid the Linux code for their ideas and experience.
+ *
+ * Code style here is a hairy mix of BSD-like and Intel-like. Should be
+ * sanitised at some point.
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#define PR_MAX_POWER_STATES 4
+#define PR_MAX_PERFORMANCE_STATES 8
+#define PR_MAX_THROTTLING_STATES 8
+
+/*
+ * Processor Commands:
+ * -------------------
+ */
+#define PR_COMMAND_GET_INFO ((BM_COMMAND) 0x80)
+#define PR_COMMAND_SET_CX_STATE_INFO ((BM_COMMAND) 0x81)
+#define PR_COMMAND_GET_THROTTLING_STATE ((BM_COMMAND) 0x82)
+#define PR_COMMAND_SET_THROTTLING_STATE ((BM_COMMAND) 0x83)
+#define PR_COMMAND_GET_PERF_STATE ((BM_COMMAND) 0x84)
+#define PR_COMMAND_SET_PERF_STATE ((BM_COMMAND) 0x85)
+#define PR_COMMAND_GET_CURRENT_FREQ ((BM_COMMAND) 0x86)
+
+/*
+ * PR_POWER_STATE:
+ * ---------------
+ */
+typedef u_int32_t PR_POWER_STATE;
+
+#define PR_POWER_STATE_UNKNOWN ((PR_POWER_STATE) 0xFFFFFFFF)
+
+#define PR_POWER_STATE_C0 ((PR_POWER_STATE) 0x00000000)
+#define PR_POWER_STATE_C1 ((PR_POWER_STATE) 0x00000001)
+#define PR_POWER_STATE_C2 ((PR_POWER_STATE) 0x00000002)
+#define PR_POWER_STATE_C3 ((PR_POWER_STATE) 0x00000003)
+
+/*
+ * Processor Notifications:
+ * ------------------------
+ */
+#define PR_NOTIFY_PERF_STATES_CHANGE ((BM_NOTIFY) 0x80)
+#define PR_NOTIFY_POWER_STATES_CHANGE ((BM_NOTIFY) 0x81)
+
+
+typedef struct
+{
+ u_int32_t TimeThreshold;
+ u_int32_t CountThreshold;
+ u_int32_t Count;
+ PR_POWER_STATE TargetState;
+} PR_POLICY_VALUES;
+
+/*
+ * PR_CX_STATE_INFO:
+ * -----------------
+ */
+typedef struct
+{
+ u_int32_t Latency;
+ u_int64_t Utilization;
+ PR_POLICY_VALUES PromotionPolicy;
+ PR_POLICY_VALUES DemotionPolicy;
+} PR_CX_STATE_INFO;
+
+/*
+ * PR_POWER_INFO:
+ * --------------
+ */
+typedef struct
+{
+ u_int32_t Count;
+ PR_POWER_STATE ActiveState;
+ PR_CX_STATE_INFO Info[PR_MAX_POWER_STATES];
+} PR_POWER_INFO;
+
+/*
+ * PR_PERFORMANCE_INFO:
+ * --------------------
+ */
+typedef struct
+{
+ u_int32_t Count;
+ /* TODO... */
+} PR_PERFORMANCE_INFO;
+
+/*
+ * PR_THROTTLING_INFO:
+ * -------------------
+ */
+typedef struct
+{
+ u_int32_t Count;
+ u_int32_t Percentage[PR_MAX_THROTTLING_STATES];
+} PR_THROTTLING_INFO;
+
+struct acpi_pr_softc {
+ device_t pr_dev;
+ ACPI_HANDLE pr_handle;
+ PR_POWER_INFO pr_PowerStates;
+ PR_PERFORMANCE_INFO pr_PerformanceStates;
+ PR_THROTTLING_INFO pr_ThrottlingStates;
+ eventhandler_tag pr_idleevent;
+
+ /* local APIC data */
+ PROCESSOR_APIC pr_lapic;
+};
+
+#define PR_MAGIC 0x20555043 /* "CPU " */
+
+static void acpi_pr_identify(driver_t *driver, device_t bus);
+static ACPI_STATUS acpi_pr_identify_cpu(ACPI_HANDLE handle, UINT32 level, void *context, void **status);
+static int acpi_pr_probe(device_t dev);
+static int acpi_pr_attach(device_t dev);
+
+static void acpi_pr_FindLapic(device_t dev, ACPI_HANDLE handle, PROCESSOR_APIC *lapic);
+static ACPI_STATUS acpi_pr_CalculatePowerStates(struct acpi_pr_softc *sc);
+static ACPI_STATUS acpi_pr_CalculatePerformanceStates(struct acpi_pr_softc *sc);
+static ACPI_STATUS acpi_pr_CalculateThrottlingStates(struct acpi_pr_softc *sc);
+static void acpi_pr_IdleHandler(void *arg, int count);
+static ACPI_STATUS acpi_pr_PolicyInitialize(struct acpi_pr_softc *sc);
+
+static device_method_t acpi_pr_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, acpi_pr_identify),
+ DEVMETHOD(device_probe, acpi_pr_probe),
+ DEVMETHOD(device_attach, acpi_pr_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_pr_driver = {
+ "acpi_pr",
+ acpi_pr_methods,
+ sizeof(struct acpi_pr_softc),
+};
+
+devclass_t acpi_pr_devclass;
+DRIVER_MODULE(acpi_pr, acpi, acpi_pr_driver, acpi_pr_devclass, 0, 0);
+
+/*
+ * Scan the \_PR_ scope for processor objects, and attach them accordingly.
+ *
+ * XXX note that we should find the local APIC address and obtain a resource
+ * that we can hand to child devices for access to it...
+ */
+static void
+acpi_pr_identify(driver_t *driver, device_t bus)
+{
+ ACPI_HANDLE handle;
+
+ if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_PR_", &handle) == AE_OK)
+ AcpiWalkNamespace(ACPI_TYPE_PROCESSOR, handle, 2, acpi_pr_identify_cpu, bus, NULL);
+}
+
+/*
+ * Create a child device for CPUs
+ */
+static ACPI_STATUS
+acpi_pr_identify_cpu(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
+{
+ device_t bus = (device_t)context;
+ device_t child;
+ PROCESSOR_APIC lapic;
+
+
+ acpi_pr_FindLapic(bus, handle, &lapic);
+
+ if (lapic.ProcessorEnabled) {
+ if ((child = BUS_ADD_CHILD(bus, 0, "acpi_pr", -1)) == NULL) {
+ device_printf(bus, "could not create CPU device\n");
+ return(AE_OK);
+ }
+ acpi_set_handle(child, handle);
+ acpi_set_magic(child, PR_MAGIC);
+ device_set_desc(child, "processor device");
+ }
+
+ return(AE_OK);
+}
+
+static int
+acpi_pr_probe(device_t dev)
+{
+ if (acpi_get_magic(dev) == PR_MAGIC)
+ return(0);
+ return(ENXIO);
+}
+
+static int
+acpi_pr_attach(device_t dev)
+{
+ struct acpi_pr_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->pr_dev = dev;
+ sc->pr_handle = acpi_get_handle(dev);
+ acpi_pr_FindLapic(dev, sc->pr_handle, &sc->pr_lapic);
+
+ /*
+ * If the APIC information is valid, print it
+ */
+ if (sc->pr_lapic.LocalApicId != (UINT8)0xff)
+ device_printf(dev, "local APIC ID %d\n", sc->pr_lapic.LocalApicId);
+
+ /*
+ * Fetch operational parameters.
+ */
+ if (acpi_pr_CalculatePowerStates(sc) == AE_OK) {
+ acpi_pr_PolicyInitialize(sc);
+ }
+ acpi_pr_CalculatePerformanceStates(sc);
+ acpi_pr_CalculateThrottlingStates(sc);
+
+ /* XXX call MD cpu-identification here? */
+
+ return(0);
+}
+
+/*
+ * Find the Local Apic information for this CPU
+ */
+static void
+acpi_pr_FindLapic(device_t dev, ACPI_HANDLE handle, PROCESSOR_APIC *lapic)
+{
+ ACPI_BUFFER buf;
+ ACPI_STATUS status;
+ APIC_HEADER *hdr;
+ APIC_TABLE *tbl;
+ PROCESSOR_APIC *pap;
+ int len, cpuno;
+
+ /*
+ * Assume that we're not going to suceed in finding/parsing the APIC table.
+ * In this case, CPU 0 is valid, and any other CPU is invalid.
+ */
+ lapic->LocalApicId = 0xff;
+ lapic->ProcessorEnabled = 0;
+ if ((status = AcpiGetProcessorId(handle, &cpuno)) != AE_OK) {
+ device_printf(dev, "error fetching CPU device ID - %s\n", acpi_strerror(status));
+ return;
+ }
+ lapic->ProcessorEnabled = (cpuno == 0);
+
+ /*
+ * Perform the tedious double-get to fetch the actual APIC table, and suck it in.
+ */
+ buf.Length = 0;
+ buf.Pointer = NULL;
+ if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_BUFFER_OVERFLOW) {
+ if (status != AE_NOT_EXIST)
+ device_printf(dev, "error sizing APIC table - %s\n", acpi_strerror(status));
+ return;
+ }
+ if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL)
+ return;
+ if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_OK) {
+ device_printf(dev, "error fetching APIC table - %s\n", acpi_strerror(status));
+ return;
+ }
+
+ /*
+ * Scan the tables looking for this CPU index.
+ */
+ tbl = (APIC_TABLE *)buf.Pointer;
+ len = tbl->header.Length - sizeof(APIC_TABLE);
+ hdr = (APIC_HEADER *)((char *)buf.Pointer + sizeof(APIC_TABLE));
+ while(len > 0) {
+ if (hdr->Length > len) {
+ device_printf(dev, "APIC header corrupt (claims %d bytes where only %d left in structure)\n",
+ hdr->Length, len);
+ break;
+ }
+ /*
+ * If we have found a processor APIC definition with
+ * matching CPU index, copy it out and return.
+ */
+ if (hdr->Type == APIC_PROC) {
+ pap = (PROCESSOR_APIC *)hdr;
+ if (pap->ProcessorApicId == cpuno) {
+ bcopy(pap, lapic, sizeof(*pap));
+ break;
+ }
+ }
+ len -= hdr->Length;
+ hdr = (APIC_HEADER *)((char *)hdr + hdr->Length);
+ }
+ AcpiOsFree(buf.Pointer);
+}
+
+static ACPI_STATUS
+acpi_pr_CalculatePowerStates(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS Status = AE_OK;
+ ACPI_BUFFER Buffer;
+ ACPI_CX_STATE *State = NULL;
+ u_int32_t StateCount = 0;
+ u_int32_t i = 0;
+
+ /*
+ * Set Latency Defaults:
+ * ---------------------
+ * Default state latency to ACPI_UINT32_MAX -- meaning that this state
+ * should not be used by policy. This value is overriden by states
+ * that are present and have usable latencies (e.g. <= 1000us for C3).
+ */
+ for (i = 0; i < PR_MAX_POWER_STATES; i++)
+ sc->pr_PowerStates.Info[i].Latency = ACPI_UINT32_MAX;
+
+ /*
+ * Get Power State Latencies:
+ * --------------------------
+ *
+ * XXX Note that ACPICA will never give us back C2 if it costs more than 100us,
+ * or C3 if it costs more than 1000us, so some of this code is redundant.
+ */
+ Status = acpi_GetIntoBuffer(sc->pr_handle, AcpiGetProcessorCxInfo, &Buffer);
+ if (Status != AE_OK) {
+ device_printf(sc->pr_dev, "could not fetch ProcessorCxInfo - %s\n", acpi_strerror(Status));
+ return(Status);
+ }
+
+ State = (ACPI_CX_STATE*)(Buffer.Pointer);
+ if (State != NULL) {
+ device_printf(sc->pr_dev, "supported power states:");
+ StateCount = Buffer.Length / sizeof(ACPI_CX_STATE);
+ for (i = 0; i < StateCount; i++) {
+ /* XXX C3 isn't supportable in MP configurations, how to best handle this? */
+ if ((State[i].StateNumber < PR_MAX_POWER_STATES) && (State[i].Latency <= 1000)) {
+ printf(" C%d (%dus)", i, State[i].Latency);
+ sc->pr_PowerStates.Info[State[i].StateNumber].Latency = State[i].Latency;
+ }
+ }
+ printf("\n");
+ }
+ sc->pr_PowerStates.Count = PR_MAX_POWER_STATES;
+ sc->pr_PowerStates.ActiveState = PR_POWER_STATE_C1;
+
+ AcpiOsFree(Buffer.Pointer);
+ return(Status);
+}
+
+static ACPI_STATUS
+acpi_pr_CalculatePerformanceStates(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS Status = AE_OK;
+
+ /* TODO... */
+
+ return(Status);
+}
+
+static ACPI_STATUS
+acpi_pr_CalculateThrottlingStates(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS Status = AE_OK;
+ ACPI_BUFFER Buffer;
+ ACPI_CPU_THROTTLING_STATE *State = NULL;
+ u_int32_t StateCount = 0;
+ u_int32_t i = 0;
+
+ /*
+ * Get Throttling States:
+ * ----------------------
+ */
+ Status = acpi_GetIntoBuffer(sc->pr_handle, AcpiGetProcessorThrottlingInfo, &Buffer);
+ if (Status != AE_OK) {
+ device_printf(sc->pr_dev, "could not fetch ThrottlingInfo - %s\n", acpi_strerror(Status));
+ return(Status);
+ }
+
+ State = (ACPI_CPU_THROTTLING_STATE*)(Buffer.Pointer);
+ if (State != NULL) {
+ StateCount = Buffer.Length / sizeof(ACPI_CPU_THROTTLING_STATE);
+ device_printf(sc->pr_dev, "supported throttling states:");
+ for (i = 0; i < StateCount; i++) {
+ if (State[i].StateNumber < PR_MAX_THROTTLING_STATES) {
+ /* TODO: Verify that state is *really* supported by this chipset/processor (e.g. errata). */
+ sc->pr_ThrottlingStates.Percentage[State[i].StateNumber] = State[i].PercentOfClock;
+ sc->pr_ThrottlingStates.Count++;
+ printf(" %d%%", State[i].PercentOfClock);
+ }
+ }
+ printf("\n");
+ }
+
+ AcpiOsFree(Buffer.Pointer);
+ return(Status);
+}
+
+static ACPI_STATUS
+acpi_pr_PolicyInitialize(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS status;
+
+ if ((status = AcpiSetProcessorSleepState(sc->pr_handle, sc->pr_PowerStates.ActiveState)) != AE_OK) {
+ device_printf(sc->pr_dev, "could not set Active sleep state - %s\n", acpi_strerror(status));
+ return(status);
+ }
+
+ /* XXX need to hook ourselves to be called when things go idle */
+/* sc->pr_idleevent = EVENTHANDLER_FAST_REGISTER(idle_event, acpi_pr_IdleHandler, sc, IDLE_PRI_FIRST); */
+ return(AE_OK);
+}
+
+static void
+acpi_pr_IdleHandler(void *arg, int count)
+{
+ struct acpi_pr_softc *sc = (struct acpi_pr_softc *)arg;
+ ACPI_STATUS Status = AE_OK;
+ PR_CX_STATE_INFO *CxState = NULL;
+ PR_POWER_STATE ActiveState = PR_POWER_STATE_UNKNOWN;
+ PR_POWER_STATE NextState = PR_POWER_STATE_UNKNOWN;
+ u_int32_t PmTimerTicks = 0;
+
+ ActiveState = NextState = sc->pr_PowerStates.ActiveState;
+ CxState = &(sc->pr_PowerStates.Info[ActiveState]);
+ CxState->Utilization++;
+
+ /*
+ * Invoke Cx State:
+ * ----------------
+ */
+ if ((Status = AcpiProcessorSleep(sc->pr_handle, &PmTimerTicks)) != AE_OK) {
+ device_printf(sc->pr_dev, "AcpiProcessorSleep() failed - %s\n", acpi_strerror(Status));
+ /*
+ * Something went wrong with the sleep attempt, so give up on trying to do this.
+ */
+/* EVENTHANDLER_FAST_DEREGISTER(idle_event, sc->pr_idleevent);*/
+ device_printf(sc->pr_dev, "disabling CPU power saving\n");
+ return;
+ }
+
+ /*
+ * Check For State Promotion:
+ * --------------------------
+ * Only need to check for promotion on C1 and C2, and then only
+ * when the state has a non-zero count threshold and target state.
+ */
+ if (CxState->PromotionPolicy.CountThreshold && CxState->PromotionPolicy.TargetState &&
+ ((ActiveState == PR_POWER_STATE_C1) || (ActiveState == PR_POWER_STATE_C2))) {
+ /*
+ * Check the amount of time we spent in the Cx state against our
+ * promotion policy. If successful (asleep longer than our threshold)
+ * increment our count and see if a promotion is in order.
+ */
+ if (PmTimerTicks > (CxState->PromotionPolicy.TimeThreshold)) {
+ CxState->PromotionPolicy.Count++;
+ CxState->DemotionPolicy.Count = 0;
+
+ if (CxState->PromotionPolicy.Count >= CxState->PromotionPolicy.CountThreshold)
+ NextState = CxState->PromotionPolicy.TargetState;
+ }
+ }
+
+ /*
+ * Check For State Demotion:
+ * -------------------------
+ * Only need to check for demotion on C2 and C3, and then only
+ * when the state has a non-zero count threshold and target state.
+ */
+ if (CxState->DemotionPolicy.CountThreshold && CxState->DemotionPolicy.TargetState &&
+ ((ActiveState == PR_POWER_STATE_C2) || (ActiveState == PR_POWER_STATE_C3))) {
+ /*
+ * Check the amount of time we spent in the Cx state against our
+ * demotion policy. If unsuccessful (asleep shorter than our threshold)
+ * increment our count and see if a demotion is in order.
+ */
+ if (PmTimerTicks < (CxState->DemotionPolicy.TimeThreshold)) {
+ CxState->DemotionPolicy.Count++;
+ CxState->PromotionPolicy.Count = 0;
+
+ if (CxState->DemotionPolicy.Count >= CxState->DemotionPolicy.CountThreshold)
+ NextState = CxState->DemotionPolicy.TargetState;
+ }
+ }
+
+ /*
+ * New Cx State?
+ * -------------
+ * If so, clean up from the previous Cx state (if necessary).
+ */
+ if (NextState != sc->pr_PowerStates.ActiveState) {
+ if ((Status = AcpiSetProcessorSleepState(sc->pr_handle, NextState)) != AE_OK) {
+ device_printf(sc->pr_dev, "AcpiSetProcessorSleepState() returned error [0x%08X]\n", Status);
+ } else {
+ CxState->PromotionPolicy.Count = 0;
+ CxState->DemotionPolicy.Count = 0;
+ sc->pr_PowerStates.ActiveState = NextState;
+ }
+ }
+}
OpenPOWER on IntegriCloud