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

Commit 0938d06b authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Add a framework to track timing of power events"

parents fee0fb84 8d5f1005
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -110,6 +110,42 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device,
static void kgsl_pwrctrl_request_state(struct kgsl_device *device,
				unsigned int state);

/**
 * _record_pwrevent() - Record the history of the new event
 * @device: Pointer to the kgsl_device struct
 * @t: Timestamp
 * @event: Event type
 *
 * Finish recording the duration of the previous event.  Then update the
 * index, record the start of the new event, and the relevant data.
 */
static void _record_pwrevent(struct kgsl_device *device,
			ktime_t t, int event) {
	struct kgsl_pwrscale *psc = &device->pwrscale;
	struct kgsl_pwr_history *history = &psc->history[event];
	int i = history->index;
	if (history->events == NULL)
		return;
	history->events[i].duration = ktime_us_delta(t,
					history->events[i].start);
	i = (i + 1) % history->size;
	history->index = i;
	history->events[i].start = t;
	switch (event) {
	case KGSL_PWREVENT_STATE:
		history->events[i].data = device->state;
		break;
	case KGSL_PWREVENT_GPU_FREQ:
		history->events[i].data = device->pwrctrl.active_pwrlevel;
		break;
	case KGSL_PWREVENT_BUS_FREQ:
		history->events[i].data = last_vote_buslevel;
		break;
	default:
		break;
	}
}

/**
 * kgsl_get_bw() - Return latest msm bus IB vote
 */
@@ -2046,6 +2082,12 @@ int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state)
		status = -EINVAL;
		break;
	}

	/* Record the state timing info */
	if (!status) {
		ktime_t t = ktime_get();
		_record_pwrevent(device, t, KGSL_PWREVENT_STATE);
	}
	return status;
}
EXPORT_SYMBOL(kgsl_pwrctrl_change_state);
+12 −1
Original line number Diff line number Diff line
/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -610,6 +610,14 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
	pwrscale->next_governor_call = ktime_add_us(ktime_get(),
			KGSL_GOVERNOR_CALL_INTERVAL);

	/* history tracking */
	for (i = 0; i < KGSL_PWREVENT_MAX; i++) {
		pwrscale->history[i].events = kzalloc(
				pwrscale->history[i].size *
				sizeof(struct kgsl_pwr_event), GFP_KERNEL);
		pwrscale->history[i].type = i;
	}

	return 0;
}
EXPORT_SYMBOL(kgsl_pwrscale_init);
@@ -622,6 +630,7 @@ EXPORT_SYMBOL(kgsl_pwrscale_init);
 */
void kgsl_pwrscale_close(struct kgsl_device *device)
{
	int i;
	struct kgsl_pwrscale *pwrscale;

	BUG_ON(!mutex_is_locked(&device->mutex));
@@ -634,6 +643,8 @@ void kgsl_pwrscale_close(struct kgsl_device *device)
	devfreq_remove_device(device->pwrscale.devfreqptr);
	device->pwrscale.devfreqptr = NULL;
	srcu_cleanup_notifier_head(&device->pwrscale.nh);
	for (i = 0; i < KGSL_PWREVENT_MAX; i++)
		kfree(pwrscale->history[i].events);
}
EXPORT_SYMBOL(kgsl_pwrscale_close);

+28 −2
Original line number Diff line number Diff line
/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -20,12 +20,32 @@
/* devfreq governor call window in usec */
#define KGSL_GOVERNOR_CALL_INTERVAL 10000

/* Power events to be tracked with history */
#define KGSL_PWREVENT_STATE	0
#define KGSL_PWREVENT_GPU_FREQ	1
#define KGSL_PWREVENT_BUS_FREQ	2
#define KGSL_PWREVENT_POPP	3
#define KGSL_PWREVENT_MAX	4

struct kgsl_power_stats {
	u64 busy_time;
	u64 ram_time;
	u64 ram_wait;
};

struct kgsl_pwr_event {
	unsigned int data;
	ktime_t start;
	s64 duration;
};

struct kgsl_pwr_history {
	struct kgsl_pwr_event *events;
	unsigned int type;
	unsigned int index;
	unsigned int size;
};

struct kgsl_pwrscale {
	struct devfreq *devfreqptr;
	struct msm_adreno_extended_profile gpu_profile;
@@ -42,6 +62,7 @@ struct kgsl_pwrscale {
	struct work_struct devfreq_resume_ws;
	struct work_struct devfreq_notify_ws;
	ktime_t next_governor_call;
	struct kgsl_pwr_history history[KGSL_PWREVENT_MAX];
};

int kgsl_pwrscale_init(struct device *dev, const char *governor);
@@ -80,5 +101,10 @@ int kgsl_busmon_get_cur_freq(struct device *dev, unsigned long *freq);
			.target = kgsl_busmon_target, \
			.get_dev_status = kgsl_busmon_get_dev_status, \
			.get_cur_freq = kgsl_busmon_get_cur_freq, \
	} } }
	} }, \
	.history[KGSL_PWREVENT_STATE].size = 10, \
	.history[KGSL_PWREVENT_GPU_FREQ].size = 3, \
	.history[KGSL_PWREVENT_BUS_FREQ].size = 5, \
	.history[KGSL_PWREVENT_POPP].size = 5, \
	}
#endif