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

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

Merge "msm: npu: handle system shutdown/reboot event properly"

parents 65ce6f82 48b897f2
Loading
Loading
Loading
Loading
+119 −40
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "npu_common.h"
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/subsystem_restart.h>
#include <linux/reboot.h>

/* -------------------------------------------------------------------------
 * Defines
@@ -279,6 +280,50 @@ int load_fw(struct npu_device *npu_dev)
	return 0;
}

static void complete_pending_commands(struct npu_host_ctx *host_ctx)
{
	struct npu_network *network = NULL;
	struct npu_kevent kevt;
	struct npu_network_cmd *cmd;
	struct npu_misc_cmd *misc_cmd;
	int i;

	/* flush all pending npu cmds */
	for (i = 0; i < MAX_LOADED_NETWORK; i++) {
		network = &host_ctx->networks[i];
		if (!network->is_valid || !network->fw_error)
			continue;

		if (network->is_async) {
			NPU_DBG("async cmd, queue ssr event\n");
			kevt.evt.type = MSM_NPU_EVENT_TYPE_SSR;
			kevt.evt.u.ssr.network_hdl =
				network->network_hdl;
			if (npu_queue_event(network->client, &kevt))
				NPU_ERR("queue npu event failed\n");

			while (!list_empty(&network->cmd_list)) {
				cmd = list_first_entry(&network->cmd_list,
					struct npu_network_cmd, list);
				npu_dequeue_network_cmd(network, cmd);
				npu_free_network_cmd(host_ctx, cmd);
			}
		} else {
			list_for_each_entry(cmd, &network->cmd_list, list) {
				NPU_INFO("complete network %llx trans_id %d\n",
					network->id, cmd->trans_id);
				complete(&cmd->cmd_done);
			}
		}
	}

	list_for_each_entry(misc_cmd, &host_ctx->misc_cmd_list, list) {
		NPU_INFO("complete misc cmd trans_id %d\n",
			misc_cmd->trans_id);
		complete(&misc_cmd->cmd_done);
	}
}

int unload_fw(struct npu_device *npu_dev)
{
	struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
@@ -294,7 +339,9 @@ int unload_fw(struct npu_device *npu_dev)
		mutex_unlock(&host_ctx->lock);
		return 0;
	} else if (host_ctx->fw_state == FW_ENABLED) {
		NPU_ERR("fw is enabled now, can't be unloaded\n");
		NPU_ERR("fw is enabled now, device is shutting down?\n");
		host_ctx->dev_shuttingdown = true;
		complete_pending_commands(host_ctx);
		mutex_unlock(&host_ctx->lock);
		return -EBUSY;
	}
@@ -315,6 +362,11 @@ static int enable_fw_nolock(struct npu_device *npu_dev)
	int ret = 0;
	uint32_t reg_val;

	if (host_ctx->dev_shuttingdown) {
		NPU_ERR("device is shutting down, ignore enable request\n");
		return -EIO;
	}

	if (host_ctx->fw_state == FW_UNLOADED) {
		ret = load_fw_nolock(npu_dev,
			host_ctx->auto_pil_disable ? true : false);
@@ -470,6 +522,11 @@ static int disable_fw_nolock(struct npu_device *npu_dev)
	if (host_ctx->fw_ref_cnt > 0)
		return ret;

	if (host_ctx->dev_shuttingdown) {
		NPU_ERR("device is shutting down, ignore disable request\n");
		return -EIO;
	}

	/* turn on auto ACK for warm shuts down */
	npu_cc_reg_write(npu_dev, NPU_CC_NPU_CPC_RSC_CTRL, 3);
	reinit_completion(&host_ctx->fw_shutdown_done);
@@ -712,6 +769,24 @@ static int npu_panic_handler(struct notifier_block *this,
	return NOTIFY_DONE;
}

static int npu_reboot_handler(struct notifier_block *this,
				unsigned long code, void *unused)
{
	struct npu_host_ctx *host_ctx =
		container_of(this, struct npu_host_ctx, reboot_nb);

	NPU_INFO("Device is rebooting with code %d\n", code);

	if ((code == NOTIFY_DONE) || (code == SYS_POWER_OFF)) {
		mutex_lock(&host_ctx->lock);
		host_ctx->dev_shuttingdown = true;
		complete_pending_commands(host_ctx);
		mutex_unlock(&host_ctx->lock);
	}

	return NOTIFY_DONE;
}

static void npu_update_pwr_work(struct work_struct *work)
{
	int ret;
@@ -764,6 +839,13 @@ int npu_host_init(struct npu_device *npu_dev)
		goto fail;
	}

	host_ctx->reboot_nb.notifier_call = npu_reboot_handler;
	ret = register_reboot_notifier(&host_ctx->reboot_nb);
	if (ret) {
		NPU_ERR("register reboot notifier failed\n");
		goto fail;
	}

	host_ctx->panic_nb.notifier_call = npu_panic_handler;
	ret = atomic_notifier_chain_register(&panic_notifier_list,
		&host_ctx->panic_nb);
@@ -839,6 +921,7 @@ int npu_host_init(struct npu_device *npu_dev)
	if (host_ctx->notif_hdle)
		subsys_notif_unregister_notifier(host_ctx->notif_hdle,
			&host_ctx->nb);
	unregister_reboot_notifier(&host_ctx->reboot_nb);
	mutex_destroy(&host_ctx->lock);
	return ret;
}
@@ -854,6 +937,7 @@ void npu_host_deinit(struct npu_device *npu_dev)
	destroy_workqueue(host_ctx->wq);
	destroy_workqueue(host_ctx->wq_pri);
	subsys_notif_unregister_notifier(host_ctx->notif_hdle, &host_ctx->nb);
	unregister_reboot_notifier(&host_ctx->reboot_nb);
	mutex_destroy(&host_ctx->lock);
}

@@ -947,9 +1031,6 @@ static int host_error_hdlr(struct npu_device *npu_dev, bool force)
{
	struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
	struct npu_network *network = NULL;
	struct npu_kevent kevt;
	struct npu_network_cmd *cmd;
	struct npu_misc_cmd *misc_cmd;
	bool fw_alive = true;
	int i, ret = 0;

@@ -961,6 +1042,12 @@ static int host_error_hdlr(struct npu_device *npu_dev, bool force)
		return 0;
	}

	if (host_ctx->dev_shuttingdown) {
		NPU_INFO("device is shutting down, igonre error handler\n");
		mutex_unlock(&host_ctx->lock);
		return -EIO;
	}

	if (host_ctx->wdg_irq_sts) {
		NPU_INFO("watchdog irq triggered\n");
		fw_alive = false;
@@ -1070,41 +1157,8 @@ static int host_error_hdlr(struct npu_device *npu_dev, bool force)
	}

	complete(&host_ctx->fw_deinit_done);
	complete_pending_commands(host_ctx);

	/* flush all pending npu cmds */
	for (i = 0; i < MAX_LOADED_NETWORK; i++) {
		network = &host_ctx->networks[i];
		if (!network->is_valid || !network->fw_error)
			continue;

		if (network->is_async) {
			NPU_DBG("async cmd, queue ssr event\n");
			kevt.evt.type = MSM_NPU_EVENT_TYPE_SSR;
			kevt.evt.u.ssr.network_hdl =
				network->network_hdl;
			if (npu_queue_event(network->client, &kevt))
				NPU_ERR("queue npu event failed\n");

			while (!list_empty(&network->cmd_list)) {
				cmd = list_first_entry(&network->cmd_list,
					struct npu_network_cmd, list);
				npu_dequeue_network_cmd(network, cmd);
				npu_free_network_cmd(host_ctx, cmd);
			}
		} else {
			list_for_each_entry(cmd, &network->cmd_list, list) {
				NPU_DBG("complete network %llx trans_id %d\n",
					network->id, cmd->trans_id);
				complete(&cmd->cmd_done);
			}
		}
	}

	list_for_each_entry(misc_cmd, &host_ctx->misc_cmd_list, list) {
		NPU_DBG("complete misc cmd trans_id %d\n",
			misc_cmd->trans_id);
		complete(&misc_cmd->cmd_done);
	}
	mutex_unlock(&host_ctx->lock);

	return ret;
@@ -2086,6 +2140,7 @@ static int npu_send_network_cmd(struct npu_device *npu_dev,
	WARN_ON(!mutex_is_locked(&host_ctx->lock));

	if (network->fw_error || host_ctx->fw_error ||
		host_ctx->dev_shuttingdown ||
		(host_ctx->fw_state != FW_ENABLED)) {
		NPU_ERR("fw is in error state or disabled\n");
		ret = -EIO;
@@ -2111,7 +2166,8 @@ static int npu_send_misc_cmd(struct npu_device *npu_dev, uint32_t q_idx,

	WARN_ON(!mutex_is_locked(&host_ctx->lock));

	if (host_ctx->fw_error || (host_ctx->fw_state != FW_ENABLED)) {
	if (host_ctx->fw_error || host_ctx->dev_shuttingdown ||
		(host_ctx->fw_state != FW_ENABLED)) {
		NPU_ERR("fw is in error state or disabled\n");
		ret = -EIO;
	} else {
@@ -2548,6 +2604,12 @@ int32_t npu_host_load_network_v2(struct npu_client *client,
		goto free_load_cmd;
	}

	if (host_ctx->dev_shuttingdown) {
		ret = -EIO;
		NPU_ERR("device is shutting down\n");
		goto free_load_cmd;
	}

	if (!ret) {
		NPU_ERR("npu: NPU_IPC_CMD_LOAD time out %lld:%d\n",
			network->id, load_cmd->trans_id);
@@ -2633,6 +2695,11 @@ int32_t npu_host_unload_network(struct npu_client *client,
		goto free_network;
	}

	if (host_ctx->dev_shuttingdown) {
		NPU_ERR("device is shutting down, skip unload network in fw\n");
		goto free_network;
	}

	NPU_DBG("Unload network %lld\n", network->id);
	/* prepare IPC packet for UNLOAD */
	unload_packet.header.cmd_type = NPU_IPC_CMD_UNLOAD;
@@ -2686,7 +2753,7 @@ int32_t npu_host_unload_network(struct npu_client *client,

	mutex_lock(&host_ctx->lock);

	if (network->fw_error) {
	if (network->fw_error || host_ctx->dev_shuttingdown) {
		ret = -EIO;
		NPU_ERR("fw is in error state during unload network\n");
		goto free_network;
@@ -2779,6 +2846,12 @@ int32_t npu_host_exec_network_v2(struct npu_client *client,
		goto exec_v2_done;
	}

	if (host_ctx->dev_shuttingdown) {
		NPU_ERR("device is shutting down\n");
		ret = -EIO;
		goto exec_v2_done;
	}

	if (network->is_async && !async_ioctl) {
		NPU_ERR("network is in async mode\n");
		ret = -EINVAL;
@@ -2869,6 +2942,12 @@ int32_t npu_host_exec_network_v2(struct npu_client *client,
		goto free_exec_cmd;
	}

	if (host_ctx->dev_shuttingdown) {
		ret = -EIO;
		NPU_ERR("device is shutting down during execute_v2 network\n");
		goto free_exec_cmd;
	}

	if (!ret) {
		NPU_ERR("npu: %llx:%d NPU_IPC_CMD_EXECUTE_V2 time out\n",
			network->id, exec_cmd->trans_id);
+3 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 */

#ifndef _NPU_MGR_H
@@ -131,10 +131,12 @@ struct npu_host_ctx {
	uint32_t err_irq_sts;
	uint32_t wdg_irq_sts;
	bool fw_error;
	bool dev_shuttingdown;
	bool cancel_work;
	bool app_crashed;
	struct notifier_block nb;
	struct notifier_block panic_nb;
	struct notifier_block reboot_nb;
	void *notif_hdle;
	spinlock_t bridge_mbox_lock;
	bool bridge_mbox_pwr_on;