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