2 * Copyright (c) 2011-2014 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.
42 #include "arch/arm/pmu.hh"
44 #include "base/trace.hh"
45 #include "cpu/base.hh"
46 #include "debug/Checkpoint.hh"
47 #include "debug/PMUVerbose.hh"
48 #include "dev/arm/base_gic.hh"
49 #include "dev/arm/realview.hh"
50 #include "params/ArmPMU.hh"
54 const MiscReg
PMU::reg_pmcr_wr_mask
= 0x39;
56 PMU::PMU(const ArmPMUParams
*p
)
57 : SimObject(p
), BaseISADevice(),
58 reg_pmcnten(0), reg_pmcr(0),
59 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
62 counters(p
->eventCounters
),
64 pmuInterrupt(p
->pmuInterrupt
),
67 DPRINTF(PMUVerbose
, "Initializing the PMU.\n");
69 if (p
->eventCounters
> 31) {
70 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
74 /* Setup the performance counter ID registers */
75 reg_pmcr_conf
.imp
= 0x41; // ARM Ltd.
76 reg_pmcr_conf
.idcode
= 0x00;
77 reg_pmcr_conf
.n
= p
->eventCounters
;
79 // Setup the hard-coded cycle counter, which is equivalent to
80 // architected counter event type 0x11.
81 cycleCounter
.eventId
= 0x11;
89 PMU::addEventProbe(unsigned int id
, SimObject
*obj
, const char *probe_name
)
91 DPRINTF(PMUVerbose
, "PMU: Adding event type '0x%x' as probe %s:%s\n",
92 id
, obj
->name(), probe_name
);
93 pmuEventTypes
.insert(std::make_pair(id
, EventType(obj
, probe_name
)));
95 // Flag the event as available in the PMCEID register if it is an
98 reg_pmceid
|= (1 << id
);
104 // Re-attach enabled counters after a resume in case they changed.
109 PMU::setMiscReg(int misc_reg
, MiscReg val
)
111 DPRINTF(PMUVerbose
, "setMiscReg(%s, 0x%x)\n",
112 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
114 switch (unflattenMiscReg(misc_reg
)) {
115 case MISCREG_PMCR_EL0
:
120 case MISCREG_PMCNTENSET_EL0
:
121 case MISCREG_PMCNTENSET
:
126 case MISCREG_PMCNTENCLR_EL0
:
127 case MISCREG_PMCNTENCLR
:
132 case MISCREG_PMOVSCLR_EL0
:
137 case MISCREG_PMSWINC_EL0
:
138 case MISCREG_PMSWINC
:
139 for (int i
= 0; i
< counters
.size(); ++i
) {
140 CounterState
&ctr(getCounter(i
));
141 if (ctr
.enabled
&& (val
& (1 << i
)))
146 case MISCREG_PMCCNTR_EL0
:
147 case MISCREG_PMCCNTR
:
148 cycleCounter
.value
= val
;
151 case MISCREG_PMSELR_EL0
:
156 case MISCREG_PMCEID0_EL0
:
157 case MISCREG_PMCEID0
:
158 case MISCREG_PMCEID1_EL0
:
159 case MISCREG_PMCEID1
:
163 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
164 setCounterTypeRegister(misc_reg
- MISCREG_PMEVCNTR0_EL0
, val
);
167 case MISCREG_PMCCFILTR
:
168 case MISCREG_PMCCFILTR_EL0
:
169 DPRINTF(PMUVerbose
, "Setting PMCCFILTR: 0x%x\n", val
);
170 setCounterTypeRegister(PMCCNTR
, val
);
173 case MISCREG_PMXEVTYPER_PMCCFILTR
:
174 case MISCREG_PMXEVTYPER_EL0
:
175 case MISCREG_PMXEVTYPER
:
176 DPRINTF(PMUVerbose
, "Setting counter type: "
177 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
178 reg_pmselr
, reg_pmselr
.sel
, val
);
179 setCounterTypeRegister(reg_pmselr
.sel
, val
);
182 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
:
183 setCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
, val
);
186 case MISCREG_PMXEVCNTR_EL0
:
187 case MISCREG_PMXEVCNTR
:
188 setCounterValue(reg_pmselr
.sel
, val
);
191 case MISCREG_PMUSERENR_EL0
:
192 case MISCREG_PMUSERENR
:
196 case MISCREG_PMINTENSET_EL1
:
197 case MISCREG_PMINTENSET
:
201 case MISCREG_PMINTENCLR_EL1
:
202 case MISCREG_PMINTENCLR
:
206 case MISCREG_PMOVSSET_EL0
:
207 case MISCREG_PMOVSSET
:
212 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
215 warn("Not doing anything for write to miscreg %s\n",
216 miscRegName
[misc_reg
]);
220 PMU::readMiscReg(int misc_reg
)
222 MiscReg
val(readMiscRegInt(misc_reg
));
223 DPRINTF(PMUVerbose
, "readMiscReg(%s): 0x%x\n",
224 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
229 PMU::readMiscRegInt(int misc_reg
)
231 misc_reg
= unflattenMiscReg(misc_reg
);
233 case MISCREG_PMCR_EL0
:
235 return reg_pmcr_conf
| (reg_pmcr
& reg_pmcr_wr_mask
);
237 case MISCREG_PMCNTENSET_EL0
:
238 case MISCREG_PMCNTENCLR_EL0
:
239 case MISCREG_PMCNTENSET
:
240 case MISCREG_PMCNTENCLR
:
243 case MISCREG_PMOVSCLR_EL0
:
244 case MISCREG_PMOVSSET_EL0
:
245 case MISCREG_PMOVSR
: // Overflow Status Register
246 case MISCREG_PMOVSSET
:
249 case MISCREG_PMSWINC_EL0
:
250 case MISCREG_PMSWINC
: // Software Increment Register (RAZ)
256 case MISCREG_PMCEID0_EL0
:
257 case MISCREG_PMCEID0
: // Common Event ID register
258 return reg_pmceid
& 0xFFFFFFFF;
260 case MISCREG_PMCEID1_EL0
:
261 case MISCREG_PMCEID1
: // Common Event ID register
262 return (reg_pmceid
>> 32) & 0xFFFFFFFF;
264 case MISCREG_PMCCNTR_EL0
:
265 return cycleCounter
.value
;
267 case MISCREG_PMCCNTR
:
268 return cycleCounter
.value
& 0xFFFFFFFF;
270 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
271 return getCounterTypeRegister(misc_reg
- MISCREG_PMEVTYPER0_EL0
);
273 case MISCREG_PMCCFILTR
:
274 case MISCREG_PMCCFILTR_EL0
:
275 return getCounterTypeRegister(PMCCNTR
);
277 case MISCREG_PMXEVTYPER_PMCCFILTR
:
278 case MISCREG_PMXEVTYPER_EL0
:
279 case MISCREG_PMXEVTYPER
:
280 return getCounterTypeRegister(reg_pmselr
.sel
);
282 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
:
283 return getCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
) & 0xFFFFFFFF;
285 case MISCREG_PMXEVCNTR_EL0
:
286 case MISCREG_PMXEVCNTR
:
287 return getCounterValue(reg_pmselr
.sel
) & 0xFFFFFFFF;
289 case MISCREG_PMUSERENR_EL0
:
290 case MISCREG_PMUSERENR
:
294 case MISCREG_PMINTENSET_EL1
:
295 case MISCREG_PMINTENCLR_EL1
:
296 case MISCREG_PMINTENSET
:
297 case MISCREG_PMINTENCLR
:
301 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
304 warn("Not doing anything for read from miscreg %s\n",
305 miscRegName
[misc_reg
]);
310 PMU::setControlReg(PMCR_t val
)
312 DPRINTF(PMUVerbose
, "Set Control Reg 0x%08x.\n", val
);
315 DPRINTF(PMUVerbose
, "PMU reset all events to zero.\n");
320 DPRINTF(PMUVerbose
, "PMU reset cycle counter to zero.\n");
321 cycleCounter
.value
= 0;
324 // Reset the clock remainder if divide by 64-mode is toggled.
325 if (reg_pmcr
.d
!= val
.d
)
328 reg_pmcr
= val
& reg_pmcr_wr_mask
;
333 PMU::updateAllCounters()
335 const bool global_enable(reg_pmcr
.e
);
337 for (int i
= 0; i
< counters
.size(); ++i
) {
338 CounterState
&ctr(counters
[i
]);
339 const bool enable(global_enable
&& (reg_pmcnten
& (1 << i
)));
340 if (ctr
.enabled
!= enable
) {
341 ctr
.enabled
= enable
;
342 updateCounter(i
, ctr
);
346 const bool ccntr_enable(global_enable
&& (reg_pmcnten
& (1 << PMCCNTR
)));
347 if (cycleCounter
.enabled
!= ccntr_enable
) {
348 cycleCounter
.enabled
= ccntr_enable
;
349 updateCounter(PMCCNTR
, cycleCounter
);
354 PMU::handleEvent(CounterId id
, uint64_t delta
)
356 CounterState
&ctr(getCounter(id
));
357 const bool overflowed(reg_pmovsr
& (1 << id
));
359 // Handle the "count every 64 cycles" mode
360 if (id
== PMCCNTR
&& reg_pmcr
.d
) {
361 clock_remainder
+= delta
;
362 delta
= (clock_remainder
>> 6);
363 clock_remainder
&= 63;
366 // Add delta and handle (new) overflows
367 if (ctr
.add(delta
) && !overflowed
) {
368 DPRINTF(PMUVerbose
, "PMU counter '%i' overflowed.\n", id
);
369 reg_pmovsr
|= (1 << id
);
370 // Deliver a PMU interrupt if interrupt delivery is enabled
372 if (reg_pminten
& (1 << id
))
378 PMU::updateCounter(CounterId id
, CounterState
&ctr
)
381 if (!ctr
.listeners
.empty()) {
382 DPRINTF(PMUVerbose
, "updateCounter(%i): Disabling counter\n", id
);
383 ctr
.listeners
.clear();
386 DPRINTF(PMUVerbose
, "updateCounter(%i): Enable event id 0x%x\n",
389 // Attach all probes belonging to this event
390 auto range(pmuEventTypes
.equal_range(ctr
.eventId
));
391 for (auto it
= range
.first
; it
!= range
.second
; ++it
) {
392 const EventType
&et(it
->second
);
394 DPRINTF(PMUVerbose
, "\tProbe: %s:%s\n", et
.obj
->name(), et
.name
);
395 ctr
.listeners
.emplace_back(et
.create(*this, id
));
398 /* The SW_INCR event type is a special case which doesn't need
399 * any probes since it is controlled by software and the PMU
402 if (ctr
.listeners
.empty() && ctr
.eventId
!= ARCH_EVENT_SW_INCR
) {
403 warn("Can't enable PMU counter of type '0x%x': "
404 "No such event type.\n", ctr
.eventId
);
411 PMU::resetEventCounts()
413 for (CounterState
&ctr
: counters
)
418 PMU::setCounterValue(CounterId id
, uint64_t val
)
420 if (!isValidCounter(id
)) {
421 warn_once("Can't change counter value: Counter %i does not exist.\n",
426 CounterState
&ctr(getCounter(id
));
431 PMU::getCounterTypeRegister(CounterId id
) const
433 if (!isValidCounter(id
))
436 const CounterState
&cs(getCounter(id
));
439 // TODO: Re-create filtering settings from counter state
440 type
.evtCount
= cs
.eventId
;
446 PMU::setCounterTypeRegister(CounterId id
, PMEVTYPER_t val
)
448 DPRINTF(PMUVerbose
, "Set Event [%d] = 0x%08x\n", id
, val
);
449 if (!isValidCounter(id
)) {
450 warn_once("Can't change counter type: Counter %i does not exist.\n",
455 CounterState
&ctr(getCounter(id
));
456 // TODO: Handle filtering (both for general purpose counters and
457 // the cycle counter)
459 // If PMCCNTR Register, do not change event type. PMCCNTR can count
460 // processor cycles only.
462 ctr
.eventId
= val
.evtCount
;
463 updateCounter(reg_pmselr
.sel
, ctr
);
468 PMU::raiseInterrupt()
470 RealView
*rv(dynamic_cast<RealView
*>(platform
));
471 if (!rv
|| !rv
->gic
) {
472 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
476 DPRINTF(PMUVerbose
, "Delivering PMU interrupt.\n");
477 rv
->gic
->sendInt(pmuInterrupt
);
481 PMU::serialize(std::ostream
&os
)
483 DPRINTF(Checkpoint
, "Serializing Arm PMU\n");
485 SERIALIZE_SCALAR(reg_pmcr
);
486 SERIALIZE_SCALAR(reg_pmcnten
);
487 SERIALIZE_SCALAR(reg_pmselr
);
488 SERIALIZE_SCALAR(reg_pminten
);
489 SERIALIZE_SCALAR(reg_pmovsr
);
490 SERIALIZE_SCALAR(reg_pmceid
);
491 SERIALIZE_SCALAR(clock_remainder
);
493 for (size_t i
= 0; i
< counters
.size(); ++i
) {
494 nameOut(os
, csprintf("%s.counters.%i", name(), i
));
495 counters
[i
].serialize(os
);
498 nameOut(os
, csprintf("%s.cycleCounter", name()));
499 cycleCounter
.serialize(os
);
503 PMU::unserialize(Checkpoint
*cp
, const std::string
§ion
)
505 DPRINTF(Checkpoint
, "Unserializing Arm PMU\n");
507 UNSERIALIZE_SCALAR(reg_pmcr
);
508 UNSERIALIZE_SCALAR(reg_pmcnten
);
509 UNSERIALIZE_SCALAR(reg_pmselr
);
510 UNSERIALIZE_SCALAR(reg_pminten
);
511 UNSERIALIZE_SCALAR(reg_pmovsr
);
512 UNSERIALIZE_SCALAR(reg_pmceid
);
513 UNSERIALIZE_SCALAR(clock_remainder
);
515 for (size_t i
= 0; i
< counters
.size(); ++i
)
516 counters
[i
].unserialize(cp
, csprintf("%s.counters.%i", section
, i
));
518 cycleCounter
.unserialize(cp
, csprintf("%s.cycleCounter", section
));
522 PMU::CounterState::serialize(std::ostream
&os
)
524 SERIALIZE_SCALAR(eventId
);
525 SERIALIZE_SCALAR(value
);
526 SERIALIZE_SCALAR(enabled
);
527 SERIALIZE_SCALAR(overflow64
);
531 PMU::CounterState::unserialize(Checkpoint
*cp
, const std::string
§ion
)
533 UNSERIALIZE_SCALAR(eventId
);
534 UNSERIALIZE_SCALAR(value
);
535 UNSERIALIZE_SCALAR(enabled
);
536 UNSERIALIZE_SCALAR(overflow64
);
540 PMU::CounterState::add(uint64_t delta
)
542 const uint64_t msb(1ULL << (overflow64
? 63 : 31));
543 const uint64_t old_value(value
);
549 // Overflow if the msb goes from 1 to 0
550 return (old_value
& msb
) && !(value
& msb
);
553 } // namespace ArmISA
556 ArmPMUParams::create()
558 return new ArmISA::PMU(this);