lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <256cecaca63266beedb57c344f10260915cc0a01.1457539622.git.jglauber@cavium.com>
Date:	Wed,  9 Mar 2016 17:21:05 +0100
From:	Jan Glauber <jglauber@...ium.com>
To:	Mark Rutland <mark.rutland@....com>,
	Will Deacon <will.deacon@....com>
Cc:	linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
	Jan Glauber <jglauber@...ium.com>
Subject: [PATCH v2 3/5] arm64/perf: Cavium ThunderX L2C CBC uncore support

Support counters of the L2 cache crossbar connect.

Signed-off-by: Jan Glauber <jglauber@...ium.com>
---
 drivers/perf/uncore/Makefile                |   3 +-
 drivers/perf/uncore/uncore_cavium.c         |   3 +
 drivers/perf/uncore/uncore_cavium.h         |   4 +
 drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 237 ++++++++++++++++++++++++++++
 4 files changed, 246 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c

diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
index 6a16caf..d52ecc9 100644
--- a/drivers/perf/uncore/Makefile
+++ b/drivers/perf/uncore/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o		\
-			      uncore_cavium_l2c_tad.o
+			      uncore_cavium_l2c_tad.o	\
+			      uncore_cavium_l2c_cbc.o
diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
index b92b2ae..a230450 100644
--- a/drivers/perf/uncore/uncore_cavium.c
+++ b/drivers/perf/uncore/uncore_cavium.c
@@ -17,6 +17,8 @@ struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event)
 {
 	if (event->pmu->type == thunder_l2c_tad_pmu.type)
 		return thunder_uncore_l2c_tad;
+	else if (event->pmu->type == thunder_l2c_cbc_pmu.type)
+		return thunder_uncore_l2c_cbc;
 	else
 		return NULL;
 }
@@ -300,6 +302,7 @@ static int __init thunder_uncore_init(void)
 	pr_info("PMU version: %d\n", thunder_uncore_version);
 
 	thunder_uncore_l2c_tad_setup();
+	thunder_uncore_l2c_cbc_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 7a9c367..94bd02c 100644
--- a/drivers/perf/uncore/uncore_cavium.h
+++ b/drivers/perf/uncore/uncore_cavium.h
@@ -8,6 +8,7 @@
 
 enum uncore_type {
 	L2C_TAD_TYPE,
+	L2C_CBC_TYPE,
 };
 
 extern int thunder_uncore_version;
@@ -66,7 +67,9 @@ 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 thunder_uncore *thunder_uncore_l2c_cbc;
 extern struct pmu thunder_l2c_tad_pmu;
+extern struct pmu thunder_l2c_cbc_pmu;
 
 /* Prototypes */
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event);
@@ -81,3 +84,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev,
 				  char *page);
 
 int thunder_uncore_l2c_tad_setup(void);
+int thunder_uncore_l2c_cbc_setup(void);
diff --git a/drivers/perf/uncore/uncore_cavium_l2c_cbc.c b/drivers/perf/uncore/uncore_cavium_l2c_cbc.c
new file mode 100644
index 0000000..bde7a51
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium_l2c_cbc.c
@@ -0,0 +1,237 @@
+/*
+ * Cavium Thunder uncore PMU support, L2C CBC counters.
+ *
+ * Copyright 2016 Cavium Inc.
+ * Author: Jan Glauber <jan.glauber@...ium.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/perf_event.h>
+
+#include "uncore_cavium.h"
+
+#ifndef PCI_DEVICE_ID_THUNDER_L2C_CBC
+#define PCI_DEVICE_ID_THUNDER_L2C_CBC	0xa02f
+#endif
+
+#define L2C_CBC_NR_COUNTERS             16
+
+/* L2C CBC event list */
+#define L2C_CBC_EVENT_XMC0		0x00
+#define L2C_CBC_EVENT_XMD0		0x01
+#define L2C_CBC_EVENT_RSC0		0x02
+#define L2C_CBC_EVENT_RSD0		0x03
+#define L2C_CBC_EVENT_INV0		0x04
+#define L2C_CBC_EVENT_IOC0		0x05
+#define L2C_CBC_EVENT_IOR0		0x06
+
+#define L2C_CBC_EVENT_XMC1		0x08	/* 0x40 */
+#define L2C_CBC_EVENT_XMD1		0x09
+#define L2C_CBC_EVENT_RSC1		0x0a
+#define L2C_CBC_EVENT_RSD1		0x0b
+#define L2C_CBC_EVENT_INV1		0x0c
+
+#define L2C_CBC_EVENT_XMC2		0x10	/* 0x80 */
+#define L2C_CBC_EVENT_XMD2		0x11
+#define L2C_CBC_EVENT_RSC2		0x12
+#define L2C_CBC_EVENT_RSD2		0x13
+
+struct thunder_uncore *thunder_uncore_l2c_cbc;
+
+int l2c_cbc_events[L2C_CBC_NR_COUNTERS] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+	0x08, 0x09, 0x0a, 0x0b, 0x0c,
+	0x10, 0x11, 0x12, 0x13
+};
+
+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;
+
+	node = get_node(hwc->config, uncore);
+
+	/* 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;
+	perf_event_update_userpage(event);
+}
+
+static void thunder_uncore_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	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 id, i;
+
+	WARN_ON_ONCE(!uncore);
+	node = get_node(hwc->config, uncore);
+	id = get_id(hwc->config);
+
+	/* 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;
+		}
+	}
+
+	/* these counters are self-sustained so idx must match the counter! */
+	hwc->idx = -1;
+	for (i = 0; i < node->num_counters; i++) {
+		if (l2c_cbc_events[i] == id) {
+			if (cmpxchg(&node->events[i], NULL, event) == NULL) {
+				hwc->idx = i;
+				break;
+			}
+		}
+	}
+
+out:
+	if (hwc->idx == -1)
+		return -EBUSY;
+
+	hwc->event_base = id * sizeof(unsigned long long);
+
+	/* counter is not stoppable so avoiding PERF_HES_STOPPED */
+	hwc->state = PERF_HES_UPTODATE;
+
+	if (flags & PERF_EF_START)
+		thunder_uncore_start(event, 0);
+
+	return 0;
+}
+
+PMU_FORMAT_ATTR(event, "config:0-4");
+
+static struct attribute *thunder_l2c_cbc_format_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_node.attr,
+	NULL,
+};
+
+static struct attribute_group thunder_l2c_cbc_format_group = {
+	.name = "format",
+	.attrs = thunder_l2c_cbc_format_attr,
+};
+
+EVENT_ATTR(xmc0,	L2C_CBC_EVENT_XMC0);
+EVENT_ATTR(xmd0,	L2C_CBC_EVENT_XMD0);
+EVENT_ATTR(rsc0,	L2C_CBC_EVENT_RSC0);
+EVENT_ATTR(rsd0,	L2C_CBC_EVENT_RSD0);
+EVENT_ATTR(inv0,	L2C_CBC_EVENT_INV0);
+EVENT_ATTR(ioc0,	L2C_CBC_EVENT_IOC0);
+EVENT_ATTR(ior0,	L2C_CBC_EVENT_IOR0);
+EVENT_ATTR(xmc1,	L2C_CBC_EVENT_XMC1);
+EVENT_ATTR(xmd1,	L2C_CBC_EVENT_XMD1);
+EVENT_ATTR(rsc1,	L2C_CBC_EVENT_RSC1);
+EVENT_ATTR(rsd1,	L2C_CBC_EVENT_RSD1);
+EVENT_ATTR(inv1,	L2C_CBC_EVENT_INV1);
+EVENT_ATTR(xmc2,	L2C_CBC_EVENT_XMC2);
+EVENT_ATTR(xmd2,	L2C_CBC_EVENT_XMD2);
+EVENT_ATTR(rsc2,	L2C_CBC_EVENT_RSC2);
+EVENT_ATTR(rsd2,	L2C_CBC_EVENT_RSD2);
+
+static struct attribute *thunder_l2c_cbc_events_attr[] = {
+	EVENT_PTR(xmc0),
+	EVENT_PTR(xmd0),
+	EVENT_PTR(rsc0),
+	EVENT_PTR(rsd0),
+	EVENT_PTR(inv0),
+	EVENT_PTR(ioc0),
+	EVENT_PTR(ior0),
+	EVENT_PTR(xmc1),
+	EVENT_PTR(xmd1),
+	EVENT_PTR(rsc1),
+	EVENT_PTR(rsd1),
+	EVENT_PTR(inv1),
+	EVENT_PTR(xmc2),
+	EVENT_PTR(xmd2),
+	EVENT_PTR(rsc2),
+	EVENT_PTR(rsd2),
+	NULL,
+};
+
+static struct attribute_group thunder_l2c_cbc_events_group = {
+	.name = "events",
+	.attrs = thunder_l2c_cbc_events_attr,
+};
+
+static const struct attribute_group *thunder_l2c_cbc_attr_groups[] = {
+	&thunder_uncore_attr_group,
+	&thunder_l2c_cbc_format_group,
+	&thunder_l2c_cbc_events_group,
+	NULL,
+};
+
+struct pmu thunder_l2c_cbc_pmu = {
+	.attr_groups	= thunder_l2c_cbc_attr_groups,
+	.name		= "thunder_l2c_cbc",
+	.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 <= L2C_CBC_EVENT_IOR0 ||
+	    (config >= L2C_CBC_EVENT_XMC1 && config <= L2C_CBC_EVENT_INV1) ||
+	    (config >= L2C_CBC_EVENT_XMC2 && config <= L2C_CBC_EVENT_RSD2))
+		return 1;
+	else
+		return 0;
+}
+
+int __init thunder_uncore_l2c_cbc_setup(void)
+{
+	int ret = -ENOMEM;
+
+	thunder_uncore_l2c_cbc = kzalloc(sizeof(struct thunder_uncore),
+					 GFP_KERNEL);
+	if (!thunder_uncore_l2c_cbc)
+		goto fail_nomem;
+
+	ret = thunder_uncore_setup(thunder_uncore_l2c_cbc,
+				   PCI_DEVICE_ID_THUNDER_L2C_CBC,
+				   0,
+				   0x100,
+				   &thunder_l2c_cbc_pmu,
+				   L2C_CBC_NR_COUNTERS);
+	if (ret)
+		goto fail;
+
+	thunder_uncore_l2c_cbc->type = L2C_CBC_TYPE;
+	thunder_uncore_l2c_cbc->event_valid = event_valid;
+	return 0;
+
+fail:
+	kfree(thunder_uncore_l2c_cbc);
+fail_nomem:
+	return ret;
+}
-- 
1.9.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ