xref: /openbmc/linux/tools/testing/selftests/powerpc/utils.c (revision 5c20de57888f0962e25a0eeec1a59c98056fc42e)
1f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fcb45ec0SMichael Ellerman /*
3fcb45ec0SMichael Ellerman  * Copyright 2013-2015, Michael Ellerman, IBM Corp.
4fcb45ec0SMichael Ellerman  */
5fcb45ec0SMichael Ellerman 
6d1301afdSMichael Ellerman #define _GNU_SOURCE	/* For CPU_ZERO etc. */
7d1301afdSMichael Ellerman 
8fcb45ec0SMichael Ellerman #include <elf.h>
9fcb45ec0SMichael Ellerman #include <errno.h>
10fcb45ec0SMichael Ellerman #include <fcntl.h>
11d1bc05b7SBenjamin Gray #include <inttypes.h>
12d1bc05b7SBenjamin Gray #include <limits.h>
13fcb45ec0SMichael Ellerman #include <link.h>
14d1301afdSMichael Ellerman #include <sched.h>
15fcb45ec0SMichael Ellerman #include <stdio.h>
16d2bf7932SNaveen N. Rao #include <stdlib.h>
1795f9b3afSMichael Ellerman #include <string.h>
18d2bf7932SNaveen N. Rao #include <sys/ioctl.h>
19fcb45ec0SMichael Ellerman #include <sys/stat.h>
20dfa03fffSSandipan Das #include <sys/sysinfo.h>
21fcb45ec0SMichael Ellerman #include <sys/types.h>
2295f9b3afSMichael Ellerman #include <sys/utsname.h>
23fcb45ec0SMichael Ellerman #include <unistd.h>
24d2bf7932SNaveen N. Rao #include <asm/unistd.h>
25d2bf7932SNaveen N. Rao #include <linux/limits.h>
26fcb45ec0SMichael Ellerman 
27fcb45ec0SMichael Ellerman #include "utils.h"
28fcb45ec0SMichael Ellerman 
29fcb45ec0SMichael Ellerman static char auxv[4096];
30fcb45ec0SMichael Ellerman 
31a974f0c1SBenjamin Gray int read_file(const char *path, char *buf, size_t count, size_t *len)
32fcb45ec0SMichael Ellerman {
33a974f0c1SBenjamin Gray 	ssize_t rc;
34a974f0c1SBenjamin Gray 	int fd;
35a974f0c1SBenjamin Gray 	int err;
36a974f0c1SBenjamin Gray 	char eof;
37fcb45ec0SMichael Ellerman 
38a974f0c1SBenjamin Gray 	fd = open(path, O_RDONLY);
39a974f0c1SBenjamin Gray 	if (fd < 0)
40e3028437SMichael Ellerman 		return -errno;
41fcb45ec0SMichael Ellerman 
42a974f0c1SBenjamin Gray 	rc = read(fd, buf, count);
43a974f0c1SBenjamin Gray 	if (rc < 0) {
44a974f0c1SBenjamin Gray 		err = -errno;
45fcb45ec0SMichael Ellerman 		goto out;
46fcb45ec0SMichael Ellerman 	}
47fcb45ec0SMichael Ellerman 
48a974f0c1SBenjamin Gray 	if (len)
49a974f0c1SBenjamin Gray 		*len = rc;
50a974f0c1SBenjamin Gray 
51a974f0c1SBenjamin Gray 	/* Overflow if there are still more bytes after filling the buffer */
52a974f0c1SBenjamin Gray 	if (rc == count) {
53a974f0c1SBenjamin Gray 		rc = read(fd, &eof, 1);
54a974f0c1SBenjamin Gray 		if (rc != 0) {
55a974f0c1SBenjamin Gray 			err = -EOVERFLOW;
56fcb45ec0SMichael Ellerman 			goto out;
57fcb45ec0SMichael Ellerman 		}
58a974f0c1SBenjamin Gray 	}
59fcb45ec0SMichael Ellerman 
60a974f0c1SBenjamin Gray 	err = 0;
61a974f0c1SBenjamin Gray 
62e3028437SMichael Ellerman out:
63e3028437SMichael Ellerman 	close(fd);
64a974f0c1SBenjamin Gray 	errno = -err;
65a974f0c1SBenjamin Gray 	return err;
66a974f0c1SBenjamin Gray }
67a974f0c1SBenjamin Gray 
68a974f0c1SBenjamin Gray int write_file(const char *path, const char *buf, size_t count)
69a974f0c1SBenjamin Gray {
70a974f0c1SBenjamin Gray 	int fd;
71a974f0c1SBenjamin Gray 	int err;
72a974f0c1SBenjamin Gray 	ssize_t rc;
73a974f0c1SBenjamin Gray 
74a974f0c1SBenjamin Gray 	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
75a974f0c1SBenjamin Gray 	if (fd < 0)
76a974f0c1SBenjamin Gray 		return -errno;
77a974f0c1SBenjamin Gray 
78a974f0c1SBenjamin Gray 	rc = write(fd, buf, count);
79a974f0c1SBenjamin Gray 	if (rc < 0) {
80a974f0c1SBenjamin Gray 		err = -errno;
81a974f0c1SBenjamin Gray 		goto out;
82a974f0c1SBenjamin Gray 	}
83a974f0c1SBenjamin Gray 
84a974f0c1SBenjamin Gray 	if (rc != count) {
85a974f0c1SBenjamin Gray 		err = -EOVERFLOW;
86a974f0c1SBenjamin Gray 		goto out;
87a974f0c1SBenjamin Gray 	}
88a974f0c1SBenjamin Gray 
89a974f0c1SBenjamin Gray 	err = 0;
90a974f0c1SBenjamin Gray 
91a974f0c1SBenjamin Gray out:
92a974f0c1SBenjamin Gray 	close(fd);
93a974f0c1SBenjamin Gray 	errno = -err;
94a974f0c1SBenjamin Gray 	return err;
95a974f0c1SBenjamin Gray }
96a974f0c1SBenjamin Gray 
97a974f0c1SBenjamin Gray int read_auxv(char *buf, ssize_t buf_size)
98a974f0c1SBenjamin Gray {
99a974f0c1SBenjamin Gray 	int err;
100a974f0c1SBenjamin Gray 
101a974f0c1SBenjamin Gray 	err = read_file("/proc/self/auxv", buf, buf_size, NULL);
102a974f0c1SBenjamin Gray 	if (err) {
103a974f0c1SBenjamin Gray 		perror("Error reading /proc/self/auxv");
104a974f0c1SBenjamin Gray 		return err;
105a974f0c1SBenjamin Gray 	}
106a974f0c1SBenjamin Gray 
107a974f0c1SBenjamin Gray 	return 0;
108e3028437SMichael Ellerman }
109e3028437SMichael Ellerman 
110121d340bSBenjamin Gray int read_debugfs_file(const char *subpath, char *buf, size_t count)
111121d340bSBenjamin Gray {
112121d340bSBenjamin Gray 	char path[PATH_MAX] = "/sys/kernel/debug/";
113121d340bSBenjamin Gray 
114121d340bSBenjamin Gray 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
115121d340bSBenjamin Gray 
116121d340bSBenjamin Gray 	return read_file(path, buf, count, NULL);
117121d340bSBenjamin Gray }
118121d340bSBenjamin Gray 
119121d340bSBenjamin Gray int write_debugfs_file(const char *subpath, const char *buf, size_t count)
120121d340bSBenjamin Gray {
121121d340bSBenjamin Gray 	char path[PATH_MAX] = "/sys/kernel/debug/";
122121d340bSBenjamin Gray 
123121d340bSBenjamin Gray 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
124121d340bSBenjamin Gray 
125121d340bSBenjamin Gray 	return write_file(path, buf, count);
126121d340bSBenjamin Gray }
127121d340bSBenjamin Gray 
128d1bc05b7SBenjamin Gray static int validate_int_parse(const char *buffer, size_t count, char *end)
129d1bc05b7SBenjamin Gray {
130d1bc05b7SBenjamin Gray 	int err = 0;
131d1bc05b7SBenjamin Gray 
132d1bc05b7SBenjamin Gray 	/* Require at least one digit */
133d1bc05b7SBenjamin Gray 	if (end == buffer) {
134d1bc05b7SBenjamin Gray 		err = -EINVAL;
135d1bc05b7SBenjamin Gray 		goto out;
136d1bc05b7SBenjamin Gray 	}
137d1bc05b7SBenjamin Gray 
138d1bc05b7SBenjamin Gray 	/* Require all remaining characters be whitespace-ish */
139d1bc05b7SBenjamin Gray 	for (; end < buffer + count; end++) {
140d1bc05b7SBenjamin Gray 		if (*end == '\0')
141d1bc05b7SBenjamin Gray 			break;
142d1bc05b7SBenjamin Gray 
143d1bc05b7SBenjamin Gray 		if (*end != ' ' && *end != '\n') {
144d1bc05b7SBenjamin Gray 			err = -EINVAL;
145d1bc05b7SBenjamin Gray 			goto out;
146d1bc05b7SBenjamin Gray 		}
147d1bc05b7SBenjamin Gray 	}
148d1bc05b7SBenjamin Gray 
149d1bc05b7SBenjamin Gray out:
150d1bc05b7SBenjamin Gray 	errno = -err;
151d1bc05b7SBenjamin Gray 	return err;
152d1bc05b7SBenjamin Gray }
153d1bc05b7SBenjamin Gray 
154d1bc05b7SBenjamin Gray static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result,
155d1bc05b7SBenjamin Gray 			     int base, intmax_t min, intmax_t max)
156d1bc05b7SBenjamin Gray {
157d1bc05b7SBenjamin Gray 	int err;
158d1bc05b7SBenjamin Gray 	char *end;
159d1bc05b7SBenjamin Gray 
160d1bc05b7SBenjamin Gray 	errno = 0;
161d1bc05b7SBenjamin Gray 	*result = strtoimax(buffer, &end, base);
162d1bc05b7SBenjamin Gray 
163d1bc05b7SBenjamin Gray 	if (errno)
164d1bc05b7SBenjamin Gray 		return -errno;
165d1bc05b7SBenjamin Gray 
166d1bc05b7SBenjamin Gray 	err = validate_int_parse(buffer, count, end);
167d1bc05b7SBenjamin Gray 	if (err)
168d1bc05b7SBenjamin Gray 		goto out;
169d1bc05b7SBenjamin Gray 
170d1bc05b7SBenjamin Gray 	if (*result < min || *result > max)
171d1bc05b7SBenjamin Gray 		err = -EOVERFLOW;
172d1bc05b7SBenjamin Gray 
173d1bc05b7SBenjamin Gray out:
174d1bc05b7SBenjamin Gray 	errno = -err;
175d1bc05b7SBenjamin Gray 	return err;
176d1bc05b7SBenjamin Gray }
177d1bc05b7SBenjamin Gray 
178d1bc05b7SBenjamin Gray static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result,
179d1bc05b7SBenjamin Gray 			      int base, uintmax_t max)
180d1bc05b7SBenjamin Gray {
181d1bc05b7SBenjamin Gray 	int err = 0;
182d1bc05b7SBenjamin Gray 	char *end;
183d1bc05b7SBenjamin Gray 
184d1bc05b7SBenjamin Gray 	errno = 0;
185d1bc05b7SBenjamin Gray 	*result = strtoumax(buffer, &end, base);
186d1bc05b7SBenjamin Gray 
187d1bc05b7SBenjamin Gray 	if (errno)
188d1bc05b7SBenjamin Gray 		return -errno;
189d1bc05b7SBenjamin Gray 
190d1bc05b7SBenjamin Gray 	err = validate_int_parse(buffer, count, end);
191d1bc05b7SBenjamin Gray 	if (err)
192d1bc05b7SBenjamin Gray 		goto out;
193d1bc05b7SBenjamin Gray 
194d1bc05b7SBenjamin Gray 	if (*result > max)
195d1bc05b7SBenjamin Gray 		err = -EOVERFLOW;
196d1bc05b7SBenjamin Gray 
197d1bc05b7SBenjamin Gray out:
198d1bc05b7SBenjamin Gray 	errno = -err;
199d1bc05b7SBenjamin Gray 	return err;
200d1bc05b7SBenjamin Gray }
201d1bc05b7SBenjamin Gray 
202d1bc05b7SBenjamin Gray int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base)
203d1bc05b7SBenjamin Gray {
204d1bc05b7SBenjamin Gray 	return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);
205d1bc05b7SBenjamin Gray }
206d1bc05b7SBenjamin Gray 
207d1bc05b7SBenjamin Gray int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base)
208d1bc05b7SBenjamin Gray {
209d1bc05b7SBenjamin Gray 	return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);
210d1bc05b7SBenjamin Gray }
211d1bc05b7SBenjamin Gray 
212d1bc05b7SBenjamin Gray int parse_int(const char *buffer, size_t count, int *result, int base)
213d1bc05b7SBenjamin Gray {
214d1bc05b7SBenjamin Gray 	intmax_t parsed;
215d1bc05b7SBenjamin Gray 	int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
216d1bc05b7SBenjamin Gray 
217d1bc05b7SBenjamin Gray 	*result = parsed;
218d1bc05b7SBenjamin Gray 	return err;
219d1bc05b7SBenjamin Gray }
220d1bc05b7SBenjamin Gray 
221d1bc05b7SBenjamin Gray int parse_uint(const char *buffer, size_t count, unsigned int *result, int base)
222d1bc05b7SBenjamin Gray {
223d1bc05b7SBenjamin Gray 	uintmax_t parsed;
224d1bc05b7SBenjamin Gray 	int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
225d1bc05b7SBenjamin Gray 
226d1bc05b7SBenjamin Gray 	*result = parsed;
227d1bc05b7SBenjamin Gray 	return err;
228d1bc05b7SBenjamin Gray }
229d1bc05b7SBenjamin Gray 
230d1bc05b7SBenjamin Gray int parse_long(const char *buffer, size_t count, long *result, int base)
231d1bc05b7SBenjamin Gray {
232d1bc05b7SBenjamin Gray 	intmax_t parsed;
233d1bc05b7SBenjamin Gray 	int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
234d1bc05b7SBenjamin Gray 
235d1bc05b7SBenjamin Gray 	*result = parsed;
236d1bc05b7SBenjamin Gray 	return err;
237d1bc05b7SBenjamin Gray }
238d1bc05b7SBenjamin Gray 
239d1bc05b7SBenjamin Gray int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base)
240d1bc05b7SBenjamin Gray {
241d1bc05b7SBenjamin Gray 	uintmax_t parsed;
242d1bc05b7SBenjamin Gray 	int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
243d1bc05b7SBenjamin Gray 
244d1bc05b7SBenjamin Gray 	*result = parsed;
245d1bc05b7SBenjamin Gray 	return err;
246d1bc05b7SBenjamin Gray }
247d1bc05b7SBenjamin Gray 
248*5c20de57SBenjamin Gray int read_long(const char *path, long *result, int base)
249*5c20de57SBenjamin Gray {
250*5c20de57SBenjamin Gray 	int err;
251*5c20de57SBenjamin Gray 	char buffer[32] = {0};
252*5c20de57SBenjamin Gray 
253*5c20de57SBenjamin Gray 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
254*5c20de57SBenjamin Gray 	if (err)
255*5c20de57SBenjamin Gray 		return err;
256*5c20de57SBenjamin Gray 
257*5c20de57SBenjamin Gray 	return parse_long(buffer, sizeof(buffer), result, base);
258*5c20de57SBenjamin Gray }
259*5c20de57SBenjamin Gray 
260*5c20de57SBenjamin Gray int read_ulong(const char *path, unsigned long *result, int base)
261*5c20de57SBenjamin Gray {
262*5c20de57SBenjamin Gray 	int err;
263*5c20de57SBenjamin Gray 	char buffer[32] = {0};
264*5c20de57SBenjamin Gray 
265*5c20de57SBenjamin Gray 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
266*5c20de57SBenjamin Gray 	if (err)
267*5c20de57SBenjamin Gray 		return err;
268*5c20de57SBenjamin Gray 
269*5c20de57SBenjamin Gray 	return parse_ulong(buffer, sizeof(buffer), result, base);
270*5c20de57SBenjamin Gray }
271*5c20de57SBenjamin Gray 
272*5c20de57SBenjamin Gray int write_long(const char *path, long result, int base)
273*5c20de57SBenjamin Gray {
274*5c20de57SBenjamin Gray 	int err;
275*5c20de57SBenjamin Gray 	int len;
276*5c20de57SBenjamin Gray 	char buffer[32];
277*5c20de57SBenjamin Gray 
278*5c20de57SBenjamin Gray 	/* Decimal only for now: no format specifier for signed hex values */
279*5c20de57SBenjamin Gray 	if (base != 10) {
280*5c20de57SBenjamin Gray 		err = -EINVAL;
281*5c20de57SBenjamin Gray 		goto out;
282*5c20de57SBenjamin Gray 	}
283*5c20de57SBenjamin Gray 
284*5c20de57SBenjamin Gray 	len = snprintf(buffer, sizeof(buffer), "%ld", result);
285*5c20de57SBenjamin Gray 	if (len < 0 || len >= sizeof(buffer)) {
286*5c20de57SBenjamin Gray 		err = -EOVERFLOW;
287*5c20de57SBenjamin Gray 		goto out;
288*5c20de57SBenjamin Gray 	}
289*5c20de57SBenjamin Gray 
290*5c20de57SBenjamin Gray 	err = write_file(path, buffer, len);
291*5c20de57SBenjamin Gray 
292*5c20de57SBenjamin Gray out:
293*5c20de57SBenjamin Gray 	errno = -err;
294*5c20de57SBenjamin Gray 	return err;
295*5c20de57SBenjamin Gray }
296*5c20de57SBenjamin Gray 
297*5c20de57SBenjamin Gray int write_ulong(const char *path, unsigned long result, int base)
298*5c20de57SBenjamin Gray {
299*5c20de57SBenjamin Gray 	int err;
300*5c20de57SBenjamin Gray 	int len;
301*5c20de57SBenjamin Gray 	char buffer[32];
302*5c20de57SBenjamin Gray 	char *fmt;
303*5c20de57SBenjamin Gray 
304*5c20de57SBenjamin Gray 	switch (base) {
305*5c20de57SBenjamin Gray 	case 10:
306*5c20de57SBenjamin Gray 		fmt = "%lu";
307*5c20de57SBenjamin Gray 		break;
308*5c20de57SBenjamin Gray 	case 16:
309*5c20de57SBenjamin Gray 		fmt = "%lx";
310*5c20de57SBenjamin Gray 		break;
311*5c20de57SBenjamin Gray 	default:
312*5c20de57SBenjamin Gray 		err = -EINVAL;
313*5c20de57SBenjamin Gray 		goto out;
314*5c20de57SBenjamin Gray 	}
315*5c20de57SBenjamin Gray 
316*5c20de57SBenjamin Gray 	len = snprintf(buffer, sizeof(buffer), fmt, result);
317*5c20de57SBenjamin Gray 	if (len < 0 || len >= sizeof(buffer)) {
318*5c20de57SBenjamin Gray 		err = -errno;
319*5c20de57SBenjamin Gray 		goto out;
320*5c20de57SBenjamin Gray 	}
321*5c20de57SBenjamin Gray 
322*5c20de57SBenjamin Gray 	err = write_file(path, buffer, len);
323*5c20de57SBenjamin Gray 
324*5c20de57SBenjamin Gray out:
325*5c20de57SBenjamin Gray 	errno = -err;
326*5c20de57SBenjamin Gray 	return err;
327*5c20de57SBenjamin Gray }
328*5c20de57SBenjamin Gray 
329e3028437SMichael Ellerman void *find_auxv_entry(int type, char *auxv)
330e3028437SMichael Ellerman {
331e3028437SMichael Ellerman 	ElfW(auxv_t) *p;
332e3028437SMichael Ellerman 
333fcb45ec0SMichael Ellerman 	p = (ElfW(auxv_t) *)auxv;
334fcb45ec0SMichael Ellerman 
335fcb45ec0SMichael Ellerman 	while (p->a_type != AT_NULL) {
336e3028437SMichael Ellerman 		if (p->a_type == type)
337e3028437SMichael Ellerman 			return p;
338fcb45ec0SMichael Ellerman 
339fcb45ec0SMichael Ellerman 		p++;
340fcb45ec0SMichael Ellerman 	}
341e3028437SMichael Ellerman 
342e3028437SMichael Ellerman 	return NULL;
343e3028437SMichael Ellerman }
344e3028437SMichael Ellerman 
345e3028437SMichael Ellerman void *get_auxv_entry(int type)
346e3028437SMichael Ellerman {
347e3028437SMichael Ellerman 	ElfW(auxv_t) *p;
348e3028437SMichael Ellerman 
349e3028437SMichael Ellerman 	if (read_auxv(auxv, sizeof(auxv)))
350e3028437SMichael Ellerman 		return NULL;
351e3028437SMichael Ellerman 
352e3028437SMichael Ellerman 	p = find_auxv_entry(type, auxv);
353e3028437SMichael Ellerman 	if (p)
354e3028437SMichael Ellerman 		return (void *)p->a_un.a_val;
355e3028437SMichael Ellerman 
356e3028437SMichael Ellerman 	return NULL;
357fcb45ec0SMichael Ellerman }
358d1301afdSMichael Ellerman 
359d1301afdSMichael Ellerman int pick_online_cpu(void)
360d1301afdSMichael Ellerman {
361dfa03fffSSandipan Das 	int ncpus, cpu = -1;
362dfa03fffSSandipan Das 	cpu_set_t *mask;
363dfa03fffSSandipan Das 	size_t size;
364d1301afdSMichael Ellerman 
365dfa03fffSSandipan Das 	ncpus = get_nprocs_conf();
366dfa03fffSSandipan Das 	size = CPU_ALLOC_SIZE(ncpus);
367dfa03fffSSandipan Das 	mask = CPU_ALLOC(ncpus);
368dfa03fffSSandipan Das 	if (!mask) {
369dfa03fffSSandipan Das 		perror("malloc");
370d1301afdSMichael Ellerman 		return -1;
371d1301afdSMichael Ellerman 	}
372d1301afdSMichael Ellerman 
373dfa03fffSSandipan Das 	CPU_ZERO_S(size, mask);
374dfa03fffSSandipan Das 
375dfa03fffSSandipan Das 	if (sched_getaffinity(0, size, mask)) {
376dfa03fffSSandipan Das 		perror("sched_getaffinity");
377dfa03fffSSandipan Das 		goto done;
378dfa03fffSSandipan Das 	}
379dfa03fffSSandipan Das 
380d1301afdSMichael Ellerman 	/* We prefer a primary thread, but skip 0 */
381dfa03fffSSandipan Das 	for (cpu = 8; cpu < ncpus; cpu += 8)
382dfa03fffSSandipan Das 		if (CPU_ISSET_S(cpu, size, mask))
383dfa03fffSSandipan Das 			goto done;
384d1301afdSMichael Ellerman 
385d1301afdSMichael Ellerman 	/* Search for anything, but in reverse */
386dfa03fffSSandipan Das 	for (cpu = ncpus - 1; cpu >= 0; cpu--)
387dfa03fffSSandipan Das 		if (CPU_ISSET_S(cpu, size, mask))
388dfa03fffSSandipan Das 			goto done;
389d1301afdSMichael Ellerman 
390d1301afdSMichael Ellerman 	printf("No cpus in affinity mask?!\n");
391dfa03fffSSandipan Das 
392dfa03fffSSandipan Das done:
393dfa03fffSSandipan Das 	CPU_FREE(mask);
394dfa03fffSSandipan Das 	return cpu;
395d1301afdSMichael Ellerman }
39695f9b3afSMichael Ellerman 
39795f9b3afSMichael Ellerman bool is_ppc64le(void)
39895f9b3afSMichael Ellerman {
39995f9b3afSMichael Ellerman 	struct utsname uts;
40095f9b3afSMichael Ellerman 	int rc;
40195f9b3afSMichael Ellerman 
40295f9b3afSMichael Ellerman 	errno = 0;
40395f9b3afSMichael Ellerman 	rc = uname(&uts);
40495f9b3afSMichael Ellerman 	if (rc) {
40595f9b3afSMichael Ellerman 		perror("uname");
40695f9b3afSMichael Ellerman 		return false;
40795f9b3afSMichael Ellerman 	}
40895f9b3afSMichael Ellerman 
40995f9b3afSMichael Ellerman 	return strcmp(uts.machine, "ppc64le") == 0;
41095f9b3afSMichael Ellerman }
411d2bf7932SNaveen N. Rao 
412c790c3d2SMichael Ellerman int read_sysfs_file(char *fpath, char *result, size_t result_size)
413c790c3d2SMichael Ellerman {
414c790c3d2SMichael Ellerman 	char path[PATH_MAX] = "/sys/";
415c790c3d2SMichael Ellerman 
416c790c3d2SMichael Ellerman 	strncat(path, fpath, PATH_MAX - strlen(path) - 1);
417c790c3d2SMichael Ellerman 
418a974f0c1SBenjamin Gray 	return read_file(path, result, result_size, NULL);
419c790c3d2SMichael Ellerman }
420c790c3d2SMichael Ellerman 
421121d340bSBenjamin Gray int read_debugfs_int(const char *debugfs_file, int *result)
422d2bf7932SNaveen N. Rao {
423a974f0c1SBenjamin Gray 	int err;
424a974f0c1SBenjamin Gray 	char value[16] = {0};
425d2bf7932SNaveen N. Rao 
426121d340bSBenjamin Gray 	err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
427a974f0c1SBenjamin Gray 	if (err)
428a974f0c1SBenjamin Gray 		return err;
429d2bf7932SNaveen N. Rao 
430d1bc05b7SBenjamin Gray 	return parse_int(value, sizeof(value), result, 10);
431d2bf7932SNaveen N. Rao }
432d2bf7932SNaveen N. Rao 
433121d340bSBenjamin Gray int write_debugfs_int(const char *debugfs_file, int result)
434d2bf7932SNaveen N. Rao {
435d2bf7932SNaveen N. Rao 	char value[16];
436d2bf7932SNaveen N. Rao 
437d2bf7932SNaveen N. Rao 	snprintf(value, 16, "%d", result);
438d2bf7932SNaveen N. Rao 
439121d340bSBenjamin Gray 	return write_debugfs_file(debugfs_file, value, strlen(value));
440d2bf7932SNaveen N. Rao }
441d2bf7932SNaveen N. Rao 
442d2bf7932SNaveen N. Rao static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
443d2bf7932SNaveen N. Rao 		int cpu, int group_fd, unsigned long flags)
444d2bf7932SNaveen N. Rao {
445d2bf7932SNaveen N. Rao 	return syscall(__NR_perf_event_open, hw_event, pid, cpu,
446d2bf7932SNaveen N. Rao 		      group_fd, flags);
447d2bf7932SNaveen N. Rao }
448d2bf7932SNaveen N. Rao 
449d2bf7932SNaveen N. Rao static void perf_event_attr_init(struct perf_event_attr *event_attr,
450d2bf7932SNaveen N. Rao 					unsigned int type,
451d2bf7932SNaveen N. Rao 					unsigned long config)
452d2bf7932SNaveen N. Rao {
453d2bf7932SNaveen N. Rao 	memset(event_attr, 0, sizeof(*event_attr));
454d2bf7932SNaveen N. Rao 
455d2bf7932SNaveen N. Rao 	event_attr->type = type;
456d2bf7932SNaveen N. Rao 	event_attr->size = sizeof(struct perf_event_attr);
457d2bf7932SNaveen N. Rao 	event_attr->config = config;
458d2bf7932SNaveen N. Rao 	event_attr->read_format = PERF_FORMAT_GROUP;
459d2bf7932SNaveen N. Rao 	event_attr->disabled = 1;
460d2bf7932SNaveen N. Rao 	event_attr->exclude_kernel = 1;
461d2bf7932SNaveen N. Rao 	event_attr->exclude_hv = 1;
462d2bf7932SNaveen N. Rao 	event_attr->exclude_guest = 1;
463d2bf7932SNaveen N. Rao }
464d2bf7932SNaveen N. Rao 
465d2bf7932SNaveen N. Rao int perf_event_open_counter(unsigned int type,
466d2bf7932SNaveen N. Rao 			    unsigned long config, int group_fd)
467d2bf7932SNaveen N. Rao {
468d2bf7932SNaveen N. Rao 	int fd;
469d2bf7932SNaveen N. Rao 	struct perf_event_attr event_attr;
470d2bf7932SNaveen N. Rao 
471d2bf7932SNaveen N. Rao 	perf_event_attr_init(&event_attr, type, config);
472d2bf7932SNaveen N. Rao 
473d2bf7932SNaveen N. Rao 	fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
474d2bf7932SNaveen N. Rao 
475d2bf7932SNaveen N. Rao 	if (fd < 0)
476d2bf7932SNaveen N. Rao 		perror("perf_event_open() failed");
477d2bf7932SNaveen N. Rao 
478d2bf7932SNaveen N. Rao 	return fd;
479d2bf7932SNaveen N. Rao }
480d2bf7932SNaveen N. Rao 
481d2bf7932SNaveen N. Rao int perf_event_enable(int fd)
482d2bf7932SNaveen N. Rao {
483d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
484d2bf7932SNaveen N. Rao 		perror("error while enabling perf events");
485d2bf7932SNaveen N. Rao 		return -1;
486d2bf7932SNaveen N. Rao 	}
487d2bf7932SNaveen N. Rao 
488d2bf7932SNaveen N. Rao 	return 0;
489d2bf7932SNaveen N. Rao }
490d2bf7932SNaveen N. Rao 
491d2bf7932SNaveen N. Rao int perf_event_disable(int fd)
492d2bf7932SNaveen N. Rao {
493d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
494d2bf7932SNaveen N. Rao 		perror("error disabling perf events");
495d2bf7932SNaveen N. Rao 		return -1;
496d2bf7932SNaveen N. Rao 	}
497d2bf7932SNaveen N. Rao 
498d2bf7932SNaveen N. Rao 	return 0;
499d2bf7932SNaveen N. Rao }
500d2bf7932SNaveen N. Rao 
501d2bf7932SNaveen N. Rao int perf_event_reset(int fd)
502d2bf7932SNaveen N. Rao {
503d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
504d2bf7932SNaveen N. Rao 		perror("error resetting perf events");
505d2bf7932SNaveen N. Rao 		return -1;
506d2bf7932SNaveen N. Rao 	}
507d2bf7932SNaveen N. Rao 
508d2bf7932SNaveen N. Rao 	return 0;
509d2bf7932SNaveen N. Rao }
510d2bf7932SNaveen N. Rao 
511c405b738SSandipan Das int using_hash_mmu(bool *using_hash)
512c405b738SSandipan Das {
513c405b738SSandipan Das 	char line[128];
514c405b738SSandipan Das 	FILE *f;
515c405b738SSandipan Das 	int rc;
516c405b738SSandipan Das 
517c405b738SSandipan Das 	f = fopen("/proc/cpuinfo", "r");
518c405b738SSandipan Das 	FAIL_IF(!f);
519c405b738SSandipan Das 
520c405b738SSandipan Das 	rc = 0;
521c405b738SSandipan Das 	while (fgets(line, sizeof(line), f) != NULL) {
52234c10334SMichael Ellerman 		if (!strcmp(line, "MMU		: Hash\n") ||
52334c10334SMichael Ellerman 		    !strcmp(line, "platform	: Cell\n") ||
52434c10334SMichael Ellerman 		    !strcmp(line, "platform	: PowerMac\n")) {
525c405b738SSandipan Das 			*using_hash = true;
526c405b738SSandipan Das 			goto out;
527c405b738SSandipan Das 		}
528c405b738SSandipan Das 
529c405b738SSandipan Das 		if (strcmp(line, "MMU		: Radix\n") == 0) {
530c405b738SSandipan Das 			*using_hash = false;
531c405b738SSandipan Das 			goto out;
532c405b738SSandipan Das 		}
533c405b738SSandipan Das 	}
534c405b738SSandipan Das 
535c405b738SSandipan Das 	rc = -1;
536c405b738SSandipan Das out:
537c405b738SSandipan Das 	fclose(f);
538c405b738SSandipan Das 	return rc;
539c405b738SSandipan Das }
540