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

Commit 947169fc authored by Jilai Wang's avatar Jilai Wang
Browse files

msm: npu: Update npu power level control



Set npu to the power level based on use case information.

Change-Id: Ie7e13431e45357a5ca2bf2a358b6b4b43f94fb43
Signed-off-by: default avatarJilai Wang <jilaiw@codeaurora.org>
parent 1ef83a2e
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -159,6 +159,19 @@ struct npu_pwrctrl {

	struct device *devbw;
	uint32_t bwmon_enabled;
	uint32_t uc_pwrlevel;
};

/**
 * struct npu_thermalctrl - Thermal control settings for a NPU device
 * @max_state - maximum thermal mitigation state
 * @current_state - current thermal mitigation state
 * @pwr_level -power level that thermal control requested
 */
struct npu_thermalctrl {
	unsigned long max_state;
	unsigned long current_state;
	uint32_t pwr_level;
};

struct npu_device {
@@ -195,6 +208,7 @@ struct npu_device {

	struct thermal_cooling_device *tcdev;
	struct npu_pwrctrl pwrctrl;
	struct npu_thermalctrl thermalctrl;

	struct llcc_slice_desc *sys_cache;
};
@@ -213,7 +227,8 @@ int npu_enable_post_pil_clocks(struct npu_device *npu_dev);

irqreturn_t npu_intr_hdler(int irq, void *ptr);

int npu_set_power_level(struct npu_device *npu_dev, uint32_t pwr_level);
int npu_set_uc_power_level(struct npu_device *npu_dev,
	uint32_t pwr_level);

int fw_init(struct npu_device *npu_dev);
void fw_deinit(struct npu_device *npu_dev);
+86 −42
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@
#define DDR_MAPPED_START_ADDR   0x80000000
#define DDR_MAPPED_SIZE         0x60000000

#define PERF_MODE_DEFAULT 0

#define POWER_LEVEL_MIN_SVS 0
#define POWER_LEVEL_LOW_SVS 1
#define POWER_LEVEL_NOMINAL 4
@@ -49,8 +51,7 @@ static int npu_enable_regulators(struct npu_device *npu_dev);
static void npu_disable_regulators(struct npu_device *npu_dev);
static int npu_enable_core_clocks(struct npu_device *npu_dev, bool post_pil);
static void npu_disable_core_clocks(struct npu_device *npu_dev);
static int npu_calc_power_level(struct npu_device *npu_dev,
	uint32_t perf_mode);
static uint32_t npu_calc_power_level(struct npu_device *npu_dev);
static ssize_t npu_show_capabilities(struct device *dev,
		struct device_attribute *attr, char *buf);
static ssize_t npu_show_pwr_state(struct device *dev,
@@ -292,6 +293,11 @@ void npu_disable_core_power(struct npu_device *npu_dev)
		npu_disable_core_clocks(npu_dev);
		npu_disable_regulators(npu_dev);
	}
	/* init the power levels back to default */
	pwr->active_pwrlevel = pwr->default_pwrlevel;
	pwr->uc_pwrlevel = pwr->default_pwrlevel;
	pr_debug("setting back to default power level=%d\n",
		pwr->default_pwrlevel);
}

int npu_enable_post_pil_clocks(struct npu_device *npu_dev)
@@ -299,26 +305,58 @@ int npu_enable_post_pil_clocks(struct npu_device *npu_dev)
	return npu_enable_core_clocks(npu_dev, true);
}

int npu_set_power_level(struct npu_device *npu_dev,
	uint32_t pwr_level)

static uint32_t npu_calc_power_level(struct npu_device *npu_dev)
{
	uint32_t ret_level;
	uint32_t therm_pwr_level = npu_dev->thermalctrl.pwr_level;
	uint32_t active_pwr_level = npu_dev->pwrctrl.active_pwrlevel;
	uint32_t uc_pwr_level = npu_dev->pwrctrl.uc_pwrlevel;

	/* if thermal power is higher than usecase power
	 * leave level at use case.  Otherwise go down to
	 * thermal power level
	 */
	if (therm_pwr_level > uc_pwr_level)
		ret_level = uc_pwr_level;
	else
		ret_level = therm_pwr_level;

	/* adjust the power level */
	/* force to lowsvs, minsvs not supported */
	if (ret_level == POWER_LEVEL_MIN_SVS)
		ret_level = POWER_LEVEL_LOW_SVS;

	pr_debug("%s therm=%d active=%d uc=%d set level=%d\n", __func__,
		therm_pwr_level, active_pwr_level, uc_pwr_level, ret_level);

	return ret_level;
}

static int npu_set_power_level(struct npu_device *npu_dev)
{
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
	struct npu_pwrlevel *pwrlevel;
	int i, ret = 0;
	long clk_rate = 0;
	uint32_t pwr_level_to_set;

	if (!pwr->pwr_vote_num) {
		pr_err("power is not enabled during set request\n");
		return -EINVAL;
	}

	if (pwr_level == pwr->active_pwrlevel)
	/* get power level to set */
	pwr_level_to_set = npu_calc_power_level(npu_dev);

	/* if the same as current, dont do anything */
	if (pwr_level_to_set == pwr->active_pwrlevel)
		return 0;

	pr_debug("%s to [%d]\n", __func__, pwr_level);
	pr_debug("setting power level to [%d]\n", pwr_level_to_set);

	pwr->active_pwrlevel = pwr_level;
	pwrlevel = &npu_dev->pwrctrl.pwrlevels[pwr_level];
	pwr->active_pwrlevel = pwr_level_to_set;
	pwrlevel = &npu_dev->pwrctrl.pwrlevels[pwr->active_pwrlevel];

	for (i = 0; i < npu_dev->core_clk_num; i++) {
		if (npu_is_exclude_rate_clock(
@@ -338,6 +376,7 @@ int npu_set_power_level(struct npu_device *npu_dev,
			pwrlevel->clk_freq[i]);

		pr_debug("actual round clk rate [%ld]\n", clk_rate);

		ret = clk_set_rate(npu_dev->core_clks[i].clk, clk_rate);
		if (ret) {
			pr_err("clk_set_rate %s to %ld failed with %d\n",
@@ -350,20 +389,17 @@ int npu_set_power_level(struct npu_device *npu_dev,
	return ret;
}

static int npu_calc_power_level(struct npu_device *npu_dev,
int npu_set_uc_power_level(struct npu_device *npu_dev,
	uint32_t perf_mode)
{
	int ret_level;
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;

	if (perf_mode == 0)
		ret_level = POWER_LEVEL_NOMINAL;
	else if (perf_mode == POWER_LEVEL_MIN_SVS)
		/* force to lowsvs, minsvs not supported */
		ret_level = POWER_LEVEL_LOW_SVS;
	if (perf_mode == PERF_MODE_DEFAULT)
		pwr->uc_pwrlevel = POWER_LEVEL_NOMINAL;
	else
		ret_level = perf_mode-1;
		pwr->uc_pwrlevel = perf_mode - 1;

	return ret_level;
	return npu_set_power_level(npu_dev);
}

/* -------------------------------------------------------------------------
@@ -513,11 +549,12 @@ static int npu_get_max_state(struct thermal_cooling_device *cdev,
				 unsigned long *state)
{
	struct npu_device *npu_dev = cdev->devdata;
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
	struct npu_thermalctrl *thermalctrl = &npu_dev->thermalctrl;

	pr_debug("enter %s\n", __func__);
	pr_debug("enter %s thermal max state=%lu\n", __func__,
		thermalctrl->max_state);

	*state = pwr->max_pwrlevel;
	*state = thermalctrl->max_state;

	return 0;
}
@@ -526,11 +563,12 @@ static int npu_get_cur_state(struct thermal_cooling_device *cdev,
				 unsigned long *state)
{
	struct npu_device *npu_dev = cdev->devdata;
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
	struct npu_thermalctrl *thermal = &npu_dev->thermalctrl;

	pr_debug("enter %s\n", __func__);
	pr_debug("enter %s thermal current state=%lu\n", __func__,
		thermal->current_state);

	*state = pwr->max_pwrlevel - pwr->active_pwrlevel;
	*state = thermal->current_state;

	return 0;
}
@@ -539,17 +577,17 @@ static int
npu_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
	struct npu_device *npu_dev = cdev->devdata;
	struct npu_thermalctrl *thermal = &npu_dev->thermalctrl;
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
	uint32_t next_pwr_level;

	pr_debug("enter %s %lu\n", __func__, state);

	if (state > pwr->max_pwrlevel)
	pr_debug("enter %s request state=%lu\n", __func__, state);
	if (state > thermal->max_state)
		return -EINVAL;

	next_pwr_level = pwr->max_pwrlevel - state;
	thermal->current_state = state;
	thermal->pwr_level =  pwr->max_pwrlevel - state;

	return npu_set_power_level(npu_dev, next_pwr_level);
	return npu_set_power_level(npu_dev);
}

/* -------------------------------------------------------------------------
@@ -786,7 +824,6 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg)
	struct msm_npu_load_network_ioctl req;
	void __user *argp = (void __user *)arg;
	int ret = 0;
	uint32_t pwr_level_to_set;

	ret = copy_from_user(&req, argp, sizeof(req));

@@ -795,23 +832,14 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg)
		return -EFAULT;
	}

	pr_debug("network load with perf request %d\n", req.flags);
	pr_debug("network load with perf request %d\n", req.perf_mode);

	ret = npu_host_load_network(npu_dev, &req);
	if (ret) {
		pr_err("npu_host_load_network failed\n");
		return ret;
		pr_err("network load failed: %d\n", ret);
		return -EFAULT;
	}

	/* get the power level to set */
	pwr_level_to_set = npu_calc_power_level(npu_dev, req.flags);

	/* set the power level */
	ret = npu_set_power_level(npu_dev, pwr_level_to_set);
	if (!ret)
		pr_debug("network load pwr level set at %d\n",
			pwr_level_to_set);

	ret = copy_to_user(argp, &req, sizeof(req));
	if (ret) {
		pr_err("fail to copy to user\n");
@@ -1071,6 +1099,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev,
	pr_debug("init power level %d\n", init_level);
	pwr->active_pwrlevel = init_level;
	pwr->default_pwrlevel = init_level;
	pwr->uc_pwrlevel = init_level;
	pwr->min_pwrlevel = 0;
	pwr->max_pwrlevel = pwr->num_pwrlevels - 1;

@@ -1121,6 +1150,17 @@ static int npu_pwrctrl_init(struct npu_device *npu_dev)
	return ret;
}

static int npu_thermalctrl_init(struct npu_device *npu_dev)
{
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
	struct npu_thermalctrl *thermalctrl = &npu_dev->thermalctrl;
	int ret = 0;

	thermalctrl->max_state = pwr->max_pwrlevel;
	thermalctrl->current_state = 0;
	return ret;
}

/* -------------------------------------------------------------------------
 * Probe/Remove
 * -------------------------------------------------------------------------
@@ -1161,6 +1201,10 @@ static int npu_probe(struct platform_device *pdev)
	if (rc)
		goto error_get_dev_num;

	rc = npu_thermalctrl_init(npu_dev);
	if (rc)
		goto error_get_dev_num;

	npu_dev->npu_base = devm_ioremap(&pdev->dev, res->start,
					npu_dev->reg_size);
	if (unlikely(!npu_dev->npu_base)) {
+36 −1
Original line number Diff line number Diff line
@@ -454,6 +454,26 @@ void host_copy_patch_data(struct npu_patch_tuple *param, uint32_t value,
		layer_info->patch_info.variable_size_in_bits;
}

static uint32_t find_networks_perf_mode(struct npu_host_ctx *host_ctx)
{
	struct npu_network *network;
	uint32_t max_perf_mode = 0;
	int i = 0;

	network = host_ctx->networks;

	/* find the max level among all the networks */
	for (i = 0; i < host_ctx->network_num; i++) {
		if ((network->perf_mode != 0) &&
			(network->perf_mode > max_perf_mode))
			max_perf_mode = network->perf_mode;
		network++;
	}
	pr_debug("max perf mode for networks: %d\n", max_perf_mode);

	return max_perf_mode;
}

int32_t npu_host_load_network(struct npu_device *npu_dev,
			struct msm_npu_load_network_ioctl *load_ioctl)
{
@@ -461,6 +481,7 @@ int32_t npu_host_load_network(struct npu_device *npu_dev,
	struct npu_network *network;
	struct ipc_cmd_load_pkt load_packet;
	struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
	uint32_t networks_perf_mode = 0;

	ret = fw_init(npu_dev);
	if (ret)
@@ -474,8 +495,18 @@ int32_t npu_host_load_network(struct npu_device *npu_dev,
	network->size = load_ioctl->buf_size;
	network->phy_add = load_ioctl->buf_phys_addr;
	network->first_block_size = load_ioctl->first_block_size;
	network->priority = load_ioctl->priority;
	network->perf_mode = load_ioctl->perf_mode;
	load_ioctl->network_hdl = network->id;

	networks_perf_mode = find_networks_perf_mode(host_ctx);

	ret = npu_set_uc_power_level(npu_dev, networks_perf_mode);
	if (ret) {
		pr_err("network load failed due to power level set\n");
		goto error_free_network;
	}

	load_packet.header.cmd_type = NPU_IPC_CMD_LOAD;
	load_packet.header.size = sizeof(struct ipc_cmd_load_pkt);
	load_packet.header.trans_id = network->ipc_trans_id++;
@@ -499,11 +530,15 @@ int32_t npu_host_load_network(struct npu_device *npu_dev,
	if (!wait_for_completion_interruptible_timeout(
		&host_ctx->load_done, NW_LOAD_TIMEOUT)) {
		pr_err_ratelimited("npu: NPU_IPC_CMD_LOAD time out\n");
		npu_dump_cal_state(npu_dev);
		ret = -ETIMEDOUT;
		goto error_free_network;
	}

	return ret;

error_free_network:
	free_network(host_ctx, network->id);
	return ret;
}

int32_t npu_host_unload_network(struct npu_device *npu_dev,
+2 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ struct npu_network {
	uint32_t first_block_size;
	uint32_t network_hdl;
	uint32_t ipc_trans_id;
	uint32_t priority;
	uint32_t perf_mode;
};

struct npu_host_ctx {