[PATCH v3 4/6] perf: hisi: Add support for HiSilicon SoC HHA PMU driver

2017-07-18 Thread Shaokun Zhang
L3 cache coherence is maintained by Hydra Home Agent (HHA) in HiSilicon
SoC. This patch adds support for HHA PMU driver, Each HHA has own
control, counter and interrupt registers and is an separate PMU. For
each HHA PMU, it has 16-programable counters and supports 0x50 events,
event code is 8-bits and every counter is free-running. Interrupt is
supported to handle counter (48-bits) overflow.

Signed-off-by: Shaokun Zhang 
Signed-off-by: Anurup M 
---
 drivers/perf/hisilicon/Makefile  |   2 +-
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 453 +++
 2 files changed, 454 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index 4a3d3e6..a72afe8 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o
+obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o 
hisi_uncore_hha_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c 
b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
new file mode 100644
index 000..f56dced
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -0,0 +1,453 @@
+/*
+ * HiSilicon SoC HHA uncore Hardware event counters support
+ *
+ * Copyright (C) 2017 Hisilicon Limited
+ * Author: Shaokun Zhang 
+ * Anurup M 
+ *
+ * This code is based on the uncore PMUs like arm-cci and arm-ccn.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "hisi_uncore_pmu.h"
+
+/* HHA register definition */
+#define HHA_INT_MASK   0x0804
+#define HHA_INT_STATUS 0x0808
+#define HHA_INT_CLEAR  0x080C
+#define HHA_PERF_CTRL  0x1E00
+#define HHA_EVENT_CTRL 0x1E04
+#define HHA_EVENT_TYPE00x1E80
+#define HHA_CNT0_LOWER 0x1F00
+
+/* HHA has 16-counters and supports 0x50 events */
+#define HHA_NR_COUNTERS0x10
+#define HHA_NR_EVENTS  0x50
+
+#define HHA_PERF_CTRL_EN   0x1
+#define HHA_EVTYPE_NONE0xff
+
+#define HHA_EVTYPE_REG(idx) (HHA_EVENT_TYPE0 + (idx <= 3 ? 0 : 4 * \
+   (idx / 4)))
+
+/*
+ * Select the counter register offset using the counter index
+ * every counter is 48-bits and [48:63] is reserved.
+ */
+static u32 get_counter_reg_off(int cntr_idx)
+{
+   return (HHA_CNT0_LOWER + (cntr_idx * 8));
+}
+
+static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu,
+struct hw_perf_event *hwc)
+{
+   u32 idx = hwc->idx;
+   u32 reg;
+
+   if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
+   dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
+   return 0;
+   }
+
+   reg = get_counter_reg_off(idx);
+
+   /* Read 64 bits and like L3C, top 16 bits are RAZ */
+   return readq(hha_pmu->base + reg);
+}
+
+static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu,
+  struct hw_perf_event *hwc, u64 val)
+{
+   u32 idx = hwc->idx;
+   u32 reg;
+
+   if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
+   dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
+   return;
+   }
+
+   reg = get_counter_reg_off(idx);
+   /* Write 64 bits and like L3C, top 16 bits are WI */
+   writeq(val, hha_pmu->base + reg);
+}
+
+static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
+ u32 type)
+{
+   u32 reg, reg_idx, shift, val;
+
+   /*
+* Select the appropriate Event select register(HHA_EVENT_TYPEx).
+* There are 4 event select registers for the 16 hardware counters.
+* Event code is 8-bits and for the first 4 hardware counters,
+* HHA_EVENT_TYPE0 is chosen. For the next 4 hardware counters,
+* HHA_EVENT_TYPE1 is chosen and so on.
+*/
+   reg = HHA_EVTYPE_REG(idx);
+   reg_idx = idx % 4;
+   shift = 8 * reg_idx;
+
+   /* Write event code to HHA_EVENT_TYPEx register */
+   val = readl(hha_pmu->base + reg);
+   val &= ~(HHA_EVTYPE_NONE << shift);
+   val |= (type << 

[PATCH v3 4/6] perf: hisi: Add support for HiSilicon SoC HHA PMU driver

2017-07-18 Thread Shaokun Zhang
L3 cache coherence is maintained by Hydra Home Agent (HHA) in HiSilicon
SoC. This patch adds support for HHA PMU driver, Each HHA has own
control, counter and interrupt registers and is an separate PMU. For
each HHA PMU, it has 16-programable counters and supports 0x50 events,
event code is 8-bits and every counter is free-running. Interrupt is
supported to handle counter (48-bits) overflow.

Signed-off-by: Shaokun Zhang 
Signed-off-by: Anurup M 
---
 drivers/perf/hisilicon/Makefile  |   2 +-
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 453 +++
 2 files changed, 454 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index 4a3d3e6..a72afe8 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o
+obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o 
hisi_uncore_hha_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c 
b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
new file mode 100644
index 000..f56dced
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -0,0 +1,453 @@
+/*
+ * HiSilicon SoC HHA uncore Hardware event counters support
+ *
+ * Copyright (C) 2017 Hisilicon Limited
+ * Author: Shaokun Zhang 
+ * Anurup M 
+ *
+ * This code is based on the uncore PMUs like arm-cci and arm-ccn.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "hisi_uncore_pmu.h"
+
+/* HHA register definition */
+#define HHA_INT_MASK   0x0804
+#define HHA_INT_STATUS 0x0808
+#define HHA_INT_CLEAR  0x080C
+#define HHA_PERF_CTRL  0x1E00
+#define HHA_EVENT_CTRL 0x1E04
+#define HHA_EVENT_TYPE00x1E80
+#define HHA_CNT0_LOWER 0x1F00
+
+/* HHA has 16-counters and supports 0x50 events */
+#define HHA_NR_COUNTERS0x10
+#define HHA_NR_EVENTS  0x50
+
+#define HHA_PERF_CTRL_EN   0x1
+#define HHA_EVTYPE_NONE0xff
+
+#define HHA_EVTYPE_REG(idx) (HHA_EVENT_TYPE0 + (idx <= 3 ? 0 : 4 * \
+   (idx / 4)))
+
+/*
+ * Select the counter register offset using the counter index
+ * every counter is 48-bits and [48:63] is reserved.
+ */
+static u32 get_counter_reg_off(int cntr_idx)
+{
+   return (HHA_CNT0_LOWER + (cntr_idx * 8));
+}
+
+static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu,
+struct hw_perf_event *hwc)
+{
+   u32 idx = hwc->idx;
+   u32 reg;
+
+   if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
+   dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
+   return 0;
+   }
+
+   reg = get_counter_reg_off(idx);
+
+   /* Read 64 bits and like L3C, top 16 bits are RAZ */
+   return readq(hha_pmu->base + reg);
+}
+
+static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu,
+  struct hw_perf_event *hwc, u64 val)
+{
+   u32 idx = hwc->idx;
+   u32 reg;
+
+   if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
+   dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
+   return;
+   }
+
+   reg = get_counter_reg_off(idx);
+   /* Write 64 bits and like L3C, top 16 bits are WI */
+   writeq(val, hha_pmu->base + reg);
+}
+
+static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
+ u32 type)
+{
+   u32 reg, reg_idx, shift, val;
+
+   /*
+* Select the appropriate Event select register(HHA_EVENT_TYPEx).
+* There are 4 event select registers for the 16 hardware counters.
+* Event code is 8-bits and for the first 4 hardware counters,
+* HHA_EVENT_TYPE0 is chosen. For the next 4 hardware counters,
+* HHA_EVENT_TYPE1 is chosen and so on.
+*/
+   reg = HHA_EVTYPE_REG(idx);
+   reg_idx = idx % 4;
+   shift = 8 * reg_idx;
+
+   /* Write event code to HHA_EVENT_TYPEx register */
+   val = readl(hha_pmu->base + reg);
+   val &= ~(HHA_EVTYPE_NONE << shift);
+   val |= (type << shift);
+   writel(val, hha_pmu->base + reg);
+}
+
+static void hisi_hha_pmu_start_counters(struct