linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
To: arm@kernel.org
Cc: will.deacon@arm.com, punit.agrawal@arm.com, mark.rutland@arm.com,
	linux-arm-kernel@lists.infradead.org, arnd@arndb.de,
	olof@lixom.net, pawel.moll@arm.com, linux-kernel@vger.kernel.org,
	"Suzuki K. Poulose" <suzuki.poulose@arm.com>
Subject: [PATCH 4/7] arm-cci: Abstract handling for CCI events
Date: Tue, 26 May 2015 10:53:13 +0100	[thread overview]
Message-ID: <1432633996-7229-5-git-send-email-suzuki.poulose@arm.com> (raw)
In-Reply-To: <1432633996-7229-1-git-send-email-suzuki.poulose@arm.com>

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


  parent reply	other threads:[~2015-05-26 14:04 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-26  9:53 [PATCH 0/7] ARM CCI PMU updates for 4.2 Suzuki K. Poulose
2015-05-26  9:53 ` [PATCH 1/7] arm-cci: Do not enable CCI-400 PMU by default Suzuki K. Poulose
2015-05-29 10:06   ` Suzuki K. Poulose
2015-05-26  9:53 ` [PATCH 2/7] arm-cci: Cleanup PMU driver code Suzuki K. Poulose
2015-05-26  9:53 ` [PATCH 3/7] arm-cci: Abstract out the PMU counter details Suzuki K. Poulose
2015-05-26  9:53 ` Suzuki K. Poulose [this message]
2015-05-26  9:53 ` [PATCH 5/7] arm-cci: Sanitise CCI400 PMU driver specific code Suzuki K. Poulose
2015-05-26  9:53 ` [PATCH 6/7] arm-cci: Add CCI-500 PMU support Suzuki K. Poulose
2015-05-26  9:53 ` [PATCH 7/7] arm-cci: Add aliases for PMU events Suzuki K. Poulose
2015-05-29  9:29 ` [PATCH 0/7] ARM CCI PMU updates for 4.2 Suzuki K. Poulose
2015-05-29 12:49   ` Arnd Bergmann
2015-05-29 13:04     ` Suzuki K. Poulose
  -- strict thread matches above, loose matches on Subject: below --
2015-05-05 11:49 [PATCH 0/7] ARM CCI-500 PMU driver support Suzuki K. Poulose
2015-05-05 11:49 ` [PATCH 4/7] arm-cci: Abstract handling for CCI events Suzuki K. Poulose
2015-05-18 13:08   ` Punit Agrawal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1432633996-7229-5-git-send-email-suzuki.poulose@arm.com \
    --to=suzuki.poulose@arm.com \
    --cc=arm@kernel.org \
    --cc=arnd@arndb.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=olof@lixom.net \
    --cc=pawel.moll@arm.com \
    --cc=punit.agrawal@arm.com \
    --cc=will.deacon@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).