145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b828f960SMark Rutland /*
3b828f960SMark Rutland * L220/L310 cache controller support
4b828f960SMark Rutland *
5b828f960SMark Rutland * Copyright (C) 2016 ARM Limited
6b828f960SMark Rutland */
7b828f960SMark Rutland #include <linux/errno.h>
8b828f960SMark Rutland #include <linux/hrtimer.h>
9b828f960SMark Rutland #include <linux/io.h>
10b828f960SMark Rutland #include <linux/list.h>
11b828f960SMark Rutland #include <linux/perf_event.h>
12b828f960SMark Rutland #include <linux/printk.h>
13b828f960SMark Rutland #include <linux/slab.h>
14b828f960SMark Rutland #include <linux/types.h>
15b828f960SMark Rutland
16b828f960SMark Rutland #include <asm/hardware/cache-l2x0.h>
17b828f960SMark Rutland
18b828f960SMark Rutland #define PMU_NR_COUNTERS 2
19b828f960SMark Rutland
20b828f960SMark Rutland static void __iomem *l2x0_base;
21b828f960SMark Rutland static struct pmu *l2x0_pmu;
22b828f960SMark Rutland static cpumask_t pmu_cpu;
23b828f960SMark Rutland
24b828f960SMark Rutland static const char *l2x0_name;
25b828f960SMark Rutland
26b828f960SMark Rutland static ktime_t l2x0_pmu_poll_period;
27b828f960SMark Rutland static struct hrtimer l2x0_pmu_hrtimer;
28b828f960SMark Rutland
29b828f960SMark Rutland /*
30b828f960SMark Rutland * The L220/PL310 PMU has two equivalent counters, Counter1 and Counter0.
31b828f960SMark Rutland * Registers controlling these are laid out in pairs, in descending order, i.e.
32b828f960SMark Rutland * the register for Counter1 comes first, followed by the register for
33b828f960SMark Rutland * Counter0.
34b828f960SMark Rutland * We ensure that idx 0 -> Counter0, and idx1 -> Counter1.
35b828f960SMark Rutland */
36b828f960SMark Rutland static struct perf_event *events[PMU_NR_COUNTERS];
37b828f960SMark Rutland
38b828f960SMark Rutland /* Find an unused counter */
l2x0_pmu_find_idx(void)39b828f960SMark Rutland static int l2x0_pmu_find_idx(void)
40b828f960SMark Rutland {
41b828f960SMark Rutland int i;
42b828f960SMark Rutland
43b828f960SMark Rutland for (i = 0; i < PMU_NR_COUNTERS; i++) {
44b828f960SMark Rutland if (!events[i])
45b828f960SMark Rutland return i;
46b828f960SMark Rutland }
47b828f960SMark Rutland
48b828f960SMark Rutland return -1;
49b828f960SMark Rutland }
50b828f960SMark Rutland
51b828f960SMark Rutland /* How many counters are allocated? */
l2x0_pmu_num_active_counters(void)52b828f960SMark Rutland static int l2x0_pmu_num_active_counters(void)
53b828f960SMark Rutland {
54b828f960SMark Rutland int i, cnt = 0;
55b828f960SMark Rutland
56b828f960SMark Rutland for (i = 0; i < PMU_NR_COUNTERS; i++) {
57b828f960SMark Rutland if (events[i])
58b828f960SMark Rutland cnt++;
59b828f960SMark Rutland }
60b828f960SMark Rutland
61b828f960SMark Rutland return cnt;
62b828f960SMark Rutland }
63b828f960SMark Rutland
l2x0_pmu_counter_config_write(int idx,u32 val)64b828f960SMark Rutland static void l2x0_pmu_counter_config_write(int idx, u32 val)
65b828f960SMark Rutland {
66b828f960SMark Rutland writel_relaxed(val, l2x0_base + L2X0_EVENT_CNT0_CFG - 4 * idx);
67b828f960SMark Rutland }
68b828f960SMark Rutland
l2x0_pmu_counter_read(int idx)69b828f960SMark Rutland static u32 l2x0_pmu_counter_read(int idx)
70b828f960SMark Rutland {
71b828f960SMark Rutland return readl_relaxed(l2x0_base + L2X0_EVENT_CNT0_VAL - 4 * idx);
72b828f960SMark Rutland }
73b828f960SMark Rutland
l2x0_pmu_counter_write(int idx,u32 val)74b828f960SMark Rutland static void l2x0_pmu_counter_write(int idx, u32 val)
75b828f960SMark Rutland {
76b828f960SMark Rutland writel_relaxed(val, l2x0_base + L2X0_EVENT_CNT0_VAL - 4 * idx);
77b828f960SMark Rutland }
78b828f960SMark Rutland
__l2x0_pmu_enable(void)79b828f960SMark Rutland static void __l2x0_pmu_enable(void)
80b828f960SMark Rutland {
81b828f960SMark Rutland u32 val = readl_relaxed(l2x0_base + L2X0_EVENT_CNT_CTRL);
82b828f960SMark Rutland val |= L2X0_EVENT_CNT_CTRL_ENABLE;
83b828f960SMark Rutland writel_relaxed(val, l2x0_base + L2X0_EVENT_CNT_CTRL);
84b828f960SMark Rutland }
85b828f960SMark Rutland
__l2x0_pmu_disable(void)86b828f960SMark Rutland static void __l2x0_pmu_disable(void)
87b828f960SMark Rutland {
88b828f960SMark Rutland u32 val = readl_relaxed(l2x0_base + L2X0_EVENT_CNT_CTRL);
89b828f960SMark Rutland val &= ~L2X0_EVENT_CNT_CTRL_ENABLE;
90b828f960SMark Rutland writel_relaxed(val, l2x0_base + L2X0_EVENT_CNT_CTRL);
91b828f960SMark Rutland }
92b828f960SMark Rutland
l2x0_pmu_enable(struct pmu * pmu)93b828f960SMark Rutland static void l2x0_pmu_enable(struct pmu *pmu)
94b828f960SMark Rutland {
95b828f960SMark Rutland if (l2x0_pmu_num_active_counters() == 0)
96b828f960SMark Rutland return;
97b828f960SMark Rutland
98b828f960SMark Rutland __l2x0_pmu_enable();
99b828f960SMark Rutland }
100b828f960SMark Rutland
l2x0_pmu_disable(struct pmu * pmu)101b828f960SMark Rutland static void l2x0_pmu_disable(struct pmu *pmu)
102b828f960SMark Rutland {
103b828f960SMark Rutland if (l2x0_pmu_num_active_counters() == 0)
104b828f960SMark Rutland return;
105b828f960SMark Rutland
106b828f960SMark Rutland __l2x0_pmu_disable();
107b828f960SMark Rutland }
108b828f960SMark Rutland
warn_if_saturated(u32 count)109b828f960SMark Rutland static void warn_if_saturated(u32 count)
110b828f960SMark Rutland {
111b828f960SMark Rutland if (count != 0xffffffff)
112b828f960SMark Rutland return;
113b828f960SMark Rutland
114b828f960SMark Rutland pr_warn_ratelimited("L2X0 counter saturated. Poll period too long\n");
115b828f960SMark Rutland }
116b828f960SMark Rutland
l2x0_pmu_event_read(struct perf_event * event)117b828f960SMark Rutland static void l2x0_pmu_event_read(struct perf_event *event)
118b828f960SMark Rutland {
119b828f960SMark Rutland struct hw_perf_event *hw = &event->hw;
120b828f960SMark Rutland u64 prev_count, new_count, mask;
121b828f960SMark Rutland
122b828f960SMark Rutland do {
123b828f960SMark Rutland prev_count = local64_read(&hw->prev_count);
124b828f960SMark Rutland new_count = l2x0_pmu_counter_read(hw->idx);
125b828f960SMark Rutland } while (local64_xchg(&hw->prev_count, new_count) != prev_count);
126b828f960SMark Rutland
127b828f960SMark Rutland mask = GENMASK_ULL(31, 0);
128b828f960SMark Rutland local64_add((new_count - prev_count) & mask, &event->count);
129b828f960SMark Rutland
130b828f960SMark Rutland warn_if_saturated(new_count);
131b828f960SMark Rutland }
132b828f960SMark Rutland
l2x0_pmu_event_configure(struct perf_event * event)133b828f960SMark Rutland static void l2x0_pmu_event_configure(struct perf_event *event)
134b828f960SMark Rutland {
135b828f960SMark Rutland struct hw_perf_event *hw = &event->hw;
136b828f960SMark Rutland
137b828f960SMark Rutland /*
138b828f960SMark Rutland * The L2X0 counters saturate at 0xffffffff rather than wrapping, so we
139b828f960SMark Rutland * will *always* lose some number of events when a counter saturates,
140b828f960SMark Rutland * and have no way of detecting how many were lost.
141b828f960SMark Rutland *
142b828f960SMark Rutland * To minimize the impact of this, we try to maximize the period by
143b828f960SMark Rutland * always starting counters at zero. To ensure that group ratios are
144b828f960SMark Rutland * representative, we poll periodically to avoid counters saturating.
145b828f960SMark Rutland * See l2x0_pmu_poll().
146b828f960SMark Rutland */
147b828f960SMark Rutland local64_set(&hw->prev_count, 0);
148b828f960SMark Rutland l2x0_pmu_counter_write(hw->idx, 0);
149b828f960SMark Rutland }
150b828f960SMark Rutland
l2x0_pmu_poll(struct hrtimer * hrtimer)151b828f960SMark Rutland static enum hrtimer_restart l2x0_pmu_poll(struct hrtimer *hrtimer)
152b828f960SMark Rutland {
153b828f960SMark Rutland unsigned long flags;
154b828f960SMark Rutland int i;
155b828f960SMark Rutland
156b828f960SMark Rutland local_irq_save(flags);
157b828f960SMark Rutland __l2x0_pmu_disable();
158b828f960SMark Rutland
159b828f960SMark Rutland for (i = 0; i < PMU_NR_COUNTERS; i++) {
160b828f960SMark Rutland struct perf_event *event = events[i];
161b828f960SMark Rutland
162b828f960SMark Rutland if (!event)
163b828f960SMark Rutland continue;
164b828f960SMark Rutland
165b828f960SMark Rutland l2x0_pmu_event_read(event);
166b828f960SMark Rutland l2x0_pmu_event_configure(event);
167b828f960SMark Rutland }
168b828f960SMark Rutland
169b828f960SMark Rutland __l2x0_pmu_enable();
170b828f960SMark Rutland local_irq_restore(flags);
171b828f960SMark Rutland
172b828f960SMark Rutland hrtimer_forward_now(hrtimer, l2x0_pmu_poll_period);
173b828f960SMark Rutland return HRTIMER_RESTART;
174b828f960SMark Rutland }
175b828f960SMark Rutland
176b828f960SMark Rutland
__l2x0_pmu_event_enable(int idx,u32 event)177b828f960SMark Rutland static void __l2x0_pmu_event_enable(int idx, u32 event)
178b828f960SMark Rutland {
179b828f960SMark Rutland u32 val;
180b828f960SMark Rutland
181b828f960SMark Rutland val = event << L2X0_EVENT_CNT_CFG_SRC_SHIFT;
182b828f960SMark Rutland val |= L2X0_EVENT_CNT_CFG_INT_DISABLED;
183b828f960SMark Rutland l2x0_pmu_counter_config_write(idx, val);
184b828f960SMark Rutland }
185b828f960SMark Rutland
l2x0_pmu_event_start(struct perf_event * event,int flags)186b828f960SMark Rutland static void l2x0_pmu_event_start(struct perf_event *event, int flags)
187b828f960SMark Rutland {
188b828f960SMark Rutland struct hw_perf_event *hw = &event->hw;
189b828f960SMark Rutland
190b828f960SMark Rutland if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
191b828f960SMark Rutland return;
192b828f960SMark Rutland
193b828f960SMark Rutland if (flags & PERF_EF_RELOAD) {
194b828f960SMark Rutland WARN_ON_ONCE(!(hw->state & PERF_HES_UPTODATE));
195b828f960SMark Rutland l2x0_pmu_event_configure(event);
196b828f960SMark Rutland }
197b828f960SMark Rutland
198b828f960SMark Rutland hw->state = 0;
199b828f960SMark Rutland
200b828f960SMark Rutland __l2x0_pmu_event_enable(hw->idx, hw->config_base);
201b828f960SMark Rutland }
202b828f960SMark Rutland
__l2x0_pmu_event_disable(int idx)203b828f960SMark Rutland static void __l2x0_pmu_event_disable(int idx)
204b828f960SMark Rutland {
205b828f960SMark Rutland u32 val;
206b828f960SMark Rutland
207b828f960SMark Rutland val = L2X0_EVENT_CNT_CFG_SRC_DISABLED << L2X0_EVENT_CNT_CFG_SRC_SHIFT;
208b828f960SMark Rutland val |= L2X0_EVENT_CNT_CFG_INT_DISABLED;
209b828f960SMark Rutland l2x0_pmu_counter_config_write(idx, val);
210b828f960SMark Rutland }
211b828f960SMark Rutland
l2x0_pmu_event_stop(struct perf_event * event,int flags)212b828f960SMark Rutland static void l2x0_pmu_event_stop(struct perf_event *event, int flags)
213b828f960SMark Rutland {
214b828f960SMark Rutland struct hw_perf_event *hw = &event->hw;
215b828f960SMark Rutland
216b828f960SMark Rutland if (WARN_ON_ONCE(event->hw.state & PERF_HES_STOPPED))
217b828f960SMark Rutland return;
218b828f960SMark Rutland
219b828f960SMark Rutland __l2x0_pmu_event_disable(hw->idx);
220b828f960SMark Rutland
221b828f960SMark Rutland hw->state |= PERF_HES_STOPPED;
222b828f960SMark Rutland
223b828f960SMark Rutland if (flags & PERF_EF_UPDATE) {
224b828f960SMark Rutland l2x0_pmu_event_read(event);
225b828f960SMark Rutland hw->state |= PERF_HES_UPTODATE;
226b828f960SMark Rutland }
227b828f960SMark Rutland }
228b828f960SMark Rutland
l2x0_pmu_event_add(struct perf_event * event,int flags)229b828f960SMark Rutland static int l2x0_pmu_event_add(struct perf_event *event, int flags)
230b828f960SMark Rutland {
231b828f960SMark Rutland struct hw_perf_event *hw = &event->hw;
232b828f960SMark Rutland int idx = l2x0_pmu_find_idx();
233b828f960SMark Rutland
234b828f960SMark Rutland if (idx == -1)
235b828f960SMark Rutland return -EAGAIN;
236b828f960SMark Rutland
237b828f960SMark Rutland /*
238b828f960SMark Rutland * Pin the timer, so that the overflows are handled by the chosen
239b828f960SMark Rutland * event->cpu (this is the same one as presented in "cpumask"
240b828f960SMark Rutland * attribute).
241b828f960SMark Rutland */
242b828f960SMark Rutland if (l2x0_pmu_num_active_counters() == 0)
243b828f960SMark Rutland hrtimer_start(&l2x0_pmu_hrtimer, l2x0_pmu_poll_period,
244b828f960SMark Rutland HRTIMER_MODE_REL_PINNED);
245b828f960SMark Rutland
246b828f960SMark Rutland events[idx] = event;
247b828f960SMark Rutland hw->idx = idx;
248b828f960SMark Rutland
249b828f960SMark Rutland l2x0_pmu_event_configure(event);
250b828f960SMark Rutland
251b828f960SMark Rutland hw->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
252b828f960SMark Rutland
253b828f960SMark Rutland if (flags & PERF_EF_START)
254b828f960SMark Rutland l2x0_pmu_event_start(event, 0);
255b828f960SMark Rutland
256b828f960SMark Rutland return 0;
257b828f960SMark Rutland }
258b828f960SMark Rutland
l2x0_pmu_event_del(struct perf_event * event,int flags)259b828f960SMark Rutland static void l2x0_pmu_event_del(struct perf_event *event, int flags)
260b828f960SMark Rutland {
261b828f960SMark Rutland struct hw_perf_event *hw = &event->hw;
262b828f960SMark Rutland
263b828f960SMark Rutland l2x0_pmu_event_stop(event, PERF_EF_UPDATE);
264b828f960SMark Rutland
265b828f960SMark Rutland events[hw->idx] = NULL;
266b828f960SMark Rutland hw->idx = -1;
267b828f960SMark Rutland
268b828f960SMark Rutland if (l2x0_pmu_num_active_counters() == 0)
269b828f960SMark Rutland hrtimer_cancel(&l2x0_pmu_hrtimer);
270b828f960SMark Rutland }
271b828f960SMark Rutland
l2x0_pmu_group_is_valid(struct perf_event * event)272b828f960SMark Rutland static bool l2x0_pmu_group_is_valid(struct perf_event *event)
273b828f960SMark Rutland {
274b828f960SMark Rutland struct pmu *pmu = event->pmu;
275b828f960SMark Rutland struct perf_event *leader = event->group_leader;
276b828f960SMark Rutland struct perf_event *sibling;
277b828f960SMark Rutland int num_hw = 0;
278b828f960SMark Rutland
279b828f960SMark Rutland if (leader->pmu == pmu)
280b828f960SMark Rutland num_hw++;
281b828f960SMark Rutland else if (!is_software_event(leader))
282b828f960SMark Rutland return false;
283b828f960SMark Rutland
284edb39592SPeter Zijlstra for_each_sibling_event(sibling, leader) {
285b828f960SMark Rutland if (sibling->pmu == pmu)
286b828f960SMark Rutland num_hw++;
287b828f960SMark Rutland else if (!is_software_event(sibling))
288b828f960SMark Rutland return false;
289b828f960SMark Rutland }
290b828f960SMark Rutland
291b828f960SMark Rutland return num_hw <= PMU_NR_COUNTERS;
292b828f960SMark Rutland }
293b828f960SMark Rutland
l2x0_pmu_event_init(struct perf_event * event)294b828f960SMark Rutland static int l2x0_pmu_event_init(struct perf_event *event)
295b828f960SMark Rutland {
296b828f960SMark Rutland struct hw_perf_event *hw = &event->hw;
297b828f960SMark Rutland
298b828f960SMark Rutland if (event->attr.type != l2x0_pmu->type)
299b828f960SMark Rutland return -ENOENT;
300b828f960SMark Rutland
301b828f960SMark Rutland if (is_sampling_event(event) ||
302b828f960SMark Rutland event->attach_state & PERF_ATTACH_TASK)
303b828f960SMark Rutland return -EINVAL;
304b828f960SMark Rutland
305b828f960SMark Rutland if (event->cpu < 0)
306b828f960SMark Rutland return -EINVAL;
307b828f960SMark Rutland
308b828f960SMark Rutland if (event->attr.config & ~L2X0_EVENT_CNT_CFG_SRC_MASK)
309b828f960SMark Rutland return -EINVAL;
310b828f960SMark Rutland
311b828f960SMark Rutland hw->config_base = event->attr.config;
312b828f960SMark Rutland
313b828f960SMark Rutland if (!l2x0_pmu_group_is_valid(event))
314b828f960SMark Rutland return -EINVAL;
315b828f960SMark Rutland
316b828f960SMark Rutland event->cpu = cpumask_first(&pmu_cpu);
317b828f960SMark Rutland
318b828f960SMark Rutland return 0;
319b828f960SMark Rutland }
320b828f960SMark Rutland
321b828f960SMark Rutland struct l2x0_event_attribute {
322b828f960SMark Rutland struct device_attribute attr;
323b828f960SMark Rutland unsigned int config;
324b828f960SMark Rutland bool pl310_only;
325b828f960SMark Rutland };
326b828f960SMark Rutland
327b828f960SMark Rutland #define L2X0_EVENT_ATTR(_name, _config, _pl310_only) \
328b828f960SMark Rutland (&((struct l2x0_event_attribute[]) {{ \
329b828f960SMark Rutland .attr = __ATTR(_name, S_IRUGO, l2x0_pmu_event_show, NULL), \
330b828f960SMark Rutland .config = _config, \
331b828f960SMark Rutland .pl310_only = _pl310_only, \
332b828f960SMark Rutland }})[0].attr.attr)
333b828f960SMark Rutland
334b828f960SMark Rutland #define L220_PLUS_EVENT_ATTR(_name, _config) \
335b828f960SMark Rutland L2X0_EVENT_ATTR(_name, _config, false)
336b828f960SMark Rutland
337b828f960SMark Rutland #define PL310_EVENT_ATTR(_name, _config) \
338b828f960SMark Rutland L2X0_EVENT_ATTR(_name, _config, true)
339b828f960SMark Rutland
l2x0_pmu_event_show(struct device * dev,struct device_attribute * attr,char * buf)340b828f960SMark Rutland static ssize_t l2x0_pmu_event_show(struct device *dev,
341b828f960SMark Rutland struct device_attribute *attr, char *buf)
342b828f960SMark Rutland {
343b828f960SMark Rutland struct l2x0_event_attribute *lattr;
344b828f960SMark Rutland
345b828f960SMark Rutland lattr = container_of(attr, typeof(*lattr), attr);
346b828f960SMark Rutland return snprintf(buf, PAGE_SIZE, "config=0x%x\n", lattr->config);
347b828f960SMark Rutland }
348b828f960SMark Rutland
l2x0_pmu_event_attr_is_visible(struct kobject * kobj,struct attribute * attr,int unused)349b828f960SMark Rutland static umode_t l2x0_pmu_event_attr_is_visible(struct kobject *kobj,
350b828f960SMark Rutland struct attribute *attr,
351b828f960SMark Rutland int unused)
352b828f960SMark Rutland {
353b828f960SMark Rutland struct device *dev = kobj_to_dev(kobj);
354b828f960SMark Rutland struct pmu *pmu = dev_get_drvdata(dev);
355b828f960SMark Rutland struct l2x0_event_attribute *lattr;
356b828f960SMark Rutland
357b828f960SMark Rutland lattr = container_of(attr, typeof(*lattr), attr.attr);
358b828f960SMark Rutland
359b828f960SMark Rutland if (!lattr->pl310_only || strcmp("l2c_310", pmu->name) == 0)
360b828f960SMark Rutland return attr->mode;
361b828f960SMark Rutland
362b828f960SMark Rutland return 0;
363b828f960SMark Rutland }
364b828f960SMark Rutland
365b828f960SMark Rutland static struct attribute *l2x0_pmu_event_attrs[] = {
366b828f960SMark Rutland L220_PLUS_EVENT_ATTR(co, 0x1),
367b828f960SMark Rutland L220_PLUS_EVENT_ATTR(drhit, 0x2),
368b828f960SMark Rutland L220_PLUS_EVENT_ATTR(drreq, 0x3),
369b828f960SMark Rutland L220_PLUS_EVENT_ATTR(dwhit, 0x4),
370b828f960SMark Rutland L220_PLUS_EVENT_ATTR(dwreq, 0x5),
371b828f960SMark Rutland L220_PLUS_EVENT_ATTR(dwtreq, 0x6),
372b828f960SMark Rutland L220_PLUS_EVENT_ATTR(irhit, 0x7),
373b828f960SMark Rutland L220_PLUS_EVENT_ATTR(irreq, 0x8),
374b828f960SMark Rutland L220_PLUS_EVENT_ATTR(wa, 0x9),
375b828f960SMark Rutland PL310_EVENT_ATTR(ipfalloc, 0xa),
376b828f960SMark Rutland PL310_EVENT_ATTR(epfhit, 0xb),
377b828f960SMark Rutland PL310_EVENT_ATTR(epfalloc, 0xc),
378b828f960SMark Rutland PL310_EVENT_ATTR(srrcvd, 0xd),
379b828f960SMark Rutland PL310_EVENT_ATTR(srconf, 0xe),
380b828f960SMark Rutland PL310_EVENT_ATTR(epfrcvd, 0xf),
381b828f960SMark Rutland NULL
382b828f960SMark Rutland };
383b828f960SMark Rutland
384b828f960SMark Rutland static struct attribute_group l2x0_pmu_event_attrs_group = {
385b828f960SMark Rutland .name = "events",
386b828f960SMark Rutland .attrs = l2x0_pmu_event_attrs,
387b828f960SMark Rutland .is_visible = l2x0_pmu_event_attr_is_visible,
388b828f960SMark Rutland };
389b828f960SMark Rutland
l2x0_pmu_cpumask_show(struct device * dev,struct device_attribute * attr,char * buf)390b828f960SMark Rutland static ssize_t l2x0_pmu_cpumask_show(struct device *dev,
391b828f960SMark Rutland struct device_attribute *attr, char *buf)
392b828f960SMark Rutland {
393b828f960SMark Rutland return cpumap_print_to_pagebuf(true, buf, &pmu_cpu);
394b828f960SMark Rutland }
395b828f960SMark Rutland
396b828f960SMark Rutland static struct device_attribute l2x0_pmu_cpumask_attr =
397b828f960SMark Rutland __ATTR(cpumask, S_IRUGO, l2x0_pmu_cpumask_show, NULL);
398b828f960SMark Rutland
399b828f960SMark Rutland static struct attribute *l2x0_pmu_cpumask_attrs[] = {
400b828f960SMark Rutland &l2x0_pmu_cpumask_attr.attr,
401b828f960SMark Rutland NULL,
402b828f960SMark Rutland };
403b828f960SMark Rutland
404b828f960SMark Rutland static struct attribute_group l2x0_pmu_cpumask_attr_group = {
405b828f960SMark Rutland .attrs = l2x0_pmu_cpumask_attrs,
406b828f960SMark Rutland };
407b828f960SMark Rutland
408b828f960SMark Rutland static const struct attribute_group *l2x0_pmu_attr_groups[] = {
409b828f960SMark Rutland &l2x0_pmu_event_attrs_group,
410b828f960SMark Rutland &l2x0_pmu_cpumask_attr_group,
411b828f960SMark Rutland NULL,
412b828f960SMark Rutland };
413b828f960SMark Rutland
l2x0_pmu_reset(void)414b828f960SMark Rutland static void l2x0_pmu_reset(void)
415b828f960SMark Rutland {
416b828f960SMark Rutland int i;
417b828f960SMark Rutland
418b828f960SMark Rutland __l2x0_pmu_disable();
419b828f960SMark Rutland
420b828f960SMark Rutland for (i = 0; i < PMU_NR_COUNTERS; i++)
421b828f960SMark Rutland __l2x0_pmu_event_disable(i);
422b828f960SMark Rutland }
423b828f960SMark Rutland
l2x0_pmu_offline_cpu(unsigned int cpu)424b828f960SMark Rutland static int l2x0_pmu_offline_cpu(unsigned int cpu)
425b828f960SMark Rutland {
426b828f960SMark Rutland unsigned int target;
427b828f960SMark Rutland
428b828f960SMark Rutland if (!cpumask_test_and_clear_cpu(cpu, &pmu_cpu))
429b828f960SMark Rutland return 0;
430b828f960SMark Rutland
431b828f960SMark Rutland target = cpumask_any_but(cpu_online_mask, cpu);
432b828f960SMark Rutland if (target >= nr_cpu_ids)
433b828f960SMark Rutland return 0;
434b828f960SMark Rutland
435b828f960SMark Rutland perf_pmu_migrate_context(l2x0_pmu, cpu, target);
436b828f960SMark Rutland cpumask_set_cpu(target, &pmu_cpu);
437b828f960SMark Rutland
438b828f960SMark Rutland return 0;
439b828f960SMark Rutland }
440b828f960SMark Rutland
l2x0_pmu_suspend(void)441b828f960SMark Rutland void l2x0_pmu_suspend(void)
442b828f960SMark Rutland {
443b828f960SMark Rutland int i;
444b828f960SMark Rutland
445b828f960SMark Rutland if (!l2x0_pmu)
446b828f960SMark Rutland return;
447b828f960SMark Rutland
448b828f960SMark Rutland l2x0_pmu_disable(l2x0_pmu);
449b828f960SMark Rutland
450b828f960SMark Rutland for (i = 0; i < PMU_NR_COUNTERS; i++) {
451b828f960SMark Rutland if (events[i])
452b828f960SMark Rutland l2x0_pmu_event_stop(events[i], PERF_EF_UPDATE);
453b828f960SMark Rutland }
454b828f960SMark Rutland
455b828f960SMark Rutland }
456b828f960SMark Rutland
l2x0_pmu_resume(void)457b828f960SMark Rutland void l2x0_pmu_resume(void)
458b828f960SMark Rutland {
459b828f960SMark Rutland int i;
460b828f960SMark Rutland
461b828f960SMark Rutland if (!l2x0_pmu)
462b828f960SMark Rutland return;
463b828f960SMark Rutland
464b828f960SMark Rutland l2x0_pmu_reset();
465b828f960SMark Rutland
466b828f960SMark Rutland for (i = 0; i < PMU_NR_COUNTERS; i++) {
467b828f960SMark Rutland if (events[i])
468b828f960SMark Rutland l2x0_pmu_event_start(events[i], PERF_EF_RELOAD);
469b828f960SMark Rutland }
470b828f960SMark Rutland
471b828f960SMark Rutland l2x0_pmu_enable(l2x0_pmu);
472b828f960SMark Rutland }
473b828f960SMark Rutland
l2x0_pmu_register(void __iomem * base,u32 part)474b828f960SMark Rutland void __init l2x0_pmu_register(void __iomem *base, u32 part)
475b828f960SMark Rutland {
476b828f960SMark Rutland /*
477b828f960SMark Rutland * Determine whether we support the PMU, and choose the name for sysfs.
478b828f960SMark Rutland * This is also used by l2x0_pmu_event_attr_is_visible to determine
479b828f960SMark Rutland * which events to display, as the PL310 PMU supports a superset of
480b828f960SMark Rutland * L220 events.
481b828f960SMark Rutland *
482b828f960SMark Rutland * The L210 PMU has a different programmer's interface, and is not
483b828f960SMark Rutland * supported by this driver.
484b828f960SMark Rutland *
485b828f960SMark Rutland * We must defer registering the PMU until the perf subsystem is up and
486b828f960SMark Rutland * running, so just stash the name and base, and leave that to another
487b828f960SMark Rutland * initcall.
488b828f960SMark Rutland */
489b828f960SMark Rutland switch (part & L2X0_CACHE_ID_PART_MASK) {
490b828f960SMark Rutland case L2X0_CACHE_ID_PART_L220:
491b828f960SMark Rutland l2x0_name = "l2c_220";
492b828f960SMark Rutland break;
493b828f960SMark Rutland case L2X0_CACHE_ID_PART_L310:
494b828f960SMark Rutland l2x0_name = "l2c_310";
495b828f960SMark Rutland break;
496b828f960SMark Rutland default:
497b828f960SMark Rutland return;
498b828f960SMark Rutland }
499b828f960SMark Rutland
500b828f960SMark Rutland l2x0_base = base;
501b828f960SMark Rutland }
502b828f960SMark Rutland
l2x0_pmu_init(void)503b828f960SMark Rutland static __init int l2x0_pmu_init(void)
504b828f960SMark Rutland {
505b828f960SMark Rutland int ret;
506b828f960SMark Rutland
507b828f960SMark Rutland if (!l2x0_base)
508b828f960SMark Rutland return 0;
509b828f960SMark Rutland
510b828f960SMark Rutland l2x0_pmu = kzalloc(sizeof(*l2x0_pmu), GFP_KERNEL);
511b828f960SMark Rutland if (!l2x0_pmu) {
512b828f960SMark Rutland pr_warn("Unable to allocate L2x0 PMU\n");
513b828f960SMark Rutland return -ENOMEM;
514b828f960SMark Rutland }
515b828f960SMark Rutland
516b828f960SMark Rutland *l2x0_pmu = (struct pmu) {
517b828f960SMark Rutland .task_ctx_nr = perf_invalid_context,
518b828f960SMark Rutland .pmu_enable = l2x0_pmu_enable,
519b828f960SMark Rutland .pmu_disable = l2x0_pmu_disable,
520b828f960SMark Rutland .read = l2x0_pmu_event_read,
521b828f960SMark Rutland .start = l2x0_pmu_event_start,
522b828f960SMark Rutland .stop = l2x0_pmu_event_stop,
523b828f960SMark Rutland .add = l2x0_pmu_event_add,
524b828f960SMark Rutland .del = l2x0_pmu_event_del,
525b828f960SMark Rutland .event_init = l2x0_pmu_event_init,
526b828f960SMark Rutland .attr_groups = l2x0_pmu_attr_groups,
527cafa780eSAndrew Murray .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
528b828f960SMark Rutland };
529b828f960SMark Rutland
530b828f960SMark Rutland l2x0_pmu_reset();
531b828f960SMark Rutland
532b828f960SMark Rutland /*
533b828f960SMark Rutland * We always use a hrtimer rather than an interrupt.
534b828f960SMark Rutland * See comments in l2x0_pmu_event_configure and l2x0_pmu_poll.
535b828f960SMark Rutland *
536b828f960SMark Rutland * Polling once a second allows the counters to fill up to 1/128th on a
537b828f960SMark Rutland * quad-core test chip with cores clocked at 400MHz. Hopefully this
538b828f960SMark Rutland * leaves sufficient headroom to avoid overflow on production silicon
539b828f960SMark Rutland * at higher frequencies.
540b828f960SMark Rutland */
541b828f960SMark Rutland l2x0_pmu_poll_period = ms_to_ktime(1000);
542b828f960SMark Rutland hrtimer_init(&l2x0_pmu_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
543b828f960SMark Rutland l2x0_pmu_hrtimer.function = l2x0_pmu_poll;
544b828f960SMark Rutland
545b828f960SMark Rutland cpumask_set_cpu(0, &pmu_cpu);
546b828f960SMark Rutland ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_L2X0_ONLINE,
54773c1b41eSThomas Gleixner "perf/arm/l2x0:online", NULL,
548b828f960SMark Rutland l2x0_pmu_offline_cpu);
549b828f960SMark Rutland if (ret)
550b828f960SMark Rutland goto out_pmu;
551b828f960SMark Rutland
552b828f960SMark Rutland ret = perf_pmu_register(l2x0_pmu, l2x0_name, -1);
553b828f960SMark Rutland if (ret)
554b828f960SMark Rutland goto out_cpuhp;
555b828f960SMark Rutland
556b828f960SMark Rutland return 0;
557b828f960SMark Rutland
558b828f960SMark Rutland out_cpuhp:
559b828f960SMark Rutland cpuhp_remove_state_nocalls(CPUHP_AP_PERF_ARM_L2X0_ONLINE);
560b828f960SMark Rutland out_pmu:
561b828f960SMark Rutland kfree(l2x0_pmu);
562b828f960SMark Rutland l2x0_pmu = NULL;
563b828f960SMark Rutland return ret;
564b828f960SMark Rutland }
565b828f960SMark Rutland device_initcall(l2x0_pmu_init);
566