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

Commit 2e6bc48a authored by Jilai Wang's avatar Jilai Wang
Browse files

msm: npu: Fix SSR race condition issue in DSP mode



Once SSR occurs in DSP mode, npu_unmap has to be done after fw
is turned off completely. Otherwise iommu violation fault may
happen if the buffer is still used by the npu cal hw.

Change-Id: I56b4d8eac8a0f6901c8616a72c59e1d47343aeb4
Signed-off-by: default avatarJilai Wang <jilaiw@codeaurora.org>
parent 67942dbf
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -380,8 +380,12 @@ static ssize_t npu_debug_ctrl_write(struct file *file,
		if (npu_enable_core_power(npu_dev))
			return -EPERM;

		REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_SET(1), 2);
		REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_SET(0), 2);
		npu_disable_core_power(npu_dev);
	} else if (strcmp(buf, "ssr_wdt") == 0) {
		pr_info("trigger wdt irq\n");
		npu_disable_post_pil_clocks(npu_dev);
	} else if (strcmp(buf, "loopback") == 0) {
		pr_debug("loopback test\n");
		rc = npu_host_loopback_test(npu_dev);
+2 −0
Original line number Diff line number Diff line
@@ -706,6 +706,8 @@ int npu_enable_irq(struct npu_device *npu_dev)
	REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0);
	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_CLEAR(0), NPU_ERROR_IRQ_MASK);
	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_ENABLE(0), NPU_ERROR_IRQ_MASK);
	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_OWNER(0), NPU_ERROR_IRQ_MASK);
	REGW(npu_dev, NPU_MASTERn_WDOG_IRQ_OWNER(0), NPU_WDOG_IRQ_MASK);

	for (i = 0; i < NPU_MAX_IRQ; i++) {
		if (npu_dev->irq[i].irq != 0) {
+4 −0
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@
#define HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_BIT   2
/* Host requests to pause fw during boot up */
#define HOST_CTRL_STATUS_FW_PAUSE                   3
/* Host requests to disable watchdog */
#define HOST_CTRL_STATUS_DISABLE_WDOG_BIT  4

/* 32 bit values of the bit fields above */
#define HOST_CTRL_STATUS_IPC_ADDRESS_READY_VAL \
@@ -88,6 +90,8 @@
		(1 << HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_BIT)
#define HOST_CTRL_STATUS_FW_PAUSE_VAL \
		(1 << HOST_CTRL_STATUS_FW_PAUSE)
#define HOST_CTRL_STATUS_DISABLE_WDOG_VAL \
		(1 << HOST_CTRL_STATUS_DISABLE_WDOG_BIT)


/* NPU HOST DSP Control/Status Register */
+3 −0
Original line number Diff line number Diff line
@@ -31,11 +31,14 @@
#define NPU_MASTERn_ERROR_IRQ_ENABLE(n) (0x00101018+0x1000*(n))
#define NPU_MASTERn_ERROR_IRQ_CLEAR(n) (0x0010101C+0x1000*(n))
#define NPU_MASTERn_ERROR_IRQ_SET(n) (0x00101020+0x1000*(n))
#define NPU_MASTERn_ERROR_IRQ_OWNER(n) (0x00107000+4*(n))
#define NPU_ERROR_IRQ_MASK 0x000000E3
#define NPU_MASTERn_WDOG_IRQ_STATUS(n) (0x00101030+0x1000*(n))
#define NPU_WDOG_BITE_IRQ_STATUS (1 << 1)
#define NPU_MASTERn_WDOG_IRQ_INCLUDE(n) (0x00101034+0x1000*(n))
#define NPU_WDOG_BITE_IRQ_INCLUDE (1 << 1)
#define NPU_MASTERn_WDOG_IRQ_OWNER(n) (0x00107010+4*(n))
#define NPU_WDOG_IRQ_MASK 0x00000002


#define NPU_GPR1 (0x00100104)
+37 −10
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up);
 */
int fw_init(struct npu_device *npu_dev)
{
	uint32_t reg_val = 0;
	uint32_t reg_val;
	struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
	int ret = 0;
	mutex_lock(&host_ctx->lock);
@@ -100,13 +100,16 @@ int fw_init(struct npu_device *npu_dev)
	REGW(npu_dev, REG_NPU_FW_CTRL_STATUS, 0x0);
	REGW(npu_dev, REG_NPU_HOST_CTRL_VALUE, 0x0);
	REGW(npu_dev, REG_FW_TO_HOST_EVENT, 0x0);
	if (host_ctx->fw_dbg_mode & FW_DBG_MODE_PAUSE) {

	pr_debug("fw_dbg_mode %x\n", host_ctx->fw_dbg_mode);
		REGW(npu_dev, REG_NPU_HOST_CTRL_STATUS,
			HOST_CTRL_STATUS_FW_PAUSE_VAL);
	} else {
		REGW(npu_dev, REG_NPU_HOST_CTRL_STATUS, 0x0);
	}
	reg_val = 0;
	if (host_ctx->fw_dbg_mode & FW_DBG_MODE_PAUSE)
		reg_val |= HOST_CTRL_STATUS_FW_PAUSE_VAL;

	if (host_ctx->fw_dbg_mode & FW_DBG_DISABLE_WDOG)
		reg_val |= HOST_CTRL_STATUS_DISABLE_WDOG_VAL;

	REGW(npu_dev, REG_NPU_HOST_CTRL_STATUS, reg_val);
	/* Read back to flush all registers for fw to read */
	REGR(npu_dev, REG_NPU_HOST_CTRL_STATUS);

@@ -150,6 +153,7 @@ int fw_init(struct npu_device *npu_dev)
	host_ctx->fw_state = FW_ENABLED;
	host_ctx->fw_error = false;
	host_ctx->fw_ref_cnt++;
	reinit_completion(&host_ctx->fw_deinit_done);
	mutex_unlock(&host_ctx->lock);
	pr_debug("firmware init complete\n");

@@ -230,12 +234,21 @@ void fw_deinit(struct npu_device *npu_dev, bool ssr)
		}
	}

	npu_notify_dsp(npu_dev, false);

	npu_disable_post_pil_clocks(npu_dev);
	npu_disable_sys_cache(npu_dev);
	subsystem_put_local(host_ctx->subsystem_handle);
	host_ctx->fw_state = FW_DISABLED;

	/*
	 * if it's not in ssr mode, notify dsp before power off
	 * otherwise delay 500 ms to make sure dsp has finished
	 * its own ssr handling.
	 */
	if (!ssr)
		npu_notify_dsp(npu_dev, false);
	else
		msleep(500);

	npu_disable_core_power(npu_dev);

	if (ssr) {
@@ -247,6 +260,7 @@ void fw_deinit(struct npu_device *npu_dev, bool ssr)
		}
	}

	complete(&host_ctx->fw_deinit_done);
	mutex_unlock(&host_ctx->lock);
	pr_debug("firmware deinit complete\n");
	return;
@@ -259,6 +273,7 @@ int npu_host_init(struct npu_device *npu_dev)

	memset(host_ctx, 0, sizeof(*host_ctx));
	init_completion(&host_ctx->loopback_done);
	init_completion(&host_ctx->fw_deinit_done);
	mutex_init(&host_ctx->lock);
	atomic_set(&host_ctx->ipc_trans_id, 1);

@@ -780,6 +795,18 @@ int32_t npu_host_map_buf(struct npu_client *client,
int32_t npu_host_unmap_buf(struct npu_client *client,
			struct msm_npu_unmap_buf_ioctl *unmap_ioctl)
{
	struct npu_device *npu_dev = client->npu_dev;
	struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;

	/*
	 * Once SSR occurs, all buffers only can be unmapped until
	 * fw is disabled
	 */
	if (host_ctx->fw_error && (host_ctx->fw_state == FW_ENABLED) &&
		!wait_for_completion_interruptible_timeout(
		&host_ctx->fw_deinit_done, NW_CMD_TIMEOUT))
		pr_warn("npu: wait for fw_deinit_done time out\n");

	npu_mem_unmap(client, unmap_ioctl->buf_ion_hdl,
		unmap_ioctl->npu_phys_addr);
	return 0;
Loading