pmu.cc revision 11447:717172baf4dd
1/*
2 * Copyright (c) 2011-2014 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 * Authors: Dam Sunwoo
38 *          Matt Horsnell
39 *          Andreas Sandberg
40 */
41
42#include "arch/arm/pmu.hh"
43
44#include "arch/arm/isa.hh"
45#include "arch/arm/utility.hh"
46#include "base/trace.hh"
47#include "cpu/base.hh"
48#include "debug/Checkpoint.hh"
49#include "debug/PMUVerbose.hh"
50#include "dev/arm/base_gic.hh"
51#include "dev/arm/realview.hh"
52#include "params/ArmPMU.hh"
53
54namespace ArmISA {
55
56const MiscReg PMU::reg_pmcr_wr_mask = 0x39;
57
58PMU::PMU(const ArmPMUParams *p)
59    : SimObject(p), BaseISADevice(),
60      reg_pmcnten(0), reg_pmcr(0),
61      reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
62      reg_pmceid(0),
63      clock_remainder(0),
64      counters(p->eventCounters),
65      reg_pmcr_conf(0),
66      pmuInterrupt(p->pmuInterrupt),
67      platform(p->platform)
68{
69    DPRINTF(PMUVerbose, "Initializing the PMU.\n");
70
71    if (p->eventCounters > 31) {
72        fatal("The PMU can only accept 31 counters, %d counters requested.\n",
73              p->eventCounters);
74    }
75
76    /* Setup the performance counter ID registers */
77    reg_pmcr_conf.imp = 0x41;    // ARM Ltd.
78    reg_pmcr_conf.idcode = 0x00;
79    reg_pmcr_conf.n = p->eventCounters;
80
81    // Setup the hard-coded cycle counter, which is equivalent to
82    // architected counter event type 0x11.
83    cycleCounter.eventId = 0x11;
84}
85
86PMU::~PMU()
87{
88}
89
90void
91PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
92{
93    DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n",
94            id, obj->name(), probe_name);
95    pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name)));
96
97    // Flag the event as available in the PMCEID register if it is an
98    // architected event.
99    if (id < 0x40)
100        reg_pmceid |= (ULL(1) << id);
101}
102
103void
104PMU::drainResume()
105{
106    // Re-attach enabled counters after a resume in case they changed.
107    updateAllCounters();
108}
109
110void
111PMU::setMiscReg(int misc_reg, MiscReg val)
112{
113    DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
114            miscRegName[unflattenMiscReg(misc_reg)], val);
115
116    switch (unflattenMiscReg(misc_reg)) {
117      case MISCREG_PMCR_EL0:
118      case MISCREG_PMCR:
119        setControlReg(val);
120        return;
121
122      case MISCREG_PMCNTENSET_EL0:
123      case MISCREG_PMCNTENSET:
124        reg_pmcnten |= val;
125        updateAllCounters();
126        return;
127
128      case MISCREG_PMCNTENCLR_EL0:
129      case MISCREG_PMCNTENCLR:
130        reg_pmcnten &= ~val;
131        updateAllCounters();
132        return;
133
134      case MISCREG_PMOVSCLR_EL0:
135      case MISCREG_PMOVSR:
136        reg_pmovsr &= ~val;
137        return;
138
139      case MISCREG_PMSWINC_EL0:
140      case MISCREG_PMSWINC:
141        for (int i = 0; i < counters.size(); ++i) {
142            CounterState &ctr(getCounter(i));
143            if (ctr.enabled && (val & (1 << i)))
144                ++ctr.value;
145        }
146        break;
147
148      case MISCREG_PMCCNTR_EL0:
149      case MISCREG_PMCCNTR:
150        cycleCounter.value = val;
151        return;
152
153      case MISCREG_PMSELR_EL0:
154      case MISCREG_PMSELR:
155        reg_pmselr = val;
156        return;
157
158      case MISCREG_PMCEID0_EL0:
159      case MISCREG_PMCEID0:
160      case MISCREG_PMCEID1_EL0:
161      case MISCREG_PMCEID1:
162        // Ignore writes
163        return;
164
165      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
166        setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
167        return;
168
169      case MISCREG_PMCCFILTR:
170      case MISCREG_PMCCFILTR_EL0:
171        DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
172        setCounterTypeRegister(PMCCNTR, val);
173        return;
174
175      case MISCREG_PMXEVTYPER_PMCCFILTR:
176      case MISCREG_PMXEVTYPER_EL0:
177      case MISCREG_PMXEVTYPER:
178        DPRINTF(PMUVerbose, "Setting counter type: "
179                "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
180                reg_pmselr, reg_pmselr.sel, val);
181        setCounterTypeRegister(reg_pmselr.sel, val);
182        return;
183
184      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
185        setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
186        return;
187
188      case MISCREG_PMXEVCNTR_EL0:
189      case MISCREG_PMXEVCNTR:
190        setCounterValue(reg_pmselr.sel, val);
191        return;
192
193      case MISCREG_PMUSERENR_EL0:
194      case MISCREG_PMUSERENR:
195        // TODO
196        break;
197
198      case MISCREG_PMINTENSET_EL1:
199      case MISCREG_PMINTENSET:
200        reg_pminten |= val;
201        return;
202
203      case MISCREG_PMINTENCLR_EL1:
204      case MISCREG_PMINTENCLR:
205        reg_pminten &= ~val;
206        return;
207
208      case MISCREG_PMOVSSET_EL0:
209      case MISCREG_PMOVSSET:
210        reg_pmovsr |= val;
211        return;
212
213      default:
214        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
215    }
216
217    warn("Not doing anything for write to miscreg %s\n",
218         miscRegName[misc_reg]);
219}
220
221MiscReg
222PMU::readMiscReg(int misc_reg)
223{
224    MiscReg val(readMiscRegInt(misc_reg));
225    DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
226            miscRegName[unflattenMiscReg(misc_reg)], val);
227    return val;
228}
229
230MiscReg
231PMU::readMiscRegInt(int misc_reg)
232{
233    misc_reg = unflattenMiscReg(misc_reg);
234    switch (misc_reg) {
235      case MISCREG_PMCR_EL0:
236      case MISCREG_PMCR:
237        return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
238
239      case MISCREG_PMCNTENSET_EL0:
240      case MISCREG_PMCNTENCLR_EL0:
241      case MISCREG_PMCNTENSET:
242      case MISCREG_PMCNTENCLR:
243        return reg_pmcnten;
244
245      case MISCREG_PMOVSCLR_EL0:
246      case MISCREG_PMOVSSET_EL0:
247      case MISCREG_PMOVSR:  // Overflow Status Register
248      case MISCREG_PMOVSSET:
249        return reg_pmovsr;
250
251      case MISCREG_PMSWINC_EL0:
252      case MISCREG_PMSWINC: // Software Increment Register (RAZ)
253        return 0;
254
255      case MISCREG_PMSELR:
256        return reg_pmselr;
257
258      case MISCREG_PMCEID0_EL0:
259      case MISCREG_PMCEID0: // Common Event ID register
260        return reg_pmceid & 0xFFFFFFFF;
261
262      case MISCREG_PMCEID1_EL0:
263      case MISCREG_PMCEID1: // Common Event ID register
264        return (reg_pmceid >> 32) & 0xFFFFFFFF;
265
266      case MISCREG_PMCCNTR_EL0:
267        return cycleCounter.value;
268
269      case MISCREG_PMCCNTR:
270        return cycleCounter.value & 0xFFFFFFFF;
271
272      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
273        return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
274
275      case MISCREG_PMCCFILTR:
276      case MISCREG_PMCCFILTR_EL0:
277        return getCounterTypeRegister(PMCCNTR);
278
279      case MISCREG_PMXEVTYPER_PMCCFILTR:
280      case MISCREG_PMXEVTYPER_EL0:
281      case MISCREG_PMXEVTYPER:
282        return getCounterTypeRegister(reg_pmselr.sel);
283
284      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
285        return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
286
287      case MISCREG_PMXEVCNTR_EL0:
288      case MISCREG_PMXEVCNTR:
289        return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
290
291      case MISCREG_PMUSERENR_EL0:
292      case MISCREG_PMUSERENR:
293        // TODO
294        return 0;
295
296      case MISCREG_PMINTENSET_EL1:
297      case MISCREG_PMINTENCLR_EL1:
298      case MISCREG_PMINTENSET:
299      case MISCREG_PMINTENCLR:
300        return reg_pminten;
301
302      default:
303        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
304    }
305
306    warn("Not doing anything for read from miscreg %s\n",
307         miscRegName[misc_reg]);
308    return 0;
309}
310
311void
312PMU::setControlReg(PMCR_t val)
313{
314    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
315
316    if (val.p) {
317        DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
318        resetEventCounts();
319    }
320
321    if (val.c) {
322        DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
323        cycleCounter.value = 0;
324    }
325
326    // Reset the clock remainder if divide by 64-mode is toggled.
327    if (reg_pmcr.d != val.d)
328        clock_remainder = 0;
329
330    reg_pmcr = val & reg_pmcr_wr_mask;
331    updateAllCounters();
332}
333
334void
335PMU::updateAllCounters()
336{
337    const bool global_enable(reg_pmcr.e);
338
339    for (int i = 0; i < counters.size(); ++i) {
340        CounterState &ctr(counters[i]);
341        const bool enable(global_enable && (reg_pmcnten & (1 << i)));
342        if (ctr.enabled != enable) {
343            ctr.enabled = enable;
344            updateCounter(i, ctr);
345        }
346    }
347
348    const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
349    if (cycleCounter.enabled != ccntr_enable) {
350        cycleCounter.enabled = ccntr_enable;
351        updateCounter(PMCCNTR, cycleCounter);
352    }
353}
354
355bool
356PMU::isFiltered(const CounterState &ctr) const
357{
358    assert(isa);
359
360    const PMEVTYPER_t filter(ctr.filter);
361    const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR));
362    const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR));
363    const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
364    const bool secure(inSecureState(scr, cpsr));
365
366    switch (el) {
367      case EL0:
368        return secure ? filter.u : (filter.u != filter.nsu);
369
370      case EL1:
371        return secure ? filter.p : (filter.p != filter.nsk);
372
373      case EL2:
374        return !filter.nsh;
375
376      case EL3:
377        return filter.p != filter.m;
378
379      default:
380        panic("Unexpected execution level in PMU::isFiltered.\n");
381    }
382}
383
384void
385PMU::handleEvent(CounterId id, uint64_t delta)
386{
387    CounterState &ctr(getCounter(id));
388    const bool overflowed(reg_pmovsr & (1 << id));
389
390    if (isFiltered(ctr))
391        return;
392
393    // Handle the "count every 64 cycles" mode
394    if (id == PMCCNTR && reg_pmcr.d) {
395        clock_remainder += delta;
396        delta = (clock_remainder >> 6);
397        clock_remainder &= 63;
398    }
399
400    // Add delta and handle (new) overflows
401    if (ctr.add(delta) && !overflowed) {
402        DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
403        reg_pmovsr |= (1 << id);
404        // Deliver a PMU interrupt if interrupt delivery is enabled
405        // for this counter.
406        if (reg_pminten  & (1 << id))
407            raiseInterrupt();
408    }
409}
410
411void
412PMU::updateCounter(CounterId id, CounterState &ctr)
413{
414    if (!ctr.enabled) {
415        if (!ctr.listeners.empty()) {
416            DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
417            ctr.listeners.clear();
418        }
419    } else {
420        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
421                id, ctr.eventId);
422
423        // Attach all probes belonging to this event
424        auto range(pmuEventTypes.equal_range(ctr.eventId));
425        for (auto it = range.first; it != range.second; ++it) {
426            const EventType &et(it->second);
427
428            DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
429            ctr.listeners.emplace_back(et.create(*this, id));
430        }
431
432        /* The SW_INCR event type is a special case which doesn't need
433         * any probes since it is controlled by software and the PMU
434         * itself.
435         */
436        if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
437            warn("Can't enable PMU counter of type '0x%x': "
438                 "No such event type.\n", ctr.eventId);
439        }
440    }
441}
442
443
444void
445PMU::resetEventCounts()
446{
447    for (CounterState &ctr : counters)
448        ctr.value = 0;
449}
450
451void
452PMU::setCounterValue(CounterId id, uint64_t val)
453{
454    if (!isValidCounter(id)) {
455        warn_once("Can't change counter value: Counter %i does not exist.\n",
456                  id);
457        return;
458    }
459
460    CounterState &ctr(getCounter(id));
461    ctr.value = val;
462}
463
464PMU::PMEVTYPER_t
465PMU::getCounterTypeRegister(CounterId id) const
466{
467    if (!isValidCounter(id))
468        return 0;
469
470    const CounterState &cs(getCounter(id));
471    PMEVTYPER_t type(cs.filter);
472
473    type.evtCount = cs.eventId;
474
475    return type;
476}
477
478void
479PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
480{
481    DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
482    if (!isValidCounter(id)) {
483        warn_once("Can't change counter type: Counter %i does not exist.\n",
484                  id);
485        return;
486    }
487
488    CounterState &ctr(getCounter(id));
489    const EventTypeId old_event_id(ctr.eventId);
490
491    ctr.filter = val;
492
493    // If PMCCNTR Register, do not change event type. PMCCNTR can
494    // count processor cycles only. If we change the event type, we
495    // need to update the probes the counter is using.
496    if (id != PMCCNTR && old_event_id != val.evtCount) {
497        ctr.eventId = val.evtCount;
498        updateCounter(reg_pmselr.sel, ctr);
499    }
500}
501
502void
503PMU::raiseInterrupt()
504{
505    RealView *rv(dynamic_cast<RealView *>(platform));
506    if (!rv || !rv->gic) {
507        warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
508        return;
509    }
510
511    DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
512    rv->gic->sendInt(pmuInterrupt);
513}
514
515void
516PMU::serialize(CheckpointOut &cp) const
517{
518    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
519
520    SERIALIZE_SCALAR(reg_pmcr);
521    SERIALIZE_SCALAR(reg_pmcnten);
522    SERIALIZE_SCALAR(reg_pmselr);
523    SERIALIZE_SCALAR(reg_pminten);
524    SERIALIZE_SCALAR(reg_pmovsr);
525    SERIALIZE_SCALAR(reg_pmceid);
526    SERIALIZE_SCALAR(clock_remainder);
527
528    for (size_t i = 0; i < counters.size(); ++i)
529        counters[i].serializeSection(cp, csprintf("counters.%i", i));
530
531    cycleCounter.serializeSection(cp, "cycleCounter");
532}
533
534void
535PMU::unserialize(CheckpointIn &cp)
536{
537    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
538
539    UNSERIALIZE_SCALAR(reg_pmcr);
540    UNSERIALIZE_SCALAR(reg_pmcnten);
541    UNSERIALIZE_SCALAR(reg_pmselr);
542    UNSERIALIZE_SCALAR(reg_pminten);
543    UNSERIALIZE_SCALAR(reg_pmovsr);
544    UNSERIALIZE_SCALAR(reg_pmceid);
545    UNSERIALIZE_SCALAR(clock_remainder);
546
547    for (size_t i = 0; i < counters.size(); ++i)
548        counters[i].unserializeSection(cp, csprintf("counters.%i", i));
549
550    cycleCounter.unserializeSection(cp, "cycleCounter");
551}
552
553void
554PMU::CounterState::serialize(CheckpointOut &cp) const
555{
556    SERIALIZE_SCALAR(eventId);
557    SERIALIZE_SCALAR(value);
558    SERIALIZE_SCALAR(enabled);
559    SERIALIZE_SCALAR(overflow64);
560}
561
562void
563PMU::CounterState::unserialize(CheckpointIn &cp)
564{
565    UNSERIALIZE_SCALAR(eventId);
566    UNSERIALIZE_SCALAR(value);
567    UNSERIALIZE_SCALAR(enabled);
568    UNSERIALIZE_SCALAR(overflow64);
569}
570
571bool
572PMU::CounterState::add(uint64_t delta)
573{
574    const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
575    const uint64_t old_value(value);
576
577    value += delta;
578
579    // Overflow if the msb goes from 1 to 0
580    return (old_value & msb) && !(value & msb);
581}
582
583} // namespace ArmISA
584
585ArmISA::PMU *
586ArmPMUParams::create()
587{
588    return new ArmISA::PMU(this);
589}
590