File thunderx2-uncore-support.patch of Package libpfm

From: Shay Gal-On <sgalon@marvell.com>
Date: Wed Oct 23 18:58:03 2019 -0700
Subject: ThunderX2 uncore support
Git-commit: 0b050ca9ba2a2bf74f87fa3a8b4ed8aec9d1dfa8
References: jsc#SLE-10000
Signed-off-by: Tony Jones <tonyj@suse.de>
X-Info: adjust for context, no 98218490 (CascadeLake X core PMU)

    ThunderX2 uncore support
    
    This patch adds ThundeX2 uncore PMUs support.
    
    The following uncore PMUs are added:
    - tx2_llc0, tx2_llc1 (last level cache)
    - tx2_dmc0, tx2_dmc1 (memory controller)
    
    Based on documentation available at:
    https://www.marvell.com/documents/hrur6mybdvk5uki1w0z7/
    
    Signed-off-by: Shay Gal-On <sgalon@marvell.com>

diff --git a/include/perfmon/pfmlib.h b/include/perfmon/pfmlib.h
index 09c673d..20d5feb 100644
--- a/include/perfmon/pfmlib.h
+++ b/include/perfmon/pfmlib.h
@@ -546,6 +546,11 @@ typedef enum {
	PFM_PMU_INTEL_KNM_UNC_UBOX,	/* Intel Knights Mill Ubox uncore */
 	PFM_PMU_INTEL_KNM_UNC_M2PCIE,	/* Intel Knights Mill M2PCIe uncore */
 	PFM_PMU_ARM_THUNDERX2,		/* Cavium ThunderX2 */
+
+	PFM_PMU_ARM_THUNDERX2_DMC0,	/* Cavium ThunderX2 DMC unit 0 uncore */
+	PFM_PMU_ARM_THUNDERX2_DMC1,	/* Cavium ThunderX2 DMC unit 1 uncore */
+	PFM_PMU_ARM_THUNDERX2_LLC0,	/* Cavium ThunderX2 LLC unit 0 uncore */
+	PFM_PMU_ARM_THUNDERX2_LLC1,	/* Cavium ThunderX2 LLC unit 1 uncore */
 	/* MUST ADD NEW PMU MODELS HERE */
 
 	PFM_PMU_MAX			/* end marker */
diff --git a/lib/Makefile b/lib/Makefile
index 2eb3ebb..f45515d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -188,7 +188,7 @@ SRCS += pfmlib_arm_perf_event.c
 endif
 
 INCARCH = $(INC_ARM64)
-SRCS   += pfmlib_arm.c pfmlib_arm_armv8.c
+SRCS   += pfmlib_arm.c pfmlib_arm_armv8.c pfmlib_tx2_unc_perf_event.c
 CFLAGS += -DCONFIG_PFMLIB_ARCH_ARM64
 endif
 
diff --git a/lib/events/arm_cavium_tx2_events.h b/lib/events/arm_cavium_tx2_events.h
index 198d33d..18d8931 100644
--- a/lib/events/arm_cavium_tx2_events.h
+++ b/lib/events/arm_cavium_tx2_events.h
@@ -835,3 +835,64 @@ static const arm_entry_t arm_thunderx2_pe[]={
 	 .desc = "Scu hwpf next line requests generated"
 	},
 };
+
+#define ARM_TX2_CORE_EVENT_COUNT	(sizeof(arm_thunderx2_pe)/sizeof(arm_entry_t))
+
+/* L3C event IDs */
+#define L3_EVENT_READ_REQ               0xD
+#define L3_EVENT_WRITEBACK_REQ          0xE
+#define L3_EVENT_EVICT_REQ              0x13
+#define L3_EVENT_READ_HIT               0x17
+#define L3_EVENT_MAX                    0x18
+
+/* DMC event IDs */
+#define DMC_EVENT_COUNT_CYCLES          0x1
+#define DMC_EVENT_WRITE_TXNS            0xB
+#define DMC_EVENT_DATA_TRANSFERS        0xD
+#define DMC_EVENT_READ_TXNS             0xF
+#define DMC_EVENT_MAX                   0x10
+
+static const arm_entry_t arm_thunderx2_unc_dmc_pe[]={
+	{.name = "UNC_DMC_READS",
+	 .modmsk = ARMV8_ATTRS,
+	 .code = DMC_EVENT_READ_TXNS,
+	 .desc = "Memory read transactions"
+	},
+	{.name = "UNC_DMC_WRITES",
+	 .modmsk = ARMV8_ATTRS,
+	 .code = DMC_EVENT_WRITE_TXNS,
+	 .desc = "Memory write transactions"
+	},
+};
+
+#define ARM_TX2_CORE_DMC_COUNT	(sizeof(arm_thunderx2_unc_dmc_pe)/sizeof(arm_entry_t))
+
+static const arm_entry_t arm_thunderx2_unc_llc_pe[]={
+	{.name = "UNC_LLC_READ",
+	 .modmsk = ARMV8_ATTRS,
+	 .code = L3_EVENT_READ_REQ,
+	 .desc = "Read requests to LLC"
+	},
+	{.name = "UNC_LLC_EVICT",
+	 .modmsk = ARMV8_ATTRS,
+	 .code = L3_EVENT_EVICT_REQ,
+	 .desc = "Evict requests to LLC"
+	},
+	{.name = "UNC_LLC_READ_HIT",
+	 .modmsk = ARMV8_ATTRS,
+	 .code = L3_EVENT_READ_HIT,
+	 .desc = "Read requests to LLC which hit"
+	},
+	{.name = "UNC_LLC_WB",
+	 .modmsk = ARMV8_ATTRS,
+	 .code = L3_EVENT_WRITEBACK_REQ,
+	 .desc = "Writeback requests to LLC"
+	}
+};
+
+#define ARM_TX2_CORE_LLC_COUNT	(sizeof(arm_thunderx2_unc_llc_pe)/sizeof(arm_entry_t))
+//Uncore accessor functions
+int
+pfm_tx2_unc_get_event_encoding(void *this, pfmlib_event_desc_t *e);
+int
+pfm_tx2_unc_get_perf_encoding(void *this, pfmlib_event_desc_t *e);
diff --git a/lib/pfmlib_arm_armv8.c b/lib/pfmlib_arm_armv8.c
index 0a3313f..35ff70f 100644
--- a/lib/pfmlib_arm_armv8.c
+++ b/lib/pfmlib_arm_armv8.c
@@ -203,3 +203,58 @@ pfmlib_pmu_t arm_thunderx2_support={
 	.get_event_nattrs	= pfm_arm_get_event_nattrs,
 };
 
+// For uncore, each socket has a separate perf name, otherwise they are the same, use macro
+
+#define DEFINE_TX2_DMC(n) \
+pfmlib_pmu_t arm_thunderx2_dmc##n##_support={ \
+	.desc			= "Cavium ThunderX2 Node"#n" DMC", \
+	.name			= "tx2_dmc"#n, \
+	.perf_name		= "uncore_dmc_"#n, \
+	.pmu			= PFM_PMU_ARM_THUNDERX2_DMC##n, \
+	.pme_count		= LIBPFM_ARRAY_SIZE(arm_thunderx2_unc_dmc_pe), \
+	.type			= PFM_PMU_TYPE_UNCORE, \
+	.pe			= arm_thunderx2_unc_dmc_pe, \
+	.pmu_detect		= pfm_arm_detect_thunderx2, \
+	.max_encoding		= 1, \
+	.num_cntrs		= 4, \
+	.get_event_encoding[PFM_OS_NONE] = pfm_tx2_unc_get_event_encoding, \
+	 PFMLIB_ENCODE_PERF(pfm_tx2_unc_get_perf_encoding),		\
+	.get_event_first	= pfm_arm_get_event_first, \
+	.get_event_next		= pfm_arm_get_event_next,  \
+	.event_is_valid		= pfm_arm_event_is_valid,  \
+	.validate_table		= pfm_arm_validate_table,  \
+	.get_event_info		= pfm_arm_get_event_info,  \
+	.get_event_attr_info	= pfm_arm_get_event_attr_info,	\
+	 PFMLIB_VALID_PERF_PATTRS(pfm_arm_perf_validate_pattrs),\
+	.get_event_nattrs	= pfm_arm_get_event_nattrs, \
+};
+
+DEFINE_TX2_DMC(0);
+DEFINE_TX2_DMC(1);
+
+#define DEFINE_TX2_LLC(n) \
+pfmlib_pmu_t arm_thunderx2_llc##n##_support={ \
+	.desc			= "Cavium ThunderX2 node "#n" LLC", \
+	.name			= "tx2_llc"#n, \
+	.perf_name		= "uncore_l3c_"#n, \
+	.pmu			= PFM_PMU_ARM_THUNDERX2_LLC##n, \
+	.pme_count		= LIBPFM_ARRAY_SIZE(arm_thunderx2_unc_llc_pe), \
+	.type			= PFM_PMU_TYPE_UNCORE, \
+	.pe			= arm_thunderx2_unc_llc_pe, \
+	.pmu_detect		= pfm_arm_detect_thunderx2, \
+	.max_encoding		= 1, \
+	.num_cntrs		= 4, \
+	.get_event_encoding[PFM_OS_NONE] = pfm_tx2_unc_get_event_encoding, \
+	 PFMLIB_ENCODE_PERF(pfm_tx2_unc_get_perf_encoding),		\
+	.get_event_first	= pfm_arm_get_event_first, \
+	.get_event_next		= pfm_arm_get_event_next,  \
+	.event_is_valid		= pfm_arm_event_is_valid,  \
+	.validate_table		= pfm_arm_validate_table,  \
+	.get_event_info		= pfm_arm_get_event_info,  \
+	.get_event_attr_info	= pfm_arm_get_event_attr_info,	\
+	 PFMLIB_VALID_PERF_PATTRS(pfm_arm_perf_validate_pattrs),\
+	.get_event_nattrs	= pfm_arm_get_event_nattrs, \
+};
+
+DEFINE_TX2_LLC(0);
+DEFINE_TX2_LLC(1);
diff --git a/lib/pfmlib_common.c b/lib/pfmlib_common.c
index 2b6cbb4..8314d4b 100644
--- a/lib/pfmlib_common.c
+++ b/lib/pfmlib_common.c
@@ -490,6 +490,10 @@ static pfmlib_pmu_t *pfmlib_pmus[]=
 	&arm_cortex_a53_support,
 	&arm_xgene_support,
 	&arm_thunderx2_support,
+	&arm_thunderx2_dmc0_support,
+	&arm_thunderx2_dmc1_support,
+	&arm_thunderx2_llc0_support,
+	&arm_thunderx2_llc1_support,
 #endif
 
 #ifdef CONFIG_PFMLIB_ARCH_S390X
diff --git a/lib/pfmlib_priv.h b/lib/pfmlib_priv.h
index b0070a6..cb83f43 100644
--- a/lib/pfmlib_priv.h
+++ b/lib/pfmlib_priv.h
@@ -644,7 +644,13 @@ extern pfmlib_pmu_t arm_qcom_krait_support;
 extern pfmlib_pmu_t arm_cortex_a57_support;
 extern pfmlib_pmu_t arm_cortex_a53_support;
 extern pfmlib_pmu_t arm_xgene_support;
+
 extern pfmlib_pmu_t arm_thunderx2_support;
+extern pfmlib_pmu_t arm_thunderx2_dmc0_support;
+extern pfmlib_pmu_t arm_thunderx2_dmc1_support;
+extern pfmlib_pmu_t arm_thunderx2_llc0_support;
+extern pfmlib_pmu_t arm_thunderx2_llc1_support;
+
 extern pfmlib_pmu_t mips_74k_support;
 extern pfmlib_pmu_t s390x_cpum_cf_support;
 extern pfmlib_pmu_t s390x_cpum_sf_support;
diff --git a/lib/pfmlib_tx2_unc_perf_event.c b/lib/pfmlib_tx2_unc_perf_event.c
new file mode 100644
index 0000000..1a04e1d
--- /dev/null
+++ b/lib/pfmlib_tx2_unc_perf_event.c
@@ -0,0 +1,139 @@
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+
+/* private headers */
+#include "pfmlib_priv.h"
+#include "pfmlib_perf_event_priv.h"
+#include "pfmlib_arm_priv.h"
+
+typedef union {
+	uint64_t val;
+	struct {
+		unsigned long unc_event:8;	/* event code */
+		unsigned long unc_umask:8;	/* unit mask */
+		unsigned long unc_res1:1;	/* reserved */
+		unsigned long unc_rst:1;	/* reset */
+		unsigned long unc_edge:1;	/* edge detect */
+		unsigned long unc_res2:3;	/* reserved */
+		unsigned long unc_en:1;		/* enable */
+		unsigned long unc_inv:1;	/* invert counter mask */
+		unsigned long unc_thres:8;	/* counter mask */
+		unsigned long unc_res3:32;	/* reserved */
+	} com; /* covers common fields for DMC/L3C */
+} tx2_unc_data_t;
+
+static void
+display_reg(void *this, pfmlib_event_desc_t *e, tx2_unc_data_t reg);
+static void
+display_com(void *this, pfmlib_event_desc_t *e, void *val);
+static int
+find_pmu_type_by_name(const char *name);
+
+int
+pfm_tx2_unc_get_event_encoding(void *this, pfmlib_event_desc_t *e)
+{
+	//from pe field in for the uncore, get the array with all the event defs
+	const arm_entry_t *event_list = this_pe(this);
+	tx2_unc_data_t reg;
+	//get code for the event from the table
+	reg.val = event_list[e->event].code;
+	//pass the data back to the caller
+	e->codes[0] = reg.val;
+	e->count = 1;
+	evt_strcat(e->fstr, "%s", event_list[e->event].name);
+	display_reg(this, e, reg);
+	return PFM_SUCCESS;
+}
+
+int
+pfm_tx2_unc_get_perf_encoding(void *this, pfmlib_event_desc_t *e)
+{
+	pfmlib_pmu_t *pmu = this;
+	struct perf_event_attr *attr = e->os_data;
+	tx2_unc_data_t reg;
+	int ret;
+
+	if (!pmu->get_event_encoding[PFM_OS_NONE])
+		return PFM_ERR_NOTSUPP;
+
+	ret = pmu->get_event_encoding[PFM_OS_NONE](this, e);
+	if (ret != PFM_SUCCESS)
+		return ret;
+	//get pmu type to probe
+	ret = find_pmu_type_by_name(pmu->perf_name);
+	if (ret < 0)
+		return ret;
+
+	attr->type = ret;
+	//get code to provide to the uncore pmu probe
+	reg.val = e->codes[0];
+	attr->config = reg.val;
+
+	// if needed, can use attr->config1 or attr->config2 for extra info from event structure defines e->codes[i]
+
+	// uncore measures at all priv levels
+	attr->exclude_hv = 0;
+	attr->exclude_kernel = 0;
+	attr->exclude_user = 0;
+
+	return PFM_SUCCESS;
+}
+
+
+static void
+display_reg(void *this, pfmlib_event_desc_t *e, tx2_unc_data_t reg)
+{
+	pfmlib_pmu_t *pmu = this;
+	if (pmu->display_reg)
+		pmu->display_reg(this, e, &reg);
+	else
+		display_com(this, e, &reg);
+}
+
+static void
+display_com(void *this, pfmlib_event_desc_t *e, void *val)
+{
+	const arm_entry_t *pe = this_pe(this);
+	tx2_unc_data_t *reg = val;
+
+	__pfm_vbprintf("[UNC=0x%"PRIx64" event=0x%x umask=0x%x en=%d "
+		       "inv=%d edge=%d thres=%d] %s\n",
+			reg->val,
+			reg->com.unc_event,
+			reg->com.unc_umask,
+			reg->com.unc_en,
+			reg->com.unc_inv,
+			reg->com.unc_edge,
+			reg->com.unc_thres,
+			pe[e->event].name);
+}
+
+static int
+find_pmu_type_by_name(const char *name)
+{
+	char filename[PATH_MAX];
+	FILE *fp;
+	int ret, type;
+
+	if (!name)
+		return PFM_ERR_NOTSUPP;
+
+	sprintf(filename, "/sys/bus/event_source/devices/%s/type", name);
+
+	fp = fopen(filename, "r");
+	if (!fp)
+		return PFM_ERR_NOTSUPP;
+
+	ret = fscanf(fp, "%d", &type);
+	if (ret != 1)
+		type = PFM_ERR_NOTSUPP;
+
+	fclose(fp);
+
+	return type;
+}
+
diff --git a/tests/validate_arm64.c b/tests/validate_arm64.c
index f7f021a..35eb6ef 100644
--- a/tests/validate_arm64.c
+++ b/tests/validate_arm64.c
@@ -177,6 +177,12 @@ static const test_event_t arm64_test_events[]={
 	  .codes[0] = 0x8000008,
 	  .fstr = "arm_thunderx2::INST_RETIRED:k=1:u=1:hv=0",
 	},
+	{ SRC_LINE,
+	  .name = "tx2_dmc1::UNC_DMC_READS",
+	  .ret  = PFM_SUCCESS,
+	  .count = 1,
+	  .codes[0] = 0xf,
+	},
 };
 #define NUM_TEST_EVENTS (int)(sizeof(arm64_test_events)/sizeof(test_event_t))
 
openSUSE Build Service is sponsored by