arm: Remove "using namespace ArmISA" from arch/arm/isa_traits.hh.
[gem5.git] / src / dev / arm / fvp_base_pwr_ctrl.cc
1 /*
2 * Copyright (c) 2020 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 */
37
38 #include "dev/arm/fvp_base_pwr_ctrl.hh"
39
40 #include "arch/arm/faults.hh"
41 #include "arch/arm/system.hh"
42 #include "arch/arm/utility.hh"
43 #include "cpu/base.hh"
44 #include "cpu/thread_context.hh"
45 #include "debug/FVPBasePwrCtrl.hh"
46 #include "mem/packet_access.hh"
47 #include "params/FVPBasePwrCtrl.hh"
48 #include "sim/system.hh"
49
50 FVPBasePwrCtrl::FVPBasePwrCtrl(FVPBasePwrCtrlParams *const params)
51 : BasicPioDevice(params, 0x1000),
52 regs(),
53 system(*static_cast<ArmSystem *>(sys))
54 {
55 warn_if(sys->multiThread,
56 "Base Power Controller does not support multi-threaded systems\n");
57 system.setPowerController(this);
58 }
59
60 void
61 FVPBasePwrCtrl::init()
62 {
63 // All cores are ON by default (PwrStatus.{l0,l1} = 0b1)
64 corePwrStatus.resize(sys->threads.size(), 0x60000000);
65 for (const auto &tc : sys->threads)
66 poweredCoresPerCluster[tc->socketId()] += 1;
67 BasicPioDevice::init();
68 }
69
70 void
71 FVPBasePwrCtrl::setStandByWfi(ThreadContext *const tc)
72 {
73 PwrStatus *pwrs = getCorePwrStatus(tc);
74
75 if (!pwrs->pwfi)
76 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::setStandByWfi: STANDBYWFI "
77 "asserted for core %d\n", tc->contextId());
78 pwrs->pwfi = 1;
79 if (pwrs->l0 && (pwrs->pp || pwrs->pc))
80 powerCoreOff(tc, pwrs);
81 }
82
83 void
84 FVPBasePwrCtrl::clearStandByWfi(ThreadContext *const tc)
85 {
86 PwrStatus *pwrs = getCorePwrStatus(tc);
87
88 if (pwrs->pwfi)
89 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::clearStandByWfi: STANDBYWFI "
90 "deasserted for core %d\n", tc->contextId());
91 pwrs->pwfi = 0;
92 }
93
94 bool
95 FVPBasePwrCtrl::setWakeRequest(ThreadContext *const tc)
96 {
97 PwrStatus *pwrs = getCorePwrStatus(tc);
98
99 if (!pwrs->pwk)
100 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::setWakeRequest: WakeRequest "
101 "asserted for core %d\n", tc->contextId());
102 pwrs->pwk = 1;
103 if (!pwrs->l0 && pwrs->wen) {
104 pwrs->wk = WK_GICWR;
105 powerCoreOn(tc, pwrs);
106 return true;
107 }
108 return false;
109 }
110
111 void
112 FVPBasePwrCtrl::clearWakeRequest(ThreadContext *const tc)
113 {
114 PwrStatus *pwrs = getCorePwrStatus(tc);
115
116 if (pwrs->pwk)
117 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::clearWakeRequest: "
118 "WakeRequest deasserted for core %d\n", tc->contextId());
119 pwrs->pwk = 0;
120 }
121
122 Tick
123 FVPBasePwrCtrl::read(PacketPtr pkt)
124 {
125 const Addr addr = pkt->getAddr() - pioAddr;
126 const size_t size = pkt->getSize();
127 panic_if(size != 4, "FVPBasePwrCtrl::read: Invalid size %i\n", size);
128
129 uint64_t resp = 0;
130 switch (addr) {
131 case PPOFFR:
132 resp = regs.ppoffr;
133 break;
134 case PPONR:
135 resp = regs.pponr;
136 break;
137 case PCOFFR:
138 resp = regs.pcoffr;
139 break;
140 case PWKUPR:
141 resp = regs.pwkupr;
142 break;
143 case PSYSR:
144 resp = regs.psysr;
145 break;
146 default:
147 warn("FVPBasePwrCtrl::read: Unexpected address (0x%x:%i), "
148 "assuming RAZ\n", addr, size);
149 }
150
151 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::read: 0x%x<-0x%x(%i)\n", resp,
152 addr, size);
153
154 pkt->setUintX(resp, ByteOrder::little);
155 pkt->makeResponse();
156 return pioDelay;
157 }
158
159 Tick
160 FVPBasePwrCtrl::write(PacketPtr pkt)
161 {
162 const Addr addr = pkt->getAddr() - pioAddr;
163 const size_t size = pkt->getSize();
164 panic_if(size != 4, "FVPBasePwrCtrl::write: Invalid size %i\n", size);
165
166 uint64_t data = pkt->getUintX(ByteOrder::little);
167
168 // Software may use the power controller to check for core presence
169 // If core is not present, return an invalid MPID as notification
170 ThreadContext *tc = getThreadContextByMPID(data & MPID_MSK);
171 PwrStatus *pwrs = tc ? getCorePwrStatus(tc) : nullptr;
172 switch (addr) {
173 case PPOFFR:
174 if (!tc) {
175 regs.ppoffr = ~0;
176 } else if (pwrs->l0) {
177 // Set pending power off
178 pwrs->pp = 1;
179 regs.ppoffr = data & MPID_MSK;
180 } else {
181 regs.ppoffr = ~0 & MPID_MSK;
182 }
183 break;
184 case PPONR:
185 if (!tc) {
186 regs.pponr = ~0;
187 } else {
188 if (!pwrs->l0) {
189 pwrs->wk = WK_PPONR;
190 powerCoreOn(tc, pwrs);
191 startCoreUp(tc);
192 regs.pponr = data & MPID_MSK;
193 } else {
194 regs.pponr = ~0 & MPID_MSK;
195 }
196 }
197 break;
198 case PCOFFR:
199 if (!tc) {
200 regs.pcoffr = ~0;
201 } else if (pwrs->l0) {
202 // Power off all cores in the cluster
203 for (const auto &tco : sys->threads) {
204 if (tc->socketId() == tco->socketId()) {
205 PwrStatus *npwrs = getCorePwrStatus(tco);
206 // Set pending cluster power off
207 npwrs->pc = 1;
208 if (npwrs->l0 && npwrs->pwfi)
209 powerCoreOff(tco, npwrs);
210 }
211 }
212 } else {
213 regs.pcoffr = ~0 & MPID_MSK;
214 }
215 break;
216 case PWKUPR:
217 if (!tc) {
218 regs.pwkupr = ~0;
219 } else {
220 // Update WEN value
221 pwrs->wen = bits(data, 31);
222 // Power-on if there is any pending Wakeup Requests
223 if (!pwrs->l0 && pwrs->wen && pwrs->pwk) {
224 pwrs->wk = WK_GICWR;
225 powerCoreOn(tc, pwrs);
226 startCoreUp(tc);
227 }
228 regs.pwkupr = data & (MPID_MSK | (1 << 31));
229 }
230 break;
231 case PSYSR:
232 if (!tc)
233 regs.psysr = ~0;
234 else
235 regs.psysr = (data & MPID_MSK) | (((uint32_t) *pwrs) & ~MPID_MSK);
236 break;
237 default:
238 warn("FVPBasePwrCtrl::write: Unexpected address (0x%x:%i), "
239 "assuming WI\n", addr, size);
240 }
241
242 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::write: 0x%x->0x%x(%i)\n", data,
243 addr, size);
244
245 pkt->makeResponse();
246 return pioDelay;
247 }
248
249 FVPBasePwrCtrl::PwrStatus *
250 FVPBasePwrCtrl::getCorePwrStatus(ThreadContext *const tc)
251 {
252 PwrStatus *pwrs = &corePwrStatus[tc->contextId()];
253 pwrs->l1 = poweredCoresPerCluster[tc->socketId()] > 0;
254 return pwrs;
255 }
256
257 ThreadContext *
258 FVPBasePwrCtrl::getThreadContextByMPID(uint32_t mpid) const
259 {
260 for (auto &tc : sys->threads) {
261 if (mpid == ArmISA::getAffinity(&system, tc))
262 return tc;
263 }
264 return nullptr;
265 }
266
267 void
268 FVPBasePwrCtrl::powerCoreOn(ThreadContext *const tc, PwrStatus *const pwrs)
269 {
270 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::powerCoreOn: Powering ON "
271 "core %d\n", tc->contextId());
272 pwrs->l0 = 1;
273 poweredCoresPerCluster[tc->socketId()]++;
274 // Clear pending power-offs to the core
275 pwrs->pp = 0;
276 // Clear pending power-offs to the core's cluster
277 for (const auto &tco : sys->threads) {
278 if (tc->socketId() == tco->socketId()) {
279 PwrStatus *npwrs = getCorePwrStatus(tco);
280 npwrs->pc = 0;
281 }
282 }
283 tc->getCpuPtr()->powerState->set(Enums::PwrState::ON);
284 }
285
286 void
287 FVPBasePwrCtrl::powerCoreOff(ThreadContext *const tc, PwrStatus *const pwrs)
288 {
289 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::powerCoreOff: Powering OFF "
290 "core %d\n", tc->contextId());
291 pwrs->l0 = 0;
292 poweredCoresPerCluster[tc->socketId()]--;
293 // Clear pending power-offs to the core
294 pwrs->pp = 0;
295 pwrs->pc = 0;
296 // Clear power-on reason
297 pwrs->wk = 0;
298 tc->getCpuPtr()->powerState->set(Enums::PwrState::OFF);
299 }
300
301 void
302 FVPBasePwrCtrl::startCoreUp(ThreadContext *const tc)
303 {
304 DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::startCoreUp: Starting core %d "
305 "from the power controller\n", tc->contextId());
306 clearStandByWfi(tc);
307 clearWakeRequest(tc);
308
309 // InitCPU
310 ArmISA::Reset().invoke(tc);
311 tc->activate();
312 }
313
314 FVPBasePwrCtrl *
315 FVPBasePwrCtrlParams::create()
316 {
317 return new FVPBasePwrCtrl(this);
318 }