aboutsummaryrefslogtreecommitdiff
path: root/external/xscom-utils
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-11-13 13:24:00 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-11-13 13:24:00 +1100
commit3cf5a0962e64a0f63537ddeecf04058793fed936 (patch)
tree9ba497f238f8ceb77c89f5c0529911bb798b44f1 /external/xscom-utils
parentf0e2dc332b2e6c926b43f3270922f91bdd8f1455 (diff)
downloadskiboot-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/xscom-utils')
-rw-r--r--external/xscom-utils/Makefile19
-rw-r--r--external/xscom-utils/getscom.c140
-rw-r--r--external/xscom-utils/putscom.c98
-rw-r--r--external/xscom-utils/xscom.c182
-rw-r--r--external/xscom-utils/xscom.h16
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 */