diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-11-13 13:24:00 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-11-13 13:24:00 +1100 |
commit | 3cf5a0962e64a0f63537ddeecf04058793fed936 (patch) | |
tree | 9ba497f238f8ceb77c89f5c0529911bb798b44f1 /external | |
parent | f0e2dc332b2e6c926b43f3270922f91bdd8f1455 (diff) | |
download | skiboot-3cf5a0962e64a0f63537ddeecf04058793fed936.zip skiboot-3cf5a0962e64a0f63537ddeecf04058793fed936.tar.gz skiboot-3cf5a0962e64a0f63537ddeecf04058793fed936.tar.bz2 |
external: Add xscom utilities
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'external')
-rw-r--r-- | external/xscom-utils/Makefile | 19 | ||||
-rw-r--r-- | external/xscom-utils/getscom.c | 140 | ||||
-rw-r--r-- | external/xscom-utils/putscom.c | 98 | ||||
-rw-r--r-- | external/xscom-utils/xscom.c | 182 | ||||
-rw-r--r-- | external/xscom-utils/xscom.h | 16 |
5 files changed, 455 insertions, 0 deletions
diff --git a/external/xscom-utils/Makefile b/external/xscom-utils/Makefile new file mode 100644 index 0000000..ff9474a --- /dev/null +++ b/external/xscom-utils/Makefile @@ -0,0 +1,19 @@ +all: getscom putscom + +VERSION=0.1 +CFLAGS=-O2 -g -Wall -m64 -DVERSION=$(VERSION) + +getscom: getscom.c xscom.c + $(CC) $(CFLAGS) -o $@ $^ + +putscom: putscom.c xscom.c + $(CC) $(CFLAGS) -o $@ $^ + +.PHONY: clean +clean: + rm -rf getscom putscom + +.PHONY: distclean +distclean: clean + rm -rf *.c~ *.h~ *.i *.s Makefile~ + diff --git a/external/xscom-utils/getscom.c b/external/xscom-utils/getscom.c new file mode 100644 index 0000000..5a678fc --- /dev/null +++ b/external/xscom-utils/getscom.c @@ -0,0 +1,140 @@ +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <stdint.h> +#include <stdbool.h> +#include <inttypes.h> + +#include "xscom.h" + +static void print_usage(void) +{ + printf("usage: getscom [-c|--chip chip-id] addr\n"); + printf(" getscom -l|--list-chips\n"); + printf(" getscom -v|--version\n"); +} + +static void print_chip_info(uint32_t chip_id) +{ + uint64_t f000f, cfam_id; + const char *name; + char uname_buf[64]; + int rc; + + rc = xscom_read(chip_id, 0xf000f, &f000f); + if (rc) + return; + + cfam_id = f000f >> 44; + + switch(cfam_id & 0xff) { + case 0xf9: + name = "P7 processor"; + break; + case 0xe8: + name = "P7+ processor"; + break; + case 0xef: + name = "P8E (Murano) processor"; + break; + case 0xea: + name = "P8 (Venice) processor"; + break; + case 0xe9: + name = "Centaur memory buffer"; + break; + default: + snprintf(uname_buf, sizeof(uname_buf), "Unknown ID 0x%02lx", + cfam_id & 0xff); + name = uname_buf; + } + + printf("%08x | DD%lx.%lx | %s\n", + chip_id, (cfam_id >> 16) & 0xf, (cfam_id >> 8) & 0xf, name); + +} + +#define VERSION_STR _str(VERSION) +#define _str(s) __str(s) +#define __str(s) #s + +int main(int argc, char *argv[]) +{ + uint64_t val, addr = -1ull; + uint32_t def_chip, chip_id = 0xffffffff; + bool show_help = false; + bool list_chips = false; + bool show_version = false; + bool no_work = false; + int rc; + + while(1) { + static struct option long_opts[] = { + {"chip", required_argument, NULL, 'c'}, + {"list-chips", no_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + }; + int c, oidx = 0; + + c = getopt_long(argc, argv, "-c:hlv", long_opts, &oidx); + if (c == EOF) + break; + switch(c) { + case 1: + addr = strtoull(optarg, NULL, 16); + break; + case 'c': + chip_id = strtoul(optarg, NULL, 0); + break; + case 'h': + show_help = true; + break; + case 'l': + list_chips = true; + break; + case 'v': + show_version = true; + break; + default: + exit(1); + } + } + + if (addr == -1ull) + no_work = true; + if (no_work && !list_chips && !show_version && !show_help) { + fprintf(stderr, "Invalid or missing address\n"); + print_usage(); + exit(1); + } + if (show_version) + printf("xscom utils version %s\n", VERSION_STR); + if (show_help) + print_usage(); + if (no_work && !list_chips) + return 0; + def_chip = xscom_init(); + if (def_chip == 0xffffffff) { + fprintf(stderr, "No valid XSCOM chip found\n"); + exit(1); + } + if (list_chips) { + printf("Chip ID | Rev | Chip type\n"); + printf("---------|-------|--------\n"); + xscom_for_each_chip(print_chip_info); + } + if (no_work) + return 0; + if (chip_id == 0xffffffff) + chip_id = def_chip; + + rc = xscom_read(chip_id, addr, &val); + if (rc) { + fprintf(stderr,"Error %d reading XSCOM\n", rc); + exit(1); + } + printf("%" PRIx64 "\n", val); + return 0; +} + diff --git a/external/xscom-utils/putscom.c b/external/xscom-utils/putscom.c new file mode 100644 index 0000000..74ecb5d --- /dev/null +++ b/external/xscom-utils/putscom.c @@ -0,0 +1,98 @@ +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <stdint.h> +#include <stdbool.h> +#include <inttypes.h> + +#include "xscom.h" + +static void print_usage(void) +{ + printf("usage: putscom [-c|--chip chip-id] addr value\n"); + printf(" putscom -v|--version\n"); +} + +#define VERSION_STR _str(VERSION) +#define _str(s) __str(s) +#define __str(s) #s + +int main(int argc, char *argv[]) +{ + uint64_t val = -1ull, addr = -1ull; + uint32_t def_chip, chip_id = 0xffffffff; + bool show_help = false, got_addr = false, got_val = false; + bool show_version = false; + bool no_work = false; + int rc; + + while(1) { + static struct option long_opts[] = { + {"chip", required_argument, NULL, 'c'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + }; + int c, oidx = 0; + + c = getopt_long(argc, argv, "-c:hv", long_opts, &oidx); + if (c == EOF) + break; + switch(c) { + case 1: + if (!got_addr) { + addr = strtoull(optarg, NULL, 16); + got_addr = true; + break; + } + val = strtoull(optarg, NULL, 16); + got_val = true; + break; + case 'c': + chip_id = strtoul(optarg, NULL, 0); + break; + case 'v': + show_version = true; + break; + case 'h': + show_help = true; + break; + default: + exit(1); + } + } + + if (!got_addr || !got_val) + no_work = true; + if (no_work && !show_version && !show_help) { + fprintf(stderr, "Invalid or missing address/value\n"); + print_usage(); + exit(1); + } + if (show_version) + printf("xscom utils version %s\n", VERSION_STR); + if (show_help) + print_usage(); + if (no_work) + return 0; + def_chip = xscom_init(); + if (def_chip == 0xffffffff) { + fprintf(stderr, "No valid XSCOM chip found\n"); + exit(1); + } + if (chip_id == 0xffffffff) + chip_id = def_chip; + + rc = xscom_write(chip_id, addr, val); + if (rc) { + fprintf(stderr,"Error %d writing XSCOM\n", rc); + exit(1); + } + rc = xscom_read(chip_id, addr, &val); + if (rc) { + fprintf(stderr,"Error %d reading XSCOM\n", rc); + exit(1); + } + printf("%" PRIx64 "\n", val); + return 0; +} + diff --git a/external/xscom-utils/xscom.c b/external/xscom-utils/xscom.c new file mode 100644 index 0000000..43e8a89 --- /dev/null +++ b/external/xscom-utils/xscom.c @@ -0,0 +1,182 @@ +#define _LARGEFILE64_SOURCE +#include <sys/mman.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> +#include <stdbool.h> +#include <dirent.h> +#include <assert.h> +#include <ctype.h> + +#include "xscom.h" + +#define XSCOM_BASE_PATH "/sys/kernel/debug/powerpc/scom" + +struct xscom_chip { + struct xscom_chip *next; + uint32_t chip_id; + int fd; +}; +static struct xscom_chip *xscom_chips; + +void xscom_for_each_chip(void (*cb)(uint32_t chip_id)) +{ + struct xscom_chip *c; + + for (c = xscom_chips; c; c = c->next) + cb(c->chip_id); +} + +static uint32_t xscom_add_chip(const char *base_path, const char *dname) +{ + char nbuf[strlen(base_path) + strlen(dname) + 16]; + struct xscom_chip *chip; + int fd; + + snprintf(nbuf, sizeof(nbuf), "%s/%s/access", base_path, dname); + fd = open(nbuf, O_RDWR); + if (fd < 0) { + perror("Failed to open SCOM access file"); + exit(1); + } + + chip = malloc(sizeof(*chip)); + assert(chip); + memset(chip, 0, sizeof(*chip)); + chip->fd = fd; + chip->chip_id = strtoul(dname, NULL, 16); + chip->next = xscom_chips; + xscom_chips = chip; + + return chip->chip_id; +} + +static bool xscom_check_dirname(const char *n) +{ + while(*n) { + char c = toupper(*(n++)); + + if ((c < 'A' || c > 'Z') && + (c < '0' || c > '9')) + return false; + } + return true; +} + +static uint32_t xscom_scan_chips(const char *base_path) +{ + int i, nfiles; + struct dirent **filelist; + uint32_t lower = 0xffffffff; + + nfiles = scandir(base_path, &filelist, NULL, alphasort); + if (nfiles < 0) { + perror("Error accessing sysfs scom directory"); + exit(1); + } + if (nfiles == 0) { + fprintf(stderr, "No SCOM dir found in sysfs\n"); + exit(1); + } + + for (i = 0; i < nfiles; i++) { + struct dirent *d = filelist[i]; + uint32_t id; + + if (d->d_type != DT_DIR) + continue; + if (!xscom_check_dirname(d->d_name)) + continue; + id = xscom_add_chip(base_path, d->d_name); + if (id < lower) + lower = id; + free(d); + } + + free(filelist); + return lower; +} + +static struct xscom_chip *xscom_find_chip(uint32_t chip_id) +{ + struct xscom_chip *c; + + for (c = xscom_chips; c; c = c->next) + if (c->chip_id == chip_id) + return c; + return NULL; +} + +static uint64_t xscom_mangle_addr(uint64_t addr) +{ + if (addr & (1ull << 63)) + addr |= (1ull << 59); + return addr << 3; +} + +int xscom_read(uint32_t chip_id, uint64_t addr, uint64_t *val) +{ + struct xscom_chip *c = xscom_find_chip(chip_id); + int rc; + + if (!c) + return -ENODEV; + addr = xscom_mangle_addr(addr); + lseek64(c->fd, addr, SEEK_SET); + rc = read(c->fd, val, 8); + if (rc < 0) + return -errno; + if (rc != 8) + return -EIO; + return 0; +} + +int xscom_write(uint32_t chip_id, uint64_t addr, uint64_t val) +{ + struct xscom_chip *c = xscom_find_chip(chip_id); + int rc; + + if (!c) + return -ENODEV; + addr = xscom_mangle_addr(addr); + lseek64(c->fd, addr, SEEK_SET); + rc = write(c->fd, &val, 8); + if (rc < 0) + return -errno; + if (rc != 8) + return -EIO; + return 0; +} + +int xscom_read_ex(uint32_t ex_target_id, uint64_t addr, uint64_t *val) +{ + uint32_t chip_id = ex_target_id >> 4;; + + addr |= (ex_target_id & 0xf) << 24; + + /* XXX TODO: Special wakeup ? */ + + return xscom_read(chip_id, addr, val); +} + +int xscom_write_ex(uint32_t ex_target_id, uint64_t addr, uint64_t val) +{ + uint32_t chip_id = ex_target_id >> 4;; + + addr |= (ex_target_id & 0xf) << 24; + + /* XXX TODO: Special wakeup ? */ + + return xscom_write(chip_id, addr, val); +} + +uint32_t xscom_init(void) +{ + return xscom_scan_chips(XSCOM_BASE_PATH); +} diff --git a/external/xscom-utils/xscom.h b/external/xscom-utils/xscom.h new file mode 100644 index 0000000..755bef7 --- /dev/null +++ b/external/xscom-utils/xscom.h @@ -0,0 +1,16 @@ +#ifndef __XSCOM_H +#define __XSCOM_H + +#include <stdint.h> + +extern int xscom_read(uint32_t chip_id, uint64_t addr, uint64_t *val); +extern int xscom_write(uint32_t chip_id, uint64_t addr, uint64_t val); + +extern int xscom_read_ex(uint32_t ex_target_id, uint64_t addr, uint64_t *val); +extern int xscom_write_ex(uint32_t ex_target_id, uint64_t addr, uint64_t val); + +extern void xscom_for_each_chip(void (*cb)(uint32_t chip_id)); + +extern uint32_t xscom_init(void); + +#endif /* __XSCOM_H */ |