linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters
@ 2016-08-03  6:34 Anurup M
  0 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-03  6:34 UTC (permalink / raw)
  To: linux-arm-kernel

Provide Support for Hisilicon SoC Hip05 Hardware event counters.
The Hisilicon SoC Hip05 series has many uncore or non-CPU performance
events and counters units.

This patch is implemented refering to arm-cci, Intel/AMD uncore and
also the cavium thunderX pmu patches.

Support for Hisilicon L3 cache(LLC) hardware events and counters are added
in this implementation.

The Hisilicon PMU datastructures are designed so as to support uncore
and also CPU specific events in future.

The Hisilicon LLC has four banks for a Super CPU Cluster(consists of
 16 CPU cores) and each LLC bank has separate hardware events and counters.
In the current implementation, the count from all these banks are summarized
and total count is output.

Hisilicon SoC use Djtag interface for r/w access to SoC PMU registers

The Hisilicon uncore PMUs can be found under /sys/bus/event_source/devices.
The counters are exported via sysfs in the corresponding events files
under the PMU directory so the perf tool can list the event names.

Note:
This is very initial patchset for Hisilicon Hip05 SoC PMU support shared for
review. Please review and share comments.

TODO:
	1. Counter overflow interrupt handling support.
	2. CPU notifier to migrate to available online CPU's in case
	   of CPU DOWN. Also mapping CPU cores to the current SCCL.
	3. Support for counting of individual LLC banks

Anurup M (8):
  arm64:perf: Add Documentaion for HIP05 PMU event counting.     
    1. Documentaion for perf usage and PMU events.
  arm64:perf: Add Devicetree bindings for Hisilicon SoC PMU
  arm64:perf: Update Kconfig for Hisilicon PMU support
  arm64:perf: Add support for Hisilicon SoC event counters
  arm64:perf: Makefile for Hisilicon Hip05 PMU
  arm64:perf: Update Makefile for Hisilicon PMU support
  arm64:perf: L3 cache(LLC) event listing in perf
  arm64: dts: hip05: Add L3 cache PMU support

Tan Xiaojun (2):
  Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts
    bindings
  drivers: soc: Add support for Hisilicon Djtag driver

 .../bindings/arm/hisilicon/hisilicon.txt           |  97 ++++
 .../devicetree/bindings/arm/hisilicon/pmu.txt      |  52 ++
 Documentation/perf/hip05-pmu.txt                   |  70 +++
 arch/arm64/boot/dts/hisilicon/hip05.dtsi           |  19 +
 drivers/perf/Kconfig                               |   9 +
 drivers/perf/Makefile                              |   1 +
 drivers/perf/hisilicon/Makefile                    |   1 +
 drivers/perf/hisilicon/hisi_uncore_l3c.c           | 561 +++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_l3c.h           | 100 ++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c           | 504 ++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.h           | 148 ++++++
 drivers/soc/Kconfig                                |   1 +
 drivers/soc/Makefile                               |   1 +
 drivers/soc/hisilicon/Kconfig                      |  12 +
 drivers/soc/hisilicon/Makefile                     |   1 +
 drivers/soc/hisilicon/djtag.c                      | 373 ++++++++++++++
 include/linux/soc/hisilicon/djtag.h                |  18 +
 17 files changed, 1968 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
 create mode 100644 Documentation/perf/hip05-pmu.txt
 create mode 100644 drivers/perf/hisilicon/Makefile
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.h
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.h
 create mode 100644 drivers/soc/hisilicon/Kconfig
 create mode 100644 drivers/soc/hisilicon/Makefile
 create mode 100644 drivers/soc/hisilicon/djtag.c
 create mode 100644 include/linux/soc/hisilicon/djtag.h

-- 
2.1.4

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

* [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters
@ 2016-08-04  9:07 Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 01/10] Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts bindings Anurup M
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

[Note: Resending the patch series as I missed to add Maintainers in --to field]

Provide Support for Hisilicon SoC Hip05 Hardware event counters.
The Hisilicon SoC Hip05 series has many uncore or non-CPU performance
events and counters units.

This patch is implemented refering to arm-cci, Intel/AMD uncore and
also the cavium thunderX pmu patches.

Support for Hisilicon L3 cache(LLC) hardware events and counters are added
in this implementation.

The Hisilicon PMU datastructures are designed so as to support uncore
and also CPU specific events in future.

The Hisilicon LLC has four banks for a Super CPU Cluster(consists of
 16 CPU cores) and each LLC bank has separate hardware events and counters.
In the current implementation, the count from all these banks are summarized
and total count is output.

Hisilicon SoC use Djtag interface for r/w access to SoC PMU registers

The Hisilicon uncore PMUs can be found under /sys/bus/event_source/devices.
The counters are exported via sysfs in the corresponding events files
under the PMU directory so the perf tool can list the event names.

Note:
This is very initial patchset for Hisilicon Hip05 SoC PMU support shared for
review. Please review and share comments.

TODO:
	1. Counter overflow interrupt handling support.
	2. CPU notifier to migrate to available online CPU's in case
	   of CPU DOWN. Also mapping CPU cores to the current SCCL.
	3. Support for counting of individual LLC banks

Anurup M (8):
  arm64:perf: Add Documentaion for HIP05 PMU event counting.     
    1. Documentaion for perf usage and PMU events.
  arm64:perf: Add Devicetree bindings for Hisilicon SoC PMU
  arm64:perf: Update Kconfig for Hisilicon PMU support
  arm64:perf: Add support for Hisilicon SoC event counters
  arm64:perf: Makefile for Hisilicon Hip05 PMU
  arm64:perf: Update Makefile for Hisilicon PMU support
  arm64:perf: L3 cache(LLC) event listing in perf
  arm64: dts: hip05: Add L3 cache PMU support

Tan Xiaojun (2):
  Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts
    bindings
  drivers: soc: Add support for Hisilicon Djtag driver

 .../bindings/arm/hisilicon/hisilicon.txt           |  97 ++++
 .../devicetree/bindings/arm/hisilicon/pmu.txt      |  52 ++
 Documentation/perf/hip05-pmu.txt                   |  70 +++
 arch/arm64/boot/dts/hisilicon/hip05.dtsi           |  19 +
 drivers/perf/Kconfig                               |   9 +
 drivers/perf/Makefile                              |   1 +
 drivers/perf/hisilicon/Makefile                    |   1 +
 drivers/perf/hisilicon/hisi_uncore_l3c.c           | 561 +++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_l3c.h           | 100 ++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c           | 504 ++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.h           | 148 ++++++
 drivers/soc/Kconfig                                |   1 +
 drivers/soc/Makefile                               |   1 +
 drivers/soc/hisilicon/Kconfig                      |  12 +
 drivers/soc/hisilicon/Makefile                     |   1 +
 drivers/soc/hisilicon/djtag.c                      | 373 ++++++++++++++
 include/linux/soc/hisilicon/djtag.h                |  18 +
 17 files changed, 1968 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
 create mode 100644 Documentation/perf/hip05-pmu.txt
 create mode 100644 drivers/perf/hisilicon/Makefile
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.h
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.h
 create mode 100644 drivers/soc/hisilicon/Kconfig
 create mode 100644 drivers/soc/hisilicon/Makefile
 create mode 100644 drivers/soc/hisilicon/djtag.c
 create mode 100644 include/linux/soc/hisilicon/djtag.h

-- 
2.1.4

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

* [RFC PATCH v1 01/10] Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts bindings
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 02/10] drivers: soc: Add support for Hisilicon Djtag driver Anurup M
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tan Xiaojun <tanxiaojun@huawei.com>

First, add Hisilicon HiP05/06/07 CPU and ALGSUB system controller dts
bindings. Then, add Hisilicon Djtag dts binding.

Signed-off-by: Tan Xiaojun <tanxiaojun@huawei.com>
Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 .../bindings/arm/hisilicon/hisilicon.txt           | 97 ++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 83fe816..67256e7 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -249,3 +249,100 @@ Required Properties:
   [1]: bootwrapper size
   [2]: relocation physical address
   [3]: relocation size
+
+-----------------------------------------------------------------------
+Hisilicon HiP05 CPU system controller
+Required properties:
+- compatible : "hisilicon,hip05-sysctrl", "syscon", "simple-mfd";
+- reg : Register address and size
+- djtag :
+  - compatible : "hisilicon,hip05-cpu-djtag-v1"
+  - syscon : which sysctrl node
+
+Hisilicon HiP06 CPU system controller
+Required properties:
+- compatible : "hisilicon,hip06-sysctrl", "syscon", "simple-mfd";
+- reg : Register address and size
+- djtag :
+  - compatible : "hisilicon,hip06-cpu-djtag-v1"
+  - syscon : which sysctrl node
+
+Hisilicon HiP07 CPU system controller
+Required properties:
+- compatible : "hisilicon,hip07-sysctrl", "syscon", "simple-mfd";
+- reg : Register address and size
+- djtag :
+  - compatible : "hisilicon,hip07-cpu-djtag-v2"
+  - syscon : which sysctrl node
+
+The Hisilicon HiP05/06/07 CPU system controller is in CPU die of SoC. It is
+used to control system operation mode, control system operating status and
+manage some important components (such as clock, reset, soft reset, secure
+debugger, etc.). We can also configure some functions of the peripheral
+devices and query their status by it.
+
+The Hisilicon Djtag in CPU die is an independent component which connects with
+some other components in the SoC by Debug Bus. This driver can be configured
+to access the registers of connecting components (like L3 cache) during real
+time debugging by sysctrl.
+
+Example:
+	/* for Hisilicon HiP05 sysctrl */
+	hip05-sysctrl: hip05-sysctrl at 80010000 {
+		compatible = "hisilicon,hip05-sysctrl", "syscon", "simple-mfd";
+		reg = <0x80010000 0x10000>;
+
+		djtag0: djtag at 0 {
+		       compatible = "hisilicon,hip05-cpu-djtag-v1";
+		       syscon = <&hip05-sysctrl>;
+		};
+	};
+
+	/* for Hisilicon HiP05 L3 cache maybe set like below */
+	l3c0: l3c {
+		compatible = "hisilicon,hip05-l3c";
+		djtag = <&djtag0>;
+	};
+
+-----------------------------------------------------------------------
+Hisilicon HiP05 ALGSUB system controller
+Required properties:
+- compatible : "hisilicon,hip05-alg-sysctrl", "syscon", "simple-mfd";
+- reg : Register address and size
+- djtag :
+  - compatible : "hisilicon,hip05-io-djtag-v1"
+  - syscon : which sysctrl node
+
+Hisilicon HiP06 ALGSUB system controller
+Required properties:
+- compatible : "hisilicon,hip06-alg-sysctrl", "syscon", "simple-mfd";
+- reg : Register address and size
+- djtag :
+  - compatible : "hisilicon,hip06-io-djtag-v2"
+  - syscon : which sysctrl node
+
+Hisilicon HiP07 ALGSUB system controller
+Required properties:
+- compatible : "hisilicon,hip07-alg-sysctrl", "syscon", "simple-mfd";
+- reg : Register address and size
+- djtag :
+  - compatible : "hisilicon,hip07-io-djtag-v2"
+  - syscon : which sysctrl node
+
+The Hisilicon HiP05/06/07 ALGSUB system controller is in IO die of SoC. It
+has a similar function as the Hisilicon HiP05/06/07 CPU system controller
+in CPU die and it manage different components, like RSA, etc.
+
+The Hisilicon Djtag in IO die has a similar function as the one in CPU die.
+
+Example:
+	/* for Hisilicon HiP05 alg subctrl */
+	hip05-alg-sysctrl: hip05-alg-sysctrl at d0000000 {
+		compatible = "hisilicon,hip05-alg-sysctrl", "syscon", "simple-mfd";
+		reg = <0xd0000000 0x10000>;
+
+		djtag0: djtag at 0 {
+		       compatible = "hisilicon,hip05-io-djtag-v1";
+		       syscon = <&hip05-alg-sysctrl>;
+		};
+	};
-- 
2.1.4

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

* [RFC PATCH v1 02/10] drivers: soc: Add support for Hisilicon Djtag driver
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 01/10] Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts bindings Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 03/10] arm64:perf: Add Documentaion for HIP05 PMU event counting. 1. Documentaion for perf usage and PMU events Anurup M
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tan Xiaojun <tanxiaojun@huawei.com>

The Hisilicon Djtag is an independent component which connects with some
other components in the SoC by Debug Bus. This driver can be configured
to access the registers of connecting components (like L3 cache) during
real time debugging.

This patch add the driver of Hisilicon Djtag.

Signed-off-by: Tan Xiaojun <tanxiaojun@huawei.com>
Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 drivers/soc/Kconfig                 |   1 +
 drivers/soc/Makefile                |   1 +
 drivers/soc/hisilicon/Kconfig       |  12 ++
 drivers/soc/hisilicon/Makefile      |   1 +
 drivers/soc/hisilicon/djtag.c       | 373 ++++++++++++++++++++++++++++++++++++
 include/linux/soc/hisilicon/djtag.h |  18 ++
 6 files changed, 406 insertions(+)
 create mode 100644 drivers/soc/hisilicon/Kconfig
 create mode 100644 drivers/soc/hisilicon/Makefile
 create mode 100644 drivers/soc/hisilicon/djtag.c
 create mode 100644 include/linux/soc/hisilicon/djtag.h

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index cb58ef0..f5982ec 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -3,6 +3,7 @@ menu "SOC (System On Chip) specific Drivers"
 source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/brcmstb/Kconfig"
 source "drivers/soc/fsl/qe/Kconfig"
+source "drivers/soc/hisilicon/Kconfig"
 source "drivers/soc/mediatek/Kconfig"
 source "drivers/soc/qcom/Kconfig"
 source "drivers/soc/rockchip/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 380230f..373449d 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SOC_BRCMSTB)	+= brcmstb/
 obj-$(CONFIG_ARCH_DOVE)		+= dove/
 obj-$(CONFIG_MACH_DOVE)		+= dove/
 obj-y				+= fsl/
+obj-$(CONFIG_ARCH_HISI)		+= hisilicon/
 obj-$(CONFIG_ARCH_MEDIATEK)	+= mediatek/
 obj-$(CONFIG_ARCH_QCOM)		+= qcom/
 obj-$(CONFIG_ARCH_RENESAS)	+= renesas/
diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig
new file mode 100644
index 0000000..6dd4ba0
--- /dev/null
+++ b/drivers/soc/hisilicon/Kconfig
@@ -0,0 +1,12 @@
+#
+# Hisilicon SoC drivers
+#
+config HISI_DJTAG
+	bool "Hisilicon Djtag Support"
+	depends on ARCH_HISI || COMPILE_TEST
+	help
+	  Say y here to enable the Hisilicon Djtag support. It is
+	  an independent component which connects with some other
+	  components in the SoC by Debug Bus. This driver can be
+	  configured to access the registers of connecting
+	  components during real time debugging.
diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile
new file mode 100644
index 0000000..35a7b4b
--- /dev/null
+++ b/drivers/soc/hisilicon/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HISI_DJTAG)	+= djtag.o
diff --git a/drivers/soc/hisilicon/djtag.c b/drivers/soc/hisilicon/djtag.c
new file mode 100644
index 0000000..a5616af
--- /dev/null
+++ b/drivers/soc/hisilicon/djtag.c
@@ -0,0 +1,373 @@
+/*
+ * Driver for Hisilicon Djtag r/w via System Controller.
+ *
+ * Copyright (C) 2016 Hisilicon Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm-generic/delay.h>
+#include <linux/soc/hisilicon/djtag.h>
+
+#define SC_DJTAG_TIMEOUT		100000	/* 100ms */
+
+/* for djtag v1 */
+#define SC_DJTAG_MSTR_EN		0x6800
+#define DJTAG_NOR_CFG			BIT(1)	/* accelerate R,W */
+#define DJTAG_MSTR_EN			BIT(0)
+#define SC_DJTAG_MSTR_START_EN		0x6804
+#define DJTAG_MSTR_START_EN		0x1
+#define SC_DJTAG_DEBUG_MODULE_SEL	0x680c
+#define SC_DJTAG_MSTR_WR		0x6810
+#define DJTAG_MSTR_W			0x1
+#define DJTAG_MSTR_R			0x0
+#define SC_DJTAG_CHAIN_UNIT_CFG_EN	0x6814
+#define CHAIN_UNIT_CFG_EN		0xFFFF
+#define SC_DJTAG_MSTR_ADDR		0x6818
+#define SC_DJTAG_MSTR_DATA		0x681c
+#define SC_DJTAG_RD_DATA_BASE		0xe800
+
+/* for djtag v2 */
+#define SC_DJTAG_SEC_ACC_EN_EX		0xd800
+#define DJTAG_SEC_ACC_EN_EX		0x1
+#define SC_DJTAG_MSTR_CFG_EX		0xd818
+#define DJTAG_MSTR_RW_SHIFT_EX		29
+#define DJTAG_MSTR_RD_EX		(0x0 << DJTAG_MSTR_RW_SHIFT_EX)
+#define DJTAG_MSTR_WR_EX		(0x1 << DJTAG_MSTR_RW_SHIFT_EX)
+#define DEBUG_MODULE_SEL_SHIFT_EX	16
+#define CHAIN_UNIT_CFG_EN_EX		0xFFFF
+#define SC_DJTAG_MSTR_ADDR_EX		0xd810
+#define SC_DJTAG_MSTR_DATA_EX		0xd814
+#define SC_DJTAG_MSTR_START_EN_EX	0xd81c
+#define DJTAG_MSTR_START_EN_EX		0x1
+#define SC_DJTAG_RD_DATA_BASE_EX	0xe800
+#define SC_DJTAG_OP_ST_EX		0xe828
+#define DJTAG_OP_DONE_EX		BIT(8)
+
+static LIST_HEAD(djtag_list);
+
+struct djtag_data {
+	spinlock_t lock;
+	struct list_head list;
+	struct regmap *scl_map;
+	struct device_node *node;
+	int (*djtag_readwrite)(struct regmap *map, u32 offset,
+			u32 mod_sel, u32 mod_mask, bool is_w,
+			u32 wval, int chain_id, u32 *rval);
+};
+
+/*
+ * djtag_readwrite_v1/v2: djtag read/write interface
+ * @regmap:	djtag base address
+ * @offset:	register's offset
+ * @mod_sel:	module selection
+ * @mod_mask:	mask to select specific modules for write
+ * @is_w:	write -> true, read -> false
+ * @wval:	value to register for write
+ * @chain_id:	which sub module for read
+ * @rval:	value in register for read
+ *
+ * Return non-zero if error, else return 0.
+ */
+static int djtag_readwrite_v1(struct regmap *map, u32 offset, u32 mod_sel,
+		u32 mod_mask, bool is_w, u32 wval, int chain_id, u32 *rval)
+{
+	u32 rd;
+	int timeout = SC_DJTAG_TIMEOUT;
+
+	if (!(mod_mask & CHAIN_UNIT_CFG_EN)) {
+		pr_warn("djtag: do nothing.\n");
+		return 0;
+	}
+
+	/* djtag mster enable & accelerate R,W */
+	regmap_write(map, SC_DJTAG_MSTR_EN, DJTAG_NOR_CFG | DJTAG_MSTR_EN);
+
+	/* select module */
+	regmap_write(map, SC_DJTAG_DEBUG_MODULE_SEL, mod_sel);
+
+	regmap_write(map, SC_DJTAG_CHAIN_UNIT_CFG_EN,
+			mod_mask & CHAIN_UNIT_CFG_EN);
+
+	if (is_w) {
+		regmap_write(map, SC_DJTAG_MSTR_WR, DJTAG_MSTR_W);
+		regmap_write(map, SC_DJTAG_MSTR_DATA, wval);
+	} else
+		regmap_write(map, SC_DJTAG_MSTR_WR, DJTAG_MSTR_R);
+
+	/* address offset */
+	regmap_write(map, SC_DJTAG_MSTR_ADDR, offset);
+
+	/* start to write to djtag register */
+	regmap_write(map, SC_DJTAG_MSTR_START_EN, DJTAG_MSTR_START_EN);
+
+	/* ensure the djtag operation is done */
+	do {
+		regmap_read(map, SC_DJTAG_MSTR_START_EN, &rd);
+
+		if (!(rd & DJTAG_MSTR_EN))
+			break;
+
+		udelay(1);
+	} while (timeout--);
+
+	if (timeout < 0) {
+		pr_err("djtag: %s timeout!\n", is_w ? "write" : "read");
+		return -EBUSY;
+	}
+
+	if (!is_w)
+		regmap_read(map, SC_DJTAG_RD_DATA_BASE + chain_id * 0x4, rval);
+
+	return 0;
+}
+
+static int djtag_readwrite_v2(struct regmap *map, u32 offset, u32 mod_sel,
+		u32 mod_mask, bool is_w, u32 wval, int chain_id, u32 *rval)
+{
+	u32 rd;
+	int timeout = SC_DJTAG_TIMEOUT;
+
+	if (!(mod_mask & CHAIN_UNIT_CFG_EN_EX)) {
+		pr_warn("djtag: do nothing.\n");
+		return 0;
+	}
+
+	/* djtag mster enable */
+	regmap_write(map, SC_DJTAG_SEC_ACC_EN_EX, DJTAG_SEC_ACC_EN_EX);
+
+	if (is_w) {
+		regmap_write(map, SC_DJTAG_MSTR_CFG_EX, DJTAG_MSTR_WR_EX
+				| (mod_sel << DEBUG_MODULE_SEL_SHIFT_EX)
+				| (mod_mask & CHAIN_UNIT_CFG_EN_EX));
+		regmap_write(map, SC_DJTAG_MSTR_DATA_EX, wval);
+	} else
+		regmap_write(map, SC_DJTAG_MSTR_CFG_EX, DJTAG_MSTR_RD_EX
+				| (mod_sel << DEBUG_MODULE_SEL_SHIFT_EX)
+				| (mod_mask & CHAIN_UNIT_CFG_EN_EX));
+
+	/* address offset */
+	regmap_write(map, SC_DJTAG_MSTR_ADDR_EX, offset);
+
+	/* start to write to djtag register */
+	regmap_write(map, SC_DJTAG_MSTR_START_EN_EX, DJTAG_MSTR_START_EN_EX);
+
+	/* ensure the djtag operation is done */
+	do {
+		regmap_read(map, SC_DJTAG_MSTR_START_EN_EX, &rd);
+
+		if (!(rd & DJTAG_MSTR_START_EN_EX))
+			break;
+
+		udelay(1);
+	} while (timeout--);
+
+	if (timeout < 0)
+		goto timeout;
+
+	timeout = SC_DJTAG_TIMEOUT;
+	do {
+		regmap_read(map, SC_DJTAG_OP_ST_EX, &rd);
+
+		if (rd & DJTAG_OP_DONE_EX)
+			break;
+
+		udelay(1);
+	} while (timeout--);
+
+	if (timeout < 0)
+		goto timeout;
+
+	if (!is_w)
+		regmap_read(map, SC_DJTAG_RD_DATA_BASE_EX + chain_id * 0x4,
+				rval);
+
+	return 0;
+
+timeout:
+	pr_err("djtag: %s timeout!\n", is_w ? "write" : "read");
+	return -EBUSY;
+}
+
+
+/**
+ * djtag_writel - write registers via djtag
+ * @node:	djtag node
+ * @offset:	register's offset
+ * @mod_sel:	module selection
+ * @mod_mask:	mask to select specific modules
+ * @val:	value to write to register
+ *
+ * If error return errno, otherwise return 0.
+ */
+int hisi_djtag_writel(struct device_node *node, u32 offset, u32 mod_sel,
+			u32 mod_mask, u32 val)
+{
+	struct regmap *map;
+	unsigned long flags;
+	struct djtag_data *tmp, *p;
+	int ret = 0;
+
+	map = NULL;
+	list_for_each_entry_safe(tmp, p, &djtag_list, list) {
+		if (tmp->node == node) {
+			map = tmp->scl_map;
+
+			spin_lock_irqsave(&tmp->lock, flags);
+			ret = tmp->djtag_readwrite(map, offset, mod_sel, mod_mask,
+					true, val, 0, NULL);
+			if (ret)
+				pr_err("djtag_writel: %s: error!\n",
+						node->full_name);
+			spin_unlock_irqrestore(&tmp->lock, flags);
+			break;
+		}
+	}
+
+	if (!map)
+		return -ENODEV;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(hisi_djtag_writel);
+
+/**
+ * djtag_readl - read registers via djtag
+ * @node:	djtag node
+ * @offset:	register's offset
+ * @mod_sel:	module type selection
+ * @chain_id:	chain_id number, mostly is 0
+ * @val:	register's value
+ *
+ * If error return errno, otherwise return 0.
+ */
+int hisi_djtag_readl(struct device_node *node, u32 offset, u32 mod_sel,
+		int chain_id, u32 *val)
+{
+	struct regmap *map;
+	unsigned long flags;
+	struct djtag_data *tmp, *p;
+	int ret = 0;
+
+	map = NULL;
+	list_for_each_entry_safe(tmp, p, &djtag_list, list) {
+		if (tmp->node == node) {
+			map = tmp->scl_map;
+
+			spin_lock_irqsave(&tmp->lock, flags);
+			ret = tmp->djtag_readwrite(map, offset, mod_sel,
+					0xffff, false, 0, chain_id, val);
+			if (ret)
+				pr_err("djtag_readl: %s: error!\n",
+						node->full_name);
+			spin_unlock_irqrestore(&tmp->lock, flags);
+			break;
+		}
+	}
+
+	if (!map)
+		return -ENODEV;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(hisi_djtag_readl);
+
+static const struct of_device_id djtag_of_match[] = {
+	/* for hip05(D02) cpu die */
+	{ .compatible = "hisilicon,hip05-cpu-djtag-v1",
+		.data = (void *)djtag_readwrite_v1 },
+	/* for hip05(D02) io die */
+	{ .compatible = "hisilicon,hip05-io-djtag-v1",
+		.data = (void *)djtag_readwrite_v1 },
+	/* for hip06(D03) cpu die */
+	{ .compatible = "hisilicon,hip06-cpu-djtag-v1",
+		.data = (void *)djtag_readwrite_v1 },
+	/* for hip06(D03) io die */
+	{ .compatible = "hisilicon,hip06-io-djtag-v2",
+		.data = (void *)djtag_readwrite_v2 },
+	/* for hip07(D05) cpu die */
+	{ .compatible = "hisilicon,hip07-cpu-djtag-v2",
+		.data = (void *)djtag_readwrite_v2 },
+	/* for hip07(D05) io die */
+	{ .compatible = "hisilicon,hip07-io-djtag-v2",
+		.data = (void *)djtag_readwrite_v2 },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, djtag_of_match);
+
+static int djtag_dev_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct djtag_data *dg_data;
+	const struct of_device_id *of_id;
+
+	of_id = of_match_device(djtag_of_match, dev);
+	if (!of_id)
+		return -EINVAL;
+
+	dg_data = kzalloc(sizeof(struct djtag_data), GFP_KERNEL);
+	if (!dg_data)
+		return -ENOMEM;
+
+	dg_data->node = dev->of_node;
+	dg_data->djtag_readwrite = of_id->data;
+	spin_lock_init(&dg_data->lock);
+
+	INIT_LIST_HEAD(&dg_data->list);
+	dg_data->scl_map = syscon_regmap_lookup_by_phandle(dg_data->node,
+			"syscon");
+	if (IS_ERR(dg_data->scl_map)) {
+		dev_warn(dev, "wrong syscon register address.\n");
+		kfree(dg_data);
+		return -EINVAL;
+	}
+
+	list_add_tail(&dg_data->list, &djtag_list);
+	dev_info(dev, "%s init successfully.\n", dg_data->node->name);
+	return 0;
+}
+
+static int djtag_dev_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct djtag_data *tmp, *p;
+
+	list_for_each_entry_safe(tmp, p, &djtag_list, list) {
+		list_del(&tmp->list);
+		dev_info(dev, "%s remove successfully.\n", tmp->node->name);
+		kfree(tmp);
+	}
+
+	return 0;
+}
+
+static struct platform_driver djtag_dev_driver = {
+	.driver = {
+		.name = "hisi-djtag",
+		.of_match_table = djtag_of_match,
+	},
+	.probe = djtag_dev_probe,
+	.remove = djtag_dev_remove,
+};
+
+module_platform_driver(djtag_dev_driver);
+
+MODULE_DESCRIPTION("Hisilicon djtag driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
diff --git a/include/linux/soc/hisilicon/djtag.h b/include/linux/soc/hisilicon/djtag.h
new file mode 100644
index 0000000..2d3fc61
--- /dev/null
+++ b/include/linux/soc/hisilicon/djtag.h
@@ -0,0 +1,18 @@
+/*
+ * Driver for Hisilicon djtag r/w via System Controller.
+ *
+ * Copyright (C) 2016-2017 Hisilicon Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __HISI_DJTAG_H
+#define __HISI_DJTAG_H
+
+int hisi_djtag_readl(struct device_node *node, u32 offset, u32 mod_sel,
+						int chain_id, u32 *val);
+int hisi_djtag_writel(struct device_node *node, u32 offset, u32 mod_sel,
+						u32 mod_mask, u32 val);
+#endif /* __HISI_DJTAG_H */
-- 
2.1.4

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

* [RFC PATCH v1 03/10] arm64:perf: Add Documentaion for HIP05 PMU event counting. 1. Documentaion for perf usage and PMU events.
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 01/10] Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts bindings Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 02/10] drivers: soc: Add support for Hisilicon Djtag driver Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 04/10] arm64:perf: Add Devicetree bindings for Hisilicon SoC PMU Anurup M
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 Documentation/perf/hip05-pmu.txt | 70 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/perf/hip05-pmu.txt

diff --git a/Documentation/perf/hip05-pmu.txt b/Documentation/perf/hip05-pmu.txt
new file mode 100644
index 0000000..fd9ca26
--- /dev/null
+++ b/Documentation/perf/hip05-pmu.txt
@@ -0,0 +1,70 @@
+Hisilicon Hip05 SoC PMU (Performance Monitoring Unit)
+=====================================================
+The Hisilicon Hip05 chip consists of varous independent system device PMU's
+such as L3 cache (LLC) and Miscellaneous Nodes(MN). These PMU devices are
+independent and have hardware logic to gather statistics and performance
+information.
+
+Hip05 is encapsulated by multiple CPU and IO die's. The CPU die is called as
+Super CPU cluster (SCCL) which includes 16 cpu-cores. Every SCCL is further
+grouped as CPU clusters (CCL) which includes 4 cpu-cores each.
+Each SCCL has 1 L3 cache and 1 MN units.
+
+The L3 cache (LLC) is shared by all CPU cores in a CPU die. The LLC has four
+banks (or instances). Each bank or instance of LLC has Eight 32-bit counter
+registers to count the 22 different statistics events. These events are very
+useful for debugging. The LLC support overflow interrupt for its 8 counter
+registers.
+
+The MN module is also shared by all CPU cores in a CPU die. It receives
+barriers and DVM(Distributed Virtual Memory) messages from cpu or smmu, and
+perform the required actions and return response messages. These events are
+very useful for debugging. The MN has total 9 statistics events and support
+four 32-bit counter registers. The MN support overflow interrupt for its 4
+counter registers.
+
+There is no memory mapping for L3 cache and MN. It can be accessed by using
+the Hisilicon djtag interface. The Djtag in a SCCL is an independent module
+which connects with some modules in the SoC by Debug Bus.
+
+HIP05 PMU driver
+----------------
+The HIP05 PMU driver shall register perf PMU drivers for L3 cache and MN.
+The available events and configuration options shall be described in the sysfs.
+The "perf list" shall list the available events from sysfs.
+eg. hip05_l3c/read_allocate,cpu_die=?,bank=?/ [kernel PMU event]
+
+The event code contains the information about the cpudie, module, banks and
+the event code.
+These are represented in Perf event attributes as
+	i) event 0-11
+		The event code will be represented using the LSB 12 bits.
+	ii) bank 12-15
+		The Banks or no of instances are with 4 bits. For PMU which
+		have only single instance, this field will be ignored. For L3
+		Cache, this will identify the bank. The 0xf value shall sum the
+		count in all available banks.
+	iii) cpu_cluster 16-19
+		This identfies the CPU cluster (CCL) which share this PMU. For
+		L3 Cache, MN, DDRC etc. which are shared for a SCCL, this field
+		will be	ignored. For modules shared by a CPU cluster this can
+		represent the cluster ID. This filed is reserved and unused now.
+	iv) cpu_die 20-23
+		This identfies the supper CPU cluster (SCCL) which share this
+		PMU. For L3 Cache, MN, DDRC etc. which are shared for a SCCL
+		this field represent the CPU die ID or (SCCL ID).
+
+Example usage of perf:
+$# perf list
+hisi_l3c/read_allocate,cpu_die=?,bank=?/ [kernel PMU event]
+hisi_l3c/read_hit,cpu_die=?,bank=?/ [kernel PMU event]
+hisi_l3c/write_hit,cpu_die=?,bank=?/ [kernel PMU event]
+-------------------------------------------------------
+-------------------------------------------------------
+
+$# perf stat -a -e hisi_l3c/read_allocate,cpu_die=0x2,bank=0xf/ sleep 5
+
+$# perf stat -C 0 -A -e hisi_l3c/read_allocate,cpu_die=0x2,bank=0xf/ ls -l
+
+The current driver doesnot support sampling. so "perf record" is unsupported.
+Also attach to a task is unsupported as the events are all uncore.
-- 
2.1.4

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

* [RFC PATCH v1 04/10] arm64:perf: Add Devicetree bindings for Hisilicon SoC PMU
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (2 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 03/10] arm64:perf: Add Documentaion for HIP05 PMU event counting. 1. Documentaion for perf usage and PMU events Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 05/10] arm64:perf: Update Kconfig for Hisilicon PMU support Anurup M
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

	1) Device tree bindings for Hisilicon Hip05 PMU.
	2) Add example for Hisilicon L3 cache and MN PMU.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 .../devicetree/bindings/arm/hisilicon/pmu.txt      | 52 ++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
new file mode 100644
index 0000000..ba540db
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
@@ -0,0 +1,52 @@
+Hisilicon SoC HIP05 ARMv8 PMU
+
+The Hisilicon Hip05 chip consists of varous independent system device PMU's
+such as L3 cache (L3C) and Miscellaneous Nodes(MN). These PMU devices are
+independent and have hardware logic to gather statistics and performance
+information.
+
+Hip05 chip is encapsulated by multiple CPU and IO die's. The CPU die is called
+as Super CPU cluster (SCCL) which includes 16 cpu-cores. Every CPU SCCL is
+further grouped as CPU clusters (CCL) which includes 4 cpu-cores each.
+Each SCCL has 1 L3 cache and 1 MN units.
+
+The below section describes the bindings for L3C and MN PMU's
+
+Required Properties:
+	- compatible : This field contain two values. The first value is
+		always "hisilicon" and second value is the Module type as shown
+		in below examples:
+		(a) "hisilicon,hip05-l3c" for Hisilicon SoC L3 cache
+		(b) "hisilicon,hip05-mn" for Hisilicon SoC MN
+
+Optional Properties:
+
+	- djtag	: The registers of modules like L3 cache, MN etc. are using
+		the Hisilicon djtag interface.
+		This field contains two values. The first value is the djtag
+		node phandle and second value is the ID of the CPU die or SCCL.
+
+	- interrupt-parent : A phandle indicating which interrupt controller
+		this PMU signals interrupts to.
+
+	- interrupts : Interrupt lines used by this PMU. If the PMU has
+		multiple banks, then all IRQ lines are listed in this
+		property in the order of bank number.
+
+Example:
+	l3c0: l3c {
+		compatible = "hisilicon,hip05-l3c";
+		djtag = <&djtag0 2>; /* DJTAG node for CPU die 2
+				      * (CPU die starts from 1) */
+		interrupt-parent = <&mbigen_pc>;
+		interrupts = <141 4>,<142 4>,
+			 <143 4>,<144 4>; /* IRQ lines for 4 L3 cache banks */
+	};
+
+	mn1: mn {
+		compatible = "hisilicon,hip05-mn";
+		djtag = <&djtag0 2>; /* DJTAG node for CPU die 2
+				      * (CPU die starts from 1) */
+		interrupt-parent = <&mbigen_pc>;
+		interrupts = <146 4>;
+	};
-- 
2.1.4

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

* [RFC PATCH v1 05/10] arm64:perf: Update Kconfig for Hisilicon PMU support
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (3 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 04/10] arm64:perf: Add Devicetree bindings for Hisilicon SoC PMU Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 06/10] arm64:perf: Add support for Hisilicon SoC event counters Anurup M
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

	1. Update Kconfig for Hip05 PMU support.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/Kconfig | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 04e2653..a90b2fc 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -12,4 +12,13 @@ config ARM_PMU
 	  Say y if you want to use CPU performance monitors on ARM-based
 	  systems.
 
+config HISI_PERFCTR
+	bool "Enable hardware event counter support for HiSilicon SoC"
+	depends on HW_PERF_EVENTS && ARM64
+	select HISI_DJTAG
+	default n
+	help
+	  Enable hardware event counter support for hardware event counters
+	  in Hisilicon Hi161x SoC. The hardware modules like LLC, MN1 and
+	  DDRC have hardware events and counters.
 endmenu
-- 
2.1.4

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

* [RFC PATCH v1 06/10] arm64:perf: Add support for Hisilicon SoC event counters
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (4 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 05/10] arm64:perf: Update Kconfig for Hisilicon PMU support Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 07/10] arm64:perf: Makefile for Hisilicon Hip05 PMU Anurup M
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

	1. Hip05 uncore PMU to support different hardware
	   event counters.
	2. Hisilicon PMU shall use the DJTAG hardware interface
	   to access hardware event counters and configuration
	   register.
	3. Routines to initialize and setup PMU.
	4. Routines to enable/disable/add/del/start/stop hardware
	   event counting.
	5. Add support to count L3 cache hardware events.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_l3c.c | 511 +++++++++++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_l3c.h | 100 ++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c | 476 ++++++++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.h | 128 ++++++++
 4 files changed, 1215 insertions(+)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.h
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.h

diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c.c b/drivers/perf/hisilicon/hisi_uncore_l3c.c
new file mode 100644
index 0000000..e606cc4
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c.c
@@ -0,0 +1,511 @@
+/*
+ * HiSilicon SoC L3C Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Anurup M <anurup.m@huawei.com>
+ *
+ * This code is based on the uncore PMU's 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 <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include "hisi_uncore_l3c.h"
+
+/* Map cfg_en values for L3C Banks */
+const int l3c_cfgen_map[] = { HISI_L3C_BANK0_CFGEN, HISI_L3C_BANK1_CFGEN,
+				HISI_L3C_BANK2_CFGEN, HISI_L3C_BANK3_CFGEN
+};
+
+static struct hisi_pmu *hisi_uncore_l3c;
+
+static inline int hisi_l3c_counter_valid(int idx)
+{
+	return (idx >= HISI_IDX_L3C_COUNTER0 &&
+			idx <= HISI_IDX_L3C_COUNTER_MAX);
+}
+
+u64 hisi_l3c_event_update(struct perf_event *event,
+				struct hw_perf_event *hwc, int idx)
+{
+	struct device_node *djtag_node;
+	struct hisi_pmu *pl3c_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+	struct hisi_l3c_data *l3c_hwmod_data;
+	u64 delta, prev_raw_count, new_raw_count = 0;
+	int cfg_en;
+	u32 raw_event_code = hwc->config_base;
+	u32 scclID = (raw_event_code & HISI_SCCL_MASK) >> 20;
+	u32 l3c_idx = scclID - 1;
+	int i;
+
+	if (!scclID || (scclID >= HISI_SCCL_MASK)) {
+		pr_err("Invalid SCCL=%d in event code!\n", scclID);
+		return 0;
+	}
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		pr_err("Unsupported event index:%d!\n", idx);
+		return 0;
+	}
+
+	punit = &pl3c_pmu->hwmod_pmu_unit[l3c_idx];
+	l3c_hwmod_data = punit->hwmod_data;
+
+	/* Check if the L3C data is initialized for this SCCL */
+	if (!l3c_hwmod_data->djtag_node) {
+		pr_err("SCCL=%d not initialized!\n", scclID);
+		return 0;
+	}
+
+	/* Find the djtag device node of the SCCL */
+	djtag_node = l3c_hwmod_data->djtag_node;
+
+	do {
+		prev_raw_count = local64_read(&hwc->prev_count);
+		for (i = 0; i < l3c_hwmod_data->num_banks; i++) {
+			cfg_en = l3c_hwmod_data->bank[i].cfg_en;
+
+			new_raw_count =
+					hisi_read_l3c_counter(idx,
+							djtag_node, cfg_en);
+			delta = (new_raw_count - prev_raw_count) &
+							HISI_MAX_PERIOD;
+
+			local64_add(delta, &event->count);
+
+			pr_debug("delta for event:0x%x is %llu\n",
+						raw_event_code, delta);
+		}
+	} while (local64_cmpxchg(
+			&hwc->prev_count, prev_raw_count, new_raw_count) !=
+								prev_raw_count);
+
+	return new_raw_count;
+}
+
+void hisi_set_l3c_evtype(struct hisi_l3c_data *l3c_hwmod_data,
+						int idx, u32 val)
+{
+	struct device_node *djtag_node;
+	u32 reg_offset;
+	u32 value = 0;
+	int cfg_en;
+	u32 event_value;
+	int i;
+
+	event_value = (val -
+			HISI_HWEVENT_L3C_READ_ALLOCATE);
+
+	/* Select the appropriate Event select register */
+	if (idx <= 3)
+		reg_offset = HISI_L3C_EVENT_TYPE0_REG_OFF;
+	else
+		reg_offset = HISI_L3C_EVENT_TYPE1_REG_OFF;
+
+	/* Value to write to event type register */
+	val = event_value << (8 * idx);
+
+	/* Find the djtag device node of the Unit */
+	djtag_node = l3c_hwmod_data->djtag_node;
+
+	/*
+	 * Set the event in L3C_EVENT_TYPEx Register
+	 * for all L3C banks
+	 */
+	for (i = 0; i < l3c_hwmod_data->num_banks; i++) {
+		cfg_en = l3c_hwmod_data->bank[i].cfg_en;
+		hisi_djtag_readreg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				reg_offset,
+				djtag_node, &value);
+
+		value &= ~(0xff << (8 * idx));
+		value |= val;
+
+		hisi_djtag_writereg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				reg_offset,
+				value,
+				djtag_node);
+	}
+}
+
+u32 hisi_write_l3c_counter(struct hisi_l3c_data *l3c_hwmod_data,
+					int idx, u32 value)
+{
+	struct device_node *djtag_node;
+	int cfg_en;
+	u32 reg_offset = 0;
+	int i, ret = 0;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		pr_err("Unsupported event index:%d!\n", idx);
+		return -EINVAL;
+	}
+
+	reg_offset = HISI_L3C_COUNTER0_REG_OFF +
+					(idx * 4);
+
+	/* Find the djtag device node of the Unit */
+	djtag_node = l3c_hwmod_data->djtag_node;
+
+	for (i = 0; i < l3c_hwmod_data->num_banks; i++) {
+		cfg_en = l3c_hwmod_data->bank[i].cfg_en;
+		ret = hisi_djtag_writereg(HISI_L3C_MODULE_ID,
+					cfg_en,
+					reg_offset,
+					value,
+					djtag_node);
+		if (!ret)
+			ret = value;
+	}
+
+	return ret;
+}
+
+int hisi_enable_l3c_counter(struct hisi_l3c_data *l3c_hwmod_data, int idx)
+{
+	struct device_node *djtag_node;
+	u32 value = 0;
+	int cfg_en;
+	int i, ret = 0;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		pr_err("Unsupported event index:%d!\n", idx);
+		return -EINVAL;
+	}
+
+	/* Find the djtag device node of the Unit */
+	djtag_node = l3c_hwmod_data->djtag_node;
+
+	/*
+	 * Set the event_bus_en bit in L3C AUCNTRL to enable counting
+	 * for all L3C banks
+	 */
+	for (i = 0; i < l3c_hwmod_data->num_banks; i++) {
+		cfg_en = l3c_hwmod_data->bank[i].cfg_en;
+		ret = hisi_djtag_readreg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				HISI_L3C_AUCTRL_REG_OFF,
+				djtag_node, &value);
+
+		value |= HISI_L3C_AUCTRL_EVENT_BUS_EN;
+		ret = hisi_djtag_writereg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				HISI_L3C_AUCTRL_REG_OFF,
+				value,
+				djtag_node);
+	}
+
+	return ret;
+}
+
+void hisi_disable_l3c_counter(struct hisi_l3c_data *l3c_hwmod_data, int idx)
+{
+	struct device_node *djtag_node;
+	u32 value = 0;
+	int cfg_en;
+	int i;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		pr_err("Unsupported event index:%d!\n", idx);
+		return;
+	}
+
+	/* Find the djtag device node of the Unit */
+	djtag_node = l3c_hwmod_data->djtag_node;
+
+	/*
+	 * Clear the event_bus_en bit in L3C AUCNTRL if no other
+	 * event counting for all L3C banks
+	 */
+	for (i = 0; i < l3c_hwmod_data->num_banks; i++) {
+		cfg_en = l3c_hwmod_data->bank[i].cfg_en;
+		hisi_djtag_readreg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				HISI_L3C_AUCTRL_REG_OFF,
+				djtag_node, &value);
+
+		value &= ~(HISI_L3C_AUCTRL_EVENT_BUS_EN);
+		hisi_djtag_writereg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				HISI_L3C_AUCTRL_REG_OFF,
+				value,
+				djtag_node);
+	}
+}
+
+void hisi_clear_l3c_event_idx(struct hisi_hwmod_unit *punit,
+							int idx)
+{
+	struct device_node *djtag_node;
+	void *bitmap_addr;
+	struct hisi_l3c_data *l3c_hwmod_data = punit->hwmod_data;
+	u32 cfg_en, value, reg_offset;
+	int i;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		pr_err("Unsupported event index:%d!\n", idx);
+		return;
+	}
+
+	bitmap_addr = l3c_hwmod_data->hisi_l3c_event_used_mask;
+
+	__clear_bit(idx, bitmap_addr);
+
+	/* Clear Counting in L3C event config register */
+	if (idx <= 3)
+		reg_offset = HISI_L3C_EVENT_TYPE0_REG_OFF;
+	else
+		reg_offset = HISI_L3C_EVENT_TYPE1_REG_OFF;
+
+	djtag_node = l3c_hwmod_data->djtag_node;
+
+	/*
+	 * Clear the event in L3C_EVENT_TYPEx Register
+	 * for all L3C banks
+	 */
+	for (i = 0; i < l3c_hwmod_data->num_banks; i++) {
+		cfg_en = l3c_hwmod_data->bank[i].cfg_en;
+
+		hisi_djtag_readreg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				reg_offset,
+				djtag_node, &value);
+
+		value &= ~(0xff << (8 * idx));
+		value |= (0xff << (8 * idx));
+		hisi_djtag_writereg(HISI_L3C_MODULE_ID,
+				cfg_en,
+				reg_offset,
+				value,
+				djtag_node);
+	}
+}
+
+int hisi_l3c_get_event_idx(struct hisi_hwmod_unit *punit)
+{
+	struct hisi_l3c_data *l3c_hwmod_data = punit->hwmod_data;
+	int event_idx;
+
+	event_idx =
+		find_first_zero_bit(
+			l3c_hwmod_data->hisi_l3c_event_used_mask,
+					HISI_MAX_CFG_L3C_CNTR);
+
+	if (event_idx == HISI_MAX_CFG_L3C_CNTR)
+		return -EAGAIN;
+
+	__set_bit(event_idx,
+		l3c_hwmod_data->hisi_l3c_event_used_mask);
+
+	pr_debug("event_idx=%d\n", event_idx);
+
+	return event_idx;
+}
+
+u32 hisi_read_l3c_counter(int idx, struct device_node *djtag_node, int bank)
+{
+	u32 reg_offset = 0;
+	u32 value;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		pr_err("Unsupported event index:%d!\n", idx);
+		return -EINVAL;
+	}
+
+	reg_offset = HISI_L3C_COUNTER0_REG_OFF + (idx * 4);
+
+	hisi_djtag_readreg(HISI_L3C_MODULE_ID, /* ModuleID  */
+			bank,
+			reg_offset, /* Register Offset */
+			djtag_node, &value);
+
+	return value;
+}
+
+static int init_hisi_l3c_banks(struct hisi_l3c_data *pl3c_data,
+				struct platform_device *pdev)
+{
+	int i;
+
+	pl3c_data->num_banks = NUM_L3C_BANKS;
+	for (i = 0; i < NUM_L3C_BANKS; i++)
+		pl3c_data->bank[i].cfg_en = l3c_cfgen_map[i];
+
+	return 0;
+}
+
+static int init_hisi_l3c_data(struct platform_device *pdev,
+					struct hisi_pmu *pl3c_pmu,
+							int *punit_id)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct device_node *djtag_node;
+	struct hisi_hwmod_unit *punit;
+	struct hisi_l3c_data *l3c_hwmod_data;
+	struct of_phandle_args arg;
+	int ret, sccl_id;
+
+	ret = of_parse_phandle_with_fixed_args(node,
+						"djtag", 1, 0, &arg);
+	if (!ret) {
+		if (arg.args[0] > 0  && arg.args[0] <= MAX_UNITS) {
+			sccl_id = arg.args[0];
+			djtag_node = arg.np;
+			if (sccl_id >= MAX_UNITS) {
+				pr_err("l3c_device_probe-Invalid SCCL=%d!\n",
+						sccl_id);
+				return -EINVAL;
+			}
+		} else
+			return -EINVAL;
+	} else {
+		pr_err("l3c_device_probe-node without djtag!\n");
+		return -EINVAL;
+	}
+
+	l3c_hwmod_data = kzalloc(sizeof(struct hisi_l3c_data), GFP_KERNEL);
+	if (!l3c_hwmod_data)
+		return -ENOMEM;
+
+	l3c_hwmod_data->djtag_node = djtag_node;
+	punit = &pl3c_pmu->hwmod_pmu_unit[sccl_id - 1];
+
+	ret = hisi_pmu_unit_init(pdev, punit, sccl_id,
+					HISI_MAX_CFG_L3C_CNTR);
+	if (ret) {
+		kfree(l3c_hwmod_data);
+		return ret;
+	}
+
+	ret = init_hisi_l3c_banks(l3c_hwmod_data, pdev);
+	if (ret) {
+		kfree(l3c_hwmod_data);
+		return ret;
+	}
+
+	punit->hwmod_data = l3c_hwmod_data;
+
+	*punit_id = sccl_id - 1;
+	return 0;
+}
+
+static void hisi_free_l3c_data(struct hisi_hwmod_unit *punit)
+{
+	kfree(punit->hwmod_data);
+}
+
+void hisi_l3c_pmu_init(struct platform_device *pdev,
+					struct hisi_pmu *pl3c_pmu)
+{
+	pl3c_pmu->pmu_type = SCCL_SPECIFIC;
+	pl3c_pmu->name = "hip05_l3c";
+	pl3c_pmu->num_counters = HISI_MAX_CFG_L3C_CNTR;
+	pl3c_pmu->num_events = HISI_L3C_MAX_EVENTS;
+	pl3c_pmu->hwmod_type = HISI_L3C;
+}
+
+static int hisi_pmu_l3c_dev_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct hisi_pmu *pl3c_pmu = hisi_uncore_l3c;
+	struct hisi_hwmod_unit *punit;
+	int unit_id;
+
+	/* Allocate and Register PMU for the first time */
+	if (!hisi_uncore_l3c) {
+		pl3c_pmu = hisi_pmu_alloc(pdev);
+		if (IS_ERR(pl3c_pmu))
+			return PTR_ERR(pl3c_pmu);
+		hisi_l3c_pmu_init(pdev, pl3c_pmu);
+	}
+
+	ret = init_hisi_l3c_data(pdev, pl3c_pmu, &unit_id);
+	if (ret)
+		goto fail_init;
+
+	pl3c_pmu->num_units++;
+
+	pl3c_pmu->plat_device = pdev;
+	hisi_l3c_pmu_init(pdev, pl3c_pmu);
+
+	if (!hisi_uncore_l3c) {
+		/* First active L3C in the chip registers the pmu */
+		pl3c_pmu->pmu = (struct pmu) {
+				.name		= "hip05_l3c",
+				.task_ctx_nr	= perf_invalid_context,
+				.pmu_enable = hisi_uncore_pmu_enable,
+				.pmu_disable = hisi_uncore_pmu_disable,
+				.event_init = hisi_uncore_pmu_event_init,
+				.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,
+		};
+
+		ret = hisi_uncore_pmu_setup(pl3c_pmu, pdev, "hip05_l3c");
+		if (ret) {
+			pr_err("hisi_uncore_pmu_init FAILED!!\n");
+			goto fail;
+		}
+
+		hisi_uncore_l3c = pl3c_pmu;
+	}
+
+	return 0;
+
+fail:
+	punit = &pl3c_pmu->hwmod_pmu_unit[unit_id];
+	hisi_free_l3c_data(punit);
+
+fail_init:
+	if (!hisi_uncore_l3c)
+		devm_kfree(&pdev->dev, pl3c_pmu);
+
+	return ret;
+}
+
+static int hisi_pmu_l3c_dev_remove(struct platform_device *pdev)
+{
+	if (hisi_uncore_l3c)
+		devm_kfree(&pdev->dev, hisi_uncore_l3c);
+
+	return 0;
+}
+
+static const struct of_device_id l3c_of_match[] = {
+	{ .compatible = "hisilicon,hip05-l3c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, l3c_of_match);
+
+static struct platform_driver hisi_pmu_l3c_driver = {
+	.driver = {
+		.name = "hip05-l3c-pmu",
+		.of_match_table = l3c_of_match,
+	},
+	.probe = hisi_pmu_l3c_dev_probe,
+	.remove = hisi_pmu_l3c_dev_remove,
+};
+module_platform_driver(hisi_pmu_l3c_driver);
+
+MODULE_DESCRIPTION("HiSilicon HIP05 L3C PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Anurup M");
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c.h b/drivers/perf/hisilicon/hisi_uncore_l3c.h
new file mode 100644
index 0000000..389e228
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c.h
@@ -0,0 +1,100 @@
+/*
+ * HiSilicon SoC L3C Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Anurup M <anurup.m@huawei.com>
+ *
+ * This code is based on the uncore PMU's 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 <http://www.gnu.org/licenses/>.
+ */
+#ifndef __HISI_UNCORE_L3C_H__
+#define __HISI_UNCORE_L3C_H__
+
+#include "hisi_uncore_pmu.h"
+
+/*
+ * ARMv8 HiSilicon L3C RAW event types.
+ */
+enum armv8_hisi_l3c_event_types {
+	HISI_HWEVENT_L3C_READ_ALLOCATE		= 0x300,
+	HISI_HWEVENT_L3C_WRITE_ALLOCATE		= 0x301,
+	HISI_HWEVENT_L3C_READ_NOALLOCATE	= 0x302,
+	HISI_HWEVENT_L3C_WRITE_NOALLOCATE	= 0x303,
+	HISI_HWEVENT_L3C_READ_HIT		= 0x304,
+	HISI_HWEVENT_L3C_WRITE_HIT		= 0x305,
+	HISI_HWEVENT_L3C_EVENT_MAX		= 0x315,
+};
+
+/*
+ * ARMv8 HiSilicon Hardware counter Index.
+ */
+enum armv8_hisi_l3c_counters {
+	HISI_IDX_L3C_COUNTER0		= 0x0,
+	HISI_IDX_L3C_COUNTER_MAX	= 0x7,
+};
+
+#define HISI_L3C_MODULE_ID	0x04
+
+#define HISI_L3C_BANK0_CFGEN  0x02
+#define HISI_L3C_BANK1_CFGEN  0x04
+#define HISI_L3C_BANK2_CFGEN  0x01
+#define HISI_L3C_BANK3_CFGEN  0x08
+
+#define HISI_L3C_AUCTRL_REG_OFF 0x04
+#define HISI_L3C_AUCTRL_EVENT_BUS_EN 0x1000000
+
+#define HISI_L3C_EVENT_TYPE0_REG_OFF 0x140
+#define HISI_L3C_EVENT_TYPE1_REG_OFF 0x144
+
+#define HISI_MAX_CFG_L3C_CNTR	0x08
+
+#define HISI_L3C_COUNTER0_REG_OFF 0x170
+
+#define HISI_L3C_MAX_EVENTS 22
+
+#define NUM_L3C_BANKS 4
+
+struct hisi_hwc_prev_counter {
+	local64_t prev_count;
+};
+
+struct hisi_l3c_hwc_data_info {
+	u32 num_banks;
+	struct hisi_hwc_prev_counter *hwc_prev_counters;
+};
+
+struct l3c_bank_info {
+	u32 cfg_en;
+};
+
+struct hisi_l3c_data {
+	struct device_node *djtag_node;
+	DECLARE_BITMAP(hisi_l3c_event_used_mask,
+				HISI_MAX_CFG_L3C_CNTR);
+	u32 num_banks;
+	struct l3c_bank_info bank[MAX_BANKS];
+};
+
+int hisi_l3c_get_event_idx(struct hisi_hwmod_unit *);
+void hisi_clear_l3c_event_idx(struct hisi_hwmod_unit *,	int);
+void hisi_set_l3c_evtype(struct hisi_l3c_data *, int, u32);
+u32 hisi_read_l3c_counter(int, struct device_node *, int);
+u32 hisi_write_l3c_counter(struct hisi_l3c_data *, int, u32);
+u64 hisi_l3c_event_update(struct perf_event *,
+				struct hw_perf_event *, int);
+void hisi_disable_l3c_counter(struct hisi_l3c_data *, int);
+int hisi_enable_l3c_counter(struct hisi_l3c_data *, int);
+
+#endif /* __HISI_UNCORE_L3C_H__ */
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
new file mode 100644
index 0000000..d0dffc3
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -0,0 +1,476 @@
+/*
+ * HiSilicon SoC Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Anurup M <anurup.m@huawei.com>
+ *
+ * This code is based on the uncore PMU's 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 <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitmap.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include "hisi_uncore_l3c.h"
+#include "hisi_uncore_pmu.h"
+
+/* djtag read interface - Call djtag driver to access SoC registers */
+int hisi_djtag_readreg(int module_id, int bank, u32 offset,
+				struct device_node *djtag_node, u32 *pvalue)
+{
+	int ret;
+	u32 chain_id = 0;
+
+	while (bank != 1) {
+		bank = (bank >> 0x1);
+		chain_id++;
+	}
+
+	ret = hisi_djtag_readl(djtag_node, offset, module_id,
+							chain_id, pvalue);
+	if (ret)
+		pr_warn("Djtag:%s Read failed!\n", djtag_node->full_name);
+
+	return ret;
+}
+
+/* djtag write interface - Call djtag driver  to access SoC registers */
+int hisi_djtag_writereg(int module_id, int bank,
+				u32 offset, u32 value,
+				struct device_node *djtag_node)
+{
+	int ret;
+
+	ret = hisi_djtag_writel(djtag_node, offset, module_id,
+						HISI_DJTAG_MOD_MASK, value);
+	if (ret)
+		pr_warn("Djtag:%s Write failed!\n", djtag_node->full_name);
+
+	return ret;
+}
+
+void hisi_uncore_pmu_write_evtype(struct hisi_hwmod_unit *punit,
+						int idx, u32 val)
+{
+	/* Select event based on Hardware counter Module */
+	if (idx >= HISI_IDX_L3C_COUNTER0 &&
+		idx <= HISI_IDX_L3C_COUNTER_MAX)
+		hisi_set_l3c_evtype(punit->hwmod_data, idx, val);
+}
+
+int hisi_pmu_get_event_idx(struct hw_perf_event *hwc,
+						struct hisi_hwmod_unit *punit)
+{
+	int event_idx = -1;
+	u32 raw_event_code = hwc->config_base;
+	unsigned long evtype = raw_event_code & HISI_EVTYPE_EVENT;
+
+	/* Get the available hardware event counter index */
+	/* If event type is L3C events */
+	if (evtype >= HISI_HWEVENT_L3C_READ_ALLOCATE &&
+			evtype <= HISI_HWEVENT_L3C_EVENT_MAX) {
+		event_idx = hisi_l3c_get_event_idx(punit);
+	}
+
+	return event_idx;
+}
+
+void hisi_pmu_clear_event_idx(struct hw_perf_event *hwc,
+					struct hisi_hwmod_unit *punit,
+								int idx)
+{
+	/* Release the hardware event counter index */
+	u32 raw_event_code = hwc->config_base;
+	unsigned long evtype = raw_event_code & HISI_EVTYPE_EVENT;
+
+	if (evtype >= HISI_HWEVENT_L3C_READ_ALLOCATE &&
+			evtype <= HISI_HWEVENT_L3C_EVENT_MAX) {
+		hisi_clear_l3c_event_idx(punit, idx);
+	}
+}
+
+static int pmu_map_event(struct perf_event *event)
+{
+	return (int)(event->attr.config & HISI_EVTYPE_EVENT);
+}
+
+static int
+__hw_perf_event_init(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int mapping;
+
+	mapping = pmu_map_event(event);
+	if (mapping < 0) {
+		pr_debug("event %x:%llx not supported\n", event->attr.type,
+							 event->attr.config);
+		return mapping;
+	}
+
+	/*
+	 * We don't assign an index until we actually place the event onto
+	 * hardware. Use -1 to signify that we haven't decided where to put it
+	 * yet.
+	 */
+	hwc->idx		= -1;
+	hwc->config_base	= 0;
+	hwc->config		= 0;
+	hwc->event_base		= 0;
+
+	/*
+	 * For HiSilicon SoC store the event encoding into the config_base
+	 * field.
+	 */
+	/* For HiSilicon SoC L3C update config_base based on event encoding */
+	if (mapping >= HISI_HWEVENT_L3C_READ_ALLOCATE &&
+				mapping <= HISI_HWEVENT_L3C_EVENT_MAX) {
+		hwc->config_base = event->attr.config;
+	} else {
+		return -EINVAL;
+	}
+
+	/*
+	 * Limit the sample_period to half of the counter width. That way, the
+	 * new counter value is far less likely to overtake the previous one
+	 * unless you have some serious IRQ latency issues.
+	 */
+	hwc->sample_period  = HISI_MAX_PERIOD >> 1;
+	hwc->last_period    = hwc->sample_period;
+	local64_set(&hwc->period_left, hwc->sample_period);
+
+	return 0;
+}
+
+int hisi_uncore_pmu_event_init(struct perf_event *event)
+{
+	struct hisi_pmu *phisi_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+	u32 raw_event_code = event->attr.config;
+	int err;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/* we do not support sampling as the counters are all
+	 * shared by all CPU cores in a CPU die(SCCL). Also we
+	 * donot support attach to a task(per-process mode)
+	 */
+	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+		return -EOPNOTSUPP;
+
+	/* counters do not have these bits */
+	if (event->attr.exclude_user	||
+	    event->attr.exclude_kernel	||
+	    event->attr.exclude_host	||
+	    event->attr.exclude_guest	||
+	    event->attr.exclude_hv	||
+	    event->attr.exclude_idle)
+		return -EINVAL;
+
+//	if (event->cpu < 0)
+//		return -EINVAL;
+
+	/* FIXME: event->cpu = cpumask_first(&pmu_dev->parent->cpu);
+	 */
+
+	punit = &phisi_pmu->hwmod_pmu_unit[GET_UNIT_IDX(raw_event_code)];
+
+	err = __hw_perf_event_init(event);
+
+	return err;
+}
+
+
+/* Read hardware counter and update the Perf counter statistics */
+u64 hisi_uncore_pmu_event_update(struct perf_event *event,
+					struct hw_perf_event *hwc,
+							int idx) {
+	u64 new_raw_count = 0;
+	int cntr_idx = idx & ~(HISI_CNTR_SCCL_MASK);
+
+	/*
+	 * Identify Event type and read appropriate hardware
+	 * counter and sum the values
+	 */
+	if (cntr_idx >= HISI_IDX_L3C_COUNTER0 &&
+		cntr_idx <= HISI_IDX_L3C_COUNTER_MAX)
+		new_raw_count = hisi_l3c_event_update(event, hwc, idx);
+
+	return new_raw_count;
+}
+
+void hisi_uncore_pmu_enable(struct pmu *pmu)
+{
+	/* Enable all the PMU counters. */
+}
+
+void hisi_uncore_pmu_disable(struct pmu *pmu)
+{
+	/* Disable all the PMU counters. */
+}
+
+int hisi_pmu_enable_counter(struct hisi_hwmod_unit *punit,
+							int idx)
+{
+	int ret = 0;
+
+	/* Enable the hardware event counting */
+	if (idx >= HISI_IDX_L3C_COUNTER0 &&
+		idx <= HISI_IDX_L3C_COUNTER_MAX)
+		ret = hisi_enable_l3c_counter(punit->hwmod_data, idx);
+
+	return ret;
+}
+
+void hisi_pmu_disable_counter(struct hisi_hwmod_unit *punit,
+							int idx)
+{
+	/* Disable the hardware event counting */
+	int cntr_idx = idx & ~(HISI_CNTR_SCCL_MASK);
+
+	if (cntr_idx >= HISI_IDX_L3C_COUNTER0 &&
+		 cntr_idx <= HISI_IDX_L3C_COUNTER_MAX)
+		hisi_disable_l3c_counter(punit->hwmod_data, idx);
+}
+
+/*
+ * Enable counter and set the counter to count
+ * the event that we're interested in.
+ */
+void hisi_uncore_pmu_enable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *phisi_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+
+	punit = &phisi_pmu->hwmod_pmu_unit[GET_UNIT_IDX(hwc->config_base)];
+
+	/*
+	 * Disable counter
+	 */
+	hisi_pmu_disable_counter(punit, GET_CNTR_IDX(hwc));
+
+	/*
+	 * Set event (if destined for Hisilicon SoC counters).
+	 */
+	hisi_uncore_pmu_write_evtype(punit, GET_CNTR_IDX(hwc),
+						hwc->config_base);
+
+	/*
+	 * Enable counter
+	 */
+	hisi_pmu_enable_counter(punit, GET_CNTR_IDX(hwc));
+
+}
+
+int hisi_pmu_write_counter(struct hisi_hwmod_unit *punit,
+						int idx,
+						u32 value)
+{
+	int ret = 0;
+
+	/* Write to the hardware event counter */
+	if (idx >= HISI_IDX_L3C_COUNTER0 &&
+		idx <= HISI_IDX_L3C_COUNTER_MAX)
+		ret = hisi_write_l3c_counter(punit->hwmod_data, idx, value);
+
+	return ret;
+}
+
+void hisi_pmu_event_set_period(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *phisi_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+
+	/*
+	 * The Hisilicon PMU counters have a period of 2^32. To account for the
+	 * possiblity of extreme interrupt latency we program for a period of
+	 * half that. Hopefully we can handle the interrupt before another 2^31
+	 * events occur and the counter overtakes its previous value.
+	 */
+	u64 val = 1ULL << 31;
+
+	punit = &phisi_pmu->hwmod_pmu_unit[GET_UNIT_IDX(hwc->config_base)];
+	local64_set(&hwc->prev_count, val);
+	hisi_pmu_write_counter(punit, GET_CNTR_IDX(hwc), val);
+}
+
+void hisi_uncore_pmu_start(struct perf_event *event,
+						int pmu_flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *phisi_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+	struct hisi_pmu_hw_events *hw_events;
+	u32 unit_idx = GET_UNIT_IDX(hwc->config_base);
+	unsigned long flags;
+
+	if (unit_idx >= (HISI_SCCL_MAX - 1)) {
+		pr_err("Invalid unitID=%d in event code=%lu!\n",
+					unit_idx + 1, hwc->config_base);
+		return;
+	}
+
+	punit = &phisi_pmu->hwmod_pmu_unit[unit_idx];
+	hw_events = &punit->hw_events;
+
+	/*
+	 * To handle interrupt latency, we always reprogram the period
+	 * regardlesss of PERF_EF_RELOAD.
+	 */
+	if (pmu_flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+	hwc->state = 0;
+
+	raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
+
+	hisi_pmu_event_set_period(event);
+	hisi_uncore_pmu_enable_event(event);
+
+	raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
+}
+
+void hisi_uncore_pmu_stop(struct perf_event *event,
+						int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *phisi_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+
+	if (hwc->state & PERF_HES_STOPPED)
+		return;
+
+	punit = &phisi_pmu->hwmod_pmu_unit[GET_UNIT_IDX(hwc->config_base)];
+
+	/*
+	 * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
+	 * hisi_uncore_pmu_start()
+	 */
+	hisi_pmu_disable_counter(punit, GET_CNTR_IDX(hwc));
+	hisi_uncore_pmu_event_update(event, hwc, GET_CNTR_IDX(hwc));
+	hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+}
+
+int hisi_uncore_pmu_add(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *phisipmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+	struct hisi_pmu_hw_events *hw_events;
+	u32 unit_idx = GET_UNIT_IDX(hwc->config_base);
+	int idx, err = 0;
+
+	if (unit_idx >= (HISI_SCCL_MAX - 1)) {
+		pr_err("Invalid unitID=%d in event code=%lu\n",
+					unit_idx + 1, hwc->config_base);
+		return -EINVAL;
+	}
+
+	punit = &phisipmu->hwmod_pmu_unit[unit_idx];
+	hw_events = &punit->hw_events;
+
+	/* If we don't have a free counter then return early. */
+	idx = hisi_pmu_get_event_idx(hwc, punit);
+	if (idx < 0) {
+		err = idx;
+		goto out;
+	}
+
+	event->hw.idx = idx;
+	hw_events->events[idx] = event;
+
+	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	if (flags & PERF_EF_START)
+		hisi_uncore_pmu_start(event, PERF_EF_RELOAD);
+
+	/* Propagate our changes to the userspace mapping. */
+	perf_event_update_userpage(event);
+
+out:
+	return err;
+}
+
+void hisi_uncore_pmu_del(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *phisipmu = to_hisi_pmu(event->pmu);
+	struct hisi_hwmod_unit *punit;
+	struct hisi_pmu_hw_events *hw_events;
+
+	punit = &phisipmu->hwmod_pmu_unit[GET_UNIT_IDX(hwc->config_base)];
+	hw_events = &punit->hw_events;
+
+	hisi_uncore_pmu_stop(event, PERF_EF_UPDATE);
+	hw_events->events[GET_CNTR_IDX(hwc)] = NULL;
+
+	hisi_pmu_clear_event_idx(hwc, punit, GET_CNTR_IDX(hwc));
+
+	perf_event_update_userpage(event);
+}
+
+struct hisi_pmu *hisi_pmu_alloc(struct platform_device *pdev)
+{
+	struct hisi_pmu *phisipmu;
+
+	phisipmu = devm_kzalloc(&pdev->dev, sizeof(*phisipmu), GFP_KERNEL);
+	if (!phisipmu)
+		return ERR_PTR(-ENOMEM);
+
+	return phisipmu;
+}
+
+int hisi_pmu_unit_init(struct platform_device *pdev,
+				struct hisi_hwmod_unit *punit,
+						int unit_id,
+						int num_counters)
+{
+	punit->hw_events.events = devm_kcalloc(&pdev->dev,
+				     num_counters,
+				     sizeof(*punit->hw_events.events),
+							     GFP_KERNEL);
+	if (!punit->hw_events.events)
+		return -ENOMEM;
+
+	raw_spin_lock_init(&punit->hw_events.pmu_lock);
+
+	punit->unit_id = unit_id;
+
+	return 0;
+}
+
+void hisi_uncore_pmu_read(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	hisi_uncore_pmu_event_update(event, hwc, GET_CNTR_IDX(hwc));
+}
+
+int hisi_uncore_pmu_setup(struct hisi_pmu *hisipmu,
+				struct platform_device *pdev,
+						char *pmu_name)
+{
+	int ret;
+
+	/* Register the events with perf */
+	ret = perf_pmu_register(&hisipmu->pmu, pmu_name, -1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
new file mode 100644
index 0000000..75ef282
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -0,0 +1,128 @@
+/*
+ * HiSilicon SoC Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Anurup M <anurup.m@huawei.com>
+ *
+ * This code is based on the uncore PMU's 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 <http://www.gnu.org/licenses/>.
+ */
+#ifndef __HISI_UNCORE_PMU_H__
+#define __HISI_UNCORE_PMU_H__
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/soc/hisilicon/djtag.h>
+#include <linux/types.h>
+#include <asm/local64.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "hisi_pmu: " fmt
+
+#define HISI_DJTAG_MOD_MASK (0xFFFF)
+
+#define HISI_CNTR_SCCL_MASK    (0xF00)
+
+#define HISI_SCCL_MAX	(1 << 4)
+#define HISI_SCCL_MASK	(0xF00000)
+#define HISI_SCCL_SHIFT 20
+
+#define HISI_EVTYPE_EVENT	0xfff
+#define HISI_MAX_PERIOD ((1LLU << 32) - 1)
+
+#define MAX_BANKS 8
+#define MAX_COUNTERS 30
+#define MAX_UNITS 8
+
+#define GET_CNTR_IDX(hwc) (hwc->idx)
+#define to_hisi_pmu(c)	(container_of(c, struct hisi_pmu, pmu))
+
+#define GET_UNIT_IDX(event_code)		\
+	(((event_code & HISI_SCCL_MASK) >>	\
+			   HISI_SCCL_SHIFT) - 1)
+
+enum hisi_hwmod_type {
+	HISI_L3C = 0x0,
+};
+
+/* Event granularity */
+enum hisi_pmu_type {
+	CORE_SPECIFIC,
+	CCL_SPECIFIC, /* For future use */
+	SCCL_SPECIFIC,
+	CHIP_SPECIFIC, /* For future use */
+};
+
+struct hisi_pmu_hw_events {
+	struct perf_event **events;
+	raw_spinlock_t pmu_lock;
+};
+
+/* Hardware module information */
+struct hisi_hwmod_unit {
+	   int unit_id;
+	   struct hisi_pmu_hw_events hw_events;
+	   void *hwmod_data;
+};
+
+/* Generic pmu struct for different pmu types */
+struct hisi_pmu {
+	const char *name;
+	enum hisi_pmu_type pmu_type;
+	enum hisi_hwmod_type hwmod_type;
+	int num_counters;
+	int	num_events;
+	struct perf_event *events[MAX_COUNTERS];
+	int num_units;
+	struct hisi_hwmod_unit hwmod_pmu_unit[MAX_UNITS];
+	struct pmu pmu; /* for custom pmu ops */
+	struct platform_device *plat_device;
+};
+
+u64 hisi_pmu_event_update(struct perf_event *,
+				struct hw_perf_event *, int);
+int hisi_pmu_enable_counter(struct hisi_hwmod_unit *, int);
+void hisi_pmu_disable_counter(struct hisi_hwmod_unit *, int);
+int hisi_pmu_write_counter(struct hisi_hwmod_unit *, int, u32);
+void hisi_pmu_write_evtype(int, u32);
+int hisi_pmu_get_event_idx(struct hw_perf_event *,
+				struct hisi_hwmod_unit *);
+void hisi_pmu_clear_event_idx(struct hw_perf_event *,
+				struct hisi_hwmod_unit *, int);
+void hisi_uncore_pmu_read(struct perf_event *);
+void hisi_uncore_pmu_del(struct perf_event *, int);
+int hisi_uncore_pmu_add(struct perf_event *, int);
+void hisi_uncore_pmu_start(struct perf_event *, int);
+void hisi_uncore_pmu_stop(struct perf_event *, int);
+void hisi_pmu_event_set_period(struct perf_event *);
+void hisi_uncore_pmu_enable_event(struct perf_event *);
+void hisi_uncore_pmu_disable_event(struct perf_event *);
+void hisi_uncore_pmu_enable(struct pmu *);
+void hisi_uncore_pmu_disable(struct pmu *);
+struct hisi_pmu *hisi_uncore_pmu_alloc(struct platform_device *);
+int hisi_uncore_pmu_setup(struct hisi_pmu *hisi_pmu,
+				struct platform_device *, char *);
+void hisi_uncore_pmu_write_evtype(struct hisi_hwmod_unit *, int, u32);
+int hisi_uncore_pmu_event_init(struct perf_event *);
+int hisi_djtag_readreg(int, int, u32, struct device_node *, u32 *);
+int hisi_djtag_writereg(int, int, u32, u32, struct device_node *);
+int hisi_pmu_unit_init(struct platform_device *,
+				struct hisi_hwmod_unit *,
+						int, int);
+struct hisi_pmu *hisi_pmu_alloc(struct platform_device *);
+#endif /* __HISI_UNCORE_PMU_H__ */
-- 
2.1.4

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

* [RFC PATCH v1 07/10] arm64:perf: Makefile for Hisilicon Hip05 PMU
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (5 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 06/10] arm64:perf: Add support for Hisilicon SoC event counters Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 08/10] arm64:perf: Update Makefile for Hisilicon PMU support Anurup M
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

	1. Add Makefile for Hip05 uncore PMU support.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/Makefile | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 drivers/perf/hisilicon/Makefile

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
new file mode 100644
index 0000000..dc4c4dd
--- /dev/null
+++ b/drivers/perf/hisilicon/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HISI_PERFCTR) += hisi_uncore_pmu.o hisi_uncore_l3c.o
-- 
2.1.4

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

* [RFC PATCH v1 08/10] arm64:perf: Update Makefile for Hisilicon PMU support
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (6 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 07/10] arm64:perf: Makefile for Hisilicon Hip05 PMU Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 09/10] arm64:perf: L3 cache(LLC) event listing in perf Anurup M
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

	1. Update Makefile for Hisilicon Hip05 PMU support.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index acd2397..7f051ad 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_HISI_PERFCTR) += hisilicon/
-- 
2.1.4

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

* [RFC PATCH v1 09/10] arm64:perf: L3 cache(LLC) event listing in perf
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (7 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 08/10] arm64:perf: Update Makefile for Hisilicon PMU support Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-04  9:07 ` [RFC PATCH v1 10/10] arm64: dts: hip05: Add L3 cache PMU support Anurup M
  2016-08-18 11:59 ` [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters John Garry
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

	1. Add L3 caches events to /sys/devices/hisi_l3c/events/
	   The events can be selected as shown in perf list
	   e.g.: For L3C_READ_ALLOCATE event for Super CPU cluster 2 the
		 event format is
		 -e "hisi_l3c/l3c_read_allocate,bank=0xf,cpu_die=0x2/"

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_l3c.c | 50 ++++++++++++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c | 28 ++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.h | 20 +++++++++++++
 3 files changed, 98 insertions(+)

diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c.c b/drivers/perf/hisilicon/hisi_uncore_l3c.c
index e606cc4..1c5e8d9 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c.c
@@ -411,6 +411,55 @@ static void hisi_free_l3c_data(struct hisi_hwmod_unit *punit)
 	kfree(punit->hwmod_data);
 }
 
+static struct attribute *hisi_l3c_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-11"),
+	HISI_PMU_FORMAT_ATTR(bank, "config:12-15"),
+	HISI_PMU_FORMAT_ATTR(cpu_cluster, "config:16-19"),
+	HISI_PMU_FORMAT_ATTR(cpu_die, "config:20-23"),
+	NULL,
+};
+
+static struct attribute_group hisi_l3c_format_group = {
+	.name = "format",
+	.attrs = hisi_l3c_format_attr,
+};
+
+static struct attribute *hisi_l3c_events_attr[] = {
+	HISI_PMU_EVENT_ATTR_STR(read_allocate,
+			"event=0x301,bank=?,cpu_die=?"),
+	HISI_PMU_EVENT_ATTR_STR(write_allocate,
+			"event=0x302,bank=?,cpu_die=?"),
+	HISI_PMU_EVENT_ATTR_STR(read_noallocate,
+			"event=0x303,bank=?,cpu_die=?"),
+	HISI_PMU_EVENT_ATTR_STR(write_noallocate,
+			"event=0x304,bank=?,cpu_die=?"),
+	HISI_PMU_EVENT_ATTR_STR(read_hit,
+			"event=0x305,bank=?,cpu_die=?"),
+	HISI_PMU_EVENT_ATTR_STR(write_hit,
+			"event=0x306,bank=?,cpu_die=?"),
+	NULL,
+};
+
+static struct attribute_group hisi_l3c_events_group = {
+	.name = "events",
+	.attrs = hisi_l3c_events_attr,
+};
+
+static struct attribute *hisi_l3c_attrs[] = {
+	NULL,
+};
+
+struct attribute_group hisi_l3c_attr_group = {
+	.attrs = hisi_l3c_attrs,
+};
+
+static const struct attribute_group *hisi_l3c_pmu_attr_groups[] = {
+	&hisi_l3c_attr_group,
+	&hisi_l3c_format_group,
+	&hisi_l3c_events_group,
+	NULL
+};
+
 void hisi_l3c_pmu_init(struct platform_device *pdev,
 					struct hisi_pmu *pl3c_pmu)
 {
@@ -458,6 +507,7 @@ static int hisi_pmu_l3c_dev_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,
 		};
 
 		ret = hisi_uncore_pmu_setup(pl3c_pmu, pdev, "hip05_l3c");
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index d0dffc3..4c81477 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -27,6 +27,34 @@
 #include "hisi_uncore_l3c.h"
 #include "hisi_uncore_pmu.h"
 
+/*
+ * PMU format attributes
+ */
+ssize_t hisi_format_sysfs_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr;
+
+	eattr = container_of(attr, struct dev_ext_attribute,
+					     attr);
+	return sprintf(buf, "%s\n", (char *) eattr->var);
+}
+
+/*
+ * PMU event attributes
+ */
+ssize_t hisi_event_sysfs_show(struct device *dev,
+				  struct device_attribute *attr, char *page)
+{
+	struct perf_pmu_events_attr *pmu_attr =
+		container_of(attr, struct perf_pmu_events_attr, attr);
+
+	if (pmu_attr->event_str)
+		return sprintf(page, "%s", pmu_attr->event_str);
+
+	return 0;
+}
+
 /* djtag read interface - Call djtag driver to access SoC registers */
 int hisi_djtag_readreg(int module_id, int bank, u32 offset,
 				struct device_node *djtag_node, u32 *pvalue)
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index 75ef282..e93690d 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -56,6 +56,22 @@
 	(((event_code & HISI_SCCL_MASK) >>	\
 			   HISI_SCCL_SHIFT) - 1)
 
+#define HISI_PMU_FORMAT_ATTR(_name, _config)		\
+	(&((struct dev_ext_attribute[]) {		\
+		{ .attr = __ATTR(_name, S_IRUGO,	\
+			hisi_format_sysfs_show, NULL),	\
+		  .var = (void *) _config,		\
+		}					\
+	})[0].attr.attr)
+
+#define HISI_PMU_EVENT_ATTR_STR(_name, _str)		\
+	(&((struct perf_pmu_events_attr[]) {		\
+		{ .attr = __ATTR(_name, S_IRUGO,	\
+			 hisi_event_sysfs_show, NULL),	\
+		  .event_str = _str,			\
+		}					\
+	  })[0].attr.attr)
+
 enum hisi_hwmod_type {
 	HISI_L3C = 0x0,
 };
@@ -125,4 +141,8 @@ int hisi_pmu_unit_init(struct platform_device *,
 				struct hisi_hwmod_unit *,
 						int, int);
 struct hisi_pmu *hisi_pmu_alloc(struct platform_device *);
+ssize_t hisi_event_sysfs_show(struct device *,
+				  struct device_attribute *, char *);
+ssize_t hisi_format_sysfs_show(struct device *,
+				  struct device_attribute *, char *);
 #endif /* __HISI_UNCORE_PMU_H__ */
-- 
2.1.4

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

* [RFC PATCH v1 10/10]  arm64: dts: hip05: Add L3 cache PMU support
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (8 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 09/10] arm64:perf: L3 cache(LLC) event listing in perf Anurup M
@ 2016-08-04  9:07 ` Anurup M
  2016-08-18 11:59 ` [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters John Garry
  10 siblings, 0 replies; 13+ messages in thread
From: Anurup M @ 2016-08-04  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

	1. Add nodes for hip05 L3 cache.
	2. Add djtag node and sysctrl node for hip05.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 arch/arm64/boot/dts/hisilicon/hip05.dtsi | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hip05.dtsi b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
index 4af2c72..0fd7e23 100644
--- a/arch/arm64/boot/dts/hisilicon/hip05.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
@@ -749,6 +749,25 @@
 			status = "disabled";
 		};
 
+		pc_sysctrl0: system-controller at 0x80010000 {
+			compatible = "hisilicon,hip05-sysctrl", "syscon";
+			reg = <0x0 0x80010000 0x0 0x10000>;
+		};
+
+		djtag0: djtag {
+			compatible = "hisilicon,hip05-cpu-djtag-v1";
+			syscon = <&pc_sysctrl0>;
+		};
+
+		l3c0: l3c {
+			compatible = "hisilicon,hip05-l3c";
+			djtag = <&djtag0 2>;
+			interrupt-parent = <&mbigen_pc>;
+			interrupts = <141 4>,<142 4>,
+				<143 4>,<144 4>;
+			status = "okay";
+		};
+
 		pcie0: pcie at b0080000 {
 			compatible = "hisilicon,hip05-pcie", "snps,dw-pcie";
 			reg = <0 0xb0080000 0 0x10000>, <0x220 0x04000000 0 0x04000000>;
-- 
2.1.4

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

* [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters
  2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
                   ` (9 preceding siblings ...)
  2016-08-04  9:07 ` [RFC PATCH v1 10/10] arm64: dts: hip05: Add L3 cache PMU support Anurup M
@ 2016-08-18 11:59 ` John Garry
  10 siblings, 0 replies; 13+ messages in thread
From: John Garry @ 2016-08-18 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/08/2016 10:07, Anurup M wrote:

Hi Anurup,

Mark already kindly gave feedback to your original patchset in June. I 
think many of the comments he gave have been addressed in this patchset.

However, I think that if you want your driver to be reviewed and 
accepted then you should drop the "RFC" and ensure it is ready be be 
accepted. I think that it is unreasonable to expect the maintainers to 
just give comments again.

Thanks,
John

> [Note: Resending the patch series as I missed to add Maintainers in --to field]
>
> Provide Support for Hisilicon SoC Hip05 Hardware event counters.
> The Hisilicon SoC Hip05 series has many uncore or non-CPU performance
> events and counters units.
>
> This patch is implemented refering to arm-cci, Intel/AMD uncore and
> also the cavium thunderX pmu patches.
>
> Support for Hisilicon L3 cache(LLC) hardware events and counters are added
> in this implementation.
>
> The Hisilicon PMU datastructures are designed so as to support uncore
> and also CPU specific events in future.
>
> The Hisilicon LLC has four banks for a Super CPU Cluster(consists of
>   16 CPU cores) and each LLC bank has separate hardware events and counters.
> In the current implementation, the count from all these banks are summarized
> and total count is output.
>
> Hisilicon SoC use Djtag interface for r/w access to SoC PMU registers
>
> The Hisilicon uncore PMUs can be found under /sys/bus/event_source/devices.
> The counters are exported via sysfs in the corresponding events files
> under the PMU directory so the perf tool can list the event names.
>
> Note:
> This is very initial patchset for Hisilicon Hip05 SoC PMU support shared for
> review. Please review and share comments.
>
> TODO:
> 	1. Counter overflow interrupt handling support.
> 	2. CPU notifier to migrate to available online CPU's in case
> 	   of CPU DOWN. Also mapping CPU cores to the current SCCL.
> 	3. Support for counting of individual LLC banks
>
> Anurup M (8):
>    arm64:perf: Add Documentaion for HIP05 PMU event counting.
>      1. Documentaion for perf usage and PMU events.
>    arm64:perf: Add Devicetree bindings for Hisilicon SoC PMU
>    arm64:perf: Update Kconfig for Hisilicon PMU support
>    arm64:perf: Add support for Hisilicon SoC event counters
>    arm64:perf: Makefile for Hisilicon Hip05 PMU
>    arm64:perf: Update Makefile for Hisilicon PMU support
>    arm64:perf: L3 cache(LLC) event listing in perf
>    arm64: dts: hip05: Add L3 cache PMU support
>
> Tan Xiaojun (2):
>    Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts
>      bindings
>    drivers: soc: Add support for Hisilicon Djtag driver
>
>   .../bindings/arm/hisilicon/hisilicon.txt           |  97 ++++
>   .../devicetree/bindings/arm/hisilicon/pmu.txt      |  52 ++
>   Documentation/perf/hip05-pmu.txt                   |  70 +++
>   arch/arm64/boot/dts/hisilicon/hip05.dtsi           |  19 +
>   drivers/perf/Kconfig                               |   9 +
>   drivers/perf/Makefile                              |   1 +
>   drivers/perf/hisilicon/Makefile                    |   1 +
>   drivers/perf/hisilicon/hisi_uncore_l3c.c           | 561 +++++++++++++++++++++
>   drivers/perf/hisilicon/hisi_uncore_l3c.h           | 100 ++++
>   drivers/perf/hisilicon/hisi_uncore_pmu.c           | 504 ++++++++++++++++++
>   drivers/perf/hisilicon/hisi_uncore_pmu.h           | 148 ++++++
>   drivers/soc/Kconfig                                |   1 +
>   drivers/soc/Makefile                               |   1 +
>   drivers/soc/hisilicon/Kconfig                      |  12 +
>   drivers/soc/hisilicon/Makefile                     |   1 +
>   drivers/soc/hisilicon/djtag.c                      | 373 ++++++++++++++
>   include/linux/soc/hisilicon/djtag.h                |  18 +
>   17 files changed, 1968 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
>   create mode 100644 Documentation/perf/hip05-pmu.txt
>   create mode 100644 drivers/perf/hisilicon/Makefile
>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.c
>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.h
>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.c
>   create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.h
>   create mode 100644 drivers/soc/hisilicon/Kconfig
>   create mode 100644 drivers/soc/hisilicon/Makefile
>   create mode 100644 drivers/soc/hisilicon/djtag.c
>   create mode 100644 include/linux/soc/hisilicon/djtag.h
>

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

end of thread, other threads:[~2016-08-18 11:59 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-08-04  9:07 [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 01/10] Documentation: arm64: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts bindings Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 02/10] drivers: soc: Add support for Hisilicon Djtag driver Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 03/10] arm64:perf: Add Documentaion for HIP05 PMU event counting. 1. Documentaion for perf usage and PMU events Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 04/10] arm64:perf: Add Devicetree bindings for Hisilicon SoC PMU Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 05/10] arm64:perf: Update Kconfig for Hisilicon PMU support Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 06/10] arm64:perf: Add support for Hisilicon SoC event counters Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 07/10] arm64:perf: Makefile for Hisilicon Hip05 PMU Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 08/10] arm64:perf: Update Makefile for Hisilicon PMU support Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 09/10] arm64:perf: L3 cache(LLC) event listing in perf Anurup M
2016-08-04  9:07 ` [RFC PATCH v1 10/10] arm64: dts: hip05: Add L3 cache PMU support Anurup M
2016-08-18 11:59 ` [RFC PATCH v1 00/10] arm64:perf: Support for Hisilicon SoC Hardware event counters John Garry
  -- strict thread matches above, loose matches on Subject: below --
2016-08-03  6:34 Anurup M

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).