[PATCH v2 2/5] arm64/perf: Cavium ThunderX L2C TAD uncore support

From: Jan Glauber
Date: Wed Mar 09 2016 - 11:21:53 EST


Support counters of the L2 Cache tag and data units.

Also support pass2 added/modified counters by checking MIDR.

Signed-off-by: Jan Glauber <jglauber@xxxxxxxxxx>
---
drivers/perf/uncore/Makefile | 3 +-
drivers/perf/uncore/uncore_cavium.c | 6 +-
drivers/perf/uncore/uncore_cavium.h | 7 +-
drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600 ++++++++++++++++++++++++++++
4 files changed, 613 insertions(+), 3 deletions(-)
create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c

diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
index b9c72c2..6a16caf 100644
--- a/drivers/perf/uncore/Makefile
+++ b/drivers/perf/uncore/Makefile
@@ -1 +1,2 @@
-obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o
+obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o \
+ uncore_cavium_l2c_tad.o
diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
index 4fd5e45..b92b2ae 100644
--- a/drivers/perf/uncore/uncore_cavium.c
+++ b/drivers/perf/uncore/uncore_cavium.c
@@ -15,7 +15,10 @@ int thunder_uncore_version;

struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event)
{
- return NULL;
+ if (event->pmu->type == thunder_l2c_tad_pmu.type)
+ return thunder_uncore_l2c_tad;
+ else
+ return NULL;
}

void thunder_uncore_read(struct perf_event *event)
@@ -296,6 +299,7 @@ static int __init thunder_uncore_init(void)
thunder_uncore_version = 1;
pr_info("PMU version: %d\n", thunder_uncore_version);

+ thunder_uncore_l2c_tad_setup();
return 0;
}
late_initcall(thunder_uncore_init);
diff --git a/drivers/perf/uncore/uncore_cavium.h b/drivers/perf/uncore/uncore_cavium.h
index c799709..7a9c367 100644
--- a/drivers/perf/uncore/uncore_cavium.h
+++ b/drivers/perf/uncore/uncore_cavium.h
@@ -7,7 +7,7 @@
#define pr_fmt(fmt) "thunderx_uncore: " fmt

enum uncore_type {
- NOP_TYPE,
+ L2C_TAD_TYPE,
};

extern int thunder_uncore_version;
@@ -65,6 +65,9 @@ static inline struct thunder_uncore_node *get_node(u64 config,
extern struct attribute_group thunder_uncore_attr_group;
extern struct device_attribute format_attr_node;

+extern struct thunder_uncore *thunder_uncore_l2c_tad;
+extern struct pmu thunder_l2c_tad_pmu;
+
/* Prototypes */
struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event);
void thunder_uncore_del(struct perf_event *event, int flags);
@@ -76,3 +79,5 @@ int thunder_uncore_setup(struct thunder_uncore *uncore, int id,
ssize_t thunder_events_sysfs_show(struct device *dev,
struct device_attribute *attr,
char *page);
+
+int thunder_uncore_l2c_tad_setup(void);
diff --git a/drivers/perf/uncore/uncore_cavium_l2c_tad.c b/drivers/perf/uncore/uncore_cavium_l2c_tad.c
new file mode 100644
index 0000000..c8dc305
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium_l2c_tad.c
@@ -0,0 +1,600 @@
+/*
+ * Cavium Thunder uncore PMU support, L2C TAD counters.
+ *
+ * Copyright 2016 Cavium Inc.
+ * Author: Jan Glauber <jan.glauber@xxxxxxxxxx>
+ */
+
+#include <linux/slab.h>
+#include <linux/perf_event.h>
+
+#include "uncore_cavium.h"
+
+#ifndef PCI_DEVICE_ID_THUNDER_L2C_TAD
+#define PCI_DEVICE_ID_THUNDER_L2C_TAD 0xa02e
+#endif
+
+#define L2C_TAD_NR_COUNTERS 4
+#define L2C_TAD_CONTROL_OFFSET 0x10000
+#define L2C_TAD_COUNTER_OFFSET 0x100
+
+/* L2C TAD event list */
+#define L2C_TAD_EVENTS_DISABLED 0x00
+
+#define L2C_TAD_EVENT_L2T_HIT 0x01
+#define L2C_TAD_EVENT_L2T_MISS 0x02
+#define L2C_TAD_EVENT_L2T_NOALLOC 0x03
+#define L2C_TAD_EVENT_L2_VIC 0x04
+#define L2C_TAD_EVENT_SC_FAIL 0x05
+#define L2C_TAD_EVENT_SC_PASS 0x06
+#define L2C_TAD_EVENT_LFB_OCC 0x07
+#define L2C_TAD_EVENT_WAIT_LFB 0x08
+#define L2C_TAD_EVENT_WAIT_VAB 0x09
+
+#define L2C_TAD_EVENT_RTG_HIT 0x41
+#define L2C_TAD_EVENT_RTG_MISS 0x42
+#define L2C_TAD_EVENT_L2_RTG_VIC 0x44
+#define L2C_TAD_EVENT_L2_OPEN_OCI 0x48
+
+#define L2C_TAD_EVENT_QD0_IDX 0x80
+#define L2C_TAD_EVENT_QD0_RDAT 0x81
+#define L2C_TAD_EVENT_QD0_BNKS 0x82
+#define L2C_TAD_EVENT_QD0_WDAT 0x83
+
+#define L2C_TAD_EVENT_QD1_IDX 0x90
+#define L2C_TAD_EVENT_QD1_RDAT 0x91
+#define L2C_TAD_EVENT_QD1_BNKS 0x92
+#define L2C_TAD_EVENT_QD1_WDAT 0x93
+
+#define L2C_TAD_EVENT_QD2_IDX 0xa0
+#define L2C_TAD_EVENT_QD2_RDAT 0xa1
+#define L2C_TAD_EVENT_QD2_BNKS 0xa2
+#define L2C_TAD_EVENT_QD2_WDAT 0xa3
+
+#define L2C_TAD_EVENT_QD3_IDX 0xb0
+#define L2C_TAD_EVENT_QD3_RDAT 0xb1
+#define L2C_TAD_EVENT_QD3_BNKS 0xb2
+#define L2C_TAD_EVENT_QD3_WDAT 0xb3
+
+#define L2C_TAD_EVENT_QD4_IDX 0xc0
+#define L2C_TAD_EVENT_QD4_RDAT 0xc1
+#define L2C_TAD_EVENT_QD4_BNKS 0xc2
+#define L2C_TAD_EVENT_QD4_WDAT 0xc3
+
+#define L2C_TAD_EVENT_QD5_IDX 0xd0
+#define L2C_TAD_EVENT_QD5_RDAT 0xd1
+#define L2C_TAD_EVENT_QD5_BNKS 0xd2
+#define L2C_TAD_EVENT_QD5_WDAT 0xd3
+
+#define L2C_TAD_EVENT_QD6_IDX 0xe0
+#define L2C_TAD_EVENT_QD6_RDAT 0xe1
+#define L2C_TAD_EVENT_QD6_BNKS 0xe2
+#define L2C_TAD_EVENT_QD6_WDAT 0xe3
+
+#define L2C_TAD_EVENT_QD7_IDX 0xf0
+#define L2C_TAD_EVENT_QD7_RDAT 0xf1
+#define L2C_TAD_EVENT_QD7_BNKS 0xf2
+#define L2C_TAD_EVENT_QD7_WDAT 0xf3
+
+/* pass2 added/changed event list */
+#define L2C_TAD_EVENT_OPEN_CCPI 0x0a
+#define L2C_TAD_EVENT_LOOKUP 0x40
+#define L2C_TAD_EVENT_LOOKUP_XMC_LCL 0x41
+#define L2C_TAD_EVENT_LOOKUP_XMC_RMT 0x42
+#define L2C_TAD_EVENT_LOOKUP_MIB 0x43
+#define L2C_TAD_EVENT_LOOKUP_ALL 0x44
+#define L2C_TAD_EVENT_TAG_ALC_HIT 0x48
+#define L2C_TAD_EVENT_TAG_ALC_MISS 0x49
+#define L2C_TAD_EVENT_TAG_ALC_NALC 0x4a
+#define L2C_TAD_EVENT_TAG_NALC_HIT 0x4b
+#define L2C_TAD_EVENT_TAG_NALC_MISS 0x4c
+#define L2C_TAD_EVENT_LMC_WR 0x4e
+#define L2C_TAD_EVENT_LMC_SBLKDTY 0x4f
+#define L2C_TAD_EVENT_TAG_ALC_RTG_HIT 0x50
+#define L2C_TAD_EVENT_TAG_ALC_RTG_HITE 0x51
+#define L2C_TAD_EVENT_TAG_ALC_RTG_HITS 0x52
+#define L2C_TAD_EVENT_TAG_ALC_RTG_MISS 0x53
+#define L2C_TAD_EVENT_TAG_NALC_RTG_HIT 0x54
+#define L2C_TAD_EVENT_TAG_NALC_RTG_MISS 0x55
+#define L2C_TAD_EVENT_TAG_NALC_RTG_HITE 0x56
+#define L2C_TAD_EVENT_TAG_NALC_RTG_HITS 0x57
+#define L2C_TAD_EVENT_TAG_ALC_LCL_EVICT 0x58
+#define L2C_TAD_EVENT_TAG_ALC_LCL_CLNVIC 0x59
+#define L2C_TAD_EVENT_TAG_ALC_LCL_DTYVIC 0x5a
+#define L2C_TAD_EVENT_TAG_ALC_RMT_EVICT 0x5b
+#define L2C_TAD_EVENT_TAG_ALC_RMT_VIC 0x5c
+#define L2C_TAD_EVENT_RTG_ALC 0x5d
+#define L2C_TAD_EVENT_RTG_ALC_HIT 0x5e
+#define L2C_TAD_EVENT_RTG_ALC_HITWB 0x5f
+#define L2C_TAD_EVENT_STC_TOTAL 0x60
+#define L2C_TAD_EVENT_STC_TOTAL_FAIL 0x61
+#define L2C_TAD_EVENT_STC_RMT 0x62
+#define L2C_TAD_EVENT_STC_RMT_FAIL 0x63
+#define L2C_TAD_EVENT_STC_LCL 0x64
+#define L2C_TAD_EVENT_STC_LCL_FAIL 0x65
+#define L2C_TAD_EVENT_OCI_RTG_WAIT 0x68
+#define L2C_TAD_EVENT_OCI_FWD_CYC_HIT 0x69
+#define L2C_TAD_EVENT_OCI_FWD_RACE 0x6a
+#define L2C_TAD_EVENT_OCI_HAKS 0x6b
+#define L2C_TAD_EVENT_OCI_FLDX_TAG_E_NODAT 0x6c
+#define L2C_TAD_EVENT_OCI_FLDX_TAG_E_DAT 0x6d
+#define L2C_TAD_EVENT_OCI_RLDD 0x6e
+#define L2C_TAD_EVENT_OCI_RLDD_PEMD 0x6f
+#define L2C_TAD_EVENT_OCI_RRQ_DAT_CNT 0x70
+#define L2C_TAD_EVENT_OCI_RRQ_DAT_DMASK 0x71
+#define L2C_TAD_EVENT_OCI_RSP_DAT_CNT 0x72
+#define L2C_TAD_EVENT_OCI_RSP_DAT_DMASK 0x73
+#define L2C_TAD_EVENT_OCI_RSP_DAT_VICD_CNT 0x74
+#define L2C_TAD_EVENT_OCI_RSP_DAT_VICD_DMASK 0x75
+#define L2C_TAD_EVENT_OCI_RTG_ALC_EVICT 0x76
+#define L2C_TAD_EVENT_OCI_RTG_ALC_VIC 0x77
+
+struct thunder_uncore *thunder_uncore_l2c_tad;
+
+static void thunder_uncore_start(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ struct thunder_uncore_unit *unit;
+ u64 prev;
+ int id;
+
+ node = get_node(hwc->config, uncore);
+ id = get_id(hwc->config);
+
+ /* restore counter value divided by units into all counters */
+ if (flags & PERF_EF_RELOAD) {
+ prev = local64_read(&hwc->prev_count);
+ prev = prev / node->nr_units;
+
+ list_for_each_entry(unit, &node->unit_list, entry)
+ writeq(prev, hwc->event_base + unit->map);
+ }
+
+ hwc->state = 0;
+
+ /* write byte in control registers for all units on the node */
+ list_for_each_entry(unit, &node->unit_list, entry)
+ writeb(id, hwc->config_base + unit->map);
+
+ perf_event_update_userpage(event);
+}
+
+static void thunder_uncore_stop(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ struct thunder_uncore_unit *unit;
+
+ /* reset selection value for all units on the node */
+ node = get_node(hwc->config, uncore);
+
+ list_for_each_entry(unit, &node->unit_list, entry)
+ writeb(L2C_TAD_EVENTS_DISABLED, hwc->config_base + unit->map);
+ hwc->state |= PERF_HES_STOPPED;
+
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ thunder_uncore_read(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static int thunder_uncore_add(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ int i;
+
+ WARN_ON_ONCE(!uncore);
+ node = get_node(hwc->config, uncore);
+
+ /* are we already assigned? */
+ if (hwc->idx != -1 && node->events[hwc->idx] == event)
+ goto out;
+
+ for (i = 0; i < node->num_counters; i++) {
+ if (node->events[i] == event) {
+ hwc->idx = i;
+ goto out;
+ }
+ }
+
+ /* if not take the first available counter */
+ hwc->idx = -1;
+ for (i = 0; i < node->num_counters; i++) {
+ if (cmpxchg(&node->events[i], NULL, event) == NULL) {
+ hwc->idx = i;
+ break;
+ }
+ }
+out:
+ if (hwc->idx == -1)
+ return -EBUSY;
+
+ hwc->config_base = hwc->idx;
+ hwc->event_base = L2C_TAD_COUNTER_OFFSET +
+ hwc->idx * sizeof(unsigned long long);
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_START)
+ thunder_uncore_start(event, PERF_EF_RELOAD);
+ return 0;
+}
+
+PMU_FORMAT_ATTR(event, "config:0-7");
+
+static struct attribute *thunder_l2c_tad_format_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_node.attr,
+ NULL,
+};
+
+static struct attribute_group thunder_l2c_tad_format_group = {
+ .name = "format",
+ .attrs = thunder_l2c_tad_format_attr,
+};
+
+EVENT_ATTR(l2t_hit, L2C_TAD_EVENT_L2T_HIT);
+EVENT_ATTR(l2t_miss, L2C_TAD_EVENT_L2T_MISS);
+EVENT_ATTR(l2t_noalloc, L2C_TAD_EVENT_L2T_NOALLOC);
+EVENT_ATTR(l2_vic, L2C_TAD_EVENT_L2_VIC);
+EVENT_ATTR(sc_fail, L2C_TAD_EVENT_SC_FAIL);
+EVENT_ATTR(sc_pass, L2C_TAD_EVENT_SC_PASS);
+EVENT_ATTR(lfb_occ, L2C_TAD_EVENT_LFB_OCC);
+EVENT_ATTR(wait_lfb, L2C_TAD_EVENT_WAIT_LFB);
+EVENT_ATTR(wait_vab, L2C_TAD_EVENT_WAIT_VAB);
+EVENT_ATTR(rtg_hit, L2C_TAD_EVENT_RTG_HIT);
+EVENT_ATTR(rtg_miss, L2C_TAD_EVENT_RTG_MISS);
+EVENT_ATTR(l2_rtg_vic, L2C_TAD_EVENT_L2_RTG_VIC);
+EVENT_ATTR(l2_open_oci, L2C_TAD_EVENT_L2_OPEN_OCI);
+
+EVENT_ATTR(qd0_idx, L2C_TAD_EVENT_QD0_IDX);
+EVENT_ATTR(qd0_rdat, L2C_TAD_EVENT_QD0_RDAT);
+EVENT_ATTR(qd0_bnks, L2C_TAD_EVENT_QD0_BNKS);
+EVENT_ATTR(qd0_wdat, L2C_TAD_EVENT_QD0_WDAT);
+
+EVENT_ATTR(qd1_idx, L2C_TAD_EVENT_QD1_IDX);
+EVENT_ATTR(qd1_rdat, L2C_TAD_EVENT_QD1_RDAT);
+EVENT_ATTR(qd1_bnks, L2C_TAD_EVENT_QD1_BNKS);
+EVENT_ATTR(qd1_wdat, L2C_TAD_EVENT_QD1_WDAT);
+
+EVENT_ATTR(qd2_idx, L2C_TAD_EVENT_QD2_IDX);
+EVENT_ATTR(qd2_rdat, L2C_TAD_EVENT_QD2_RDAT);
+EVENT_ATTR(qd2_bnks, L2C_TAD_EVENT_QD2_BNKS);
+EVENT_ATTR(qd2_wdat, L2C_TAD_EVENT_QD2_WDAT);
+
+EVENT_ATTR(qd3_idx, L2C_TAD_EVENT_QD3_IDX);
+EVENT_ATTR(qd3_rdat, L2C_TAD_EVENT_QD3_RDAT);
+EVENT_ATTR(qd3_bnks, L2C_TAD_EVENT_QD3_BNKS);
+EVENT_ATTR(qd3_wdat, L2C_TAD_EVENT_QD3_WDAT);
+
+EVENT_ATTR(qd4_idx, L2C_TAD_EVENT_QD4_IDX);
+EVENT_ATTR(qd4_rdat, L2C_TAD_EVENT_QD4_RDAT);
+EVENT_ATTR(qd4_bnks, L2C_TAD_EVENT_QD4_BNKS);
+EVENT_ATTR(qd4_wdat, L2C_TAD_EVENT_QD4_WDAT);
+
+EVENT_ATTR(qd5_idx, L2C_TAD_EVENT_QD5_IDX);
+EVENT_ATTR(qd5_rdat, L2C_TAD_EVENT_QD5_RDAT);
+EVENT_ATTR(qd5_bnks, L2C_TAD_EVENT_QD5_BNKS);
+EVENT_ATTR(qd5_wdat, L2C_TAD_EVENT_QD5_WDAT);
+
+EVENT_ATTR(qd6_idx, L2C_TAD_EVENT_QD6_IDX);
+EVENT_ATTR(qd6_rdat, L2C_TAD_EVENT_QD6_RDAT);
+EVENT_ATTR(qd6_bnks, L2C_TAD_EVENT_QD6_BNKS);
+EVENT_ATTR(qd6_wdat, L2C_TAD_EVENT_QD6_WDAT);
+
+EVENT_ATTR(qd7_idx, L2C_TAD_EVENT_QD7_IDX);
+EVENT_ATTR(qd7_rdat, L2C_TAD_EVENT_QD7_RDAT);
+EVENT_ATTR(qd7_bnks, L2C_TAD_EVENT_QD7_BNKS);
+EVENT_ATTR(qd7_wdat, L2C_TAD_EVENT_QD7_WDAT);
+
+static struct attribute *thunder_l2c_tad_events_attr[] = {
+ EVENT_PTR(l2t_hit),
+ EVENT_PTR(l2t_miss),
+ EVENT_PTR(l2t_noalloc),
+ EVENT_PTR(l2_vic),
+ EVENT_PTR(sc_fail),
+ EVENT_PTR(sc_pass),
+ EVENT_PTR(lfb_occ),
+ EVENT_PTR(wait_lfb),
+ EVENT_PTR(wait_vab),
+ EVENT_PTR(rtg_hit),
+ EVENT_PTR(rtg_miss),
+ EVENT_PTR(l2_rtg_vic),
+ EVENT_PTR(l2_open_oci),
+
+ EVENT_PTR(qd0_idx),
+ EVENT_PTR(qd0_rdat),
+ EVENT_PTR(qd0_bnks),
+ EVENT_PTR(qd0_wdat),
+
+ EVENT_PTR(qd1_idx),
+ EVENT_PTR(qd1_rdat),
+ EVENT_PTR(qd1_bnks),
+ EVENT_PTR(qd1_wdat),
+
+ EVENT_PTR(qd2_idx),
+ EVENT_PTR(qd2_rdat),
+ EVENT_PTR(qd2_bnks),
+ EVENT_PTR(qd2_wdat),
+
+ EVENT_PTR(qd3_idx),
+ EVENT_PTR(qd3_rdat),
+ EVENT_PTR(qd3_bnks),
+ EVENT_PTR(qd3_wdat),
+
+ EVENT_PTR(qd4_idx),
+ EVENT_PTR(qd4_rdat),
+ EVENT_PTR(qd4_bnks),
+ EVENT_PTR(qd4_wdat),
+
+ EVENT_PTR(qd5_idx),
+ EVENT_PTR(qd5_rdat),
+ EVENT_PTR(qd5_bnks),
+ EVENT_PTR(qd5_wdat),
+
+ EVENT_PTR(qd6_idx),
+ EVENT_PTR(qd6_rdat),
+ EVENT_PTR(qd6_bnks),
+ EVENT_PTR(qd6_wdat),
+
+ EVENT_PTR(qd7_idx),
+ EVENT_PTR(qd7_rdat),
+ EVENT_PTR(qd7_bnks),
+ EVENT_PTR(qd7_wdat),
+ NULL,
+};
+
+/* pass2 added/chanegd events */
+EVENT_ATTR(open_ccpi, L2C_TAD_EVENT_OPEN_CCPI);
+EVENT_ATTR(lookup, L2C_TAD_EVENT_LOOKUP);
+EVENT_ATTR(lookup_xmc_lcl, L2C_TAD_EVENT_LOOKUP_XMC_LCL);
+EVENT_ATTR(lookup_xmc_rmt, L2C_TAD_EVENT_LOOKUP_XMC_RMT);
+EVENT_ATTR(lookup_mib, L2C_TAD_EVENT_LOOKUP_MIB);
+EVENT_ATTR(lookup_all, L2C_TAD_EVENT_LOOKUP_ALL);
+
+EVENT_ATTR(tag_alc_hit, L2C_TAD_EVENT_TAG_ALC_HIT);
+EVENT_ATTR(tag_alc_miss, L2C_TAD_EVENT_TAG_ALC_MISS);
+EVENT_ATTR(tag_alc_nalc, L2C_TAD_EVENT_TAG_ALC_NALC);
+EVENT_ATTR(tag_nalc_hit, L2C_TAD_EVENT_TAG_NALC_HIT);
+EVENT_ATTR(tag_nalc_miss, L2C_TAD_EVENT_TAG_NALC_MISS);
+
+EVENT_ATTR(lmc_wr, L2C_TAD_EVENT_LMC_WR);
+EVENT_ATTR(lmc_sblkdty, L2C_TAD_EVENT_LMC_SBLKDTY);
+
+EVENT_ATTR(tag_alc_rtg_hit, L2C_TAD_EVENT_TAG_ALC_RTG_HIT);
+EVENT_ATTR(tag_alc_rtg_hite, L2C_TAD_EVENT_TAG_ALC_RTG_HITE);
+EVENT_ATTR(tag_alc_rtg_hits, L2C_TAD_EVENT_TAG_ALC_RTG_HITS);
+EVENT_ATTR(tag_alc_rtg_miss, L2C_TAD_EVENT_TAG_ALC_RTG_MISS);
+EVENT_ATTR(tag_alc_nalc_rtg_hit, L2C_TAD_EVENT_TAG_NALC_RTG_HIT);
+EVENT_ATTR(tag_nalc_rtg_miss, L2C_TAD_EVENT_TAG_NALC_RTG_MISS);
+EVENT_ATTR(tag_nalc_rtg_hite, L2C_TAD_EVENT_TAG_NALC_RTG_HITE);
+EVENT_ATTR(tag_nalc_rtg_hits, L2C_TAD_EVENT_TAG_NALC_RTG_HITS);
+EVENT_ATTR(tag_alc_lcl_evict, L2C_TAD_EVENT_TAG_ALC_LCL_EVICT);
+EVENT_ATTR(tag_alc_lcl_clnvic, L2C_TAD_EVENT_TAG_ALC_LCL_CLNVIC);
+EVENT_ATTR(tag_alc_lcl_dtyvic, L2C_TAD_EVENT_TAG_ALC_LCL_DTYVIC);
+EVENT_ATTR(tag_alc_rmt_evict, L2C_TAD_EVENT_TAG_ALC_RMT_EVICT);
+EVENT_ATTR(tag_alc_rmt_vic, L2C_TAD_EVENT_TAG_ALC_RMT_VIC);
+
+EVENT_ATTR(rtg_alc, L2C_TAD_EVENT_RTG_ALC);
+EVENT_ATTR(rtg_alc_hit, L2C_TAD_EVENT_RTG_ALC_HIT);
+EVENT_ATTR(rtg_alc_hitwb, L2C_TAD_EVENT_RTG_ALC_HITWB);
+
+EVENT_ATTR(stc_total, L2C_TAD_EVENT_STC_TOTAL);
+EVENT_ATTR(stc_total_fail, L2C_TAD_EVENT_STC_TOTAL_FAIL);
+EVENT_ATTR(stc_rmt, L2C_TAD_EVENT_STC_RMT);
+EVENT_ATTR(stc_rmt_fail, L2C_TAD_EVENT_STC_RMT_FAIL);
+EVENT_ATTR(stc_lcl, L2C_TAD_EVENT_STC_LCL);
+EVENT_ATTR(stc_lcl_fail, L2C_TAD_EVENT_STC_LCL_FAIL);
+
+EVENT_ATTR(oci_rtg_wait, L2C_TAD_EVENT_OCI_RTG_WAIT);
+EVENT_ATTR(oci_fwd_cyc_hit, L2C_TAD_EVENT_OCI_FWD_CYC_HIT);
+EVENT_ATTR(oci_fwd_race, L2C_TAD_EVENT_OCI_FWD_RACE);
+EVENT_ATTR(oci_haks, L2C_TAD_EVENT_OCI_HAKS);
+EVENT_ATTR(oci_fldx_tag_e_nodat, L2C_TAD_EVENT_OCI_FLDX_TAG_E_NODAT);
+EVENT_ATTR(oci_fldx_tag_e_dat, L2C_TAD_EVENT_OCI_FLDX_TAG_E_DAT);
+EVENT_ATTR(oci_rldd, L2C_TAD_EVENT_OCI_RLDD);
+EVENT_ATTR(oci_rldd_pemd, L2C_TAD_EVENT_OCI_RLDD_PEMD);
+EVENT_ATTR(oci_rrq_dat_cnt, L2C_TAD_EVENT_OCI_RRQ_DAT_CNT);
+EVENT_ATTR(oci_rrq_dat_dmask, L2C_TAD_EVENT_OCI_RRQ_DAT_DMASK);
+EVENT_ATTR(oci_rsp_dat_cnt, L2C_TAD_EVENT_OCI_RSP_DAT_CNT);
+EVENT_ATTR(oci_rsp_dat_dmaks, L2C_TAD_EVENT_OCI_RSP_DAT_DMASK);
+EVENT_ATTR(oci_rsp_dat_vicd_cnt, L2C_TAD_EVENT_OCI_RSP_DAT_VICD_CNT);
+EVENT_ATTR(oci_rsp_dat_vicd_dmask, L2C_TAD_EVENT_OCI_RSP_DAT_VICD_DMASK);
+EVENT_ATTR(oci_rtg_alc_evict, L2C_TAD_EVENT_OCI_RTG_ALC_EVICT);
+EVENT_ATTR(oci_rtg_alc_vic, L2C_TAD_EVENT_OCI_RTG_ALC_VIC);
+
+static struct attribute *thunder_l2c_tad_pass2_events_attr[] = {
+ EVENT_PTR(l2t_hit),
+ EVENT_PTR(l2t_miss),
+ EVENT_PTR(l2t_noalloc),
+ EVENT_PTR(l2_vic),
+ EVENT_PTR(sc_fail),
+ EVENT_PTR(sc_pass),
+ EVENT_PTR(lfb_occ),
+ EVENT_PTR(wait_lfb),
+ EVENT_PTR(wait_vab),
+ EVENT_PTR(open_ccpi),
+
+ EVENT_PTR(lookup),
+ EVENT_PTR(lookup_xmc_lcl),
+ EVENT_PTR(lookup_xmc_rmt),
+ EVENT_PTR(lookup_mib),
+ EVENT_PTR(lookup_all),
+
+ EVENT_PTR(tag_alc_hit),
+ EVENT_PTR(tag_alc_miss),
+ EVENT_PTR(tag_alc_nalc),
+ EVENT_PTR(tag_nalc_hit),
+ EVENT_PTR(tag_nalc_miss),
+
+ EVENT_PTR(lmc_wr),
+ EVENT_PTR(lmc_sblkdty),
+
+ EVENT_PTR(tag_alc_rtg_hit),
+ EVENT_PTR(tag_alc_rtg_hite),
+ EVENT_PTR(tag_alc_rtg_hits),
+ EVENT_PTR(tag_alc_rtg_miss),
+ EVENT_PTR(tag_alc_nalc_rtg_hit),
+ EVENT_PTR(tag_nalc_rtg_miss),
+ EVENT_PTR(tag_nalc_rtg_hite),
+ EVENT_PTR(tag_nalc_rtg_hits),
+ EVENT_PTR(tag_alc_lcl_evict),
+ EVENT_PTR(tag_alc_lcl_clnvic),
+ EVENT_PTR(tag_alc_lcl_dtyvic),
+ EVENT_PTR(tag_alc_rmt_evict),
+ EVENT_PTR(tag_alc_rmt_vic),
+
+ EVENT_PTR(rtg_alc),
+ EVENT_PTR(rtg_alc_hit),
+ EVENT_PTR(rtg_alc_hitwb),
+
+ EVENT_PTR(stc_total),
+ EVENT_PTR(stc_total_fail),
+ EVENT_PTR(stc_rmt),
+ EVENT_PTR(stc_rmt_fail),
+ EVENT_PTR(stc_lcl),
+ EVENT_PTR(stc_lcl_fail),
+
+ EVENT_PTR(oci_rtg_wait),
+ EVENT_PTR(oci_fwd_cyc_hit),
+ EVENT_PTR(oci_fwd_race),
+ EVENT_PTR(oci_haks),
+ EVENT_PTR(oci_fldx_tag_e_nodat),
+ EVENT_PTR(oci_fldx_tag_e_dat),
+ EVENT_PTR(oci_rldd),
+ EVENT_PTR(oci_rldd_pemd),
+ EVENT_PTR(oci_rrq_dat_cnt),
+ EVENT_PTR(oci_rrq_dat_dmask),
+ EVENT_PTR(oci_rsp_dat_cnt),
+ EVENT_PTR(oci_rsp_dat_dmaks),
+ EVENT_PTR(oci_rsp_dat_vicd_cnt),
+ EVENT_PTR(oci_rsp_dat_vicd_dmask),
+ EVENT_PTR(oci_rtg_alc_evict),
+ EVENT_PTR(oci_rtg_alc_vic),
+
+ EVENT_PTR(qd0_idx),
+ EVENT_PTR(qd0_rdat),
+ EVENT_PTR(qd0_bnks),
+ EVENT_PTR(qd0_wdat),
+
+ EVENT_PTR(qd1_idx),
+ EVENT_PTR(qd1_rdat),
+ EVENT_PTR(qd1_bnks),
+ EVENT_PTR(qd1_wdat),
+
+ EVENT_PTR(qd2_idx),
+ EVENT_PTR(qd2_rdat),
+ EVENT_PTR(qd2_bnks),
+ EVENT_PTR(qd2_wdat),
+
+ EVENT_PTR(qd3_idx),
+ EVENT_PTR(qd3_rdat),
+ EVENT_PTR(qd3_bnks),
+ EVENT_PTR(qd3_wdat),
+
+ EVENT_PTR(qd4_idx),
+ EVENT_PTR(qd4_rdat),
+ EVENT_PTR(qd4_bnks),
+ EVENT_PTR(qd4_wdat),
+
+ EVENT_PTR(qd5_idx),
+ EVENT_PTR(qd5_rdat),
+ EVENT_PTR(qd5_bnks),
+ EVENT_PTR(qd5_wdat),
+
+ EVENT_PTR(qd6_idx),
+ EVENT_PTR(qd6_rdat),
+ EVENT_PTR(qd6_bnks),
+ EVENT_PTR(qd6_wdat),
+
+ EVENT_PTR(qd7_idx),
+ EVENT_PTR(qd7_rdat),
+ EVENT_PTR(qd7_bnks),
+ EVENT_PTR(qd7_wdat),
+ NULL,
+};
+
+static struct attribute_group thunder_l2c_tad_events_group = {
+ .name = "events",
+ .attrs = NULL,
+};
+
+static const struct attribute_group *thunder_l2c_tad_attr_groups[] = {
+ &thunder_uncore_attr_group,
+ &thunder_l2c_tad_format_group,
+ &thunder_l2c_tad_events_group,
+ NULL,
+};
+
+struct pmu thunder_l2c_tad_pmu = {
+ .attr_groups = thunder_l2c_tad_attr_groups,
+ .name = "thunder_l2c_tad",
+ .event_init = thunder_uncore_event_init,
+ .add = thunder_uncore_add,
+ .del = thunder_uncore_del,
+ .start = thunder_uncore_start,
+ .stop = thunder_uncore_stop,
+ .read = thunder_uncore_read,
+};
+
+static int event_valid(u64 config)
+{
+ if ((config > 0 && config <= L2C_TAD_EVENT_WAIT_VAB) ||
+ config == L2C_TAD_EVENT_RTG_HIT ||
+ config == L2C_TAD_EVENT_RTG_MISS ||
+ config == L2C_TAD_EVENT_L2_RTG_VIC ||
+ config == L2C_TAD_EVENT_L2_OPEN_OCI ||
+ ((config & 0x80) && ((config & 0xf) <= 3)))
+ return 1;
+
+ if (thunder_uncore_version == 1)
+ if (config == L2C_TAD_EVENT_OPEN_CCPI ||
+ (config >= L2C_TAD_EVENT_LOOKUP &&
+ config <= L2C_TAD_EVENT_LOOKUP_ALL) ||
+ (config >= L2C_TAD_EVENT_TAG_ALC_HIT &&
+ config <= L2C_TAD_EVENT_OCI_RTG_ALC_VIC &&
+ config != 0x4d &&
+ config != 0x66 &&
+ config != 0x67))
+ return 1;
+
+ return 0;
+}
+
+int __init thunder_uncore_l2c_tad_setup(void)
+{
+ int ret = -ENOMEM;
+
+ thunder_uncore_l2c_tad = kzalloc(sizeof(struct thunder_uncore),
+ GFP_KERNEL);
+ if (!thunder_uncore_l2c_tad)
+ goto fail_nomem;
+
+ if (thunder_uncore_version == 0)
+ thunder_l2c_tad_events_group.attrs = thunder_l2c_tad_events_attr;
+ else /* default */
+ thunder_l2c_tad_events_group.attrs = thunder_l2c_tad_pass2_events_attr;
+
+ ret = thunder_uncore_setup(thunder_uncore_l2c_tad,
+ PCI_DEVICE_ID_THUNDER_L2C_TAD,
+ L2C_TAD_CONTROL_OFFSET,
+ L2C_TAD_COUNTER_OFFSET + L2C_TAD_NR_COUNTERS
+ * sizeof(unsigned long long),
+ &thunder_l2c_tad_pmu,
+ L2C_TAD_NR_COUNTERS);
+ if (ret)
+ goto fail;
+
+ thunder_uncore_l2c_tad->type = L2C_TAD_TYPE;
+ thunder_uncore_l2c_tad->event_valid = event_valid;
+ return 0;
+
+fail:
+ kfree(thunder_uncore_l2c_tad);
+fail_nomem:
+ return ret;
+}
--
1.9.1