Add PMU support for the CPU-measurement counter facility available
for Linux on System z instances.  The CPU-measurement counter facility
provides multiple counter sets for measuring generic, problem-state,
and crypto activaties.  Also an extended counter set for the
IBM System z10 and IBM z196 mainframes is available.

Signed-off-by: Hendrik Brueckner <brueck...@linux.vnet.ibm.com>
---
 config.mk                       |    4 +
 include/perfmon/pfmlib.h        |    2 +
 lib/Makefile                    |   14 +
 lib/events/s390x_cpumf_events.h |  562 +++++++++++++++++++++++++++++++++++++++
 lib/pfmlib_common.c             |    3 +
 lib/pfmlib_priv.h               |    1 +
 lib/pfmlib_s390x_cpumf.c        |  265 ++++++++++++++++++
 lib/pfmlib_s390x_perf_event.c   |   52 ++++
 lib/pfmlib_s390x_priv.h         |   15 +
 9 files changed, 918 insertions(+), 0 deletions(-)
 create mode 100644 lib/events/s390x_cpumf_events.h
 create mode 100644 lib/pfmlib_s390x_cpumf.c
 create mode 100644 lib/pfmlib_s390x_perf_event.c
 create mode 100644 lib/pfmlib_s390x_priv.h

diff --git a/config.mk b/config.mk
index 29d848f..9e5504c 100644
--- a/config.mk
+++ b/config.mk
@@ -146,6 +146,10 @@ ifeq ($(ARCH),arm)
 CONFIG_PFMLIB_ARCH_ARM=y
 endif
 
+ifeq ($(ARCH),s390x)
+CONFIG_PFMLIB_ARCH_S390X=y
+endif
+
 ifeq ($(XTPE_COMPILE_TARGET),linux)
 CONFIG_PFMLIB_ARCH_CRAYXT=y
 endif
diff --git a/include/perfmon/pfmlib.h b/include/perfmon/pfmlib.h
index 6af4328..b122ca5 100644
--- a/include/perfmon/pfmlib.h
+++ b/include/perfmon/pfmlib.h
@@ -178,6 +178,8 @@ typedef enum {
        PFM_PMU_INTEL_SNBEP_UNC_R3QPI1, /* Intel SandyBridge-EP R3QPI 1 uncore 
*/
        PFM_PMU_INTEL_KNC,              /* Intel Knights Corner (Xeon Phi) */
 
+       PFM_PMU_S390X_CPUM_CF,          /* s390x: CPU-M counter facility */
+
        /* MUST ADD NEW PMU MODELS HERE */
 
        PFM_PMU_MAX                     /* end marker */
diff --git a/lib/Makefile b/lib/Makefile
index 3d36063..d2f00a9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -98,6 +98,17 @@ SRCS   += pfmlib_powerpc.c pfmlib_power4.c pfmlib_ppc970.c 
pfmlib_power5.c pfmli
 CFLAGS += -DCONFIG_PFMLIB_ARCH_POWERPC
 endif
 
+ifeq ($(CONFIG_PFMLIB_ARCH_S390X),y)
+
+ifeq ($(SYS),Linux)
+SRCS += pfmlib_s390x_perf_event.c
+endif
+
+INCARCH = $(INC_S390X)
+SRCS   += pfmlib_s390x_cpumf.c
+CFLAGS += -DCONFIG_PFMLIB_ARCH_S390X
+endif
+
 ifeq ($(CONFIG_PFMLIB_ARCH_SPARC),y)
 
 ifeq ($(SYS),Linux)
@@ -216,6 +227,9 @@ INC_POWERPC=events/ppc970_events.h  \
        events/power7_events.h          \
        events/torrent_events.h
 
+INC_S390X=pfmlib_s390x_priv.h \
+       events/s390x_cpumf_events.h
+
 INC_SPARC=events/sparc_ultra12_events.h                \
        events/sparc_ultra3_events.h            \
        events/sparc_ultra3plus_events.h        \
diff --git a/lib/events/s390x_cpumf_events.h b/lib/events/s390x_cpumf_events.h
new file mode 100644
index 0000000..9628cee
--- /dev/null
+++ b/lib/events/s390x_cpumf_events.h
@@ -0,0 +1,562 @@
+#ifndef __S390X_CPUMF_EVENTS_H__
+#define __S390X_CPUMF_EVENTS_H__
+
+
+#define __stringify(x)         #x
+#define STRINGIFY(x)           __stringify(x)
+
+/* CPUMF counter sets */
+#define CPUMF_CTRSET_BASIC           0
+#define CPUMF_CTRSET_PROBLEM_STATE    1
+#define CPUMF_CTRSET_CRYPTO          2
+#define CPUMF_CTRSET_EXTENDED        3
+
+
+static const pme_cpumf_ctr_t cpumf_generic_ctr[] = {
+       /* Basic counter set */
+       {
+               .ctrnum = 0,
+               .ctrset = CPUMF_CTRSET_BASIC,
+               .name = "CPU_CYCLES",
+               .desc = "Cycle Count",
+       },
+       {
+               .ctrnum = 1,
+               .ctrset = CPUMF_CTRSET_BASIC,
+               .name = "INSTRUCTIONS",
+               .desc = "Instruction Count",
+       },
+       {
+               .ctrnum = 2,
+               .ctrset = CPUMF_CTRSET_BASIC,
+               .name = "L1I_DRCT_WRITES",
+               .desc = "Level-1 I-Cache Directory Write Count",
+       },
+       {
+               .ctrnum = 3,
+               .ctrset = CPUMF_CTRSET_BASIC,
+               .name = "L1I_PENALTY_CYCLES",
+               .desc = "Level-1 I-Cache Penalty Cycle Count",
+       },
+       {
+               .ctrnum = 4,
+               .ctrset = CPUMF_CTRSET_BASIC,
+               .name = "L1D_DRCT_WRITES",
+               .desc = "Level-1 D-Cache Directory Write Count",
+       },
+       {
+               .ctrnum = 5,
+               .ctrset = CPUMF_CTRSET_BASIC,
+               .name = "L1D_PENALTY_CYCLES",
+               .desc = "Level-1 D-Cache Penalty Cycle Count",
+       },
+       /* Problem-state counter set */
+       {
+               .ctrnum = 32,
+               .ctrset = CPUMF_CTRSET_PROBLEM_STATE,
+               .name = "PROBLEM_STATE_CPU_CYCLES",
+               .desc = "Problem-State Cycle Count",
+       },
+       {
+               .ctrnum = 33,
+               .ctrset = CPUMF_CTRSET_PROBLEM_STATE,
+               .name = "PROBLEM_STATE_INSTRUCTIONS",
+               .desc = "Problem-State Instruction Count",
+       },
+       {
+               .ctrnum = 34,
+               .ctrset = CPUMF_CTRSET_PROBLEM_STATE,
+               .name = "PROBLEM_STATE_L1I_DRCT_WRITES",
+               .desc = "Problem-State Level-1 I-Cache Directory Write Count",
+       },
+       {
+               .ctrnum = 35,
+               .ctrset = CPUMF_CTRSET_PROBLEM_STATE,
+               .name = "PROBLEM_STATE_L1I_PENALTY_CYCLES",
+               .desc = "Problem-State Level-1 I-Cache Penalty Cycle Count",
+       },
+       {
+               .ctrnum = 36,
+               .ctrset = CPUMF_CTRSET_PROBLEM_STATE,
+               .name = "PROBLEM_STATE_L1D_DRCT_WRITES",
+               .desc = "Problem-State Level-1 D-Cache Directory Write Count",
+       },
+       {
+               .ctrnum = 37,
+               .ctrset = CPUMF_CTRSET_PROBLEM_STATE,
+               .name = "PROBLEM_STATE_L1D_PENALTY_CYCLES",
+               .desc = "Problem-State Level-1 D-Cache Penalty Cycle Count",
+       },
+       /* Crypto-activity counter set */
+       {
+               .ctrnum = 64,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "PRNG_FUNCTIONS",
+               .desc = "Total number of the PRNG functions issued by the CPU",
+       },
+       {
+               .ctrnum = 65,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "PRNG_CYCLES",
+               .desc = "Total number of CPU cycles when the DEA/AES "
+                       "coprocessor is busy performing PRNG functions "
+                       "issued by the CPU",
+       },
+       {
+               .ctrnum = 66,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "PRNG_BLOCKED_FUNCTIONS",
+               .desc = "Total number of the PRNG functions that are issued "
+                       "by the CPU and are blocked because the DEA/AES "
+                       "coprocessor is busy performing a function issued "
+                       "by another CPU",
+       },
+       {
+               .ctrnum = 67,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "PRNG_BLOCKED_CYCLES",
+               .desc = "Total number of CPU cycles blocked for the PRNG "
+                       "functions issued by the CPU because the DEA/AES "
+                       "coprocessor is busy performing a function issued "
+                       "by another CPU",
+       },
+       {
+               .ctrnum = 68,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "SHA_FUNCTIONS",
+               .desc = "Total number of SHA functions issued by the CPU",
+       },
+       {
+               .ctrnum = 69,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "SHA_CYCLES",
+               .desc = "Total number of CPU cycles when the SHA coprocessor "
+                       "is busy performing the SHA functions issued by the "
+                       "CPU",
+       },
+       {
+               .ctrnum = 70,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "SHA_BLOCKED_FUNCTIONS",
+               .desc = "Total number of the SHA functions that are issued by "
+                       "the CPU and are blocked because the SHA coprocessor "
+                       "is busy performing a function issued by another CPU",
+       },
+       {
+               .ctrnum = 71,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "SHA_BLOCKED_CYCLES",
+               .desc = "Total number of CPU cycles blocked for the SHA "
+                       "functions issued by the CPU because the SHA "
+                       "coprocessor is busy performing a function issued by "
+                       "another CPU",
+       },
+       {
+               .ctrnum = 72,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "DEA_FUNCTIONS",
+               .desc = "Total number of the DEA functions issued by the CPU",
+       },
+       {
+               .ctrnum = 73,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "DEA_CYCLES",
+               .desc = "Total number of CPU cycles when the DEA/AES 
coprocessor"
+                       " is busy performing the DEA functions issued by the 
CPU",
+       },
+       {
+               .ctrnum = 74,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "DEA_BLOCKED_FUNCTIONS",
+               .desc = "Total number of the DEA functions that are issued by "
+                       "the CPU and are blocked because the DEA/AES 
coprocessor"
+                       " is busy performing a function issued by another CPU",
+       },
+       {
+               .ctrnum = 75,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "DEA_BLOCKED_CYCLES",
+               .desc = "Total number of CPU cycles blocked for the DEA 
functions"
+                       " issued by the CPU because the DEA/AES coprocessor is "
+                       "busy performing a function issued by another CPU",
+       },
+       {
+               .ctrnum = 76,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "AES_FUNCTIONS",
+               .desc = "Total number of AES functions issued by the CPU",
+       },
+       {
+               .ctrnum = 77,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "AES_CYCLES",
+               .desc = "Total number of CPU cycles when the DEA/AES 
coprocessor"
+                       " is busy performing the AES functions issued by the 
CPU",
+       },
+       {
+               .ctrnum = 78,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "AES_BLOCKED_FUNCTIONS",
+               .desc = "Total number of AES functions that are issued by the 
CPU"
+                       " and are blocked because the DEA/AES coprocessor is"
+                       " busy performing a function issued by another CPU",
+       },
+       {
+               .ctrnum = 79,
+               .ctrset = CPUMF_CTRSET_CRYPTO,
+               .name = "AES_BLOCKED_CYCLES",
+               .desc = "Total number of CPU cycles blocked for the AES 
functions"
+                       " issued by the CPU because the DEA/AES coprocessor is"
+                       " busy performing a function issued by another CPU",
+       },
+};
+
+/* Extended counter set for IBM System z10 */
+static const pme_cpumf_ctr_t cpumf_ctr_set_ext_z10[] = {
+       {
+               .ctrnum = 128,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_L2_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the returned cache line was sourced from the"
+                       " Level-2 (L1.5) cache",
+       },
+       {
+               .ctrnum = 129,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_L2_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the installed cache line was sourced from the"
+                       " Level-2 (L1.5) cache",
+       },
+       {
+               .ctrnum = 130,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_L3_LOCAL_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the installed cache line was sourced from the"
+                       " Level-3 cache that is on the same book as the"
+                       " Instruction cache (Local L2 cache)",
+       },
+       {
+               .ctrnum = 131,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_L3_LOCAL_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the installtion cache line was source from the"
+                       " Level-3 cache that is on the same book as the Data"
+                       " cache (Local L2 cache)",
+       },
+       {
+               .ctrnum = 132,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_L3_REMOTE_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the installed cache line was sourced from a"
+                       " Level-3 cache that is not on the same book as the"
+                       " Instruction cache (Remote L2 cache)",
+       },
+       {
+               .ctrnum = 133,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_L3_REMOTE_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the installed cache line was sourced from a"
+                       " Level-3 cache that is not on the same book as the"
+                       " Data cache (Remote L2 cache)",
+       },
+       {
+               .ctrnum = 134,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_LMEM_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the installed cache line was sourced from"
+                       " memory that is attached to the same book as the"
+                       " Data cache (Local Memory)",
+       },
+       {
+               .ctrnum = 135,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_LMEM_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache where the"
+                       " installed cache line was sourced from memory that"
+                       " is attached to the s ame book as the Instruction"
+                       " cahe (local Memory)",
+       },
+       {
+               .ctrnum = 136,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_RO_EXCL_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache where the"
+                       " line was originally in a Read-Only state in the"
+                       " cache but has been updated to be in the Exclusive"
+                       " state that allows stores to the cache line",
+       },
+       {
+               .ctrnum = 137,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_CACHELINE_INVALIDATES",
+               .desc = "A cache line in the Level-1 I-Cache has been"
+                       " invalidated by a store on the same CPU as the Level-1"
+                       " I-Cache",
+       },
+       {
+               .ctrnum = 138,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "ITLB1_WRITES",
+               .desc = "A translation entry has been written into the Level-1"
+                       " Instruction Translation Lookaside Buffer",
+       },
+       {
+               .ctrnum = 139,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "DTLB1_WRITES",
+               .desc = "A translation entry has been written to the Level-1"
+                       " Data Translation Lookaside Buffer",
+       },
+       {
+               .ctrnum = 140,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "TLB2_PTE_WRITES",
+               .desc = "A translation entry has been written to the Level-2"
+                       " TLB Page Table Entry arrays",
+       },
+       {
+               .ctrnum = 141,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "TLB2_CRSTE_WRITES",
+               .desc = "A translation entry has been written to the Level-2"
+                       " TLB Common Region Segment Table Entry arrays",
+       },
+       {
+               .ctrnum = 142,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "TLB2_CRSTE_HPAGE_WRITES",
+               .desc = "A translation entry has been written to the Level-2"
+                       " TLB Common Region Segment Table Entry arrays for a"
+                       " one-megabyte large page translation",
+       },
+       {
+               .ctrnum = 145,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "ITLB1_MISSES",
+               .desc = "Level-1 Instruction TLB miss in progress. Incremented"
+                       " by one for every cycle an ITLB1 miss is in progress",
+       },
+       {
+               .ctrnum = 146,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "DTLB1_MISSES",
+               .desc = "Level-1 Data TLB miss in progress. Incremented by one"
+                       " for every cycle an DTLB1 miss is in progress",
+       },
+       {
+               .ctrnum = 147,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L2C_STORES_SENT",
+               .desc = "Incremented by one for every store sent to"
+                       " Level-2 (L1.5) cache",
+       },
+};
+
+/* Extended counter set for IBM zEnterprise 196 */
+static const pme_cpumf_ctr_t cpumf_ctr_set_ext_z196[] = {
+       {
+               .ctrnum = 128,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_L2_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the returned cache line was sourced from the"
+                       " Level-2 cache",
+       },
+       {
+               .ctrnum = 129,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_L2_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the returned cache line was sourced from"
+                       " the Level-2 cache",
+       },
+       {
+               .ctrnum = 130,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "DTLB1_MISSES",
+               .desc = "Level-1 Data TLB miss in progress. Incremented by one"
+                       " for every cycle a DTLB1 miss is in progress.",
+       },
+       {
+               .ctrnum = 131,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "ITLB1_MISSES",
+               .desc = "Level-1 Instruction TLB miss in progress. Incremented"
+                       " by one for every cycle a ITLB1 miss is in progress.",
+       },
+       {
+               .ctrnum = 133,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L2C_STORES_SENT",
+               .desc = "Incremented by one for every store sent to"
+                       " Level-2 cache",
+       },
+       {
+               .ctrnum = 134,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_OFFBOOK_L3_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " Off Book Level-3 cache",
+       },
+       {
+               .ctrnum = 135,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_ONBOOK_L4_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " On Book Level-4 cache",
+       },
+       {
+               .ctrnum = 136,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_ONBOOK_L4_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " On Book Level-4 cache",
+       },
+       {
+               .ctrnum = 137,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_RO_EXCL_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache where the"
+                       " line was originally in a Read-Only state in the"
+                       " cache but has been updated to be in the Exclusive"
+                       " state that allows stores to the cache line",
+       },
+       {
+               .ctrnum = 138,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_OFFBOOK_L4_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " Off Book Level-4 cache",
+       },
+       {
+               .ctrnum = 139,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_OFFBOOK_L4_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " Off Book Level-4 cache",
+       },
+       {
+               .ctrnum = 140,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "DTLB1_HPAGE_WRITES",
+               .desc = "A translation entry has been written to the Level-1"
+                       " Data Translation Lookaside Buffer for a one-megabyte"
+                       " page",
+       },
+       {
+               .ctrnum = 141,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_LMEM_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache where the"
+                       " installed cache line was sourced from memory that"
+                       " is attached to the same book as the Data cache"
+                       " (Local Memory)",
+       },
+       {
+               .ctrnum = 142,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_LMEM_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache where the"
+                       " installed cache line was sourced from memory that"
+                       " is attached to the same book as the Instruction"
+                       " cache (Local Memory)",
+       },
+       {
+               .ctrnum = 143,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_OFFBOOK_L3_SOURCED_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " Off Book Level-3 cache",
+       },
+       {
+               .ctrnum = 144,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "DTLB1_WRITES",
+               .desc = "A translation entry has been written to the Level-1"
+                       " Data Translation Lookaside Buffer",
+       },
+       {
+               .ctrnum = 145,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "ITLB1_WRITES",
+               .desc = "A translation entry has been written to the Level-1"
+                       " Instruction Translation Lookaside Buffer",
+       },
+       {
+               .ctrnum = 146,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "TLB2_PTE_WRITES",
+               .desc = "A translation entry has been written to the Level-2"
+                       " TLB Page Table Entry arrays",
+       },
+       {
+               .ctrnum = 147,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "TLB2_CRSTE_HPAGE_WRITES",
+               .desc = "A translation entry has been written to the Level-2"
+                       " TLB Common Region Segment Table Entry arrays for a"
+                       " one-megabyte large page translation",
+       },
+       {
+               .ctrnum = 148,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "TLB2_CRSTE_WRITES",
+               .desc = "A translation entry has been written to the Level-2"
+                       " TLB Common Region Segment Table Entry arrays",
+       },
+       {
+               .ctrnum = 150,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_ONCHIP_L3_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " On Chip Level-3 cache",
+       },
+       {
+               .ctrnum = 152,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1D_OFFCHIP_L3_WRITES",
+               .desc = "A directory write to the Level-1 D-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " Off Chip/On Book Level-3 cache",
+       },
+       {
+               .ctrnum = 153,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_ONCHIP_L3_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " On Chip Level-3 cache",
+       },
+       {
+               .ctrnum = 155,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "L1I_OFFCHIP_L3_WRITES",
+               .desc = "A directory write to the Level-1 I-Cache directory"
+                       " where the returned cache line was sourced from an"
+                       " Off Chip/On Book Level-3 cache",
+       },
+};
+
+#if 0
+       {
+               .ctrnum = ,
+               .ctrset = CPUMF_CTRSET_EXTENDED,
+               .name = "",
+               .desc = "",
+       },
+#endif
+#endif /* __S390X_CPUMF_EVENTS_H__ */
diff --git a/lib/pfmlib_common.c b/lib/pfmlib_common.c
index 765f45b..dcaa0ce 100644
--- a/lib/pfmlib_common.c
+++ b/lib/pfmlib_common.c
@@ -153,6 +153,9 @@ static pfmlib_pmu_t *pfmlib_pmus[]=
        &arm_cortex_a9_support,
        &arm_cortex_a15_support,
 #endif
+#ifdef CONFIG_PFMLIB_ARCH_S390X
+       &s390x_cpum_cf_support,
+#endif
 #ifdef __linux__
        &perf_event_support,
 #endif
diff --git a/lib/pfmlib_priv.h b/lib/pfmlib_priv.h
index 7fb550a..8d3353d 100644
--- a/lib/pfmlib_priv.h
+++ b/lib/pfmlib_priv.h
@@ -275,6 +275,7 @@ extern pfmlib_pmu_t arm_cortex_a8_support;
 extern pfmlib_pmu_t arm_cortex_a9_support;
 extern pfmlib_pmu_t arm_cortex_a15_support;
 extern pfmlib_pmu_t mips_74k_support;
+extern pfmlib_pmu_t s390x_cpum_cf_support;
 
 extern pfmlib_os_t pfmlib_os_perf;
 extern pfmlib_os_t pfmlib_os_perf_ext;
diff --git a/lib/pfmlib_s390x_cpumf.c b/lib/pfmlib_s390x_cpumf.c
new file mode 100644
index 0000000..025c9d2
--- /dev/null
+++ b/lib/pfmlib_s390x_cpumf.c
@@ -0,0 +1,265 @@
+/*
+ * PMU support for the CPU-measurement counter facility
+ *
+ * Copyright IBM Corp. 2012
+ * Contributed by Hendrik Brueckner <brueck...@linux.vnet.ibm.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies
+ * of the Software, and to permit persons to whom the Software is furnished to 
do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in 
all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR 
A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <ctype.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* private library and arch headers */
+#include "pfmlib_priv.h"
+#include "pfmlib_s390x_priv.h"
+#include "pfmlib_perf_event_priv.h"
+#include "events/s390x_cpumf_events.h"
+
+
+#define CPUMF_DEVICE_DIR  "/sys/bus/event_source/devices/cpum_cf"
+#define SYS_INFO         "/proc/sysinfo"
+
+
+/* CPU-measurement counter list (pmu events) */
+static pme_cpumf_ctr_t *cpumcf_pe = NULL;
+
+/* Detect the CPU-measurement facility */
+static int pfm_cpumcf_detect(void *this)
+{
+       if (access(CPUMF_DEVICE_DIR, R_OK))
+               return PFM_ERR_NOTSUPP;
+       return PFM_SUCCESS;
+}
+
+/* Parses the machine type that identifies an IBM mainframe.
+ * These kind of information are from /proc/sysinfo.
+ */
+static long get_machine_type(void)
+{
+       long machine_type;
+       size_t buflen, len;
+       char *buffer, *tmp;
+       FILE *fp;
+
+       machine_type = 0;
+       fp = fopen(SYS_INFO, "r");
+       if (fp == NULL)
+               goto out;
+
+       buffer = NULL;
+       while (pfmlib_getl(&buffer, &buflen, fp) != -1) {
+               /* skip empty lines */
+               if (*buffer == '\n')
+                       continue;
+
+               /* look for 'Type:' entry */
+               if (!strncmp("Type:", buffer, 5)) {
+                       tmp = buffer + 5;    /* set ptr after ':' */
+                       /* skip leading blanks */
+                       while (isspace(*tmp))
+                               tmp++;
+                       /* skip trailing blanks */
+                       len = strlen(tmp);
+                       while (len > 0 && isspace(tmp[len]))
+                               len--;
+                       tmp[len+1] = '\0';
+                       machine_type = strtol(tmp, NULL, 10);
+                       break;
+               }
+       }
+       fclose(fp);
+       free(buffer);
+out:
+       return machine_type;
+}
+
+/* Initialize the PMU representation for CPUMF.
+ *
+ * Set up the PMU events array based on
+ *  - generic (basic, problem-state, and crypto-activaty) counter sets
+ *  - the extended counter depending on the machine type
+ */
+static int pfm_cpumcf_init(void *this)
+{
+       pfmlib_pmu_t *pmu = this;
+       const pme_cpumf_ctr_t *ext_set;
+       size_t generic_count, ext_set_count;
+
+       /* check and assign a machine-specific extended counter set */
+       switch (get_machine_type()) {
+       case 2097:  /* IBM System z10 EC */
+       case 2098:  /* IBM System z10 BC */
+               ext_set = cpumf_ctr_set_ext_z10;
+               ext_set_count = LIBPFM_ARRAY_SIZE(cpumf_ctr_set_ext_z10);
+               break;
+       case 2817:  /* IBM zEnterprise 196 */
+       case 2818:  /* IBM zEnterprise 114 */
+               ext_set = cpumf_ctr_set_ext_z196;
+               ext_set_count = LIBPFM_ARRAY_SIZE(cpumf_ctr_set_ext_z196);
+               break;
+       default:
+               /* No extended counter set for this machine type or there
+                * was an error retrieving the machine type */
+               ext_set = NULL;
+               ext_set_count = 0;
+               break;
+       }
+
+       generic_count = LIBPFM_ARRAY_SIZE(cpumf_generic_ctr);
+
+       cpumcf_pe = calloc(sizeof(*cpumcf_pe), generic_count + ext_set_count);
+       if (cpumcf_pe == NULL)
+               return PFM_ERR_NOMEM;
+
+       memcpy(cpumcf_pe, cpumf_generic_ctr, sizeof(*cpumcf_pe) * 
generic_count);
+       if (ext_set_count)
+               memcpy((void *) (cpumcf_pe + generic_count),
+                      ext_set, sizeof(*cpumcf_pe) * ext_set_count);
+
+       pmu->pe = cpumcf_pe;
+       pmu->pme_count = generic_count + ext_set_count;
+
+       return PFM_SUCCESS;
+}
+
+static void pfm_cpumcf_exit(void *this)
+{
+       pfmlib_pmu_t *pmu = this;
+
+       pmu->pme_count = 0;
+       pmu->pe = NULL;
+
+       free(cpumcf_pe);
+}
+
+static int pfm_cpumcf_get_encoding(void *this, pfmlib_event_desc_t *e)
+{
+       const pme_cpumf_ctr_t *pe = this_pe(this);
+
+       e->count = 1;     /* number of encoded entries in e->codes */
+       e->codes[0] = pe[e->event].ctrnum;
+       evt_strcat(e->fstr, "%s", pe[e->event].name);
+
+       return PFM_SUCCESS;
+}
+
+static int pfm_cpumcf_get_event_first(void *this)
+{
+       return 0;
+}
+
+static int pfm_cpumcf_get_event_next(void *this, int idx)
+{
+       pfmlib_pmu_t *pmu = this;
+
+       if (idx >= (pmu->pme_count - 1))
+               return -1;
+       return idx + 1;
+}
+
+static int pfm_cpumcf_event_is_valid(void *this, int idx)
+{
+       pfmlib_pmu_t *pmu = this;
+
+       return (idx >= 0 && idx < pmu->pme_count);
+}
+
+static int pfm_cpumcf_validate_table(void *this, FILE *fp)
+{
+       pfmlib_pmu_t *pmu = this;
+       const pme_cpumf_ctr_t *pe = this_pe(this);
+       int i, rc;
+
+       rc = PFM_ERR_INVAL;
+       if (pmu->pme_count > CPUMF_COUNTER_MAX) {
+               fprintf(fp, "pmu: %s: pme number exceeded maximum\n",
+                       pmu->name);
+               goto failed;
+       }
+
+       for (i = 0; i < pmu->pme_count; i++) {
+               if (!pe[i].name) {
+                       fprintf(fp, "pmu: %s event: %i: No name\n",
+                               pmu->name, i);
+                       goto failed;
+               }
+               if (!pe[i].desc) {
+                       fprintf(fp, "pmu: %s event: %i: No description\n",
+                               pmu->name, i);
+                       goto failed;
+               }
+       }
+
+       rc = PFM_SUCCESS;
+failed:
+       return rc;
+}
+
+static int pfm_cpumcf_get_event_info(void *this, int idx,
+                                   pfm_event_info_t *info)
+{
+       pfmlib_pmu_t *pmu = this;
+       const pme_cpumf_ctr_t *pe = this_pe(this);
+
+       info->name = pe[idx].name;
+       info->desc = pe[idx].desc;
+       info->code = pe[idx].ctrnum;
+       info->equiv = NULL;
+       info->idx = idx;
+       info->pmu = pmu->pmu;
+       info->is_precise = 0;
+
+       info->nattrs = 0;       /* attributes are not supported */
+
+       return PFM_SUCCESS;
+}
+
+static int pfm_cpumcf_get_event_attr_info(void *this, int idx, int umask_idx,
+                                        pfm_event_attr_info_t *info)
+{
+       /* Attributes are not supported */
+       return PFM_ERR_ATTR;
+}
+
+pfmlib_pmu_t s390x_cpum_cf_support = {
+       .desc      = "CPU-measurement counter facility",
+       .name      = "cpum_cf",
+       .pmu       = PFM_PMU_S390X_CPUM_CF,
+       .type      = PFM_PMU_TYPE_CORE,
+       .flags     = PFMLIB_PMU_FL_ARCH_DFL,
+
+       .num_cntrs       = 0,     /* no general-purpose counters */
+       .num_fixed_cntrs = CPUMF_COUNTER_MAX,   /* fixed counters only */
+       .max_encoding    = 1,
+
+       .pmu_detect    = pfm_cpumcf_detect,
+       .pmu_init      = pfm_cpumcf_init,
+       .pmu_terminate = pfm_cpumcf_exit,
+
+       .get_event_encoding[PFM_OS_NONE] = pfm_cpumcf_get_encoding,
+               PFMLIB_ENCODE_PERF(pfm_s390x_get_perf_encoding),
+       .get_event_first        = pfm_cpumcf_get_event_first,
+       .get_event_next         = pfm_cpumcf_get_event_next,
+       .event_is_valid         = pfm_cpumcf_event_is_valid,
+       .validate_table         = pfm_cpumcf_validate_table,
+       .get_event_info         = pfm_cpumcf_get_event_info,
+       .get_event_attr_info    = pfm_cpumcf_get_event_attr_info,
+};
diff --git a/lib/pfmlib_s390x_perf_event.c b/lib/pfmlib_s390x_perf_event.c
new file mode 100644
index 0000000..fb75892
--- /dev/null
+++ b/lib/pfmlib_s390x_perf_event.c
@@ -0,0 +1,52 @@
+/*
+ * perf_event for Linux on IBM System z
+ *
+ * Copyright IBM Corp. 2012
+ * Contributed by Hendrik Brueckner <brueck...@linux.vnet.ibm.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies
+ * of the Software, and to permit persons to whom the Software is furnished to 
do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in 
all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR 
A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* private library and arch headers */
+#include "pfmlib_priv.h"
+#include "pfmlib_s390x_priv.h"
+#include "pfmlib_perf_event_priv.h"
+
+
+int pfm_s390x_get_perf_encoding(void *this, pfmlib_event_desc_t *e)
+{
+       pfmlib_pmu_t *pmu = this;
+       struct perf_event_attr *attr = e->os_data;
+       int rc;
+
+       if (!pmu->get_event_encoding[PFM_OS_NONE])
+               return PFM_ERR_NOTSUPP;
+
+       /* set up raw pmu event encoding */
+       rc = pmu->get_event_encoding[PFM_OS_NONE](this, e);
+       if (rc == PFM_SUCCESS) {
+               /* currently use raw events only */
+               attr->type = PERF_TYPE_RAW;
+               attr->config = e->codes[0];
+       }
+
+       return rc;
+}
diff --git a/lib/pfmlib_s390x_priv.h b/lib/pfmlib_s390x_priv.h
new file mode 100644
index 0000000..45259f2
--- /dev/null
+++ b/lib/pfmlib_s390x_priv.h
@@ -0,0 +1,15 @@
+#ifndef __PFMLIB_S390X_PRIV_H__
+#define __PFMLIB_S390X_PRIV_H__
+
+#define CPUMF_COUNTER_MAX          160
+typedef struct {
+       uint64_t ctrnum;            /* counter number */
+       unsigned int ctrset;        /* counter set */
+       char *name;                 /* counter ID */
+       char *desc;                 /* short description */
+} pme_cpumf_ctr_t;
+
+#define min(a, b)        ((a) < (b) ? (a) : (b))
+extern int pfm_s390x_get_perf_encoding(void *this, pfmlib_event_desc_t *e);
+
+#endif /* __PFMLIB_S390X_PRIV_H__ */
-- 
1.7.5.4


------------------------------------------------------------------------------
Keep yourself connected to Go Parallel: 
INSIGHTS What's next for parallel hardware, programming and related areas?
Interviews and blogs by thought leaders keep you ahead of the curve.
http://goparallel.sourceforge.net
_______________________________________________
perfmon2-devel mailing list
perfmon2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perfmon2-devel

Reply via email to