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

Commit c9b7da0a authored by Prakash Kamliya's avatar Prakash Kamliya Committed by Lynus Vaz
Browse files

msm: kgsl: Do a midframe sampling of power stats if enabled



Currently we sample power stats at the expiry of
cmdbatch. In cases where cmdbatch takes a long time
to finish the job, it delays power stats sampling,
in effect it delays DCVS decision for changing the
frequency. Do a midframe power stats sampling and
feed it to DCVS if it is enabled.

Change-Id: I547d792b38649aa1d60525b0dc335791b37989fd
Signed-off-by: default avatarPrakash Kamliya <pkamliya@codeaurora.org>
parent 24fee1ce
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -156,6 +156,12 @@ Optional Properties:
				Specify the name of GPU temperature sensor. This name will be used
				to get the temperature from the thermal driver API.

- qcom,enable-midframe-timer:
				Boolean. Enables the use of midframe sampling timer. This timer
				samples the GPU powerstats if the cmdbatch expiry takes longer than
				the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if
				target has NAP state enabled.

GPU Quirks:
- qcom,gpu-quirk-two-pass-use-wfi:
				Signal the GPU to set Set TWOPASSUSEWFI bit in
+10 −0
Original line number Diff line number Diff line
@@ -608,6 +608,16 @@ static int sendcmd(struct adreno_device *adreno_dev,
			if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE,
				&dispatcher->priv))
				reinit_completion(&dispatcher->idle_gate);

			/*
			 * We update power stats generally at the expire of
			 * cmdbatch. In cases where the cmdbatch takes a long
			 * time to finish, it will delay power stats update,
			 * in effect it will delay DCVS decision. Start a
			 * timer to update power state on expire of this timer.
			 */
			kgsl_pwrscale_midframe_timer_restart(device);

		} else {
			kgsl_active_count_put(device);
			clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
+5 −0
Original line number Diff line number Diff line
@@ -2416,6 +2416,7 @@ static int _init(struct kgsl_device *device)
	case KGSL_STATE_ACTIVE:
		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
		del_timer_sync(&device->idle_timer);
		kgsl_pwrscale_midframe_timer_cancel(device);
		device->ftbl->stop(device);
		/* fall through */
	case KGSL_STATE_AWARE:
@@ -2524,6 +2525,7 @@ _aware(struct kgsl_device *device)
	case KGSL_STATE_ACTIVE:
		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
		del_timer_sync(&device->idle_timer);
		kgsl_pwrscale_midframe_timer_cancel(device);
		break;
	case KGSL_STATE_SLUMBER:
		status = kgsl_pwrctrl_enable(device);
@@ -2548,6 +2550,8 @@ _nap(struct kgsl_device *device)
			return -EBUSY;
		}

		kgsl_pwrscale_midframe_timer_cancel(device);

		/*
		 * Read HW busy counters before going to NAP state.
		 * The data might be used by power scale governors
@@ -2587,6 +2591,7 @@ _slumber(struct kgsl_device *device)
		/* fall through */
	case KGSL_STATE_NAP:
		del_timer_sync(&device->idle_timer);
		kgsl_pwrscale_midframe_timer_cancel(device);
		if (device->pwrctrl.thermal_cycle == CYCLE_ACTIVE) {
			device->pwrctrl.thermal_cycle = CYCLE_ENABLE;
			del_timer_sync(&device->pwrctrl.thermal_timer);
+79 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@

#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>

#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -37,6 +38,18 @@ static struct kgsl_popp popp_param[POPP_MAX] = {
	{0, 0},
};

/**
 * struct kgsl_midframe_info - midframe power stats sampling info
 * @timer - midframe sampling timer
 * @timer_check_ws - Updates powerstats on midframe expiry
 * @device - pointer to kgsl_device
 */
static struct kgsl_midframe_info {
	struct hrtimer timer;
	struct work_struct timer_check_ws;
	struct kgsl_device *device;
} *kgsl_midframe = NULL;

static void do_devfreq_suspend(struct work_struct *work);
static void do_devfreq_resume(struct work_struct *work);
static void do_devfreq_notify(struct work_struct *work);
@@ -187,9 +200,57 @@ void kgsl_pwrscale_update(struct kgsl_device *device)
	if (device->state != KGSL_STATE_SLUMBER)
		queue_work(device->pwrscale.devfreq_wq,
			&device->pwrscale.devfreq_notify_ws);

	kgsl_pwrscale_midframe_timer_restart(device);
}
EXPORT_SYMBOL(kgsl_pwrscale_update);

void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device)
{
	if (kgsl_midframe) {
		WARN_ON(!mutex_is_locked(&device->mutex));

		/* If the timer is already running, stop it */
		if (hrtimer_active(&kgsl_midframe->timer))
			hrtimer_cancel(
				&kgsl_midframe->timer);

		hrtimer_start(&kgsl_midframe->timer,
				ns_to_ktime(KGSL_GOVERNOR_CALL_INTERVAL
					* NSEC_PER_USEC), HRTIMER_MODE_REL);
	}
}
EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_restart);

void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device)
{
	if (kgsl_midframe) {
		WARN_ON(!mutex_is_locked(&device->mutex));
		hrtimer_cancel(&kgsl_midframe->timer);
	}
}
EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_cancel);

static void kgsl_pwrscale_midframe_timer_check(struct work_struct *work)
{
	struct kgsl_device *device = kgsl_midframe->device;

	mutex_lock(&device->mutex);
	if (device->state == KGSL_STATE_ACTIVE)
		kgsl_pwrscale_update(device);
	mutex_unlock(&device->mutex);
}

static enum hrtimer_restart kgsl_pwrscale_midframe_timer(struct hrtimer *timer)
{
	struct kgsl_device *device = kgsl_midframe->device;

	queue_work(device->pwrscale.devfreq_wq,
			&kgsl_midframe->timer_check_ws);

	return HRTIMER_NORESTART;
}

/*
 * kgsl_pwrscale_disable - temporarily disable the governor
 * @device: The device
@@ -860,6 +921,17 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
			data->bin.ctxt_aware_busy_penalty = 12000;
	}

	if (of_property_read_bool(device->pdev->dev.of_node,
			"qcom,enable-midframe-timer")) {
		kgsl_midframe = kzalloc(
				sizeof(struct kgsl_midframe_info), GFP_KERNEL);
		hrtimer_init(&kgsl_midframe->timer,
				CLOCK_MONOTONIC, HRTIMER_MODE_REL);
		kgsl_midframe->timer.function =
				kgsl_pwrscale_midframe_timer;
		kgsl_midframe->device = device;
	}

	/*
	 * If there is a separate GX power rail, allow
	 * independent modification to its voltage through
@@ -908,6 +980,9 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
	INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
	INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
	INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
	if (kgsl_midframe)
		INIT_WORK(&kgsl_midframe->timer_check_ws,
				kgsl_pwrscale_midframe_timer_check);

	pwrscale->next_governor_call = ktime_add_us(ktime_get(),
			KGSL_GOVERNOR_CALL_INTERVAL);
@@ -946,9 +1021,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device)
	pwrscale = &device->pwrscale;
	if (!pwrscale->devfreqptr)
		return;

	kgsl_pwrscale_midframe_timer_cancel(device);
	flush_workqueue(pwrscale->devfreq_wq);
	destroy_workqueue(pwrscale->devfreq_wq);
	devfreq_remove_device(device->pwrscale.devfreqptr);
	kfree(kgsl_midframe);
	kgsl_midframe = NULL;
	device->pwrscale.devfreqptr = NULL;
	srcu_cleanup_notifier_head(&device->pwrscale.nh);
	for (i = 0; i < KGSL_PWREVENT_MAX; i++)
+3 −0
Original line number Diff line number Diff line
@@ -122,6 +122,9 @@ void kgsl_pwrscale_busy(struct kgsl_device *device);
void kgsl_pwrscale_sleep(struct kgsl_device *device);
void kgsl_pwrscale_wake(struct kgsl_device *device);

void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device);
void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device);

void kgsl_pwrscale_enable(struct kgsl_device *device);
void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo);