From patchwork Thu Feb 5 08:41:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasant Hegde X-Patchwork-Id: 436688 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 140911401DE for ; Thu, 5 Feb 2015 19:42:23 +1100 (AEDT) Received: from ozlabs.org (ozlabs.org [103.22.144.67]) by lists.ozlabs.org (Postfix) with ESMTP id F360F1A1096 for ; Thu, 5 Feb 2015 19:42:22 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from e23smtp02.au.ibm.com (e23smtp02.au.ibm.com [202.81.31.144]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 127211A0F44 for ; Thu, 5 Feb 2015 19:41:56 +1100 (AEDT) Received: from /spool/local by e23smtp02.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 5 Feb 2015 18:41:55 +1000 Received: from d23dlp01.au.ibm.com (202.81.31.203) by e23smtp02.au.ibm.com (202.81.31.208) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 5 Feb 2015 18:41:52 +1000 Received: from d23relay09.au.ibm.com (d23relay09.au.ibm.com [9.185.63.181]) by d23dlp01.au.ibm.com (Postfix) with ESMTP id 8AF972CE804E for ; Thu, 5 Feb 2015 19:41:52 +1100 (EST) Received: from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97]) by d23relay09.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t158fiHQ44498990 for ; Thu, 5 Feb 2015 19:41:52 +1100 Received: from d23av03.au.ibm.com (localhost [127.0.0.1]) by d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t158fJes003220 for ; Thu, 5 Feb 2015 19:41:19 +1100 Received: from localhost.localdomain ([9.124.35.64]) by d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t158fIAJ002779 for ; Thu, 5 Feb 2015 19:41:18 +1100 From: Vasant Hegde To: skiboot@lists.ozlabs.org Date: Thu, 05 Feb 2015 14:11:03 +0530 Message-ID: <20150205084103.12859.26553.stgit@localhost.localdomain> In-Reply-To: <20150205083611.12859.41225.stgit@localhost.localdomain> References: <20150205083611.12859.41225.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15020508-0005-0000-0000-0000014B3BF4 Subject: [Skiboot] [PATCH 15/22] FSP/LEDS: Implement a set LED SPCN command queue X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Simultaneous FSP async commands and OPAL requests to change various LED states will generate multiple SPCN commands back to back before their callback get processed. With this, some of the SPCN requests might get overridden with the newer ones and hence will be lost. This patch implements a set LED SPCN command queue which will serialize multiple SPCN commands generated either through FSP async or OPAL requests. All new requests are added to the queue when any previous SPCN command completion is still pending. These requests would be de-queued and then processed inside the SPCN command callback function sequentially. This ensures completion of all the generated LED state change requests without any loss. Signed-off-by: Vasant Hegde Signed-off-by: Anshuman Khandual --- hw/fsp/fsp-leds.c | 141 ++++++++++++++++++++++++++++++++++++++++++----------- hw/fsp/fsp-leds.h | 8 +++ 2 files changed, 121 insertions(+), 28 deletions(-) diff --git a/hw/fsp/fsp-leds.c b/hw/fsp/fsp-leds.c index cf3328b..16c9b68 100644 --- a/hw/fsp/fsp-leds.c +++ b/hw/fsp/fsp-leds.c @@ -65,16 +65,21 @@ static void *led_buffer; */ static struct list_head cec_ledq; /* CEC LED list */ static struct list_head encl_ledq; /* Enclosure LED list */ +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 bool spcn_cmd_cmplt = true; /* SPCN command complete */ /* Last SPCN command */ static u32 last_spcn_cmd; static int replay = 0; - +/* Forward declaration */ static void fsp_read_leds_data_complete(struct fsp_msg *msg); +static int process_led_state_change(void); DEFINE_LOG_ENTRY(OPAL_RC_LED_SPCN, OPAL_PLATFORM_ERR_EVT, OPAL_LED, OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL, @@ -282,7 +287,12 @@ static void fsp_spcn_set_led_completion(struct fsp_msg *msg) prerror(PREFIX "Failed to queue FSP_RSP_SET_LED_STATE\n"); } } + + /* free msg */ fsp_freemsg(msg); + + /* Process pending LED update request */ + process_led_state_change(); } /* @@ -299,7 +309,7 @@ static void fsp_spcn_set_led_completion(struct fsp_msg *msg) * char lc_code[LOC_CODE_SIZE]; *}; */ -static int fsp_msg_set_led_state(char *loc_code, bool command, bool state) +static int fsp_msg_set_led_state(struct led_set_cmd *spcn_cmd) { struct spcn_led_data sled; struct fsp_msg *msg = NULL; @@ -309,8 +319,8 @@ static int fsp_msg_set_led_state(char *loc_code, bool command, bool state) u32 cmd_hdr = 0; int rc = -1; - sled.lc_len = strlen(loc_code); - strncpy(sled.lc_code, loc_code, sled.lc_len); + sled.lc_len = strlen(spcn_cmd->loc_code); + strncpy(sled.lc_code, spcn_cmd->loc_code, sled.lc_len); /* Location code length + Location code + LED control */ data_len = LOC_CODE_LEN + sled.lc_len + LED_CONTROL_LEN; @@ -318,7 +328,7 @@ static int fsp_msg_set_led_state(char *loc_code, bool command, bool state) data_len; /* Fetch the current state of LED */ - led = fsp_find_cec_led(loc_code); + led = fsp_find_cec_led(spcn_cmd->loc_code); /* LED not present */ if (led == NULL) { @@ -350,35 +360,35 @@ static int fsp_msg_set_led_state(char *loc_code, bool command, bool state) sled.state = led->status; /* Update the exclussive LED bits */ - if (is_enclosure_led(loc_code)) { - if (command == LED_COMMAND_FAULT) { - if (state == LED_STATE_ON) + if (is_enclosure_led(spcn_cmd->loc_code)) { + if (spcn_cmd->command == LED_COMMAND_FAULT) { + if (spcn_cmd->state == LED_STATE_ON) led->excl_bit |= FSP_LED_EXCL_FAULT; - if (state == LED_STATE_OFF) + if (spcn_cmd->state == LED_STATE_OFF) led->excl_bit &= ~FSP_LED_EXCL_FAULT; } - if (command == LED_COMMAND_IDENTIFY) { - if (state == LED_STATE_ON) + if (spcn_cmd->command == LED_COMMAND_IDENTIFY) { + if (spcn_cmd->state == LED_STATE_ON) led->excl_bit |= FSP_LED_EXCL_IDENTIFY; - if (state == LED_STATE_OFF) + if (spcn_cmd->state == LED_STATE_OFF) led->excl_bit &= ~FSP_LED_EXCL_IDENTIFY; } } /* LED FAULT commad */ - if (command == LED_COMMAND_FAULT) { - if (state == LED_STATE_ON) + if (spcn_cmd->command == LED_COMMAND_FAULT) { + if (spcn_cmd->state == LED_STATE_ON) sled.state |= SPCN_LED_FAULT_MASK; - if (state == LED_STATE_OFF) + if (spcn_cmd->state == LED_STATE_OFF) sled.state &= ~SPCN_LED_FAULT_MASK; } /* LED IDENTIFY command */ - if (command == LED_COMMAND_IDENTIFY) { - if (state == LED_STATE_ON) + if (spcn_cmd->command == LED_COMMAND_IDENTIFY) { + if (spcn_cmd->state == LED_STATE_ON) sled.state |= SPCN_LED_IDENTIFY_MASK; - if (state == LED_STATE_OFF) + if (spcn_cmd->state == LED_STATE_OFF) sled.state &= ~SPCN_LED_IDENTIFY_MASK; } @@ -397,7 +407,7 @@ static int fsp_msg_set_led_state(char *loc_code, bool command, bool state) * set/reset an individual led (CEC or ENCL). */ lock(&led_lock); - update_led_list(loc_code, sled.state); + update_led_list(spcn_cmd->loc_code, sled.state); msg->user_data = led; unlock(&led_lock); @@ -408,6 +418,87 @@ static int fsp_msg_set_led_state(char *loc_code, bool command, bool state) } /* + * process_led_state_change + * + * If the command queue is empty, it sets the 'spcn_cmd_cmplt' as true + * and just returns. Else it pops one element from the command queue + * and processes the command for the requested LED state change. + */ +static int process_led_state_change(void) +{ + struct led_set_cmd *spcn_cmd; + int rc = 0; + + /* + * The command queue is empty. This will only + * happen during the SPCN command callback path + * in which case we set 'spcn_cmd_cmplt' as true. + */ + lock(&spcn_cmd_lock); + if (list_empty(&spcn_cmdq)) { + spcn_cmd_cmplt = true; + unlock(&spcn_cmd_lock); + return rc; + } + + spcn_cmd = list_pop(&spcn_cmdq, struct led_set_cmd, link); + unlock(&spcn_cmd_lock); + + rc = fsp_msg_set_led_state(spcn_cmd); + if (rc) + log_simple_error(&e_info(OPAL_RC_LED_STATE), + PREFIX "Set led state failed at LC=%s\n", + spcn_cmd->loc_code); + free(spcn_cmd); + return rc; +} + +/* + * queue_led_state_change + * + * FSP async command or OPAL based request for LED state change gets queued + * up in the command queue. If no previous SPCN command is pending, then it + * immediately pops up one element from the list and processes it. If previous + * SPCN commands are still pending then it just queues up and return. When the + * SPCN command callback gets to execute, it processes one element from the + * list and keeps the chain execution going. At last when there are no elements + * in the command queue it sets 'spcn_cmd_cmplt' as true again. + */ +static int queue_led_state_change(char *loc_code, u8 command, u8 state) +{ + struct led_set_cmd *cmd; + int rc = 0; + + /* New request node */ + cmd = zalloc(sizeof(struct led_set_cmd)); + if (!cmd) { + prlog(PR_ERR, PREFIX + "SPCN set command node allocation failed\n"); + return -1; + } + + /* Save the request */ + strncpy(cmd->loc_code, loc_code, strlen(loc_code)); + cmd->command = command; + cmd->state = state; + + /* Add to the queue */ + lock(&spcn_cmd_lock); + list_add_tail(&spcn_cmdq, &cmd->link); + + /* No previous SPCN command pending */ + if (spcn_cmd_cmplt) { + spcn_cmd_cmplt = false; + unlock(&spcn_cmd_lock); + rc = process_led_state_change(); + return rc; + } + + unlock(&spcn_cmd_lock); + return rc; +} + +/* * Write single location code information into the TCE outbound buffer * * Data layout @@ -820,19 +911,12 @@ static void fsp_set_led_state(struct fsp_msg *msg) if (!strcmp(led->loc_code, req.loc_code)) continue; - if (fsp_msg_set_led_state(led->loc_code, - command, state)) - log_simple_error(&e_info(OPAL_RC_LED_STATE), - PREFIX "Set led state failed at LC=%s\n", - led->loc_code); + queue_led_state_change(led->loc_code, command, state); } break; case SET_IND_SINGLE_LOC_CODE: /* Set led state for single descendent led */ - if (fsp_msg_set_led_state(req.loc_code, command, state)) - log_simple_error(&e_info(OPAL_RC_LED_STATE), - PREFIX "Set led state failed at LC=%s\n", - req.loc_code); + queue_led_state_change(req.loc_code, command, state); break; default: resp = fsp_mkmsg(FSP_RSP_SET_LED_STATE | @@ -1335,6 +1419,7 @@ void fsp_led_init(void) /* Init the master lists */ list_head_init(&cec_ledq); list_head_init(&encl_ledq); + list_head_init(&spcn_cmdq); fsp_leds_query_spcn(); prlog(PR_TRACE, PREFIX "Init completed\n"); diff --git a/hw/fsp/fsp-leds.h b/hw/fsp/fsp-leds.h index 4cf4816..a09a27e 100644 --- a/hw/fsp/fsp-leds.h +++ b/hw/fsp/fsp-leds.h @@ -108,6 +108,14 @@ struct fsp_set_ind_state_req { char loc_code[LOC_CODE_SIZE]; }; +/* LED set SPCN command */ +struct led_set_cmd { + char loc_code[LOC_CODE_SIZE]; + u8 command; + u8 state; + struct list_node link; +}; + /* LED commands and state */ #define LED_COMMAND_FAULT 1 #define LED_COMMAND_IDENTIFY 0