18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright © 2019 Intel Corporation
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kobject.h>
78c2ecf20Sopenharmony_ci#include <linux/sysfs.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "i915_drv.h"
108c2ecf20Sopenharmony_ci#include "intel_engine.h"
118c2ecf20Sopenharmony_ci#include "intel_engine_heartbeat.h"
128c2ecf20Sopenharmony_ci#include "sysfs_engines.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistruct kobj_engine {
158c2ecf20Sopenharmony_ci	struct kobject base;
168c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine;
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic struct intel_engine_cs *kobj_to_engine(struct kobject *kobj)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	return container_of(kobj, struct kobj_engine, base)->engine;
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic ssize_t
258c2ecf20Sopenharmony_ciname_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", kobj_to_engine(kobj)->name);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic struct kobj_attribute name_attr =
318c2ecf20Sopenharmony_ci__ATTR(name, 0444, name_show, NULL);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic ssize_t
348c2ecf20Sopenharmony_ciclass_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", kobj_to_engine(kobj)->uabi_class);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic struct kobj_attribute class_attr =
408c2ecf20Sopenharmony_ci__ATTR(class, 0444, class_show, NULL);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic ssize_t
438c2ecf20Sopenharmony_ciinst_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", kobj_to_engine(kobj)->uabi_instance);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic struct kobj_attribute inst_attr =
498c2ecf20Sopenharmony_ci__ATTR(instance, 0444, inst_show, NULL);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic ssize_t
528c2ecf20Sopenharmony_cimmio_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%x\n", kobj_to_engine(kobj)->mmio_base);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic struct kobj_attribute mmio_attr =
588c2ecf20Sopenharmony_ci__ATTR(mmio_base, 0444, mmio_show, NULL);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic const char * const vcs_caps[] = {
618c2ecf20Sopenharmony_ci	[ilog2(I915_VIDEO_CLASS_CAPABILITY_HEVC)] = "hevc",
628c2ecf20Sopenharmony_ci	[ilog2(I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC)] = "sfc",
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const char * const vecs_caps[] = {
668c2ecf20Sopenharmony_ci	[ilog2(I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC)] = "sfc",
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic ssize_t repr_trim(char *buf, ssize_t len)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	/* Trim off the trailing space and replace with a newline */
728c2ecf20Sopenharmony_ci	if (len > PAGE_SIZE)
738c2ecf20Sopenharmony_ci		len = PAGE_SIZE;
748c2ecf20Sopenharmony_ci	if (len > 0)
758c2ecf20Sopenharmony_ci		buf[len - 1] = '\n';
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return len;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic ssize_t
818c2ecf20Sopenharmony_ci__caps_show(struct intel_engine_cs *engine,
828c2ecf20Sopenharmony_ci	    u32 caps, char *buf, bool show_unknown)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	const char * const *repr;
858c2ecf20Sopenharmony_ci	int count, n;
868c2ecf20Sopenharmony_ci	ssize_t len;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	BUILD_BUG_ON(!typecheck(typeof(caps), engine->uabi_capabilities));
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	switch (engine->class) {
918c2ecf20Sopenharmony_ci	case VIDEO_DECODE_CLASS:
928c2ecf20Sopenharmony_ci		repr = vcs_caps;
938c2ecf20Sopenharmony_ci		count = ARRAY_SIZE(vcs_caps);
948c2ecf20Sopenharmony_ci		break;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	case VIDEO_ENHANCEMENT_CLASS:
978c2ecf20Sopenharmony_ci		repr = vecs_caps;
988c2ecf20Sopenharmony_ci		count = ARRAY_SIZE(vecs_caps);
998c2ecf20Sopenharmony_ci		break;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	default:
1028c2ecf20Sopenharmony_ci		repr = NULL;
1038c2ecf20Sopenharmony_ci		count = 0;
1048c2ecf20Sopenharmony_ci		break;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci	GEM_BUG_ON(count > BITS_PER_TYPE(typeof(caps)));
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	len = 0;
1098c2ecf20Sopenharmony_ci	for_each_set_bit(n,
1108c2ecf20Sopenharmony_ci			 (unsigned long *)&caps,
1118c2ecf20Sopenharmony_ci			 show_unknown ? BITS_PER_TYPE(typeof(caps)) : count) {
1128c2ecf20Sopenharmony_ci		if (n >= count || !repr[n]) {
1138c2ecf20Sopenharmony_ci			if (GEM_WARN_ON(show_unknown))
1148c2ecf20Sopenharmony_ci				len += snprintf(buf + len, PAGE_SIZE - len,
1158c2ecf20Sopenharmony_ci						"[%x] ", n);
1168c2ecf20Sopenharmony_ci		} else {
1178c2ecf20Sopenharmony_ci			len += snprintf(buf + len, PAGE_SIZE - len,
1188c2ecf20Sopenharmony_ci					"%s ", repr[n]);
1198c2ecf20Sopenharmony_ci		}
1208c2ecf20Sopenharmony_ci		if (GEM_WARN_ON(len >= PAGE_SIZE))
1218c2ecf20Sopenharmony_ci			break;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci	return repr_trim(buf, len);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic ssize_t
1278c2ecf20Sopenharmony_cicaps_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return __caps_show(engine, engine->uabi_capabilities, buf, true);
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct kobj_attribute caps_attr =
1358c2ecf20Sopenharmony_ci__ATTR(capabilities, 0444, caps_show, NULL);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic ssize_t
1388c2ecf20Sopenharmony_ciall_caps_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	return __caps_show(kobj_to_engine(kobj), -1, buf, false);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic struct kobj_attribute all_caps_attr =
1448c2ecf20Sopenharmony_ci__ATTR(known_capabilities, 0444, all_caps_show, NULL);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic ssize_t
1478c2ecf20Sopenharmony_cimax_spin_store(struct kobject *kobj, struct kobj_attribute *attr,
1488c2ecf20Sopenharmony_ci	       const char *buf, size_t count)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
1518c2ecf20Sopenharmony_ci	unsigned long long duration;
1528c2ecf20Sopenharmony_ci	int err;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	 * When waiting for a request, if is it currently being executed
1568c2ecf20Sopenharmony_ci	 * on the GPU, we busywait for a short while before sleeping. The
1578c2ecf20Sopenharmony_ci	 * premise is that most requests are short, and if it is already
1588c2ecf20Sopenharmony_ci	 * executing then there is a good chance that it will complete
1598c2ecf20Sopenharmony_ci	 * before we can setup the interrupt handler and go to sleep.
1608c2ecf20Sopenharmony_ci	 * We try to offset the cost of going to sleep, by first spinning
1618c2ecf20Sopenharmony_ci	 * on the request -- if it completed in less time than it would take
1628c2ecf20Sopenharmony_ci	 * to go sleep, process the interrupt and return back to the client,
1638c2ecf20Sopenharmony_ci	 * then we have saved the client some latency, albeit at the cost
1648c2ecf20Sopenharmony_ci	 * of spinning on an expensive CPU core.
1658c2ecf20Sopenharmony_ci	 *
1668c2ecf20Sopenharmony_ci	 * While we try to avoid waiting at all for a request that is unlikely
1678c2ecf20Sopenharmony_ci	 * to complete, deciding how long it is worth spinning is for is an
1688c2ecf20Sopenharmony_ci	 * arbitrary decision: trading off power vs latency.
1698c2ecf20Sopenharmony_ci	 */
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	err = kstrtoull(buf, 0, &duration);
1728c2ecf20Sopenharmony_ci	if (err)
1738c2ecf20Sopenharmony_ci		return err;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (duration > jiffies_to_nsecs(2))
1768c2ecf20Sopenharmony_ci		return -EINVAL;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	WRITE_ONCE(engine->props.max_busywait_duration_ns, duration);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	return count;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic ssize_t
1848c2ecf20Sopenharmony_cimax_spin_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->props.max_busywait_duration_ns);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic struct kobj_attribute max_spin_attr =
1928c2ecf20Sopenharmony_ci__ATTR(max_busywait_duration_ns, 0644, max_spin_show, max_spin_store);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic ssize_t
1958c2ecf20Sopenharmony_cimax_spin_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->defaults.max_busywait_duration_ns);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic struct kobj_attribute max_spin_def =
2038c2ecf20Sopenharmony_ci__ATTR(max_busywait_duration_ns, 0444, max_spin_default, NULL);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic ssize_t
2068c2ecf20Sopenharmony_citimeslice_store(struct kobject *kobj, struct kobj_attribute *attr,
2078c2ecf20Sopenharmony_ci		const char *buf, size_t count)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
2108c2ecf20Sopenharmony_ci	unsigned long long duration;
2118c2ecf20Sopenharmony_ci	int err;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/*
2148c2ecf20Sopenharmony_ci	 * Execlists uses a scheduling quantum (a timeslice) to alternate
2158c2ecf20Sopenharmony_ci	 * execution between ready-to-run contexts of equal priority. This
2168c2ecf20Sopenharmony_ci	 * ensures that all users (though only if they of equal importance)
2178c2ecf20Sopenharmony_ci	 * have the opportunity to run and prevents livelocks where contexts
2188c2ecf20Sopenharmony_ci	 * may have implicit ordering due to userspace semaphores.
2198c2ecf20Sopenharmony_ci	 */
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	err = kstrtoull(buf, 0, &duration);
2228c2ecf20Sopenharmony_ci	if (err)
2238c2ecf20Sopenharmony_ci		return err;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
2268c2ecf20Sopenharmony_ci		return -EINVAL;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	WRITE_ONCE(engine->props.timeslice_duration_ms, duration);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (execlists_active(&engine->execlists))
2318c2ecf20Sopenharmony_ci		set_timer_ms(&engine->execlists.timer, duration);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return count;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic ssize_t
2378c2ecf20Sopenharmony_citimeslice_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->props.timeslice_duration_ms);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic struct kobj_attribute timeslice_duration_attr =
2458c2ecf20Sopenharmony_ci__ATTR(timeslice_duration_ms, 0644, timeslice_show, timeslice_store);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic ssize_t
2488c2ecf20Sopenharmony_citimeslice_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->defaults.timeslice_duration_ms);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic struct kobj_attribute timeslice_duration_def =
2568c2ecf20Sopenharmony_ci__ATTR(timeslice_duration_ms, 0444, timeslice_default, NULL);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic ssize_t
2598c2ecf20Sopenharmony_cistop_store(struct kobject *kobj, struct kobj_attribute *attr,
2608c2ecf20Sopenharmony_ci	   const char *buf, size_t count)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
2638c2ecf20Sopenharmony_ci	unsigned long long duration;
2648c2ecf20Sopenharmony_ci	int err;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/*
2678c2ecf20Sopenharmony_ci	 * When we allow ourselves to sleep before a GPU reset after disabling
2688c2ecf20Sopenharmony_ci	 * submission, even for a few milliseconds, gives an innocent context
2698c2ecf20Sopenharmony_ci	 * the opportunity to clear the GPU before the reset occurs. However,
2708c2ecf20Sopenharmony_ci	 * how long to sleep depends on the typical non-preemptible duration
2718c2ecf20Sopenharmony_ci	 * (a similar problem to determining the ideal preempt-reset timeout
2728c2ecf20Sopenharmony_ci	 * or even the heartbeat interval).
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	err = kstrtoull(buf, 0, &duration);
2768c2ecf20Sopenharmony_ci	if (err)
2778c2ecf20Sopenharmony_ci		return err;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
2808c2ecf20Sopenharmony_ci		return -EINVAL;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	WRITE_ONCE(engine->props.stop_timeout_ms, duration);
2838c2ecf20Sopenharmony_ci	return count;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic ssize_t
2878c2ecf20Sopenharmony_cistop_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->props.stop_timeout_ms);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic struct kobj_attribute stop_timeout_attr =
2958c2ecf20Sopenharmony_ci__ATTR(stop_timeout_ms, 0644, stop_show, stop_store);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic ssize_t
2988c2ecf20Sopenharmony_cistop_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->defaults.stop_timeout_ms);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic struct kobj_attribute stop_timeout_def =
3068c2ecf20Sopenharmony_ci__ATTR(stop_timeout_ms, 0444, stop_default, NULL);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic ssize_t
3098c2ecf20Sopenharmony_cipreempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr,
3108c2ecf20Sopenharmony_ci		      const char *buf, size_t count)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
3138c2ecf20Sopenharmony_ci	unsigned long long timeout;
3148c2ecf20Sopenharmony_ci	int err;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/*
3178c2ecf20Sopenharmony_ci	 * After initialising a preemption request, we give the current
3188c2ecf20Sopenharmony_ci	 * resident a small amount of time to vacate the GPU. The preemption
3198c2ecf20Sopenharmony_ci	 * request is for a higher priority context and should be immediate to
3208c2ecf20Sopenharmony_ci	 * maintain high quality of service (and avoid priority inversion).
3218c2ecf20Sopenharmony_ci	 * However, the preemption granularity of the GPU can be quite coarse
3228c2ecf20Sopenharmony_ci	 * and so we need a compromise.
3238c2ecf20Sopenharmony_ci	 */
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	err = kstrtoull(buf, 0, &timeout);
3268c2ecf20Sopenharmony_ci	if (err)
3278c2ecf20Sopenharmony_ci		return err;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (timeout > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
3308c2ecf20Sopenharmony_ci		return -EINVAL;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	WRITE_ONCE(engine->props.preempt_timeout_ms, timeout);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (READ_ONCE(engine->execlists.pending[0]))
3358c2ecf20Sopenharmony_ci		set_timer_ms(&engine->execlists.preempt, timeout);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return count;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic ssize_t
3418c2ecf20Sopenharmony_cipreempt_timeout_show(struct kobject *kobj, struct kobj_attribute *attr,
3428c2ecf20Sopenharmony_ci		     char *buf)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->props.preempt_timeout_ms);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic struct kobj_attribute preempt_timeout_attr =
3508c2ecf20Sopenharmony_ci__ATTR(preempt_timeout_ms, 0644, preempt_timeout_show, preempt_timeout_store);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic ssize_t
3538c2ecf20Sopenharmony_cipreempt_timeout_default(struct kobject *kobj, struct kobj_attribute *attr,
3548c2ecf20Sopenharmony_ci			char *buf)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->defaults.preempt_timeout_ms);
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic struct kobj_attribute preempt_timeout_def =
3628c2ecf20Sopenharmony_ci__ATTR(preempt_timeout_ms, 0444, preempt_timeout_default, NULL);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic ssize_t
3658c2ecf20Sopenharmony_ciheartbeat_store(struct kobject *kobj, struct kobj_attribute *attr,
3668c2ecf20Sopenharmony_ci		const char *buf, size_t count)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
3698c2ecf20Sopenharmony_ci	unsigned long long delay;
3708c2ecf20Sopenharmony_ci	int err;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/*
3738c2ecf20Sopenharmony_ci	 * We monitor the health of the system via periodic heartbeat pulses.
3748c2ecf20Sopenharmony_ci	 * The pulses also provide the opportunity to perform garbage
3758c2ecf20Sopenharmony_ci	 * collection.  However, we interpret an incomplete pulse (a missed
3768c2ecf20Sopenharmony_ci	 * heartbeat) as an indication that the system is no longer responsive,
3778c2ecf20Sopenharmony_ci	 * i.e. hung, and perform an engine or full GPU reset. Given that the
3788c2ecf20Sopenharmony_ci	 * preemption granularity can be very coarse on a system, the optimal
3798c2ecf20Sopenharmony_ci	 * value for any workload is unknowable!
3808c2ecf20Sopenharmony_ci	 */
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	err = kstrtoull(buf, 0, &delay);
3838c2ecf20Sopenharmony_ci	if (err)
3848c2ecf20Sopenharmony_ci		return err;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	if (delay >= jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
3878c2ecf20Sopenharmony_ci		return -EINVAL;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	err = intel_engine_set_heartbeat(engine, delay);
3908c2ecf20Sopenharmony_ci	if (err)
3918c2ecf20Sopenharmony_ci		return err;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return count;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic ssize_t
3978c2ecf20Sopenharmony_ciheartbeat_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->props.heartbeat_interval_ms);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic struct kobj_attribute heartbeat_interval_attr =
4058c2ecf20Sopenharmony_ci__ATTR(heartbeat_interval_ms, 0644, heartbeat_show, heartbeat_store);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic ssize_t
4088c2ecf20Sopenharmony_ciheartbeat_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = kobj_to_engine(kobj);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	return sprintf(buf, "%lu\n", engine->defaults.heartbeat_interval_ms);
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic struct kobj_attribute heartbeat_interval_def =
4168c2ecf20Sopenharmony_ci__ATTR(heartbeat_interval_ms, 0444, heartbeat_default, NULL);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic void kobj_engine_release(struct kobject *kobj)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	kfree(kobj);
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic struct kobj_type kobj_engine_type = {
4248c2ecf20Sopenharmony_ci	.release = kobj_engine_release,
4258c2ecf20Sopenharmony_ci	.sysfs_ops = &kobj_sysfs_ops
4268c2ecf20Sopenharmony_ci};
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic struct kobject *
4298c2ecf20Sopenharmony_cikobj_engine(struct kobject *dir, struct intel_engine_cs *engine)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct kobj_engine *ke;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	ke = kzalloc(sizeof(*ke), GFP_KERNEL);
4348c2ecf20Sopenharmony_ci	if (!ke)
4358c2ecf20Sopenharmony_ci		return NULL;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	kobject_init(&ke->base, &kobj_engine_type);
4388c2ecf20Sopenharmony_ci	ke->engine = engine;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (kobject_add(&ke->base, dir, "%s", engine->name)) {
4418c2ecf20Sopenharmony_ci		kobject_put(&ke->base);
4428c2ecf20Sopenharmony_ci		return NULL;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* xfer ownership to sysfs tree */
4468c2ecf20Sopenharmony_ci	return &ke->base;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic void add_defaults(struct kobj_engine *parent)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	static const struct attribute *files[] = {
4528c2ecf20Sopenharmony_ci		&max_spin_def.attr,
4538c2ecf20Sopenharmony_ci		&stop_timeout_def.attr,
4548c2ecf20Sopenharmony_ci#if CONFIG_DRM_I915_HEARTBEAT_INTERVAL
4558c2ecf20Sopenharmony_ci		&heartbeat_interval_def.attr,
4568c2ecf20Sopenharmony_ci#endif
4578c2ecf20Sopenharmony_ci		NULL
4588c2ecf20Sopenharmony_ci	};
4598c2ecf20Sopenharmony_ci	struct kobj_engine *ke;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	ke = kzalloc(sizeof(*ke), GFP_KERNEL);
4628c2ecf20Sopenharmony_ci	if (!ke)
4638c2ecf20Sopenharmony_ci		return;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	kobject_init(&ke->base, &kobj_engine_type);
4668c2ecf20Sopenharmony_ci	ke->engine = parent->engine;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (kobject_add(&ke->base, &parent->base, "%s", ".defaults")) {
4698c2ecf20Sopenharmony_ci		kobject_put(&ke->base);
4708c2ecf20Sopenharmony_ci		return;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (sysfs_create_files(&ke->base, files))
4748c2ecf20Sopenharmony_ci		return;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (intel_engine_has_timeslices(ke->engine) &&
4778c2ecf20Sopenharmony_ci	    sysfs_create_file(&ke->base, &timeslice_duration_def.attr))
4788c2ecf20Sopenharmony_ci		return;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (intel_engine_has_preempt_reset(ke->engine) &&
4818c2ecf20Sopenharmony_ci	    sysfs_create_file(&ke->base, &preempt_timeout_def.attr))
4828c2ecf20Sopenharmony_ci		return;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_civoid intel_engines_add_sysfs(struct drm_i915_private *i915)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	static const struct attribute *files[] = {
4888c2ecf20Sopenharmony_ci		&name_attr.attr,
4898c2ecf20Sopenharmony_ci		&class_attr.attr,
4908c2ecf20Sopenharmony_ci		&inst_attr.attr,
4918c2ecf20Sopenharmony_ci		&mmio_attr.attr,
4928c2ecf20Sopenharmony_ci		&caps_attr.attr,
4938c2ecf20Sopenharmony_ci		&all_caps_attr.attr,
4948c2ecf20Sopenharmony_ci		&max_spin_attr.attr,
4958c2ecf20Sopenharmony_ci		&stop_timeout_attr.attr,
4968c2ecf20Sopenharmony_ci#if CONFIG_DRM_I915_HEARTBEAT_INTERVAL
4978c2ecf20Sopenharmony_ci		&heartbeat_interval_attr.attr,
4988c2ecf20Sopenharmony_ci#endif
4998c2ecf20Sopenharmony_ci		NULL
5008c2ecf20Sopenharmony_ci	};
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	struct device *kdev = i915->drm.primary->kdev;
5038c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine;
5048c2ecf20Sopenharmony_ci	struct kobject *dir;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	dir = kobject_create_and_add("engine", &kdev->kobj);
5078c2ecf20Sopenharmony_ci	if (!dir)
5088c2ecf20Sopenharmony_ci		return;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	for_each_uabi_engine(engine, i915) {
5118c2ecf20Sopenharmony_ci		struct kobject *kobj;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		kobj = kobj_engine(dir, engine);
5148c2ecf20Sopenharmony_ci		if (!kobj)
5158c2ecf20Sopenharmony_ci			goto err_engine;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		if (sysfs_create_files(kobj, files))
5188c2ecf20Sopenharmony_ci			goto err_object;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		if (intel_engine_has_timeslices(engine) &&
5218c2ecf20Sopenharmony_ci		    sysfs_create_file(kobj, &timeslice_duration_attr.attr))
5228c2ecf20Sopenharmony_ci			goto err_engine;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci		if (intel_engine_has_preempt_reset(engine) &&
5258c2ecf20Sopenharmony_ci		    sysfs_create_file(kobj, &preempt_timeout_attr.attr))
5268c2ecf20Sopenharmony_ci			goto err_engine;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		add_defaults(container_of(kobj, struct kobj_engine, base));
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci		if (0) {
5318c2ecf20Sopenharmony_cierr_object:
5328c2ecf20Sopenharmony_ci			kobject_put(kobj);
5338c2ecf20Sopenharmony_cierr_engine:
5348c2ecf20Sopenharmony_ci			dev_err(kdev, "Failed to add sysfs engine '%s'\n",
5358c2ecf20Sopenharmony_ci				engine->name);
5368c2ecf20Sopenharmony_ci			break;
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci}
540