summaryrefslogtreecommitdiffstats
path: root/libpdbg
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2018-04-27 14:08:51 +1000
committerAlistair Popple <alistair@popple.id.au>2018-04-27 14:08:51 +1000
commitad058f045c4403346c92ddd9115397a939b44a79 (patch)
tree83659a06243db24d7d860c59af7d343bb02bd03a /libpdbg
parentd74029ccdd3bb680e3753a07df4ff60c3e18aea2 (diff)
downloadpdbg-ad058f045c4403346c92ddd9115397a939b44a79.tar.gz
pdbg-ad058f045c4403346c92ddd9115397a939b44a79.zip
libpdbg: Add support for getring on POWER9
Add basic support for a getring operation on POWER9. Signed-off-by: Alistair Popple <alistair@popple.id.au>
Diffstat (limited to 'libpdbg')
-rw-r--r--libpdbg/chip.c12
-rw-r--r--libpdbg/libpdbg.h2
-rw-r--r--libpdbg/p9chip.c99
-rw-r--r--libpdbg/target.c22
-rw-r--r--libpdbg/target.h2
5 files changed, 133 insertions, 4 deletions
diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index 06ea4e9..79bc87d 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -272,3 +272,15 @@ int ram_getmem(struct pdbg_target *thread, uint64_t addr, uint64_t *value)
*value = results[3];
return 0;
}
+
+/*
+ * Read the given ring from the given chiplet. Result must be large enough to hold ring_len bits.
+ */
+int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[])
+{
+ struct chiplet *chiplet;
+
+ assert(!strcmp(chiplet_target->class, "chiplet"));
+ chiplet = target_to_chiplet(chiplet_target);
+ return chiplet->getring(chiplet, ring_addr, ring_len, result);
+}
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index 15537b8..f843816 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -78,6 +78,7 @@ int fsi_write(struct pdbg_target *target, uint32_t addr, uint32_t val);
int pib_read(struct pdbg_target *target, uint64_t addr, uint64_t *val);
int pib_write(struct pdbg_target *target, uint64_t addr, uint64_t val);
+int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data);
int ram_putmsr(struct pdbg_target *target, uint64_t val);
int ram_putnia(struct pdbg_target *target, uint64_t val);
@@ -92,6 +93,7 @@ int ram_step_thread(struct pdbg_target *target, int steps);
int ram_stop_thread(struct pdbg_target *target);
int ram_sreset_thread(struct pdbg_target *target);
uint64_t thread_status(struct pdbg_target *target);
+int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]);
#define THREAD_STATUS_DISABLED PPC_BIT(0)
#define THREAD_STATUS_ACTIVE PPC_BIT(63)
diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c
index 41f694e..380cb59 100644
--- a/libpdbg/p9chip.c
+++ b/libpdbg/p9chip.c
@@ -35,11 +35,34 @@
#define P9_SPR_MODE 0x10a84
#define P9_SCR0_REG 0x10a86
+#define CHIPLET_CTRL0_WOR 0x10
+#define CHIPLET_CTRL0_CLEAR 0x20
+#define CHIPLET_CTRL0_CTRL_CC_ABIST_MUXSEL_DC PPC_BIT(0)
+#define CHIPLET_CTRL0_TC_UNIT_SYNCCLK_MUXSEL_DC PPC_BIT(1)
+#define CHIPLET_CTRL0_CTRL_CC_FLUSHMODE_INH_DC PPC_BIT(2)
+
+#define CHIPLET_CTRL1_WOR 0x11
+#define CHIPLET_CTRL1_TC_VITL_REGION_FENCE PPC_BIT(3)
+
+#define CHIPLET_STAT0 0x100
+#define CHIPLET_STAT0_CC_CTRL_OPCG_DONE_DC PPC_BIT(8)
+
+#define CHIPLET_SCAN_REGION_TYPE 0x30005
+#define CHIPLET_CLK_REGION 0x30006
+#define CHIPLET_CLK_REGION_CLOCK_CMD PPC_BITMASK(0, 1)
+#define CHIPLET_CLK_REGION_CLOCK_CMD_STOP 0x2
+#define CHIPLET_CLK_REGION_SLAVE_MODE PPC_BIT(2)
+#define CHIPLET_CLK_REGION_MASTER_MODE PPC_BIT(3)
+#define CHIPLET_CLK_REGION_REGIONS PPC_BITMASK(4, 14)
+#define CHIPLET_CLK_REGION_SEL_THOLD PPC_BITMASK(48, 50)
+
/* PCB Slave Registers */
-#define NET_CTRL0 0xf0040
-#define NET_CTRL0_CHIPLET_ENABLE PPC_BIT(0)
-#define PPM_GPMMR 0xf0100
-#define PPM_SPWKUP_OTR 0xf010a
+#define NET_CTRL0 0xf0040
+#define NET_CTRL0_CHIPLET_ENABLE PPC_BIT(0)
+#define NET_CTRL0_FENCE_EN PPC_BIT(18)
+#define NET_CTRL0_WOR 0xf0042
+#define PPM_GPMMR 0xf0100
+#define PPM_SPWKUP_OTR 0xf010a
#define SPECIAL_WKUP_DONE PPC_BIT(1)
#define RAS_STATUS_TIMEOUT 100
@@ -215,6 +238,73 @@ struct thread p9_thread = {
};
DECLARE_HW_UNIT(p9_thread);
+#define HEADER_CHECK_DATA ((uint64_t) 0xc0ffee03 << 32)
+
+static int p9_chiplet_getring(struct chiplet *chiplet, uint64_t ring_addr, int64_t ring_len, uint32_t result[])
+{
+ uint64_t scan_type_addr;
+ uint64_t scan_data_addr;
+ uint64_t scan_header_addr;
+ uint64_t scan_type_data;
+ uint64_t set_pulse = 1;
+ uint64_t bits = 32;
+ uint64_t data;
+
+ /* We skip the first word in the results so we can write it later as it
+ * should contain the header read out at the end */
+ int i = 0;
+
+ scan_type_addr = (ring_addr & 0x7fff0000) | 0x7;
+ scan_data_addr = (scan_type_addr & 0xffff0000) | 0x8000;
+ scan_header_addr = scan_data_addr & 0xffffe000;
+
+ scan_type_data = (ring_addr & 0xfff0) << 13;
+ scan_type_data |= 0x800 >> (ring_addr & 0xf);
+ scan_type_data <<= 32;
+
+ pib_write(&chiplet->target, scan_type_addr, scan_type_data);
+ pib_write(&chiplet->target, scan_header_addr, HEADER_CHECK_DATA);
+
+ /* The final 32 bit read is the header which we do at the end */
+ ring_len -= 32;
+ i = 1;
+
+ while (ring_len > 0) {
+ ring_len -= bits;
+ if (set_pulse) {
+ scan_data_addr |= 0x4000;
+ set_pulse = 0;
+ } else
+ scan_data_addr &= ~0x4000ULL;
+
+ scan_data_addr &= ~0xffull;
+ scan_data_addr |= bits;
+ pib_read(&chiplet->target, scan_data_addr, &data);
+
+ /* Discard lower 32 bits */
+ /* TODO: We always read 64-bits from the ring on P9 so we could
+ * optimise here by reading 64-bits at a time, but I'm not
+ * confident I've figured that out and 32-bits is what Hostboot
+ * does and seems to work. */
+ data >>= 32;
+
+ /* Left-align data */
+ data <<= 32 - bits;
+ result[i++] = data;
+ if (ring_len > 0 && (ring_len < bits))
+ bits = ring_len;
+ }
+
+ pib_read(&chiplet->target, scan_header_addr | 0x20, &data);
+ data &= 0xffffffff00000000;
+ result[0] = data >> 32;
+ if (data != HEADER_CHECK_DATA)
+ printf("WARNING: Header check failed. Make sure you specified the right ring length!\n"
+ "Ring data is probably corrupt now.\n");
+
+ return 0;
+}
+
static int p9_core_probe(struct pdbg_target *target)
{
int i = 0;
@@ -271,5 +361,6 @@ struct chiplet p9_chiplet = {
.class = "chiplet",
.probe = p9_chiplet_probe,
},
+ .getring = p9_chiplet_getring,
};
DECLARE_HW_UNIT(p9_chiplet);
diff --git a/libpdbg/target.c b/libpdbg/target.c
index 7e42b58..704d7d5 100644
--- a/libpdbg/target.c
+++ b/libpdbg/target.c
@@ -139,6 +139,28 @@ int pib_write(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data)
return rc;
}
+/* Wait for a SCOM register addr to match value & mask == data */
+int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data)
+{
+ struct pib *pib;
+ uint64_t tmp;
+ int rc;
+
+ pib_dt = get_class_target_addr(pib_dt, "pib", &addr);
+ pib = target_to_pib(pib_dt);
+
+ do {
+ if (addr & PPC_BIT(0))
+ rc = pib_indirect_read(pib, addr, &tmp);
+ else
+ rc = pib->read(pib, addr, &tmp);
+ if (rc)
+ return rc;
+ } while ((tmp & mask) != data);
+
+ return 0;
+}
+
int opb_read(struct pdbg_target *opb_dt, uint32_t addr, uint32_t *data)
{
struct opb *opb;
diff --git a/libpdbg/target.h b/libpdbg/target.h
index dc91d68..eba26cb 100644
--- a/libpdbg/target.h
+++ b/libpdbg/target.h
@@ -157,5 +157,7 @@ struct thread {
/* Place holder for chiplets which we just want translation for */
struct chiplet {
struct pdbg_target target;
+ int (*getring)(struct chiplet *, uint64_t, int64_t, uint32_t[]);
};
+#define target_to_chiplet(x) container_of(x, struct chiplet, target)
#endif
OpenPOWER on IntegriCloud