0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * CDDL HEADER START
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * The contents of this file are subject to the terms of the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Common Development and Distribution License (the "License").
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * You may not use this file except in compliance with the License.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * or http://www.opensolaris.org/os/licensing.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * See the License for the specific language governing permissions
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * and limitations under the License.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * When distributing Covered Code, include this CDDL HEADER in each
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * If applicable, add the following below this CDDL HEADER, with the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * fields enclosed by brackets "[]" replaced with your own identifying
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * information: Portions Copyright [yyyy] [name of copyright owner]
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * CDDL HEADER END
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Use is subject to license terms.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe#include <sys/cpu_pm.h>
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe#include <sys/cmn_err.h>
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe#include <sys/time.h>
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe#include <sys/sdt.h>
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Solaris Event Based CPU Power Manager
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * This file implements platform independent event based CPU power management.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * When CPUs are configured into the system, the CMT scheduling subsystem will
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * query the platform to determine if the CPU belongs to any power management
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * domains. That is, sets of CPUs that share power management states.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Active Power Management domains represent a group of CPUs across which the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Operating System can request speed changes (which may in turn result
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * in voltage changes). This allows the operating system to trade off
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * performance for power savings.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Idle Power Management domains can enter power savings states when they are
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * unutilized. These states allow the Operating System to trade off power
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * for performance (in the form of latency to transition from the idle state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to an active one).
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * For each active and idle power domain the CMT subsystem instantiates, a
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * cpupm_domain_t structure is created. As the dispatcher schedules threads
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to run on the system's CPUs, it will also track the utilization of the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * enumerated power domains. Significant changes in utilization will result
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * in the dispatcher sending the power manager events that relate to the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * utilization of the power domain. The power manager recieves the events,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * and in the context of the policy objectives in force, may decide to request
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * the domain's power/performance state be changed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Under the "elastic" CPUPM policy, when the utilization rises, the CPU power
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * manager will request the CPUs in the domain run at their fastest (and most
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * power consuming) state. When the domain becomes idle (utilization at zero),
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * the power manager will request that the CPUs run at a speed that saves the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * most power.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * The advantage of this scheme, is that the CPU power manager working with the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * dispatcher can be extremely responsive to changes in utilization. Optimizing
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * for performance in the presence of utilization, and power savings in the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * presence of idleness. Such close collaboration with the dispatcher has other
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * benefits that will play out in the form of more sophisticated power /
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * performance policy in the near future.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Avoiding state thrashing in the presence of transient periods of utilization
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * and idleness while still being responsive to non-transient periods is key.
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * The power manager implements a "governor" that is used to throttle
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * state transitions when a significant amount of transient idle or transient
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * work is detected.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Kernel background activity (e.g. taskq threads) are by far the most common
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * form of transient utilization. Ungoverned in the face of this utililzation,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * hundreds of state transitions per second would result on an idle system.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Transient idleness is common when a thread briefly yields the CPU to
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * wait for an event elsewhere in the system. Where the idle period is short
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * enough, the overhead associated with making the state transition doesn't
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * justify the power savings.
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe *
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * The following is the state machine for the governor implemented by
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * cpupm_utilization_event():
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe *
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * ----->---tw---->-----
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * / \
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * (I)-<-ti-<- -<-ntw-<(W)
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * | \ / |
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * \ \ / /
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * >-nti/rm->(D)--->-tw->-
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * Key:
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe *
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * States
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - (D): Default (ungoverned)
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - (W): Transient work governed
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - (I): Transient idle governed
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * State Transitions
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - tw: transient work
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - ti: transient idleness
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - ntw: non-transient work
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - nti: non-transient idleness
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * - rm: thread remain event
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxestatic cpupm_domain_t *cpupm_domains = NULL;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Uninitialized state of CPU power management is disabled
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_policy_t cpupm_policy = CPUPM_POLICY_DISABLED;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Periods of utilization lasting less than this time interval are characterized
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * as transient. State changes associated with transient work are considered
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to be mispredicted. That is, it's not worth raising and lower power states
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * where the utilization lasts for less than this interval.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxehrtime_t cpupm_tw_predict_interval;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Periods of idleness lasting less than this time interval are characterized
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * as transient. State changes associated with transient idle are considered
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to be mispredicted. That is, it's not worth lowering and raising power
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * states where the idleness lasts for less than this interval.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxehrtime_t cpupm_ti_predict_interval;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Number of mispredictions after which future transitions will be governed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxeint cpupm_mispredict_thresh = 4;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Likewise, the number of mispredicted governed transitions after which the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * governor will be removed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxeint cpupm_mispredict_gov_thresh = 4;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * The transient work and transient idle prediction intervals are specified
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * here. Tuning them higher will result in the transient work, and transient
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * idle governors being used more aggresively, which limits the frequency of
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * state transitions at the expense of performance and power savings,
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * respectively. The intervals are specified in nanoseconds.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * 400 usec
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe#define CPUPM_DEFAULT_TI_INTERVAL 400000
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe/*
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * 400 usec
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe#define CPUPM_DEFAULT_TW_INTERVAL 400000
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxehrtime_t cpupm_ti_gov_interval = CPUPM_DEFAULT_TI_INTERVAL;
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxehrtime_t cpupm_tw_gov_interval = CPUPM_DEFAULT_TW_INTERVAL;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxestatic void cpupm_governor_initialize(void);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxestatic void cpupm_state_change_global(cpupm_dtype_t, cpupm_state_name_t);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_policy_t
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_get_policy(void)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (cpupm_policy);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxeint
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_set_policy(cpupm_policy_t new_policy)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe static int gov_init = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe int result = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe mutex_enter(&cpu_lock);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (new_policy == cpupm_policy) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe mutex_exit(&cpu_lock);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (result);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Pausing CPUs causes a high priority thread to be scheduled
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * on all other CPUs (besides the current one). This locks out
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * other CPUs from making CPUPM state transitions.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe switch (new_policy) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe case CPUPM_POLICY_DISABLED:
0ed5c46e82c989cfa9726d9dae452e3d24ef83beJosef 'Jeff' Sipek pause_cpus(NULL, NULL);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_policy = CPUPM_POLICY_DISABLED;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe start_cpus();
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe result = cmt_pad_disable(PGHW_POW_ACTIVE);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Once PAD has been enabled, it should always be possible
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to disable it.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe ASSERT(result == 0);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Bring all the active power domains to the maximum
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * performance state.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_state_change_global(CPUPM_DTYPE_ACTIVE,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe CPUPM_STATE_MAX_PERF);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe case CPUPM_POLICY_ELASTIC:
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe result = cmt_pad_enable(PGHW_POW_ACTIVE);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (result < 0) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Failed to enable PAD across the active power
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * domains, which may well be because none were
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * enumerated.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * Initialize the governor parameters the first time through.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (gov_init == 0) {
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe cpupm_governor_initialize();
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe gov_init = 1;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe
0ed5c46e82c989cfa9726d9dae452e3d24ef83beJosef 'Jeff' Sipek pause_cpus(NULL, NULL);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_policy = CPUPM_POLICY_ELASTIC;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe start_cpus();
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe default:
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cmn_err(CE_WARN, "Attempt to set unknown CPUPM policy %d\n",
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe new_policy);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe ASSERT(0);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe mutex_exit(&cpu_lock);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (result);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Look for an existing power domain
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxestatic cpupm_domain_t *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_domain_find(id_t id, cpupm_dtype_t type)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe ASSERT(MUTEX_HELD(&cpu_lock));
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *dom;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom = cpupm_domains;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe while (dom != NULL) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (id == dom->cpd_id && type == dom->cpd_type)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom = dom->cpd_next;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (NULL);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Create a new domain
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxestatic cpupm_domain_t *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_domain_create(id_t id, cpupm_dtype_t type)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *dom;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe ASSERT(MUTEX_HELD(&cpu_lock));
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom = kmem_zalloc(sizeof (cpupm_domain_t), KM_SLEEP);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_id = id;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_type = type;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /* Link into the known domain list */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_next = cpupm_domains;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domains = dom;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxestatic void
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_domain_state_enum(struct cpu *cp, cpupm_domain_t *dom)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * In the envent we're enumerating because the domain's state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * configuration has changed, toss any existing states.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom->cpd_nstates > 0) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe kmem_free(dom->cpd_states,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe sizeof (cpupm_state_t) * dom->cpd_nstates);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_nstates = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Query to determine the number of states, allocate storage
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * large enough to hold the state information, and pass it back
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to the platform driver to complete the enumeration.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_nstates = cpupm_plat_state_enumerate(cp, dom->cpd_type, NULL);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom->cpd_nstates == 0)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_states =
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe kmem_zalloc(dom->cpd_nstates * sizeof (cpupm_state_t), KM_SLEEP);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe (void) cpupm_plat_state_enumerate(cp, dom->cpd_type, dom->cpd_states);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Initialize the specified type of power domain on behalf of the CPU
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_domain_t *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_domain_init(struct cpu *cp, cpupm_dtype_t type)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *dom;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe id_t did;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe ASSERT(MUTEX_HELD(&cpu_lock));
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Instantiate the domain if it doesn't already exist
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * and enumerate its power states.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe did = cpupm_domain_id(cp, type);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom = cpupm_domain_find(did, type);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom == NULL) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom = cpupm_domain_create(did, type);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_state_enum(cp, dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Named state initialization
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (type == CPUPM_DTYPE_ACTIVE) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * For active power domains, the highest performance
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * state is defined as first state returned from
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * the domain enumeration.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_MAX_PERF] =
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe &dom->cpd_states[0];
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_LOW_POWER] =
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe &dom->cpd_states[dom->cpd_nstates - 1];
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Begin by assuming CPU is running at the max perf state.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_state = dom->cpd_named_states[CPUPM_STATE_MAX_PERF];
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Return the id associated with the given type of domain
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to which cp belongs
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxeid_t
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_domain_id(struct cpu *cp, cpupm_dtype_t type)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (cpupm_plat_domain_id(cp, type));
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Initiate a state change for the specified domain on behalf of cp
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxeint
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_change_state(struct cpu *cp, cpupm_domain_t *dom, cpupm_state_t *state)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (cpupm_plat_change_state(cp, state) < 0)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (-1);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE2(cpupm__change__state,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_state_t *, state);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_state = state;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return (0);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Interface into the CPU power manager to indicate a significant change
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * in utilization of the specified active power domain
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxevoid
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_utilization_event(struct cpu *cp, hrtime_t now, cpupm_domain_t *dom,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_util_event_t event)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_state_t *new_state = NULL;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe hrtime_t last;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (cpupm_policy == CPUPM_POLICY_DISABLED) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * What follows is a simple elastic power state management policy.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * If the utilization has become non-zero, and the domain was
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * previously at it's lowest power state, then transition it
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to the highest state in the spirit of "race to idle".
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * If the utilization has dropped to zero, then transition the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * domain to its lowest power state.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe *
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * Statistics are maintained to implement a governor to reduce state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * transitions resulting from either transient work, or periods of
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * transient idleness on the domain.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe switch (event) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe case CPUPM_DOM_REMAIN_BUSY:
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * We've received an event that the domain is running a thread
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * that's made it to the end of it's time slice. If we are at
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * low power, then raise it. If the transient work governor
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * is engaged, then remove it.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom->cpd_state ==
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_LOW_POWER]) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe new_state =
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_MAX_PERF];
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (dom->cpd_governor == CPUPM_GOV_TRANS_WORK) {
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe dom->cpd_governor = CPUPM_GOV_DISENGAGED;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_tw = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe case CPUPM_DOM_BUSY_FROM_IDLE:
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe last = dom->cpd_last_lower;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_last_raise = now;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE3(cpupm__raise__req,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe hrtime_t, last,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe hrtime_t, now);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom->cpd_state ==
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_LOW_POWER]) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * There's non-zero utilization, and the domain is
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * running in the lower power state. Before we
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * consider raising power, check if the preceeding
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * idle period was transient in duration.
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe *
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * If the domain is already transient work governed,
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * then we don't bother maintaining transient idle
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * statistics, as the presence of enough transient work
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * can also make the domain frequently transiently idle.
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * In this case, we still want to remain transient work
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * governed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (dom->cpd_governor == CPUPM_GOV_DISENGAGED) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if ((now - last) < cpupm_ti_predict_interval) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * We're raising the domain power and
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * we *just* lowered it. Consider
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * this a mispredicted power state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * transition due to a transient
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * idle period.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (++dom->cpd_ti >=
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_mispredict_thresh) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * There's enough transient
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * idle transitions to
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * justify governing future
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * lowering requests.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe dom->cpd_governor =
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe CPUPM_GOV_TRANS_IDLE;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_ti = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE1(
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm__ti__governed,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe } else {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * We correctly predicted the last
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * lowering.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_ti = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (dom->cpd_governor == CPUPM_GOV_TRANS_WORK) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Raise requests are governed due to
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * transient work.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE1(cpupm__raise__governed,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Prepare to transition to the higher power state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe new_state = dom->cpd_named_states[CPUPM_STATE_MAX_PERF];
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe } else if (dom->cpd_state ==
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_MAX_PERF]) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Utilization is non-zero, and we're already running
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * in the higher power state. Take this opportunity to
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * perform some book keeping if the last lowering
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * request was governed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (dom->cpd_governor == CPUPM_GOV_TRANS_IDLE) {
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if ((now - last) >= cpupm_ti_predict_interval) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * The domain is transient idle
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * governed, and we mispredicted
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * governing the last lowering request.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (++dom->cpd_ti >=
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_mispredict_gov_thresh) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * There's enough non-transient
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * idle periods to justify
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * removing the governor.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe dom->cpd_governor =
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe CPUPM_GOV_DISENGAGED;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_ti = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE1(
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm__ti__ungoverned,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe } else {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Correctly predicted governing the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * last lowering request.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_ti = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe case CPUPM_DOM_IDLE_FROM_BUSY:
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe last = dom->cpd_last_raise;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_last_lower = now;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE3(cpupm__lower__req,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe hrtime_t, last,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe hrtime_t, now);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom->cpd_state ==
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_MAX_PERF]) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * The domain is idle, and is running in the highest
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * performance state. Before we consider lowering power,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * perform some book keeping for the transient work
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * governor.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (dom->cpd_governor == CPUPM_GOV_DISENGAGED) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if ((now - last) < cpupm_tw_predict_interval) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * We're lowering the domain power and
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * we *just* raised it. Consider the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * last raise mispredicted due to
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * transient work.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (++dom->cpd_tw >=
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_mispredict_thresh) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * There's enough transient work
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * transitions to justify
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * governing future raise
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * requests.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe dom->cpd_governor =
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe CPUPM_GOV_TRANS_WORK;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_tw = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE1(
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm__tw__governed,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe } else {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * We correctly predicted during the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * last raise.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_tw = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (dom->cpd_governor == CPUPM_GOV_TRANS_IDLE) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Lowering requests are governed due to
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * transient idleness.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE1(cpupm__lowering__governed,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Prepare to transition to a lower power state.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe new_state =
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_LOW_POWER];
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe } else if (dom->cpd_state ==
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_LOW_POWER]) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * The domain is idle, and we're already running in
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * the lower power state. Take this opportunity to
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * perform some book keeping if the last raising
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * request was governed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe if (dom->cpd_governor == CPUPM_GOV_TRANS_WORK) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if ((now - last) >= cpupm_tw_predict_interval) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * The domain is transient work
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * governed, and we mispredicted
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * governing the last raising request.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (++dom->cpd_tw >=
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_mispredict_gov_thresh) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * There's enough non-transient
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * work to justify removing
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * the governor.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe dom->cpd_governor =
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe CPUPM_GOV_DISENGAGED;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_tw = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe DTRACE_PROBE1(
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm__tw__ungoverned,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *, dom);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe } else {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * We correctly predicted governing
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * the last raise.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_tw = 0;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Change the power state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Not much currently done if this doesn't succeed
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (new_state)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe (void) cpupm_change_state(cp, dom, new_state);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Interface called by platforms to dynamically change the
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * MAX performance cpupm state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxevoid
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_redefine_max_activepwr_state(struct cpu *cp, int max_perf_level)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *dom;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe id_t did;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_dtype_t type = CPUPM_DTYPE_ACTIVE;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe boolean_t change_state = B_FALSE;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_state_t *new_state = NULL;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe did = cpupm_domain_id(cp, type);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (MUTEX_HELD(&cpu_lock)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dom = cpupm_domain_find(did, type);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&cpu_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dom = cpupm_domain_find(did, type);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&cpu_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Can use a lock to avoid changing the power state of the cpu when
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * CPUPM_STATE_MAX_PERF is getting changed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Since the occurance of events to change MAX_PERF is not frequent,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * it may not be a good idea to overburden with locks. In the worst
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * case, for one cycle the power may not get changed to the required
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * level
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom != NULL) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (dom->cpd_state ==
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_MAX_PERF]) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe change_state = B_TRUE;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * If an out of range level is passed, use the lowest supported
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * speed.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (max_perf_level >= dom->cpd_nstates &&
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_nstates > 1) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe max_perf_level = dom->cpd_nstates - 1;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_MAX_PERF] =
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe &dom->cpd_states[max_perf_level];
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * If the current state is MAX_PERF, change the current state
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * to the new MAX_PERF
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (change_state) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe new_state =
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[CPUPM_STATE_MAX_PERF];
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if (new_state) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe (void) cpupm_change_state(cp, dom, new_state);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * Initialize the parameters for the transience governor state machine
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxestatic void
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_governor_initialize(void)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * The default prediction intervals are specified in nanoseconds.
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * Convert these to the equivalent in unscaled hrtime, which is the
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe * format of the timestamps passed to cpupm_utilization_event()
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe cpupm_ti_predict_interval = unscalehrtime(cpupm_ti_gov_interval);
113b131b48d0e653a91612bb4461ea90adbd849aEric Saxe cpupm_tw_predict_interval = unscalehrtime(cpupm_tw_gov_interval);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe/*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Initiate a state change in all CPUPM domain instances of the specified type
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxestatic void
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxecpupm_state_change_global(cpupm_dtype_t type, cpupm_state_name_t state)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe{
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpu_t *cp;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe pg_cmt_t *pwr_pg;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe cpupm_domain_t *dom;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe group_t *hwset;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe group_iter_t giter;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe pg_cpu_itr_t cpu_iter;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe pghw_type_t hw;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe ASSERT(MUTEX_HELD(&cpu_lock));
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe switch (type) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe case CPUPM_DTYPE_ACTIVE:
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe hw = PGHW_POW_ACTIVE;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe break;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe default:
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Power domain types other than "active" unsupported.
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe ASSERT(type == CPUPM_DTYPE_ACTIVE);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe if ((hwset = pghw_set_lookup(hw)) == NULL)
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe return;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Iterate over the power domains
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe group_iter_init(&giter);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe while ((pwr_pg = group_iterate(hwset, &giter)) != NULL) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom = (cpupm_domain_t *)pwr_pg->cmt_pg.pghw_handle;
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe /*
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe * Iterate over the CPUs in each domain
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe */
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe PG_CPU_ITR_INIT(pwr_pg, cpu_iter);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe while ((cp = pg_cpu_next(&cpu_iter)) != NULL) {
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe (void) cpupm_change_state(cp, dom,
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe dom->cpd_named_states[state]);
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe }
0e7515250c8395f368aa45fb9acae7c4f8f8b786Eric Saxe}