[Skiboot] [PATCH 10/12] FSP/LED: Add system attention indicator support

Vasant Hegde hegdevasant at linux.vnet.ibm.com
Mon Apr 6 17:06:44 AEST 2015


SAI is controlled by FSP. This patch adds support to get/set
this indicator. Also update OPAL interface so that playload
can read/set this indicator.

During init, we read this indicator state using MBOX command.
OPAL uses MBOX interface to update this SAI.

FSP sends update notification whenever there is change in SAI
state (except for OPAL initiates updates). We use the notification
to update cached SAI state.

Signed-off-by: Vasant Hegde <hegdevasant at linux.vnet.ibm.com>
---
 doc/opal-api/opal-led-get-set-114-115.txt |   19 +++
 hw/fsp/fsp-leds.c                         |  177 +++++++++++++++++++++++++++++
 include/fsp.h                             |   12 ++
 include/opal-api.h                        |    3 
 4 files changed, 209 insertions(+), 2 deletions(-)

diff --git a/doc/opal-api/opal-led-get-set-114-115.txt b/doc/opal-api/opal-led-get-set-114-115.txt
index 4644adc..1d90ea4 100644
--- a/doc/opal-api/opal-led-get-set-114-115.txt
+++ b/doc/opal-api/opal-led-get-set-114-115.txt
@@ -19,6 +19,25 @@ Different types of indicators handled by LED code:
 	location with which the indicator is associated.
 
 
+LED Design:
+-----------
+  When it comes to implementation we can classify LEDs into two
+  categories:
+    1 - Hypervisor (OPAL) controlled LEDs (All identify & fault indicators)
+	During boot, we read/cache these LED details in OPAL (location code,
+        state, etc). We use cached data to serve read request from FSP/Host.
+	And we use SPCN passthrough MBOX command to update these LED state.
+
+    2 - Service processor (FSP) controlled LEDs (System Attention Indicator)
+	During boot, we read/cache this LED info using MBOX command. Later
+	anytime FSP updates this LED, it sends update system parameter
+	notification MBOX command. We use that data to update cached data.
+	LED update request is sent via set/reset attn MBOX command.
+
+  LED update request:
+    Both FSP and Host will send LED update requests. We have to serialize
+    SPCN passthrough command. Hence we maintain local queue.
+
 Note:
   - For more information regarding service indicator refer to PAPR spec
     (Service Indicators chapter).
diff --git a/hw/fsp/fsp-leds.c b/hw/fsp/fsp-leds.c
index 5aa6f20..83d4b38 100644
--- a/hw/fsp/fsp-leds.c
+++ b/hw/fsp/fsp-leds.c
@@ -70,6 +70,7 @@ static struct list_head  spcn_cmdq;	/* SPCN command queue */
 /* LED lock */
 static struct lock led_lock = LOCK_UNLOCKED;
 static struct lock spcn_cmd_lock = LOCK_UNLOCKED;
+static struct lock sai_lock = LOCK_UNLOCKED;
 
 static bool spcn_cmd_complete = true;	/* SPCN command complete */
 
@@ -201,6 +202,135 @@ static inline void opal_led_update_complete(u64 async_token, u64 result)
 	opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL, async_token, result);
 }
 
+static inline bool is_sai_loc_code(char *loc_code)
+{
+	if (!strcmp(sai_data.loc_code, loc_code))
+		return true;
+
+	return false;
+}
+
+/* Set/Reset System attention indicator */
+static void fsp_set_sai_complete(struct fsp_msg *msg)
+{
+	int ret = OPAL_SUCCESS;
+	int rc = msg->resp->word1 & 0xff00;
+	struct led_set_cmd *spcn_cmd = (struct led_set_cmd *)msg->user_data;
+
+	if (rc) {
+		prlog(PR_ERR, PREFIX "Update SAI cmd failed [rc=%d].\n", rc);
+		ret = OPAL_INTERNAL_ERROR;
+
+		/* Roll back */
+		lock(&sai_lock);
+		sai_data.state = spcn_cmd->ckpt_status;
+		unlock(&sai_lock);
+	}
+
+	if (spcn_cmd->cmd_src == SPCN_SRC_OPAL)
+		opal_led_update_complete(spcn_cmd->async_token, ret);
+
+	/* free msg and spcn command */
+	free(spcn_cmd);
+	fsp_freemsg(msg);
+
+	/* Process pending LED update request */
+	process_led_state_change();
+}
+
+static int fsp_set_sai(struct led_set_cmd *spcn_cmd)
+{
+	int rc = -ENOMEM;
+	uint32_t cmd = FSP_CMD_SA_INDICATOR;
+	struct fsp_msg *msg;
+
+	/*
+	 * FSP does not allow hypervisor to set real SAI, but we can
+	 * reset real SAI. Also in our case only host can control
+	 * LEDs, not guests. Hence we will set platform virtual SAI
+	 * and reset real SAI.
+	 */
+	if (spcn_cmd->state == LED_STATE_ON)
+		cmd |= FSP_LED_SET_PLAT_SAI;
+	else
+		cmd |= FSP_LED_RESET_REAL_SAI;
+
+	prlog(PR_TRACE, PREFIX
+	      "Update SAI Indicator [cur : 0x%x, new : 0x%x].\n",
+	      sai_data.state, spcn_cmd->state);
+
+	msg = fsp_mkmsg(cmd, 0);
+	if (!msg) {
+		prlog(PR_ERR, PREFIX
+		      "%s: Memory allocation failed.\n", __func__);
+		goto sai_fail;
+	}
+
+	spcn_cmd->ckpt_status = sai_data.state;
+	msg->user_data = spcn_cmd;
+	rc = fsp_queue_msg(msg, fsp_set_sai_complete);
+	if (rc) {
+		fsp_freemsg(msg);
+		prlog(PR_ERR, PREFIX
+		      "%s: Failed to queue the message\n", __func__);
+		goto sai_fail;
+	}
+
+	lock(&sai_lock);
+	sai_data.state = spcn_cmd->state;
+	unlock(&sai_lock);
+
+	return OPAL_SUCCESS;
+
+sai_fail:
+	if (spcn_cmd->cmd_src == SPCN_SRC_OPAL)
+		opal_led_update_complete(spcn_cmd->async_token,
+					 OPAL_INTERNAL_ERROR);
+
+	return OPAL_INTERNAL_ERROR;
+}
+
+static void fsp_get_sai_complete(struct fsp_msg *msg)
+{
+	int rc = msg->resp->word1 & 0xff00;
+
+	if (rc) {
+		prlog(PR_ERR, PREFIX
+		      "Read real SAI cmd failed [rc = 0x%x].\n", rc);
+	} else { /* Update SAI state */
+		lock(&sai_lock);
+		sai_data.state = msg->resp->data.words[0] & 0xff;
+		unlock(&sai_lock);
+
+		prlog(PR_TRACE, PREFIX
+		      "SAI initial state = 0x%x\n", sai_data.state);
+	}
+
+	fsp_freemsg(msg);
+}
+
+/* Read initial SAI state. */
+static void fsp_get_sai(void)
+{
+	int rc;
+	uint32_t cmd = FSP_CMD_SA_INDICATOR | FSP_LED_READ_REAL_SAI;
+	struct fsp_msg *msg;
+
+	msg = fsp_mkmsg(cmd, 0);
+	if (!msg) {
+		prlog(PR_ERR, PREFIX
+		      "%s: Memory allocation failed.\n", __func__);
+		return;
+	}
+	rc = fsp_queue_msg(msg, fsp_get_sai_complete);
+	if (rc) {
+		fsp_freemsg(msg);
+		prlog(PR_ERR, PREFIX
+		      "%s: Failed to queue the message\n", __func__);
+	}
+}
+
+
 /*
  * Update both the local LED lists to reflect upon led state changes
  * occured with the recent SPCN command. Subsequent LED requests will
@@ -499,7 +629,11 @@ static int process_led_state_change(void)
 	spcn_cmd = list_pop(&spcn_cmdq, struct led_set_cmd, link);
 	unlock(&spcn_cmd_lock);
 
-	rc = fsp_msg_set_led_state(spcn_cmd);
+	if (is_sai_loc_code(spcn_cmd->loc_code))
+		rc = fsp_set_sai(spcn_cmd);
+	else
+		rc = fsp_msg_set_led_state(spcn_cmd);
+
 	if (rc) {
 		free(spcn_cmd);
 		process_led_state_change();
@@ -1094,6 +1228,31 @@ static struct fsp_client fsp_indicator_client = {
 };
 
 
+static int fsp_opal_get_sai(u64 *led_mask, u64 *led_value)
+{
+	*led_mask |= OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_ATTN;
+	if (sai_data.state & OPAL_SLOT_LED_STATE_ON)
+		*led_value |=
+			OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_ATTN;
+
+	return OPAL_SUCCESS;
+}
+
+static int fsp_opal_set_sai(uint64_t async_token, char *loc_code,
+			    const u64 led_mask, const u64 led_value)
+{
+	int state = LED_STATE_OFF;
+
+	if (!((led_mask >> OPAL_SLOT_LED_TYPE_ATTN) & OPAL_SLOT_LED_STATE_ON))
+		return OPAL_PARAMETER;
+
+	if ((led_value >> OPAL_SLOT_LED_TYPE_ATTN) & OPAL_SLOT_LED_STATE_ON)
+		state = LED_STATE_ON;
+
+	return queue_led_state_change(loc_code, 0,
+				      state, SPCN_SRC_OPAL, async_token);
+}
+
 /*
  * fsp_opal_leds_get_ind (OPAL_LEDS_GET_INDICATOR)
  *
@@ -1122,6 +1281,7 @@ static int64_t fsp_opal_leds_get_ind(char *loc_code, u64 *led_mask,
 {
 	bool supported = true;
 	int64_t max;
+	int rc;
 	struct fsp_led_data *led;
 
 	/* FSP not present */
@@ -1143,6 +1303,12 @@ static int64_t fsp_opal_leds_get_ind(char *loc_code, u64 *led_mask,
 	if (max <= 0)
 		return OPAL_PARAMETER;
 
+	/* Get System attention indicator state */
+	if (is_sai_loc_code(loc_code)) {
+		rc = fsp_opal_get_sai(led_mask, led_value);
+		return rc;
+	}
+
 	/* LED not found */
 	led = fsp_find_cec_led(loc_code);
 	if (!led)
@@ -1228,6 +1394,14 @@ static int64_t fsp_opal_leds_set_ind(uint64_t async_token,
 	if (max <= 0)
 		return OPAL_PARAMETER;
 
+	/* Set System attention indicator state */
+	if (is_sai_loc_code(loc_code)) {
+		supported = true;
+		rc = fsp_opal_set_sai(async_token,
+				      loc_code, led_mask, led_value);
+		goto success;
+	}
+
 	/* LED not found */
 	led = fsp_find_cec_led(loc_code);
 	if (!led)
@@ -1719,6 +1893,7 @@ void fsp_led_init(void)
 
 	/* Get System attention indicator state */
 	dt_get_sai_loc_code();
+	fsp_get_sai();
 
 	/* Handle FSP initiated async LED commands */
 	fsp_register_client(&fsp_indicator_client, FSP_MCLASS_INDICATOR);
diff --git a/include/fsp.h b/include/fsp.h
index f461575..c74996d 100644
--- a/include/fsp.h
+++ b/include/fsp.h
@@ -338,6 +338,8 @@
 #define FSP_RSP_ERRLOG_PHYP_ACK	0x0ce8800 /* FSP->HV */
 #define FSP_CMD_ERRLOG_GET_PLID	0x0ce0900 /* FSP->HV: Get PLID */
 #define FSP_RSP_ERRLOG_GET_PLID	0x0ce8900 /* HV->FSP */
+#define FSP_CMD_SA_INDICATOR	0x1ce1000 /* HV->FSP: read/update SAI */
+#define FSP_RSP_SA_INDICATOR	0x0ce9000 /* FSP->HV */
 #define FSP_CMD_QUERY_SPARM	0x1ce1200 /* HV->FSP: System parameter query */
 #define FSP_RSP_QUERY_SPARM	0x0ce9200 /* FSP->HV: System parameter resp */
 #define FSP_CMD_SET_SPARM_1	0x1ce1301 /* HV->FSP: Set system parameter */
@@ -370,6 +372,16 @@
 #define FSP_CMD_PANELSTATUS_EX1	0x0ce5c02 /* FSP->HV */
 #define FSP_CMD_PANELSTATUS_EX2	0x0ce5c03 /* FSP->HV */
 
+/* SAI read/update sub commands */
+#define FSP_LED_RESET_REAL_SAI		0x00
+#define FSP_LED_READ_REAL_SAI		0x02
+#define FSP_LED_RESET_PARTITION_SAI	0x80
+#define FSP_LED_SET_PARTITION_SAI	0x81
+#define FSP_LED_READ_PARTITION_SAI	0x82
+#define FSP_LED_READ_PLAT_SAI		0x83
+#define FSP_LED_RESET_PLAT_SAI		0x84
+#define FSP_LED_SET_PLAT_SAI		0x85
+
 /*
  * Class 0xD2
  */
diff --git a/include/opal-api.h b/include/opal-api.h
index 1698311..29421c1 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -376,7 +376,8 @@ enum OpalPciMaskAction {
 enum OpalSlotLedType {
 	OPAL_SLOT_LED_TYPE_ID = 0,	/* IDENTIFY LED */
 	OPAL_SLOT_LED_TYPE_FAULT = 1,	/* FAULT LED */
-	OPAL_SLOT_LED_TYPE_MAX = 2
+	OPAL_SLOT_LED_TYPE_ATTN = 2,	/* System Attention LED */
+	OPAL_SLOT_LED_TYPE_MAX = 3
 };
 
 enum OpalSlotLedState {



More information about the Skiboot mailing list