summaryrefslogtreecommitdiffstats
path: root/libpdbg/chip.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpdbg/chip.c')
-rw-r--r--libpdbg/chip.c242
1 files changed, 119 insertions, 123 deletions
diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index 8abc131..cde11a3 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -20,6 +20,7 @@
#include <ccan/array_size/array_size.h>
#include <unistd.h>
+#include "target.h"
#include "operations.h"
#include "bitutils.h"
@@ -68,7 +69,7 @@
#define SPECIAL_WKUP_DONE PPC_BIT(31)
/* How long (in us) to wait for a special wakeup to complete */
-#define SPECIAL_WKUP_TIMEOUT 1000
+#define SPECIAL_WKUP_TIMEOUT 10
/* Opcodes */
#define MTNIA_OPCODE 0x00000002UL
@@ -135,21 +136,22 @@ static uint64_t ld(uint64_t rt, uint64_t ds, uint64_t ra)
return LD_OPCODE | (rt << 21) | (ra << 16) | (ds << 2);
}
-static int assert_special_wakeup(struct target *chip)
+static int assert_special_wakeup(struct chiplet *chip)
{
int i = 0;
uint64_t gp0;
/* Assert special wakeup to prevent low power states */
- CHECK_ERR(write_target(chip, PMSPCWKUPFSP_REG, FSP_SPECIAL_WAKEUP));
+ CHECK_ERR(pib_write(&chip->target, PMSPCWKUPFSP_REG, FSP_SPECIAL_WAKEUP));
/* Poll for completion */
do {
usleep(1);
- CHECK_ERR(read_target(chip, EX_PM_GP0_REG, &gp0));
+ CHECK_ERR(pib_read(&chip->target, EX_PM_GP0_REG, &gp0));
if (i++ > SPECIAL_WKUP_TIMEOUT) {
- PR_ERROR("Timeout waiting for special wakeup\n");
+ PR_ERROR("Timeout waiting for special wakeup on %s@0x%08lx\n", chip->target.name,
+ dt_get_address(chip->target.dn, 0, NULL));
return -1;
}
} while (!(gp0 & SPECIAL_WKUP_DONE));
@@ -157,41 +159,41 @@ static int assert_special_wakeup(struct target *chip)
return 0;
}
-static int deassert_special_wakeup(struct target *chip)
+static int deassert_special_wakeup(struct chiplet *chip)
{
/* Assert special wakeup to prevent low power states */
- CHECK_ERR(write_target(chip, PMSPCWKUPFSP_REG, 0));
+ CHECK_ERR(pib_write(&chip->target, PMSPCWKUPFSP_REG, 0));
return 0;
}
-uint64_t chiplet_thread_status(struct target *thread)
+uint64_t thread_status(struct thread *thread)
{
return thread->status;
}
-static uint64_t get_thread_status(struct target *thread)
+static uint64_t get_thread_status(struct thread *thread)
{
uint64_t val, mode_reg, thread_status = thread->status;
/* Need to activete debug mode to get complete status */
- CHECK_ERR(read_target(thread, RAS_MODE_REG, &mode_reg));
+ CHECK_ERR(pib_read(&thread->target, RAS_MODE_REG, &mode_reg));
mode_reg |= MR_THREAD_IN_DEBUG;
- CHECK_ERR(write_target(thread, RAS_MODE_REG, mode_reg));
+ CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, mode_reg));
/* Read status */
- CHECK_ERR(read_target(thread, RAS_STATUS_REG, &val));
+ CHECK_ERR(pib_read(&thread->target, RAS_STATUS_REG, &val));
thread_status = SETFIELD(THREAD_STATUS_ACTIVE, thread_status, !!(val & RAS_STATUS_THREAD_ACTIVE));
thread_status = SETFIELD(THREAD_STATUS_QUIESCE, thread_status, !!(val & RAS_STATUS_TS_QUIESCE));
/* Read POW status */
- CHECK_ERR(read_target(thread, POW_STATUS_REG, &val));
+ CHECK_ERR(pib_read(&thread->target, POW_STATUS_REG, &val));
thread_status = SETFIELD(THREAD_STATUS_STATE, thread_status, GETFIELD(PMC_POW_STATE, val));
/* Clear debug mode */
mode_reg &= ~MR_THREAD_IN_DEBUG;
- CHECK_ERR(write_target(thread, RAS_MODE_REG, mode_reg));
+ CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, mode_reg));
return thread_status;
}
@@ -199,48 +201,48 @@ static uint64_t get_thread_status(struct target *thread)
/*
* Single step the thread count instructions.
*/
-int ram_step_thread(struct target *thread, int count)
+int ram_step_thread(struct thread *thread, int count)
{
int i;
uint64_t ras_mode, ras_status;
/* Activate single-step mode */
- CHECK_ERR(read_target(thread, RAS_MODE_REG, &ras_mode));
+ CHECK_ERR(pib_read(&thread->target, RAS_MODE_REG, &ras_mode));
ras_mode |= MR_DO_SINGLE_MODE;
- CHECK_ERR(write_target(thread, RAS_MODE_REG, ras_mode));
+ CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, ras_mode));
/* Step the core */
for (i = 0; i < count; i++) {
- CHECK_ERR(write_target(thread, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_STEP));
+ CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_STEP));
/* Wait for step to complete */
do {
- CHECK_ERR(read_target(thread, RAS_STATUS_REG, &ras_status));
+ CHECK_ERR(pib_read(&thread->target, RAS_STATUS_REG, &ras_status));
} while (!(ras_status & RAS_STATUS_INST_COMPLETE));
}
/* Deactivate single-step mode */
ras_mode &= ~MR_DO_SINGLE_MODE;
- CHECK_ERR(write_target(thread, RAS_MODE_REG, ras_mode));
+ CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, ras_mode));
return 0;
}
-int ram_stop_thread(struct target *thread)
+int ram_stop_thread(struct thread *thread)
{
- int i = 0, thread_id = (thread->base >> 4) & 0x7;
+ int i = 0;
uint64_t val;
- struct target *chip = thread->next;
+ struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target);
do {
/* Quiese active thread */
- CHECK_ERR(write_target(thread, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_STOP));
+ CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_STOP));
/* Wait for thread to quiese */
- CHECK_ERR(read_target(chip, RAS_STATUS_REG, &val));
+ CHECK_ERR(pib_read(&chip->target, RAS_STATUS_REG, &val));
if (i++ > RAS_STATUS_TIMEOUT) {
PR_ERROR("Unable to quiesce thread %d (0x%016llx).\n",
- thread->index, val);
+ thread->id, val);
PR_ERROR("Continuing anyway.\n");
if (val & PPC_BIT(48)) {
PR_ERROR("Unable to continue\n");
@@ -258,27 +260,42 @@ int ram_stop_thread(struct target *thread)
/* Make the threads RAM thread active */
- CHECK_ERR(read_target(chip, THREAD_ACTIVE_REG, &val));
- val |= PPC_BIT(8) >> thread_id;
- CHECK_ERR(write_target(chip, THREAD_ACTIVE_REG, val));
+ CHECK_ERR(pib_read(&chip->target, THREAD_ACTIVE_REG, &val));
+ val |= PPC_BIT(8) >> thread->id;
+ CHECK_ERR(pib_write(&chip->target, THREAD_ACTIVE_REG, val));
return 0;
}
-int ram_start_thread(struct target *thread)
+int ram_start_thread(struct thread *thread)
{
uint64_t val;
- struct target *chip = thread->next;
- int thread_id = (thread->base >> 4) & 0x7;
+ struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target);
/* Activate thread */
- CHECK_ERR(write_target(thread, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_START));
+ CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_START));
/* Restore thread active */
- CHECK_ERR(read_target(chip, THREAD_ACTIVE_REG, &val));
- val &= ~(PPC_BIT(8) >> thread_id);
- val |= PPC_BIT(thread_id);
- CHECK_ERR(write_target(chip, THREAD_ACTIVE_REG, val));
+ CHECK_ERR(pib_read(&chip->target, THREAD_ACTIVE_REG, &val));
+ val &= ~(PPC_BIT(8) >> thread->id);
+ val |= PPC_BIT(thread->id);
+ CHECK_ERR(pib_write(&chip->target, THREAD_ACTIVE_REG, val));
+
+ return 0;
+}
+
+/* We can only ram a thread if all the threads on the core/chip are
+ * quiesced */
+int ram_status(struct chiplet *chip)
+{
+ struct dt_node *dn;
+
+ dt_for_each_compatible(chip->target.dn, dn, "ibm,power8-thread") {
+ struct thread *thread;
+ thread = target_to_thread(dn->target);
+ if (!(get_thread_status(thread) & THREAD_STATUS_QUIESCE))
+ return -1;
+ }
return 0;
}
@@ -291,26 +308,32 @@ int ram_start_thread(struct target *thread)
* data. Note that only register r0 is saved and restored so opcodes
* must not touch other registers.
*/
-static int ram_instructions(struct target *thread, uint64_t *opcodes,
+static int ram_instructions(struct thread *thread, uint64_t *opcodes,
uint64_t *results, int len, unsigned int lpar)
{
uint64_t ram_mode, val, opcode, r0 = 0, r1 = 0;
- struct target *chiplet = thread->next;
- int thread_id = (thread->base >> 4) & 0x7;
+ struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target);
int i;
int exception = 0;
+ /* Check to see if the parent chip is in a state that can RAM instructions */
+ if (ram_status(chip))
+ return 1;
+
+ if (!(thread_status(thread) & THREAD_STATUS_ACTIVE))
+ return 2;
+
/* Activate RAM mode */
- CHECK_ERR(read_target(chiplet, RAM_MODE_REG, &ram_mode));
+ CHECK_ERR(pib_read(&chip->target, RAM_MODE_REG, &ram_mode));
ram_mode |= RAM_MODE_ENABLE;
- CHECK_ERR(write_target(chiplet, RAM_MODE_REG, ram_mode));
+ CHECK_ERR(pib_write(&chip->target, RAM_MODE_REG, ram_mode));
/* Setup SPRC to use SPRD */
val = SPR_MODE_SPRC_WR_EN;
val = SETFIELD(SPR_MODE_SPRC_SEL, val, 1 << (3 - lpar));
- val = SETFIELD(SPR_MODE_SPRC_T_SEL, val, 1 << (7 - thread_id));
- CHECK_ERR(write_target(chiplet, SPR_MODE_REG, val));
- CHECK_ERR(write_target(chiplet, L0_SCOM_SPRC_REG, SCOM_SPRC_SCRATCH_SPR));
+ val = SETFIELD(SPR_MODE_SPRC_T_SEL, val, 1 << (7 - thread->id));
+ CHECK_ERR(pib_write(&chip->target, SPR_MODE_REG, val));
+ CHECK_ERR(pib_write(&chip->target, L0_SCOM_SPRC_REG, SCOM_SPRC_SCRATCH_SPR));
/* RAM instructions */
for (i = -2; i < len + 2; i++) {
@@ -320,26 +343,26 @@ static int ram_instructions(struct target *thread, uint64_t *opcodes,
/* Save r0 (assumes opcodes don't touch other registers) */
opcode = mtspr(277, 0);
else if (i < len) {
- CHECK_ERR(write_target(chiplet, SCR0_REG, results[i]));
+ CHECK_ERR(pib_write(&chip->target, SCR0_REG, results[i]));
opcode = opcodes[i];
} else if (i == len) {
/* Restore r0 */
- CHECK_ERR(write_target(chiplet, SCR0_REG, r0));
+ CHECK_ERR(pib_write(&chip->target, SCR0_REG, r0));
opcode = mfspr(0, 277);
} else if (i == len + 1) {
/* Restore r1 */
- CHECK_ERR(write_target(chiplet, SCR0_REG, r1));
+ CHECK_ERR(pib_write(&chip->target, SCR0_REG, r1));
opcode = mfspr(0, 277);
}
/* ram instruction */
- val = SETFIELD(RAM_THREAD_SELECT, 0ULL, thread_id);
+ val = SETFIELD(RAM_THREAD_SELECT, 0ULL, thread->id);
val = SETFIELD(RAM_INSTR, val, opcode);
- CHECK_ERR(write_target(chiplet, RAM_CTRL_REG, val));
+ CHECK_ERR(pib_write(&chip->target, RAM_CTRL_REG, val));
/* wait for completion */
do {
- CHECK_ERR(read_target(chiplet, RAM_STATUS_REG, &val));
+ CHECK_ERR(pib_read(&chip->target, RAM_STATUS_REG, &val));
} while (!((val & PPC_BIT(1)) || ((val & PPC_BIT(2)) && (val & PPC_BIT(3)))));
if (!(val & PPC_BIT(1))) {
@@ -353,7 +376,7 @@ static int ram_instructions(struct target *thread, uint64_t *opcodes,
}
/* Save the results */
- CHECK_ERR(read_target(chiplet, SCR0_REG, &val));
+ CHECK_ERR(pib_read(&chip->target, SCR0_REG, &val));
if (i == -2)
r1 = val;
else if (i == -1)
@@ -364,7 +387,7 @@ static int ram_instructions(struct target *thread, uint64_t *opcodes,
/* Disable RAM mode */
ram_mode &= ~RAM_MODE_ENABLE;
- CHECK_ERR(write_target(chiplet, RAM_MODE_REG, ram_mode));
+ CHECK_ERR(pib_write(&chip->target, RAM_MODE_REG, ram_mode));
return exception;
}
@@ -372,7 +395,7 @@ static int ram_instructions(struct target *thread, uint64_t *opcodes,
/*
* Get gpr value. Chip must be stopped.
*/
-int ram_getgpr(struct target *thread, int gpr, uint64_t *value)
+int ram_getgpr(struct thread *thread, int gpr, uint64_t *value)
{
uint64_t opcodes[] = {mtspr(277, gpr)};
uint64_t results[] = {0};
@@ -382,7 +405,7 @@ int ram_getgpr(struct target *thread, int gpr, uint64_t *value)
return 0;
}
-int ram_putgpr(struct target *thread, int gpr, uint64_t value)
+int ram_putgpr(struct thread *thread, int gpr, uint64_t value)
{
uint64_t opcodes[] = {mfspr(gpr, 277)};
uint64_t results[] = {value};
@@ -392,7 +415,7 @@ int ram_putgpr(struct target *thread, int gpr, uint64_t value)
return 0;
}
-int ram_getnia(struct target *thread, uint64_t *value)
+int ram_getnia(struct thread *thread, uint64_t *value)
{
uint64_t opcodes[] = {mfnia(0), mtspr(277, 0)};
uint64_t results[] = {0, 0};
@@ -402,7 +425,7 @@ int ram_getnia(struct target *thread, uint64_t *value)
return 0;
}
-int ram_putnia(struct target *thread, uint64_t value)
+int ram_putnia(struct thread *thread, uint64_t value)
{
uint64_t opcodes[] = {mfspr(0, 277), mtnia(0)};
uint64_t results[] = {value, 0};
@@ -411,7 +434,7 @@ int ram_putnia(struct target *thread, uint64_t value)
return 0;
}
-int ram_getspr(struct target *thread, int spr, uint64_t *value)
+int ram_getspr(struct thread *thread, int spr, uint64_t *value)
{
uint64_t opcodes[] = {mfspr(0, spr), mtspr(277, 0)};
uint64_t results[] = {0, 0};
@@ -421,7 +444,7 @@ int ram_getspr(struct target *thread, int spr, uint64_t *value)
return 0;
}
-int ram_putspr(struct target *thread, int spr, uint64_t value)
+int ram_putspr(struct thread *thread, int spr, uint64_t value)
{
uint64_t opcodes[] = {mfspr(0, 277), mtspr(spr, 0)};
uint64_t results[] = {value, 0};
@@ -430,7 +453,7 @@ int ram_putspr(struct target *thread, int spr, uint64_t value)
return 0;
}
-int ram_getmsr(struct target *thread, uint64_t *value)
+int ram_getmsr(struct thread *thread, uint64_t *value)
{
uint64_t opcodes[] = {mfmsr(0), mtspr(277, 0)};
uint64_t results[] = {0, 0};
@@ -440,7 +463,7 @@ int ram_getmsr(struct target *thread, uint64_t *value)
return 0;
}
-int ram_putmsr(struct target *thread, uint64_t value)
+int ram_putmsr(struct thread *thread, uint64_t value)
{
uint64_t opcodes[] = {mfspr(0, 277), mtmsr(0)};
uint64_t results[] = {value, 0};
@@ -449,7 +472,7 @@ int ram_putmsr(struct target *thread, uint64_t value)
return 0;
}
-int ram_getmem(struct target *thread, uint64_t addr, uint64_t *value)
+int ram_getmem(struct thread *thread, uint64_t addr, uint64_t *value)
{
uint64_t opcodes[] = {mfspr(0, 277), mfspr(1, 277), ld(0, 0, 1), mtspr(277, 0)};
uint64_t results[] = {0xdeaddeaddeaddead, addr, 0, 0};
@@ -459,81 +482,54 @@ int ram_getmem(struct target *thread, uint64_t addr, uint64_t *value)
return 0;
}
-int thread_target_init(struct target *thread, const char *name, uint64_t thread_id, struct target *next)
-{
- target_init(thread, name, 0x13000 | (thread_id << 4), NULL, NULL, NULL, next);
- thread->status = get_thread_status(thread);
-
- /* Threads always exist, although they may not be in a useful state for most operations */
- return 0;
-}
-
/*
* Initialise all viable threads for ramming on the given chiplet.
*/
-int thread_target_probe(struct target *chiplet, struct target *targets, int max_target_count)
+static int p8_thread_probe(struct target *target)
{
- struct target *thread = targets;
- int i, count = 0;
+ struct thread *thread = target_to_thread(target);
- for (i = 0; i < THREADS_PER_CORE && i < max_target_count; i++) {
- thread_target_init(thread, "Thread", i, chiplet);
- thread++;
- count++;
- }
+ thread->id = (dt_get_address(target->dn, 0, NULL) >> 4) & 0xf;
+ thread->status = get_thread_status(thread);
- return count;
+ return 0;
}
-int chiplet_target_init(struct target *target, const char *name, uint64_t chip_id, struct target *next)
+struct thread p8_thread = {
+ .target = {
+ .name = "POWER8 Thread",
+ .compatible = "ibm,power8-thread",
+ .class = "thread",
+ .probe = p8_thread_probe,
+ },
+};
+DECLARE_HW_UNIT(p8_thread);
+
+static int p8_chiplet_probe(struct target *target)
{
- uint64_t value, base;
-
- base = 0x10000000 | (chip_id << 24);
-
- target_init(target, name, base, NULL, NULL, NULL, next);
+ uint64_t value;
+ struct chiplet *chiplet = target_to_chiplet(target);
+ int i, count = 0, rc = 0;
/* Work out if this chip is actually present */
- if (read_target(target, SCOM_EX_GP3, &value)) {
+ if (pib_read(target, SCOM_EX_GP3, &value)) {
PR_DEBUG("Error reading chip GP3 register\n");
return -1;
}
- /* Return 0 is a chip is actually present. We still leave the
- target initialised even if it isn't present as a user may
- want to continue anyway. */
- return -!GETFIELD(PPC_BIT(0), value);
-}
-
-/* Initialises all possible chiplets on the given processor
- * target. *targets should point to pre-allocated memory with enough
- * free space for the maximum number of targets. Returns the number of
- * chips found. */
-int chiplet_target_probe(struct target *processor, struct target *targets, int max_target_count)
-{
- struct target *target = targets;
- int i, count = 0, rc = 0;
-
- /* P9 chiplets are not currently supported */
- if (processor->chip_type == CHIP_P9)
- return 0;
-
- for (i = 0; i <= 0xf && i < max_target_count; i++) {
- if (i == 0 || i == 7 || i == 8 || i == 0xf)
- /* 0, 7, 8 & 0xf are reserved */
- continue;
-
- if (!(rc = chiplet_target_init(target, "Chiplet", i, processor))) {
- assert_special_wakeup(target);
- target++;
- count++;
- } else
- target_del(target);
- }
-
- if (rc)
- /* The last target is invalid, zero it out */
- memset(target, 0, sizeof(*target));
+ if (!GETFIELD(PPC_BIT(0), value))
+ return -1;
- return count;
+ assert_special_wakeup(chiplet);
+ return 0;
}
+
+struct chiplet p8_chiplet = {
+ .target = {
+ .name = "POWER8 Chiplet",
+ .compatible = "ibm,power8-core",
+ .class = "chiplet",
+ .probe = p8_chiplet_probe,
+ },
+};
+DECLARE_HW_UNIT(p8_chiplet);
OpenPOWER on IntegriCloud