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

Commit 53deebb2 authored by Vikash Garodia's avatar Vikash Garodia
Browse files

msm: vidc: Remove devfreq module from video



Bus bandwidth voting can be achieved by directly call
the bus apis. DevFreq functionality is not utilized nor
necessary. Also, video bus bandwidth votes are dynamic
and cannot conform to the OPP table entries.

CRs-Fixed: 2384822
Change-Id: Ib83f51d7d07efe24a256e0287433e7a28e2ae057
Signed-off-by: default avatarChinmay Sawarkar <chinmays@codeaurora.org>
Signed-off-by: default avatarVikash Garodia <vgarodia@codeaurora.org>
parent aef06aa7
Loading
Loading
Loading
Loading
+59 −142
Original line number Diff line number Diff line
@@ -3,28 +3,21 @@
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 */


#include <linux/module.h>
#include "governor.h"
#include "msm_vidc_debug.h"
#include "fixedpoint.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
#define COMPRESSION_RATIO_MAX 5

enum governor_mode {
	GOVERNOR_DDR,
	GOVERNOR_LLCC,
};

struct governor {
	enum governor_mode mode;
	struct devfreq_governor devfreq_gov;
enum vidc_bus_type {
	PERF,
	DDR,
	LLCC,
};

/*
 * Minimum dimensions that the governor is willing to calculate
 * bandwidth for.  This means that anything bandwidth(0, 0) ==
 * Minimum dimensions for which to calculate bandwidth.
 * This means that anything bandwidth(0, 0) ==
 * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height)
 */
static const struct {
@@ -34,15 +27,6 @@ static const struct {
	.height = 720,
};

/*
 * These are hardcoded AB values that the governor votes for in certain
 * situations, where a certain bus frequency is desired.  It isn't exactly
 * scalable since different platforms have different bus widths, but we'll
 * deal with that in the future.
 */
const unsigned long NOMINAL_BW_MBPS = 6000 /* ideally 320 Mhz */,
	SVS_BW_MBPS = 2000 /* ideally 100 Mhz */;

/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */
#define kbps(__mbps) ((__mbps) * 1000)
#define bps(__mbps) (kbps(__mbps) * 1000)
@@ -207,6 +191,16 @@ static struct lut {
	},
};

static u32 get_type_frm_name(char *name)
{
	if (!strcmp(name, "venus-llcc"))
		return LLCC;
	else if (!strcmp(name, "venus-ddr"))
		return DDR;
	else
		return PERF;
}

static struct lut const *__lut(int width, int height, int fps)
{
	int frame_size = height * width, c = 0;
@@ -277,21 +271,21 @@ static void __dump(struct dump dump[], int len)
}

static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d,
		enum governor_mode gm)
		enum vidc_bus_type type)
{
	return 0;
}

static unsigned long __calculate_cvp(struct vidc_bus_vote_data *d,
		enum governor_mode gm)
		enum vidc_bus_type type)
{
	unsigned long ret = 0;

	switch (gm) {
	case GOVERNOR_DDR:
	switch (type) {
	case DDR:
		ret = d->ddr_bw;
		break;
	case GOVERNOR_LLCC:
	case LLCC:
		ret = d->sys_cache_bw;
		break;
	default:
@@ -332,7 +326,7 @@ static int __bpp(enum hal_uncompressed_format f)
}

static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
		enum governor_mode gm)
		enum vidc_bus_type type)
{
	/*
	 * XXX: Don't fool around with any of the hardcoded numbers unless you
@@ -573,11 +567,11 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
		__dump(dump, ARRAY_SIZE(dump));
	}

	switch (gm) {
	case GOVERNOR_DDR:
	switch (type) {
	case DDR:
		ret = kbps(fp_round(ddr.total));
		break;
	case GOVERNOR_LLCC:
	case LLCC:
		ret = kbps(fp_round(llc.total));
		break;
	default:
@@ -588,7 +582,7 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
}

static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
		enum governor_mode gm)
		enum vidc_bus_type type)
{
	/*
	 * XXX: Don't fool around with any of the hardcoded numbers unless you
@@ -870,11 +864,11 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
		__dump(dump, ARRAY_SIZE(dump));
	}

	switch (gm) {
	case GOVERNOR_DDR:
	switch (type) {
	case DDR:
		ret = kbps(fp_round(ddr.total));
		break;
	case GOVERNOR_LLCC:
	case LLCC:
		ret = kbps(fp_round(llc.total));
		break;
	default:
@@ -885,41 +879,37 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
}

static unsigned long __calculate(struct vidc_bus_vote_data *d,
		enum governor_mode gm)
		enum vidc_bus_type type)
{
	unsigned long (*calc[])(struct vidc_bus_vote_data *,
			enum governor_mode) = {
		[HAL_VIDEO_DOMAIN_VPE] = __calculate_vpe,
		[HAL_VIDEO_DOMAIN_ENCODER] = __calculate_encoder,
		[HAL_VIDEO_DOMAIN_DECODER] = __calculate_decoder,
		[HAL_VIDEO_DOMAIN_CVP] = __calculate_cvp,
	};
	unsigned long value = 0;

	if (d->domain >= ARRAY_SIZE(calc)) {
		dprintk(VIDC_ERR, "%s: invalid domain %d\n",
			__func__, d->domain);
		return 0;
	}
	return calc[d->domain](d, gm);
	switch (d->domain) {
	case HAL_VIDEO_DOMAIN_VPE:
		value = __calculate_vpe(d, type);
		break;
	case HAL_VIDEO_DOMAIN_ENCODER:
		value = __calculate_encoder(d, type);
		break;
	case HAL_VIDEO_DOMAIN_DECODER:
		value = __calculate_decoder(d, type);
		break;
	case HAL_VIDEO_DOMAIN_CVP:
		value = __calculate_cvp(d, type);
		break;
	default:
		dprintk(VIDC_ERR, "Unknown Domain");
	}

	return value;
}

static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
unsigned long __calc_bw(struct bus_info *bus,
				struct msm_vidc_gov_data *vidc_data)
{
	unsigned long ab_kbps = 0, c = 0;
	struct devfreq_dev_status stats = {0};
	struct msm_vidc_gov_data *vidc_data = NULL;
	struct governor *gov = NULL;

	if (!dev || !freq)
		return -EINVAL;
	enum vidc_bus_type type;

	gov = container_of(dev->governor,
			struct governor, devfreq_gov);
	dev->profile->get_dev_status(dev->dev.parent, &stats);
	vidc_data = (struct msm_vidc_gov_data *)stats.private_data;

	if (!vidc_data || !vidc_data->data_count)
	if (!vidc_data || !vidc_data->data_count || !vidc_data->data)
		goto exit;

	for (c = 0; c < vidc_data->data_count; ++c) {
@@ -929,85 +919,12 @@ static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
		}
	}

	type = get_type_frm_name(bus->name);

	for (c = 0; c < vidc_data->data_count; ++c)
		ab_kbps += __calculate(&vidc_data->data[c], gov->mode);
		ab_kbps += __calculate(&vidc_data->data[c], type);

exit:
	*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?
		dev->max_freq : UINT_MAX);
	trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq);
	return 0;
}

static int __event_handler(struct devfreq *devfreq, unsigned int event,
		void *data)
{
	int rc = 0;

	if (!devfreq)
		return -EINVAL;

	switch (event) {
	case DEVFREQ_GOV_START:
	case DEVFREQ_GOV_RESUME:
	case DEVFREQ_GOV_SUSPEND:
		mutex_lock(&devfreq->lock);
		rc = update_devfreq(devfreq);
		mutex_unlock(&devfreq->lock);
		break;
	}

	return rc;
}

static struct governor governors[] = {
	{
		.mode = GOVERNOR_DDR,
		.devfreq_gov = {
			.name = "msm-vidc-ddr",
			.get_target_freq = __get_target_freq,
			.event_handler = __event_handler,
		},
	},
	{
		.mode = GOVERNOR_LLCC,
		.devfreq_gov = {
			.name = "msm-vidc-llcc",
			.get_target_freq = __get_target_freq,
			.event_handler = __event_handler,
		},
	},
};

static int __init msm_vidc_bw_gov_init(void)
{
	int c = 0, rc = 0;

	for (c = 0; c < ARRAY_SIZE(governors); ++c) {
		dprintk(VIDC_DBG, "Adding governor %s\n",
				governors[c].devfreq_gov.name);

		rc = devfreq_add_governor(&governors[c].devfreq_gov);
		if (rc) {
			dprintk(VIDC_ERR, "Error adding governor %s: %d\n",
				governors[c].devfreq_gov.name, rc);
			break;
		}
	}

	return rc;
}
module_init(msm_vidc_bw_gov_init);

static void __exit msm_vidc_bw_gov_exit(void)
{
	int c = 0;

	for (c = 0; c < ARRAY_SIZE(governors); ++c) {
		dprintk(VIDC_DBG, "Removing governor %s\n",
				governors[c].devfreq_gov.name);
		devfreq_remove_governor(&governors[c].devfreq_gov);
	}
	trace_msm_vidc_perf_bus_vote(bus->name, ab_kbps);
	return ab_kbps;
}
module_exit(msm_vidc_bw_gov_exit);
MODULE_LICENSE("GPL v2");
+5 −16
Original line number Diff line number Diff line
@@ -420,23 +420,12 @@ static int msm_vidc_populate_bus(struct device *dev,
		goto err_bus;
	}

	rc = of_property_read_string(dev->of_node, "qcom,bus-governor",
			&bus->governor);
	if (rc) {
		rc = 0;
		dprintk(VIDC_DBG,
				"'qcom,bus-governor' not found, default to performance governor\n");
		bus->governor = PERF_GOV;
	}
	rc = of_property_read_string(dev->of_node, "qcom,mode",
			&bus->mode);

	if (!strcmp(bus->governor, PERF_GOV))
	if (!rc && !strcmp(bus->mode, PERF_GOV))
		bus->is_prfm_gov_used = true;

	if (of_find_property(dev->of_node, "operating-points-v2", NULL))
		bus->has_freq_table = true;
	else
		bus->has_freq_table = false;

	rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps",
			range, ARRAY_SIZE(range));
	if (rc) {
@@ -452,8 +441,8 @@ static int msm_vidc_populate_bus(struct device *dev,

	buses->count++;
	bus->dev = dev;
	dprintk(VIDC_DBG, "Found bus %s [%d->%d] with governor %s\n",
			bus->name, bus->master, bus->slave, bus->governor);
	dprintk(VIDC_DBG, "Found bus %s [%d->%d] with mode %s\n",
			bus->name, bus->master, bus->slave, bus->mode);
err_bus:
	return rc;
}
+1 −5
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@
#ifndef __MSM_VIDC_RESOURCES_H__
#define __MSM_VIDC_RESOURCES_H__

#include <linux/devfreq.h>
#include <linux/platform_device.h>
#include "msm_vidc.h"
#include <linux/soc/qcom/llcc-qcom.h>
@@ -94,13 +93,10 @@ struct bus_info {
	int master;
	int slave;
	unsigned int range[2];
	const char *governor;
	struct device *dev;
	struct devfreq_dev_profile devfreq_prof;
	struct devfreq *devfreq;
	struct msm_bus_client_handle *client;
	bool is_prfm_gov_used;
	bool has_freq_table;
	const char *mode;
};

struct bus_set {
+24 −130
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@
#include <linux/clk/qcom.h>
#include <linux/coresight-stm.h>
#include <linux/delay.h>
#include <linux/devfreq.h>
#include <linux/hash.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -984,84 +983,24 @@ static void __set_threshold_registers(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Failed to restore threshold values\n");
}

static int __devfreq_target(struct device *devfreq_dev,
		unsigned long *freq, u32 flags)
static int __vote_bandwidth(struct bus_info *bus,
		unsigned long *freq)
{
	int rc = 0;
	uint64_t ab = 0;
	struct bus_info *bus = NULL, *temp = NULL;
	struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);

	venus_hfi_for_each_bus(device, temp) {
		if (temp->dev == devfreq_dev) {
			bus = temp;
			break;
		}
	}

	if (!bus) {
		rc = -EBADHANDLE;
		goto err_unknown_device;
	}

	/*
	 * Clamp for all non zero frequencies. This clamp is necessary to stop
	 * devfreq driver from spamming - Couldn't update frequency - logs, if
	 * the scaled ab value is not part of the frequency table.
	 */
	if (*freq)
		*freq = clamp_t(typeof(*freq), *freq, bus->range[0],
				bus->range[1]);

	/* we expect governors to provide values in kBps form, convert to Bps */
	/* Bus Driver expects values in Bps */
	ab = *freq * 1000;
	dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab);
	rc = msm_bus_scale_update_bw(bus->client, ab, 0);
	if (rc) {
		dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu\n: %d",
	if (rc)
		dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu, rc=%d\n",
				bus->name, ab, rc);
		goto err_unknown_device;
	}

	dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab);

	return 0;
err_unknown_device:
	return rc;
}

static int __devfreq_get_status(struct device *devfreq_dev,
		struct devfreq_dev_status *stat)
{
	int rc = 0;
	struct bus_info *bus = NULL, *temp = NULL;
	struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);

	venus_hfi_for_each_bus(device, temp) {
		if (temp->dev == devfreq_dev) {
			bus = temp;
			break;
		}
	}

	if (!bus) {
		rc = -EBADHANDLE;
		goto err_unknown_device;
	}

	*stat = (struct devfreq_dev_status) {
		.private_data = &device->bus_vote,
		/*
		 * Put in dummy place holder values for upstream govs, our
		 * custom gov only needs .private_data.  We should fill this in
		 * properly if we can actually measure busy_time accurately
		 * (which we can't at the moment)
		 */
		.total_time = 1,
		.busy_time = 1,
		.current_frequency = 0,
	};

err_unknown_device:
	return rc;
}

@@ -1069,18 +1008,19 @@ static int __unvote_buses(struct venus_hfi_device *device)
{
	int rc = 0;
	struct bus_info *bus = NULL;
	unsigned long freq = 0, zero = 0;

	kfree(device->bus_vote.data);
	device->bus_vote.data = NULL;
	device->bus_vote.data_count = 0;

	venus_hfi_for_each_bus(device, bus) {
		unsigned long zero = 0;

		if (!bus->is_prfm_gov_used)
			rc = devfreq_suspend_device(bus->devfreq);
		if (!bus->is_prfm_gov_used) {
			freq = __calc_bw(bus, &device->bus_vote);
			rc = __vote_bandwidth(bus, &freq);
		}
		else
			rc = __devfreq_target(bus->dev, &zero, 0);
			rc = __vote_bandwidth(bus, &zero);

		if (rc)
			goto err_unknown_device;
@@ -1096,6 +1036,7 @@ static int __vote_buses(struct venus_hfi_device *device,
	int rc = 0;
	struct bus_info *bus = NULL;
	struct vidc_bus_vote_data *new_data = NULL;
	unsigned long freq = 0;

	if (!num_data) {
		dprintk(VIDC_DBG, "No vote data available\n");
@@ -1118,15 +1059,18 @@ static int __vote_buses(struct venus_hfi_device *device,
	device->bus_vote.data_count = num_data;

	venus_hfi_for_each_bus(device, bus) {
		if (bus && bus->devfreq) {
		if (bus) {
			if (!bus->is_prfm_gov_used) {
				rc = devfreq_resume_device(bus->devfreq);
				if (rc)
					goto err_no_mem;
				freq = __calc_bw(bus, &device->bus_vote);
			} else {
				bus->devfreq->nb.notifier_call(
					&bus->devfreq->nb, 0, NULL);
				freq = bus->range[1];
				dprintk(VIDC_ERR, "%s %s perf Vote %u\n",
						__func__, bus->name,
						bus->range[1]);
			}
			rc = __vote_bandwidth(bus, &freq);
		} else {
			dprintk(VIDC_ERR, "No BUS to Vote\n");
		}
	}

@@ -3891,10 +3835,6 @@ static void __deinit_bus(struct venus_hfi_device *device)
	device->bus_vote = DEFAULT_BUS_VOTE;

	venus_hfi_for_each_bus_reverse(device, bus) {
		devfreq_remove_device(bus->devfreq);
		bus->devfreq = NULL;
		dev_set_drvdata(bus->dev, NULL);

		msm_bus_scale_unregister(bus->client);
		bus->client = NULL;
	}
@@ -3909,41 +3849,14 @@ static int __init_bus(struct venus_hfi_device *device)
		return -EINVAL;

	venus_hfi_for_each_bus(device, bus) {
		struct devfreq_dev_profile profile = {
			.initial_freq = 0,
			.polling_ms = INT_MAX,
			.freq_table = NULL,
			.max_state = 0,
			.target = __devfreq_target,
			.get_dev_status = __devfreq_get_status,
			.exit = NULL,
			/*.get_cur_greq = NULL,*/
		};

		if (!strcmp(bus->governor, "msm-vidc-llcc")) {
		if (!strcmp(bus->mode, "msm-vidc-llcc")) {
			if (msm_vidc_syscache_disable) {
				dprintk(VIDC_DBG,
					 "Skipping LLC bus init %s: %s\n",
				bus->name, bus->governor);
				bus->name, bus->mode);
				continue;
			}
		}

		/*
		 * This is stupid, but there's no other easy way to get a hold
		 * of struct bus_info in venus_hfi_devfreq_*()
		 */
		WARN(dev_get_drvdata(bus->dev), "%s's drvdata already set\n",
				dev_name(bus->dev));
		dev_set_drvdata(bus->dev, device);

		if (bus->has_freq_table) {
			rc = dev_pm_opp_of_add_table(bus->dev);
			if (rc)
				dprintk(VIDC_ERR, "Failed to add %s OPP table",
						bus->name);
		}

		bus->client = msm_bus_scale_register(bus->master, bus->slave,
				bus->name, false);
		if (IS_ERR_OR_NULL(bus->client)) {
@@ -3954,25 +3867,6 @@ static int __init_bus(struct venus_hfi_device *device)
			bus->client = NULL;
			goto err_add_dev;
		}

		bus->devfreq_prof = profile;
		bus->devfreq = devfreq_add_device(bus->dev,
				&bus->devfreq_prof, bus->governor, NULL);
		if (IS_ERR_OR_NULL(bus->devfreq)) {
			rc = PTR_ERR(bus->devfreq) ?
				PTR_ERR(bus->devfreq) : -EBADHANDLE;
			dprintk(VIDC_ERR,
					"Failed to add devfreq device for bus %s and governor %s: %d\n",
					bus->name, bus->governor, rc);
			bus->devfreq = NULL;
			goto err_add_dev;
		}

		/*
		 * Devfreq starts monitoring immediately, since we are just
		 * initializing stuff at this point, force it to suspend
		 */
		devfreq_suspend_device(bus->devfreq);
	}

	return 0;
+3 −0
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@
#define VIDC_MAX_SUBCACHES 4
#define VIDC_MAX_SUBCACHE_SIZE 52

extern unsigned long __calc_bw(struct bus_info *bus,
			struct msm_vidc_gov_data *vidc_data);

struct hfi_queue_table_header {
	u32 qtbl_version;
	u32 qtbl_size;