13bf30882SShaokun Zhang // SPDX-License-Identifier: GPL-2.0-only
23bf30882SShaokun Zhang /*
33bf30882SShaokun Zhang * HiSilicon SLLC uncore Hardware event counters support
43bf30882SShaokun Zhang *
52db52237SHao Fang * Copyright (C) 2020 HiSilicon Limited
63bf30882SShaokun Zhang * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
73bf30882SShaokun Zhang *
83bf30882SShaokun Zhang * This code is based on the uncore PMUs like arm-cci and arm-ccn.
93bf30882SShaokun Zhang */
103bf30882SShaokun Zhang #include <linux/acpi.h>
113bf30882SShaokun Zhang #include <linux/cpuhotplug.h>
123bf30882SShaokun Zhang #include <linux/interrupt.h>
133bf30882SShaokun Zhang #include <linux/irq.h>
143bf30882SShaokun Zhang #include <linux/list.h>
153bf30882SShaokun Zhang #include <linux/smp.h>
163bf30882SShaokun Zhang
173bf30882SShaokun Zhang #include "hisi_uncore_pmu.h"
183bf30882SShaokun Zhang
193bf30882SShaokun Zhang /* SLLC register definition */
203bf30882SShaokun Zhang #define SLLC_INT_MASK 0x0814
213bf30882SShaokun Zhang #define SLLC_INT_STATUS 0x0818
223bf30882SShaokun Zhang #define SLLC_INT_CLEAR 0x081c
233bf30882SShaokun Zhang #define SLLC_PERF_CTRL 0x1c00
243bf30882SShaokun Zhang #define SLLC_SRCID_CTRL 0x1c04
253bf30882SShaokun Zhang #define SLLC_TGTID_CTRL 0x1c08
263bf30882SShaokun Zhang #define SLLC_EVENT_CTRL 0x1c14
273bf30882SShaokun Zhang #define SLLC_EVENT_TYPE0 0x1c18
283bf30882SShaokun Zhang #define SLLC_VERSION 0x1cf0
293bf30882SShaokun Zhang #define SLLC_EVENT_CNT0_L 0x1d00
303bf30882SShaokun Zhang
311fd20ba0SJunhao He /* SLLC registers definition in v3 */
321fd20ba0SJunhao He #define SLLC_V3_INT_MASK 0x6834
331fd20ba0SJunhao He #define SLLC_V3_INT_STATUS 0x6838
341fd20ba0SJunhao He #define SLLC_V3_INT_CLEAR 0x683c
351fd20ba0SJunhao He #define SLLC_V3_VERSION 0x6c00
361fd20ba0SJunhao He #define SLLC_V3_PERF_CTRL 0x6d00
371fd20ba0SJunhao He #define SLLC_V3_SRCID_CTRL 0x6d04
381fd20ba0SJunhao He #define SLLC_V3_TGTID_CTRL 0x6d08
391fd20ba0SJunhao He #define SLLC_V3_EVENT_CTRL 0x6d14
401fd20ba0SJunhao He #define SLLC_V3_EVENT_TYPE0 0x6d18
411fd20ba0SJunhao He #define SLLC_V3_EVENT_CNT0_L 0x6e00
421fd20ba0SJunhao He
433bf30882SShaokun Zhang #define SLLC_EVTYPE_MASK 0xff
443bf30882SShaokun Zhang #define SLLC_PERF_CTRL_EN BIT(0)
453bf30882SShaokun Zhang #define SLLC_FILT_EN BIT(1)
463bf30882SShaokun Zhang #define SLLC_TRACETAG_EN BIT(2)
473bf30882SShaokun Zhang #define SLLC_SRCID_EN BIT(4)
483bf30882SShaokun Zhang #define SLLC_SRCID_NONE 0x0
493bf30882SShaokun Zhang #define SLLC_TGTID_EN BIT(5)
503bf30882SShaokun Zhang #define SLLC_TGTID_NONE 0x0
513bf30882SShaokun Zhang #define SLLC_TGTID_MIN_SHIFT 1
523bf30882SShaokun Zhang #define SLLC_TGTID_MAX_SHIFT 12
533bf30882SShaokun Zhang #define SLLC_SRCID_CMD_SHIFT 1
543bf30882SShaokun Zhang #define SLLC_SRCID_MSK_SHIFT 12
551fd20ba0SJunhao He
561fd20ba0SJunhao He #define SLLC_V3_TGTID_MIN_SHIFT 1
571fd20ba0SJunhao He #define SLLC_V3_TGTID_MAX_SHIFT 10
581fd20ba0SJunhao He #define SLLC_V3_SRCID_CMD_SHIFT 1
591fd20ba0SJunhao He #define SLLC_V3_SRCID_MSK_SHIFT 10
601fd20ba0SJunhao He
61*35f5b36eSJunhao He #define SLLC_NR_EVENTS 0xff
6229614c55SJunhao He #define SLLC_EVENT_CNTn(cnt0, n) ((cnt0) + (n) * 8)
633bf30882SShaokun Zhang
643bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_min, config1, 10, 0);
653bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_max, config1, 21, 11);
663bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
673bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
683bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
693bf30882SShaokun Zhang
7029614c55SJunhao He struct hisi_sllc_pmu_regs {
7129614c55SJunhao He u32 int_mask;
7229614c55SJunhao He u32 int_clear;
7329614c55SJunhao He u32 int_status;
7429614c55SJunhao He u32 perf_ctrl;
7529614c55SJunhao He u32 srcid_ctrl;
7629614c55SJunhao He u32 srcid_cmd_shift;
7729614c55SJunhao He u32 srcid_mask_shift;
7829614c55SJunhao He u32 tgtid_ctrl;
7929614c55SJunhao He u32 tgtid_min_shift;
8029614c55SJunhao He u32 tgtid_max_shift;
8129614c55SJunhao He u32 event_ctrl;
8229614c55SJunhao He u32 event_type0;
8329614c55SJunhao He u32 version;
8429614c55SJunhao He u32 event_cnt0;
8529614c55SJunhao He };
8629614c55SJunhao He
tgtid_is_valid(u32 max,u32 min)873bf30882SShaokun Zhang static bool tgtid_is_valid(u32 max, u32 min)
883bf30882SShaokun Zhang {
893bf30882SShaokun Zhang return max > 0 && max >= min;
903bf30882SShaokun Zhang }
913bf30882SShaokun Zhang
hisi_sllc_pmu_enable_tracetag(struct perf_event * event)923bf30882SShaokun Zhang static void hisi_sllc_pmu_enable_tracetag(struct perf_event *event)
933bf30882SShaokun Zhang {
943bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
9529614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
963bf30882SShaokun Zhang u32 tt_en = hisi_get_tracetag_en(event);
973bf30882SShaokun Zhang
983bf30882SShaokun Zhang if (tt_en) {
993bf30882SShaokun Zhang u32 val;
1003bf30882SShaokun Zhang
10129614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
1023bf30882SShaokun Zhang val |= SLLC_TRACETAG_EN | SLLC_FILT_EN;
10329614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
1043bf30882SShaokun Zhang }
1053bf30882SShaokun Zhang }
1063bf30882SShaokun Zhang
hisi_sllc_pmu_disable_tracetag(struct perf_event * event)1073bf30882SShaokun Zhang static void hisi_sllc_pmu_disable_tracetag(struct perf_event *event)
1083bf30882SShaokun Zhang {
1093bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
11029614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
1113bf30882SShaokun Zhang u32 tt_en = hisi_get_tracetag_en(event);
1123bf30882SShaokun Zhang
1133bf30882SShaokun Zhang if (tt_en) {
1143bf30882SShaokun Zhang u32 val;
1153bf30882SShaokun Zhang
11629614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
1173bf30882SShaokun Zhang val &= ~(SLLC_TRACETAG_EN | SLLC_FILT_EN);
11829614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
1193bf30882SShaokun Zhang }
1203bf30882SShaokun Zhang }
1213bf30882SShaokun Zhang
hisi_sllc_pmu_config_tgtid(struct perf_event * event)1223bf30882SShaokun Zhang static void hisi_sllc_pmu_config_tgtid(struct perf_event *event)
1233bf30882SShaokun Zhang {
1243bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
12529614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
1263bf30882SShaokun Zhang u32 min = hisi_get_tgtid_min(event);
1273bf30882SShaokun Zhang u32 max = hisi_get_tgtid_max(event);
1283bf30882SShaokun Zhang
1293bf30882SShaokun Zhang if (tgtid_is_valid(max, min)) {
13029614c55SJunhao He u32 val = (max << regs->tgtid_max_shift) |
13129614c55SJunhao He (min << regs->tgtid_min_shift);
1323bf30882SShaokun Zhang
13329614c55SJunhao He writel(val, sllc_pmu->base + regs->tgtid_ctrl);
1343bf30882SShaokun Zhang /* Enable the tgtid */
13529614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
1363bf30882SShaokun Zhang val |= SLLC_TGTID_EN | SLLC_FILT_EN;
13729614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
1383bf30882SShaokun Zhang }
1393bf30882SShaokun Zhang }
1403bf30882SShaokun Zhang
hisi_sllc_pmu_clear_tgtid(struct perf_event * event)1413bf30882SShaokun Zhang static void hisi_sllc_pmu_clear_tgtid(struct perf_event *event)
1423bf30882SShaokun Zhang {
1433bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
14429614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
1453bf30882SShaokun Zhang u32 min = hisi_get_tgtid_min(event);
1463bf30882SShaokun Zhang u32 max = hisi_get_tgtid_max(event);
1473bf30882SShaokun Zhang
1483bf30882SShaokun Zhang if (tgtid_is_valid(max, min)) {
1493bf30882SShaokun Zhang u32 val;
1503bf30882SShaokun Zhang
15129614c55SJunhao He writel(SLLC_TGTID_NONE, sllc_pmu->base + regs->tgtid_ctrl);
1523bf30882SShaokun Zhang /* Disable the tgtid */
15329614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
1543bf30882SShaokun Zhang val &= ~(SLLC_TGTID_EN | SLLC_FILT_EN);
15529614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
1563bf30882SShaokun Zhang }
1573bf30882SShaokun Zhang }
1583bf30882SShaokun Zhang
hisi_sllc_pmu_config_srcid(struct perf_event * event)1593bf30882SShaokun Zhang static void hisi_sllc_pmu_config_srcid(struct perf_event *event)
1603bf30882SShaokun Zhang {
1613bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
16229614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
1633bf30882SShaokun Zhang u32 cmd = hisi_get_srcid_cmd(event);
1643bf30882SShaokun Zhang
1653bf30882SShaokun Zhang if (cmd) {
1663bf30882SShaokun Zhang u32 val, msk;
1673bf30882SShaokun Zhang
1683bf30882SShaokun Zhang msk = hisi_get_srcid_msk(event);
16929614c55SJunhao He val = (cmd << regs->srcid_cmd_shift) |
17029614c55SJunhao He (msk << regs->srcid_mask_shift);
17129614c55SJunhao He writel(val, sllc_pmu->base + regs->srcid_ctrl);
1723bf30882SShaokun Zhang /* Enable the srcid */
17329614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
1743bf30882SShaokun Zhang val |= SLLC_SRCID_EN | SLLC_FILT_EN;
17529614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
1763bf30882SShaokun Zhang }
1773bf30882SShaokun Zhang }
1783bf30882SShaokun Zhang
hisi_sllc_pmu_clear_srcid(struct perf_event * event)1793bf30882SShaokun Zhang static void hisi_sllc_pmu_clear_srcid(struct perf_event *event)
1803bf30882SShaokun Zhang {
1813bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
18229614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
1833bf30882SShaokun Zhang u32 cmd = hisi_get_srcid_cmd(event);
1843bf30882SShaokun Zhang
1853bf30882SShaokun Zhang if (cmd) {
1863bf30882SShaokun Zhang u32 val;
1873bf30882SShaokun Zhang
18829614c55SJunhao He writel(SLLC_SRCID_NONE, sllc_pmu->base + regs->srcid_ctrl);
1893bf30882SShaokun Zhang /* Disable the srcid */
19029614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
1913bf30882SShaokun Zhang val &= ~(SLLC_SRCID_EN | SLLC_FILT_EN);
19229614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
1933bf30882SShaokun Zhang }
1943bf30882SShaokun Zhang }
1953bf30882SShaokun Zhang
hisi_sllc_pmu_enable_filter(struct perf_event * event)1963bf30882SShaokun Zhang static void hisi_sllc_pmu_enable_filter(struct perf_event *event)
1973bf30882SShaokun Zhang {
1983bf30882SShaokun Zhang if (event->attr.config1 != 0x0) {
1993bf30882SShaokun Zhang hisi_sllc_pmu_enable_tracetag(event);
2003bf30882SShaokun Zhang hisi_sllc_pmu_config_srcid(event);
2013bf30882SShaokun Zhang hisi_sllc_pmu_config_tgtid(event);
2023bf30882SShaokun Zhang }
2033bf30882SShaokun Zhang }
2043bf30882SShaokun Zhang
hisi_sllc_pmu_clear_filter(struct perf_event * event)2053bf30882SShaokun Zhang static void hisi_sllc_pmu_clear_filter(struct perf_event *event)
2063bf30882SShaokun Zhang {
2073bf30882SShaokun Zhang if (event->attr.config1 != 0x0) {
2083bf30882SShaokun Zhang hisi_sllc_pmu_disable_tracetag(event);
2093bf30882SShaokun Zhang hisi_sllc_pmu_clear_srcid(event);
2103bf30882SShaokun Zhang hisi_sllc_pmu_clear_tgtid(event);
2113bf30882SShaokun Zhang }
2123bf30882SShaokun Zhang }
2133bf30882SShaokun Zhang
hisi_sllc_pmu_read_counter(struct hisi_pmu * sllc_pmu,struct hw_perf_event * hwc)2143bf30882SShaokun Zhang static u64 hisi_sllc_pmu_read_counter(struct hisi_pmu *sllc_pmu,
2153bf30882SShaokun Zhang struct hw_perf_event *hwc)
2163bf30882SShaokun Zhang {
21729614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
21829614c55SJunhao He
21929614c55SJunhao He return readq(sllc_pmu->base + SLLC_EVENT_CNTn(regs->event_cnt0, hwc->idx));
2203bf30882SShaokun Zhang }
2213bf30882SShaokun Zhang
hisi_sllc_pmu_write_counter(struct hisi_pmu * sllc_pmu,struct hw_perf_event * hwc,u64 val)2223bf30882SShaokun Zhang static void hisi_sllc_pmu_write_counter(struct hisi_pmu *sllc_pmu,
2233bf30882SShaokun Zhang struct hw_perf_event *hwc, u64 val)
2243bf30882SShaokun Zhang {
22529614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
22629614c55SJunhao He
22729614c55SJunhao He writeq(val, sllc_pmu->base + SLLC_EVENT_CNTn(regs->event_cnt0, hwc->idx));
2283bf30882SShaokun Zhang }
2293bf30882SShaokun Zhang
hisi_sllc_pmu_write_evtype(struct hisi_pmu * sllc_pmu,int idx,u32 type)2303bf30882SShaokun Zhang static void hisi_sllc_pmu_write_evtype(struct hisi_pmu *sllc_pmu, int idx,
2313bf30882SShaokun Zhang u32 type)
2323bf30882SShaokun Zhang {
23329614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
23429614c55SJunhao He u32 reg, val;
2353bf30882SShaokun Zhang
2363bf30882SShaokun Zhang /*
2373bf30882SShaokun Zhang * Select the appropriate event select register(SLLC_EVENT_TYPE0/1).
2383bf30882SShaokun Zhang * There are 2 event select registers for the 8 hardware counters.
2393bf30882SShaokun Zhang * Event code is 8-bits and for the former 4 hardware counters,
2403bf30882SShaokun Zhang * SLLC_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
2413bf30882SShaokun Zhang * SLLC_EVENT_TYPE1 is chosen.
2423bf30882SShaokun Zhang */
24329614c55SJunhao He reg = regs->event_type0 + (idx / 4) * 4;
2443bf30882SShaokun Zhang
2453bf30882SShaokun Zhang /* Write event code to SLLC_EVENT_TYPEx Register */
2463bf30882SShaokun Zhang val = readl(sllc_pmu->base + reg);
24729614c55SJunhao He val &= ~(SLLC_EVTYPE_MASK << HISI_PMU_EVTYPE_SHIFT(idx));
24829614c55SJunhao He val |= (type << HISI_PMU_EVTYPE_SHIFT(idx));
2493bf30882SShaokun Zhang writel(val, sllc_pmu->base + reg);
2503bf30882SShaokun Zhang }
2513bf30882SShaokun Zhang
hisi_sllc_pmu_start_counters(struct hisi_pmu * sllc_pmu)2523bf30882SShaokun Zhang static void hisi_sllc_pmu_start_counters(struct hisi_pmu *sllc_pmu)
2533bf30882SShaokun Zhang {
25429614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
2553bf30882SShaokun Zhang u32 val;
2563bf30882SShaokun Zhang
25729614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
2583bf30882SShaokun Zhang val |= SLLC_PERF_CTRL_EN;
25929614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
2603bf30882SShaokun Zhang }
2613bf30882SShaokun Zhang
hisi_sllc_pmu_stop_counters(struct hisi_pmu * sllc_pmu)2623bf30882SShaokun Zhang static void hisi_sllc_pmu_stop_counters(struct hisi_pmu *sllc_pmu)
2633bf30882SShaokun Zhang {
26429614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
2653bf30882SShaokun Zhang u32 val;
2663bf30882SShaokun Zhang
26729614c55SJunhao He val = readl(sllc_pmu->base + regs->perf_ctrl);
2683bf30882SShaokun Zhang val &= ~(SLLC_PERF_CTRL_EN);
26929614c55SJunhao He writel(val, sllc_pmu->base + regs->perf_ctrl);
2703bf30882SShaokun Zhang }
2713bf30882SShaokun Zhang
hisi_sllc_pmu_enable_counter(struct hisi_pmu * sllc_pmu,struct hw_perf_event * hwc)2723bf30882SShaokun Zhang static void hisi_sllc_pmu_enable_counter(struct hisi_pmu *sllc_pmu,
2733bf30882SShaokun Zhang struct hw_perf_event *hwc)
2743bf30882SShaokun Zhang {
27529614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
2763bf30882SShaokun Zhang u32 val;
2773bf30882SShaokun Zhang
27829614c55SJunhao He val = readl(sllc_pmu->base + regs->event_ctrl);
27929614c55SJunhao He val |= BIT_ULL(hwc->idx);
28029614c55SJunhao He writel(val, sllc_pmu->base + regs->event_ctrl);
2813bf30882SShaokun Zhang }
2823bf30882SShaokun Zhang
hisi_sllc_pmu_disable_counter(struct hisi_pmu * sllc_pmu,struct hw_perf_event * hwc)2833bf30882SShaokun Zhang static void hisi_sllc_pmu_disable_counter(struct hisi_pmu *sllc_pmu,
2843bf30882SShaokun Zhang struct hw_perf_event *hwc)
2853bf30882SShaokun Zhang {
28629614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
2873bf30882SShaokun Zhang u32 val;
2883bf30882SShaokun Zhang
28929614c55SJunhao He val = readl(sllc_pmu->base + regs->event_ctrl);
29029614c55SJunhao He val &= ~BIT_ULL(hwc->idx);
29129614c55SJunhao He writel(val, sllc_pmu->base + regs->event_ctrl);
2923bf30882SShaokun Zhang }
2933bf30882SShaokun Zhang
hisi_sllc_pmu_enable_counter_int(struct hisi_pmu * sllc_pmu,struct hw_perf_event * hwc)2943bf30882SShaokun Zhang static void hisi_sllc_pmu_enable_counter_int(struct hisi_pmu *sllc_pmu,
2953bf30882SShaokun Zhang struct hw_perf_event *hwc)
2963bf30882SShaokun Zhang {
29729614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
2983bf30882SShaokun Zhang u32 val;
2993bf30882SShaokun Zhang
30029614c55SJunhao He val = readl(sllc_pmu->base + regs->int_mask);
30129614c55SJunhao He val &= ~BIT_ULL(hwc->idx);
30229614c55SJunhao He writel(val, sllc_pmu->base + regs->int_mask);
3033bf30882SShaokun Zhang }
3043bf30882SShaokun Zhang
hisi_sllc_pmu_disable_counter_int(struct hisi_pmu * sllc_pmu,struct hw_perf_event * hwc)3053bf30882SShaokun Zhang static void hisi_sllc_pmu_disable_counter_int(struct hisi_pmu *sllc_pmu,
3063bf30882SShaokun Zhang struct hw_perf_event *hwc)
3073bf30882SShaokun Zhang {
30829614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
3093bf30882SShaokun Zhang u32 val;
3103bf30882SShaokun Zhang
31129614c55SJunhao He val = readl(sllc_pmu->base + regs->int_mask);
31229614c55SJunhao He val |= BIT_ULL(hwc->idx);
31329614c55SJunhao He writel(val, sllc_pmu->base + regs->int_mask);
3143bf30882SShaokun Zhang }
3153bf30882SShaokun Zhang
hisi_sllc_pmu_get_int_status(struct hisi_pmu * sllc_pmu)3163bf30882SShaokun Zhang static u32 hisi_sllc_pmu_get_int_status(struct hisi_pmu *sllc_pmu)
3173bf30882SShaokun Zhang {
31829614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
31929614c55SJunhao He
32029614c55SJunhao He return readl(sllc_pmu->base + regs->int_status);
3213bf30882SShaokun Zhang }
3223bf30882SShaokun Zhang
hisi_sllc_pmu_clear_int_status(struct hisi_pmu * sllc_pmu,int idx)3233bf30882SShaokun Zhang static void hisi_sllc_pmu_clear_int_status(struct hisi_pmu *sllc_pmu, int idx)
3243bf30882SShaokun Zhang {
32529614c55SJunhao He struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private;
3263bf30882SShaokun Zhang
32729614c55SJunhao He writel(BIT_ULL(idx), sllc_pmu->base + regs->int_clear);
32829614c55SJunhao He }
3293bf30882SShaokun Zhang
hisi_sllc_pmu_init_data(struct platform_device * pdev,struct hisi_pmu * sllc_pmu)3303bf30882SShaokun Zhang static int hisi_sllc_pmu_init_data(struct platform_device *pdev,
3313bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu)
3323bf30882SShaokun Zhang {
33329614c55SJunhao He struct hisi_sllc_pmu_regs *regs;
33429614c55SJunhao He
33532528b16SYicong Yang hisi_uncore_pmu_init_topology(sllc_pmu, &pdev->dev);
33632528b16SYicong Yang
3373bf30882SShaokun Zhang /*
3383bf30882SShaokun Zhang * Use the SCCL_ID and the index ID to identify the SLLC PMU,
3393bf30882SShaokun Zhang * while SCCL_ID is from MPIDR_EL1 by CPU.
3403bf30882SShaokun Zhang */
34132528b16SYicong Yang if (sllc_pmu->topo.sccl_id < 0) {
3423bf30882SShaokun Zhang dev_err(&pdev->dev, "Cannot read sccl-id!\n");
3433bf30882SShaokun Zhang return -EINVAL;
3443bf30882SShaokun Zhang }
3453bf30882SShaokun Zhang
34632528b16SYicong Yang if (sllc_pmu->topo.index_id < 0) {
3473bf30882SShaokun Zhang dev_err(&pdev->dev, "Cannot read idx-id!\n");
3483bf30882SShaokun Zhang return -EINVAL;
3493bf30882SShaokun Zhang }
3503bf30882SShaokun Zhang
35129614c55SJunhao He sllc_pmu->dev_info = device_get_match_data(&pdev->dev);
35229614c55SJunhao He if (!sllc_pmu->dev_info)
35329614c55SJunhao He return -ENODEV;
35429614c55SJunhao He
3553bf30882SShaokun Zhang sllc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
3563bf30882SShaokun Zhang if (IS_ERR(sllc_pmu->base)) {
3573bf30882SShaokun Zhang dev_err(&pdev->dev, "ioremap failed for sllc_pmu resource.\n");
3583bf30882SShaokun Zhang return PTR_ERR(sllc_pmu->base);
3593bf30882SShaokun Zhang }
3603bf30882SShaokun Zhang
36129614c55SJunhao He regs = sllc_pmu->dev_info->private;
36229614c55SJunhao He sllc_pmu->identifier = readl(sllc_pmu->base + regs->version);
3633bf30882SShaokun Zhang
3643bf30882SShaokun Zhang return 0;
3653bf30882SShaokun Zhang }
3663bf30882SShaokun Zhang
3673bf30882SShaokun Zhang static struct attribute *hisi_sllc_pmu_v2_format_attr[] = {
3683bf30882SShaokun Zhang HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
3693bf30882SShaokun Zhang HISI_PMU_FORMAT_ATTR(tgtid_min, "config1:0-10"),
3703bf30882SShaokun Zhang HISI_PMU_FORMAT_ATTR(tgtid_max, "config1:11-21"),
3713bf30882SShaokun Zhang HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"),
3723bf30882SShaokun Zhang HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:33-43"),
3733bf30882SShaokun Zhang HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"),
3743bf30882SShaokun Zhang NULL
3753bf30882SShaokun Zhang };
3763bf30882SShaokun Zhang
3773bf30882SShaokun Zhang static const struct attribute_group hisi_sllc_pmu_v2_format_group = {
3783bf30882SShaokun Zhang .name = "format",
3793bf30882SShaokun Zhang .attrs = hisi_sllc_pmu_v2_format_attr,
3803bf30882SShaokun Zhang };
3813bf30882SShaokun Zhang
3823bf30882SShaokun Zhang static struct attribute *hisi_sllc_pmu_v2_events_attr[] = {
3833bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR(rx_req, 0x30),
3843bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR(rx_data, 0x31),
3853bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR(tx_req, 0x34),
3863bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR(tx_data, 0x35),
3873bf30882SShaokun Zhang HISI_PMU_EVENT_ATTR(cycles, 0x09),
3883bf30882SShaokun Zhang NULL
3893bf30882SShaokun Zhang };
3903bf30882SShaokun Zhang
3913bf30882SShaokun Zhang static const struct attribute_group hisi_sllc_pmu_v2_events_group = {
3923bf30882SShaokun Zhang .name = "events",
3933bf30882SShaokun Zhang .attrs = hisi_sllc_pmu_v2_events_attr,
3943bf30882SShaokun Zhang };
3953bf30882SShaokun Zhang
3963bf30882SShaokun Zhang static const struct attribute_group *hisi_sllc_pmu_v2_attr_groups[] = {
3973bf30882SShaokun Zhang &hisi_sllc_pmu_v2_format_group,
3983bf30882SShaokun Zhang &hisi_sllc_pmu_v2_events_group,
3998688c01eSYicong Yang &hisi_pmu_cpumask_attr_group,
4008688c01eSYicong Yang &hisi_pmu_identifier_group,
4013bf30882SShaokun Zhang NULL
4023bf30882SShaokun Zhang };
4033bf30882SShaokun Zhang
40429614c55SJunhao He static struct hisi_sllc_pmu_regs hisi_sllc_v2_pmu_regs = {
40529614c55SJunhao He .int_mask = SLLC_INT_MASK,
40629614c55SJunhao He .int_clear = SLLC_INT_CLEAR,
40729614c55SJunhao He .int_status = SLLC_INT_STATUS,
40829614c55SJunhao He .perf_ctrl = SLLC_PERF_CTRL,
40929614c55SJunhao He .srcid_ctrl = SLLC_SRCID_CTRL,
41029614c55SJunhao He .srcid_cmd_shift = SLLC_SRCID_CMD_SHIFT,
41129614c55SJunhao He .srcid_mask_shift = SLLC_SRCID_MSK_SHIFT,
41229614c55SJunhao He .tgtid_ctrl = SLLC_TGTID_CTRL,
41329614c55SJunhao He .tgtid_min_shift = SLLC_TGTID_MIN_SHIFT,
41429614c55SJunhao He .tgtid_max_shift = SLLC_TGTID_MAX_SHIFT,
41529614c55SJunhao He .event_ctrl = SLLC_EVENT_CTRL,
41629614c55SJunhao He .event_type0 = SLLC_EVENT_TYPE0,
41729614c55SJunhao He .version = SLLC_VERSION,
41829614c55SJunhao He .event_cnt0 = SLLC_EVENT_CNT0_L,
41929614c55SJunhao He };
42029614c55SJunhao He
42129614c55SJunhao He static const struct hisi_pmu_dev_info hisi_sllc_v2 = {
42229614c55SJunhao He .private = &hisi_sllc_v2_pmu_regs,
42329614c55SJunhao He };
42429614c55SJunhao He
4251fd20ba0SJunhao He static struct hisi_sllc_pmu_regs hisi_sllc_v3_pmu_regs = {
4261fd20ba0SJunhao He .int_mask = SLLC_V3_INT_MASK,
4271fd20ba0SJunhao He .int_clear = SLLC_V3_INT_CLEAR,
4281fd20ba0SJunhao He .int_status = SLLC_V3_INT_STATUS,
4291fd20ba0SJunhao He .perf_ctrl = SLLC_V3_PERF_CTRL,
4301fd20ba0SJunhao He .srcid_ctrl = SLLC_V3_SRCID_CTRL,
4311fd20ba0SJunhao He .srcid_cmd_shift = SLLC_V3_SRCID_CMD_SHIFT,
4321fd20ba0SJunhao He .srcid_mask_shift = SLLC_V3_SRCID_MSK_SHIFT,
4331fd20ba0SJunhao He .tgtid_ctrl = SLLC_V3_TGTID_CTRL,
4341fd20ba0SJunhao He .tgtid_min_shift = SLLC_V3_TGTID_MIN_SHIFT,
4351fd20ba0SJunhao He .tgtid_max_shift = SLLC_V3_TGTID_MAX_SHIFT,
4361fd20ba0SJunhao He .event_ctrl = SLLC_V3_EVENT_CTRL,
4371fd20ba0SJunhao He .event_type0 = SLLC_V3_EVENT_TYPE0,
4381fd20ba0SJunhao He .version = SLLC_V3_VERSION,
4391fd20ba0SJunhao He .event_cnt0 = SLLC_V3_EVENT_CNT0_L,
4401fd20ba0SJunhao He };
4411fd20ba0SJunhao He
4421fd20ba0SJunhao He static const struct hisi_pmu_dev_info hisi_sllc_v3 = {
4431fd20ba0SJunhao He .private = &hisi_sllc_v3_pmu_regs,
4441fd20ba0SJunhao He };
4451fd20ba0SJunhao He
4463bf30882SShaokun Zhang static const struct hisi_uncore_ops hisi_uncore_sllc_ops = {
4473bf30882SShaokun Zhang .write_evtype = hisi_sllc_pmu_write_evtype,
4483bf30882SShaokun Zhang .get_event_idx = hisi_uncore_pmu_get_event_idx,
4493bf30882SShaokun Zhang .start_counters = hisi_sllc_pmu_start_counters,
4503bf30882SShaokun Zhang .stop_counters = hisi_sllc_pmu_stop_counters,
4513bf30882SShaokun Zhang .enable_counter = hisi_sllc_pmu_enable_counter,
4523bf30882SShaokun Zhang .disable_counter = hisi_sllc_pmu_disable_counter,
4533bf30882SShaokun Zhang .enable_counter_int = hisi_sllc_pmu_enable_counter_int,
4543bf30882SShaokun Zhang .disable_counter_int = hisi_sllc_pmu_disable_counter_int,
4553bf30882SShaokun Zhang .write_counter = hisi_sllc_pmu_write_counter,
4563bf30882SShaokun Zhang .read_counter = hisi_sllc_pmu_read_counter,
4573bf30882SShaokun Zhang .get_int_status = hisi_sllc_pmu_get_int_status,
4583bf30882SShaokun Zhang .clear_int_status = hisi_sllc_pmu_clear_int_status,
4593bf30882SShaokun Zhang .enable_filter = hisi_sllc_pmu_enable_filter,
4603bf30882SShaokun Zhang .disable_filter = hisi_sllc_pmu_clear_filter,
4613bf30882SShaokun Zhang };
4623bf30882SShaokun Zhang
hisi_sllc_pmu_dev_probe(struct platform_device * pdev,struct hisi_pmu * sllc_pmu)4633bf30882SShaokun Zhang static int hisi_sllc_pmu_dev_probe(struct platform_device *pdev,
4643bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu)
4653bf30882SShaokun Zhang {
4663bf30882SShaokun Zhang int ret;
4673bf30882SShaokun Zhang
4683bf30882SShaokun Zhang ret = hisi_sllc_pmu_init_data(pdev, sllc_pmu);
4693bf30882SShaokun Zhang if (ret)
4703bf30882SShaokun Zhang return ret;
4713bf30882SShaokun Zhang
4723bf30882SShaokun Zhang ret = hisi_uncore_pmu_init_irq(sllc_pmu, pdev);
4733bf30882SShaokun Zhang if (ret)
4743bf30882SShaokun Zhang return ret;
4753bf30882SShaokun Zhang
4763bf30882SShaokun Zhang sllc_pmu->pmu_events.attr_groups = hisi_sllc_pmu_v2_attr_groups;
4773bf30882SShaokun Zhang sllc_pmu->ops = &hisi_uncore_sllc_ops;
4783bf30882SShaokun Zhang sllc_pmu->check_event = SLLC_NR_EVENTS;
4793bf30882SShaokun Zhang sllc_pmu->counter_bits = 64;
4803bf30882SShaokun Zhang sllc_pmu->num_counters = 8;
4813bf30882SShaokun Zhang sllc_pmu->dev = &pdev->dev;
4823bf30882SShaokun Zhang sllc_pmu->on_cpu = -1;
4833bf30882SShaokun Zhang
4843bf30882SShaokun Zhang return 0;
4853bf30882SShaokun Zhang }
4863bf30882SShaokun Zhang
hisi_sllc_pmu_probe(struct platform_device * pdev)4873bf30882SShaokun Zhang static int hisi_sllc_pmu_probe(struct platform_device *pdev)
4883bf30882SShaokun Zhang {
4893bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu;
4903bf30882SShaokun Zhang char *name;
4913bf30882SShaokun Zhang int ret;
4923bf30882SShaokun Zhang
4933bf30882SShaokun Zhang sllc_pmu = devm_kzalloc(&pdev->dev, sizeof(*sllc_pmu), GFP_KERNEL);
4943bf30882SShaokun Zhang if (!sllc_pmu)
4953bf30882SShaokun Zhang return -ENOMEM;
4963bf30882SShaokun Zhang
4973bf30882SShaokun Zhang ret = hisi_sllc_pmu_dev_probe(pdev, sllc_pmu);
4983bf30882SShaokun Zhang if (ret)
4993bf30882SShaokun Zhang return ret;
5003bf30882SShaokun Zhang
501c192026cSYicong Yang name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_sllc%d",
502c192026cSYicong Yang sllc_pmu->topo.sccl_id, sllc_pmu->topo.index_id);
5033bf30882SShaokun Zhang if (!name)
5043bf30882SShaokun Zhang return -ENOMEM;
5053bf30882SShaokun Zhang
5063bf30882SShaokun Zhang ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
5073bf30882SShaokun Zhang &sllc_pmu->node);
5083bf30882SShaokun Zhang if (ret) {
5093bf30882SShaokun Zhang dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
5103bf30882SShaokun Zhang return ret;
5113bf30882SShaokun Zhang }
5123bf30882SShaokun Zhang
51325d8c250SJunhao He hisi_pmu_init(sllc_pmu, THIS_MODULE);
5143bf30882SShaokun Zhang
5153bf30882SShaokun Zhang ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
5163bf30882SShaokun Zhang if (ret) {
5173bf30882SShaokun Zhang dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
518b805cafcSJunhao He cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
5193bf30882SShaokun Zhang &sllc_pmu->node);
5203bf30882SShaokun Zhang return ret;
5213bf30882SShaokun Zhang }
5223bf30882SShaokun Zhang
5233bf30882SShaokun Zhang platform_set_drvdata(pdev, sllc_pmu);
5243bf30882SShaokun Zhang
5253bf30882SShaokun Zhang return ret;
5263bf30882SShaokun Zhang }
5273bf30882SShaokun Zhang
hisi_sllc_pmu_remove(struct platform_device * pdev)528e07486a8SUwe Kleine-König static void hisi_sllc_pmu_remove(struct platform_device *pdev)
5293bf30882SShaokun Zhang {
5303bf30882SShaokun Zhang struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev);
5313bf30882SShaokun Zhang
5323bf30882SShaokun Zhang perf_pmu_unregister(&sllc_pmu->pmu);
5333bf30882SShaokun Zhang cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
5343bf30882SShaokun Zhang &sllc_pmu->node);
5353bf30882SShaokun Zhang }
5363bf30882SShaokun Zhang
53729614c55SJunhao He static const struct acpi_device_id hisi_sllc_pmu_acpi_match[] = {
53829614c55SJunhao He { "HISI0263", (kernel_ulong_t)&hisi_sllc_v2 },
5391fd20ba0SJunhao He { "HISI0264", (kernel_ulong_t)&hisi_sllc_v3 },
54029614c55SJunhao He {}
54129614c55SJunhao He };
54229614c55SJunhao He MODULE_DEVICE_TABLE(acpi, hisi_sllc_pmu_acpi_match);
54329614c55SJunhao He
5443bf30882SShaokun Zhang static struct platform_driver hisi_sllc_pmu_driver = {
5453bf30882SShaokun Zhang .driver = {
5463bf30882SShaokun Zhang .name = "hisi_sllc_pmu",
5473bf30882SShaokun Zhang .acpi_match_table = hisi_sllc_pmu_acpi_match,
5483bf30882SShaokun Zhang .suppress_bind_attrs = true,
5493bf30882SShaokun Zhang },
5503bf30882SShaokun Zhang .probe = hisi_sllc_pmu_probe,
551845fd2cbSUwe Kleine-König .remove = hisi_sllc_pmu_remove,
5523bf30882SShaokun Zhang };
5533bf30882SShaokun Zhang
hisi_sllc_pmu_module_init(void)5543bf30882SShaokun Zhang static int __init hisi_sllc_pmu_module_init(void)
5553bf30882SShaokun Zhang {
5563bf30882SShaokun Zhang int ret;
5573bf30882SShaokun Zhang
5583bf30882SShaokun Zhang ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
5593bf30882SShaokun Zhang "AP_PERF_ARM_HISI_SLLC_ONLINE",
5603bf30882SShaokun Zhang hisi_uncore_pmu_online_cpu,
5613bf30882SShaokun Zhang hisi_uncore_pmu_offline_cpu);
5623bf30882SShaokun Zhang if (ret) {
5633bf30882SShaokun Zhang pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret);
5643bf30882SShaokun Zhang return ret;
5653bf30882SShaokun Zhang }
5663bf30882SShaokun Zhang
5673bf30882SShaokun Zhang ret = platform_driver_register(&hisi_sllc_pmu_driver);
5683bf30882SShaokun Zhang if (ret)
5693bf30882SShaokun Zhang cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
5703bf30882SShaokun Zhang
5713bf30882SShaokun Zhang return ret;
5723bf30882SShaokun Zhang }
5733bf30882SShaokun Zhang module_init(hisi_sllc_pmu_module_init);
5743bf30882SShaokun Zhang
hisi_sllc_pmu_module_exit(void)5753bf30882SShaokun Zhang static void __exit hisi_sllc_pmu_module_exit(void)
5763bf30882SShaokun Zhang {
5773bf30882SShaokun Zhang platform_driver_unregister(&hisi_sllc_pmu_driver);
5783bf30882SShaokun Zhang cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
5793bf30882SShaokun Zhang }
5803bf30882SShaokun Zhang module_exit(hisi_sllc_pmu_module_exit);
5813bf30882SShaokun Zhang
58241729809SYicong Yang MODULE_IMPORT_NS("HISI_PMU");
5833bf30882SShaokun Zhang MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver");
5843bf30882SShaokun Zhang MODULE_LICENSE("GPL v2");
5853bf30882SShaokun Zhang MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
5863bf30882SShaokun Zhang MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
587