Example #1
0
static void nvhost_scale_notify(struct platform_device *pdev, bool busy)
{
	struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
	struct nvhost_device_profile *profile = pdata->power_profile;
	struct devfreq *devfreq = pdata->power_manager;

	/* Is the device profile initialised? */
	if (!profile)
		return;

	/* inform edp about new constraint */
	if (pdata->gpu_edp_device) {
		u32 avg = 0;
		actmon_op().read_avg_norm(profile->actmon, &avg);
		BUG();
		/* the next line passes a bogus frequency */
		tegra_edp_notify_gpu_load(avg, 0);
	}

	/* If defreq is disabled, set the freq to max or min */
	if (!devfreq) {
		unsigned long freq = busy ? UINT_MAX : 0;
		nvhost_scale_target(&pdev->dev, &freq, 0);
		return;
	}

	mutex_lock(&devfreq->lock);
	if (!profile->actmon)
		update_load_estimate(profile, busy);
	profile->dev_stat.busy = busy;
	update_devfreq(devfreq);
	mutex_unlock(&devfreq->lock);
}
Example #2
0
static int actmon_k_show(struct seq_file *s, void *unused)
{
	struct nvhost_master *host = s->private;
	long period = actmon_op().get_k(host);
	seq_printf(s, "%ld\n", period);
	return 0;
}
Example #3
0
void nvhost_scale_hw_deinit(struct platform_device *pdev)
{
	struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
	struct nvhost_device_profile *profile = pdata->power_profile;

	if (profile && profile->actmon)
		actmon_op().deinit(profile->actmon);
}
Example #4
0
static int actmon_avg_norm_show(struct seq_file *s, void *unused)
{
	struct nvhost_master *host = s->private;
	u32 avg;
	int err;

	err = actmon_op().read_avg_norm(host, &avg);
	if (!err)
		seq_printf(s, "%d\n", avg);
	return err;
}
Example #5
0
static ssize_t nvhost_scale_load_show(struct device *dev,
				      struct device_attribute *attr,
				      char *buf)
{
	struct nvhost_device_data *pdata = dev_get_drvdata(dev);
	struct nvhost_device_profile *profile = pdata->power_profile;
	u32 busy_time;
	ssize_t res;

	actmon_op().read_avg_norm(profile->actmon, &busy_time);
	res = snprintf(buf, PAGE_SIZE, "%u\n", busy_time);

	return res;
}
Example #6
0
static void update_load_estimate_actmon(struct nvhost_device_profile *profile)
{
	ktime_t t;
	unsigned long dt;
	u32 busy_time;

	t = ktime_get();
	dt = ktime_us_delta(t, profile->last_event_time);

	profile->dev_stat.total_time = dt;
	profile->last_event_time = t;
	actmon_op().read_avg_norm(profile->actmon, &busy_time);
	profile->dev_stat.busy_time = (busy_time * dt) / 1000;
}
Example #7
0
void nvhost_scale3d_callback(struct nvhost_device_profile *profile,
			     unsigned long freq)
{
	struct nvhost_gr3d_params *gr3d_params = profile->private_data;
	struct nvhost_device_data *pdata = platform_get_drvdata(profile->pdev);
	struct nvhost_emc_params *emc_params = &gr3d_params->emc_params;
	long hz;
	long after;

	/* Set EMC clockrate */
	after = (long) clk_get_rate(clk(profile, gr3d_params->clk_3d));
	hz = nvhost_scale3d_get_emc_rate(emc_params, after);
	nvhost_module_set_devfreq_rate(profile->pdev, gr3d_params->clk_3d_emc,
				       hz);

	if (pdata->gpu_edp_device) {
		u32 avg = 0;
		actmon_op().read_avg_norm(profile->actmon, &avg);
		tegra_edp_notify_gpu_load(avg);
	}
}
Example #8
0
static int actmon_k_write(struct file *file,
				const char __user *user_buf,
				size_t count, loff_t *ppos)
{
	struct seq_file *s = file->private_data;
	struct nvhost_master *host = s->private;
	char buffer[40];
	int buf_size;
	unsigned long k;

	memset(buffer, 0, sizeof(buffer));
	buf_size = min(count, (sizeof(buffer)-1));

	if (copy_from_user(buffer, user_buf, buf_size))
		return -EFAULT;

	if (kstrtoul(buffer, 10, &k))
		return -EINVAL;

	actmon_op().set_k(host, k);

	return count;
}
static int nvhost_scale3d_get_dev_status(struct device *d,
		      struct devfreq_dev_status *stat)
{
	struct platform_device *dev = to_platform_device(d);
	struct nvhost_master *host_master = nvhost_get_host(dev);
	struct nvhost_devfreq_ext_stat *ext_stat =
		power_profile.dev_stat->private_data;
	u32 avg = 0;
	ktime_t t;

	/* Make sure there are correct values for the current frequency */
	power_profile.dev_stat->current_frequency =
		clk_get_rate(power_profile.clk_3d);

	/* Copy the contents of the current device status */
	ext_stat->busy = power_profile.last_event_type;
	*stat = *power_profile.dev_stat;

	/* Read and scale AVG. AVG is scaled to interval 0-dt, where dt
	 * is the last time it was read. (this is really clumsy, but the
	 * governor uses internally time differences) */
	actmon_op().read_avg_norm(host_master, &avg);
	t = ktime_get();
	stat->total_time = ktime_us_delta(t, power_profile.last_request_time);
	stat->busy_time = (avg * stat->total_time) / 1000;
	power_profile.last_request_time = t;

	/* Finally, clear out the local values */
	power_profile.dev_stat->total_time = 0;
	power_profile.dev_stat->busy_time = 0;
	power_profile.last_event_type = DEVICE_UNKNOWN;

	tegra_edp_notify_gpu_load(avg);

	return 0;
}
Example #10
0
static int actmon_above_wmark_show(struct seq_file *s, void *unused)
{
	struct nvhost_master *host = s->private;
	seq_printf(s, "%d\n", actmon_op().above_wmark_count(host));
	return 0;
}
Example #11
0
void nvhost_scale_init(struct platform_device *pdev)
{
	struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
	struct nvhost_device_profile *profile;
	int err;

	if (pdata->power_profile)
		return;

	profile = kzalloc(sizeof(struct nvhost_device_profile), GFP_KERNEL);
	if (!profile)
		return;
	pdata->power_profile = profile;
	profile->pdev = pdev;
	profile->clk = pdata->clk[0];
	profile->dev_stat.busy = false;

	/* Create frequency table */
	err = nvhost_scale_make_freq_table(profile);
	if (err || !profile->devfreq_profile.max_state)
		goto err_get_freqs;

	/* Initialize actmon */
	if (pdata->actmon_enabled) {

		if (device_create_file(&pdev->dev,
		    &dev_attr_load))
			goto err_create_sysfs_entry;

		profile->actmon = kzalloc(sizeof(struct host1x_actmon),
					  GFP_KERNEL);
		if (!profile->actmon)
			goto err_allocate_actmon;

		profile->actmon->host = nvhost_get_host(pdev);
		profile->actmon->regs = nvhost_get_host(pdev)->aperture +
			pdata->actmon_regs;

		actmon_op().init(profile->actmon);
		actmon_op().debug_init(profile->actmon, pdata->debugfs);
		actmon_op().deinit(profile->actmon);
	}

	if (pdata->devfreq_governor) {
		struct devfreq *devfreq;

		profile->devfreq_profile.initial_freq =
			profile->devfreq_profile.freq_table[0];
		profile->devfreq_profile.target = nvhost_scale_target;
		profile->devfreq_profile.get_dev_status =
			nvhost_scale_get_dev_status;

		devfreq = devfreq_add_device(&pdev->dev,
					&profile->devfreq_profile,
					pdata->devfreq_governor, NULL);

		if (IS_ERR(devfreq))
			devfreq = NULL;

		pdata->power_manager = devfreq;
	}

	/* Should we register QoS callback for this device? */
	if (pdata->qos_id < PM_QOS_NUM_CLASSES &&
	    pdata->qos_id != PM_QOS_RESERVED) {
		profile->qos_notify_block.notifier_call =
			&nvhost_scale_qos_notify;
		pm_qos_add_notifier(pdata->qos_id,
				    &profile->qos_notify_block);
	}

	return;

err_get_freqs:
err_allocate_actmon:
	device_remove_file(&pdev->dev, &dev_attr_load);
err_create_sysfs_entry:
	kfree(pdata->power_profile);
	pdata->power_profile = NULL;
}
void nvhost_scale_init(struct platform_device *pdev)
{
	struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
	struct nvhost_device_profile *profile;

	if (pdata->power_profile)
		return;

	profile = kzalloc(sizeof(struct nvhost_device_profile), GFP_KERNEL);
	if (!profile)
		return;
	pdata->power_profile = profile;
	profile->pdev = pdev;
	profile->clk = pdata->clk[0];
	profile->last_event_type = DEVICE_UNKNOWN;

	/* Initialize devfreq related structures */
	profile->dev_stat.private_data = &profile->ext_stat;
	profile->ext_stat.min_freq =
		clk_round_rate(clk_get_parent(profile->clk), 0);
	profile->ext_stat.max_freq =
		clk_round_rate(clk_get_parent(profile->clk), UINT_MAX);
	profile->ext_stat.busy = DEVICE_UNKNOWN;

	if (profile->ext_stat.min_freq == profile->ext_stat.max_freq) {
		dev_warn(&pdev->dev, "max rate = min rate (%lu), disabling scaling\n",
			 profile->ext_stat.min_freq);
		goto err_fetch_clocks;
	}

	/* Initialize actmon */
	if (pdata->actmon_enabled) {

		if (device_create_file(&pdev->dev,
		    &dev_attr_load))
			goto err_create_sysfs_entry;

		profile->actmon = kzalloc(sizeof(struct host1x_actmon),
					  GFP_KERNEL);
		if (!profile->actmon)
			goto err_allocate_actmon;

		profile->actmon->host = nvhost_get_host(pdev);
		profile->actmon->regs = nvhost_get_host(pdev)->aperture +
			pdata->actmon_regs;

		actmon_op().init(profile->actmon);
		actmon_op().debug_init(profile->actmon, pdata->debugfs);
		actmon_op().deinit(profile->actmon);
	}

	if (pdata->devfreq_governor) {
		struct devfreq *devfreq = devfreq_add_device(&pdev->dev,
					&nvhost_scale_devfreq_profile,
					pdata->devfreq_governor, NULL);

		if (IS_ERR(devfreq))
			devfreq = NULL;

		pdata->power_manager = devfreq;
	}

	return;

err_allocate_actmon:
	device_remove_file(&pdev->dev, &dev_attr_load);
err_create_sysfs_entry:
err_fetch_clocks:
	kfree(pdata->power_profile);
	pdata->power_profile = NULL;
}