pmu.cc revision 10537:47fe87b0cf97
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 "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"
51
52namespace ArmISA {
53
54const MiscReg PMU::reg_pmcr_wr_mask = 0x39;
55
56PMU::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),
60      reg_pmceid(0),
61      clock_remainder(0),
62      counters(p->eventCounters),
63      reg_pmcr_conf(0),
64      pmuInterrupt(p->pmuInterrupt),
65      platform(p->platform)
66{
67    DPRINTF(PMUVerbose, "Initializing the PMU.\n");
68
69    if (p->eventCounters > 31) {
70        fatal("The PMU can only accept 31 counters, %d counters requested.\n",
71              p->eventCounters);
72    }
73
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;
78
79    // Setup the hard-coded cycle counter, which is equivalent to
80    // architected counter event type 0x11.
81    cycleCounter.eventId = 0x11;
82}
83
84PMU::~PMU()
85{
86}
87
88void
89PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
90{
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)));
94
95    // Flag the event as available in the PMCEID register if it is an
96    // architected event.
97    if (id < 0x40)
98        reg_pmceid |= (ULL(1) << id);
99}
100
101void
102PMU::drainResume()
103{
104    // Re-attach enabled counters after a resume in case they changed.
105    updateAllCounters();
106}
107
108void
109PMU::setMiscReg(int misc_reg, MiscReg val)
110{
111    DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
112            miscRegName[unflattenMiscReg(misc_reg)], val);
113
114    switch (unflattenMiscReg(misc_reg)) {
115      case MISCREG_PMCR_EL0:
116      case MISCREG_PMCR:
117        setControlReg(val);
118        return;
119
120      case MISCREG_PMCNTENSET_EL0:
121      case MISCREG_PMCNTENSET:
122        reg_pmcnten |= val;
123        updateAllCounters();
124        return;
125
126      case MISCREG_PMCNTENCLR_EL0:
127      case MISCREG_PMCNTENCLR:
128        reg_pmcnten &= ~val;
129        updateAllCounters();
130        return;
131
132      case MISCREG_PMOVSCLR_EL0:
133      case MISCREG_PMOVSR:
134        reg_pmovsr &= ~val;
135        return;
136
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)))
142                ++ctr.value;
143        }
144        break;
145
146      case MISCREG_PMCCNTR_EL0:
147      case MISCREG_PMCCNTR:
148        cycleCounter.value = val;
149        return;
150
151      case MISCREG_PMSELR_EL0:
152      case MISCREG_PMSELR:
153        reg_pmselr = val;
154        return;
155
156      case MISCREG_PMCEID0_EL0:
157      case MISCREG_PMCEID0:
158      case MISCREG_PMCEID1_EL0:
159      case MISCREG_PMCEID1:
160        // Ignore writes
161        return;
162
163      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
164        setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
165        return;
166
167      case MISCREG_PMCCFILTR:
168      case MISCREG_PMCCFILTR_EL0:
169        DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
170        setCounterTypeRegister(PMCCNTR, val);
171        return;
172
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);
180        return;
181
182      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
183        setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
184        return;
185
186      case MISCREG_PMXEVCNTR_EL0:
187      case MISCREG_PMXEVCNTR:
188        setCounterValue(reg_pmselr.sel, val);
189        return;
190
191      case MISCREG_PMUSERENR_EL0:
192      case MISCREG_PMUSERENR:
193        // TODO
194        break;
195
196      case MISCREG_PMINTENSET_EL1:
197      case MISCREG_PMINTENSET:
198        reg_pminten |= val;
199        return;
200
201      case MISCREG_PMINTENCLR_EL1:
202      case MISCREG_PMINTENCLR:
203        reg_pminten &= ~val;
204        return;
205
206      case MISCREG_PMOVSSET_EL0:
207      case MISCREG_PMOVSSET:
208        reg_pmovsr |= val;
209        return;
210
211      default:
212        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
213    }
214
215    warn("Not doing anything for write to miscreg %s\n",
216         miscRegName[misc_reg]);
217}
218
219MiscReg
220PMU::readMiscReg(int misc_reg)
221{
222    MiscReg val(readMiscRegInt(misc_reg));
223    DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
224            miscRegName[unflattenMiscReg(misc_reg)], val);
225    return val;
226}
227
228MiscReg
229PMU::readMiscRegInt(int misc_reg)
230{
231    misc_reg = unflattenMiscReg(misc_reg);
232    switch (misc_reg) {
233      case MISCREG_PMCR_EL0:
234      case MISCREG_PMCR:
235        return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
236
237      case MISCREG_PMCNTENSET_EL0:
238      case MISCREG_PMCNTENCLR_EL0:
239      case MISCREG_PMCNTENSET:
240      case MISCREG_PMCNTENCLR:
241        return reg_pmcnten;
242
243      case MISCREG_PMOVSCLR_EL0:
244      case MISCREG_PMOVSSET_EL0:
245      case MISCREG_PMOVSR:  // Overflow Status Register
246      case MISCREG_PMOVSSET:
247        return reg_pmovsr;
248
249      case MISCREG_PMSWINC_EL0:
250      case MISCREG_PMSWINC: // Software Increment Register (RAZ)
251        return 0;
252
253      case MISCREG_PMSELR:
254        return reg_pmselr;
255
256      case MISCREG_PMCEID0_EL0:
257      case MISCREG_PMCEID0: // Common Event ID register
258        return reg_pmceid & 0xFFFFFFFF;
259
260      case MISCREG_PMCEID1_EL0:
261      case MISCREG_PMCEID1: // Common Event ID register
262        return (reg_pmceid >> 32) & 0xFFFFFFFF;
263
264      case MISCREG_PMCCNTR_EL0:
265        return cycleCounter.value;
266
267      case MISCREG_PMCCNTR:
268        return cycleCounter.value & 0xFFFFFFFF;
269
270      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
271        return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
272
273      case MISCREG_PMCCFILTR:
274      case MISCREG_PMCCFILTR_EL0:
275        return getCounterTypeRegister(PMCCNTR);
276
277      case MISCREG_PMXEVTYPER_PMCCFILTR:
278      case MISCREG_PMXEVTYPER_EL0:
279      case MISCREG_PMXEVTYPER:
280        return getCounterTypeRegister(reg_pmselr.sel);
281
282      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
283        return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
284
285      case MISCREG_PMXEVCNTR_EL0:
286      case MISCREG_PMXEVCNTR:
287        return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
288
289      case MISCREG_PMUSERENR_EL0:
290      case MISCREG_PMUSERENR:
291        // TODO
292        return 0;
293
294      case MISCREG_PMINTENSET_EL1:
295      case MISCREG_PMINTENCLR_EL1:
296      case MISCREG_PMINTENSET:
297      case MISCREG_PMINTENCLR:
298        return reg_pminten;
299
300      default:
301        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
302    }
303
304    warn("Not doing anything for read from miscreg %s\n",
305         miscRegName[misc_reg]);
306    return 0;
307}
308
309void
310PMU::setControlReg(PMCR_t val)
311{
312    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
313
314    if (val.p) {
315        DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
316        resetEventCounts();
317    }
318
319    if (val.c) {
320        DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
321        cycleCounter.value = 0;
322    }
323
324    // Reset the clock remainder if divide by 64-mode is toggled.
325    if (reg_pmcr.d != val.d)
326        clock_remainder = 0;
327
328    reg_pmcr = val & reg_pmcr_wr_mask;
329    updateAllCounters();
330}
331
332void
333PMU::updateAllCounters()
334{
335    const bool global_enable(reg_pmcr.e);
336
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);
343        }
344    }
345
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);
350    }
351}
352
353void
354PMU::handleEvent(CounterId id, uint64_t delta)
355{
356    CounterState &ctr(getCounter(id));
357    const bool overflowed(reg_pmovsr & (1 << id));
358
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;
364    }
365
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
371        // for this counter.
372        if (reg_pminten  & (1 << id))
373            raiseInterrupt();
374    }
375}
376
377void
378PMU::updateCounter(CounterId id, CounterState &ctr)
379{
380    if (!ctr.enabled) {
381        if (!ctr.listeners.empty()) {
382            DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
383            ctr.listeners.clear();
384        }
385    } else {
386        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
387                id, ctr.eventId);
388
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);
393
394            DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
395            ctr.listeners.emplace_back(et.create(*this, id));
396        }
397
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
400         * itself.
401         */
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);
405        }
406    }
407}
408
409
410void
411PMU::resetEventCounts()
412{
413    for (CounterState &ctr : counters)
414        ctr.value = 0;
415}
416
417void
418PMU::setCounterValue(CounterId id, uint64_t val)
419{
420    if (!isValidCounter(id)) {
421        warn_once("Can't change counter value: Counter %i does not exist.\n",
422                  id);
423        return;
424    }
425
426    CounterState &ctr(getCounter(id));
427    ctr.value = val;
428}
429
430PMU::PMEVTYPER_t
431PMU::getCounterTypeRegister(CounterId id) const
432{
433    if (!isValidCounter(id))
434        return 0;
435
436    const CounterState &cs(getCounter(id));
437    PMEVTYPER_t type(0);
438
439    // TODO: Re-create filtering settings from counter state
440    type.evtCount = cs.eventId;
441
442    return type;
443}
444
445void
446PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
447{
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",
451                  id);
452        return;
453    }
454
455    CounterState &ctr(getCounter(id));
456    // TODO: Handle filtering (both for general purpose counters and
457    // the cycle counter)
458
459    // If PMCCNTR Register, do not change event type. PMCCNTR can count
460    // processor cycles only.
461    if (id != PMCCNTR) {
462        ctr.eventId = val.evtCount;
463        updateCounter(reg_pmselr.sel, ctr);
464    }
465}
466
467void
468PMU::raiseInterrupt()
469{
470    RealView *rv(dynamic_cast<RealView *>(platform));
471    if (!rv || !rv->gic) {
472        warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
473        return;
474    }
475
476    DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
477    rv->gic->sendInt(pmuInterrupt);
478}
479
480void
481PMU::serialize(std::ostream &os)
482{
483    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
484
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);
492
493    for (size_t i = 0; i < counters.size(); ++i) {
494        nameOut(os, csprintf("%s.counters.%i", name(), i));
495        counters[i].serialize(os);
496    }
497
498    nameOut(os, csprintf("%s.cycleCounter", name()));
499    cycleCounter.serialize(os);
500}
501
502void
503PMU::unserialize(Checkpoint *cp, const std::string &section)
504{
505    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
506
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);
514
515    for (size_t i = 0; i < counters.size(); ++i)
516        counters[i].unserialize(cp, csprintf("%s.counters.%i", section, i));
517
518    cycleCounter.unserialize(cp, csprintf("%s.cycleCounter", section));
519}
520
521void
522PMU::CounterState::serialize(std::ostream &os)
523{
524    SERIALIZE_SCALAR(eventId);
525    SERIALIZE_SCALAR(value);
526    SERIALIZE_SCALAR(enabled);
527    SERIALIZE_SCALAR(overflow64);
528}
529
530void
531PMU::CounterState::unserialize(Checkpoint *cp, const std::string &section)
532{
533    UNSERIALIZE_SCALAR(eventId);
534    UNSERIALIZE_SCALAR(value);
535    UNSERIALIZE_SCALAR(enabled);
536    UNSERIALIZE_SCALAR(overflow64);
537}
538
539bool
540PMU::CounterState::add(uint64_t delta)
541{
542    const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
543    const uint64_t old_value(value);
544
545    assert(delta > 0);
546
547    value += delta;
548
549    // Overflow if the msb goes from 1 to 0
550    return (old_value & msb) && !(value & msb);
551}
552
553} // namespace ArmISA
554
555ArmISA::PMU *
556ArmPMUParams::create()
557{
558    return new ArmISA::PMU(this);
559}
560