diff options
Diffstat (limited to 'roms/skiboot/external/xscom-utils')
-rw-r--r-- | roms/skiboot/external/xscom-utils/.gitignore | 3 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/Makefile | 61 | ||||
-rwxr-xr-x | roms/skiboot/external/xscom-utils/adu_scoms.py | 300 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/getscom.1 | 23 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/getscom.c | 167 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/getsram.1 | 23 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/getsram.c | 132 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/putscom.1 | 18 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/putscom.c | 115 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/sram.c | 139 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/sram.h | 14 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/xscom.c | 206 | ||||
-rw-r--r-- | roms/skiboot/external/xscom-utils/xscom.h | 26 |
13 files changed, 1227 insertions, 0 deletions
diff --git a/roms/skiboot/external/xscom-utils/.gitignore b/roms/skiboot/external/xscom-utils/.gitignore new file mode 100644 index 000000000..43e219f9c --- /dev/null +++ b/roms/skiboot/external/xscom-utils/.gitignore @@ -0,0 +1,3 @@ +getscom +getsram +putscom diff --git a/roms/skiboot/external/xscom-utils/Makefile b/roms/skiboot/external/xscom-utils/Makefile new file mode 100644 index 000000000..69ce87a72 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/Makefile @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +CC = $(CROSS_COMPILE)gcc + +XSCOM_VERSION ?= $(shell ../../make_version.sh xscom-utils) +CFLAGS += -O2 -g -Wall -m64 + +prefix = /usr/local/ +sbindir = $(prefix)/sbin +datadir = $(prefix)/share +mandir = $(datadir)/man + +%.o: %.c + $(Q_CC)$(COMPILE.c) $< -o $@ + +# Use make V=1 for a verbose build. +ifndef V + Q_CC= @echo ' CC ' $@; + Q_LINK= @echo ' LINK ' $@; + Q_LN= @echo ' LN ' $@; + Q_MKDIR=@echo ' MKDIR ' $@; +endif + +all: getscom putscom getsram + +getscom: getscom.o xscom.o version.o + $(Q_LINK)$(LINK.o) -o $@ $^ + +getsram: getsram.o xscom.o sram.o version.o + $(Q_LINK)$(LINK.o) -o $@ $^ + +putscom: putscom.o xscom.o version.o + $(Q_LINK)$(LINK.o) -o $@ $^ + +install: all + install -D getscom $(DESTDIR)$(sbindir)/getscom + install -D putscom $(DESTDIR)$(sbindir)/putscom + install -D getsram $(DESTDIR)$(sbindir)/getsram + install -D -m 0644 getscom.1 $(DESTDIR)$(mandir)/man1/getscom.1 + install -D -m 0644 putscom.1 $(DESTDIR)$(mandir)/man1/putscom.1 + install -D -m 0644 getsram.1 $(DESTDIR)$(mandir)/man1/getsram.1 + +.PHONY: clean +clean: + rm -rf *.[od] getscom putscom getsram + +.PHONY: distclean +distclean: clean + rm -rf *.c~ *.h~ *.i *.s Makefile~ .version version.c + +version.c: ../../make_version.sh .version + @(if [ "a$(XSCOM_VERSION)" = "a" ]; then \ + echo "#error You need to set XSCOM_VERSION environment variable" > $@ ;\ + else \ + echo "const char version[] = \"$(XSCOM_VERSION)\";" ;\ + fi) > $@ + +.PHONY: VERSION-always +.version: VERSION-always + @echo $(XSCOM_VERSION) > $@.tmp + @cmp -s $@ $@.tmp || cp $@.tmp $@ + @rm -f $@.tmp diff --git a/roms/skiboot/external/xscom-utils/adu_scoms.py b/roms/skiboot/external/xscom-utils/adu_scoms.py new file mode 100755 index 000000000..e90634190 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/adu_scoms.py @@ -0,0 +1,300 @@ +#!/usr/bin/python +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +# +# Python library for in-band SCom access +# (based on xscom-utils from OPAL firmware) +# +# Copyright 2018 IBM Corp. + +import os, sys, struct, getopt + +class XSCom(object): + def __init__(self): + self.name = "xscom" + self.base = "/sys/kernel/debug/powerpc/scom/" + self.enabled = False + self.setup = False + self.chips = [] + self.dirs = [] + self.key_val_bin = {} + self.file = "/access" + + if os.path.exists(self.base): + self.enabled = True + + if not self.scan_chips(): + raise ValueError + + def scan_chips(self): + if not self.enabled: + print("Not supported") + return False + + for i in os.listdir(self.base): + if os.path.isdir(self.base+i): + self.dirs.append(i) + self.chips.append(int(i,16)) + + for i in self.dirs: + try: + b = open(self.base+i+self.file, "rb+") + self.key_val_bin[int(i,16)] = b + except: + print("Count not open"+self.base+i+self.file) + return False + + self.setup = True + return True + + def is_supported(self): + return self.enabled + + def get_chip_ids(self): + return list(self.key_val_bin.keys()) + + def mangle_addr(self, addr): + tmp = (addr & 0xf000000000000000) >> 4 + addr = (addr & 0x00ffffffffffffff) + addr = addr | tmp + return (addr << 3) + + def xscom_read(self, chip_id, addr): + if not isinstance(chip_id, int) or not isinstance(addr, int): + print("xscom_read: Input paramater type mismatch") + return -1 + + if chip_id not in self.key_val_bin: + print("Invalid Chip id") + return -1 + + saddr = self.mangle_addr(addr) + fd = self.key_val_bin.get(chip_id) + fd.seek(saddr, 0) + return struct.unpack('Q',fd.read(8))[0] + + def xscom_read_spl(self, chip_id, addr): + if not isinstance(chip_id, int) or not isinstance(addr, int): + print("xscom_read: Input paramater type mismatch") + return -1 + + if chip_id not in self.key_val_bin: + print("Invalid Chip id") + return -1 + + saddr = self.mangle_addr(addr) + fd = self.key_val_bin.get(chip_id) + fd.seek(saddr, 0) + val = struct.unpack('Q',fd.read(8))[0] + fd.close() + try: + b = open(self.key_val_path.get(chip_id), "rb+") + except: + print("Reopen failed") + return val + self.key_val_bin[chip_id] = b + return val + + def xscom_write(self, chip_id, addr, val): + if chip_id not in self.key_val_bin: + print("Invalid Chip id") + return -1 + + c = struct.pack('Q',val) + saddr = self.mangle_addr(addr) + fd = self.key_val_bin.get(chip_id) + + try: + fd.seek(saddr, 0) + fd.write(c) + # write again just to be sure + fd.seek(saddr, 0) + fd.write(c) + except: + print("Write() error") + return -1 + + def xscom_read_ex(self, ex_target_id, addr): + if not isinstance(ex_target_id, int) or not isinstance(addr, int): + print("xscom_read_ex: Input paramater type mismatch") + return -1 + + chip_id = ex_target_id >> 4 + addr |= (ex_target_id & 0xf) << 24; + return self.xscom_read(chip_id, addr, val); + + def xscom_write_ex(self, ex_target_id, addr, val): + chip_id = ex_target_id >> 4 + addr |= (ex_target_id & 0xf) << 24; + return self.xscom_write(chip_id, addr, val) + +class GetSCom(object): + def __init__(self): + self.name = "getscom" + self.backend = XSCom() + self.listchip = False + self.chip_id = 0 + self.chips = False + self.addr = 0 + self.flg_addr = False + + if not self.backend.is_supported(): + print("In-Band SCom not supported Exiting....") + raise ValueError + + def set_chip(self, chip_id): + self.chip_id = chip_id + self.chips = True + + def set_addr(self, scom_addr): + self.addr = scom_addr + self.flg_addr = True + + def print_usage(self): + print("usage: getscom [-c|--chip chip-id] addr") + print(" getscom -l|--list-chips") + print(" getscom -h|--help") + sys.exit(0) + + + def chip_info(self, chip_id): + val = self.backend.xscom_read(chip_id, 0xf000f) + if val < 0: + print("Error in scom read") + raise ValueError + + c_id = val >> 44 + id = c_id & 0xff + if id == 0xef: + name = "P8E (Murano) processor" + elif id == 0xea: + name = "P8 (Venice) processor" + elif id == 0xd3: + name = "P8NVL (Naples) processor" + elif id == 0xd1: + name = "P9 (Nimbus) processor" + elif id == 0xd4: + name = "P9 (Cumulus) processor" + elif id == 0xd9: + name = "P9P (Axone) processor" + elif id == 0xda: + name = "P10 processor" + elif id == 0xe9: + name = "Centaur memory buffer" + else: + name = "Unknown ID 0x%x"%id + + print(("%08x | DD%s.%s | %s"%(chip_id, ((c_id >> 16) & 0xf), ((c_id >> 8) & 0xf), name))) + + def parse_args(self): + try: + optlist, sys.argv = getopt.getopt(sys.argv[1:], "lhc:", ["chip", "list-chips", "help"]) + except getopt.GetoptError as err: + print(str(err)) + self.print_usage() + sys.exit(0) + + if len(optlist) == 0: + self.print_usage() + sys.exit(0) + + for opt, arg in optlist: + if opt in [ "-h", "--help"]: + self.print_usage() + sys.exit(0) + + elif opt in [ "-l", "--list-chips"]: + self.listchip = True + + elif opt in ["-c", "--chip"]: + self.chip_id = int(arg, 16) + self.chips = True + + if sys.argv: + self.addr = int(sys.argv.pop(), 16) + self.flg_addr = True + + if self.listchip: + print("Chip ID | Rev | Chip type") + print("---------|-------|-----------") + for i in self.backend.get_chip_ids(): + self.chip_info(i) + + sys.exit(0) + + def run_command(self): + if self.chips and self.flg_addr: + print(hex(self.backend.xscom_read(self.chip_id, self.addr))) + + def list_chips(self): + print("Chip ID | Rev | Chip type") + print("---------|-------|-----------") + for i in self.backend.get_chip_ids(): + self.chip_info(i) + + raise ValueError + + def execute(self, chip_id, addr): + return self.backend.xscom_read(chip_id, addr) + + def execute_spl(self, chip_id, addr): + return self.backend.xscom_read_spl(chip_id, addr) + +class PutSCom(object): + def __init__(self): + self.name = "putscom" + self.backend = XSCom() + self.chip_id = 0 + self.chips = False + self.addr = 0 + self.value = 0 + + if not self.backend.is_supported(): + print("In-Band SCom not supported Exiting....") + raise ValueError + + def set_addr(self, addr): + self.addr = addr + + def set_value(self, value): + self.value = value + + def print_usage(self): + print("usage: putscom [-c|--chip chip-id] addr value") + print(" putscom -h|--help") + sys.exit(0) + + def parse_args(self): + try: + optlist, sys.argv = getopt.getopt(sys.argv[1:], "hc:", ["chip", "help"]) + except getopt.GetoptError as err: + print(str(err)) + self.print_usage() + sys.exit(0) + + if len(optlist) == 0: + self.print_usage() + sys.exit(0) + + for opt, arg in optlist: + if opt in [ "-h", "--help"]: + self.print_usage() + sys.exit(0) + + elif opt in ["-c", "--chip"]: + self.chip_id = int(arg, 16) + self.chips = True + + if sys.argv: + self.value = int(sys.argv.pop(), 16) + self.addr = int(sys.argv.pop(), 16) + + if self.chips: + self.backend.xscom_write(self.chip_id, self.addr, self.value) + + def run_command(self): + if self.chips: + self.backend.xscom_write(self.chip_id, self.addr, self.value) + + def execute(self, chip_id, addr, value): + self.backend.xscom_write(chip_id, addr, value) + diff --git a/roms/skiboot/external/xscom-utils/getscom.1 b/roms/skiboot/external/xscom-utils/getscom.1 new file mode 100644 index 000000000..295b99d56 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/getscom.1 @@ -0,0 +1,23 @@ +.TH XSCOM "1" "September 2016" +.SH NAME +getscom \- part of xscom utils +.SH SYNOPIS +.TP +\fBgetscom\fP [\-c | \-\-chip \fIchip\-id\fP] \fIaddr\fP +.TP +\fBgetscom\fP [\-l | \-\-list\-chips] +.TP +\fBgetscom\fP [\-v | \-\-version] +.SH DESCRIPTION +\fBgetscom\fP utility provides an interface to query the +registers of the different chipsets of an OpenPower system. +.SS Options +.TP +\fB\-c|\-\-chip-id\fP \fIchip-id\fP +Specify chipset where to read register at \fIaddr\fP +.TP +\fB\-l|\-\-list\-chips\fP +List the chipsets found on the system +.TP +\fB\-v|\-\-version\fP +Display version of the tool diff --git a/roms/skiboot/external/xscom-utils/getscom.c b/roms/skiboot/external/xscom-utils/getscom.c new file mode 100644 index 000000000..67596e618 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/getscom.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * getscom + * + * Copyright 2014-2017 IBM Corp. + */ + +#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(int code) +{ + printf("usage: getscom [-c|--chip chip-id] [-b|--list-bits] addr\n"); + printf(" getscom -l|--list-chips\n"); + printf(" getscom -v|--version\n"); + printf("\n"); + printf(" NB: --list-bits shows which PPC bits are set\n"); + exit(code); +} + +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 0xef: + name = "P8E (Murano) processor"; + break; + case 0xea: + name = "P8 (Venice) processor"; + break; + case 0xd3: + name = "P8NVL (Naples) processor"; + break; + case 0xd1: + name = "P9 (Nimbus) processor"; + break; + case 0xd4: + name = "P9 (Cumulus) processor"; + break; + case 0xd9: + name = "P9P (Axone) processor"; + break; + case 0xda: + name = "P10 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); +} + +extern const char version[]; + +int main(int argc, char *argv[]) +{ + uint64_t val, addr = -1ull; + uint32_t def_chip, chip_id = 0xffffffff; + bool list_chips = false; + bool no_work = false; + bool list_bits = 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'}, + {"list-bits", no_argument, NULL, 'b'}, + }; + int c, oidx = 0; + + c = getopt_long(argc, argv, "-c:bhlv", long_opts, &oidx); + if (c == EOF) + break; + switch(c) { + case 1: + addr = strtoull(optarg, NULL, 16); + break; + case 'c': + chip_id = strtoul(optarg, NULL, 16); + break; + case 'h': + print_usage(0); + break; + case 'l': + list_chips = true; + break; + case 'b': + list_bits = true; + break; + case 'v': + printf("xscom utils version %s\n", version); + exit(0); + default: + exit(1); + } + } + + if (addr == -1ull) + no_work = true; + if (no_work && !list_chips) { + fprintf(stderr, "Invalid or missing address\n"); + print_usage(1); + } + + 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("%016" PRIx64, val); + + if (list_bits) { + int i; + + printf(" - set: "); + + for (i = 0; i < 64; i++) + if (val & PPC_BIT(i)) + printf("%d ", i); + } + + putchar('\n'); + + return 0; +} + diff --git a/roms/skiboot/external/xscom-utils/getsram.1 b/roms/skiboot/external/xscom-utils/getsram.1 new file mode 100644 index 000000000..19b297414 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/getsram.1 @@ -0,0 +1,23 @@ +.TH XSCOM "1" "January 2018" +.SH NAME +getsram \- part of xscom utils +.SH SYNOPIS +.TP +\fBgetsram\fP [\-c | \-\-chip \fIchip\-id\fP] \fIaddr\fP +.TP +\fBgetsram\fP [\-n | \-\-occ\-channel \fIchan\fP] +.TP +\fBgetsram\fP [\-v | \-\-version] +.SH DESCRIPTION +\fBgetsram\fP utility provides an interface to query the +OCC RAM of an OpenPower system. +.SS Options +.TP +\fB\-c|\-\-chip-id\fP \fIchip-id\fP +Specify chipset where to read register at \fIaddr\fP +.TP +\fB\-n|\-\-occ\-channel\fP +Specify the channel : 0, 1, 2 or 3 +.TP +\fB\-v|\-\-version\fP +Display version of the tool diff --git a/roms/skiboot/external/xscom-utils/getsram.c b/roms/skiboot/external/xscom-utils/getsram.c new file mode 100644 index 000000000..7d9c4bfac --- /dev/null +++ b/roms/skiboot/external/xscom-utils/getsram.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * Read SRAM + * + * Copyright 2014-2018 IBM Corp. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <stdint.h> +#include <stdbool.h> +#include <inttypes.h> + +#include "xscom.h" +#include "sram.h" + +static void print_usage(int code) +{ + printf("usage: getsram [opts] addr\n"); + printf(" -c|--chip <chip-id>\n"); + printf(" -l|--length <size to read>\n"); + printf(" -n|--occ-channel <chan>\n"); + printf(" -f|--file <filename>\n"); + printf(" -v|--version\n"); + exit(code); +} + +extern const char version[]; + +int main(int argc, char *argv[]) +{ + uint64_t val, addr = -1ull, length = 8; + uint32_t def_chip, chip_id = 0xffffffff; + int rc; + int occ_channel = 0; + char *filename = NULL; + FILE *f = stdout; + + while(1) { + static struct option long_opts[] = { + {"chip", required_argument, NULL, 'c'}, + {"occ-channel", required_argument, NULL, 'n'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {"length", required_argument, NULL, 'l'}, + {"file", required_argument, NULL, 'f'}, + }; + int c, oidx = 0; + + c = getopt_long(argc, argv, "-c:n:hl:vf:", long_opts, &oidx); + if (c == EOF) + break; + switch(c) { + case 1: + addr = strtoull(optarg, NULL, 16); + break; + case 'c': + chip_id = strtoul(optarg, NULL, 16); + break; + case 'n': + occ_channel = strtoul(optarg, NULL, 0); + if (occ_channel < 0 || occ_channel > 3) { + fprintf(stderr, "occ-channel out of range 0 <= c <= 3\n"); + exit(1); + } + break; + case 'h': + print_usage(0); + break; + case 'v': + printf("xscom utils version %s\n", version); + exit(0); + case 'f': + filename = optarg; + break; + case 'l': + length = strtoul(optarg, NULL, 0); + length = (length + 7) & ~0x7; /* round up to an eight byte interval */ + break; + default: + exit(1); + } + } + + if (addr == -1ull) { + fprintf(stderr, "Invalid or missing address\n"); + print_usage(1); + } + + 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; + + if (filename) { + f = fopen(filename, "wb"); + if (!f) { + fprintf(stderr, "unable to open %s for writing\n", filename); + exit(1); + } + } + + rc = 0; + while (length) { + rc = sram_read(chip_id, occ_channel, addr, &val); + if (rc) + break; + + if (f) { + int i; + + /* make sure we write it out big endian */ + for (i = 1; i <= 8; i++) + fputc((val >> (64 - i * 8)) & 0xff, f); + } else { + printf("OCC%d: %" PRIx64 "\n", occ_channel, val); + } + + length -= 8; + addr += 8; + } + + if (rc) { + fprintf(stderr,"Error %d reading XSCOM\n", rc); + exit(1); + } + return 0; +} diff --git a/roms/skiboot/external/xscom-utils/putscom.1 b/roms/skiboot/external/xscom-utils/putscom.1 new file mode 100644 index 000000000..9c329fc27 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/putscom.1 @@ -0,0 +1,18 @@ +.TH XSCOM "1" "September 2016" +.SH NAME +putscom \- part of xscom utils +.SH SYNOPIS +.TP +\fBputscom\fP [\-c | \-\-chip \fIchip\-id\fP] \fIaddr\fP \fIvalue\fP +.TP +\fBputscom\fP [\-v | \-\-version] +.SH DESCRIPTION +\fBputscom\fP utility provides an interface to modify the +registers of the different chipsets of an OpenPower system. +.SS Options +.TP +\fB\-c|\-\-chip-id\fP \fIchip\-id\fP +Specify chipset where to modify register at \fIaddr\fP with \fIvalue\fP +.TP +\fB\-v|\-\-version\fP +Display version of the tool diff --git a/roms/skiboot/external/xscom-utils/putscom.c b/roms/skiboot/external/xscom-utils/putscom.c new file mode 100644 index 000000000..b942eeb58 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/putscom.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * getscom + * + * Copyright 2014-2017 IBM Corp. + */ + +#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(int code) +{ + printf("usage: putscom [-c|--chip chip-id] [-b|--list-bits] addr value\n"); + printf(" putscom -v|--version\n"); + printf("\n"); + printf(" NB: --list-bits shows which PPC bits are set\n"); + exit(code); + exit(code); +} + +extern const char version[]; + +int main(int argc, char *argv[]) +{ + uint64_t val = -1ull, addr = -1ull; + uint32_t def_chip, chip_id = 0xffffffff; + bool got_addr = false, got_val = false; + bool list_bits = 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:bhv", 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, 16); + break; + case 'b': + list_bits = true; + break; + case 'v': + printf("xscom utils version %s\n", version); + exit(0); + case 'h': + print_usage(0); + break; + default: + exit(1); + } + } + + if (!got_addr || !got_val) { + fprintf(stderr, "Invalid or missing address/value\n"); + print_usage(1); + } + + 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); + } + if (xscom_readable(addr)) { + rc = xscom_read(chip_id, addr, &val); + if (rc) { + fprintf(stderr,"Error %d reading XSCOM\n", rc); + exit(1); + } + } + + printf("%016" PRIx64, val); + if (list_bits) { + int i; + + printf(" - set: "); + + for (i = 0; i < 64; i++) + if (val & PPC_BIT(i)) + printf("%d ", i); + } + + putchar('\n'); + return 0; +} + diff --git a/roms/skiboot/external/xscom-utils/sram.c b/roms/skiboot/external/xscom-utils/sram.c new file mode 100644 index 000000000..efe08d8e7 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/sram.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2014-2019 IBM Corp. */ + +#include <stdint.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <time.h> + +#include "xscom.h" + +#define DBG(fmt...) do { if (verbose) printf(fmt); } while(0) +#define ERR(fmt...) do { fprintf(stderr, fmt); } while(0) + +#define OCB_PIB_BASE_P8 0x0006B000 +#define OCB_PIB_BASE_P9 0x0006D000 + +#define OCBCSR0 0x11 +#define OCBCSR0_AND 0x12 +#define OCBCSR0_OR 0x13 +#define OCB_STREAM_MODE PPC_BIT(4) +#define OCB_STREAM_TYPE PPC_BIT(5) +#define OCBAR0 0x10 +#define OCBDR0 0x15 + +#define PVR_TYPE_P8E 0x004b /* Murano */ +#define PVR_TYPE_P8 0x004d /* Venice */ +#define PVR_TYPE_P8NVL 0x004c /* Naples */ +#define PVR_TYPE_P9 0x004e +#define PVR_TYPE_P9P 0x004f /* Axone */ +#define PVR_TYPE_P10 0x0080 + +#ifdef __powerpc__ +static uint64_t get_xscom_base(void) +{ + unsigned int pvr; + + asm volatile("mfpvr %0" : "=r" (pvr)); + + switch (pvr >> 16) { + case PVR_TYPE_P9: + case PVR_TYPE_P9P: + case PVR_TYPE_P10: /* P10 OCB_PIB OCC Control Register is same for P9 and P10 */ + return OCB_PIB_BASE_P9; + + case PVR_TYPE_P8E: + case PVR_TYPE_P8: + case PVR_TYPE_P8NVL: + return OCB_PIB_BASE_P8; + } + + ERR("Unknown processor, exiting\n"); + exit(1); + return 0; +} +#else +/* Just so it compiles on x86 */ +static uint64_t get_xscom_base(void) { return 0; } +#endif + +int sram_read(uint32_t chip_id, int chan, uint32_t addr, uint64_t *val) +{ + uint64_t sdat, base = get_xscom_base(); + uint32_t coff = chan * 0x20; + int rc; + + /* Read for debug purposes */ + rc = xscom_read(chip_id, base + OCBCSR0 + coff, &sdat); + if (rc) { + ERR("xscom OCBCSR0 read error %d\n", rc); + return -1; + } + + /* Create an AND mask to clear bit 4 and 5 and poke the AND register */ + sdat = ~(OCB_STREAM_MODE | OCB_STREAM_TYPE); + rc = xscom_write(chip_id, base + OCBCSR0_AND + coff, sdat); + if (rc) { + ERR("xscom OCBCSR0_AND write error %d\n", rc); + return -1; + } + + sdat = ((uint64_t)addr) << 32; + rc = xscom_write(chip_id, base + OCBAR0 + coff, sdat); + if (rc) { + ERR("xscom OCBAR0 write error %d\n", rc); + return -1; + } + + rc = xscom_read(chip_id, base + OCBDR0 + coff, val); + if (rc) { + ERR("xscom OCBDR0 read error %d\n", rc); + return -1; + } + return 0; +} + +int sram_write(uint32_t chip_id, int chan, uint32_t addr, uint64_t val) +{ + uint64_t sdat, base = get_xscom_base(); + uint32_t coff = chan * 0x20; + int rc; + +#if 0 + if (dummy) { + printf("[dummy] write chip %d OCC sram 0x%08x = %016lx\n", + chip_id, addr, val); + return 0; + } +#endif + + /* Read for debug purposes */ + rc = xscom_read(chip_id, base + OCBCSR0 + coff, &sdat); + if (rc) { + ERR("xscom OCBCSR0 read error %d\n", rc); + return -1; + } + + /* Create an AND mask to clear bit 4 and 5 and poke the AND register */ + sdat = ~(OCB_STREAM_MODE | OCB_STREAM_TYPE); + rc = xscom_write(chip_id, base + OCBCSR0_AND + coff, sdat); + if (rc) { + ERR("xscom OCBCSR0_AND write error %d\n", rc); + return -1; + } + + sdat = ((uint64_t)addr) << 32; + rc = xscom_write(chip_id, base + OCBAR0 + coff, sdat); + if (rc) { + ERR("xscom OCBAR0 write error %d\n", rc); + return -1; + } + + rc = xscom_write(chip_id, base + OCBDR0 + coff, val); + if (rc) { + ERR("xscom OCBDR0 write error %d\n", rc); + return -1; + } + return 0; +} diff --git a/roms/skiboot/external/xscom-utils/sram.h b/roms/skiboot/external/xscom-utils/sram.h new file mode 100644 index 000000000..75d9155c4 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/sram.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2014-2016 IBM Corp. */ + +#ifndef __SRAM_H +#define __SRAM_H + +#include <stdint.h> + +extern int sram_read(uint32_t chip_id, int chan, uint64_t addr, uint64_t *val); +extern int sram_write(uint32_t chip_id, int chan, uint64_t addr, uint64_t val); + +extern void sram_for_each_chip(void (*cb)(uint32_t chip_id)); + +#endif /* __SRAM_H */ diff --git a/roms/skiboot/external/xscom-utils/xscom.c b/roms/skiboot/external/xscom-utils/xscom.c new file mode 100644 index 000000000..031f9e193 --- /dev/null +++ b/roms/skiboot/external/xscom-utils/xscom.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * Do XSCOMs through linux debugfs interface + * + * Copyright 2014-2017 IBM Corp. + */ + +#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) +{ + uint64_t tmp; + + /* + * Shift the top 4 bits (indirect mode) down by 4 bits so we + * don't lose going through the debugfs interfaces. + */ + tmp = (addr & 0xf000000000000000) >> 4; + addr &= 0x00ffffffffffffff; + addr |= tmp; + + /* Shift up by 3 for debugfs */ + 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); +} + +bool xscom_readable(uint64_t addr) +{ + /* Top nibble 9 indicates form 1 indirect, which is write only */ + if (((addr >> 60) & 0xf) == 9) + return false; + return true; +} + +uint32_t xscom_init(void) +{ + return xscom_scan_chips(XSCOM_BASE_PATH); +} diff --git a/roms/skiboot/external/xscom-utils/xscom.h b/roms/skiboot/external/xscom-utils/xscom.h new file mode 100644 index 000000000..05b8f543b --- /dev/null +++ b/roms/skiboot/external/xscom-utils/xscom.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2014-2017 IBM Corp. + */ + +#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 bool xscom_readable(uint64_t addr); + +extern uint32_t xscom_init(void); + +#ifndef PPC_BIT +#define PPC_BIT(bit) (0x8000000000000000UL >> (bit)) +#endif + +#endif /* __XSCOM_H */ |