1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * HiSilicon SoC Hardware event counters support |
4 | * |
5 | * Copyright (C) 2017 HiSilicon Limited |
6 | * Author: Anurup M <anurup.m@huawei.com> |
7 | * Shaokun Zhang <zhangshaokun@hisilicon.com> |
8 | * |
9 | * This code is based on the uncore PMUs like arm-cci and arm-ccn. |
10 | */ |
11 | #ifndef __HISI_UNCORE_PMU_H__ |
12 | #define __HISI_UNCORE_PMU_H__ |
13 | |
14 | #include <linux/bitfield.h> |
15 | #include <linux/cpumask.h> |
16 | #include <linux/device.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> |
19 | #include <linux/perf_event.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/types.h> |
22 | |
23 | #undef pr_fmt |
24 | #define pr_fmt(fmt) "hisi_pmu: " fmt |
25 | |
26 | #define HISI_PMU_V2 0x30 |
27 | #define HISI_MAX_COUNTERS 0x10 |
28 | #define to_hisi_pmu(p) (container_of(p, struct hisi_pmu, pmu)) |
29 | |
30 | #define HISI_PMU_ATTR(_name, _func, _config) \ |
31 | (&((struct dev_ext_attribute[]) { \ |
32 | { __ATTR(_name, 0444, _func, NULL), (void *)_config } \ |
33 | })[0].attr.attr) |
34 | |
35 | #define HISI_PMU_FORMAT_ATTR(_name, _config) \ |
36 | HISI_PMU_ATTR(_name, hisi_format_sysfs_show, (void *)_config) |
37 | #define HISI_PMU_EVENT_ATTR(_name, _config) \ |
38 | HISI_PMU_ATTR(_name, hisi_event_sysfs_show, (unsigned long)_config) |
39 | |
40 | #define (name, config, hi, lo) \ |
41 | static inline u32 hisi_get_##name(struct perf_event *event) \ |
42 | { \ |
43 | return FIELD_GET(GENMASK_ULL(hi, lo), event->attr.config); \ |
44 | } |
45 | |
46 | #define HISI_GET_EVENTID(ev) (ev->hw.config_base & 0xff) |
47 | |
48 | #define HISI_PMU_EVTYPE_BITS 8 |
49 | #define HISI_PMU_EVTYPE_SHIFT(idx) ((idx) % 4 * HISI_PMU_EVTYPE_BITS) |
50 | |
51 | struct hisi_pmu; |
52 | |
53 | struct hisi_uncore_ops { |
54 | int (*check_filter)(struct perf_event *event); |
55 | void (*write_evtype)(struct hisi_pmu *, int, u32); |
56 | int (*get_event_idx)(struct perf_event *); |
57 | u64 (*read_counter)(struct hisi_pmu *, struct hw_perf_event *); |
58 | void (*write_counter)(struct hisi_pmu *, struct hw_perf_event *, u64); |
59 | void (*enable_counter)(struct hisi_pmu *, struct hw_perf_event *); |
60 | void (*disable_counter)(struct hisi_pmu *, struct hw_perf_event *); |
61 | void (*enable_counter_int)(struct hisi_pmu *, struct hw_perf_event *); |
62 | void (*disable_counter_int)(struct hisi_pmu *, struct hw_perf_event *); |
63 | void (*start_counters)(struct hisi_pmu *); |
64 | void (*stop_counters)(struct hisi_pmu *); |
65 | u32 (*get_int_status)(struct hisi_pmu *hisi_pmu); |
66 | void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx); |
67 | void (*enable_filter)(struct perf_event *event); |
68 | void (*disable_filter)(struct perf_event *event); |
69 | }; |
70 | |
71 | /* Describes the HISI PMU chip features information */ |
72 | struct hisi_pmu_dev_info { |
73 | const char *name; |
74 | const struct attribute_group **attr_groups; |
75 | void *private; |
76 | }; |
77 | |
78 | struct hisi_pmu_hwevents { |
79 | struct perf_event *hw_events[HISI_MAX_COUNTERS]; |
80 | DECLARE_BITMAP(used_mask, HISI_MAX_COUNTERS); |
81 | const struct attribute_group **attr_groups; |
82 | }; |
83 | |
84 | /* Generic pmu struct for different pmu types */ |
85 | struct hisi_pmu { |
86 | struct pmu pmu; |
87 | const struct hisi_uncore_ops *ops; |
88 | const struct hisi_pmu_dev_info *dev_info; |
89 | struct hisi_pmu_hwevents pmu_events; |
90 | /* associated_cpus: All CPUs associated with the PMU */ |
91 | cpumask_t associated_cpus; |
92 | /* CPU used for counting */ |
93 | int on_cpu; |
94 | int irq; |
95 | struct device *dev; |
96 | struct hlist_node node; |
97 | int sccl_id; |
98 | int sicl_id; |
99 | int ccl_id; |
100 | void __iomem *base; |
101 | /* the ID of the PMU modules */ |
102 | u32 index_id; |
103 | /* For DDRC PMU v2: each DDRC has more than one DMC */ |
104 | u32 sub_id; |
105 | int num_counters; |
106 | int counter_bits; |
107 | /* check event code range */ |
108 | int check_event; |
109 | u32 identifier; |
110 | }; |
111 | |
112 | int hisi_uncore_pmu_get_event_idx(struct perf_event *event); |
113 | void hisi_uncore_pmu_read(struct perf_event *event); |
114 | int hisi_uncore_pmu_add(struct perf_event *event, int flags); |
115 | void hisi_uncore_pmu_del(struct perf_event *event, int flags); |
116 | void hisi_uncore_pmu_start(struct perf_event *event, int flags); |
117 | void hisi_uncore_pmu_stop(struct perf_event *event, int flags); |
118 | void hisi_uncore_pmu_set_event_period(struct perf_event *event); |
119 | void hisi_uncore_pmu_event_update(struct perf_event *event); |
120 | int hisi_uncore_pmu_event_init(struct perf_event *event); |
121 | void hisi_uncore_pmu_enable(struct pmu *pmu); |
122 | void hisi_uncore_pmu_disable(struct pmu *pmu); |
123 | ssize_t hisi_event_sysfs_show(struct device *dev, |
124 | struct device_attribute *attr, char *buf); |
125 | ssize_t hisi_format_sysfs_show(struct device *dev, |
126 | struct device_attribute *attr, char *buf); |
127 | ssize_t hisi_cpumask_sysfs_show(struct device *dev, |
128 | struct device_attribute *attr, char *buf); |
129 | int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node); |
130 | int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node); |
131 | |
132 | ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev, |
133 | struct device_attribute *attr, |
134 | char *page); |
135 | int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu, |
136 | struct platform_device *pdev); |
137 | |
138 | void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module); |
139 | #endif /* __HISI_UNCORE_PMU_H__ */ |
140 | |