[Skiboot] [PATCH v3 2/2] fsp/ipmi: Add the in-band IPMI support for FSP systems

Alistair Popple alistair at popple.id.au
Fri Jul 10 15:52:49 AEST 2015


I've haven't had a chance to review the changes from v2 -> v3 in depth but 
they were pretty straight forward and look ok at a glance.

Acked-By: Alistair Popple <alistair at popple.id.au>

On Fri, 10 Jul 2015 11:16:49 Neelesh Gupta wrote:
> FSP implements the IPMI commands support that can be accessed over
> the mailbox interface from the host. The host needs to provide and
> receive the message/data bytes of the IPMI command in the TCE space
> in the  KCS (Keyboard Controller Style) format.
> 
> Signed-off-by: Neelesh Gupta <neelegup at linux.vnet.ibm.com>
> ---
> 
> v2 -> v3
> * Handle the error path case in fsp_ipmi_send_request().
> * Send a generic error code for mailbox failure instead of IPMI one.
> * Use new macro IPMI_NETFN_RETURN_CODE
> 
> v1 -> v2
> * Fixed the intermittent assertion fail in the function 
fsp_ipmi_req_complete()
>   on the conditon  'assert(fsp_ipmi_msg == fsp_ipmi.cur_msg)'
> 
>   It happened because there could be 'response message' arrived to this
>   driver before the 'response' of the request and 'response message'
>   handing path resets the 'cur_msg', fsp sends it in order though.. i.e.,
>   'response' followed by 'response message'.
> * Replaced list_del() with list_del_from() to perform extra check for
>   the dequeue_msg() interface.
> 
>  hw/fsp/Makefile.inc        |    2 
>  hw/fsp/fsp-ipmi.c          |  355 
++++++++++++++++++++++++++++++++++++++++++++
>  include/errorlog.h         |    6 +
>  include/fsp.h              |    6 +
>  include/psi.h              |    4 
>  platforms/ibm-fsp/common.c |    5 +
>  6 files changed, 377 insertions(+), 1 deletion(-)
>  create mode 100644 hw/fsp/fsp-ipmi.c
> 
> diff --git a/hw/fsp/Makefile.inc b/hw/fsp/Makefile.inc
> index 2fe4f0d..7169095 100644
> --- a/hw/fsp/Makefile.inc
> +++ b/hw/fsp/Makefile.inc
> @@ -4,7 +4,7 @@ FSP_OBJS  = fsp.o fsp-console.o fsp-rtc.o fsp-nvram.o fsp-
sysparam.o
>  FSP_OBJS += fsp-surveillance.o fsp-codeupdate.o fsp-sensor.o
>  FSP_OBJS += fsp-diag.o fsp-leds.o fsp-mem-err.o fsp-op-panel.o
>  FSP_OBJS += fsp-elog-read.o fsp-elog-write.o fsp-epow.o fsp-dpo.o
> -FSP_OBJS += fsp-dump.o fsp-mdst-table.o fsp-chiptod.o
> +FSP_OBJS += fsp-dump.o fsp-mdst-table.o fsp-chiptod.o fsp-ipmi.o
>  FSP_OBJS += fsp-attn.o
>  FSP = hw/fsp/built-in.o
>  $(FSP): $(FSP_OBJS:%=hw/fsp/%)
> diff --git a/hw/fsp/fsp-ipmi.c b/hw/fsp/fsp-ipmi.c
> new file mode 100644
> index 0000000..e5cd6e2
> --- /dev/null
> +++ b/hw/fsp/fsp-ipmi.c
> @@ -0,0 +1,355 @@
> +/* Copyright 2014-2015 IBM Corp.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *	http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> + * implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <errorlog.h>
> +#include <fsp.h>
> +#include <ipmi.h>
> +#include <lock.h>
> +#include <opal-api.h>
> +
> +/*
> + * Under the hood, FSP IPMI component implements the KCS (Keyboard 
Controller
> + * Style) interface
> + *
> + * KCS interface request message format
> + *
> + *    BYTE 1	 BYTE 2	       BYTE 3:N
> + *  -------------------------------------
> + * | NetFn/LUN |    Cmd    |    Data     |
> + *  -------------------------------------
> + *
> + * KCS interface response message format
> + *
> + *    BYTE 1	 BYTE 2		BYTE 3	  BYTE 4:N
> + *  ------------------------------------------------
> + * | NetFn/LUN |    Cmd    |  CompCode  |   Data    |
> + *  ------------------------------------------------
> +
> + */
> +
> +#define FSP_IPMI_REQ_MIN_LEN	2 /* NetFn + Cmd */
> +#define FSP_IPMI_RESP_MIN_LEN	3 /* NetFn + Cmd + Completion code */
> +
> +DEFINE_LOG_ENTRY(OPAL_RC_IPMI_REQ, OPAL_PLATFORM_ERR_EVT, OPAL_IPMI,
> +		 OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
> +		 OPAL_NA, NULL);
> +DEFINE_LOG_ENTRY(OPAL_RC_IPMI_RESP, OPAL_PLATFORM_ERR_EVT, OPAL_IPMI,
> +		 OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
> +		 OPAL_NA, NULL);
> +
> +struct fsp_ipmi_msg {
> +	struct list_node	link;
> +	struct ipmi_msg		ipmi_msg;
> +};
> +
> +static struct fsp_ipmi {
> +	struct list_head	msg_queue;
> +	void			*ipmi_req_buf;
> +	void			*ipmi_resp_buf;
> +	/* There can only be one outstanding request whose reference is stored
> +	 * in 'cur_msg' and the 'lock' protects against the concurrent updates
> +	 * of it through request and response. The same 'lock' also protects
> +	 * the list manipulation.
> +	 */
> +	struct fsp_ipmi_msg	*cur_msg;
> +	struct lock		lock;
> +} fsp_ipmi;
> +
> +static int fsp_ipmi_send_request(void);
> +
> +static void fsp_ipmi_cmd_done(uint8_t cmd, uint8_t netfn, uint8_t cc)
> +{
> +	struct fsp_ipmi_msg *fsp_ipmi_msg = fsp_ipmi.cur_msg;
> +
> +	lock(&fsp_ipmi.lock);
> +	list_del(&fsp_ipmi_msg->link);
> +	fsp_ipmi.cur_msg = NULL;
> +	unlock(&fsp_ipmi.lock);
> +
> +	ipmi_cmd_done(cmd, netfn, cc, &fsp_ipmi_msg->ipmi_msg);
> +}
> +
> +
> +static void fsp_ipmi_req_complete(struct fsp_msg *msg)
> +{
> +	uint8_t status = (msg->resp->word1 >> 8) & 0xff;
> +	uint32_t length = msg->resp->data.words[0];
> +	struct fsp_ipmi_msg *fsp_ipmi_msg;
> +	struct ipmi_msg *ipmi_msg;
> +
> +	fsp_freemsg(msg);
> +
> +	if (status != FSP_STATUS_SUCCESS) {
> +		fsp_ipmi_msg = msg->user_data;
> +		assert(fsp_ipmi_msg == fsp_ipmi.cur_msg);
> +
> +		ipmi_msg = &fsp_ipmi_msg->ipmi_msg;
> +
> +		if (length != (ipmi_msg->req_size + FSP_IPMI_REQ_MIN_LEN))
> +			prlog(PR_DEBUG, "IPMI: Length mismatch in req 
completion "
> +			      "(%d, %d)\n", ipmi_msg->req_size, length);
> +
> +		log_simple_error(&e_info(OPAL_RC_IPMI_REQ), "IPMI: Request "
> +				 "failed with status:0x%02x\n", status);
> +		/* FSP will not send the response now, so clear the current
> +		 * outstanding request
> +		 */
> +		fsp_ipmi_cmd_done(ipmi_msg->cmd,
> +				  IPMI_NETFN_RETURN_CODE(ipmi_msg->netfn),
> +				  IPMI_ERR_UNSPECIFIED);
> +
> +		/* Send the next request in the queue */
> +		fsp_ipmi_send_request();
> +	}
> +}
> +
> +static int fsp_ipmi_send_request(void)
> +{
> +	uint8_t *req_buf = fsp_ipmi.ipmi_req_buf;
> +	struct ipmi_msg *ipmi_msg;
> +	struct fsp_msg *msg;
> +	int rc;
> +
> +	lock(&fsp_ipmi.lock);
> +	/* An outstanding request is still pending */
> +	if (fsp_ipmi.cur_msg) {
> +		unlock(&fsp_ipmi.lock);
> +		return OPAL_SUCCESS;
> +	}
> +
> +	fsp_ipmi.cur_msg = list_top(&fsp_ipmi.msg_queue, struct fsp_ipmi_msg,
> +				    link);
> +	unlock(&fsp_ipmi.lock);
> +
> +	if (!fsp_ipmi.cur_msg)
> +		return OPAL_SUCCESS;
> +
> +	ipmi_msg = &fsp_ipmi.cur_msg->ipmi_msg;
> +	prlog(PR_TRACE, "IPMI: Send request, netfn:0x%02x, cmd:0x%02x, "
> +	      "req_len:%d\n", ipmi_msg->netfn, ipmi_msg->cmd, ipmi_msg-
>req_size);
> +
> +	/* KCS request message format */
> +	*req_buf++ = ipmi_msg->netfn;	/* BYTE 1 */
> +	*req_buf++ = ipmi_msg->cmd;	/* BYTE 2 */
> +	if (ipmi_msg->req_size)
> +		memcpy(req_buf, ipmi_msg->data, ipmi_msg->req_size);
> +
> +	msg = fsp_mkmsg(FSP_CMD_FETCH_PLAT_DATA, 5, 0, PSI_DMA_PLAT_REQ_BUF,
> +			0, PSI_DMA_PLAT_RESP_BUF,
> +			ipmi_msg->req_size + FSP_IPMI_REQ_MIN_LEN);
> +	if (!msg) {
> +		log_simple_error(&e_info(OPAL_RC_IPMI_REQ), "IPMI: Failed to "
> +				 "allocate request message\n");
> +		fsp_ipmi_cmd_done(ipmi_msg->cmd,
> +				  IPMI_NETFN_RETURN_CODE(ipmi_msg->netfn),
> +				  IPMI_ERR_UNSPECIFIED);
> +		return OPAL_NO_MEM;
> +	}
> +
> +	msg->user_data = fsp_ipmi.cur_msg;
> +	rc = fsp_queue_msg(msg, fsp_ipmi_req_complete);
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_IPMI_REQ), "IPMI: Failed to "
> +				 "queue request message (%d)\n", rc);
> +		fsp_freemsg(msg);
> +		fsp_ipmi_cmd_done(ipmi_msg->cmd,
> +				  IPMI_NETFN_RETURN_CODE(ipmi_msg->netfn),
> +				  IPMI_ERR_UNSPECIFIED);
> +		return OPAL_INTERNAL_ERROR;
> +	}
> +
> +	return OPAL_SUCCESS;
> +}
> +
> +static struct ipmi_msg *fsp_ipmi_alloc_msg(size_t req_size, size_t 
resp_size)
> +{
> +	struct fsp_ipmi_msg *fsp_ipmi_msg;
> +	struct ipmi_msg *ipmi_msg;
> +
> +	fsp_ipmi_msg = zalloc(sizeof(*fsp_ipmi_msg) + MAX(req_size, 
resp_size));
> +	if (!fsp_ipmi_msg)
> +		return NULL;
> +
> +	ipmi_msg = &fsp_ipmi_msg->ipmi_msg;
> +
> +	ipmi_msg->req_size = req_size;
> +	ipmi_msg->resp_size = resp_size;
> +	ipmi_msg->data = (uint8_t *)(fsp_ipmi_msg + 1);
> +
> +	return ipmi_msg;
> +}
> +
> +static void fsp_ipmi_free_msg(struct ipmi_msg *ipmi_msg)
> +{
> +	struct fsp_ipmi_msg *fsp_ipmi_msg = container_of(ipmi_msg,
> +			struct fsp_ipmi_msg, ipmi_msg);
> +
> +	free(fsp_ipmi_msg);
> +}
> +
> +static int fsp_ipmi_queue_msg(struct ipmi_msg *ipmi_msg)
> +{
> +	struct fsp_ipmi_msg *fsp_ipmi_msg = container_of(ipmi_msg,
> +			struct fsp_ipmi_msg, ipmi_msg);
> +
> +	lock(&fsp_ipmi.lock);
> +	list_add_tail(&fsp_ipmi.msg_queue, &fsp_ipmi_msg->link);
> +	unlock(&fsp_ipmi.lock);
> +
> +	return fsp_ipmi_send_request();
> +}
> +
> +static int fsp_ipmi_queue_msg_head(struct ipmi_msg *ipmi_msg)
> +{
> +	struct fsp_ipmi_msg *fsp_ipmi_msg = container_of(ipmi_msg,
> +			struct fsp_ipmi_msg, ipmi_msg);
> +
> +	lock(&fsp_ipmi.lock);
> +	list_add(&fsp_ipmi.msg_queue, &fsp_ipmi_msg->link);
> +	unlock(&fsp_ipmi.lock);
> +
> +	return fsp_ipmi_send_request();
> +}
> +
> +static int fsp_ipmi_dequeue_msg(struct ipmi_msg *ipmi_msg)
> +{
> +	struct fsp_ipmi_msg *fsp_ipmi_msg = container_of(ipmi_msg,
> +			struct fsp_ipmi_msg, ipmi_msg);
> +
> +	lock(&fsp_ipmi.lock);
> +	list_del_from(&fsp_ipmi.msg_queue, &fsp_ipmi_msg->link);
> +	unlock(&fsp_ipmi.lock);
> +
> +	return 0;
> +}
> +
> +static struct ipmi_backend fsp_ipmi_backend = {
> +	.alloc_msg	= fsp_ipmi_alloc_msg,
> +	.free_msg	= fsp_ipmi_free_msg,
> +	.queue_msg	= fsp_ipmi_queue_msg,
> +	.queue_msg_head	= fsp_ipmi_queue_msg_head,
> +	.dequeue_msg	= fsp_ipmi_dequeue_msg,
> +};
> +
> +static bool fsp_ipmi_send_response(uint32_t cmd)
> +{
> +	struct fsp_msg *resp;
> +	int rc;
> +
> +	resp = fsp_mkmsg(cmd, 0);
> +	if (!resp) {
> +		log_simple_error(&e_info(OPAL_RC_IPMI_RESP), "IPMI: Failed to 
"
> +				 "allocate response message\n");
> +		return false;
> +	}
> +
> +	rc = fsp_queue_msg(resp, fsp_freemsg);
> +	if (rc) {
> +		fsp_freemsg(resp);
> +		log_simple_error(&e_info(OPAL_RC_IPMI_RESP), "IPMI: Failed to 
"
> +				 "queue response message\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static bool fsp_ipmi_read_response(struct fsp_msg *msg)
> +{
> +	uint8_t *resp_buf = fsp_ipmi.ipmi_resp_buf;
> +	uint32_t status = msg->data.words[3];
> +	uint32_t length = msg->data.words[2];
> +	struct ipmi_msg *ipmi_msg;
> +	uint8_t netfn, cmd, cc;
> +
> +	assert(fsp_ipmi.cur_msg);
> +	ipmi_msg = &fsp_ipmi.cur_msg->ipmi_msg;
> +
> +	/* Response TCE token */
> +	assert(msg->data.words[1] == PSI_DMA_PLAT_RESP_BUF);
> +
> +	if (status != FSP_STATUS_SUCCESS) {
> +		log_simple_error(&e_info(OPAL_RC_IPMI_RESP), "IPMI: Response "
> +				 "with bad status:0x%02x\n", status);
> +		fsp_ipmi_cmd_done(ipmi_msg->cmd,
> +				  IPMI_NETFN_RETURN_CODE(ipmi_msg->netfn),
> +				  IPMI_ERR_UNSPECIFIED);
> +		return fsp_ipmi_send_response(FSP_RSP_PLAT_DATA |
> +					      FSP_STATUS_GENERIC_ERROR);
> +	}
> +
> +	/* KCS response message format */
> +	netfn = *resp_buf++;
> +	cmd = *resp_buf++;
> +	cc = *resp_buf++;
> +	length -= FSP_IPMI_RESP_MIN_LEN;
> +
> +	prlog(PR_TRACE, "IPMI: fsp response received, netfn:0x%02x, 
cmd:0x%02x,"
> +	      " cc:0x%02x, length:%d\n", netfn, cmd, cc, length);
> +
> +	if (length > ipmi_msg->resp_size) {
> +		prlog(PR_DEBUG, "IPMI: Length mismatch in response (%d, 
%d)\n",
> +		      length, ipmi_msg->resp_size);
> +		length = ipmi_msg->resp_size; /* Truncate */
> +		cc = IPMI_ERR_MSG_TRUNCATED;
> +	}
> +
> +	ipmi_msg->resp_size = length;
> +	if (length)
> +		memcpy(ipmi_msg->data, resp_buf, length);
> +
> +	fsp_ipmi_cmd_done(cmd, netfn, cc);
> +
> +	return fsp_ipmi_send_response(FSP_RSP_PLAT_DATA);
> +}
> +
> +static bool fsp_ipmi_response(uint32_t cmd_sub_mod, struct fsp_msg *msg)
> +{
> +	bool rc;
> +
> +	switch (cmd_sub_mod) {
> +	case FSP_CMD_SEND_PLAT_DATA:
> +		prlog(PR_TRACE, "FSP_CMD_SEND_PLAT_DATA command received\n");
> +		rc = fsp_ipmi_read_response(msg);
> +		break;
> +	default:
> +		return false;
> +	};
> +
> +	/* If response sent successfully, pick the next request */
> +	if (rc == true)
> +		fsp_ipmi_send_request();
> +
> +	return rc;
> +}
> +
> +static struct fsp_client fsp_ipmi_client = {
> +	.message = fsp_ipmi_response,
> +};
> +
> +void fsp_ipmi_init(void)
> +{
> +	fsp_tce_map(PSI_DMA_PLAT_REQ_BUF, fsp_ipmi.ipmi_req_buf,
> +		    PSI_DMA_PLAT_REQ_BUF_SIZE);
> +	fsp_tce_map(PSI_DMA_PLAT_RESP_BUF, fsp_ipmi.ipmi_resp_buf,
> +		    PSI_DMA_PLAT_RESP_BUF_SIZE);
> +
> +	list_head_init(&fsp_ipmi.msg_queue);
> +	init_lock(&fsp_ipmi.lock);
> +
> +	fsp_register_client(&fsp_ipmi_client, FSP_MCLASS_FETCH_SPDATA);
> +	ipmi_register_backend(&fsp_ipmi_backend);
> +}
> diff --git a/include/errorlog.h b/include/errorlog.h
> index 51af88c..af9b441 100644
> --- a/include/errorlog.h
> +++ b/include/errorlog.h
> @@ -192,6 +192,7 @@ struct opal_err_info {
>  #define OPAL_SLW			0x534C	/* SL */
>  #define OPAL_FSP			0x4650	/* FP */
>  #define OPAL_I2C			0x4943	/* IC */
> +#define OPAL_IPMI			0x4950  /* IP */
>  
>  /* SAPPHIRE SRC componenet ID*/
>  #define OPAL_CU				0x1000
> @@ -223,6 +224,7 @@ struct opal_err_info {
>  #define OPAL_SL				0x2100
>  #define OPAL_FP				0x2200
>  #define OPAL_IC				0x2300
> +#define OPAL_IP				0x2400
>  
>  enum opal_reasoncode {
>  /* code update */
> @@ -317,6 +319,10 @@ enum opal_reasoncode {
>  	OPAL_RC_I2C_TIMEOUT	= OPAL_IC | 0x12,
>  	OPAL_RC_I2C_TRANSFER	= OPAL_IC | 0x13,
>  	OPAL_RC_I2C_RESET	= OPAL_IC | 0x14,
> +
> +/* IPMI */
> +	OPAL_RC_IPMI_REQ	= OPAL_IP | 0x10,
> +	OPAL_RC_IPMI_RESP	= OPAL_IP | 0x11,
>  };
>  
>  #define DEFINE_LOG_ENTRY(reason, type, id, subsys,			\
> diff --git a/include/fsp.h b/include/fsp.h
> index 3df78a1..0291084 100644
> --- a/include/fsp.h
> +++ b/include/fsp.h
> @@ -421,6 +421,9 @@
>   */
>  #define FSP_CMD_FETCH_SP_DATA	0x1d40101 /* HV->FSP: Fetch & DMA data 
*/
>  #define FSP_CMD_WRITE_SP_DATA	0x1d40201 /* HV->FSP: Fetch & DMA data 
*/
> +#define FSP_CMD_FETCH_PLAT_DATA	0x1d40500 /* HV->FSP: Platform function 
data */
> +#define FSP_CMD_SEND_PLAT_DATA	0x0d40501 /* FSP->HV */
> +#define FSP_RSP_PLAT_DATA	0x0d48500 /* HV->FSP */
>  
>  /* Data set IDs for SP data commands */
>  #define FSP_DATASET_SP_DUMP	0x01
> @@ -793,6 +796,9 @@ extern int (*fsp_flash_term_hook)(void);
>  extern void fsp_init_surveillance(void);
>  extern void fsp_surv_query(void);
>  
> +/* IPMI */
> +extern void fsp_ipmi_init(void);
> +
>  /* Reset/Reload */
>  extern void fsp_reinit_fsp(void);
>  extern void fsp_trigger_reset(void);
> diff --git a/include/psi.h b/include/psi.h
> index 62643aa..36240e1 100644
> --- a/include/psi.h
> +++ b/include/psi.h
> @@ -193,6 +193,10 @@
>  #define PSI_DMA_MEMCONS_SZ		0x00001000
>  #define PSI_DMA_LOG_BUF			0x03200000
>  #define PSI_DMA_LOG_BUF_SZ		0x00100000 /* INMEM_CON_LEN */
> +#define PSI_DMA_PLAT_REQ_BUF		0x03300000
> +#define PSI_DMA_PLAT_REQ_BUF_SIZE	0x00001000
> +#define PSI_DMA_PLAT_RESP_BUF		0x03301000
> +#define PSI_DMA_PLAT_RESP_BUF_SIZE	0x00001000
>  
>  /* P8 only mappings */
>  #define PSI_DMA_TRACE_BASE		0x04000000
> diff --git a/platforms/ibm-fsp/common.c b/platforms/ibm-fsp/common.c
> index 12536bd..59a890b 100644
> --- a/platforms/ibm-fsp/common.c
> +++ b/platforms/ibm-fsp/common.c
> @@ -21,6 +21,7 @@
>  #include <opal.h>
>  #include <console.h>
>  #include <hostservices.h>
> +#include <ipmi.h>
>  
>  #include "ibm-fsp.h"
>  
> @@ -125,6 +126,10 @@ void ibm_fsp_init(void)
>  	op_display(OP_LOG, OP_MOD_INIT, 0x0002);
>  	fsp_init_surveillance();
>  
> +	/* IPMI */
> +	fsp_ipmi_init();
> +	ipmi_opal_init();
> +
>  	/* Initialize sensor access */
>  	op_display(OP_LOG, OP_MOD_INIT, 0x0003);
>  	fsp_init_sensor();
> 
> _______________________________________________
> Skiboot mailing list
> Skiboot at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
> 



More information about the Skiboot mailing list