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

Commit d151c07f authored by Jilai Wang's avatar Jilai Wang
Browse files

msm: npu: Support delayed unloading NPU fw



In order to reduce the latency caused by loading NPU fw during
switching networks, support delayed unloading fw after network
is unloaded.

Change-Id: Ibb92ed7f55829ac82158792d8630cd5a187de07f
Signed-off-by: default avatarJilai Wang <jilaiw@codeaurora.org>
parent 28ced727
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -68,6 +68,12 @@ static ssize_t npu_show_perf_mode_override(struct device *dev,
static ssize_t npu_store_perf_mode_override(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count);
static ssize_t npu_show_fw_unload_delay_ms(struct device *dev,
					 struct device_attribute *attr,
					 char *buf);
static ssize_t npu_store_fw_unload_delay_ms(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count);
static ssize_t npu_show_fw_state(struct device *dev,
					 struct device_attribute *attr,
					 char *buf);
@@ -172,6 +178,8 @@ static DEVICE_ATTR(caps, 0444, npu_show_capabilities, NULL);
static DEVICE_ATTR(pwr, 0644, npu_show_pwr_state, npu_store_pwr_state);
static DEVICE_ATTR(perf_mode_override, 0644,
	npu_show_perf_mode_override, npu_store_perf_mode_override);
static DEVICE_ATTR(fw_unload_delay_ms, 0644,
	npu_show_fw_unload_delay_ms, npu_store_fw_unload_delay_ms);
static DEVICE_ATTR(fw_state, 0644, npu_show_fw_state, npu_store_fw_state);

static struct attribute *npu_fs_attrs[] = {
@@ -179,6 +187,7 @@ static struct attribute *npu_fs_attrs[] = {
	&dev_attr_pwr.attr,
	&dev_attr_perf_mode_override.attr,
	&dev_attr_fw_state.attr,
	&dev_attr_fw_unload_delay_ms.attr,
	NULL
};

@@ -315,6 +324,40 @@ static ssize_t npu_store_perf_mode_override(struct device *dev,
	return count;
}

/* -------------------------------------------------------------------------
 * SysFS - Delayed FW unload
 * -------------------------------------------------------------------------
 */
static ssize_t npu_show_fw_unload_delay_ms(struct device *dev,
					 struct device_attribute *attr,
					 char *buf)
{
	struct npu_device *npu_dev = dev_get_drvdata(dev);

	return scnprintf(buf, PAGE_SIZE, "%d\n",
		npu_dev->host_ctx.fw_unload_delay_ms);
}

static ssize_t npu_store_fw_unload_delay_ms(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count)
{
	struct npu_device *npu_dev = dev_get_drvdata(dev);
	uint32_t val;
	int rc;

	rc = kstrtou32(buf, 10, &val);
	if (rc) {
		pr_err("Invalid input for fw unload delay setting\n");
		return -EINVAL;
	}

	npu_dev->host_ctx.fw_unload_delay_ms = val;
	pr_debug("setting fw_unload_delay_ms to %d\n", val);

	return count;
}

/* -------------------------------------------------------------------------
 * SysFS - firmware state
 * -------------------------------------------------------------------------
+1 −20
Original line number Diff line number Diff line
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -378,25 +378,6 @@ void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr)
	npu_free_npu_ion_buffer(client, buf_hdl);
}

/* -------------------------------------------------------------------------
 * Functions - Work Queue
 * -------------------------------------------------------------------------
 */
void npu_destroy_wq(struct workqueue_struct *wq)
{
	destroy_workqueue(wq);
}

struct workqueue_struct *npu_create_wq(struct npu_host_ctx *host_ctx,
	const char *name, wq_hdlr_fn hdlr, struct work_struct *irq_work)
{
	struct workqueue_struct *wq = create_workqueue(name);

	INIT_WORK(irq_work, hdlr);

	return wq;
}

/* -------------------------------------------------------------------------
 * Functions - Features
 * -------------------------------------------------------------------------
+1 −5
Original line number Diff line number Diff line
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -78,10 +78,6 @@ void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num);
int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev);
int32_t npu_interrupt_raise_dsp(struct npu_device *npu_dev);

struct workqueue_struct *npu_create_wq(struct npu_host_ctx *host_ctx,
	const char *name, wq_hdlr_fn hdlr, struct work_struct *irq_work);
void npu_destroy_wq(struct workqueue_struct *wq);

uint8_t npu_hw_clk_gating_enabled(void);
uint8_t npu_hw_log_enabled(void);

+48 −4
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
 * -------------------------------------------------------------------------
 */
static void host_irq_wq(struct work_struct *work);
static void fw_deinit_wq(struct work_struct *work);
static void turn_off_fw_logging(struct npu_device *npu_dev);
static int wait_for_status_ready(struct npu_device *npu_dev,
	uint32_t status_reg, uint32_t status_bits);
@@ -65,6 +66,9 @@ static int npu_send_misc_cmd(struct npu_device *npu_dev, uint32_t q_idx,
static int npu_queue_event(struct npu_client *client, struct npu_kevent *evt);
static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up);
static int npu_notify_aop(struct npu_device *npu_dev, bool on);
static void npu_destroy_wq(struct npu_host_ctx *host_ctx);
static struct workqueue_struct *npu_create_wq(struct npu_host_ctx *host_ctx,
	const char *name);

/* -------------------------------------------------------------------------
 * Function Definitions - Init / Deinit
@@ -298,8 +302,7 @@ int npu_host_init(struct npu_device *npu_dev)
	mutex_init(&host_ctx->lock);
	atomic_set(&host_ctx->ipc_trans_id, 1);

	host_ctx->wq = npu_create_wq(host_ctx, "irq_hdl", host_irq_wq,
		&host_ctx->irq_work);
	host_ctx->wq = npu_create_wq(host_ctx, "npu_wq");
	if (!host_ctx->wq)
		sts = -EPERM;

@@ -310,7 +313,7 @@ void npu_host_deinit(struct npu_device *npu_dev)
{
	struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;

	npu_destroy_wq(host_ctx->wq);
	npu_destroy_wq(host_ctx);
	mutex_destroy(&host_ctx->lock);
}

@@ -397,6 +400,40 @@ static void host_irq_wq(struct work_struct *work)
	host_session_msg_hdlr(npu_dev);
}

static void fw_deinit_wq(struct work_struct *work)
{
	struct npu_host_ctx *host_ctx;
	struct npu_device *npu_dev;

	pr_debug("%s: deinit fw\n", __func__);
	host_ctx = container_of(work, struct npu_host_ctx, fw_deinit_work.work);
	npu_dev = container_of(host_ctx, struct npu_device, host_ctx);

	if (atomic_read(&host_ctx->fw_deinit_work_cnt) == 0)
		return;

	do {
		fw_deinit(npu_dev, false, true);
	} while (!atomic_dec_and_test(&host_ctx->fw_deinit_work_cnt));
}

static void npu_destroy_wq(struct npu_host_ctx *host_ctx)
{
	flush_delayed_work(&host_ctx->fw_deinit_work);
	destroy_workqueue(host_ctx->wq);
}

static struct workqueue_struct *npu_create_wq(struct npu_host_ctx *host_ctx,
	const char *name)
{
	struct workqueue_struct *wq = create_workqueue(name);

	INIT_WORK(&host_ctx->irq_work, host_irq_wq);
	INIT_DELAYED_WORK(&host_ctx->fw_deinit_work, fw_deinit_wq);

	return wq;
}

static void turn_off_fw_logging(struct npu_device *npu_dev)
{
	struct ipc_cmd_log_state_pkt log_packet;
@@ -1433,7 +1470,14 @@ int32_t npu_host_unload_network(struct npu_client *client,
	if (ret)
		pr_err("network unload failed to set power level\n");
	mutex_unlock(&host_ctx->lock);
	if (host_ctx->fw_unload_delay_ms) {
		flush_delayed_work(&host_ctx->fw_deinit_work);
		atomic_inc(&host_ctx->fw_deinit_work_cnt);
		queue_delayed_work(host_ctx->wq, &host_ctx->fw_deinit_work,
			msecs_to_jiffies(host_ctx->fw_unload_delay_ms));
	} else {
		fw_deinit(npu_dev, false, true);
	}
	return ret;
}

+4 −1
Original line number Diff line number Diff line
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -78,6 +78,8 @@ struct npu_host_ctx {
	int32_t fw_ref_cnt;
	int32_t power_vote_num;
	struct work_struct irq_work;
	struct delayed_work fw_deinit_work;
	atomic_t fw_deinit_work_cnt;
	struct workqueue_struct *wq;
	struct completion loopback_done;
	struct completion fw_deinit_done;
@@ -86,6 +88,7 @@ struct npu_host_ctx {
	bool sys_cache_disable;
	uint32_t fw_dbg_mode;
	uint32_t exec_flags_override;
	uint32_t fw_unload_delay_ms;
	atomic_t ipc_trans_id;
	atomic_t network_exeute_cnt;