diff mbox series

[v2,4/9] libpdbg: Add nhtm hardware unit for p10

Message ID 20211125004138.120917-5-jniethe5@gmail.com
State Accepted
Headers show
Series Add P10 HTM support | expand

Commit Message

Jordan Niethe Nov. 25, 2021, 12:41 a.m. UTC
p10 also has a Nest HTM. The biggest change is that on p10 there are two
nhtm units. Add support for it.

Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
v2: HTM1 -> HTM2 etc
    replace reg_off() with dual_htm_offset
---
 libpdbg/htm.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 221 insertions(+), 17 deletions(-)
diff mbox series

Patch

diff --git a/libpdbg/htm.c b/libpdbg/htm.c
index 43cef84522ef..419ac287e760 100644
--- a/libpdbg/htm.c
+++ b/libpdbg/htm.c
@@ -35,6 +35,7 @@ 
 			rc;})
 
 #define MIN(x,y) ((x < y) ? x : y)
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
 
 #define DEBUGFS_POWERPC "/sys/kernel/debug/powerpc"
 #define DEBUGFS_SCOM DEBUGFS_POWERPC"/scom"
@@ -75,10 +76,34 @@ 
 #define   HTM_MEM_SCOPE			PPC_BITMASK(1,3)
 /* Note: the next 3 change on P9 */
 #define   HTM_MEM_PRIORITY		PPC_BITMASK(4,5)
+#define   HTM_MEM_PRIORITY_P10		PPC_BITMASK(4)
 #define   HTM_MEM_SIZE_SMALL		PPC_BIT(13)
+#define   HTM_MEM_SIZE_SMALL_P10	PPC_BIT(5)
 #define   HTM_MEM_BASE			PPC_BITMASK(14,39)
+#define   HTM_MEM_BASE_P10		PPC_BITMASK(8,39)
 #define	  HTM_MEM_SIZE			PPC_BITMASK(40,48)
 #define HTM_STATUS			2
+#define   HTM2_STATUS_MASK		PPC_BITMASK(22,39)
+#define   HTM2_STATUS_CRESP_OV		PPC_BIT(22)
+#define	  HTM2_STATUS_REPAIR		PPC_BIT(23)
+#define   HTM2_STATUS_BUF_WAIT		PPC_BIT(24)
+#define   HTM2_STATUS_TRIG_DROPPED	PPC_BIT(25)
+#define   HTM2_STATUS_ADDR_ERROR	PPC_BIT(26)
+#define   HTM2_STATUS_REC_DROPPED	PPC_BIT(27)
+#define   HTM2_STATUS_INIT		PPC_BIT(28)
+#define   HTM2_STATUS_PREREQ		PPC_BIT(29)
+#define   HTM2_STATUS_READY		PPC_BIT(30)
+#define   HTM2_STATUS_TRACING		PPC_BIT(31)
+#define   HTM2_STATUS_PAUSED		PPC_BIT(32)
+#define   HTM2_STATUS_FLUSH		PPC_BIT(33)
+#define   HTM2_STATUS_COMPLETE		PPC_BIT(34)
+#define   HTM2_STATUS_ENABLE		PPC_BIT(35)
+#define   HTM2_STATUS_STAMP		PPC_BIT(36)
+#define   HTM2_STATUS_SCOM_ERROR	PPC_BIT(37)
+#define   HTM2_STATUS_PARITY_ERROR	PPC_BIT(38)
+#define   HTM2_STATUS_INVALID_CRESP	PPC_BIT(39)
+#define   HTM2_STATUS_STATE_MASK	(PPC_BITMASK(28,36) | HTM_STATUS_REPAIR)
+#define	  HTM2_STATUS_ERROR_MASK	(HTM_STATUS_CRESP_OV | PPC_BITMASK(24,27) | PPC_BITMASK(37,39))
 #define   HTM_STATUS_MASK		PPC_BITMASK(2,19)
 #define   HTM_STATUS_CRESP_OV		PPC_BIT(2)
 #define	  HTM_STATUS_REPAIR		PPC_BIT(3)
@@ -102,7 +127,9 @@ 
 #define	  HTM_STATUS_ERROR_MASK		(HTM_STATUS_CRESP_OV | PPC_BITMASK(4,7) | PPC_BITMASK(17,19))
 #define HTM_LAST_ADDRESS		3
 #define   HTM_LAST_ADDRESS_MASK		PPC_BITMASK(8,56)
-#define HTM_SCOM_TRIGGER		4
+#define HTM2_LAST_ADDRESS		4
+#define   HTM2_LAST_ADDRESS_MASK	PPC_BITMASK(8,56)
+#define HTM_SCOM_TRIGGER		(4 + dual_htm_offset)
 #define	  HTM_TRIG_START		PPC_BIT(0)
 #define   HTM_TRIG_STOP			PPC_BIT(1)
 #define   HTM_TRIG_PAUSE		PPC_BIT(2)
@@ -110,28 +137,49 @@ 
 #define   HTM_TRIG_RESET		PPC_BIT(4)
 #define   HTM_TRIG_MARK_VALID		PPC_BIT(5)
 #define   HTM_TRIG_MARK_TYPE		PPC_BITMASK(6,15)
-#define HTM_TRIGGER_CONTROL		5
+#define HTM_TRIGGER_CONTROL		(5 + dual_htm_offset)
 #define   HTM_CTRL_TRIG			PPC_BITMASK(0,1)
 #define   HTM_CTRL_MASK			PPC_BITMASK(4,5)
 #define   HTM_CTRL_XSTOP_STOP		PPC_BIT(13)
-#define NHTM_FILTER_CONTROL		6
+#define NHTM_FILTER_CONTROL		(6 + dual_htm_offset)
 #define   NHTM_FILTER_RCMD_SCOPE	PPC_BITMASK(17,19)
 #define   NHTM_FILTER_RCMD_SOURCE	PPC_BITMASK(20,21)
 #define   NHTM_FILTER_CRESP_PATTERN	PPC_BITMASK(27,31)
 #define   NHTM_FILTER_MASK		PPC_BITMASK(32,54)
 #define   NHTM_FILTER_CRESP_MASK	PPC_BITMASK(59,63)
-#define NHTM_TTYPE_FILTER_CONTROL	7
+#define NHTM_TTYPE_FILTER_CONTROL	(7 + dual_htm_offset)
 #define   NHTM_TTYPE_TYPE_MASK		PPC_BITMASK(17,23)
 #define   NHTM_TTYPE_SIZE_MASK		PPC_BITMASK(24,31)
-#define NHTM_CONFIGURATION		8
+#define NHTM_CONFIGURATION		(8 + dual_htm_offset)
 #define   NHTM_CONF_HANG_DIV_RATIO	PPC_BITMASK(0,4)
 #define   NHTM_CONF_RTY_DROP_COUNT	PPC_BITMASK(5,8)
 #define   NHTM_CONF_DROP_PRIORITY_INC	PPC_BIT(9)
 #define   NHTM_CONF_RETRY_BACKOFF	PPC_BIT(10)
 #define   NHTM_CONF_OPERALIONAL_HANG	PPC_BIT(11)
-#define NHTM_FLEX_MUX			9
+#define NHTM_FLEX_MUX			(9 + dual_htm_offset)
 #define   NHTM_FLEX_MUX_MASK		PPC_BITMASK(0,35)
 #define   NHTM_FLEX_DEFAULT		0xCB3456129
+#define   NHTM_FLEX_MUX_MASK_P10	PPC_BITMASK(0,39)
+#define   NHTM_FLEX_DEFAULT_P10		0xCB34561567
+#define NHTM_ADDR_PAT			0xb
+#define   NHTM_ADDR_PAT_MASK		PPC_BITMASK(0, 55)
+#define NHTM_ADDR_MASK			0xc
+#define   NHTM_ADDR_MASK_MASK		PPC_BITMASK(0, 55)
+#define NHTM_STOP_FILTER		0xd
+#define   NHTM_STOP_FILTER_TTAG_PAT	PPC_BITMASK(0, 14)
+#define   NHTM_STOP_FILTER_TTAG_MASK	PPC_BITMASK(15, 29)
+#define   NHTM_STOP_FILTER_TTYPE_PAT	PPC_BITMASK(30, 36)
+#define   NHTM_STOP_FILTER_TTYPE_MASK	PPC_BITMASK(37, 43)
+#define   NHTM_STOP_FILTER_CRESP_PAT	PPC_BITMASK(44, 48)
+#define   NHTM_STOP_FILTER_CRESP_MASK	PPC_BITMASK(49, 53)
+#define   NHTM_STOP_CYCLES		PPC_BITMASK(54, 60)
+#define NHTM_STOP_FILT_ADDR_PAT		0xe
+#define   NHTM_STOP_FILT_ADDR_PAT_MASK	PPC_BITMASK(0, 55)
+#define NHTM_STOP_FILT_ADDR_MASK	0xf
+#define   NHTM_STOP_FILT_ADDR_MASK_MASK	PPC_BITMASK(0, 55)
+
+/* On P10 there are two nhtms which shifts some of the registers */
+static int dual_htm_offset;
 
 enum htm_state {
 	INIT,
@@ -161,11 +209,14 @@  enum htm_error {
 
 struct htm_status {
 	enum htm_state state;
+	enum htm_state state2;
 	enum htm_error error;
+	enum htm_error error2;
 	bool mem_size_select;
 	uint16_t mem_size;
 	uint64_t mem_base;
 	uint64_t mem_last;
+	uint64_t mem_last2;
 	uint64_t raw;
 };
 
@@ -292,6 +343,37 @@  static int get_status(struct htm *htm, struct htm_status *status)
 		status->error = NONE;
 	}
 
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm")) {
+		switch (status->raw & HTM2_STATUS_ERROR_MASK) {
+		case HTM2_STATUS_CRESP_OV:
+			status->error2 = CRESP_OV;
+			break;
+		case HTM2_STATUS_BUF_WAIT:
+			status->error2 = BUF_WAIT;
+			break;
+		case HTM2_STATUS_TRIG_DROPPED:
+			status->error2 = TRIGGER_DROPPED;
+			break;
+		case HTM2_STATUS_ADDR_ERROR:
+			status->error2 = ADDR_ERROR;
+			break;
+		case HTM2_STATUS_REC_DROPPED:
+			status->error2 = RECORD_DROPPED;
+			break;
+		case HTM2_STATUS_SCOM_ERROR:
+			status->error2 = SCOM_ERROR;
+			break;
+		case HTM2_STATUS_PARITY_ERROR:
+			status->error2 = PARITY_ERROR;
+			break;
+		case HTM2_STATUS_INVALID_CRESP:
+			status->error2 = INVALID_CRESP;
+			break;
+		default:
+			status->error2 = NONE;
+		}
+	}
+
 	switch (status->raw & HTM_STATUS_STATE_MASK) {
 	case HTM_STATUS_REPAIR:
 		status->state = REPAIR;
@@ -327,16 +409,63 @@  static int get_status(struct htm *htm, struct htm_status *status)
 		status->state = UNINITIALIZED;
 	}
 
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm")) {
+		switch (status->raw & HTM2_STATUS_STATE_MASK) {
+		case HTM2_STATUS_REPAIR:
+			status->state2 = REPAIR;
+			break;
+		case HTM2_STATUS_INIT:
+			status->state2 = INIT;
+			break;
+		case HTM2_STATUS_PREREQ:
+			status->state2 = PREREQ;
+			break;
+		case HTM2_STATUS_READY:
+			status->state2 = READY;
+			break;
+		case HTM2_STATUS_TRACING:
+			status->state2 = TRACING;
+			break;
+		case HTM2_STATUS_PAUSED:
+			status->state2 = PAUSED;
+			break;
+		case HTM2_STATUS_FLUSH:
+			status->state2 = FLUSH;
+			break;
+		case HTM2_STATUS_COMPLETE:
+			status->state2 = COMPLETE;
+			break;
+		case HTM2_STATUS_ENABLE:
+			status->state2 = ENABLE;
+			break;
+		case HTM2_STATUS_STAMP:
+			status->state2 = STAMP;
+			break;
+		default:
+			status->state2 = UNINITIALIZED;
+		}
+	}
+
 	if (HTM_ERR(pib_read(&htm->target, HTM_MEMORY_CONF, &val)))
 		return -1;
 
-	status->mem_size_select = val & HTM_MEM_SIZE_SMALL;
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm")) {
+		status->mem_size_select = val & HTM_MEM_SIZE_SMALL_P10;
+		status->mem_base = val & HTM_MEM_BASE_P10;
+	} else {
+		status->mem_size_select = val & HTM_MEM_SIZE_SMALL;
+		status->mem_base = val & HTM_MEM_BASE;
+	}
 	status->mem_size = GETFIELD(HTM_MEM_SIZE,val);
-	status->mem_base = val & HTM_MEM_BASE;
 
 	if (HTM_ERR(pib_read(&htm->target, HTM_LAST_ADDRESS, &status->mem_last)))
 		return -1;
 
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm")) {
+		if (HTM_ERR(pib_read(&htm->target, HTM2_LAST_ADDRESS, &status->mem_last2)))
+			return -1;
+	}
+
 	return 0;
 }
 
@@ -566,6 +695,35 @@  static int configure_nhtm(struct htm *htm, bool wrap)
 		}
 	}
 
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm")) {
+		if (HTM_ERR(pib_read(&htm->target, NHTM_FLEX_MUX, &val)))
+			return -1;
+
+		if (GETFIELD(NHTM_FLEX_MUX_MASK_P10, val) != NHTM_FLEX_DEFAULT_P10) {
+			PR_ERROR("The HTM Flex wasn't default value\n");
+			return -1;
+		}
+
+		if (HTM_ERR(pib_write(&htm->target, NHTM_ADDR_PAT, 0)))
+			return -1;
+
+		if (HTM_ERR(pib_write(&htm->target, NHTM_ADDR_MASK, NHTM_ADDR_MASK_MASK)))
+			return -1;
+
+		if (HTM_ERR(pib_write(&htm->target, NHTM_STOP_FILTER,
+				      NHTM_STOP_FILTER_TTAG_MASK |
+				      NHTM_STOP_FILTER_TTYPE_MASK |
+				      NHTM_STOP_FILTER_CRESP_MASK)))
+			return -1;
+
+		if (HTM_ERR(pib_write(&htm->target, NHTM_STOP_FILT_ADDR_PAT, 0)))
+			return -1;
+
+		if (HTM_ERR(pib_write(&htm->target, NHTM_STOP_FILT_ADDR_MASK,
+				      NHTM_STOP_FILT_ADDR_MASK_MASK)))
+			return -1;
+	}
+
 	return 0;
 }
 
@@ -577,9 +735,13 @@  static int deconfigure_nhtm(struct htm *htm)
 	return 0;
 }
 
-static int is_startable(struct htm_status *status)
+static int is_startable(struct htm *htm, struct htm_status *status)
 {
-	return (status->state == READY || status->state == PAUSED);
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm"))
+		return ((status->state == READY || status->state == PAUSED) &&
+			(status->state2 == READY || status->state2 == PAUSED));
+	else
+		return (status->state == READY || status->state == PAUSED);
 }
 
 static char *get_debugfs_file(struct htm *htm, const char *file)
@@ -715,7 +877,10 @@  static int configure_memory(struct htm *htm)
 	small = 0;
 	if (size < 512*1024*1024)
 		small = 1;
-	val = SETFIELD(HTM_MEM_SIZE_SMALL, val, small);
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm"))
+		val = SETFIELD(HTM_MEM_SIZE_SMALL_P10, val, small);
+	else
+		val = SETFIELD(HTM_MEM_SIZE_SMALL, val, small);
 	shift = 29; /* large */
 	if (small)
 		shift = 24;
@@ -728,7 +893,10 @@  static int configure_memory(struct htm *htm)
 	 * already shifted correct as read from the kernel, or'ing it
 	 * in works fine.
 	 */
-	val = SETFIELD(HTM_MEM_BASE, val, 0);
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm"))
+		val = SETFIELD(HTM_MEM_BASE_P10, val, 0);
+	else
+		val = SETFIELD(HTM_MEM_BASE, val, 0);
 	val |= base;
 
 	if (HTM_ERR(pib_write(&htm->target, HTM_MEMORY_CONF, val)))
@@ -800,7 +968,7 @@  static int __do_htm_start(struct htm *htm, bool wrap)
 	if (HTM_ERR(get_status(htm, &status)))
 		return -1;
 
-	if (!is_startable(&status)) {
+	if (!is_startable(htm, &status)) {
 		PR_ERROR("HTM not in a startable state!\n");
 		return -1;
 	}
@@ -1008,9 +1176,9 @@  static int do_htm_dump(struct htm *htm, char *filename)
 {
 	char *trace_file;
 	struct htm_status status;
-	uint64_t last, end, trace_size;
+	uint64_t last, end, trace_size, last2 = 0;
 	int trace_fd, dump_fd;
-	uint32_t eyecatcher;
+	uint64_t eyecatcher;
 	size_t r;
 	bool wrapped;
 
@@ -1025,6 +1193,11 @@  static int do_htm_dump(struct htm *htm, char *filename)
 		return -1;
 	}
 
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm") && status.state2 != COMPLETE) {
+		PR_INFO("* Skipping DUMP tigger, HTM2 is not in complete state\n");
+		return -1;
+	}
+
 	trace_file = get_debugfs_file(htm, "trace");
 	if (!trace_file)
 		return -1;
@@ -1036,7 +1209,12 @@  static int do_htm_dump(struct htm *htm, char *filename)
 		goto out3;
 	}
 
-	r = read(trace_fd, &eyecatcher, 4);
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm")) {
+		lseek(trace_fd, 8, SEEK_SET);
+		r = read(trace_fd, &eyecatcher, 8);
+	} else {
+		r = read(trace_fd, &eyecatcher, 4);
+	}
 	if (r == -1) {
 		PR_ERROR("Failed to read from %s: %m\n", trace_file);
 		goto out2;
@@ -1045,6 +1223,8 @@  static int do_htm_dump(struct htm *htm, char *filename)
 	if (eyecatcher == 0x00f0efac)
 		wrapped = false;
 	last = status.mem_last - status.mem_base;
+	if (pdbg_target_compatible(&htm->target, "ibm,power10-nhtm"))
+		last2 = status.mem_last2 - status.mem_base;
 	end = htm_trace_size(&status);
 	trace_size = wrapped ? end : last;
 
@@ -1083,7 +1263,7 @@  static int do_htm_dump(struct htm *htm, char *filename)
 	r = lseek(trace_fd, 0, SEEK_SET);
 	if (r == -1)
 		goto out1;
-	r = copy_file(dump_fd, trace_fd, last);
+	r = copy_file(dump_fd, trace_fd, MAX(last2, last));
 	if (r)
 		goto out1;
 	r = 1;
@@ -1140,6 +1320,14 @@  static int nhtm_probe(struct pdbg_target *target)
 		}
 	}
 
+	switch (pdbg_get_proc()) {
+	case PDBG_PROC_P10:
+		dual_htm_offset = 0x01;
+		break;
+	default:
+		break;
+	}
+
 	return 0;
 }
 
@@ -1193,10 +1381,26 @@  static struct htm p8_chtm = {
 };
 DECLARE_HW_UNIT(p8_chtm);
 
+static struct htm p10_nhtm = {
+	.target = {
+		.name = "POWER10 Nest HTM",
+		.compatible = "ibm,power10-nhtm",
+		.class = "nhtm",
+		.probe = nhtm_probe,
+	},
+	.start = do_htm_start,
+	.stop = do_htm_stop,
+	.record = do_htm_record,
+	.status = do_htm_status,
+	.dump = do_htm_dump,
+};
+DECLARE_HW_UNIT(p10_nhtm);
+
 __attribute__((constructor))
 static void register_htm(void)
 {
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p8_nhtm_hw_unit);
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p9_nhtm_hw_unit);
+	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_nhtm_hw_unit);
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p8_chtm_hw_unit);
 }