[Skiboot] [PATCH] FSP: Do not process incoming FSP messages in fsp_sync_msg path

Vasant Hegde hegdevasant at linux.vnet.ibm.com
Tue Mar 10 17:22:24 AEDT 2015


Presently we process incoming messages from FSP all the time.
Our fsp_fetch_data function holds lock and calls fsp_sync_msg.
Due to our callback mechanism its possible that in some cases
we may hit recursive lock issue in fsp_fetch_data.

Sample code path:
  fsp_fetch_data ->
     fsp_sync_msg ->
       Incoming message (ex: OCC LID load) ->
         notify registered client (ex: fsp_occ_msg) ->
	   fsp_fetch_data -> Lock issue!

This patch adds support to queue incoming messages in fsp_fetch_data
path. That way we are sure that we will not hit above scenario. Also
I have changed locking code in fsp_fetch_data. Now we just hold lock
to update flag.

Note:
  We still have one lock issue in poller path. (We held capi_lock in
  capp_lid_download and call opal_run_pollers via load_resources).

  [4108781364,3] Running pollers with lock held !
  CPU 0830 Backtrace:
  S: 0000000033ac3800 R: 0000000030013520   .backtrace+0x2c
  S: 0000000033ac3890 R: 0000000030017dd8   .opal_run_pollers+0x44
  S: 0000000033ac3910 R: 0000000030046190   .fsp_sync_msg+0x40
  S: 0000000033ac39a0 R: 0000000030047c10   .fsp_fetch_data+0x188
  S: 0000000033ac3a90 R: 0000000030047ed8   .fsp_load_resource+0x12c
  S: 0000000033ac3b50 R: 0000000030021bb0   .load_resource+0x38
  S: 0000000033ac3bc0 R: 000000003003b610   .capp_load_ucode+0x168
  S: 0000000033ac3c90 R: 0000000030041140   .probe_phb3+0x1224
  S: 0000000033ac3e30 R: 000000003001420c   .main_cpu_entry+0x444
  S: 0000000033ac3f00 R: 0000000030002524   boot_entry+0x18c

Signed-off-by: Vasant Hegde <hegdevasant at linux.vnet.ibm.com>
---
 hw/fsp/fsp.c |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 70 insertions(+), 1 deletion(-)

diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
index fdf175a..c73a193 100644
--- a/hw/fsp/fsp.c
+++ b/hw/fsp/fsp.c
@@ -117,6 +117,13 @@ static u32 disr_last_print;
 static u32 drcr_last_print;
 static u32 hstate_last_print;
 
+/*
+ * Keep track of incoming messages during sychronous FSP call from
+ * fsp_fetch_data and process them later.
+ */
+static LIST_HEAD(fsp_msg_list);
+static bool fsp_handle_cmd_ready = true;
+
 void fsp_handle_resp(struct fsp_msg *msg);
 
 struct fsp_cmdclass {
@@ -1254,7 +1261,7 @@ static bool fsp_local_command(u32 cmd_sub_mod, struct fsp_msg *msg)
 
 
 /* This is called without the FSP lock */
-static void fsp_handle_command(struct fsp_msg *msg)
+static void __fsp_handle_command(struct fsp_msg *msg)
 {
 	struct fsp_cmdclass *cmdclass = fsp_get_cmdclass(msg);
 	struct fsp_client *client, *next;
@@ -1300,6 +1307,49 @@ static void fsp_handle_command(struct fsp_msg *msg)
 	fsp_freemsg(msg);
 }
 
+/*
+ * Queue incoming messages, if we are in the middle of
+ * fsp_sync_msg call
+ */
+static void fsp_handle_command(struct fsp_msg *msg)
+{
+	u32 cmd_sub_mod;
+
+	/*
+	 * Check if we are ready to handle command. If not, queue
+	 * incoming message.
+	 *
+	 * XXX: Note that we use same link (msg->link) in fsp_queue_msg()
+	 *      as well. But these are two different path. Hence we are
+	 *      fine here.
+	 */
+	if (!fsp_handle_cmd_ready) {
+		cmd_sub_mod =  (msg->word0 & 0xff) << 16;
+		cmd_sub_mod |= (msg->word1 & 0xff) << 8;
+		cmd_sub_mod |= (msg->word1 >> 8) & 0xff;
+		prlog(PR_TRACE, "FSP: Queued incoming message [%x]\n",
+		      cmd_sub_mod);
+
+		list_add_tail(&fsp_msg_list, &msg->link);
+		return;
+	}
+
+	__fsp_handle_command(msg);
+}
+
+static void fsp_poke_cmd_queue(void)
+{
+	struct fsp_msg *msg;
+
+	if (list_empty(&fsp_msg_list))
+		return;
+
+	list_for_each(&fsp_msg_list, msg, link) {
+		list_del(&msg->link);
+		__fsp_handle_command(msg);
+	}
+}
+
 static void __fsp_fill_incoming(struct fsp *fsp, struct fsp_msg *msg,
 				int dlen, u32 w0, u32 w1)
 {
@@ -2166,6 +2216,19 @@ int fsp_fetch_data(uint8_t flags, uint16_t id, uint32_t sub_id,
 	 */
 	lock(&fsp_fetch_lock);
 
+	/*
+	 * XXX: This means we are re-entering this code. Ideally this
+	 * should never happen.
+	 */
+	if (!fsp_handle_cmd_ready) {
+		prlog(PR_ERR, "FSP: Re-entering fsp_fetch_data!\n");
+		unlock(&fsp_fetch_lock);
+		return -EBUSY;
+	}
+
+	fsp_handle_cmd_ready = false;
+	unlock(&fsp_fetch_lock);
+
 	while(remaining) {
 		uint32_t chunk, taddr, woffset, wlen;
 		uint8_t rc;
@@ -2201,7 +2264,10 @@ int fsp_fetch_data(uint8_t flags, uint16_t id, uint32_t sub_id,
 
 		/* XXX Is flash busy (0x3f) a reason for retry ? */
 		if (rc != 0 && rc != 2) {
+			lock(&fsp_fetch_lock);
+			fsp_handle_cmd_ready = true;
 			unlock(&fsp_fetch_lock);
+			fsp_poke_cmd_queue();
 			return -EIO;
 		}
 
@@ -2218,10 +2284,13 @@ int fsp_fetch_data(uint8_t flags, uint16_t id, uint32_t sub_id,
 		if (wlen < chunk)
 			break;
 	}
+	lock(&fsp_fetch_lock);
+	fsp_handle_cmd_ready = true;
 	unlock(&fsp_fetch_lock);
 
 	*length = total;
 
+	fsp_poke_cmd_queue();
 	return 0;
 }
 



More information about the Skiboot mailing list