s390/cpumf: support user space events for counting
authorThomas Richter <tmricht@linux.ibm.com>
Fri, 23 Dec 2022 10:03:32 +0000 (11:03 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Mon, 9 Jan 2023 13:33:56 +0000 (14:33 +0100)
CPU Measurement counting facility events PROBLEM_STATE_CPU_CYCLES(32)
and PROBLEM_STATE_INSTRUCTIONS(33) are valid events. However the device
driver returns error -EOPNOTSUPP when these event are to be installed.

Fix this and allow installation of events PROBLEM_STATE_CPU_CYCLES,
PROBLEM_STATE_CPU_CYCLES:u, PROBLEM_STATE_INSTRUCTIONS and
PROBLEM_STATE_INSTRUCTIONS:u.
Kernel space counting only is still not supported by s390.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/kernel/perf_cpum_cf.c

index f043a7ff220b72e5e5008e8db4cf4c8d80147e9c..28fa80fd69fa0db29298e7278a1823081f81f132 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Performance event support for s390x - CPU-measurement Counter Facility
  *
- *  Copyright IBM Corp. 2012, 2021
+ *  Copyright IBM Corp. 2012, 2022
  *  Author(s): Hendrik Brueckner <brueckner@linux.ibm.com>
  *            Thomas Richter <tmricht@linux.ibm.com>
  */
@@ -434,6 +434,12 @@ static void cpumf_hw_inuse(void)
        mutex_unlock(&pmc_reserve_mutex);
 }
 
+static int is_userspace_event(u64 ev)
+{
+       return cpumf_generic_events_user[PERF_COUNT_HW_CPU_CYCLES] == ev ||
+              cpumf_generic_events_user[PERF_COUNT_HW_INSTRUCTIONS] == ev;
+}
+
 static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
 {
        struct perf_event_attr *attr = &event->attr;
@@ -456,19 +462,26 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
                if (is_sampling_event(event))   /* No sampling support */
                        return -ENOENT;
                ev = attr->config;
-               /* Count user space (problem-state) only */
                if (!attr->exclude_user && attr->exclude_kernel) {
-                       if (ev >= ARRAY_SIZE(cpumf_generic_events_user))
-                               return -EOPNOTSUPP;
-                       ev = cpumf_generic_events_user[ev];
-
-               /* No support for kernel space counters only */
+                       /*
+                        * Count user space (problem-state) only
+                        * Handle events 32 and 33 as 0:u and 1:u
+                        */
+                       if (!is_userspace_event(ev)) {
+                               if (ev >= ARRAY_SIZE(cpumf_generic_events_user))
+                                       return -EOPNOTSUPP;
+                               ev = cpumf_generic_events_user[ev];
+                       }
                } else if (!attr->exclude_kernel && attr->exclude_user) {
+                       /* No support for kernel space counters only */
                        return -EOPNOTSUPP;
-               } else {        /* Count user and kernel space */
-                       if (ev >= ARRAY_SIZE(cpumf_generic_events_basic))
-                               return -EOPNOTSUPP;
-                       ev = cpumf_generic_events_basic[ev];
+               } else {
+                       /* Count user and kernel space, incl. events 32 + 33 */
+                       if (!is_userspace_event(ev)) {
+                               if (ev >= ARRAY_SIZE(cpumf_generic_events_basic))
+                                       return -EOPNOTSUPP;
+                               ev = cpumf_generic_events_basic[ev];
+                       }
                }
                break;