summaryrefslogtreecommitdiffstats
path: root/libpdbg/p8chip.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpdbg/p8chip.c')
-rw-r--r--libpdbg/p8chip.c131
1 files changed, 128 insertions, 3 deletions
diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c
index cd4a50b..1202caa 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -29,6 +29,7 @@
#define RAS_STATUS_TIMEOUT 100
#define DIRECT_CONTROLS_REG 0x0
+#define DIRECT_CONTROL_SP_SRESET PPC_BIT(60)
#define DIRECT_CONTROL_SP_STEP PPC_BIT(61)
#define DIRECT_CONTROL_SP_START PPC_BIT(62)
#define DIRECT_CONTROL_SP_STOP PPC_BIT(63)
@@ -314,10 +315,60 @@ static int p8_thread_start(struct thread *thread)
return 0;
}
-static int p8_thread_sreset(struct thread *thread)
+static void p8_ram_unquiesce_siblings(struct thread *thread)
+{
+ struct pdbg_target *target;
+ struct core *chip = target_to_core(
+ pdbg_target_require_parent("core", &thread->target));
+
+ pdbg_for_each_compatible(&chip->target, target, "ibm,power8-thread") {
+ struct thread *tmp;
+
+ if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED)
+ continue;
+
+ tmp = target_to_thread(target);
+ if (!tmp->status.quiesced)
+ continue;
+
+ if (!tmp->ram_did_quiesce)
+ continue;
+
+ p8_thread_start(tmp);
+
+ tmp->ram_did_quiesce = false;
+ }
+}
+
+static int p8_ram_quiesce_siblings(struct thread *thread)
{
- /* Broken on p8 */
- return 1;
+ struct pdbg_target *target;
+ struct core *chip = target_to_core(
+ pdbg_target_require_parent("core", &thread->target));
+ int rc = 0;
+
+ pdbg_for_each_compatible(&chip->target, target, "ibm,power8-thread") {
+ struct thread *tmp;
+
+ if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED)
+ continue;
+
+ tmp = target_to_thread(target);
+ if (tmp->status.quiesced)
+ continue;
+
+ rc = p8_thread_stop(tmp);
+ if (rc)
+ break;
+ tmp->ram_did_quiesce = true;
+ }
+
+ if (!rc)
+ return 0;
+
+ p8_ram_unquiesce_siblings(thread);
+
+ return rc;
}
static int p8_ram_setup(struct thread *thread)
@@ -458,6 +509,80 @@ static int p8_ram_putxer(struct pdbg_target *thread, uint64_t value)
return 0;
}
+#define SPR_SRR0 0x01a
+#define SPR_SRR1 0x01b
+
+#define HID0_HILE PPC_BIT(19)
+
+#define MSR_HV PPC_BIT(3) /* Hypervisor mode */
+#define MSR_EE PPC_BIT(48) /* External Int. Enable */
+#define MSR_PR PPC_BIT(49) /* Problem State */
+#define MSR_FE0 PPC_BIT(52) /* FP Exception 0 */
+#define MSR_FE1 PPC_BIT(55) /* FP Exception 1 */
+#define MSR_IR PPC_BIT(58) /* Instructions reloc */
+#define MSR_DR PPC_BIT(59) /* Data reloc */
+#define MSR_RI PPC_BIT(62) /* Recoverable Interrupt */
+#define MSR_LE PPC_BIT(63) /* Little Endian */
+
+static int p8_get_hid0(struct pdbg_target *chip, uint64_t *value);
+static int emulate_sreset(struct thread *thread)
+{
+ struct pdbg_target *chip = pdbg_target_parent("core", &thread->target);
+ uint64_t hid0;
+ uint64_t old_nia, old_msr;
+ uint64_t new_nia, new_msr;
+
+ printf("emulate sreset begin\n");
+ CHECK_ERR(p8_get_hid0(chip, &hid0));
+ printf("emulate sreset HILE=%d\n", !!(hid0 & HID0_HILE));
+ CHECK_ERR(ram_getnia(&thread->target, &old_nia));
+ CHECK_ERR(ram_getmsr(&thread->target, &old_msr));
+ new_nia = 0x100;
+ new_msr = (old_msr & ~(MSR_PR | MSR_IR | MSR_DR | MSR_FE0 | MSR_FE1 | MSR_EE | MSR_RI)) | MSR_HV;
+ if (hid0 & HID0_HILE)
+ new_msr |= MSR_LE;
+ else
+ new_msr &= ~MSR_LE;
+ printf("emulate sreset old NIA: 0x%016" PRIx64 " MSR: 0x%016" PRIx64 "\n", old_nia, old_msr);
+ printf("emulate sreset new NIA: 0x%016" PRIx64 " MSR: 0x%016" PRIx64 "\n", new_nia, new_msr);
+ CHECK_ERR(ram_putspr(&thread->target, SPR_SRR0, old_nia));
+ CHECK_ERR(ram_putspr(&thread->target, SPR_SRR1, old_msr));
+ CHECK_ERR(ram_putnia(&thread->target, new_nia));
+ CHECK_ERR(ram_putmsr(&thread->target, new_msr));
+ printf("emulate sreset done\n");
+
+ return 0;
+}
+
+static int p8_thread_sreset(struct thread *thread)
+{
+ int rc;
+
+ if (!(thread->status.active)) {
+ CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_SRESET));
+ thread->status = get_thread_status(thread);
+
+ return 0;
+ }
+
+ rc = p8_ram_quiesce_siblings(thread);
+ if (rc)
+ return rc;
+
+ /* Thread was active, emulate the sreset */
+ rc = p8_ram_setup(thread);
+ if (rc) {
+ p8_ram_unquiesce_siblings(thread);
+ return rc;
+ }
+ rc = emulate_sreset(thread);
+ p8_ram_destroy(thread);
+ p8_ram_unquiesce_siblings(thread);
+ if (rc)
+ return rc;
+ return p8_thread_start(thread);
+}
+
/*
* Initialise all viable threads for ramming on the given core.
*/
OpenPOWER on IntegriCloud