[Pdbg] [PATCH 01/10] sbefifo: Refactor ffdc parsing code to store ffdc data

Amitay Isaacs amitay at ozlabs.org
Wed Jul 3 13:46:10 AEST 2019


Instead of dumping ffdc data, store it so an application can query it in
case of chip-op failures.

FFDC data is stored only for the last chip-op.

Signed-off-by: Amitay Isaacs <amitay at ozlabs.org>
---
 libpdbg/hwunit.h  |   3 ++
 libpdbg/sbefifo.c | 116 +++++++++++++++++++++++++++++++++++-----------
 2 files changed, 91 insertions(+), 28 deletions(-)

diff --git a/libpdbg/hwunit.h b/libpdbg/hwunit.h
index b816ae3..0b0c62b 100644
--- a/libpdbg/hwunit.h
+++ b/libpdbg/hwunit.h
@@ -71,6 +71,9 @@ struct sbefifo {
 	int (*mem_read)(struct sbefifo *, uint64_t, uint8_t *, uint64_t, bool);
 	int (*mem_write)(struct sbefifo *, uint64_t, uint8_t *, uint64_t, bool);
 	int fd;
+	uint32_t status;
+	uint8_t *ffdc;
+	uint32_t ffdc_len;
 };
 #define target_to_sbefifo(x) container_of(x, struct sbefifo, target)
 
diff --git a/libpdbg/sbefifo.c b/libpdbg/sbefifo.c
index 284d3d5..a23d0b4 100644
--- a/libpdbg/sbefifo.c
+++ b/libpdbg/sbefifo.c
@@ -69,22 +69,76 @@ static int sbefifo_op_write(struct sbefifo *sbefifo, void *buf, size_t buflen)
 	return 0;
 }
 
-static int sbefifo_op_ffdc_read(uint8_t *buf, uint32_t buflen)
+static void sbefifo_ffdc_clear(struct sbefifo *sbefifo)
 {
-	int offset = 0;
+	sbefifo->status = 0;
+	if (sbefifo->ffdc) {
+		free(sbefifo->ffdc);
+		sbefifo->ffdc = NULL;
+		sbefifo->ffdc_len = 0;
+	}
+}
+
+static void sbefifo_ffdc_set(struct sbefifo *sbefifo, uint8_t *buf, uint32_t buflen, uint32_t status)
+{
+	sbefifo->status = status;
+
+	sbefifo->ffdc = malloc(buflen);
+	if (!sbefifo->ffdc) {
+		PR_ERROR("sbefifo: Failed to store FFDC data\n");
+		return;
+	}
+
+	memcpy(sbefifo->ffdc, buf, buflen);
+	sbefifo->ffdc_len = buflen;
+}
+
+static int sbefifo_ffdc_get_uint32(struct sbefifo *sbefifo, uint32_t offset, uint32_t *value)
+{
+	uint32_t v;
+
+	if (offset + 4 > sbefifo->ffdc_len)
+		return -1;
+
+	memcpy(&v, sbefifo->ffdc + offset, 4);
+	*value = be32toh(v);
+
+	return 0;
+}
+
+static int sbefifo_ffdc_dump_pkg(struct sbefifo *sbefifo, uint32_t offset)
+{
+	uint32_t offset2 = offset;
 	uint32_t header, value;
 	uint16_t magic, len_words;
-	int i;
+	int i, rc;
 
-	if (buflen < 4)
+	rc = sbefifo_ffdc_get_uint32(sbefifo, offset2, &header);
+	if (rc < 0)
 		return -1;
+	offset2 += 4;
 
-	/* End of ffdc data */
-	if (buflen == 4)
-		return 0;
-
-	header = be32toh(*(uint32_t *)(buf + offset));
-	offset += 4;
+	/*
+	 * FFDC package structure
+	 *
+	 *             +----------+----------+----------+----------+
+	 *             |  Byte 0  |  Byte 1  |  Byte 2  |  Byte  3 |
+	 *  +----------+----------+----------+----------+----------+
+	 *  |  word 0  |        magic        | length in words (N) |
+	 *  +----------+---------------------+---------------------+
+	 *  |  word 1  |      sequence id    |       command       |
+	 *  +----------+---------------------+---------------------+
+	 *  |  word 2  |              return code                  |
+	 *  +----------+-------------------------------------------+
+	 *  |  word 3  |            FFDC Data - word 0             |
+	 *  +----------+-------------------------------------------+
+	 *  |  word 4  |            FFDC Data - word 1             |
+	 *  +----------+-------------------------------------------+
+	 *  |    ...   |                    ...                    |
+	 *  +----------+-------------------------------------------+
+	 *  |  word N  |            FFDC Data - word N-3           |
+	 *  +----------+----------+----------+----------+----------+
+	 */
 
 	magic = header >> 16;
 	if (magic != 0xffdc) {
@@ -93,44 +147,47 @@ static int sbefifo_op_ffdc_read(uint8_t *buf, uint32_t buflen)
 	}
 
 	len_words = header & 0xffff;
-	if (offset + len_words * 4 > buflen)
-		return -1;
 
-	value = be32toh(*(uint32_t *)(buf + offset));
-	offset += 4;
+	rc = sbefifo_ffdc_get_uint32(sbefifo, offset2, &value);
+	if (rc < 0)
+		return -1;
+	offset2 += 4;
 
 	PR_ERROR("FFDC: Sequence = %u\n", value >> 16);
 	PR_ERROR("FFDC: Command = 0x%08x\n", value & 0xffff);
 
-	value = be32toh(*(uint32_t *)(buf + offset));
-	offset += 4;
+	rc = sbefifo_ffdc_get_uint32(sbefifo, offset2, &value);
+	if (rc < 0)
+		return -1;
+	offset2 += 4;
 
 	PR_ERROR("FFDC: RC = 0x%08x\n", value);
 
 	for (i=0; i<len_words-3; i++) {
-		value = be32toh(*(uint32_t *)(buf + offset));
-		offset += 4;
+		rc = sbefifo_ffdc_get_uint32(sbefifo, offset2, &value);
+		if (rc < 0)
+			return -1;
+		offset2 += 4;
 
 		PR_ERROR("FFDC: Data: 0x%08x\n", value);
 	}
 
-	return offset;
+	return offset2 - offset;
 }
 
-static int sbefifo_op_ffdc(uint8_t *buf, uint32_t buflen)
+static void sbefifo_ffdc_dump(struct sbefifo *sbefifo)
 {
 	uint32_t offset = 0;
-	int rc;
 
-	while (1) {
-		rc = sbefifo_op_ffdc_read(buf + offset, buflen - offset);
-		if (rc <= 0)
+	while (offset < sbefifo->ffdc_len) {
+		int n;
+
+		n = sbefifo_ffdc_dump_pkg(sbefifo, offset);
+		if (n <= 0)
 			break;
 
-		offset += rc;
+		offset += n;
 	}
-
-	return rc;
 }
 
 static int sbefifo_op(struct sbefifo *sbefifo,
@@ -144,6 +201,8 @@ static int sbefifo_op(struct sbefifo *sbefifo,
 	uint16_t value;
 	int rc;
 
+	sbefifo_ffdc_clear(sbefifo);
+
 	assert(msg_len > 0);
 
 	/* Allocate extra memory for FFDC (SBEFIFO_MAX_FFDC_SIZE = 0x2000) */
@@ -200,7 +259,8 @@ static int sbefifo_op(struct sbefifo *sbefifo,
 		return 0;
 	} else {
 		PR_ERROR("sbefifo: Operation failed, response=0x%08x\n", resp[1]);
-		sbefifo_op_ffdc(buf + offset, buflen - offset);
+		sbefifo_ffdc_set(sbefifo, buf + offset, buflen - offset - 4, resp[1]);
+		sbefifo_ffdc_dump(sbefifo);
 	}
 
 fail:
-- 
2.21.0



More information about the Pdbg mailing list