From: Chen Jun chenjun102@huawei.com
Signed-off-by: Chen Jun chenjun102@huawei.com --- drivers/perf/hisilicon/Makefile | 4 +- .../hisilicon/hisi_uncore_ddrc_pmu_mini.c | 404 +++++++++++++ .../perf/hisilicon/hisi_uncore_l3c_pmu_mini.c | 530 ++++++++++++++++++ drivers/perf/hisilicon/hisi_uncore_pmu.c | 47 +- drivers/perf/hisilicon/hisi_uncore_pmu.h | 13 +- include/linux/cpuhotplug.h | 2 + 6 files changed, 995 insertions(+), 5 deletions(-) create mode 100644 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu_mini.c create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c_pmu_mini.c
diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile index 22e384cdfd53..a914e2211dcd 100644 --- a/drivers/perf/hisilicon/Makefile +++ b/drivers/perf/hisilicon/Makefile @@ -3,4 +3,6 @@ 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_l3t_pmu.o \ - hisi_uncore_lpddrc_pmu.o + hisi_uncore_lpddrc_pmu.o \ + hisi_uncore_ddrc_pmu_mini.o \ + hisi_uncore_l3c_pmu_mini.o diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu_mini.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu_mini.c new file mode 100644 index 000000000000..41f705a22ac8 --- /dev/null +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu_mini.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HiSilicon SoC DDRC uncore Hardware event counters support + * + * Copyright (C) 2017 Hisilicon Limited + * Author: Shaokun Zhang zhangshaokun@hisilicon.com + * Anurup M anurup.m@huawei.com + * + * This code is based on the uncore PMUs like arm-cci and arm-ccn. + */ +#include <linux/acpi.h> +#include <linux/bug.h> +#include <linux/cpuhotplug.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/list.h> +#include <linux/smp.h> + +#include "hisi_uncore_pmu.h" + +/* DDRC register definition in v1 */ +#define DDRC_PERF_CTRL 0x4010 +#define DDRC_FLUX_WR 0x4380 +#define DDRC_FLUX_RD 0x4384 +#define DDRC_FLUX_WCMD 0x4388 +#define DDRC_FLUX_RCMD 0x438c +#define DDRC_PRE_CMD 0x43c0 +#define DDRC_ACT_CMD 0x43c4 +#define DDRC_RNK_CHG 0x43cc +#define DDRC_RW_CHG 0x43d0 +#define DDRC_EVENT_CTRL 0x46C0 +#define DDRC_INT_MASK 0x46c8 +#define DDRC_INT_STATUS 0x46cc +#define DDRC_INT_CLEAR 0x46d0 + +/* DDRC has 8-counters */ +#define DDRC_NR_COUNTERS 0x8 +#define DDRC_PERF_CTRL_EN 0x2 +#define DDRC_NR_EVENTS 0x7 + +/* + * For PMU v1, there are eight-events and every event has been mapped + * to fixed-purpose counters which register offset is not consistent. + * Therefore there is no write event type and we assume that event + * code (0 to 7) is equal to counter index in PMU driver. + */ +#define GET_DDRC_EVENTID(hwc) (hwc->config_base & 0x7) + +static const u32 ddrc_reg_off[] = { + DDRC_FLUX_WR, DDRC_FLUX_RD, DDRC_FLUX_WCMD, DDRC_FLUX_RCMD, + DDRC_PRE_CMD, DDRC_ACT_CMD, DDRC_RNK_CHG, DDRC_RW_CHG +}; + +/* + * Select the counter register offset using the counter index. + * In PMU v1, there are no programmable counter, the count + * is read form the statistics counter register itself. + */ +static u32 hisi_ddrc_pmu_mini_get_counter_offset(int cntr_idx) +{ + return ddrc_reg_off[cntr_idx]; +} + +static u64 hisi_ddrc_pmu_mini_read_counter(struct hisi_pmu *ddrc_pmu_mini, + struct hw_perf_event *hwc) +{ + return readl(ddrc_pmu_mini->base + + hisi_ddrc_pmu_mini_get_counter_offset(hwc->idx)); +} + +static void hisi_ddrc_pmu_mini_write_counter(struct hisi_pmu *ddrc_pmu_mini, + struct hw_perf_event *hwc, u64 val) +{ + writel((u32)val, + ddrc_pmu_mini->base + hisi_ddrc_pmu_mini_get_counter_offset(hwc->idx)); +} + +static void hisi_ddrc_pmu_mini_write_evtype(struct hisi_pmu *hha_pmu, int idx, + u32 type) +{ +} + +static void hisi_ddrc_pmu_mini_start_counters(struct hisi_pmu *ddrc_pmu_mini) +{ + u32 val; + + /* Set perf_enable in DDRC_PERF_CTRL to start event counting */ + val = readl(ddrc_pmu_mini->base + DDRC_PERF_CTRL); + val |= DDRC_PERF_CTRL_EN; + writel(val, ddrc_pmu_mini->base + DDRC_PERF_CTRL); +} + +static void hisi_ddrc_pmu_mini_stop_counters(struct hisi_pmu *ddrc_pmu_mini) +{ + u32 val; + + /* Clear perf_enable in DDRC_PERF_CTRL to stop event counting */ + val = readl(ddrc_pmu_mini->base + DDRC_PERF_CTRL); + val &= ~DDRC_PERF_CTRL_EN; + writel(val, ddrc_pmu_mini->base + DDRC_PERF_CTRL); +} + +static void hisi_ddrc_pmu_mini_enable_counter(struct hisi_pmu *ddrc_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Set counter index(event code) in DDRC_EVENT_CTRL register */ + val = readl(ddrc_pmu_mini->base + DDRC_EVENT_CTRL); + val |= (1 << GET_DDRC_EVENTID(hwc)); + writel(val, ddrc_pmu_mini->base + DDRC_EVENT_CTRL); +} + +static void hisi_ddrc_pmu_mini_disable_counter(struct hisi_pmu *ddrc_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Clear counter index(event code) in DDRC_EVENT_CTRL register */ + val = readl(ddrc_pmu_mini->base + DDRC_EVENT_CTRL); + val &= ~(1 << GET_DDRC_EVENTID(hwc)); + writel(val, ddrc_pmu_mini->base + DDRC_EVENT_CTRL); +} + +static int hisi_ddrc_pmu_mini_get_event_idx(struct perf_event *event) +{ + struct hisi_pmu *ddrc_pmu_mini = to_hisi_pmu(event->pmu); + unsigned long *used_mask = ddrc_pmu_mini->pmu_events.used_mask; + struct hw_perf_event *hwc = &event->hw; + /* For DDRC PMU, we use event code as counter index */ + int idx = GET_DDRC_EVENTID(hwc); + + if (test_bit(idx, used_mask)) + return -EAGAIN; + + set_bit(idx, used_mask); + + return idx; +} + +static void hisi_ddrc_pmu_mini_enable_counter_int(struct hisi_pmu *ddrc_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Write 0 to enable interrupt */ + val = readl(ddrc_pmu_mini->base + DDRC_INT_MASK); + val &= ~(1 << hwc->idx); + writel(val, ddrc_pmu_mini->base + DDRC_INT_MASK); +} + +static void hisi_ddrc_pmu_mini_disable_counter_int(struct hisi_pmu *ddrc_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Write 1 to mask interrupt */ + val = readl(ddrc_pmu_mini->base + DDRC_INT_MASK); + val |= 1 << hwc->idx; + writel(val, ddrc_pmu_mini->base + DDRC_INT_MASK); +} + +static u32 hisi_ddrc_pmu_mini_get_int_status(struct hisi_pmu *ddrc_pmu_mini) +{ + return readl(ddrc_pmu_mini->base + DDRC_INT_STATUS); +} + +static void hisi_ddrc_pmu_mini_clear_int_status(struct hisi_pmu *ddrc_pmu_mini, + int idx) +{ + writel(1 << idx, ddrc_pmu_mini->base + DDRC_INT_CLEAR); +} + +static const struct acpi_device_id hisi_ddrc_pmu_mini_acpi_match[] = { + {} +}; +MODULE_DEVICE_TABLE(acpi, hisi_ddrc_pmu_mini_acpi_match); + +static const struct of_device_id ddrc_of_match[] = { + { .compatible = "hisilicon,ddrc-pmu-mini", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ddrc_of_match); + +static int hisi_ddrc_pmu_mini_init_data(struct platform_device *pdev, + struct hisi_pmu *ddrc_pmu_mini) +{ + /* + * Use the SCCL_ID and DDRC channel ID to identify the + * DDRC PMU, while SCCL_ID is in MPIDR[aff2]. + */ + if (device_property_read_u32(&pdev->dev, "hisilicon,ch-id", + &ddrc_pmu_mini->index_id)) { + dev_err(&pdev->dev, "Can not read ddrc channel-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", + &ddrc_pmu_mini->sccl_id)) { + dev_err(&pdev->dev, "Can not read ddrc sccl-id!\n"); + return -EINVAL; + } + /* DDRC PMUs only share the same SCCL */ + ddrc_pmu_mini->ccl_id = -1; + + ddrc_pmu_mini->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ddrc_pmu_mini->base)) { + dev_err(&pdev->dev, "ioremap failed for ddrc_pmu_mini resource\n"); + return PTR_ERR(ddrc_pmu_mini->base); + } + + return 0; +} + +static struct attribute *hisi_ddrc_pmu_mini_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-4"), + NULL, +}; + +static const struct attribute_group hisi_ddrc_pmu_mini_format_group = { + .name = "format", + .attrs = hisi_ddrc_pmu_mini_format_attr, +}; + +static struct attribute *hisi_ddrc_pmu_mini_events_attr[] = { + HISI_PMU_EVENT_ATTR(flux_write, 0x00), + HISI_PMU_EVENT_ATTR(flux_read, 0x01), + HISI_PMU_EVENT_ATTR(flux_write_cmd, 0x02), + HISI_PMU_EVENT_ATTR(flux_read_cmd, 0x03), + HISI_PMU_EVENT_ATTR(fluxid_write, 0x04), + HISI_PMU_EVENT_ATTR(fluxid_read, 0x05), + HISI_PMU_EVENT_ATTR(fluxid_write_cmd, 0x06), + HISI_PMU_EVENT_ATTR(fluxid_read_cmd, 0x07), + NULL, +}; + +static const struct attribute_group hisi_ddrc_pmu_mini_events_group = { + .name = "events", + .attrs = hisi_ddrc_pmu_mini_events_attr, +}; + +static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); + +static struct attribute *hisi_ddrc_pmu_mini_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static const struct attribute_group hisi_ddrc_pmu_mini_cpumask_attr_group = { + .attrs = hisi_ddrc_pmu_mini_cpumask_attrs, +}; + +static const struct attribute_group *hisi_ddrc_pmu_mini_attr_groups[] = { + &hisi_ddrc_pmu_mini_format_group, + &hisi_ddrc_pmu_mini_events_group, + &hisi_ddrc_pmu_mini_cpumask_attr_group, + NULL, +}; + +static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = { + .write_evtype = hisi_ddrc_pmu_mini_write_evtype, + .get_event_idx = hisi_ddrc_pmu_mini_get_event_idx, + .start_counters = hisi_ddrc_pmu_mini_start_counters, + .stop_counters = hisi_ddrc_pmu_mini_stop_counters, + .enable_counter = hisi_ddrc_pmu_mini_enable_counter, + .disable_counter = hisi_ddrc_pmu_mini_disable_counter, + .enable_counter_int = hisi_ddrc_pmu_mini_enable_counter_int, + .disable_counter_int = hisi_ddrc_pmu_mini_disable_counter_int, + .write_counter = hisi_ddrc_pmu_mini_write_counter, + .read_counter = hisi_ddrc_pmu_mini_read_counter, + .get_int_status = hisi_ddrc_pmu_mini_get_int_status, + .clear_int_status = hisi_ddrc_pmu_mini_clear_int_status, +}; + +static int hisi_ddrc_pmu_mini_dev_probe(struct platform_device *pdev, + struct hisi_pmu *ddrc_pmu_mini) +{ + int ret; + + ret = hisi_ddrc_pmu_mini_init_data(pdev, ddrc_pmu_mini); + if (ret) + return ret; + + ret = hisi_uncore_pmu_init_irq(ddrc_pmu_mini, pdev); + if (ret) + return ret; + + ddrc_pmu_mini->counter_bits = 32; + ddrc_pmu_mini->check_event = DDRC_NR_EVENTS; + ddrc_pmu_mini->pmu_events.attr_groups = hisi_ddrc_pmu_mini_attr_groups; + ddrc_pmu_mini->ops = &hisi_uncore_ddrc_ops; + ddrc_pmu_mini->num_counters = DDRC_NR_COUNTERS; + ddrc_pmu_mini->dev = &pdev->dev; + ddrc_pmu_mini->on_cpu = -1; + + return 0; +} + +static int hisi_ddrc_pmu_mini_probe(struct platform_device *pdev) +{ + struct hisi_pmu *ddrc_pmu_mini; + char *name; + int ret; + + ddrc_pmu_mini = devm_kzalloc(&pdev->dev, sizeof(*ddrc_pmu_mini), GFP_KERNEL); + if (!ddrc_pmu_mini) + return -ENOMEM; + + platform_set_drvdata(pdev, ddrc_pmu_mini); + + ret = hisi_ddrc_pmu_mini_dev_probe(pdev, ddrc_pmu_mini); + if (ret) + return ret; + + ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_DDRC_MINI_ONLINE, + &ddrc_pmu_mini->node); + if (ret) { + dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret); + return ret; + } + + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_ddrc%u_%u", + ddrc_pmu_mini->index_id, ddrc_pmu_mini->sccl_id - 1); + + ddrc_pmu_mini->pmu = (struct pmu) { + .name = name, + .module = THIS_MODULE, + .task_ctx_nr = perf_invalid_context, + .event_init = hisi_uncore_pmu_event_init, + .pmu_enable = hisi_uncore_pmu_enable, + .pmu_disable = hisi_uncore_pmu_disable, + .add = hisi_uncore_pmu_add, + .del = hisi_uncore_pmu_del, + .start = hisi_uncore_pmu_start, + .stop = hisi_uncore_pmu_stop, + .read = hisi_uncore_pmu_read, + .attr_groups = ddrc_pmu_mini->pmu_events.attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + }; + + ret = perf_pmu_register(&ddrc_pmu_mini->pmu, name, -1); + if (ret) { + dev_err(ddrc_pmu_mini->dev, "DDRC PMU register failed!\n"); + cpuhp_state_remove_instance_nocalls( + CPUHP_AP_PERF_ARM_HISI_DDRC_MINI_ONLINE, &ddrc_pmu_mini->node); + } + + return ret; +} + +static int hisi_ddrc_pmu_mini_remove(struct platform_device *pdev) +{ + struct hisi_pmu *ddrc_pmu_mini = platform_get_drvdata(pdev); + + perf_pmu_unregister(&ddrc_pmu_mini->pmu); + cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_DDRC_MINI_ONLINE, + &ddrc_pmu_mini->node); + return 0; +} + +static struct platform_driver hisi_ddrc_pmu_mini_driver = { + .driver = { + .name = "hisi_ddrc_pmu_mini", + .acpi_match_table = ACPI_PTR(hisi_ddrc_pmu_mini_acpi_match), + .of_match_table = ddrc_of_match, + .suppress_bind_attrs = true, + }, + .probe = hisi_ddrc_pmu_mini_probe, + .remove = hisi_ddrc_pmu_mini_remove, +}; + +static int __init hisi_ddrc_pmu_mini_module_init(void) +{ + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_DDRC_MINI_ONLINE, + "AP_PERF_ARM_HISI_DDRC_MINI_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_mini_driver); + if (ret) + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_MINI_ONLINE); + + return ret; +} +module_init(hisi_ddrc_pmu_mini_module_init); + +static void __exit hisi_ddrc_pmu_mini_module_exit(void) +{ + platform_driver_unregister(&hisi_ddrc_pmu_mini_driver); + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_MINI_ONLINE); + +} +module_exit(hisi_ddrc_pmu_mini_module_exit); + +MODULE_DESCRIPTION("HiSilicon SoC DDRC uncore PMU mini driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Shaokun Zhang zhangshaokun@hisilicon.com"); +MODULE_AUTHOR("Anurup M anurup.m@huawei.com"); diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu_mini.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu_mini.c new file mode 100644 index 000000000000..d26ef9e6189c --- /dev/null +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu_mini.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HiSilicon SoC L3C uncore Hardware event counters support + * + * Copyright (C) 2017 Hisilicon Limited + * Author: Anurup M anurup.m@huawei.com + * Shaokun Zhang zhangshaokun@hisilicon.com + * + * This code is based on the uncore PMUs like arm-cci and arm-ccn. + */ +#include <linux/acpi.h> +#include <linux/bug.h> +#include <linux/cpuhotplug.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/list.h> +#include <linux/smp.h> + +#include "hisi_uncore_pmu.h" + +/* + * ARMv8 HiSilicon L3C event types. + */ +enum armv8_hisi_l3c_event_types { + HISI_HWEVENT_L3C_READ_ALLOCATE = 0x0, + HISI_HWEVENT_L3C_WRITE_ALLOCATE = 0x01, + HISI_HWEVENT_L3C_READ_NOALLOCATE = 0x02, + HISI_HWEVENT_L3C_WRITE_NOALLOCATE = 0x03, + HISI_HWEVENT_L3C_READ_HIT = 0x04, + HISI_HWEVENT_L3C_WRITE_HIT = 0x05, + HISI_HWEVENT_L3C_DSID0 = 0x30, + HISI_HWEVENT_L3C_DSID1 = 0x31, + HISI_HWEVENT_L3C_DSID2 = 0x32, + HISI_HWEVENT_L3C_DSID3 = 0x33, + HISI_HWEVENT_L3C_DSID4 = 0x34, + HISI_HWEVENT_L3C_DSID5 = 0x35, + HISI_HWEVENT_L3C_DSID6 = 0x36, + HISI_HWEVENT_L3C_DSID7 = 0x37, + HISI_HWEVENT_L3C_EVENT_MAX = 0x41, +}; + +/* L3C register definition */ +#define L3C_PERF_CTRL 0x04 +#define L3C_INT_MASK 0x0800 +#define L3C_INT_STATUS 0x0808 +#define L3C_INT_CLEAR 0x080c +#define L3C_EVENT_CTRL 0x1c00 +#define L3C_EVENT_TYPE0 0x140 +#define L3C_CNTR0_LOWER 0x170 + +/* L3C has 8-counters */ +#define L3C_NR_COUNTERS 0x8 + +#define L3C_PERF_CTRL_EN 0x1000000 +#define L3C_EVTYPE_NONE 0xff + +#define L3C_NR_EVENTS 0x59 + +#define L3C_DSID_PART_REG(idx) (0x40 + ((idx) / 4) * 0x4) +#define LLC_AA_CPU_PART(n) (0x00040 + (n) * 0x4) +#define LLC_AA_PART_MODE (0x00090) + +#define L3C_HRTIMER_INTERVAL (10LL * MSEC_PER_SEC) +#define HISI_MAX_PERIOD(nr) (BIT_ULL(nr) - 1) + +static u32 hisi_l3c_pmu_mini_get_counter_offset(int cntr_idx) +{ + return (L3C_CNTR0_LOWER + (cntr_idx * 4)); +} + +static u64 hisi_l3c_pmu_mini_read_counter(struct hisi_pmu *l3c_pmu_mini, + struct hw_perf_event *hwc) +{ + return readl(l3c_pmu_mini->base + hisi_l3c_pmu_mini_get_counter_offset(hwc->idx)); +} + +static void hisi_l3c_pmu_mini_write_counter(struct hisi_pmu *l3c_pmu_mini, + struct hw_perf_event *hwc, u64 val) +{ + writel(val, l3c_pmu_mini->base + hisi_l3c_pmu_mini_get_counter_offset(hwc->idx)); +} + +static bool hisi_l3c_pmu_mini_cal_dsid_delta(struct perf_event *event) +{ + int event_id = event->hw.config_base & 0xff; + return event_id >= HISI_HWEVENT_L3C_DSID0 && event_id <= HISI_HWEVENT_L3C_DSID7; +} + +static void hisi_l3c_pmu_mini_write_evtype(struct hisi_pmu *l3c_pmu_mini, int idx, + u32 type) +{ + u32 reg, reg_idx, shift, val; + + /* + * Select the appropriate event select register(L3C_EVENT_TYPE0/1). + * There are 2 event select registers for the 8 hardware counters. + * Event code is 8-bits and for the former 4 hardware counters, + * L3C_EVENT_TYPE0 is chosen. For the latter 4 hardware counters, + * L3C_EVENT_TYPE1 is chosen. + */ + reg = L3C_EVENT_TYPE0 + (idx / 4) * 4; + reg_idx = idx % 4; + shift = 8 * reg_idx; + + /* Write event code to L3C_EVENT_TYPEx Register */ + val = readl(l3c_pmu_mini->base + reg); + val &= ~(L3C_EVTYPE_NONE << shift); + val |= (type << shift); + writel(val, l3c_pmu_mini->base + reg); + + writel(0x4, l3c_pmu_mini->aa_base + LLC_AA_PART_MODE); + writel(0xf10000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(0)); + writel(0xf30000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(1)); + writel(0xf50000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(2)); + writel(0xf70000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(3)); + writel(0xf90000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(4)); + writel(0xfb0000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(5)); + writel(0xfd0000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(6)); + writel(0xff0000, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(7)); + writel(0xf7f5f3f1, l3c_pmu_mini->base + L3C_DSID_PART_REG(0)); + writel(0xfffdfbf9, l3c_pmu_mini->base + L3C_DSID_PART_REG(1)); +} + +static void hisi_l3c_pmu_mini_clear_evtype(struct hisi_pmu *l3c_pmu_mini, int idx) +{ + u32 reg, reg_idx, shift, val; + + /* + * Clear the event in L3C_EVENT_TYPEx Register + * Each byte in the 32 bit event select register is used to configure + * the event code. Each byte correspond to a counter register to use. + * Use (idx % 4) to select the byte to clear in event select register + * with the vale 0xff. + */ + + reg = L3C_EVENT_TYPE0 + (idx / 4) * 4; + reg_idx = idx % 4; + shift = 8 * reg_idx; + + /* Write event code to L3C_EVENT_TYPEx Register */ + val = readl(l3c_pmu_mini->base + reg); + val &= ~(L3C_EVTYPE_NONE << shift); + val |= (L3C_EVTYPE_NONE << shift); + writel(val, l3c_pmu_mini->base + reg); + + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_PART_MODE); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(0)); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(1)); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(2)); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(3)); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(4)); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(5)); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(6)); + writel(0x0, l3c_pmu_mini->aa_base + LLC_AA_CPU_PART(7)); + writel(0x0, l3c_pmu_mini->base + L3C_DSID_PART_REG(0)); + writel(0x0, l3c_pmu_mini->base + L3C_DSID_PART_REG(1)); +} + +static void hisi_l3c_pmu_mini_start_counters(struct hisi_pmu *l3c_pmu_mini) +{ + u32 val; + + /* + * Set perf_enable bit in L3C_PERF_CTRL register to start counting + * for all enabled counters. + */ + val = readl(l3c_pmu_mini->base + L3C_PERF_CTRL); + val |= L3C_PERF_CTRL_EN; + writel(val, l3c_pmu_mini->base + L3C_PERF_CTRL); +} + +static void hisi_l3c_pmu_mini_stop_counters(struct hisi_pmu *l3c_pmu_mini) +{ + u32 val; + + /* + * Clear perf_enable bit in L3C_PERF_CTRL register to stop counting + * for all enabled counters. + */ + val = readl(l3c_pmu_mini->base + L3C_PERF_CTRL); + val &= ~(L3C_PERF_CTRL_EN); + writel(val, l3c_pmu_mini->base + L3C_PERF_CTRL); +} + +static void hisi_l3c_pmu_mini_enable_counter(struct hisi_pmu *l3c_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Enable counter index in L3C_EVENT_CTRL register */ + val = readl(l3c_pmu_mini->base + L3C_EVENT_CTRL); + val |= (1 << hwc->idx); + writel(val, l3c_pmu_mini->base + L3C_EVENT_CTRL); +} + +static void hisi_l3c_pmu_mini_disable_counter(struct hisi_pmu *l3c_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Clear counter index in L3C_EVENT_CTRL register */ + val = readl(l3c_pmu_mini->base + L3C_EVENT_CTRL); + val &= ~(1 << hwc->idx); + writel(val, l3c_pmu_mini->base + L3C_EVENT_CTRL); +} + +static void hisi_l3c_pmu_mini_enable_counter_int(struct hisi_pmu *l3c_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + val = readl(l3c_pmu_mini->base + L3C_INT_MASK); + /* Write 0 to enable interrupt */ + val &= ~(1 << hwc->idx); + writel(val, l3c_pmu_mini->base + L3C_INT_MASK); +} + +static void hisi_l3c_pmu_mini_disable_counter_int(struct hisi_pmu *l3c_pmu_mini, + struct hw_perf_event *hwc) +{ + u32 val; + + val = readl(l3c_pmu_mini->base + L3C_INT_MASK); + /* Write 1 to mask interrupt */ + val |= (1 << hwc->idx); + writel(val, l3c_pmu_mini->base + L3C_INT_MASK); +} + +static u32 hisi_l3c_pmu_mini_get_int_status(struct hisi_pmu *l3c_pmu_mini) +{ + return readl(l3c_pmu_mini->base + L3C_INT_STATUS); +} + +static void hisi_l3c_pmu_mini_clear_int_status(struct hisi_pmu *l3c_pmu_mini, int idx) +{ + writel(1 << idx, l3c_pmu_mini->base + L3C_INT_CLEAR); +} + +static const struct acpi_device_id hisi_l3c_pmu_mini_acpi_match[] = { + {} +}; +MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_mini_acpi_match); + +static const struct of_device_id l3c_of_match[] = { + { .compatible = "hisilicon,l3c-pmu-mini", }, + {}, +}; +MODULE_DEVICE_TABLE(of, l3c_of_match); + +static int hisi_l3c_pmu_mini_init_data(struct platform_device *pdev, + struct hisi_pmu *l3c_pmu_mini) +{ + /* + * Use the SCCL_ID and CCL_ID to identify the L3C PMU, while + * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1]. + */ + if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", + &l3c_pmu_mini->sccl_id)) { + dev_err(&pdev->dev, "Can not read l3c sccl-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "hisilicon,ccl-id", + &l3c_pmu_mini->ccl_id)) { + dev_err(&pdev->dev, "Can not read l3c ccl-id!\n"); + return -EINVAL; + } + + l3c_pmu_mini->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(l3c_pmu_mini->base)) { + dev_err(&pdev->dev, "ioremap failed for l3c_pmu resource\n"); + return PTR_ERR(l3c_pmu_mini->base); + } + + return 0; +} + +static struct attribute *hisi_l3c_pmu_mini_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-7"), + NULL, +}; + +static const struct attribute_group hisi_l3c_pmu_mini_format_group = { + .name = "format", + .attrs = hisi_l3c_pmu_mini_format_attr, +}; + +static struct attribute *hisi_l3c_pmu_mini_events_attr[] = { + HISI_PMU_EVENT_ATTR(read_allocate, 0x00), + HISI_PMU_EVENT_ATTR(write_allocate, 0x01), + HISI_PMU_EVENT_ATTR(read_noallocate, 0x02), + HISI_PMU_EVENT_ATTR(write_noallocate, 0x03), + HISI_PMU_EVENT_ATTR(read_hit, 0x04), + HISI_PMU_EVENT_ATTR(write_hit, 0x05), + HISI_PMU_EVENT_ATTR(dsid0, 0x30), + HISI_PMU_EVENT_ATTR(dsid1, 0x31), + HISI_PMU_EVENT_ATTR(dsid2, 0x32), + HISI_PMU_EVENT_ATTR(dsid3, 0x33), + HISI_PMU_EVENT_ATTR(dsid4, 0x34), + HISI_PMU_EVENT_ATTR(dsid5, 0x35), + HISI_PMU_EVENT_ATTR(dsid6, 0x36), + HISI_PMU_EVENT_ATTR(dsid7, 0x37), + NULL, +}; + +static const struct attribute_group hisi_l3c_pmu_mini_events_group = { + .name = "events", + .attrs = hisi_l3c_pmu_mini_events_attr, +}; + +static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); + +static struct attribute *hisi_l3c_pmu_mini_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static const struct attribute_group hisi_l3c_pmu_mini_cpumask_attr_group = { + .attrs = hisi_l3c_pmu_mini_cpumask_attrs, +}; + +static const struct attribute_group *hisi_l3c_pmu_mini_attr_groups[] = { + &hisi_l3c_pmu_mini_format_group, + &hisi_l3c_pmu_mini_events_group, + &hisi_l3c_pmu_mini_cpumask_attr_group, + NULL, +}; + +static enum hrtimer_restart hisi_hrtimer_callback_llc(struct hrtimer *hrtimer) +{ + struct hisi_pmu *hisi_pmu = container_of(hrtimer, + struct hisi_pmu, hrtimer); + struct perf_event *event = NULL; + unsigned long flags; + int event_id; + + /* Return if no active events */ + if (!hisi_pmu->num_active) + return HRTIMER_NORESTART; + + local_irq_save(flags); + + /* Update event count for each active event */ + list_for_each_entry(event, &hisi_pmu->active_list, active_entry) { + /* Read hardware counter and update the Perf event counter */ + /* disd counts show the amount of cache, no increase */ + event_id = event->hw.config & 0xff; + if (event_id < HISI_HWEVENT_L3C_DSID0) + hisi_uncore_pmu_event_update(event); + } + + local_irq_restore(flags); + hrtimer_forward_now(hrtimer, ms_to_ktime(hisi_pmu->hrt_duration)); + return HRTIMER_RESTART; +} + +void hisi_hrtimer_init_llc(struct hisi_pmu *hisi_pmu_mini, u64 timer_interval) +{ + /* hr timer clock initalization */ + hrtimer_init(&hisi_pmu_mini->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hisi_pmu_mini->hrtimer.function = &hisi_hrtimer_callback_llc; + hisi_pmu_mini->hrt_duration = timer_interval; +} + +static const struct hisi_uncore_ops hisi_uncore_l3c_ops = { + .write_evtype = hisi_l3c_pmu_mini_write_evtype, + .clear_evtype = hisi_l3c_pmu_mini_clear_evtype, + .get_event_idx = hisi_uncore_pmu_get_event_idx, + .start_counters = hisi_l3c_pmu_mini_start_counters, + .stop_counters = hisi_l3c_pmu_mini_stop_counters, + .enable_counter = hisi_l3c_pmu_mini_enable_counter, + .disable_counter = hisi_l3c_pmu_mini_disable_counter, + .enable_counter_int = hisi_l3c_pmu_mini_enable_counter_int, + .disable_counter_int = hisi_l3c_pmu_mini_disable_counter_int, + .write_counter = hisi_l3c_pmu_mini_write_counter, + .read_counter = hisi_l3c_pmu_mini_read_counter, + .get_int_status = hisi_l3c_pmu_mini_get_int_status, + .clear_int_status = hisi_l3c_pmu_mini_clear_int_status, + .start_hrtimer = hisi_hrtimer_start, + .stop_hrtimer = hisi_hrtimer_stop, + .cal_dsid_delta = hisi_l3c_pmu_mini_cal_dsid_delta, +}; + +/* Initialize hrtimer to poll for avoiding counter overflow */ +static void hisi_l3c_pmu_mini_hrtimer_init(struct hisi_pmu *l3c_pmu_mini) +{ + INIT_LIST_HEAD(&l3c_pmu_mini->active_list); + hisi_hrtimer_init_llc(l3c_pmu_mini, L3C_HRTIMER_INTERVAL); +} + +static int hisi_l3c_pmu_mini_dev_probe(struct platform_device *pdev, + struct hisi_pmu *l3c_pmu_mini) +{ + int ret; + + ret = hisi_l3c_pmu_mini_init_data(pdev, l3c_pmu_mini); + if (ret) + return ret; + + ret = hisi_uncore_pmu_init_irq(l3c_pmu_mini, pdev); + if (ret) + return ret; + + l3c_pmu_mini->counter_bits = 32; + l3c_pmu_mini->check_event = L3C_NR_EVENTS; + l3c_pmu_mini->pmu_events.attr_groups = hisi_l3c_pmu_mini_attr_groups; + l3c_pmu_mini->num_counters = L3C_NR_COUNTERS; + l3c_pmu_mini->ops = &hisi_uncore_l3c_ops; + l3c_pmu_mini->dev = &pdev->dev; + l3c_pmu_mini->on_cpu = -1; + + l3c_pmu_mini->num_active = 0; + l3c_pmu_mini->aa_base = ioremap(0x100120000, 0x10000); + /* + * Use poll method to avoid counter overflow as overflow IRQ + * is not supported in v1,v2 hardware. + */ + hisi_l3c_pmu_mini_hrtimer_init(l3c_pmu_mini); + + return 0; +} + +static int hisi_l3c_pmu_mini_probe(struct platform_device *pdev) +{ + struct hisi_pmu *l3c_pmu_mini; + char *name; + int ret; + + l3c_pmu_mini = devm_kzalloc(&pdev->dev, sizeof(*l3c_pmu_mini), GFP_KERNEL); + if (!l3c_pmu_mini) + return -ENOMEM; + + platform_set_drvdata(pdev, l3c_pmu_mini); + + ret = hisi_l3c_pmu_mini_dev_probe(pdev, l3c_pmu_mini); + if (ret) + return ret; + + ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_L3C_MINI_ONLINE, + &l3c_pmu_mini->node); + if (ret) { + dev_err(&pdev->dev, "Error %d registering hotplug\n", ret); + return ret; + } + + /* + * CCL_ID is used to identify the L3C in the same SCCL which was + * used _UID by mistake. + */ + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_l3c%u_%u", + l3c_pmu_mini->index_id, l3c_pmu_mini->sccl_id); + l3c_pmu_mini->pmu = (struct pmu) { + .name = name, + .module = THIS_MODULE, + .task_ctx_nr = perf_invalid_context, + .event_init = hisi_uncore_pmu_event_init, + .pmu_enable = hisi_uncore_pmu_enable, + .pmu_disable = hisi_uncore_pmu_disable, + .add = hisi_uncore_pmu_add, + .del = hisi_uncore_pmu_del, + .start = hisi_uncore_pmu_start, + .stop = hisi_uncore_pmu_stop, + .read = hisi_uncore_pmu_read, + .attr_groups = l3c_pmu_mini->pmu_events.attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + }; + + ret = perf_pmu_register(&l3c_pmu_mini->pmu, name, -1); + if (ret) { + dev_err(l3c_pmu_mini->dev, "L3C PMU register failed!\n"); + cpuhp_state_remove_instance_nocalls( + CPUHP_AP_PERF_ARM_HISI_L3C_MINI_ONLINE, &l3c_pmu_mini->node); + } + + return ret; +} + +static int hisi_l3c_pmu_mini_remove(struct platform_device *pdev) +{ + struct hisi_pmu *l3c_pmu_mini = platform_get_drvdata(pdev); + + perf_pmu_unregister(&l3c_pmu_mini->pmu); + cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_L3C_MINI_ONLINE, + &l3c_pmu_mini->node); + return 0; +} + +static struct platform_driver hisi_l3c_pmu_mini_driver = { + .driver = { + .name = "hisi_l3c_pmu_mini", + .acpi_match_table = ACPI_PTR(hisi_l3c_pmu_mini_acpi_match), + .of_match_table = of_match_ptr(l3c_of_match), + .suppress_bind_attrs = true, + }, + .probe = hisi_l3c_pmu_mini_probe, + .remove = hisi_l3c_pmu_mini_remove, +}; + +static int __init hisi_l3c_pmu_mini_module_init(void) +{ + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_L3C_MINI_ONLINE, + "AP_PERF_ARM_HISI_L3C_MINI_ONLINE", + hisi_uncore_pmu_online_cpu, + hisi_uncore_pmu_offline_cpu); + if (ret) { + pr_err("L3C PMU: Error setup hotplug, ret = %d\n", ret); + return ret; + } + + ret = platform_driver_register(&hisi_l3c_pmu_mini_driver); + if (ret) + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3C_MINI_ONLINE); + + return ret; +} +module_init(hisi_l3c_pmu_mini_module_init); + +static void __exit hisi_l3c_pmu_mini_module_exit(void) +{ + platform_driver_unregister(&hisi_l3c_pmu_mini_driver); + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3C_MINI_ONLINE); +} +module_exit(hisi_l3c_pmu_mini_module_exit); + +MODULE_DESCRIPTION("HiSilicon SoC L3C uncore PMU mini driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Anurup M anurup.m@huawei.com"); +MODULE_AUTHOR("Shaokun Zhang zhangshaokun@hisilicon.com"); diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c index 07f0c7015181..ab718a039b44 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c @@ -63,6 +63,18 @@ ssize_t hisi_cpumask_sysfs_show(struct device *dev, } EXPORT_SYMBOL_GPL(hisi_cpumask_sysfs_show);
+void hisi_hrtimer_start(struct hisi_pmu *hisi_pmu) +{ + hrtimer_start(&hisi_pmu->hrtimer, + ms_to_ktime(hisi_pmu->hrt_duration), + HRTIMER_MODE_REL_PINNED); +} + +void hisi_hrtimer_stop(struct hisi_pmu *hisi_pmu) +{ + hrtimer_cancel(&hisi_pmu->hrtimer); +} + static bool hisi_validate_event_group(struct perf_event *event) { struct perf_event *sibling, *leader = event->group_leader; @@ -265,12 +277,16 @@ static void hisi_uncore_pmu_disable_event(struct perf_event *event)
if (hisi_pmu->ops->disable_filter) hisi_pmu->ops->disable_filter(event); + + if (hisi_pmu->ops->clear_evtype != NULL) + hisi_pmu->ops->clear_evtype(hisi_pmu, hwc->idx); }
void hisi_uncore_pmu_set_event_period(struct perf_event *event) { struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; + u64 val;
/* * The HiSilicon PMU counters support 32 bits or 48 bits, depending on @@ -279,7 +295,10 @@ void hisi_uncore_pmu_set_event_period(struct perf_event *event) * interrupt before another 2^(counter_bits - 1) events occur and the * counter overtakes its previous value. */ - u64 val = BIT_ULL(hisi_pmu->counter_bits - 1); + if (hisi_pmu->ops->cal_dsid_delta && hisi_pmu->ops->cal_dsid_delta(event)) + val = 0; + else + val = BIT_ULL(hisi_pmu->counter_bits - 1);
local64_set(&hwc->prev_count, val); /* Write start value to the hardware event counter */ @@ -302,8 +321,11 @@ void hisi_uncore_pmu_event_update(struct perf_event *event) /* * compute the delta */ - delta = (new_raw_count - prev_raw_count) & - HISI_MAX_PERIOD(hisi_pmu->counter_bits); + if (hisi_pmu->ops->cal_dsid_delta && hisi_pmu->ops->cal_dsid_delta(event)) + delta = new_raw_count; + else + delta = (new_raw_count - prev_raw_count) & + HISI_MAX_PERIOD(hisi_pmu->counter_bits); local64_add(delta, &event->count); } EXPORT_SYMBOL_GPL(hisi_uncore_pmu_event_update); @@ -326,6 +348,15 @@ void hisi_uncore_pmu_start(struct perf_event *event, int flags) hisi_pmu->ops->write_counter(hisi_pmu, hwc, prev_raw_count); }
+ /* Start hrtimer when the first event is started in this PMU */ + if (hisi_pmu->ops->start_hrtimer != NULL) { + hisi_pmu->num_active++; + list_add_tail(&event->active_entry, &hisi_pmu->active_list); + + if (hisi_pmu->num_active == 1) + hisi_pmu->ops->start_hrtimer(hisi_pmu); + } + hisi_uncore_pmu_enable_event(event); perf_event_update_userpage(event); } @@ -334,11 +365,21 @@ EXPORT_SYMBOL_GPL(hisi_uncore_pmu_start); void hisi_uncore_pmu_stop(struct perf_event *event, int flags) { struct hw_perf_event *hwc = &event->hw; + struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
hisi_uncore_pmu_disable_event(event); WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); hwc->state |= PERF_HES_STOPPED;
+ /* Stop hrtimer when the last event is stopped in this PMU */ + if (hisi_pmu->ops->stop_hrtimer != NULL) { + hisi_pmu->num_active--; + list_del(&event->active_entry); + + if (hisi_pmu->num_active == 0) + hisi_pmu->ops->stop_hrtimer(hisi_pmu); + } + if (hwc->state & PERF_HES_UPTODATE) return;
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h index ea9d89bbc1ea..f9c17ef5b40c 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h @@ -47,6 +47,7 @@ struct hisi_pmu;
struct hisi_uncore_ops { void (*write_evtype)(struct hisi_pmu *, int, u32); + void (*clear_evtype)(struct hisi_pmu *, int); int (*get_event_idx)(struct perf_event *); u64 (*read_counter)(struct hisi_pmu *, struct hw_perf_event *); void (*write_counter)(struct hisi_pmu *, struct hw_perf_event *, u64); @@ -60,6 +61,9 @@ struct hisi_uncore_ops { void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx); void (*enable_filter)(struct perf_event *event); void (*disable_filter)(struct perf_event *event); + void (*start_hrtimer)(struct hisi_pmu *); + void (*stop_hrtimer)(struct hisi_pmu *); + bool (*cal_dsid_delta)(struct perf_event *event); };
struct hisi_pmu_hwevents { @@ -79,16 +83,22 @@ struct hisi_pmu { int on_cpu; int irq; struct device *dev; + struct list_head active_list; /* Active events list */ + /* hrtimer to handle the counter overflow */ + struct hrtimer hrtimer; + u64 hrt_duration; /* hrtimer timeout */ struct hlist_node node; int sccl_id; int ccl_id; void __iomem *base; + void __iomem *aa_base; /* the ID of the PMU modules */ u32 index_id; /* For DDRC PMU v2: each DDRC has more than one DMC */ u32 sub_id; int num_counters; int counter_bits; + int num_active; /* check event code range */ int check_event; u32 identifier; @@ -113,7 +123,8 @@ ssize_t hisi_cpumask_sysfs_show(struct device *dev, struct device_attribute *attr, char *buf); int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node); int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node); - +void hisi_hrtimer_start(struct hisi_pmu *hisi_pmu); +void hisi_hrtimer_stop(struct hisi_pmu *hisi_pmu); ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev, struct device_attribute *attr, char *page); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index b98b9eb7d5f8..6ef2431c4aac 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -174,8 +174,10 @@ enum cpuhp_state { CPUHP_AP_PERF_ARM_CCI_ONLINE, CPUHP_AP_PERF_ARM_CCN_ONLINE, CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, + CPUHP_AP_PERF_ARM_HISI_DDRC_MINI_ONLINE, CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, + CPUHP_AP_PERF_ARM_HISI_L3C_MINI_ONLINE, CPUHP_AP_PERF_ARM_HISI_PA_ONLINE, CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, CPUHP_AP_PERF_ARM_L2X0_ONLINE,