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

Commit 75cf18ef authored by Praneeth Paladugu's avatar Praneeth Paladugu Committed by Gerrit - the friendly Code Review server
Browse files

msm: vidc: Simplify DCVS algorithm



Unify Encoder and Decoder DCVS by removing complex buffer
tracking logic. DCVS is based on simple logic now.

    - More YUV buffers with Venus --> Venus is Late -->
          Increase Venus clock.
    - Less YUV buffers with Venus --> Venus is not late -->
          Decrease Venus clock.

CRs-Fixed: 2012520
Change-Id: I47870747dd73e20e1be1fd156ed8ae89ca4b824a
Signed-off-by: default avatarPraneeth Paladugu <ppaladug@codeaurora.org>
parent b71968b4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -883,6 +883,7 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
		property_id = HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
		hal_property.enable = ctrl->val;
		pdata = &hal_property;
		msm_dcvs_try_enable(inst);
		break;
	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
		inst->flags |= VIDC_SECURE;
+1 −2
Original line number Diff line number Diff line
@@ -1390,7 +1390,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
			"Failed to move inst: %pK to start done state\n", inst);
		goto fail_start;
	}
	msm_dcvs_init_load(inst);
	msm_dcvs_init(inst);
	if (msm_comm_get_stream_output_mode(inst) ==
			HAL_VIDEO_DECODER_SECONDARY) {
		rc = msm_comm_queue_output_buffers(inst);
@@ -1953,7 +1953,6 @@ void *msm_vidc_open(int core_id, int session_type)
	if (rc)
		goto fail_bufq_capture;

	msm_dcvs_init(inst);
	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
			session_type);
	if (rc) {
+126 −529
Original line number Diff line number Diff line
@@ -16,13 +16,6 @@
#include "msm_vidc_debug.h"
#include "msm_vidc_clocks.h"

#define IS_VALID_DCVS_SESSION(__cur_mbpf, __min_mbpf) \
		((__cur_mbpf) >= (__min_mbpf))

static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst);
static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst);
static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd);

int msm_comm_vote_bus(struct msm_vidc_core *core)
{
	int rc = 0, vote_data_count = 0, i = 0;
@@ -103,6 +96,82 @@ int msm_comm_vote_bus(struct msm_vidc_core *core)
	return rc;
}

static inline int get_pending_bufs_fw(struct msm_vidc_inst *inst)
{
	int fw_out_qsize = 0, buffers_in_driver = 0;

	/*
	 * DCVS always operates on Uncompressed buffers.
	 * For Decoders, FTB and Encoders, ETB.
	 */

	if (inst->state >= MSM_VIDC_OPEN_DONE &&
			inst->state < MSM_VIDC_STOP_DONE) {
		if (inst->session_type == MSM_VIDC_DECODER)
			fw_out_qsize = inst->count.ftb - inst->count.fbd;
		else
			fw_out_qsize = inst->count.etb - inst->count.ebd;

		buffers_in_driver = inst->buffers_held_in_driver;
	}

	return fw_out_qsize + buffers_in_driver;
}

static int msm_dcvs_scale_clocks(struct msm_vidc_inst *inst)
{
	int rc = 0;
	int fw_pending_bufs = 0;
	int total_output_buf = 0;
	int buffers_outside_fw = 0;
	struct msm_vidc_core *core;
	struct hal_buffer_requirements *output_buf_req;
	struct dcvs_stats *dcvs;

	if (!inst || !inst->core || !inst->core->device) {
		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
		return -EINVAL;
	}
	if (!inst->dcvs_mode) {
		dprintk(VIDC_DBG, "DCVS is not enabled\n");
		return 0;
	}

	dcvs = &inst->dcvs;

	core = inst->core;
	mutex_lock(&inst->lock);
	fw_pending_bufs = get_pending_bufs_fw(inst);

	output_buf_req = get_buff_req_buffer(inst,
			dcvs->buffer_type);
	mutex_unlock(&inst->lock);
	if (!output_buf_req) {
		dprintk(VIDC_ERR,
				"%s: No buffer requirement for buffer type %x\n",
				__func__, dcvs->buffer_type);
		return -EINVAL;
	}

	/* Total number of output buffers */
	total_output_buf = output_buf_req->buffer_count_actual;

	/* Buffers outside FW are with display */
	buffers_outside_fw = total_output_buf - fw_pending_bufs;
	dprintk(VIDC_DBG,
		"Counts : total_output_buf = %d fw_pending_bufs = %d buffers_outside_fw = %d\n",
		total_output_buf, fw_pending_bufs, buffers_outside_fw);

	if (buffers_outside_fw >=  dcvs->min_threshold &&
			dcvs->load > dcvs->load_low) {
		dcvs->load = dcvs->load_low;
	} else if (buffers_outside_fw < dcvs->min_threshold &&
			dcvs->load == dcvs->load_low) {
		dcvs->load = dcvs->load_high;
	}
	return rc;
}

static void msm_vidc_update_freq_entry(struct msm_vidc_inst *inst,
	unsigned long freq, ion_phys_addr_t device_addr)
{
@@ -140,10 +209,12 @@ void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
			temp->freq = 0;
	}
	mutex_unlock(&inst->freqs.lock);

	inst->dcvs.buffer_counter++;
}


static unsigned long msm_vidc_get_highest_freq(struct msm_vidc_inst *inst)
static unsigned long msm_vidc_adjust_freq(struct msm_vidc_inst *inst)
{
	struct vidc_freq_data *temp;
	unsigned long freq = 0;
@@ -154,6 +225,15 @@ static unsigned long msm_vidc_get_highest_freq(struct msm_vidc_inst *inst)
	}
	mutex_unlock(&inst->freqs.lock);

	/* If current requirement is within DCVS limits, try DCVS. */

	if (freq < inst->dcvs.load_high) {
		dprintk(VIDC_DBG, "Calling DCVS now\n");
		// TODO calling DCVS here may reduce the residency. Re-visit.
		msm_dcvs_scale_clocks(inst);
		freq = inst->dcvs.load;
	}

	return freq;
}

@@ -285,7 +365,7 @@ int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
	u32 filled_len = 0;
	ion_phys_addr_t device_addr = 0;

	if (inst->count.fbd < DCVS_FTB_WINDOW) {
	if (inst->dcvs.buffer_counter < DCVS_FTB_WINDOW) {
		freq = msm_vidc_max_freq(inst);
		goto decision_done;
	}
@@ -309,7 +389,7 @@ int msm_comm_scale_clocks(struct msm_vidc_inst *inst)

	msm_vidc_update_freq_entry(inst, freq, device_addr);

	freq = msm_vidc_get_highest_freq(inst);
	freq = msm_vidc_adjust_freq(inst);

decision_done:
	inst->freq = freq;
@@ -346,35 +426,16 @@ int msm_dcvs_try_enable(struct msm_vidc_inst *inst)
		dprintk(VIDC_ERR, "%s: Invalid args: %p\n", __func__, inst);
		return -EINVAL;
	}
	inst->dcvs_mode = msm_dcvs_check_supported(inst);
	return 0;
}

static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core,
	enum session_type session_type)
{
	int active_instances = 0;
	struct msm_vidc_inst *temp = NULL;

	if (!core) {
		dprintk(VIDC_ERR, "%s: Invalid args: %pK\n", __func__, core);
		return -EINVAL;
	if (inst->flags & VIDC_THUMBNAIL) {
		dprintk(VIDC_PROF, "Thumbnail sessions don't need DCVS : %pK\n",
			inst);
		return false;
	}
	inst->dcvs_mode = true;

	/* DCVS condition is as following
	 * Decoder DCVS : Only for ONE decoder session.
	 * Encoder DCVS : Only for ONE encoder session + ONE decoder session
	 */
	mutex_lock(&core->lock);
	list_for_each_entry(temp, &core->instances, list) {
		if (temp->state >= MSM_VIDC_OPEN_DONE &&
			temp->state < MSM_VIDC_STOP_DONE &&
			(temp->session_type == session_type ||
			 temp->session_type == MSM_VIDC_ENCODER))
			active_instances++;
	}
	mutex_unlock(&core->lock);
	return active_instances;
	// TODO : Update with proper number based on on-target tuning.
	inst->dcvs.extra_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
	return true;
}

static bool msm_dcvs_check_codec_supported(int fourcc,
@@ -406,7 +467,6 @@ static bool msm_dcvs_check_codec_supported(int fourcc,

int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst)
{

	int rc = 0, j = 0;
	struct clock_freq_table *clk_freq_tbl = NULL;
	struct clock_profile_entry *entry = NULL;
@@ -442,92 +502,6 @@ int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst)
	return rc;
}

static void msm_dcvs_update_dcvs_params(int idx, struct msm_vidc_inst *inst)
{
	struct dcvs_stats *dcvs = NULL;
	struct msm_vidc_platform_resources *res = NULL;
	struct dcvs_table *table = NULL;

	if (!inst || !inst->core) {
		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
		return;
	}

	dcvs = &inst->dcvs;
	res = &inst->core->resources;
	table = res->dcvs_tbl;

	dcvs->load_low = table[idx].load_low;
	dcvs->load_high = table[idx].load_high;
	dcvs->supported_codecs = table[idx].supported_codecs;
}

static void msm_dcvs_enc_check_and_scale_clocks(struct msm_vidc_inst *inst)
{
	int rc = 0;

	if (inst->session_type == MSM_VIDC_ENCODER &&
		msm_vidc_enc_dcvs_mode) {
		rc = msm_dcvs_enc_scale_clocks(inst);
		if (rc) {
			dprintk(VIDC_DBG,
				"ENC_DCVS: error while scaling clocks\n");
		}
	}
}

static void msm_dcvs_dec_check_and_scale_clocks(struct msm_vidc_inst *inst)
{
	int rc = 0;

	if (inst->session_type == MSM_VIDC_DECODER &&
		msm_vidc_dec_dcvs_mode) {
		msm_dcvs_monitor_buffer(inst);
		rc = msm_dcvs_dec_scale_clocks(inst, false);
		if (rc) {
			dprintk(VIDC_ERR,
					"%s: Failed to scale clocks in DCVS: %d\n",
					__func__, rc);
		}
	}
}

void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb)
{
	if (!inst) {
		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
		return;
	}
	msm_dcvs_try_enable(inst);
	if (!inst->dcvs_mode) {
		dprintk(VIDC_DBG, "DCVS is not enabled\n");
		return;
	}

	if (is_etb)
		msm_dcvs_enc_check_and_scale_clocks(inst);
	else
		msm_dcvs_dec_check_and_scale_clocks(inst);
}

static inline int get_pending_bufs_fw(struct msm_vidc_inst *inst)
{
	int fw_out_qsize = 0, buffers_in_driver = 0;

	if (!inst) {
		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
		return -EINVAL;
	}

	if (inst->state >= MSM_VIDC_OPEN_DONE &&
		inst->state < MSM_VIDC_STOP_DONE) {
		fw_out_qsize = inst->count.ftb - inst->count.fbd;
		buffers_in_driver = inst->buffers_held_in_driver;
	}

	return fw_out_qsize + buffers_in_driver;
}

static inline void msm_dcvs_print_dcvs_stats(struct dcvs_stats *dcvs)
{
	dprintk(VIDC_DBG,
@@ -535,24 +509,19 @@ static inline void msm_dcvs_print_dcvs_stats(struct dcvs_stats *dcvs)
		dcvs->load_low,
		dcvs->load_high);

	dprintk(VIDC_DBG,
		"DCVS: ThrDispBufLow %d, ThrDispBufHigh %d\n",
		dcvs->threshold_disp_buf_low,
		dcvs->threshold_disp_buf_high);

	dprintk(VIDC_DBG,
		"DCVS: min_threshold %d, max_threshold %d\n",
		dcvs->min_threshold, dcvs->max_threshold);
}

void msm_dcvs_init_load(struct msm_vidc_inst *inst)
void msm_dcvs_init(struct msm_vidc_inst *inst)
{
	struct msm_vidc_core *core;
	struct hal_buffer_requirements *output_buf_req;
	int i = 0;
	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
	u64 total_freq = 0, rate = 0, load;
	int cycles;
	struct dcvs_stats *dcvs;
	struct dcvs_table *table;
	struct msm_vidc_platform_resources *res = NULL;
	int i, num_rows, fourcc;

	dprintk(VIDC_DBG, "Init DCVS Load\n");

@@ -563,412 +532,40 @@ void msm_dcvs_init_load(struct msm_vidc_inst *inst)

	core = inst->core;
	dcvs = &inst->dcvs;
	res = &core->resources;
	dcvs->load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);

	num_rows = res->dcvs_tbl_size;
	table = res->dcvs_tbl;
	inst->dcvs = (struct dcvs_stats){0};
	load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
	cycles = inst->entry->vpp_cycles;
	allowed_clks_tbl = core->resources.allowed_clks_tbl;
	if (inst->session_type == MSM_VIDC_ENCODER) {
		cycles = inst->flags & VIDC_LOW_POWER ?
			inst->entry->low_power_cycles :
			cycles;

	if (!num_rows || !table) {
		dprintk(VIDC_ERR,
				"%s: Dcvs table entry not found.\n", __func__);
		dcvs->buffer_type = HAL_BUFFER_INPUT;
		// TODO : Update with proper no based on Buffer counts change.
		dcvs->min_threshold = 7;
	} else if (inst->session_type == MSM_VIDC_DECODER) {
		dcvs->buffer_type = msm_comm_get_hal_output_buffer(inst);
		// TODO : Update with proper no based on Buffer counts change.
		dcvs->min_threshold = 4;
	} else {
		return;
	}

	fourcc = inst->session_type == MSM_VIDC_DECODER ?
				inst->fmts[OUTPUT_PORT].fourcc :
				inst->fmts[CAPTURE_PORT].fourcc;
	total_freq = cycles * load;

	for (i = 0; i < num_rows; i++) {
		bool matches = msm_dcvs_check_codec_supported(
					fourcc,
					table[i].supported_codecs,
					inst->session_type);
		if (!matches)
			continue;

		if (dcvs->load > table[i].load) {
			msm_dcvs_update_dcvs_params(i, inst);
	for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) {
		rate = allowed_clks_tbl[i].clock_rate;
		if (rate >= total_freq)
			break;
	}
	}

	if (inst->session_type == MSM_VIDC_ENCODER)
		goto print_stats;

	output_buf_req = get_buff_req_buffer(inst,
		msm_comm_get_hal_output_buffer(inst));

	if (!output_buf_req) {
		dprintk(VIDC_ERR,
			"%s: No buffer requirement for buffer type %x\n",
			__func__, HAL_BUFFER_OUTPUT);
		return;
	}

	dcvs->transition_turbo = false;
	dcvs->load = dcvs->load_high = rate;
	dcvs->load_low = allowed_clks_tbl[i+1].clock_rate;

	/* calculating the min and max threshold */
	if (output_buf_req->buffer_count_actual) {
		dcvs->min_threshold = output_buf_req->buffer_count_actual -
			output_buf_req->buffer_count_min -
			msm_dcvs_get_extra_buff_count(inst) + 1;
		dcvs->max_threshold = output_buf_req->buffer_count_actual;
		if (dcvs->max_threshold <= dcvs->min_threshold)
			dcvs->max_threshold =
				dcvs->min_threshold + DCVS_BUFFER_SAFEGUARD;
		dcvs->threshold_disp_buf_low = dcvs->min_threshold;
		dcvs->threshold_disp_buf_high = dcvs->max_threshold;
	}

print_stats:
	msm_dcvs_print_dcvs_stats(dcvs);
}

void msm_dcvs_init(struct msm_vidc_inst *inst)
{
	dprintk(VIDC_DBG, "Init DCVS Struct\n");

	if (!inst) {
		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
		return;
	}

	inst->dcvs = (struct dcvs_stats){ {0} };
	inst->dcvs.threshold_disp_buf_high = DCVS_NOMINAL_THRESHOLD;
	inst->dcvs.threshold_disp_buf_low = DCVS_TURBO_THRESHOLD;
}

void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst)
{
	int new_ftb, i, prev_buf_count;
	int fw_pending_bufs, total_output_buf, buffers_outside_fw;
	struct dcvs_stats *dcvs;
	struct hal_buffer_requirements *output_buf_req;

	if (!inst) {
		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
		return;
	}
	dcvs = &inst->dcvs;

	mutex_lock(&inst->lock);
	output_buf_req = get_buff_req_buffer(inst,
				msm_comm_get_hal_output_buffer(inst));
	if (!output_buf_req) {
		dprintk(VIDC_ERR, "%s : Get output buffer req failed %pK\n",
			__func__, inst);
		mutex_unlock(&inst->lock);
		return;
	}

	total_output_buf = output_buf_req->buffer_count_actual;
	fw_pending_bufs = get_pending_bufs_fw(inst);
	mutex_unlock(&inst->lock);

	buffers_outside_fw = total_output_buf - fw_pending_bufs;
	dcvs->num_ftb[dcvs->ftb_index] = buffers_outside_fw;
	dcvs->ftb_index = (dcvs->ftb_index + 1) % DCVS_FTB_WINDOW;

	if (dcvs->ftb_counter < DCVS_FTB_WINDOW)
		dcvs->ftb_counter++;

	dprintk(VIDC_PROF,
		"DCVS: ftb_counter %d\n", dcvs->ftb_counter);

	if (dcvs->ftb_counter == DCVS_FTB_WINDOW) {
		new_ftb = 0;
		for (i = 0; i < dcvs->ftb_counter; i++) {
			if (dcvs->num_ftb[i] > new_ftb)
				new_ftb = dcvs->num_ftb[i];
		}

		dcvs->threshold_disp_buf_high = new_ftb;
		if (dcvs->threshold_disp_buf_high <=
			dcvs->threshold_disp_buf_low +
			DCVS_BUFFER_SAFEGUARD) {
			dcvs->threshold_disp_buf_high =
				dcvs->threshold_disp_buf_low +
				DCVS_BUFFER_SAFEGUARD
				+ (DCVS_BUFFER_SAFEGUARD == 0);
		}

		dcvs->threshold_disp_buf_high =
			clamp(dcvs->threshold_disp_buf_high,
				dcvs->min_threshold,
				dcvs->max_threshold);
	}

	if (dcvs->ftb_counter == DCVS_FTB_WINDOW &&
			dcvs->load == dcvs->load_low) {
		prev_buf_count =
			dcvs->num_ftb[((dcvs->ftb_index - 2 +
				DCVS_FTB_WINDOW) % DCVS_FTB_WINDOW)];
		if (prev_buf_count == dcvs->threshold_disp_buf_low &&
			buffers_outside_fw <= dcvs->threshold_disp_buf_low) {
			dcvs->transition_turbo = true;
		} else if (buffers_outside_fw > dcvs->threshold_disp_buf_low &&
			(buffers_outside_fw -
			 (prev_buf_count - buffers_outside_fw))
			< dcvs->threshold_disp_buf_low){
			dcvs->transition_turbo = true;
		}
	}

	dprintk(VIDC_PROF,
		"DCVS: total_output_buf %d buffers_outside_fw %d load %d transition_turbo %d\n",
		total_output_buf, buffers_outside_fw, dcvs->load_low,
		dcvs->transition_turbo);
}

static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst)
{
	int rc = 0, fw_pending_bufs = 0, total_input_buf = 0;
	struct msm_vidc_core *core;
	struct dcvs_stats *dcvs;

	if (!inst || !inst->core || !inst->core->device) {
		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
		return -EINVAL;
	}

	core = inst->core;
	dcvs = &inst->dcvs;

	mutex_lock(&inst->lock);
	total_input_buf = inst->buff_req.buffer[0].buffer_count_actual;
	fw_pending_bufs = (inst->count.etb - inst->count.ebd);
	mutex_unlock(&inst->lock);

	dprintk(VIDC_PROF,
		"DCVS: total_input_buf %d, fw_pending_bufs %d\n",
		total_input_buf, fw_pending_bufs);

	if (dcvs->etb_counter < total_input_buf) {
		dcvs->etb_counter++;
		if (dcvs->etb_counter != total_input_buf)
			return rc;
	}

	dprintk(VIDC_PROF,
		"DCVS: total_input_buf %d, fw_pending_bufs %d etb_counter %d  dcvs->load %d\n",
		total_input_buf, fw_pending_bufs,
		dcvs->etb_counter, dcvs->load);

	if (fw_pending_bufs <= DCVS_ENC_LOW_THR &&
		dcvs->load > dcvs->load_low) {
		dcvs->load = dcvs->load_low;
		dcvs->prev_freq_lowered = true;
	} else {
		dcvs->prev_freq_lowered = false;
	}

	if (fw_pending_bufs >= DCVS_ENC_HIGH_THR &&
		dcvs->load <= dcvs->load_low) {
		dcvs->load = dcvs->load_high;
		dcvs->prev_freq_increased = true;
	} else {
		dcvs->prev_freq_increased = false;
	}

	if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
		dprintk(VIDC_PROF,
			"DCVS: (Scaling Clock %s)  etb clock set = %d total_input_buf = %d fw_pending_bufs %d\n",
			dcvs->prev_freq_lowered ? "Lower" : "Higher",
			dcvs->load, total_input_buf, fw_pending_bufs);

		if (rc) {
			dprintk(VIDC_PROF,
				"Failed to set clock rate in FBD: %d\n", rc);
		}
	} else {
		dprintk(VIDC_PROF,
			"DCVS: etb clock load_old = %d total_input_buf = %d fw_pending_bufs %d\n",
			dcvs->load, total_input_buf, fw_pending_bufs);
	}

	return rc;
}


/*
 * In DCVS scale_clocks will be done both in qbuf and FBD
 * 1 indicates call made from fbd that lowers clock
 * 0 indicates call made from qbuf that increases clock
 * based on DCVS algorithm
 */

static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd)
{
	int rc = 0;
	int fw_pending_bufs = 0;
	int total_output_buf = 0;
	int buffers_outside_fw = 0;
	struct msm_vidc_core *core;
	struct hal_buffer_requirements *output_buf_req;
	struct dcvs_stats *dcvs;

	if (!inst || !inst->core || !inst->core->device) {
		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
		return -EINVAL;
	}
	core = inst->core;
	dcvs = &inst->dcvs;
	mutex_lock(&inst->lock);
	fw_pending_bufs = get_pending_bufs_fw(inst);

	output_buf_req = get_buff_req_buffer(inst,
		msm_comm_get_hal_output_buffer(inst));
	mutex_unlock(&inst->lock);
	if (!output_buf_req) {
		dprintk(VIDC_ERR,
			"%s: No buffer requirement for buffer type %x\n",
			__func__, HAL_BUFFER_OUTPUT);
		return -EINVAL;
	}

	/* Total number of output buffers */
	total_output_buf = output_buf_req->buffer_count_actual;

	/* Buffers outside FW are with display */
	buffers_outside_fw = total_output_buf - fw_pending_bufs;

	if (buffers_outside_fw >= dcvs->threshold_disp_buf_high &&
		!dcvs->prev_freq_increased &&
		dcvs->load > dcvs->load_low) {
		dcvs->load = dcvs->load_low;
		dcvs->prev_freq_lowered = true;
		dcvs->prev_freq_increased = false;
	} else if (dcvs->transition_turbo && dcvs->load == dcvs->load_low) {
		dcvs->load = dcvs->load_high;
		dcvs->prev_freq_increased = true;
		dcvs->prev_freq_lowered = false;
		dcvs->transition_turbo = false;
	} else {
		dcvs->prev_freq_increased = false;
		dcvs->prev_freq_lowered = false;
	}

	if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
		dprintk(VIDC_PROF,
			"DCVS: clock set = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
			dcvs->load, total_output_buf, buffers_outside_fw,
			dcvs->threshold_disp_buf_high, dcvs->transition_turbo);

		if (rc) {
			dprintk(VIDC_ERR,
				"Failed to set clock rate in FBD: %d\n", rc);
		}
	} else {
		dprintk(VIDC_PROF,
			"DCVS: clock old = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
			dcvs->load, total_output_buf, buffers_outside_fw,
			dcvs->threshold_disp_buf_high, dcvs->transition_turbo);
	}
	return rc;
}

static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst)
{
	int num_mbs_per_frame = 0, instance_count = 0;
	long int instance_load = 0;
	long int dcvs_limit = 0;
	struct msm_vidc_inst *temp = NULL;
	struct msm_vidc_core *core;
	struct hal_buffer_requirements *output_buf_req;
	struct dcvs_stats *dcvs;
	bool is_codec_supported = false;
	bool is_dcvs_supported = true;
	struct msm_vidc_platform_resources *res = NULL;

	if (!inst || !inst->core || !inst->core->device) {
		dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
		return -EINVAL;
	}

	core = inst->core;
	dcvs = &inst->dcvs;
	res = &core->resources;

	if (!res->dcvs_limit) {
		dprintk(VIDC_WARN,
				"%s: dcvs limit table not found\n", __func__);
		return false;
	}
	instance_count = msm_dcvs_count_active_instances(core,
		inst->session_type);
	num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
	instance_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
	dcvs_limit =
		(long int)res->dcvs_limit[inst->session_type].min_mbpf *
		res->dcvs_limit[inst->session_type].fps;
	inst->dcvs.extra_buffer_count = 0;

	if (!IS_VALID_DCVS_SESSION(num_mbs_per_frame,
				res->dcvs_limit[inst->session_type].min_mbpf)) {
		inst->dcvs.extra_buffer_count = 0;
		is_dcvs_supported = false;
		goto dcvs_decision_done;

	}

	if (inst->session_type == MSM_VIDC_DECODER) {
		inst->dcvs.extra_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
		output_buf_req = get_buff_req_buffer(inst,
				msm_comm_get_hal_output_buffer(inst));
		if (!output_buf_req) {
			dprintk(VIDC_ERR,
					"%s: No buffer requirement for buffer type %x\n",
					__func__, HAL_BUFFER_OUTPUT);
			return false;
		}
		is_codec_supported =
			msm_dcvs_check_codec_supported(
				inst->fmts[OUTPUT_PORT].fourcc,
				inst->dcvs.supported_codecs,
				inst->session_type);
		if (!is_codec_supported ||
				!msm_vidc_dec_dcvs_mode) {
			inst->dcvs.extra_buffer_count = 0;
			is_dcvs_supported = false;
			goto dcvs_decision_done;
		}
		if (msm_comm_turbo_session(inst) ||
			!IS_VALID_DCVS_SESSION(instance_load, dcvs_limit) ||
			instance_count > 1)
			is_dcvs_supported = false;
	}
	if (inst->session_type == MSM_VIDC_ENCODER) {
		inst->dcvs.extra_buffer_count = DCVS_ENC_EXTRA_OUTPUT_BUFFERS;
		is_codec_supported =
			msm_dcvs_check_codec_supported(
				inst->fmts[CAPTURE_PORT].fourcc,
				inst->dcvs.supported_codecs,
				inst->session_type);
		if (!is_codec_supported ||
				!msm_vidc_enc_dcvs_mode) {
			inst->dcvs.extra_buffer_count = 0;
			is_dcvs_supported = false;
			goto dcvs_decision_done;
		}
		if (msm_comm_turbo_session(inst) ||
			!IS_VALID_DCVS_SESSION(instance_load, dcvs_limit) ||
				instance_count > 1)
			is_dcvs_supported = false;
	}
dcvs_decision_done:
	if (!is_dcvs_supported) {
		msm_comm_scale_clocks(inst);
		if (instance_count > 1) {
			mutex_lock(&core->lock);
			list_for_each_entry(temp, &core->instances, list)
				temp->dcvs_mode = false;
			mutex_unlock(&core->lock);
		}
	}
	return is_dcvs_supported;
}

int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst)
{
	if (!inst) {
+0 −3
Original line number Diff line number Diff line
@@ -32,10 +32,7 @@
#define DCVS_BUFFER_SAFEGUARD (DCVS_DEC_EXTRA_OUTPUT_BUFFERS - 1)

void msm_dcvs_init(struct msm_vidc_inst *inst);
void msm_dcvs_init_load(struct msm_vidc_inst *inst);
void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst);
int  msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst);
void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb);
int msm_dcvs_try_enable(struct msm_vidc_inst *inst);
int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst);
+4 −10
Original line number Diff line number Diff line
@@ -1525,9 +1525,6 @@ static void handle_event_change(enum hal_command_response cmd, void *data)
		inst->prop.width[OUTPUT_PORT] = event_notify->width;
	}

	if (inst->session_type == MSM_VIDC_DECODER)
		msm_dcvs_init_load(inst);

	rc = msm_vidc_check_session_supported(inst);
	if (!rc) {
		seq_changed_event.type = event;
@@ -3850,7 +3847,6 @@ static void log_frame(struct msm_vidc_inst *inst, struct vidc_frame_data *data,
			data->timestamp, data->flags);
		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FTB);
	}

}

/*
@@ -4723,6 +4719,10 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
		return 0;
	}

	// Finish FLUSH As Soon As Possible.
	inst->dcvs.buffer_counter = 0;
	msm_comm_scale_clocks_and_bus(inst);

	msm_comm_flush_dynamic_buffers(inst);

	if (inst->state == MSM_VIDC_CORE_INVALID ||
@@ -5058,9 +5058,6 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
		return -ENOTSUPP;
	}

	if (!rc)
		msm_dcvs_try_enable(inst);

	if (!rc) {
		if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
			inst->prop.height[CAPTURE_PORT] <
@@ -5377,10 +5374,7 @@ int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
			if (rc)
				dprintk(VIDC_WARN,
					"Failed to set frame rate %d\n", rc);
		} else {
			msm_dcvs_init_load(inst);
		}
		msm_dcvs_try_enable(inst);
	}
exit:
	return rc;
Loading