Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/perf_event.h>
0003 #include <linux/types.h>
0004 
0005 #include "../perf_event.h"
0006 
0007 /*
0008  * Not sure about some of these
0009  */
0010 static const u64 p6_perfmon_event_map[] =
0011 {
0012   [PERF_COUNT_HW_CPU_CYCLES]        = 0x0079,   /* CPU_CLK_UNHALTED */
0013   [PERF_COUNT_HW_INSTRUCTIONS]      = 0x00c0,   /* INST_RETIRED     */
0014   [PERF_COUNT_HW_CACHE_REFERENCES]  = 0x0f2e,   /* L2_RQSTS:M:E:S:I */
0015   [PERF_COUNT_HW_CACHE_MISSES]      = 0x012e,   /* L2_RQSTS:I       */
0016   [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]   = 0x00c4,   /* BR_INST_RETIRED  */
0017   [PERF_COUNT_HW_BRANCH_MISSES]     = 0x00c5,   /* BR_MISS_PRED_RETIRED */
0018   [PERF_COUNT_HW_BUS_CYCLES]        = 0x0062,   /* BUS_DRDY_CLOCKS  */
0019   [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00a2, /* RESOURCE_STALLS  */
0020 
0021 };
0022 
0023 static const u64 __initconst p6_hw_cache_event_ids
0024                 [PERF_COUNT_HW_CACHE_MAX]
0025                 [PERF_COUNT_HW_CACHE_OP_MAX]
0026                 [PERF_COUNT_HW_CACHE_RESULT_MAX] =
0027 {
0028  [ C(L1D) ] = {
0029     [ C(OP_READ) ] = {
0030         [ C(RESULT_ACCESS) ] = 0x0043,  /* DATA_MEM_REFS       */
0031                 [ C(RESULT_MISS)   ] = 0x0045,  /* DCU_LINES_IN        */
0032     },
0033     [ C(OP_WRITE) ] = {
0034         [ C(RESULT_ACCESS) ] = 0,
0035         [ C(RESULT_MISS)   ] = 0x0f29,  /* L2_LD:M:E:S:I       */
0036     },
0037         [ C(OP_PREFETCH) ] = {
0038         [ C(RESULT_ACCESS) ] = 0,
0039         [ C(RESULT_MISS)   ] = 0,
0040         },
0041  },
0042  [ C(L1I ) ] = {
0043     [ C(OP_READ) ] = {
0044         [ C(RESULT_ACCESS) ] = 0x0080,  /* IFU_IFETCH         */
0045         [ C(RESULT_MISS)   ] = 0x0f28,  /* L2_IFETCH:M:E:S:I  */
0046     },
0047     [ C(OP_WRITE) ] = {
0048         [ C(RESULT_ACCESS) ] = -1,
0049         [ C(RESULT_MISS)   ] = -1,
0050     },
0051     [ C(OP_PREFETCH) ] = {
0052         [ C(RESULT_ACCESS) ] = 0,
0053         [ C(RESULT_MISS)   ] = 0,
0054     },
0055  },
0056  [ C(LL  ) ] = {
0057     [ C(OP_READ) ] = {
0058         [ C(RESULT_ACCESS) ] = 0,
0059         [ C(RESULT_MISS)   ] = 0,
0060     },
0061     [ C(OP_WRITE) ] = {
0062         [ C(RESULT_ACCESS) ] = 0,
0063         [ C(RESULT_MISS)   ] = 0x0025,  /* L2_M_LINES_INM     */
0064     },
0065     [ C(OP_PREFETCH) ] = {
0066         [ C(RESULT_ACCESS) ] = 0,
0067         [ C(RESULT_MISS)   ] = 0,
0068     },
0069  },
0070  [ C(DTLB) ] = {
0071     [ C(OP_READ) ] = {
0072         [ C(RESULT_ACCESS) ] = 0x0043,  /* DATA_MEM_REFS      */
0073         [ C(RESULT_MISS)   ] = 0,
0074     },
0075     [ C(OP_WRITE) ] = {
0076         [ C(RESULT_ACCESS) ] = 0,
0077         [ C(RESULT_MISS)   ] = 0,
0078     },
0079     [ C(OP_PREFETCH) ] = {
0080         [ C(RESULT_ACCESS) ] = 0,
0081         [ C(RESULT_MISS)   ] = 0,
0082     },
0083  },
0084  [ C(ITLB) ] = {
0085     [ C(OP_READ) ] = {
0086         [ C(RESULT_ACCESS) ] = 0x0080,  /* IFU_IFETCH         */
0087         [ C(RESULT_MISS)   ] = 0x0085,  /* ITLB_MISS          */
0088     },
0089     [ C(OP_WRITE) ] = {
0090         [ C(RESULT_ACCESS) ] = -1,
0091         [ C(RESULT_MISS)   ] = -1,
0092     },
0093     [ C(OP_PREFETCH) ] = {
0094         [ C(RESULT_ACCESS) ] = -1,
0095         [ C(RESULT_MISS)   ] = -1,
0096     },
0097  },
0098  [ C(BPU ) ] = {
0099     [ C(OP_READ) ] = {
0100         [ C(RESULT_ACCESS) ] = 0x00c4,  /* BR_INST_RETIRED      */
0101         [ C(RESULT_MISS)   ] = 0x00c5,  /* BR_MISS_PRED_RETIRED */
0102         },
0103     [ C(OP_WRITE) ] = {
0104         [ C(RESULT_ACCESS) ] = -1,
0105         [ C(RESULT_MISS)   ] = -1,
0106     },
0107     [ C(OP_PREFETCH) ] = {
0108         [ C(RESULT_ACCESS) ] = -1,
0109         [ C(RESULT_MISS)   ] = -1,
0110     },
0111  },
0112 };
0113 
0114 static u64 p6_pmu_event_map(int hw_event)
0115 {
0116     return p6_perfmon_event_map[hw_event];
0117 }
0118 
0119 /*
0120  * Event setting that is specified not to count anything.
0121  * We use this to effectively disable a counter.
0122  *
0123  * L2_RQSTS with 0 MESI unit mask.
0124  */
0125 #define P6_NOP_EVENT            0x0000002EULL
0126 
0127 static struct event_constraint p6_event_constraints[] =
0128 {
0129     INTEL_EVENT_CONSTRAINT(0xc1, 0x1),  /* FLOPS */
0130     INTEL_EVENT_CONSTRAINT(0x10, 0x1),  /* FP_COMP_OPS_EXE */
0131     INTEL_EVENT_CONSTRAINT(0x11, 0x2),  /* FP_ASSIST */
0132     INTEL_EVENT_CONSTRAINT(0x12, 0x2),  /* MUL */
0133     INTEL_EVENT_CONSTRAINT(0x13, 0x2),  /* DIV */
0134     INTEL_EVENT_CONSTRAINT(0x14, 0x1),  /* CYCLES_DIV_BUSY */
0135     EVENT_CONSTRAINT_END
0136 };
0137 
0138 static void p6_pmu_disable_all(void)
0139 {
0140     u64 val;
0141 
0142     /* p6 only has one enable register */
0143     rdmsrl(MSR_P6_EVNTSEL0, val);
0144     val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
0145     wrmsrl(MSR_P6_EVNTSEL0, val);
0146 }
0147 
0148 static void p6_pmu_enable_all(int added)
0149 {
0150     unsigned long val;
0151 
0152     /* p6 only has one enable register */
0153     rdmsrl(MSR_P6_EVNTSEL0, val);
0154     val |= ARCH_PERFMON_EVENTSEL_ENABLE;
0155     wrmsrl(MSR_P6_EVNTSEL0, val);
0156 }
0157 
0158 static inline void
0159 p6_pmu_disable_event(struct perf_event *event)
0160 {
0161     struct hw_perf_event *hwc = &event->hw;
0162     u64 val = P6_NOP_EVENT;
0163 
0164     (void)wrmsrl_safe(hwc->config_base, val);
0165 }
0166 
0167 static void p6_pmu_enable_event(struct perf_event *event)
0168 {
0169     struct hw_perf_event *hwc = &event->hw;
0170     u64 val;
0171 
0172     val = hwc->config;
0173 
0174     /*
0175      * p6 only has a global event enable, set on PerfEvtSel0
0176      * We "disable" events by programming P6_NOP_EVENT
0177      * and we rely on p6_pmu_enable_all() being called
0178      * to actually enable the events.
0179      */
0180 
0181     (void)wrmsrl_safe(hwc->config_base, val);
0182 }
0183 
0184 PMU_FORMAT_ATTR(event,  "config:0-7"    );
0185 PMU_FORMAT_ATTR(umask,  "config:8-15"   );
0186 PMU_FORMAT_ATTR(edge,   "config:18" );
0187 PMU_FORMAT_ATTR(pc, "config:19" );
0188 PMU_FORMAT_ATTR(inv,    "config:23" );
0189 PMU_FORMAT_ATTR(cmask,  "config:24-31"  );
0190 
0191 static struct attribute *intel_p6_formats_attr[] = {
0192     &format_attr_event.attr,
0193     &format_attr_umask.attr,
0194     &format_attr_edge.attr,
0195     &format_attr_pc.attr,
0196     &format_attr_inv.attr,
0197     &format_attr_cmask.attr,
0198     NULL,
0199 };
0200 
0201 static __initconst const struct x86_pmu p6_pmu = {
0202     .name           = "p6",
0203     .handle_irq     = x86_pmu_handle_irq,
0204     .disable_all        = p6_pmu_disable_all,
0205     .enable_all     = p6_pmu_enable_all,
0206     .enable         = p6_pmu_enable_event,
0207     .disable        = p6_pmu_disable_event,
0208     .hw_config      = x86_pmu_hw_config,
0209     .schedule_events    = x86_schedule_events,
0210     .eventsel       = MSR_P6_EVNTSEL0,
0211     .perfctr        = MSR_P6_PERFCTR0,
0212     .event_map      = p6_pmu_event_map,
0213     .max_events     = ARRAY_SIZE(p6_perfmon_event_map),
0214     .apic           = 1,
0215     .max_period     = (1ULL << 31) - 1,
0216     .version        = 0,
0217     .num_counters       = 2,
0218     /*
0219      * Events have 40 bits implemented. However they are designed such
0220      * that bits [32-39] are sign extensions of bit 31. As such the
0221      * effective width of a event for P6-like PMU is 32 bits only.
0222      *
0223      * See IA-32 Intel Architecture Software developer manual Vol 3B
0224      */
0225     .cntval_bits        = 32,
0226     .cntval_mask        = (1ULL << 32) - 1,
0227     .get_event_constraints  = x86_get_event_constraints,
0228     .event_constraints  = p6_event_constraints,
0229 
0230     .format_attrs       = intel_p6_formats_attr,
0231     .events_sysfs_show  = intel_event_sysfs_show,
0232 
0233 };
0234 
0235 static __init void p6_pmu_rdpmc_quirk(void)
0236 {
0237     if (boot_cpu_data.x86_stepping < 9) {
0238         /*
0239          * PPro erratum 26; fixed in stepping 9 and above.
0240          */
0241         pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
0242         x86_pmu.attr_rdpmc_broken = 1;
0243         x86_pmu.attr_rdpmc = 0;
0244     }
0245 }
0246 
0247 __init int p6_pmu_init(void)
0248 {
0249     x86_pmu = p6_pmu;
0250 
0251     switch (boot_cpu_data.x86_model) {
0252     case  1: /* Pentium Pro */
0253         x86_add_quirk(p6_pmu_rdpmc_quirk);
0254         break;
0255 
0256     case  3: /* Pentium II - Klamath */
0257     case  5: /* Pentium II - Deschutes */
0258     case  6: /* Pentium II - Mendocino */
0259         break;
0260 
0261     case  7: /* Pentium III - Katmai */
0262     case  8: /* Pentium III - Coppermine */
0263     case 10: /* Pentium III Xeon */
0264     case 11: /* Pentium III - Tualatin */
0265         break;
0266 
0267     case  9: /* Pentium M - Banias */
0268     case 13: /* Pentium M - Dothan */
0269         break;
0270 
0271     default:
0272         pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model);
0273         return -ENODEV;
0274     }
0275 
0276     memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
0277         sizeof(hw_cache_event_ids));
0278 
0279     return 0;
0280 }