summaryrefslogtreecommitdiffstats
path: root/libpdbg/p8chip.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpdbg/p8chip.c')
-rw-r--r--libpdbg/p8chip.c67
1 files changed, 58 insertions, 9 deletions
diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c
index b93e953..71e6569 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -163,16 +163,11 @@ static int assert_special_wakeup(struct core *chip)
return 0;
}
-#if 0
-/* TODO: Work out when to do this. */
-static int deassert_special_wakeup(struct core *chip)
+static void deassert_special_wakeup(struct core *chip)
{
/* Assert special wakeup to prevent low power states */
- CHECK_ERR(pib_write(&chip->target, PMSPCWKUPFSP_REG, 0));
-
- return 0;
+ pib_write(&chip->target, PMSPCWKUPFSP_REG, 0);
}
-#endif
static struct thread_state get_thread_status(struct thread *thread)
{
@@ -318,6 +313,8 @@ static int p8_thread_stop(struct thread *thread)
val |= PPC_BIT(8) >> thread->id;
CHECK_ERR(pib_write(&chip->target, THREAD_ACTIVE_REG, val));
+ thread->status = get_thread_status(thread);
+
return 0;
}
@@ -336,6 +333,8 @@ static int p8_thread_start(struct thread *thread)
val |= PPC_BIT(thread->id);
CHECK_ERR(pib_write(&chip->target, THREAD_ACTIVE_REG, val));
+ thread->status = get_thread_status(thread);
+
return 0;
}
@@ -366,7 +365,7 @@ static int p8_ram_setup(struct thread *thread)
return 1;
tmp = target_to_thread(target);
- if (!(get_thread_status(tmp).quiesced))
+ if (!tmp->status.quiesced)
return 1;
}
@@ -487,6 +486,16 @@ static int p8_thread_probe(struct pdbg_target *target)
return 0;
}
+static void p8_thread_release(struct pdbg_target *target)
+{
+ struct core *core = target_to_core(pdbg_target_require_parent("core", target));
+ struct thread *thread = target_to_thread(target);
+
+ if (thread->status.quiesced)
+ /* this thread is still quiesced so don't release spwkup */
+ core->release_spwkup = false;
+}
+
static int p8_get_hid0(struct pdbg_target *chip, uint64_t *value)
{
CHECK_ERR(pib_read(chip, HID0_REG, value));
@@ -534,6 +543,7 @@ static struct thread p8_thread = {
.compatible = "ibm,power8-thread",
.class = "thread",
.probe = p8_thread_probe,
+ .release = p8_thread_release,
},
.step = p8_thread_step,
.start = p8_thread_start,
@@ -562,16 +572,55 @@ static int p8_core_probe(struct pdbg_target *target)
if (!GETFIELD(PPC_BIT(0), value))
return -1;
- assert_special_wakeup(core);
+ if (assert_special_wakeup(core))
+ return -1;
+
+ /* Child threads will set this to false if they are released while quiesced */
+ core->release_spwkup = true;
+
return 0;
}
+static void p8_core_release(struct pdbg_target *target)
+{
+ struct pdbg_target *child;
+ struct core *core = target_to_core(target);
+ enum pdbg_target_status status;
+
+ usleep(1); /* enforce small delay before and after it is cleared */
+
+ /* Probe and release all threads to ensure release_spwkup is up to
+ * date */
+ pdbg_for_each_target("thread", target, child) {
+ status = pdbg_target_status(child);
+
+ /* This thread has already been release so should have set
+ * release_spwkup to false if it was quiesced, */
+ if (status == PDBG_TARGET_RELEASED)
+ continue;
+
+ status = pdbg_target_probe(child);
+ if (status != PDBG_TARGET_ENABLED)
+ continue;
+
+ /* Release the thread to ensure release_spwkup is updated. */
+ pdbg_target_release(child);
+ }
+
+ if (!core->release_spwkup)
+ return;
+
+ deassert_special_wakeup(core);
+ usleep(10000);
+}
+
static struct core p8_core = {
.target = {
.name = "POWER8 Core",
.compatible = "ibm,power8-core",
.class = "core",
.probe = p8_core_probe,
+ .release = p8_core_release,
},
};
DECLARE_HW_UNIT(p8_core);
OpenPOWER on IntegriCloud