* [PATCH v4 0/3] drivers/perf: hisi: Updates for HiSilicon uncore PMUs
@ 2026-07-24 2:52 Yushan Wang
2026-07-24 2:52 ` [PATCH 1/3] drivers/perf: hisi: Consolidate uncore PMU cpuhp states Yushan Wang
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Yushan Wang @ 2026-07-24 2:52 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: u.kleine-koenig, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12, wuyifan50
This patchset added support of ITS PMU, and new version of MN PMU.
ITS PMU supports counting number and latency of interrupts by
category, and statistics of micro-ops of ITS.
The new version of MN PMU added cycles event, to be used for MN
metric computing.
Changes:
v4:
- Moved unnecessary cpuhp states for each PMU drivers to hisi_uncore_pmu
framework as suggested by Robin.
- Reserve the ITS INT_ID filter slot for the lifetime of the event so
concurrent or multiplexed events cannot clobber the global filter
configuration.
Link to v3: https://lore.kernel.org/all/20260713125647.2958626-1-wangyushan12@huawei.com/
Link to Sashiko review report: https://sashiko.dev/#/patchset/20260713125647.2958626-1-wangyushan12%40huawei.com
v3:
- Added check_filter callback to refuse new filtered events when there
are already filtered ones running as per Sashiko.
Link to v2: https://lore.kernel.org/all/20260612093812.1249049-1-wangyushan12@huawei.com/
Link to Sashiko review report: https://sashiko.dev/#/message/20260612093812.1249049-1-wangyushan12%40huawei.com
v2:
- Added int_en filter to tell if int_id is used, enabling filtering
interrupt with 0 int_id per Sashiko.
- Changed event format width to align with register width per Sashiko.
Link to v1: https://lore.kernel.org/all/20260423152959.1458563-1-wangyushan12@huawei.com/
Link to Sashiko review report: https://sashiko.dev/#/patchset/20260423152959.1458563-1-wangyushan12%40huawei.com
Yifan Wu (1):
drivers/perf: hisi: Add cycle event for HIP13 MN PMU
Yushan Wang (2):
drivers/perf: hisi: Consolidate uncore PMU cpuhp states
drivers/perf: hisi: Add support for uncore ITS PMU
Documentation/admin-guide/perf/hisi-pmu.rst | 13 +
drivers/perf/hisilicon/Makefile | 2 +-
drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c | 34 +-
drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 34 +-
drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 34 +-
drivers/perf/hisilicon/hisi_uncore_its_pmu.c | 400 ++++++++++++++++++
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 21 +-
drivers/perf/hisilicon/hisi_uncore_mn_pmu.c | 98 +++--
drivers/perf/hisilicon/hisi_uncore_noc_pmu.c | 35 +-
drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 34 +-
drivers/perf/hisilicon/hisi_uncore_pmu.c | 25 ++
drivers/perf/hisilicon/hisi_uncore_pmu.h | 2 +
drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 34 +-
drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | 36 +-
include/linux/cpuhotplug.h | 6 -
15 files changed, 537 insertions(+), 271 deletions(-)
create mode 100644 drivers/perf/hisilicon/hisi_uncore_its_pmu.c
--
2.33.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] drivers/perf: hisi: Consolidate uncore PMU cpuhp states
2026-07-24 2:52 [PATCH v4 0/3] drivers/perf: hisi: Updates for HiSilicon uncore PMUs Yushan Wang
@ 2026-07-24 2:52 ` Yushan Wang
2026-07-27 12:41 ` Robin Murphy
2026-07-24 2:52 ` [PATCH 2/3] drivers/perf: hisi: Add support for uncore ITS PMU Yushan Wang
2026-07-24 2:52 ` [PATCH 3/3] drivers/perf: hisi: Add cycle event for HIP13 MN PMU Yushan Wang
2 siblings, 1 reply; 5+ messages in thread
From: Yushan Wang @ 2026-07-24 2:52 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: u.kleine-koenig, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12, wuyifan50
Every HiSilicon uncore PMU driver allocates its own static cpuhp state
even though they all register identical online/offline callbacks. This
wastes slots in the cpuhp state enum and needlessly fragments the
hotplug state space.
Move the cpuhp state setup into the shared hisi_uncore_pmu framework:
register a single dynamic state (CPUHP_AP_ONLINE_DYN) at framework
module init and export it for all HiSilicon uncore PMU drivers to use.
Drop the now-unused static CPUHP_AP_PERF_ARM_HISI_* entries from
include/linux/cpuhotplug.h.
The L3C PMU driver keeps a private dynamic state because it has its own
hotplug callbacks for migrating multiple per-CPU interrupt affinities,
but switches from its former static slot to CPUHP_AP_ONLINE_DYN for
consistency.
No intended functional changes.
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
---
drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c | 34 +++---------------
drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 34 +++---------------
drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 34 +++---------------
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 21 +++++------
drivers/perf/hisilicon/hisi_uncore_mn_pmu.c | 35 ++----------------
drivers/perf/hisilicon/hisi_uncore_noc_pmu.c | 35 ++----------------
drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 34 +++---------------
drivers/perf/hisilicon/hisi_uncore_pmu.c | 25 +++++++++++++
drivers/perf/hisilicon/hisi_uncore_pmu.h | 2 ++
drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 34 +++---------------
drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | 36 ++-----------------
include/linux/cpuhotplug.h | 6 ----
12 files changed, 67 insertions(+), 263 deletions(-)
diff --git a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c
index b879b81adfdd..83967725c51c 100644
--- a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c
@@ -295,7 +295,7 @@ static int hisi_cpa_pmu_probe(struct platform_device *pdev)
/* Power Management should be disabled before using CPA PMU. */
hisi_cpa_pmu_disable_pm(cpa_pmu);
- ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
&cpa_pmu->node);
if (ret) {
dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
@@ -307,7 +307,7 @@ static int hisi_cpa_pmu_probe(struct platform_device *pdev)
if (ret) {
dev_err(cpa_pmu->dev, "PMU register failed\n");
cpuhp_state_remove_instance_nocalls(
- CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE, &cpa_pmu->node);
+ hisi_uncore_pmu_cpuhp_state, &cpa_pmu->node);
hisi_cpa_pmu_enable_pm(cpa_pmu);
return ret;
}
@@ -321,7 +321,7 @@ static void hisi_cpa_pmu_remove(struct platform_device *pdev)
struct hisi_pmu *cpa_pmu = platform_get_drvdata(pdev);
perf_pmu_unregister(&cpa_pmu->pmu);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
&cpa_pmu->node);
hisi_cpa_pmu_enable_pm(cpa_pmu);
}
@@ -336,33 +336,7 @@ static struct platform_driver hisi_cpa_pmu_driver = {
.remove = hisi_cpa_pmu_remove,
};
-static int __init hisi_cpa_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
- "AP_PERF_ARM_HISI_CPA_ONLINE",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret) {
- pr_err("setup hotplug failed: %d\n", ret);
- return ret;
- }
-
- ret = platform_driver_register(&hisi_cpa_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE);
-
- return ret;
-}
-module_init(hisi_cpa_pmu_module_init);
-
-static void __exit hisi_cpa_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_cpa_pmu_driver);
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE);
-}
-module_exit(hisi_cpa_pmu_module_exit);
+module_platform_driver(hisi_cpa_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon SoC CPA PMU driver");
diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index 21c494881ca0..e905160523ee 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -401,7 +401,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
&ddrc_pmu->node);
if (ret) {
dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret);
@@ -414,7 +414,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
if (ret) {
dev_err(ddrc_pmu->dev, "DDRC PMU register failed!\n");
cpuhp_state_remove_instance_nocalls(
- CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, &ddrc_pmu->node);
+ hisi_uncore_pmu_cpuhp_state, &ddrc_pmu->node);
}
return ret;
@@ -425,7 +425,7 @@ static void hisi_ddrc_pmu_remove(struct platform_device *pdev)
struct hisi_pmu *ddrc_pmu = platform_get_drvdata(pdev);
perf_pmu_unregister(&ddrc_pmu->pmu);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
&ddrc_pmu->node);
}
@@ -501,33 +501,7 @@ static struct platform_driver hisi_ddrc_pmu_driver = {
.remove = hisi_ddrc_pmu_remove,
};
-static int __init hisi_ddrc_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
- "AP_PERF_ARM_HISI_DDRC_ONLINE",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret) {
- pr_err("DDRC PMU: setup hotplug, ret = %d\n", ret);
- return ret;
- }
-
- ret = platform_driver_register(&hisi_ddrc_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
-
- return ret;
-}
-module_init(hisi_ddrc_pmu_module_init);
-
-static void __exit hisi_ddrc_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_ddrc_pmu_driver);
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
-}
-module_exit(hisi_ddrc_pmu_module_exit);
+module_platform_driver(hisi_ddrc_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon SoC DDRC uncore PMU driver");
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 97cfaa586a87..93a250b7abb8 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -490,7 +490,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
&hha_pmu->node);
if (ret) {
dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
@@ -503,7 +503,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
if (ret) {
dev_err(hha_pmu->dev, "HHA PMU register failed!\n");
cpuhp_state_remove_instance_nocalls(
- CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, &hha_pmu->node);
+ hisi_uncore_pmu_cpuhp_state, &hha_pmu->node);
}
return ret;
@@ -514,7 +514,7 @@ static void hisi_hha_pmu_remove(struct platform_device *pdev)
struct hisi_pmu *hha_pmu = platform_get_drvdata(pdev);
perf_pmu_unregister(&hha_pmu->pmu);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
&hha_pmu->node);
}
@@ -528,33 +528,7 @@ static struct platform_driver hisi_hha_pmu_driver = {
.remove = hisi_hha_pmu_remove,
};
-static int __init hisi_hha_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
- "AP_PERF_ARM_HISI_HHA_ONLINE",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret) {
- pr_err("HHA PMU: Error setup hotplug, ret = %d;\n", ret);
- return ret;
- }
-
- ret = platform_driver_register(&hisi_hha_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE);
-
- return ret;
-}
-module_init(hisi_hha_pmu_module_init);
-
-static void __exit hisi_hha_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_hha_pmu_driver);
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE);
-}
-module_exit(hisi_hha_pmu_module_exit);
+module_platform_driver(hisi_hha_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon SoC HHA uncore PMU driver");
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index f963e4f9e552..0b78a0e094dd 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -93,6 +93,8 @@ struct hisi_l3c_pmu_ext {
bool support_ext;
};
+static enum cpuhp_state hisi_l3c_pmu_cpuhp_state;
+
static bool support_ext(struct hisi_l3c_pmu *pmu)
{
struct hisi_l3c_pmu_ext *l3c_pmu_ext = pmu->l3c_pmu.dev_info->private;
@@ -845,8 +847,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
- &l3c_pmu->node);
+ ret = cpuhp_state_add_instance(hisi_l3c_pmu_cpuhp_state, &l3c_pmu->node);
if (ret) {
dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
return ret;
@@ -858,7 +859,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
if (ret) {
dev_err(l3c_pmu->dev, "L3C PMU register failed!\n");
cpuhp_state_remove_instance_nocalls(
- CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, &l3c_pmu->node);
+ hisi_l3c_pmu_cpuhp_state, &l3c_pmu->node);
}
return ret;
@@ -869,7 +870,7 @@ static void hisi_l3c_pmu_remove(struct platform_device *pdev)
struct hisi_pmu *l3c_pmu = platform_get_drvdata(pdev);
perf_pmu_unregister(&l3c_pmu->pmu);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_l3c_pmu_cpuhp_state,
&l3c_pmu->node);
}
@@ -939,20 +940,20 @@ static int hisi_l3c_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
static int __init hisi_l3c_pmu_module_init(void)
{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
+ int ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
"AP_PERF_ARM_HISI_L3_ONLINE",
hisi_l3c_pmu_online_cpu,
hisi_l3c_pmu_offline_cpu);
- if (ret) {
+ if (ret < 0) {
pr_err("L3C PMU: Error setup hotplug, ret = %d\n", ret);
return ret;
}
+ hisi_l3c_pmu_cpuhp_state = ret;
+
ret = platform_driver_register(&hisi_l3c_pmu_driver);
if (ret)
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);
+ cpuhp_remove_multi_state(hisi_l3c_pmu_cpuhp_state);
return ret;
}
@@ -961,7 +962,7 @@ module_init(hisi_l3c_pmu_module_init);
static void __exit hisi_l3c_pmu_module_exit(void)
{
platform_driver_unregister(&hisi_l3c_pmu_driver);
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);
+ cpuhp_remove_multi_state(hisi_l3c_pmu_cpuhp_state);
}
module_exit(hisi_l3c_pmu_module_exit);
diff --git a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
index 246cc0333099..ad898153ff49 100644
--- a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
@@ -13,9 +13,6 @@
#include "hisi_uncore_pmu.h"
-/* Dynamic CPU hotplug state used by MN PMU */
-static enum cpuhp_state hisi_mn_pmu_online;
-
/* MN register definition */
#define HISI_MN_DYNAMIC_CTRL_REG 0x400
#define HISI_MN_DYNAMIC_CTRL_EN BIT(0)
@@ -291,7 +288,7 @@ static int hisi_mn_pmu_dev_init(struct platform_device *pdev,
static void hisi_mn_pmu_remove_cpuhp(void *hotplug_node)
{
- cpuhp_state_remove_instance_nocalls(hisi_mn_pmu_online, hotplug_node);
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state, hotplug_node);
}
static void hisi_mn_pmu_unregister(void *pmu)
@@ -320,7 +317,7 @@ static int hisi_mn_pmu_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- ret = cpuhp_state_add_instance(hisi_mn_pmu_online, &mn_pmu->node);
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state, &mn_pmu->node);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Failed to register cpu hotplug\n");
@@ -376,33 +373,7 @@ static struct platform_driver hisi_mn_pmu_driver = {
.probe = hisi_mn_pmu_probe,
};
-static int __init hisi_mn_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "perf/hisi/mn:online",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret < 0) {
- pr_err("hisi_mn_pmu: Failed to setup MN PMU hotplug: %d\n", ret);
- return ret;
- }
- hisi_mn_pmu_online = ret;
-
- ret = platform_driver_register(&hisi_mn_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(hisi_mn_pmu_online);
-
- return ret;
-}
-module_init(hisi_mn_pmu_module_init);
-
-static void __exit hisi_mn_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_mn_pmu_driver);
- cpuhp_remove_multi_state(hisi_mn_pmu_online);
-}
-module_exit(hisi_mn_pmu_module_exit);
+module_platform_driver(hisi_mn_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon SoC MN uncore PMU driver");
diff --git a/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c
index 616f4af57db7..abf44fa46d17 100644
--- a/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c
@@ -41,9 +41,6 @@
HISI_PMU_EVENT_ATTR_EXTRACTOR(ch, config1, 2, 0);
HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_en, config1, 3, 3);
-/* Dynamic CPU hotplug state used by this PMU driver */
-static enum cpuhp_state hisi_noc_pmu_cpuhp_state;
-
struct hisi_noc_pmu_regs {
u32 version;
u32 pmu_ctrl;
@@ -324,7 +321,7 @@ static int hisi_noc_pmu_dev_init(struct platform_device *pdev, struct hisi_pmu *
static void hisi_noc_pmu_remove_cpuhp_instance(void *hotplug_node)
{
- cpuhp_state_remove_instance_nocalls(hisi_noc_pmu_cpuhp_state, hotplug_node);
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state, hotplug_node);
}
static void hisi_noc_pmu_unregister_pmu(void *pmu)
@@ -353,7 +350,7 @@ static int hisi_noc_pmu_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = cpuhp_state_add_instance(hisi_noc_pmu_cpuhp_state, &noc_pmu->node);
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state, &noc_pmu->node);
if (ret)
return dev_err_probe(dev, ret, "Fail to register cpuhp instance\n");
@@ -408,33 +405,7 @@ static struct platform_driver hisi_noc_pmu_driver = {
.probe = hisi_noc_pmu_probe,
};
-static int __init hisi_noc_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "perf/hisi/noc:online",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret < 0) {
- pr_err("hisi_noc_pmu: Fail to setup cpuhp callbacks, ret = %d\n", ret);
- return ret;
- }
- hisi_noc_pmu_cpuhp_state = ret;
-
- ret = platform_driver_register(&hisi_noc_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(hisi_noc_pmu_cpuhp_state);
-
- return ret;
-}
-module_init(hisi_noc_pmu_module_init);
-
-static void __exit hisi_noc_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_noc_pmu_driver);
- cpuhp_remove_multi_state(hisi_noc_pmu_cpuhp_state);
-}
-module_exit(hisi_noc_pmu_module_exit);
+module_platform_driver(hisi_noc_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon SoC Uncore NoC PMU driver");
diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
index 80108c63cb60..3d1e0af64260 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
@@ -468,7 +468,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
&pa_pmu->node);
if (ret) {
dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
@@ -479,7 +479,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
if (ret) {
dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
&pa_pmu->node);
return ret;
}
@@ -493,7 +493,7 @@ static void hisi_pa_pmu_remove(struct platform_device *pdev)
struct hisi_pmu *pa_pmu = platform_get_drvdata(pdev);
perf_pmu_unregister(&pa_pmu->pmu);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
&pa_pmu->node);
}
@@ -515,33 +515,7 @@ static struct platform_driver hisi_pa_pmu_driver = {
.remove = hisi_pa_pmu_remove,
};
-static int __init hisi_pa_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
- "AP_PERF_ARM_HISI_PA_ONLINE",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret) {
- pr_err("PA PMU: cpuhp state setup failed, ret = %d\n", ret);
- return ret;
- }
-
- ret = platform_driver_register(&hisi_pa_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
-
- return ret;
-}
-module_init(hisi_pa_pmu_module_init);
-
-static void __exit hisi_pa_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_pa_pmu_driver);
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
-}
-module_exit(hisi_pa_pmu_module_exit);
+module_platform_driver(hisi_pa_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon Protocol Adapter uncore PMU driver");
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index de71dcf11653..276785a79ae9 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -23,6 +23,9 @@
#define HISI_MAX_PERIOD(nr) (GENMASK_ULL((nr) - 1, 0))
+enum cpuhp_state hisi_uncore_pmu_cpuhp_state;
+EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_cpuhp_state, "HISI_PMU");
+
/*
* PMU event attributes
*/
@@ -621,5 +624,27 @@ void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module)
}
EXPORT_SYMBOL_NS_GPL(hisi_pmu_init, "HISI_PMU");
+static int __init hisi_uncore_pmu_init(void)
+{
+ int ret;
+
+ ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "perf/hisi/uncore:online",
+ hisi_uncore_pmu_online_cpu,
+ hisi_uncore_pmu_offline_cpu);
+ if (ret < 0)
+ return ret;
+
+ hisi_uncore_pmu_cpuhp_state = ret;
+
+ return 0;
+}
+module_init(hisi_uncore_pmu_init);
+
+static void __exit hisi_uncore_pmu_exit(void)
+{
+ cpuhp_remove_multi_state(hisi_uncore_pmu_cpuhp_state);
+}
+module_exit(hisi_uncore_pmu_exit);
+
MODULE_DESCRIPTION("HiSilicon SoC uncore Performance Monitor driver framework");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index 3ffe6acda653..e5a4b3898865 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -171,4 +171,6 @@ int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
void hisi_uncore_pmu_init_topology(struct hisi_pmu *hisi_pmu, struct device *dev);
void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module);
+
+extern enum cpuhp_state hisi_uncore_pmu_cpuhp_state;
#endif /* __HISI_UNCORE_PMU_H__ */
diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
index cd32d606df05..d01340ff2e5c 100644
--- a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
@@ -503,7 +503,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
&sllc_pmu->node);
if (ret) {
dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
@@ -515,7 +515,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
if (ret) {
dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
&sllc_pmu->node);
return ret;
}
@@ -530,7 +530,7 @@ static void hisi_sllc_pmu_remove(struct platform_device *pdev)
struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev);
perf_pmu_unregister(&sllc_pmu->pmu);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
&sllc_pmu->node);
}
@@ -551,33 +551,7 @@ static struct platform_driver hisi_sllc_pmu_driver = {
.remove = hisi_sllc_pmu_remove,
};
-static int __init hisi_sllc_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
- "AP_PERF_ARM_HISI_SLLC_ONLINE",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret) {
- pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret);
- return ret;
- }
-
- ret = platform_driver_register(&hisi_sllc_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
-
- return ret;
-}
-module_init(hisi_sllc_pmu_module_init);
-
-static void __exit hisi_sllc_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_sllc_pmu_driver);
- cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
-}
-module_exit(hisi_sllc_pmu_module_exit);
+module_platform_driver(hisi_sllc_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver");
diff --git a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c
index e8186b6e1687..b4d017a5d688 100644
--- a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c
@@ -13,9 +13,6 @@
#include "hisi_uncore_pmu.h"
-/* Dynamic CPU hotplug state used by UC PMU */
-static enum cpuhp_state hisi_uc_pmu_online;
-
/* UC register definition */
#define HISI_UC_INT_MASK_REG 0x0800
#define HISI_UC_INT_STS_REG 0x0808
@@ -488,7 +485,7 @@ static int hisi_uc_pmu_dev_probe(struct platform_device *pdev,
static void hisi_uc_pmu_remove_cpuhp_instance(void *hotplug_node)
{
- cpuhp_state_remove_instance_nocalls(hisi_uc_pmu_online, hotplug_node);
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state, hotplug_node);
}
static void hisi_uc_pmu_unregister_pmu(void *pmu)
@@ -518,7 +515,7 @@ static int hisi_uc_pmu_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- ret = cpuhp_state_add_instance(hisi_uc_pmu_online, &uc_pmu->node);
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state, &uc_pmu->node);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Error registering hotplug\n");
@@ -559,34 +556,7 @@ static struct platform_driver hisi_uc_pmu_driver = {
.probe = hisi_uc_pmu_probe,
};
-static int __init hisi_uc_pmu_module_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
- "perf/hisi/uc:online",
- hisi_uncore_pmu_online_cpu,
- hisi_uncore_pmu_offline_cpu);
- if (ret < 0) {
- pr_err("UC PMU: Error setup hotplug, ret = %d\n", ret);
- return ret;
- }
- hisi_uc_pmu_online = ret;
-
- ret = platform_driver_register(&hisi_uc_pmu_driver);
- if (ret)
- cpuhp_remove_multi_state(hisi_uc_pmu_online);
-
- return ret;
-}
-module_init(hisi_uc_pmu_module_init);
-
-static void __exit hisi_uc_pmu_module_exit(void)
-{
- platform_driver_unregister(&hisi_uc_pmu_driver);
- cpuhp_remove_multi_state(hisi_uc_pmu_online);
-}
-module_exit(hisi_uc_pmu_module_exit);
+module_platform_driver(hisi_uc_pmu_driver);
MODULE_IMPORT_NS("HISI_PMU");
MODULE_DESCRIPTION("HiSilicon SoC UC uncore PMU driver");
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 0fb3a2a62eb0..965d6ce02a29 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -210,12 +210,6 @@ enum cpuhp_state {
CPUHP_AP_PERF_S390_SF_ONLINE,
CPUHP_AP_PERF_ARM_CCI_ONLINE,
CPUHP_AP_PERF_ARM_CCN_ONLINE,
- CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
- CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
- CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
- CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
- CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
- CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
CPUHP_AP_PERF_ARM_HISI_PCIE_PMU_ONLINE,
CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
CPUHP_AP_PERF_ARM_L2X0_ONLINE,
--
2.33.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] drivers/perf: hisi: Add support for uncore ITS PMU
2026-07-24 2:52 [PATCH v4 0/3] drivers/perf: hisi: Updates for HiSilicon uncore PMUs Yushan Wang
2026-07-24 2:52 ` [PATCH 1/3] drivers/perf: hisi: Consolidate uncore PMU cpuhp states Yushan Wang
@ 2026-07-24 2:52 ` Yushan Wang
2026-07-24 2:52 ` [PATCH 3/3] drivers/perf: hisi: Add cycle event for HIP13 MN PMU Yushan Wang
2 siblings, 0 replies; 5+ messages in thread
From: Yushan Wang @ 2026-07-24 2:52 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: u.kleine-koenig, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12, wuyifan50
The Interrupt Translation Service (ITS) PMU counts interrupts routed
to the ITS by category (LPI/SGI/PPI event counts and latencies) and
also collects micro-op statistics for the ITS itself.
Add a driver for the ITS PMU on the HiSilicon uncore PMU framework.
Like the NoC PMU it has no overflow interrupt, so the interrupt
enable/disable callbacks are empty stubs.
The PMU supports filtering counters by a 32-bit interrupt id (int_id),
composed of a 16-bit DeviceID/PEID in the upper half and a 16-bit
EventID/IntID in the lower half. The INT_ID filter is global to the
PMU instance, so only one filtered event (int_en=1) may run at a time;
opening a second filtered event returns -EINVAL. The filter slot is
reserved at event_init() time and held for the lifetime of the event
via event->destroy, so concurrent event_init() callers and events that
are multiplexed out cannot race to clobber the hardware filter
configuration.
Document the int_id and int_en format attributes in
Documentation/admin-guide/perf/hisi-pmu.rst.
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
---
Documentation/admin-guide/perf/hisi-pmu.rst | 13 +
drivers/perf/hisilicon/Makefile | 2 +-
drivers/perf/hisilicon/hisi_uncore_its_pmu.c | 400 +++++++++++++++++++
3 files changed, 414 insertions(+), 1 deletion(-)
create mode 100644 drivers/perf/hisilicon/hisi_uncore_its_pmu.c
diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst
index d56b2d690709..b69931e4be4e 100644
--- a/Documentation/admin-guide/perf/hisi-pmu.rst
+++ b/Documentation/admin-guide/perf/hisi-pmu.rst
@@ -128,6 +128,19 @@ channel with this option. The current supported channels are as follows:
7. tt_en: NoC PMU supports counting only transactions that have tracetag set
if this option is set. See the 2nd list for more information about tracetag.
+8. int_id: ITS PMU supports filtering by interrupt id, which is defined by
+hardware. Interrupt id takes up to 32 bits, and can be divided into 2 parts:
+
+- Upper 16 bits: DeviceID if counting LPI, PEID if counting SGI/PPI.
+- Lower 16 bits: EventID if counting LPI, IntID if counting SGI/PPI.
+
+int_id is a global configuration for each PMU instance. Only one filtered
+event (with int_en set) can run at a time; if a filtered event is already
+running, new filtered events will be refused.
+
+9. int_en: A one-bit flag to tell if int_id is used to filter the statistics. It
+allows filtering 0 DeviceID and EventID.
+
For HiSilicon uncore PMU v3 whose identifier is 0x40, some uncore PMUs are
further divided into parts for finer granularity of tracing, each part has its
own dedicated PMU, and all such PMUs together cover the monitoring job of events
diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index 186be3d02238..5f28cfdb8a72 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -2,7 +2,7 @@
obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o \
hisi_uncore_pa_pmu.o hisi_uncore_cpa_pmu.o hisi_uncore_uc_pmu.o \
- hisi_uncore_noc_pmu.o hisi_uncore_mn_pmu.o
+ hisi_uncore_noc_pmu.o hisi_uncore_mn_pmu.o hisi_uncore_its_pmu.o
obj-$(CONFIG_HISI_PCIE_PMU) += hisi_pcie_pmu.o
obj-$(CONFIG_HNS3_PMU) += hns3_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_its_pmu.c b/drivers/perf/hisilicon/hisi_uncore_its_pmu.c
new file mode 100644
index 000000000000..375a14f20ee2
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_its_pmu.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for HiSilicon Uncore ITS PMU device
+ *
+ * Copyright (c) 2026 HiSilicon Technologies Co., Ltd.
+ * Author: Yushan Wang <wangyushan12@huawei.com>
+ */
+#include <linux/bitops.h>
+#include <linux/cpuhotplug.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+
+#include "hisi_uncore_pmu.h"
+
+#define ITS_PMU_VERSION 0x21000
+#define ITS_PMU_GLOBAL_CTRL 0x21004
+#define ITS_PMU_GLOBAL_CTRL_PMU_EN BIT(0)
+#define ITS_PMU_COUNTER_CTRL 0x21008
+#define ITS_PMU_EVENT_CTRL 0x2100c
+#define ITS_PMU_COUNTER0 0x21010
+
+#define ITS_PMU_INT_ID_MASK 0x20008
+#define ITS_PMU_INT_ID_CTRL 0x20084
+
+#define ITS_PMU_NR_COUNTERS 4
+
+#define ITS_PMU_EVENT_CNTRn(cntr0, n) ((cntr0) + 8 * (n))
+#define ITS_PMU_CNTR_CTRL_MASK(n) GENMASK(8 * ((n) + 1) - 1, 8 * (n))
+#define ITS_PMU_CNTR_EVENT_CFG(n, e) ((e) << ((n) * 8))
+#define ITS_PMU_EVENT_CTRL_TYPE GENMASK(12, 0)
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(int_id, config1, 31, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(int_en, config1, 32, 32);
+
+struct hisi_its_pmu_regs {
+ u32 version;
+ u32 pmu_ctrl;
+ u32 event_ctrl0;
+ u32 event_cntr0;
+ u32 cntr_ctrl;
+};
+
+struct hisi_its_pmu {
+ struct hisi_pmu pmu;
+ /* Protects filter_busy and the global INT_ID filter config. */
+ spinlock_t filter_lock;
+ /* Reserved by a filtered event for its whole lifetime. */
+ bool filter_busy;
+};
+
+static void hisi_its_pmu_write_evtype(struct hisi_pmu *pmu, int idx, u32 type)
+{
+ struct hisi_its_pmu_regs *reg_info = pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(pmu->base + reg_info->event_ctrl0);
+ reg &= ~ITS_PMU_CNTR_CTRL_MASK(idx);
+ reg |= ITS_PMU_CNTR_EVENT_CFG(idx, type);
+ writel(reg, pmu->base + reg_info->event_ctrl0);
+}
+
+static u64 hisi_its_pmu_read_counter(struct hisi_pmu *pmu,
+ struct hw_perf_event *hwc)
+{
+ struct hisi_its_pmu_regs *reg_info = pmu->dev_info->private;
+
+ return readq(pmu->base + ITS_PMU_EVENT_CNTRn(reg_info->event_cntr0, hwc->idx));
+}
+
+static void hisi_its_pmu_write_counter(struct hisi_pmu *pmu,
+ struct hw_perf_event *hwc, u64 val)
+{
+ struct hisi_its_pmu_regs *reg_info = pmu->dev_info->private;
+
+ writeq(val, pmu->base + ITS_PMU_EVENT_CNTRn(reg_info->event_cntr0, hwc->idx));
+}
+
+static void hisi_its_pmu_enable_counter(struct hisi_pmu *pmu,
+ struct hw_perf_event *hwc)
+{
+ struct hisi_its_pmu_regs *reg_info = pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(pmu->base + reg_info->cntr_ctrl);
+ reg |= BIT(hwc->idx);
+ writel(reg, pmu->base + reg_info->cntr_ctrl);
+}
+
+static void hisi_its_pmu_disable_counter(struct hisi_pmu *pmu,
+ struct hw_perf_event *hwc)
+{
+ struct hisi_its_pmu_regs *reg_info = pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(pmu->base + reg_info->cntr_ctrl);
+ reg &= ~BIT(hwc->idx);
+ writel(reg, pmu->base + reg_info->cntr_ctrl);
+}
+
+static void hisi_its_pmu_enable_counter_int(struct hisi_pmu *pmu,
+ struct hw_perf_event *hwc)
+{
+ /* We don't support interrupt, so a stub here. */
+}
+
+static void hisi_its_pmu_disable_counter_int(struct hisi_pmu *pmu,
+ struct hw_perf_event *hwc)
+{
+}
+
+static void hisi_its_pmu_start_counters(struct hisi_pmu *pmu)
+{
+ struct hisi_its_pmu_regs *reg_info = pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(pmu->base + reg_info->pmu_ctrl);
+ reg |= ITS_PMU_GLOBAL_CTRL_PMU_EN;
+ writel(reg, pmu->base + reg_info->pmu_ctrl);
+}
+
+static void hisi_its_pmu_stop_counters(struct hisi_pmu *pmu)
+{
+ struct hisi_its_pmu_regs *reg_info = pmu->dev_info->private;
+ u32 reg;
+
+ reg = readl(pmu->base + reg_info->pmu_ctrl);
+ reg &= ~ITS_PMU_GLOBAL_CTRL_PMU_EN;
+ writel(reg, pmu->base + reg_info->pmu_ctrl);
+}
+
+static void hisi_its_pmu_enable_filter(struct perf_event *event)
+{
+ struct hisi_pmu *pmu = to_hisi_pmu(event->pmu);
+ u32 int_id = hisi_get_int_id(event);
+ u32 int_en = hisi_get_int_en(event);
+
+ if (!int_en)
+ return;
+
+ writel(int_id, pmu->base + ITS_PMU_INT_ID_CTRL);
+ /* Write 0 to this register to enable filtering with int_id. */
+ writel(0, pmu->base + ITS_PMU_INT_ID_MASK);
+}
+
+static void hisi_its_pmu_disable_filter(struct perf_event *event)
+{
+ struct hisi_pmu *pmu = to_hisi_pmu(event->pmu);
+ u32 int_en = hisi_get_int_en(event);
+
+ if (!int_en)
+ return;
+
+ writel(0, pmu->base + ITS_PMU_INT_ID_CTRL);
+ writel(-1U, pmu->base + ITS_PMU_INT_ID_MASK);
+}
+
+/* Release the filter slot reserved in check_filter(). */
+static void hisi_its_pmu_destroy_event(struct perf_event *event)
+{
+ struct hisi_pmu *pmu = to_hisi_pmu(event->pmu);
+ struct hisi_its_pmu *its_pmu = container_of(pmu, struct hisi_its_pmu, pmu);
+ u32 int_en = hisi_get_int_en(event);
+
+ if (!int_en)
+ return;
+
+ spin_lock(&its_pmu->filter_lock);
+ its_pmu->filter_busy = false;
+ spin_unlock(&its_pmu->filter_lock);
+}
+
+static int hisi_its_pmu_check_filter(struct perf_event *event)
+{
+ struct hisi_pmu *pmu = to_hisi_pmu(event->pmu);
+ struct hisi_its_pmu *its_pmu = container_of(pmu, struct hisi_its_pmu, pmu);
+ u32 int_en = hisi_get_int_en(event);
+
+ if (!int_en)
+ return 0;
+
+ /*
+ * The INT_ID filter is global to the PMU instance: when set, all
+ * counters only count traffic matching int_id. Reserve the slot
+ * at event_init() time and hold it for the lifetime of the event
+ * so a concurrent or multiplexed event cannot clobber the hardware
+ * state. The slot is released by event->destroy(), which the perf
+ * core calls on both the event_init() error path and final free.
+ */
+ spin_lock(&its_pmu->filter_lock);
+ if (its_pmu->filter_busy) {
+ spin_unlock(&its_pmu->filter_lock);
+ return -EINVAL;
+ }
+ its_pmu->filter_busy = true;
+ spin_unlock(&its_pmu->filter_lock);
+
+ event->destroy = hisi_its_pmu_destroy_event;
+ return 0;
+}
+
+static const struct hisi_uncore_ops hisi_uncore_its_ops = {
+ .write_evtype = hisi_its_pmu_write_evtype,
+ .get_event_idx = hisi_uncore_pmu_get_event_idx,
+ .read_counter = hisi_its_pmu_read_counter,
+ .write_counter = hisi_its_pmu_write_counter,
+ .enable_counter = hisi_its_pmu_enable_counter,
+ .disable_counter = hisi_its_pmu_disable_counter,
+ .enable_counter_int = hisi_its_pmu_enable_counter_int,
+ .disable_counter_int = hisi_its_pmu_disable_counter_int,
+ .start_counters = hisi_its_pmu_start_counters,
+ .stop_counters = hisi_its_pmu_stop_counters,
+ .enable_filter = hisi_its_pmu_enable_filter,
+ .disable_filter = hisi_its_pmu_disable_filter,
+ .check_filter = hisi_its_pmu_check_filter
+};
+
+static struct attribute *hisi_its_pmu_format_attrs[] = {
+ HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+ HISI_PMU_FORMAT_ATTR(int_id, "config1:0-31"),
+ HISI_PMU_FORMAT_ATTR(int_en, "config1:32-32"),
+ NULL
+};
+
+static const struct attribute_group hisi_its_pmu_format_group = {
+ .name = "format",
+ .attrs = hisi_its_pmu_format_attrs,
+};
+
+static struct attribute *hisi_its_pmu_events_attrs[] = {
+ HISI_PMU_EVENT_ATTR(lpi_num, 0xc0),
+ HISI_PMU_EVENT_ATTR(lpi_time, 0x80),
+ HISI_PMU_EVENT_ATTR(sgi_num, 0xc1),
+ HISI_PMU_EVENT_ATTR(sgi_time, 0x81),
+ HISI_PMU_EVENT_ATTR(ppi_num, 0xc2),
+ HISI_PMU_EVENT_ATTR(ppi_time, 0x82),
+ HISI_PMU_EVENT_ATTR(sl3_lpi_num, 0xc3),
+ HISI_PMU_EVENT_ATTR(sl3_sgi_num, 0xc4),
+ HISI_PMU_EVENT_ATTR(sl3_ppi_num, 0xc5),
+ HISI_PMU_EVENT_ATTR(sl0_ddr_read, 0xc9),
+ HISI_PMU_EVENT_ATTR(sl0_ddr_time, 0x89),
+ HISI_PMU_EVENT_ATTR(sl1_ddr_read, 0xca),
+ HISI_PMU_EVENT_ATTR(sl1_ddr_time, 0x8a),
+ HISI_PMU_EVENT_ATTR(sl2_ddr_read, 0xcb),
+ HISI_PMU_EVENT_ATTR(sl2_ddr_time, 0x8b),
+ HISI_PMU_EVENT_ATTR(cycles, 0xcc),
+ NULL
+};
+
+static const struct attribute_group hisi_its_pmu_events_group = {
+ .name = "events",
+ .attrs = hisi_its_pmu_events_attrs,
+};
+
+static const struct attribute_group *hisi_its_pmu_attr_groups[] = {
+ &hisi_its_pmu_format_group,
+ &hisi_its_pmu_events_group,
+ &hisi_pmu_cpumask_attr_group,
+ &hisi_pmu_identifier_group,
+ NULL
+};
+
+static int hisi_its_pmu_dev_init(struct platform_device *pdev,
+ struct hisi_its_pmu *its_pmu)
+{
+ struct hisi_its_pmu_regs *reg_info;
+ struct hisi_pmu *pmu = &its_pmu->pmu;
+
+ hisi_uncore_pmu_init_topology(pmu, &pdev->dev);
+
+ if (pmu->topo.scl_id < 0)
+ return dev_err_probe(&pdev->dev, -EINVAL, "failed to get scl-id\n");
+
+ if (pmu->topo.index_id < 0)
+ return dev_err_probe(&pdev->dev, -EINVAL, "failed to get idx-id\n");
+
+ pmu->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pmu->base))
+ return dev_err_probe(&pdev->dev, PTR_ERR(pmu->base),
+ "fail to remap io memory\n");
+
+ pmu->dev_info = device_get_match_data(&pdev->dev);
+ if (!pmu->dev_info)
+ return -ENODEV;
+
+ pmu->pmu_events.attr_groups = pmu->dev_info->attr_groups;
+ pmu->counter_bits = pmu->dev_info->counter_bits;
+ pmu->check_event = pmu->dev_info->check_event;
+ pmu->num_counters = ITS_PMU_NR_COUNTERS;
+ pmu->ops = &hisi_uncore_its_ops;
+ pmu->dev = &pdev->dev;
+ pmu->on_cpu = -1;
+
+ reg_info = pmu->dev_info->private;
+ pmu->identifier = readl(pmu->base + reg_info->version);
+
+ return 0;
+}
+
+static void hisi_its_pmu_remove_cpuhp_instance(void *hotplug_node)
+{
+ cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
+ hotplug_node);
+}
+
+static void hisi_its_pmu_unregister_pmu(void *pmu)
+{
+ perf_pmu_unregister(pmu);
+}
+
+static int hisi_its_pmu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hisi_its_pmu *its_pmu;
+ struct hisi_pmu *pmu;
+ char *name;
+ int ret;
+
+ its_pmu = devm_kzalloc(dev, sizeof(*its_pmu), GFP_KERNEL);
+ if (!its_pmu)
+ return -ENOMEM;
+
+ spin_lock_init(&its_pmu->filter_lock);
+
+ pmu = &its_pmu->pmu;
+
+ /*
+ * HiSilicon Uncore PMU framework needs to get common hisi_pmu device
+ * from device's drvdata.
+ */
+ platform_set_drvdata(pdev, its_pmu);
+
+ ret = hisi_its_pmu_dev_init(pdev, its_pmu);
+ if (ret)
+ return ret;
+
+ ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state, &pmu->node);
+ if (ret)
+ return dev_err_probe(dev, ret, "Fail to register cpuhp instance\n");
+
+ ret = devm_add_action_or_reset(dev, hisi_its_pmu_remove_cpuhp_instance,
+ &pmu->node);
+ if (ret)
+ return ret;
+
+ hisi_pmu_init(pmu, THIS_MODULE);
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "hisi_scl%d_its%d",
+ pmu->topo.scl_id, pmu->topo.index_id);
+ if (!name)
+ return -ENOMEM;
+
+ ret = perf_pmu_register(&pmu->pmu, name, -1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Fail to register PMU\n");
+
+ return devm_add_action_or_reset(dev, hisi_its_pmu_unregister_pmu,
+ &pmu->pmu);
+}
+
+static struct hisi_its_pmu_regs hisi_its_v1_pmu_regs = {
+ .version = ITS_PMU_VERSION,
+ .pmu_ctrl = ITS_PMU_GLOBAL_CTRL,
+ .event_ctrl0 = ITS_PMU_EVENT_CTRL,
+ .event_cntr0 = ITS_PMU_COUNTER0,
+ .cntr_ctrl = ITS_PMU_COUNTER_CTRL,
+};
+
+static const struct hisi_pmu_dev_info hisi_its_v1 = {
+ .attr_groups = hisi_its_pmu_attr_groups,
+ .counter_bits = 48,
+ .check_event = ITS_PMU_EVENT_CTRL_TYPE,
+ .private = &hisi_its_v1_pmu_regs,
+};
+
+static const struct acpi_device_id hisi_its_pmu_ids[] = {
+ { "HISI0591", (kernel_ulong_t)&hisi_its_v1 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, hisi_its_pmu_ids);
+
+static struct platform_driver hisi_its_pmu_driver = {
+ .driver = {
+ .name = "hisi_its_pmu",
+ .acpi_match_table = hisi_its_pmu_ids,
+ .suppress_bind_attrs = true,
+ },
+ .probe = hisi_its_pmu_probe,
+};
+
+module_platform_driver(hisi_its_pmu_driver);
+
+MODULE_IMPORT_NS("HISI_PMU");
+MODULE_DESCRIPTION("HiSilicon SoC Uncore ITS PMU driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yushan Wang <wangyushan12@huawei.com>");
--
2.33.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] drivers/perf: hisi: Add cycle event for HIP13 MN PMU
2026-07-24 2:52 [PATCH v4 0/3] drivers/perf: hisi: Updates for HiSilicon uncore PMUs Yushan Wang
2026-07-24 2:52 ` [PATCH 1/3] drivers/perf: hisi: Consolidate uncore PMU cpuhp states Yushan Wang
2026-07-24 2:52 ` [PATCH 2/3] drivers/perf: hisi: Add support for uncore ITS PMU Yushan Wang
@ 2026-07-24 2:52 ` Yushan Wang
2 siblings, 0 replies; 5+ messages in thread
From: Yushan Wang @ 2026-07-24 2:52 UTC (permalink / raw)
To: will, mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel
Cc: u.kleine-koenig, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wangyushan12, wuyifan50
From: Yifan Wu <wuyifan50@huawei.com>
The MN (Miscellaneous Node) PMU on HiSilicon HIP13 exposes a cycle
counter in addition to the existing event set. Add a v2 event list
that includes the cycles event (0x0F) and a new hisi_mn_v2 dev_info
matched by the new ACPI id HISI0224.
Rename the existing event list, attribute group and attr_groups array
to *_v1 so the two MN PMU versions can coexist.
Signed-off-by: Yifan Wu <wuyifan50@huawei.com>
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
---
drivers/perf/hisilicon/hisi_uncore_mn_pmu.c | 63 ++++++++++++++++++---
1 file changed, 56 insertions(+), 7 deletions(-)
diff --git a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
index ad898153ff49..1ded8a6b2358 100644
--- a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
@@ -188,7 +188,7 @@ static const struct attribute_group hisi_mn_pmu_format_group = {
.attrs = hisi_mn_pmu_format_attr,
};
-static struct attribute *hisi_mn_pmu_events_attr[] = {
+static struct attribute *hisi_mn_pmu_events_attr_v1[] = {
HISI_PMU_EVENT_ATTR(req_eobarrier_num, 0x00),
HISI_PMU_EVENT_ATTR(req_ecbarrier_num, 0x01),
HISI_PMU_EVENT_ATTR(req_dvmop_num, 0x02),
@@ -215,14 +215,55 @@ static struct attribute *hisi_mn_pmu_events_attr[] = {
NULL
};
-static const struct attribute_group hisi_mn_pmu_events_group = {
+static const struct attribute_group hisi_mn_pmu_events_group_v1 = {
.name = "events",
- .attrs = hisi_mn_pmu_events_attr,
+ .attrs = hisi_mn_pmu_events_attr_v1,
};
-static const struct attribute_group *hisi_mn_pmu_attr_groups[] = {
+static const struct attribute_group *hisi_mn_pmu_attr_groups_v1[] = {
&hisi_mn_pmu_format_group,
- &hisi_mn_pmu_events_group,
+ &hisi_mn_pmu_events_group_v1,
+ &hisi_pmu_cpumask_attr_group,
+ &hisi_pmu_identifier_group,
+ NULL
+};
+
+static struct attribute *hisi_mn_pmu_events_attr_v2[] = {
+ HISI_PMU_EVENT_ATTR(req_eobarrier_num, 0x00),
+ HISI_PMU_EVENT_ATTR(req_ecbarrier_num, 0x01),
+ HISI_PMU_EVENT_ATTR(req_dvmop_num, 0x02),
+ HISI_PMU_EVENT_ATTR(req_dvmsync_num, 0x03),
+ HISI_PMU_EVENT_ATTR(req_retry_num, 0x04),
+ HISI_PMU_EVENT_ATTR(req_writenosnp_num, 0x05),
+ HISI_PMU_EVENT_ATTR(req_readnosnp_num, 0x06),
+ HISI_PMU_EVENT_ATTR(snp_dvm_num, 0x07),
+ HISI_PMU_EVENT_ATTR(snp_dvmsync_num, 0x08),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvm_num, 0x09),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvmsync_num, 0x0A),
+ HISI_PMU_EVENT_ATTR(mn_req_dvm_num, 0x0B),
+ HISI_PMU_EVENT_ATTR(mn_req_dvmsync_num, 0x0C),
+ HISI_PMU_EVENT_ATTR(pa_req_dvm_num, 0x0D),
+ HISI_PMU_EVENT_ATTR(pa_req_dvmsync_num, 0x0E),
+ HISI_PMU_EVENT_ATTR(cycles, 0x0F),
+ HISI_PMU_EVENT_ATTR(snp_dvm_latency, 0x80),
+ HISI_PMU_EVENT_ATTR(snp_dvmsync_latency, 0x81),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvm_latency, 0x82),
+ HISI_PMU_EVENT_ATTR(l3t_req_dvmsync_latency, 0x83),
+ HISI_PMU_EVENT_ATTR(mn_req_dvm_latency, 0x84),
+ HISI_PMU_EVENT_ATTR(mn_req_dvmsync_latency, 0x85),
+ HISI_PMU_EVENT_ATTR(pa_req_dvm_latency, 0x86),
+ HISI_PMU_EVENT_ATTR(pa_req_dvmsync_latency, 0x87),
+ NULL
+};
+
+static const struct attribute_group hisi_mn_pmu_events_group_v2 = {
+ .name = "events",
+ .attrs = hisi_mn_pmu_events_attr_v2,
+};
+
+static const struct attribute_group *hisi_mn_pmu_attr_groups_v2[] = {
+ &hisi_mn_pmu_format_group,
+ &hisi_mn_pmu_events_group_v2,
&hisi_pmu_cpumask_attr_group,
&hisi_pmu_identifier_group,
NULL
@@ -347,14 +388,22 @@ static struct hisi_mn_pmu_regs hisi_mn_v1_pmu_regs = {
};
static const struct hisi_pmu_dev_info hisi_mn_v1 = {
- .attr_groups = hisi_mn_pmu_attr_groups,
+ .attr_groups = hisi_mn_pmu_attr_groups_v1,
+ .counter_bits = 48,
+ .check_event = HISI_MN_EVTYPE_MASK,
+ .private = &hisi_mn_v1_pmu_regs,
+};
+
+static const struct hisi_pmu_dev_info hisi_mn_v2 = {
+ .attr_groups = hisi_mn_pmu_attr_groups_v2,
.counter_bits = 48,
.check_event = HISI_MN_EVTYPE_MASK,
.private = &hisi_mn_v1_pmu_regs,
};
static const struct acpi_device_id hisi_mn_pmu_acpi_match[] = {
- { "HISI0222", (kernel_ulong_t) &hisi_mn_v1 },
+ { "HISI0222", (kernel_ulong_t)&hisi_mn_v1 },
+ { "HISI0224", (kernel_ulong_t)&hisi_mn_v2 },
{ }
};
MODULE_DEVICE_TABLE(acpi, hisi_mn_pmu_acpi_match);
--
2.33.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/3] drivers/perf: hisi: Consolidate uncore PMU cpuhp states
2026-07-24 2:52 ` [PATCH 1/3] drivers/perf: hisi: Consolidate uncore PMU cpuhp states Yushan Wang
@ 2026-07-27 12:41 ` Robin Murphy
0 siblings, 0 replies; 5+ messages in thread
From: Robin Murphy @ 2026-07-27 12:41 UTC (permalink / raw)
To: Yushan Wang, will, mark.rutland, linux-arm-kernel, linux-kernel
Cc: u.kleine-koenig, linuxarm, liuyonglong, prime.zeng, wangzhou1,
wuyifan50
On 24/07/2026 3:52 am, Yushan Wang wrote:
> Every HiSilicon uncore PMU driver allocates its own static cpuhp state
> even though they all register identical online/offline callbacks. This
> wastes slots in the cpuhp state enum and needlessly fragments the
> hotplug state space.
>
> Move the cpuhp state setup into the shared hisi_uncore_pmu framework:
> register a single dynamic state (CPUHP_AP_ONLINE_DYN) at framework
> module init and export it for all HiSilicon uncore PMU drivers to use.
> Drop the now-unused static CPUHP_AP_PERF_ARM_HISI_* entries from
> include/linux/cpuhotplug.h.
>
> The L3C PMU driver keeps a private dynamic state because it has its own
> hotplug callbacks for migrating multiple per-CPU interrupt affinities,
> but switches from its former static slot to CPUHP_AP_ONLINE_DYN for
> consistency.
>
> No intended functional changes.
>
> Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
> ---
> drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c | 34 +++---------------
> drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 34 +++---------------
> drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 34 +++---------------
> drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 21 +++++------
> drivers/perf/hisilicon/hisi_uncore_mn_pmu.c | 35 ++----------------
> drivers/perf/hisilicon/hisi_uncore_noc_pmu.c | 35 ++----------------
> drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 34 +++---------------
> drivers/perf/hisilicon/hisi_uncore_pmu.c | 25 +++++++++++++
> drivers/perf/hisilicon/hisi_uncore_pmu.h | 2 ++
> drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 34 +++---------------
> drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | 36 ++-----------------
> include/linux/cpuhotplug.h | 6 ----
> 12 files changed, 67 insertions(+), 263 deletions(-)
Neat! Seems like a pretty nice win already, plus it only makes a
conversion easier if my generic hotplug idea takes off :)
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> diff --git a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c
> index b879b81adfdd..83967725c51c 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c
> @@ -295,7 +295,7 @@ static int hisi_cpa_pmu_probe(struct platform_device *pdev)
>
> /* Power Management should be disabled before using CPA PMU. */
> hisi_cpa_pmu_disable_pm(cpa_pmu);
> - ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
> &cpa_pmu->node);
> if (ret) {
> dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
> @@ -307,7 +307,7 @@ static int hisi_cpa_pmu_probe(struct platform_device *pdev)
> if (ret) {
> dev_err(cpa_pmu->dev, "PMU register failed\n");
> cpuhp_state_remove_instance_nocalls(
> - CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE, &cpa_pmu->node);
> + hisi_uncore_pmu_cpuhp_state, &cpa_pmu->node);
> hisi_cpa_pmu_enable_pm(cpa_pmu);
> return ret;
> }
> @@ -321,7 +321,7 @@ static void hisi_cpa_pmu_remove(struct platform_device *pdev)
> struct hisi_pmu *cpa_pmu = platform_get_drvdata(pdev);
>
> perf_pmu_unregister(&cpa_pmu->pmu);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
> &cpa_pmu->node);
> hisi_cpa_pmu_enable_pm(cpa_pmu);
> }
> @@ -336,33 +336,7 @@ static struct platform_driver hisi_cpa_pmu_driver = {
> .remove = hisi_cpa_pmu_remove,
> };
>
> -static int __init hisi_cpa_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
> - "AP_PERF_ARM_HISI_CPA_ONLINE",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret) {
> - pr_err("setup hotplug failed: %d\n", ret);
> - return ret;
> - }
> -
> - ret = platform_driver_register(&hisi_cpa_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE);
> -
> - return ret;
> -}
> -module_init(hisi_cpa_pmu_module_init);
> -
> -static void __exit hisi_cpa_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_cpa_pmu_driver);
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE);
> -}
> -module_exit(hisi_cpa_pmu_module_exit);
> +module_platform_driver(hisi_cpa_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon SoC CPA PMU driver");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> index 21c494881ca0..e905160523ee 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> @@ -401,7 +401,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
> if (!name)
> return -ENOMEM;
>
> - ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
> &ddrc_pmu->node);
> if (ret) {
> dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret);
> @@ -414,7 +414,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
> if (ret) {
> dev_err(ddrc_pmu->dev, "DDRC PMU register failed!\n");
> cpuhp_state_remove_instance_nocalls(
> - CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, &ddrc_pmu->node);
> + hisi_uncore_pmu_cpuhp_state, &ddrc_pmu->node);
> }
>
> return ret;
> @@ -425,7 +425,7 @@ static void hisi_ddrc_pmu_remove(struct platform_device *pdev)
> struct hisi_pmu *ddrc_pmu = platform_get_drvdata(pdev);
>
> perf_pmu_unregister(&ddrc_pmu->pmu);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
> &ddrc_pmu->node);
> }
>
> @@ -501,33 +501,7 @@ static struct platform_driver hisi_ddrc_pmu_driver = {
> .remove = hisi_ddrc_pmu_remove,
> };
>
> -static int __init hisi_ddrc_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
> - "AP_PERF_ARM_HISI_DDRC_ONLINE",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret) {
> - pr_err("DDRC PMU: setup hotplug, ret = %d\n", ret);
> - return ret;
> - }
> -
> - ret = platform_driver_register(&hisi_ddrc_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
> -
> - return ret;
> -}
> -module_init(hisi_ddrc_pmu_module_init);
> -
> -static void __exit hisi_ddrc_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_ddrc_pmu_driver);
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
> -}
> -module_exit(hisi_ddrc_pmu_module_exit);
> +module_platform_driver(hisi_ddrc_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon SoC DDRC uncore PMU driver");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> index 97cfaa586a87..93a250b7abb8 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> @@ -490,7 +490,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
> if (!name)
> return -ENOMEM;
>
> - ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
> &hha_pmu->node);
> if (ret) {
> dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
> @@ -503,7 +503,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
> if (ret) {
> dev_err(hha_pmu->dev, "HHA PMU register failed!\n");
> cpuhp_state_remove_instance_nocalls(
> - CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, &hha_pmu->node);
> + hisi_uncore_pmu_cpuhp_state, &hha_pmu->node);
> }
>
> return ret;
> @@ -514,7 +514,7 @@ static void hisi_hha_pmu_remove(struct platform_device *pdev)
> struct hisi_pmu *hha_pmu = platform_get_drvdata(pdev);
>
> perf_pmu_unregister(&hha_pmu->pmu);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
> &hha_pmu->node);
> }
>
> @@ -528,33 +528,7 @@ static struct platform_driver hisi_hha_pmu_driver = {
> .remove = hisi_hha_pmu_remove,
> };
>
> -static int __init hisi_hha_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
> - "AP_PERF_ARM_HISI_HHA_ONLINE",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret) {
> - pr_err("HHA PMU: Error setup hotplug, ret = %d;\n", ret);
> - return ret;
> - }
> -
> - ret = platform_driver_register(&hisi_hha_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE);
> -
> - return ret;
> -}
> -module_init(hisi_hha_pmu_module_init);
> -
> -static void __exit hisi_hha_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_hha_pmu_driver);
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE);
> -}
> -module_exit(hisi_hha_pmu_module_exit);
> +module_platform_driver(hisi_hha_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon SoC HHA uncore PMU driver");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> index f963e4f9e552..0b78a0e094dd 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> @@ -93,6 +93,8 @@ struct hisi_l3c_pmu_ext {
> bool support_ext;
> };
>
> +static enum cpuhp_state hisi_l3c_pmu_cpuhp_state;
> +
> static bool support_ext(struct hisi_l3c_pmu *pmu)
> {
> struct hisi_l3c_pmu_ext *l3c_pmu_ext = pmu->l3c_pmu.dev_info->private;
> @@ -845,8 +847,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
> if (!name)
> return -ENOMEM;
>
> - ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
> - &l3c_pmu->node);
> + ret = cpuhp_state_add_instance(hisi_l3c_pmu_cpuhp_state, &l3c_pmu->node);
> if (ret) {
> dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
> return ret;
> @@ -858,7 +859,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
> if (ret) {
> dev_err(l3c_pmu->dev, "L3C PMU register failed!\n");
> cpuhp_state_remove_instance_nocalls(
> - CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, &l3c_pmu->node);
> + hisi_l3c_pmu_cpuhp_state, &l3c_pmu->node);
> }
>
> return ret;
> @@ -869,7 +870,7 @@ static void hisi_l3c_pmu_remove(struct platform_device *pdev)
> struct hisi_pmu *l3c_pmu = platform_get_drvdata(pdev);
>
> perf_pmu_unregister(&l3c_pmu->pmu);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_l3c_pmu_cpuhp_state,
> &l3c_pmu->node);
> }
>
> @@ -939,20 +940,20 @@ static int hisi_l3c_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
>
> static int __init hisi_l3c_pmu_module_init(void)
> {
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
> + int ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
> "AP_PERF_ARM_HISI_L3_ONLINE",
> hisi_l3c_pmu_online_cpu,
> hisi_l3c_pmu_offline_cpu);
> - if (ret) {
> + if (ret < 0) {
> pr_err("L3C PMU: Error setup hotplug, ret = %d\n", ret);
> return ret;
> }
>
> + hisi_l3c_pmu_cpuhp_state = ret;
> +
> ret = platform_driver_register(&hisi_l3c_pmu_driver);
> if (ret)
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);
> + cpuhp_remove_multi_state(hisi_l3c_pmu_cpuhp_state);
>
> return ret;
> }
> @@ -961,7 +962,7 @@ module_init(hisi_l3c_pmu_module_init);
> static void __exit hisi_l3c_pmu_module_exit(void)
> {
> platform_driver_unregister(&hisi_l3c_pmu_driver);
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);
> + cpuhp_remove_multi_state(hisi_l3c_pmu_cpuhp_state);
> }
> module_exit(hisi_l3c_pmu_module_exit);
>
> diff --git a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
> index 246cc0333099..ad898153ff49 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c
> @@ -13,9 +13,6 @@
>
> #include "hisi_uncore_pmu.h"
>
> -/* Dynamic CPU hotplug state used by MN PMU */
> -static enum cpuhp_state hisi_mn_pmu_online;
> -
> /* MN register definition */
> #define HISI_MN_DYNAMIC_CTRL_REG 0x400
> #define HISI_MN_DYNAMIC_CTRL_EN BIT(0)
> @@ -291,7 +288,7 @@ static int hisi_mn_pmu_dev_init(struct platform_device *pdev,
>
> static void hisi_mn_pmu_remove_cpuhp(void *hotplug_node)
> {
> - cpuhp_state_remove_instance_nocalls(hisi_mn_pmu_online, hotplug_node);
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state, hotplug_node);
> }
>
> static void hisi_mn_pmu_unregister(void *pmu)
> @@ -320,7 +317,7 @@ static int hisi_mn_pmu_probe(struct platform_device *pdev)
> if (!name)
> return -ENOMEM;
>
> - ret = cpuhp_state_add_instance(hisi_mn_pmu_online, &mn_pmu->node);
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state, &mn_pmu->node);
> if (ret)
> return dev_err_probe(&pdev->dev, ret, "Failed to register cpu hotplug\n");
>
> @@ -376,33 +373,7 @@ static struct platform_driver hisi_mn_pmu_driver = {
> .probe = hisi_mn_pmu_probe,
> };
>
> -static int __init hisi_mn_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "perf/hisi/mn:online",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret < 0) {
> - pr_err("hisi_mn_pmu: Failed to setup MN PMU hotplug: %d\n", ret);
> - return ret;
> - }
> - hisi_mn_pmu_online = ret;
> -
> - ret = platform_driver_register(&hisi_mn_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(hisi_mn_pmu_online);
> -
> - return ret;
> -}
> -module_init(hisi_mn_pmu_module_init);
> -
> -static void __exit hisi_mn_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_mn_pmu_driver);
> - cpuhp_remove_multi_state(hisi_mn_pmu_online);
> -}
> -module_exit(hisi_mn_pmu_module_exit);
> +module_platform_driver(hisi_mn_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon SoC MN uncore PMU driver");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c
> index 616f4af57db7..abf44fa46d17 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c
> @@ -41,9 +41,6 @@
> HISI_PMU_EVENT_ATTR_EXTRACTOR(ch, config1, 2, 0);
> HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_en, config1, 3, 3);
>
> -/* Dynamic CPU hotplug state used by this PMU driver */
> -static enum cpuhp_state hisi_noc_pmu_cpuhp_state;
> -
> struct hisi_noc_pmu_regs {
> u32 version;
> u32 pmu_ctrl;
> @@ -324,7 +321,7 @@ static int hisi_noc_pmu_dev_init(struct platform_device *pdev, struct hisi_pmu *
>
> static void hisi_noc_pmu_remove_cpuhp_instance(void *hotplug_node)
> {
> - cpuhp_state_remove_instance_nocalls(hisi_noc_pmu_cpuhp_state, hotplug_node);
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state, hotplug_node);
> }
>
> static void hisi_noc_pmu_unregister_pmu(void *pmu)
> @@ -353,7 +350,7 @@ static int hisi_noc_pmu_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> - ret = cpuhp_state_add_instance(hisi_noc_pmu_cpuhp_state, &noc_pmu->node);
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state, &noc_pmu->node);
> if (ret)
> return dev_err_probe(dev, ret, "Fail to register cpuhp instance\n");
>
> @@ -408,33 +405,7 @@ static struct platform_driver hisi_noc_pmu_driver = {
> .probe = hisi_noc_pmu_probe,
> };
>
> -static int __init hisi_noc_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "perf/hisi/noc:online",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret < 0) {
> - pr_err("hisi_noc_pmu: Fail to setup cpuhp callbacks, ret = %d\n", ret);
> - return ret;
> - }
> - hisi_noc_pmu_cpuhp_state = ret;
> -
> - ret = platform_driver_register(&hisi_noc_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(hisi_noc_pmu_cpuhp_state);
> -
> - return ret;
> -}
> -module_init(hisi_noc_pmu_module_init);
> -
> -static void __exit hisi_noc_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_noc_pmu_driver);
> - cpuhp_remove_multi_state(hisi_noc_pmu_cpuhp_state);
> -}
> -module_exit(hisi_noc_pmu_module_exit);
> +module_platform_driver(hisi_noc_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon SoC Uncore NoC PMU driver");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
> index 80108c63cb60..3d1e0af64260 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
> @@ -468,7 +468,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
> if (!name)
> return -ENOMEM;
>
> - ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
> &pa_pmu->node);
> if (ret) {
> dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
> @@ -479,7 +479,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
> ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
> if (ret) {
> dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
> &pa_pmu->node);
> return ret;
> }
> @@ -493,7 +493,7 @@ static void hisi_pa_pmu_remove(struct platform_device *pdev)
> struct hisi_pmu *pa_pmu = platform_get_drvdata(pdev);
>
> perf_pmu_unregister(&pa_pmu->pmu);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
> &pa_pmu->node);
> }
>
> @@ -515,33 +515,7 @@ static struct platform_driver hisi_pa_pmu_driver = {
> .remove = hisi_pa_pmu_remove,
> };
>
> -static int __init hisi_pa_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> - "AP_PERF_ARM_HISI_PA_ONLINE",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret) {
> - pr_err("PA PMU: cpuhp state setup failed, ret = %d\n", ret);
> - return ret;
> - }
> -
> - ret = platform_driver_register(&hisi_pa_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
> -
> - return ret;
> -}
> -module_init(hisi_pa_pmu_module_init);
> -
> -static void __exit hisi_pa_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_pa_pmu_driver);
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
> -}
> -module_exit(hisi_pa_pmu_module_exit);
> +module_platform_driver(hisi_pa_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon Protocol Adapter uncore PMU driver");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
> index de71dcf11653..276785a79ae9 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
> @@ -23,6 +23,9 @@
>
> #define HISI_MAX_PERIOD(nr) (GENMASK_ULL((nr) - 1, 0))
>
> +enum cpuhp_state hisi_uncore_pmu_cpuhp_state;
> +EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_cpuhp_state, "HISI_PMU");
> +
> /*
> * PMU event attributes
> */
> @@ -621,5 +624,27 @@ void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module)
> }
> EXPORT_SYMBOL_NS_GPL(hisi_pmu_init, "HISI_PMU");
>
> +static int __init hisi_uncore_pmu_init(void)
> +{
> + int ret;
> +
> + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "perf/hisi/uncore:online",
> + hisi_uncore_pmu_online_cpu,
> + hisi_uncore_pmu_offline_cpu);
> + if (ret < 0)
> + return ret;
> +
> + hisi_uncore_pmu_cpuhp_state = ret;
> +
> + return 0;
> +}
> +module_init(hisi_uncore_pmu_init);
> +
> +static void __exit hisi_uncore_pmu_exit(void)
> +{
> + cpuhp_remove_multi_state(hisi_uncore_pmu_cpuhp_state);
> +}
> +module_exit(hisi_uncore_pmu_exit);
> +
> MODULE_DESCRIPTION("HiSilicon SoC uncore Performance Monitor driver framework");
> MODULE_LICENSE("GPL v2");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
> index 3ffe6acda653..e5a4b3898865 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
> +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
> @@ -171,4 +171,6 @@ int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
> void hisi_uncore_pmu_init_topology(struct hisi_pmu *hisi_pmu, struct device *dev);
>
> void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module);
> +
> +extern enum cpuhp_state hisi_uncore_pmu_cpuhp_state;
> #endif /* __HISI_UNCORE_PMU_H__ */
> diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
> index cd32d606df05..d01340ff2e5c 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
> @@ -503,7 +503,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
> if (!name)
> return -ENOMEM;
>
> - ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state,
> &sllc_pmu->node);
> if (ret) {
> dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
> @@ -515,7 +515,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
> ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
> if (ret) {
> dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
> &sllc_pmu->node);
> return ret;
> }
> @@ -530,7 +530,7 @@ static void hisi_sllc_pmu_remove(struct platform_device *pdev)
> struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev);
>
> perf_pmu_unregister(&sllc_pmu->pmu);
> - cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state,
> &sllc_pmu->node);
> }
>
> @@ -551,33 +551,7 @@ static struct platform_driver hisi_sllc_pmu_driver = {
> .remove = hisi_sllc_pmu_remove,
> };
>
> -static int __init hisi_sllc_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> - "AP_PERF_ARM_HISI_SLLC_ONLINE",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret) {
> - pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret);
> - return ret;
> - }
> -
> - ret = platform_driver_register(&hisi_sllc_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
> -
> - return ret;
> -}
> -module_init(hisi_sllc_pmu_module_init);
> -
> -static void __exit hisi_sllc_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_sllc_pmu_driver);
> - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
> -}
> -module_exit(hisi_sllc_pmu_module_exit);
> +module_platform_driver(hisi_sllc_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver");
> diff --git a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c
> index e8186b6e1687..b4d017a5d688 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c
> @@ -13,9 +13,6 @@
>
> #include "hisi_uncore_pmu.h"
>
> -/* Dynamic CPU hotplug state used by UC PMU */
> -static enum cpuhp_state hisi_uc_pmu_online;
> -
> /* UC register definition */
> #define HISI_UC_INT_MASK_REG 0x0800
> #define HISI_UC_INT_STS_REG 0x0808
> @@ -488,7 +485,7 @@ static int hisi_uc_pmu_dev_probe(struct platform_device *pdev,
>
> static void hisi_uc_pmu_remove_cpuhp_instance(void *hotplug_node)
> {
> - cpuhp_state_remove_instance_nocalls(hisi_uc_pmu_online, hotplug_node);
> + cpuhp_state_remove_instance_nocalls(hisi_uncore_pmu_cpuhp_state, hotplug_node);
> }
>
> static void hisi_uc_pmu_unregister_pmu(void *pmu)
> @@ -518,7 +515,7 @@ static int hisi_uc_pmu_probe(struct platform_device *pdev)
> if (!name)
> return -ENOMEM;
>
> - ret = cpuhp_state_add_instance(hisi_uc_pmu_online, &uc_pmu->node);
> + ret = cpuhp_state_add_instance(hisi_uncore_pmu_cpuhp_state, &uc_pmu->node);
> if (ret)
> return dev_err_probe(&pdev->dev, ret, "Error registering hotplug\n");
>
> @@ -559,34 +556,7 @@ static struct platform_driver hisi_uc_pmu_driver = {
> .probe = hisi_uc_pmu_probe,
> };
>
> -static int __init hisi_uc_pmu_module_init(void)
> -{
> - int ret;
> -
> - ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
> - "perf/hisi/uc:online",
> - hisi_uncore_pmu_online_cpu,
> - hisi_uncore_pmu_offline_cpu);
> - if (ret < 0) {
> - pr_err("UC PMU: Error setup hotplug, ret = %d\n", ret);
> - return ret;
> - }
> - hisi_uc_pmu_online = ret;
> -
> - ret = platform_driver_register(&hisi_uc_pmu_driver);
> - if (ret)
> - cpuhp_remove_multi_state(hisi_uc_pmu_online);
> -
> - return ret;
> -}
> -module_init(hisi_uc_pmu_module_init);
> -
> -static void __exit hisi_uc_pmu_module_exit(void)
> -{
> - platform_driver_unregister(&hisi_uc_pmu_driver);
> - cpuhp_remove_multi_state(hisi_uc_pmu_online);
> -}
> -module_exit(hisi_uc_pmu_module_exit);
> +module_platform_driver(hisi_uc_pmu_driver);
>
> MODULE_IMPORT_NS("HISI_PMU");
> MODULE_DESCRIPTION("HiSilicon SoC UC uncore PMU driver");
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> index 0fb3a2a62eb0..965d6ce02a29 100644
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -210,12 +210,6 @@ enum cpuhp_state {
> CPUHP_AP_PERF_S390_SF_ONLINE,
> CPUHP_AP_PERF_ARM_CCI_ONLINE,
> CPUHP_AP_PERF_ARM_CCN_ONLINE,
> - CPUHP_AP_PERF_ARM_HISI_CPA_ONLINE,
> - CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
> - CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
> - CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
> - CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
> - CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
> CPUHP_AP_PERF_ARM_HISI_PCIE_PMU_ONLINE,
> CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
> CPUHP_AP_PERF_ARM_L2X0_ONLINE,
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-27 12:42 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 2:52 [PATCH v4 0/3] drivers/perf: hisi: Updates for HiSilicon uncore PMUs Yushan Wang
2026-07-24 2:52 ` [PATCH 1/3] drivers/perf: hisi: Consolidate uncore PMU cpuhp states Yushan Wang
2026-07-27 12:41 ` Robin Murphy
2026-07-24 2:52 ` [PATCH 2/3] drivers/perf: hisi: Add support for uncore ITS PMU Yushan Wang
2026-07-24 2:52 ` [PATCH 3/3] drivers/perf: hisi: Add cycle event for HIP13 MN PMU Yushan Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox