summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2016-12-19 21:07:51 +1100
committerAlistair Popple <alistair@popple.id.au>2017-03-30 15:37:41 +1100
commitf045f14437ef63e10f57580978dc9ca3e0256007 (patch)
tree86c0bdfe2fd6a54d5517ee5313e89765cd801a08 /src
parent72bf33c09f06ae63cd9f8d05e412b64622b340d1 (diff)
downloadpdbg-f045f14437ef63e10f57580978dc9ca3e0256007.tar.gz
pdbg-f045f14437ef63e10f57580978dc9ca3e0256007.zip
Clean-up target configuration in preparation for adding P9 support
The previous implementation of targeting was hardcoded, cumbersome and difficult to reconfigure for different chip types. This moves to a method of configuring targets using device-tree which is much easier to maintain and allows methods to be added to support operations like getmem on POWER9. Signed-off-by: Alistair Popple <alistair@popple.id.au>
Diffstat (limited to 'src')
-rw-r--r--src/main.c906
1 files changed, 357 insertions, 549 deletions
diff --git a/src/main.c b/src/main.c
index 9fcd6bc..29cd38f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -23,20 +23,25 @@
#include <errno.h>
#include <assert.h>
#include <limits.h>
+#include <inttypes.h>
#include <backend.h>
#include <operations.h>
#include <target.h>
+#include <device.h>
#include <config.h>
#include "bitutils.h"
+#undef PR_DEBUG
+#define PR_DEBUG(...)
+
enum command { GETCFAM = 1, PUTCFAM, GETSCOM, PUTSCOM, \
GETMEM, PUTMEM, GETGPR, GETNIA, GETSPR, \
GETMSR, PUTGPR, PUTNIA, PUTSPR, PUTMSR, \
- STOPCHIP, STARTCHIP, THREADSTATUS, STEP, \
- PROBE, GETVMEM };
+ STOP, START, THREADSTATUS, STEP, PROBE, \
+ GETVMEM };
#define MAX_CMD_ARGS 3
enum command cmd = 0;
@@ -47,43 +52,25 @@ static int cmd_max_arg_count = 0;
/* At the moment all commands only take some kind of number */
static uint64_t cmd_args[MAX_CMD_ARGS];
-enum backend { FSI, I2C, KERNEL };
+enum backend { FSI, I2C, KERNEL, FAKE };
static enum backend backend = KERNEL;
static char const *device_node;
static int i2c_addr = 0x50;
-#define MAX_TARGETS 400
-static struct target targets[MAX_TARGETS];
-
#define MAX_PROCESSORS 16
#define MAX_CHIPS 16
#define MAX_THREADS THREADS_PER_CORE
-static int **processor[MAX_PROCESSORS];
-static int *chip[MAX_PROCESSORS][MAX_CHIPS];
-static int thread[MAX_PROCESSORS][MAX_CHIPS][MAX_THREADS];
-
-struct target_class cfams = {
- .name = "CFAMS",
-};
+static int **processorsel[MAX_PROCESSORS];
+static int *chipsel[MAX_PROCESSORS][MAX_CHIPS];
+static int threadsel[MAX_PROCESSORS][MAX_CHIPS][MAX_THREADS];
-struct target_class processors = {
- .name = "Processors",
-};
-
-struct target_class chiplets = {
- .name = "Chiplets",
-};
-
-struct target_class threads = {
- .name = "Threads",
-};
-
-#define for_each_thread(x) list_for_each(&threads.targets, x, class_link)
-#define for_each_chiplet(x) list_for_each(&chiplets.targets, x, class_link)
-#define for_each_processor(x) list_for_each(&processors.targets, x, class_link)
-#define for_each_cfam(x) list_for_each(&cfams.targets, x, class_link)
+/* Convenience functions */
+#define for_each_thread(x) while(0)
+#define for_each_chiplet(x) while(0)
+#define for_each_processor(x) while(0)
+#define for_each_cfam(x) while(0)
static void print_usage(char *pname)
{
@@ -124,9 +111,9 @@ static void print_usage(char *pname)
printf("\tputnia <value>\n");
printf("\tgetspr <spr>\n");
printf("\tputspr <spr> <value>\n");
- printf("\tstartchip\n");
+ printf("\tstart\n");
printf("\tstep <count>\n");
- printf("\tstopchip\n");
+ printf("\tstop\n");
printf("\tthreadstatus\n");
printf("\tprobe\n");
}
@@ -188,14 +175,14 @@ enum command parse_cmd(char *optarg)
} else if (strcmp(optarg, "getvmem") == 0) {
cmd = GETVMEM;
cmd_min_arg_count = 1;
- } else if (strcmp(optarg, "startchip") == 0) {
- cmd = STARTCHIP;
+ } else if (strcmp(optarg, "start") == 0) {
+ cmd = START;
cmd_min_arg_count = 0;
} else if (strcmp(optarg, "step") == 0) {
cmd = STEP;
cmd_min_arg_count = 1;
- } else if (strcmp(optarg, "stopchip") == 0) {
- cmd = STOPCHIP;
+ } else if (strcmp(optarg, "stop") == 0) {
+ cmd = STOP;
cmd_min_arg_count = 0;
} else if (strcmp(optarg, "threadstatus") == 0) {
cmd = THREADSTATUS;
@@ -248,11 +235,11 @@ static bool parse_options(int argc, char *argv[])
case 'a':
opt_error = false;
for (current_processor = 0; current_processor < MAX_PROCESSORS; current_processor++) {
- processor[current_processor] = &chip[current_processor][0];
+ processorsel[current_processor] = &chipsel[current_processor][0];
for (current_chip = 0; current_chip < MAX_CHIPS; current_chip++) {
- chip[current_processor][current_chip] = &thread[current_processor][current_chip][0];
+ chipsel[current_processor][current_chip] = &threadsel[current_processor][current_chip][0];
for (current_thread = 0; current_thread < MAX_THREADS; current_thread++)
- thread[current_processor][current_chip][current_thread] = 1;
+ threadsel[current_processor][current_chip][current_thread] = 1;
}
}
break;
@@ -263,7 +250,7 @@ static bool parse_options(int argc, char *argv[])
if (current_processor >= MAX_PROCESSORS)
errno = -1;
else
- processor[current_processor] = &chip[current_processor][0];
+ processorsel[current_processor] = &chipsel[current_processor][0];
opt_error = errno;
break;
@@ -273,7 +260,7 @@ static bool parse_options(int argc, char *argv[])
if (current_chip >= MAX_CHIPS)
errno = -1;
else
- chip[current_processor][current_chip] = &thread[current_processor][current_chip][0];
+ chipsel[current_processor][current_chip] = &threadsel[current_processor][current_chip][0];
opt_error = errno;
break;
@@ -283,7 +270,7 @@ static bool parse_options(int argc, char *argv[])
if (current_thread >= MAX_THREADS)
errno = -1;
else
- thread[current_processor][current_chip][current_thread] = 1;
+ threadsel[current_processor][current_chip][current_thread] = 1;
opt_error = errno;
break;
@@ -335,666 +322,487 @@ static bool parse_options(int argc, char *argv[])
return opt_error;
}
-/*
- * Add a given target to the class
- */
-void target_class_add(struct target_class *class, struct target *target, int index)
+/* Returns the sum of return codes. This can be used to count how many targets the callback was run on. */
+static int for_each_child_target(char *class, struct target *parent,
+ int (*cb)(struct target *, uint32_t, uint64_t *, uint64_t *),
+ uint64_t *arg1, uint64_t *arg2)
{
- list_add_tail(&class->targets, &target->class_link);
- target->index = index;
-}
+ int rc = 0;
+ struct target *target;
+ uint32_t index;
+ struct dt_node *dn;
-/*
- * Initialises an I2C based backend. Returns the number of targets
- * added on success.
- */
-static int i2c_backend_targets_init(const char *bus, int addr)
-{
- int i, cfam_count;
+ for_each_class_target(class, target) {
+ struct dt_property *p;
- CHECK_ERR(i2c_target_init(&targets[0], "BMC I2C Backend", NULL, device_node, i2c_addr));
- CHECK_ERR(opb_target_init(&targets[1], "PIB2OPB", 0x20010, &targets[0]));
+ dn = target->dn;
+ if (parent && dn->parent != parent->dn)
+ continue;
- if (processor[0])
- target_class_add(&processors, &targets[0], 0);
+ /* Search up the tree for an index */
+ for (index = dt_prop_get_u32_def(dn, "index", -1); index == -1; dn = dn->parent);
+ assert(index != -1);
- /* Probe cascaded CFAMs on hMFSI ports and add FSI2PIB bridges */
- cfam_count = hmfsi_target_probe(&targets[1], &targets[2], MAX_TARGETS);
- for (i = 0; i < cfam_count; i++) {
- /* Skip prcessors that aren't selected */
- if (!(processor[i + 1]))
+ p = dt_find_property(dn, "status");
+ if (p && (!strcmp(p->prop, "disabled") || !strcmp(p->prop, "hidden")))
continue;
- fsi2pib_target_init(&targets[2 + cfam_count + i], "FSI2PIB", FSI2PIB_BASE, &targets[2 + i]);
-
- /* CFAM index should match processor index even though
- * we don't support cfam 0 on i2c */
- target_class_add(&cfams, &targets[2 + i], i + 1);
- target_class_add(&processors, &targets[2 + cfam_count + i], i + 1);
+ rc += cb(target, index, arg1, arg2);
}
- return 2 + 2*cfam_count;
+ return rc;
}
-static int kernel_backend_targets_init(void)
+static int for_each_target(char *class, int (*cb)(struct target *, uint32_t, uint64_t *, uint64_t *), uint64_t *arg1, uint64_t *arg2)
{
- struct target *cfam;
- int rc, i, cfam_count;
-
- rc = kernel_fsi_target_init(&targets[0], "Kernel FSI Backend", NULL);
- if (rc < 0)
- exit(1);
-
- /* The backend is directly connected to a processor CFAM */
- if (processor[0])
- target_class_add(&cfams, &targets[0], 0);
- cfam_count = 1;
-
- /* Probe cascaded CFAMs on hMFSI ports */
- cfam_count += hmfsi_target_probe(&targets[0], &targets[1], MAX_TARGETS);
- for (i = 1; i < cfam_count; i++)
- if (processor[i])
- target_class_add(&cfams, &targets[i], i);
-
- /* Add a FSI2PIB bridges for each CFAM */
- i = 0;
- for_each_cfam(cfam) {
- kernel_fsi2pib_target_init(&targets[cfam_count + i],
- "FSI2PIB", FSI2PIB_BASE, cfam);
-
- if (processor[i])
- target_class_add(&processors, &targets[cfam_count + i], i);
- i++;
- }
-
- return 2*cfam_count;
+ return for_each_child_target(class, NULL, cb, arg1, arg2);
}
-static int fsi_backend_targets_init(void)
+static int getcfam(struct target *target, uint32_t index, uint64_t *addr, uint64_t *unused)
{
- struct target *cfam;
- int i, cfam_count;
- enum fsi_system_type type;
-
- if (!strcmp(device_node, "p8"))
- type = FSI_SYSTEM_P8;
- else if (!strcmp(device_node, "p9w") || !strcmp(device_node, "witherspoon"))
- type = FSI_SYSTEM_P9W;
- else if (!strcmp(device_node, "p9r") || !strcmp(device_node, "romulus"))
- type = FSI_SYSTEM_P9R;
- else if (!strcmp(device_node, "p9z") || !strcmp(device_node, "zaius"))
- type = FSI_SYSTEM_P9Z;
- else {
- PR_ERROR("Unrecognized FSI system type %s\n", device_node);
- return -1;
- }
-
- fsi_target_init(&targets[0], "BMC FSI Backend", type, NULL);
-
- /* The backend is directly connected to a processor CFAM */
- if (processor[0])
- target_class_add(&cfams, &targets[0], 0);
- cfam_count = 1;
+ uint32_t value;
- /* Probe cascaded CFAMs on hMFSI ports */
- cfam_count += hmfsi_target_probe(&targets[0], &targets[1], MAX_TARGETS);
- for (i = 1; i < cfam_count; i++)
- if (processor[i])
- target_class_add(&cfams, &targets[i], i);
-
- /* Add a FSI2PIB bridges for each CFAM */
- i = 0;
- for_each_cfam(cfam) {
- fsi2pib_target_init(&targets[cfam_count + i], "FSI2PIB", FSI2PIB_BASE, cfam);
+ if (fsi_read(target, *addr, &value))
+ return 0;
- if (processor[cfam->index])
- target_class_add(&processors, &targets[cfam_count + i], cfam->index);
- i++;
- }
+ printf("p%d:0x%x = 0x%08x\n", index, (uint32_t) *addr, value);
- return 2*cfam_count;
+ return 1;
}
-static int backend_init(void)
+static int putcfam(struct target *target, uint32_t index, uint64_t *addr, uint64_t *data)
{
- int i, j, target_count = 0, chiplet_count = 0, thread_count = 0;
- struct target *target, *processor, *chiplet;
-
- list_head_init(&cfams.targets);
- list_head_init(&processors.targets);
- list_head_init(&chiplets.targets);
- list_head_init(&threads.targets);
-
- switch (backend) {
- case I2C:
- if ((target_count = i2c_backend_targets_init(device_node, i2c_addr)) < 0) {
- PR_ERROR("Unable to I2C initialise backend\n");
- return -1;
- }
- break;
-
- case FSI:
- if ((target_count = fsi_backend_targets_init()) < 0) {
- PR_ERROR("Unable to FSI initialise backend\n");
- return -1;
- }
- break;
-
- case KERNEL:
- if ((target_count = kernel_backend_targets_init()) < 0) {
- PR_ERROR("Unable to initialise kernel backend\n");
- return -1;
- }
- break;
-
- default:
- PR_ERROR("Invalid backend specified\n");
- return -1;
- }
-
- target = &targets[target_count];
- j = 0;
- for_each_processor(processor) {
- chiplet_count += chiplet_target_probe(processor, target, MAX_TARGETS - target_count);
- for (i = 0; j < chiplet_count; i++, j++) {
- /* Skip chips that aren't selected */
- if (chip[processor->index][j])
- target_class_add(&chiplets, target, i);
-
- target++;
- }
- }
-
- target_count += chiplet_count;
- target = &targets[target_count];
- j = 0;
- for_each_chiplet(chiplet) {
- thread_count += thread_target_probe(chiplet, target, MAX_TARGETS - target_count);
- for (i = 0; j < thread_count; i++, j++) {
- target_class_add(&threads, target, i);
- if (!chip[chiplet->next->index][chiplet->index][j])
- target->status |= THREAD_STATUS_DISABLED;
- target++;
- }
- }
+ if (fsi_write(target, *addr, *data))
+ return 0;
- return 0;
+ return 1;
}
-
-static void dump_targets(int indent, struct target *target)
+static int getscom(struct target *target, uint32_t index, uint64_t *addr, uint64_t *unused)
{
- int i;
- struct target *child;
+ uint64_t value;
- for (i = 0; i < indent; i++)
- printf(" ");
+ if (pib_read(target, *addr, &value))
+ return 0;
- printf("%s@%llx\n", target->name, target->base);
+ printf("p%d:0x%" PRIx64 " = 0x%016" PRIx64 "\n", index, *addr, value);
- if (!list_empty(&target->children))
- list_for_each(&target->children, child, link)
- dump_targets(indent + 1, child);
+ return 1;
}
-/* Dump all processors and chiplets */
-static uint64_t probe(void)
+static int putscom(struct target *target, uint32_t index, uint64_t *addr, uint64_t *data)
{
- struct target *cfam, *processor, *chiplet, *thread;
- int i, j;
-
- printf("Overall System Topology\n");
- printf("=======================\n\n");
- dump_targets(0, &targets[0]);
-
- i = 0;
- printf("\nCFAMs Present\n");
- printf("=============\n\n");
- for_each_cfam(cfam)
- printf("%d: %s@%llx\n", i++, cfam->name, cfam->base);
-
- i = 0;
- printf("\nProcessors/Chiplets Present\n");
- printf("===========================\n\n");
- for_each_processor(processor) {
- printf("Processor-ID %d: %s@%llx\n", processor->index, processor->name, processor->base);
- j = 0;
- for_each_chiplet(chiplet)
- if (chiplet->next == processor) {
- printf("\tChiplet-ID %d: %s@%llx\n", chiplet->index, chiplet->name, chiplet->base);
- for_each_thread(thread)
- if (thread->next == chiplet)
- printf("\t\tThread-ID %d: %s@%llx\n", thread->index, thread->name, thread->base);
- }
- }
+ if (pib_write(target, *addr, *data))
+ return 0;
- return 0;
+ return 1;
}
-static int filter_parent(struct target *target, void *priv)
+static int print_thread_status(struct target *thread_target, uint32_t index, uint64_t *status, uint64_t *unused1)
{
- struct target *parent = priv;
+ struct thread *thread = target_to_thread(thread_target);
- return target->next == parent;
+ *status = SETFIELD(0xf << (index * 4), *status, thread_status(thread) & 0xf);
+ return 1;
}
-/*
- * Call cb() on each member of the target class when filter() returns
- * true. Returns either the result from cb() (should be -ve on error)
- * or the number of time cb() was called.
- */
-static int for_each_class_call(struct target_class *class, int (*filter)(struct target *, void *),
- int (*cb)(struct target *, uint64_t, uint64_t *),
- void *priv, uint64_t addr, uint64_t *data)
+static int print_chiplet_thread_status(struct target *chiplet_target, uint32_t index, uint64_t *unused, uint64_t *unused1)
{
- struct target *target;
- int rc, count = 0;
+ uint64_t status = -1UL;
+ int i, rc;
+
+ printf("c%02d:", index);
+ rc = for_each_child_target("thread", chiplet_target, print_thread_status, &status, NULL);
+ for (i = 0; i < 8; i++)
+ switch ((status >> (i * 4)) & 0xf) {
+ case THREAD_STATUS_ACTIVE:
+ printf(" A");
+ break;
- list_for_each(&class->targets, target, class_link)
- if ((!filter || filter(target, priv)) && !(target->status & THREAD_STATUS_DISABLED)) {
- count++;
- if((rc = cb(target, addr, data)))
- return rc;
- }
+ case THREAD_STATUS_DOZE:
+ case THREAD_STATUS_QUIESCE | THREAD_STATUS_DOZE:
+ printf(" D");
+ break;
- return count;
-}
+ case THREAD_STATUS_NAP:
+ case THREAD_STATUS_QUIESCE | THREAD_STATUS_NAP:
+ printf(" N");
+ break;
-/* Same as above but calls cb() on all targets rather than just active ones */
-static int for_each_class_call_all(struct target_class *class, int (*filter)(struct target *, void *),
- int (*cb)(struct target *, uint64_t, uint64_t *),
- void *priv, uint64_t addr, uint64_t *data)
-{
- struct target *target;
- int rc, count = 0;
+ case THREAD_STATUS_SLEEP:
+ case THREAD_STATUS_QUIESCE | THREAD_STATUS_SLEEP:
+ printf(" S");
+ break;
+
+ case THREAD_STATUS_ACTIVE | THREAD_STATUS_QUIESCE:
+ printf(" Q");
+ break;
+
+ case 0xf:
+ printf(" ");
+ break;
- list_for_each(&class->targets, target, class_link)
- if (!filter || filter(target, priv)) {
- count++;
- if((rc = cb(target, addr, data)))
- return rc;
+ default:
+ printf(" U");
+ break;
}
+ printf("\n");
- return count;
+ return rc;
}
-static int print_thread_status(struct target *thread, uint64_t addr, uint64_t *data)
+static int print_proc_thread_status(struct target *pib_target, uint32_t index, uint64_t *unused, uint64_t *unused1)
{
- uint64_t status = chiplet_thread_status(thread);
- static int last_index = -1;
- int i;
-
- if (thread->index <= last_index)
- last_index = -1;
-
- for (i = last_index + 1; i < thread->index; i++)
- printf(" ");
-
- last_index = thread->index;
-
- switch (status)
- {
- case THREAD_STATUS_ACTIVE:
- printf(" A");
- break;
-
- case THREAD_STATUS_DOZE:
- case THREAD_STATUS_QUIESCE | THREAD_STATUS_DOZE:
- printf(" D");
- break;
-
- case THREAD_STATUS_NAP:
- case THREAD_STATUS_QUIESCE | THREAD_STATUS_NAP:
- printf(" N");
- break;
-
- case THREAD_STATUS_SLEEP:
- case THREAD_STATUS_QUIESCE | THREAD_STATUS_SLEEP:
- printf(" S");
- break;
-
- case THREAD_STATUS_ACTIVE | THREAD_STATUS_QUIESCE:
- printf(" Q");
- break;
-
- default:
- printf(" U");
- break;
- }
+ printf("\np%01dt: 0 1 2 3 4 5 6 7\n", index);
+ return for_each_child_target("chiplet", pib_target, print_chiplet_thread_status, NULL, NULL);
+};
- return 0;
+#define REG_MEM -3
+#define REG_MSR -2
+#define REG_NIA -1
+#define REG_R31 31
+static void print_proc_reg(struct thread *thread, uint64_t reg, uint64_t value, int rc)
+{
+ int proc_index, chip_index, thread_index;
+
+ thread_index = dt_prop_get_u32(thread->target.dn, "index");
+ chip_index = dt_prop_get_u32(thread->target.dn->parent, "index");
+ proc_index = dt_prop_get_u32(thread->target.dn->parent->parent, "index");
+ printf("p%d:c%d:t%d:", proc_index, chip_index, thread_index);
+
+ if (reg == REG_MSR)
+ printf("msr: ");
+ else if (reg == REG_NIA)
+ printf("nia: ");
+ else if (reg > REG_R31)
+ printf("spr%03" PRIu64 ": ", reg - REG_R31);
+ else if (reg >= 0 && reg <= 31)
+ printf("gpr%02" PRIu64 ": ", reg);
+
+ if (rc == 1)
+ printf("Chiplet in incorrect state\n");
+ else if (rc == 2)
+ printf("Thread in incorrect state\n");
+ else
+ printf("0x%016" PRIx64 "\n", value);
}
-static int print_chiplet_thread_status(struct target *chiplet, uint64_t addr, uint64_t *data)
+static int putprocreg(struct target *thread_target, uint32_t index, uint64_t *reg, uint64_t *value)
{
- printf("c%02d:", chiplet->index);
+ struct thread *thread = target_to_thread(thread_target);
+ int rc;
- for_each_class_call(&threads, filter_parent, print_thread_status, chiplet, 0, NULL);
- printf("\n");
+ if (*reg == REG_MSR)
+ rc = ram_putmsr(thread, *value);
+ else if (*reg == REG_NIA)
+ rc = ram_putnia(thread, *value);
+ else if (*reg > REG_R31)
+ rc = ram_putspr(thread, *reg - REG_R31, *value);
+ else if (*reg >= 0 && *reg <= 31)
+ rc = ram_putgpr(thread, *reg, *value);
+
+ print_proc_reg(thread, *reg, *value, rc);
return 0;
}
-static int getaddr(struct target *target, uint64_t addr, uint64_t *data)
+static int getprocreg(struct target *thread_target, uint32_t index, uint64_t *reg, uint64_t *unused)
{
+ struct thread *thread = target_to_thread(thread_target);
int rc;
+ uint64_t value;
- if ((rc = read_target(target, addr, data)))
- PR_ERROR("Error reading register\n");
- else
- printf("p%d:0x%llx: 0x%016llx\n", target->index, addr, *data);
+ if (*reg == REG_MSR)
+ rc = ram_getmsr(thread, &value);
+ else if (*reg == REG_NIA)
+ rc = ram_getnia(thread, &value);
+ else if (*reg > REG_R31)
+ rc = ram_getspr(thread, *reg - REG_R31, &value);
+ else if (*reg >= 0 && *reg <= 31)
+ rc = ram_getgpr(thread, *reg, &value);
- return rc;
+ print_proc_reg(thread, *reg, value, rc);
+
+ return !rc;
}
-static int putaddr(struct target *target, uint64_t addr, uint64_t *data)
+#define PUTMEM_BUF_SIZE 1024
+static int putmem(uint64_t addr)
{
- uint64_t val, mask = data[1];
- int rc;
-
- if (mask != -1ULL) {
- if ((rc = read_target(target, addr, &val))) {
- PR_ERROR("Unable to read register\n");
- return rc;
- }
-
- val &= ~mask;
- val |= data[0] & mask;
- } else
- val = data[0];
+ uint8_t *buf;
+ int read_size, rc = 0;
+ struct target *adu_target;
- if ((rc = write_target(target, addr, val)))
- PR_ERROR("Error writing register\n");
- else
- printf("p%d:0x%llx: 0x%016llx\n", target->index, addr, val);
+ for_each_class_target("adu", adu_target)
+ break;
- return rc;
+ buf = malloc(PUTMEM_BUF_SIZE);
+ assert(buf);
+ do {
+ read_size = read(STDIN_FILENO, buf, PUTMEM_BUF_SIZE);
+ if (adu_putmem(adu_target, addr, buf, read_size)) {
+ rc = 0;
+ PR_ERROR("Unable to write memory.\n");
+ break;
+ }
+ rc += read_size;
+ } while (read_size > 0);
+
+ free(buf);
+ return rc;
}
-#define START_CHIP 1
-#define STEP_CHIP 2
-#define STOP_CHIP 3
-static int startstopstep_thread(struct target *thread, uint64_t action, uint64_t *data)
+static int start_thread(struct target *thread_target, uint32_t index, uint64_t *unused, uint64_t *unused1)
{
- uint64_t status;
-
- if (action == START_CHIP)
- return ram_start_thread(thread);
- else if (action == STEP_CHIP) {
- status = chiplet_thread_status(thread);
- if (!(GETFIELD(THREAD_STATUS_QUIESCE, status) && GETFIELD(THREAD_STATUS_ACTIVE, status))) {
- PR_ERROR("Thread %d not stopped. Use stopchip first.\n", thread->index);
-
- /* Return 0 so we continue stepping other threads if requested */
- return 0;
- }
+ struct thread *thread = target_to_thread(thread_target);
- return ram_step_thread(thread, *data);
- } else
- return ram_stop_thread(thread);
+ return ram_start_thread(thread) ? 1 : 0;
}
-/*
- * Start/stop all threads on the chip.
- */
-static int startstopstep_chip(struct target *chiplet, uint64_t action, uint64_t *data)
+static int step_thread(struct target *thread_target, uint32_t index, uint64_t *count, uint64_t *unused1)
{
- if (action == STEP_CHIP)
- for_each_class_call(&threads, filter_parent, startstopstep_thread, chiplet, action, data);
- else
- for_each_class_call_all(&threads, filter_parent, startstopstep_thread, chiplet, action, data);
+ struct thread *thread = target_to_thread(thread_target);
- return 0;
+ return ram_step_thread(thread, *count) ? 1 : 0;
}
-static int check_thread_status(struct target *thread, uint64_t unused, uint64_t *unused1)
+static int stop_thread(struct target *thread_target, uint32_t index, uint64_t *unused, uint64_t *unused1)
{
- uint64_t status = chiplet_thread_status(thread);
+ struct thread *thread = target_to_thread(thread_target);
- if (status & THREAD_STATUS_QUIESCE)
- return 0;
- else
- return -1;
+ return ram_stop_thread(thread) ? 1 : 0;
}
-static int check_state(struct target *thread)
+static void enable_dn(struct dt_node *dn)
{
- struct target *chiplet = thread->next;
+ struct dt_property *p;
- if (for_each_class_call_all(&threads, filter_parent, check_thread_status, chiplet, 0, NULL) < 0) {
- PR_ERROR("Not all threads are quiesced. Use the stopchip command"
- " first to ensure all chiplet threads are quiesced\n");
- return -1;
- }
+ PR_DEBUG("Enabling %s\n", dn->name);
+ p = dt_find_property(dn, "status");
- if (!((thread->status & THREAD_STATUS_ACTIVE) && (thread->status & THREAD_STATUS_QUIESCE))) {
- PR_ERROR("Skipping thread %d as it is not active.\n", thread->index);
- return -2;
- }
+ if (!p)
+ /* Default assumption enabled */
+ return;
- return 0;
-}
+ /* We only override a status of "hidden" */
+ if (strcmp(p->prop, "hidden"))
+ return;
-#define REG_MEM -3ULL
-#define REG_MSR -2ULL
-#define REG_NIA -1ULL
-#define REG_R31 31ULL
+ dt_del_property(dn, p);
+}
-static int putreg(struct target *thread, uint64_t reg, uint64_t *data)
+static void disable_dn(struct dt_node *dn)
{
- int state;
+ struct dt_property *p;
- state = check_state(thread);
- if (state == -2)
- /* Return 0 so we keep attempting other non-sleeping
- * threads on the chiplet if requested */
- return 0;
- else if (state)
- return state;
-
- if (reg == REG_NIA)
- if (ram_putnia(thread, *data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:nia = 0x%016llx\n", thread->next->index, thread->index, *data);
- else if (reg == REG_MSR)
- if (ram_putmsr(thread, *data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:msr = 0x%016llx\n", thread->next->index, thread->index, *data);
- else if (reg <= REG_R31)
- if (ram_putgpr(thread, reg, *data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:r%lld = 0x%016llx\n", thread->next->index, thread->index, reg, *data);
- else {
- reg -= 32;
- if (ram_putspr(thread, reg, *data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:spr%lld = 0x%016llx\n", thread->next->index, thread->index, reg, *data);
- }
+ PR_DEBUG("Disabling %s\n", dn->name);
+ p = dt_find_property(dn, "status");
+ if (p)
+ /* We don't override hard-coded device tree
+ * status. This is needed to avoid disabling that
+ * backend. */
+ return;
- return 0;
+ dt_add_property_string(dn, "status", "disabled");
}
-static int getreg(struct target *thread, uint64_t reg, uint64_t *data)
+/* TODO: It would be nice to have a more dynamic way of doing this */
+extern unsigned char _binary_p8_i2c_dtb_o_start;
+extern unsigned char _binary_p8_i2c_dtb_o_end;
+extern unsigned char _binary_p8_fsi_dtb_o_start;
+extern unsigned char _binary_p8_fsi_dtb_o_end;
+extern unsigned char _binary_p9w_fsi_dtb_o_start;
+extern unsigned char _binary_p9w_fsi_dtb_o_end;
+extern unsigned char _binary_p9r_fsi_dtb_o_start;
+extern unsigned char _binary_p9r_fsi_dtb_o_end;
+extern unsigned char _binary_p9z_fsi_dtb_o_start;
+extern unsigned char _binary_p9z_fsi_dtb_o_end;
+extern unsigned char _binary_p9_kernel_dtb_o_start;
+extern unsigned char _binary_p9_kernel_dtb_o_end;
+extern unsigned char _binary_fake_dtb_o_start;
+extern unsigned char _binary_fake_dtb_o_end;
+static int target_select(void)
{
- uint64_t addr = *data;
- int state;
+ struct target *fsi, *pib, *chip, *thread;
- state = check_state(thread);
- if (state == -2)
- /* Return 0 so we keep attempting other non-sleeping
- * threads on the chiplet if requested */
- return 0;
- else if (state)
- return state;
+ switch (backend) {
+ case I2C:
+ targets_init(&_binary_p8_i2c_dtb_o_start);
+ break;
- if (reg == REG_NIA)
- if (ram_getnia(thread, data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:nia = 0x%016llx\n", thread->next->index, thread->index, *data);
- else if (reg == REG_MSR)
- if (ram_getmsr(thread, data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:msr = 0x%016llx\n", thread->next->index, thread->index, *data);
- else if (reg == REG_MEM)
- if (ram_getmem(thread, addr, data))
- PR_ERROR("Page fault reading memory\n");
- else
- printf("c%02d:t%d:0x%016llx = 0x%016llx\n", thread->next->index, thread->index, addr, *data);
- else if (reg <= REG_R31)
- if (ram_getgpr(thread, reg, data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:r%lld = 0x%016llx\n", thread->next->index, thread->index, reg, *data);
- else {
- reg -= 32;
- if (ram_getspr(thread, reg, data))
- PR_ERROR("Error reading register\n");
- else
- printf("c%02d:t%d:spr%lld = 0x%016llx\n", thread->next->index, thread->index, reg, *data);
- }
+ case FSI:
+ if (!strcmp(device_node, "p8"))
+ targets_init(&_binary_p8_fsi_dtb_o_start);
+ else if (!strcmp(device_node, "p9w") || !strcmp(device_node, "witherspoon"))
+ targets_init(&_binary_p9w_fsi_dtb_o_start);
+ else if (!strcmp(device_node, "p9r") || !strcmp(device_node, "romulus"))
+ targets_init(&_binary_p9r_fsi_dtb_o_start);
+ else if (!strcmp(device_node, "p9z") || !strcmp(device_node, "zaius"))
+ targets_init(&_binary_p9z_fsi_dtb_o_start);
+ else {
+ PR_ERROR("Invalid device type specified\n");
+ return -1;
+ }
+ break;
- return 0;
-}
+ case KERNEL:
+ targets_init(&_binary_p9_kernel_dtb_o_start);
+ break;
-#define PUTMEM_BUF_SIZE 1024
-static int putmem(uint64_t addr)
-{
- uint8_t *buf;
- int read_size, rc = 0;
- struct target *target;
+ case FAKE:
+ targets_init(&_binary_fake_dtb_o_start);
+ break;
- /* It doesn't matter which processor we execute on so
- * just use the primary one */
- if (list_empty(&processors.targets))
- return 0;
+ default:
+ PR_ERROR("Invalid backend specified\n");
+ return -1;
+ }
- target = list_entry(processors.targets.n.next, struct target, class_link);
- buf = malloc(PUTMEM_BUF_SIZE);
- assert(buf);
- do {
- read_size = read(STDIN_FILENO, buf, PUTMEM_BUF_SIZE);
- if (adu_putmem(target, addr, buf, read_size)) {
- rc = 0;
- PR_ERROR("Unable to write memory.\n");
- break;
- }
+ /* At this point we should have a device-tree loaded. We want
+ * to walk the tree and disabled nodes we don't care about
+ * prior to probing. */
+ for_each_class_target("pib", pib) {
+ int proc_index = dt_prop_get_u32(pib->dn, "index");
+
+ if (processorsel[proc_index]) {
+ enable_dn(pib->dn);
+ if (!find_target_class("chiplet"))
+ continue;
+ for_each_class_target("chiplet", chip) {
+ if (chip->dn->parent != pib->dn)
+ continue;
+ int chip_index = dt_prop_get_u32(chip->dn, "index");
+ if (chipsel[proc_index][chip_index]) {
+ enable_dn(chip->dn);
+ if (!find_target_class("thread"))
+ continue;
+ for_each_class_target("thread", thread) {
+ if (thread->dn->parent != chip->dn)
+ continue;
+
+ int thread_index = dt_prop_get_u32(thread->dn, "index");
+ if (threadsel[proc_index][chip_index][thread_index])
+ enable_dn(thread->dn);
+ else
+ disable_dn(thread->dn);
+ }
+ } else
+ disable_dn(chip->dn);
+ }
+ } else
+ disable_dn(pib->dn);
+ }
- rc += read_size;
- } while (read_size > 0);
+ for_each_class_target("fsi", fsi) {
+ int index = dt_prop_get_u32(fsi->dn, "index");
+ if (processorsel[index])
+ enable_dn(fsi->dn);
+ else
+ disable_dn(fsi->dn);
+ }
- free(buf);
- return rc;
+ return 0;
}
int main(int argc, char *argv[])
{
int rc = 0;
- uint64_t value = 0;
uint8_t *buf;
struct target *target;
if (parse_options(argc, argv))
return 1;
- if (backend_init())
+ /* Disable unselected targets */
+ if (target_select())
return 1;
+ target_probe();
+
switch(cmd) {
case GETCFAM:
- rc = for_each_class_call(&cfams, NULL, getaddr, NULL, cmd_args[0], &value);
- break;
- case GETSCOM:
- rc = for_each_class_call(&processors, NULL, getaddr, NULL, cmd_args[0], &value);
+ rc = for_each_target("fsi", getcfam, &cmd_args[0], NULL);
break;
case PUTCFAM:
- rc = for_each_class_call(&cfams, NULL, putaddr, NULL, cmd_args[0], &cmd_args[1]);
+ rc = for_each_target("fsi", putcfam, &cmd_args[0], &cmd_args[1]);
+ break;
+ case GETSCOM:
+ rc = for_each_target("pib", getscom, &cmd_args[0], NULL);
break;
case PUTSCOM:
- rc = for_each_class_call(&processors, NULL, putaddr, NULL, cmd_args[0], &cmd_args[1]);
+ rc = for_each_target("pib", putscom, &cmd_args[0], &cmd_args[1]);
break;
case GETMEM:
- /* It doesn't matter which processor we execute on so
- * just use the primary one */
- if (list_empty(&processors.targets))
- break;
+ buf = malloc(cmd_args[1]);
+ assert(buf);
+ for_each_class_target("adu", target) {
+ if (!adu_getmem(target, cmd_args[0], buf, cmd_args[1])) {
+ write(STDOUT_FILENO, buf, cmd_args[1]);
+ rc++;
+ } else
+ PR_ERROR("Unable to read memory.\n");
- target = list_entry(processors.targets.n.next, struct target, class_link);
- buf = malloc(cmd_args[1]);
- assert(buf);
- if (!adu_getmem(target, cmd_args[0], buf, cmd_args[1])) {
- rc = 1;
- write(STDOUT_FILENO, buf, cmd_args[1]);
- } else
- PR_ERROR("Unable to read memory.\n");
+ /* We only ever care about getting memory from a single processor */
+ break;
+ }
free(buf);
break;
case PUTMEM:
- rc = putmem(cmd_args[0]);
- printf("Wrote %d bytes starting at 0x%016llx\n", rc, cmd_args[0]);
+ rc = putmem(cmd_args[0]);
+ printf("Wrote %d bytes starting at 0x%016" PRIx64 "\n", rc, cmd_args[0]);
break;
case GETGPR:
- rc = for_each_class_call(&threads, NULL, getreg, NULL, cmd_args[0], &value);
+ for_each_target("thread", getprocreg, &cmd_args[0], NULL);
break;
case PUTGPR:
- rc = for_each_class_call(&threads, NULL, putreg, NULL, cmd_args[0], &cmd_args[1]);
+ for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]);
break;
case GETNIA:
- rc = for_each_class_call(&threads, NULL, getreg, NULL, REG_NIA, &value);
+ cmd_args[0] = REG_NIA;
+ for_each_target("thread", getprocreg, &cmd_args[0], NULL);
break;
case PUTNIA:
- rc = for_each_class_call(&threads, NULL, putreg, NULL, REG_NIA, &cmd_args[0]);
+ cmd_args[1] = cmd_args[0];
+ cmd_args[0] = REG_NIA;
+ for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]);
break;
case GETSPR:
- rc = for_each_class_call(&threads, NULL, getreg, NULL, cmd_args[0] + 32, &value);
+ cmd_args[0] += REG_R31;
+ for_each_target("thread", getprocreg, &cmd_args[0], NULL);
break;
case PUTSPR:
- rc = for_each_class_call(&threads, NULL, putreg, NULL, cmd_args[0] + 32, &cmd_args[1]);
+ cmd_args[0] += REG_R31;
+ for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]);
break;
case GETMSR:
- rc = for_each_class_call(&threads, NULL, getreg, NULL, REG_MSR, &value);
+ cmd_args[0] = REG_MSR;
+ for_each_target("thread", getprocreg, &cmd_args[0], NULL);
break;
case PUTMSR:
- rc = for_each_class_call(&threads, NULL, putreg, NULL, REG_MSR, &cmd_args[0]);
- break;
- case GETVMEM:
- rc = for_each_class_call(&threads, NULL, getreg, NULL, REG_MEM, &cmd_args[0]);
+ cmd_args[1] = cmd_args[0];
+ cmd_args[0] = REG_MSR;
+ for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]);
break;
case THREADSTATUS:
- printf(" t: 0 1 2 3 4 5 6 7\n");
- rc = for_each_class_call(&chiplets, NULL, print_chiplet_thread_status, NULL, 0, 0);
- printf("\nA - Active\nS - Sleep\nN - Nap\nD - Doze\nQ - Quiesced/Stopped\nU - Unknown\n");
+ for_each_target("pib", print_proc_thread_status, NULL, NULL);
break;
- case STARTCHIP:
- rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, START_CHIP, NULL);
+ case START:
+ for_each_target("thread", start_thread, NULL, NULL);
break;
case STEP:
- rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, STEP_CHIP, &cmd_args[0]);
+ for_each_target("thread", step_thread, &cmd_args[0], NULL);
break;
- case STOPCHIP:
- rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, STOP_CHIP, NULL);
+ case STOP:
+ for_each_target("thread", stop_thread, NULL, NULL);
break;
- case PROBE:
- rc = 1;
- probe();
+ default:
+ PR_ERROR("Unsupported command\n");
break;
}
- if (rc <= 0) {
- printf("No valid targets found or specified. Try adding -p/-c/-t options to specify a target.\n");
- printf("Alternatively run %s -a probe to get a list of all valid targets\n", argv[0]);
- rc = -1;
- } else
- rc = 0;
-
- /* TODO: We don't properly tear down all the targets yet */
- targets[0].destroy(&targets[0]);
+ if (backend == FSI)
+ fsi_destroy(NULL);
return rc;
}
OpenPOWER on IntegriCloud