0001
0002
0003
0004
0005
0006
0007 #include <linux/string.h>
0008 #include <linux/perf_event.h>
0009 #include <asm/reg.h>
0010 #include <asm/cputable.h>
0011
0012 #define N_COUNTER 6
0013 #define MAX_ALT 3
0014
0015
0016
0017
0018 #define PM_THRMULT_MSKS 0x40000
0019 #define PM_THRESH_SH 12
0020 #define PM_THRESH_MSK 0x3f
0021 #define PM_PMC_SH 8
0022 #define PM_PMC_MSK 7
0023 #define PM_PMCSEL_MSK 0x7f
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #define N_CLASSES 5
0036
0037 static int mpc7450_classify_event(u32 event)
0038 {
0039 int pmc;
0040
0041 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
0042 if (pmc) {
0043 if (pmc > N_COUNTER)
0044 return -1;
0045 return 4;
0046 }
0047 event &= PM_PMCSEL_MSK;
0048 if (event <= 1)
0049 return 0;
0050 if (event <= 7)
0051 return 1;
0052 if (event <= 13)
0053 return 2;
0054 if (event <= 22)
0055 return 3;
0056 return -1;
0057 }
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 static int mpc7450_threshold_use(u32 event)
0078 {
0079 int pmc, sel;
0080
0081 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
0082 sel = event & PM_PMCSEL_MSK;
0083 switch (pmc) {
0084 case 1:
0085 if (sel == 0x1e || sel == 0x1f)
0086 return 1;
0087 if (sel == 0x28 || sel == 0x2b)
0088 return 2;
0089 break;
0090 case 2:
0091 if (sel == 0x20)
0092 return 1;
0093 break;
0094 case 3:
0095 if (sel == 0xc || sel == 0xd)
0096 return 1;
0097 if (sel == 0x11)
0098 return 2;
0099 break;
0100 case 4:
0101 if (sel == 0x10)
0102 return 1;
0103 break;
0104 }
0105 return 0;
0106 }
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134 static u32 pmcbits[N_COUNTER][2] = {
0135 { 0x00844002, 0x00111001 },
0136 { 0x00844008, 0x00111004 },
0137 { 0x00800020, 0x00100010 },
0138 { 0x00840080, 0x00110040 },
0139 { 0x00000200, 0x00000100 },
0140 { 0x00000800, 0x00000400 }
0141 };
0142
0143 static u32 classbits[N_CLASSES - 1][2] = {
0144 { 0x00000000, 0x00000000 },
0145 { 0x00800000, 0x00100000 },
0146 { 0x00040000, 0x00010000 },
0147 { 0x00004000, 0x00001000 },
0148 };
0149
0150 static int mpc7450_get_constraint(u64 event, unsigned long *maskp,
0151 unsigned long *valp, u64 event_config1 __maybe_unused)
0152 {
0153 int pmc, class;
0154 u32 mask, value;
0155 int thresh, tuse;
0156
0157 class = mpc7450_classify_event(event);
0158 if (class < 0)
0159 return -1;
0160 if (class == 4) {
0161 pmc = ((unsigned int)event >> PM_PMC_SH) & PM_PMC_MSK;
0162 mask = pmcbits[pmc - 1][0];
0163 value = pmcbits[pmc - 1][1];
0164 } else {
0165 mask = classbits[class][0];
0166 value = classbits[class][1];
0167 }
0168
0169 tuse = mpc7450_threshold_use(event);
0170 if (tuse) {
0171 thresh = ((unsigned int)event >> PM_THRESH_SH) & PM_THRESH_MSK;
0172 mask |= 0x3f << 24;
0173 value |= thresh << 24;
0174 if (tuse == 2) {
0175 mask |= 0x40000000;
0176 if ((unsigned int)event & PM_THRMULT_MSKS)
0177 value |= 0x40000000;
0178 }
0179 }
0180
0181 *maskp = mask;
0182 *valp = value;
0183 return 0;
0184 }
0185
0186 static const unsigned int event_alternatives[][MAX_ALT] = {
0187 { 0x217, 0x317 },
0188 { 0x418, 0x50f, 0x60f },
0189 { 0x502, 0x602 },
0190 { 0x503, 0x603 },
0191 { 0x504, 0x604 },
0192 { 0x505, 0x605 },
0193 { 0x506, 0x606 },
0194 { 0x507, 0x607 },
0195 { 0x50a, 0x623 },
0196 { 0x50b, 0x624 },
0197 { 0x50d, 0x60d },
0198 { 0x50e, 0x60e },
0199 { 0x512, 0x612 },
0200 { 0x513, 0x61d },
0201 { 0x514, 0x61e },
0202 };
0203
0204
0205
0206
0207
0208 static int find_alternative(u32 event)
0209 {
0210 int i, j;
0211
0212 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
0213 if (event < event_alternatives[i][0])
0214 break;
0215 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
0216 if (event == event_alternatives[i][j])
0217 return i;
0218 }
0219 return -1;
0220 }
0221
0222 static int mpc7450_get_alternatives(u64 event, unsigned int flags, u64 alt[])
0223 {
0224 int i, j, nalt = 1;
0225 u32 ae;
0226
0227 alt[0] = event;
0228 nalt = 1;
0229 i = find_alternative((u32)event);
0230 if (i >= 0) {
0231 for (j = 0; j < MAX_ALT; ++j) {
0232 ae = event_alternatives[i][j];
0233 if (ae && ae != (u32)event)
0234 alt[nalt++] = ae;
0235 }
0236 }
0237 return nalt;
0238 }
0239
0240
0241
0242
0243
0244 static const u8 classmap[N_CLASSES] = {
0245 0x3f, 0x0f, 0x0b, 0x03, 0
0246 };
0247
0248
0249 static const int pmcsel_shift[N_COUNTER] = {
0250 6, 0, 27, 22, 17, 11
0251 };
0252 static const u32 pmcsel_mask[N_COUNTER] = {
0253 0x7f, 0x3f, 0x1f, 0x1f, 0x1f, 0x3f
0254 };
0255
0256
0257
0258
0259 static int mpc7450_compute_mmcr(u64 event[], int n_ev, unsigned int hwc[],
0260 struct mmcr_regs *mmcr,
0261 struct perf_event *pevents[],
0262 u32 flags __maybe_unused)
0263 {
0264 u8 event_index[N_CLASSES][N_COUNTER];
0265 int n_classevent[N_CLASSES];
0266 int i, j, class, tuse;
0267 u32 pmc_inuse = 0, pmc_avail;
0268 u32 mmcr0 = 0, mmcr1 = 0, mmcr2 = 0;
0269 u32 ev, pmc, thresh;
0270
0271 if (n_ev > N_COUNTER)
0272 return -1;
0273
0274
0275 for (i = 0; i < N_CLASSES; ++i)
0276 n_classevent[i] = 0;
0277 for (i = 0; i < n_ev; ++i) {
0278 class = mpc7450_classify_event(event[i]);
0279 if (class < 0)
0280 return -1;
0281 j = n_classevent[class]++;
0282 event_index[class][j] = i;
0283 }
0284
0285
0286 for (class = N_CLASSES - 1; class >= 0; --class) {
0287 for (i = 0; i < n_classevent[class]; ++i) {
0288 ev = event[event_index[class][i]];
0289 if (class == 4) {
0290 pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
0291 if (pmc_inuse & (1 << (pmc - 1)))
0292 return -1;
0293 } else {
0294
0295 pmc_avail = classmap[class] & ~pmc_inuse;
0296 if (!pmc_avail)
0297 return -1;
0298 pmc = ffs(pmc_avail);
0299 }
0300 pmc_inuse |= 1 << (pmc - 1);
0301
0302 tuse = mpc7450_threshold_use(ev);
0303 if (tuse) {
0304 thresh = (ev >> PM_THRESH_SH) & PM_THRESH_MSK;
0305 mmcr0 |= thresh << 16;
0306 if (tuse == 2 && (ev & PM_THRMULT_MSKS))
0307 mmcr2 = 0x80000000;
0308 }
0309 ev &= pmcsel_mask[pmc - 1];
0310 ev <<= pmcsel_shift[pmc - 1];
0311 if (pmc <= 2)
0312 mmcr0 |= ev;
0313 else
0314 mmcr1 |= ev;
0315 hwc[event_index[class][i]] = pmc - 1;
0316 }
0317 }
0318
0319 if (pmc_inuse & 1)
0320 mmcr0 |= MMCR0_PMC1CE;
0321 if (pmc_inuse & 0x3e)
0322 mmcr0 |= MMCR0_PMCnCE;
0323
0324
0325 mmcr->mmcr0 = mmcr0;
0326 mmcr->mmcr1 = mmcr1;
0327 mmcr->mmcr2 = mmcr2;
0328
0329
0330
0331
0332
0333
0334 mmcr->mmcra = mmcr2;
0335 return 0;
0336 }
0337
0338
0339
0340
0341
0342 static void mpc7450_disable_pmc(unsigned int pmc, struct mmcr_regs *mmcr)
0343 {
0344 if (pmc <= 1)
0345 mmcr->mmcr0 &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
0346 else
0347 mmcr->mmcr1 &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
0348 }
0349
0350 static int mpc7450_generic_events[] = {
0351 [PERF_COUNT_HW_CPU_CYCLES] = 1,
0352 [PERF_COUNT_HW_INSTRUCTIONS] = 2,
0353 [PERF_COUNT_HW_CACHE_MISSES] = 0x217,
0354 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x122,
0355 [PERF_COUNT_HW_BRANCH_MISSES] = 0x41c,
0356 };
0357
0358 #define C(x) PERF_COUNT_HW_CACHE_##x
0359
0360
0361
0362
0363
0364
0365 static u64 mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
0366 [C(L1D)] = {
0367 [C(OP_READ)] = { 0, 0x225 },
0368 [C(OP_WRITE)] = { 0, 0x227 },
0369 [C(OP_PREFETCH)] = { 0, 0 },
0370 },
0371 [C(L1I)] = {
0372 [C(OP_READ)] = { 0x129, 0x115 },
0373 [C(OP_WRITE)] = { -1, -1 },
0374 [C(OP_PREFETCH)] = { 0x634, 0 },
0375 },
0376 [C(LL)] = {
0377 [C(OP_READ)] = { 0, 0 },
0378 [C(OP_WRITE)] = { 0, 0 },
0379 [C(OP_PREFETCH)] = { 0, 0 },
0380 },
0381 [C(DTLB)] = {
0382 [C(OP_READ)] = { 0, 0x312 },
0383 [C(OP_WRITE)] = { -1, -1 },
0384 [C(OP_PREFETCH)] = { -1, -1 },
0385 },
0386 [C(ITLB)] = {
0387 [C(OP_READ)] = { 0, 0x223 },
0388 [C(OP_WRITE)] = { -1, -1 },
0389 [C(OP_PREFETCH)] = { -1, -1 },
0390 },
0391 [C(BPU)] = {
0392 [C(OP_READ)] = { 0x122, 0x41c },
0393 [C(OP_WRITE)] = { -1, -1 },
0394 [C(OP_PREFETCH)] = { -1, -1 },
0395 },
0396 [C(NODE)] = {
0397 [C(OP_READ)] = { -1, -1 },
0398 [C(OP_WRITE)] = { -1, -1 },
0399 [C(OP_PREFETCH)] = { -1, -1 },
0400 },
0401 };
0402
0403 struct power_pmu mpc7450_pmu = {
0404 .name = "MPC7450 family",
0405 .n_counter = N_COUNTER,
0406 .max_alternatives = MAX_ALT,
0407 .add_fields = 0x00111555ul,
0408 .test_adder = 0x00301000ul,
0409 .compute_mmcr = mpc7450_compute_mmcr,
0410 .get_constraint = mpc7450_get_constraint,
0411 .get_alternatives = mpc7450_get_alternatives,
0412 .disable_pmc = mpc7450_disable_pmc,
0413 .n_generic = ARRAY_SIZE(mpc7450_generic_events),
0414 .generic_events = mpc7450_generic_events,
0415 .cache_events = &mpc7450_cache_events,
0416 };
0417
0418 static int __init init_mpc7450_pmu(void)
0419 {
0420 unsigned int pvr = mfspr(SPRN_PVR);
0421
0422 if (PVR_VER(pvr) != PVR_7450)
0423 return -ENODEV;
0424
0425 return register_power_pmu(&mpc7450_pmu);
0426 }
0427
0428 early_initcall(init_mpc7450_pmu);