Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06ed8063 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents d9213f6b d1a006c8
Loading
Loading
Loading
Loading
+58 −22
Original line number Diff line number Diff line
@@ -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 @@ static void adsp_load_fw(struct work_struct *adsp_ldr_work)
		}

		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
Original line number Diff line number Diff line
/* 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
Original line number Diff line number Diff line
// 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)
@@ -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();
}