All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver
@ 2020-12-31  6:19 Shaokun Zhang
  2020-12-31  6:19 ` [PATCH 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
                   ` (8 more replies)
  0 siblings, 9 replies; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

This patchset adds support for HiSilicon Hip09 SoC uncore PMUs driver
which is PMU v2 and it includes:
(a) Refactor interrupt registration and handler function for later
new uncore PMU driver in patch1;
(b) Update the PMU version suffiex for existing driver in patch2
(b) Some new functions are added on L3C/HHA PMU in patch3/4;
(c) New DDRC PMU model is supported using programable counter and
supports more events in patch5;
(d) Add new modules SLLC and PA PMU drivers in patch6/7;
(e) Update the perf document for the new functions and modules in
patch8;


Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Qi Liu <liuqi115@huawei.com>

Shaokun Zhang (8):
  drivers/perf: hisi: Refactor code for more uncore PMUs
  drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  drivers/perf: hisi: Add new functions for L3C PMU
  drivers/perf: hisi: Add new functions for HHA PMU
  drivers/perf: hisi: Update DDRC PMU for programable counter
  drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  docs: perf: Add new description on HiSilicon uncore PMU v2

 Documentation/admin-guide/perf/hisi-pmu.rst   |  54 +++
 drivers/perf/hisilicon/Makefile               |   3 +-
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 346 +++++++++++------
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 301 ++++++++++-----
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 353 ++++++++++++-----
 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c   | 498 ++++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c      |  76 +++-
 drivers/perf/hisilicon/hisi_uncore_pmu.h      |  19 +-
 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 530 ++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                    |   2 +
 10 files changed, 1878 insertions(+), 304 deletions(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c

-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2020-12-31  6:19 ` [PATCH 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon uncore PMU drivers, interrupt handling function and interrupt
registration function are very similar in differents PMU modules. Let's
refactor the frame, use a callback function for the HW accessors.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 79 ++++-----------------------
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 77 +++-----------------------
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 77 +++-----------------------
 drivers/perf/hisilicon/hisi_uncore_pmu.c      | 68 ++++++++++++++++++++++-
 drivers/perf/hisilicon/hisi_uncore_pmu.h      |  6 +-
 5 files changed, 100 insertions(+), 207 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index 5ac6c9113767..69ccbe02f1e3 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
-#include <linux/platform_device.h>
 #include <linux/smp.h>
 
 #include "hisi_uncore_pmu.h"
@@ -65,29 +64,15 @@ static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_ddrc_pmu_read_counter(struct hisi_pmu *ddrc_pmu,
 				      struct hw_perf_event *hwc)
 {
-	/* Use event code as counter index */
-	u32 idx = GET_DDRC_EVENTID(hwc);
-
-	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
-		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return 0;
-	}
-
-	return readl(ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
+	return readl(ddrc_pmu->base +
+		     hisi_ddrc_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_ddrc_pmu_write_counter(struct hisi_pmu *ddrc_pmu,
 					struct hw_perf_event *hwc, u64 val)
 {
-	u32 idx = GET_DDRC_EVENTID(hwc);
-
-	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
-		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return;
-	}
-
 	writel((u32)val,
-	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
+	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(hwc->idx));
 }
 
 /*
@@ -179,60 +164,14 @@ static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
-static irqreturn_t hisi_ddrc_pmu_isr(int irq, void *dev_id)
+static u32 hisi_ddrc_pmu_get_int_status(struct hisi_pmu *ddrc_pmu)
 {
-	struct hisi_pmu *ddrc_pmu = dev_id;
-	struct perf_event *event;
-	unsigned long overflown;
-	int idx;
-
-	/* Read the DDRC_INT_STATUS register */
-	overflown = readl(ddrc_pmu->base + DDRC_INT_STATUS);
-	if (!overflown)
-		return IRQ_NONE;
-
-	/*
-	 * Find the counter index which overflowed if the bit was set
-	 * and handle it
-	 */
-	for_each_set_bit(idx, &overflown, DDRC_NR_COUNTERS) {
-		/* Write 1 to clear the IRQ status flag */
-		writel((1 << idx), ddrc_pmu->base + DDRC_INT_CLEAR);
-
-		/* Get the corresponding event struct */
-		event = ddrc_pmu->pmu_events.hw_events[idx];
-		if (!event)
-			continue;
-
-		hisi_uncore_pmu_event_update(event);
-		hisi_uncore_pmu_set_event_period(event);
-	}
-
-	return IRQ_HANDLED;
+	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
 }
 
-static int hisi_ddrc_pmu_init_irq(struct hisi_pmu *ddrc_pmu,
-				  struct platform_device *pdev)
+static void hisi_ddrc_pmu_clear_int_status(struct hisi_pmu *ddrc_pmu, int idx)
 {
-	int irq, ret;
-
-	/* Read and init IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_irq(&pdev->dev, irq, hisi_ddrc_pmu_isr,
-			       IRQF_NOBALANCING | IRQF_NO_THREAD,
-			       dev_name(&pdev->dev), ddrc_pmu);
-	if (ret < 0) {
-		dev_err(&pdev->dev,
-			"Fail to request IRQ:%d ret:%d\n", irq, ret);
-		return ret;
-	}
-
-	ddrc_pmu->irq = irq;
-
-	return 0;
+	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
 }
 
 static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
@@ -342,6 +281,8 @@ static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = {
 	.disable_counter_int	= hisi_ddrc_pmu_disable_counter_int,
 	.write_counter		= hisi_ddrc_pmu_write_counter,
 	.read_counter		= hisi_ddrc_pmu_read_counter,
+	.get_int_status		= hisi_ddrc_pmu_get_int_status,
+	.clear_int_status	= hisi_ddrc_pmu_clear_int_status,
 };
 
 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
@@ -353,7 +294,7 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	ret = hisi_ddrc_pmu_init_irq(ddrc_pmu, pdev);
+	ret = hisi_uncore_pmu_init_irq(ddrc_pmu, pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 41b2dceb5f26..29c26f2e3c08 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
-#include <linux/platform_device.h>
 #include <linux/smp.h>
 
 #include "hisi_uncore_pmu.h"
@@ -51,29 +50,15 @@ static u32 hisi_hha_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu,
 				     struct hw_perf_event *hwc)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
-		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return 0;
-	}
-
 	/* Read 64 bits and like L3C, top 16 bits are RAZ */
-	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
+	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu,
 				       struct hw_perf_event *hwc, u64 val)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
-		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return;
-	}
-
 	/* Write 64 bits and like L3C, top 16 bits are WI */
-	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
+	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
@@ -169,60 +154,14 @@ static void hisi_hha_pmu_disable_counter_int(struct hisi_pmu *hha_pmu,
 	writel(val, hha_pmu->base + HHA_INT_MASK);
 }
 
-static irqreturn_t hisi_hha_pmu_isr(int irq, void *dev_id)
+static u32 hisi_hha_pmu_get_int_status(struct hisi_pmu *hha_pmu)
 {
-	struct hisi_pmu *hha_pmu = dev_id;
-	struct perf_event *event;
-	unsigned long overflown;
-	int idx;
-
-	/* Read HHA_INT_STATUS register */
-	overflown = readl(hha_pmu->base + HHA_INT_STATUS);
-	if (!overflown)
-		return IRQ_NONE;
-
-	/*
-	 * Find the counter index which overflowed if the bit was set
-	 * and handle it
-	 */
-	for_each_set_bit(idx, &overflown, HHA_NR_COUNTERS) {
-		/* Write 1 to clear the IRQ status flag */
-		writel((1 << idx), hha_pmu->base + HHA_INT_CLEAR);
-
-		/* Get the corresponding event struct */
-		event = hha_pmu->pmu_events.hw_events[idx];
-		if (!event)
-			continue;
-
-		hisi_uncore_pmu_event_update(event);
-		hisi_uncore_pmu_set_event_period(event);
-	}
-
-	return IRQ_HANDLED;
+	return readl(hha_pmu->base + HHA_INT_STATUS);
 }
 
-static int hisi_hha_pmu_init_irq(struct hisi_pmu *hha_pmu,
-				 struct platform_device *pdev)
+static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx)
 {
-	int irq, ret;
-
-	/* Read and init IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_irq(&pdev->dev, irq, hisi_hha_pmu_isr,
-			      IRQF_NOBALANCING | IRQF_NO_THREAD,
-			      dev_name(&pdev->dev), hha_pmu);
-	if (ret < 0) {
-		dev_err(&pdev->dev,
-			"Fail to request IRQ:%d ret:%d\n", irq, ret);
-		return ret;
-	}
-
-	hha_pmu->irq = irq;
-
-	return 0;
+	writel(1 << idx, hha_pmu->base + HHA_INT_CLEAR);
 }
 
 static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = {
@@ -354,6 +293,8 @@ static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
 	.disable_counter_int	= hisi_hha_pmu_disable_counter_int,
 	.write_counter		= hisi_hha_pmu_write_counter,
 	.read_counter		= hisi_hha_pmu_read_counter,
+	.get_int_status		= hisi_hha_pmu_get_int_status,
+	.clear_int_status	= hisi_hha_pmu_clear_int_status,
 };
 
 static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
@@ -365,7 +306,7 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	ret = hisi_hha_pmu_init_irq(hha_pmu, pdev);
+	ret = hisi_uncore_pmu_init_irq(hha_pmu, pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index 705501d18d03..68c00689b275 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
-#include <linux/platform_device.h>
 #include <linux/smp.h>
 
 #include "hisi_uncore_pmu.h"
@@ -50,29 +49,15 @@ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
 				     struct hw_perf_event *hwc)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
-		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return 0;
-	}
-
 	/* Read 64-bits and the upper 16 bits are RAZ */
-	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
+	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,
 				       struct hw_perf_event *hwc, u64 val)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
-		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return;
-	}
-
 	/* Write 64-bits and the upper 16 bits are WI */
-	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
+	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx,
@@ -168,60 +153,14 @@ static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu,
 	writel(val, l3c_pmu->base + L3C_INT_MASK);
 }
 
-static irqreturn_t hisi_l3c_pmu_isr(int irq, void *dev_id)
+static u32 hisi_l3c_pmu_get_int_status(struct hisi_pmu *l3c_pmu)
 {
-	struct hisi_pmu *l3c_pmu = dev_id;
-	struct perf_event *event;
-	unsigned long overflown;
-	int idx;
-
-	/* Read L3C_INT_STATUS register */
-	overflown = readl(l3c_pmu->base + L3C_INT_STATUS);
-	if (!overflown)
-		return IRQ_NONE;
-
-	/*
-	 * Find the counter index which overflowed if the bit was set
-	 * and handle it.
-	 */
-	for_each_set_bit(idx, &overflown, L3C_NR_COUNTERS) {
-		/* Write 1 to clear the IRQ status flag */
-		writel((1 << idx), l3c_pmu->base + L3C_INT_CLEAR);
-
-		/* Get the corresponding event struct */
-		event = l3c_pmu->pmu_events.hw_events[idx];
-		if (!event)
-			continue;
-
-		hisi_uncore_pmu_event_update(event);
-		hisi_uncore_pmu_set_event_period(event);
-	}
-
-	return IRQ_HANDLED;
+	return readl(l3c_pmu->base + L3C_INT_STATUS);
 }
 
-static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu,
-				 struct platform_device *pdev)
+static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx)
 {
-	int irq, ret;
-
-	/* Read and init IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr,
-			       IRQF_NOBALANCING | IRQF_NO_THREAD,
-			       dev_name(&pdev->dev), l3c_pmu);
-	if (ret < 0) {
-		dev_err(&pdev->dev,
-			"Fail to request IRQ:%d ret:%d\n", irq, ret);
-		return ret;
-	}
-
-	l3c_pmu->irq = irq;
-
-	return 0;
+	writel(1 << idx, l3c_pmu->base + L3C_INT_CLEAR);
 }
 
 static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {
@@ -344,6 +283,8 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
 	.disable_counter_int	= hisi_l3c_pmu_disable_counter_int,
 	.write_counter		= hisi_l3c_pmu_write_counter,
 	.read_counter		= hisi_l3c_pmu_read_counter,
+	.get_int_status		= hisi_l3c_pmu_get_int_status,
+	.clear_int_status	= hisi_l3c_pmu_clear_int_status,
 };
 
 static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
@@ -355,7 +296,7 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	ret = hisi_l3c_pmu_init_irq(l3c_pmu, pdev);
+	ret = hisi_uncore_pmu_init_irq(l3c_pmu, pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index 9dbdc3fc3bb4..82a4ff2bc3ae 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -132,13 +132,67 @@ EXPORT_SYMBOL_GPL(hisi_uncore_pmu_identifier_attr_show);
 static void hisi_uncore_pmu_clear_event_idx(struct hisi_pmu *hisi_pmu, int idx)
 {
 	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
-		dev_err(hisi_pmu->dev, "Unsupported event index:%d!\n", idx);
+		dev_err(hisi_pmu->dev, "Unsupported event index: %d\n", idx);
 		return;
 	}
 
 	clear_bit(idx, hisi_pmu->pmu_events.used_mask);
 }
 
+static irqreturn_t hisi_uncore_pmu_isr(int irq, void *data)
+{
+	struct hisi_pmu *hisi_pmu = data;
+	struct perf_event *event;
+	unsigned long overflown;
+	int idx;
+
+	overflown = hisi_pmu->ops->get_int_status(hisi_pmu);
+	if (!overflown)
+		return IRQ_NONE;
+
+	/*
+	 * Find the counter index which overflowed if the bit was set
+	 * and handle it.
+	 */
+	for_each_set_bit(idx, &overflown, hisi_pmu->num_counters) {
+		/* Write 1 to clear the IRQ status flag */
+		hisi_pmu->ops->clear_int_status(hisi_pmu, idx);
+		/* Get the corresponding event struct */
+		event = hisi_pmu->pmu_events.hw_events[idx];
+		if (!event)
+			continue;
+
+		hisi_uncore_pmu_event_update(event);
+		hisi_uncore_pmu_set_event_period(event);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
+			     struct platform_device *pdev)
+{
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_irq(&pdev->dev, irq, hisi_uncore_pmu_isr,
+			       IRQF_NOBALANCING | IRQF_NO_THREAD,
+			       dev_name(&pdev->dev), hisi_pmu);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"Fail to request IRQ:%d ret:%d\n", irq, ret);
+		return ret;
+	}
+
+	hisi_pmu->irq = irq;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_uncore_pmu_init_irq);
+
 int hisi_uncore_pmu_event_init(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
@@ -243,6 +297,12 @@ void hisi_uncore_pmu_event_update(struct perf_event *event)
 	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
 	u64 delta, prev_raw_count, new_raw_count;
+	u32 idx = hwc->idx;
+
+	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
+		dev_err(hisi_pmu->dev, "Unsupported counter index: %d\n", idx);
+		return;
+	}
 
 	do {
 		/* Read the count from the counter register */
@@ -263,10 +323,16 @@ void hisi_uncore_pmu_start(struct perf_event *event, int flags)
 {
 	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
+	u32 idx = hwc->idx;
 
 	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
 		return;
 
+	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
+		dev_err(hisi_pmu->dev, "Unsupported counter index: %d.\n", idx);
+		return;
+	}
+
 	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
 	hwc->state = 0;
 	hisi_uncore_pmu_set_event_period(event);
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index 25b7cbe1f818..aaaf637cc9ea 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/perf_event.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 
 #undef pr_fmt
@@ -47,6 +48,8 @@ struct hisi_uncore_ops {
 	void (*disable_counter_int)(struct hisi_pmu *, struct hw_perf_event *);
 	void (*start_counters)(struct hisi_pmu *);
 	void (*stop_counters)(struct hisi_pmu *);
+	u32 (*get_int_status)(struct hisi_pmu *hisi_pmu);
+	void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx);
 };
 
 struct hisi_pmu_hwevents {
@@ -102,6 +105,7 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node);
 ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
 					     struct device_attribute *attr,
 					     char *page);
-
+int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
+			     struct platform_device *pdev);
 
 #endif /* __HISI_UNCORE_PMU_H__ */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
  2020-12-31  6:19 ` [PATCH 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2021-01-26 11:46   ` John Garry
  2020-12-31  6:19 ` [PATCH 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

For HiSilicon uncore PMU, more versions are supported and some variables
shall be added suffiex to distinguish the version which are prepared for
the new drivers.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 95 ++++++++++++++-------------
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 27 ++++----
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 24 +++----
 3 files changed, 74 insertions(+), 72 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index 69ccbe02f1e3..7f940c47b833 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -36,8 +36,8 @@
 
 /* DDRC has 8-counters */
 #define DDRC_NR_COUNTERS	0x8
-#define DDRC_PERF_CTRL_EN	0x2
-
+#define DDRC_V1_PERF_CTRL_EN	0x2
+#define DDRC_V1_NR_EVENTS	0x07
 /*
  * For DDRC PMU, there are eight-events and every event has been mapped
  * to fixed-purpose counters which register offset is not consistent.
@@ -53,26 +53,26 @@ static const u32 ddrc_reg_off[] = {
 
 /*
  * Select the counter register offset using the counter index.
- * In DDRC there are no programmable counter, the count
+ * In PMU v1, there are no programmable counter, the count
  * is readed form the statistics counter register itself.
  */
-static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
+static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
 {
 	return ddrc_reg_off[cntr_idx];
 }
 
-static u64 hisi_ddrc_pmu_read_counter(struct hisi_pmu *ddrc_pmu,
+static u64 hisi_ddrc_pmu_v1_read_counter(struct hisi_pmu *ddrc_pmu,
 				      struct hw_perf_event *hwc)
 {
 	return readl(ddrc_pmu->base +
-		     hisi_ddrc_pmu_get_counter_offset(hwc->idx));
+		     hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
 }
 
-static void hisi_ddrc_pmu_write_counter(struct hisi_pmu *ddrc_pmu,
+static void hisi_ddrc_pmu_v1_write_counter(struct hisi_pmu *ddrc_pmu,
 					struct hw_perf_event *hwc, u64 val)
 {
 	writel((u32)val,
-	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(hwc->idx));
+	       ddrc_pmu->base + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
 }
 
 /*
@@ -84,28 +84,28 @@ static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
 {
 }
 
-static void hisi_ddrc_pmu_start_counters(struct hisi_pmu *ddrc_pmu)
+static void hisi_ddrc_pmu_v1_start_counters(struct hisi_pmu *ddrc_pmu)
 {
 	u32 val;
 
 	/* Set perf_enable in DDRC_PERF_CTRL to start event counting */
 	val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
-	val |= DDRC_PERF_CTRL_EN;
+	val |= DDRC_V1_PERF_CTRL_EN;
 	writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
 }
 
-static void hisi_ddrc_pmu_stop_counters(struct hisi_pmu *ddrc_pmu)
+static void hisi_ddrc_pmu_v1_stop_counters(struct hisi_pmu *ddrc_pmu)
 {
 	u32 val;
 
 	/* Clear perf_enable in DDRC_PERF_CTRL to stop event counting */
 	val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
-	val &= ~DDRC_PERF_CTRL_EN;
+	val &= ~DDRC_V1_PERF_CTRL_EN;
 	writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
 }
 
-static void hisi_ddrc_pmu_enable_counter(struct hisi_pmu *ddrc_pmu,
-					 struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_enable_counter(struct hisi_pmu *ddrc_pmu,
+					    struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -115,8 +115,8 @@ static void hisi_ddrc_pmu_enable_counter(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
 }
 
-static void hisi_ddrc_pmu_disable_counter(struct hisi_pmu *ddrc_pmu,
-					  struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_disable_counter(struct hisi_pmu *ddrc_pmu,
+					     struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -126,7 +126,7 @@ static void hisi_ddrc_pmu_disable_counter(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
 }
 
-static int hisi_ddrc_pmu_get_event_idx(struct perf_event *event)
+static int hisi_ddrc_pmu_v1_get_event_idx(struct perf_event *event)
 {
 	struct hisi_pmu *ddrc_pmu = to_hisi_pmu(event->pmu);
 	unsigned long *used_mask = ddrc_pmu->pmu_events.used_mask;
@@ -142,8 +142,8 @@ static int hisi_ddrc_pmu_get_event_idx(struct perf_event *event)
 	return idx;
 }
 
-static void hisi_ddrc_pmu_enable_counter_int(struct hisi_pmu *ddrc_pmu,
-					     struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
+						struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -153,8 +153,8 @@ static void hisi_ddrc_pmu_enable_counter_int(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
-static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
-					      struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_disable_counter_int(struct hisi_pmu *ddrc_pmu,
+						 struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -164,12 +164,13 @@ static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
-static u32 hisi_ddrc_pmu_get_int_status(struct hisi_pmu *ddrc_pmu)
+static u32 hisi_ddrc_pmu_v1_get_int_status(struct hisi_pmu *ddrc_pmu)
 {
 	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
 }
 
-static void hisi_ddrc_pmu_clear_int_status(struct hisi_pmu *ddrc_pmu, int idx)
+static void hisi_ddrc_pmu_v1_clear_int_status(struct hisi_pmu *ddrc_pmu,
+					      int idx)
 {
 	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
 }
@@ -212,17 +213,17 @@ static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
 	return 0;
 }
 
-static struct attribute *hisi_ddrc_pmu_format_attr[] = {
+static struct attribute *hisi_ddrc_pmu_v1_format_attr[] = {
 	HISI_PMU_FORMAT_ATTR(event, "config:0-4"),
 	NULL,
 };
 
-static const struct attribute_group hisi_ddrc_pmu_format_group = {
+static const struct attribute_group hisi_ddrc_pmu_v1_format_group = {
 	.name = "format",
-	.attrs = hisi_ddrc_pmu_format_attr,
+	.attrs = hisi_ddrc_pmu_v1_format_attr,
 };
 
-static struct attribute *hisi_ddrc_pmu_events_attr[] = {
+static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(flux_wr,		0x00),
 	HISI_PMU_EVENT_ATTR(flux_rd,		0x01),
 	HISI_PMU_EVENT_ATTR(flux_wcmd,		0x02),
@@ -234,9 +235,9 @@ static struct attribute *hisi_ddrc_pmu_events_attr[] = {
 	NULL,
 };
 
-static const struct attribute_group hisi_ddrc_pmu_events_group = {
+static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
 	.name = "events",
-	.attrs = hisi_ddrc_pmu_events_attr,
+	.attrs = hisi_ddrc_pmu_v1_events_attr,
 };
 
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
@@ -262,27 +263,27 @@ static struct attribute_group hisi_ddrc_pmu_identifier_group = {
 	.attrs = hisi_ddrc_pmu_identifier_attrs,
 };
 
-static const struct attribute_group *hisi_ddrc_pmu_attr_groups[] = {
-	&hisi_ddrc_pmu_format_group,
-	&hisi_ddrc_pmu_events_group,
+static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = {
+	&hisi_ddrc_pmu_v1_format_group,
+	&hisi_ddrc_pmu_v1_events_group,
 	&hisi_ddrc_pmu_cpumask_attr_group,
 	&hisi_ddrc_pmu_identifier_group,
 	NULL,
 };
 
-static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = {
+static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
 	.write_evtype           = hisi_ddrc_pmu_write_evtype,
-	.get_event_idx		= hisi_ddrc_pmu_get_event_idx,
-	.start_counters		= hisi_ddrc_pmu_start_counters,
-	.stop_counters		= hisi_ddrc_pmu_stop_counters,
-	.enable_counter		= hisi_ddrc_pmu_enable_counter,
-	.disable_counter	= hisi_ddrc_pmu_disable_counter,
-	.enable_counter_int	= hisi_ddrc_pmu_enable_counter_int,
-	.disable_counter_int	= hisi_ddrc_pmu_disable_counter_int,
-	.write_counter		= hisi_ddrc_pmu_write_counter,
-	.read_counter		= hisi_ddrc_pmu_read_counter,
-	.get_int_status		= hisi_ddrc_pmu_get_int_status,
-	.clear_int_status	= hisi_ddrc_pmu_clear_int_status,
+	.get_event_idx		= hisi_ddrc_pmu_v1_get_event_idx,
+	.start_counters		= hisi_ddrc_pmu_v1_start_counters,
+	.stop_counters		= hisi_ddrc_pmu_v1_stop_counters,
+	.enable_counter		= hisi_ddrc_pmu_v1_enable_counter,
+	.disable_counter	= hisi_ddrc_pmu_v1_disable_counter,
+	.enable_counter_int	= hisi_ddrc_pmu_v1_enable_counter_int,
+	.disable_counter_int	= hisi_ddrc_pmu_v1_disable_counter_int,
+	.write_counter		= hisi_ddrc_pmu_v1_write_counter,
+	.read_counter		= hisi_ddrc_pmu_v1_read_counter,
+	.get_int_status		= hisi_ddrc_pmu_v1_get_int_status,
+	.clear_int_status	= hisi_ddrc_pmu_v1_clear_int_status,
 };
 
 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
@@ -300,10 +301,10 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 
 	ddrc_pmu->num_counters = DDRC_NR_COUNTERS;
 	ddrc_pmu->counter_bits = 32;
-	ddrc_pmu->ops = &hisi_uncore_ddrc_ops;
+	ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
 	ddrc_pmu->dev = &pdev->dev;
 	ddrc_pmu->on_cpu = -1;
-	ddrc_pmu->check_event = 7;
+	ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -345,7 +346,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_ddrc_pmu_attr_groups,
+		.attr_groups	= hisi_ddrc_pmu_v1_attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 29c26f2e3c08..2f55e5864d39 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -33,10 +33,11 @@
 #define HHA_CNT0_LOWER		0x1F00
 
 /* HHA has 16-counters */
-#define HHA_NR_COUNTERS		0x10
+#define HHA_V1_NR_COUNTERS	0x10
 
 #define HHA_PERF_CTRL_EN	0x1
 #define HHA_EVTYPE_NONE		0xff
+#define HHA_V1_NR_EVENT		0x65
 
 /*
  * Select the counter register offset using the counter index
@@ -206,17 +207,17 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
 	return 0;
 }
 
-static struct attribute *hisi_hha_pmu_format_attr[] = {
+static struct attribute *hisi_hha_pmu_v1_format_attr[] = {
 	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
 	NULL,
 };
 
-static const struct attribute_group hisi_hha_pmu_format_group = {
+static const struct attribute_group hisi_hha_pmu_v1_format_group = {
 	.name = "format",
-	.attrs = hisi_hha_pmu_format_attr,
+	.attrs = hisi_hha_pmu_v1_format_attr,
 };
 
-static struct attribute *hisi_hha_pmu_events_attr[] = {
+static struct attribute *hisi_hha_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rx_ops_num,		0x00),
 	HISI_PMU_EVENT_ATTR(rx_outer,		0x01),
 	HISI_PMU_EVENT_ATTR(rx_sccl,		0x02),
@@ -246,9 +247,9 @@ static struct attribute *hisi_hha_pmu_events_attr[] = {
 	NULL,
 };
 
-static const struct attribute_group hisi_hha_pmu_events_group = {
+static const struct attribute_group hisi_hha_pmu_v1_events_group = {
 	.name = "events",
-	.attrs = hisi_hha_pmu_events_attr,
+	.attrs = hisi_hha_pmu_v1_events_attr,
 };
 
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
@@ -274,9 +275,9 @@ static struct attribute_group hisi_hha_pmu_identifier_group = {
 	.attrs = hisi_hha_pmu_identifier_attrs,
 };
 
-static const struct attribute_group *hisi_hha_pmu_attr_groups[] = {
-	&hisi_hha_pmu_format_group,
-	&hisi_hha_pmu_events_group,
+static const struct attribute_group *hisi_hha_pmu_v1_attr_groups[] = {
+	&hisi_hha_pmu_v1_format_group,
+	&hisi_hha_pmu_v1_events_group,
 	&hisi_hha_pmu_cpumask_attr_group,
 	&hisi_hha_pmu_identifier_group,
 	NULL,
@@ -310,12 +311,12 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	hha_pmu->num_counters = HHA_NR_COUNTERS;
+	hha_pmu->num_counters = HHA_V1_NR_COUNTERS;
 	hha_pmu->counter_bits = 48;
 	hha_pmu->ops = &hisi_uncore_hha_ops;
 	hha_pmu->dev = &pdev->dev;
 	hha_pmu->on_cpu = -1;
-	hha_pmu->check_event = 0x65;
+	hha_pmu->check_event = HHA_V1_NR_EVENT;
 
 	return 0;
 }
@@ -357,7 +358,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_hha_pmu_attr_groups,
+		.attr_groups	= hisi_hha_pmu_v1_attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index 68c00689b275..dc06e3ca7505 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -37,7 +37,7 @@
 
 #define L3C_PERF_CTRL_EN	0x10000
 #define L3C_EVTYPE_NONE		0xff
-
+#define L3C_V1_NR_EVENTS	0x59
 /*
  * Select the counter register offset using the counter index
  */
@@ -209,17 +209,17 @@ static int hisi_l3c_pmu_init_data(struct platform_device *pdev,
 	return 0;
 }
 
-static struct attribute *hisi_l3c_pmu_format_attr[] = {
+static struct attribute *hisi_l3c_pmu_v1_format_attr[] = {
 	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
 	NULL,
 };
 
-static const struct attribute_group hisi_l3c_pmu_format_group = {
+static const struct attribute_group hisi_l3c_pmu_v1_format_group = {
 	.name = "format",
-	.attrs = hisi_l3c_pmu_format_attr,
+	.attrs = hisi_l3c_pmu_v1_format_attr,
 };
 
-static struct attribute *hisi_l3c_pmu_events_attr[] = {
+static struct attribute *hisi_l3c_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rd_cpipe,		0x00),
 	HISI_PMU_EVENT_ATTR(wr_cpipe,		0x01),
 	HISI_PMU_EVENT_ATTR(rd_hit_cpipe,	0x02),
@@ -236,9 +236,9 @@ static struct attribute *hisi_l3c_pmu_events_attr[] = {
 	NULL,
 };
 
-static const struct attribute_group hisi_l3c_pmu_events_group = {
+static const struct attribute_group hisi_l3c_pmu_v1_events_group = {
 	.name = "events",
-	.attrs = hisi_l3c_pmu_events_attr,
+	.attrs = hisi_l3c_pmu_v1_events_attr,
 };
 
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
@@ -264,9 +264,9 @@ static struct attribute_group hisi_l3c_pmu_identifier_group = {
 	.attrs = hisi_l3c_pmu_identifier_attrs,
 };
 
-static const struct attribute_group *hisi_l3c_pmu_attr_groups[] = {
-	&hisi_l3c_pmu_format_group,
-	&hisi_l3c_pmu_events_group,
+static const struct attribute_group *hisi_l3c_pmu_v1_attr_groups[] = {
+	&hisi_l3c_pmu_v1_format_group,
+	&hisi_l3c_pmu_v1_events_group,
 	&hisi_l3c_pmu_cpumask_attr_group,
 	&hisi_l3c_pmu_identifier_group,
 	NULL,
@@ -305,7 +305,7 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
 	l3c_pmu->ops = &hisi_uncore_l3c_ops;
 	l3c_pmu->dev = &pdev->dev;
 	l3c_pmu->on_cpu = -1;
-	l3c_pmu->check_event = 0x59;
+	l3c_pmu->check_event = L3C_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -347,7 +347,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_l3c_pmu_attr_groups,
+		.attr_groups	= hisi_l3c_pmu_v1_attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 3/8] drivers/perf: hisi: Add new functions for L3C PMU
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
  2020-12-31  6:19 ` [PATCH 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
  2020-12-31  6:19 ` [PATCH 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2021-01-26 12:05   ` John Garry
  2020-12-31  6:19 ` [PATCH 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon Hip09 platform, some new functions are enhanced on L3C PMU,
like, tracetag feature that L3C PMU can only count the specified
operations by the user, or L3C PMU can give the desired core's statistics
in the cluster.
$# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0xf/ sleep 5

$# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 258 +++++++++++++++++++++++++--
 drivers/perf/hisilicon/hisi_uncore_pmu.c     |   8 +-
 drivers/perf/hisilicon/hisi_uncore_pmu.h     |  11 ++
 3 files changed, 257 insertions(+), 20 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index dc06e3ca7505..cf4c95ed075b 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -23,12 +23,17 @@
 #define L3C_INT_MASK		0x0800
 #define L3C_INT_STATUS		0x0808
 #define L3C_INT_CLEAR		0x080c
+#define L3C_CORE_CTRL           0x1b04
+#define L3C_TRACETAG_CTRL       0x1b20
+#define L3C_DATSRC_TYPE         0x1b48
+#define L3C_DATSRC_CTRL         0x1bf0
 #define L3C_EVENT_CTRL	        0x1c00
 #define L3C_VERSION		0x1cf0
 #define L3C_EVENT_TYPE0		0x1d00
 /*
- * Each counter is 48-bits and [48:63] are reserved
- * which are Read-As-Zero and Writes-Ignored.
+ * If the HW version only supports a 48-bit counter, then
+ * bits [63:48] are reserved, which are Read-As-Zero and
+ * Writes-Ignored.
  */
 #define L3C_CNTR0_LOWER		0x1e00
 
@@ -36,8 +41,187 @@
 #define L3C_NR_COUNTERS		0x8
 
 #define L3C_PERF_CTRL_EN	0x10000
+#define L3C_TRACETAG_EN		BIT(31)
+#define L3C_TRACETAG_REQ_SHIFT	7
+#define L3C_TRACETAG_MARK_EN	BIT(0)
+#define L3C_TRACETAG_REQ_EN	(L3C_TRACETAG_MARK_EN | BIT(2))
+#define L3C_TRACETAG_CORE_EN	(L3C_TRACETAG_MARK_EN | BIT(3))
+#define L3C_CORE_EN		BIT(20)
+#define L3C_COER_NONE		0x0
+#define L3C_DATSRC_MASK		0xFF
+#define L3C_DATSRC_SKT_EN	BIT(23)
+#define L3C_DATSRC_NONE		0x0
 #define L3C_EVTYPE_NONE		0xff
 #define L3C_V1_NR_EVENTS	0x59
+#define L3C_V2_NR_EVENTS	0xFF
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core, config1, 7, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16);
+
+static inline void hisi_l3c_pmu_config_req_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_req = hisi_get_tt_req(event);
+
+	if (tt_req) {
+		u32 val;
+
+		/* Set request-type for tracetag */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val |= tt_req << L3C_TRACETAG_REQ_SHIFT;
+		val |= L3C_TRACETAG_REQ_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+
+		/* Enable request-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val |= L3C_TRACETAG_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+	}
+}
+
+static inline void hisi_l3c_pmu_clear_req_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_req = hisi_get_tt_req(event);
+
+	if (tt_req) {
+		u32 val;
+
+		/* Clear request-type */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val &= ~(tt_req << L3C_TRACETAG_REQ_SHIFT);
+		val &= ~L3C_TRACETAG_REQ_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+
+		/* Disable request-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val &= ~L3C_TRACETAG_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+	}
+}
+
+static inline void hisi_l3c_pmu_write_ds(struct perf_event *event, u32 ds_cfg)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	u32 reg, reg_idx, shift, val;
+	int idx = hwc->idx;
+
+	/*
+	 * Select the appropriate datasource register(L3C_DATSRC_TYPE0/1).
+	 * There are 2 datasource ctrl register for the 8 hardware counters.
+	 * Datasrc is 8-bits and for the former 4 hardware counters,
+	 * L3C_DATSRC_TYPE0 is chosen. For the latter 4 hardware counters,
+	 * L3C_DATSRC_TYPE1 is chosen.
+	 */
+	reg = L3C_DATSRC_TYPE + rounddown(idx, 4);
+	reg_idx = idx % 4;
+	shift = 8 * reg_idx;
+
+	val = readl(l3c_pmu->base + reg);
+	val &= ~(L3C_DATSRC_MASK << shift);
+	val |= ds_cfg << shift;
+	writel(val, l3c_pmu->base + reg);
+}
+
+static inline void hisi_l3c_pmu_config_ds(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_cfg = hisi_get_datasrc_cfg(event);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_cfg)
+		hisi_l3c_pmu_write_ds(event, ds_cfg);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(l3c_pmu->base + L3C_DATSRC_CTRL);
+		val |= L3C_DATSRC_SKT_EN;
+		writel(val, l3c_pmu->base + L3C_DATSRC_CTRL);
+	}
+}
+
+static inline void hisi_l3c_pmu_clear_ds(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_cfg = hisi_get_datasrc_cfg(event);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_cfg)
+		hisi_l3c_pmu_write_ds(event, L3C_DATSRC_NONE);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(l3c_pmu->base + L3C_DATSRC_CTRL);
+		val &= ~L3C_DATSRC_SKT_EN;
+		writel(val, l3c_pmu->base + L3C_DATSRC_CTRL);
+	}
+}
+
+static inline void hisi_l3c_pmu_config_core_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 core = hisi_get_tt_core(event);
+
+	if (core) {
+		u32 val;
+
+		/* Config and enable core information */
+		writel(core, l3c_pmu->base + L3C_CORE_CTRL);
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val |= L3C_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+
+		/* Enable core-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val |= L3C_TRACETAG_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+	}
+}
+
+static inline void hisi_l3c_pmu_clear_core_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 core = hisi_get_tt_core(event);
+
+	if (core) {
+		u32 val;
+
+		/* Clear core information */
+		writel(L3C_COER_NONE, l3c_pmu->base + L3C_CORE_CTRL);
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val &= ~L3C_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+
+		/* Disable core-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val &= ~L3C_TRACETAG_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+	}
+}
+
+static void hisi_l3c_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_l3c_pmu_config_req_tracetag(event);
+		hisi_l3c_pmu_config_core_tracetag(event);
+		hisi_l3c_pmu_config_ds(event);
+	}
+}
+
+static void hisi_l3c_pmu_disable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_l3c_pmu_clear_ds(event);
+		hisi_l3c_pmu_clear_core_tracetag(event);
+		hisi_l3c_pmu_clear_req_tracetag(event);
+	}
+}
+
 /*
  * Select the counter register offset using the counter index
  */
@@ -49,14 +233,12 @@ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
 				     struct hw_perf_event *hwc)
 {
-	/* Read 64-bits and the upper 16 bits are RAZ */
 	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,
 				       struct hw_perf_event *hwc, u64 val)
 {
-	/* Write 64-bits and the upper 16 bits are WI */
 	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
@@ -165,23 +347,14 @@ static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx)
 
 static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {
 	{ "HISI0213", },
-	{},
+	{ "HISI0214", },
+	{}
 };
 MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_acpi_match);
 
 static int hisi_l3c_pmu_init_data(struct platform_device *pdev,
 				  struct hisi_pmu *l3c_pmu)
 {
-	unsigned long long id;
-	acpi_status status;
-
-	status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
-				       "_UID", NULL, &id);
-	if (ACPI_FAILURE(status))
-		return -EINVAL;
-
-	l3c_pmu->index_id = id;
-
 	/*
 	 * Use the SCCL_ID and CCL_ID to identify the L3C PMU, while
 	 * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1].
@@ -219,6 +392,20 @@ static const struct attribute_group hisi_l3c_pmu_v1_format_group = {
 	.attrs = hisi_l3c_pmu_v1_format_attr,
 };
 
+static struct attribute *hisi_l3c_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(tt_core, "config1:0-7"),
+	HISI_PMU_FORMAT_ATTR(tt_req, "config1:8-10"),
+	HISI_PMU_FORMAT_ATTR(datasrc_cfg, "config1:11-15"),
+	HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:16"),
+	NULL
+};
+
+static const struct attribute_group hisi_l3c_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_l3c_pmu_v2_format_attr,
+};
+
 static struct attribute *hisi_l3c_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rd_cpipe,		0x00),
 	HISI_PMU_EVENT_ATTR(wr_cpipe,		0x01),
@@ -241,6 +428,17 @@ static const struct attribute_group hisi_l3c_pmu_v1_events_group = {
 	.attrs = hisi_l3c_pmu_v1_events_attr,
 };
 
+static struct attribute *hisi_l3c_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(dat_hit,		0x48),
+	HISI_PMU_EVENT_ATTR(dat_access,		0xb8),
+	NULL
+};
+
+static const struct attribute_group hisi_l3c_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_l3c_pmu_v2_events_attr,
+};
+
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
 
 static struct attribute *hisi_l3c_pmu_cpumask_attrs[] = {
@@ -272,6 +470,14 @@ static const struct attribute_group *hisi_l3c_pmu_v1_attr_groups[] = {
 	NULL,
 };
 
+static const struct attribute_group *hisi_l3c_pmu_v2_attr_groups[] = {
+	&hisi_l3c_pmu_v2_format_group,
+	&hisi_l3c_pmu_v2_events_group,
+	&hisi_l3c_pmu_cpumask_attr_group,
+	&hisi_l3c_pmu_identifier_group,
+	NULL
+};
+
 static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
 	.write_evtype		= hisi_l3c_pmu_write_evtype,
 	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
@@ -285,6 +491,8 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
 	.read_counter		= hisi_l3c_pmu_read_counter,
 	.get_int_status		= hisi_l3c_pmu_get_int_status,
 	.clear_int_status	= hisi_l3c_pmu_clear_int_status,
+	.enable_filter		= hisi_l3c_pmu_enable_filter,
+	.disable_filter		= hisi_l3c_pmu_disable_filter,
 };
 
 static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
@@ -300,12 +508,20 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
+	if (l3c_pmu->identifier >= HISI_PMU_V2) {
+		l3c_pmu->counter_bits = 64;
+		l3c_pmu->check_event = L3C_V2_NR_EVENTS;
+		l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v2_attr_groups;
+	} else {
+		l3c_pmu->counter_bits = 48;
+		l3c_pmu->check_event = L3C_V1_NR_EVENTS;
+		l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v1_attr_groups;
+	}
+
 	l3c_pmu->num_counters = L3C_NR_COUNTERS;
-	l3c_pmu->counter_bits = 48;
 	l3c_pmu->ops = &hisi_uncore_l3c_ops;
 	l3c_pmu->dev = &pdev->dev;
 	l3c_pmu->on_cpu = -1;
-	l3c_pmu->check_event = L3C_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -333,8 +549,12 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	/*
+	 * CCL_ID is used to identify the L3C in the same SCCL which was
+	 * used _UID by mistake.
+	 */
 	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",
-			      l3c_pmu->sccl_id, l3c_pmu->index_id);
+			      l3c_pmu->sccl_id, l3c_pmu->ccl_id);
 	l3c_pmu->pmu = (struct pmu) {
 		.name		= name,
 		.module		= THIS_MODULE,
@@ -347,7 +567,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_l3c_pmu_v1_attr_groups,
+		.attr_groups	= l3c_pmu->pmu_events.attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index 82a4ff2bc3ae..30fb152e217c 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -21,7 +21,7 @@
 #include "hisi_uncore_pmu.h"
 
 #define HISI_GET_EVENTID(ev) (ev->hw.config_base & 0xff)
-#define HISI_MAX_PERIOD(nr) (BIT_ULL(nr) - 1)
+#define HISI_MAX_PERIOD(nr) (GENMASK_ULL((nr) - 1, 0))
 
 /*
  * PMU format attributes
@@ -256,6 +256,9 @@ static void hisi_uncore_pmu_enable_event(struct perf_event *event)
 	hisi_pmu->ops->write_evtype(hisi_pmu, hwc->idx,
 				    HISI_GET_EVENTID(event));
 
+	if (hisi_pmu->ops->enable_filter)
+		hisi_pmu->ops->enable_filter(event);
+
 	hisi_pmu->ops->enable_counter_int(hisi_pmu, hwc);
 	hisi_pmu->ops->enable_counter(hisi_pmu, hwc);
 }
@@ -268,6 +271,9 @@ static void hisi_uncore_pmu_disable_event(struct perf_event *event)
 	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
 
+	if (hisi_pmu->ops->disable_filter)
+		hisi_pmu->ops->disable_filter(event);
+
 	hisi_pmu->ops->disable_counter(hisi_pmu, hwc);
 	hisi_pmu->ops->disable_counter_int(hisi_pmu, hwc);
 }
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index aaaf637cc9ea..c9f180001ab0 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -11,6 +11,7 @@
 #ifndef __HISI_UNCORE_PMU_H__
 #define __HISI_UNCORE_PMU_H__
 
+#include <linux/bitfield.h>
 #include <linux/cpumask.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
@@ -22,6 +23,7 @@
 #undef pr_fmt
 #define pr_fmt(fmt)     "hisi_pmu: " fmt
 
+#define HISI_PMU_V2		0x30
 #define HISI_MAX_COUNTERS 0x10
 #define to_hisi_pmu(p)	(container_of(p, struct hisi_pmu, pmu))
 
@@ -35,6 +37,12 @@
 #define HISI_PMU_EVENT_ATTR(_name, _config)		\
 	HISI_PMU_ATTR(_name, hisi_event_sysfs_show, (unsigned long)_config)
 
+#define HISI_PMU_EVENT_ATTR_EXTRACTOR(name, config, hi, lo)        \
+	static inline u32 hisi_get_##name(struct perf_event *event)            \
+	{                                                                  \
+		return FIELD_GET(GENMASK_ULL(hi, lo), event->attr.config);  \
+	}
+
 struct hisi_pmu;
 
 struct hisi_uncore_ops {
@@ -50,11 +58,14 @@ struct hisi_uncore_ops {
 	void (*stop_counters)(struct hisi_pmu *);
 	u32 (*get_int_status)(struct hisi_pmu *hisi_pmu);
 	void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx);
+	void (*enable_filter)(struct perf_event *event);
+	void (*disable_filter)(struct perf_event *event);
 };
 
 struct hisi_pmu_hwevents {
 	struct perf_event *hw_events[HISI_MAX_COUNTERS];
 	DECLARE_BITMAP(used_mask, HISI_MAX_COUNTERS);
+	const struct attribute_group **attr_groups;
 };
 
 /* Generic pmu struct for different pmu types */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 4/8] drivers/perf: hisi: Add new functions for HHA PMU
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (2 preceding siblings ...)
  2020-12-31  6:19 ` [PATCH 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2021-01-26 12:10   ` John Garry
  2020-12-31  6:19 ` [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon Hip09 platform, some new functions are also supported on
HHA PMU, it can filter gathered statistics by the Master ID and mask
from the SoC if the user wants to do deep-going profiling.
Tracetag support is also added with L3C PMU in the SoC system.

$# perf stat -a -e hisi_sccl3_hha0/config=0x02,tracetag_en=0x1/ sleep 5

$# perf stat -a -e hisi_sccl3_hha0/config=0x02,srcid_cmd=0x1/ sleep 5
Much more introduction is added in documentation:
Documentation/admin-guide/perf/hisi-pmu.rst

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 203 +++++++++++++++++++++++++--
 1 file changed, 188 insertions(+), 15 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 2f55e5864d39..5e1c4b61ffce 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -25,19 +25,136 @@
 #define HHA_VERSION		0x1cf0
 #define HHA_PERF_CTRL		0x1E00
 #define HHA_EVENT_CTRL		0x1E04
+#define HHA_SRCID_CTRL		0x1E08
+#define HHA_DATSRC_CTRL		0x1BF0
 #define HHA_EVENT_TYPE0		0x1E80
 /*
- * Each counter is 48-bits and [48:63] are reserved
- * which are Read-As-Zero and Writes-Ignored.
+ * If the HW version only supports a 48-bit counter, then
+ * bits [63:48] are reserved, which are Read-As-Zero and
+ * Writes-Ignored.
  */
 #define HHA_CNT0_LOWER		0x1F00
 
-/* HHA has 16-counters */
+/* HHA PMU v1 has 16-counter and v2 only has 8-counter */
 #define HHA_V1_NR_COUNTERS	0x10
+#define HHA_V2_NR_COUNTERS	0x8
 
 #define HHA_PERF_CTRL_EN	0x1
+#define HHA_TRACETAG_EN		BIT(31)
+#define HHA_SRCID_EN		BIT(2)
+#define HHA_SRCID_CMD_SHIFT	6
+#define HHA_SRCID_MASK_SHIFT	20
+#define HHA_SRCID_CMD		GENMASK(16, 6)
+#define HHA_SRCID_MSK		GENMASK(30, 20)
+#define HHA_DATSRC_SKT_EN	BIT(23)
 #define HHA_EVTYPE_NONE		0xff
 #define HHA_V1_NR_EVENT		0x65
+#define HHA_V2_NR_EVENT		0xCE
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 10, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 21, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 22, 22);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 23, 23);
+
+static inline void hisi_hha_pmu_enable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+		val |= HHA_TRACETAG_EN;
+		writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+	}
+}
+
+static inline void hisi_hha_pmu_clear_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 val;
+
+	val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+	val &= ~HHA_TRACETAG_EN;
+	writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+}
+
+static inline void hisi_hha_pmu_config_ds(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
+		val |= HHA_DATSRC_SKT_EN;
+		writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+	}
+}
+
+static inline void hisi_hha_pmu_clear_ds(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
+		val &= ~HHA_DATSRC_SKT_EN;
+		writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+	}
+}
+
+static inline void hisi_hha_pmu_config_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val, msk;
+
+		msk = hisi_get_srcid_msk(event);
+		val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+		val |= HHA_SRCID_EN | (cmd << HHA_SRCID_CMD_SHIFT) |
+			(msk << HHA_SRCID_MASK_SHIFT);
+		writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+	}
+}
+
+static inline void hisi_hha_pmu_disable_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+		val &= ~(HHA_SRCID_EN | HHA_SRCID_MSK | HHA_SRCID_CMD);
+		writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+	}
+}
+
+static void hisi_hha_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_hha_pmu_enable_tracetag(event);
+		hisi_hha_pmu_config_ds(event);
+		hisi_hha_pmu_config_srcid(event);
+	}
+}
+
+static void hisi_hha_pmu_disable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_hha_pmu_disable_srcid(event);
+		hisi_hha_pmu_clear_ds(event);
+		hisi_hha_pmu_clear_tracetag(event);
+	}
+}
 
 /*
  * Select the counter register offset using the counter index
@@ -167,7 +284,8 @@ static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx)
 
 static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = {
 	{ "HISI0243", },
-	{},
+	{ "HISI0244", },
+	{}
 };
 MODULE_DEVICE_TABLE(acpi, hisi_hha_pmu_acpi_match);
 
@@ -177,13 +295,6 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
 	unsigned long long id;
 	acpi_status status;
 
-	status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
-				       "_UID", NULL, &id);
-	if (ACPI_FAILURE(status))
-		return -EINVAL;
-
-	hha_pmu->index_id = id;
-
 	/*
 	 * Use SCCL_ID and UID to identify the HHA PMU, while
 	 * SCCL_ID is in MPIDR[aff2].
@@ -193,6 +304,22 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
 		dev_err(&pdev->dev, "Can not read hha sccl-id!\n");
 		return -EINVAL;
 	}
+
+	/*
+	 * Early versions of BIOS support _UID by mistake, so we support
+	 * both "hisilicon, idx-id" as preference, if availbale.
+	 */
+	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
+				     &hha_pmu->index_id)) {
+		status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
+					       "_UID", NULL, &id);
+		if (ACPI_FAILURE(status)) {
+			dev_err(&pdev->dev, "Cannot read idx-id!\n");
+			return -EINVAL;
+		}
+
+		hha_pmu->index_id = id;
+	}
 	/* HHA PMUs only share the same SCCL */
 	hha_pmu->ccl_id = -1;
 
@@ -217,6 +344,20 @@ static const struct attribute_group hisi_hha_pmu_v1_format_group = {
 	.attrs = hisi_hha_pmu_v1_format_attr,
 };
 
+static struct attribute *hisi_hha_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:0-10"),
+	HISI_PMU_FORMAT_ATTR(srcid_mask, "config1:11-21"),
+	HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:22"),
+	HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:23"),
+	NULL
+};
+
+static const struct attribute_group hisi_hha_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_hha_pmu_v2_format_attr,
+};
+
 static struct attribute *hisi_hha_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rx_ops_num,		0x00),
 	HISI_PMU_EVENT_ATTR(rx_outer,		0x01),
@@ -252,6 +393,20 @@ static const struct attribute_group hisi_hha_pmu_v1_events_group = {
 	.attrs = hisi_hha_pmu_v1_events_attr,
 };
 
+static struct attribute *hisi_hha_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(rx_ops_num,		0x00),
+	HISI_PMU_EVENT_ATTR(rx_outer,		0x01),
+	HISI_PMU_EVENT_ATTR(rx_sccl,		0x02),
+	HISI_PMU_EVENT_ATTR(hha_retry,		0x2e),
+	HISI_PMU_EVENT_ATTR(cycles,		0x55),
+	NULL
+};
+
+static const struct attribute_group hisi_hha_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_hha_pmu_v2_events_attr,
+};
+
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
 
 static struct attribute *hisi_hha_pmu_cpumask_attrs[] = {
@@ -283,6 +438,14 @@ static const struct attribute_group *hisi_hha_pmu_v1_attr_groups[] = {
 	NULL,
 };
 
+static const struct attribute_group *hisi_hha_pmu_v2_attr_groups[] = {
+	&hisi_hha_pmu_v2_format_group,
+	&hisi_hha_pmu_v2_events_group,
+	&hisi_hha_pmu_cpumask_attr_group,
+	&hisi_hha_pmu_identifier_group,
+	NULL
+};
+
 static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
 	.write_evtype		= hisi_hha_pmu_write_evtype,
 	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
@@ -296,6 +459,8 @@ static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
 	.read_counter		= hisi_hha_pmu_read_counter,
 	.get_int_status		= hisi_hha_pmu_get_int_status,
 	.clear_int_status	= hisi_hha_pmu_clear_int_status,
+	.enable_filter		= hisi_hha_pmu_enable_filter,
+	.disable_filter		= hisi_hha_pmu_disable_filter,
 };
 
 static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
@@ -311,12 +476,20 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	hha_pmu->num_counters = HHA_V1_NR_COUNTERS;
-	hha_pmu->counter_bits = 48;
+	if (hha_pmu->identifier >= HISI_PMU_V2) {
+		hha_pmu->counter_bits = 64;
+		hha_pmu->check_event = HHA_V2_NR_EVENT;
+		hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v2_attr_groups;
+		hha_pmu->num_counters = HHA_V2_NR_COUNTERS;
+	} else {
+		hha_pmu->counter_bits = 48;
+		hha_pmu->check_event = HHA_V1_NR_EVENT;
+		hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v1_attr_groups;
+		hha_pmu->num_counters = HHA_V1_NR_COUNTERS;
+	}
 	hha_pmu->ops = &hisi_uncore_hha_ops;
 	hha_pmu->dev = &pdev->dev;
 	hha_pmu->on_cpu = -1;
-	hha_pmu->check_event = HHA_V1_NR_EVENT;
 
 	return 0;
 }
@@ -358,7 +531,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_hha_pmu_v1_attr_groups,
+		.attr_groups	= hha_pmu->pmu_events.attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (3 preceding siblings ...)
  2020-12-31  6:19 ` [PATCH 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2021-01-26 12:33   ` John Garry
  2020-12-31  6:19 ` [PATCH 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

DDRC PMU's events are useful for performance profiling, but the events
are limited and counter is fixed. On HiSilicon Hip09 platform, PMU
counters are the programable and more events are supported. Let's
add the DDRC PMU v2 driver.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 208 ++++++++++++++++++++++++--
 drivers/perf/hisilicon/hisi_uncore_pmu.h      |   2 +
 2 files changed, 197 insertions(+), 13 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index 7f940c47b833..8d2db5d28335 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -18,7 +18,7 @@
 
 #include "hisi_uncore_pmu.h"
 
-/* DDRC register definition */
+/* DDRC register definition in v1 */
 #define DDRC_PERF_CTRL		0x010
 #define DDRC_FLUX_WR		0x380
 #define DDRC_FLUX_RD		0x384
@@ -34,12 +34,24 @@
 #define DDRC_INT_CLEAR		0x6d0
 #define DDRC_VERSION		0x710
 
+/* DDRC register definition in v2 */
+#define DDRC_V2_INT_MASK	0x528
+#define DDRC_V2_INT_STATUS	0x52c
+#define DDRC_V2_INT_CLEAR	0x530
+#define DDRC_V2_EVENT_CNT	0xE00
+#define DDRC_V2_EVENT_CTRL	0xE70
+#define DDRC_V2_EVENT_TYPE	0xE74
+#define DDRC_V2_PERF_CTRL	0xEA0
+
 /* DDRC has 8-counters */
 #define DDRC_NR_COUNTERS	0x8
 #define DDRC_V1_PERF_CTRL_EN	0x2
+#define DDRC_V2_PERF_CTRL_EN	0x1
 #define DDRC_V1_NR_EVENTS	0x07
+#define DDRC_V2_NR_EVENTS	0x90
+
 /*
- * For DDRC PMU, there are eight-events and every event has been mapped
+ * For PMU v1, there are eight-events and every event has been mapped
  * to fixed-purpose counters which register offset is not consistent.
  * Therefore there is no write event type and we assume that event
  * code (0 to 7) is equal to counter index in PMU driver.
@@ -61,6 +73,11 @@ static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
 	return ddrc_reg_off[cntr_idx];
 }
 
+static u32 hisi_ddrc_pmu_v2_get_counter_offset(int cntr_idx)
+{
+	return DDRC_V2_EVENT_CNT + cntr_idx * 8;
+}
+
 static u64 hisi_ddrc_pmu_v1_read_counter(struct hisi_pmu *ddrc_pmu,
 				      struct hw_perf_event *hwc)
 {
@@ -75,13 +92,34 @@ static void hisi_ddrc_pmu_v1_write_counter(struct hisi_pmu *ddrc_pmu,
 	       ddrc_pmu->base + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
 }
 
+static u64 hisi_ddrc_pmu_v2_read_counter(struct hisi_pmu *ddrc_pmu,
+					 struct hw_perf_event *hwc)
+{
+	return readq(ddrc_pmu->base +
+		     hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
+}
+
+static void hisi_ddrc_pmu_v2_write_counter(struct hisi_pmu *ddrc_pmu,
+					   struct hw_perf_event *hwc, u64 val)
+{
+	writeq(val,
+	       ddrc_pmu->base + hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
+}
+
 /*
- * For DDRC PMU, event has been mapped to fixed-purpose counter by hardware,
- * so there is no need to write event type.
+ * For DDRC PMU v1, event has been mapped to fixed-purpose counter by hardware,
+ * so there is no need to write event type, while it is programmable counter in
+ * PMU v2.
  */
 static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
 				       u32 type)
 {
+	u32 offset;
+
+	if (hha_pmu->identifier >= HISI_PMU_V2) {
+		offset = DDRC_V2_EVENT_TYPE + 4 * idx;
+		writel(type, hha_pmu->base + offset);
+	}
 }
 
 static void hisi_ddrc_pmu_v1_start_counters(struct hisi_pmu *ddrc_pmu)
@@ -142,6 +180,49 @@ static int hisi_ddrc_pmu_v1_get_event_idx(struct perf_event *event)
 	return idx;
 }
 
+static int hisi_ddrc_pmu_v2_get_event_idx(struct perf_event *event)
+{
+	return hisi_uncore_pmu_get_event_idx(event);
+}
+
+static void hisi_ddrc_pmu_v2_start_counters(struct hisi_pmu *ddrc_pmu)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+	val |= DDRC_V2_PERF_CTRL_EN;
+	writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+}
+
+static void hisi_ddrc_pmu_v2_stop_counters(struct hisi_pmu *ddrc_pmu)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+	val &= ~DDRC_V2_PERF_CTRL_EN;
+	writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+}
+
+static void hisi_ddrc_pmu_v2_enable_counter(struct hisi_pmu *ddrc_pmu,
+					    struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+	val |= 1 << hwc->idx;
+	writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+}
+
+static void hisi_ddrc_pmu_v2_disable_counter(struct hisi_pmu *ddrc_pmu,
+					     struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+	val &= ~(1 << hwc->idx);
+	writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+}
+
 static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
 						struct hw_perf_event *hwc)
 {
@@ -149,7 +230,7 @@ static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
 
 	/* Write 0 to enable interrupt */
 	val = readl(ddrc_pmu->base + DDRC_INT_MASK);
-	val &= ~(1 << GET_DDRC_EVENTID(hwc));
+	val &= ~(1 << hwc->idx);
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
@@ -160,10 +241,30 @@ static void hisi_ddrc_pmu_v1_disable_counter_int(struct hisi_pmu *ddrc_pmu,
 
 	/* Write 1 to mask interrupt */
 	val = readl(ddrc_pmu->base + DDRC_INT_MASK);
-	val |= (1 << GET_DDRC_EVENTID(hwc));
+	val |= 1 << hwc->idx;
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
+static void hisi_ddrc_pmu_v2_enable_counter_int(struct hisi_pmu *ddrc_pmu,
+						struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
+	val &= ~(1 << hwc->idx);
+	writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
+}
+
+static void hisi_ddrc_pmu_v2_disable_counter_int(struct hisi_pmu *ddrc_pmu,
+						struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
+	val |= 1 << hwc->idx;
+	writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
+}
+
 static u32 hisi_ddrc_pmu_v1_get_int_status(struct hisi_pmu *ddrc_pmu)
 {
 	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
@@ -175,9 +276,21 @@ static void hisi_ddrc_pmu_v1_clear_int_status(struct hisi_pmu *ddrc_pmu,
 	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
 }
 
+static u32 hisi_ddrc_pmu_v2_get_int_status(struct hisi_pmu *ddrc_pmu)
+{
+	return readl(ddrc_pmu->base + DDRC_V2_INT_STATUS);
+}
+
+static void hisi_ddrc_pmu_v2_clear_int_status(struct hisi_pmu *ddrc_pmu,
+					      int idx)
+{
+	writel(1 << idx, ddrc_pmu->base + DDRC_V2_INT_CLEAR);
+}
+
 static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
 	{ "HISI0233", },
-	{},
+	{ "HISI0234", },
+	{}
 };
 MODULE_DEVICE_TABLE(acpi, hisi_ddrc_pmu_acpi_match);
 
@@ -209,6 +322,13 @@ static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
 	}
 
 	ddrc_pmu->identifier = readl(ddrc_pmu->base + DDRC_VERSION);
+	if (ddrc_pmu->identifier >= HISI_PMU_V2) {
+		if (device_property_read_u32(&pdev->dev, "hisilicon,sub-id",
+					     &ddrc_pmu->sub_id)) {
+			dev_err(&pdev->dev, "Can not read sub-id!\n");
+			return -EINVAL;
+		}
+	}
 
 	return 0;
 }
@@ -223,6 +343,16 @@ static const struct attribute_group hisi_ddrc_pmu_v1_format_group = {
 	.attrs = hisi_ddrc_pmu_v1_format_attr,
 };
 
+static struct attribute *hisi_ddrc_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	NULL
+};
+
+static const struct attribute_group hisi_ddrc_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_ddrc_pmu_v2_format_attr,
+};
+
 static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(flux_wr,		0x00),
 	HISI_PMU_EVENT_ATTR(flux_rd,		0x01),
@@ -240,6 +370,18 @@ static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
 	.attrs = hisi_ddrc_pmu_v1_events_attr,
 };
 
+static struct attribute *hisi_ddrc_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(clocks,		0x00),
+	HISI_PMU_EVENT_ATTR(flux_wr,		0x83),
+	HISI_PMU_EVENT_ATTR(flux_rd,		0x84),
+	NULL
+};
+
+static const struct attribute_group hisi_ddrc_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_ddrc_pmu_v2_events_attr,
+};
+
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
 
 static struct attribute *hisi_ddrc_pmu_cpumask_attrs[] = {
@@ -271,6 +413,14 @@ static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = {
 	NULL,
 };
 
+static const struct attribute_group *hisi_ddrc_pmu_v2_attr_groups[] = {
+	&hisi_ddrc_pmu_v2_format_group,
+	&hisi_ddrc_pmu_v2_events_group,
+	&hisi_ddrc_pmu_cpumask_attr_group,
+	&hisi_ddrc_pmu_identifier_group,
+	NULL
+};
+
 static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
 	.write_evtype           = hisi_ddrc_pmu_write_evtype,
 	.get_event_idx		= hisi_ddrc_pmu_v1_get_event_idx,
@@ -286,6 +436,21 @@ static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
 	.clear_int_status	= hisi_ddrc_pmu_v1_clear_int_status,
 };
 
+static const struct hisi_uncore_ops hisi_uncore_ddrc_v2_ops = {
+	.write_evtype           = hisi_ddrc_pmu_write_evtype,
+	.get_event_idx		= hisi_ddrc_pmu_v2_get_event_idx,
+	.start_counters		= hisi_ddrc_pmu_v2_start_counters,
+	.stop_counters		= hisi_ddrc_pmu_v2_stop_counters,
+	.enable_counter		= hisi_ddrc_pmu_v2_enable_counter,
+	.disable_counter	= hisi_ddrc_pmu_v2_disable_counter,
+	.enable_counter_int	= hisi_ddrc_pmu_v2_enable_counter_int,
+	.disable_counter_int	= hisi_ddrc_pmu_v2_disable_counter_int,
+	.write_counter		= hisi_ddrc_pmu_v2_write_counter,
+	.read_counter		= hisi_ddrc_pmu_v2_read_counter,
+	.get_int_status		= hisi_ddrc_pmu_v2_get_int_status,
+	.clear_int_status	= hisi_ddrc_pmu_v2_clear_int_status,
+};
+
 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 				   struct hisi_pmu *ddrc_pmu)
 {
@@ -299,12 +464,21 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
+	if (ddrc_pmu->identifier >= HISI_PMU_V2) {
+		ddrc_pmu->counter_bits = 48;
+		ddrc_pmu->check_event = DDRC_V2_NR_EVENTS;
+		ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v2_attr_groups;
+		ddrc_pmu->ops = &hisi_uncore_ddrc_v2_ops;
+	} else {
+		ddrc_pmu->counter_bits = 32;
+		ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
+		ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v1_attr_groups;
+		ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
+	}
+
 	ddrc_pmu->num_counters = DDRC_NR_COUNTERS;
-	ddrc_pmu->counter_bits = 32;
-	ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
 	ddrc_pmu->dev = &pdev->dev;
 	ddrc_pmu->on_cpu = -1;
-	ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -332,8 +506,16 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_ddrc%u",
-			      ddrc_pmu->sccl_id, ddrc_pmu->index_id);
+	if (ddrc_pmu->identifier >= HISI_PMU_V2)
+		name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+				      "hisi_sccl%u_ddrc%u_%u",
+				      ddrc_pmu->sccl_id, ddrc_pmu->index_id,
+				      ddrc_pmu->sub_id);
+	else
+		name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+				      "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
+				      ddrc_pmu->index_id);
+
 	ddrc_pmu->pmu = (struct pmu) {
 		.name		= name,
 		.module		= THIS_MODULE,
@@ -346,7 +528,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_ddrc_pmu_v1_attr_groups,
+		.attr_groups	= ddrc_pmu->pmu_events.attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index c9f180001ab0..7e2dba8841de 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -85,6 +85,8 @@ struct hisi_pmu {
 	void __iomem *base;
 	/* the ID of the PMU modules */
 	u32 index_id;
+	/* For DDRC PMU v2: each DDRC has more than one DMC */
+	u32 sub_id;
 	int num_counters;
 	int counter_bits;
 	/* check event code range */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (4 preceding siblings ...)
  2020-12-31  6:19 ` [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2021-01-26 12:30   ` John Garry
  2020-12-31  6:19 ` [PATCH 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
module (Skyros Link Layer Controller), its has separate PMU registers which
the driver can program it freely and interrupt is supported to handle
counter overflow. Let's support its driver under the framework of HiSilicon
uncore PMU driver.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/Makefile               |   2 +-
 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 530 ++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                    |   1 +
 3 files changed, 532 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index e8377061845f..6600a9d45dd8 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
-			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o
+			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
new file mode 100644
index 000000000000..6911c388a5ac
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HiSilicon SLLC uncore Hardware event counters support
+ *
+ * Copyright (C) 2020 Hisilicon Limited
+ * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
+ *
+ * This code is based on the uncore PMUs like arm-cci and arm-ccn.
+ */
+#include <linux/acpi.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+
+#include "hisi_uncore_pmu.h"
+
+/* SLLC register definition */
+#define SLLC_INT_MASK			0x0814
+#define SLLC_INT_STATUS			0x0818
+#define SLLC_INT_CLEAR			0x081C
+#define SLLC_PERF_CTRL			0x1C00
+#define SLLC_SRCID_CTRL			0x1C04
+#define SLLC_TGTID_CTRL			0x1C08
+#define SLLC_EVENT_CTRL			0x1C14
+#define SLLC_EVENT_TYPE0		0x1C18
+#define SLLC_VERSION			0x1CF0
+#define SLLC_EVENT_CNT0_L		0x1D00
+
+#define SLLC_EVTYPE_MASK		0xFF
+#define SLLC_PERF_CTRL_EN		BIT(0)
+#define SLLC_FILT_EN			BIT(1)
+#define SLLC_TRACETAG_EN		BIT(2)
+#define SLLC_SRCID_EN			BIT(4)
+#define SLLC_SRCID_NONE			0x0
+#define SLLC_TGTID_EN			BIT(5)
+#define SLLC_TGTID_NONE			0x0
+#define SLLC_TGTID_LO_SHIFT		1
+#define SLLC_TGTID_HI_SHIFT		12
+#define SLLC_SRCID_CMD_SHIFT		1
+#define SLLC_SRCID_MSK_SHIFT		12
+#define SLLC_NR_EVENTS			0x80
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
+
+static inline bool tgtid_is_valid(u32 hi, u32 lo)
+{
+	return lo > 0 && hi >= lo;
+}
+
+static inline void hisi_sllc_pmu_enable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val |= SLLC_TRACETAG_EN | SLLC_FILT_EN;
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static inline void hisi_sllc_pmu_disable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val &= ~(SLLC_TRACETAG_EN | SLLC_FILT_EN);
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static inline void hisi_sllc_pmu_config_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 lo = hisi_get_tgtid_lo(event);
+	u32 hi = hisi_get_tgtid_hi(event);
+
+	if (tgtid_is_valid(hi, lo)) {
+		u32 val = (hi << SLLC_TGTID_HI_SHIFT) | (lo << SLLC_TGTID_LO_SHIFT);
+
+		writel(val, sllc_pmu->base + SLLC_TGTID_CTRL);
+
+		/* Enable the tgtid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val |= SLLC_TGTID_EN | SLLC_FILT_EN;
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static inline void hisi_sllc_pmu_clear_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 lo = hisi_get_tgtid_lo(event);
+	u32 hi = hisi_get_tgtid_hi(event);
+
+	if (tgtid_is_valid(hi, lo)) {
+		u32 val;
+
+		writel(SLLC_TGTID_NONE, sllc_pmu->base + SLLC_TGTID_CTRL);
+		/* Disable the tgtid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val &= ~(SLLC_TGTID_EN | SLLC_FILT_EN);
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static inline void hisi_sllc_pmu_config_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val, msk;
+
+		msk = hisi_get_srcid_msk(event);
+		val = (cmd << SLLC_SRCID_CMD_SHIFT) | (msk << SLLC_SRCID_MSK_SHIFT);
+		writel(val, sllc_pmu->base + SLLC_SRCID_CTRL);
+		/* Enable the srcid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val |= SLLC_SRCID_EN | SLLC_FILT_EN;
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static inline void hisi_sllc_pmu_clear_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val;
+
+		writel(SLLC_SRCID_NONE, sllc_pmu->base + SLLC_SRCID_CTRL);
+		/* Disable the srcid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val &= ~(SLLC_SRCID_EN | SLLC_FILT_EN);
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static void hisi_sllc_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_sllc_pmu_enable_tracetag(event);
+		hisi_sllc_pmu_config_srcid(event);
+		hisi_sllc_pmu_config_tgtid(event);
+	}
+}
+
+static void hisi_sllc_pmu_clear_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_sllc_pmu_disable_tracetag(event);
+		hisi_sllc_pmu_clear_srcid(event);
+		hisi_sllc_pmu_clear_tgtid(event);
+	}
+}
+
+static u32 hisi_sllc_pmu_get_counter_offset(int idx)
+{
+	return (SLLC_EVENT_CNT0_L + idx * 8);
+}
+
+static u64 hisi_sllc_pmu_read_counter(struct hisi_pmu *sllc_pmu,
+				      struct hw_perf_event *hwc)
+{
+	return readq(sllc_pmu->base +
+		     hisi_sllc_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_sllc_pmu_write_counter(struct hisi_pmu *sllc_pmu,
+					struct hw_perf_event *hwc, u64 val)
+{
+	writeq(val, sllc_pmu->base +
+	       hisi_sllc_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_sllc_pmu_write_evtype(struct hisi_pmu *sllc_pmu, int idx,
+				       u32 type)
+{
+	u32 reg, reg_idx, shift, val;
+
+	/*
+	 * Select the appropriate event select register(SLLC_EVENT_TYPE0/1).
+	 * There are 2 event select registers for the 8 hardware counters.
+	 * Event code is 8-bits and for the former 4 hardware counters,
+	 * SLLC_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
+	 * SLLC_EVENT_TYPE1 is chosen.
+	 */
+	reg = SLLC_EVENT_TYPE0 + rounddown(idx, 4);
+	reg_idx = idx % 4;
+	shift = 8 * reg_idx;
+
+	/* Write event code to SLLC_EVENT_TYPEx Register */
+	val = readl(sllc_pmu->base + reg);
+	val &= ~(SLLC_EVTYPE_MASK << shift);
+	val |= (type << shift);
+	writel(val, sllc_pmu->base + reg);
+}
+
+static void hisi_sllc_pmu_start_counters(struct hisi_pmu *sllc_pmu)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+	val |= SLLC_PERF_CTRL_EN;
+	writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+}
+
+static void hisi_sllc_pmu_stop_counters(struct hisi_pmu *sllc_pmu)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+	val &= ~(SLLC_PERF_CTRL_EN);
+	writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+}
+
+static void hisi_sllc_pmu_enable_counter(struct hisi_pmu *sllc_pmu,
+					 struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_EVENT_CTRL);
+	val |= 1 << hwc->idx;
+	writel(val, sllc_pmu->base + SLLC_EVENT_CTRL);
+}
+
+static void hisi_sllc_pmu_disable_counter(struct hisi_pmu *sllc_pmu,
+					  struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_EVENT_CTRL);
+	val &= ~(1 << hwc->idx);
+	writel(val, sllc_pmu->base + SLLC_EVENT_CTRL);
+}
+
+static void hisi_sllc_pmu_enable_counter_int(struct hisi_pmu *sllc_pmu,
+					     struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_INT_MASK);
+	/* Write 0 to enable interrupt */
+	val &= ~(1 << hwc->idx);
+	writel(val, sllc_pmu->base + SLLC_INT_MASK);
+}
+
+static void hisi_sllc_pmu_disable_counter_int(struct hisi_pmu *sllc_pmu,
+					      struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_INT_MASK);
+	/* Write 1 to mask interrupt */
+	val |= 1 << hwc->idx;
+	writel(val, sllc_pmu->base + SLLC_INT_MASK);
+}
+
+static u32 hisi_sllc_pmu_get_int_status(struct hisi_pmu *sllc_pmu)
+{
+	return readl(sllc_pmu->base + SLLC_INT_STATUS);
+}
+
+static void hisi_sllc_pmu_clear_int_status(struct hisi_pmu *sllc_pmu, int idx)
+{
+	writel(1 << idx, sllc_pmu->base + SLLC_INT_CLEAR);
+}
+
+static const struct acpi_device_id hisi_sllc_pmu_acpi_match[] = {
+	{ "HISI0263", },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, hisi_sllc_pmu_acpi_match);
+
+static int hisi_sllc_pmu_init_data(struct platform_device *pdev,
+				   struct hisi_pmu *sllc_pmu)
+{
+	/*
+	 * Use the SCCL_ID and the index ID to identify the SLLC PMU,
+	 * while SCCL_ID is from MPIDR_EL1 by CPU.
+	 */
+	if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
+				     &sllc_pmu->sccl_id)) {
+		dev_err(&pdev->dev, "Cannot read sccl-id!\n");
+		return -EINVAL;
+	}
+
+	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
+				     &sllc_pmu->index_id)) {
+		dev_err(&pdev->dev, "Cannot read idx-id!\n");
+		return -EINVAL;
+	}
+
+	/* SLLC PMUs only share the same SCCL */
+	sllc_pmu->ccl_id = -1;
+
+	sllc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(sllc_pmu->base)) {
+		dev_err(&pdev->dev, "ioremap failed for sllc_pmu resource.\n");
+		return PTR_ERR(sllc_pmu->base);
+	}
+
+	sllc_pmu->identifier = readl(sllc_pmu->base + SLLC_VERSION);
+
+	return 0;
+}
+
+static struct attribute *hisi_sllc_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(tgtid_low, "config1:0-10"),
+	HISI_PMU_FORMAT_ATTR(tgtid_high, "config1:11-21"),
+	HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"),
+	HISI_PMU_FORMAT_ATTR(srcid_mask, "config1:33-43"),
+	HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"),
+	NULL
+};
+
+static const struct attribute_group hisi_sllc_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_sllc_pmu_v2_format_attr,
+};
+
+static struct attribute *hisi_sllc_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(rx_req,             0x30),
+	HISI_PMU_EVENT_ATTR(rx_data,            0x31),
+	HISI_PMU_EVENT_ATTR(tx_req,             0x34),
+	HISI_PMU_EVENT_ATTR(tx_data,            0x35),
+	HISI_PMU_EVENT_ATTR(cycles,             0x09),
+	NULL
+};
+
+static const struct attribute_group hisi_sllc_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_sllc_pmu_v2_events_attr,
+};
+
+static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
+
+static struct attribute *hisi_sllc_pmu_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL
+};
+
+static const struct attribute_group hisi_sllc_pmu_cpumask_attr_group = {
+	.attrs = hisi_sllc_pmu_cpumask_attrs,
+};
+
+static struct device_attribute hisi_sllc_pmu_identifier_attr =
+	__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
+
+static struct attribute *hisi_sllc_pmu_identifier_attrs[] = {
+	&hisi_sllc_pmu_identifier_attr.attr,
+	NULL
+};
+
+static struct attribute_group hisi_sllc_pmu_identifier_group = {
+	.attrs = hisi_sllc_pmu_identifier_attrs,
+};
+
+static const struct attribute_group *hisi_sllc_pmu_v2_attr_groups[] = {
+	&hisi_sllc_pmu_v2_format_group,
+	&hisi_sllc_pmu_v2_events_group,
+	&hisi_sllc_pmu_cpumask_attr_group,
+	&hisi_sllc_pmu_identifier_group,
+	NULL
+};
+
+static const struct hisi_uncore_ops hisi_uncore_sllc_ops = {
+	.write_evtype		= hisi_sllc_pmu_write_evtype,
+	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
+	.start_counters		= hisi_sllc_pmu_start_counters,
+	.stop_counters		= hisi_sllc_pmu_stop_counters,
+	.enable_counter		= hisi_sllc_pmu_enable_counter,
+	.disable_counter	= hisi_sllc_pmu_disable_counter,
+	.enable_counter_int	= hisi_sllc_pmu_enable_counter_int,
+	.disable_counter_int	= hisi_sllc_pmu_disable_counter_int,
+	.write_counter		= hisi_sllc_pmu_write_counter,
+	.read_counter		= hisi_sllc_pmu_read_counter,
+	.get_int_status		= hisi_sllc_pmu_get_int_status,
+	.clear_int_status	= hisi_sllc_pmu_clear_int_status,
+	.enable_filter		= hisi_sllc_pmu_enable_filter,
+	.disable_filter		= hisi_sllc_pmu_clear_filter,
+};
+
+static int hisi_sllc_pmu_dev_probe(struct platform_device *pdev,
+				   struct hisi_pmu *sllc_pmu)
+{
+	int ret;
+
+	ret = hisi_sllc_pmu_init_data(pdev, sllc_pmu);
+	if (ret)
+		return ret;
+
+	ret = hisi_uncore_pmu_init_irq(sllc_pmu, pdev);
+	if (ret)
+		return ret;
+
+	sllc_pmu->pmu_events.attr_groups = hisi_sllc_pmu_v2_attr_groups;
+	sllc_pmu->ops = &hisi_uncore_sllc_ops;
+	sllc_pmu->check_event = SLLC_NR_EVENTS;
+	sllc_pmu->counter_bits = 64;
+	sllc_pmu->num_counters = 8;
+	sllc_pmu->dev = &pdev->dev;
+	sllc_pmu->on_cpu = -1;
+
+	return 0;
+}
+
+static int hisi_sllc_pmu_probe(struct platform_device *pdev)
+{
+	struct hisi_pmu *sllc_pmu;
+	char *name;
+	int ret;
+
+	sllc_pmu = devm_kzalloc(&pdev->dev, sizeof(*sllc_pmu), GFP_KERNEL);
+	if (!sllc_pmu)
+		return -ENOMEM;
+
+	ret = hisi_sllc_pmu_dev_probe(pdev, sllc_pmu);
+	if (ret)
+		return ret;
+
+	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_sllc%u",
+			      sllc_pmu->sccl_id, sllc_pmu->index_id);
+	if (!name) {
+		dev_err(&pdev->dev, "failed to allocate name for PMU\n");
+		return -ENOMEM;
+	}
+
+	ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+				       &sllc_pmu->node);
+	if (ret) {
+		dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
+		return ret;
+	}
+
+	sllc_pmu->pmu = (struct pmu) {
+		.module		= THIS_MODULE,
+		.task_ctx_nr	= perf_invalid_context,
+		.event_init	= hisi_uncore_pmu_event_init,
+		.pmu_enable	= hisi_uncore_pmu_enable,
+		.pmu_disable	= hisi_uncore_pmu_disable,
+		.add		= hisi_uncore_pmu_add,
+		.del		= hisi_uncore_pmu_del,
+		.start		= hisi_uncore_pmu_start,
+		.stop		= hisi_uncore_pmu_stop,
+		.read		= hisi_uncore_pmu_read,
+		.attr_groups    = sllc_pmu->pmu_events.attr_groups,
+		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
+	};
+
+	ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
+	if (ret) {
+		dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
+		cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+					    &sllc_pmu->node);
+		irq_set_affinity_hint(sllc_pmu->irq, NULL);
+	}
+
+	platform_set_drvdata(pdev, sllc_pmu);
+
+	return ret;
+}
+
+static int hisi_sllc_pmu_remove(struct platform_device *pdev)
+{
+	struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev);
+
+	perf_pmu_unregister(&sllc_pmu->pmu);
+	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+					    &sllc_pmu->node);
+	irq_set_affinity_hint(sllc_pmu->irq, NULL);
+
+	return 0;
+}
+
+static struct platform_driver hisi_sllc_pmu_driver = {
+	.driver = {
+		.name = "hisi_sllc_pmu",
+		.acpi_match_table = hisi_sllc_pmu_acpi_match,
+	},
+	.probe = hisi_sllc_pmu_probe,
+	.remove = hisi_sllc_pmu_remove,
+};
+
+static int __init hisi_sllc_pmu_module_init(void)
+{
+	int ret;
+
+	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+				      "AP_PERF_ARM_HISI_SLLC_ONLINE",
+				      hisi_uncore_pmu_online_cpu,
+				      hisi_uncore_pmu_offline_cpu);
+	if (ret) {
+		pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = platform_driver_register(&hisi_sllc_pmu_driver);
+	if (ret)
+		cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
+
+	return ret;
+}
+module_init(hisi_sllc_pmu_module_init);
+
+static void __exit hisi_sllc_pmu_module_exit(void)
+{
+	platform_driver_unregister(&hisi_sllc_pmu_driver);
+	cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
+}
+module_exit(hisi_sllc_pmu_module_exit);
+
+MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 0042ef362511..b5e04f9b68f1 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -174,6 +174,7 @@ enum cpuhp_state {
 	CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
+	CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
 	CPUHP_AP_PERF_ARM_L2X0_ONLINE,
 	CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
 	CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 7/8] drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (5 preceding siblings ...)
  2020-12-31  6:19 ` [PATCH 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2021-01-26 12:45   ` John Garry
  2020-12-31  6:19 ` [PATCH 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2 Shaokun Zhang
  2021-01-22  6:03 ` [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
  8 siblings, 1 reply; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon Hip09 platform, there is a PA (Protocol Adapter) module on
each chip SICL (Super I/O Cluster) which incorporates three Hydra interface
and facilitates the cache coherency between the dies on the chip. While PA
uncore PMU model is the same as other Hip09 PMU modules and many PMU events
are supported. Let's support the PMU driver using the HiSilicon uncore PMU
framework.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/Makefile             |   3 +-
 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 498 ++++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                  |   1 +
 3 files changed, 501 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index 6600a9d45dd8..7643c9f93e36 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
-			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
+			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o \
+			  hisi_uncore_pa_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
new file mode 100644
index 000000000000..eec12f5daf71
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HiSilicon PA uncore Hardware event counters support
+ *
+ * Copyright (C) 2020 HiSilicon Limited
+ * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
+ *
+ * This code is based on the uncore PMUs like arm-cci and arm-ccn.
+ */
+#include <linux/acpi.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+
+#include "hisi_uncore_pmu.h"
+
+/* PA register definition */
+#define PA_PERF_CTRL			0x1C00
+#define PA_EVENT_CTRL			0x1C04
+#define PA_TT_CTRL			0x1C08
+#define PA_TGTID_CTRL			0x1C14
+#define PA_SRCID_CTRL			0x1C18
+#define PA_INT_MASK			0x1C70
+#define PA_INT_STATUS			0x1C78
+#define PA_INT_CLEAR			0x1C7C
+#define PA_EVENT_TYPE0			0x1C80
+#define PA_PMU_VERSION			0x1CF0
+#define PA_EVENT_CNT0_L			0x1D00
+
+#define PA_EVTYPE_MASK			0xFF
+#define PA_NR_COUNTERS			0x8
+#define PA_PERF_CTRL_EN			BIT(0)
+#define PA_TRACETAG_EN			BIT(4)
+#define PA_TGTID_EN			BIT(11)
+#define PA_SRCID_EN			BIT(11)
+#define PA_TGTID_NONE			0
+#define PA_SRCID_NONE			0
+#define PA_TGTID_MASK_SHIFT		12
+#define PA_SRCID_MASK_SHIFT		12
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_cmd, config1, 10, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_msk, config1, 21, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
+
+static inline void hisi_pa_pmu_enable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(pa_pmu->base + PA_TT_CTRL);
+		val |= PA_TRACETAG_EN;
+		writel(val, pa_pmu->base + PA_TT_CTRL);
+	}
+}
+
+static inline void hisi_pa_pmu_clear_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(pa_pmu->base + PA_TT_CTRL);
+		val &= ~PA_TRACETAG_EN;
+		writel(val, pa_pmu->base + PA_TT_CTRL);
+	}
+}
+
+static inline void hisi_pa_pmu_config_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_tgtid_cmd(event);
+
+	if (cmd) {
+		u32 msk = hisi_get_tgtid_msk(event);
+		u32 val = cmd | PA_TGTID_EN | (msk << PA_TGTID_MASK_SHIFT);
+
+		writel(val, pa_pmu->base + PA_TGTID_CTRL);
+	}
+}
+
+static inline void hisi_pa_pmu_clear_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_tgtid_cmd(event);
+
+	if (cmd)
+		writel(PA_TGTID_NONE, pa_pmu->base + PA_TGTID_CTRL);
+}
+
+static inline void hisi_pa_pmu_config_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 msk = hisi_get_srcid_msk(event);
+		u32 val = cmd | PA_SRCID_EN | (msk << PA_SRCID_MASK_SHIFT);
+
+		writel(val, pa_pmu->base + PA_SRCID_CTRL);
+	}
+}
+
+static inline void hisi_pa_pmu_clear_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd)
+		writel(PA_SRCID_NONE, pa_pmu->base + PA_SRCID_CTRL);
+}
+
+static inline void hisi_pa_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_pa_pmu_enable_tracetag(event);
+		hisi_pa_pmu_config_srcid(event);
+		hisi_pa_pmu_config_tgtid(event);
+	}
+}
+
+static void hisi_pa_pmu_disable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_pa_pmu_clear_tgtid(event);
+		hisi_pa_pmu_clear_srcid(event);
+		hisi_pa_pmu_clear_tracetag(event);
+	}
+}
+
+static u32 hisi_pa_pmu_get_counter_offset(int idx)
+{
+	return (PA_EVENT_CNT0_L + idx * 8);
+}
+
+static u64 hisi_pa_pmu_read_counter(struct hisi_pmu *pa_pmu,
+				    struct hw_perf_event *hwc)
+{
+	return readq(pa_pmu->base + hisi_pa_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_pa_pmu_write_counter(struct hisi_pmu *pa_pmu,
+				      struct hw_perf_event *hwc, u64 val)
+{
+	writeq(val, pa_pmu->base + hisi_pa_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_pa_pmu_write_evtype(struct hisi_pmu *pa_pmu, int idx,
+				     u32 type)
+{
+	u32 reg, reg_idx, shift, val;
+
+	/*
+	 * Select the appropriate event select register(PA_EVENT_TYPE0/1).
+	 * There are 2 event select registers for the 8 hardware counters.
+	 * Event code is 8-bits and for the former 4 hardware counters,
+	 * PA_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
+	 * PA_EVENT_TYPE1 is chosen.
+	 */
+	reg = PA_EVENT_TYPE0 + rounddown(idx, 4);
+	reg_idx = idx % 4;
+	shift = 8 * reg_idx;
+
+	/* Write event code to pa_EVENT_TYPEx Register */
+	val = readl(pa_pmu->base + reg);
+	val &= ~(PA_EVTYPE_MASK << shift);
+	val |= (type << shift);
+	writel(val, pa_pmu->base + reg);
+}
+
+static void hisi_pa_pmu_start_counters(struct hisi_pmu *pa_pmu)
+{
+	u32 val;
+
+	val = readl(pa_pmu->base + PA_PERF_CTRL);
+	val |= PA_PERF_CTRL_EN;
+	writel(val, pa_pmu->base + PA_PERF_CTRL);
+}
+
+static void hisi_pa_pmu_stop_counters(struct hisi_pmu *pa_pmu)
+{
+	u32 val;
+
+	val = readl(pa_pmu->base + PA_PERF_CTRL);
+	val &= ~(PA_PERF_CTRL_EN);
+	writel(val, pa_pmu->base + PA_PERF_CTRL);
+}
+
+static void hisi_pa_pmu_enable_counter(struct hisi_pmu *pa_pmu,
+				       struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Enable counter index in PA_EVENT_CTRL register */
+	val = readl(pa_pmu->base + PA_EVENT_CTRL);
+	val |= 1 << hwc->idx;
+	writel(val, pa_pmu->base + PA_EVENT_CTRL);
+}
+
+static void hisi_pa_pmu_disable_counter(struct hisi_pmu *pa_pmu,
+					struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Clear counter index in PA_EVENT_CTRL register */
+	val = readl(pa_pmu->base + PA_EVENT_CTRL);
+	val &= ~(1 << hwc->idx);
+	writel(val, pa_pmu->base + PA_EVENT_CTRL);
+}
+
+static void hisi_pa_pmu_enable_counter_int(struct hisi_pmu *pa_pmu,
+					   struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Write 0 to enable interrupt */
+	val = readl(pa_pmu->base + PA_INT_MASK);
+	val &= ~(1 << hwc->idx);
+	writel(val, pa_pmu->base + PA_INT_MASK);
+}
+
+static void hisi_pa_pmu_disable_counter_int(struct hisi_pmu *pa_pmu,
+					    struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Write 1 to mask interrupt */
+	val = readl(pa_pmu->base + PA_INT_MASK);
+	val |= 1 << hwc->idx;
+	writel(val, pa_pmu->base + PA_INT_MASK);
+}
+
+static u32 hisi_pa_pmu_get_int_status(struct hisi_pmu *pa_pmu)
+{
+	return readl(pa_pmu->base + PA_INT_STATUS);
+}
+
+static void hisi_pa_pmu_clear_int_status(struct hisi_pmu *pa_pmu, int idx)
+{
+	writel(1 << idx, pa_pmu->base + PA_INT_CLEAR);
+}
+
+static const struct acpi_device_id hisi_pa_pmu_acpi_match[] = {
+	{ "HISI0273", },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, hisi_pa_pmu_acpi_match);
+
+static int hisi_pa_pmu_init_data(struct platform_device *pdev,
+				   struct hisi_pmu *pa_pmu)
+{
+	/*
+	 * Use the SCCL_ID and the index ID to identify the PA PMU,
+	 * while SCCL_ID is the nearst SCCL_ID from this SICL.
+	 */
+	if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
+				     &pa_pmu->sccl_id)) {
+		dev_err(&pdev->dev, "Cannot read sccl-id!\n");
+		return -EINVAL;
+	}
+
+	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
+				     &pa_pmu->index_id)) {
+		dev_err(&pdev->dev, "Cannot read idx-id!\n");
+		return -EINVAL;
+	}
+
+	pa_pmu->ccl_id = -1;
+
+	pa_pmu->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pa_pmu->base)) {
+		dev_err(&pdev->dev, "ioremap failed for pa_pmu resource.\n");
+		return PTR_ERR(pa_pmu->base);
+	}
+
+	pa_pmu->identifier = readl(pa_pmu->base + PA_PMU_VERSION);
+
+	return 0;
+}
+
+static struct attribute *hisi_pa_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(tgtid_cmd, "config1:0-10"),
+	HISI_PMU_FORMAT_ATTR(tgtid_msk, "config1:11-21"),
+	HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"),
+	HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:33-43"),
+	HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"),
+	NULL,
+};
+
+static const struct attribute_group hisi_pa_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_pa_pmu_v2_format_attr,
+};
+
+static struct attribute *hisi_pa_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(rx_req,		0x40),
+	HISI_PMU_EVENT_ATTR(tx_req,             0x5c),
+	HISI_PMU_EVENT_ATTR(cycle,		0x78),
+	NULL
+};
+
+static const struct attribute_group hisi_pa_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_pa_pmu_v2_events_attr,
+};
+
+static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
+
+static struct attribute *hisi_pa_pmu_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL
+};
+
+static const struct attribute_group hisi_pa_pmu_cpumask_attr_group = {
+	.attrs = hisi_pa_pmu_cpumask_attrs,
+};
+
+static struct device_attribute hisi_pa_pmu_identifier_attr =
+	__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
+
+static struct attribute *hisi_pa_pmu_identifier_attrs[] = {
+	&hisi_pa_pmu_identifier_attr.attr,
+	NULL
+};
+
+static struct attribute_group hisi_pa_pmu_identifier_group = {
+	.attrs = hisi_pa_pmu_identifier_attrs,
+};
+
+static const struct attribute_group *hisi_pa_pmu_v2_attr_groups[] = {
+	&hisi_pa_pmu_v2_format_group,
+	&hisi_pa_pmu_v2_events_group,
+	&hisi_pa_pmu_cpumask_attr_group,
+	&hisi_pa_pmu_identifier_group,
+	NULL
+};
+
+static const struct hisi_uncore_ops hisi_uncore_pa_ops = {
+	.write_evtype		= hisi_pa_pmu_write_evtype,
+	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
+	.start_counters		= hisi_pa_pmu_start_counters,
+	.stop_counters		= hisi_pa_pmu_stop_counters,
+	.enable_counter		= hisi_pa_pmu_enable_counter,
+	.disable_counter	= hisi_pa_pmu_disable_counter,
+	.enable_counter_int	= hisi_pa_pmu_enable_counter_int,
+	.disable_counter_int	= hisi_pa_pmu_disable_counter_int,
+	.write_counter		= hisi_pa_pmu_write_counter,
+	.read_counter		= hisi_pa_pmu_read_counter,
+	.get_int_status		= hisi_pa_pmu_get_int_status,
+	.clear_int_status	= hisi_pa_pmu_clear_int_status,
+	.enable_filter		= hisi_pa_pmu_enable_filter,
+	.disable_filter		= hisi_pa_pmu_disable_filter,
+};
+
+static int hisi_pa_pmu_dev_probe(struct platform_device *pdev,
+				 struct hisi_pmu *pa_pmu)
+{
+	int ret;
+
+	ret = hisi_pa_pmu_init_data(pdev, pa_pmu);
+	if (ret)
+		return ret;
+
+	ret = hisi_uncore_pmu_init_irq(pa_pmu, pdev);
+	if (ret)
+		return ret;
+
+	pa_pmu->pmu_events.attr_groups = hisi_pa_pmu_v2_attr_groups;
+	pa_pmu->num_counters = PA_NR_COUNTERS;
+	pa_pmu->ops = &hisi_uncore_pa_ops;
+	pa_pmu->check_event = 0xB0;
+	pa_pmu->counter_bits = 64;
+	pa_pmu->dev = &pdev->dev;
+	pa_pmu->on_cpu = -1;
+
+	return 0;
+}
+
+static int hisi_pa_pmu_probe(struct platform_device *pdev)
+{
+	struct hisi_pmu *pa_pmu;
+	char *name;
+	int ret;
+
+	pa_pmu = devm_kzalloc(&pdev->dev, sizeof(*pa_pmu), GFP_KERNEL);
+	if (!pa_pmu)
+		return -ENOMEM;
+
+	ret = hisi_pa_pmu_dev_probe(pdev, pa_pmu);
+	if (ret)
+		return ret;
+	/*
+	 * PA is attached in SICL and the CPU core is chosen to manage this
+	 * PMU which is the nearest SCCL, while its SCCL_ID is greater than
+	 * one with the SICL_ID.
+	 */
+	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%u_pa%u",
+			      pa_pmu->sccl_id - 1, pa_pmu->index_id);
+	if (!name) {
+		dev_err(&pdev->dev, "failed to allocate name for PMU\n");
+		return -ENOMEM;
+	}
+
+	ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+				       &pa_pmu->node);
+	if (ret) {
+		dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
+		return ret;
+	}
+
+	pa_pmu->pmu = (struct pmu) {
+		.module		= THIS_MODULE,
+		.task_ctx_nr	= perf_invalid_context,
+		.event_init	= hisi_uncore_pmu_event_init,
+		.pmu_enable	= hisi_uncore_pmu_enable,
+		.pmu_disable	= hisi_uncore_pmu_disable,
+		.add		= hisi_uncore_pmu_add,
+		.del		= hisi_uncore_pmu_del,
+		.start		= hisi_uncore_pmu_start,
+		.stop		= hisi_uncore_pmu_stop,
+		.read		= hisi_uncore_pmu_read,
+		.attr_groups    = pa_pmu->pmu_events.attr_groups,
+		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
+	};
+
+	ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
+	if (ret) {
+		dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
+		cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+					    &pa_pmu->node);
+		irq_set_affinity_hint(pa_pmu->irq, NULL);
+	}
+
+	platform_set_drvdata(pdev, pa_pmu);
+	return ret;
+}
+
+static int hisi_pa_pmu_remove(struct platform_device *pdev)
+{
+	struct hisi_pmu *pa_pmu = platform_get_drvdata(pdev);
+
+	perf_pmu_unregister(&pa_pmu->pmu);
+	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+					    &pa_pmu->node);
+	irq_set_affinity_hint(pa_pmu->irq, NULL);
+
+	return 0;
+}
+
+static struct platform_driver hisi_pa_pmu_driver = {
+	.driver = {
+		.name = "hisi_pa_pmu",
+		.acpi_match_table = hisi_pa_pmu_acpi_match,
+	},
+	.probe = hisi_pa_pmu_probe,
+	.remove = hisi_pa_pmu_remove,
+};
+
+static int __init hisi_pa_pmu_module_init(void)
+{
+	int ret;
+
+	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+				      "AP_PERF_ARM_HISI_PA_ONLINE",
+				      hisi_uncore_pmu_online_cpu,
+				      hisi_uncore_pmu_offline_cpu);
+	if (ret) {
+		pr_err("PA PMU: cpuhp state setup failed, ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = platform_driver_register(&hisi_pa_pmu_driver);
+	if (ret)
+		cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
+
+	return ret;
+}
+module_init(hisi_pa_pmu_module_init);
+
+static void __exit hisi_pa_pmu_module_exit(void)
+{
+	platform_driver_unregister(&hisi_pa_pmu_driver);
+	cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
+}
+module_exit(hisi_pa_pmu_module_exit);
+
+MODULE_DESCRIPTION("HiSilicon PA uncore PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index b5e04f9b68f1..37f591ed80d0 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -174,6 +174,7 @@ enum cpuhp_state {
 	CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
+	CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
 	CPUHP_AP_PERF_ARM_L2X0_ONLINE,
 	CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (6 preceding siblings ...)
  2020-12-31  6:19 ` [PATCH 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
@ 2020-12-31  6:19 ` Shaokun Zhang
  2021-01-22  6:03 ` [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
  8 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2020-12-31  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

Some news functions are added on HiSilicon uncore PMUs. Document them
to provide guidance on how to use them.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 Documentation/admin-guide/perf/hisi-pmu.rst | 54 +++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst
index 404a5c3d9d00..47aadbcda301 100644
--- a/Documentation/admin-guide/perf/hisi-pmu.rst
+++ b/Documentation/admin-guide/perf/hisi-pmu.rst
@@ -53,6 +53,60 @@ Example usage of perf::
   $# perf stat -a -e hisi_sccl3_l3c0/rd_hit_cpipe/ sleep 5
   $# perf stat -a -e hisi_sccl3_l3c0/config=0x02/ sleep 5
 
+For HiSilicon uncore PMU v2 whose identifier is 0x30, the topology is the same
+as PMU v1, but some new functions are added to the hardware.
+
+(a) L3C PMU supports filtering by core/thread within the cluster which can be
+specified as a bitmap.
+  $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0x3/ sleep 5
+This will only count the operations from core/thread 0 and 1 in this cluster.
+
+(b) Tracetag allow the user to chose to count only read, write or atomic
+operations via the tt_req parameeter in perf. The default value counts all
+operations. tt_req is 3bits, 3'b100 represents read operations, 3'b101
+represents write operations, 3'b110 represents atomic store operations and
+3'b111 represents atomic non-store operations, other values are reserved.
+  $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5
+This will only count the read operations in this cluster.
+
+(c) Datasrc allows the user to check where the data comes from. It is 5 bits.
+Some important codes are as follows:
+5'b00001: comes from L3C in this die;
+5'b01000: comes from L3C in the cross-die;
+5'b01001: comes from L3C which is in another socket;
+5'b01110: comes from the local DDR;
+5'b01111: comes from the cross-die DDR;
+5'b10000: comes from cross-socket DDR;
+etc, it is mainly helpful to find that the data source is nearest from the CPU
+cores. If datasrc is used in the multi-chips, the ds_skt shall be configured in
+perf command.
+  $# perf stat -a -e hisi_sccl3_l3c0/config=0xb9,ds_cfg=0xE/,
+  hisi_sccl3_l3c0/config=0xb9,ds_cfg=0xF/ sleep 5
+
+(d)Some HiSilicon SoCs encapsulate multiple CPU and IO dies.  Each CPU die contains
+many Compute Clusters (CCLs). The I/O dies are called Super I/O clusters (SICL)
+containing multiple I/O clusters (ICLs).   Each CCL/ICL in the SoC has a
+unique master-ID.  The uncore PMU can filter by specified master-ID or
+combination of master-IDs.  The master-ID is 14bits of which the lower 3-bits
+specify the individual core within a CCL. The upper 11 bits include a
+6-bit SCCL-ID and 5-bit CCL/ICL-ID.
+The user may filter by a specific CCL/ICL through the mstid_cmd and mstid_msk
+parameters. A set bit in mstid_mask means the PMU will not check the bit when
+matching against the mstid_cmd.
+
+(e) For new uncore PMU, SLLC and PA, normal PMU events are supported and other
+new functions are also added simultaneously, such as, tgt_id and src_id can
+be determined by the requirements which are also 11-bits including SCCL-ID and
+CCL/ICL-ID. For I/O die, the ICL-ID is followed by:
+5'b00000: I/O_MGMT_ICL;
+5'b00001: Network_ICL;
+5'b00011: HAC_ICL;
+5'b10000: PCIe_ICL;
+
+If all of these options are disabled, it can works by the default value that
+doesn't distinguish the filter condition and ID information and will return
+the total counter values in the PMU counters.
+
 The current driver does not support sampling. So "perf record" is unsupported.
 Also attach to a task is unsupported as the events are all uncore.
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver
  2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (7 preceding siblings ...)
  2020-12-31  6:19 ` [PATCH 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2 Shaokun Zhang
@ 2021-01-22  6:03 ` Shaokun Zhang
  2021-02-02 18:48   ` Will Deacon
  8 siblings, 1 reply; 24+ messages in thread
From: Shaokun Zhang @ 2021-01-22  6:03 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Will Deacon, Jonathan Cameron

Hi all,

A gentle ping.

Thanks,
Shaokun

在 2020/12/31 14:19, Shaokun Zhang 写道:
> This patchset adds support for HiSilicon Hip09 SoC uncore PMUs driver
> which is PMU v2 and it includes:
> (a) Refactor interrupt registration and handler function for later
> new uncore PMU driver in patch1;
> (b) Update the PMU version suffiex for existing driver in patch2
> (b) Some new functions are added on L3C/HHA PMU in patch3/4;
> (c) New DDRC PMU model is supported using programable counter and
> supports more events in patch5;
> (d) Add new modules SLLC and PA PMU drivers in patch6/7;
> (e) Update the perf document for the new functions and modules in
> patch8;
> 
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: John Garry <john.garry@huawei.com>
> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Cc: Qi Liu <liuqi115@huawei.com>
> 
> Shaokun Zhang (8):
>   drivers/perf: hisi: Refactor code for more uncore PMUs
>   drivers/perf: hisi: Add PMU version for uncore PMU drivers.
>   drivers/perf: hisi: Add new functions for L3C PMU
>   drivers/perf: hisi: Add new functions for HHA PMU
>   drivers/perf: hisi: Update DDRC PMU for programable counter
>   drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
>   drivers/perf: hisi: Add support for HiSilicon PA PMU driver
>   docs: perf: Add new description on HiSilicon uncore PMU v2
> 
>  Documentation/admin-guide/perf/hisi-pmu.rst   |  54 +++
>  drivers/perf/hisilicon/Makefile               |   3 +-
>  drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 346 +++++++++++------
>  drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 301 ++++++++++-----
>  drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 353 ++++++++++++-----
>  drivers/perf/hisilicon/hisi_uncore_pa_pmu.c   | 498 ++++++++++++++++++++++++
>  drivers/perf/hisilicon/hisi_uncore_pmu.c      |  76 +++-
>  drivers/perf/hisilicon/hisi_uncore_pmu.h      |  19 +-
>  drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 530 ++++++++++++++++++++++++++
>  include/linux/cpuhotplug.h                    |   2 +
>  10 files changed, 1878 insertions(+), 304 deletions(-)
>  create mode 100644 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
>  create mode 100644 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  2020-12-31  6:19 ` [PATCH 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
@ 2021-01-26 11:46   ` John Garry
  2021-01-27  7:56     ` Shaokun Zhang
  0 siblings, 1 reply; 24+ messages in thread
From: John Garry @ 2021-01-26 11:46 UTC (permalink / raw)
  To: Shaokun Zhang, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

On 31/12/2020 06:19, Shaokun Zhang wrote:

nit: the subject is a little ambiguous. Maybe could have "Add v1 hw PMU 
symbol versioning for uncore PMU drivers"

> For HiSilicon uncore PMU, more versions are supported and some variables
> shall be added suffiex to distinguish the version which are prepared for

suffix

> the new drivers.
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: John Garry <john.garry@huawei.com>
> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Co-developed-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>

Apart from some small issues:
Reviewed-by: John Garry <john.garry@huawei.com>

> ---
>   drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 95 ++++++++++++++-------------
>   drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 27 ++++----
>   drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 24 +++----
>   3 files changed, 74 insertions(+), 72 deletions(-)
> 
> diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> index 69ccbe02f1e3..7f940c47b833 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> @@ -36,8 +36,8 @@
>   
>   /* DDRC has 8-counters */
>   #define DDRC_NR_COUNTERS	0x8
> -#define DDRC_PERF_CTRL_EN	0x2
> -
> +#define DDRC_V1_PERF_CTRL_EN	0x2
> +#define DDRC_V1_NR_EVENTS	0x07
>   /*
>    * For DDRC PMU, there are eight-events and every event has been mapped
>    * to fixed-purpose counters which register offset is not consistent.
> @@ -53,26 +53,26 @@ static const u32 ddrc_reg_off[] = {
>   
>   /*
>    * Select the counter register offset using the counter index.
> - * In DDRC there are no programmable counter, the count
> + * In PMU v1, there are no programmable counter, the count
>    * is readed form the statistics counter register itself.

comment on existing code:

/s/is readed form/is read from/

>    */
> -static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
> +static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
>   {
>   	return ddrc_reg_off[cntr_idx];
>   }
>   

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 3/8] drivers/perf: hisi: Add new functions for L3C PMU
  2020-12-31  6:19 ` [PATCH 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
@ 2021-01-26 12:05   ` John Garry
  0 siblings, 0 replies; 24+ messages in thread
From: John Garry @ 2021-01-26 12:05 UTC (permalink / raw)
  To: Shaokun Zhang, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

On 31/12/2020 06:19, Shaokun Zhang wrote:
> On HiSilicon Hip09 platform, some new functions are enhanced on L3C PMU,
> like, tracetag feature that L3C PMU can only count the specified
> operations by the user, or L3C PMU can give the desired core's statistics
> in the cluster.
> $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0xf/ sleep 5
> 
> $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5
> 
> Cc: Mark Rutland<mark.rutland@arm.com>
> Cc: Will Deacon<will@kernel.org>
> Cc: John Garry<john.garry@huawei.com>
> Cc: Jonathan Cameron<Jonathan.Cameron@huawei.com>
> Co-developed-by: Qi Liu<liuqi115@huawei.com>
> Signed-off-by: Qi Liu<liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang<zhangshaokun@hisilicon.com>

Reviewed-by: John Garry <john.garry@huawei.com>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 4/8] drivers/perf: hisi: Add new functions for HHA PMU
  2020-12-31  6:19 ` [PATCH 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
@ 2021-01-26 12:10   ` John Garry
  2021-01-27  8:02     ` Shaokun Zhang
  0 siblings, 1 reply; 24+ messages in thread
From: John Garry @ 2021-01-26 12:10 UTC (permalink / raw)
  To: Shaokun Zhang, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

On 31/12/2020 06:19, Shaokun Zhang wrote:
> On HiSilicon Hip09 platform, some new functions are also supported on
> HHA PMU, it can filter gathered statistics by the Master ID and mask
> from the SoC if the user wants to do deep-going profiling.
> Tracetag support is also added with L3C PMU in the SoC system.
> 
> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,tracetag_en=0x1/ sleep 5
> 
> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,srcid_cmd=0x1/ sleep 5
> Much more introduction is added in documentation:



> Documentation/admin-guide/perf/hisi-pmu.rst

I think that it would make sense to add that prior to the driver change, 
like how we do with dt bindings, but not so important

> 
> Cc: Mark Rutland<mark.rutland@arm.com>
> Cc: Will Deacon<will@kernel.org>
> Cc: John Garry<john.garry@huawei.com>
> Cc: Jonathan Cameron<Jonathan.Cameron@huawei.com>
> Co-developed-by: Qi Liu<liuqi115@huawei.com>
> Signed-off-by: Qi Liu<liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang<zhangshaokun@hisilicon.com>

Reviewed-by: John Garry <john.garry@huawei.com>

I suppose the change in hisi_hha_pmu_init_data() is ok (not shown).

> ---
>   drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 203 +++++++++++++++++++++++++--
>   1 file changed, 188 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> index 2f55e5864d39..5e1c4b61ffce 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> @@ -25,19 +25,136 @@
>   #define HHA_VERSION		0x1cf0
>   #define HHA_PERF_CTRL		0x1E00
>   #define HHA_EVENT_CTRL		0x1E04
> +#define HHA_SRCID_CTRL		0x1E08
> +#define HHA_DATSRC_CTRL		0x1BF0
>   #define HHA_EVENT_TYPE0		0x1E80
>   /*
> - * Each counter is 48-bits and [48:63] are reserved
> - * which are Read-As-Zero and Writes-Ignored.
> + * If the HW version only supports a 48-bit counter, then
> + * bits [63:48] are reserved, which are Read-As-Zero and
> + * Writes-Ignored.
>    */
>   #define HHA_CNT0_LOWER		0x1F00
>   
> -/* HHA has 16-counters */
> +/* HHA PMU v1 has 16-counter and v2 only has 8-counter */

nit: "has 16 counters and v2 has only 8 counters */

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2020-12-31  6:19 ` [PATCH 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
@ 2021-01-26 12:30   ` John Garry
  2021-01-27  8:26     ` Shaokun Zhang
  0 siblings, 1 reply; 24+ messages in thread
From: John Garry @ 2021-01-26 12:30 UTC (permalink / raw)
  To: Shaokun Zhang, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

On 31/12/2020 06:19, Shaokun Zhang wrote:
> HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
> module (Skyros Link Layer Controller), its has separate PMU registers which
> the driver can program it freely and interrupt is supported to handle
> counter overflow. Let's support its driver under the framework of HiSilicon
> uncore PMU driver.
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: John Garry <john.garry@huawei.com>
> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Co-developed-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>

layout looks consistent with other hisi uncore PMU drivers, but some 
small comments, below

Reviewed-by: John Garry <john.garry@huawei.com>

> ---
>   drivers/perf/hisilicon/Makefile               |   2 +-
>   drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 530 ++++++++++++++++++++++++++
>   include/linux/cpuhotplug.h                    |   1 +
>   3 files changed, 532 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
> 
> diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
> index e8377061845f..6600a9d45dd8 100644
> --- a/drivers/perf/hisilicon/Makefile
> +++ b/drivers/perf/hisilicon/Makefile
> @@ -1,3 +1,3 @@
>   # SPDX-License-Identifier: GPL-2.0-only
>   obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
> -			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o
> +			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
> diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
> new file mode 100644
> index 000000000000..6911c388a5ac
> --- /dev/null
> +++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
> @@ -0,0 +1,530 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * HiSilicon SLLC uncore Hardware event counters support
> + *
> + * Copyright (C) 2020 Hisilicon Limited
> + * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
> + *
> + * This code is based on the uncore PMUs like arm-cci and arm-ccn.
> + */
> +#include <linux/acpi.h>
> +#include <linux/cpuhotplug.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/list.h>
> +#include <linux/smp.h>
> +
> +#include "hisi_uncore_pmu.h"
> +
> +/* SLLC register definition */
> +#define SLLC_INT_MASK			0x0814
> +#define SLLC_INT_STATUS			0x0818
> +#define SLLC_INT_CLEAR			0x081C
> +#define SLLC_PERF_CTRL			0x1C00
> +#define SLLC_SRCID_CTRL			0x1C04
> +#define SLLC_TGTID_CTRL			0x1C08
> +#define SLLC_EVENT_CTRL			0x1C14
> +#define SLLC_EVENT_TYPE0		0x1C18
> +#define SLLC_VERSION			0x1CF0
> +#define SLLC_EVENT_CNT0_L		0x1D00
> +
> +#define SLLC_EVTYPE_MASK		0xFF
> +#define SLLC_PERF_CTRL_EN		BIT(0)
> +#define SLLC_FILT_EN			BIT(1)
> +#define SLLC_TRACETAG_EN		BIT(2)
> +#define SLLC_SRCID_EN			BIT(4)
> +#define SLLC_SRCID_NONE			0x0
> +#define SLLC_TGTID_EN			BIT(5)
> +#define SLLC_TGTID_NONE			0x0
> +#define SLLC_TGTID_LO_SHIFT		1
> +#define SLLC_TGTID_HI_SHIFT		12
> +#define SLLC_SRCID_CMD_SHIFT		1
> +#define SLLC_SRCID_MSK_SHIFT		12
> +#define SLLC_NR_EVENTS			0x80
> +
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
> +
> +static inline bool tgtid_is_valid(u32 hi, u32 lo)

nit: no need for inline

> +{
> +	return lo > 0 && hi >= lo;
> +}
> +
> +static inline void hisi_sllc_pmu_enable_tracetag(struct perf_event *event)
> +{
> +	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
> +	u32 tt_en = hisi_get_tracetag_en(event);
> +
> +	if (tt_en) {
> +		u32 val;
> +
> +		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
> +		val |= SLLC_TRACETAG_EN | SLLC_FILT_EN;
> +		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
> +	}
> +}
> +
> +static inline void hisi_sllc_pmu_disable_tracetag(struct perf_event *event)
> +{
> +	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
> +	u32 tt_en = hisi_get_tracetag_en(event);
> +
> +	if (tt_en) {
> +		u32 val;
> +
> +		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
> +		val &= ~(SLLC_TRACETAG_EN | SLLC_FILT_EN);
> +		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);

note: i think that all these can be _relaxed variant, but that is for 
existing drivers as well, so can be reviewed later

> +	}
> +}
> +
> +static inline void hisi_sllc_pmu_config_tgtid(struct perf_event *event)
> +{
> +	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
> +	u32 lo = hisi_get_tgtid_lo(event);
> +	u32 hi = hisi_get_tgtid_hi(event);
> +
> +	if (tgtid_is_valid(hi, lo)) {
> +		u32 val = (hi << SLLC_TGTID_HI_SHIFT) | (lo << SLLC_TGTID_LO_SHIFT);
> +
> +		writel(val, sllc_pmu->base + SLLC_TGTID_CTRL);
> +
> +		/* Enable the tgtid */
> +		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
> +		val |= SLLC_TGTID_EN | SLLC_FILT_EN;
> +		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
> +	}
> +}
> +	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_sllc%u",
> +			      sllc_pmu->sccl_id, sllc_pmu->index_id);
> +	if (!name) {
> +		dev_err(&pdev->dev, "failed to allocate name for PMU\n");

maybe this message is not so useful

> +		return -ENOMEM;
> +	}
> +
> +	ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> +				       &sllc_pmu->node);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
> +		return ret;
> +	}
> +
> +	sllc_pmu->pmu = (struct pmu) {
> +		.module		= THIS_MODULE,
> +		.task_ctx_nr	= perf_invalid_context,
> +		.event_init	= hisi_uncore_pmu_event_init,
> +		.pmu_enable	= hisi_uncore_pmu_enable,
> +		.pmu_disable	= hisi_uncore_pmu_disable,
> +		.add		= hisi_uncore_pmu_add,
> +		.del		= hisi_uncore_pmu_del,
> +		.start		= hisi_uncore_pmu_start,
> +		.stop		= hisi_uncore_pmu_stop,
> +		.read		= hisi_uncore_pmu_read,
> +		.attr_groups    = sllc_pmu->pmu_events.attr_groups,
> +		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
> +	};
> +
> +	ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
> +	if (ret) {
> +		dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
> +		cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> +					    &sllc_pmu->node);
> +		irq_set_affinity_hint(sllc_pmu->irq, NULL);
> +	}
> +
> +	platform_set_drvdata(pdev, sllc_pmu);

strange that we still do this for an error

> +
> +	return ret;
> +}
> +
> +static int hisi_sllc_pmu_remove(struct platform_device *pdev)
> +{
> +	struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev);
> +
> +	perf_pmu_unregister(&sllc_pmu->pmu);
> +	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> +					    &sllc_pmu->node);
> +	irq_set_affinity_hint(sllc_pmu->irq, NULL);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver hisi_sllc_pmu_driver = {
> +	.driver = {
> +		.name = "hisi_sllc_pmu",
> +		.acpi_match_table = hisi_sllc_pmu_acpi_match,

please set unbind unsupported

> +	},
> +	.probe = hisi_sllc_pmu_probe,
> +	.remove = hisi_sllc_pmu_remove,
> +};
> +
> +static int __init hisi_sllc_pmu_module_init(void)
> +{
> +	int ret;
> +
> +	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> +				      "AP_PERF_ARM_HISI_SLLC_ONLINE",
> +				      hisi_uncore_pmu_online_cpu,
> +				      hisi_uncore_pmu_offline_cpu);
> +	if (ret) {
> +		pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = platform_driver_register(&hisi_sllc_pmu_driver);
> +	if (ret)
> +		cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
> +
> +	return ret;
> +}
> +module_init(hisi_sllc_pmu_module_init);
> +
> +static void __exit hisi_sllc_pmu_module_exit(void)
> +{
> +	platform_driver_unregister(&hisi_sllc_pmu_driver);
> +	cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
> +}
> +module_exit(hisi_sllc_pmu_module_exit);
> +
> +MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> index 0042ef362511..b5e04f9b68f1 100644
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -174,6 +174,7 @@ enum cpuhp_state {
>   	CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
>   	CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
>   	CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
> +	CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>   	CPUHP_AP_PERF_ARM_L2X0_ONLINE,
>   	CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
>   	CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter
  2020-12-31  6:19 ` [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
@ 2021-01-26 12:33   ` John Garry
  2021-01-26 15:56     ` John Garry
  0 siblings, 1 reply; 24+ messages in thread
From: John Garry @ 2021-01-26 12:33 UTC (permalink / raw)
  To: Shaokun Zhang, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

On 31/12/2020 06:19, Shaokun Zhang wrote:
> DDRC PMU's events are useful for performance profiling, but the events
> are limited and counter is fixed. On HiSilicon Hip09 platform, PMU
> counters are the programable and more events are supported. Let's

programmable

> add the DDRC PMU v2 driver.
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: John Garry <john.garry@huawei.com>
> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Co-developed-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
> ---
>   drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 208 ++++++++++++++++++++++++--
>   drivers/perf/hisilicon/hisi_uncore_pmu.h      |   2 +
>   2 files changed, 197 insertions(+), 13 deletions(-)
> 

generally looks ok, but ...

>   }
> @@ -332,8 +506,16 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
>   		return ret;
>   	}
>   
> -	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_ddrc%u",
> -			      ddrc_pmu->sccl_id, ddrc_pmu->index_id);
> +	if (ddrc_pmu->identifier >= HISI_PMU_V2)
> +		name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +				      "hisi_sccl%u_ddrc%u_%u",
> +				      ddrc_pmu->sccl_id, ddrc_pmu->index_id,
> +				      ddrc_pmu->sub_id);

I don't think perf can support event aliasing in this format 
(hisi_scclX_Y_Z), but I need to double-check.

> +	else
> +		name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +				      "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
> +				      ddrc_pmu->index_id);
> +
>   	ddrc_pmu->pmu = (struct pmu) {
>   		.name		= name,
>   		.module		= THIS_MODULE,
> @@ -346,7 +528,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
>   		.start		= hisi_uncore_pmu_start,
>   		.stop		= hisi_uncore_pmu_stop,
>   		.read		= hisi_uncore_pmu_read,
> -		.attr_groups	= hisi_ddrc_pmu_v1_attr_groups,
> +		.attr_groups	= ddrc_pmu->pmu_events.attr_groups,
>   		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
>   	};
>   

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 7/8] drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  2020-12-31  6:19 ` [PATCH 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
@ 2021-01-26 12:45   ` John Garry
  2021-01-27  8:41     ` Shaokun Zhang
  0 siblings, 1 reply; 24+ messages in thread
From: John Garry @ 2021-01-26 12:45 UTC (permalink / raw)
  To: Shaokun Zhang, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

On 31/12/2020 06:19, Shaokun Zhang wrote:
> On HiSilicon Hip09 platform, there is a PA (Protocol Adapter) module on
> each chip SICL (Super I/O Cluster) which incorporates three Hydra interface
> and facilitates the cache coherency between the dies on the chip. While PA
> uncore PMU model is the same as other Hip09 PMU modules and many PMU events
> are supported. Let's support the PMU driver using the HiSilicon uncore PMU
> framework.
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: John Garry <john.garry@huawei.com>
> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Co-developed-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>

nit: please stop using inline when not needed

Apart from minor comments, below:
Reviewed-by: John Garry <john.garry@huawei.com>

note: we do internal review, but tags not given - maybe we should in 
future...

> ---
>   drivers/perf/hisilicon/Makefile             |   3 +-
>   drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 498 ++++++++++++++++++++++++++++
>   include/linux/cpuhotplug.h                  |   1 +
>   3 files changed, 501 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
> 
> diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
> index 6600a9d45dd8..7643c9f93e36 100644
> --- a/drivers/perf/hisilicon/Makefile
> +++ b/drivers/perf/hisilicon/Makefile
> @@ -1,3 +1,4 @@
>   # SPDX-License-Identifier: GPL-2.0-only
>   obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
> -			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
> +			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o \
> +			  hisi_uncore_pa_pmu.o
> diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
> new file mode 100644
> index 000000000000..eec12f5daf71
> --- /dev/null
> +++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
> @@ -0,0 +1,498 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * HiSilicon PA uncore Hardware event counters support
> + *
> + * Copyright (C) 2020 HiSilicon Limited
> + * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
> + *
> + * This code is based on the uncore PMUs like arm-cci and arm-ccn.
> + */
> +#include <linux/acpi.h>
> +#include <linux/cpuhotplug.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/list.h>
> +#include <linux/smp.h>
> +
> +#include "hisi_uncore_pmu.h"
> +
> +/* PA register definition */
> +#define PA_PERF_CTRL			0x1C00

nit: generally lower case used for hex, but not so important

> +#define PA_EVENT_CTRL			0x1C04
> +#define PA_TT_CTRL			0x1C08
> +#define PA_TGTID_CTRL			0x1C14
> +#define PA_SRCID_CTRL			0x1C18
> +#define PA_INT_MASK			0x1C70
> +#define PA_INT_STATUS			0x1C78
> +#define PA_INT_CLEAR			0x1C7C
> +#define PA_EVENT_TYPE0			0x1C80
> +#define PA_PMU_VERSION			0x1CF0
> +#define PA_EVENT_CNT0_L			0x1D00
> +

...

> +
> +static int hisi_pa_pmu_init_data(struct platform_device *pdev,
> +				   struct hisi_pmu *pa_pmu)
> +{
> +	/*
> +	 * Use the SCCL_ID and the index ID to identify the PA PMU,
> +	 * while SCCL_ID is the nearst SCCL_ID from this SICL.
> +	 */
> +	if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
> +				     &pa_pmu->sccl_id)) {

hmmm... I do wonder if we should make it clearer in the driver that this 
is the SICL. I know I mentioned this before--sorry

> +		dev_err(&pdev->dev, "Cannot read sccl-id!\n");
> +		return -EINVAL;
> +	}
> +
> +	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
> +				     &pa_pmu->index_id)) {
> +		dev_err(&pdev->dev, "Cannot read idx-id!\n");
> +		return -EINVAL;
> +	}
> +
> +	pa_pmu->ccl_id = -1;
> +
> +	pa_pmu->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(pa_pmu->base)) {
> +		dev_err(&pdev->dev, "ioremap failed for pa_pmu resource.\n");
> +		return PTR_ERR(pa_pmu->base);
> +	}
> +
> +	pa_pmu->identifier = readl(pa_pmu->base + PA_PMU_VERSION);
> +
> +	return 0;
> +}
> +

...

> +static int hisi_pa_pmu_probe(struct platform_device *pdev)
> +{
> +	struct hisi_pmu *pa_pmu;
> +	char *name;
> +	int ret;
> +
> +	pa_pmu = devm_kzalloc(&pdev->dev, sizeof(*pa_pmu), GFP_KERNEL);
> +	if (!pa_pmu)
> +		return -ENOMEM;
> +
> +	ret = hisi_pa_pmu_dev_probe(pdev, pa_pmu);
> +	if (ret)
> +		return ret;
> +	/*
> +	 * PA is attached in SICL and the CPU core is chosen to manage this
> +	 * PMU which is the nearest SCCL,

do we really need to do this? Can any CPU in that chip do it?

> while its SCCL_ID is greater than
> +	 * one with the SICL_ID.
> +	 */
> +	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%u_pa%u",
> +			      pa_pmu->sccl_id - 1, pa_pmu->index_id);
> +	if (!name) {
> +		dev_err(&pdev->dev, "failed to allocate name for PMU\n");
> +		return -ENOMEM;
> +	}
> +
> +	ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> +				       &pa_pmu->node);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
> +		return ret;
> +	}
> +
> +	pa_pmu->pmu = (struct pmu) {
> +		.module		= THIS_MODULE,
> +		.task_ctx_nr	= perf_invalid_context,
> +		.event_init	= hisi_uncore_pmu_event_init,
> +		.pmu_enable	= hisi_uncore_pmu_enable,
> +		.pmu_disable	= hisi_uncore_pmu_disable,
> +		.add		= hisi_uncore_pmu_add,
> +		.del		= hisi_uncore_pmu_del,
> +		.start		= hisi_uncore_pmu_start,
> +		.stop		= hisi_uncore_pmu_stop,
> +		.read		= hisi_uncore_pmu_read,
> +		.attr_groups    = pa_pmu->pmu_events.attr_groups,
> +		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
> +	};
> +
> +	ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
> +	if (ret) {
> +		dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
> +		cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> +					    &pa_pmu->node);
> +		irq_set_affinity_hint(pa_pmu->irq, NULL);
> +	}
> +
> +	platform_set_drvdata(pdev, pa_pmu);

as before

> +	return ret;
> +}
> +
> +static int hisi_pa_pmu_remove(struct platform_device *pdev)
> +{
> +	struct hisi_pmu *pa_pmu = platform_get_drvdata(pdev);
> +
> +	perf_pmu_unregister(&pa_pmu->pmu);
> +	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> +					    &pa_pmu->node);
> +	irq_set_affinity_hint(pa_pmu->irq, NULL);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver hisi_pa_pmu_driver = {
> +	.driver = {
> +		.name = "hisi_pa_pmu",
> +		.acpi_match_table = hisi_pa_pmu_acpi_match,

some small comments on earlier patch reviews apply here

> +	},
> +	.probe = hisi_pa_pmu_probe,
> +	.remove = hisi_pa_pmu_remove,
> +};
> +
> +static int __init hisi_pa_pmu_module_init(void)
> +{
> +	int ret;
> +
> +	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> +				      "AP_PERF_ARM_HISI_PA_ONLINE",
> +				      hisi_uncore_pmu_online_cpu,
> +				      hisi_uncore_pmu_offline_cpu);
> +	if (ret) {
> +		pr_err("PA PMU: cpuhp state setup failed, ret = %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = platform_driver_register(&hisi_pa_pmu_driver);
> +	if (ret)
> +		cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
> +
> +	return ret;
> +}
> +module_init(hisi_pa_pmu_module_init);
> +
> +static void __exit hisi_pa_pmu_module_exit(void)
> +{
> +	platform_driver_unregister(&hisi_pa_pmu_driver);
> +	cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
> +}
> +module_exit(hisi_pa_pmu_module_exit);
> +
> +MODULE_DESCRIPTION("HiSilicon PA uncore PMU driver");

nit maybe have "PA (Protocol Adapter)"

> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> index b5e04f9b68f1..37f591ed80d0 100644
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -174,6 +174,7 @@ enum cpuhp_state {
>   	CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
>   	CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
>   	CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
> +	CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
>   	CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>   	CPUHP_AP_PERF_ARM_L2X0_ONLINE,
>   	CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter
  2021-01-26 12:33   ` John Garry
@ 2021-01-26 15:56     ` John Garry
  2021-01-27  8:16       ` Shaokun Zhang
  0 siblings, 1 reply; 24+ messages in thread
From: John Garry @ 2021-01-26 15:56 UTC (permalink / raw)
  To: Shaokun Zhang, linux-arm-kernel
  Cc: Mark Rutland, Will Deacon, Qi Liu, Jonathan Cameron

On 26/01/2021 12:33, John Garry wrote:
>>   }
>> @@ -332,8 +506,16 @@ static int hisi_ddrc_pmu_probe(struct 
>> platform_device *pdev)
>>           return ret;
>>       }
>> -    name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_ddrc%u",
>> -                  ddrc_pmu->sccl_id, ddrc_pmu->index_id);
>> +    if (ddrc_pmu->identifier >= HISI_PMU_V2)
>> +        name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
>> +                      "hisi_sccl%u_ddrc%u_%u",
>> +                      ddrc_pmu->sccl_id, ddrc_pmu->index_id,
>> +                      ddrc_pmu->sub_id);

I think that this is actually ok for perf.

Checking pmu_uncore_alias_match():

bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
{
	char *tmp = NULL, *tok, *str;
	bool res;

...

	for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) {
		name = strstr(name, tok);
		if (!name) {
			res = false;
			goto out;
		}
	}

	...
}

We match each token in @pmu_name, "hisi_sccl,ddrc". So we would match 
"hisi_sccl%u_" part with "hisi_sccl" token and then match "ddrc%u_%u" 
with "ddrc" token.

But it would be good to triple check. We need the JSON files created at 
some stage anyway :)

> 
> I don't think perf can support event aliasing in this format 
> (hisi_scclX_Y_Z), but I need to double-check.
> 
>> +    else
>> +        name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  2021-01-26 11:46   ` John Garry
@ 2021-01-27  7:56     ` Shaokun Zhang
  0 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2021-01-27  7:56 UTC (permalink / raw)
  To: John Garry, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

Hi John,

在 2021/1/26 19:46, John Garry 写道:
> On 31/12/2020 06:19, Shaokun Zhang wrote:
> 
> nit: the subject is a little ambiguous. Maybe could have "Add v1 hw PMU symbol versioning for uncore
> PMU drivers"
> 
>> For HiSilicon uncore PMU, more versions are supported and some variables
>> shall be added suffiex to distinguish the version which are prepared for
> 
> suffix

Ok,

> 
>> the new drivers.
>>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: John Garry <john.garry@huawei.com>
>> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>> Co-developed-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
> 
> Apart from some small issues:
> Reviewed-by: John Garry <john.garry@huawei.com>
> 

thanks for your tag,

>> ---
>>   drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 95 ++++++++++++++-------------
>>   drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 27 ++++----
>>   drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 24 +++----
>>   3 files changed, 74 insertions(+), 72 deletions(-)
>>
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> index 69ccbe02f1e3..7f940c47b833 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> @@ -36,8 +36,8 @@
>>     /* DDRC has 8-counters */
>>   #define DDRC_NR_COUNTERS    0x8
>> -#define DDRC_PERF_CTRL_EN    0x2
>> -
>> +#define DDRC_V1_PERF_CTRL_EN    0x2
>> +#define DDRC_V1_NR_EVENTS    0x07
>>   /*
>>    * For DDRC PMU, there are eight-events and every event has been mapped
>>    * to fixed-purpose counters which register offset is not consistent.
>> @@ -53,26 +53,26 @@ static const u32 ddrc_reg_off[] = {
>>     /*
>>    * Select the counter register offset using the counter index.
>> - * In DDRC there are no programmable counter, the count
>> + * In PMU v1, there are no programmable counter, the count
>>    * is readed form the statistics counter register itself.
> 
> comment on existing code:
> 
> /s/is readed form/is read from/
> 

Ok,

Thanks,
Shaokun

>>    */
>> -static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
>> +static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
>>   {
>>       return ddrc_reg_off[cntr_idx];
>>   }
>>   
> .

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 4/8] drivers/perf: hisi: Add new functions for HHA PMU
  2021-01-26 12:10   ` John Garry
@ 2021-01-27  8:02     ` Shaokun Zhang
  0 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2021-01-27  8:02 UTC (permalink / raw)
  To: John Garry, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

Hi John,

在 2021/1/26 20:10, John Garry 写道:
> On 31/12/2020 06:19, Shaokun Zhang wrote:
>> On HiSilicon Hip09 platform, some new functions are also supported on
>> HHA PMU, it can filter gathered statistics by the Master ID and mask
>> from the SoC if the user wants to do deep-going profiling.
>> Tracetag support is also added with L3C PMU in the SoC system.
>>
>> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,tracetag_en=0x1/ sleep 5
>>
>> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,srcid_cmd=0x1/ sleep 5
>> Much more introduction is added in documentation:
> 
> 
> 
>> Documentation/admin-guide/perf/hisi-pmu.rst
> 
> I think that it would make sense to add that prior to the driver change, like how we do with dt
> bindings, but not so important

I will consider this.

> 
>>
>> Cc: Mark Rutland<mark.rutland@arm.com>
>> Cc: Will Deacon<will@kernel.org>
>> Cc: John Garry<john.garry@huawei.com>
>> Cc: Jonathan Cameron<Jonathan.Cameron@huawei.com>
>> Co-developed-by: Qi Liu<liuqi115@huawei.com>
>> Signed-off-by: Qi Liu<liuqi115@huawei.com>
>> Signed-off-by: Shaokun Zhang<zhangshaokun@hisilicon.com>
> 
> Reviewed-by: John Garry <john.garry@huawei.com>
> 
> I suppose the change in hisi_hha_pmu_init_data() is ok (not shown).
> 
>> ---
>>   drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 203 +++++++++++++++++++++++++--
>>   1 file changed, 188 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
>> b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
>> index 2f55e5864d39..5e1c4b61ffce 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
>> +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
>> @@ -25,19 +25,136 @@
>>   #define HHA_VERSION        0x1cf0
>>   #define HHA_PERF_CTRL        0x1E00
>>   #define HHA_EVENT_CTRL        0x1E04
>> +#define HHA_SRCID_CTRL        0x1E08
>> +#define HHA_DATSRC_CTRL        0x1BF0
>>   #define HHA_EVENT_TYPE0        0x1E80
>>   /*
>> - * Each counter is 48-bits and [48:63] are reserved
>> - * which are Read-As-Zero and Writes-Ignored.
>> + * If the HW version only supports a 48-bit counter, then
>> + * bits [63:48] are reserved, which are Read-As-Zero and
>> + * Writes-Ignored.
>>    */
>>   #define HHA_CNT0_LOWER        0x1F00
>>   -/* HHA has 16-counters */
>> +/* HHA PMU v1 has 16-counter and v2 only has 8-counter */
> 
> nit: "has 16 counters and v2 has only 8 counters */

Ok,

Thanks,
Shaokun

> .

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter
  2021-01-26 15:56     ` John Garry
@ 2021-01-27  8:16       ` Shaokun Zhang
  0 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2021-01-27  8:16 UTC (permalink / raw)
  To: John Garry, linux-arm-kernel
  Cc: Mark Rutland, Will Deacon, Qi Liu, Jonathan Cameron

Hi John,

在 2021/1/26 23:56, John Garry 写道:
> On 26/01/2021 12:33, John Garry wrote:
>>>   }
>>> @@ -332,8 +506,16 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
>>>           return ret;
>>>       }
>>> -    name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_ddrc%u",
>>> -                  ddrc_pmu->sccl_id, ddrc_pmu->index_id);
>>> +    if (ddrc_pmu->identifier >= HISI_PMU_V2)
>>> +        name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
>>> +                      "hisi_sccl%u_ddrc%u_%u",
>>> +                      ddrc_pmu->sccl_id, ddrc_pmu->index_id,
>>> +                      ddrc_pmu->sub_id);
> 
> I think that this is actually ok for perf.
> 

Sounds good,

> Checking pmu_uncore_alias_match():
> 
> bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
> {
>     char *tmp = NULL, *tok, *str;
>     bool res;
> 
> ...
> 
>     for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) {
>         name = strstr(name, tok);
>         if (!name) {
>             res = false;
>             goto out;
>         }
>     }
> 
>     ...
> }
> 
> We match each token in @pmu_name, "hisi_sccl,ddrc". So we would match "hisi_sccl%u_" part with
> "hisi_sccl" token and then match "ddrc%u_%u" with "ddrc" token.
> 
> But it would be good to triple check. We need the JSON files created at some stage anyway :)
> 

Sure, will do it.

Thanks,
Shaokun

>>
>> I don't think perf can support event aliasing in this format (hisi_scclX_Y_Z), but I need to
>> double-check.
>>
>>> +    else
>>> +        name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 
> 
> .

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2021-01-26 12:30   ` John Garry
@ 2021-01-27  8:26     ` Shaokun Zhang
  0 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2021-01-27  8:26 UTC (permalink / raw)
  To: John Garry, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

Hi John,

在 2021/1/26 20:30, John Garry 写道:
> On 31/12/2020 06:19, Shaokun Zhang wrote:
>> HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
>> module (Skyros Link Layer Controller), its has separate PMU registers which
>> the driver can program it freely and interrupt is supported to handle
>> counter overflow. Let's support its driver under the framework of HiSilicon
>> uncore PMU driver.
>>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: John Garry <john.garry@huawei.com>
>> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>> Co-developed-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
> 
> layout looks consistent with other hisi uncore PMU drivers, but some small comments, below
> 
> Reviewed-by: John Garry <john.garry@huawei.com>
> 
>> ---
>>   drivers/perf/hisilicon/Makefile               |   2 +-
>>   drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 530 ++++++++++++++++++++++++++
>>   include/linux/cpuhotplug.h                    |   1 +
>>   3 files changed, 532 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
>>
>> diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
>> index e8377061845f..6600a9d45dd8 100644
>> --- a/drivers/perf/hisilicon/Makefile
>> +++ b/drivers/perf/hisilicon/Makefile
>> @@ -1,3 +1,3 @@
>>   # SPDX-License-Identifier: GPL-2.0-only
>>   obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
>> -              hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o
>> +              hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
>> b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
>> new file mode 100644
>> index 000000000000..6911c388a5ac
>> --- /dev/null
>> +++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
>> @@ -0,0 +1,530 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * HiSilicon SLLC uncore Hardware event counters support
>> + *
>> + * Copyright (C) 2020 Hisilicon Limited
>> + * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
>> + *
>> + * This code is based on the uncore PMUs like arm-cci and arm-ccn.
>> + */
>> +#include <linux/acpi.h>
>> +#include <linux/cpuhotplug.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/list.h>
>> +#include <linux/smp.h>
>> +
>> +#include "hisi_uncore_pmu.h"
>> +
>> +/* SLLC register definition */
>> +#define SLLC_INT_MASK            0x0814
>> +#define SLLC_INT_STATUS            0x0818
>> +#define SLLC_INT_CLEAR            0x081C
>> +#define SLLC_PERF_CTRL            0x1C00
>> +#define SLLC_SRCID_CTRL            0x1C04
>> +#define SLLC_TGTID_CTRL            0x1C08
>> +#define SLLC_EVENT_CTRL            0x1C14
>> +#define SLLC_EVENT_TYPE0        0x1C18
>> +#define SLLC_VERSION            0x1CF0
>> +#define SLLC_EVENT_CNT0_L        0x1D00
>> +
>> +#define SLLC_EVTYPE_MASK        0xFF
>> +#define SLLC_PERF_CTRL_EN        BIT(0)
>> +#define SLLC_FILT_EN            BIT(1)
>> +#define SLLC_TRACETAG_EN        BIT(2)
>> +#define SLLC_SRCID_EN            BIT(4)
>> +#define SLLC_SRCID_NONE            0x0
>> +#define SLLC_TGTID_EN            BIT(5)
>> +#define SLLC_TGTID_NONE            0x0
>> +#define SLLC_TGTID_LO_SHIFT        1
>> +#define SLLC_TGTID_HI_SHIFT        12
>> +#define SLLC_SRCID_CMD_SHIFT        1
>> +#define SLLC_SRCID_MSK_SHIFT        12
>> +#define SLLC_NR_EVENTS            0x80
>> +
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
>> +
>> +static inline bool tgtid_is_valid(u32 hi, u32 lo)
> 
> nit: no need for inline
> 

Ok,

>> +{
>> +    return lo > 0 && hi >= lo;
>> +}
>> +
>> +static inline void hisi_sllc_pmu_enable_tracetag(struct perf_event *event)
>> +{
>> +    struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
>> +    u32 tt_en = hisi_get_tracetag_en(event);
>> +
>> +    if (tt_en) {
>> +        u32 val;
>> +
>> +        val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
>> +        val |= SLLC_TRACETAG_EN | SLLC_FILT_EN;
>> +        writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
>> +    }
>> +}
>> +
>> +static inline void hisi_sllc_pmu_disable_tracetag(struct perf_event *event)
>> +{
>> +    struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
>> +    u32 tt_en = hisi_get_tracetag_en(event);
>> +
>> +    if (tt_en) {
>> +        u32 val;
>> +
>> +        val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
>> +        val &= ~(SLLC_TRACETAG_EN | SLLC_FILT_EN);
>> +        writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
> 
> note: i think that all these can be _relaxed variant, but that is for existing drivers as well, so
> can be reviewed later
> 

Ok,

>> +    }
>> +}
>> +
>> +static inline void hisi_sllc_pmu_config_tgtid(struct perf_event *event)
>> +{
>> +    struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
>> +    u32 lo = hisi_get_tgtid_lo(event);
>> +    u32 hi = hisi_get_tgtid_hi(event);
>> +
>> +    if (tgtid_is_valid(hi, lo)) {
>> +        u32 val = (hi << SLLC_TGTID_HI_SHIFT) | (lo << SLLC_TGTID_LO_SHIFT);
>> +
>> +        writel(val, sllc_pmu->base + SLLC_TGTID_CTRL);
>> +
>> +        /* Enable the tgtid */
>> +        val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
>> +        val |= SLLC_TGTID_EN | SLLC_FILT_EN;
>> +        writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
>> +    }
>> +}
>> +    name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_sllc%u",
>> +                  sllc_pmu->sccl_id, sllc_pmu->index_id);
>> +    if (!name) {
>> +        dev_err(&pdev->dev, "failed to allocate name for PMU\n");
> 
> maybe this message is not so useful

Ok, if it is not useful, let's return -ENOMEM directly.

> 
>> +        return -ENOMEM;
>> +    }
>> +
>> +    ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>> +                       &sllc_pmu->node);
>> +    if (ret) {
>> +        dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    sllc_pmu->pmu = (struct pmu) {
>> +        .module        = THIS_MODULE,
>> +        .task_ctx_nr    = perf_invalid_context,
>> +        .event_init    = hisi_uncore_pmu_event_init,
>> +        .pmu_enable    = hisi_uncore_pmu_enable,
>> +        .pmu_disable    = hisi_uncore_pmu_disable,
>> +        .add        = hisi_uncore_pmu_add,
>> +        .del        = hisi_uncore_pmu_del,
>> +        .start        = hisi_uncore_pmu_start,
>> +        .stop        = hisi_uncore_pmu_stop,
>> +        .read        = hisi_uncore_pmu_read,
>> +        .attr_groups    = sllc_pmu->pmu_events.attr_groups,
>> +        .capabilities    = PERF_PMU_CAP_NO_EXCLUDE,
>> +    };
>> +
>> +    ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
>> +    if (ret) {
>> +        dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
>> +        cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>> +                        &sllc_pmu->node);
>> +        irq_set_affinity_hint(sllc_pmu->irq, NULL);
>> +    }
>> +
>> +    platform_set_drvdata(pdev, sllc_pmu);
> 
> strange that we still do this for an error
> 

Oops, this shall be set when alloc sllc_pmu.

>> +
>> +    return ret;
>> +}
>> +
>> +static int hisi_sllc_pmu_remove(struct platform_device *pdev)
>> +{
>> +    struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev);
>> +
>> +    perf_pmu_unregister(&sllc_pmu->pmu);
>> +    cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>> +                        &sllc_pmu->node);
>> +    irq_set_affinity_hint(sllc_pmu->irq, NULL);
>> +
>> +    return 0;
>> +}
>> +
>> +static struct platform_driver hisi_sllc_pmu_driver = {
>> +    .driver = {
>> +        .name = "hisi_sllc_pmu",
>> +        .acpi_match_table = hisi_sllc_pmu_acpi_match,
> 
> please set unbind unsupported
> 

Ok,

Thanks,
Shaokun

>> +    },
>> +    .probe = hisi_sllc_pmu_probe,
>> +    .remove = hisi_sllc_pmu_remove,
>> +};
>> +
>> +static int __init hisi_sllc_pmu_module_init(void)
>> +{
>> +    int ret;
>> +
>> +    ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>> +                      "AP_PERF_ARM_HISI_SLLC_ONLINE",
>> +                      hisi_uncore_pmu_online_cpu,
>> +                      hisi_uncore_pmu_offline_cpu);
>> +    if (ret) {
>> +        pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = platform_driver_register(&hisi_sllc_pmu_driver);
>> +    if (ret)
>> +        cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
>> +
>> +    return ret;
>> +}
>> +module_init(hisi_sllc_pmu_module_init);
>> +
>> +static void __exit hisi_sllc_pmu_module_exit(void)
>> +{
>> +    platform_driver_unregister(&hisi_sllc_pmu_driver);
>> +    cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
>> +}
>> +module_exit(hisi_sllc_pmu_module_exit);
>> +
>> +MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
>> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
>> index 0042ef362511..b5e04f9b68f1 100644
>> --- a/include/linux/cpuhotplug.h
>> +++ b/include/linux/cpuhotplug.h
>> @@ -174,6 +174,7 @@ enum cpuhp_state {
>>       CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
>>       CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
>>       CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
>> +    CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>>       CPUHP_AP_PERF_ARM_L2X0_ONLINE,
>>       CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
>>       CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
>>
> 
> .

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 7/8] drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  2021-01-26 12:45   ` John Garry
@ 2021-01-27  8:41     ` Shaokun Zhang
  0 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2021-01-27  8:41 UTC (permalink / raw)
  To: John Garry, linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, Will Deacon, Jonathan Cameron

Hi John,

在 2021/1/26 20:45, John Garry 写道:
> On 31/12/2020 06:19, Shaokun Zhang wrote:
>> On HiSilicon Hip09 platform, there is a PA (Protocol Adapter) module on
>> each chip SICL (Super I/O Cluster) which incorporates three Hydra interface
>> and facilitates the cache coherency between the dies on the chip. While PA
>> uncore PMU model is the same as other Hip09 PMU modules and many PMU events
>> are supported. Let's support the PMU driver using the HiSilicon uncore PMU
>> framework.
>>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: John Garry <john.garry@huawei.com>
>> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>> Co-developed-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
> 
> nit: please stop using inline when not needed

Ok,

> 
> Apart from minor comments, below:
> Reviewed-by: John Garry <john.garry@huawei.com>
> 
> note: we do internal review, but tags not given - maybe we should in future...

Sure, will do this in the next version.

> 
>> ---
>>   drivers/perf/hisilicon/Makefile             |   3 +-
>>   drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 498 ++++++++++++++++++++++++++++
>>   include/linux/cpuhotplug.h                  |   1 +
>>   3 files changed, 501 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
>>
>> diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
>> index 6600a9d45dd8..7643c9f93e36 100644
>> --- a/drivers/perf/hisilicon/Makefile
>> +++ b/drivers/perf/hisilicon/Makefile
>> @@ -1,3 +1,4 @@
>>   # SPDX-License-Identifier: GPL-2.0-only
>>   obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
>> -              hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
>> +              hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o \
>> +              hisi_uncore_pa_pmu.o
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
>> b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
>> new file mode 100644
>> index 000000000000..eec12f5daf71
>> --- /dev/null
>> +++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
>> @@ -0,0 +1,498 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * HiSilicon PA uncore Hardware event counters support
>> + *
>> + * Copyright (C) 2020 HiSilicon Limited
>> + * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
>> + *
>> + * This code is based on the uncore PMUs like arm-cci and arm-ccn.
>> + */
>> +#include <linux/acpi.h>
>> +#include <linux/cpuhotplug.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/list.h>
>> +#include <linux/smp.h>
>> +
>> +#include "hisi_uncore_pmu.h"
>> +
>> +/* PA register definition */
>> +#define PA_PERF_CTRL            0x1C00
> 
> nit: generally lower case used for hex, but not so important

Ok,

> 
>> +#define PA_EVENT_CTRL            0x1C04
>> +#define PA_TT_CTRL            0x1C08
>> +#define PA_TGTID_CTRL            0x1C14
>> +#define PA_SRCID_CTRL            0x1C18
>> +#define PA_INT_MASK            0x1C70
>> +#define PA_INT_STATUS            0x1C78
>> +#define PA_INT_CLEAR            0x1C7C
>> +#define PA_EVENT_TYPE0            0x1C80
>> +#define PA_PMU_VERSION            0x1CF0
>> +#define PA_EVENT_CNT0_L            0x1D00
>> +
> 
> ...
> 
>> +
>> +static int hisi_pa_pmu_init_data(struct platform_device *pdev,
>> +                   struct hisi_pmu *pa_pmu)
>> +{
>> +    /*
>> +     * Use the SCCL_ID and the index ID to identify the PA PMU,
>> +     * while SCCL_ID is the nearst SCCL_ID from this SICL.
>> +     */
>> +    if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
>> +                     &pa_pmu->sccl_id)) {
> 
> hmmm... I do wonder if we should make it clearer in the driver that this is the SICL. I know I

This is used to check the cpu core in SCCL affinity when online/offline cpu core.
But for PMU name, we show it using SICL as follow.

> mentioned this before--sorry
> 
>> +        dev_err(&pdev->dev, "Cannot read sccl-id!\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
>> +                     &pa_pmu->index_id)) {
>> +        dev_err(&pdev->dev, "Cannot read idx-id!\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    pa_pmu->ccl_id = -1;
>> +
>> +    pa_pmu->base = devm_platform_ioremap_resource(pdev, 0);
>> +    if (IS_ERR(pa_pmu->base)) {
>> +        dev_err(&pdev->dev, "ioremap failed for pa_pmu resource.\n");
>> +        return PTR_ERR(pa_pmu->base);
>> +    }
>> +
>> +    pa_pmu->identifier = readl(pa_pmu->base + PA_PMU_VERSION);
>> +
>> +    return 0;
>> +}
>> +
> 
> ...
> 
>> +static int hisi_pa_pmu_probe(struct platform_device *pdev)
>> +{
>> +    struct hisi_pmu *pa_pmu;
>> +    char *name;
>> +    int ret;
>> +
>> +    pa_pmu = devm_kzalloc(&pdev->dev, sizeof(*pa_pmu), GFP_KERNEL);
>> +    if (!pa_pmu)
>> +        return -ENOMEM;
>> +
>> +    ret = hisi_pa_pmu_dev_probe(pdev, pa_pmu);
>> +    if (ret)
>> +        return ret;
>> +    /*
>> +     * PA is attached in SICL and the CPU core is chosen to manage this
>> +     * PMU which is the nearest SCCL,
> 
> do we really need to do this? Can any CPU in that chip do it?

Any CPU core can do this, but I think it's better to choose the nearest SCCL's
CPU core to do this that we can avoid cross SCCL operations.

> 
>> while its SCCL_ID is greater than
>> +     * one with the SICL_ID.
>> +     */
>> +    name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%u_pa%u",
>> +                  pa_pmu->sccl_id - 1, pa_pmu->index_id);
>> +    if (!name) {
>> +        dev_err(&pdev->dev, "failed to allocate name for PMU\n");
>> +        return -ENOMEM;
>> +    }
>> +
>> +    ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
>> +                       &pa_pmu->node);
>> +    if (ret) {
>> +        dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    pa_pmu->pmu = (struct pmu) {
>> +        .module        = THIS_MODULE,
>> +        .task_ctx_nr    = perf_invalid_context,
>> +        .event_init    = hisi_uncore_pmu_event_init,
>> +        .pmu_enable    = hisi_uncore_pmu_enable,
>> +        .pmu_disable    = hisi_uncore_pmu_disable,
>> +        .add        = hisi_uncore_pmu_add,
>> +        .del        = hisi_uncore_pmu_del,
>> +        .start        = hisi_uncore_pmu_start,
>> +        .stop        = hisi_uncore_pmu_stop,
>> +        .read        = hisi_uncore_pmu_read,
>> +        .attr_groups    = pa_pmu->pmu_events.attr_groups,
>> +        .capabilities    = PERF_PMU_CAP_NO_EXCLUDE,
>> +    };
>> +
>> +    ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
>> +    if (ret) {
>> +        dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
>> +        cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
>> +                        &pa_pmu->node);
>> +        irq_set_affinity_hint(pa_pmu->irq, NULL);
>> +    }
>> +
>> +    platform_set_drvdata(pdev, pa_pmu);
> 
> as before

Apologies and will fix this.

> 
>> +    return ret;
>> +}
>> +
>> +static int hisi_pa_pmu_remove(struct platform_device *pdev)
>> +{
>> +    struct hisi_pmu *pa_pmu = platform_get_drvdata(pdev);
>> +
>> +    perf_pmu_unregister(&pa_pmu->pmu);
>> +    cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
>> +                        &pa_pmu->node);
>> +    irq_set_affinity_hint(pa_pmu->irq, NULL);
>> +
>> +    return 0;
>> +}
>> +
>> +static struct platform_driver hisi_pa_pmu_driver = {
>> +    .driver = {
>> +        .name = "hisi_pa_pmu",
>> +        .acpi_match_table = hisi_pa_pmu_acpi_match,
> 
> some small comments on earlier patch reviews apply here
> 

Ok,

>> +    },
>> +    .probe = hisi_pa_pmu_probe,
>> +    .remove = hisi_pa_pmu_remove,
>> +};
>> +
>> +static int __init hisi_pa_pmu_module_init(void)
>> +{
>> +    int ret;
>> +
>> +    ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
>> +                      "AP_PERF_ARM_HISI_PA_ONLINE",
>> +                      hisi_uncore_pmu_online_cpu,
>> +                      hisi_uncore_pmu_offline_cpu);
>> +    if (ret) {
>> +        pr_err("PA PMU: cpuhp state setup failed, ret = %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = platform_driver_register(&hisi_pa_pmu_driver);
>> +    if (ret)
>> +        cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
>> +
>> +    return ret;
>> +}
>> +module_init(hisi_pa_pmu_module_init);
>> +
>> +static void __exit hisi_pa_pmu_module_exit(void)
>> +{
>> +    platform_driver_unregister(&hisi_pa_pmu_driver);
>> +    cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
>> +}
>> +module_exit(hisi_pa_pmu_module_exit);
>> +
>> +MODULE_DESCRIPTION("HiSilicon PA uncore PMU driver");
> 
> nit maybe have "PA (Protocol Adapter)"
> 

Sure,

Thanks,
Shaokun


>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
>> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
>> index b5e04f9b68f1..37f591ed80d0 100644
>> --- a/include/linux/cpuhotplug.h
>> +++ b/include/linux/cpuhotplug.h
>> @@ -174,6 +174,7 @@ enum cpuhp_state {
>>       CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
>>       CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
>>       CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
>> +    CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
>>       CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
>>       CPUHP_AP_PERF_ARM_L2X0_ONLINE,
>>       CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
>>
> 
> .

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver
  2021-01-22  6:03 ` [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
@ 2021-02-02 18:48   ` Will Deacon
  2021-02-03  1:46     ` Shaokun Zhang
  0 siblings, 1 reply; 24+ messages in thread
From: Will Deacon @ 2021-02-02 18:48 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Mark Rutland, John Garry, Qi Liu, linux-arm-kernel, Jonathan Cameron

On Fri, Jan 22, 2021 at 02:03:57PM +0800, Shaokun Zhang wrote:
> A gentle ping.

Looks like John had some comments on this version, so please address those
in v2.

Will

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver
  2021-02-02 18:48   ` Will Deacon
@ 2021-02-03  1:46     ` Shaokun Zhang
  0 siblings, 0 replies; 24+ messages in thread
From: Shaokun Zhang @ 2021-02-03  1:46 UTC (permalink / raw)
  To: Will Deacon
  Cc: Mark Rutland, John Garry, Qi Liu, linux-arm-kernel, Jonathan Cameron

Hi Will,

在 2021/2/3 2:48, Will Deacon 写道:
> On Fri, Jan 22, 2021 at 02:03:57PM +0800, Shaokun Zhang wrote:
>> A gentle ping.
> 
> Looks like John had some comments on this version, so please address those
> in v2.

Sure, I will send these later today.

Thanks,
Shaokun

> 
> Will
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2021-02-03  1:48 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-31  6:19 [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
2020-12-31  6:19 ` [PATCH 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
2020-12-31  6:19 ` [PATCH 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
2021-01-26 11:46   ` John Garry
2021-01-27  7:56     ` Shaokun Zhang
2020-12-31  6:19 ` [PATCH 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
2021-01-26 12:05   ` John Garry
2020-12-31  6:19 ` [PATCH 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
2021-01-26 12:10   ` John Garry
2021-01-27  8:02     ` Shaokun Zhang
2020-12-31  6:19 ` [PATCH 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
2021-01-26 12:33   ` John Garry
2021-01-26 15:56     ` John Garry
2021-01-27  8:16       ` Shaokun Zhang
2020-12-31  6:19 ` [PATCH 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
2021-01-26 12:30   ` John Garry
2021-01-27  8:26     ` Shaokun Zhang
2020-12-31  6:19 ` [PATCH 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
2021-01-26 12:45   ` John Garry
2021-01-27  8:41     ` Shaokun Zhang
2020-12-31  6:19 ` [PATCH 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2 Shaokun Zhang
2021-01-22  6:03 ` [PATCH 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
2021-02-02 18:48   ` Will Deacon
2021-02-03  1:46     ` Shaokun Zhang

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.