Perf: Add L2 slave port filtering

The L2CC PMU's can filter traffic at the L2 slave port.
This patch allows the user to count non-CPU master events.

Change-Id: I42283a0902b8e746cb86440d423136ae394e7cd6
Signed-off-by: Ashwin Chaugule <ashwinc@codeaurora.org>
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index 22dbff3..5f76a92 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -21,6 +21,10 @@
 #define MAX_L2_PERIOD	((1ULL << 32) - 1)
 #define MAX_KRAIT_L2_CTRS 5
 
+#define L2_EVT_MASK 0xfffff
+
+#define L2_SLAVE_EV_PREFIX 4
+
 #define L2PMCCNTR 0x409
 #define L2PMCCNTCR 0x408
 #define L2PMCCNTSR 0x40A
@@ -49,9 +53,12 @@
 
 /* event format is -e rsRCCG See get_event_desc() */
 
-#define EVENT_REG_MASK		0xf000
-#define EVENT_GROUPSEL_MASK	0x000f
-#define	EVENT_GROUPCODE_MASK	0x0ff0
+#define EVENT_PREFIX_MASK	0xf0000
+#define EVENT_REG_MASK		0x0f000
+#define EVENT_GROUPSEL_MASK	0x0000f
+#define	EVENT_GROUPCODE_MASK	0x00ff0
+
+#define EVENT_PREFIX_SHIFT	16
 #define EVENT_REG_SHIFT		12
 #define EVENT_GROUPCODE_SHIFT	4
 
@@ -70,11 +77,13 @@
 };
 
 /* NRCCG format for perf RAW codes. */
+PMU_FORMAT_ATTR(l2_prefix, "config:16-19");
 PMU_FORMAT_ATTR(l2_reg,	"config:12-15");
 PMU_FORMAT_ATTR(l2_code, "config:4-11");
 PMU_FORMAT_ATTR(l2_grp,	"config:0-3");
 
 static struct attribute *msm_l2_ev_formats[] = {
+	&format_attr_l2_prefix.attr,
 	&format_attr_l2_reg.attr,
 	&format_attr_l2_code.attr,
 	&format_attr_l2_grp.attr,
@@ -97,6 +106,9 @@
 
 static u32 l2_orig_filter_prefix = 0x000f0030;
 
+/* L2 slave port traffic filtering */
+static u32 l2_slv_filter_prefix = 0x000f0010;
+
 static u32 pmu_type;
 
 static struct arm_pmu krait_l2_pmu;
@@ -167,19 +179,25 @@
 	set_l2_indirect_reg(group_reg, resr_val);
 }
 
-static void set_evfilter_task_mode(int ctr)
+static void set_evfilter_task_mode(int ctr, unsigned int is_slv)
 {
 	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
 	u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id();
 
+	if (is_slv)
+		filter_val = l2_slv_filter_prefix;
+
 	set_l2_indirect_reg(filter_reg, filter_val);
 }
 
-static void set_evfilter_sys_mode(int ctr)
+static void set_evfilter_sys_mode(int ctr, unsigned int is_slv)
 {
 	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
 	u32 filter_val = l2_orig_filter_prefix | 0xf;
 
+	if (is_slv)
+		filter_val = l2_slv_filter_prefix;
+
 	set_l2_indirect_reg(filter_reg, filter_val);
 }
 
@@ -251,12 +269,21 @@
 {
 	struct event_desc evdesc;
 	unsigned long iflags;
+	unsigned int is_slv = 0;
+	unsigned int evt_prefix;
 
 	raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags);
 
 	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE)
 		goto out;
 
+	/* Check if user requested any special origin filtering. */
+	evt_prefix = (hwc->config_base &
+			EVENT_PREFIX_MASK) >> EVENT_PREFIX_SHIFT;
+
+	if (evt_prefix == L2_SLAVE_EV_PREFIX)
+		is_slv = 1;
+
 	set_evcntcr(idx);
 
 	memset(&evdesc, 0, sizeof(evdesc));
@@ -269,9 +296,9 @@
 		  evdesc.event_group_code);
 
 	if (cpu < 0)
-		set_evfilter_task_mode(idx);
+		set_evfilter_task_mode(idx, is_slv);
 	else
-		set_evfilter_sys_mode(idx);
+		set_evfilter_sys_mode(idx, is_slv);
 
 out:
 	enable_intenset(idx);
@@ -397,7 +424,7 @@
 static int krait_l2_map_event(struct perf_event *event)
 {
 	if (pmu_type > 0 && pmu_type == event->attr.type)
-		return event->attr.config & 0xffff;
+		return event->attr.config & L2_EVT_MASK;
 	else
 		return -ENOENT;
 }
@@ -419,7 +446,7 @@
 
 static int msm_l2_test_set_ev_constraint(struct perf_event *event)
 {
-	u32 evt_type = event->attr.config & 0xffff;
+	u32 evt_type = event->attr.config & L2_EVT_MASK;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
 	u8 group =  evt_type & 0x0000F;
 	unsigned long flags;
@@ -444,7 +471,7 @@
 
 static int msm_l2_clear_ev_constraint(struct perf_event *event)
 {
-	u32 evt_type = event->attr.config & 0xffff;
+	u32 evt_type = event->attr.config & L2_EVT_MASK;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
 	u8 group =  evt_type & 0x0000F;
 	unsigned long flags;
@@ -476,7 +503,7 @@
 	.read_counter	=	krait_l2_read_counter,
 	.write_counter	=	krait_l2_write_counter,
 	.map_event	=	krait_l2_map_event,
-	.max_period	=	(1LLU << 32) - 1,
+	.max_period	=	MAX_L2_PERIOD,
 	.get_hw_events	=	krait_l2_get_hw_events,
 	.num_events	=	MAX_KRAIT_L2_CTRS,
 	.test_set_event_constraints	= msm_l2_test_set_ev_constraint,
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
index e3ab64a..5a5bf57 100644
--- a/arch/arm/mach-msm/perf_event_msm_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -24,6 +24,11 @@
 #define SCORPION_L2_EVT_PREFIX 3
 #define SCORPION_MAX_L2_REG 4
 
+#define L2_EVT_MASK 0xfffff
+#define L2_EVT_PREFIX_MASK 0xf0000
+#define L2_EVT_PREFIX_SHIFT 16
+#define L2_SLAVE_EVT_PREFIX 4
+
 
 /*
  * The L2 PMU is shared between all CPU's, so protect
@@ -69,6 +74,11 @@
 
 static struct arm_pmu scorpion_l2_pmu;
 
+static u32 l2_orig_filter_prefix = 0x000f0030;
+
+/* L2 slave port traffic filtering */
+static u32 l2_slv_filter_prefix = 0x000f0010;
+
 static struct perf_event *l2_events[MAX_SCORPION_L2_CTRS];
 static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_SCORPION_L2_CTRS)];
 
@@ -418,7 +428,8 @@
 	u8 group;
 
 	prefix = (evt_type & 0xF0000) >> 16;
-	if (prefix == SCORPION_L2_EVT_PREFIX) {
+	if (prefix == SCORPION_L2_EVT_PREFIX ||
+			prefix == L2_SLAVE_EVT_PREFIX) {
 		reg   = (evt_type & 0x0F000) >> 12;
 		code  = (evt_type & 0x00FF0) >> 4;
 		group =  evt_type & 0x0000F;
@@ -475,16 +486,22 @@
 	asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
 }
 
-static void scorpion_l2_set_evfilter_task_mode(void)
+static void scorpion_l2_set_evfilter_task_mode(unsigned int is_slv)
 {
-	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
+	u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id();
+
+	if (is_slv)
+		filter_val = l2_slv_filter_prefix;
 
 	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
 }
 
-static void scorpion_l2_set_evfilter_sys_mode(void)
+static void scorpion_l2_set_evfilter_sys_mode(unsigned int is_slv)
 {
-	u32 filter_val = 0x000f003f;
+	u32 filter_val = l2_orig_filter_prefix | 0xf;
+
+	if (is_slv)
+		filter_val = l2_slv_filter_prefix;
 
 	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
 }
@@ -584,12 +601,21 @@
 	int evtype = hwc->config_base;
 	int ev_typer;
 	unsigned long iflags;
+	unsigned int is_slv = 0;
+	unsigned int evt_prefix;
 
 	raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
 
 	if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE)
 		goto out;
 
+	/* Check if user requested any special origin filtering. */
+	evt_prefix = (hwc->config_base &
+			L2_EVT_PREFIX_MASK) >> L2_EVT_PREFIX_SHIFT;
+
+	if (evt_prefix == L2_SLAVE_EVT_PREFIX)
+		is_slv = 1;
+
 	memset(&evtinfo, 0, sizeof(evtinfo));
 
 	ev_typer = get_scorpion_l2_evtinfo(evtype, &evtinfo);
@@ -599,9 +625,9 @@
 	scorpion_l2_set_evcntcr();
 
 	if (cpu < 0)
-		scorpion_l2_set_evfilter_task_mode();
+		scorpion_l2_set_evfilter_task_mode(is_slv);
 	else
-		scorpion_l2_set_evfilter_sys_mode();
+		scorpion_l2_set_evfilter_sys_mode(is_slv);
 
 	scorpion_l2_evt_setup(evtinfo.grp, evtinfo.val);
 
@@ -735,7 +761,7 @@
 static int scorpion_l2_map_event(struct perf_event *event)
 {
 	if (pmu_type > 0 && pmu_type == event->attr.type)
-		return event->attr.config & 0xfffff;
+		return event->attr.config & L2_EVT_MASK;
 	else
 		return -ENOENT;
 }
@@ -757,7 +783,7 @@
 
 static int msm_l2_test_set_ev_constraint(struct perf_event *event)
 {
-	u32 evt_type = event->attr.config & 0xfffff;
+	u32 evt_type = event->attr.config & L2_EVT_MASK;
 	u8 prefix = (evt_type & 0xF0000) >> 16;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
 	u8 group =  evt_type & 0x0000F;
@@ -787,7 +813,7 @@
 
 static int msm_l2_clear_ev_constraint(struct perf_event *event)
 {
-	u32 evt_type = event->attr.config & 0xfffff;
+	u32 evt_type = event->attr.config & L2_EVT_MASK;
 	u8 prefix = (evt_type & 0xF0000) >> 16;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
 	u8 group =  evt_type & 0x0000F;