[Skiboot] [PATCH V5 1/3] occ: Add support for OPAL-OCC command/response interface

Shilpasri G Bhat shilpa.bhat at linux.vnet.ibm.com
Thu Jul 13 16:47:40 AEST 2017


This patch adds support for a shared memory based command/response
interface between OCC and OPAL. In HOMER, there is an OPAL command
buffer and an OCC response buffer which is used to send inband
commands to OCC.

The OPAL-OCC command/response sequence is as follows:

1. Check if both 'OCC Progress' bit in OCC response flag and 'Cmd Ready'
   bit in OPAL command flag are set to zero. If yes then proceed with
   below steps to send a command to OCC.
2. Write the command value, request ID and command specific data
   to the OPAL command buffer.
3. Clear the response flag and set the 'Cmd Ready' bit in OPAL command
   flag to indicate command is ready.
4. OCC will poll the command flag every 4ms to check if 'Cmd Ready' bit
   is set by OPAL. If the bit is set then OCC will set the 'OCC Progress'
   bit.
5. OCC will process the command and write the response to the OCC response
   buffer and set the 'Rsp Ready' bit in the response flag and sends an
   interrupt.
8. OPAL will receive the interrupt and queue the response to the host.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
Changes from V4:
- Removed patch to dynamically increase OPAL_MAX_ASYNC_COMP to add
  number of available chips. Instead increased OPAL_MAX_ASYNC_COMP to
  16 to acommodate maximum number of chips possible.
- Replaced new OCC errors with old opal error codes and added
  OPAL_OCC_CMD_RSP_ERROR to indicate timeout or cmd/rsp mismatch in
  OCC response
- Added documentation.

 doc/opal-api/opal-occ-command-152.rst | 143 ++++++++++++
 hw/occ.c                              | 414 +++++++++++++++++++++++++++++++++-
 include/opal-api.h                    |  79 ++++++-
 include/opal-msg.h                    |   2 +-
 4 files changed, 632 insertions(+), 6 deletions(-)
 create mode 100644 doc/opal-api/opal-occ-command-152.rst

diff --git a/doc/opal-api/opal-occ-command-152.rst b/doc/opal-api/opal-occ-command-152.rst
new file mode 100644
index 0000000..2eefa5b
--- /dev/null
+++ b/doc/opal-api/opal-occ-command-152.rst
@@ -0,0 +1,143 @@
+OPAL_OCC_COMMAND
+================
+
+The OPAL_OCC_COMMAND call is used to send commands to OCC via
+shared-memory based command-response interface in HOMER. This call
+is asynchrouns and will return OPAL_ASYNC_COMPLETION on successfully
+writing the command.
+
+Parameters
+----------
+
+``int chip_id``
+  Id of the chip to which OCC command needs to be sent
+
+
+``struct opal_occ_cmd_rsp_msg *msg``
+  Contains the command data and response buffer to pass data to/from OCC
+  Following commands are supported by OCC:
+  1) `OCC_CMD_AMESTER_PASS_THRU`
+    Used to send commands from Amester to OCC.
+    Command details:
+    - Command value: 0x41
+    - Command data length: Variable
+    - Command data: Data from Amester
+    Response details:
+    - Response status:
+        - 0x00 = Success
+        - 0x11 = Invalid command
+        - 0x15 = Internal OCC error
+    - Response data length: Variable
+    - Response data: Specific data for Amester command
+  2) `OCC_CMD_CLEAR_SENSOR_DATA`
+    Used to clear the minimum and maximum for every sensor for the given
+    owner. OCC owned min/max cannot be cleared using this command.
+    Command details:
+    - Command value: 0xD0
+    - Command data length in bytes: 4
+    - Command data:
+        - Byte 1 indicates the sensor data owner ID to clear the sensor
+          min/max and they can be one of the below:
+                - CSM = 0x10
+                - Profiler = 0x20
+                - Job scheduler = 0x30
+        - Byte 2,3 and 4 are reserved (0x00)
+    Response details:
+    - Response status:
+        - 0x00 = Success
+        - 0x12 = Invalid command data length
+        - 0x13 = Invalid sensor data owner ID
+        - 0x15 Internal OCC error
+    - Response data length in bytes: 4 on success
+    - Response data:
+        - Byte 1 indicates the sensor data owner ID for which the sensor
+          min/max was cleared
+        - Byte 2,3 and 4 are reserved (0x00)
+  3) `OCC_CMD_SET_POWER_CAP`
+    Used to set system powercap. This command can be only sent to master OCC.
+    Command details:
+    - Command value: 0xD1
+    - Command data length in bytes: 2
+    - Command data:
+        - Byte 1-2 indicates the powercap to be set in Watts.
+          Passing 0x00 here clears the powercap.
+    Response details:
+    - Response status:
+        - 0x00 = Success
+        - 0x11 = Command sent to slave OCC
+        - 0x12 = Invalid command data length
+        - 0x13 = Non-zero powercap requested is not within powercap
+                 min/max limits
+    - Response data length in bytes: 2
+    - Response data:
+        - Byte 1-2 indicates the current powercap.
+  4) `OCC_CMD_SET_POWER_SHIFTING_RATIO`
+    Used to set the CPU-GPU power shifting ratio used by the OCC power
+    capping algorithm.
+    Command details:
+    - Command value: 0xD2
+    - Command data length in bytes: 1
+    - Command data:
+        - 0-100 Power-Shifting-Ratio in %
+        - 0 indicates OCC to take zero power away from CPU (cap GPU first)
+        - 100 indicates OCC to take all power away from CPU first
+    Response details:
+    - Response status:
+        - 0x00 = Success
+        - 0x12 = Invalid command data length
+        - 0x13 = Invalid Power-Shifting-Ratio
+    - Response data length in bytes: 1
+    - Response data: Current Power-Shifting-Ratio
+  5) `OCC_CMD_SELECT_SENSOR_GROUPS`
+    Used to tell OCC the sensor groups to be copied to main memory.
+    Command details:
+    - Command value: 0xD3
+    - Command data length in bytes: 2
+    - Command data:
+        - Bytes 1-2 indicates the sensor group mask. The sensor group will
+          be copied to main memory whose bit is set to 1.
+                - Bit 0:5 = reserved
+                - Bit 6   = Performance
+                - Bit 7   = reserved
+                - Bit 8   = Power
+                - Bit 9   = Frequency
+                - Bit 10  = Time
+                - Bit 11  = Utilization
+                - Bit 12  = Temperature
+                - Bit 13  = Voltage
+                - Bit 14  = Current
+                - Bit 15   = Generic
+    Response details:
+    - Response status:
+        - 0x00 = Success
+        - 0x12 = Invalid command data length
+        - 0x13 = Invalid sensor group mask
+        - 0x15 = Internal OCC error
+    - Response data length in bytes: 2
+    - Response data: Sensor group mask
+
+
+``int token``
+  Token passed by kernel which is returned on completion of OCC response
+
+
+``bool retry``
+  Indicates if the command is a retry after a failure.
+
+Return values
+-------------
+
+- OPAL_ASYNC_COMPLETION : On successful command write
+- OPAL_UNSUPPORTED : Unsupported OCC Command
+- OPAL_PARAMETER : Invalid parameters
+- OPAL_WRONG_STATE : Invalid OCC state, unable to process the command
+- OPAL_BUSY : OCC is busy processing a command
+
+Response Status on successful command write :
+
+- OPAL_SUCCESS: Successful OCC response
+- OPAL_OCC_CMD_RSP_ERROR : Either the OCC timed out handling the command
+  or there was a mismatch in the command and response data. Kernel will
+  retry the command once on recieving this error.
+
+
diff --git a/hw/occ.c b/hw/occ.c
index 7d0d22c..cde52e7 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -120,6 +120,87 @@ struct occ_pstate_table {
 } __packed;
 
 /**
+ * OPAL-OCC Command Response Interface
+ *
+ * OPAL-OCC Command Buffer
+ *
+ * ---------------------------------------------------------------------
+ * | OPAL  |  Cmd    | OPAL |	       | Cmd Data | Cmd Data | OPAL    |
+ * | Cmd   | Request | OCC  | Reserved | Length   | Length   | Cmd     |
+ * | Flags |   ID    | Cmd  |	       | (MSB)    | (LSB)    | Data... |
+ * ---------------------------------------------------------------------
+ * |  ….OPAL Command Data up to max of Cmd Data Length 4090 bytes      |
+ * |								       |
+ * ---------------------------------------------------------------------
+ *
+ * OPAL Command Flag
+ *
+ * -----------------------------------------------------------------
+ * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
+ * | (msb) |	   |	   |	   |	   |	   |	   | (lsb) |
+ * -----------------------------------------------------------------
+ * |Cmd    |       |       |       |       |       |       |       |
+ * |Ready  |	   |	   |	   |	   |	   |	   |	   |
+ * -----------------------------------------------------------------
+ *
+ * struct opal_command_buffer -	Defines the layout of OPAL command buffer
+ * @flag:			Provides general status of the command
+ * @request_id:			Token to identify request
+ * @cmd:			Command sent
+ * @data_size:			Command data length
+ * @data:			Command specific data
+ * @spare:			Unused byte
+ */
+struct opal_command_buffer {
+	u8 flag;
+	u8 request_id;
+	u8 cmd;
+	u8 spare;
+	u16 data_size;
+	u8 data[MAX_OPAL_CMD_DATA_LENGTH];
+} __packed;
+
+/**
+ * OPAL-OCC Response Buffer
+ *
+ * ---------------------------------------------------------------------
+ * | OCC   |  Cmd    | OPAL | Response | Rsp Data | Rsp Data | OPAL    |
+ * | Rsp   | Request | OCC  |  Status  | Length   | Length   | Rsp     |
+ * | Flags |   ID    | Cmd  |	       | (MSB)    | (LSB)    | Data... |
+ * ---------------------------------------------------------------------
+ * |  ….OPAL Response Data up to max of Rsp Data Length 8698 bytes     |
+ * |								       |
+ * ---------------------------------------------------------------------
+ *
+ * OCC Response Flag
+ *
+ * -----------------------------------------------------------------
+ * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
+ * | (msb) |	   |	   |	   |	   |	   |	   | (lsb) |
+ * -----------------------------------------------------------------
+ * |       |       |       |       |       |       |OCC in  | Rsp  |
+ * |       |	   |	   |	   |	   |	   |progress|Ready |
+ * -----------------------------------------------------------------
+ *
+ * struct occ_response_buffer -	Defines the layout of OCC response buffer
+ * @flag:			Provides general status of the response
+ * @request_id:			Token to identify request
+ * @cmd:			Command requested
+ * @status:			Indicates success/failure status of
+ *				the command
+ * @data_size:			Response data length
+ * @data:			Response specific data
+ */
+struct occ_response_buffer {
+	u8 flag;
+	u8 request_id;
+	u8 cmd;
+	u8 status;
+	u16 data_size;
+	u8 data[MAX_OCC_RSP_DATA_LENGTH];
+} __packed;
+
+/**
  * OCC-OPAL Shared Memory Interface Dynamic Data Vx90
  *
  * struct occ_dynamic_data -	Contains runtime attributes
@@ -136,6 +217,8 @@ struct occ_pstate_table {
  * @max_pwr_cap:		Maximum allowed system power cap in Watts
  * @cur_pwr_cap:		Current system power cap
  * @spare/reserved:		Unused data
+ * @cmd:			Opal Command Buffer
+ * @rsp:			OCC Response Buffer
  */
 struct occ_dynamic_data {
 	u8 occ_state;
@@ -151,7 +234,9 @@ struct occ_dynamic_data {
 	u16 min_pwr_cap;
 	u16 max_pwr_cap;
 	u16 cur_pwr_cap;
-	u64 reserved;
+	u8 pad[112];
+	struct opal_command_buffer cmd;
+	struct occ_response_buffer rsp;
 } __packed;
 
 static bool occ_reset;
@@ -841,6 +926,324 @@ done:
 	unlock(&occ_lock);
 }
 
+#define OCC_RSP_READY		0x01
+#define OCC_IN_PROGRESS		0x02
+#define OPAL_CMD_READY		0x80
+
+enum occ_state {
+	OCC_STATE_NOT_RUNNING		= 0x00,
+	OCC_STATE_STANDBY		= 0x01,
+	OCC_STATE_OBSERVATION		= 0x02,
+	OCC_STATE_ACTIVE		= 0x03,
+	OCC_STATE_SAFE			= 0x04,
+	OCC_STATE_CHARACTERIZATION	= 0x05,
+};
+
+enum occ_role {
+	OCC_ROLE_SLAVE		= 0x0,
+	OCC_ROLE_MASTER		= 0x1,
+};
+
+enum occ_cmd_value {
+	OCC_CMD_VALUE_AMESTER_PASS_THRU		= 0x41,
+	OCC_CMD_VALUE_CLEAR_SENSOR_DATA		= 0xD0,
+	OCC_CMD_VALUE_SET_POWER_CAP		= 0xD1,
+	OCC_CMD_VALUE_SET_POWER_SHIFTING_RATIO	= 0xD2,
+	OCC_CMD_VALUE_SELECT_SENSOR_GROUPS	= 0xD3,
+};
+
+struct opal_occ_cmd_info {
+	enum	occ_cmd_value value;
+	int	timeout_ms;
+	u16	state_mask;
+	u8	role_mask;
+};
+
+static struct opal_occ_cmd_info occ_cmds[] = {
+	{	OCC_CMD_VALUE_AMESTER_PASS_THRU,
+		1000,
+		PPC_BIT16(OCC_STATE_OBSERVATION) |
+		PPC_BIT16(OCC_STATE_ACTIVE) |
+		PPC_BIT16(OCC_STATE_CHARACTERIZATION),
+		PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
+	},
+	{	OCC_CMD_VALUE_CLEAR_SENSOR_DATA,
+		1000,
+		PPC_BIT16(OCC_STATE_OBSERVATION) |
+		PPC_BIT16(OCC_STATE_ACTIVE) |
+		PPC_BIT16(OCC_STATE_CHARACTERIZATION),
+		PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
+	},
+	{	OCC_CMD_VALUE_SET_POWER_CAP,
+		1000,
+		PPC_BIT16(OCC_STATE_OBSERVATION) |
+		PPC_BIT16(OCC_STATE_ACTIVE) |
+		PPC_BIT16(OCC_STATE_CHARACTERIZATION),
+		PPC_BIT8(OCC_ROLE_MASTER)
+	},
+	{	OCC_CMD_VALUE_SET_POWER_SHIFTING_RATIO,
+		1000,
+		PPC_BIT16(OCC_STATE_OBSERVATION) |
+		PPC_BIT16(OCC_STATE_ACTIVE) |
+		PPC_BIT16(OCC_STATE_CHARACTERIZATION),
+		PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
+	},
+	{	OCC_CMD_VALUE_SELECT_SENSOR_GROUPS,
+		1000,
+		PPC_BIT16(OCC_STATE_OBSERVATION) |
+		PPC_BIT16(OCC_STATE_ACTIVE) |
+		PPC_BIT16(OCC_STATE_CHARACTERIZATION),
+		PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
+	},
+};
+
+static struct cmd_interface {
+	struct lock queue_lock;
+	struct timer timeout;
+	struct opal_command_buffer *cmd;
+	struct occ_response_buffer *rsp;
+	struct opal_occ_cmd_rsp_msg *msg;
+	u32 id;
+	u32 token;
+	enum occ_cmd prev_cmd;
+	u8 occ_role;
+	u8 *occ_state;
+	bool cmd_in_progress;
+} *chips;
+
+static int nr_occs;
+
+static inline struct cmd_interface *get_chip_cmd_interface(int chip_id)
+{
+	int i;
+
+	for (i = 0; i < nr_occs; i++)
+		if (chips[i].id == chip_id)
+			return &chips[i];
+
+	return NULL;
+}
+
+static inline bool occ_in_progress(struct cmd_interface *chip)
+{
+	return (chip->rsp->flag == OCC_IN_PROGRESS);
+}
+
+static int write_occ_cmd(struct cmd_interface *chip, bool retry)
+{
+	struct opal_command_buffer *cmd = chip->cmd;
+	struct opal_occ_cmd_rsp_msg *msg = chip->msg;
+
+	if (!retry && occ_in_progress(chip)) {
+		chip->cmd_in_progress = false;
+		return OPAL_BUSY;
+	}
+
+	cmd->flag = chip->rsp->flag = 0;
+	cmd->cmd = occ_cmds[msg->cmd].value;
+	cmd->request_id = msg->request_id;
+	cmd->data_size = msg->cdata_size;
+	memcpy(&cmd->data, (u8 *)msg->cdata, msg->cdata_size);
+	cmd->flag = OPAL_CMD_READY;
+
+	schedule_timer(&chip->timeout,
+		       msecs_to_tb(occ_cmds[msg->cmd].timeout_ms));
+	chip->prev_cmd = msg->cmd;
+
+	return OPAL_ASYNC_COMPLETION;
+}
+
+static int64_t opal_occ_command(int chip_id, struct opal_occ_cmd_rsp_msg *msg,
+				int token, bool retry)
+{
+	struct cmd_interface *chip;
+	int rc;
+
+	if (!msg || !opal_addr_valid(msg) ||
+	    !opal_addr_valid((u8 *)msg->cdata) ||
+	    !opal_addr_valid((u8 *)msg->rdata))
+		return OPAL_PARAMETER;
+
+	if (msg->cmd >= OCC_CMD_LAST)
+		return OPAL_UNSUPPORTED;
+
+	if (msg->cdata_size > MAX_OPAL_CMD_DATA_LENGTH)
+		return OPAL_PARAMETER;
+
+	chip = get_chip_cmd_interface(chip_id);
+	if (!chip)
+		return OPAL_PARAMETER;
+
+	if (retry && msg->cmd != chip->prev_cmd)
+		return OPAL_PARAMETER;
+
+	if (!(PPC_BIT8(chip->occ_role) & occ_cmds[msg->cmd].role_mask))
+		return OPAL_PARAMETER;
+
+	if (!(PPC_BIT16(*chip->occ_state) & occ_cmds[msg->cmd].state_mask))
+		return OPAL_WRONG_STATE;
+
+	lock(&chip->queue_lock);
+	if (chip->cmd_in_progress) {
+		rc = OPAL_BUSY;
+		goto out;
+	}
+
+	chip->msg = msg;
+	chip->token = token;
+	chip->cmd_in_progress = true;
+	rc = write_occ_cmd(chip, retry);
+out:
+	unlock(&chip->queue_lock);
+	return rc;
+}
+
+static inline bool sanity_check_opal_cmd(struct opal_command_buffer *cmd,
+					 struct opal_occ_cmd_rsp_msg *msg)
+{
+	return ((cmd->cmd == occ_cmds[msg->cmd].value) &&
+		(cmd->request_id == msg->request_id) &&
+		(cmd->data_size == msg->cdata_size));
+}
+
+static inline bool check_occ_rsp(struct opal_command_buffer *cmd,
+				 struct occ_response_buffer *rsp)
+{
+	if (cmd->cmd != rsp->cmd) {
+		prlog(PR_WARNING, "OCC: Command value mismatch in OCC response"
+		      "rsp->cmd = %d cmd->cmd = %d\n", rsp->cmd, cmd->cmd);
+		return false;
+	}
+
+	if (cmd->request_id != rsp->request_id) {
+		prlog(PR_WARNING, "OCC: Request ID mismatch in OCC response"
+		      "rsp->request_id = %d cmd->request_id = %d\n",
+		      rsp->request_id, cmd->request_id);
+		return false;
+	}
+
+	return true;
+}
+
+static inline void queue_occ_rsp_msg(int token, int rc)
+{
+	int ret;
+
+	ret = opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL, token, rc);
+	if (ret)
+		prerror("OCC: Failed to queue OCC response status message\n");
+}
+
+static void occ_cmd_timeout_handler(struct timer *t __unused, void *data,
+				    uint64_t now __unused)
+{
+	struct cmd_interface *chip = data;
+
+	lock(&chip->queue_lock);
+	if (!chip->cmd_in_progress)
+		goto exit;
+
+	chip->cmd_in_progress = false;
+	queue_occ_rsp_msg(chip->token, OPAL_OCC_CMD_RSP_ERROR);
+exit:
+	unlock(&chip->queue_lock);
+}
+
+static void read_occ_rsp(struct occ_response_buffer *rsp,
+			 struct opal_occ_cmd_rsp_msg *msg)
+{
+	/* Copy response to host buffer */
+	msg->status = rsp->status;
+	msg->rdata_size = rsp->data_size;
+	memcpy((u8 *)msg->rdata, rsp->data, rsp->data_size);
+
+	/* Clear the OCC response flag */
+	rsp->flag = 0;
+}
+
+static void handle_occ_rsp(uint32_t chip_id)
+{
+	struct cmd_interface *chip;
+	struct opal_command_buffer *cmd;
+	struct occ_response_buffer *rsp;
+	struct opal_occ_cmd_rsp_msg *msg;
+
+	chip = get_chip_cmd_interface(chip_id);
+	if (!chip)
+		return;
+
+	cmd = chip->cmd;
+	rsp = chip->rsp;
+	msg = chip->msg;
+
+	/*Read rsp*/
+	if (rsp->flag != OCC_RSP_READY)
+		return;
+	lock(&chip->queue_lock);
+	if (!chip->cmd_in_progress)
+		goto exit;
+
+	chip->cmd_in_progress = false;
+	cancel_timer(&chip->timeout);
+	if (!sanity_check_opal_cmd(cmd, chip->msg) ||
+	    !check_occ_rsp(cmd, rsp)) {
+		queue_occ_rsp_msg(chip->token, OPAL_OCC_CMD_RSP_ERROR);
+		goto exit;
+	}
+
+	read_occ_rsp(chip->rsp, msg);
+	queue_occ_rsp_msg(chip->token, OPAL_SUCCESS);
+exit:
+	unlock(&chip->queue_lock);
+}
+
+static void occ_cmd_interface_init(void)
+{
+	struct dt_node *power_mgt;
+	struct occ_dynamic_data *data;
+	struct occ_pstate_table *pdata;
+	struct proc_chip *chip;
+	int i = 0;
+
+	chip = next_chip(NULL);
+	pdata = get_occ_pstate_table(chip);
+	if (pdata->version != 0x90)
+		return;
+
+	for_each_chip(chip)
+		nr_occs++;
+
+	chips = malloc(sizeof(*chips) * nr_occs);
+	assert(chips);
+
+	for_each_chip(chip) {
+		pdata = get_occ_pstate_table(chip);
+		data = get_occ_dynamic_data(chip);
+		chips[i].id = chip->id;
+		chips[i].occ_role = pdata->v9.occ_role;
+		chips[i].occ_state = &data->occ_state;
+		chips[i].cmd = &data->cmd;
+		chips[i].rsp = &data->rsp;
+		init_lock(&chips[i].queue_lock);
+		chips[i].cmd_in_progress = false;
+		chips[i].prev_cmd = OCC_CMD_LAST;
+		init_timer(&chips[i].timeout, occ_cmd_timeout_handler,
+			   &chips[i]);
+		i++;
+	}
+
+	power_mgt = dt_find_by_path(dt_root, "/ibm,opal/power-mgt");
+	if (!power_mgt) {
+		prerror("OCC: dt node /ibm,opal/power-mgt not found\n");
+		free(chips);
+		return;
+	}
+
+	dt_add_property_string(power_mgt, "compatible",
+			       "ibm,opal-occ-cmd-rsp-interface");
+	opal_register(OPAL_OCC_COMMAND, opal_occ_command, 4);
+}
+
 /* CPU-OCC PState init */
 /* Called after OCC init on P8 and P9 */
 void occ_pstates_init(void)
@@ -908,6 +1311,9 @@ void occ_pstates_init(void)
 		chip->throttle = 0;
 	opal_add_poller(occ_throttle_poll, NULL);
 	occ_pstates_initialized = true;
+
+	/* Init OPAL-OCC command-response interface */
+	occ_cmd_interface_init();
 }
 
 struct occ_load_req {
@@ -1407,8 +1813,10 @@ void occ_p9_interrupt(uint32_t chip_id)
 	if (ireg & OCB_OCI_OCIMISC_IRQ_TMGT)
 		prd_tmgt_interrupt(chip_id);
 
-	if (ireg & OCB_OCI_OCIMISC_IRQ_SHMEM)
+	if (ireg & OCB_OCI_OCIMISC_IRQ_SHMEM) {
 		occ_throttle_poll(NULL);
+		handle_occ_rsp(chip_id);
+	}
 
 	if (ireg & OCB_OCI_OCIMISC_IRQ_I2C)
 		p9_i2c_bus_owner_change(chip_id);
@@ -1433,5 +1841,3 @@ void occ_fsp_init(void)
 	if (fsp_present())
 		fsp_register_client(&fsp_occ_client, FSP_MCLASS_OCC);
 }
-
-
diff --git a/include/opal-api.h b/include/opal-api.h
index edae069..b7b6e67 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -55,6 +55,7 @@
 #define OPAL_XSCOM_CTR_OFFLINED	-30
 #define OPAL_XIVE_PROVISIONING	-31
 #define OPAL_XIVE_FREE_ACTIVE	-32
+#define OPAL_OCC_CMD_RSP_ERROR	-33
 
 /* API Tokens (in r0) */
 #define OPAL_INVALID_CALL		       -1
@@ -207,7 +208,8 @@
 #define OPAL_IMC_COUNTERS_INIT			149
 #define OPAL_IMC_COUNTERS_START			150
 #define OPAL_IMC_COUNTERS_STOP			151
-#define OPAL_LAST				151
+#define OPAL_OCC_COMMAND			152
+#define OPAL_LAST				152
 
 /* Device tree flags */
 
@@ -1033,6 +1035,81 @@ typedef struct oppanel_line {
 	__be64 line_len;
 } oppanel_line_t;
 
+enum occ_cmd {
+	OCC_CMD_AMESTER_PASS_THRU = 0,
+	OCC_CMD_CLEAR_SENSOR_DATA,
+	OCC_CMD_SET_POWER_CAP,
+	OCC_CMD_SET_POWER_SHIFTING_RATIO,
+	OCC_CMD_SELECT_SENSOR_GROUPS,
+	OCC_CMD_LAST
+};
+
+enum occ_cmd_data_length {
+	OCC_CMD_DL_AMESTER_PASS_THRU		= 0, /* Variable data length */
+	OCC_CMD_DL_CLEAR_SENSOR_DATA		= 4,
+	OCC_CMD_DL_SET_POWER_CAP		= 2,
+	OCC_CMD_DL_SET_POWER_SHIFTING_RATIO	= 1,
+	OCC_CMD_DL_SELECT_SENSOR_GROUPS		= 2,
+};
+
+enum occ_rsp_data_length {
+	OCC_RSP_DL_AMESTER_PASS_THRU		= 0, /* Variable data length */
+	OCC_RSP_DL_CLEAR_SENSOR_DATA		= 4,
+	OCC_RSP_DL_SET_POWER_CAP		= 2,
+	OCC_RSP_DL_SET_POWER_SHIFTING_RATIO	= 1,
+	OCC_RSP_DL_SELECT_SENSOR_GROUPS		= 2,
+};
+
+enum occ_sensor_limit_group {
+	OCC_SENSOR_LIMIT_GROUP_CSM		= 0x10,
+	OCC_SENSOR_LIMIT_GROUP_PROFILER		= 0x20,
+	OCC_SENSOR_LIMIT_GROUP_JOB_SCHED	= 0x40,
+};
+
+enum occ_sensor_group_mask {
+	OCC_SENSOR_GROUP_MASK_PERFORMANCE	= 6,
+	OCC_SENSOR_GROUP_MASK_POWER		= 8,
+	OCC_SENSOR_GROUP_MASK_FREQUENCY		= 9,
+	OCC_SENSOR_GROUP_MASK_TIME		= 10,
+	OCC_SENSOR_GROUP_MASK_UTILIZATION	= 11,
+	OCC_SENSOR_GROUP_MASK_TEMPERATURE	= 12,
+	OCC_SENSOR_GROUP_MASK_VOLTAGE		= 13,
+	OCC_SENSOR_GROUP_MASK_CURRENT		= 14,
+};
+
+#define MAX_OPAL_CMD_DATA_LENGTH	4090
+#define MAX_OCC_RSP_DATA_LENGTH		8698
+
+enum occ_response_status {
+	OCC_SUCCESS			= 0x00,
+	OCC_INVALID_COMMAND		= 0x11,
+	OCC_INVALID_CMD_DATA_LENGTH	= 0x12,
+	OCC_INVALID_DATA		= 0x13,
+	OCC_INTERNAL_ERROR		= 0x15,
+};
+
+struct opal_occ_cmd_rsp_msg {
+	__be64 cdata;
+	__be64 rdata;
+	__be16 cdata_size;
+	__be16 rdata_size;
+	u8 cmd;
+	u8 request_id;
+	u8 status;
+};
+
+struct opal_occ_cmd_data {
+	__be16 size;
+	u8 cmd;
+	u8 data[];
+};
+
+struct opal_occ_rsp_data {
+	__be16 size;
+	u8 status;
+	u8 data[];
+};
+
 enum opal_prd_msg_type {
 	OPAL_PRD_MSG_TYPE_INIT = 0,	/* HBRT --> OPAL */
 	OPAL_PRD_MSG_TYPE_FINI,		/* HBRT/kernel --> OPAL */
diff --git a/include/opal-msg.h b/include/opal-msg.h
index a75bc4e..74163c4 100644
--- a/include/opal-msg.h
+++ b/include/opal-msg.h
@@ -25,7 +25,7 @@
  * ideally the value matches to the number of modules using async
  * infrastructure, but not necessarily the same..
  */
-#define OPAL_MAX_ASYNC_COMP	8
+#define OPAL_MAX_ASYNC_COMP	16
 
 int _opal_queue_msg(enum opal_msg_type msg_type, void *data,
 		    void (*consumed)(void *data), size_t num_params,
-- 
1.8.3.1



More information about the Skiboot mailing list