All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] ARM CCI-500 PMU driver support
@ 2015-05-05 11:49 ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Suzuki K. Poulose

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

This series adds the support for CCI-500 PMU,  by
reusing and rearranging the CCI-400 PMU driver code.

CCI-500 (the new Cache Coherent Interconnect IP) has
a PMU with 8 independent event counters and supports
profiling events related to master/slave interfaces
along with the global events(cci internal events).

The series also adds aliases for events for all the
supported CCI PMUs(CCI_400{r0,r1}, CCI_500).

Patches 1/7 is a fix posted by Mark Salter, which has
been posted to arm@kernel.org already. I have included
it in this series, as this series applies on top of it.

Patches 2-5 - Creates an abstraction of a CCI PMU and
makes the CCI-400 driver code to make use of the abstraction.
Patch 6 - Adds the CCI-500 PMU driver support
Patch 7 - Adds the aliases for CCI PMU events (specific to chipsets).

With the series, one can use named events for the CCI pmus.

e.g, CCI-400

 # perf list | grep CCI
  CCI_400/cycles/                                    [Kernel PMU event]
  CCI_400/mi_retry_speculative_fetch,source=?/       [Kernel PMU event]

e.g, CCI-500

 # perf list |grep CCI
  CCI_500/cci_rq_stall_address_hazard/               [Kernel PMU event]
  CCI_500/cci_snoop_access_filter_bank_0_1/          [Kernel PMU event]

Testing was performed on a fast model, with perf fuzzer and functional
tests for the CCI-500 PMU.

Mark Salter (1):
  drivers: CCI: fix used_mask init in validate_group()

Suzuki K. Poulose (6):
  arm-cci: Cleanup PMU driver code
  arm-cci: Abstract out the PMU counter details
  arm-cci: Abstract handling for CCI events
  arm-cci: Sanitise CCI400 PMU driver specific code
  arm-cci: Add CCI-500 PMU support
  arm-cci: Add aliases for PMU events

 Documentation/devicetree/bindings/arm/cci.txt |    4 +-
 drivers/bus/Kconfig                           |   17 +
 drivers/bus/arm-cci.c                         |  905 ++++++++++++++++++++-----
 3 files changed, 756 insertions(+), 170 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 0/7] ARM CCI-500 PMU driver support
@ 2015-05-05 11:49 ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Suzuki K. Poulose

From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

This series adds the support for CCI-500 PMU,  by
reusing and rearranging the CCI-400 PMU driver code.

CCI-500 (the new Cache Coherent Interconnect IP) has
a PMU with 8 independent event counters and supports
profiling events related to master/slave interfaces
along with the global events(cci internal events).

The series also adds aliases for events for all the
supported CCI PMUs(CCI_400{r0,r1}, CCI_500).

Patches 1/7 is a fix posted by Mark Salter, which has
been posted to arm-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org already. I have included
it in this series, as this series applies on top of it.

Patches 2-5 - Creates an abstraction of a CCI PMU and
makes the CCI-400 driver code to make use of the abstraction.
Patch 6 - Adds the CCI-500 PMU driver support
Patch 7 - Adds the aliases for CCI PMU events (specific to chipsets).

With the series, one can use named events for the CCI pmus.

e.g, CCI-400

 # perf list | grep CCI
  CCI_400/cycles/                                    [Kernel PMU event]
  CCI_400/mi_retry_speculative_fetch,source=?/       [Kernel PMU event]

e.g, CCI-500

 # perf list |grep CCI
  CCI_500/cci_rq_stall_address_hazard/               [Kernel PMU event]
  CCI_500/cci_snoop_access_filter_bank_0_1/          [Kernel PMU event]

Testing was performed on a fast model, with perf fuzzer and functional
tests for the CCI-500 PMU.

Mark Salter (1):
  drivers: CCI: fix used_mask init in validate_group()

Suzuki K. Poulose (6):
  arm-cci: Cleanup PMU driver code
  arm-cci: Abstract out the PMU counter details
  arm-cci: Abstract handling for CCI events
  arm-cci: Sanitise CCI400 PMU driver specific code
  arm-cci: Add CCI-500 PMU support
  arm-cci: Add aliases for PMU events

 Documentation/devicetree/bindings/arm/cci.txt |    4 +-
 drivers/bus/Kconfig                           |   17 +
 drivers/bus/arm-cci.c                         |  905 ++++++++++++++++++++-----
 3 files changed, 756 insertions(+), 170 deletions(-)

-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 0/7] ARM CCI-500 PMU driver support
@ 2015-05-05 11:49 ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

This series adds the support for CCI-500 PMU,  by
reusing and rearranging the CCI-400 PMU driver code.

CCI-500 (the new Cache Coherent Interconnect IP) has
a PMU with 8 independent event counters and supports
profiling events related to master/slave interfaces
along with the global events(cci internal events).

The series also adds aliases for events for all the
supported CCI PMUs(CCI_400{r0,r1}, CCI_500).

Patches 1/7 is a fix posted by Mark Salter, which has
been posted to arm at kernel.org already. I have included
it in this series, as this series applies on top of it.

Patches 2-5 - Creates an abstraction of a CCI PMU and
makes the CCI-400 driver code to make use of the abstraction.
Patch 6 - Adds the CCI-500 PMU driver support
Patch 7 - Adds the aliases for CCI PMU events (specific to chipsets).

With the series, one can use named events for the CCI pmus.

e.g, CCI-400

 # perf list | grep CCI
  CCI_400/cycles/                                    [Kernel PMU event]
  CCI_400/mi_retry_speculative_fetch,source=?/       [Kernel PMU event]

e.g, CCI-500

 # perf list |grep CCI
  CCI_500/cci_rq_stall_address_hazard/               [Kernel PMU event]
  CCI_500/cci_snoop_access_filter_bank_0_1/          [Kernel PMU event]

Testing was performed on a fast model, with perf fuzzer and functional
tests for the CCI-500 PMU.

Mark Salter (1):
  drivers: CCI: fix used_mask init in validate_group()

Suzuki K. Poulose (6):
  arm-cci: Cleanup PMU driver code
  arm-cci: Abstract out the PMU counter details
  arm-cci: Abstract handling for CCI events
  arm-cci: Sanitise CCI400 PMU driver specific code
  arm-cci: Add CCI-500 PMU support
  arm-cci: Add aliases for PMU events

 Documentation/devicetree/bindings/arm/cci.txt |    4 +-
 drivers/bus/Kconfig                           |   17 +
 drivers/bus/arm-cci.c                         |  905 ++++++++++++++++++++-----
 3 files changed, 756 insertions(+), 170 deletions(-)

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 1/7] drivers: CCI: fix used_mask init in validate_group()
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Mark Salter

From: Mark Salter <msalter@redhat.com>

Currently in validate_group(), there is a static initializer
for fake_pmu.used_mask which is based on CPU_BITS_NONE but
the used_mask array size is based on CCI_PMU_MAX_HW_EVENTS.
CCI_PMU_MAX_HW_EVENTS is not based on NR_CPUS, so CPU_BITS_NONE
is not correct and will cause a build failure if NR_CPUS
is set high enough to make CPU_BITS_NONE larger than used_mask.
This patch changes the used_mask initialization to be runtime
based on the actual size of the array.

Signed-off-by: Mark Salter <msalter@redhat.com>
---
 drivers/bus/arm-cci.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index b854125..941b831 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -660,7 +660,7 @@ validate_group(struct perf_event *event)
 		 * Initialise the fake PMU. We only need to populate the
 		 * used_mask for the purposes of validation.
 		 */
-		.used_mask = CPU_BITS_NONE,
+		.used_mask =  { 0 },
 	};
 
 	if (!validate_event(event->pmu, &fake_pmu, leader))
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 1/7] drivers: CCI: fix used_mask init in validate_group()
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Mark Salter

From: Mark Salter <msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Currently in validate_group(), there is a static initializer
for fake_pmu.used_mask which is based on CPU_BITS_NONE but
the used_mask array size is based on CCI_PMU_MAX_HW_EVENTS.
CCI_PMU_MAX_HW_EVENTS is not based on NR_CPUS, so CPU_BITS_NONE
is not correct and will cause a build failure if NR_CPUS
is set high enough to make CPU_BITS_NONE larger than used_mask.
This patch changes the used_mask initialization to be runtime
based on the actual size of the array.

Signed-off-by: Mark Salter <msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 drivers/bus/arm-cci.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index b854125..941b831 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -660,7 +660,7 @@ validate_group(struct perf_event *event)
 		 * Initialise the fake PMU. We only need to populate the
 		 * used_mask for the purposes of validation.
 		 */
-		.used_mask = CPU_BITS_NONE,
+		.used_mask =  { 0 },
 	};
 
 	if (!validate_event(event->pmu, &fake_pmu, leader))
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 1/7] drivers: CCI: fix used_mask init in validate_group()
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Mark Salter <msalter@redhat.com>

Currently in validate_group(), there is a static initializer
for fake_pmu.used_mask which is based on CPU_BITS_NONE but
the used_mask array size is based on CCI_PMU_MAX_HW_EVENTS.
CCI_PMU_MAX_HW_EVENTS is not based on NR_CPUS, so CPU_BITS_NONE
is not correct and will cause a build failure if NR_CPUS
is set high enough to make CPU_BITS_NONE larger than used_mask.
This patch changes the used_mask initialization to be runtime
based on the actual size of the array.

Signed-off-by: Mark Salter <msalter@redhat.com>
---
 drivers/bus/arm-cci.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index b854125..941b831 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -660,7 +660,7 @@ validate_group(struct perf_event *event)
 		 * Initialise the fake PMU. We only need to populate the
 		 * used_mask for the purposes of validation.
 		 */
-		.used_mask = CPU_BITS_NONE,
+		.used_mask =  { 0 },
 	};
 
 	if (!validate_event(event->pmu, &fake_pmu, leader))
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 2/7] arm-cci: Cleanup PMU driver code
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

This patch gets rid of the global struct cci_pmu variable and makes
the code use the cci_pmu explicitly. Makes code a bit more robust
and reader friendly.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |  142 ++++++++++++++++++++++++++++---------------------
 1 file changed, 80 insertions(+), 62 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 941b831..27cc200 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -124,9 +124,9 @@ struct cci_pmu {
 	int num_events;
 	atomic_t active_events;
 	struct mutex reserve_mutex;
+	struct notifier_block cpu_nb;
 	cpumask_t cpus;
 };
-static struct cci_pmu *pmu;
 
 #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
 
@@ -179,7 +179,7 @@ enum cci400_perf_events {
 #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
 
-static int pmu_validate_hw_event(unsigned long hw_event)
+static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
 	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
 	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
@@ -207,8 +207,8 @@ static int pmu_validate_hw_event(unsigned long hw_event)
 		return -ENOENT;
 	}
 
-	if (ev_code >= pmu->model->event_ranges[if_type].min &&
-		ev_code <= pmu->model->event_ranges[if_type].max)
+	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+		ev_code <= cci_pmu->model->event_ranges[if_type].max)
 		return hw_event;
 
 	return -ENOENT;
@@ -239,29 +239,31 @@ static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
 }
 
-static u32 pmu_read_register(int idx, unsigned int offset)
+static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
 {
-	return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
 }
 
-static void pmu_write_register(u32 value, int idx, unsigned int offset)
+static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
+			       int idx, unsigned int offset)
 {
-	return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return writel_relaxed(value, cci_pmu->base +
+			      CCI_PMU_CNTR_BASE(idx) + offset);
 }
 
-static void pmu_disable_counter(int idx)
+static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL);
+	pmu_write_register(cci_pmu, 0, idx, CCI_PMU_CNTR_CTRL);
 }
 
-static void pmu_enable_counter(int idx)
+static void pmu_enable_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL);
+	pmu_write_register(cci_pmu, 1, idx, CCI_PMU_CNTR_CTRL);
 }
 
-static void pmu_set_event(int idx, unsigned long event)
+static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
 {
-	pmu_write_register(event, idx, CCI_PMU_EVT_SEL);
+	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
 }
 
 static u32 pmu_get_max_counters(void)
@@ -306,7 +308,8 @@ static int pmu_map_event(struct perf_event *event)
 	if (config == CCI_PMU_CYCLES)
 		mapping = config;
 	else
-		mapping = pmu_validate_hw_event(config);
+		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
+							config);
 
 	return mapping;
 }
@@ -319,7 +322,7 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
 	if (unlikely(!pmu_device))
 		return -ENODEV;
 
-	if (pmu->nr_irqs < 1) {
+	if (cci_pmu->nr_irqs < 1) {
 		dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n");
 		return -ENODEV;
 	}
@@ -331,16 +334,16 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
 	 *
 	 * This should allow handling of non-unique interrupt for the counters.
 	 */
-	for (i = 0; i < pmu->nr_irqs; i++) {
-		int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED,
+	for (i = 0; i < cci_pmu->nr_irqs; i++) {
+		int err = request_irq(cci_pmu->irqs[i], handler, IRQF_SHARED,
 				"arm-cci-pmu", cci_pmu);
 		if (err) {
 			dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n",
-				pmu->irqs[i]);
+				cci_pmu->irqs[i]);
 			return err;
 		}
 
-		set_bit(i, &pmu->active_irqs);
+		set_bit(i, &cci_pmu->active_irqs);
 	}
 
 	return 0;
@@ -350,11 +353,11 @@ static void pmu_free_irq(struct cci_pmu *cci_pmu)
 {
 	int i;
 
-	for (i = 0; i < pmu->nr_irqs; i++) {
-		if (!test_and_clear_bit(i, &pmu->active_irqs))
+	for (i = 0; i < cci_pmu->nr_irqs; i++) {
+		if (!test_and_clear_bit(i, &cci_pmu->active_irqs))
 			continue;
 
-		free_irq(pmu->irqs[i], cci_pmu);
+		free_irq(cci_pmu->irqs[i], cci_pmu);
 	}
 }
 
@@ -369,7 +372,7 @@ static u32 pmu_read_counter(struct perf_event *event)
 		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
 		return 0;
 	}
-	value = pmu_read_register(idx, CCI_PMU_CNTR);
+	value = pmu_read_register(cci_pmu, idx, CCI_PMU_CNTR);
 
 	return value;
 }
@@ -383,7 +386,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value)
 	if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
 		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
 	else
-		pmu_write_register(value, idx, CCI_PMU_CNTR);
+		pmu_write_register(cci_pmu, value, idx, CCI_PMU_CNTR);
 }
 
 static u64 pmu_event_update(struct perf_event *event)
@@ -427,7 +430,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 {
 	unsigned long flags;
 	struct cci_pmu *cci_pmu = dev;
-	struct cci_pmu_hw_events *events = &pmu->hw_events;
+	struct cci_pmu_hw_events *events = &cci_pmu->hw_events;
 	int idx, handled = IRQ_NONE;
 
 	raw_spin_lock_irqsave(&events->pmu_lock, flags);
@@ -446,11 +449,12 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 		hw_counter = &event->hw;
 
 		/* Did this counter overflow? */
-		if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) &
+		if (!(pmu_read_register(cci_pmu, idx, CCI_PMU_OVRFLW) &
 		      CCI_PMU_OVRFLW_FLAG))
 			continue;
 
-		pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
+		pmu_write_register(cci_pmu, CCI_PMU_OVRFLW_FLAG, idx,
+							CCI_PMU_OVRFLW);
 
 		pmu_event_update(event);
 		pmu_event_set_period(event);
@@ -549,10 +553,10 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
 	/* Configure the event to count, unless you are counting cycles */
 	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
-		pmu_set_event(idx, hwc->config_base);
+		pmu_set_event(cci_pmu, idx, hwc->config_base);
 
 	pmu_event_set_period(event);
-	pmu_enable_counter(idx);
+	pmu_enable_counter(cci_pmu, idx);
 
 	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
 }
@@ -575,7 +579,7 @@ static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
 	 * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
 	 * cci_pmu_start()
 	 */
-	pmu_disable_counter(idx);
+	pmu_disable_counter(cci_pmu, idx);
 	pmu_event_update(event);
 	hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
 }
@@ -779,20 +783,27 @@ static int cci_pmu_event_init(struct perf_event *event)
 	return err;
 }
 
-static ssize_t pmu_attr_cpumask_show(struct device *dev,
+static ssize_t pmu_cpumask_attr_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct dev_ext_attribute *eattr = container_of(attr,
+					struct dev_ext_attribute, attr);
+	struct cci_pmu *cci_pmu = eattr->var;
+
 	int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
-			  cpumask_pr_args(&pmu->cpus));
+			  cpumask_pr_args(&cci_pmu->cpus));
 	buf[n++] = '\n';
 	buf[n] = '\0';
 	return n;
 }
 
-static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
+static struct dev_ext_attribute pmu_cpumask_attr = {
+	__ATTR(cpumask, S_IRUGO, pmu_cpumask_attr_show, NULL),
+	NULL,		/* Populated in cci_pmu_init */
+};
 
 static struct attribute *pmu_attrs[] = {
-	&dev_attr_cpumask.attr,
+	&pmu_cpumask_attr.attr.attr,
 	NULL,
 };
 
@@ -808,6 +819,8 @@ static const struct attribute_group *pmu_attr_groups[] = {
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
+
+	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
 		.name		= cci_pmu->model->name,
 		.task_ctx_nr	= perf_invalid_context,
@@ -831,12 +844,14 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 static int cci_pmu_cpu_notifier(struct notifier_block *self,
 				unsigned long action, void *hcpu)
 {
+	struct cci_pmu *cci_pmu = container_of(self,
+					struct cci_pmu, cpu_nb);
 	unsigned int cpu = (long)hcpu;
 	unsigned int target;
 
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_DOWN_PREPARE:
-		if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
+		if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
 			break;
 		target = cpumask_any_but(cpu_online_mask, cpu);
 		if (target < 0) // UP, last CPU
@@ -845,7 +860,7 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 		 * TODO: migrate context once core races on event->ctx have
 		 * been fixed.
 		 */
-		cpumask_set_cpu(target, &pmu->cpus);
+		cpumask_set_cpu(target, &cci_pmu->cpus);
 	default:
 		break;
 	}
@@ -853,15 +868,6 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 	return NOTIFY_OK;
 }
 
-static struct notifier_block cci_pmu_cpu_nb = {
-	.notifier_call	= cci_pmu_cpu_notifier,
-	/*
-	 * to migrate uncore events, our notifier should be executed
-	 * before perf core's notifier.
-	 */
-	.priority	= CPU_PRI_PERF + 1,
-};
-
 static struct cci_pmu_model cci_pmu_models[] = {
 	[CCI_REV_R0] = {
 		.name = "CCI_400",
@@ -935,6 +941,7 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
 static int cci_pmu_probe(struct platform_device *pdev)
 {
 	struct resource *res;
+	struct cci_pmu *cci_pmu;
 	int i, ret, irq;
 	const struct cci_pmu_model *model;
 
@@ -944,30 +951,30 @@ static int cci_pmu_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
-	if (!pmu)
+	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
+	if (!cci_pmu)
 		return -ENOMEM;
 
-	pmu->model = model;
+	cci_pmu->model = model;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	pmu->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(pmu->base))
+	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(cci_pmu->base))
 		return -ENOMEM;
 
 	/*
 	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
 	 * together to a common interrupt.
 	 */
-	pmu->nr_irqs = 0;
+	cci_pmu->nr_irqs = 0;
 	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
 		irq = platform_get_irq(pdev, i);
 		if (irq < 0)
 			break;
 
-		if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs))
+		if (is_duplicate_irq(irq, cci_pmu->irqs, cci_pmu->nr_irqs))
 			continue;
 
-		pmu->irqs[pmu->nr_irqs++] = irq;
+		cci_pmu->irqs[cci_pmu->nr_irqs++] = irq;
 	}
 
 	/*
@@ -980,20 +987,31 @@ static int cci_pmu_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	raw_spin_lock_init(&pmu->hw_events.pmu_lock);
-	mutex_init(&pmu->reserve_mutex);
-	atomic_set(&pmu->active_events, 0);
-	cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
+	raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock);
+	mutex_init(&cci_pmu->reserve_mutex);
+	atomic_set(&cci_pmu->active_events, 0);
+	cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
 
-	ret = register_cpu_notifier(&cci_pmu_cpu_nb);
+	cci_pmu->cpu_nb = (struct notifier_block) {
+		.notifier_call	= cci_pmu_cpu_notifier,
+		/*
+		 * to migrate uncore events, our notifier should be executed
+		 * before perf core's notifier.
+		 */
+		.priority	= CPU_PRI_PERF + 1,
+	};
+
+	ret = register_cpu_notifier(&cci_pmu->cpu_nb);
 	if (ret)
 		return ret;
 
-	ret = cci_pmu_init(pmu, pdev);
-	if (ret)
+	ret = cci_pmu_init(cci_pmu, pdev);
+	if (ret) {
+		unregister_cpu_notifier(&cci_pmu->cpu_nb);
 		return ret;
+	}
 
-	pr_info("ARM %s PMU driver probed", pmu->model->name);
+	pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 2/7] arm-cci: Cleanup PMU driver code
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

This patch gets rid of the global struct cci_pmu variable and makes
the code use the cci_pmu explicitly. Makes code a bit more robust
and reader friendly.

Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
---
 drivers/bus/arm-cci.c |  142 ++++++++++++++++++++++++++++---------------------
 1 file changed, 80 insertions(+), 62 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 941b831..27cc200 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -124,9 +124,9 @@ struct cci_pmu {
 	int num_events;
 	atomic_t active_events;
 	struct mutex reserve_mutex;
+	struct notifier_block cpu_nb;
 	cpumask_t cpus;
 };
-static struct cci_pmu *pmu;
 
 #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
 
@@ -179,7 +179,7 @@ enum cci400_perf_events {
 #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
 
-static int pmu_validate_hw_event(unsigned long hw_event)
+static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
 	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
 	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
@@ -207,8 +207,8 @@ static int pmu_validate_hw_event(unsigned long hw_event)
 		return -ENOENT;
 	}
 
-	if (ev_code >= pmu->model->event_ranges[if_type].min &&
-		ev_code <= pmu->model->event_ranges[if_type].max)
+	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+		ev_code <= cci_pmu->model->event_ranges[if_type].max)
 		return hw_event;
 
 	return -ENOENT;
@@ -239,29 +239,31 @@ static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
 }
 
-static u32 pmu_read_register(int idx, unsigned int offset)
+static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
 {
-	return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
 }
 
-static void pmu_write_register(u32 value, int idx, unsigned int offset)
+static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
+			       int idx, unsigned int offset)
 {
-	return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return writel_relaxed(value, cci_pmu->base +
+			      CCI_PMU_CNTR_BASE(idx) + offset);
 }
 
-static void pmu_disable_counter(int idx)
+static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL);
+	pmu_write_register(cci_pmu, 0, idx, CCI_PMU_CNTR_CTRL);
 }
 
-static void pmu_enable_counter(int idx)
+static void pmu_enable_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL);
+	pmu_write_register(cci_pmu, 1, idx, CCI_PMU_CNTR_CTRL);
 }
 
-static void pmu_set_event(int idx, unsigned long event)
+static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
 {
-	pmu_write_register(event, idx, CCI_PMU_EVT_SEL);
+	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
 }
 
 static u32 pmu_get_max_counters(void)
@@ -306,7 +308,8 @@ static int pmu_map_event(struct perf_event *event)
 	if (config == CCI_PMU_CYCLES)
 		mapping = config;
 	else
-		mapping = pmu_validate_hw_event(config);
+		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
+							config);
 
 	return mapping;
 }
@@ -319,7 +322,7 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
 	if (unlikely(!pmu_device))
 		return -ENODEV;
 
-	if (pmu->nr_irqs < 1) {
+	if (cci_pmu->nr_irqs < 1) {
 		dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n");
 		return -ENODEV;
 	}
@@ -331,16 +334,16 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
 	 *
 	 * This should allow handling of non-unique interrupt for the counters.
 	 */
-	for (i = 0; i < pmu->nr_irqs; i++) {
-		int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED,
+	for (i = 0; i < cci_pmu->nr_irqs; i++) {
+		int err = request_irq(cci_pmu->irqs[i], handler, IRQF_SHARED,
 				"arm-cci-pmu", cci_pmu);
 		if (err) {
 			dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n",
-				pmu->irqs[i]);
+				cci_pmu->irqs[i]);
 			return err;
 		}
 
-		set_bit(i, &pmu->active_irqs);
+		set_bit(i, &cci_pmu->active_irqs);
 	}
 
 	return 0;
@@ -350,11 +353,11 @@ static void pmu_free_irq(struct cci_pmu *cci_pmu)
 {
 	int i;
 
-	for (i = 0; i < pmu->nr_irqs; i++) {
-		if (!test_and_clear_bit(i, &pmu->active_irqs))
+	for (i = 0; i < cci_pmu->nr_irqs; i++) {
+		if (!test_and_clear_bit(i, &cci_pmu->active_irqs))
 			continue;
 
-		free_irq(pmu->irqs[i], cci_pmu);
+		free_irq(cci_pmu->irqs[i], cci_pmu);
 	}
 }
 
@@ -369,7 +372,7 @@ static u32 pmu_read_counter(struct perf_event *event)
 		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
 		return 0;
 	}
-	value = pmu_read_register(idx, CCI_PMU_CNTR);
+	value = pmu_read_register(cci_pmu, idx, CCI_PMU_CNTR);
 
 	return value;
 }
@@ -383,7 +386,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value)
 	if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
 		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
 	else
-		pmu_write_register(value, idx, CCI_PMU_CNTR);
+		pmu_write_register(cci_pmu, value, idx, CCI_PMU_CNTR);
 }
 
 static u64 pmu_event_update(struct perf_event *event)
@@ -427,7 +430,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 {
 	unsigned long flags;
 	struct cci_pmu *cci_pmu = dev;
-	struct cci_pmu_hw_events *events = &pmu->hw_events;
+	struct cci_pmu_hw_events *events = &cci_pmu->hw_events;
 	int idx, handled = IRQ_NONE;
 
 	raw_spin_lock_irqsave(&events->pmu_lock, flags);
@@ -446,11 +449,12 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 		hw_counter = &event->hw;
 
 		/* Did this counter overflow? */
-		if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) &
+		if (!(pmu_read_register(cci_pmu, idx, CCI_PMU_OVRFLW) &
 		      CCI_PMU_OVRFLW_FLAG))
 			continue;
 
-		pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
+		pmu_write_register(cci_pmu, CCI_PMU_OVRFLW_FLAG, idx,
+							CCI_PMU_OVRFLW);
 
 		pmu_event_update(event);
 		pmu_event_set_period(event);
@@ -549,10 +553,10 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
 	/* Configure the event to count, unless you are counting cycles */
 	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
-		pmu_set_event(idx, hwc->config_base);
+		pmu_set_event(cci_pmu, idx, hwc->config_base);
 
 	pmu_event_set_period(event);
-	pmu_enable_counter(idx);
+	pmu_enable_counter(cci_pmu, idx);
 
 	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
 }
@@ -575,7 +579,7 @@ static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
 	 * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
 	 * cci_pmu_start()
 	 */
-	pmu_disable_counter(idx);
+	pmu_disable_counter(cci_pmu, idx);
 	pmu_event_update(event);
 	hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
 }
@@ -779,20 +783,27 @@ static int cci_pmu_event_init(struct perf_event *event)
 	return err;
 }
 
-static ssize_t pmu_attr_cpumask_show(struct device *dev,
+static ssize_t pmu_cpumask_attr_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct dev_ext_attribute *eattr = container_of(attr,
+					struct dev_ext_attribute, attr);
+	struct cci_pmu *cci_pmu = eattr->var;
+
 	int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
-			  cpumask_pr_args(&pmu->cpus));
+			  cpumask_pr_args(&cci_pmu->cpus));
 	buf[n++] = '\n';
 	buf[n] = '\0';
 	return n;
 }
 
-static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
+static struct dev_ext_attribute pmu_cpumask_attr = {
+	__ATTR(cpumask, S_IRUGO, pmu_cpumask_attr_show, NULL),
+	NULL,		/* Populated in cci_pmu_init */
+};
 
 static struct attribute *pmu_attrs[] = {
-	&dev_attr_cpumask.attr,
+	&pmu_cpumask_attr.attr.attr,
 	NULL,
 };
 
@@ -808,6 +819,8 @@ static const struct attribute_group *pmu_attr_groups[] = {
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
+
+	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
 		.name		= cci_pmu->model->name,
 		.task_ctx_nr	= perf_invalid_context,
@@ -831,12 +844,14 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 static int cci_pmu_cpu_notifier(struct notifier_block *self,
 				unsigned long action, void *hcpu)
 {
+	struct cci_pmu *cci_pmu = container_of(self,
+					struct cci_pmu, cpu_nb);
 	unsigned int cpu = (long)hcpu;
 	unsigned int target;
 
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_DOWN_PREPARE:
-		if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
+		if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
 			break;
 		target = cpumask_any_but(cpu_online_mask, cpu);
 		if (target < 0) // UP, last CPU
@@ -845,7 +860,7 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 		 * TODO: migrate context once core races on event->ctx have
 		 * been fixed.
 		 */
-		cpumask_set_cpu(target, &pmu->cpus);
+		cpumask_set_cpu(target, &cci_pmu->cpus);
 	default:
 		break;
 	}
@@ -853,15 +868,6 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 	return NOTIFY_OK;
 }
 
-static struct notifier_block cci_pmu_cpu_nb = {
-	.notifier_call	= cci_pmu_cpu_notifier,
-	/*
-	 * to migrate uncore events, our notifier should be executed
-	 * before perf core's notifier.
-	 */
-	.priority	= CPU_PRI_PERF + 1,
-};
-
 static struct cci_pmu_model cci_pmu_models[] = {
 	[CCI_REV_R0] = {
 		.name = "CCI_400",
@@ -935,6 +941,7 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
 static int cci_pmu_probe(struct platform_device *pdev)
 {
 	struct resource *res;
+	struct cci_pmu *cci_pmu;
 	int i, ret, irq;
 	const struct cci_pmu_model *model;
 
@@ -944,30 +951,30 @@ static int cci_pmu_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
-	if (!pmu)
+	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
+	if (!cci_pmu)
 		return -ENOMEM;
 
-	pmu->model = model;
+	cci_pmu->model = model;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	pmu->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(pmu->base))
+	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(cci_pmu->base))
 		return -ENOMEM;
 
 	/*
 	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
 	 * together to a common interrupt.
 	 */
-	pmu->nr_irqs = 0;
+	cci_pmu->nr_irqs = 0;
 	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
 		irq = platform_get_irq(pdev, i);
 		if (irq < 0)
 			break;
 
-		if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs))
+		if (is_duplicate_irq(irq, cci_pmu->irqs, cci_pmu->nr_irqs))
 			continue;
 
-		pmu->irqs[pmu->nr_irqs++] = irq;
+		cci_pmu->irqs[cci_pmu->nr_irqs++] = irq;
 	}
 
 	/*
@@ -980,20 +987,31 @@ static int cci_pmu_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	raw_spin_lock_init(&pmu->hw_events.pmu_lock);
-	mutex_init(&pmu->reserve_mutex);
-	atomic_set(&pmu->active_events, 0);
-	cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
+	raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock);
+	mutex_init(&cci_pmu->reserve_mutex);
+	atomic_set(&cci_pmu->active_events, 0);
+	cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
 
-	ret = register_cpu_notifier(&cci_pmu_cpu_nb);
+	cci_pmu->cpu_nb = (struct notifier_block) {
+		.notifier_call	= cci_pmu_cpu_notifier,
+		/*
+		 * to migrate uncore events, our notifier should be executed
+		 * before perf core's notifier.
+		 */
+		.priority	= CPU_PRI_PERF + 1,
+	};
+
+	ret = register_cpu_notifier(&cci_pmu->cpu_nb);
 	if (ret)
 		return ret;
 
-	ret = cci_pmu_init(pmu, pdev);
-	if (ret)
+	ret = cci_pmu_init(cci_pmu, pdev);
+	if (ret) {
+		unregister_cpu_notifier(&cci_pmu->cpu_nb);
 		return ret;
+	}
 
-	pr_info("ARM %s PMU driver probed", pmu->model->name);
+	pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
 	return 0;
 }
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 2/7] arm-cci: Cleanup PMU driver code
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

This patch gets rid of the global struct cci_pmu variable and makes
the code use the cci_pmu explicitly. Makes code a bit more robust
and reader friendly.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |  142 ++++++++++++++++++++++++++++---------------------
 1 file changed, 80 insertions(+), 62 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 941b831..27cc200 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -124,9 +124,9 @@ struct cci_pmu {
 	int num_events;
 	atomic_t active_events;
 	struct mutex reserve_mutex;
+	struct notifier_block cpu_nb;
 	cpumask_t cpus;
 };
-static struct cci_pmu *pmu;
 
 #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
 
@@ -179,7 +179,7 @@ enum cci400_perf_events {
 #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
 
-static int pmu_validate_hw_event(unsigned long hw_event)
+static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
 	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
 	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
@@ -207,8 +207,8 @@ static int pmu_validate_hw_event(unsigned long hw_event)
 		return -ENOENT;
 	}
 
-	if (ev_code >= pmu->model->event_ranges[if_type].min &&
-		ev_code <= pmu->model->event_ranges[if_type].max)
+	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+		ev_code <= cci_pmu->model->event_ranges[if_type].max)
 		return hw_event;
 
 	return -ENOENT;
@@ -239,29 +239,31 @@ static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
 }
 
-static u32 pmu_read_register(int idx, unsigned int offset)
+static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
 {
-	return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
 }
 
-static void pmu_write_register(u32 value, int idx, unsigned int offset)
+static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
+			       int idx, unsigned int offset)
 {
-	return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return writel_relaxed(value, cci_pmu->base +
+			      CCI_PMU_CNTR_BASE(idx) + offset);
 }
 
-static void pmu_disable_counter(int idx)
+static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL);
+	pmu_write_register(cci_pmu, 0, idx, CCI_PMU_CNTR_CTRL);
 }
 
-static void pmu_enable_counter(int idx)
+static void pmu_enable_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL);
+	pmu_write_register(cci_pmu, 1, idx, CCI_PMU_CNTR_CTRL);
 }
 
-static void pmu_set_event(int idx, unsigned long event)
+static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
 {
-	pmu_write_register(event, idx, CCI_PMU_EVT_SEL);
+	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
 }
 
 static u32 pmu_get_max_counters(void)
@@ -306,7 +308,8 @@ static int pmu_map_event(struct perf_event *event)
 	if (config == CCI_PMU_CYCLES)
 		mapping = config;
 	else
-		mapping = pmu_validate_hw_event(config);
+		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
+							config);
 
 	return mapping;
 }
@@ -319,7 +322,7 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
 	if (unlikely(!pmu_device))
 		return -ENODEV;
 
-	if (pmu->nr_irqs < 1) {
+	if (cci_pmu->nr_irqs < 1) {
 		dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n");
 		return -ENODEV;
 	}
@@ -331,16 +334,16 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
 	 *
 	 * This should allow handling of non-unique interrupt for the counters.
 	 */
-	for (i = 0; i < pmu->nr_irqs; i++) {
-		int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED,
+	for (i = 0; i < cci_pmu->nr_irqs; i++) {
+		int err = request_irq(cci_pmu->irqs[i], handler, IRQF_SHARED,
 				"arm-cci-pmu", cci_pmu);
 		if (err) {
 			dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n",
-				pmu->irqs[i]);
+				cci_pmu->irqs[i]);
 			return err;
 		}
 
-		set_bit(i, &pmu->active_irqs);
+		set_bit(i, &cci_pmu->active_irqs);
 	}
 
 	return 0;
@@ -350,11 +353,11 @@ static void pmu_free_irq(struct cci_pmu *cci_pmu)
 {
 	int i;
 
-	for (i = 0; i < pmu->nr_irqs; i++) {
-		if (!test_and_clear_bit(i, &pmu->active_irqs))
+	for (i = 0; i < cci_pmu->nr_irqs; i++) {
+		if (!test_and_clear_bit(i, &cci_pmu->active_irqs))
 			continue;
 
-		free_irq(pmu->irqs[i], cci_pmu);
+		free_irq(cci_pmu->irqs[i], cci_pmu);
 	}
 }
 
@@ -369,7 +372,7 @@ static u32 pmu_read_counter(struct perf_event *event)
 		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
 		return 0;
 	}
-	value = pmu_read_register(idx, CCI_PMU_CNTR);
+	value = pmu_read_register(cci_pmu, idx, CCI_PMU_CNTR);
 
 	return value;
 }
@@ -383,7 +386,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value)
 	if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
 		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
 	else
-		pmu_write_register(value, idx, CCI_PMU_CNTR);
+		pmu_write_register(cci_pmu, value, idx, CCI_PMU_CNTR);
 }
 
 static u64 pmu_event_update(struct perf_event *event)
@@ -427,7 +430,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 {
 	unsigned long flags;
 	struct cci_pmu *cci_pmu = dev;
-	struct cci_pmu_hw_events *events = &pmu->hw_events;
+	struct cci_pmu_hw_events *events = &cci_pmu->hw_events;
 	int idx, handled = IRQ_NONE;
 
 	raw_spin_lock_irqsave(&events->pmu_lock, flags);
@@ -446,11 +449,12 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 		hw_counter = &event->hw;
 
 		/* Did this counter overflow? */
-		if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) &
+		if (!(pmu_read_register(cci_pmu, idx, CCI_PMU_OVRFLW) &
 		      CCI_PMU_OVRFLW_FLAG))
 			continue;
 
-		pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
+		pmu_write_register(cci_pmu, CCI_PMU_OVRFLW_FLAG, idx,
+							CCI_PMU_OVRFLW);
 
 		pmu_event_update(event);
 		pmu_event_set_period(event);
@@ -549,10 +553,10 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
 	/* Configure the event to count, unless you are counting cycles */
 	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
-		pmu_set_event(idx, hwc->config_base);
+		pmu_set_event(cci_pmu, idx, hwc->config_base);
 
 	pmu_event_set_period(event);
-	pmu_enable_counter(idx);
+	pmu_enable_counter(cci_pmu, idx);
 
 	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
 }
@@ -575,7 +579,7 @@ static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
 	 * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
 	 * cci_pmu_start()
 	 */
-	pmu_disable_counter(idx);
+	pmu_disable_counter(cci_pmu, idx);
 	pmu_event_update(event);
 	hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
 }
@@ -779,20 +783,27 @@ static int cci_pmu_event_init(struct perf_event *event)
 	return err;
 }
 
-static ssize_t pmu_attr_cpumask_show(struct device *dev,
+static ssize_t pmu_cpumask_attr_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct dev_ext_attribute *eattr = container_of(attr,
+					struct dev_ext_attribute, attr);
+	struct cci_pmu *cci_pmu = eattr->var;
+
 	int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
-			  cpumask_pr_args(&pmu->cpus));
+			  cpumask_pr_args(&cci_pmu->cpus));
 	buf[n++] = '\n';
 	buf[n] = '\0';
 	return n;
 }
 
-static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
+static struct dev_ext_attribute pmu_cpumask_attr = {
+	__ATTR(cpumask, S_IRUGO, pmu_cpumask_attr_show, NULL),
+	NULL,		/* Populated in cci_pmu_init */
+};
 
 static struct attribute *pmu_attrs[] = {
-	&dev_attr_cpumask.attr,
+	&pmu_cpumask_attr.attr.attr,
 	NULL,
 };
 
@@ -808,6 +819,8 @@ static const struct attribute_group *pmu_attr_groups[] = {
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
+
+	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
 		.name		= cci_pmu->model->name,
 		.task_ctx_nr	= perf_invalid_context,
@@ -831,12 +844,14 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 static int cci_pmu_cpu_notifier(struct notifier_block *self,
 				unsigned long action, void *hcpu)
 {
+	struct cci_pmu *cci_pmu = container_of(self,
+					struct cci_pmu, cpu_nb);
 	unsigned int cpu = (long)hcpu;
 	unsigned int target;
 
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_DOWN_PREPARE:
-		if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
+		if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
 			break;
 		target = cpumask_any_but(cpu_online_mask, cpu);
 		if (target < 0) // UP, last CPU
@@ -845,7 +860,7 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 		 * TODO: migrate context once core races on event->ctx have
 		 * been fixed.
 		 */
-		cpumask_set_cpu(target, &pmu->cpus);
+		cpumask_set_cpu(target, &cci_pmu->cpus);
 	default:
 		break;
 	}
@@ -853,15 +868,6 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 	return NOTIFY_OK;
 }
 
-static struct notifier_block cci_pmu_cpu_nb = {
-	.notifier_call	= cci_pmu_cpu_notifier,
-	/*
-	 * to migrate uncore events, our notifier should be executed
-	 * before perf core's notifier.
-	 */
-	.priority	= CPU_PRI_PERF + 1,
-};
-
 static struct cci_pmu_model cci_pmu_models[] = {
 	[CCI_REV_R0] = {
 		.name = "CCI_400",
@@ -935,6 +941,7 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
 static int cci_pmu_probe(struct platform_device *pdev)
 {
 	struct resource *res;
+	struct cci_pmu *cci_pmu;
 	int i, ret, irq;
 	const struct cci_pmu_model *model;
 
@@ -944,30 +951,30 @@ static int cci_pmu_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
-	if (!pmu)
+	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
+	if (!cci_pmu)
 		return -ENOMEM;
 
-	pmu->model = model;
+	cci_pmu->model = model;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	pmu->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(pmu->base))
+	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(cci_pmu->base))
 		return -ENOMEM;
 
 	/*
 	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
 	 * together to a common interrupt.
 	 */
-	pmu->nr_irqs = 0;
+	cci_pmu->nr_irqs = 0;
 	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
 		irq = platform_get_irq(pdev, i);
 		if (irq < 0)
 			break;
 
-		if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs))
+		if (is_duplicate_irq(irq, cci_pmu->irqs, cci_pmu->nr_irqs))
 			continue;
 
-		pmu->irqs[pmu->nr_irqs++] = irq;
+		cci_pmu->irqs[cci_pmu->nr_irqs++] = irq;
 	}
 
 	/*
@@ -980,20 +987,31 @@ static int cci_pmu_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	raw_spin_lock_init(&pmu->hw_events.pmu_lock);
-	mutex_init(&pmu->reserve_mutex);
-	atomic_set(&pmu->active_events, 0);
-	cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
+	raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock);
+	mutex_init(&cci_pmu->reserve_mutex);
+	atomic_set(&cci_pmu->active_events, 0);
+	cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
 
-	ret = register_cpu_notifier(&cci_pmu_cpu_nb);
+	cci_pmu->cpu_nb = (struct notifier_block) {
+		.notifier_call	= cci_pmu_cpu_notifier,
+		/*
+		 * to migrate uncore events, our notifier should be executed
+		 * before perf core's notifier.
+		 */
+		.priority	= CPU_PRI_PERF + 1,
+	};
+
+	ret = register_cpu_notifier(&cci_pmu->cpu_nb);
 	if (ret)
 		return ret;
 
-	ret = cci_pmu_init(pmu, pdev);
-	if (ret)
+	ret = cci_pmu_init(cci_pmu, pdev);
+	if (ret) {
+		unregister_cpu_notifier(&cci_pmu->cpu_nb);
 		return ret;
+	}
 
-	pr_info("ARM %s PMU driver probed", pmu->model->name);
+	pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
 	return 0;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 3/7] arm-cci: Abstract out the PMU counter details
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Adds the PMU model specific counters to the PMU model
abstraction to make it easier to add a new PMU.

The patch cleans up the naming convention used all over
the code.
e.g, CCI_PMU_MAX_HW_EVENTS => maximum number of events that
can be counted at any time, which is in fact the maximum
number of counters available.

Change all such namings to use 'counters' instead of events.

This patch also abstracts the following:

1) Size of a PMU event counter area.
2) Maximum number of programmable counters supported by the PMU model
3) Number of counters which counts fixed events (e.g, cycle
  counter on CCI-400).

Also changes some of the static allocation of the data
structures to dynamic, to accommodate the number of events
supported by a PMU.

Gets rid ofthe CCI_PMU_* defines for the model. All such
data should be accessed via the model abstraction.

Limits the number of counters to the maximum supported
by the 'model'.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |  123 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 93 insertions(+), 30 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 27cc200..82d5681 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -77,15 +77,17 @@ static const struct of_device_id arm_cci_matches[] = {
 
 #define CCI_PMU_OVRFLW_FLAG	1
 
-#define CCI_PMU_CNTR_BASE(idx)	((idx) * SZ_4K)
-
-#define CCI_PMU_CNTR_MASK	((1ULL << 32) -1)
+#define CCI_PMU_CNTR_SIZE(model)	((model)->cntr_size)
+#define CCI_PMU_CNTR_BASE(model, idx)	((idx) * CCI_PMU_CNTR_SIZE(model))
+#define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
+#define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
 
 #define CCI_PMU_EVENT_MASK		0xffUL
 #define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
 #define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
 
-#define CCI_PMU_MAX_HW_EVENTS 5   /* CCI PMU has 4 counters + 1 cycle counter */
+#define CCI_PMU_MAX_HW_CNTRS(model) \
+	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
 
 /* Types of interfaces that can generate events */
 enum {
@@ -100,13 +102,22 @@ struct event_range {
 };
 
 struct cci_pmu_hw_events {
-	struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
-	unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
+	struct perf_event **events;
+	unsigned long *used_mask;
 	raw_spinlock_t pmu_lock;
 };
 
+/*
+ * struct cci_pmu_model:
+ * @fixed_hw_cntrs - Number of fixed event counters
+ * @num_hw_cntrs - Maximum number of programmable event counters
+ * @cntr_size - Size of an event counter mapping
+ */
 struct cci_pmu_model {
 	char *name;
+	u32 fixed_hw_cntrs;
+	u32 num_hw_cntrs;
+	u32 cntr_size;
 	struct event_range event_ranges[CCI_IF_MAX];
 };
 
@@ -116,12 +127,12 @@ struct cci_pmu {
 	void __iomem *base;
 	struct pmu pmu;
 	int nr_irqs;
-	int irqs[CCI_PMU_MAX_HW_EVENTS];
+	int *irqs;
 	unsigned long active_irqs;
 	const struct cci_pmu_model *model;
 	struct cci_pmu_hw_events hw_events;
 	struct platform_device *plat_device;
-	int num_events;
+	int num_cntrs;
 	atomic_t active_events;
 	struct mutex reserve_mutex;
 	struct notifier_block cpu_nb;
@@ -155,7 +166,6 @@ enum cci400_perf_events {
 
 #define CCI_PMU_CYCLE_CNTR_IDX		0
 #define CCI_PMU_CNTR0_IDX		1
-#define CCI_PMU_CNTR_LAST(cci_pmu)	(CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1)
 
 /*
  * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
@@ -235,20 +245,20 @@ static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
 
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
-		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
+	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
 }
 
 static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
 {
-	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return readl_relaxed(cci_pmu->base +
+			     CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
 }
 
 static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
 			       int idx, unsigned int offset)
 {
 	return writel_relaxed(value, cci_pmu->base +
-			      CCI_PMU_CNTR_BASE(idx) + offset);
+			      CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
 }
 
 static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
@@ -266,13 +276,14 @@ static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
 	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
 }
 
+/*
+ * Returns the number of programmable counters actually implemented
+ * by the cci
+ */
 static u32 pmu_get_max_counters(void)
 {
-	u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
-		      CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
-
-	/* add 1 for cycle counter */
-	return n_cnts + 1;
+	return (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
+		CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
 }
 
 static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
@@ -496,7 +507,7 @@ static void cci_pmu_enable(struct pmu *pmu)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
 	struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
-	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
+	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_cntrs);
 	unsigned long flags;
 	u32 val;
 
@@ -659,13 +670,16 @@ static int
 validate_group(struct perf_event *event)
 {
 	struct perf_event *sibling, *leader = event->group_leader;
+	struct cci_pmu  *cci_pmu = to_cci_pmu(event->pmu);
+	unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
 	struct cci_pmu_hw_events fake_pmu = {
 		/*
 		 * Initialise the fake PMU. We only need to populate the
 		 * used_mask for the purposes of validation.
 		 */
-		.used_mask =  { 0 },
+		.used_mask = mask,
 	};
+	memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
 
 	if (!validate_event(event->pmu, &fake_pmu, leader))
 		return -EINVAL;
@@ -819,6 +833,7 @@ static const struct attribute_group *pmu_attr_groups[] = {
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
+	u32 num_cntrs;
 
 	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
@@ -836,7 +851,15 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 	};
 
 	cci_pmu->plat_device = pdev;
-	cci_pmu->num_events = pmu_get_max_counters();
+	num_cntrs = pmu_get_max_counters();
+	if (num_cntrs > cci_pmu->model->num_hw_cntrs) {
+		dev_warn(&pdev->dev,
+			"PMU implements more counters(%d) than supported by"
+			" the model(%d), truncated.",
+			num_cntrs, cci_pmu->model->num_hw_cntrs);
+		num_cntrs = cci_pmu->model->num_hw_cntrs;
+	}
+	cci_pmu->num_cntrs = num_cntrs + cci_pmu->model->fixed_hw_cntrs;
 
 	return perf_pmu_register(&cci_pmu->pmu, name, -1);
 }
@@ -871,6 +894,9 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 static struct cci_pmu_model cci_pmu_models[] = {
 	[CCI_REV_R0] = {
 		.name = "CCI_400",
+		.fixed_hw_cntrs = 1,	/* Cycle counter */
+		.num_hw_cntrs = 4,
+		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI_REV_R0_SLAVE_PORT_MIN_EV,
@@ -884,6 +910,9 @@ static struct cci_pmu_model cci_pmu_models[] = {
 	},
 	[CCI_REV_R1] = {
 		.name = "CCI_400_r1",
+		.fixed_hw_cntrs = 1,	/* Cycle counter */
+		.num_hw_cntrs = 4,
+		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI_REV_R1_SLAVE_PORT_MIN_EV,
@@ -938,35 +967,69 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
 	return false;
 }
 
-static int cci_pmu_probe(struct platform_device *pdev)
+static struct cci_pmu *cci_pmu_alloc(struct platform_device *pdev)
 {
-	struct resource *res;
 	struct cci_pmu *cci_pmu;
-	int i, ret, irq;
 	const struct cci_pmu_model *model;
 
+	/*
+	 * All allocations are devm_* hence we don't have to free
+	 * them explicitly on an error, as it would end up in driver
+	 * detach.
+	 */
 	model = get_cci_model(pdev);
 	if (!model) {
 		dev_warn(&pdev->dev, "CCI PMU version not supported\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
 	if (!cci_pmu)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cci_pmu->model = model;
+	cci_pmu->irqs = devm_kcalloc(&pdev->dev, CCI_PMU_MAX_HW_CNTRS(model),
+					sizeof(*cci_pmu->irqs), GFP_KERNEL);
+	if (!cci_pmu->irqs)
+		return ERR_PTR(-ENOMEM);
+	cci_pmu->hw_events.events = devm_kcalloc(&pdev->dev,
+					     CCI_PMU_MAX_HW_CNTRS(model),
+					     sizeof(*cci_pmu->hw_events.events),
+					     GFP_KERNEL);
+	if (!cci_pmu->hw_events.events)
+		return ERR_PTR(-ENOMEM);
+	cci_pmu->hw_events.used_mask = devm_kcalloc(&pdev->dev,
+						BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
+						sizeof(*cci_pmu->hw_events.used_mask),
+						GFP_KERNEL);
+	if (!cci_pmu->hw_events.used_mask)
+		return ERR_PTR(-ENOMEM);
+
+	return cci_pmu;
+}
+
+
+static int cci_pmu_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct cci_pmu *cci_pmu;
+	int i, ret, irq;
+
+	cci_pmu = cci_pmu_alloc(pdev);
+	if (IS_ERR(cci_pmu))
+		return PTR_ERR(cci_pmu);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(cci_pmu->base))
 		return -ENOMEM;
 
 	/*
-	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
+	 * CCI PMU has one overflow interrupt per counter; but some may be tied
 	 * together to a common interrupt.
 	 */
 	cci_pmu->nr_irqs = 0;
-	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
+	for (i = 0; i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model); i++) {
 		irq = platform_get_irq(pdev, i);
 		if (irq < 0)
 			break;
@@ -981,9 +1044,9 @@ static int cci_pmu_probe(struct platform_device *pdev)
 	 * Ensure that the device tree has as many interrupts as the number
 	 * of counters.
 	 */
-	if (i < CCI_PMU_MAX_HW_EVENTS) {
+	if (i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model)) {
 		dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n",
-			i, CCI_PMU_MAX_HW_EVENTS);
+			i, CCI_PMU_MAX_HW_CNTRS(cci_pmu->model));
 		return -EINVAL;
 	}
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 3/7] arm-cci: Abstract out the PMU counter details
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

Adds the PMU model specific counters to the PMU model
abstraction to make it easier to add a new PMU.

The patch cleans up the naming convention used all over
the code.
e.g, CCI_PMU_MAX_HW_EVENTS => maximum number of events that
can be counted at any time, which is in fact the maximum
number of counters available.

Change all such namings to use 'counters' instead of events.

This patch also abstracts the following:

1) Size of a PMU event counter area.
2) Maximum number of programmable counters supported by the PMU model
3) Number of counters which counts fixed events (e.g, cycle
  counter on CCI-400).

Also changes some of the static allocation of the data
structures to dynamic, to accommodate the number of events
supported by a PMU.

Gets rid ofthe CCI_PMU_* defines for the model. All such
data should be accessed via the model abstraction.

Limits the number of counters to the maximum supported
by the 'model'.

Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
---
 drivers/bus/arm-cci.c |  123 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 93 insertions(+), 30 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 27cc200..82d5681 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -77,15 +77,17 @@ static const struct of_device_id arm_cci_matches[] = {
 
 #define CCI_PMU_OVRFLW_FLAG	1
 
-#define CCI_PMU_CNTR_BASE(idx)	((idx) * SZ_4K)
-
-#define CCI_PMU_CNTR_MASK	((1ULL << 32) -1)
+#define CCI_PMU_CNTR_SIZE(model)	((model)->cntr_size)
+#define CCI_PMU_CNTR_BASE(model, idx)	((idx) * CCI_PMU_CNTR_SIZE(model))
+#define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
+#define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
 
 #define CCI_PMU_EVENT_MASK		0xffUL
 #define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
 #define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
 
-#define CCI_PMU_MAX_HW_EVENTS 5   /* CCI PMU has 4 counters + 1 cycle counter */
+#define CCI_PMU_MAX_HW_CNTRS(model) \
+	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
 
 /* Types of interfaces that can generate events */
 enum {
@@ -100,13 +102,22 @@ struct event_range {
 };
 
 struct cci_pmu_hw_events {
-	struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
-	unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
+	struct perf_event **events;
+	unsigned long *used_mask;
 	raw_spinlock_t pmu_lock;
 };
 
+/*
+ * struct cci_pmu_model:
+ * @fixed_hw_cntrs - Number of fixed event counters
+ * @num_hw_cntrs - Maximum number of programmable event counters
+ * @cntr_size - Size of an event counter mapping
+ */
 struct cci_pmu_model {
 	char *name;
+	u32 fixed_hw_cntrs;
+	u32 num_hw_cntrs;
+	u32 cntr_size;
 	struct event_range event_ranges[CCI_IF_MAX];
 };
 
@@ -116,12 +127,12 @@ struct cci_pmu {
 	void __iomem *base;
 	struct pmu pmu;
 	int nr_irqs;
-	int irqs[CCI_PMU_MAX_HW_EVENTS];
+	int *irqs;
 	unsigned long active_irqs;
 	const struct cci_pmu_model *model;
 	struct cci_pmu_hw_events hw_events;
 	struct platform_device *plat_device;
-	int num_events;
+	int num_cntrs;
 	atomic_t active_events;
 	struct mutex reserve_mutex;
 	struct notifier_block cpu_nb;
@@ -155,7 +166,6 @@ enum cci400_perf_events {
 
 #define CCI_PMU_CYCLE_CNTR_IDX		0
 #define CCI_PMU_CNTR0_IDX		1
-#define CCI_PMU_CNTR_LAST(cci_pmu)	(CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1)
 
 /*
  * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
@@ -235,20 +245,20 @@ static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
 
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
-		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
+	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
 }
 
 static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
 {
-	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return readl_relaxed(cci_pmu->base +
+			     CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
 }
 
 static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
 			       int idx, unsigned int offset)
 {
 	return writel_relaxed(value, cci_pmu->base +
-			      CCI_PMU_CNTR_BASE(idx) + offset);
+			      CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
 }
 
 static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
@@ -266,13 +276,14 @@ static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
 	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
 }
 
+/*
+ * Returns the number of programmable counters actually implemented
+ * by the cci
+ */
 static u32 pmu_get_max_counters(void)
 {
-	u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
-		      CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
-
-	/* add 1 for cycle counter */
-	return n_cnts + 1;
+	return (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
+		CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
 }
 
 static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
@@ -496,7 +507,7 @@ static void cci_pmu_enable(struct pmu *pmu)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
 	struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
-	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
+	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_cntrs);
 	unsigned long flags;
 	u32 val;
 
@@ -659,13 +670,16 @@ static int
 validate_group(struct perf_event *event)
 {
 	struct perf_event *sibling, *leader = event->group_leader;
+	struct cci_pmu  *cci_pmu = to_cci_pmu(event->pmu);
+	unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
 	struct cci_pmu_hw_events fake_pmu = {
 		/*
 		 * Initialise the fake PMU. We only need to populate the
 		 * used_mask for the purposes of validation.
 		 */
-		.used_mask =  { 0 },
+		.used_mask = mask,
 	};
+	memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
 
 	if (!validate_event(event->pmu, &fake_pmu, leader))
 		return -EINVAL;
@@ -819,6 +833,7 @@ static const struct attribute_group *pmu_attr_groups[] = {
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
+	u32 num_cntrs;
 
 	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
@@ -836,7 +851,15 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 	};
 
 	cci_pmu->plat_device = pdev;
-	cci_pmu->num_events = pmu_get_max_counters();
+	num_cntrs = pmu_get_max_counters();
+	if (num_cntrs > cci_pmu->model->num_hw_cntrs) {
+		dev_warn(&pdev->dev,
+			"PMU implements more counters(%d) than supported by"
+			" the model(%d), truncated.",
+			num_cntrs, cci_pmu->model->num_hw_cntrs);
+		num_cntrs = cci_pmu->model->num_hw_cntrs;
+	}
+	cci_pmu->num_cntrs = num_cntrs + cci_pmu->model->fixed_hw_cntrs;
 
 	return perf_pmu_register(&cci_pmu->pmu, name, -1);
 }
@@ -871,6 +894,9 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 static struct cci_pmu_model cci_pmu_models[] = {
 	[CCI_REV_R0] = {
 		.name = "CCI_400",
+		.fixed_hw_cntrs = 1,	/* Cycle counter */
+		.num_hw_cntrs = 4,
+		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI_REV_R0_SLAVE_PORT_MIN_EV,
@@ -884,6 +910,9 @@ static struct cci_pmu_model cci_pmu_models[] = {
 	},
 	[CCI_REV_R1] = {
 		.name = "CCI_400_r1",
+		.fixed_hw_cntrs = 1,	/* Cycle counter */
+		.num_hw_cntrs = 4,
+		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI_REV_R1_SLAVE_PORT_MIN_EV,
@@ -938,35 +967,69 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
 	return false;
 }
 
-static int cci_pmu_probe(struct platform_device *pdev)
+static struct cci_pmu *cci_pmu_alloc(struct platform_device *pdev)
 {
-	struct resource *res;
 	struct cci_pmu *cci_pmu;
-	int i, ret, irq;
 	const struct cci_pmu_model *model;
 
+	/*
+	 * All allocations are devm_* hence we don't have to free
+	 * them explicitly on an error, as it would end up in driver
+	 * detach.
+	 */
 	model = get_cci_model(pdev);
 	if (!model) {
 		dev_warn(&pdev->dev, "CCI PMU version not supported\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
 	if (!cci_pmu)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cci_pmu->model = model;
+	cci_pmu->irqs = devm_kcalloc(&pdev->dev, CCI_PMU_MAX_HW_CNTRS(model),
+					sizeof(*cci_pmu->irqs), GFP_KERNEL);
+	if (!cci_pmu->irqs)
+		return ERR_PTR(-ENOMEM);
+	cci_pmu->hw_events.events = devm_kcalloc(&pdev->dev,
+					     CCI_PMU_MAX_HW_CNTRS(model),
+					     sizeof(*cci_pmu->hw_events.events),
+					     GFP_KERNEL);
+	if (!cci_pmu->hw_events.events)
+		return ERR_PTR(-ENOMEM);
+	cci_pmu->hw_events.used_mask = devm_kcalloc(&pdev->dev,
+						BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
+						sizeof(*cci_pmu->hw_events.used_mask),
+						GFP_KERNEL);
+	if (!cci_pmu->hw_events.used_mask)
+		return ERR_PTR(-ENOMEM);
+
+	return cci_pmu;
+}
+
+
+static int cci_pmu_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct cci_pmu *cci_pmu;
+	int i, ret, irq;
+
+	cci_pmu = cci_pmu_alloc(pdev);
+	if (IS_ERR(cci_pmu))
+		return PTR_ERR(cci_pmu);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(cci_pmu->base))
 		return -ENOMEM;
 
 	/*
-	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
+	 * CCI PMU has one overflow interrupt per counter; but some may be tied
 	 * together to a common interrupt.
 	 */
 	cci_pmu->nr_irqs = 0;
-	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
+	for (i = 0; i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model); i++) {
 		irq = platform_get_irq(pdev, i);
 		if (irq < 0)
 			break;
@@ -981,9 +1044,9 @@ static int cci_pmu_probe(struct platform_device *pdev)
 	 * Ensure that the device tree has as many interrupts as the number
 	 * of counters.
 	 */
-	if (i < CCI_PMU_MAX_HW_EVENTS) {
+	if (i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model)) {
 		dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n",
-			i, CCI_PMU_MAX_HW_EVENTS);
+			i, CCI_PMU_MAX_HW_CNTRS(cci_pmu->model));
 		return -EINVAL;
 	}
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 3/7] arm-cci: Abstract out the PMU counter details
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Adds the PMU model specific counters to the PMU model
abstraction to make it easier to add a new PMU.

The patch cleans up the naming convention used all over
the code.
e.g, CCI_PMU_MAX_HW_EVENTS => maximum number of events that
can be counted at any time, which is in fact the maximum
number of counters available.

Change all such namings to use 'counters' instead of events.

This patch also abstracts the following:

1) Size of a PMU event counter area.
2) Maximum number of programmable counters supported by the PMU model
3) Number of counters which counts fixed events (e.g, cycle
  counter on CCI-400).

Also changes some of the static allocation of the data
structures to dynamic, to accommodate the number of events
supported by a PMU.

Gets rid ofthe CCI_PMU_* defines for the model. All such
data should be accessed via the model abstraction.

Limits the number of counters to the maximum supported
by the 'model'.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |  123 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 93 insertions(+), 30 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 27cc200..82d5681 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -77,15 +77,17 @@ static const struct of_device_id arm_cci_matches[] = {
 
 #define CCI_PMU_OVRFLW_FLAG	1
 
-#define CCI_PMU_CNTR_BASE(idx)	((idx) * SZ_4K)
-
-#define CCI_PMU_CNTR_MASK	((1ULL << 32) -1)
+#define CCI_PMU_CNTR_SIZE(model)	((model)->cntr_size)
+#define CCI_PMU_CNTR_BASE(model, idx)	((idx) * CCI_PMU_CNTR_SIZE(model))
+#define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
+#define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
 
 #define CCI_PMU_EVENT_MASK		0xffUL
 #define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
 #define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
 
-#define CCI_PMU_MAX_HW_EVENTS 5   /* CCI PMU has 4 counters + 1 cycle counter */
+#define CCI_PMU_MAX_HW_CNTRS(model) \
+	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
 
 /* Types of interfaces that can generate events */
 enum {
@@ -100,13 +102,22 @@ struct event_range {
 };
 
 struct cci_pmu_hw_events {
-	struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
-	unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
+	struct perf_event **events;
+	unsigned long *used_mask;
 	raw_spinlock_t pmu_lock;
 };
 
+/*
+ * struct cci_pmu_model:
+ * @fixed_hw_cntrs - Number of fixed event counters
+ * @num_hw_cntrs - Maximum number of programmable event counters
+ * @cntr_size - Size of an event counter mapping
+ */
 struct cci_pmu_model {
 	char *name;
+	u32 fixed_hw_cntrs;
+	u32 num_hw_cntrs;
+	u32 cntr_size;
 	struct event_range event_ranges[CCI_IF_MAX];
 };
 
@@ -116,12 +127,12 @@ struct cci_pmu {
 	void __iomem *base;
 	struct pmu pmu;
 	int nr_irqs;
-	int irqs[CCI_PMU_MAX_HW_EVENTS];
+	int *irqs;
 	unsigned long active_irqs;
 	const struct cci_pmu_model *model;
 	struct cci_pmu_hw_events hw_events;
 	struct platform_device *plat_device;
-	int num_events;
+	int num_cntrs;
 	atomic_t active_events;
 	struct mutex reserve_mutex;
 	struct notifier_block cpu_nb;
@@ -155,7 +166,6 @@ enum cci400_perf_events {
 
 #define CCI_PMU_CYCLE_CNTR_IDX		0
 #define CCI_PMU_CNTR0_IDX		1
-#define CCI_PMU_CNTR_LAST(cci_pmu)	(CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1)
 
 /*
  * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
@@ -235,20 +245,20 @@ static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
 
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
-	return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
-		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
+	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
 }
 
 static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
 {
-	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+	return readl_relaxed(cci_pmu->base +
+			     CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
 }
 
 static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
 			       int idx, unsigned int offset)
 {
 	return writel_relaxed(value, cci_pmu->base +
-			      CCI_PMU_CNTR_BASE(idx) + offset);
+			      CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
 }
 
 static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
@@ -266,13 +276,14 @@ static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
 	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
 }
 
+/*
+ * Returns the number of programmable counters actually implemented
+ * by the cci
+ */
 static u32 pmu_get_max_counters(void)
 {
-	u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
-		      CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
-
-	/* add 1 for cycle counter */
-	return n_cnts + 1;
+	return (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
+		CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
 }
 
 static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
@@ -496,7 +507,7 @@ static void cci_pmu_enable(struct pmu *pmu)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
 	struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
-	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
+	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_cntrs);
 	unsigned long flags;
 	u32 val;
 
@@ -659,13 +670,16 @@ static int
 validate_group(struct perf_event *event)
 {
 	struct perf_event *sibling, *leader = event->group_leader;
+	struct cci_pmu  *cci_pmu = to_cci_pmu(event->pmu);
+	unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
 	struct cci_pmu_hw_events fake_pmu = {
 		/*
 		 * Initialise the fake PMU. We only need to populate the
 		 * used_mask for the purposes of validation.
 		 */
-		.used_mask =  { 0 },
+		.used_mask = mask,
 	};
+	memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
 
 	if (!validate_event(event->pmu, &fake_pmu, leader))
 		return -EINVAL;
@@ -819,6 +833,7 @@ static const struct attribute_group *pmu_attr_groups[] = {
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
+	u32 num_cntrs;
 
 	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
@@ -836,7 +851,15 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 	};
 
 	cci_pmu->plat_device = pdev;
-	cci_pmu->num_events = pmu_get_max_counters();
+	num_cntrs = pmu_get_max_counters();
+	if (num_cntrs > cci_pmu->model->num_hw_cntrs) {
+		dev_warn(&pdev->dev,
+			"PMU implements more counters(%d) than supported by"
+			" the model(%d), truncated.",
+			num_cntrs, cci_pmu->model->num_hw_cntrs);
+		num_cntrs = cci_pmu->model->num_hw_cntrs;
+	}
+	cci_pmu->num_cntrs = num_cntrs + cci_pmu->model->fixed_hw_cntrs;
 
 	return perf_pmu_register(&cci_pmu->pmu, name, -1);
 }
@@ -871,6 +894,9 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 static struct cci_pmu_model cci_pmu_models[] = {
 	[CCI_REV_R0] = {
 		.name = "CCI_400",
+		.fixed_hw_cntrs = 1,	/* Cycle counter */
+		.num_hw_cntrs = 4,
+		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI_REV_R0_SLAVE_PORT_MIN_EV,
@@ -884,6 +910,9 @@ static struct cci_pmu_model cci_pmu_models[] = {
 	},
 	[CCI_REV_R1] = {
 		.name = "CCI_400_r1",
+		.fixed_hw_cntrs = 1,	/* Cycle counter */
+		.num_hw_cntrs = 4,
+		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI_REV_R1_SLAVE_PORT_MIN_EV,
@@ -938,35 +967,69 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
 	return false;
 }
 
-static int cci_pmu_probe(struct platform_device *pdev)
+static struct cci_pmu *cci_pmu_alloc(struct platform_device *pdev)
 {
-	struct resource *res;
 	struct cci_pmu *cci_pmu;
-	int i, ret, irq;
 	const struct cci_pmu_model *model;
 
+	/*
+	 * All allocations are devm_* hence we don't have to free
+	 * them explicitly on an error, as it would end up in driver
+	 * detach.
+	 */
 	model = get_cci_model(pdev);
 	if (!model) {
 		dev_warn(&pdev->dev, "CCI PMU version not supported\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
 	if (!cci_pmu)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cci_pmu->model = model;
+	cci_pmu->irqs = devm_kcalloc(&pdev->dev, CCI_PMU_MAX_HW_CNTRS(model),
+					sizeof(*cci_pmu->irqs), GFP_KERNEL);
+	if (!cci_pmu->irqs)
+		return ERR_PTR(-ENOMEM);
+	cci_pmu->hw_events.events = devm_kcalloc(&pdev->dev,
+					     CCI_PMU_MAX_HW_CNTRS(model),
+					     sizeof(*cci_pmu->hw_events.events),
+					     GFP_KERNEL);
+	if (!cci_pmu->hw_events.events)
+		return ERR_PTR(-ENOMEM);
+	cci_pmu->hw_events.used_mask = devm_kcalloc(&pdev->dev,
+						BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
+						sizeof(*cci_pmu->hw_events.used_mask),
+						GFP_KERNEL);
+	if (!cci_pmu->hw_events.used_mask)
+		return ERR_PTR(-ENOMEM);
+
+	return cci_pmu;
+}
+
+
+static int cci_pmu_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct cci_pmu *cci_pmu;
+	int i, ret, irq;
+
+	cci_pmu = cci_pmu_alloc(pdev);
+	if (IS_ERR(cci_pmu))
+		return PTR_ERR(cci_pmu);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(cci_pmu->base))
 		return -ENOMEM;
 
 	/*
-	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
+	 * CCI PMU has one overflow interrupt per counter; but some may be tied
 	 * together to a common interrupt.
 	 */
 	cci_pmu->nr_irqs = 0;
-	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
+	for (i = 0; i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model); i++) {
 		irq = platform_get_irq(pdev, i);
 		if (irq < 0)
 			break;
@@ -981,9 +1044,9 @@ static int cci_pmu_probe(struct platform_device *pdev)
 	 * Ensure that the device tree has as many interrupts as the number
 	 * of counters.
 	 */
-	if (i < CCI_PMU_MAX_HW_EVENTS) {
+	if (i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model)) {
 		dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n",
-			i, CCI_PMU_MAX_HW_EVENTS);
+			i, CCI_PMU_MAX_HW_CNTRS(cci_pmu->model));
 		return -EINVAL;
 	}
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 4/7] arm-cci: Abstract handling for CCI events
  2015-05-05 11:49 ` Suzuki K. Poulose
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  -1 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Given that each CCI has different set of interfaces and
its associated events, it is good to abstract the validation of the
event codes to make it easier to add support for a new CCI model.

This patch also abstracts the mapping of a given event to a counter,
as there are some special counters for certain specific events.

We assume that the fixed hardware counters are always at the beginning,
so that we can use cci_model->fixed_hw_events as an upper bound to given
idx to check if we need to program the counter for an event.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |   78 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 23 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 82d5681..4b9a8d3 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -107,6 +107,7 @@ struct cci_pmu_hw_events {
 	raw_spinlock_t pmu_lock;
 };
 
+struct cci_pmu;
 /*
  * struct cci_pmu_model:
  * @fixed_hw_cntrs - Number of fixed event counters
@@ -119,6 +120,8 @@ struct cci_pmu_model {
 	u32 num_hw_cntrs;
 	u32 cntr_size;
 	struct event_range event_ranges[CCI_IF_MAX];
+	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
+	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
 };
 
 static struct cci_pmu_model cci_pmu_models[];
@@ -189,7 +192,29 @@ enum cci400_perf_events {
 #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
 
-static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
+static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
+				struct cci_pmu_hw_events *hw,
+				unsigned long cci_event)
+{
+	int idx;
+
+	/* cycles event idx is fixed */
+	if (cci_event == CCI_PMU_CYCLES) {
+		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+			return -EAGAIN;
+
+		return CCI_PMU_CYCLE_CNTR_IDX;
+	}
+
+	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+		if (!test_and_set_bit(idx, hw->used_mask))
+			return idx;
+
+	/* No counters available */
+	return -EAGAIN;
+}
+
+static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
 	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
 	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
@@ -198,6 +223,9 @@ static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event
 	if (hw_event & ~CCI_PMU_EVENT_MASK)
 		return -ENOENT;
 
+	if (hw_event == CCI_PMU_CYCLES)
+		return hw_event;
+
 	switch (ev_source) {
 	case CCI_PORT_S0:
 	case CCI_PORT_S1:
@@ -289,18 +317,14 @@ static u32 pmu_get_max_counters(void)
 static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
-	struct hw_perf_event *hw_event = &event->hw;
-	unsigned long cci_event = hw_event->config_base;
+	unsigned long cci_event = event->hw.config_base;
 	int idx;
 
-	if (cci_event == CCI_PMU_CYCLES) {
-		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
-			return -EAGAIN;
+	if (cci_pmu->model->get_event_idx)
+		return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
 
-		return CCI_PMU_CYCLE_CNTR_IDX;
-	}
-
-	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+	/* Generic code to find an unused idx from the mask */
+	for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
 		if (!test_and_set_bit(idx, hw->used_mask))
 			return idx;
 
@@ -310,19 +334,13 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
 
 static int pmu_map_event(struct perf_event *event)
 {
-	int mapping;
-	unsigned long config = event->attr.config;
+	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
 
-	if (event->attr.type < PERF_TYPE_MAX)
+	if (event->attr.type < PERF_TYPE_MAX ||
+			!cci_pmu->model->validate_hw_event)
 		return -ENOENT;
 
-	if (config == CCI_PMU_CYCLES)
-		mapping = config;
-	else
-		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
-							config);
-
-	return mapping;
+	return	cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config);
 }
 
 static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
@@ -450,7 +468,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 	 * This should work regardless of whether we have per-counter overflow
 	 * interrupt or a combined overflow interrupt.
 	 */
-	for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
+	for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
 		struct perf_event *event = events->events[idx];
 		struct hw_perf_event *hw_counter;
 
@@ -538,6 +556,16 @@ static void cci_pmu_disable(struct pmu *pmu)
 	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
 }
 
+/*
+ * Check if the idx represents a non-programmable counter.
+ * All the fixed event counters are mapped before the programmable
+ * counters.
+ */
+static bool pmu_fixed_hw_idx(struct cci_pmu *cci_pmu, int idx)
+{
+	return (idx >= 0) && (idx < cci_pmu->model->fixed_hw_cntrs);
+}
+
 static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
@@ -562,8 +590,8 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
 	raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
 
-	/* Configure the event to count, unless you are counting cycles */
-	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
+	/* Configure the counter unless you are counting a fixed event */
+	if (!pmu_fixed_hw_idx(cci_pmu, idx))
 		pmu_set_event(cci_pmu, idx, hwc->config_base);
 
 	pmu_event_set_period(event);
@@ -907,6 +935,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R0_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 	[CCI_REV_R1] = {
 		.name = "CCI_400_r1",
@@ -923,6 +953,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R1_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 };
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 4/7] arm-cci: Abstract handling for CCI events
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Given that each CCI has different set of interfaces and
its associated events, it is good to abstract the validation of the
event codes to make it easier to add support for a new CCI model.

This patch also abstracts the mapping of a given event to a counter,
as there are some special counters for certain specific events.

We assume that the fixed hardware counters are always at the beginning,
so that we can use cci_model->fixed_hw_events as an upper bound to given
idx to check if we need to program the counter for an event.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |   78 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 23 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 82d5681..4b9a8d3 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -107,6 +107,7 @@ struct cci_pmu_hw_events {
 	raw_spinlock_t pmu_lock;
 };
 
+struct cci_pmu;
 /*
  * struct cci_pmu_model:
  * @fixed_hw_cntrs - Number of fixed event counters
@@ -119,6 +120,8 @@ struct cci_pmu_model {
 	u32 num_hw_cntrs;
 	u32 cntr_size;
 	struct event_range event_ranges[CCI_IF_MAX];
+	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
+	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
 };
 
 static struct cci_pmu_model cci_pmu_models[];
@@ -189,7 +192,29 @@ enum cci400_perf_events {
 #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
 
-static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
+static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
+				struct cci_pmu_hw_events *hw,
+				unsigned long cci_event)
+{
+	int idx;
+
+	/* cycles event idx is fixed */
+	if (cci_event == CCI_PMU_CYCLES) {
+		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+			return -EAGAIN;
+
+		return CCI_PMU_CYCLE_CNTR_IDX;
+	}
+
+	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+		if (!test_and_set_bit(idx, hw->used_mask))
+			return idx;
+
+	/* No counters available */
+	return -EAGAIN;
+}
+
+static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
 	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
 	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
@@ -198,6 +223,9 @@ static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event
 	if (hw_event & ~CCI_PMU_EVENT_MASK)
 		return -ENOENT;
 
+	if (hw_event == CCI_PMU_CYCLES)
+		return hw_event;
+
 	switch (ev_source) {
 	case CCI_PORT_S0:
 	case CCI_PORT_S1:
@@ -289,18 +317,14 @@ static u32 pmu_get_max_counters(void)
 static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
-	struct hw_perf_event *hw_event = &event->hw;
-	unsigned long cci_event = hw_event->config_base;
+	unsigned long cci_event = event->hw.config_base;
 	int idx;
 
-	if (cci_event == CCI_PMU_CYCLES) {
-		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
-			return -EAGAIN;
+	if (cci_pmu->model->get_event_idx)
+		return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
 
-		return CCI_PMU_CYCLE_CNTR_IDX;
-	}
-
-	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+	/* Generic code to find an unused idx from the mask */
+	for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
 		if (!test_and_set_bit(idx, hw->used_mask))
 			return idx;
 
@@ -310,19 +334,13 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
 
 static int pmu_map_event(struct perf_event *event)
 {
-	int mapping;
-	unsigned long config = event->attr.config;
+	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
 
-	if (event->attr.type < PERF_TYPE_MAX)
+	if (event->attr.type < PERF_TYPE_MAX ||
+			!cci_pmu->model->validate_hw_event)
 		return -ENOENT;
 
-	if (config == CCI_PMU_CYCLES)
-		mapping = config;
-	else
-		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
-							config);
-
-	return mapping;
+	return	cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config);
 }
 
 static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
@@ -450,7 +468,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 	 * This should work regardless of whether we have per-counter overflow
 	 * interrupt or a combined overflow interrupt.
 	 */
-	for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
+	for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
 		struct perf_event *event = events->events[idx];
 		struct hw_perf_event *hw_counter;
 
@@ -538,6 +556,16 @@ static void cci_pmu_disable(struct pmu *pmu)
 	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
 }
 
+/*
+ * Check if the idx represents a non-programmable counter.
+ * All the fixed event counters are mapped before the programmable
+ * counters.
+ */
+static bool pmu_fixed_hw_idx(struct cci_pmu *cci_pmu, int idx)
+{
+	return (idx >= 0) && (idx < cci_pmu->model->fixed_hw_cntrs);
+}
+
 static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
@@ -562,8 +590,8 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
 	raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
 
-	/* Configure the event to count, unless you are counting cycles */
-	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
+	/* Configure the counter unless you are counting a fixed event */
+	if (!pmu_fixed_hw_idx(cci_pmu, idx))
 		pmu_set_event(cci_pmu, idx, hwc->config_base);
 
 	pmu_event_set_period(event);
@@ -907,6 +935,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R0_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 	[CCI_REV_R1] = {
 		.name = "CCI_400_r1",
@@ -923,6 +953,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R1_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 };
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Rename CCI400 specific defintions from CCI_xxx to CCI400_xxx.

Introduce generic ARM_CCI_PMU to cover common code for handling
the CCI PMU.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Punit Agrawal <punit.agrawal@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/Kconfig   |    5 ++
 drivers/bus/arm-cci.c |  157 +++++++++++++++++++++++++++++--------------------
 2 files changed, 97 insertions(+), 65 deletions(-)

diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index a1d4af6..be66b7c 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -7,6 +7,10 @@ menu "Bus devices"
 config ARM_CCI
 	bool
 
+config ARM_CCI_PMU
+	bool
+	select ARM_CCI
+
 config ARM_CCI400_COMMON
 	bool
 	select ARM_CCI
@@ -17,6 +21,7 @@ config ARM_CCI400_PMU
 	depends on ARM || ARM64
 	depends on HW_PERF_EVENTS
 	select ARM_CCI400_COMMON
+	select ARM_CCI_PMU
 	help
 	  Support for PMU events monitoring on the ARM CCI cache coherent
 	  interconnect.
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 4b9a8d3..2b43cea 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -55,9 +55,9 @@ static const struct of_device_id arm_cci_matches[] = {
 	{},
 };
 
-#ifdef CONFIG_ARM_CCI400_PMU
+#ifdef CONFIG_ARM_CCI_PMU
 
-#define DRIVER_NAME		"CCI-400"
+#define DRIVER_NAME		"ARM-CCI"
 #define DRIVER_NAME_PMU		DRIVER_NAME " PMU"
 
 #define CCI_PMCR		0x0100
@@ -82,10 +82,6 @@ static const struct of_device_id arm_cci_matches[] = {
 #define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
 #define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
 
-#define CCI_PMU_EVENT_MASK		0xffUL
-#define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
-#define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
-
 #define CCI_PMU_MAX_HW_CNTRS(model) \
 	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
 
@@ -144,19 +140,29 @@ struct cci_pmu {
 
 #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
 
+enum cci_models {
+#ifdef CONFIG_ARM_CCI400_PMU
+	CCI400_R0,
+	CCI400_R1,
+#endif
+	CCI_MODEL_MAX
+};
+
+/* CCI400 PMU Specific definitions */
+
+#ifdef CONFIG_ARM_CCI400_PMU
+
 /* Port ids */
-#define CCI_PORT_S0	0
-#define CCI_PORT_S1	1
-#define CCI_PORT_S2	2
-#define CCI_PORT_S3	3
-#define CCI_PORT_S4	4
-#define CCI_PORT_M0	5
-#define CCI_PORT_M1	6
-#define CCI_PORT_M2	7
-
-#define CCI_REV_R0		0
-#define CCI_REV_R1		1
-#define CCI_REV_R1_PX		5
+#define CCI400_PORT_S0		0
+#define CCI400_PORT_S1		1
+#define CCI400_PORT_S2		2
+#define CCI400_PORT_S3		3
+#define CCI400_PORT_S4		4
+#define CCI400_PORT_M0		5
+#define CCI400_PORT_M1		6
+#define CCI400_PORT_M2		7
+
+#define CCI400_R1_PX		5
 
 /*
  * Instead of an event id to monitor CCI cycles, a dedicated counter is
@@ -164,11 +170,11 @@ struct cci_pmu {
  * make use of this event in hardware.
  */
 enum cci400_perf_events {
-	CCI_PMU_CYCLES = 0xff
+	CCI400_PMU_CYCLES = 0xff
 };
 
-#define CCI_PMU_CYCLE_CNTR_IDX		0
-#define CCI_PMU_CNTR0_IDX		1
+#define CCI400_PMU_CYCLE_CNTR_IDX	0
+#define CCI400_PMU_CNTR0_IDX		1
 
 /*
  * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
@@ -182,15 +188,26 @@ enum cci400_perf_events {
  * the different revisions and are used to validate the event to be monitored.
  */
 
-#define CCI_REV_R0_SLAVE_PORT_MIN_EV	0x00
-#define CCI_REV_R0_SLAVE_PORT_MAX_EV	0x13
-#define CCI_REV_R0_MASTER_PORT_MIN_EV	0x14
-#define CCI_REV_R0_MASTER_PORT_MAX_EV	0x1a
-
-#define CCI_REV_R1_SLAVE_PORT_MIN_EV	0x00
-#define CCI_REV_R1_SLAVE_PORT_MAX_EV	0x14
-#define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
-#define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
+#define CCI400_PMU_EVENT_MASK		0xffUL
+#define CCI400_PMU_EVENT_SOURCE_SHIFT	5
+#define CCI400_PMU_EVENT_SOURCE_MASK	0x7
+#define CCI400_PMU_EVENT_CODE_SHIFT	0
+#define CCI400_PMU_EVENT_CODE_MASK	0x1f
+#define CCI400_PMU_EVENT_SOURCE(event) \
+	((event >> CCI400_PMU_EVENT_SOURCE_SHIFT) & \
+			CCI400_PMU_EVENT_SOURCE_MASK)
+#define CCI400_PMU_EVENT_CODE(event) \
+	((event >> CCI400_PMU_EVENT_CODE_SHIFT) & CCI400_PMU_EVENT_CODE_MASK)
+
+#define CCI400_R0_SLAVE_PORT_MIN_EV	0x00
+#define CCI400_R0_SLAVE_PORT_MAX_EV	0x13
+#define CCI400_R0_MASTER_PORT_MIN_EV	0x14
+#define CCI400_R0_MASTER_PORT_MAX_EV	0x1a
+
+#define CCI400_R1_SLAVE_PORT_MIN_EV	0x00
+#define CCI400_R1_SLAVE_PORT_MAX_EV	0x14
+#define CCI400_R1_MASTER_PORT_MIN_EV	0x00
+#define CCI400_R1_MASTER_PORT_MAX_EV	0x11
 
 static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 				struct cci_pmu_hw_events *hw,
@@ -199,14 +216,14 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 	int idx;
 
 	/* cycles event idx is fixed */
-	if (cci_event == CCI_PMU_CYCLES) {
-		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+	if (cci_event == CCI400_PMU_CYCLES) {
+		if (test_and_set_bit(CCI400_PMU_CYCLE_CNTR_IDX, hw->used_mask))
 			return -EAGAIN;
 
-		return CCI_PMU_CYCLE_CNTR_IDX;
+		return CCI400_PMU_CYCLE_CNTR_IDX;
 	}
 
-	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+	for (idx = CCI400_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
 		if (!test_and_set_bit(idx, hw->used_mask))
 			return idx;
 
@@ -216,28 +233,28 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 
 static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
-	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
-	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
+	u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event);
+	u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event);
 	int if_type;
 
-	if (hw_event & ~CCI_PMU_EVENT_MASK)
+	if (hw_event & ~CCI400_PMU_EVENT_MASK)
 		return -ENOENT;
 
-	if (hw_event == CCI_PMU_CYCLES)
+	if (hw_event == CCI400_PMU_CYCLES)
 		return hw_event;
 
 	switch (ev_source) {
-	case CCI_PORT_S0:
-	case CCI_PORT_S1:
-	case CCI_PORT_S2:
-	case CCI_PORT_S3:
-	case CCI_PORT_S4:
+	case CCI400_PORT_S0:
+	case CCI400_PORT_S1:
+	case CCI400_PORT_S2:
+	case CCI400_PORT_S3:
+	case CCI400_PORT_S4:
 		/* Slave Interface */
 		if_type = CCI_IF_SLAVE;
 		break;
-	case CCI_PORT_M0:
-	case CCI_PORT_M1:
-	case CCI_PORT_M2:
+	case CCI400_PORT_M0:
+	case CCI400_PORT_M1:
+	case CCI400_PORT_M2:
 		/* Master Interface */
 		if_type = CCI_IF_MASTER;
 		break;
@@ -252,24 +269,30 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev
 	return -ENOENT;
 }
 
-static int probe_cci_revision(void)
+static int probe_cci400_revision(void)
 {
 	int rev;
 	rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK;
 	rev >>= CCI_PID2_REV_SHIFT;
 
-	if (rev < CCI_REV_R1_PX)
-		return CCI_REV_R0;
+	if (rev < CCI400_R1_PX)
+		return CCI400_R0;
 	else
-		return CCI_REV_R1;
+		return CCI400_R1;
 }
 
 static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
 {
 	if (platform_has_secure_cci_access())
-		return &cci_pmu_models[probe_cci_revision()];
+		return &cci_pmu_models[probe_cci400_revision()];
+	return NULL;
+}
+#else	/* !CONFIG_ARM_CCI400_PMU */
+static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
+{
 	return NULL;
 }
+#endif	/* CONFIG_ARM_CCI400_PMU */
 
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
@@ -920,57 +943,61 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 }
 
 static struct cci_pmu_model cci_pmu_models[] = {
-	[CCI_REV_R0] = {
+#ifdef CONFIG_ARM_CCI400_PMU
+	[CCI400_R0] = {
 		.name = "CCI_400",
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
-				CCI_REV_R0_SLAVE_PORT_MIN_EV,
-				CCI_REV_R0_SLAVE_PORT_MAX_EV,
+				CCI400_R0_SLAVE_PORT_MIN_EV,
+				CCI400_R0_SLAVE_PORT_MAX_EV,
 			},
 			[CCI_IF_MASTER] = {
-				CCI_REV_R0_MASTER_PORT_MIN_EV,
-				CCI_REV_R0_MASTER_PORT_MAX_EV,
+				CCI400_R0_MASTER_PORT_MIN_EV,
+				CCI400_R0_MASTER_PORT_MAX_EV,
 			},
 		},
 		.validate_hw_event = cci400_validate_hw_event,
 		.get_event_idx = cci400_get_event_idx,
 	},
-	[CCI_REV_R1] = {
+	[CCI400_R1] = {
 		.name = "CCI_400_r1",
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
-				CCI_REV_R1_SLAVE_PORT_MIN_EV,
-				CCI_REV_R1_SLAVE_PORT_MAX_EV,
+				CCI400_R1_SLAVE_PORT_MIN_EV,
+				CCI400_R1_SLAVE_PORT_MAX_EV,
 			},
 			[CCI_IF_MASTER] = {
-				CCI_REV_R1_MASTER_PORT_MIN_EV,
-				CCI_REV_R1_MASTER_PORT_MAX_EV,
+				CCI400_R1_MASTER_PORT_MIN_EV,
+				CCI400_R1_MASTER_PORT_MAX_EV,
 			},
 		},
 		.validate_hw_event = cci400_validate_hw_event,
 		.get_event_idx = cci400_get_event_idx,
 	},
+#endif
 };
 
 static const struct of_device_id arm_cci_pmu_matches[] = {
+#ifdef CONFIG_ARM_CCI400_PMU
 	{
 		.compatible = "arm,cci-400-pmu",
 		.data	= NULL,
 	},
 	{
 		.compatible = "arm,cci-400-pmu,r0",
-		.data	= &cci_pmu_models[CCI_REV_R0],
+		.data	= &cci_pmu_models[CCI400_R0],
 	},
 	{
 		.compatible = "arm,cci-400-pmu,r1",
-		.data	= &cci_pmu_models[CCI_REV_R1],
+		.data	= &cci_pmu_models[CCI400_R1],
 	},
+#endif
 	{},
 };
 
@@ -1145,14 +1172,14 @@ static int __init cci_platform_init(void)
 	return platform_driver_register(&cci_platform_driver);
 }
 
-#else /* !CONFIG_ARM_CCI400_PMU */
+#else /* !CONFIG_ARM_CCI_PMU */
 
 static int __init cci_platform_init(void)
 {
 	return 0;
 }
 
-#endif /* CONFIG_ARM_CCI400_PMU */
+#endif /* CONFIG_ARM_CCI_PMU */
 
 #ifdef CONFIG_ARM_CCI400_PORT_CTRL
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

Rename CCI400 specific defintions from CCI_xxx to CCI400_xxx.

Introduce generic ARM_CCI_PMU to cover common code for handling
the CCI PMU.

Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
---
 drivers/bus/Kconfig   |    5 ++
 drivers/bus/arm-cci.c |  157 +++++++++++++++++++++++++++++--------------------
 2 files changed, 97 insertions(+), 65 deletions(-)

diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index a1d4af6..be66b7c 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -7,6 +7,10 @@ menu "Bus devices"
 config ARM_CCI
 	bool
 
+config ARM_CCI_PMU
+	bool
+	select ARM_CCI
+
 config ARM_CCI400_COMMON
 	bool
 	select ARM_CCI
@@ -17,6 +21,7 @@ config ARM_CCI400_PMU
 	depends on ARM || ARM64
 	depends on HW_PERF_EVENTS
 	select ARM_CCI400_COMMON
+	select ARM_CCI_PMU
 	help
 	  Support for PMU events monitoring on the ARM CCI cache coherent
 	  interconnect.
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 4b9a8d3..2b43cea 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -55,9 +55,9 @@ static const struct of_device_id arm_cci_matches[] = {
 	{},
 };
 
-#ifdef CONFIG_ARM_CCI400_PMU
+#ifdef CONFIG_ARM_CCI_PMU
 
-#define DRIVER_NAME		"CCI-400"
+#define DRIVER_NAME		"ARM-CCI"
 #define DRIVER_NAME_PMU		DRIVER_NAME " PMU"
 
 #define CCI_PMCR		0x0100
@@ -82,10 +82,6 @@ static const struct of_device_id arm_cci_matches[] = {
 #define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
 #define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
 
-#define CCI_PMU_EVENT_MASK		0xffUL
-#define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
-#define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
-
 #define CCI_PMU_MAX_HW_CNTRS(model) \
 	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
 
@@ -144,19 +140,29 @@ struct cci_pmu {
 
 #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
 
+enum cci_models {
+#ifdef CONFIG_ARM_CCI400_PMU
+	CCI400_R0,
+	CCI400_R1,
+#endif
+	CCI_MODEL_MAX
+};
+
+/* CCI400 PMU Specific definitions */
+
+#ifdef CONFIG_ARM_CCI400_PMU
+
 /* Port ids */
-#define CCI_PORT_S0	0
-#define CCI_PORT_S1	1
-#define CCI_PORT_S2	2
-#define CCI_PORT_S3	3
-#define CCI_PORT_S4	4
-#define CCI_PORT_M0	5
-#define CCI_PORT_M1	6
-#define CCI_PORT_M2	7
-
-#define CCI_REV_R0		0
-#define CCI_REV_R1		1
-#define CCI_REV_R1_PX		5
+#define CCI400_PORT_S0		0
+#define CCI400_PORT_S1		1
+#define CCI400_PORT_S2		2
+#define CCI400_PORT_S3		3
+#define CCI400_PORT_S4		4
+#define CCI400_PORT_M0		5
+#define CCI400_PORT_M1		6
+#define CCI400_PORT_M2		7
+
+#define CCI400_R1_PX		5
 
 /*
  * Instead of an event id to monitor CCI cycles, a dedicated counter is
@@ -164,11 +170,11 @@ struct cci_pmu {
  * make use of this event in hardware.
  */
 enum cci400_perf_events {
-	CCI_PMU_CYCLES = 0xff
+	CCI400_PMU_CYCLES = 0xff
 };
 
-#define CCI_PMU_CYCLE_CNTR_IDX		0
-#define CCI_PMU_CNTR0_IDX		1
+#define CCI400_PMU_CYCLE_CNTR_IDX	0
+#define CCI400_PMU_CNTR0_IDX		1
 
 /*
  * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
@@ -182,15 +188,26 @@ enum cci400_perf_events {
  * the different revisions and are used to validate the event to be monitored.
  */
 
-#define CCI_REV_R0_SLAVE_PORT_MIN_EV	0x00
-#define CCI_REV_R0_SLAVE_PORT_MAX_EV	0x13
-#define CCI_REV_R0_MASTER_PORT_MIN_EV	0x14
-#define CCI_REV_R0_MASTER_PORT_MAX_EV	0x1a
-
-#define CCI_REV_R1_SLAVE_PORT_MIN_EV	0x00
-#define CCI_REV_R1_SLAVE_PORT_MAX_EV	0x14
-#define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
-#define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
+#define CCI400_PMU_EVENT_MASK		0xffUL
+#define CCI400_PMU_EVENT_SOURCE_SHIFT	5
+#define CCI400_PMU_EVENT_SOURCE_MASK	0x7
+#define CCI400_PMU_EVENT_CODE_SHIFT	0
+#define CCI400_PMU_EVENT_CODE_MASK	0x1f
+#define CCI400_PMU_EVENT_SOURCE(event) \
+	((event >> CCI400_PMU_EVENT_SOURCE_SHIFT) & \
+			CCI400_PMU_EVENT_SOURCE_MASK)
+#define CCI400_PMU_EVENT_CODE(event) \
+	((event >> CCI400_PMU_EVENT_CODE_SHIFT) & CCI400_PMU_EVENT_CODE_MASK)
+
+#define CCI400_R0_SLAVE_PORT_MIN_EV	0x00
+#define CCI400_R0_SLAVE_PORT_MAX_EV	0x13
+#define CCI400_R0_MASTER_PORT_MIN_EV	0x14
+#define CCI400_R0_MASTER_PORT_MAX_EV	0x1a
+
+#define CCI400_R1_SLAVE_PORT_MIN_EV	0x00
+#define CCI400_R1_SLAVE_PORT_MAX_EV	0x14
+#define CCI400_R1_MASTER_PORT_MIN_EV	0x00
+#define CCI400_R1_MASTER_PORT_MAX_EV	0x11
 
 static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 				struct cci_pmu_hw_events *hw,
@@ -199,14 +216,14 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 	int idx;
 
 	/* cycles event idx is fixed */
-	if (cci_event == CCI_PMU_CYCLES) {
-		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+	if (cci_event == CCI400_PMU_CYCLES) {
+		if (test_and_set_bit(CCI400_PMU_CYCLE_CNTR_IDX, hw->used_mask))
 			return -EAGAIN;
 
-		return CCI_PMU_CYCLE_CNTR_IDX;
+		return CCI400_PMU_CYCLE_CNTR_IDX;
 	}
 
-	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+	for (idx = CCI400_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
 		if (!test_and_set_bit(idx, hw->used_mask))
 			return idx;
 
@@ -216,28 +233,28 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 
 static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
-	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
-	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
+	u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event);
+	u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event);
 	int if_type;
 
-	if (hw_event & ~CCI_PMU_EVENT_MASK)
+	if (hw_event & ~CCI400_PMU_EVENT_MASK)
 		return -ENOENT;
 
-	if (hw_event == CCI_PMU_CYCLES)
+	if (hw_event == CCI400_PMU_CYCLES)
 		return hw_event;
 
 	switch (ev_source) {
-	case CCI_PORT_S0:
-	case CCI_PORT_S1:
-	case CCI_PORT_S2:
-	case CCI_PORT_S3:
-	case CCI_PORT_S4:
+	case CCI400_PORT_S0:
+	case CCI400_PORT_S1:
+	case CCI400_PORT_S2:
+	case CCI400_PORT_S3:
+	case CCI400_PORT_S4:
 		/* Slave Interface */
 		if_type = CCI_IF_SLAVE;
 		break;
-	case CCI_PORT_M0:
-	case CCI_PORT_M1:
-	case CCI_PORT_M2:
+	case CCI400_PORT_M0:
+	case CCI400_PORT_M1:
+	case CCI400_PORT_M2:
 		/* Master Interface */
 		if_type = CCI_IF_MASTER;
 		break;
@@ -252,24 +269,30 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev
 	return -ENOENT;
 }
 
-static int probe_cci_revision(void)
+static int probe_cci400_revision(void)
 {
 	int rev;
 	rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK;
 	rev >>= CCI_PID2_REV_SHIFT;
 
-	if (rev < CCI_REV_R1_PX)
-		return CCI_REV_R0;
+	if (rev < CCI400_R1_PX)
+		return CCI400_R0;
 	else
-		return CCI_REV_R1;
+		return CCI400_R1;
 }
 
 static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
 {
 	if (platform_has_secure_cci_access())
-		return &cci_pmu_models[probe_cci_revision()];
+		return &cci_pmu_models[probe_cci400_revision()];
+	return NULL;
+}
+#else	/* !CONFIG_ARM_CCI400_PMU */
+static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
+{
 	return NULL;
 }
+#endif	/* CONFIG_ARM_CCI400_PMU */
 
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
@@ -920,57 +943,61 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 }
 
 static struct cci_pmu_model cci_pmu_models[] = {
-	[CCI_REV_R0] = {
+#ifdef CONFIG_ARM_CCI400_PMU
+	[CCI400_R0] = {
 		.name = "CCI_400",
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
-				CCI_REV_R0_SLAVE_PORT_MIN_EV,
-				CCI_REV_R0_SLAVE_PORT_MAX_EV,
+				CCI400_R0_SLAVE_PORT_MIN_EV,
+				CCI400_R0_SLAVE_PORT_MAX_EV,
 			},
 			[CCI_IF_MASTER] = {
-				CCI_REV_R0_MASTER_PORT_MIN_EV,
-				CCI_REV_R0_MASTER_PORT_MAX_EV,
+				CCI400_R0_MASTER_PORT_MIN_EV,
+				CCI400_R0_MASTER_PORT_MAX_EV,
 			},
 		},
 		.validate_hw_event = cci400_validate_hw_event,
 		.get_event_idx = cci400_get_event_idx,
 	},
-	[CCI_REV_R1] = {
+	[CCI400_R1] = {
 		.name = "CCI_400_r1",
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
-				CCI_REV_R1_SLAVE_PORT_MIN_EV,
-				CCI_REV_R1_SLAVE_PORT_MAX_EV,
+				CCI400_R1_SLAVE_PORT_MIN_EV,
+				CCI400_R1_SLAVE_PORT_MAX_EV,
 			},
 			[CCI_IF_MASTER] = {
-				CCI_REV_R1_MASTER_PORT_MIN_EV,
-				CCI_REV_R1_MASTER_PORT_MAX_EV,
+				CCI400_R1_MASTER_PORT_MIN_EV,
+				CCI400_R1_MASTER_PORT_MAX_EV,
 			},
 		},
 		.validate_hw_event = cci400_validate_hw_event,
 		.get_event_idx = cci400_get_event_idx,
 	},
+#endif
 };
 
 static const struct of_device_id arm_cci_pmu_matches[] = {
+#ifdef CONFIG_ARM_CCI400_PMU
 	{
 		.compatible = "arm,cci-400-pmu",
 		.data	= NULL,
 	},
 	{
 		.compatible = "arm,cci-400-pmu,r0",
-		.data	= &cci_pmu_models[CCI_REV_R0],
+		.data	= &cci_pmu_models[CCI400_R0],
 	},
 	{
 		.compatible = "arm,cci-400-pmu,r1",
-		.data	= &cci_pmu_models[CCI_REV_R1],
+		.data	= &cci_pmu_models[CCI400_R1],
 	},
+#endif
 	{},
 };
 
@@ -1145,14 +1172,14 @@ static int __init cci_platform_init(void)
 	return platform_driver_register(&cci_platform_driver);
 }
 
-#else /* !CONFIG_ARM_CCI400_PMU */
+#else /* !CONFIG_ARM_CCI_PMU */
 
 static int __init cci_platform_init(void)
 {
 	return 0;
 }
 
-#endif /* CONFIG_ARM_CCI400_PMU */
+#endif /* CONFIG_ARM_CCI_PMU */
 
 #ifdef CONFIG_ARM_CCI400_PORT_CTRL
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Rename CCI400 specific defintions from CCI_xxx to CCI400_xxx.

Introduce generic ARM_CCI_PMU to cover common code for handling
the CCI PMU.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Punit Agrawal <punit.agrawal@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/Kconfig   |    5 ++
 drivers/bus/arm-cci.c |  157 +++++++++++++++++++++++++++++--------------------
 2 files changed, 97 insertions(+), 65 deletions(-)

diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index a1d4af6..be66b7c 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -7,6 +7,10 @@ menu "Bus devices"
 config ARM_CCI
 	bool
 
+config ARM_CCI_PMU
+	bool
+	select ARM_CCI
+
 config ARM_CCI400_COMMON
 	bool
 	select ARM_CCI
@@ -17,6 +21,7 @@ config ARM_CCI400_PMU
 	depends on ARM || ARM64
 	depends on HW_PERF_EVENTS
 	select ARM_CCI400_COMMON
+	select ARM_CCI_PMU
 	help
 	  Support for PMU events monitoring on the ARM CCI cache coherent
 	  interconnect.
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 4b9a8d3..2b43cea 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -55,9 +55,9 @@ static const struct of_device_id arm_cci_matches[] = {
 	{},
 };
 
-#ifdef CONFIG_ARM_CCI400_PMU
+#ifdef CONFIG_ARM_CCI_PMU
 
-#define DRIVER_NAME		"CCI-400"
+#define DRIVER_NAME		"ARM-CCI"
 #define DRIVER_NAME_PMU		DRIVER_NAME " PMU"
 
 #define CCI_PMCR		0x0100
@@ -82,10 +82,6 @@ static const struct of_device_id arm_cci_matches[] = {
 #define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
 #define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
 
-#define CCI_PMU_EVENT_MASK		0xffUL
-#define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
-#define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
-
 #define CCI_PMU_MAX_HW_CNTRS(model) \
 	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
 
@@ -144,19 +140,29 @@ struct cci_pmu {
 
 #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
 
+enum cci_models {
+#ifdef CONFIG_ARM_CCI400_PMU
+	CCI400_R0,
+	CCI400_R1,
+#endif
+	CCI_MODEL_MAX
+};
+
+/* CCI400 PMU Specific definitions */
+
+#ifdef CONFIG_ARM_CCI400_PMU
+
 /* Port ids */
-#define CCI_PORT_S0	0
-#define CCI_PORT_S1	1
-#define CCI_PORT_S2	2
-#define CCI_PORT_S3	3
-#define CCI_PORT_S4	4
-#define CCI_PORT_M0	5
-#define CCI_PORT_M1	6
-#define CCI_PORT_M2	7
-
-#define CCI_REV_R0		0
-#define CCI_REV_R1		1
-#define CCI_REV_R1_PX		5
+#define CCI400_PORT_S0		0
+#define CCI400_PORT_S1		1
+#define CCI400_PORT_S2		2
+#define CCI400_PORT_S3		3
+#define CCI400_PORT_S4		4
+#define CCI400_PORT_M0		5
+#define CCI400_PORT_M1		6
+#define CCI400_PORT_M2		7
+
+#define CCI400_R1_PX		5
 
 /*
  * Instead of an event id to monitor CCI cycles, a dedicated counter is
@@ -164,11 +170,11 @@ struct cci_pmu {
  * make use of this event in hardware.
  */
 enum cci400_perf_events {
-	CCI_PMU_CYCLES = 0xff
+	CCI400_PMU_CYCLES = 0xff
 };
 
-#define CCI_PMU_CYCLE_CNTR_IDX		0
-#define CCI_PMU_CNTR0_IDX		1
+#define CCI400_PMU_CYCLE_CNTR_IDX	0
+#define CCI400_PMU_CNTR0_IDX		1
 
 /*
  * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
@@ -182,15 +188,26 @@ enum cci400_perf_events {
  * the different revisions and are used to validate the event to be monitored.
  */
 
-#define CCI_REV_R0_SLAVE_PORT_MIN_EV	0x00
-#define CCI_REV_R0_SLAVE_PORT_MAX_EV	0x13
-#define CCI_REV_R0_MASTER_PORT_MIN_EV	0x14
-#define CCI_REV_R0_MASTER_PORT_MAX_EV	0x1a
-
-#define CCI_REV_R1_SLAVE_PORT_MIN_EV	0x00
-#define CCI_REV_R1_SLAVE_PORT_MAX_EV	0x14
-#define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
-#define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
+#define CCI400_PMU_EVENT_MASK		0xffUL
+#define CCI400_PMU_EVENT_SOURCE_SHIFT	5
+#define CCI400_PMU_EVENT_SOURCE_MASK	0x7
+#define CCI400_PMU_EVENT_CODE_SHIFT	0
+#define CCI400_PMU_EVENT_CODE_MASK	0x1f
+#define CCI400_PMU_EVENT_SOURCE(event) \
+	((event >> CCI400_PMU_EVENT_SOURCE_SHIFT) & \
+			CCI400_PMU_EVENT_SOURCE_MASK)
+#define CCI400_PMU_EVENT_CODE(event) \
+	((event >> CCI400_PMU_EVENT_CODE_SHIFT) & CCI400_PMU_EVENT_CODE_MASK)
+
+#define CCI400_R0_SLAVE_PORT_MIN_EV	0x00
+#define CCI400_R0_SLAVE_PORT_MAX_EV	0x13
+#define CCI400_R0_MASTER_PORT_MIN_EV	0x14
+#define CCI400_R0_MASTER_PORT_MAX_EV	0x1a
+
+#define CCI400_R1_SLAVE_PORT_MIN_EV	0x00
+#define CCI400_R1_SLAVE_PORT_MAX_EV	0x14
+#define CCI400_R1_MASTER_PORT_MIN_EV	0x00
+#define CCI400_R1_MASTER_PORT_MAX_EV	0x11
 
 static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 				struct cci_pmu_hw_events *hw,
@@ -199,14 +216,14 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 	int idx;
 
 	/* cycles event idx is fixed */
-	if (cci_event == CCI_PMU_CYCLES) {
-		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+	if (cci_event == CCI400_PMU_CYCLES) {
+		if (test_and_set_bit(CCI400_PMU_CYCLE_CNTR_IDX, hw->used_mask))
 			return -EAGAIN;
 
-		return CCI_PMU_CYCLE_CNTR_IDX;
+		return CCI400_PMU_CYCLE_CNTR_IDX;
 	}
 
-	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+	for (idx = CCI400_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
 		if (!test_and_set_bit(idx, hw->used_mask))
 			return idx;
 
@@ -216,28 +233,28 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 
 static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
-	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
-	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
+	u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event);
+	u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event);
 	int if_type;
 
-	if (hw_event & ~CCI_PMU_EVENT_MASK)
+	if (hw_event & ~CCI400_PMU_EVENT_MASK)
 		return -ENOENT;
 
-	if (hw_event == CCI_PMU_CYCLES)
+	if (hw_event == CCI400_PMU_CYCLES)
 		return hw_event;
 
 	switch (ev_source) {
-	case CCI_PORT_S0:
-	case CCI_PORT_S1:
-	case CCI_PORT_S2:
-	case CCI_PORT_S3:
-	case CCI_PORT_S4:
+	case CCI400_PORT_S0:
+	case CCI400_PORT_S1:
+	case CCI400_PORT_S2:
+	case CCI400_PORT_S3:
+	case CCI400_PORT_S4:
 		/* Slave Interface */
 		if_type = CCI_IF_SLAVE;
 		break;
-	case CCI_PORT_M0:
-	case CCI_PORT_M1:
-	case CCI_PORT_M2:
+	case CCI400_PORT_M0:
+	case CCI400_PORT_M1:
+	case CCI400_PORT_M2:
 		/* Master Interface */
 		if_type = CCI_IF_MASTER;
 		break;
@@ -252,24 +269,30 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev
 	return -ENOENT;
 }
 
-static int probe_cci_revision(void)
+static int probe_cci400_revision(void)
 {
 	int rev;
 	rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK;
 	rev >>= CCI_PID2_REV_SHIFT;
 
-	if (rev < CCI_REV_R1_PX)
-		return CCI_REV_R0;
+	if (rev < CCI400_R1_PX)
+		return CCI400_R0;
 	else
-		return CCI_REV_R1;
+		return CCI400_R1;
 }
 
 static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
 {
 	if (platform_has_secure_cci_access())
-		return &cci_pmu_models[probe_cci_revision()];
+		return &cci_pmu_models[probe_cci400_revision()];
+	return NULL;
+}
+#else	/* !CONFIG_ARM_CCI400_PMU */
+static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
+{
 	return NULL;
 }
+#endif	/* CONFIG_ARM_CCI400_PMU */
 
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
@@ -920,57 +943,61 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
 }
 
 static struct cci_pmu_model cci_pmu_models[] = {
-	[CCI_REV_R0] = {
+#ifdef CONFIG_ARM_CCI400_PMU
+	[CCI400_R0] = {
 		.name = "CCI_400",
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
-				CCI_REV_R0_SLAVE_PORT_MIN_EV,
-				CCI_REV_R0_SLAVE_PORT_MAX_EV,
+				CCI400_R0_SLAVE_PORT_MIN_EV,
+				CCI400_R0_SLAVE_PORT_MAX_EV,
 			},
 			[CCI_IF_MASTER] = {
-				CCI_REV_R0_MASTER_PORT_MIN_EV,
-				CCI_REV_R0_MASTER_PORT_MAX_EV,
+				CCI400_R0_MASTER_PORT_MIN_EV,
+				CCI400_R0_MASTER_PORT_MAX_EV,
 			},
 		},
 		.validate_hw_event = cci400_validate_hw_event,
 		.get_event_idx = cci400_get_event_idx,
 	},
-	[CCI_REV_R1] = {
+	[CCI400_R1] = {
 		.name = "CCI_400_r1",
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
-				CCI_REV_R1_SLAVE_PORT_MIN_EV,
-				CCI_REV_R1_SLAVE_PORT_MAX_EV,
+				CCI400_R1_SLAVE_PORT_MIN_EV,
+				CCI400_R1_SLAVE_PORT_MAX_EV,
 			},
 			[CCI_IF_MASTER] = {
-				CCI_REV_R1_MASTER_PORT_MIN_EV,
-				CCI_REV_R1_MASTER_PORT_MAX_EV,
+				CCI400_R1_MASTER_PORT_MIN_EV,
+				CCI400_R1_MASTER_PORT_MAX_EV,
 			},
 		},
 		.validate_hw_event = cci400_validate_hw_event,
 		.get_event_idx = cci400_get_event_idx,
 	},
+#endif
 };
 
 static const struct of_device_id arm_cci_pmu_matches[] = {
+#ifdef CONFIG_ARM_CCI400_PMU
 	{
 		.compatible = "arm,cci-400-pmu",
 		.data	= NULL,
 	},
 	{
 		.compatible = "arm,cci-400-pmu,r0",
-		.data	= &cci_pmu_models[CCI_REV_R0],
+		.data	= &cci_pmu_models[CCI400_R0],
 	},
 	{
 		.compatible = "arm,cci-400-pmu,r1",
-		.data	= &cci_pmu_models[CCI_REV_R1],
+		.data	= &cci_pmu_models[CCI400_R1],
 	},
+#endif
 	{},
 };
 
@@ -1145,14 +1172,14 @@ static int __init cci_platform_init(void)
 	return platform_driver_register(&cci_platform_driver);
 }
 
-#else /* !CONFIG_ARM_CCI400_PMU */
+#else /* !CONFIG_ARM_CCI_PMU */
 
 static int __init cci_platform_init(void)
 {
 	return 0;
 }
 
-#endif /* CONFIG_ARM_CCI400_PMU */
+#endif /* CONFIG_ARM_CCI_PMU */
 
 #ifdef CONFIG_ARM_CCI400_PORT_CTRL
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 6/7] arm-cci: Add CCI-500 PMU support
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

CCI-500 provides 8 event counters which can count any of the
supported events independently. The PMU event id is a 9-bit
value made of two parts.
	bits [8:5] - Source port
			0x0-0x6 Slave Ports
			0x8-0xD Master Ports
			0xf     Global Events to CCI
			0x7,0xe Reserved
	bits [0:4] - Event code (specific to each type of port)

The generic CCI-500 controlling interface remains the same with CCI-400.
However there are some differences in the PMU event counters.
 - No cycle counter
 - Upto 8 counters(4 in CCI-400)
 - Each counter area is 64K(4K in CCI400)
 - The counter0 starts at offset 0x10000 from the base of CCI

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: devicetree@vger.kernel.org
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 Documentation/devicetree/bindings/arm/cci.txt |    4 +-
 drivers/bus/Kconfig                           |   12 +++
 drivers/bus/arm-cci.c                         |  133 +++++++++++++++++++++++++
 3 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt
index 3c5c631..aef1d20 100644
--- a/Documentation/devicetree/bindings/arm/cci.txt
+++ b/Documentation/devicetree/bindings/arm/cci.txt
@@ -31,8 +31,9 @@ specific to ARM.
 	- compatible
 		Usage: required
 		Value type: <string>
-		Definition: must be set to
+		Definition: must contain one of the following:
 			    "arm,cci-400"
+			    "arm,cci-500"
 
 	- reg
 		Usage: required
@@ -99,6 +100,7 @@ specific to ARM.
 				 "arm,cci-400-pmu,r1"
 				 "arm,cci-400-pmu"  - DEPRECATED, permitted only where OS has
 						      secure acces to CCI registers
+				 "arm,cci-500-pmu,r0"
 		- reg:
 			Usage: required
 			Value type: Integer cells. A register entry, expressed
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index be66b7c..5fb3150 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -36,6 +36,18 @@ config ARM_CCI400_PORT_CTRL
 	  Low level power management driver for CCI400 cache coherent
 	  interconnect for ARM platforms.
 
+config ARM_CCI500_PMU
+	bool "ARM CCI500 PMU support"
+	default y
+	depends on ARM || ARM64
+	depends on HW_PERF_EVENTS
+	select ARM_CCI_PMU
+	help
+	  Support for PMU events monitoring on the ARM CCI-500 cache coherent
+	  interconnect.
+
+	  If unsure, say Y
+
 config ARM_CCN
 	bool "ARM CCN driver support"
 	depends on ARM || ARM64
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 2b43cea..e12ddba 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -52,6 +52,9 @@ static const struct of_device_id arm_cci_matches[] = {
 #ifdef CONFIG_ARM_CCI400_COMMON
 	{.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA },
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	{ .compatible = "arm,cci-500", },
+#endif
 	{},
 };
 
@@ -89,6 +92,9 @@ static const struct of_device_id arm_cci_matches[] = {
 enum {
 	CCI_IF_SLAVE,
 	CCI_IF_MASTER,
+#ifdef CONFIG_ARM_CCI500_PMU
+	CCI_IF_GLOBAL,
+#endif
 	CCI_IF_MAX,
 };
 
@@ -145,6 +151,9 @@ enum cci_models {
 	CCI400_R0,
 	CCI400_R1,
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	CCI500_R0,
+#endif
 	CCI_MODEL_MAX
 };
 
@@ -294,6 +303,101 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
 }
 #endif	/* CONFIG_ARM_CCI400_PMU */
 
+#ifdef CONFIG_ARM_CCI500_PMU
+
+/*
+ * CCI500 provides 8 independent event counters that can count
+ * any of the events available.
+ *
+ * CCI500 PMU event id is an 9-bit value made of two parts.
+ *	 bits [8:5] - Source for the event
+ *		      0x0-0x6 - Slave interfaces
+ *		      0x8-0xD - Master interfaces
+ *		      0xf     - Global Events
+ *		      0x7,0xe - Reserved
+ *
+ *	 bits [4:0] - Event code (specific to type of interface)
+ */
+
+/* Port ids */
+#define CCI500_PORT_S0			0x0
+#define CCI500_PORT_S1			0x1
+#define CCI500_PORT_S2			0x2
+#define CCI500_PORT_S3			0x3
+#define CCI500_PORT_S4			0x4
+#define CCI500_PORT_S5			0x5
+#define CCI500_PORT_S6			0x6
+
+#define CCI500_PORT_M0			0x8
+#define CCI500_PORT_M1			0x9
+#define CCI500_PORT_M2			0xa
+#define CCI500_PORT_M3			0xb
+#define CCI500_PORT_M4			0xc
+#define CCI500_PORT_M5			0xd
+
+#define CCI500_PORT_GLOBAL 		0xf
+
+#define CCI500_PMU_EVENT_MASK		0x1ffUL
+#define CCI500_PMU_EVENT_SOURCE_SHIFT	0x5
+#define CCI500_PMU_EVENT_SOURCE_MASK	0xf
+#define CCI500_PMU_EVENT_CODE_SHIFT	0x0
+#define CCI500_PMU_EVENT_CODE_MASK	0x1f
+
+#define CCI500_PMU_EVENT_SOURCE(event)	\
+	((event >> CCI500_PMU_EVENT_SOURCE_SHIFT) & CCI500_PMU_EVENT_SOURCE_MASK)
+#define CCI500_PMU_EVENT_CODE(event)	\
+	((event >> CCI500_PMU_EVENT_CODE_SHIFT) & CCI500_PMU_EVENT_CODE_MASK)
+
+#define CCI500_SLAVE_PORT_MIN_EV	0x00
+#define CCI500_SLAVE_PORT_MAX_EV	0x1f
+#define CCI500_MASTER_PORT_MIN_EV	0x00
+#define CCI500_MASTER_PORT_MAX_EV	0x06
+#define CCI500_GLOBAL_PORT_MIN_EV	0x00
+#define CCI500_GLOBAL_PORT_MAX_EV	0x0f
+
+static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
+					unsigned long hw_event)
+{
+	u32 ev_source = CCI500_PMU_EVENT_SOURCE(hw_event);
+	u32 ev_code = CCI500_PMU_EVENT_CODE(hw_event);
+	int if_type;
+
+	if (hw_event & ~CCI500_PMU_EVENT_MASK)
+		return -ENOENT;
+
+	switch (ev_source) {
+	case CCI500_PORT_S0:
+	case CCI500_PORT_S1:
+	case CCI500_PORT_S2:
+	case CCI500_PORT_S3:
+	case CCI500_PORT_S4:
+	case CCI500_PORT_S5:
+	case CCI500_PORT_S6:
+		if_type = CCI_IF_SLAVE;
+		break;
+	case CCI500_PORT_M0:
+	case CCI500_PORT_M1:
+	case CCI500_PORT_M2:
+	case CCI500_PORT_M3:
+	case CCI500_PORT_M4:
+	case CCI500_PORT_M5:
+		if_type = CCI_IF_MASTER;
+		break;
+	case CCI500_PORT_GLOBAL:
+		if_type = CCI_IF_GLOBAL;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+		ev_code <= cci_pmu->model->event_ranges[if_type].max)
+		return hw_event;
+
+	return -ENOENT;
+}
+#endif	/* CONFIG_ARM_CCI500_PMU */
+
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
 	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
@@ -981,6 +1085,29 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.get_event_idx = cci400_get_event_idx,
 	},
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	[CCI500_R0] = {
+		.name = "CCI_500",
+		.fixed_hw_cntrs = 0,
+		.num_hw_cntrs = 8,
+		.cntr_size = SZ_64K,
+		.event_ranges = {
+			[CCI_IF_SLAVE] = {
+				CCI500_SLAVE_PORT_MIN_EV,
+				CCI500_SLAVE_PORT_MAX_EV,
+			},
+			[CCI_IF_MASTER] = {
+				CCI500_MASTER_PORT_MIN_EV,
+				CCI500_MASTER_PORT_MAX_EV,
+			},
+			[CCI_IF_GLOBAL] = {
+				CCI500_GLOBAL_PORT_MIN_EV,
+				CCI500_GLOBAL_PORT_MAX_EV,
+			},
+		},
+		.validate_hw_event = cci500_validate_hw_event,
+	},
+#endif
 };
 
 static const struct of_device_id arm_cci_pmu_matches[] = {
@@ -998,6 +1125,12 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
 		.data	= &cci_pmu_models[CCI400_R1],
 	},
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	{
+		.compatible = "arm,cci-500-pmu,r0",
+		.data = &cci_pmu_models[CCI500_R0],
+	},
+#endif
 	{},
 };
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 6/7] arm-cci: Add CCI-500 PMU support
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

CCI-500 provides 8 event counters which can count any of the
supported events independently. The PMU event id is a 9-bit
value made of two parts.
	bits [8:5] - Source port
			0x0-0x6 Slave Ports
			0x8-0xD Master Ports
			0xf     Global Events to CCI
			0x7,0xe Reserved
	bits [0:4] - Event code (specific to each type of port)

The generic CCI-500 controlling interface remains the same with CCI-400.
However there are some differences in the PMU event counters.
 - No cycle counter
 - Upto 8 counters(4 in CCI-400)
 - Each counter area is 64K(4K in CCI400)
 - The counter0 starts at offset 0x10000 from the base of CCI

Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
---
 Documentation/devicetree/bindings/arm/cci.txt |    4 +-
 drivers/bus/Kconfig                           |   12 +++
 drivers/bus/arm-cci.c                         |  133 +++++++++++++++++++++++++
 3 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt
index 3c5c631..aef1d20 100644
--- a/Documentation/devicetree/bindings/arm/cci.txt
+++ b/Documentation/devicetree/bindings/arm/cci.txt
@@ -31,8 +31,9 @@ specific to ARM.
 	- compatible
 		Usage: required
 		Value type: <string>
-		Definition: must be set to
+		Definition: must contain one of the following:
 			    "arm,cci-400"
+			    "arm,cci-500"
 
 	- reg
 		Usage: required
@@ -99,6 +100,7 @@ specific to ARM.
 				 "arm,cci-400-pmu,r1"
 				 "arm,cci-400-pmu"  - DEPRECATED, permitted only where OS has
 						      secure acces to CCI registers
+				 "arm,cci-500-pmu,r0"
 		- reg:
 			Usage: required
 			Value type: Integer cells. A register entry, expressed
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index be66b7c..5fb3150 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -36,6 +36,18 @@ config ARM_CCI400_PORT_CTRL
 	  Low level power management driver for CCI400 cache coherent
 	  interconnect for ARM platforms.
 
+config ARM_CCI500_PMU
+	bool "ARM CCI500 PMU support"
+	default y
+	depends on ARM || ARM64
+	depends on HW_PERF_EVENTS
+	select ARM_CCI_PMU
+	help
+	  Support for PMU events monitoring on the ARM CCI-500 cache coherent
+	  interconnect.
+
+	  If unsure, say Y
+
 config ARM_CCN
 	bool "ARM CCN driver support"
 	depends on ARM || ARM64
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 2b43cea..e12ddba 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -52,6 +52,9 @@ static const struct of_device_id arm_cci_matches[] = {
 #ifdef CONFIG_ARM_CCI400_COMMON
 	{.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA },
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	{ .compatible = "arm,cci-500", },
+#endif
 	{},
 };
 
@@ -89,6 +92,9 @@ static const struct of_device_id arm_cci_matches[] = {
 enum {
 	CCI_IF_SLAVE,
 	CCI_IF_MASTER,
+#ifdef CONFIG_ARM_CCI500_PMU
+	CCI_IF_GLOBAL,
+#endif
 	CCI_IF_MAX,
 };
 
@@ -145,6 +151,9 @@ enum cci_models {
 	CCI400_R0,
 	CCI400_R1,
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	CCI500_R0,
+#endif
 	CCI_MODEL_MAX
 };
 
@@ -294,6 +303,101 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
 }
 #endif	/* CONFIG_ARM_CCI400_PMU */
 
+#ifdef CONFIG_ARM_CCI500_PMU
+
+/*
+ * CCI500 provides 8 independent event counters that can count
+ * any of the events available.
+ *
+ * CCI500 PMU event id is an 9-bit value made of two parts.
+ *	 bits [8:5] - Source for the event
+ *		      0x0-0x6 - Slave interfaces
+ *		      0x8-0xD - Master interfaces
+ *		      0xf     - Global Events
+ *		      0x7,0xe - Reserved
+ *
+ *	 bits [4:0] - Event code (specific to type of interface)
+ */
+
+/* Port ids */
+#define CCI500_PORT_S0			0x0
+#define CCI500_PORT_S1			0x1
+#define CCI500_PORT_S2			0x2
+#define CCI500_PORT_S3			0x3
+#define CCI500_PORT_S4			0x4
+#define CCI500_PORT_S5			0x5
+#define CCI500_PORT_S6			0x6
+
+#define CCI500_PORT_M0			0x8
+#define CCI500_PORT_M1			0x9
+#define CCI500_PORT_M2			0xa
+#define CCI500_PORT_M3			0xb
+#define CCI500_PORT_M4			0xc
+#define CCI500_PORT_M5			0xd
+
+#define CCI500_PORT_GLOBAL 		0xf
+
+#define CCI500_PMU_EVENT_MASK		0x1ffUL
+#define CCI500_PMU_EVENT_SOURCE_SHIFT	0x5
+#define CCI500_PMU_EVENT_SOURCE_MASK	0xf
+#define CCI500_PMU_EVENT_CODE_SHIFT	0x0
+#define CCI500_PMU_EVENT_CODE_MASK	0x1f
+
+#define CCI500_PMU_EVENT_SOURCE(event)	\
+	((event >> CCI500_PMU_EVENT_SOURCE_SHIFT) & CCI500_PMU_EVENT_SOURCE_MASK)
+#define CCI500_PMU_EVENT_CODE(event)	\
+	((event >> CCI500_PMU_EVENT_CODE_SHIFT) & CCI500_PMU_EVENT_CODE_MASK)
+
+#define CCI500_SLAVE_PORT_MIN_EV	0x00
+#define CCI500_SLAVE_PORT_MAX_EV	0x1f
+#define CCI500_MASTER_PORT_MIN_EV	0x00
+#define CCI500_MASTER_PORT_MAX_EV	0x06
+#define CCI500_GLOBAL_PORT_MIN_EV	0x00
+#define CCI500_GLOBAL_PORT_MAX_EV	0x0f
+
+static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
+					unsigned long hw_event)
+{
+	u32 ev_source = CCI500_PMU_EVENT_SOURCE(hw_event);
+	u32 ev_code = CCI500_PMU_EVENT_CODE(hw_event);
+	int if_type;
+
+	if (hw_event & ~CCI500_PMU_EVENT_MASK)
+		return -ENOENT;
+
+	switch (ev_source) {
+	case CCI500_PORT_S0:
+	case CCI500_PORT_S1:
+	case CCI500_PORT_S2:
+	case CCI500_PORT_S3:
+	case CCI500_PORT_S4:
+	case CCI500_PORT_S5:
+	case CCI500_PORT_S6:
+		if_type = CCI_IF_SLAVE;
+		break;
+	case CCI500_PORT_M0:
+	case CCI500_PORT_M1:
+	case CCI500_PORT_M2:
+	case CCI500_PORT_M3:
+	case CCI500_PORT_M4:
+	case CCI500_PORT_M5:
+		if_type = CCI_IF_MASTER;
+		break;
+	case CCI500_PORT_GLOBAL:
+		if_type = CCI_IF_GLOBAL;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+		ev_code <= cci_pmu->model->event_ranges[if_type].max)
+		return hw_event;
+
+	return -ENOENT;
+}
+#endif	/* CONFIG_ARM_CCI500_PMU */
+
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
 	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
@@ -981,6 +1085,29 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.get_event_idx = cci400_get_event_idx,
 	},
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	[CCI500_R0] = {
+		.name = "CCI_500",
+		.fixed_hw_cntrs = 0,
+		.num_hw_cntrs = 8,
+		.cntr_size = SZ_64K,
+		.event_ranges = {
+			[CCI_IF_SLAVE] = {
+				CCI500_SLAVE_PORT_MIN_EV,
+				CCI500_SLAVE_PORT_MAX_EV,
+			},
+			[CCI_IF_MASTER] = {
+				CCI500_MASTER_PORT_MIN_EV,
+				CCI500_MASTER_PORT_MAX_EV,
+			},
+			[CCI_IF_GLOBAL] = {
+				CCI500_GLOBAL_PORT_MIN_EV,
+				CCI500_GLOBAL_PORT_MAX_EV,
+			},
+		},
+		.validate_hw_event = cci500_validate_hw_event,
+	},
+#endif
 };
 
 static const struct of_device_id arm_cci_pmu_matches[] = {
@@ -998,6 +1125,12 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
 		.data	= &cci_pmu_models[CCI400_R1],
 	},
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	{
+		.compatible = "arm,cci-500-pmu,r0",
+		.data = &cci_pmu_models[CCI500_R0],
+	},
+#endif
 	{},
 };
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 6/7] arm-cci: Add CCI-500 PMU support
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

CCI-500 provides 8 event counters which can count any of the
supported events independently. The PMU event id is a 9-bit
value made of two parts.
	bits [8:5] - Source port
			0x0-0x6 Slave Ports
			0x8-0xD Master Ports
			0xf     Global Events to CCI
			0x7,0xe Reserved
	bits [0:4] - Event code (specific to each type of port)

The generic CCI-500 controlling interface remains the same with CCI-400.
However there are some differences in the PMU event counters.
 - No cycle counter
 - Upto 8 counters(4 in CCI-400)
 - Each counter area is 64K(4K in CCI400)
 - The counter0 starts at offset 0x10000 from the base of CCI

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: devicetree at vger.kernel.org
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 Documentation/devicetree/bindings/arm/cci.txt |    4 +-
 drivers/bus/Kconfig                           |   12 +++
 drivers/bus/arm-cci.c                         |  133 +++++++++++++++++++++++++
 3 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt
index 3c5c631..aef1d20 100644
--- a/Documentation/devicetree/bindings/arm/cci.txt
+++ b/Documentation/devicetree/bindings/arm/cci.txt
@@ -31,8 +31,9 @@ specific to ARM.
 	- compatible
 		Usage: required
 		Value type: <string>
-		Definition: must be set to
+		Definition: must contain one of the following:
 			    "arm,cci-400"
+			    "arm,cci-500"
 
 	- reg
 		Usage: required
@@ -99,6 +100,7 @@ specific to ARM.
 				 "arm,cci-400-pmu,r1"
 				 "arm,cci-400-pmu"  - DEPRECATED, permitted only where OS has
 						      secure acces to CCI registers
+				 "arm,cci-500-pmu,r0"
 		- reg:
 			Usage: required
 			Value type: Integer cells. A register entry, expressed
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index be66b7c..5fb3150 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -36,6 +36,18 @@ config ARM_CCI400_PORT_CTRL
 	  Low level power management driver for CCI400 cache coherent
 	  interconnect for ARM platforms.
 
+config ARM_CCI500_PMU
+	bool "ARM CCI500 PMU support"
+	default y
+	depends on ARM || ARM64
+	depends on HW_PERF_EVENTS
+	select ARM_CCI_PMU
+	help
+	  Support for PMU events monitoring on the ARM CCI-500 cache coherent
+	  interconnect.
+
+	  If unsure, say Y
+
 config ARM_CCN
 	bool "ARM CCN driver support"
 	depends on ARM || ARM64
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 2b43cea..e12ddba 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -52,6 +52,9 @@ static const struct of_device_id arm_cci_matches[] = {
 #ifdef CONFIG_ARM_CCI400_COMMON
 	{.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA },
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	{ .compatible = "arm,cci-500", },
+#endif
 	{},
 };
 
@@ -89,6 +92,9 @@ static const struct of_device_id arm_cci_matches[] = {
 enum {
 	CCI_IF_SLAVE,
 	CCI_IF_MASTER,
+#ifdef CONFIG_ARM_CCI500_PMU
+	CCI_IF_GLOBAL,
+#endif
 	CCI_IF_MAX,
 };
 
@@ -145,6 +151,9 @@ enum cci_models {
 	CCI400_R0,
 	CCI400_R1,
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	CCI500_R0,
+#endif
 	CCI_MODEL_MAX
 };
 
@@ -294,6 +303,101 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
 }
 #endif	/* CONFIG_ARM_CCI400_PMU */
 
+#ifdef CONFIG_ARM_CCI500_PMU
+
+/*
+ * CCI500 provides 8 independent event counters that can count
+ * any of the events available.
+ *
+ * CCI500 PMU event id is an 9-bit value made of two parts.
+ *	 bits [8:5] - Source for the event
+ *		      0x0-0x6 - Slave interfaces
+ *		      0x8-0xD - Master interfaces
+ *		      0xf     - Global Events
+ *		      0x7,0xe - Reserved
+ *
+ *	 bits [4:0] - Event code (specific to type of interface)
+ */
+
+/* Port ids */
+#define CCI500_PORT_S0			0x0
+#define CCI500_PORT_S1			0x1
+#define CCI500_PORT_S2			0x2
+#define CCI500_PORT_S3			0x3
+#define CCI500_PORT_S4			0x4
+#define CCI500_PORT_S5			0x5
+#define CCI500_PORT_S6			0x6
+
+#define CCI500_PORT_M0			0x8
+#define CCI500_PORT_M1			0x9
+#define CCI500_PORT_M2			0xa
+#define CCI500_PORT_M3			0xb
+#define CCI500_PORT_M4			0xc
+#define CCI500_PORT_M5			0xd
+
+#define CCI500_PORT_GLOBAL 		0xf
+
+#define CCI500_PMU_EVENT_MASK		0x1ffUL
+#define CCI500_PMU_EVENT_SOURCE_SHIFT	0x5
+#define CCI500_PMU_EVENT_SOURCE_MASK	0xf
+#define CCI500_PMU_EVENT_CODE_SHIFT	0x0
+#define CCI500_PMU_EVENT_CODE_MASK	0x1f
+
+#define CCI500_PMU_EVENT_SOURCE(event)	\
+	((event >> CCI500_PMU_EVENT_SOURCE_SHIFT) & CCI500_PMU_EVENT_SOURCE_MASK)
+#define CCI500_PMU_EVENT_CODE(event)	\
+	((event >> CCI500_PMU_EVENT_CODE_SHIFT) & CCI500_PMU_EVENT_CODE_MASK)
+
+#define CCI500_SLAVE_PORT_MIN_EV	0x00
+#define CCI500_SLAVE_PORT_MAX_EV	0x1f
+#define CCI500_MASTER_PORT_MIN_EV	0x00
+#define CCI500_MASTER_PORT_MAX_EV	0x06
+#define CCI500_GLOBAL_PORT_MIN_EV	0x00
+#define CCI500_GLOBAL_PORT_MAX_EV	0x0f
+
+static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
+					unsigned long hw_event)
+{
+	u32 ev_source = CCI500_PMU_EVENT_SOURCE(hw_event);
+	u32 ev_code = CCI500_PMU_EVENT_CODE(hw_event);
+	int if_type;
+
+	if (hw_event & ~CCI500_PMU_EVENT_MASK)
+		return -ENOENT;
+
+	switch (ev_source) {
+	case CCI500_PORT_S0:
+	case CCI500_PORT_S1:
+	case CCI500_PORT_S2:
+	case CCI500_PORT_S3:
+	case CCI500_PORT_S4:
+	case CCI500_PORT_S5:
+	case CCI500_PORT_S6:
+		if_type = CCI_IF_SLAVE;
+		break;
+	case CCI500_PORT_M0:
+	case CCI500_PORT_M1:
+	case CCI500_PORT_M2:
+	case CCI500_PORT_M3:
+	case CCI500_PORT_M4:
+	case CCI500_PORT_M5:
+		if_type = CCI_IF_MASTER;
+		break;
+	case CCI500_PORT_GLOBAL:
+		if_type = CCI_IF_GLOBAL;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+		ev_code <= cci_pmu->model->event_ranges[if_type].max)
+		return hw_event;
+
+	return -ENOENT;
+}
+#endif	/* CONFIG_ARM_CCI500_PMU */
+
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
 	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
@@ -981,6 +1085,29 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.get_event_idx = cci400_get_event_idx,
 	},
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	[CCI500_R0] = {
+		.name = "CCI_500",
+		.fixed_hw_cntrs = 0,
+		.num_hw_cntrs = 8,
+		.cntr_size = SZ_64K,
+		.event_ranges = {
+			[CCI_IF_SLAVE] = {
+				CCI500_SLAVE_PORT_MIN_EV,
+				CCI500_SLAVE_PORT_MAX_EV,
+			},
+			[CCI_IF_MASTER] = {
+				CCI500_MASTER_PORT_MIN_EV,
+				CCI500_MASTER_PORT_MAX_EV,
+			},
+			[CCI_IF_GLOBAL] = {
+				CCI500_GLOBAL_PORT_MIN_EV,
+				CCI500_GLOBAL_PORT_MAX_EV,
+			},
+		},
+		.validate_hw_event = cci500_validate_hw_event,
+	},
+#endif
 };
 
 static const struct of_device_id arm_cci_pmu_matches[] = {
@@ -998,6 +1125,12 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
 		.data	= &cci_pmu_models[CCI400_R1],
 	},
 #endif
+#ifdef CONFIG_ARM_CCI500_PMU
+	{
+		.compatible = "arm,cci-500-pmu,r0",
+		.data = &cci_pmu_models[CCI500_R0],
+	},
+#endif
 	{},
 };
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 7/7] arm-cci: Add aliases for PMU events
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arnd Bergmann, devicetree, linux-kernel, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon, arm,
	Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Each CCI model have different event/source codes and formats. This
patch exports this information via the sysfs, which includes the
aliases for the events. The aliases are listed by 'perf list', helping
the users to specify the name of the event instead of the binary
config values.

Each event alias must accompany the 'source' code except for the
following cases :

1) CCI-400 - cycles event, doesn't relate to an interface.
2) CCI-500 - Global events to the CCI. (Fixed source code = 0xf)

Each CCI model provides two sets of attributes(format and event),
which are dynamically populated before registering the PMU, to
allow for the appropriate information.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 295 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index e12ddba..a72fccb 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -121,6 +121,10 @@ struct cci_pmu_model {
 	u32 fixed_hw_cntrs;
 	u32 num_hw_cntrs;
 	u32 cntr_size;
+	u64 nformat_attrs;
+	u64 nevent_attrs;
+	struct dev_ext_attribute *format_attrs;
+	struct dev_ext_attribute *event_attrs;
 	struct event_range event_ranges[CCI_IF_MAX];
 	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
 	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
@@ -157,6 +161,19 @@ enum cci_models {
 	CCI_MODEL_MAX
 };
 
+static ssize_t cci_pmu_format_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+static ssize_t cci_pmu_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
+	{ __ATTR(_name, S_IRUGO, _func, NULL), (void *)_config }
+
+#define CCI_FORMAT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_format_show, (char *)_config)
+#define CCI_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_event_show, (unsigned long)_config)
+
 /* CCI400 PMU Specific definitions */
 
 #ifdef CONFIG_ARM_CCI400_PMU
@@ -218,6 +235,106 @@ enum cci400_perf_events {
 #define CCI400_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI400_R1_MASTER_PORT_MAX_EV	0x11
 
+#define CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci400_pmu_cycle_event_show, \
+					(unsigned long)_config)
+
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci400_pmu_format_attrs[] = {
+	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-7"),
+};
+
+static struct dev_ext_attribute cci400_r0_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x14),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_addr_hazard, 0x15),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_id_hazard, 0x16),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_tt_full, 0x17),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x18),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x19),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_tt_full, 0x1A),
+	/* Special event for cycles counter */
+	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
+
+static struct dev_ext_attribute cci400_r1_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_slave_id_hazard, 0x14),
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_stall_cycle_addr_hazard, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_master_id_hazard, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_hi_prio_rtq_full, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_wtq_full, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_low_prio_rtq_full, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_mid_prio_rtq_full, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn0, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn1, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn2, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn3, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn0, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn1, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn2, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn3, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_unique_or_line_unique_addr_hazard, 0x11),
+	/* Special event for cycles counter */
+	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
+
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	return snprintf(buf, PAGE_SIZE, "config=0x%lx\n", (unsigned long)eattr->var);
+}
+
 static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 				struct cci_pmu_hw_events *hw,
 				unsigned long cci_event)
@@ -355,6 +472,92 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
 #define CCI500_GLOBAL_PORT_MIN_EV	0x00
 #define CCI500_GLOBAL_PORT_MAX_EV	0x0f
 
+
+#define CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci500_pmu_global_event_show, \
+					(unsigned long) _config)
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+				struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci500_pmu_format_attrs[] = {
+	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-8"),
+};
+
+static struct dev_ext_attribute cci500_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_arvalid, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_dev, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_non_alloc, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_alloc, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_invalidate, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maint, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rval, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rlast_snoop, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_awalid, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_dev, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_non_shareable, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wb, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wlu, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wunique, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_evict, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_wrevict, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_beat, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_acvalid, 0x13),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_read, 0x14),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_clean, 0x15),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_data_transfer_low, 0x16),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_arvalid, 0x17),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall, 0x18),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall, 0x19),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_stall, 0x1A),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_resp_stall, 0x1B),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_stall, 0x1C),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_s_data_stall, 0x1D),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rq_stall_ot_limit, 0x1E),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_stall_arbit, 0x1F),
+
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_beat_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_beat_any, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_stall, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_stall, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_resp_stall, 0x6),
+
+	/* Global events */
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_0_1, 0x0),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_2_3, 0x1),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_4_5, 0x2),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_6_7, 0x3),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_0_1, 0x4),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_2_3, 0x5),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_4_5, 0x6),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_6_7, 0x7),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_back_invalidation, 0x8),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_alloc_busy, 0x9),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_tt_full, 0xA),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_wrq, 0xB),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_cd_hs, 0xC),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_rq_stall_addr_hazard, 0xD),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snopp_rq_stall_tt_full, 0xE),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_rq_tzmp1_prot, 0xF),
+};
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+					struct dev_ext_attribute, attr);
+	/* Global events have single fixed source code */
+	return snprintf(buf, PAGE_SIZE, "event=0x%lx,source=0x%x\n",
+				(unsigned long)eattr->var, CCI500_PORT_GLOBAL);
+}
+
 static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
 					unsigned long hw_event)
 {
@@ -398,6 +601,24 @@ static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
 }
 #endif	/* CONFIG_ARM_CCI500_PMU */
 
+static ssize_t cci_pmu_format_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var);
+}
+
+static ssize_t cci_pmu_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	/* source parameter is mandatory for normal PMU events */
+	return snprintf(buf, PAGE_SIZE, "source=?,event=0x%lx\n",
+					 (unsigned long)eattr->var);
+}
+
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
 	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
@@ -980,17 +1201,78 @@ static struct attribute_group pmu_attr_group = {
 	.attrs = pmu_attrs,
 };
 
+static struct attribute_group pmu_format_attr_group = {
+	.name = "format",
+	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
+};
+
+static struct attribute_group pmu_event_attr_group = {
+	.name = "events",
+	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
+};
+
 static const struct attribute_group *pmu_attr_groups[] = {
 	&pmu_attr_group,
+	&pmu_format_attr_group,
+	&pmu_event_attr_group,
 	NULL
 };
 
+static struct attribute **alloc_attrs(struct platform_device *pdev,
+				int n, struct dev_ext_attribute *source)
+{
+	int i;
+	struct attribute **attrs;
+
+	/* Alloc n + 1 (for terminating NULL) */
+	attrs  = devm_kcalloc(&pdev->dev, n + 1, sizeof(struct attribute *),
+								GFP_KERNEL);
+	if (!attrs)
+		return attrs;
+	for(i = 0; i < n; i++)
+		attrs[i] = &source[i].attr.attr;
+	return attrs;
+}
+
+static int cci_pmu_init_attrs(struct cci_pmu *cci_pmu, struct platform_device *pdev)
+{
+	const struct cci_pmu_model *model = cci_pmu->model;
+	struct attribute **attrs;
+
+	/*
+	 * All allocations below are managed, hence doesn't need to be
+	 * free'd explicitly in case of an error.
+	 */
+
+	if (model->nevent_attrs) {
+		attrs = alloc_attrs(pdev, model->nevent_attrs,
+						model->event_attrs);
+		if (!attrs)
+			return -ENOMEM;
+		pmu_event_attr_group.attrs = attrs;
+	}
+	if (model->nformat_attrs) {
+		attrs = alloc_attrs(pdev, model->nformat_attrs,
+						 model->format_attrs);
+		if (!attrs)
+			return -ENOMEM;
+		pmu_format_attr_group.attrs = attrs;
+	}
+	pmu_cpumask_attr.var = cci_pmu;
+
+	return 0;
+}
+
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
 	u32 num_cntrs;
+	int rc;
+
+	rc = cci_pmu_init_attrs(cci_pmu, pdev);
+	if (rc)
+		return rc;
 
-	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
 		.name		= cci_pmu->model->name,
 		.task_ctx_nr	= perf_invalid_context,
@@ -1053,6 +1335,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
+		.format_attrs = cci400_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+		.event_attrs = cci400_r0_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci400_r0_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI400_R0_SLAVE_PORT_MIN_EV,
@@ -1071,6 +1357,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
+		.format_attrs = cci400_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+		.event_attrs = cci400_r1_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci400_r1_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI400_R1_SLAVE_PORT_MIN_EV,
@@ -1091,6 +1381,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 0,
 		.num_hw_cntrs = 8,
 		.cntr_size = SZ_64K,
+		.format_attrs = cci500_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci500_pmu_format_attrs),
+		.event_attrs = cci500_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci500_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI500_SLAVE_PORT_MIN_EV,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 7/7] arm-cci: Add aliases for PMU events
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Olof Johansson, Pawel Moll, Punit Agrawal, Will Deacon,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

Each CCI model have different event/source codes and formats. This
patch exports this information via the sysfs, which includes the
aliases for the events. The aliases are listed by 'perf list', helping
the users to specify the name of the event instead of the binary
config values.

Each event alias must accompany the 'source' code except for the
following cases :

1) CCI-400 - cycles event, doesn't relate to an interface.
2) CCI-500 - Global events to the CCI. (Fixed source code = 0xf)

Each CCI model provides two sets of attributes(format and event),
which are dynamically populated before registering the PMU, to
allow for the appropriate information.

Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
---
 drivers/bus/arm-cci.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 295 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index e12ddba..a72fccb 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -121,6 +121,10 @@ struct cci_pmu_model {
 	u32 fixed_hw_cntrs;
 	u32 num_hw_cntrs;
 	u32 cntr_size;
+	u64 nformat_attrs;
+	u64 nevent_attrs;
+	struct dev_ext_attribute *format_attrs;
+	struct dev_ext_attribute *event_attrs;
 	struct event_range event_ranges[CCI_IF_MAX];
 	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
 	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
@@ -157,6 +161,19 @@ enum cci_models {
 	CCI_MODEL_MAX
 };
 
+static ssize_t cci_pmu_format_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+static ssize_t cci_pmu_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
+	{ __ATTR(_name, S_IRUGO, _func, NULL), (void *)_config }
+
+#define CCI_FORMAT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_format_show, (char *)_config)
+#define CCI_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_event_show, (unsigned long)_config)
+
 /* CCI400 PMU Specific definitions */
 
 #ifdef CONFIG_ARM_CCI400_PMU
@@ -218,6 +235,106 @@ enum cci400_perf_events {
 #define CCI400_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI400_R1_MASTER_PORT_MAX_EV	0x11
 
+#define CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci400_pmu_cycle_event_show, \
+					(unsigned long)_config)
+
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci400_pmu_format_attrs[] = {
+	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-7"),
+};
+
+static struct dev_ext_attribute cci400_r0_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x14),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_addr_hazard, 0x15),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_id_hazard, 0x16),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_tt_full, 0x17),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x18),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x19),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_tt_full, 0x1A),
+	/* Special event for cycles counter */
+	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
+
+static struct dev_ext_attribute cci400_r1_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_slave_id_hazard, 0x14),
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_stall_cycle_addr_hazard, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_master_id_hazard, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_hi_prio_rtq_full, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_wtq_full, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_low_prio_rtq_full, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_mid_prio_rtq_full, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn0, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn1, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn2, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn3, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn0, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn1, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn2, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn3, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_unique_or_line_unique_addr_hazard, 0x11),
+	/* Special event for cycles counter */
+	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
+
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	return snprintf(buf, PAGE_SIZE, "config=0x%lx\n", (unsigned long)eattr->var);
+}
+
 static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 				struct cci_pmu_hw_events *hw,
 				unsigned long cci_event)
@@ -355,6 +472,92 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
 #define CCI500_GLOBAL_PORT_MIN_EV	0x00
 #define CCI500_GLOBAL_PORT_MAX_EV	0x0f
 
+
+#define CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci500_pmu_global_event_show, \
+					(unsigned long) _config)
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+				struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci500_pmu_format_attrs[] = {
+	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-8"),
+};
+
+static struct dev_ext_attribute cci500_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_arvalid, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_dev, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_non_alloc, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_alloc, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_invalidate, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maint, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rval, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rlast_snoop, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_awalid, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_dev, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_non_shareable, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wb, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wlu, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wunique, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_evict, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_wrevict, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_beat, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_acvalid, 0x13),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_read, 0x14),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_clean, 0x15),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_data_transfer_low, 0x16),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_arvalid, 0x17),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall, 0x18),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall, 0x19),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_stall, 0x1A),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_resp_stall, 0x1B),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_stall, 0x1C),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_s_data_stall, 0x1D),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rq_stall_ot_limit, 0x1E),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_stall_arbit, 0x1F),
+
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_beat_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_beat_any, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_stall, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_stall, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_resp_stall, 0x6),
+
+	/* Global events */
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_0_1, 0x0),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_2_3, 0x1),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_4_5, 0x2),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_6_7, 0x3),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_0_1, 0x4),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_2_3, 0x5),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_4_5, 0x6),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_6_7, 0x7),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_back_invalidation, 0x8),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_alloc_busy, 0x9),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_tt_full, 0xA),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_wrq, 0xB),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_cd_hs, 0xC),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_rq_stall_addr_hazard, 0xD),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snopp_rq_stall_tt_full, 0xE),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_rq_tzmp1_prot, 0xF),
+};
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+					struct dev_ext_attribute, attr);
+	/* Global events have single fixed source code */
+	return snprintf(buf, PAGE_SIZE, "event=0x%lx,source=0x%x\n",
+				(unsigned long)eattr->var, CCI500_PORT_GLOBAL);
+}
+
 static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
 					unsigned long hw_event)
 {
@@ -398,6 +601,24 @@ static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
 }
 #endif	/* CONFIG_ARM_CCI500_PMU */
 
+static ssize_t cci_pmu_format_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var);
+}
+
+static ssize_t cci_pmu_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	/* source parameter is mandatory for normal PMU events */
+	return snprintf(buf, PAGE_SIZE, "source=?,event=0x%lx\n",
+					 (unsigned long)eattr->var);
+}
+
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
 	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
@@ -980,17 +1201,78 @@ static struct attribute_group pmu_attr_group = {
 	.attrs = pmu_attrs,
 };
 
+static struct attribute_group pmu_format_attr_group = {
+	.name = "format",
+	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
+};
+
+static struct attribute_group pmu_event_attr_group = {
+	.name = "events",
+	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
+};
+
 static const struct attribute_group *pmu_attr_groups[] = {
 	&pmu_attr_group,
+	&pmu_format_attr_group,
+	&pmu_event_attr_group,
 	NULL
 };
 
+static struct attribute **alloc_attrs(struct platform_device *pdev,
+				int n, struct dev_ext_attribute *source)
+{
+	int i;
+	struct attribute **attrs;
+
+	/* Alloc n + 1 (for terminating NULL) */
+	attrs  = devm_kcalloc(&pdev->dev, n + 1, sizeof(struct attribute *),
+								GFP_KERNEL);
+	if (!attrs)
+		return attrs;
+	for(i = 0; i < n; i++)
+		attrs[i] = &source[i].attr.attr;
+	return attrs;
+}
+
+static int cci_pmu_init_attrs(struct cci_pmu *cci_pmu, struct platform_device *pdev)
+{
+	const struct cci_pmu_model *model = cci_pmu->model;
+	struct attribute **attrs;
+
+	/*
+	 * All allocations below are managed, hence doesn't need to be
+	 * free'd explicitly in case of an error.
+	 */
+
+	if (model->nevent_attrs) {
+		attrs = alloc_attrs(pdev, model->nevent_attrs,
+						model->event_attrs);
+		if (!attrs)
+			return -ENOMEM;
+		pmu_event_attr_group.attrs = attrs;
+	}
+	if (model->nformat_attrs) {
+		attrs = alloc_attrs(pdev, model->nformat_attrs,
+						 model->format_attrs);
+		if (!attrs)
+			return -ENOMEM;
+		pmu_format_attr_group.attrs = attrs;
+	}
+	pmu_cpumask_attr.var = cci_pmu;
+
+	return 0;
+}
+
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
 	u32 num_cntrs;
+	int rc;
+
+	rc = cci_pmu_init_attrs(cci_pmu, pdev);
+	if (rc)
+		return rc;
 
-	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
 		.name		= cci_pmu->model->name,
 		.task_ctx_nr	= perf_invalid_context,
@@ -1053,6 +1335,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
+		.format_attrs = cci400_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+		.event_attrs = cci400_r0_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci400_r0_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI400_R0_SLAVE_PORT_MIN_EV,
@@ -1071,6 +1357,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
+		.format_attrs = cci400_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+		.event_attrs = cci400_r1_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci400_r1_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI400_R1_SLAVE_PORT_MIN_EV,
@@ -1091,6 +1381,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 0,
 		.num_hw_cntrs = 8,
 		.cntr_size = SZ_64K,
+		.format_attrs = cci500_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci500_pmu_format_attrs),
+		.event_attrs = cci500_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci500_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI500_SLAVE_PORT_MIN_EV,
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 7/7] arm-cci: Add aliases for PMU events
@ 2015-05-05 11:49   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-05 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Each CCI model have different event/source codes and formats. This
patch exports this information via the sysfs, which includes the
aliases for the events. The aliases are listed by 'perf list', helping
the users to specify the name of the event instead of the binary
config values.

Each event alias must accompany the 'source' code except for the
following cases :

1) CCI-400 - cycles event, doesn't relate to an interface.
2) CCI-500 - Global events to the CCI. (Fixed source code = 0xf)

Each CCI model provides two sets of attributes(format and event),
which are dynamically populated before registering the PMU, to
allow for the appropriate information.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 drivers/bus/arm-cci.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 295 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index e12ddba..a72fccb 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -121,6 +121,10 @@ struct cci_pmu_model {
 	u32 fixed_hw_cntrs;
 	u32 num_hw_cntrs;
 	u32 cntr_size;
+	u64 nformat_attrs;
+	u64 nevent_attrs;
+	struct dev_ext_attribute *format_attrs;
+	struct dev_ext_attribute *event_attrs;
 	struct event_range event_ranges[CCI_IF_MAX];
 	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
 	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
@@ -157,6 +161,19 @@ enum cci_models {
 	CCI_MODEL_MAX
 };
 
+static ssize_t cci_pmu_format_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+static ssize_t cci_pmu_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
+	{ __ATTR(_name, S_IRUGO, _func, NULL), (void *)_config }
+
+#define CCI_FORMAT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_format_show, (char *)_config)
+#define CCI_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_event_show, (unsigned long)_config)
+
 /* CCI400 PMU Specific definitions */
 
 #ifdef CONFIG_ARM_CCI400_PMU
@@ -218,6 +235,106 @@ enum cci400_perf_events {
 #define CCI400_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI400_R1_MASTER_PORT_MAX_EV	0x11
 
+#define CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci400_pmu_cycle_event_show, \
+					(unsigned long)_config)
+
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci400_pmu_format_attrs[] = {
+	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-7"),
+};
+
+static struct dev_ext_attribute cci400_r0_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x14),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_addr_hazard, 0x15),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_id_hazard, 0x16),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_tt_full, 0x17),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x18),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x19),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_tt_full, 0x1A),
+	/* Special event for cycles counter */
+	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
+
+static struct dev_ext_attribute cci400_r1_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_slave_id_hazard, 0x14),
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_stall_cycle_addr_hazard, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_master_id_hazard, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_hi_prio_rtq_full, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_wtq_full, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_low_prio_rtq_full, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_mid_prio_rtq_full, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn0, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn1, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn2, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn3, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn0, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn1, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn2, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn3, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_unique_or_line_unique_addr_hazard, 0x11),
+	/* Special event for cycles counter */
+	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
+
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	return snprintf(buf, PAGE_SIZE, "config=0x%lx\n", (unsigned long)eattr->var);
+}
+
 static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
 				struct cci_pmu_hw_events *hw,
 				unsigned long cci_event)
@@ -355,6 +472,92 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
 #define CCI500_GLOBAL_PORT_MIN_EV	0x00
 #define CCI500_GLOBAL_PORT_MAX_EV	0x0f
 
+
+#define CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+	CCI_EXT_ATTR_ENTRY(_name, cci500_pmu_global_event_show, \
+					(unsigned long) _config)
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+				struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci500_pmu_format_attrs[] = {
+	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-8"),
+};
+
+static struct dev_ext_attribute cci500_pmu_event_attrs[] = {
+	/* Slave events */
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_arvalid, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_dev, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_nonshareable, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_non_alloc, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_alloc, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_invalidate, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maint, 0x6),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rval, 0x8),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rlast_snoop, 0x9),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_awalid, 0xA),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_dev, 0xB),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_non_shareable, 0xC),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wb, 0xD),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wlu, 0xE),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wunique, 0xF),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_evict, 0x10),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_wrevict, 0x11),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_beat, 0x12),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_acvalid, 0x13),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_read, 0x14),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_clean, 0x15),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_data_transfer_low, 0x16),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_arvalid, 0x17),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall, 0x18),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall, 0x19),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_stall, 0x1A),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_w_resp_stall, 0x1B),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_stall, 0x1C),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_s_data_stall, 0x1D),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_rq_stall_ot_limit, 0x1E),
+	CCI_EVENT_EXT_ATTR_ENTRY(si_r_stall_arbit, 0x1F),
+
+	/* Master events */
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_beat_any, 0x0),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_beat_any, 0x1),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall, 0x2),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_stall, 0x3),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall, 0x4),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_stall, 0x5),
+	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_resp_stall, 0x6),
+
+	/* Global events */
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_0_1, 0x0),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_2_3, 0x1),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_4_5, 0x2),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_6_7, 0x3),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_0_1, 0x4),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_2_3, 0x5),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_4_5, 0x6),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_6_7, 0x7),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_back_invalidation, 0x8),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_alloc_busy, 0x9),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_tt_full, 0xA),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_wrq, 0xB),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_cd_hs, 0xC),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_rq_stall_addr_hazard, 0xD),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snopp_rq_stall_tt_full, 0xE),
+	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_rq_tzmp1_prot, 0xF),
+};
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+					struct dev_ext_attribute, attr);
+	/* Global events have single fixed source code */
+	return snprintf(buf, PAGE_SIZE, "event=0x%lx,source=0x%x\n",
+				(unsigned long)eattr->var, CCI500_PORT_GLOBAL);
+}
+
 static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
 					unsigned long hw_event)
 {
@@ -398,6 +601,24 @@ static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
 }
 #endif	/* CONFIG_ARM_CCI500_PMU */
 
+static ssize_t cci_pmu_format_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var);
+}
+
+static ssize_t cci_pmu_event_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	/* source parameter is mandatory for normal PMU events */
+	return snprintf(buf, PAGE_SIZE, "source=?,event=0x%lx\n",
+					 (unsigned long)eattr->var);
+}
+
 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
 {
 	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
@@ -980,17 +1201,78 @@ static struct attribute_group pmu_attr_group = {
 	.attrs = pmu_attrs,
 };
 
+static struct attribute_group pmu_format_attr_group = {
+	.name = "format",
+	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
+};
+
+static struct attribute_group pmu_event_attr_group = {
+	.name = "events",
+	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
+};
+
 static const struct attribute_group *pmu_attr_groups[] = {
 	&pmu_attr_group,
+	&pmu_format_attr_group,
+	&pmu_event_attr_group,
 	NULL
 };
 
+static struct attribute **alloc_attrs(struct platform_device *pdev,
+				int n, struct dev_ext_attribute *source)
+{
+	int i;
+	struct attribute **attrs;
+
+	/* Alloc n + 1 (for terminating NULL) */
+	attrs  = devm_kcalloc(&pdev->dev, n + 1, sizeof(struct attribute *),
+								GFP_KERNEL);
+	if (!attrs)
+		return attrs;
+	for(i = 0; i < n; i++)
+		attrs[i] = &source[i].attr.attr;
+	return attrs;
+}
+
+static int cci_pmu_init_attrs(struct cci_pmu *cci_pmu, struct platform_device *pdev)
+{
+	const struct cci_pmu_model *model = cci_pmu->model;
+	struct attribute **attrs;
+
+	/*
+	 * All allocations below are managed, hence doesn't need to be
+	 * free'd explicitly in case of an error.
+	 */
+
+	if (model->nevent_attrs) {
+		attrs = alloc_attrs(pdev, model->nevent_attrs,
+						model->event_attrs);
+		if (!attrs)
+			return -ENOMEM;
+		pmu_event_attr_group.attrs = attrs;
+	}
+	if (model->nformat_attrs) {
+		attrs = alloc_attrs(pdev, model->nformat_attrs,
+						 model->format_attrs);
+		if (!attrs)
+			return -ENOMEM;
+		pmu_format_attr_group.attrs = attrs;
+	}
+	pmu_cpumask_attr.var = cci_pmu;
+
+	return 0;
+}
+
 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
 {
 	char *name = cci_pmu->model->name;
 	u32 num_cntrs;
+	int rc;
+
+	rc = cci_pmu_init_attrs(cci_pmu, pdev);
+	if (rc)
+		return rc;
 
-	pmu_cpumask_attr.var = cci_pmu;
 	cci_pmu->pmu = (struct pmu) {
 		.name		= cci_pmu->model->name,
 		.task_ctx_nr	= perf_invalid_context,
@@ -1053,6 +1335,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
+		.format_attrs = cci400_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+		.event_attrs = cci400_r0_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci400_r0_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI400_R0_SLAVE_PORT_MIN_EV,
@@ -1071,6 +1357,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 1,	/* Cycle counter */
 		.num_hw_cntrs = 4,
 		.cntr_size = SZ_4K,
+		.format_attrs = cci400_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+		.event_attrs = cci400_r1_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci400_r1_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI400_R1_SLAVE_PORT_MIN_EV,
@@ -1091,6 +1381,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
 		.fixed_hw_cntrs = 0,
 		.num_hw_cntrs = 8,
 		.cntr_size = SZ_64K,
+		.format_attrs = cci500_pmu_format_attrs,
+		.nformat_attrs = ARRAY_SIZE(cci500_pmu_format_attrs),
+		.event_attrs = cci500_pmu_event_attrs,
+		.nevent_attrs = ARRAY_SIZE(cci500_pmu_event_attrs),
 		.event_ranges = {
 			[CCI_IF_SLAVE] = {
 				CCI500_SLAVE_PORT_MIN_EV,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH 2/7] arm-cci: Cleanup PMU driver code
@ 2015-05-18 10:18     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 10:18 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel, Mark Rutland, devicetree, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon, linux-kernel, arm,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> This patch gets rid of the global struct cci_pmu variable and makes
> the code use the cci_pmu explicitly. Makes code a bit more robust
> and reader friendly.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/arm-cci.c |  142 ++++++++++++++++++++++++++++---------------------
>  1 file changed, 80 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 941b831..27cc200 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -124,9 +124,9 @@ struct cci_pmu {
>  	int num_events;
>  	atomic_t active_events;
>  	struct mutex reserve_mutex;
> +	struct notifier_block cpu_nb;
>  	cpumask_t cpus;
>  };
> -static struct cci_pmu *pmu;
>  
>  #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
>  
> @@ -179,7 +179,7 @@ enum cci400_perf_events {
>  #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
>  #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
>  
> -static int pmu_validate_hw_event(unsigned long hw_event)
> +static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
>  	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
>  	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> @@ -207,8 +207,8 @@ static int pmu_validate_hw_event(unsigned long hw_event)
>  		return -ENOENT;
>  	}
>  
> -	if (ev_code >= pmu->model->event_ranges[if_type].min &&
> -		ev_code <= pmu->model->event_ranges[if_type].max)
> +	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
> +		ev_code <= cci_pmu->model->event_ranges[if_type].max)
>  		return hw_event;
>  
>  	return -ENOENT;
> @@ -239,29 +239,31 @@ static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
>  }
>  
> -static u32 pmu_read_register(int idx, unsigned int offset)
> +static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
>  {
> -	return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
>  }
>  
> -static void pmu_write_register(u32 value, int idx, unsigned int offset)
> +static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
> +			       int idx, unsigned int offset)
>  {
> -	return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return writel_relaxed(value, cci_pmu->base +
> +			      CCI_PMU_CNTR_BASE(idx) + offset);
>  }
>  
> -static void pmu_disable_counter(int idx)
> +static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL);
> +	pmu_write_register(cci_pmu, 0, idx, CCI_PMU_CNTR_CTRL);
>  }
>  
> -static void pmu_enable_counter(int idx)
> +static void pmu_enable_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL);
> +	pmu_write_register(cci_pmu, 1, idx, CCI_PMU_CNTR_CTRL);
>  }
>  
> -static void pmu_set_event(int idx, unsigned long event)
> +static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
>  {
> -	pmu_write_register(event, idx, CCI_PMU_EVT_SEL);
> +	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
>  }
>  
>  static u32 pmu_get_max_counters(void)
> @@ -306,7 +308,8 @@ static int pmu_map_event(struct perf_event *event)
>  	if (config == CCI_PMU_CYCLES)
>  		mapping = config;
>  	else
> -		mapping = pmu_validate_hw_event(config);
> +		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
> +							config);
>  
>  	return mapping;
>  }
> @@ -319,7 +322,7 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
>  	if (unlikely(!pmu_device))
>  		return -ENODEV;
>  
> -	if (pmu->nr_irqs < 1) {
> +	if (cci_pmu->nr_irqs < 1) {
>  		dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n");
>  		return -ENODEV;
>  	}
> @@ -331,16 +334,16 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
>  	 *
>  	 * This should allow handling of non-unique interrupt for the counters.
>  	 */
> -	for (i = 0; i < pmu->nr_irqs; i++) {
> -		int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED,
> +	for (i = 0; i < cci_pmu->nr_irqs; i++) {
> +		int err = request_irq(cci_pmu->irqs[i], handler, IRQF_SHARED,
>  				"arm-cci-pmu", cci_pmu);
>  		if (err) {
>  			dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n",
> -				pmu->irqs[i]);
> +				cci_pmu->irqs[i]);
>  			return err;
>  		}
>  
> -		set_bit(i, &pmu->active_irqs);
> +		set_bit(i, &cci_pmu->active_irqs);
>  	}
>  
>  	return 0;
> @@ -350,11 +353,11 @@ static void pmu_free_irq(struct cci_pmu *cci_pmu)
>  {
>  	int i;
>  
> -	for (i = 0; i < pmu->nr_irqs; i++) {
> -		if (!test_and_clear_bit(i, &pmu->active_irqs))
> +	for (i = 0; i < cci_pmu->nr_irqs; i++) {
> +		if (!test_and_clear_bit(i, &cci_pmu->active_irqs))
>  			continue;
>  
> -		free_irq(pmu->irqs[i], cci_pmu);
> +		free_irq(cci_pmu->irqs[i], cci_pmu);
>  	}
>  }
>  
> @@ -369,7 +372,7 @@ static u32 pmu_read_counter(struct perf_event *event)
>  		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
>  		return 0;
>  	}
> -	value = pmu_read_register(idx, CCI_PMU_CNTR);
> +	value = pmu_read_register(cci_pmu, idx, CCI_PMU_CNTR);
>  
>  	return value;
>  }
> @@ -383,7 +386,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value)
>  	if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
>  		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
>  	else
> -		pmu_write_register(value, idx, CCI_PMU_CNTR);
> +		pmu_write_register(cci_pmu, value, idx, CCI_PMU_CNTR);
>  }
>  
>  static u64 pmu_event_update(struct perf_event *event)
> @@ -427,7 +430,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  {
>  	unsigned long flags;
>  	struct cci_pmu *cci_pmu = dev;
> -	struct cci_pmu_hw_events *events = &pmu->hw_events;
> +	struct cci_pmu_hw_events *events = &cci_pmu->hw_events;
>  	int idx, handled = IRQ_NONE;
>  
>  	raw_spin_lock_irqsave(&events->pmu_lock, flags);
> @@ -446,11 +449,12 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  		hw_counter = &event->hw;
>  
>  		/* Did this counter overflow? */
> -		if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) &
> +		if (!(pmu_read_register(cci_pmu, idx, CCI_PMU_OVRFLW) &
>  		      CCI_PMU_OVRFLW_FLAG))
>  			continue;
>  
> -		pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
> +		pmu_write_register(cci_pmu, CCI_PMU_OVRFLW_FLAG, idx,
> +							CCI_PMU_OVRFLW);
>  
>  		pmu_event_update(event);
>  		pmu_event_set_period(event);
> @@ -549,10 +553,10 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
>  
>  	/* Configure the event to count, unless you are counting cycles */
>  	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
> -		pmu_set_event(idx, hwc->config_base);
> +		pmu_set_event(cci_pmu, idx, hwc->config_base);
>  
>  	pmu_event_set_period(event);
> -	pmu_enable_counter(idx);
> +	pmu_enable_counter(cci_pmu, idx);
>  
>  	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
>  }
> @@ -575,7 +579,7 @@ static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
>  	 * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
>  	 * cci_pmu_start()
>  	 */
> -	pmu_disable_counter(idx);
> +	pmu_disable_counter(cci_pmu, idx);
>  	pmu_event_update(event);
>  	hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
>  }
> @@ -779,20 +783,27 @@ static int cci_pmu_event_init(struct perf_event *event)
>  	return err;
>  }
>  
> -static ssize_t pmu_attr_cpumask_show(struct device *dev,
> +static ssize_t pmu_cpumask_attr_show(struct device *dev,
>  				     struct device_attribute *attr, char *buf)
>  {
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +					struct dev_ext_attribute, attr);
> +	struct cci_pmu *cci_pmu = eattr->var;
> +
>  	int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
> -			  cpumask_pr_args(&pmu->cpus));
> +			  cpumask_pr_args(&cci_pmu->cpus));
>  	buf[n++] = '\n';
>  	buf[n] = '\0';
>  	return n;
>  }
>  
> -static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
> +static struct dev_ext_attribute pmu_cpumask_attr = {
> +	__ATTR(cpumask, S_IRUGO, pmu_cpumask_attr_show, NULL),
> +	NULL,		/* Populated in cci_pmu_init */
> +};
>  
>  static struct attribute *pmu_attrs[] = {
> -	&dev_attr_cpumask.attr,
> +	&pmu_cpumask_attr.attr.attr,
>  	NULL,
>  };
>  
> @@ -808,6 +819,8 @@ static const struct attribute_group *pmu_attr_groups[] = {
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
> +
> +	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
>  		.name		= cci_pmu->model->name,
>  		.task_ctx_nr	= perf_invalid_context,
> @@ -831,12 +844,14 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  				unsigned long action, void *hcpu)
>  {
> +	struct cci_pmu *cci_pmu = container_of(self,
> +					struct cci_pmu, cpu_nb);
>  	unsigned int cpu = (long)hcpu;
>  	unsigned int target;
>  
>  	switch (action & ~CPU_TASKS_FROZEN) {
>  	case CPU_DOWN_PREPARE:
> -		if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
> +		if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
>  			break;
>  		target = cpumask_any_but(cpu_online_mask, cpu);
>  		if (target < 0) // UP, last CPU
> @@ -845,7 +860,7 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  		 * TODO: migrate context once core races on event->ctx have
>  		 * been fixed.
>  		 */
> -		cpumask_set_cpu(target, &pmu->cpus);
> +		cpumask_set_cpu(target, &cci_pmu->cpus);
>  	default:
>  		break;
>  	}
> @@ -853,15 +868,6 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  	return NOTIFY_OK;
>  }
>  
> -static struct notifier_block cci_pmu_cpu_nb = {
> -	.notifier_call	= cci_pmu_cpu_notifier,
> -	/*
> -	 * to migrate uncore events, our notifier should be executed
> -	 * before perf core's notifier.
> -	 */
> -	.priority	= CPU_PRI_PERF + 1,
> -};
> -
>  static struct cci_pmu_model cci_pmu_models[] = {
>  	[CCI_REV_R0] = {
>  		.name = "CCI_400",
> @@ -935,6 +941,7 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
>  static int cci_pmu_probe(struct platform_device *pdev)
>  {
>  	struct resource *res;
> +	struct cci_pmu *cci_pmu;
>  	int i, ret, irq;
>  	const struct cci_pmu_model *model;
>  
> @@ -944,30 +951,30 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  		return -ENODEV;
>  	}
>  
> -	pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
> -	if (!pmu)
> +	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
> +	if (!cci_pmu)
>  		return -ENOMEM;
>  
> -	pmu->model = model;
> +	cci_pmu->model = model;
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	pmu->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(pmu->base))
> +	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(cci_pmu->base))
>  		return -ENOMEM;
>  
>  	/*
>  	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
>  	 * together to a common interrupt.
>  	 */
> -	pmu->nr_irqs = 0;
> +	cci_pmu->nr_irqs = 0;
>  	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
>  		irq = platform_get_irq(pdev, i);
>  		if (irq < 0)
>  			break;
>  
> -		if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs))
> +		if (is_duplicate_irq(irq, cci_pmu->irqs, cci_pmu->nr_irqs))
>  			continue;
>  
> -		pmu->irqs[pmu->nr_irqs++] = irq;
> +		cci_pmu->irqs[cci_pmu->nr_irqs++] = irq;
>  	}
>  
>  	/*
> @@ -980,20 +987,31 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	raw_spin_lock_init(&pmu->hw_events.pmu_lock);
> -	mutex_init(&pmu->reserve_mutex);
> -	atomic_set(&pmu->active_events, 0);
> -	cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
> +	raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock);
> +	mutex_init(&cci_pmu->reserve_mutex);
> +	atomic_set(&cci_pmu->active_events, 0);
> +	cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
>  
> -	ret = register_cpu_notifier(&cci_pmu_cpu_nb);
> +	cci_pmu->cpu_nb = (struct notifier_block) {
> +		.notifier_call	= cci_pmu_cpu_notifier,
> +		/*
> +		 * to migrate uncore events, our notifier should be executed
> +		 * before perf core's notifier.
> +		 */
> +		.priority	= CPU_PRI_PERF + 1,
> +	};
> +
> +	ret = register_cpu_notifier(&cci_pmu->cpu_nb);
>  	if (ret)
>  		return ret;
>  
> -	ret = cci_pmu_init(pmu, pdev);
> -	if (ret)
> +	ret = cci_pmu_init(cci_pmu, pdev);
> +	if (ret) {
> +		unregister_cpu_notifier(&cci_pmu->cpu_nb);
>  		return ret;
> +	}
>  
> -	pr_info("ARM %s PMU driver probed", pmu->model->name);
> +	pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
>  	return 0;
>  }

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 2/7] arm-cci: Cleanup PMU driver code
@ 2015-05-18 10:18     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 10:18 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, arm-DgEjT+Ai2ygdnm+yROfE0A,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
>
> This patch gets rid of the global struct cci_pmu variable and makes
> the code use the cci_pmu explicitly. Makes code a bit more robust
> and reader friendly.
>
> Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

Acked-by: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>

> ---
>  drivers/bus/arm-cci.c |  142 ++++++++++++++++++++++++++++---------------------
>  1 file changed, 80 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 941b831..27cc200 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -124,9 +124,9 @@ struct cci_pmu {
>  	int num_events;
>  	atomic_t active_events;
>  	struct mutex reserve_mutex;
> +	struct notifier_block cpu_nb;
>  	cpumask_t cpus;
>  };
> -static struct cci_pmu *pmu;
>  
>  #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
>  
> @@ -179,7 +179,7 @@ enum cci400_perf_events {
>  #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
>  #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
>  
> -static int pmu_validate_hw_event(unsigned long hw_event)
> +static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
>  	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
>  	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> @@ -207,8 +207,8 @@ static int pmu_validate_hw_event(unsigned long hw_event)
>  		return -ENOENT;
>  	}
>  
> -	if (ev_code >= pmu->model->event_ranges[if_type].min &&
> -		ev_code <= pmu->model->event_ranges[if_type].max)
> +	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
> +		ev_code <= cci_pmu->model->event_ranges[if_type].max)
>  		return hw_event;
>  
>  	return -ENOENT;
> @@ -239,29 +239,31 @@ static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
>  }
>  
> -static u32 pmu_read_register(int idx, unsigned int offset)
> +static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
>  {
> -	return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
>  }
>  
> -static void pmu_write_register(u32 value, int idx, unsigned int offset)
> +static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
> +			       int idx, unsigned int offset)
>  {
> -	return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return writel_relaxed(value, cci_pmu->base +
> +			      CCI_PMU_CNTR_BASE(idx) + offset);
>  }
>  
> -static void pmu_disable_counter(int idx)
> +static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL);
> +	pmu_write_register(cci_pmu, 0, idx, CCI_PMU_CNTR_CTRL);
>  }
>  
> -static void pmu_enable_counter(int idx)
> +static void pmu_enable_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL);
> +	pmu_write_register(cci_pmu, 1, idx, CCI_PMU_CNTR_CTRL);
>  }
>  
> -static void pmu_set_event(int idx, unsigned long event)
> +static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
>  {
> -	pmu_write_register(event, idx, CCI_PMU_EVT_SEL);
> +	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
>  }
>  
>  static u32 pmu_get_max_counters(void)
> @@ -306,7 +308,8 @@ static int pmu_map_event(struct perf_event *event)
>  	if (config == CCI_PMU_CYCLES)
>  		mapping = config;
>  	else
> -		mapping = pmu_validate_hw_event(config);
> +		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
> +							config);
>  
>  	return mapping;
>  }
> @@ -319,7 +322,7 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
>  	if (unlikely(!pmu_device))
>  		return -ENODEV;
>  
> -	if (pmu->nr_irqs < 1) {
> +	if (cci_pmu->nr_irqs < 1) {
>  		dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n");
>  		return -ENODEV;
>  	}
> @@ -331,16 +334,16 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
>  	 *
>  	 * This should allow handling of non-unique interrupt for the counters.
>  	 */
> -	for (i = 0; i < pmu->nr_irqs; i++) {
> -		int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED,
> +	for (i = 0; i < cci_pmu->nr_irqs; i++) {
> +		int err = request_irq(cci_pmu->irqs[i], handler, IRQF_SHARED,
>  				"arm-cci-pmu", cci_pmu);
>  		if (err) {
>  			dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n",
> -				pmu->irqs[i]);
> +				cci_pmu->irqs[i]);
>  			return err;
>  		}
>  
> -		set_bit(i, &pmu->active_irqs);
> +		set_bit(i, &cci_pmu->active_irqs);
>  	}
>  
>  	return 0;
> @@ -350,11 +353,11 @@ static void pmu_free_irq(struct cci_pmu *cci_pmu)
>  {
>  	int i;
>  
> -	for (i = 0; i < pmu->nr_irqs; i++) {
> -		if (!test_and_clear_bit(i, &pmu->active_irqs))
> +	for (i = 0; i < cci_pmu->nr_irqs; i++) {
> +		if (!test_and_clear_bit(i, &cci_pmu->active_irqs))
>  			continue;
>  
> -		free_irq(pmu->irqs[i], cci_pmu);
> +		free_irq(cci_pmu->irqs[i], cci_pmu);
>  	}
>  }
>  
> @@ -369,7 +372,7 @@ static u32 pmu_read_counter(struct perf_event *event)
>  		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
>  		return 0;
>  	}
> -	value = pmu_read_register(idx, CCI_PMU_CNTR);
> +	value = pmu_read_register(cci_pmu, idx, CCI_PMU_CNTR);
>  
>  	return value;
>  }
> @@ -383,7 +386,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value)
>  	if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
>  		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
>  	else
> -		pmu_write_register(value, idx, CCI_PMU_CNTR);
> +		pmu_write_register(cci_pmu, value, idx, CCI_PMU_CNTR);
>  }
>  
>  static u64 pmu_event_update(struct perf_event *event)
> @@ -427,7 +430,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  {
>  	unsigned long flags;
>  	struct cci_pmu *cci_pmu = dev;
> -	struct cci_pmu_hw_events *events = &pmu->hw_events;
> +	struct cci_pmu_hw_events *events = &cci_pmu->hw_events;
>  	int idx, handled = IRQ_NONE;
>  
>  	raw_spin_lock_irqsave(&events->pmu_lock, flags);
> @@ -446,11 +449,12 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  		hw_counter = &event->hw;
>  
>  		/* Did this counter overflow? */
> -		if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) &
> +		if (!(pmu_read_register(cci_pmu, idx, CCI_PMU_OVRFLW) &
>  		      CCI_PMU_OVRFLW_FLAG))
>  			continue;
>  
> -		pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
> +		pmu_write_register(cci_pmu, CCI_PMU_OVRFLW_FLAG, idx,
> +							CCI_PMU_OVRFLW);
>  
>  		pmu_event_update(event);
>  		pmu_event_set_period(event);
> @@ -549,10 +553,10 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
>  
>  	/* Configure the event to count, unless you are counting cycles */
>  	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
> -		pmu_set_event(idx, hwc->config_base);
> +		pmu_set_event(cci_pmu, idx, hwc->config_base);
>  
>  	pmu_event_set_period(event);
> -	pmu_enable_counter(idx);
> +	pmu_enable_counter(cci_pmu, idx);
>  
>  	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
>  }
> @@ -575,7 +579,7 @@ static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
>  	 * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
>  	 * cci_pmu_start()
>  	 */
> -	pmu_disable_counter(idx);
> +	pmu_disable_counter(cci_pmu, idx);
>  	pmu_event_update(event);
>  	hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
>  }
> @@ -779,20 +783,27 @@ static int cci_pmu_event_init(struct perf_event *event)
>  	return err;
>  }
>  
> -static ssize_t pmu_attr_cpumask_show(struct device *dev,
> +static ssize_t pmu_cpumask_attr_show(struct device *dev,
>  				     struct device_attribute *attr, char *buf)
>  {
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +					struct dev_ext_attribute, attr);
> +	struct cci_pmu *cci_pmu = eattr->var;
> +
>  	int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
> -			  cpumask_pr_args(&pmu->cpus));
> +			  cpumask_pr_args(&cci_pmu->cpus));
>  	buf[n++] = '\n';
>  	buf[n] = '\0';
>  	return n;
>  }
>  
> -static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
> +static struct dev_ext_attribute pmu_cpumask_attr = {
> +	__ATTR(cpumask, S_IRUGO, pmu_cpumask_attr_show, NULL),
> +	NULL,		/* Populated in cci_pmu_init */
> +};
>  
>  static struct attribute *pmu_attrs[] = {
> -	&dev_attr_cpumask.attr,
> +	&pmu_cpumask_attr.attr.attr,
>  	NULL,
>  };
>  
> @@ -808,6 +819,8 @@ static const struct attribute_group *pmu_attr_groups[] = {
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
> +
> +	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
>  		.name		= cci_pmu->model->name,
>  		.task_ctx_nr	= perf_invalid_context,
> @@ -831,12 +844,14 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  				unsigned long action, void *hcpu)
>  {
> +	struct cci_pmu *cci_pmu = container_of(self,
> +					struct cci_pmu, cpu_nb);
>  	unsigned int cpu = (long)hcpu;
>  	unsigned int target;
>  
>  	switch (action & ~CPU_TASKS_FROZEN) {
>  	case CPU_DOWN_PREPARE:
> -		if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
> +		if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
>  			break;
>  		target = cpumask_any_but(cpu_online_mask, cpu);
>  		if (target < 0) // UP, last CPU
> @@ -845,7 +860,7 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  		 * TODO: migrate context once core races on event->ctx have
>  		 * been fixed.
>  		 */
> -		cpumask_set_cpu(target, &pmu->cpus);
> +		cpumask_set_cpu(target, &cci_pmu->cpus);
>  	default:
>  		break;
>  	}
> @@ -853,15 +868,6 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  	return NOTIFY_OK;
>  }
>  
> -static struct notifier_block cci_pmu_cpu_nb = {
> -	.notifier_call	= cci_pmu_cpu_notifier,
> -	/*
> -	 * to migrate uncore events, our notifier should be executed
> -	 * before perf core's notifier.
> -	 */
> -	.priority	= CPU_PRI_PERF + 1,
> -};
> -
>  static struct cci_pmu_model cci_pmu_models[] = {
>  	[CCI_REV_R0] = {
>  		.name = "CCI_400",
> @@ -935,6 +941,7 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
>  static int cci_pmu_probe(struct platform_device *pdev)
>  {
>  	struct resource *res;
> +	struct cci_pmu *cci_pmu;
>  	int i, ret, irq;
>  	const struct cci_pmu_model *model;
>  
> @@ -944,30 +951,30 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  		return -ENODEV;
>  	}
>  
> -	pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
> -	if (!pmu)
> +	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
> +	if (!cci_pmu)
>  		return -ENOMEM;
>  
> -	pmu->model = model;
> +	cci_pmu->model = model;
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	pmu->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(pmu->base))
> +	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(cci_pmu->base))
>  		return -ENOMEM;
>  
>  	/*
>  	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
>  	 * together to a common interrupt.
>  	 */
> -	pmu->nr_irqs = 0;
> +	cci_pmu->nr_irqs = 0;
>  	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
>  		irq = platform_get_irq(pdev, i);
>  		if (irq < 0)
>  			break;
>  
> -		if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs))
> +		if (is_duplicate_irq(irq, cci_pmu->irqs, cci_pmu->nr_irqs))
>  			continue;
>  
> -		pmu->irqs[pmu->nr_irqs++] = irq;
> +		cci_pmu->irqs[cci_pmu->nr_irqs++] = irq;
>  	}
>  
>  	/*
> @@ -980,20 +987,31 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	raw_spin_lock_init(&pmu->hw_events.pmu_lock);
> -	mutex_init(&pmu->reserve_mutex);
> -	atomic_set(&pmu->active_events, 0);
> -	cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
> +	raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock);
> +	mutex_init(&cci_pmu->reserve_mutex);
> +	atomic_set(&cci_pmu->active_events, 0);
> +	cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
>  
> -	ret = register_cpu_notifier(&cci_pmu_cpu_nb);
> +	cci_pmu->cpu_nb = (struct notifier_block) {
> +		.notifier_call	= cci_pmu_cpu_notifier,
> +		/*
> +		 * to migrate uncore events, our notifier should be executed
> +		 * before perf core's notifier.
> +		 */
> +		.priority	= CPU_PRI_PERF + 1,
> +	};
> +
> +	ret = register_cpu_notifier(&cci_pmu->cpu_nb);
>  	if (ret)
>  		return ret;
>  
> -	ret = cci_pmu_init(pmu, pdev);
> -	if (ret)
> +	ret = cci_pmu_init(cci_pmu, pdev);
> +	if (ret) {
> +		unregister_cpu_notifier(&cci_pmu->cpu_nb);
>  		return ret;
> +	}
>  
> -	pr_info("ARM %s PMU driver probed", pmu->model->name);
> +	pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
>  	return 0;
>  }
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 2/7] arm-cci: Cleanup PMU driver code
@ 2015-05-18 10:18     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 10:18 UTC (permalink / raw)
  To: linux-arm-kernel

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> This patch gets rid of the global struct cci_pmu variable and makes
> the code use the cci_pmu explicitly. Makes code a bit more robust
> and reader friendly.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/arm-cci.c |  142 ++++++++++++++++++++++++++++---------------------
>  1 file changed, 80 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 941b831..27cc200 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -124,9 +124,9 @@ struct cci_pmu {
>  	int num_events;
>  	atomic_t active_events;
>  	struct mutex reserve_mutex;
> +	struct notifier_block cpu_nb;
>  	cpumask_t cpus;
>  };
> -static struct cci_pmu *pmu;
>  
>  #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
>  
> @@ -179,7 +179,7 @@ enum cci400_perf_events {
>  #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
>  #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
>  
> -static int pmu_validate_hw_event(unsigned long hw_event)
> +static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
>  	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
>  	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> @@ -207,8 +207,8 @@ static int pmu_validate_hw_event(unsigned long hw_event)
>  		return -ENOENT;
>  	}
>  
> -	if (ev_code >= pmu->model->event_ranges[if_type].min &&
> -		ev_code <= pmu->model->event_ranges[if_type].max)
> +	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
> +		ev_code <= cci_pmu->model->event_ranges[if_type].max)
>  		return hw_event;
>  
>  	return -ENOENT;
> @@ -239,29 +239,31 @@ static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
>  }
>  
> -static u32 pmu_read_register(int idx, unsigned int offset)
> +static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
>  {
> -	return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
>  }
>  
> -static void pmu_write_register(u32 value, int idx, unsigned int offset)
> +static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
> +			       int idx, unsigned int offset)
>  {
> -	return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return writel_relaxed(value, cci_pmu->base +
> +			      CCI_PMU_CNTR_BASE(idx) + offset);
>  }
>  
> -static void pmu_disable_counter(int idx)
> +static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL);
> +	pmu_write_register(cci_pmu, 0, idx, CCI_PMU_CNTR_CTRL);
>  }
>  
> -static void pmu_enable_counter(int idx)
> +static void pmu_enable_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL);
> +	pmu_write_register(cci_pmu, 1, idx, CCI_PMU_CNTR_CTRL);
>  }
>  
> -static void pmu_set_event(int idx, unsigned long event)
> +static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
>  {
> -	pmu_write_register(event, idx, CCI_PMU_EVT_SEL);
> +	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
>  }
>  
>  static u32 pmu_get_max_counters(void)
> @@ -306,7 +308,8 @@ static int pmu_map_event(struct perf_event *event)
>  	if (config == CCI_PMU_CYCLES)
>  		mapping = config;
>  	else
> -		mapping = pmu_validate_hw_event(config);
> +		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
> +							config);
>  
>  	return mapping;
>  }
> @@ -319,7 +322,7 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
>  	if (unlikely(!pmu_device))
>  		return -ENODEV;
>  
> -	if (pmu->nr_irqs < 1) {
> +	if (cci_pmu->nr_irqs < 1) {
>  		dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n");
>  		return -ENODEV;
>  	}
> @@ -331,16 +334,16 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
>  	 *
>  	 * This should allow handling of non-unique interrupt for the counters.
>  	 */
> -	for (i = 0; i < pmu->nr_irqs; i++) {
> -		int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED,
> +	for (i = 0; i < cci_pmu->nr_irqs; i++) {
> +		int err = request_irq(cci_pmu->irqs[i], handler, IRQF_SHARED,
>  				"arm-cci-pmu", cci_pmu);
>  		if (err) {
>  			dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n",
> -				pmu->irqs[i]);
> +				cci_pmu->irqs[i]);
>  			return err;
>  		}
>  
> -		set_bit(i, &pmu->active_irqs);
> +		set_bit(i, &cci_pmu->active_irqs);
>  	}
>  
>  	return 0;
> @@ -350,11 +353,11 @@ static void pmu_free_irq(struct cci_pmu *cci_pmu)
>  {
>  	int i;
>  
> -	for (i = 0; i < pmu->nr_irqs; i++) {
> -		if (!test_and_clear_bit(i, &pmu->active_irqs))
> +	for (i = 0; i < cci_pmu->nr_irqs; i++) {
> +		if (!test_and_clear_bit(i, &cci_pmu->active_irqs))
>  			continue;
>  
> -		free_irq(pmu->irqs[i], cci_pmu);
> +		free_irq(cci_pmu->irqs[i], cci_pmu);
>  	}
>  }
>  
> @@ -369,7 +372,7 @@ static u32 pmu_read_counter(struct perf_event *event)
>  		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
>  		return 0;
>  	}
> -	value = pmu_read_register(idx, CCI_PMU_CNTR);
> +	value = pmu_read_register(cci_pmu, idx, CCI_PMU_CNTR);
>  
>  	return value;
>  }
> @@ -383,7 +386,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value)
>  	if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
>  		dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
>  	else
> -		pmu_write_register(value, idx, CCI_PMU_CNTR);
> +		pmu_write_register(cci_pmu, value, idx, CCI_PMU_CNTR);
>  }
>  
>  static u64 pmu_event_update(struct perf_event *event)
> @@ -427,7 +430,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  {
>  	unsigned long flags;
>  	struct cci_pmu *cci_pmu = dev;
> -	struct cci_pmu_hw_events *events = &pmu->hw_events;
> +	struct cci_pmu_hw_events *events = &cci_pmu->hw_events;
>  	int idx, handled = IRQ_NONE;
>  
>  	raw_spin_lock_irqsave(&events->pmu_lock, flags);
> @@ -446,11 +449,12 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  		hw_counter = &event->hw;
>  
>  		/* Did this counter overflow? */
> -		if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) &
> +		if (!(pmu_read_register(cci_pmu, idx, CCI_PMU_OVRFLW) &
>  		      CCI_PMU_OVRFLW_FLAG))
>  			continue;
>  
> -		pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
> +		pmu_write_register(cci_pmu, CCI_PMU_OVRFLW_FLAG, idx,
> +							CCI_PMU_OVRFLW);
>  
>  		pmu_event_update(event);
>  		pmu_event_set_period(event);
> @@ -549,10 +553,10 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
>  
>  	/* Configure the event to count, unless you are counting cycles */
>  	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
> -		pmu_set_event(idx, hwc->config_base);
> +		pmu_set_event(cci_pmu, idx, hwc->config_base);
>  
>  	pmu_event_set_period(event);
> -	pmu_enable_counter(idx);
> +	pmu_enable_counter(cci_pmu, idx);
>  
>  	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
>  }
> @@ -575,7 +579,7 @@ static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
>  	 * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
>  	 * cci_pmu_start()
>  	 */
> -	pmu_disable_counter(idx);
> +	pmu_disable_counter(cci_pmu, idx);
>  	pmu_event_update(event);
>  	hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
>  }
> @@ -779,20 +783,27 @@ static int cci_pmu_event_init(struct perf_event *event)
>  	return err;
>  }
>  
> -static ssize_t pmu_attr_cpumask_show(struct device *dev,
> +static ssize_t pmu_cpumask_attr_show(struct device *dev,
>  				     struct device_attribute *attr, char *buf)
>  {
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +					struct dev_ext_attribute, attr);
> +	struct cci_pmu *cci_pmu = eattr->var;
> +
>  	int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
> -			  cpumask_pr_args(&pmu->cpus));
> +			  cpumask_pr_args(&cci_pmu->cpus));
>  	buf[n++] = '\n';
>  	buf[n] = '\0';
>  	return n;
>  }
>  
> -static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
> +static struct dev_ext_attribute pmu_cpumask_attr = {
> +	__ATTR(cpumask, S_IRUGO, pmu_cpumask_attr_show, NULL),
> +	NULL,		/* Populated in cci_pmu_init */
> +};
>  
>  static struct attribute *pmu_attrs[] = {
> -	&dev_attr_cpumask.attr,
> +	&pmu_cpumask_attr.attr.attr,
>  	NULL,
>  };
>  
> @@ -808,6 +819,8 @@ static const struct attribute_group *pmu_attr_groups[] = {
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
> +
> +	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
>  		.name		= cci_pmu->model->name,
>  		.task_ctx_nr	= perf_invalid_context,
> @@ -831,12 +844,14 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  				unsigned long action, void *hcpu)
>  {
> +	struct cci_pmu *cci_pmu = container_of(self,
> +					struct cci_pmu, cpu_nb);
>  	unsigned int cpu = (long)hcpu;
>  	unsigned int target;
>  
>  	switch (action & ~CPU_TASKS_FROZEN) {
>  	case CPU_DOWN_PREPARE:
> -		if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
> +		if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
>  			break;
>  		target = cpumask_any_but(cpu_online_mask, cpu);
>  		if (target < 0) // UP, last CPU
> @@ -845,7 +860,7 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  		 * TODO: migrate context once core races on event->ctx have
>  		 * been fixed.
>  		 */
> -		cpumask_set_cpu(target, &pmu->cpus);
> +		cpumask_set_cpu(target, &cci_pmu->cpus);
>  	default:
>  		break;
>  	}
> @@ -853,15 +868,6 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  	return NOTIFY_OK;
>  }
>  
> -static struct notifier_block cci_pmu_cpu_nb = {
> -	.notifier_call	= cci_pmu_cpu_notifier,
> -	/*
> -	 * to migrate uncore events, our notifier should be executed
> -	 * before perf core's notifier.
> -	 */
> -	.priority	= CPU_PRI_PERF + 1,
> -};
> -
>  static struct cci_pmu_model cci_pmu_models[] = {
>  	[CCI_REV_R0] = {
>  		.name = "CCI_400",
> @@ -935,6 +941,7 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
>  static int cci_pmu_probe(struct platform_device *pdev)
>  {
>  	struct resource *res;
> +	struct cci_pmu *cci_pmu;
>  	int i, ret, irq;
>  	const struct cci_pmu_model *model;
>  
> @@ -944,30 +951,30 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  		return -ENODEV;
>  	}
>  
> -	pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
> -	if (!pmu)
> +	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
> +	if (!cci_pmu)
>  		return -ENOMEM;
>  
> -	pmu->model = model;
> +	cci_pmu->model = model;
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	pmu->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(pmu->base))
> +	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(cci_pmu->base))
>  		return -ENOMEM;
>  
>  	/*
>  	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
>  	 * together to a common interrupt.
>  	 */
> -	pmu->nr_irqs = 0;
> +	cci_pmu->nr_irqs = 0;
>  	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
>  		irq = platform_get_irq(pdev, i);
>  		if (irq < 0)
>  			break;
>  
> -		if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs))
> +		if (is_duplicate_irq(irq, cci_pmu->irqs, cci_pmu->nr_irqs))
>  			continue;
>  
> -		pmu->irqs[pmu->nr_irqs++] = irq;
> +		cci_pmu->irqs[cci_pmu->nr_irqs++] = irq;
>  	}
>  
>  	/*
> @@ -980,20 +987,31 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	raw_spin_lock_init(&pmu->hw_events.pmu_lock);
> -	mutex_init(&pmu->reserve_mutex);
> -	atomic_set(&pmu->active_events, 0);
> -	cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
> +	raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock);
> +	mutex_init(&cci_pmu->reserve_mutex);
> +	atomic_set(&cci_pmu->active_events, 0);
> +	cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
>  
> -	ret = register_cpu_notifier(&cci_pmu_cpu_nb);
> +	cci_pmu->cpu_nb = (struct notifier_block) {
> +		.notifier_call	= cci_pmu_cpu_notifier,
> +		/*
> +		 * to migrate uncore events, our notifier should be executed
> +		 * before perf core's notifier.
> +		 */
> +		.priority	= CPU_PRI_PERF + 1,
> +	};
> +
> +	ret = register_cpu_notifier(&cci_pmu->cpu_nb);
>  	if (ret)
>  		return ret;
>  
> -	ret = cci_pmu_init(pmu, pdev);
> -	if (ret)
> +	ret = cci_pmu_init(cci_pmu, pdev);
> +	if (ret) {
> +		unregister_cpu_notifier(&cci_pmu->cpu_nb);
>  		return ret;
> +	}
>  
> -	pr_info("ARM %s PMU driver probed", pmu->model->name);
> +	pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
>  	return 0;
>  }

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 3/7] arm-cci: Abstract out the PMU counter details
@ 2015-05-18 11:54     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 11:54 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel, Mark Rutland, devicetree, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon, linux-kernel, arm,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Adds the PMU model specific counters to the PMU model
> abstraction to make it easier to add a new PMU.
>
> The patch cleans up the naming convention used all over
> the code.
> e.g, CCI_PMU_MAX_HW_EVENTS => maximum number of events that
> can be counted at any time, which is in fact the maximum
> number of counters available.
>
> Change all such namings to use 'counters' instead of events.
>
> This patch also abstracts the following:
>
> 1) Size of a PMU event counter area.
> 2) Maximum number of programmable counters supported by the PMU model
> 3) Number of counters which counts fixed events (e.g, cycle
>   counter on CCI-400).
>
> Also changes some of the static allocation of the data
> structures to dynamic, to accommodate the number of events
> supported by a PMU.
>
> Gets rid ofthe CCI_PMU_* defines for the model. All such
> data should be accessed via the model abstraction.
>
> Limits the number of counters to the maximum supported
> by the 'model'.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/arm-cci.c |  123 +++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 93 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 27cc200..82d5681 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -77,15 +77,17 @@ static const struct of_device_id arm_cci_matches[] = {
>  
>  #define CCI_PMU_OVRFLW_FLAG	1
>  
> -#define CCI_PMU_CNTR_BASE(idx)	((idx) * SZ_4K)
> -
> -#define CCI_PMU_CNTR_MASK	((1ULL << 32) -1)
> +#define CCI_PMU_CNTR_SIZE(model)	((model)->cntr_size)
> +#define CCI_PMU_CNTR_BASE(model, idx)	((idx) * CCI_PMU_CNTR_SIZE(model))
> +#define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
> +#define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
>  
>  #define CCI_PMU_EVENT_MASK		0xffUL
>  #define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
>  #define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
>  
> -#define CCI_PMU_MAX_HW_EVENTS 5   /* CCI PMU has 4 counters + 1 cycle counter */
> +#define CCI_PMU_MAX_HW_CNTRS(model) \
> +	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
>  
>  /* Types of interfaces that can generate events */
>  enum {
> @@ -100,13 +102,22 @@ struct event_range {
>  };
>  
>  struct cci_pmu_hw_events {
> -	struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
> -	unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
> +	struct perf_event **events;
> +	unsigned long *used_mask;
>  	raw_spinlock_t pmu_lock;
>  };
>  
> +/*
> + * struct cci_pmu_model:
> + * @fixed_hw_cntrs - Number of fixed event counters
> + * @num_hw_cntrs - Maximum number of programmable event counters
> + * @cntr_size - Size of an event counter mapping
> + */
>  struct cci_pmu_model {
>  	char *name;
> +	u32 fixed_hw_cntrs;
> +	u32 num_hw_cntrs;
> +	u32 cntr_size;
>  	struct event_range event_ranges[CCI_IF_MAX];
>  };
>  
> @@ -116,12 +127,12 @@ struct cci_pmu {
>  	void __iomem *base;
>  	struct pmu pmu;
>  	int nr_irqs;
> -	int irqs[CCI_PMU_MAX_HW_EVENTS];
> +	int *irqs;
>  	unsigned long active_irqs;
>  	const struct cci_pmu_model *model;
>  	struct cci_pmu_hw_events hw_events;
>  	struct platform_device *plat_device;
> -	int num_events;
> +	int num_cntrs;
>  	atomic_t active_events;
>  	struct mutex reserve_mutex;
>  	struct notifier_block cpu_nb;
> @@ -155,7 +166,6 @@ enum cci400_perf_events {
>  
>  #define CCI_PMU_CYCLE_CNTR_IDX		0
>  #define CCI_PMU_CNTR0_IDX		1
> -#define CCI_PMU_CNTR_LAST(cci_pmu)	(CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1)
>  
>  /*
>   * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
> @@ -235,20 +245,20 @@ static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
>  
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
> -		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> +	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
>  }
>  
>  static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
>  {
> -	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return readl_relaxed(cci_pmu->base +
> +			     CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
>  }
>  
>  static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
>  			       int idx, unsigned int offset)
>  {
>  	return writel_relaxed(value, cci_pmu->base +
> -			      CCI_PMU_CNTR_BASE(idx) + offset);
> +			      CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
>  }
>  
>  static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
> @@ -266,13 +276,14 @@ static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
>  	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
>  }
>  
> +/*
> + * Returns the number of programmable counters actually implemented
> + * by the cci
> + */
>  static u32 pmu_get_max_counters(void)
>  {
> -	u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
> -		      CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
> -
> -	/* add 1 for cycle counter */
> -	return n_cnts + 1;
> +	return (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
> +		CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
>  }
>  
>  static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
> @@ -496,7 +507,7 @@ static void cci_pmu_enable(struct pmu *pmu)
>  {
>  	struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
>  	struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
> -	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
> +	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_cntrs);
>  	unsigned long flags;
>  	u32 val;
>  
> @@ -659,13 +670,16 @@ static int
>  validate_group(struct perf_event *event)
>  {
>  	struct perf_event *sibling, *leader = event->group_leader;
> +	struct cci_pmu  *cci_pmu = to_cci_pmu(event->pmu);
> +	unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
>  	struct cci_pmu_hw_events fake_pmu = {
>  		/*
>  		 * Initialise the fake PMU. We only need to populate the
>  		 * used_mask for the purposes of validation.
>  		 */
> -		.used_mask =  { 0 },
> +		.used_mask = mask,
>  	};
> +	memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
>  
>  	if (!validate_event(event->pmu, &fake_pmu, leader))
>  		return -EINVAL;
> @@ -819,6 +833,7 @@ static const struct attribute_group *pmu_attr_groups[] = {
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
> +	u32 num_cntrs;
>  
>  	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
> @@ -836,7 +851,15 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  	};
>  
>  	cci_pmu->plat_device = pdev;
> -	cci_pmu->num_events = pmu_get_max_counters();
> +	num_cntrs = pmu_get_max_counters();
> +	if (num_cntrs > cci_pmu->model->num_hw_cntrs) {
> +		dev_warn(&pdev->dev,
> +			"PMU implements more counters(%d) than supported by"
> +			" the model(%d), truncated.",
> +			num_cntrs, cci_pmu->model->num_hw_cntrs);
> +		num_cntrs = cci_pmu->model->num_hw_cntrs;
> +	}
> +	cci_pmu->num_cntrs = num_cntrs + cci_pmu->model->fixed_hw_cntrs;
>  
>  	return perf_pmu_register(&cci_pmu->pmu, name, -1);
>  }
> @@ -871,6 +894,9 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  static struct cci_pmu_model cci_pmu_models[] = {
>  	[CCI_REV_R0] = {
>  		.name = "CCI_400",
> +		.fixed_hw_cntrs = 1,	/* Cycle counter */
> +		.num_hw_cntrs = 4,
> +		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI_REV_R0_SLAVE_PORT_MIN_EV,
> @@ -884,6 +910,9 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  	},
>  	[CCI_REV_R1] = {
>  		.name = "CCI_400_r1",
> +		.fixed_hw_cntrs = 1,	/* Cycle counter */
> +		.num_hw_cntrs = 4,
> +		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI_REV_R1_SLAVE_PORT_MIN_EV,
> @@ -938,35 +967,69 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
>  	return false;
>  }
>  
> -static int cci_pmu_probe(struct platform_device *pdev)
> +static struct cci_pmu *cci_pmu_alloc(struct platform_device *pdev)
>  {
> -	struct resource *res;
>  	struct cci_pmu *cci_pmu;
> -	int i, ret, irq;
>  	const struct cci_pmu_model *model;
>  
> +	/*
> +	 * All allocations are devm_* hence we don't have to free
> +	 * them explicitly on an error, as it would end up in driver
> +	 * detach.
> +	 */
>  	model = get_cci_model(pdev);
>  	if (!model) {
>  		dev_warn(&pdev->dev, "CCI PMU version not supported\n");
> -		return -ENODEV;
> +		return ERR_PTR(-ENODEV);
>  	}
>  
>  	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
>  	if (!cci_pmu)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  
>  	cci_pmu->model = model;
> +	cci_pmu->irqs = devm_kcalloc(&pdev->dev, CCI_PMU_MAX_HW_CNTRS(model),
> +					sizeof(*cci_pmu->irqs), GFP_KERNEL);
> +	if (!cci_pmu->irqs)
> +		return ERR_PTR(-ENOMEM);
> +	cci_pmu->hw_events.events = devm_kcalloc(&pdev->dev,
> +					     CCI_PMU_MAX_HW_CNTRS(model),
> +					     sizeof(*cci_pmu->hw_events.events),
> +					     GFP_KERNEL);
> +	if (!cci_pmu->hw_events.events)
> +		return ERR_PTR(-ENOMEM);
> +	cci_pmu->hw_events.used_mask = devm_kcalloc(&pdev->dev,
> +						BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
> +						sizeof(*cci_pmu->hw_events.used_mask),
> +						GFP_KERNEL);
> +	if (!cci_pmu->hw_events.used_mask)
> +		return ERR_PTR(-ENOMEM);
> +
> +	return cci_pmu;
> +}
> +
> +
> +static int cci_pmu_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct cci_pmu *cci_pmu;
> +	int i, ret, irq;
> +
> +	cci_pmu = cci_pmu_alloc(pdev);
> +	if (IS_ERR(cci_pmu))
> +		return PTR_ERR(cci_pmu);
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(cci_pmu->base))
>  		return -ENOMEM;
>  
>  	/*
> -	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
> +	 * CCI PMU has one overflow interrupt per counter; but some may be tied
>  	 * together to a common interrupt.
>  	 */
>  	cci_pmu->nr_irqs = 0;
> -	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
> +	for (i = 0; i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model); i++) {
>  		irq = platform_get_irq(pdev, i);
>  		if (irq < 0)
>  			break;
> @@ -981,9 +1044,9 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  	 * Ensure that the device tree has as many interrupts as the number
>  	 * of counters.
>  	 */
> -	if (i < CCI_PMU_MAX_HW_EVENTS) {
> +	if (i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model)) {
>  		dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n",
> -			i, CCI_PMU_MAX_HW_EVENTS);
> +			i, CCI_PMU_MAX_HW_CNTRS(cci_pmu->model));
>  		return -EINVAL;
>  	}

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 3/7] arm-cci: Abstract out the PMU counter details
@ 2015-05-18 11:54     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 11:54 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, arm-DgEjT+Ai2ygdnm+yROfE0A,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
>
> Adds the PMU model specific counters to the PMU model
> abstraction to make it easier to add a new PMU.
>
> The patch cleans up the naming convention used all over
> the code.
> e.g, CCI_PMU_MAX_HW_EVENTS => maximum number of events that
> can be counted at any time, which is in fact the maximum
> number of counters available.
>
> Change all such namings to use 'counters' instead of events.
>
> This patch also abstracts the following:
>
> 1) Size of a PMU event counter area.
> 2) Maximum number of programmable counters supported by the PMU model
> 3) Number of counters which counts fixed events (e.g, cycle
>   counter on CCI-400).
>
> Also changes some of the static allocation of the data
> structures to dynamic, to accommodate the number of events
> supported by a PMU.
>
> Gets rid ofthe CCI_PMU_* defines for the model. All such
> data should be accessed via the model abstraction.
>
> Limits the number of counters to the maximum supported
> by the 'model'.
>
> Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

Acked-by: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>

> ---
>  drivers/bus/arm-cci.c |  123 +++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 93 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 27cc200..82d5681 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -77,15 +77,17 @@ static const struct of_device_id arm_cci_matches[] = {
>  
>  #define CCI_PMU_OVRFLW_FLAG	1
>  
> -#define CCI_PMU_CNTR_BASE(idx)	((idx) * SZ_4K)
> -
> -#define CCI_PMU_CNTR_MASK	((1ULL << 32) -1)
> +#define CCI_PMU_CNTR_SIZE(model)	((model)->cntr_size)
> +#define CCI_PMU_CNTR_BASE(model, idx)	((idx) * CCI_PMU_CNTR_SIZE(model))
> +#define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
> +#define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
>  
>  #define CCI_PMU_EVENT_MASK		0xffUL
>  #define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
>  #define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
>  
> -#define CCI_PMU_MAX_HW_EVENTS 5   /* CCI PMU has 4 counters + 1 cycle counter */
> +#define CCI_PMU_MAX_HW_CNTRS(model) \
> +	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
>  
>  /* Types of interfaces that can generate events */
>  enum {
> @@ -100,13 +102,22 @@ struct event_range {
>  };
>  
>  struct cci_pmu_hw_events {
> -	struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
> -	unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
> +	struct perf_event **events;
> +	unsigned long *used_mask;
>  	raw_spinlock_t pmu_lock;
>  };
>  
> +/*
> + * struct cci_pmu_model:
> + * @fixed_hw_cntrs - Number of fixed event counters
> + * @num_hw_cntrs - Maximum number of programmable event counters
> + * @cntr_size - Size of an event counter mapping
> + */
>  struct cci_pmu_model {
>  	char *name;
> +	u32 fixed_hw_cntrs;
> +	u32 num_hw_cntrs;
> +	u32 cntr_size;
>  	struct event_range event_ranges[CCI_IF_MAX];
>  };
>  
> @@ -116,12 +127,12 @@ struct cci_pmu {
>  	void __iomem *base;
>  	struct pmu pmu;
>  	int nr_irqs;
> -	int irqs[CCI_PMU_MAX_HW_EVENTS];
> +	int *irqs;
>  	unsigned long active_irqs;
>  	const struct cci_pmu_model *model;
>  	struct cci_pmu_hw_events hw_events;
>  	struct platform_device *plat_device;
> -	int num_events;
> +	int num_cntrs;
>  	atomic_t active_events;
>  	struct mutex reserve_mutex;
>  	struct notifier_block cpu_nb;
> @@ -155,7 +166,6 @@ enum cci400_perf_events {
>  
>  #define CCI_PMU_CYCLE_CNTR_IDX		0
>  #define CCI_PMU_CNTR0_IDX		1
> -#define CCI_PMU_CNTR_LAST(cci_pmu)	(CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1)
>  
>  /*
>   * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
> @@ -235,20 +245,20 @@ static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
>  
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
> -		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> +	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
>  }
>  
>  static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
>  {
> -	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return readl_relaxed(cci_pmu->base +
> +			     CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
>  }
>  
>  static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
>  			       int idx, unsigned int offset)
>  {
>  	return writel_relaxed(value, cci_pmu->base +
> -			      CCI_PMU_CNTR_BASE(idx) + offset);
> +			      CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
>  }
>  
>  static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
> @@ -266,13 +276,14 @@ static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
>  	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
>  }
>  
> +/*
> + * Returns the number of programmable counters actually implemented
> + * by the cci
> + */
>  static u32 pmu_get_max_counters(void)
>  {
> -	u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
> -		      CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
> -
> -	/* add 1 for cycle counter */
> -	return n_cnts + 1;
> +	return (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
> +		CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
>  }
>  
>  static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
> @@ -496,7 +507,7 @@ static void cci_pmu_enable(struct pmu *pmu)
>  {
>  	struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
>  	struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
> -	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
> +	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_cntrs);
>  	unsigned long flags;
>  	u32 val;
>  
> @@ -659,13 +670,16 @@ static int
>  validate_group(struct perf_event *event)
>  {
>  	struct perf_event *sibling, *leader = event->group_leader;
> +	struct cci_pmu  *cci_pmu = to_cci_pmu(event->pmu);
> +	unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
>  	struct cci_pmu_hw_events fake_pmu = {
>  		/*
>  		 * Initialise the fake PMU. We only need to populate the
>  		 * used_mask for the purposes of validation.
>  		 */
> -		.used_mask =  { 0 },
> +		.used_mask = mask,
>  	};
> +	memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
>  
>  	if (!validate_event(event->pmu, &fake_pmu, leader))
>  		return -EINVAL;
> @@ -819,6 +833,7 @@ static const struct attribute_group *pmu_attr_groups[] = {
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
> +	u32 num_cntrs;
>  
>  	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
> @@ -836,7 +851,15 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  	};
>  
>  	cci_pmu->plat_device = pdev;
> -	cci_pmu->num_events = pmu_get_max_counters();
> +	num_cntrs = pmu_get_max_counters();
> +	if (num_cntrs > cci_pmu->model->num_hw_cntrs) {
> +		dev_warn(&pdev->dev,
> +			"PMU implements more counters(%d) than supported by"
> +			" the model(%d), truncated.",
> +			num_cntrs, cci_pmu->model->num_hw_cntrs);
> +		num_cntrs = cci_pmu->model->num_hw_cntrs;
> +	}
> +	cci_pmu->num_cntrs = num_cntrs + cci_pmu->model->fixed_hw_cntrs;
>  
>  	return perf_pmu_register(&cci_pmu->pmu, name, -1);
>  }
> @@ -871,6 +894,9 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  static struct cci_pmu_model cci_pmu_models[] = {
>  	[CCI_REV_R0] = {
>  		.name = "CCI_400",
> +		.fixed_hw_cntrs = 1,	/* Cycle counter */
> +		.num_hw_cntrs = 4,
> +		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI_REV_R0_SLAVE_PORT_MIN_EV,
> @@ -884,6 +910,9 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  	},
>  	[CCI_REV_R1] = {
>  		.name = "CCI_400_r1",
> +		.fixed_hw_cntrs = 1,	/* Cycle counter */
> +		.num_hw_cntrs = 4,
> +		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI_REV_R1_SLAVE_PORT_MIN_EV,
> @@ -938,35 +967,69 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
>  	return false;
>  }
>  
> -static int cci_pmu_probe(struct platform_device *pdev)
> +static struct cci_pmu *cci_pmu_alloc(struct platform_device *pdev)
>  {
> -	struct resource *res;
>  	struct cci_pmu *cci_pmu;
> -	int i, ret, irq;
>  	const struct cci_pmu_model *model;
>  
> +	/*
> +	 * All allocations are devm_* hence we don't have to free
> +	 * them explicitly on an error, as it would end up in driver
> +	 * detach.
> +	 */
>  	model = get_cci_model(pdev);
>  	if (!model) {
>  		dev_warn(&pdev->dev, "CCI PMU version not supported\n");
> -		return -ENODEV;
> +		return ERR_PTR(-ENODEV);
>  	}
>  
>  	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
>  	if (!cci_pmu)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  
>  	cci_pmu->model = model;
> +	cci_pmu->irqs = devm_kcalloc(&pdev->dev, CCI_PMU_MAX_HW_CNTRS(model),
> +					sizeof(*cci_pmu->irqs), GFP_KERNEL);
> +	if (!cci_pmu->irqs)
> +		return ERR_PTR(-ENOMEM);
> +	cci_pmu->hw_events.events = devm_kcalloc(&pdev->dev,
> +					     CCI_PMU_MAX_HW_CNTRS(model),
> +					     sizeof(*cci_pmu->hw_events.events),
> +					     GFP_KERNEL);
> +	if (!cci_pmu->hw_events.events)
> +		return ERR_PTR(-ENOMEM);
> +	cci_pmu->hw_events.used_mask = devm_kcalloc(&pdev->dev,
> +						BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
> +						sizeof(*cci_pmu->hw_events.used_mask),
> +						GFP_KERNEL);
> +	if (!cci_pmu->hw_events.used_mask)
> +		return ERR_PTR(-ENOMEM);
> +
> +	return cci_pmu;
> +}
> +
> +
> +static int cci_pmu_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct cci_pmu *cci_pmu;
> +	int i, ret, irq;
> +
> +	cci_pmu = cci_pmu_alloc(pdev);
> +	if (IS_ERR(cci_pmu))
> +		return PTR_ERR(cci_pmu);
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(cci_pmu->base))
>  		return -ENOMEM;
>  
>  	/*
> -	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
> +	 * CCI PMU has one overflow interrupt per counter; but some may be tied
>  	 * together to a common interrupt.
>  	 */
>  	cci_pmu->nr_irqs = 0;
> -	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
> +	for (i = 0; i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model); i++) {
>  		irq = platform_get_irq(pdev, i);
>  		if (irq < 0)
>  			break;
> @@ -981,9 +1044,9 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  	 * Ensure that the device tree has as many interrupts as the number
>  	 * of counters.
>  	 */
> -	if (i < CCI_PMU_MAX_HW_EVENTS) {
> +	if (i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model)) {
>  		dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n",
> -			i, CCI_PMU_MAX_HW_EVENTS);
> +			i, CCI_PMU_MAX_HW_CNTRS(cci_pmu->model));
>  		return -EINVAL;
>  	}
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 3/7] arm-cci: Abstract out the PMU counter details
@ 2015-05-18 11:54     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 11:54 UTC (permalink / raw)
  To: linux-arm-kernel

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Adds the PMU model specific counters to the PMU model
> abstraction to make it easier to add a new PMU.
>
> The patch cleans up the naming convention used all over
> the code.
> e.g, CCI_PMU_MAX_HW_EVENTS => maximum number of events that
> can be counted at any time, which is in fact the maximum
> number of counters available.
>
> Change all such namings to use 'counters' instead of events.
>
> This patch also abstracts the following:
>
> 1) Size of a PMU event counter area.
> 2) Maximum number of programmable counters supported by the PMU model
> 3) Number of counters which counts fixed events (e.g, cycle
>   counter on CCI-400).
>
> Also changes some of the static allocation of the data
> structures to dynamic, to accommodate the number of events
> supported by a PMU.
>
> Gets rid ofthe CCI_PMU_* defines for the model. All such
> data should be accessed via the model abstraction.
>
> Limits the number of counters to the maximum supported
> by the 'model'.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/arm-cci.c |  123 +++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 93 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 27cc200..82d5681 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -77,15 +77,17 @@ static const struct of_device_id arm_cci_matches[] = {
>  
>  #define CCI_PMU_OVRFLW_FLAG	1
>  
> -#define CCI_PMU_CNTR_BASE(idx)	((idx) * SZ_4K)
> -
> -#define CCI_PMU_CNTR_MASK	((1ULL << 32) -1)
> +#define CCI_PMU_CNTR_SIZE(model)	((model)->cntr_size)
> +#define CCI_PMU_CNTR_BASE(model, idx)	((idx) * CCI_PMU_CNTR_SIZE(model))
> +#define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
> +#define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
>  
>  #define CCI_PMU_EVENT_MASK		0xffUL
>  #define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
>  #define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
>  
> -#define CCI_PMU_MAX_HW_EVENTS 5   /* CCI PMU has 4 counters + 1 cycle counter */
> +#define CCI_PMU_MAX_HW_CNTRS(model) \
> +	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
>  
>  /* Types of interfaces that can generate events */
>  enum {
> @@ -100,13 +102,22 @@ struct event_range {
>  };
>  
>  struct cci_pmu_hw_events {
> -	struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
> -	unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
> +	struct perf_event **events;
> +	unsigned long *used_mask;
>  	raw_spinlock_t pmu_lock;
>  };
>  
> +/*
> + * struct cci_pmu_model:
> + * @fixed_hw_cntrs - Number of fixed event counters
> + * @num_hw_cntrs - Maximum number of programmable event counters
> + * @cntr_size - Size of an event counter mapping
> + */
>  struct cci_pmu_model {
>  	char *name;
> +	u32 fixed_hw_cntrs;
> +	u32 num_hw_cntrs;
> +	u32 cntr_size;
>  	struct event_range event_ranges[CCI_IF_MAX];
>  };
>  
> @@ -116,12 +127,12 @@ struct cci_pmu {
>  	void __iomem *base;
>  	struct pmu pmu;
>  	int nr_irqs;
> -	int irqs[CCI_PMU_MAX_HW_EVENTS];
> +	int *irqs;
>  	unsigned long active_irqs;
>  	const struct cci_pmu_model *model;
>  	struct cci_pmu_hw_events hw_events;
>  	struct platform_device *plat_device;
> -	int num_events;
> +	int num_cntrs;
>  	atomic_t active_events;
>  	struct mutex reserve_mutex;
>  	struct notifier_block cpu_nb;
> @@ -155,7 +166,6 @@ enum cci400_perf_events {
>  
>  #define CCI_PMU_CYCLE_CNTR_IDX		0
>  #define CCI_PMU_CNTR0_IDX		1
> -#define CCI_PMU_CNTR_LAST(cci_pmu)	(CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1)
>  
>  /*
>   * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
> @@ -235,20 +245,20 @@ static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
>  
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> -	return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
> -		idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> +	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
>  }
>  
>  static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
>  {
> -	return readl_relaxed(cci_pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
> +	return readl_relaxed(cci_pmu->base +
> +			     CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
>  }
>  
>  static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
>  			       int idx, unsigned int offset)
>  {
>  	return writel_relaxed(value, cci_pmu->base +
> -			      CCI_PMU_CNTR_BASE(idx) + offset);
> +			      CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
>  }
>  
>  static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
> @@ -266,13 +276,14 @@ static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
>  	pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
>  }
>  
> +/*
> + * Returns the number of programmable counters actually implemented
> + * by the cci
> + */
>  static u32 pmu_get_max_counters(void)
>  {
> -	u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
> -		      CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
> -
> -	/* add 1 for cycle counter */
> -	return n_cnts + 1;
> +	return (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
> +		CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
>  }
>  
>  static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
> @@ -496,7 +507,7 @@ static void cci_pmu_enable(struct pmu *pmu)
>  {
>  	struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
>  	struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
> -	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
> +	int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_cntrs);
>  	unsigned long flags;
>  	u32 val;
>  
> @@ -659,13 +670,16 @@ static int
>  validate_group(struct perf_event *event)
>  {
>  	struct perf_event *sibling, *leader = event->group_leader;
> +	struct cci_pmu  *cci_pmu = to_cci_pmu(event->pmu);
> +	unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
>  	struct cci_pmu_hw_events fake_pmu = {
>  		/*
>  		 * Initialise the fake PMU. We only need to populate the
>  		 * used_mask for the purposes of validation.
>  		 */
> -		.used_mask =  { 0 },
> +		.used_mask = mask,
>  	};
> +	memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
>  
>  	if (!validate_event(event->pmu, &fake_pmu, leader))
>  		return -EINVAL;
> @@ -819,6 +833,7 @@ static const struct attribute_group *pmu_attr_groups[] = {
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
> +	u32 num_cntrs;
>  
>  	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
> @@ -836,7 +851,15 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  	};
>  
>  	cci_pmu->plat_device = pdev;
> -	cci_pmu->num_events = pmu_get_max_counters();
> +	num_cntrs = pmu_get_max_counters();
> +	if (num_cntrs > cci_pmu->model->num_hw_cntrs) {
> +		dev_warn(&pdev->dev,
> +			"PMU implements more counters(%d) than supported by"
> +			" the model(%d), truncated.",
> +			num_cntrs, cci_pmu->model->num_hw_cntrs);
> +		num_cntrs = cci_pmu->model->num_hw_cntrs;
> +	}
> +	cci_pmu->num_cntrs = num_cntrs + cci_pmu->model->fixed_hw_cntrs;
>  
>  	return perf_pmu_register(&cci_pmu->pmu, name, -1);
>  }
> @@ -871,6 +894,9 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  static struct cci_pmu_model cci_pmu_models[] = {
>  	[CCI_REV_R0] = {
>  		.name = "CCI_400",
> +		.fixed_hw_cntrs = 1,	/* Cycle counter */
> +		.num_hw_cntrs = 4,
> +		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI_REV_R0_SLAVE_PORT_MIN_EV,
> @@ -884,6 +910,9 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  	},
>  	[CCI_REV_R1] = {
>  		.name = "CCI_400_r1",
> +		.fixed_hw_cntrs = 1,	/* Cycle counter */
> +		.num_hw_cntrs = 4,
> +		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI_REV_R1_SLAVE_PORT_MIN_EV,
> @@ -938,35 +967,69 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
>  	return false;
>  }
>  
> -static int cci_pmu_probe(struct platform_device *pdev)
> +static struct cci_pmu *cci_pmu_alloc(struct platform_device *pdev)
>  {
> -	struct resource *res;
>  	struct cci_pmu *cci_pmu;
> -	int i, ret, irq;
>  	const struct cci_pmu_model *model;
>  
> +	/*
> +	 * All allocations are devm_* hence we don't have to free
> +	 * them explicitly on an error, as it would end up in driver
> +	 * detach.
> +	 */
>  	model = get_cci_model(pdev);
>  	if (!model) {
>  		dev_warn(&pdev->dev, "CCI PMU version not supported\n");
> -		return -ENODEV;
> +		return ERR_PTR(-ENODEV);
>  	}
>  
>  	cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
>  	if (!cci_pmu)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  
>  	cci_pmu->model = model;
> +	cci_pmu->irqs = devm_kcalloc(&pdev->dev, CCI_PMU_MAX_HW_CNTRS(model),
> +					sizeof(*cci_pmu->irqs), GFP_KERNEL);
> +	if (!cci_pmu->irqs)
> +		return ERR_PTR(-ENOMEM);
> +	cci_pmu->hw_events.events = devm_kcalloc(&pdev->dev,
> +					     CCI_PMU_MAX_HW_CNTRS(model),
> +					     sizeof(*cci_pmu->hw_events.events),
> +					     GFP_KERNEL);
> +	if (!cci_pmu->hw_events.events)
> +		return ERR_PTR(-ENOMEM);
> +	cci_pmu->hw_events.used_mask = devm_kcalloc(&pdev->dev,
> +						BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
> +						sizeof(*cci_pmu->hw_events.used_mask),
> +						GFP_KERNEL);
> +	if (!cci_pmu->hw_events.used_mask)
> +		return ERR_PTR(-ENOMEM);
> +
> +	return cci_pmu;
> +}
> +
> +
> +static int cci_pmu_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct cci_pmu *cci_pmu;
> +	int i, ret, irq;
> +
> +	cci_pmu = cci_pmu_alloc(pdev);
> +	if (IS_ERR(cci_pmu))
> +		return PTR_ERR(cci_pmu);
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(cci_pmu->base))
>  		return -ENOMEM;
>  
>  	/*
> -	 * CCI PMU has 5 overflow signals - one per counter; but some may be tied
> +	 * CCI PMU has one overflow interrupt per counter; but some may be tied
>  	 * together to a common interrupt.
>  	 */
>  	cci_pmu->nr_irqs = 0;
> -	for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
> +	for (i = 0; i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model); i++) {
>  		irq = platform_get_irq(pdev, i);
>  		if (irq < 0)
>  			break;
> @@ -981,9 +1044,9 @@ static int cci_pmu_probe(struct platform_device *pdev)
>  	 * Ensure that the device tree has as many interrupts as the number
>  	 * of counters.
>  	 */
> -	if (i < CCI_PMU_MAX_HW_EVENTS) {
> +	if (i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model)) {
>  		dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n",
> -			i, CCI_PMU_MAX_HW_EVENTS);
> +			i, CCI_PMU_MAX_HW_CNTRS(cci_pmu->model));
>  		return -EINVAL;
>  	}

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 4/7] arm-cci: Abstract handling for CCI events
  2015-05-05 11:49   ` Suzuki K. Poulose
@ 2015-05-18 13:08     ` Punit Agrawal
  -1 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:08 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel, Mark Rutland, devicetree, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon, linux-kernel, arm,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Given that each CCI has different set of interfaces and
> its associated events, it is good to abstract the validation of the
> event codes to make it easier to add support for a new CCI model.
>
> This patch also abstracts the mapping of a given event to a counter,
> as there are some special counters for certain specific events.
>
> We assume that the fixed hardware counters are always at the beginning,
> so that we can use cci_model->fixed_hw_events as an upper bound to given
> idx to check if we need to program the counter for an event.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/arm-cci.c |   78 ++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 55 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 82d5681..4b9a8d3 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -107,6 +107,7 @@ struct cci_pmu_hw_events {
>  	raw_spinlock_t pmu_lock;
>  };
>  
> +struct cci_pmu;
>  /*
>   * struct cci_pmu_model:
>   * @fixed_hw_cntrs - Number of fixed event counters
> @@ -119,6 +120,8 @@ struct cci_pmu_model {
>  	u32 num_hw_cntrs;
>  	u32 cntr_size;
>  	struct event_range event_ranges[CCI_IF_MAX];
> +	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
> +	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
>  };
>  
>  static struct cci_pmu_model cci_pmu_models[];
> @@ -189,7 +192,29 @@ enum cci400_perf_events {
>  #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
>  #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
>  
> -static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
> +static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
> +				struct cci_pmu_hw_events *hw,
> +				unsigned long cci_event)
> +{
> +	int idx;
> +
> +	/* cycles event idx is fixed */
> +	if (cci_event == CCI_PMU_CYCLES) {
> +		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
> +			return -EAGAIN;
> +
> +		return CCI_PMU_CYCLE_CNTR_IDX;
> +	}
> +
> +	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
> +		if (!test_and_set_bit(idx, hw->used_mask))
> +			return idx;
> +
> +	/* No counters available */
> +	return -EAGAIN;
> +}
> +
> +static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
>  	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
>  	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> @@ -198,6 +223,9 @@ static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event
>  	if (hw_event & ~CCI_PMU_EVENT_MASK)
>  		return -ENOENT;
>  
> +	if (hw_event == CCI_PMU_CYCLES)
> +		return hw_event;
> +
>  	switch (ev_source) {
>  	case CCI_PORT_S0:
>  	case CCI_PORT_S1:
> @@ -289,18 +317,14 @@ static u32 pmu_get_max_counters(void)
>  static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
>  {
>  	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
> -	struct hw_perf_event *hw_event = &event->hw;
> -	unsigned long cci_event = hw_event->config_base;
> +	unsigned long cci_event = event->hw.config_base;
>  	int idx;
>  
> -	if (cci_event == CCI_PMU_CYCLES) {
> -		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
> -			return -EAGAIN;
> +	if (cci_pmu->model->get_event_idx)
> +		return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
>  
> -		return CCI_PMU_CYCLE_CNTR_IDX;
> -	}
> -
> -	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
> +	/* Generic code to find an unused idx from the mask */
> +	for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
>  		if (!test_and_set_bit(idx, hw->used_mask))
>  			return idx;
>  
> @@ -310,19 +334,13 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
>  
>  static int pmu_map_event(struct perf_event *event)
>  {
> -	int mapping;
> -	unsigned long config = event->attr.config;
> +	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
>  
> -	if (event->attr.type < PERF_TYPE_MAX)
> +	if (event->attr.type < PERF_TYPE_MAX ||
> +			!cci_pmu->model->validate_hw_event)
>  		return -ENOENT;
>  
> -	if (config == CCI_PMU_CYCLES)
> -		mapping = config;
> -	else
> -		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
> -							config);
> -
> -	return mapping;
> +	return	cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config);
>  }
>  
>  static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
> @@ -450,7 +468,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  	 * This should work regardless of whether we have per-counter overflow
>  	 * interrupt or a combined overflow interrupt.
>  	 */
> -	for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
> +	for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
>  		struct perf_event *event = events->events[idx];
>  		struct hw_perf_event *hw_counter;
>  
> @@ -538,6 +556,16 @@ static void cci_pmu_disable(struct pmu *pmu)
>  	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
>  }
>  
> +/*
> + * Check if the idx represents a non-programmable counter.
> + * All the fixed event counters are mapped before the programmable
> + * counters.
> + */
> +static bool pmu_fixed_hw_idx(struct cci_pmu *cci_pmu, int idx)
> +{
> +	return (idx >= 0) && (idx < cci_pmu->model->fixed_hw_cntrs);
> +}
> +
>  static void cci_pmu_start(struct perf_event *event, int pmu_flags)
>  {
>  	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
> @@ -562,8 +590,8 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
>  
>  	raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
>  
> -	/* Configure the event to count, unless you are counting cycles */
> -	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
> +	/* Configure the counter unless you are counting a fixed event */
> +	if (!pmu_fixed_hw_idx(cci_pmu, idx))
>  		pmu_set_event(cci_pmu, idx, hwc->config_base);
>  
>  	pmu_event_set_period(event);
> @@ -907,6 +935,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  				CCI_REV_R0_MASTER_PORT_MAX_EV,
>  			},
>  		},
> +		.validate_hw_event = cci400_validate_hw_event,
> +		.get_event_idx = cci400_get_event_idx,
>  	},
>  	[CCI_REV_R1] = {
>  		.name = "CCI_400_r1",
> @@ -923,6 +953,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  				CCI_REV_R1_MASTER_PORT_MAX_EV,
>  			},
>  		},
> +		.validate_hw_event = cci400_validate_hw_event,
> +		.get_event_idx = cci400_get_event_idx,
>  	},
>  };

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 4/7] arm-cci: Abstract handling for CCI events
@ 2015-05-18 13:08     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:08 UTC (permalink / raw)
  To: linux-arm-kernel

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Given that each CCI has different set of interfaces and
> its associated events, it is good to abstract the validation of the
> event codes to make it easier to add support for a new CCI model.
>
> This patch also abstracts the mapping of a given event to a counter,
> as there are some special counters for certain specific events.
>
> We assume that the fixed hardware counters are always at the beginning,
> so that we can use cci_model->fixed_hw_events as an upper bound to given
> idx to check if we need to program the counter for an event.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/arm-cci.c |   78 ++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 55 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 82d5681..4b9a8d3 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -107,6 +107,7 @@ struct cci_pmu_hw_events {
>  	raw_spinlock_t pmu_lock;
>  };
>  
> +struct cci_pmu;
>  /*
>   * struct cci_pmu_model:
>   * @fixed_hw_cntrs - Number of fixed event counters
> @@ -119,6 +120,8 @@ struct cci_pmu_model {
>  	u32 num_hw_cntrs;
>  	u32 cntr_size;
>  	struct event_range event_ranges[CCI_IF_MAX];
> +	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
> +	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
>  };
>  
>  static struct cci_pmu_model cci_pmu_models[];
> @@ -189,7 +192,29 @@ enum cci400_perf_events {
>  #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
>  #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
>  
> -static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
> +static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
> +				struct cci_pmu_hw_events *hw,
> +				unsigned long cci_event)
> +{
> +	int idx;
> +
> +	/* cycles event idx is fixed */
> +	if (cci_event == CCI_PMU_CYCLES) {
> +		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
> +			return -EAGAIN;
> +
> +		return CCI_PMU_CYCLE_CNTR_IDX;
> +	}
> +
> +	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
> +		if (!test_and_set_bit(idx, hw->used_mask))
> +			return idx;
> +
> +	/* No counters available */
> +	return -EAGAIN;
> +}
> +
> +static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
>  	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
>  	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> @@ -198,6 +223,9 @@ static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event
>  	if (hw_event & ~CCI_PMU_EVENT_MASK)
>  		return -ENOENT;
>  
> +	if (hw_event == CCI_PMU_CYCLES)
> +		return hw_event;
> +
>  	switch (ev_source) {
>  	case CCI_PORT_S0:
>  	case CCI_PORT_S1:
> @@ -289,18 +317,14 @@ static u32 pmu_get_max_counters(void)
>  static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
>  {
>  	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
> -	struct hw_perf_event *hw_event = &event->hw;
> -	unsigned long cci_event = hw_event->config_base;
> +	unsigned long cci_event = event->hw.config_base;
>  	int idx;
>  
> -	if (cci_event == CCI_PMU_CYCLES) {
> -		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
> -			return -EAGAIN;
> +	if (cci_pmu->model->get_event_idx)
> +		return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
>  
> -		return CCI_PMU_CYCLE_CNTR_IDX;
> -	}
> -
> -	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
> +	/* Generic code to find an unused idx from the mask */
> +	for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
>  		if (!test_and_set_bit(idx, hw->used_mask))
>  			return idx;
>  
> @@ -310,19 +334,13 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
>  
>  static int pmu_map_event(struct perf_event *event)
>  {
> -	int mapping;
> -	unsigned long config = event->attr.config;
> +	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
>  
> -	if (event->attr.type < PERF_TYPE_MAX)
> +	if (event->attr.type < PERF_TYPE_MAX ||
> +			!cci_pmu->model->validate_hw_event)
>  		return -ENOENT;
>  
> -	if (config == CCI_PMU_CYCLES)
> -		mapping = config;
> -	else
> -		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
> -							config);
> -
> -	return mapping;
> +	return	cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config);
>  }
>  
>  static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
> @@ -450,7 +468,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
>  	 * This should work regardless of whether we have per-counter overflow
>  	 * interrupt or a combined overflow interrupt.
>  	 */
> -	for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
> +	for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
>  		struct perf_event *event = events->events[idx];
>  		struct hw_perf_event *hw_counter;
>  
> @@ -538,6 +556,16 @@ static void cci_pmu_disable(struct pmu *pmu)
>  	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
>  }
>  
> +/*
> + * Check if the idx represents a non-programmable counter.
> + * All the fixed event counters are mapped before the programmable
> + * counters.
> + */
> +static bool pmu_fixed_hw_idx(struct cci_pmu *cci_pmu, int idx)
> +{
> +	return (idx >= 0) && (idx < cci_pmu->model->fixed_hw_cntrs);
> +}
> +
>  static void cci_pmu_start(struct perf_event *event, int pmu_flags)
>  {
>  	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
> @@ -562,8 +590,8 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
>  
>  	raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
>  
> -	/* Configure the event to count, unless you are counting cycles */
> -	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
> +	/* Configure the counter unless you are counting a fixed event */
> +	if (!pmu_fixed_hw_idx(cci_pmu, idx))
>  		pmu_set_event(cci_pmu, idx, hwc->config_base);
>  
>  	pmu_event_set_period(event);
> @@ -907,6 +935,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  				CCI_REV_R0_MASTER_PORT_MAX_EV,
>  			},
>  		},
> +		.validate_hw_event = cci400_validate_hw_event,
> +		.get_event_idx = cci400_get_event_idx,
>  	},
>  	[CCI_REV_R1] = {
>  		.name = "CCI_400_r1",
> @@ -923,6 +953,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  				CCI_REV_R1_MASTER_PORT_MAX_EV,
>  			},
>  		},
> +		.validate_hw_event = cci400_validate_hw_event,
> +		.get_event_idx = cci400_get_event_idx,
>  	},
>  };

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code
@ 2015-05-18 13:22     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:22 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel, Mark Rutland, devicetree, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon, linux-kernel, arm,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Rename CCI400 specific defintions from CCI_xxx to CCI400_xxx.
>
> Introduce generic ARM_CCI_PMU to cover common code for handling
> the CCI PMU.
>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/Kconfig   |    5 ++
>  drivers/bus/arm-cci.c |  157 +++++++++++++++++++++++++++++--------------------
>  2 files changed, 97 insertions(+), 65 deletions(-)
>
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index a1d4af6..be66b7c 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -7,6 +7,10 @@ menu "Bus devices"
>  config ARM_CCI
>  	bool
>  
> +config ARM_CCI_PMU
> +	bool
> +	select ARM_CCI
> +
>  config ARM_CCI400_COMMON
>  	bool
>  	select ARM_CCI
> @@ -17,6 +21,7 @@ config ARM_CCI400_PMU
>  	depends on ARM || ARM64
>  	depends on HW_PERF_EVENTS
>  	select ARM_CCI400_COMMON
> +	select ARM_CCI_PMU
>  	help
>  	  Support for PMU events monitoring on the ARM CCI cache coherent
>  	  interconnect.
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 4b9a8d3..2b43cea 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -55,9 +55,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  	{},
>  };
>  
> -#ifdef CONFIG_ARM_CCI400_PMU
> +#ifdef CONFIG_ARM_CCI_PMU
>  
> -#define DRIVER_NAME		"CCI-400"
> +#define DRIVER_NAME		"ARM-CCI"
>  #define DRIVER_NAME_PMU		DRIVER_NAME " PMU"
>  
>  #define CCI_PMCR		0x0100
> @@ -82,10 +82,6 @@ static const struct of_device_id arm_cci_matches[] = {
>  #define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
>  #define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
>  
> -#define CCI_PMU_EVENT_MASK		0xffUL
> -#define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
> -#define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
> -
>  #define CCI_PMU_MAX_HW_CNTRS(model) \
>  	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
>  
> @@ -144,19 +140,29 @@ struct cci_pmu {
>  
>  #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
>  
> +enum cci_models {
> +#ifdef CONFIG_ARM_CCI400_PMU
> +	CCI400_R0,
> +	CCI400_R1,
> +#endif
> +	CCI_MODEL_MAX
> +};
> +
> +/* CCI400 PMU Specific definitions */
> +
> +#ifdef CONFIG_ARM_CCI400_PMU
> +
>  /* Port ids */
> -#define CCI_PORT_S0	0
> -#define CCI_PORT_S1	1
> -#define CCI_PORT_S2	2
> -#define CCI_PORT_S3	3
> -#define CCI_PORT_S4	4
> -#define CCI_PORT_M0	5
> -#define CCI_PORT_M1	6
> -#define CCI_PORT_M2	7
> -
> -#define CCI_REV_R0		0
> -#define CCI_REV_R1		1
> -#define CCI_REV_R1_PX		5
> +#define CCI400_PORT_S0		0
> +#define CCI400_PORT_S1		1
> +#define CCI400_PORT_S2		2
> +#define CCI400_PORT_S3		3
> +#define CCI400_PORT_S4		4
> +#define CCI400_PORT_M0		5
> +#define CCI400_PORT_M1		6
> +#define CCI400_PORT_M2		7
> +
> +#define CCI400_R1_PX		5
>  
>  /*
>   * Instead of an event id to monitor CCI cycles, a dedicated counter is
> @@ -164,11 +170,11 @@ struct cci_pmu {
>   * make use of this event in hardware.
>   */
>  enum cci400_perf_events {
> -	CCI_PMU_CYCLES = 0xff
> +	CCI400_PMU_CYCLES = 0xff
>  };
>  
> -#define CCI_PMU_CYCLE_CNTR_IDX		0
> -#define CCI_PMU_CNTR0_IDX		1
> +#define CCI400_PMU_CYCLE_CNTR_IDX	0
> +#define CCI400_PMU_CNTR0_IDX		1
>  
>  /*
>   * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
> @@ -182,15 +188,26 @@ enum cci400_perf_events {
>   * the different revisions and are used to validate the event to be monitored.
>   */
>  
> -#define CCI_REV_R0_SLAVE_PORT_MIN_EV	0x00
> -#define CCI_REV_R0_SLAVE_PORT_MAX_EV	0x13
> -#define CCI_REV_R0_MASTER_PORT_MIN_EV	0x14
> -#define CCI_REV_R0_MASTER_PORT_MAX_EV	0x1a
> -
> -#define CCI_REV_R1_SLAVE_PORT_MIN_EV	0x00
> -#define CCI_REV_R1_SLAVE_PORT_MAX_EV	0x14
> -#define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
> -#define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
> +#define CCI400_PMU_EVENT_MASK		0xffUL
> +#define CCI400_PMU_EVENT_SOURCE_SHIFT	5
> +#define CCI400_PMU_EVENT_SOURCE_MASK	0x7
> +#define CCI400_PMU_EVENT_CODE_SHIFT	0
> +#define CCI400_PMU_EVENT_CODE_MASK	0x1f
> +#define CCI400_PMU_EVENT_SOURCE(event) \
> +	((event >> CCI400_PMU_EVENT_SOURCE_SHIFT) & \
> +			CCI400_PMU_EVENT_SOURCE_MASK)
> +#define CCI400_PMU_EVENT_CODE(event) \
> +	((event >> CCI400_PMU_EVENT_CODE_SHIFT) & CCI400_PMU_EVENT_CODE_MASK)
> +
> +#define CCI400_R0_SLAVE_PORT_MIN_EV	0x00
> +#define CCI400_R0_SLAVE_PORT_MAX_EV	0x13
> +#define CCI400_R0_MASTER_PORT_MIN_EV	0x14
> +#define CCI400_R0_MASTER_PORT_MAX_EV	0x1a
> +
> +#define CCI400_R1_SLAVE_PORT_MIN_EV	0x00
> +#define CCI400_R1_SLAVE_PORT_MAX_EV	0x14
> +#define CCI400_R1_MASTER_PORT_MIN_EV	0x00
> +#define CCI400_R1_MASTER_PORT_MAX_EV	0x11
>  
>  static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  				struct cci_pmu_hw_events *hw,
> @@ -199,14 +216,14 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  	int idx;
>  
>  	/* cycles event idx is fixed */
> -	if (cci_event == CCI_PMU_CYCLES) {
> -		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
> +	if (cci_event == CCI400_PMU_CYCLES) {
> +		if (test_and_set_bit(CCI400_PMU_CYCLE_CNTR_IDX, hw->used_mask))
>  			return -EAGAIN;
>  
> -		return CCI_PMU_CYCLE_CNTR_IDX;
> +		return CCI400_PMU_CYCLE_CNTR_IDX;
>  	}
>  
> -	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
> +	for (idx = CCI400_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
>  		if (!test_and_set_bit(idx, hw->used_mask))
>  			return idx;
>  
> @@ -216,28 +233,28 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  
>  static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
> -	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
> -	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> +	u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event);
> +	u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event);
>  	int if_type;
>  
> -	if (hw_event & ~CCI_PMU_EVENT_MASK)
> +	if (hw_event & ~CCI400_PMU_EVENT_MASK)
>  		return -ENOENT;
>  
> -	if (hw_event == CCI_PMU_CYCLES)
> +	if (hw_event == CCI400_PMU_CYCLES)
>  		return hw_event;
>  
>  	switch (ev_source) {
> -	case CCI_PORT_S0:
> -	case CCI_PORT_S1:
> -	case CCI_PORT_S2:
> -	case CCI_PORT_S3:
> -	case CCI_PORT_S4:
> +	case CCI400_PORT_S0:
> +	case CCI400_PORT_S1:
> +	case CCI400_PORT_S2:
> +	case CCI400_PORT_S3:
> +	case CCI400_PORT_S4:
>  		/* Slave Interface */
>  		if_type = CCI_IF_SLAVE;
>  		break;
> -	case CCI_PORT_M0:
> -	case CCI_PORT_M1:
> -	case CCI_PORT_M2:
> +	case CCI400_PORT_M0:
> +	case CCI400_PORT_M1:
> +	case CCI400_PORT_M2:
>  		/* Master Interface */
>  		if_type = CCI_IF_MASTER;
>  		break;
> @@ -252,24 +269,30 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev
>  	return -ENOENT;
>  }
>  
> -static int probe_cci_revision(void)
> +static int probe_cci400_revision(void)
>  {
>  	int rev;
>  	rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK;
>  	rev >>= CCI_PID2_REV_SHIFT;
>  
> -	if (rev < CCI_REV_R1_PX)
> -		return CCI_REV_R0;
> +	if (rev < CCI400_R1_PX)
> +		return CCI400_R0;
>  	else
> -		return CCI_REV_R1;
> +		return CCI400_R1;
>  }
>  
>  static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
>  {
>  	if (platform_has_secure_cci_access())
> -		return &cci_pmu_models[probe_cci_revision()];
> +		return &cci_pmu_models[probe_cci400_revision()];
> +	return NULL;
> +}
> +#else	/* !CONFIG_ARM_CCI400_PMU */
> +static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
> +{
>  	return NULL;
>  }
> +#endif	/* CONFIG_ARM_CCI400_PMU */
>  
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> @@ -920,57 +943,61 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  }
>  
>  static struct cci_pmu_model cci_pmu_models[] = {
> -	[CCI_REV_R0] = {
> +#ifdef CONFIG_ARM_CCI400_PMU
> +	[CCI400_R0] = {
>  		.name = "CCI_400",
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
> -				CCI_REV_R0_SLAVE_PORT_MIN_EV,
> -				CCI_REV_R0_SLAVE_PORT_MAX_EV,
> +				CCI400_R0_SLAVE_PORT_MIN_EV,
> +				CCI400_R0_SLAVE_PORT_MAX_EV,
>  			},
>  			[CCI_IF_MASTER] = {
> -				CCI_REV_R0_MASTER_PORT_MIN_EV,
> -				CCI_REV_R0_MASTER_PORT_MAX_EV,
> +				CCI400_R0_MASTER_PORT_MIN_EV,
> +				CCI400_R0_MASTER_PORT_MAX_EV,
>  			},
>  		},
>  		.validate_hw_event = cci400_validate_hw_event,
>  		.get_event_idx = cci400_get_event_idx,
>  	},
> -	[CCI_REV_R1] = {
> +	[CCI400_R1] = {
>  		.name = "CCI_400_r1",
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
> -				CCI_REV_R1_SLAVE_PORT_MIN_EV,
> -				CCI_REV_R1_SLAVE_PORT_MAX_EV,
> +				CCI400_R1_SLAVE_PORT_MIN_EV,
> +				CCI400_R1_SLAVE_PORT_MAX_EV,
>  			},
>  			[CCI_IF_MASTER] = {
> -				CCI_REV_R1_MASTER_PORT_MIN_EV,
> -				CCI_REV_R1_MASTER_PORT_MAX_EV,
> +				CCI400_R1_MASTER_PORT_MIN_EV,
> +				CCI400_R1_MASTER_PORT_MAX_EV,
>  			},
>  		},
>  		.validate_hw_event = cci400_validate_hw_event,
>  		.get_event_idx = cci400_get_event_idx,
>  	},
> +#endif
>  };
>  
>  static const struct of_device_id arm_cci_pmu_matches[] = {
> +#ifdef CONFIG_ARM_CCI400_PMU
>  	{
>  		.compatible = "arm,cci-400-pmu",
>  		.data	= NULL,
>  	},
>  	{
>  		.compatible = "arm,cci-400-pmu,r0",
> -		.data	= &cci_pmu_models[CCI_REV_R0],
> +		.data	= &cci_pmu_models[CCI400_R0],
>  	},
>  	{
>  		.compatible = "arm,cci-400-pmu,r1",
> -		.data	= &cci_pmu_models[CCI_REV_R1],
> +		.data	= &cci_pmu_models[CCI400_R1],
>  	},
> +#endif
>  	{},
>  };
>  
> @@ -1145,14 +1172,14 @@ static int __init cci_platform_init(void)
>  	return platform_driver_register(&cci_platform_driver);
>  }
>  
> -#else /* !CONFIG_ARM_CCI400_PMU */
> +#else /* !CONFIG_ARM_CCI_PMU */
>  
>  static int __init cci_platform_init(void)
>  {
>  	return 0;
>  }
>  
> -#endif /* CONFIG_ARM_CCI400_PMU */
> +#endif /* CONFIG_ARM_CCI_PMU */
>  
>  #ifdef CONFIG_ARM_CCI400_PORT_CTRL

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code
@ 2015-05-18 13:22     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:22 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, arm-DgEjT+Ai2ygdnm+yROfE0A,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
>
> Rename CCI400 specific defintions from CCI_xxx to CCI400_xxx.
>
> Introduce generic ARM_CCI_PMU to cover common code for handling
> the CCI PMU.
>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
> Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

Acked-by: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>

> ---
>  drivers/bus/Kconfig   |    5 ++
>  drivers/bus/arm-cci.c |  157 +++++++++++++++++++++++++++++--------------------
>  2 files changed, 97 insertions(+), 65 deletions(-)
>
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index a1d4af6..be66b7c 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -7,6 +7,10 @@ menu "Bus devices"
>  config ARM_CCI
>  	bool
>  
> +config ARM_CCI_PMU
> +	bool
> +	select ARM_CCI
> +
>  config ARM_CCI400_COMMON
>  	bool
>  	select ARM_CCI
> @@ -17,6 +21,7 @@ config ARM_CCI400_PMU
>  	depends on ARM || ARM64
>  	depends on HW_PERF_EVENTS
>  	select ARM_CCI400_COMMON
> +	select ARM_CCI_PMU
>  	help
>  	  Support for PMU events monitoring on the ARM CCI cache coherent
>  	  interconnect.
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 4b9a8d3..2b43cea 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -55,9 +55,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  	{},
>  };
>  
> -#ifdef CONFIG_ARM_CCI400_PMU
> +#ifdef CONFIG_ARM_CCI_PMU
>  
> -#define DRIVER_NAME		"CCI-400"
> +#define DRIVER_NAME		"ARM-CCI"
>  #define DRIVER_NAME_PMU		DRIVER_NAME " PMU"
>  
>  #define CCI_PMCR		0x0100
> @@ -82,10 +82,6 @@ static const struct of_device_id arm_cci_matches[] = {
>  #define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
>  #define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
>  
> -#define CCI_PMU_EVENT_MASK		0xffUL
> -#define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
> -#define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
> -
>  #define CCI_PMU_MAX_HW_CNTRS(model) \
>  	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
>  
> @@ -144,19 +140,29 @@ struct cci_pmu {
>  
>  #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
>  
> +enum cci_models {
> +#ifdef CONFIG_ARM_CCI400_PMU
> +	CCI400_R0,
> +	CCI400_R1,
> +#endif
> +	CCI_MODEL_MAX
> +};
> +
> +/* CCI400 PMU Specific definitions */
> +
> +#ifdef CONFIG_ARM_CCI400_PMU
> +
>  /* Port ids */
> -#define CCI_PORT_S0	0
> -#define CCI_PORT_S1	1
> -#define CCI_PORT_S2	2
> -#define CCI_PORT_S3	3
> -#define CCI_PORT_S4	4
> -#define CCI_PORT_M0	5
> -#define CCI_PORT_M1	6
> -#define CCI_PORT_M2	7
> -
> -#define CCI_REV_R0		0
> -#define CCI_REV_R1		1
> -#define CCI_REV_R1_PX		5
> +#define CCI400_PORT_S0		0
> +#define CCI400_PORT_S1		1
> +#define CCI400_PORT_S2		2
> +#define CCI400_PORT_S3		3
> +#define CCI400_PORT_S4		4
> +#define CCI400_PORT_M0		5
> +#define CCI400_PORT_M1		6
> +#define CCI400_PORT_M2		7
> +
> +#define CCI400_R1_PX		5
>  
>  /*
>   * Instead of an event id to monitor CCI cycles, a dedicated counter is
> @@ -164,11 +170,11 @@ struct cci_pmu {
>   * make use of this event in hardware.
>   */
>  enum cci400_perf_events {
> -	CCI_PMU_CYCLES = 0xff
> +	CCI400_PMU_CYCLES = 0xff
>  };
>  
> -#define CCI_PMU_CYCLE_CNTR_IDX		0
> -#define CCI_PMU_CNTR0_IDX		1
> +#define CCI400_PMU_CYCLE_CNTR_IDX	0
> +#define CCI400_PMU_CNTR0_IDX		1
>  
>  /*
>   * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
> @@ -182,15 +188,26 @@ enum cci400_perf_events {
>   * the different revisions and are used to validate the event to be monitored.
>   */
>  
> -#define CCI_REV_R0_SLAVE_PORT_MIN_EV	0x00
> -#define CCI_REV_R0_SLAVE_PORT_MAX_EV	0x13
> -#define CCI_REV_R0_MASTER_PORT_MIN_EV	0x14
> -#define CCI_REV_R0_MASTER_PORT_MAX_EV	0x1a
> -
> -#define CCI_REV_R1_SLAVE_PORT_MIN_EV	0x00
> -#define CCI_REV_R1_SLAVE_PORT_MAX_EV	0x14
> -#define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
> -#define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
> +#define CCI400_PMU_EVENT_MASK		0xffUL
> +#define CCI400_PMU_EVENT_SOURCE_SHIFT	5
> +#define CCI400_PMU_EVENT_SOURCE_MASK	0x7
> +#define CCI400_PMU_EVENT_CODE_SHIFT	0
> +#define CCI400_PMU_EVENT_CODE_MASK	0x1f
> +#define CCI400_PMU_EVENT_SOURCE(event) \
> +	((event >> CCI400_PMU_EVENT_SOURCE_SHIFT) & \
> +			CCI400_PMU_EVENT_SOURCE_MASK)
> +#define CCI400_PMU_EVENT_CODE(event) \
> +	((event >> CCI400_PMU_EVENT_CODE_SHIFT) & CCI400_PMU_EVENT_CODE_MASK)
> +
> +#define CCI400_R0_SLAVE_PORT_MIN_EV	0x00
> +#define CCI400_R0_SLAVE_PORT_MAX_EV	0x13
> +#define CCI400_R0_MASTER_PORT_MIN_EV	0x14
> +#define CCI400_R0_MASTER_PORT_MAX_EV	0x1a
> +
> +#define CCI400_R1_SLAVE_PORT_MIN_EV	0x00
> +#define CCI400_R1_SLAVE_PORT_MAX_EV	0x14
> +#define CCI400_R1_MASTER_PORT_MIN_EV	0x00
> +#define CCI400_R1_MASTER_PORT_MAX_EV	0x11
>  
>  static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  				struct cci_pmu_hw_events *hw,
> @@ -199,14 +216,14 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  	int idx;
>  
>  	/* cycles event idx is fixed */
> -	if (cci_event == CCI_PMU_CYCLES) {
> -		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
> +	if (cci_event == CCI400_PMU_CYCLES) {
> +		if (test_and_set_bit(CCI400_PMU_CYCLE_CNTR_IDX, hw->used_mask))
>  			return -EAGAIN;
>  
> -		return CCI_PMU_CYCLE_CNTR_IDX;
> +		return CCI400_PMU_CYCLE_CNTR_IDX;
>  	}
>  
> -	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
> +	for (idx = CCI400_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
>  		if (!test_and_set_bit(idx, hw->used_mask))
>  			return idx;
>  
> @@ -216,28 +233,28 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  
>  static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
> -	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
> -	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> +	u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event);
> +	u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event);
>  	int if_type;
>  
> -	if (hw_event & ~CCI_PMU_EVENT_MASK)
> +	if (hw_event & ~CCI400_PMU_EVENT_MASK)
>  		return -ENOENT;
>  
> -	if (hw_event == CCI_PMU_CYCLES)
> +	if (hw_event == CCI400_PMU_CYCLES)
>  		return hw_event;
>  
>  	switch (ev_source) {
> -	case CCI_PORT_S0:
> -	case CCI_PORT_S1:
> -	case CCI_PORT_S2:
> -	case CCI_PORT_S3:
> -	case CCI_PORT_S4:
> +	case CCI400_PORT_S0:
> +	case CCI400_PORT_S1:
> +	case CCI400_PORT_S2:
> +	case CCI400_PORT_S3:
> +	case CCI400_PORT_S4:
>  		/* Slave Interface */
>  		if_type = CCI_IF_SLAVE;
>  		break;
> -	case CCI_PORT_M0:
> -	case CCI_PORT_M1:
> -	case CCI_PORT_M2:
> +	case CCI400_PORT_M0:
> +	case CCI400_PORT_M1:
> +	case CCI400_PORT_M2:
>  		/* Master Interface */
>  		if_type = CCI_IF_MASTER;
>  		break;
> @@ -252,24 +269,30 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev
>  	return -ENOENT;
>  }
>  
> -static int probe_cci_revision(void)
> +static int probe_cci400_revision(void)
>  {
>  	int rev;
>  	rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK;
>  	rev >>= CCI_PID2_REV_SHIFT;
>  
> -	if (rev < CCI_REV_R1_PX)
> -		return CCI_REV_R0;
> +	if (rev < CCI400_R1_PX)
> +		return CCI400_R0;
>  	else
> -		return CCI_REV_R1;
> +		return CCI400_R1;
>  }
>  
>  static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
>  {
>  	if (platform_has_secure_cci_access())
> -		return &cci_pmu_models[probe_cci_revision()];
> +		return &cci_pmu_models[probe_cci400_revision()];
> +	return NULL;
> +}
> +#else	/* !CONFIG_ARM_CCI400_PMU */
> +static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
> +{
>  	return NULL;
>  }
> +#endif	/* CONFIG_ARM_CCI400_PMU */
>  
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> @@ -920,57 +943,61 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  }
>  
>  static struct cci_pmu_model cci_pmu_models[] = {
> -	[CCI_REV_R0] = {
> +#ifdef CONFIG_ARM_CCI400_PMU
> +	[CCI400_R0] = {
>  		.name = "CCI_400",
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
> -				CCI_REV_R0_SLAVE_PORT_MIN_EV,
> -				CCI_REV_R0_SLAVE_PORT_MAX_EV,
> +				CCI400_R0_SLAVE_PORT_MIN_EV,
> +				CCI400_R0_SLAVE_PORT_MAX_EV,
>  			},
>  			[CCI_IF_MASTER] = {
> -				CCI_REV_R0_MASTER_PORT_MIN_EV,
> -				CCI_REV_R0_MASTER_PORT_MAX_EV,
> +				CCI400_R0_MASTER_PORT_MIN_EV,
> +				CCI400_R0_MASTER_PORT_MAX_EV,
>  			},
>  		},
>  		.validate_hw_event = cci400_validate_hw_event,
>  		.get_event_idx = cci400_get_event_idx,
>  	},
> -	[CCI_REV_R1] = {
> +	[CCI400_R1] = {
>  		.name = "CCI_400_r1",
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
> -				CCI_REV_R1_SLAVE_PORT_MIN_EV,
> -				CCI_REV_R1_SLAVE_PORT_MAX_EV,
> +				CCI400_R1_SLAVE_PORT_MIN_EV,
> +				CCI400_R1_SLAVE_PORT_MAX_EV,
>  			},
>  			[CCI_IF_MASTER] = {
> -				CCI_REV_R1_MASTER_PORT_MIN_EV,
> -				CCI_REV_R1_MASTER_PORT_MAX_EV,
> +				CCI400_R1_MASTER_PORT_MIN_EV,
> +				CCI400_R1_MASTER_PORT_MAX_EV,
>  			},
>  		},
>  		.validate_hw_event = cci400_validate_hw_event,
>  		.get_event_idx = cci400_get_event_idx,
>  	},
> +#endif
>  };
>  
>  static const struct of_device_id arm_cci_pmu_matches[] = {
> +#ifdef CONFIG_ARM_CCI400_PMU
>  	{
>  		.compatible = "arm,cci-400-pmu",
>  		.data	= NULL,
>  	},
>  	{
>  		.compatible = "arm,cci-400-pmu,r0",
> -		.data	= &cci_pmu_models[CCI_REV_R0],
> +		.data	= &cci_pmu_models[CCI400_R0],
>  	},
>  	{
>  		.compatible = "arm,cci-400-pmu,r1",
> -		.data	= &cci_pmu_models[CCI_REV_R1],
> +		.data	= &cci_pmu_models[CCI400_R1],
>  	},
> +#endif
>  	{},
>  };
>  
> @@ -1145,14 +1172,14 @@ static int __init cci_platform_init(void)
>  	return platform_driver_register(&cci_platform_driver);
>  }
>  
> -#else /* !CONFIG_ARM_CCI400_PMU */
> +#else /* !CONFIG_ARM_CCI_PMU */
>  
>  static int __init cci_platform_init(void)
>  {
>  	return 0;
>  }
>  
> -#endif /* CONFIG_ARM_CCI400_PMU */
> +#endif /* CONFIG_ARM_CCI_PMU */
>  
>  #ifdef CONFIG_ARM_CCI400_PORT_CTRL
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code
@ 2015-05-18 13:22     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Rename CCI400 specific defintions from CCI_xxx to CCI400_xxx.
>
> Introduce generic ARM_CCI_PMU to cover common code for handling
> the CCI PMU.
>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  drivers/bus/Kconfig   |    5 ++
>  drivers/bus/arm-cci.c |  157 +++++++++++++++++++++++++++++--------------------
>  2 files changed, 97 insertions(+), 65 deletions(-)
>
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index a1d4af6..be66b7c 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -7,6 +7,10 @@ menu "Bus devices"
>  config ARM_CCI
>  	bool
>  
> +config ARM_CCI_PMU
> +	bool
> +	select ARM_CCI
> +
>  config ARM_CCI400_COMMON
>  	bool
>  	select ARM_CCI
> @@ -17,6 +21,7 @@ config ARM_CCI400_PMU
>  	depends on ARM || ARM64
>  	depends on HW_PERF_EVENTS
>  	select ARM_CCI400_COMMON
> +	select ARM_CCI_PMU
>  	help
>  	  Support for PMU events monitoring on the ARM CCI cache coherent
>  	  interconnect.
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 4b9a8d3..2b43cea 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -55,9 +55,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  	{},
>  };
>  
> -#ifdef CONFIG_ARM_CCI400_PMU
> +#ifdef CONFIG_ARM_CCI_PMU
>  
> -#define DRIVER_NAME		"CCI-400"
> +#define DRIVER_NAME		"ARM-CCI"
>  #define DRIVER_NAME_PMU		DRIVER_NAME " PMU"
>  
>  #define CCI_PMCR		0x0100
> @@ -82,10 +82,6 @@ static const struct of_device_id arm_cci_matches[] = {
>  #define CCI_PMU_CNTR_MASK		((1ULL << 32) -1)
>  #define CCI_PMU_CNTR_LAST(cci_pmu)	(cci_pmu->num_cntrs - 1)
>  
> -#define CCI_PMU_EVENT_MASK		0xffUL
> -#define CCI_PMU_EVENT_SOURCE(event)	((event >> 5) & 0x7)
> -#define CCI_PMU_EVENT_CODE(event)	(event & 0x1f)
> -
>  #define CCI_PMU_MAX_HW_CNTRS(model) \
>  	((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
>  
> @@ -144,19 +140,29 @@ struct cci_pmu {
>  
>  #define to_cci_pmu(c)	(container_of(c, struct cci_pmu, pmu))
>  
> +enum cci_models {
> +#ifdef CONFIG_ARM_CCI400_PMU
> +	CCI400_R0,
> +	CCI400_R1,
> +#endif
> +	CCI_MODEL_MAX
> +};
> +
> +/* CCI400 PMU Specific definitions */
> +
> +#ifdef CONFIG_ARM_CCI400_PMU
> +
>  /* Port ids */
> -#define CCI_PORT_S0	0
> -#define CCI_PORT_S1	1
> -#define CCI_PORT_S2	2
> -#define CCI_PORT_S3	3
> -#define CCI_PORT_S4	4
> -#define CCI_PORT_M0	5
> -#define CCI_PORT_M1	6
> -#define CCI_PORT_M2	7
> -
> -#define CCI_REV_R0		0
> -#define CCI_REV_R1		1
> -#define CCI_REV_R1_PX		5
> +#define CCI400_PORT_S0		0
> +#define CCI400_PORT_S1		1
> +#define CCI400_PORT_S2		2
> +#define CCI400_PORT_S3		3
> +#define CCI400_PORT_S4		4
> +#define CCI400_PORT_M0		5
> +#define CCI400_PORT_M1		6
> +#define CCI400_PORT_M2		7
> +
> +#define CCI400_R1_PX		5
>  
>  /*
>   * Instead of an event id to monitor CCI cycles, a dedicated counter is
> @@ -164,11 +170,11 @@ struct cci_pmu {
>   * make use of this event in hardware.
>   */
>  enum cci400_perf_events {
> -	CCI_PMU_CYCLES = 0xff
> +	CCI400_PMU_CYCLES = 0xff
>  };
>  
> -#define CCI_PMU_CYCLE_CNTR_IDX		0
> -#define CCI_PMU_CNTR0_IDX		1
> +#define CCI400_PMU_CYCLE_CNTR_IDX	0
> +#define CCI400_PMU_CNTR0_IDX		1
>  
>  /*
>   * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
> @@ -182,15 +188,26 @@ enum cci400_perf_events {
>   * the different revisions and are used to validate the event to be monitored.
>   */
>  
> -#define CCI_REV_R0_SLAVE_PORT_MIN_EV	0x00
> -#define CCI_REV_R0_SLAVE_PORT_MAX_EV	0x13
> -#define CCI_REV_R0_MASTER_PORT_MIN_EV	0x14
> -#define CCI_REV_R0_MASTER_PORT_MAX_EV	0x1a
> -
> -#define CCI_REV_R1_SLAVE_PORT_MIN_EV	0x00
> -#define CCI_REV_R1_SLAVE_PORT_MAX_EV	0x14
> -#define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
> -#define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
> +#define CCI400_PMU_EVENT_MASK		0xffUL
> +#define CCI400_PMU_EVENT_SOURCE_SHIFT	5
> +#define CCI400_PMU_EVENT_SOURCE_MASK	0x7
> +#define CCI400_PMU_EVENT_CODE_SHIFT	0
> +#define CCI400_PMU_EVENT_CODE_MASK	0x1f
> +#define CCI400_PMU_EVENT_SOURCE(event) \
> +	((event >> CCI400_PMU_EVENT_SOURCE_SHIFT) & \
> +			CCI400_PMU_EVENT_SOURCE_MASK)
> +#define CCI400_PMU_EVENT_CODE(event) \
> +	((event >> CCI400_PMU_EVENT_CODE_SHIFT) & CCI400_PMU_EVENT_CODE_MASK)
> +
> +#define CCI400_R0_SLAVE_PORT_MIN_EV	0x00
> +#define CCI400_R0_SLAVE_PORT_MAX_EV	0x13
> +#define CCI400_R0_MASTER_PORT_MIN_EV	0x14
> +#define CCI400_R0_MASTER_PORT_MAX_EV	0x1a
> +
> +#define CCI400_R1_SLAVE_PORT_MIN_EV	0x00
> +#define CCI400_R1_SLAVE_PORT_MAX_EV	0x14
> +#define CCI400_R1_MASTER_PORT_MIN_EV	0x00
> +#define CCI400_R1_MASTER_PORT_MAX_EV	0x11
>  
>  static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  				struct cci_pmu_hw_events *hw,
> @@ -199,14 +216,14 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  	int idx;
>  
>  	/* cycles event idx is fixed */
> -	if (cci_event == CCI_PMU_CYCLES) {
> -		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
> +	if (cci_event == CCI400_PMU_CYCLES) {
> +		if (test_and_set_bit(CCI400_PMU_CYCLE_CNTR_IDX, hw->used_mask))
>  			return -EAGAIN;
>  
> -		return CCI_PMU_CYCLE_CNTR_IDX;
> +		return CCI400_PMU_CYCLE_CNTR_IDX;
>  	}
>  
> -	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
> +	for (idx = CCI400_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
>  		if (!test_and_set_bit(idx, hw->used_mask))
>  			return idx;
>  
> @@ -216,28 +233,28 @@ static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  
>  static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
>  {
> -	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
> -	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
> +	u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event);
> +	u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event);
>  	int if_type;
>  
> -	if (hw_event & ~CCI_PMU_EVENT_MASK)
> +	if (hw_event & ~CCI400_PMU_EVENT_MASK)
>  		return -ENOENT;
>  
> -	if (hw_event == CCI_PMU_CYCLES)
> +	if (hw_event == CCI400_PMU_CYCLES)
>  		return hw_event;
>  
>  	switch (ev_source) {
> -	case CCI_PORT_S0:
> -	case CCI_PORT_S1:
> -	case CCI_PORT_S2:
> -	case CCI_PORT_S3:
> -	case CCI_PORT_S4:
> +	case CCI400_PORT_S0:
> +	case CCI400_PORT_S1:
> +	case CCI400_PORT_S2:
> +	case CCI400_PORT_S3:
> +	case CCI400_PORT_S4:
>  		/* Slave Interface */
>  		if_type = CCI_IF_SLAVE;
>  		break;
> -	case CCI_PORT_M0:
> -	case CCI_PORT_M1:
> -	case CCI_PORT_M2:
> +	case CCI400_PORT_M0:
> +	case CCI400_PORT_M1:
> +	case CCI400_PORT_M2:
>  		/* Master Interface */
>  		if_type = CCI_IF_MASTER;
>  		break;
> @@ -252,24 +269,30 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev
>  	return -ENOENT;
>  }
>  
> -static int probe_cci_revision(void)
> +static int probe_cci400_revision(void)
>  {
>  	int rev;
>  	rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK;
>  	rev >>= CCI_PID2_REV_SHIFT;
>  
> -	if (rev < CCI_REV_R1_PX)
> -		return CCI_REV_R0;
> +	if (rev < CCI400_R1_PX)
> +		return CCI400_R0;
>  	else
> -		return CCI_REV_R1;
> +		return CCI400_R1;
>  }
>  
>  static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
>  {
>  	if (platform_has_secure_cci_access())
> -		return &cci_pmu_models[probe_cci_revision()];
> +		return &cci_pmu_models[probe_cci400_revision()];
> +	return NULL;
> +}
> +#else	/* !CONFIG_ARM_CCI400_PMU */
> +static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
> +{
>  	return NULL;
>  }
> +#endif	/* CONFIG_ARM_CCI400_PMU */
>  
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
> @@ -920,57 +943,61 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
>  }
>  
>  static struct cci_pmu_model cci_pmu_models[] = {
> -	[CCI_REV_R0] = {
> +#ifdef CONFIG_ARM_CCI400_PMU
> +	[CCI400_R0] = {
>  		.name = "CCI_400",
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
> -				CCI_REV_R0_SLAVE_PORT_MIN_EV,
> -				CCI_REV_R0_SLAVE_PORT_MAX_EV,
> +				CCI400_R0_SLAVE_PORT_MIN_EV,
> +				CCI400_R0_SLAVE_PORT_MAX_EV,
>  			},
>  			[CCI_IF_MASTER] = {
> -				CCI_REV_R0_MASTER_PORT_MIN_EV,
> -				CCI_REV_R0_MASTER_PORT_MAX_EV,
> +				CCI400_R0_MASTER_PORT_MIN_EV,
> +				CCI400_R0_MASTER_PORT_MAX_EV,
>  			},
>  		},
>  		.validate_hw_event = cci400_validate_hw_event,
>  		.get_event_idx = cci400_get_event_idx,
>  	},
> -	[CCI_REV_R1] = {
> +	[CCI400_R1] = {
>  		.name = "CCI_400_r1",
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
> -				CCI_REV_R1_SLAVE_PORT_MIN_EV,
> -				CCI_REV_R1_SLAVE_PORT_MAX_EV,
> +				CCI400_R1_SLAVE_PORT_MIN_EV,
> +				CCI400_R1_SLAVE_PORT_MAX_EV,
>  			},
>  			[CCI_IF_MASTER] = {
> -				CCI_REV_R1_MASTER_PORT_MIN_EV,
> -				CCI_REV_R1_MASTER_PORT_MAX_EV,
> +				CCI400_R1_MASTER_PORT_MIN_EV,
> +				CCI400_R1_MASTER_PORT_MAX_EV,
>  			},
>  		},
>  		.validate_hw_event = cci400_validate_hw_event,
>  		.get_event_idx = cci400_get_event_idx,
>  	},
> +#endif
>  };
>  
>  static const struct of_device_id arm_cci_pmu_matches[] = {
> +#ifdef CONFIG_ARM_CCI400_PMU
>  	{
>  		.compatible = "arm,cci-400-pmu",
>  		.data	= NULL,
>  	},
>  	{
>  		.compatible = "arm,cci-400-pmu,r0",
> -		.data	= &cci_pmu_models[CCI_REV_R0],
> +		.data	= &cci_pmu_models[CCI400_R0],
>  	},
>  	{
>  		.compatible = "arm,cci-400-pmu,r1",
> -		.data	= &cci_pmu_models[CCI_REV_R1],
> +		.data	= &cci_pmu_models[CCI400_R1],
>  	},
> +#endif
>  	{},
>  };
>  
> @@ -1145,14 +1172,14 @@ static int __init cci_platform_init(void)
>  	return platform_driver_register(&cci_platform_driver);
>  }
>  
> -#else /* !CONFIG_ARM_CCI400_PMU */
> +#else /* !CONFIG_ARM_CCI_PMU */
>  
>  static int __init cci_platform_init(void)
>  {
>  	return 0;
>  }
>  
> -#endif /* CONFIG_ARM_CCI400_PMU */
> +#endif /* CONFIG_ARM_CCI_PMU */
>  
>  #ifdef CONFIG_ARM_CCI400_PORT_CTRL

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 6/7] arm-cci: Add CCI-500 PMU support
@ 2015-05-18 13:22     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:22 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel, Mark Rutland, devicetree, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon, linux-kernel, arm,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> CCI-500 provides 8 event counters which can count any of the
> supported events independently. The PMU event id is a 9-bit
> value made of two parts.
> 	bits [8:5] - Source port
> 			0x0-0x6 Slave Ports
> 			0x8-0xD Master Ports
> 			0xf     Global Events to CCI
> 			0x7,0xe Reserved
> 	bits [0:4] - Event code (specific to each type of port)
>
> The generic CCI-500 controlling interface remains the same with CCI-400.
> However there are some differences in the PMU event counters.
>  - No cycle counter
>  - Upto 8 counters(4 in CCI-400)
>  - Each counter area is 64K(4K in CCI400)
>  - The counter0 starts at offset 0x10000 from the base of CCI
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  Documentation/devicetree/bindings/arm/cci.txt |    4 +-
>  drivers/bus/Kconfig                           |   12 +++
>  drivers/bus/arm-cci.c                         |  133 +++++++++++++++++++++++++
>  3 files changed, 148 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt
> index 3c5c631..aef1d20 100644
> --- a/Documentation/devicetree/bindings/arm/cci.txt
> +++ b/Documentation/devicetree/bindings/arm/cci.txt
> @@ -31,8 +31,9 @@ specific to ARM.
>  	- compatible
>  		Usage: required
>  		Value type: <string>
> -		Definition: must be set to
> +		Definition: must contain one of the following:
>  			    "arm,cci-400"
> +			    "arm,cci-500"
>  
>  	- reg
>  		Usage: required
> @@ -99,6 +100,7 @@ specific to ARM.
>  				 "arm,cci-400-pmu,r1"
>  				 "arm,cci-400-pmu"  - DEPRECATED, permitted only where OS has
>  						      secure acces to CCI registers
> +				 "arm,cci-500-pmu,r0"
>  		- reg:
>  			Usage: required
>  			Value type: Integer cells. A register entry, expressed
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index be66b7c..5fb3150 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -36,6 +36,18 @@ config ARM_CCI400_PORT_CTRL
>  	  Low level power management driver for CCI400 cache coherent
>  	  interconnect for ARM platforms.
>  
> +config ARM_CCI500_PMU
> +	bool "ARM CCI500 PMU support"
> +	default y
> +	depends on ARM || ARM64
> +	depends on HW_PERF_EVENTS
> +	select ARM_CCI_PMU
> +	help
> +	  Support for PMU events monitoring on the ARM CCI-500 cache coherent
> +	  interconnect.
> +
> +	  If unsure, say Y
> +
>  config ARM_CCN
>  	bool "ARM CCN driver support"
>  	depends on ARM || ARM64
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 2b43cea..e12ddba 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -52,6 +52,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  #ifdef CONFIG_ARM_CCI400_COMMON
>  	{.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA },
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	{ .compatible = "arm,cci-500", },
> +#endif
>  	{},
>  };
>  
> @@ -89,6 +92,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  enum {
>  	CCI_IF_SLAVE,
>  	CCI_IF_MASTER,
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	CCI_IF_GLOBAL,
> +#endif
>  	CCI_IF_MAX,
>  };
>  
> @@ -145,6 +151,9 @@ enum cci_models {
>  	CCI400_R0,
>  	CCI400_R1,
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	CCI500_R0,
> +#endif
>  	CCI_MODEL_MAX
>  };
>  
> @@ -294,6 +303,101 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
>  }
>  #endif	/* CONFIG_ARM_CCI400_PMU */
>  
> +#ifdef CONFIG_ARM_CCI500_PMU
> +
> +/*
> + * CCI500 provides 8 independent event counters that can count
> + * any of the events available.
> + *
> + * CCI500 PMU event id is an 9-bit value made of two parts.
> + *	 bits [8:5] - Source for the event
> + *		      0x0-0x6 - Slave interfaces
> + *		      0x8-0xD - Master interfaces
> + *		      0xf     - Global Events
> + *		      0x7,0xe - Reserved
> + *
> + *	 bits [4:0] - Event code (specific to type of interface)
> + */
> +
> +/* Port ids */
> +#define CCI500_PORT_S0			0x0
> +#define CCI500_PORT_S1			0x1
> +#define CCI500_PORT_S2			0x2
> +#define CCI500_PORT_S3			0x3
> +#define CCI500_PORT_S4			0x4
> +#define CCI500_PORT_S5			0x5
> +#define CCI500_PORT_S6			0x6
> +
> +#define CCI500_PORT_M0			0x8
> +#define CCI500_PORT_M1			0x9
> +#define CCI500_PORT_M2			0xa
> +#define CCI500_PORT_M3			0xb
> +#define CCI500_PORT_M4			0xc
> +#define CCI500_PORT_M5			0xd
> +
> +#define CCI500_PORT_GLOBAL 		0xf
> +
> +#define CCI500_PMU_EVENT_MASK		0x1ffUL
> +#define CCI500_PMU_EVENT_SOURCE_SHIFT	0x5
> +#define CCI500_PMU_EVENT_SOURCE_MASK	0xf
> +#define CCI500_PMU_EVENT_CODE_SHIFT	0x0
> +#define CCI500_PMU_EVENT_CODE_MASK	0x1f
> +
> +#define CCI500_PMU_EVENT_SOURCE(event)	\
> +	((event >> CCI500_PMU_EVENT_SOURCE_SHIFT) & CCI500_PMU_EVENT_SOURCE_MASK)
> +#define CCI500_PMU_EVENT_CODE(event)	\
> +	((event >> CCI500_PMU_EVENT_CODE_SHIFT) & CCI500_PMU_EVENT_CODE_MASK)
> +
> +#define CCI500_SLAVE_PORT_MIN_EV	0x00
> +#define CCI500_SLAVE_PORT_MAX_EV	0x1f
> +#define CCI500_MASTER_PORT_MIN_EV	0x00
> +#define CCI500_MASTER_PORT_MAX_EV	0x06
> +#define CCI500_GLOBAL_PORT_MIN_EV	0x00
> +#define CCI500_GLOBAL_PORT_MAX_EV	0x0f
> +
> +static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
> +					unsigned long hw_event)
> +{
> +	u32 ev_source = CCI500_PMU_EVENT_SOURCE(hw_event);
> +	u32 ev_code = CCI500_PMU_EVENT_CODE(hw_event);
> +	int if_type;
> +
> +	if (hw_event & ~CCI500_PMU_EVENT_MASK)
> +		return -ENOENT;
> +
> +	switch (ev_source) {
> +	case CCI500_PORT_S0:
> +	case CCI500_PORT_S1:
> +	case CCI500_PORT_S2:
> +	case CCI500_PORT_S3:
> +	case CCI500_PORT_S4:
> +	case CCI500_PORT_S5:
> +	case CCI500_PORT_S6:
> +		if_type = CCI_IF_SLAVE;
> +		break;
> +	case CCI500_PORT_M0:
> +	case CCI500_PORT_M1:
> +	case CCI500_PORT_M2:
> +	case CCI500_PORT_M3:
> +	case CCI500_PORT_M4:
> +	case CCI500_PORT_M5:
> +		if_type = CCI_IF_MASTER;
> +		break;
> +	case CCI500_PORT_GLOBAL:
> +		if_type = CCI_IF_GLOBAL;
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
> +
> +	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
> +		ev_code <= cci_pmu->model->event_ranges[if_type].max)
> +		return hw_event;
> +
> +	return -ENOENT;
> +}
> +#endif	/* CONFIG_ARM_CCI500_PMU */
> +
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
>  	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> @@ -981,6 +1085,29 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.get_event_idx = cci400_get_event_idx,
>  	},
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	[CCI500_R0] = {
> +		.name = "CCI_500",
> +		.fixed_hw_cntrs = 0,
> +		.num_hw_cntrs = 8,
> +		.cntr_size = SZ_64K,
> +		.event_ranges = {
> +			[CCI_IF_SLAVE] = {
> +				CCI500_SLAVE_PORT_MIN_EV,
> +				CCI500_SLAVE_PORT_MAX_EV,
> +			},
> +			[CCI_IF_MASTER] = {
> +				CCI500_MASTER_PORT_MIN_EV,
> +				CCI500_MASTER_PORT_MAX_EV,
> +			},
> +			[CCI_IF_GLOBAL] = {
> +				CCI500_GLOBAL_PORT_MIN_EV,
> +				CCI500_GLOBAL_PORT_MAX_EV,
> +			},
> +		},
> +		.validate_hw_event = cci500_validate_hw_event,
> +	},
> +#endif
>  };
>  
>  static const struct of_device_id arm_cci_pmu_matches[] = {
> @@ -998,6 +1125,12 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
>  		.data	= &cci_pmu_models[CCI400_R1],
>  	},
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	{
> +		.compatible = "arm,cci-500-pmu,r0",
> +		.data = &cci_pmu_models[CCI500_R0],
> +	},
> +#endif
>  	{},
>  };

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 6/7] arm-cci: Add CCI-500 PMU support
@ 2015-05-18 13:22     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:22 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, arm-DgEjT+Ai2ygdnm+yROfE0A,
	Olof Johansson

"Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>
>
> CCI-500 provides 8 event counters which can count any of the
> supported events independently. The PMU event id is a 9-bit
> value made of two parts.
> 	bits [8:5] - Source port
> 			0x0-0x6 Slave Ports
> 			0x8-0xD Master Ports
> 			0xf     Global Events to CCI
> 			0x7,0xe Reserved
> 	bits [0:4] - Event code (specific to each type of port)
>
> The generic CCI-500 controlling interface remains the same with CCI-400.
> However there are some differences in the PMU event counters.
>  - No cycle counter
>  - Upto 8 counters(4 in CCI-400)
>  - Each counter area is 64K(4K in CCI400)
>  - The counter0 starts at offset 0x10000 from the base of CCI
>
> Cc: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose-5wv7dgnIgG8@public.gmane.org>

Acked-by: Punit Agrawal <punit.agrawal-5wv7dgnIgG8@public.gmane.org>

> ---
>  Documentation/devicetree/bindings/arm/cci.txt |    4 +-
>  drivers/bus/Kconfig                           |   12 +++
>  drivers/bus/arm-cci.c                         |  133 +++++++++++++++++++++++++
>  3 files changed, 148 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt
> index 3c5c631..aef1d20 100644
> --- a/Documentation/devicetree/bindings/arm/cci.txt
> +++ b/Documentation/devicetree/bindings/arm/cci.txt
> @@ -31,8 +31,9 @@ specific to ARM.
>  	- compatible
>  		Usage: required
>  		Value type: <string>
> -		Definition: must be set to
> +		Definition: must contain one of the following:
>  			    "arm,cci-400"
> +			    "arm,cci-500"
>  
>  	- reg
>  		Usage: required
> @@ -99,6 +100,7 @@ specific to ARM.
>  				 "arm,cci-400-pmu,r1"
>  				 "arm,cci-400-pmu"  - DEPRECATED, permitted only where OS has
>  						      secure acces to CCI registers
> +				 "arm,cci-500-pmu,r0"
>  		- reg:
>  			Usage: required
>  			Value type: Integer cells. A register entry, expressed
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index be66b7c..5fb3150 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -36,6 +36,18 @@ config ARM_CCI400_PORT_CTRL
>  	  Low level power management driver for CCI400 cache coherent
>  	  interconnect for ARM platforms.
>  
> +config ARM_CCI500_PMU
> +	bool "ARM CCI500 PMU support"
> +	default y
> +	depends on ARM || ARM64
> +	depends on HW_PERF_EVENTS
> +	select ARM_CCI_PMU
> +	help
> +	  Support for PMU events monitoring on the ARM CCI-500 cache coherent
> +	  interconnect.
> +
> +	  If unsure, say Y
> +
>  config ARM_CCN
>  	bool "ARM CCN driver support"
>  	depends on ARM || ARM64
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 2b43cea..e12ddba 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -52,6 +52,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  #ifdef CONFIG_ARM_CCI400_COMMON
>  	{.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA },
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	{ .compatible = "arm,cci-500", },
> +#endif
>  	{},
>  };
>  
> @@ -89,6 +92,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  enum {
>  	CCI_IF_SLAVE,
>  	CCI_IF_MASTER,
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	CCI_IF_GLOBAL,
> +#endif
>  	CCI_IF_MAX,
>  };
>  
> @@ -145,6 +151,9 @@ enum cci_models {
>  	CCI400_R0,
>  	CCI400_R1,
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	CCI500_R0,
> +#endif
>  	CCI_MODEL_MAX
>  };
>  
> @@ -294,6 +303,101 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
>  }
>  #endif	/* CONFIG_ARM_CCI400_PMU */
>  
> +#ifdef CONFIG_ARM_CCI500_PMU
> +
> +/*
> + * CCI500 provides 8 independent event counters that can count
> + * any of the events available.
> + *
> + * CCI500 PMU event id is an 9-bit value made of two parts.
> + *	 bits [8:5] - Source for the event
> + *		      0x0-0x6 - Slave interfaces
> + *		      0x8-0xD - Master interfaces
> + *		      0xf     - Global Events
> + *		      0x7,0xe - Reserved
> + *
> + *	 bits [4:0] - Event code (specific to type of interface)
> + */
> +
> +/* Port ids */
> +#define CCI500_PORT_S0			0x0
> +#define CCI500_PORT_S1			0x1
> +#define CCI500_PORT_S2			0x2
> +#define CCI500_PORT_S3			0x3
> +#define CCI500_PORT_S4			0x4
> +#define CCI500_PORT_S5			0x5
> +#define CCI500_PORT_S6			0x6
> +
> +#define CCI500_PORT_M0			0x8
> +#define CCI500_PORT_M1			0x9
> +#define CCI500_PORT_M2			0xa
> +#define CCI500_PORT_M3			0xb
> +#define CCI500_PORT_M4			0xc
> +#define CCI500_PORT_M5			0xd
> +
> +#define CCI500_PORT_GLOBAL 		0xf
> +
> +#define CCI500_PMU_EVENT_MASK		0x1ffUL
> +#define CCI500_PMU_EVENT_SOURCE_SHIFT	0x5
> +#define CCI500_PMU_EVENT_SOURCE_MASK	0xf
> +#define CCI500_PMU_EVENT_CODE_SHIFT	0x0
> +#define CCI500_PMU_EVENT_CODE_MASK	0x1f
> +
> +#define CCI500_PMU_EVENT_SOURCE(event)	\
> +	((event >> CCI500_PMU_EVENT_SOURCE_SHIFT) & CCI500_PMU_EVENT_SOURCE_MASK)
> +#define CCI500_PMU_EVENT_CODE(event)	\
> +	((event >> CCI500_PMU_EVENT_CODE_SHIFT) & CCI500_PMU_EVENT_CODE_MASK)
> +
> +#define CCI500_SLAVE_PORT_MIN_EV	0x00
> +#define CCI500_SLAVE_PORT_MAX_EV	0x1f
> +#define CCI500_MASTER_PORT_MIN_EV	0x00
> +#define CCI500_MASTER_PORT_MAX_EV	0x06
> +#define CCI500_GLOBAL_PORT_MIN_EV	0x00
> +#define CCI500_GLOBAL_PORT_MAX_EV	0x0f
> +
> +static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
> +					unsigned long hw_event)
> +{
> +	u32 ev_source = CCI500_PMU_EVENT_SOURCE(hw_event);
> +	u32 ev_code = CCI500_PMU_EVENT_CODE(hw_event);
> +	int if_type;
> +
> +	if (hw_event & ~CCI500_PMU_EVENT_MASK)
> +		return -ENOENT;
> +
> +	switch (ev_source) {
> +	case CCI500_PORT_S0:
> +	case CCI500_PORT_S1:
> +	case CCI500_PORT_S2:
> +	case CCI500_PORT_S3:
> +	case CCI500_PORT_S4:
> +	case CCI500_PORT_S5:
> +	case CCI500_PORT_S6:
> +		if_type = CCI_IF_SLAVE;
> +		break;
> +	case CCI500_PORT_M0:
> +	case CCI500_PORT_M1:
> +	case CCI500_PORT_M2:
> +	case CCI500_PORT_M3:
> +	case CCI500_PORT_M4:
> +	case CCI500_PORT_M5:
> +		if_type = CCI_IF_MASTER;
> +		break;
> +	case CCI500_PORT_GLOBAL:
> +		if_type = CCI_IF_GLOBAL;
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
> +
> +	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
> +		ev_code <= cci_pmu->model->event_ranges[if_type].max)
> +		return hw_event;
> +
> +	return -ENOENT;
> +}
> +#endif	/* CONFIG_ARM_CCI500_PMU */
> +
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
>  	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> @@ -981,6 +1085,29 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.get_event_idx = cci400_get_event_idx,
>  	},
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	[CCI500_R0] = {
> +		.name = "CCI_500",
> +		.fixed_hw_cntrs = 0,
> +		.num_hw_cntrs = 8,
> +		.cntr_size = SZ_64K,
> +		.event_ranges = {
> +			[CCI_IF_SLAVE] = {
> +				CCI500_SLAVE_PORT_MIN_EV,
> +				CCI500_SLAVE_PORT_MAX_EV,
> +			},
> +			[CCI_IF_MASTER] = {
> +				CCI500_MASTER_PORT_MIN_EV,
> +				CCI500_MASTER_PORT_MAX_EV,
> +			},
> +			[CCI_IF_GLOBAL] = {
> +				CCI500_GLOBAL_PORT_MIN_EV,
> +				CCI500_GLOBAL_PORT_MAX_EV,
> +			},
> +		},
> +		.validate_hw_event = cci500_validate_hw_event,
> +	},
> +#endif
>  };
>  
>  static const struct of_device_id arm_cci_pmu_matches[] = {
> @@ -998,6 +1125,12 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
>  		.data	= &cci_pmu_models[CCI400_R1],
>  	},
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	{
> +		.compatible = "arm,cci-500-pmu,r0",
> +		.data = &cci_pmu_models[CCI500_R0],
> +	},
> +#endif
>  	{},
>  };
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 6/7] arm-cci: Add CCI-500 PMU support
@ 2015-05-18 13:22     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> CCI-500 provides 8 event counters which can count any of the
> supported events independently. The PMU event id is a 9-bit
> value made of two parts.
> 	bits [8:5] - Source port
> 			0x0-0x6 Slave Ports
> 			0x8-0xD Master Ports
> 			0xf     Global Events to CCI
> 			0x7,0xe Reserved
> 	bits [0:4] - Event code (specific to each type of port)
>
> The generic CCI-500 controlling interface remains the same with CCI-400.
> However there are some differences in the PMU event counters.
>  - No cycle counter
>  - Upto 8 counters(4 in CCI-400)
>  - Each counter area is 64K(4K in CCI400)
>  - The counter0 starts at offset 0x10000 from the base of CCI
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: devicetree at vger.kernel.org
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

> ---
>  Documentation/devicetree/bindings/arm/cci.txt |    4 +-
>  drivers/bus/Kconfig                           |   12 +++
>  drivers/bus/arm-cci.c                         |  133 +++++++++++++++++++++++++
>  3 files changed, 148 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt
> index 3c5c631..aef1d20 100644
> --- a/Documentation/devicetree/bindings/arm/cci.txt
> +++ b/Documentation/devicetree/bindings/arm/cci.txt
> @@ -31,8 +31,9 @@ specific to ARM.
>  	- compatible
>  		Usage: required
>  		Value type: <string>
> -		Definition: must be set to
> +		Definition: must contain one of the following:
>  			    "arm,cci-400"
> +			    "arm,cci-500"
>  
>  	- reg
>  		Usage: required
> @@ -99,6 +100,7 @@ specific to ARM.
>  				 "arm,cci-400-pmu,r1"
>  				 "arm,cci-400-pmu"  - DEPRECATED, permitted only where OS has
>  						      secure acces to CCI registers
> +				 "arm,cci-500-pmu,r0"
>  		- reg:
>  			Usage: required
>  			Value type: Integer cells. A register entry, expressed
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index be66b7c..5fb3150 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -36,6 +36,18 @@ config ARM_CCI400_PORT_CTRL
>  	  Low level power management driver for CCI400 cache coherent
>  	  interconnect for ARM platforms.
>  
> +config ARM_CCI500_PMU
> +	bool "ARM CCI500 PMU support"
> +	default y
> +	depends on ARM || ARM64
> +	depends on HW_PERF_EVENTS
> +	select ARM_CCI_PMU
> +	help
> +	  Support for PMU events monitoring on the ARM CCI-500 cache coherent
> +	  interconnect.
> +
> +	  If unsure, say Y
> +
>  config ARM_CCN
>  	bool "ARM CCN driver support"
>  	depends on ARM || ARM64
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 2b43cea..e12ddba 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -52,6 +52,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  #ifdef CONFIG_ARM_CCI400_COMMON
>  	{.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA },
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	{ .compatible = "arm,cci-500", },
> +#endif
>  	{},
>  };
>  
> @@ -89,6 +92,9 @@ static const struct of_device_id arm_cci_matches[] = {
>  enum {
>  	CCI_IF_SLAVE,
>  	CCI_IF_MASTER,
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	CCI_IF_GLOBAL,
> +#endif
>  	CCI_IF_MAX,
>  };
>  
> @@ -145,6 +151,9 @@ enum cci_models {
>  	CCI400_R0,
>  	CCI400_R1,
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	CCI500_R0,
> +#endif
>  	CCI_MODEL_MAX
>  };
>  
> @@ -294,6 +303,101 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
>  }
>  #endif	/* CONFIG_ARM_CCI400_PMU */
>  
> +#ifdef CONFIG_ARM_CCI500_PMU
> +
> +/*
> + * CCI500 provides 8 independent event counters that can count
> + * any of the events available.
> + *
> + * CCI500 PMU event id is an 9-bit value made of two parts.
> + *	 bits [8:5] - Source for the event
> + *		      0x0-0x6 - Slave interfaces
> + *		      0x8-0xD - Master interfaces
> + *		      0xf     - Global Events
> + *		      0x7,0xe - Reserved
> + *
> + *	 bits [4:0] - Event code (specific to type of interface)
> + */
> +
> +/* Port ids */
> +#define CCI500_PORT_S0			0x0
> +#define CCI500_PORT_S1			0x1
> +#define CCI500_PORT_S2			0x2
> +#define CCI500_PORT_S3			0x3
> +#define CCI500_PORT_S4			0x4
> +#define CCI500_PORT_S5			0x5
> +#define CCI500_PORT_S6			0x6
> +
> +#define CCI500_PORT_M0			0x8
> +#define CCI500_PORT_M1			0x9
> +#define CCI500_PORT_M2			0xa
> +#define CCI500_PORT_M3			0xb
> +#define CCI500_PORT_M4			0xc
> +#define CCI500_PORT_M5			0xd
> +
> +#define CCI500_PORT_GLOBAL 		0xf
> +
> +#define CCI500_PMU_EVENT_MASK		0x1ffUL
> +#define CCI500_PMU_EVENT_SOURCE_SHIFT	0x5
> +#define CCI500_PMU_EVENT_SOURCE_MASK	0xf
> +#define CCI500_PMU_EVENT_CODE_SHIFT	0x0
> +#define CCI500_PMU_EVENT_CODE_MASK	0x1f
> +
> +#define CCI500_PMU_EVENT_SOURCE(event)	\
> +	((event >> CCI500_PMU_EVENT_SOURCE_SHIFT) & CCI500_PMU_EVENT_SOURCE_MASK)
> +#define CCI500_PMU_EVENT_CODE(event)	\
> +	((event >> CCI500_PMU_EVENT_CODE_SHIFT) & CCI500_PMU_EVENT_CODE_MASK)
> +
> +#define CCI500_SLAVE_PORT_MIN_EV	0x00
> +#define CCI500_SLAVE_PORT_MAX_EV	0x1f
> +#define CCI500_MASTER_PORT_MIN_EV	0x00
> +#define CCI500_MASTER_PORT_MAX_EV	0x06
> +#define CCI500_GLOBAL_PORT_MIN_EV	0x00
> +#define CCI500_GLOBAL_PORT_MAX_EV	0x0f
> +
> +static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
> +					unsigned long hw_event)
> +{
> +	u32 ev_source = CCI500_PMU_EVENT_SOURCE(hw_event);
> +	u32 ev_code = CCI500_PMU_EVENT_CODE(hw_event);
> +	int if_type;
> +
> +	if (hw_event & ~CCI500_PMU_EVENT_MASK)
> +		return -ENOENT;
> +
> +	switch (ev_source) {
> +	case CCI500_PORT_S0:
> +	case CCI500_PORT_S1:
> +	case CCI500_PORT_S2:
> +	case CCI500_PORT_S3:
> +	case CCI500_PORT_S4:
> +	case CCI500_PORT_S5:
> +	case CCI500_PORT_S6:
> +		if_type = CCI_IF_SLAVE;
> +		break;
> +	case CCI500_PORT_M0:
> +	case CCI500_PORT_M1:
> +	case CCI500_PORT_M2:
> +	case CCI500_PORT_M3:
> +	case CCI500_PORT_M4:
> +	case CCI500_PORT_M5:
> +		if_type = CCI_IF_MASTER;
> +		break;
> +	case CCI500_PORT_GLOBAL:
> +		if_type = CCI_IF_GLOBAL;
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
> +
> +	if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
> +		ev_code <= cci_pmu->model->event_ranges[if_type].max)
> +		return hw_event;
> +
> +	return -ENOENT;
> +}
> +#endif	/* CONFIG_ARM_CCI500_PMU */
> +
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
>  	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> @@ -981,6 +1085,29 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.get_event_idx = cci400_get_event_idx,
>  	},
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	[CCI500_R0] = {
> +		.name = "CCI_500",
> +		.fixed_hw_cntrs = 0,
> +		.num_hw_cntrs = 8,
> +		.cntr_size = SZ_64K,
> +		.event_ranges = {
> +			[CCI_IF_SLAVE] = {
> +				CCI500_SLAVE_PORT_MIN_EV,
> +				CCI500_SLAVE_PORT_MAX_EV,
> +			},
> +			[CCI_IF_MASTER] = {
> +				CCI500_MASTER_PORT_MIN_EV,
> +				CCI500_MASTER_PORT_MAX_EV,
> +			},
> +			[CCI_IF_GLOBAL] = {
> +				CCI500_GLOBAL_PORT_MIN_EV,
> +				CCI500_GLOBAL_PORT_MAX_EV,
> +			},
> +		},
> +		.validate_hw_event = cci500_validate_hw_event,
> +	},
> +#endif
>  };
>  
>  static const struct of_device_id arm_cci_pmu_matches[] = {
> @@ -998,6 +1125,12 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
>  		.data	= &cci_pmu_models[CCI400_R1],
>  	},
>  #endif
> +#ifdef CONFIG_ARM_CCI500_PMU
> +	{
> +		.compatible = "arm,cci-500-pmu,r0",
> +		.data = &cci_pmu_models[CCI500_R0],
> +	},
> +#endif
>  	{},
>  };

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 7/7] arm-cci: Add aliases for PMU events
  2015-05-05 11:49   ` Suzuki K. Poulose
@ 2015-05-18 13:33     ` Punit Agrawal
  -1 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:33 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel, Mark Rutland, devicetree, Lorenzo Pieralisi,
	Arnd Bergmann, Pawel Moll, Will Deacon, linux-kernel, arm,
	Olof Johansson

Hi Suzuki,

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Each CCI model have different event/source codes and formats. This
> patch exports this information via the sysfs, which includes the
> aliases for the events. The aliases are listed by 'perf list', helping
> the users to specify the name of the event instead of the binary
> config values.
>
> Each event alias must accompany the 'source' code except for the
> following cases :
>
> 1) CCI-400 - cycles event, doesn't relate to an interface.
> 2) CCI-500 - Global events to the CCI. (Fixed source code = 0xf)
>
> Each CCI model provides two sets of attributes(format and event),
> which are dynamically populated before registering the PMU, to
> allow for the appropriate information.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

Thanks for the clean-ups and re-factoring. This series is a nice
improvement on existing code and the aliases should improve usability as
well.

Regards,
Punit

> ---
>  drivers/bus/arm-cci.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 295 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index e12ddba..a72fccb 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -121,6 +121,10 @@ struct cci_pmu_model {
>  	u32 fixed_hw_cntrs;
>  	u32 num_hw_cntrs;
>  	u32 cntr_size;
> +	u64 nformat_attrs;
> +	u64 nevent_attrs;
> +	struct dev_ext_attribute *format_attrs;
> +	struct dev_ext_attribute *event_attrs;
>  	struct event_range event_ranges[CCI_IF_MAX];
>  	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
>  	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
> @@ -157,6 +161,19 @@ enum cci_models {
>  	CCI_MODEL_MAX
>  };
>  
> +static ssize_t cci_pmu_format_show(struct device *dev,
> +			struct device_attribute *attr, char *buf);
> +static ssize_t cci_pmu_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf);
> +
> +#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
> +	{ __ATTR(_name, S_IRUGO, _func, NULL), (void *)_config }
> +
> +#define CCI_FORMAT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_format_show, (char *)_config)
> +#define CCI_EVENT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_event_show, (unsigned long)_config)
> +
>  /* CCI400 PMU Specific definitions */
>  
>  #ifdef CONFIG_ARM_CCI400_PMU
> @@ -218,6 +235,106 @@ enum cci400_perf_events {
>  #define CCI400_R1_MASTER_PORT_MIN_EV	0x00
>  #define CCI400_R1_MASTER_PORT_MAX_EV	0x11
>  
> +#define CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci400_pmu_cycle_event_show, \
> +					(unsigned long)_config)
> +
> +static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf);
> +
> +static struct dev_ext_attribute cci400_pmu_format_attrs[] = {
> +	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
> +	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-7"),
> +};
> +
> +static struct dev_ext_attribute cci400_r0_pmu_event_attrs[] = {
> +	/* Slave events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
> +	/* Master events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x14),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_addr_hazard, 0x15),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_id_hazard, 0x16),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_tt_full, 0x17),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x18),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x19),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_tt_full, 0x1A),
> +	/* Special event for cycles counter */
> +	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
> +};
> +
> +static struct dev_ext_attribute cci400_r1_pmu_event_attrs[] = {
> +	/* Slave events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_slave_id_hazard, 0x14),
> +	/* Master events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_stall_cycle_addr_hazard, 0x1),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_master_id_hazard, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_hi_prio_rtq_full, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_wtq_full, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_low_prio_rtq_full, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_mid_prio_rtq_full, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn0, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn1, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn2, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn3, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn0, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn1, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn2, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn3, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_unique_or_line_unique_addr_hazard, 0x11),
> +	/* Special event for cycles counter */
> +	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
> +};
> +
> +static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +				struct dev_ext_attribute, attr);
> +	return snprintf(buf, PAGE_SIZE, "config=0x%lx\n", (unsigned long)eattr->var);
> +}
> +
>  static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  				struct cci_pmu_hw_events *hw,
>  				unsigned long cci_event)
> @@ -355,6 +472,92 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
>  #define CCI500_GLOBAL_PORT_MIN_EV	0x00
>  #define CCI500_GLOBAL_PORT_MAX_EV	0x0f
>  
> +
> +#define CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci500_pmu_global_event_show, \
> +					(unsigned long) _config)
> +
> +static ssize_t cci500_pmu_global_event_show(struct device *dev,
> +				struct device_attribute *attr, char *buf);
> +
> +static struct dev_ext_attribute cci500_pmu_format_attrs[] = {
> +	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
> +	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-8"),
> +};
> +
> +static struct dev_ext_attribute cci500_pmu_event_attrs[] = {
> +	/* Slave events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_arvalid, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_dev, 0x1),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_nonshareable, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_non_alloc, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_alloc, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_invalidate, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maint, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rval, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rlast_snoop, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_awalid, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_dev, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_non_shareable, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wb, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wlu, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wunique, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_evict, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_wrevict, 0x11),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_beat, 0x12),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_acvalid, 0x13),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_read, 0x14),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_clean, 0x15),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_data_transfer_low, 0x16),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_arvalid, 0x17),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall, 0x18),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall, 0x19),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_stall, 0x1A),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_w_resp_stall, 0x1B),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_stall, 0x1C),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_s_data_stall, 0x1D),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rq_stall_ot_limit, 0x1E),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_stall_arbit, 0x1F),
> +
> +	/* Master events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_beat_any, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_beat_any, 0x1),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_stall, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_stall, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_resp_stall, 0x6),
> +
> +	/* Global events */
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_0_1, 0x0),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_2_3, 0x1),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_4_5, 0x2),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_6_7, 0x3),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_0_1, 0x4),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_2_3, 0x5),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_4_5, 0x6),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_6_7, 0x7),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_back_invalidation, 0x8),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_alloc_busy, 0x9),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_tt_full, 0xA),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_wrq, 0xB),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_cd_hs, 0xC),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_rq_stall_addr_hazard, 0xD),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snopp_rq_stall_tt_full, 0xE),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_rq_tzmp1_prot, 0xF),
> +};
> +
> +static ssize_t cci500_pmu_global_event_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +					struct dev_ext_attribute, attr);
> +	/* Global events have single fixed source code */
> +	return snprintf(buf, PAGE_SIZE, "event=0x%lx,source=0x%x\n",
> +				(unsigned long)eattr->var, CCI500_PORT_GLOBAL);
> +}
> +
>  static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
>  					unsigned long hw_event)
>  {
> @@ -398,6 +601,24 @@ static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
>  }
>  #endif	/* CONFIG_ARM_CCI500_PMU */
>  
> +static ssize_t cci_pmu_format_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +				struct dev_ext_attribute, attr);
> +	return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var);
> +}
> +
> +static ssize_t cci_pmu_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +				struct dev_ext_attribute, attr);
> +	/* source parameter is mandatory for normal PMU events */
> +	return snprintf(buf, PAGE_SIZE, "source=?,event=0x%lx\n",
> +					 (unsigned long)eattr->var);
> +}
> +
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
>  	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> @@ -980,17 +1201,78 @@ static struct attribute_group pmu_attr_group = {
>  	.attrs = pmu_attrs,
>  };
>  
> +static struct attribute_group pmu_format_attr_group = {
> +	.name = "format",
> +	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
> +};
> +
> +static struct attribute_group pmu_event_attr_group = {
> +	.name = "events",
> +	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
> +};
> +
>  static const struct attribute_group *pmu_attr_groups[] = {
>  	&pmu_attr_group,
> +	&pmu_format_attr_group,
> +	&pmu_event_attr_group,
>  	NULL
>  };
>  
> +static struct attribute **alloc_attrs(struct platform_device *pdev,
> +				int n, struct dev_ext_attribute *source)
> +{
> +	int i;
> +	struct attribute **attrs;
> +
> +	/* Alloc n + 1 (for terminating NULL) */
> +	attrs  = devm_kcalloc(&pdev->dev, n + 1, sizeof(struct attribute *),
> +								GFP_KERNEL);
> +	if (!attrs)
> +		return attrs;
> +	for(i = 0; i < n; i++)
> +		attrs[i] = &source[i].attr.attr;
> +	return attrs;
> +}
> +
> +static int cci_pmu_init_attrs(struct cci_pmu *cci_pmu, struct platform_device *pdev)
> +{
> +	const struct cci_pmu_model *model = cci_pmu->model;
> +	struct attribute **attrs;
> +
> +	/*
> +	 * All allocations below are managed, hence doesn't need to be
> +	 * free'd explicitly in case of an error.
> +	 */
> +
> +	if (model->nevent_attrs) {
> +		attrs = alloc_attrs(pdev, model->nevent_attrs,
> +						model->event_attrs);
> +		if (!attrs)
> +			return -ENOMEM;
> +		pmu_event_attr_group.attrs = attrs;
> +	}
> +	if (model->nformat_attrs) {
> +		attrs = alloc_attrs(pdev, model->nformat_attrs,
> +						 model->format_attrs);
> +		if (!attrs)
> +			return -ENOMEM;
> +		pmu_format_attr_group.attrs = attrs;
> +	}
> +	pmu_cpumask_attr.var = cci_pmu;
> +
> +	return 0;
> +}
> +
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
>  	u32 num_cntrs;
> +	int rc;
> +
> +	rc = cci_pmu_init_attrs(cci_pmu, pdev);
> +	if (rc)
> +		return rc;
>  
> -	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
>  		.name		= cci_pmu->model->name,
>  		.task_ctx_nr	= perf_invalid_context,
> @@ -1053,6 +1335,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
> +		.format_attrs = cci400_pmu_format_attrs,
> +		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
> +		.event_attrs = cci400_r0_pmu_event_attrs,
> +		.nevent_attrs = ARRAY_SIZE(cci400_r0_pmu_event_attrs),
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI400_R0_SLAVE_PORT_MIN_EV,
> @@ -1071,6 +1357,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
> +		.format_attrs = cci400_pmu_format_attrs,
> +		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
> +		.event_attrs = cci400_r1_pmu_event_attrs,
> +		.nevent_attrs = ARRAY_SIZE(cci400_r1_pmu_event_attrs),
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI400_R1_SLAVE_PORT_MIN_EV,
> @@ -1091,6 +1381,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.fixed_hw_cntrs = 0,
>  		.num_hw_cntrs = 8,
>  		.cntr_size = SZ_64K,
> +		.format_attrs = cci500_pmu_format_attrs,
> +		.nformat_attrs = ARRAY_SIZE(cci500_pmu_format_attrs),
> +		.event_attrs = cci500_pmu_event_attrs,
> +		.nevent_attrs = ARRAY_SIZE(cci500_pmu_event_attrs),
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI500_SLAVE_PORT_MIN_EV,

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 7/7] arm-cci: Add aliases for PMU events
@ 2015-05-18 13:33     ` Punit Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Punit Agrawal @ 2015-05-18 13:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Suzuki,

"Suzuki K. Poulose" <suzuki.poulose@arm.com> writes:

> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>
> Each CCI model have different event/source codes and formats. This
> patch exports this information via the sysfs, which includes the
> aliases for the events. The aliases are listed by 'perf list', helping
> the users to specify the name of the event instead of the binary
> config values.
>
> Each event alias must accompany the 'source' code except for the
> following cases :
>
> 1) CCI-400 - cycles event, doesn't relate to an interface.
> 2) CCI-500 - Global events to the CCI. (Fixed source code = 0xf)
>
> Each CCI model provides two sets of attributes(format and event),
> which are dynamically populated before registering the PMU, to
> allow for the appropriate information.
>
> Cc: Punit Agrawal <punit.agrawal@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>

Acked-by: Punit Agrawal <punit.agrawal@arm.com>

Thanks for the clean-ups and re-factoring. This series is a nice
improvement on existing code and the aliases should improve usability as
well.

Regards,
Punit

> ---
>  drivers/bus/arm-cci.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 295 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index e12ddba..a72fccb 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -121,6 +121,10 @@ struct cci_pmu_model {
>  	u32 fixed_hw_cntrs;
>  	u32 num_hw_cntrs;
>  	u32 cntr_size;
> +	u64 nformat_attrs;
> +	u64 nevent_attrs;
> +	struct dev_ext_attribute *format_attrs;
> +	struct dev_ext_attribute *event_attrs;
>  	struct event_range event_ranges[CCI_IF_MAX];
>  	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
>  	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
> @@ -157,6 +161,19 @@ enum cci_models {
>  	CCI_MODEL_MAX
>  };
>  
> +static ssize_t cci_pmu_format_show(struct device *dev,
> +			struct device_attribute *attr, char *buf);
> +static ssize_t cci_pmu_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf);
> +
> +#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
> +	{ __ATTR(_name, S_IRUGO, _func, NULL), (void *)_config }
> +
> +#define CCI_FORMAT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_format_show, (char *)_config)
> +#define CCI_EVENT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci_pmu_event_show, (unsigned long)_config)
> +
>  /* CCI400 PMU Specific definitions */
>  
>  #ifdef CONFIG_ARM_CCI400_PMU
> @@ -218,6 +235,106 @@ enum cci400_perf_events {
>  #define CCI400_R1_MASTER_PORT_MIN_EV	0x00
>  #define CCI400_R1_MASTER_PORT_MAX_EV	0x11
>  
> +#define CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci400_pmu_cycle_event_show, \
> +					(unsigned long)_config)
> +
> +static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf);
> +
> +static struct dev_ext_attribute cci400_pmu_format_attrs[] = {
> +	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
> +	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-7"),
> +};
> +
> +static struct dev_ext_attribute cci400_r0_pmu_event_attrs[] = {
> +	/* Slave events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
> +	/* Master events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x14),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_addr_hazard, 0x15),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_id_hazard, 0x16),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_tt_full, 0x17),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x18),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x19),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_tt_full, 0x1A),
> +	/* Special event for cycles counter */
> +	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
> +};
> +
> +static struct dev_ext_attribute cci400_r1_pmu_event_attrs[] = {
> +	/* Slave events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_slave_id_hazard, 0x14),
> +	/* Master events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_stall_cycle_addr_hazard, 0x1),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_master_id_hazard, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_hi_prio_rtq_full, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_wtq_full, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_low_prio_rtq_full, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_mid_prio_rtq_full, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn0, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn1, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn2, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn3, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn0, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn1, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn2, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn3, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_unique_or_line_unique_addr_hazard, 0x11),
> +	/* Special event for cycles counter */
> +	CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
> +};
> +
> +static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +				struct dev_ext_attribute, attr);
> +	return snprintf(buf, PAGE_SIZE, "config=0x%lx\n", (unsigned long)eattr->var);
> +}
> +
>  static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
>  				struct cci_pmu_hw_events *hw,
>  				unsigned long cci_event)
> @@ -355,6 +472,92 @@ static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev
>  #define CCI500_GLOBAL_PORT_MIN_EV	0x00
>  #define CCI500_GLOBAL_PORT_MAX_EV	0x0f
>  
> +
> +#define CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(_name, _config) \
> +	CCI_EXT_ATTR_ENTRY(_name, cci500_pmu_global_event_show, \
> +					(unsigned long) _config)
> +
> +static ssize_t cci500_pmu_global_event_show(struct device *dev,
> +				struct device_attribute *attr, char *buf);
> +
> +static struct dev_ext_attribute cci500_pmu_format_attrs[] = {
> +	CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
> +	CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-8"),
> +};
> +
> +static struct dev_ext_attribute cci500_pmu_event_attrs[] = {
> +	/* Slave events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_arvalid, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_dev, 0x1),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_nonshareable, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_non_alloc, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_alloc, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_invalidate, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maint, 0x6),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rval, 0x8),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rlast_snoop, 0x9),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_awalid, 0xA),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_dev, 0xB),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_non_shareable, 0xC),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wb, 0xD),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wlu, 0xE),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wunique, 0xF),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_evict, 0x10),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_wrevict, 0x11),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_beat, 0x12),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_acvalid, 0x13),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_read, 0x14),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_clean, 0x15),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_data_transfer_low, 0x16),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_arvalid, 0x17),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall, 0x18),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall, 0x19),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_stall, 0x1A),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_w_resp_stall, 0x1B),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_srq_stall, 0x1C),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_s_data_stall, 0x1D),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_rq_stall_ot_limit, 0x1E),
> +	CCI_EVENT_EXT_ATTR_ENTRY(si_r_stall_arbit, 0x1F),
> +
> +	/* Master events */
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_beat_any, 0x0),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_beat_any, 0x1),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall, 0x2),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_stall, 0x3),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall, 0x4),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_stall, 0x5),
> +	CCI_EVENT_EXT_ATTR_ENTRY(mi_w_resp_stall, 0x6),
> +
> +	/* Global events */
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_0_1, 0x0),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_2_3, 0x1),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_4_5, 0x2),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_6_7, 0x3),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_0_1, 0x4),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_2_3, 0x5),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_4_5, 0x6),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_6_7, 0x7),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_back_invalidation, 0x8),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_alloc_busy, 0x9),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_tt_full, 0xA),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_wrq, 0xB),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_cd_hs, 0xC),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_rq_stall_addr_hazard, 0xD),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snopp_rq_stall_tt_full, 0xE),
> +	CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_rq_tzmp1_prot, 0xF),
> +};
> +
> +static ssize_t cci500_pmu_global_event_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +					struct dev_ext_attribute, attr);
> +	/* Global events have single fixed source code */
> +	return snprintf(buf, PAGE_SIZE, "event=0x%lx,source=0x%x\n",
> +				(unsigned long)eattr->var, CCI500_PORT_GLOBAL);
> +}
> +
>  static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
>  					unsigned long hw_event)
>  {
> @@ -398,6 +601,24 @@ static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
>  }
>  #endif	/* CONFIG_ARM_CCI500_PMU */
>  
> +static ssize_t cci_pmu_format_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +				struct dev_ext_attribute, attr);
> +	return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var);
> +}
> +
> +static ssize_t cci_pmu_event_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr = container_of(attr,
> +				struct dev_ext_attribute, attr);
> +	/* source parameter is mandatory for normal PMU events */
> +	return snprintf(buf, PAGE_SIZE, "source=?,event=0x%lx\n",
> +					 (unsigned long)eattr->var);
> +}
> +
>  static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
>  {
>  	return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
> @@ -980,17 +1201,78 @@ static struct attribute_group pmu_attr_group = {
>  	.attrs = pmu_attrs,
>  };
>  
> +static struct attribute_group pmu_format_attr_group = {
> +	.name = "format",
> +	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
> +};
> +
> +static struct attribute_group pmu_event_attr_group = {
> +	.name = "events",
> +	.attrs = NULL,		/* Filled in cci_pmu_init_attrs */
> +};
> +
>  static const struct attribute_group *pmu_attr_groups[] = {
>  	&pmu_attr_group,
> +	&pmu_format_attr_group,
> +	&pmu_event_attr_group,
>  	NULL
>  };
>  
> +static struct attribute **alloc_attrs(struct platform_device *pdev,
> +				int n, struct dev_ext_attribute *source)
> +{
> +	int i;
> +	struct attribute **attrs;
> +
> +	/* Alloc n + 1 (for terminating NULL) */
> +	attrs  = devm_kcalloc(&pdev->dev, n + 1, sizeof(struct attribute *),
> +								GFP_KERNEL);
> +	if (!attrs)
> +		return attrs;
> +	for(i = 0; i < n; i++)
> +		attrs[i] = &source[i].attr.attr;
> +	return attrs;
> +}
> +
> +static int cci_pmu_init_attrs(struct cci_pmu *cci_pmu, struct platform_device *pdev)
> +{
> +	const struct cci_pmu_model *model = cci_pmu->model;
> +	struct attribute **attrs;
> +
> +	/*
> +	 * All allocations below are managed, hence doesn't need to be
> +	 * free'd explicitly in case of an error.
> +	 */
> +
> +	if (model->nevent_attrs) {
> +		attrs = alloc_attrs(pdev, model->nevent_attrs,
> +						model->event_attrs);
> +		if (!attrs)
> +			return -ENOMEM;
> +		pmu_event_attr_group.attrs = attrs;
> +	}
> +	if (model->nformat_attrs) {
> +		attrs = alloc_attrs(pdev, model->nformat_attrs,
> +						 model->format_attrs);
> +		if (!attrs)
> +			return -ENOMEM;
> +		pmu_format_attr_group.attrs = attrs;
> +	}
> +	pmu_cpumask_attr.var = cci_pmu;
> +
> +	return 0;
> +}
> +
>  static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
>  {
>  	char *name = cci_pmu->model->name;
>  	u32 num_cntrs;
> +	int rc;
> +
> +	rc = cci_pmu_init_attrs(cci_pmu, pdev);
> +	if (rc)
> +		return rc;
>  
> -	pmu_cpumask_attr.var = cci_pmu;
>  	cci_pmu->pmu = (struct pmu) {
>  		.name		= cci_pmu->model->name,
>  		.task_ctx_nr	= perf_invalid_context,
> @@ -1053,6 +1335,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
> +		.format_attrs = cci400_pmu_format_attrs,
> +		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
> +		.event_attrs = cci400_r0_pmu_event_attrs,
> +		.nevent_attrs = ARRAY_SIZE(cci400_r0_pmu_event_attrs),
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI400_R0_SLAVE_PORT_MIN_EV,
> @@ -1071,6 +1357,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.fixed_hw_cntrs = 1,	/* Cycle counter */
>  		.num_hw_cntrs = 4,
>  		.cntr_size = SZ_4K,
> +		.format_attrs = cci400_pmu_format_attrs,
> +		.nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
> +		.event_attrs = cci400_r1_pmu_event_attrs,
> +		.nevent_attrs = ARRAY_SIZE(cci400_r1_pmu_event_attrs),
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI400_R1_SLAVE_PORT_MIN_EV,
> @@ -1091,6 +1381,10 @@ static struct cci_pmu_model cci_pmu_models[] = {
>  		.fixed_hw_cntrs = 0,
>  		.num_hw_cntrs = 8,
>  		.cntr_size = SZ_64K,
> +		.format_attrs = cci500_pmu_format_attrs,
> +		.nformat_attrs = ARRAY_SIZE(cci500_pmu_format_attrs),
> +		.event_attrs = cci500_pmu_event_attrs,
> +		.nevent_attrs = ARRAY_SIZE(cci500_pmu_event_attrs),
>  		.event_ranges = {
>  			[CCI_IF_SLAVE] = {
>  				CCI500_SLAVE_PORT_MIN_EV,

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 4/7] arm-cci: Abstract handling for CCI events
  2015-05-26  9:53 [PATCH 0/7] ARM CCI PMU updates for 4.2 Suzuki K. Poulose
@ 2015-05-26  9:53   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-26  9:53 UTC (permalink / raw)
  To: arm
  Cc: will.deacon, punit.agrawal, mark.rutland, linux-arm-kernel, arnd,
	olof, pawel.moll, linux-kernel, Suzuki K. Poulose

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Given that each CCI has different set of interfaces and
its associated events, it is good to abstract the validation of the
event codes to make it easier to add support for a new CCI model.

This patch also abstracts the mapping of a given event to a counter,
as there are some special counters for certain specific events.

We assume that the fixed hardware counters are always at the beginning,
so that we can use cci_model->fixed_hw_events as an upper bound to given
idx to check if we need to program the counter for an event.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Acked-by: Punit Agrawal <punit.agrawal@arm.com>
---
 drivers/bus/arm-cci.c |   78 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 23 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 602bf64..9b71c57 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -107,6 +107,7 @@ struct cci_pmu_hw_events {
 	raw_spinlock_t pmu_lock;
 };
 
+struct cci_pmu;
 /*
  * struct cci_pmu_model:
  * @fixed_hw_cntrs - Number of fixed event counters
@@ -119,6 +120,8 @@ struct cci_pmu_model {
 	u32 num_hw_cntrs;
 	u32 cntr_size;
 	struct event_range event_ranges[CCI_IF_MAX];
+	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
+	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
 };
 
 static struct cci_pmu_model cci_pmu_models[];
@@ -189,7 +192,29 @@ enum cci400_perf_events {
 #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
 
-static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
+static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
+				struct cci_pmu_hw_events *hw,
+				unsigned long cci_event)
+{
+	int idx;
+
+	/* cycles event idx is fixed */
+	if (cci_event == CCI_PMU_CYCLES) {
+		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+			return -EAGAIN;
+
+		return CCI_PMU_CYCLE_CNTR_IDX;
+	}
+
+	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+		if (!test_and_set_bit(idx, hw->used_mask))
+			return idx;
+
+	/* No counters available */
+	return -EAGAIN;
+}
+
+static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
 	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
 	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
@@ -198,6 +223,9 @@ static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event
 	if (hw_event & ~CCI_PMU_EVENT_MASK)
 		return -ENOENT;
 
+	if (hw_event == CCI_PMU_CYCLES)
+		return hw_event;
+
 	switch (ev_source) {
 	case CCI_PORT_S0:
 	case CCI_PORT_S1:
@@ -289,18 +317,14 @@ static u32 pmu_get_max_counters(void)
 static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
-	struct hw_perf_event *hw_event = &event->hw;
-	unsigned long cci_event = hw_event->config_base;
+	unsigned long cci_event = event->hw.config_base;
 	int idx;
 
-	if (cci_event == CCI_PMU_CYCLES) {
-		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
-			return -EAGAIN;
+	if (cci_pmu->model->get_event_idx)
+		return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
 
-		return CCI_PMU_CYCLE_CNTR_IDX;
-	}
-
-	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+	/* Generic code to find an unused idx from the mask */
+	for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
 		if (!test_and_set_bit(idx, hw->used_mask))
 			return idx;
 
@@ -310,19 +334,13 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
 
 static int pmu_map_event(struct perf_event *event)
 {
-	int mapping;
-	unsigned long config = event->attr.config;
+	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
 
-	if (event->attr.type < PERF_TYPE_MAX)
+	if (event->attr.type < PERF_TYPE_MAX ||
+			!cci_pmu->model->validate_hw_event)
 		return -ENOENT;
 
-	if (config == CCI_PMU_CYCLES)
-		mapping = config;
-	else
-		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
-							config);
-
-	return mapping;
+	return	cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config);
 }
 
 static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
@@ -450,7 +468,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 	 * This should work regardless of whether we have per-counter overflow
 	 * interrupt or a combined overflow interrupt.
 	 */
-	for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
+	for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
 		struct perf_event *event = events->events[idx];
 		struct hw_perf_event *hw_counter;
 
@@ -538,6 +556,16 @@ static void cci_pmu_disable(struct pmu *pmu)
 	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
 }
 
+/*
+ * Check if the idx represents a non-programmable counter.
+ * All the fixed event counters are mapped before the programmable
+ * counters.
+ */
+static bool pmu_fixed_hw_idx(struct cci_pmu *cci_pmu, int idx)
+{
+	return (idx >= 0) && (idx < cci_pmu->model->fixed_hw_cntrs);
+}
+
 static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
@@ -562,8 +590,8 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
 	raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
 
-	/* Configure the event to count, unless you are counting cycles */
-	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
+	/* Configure the counter unless you are counting a fixed event */
+	if (!pmu_fixed_hw_idx(cci_pmu, idx))
 		pmu_set_event(cci_pmu, idx, hwc->config_base);
 
 	pmu_event_set_period(event);
@@ -907,6 +935,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R0_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 	[CCI_REV_R1] = {
 		.name = "CCI_400_r1",
@@ -923,6 +953,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R1_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 };
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 4/7] arm-cci: Abstract handling for CCI events
@ 2015-05-26  9:53   ` Suzuki K. Poulose
  0 siblings, 0 replies; 41+ messages in thread
From: Suzuki K. Poulose @ 2015-05-26  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Given that each CCI has different set of interfaces and
its associated events, it is good to abstract the validation of the
event codes to make it easier to add support for a new CCI model.

This patch also abstracts the mapping of a given event to a counter,
as there are some special counters for certain specific events.

We assume that the fixed hardware counters are always at the beginning,
so that we can use cci_model->fixed_hw_events as an upper bound to given
idx to check if we need to program the counter for an event.

Cc: Punit Agrawal <punit.agrawal@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Acked-by: Punit Agrawal <punit.agrawal@arm.com>
---
 drivers/bus/arm-cci.c |   78 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 23 deletions(-)

diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 602bf64..9b71c57 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -107,6 +107,7 @@ struct cci_pmu_hw_events {
 	raw_spinlock_t pmu_lock;
 };
 
+struct cci_pmu;
 /*
  * struct cci_pmu_model:
  * @fixed_hw_cntrs - Number of fixed event counters
@@ -119,6 +120,8 @@ struct cci_pmu_model {
 	u32 num_hw_cntrs;
 	u32 cntr_size;
 	struct event_range event_ranges[CCI_IF_MAX];
+	int (*validate_hw_event)(struct cci_pmu *, unsigned long);
+	int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
 };
 
 static struct cci_pmu_model cci_pmu_models[];
@@ -189,7 +192,29 @@ enum cci400_perf_events {
 #define CCI_REV_R1_MASTER_PORT_MIN_EV	0x00
 #define CCI_REV_R1_MASTER_PORT_MAX_EV	0x11
 
-static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
+static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
+				struct cci_pmu_hw_events *hw,
+				unsigned long cci_event)
+{
+	int idx;
+
+	/* cycles event idx is fixed */
+	if (cci_event == CCI_PMU_CYCLES) {
+		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+			return -EAGAIN;
+
+		return CCI_PMU_CYCLE_CNTR_IDX;
+	}
+
+	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+		if (!test_and_set_bit(idx, hw->used_mask))
+			return idx;
+
+	/* No counters available */
+	return -EAGAIN;
+}
+
+static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
 {
 	u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
 	u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
@@ -198,6 +223,9 @@ static int pmu_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event
 	if (hw_event & ~CCI_PMU_EVENT_MASK)
 		return -ENOENT;
 
+	if (hw_event == CCI_PMU_CYCLES)
+		return hw_event;
+
 	switch (ev_source) {
 	case CCI_PORT_S0:
 	case CCI_PORT_S1:
@@ -289,18 +317,14 @@ static u32 pmu_get_max_counters(void)
 static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
-	struct hw_perf_event *hw_event = &event->hw;
-	unsigned long cci_event = hw_event->config_base;
+	unsigned long cci_event = event->hw.config_base;
 	int idx;
 
-	if (cci_event == CCI_PMU_CYCLES) {
-		if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
-			return -EAGAIN;
+	if (cci_pmu->model->get_event_idx)
+		return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
 
-		return CCI_PMU_CYCLE_CNTR_IDX;
-	}
-
-	for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+	/* Generic code to find an unused idx from the mask */
+	for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
 		if (!test_and_set_bit(idx, hw->used_mask))
 			return idx;
 
@@ -310,19 +334,13 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
 
 static int pmu_map_event(struct perf_event *event)
 {
-	int mapping;
-	unsigned long config = event->attr.config;
+	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
 
-	if (event->attr.type < PERF_TYPE_MAX)
+	if (event->attr.type < PERF_TYPE_MAX ||
+			!cci_pmu->model->validate_hw_event)
 		return -ENOENT;
 
-	if (config == CCI_PMU_CYCLES)
-		mapping = config;
-	else
-		mapping = pmu_validate_hw_event(to_cci_pmu(event->pmu),
-							config);
-
-	return mapping;
+	return	cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config);
 }
 
 static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
@@ -450,7 +468,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
 	 * This should work regardless of whether we have per-counter overflow
 	 * interrupt or a combined overflow interrupt.
 	 */
-	for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
+	for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
 		struct perf_event *event = events->events[idx];
 		struct hw_perf_event *hw_counter;
 
@@ -538,6 +556,16 @@ static void cci_pmu_disable(struct pmu *pmu)
 	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
 }
 
+/*
+ * Check if the idx represents a non-programmable counter.
+ * All the fixed event counters are mapped before the programmable
+ * counters.
+ */
+static bool pmu_fixed_hw_idx(struct cci_pmu *cci_pmu, int idx)
+{
+	return (idx >= 0) && (idx < cci_pmu->model->fixed_hw_cntrs);
+}
+
 static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 {
 	struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
@@ -562,8 +590,8 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
 	raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
 
-	/* Configure the event to count, unless you are counting cycles */
-	if (idx != CCI_PMU_CYCLE_CNTR_IDX)
+	/* Configure the counter unless you are counting a fixed event */
+	if (!pmu_fixed_hw_idx(cci_pmu, idx))
 		pmu_set_event(cci_pmu, idx, hwc->config_base);
 
 	pmu_event_set_period(event);
@@ -907,6 +935,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R0_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 	[CCI_REV_R1] = {
 		.name = "CCI_400_r1",
@@ -923,6 +953,8 @@ static struct cci_pmu_model cci_pmu_models[] = {
 				CCI_REV_R1_MASTER_PORT_MAX_EV,
 			},
 		},
+		.validate_hw_event = cci400_validate_hw_event,
+		.get_event_idx = cci400_get_event_idx,
 	},
 };
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2015-05-26 14:04 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-05 11:49 [PATCH 0/7] ARM CCI-500 PMU driver support Suzuki K. Poulose
2015-05-05 11:49 ` Suzuki K. Poulose
2015-05-05 11:49 ` Suzuki K. Poulose
2015-05-05 11:49 ` [PATCH 1/7] drivers: CCI: fix used_mask init in validate_group() Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-05 11:49 ` [PATCH 2/7] arm-cci: Cleanup PMU driver code Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-18 10:18   ` Punit Agrawal
2015-05-18 10:18     ` Punit Agrawal
2015-05-18 10:18     ` Punit Agrawal
2015-05-05 11:49 ` [PATCH 3/7] arm-cci: Abstract out the PMU counter details Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-18 11:54   ` Punit Agrawal
2015-05-18 11:54     ` Punit Agrawal
2015-05-18 11:54     ` Punit Agrawal
2015-05-05 11:49 ` [PATCH 4/7] arm-cci: Abstract handling for CCI events Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-18 13:08   ` Punit Agrawal
2015-05-18 13:08     ` Punit Agrawal
2015-05-05 11:49 ` [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-18 13:22   ` Punit Agrawal
2015-05-18 13:22     ` Punit Agrawal
2015-05-18 13:22     ` Punit Agrawal
2015-05-05 11:49 ` [PATCH 6/7] arm-cci: Add CCI-500 PMU support Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-18 13:22   ` Punit Agrawal
2015-05-18 13:22     ` Punit Agrawal
2015-05-18 13:22     ` Punit Agrawal
2015-05-05 11:49 ` [PATCH 7/7] arm-cci: Add aliases for PMU events Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-05 11:49   ` Suzuki K. Poulose
2015-05-18 13:33   ` Punit Agrawal
2015-05-18 13:33     ` Punit Agrawal
2015-05-26  9:53 [PATCH 0/7] ARM CCI PMU updates for 4.2 Suzuki K. Poulose
2015-05-26  9:53 ` [PATCH 4/7] arm-cci: Abstract handling for CCI events Suzuki K. Poulose
2015-05-26  9:53   ` Suzuki K. Poulose

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.