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

Commit 25f5cfd9 authored by George Shen's avatar George Shen
Browse files

msm: cvp: cvp power management enhancement



Knowledge of break-down of CVP core sub-blocks cycle usage enables
driver to tune CVP clock and ddr vote in finer granularity. The change
is backward compatible with legacy power voting mechanism. The
enhancement only takes place when user mode provides extra knowledge
needed.

Change-Id: I596e2ad0e585723364e26db3547db41b1af45997
Signed-off-by: default avatarGeorge Shen <sqiao@codeaurora.org>
parent 7930610c
Loading
Loading
Loading
Loading
+194 −12
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@

struct cvp_power_level {
	unsigned long core_sum;
	unsigned long op_core_sum;
	unsigned long bw_sum;
};

@@ -674,7 +675,8 @@ static int msm_cvp_session_receive_hfi(struct msm_cvp_inst *inst,
			__func__, inst->session_queue.state,
			inst->session_queue.msg_count);

		if (inst->state >= MSM_CVP_CLOSE_DONE) {
		if (inst->state >= MSM_CVP_CLOSE_DONE ||
				sq->state != QUEUE_ACTIVE) {
			rc = -ECONNRESET;
			goto exit;
		}
@@ -1433,6 +1435,89 @@ static inline int max_3(unsigned int a, unsigned int b, unsigned int c)
	return (a >= b) ? ((a >= c) ? a : c) : ((b >= c) ? b : c);
}

static bool is_subblock_profile_existed(struct msm_cvp_inst *inst)
{
	return (inst->prop.od_cycles ||
			inst->prop.mpu_cycles ||
			inst->prop.fdu_cycles);
}

static void aggregate_power_update(struct msm_cvp_core *core,
	struct cvp_power_level *nrt_pwr,
	struct cvp_power_level *rt_pwr,
	unsigned int max_clk_rate)
{
	struct msm_cvp_inst *inst;
	int i;
	unsigned long fdu_sum[2] = {0}, od_sum[2] = {0}, mpu_sum[2] = {0};
	unsigned long ica_sum[2] = {0}, fw_sum[2] = {0};
	unsigned long op_fdu_max[2] = {0}, op_od_max[2] = {0};
	unsigned long op_mpu_max[2] = {0}, op_ica_max[2] = {0};
	unsigned long op_fw_max[2] = {0}, bw_sum[2] = {0}, op_bw_max[2] = {0};

	list_for_each_entry(inst, &core->instances, list) {
		if (inst->state == MSM_CVP_CORE_INVALID ||
			inst->state == MSM_CVP_CORE_UNINIT ||
			!is_subblock_profile_existed(inst))
			continue;
		if (inst->prop.priority <= CVP_RT_PRIO_THRESHOLD) {
			/* Non-realtime session use index 0 */
			i = 0;
		} else {
			i = 1;
		}
		fdu_sum[i] += inst->prop.fdu_cycles;
		od_sum[i] += inst->prop.od_cycles;
		mpu_sum[i] += inst->prop.mpu_cycles;
		ica_sum[i] += inst->prop.ica_cycles;
		fw_sum[i] += inst->prop.fw_cycles;
		op_fdu_max[i] =
			(op_fdu_max[i] >= inst->prop.fdu_op_cycles) ?
			op_fdu_max[i] : inst->prop.fdu_op_cycles;
		op_od_max[i] =
			(op_od_max[i] >= inst->prop.od_op_cycles) ?
			op_od_max[i] : inst->prop.od_op_cycles;
		op_mpu_max[i] =
			(op_mpu_max[i] >= inst->prop.mpu_op_cycles) ?
			op_mpu_max[i] : inst->prop.mpu_op_cycles;
		op_ica_max[i] =
			(op_ica_max[i] >= inst->prop.ica_op_cycles) ?
			op_ica_max[i] : inst->prop.ica_op_cycles;
		op_fw_max[i] =
			(op_fw_max[i] >= inst->prop.fw_op_cycles) ?
			op_fw_max[i] : inst->prop.fw_op_cycles;
		bw_sum[i] += inst->prop.ddr_bw;
		op_bw_max[i] =
			(op_bw_max[i] >= inst->prop.ddr_op_bw) ?
			op_bw_max[i] : inst->prop.ddr_op_bw;
	}

	for (i = 0; i < 2; i++) {
		fdu_sum[i] = max_3(fdu_sum[i], od_sum[i], mpu_sum[i]);
		fdu_sum[i] = max_3(fdu_sum[i], ica_sum[i], fw_sum[i]);

		op_fdu_max[i] = max_3(op_fdu_max[i], op_od_max[i],
			op_mpu_max[i]);
		op_fdu_max[i] = max_3(op_fdu_max[i],
			op_ica_max[i], op_fw_max[i]);
		op_fdu_max[i] =
			(op_fdu_max[i] > max_clk_rate) ?
			max_clk_rate : op_fdu_max[i];
		bw_sum[i] = (bw_sum[i] >= op_bw_max[i]) ?
			bw_sum[i] : op_bw_max[i];
	}

	nrt_pwr->core_sum += fdu_sum[0];
	nrt_pwr->op_core_sum = (nrt_pwr->op_core_sum >= op_fdu_max[0]) ?
			nrt_pwr->op_core_sum : op_fdu_max[0];
	nrt_pwr->bw_sum += bw_sum[0];
	rt_pwr->core_sum += fdu_sum[1];
	rt_pwr->op_core_sum = (rt_pwr->op_core_sum >= op_fdu_max[1]) ?
			rt_pwr->op_core_sum : op_fdu_max[1];
	rt_pwr->bw_sum += bw_sum[1];
}


static void aggregate_power_request(struct msm_cvp_core *core,
	struct cvp_power_level *nrt_pwr,
	struct cvp_power_level *rt_pwr,
@@ -1446,7 +1531,8 @@ static void aggregate_power_request(struct msm_cvp_core *core,

	list_for_each_entry(inst, &core->instances, list) {
		if (inst->state == MSM_CVP_CORE_INVALID ||
			inst->state == MSM_CVP_CORE_UNINIT)
			inst->state == MSM_CVP_CORE_UNINIT ||
			is_subblock_profile_existed(inst))
			continue;
		if (inst->prop.priority <= CVP_RT_PRIO_THRESHOLD) {
			/* Non-realtime session use index 0 */
@@ -1479,17 +1565,18 @@ static void aggregate_power_request(struct msm_cvp_core *core,
		op_core_max[i] =
			(op_core_max[i] > max_clk_rate) ?
			max_clk_rate : op_core_max[i];
		core_sum[i] =
			(core_sum[i] >= op_core_max[i]) ?
			core_sum[i] : op_core_max[i];
		bw_sum[i] = (bw_sum[i] >= op_bw_max[i]) ?
			bw_sum[i] : op_bw_max[i];
	}

	nrt_pwr->core_sum = core_sum[0];
	nrt_pwr->bw_sum = bw_sum[0];
	rt_pwr->core_sum = core_sum[1];
	rt_pwr->bw_sum = bw_sum[1];
	nrt_pwr->core_sum += core_sum[0];
	nrt_pwr->op_core_sum = (nrt_pwr->op_core_sum >= op_core_max[0]) ?
			nrt_pwr->op_core_sum : op_core_max[0];
	nrt_pwr->bw_sum += bw_sum[0];
	rt_pwr->core_sum += core_sum[1];
	rt_pwr->op_core_sum = (rt_pwr->op_core_sum >= op_core_max[1]) ?
			rt_pwr->op_core_sum : op_core_max[1];
	rt_pwr->bw_sum += bw_sum[1];
}

/**
@@ -1513,8 +1600,8 @@ static int adjust_bw_freqs(void)
	struct allowed_clock_rates_table *tbl = NULL;
	unsigned int tbl_size;
	unsigned int cvp_min_rate, cvp_max_rate, max_bw;
	struct cvp_power_level rt_pwr, nrt_pwr;
	unsigned long tmp, core_sum, bw_sum;
	struct cvp_power_level rt_pwr = {0}, nrt_pwr = {0};
	unsigned long tmp, core_sum, op_core_sum, bw_sum;
	int i, rc = 0;

	core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list);
@@ -1530,6 +1617,13 @@ static int adjust_bw_freqs(void)
	max_bw = bus->range[1];

	aggregate_power_request(core, &nrt_pwr, &rt_pwr, cvp_max_rate);
	dprintk(CVP_DBG, "PwrReq nrt %u %u rt %u %u\n",
		nrt_pwr.core_sum, nrt_pwr.op_core_sum,
		rt_pwr.core_sum, rt_pwr.op_core_sum);
	aggregate_power_update(core, &nrt_pwr, &rt_pwr, cvp_max_rate);
	dprintk(CVP_DBG, "PwrUpdate nrt %u %u rt %u %u\n",
		nrt_pwr.core_sum, nrt_pwr.op_core_sum,
		rt_pwr.core_sum, rt_pwr.op_core_sum);

	if (rt_pwr.core_sum > cvp_max_rate) {
		dprintk(CVP_WARN, "%s clk vote out of range %lld\n",
@@ -1538,6 +1632,11 @@ static int adjust_bw_freqs(void)
	}

	core_sum = rt_pwr.core_sum + nrt_pwr.core_sum;
	op_core_sum = (rt_pwr.op_core_sum >= nrt_pwr.op_core_sum) ?
		rt_pwr.op_core_sum : nrt_pwr.op_core_sum;

	core_sum = (core_sum >= op_core_sum) ?
		core_sum : op_core_sum;

	if (core_sum > cvp_max_rate) {
		core_sum = cvp_max_rate;
@@ -1622,7 +1721,6 @@ static int msm_cvp_request_power(struct msm_cvp_inst *inst,
	inst->power.reserved[0] = div_by_1dot5(inst->power.reserved[0]);
	inst->power.reserved[2] = div_by_1dot5(inst->power.reserved[2]);
	inst->power.reserved[3] = div_by_1dot5(inst->power.reserved[3]);
	inst->power.reserved[4] = div_by_1dot5(inst->power.reserved[4]);

	/* Convert bps to KBps */
	inst->power.ddr_bw = inst->power.ddr_bw >> 10;
@@ -1640,6 +1738,33 @@ static int msm_cvp_request_power(struct msm_cvp_inst *inst,
	return rc;
}

static int msm_cvp_update_power(struct msm_cvp_inst *inst)

{	int rc = 0;
	struct msm_cvp_core *core;
	struct msm_cvp_inst *s;

	if (!inst) {
		dprintk(CVP_ERR, "%s: invalid params\n", __func__);
		return -EINVAL;
	}

	s = cvp_get_inst_validate(inst->core, inst);
	if (!s)
		return -ECONNRESET;

	inst->cur_cmd_type = CVP_KMD_UPDATE_POWER;
	core = inst->core;

	mutex_lock(&core->lock);
	rc = adjust_bw_freqs();
	mutex_unlock(&core->lock);
	inst->cur_cmd_type = 0;
	cvp_put_inst(s);

	return rc;
}

static int msm_cvp_register_buffer(struct msm_cvp_inst *inst,
		struct cvp_kmd_buffer *buf)
{
@@ -1874,6 +1999,12 @@ static int msm_cvp_set_sysprop(struct msm_cvp_inst *inst,
		return -EINVAL;
	}

	if (props->prop_num >= MAX_KMD_PROP_NUM) {
		dprintk(CVP_ERR, "Too many properties %d to set\n",
			props->prop_num);
		return -E2BIG;
	}

	prop_array = &arg->data.sys_properties.prop_data;
	session_prop = &inst->prop;

@@ -1894,6 +2025,52 @@ static int msm_cvp_set_sysprop(struct msm_cvp_inst *inst,
		case CVP_KMD_PROP_SESSION_DSPMASK:
			session_prop->dsp_mask = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_FDU:
			session_prop->fdu_cycles = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_ICA:
			session_prop->ica_cycles =
				div_by_1dot5(prop_array[i].data);
			break;
		case CVP_KMD_PROP_PWR_OD:
			session_prop->od_cycles = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_MPU:
			session_prop->mpu_cycles = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_FW:
			session_prop->fw_cycles =
				div_by_1dot5(prop_array[i].data);
			break;
		case CVP_KMD_PROP_PWR_DDR:
			session_prop->ddr_bw = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_SYSCACHE:
			session_prop->ddr_cache = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_FDU_OP:
			session_prop->fdu_op_cycles = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_ICA_OP:
			session_prop->ica_op_cycles =
				div_by_1dot5(prop_array[i].data);
			break;
		case CVP_KMD_PROP_PWR_OD_OP:
			session_prop->od_op_cycles = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_MPU_OP:
			session_prop->mpu_op_cycles = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_FW_OP:
			session_prop->fw_op_cycles =
				div_by_1dot5(prop_array[i].data);
			break;
		case CVP_KMD_PROP_PWR_DDR_OP:
			session_prop->ddr_op_bw = prop_array[i].data;
			break;
		case CVP_KMD_PROP_PWR_SYSCACHE_OP:
			session_prop->ddr_op_cache = prop_array[i].data;
			break;
		default:
			dprintk(CVP_ERR,
				"unrecognized sys property to set %d\n",
@@ -1944,6 +2121,11 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg)
		rc = msm_cvp_request_power(inst, power);
		break;
	}
	case CVP_KMD_UPDATE_POWER:
	{
		rc = msm_cvp_update_power(inst);
		break;
	}
	case CVP_KMD_REGISTER_BUFFER:
	{
		struct cvp_kmd_buffer *buf =
+14 −0
Original line number Diff line number Diff line
@@ -259,6 +259,20 @@ struct cvp_session_prop {
	u32 priority;
	u32 is_secure;
	u32 dsp_mask;
	u32 fdu_cycles;
	u32 od_cycles;
	u32 mpu_cycles;
	u32 ica_cycles;
	u32 fw_cycles;
	u32 fdu_op_cycles;
	u32 od_op_cycles;
	u32 mpu_op_cycles;
	u32 ica_op_cycles;
	u32 fw_op_cycles;
	u32 ddr_bw;
	u32 ddr_op_bw;
	u32 ddr_cache;
	u32 ddr_op_cache;
};

enum cvp_event_t {
+4 −0
Original line number Diff line number Diff line
@@ -423,6 +423,8 @@ static int convert_from_user(struct cvp_kmd_arg *kp,
		}
		break;
	}
	case CVP_KMD_UPDATE_POWER:
		break;
	default:
		dprintk(CVP_ERR, "%s: unknown cmd type 0x%x\n",
			__func__, kp->type);
@@ -594,6 +596,8 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg)
	}
	case CVP_KMD_SET_SYS_PROPERTY:
		break;
	case CVP_KMD_UPDATE_POWER:
		break;
	default:
		dprintk(CVP_ERR, "%s: unknown cmd type 0x%x\n",
			__func__, kp->type);
+20 −0
Original line number Diff line number Diff line
@@ -75,6 +75,8 @@

#define CVP_KMD_HFI_FD_FRAME_CMD  (CVP_KMD_CMD_START + 16)

#define CVP_KMD_UPDATE_POWER	(CVP_KMD_CMD_START + 17)

#define CVP_KMD_SEND_CMD_PKT	(CVP_KMD_CMD_START + 64)

#define CVP_KMD_RECEIVE_MSG_PKT	 (CVP_KMD_CMD_START + 65)
@@ -225,6 +227,24 @@ struct cvp_kmd_hfi_packet {
#define CVP_KMD_PROP_SESSION_PRIORITY	4
#define CVP_KMD_PROP_SESSION_SECURITY	5
#define CVP_KMD_PROP_SESSION_DSPMASK	6

#define CVP_KMD_PROP_PWR_FDU	0x10
#define CVP_KMD_PROP_PWR_ICA	0x11
#define CVP_KMD_PROP_PWR_OD	0x12
#define CVP_KMD_PROP_PWR_MPU	0x13
#define CVP_KMD_PROP_PWR_FW	0x14
#define CVP_KMD_PROP_PWR_DDR	0x15
#define CVP_KMD_PROP_PWR_SYSCACHE	0x16
#define CVP_KMD_PROP_PWR_FDU_OP	0x17
#define CVP_KMD_PROP_PWR_ICA_OP	0x18
#define CVP_KMD_PROP_PWR_OD_OP	0x19
#define CVP_KMD_PROP_PWR_MPU_OP	0x1A
#define CVP_KMD_PROP_PWR_FW_OP	0x1B
#define CVP_KMD_PROP_PWR_DDR_OP	0x1C
#define CVP_KMD_PROP_PWR_SYSCACHE_OP	0x1D

#define MAX_KMD_PROP_NUM	(CVP_KMD_PROP_PWR_SYSCACHE_OP + 1)

struct cvp_kmd_sys_property {
	unsigned int prop_type;
	unsigned int data;