[Skiboot] [RFC 1/2] occ: Add support for OPAL-OCC command/response interface

Cyril Bur cyrilbur at gmail.com
Wed Jun 7 16:39:09 AEST 2017


On Wed, 2017-06-07 at 09:19 +0530, Shilpasri G Bhat wrote:
> Hi,
> 
> On 06/06/2017 11:11 AM, Cyril Bur wrote:
> > On Mon, 2017-06-05 at 10:10 +0530, Shilpasri G Bhat wrote:
> > > 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.
> > > 
> > 
> > Hi Shilpasri,
> > 
> > Looks good! 
> > 
> > I have a question about retries, from what I can see this allows
> > write_occ_cmd() to memcpy() no matter what, which sounds good, however,
> > you've called it 'retry' does that mean theres an expectation that the
> > caller wants to retry the same command? As far as I can tell the caller
> > could 'retry' anything.
> 
> The caller retries the same command one more time on command failures due to
> timeout and command response mismatch. When retry=true OCC_PROGRESS_BIT check is
> ignored while writing the same command.
> 

Ah right, yes, sorry I neglected to realise that in this case Linux is
the caller. My badly formulated point was that in skiboot you rely on
the caller to retry the same command. I suppose my question is: Do we
trust Linux or should there be some check to enforce that a retry is
only for the same command.

Cyril

> Thanks for the review. I will take care of the rest of the comments.
> 
> Regards,
> Shilpa
> 
> > 
> > Other comments inline.
> > 
> > > Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
> > > ---
> > >  hw/occ.c           | 453 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> > >  include/opal-api.h |  68 +++++++-
> > >  2 files changed, 516 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/hw/occ.c b/hw/occ.c
> > > index 4be4df4..aa01bba 100644
> > > --- a/hw/occ.c
> > > +++ b/hw/occ.c
> > > @@ -119,6 +119,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
> > > @@ -135,6 +216,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;
> > > @@ -150,7 +233,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;
> > > @@ -842,6 +927,363 @@ 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_CHAR		= 0x05, /* Characterization */
> > 
> > Not to be confused with the type... I can't think of a better name...
> > 
> > > +};
> > > +
> > > +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,
> > > +};
> > > +
> > > +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_CHAR),
> > > +		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_CHAR),
> > > +		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_CHAR),
> > > +		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_CHAR),
> > > +		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;
> > > +	u8 occ_role;
> > > +	u8 *occ_state;
> > > +	bool cmd_in_progress;
> > > +} *chips;
> > > +
> > > +struct occ_rsp_msg {
> > > +	struct list_node link;
> > > +	u8 token;
> > > +	int rc;
> > > +};
> > > +
> > > +static LIST_HEAD(rsp_msg_list);
> > > +static struct lock rsp_msg_lock = LOCK_UNLOCKED;
> > > +static bool rsp_msg_in_use;
> > > +
> > > +static inline struct cmd_interface *get_chip_cmd_interface(int chip_id)
> > > +{
> > > +	struct proc_chip *chip;
> > > +	int i = 0;
> > > +
> > > +	for_each_chip(chip) {
> > > +		if (chips[i].id == chip_id)
> > > +			return &chips[i];
> > > +		i++;
> > > +	}
> > > +
> > > +	return NULL;
> > > +}
> > 
> > You seem to have abused the for_each_chip() macro to loop on your chips
> > structure. It should work, in the init your chips->id is equal to each
> > chip->id.
> > Would it not make more sense to store the size of your chips array so
> > that you can 
> > for (i = 0; i < nr_chips; i++) { 
> > instead of
> > for_each_chip(chip) {
> > 
> > 
> > 
> > 
> > Cyril
> > 
> > 
> > > +
> > > +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_OCC_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, msg->cdata, msg->cdata_size);
> > > +	cmd->flag = OPAL_CMD_READY;
> > > +
> > > +	schedule_timer(&chip->timeout,
> > > +		       msecs_to_tb(occ_cmds[msg->cmd].timeout_ms));
> > > +
> > > +	return OPAL_ASYNC_COMPLETION;
> > > +}
> > > +
> > > +static int64_t opal_occ_command(int chip_id, struct opal_occ_cmd_rsp_msg *msg,
> > > +				bool retry)
> > > +{
> > > +	struct cmd_interface *chip;
> > > +	int rc;
> > > +
> > > +	if (!msg || !opal_addr_valid(msg->cdata) ||
> > > +	    !opal_addr_valid(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 (!(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_OCC_INVALID_STATE;
> > > +
> > > +	lock(&chip->queue_lock);
> > > +	if (chip->cmd_in_progress) {
> > > +		rc = OPAL_OCC_BUSY;
> > > +		goto out;
> > > +	}
> > > +
> > > +	chip->msg = msg;
> > > +	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 void occ_rsp_msg_consumed(void *data __unused);
> > > +
> > > +static inline int queue_occ_rsp_msg(int token, int rc)
> > > +{
> > > +	return opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, occ_rsp_msg_consumed,
> > > +			      token, rc);
> > > +}
> > > +
> > > +static void occ_rsp_msg_consumed(void *data __unused)
> > > +{
> > > +	struct occ_rsp_msg *item;
> > > +
> > > +	lock(&rsp_msg_lock);
> > > +
> > > +	/* Queue next message */
> > > +	item = list_pop(&rsp_msg_list, struct occ_rsp_msg, link);
> > > +	if (!item) {
> > > +		rsp_msg_in_use = false;
> > > +		goto exit;
> > > +	}
> > > +
> > > +	if (!queue_occ_rsp_msg(item->token, item->rc)) {
> > > +		rsp_msg_in_use = true;
> > > +		free(item);
> > > +	} else {
> > > +		rsp_msg_in_use = false;
> > > +		list_add(&rsp_msg_list, &item->link);
> > > +	}
> > > +exit:
> > > +	unlock(&rsp_msg_lock);
> > > +}
> > > +
> > > +static void send_occ_rsp_msg(u8 token, int rc)
> > > +{
> > > +	struct occ_rsp_msg *item;
> > > +
> > > +	lock(&rsp_msg_lock);
> > > +	if (!rsp_msg_in_use && !queue_occ_rsp_msg(token, rc)) {
> > > +		rsp_msg_in_use = true;
> > > +		goto out;
> > > +	}
> > > +
> > > +	item = malloc(sizeof(*item));
> > > +	if (!item)
> > > +		goto out;
> > > +
> > > +	item->token = token;
> > > +	item->rc = rc;
> > > +	item->link.next = item->link.prev = NULL;
> > > +	list_add_tail(&rsp_msg_list, &item->link);
> > > +out:
> > > +	unlock(&rsp_msg_lock);
> > > +}
> > > +
> > > +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;
> > > +	send_occ_rsp_msg(chip->msg->request_id, OPAL_OCC_CMD_TIMEOUT);
> > > +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(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)) {
> > > +		send_occ_rsp_msg(msg->request_id, OPAL_OCC_CMD_MISMATCH);
> > > +		goto exit;
> > > +	}
> > > +
> > > +	read_occ_rsp(chip->rsp, msg);
> > > +	send_occ_rsp_msg(msg->request_id, 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, nr_chips = 0;
> > > +
> > > +	chip = next_chip(NULL);
> > > +	pdata = get_occ_pstate_table(chip);
> > > +	if (pdata->version != 0x90)
> > > +		return;
> > > +
> > > +	for_each_chip(chip)
> > > +		nr_chips++;
> > > +
> > > +	chips = malloc(sizeof(*chips) * nr_chips);
> > > +	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;
> > > +		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, 3);
> > > +}
> > > +
> > >  /* CPU-OCC PState init */
> > >  /* Called after OCC init on P8 and P9 */
> > >  void occ_pstates_init(void)
> > > @@ -909,6 +1351,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 {
> > > @@ -1394,8 +1839,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);
> > > +	}
> > >  
> > >  	/* We may have masked-out OCB_OCI_OCIMISC_IRQ in the previous
> > >  	 * OCCMISC_AND write. Check if there are any new source bits set,
> > > @@ -1417,5 +1864,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 80033c6..4acbd44 100644
> > > --- a/include/opal-api.h
> > > +++ b/include/opal-api.h
> > > @@ -55,6 +55,10 @@
> > >  #define OPAL_XSCOM_CTR_OFFLINED	-30
> > >  #define OPAL_XIVE_PROVISIONING	-31
> > >  #define OPAL_XIVE_FREE_ACTIVE	-32
> > > +#define OPAL_OCC_INVALID_STATE	-33
> > > +#define OPAL_OCC_BUSY		-34
> > > +#define OPAL_OCC_CMD_TIMEOUT	-35
> > > +#define OPAL_OCC_CMD_MISMATCH -36
> > >  
> > >  /* API Tokens (in r0) */
> > >  #define OPAL_INVALID_CALL		       -1
> > > @@ -204,7 +208,8 @@
> > >  #define OPAL_NPU_INIT_CONTEXT			146
> > >  #define OPAL_NPU_DESTROY_CONTEXT		147
> > >  #define OPAL_NPU_MAP_LPAR			148
> > > -#define OPAL_LAST				148
> > > +#define OPAL_OCC_COMMAND			149
> > > +#define OPAL_LAST				149
> > >  
> > >  /* Device tree flags */
> > >  
> > > @@ -1021,6 +1026,67 @@ 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_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,
> > > +};
> > > +
> > > +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,
> > > +};
> > > +
> > > +enum occ_sensor_limit_group {
> > > +	OCC_SENSOR_LIMIT_GROUP_CSM		= 0x10,
> > > +	OCC_SENSOR_LIMIT_GROUP_PROFILER		= 0x20,
> > > +	OCC_SENSOR_LIMIT_GROUP_JOB_SCHED	= 0x30,
> > > +};
> > > +
> > > +#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 {
> > > +	u8 *cdata;
> > > +	u8 *rdata;
> > > +	__be16 cdata_size;
> > > +	__be16 rdata_size;
> > > +	u8 cmd;
> > > +	u8 request_id;
> > > +	u8 status;
> > > +};
> > > +
> > > +struct opal_occ_cmd_data {
> > > +	u16 size;
> > > +	u8 cmd;
> > > +	u8 data[];
> > > +};
> > > +
> > > +struct opal_occ_rsp_data {
> > > +	u16 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 */
> 
> 


More information about the Skiboot mailing list