xref: /openbmc/linux/tools/lib/perf/mmap.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
13ce311afSJiri Olsa // SPDX-License-Identifier: GPL-2.0
23ce311afSJiri Olsa #include <sys/mman.h>
33ce311afSJiri Olsa #include <inttypes.h>
43ce311afSJiri Olsa #include <asm/bug.h>
53ce311afSJiri Olsa #include <errno.h>
63ce311afSJiri Olsa #include <string.h>
73ce311afSJiri Olsa #include <linux/ring_buffer.h>
83ce311afSJiri Olsa #include <linux/perf_event.h>
93ce311afSJiri Olsa #include <perf/mmap.h>
103ce311afSJiri Olsa #include <perf/event.h>
1147d01e7bSRob Herring #include <perf/evsel.h>
123ce311afSJiri Olsa #include <internal/mmap.h>
133ce311afSJiri Olsa #include <internal/lib.h>
143ce311afSJiri Olsa #include <linux/kernel.h>
1547d01e7bSRob Herring #include <linux/math64.h>
16407eb43aSRob Herring #include <linux/stringify.h>
173ce311afSJiri Olsa #include "internal.h"
183ce311afSJiri Olsa 
perf_mmap__init(struct perf_mmap * map,struct perf_mmap * prev,bool overwrite,libperf_unmap_cb_t unmap_cb)193ce311afSJiri Olsa void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
203ce311afSJiri Olsa 		     bool overwrite, libperf_unmap_cb_t unmap_cb)
213ce311afSJiri Olsa {
223ce311afSJiri Olsa 	map->fd = -1;
233ce311afSJiri Olsa 	map->overwrite = overwrite;
243ce311afSJiri Olsa 	map->unmap_cb  = unmap_cb;
253ce311afSJiri Olsa 	refcount_set(&map->refcnt, 0);
263ce311afSJiri Olsa 	if (prev)
273ce311afSJiri Olsa 		prev->next = map;
283ce311afSJiri Olsa }
293ce311afSJiri Olsa 
perf_mmap__mmap_len(struct perf_mmap * map)303ce311afSJiri Olsa size_t perf_mmap__mmap_len(struct perf_mmap *map)
313ce311afSJiri Olsa {
323ce311afSJiri Olsa 	return map->mask + 1 + page_size;
333ce311afSJiri Olsa }
343ce311afSJiri Olsa 
perf_mmap__mmap(struct perf_mmap * map,struct perf_mmap_param * mp,int fd,struct perf_cpu cpu)353ce311afSJiri Olsa int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
366d18804bSIan Rogers 		    int fd, struct perf_cpu cpu)
373ce311afSJiri Olsa {
383ce311afSJiri Olsa 	map->prev = 0;
393ce311afSJiri Olsa 	map->mask = mp->mask;
403ce311afSJiri Olsa 	map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot,
413ce311afSJiri Olsa 			 MAP_SHARED, fd, 0);
423ce311afSJiri Olsa 	if (map->base == MAP_FAILED) {
433ce311afSJiri Olsa 		map->base = NULL;
443ce311afSJiri Olsa 		return -1;
453ce311afSJiri Olsa 	}
463ce311afSJiri Olsa 
473ce311afSJiri Olsa 	map->fd  = fd;
483ce311afSJiri Olsa 	map->cpu = cpu;
493ce311afSJiri Olsa 	return 0;
503ce311afSJiri Olsa }
513ce311afSJiri Olsa 
perf_mmap__munmap(struct perf_mmap * map)523ce311afSJiri Olsa void perf_mmap__munmap(struct perf_mmap *map)
533ce311afSJiri Olsa {
543ce311afSJiri Olsa 	if (map && map->base != NULL) {
553ce311afSJiri Olsa 		munmap(map->base, perf_mmap__mmap_len(map));
563ce311afSJiri Olsa 		map->base = NULL;
573ce311afSJiri Olsa 		map->fd = -1;
583ce311afSJiri Olsa 		refcount_set(&map->refcnt, 0);
593ce311afSJiri Olsa 	}
603ce311afSJiri Olsa 	if (map && map->unmap_cb)
613ce311afSJiri Olsa 		map->unmap_cb(map);
623ce311afSJiri Olsa }
633ce311afSJiri Olsa 
perf_mmap__get(struct perf_mmap * map)643ce311afSJiri Olsa void perf_mmap__get(struct perf_mmap *map)
653ce311afSJiri Olsa {
663ce311afSJiri Olsa 	refcount_inc(&map->refcnt);
673ce311afSJiri Olsa }
683ce311afSJiri Olsa 
perf_mmap__put(struct perf_mmap * map)693ce311afSJiri Olsa void perf_mmap__put(struct perf_mmap *map)
703ce311afSJiri Olsa {
713ce311afSJiri Olsa 	BUG_ON(map->base && refcount_read(&map->refcnt) == 0);
723ce311afSJiri Olsa 
733ce311afSJiri Olsa 	if (refcount_dec_and_test(&map->refcnt))
743ce311afSJiri Olsa 		perf_mmap__munmap(map);
753ce311afSJiri Olsa }
763ce311afSJiri Olsa 
perf_mmap__write_tail(struct perf_mmap * md,u64 tail)773ce311afSJiri Olsa static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail)
783ce311afSJiri Olsa {
793ce311afSJiri Olsa 	ring_buffer_write_tail(md->base, tail);
803ce311afSJiri Olsa }
813ce311afSJiri Olsa 
perf_mmap__read_head(struct perf_mmap * map)823ce311afSJiri Olsa u64 perf_mmap__read_head(struct perf_mmap *map)
833ce311afSJiri Olsa {
843ce311afSJiri Olsa 	return ring_buffer_read_head(map->base);
853ce311afSJiri Olsa }
863ce311afSJiri Olsa 
perf_mmap__empty(struct perf_mmap * map)873ce311afSJiri Olsa static bool perf_mmap__empty(struct perf_mmap *map)
883ce311afSJiri Olsa {
893ce311afSJiri Olsa 	struct perf_event_mmap_page *pc = map->base;
903ce311afSJiri Olsa 
913ce311afSJiri Olsa 	return perf_mmap__read_head(map) == map->prev && !pc->aux_size;
923ce311afSJiri Olsa }
933ce311afSJiri Olsa 
perf_mmap__consume(struct perf_mmap * map)943ce311afSJiri Olsa void perf_mmap__consume(struct perf_mmap *map)
953ce311afSJiri Olsa {
963ce311afSJiri Olsa 	if (!map->overwrite) {
973ce311afSJiri Olsa 		u64 old = map->prev;
983ce311afSJiri Olsa 
993ce311afSJiri Olsa 		perf_mmap__write_tail(map, old);
1003ce311afSJiri Olsa 	}
1013ce311afSJiri Olsa 
1023ce311afSJiri Olsa 	if (refcount_read(&map->refcnt) == 1 && perf_mmap__empty(map))
1033ce311afSJiri Olsa 		perf_mmap__put(map);
1043ce311afSJiri Olsa }
1053ce311afSJiri Olsa 
overwrite_rb_find_range(void * buf,int mask,u64 * start,u64 * end)1063ce311afSJiri Olsa static int overwrite_rb_find_range(void *buf, int mask, u64 *start, u64 *end)
1073ce311afSJiri Olsa {
1083ce311afSJiri Olsa 	struct perf_event_header *pheader;
1093ce311afSJiri Olsa 	u64 evt_head = *start;
1103ce311afSJiri Olsa 	int size = mask + 1;
1113ce311afSJiri Olsa 
1123ce311afSJiri Olsa 	pr_debug2("%s: buf=%p, start=%"PRIx64"\n", __func__, buf, *start);
1133ce311afSJiri Olsa 	pheader = (struct perf_event_header *)(buf + (*start & mask));
1143ce311afSJiri Olsa 	while (true) {
1153ce311afSJiri Olsa 		if (evt_head - *start >= (unsigned int)size) {
1163ce311afSJiri Olsa 			pr_debug("Finished reading overwrite ring buffer: rewind\n");
1173ce311afSJiri Olsa 			if (evt_head - *start > (unsigned int)size)
1183ce311afSJiri Olsa 				evt_head -= pheader->size;
1193ce311afSJiri Olsa 			*end = evt_head;
1203ce311afSJiri Olsa 			return 0;
1213ce311afSJiri Olsa 		}
1223ce311afSJiri Olsa 
1233ce311afSJiri Olsa 		pheader = (struct perf_event_header *)(buf + (evt_head & mask));
1243ce311afSJiri Olsa 
1253ce311afSJiri Olsa 		if (pheader->size == 0) {
1263ce311afSJiri Olsa 			pr_debug("Finished reading overwrite ring buffer: get start\n");
1273ce311afSJiri Olsa 			*end = evt_head;
1283ce311afSJiri Olsa 			return 0;
1293ce311afSJiri Olsa 		}
1303ce311afSJiri Olsa 
1313ce311afSJiri Olsa 		evt_head += pheader->size;
1323ce311afSJiri Olsa 		pr_debug3("move evt_head: %"PRIx64"\n", evt_head);
1333ce311afSJiri Olsa 	}
1343ce311afSJiri Olsa 	WARN_ONCE(1, "Shouldn't get here\n");
1353ce311afSJiri Olsa 	return -1;
1363ce311afSJiri Olsa }
1373ce311afSJiri Olsa 
1383ce311afSJiri Olsa /*
1393ce311afSJiri Olsa  * Report the start and end of the available data in ringbuffer
1403ce311afSJiri Olsa  */
__perf_mmap__read_init(struct perf_mmap * md)1413ce311afSJiri Olsa static int __perf_mmap__read_init(struct perf_mmap *md)
1423ce311afSJiri Olsa {
1433ce311afSJiri Olsa 	u64 head = perf_mmap__read_head(md);
1443ce311afSJiri Olsa 	u64 old = md->prev;
1453ce311afSJiri Olsa 	unsigned char *data = md->base + page_size;
1463ce311afSJiri Olsa 	unsigned long size;
1473ce311afSJiri Olsa 
1483ce311afSJiri Olsa 	md->start = md->overwrite ? head : old;
1493ce311afSJiri Olsa 	md->end = md->overwrite ? old : head;
1503ce311afSJiri Olsa 
1513ce311afSJiri Olsa 	if ((md->end - md->start) < md->flush)
1523ce311afSJiri Olsa 		return -EAGAIN;
1533ce311afSJiri Olsa 
1543ce311afSJiri Olsa 	size = md->end - md->start;
1553ce311afSJiri Olsa 	if (size > (unsigned long)(md->mask) + 1) {
1563ce311afSJiri Olsa 		if (!md->overwrite) {
1573ce311afSJiri Olsa 			WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
1583ce311afSJiri Olsa 
1593ce311afSJiri Olsa 			md->prev = head;
1603ce311afSJiri Olsa 			perf_mmap__consume(md);
1613ce311afSJiri Olsa 			return -EAGAIN;
1623ce311afSJiri Olsa 		}
1633ce311afSJiri Olsa 
1643ce311afSJiri Olsa 		/*
1653ce311afSJiri Olsa 		 * Backward ring buffer is full. We still have a chance to read
1663ce311afSJiri Olsa 		 * most of data from it.
1673ce311afSJiri Olsa 		 */
1683ce311afSJiri Olsa 		if (overwrite_rb_find_range(data, md->mask, &md->start, &md->end))
1693ce311afSJiri Olsa 			return -EINVAL;
1703ce311afSJiri Olsa 	}
1713ce311afSJiri Olsa 
1723ce311afSJiri Olsa 	return 0;
1733ce311afSJiri Olsa }
1743ce311afSJiri Olsa 
perf_mmap__read_init(struct perf_mmap * map)1753ce311afSJiri Olsa int perf_mmap__read_init(struct perf_mmap *map)
1763ce311afSJiri Olsa {
1773ce311afSJiri Olsa 	/*
1783ce311afSJiri Olsa 	 * Check if event was unmapped due to a POLLHUP/POLLERR.
1793ce311afSJiri Olsa 	 */
1803ce311afSJiri Olsa 	if (!refcount_read(&map->refcnt))
1813ce311afSJiri Olsa 		return -ENOENT;
1823ce311afSJiri Olsa 
1833ce311afSJiri Olsa 	return __perf_mmap__read_init(map);
1843ce311afSJiri Olsa }
1853ce311afSJiri Olsa 
1863ce311afSJiri Olsa /*
1873ce311afSJiri Olsa  * Mandatory for overwrite mode
1883ce311afSJiri Olsa  * The direction of overwrite mode is backward.
1893ce311afSJiri Olsa  * The last perf_mmap__read() will set tail to map->core.prev.
1903ce311afSJiri Olsa  * Need to correct the map->core.prev to head which is the end of next read.
1913ce311afSJiri Olsa  */
perf_mmap__read_done(struct perf_mmap * map)1923ce311afSJiri Olsa void perf_mmap__read_done(struct perf_mmap *map)
1933ce311afSJiri Olsa {
1943ce311afSJiri Olsa 	/*
1953ce311afSJiri Olsa 	 * Check if event was unmapped due to a POLLHUP/POLLERR.
1963ce311afSJiri Olsa 	 */
1973ce311afSJiri Olsa 	if (!refcount_read(&map->refcnt))
1983ce311afSJiri Olsa 		return;
1993ce311afSJiri Olsa 
2003ce311afSJiri Olsa 	map->prev = perf_mmap__read_head(map);
2013ce311afSJiri Olsa }
2023ce311afSJiri Olsa 
2033ce311afSJiri Olsa /* When check_messup is true, 'end' must points to a good entry */
perf_mmap__read(struct perf_mmap * map,u64 * startp,u64 end)2043ce311afSJiri Olsa static union perf_event *perf_mmap__read(struct perf_mmap *map,
2053ce311afSJiri Olsa 					 u64 *startp, u64 end)
2063ce311afSJiri Olsa {
2073ce311afSJiri Olsa 	unsigned char *data = map->base + page_size;
2083ce311afSJiri Olsa 	union perf_event *event = NULL;
2093ce311afSJiri Olsa 	int diff = end - *startp;
2103ce311afSJiri Olsa 
2113ce311afSJiri Olsa 	if (diff >= (int)sizeof(event->header)) {
2123ce311afSJiri Olsa 		size_t size;
2133ce311afSJiri Olsa 
2143ce311afSJiri Olsa 		event = (union perf_event *)&data[*startp & map->mask];
2153ce311afSJiri Olsa 		size = event->header.size;
2163ce311afSJiri Olsa 
2173ce311afSJiri Olsa 		if (size < sizeof(event->header) || diff < (int)size)
2183ce311afSJiri Olsa 			return NULL;
2193ce311afSJiri Olsa 
2203ce311afSJiri Olsa 		/*
2213ce311afSJiri Olsa 		 * Event straddles the mmap boundary -- header should always
2223ce311afSJiri Olsa 		 * be inside due to u64 alignment of output.
2233ce311afSJiri Olsa 		 */
2243ce311afSJiri Olsa 		if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) {
2253ce311afSJiri Olsa 			unsigned int offset = *startp;
2263ce311afSJiri Olsa 			unsigned int len = min(sizeof(*event), size), cpy;
2273ce311afSJiri Olsa 			void *dst = map->event_copy;
2283ce311afSJiri Olsa 
2293ce311afSJiri Olsa 			do {
2303ce311afSJiri Olsa 				cpy = min(map->mask + 1 - (offset & map->mask), len);
2313ce311afSJiri Olsa 				memcpy(dst, &data[offset & map->mask], cpy);
2323ce311afSJiri Olsa 				offset += cpy;
2333ce311afSJiri Olsa 				dst += cpy;
2343ce311afSJiri Olsa 				len -= cpy;
2353ce311afSJiri Olsa 			} while (len);
2363ce311afSJiri Olsa 
2373ce311afSJiri Olsa 			event = (union perf_event *)map->event_copy;
2383ce311afSJiri Olsa 		}
2393ce311afSJiri Olsa 
2403ce311afSJiri Olsa 		*startp += size;
2413ce311afSJiri Olsa 	}
2423ce311afSJiri Olsa 
2433ce311afSJiri Olsa 	return event;
2443ce311afSJiri Olsa }
2453ce311afSJiri Olsa 
2463ce311afSJiri Olsa /*
2473ce311afSJiri Olsa  * Read event from ring buffer one by one.
2483ce311afSJiri Olsa  * Return one event for each call.
2493ce311afSJiri Olsa  *
2503ce311afSJiri Olsa  * Usage:
2513ce311afSJiri Olsa  * perf_mmap__read_init()
2523ce311afSJiri Olsa  * while(event = perf_mmap__read_event()) {
2533ce311afSJiri Olsa  *	//process the event
2543ce311afSJiri Olsa  *	perf_mmap__consume()
2553ce311afSJiri Olsa  * }
2563ce311afSJiri Olsa  * perf_mmap__read_done()
2573ce311afSJiri Olsa  */
perf_mmap__read_event(struct perf_mmap * map)2583ce311afSJiri Olsa union perf_event *perf_mmap__read_event(struct perf_mmap *map)
2593ce311afSJiri Olsa {
2603ce311afSJiri Olsa 	union perf_event *event;
2613ce311afSJiri Olsa 
2623ce311afSJiri Olsa 	/*
2633ce311afSJiri Olsa 	 * Check if event was unmapped due to a POLLHUP/POLLERR.
2643ce311afSJiri Olsa 	 */
2653ce311afSJiri Olsa 	if (!refcount_read(&map->refcnt))
2663ce311afSJiri Olsa 		return NULL;
2673ce311afSJiri Olsa 
2683ce311afSJiri Olsa 	/* non-overwirte doesn't pause the ringbuffer */
2693ce311afSJiri Olsa 	if (!map->overwrite)
2703ce311afSJiri Olsa 		map->end = perf_mmap__read_head(map);
2713ce311afSJiri Olsa 
2723ce311afSJiri Olsa 	event = perf_mmap__read(map, &map->start, map->end);
2733ce311afSJiri Olsa 
2743ce311afSJiri Olsa 	if (!map->overwrite)
2753ce311afSJiri Olsa 		map->prev = map->start;
2763ce311afSJiri Olsa 
2773ce311afSJiri Olsa 	return event;
2783ce311afSJiri Olsa }
27947d01e7bSRob Herring 
28047d01e7bSRob Herring #if defined(__i386__) || defined(__x86_64__)
read_perf_counter(unsigned int counter)28147d01e7bSRob Herring static u64 read_perf_counter(unsigned int counter)
28247d01e7bSRob Herring {
28347d01e7bSRob Herring 	unsigned int low, high;
28447d01e7bSRob Herring 
28547d01e7bSRob Herring 	asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
28647d01e7bSRob Herring 
28747d01e7bSRob Herring 	return low | ((u64)high) << 32;
28847d01e7bSRob Herring }
28947d01e7bSRob Herring 
read_timestamp(void)29047d01e7bSRob Herring static u64 read_timestamp(void)
29147d01e7bSRob Herring {
29247d01e7bSRob Herring 	unsigned int low, high;
29347d01e7bSRob Herring 
29447d01e7bSRob Herring 	asm volatile("rdtsc" : "=a" (low), "=d" (high));
29547d01e7bSRob Herring 
29647d01e7bSRob Herring 	return low | ((u64)high) << 32;
29747d01e7bSRob Herring }
298407eb43aSRob Herring #elif defined(__aarch64__)
299407eb43aSRob Herring #define read_sysreg(r) ({						\
300407eb43aSRob Herring 	u64 __val;							\
301407eb43aSRob Herring 	asm volatile("mrs %0, " __stringify(r) : "=r" (__val));		\
302407eb43aSRob Herring 	__val;								\
303407eb43aSRob Herring })
304407eb43aSRob Herring 
read_pmccntr(void)305407eb43aSRob Herring static u64 read_pmccntr(void)
306407eb43aSRob Herring {
307407eb43aSRob Herring 	return read_sysreg(pmccntr_el0);
308407eb43aSRob Herring }
309407eb43aSRob Herring 
310407eb43aSRob Herring #define PMEVCNTR_READ(idx)					\
311407eb43aSRob Herring 	static u64 read_pmevcntr_##idx(void) {			\
312407eb43aSRob Herring 		return read_sysreg(pmevcntr##idx##_el0);	\
313407eb43aSRob Herring 	}
314407eb43aSRob Herring 
315407eb43aSRob Herring PMEVCNTR_READ(0);
316407eb43aSRob Herring PMEVCNTR_READ(1);
317407eb43aSRob Herring PMEVCNTR_READ(2);
318407eb43aSRob Herring PMEVCNTR_READ(3);
319407eb43aSRob Herring PMEVCNTR_READ(4);
320407eb43aSRob Herring PMEVCNTR_READ(5);
321407eb43aSRob Herring PMEVCNTR_READ(6);
322407eb43aSRob Herring PMEVCNTR_READ(7);
323407eb43aSRob Herring PMEVCNTR_READ(8);
324407eb43aSRob Herring PMEVCNTR_READ(9);
325407eb43aSRob Herring PMEVCNTR_READ(10);
326407eb43aSRob Herring PMEVCNTR_READ(11);
327407eb43aSRob Herring PMEVCNTR_READ(12);
328407eb43aSRob Herring PMEVCNTR_READ(13);
329407eb43aSRob Herring PMEVCNTR_READ(14);
330407eb43aSRob Herring PMEVCNTR_READ(15);
331407eb43aSRob Herring PMEVCNTR_READ(16);
332407eb43aSRob Herring PMEVCNTR_READ(17);
333407eb43aSRob Herring PMEVCNTR_READ(18);
334407eb43aSRob Herring PMEVCNTR_READ(19);
335407eb43aSRob Herring PMEVCNTR_READ(20);
336407eb43aSRob Herring PMEVCNTR_READ(21);
337407eb43aSRob Herring PMEVCNTR_READ(22);
338407eb43aSRob Herring PMEVCNTR_READ(23);
339407eb43aSRob Herring PMEVCNTR_READ(24);
340407eb43aSRob Herring PMEVCNTR_READ(25);
341407eb43aSRob Herring PMEVCNTR_READ(26);
342407eb43aSRob Herring PMEVCNTR_READ(27);
343407eb43aSRob Herring PMEVCNTR_READ(28);
344407eb43aSRob Herring PMEVCNTR_READ(29);
345407eb43aSRob Herring PMEVCNTR_READ(30);
346407eb43aSRob Herring 
347407eb43aSRob Herring /*
348407eb43aSRob Herring  * Read a value direct from PMEVCNTR<idx>
349407eb43aSRob Herring  */
read_perf_counter(unsigned int counter)350407eb43aSRob Herring static u64 read_perf_counter(unsigned int counter)
351407eb43aSRob Herring {
352407eb43aSRob Herring 	static u64 (* const read_f[])(void) = {
353407eb43aSRob Herring 		read_pmevcntr_0,
354407eb43aSRob Herring 		read_pmevcntr_1,
355407eb43aSRob Herring 		read_pmevcntr_2,
356407eb43aSRob Herring 		read_pmevcntr_3,
357407eb43aSRob Herring 		read_pmevcntr_4,
358407eb43aSRob Herring 		read_pmevcntr_5,
359407eb43aSRob Herring 		read_pmevcntr_6,
360407eb43aSRob Herring 		read_pmevcntr_7,
361407eb43aSRob Herring 		read_pmevcntr_8,
362407eb43aSRob Herring 		read_pmevcntr_9,
363407eb43aSRob Herring 		read_pmevcntr_10,
364407eb43aSRob Herring 		read_pmevcntr_11,
365407eb43aSRob Herring 		read_pmevcntr_13,
366407eb43aSRob Herring 		read_pmevcntr_12,
367407eb43aSRob Herring 		read_pmevcntr_14,
368407eb43aSRob Herring 		read_pmevcntr_15,
369407eb43aSRob Herring 		read_pmevcntr_16,
370407eb43aSRob Herring 		read_pmevcntr_17,
371407eb43aSRob Herring 		read_pmevcntr_18,
372407eb43aSRob Herring 		read_pmevcntr_19,
373407eb43aSRob Herring 		read_pmevcntr_20,
374407eb43aSRob Herring 		read_pmevcntr_21,
375407eb43aSRob Herring 		read_pmevcntr_22,
376407eb43aSRob Herring 		read_pmevcntr_23,
377407eb43aSRob Herring 		read_pmevcntr_24,
378407eb43aSRob Herring 		read_pmevcntr_25,
379407eb43aSRob Herring 		read_pmevcntr_26,
380407eb43aSRob Herring 		read_pmevcntr_27,
381407eb43aSRob Herring 		read_pmevcntr_28,
382407eb43aSRob Herring 		read_pmevcntr_29,
383407eb43aSRob Herring 		read_pmevcntr_30,
384407eb43aSRob Herring 		read_pmccntr
385407eb43aSRob Herring 	};
386407eb43aSRob Herring 
387407eb43aSRob Herring 	if (counter < ARRAY_SIZE(read_f))
388407eb43aSRob Herring 		return (read_f[counter])();
389407eb43aSRob Herring 
390407eb43aSRob Herring 	return 0;
391407eb43aSRob Herring }
392407eb43aSRob Herring 
read_timestamp(void)393407eb43aSRob Herring static u64 read_timestamp(void) { return read_sysreg(cntvct_el0); }
394407eb43aSRob Herring 
395*60bd5011SAlexandre Ghiti /* __riscv_xlen contains the witdh of the native base integer, here 64-bit */
396*60bd5011SAlexandre Ghiti #elif defined(__riscv) && __riscv_xlen == 64
397*60bd5011SAlexandre Ghiti 
398*60bd5011SAlexandre Ghiti /* TODO: implement rv32 support */
399*60bd5011SAlexandre Ghiti 
400*60bd5011SAlexandre Ghiti #define CSR_CYCLE	0xc00
401*60bd5011SAlexandre Ghiti #define CSR_TIME	0xc01
402*60bd5011SAlexandre Ghiti 
403*60bd5011SAlexandre Ghiti #define csr_read(csr)						\
404*60bd5011SAlexandre Ghiti ({								\
405*60bd5011SAlexandre Ghiti 	register unsigned long __v;				\
406*60bd5011SAlexandre Ghiti 		__asm__ __volatile__ ("csrr %0, %1"		\
407*60bd5011SAlexandre Ghiti 		 : "=r" (__v)					\
408*60bd5011SAlexandre Ghiti 		 : "i" (csr) : );				\
409*60bd5011SAlexandre Ghiti 		 __v;						\
410*60bd5011SAlexandre Ghiti })
411*60bd5011SAlexandre Ghiti 
csr_read_num(int csr_num)412*60bd5011SAlexandre Ghiti static unsigned long csr_read_num(int csr_num)
413*60bd5011SAlexandre Ghiti {
414*60bd5011SAlexandre Ghiti #define switchcase_csr_read(__csr_num, __val)           {\
415*60bd5011SAlexandre Ghiti 	case __csr_num:                                 \
416*60bd5011SAlexandre Ghiti 		__val = csr_read(__csr_num);            \
417*60bd5011SAlexandre Ghiti 		break; }
418*60bd5011SAlexandre Ghiti #define switchcase_csr_read_2(__csr_num, __val)         {\
419*60bd5011SAlexandre Ghiti 	switchcase_csr_read(__csr_num + 0, __val)        \
420*60bd5011SAlexandre Ghiti 	switchcase_csr_read(__csr_num + 1, __val)}
421*60bd5011SAlexandre Ghiti #define switchcase_csr_read_4(__csr_num, __val)         {\
422*60bd5011SAlexandre Ghiti 	switchcase_csr_read_2(__csr_num + 0, __val)      \
423*60bd5011SAlexandre Ghiti 	switchcase_csr_read_2(__csr_num + 2, __val)}
424*60bd5011SAlexandre Ghiti #define switchcase_csr_read_8(__csr_num, __val)         {\
425*60bd5011SAlexandre Ghiti 	switchcase_csr_read_4(__csr_num + 0, __val)      \
426*60bd5011SAlexandre Ghiti 	switchcase_csr_read_4(__csr_num + 4, __val)}
427*60bd5011SAlexandre Ghiti #define switchcase_csr_read_16(__csr_num, __val)        {\
428*60bd5011SAlexandre Ghiti 	switchcase_csr_read_8(__csr_num + 0, __val)      \
429*60bd5011SAlexandre Ghiti 	switchcase_csr_read_8(__csr_num + 8, __val)}
430*60bd5011SAlexandre Ghiti #define switchcase_csr_read_32(__csr_num, __val)        {\
431*60bd5011SAlexandre Ghiti 	switchcase_csr_read_16(__csr_num + 0, __val)     \
432*60bd5011SAlexandre Ghiti 	switchcase_csr_read_16(__csr_num + 16, __val)}
433*60bd5011SAlexandre Ghiti 
434*60bd5011SAlexandre Ghiti 	unsigned long ret = 0;
435*60bd5011SAlexandre Ghiti 
436*60bd5011SAlexandre Ghiti 	switch (csr_num) {
437*60bd5011SAlexandre Ghiti 	switchcase_csr_read_32(CSR_CYCLE, ret)
438*60bd5011SAlexandre Ghiti 	default:
439*60bd5011SAlexandre Ghiti 		break;
440*60bd5011SAlexandre Ghiti 	}
441*60bd5011SAlexandre Ghiti 
442*60bd5011SAlexandre Ghiti 	return ret;
443*60bd5011SAlexandre Ghiti #undef switchcase_csr_read_32
444*60bd5011SAlexandre Ghiti #undef switchcase_csr_read_16
445*60bd5011SAlexandre Ghiti #undef switchcase_csr_read_8
446*60bd5011SAlexandre Ghiti #undef switchcase_csr_read_4
447*60bd5011SAlexandre Ghiti #undef switchcase_csr_read_2
448*60bd5011SAlexandre Ghiti #undef switchcase_csr_read
449*60bd5011SAlexandre Ghiti }
450*60bd5011SAlexandre Ghiti 
read_perf_counter(unsigned int counter)451*60bd5011SAlexandre Ghiti static u64 read_perf_counter(unsigned int counter)
452*60bd5011SAlexandre Ghiti {
453*60bd5011SAlexandre Ghiti 	return csr_read_num(CSR_CYCLE + counter);
454*60bd5011SAlexandre Ghiti }
455*60bd5011SAlexandre Ghiti 
read_timestamp(void)456*60bd5011SAlexandre Ghiti static u64 read_timestamp(void)
457*60bd5011SAlexandre Ghiti {
458*60bd5011SAlexandre Ghiti 	return csr_read_num(CSR_TIME);
459*60bd5011SAlexandre Ghiti }
460*60bd5011SAlexandre Ghiti 
46147d01e7bSRob Herring #else
read_perf_counter(unsigned int counter __maybe_unused)46247d01e7bSRob Herring static u64 read_perf_counter(unsigned int counter __maybe_unused) { return 0; }
read_timestamp(void)46347d01e7bSRob Herring static u64 read_timestamp(void) { return 0; }
46447d01e7bSRob Herring #endif
46547d01e7bSRob Herring 
perf_mmap__read_self(struct perf_mmap * map,struct perf_counts_values * count)46647d01e7bSRob Herring int perf_mmap__read_self(struct perf_mmap *map, struct perf_counts_values *count)
46747d01e7bSRob Herring {
46847d01e7bSRob Herring 	struct perf_event_mmap_page *pc = map->base;
46947d01e7bSRob Herring 	u32 seq, idx, time_mult = 0, time_shift = 0;
47047d01e7bSRob Herring 	u64 cnt, cyc = 0, time_offset = 0, time_cycles = 0, time_mask = ~0ULL;
47147d01e7bSRob Herring 
47247d01e7bSRob Herring 	if (!pc || !pc->cap_user_rdpmc)
47347d01e7bSRob Herring 		return -1;
47447d01e7bSRob Herring 
47547d01e7bSRob Herring 	do {
47647d01e7bSRob Herring 		seq = READ_ONCE(pc->lock);
47747d01e7bSRob Herring 		barrier();
47847d01e7bSRob Herring 
47947d01e7bSRob Herring 		count->ena = READ_ONCE(pc->time_enabled);
48047d01e7bSRob Herring 		count->run = READ_ONCE(pc->time_running);
48147d01e7bSRob Herring 
48247d01e7bSRob Herring 		if (pc->cap_user_time && count->ena != count->run) {
48347d01e7bSRob Herring 			cyc = read_timestamp();
48447d01e7bSRob Herring 			time_mult = READ_ONCE(pc->time_mult);
48547d01e7bSRob Herring 			time_shift = READ_ONCE(pc->time_shift);
48647d01e7bSRob Herring 			time_offset = READ_ONCE(pc->time_offset);
48747d01e7bSRob Herring 
48847d01e7bSRob Herring 			if (pc->cap_user_time_short) {
48947d01e7bSRob Herring 				time_cycles = READ_ONCE(pc->time_cycles);
49047d01e7bSRob Herring 				time_mask = READ_ONCE(pc->time_mask);
49147d01e7bSRob Herring 			}
49247d01e7bSRob Herring 		}
49347d01e7bSRob Herring 
49447d01e7bSRob Herring 		idx = READ_ONCE(pc->index);
49547d01e7bSRob Herring 		cnt = READ_ONCE(pc->offset);
49647d01e7bSRob Herring 		if (pc->cap_user_rdpmc && idx) {
49747d01e7bSRob Herring 			s64 evcnt = read_perf_counter(idx - 1);
49847d01e7bSRob Herring 			u16 width = READ_ONCE(pc->pmc_width);
49947d01e7bSRob Herring 
50047d01e7bSRob Herring 			evcnt <<= 64 - width;
50147d01e7bSRob Herring 			evcnt >>= 64 - width;
50247d01e7bSRob Herring 			cnt += evcnt;
50347d01e7bSRob Herring 		} else
50447d01e7bSRob Herring 			return -1;
50547d01e7bSRob Herring 
50647d01e7bSRob Herring 		barrier();
50747d01e7bSRob Herring 	} while (READ_ONCE(pc->lock) != seq);
50847d01e7bSRob Herring 
50947d01e7bSRob Herring 	if (count->ena != count->run) {
51047d01e7bSRob Herring 		u64 delta;
51147d01e7bSRob Herring 
51247d01e7bSRob Herring 		/* Adjust for cap_usr_time_short, a nop if not */
51347d01e7bSRob Herring 		cyc = time_cycles + ((cyc - time_cycles) & time_mask);
51447d01e7bSRob Herring 
51547d01e7bSRob Herring 		delta = time_offset + mul_u64_u32_shr(cyc, time_mult, time_shift);
51647d01e7bSRob Herring 
51747d01e7bSRob Herring 		count->ena += delta;
51847d01e7bSRob Herring 		if (idx)
51947d01e7bSRob Herring 			count->run += delta;
52047d01e7bSRob Herring 	}
52147d01e7bSRob Herring 
52247d01e7bSRob Herring 	count->val = cnt;
52347d01e7bSRob Herring 
52447d01e7bSRob Herring 	return 0;
52547d01e7bSRob Herring }
526