Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Performance counter support for POWER7 processors.
0004  *
0005  * Copyright 2009 Paul Mackerras, IBM Corporation.
0006  */
0007 #include <linux/kernel.h>
0008 #include <linux/perf_event.h>
0009 #include <linux/string.h>
0010 #include <asm/reg.h>
0011 #include <asm/cputable.h>
0012 
0013 #include "internal.h"
0014 
0015 /*
0016  * Bits in event code for POWER7
0017  */
0018 #define PM_PMC_SH   16  /* PMC number (1-based) for direct events */
0019 #define PM_PMC_MSK  0xf
0020 #define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
0021 #define PM_UNIT_SH  12  /* TTMMUX number and setting - unit select */
0022 #define PM_UNIT_MSK 0xf
0023 #define PM_COMBINE_SH   11  /* Combined event bit */
0024 #define PM_COMBINE_MSK  1
0025 #define PM_COMBINE_MSKS 0x800
0026 #define PM_L2SEL_SH 8   /* L2 event select */
0027 #define PM_L2SEL_MSK    7
0028 #define PM_PMCSEL_MSK   0xff
0029 
0030 /*
0031  * Bits in MMCR1 for POWER7
0032  */
0033 #define MMCR1_TTM0SEL_SH    60
0034 #define MMCR1_TTM1SEL_SH    56
0035 #define MMCR1_TTM2SEL_SH    52
0036 #define MMCR1_TTM3SEL_SH    48
0037 #define MMCR1_TTMSEL_MSK    0xf
0038 #define MMCR1_L2SEL_SH      45
0039 #define MMCR1_L2SEL_MSK     7
0040 #define MMCR1_PMC1_COMBINE_SH   35
0041 #define MMCR1_PMC2_COMBINE_SH   34
0042 #define MMCR1_PMC3_COMBINE_SH   33
0043 #define MMCR1_PMC4_COMBINE_SH   32
0044 #define MMCR1_PMC1SEL_SH    24
0045 #define MMCR1_PMC2SEL_SH    16
0046 #define MMCR1_PMC3SEL_SH    8
0047 #define MMCR1_PMC4SEL_SH    0
0048 #define MMCR1_PMCSEL_SH(n)  (MMCR1_PMC1SEL_SH - (n) * 8)
0049 #define MMCR1_PMCSEL_MSK    0xff
0050 
0051 /*
0052  * Power7 event codes.
0053  */
0054 #define EVENT(_name, _code) \
0055     _name = _code,
0056 
0057 enum {
0058 #include "power7-events-list.h"
0059 };
0060 #undef EVENT
0061 
0062 /*
0063  * Layout of constraint bits:
0064  * 6666555555555544444444443333333333222222222211111111110000000000
0065  * 3210987654321098765432109876543210987654321098765432109876543210
0066  *                                              < ><  ><><><><><><>
0067  *                                              L2  NC P6P5P4P3P2P1
0068  *
0069  * L2 - 16-18 - Required L2SEL value (select field)
0070  *
0071  * NC - number of counters
0072  *     15: NC error 0x8000
0073  *     12-14: number of events needing PMC1-4 0x7000
0074  *
0075  * P6
0076  *     11: P6 error 0x800
0077  *     10-11: Count of events needing PMC6
0078  *
0079  * P1..P5
0080  *     0-9: Count of events needing PMC1..PMC5
0081  */
0082 
0083 static int power7_get_constraint(u64 event, unsigned long *maskp,
0084                  unsigned long *valp, u64 event_config1 __maybe_unused)
0085 {
0086     int pmc, sh, unit;
0087     unsigned long mask = 0, value = 0;
0088 
0089     pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
0090     if (pmc) {
0091         if (pmc > 6)
0092             return -1;
0093         sh = (pmc - 1) * 2;
0094         mask |= 2 << sh;
0095         value |= 1 << sh;
0096         if (pmc >= 5 && !(event == 0x500fa || event == 0x600f4))
0097             return -1;
0098     }
0099     if (pmc < 5) {
0100         /* need a counter from PMC1-4 set */
0101         mask  |= 0x8000;
0102         value |= 0x1000;
0103     }
0104 
0105     unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
0106     if (unit == 6) {
0107         /* L2SEL must be identical across events */
0108         int l2sel = (event >> PM_L2SEL_SH) & PM_L2SEL_MSK;
0109         mask  |= 0x7 << 16;
0110         value |= l2sel << 16;
0111     }
0112 
0113     *maskp = mask;
0114     *valp = value;
0115     return 0;
0116 }
0117 
0118 #define MAX_ALT 2   /* at most 2 alternatives for any event */
0119 
0120 static const unsigned int event_alternatives[][MAX_ALT] = {
0121     { 0x200f2, 0x300f2 },       /* PM_INST_DISP */
0122     { 0x200f4, 0x600f4 },       /* PM_RUN_CYC */
0123     { 0x400fa, 0x500fa },       /* PM_RUN_INST_CMPL */
0124 };
0125 
0126 /*
0127  * Scan the alternatives table for a match and return the
0128  * index into the alternatives table if found, else -1.
0129  */
0130 static int find_alternative(u64 event)
0131 {
0132     int i, j;
0133 
0134     for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
0135         if (event < event_alternatives[i][0])
0136             break;
0137         for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
0138             if (event == event_alternatives[i][j])
0139                 return i;
0140     }
0141     return -1;
0142 }
0143 
0144 static s64 find_alternative_decode(u64 event)
0145 {
0146     int pmc, psel;
0147 
0148     /* this only handles the 4x decode events */
0149     pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
0150     psel = event & PM_PMCSEL_MSK;
0151     if ((pmc == 2 || pmc == 4) && (psel & ~7) == 0x40)
0152         return event - (1 << PM_PMC_SH) + 8;
0153     if ((pmc == 1 || pmc == 3) && (psel & ~7) == 0x48)
0154         return event + (1 << PM_PMC_SH) - 8;
0155     return -1;
0156 }
0157 
0158 static int power7_get_alternatives(u64 event, unsigned int flags, u64 alt[])
0159 {
0160     int i, j, nalt = 1;
0161     s64 ae;
0162 
0163     alt[0] = event;
0164     nalt = 1;
0165     i = find_alternative(event);
0166     if (i >= 0) {
0167         for (j = 0; j < MAX_ALT; ++j) {
0168             ae = event_alternatives[i][j];
0169             if (ae && ae != event)
0170                 alt[nalt++] = ae;
0171         }
0172     } else {
0173         ae = find_alternative_decode(event);
0174         if (ae > 0)
0175             alt[nalt++] = ae;
0176     }
0177 
0178     if (flags & PPMU_ONLY_COUNT_RUN) {
0179         /*
0180          * We're only counting in RUN state,
0181          * so PM_CYC is equivalent to PM_RUN_CYC
0182          * and PM_INST_CMPL === PM_RUN_INST_CMPL.
0183          * This doesn't include alternatives that don't provide
0184          * any extra flexibility in assigning PMCs.
0185          */
0186         j = nalt;
0187         for (i = 0; i < nalt; ++i) {
0188             switch (alt[i]) {
0189             case 0x1e:  /* PM_CYC */
0190                 alt[j++] = 0x600f4; /* PM_RUN_CYC */
0191                 break;
0192             case 0x600f4:   /* PM_RUN_CYC */
0193                 alt[j++] = 0x1e;
0194                 break;
0195             case 0x2:   /* PM_PPC_CMPL */
0196                 alt[j++] = 0x500fa; /* PM_RUN_INST_CMPL */
0197                 break;
0198             case 0x500fa:   /* PM_RUN_INST_CMPL */
0199                 alt[j++] = 0x2; /* PM_PPC_CMPL */
0200                 break;
0201             }
0202         }
0203         nalt = j;
0204     }
0205 
0206     return nalt;
0207 }
0208 
0209 /*
0210  * Returns 1 if event counts things relating to marked instructions
0211  * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
0212  */
0213 static int power7_marked_instr_event(u64 event)
0214 {
0215     int pmc, psel;
0216     int unit;
0217 
0218     pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
0219     unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
0220     psel = event & PM_PMCSEL_MSK & ~1;  /* trim off edge/level bit */
0221     if (pmc >= 5)
0222         return 0;
0223 
0224     switch (psel >> 4) {
0225     case 2:
0226         return pmc == 2 || pmc == 4;
0227     case 3:
0228         if (psel == 0x3c)
0229             return pmc == 1;
0230         if (psel == 0x3e)
0231             return pmc != 2;
0232         return 1;
0233     case 4:
0234     case 5:
0235         return unit == 0xd;
0236     case 6:
0237         if (psel == 0x64)
0238             return pmc >= 3;
0239         break;
0240     case 8:
0241         return unit == 0xd;
0242     }
0243     return 0;
0244 }
0245 
0246 static int power7_compute_mmcr(u64 event[], int n_ev,
0247                    unsigned int hwc[], struct mmcr_regs *mmcr,
0248                    struct perf_event *pevents[],
0249                    u32 flags __maybe_unused)
0250 {
0251     unsigned long mmcr1 = 0;
0252     unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
0253     unsigned int pmc, unit, combine, l2sel, psel;
0254     unsigned int pmc_inuse = 0;
0255     int i;
0256 
0257     /* First pass to count resource use */
0258     for (i = 0; i < n_ev; ++i) {
0259         pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
0260         if (pmc) {
0261             if (pmc > 6)
0262                 return -1;
0263             if (pmc_inuse & (1 << (pmc - 1)))
0264                 return -1;
0265             pmc_inuse |= 1 << (pmc - 1);
0266         }
0267     }
0268 
0269     /* Second pass: assign PMCs, set all MMCR1 fields */
0270     for (i = 0; i < n_ev; ++i) {
0271         pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
0272         unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
0273         combine = (event[i] >> PM_COMBINE_SH) & PM_COMBINE_MSK;
0274         l2sel = (event[i] >> PM_L2SEL_SH) & PM_L2SEL_MSK;
0275         psel = event[i] & PM_PMCSEL_MSK;
0276         if (!pmc) {
0277             /* Bus event or any-PMC direct event */
0278             for (pmc = 0; pmc < 4; ++pmc) {
0279                 if (!(pmc_inuse & (1 << pmc)))
0280                     break;
0281             }
0282             if (pmc >= 4)
0283                 return -1;
0284             pmc_inuse |= 1 << pmc;
0285         } else {
0286             /* Direct or decoded event */
0287             --pmc;
0288         }
0289         if (pmc <= 3) {
0290             mmcr1 |= (unsigned long) unit
0291                 << (MMCR1_TTM0SEL_SH - 4 * pmc);
0292             mmcr1 |= (unsigned long) combine
0293                 << (MMCR1_PMC1_COMBINE_SH - pmc);
0294             mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
0295             if (unit == 6)  /* L2 events */
0296                 mmcr1 |= (unsigned long) l2sel
0297                     << MMCR1_L2SEL_SH;
0298         }
0299         if (power7_marked_instr_event(event[i]))
0300             mmcra |= MMCRA_SAMPLE_ENABLE;
0301         hwc[i] = pmc;
0302     }
0303 
0304     /* Return MMCRx values */
0305     mmcr->mmcr0 = 0;
0306     if (pmc_inuse & 1)
0307         mmcr->mmcr0 = MMCR0_PMC1CE;
0308     if (pmc_inuse & 0x3e)
0309         mmcr->mmcr0 |= MMCR0_PMCjCE;
0310     mmcr->mmcr1 = mmcr1;
0311     mmcr->mmcra = mmcra;
0312     return 0;
0313 }
0314 
0315 static void power7_disable_pmc(unsigned int pmc, struct mmcr_regs *mmcr)
0316 {
0317     if (pmc <= 3)
0318         mmcr->mmcr1 &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
0319 }
0320 
0321 static int power7_generic_events[] = {
0322     [PERF_COUNT_HW_CPU_CYCLES] =            PM_CYC,
0323     [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =   PM_GCT_NOSLOT_CYC,
0324     [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =    PM_CMPLU_STALL,
0325     [PERF_COUNT_HW_INSTRUCTIONS] =          PM_INST_CMPL,
0326     [PERF_COUNT_HW_CACHE_REFERENCES] =      PM_LD_REF_L1,
0327     [PERF_COUNT_HW_CACHE_MISSES] =          PM_LD_MISS_L1,
0328     [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =       PM_BRU_FIN,
0329     [PERF_COUNT_HW_BRANCH_MISSES] =         PM_BR_MPRED,
0330 };
0331 
0332 #define C(x)    PERF_COUNT_HW_CACHE_##x
0333 
0334 /*
0335  * Table of generalized cache-related events.
0336  * 0 means not supported, -1 means nonsensical, other values
0337  * are event codes.
0338  */
0339 static u64 power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
0340     [C(L1D)] = {        /*  RESULT_ACCESS   RESULT_MISS */
0341         [C(OP_READ)] = {    0xc880,     0x400f0 },
0342         [C(OP_WRITE)] = {   0,      0x300f0 },
0343         [C(OP_PREFETCH)] = {    0xd8b8,     0   },
0344     },
0345     [C(L1I)] = {        /*  RESULT_ACCESS   RESULT_MISS */
0346         [C(OP_READ)] = {    0,      0x200fc },
0347         [C(OP_WRITE)] = {   -1,     -1  },
0348         [C(OP_PREFETCH)] = {    0x408a,     0   },
0349     },
0350     [C(LL)] = {     /*  RESULT_ACCESS   RESULT_MISS */
0351         [C(OP_READ)] = {    0x16080,    0x26080 },
0352         [C(OP_WRITE)] = {   0x16082,    0x26082 },
0353         [C(OP_PREFETCH)] = {    0,      0   },
0354     },
0355     [C(DTLB)] = {       /*  RESULT_ACCESS   RESULT_MISS */
0356         [C(OP_READ)] = {    0,      0x300fc },
0357         [C(OP_WRITE)] = {   -1,     -1  },
0358         [C(OP_PREFETCH)] = {    -1,     -1  },
0359     },
0360     [C(ITLB)] = {       /*  RESULT_ACCESS   RESULT_MISS */
0361         [C(OP_READ)] = {    0,      0x400fc },
0362         [C(OP_WRITE)] = {   -1,     -1  },
0363         [C(OP_PREFETCH)] = {    -1,     -1  },
0364     },
0365     [C(BPU)] = {        /*  RESULT_ACCESS   RESULT_MISS */
0366         [C(OP_READ)] = {    0x10068,    0x400f6 },
0367         [C(OP_WRITE)] = {   -1,     -1  },
0368         [C(OP_PREFETCH)] = {    -1,     -1  },
0369     },
0370     [C(NODE)] = {       /*  RESULT_ACCESS   RESULT_MISS */
0371         [C(OP_READ)] = {    -1,     -1  },
0372         [C(OP_WRITE)] = {   -1,     -1  },
0373         [C(OP_PREFETCH)] = {    -1,     -1  },
0374     },
0375 };
0376 
0377 
0378 GENERIC_EVENT_ATTR(cpu-cycles,          PM_CYC);
0379 GENERIC_EVENT_ATTR(stalled-cycles-frontend, PM_GCT_NOSLOT_CYC);
0380 GENERIC_EVENT_ATTR(stalled-cycles-backend,  PM_CMPLU_STALL);
0381 GENERIC_EVENT_ATTR(instructions,        PM_INST_CMPL);
0382 GENERIC_EVENT_ATTR(cache-references,        PM_LD_REF_L1);
0383 GENERIC_EVENT_ATTR(cache-misses,        PM_LD_MISS_L1);
0384 GENERIC_EVENT_ATTR(branch-instructions,     PM_BRU_FIN);
0385 GENERIC_EVENT_ATTR(branch-misses,       PM_BR_MPRED);
0386 
0387 #define EVENT(_name, _code)     POWER_EVENT_ATTR(_name, _name);
0388 #include "power7-events-list.h"
0389 #undef EVENT
0390 
0391 #define EVENT(_name, _code)     POWER_EVENT_PTR(_name),
0392 
0393 static struct attribute *power7_events_attr[] = {
0394     GENERIC_EVENT_PTR(PM_CYC),
0395     GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC),
0396     GENERIC_EVENT_PTR(PM_CMPLU_STALL),
0397     GENERIC_EVENT_PTR(PM_INST_CMPL),
0398     GENERIC_EVENT_PTR(PM_LD_REF_L1),
0399     GENERIC_EVENT_PTR(PM_LD_MISS_L1),
0400     GENERIC_EVENT_PTR(PM_BRU_FIN),
0401     GENERIC_EVENT_PTR(PM_BR_MPRED),
0402 
0403     #include "power7-events-list.h"
0404     #undef EVENT
0405     NULL
0406 };
0407 
0408 static const struct attribute_group power7_pmu_events_group = {
0409     .name = "events",
0410     .attrs = power7_events_attr,
0411 };
0412 
0413 PMU_FORMAT_ATTR(event, "config:0-19");
0414 
0415 static struct attribute *power7_pmu_format_attr[] = {
0416     &format_attr_event.attr,
0417     NULL,
0418 };
0419 
0420 static const struct attribute_group power7_pmu_format_group = {
0421     .name = "format",
0422     .attrs = power7_pmu_format_attr,
0423 };
0424 
0425 static const struct attribute_group *power7_pmu_attr_groups[] = {
0426     &power7_pmu_format_group,
0427     &power7_pmu_events_group,
0428     NULL,
0429 };
0430 
0431 static struct power_pmu power7_pmu = {
0432     .name           = "POWER7",
0433     .n_counter      = 6,
0434     .max_alternatives   = MAX_ALT + 1,
0435     .add_fields     = 0x1555ul,
0436     .test_adder     = 0x3000ul,
0437     .compute_mmcr       = power7_compute_mmcr,
0438     .get_constraint     = power7_get_constraint,
0439     .get_alternatives   = power7_get_alternatives,
0440     .disable_pmc        = power7_disable_pmc,
0441     .flags          = PPMU_ALT_SIPR,
0442     .attr_groups        = power7_pmu_attr_groups,
0443     .n_generic      = ARRAY_SIZE(power7_generic_events),
0444     .generic_events     = power7_generic_events,
0445     .cache_events       = &power7_cache_events,
0446 };
0447 
0448 int __init init_power7_pmu(void)
0449 {
0450     unsigned int pvr = mfspr(SPRN_PVR);
0451 
0452     if (PVR_VER(pvr) != PVR_POWER7 && PVR_VER(pvr) != PVR_POWER7p)
0453         return -ENODEV;
0454 
0455     if (PVR_VER(pvr) == PVR_POWER7p)
0456         power7_pmu.flags |= PPMU_SIAR_VALID;
0457 
0458     return register_power_pmu(&power7_pmu);
0459 }