Prechádzať zdrojové kódy

Merge "dsp: adsp-loader: Support ADSP restart recovery when stuck"

qctecmdr 4 rokov pred
rodič
commit
06ed8063cd
3 zmenil súbory, kde vykonal 103 pridanie a 26 odobranie
  1. 58 22
      dsp/adsp-loader.c
  2. 10 1
      include/ipc/apr.h
  3. 35 3
      ipc/apr.c

+ 58 - 22
dsp/adsp-loader.c

@@ -55,6 +55,51 @@ static struct work_struct adsp_ldr_work;
 static struct platform_device *adsp_private;
 static void adsp_loader_unload(struct platform_device *pdev);
 
+static int adsp_restart_subsys(void)
+{
+	struct subsys_device *adsp_dev = NULL;
+	struct platform_device *pdev = adsp_private;
+	struct adsp_loader_private *priv = NULL;
+	int rc = -EINVAL;
+
+	priv = platform_get_drvdata(pdev);
+	if (!priv)
+		return rc;
+
+	adsp_dev = (struct subsys_device *)priv->pil_h;
+	if (!adsp_dev)
+		return rc;
+
+	/* subsystem_restart_dev has worker queue to handle */
+	rc = subsystem_restart_dev(adsp_dev);
+	if (rc) {
+		dev_err(&pdev->dev, "subsystem_restart_dev failed\n");
+		return rc;
+	}
+	pr_debug("%s :: Restart Success %d\n", __func__, rc);
+	return rc;
+}
+
+static void adsp_load_state_notify_cb(enum apr_subsys_state state,
+						void *phandle)
+{
+	struct platform_device *pdev = adsp_private;
+	struct adsp_loader_private *priv = NULL;
+
+	priv = platform_get_drvdata(pdev);
+	if (!priv)
+		return;
+	if (phandle != adsp_private) {
+		pr_err("%s:callback is not for adsp-loader client\n", __func__);
+		return;
+	}
+	pr_debug("%s:: Received cb for ADSP restart\n", __func__);
+	if (state == APR_SUBSYS_UNKNOWN)
+		adsp_restart_subsys();
+	else
+		pr_debug("%s:Ignore restart request for ADSP", __func__);
+}
+
 static void adsp_load_fw(struct work_struct *adsp_ldr_work)
 {
 	struct platform_device *pdev = adsp_private;
@@ -63,6 +108,7 @@ static void adsp_load_fw(struct work_struct *adsp_ldr_work)
 	int rc = 0;
 	u32 adsp_state;
 	const char *img_name;
+	void *padsp_restart_cb = &adsp_load_state_notify_cb;
 
 	if (!pdev) {
 		dev_err(&pdev->dev, "%s: Platform device null\n", __func__);
@@ -119,7 +165,7 @@ static void adsp_load_fw(struct work_struct *adsp_ldr_work)
 		}
 
 		dev_dbg(&pdev->dev, "%s: Q6/MDSP image is loaded\n", __func__);
-		return;
+		goto success;
 	}
 
 load_adsp:
@@ -153,10 +199,13 @@ load_adsp:
 		}
 
 		dev_dbg(&pdev->dev, "%s: Q6/ADSP image is loaded\n", __func__);
-		return;
+		apr_register_adsp_state_cb(padsp_restart_cb, adsp_private);
+		goto success;
 	}
 fail:
 	dev_err(&pdev->dev, "%s: Q6 image loading failed\n", __func__);
+success:
+	return;
 }
 
 static void adsp_loader_do(struct platform_device *pdev)
@@ -170,37 +219,24 @@ static ssize_t adsp_ssr_store(struct kobject *kobj,
 	size_t count)
 {
 	int ssr_command = 0;
-	struct subsys_device *adsp_dev = NULL;
 	struct platform_device *pdev = adsp_private;
 	struct adsp_loader_private *priv = NULL;
-	int rc;
+	int rc = -EINVAL;
 
 	dev_dbg(&pdev->dev, "%s: going to call adsp ssr\n ", __func__);
 
-	if (kstrtoint(buf, 10, &ssr_command) < 0)
-		return -EINVAL;
-
-	if (ssr_command != SSR_RESET_CMD)
-		return -EINVAL;
-
 	priv = platform_get_drvdata(pdev);
 	if (!priv)
-		return -EINVAL;
+		return rc;
 
-	adsp_dev = (struct subsys_device *)priv->pil_h;
-	if (!adsp_dev)
+	if (kstrtoint(buf, 10, &ssr_command) < 0)
 		return -EINVAL;
 
-	dev_err(&pdev->dev, "requesting for ADSP restart\n");
-
-	/* subsystem_restart_dev has worker queue to handle */
-	rc = subsystem_restart_dev(adsp_dev);
-	if (rc) {
-		dev_err(&pdev->dev, "subsystem_restart_dev failed\n");
-		return rc;
-	}
+	if (ssr_command != SSR_RESET_CMD)
+		return -EINVAL;
 
-	dev_dbg(&pdev->dev, "ADSP restarted\n");
+	adsp_restart_subsys();
+	dev_dbg(&pdev->dev, "%s :: ADSP restarted\n", __func__);
 	return count;
 }
 

+ 10 - 1
include/ipc/apr.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2017, 2019, 2020, The Linux Foundation. All rights reserved.
  */
 #ifndef __APR_H_
 #define __APR_H_
@@ -12,6 +12,7 @@ enum apr_subsys_state {
 	APR_SUBSYS_DOWN,
 	APR_SUBSYS_UP,
 	APR_SUBSYS_LOADED,
+	APR_SUBSYS_UNKNOWN,
 };
 
 struct apr_q6 {
@@ -19,6 +20,13 @@ struct apr_q6 {
 	atomic_t q6_state;
 	atomic_t modem_state;
 	struct mutex lock;
+/*
+ * ToDo - Multiple client support to be added.
+ * And checking for state UNKNOWN currently.
+ */
+	void (*state_notify_cb)(enum apr_subsys_state state,
+				void *client_handle);
+	void *client_handle;
 };
 
 struct apr_hdr {
@@ -186,4 +194,5 @@ const char *apr_get_lpass_subsys_name(void);
 uint16_t apr_get_reset_domain(uint16_t proc);
 int apr_start_rx_rt(void *handle);
 int apr_end_rx_rt(void *handle);
+void apr_register_adsp_state_cb(void *adsp_cb, void *client_handle);
 #endif

+ 35 - 3
ipc/apr.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2010-2014, 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, 2016-2020 The Linux Foundation. All rights reserved.
  */
 
 #include <linux/kernel.h>
@@ -32,9 +32,14 @@
 
 #define APR_PKT_IPC_LOG_PAGE_CNT 2
 
+static int apr_pkt_cnt_adsp_restart = 20;
+module_param(apr_pkt_cnt_adsp_restart, int, 0664);
+MODULE_PARM_DESC(apr_pkt_cnt_adsp_restart, "set apr pktcount for adsp restart feature");
+
 static struct apr_q6 q6;
 static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
 static void *apr_pkt_ctx;
+static int apr_send_pkt_count;
 static wait_queue_head_t modem_wait;
 static bool is_modem_up;
 static char *subsys_name = NULL;
@@ -61,6 +66,8 @@ struct apr_private {
 
 static struct apr_private *apr_priv;
 static bool apr_cf_debug;
+static struct work_struct apr_cb_work;
+static void state_notify_cb(struct work_struct *work);
 
 #ifdef CONFIG_DEBUG_FS
 static struct dentry *debugfs_apr_debug;
@@ -313,6 +320,7 @@ static void apr_adsp_up(void)
 		schedule_work(&apr_priv->add_chld_dev_work);
 	spin_unlock(&apr_priv->apr_lock);
 	snd_event_notify(apr_priv->dev, SND_EVENT_UP);
+	cancel_work_sync(&apr_cb_work);
 }
 
 int apr_load_adsp_image(void)
@@ -415,7 +423,7 @@ int apr_send_pkt(void *handle, uint32_t *buf)
 		w_len = rc;
 		if (w_len != hdr->pkt_size) {
 			pr_err("%s: Unable to write whole APR pkt successfully: %d\n",
-			       __func__, rc);
+				__func__, rc);
 			rc = -EINVAL;
 		}
 	} else {
@@ -426,6 +434,17 @@ int apr_send_pkt(void *handle, uint32_t *buf)
 					__func__);
 			rc = -ENETRESET;
 		}
+		if (rc == -EAGAIN || rc == -ETIMEDOUT) {
+			apr_send_pkt_count++;
+			pr_err("%s:: send pkt timedout apr_send_pkt_count %d\n",
+				__func__, apr_send_pkt_count);
+		}
+	}
+	if (apr_send_pkt_count == apr_pkt_cnt_adsp_restart) {
+		pr_debug("%s:: schedule work for adsp loader restart cb\n",
+				__func__);
+		schedule_work(&apr_cb_work);
+		apr_send_pkt_count = 0;
 	}
 	spin_unlock_irqrestore(&svc->w_lock, flags);
 
@@ -800,6 +819,19 @@ static void apr_reset_deregister(struct work_struct *work)
 	kfree(apr_reset);
 }
 
+static void state_notify_cb(struct work_struct *work)
+{
+	if (q6.state_notify_cb)
+		q6.state_notify_cb(APR_SUBSYS_UNKNOWN, q6.client_handle);
+}
+
+void apr_register_adsp_state_cb(void *adsp_cb, void *client_handle)
+{
+	q6.state_notify_cb = adsp_cb;
+	q6.client_handle = client_handle;
+}
+EXPORT_SYMBOL(apr_register_adsp_state_cb);
+
 /**
  * apr_start_rx_rt - Clients call to vote for thread
  * priority upgrade whenever needed.
@@ -1212,7 +1244,7 @@ static int apr_probe(struct platform_device *pdev)
 			__func__, ret);
 		ret = 0;
 	}
-
+	INIT_WORK(&apr_cb_work, state_notify_cb);
 	return apr_debug_init();
 }