2 * Copyright (c) 2017, 2019-2020 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include "sim/power_domain.hh"
40 #include <unordered_map>
42 #include "base/trace.hh"
43 #include "debug/PowerDomain.hh"
45 PowerDomain::PowerDomain(const PowerDomainParams
&p
) :
48 pwrStateUpdateEvent(*this),
51 // Check if there is at least one leader
52 fatal_if(leaders
.empty(), "No leaders registered in %s!)", name());
54 // Go over the leaders and register this power domain with them
55 for (auto leader
: leaders
) {
56 leader
->setControlledDomain(this);
59 // We will assume a power domain to start in the most performant p-state
60 // This will be corrected during startup()
61 leaderTargetState
= Enums::PwrState::ON
;
62 _currState
= Enums::PwrState::ON
;
66 PowerDomain::addFollower(PowerState
* pwr_obj
)
68 DPRINTF(PowerDomain
, "%s is a follower in %s\n", pwr_obj
->name(), name());
69 followers
.push_back(pwr_obj
);
73 PowerDomain::startup()
75 DPRINTF(PowerDomain
, "Checks at startup\n");
76 // Check if the leaders and followers have the correct power states.
77 DPRINTF(PowerDomain
, "Checking power state of leaders & followers\n");
78 for (const auto &objs
: { leaders
, followers
}) {
79 for (const auto &obj
: objs
) {
80 const auto & states
= obj
->getPossibleStates();
81 auto it
= states
.find(Enums::PwrState::ON
);
82 fatal_if(it
== states
.end(),
83 "%s in %s does not have the required power states to be "
84 "part of a PowerDomain i.e. the ON state!", obj
->name(),
89 // Now all objects have been checked for the minimally required power
90 // states, calculate the possible power states for the domain. This is the
91 // intersection between the possible power states of the followers and
93 calculatePossiblePwrStates();
95 // Check that there is no objects which is both a leader and a
97 DPRINTF(PowerDomain
, "Checking for double entries\n");
98 for (auto follower
: followers
) {
99 for (auto leader
: leaders
) {
100 fatal_if(leader
== follower
, "%s is both a leader and follower"
101 " in %s\n!", leader
->name(), name());
104 // Record the power states of the leaders and followers
105 DPRINTF(PowerDomain
, "Recording the current power states in domain\n");
106 for (auto leader
: leaders
) {
107 Enums::PwrState pws
= leader
->get();
108 fatal_if(pws
== Enums::PwrState::UNDEFINED
,
109 "%s is in the UNDEFINED power state, not acceptable as "
110 "leader!", leader
->name());
113 // Calculate the power state of the domain, only looking at leader
114 leaderTargetState
= calculatePowerDomainState();
115 // Set the power states of the followers, based upon leaderTargetState.
116 setFollowerPowerStates();
120 PowerDomain::isPossiblePwrState(Enums::PwrState p_state
)
122 for (const auto &objs
: { leaders
, followers
}) {
123 for (const auto &obj
: objs
) {
124 const auto &obj_states
= obj
->getPossibleStates();
125 if (obj_states
.find(p_state
) == obj_states
.end()) {
134 PowerDomain::calculatePossiblePwrStates()
136 assert(possibleStates
.empty());
137 for (auto p_state
: leaders
[0]->getPossibleStates()) {
138 if (isPossiblePwrState(p_state
)) {
139 possibleStates
.emplace(p_state
);
140 DPRINTF(PowerDomain
, "%u/%s is a p-state\n", p_state
,
141 Enums::PwrStateStrings
[p_state
]);
147 PowerDomain::calculatePowerDomainState(
148 const std::vector
<Enums::PwrState
> &f_states
)
150 DPRINTF(PowerDomain
, "Calculating the power state\n");
151 Enums::PwrState most_perf_state
= Enums::PwrState::Num_PwrState
;
152 std::string most_perf_leader
;
153 for (auto leader
: leaders
) {
154 Enums::PwrState pw
= leader
->get();
155 if (pw
< most_perf_state
) {
156 most_perf_state
= pw
;
157 most_perf_leader
= leader
->name();
160 assert(most_perf_state
!= Enums::PwrState::Num_PwrState
);
161 DPRINTF(PowerDomain
, "Most performant leader is %s, at %u\n",
162 most_perf_leader
, most_perf_state
);
164 // If asked to check the power states of the followers (f_states contains
165 // the power states of the followers)
166 if (!f_states
.empty()) {
167 for (Enums::PwrState f_pw
: f_states
) {
168 // Ignore UNDEFINED state of follower, at startup the followers
169 // might be in the UNDEFINED state, PowerDomain will pull them up
170 if ((f_pw
!= Enums::PwrState::UNDEFINED
) &&
171 (f_pw
< most_perf_state
)) {
172 most_perf_state
= f_pw
;
175 DPRINTF(PowerDomain
, "Most performant state, including followers "
176 "is %u\n", most_perf_state
);
178 return most_perf_state
;
182 PowerDomain::setFollowerPowerStates()
184 // Loop over all followers and tell them to change their power state so
185 // they match that of the power domain (or a more performant power state)
186 std::vector
<Enums::PwrState
> matched_states
;
187 for (auto follower
: followers
) {
188 Enums::PwrState actual_pws
=
189 follower
->matchPwrState(leaderTargetState
);
190 matched_states
.push_back(actual_pws
);
191 assert(actual_pws
<= leaderTargetState
);
192 DPRINTF(PowerDomain
, "%u matched domain power state (%u) with %u\n",
193 follower
->name(), leaderTargetState
,
196 // Now the power states of the follower have been changed recalculate the
197 // power state of the domain as a whole, including followers
198 Enums::PwrState new_power_state
=
199 calculatePowerDomainState(matched_states
);
200 if (new_power_state
!= _currState
) {
201 // Change in power state of the domain, so update. Updates in power
202 // state need to happen via set() so it can propagate to
203 // overarching power domains (if there are any).
204 DPRINTF(PowerDomain
, "Updated power domain state to %u\n",
206 set(new_power_state
);
211 PowerDomain::pwrStateChangeCallback(Enums::PwrState new_pwr_state
,
214 DPRINTF(PowerDomain
, "PwrState update to %u by %s\n", new_pwr_state
,
217 Enums::PwrState old_target_state
= leaderTargetState
;
218 // Calculate the power state of the domain, based on the leaders
219 if (new_pwr_state
< _currState
) {
220 // The power state of the power domain always needs to match that of
221 // the most performant leader so no need to go over the other leaders
222 // The power state need to be changed via a the PwrStateCall() so any
223 // overarching power domains get informed
224 leaderTargetState
= new_pwr_state
;
226 // Need to calculate the newly required power state, based on the
227 // leaders only and change to that state.
228 leaderTargetState
= calculatePowerDomainState();
230 if (old_target_state
!= leaderTargetState
) {
231 // The followers will try to match that power state requested by the
232 // leaders in in the update event, based upon the actual power state,
233 // we will 'officially' change the power state of the domain by calling
235 schedule(pwrStateUpdateEvent
, curTick() + updateLatency
);
236 DPRINTF(PowerDomain
, "TargetState change from %u to %u, followers will"
237 "be updated in %u ticks\n", old_target_state
,
238 leaderTargetState
, updateLatency
);
239 stats
.numLeaderCallsChangingState
++;
241 stats
.numLeaderCalls
++;
244 PowerDomain::PowerDomainStats::PowerDomainStats(PowerDomain
&pd
)
246 ADD_STAT(numLeaderCalls
, UNIT_COUNT
,
247 "Number of calls by leaders to change power domain state"),
248 ADD_STAT(numLeaderCallsChangingState
, UNIT_COUNT
,
249 "Number of calls by leader to change power domain state actually "
250 "resulting in a power state change")
255 PowerDomain::PowerDomainStats::regStats()
257 Stats::Group::regStats();
260 .flags(Stats::nozero
)
262 numLeaderCallsChangingState
263 .flags(Stats::nozero
)