[Skiboot] [PATCH RFC 5/5] external/opal-prd: opal-prd to support htmgt passthru and attribute override

Neelesh Gupta neelegup at linux.vnet.ibm.com
Wed Jul 29 02:44:21 AEST 2015


This patch adds the support for htmgt passthru and attribute override
commands. The command format would like something as below:

# opal-prd occ passthru 0x10 0x11 0xac

It will pass the arguments after 'passthru' in an array as input data to
hbrt->htmgt_pass_thru(). The HBRT will return the output data to a buffer
provided by 'opal-prd' of maximum length 256 bytes.

# opal-prd override <file_name_of_binary_blob>

It will read the contents of the binary blob into a buffer and invoke
hbrt->apply_attr_override() with the buffer and size as the input to
the interface.

Signed-off-by: Neelesh Gupta <neelegup at linux.vnet.ibm.com>
---
 external/opal-prd/hostboot-interface.h |   35 ++++
 external/opal-prd/opal-prd.c           |  250 +++++++++++++++++++++++++++++---
 external/opal-prd/thunk.S              |    2 
 3 files changed, 263 insertions(+), 24 deletions(-)

diff --git a/external/opal-prd/hostboot-interface.h b/external/opal-prd/hostboot-interface.h
index d186819..4c97a63 100644
--- a/external/opal-prd/hostboot-interface.h
+++ b/external/opal-prd/hostboot-interface.h
@@ -432,6 +432,41 @@ struct runtime_interfaces {
 	 */
 	int (*run_command)(int argc, const char **argv, char **o_outString);
 
+	/**
+	 * @brief	Send a pass-through command to HTMGT
+	 *
+	 * @details	This is a blocking call that will send a command to
+	 *		HTMGT.
+	 *
+	 * @note	If o_rspLength is returned with a non-zero value, the
+	 *		data at the o_rspData should be dumped to stdout in a
+	 *		hex dump format.
+	 * @note	The maximum response data returned will be 256 bytes
+	 *
+	 * @param[in]	i_cmdLength  number of bytes in pass-thru command data
+	 * @param[in]	*i_cmdData   pointer to pass-thru command data
+	 * @param[out]	*o_rspLength pointer to number of bytes returned in
+	 *			     o_rspData
+	 * @param[out]	*o_rspData   pointer to a 256 byte buffer that will
+	 *			     contain the response data from the command
+	 *
+	 * @returns	0 on success, or return code if the command failed
+	 * @platform	OpenPower
+	 */
+	int (*htmgt_pass_thru)(uint16_t i_cmdLength, uint8_t *i_cmdData,
+			       uint16_t *o_rspLength, uint8_t *o_rspData);
+
+	/**
+	 * @brief	Apply a set of attribute overrides
+	 *
+	 * @param[in]	pointer to binary override data
+	 * @param[in]	length of override data (bytes)
+	 * @returns	0 on success, or return code if the command failed
+	 *
+	 * @platform	OpenPower
+	 */
+	int (*apply_attr_override)(uint8_t *i_data, size_t size);
+
 	/* Reserve some space for future growth. */
 	void (*reserved[32])(void);
 };
diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index c477602..a5bfa5c 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -83,7 +83,9 @@ enum control_msg_type {
 	CONTROL_MSG_DISABLE_OCCS	= 0x01,
 	CONTROL_MSG_TEMP_OCC_RESET	= 0x02,
 	CONTROL_MSG_TEMP_OCC_ERROR	= 0x03,
+	CONTROL_MSG_HTMGT_PASSTHRU	= 0x04,
 	CONTROL_MSG_RUN_CMD		= 0x10,
+	CONTROL_MSG_ATTR_OVERRIDE	= 0x20,
 	CONTROL_MSG_INVALID             = 0xf0,
 };
 
@@ -97,12 +99,28 @@ struct control_msg {
 			uint32_t	len;
 			char		data[];
 		} run_cmd;
+		struct {
+			uint32_t	argc;
+			uint8_t		data[];
+		} htmgt_cmd;
+		struct {
+			uint32_t	size;
+			uint8_t		data[];
+		} attr_override;
 	};
 };
 
 #define MAX_CONTROL_RUN_CMD_DATA	4096
-#define MAX_CONTROL_RUN_CMD	\
+#define MAX_CONTROL_OCC_DATA		256
+#define MAX_CONTROL_ATTR_OVERRIDE_DATA	4096 /* XXX ?? */
+
+#define MAX_CONTROL_RUN_CMD		\
 		(sizeof(struct control_msg) + MAX_CONTROL_RUN_CMD_DATA)
+#define MAX_CONTROL_OCC			\
+		(sizeof(struct control_msg) + MAX_CONTROL_OCC_DATA)
+#define MAX_CONTROL_ATTR_OVERRIDE	\
+		(sizeof(struct control_msg) + MAX_CONTROL_ATTR_OVERRIDE_DATA)
+#define MAX_CONTROL_MSG			MAX_CONTROL_RUN_CMD
 
 static struct opal_prd_ctx *ctx;
 
@@ -215,6 +233,9 @@ extern int call_enable_attns(void);
 extern int call_enable_occ_actuation(bool i_occActivation);
 extern void call_process_occ_reset(uint64_t i_chipId);
 extern int call_run_command(int argc, const char **argv, char **o_outString);
+extern int call_htmgt_pass_thru(uint16_t i_cmdLength, uint8_t *i_cmdData,
+				uint16_t *o_rspLength, uint8_t *o_rspData);
+extern int call_apply_attr_override(uint8_t *i_data, size_t size);
 
 void hservice_puts(const char *str)
 {
@@ -1149,13 +1170,71 @@ out:
 	*size = sizeof(*msg);
 }
 
+static void handle_prd_htmgt_passthru(struct control_msg *msg, int *size)
+{
+	uint8_t rsp_data[MAX_CONTROL_OCC_DATA];
+	uint16_t rsp_len;
+
+	if (*size != (sizeof(*msg) + msg->htmgt_cmd.argc)) {
+		pr_log(LOG_WARNING, "CTRL: htmgt_pass_thru, failed to "
+				"receive control message: %m");
+		goto out;
+	}
+
+	if (!hservice_runtime->htmgt_pass_thru) {
+		pr_log_nocall("htmgt_pass_thru");
+		goto out;
+	}
+
+	pr_debug("CTRL: calling htmgt_pass_thru");
+	msg->response = call_htmgt_pass_thru(msg->htmgt_cmd.argc,
+					     msg->htmgt_cmd.data,
+					     &rsp_len, rsp_data);
+	rsp_len = be16toh(rsp_len);
+	if (rsp_len > MAX_CONTROL_OCC_DATA) {
+		pr_log(LOG_WARNING, "CTRL: response truncated for "
+				"htmgt_pass_thru");
+		rsp_len = MAX_CONTROL_OCC_DATA;
+	}
+
+	*size = sizeof(*msg) + rsp_len;
+	msg->htmgt_cmd.argc = rsp_len;
+	memcpy(msg->htmgt_cmd.data, rsp_data, rsp_len);
+
+	return;
+
+out:
+	*size = sizeof(*msg);
+}
+
+static void handle_prd_attr_override(struct control_msg *msg, int *size)
+{
+	if (*size != (sizeof(*msg) + msg->attr_override.size)) {
+		pr_log(LOG_WARNING, "CTRL: apply_attr_override, failed to "
+				"receive control message: %m");
+		goto out;
+	}
+
+	if (!hservice_runtime->apply_attr_override) {
+		pr_log_nocall("apply_attr_override");
+		goto out;
+	}
+
+	pr_debug("CTRL: calling apply_attr_override");
+	msg->response = call_apply_attr_override(msg->attr_override.data,
+						 msg->attr_override.size);
+
+out:
+	*size = sizeof(*msg);
+}
+
 static void handle_prd_control(struct opal_prd_ctx *ctx, int fd)
 {
 	struct control_msg *msg, invalid_msg;
 	bool enabled = false;
 	int rc, size;
 
-	msg = malloc(MAX_CONTROL_RUN_CMD);
+	msg = malloc(MAX_CONTROL_MSG);
 	if (!msg) {
 		pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
 		msg = &invalid_msg;
@@ -1164,7 +1243,7 @@ static void handle_prd_control(struct opal_prd_ctx *ctx, int fd)
 		goto out_send;
 	}
 
-	size = recv(fd, msg, MAX_CONTROL_RUN_CMD, MSG_TRUNC);
+	size = recv(fd, msg, MAX_CONTROL_MSG, MSG_TRUNC);
 	if (size < sizeof(*msg)) {
 		pr_log(LOG_WARNING, "CTRL: failed to receive control "
 				"message: %m");
@@ -1185,9 +1264,15 @@ static void handle_prd_control(struct opal_prd_ctx *ctx, int fd)
 	case CONTROL_MSG_TEMP_OCC_ERROR:
 		handle_prd_control_occ_error(msg, &size);
 		break;
+	case CONTROL_MSG_HTMGT_PASSTHRU:
+		handle_prd_htmgt_passthru(msg, &size);
+		break;
 	case CONTROL_MSG_RUN_CMD:
 		handle_prd_control_run_cmd(msg, &size);
 		break;
+	case CONTROL_MSG_ATTR_OVERRIDE:
+		handle_prd_attr_override(msg, &size);
+		break;
 	default:
 		pr_log(LOG_WARNING, "CTRL: Unknown control message action %d",
 				msg->type);
@@ -1449,6 +1534,7 @@ static int send_prd_control(struct control_msg *msg, size_t send_sz,
 	case CONTROL_MSG_DISABLE_OCCS:
 	case CONTROL_MSG_TEMP_OCC_RESET:
 	case CONTROL_MSG_TEMP_OCC_ERROR:
+	case CONTROL_MSG_ATTR_OVERRIDE:
 		if (rc != sizeof(*msg)) {
 			pr_log(LOG_WARNING, "CTRL: Short read from control "
 					"socket");
@@ -1456,6 +1542,13 @@ static int send_prd_control(struct control_msg *msg, size_t send_sz,
 			goto out_close;
 		}
 		break;
+	case CONTROL_MSG_HTMGT_PASSTHRU:
+		if (rc != (sizeof(*msg) + msg->htmgt_cmd.argc)) {
+			pr_log(LOG_WARNING, "CTRL: short read from control "
+					"socket");
+			rc = -1;
+			goto out_close;
+		}
 	case CONTROL_MSG_RUN_CMD:
 		break;
 	case CONTROL_MSG_INVALID:
@@ -1475,31 +1568,67 @@ out_close:
 	return rc;
 }
 
-static int send_occ_control(struct opal_prd_ctx *ctx, const char *str)
+static int send_occ_control(struct opal_prd_ctx *ctx, int argc, char *argv[])
 {
-	struct control_msg msg;
-	int rc;
+	size_t send_sz, recv_sz;
+	struct control_msg *msg;
+	uint8_t *data;
+	int i, rc;
+
+	msg = malloc(MAX_CONTROL_OCC);
+	if (!msg) {
+		pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+		return -1;
+	}
 
 	memset(&msg, 0, sizeof(msg));
+	send_sz = recv_sz = sizeof(struct control_msg);
+
+	if (!strcmp(argv[0], "enable")) {
+		msg->type = CONTROL_MSG_ENABLE_OCCS;
+	} else if (!strcmp(argv[0], "disable")) {
+		msg->type = CONTROL_MSG_DISABLE_OCCS;
+	} else if (!strcmp(argv[0], "reset")) {
+		msg->type = CONTROL_MSG_TEMP_OCC_RESET;
+	} else if (!strcmp(argv[0], "process-error")) {
+		msg->type = CONTROL_MSG_TEMP_OCC_ERROR;
+	} else if (!strcmp(argv[0], "passthru")) {
+		if (ctx->debug) {
+			for (i = 0; i < (argc - 1); i++) {
+				pr_debug("CTRL: run command arguments:");
+				pr_debug("argv[%d] = %s", i, argv[i]);
+			}
+		}
+
+		msg->type = CONTROL_MSG_HTMGT_PASSTHRU;
+		msg->htmgt_cmd.argc = argc - 1;
+		for (i = 0; (i < (argc - 1)) && (i < MAX_CONTROL_OCC_DATA);
+				i++)
+			sscanf(argv[i + 1], "%hhx", &msg->htmgt_cmd.data[i]);
 
-	if (!strcmp(str, "enable")) {
-		msg.type = CONTROL_MSG_ENABLE_OCCS;
-	} else if (!strcmp(str, "disable")) {
-		msg.type = CONTROL_MSG_DISABLE_OCCS;
-	} else if (!strcmp(str, "reset")) {
-		msg.type = CONTROL_MSG_TEMP_OCC_RESET;
-	} else if (!strcmp(str, "process-error")) {
-		msg.type = CONTROL_MSG_TEMP_OCC_ERROR;
+		send_sz = sizeof(*msg) + argc - 1;
+		recv_sz = MAX_CONTROL_OCC;
 	} else {
-		pr_log(LOG_ERR, "OCC: Invalid OCC action '%s'", str);
-		return -1;
+		pr_log(LOG_ERR, "OCC: Invalid OCC action '%s'", argv[0]);
+		rc = -1;
+		goto out;
 	}
 
-	rc = send_prd_control(&msg, sizeof(msg), sizeof(msg));
-	if (msg.response || ctx->debug)
+	rc = send_prd_control(msg, send_sz, recv_sz);
+	if (msg->response || ctx->debug)
 		pr_debug("OCC: OCC action %s returned status %ld",
-				str, msg.response);
+				argv[0], msg->response);
 
+	if (msg->type == CONTROL_MSG_HTMGT_PASSTHRU && !msg->response) {
+		pr_log(LOG_INFO, "Received:");
+		argc = msg->htmgt_cmd.argc;
+		data = msg->htmgt_cmd.data;
+		for (i = 0; i < argc; i++) /* XXX format nicely*/
+			pr_log(LOG_INFO, "%02x", data[i]);
+	}
+
+out:
+	free(msg);
 	return rc;
 }
 
@@ -1553,6 +1682,56 @@ out_free:
 	return rc;
 }
 
+static int send_attr_override(struct opal_prd_ctx *ctx, uint32_t argc,
+			      char *argv[])
+{
+	struct control_msg *msg;
+	size_t send_sz, sz;
+	FILE *fd;
+	int rc;
+
+	msg = malloc(MAX_CONTROL_ATTR_OVERRIDE);
+	if (!msg) {
+		pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+		return -1;
+	}
+
+	fd = fopen(argv[0], "rb");
+	if (!fd) {
+		pr_log(LOG_NOTICE, "CTRL: can't open %s: %m", argv[0]);
+		rc = -1;
+		goto out_free;
+	}
+
+	fseek(fd, 0, SEEK_END);
+	send_sz = ftell(fd);
+	fseek(fd, 0, SEEK_SET);
+
+	if (send_sz > MAX_CONTROL_ATTR_OVERRIDE_DATA) {
+		pr_log(LOG_ERR, "CTRL: binary override data too big");
+		rc = -1;
+		goto out_close;
+	}
+
+	sz = fread(msg->attr_override.data, 1, send_sz, fd);
+	if (sz != send_sz) {
+		pr_log(LOG_ERR, "CTRL: short read from the file");
+		rc = -1;
+		goto out_close;
+	}
+
+	msg->type = CONTROL_MSG_ATTR_OVERRIDE;
+	msg->attr_override.size = send_sz;
+	rc = send_prd_control(msg, send_sz, sizeof(*msg));
+
+out_close:
+	fclose(fd);
+out_free:
+	free(msg);
+	return rc;
+}
+
+/* TODO usage */
 static void usage(const char *progname)
 {
 	printf("Usage:\n");
@@ -1560,6 +1739,9 @@ static void usage(const char *progname)
 			progname);
 	printf("\t%s occ <enable|disable>\n", progname);
 	printf("\t%s run [arg 0] [arg 1]..[arg n]\n", progname);
+	printf("\t%s htmgt passthru [1st byte] [2nd byte]..[nth byte]\n",
+			progname);
+	printf("\t%s override <binary_blob>\n", progname);
 	printf("\n");
 	printf("Options:\n"
 "\t--debug            verbose logging for debug information\n"
@@ -1589,6 +1771,7 @@ enum action {
 	ACTION_RUN_DAEMON,
 	ACTION_OCC_CONTROL,
 	ACTION_RUN_COMMAND,
+	ACTION_ATTR_OVERRIDE,
 };
 
 static int parse_action(const char *str, enum action *action)
@@ -1608,6 +1791,11 @@ static int parse_action(const char *str, enum action *action)
 		return 0;
 	}
 
+	if (!strcmp(str, "override")) {
+		*action = ACTION_ATTR_OVERRIDE;
+		return 0;
+	}
+
 	pr_log(LOG_ERR, "CTRL: unknown argument '%s'", str);
 	return -1;
 }
@@ -1665,18 +1853,20 @@ int main(int argc, char *argv[])
 		action = ACTION_RUN_DAEMON;
 	}
 
-	if (action == ACTION_RUN_DAEMON) {
+	switch (action) {
+	case ACTION_RUN_DAEMON:
 		rc = run_prd_daemon(ctx);
-
-	} else if (action == ACTION_OCC_CONTROL) {
+		break;
+	case ACTION_OCC_CONTROL:
 		if (optind + 1 >= argc) {
 			pr_log(LOG_ERR, "CTRL: occ command requires "
 					"an argument");
 			return EXIT_FAILURE;
 		}
 
-		rc = send_occ_control(ctx, argv[optind + 1]);
-	} else if (action == ACTION_RUN_COMMAND) {
+		rc = send_occ_control(ctx, argc - optind - 1, &argv[optind + 1]);
+		break;
+	case ACTION_RUN_COMMAND:
 		if (optind + 1 >= argc) {
 			pr_log(LOG_ERR, "CTRL: run command requires "
 					"argument(s)");
@@ -1684,6 +1874,18 @@ int main(int argc, char *argv[])
 		}
 
 		rc = send_run_command(ctx, argc - optind - 1, &argv[optind + 1]);
+		break;
+	case ACTION_ATTR_OVERRIDE:
+		if (optind + 1 >= argc) {
+			pr_log(LOG_ERR, "CTRL: attribute override command "
+					"requires an argument");
+			return EXIT_FAILURE;
+		}
+
+		rc = send_attr_override(ctx, argc - optind - 1, &argv[optind + 1]);
+		break;
+	default:
+		break;
 	}
 
 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
index f2dcebd..d01d94a 100644
--- a/external/opal-prd/thunk.S
+++ b/external/opal-prd/thunk.S
@@ -91,6 +91,8 @@ call_##name:					;\
 	CALL_THUNK(process_occ_reset, 10)
 	CALL_THUNK(enable_occ_actuation, 11)
 	CALL_THUNK(run_command, 12)
+	CALL_THUNK(htmgt_pass_thru, 13)
+	CALL_THUNK(apply_attr_override, 14)
 
 	.globl call_hbrt_init
 call_hbrt_init:



More information about the Skiboot mailing list