14ec76dbeSChris Wilson // SPDX-License-Identifier: MIT
24ec76dbeSChris Wilson /*
34ec76dbeSChris Wilson * Copyright © 2019 Intel Corporation
44ec76dbeSChris Wilson */
54ec76dbeSChris Wilson
64ec76dbeSChris Wilson #include <linux/kobject.h>
74ec76dbeSChris Wilson #include <linux/sysfs.h>
84ec76dbeSChris Wilson
94ec76dbeSChris Wilson #include "i915_drv.h"
104ec76dbeSChris Wilson #include "intel_engine.h"
119a40bdddSChris Wilson #include "intel_engine_heartbeat.h"
124ec76dbeSChris Wilson #include "sysfs_engines.h"
134ec76dbeSChris Wilson
144ec76dbeSChris Wilson struct kobj_engine {
154ec76dbeSChris Wilson struct kobject base;
164ec76dbeSChris Wilson struct intel_engine_cs *engine;
174ec76dbeSChris Wilson };
184ec76dbeSChris Wilson
kobj_to_engine(struct kobject * kobj)194ec76dbeSChris Wilson static struct intel_engine_cs *kobj_to_engine(struct kobject *kobj)
204ec76dbeSChris Wilson {
214ec76dbeSChris Wilson return container_of(kobj, struct kobj_engine, base)->engine;
224ec76dbeSChris Wilson }
234ec76dbeSChris Wilson
244ec76dbeSChris Wilson static ssize_t
name_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)254ec76dbeSChris Wilson name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
264ec76dbeSChris Wilson {
271f16fdbbSNirmoy Das return sysfs_emit(buf, "%s\n", kobj_to_engine(kobj)->name);
284ec76dbeSChris Wilson }
294ec76dbeSChris Wilson
30*d2a9692aSJani Nikula static const struct kobj_attribute name_attr =
314ec76dbeSChris Wilson __ATTR(name, 0444, name_show, NULL);
324ec76dbeSChris Wilson
334ec76dbeSChris Wilson static ssize_t
class_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)344ec76dbeSChris Wilson class_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
354ec76dbeSChris Wilson {
361f16fdbbSNirmoy Das return sysfs_emit(buf, "%d\n", kobj_to_engine(kobj)->uabi_class);
374ec76dbeSChris Wilson }
384ec76dbeSChris Wilson
39*d2a9692aSJani Nikula static const struct kobj_attribute class_attr =
404ec76dbeSChris Wilson __ATTR(class, 0444, class_show, NULL);
414ec76dbeSChris Wilson
424ec76dbeSChris Wilson static ssize_t
inst_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)434ec76dbeSChris Wilson inst_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
444ec76dbeSChris Wilson {
451f16fdbbSNirmoy Das return sysfs_emit(buf, "%d\n", kobj_to_engine(kobj)->uabi_instance);
464ec76dbeSChris Wilson }
474ec76dbeSChris Wilson
48*d2a9692aSJani Nikula static const struct kobj_attribute inst_attr =
494ec76dbeSChris Wilson __ATTR(instance, 0444, inst_show, NULL);
504ec76dbeSChris Wilson
516e57cc39SChris Wilson static ssize_t
mmio_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)526e57cc39SChris Wilson mmio_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
536e57cc39SChris Wilson {
541f16fdbbSNirmoy Das return sysfs_emit(buf, "0x%x\n", kobj_to_engine(kobj)->mmio_base);
556e57cc39SChris Wilson }
566e57cc39SChris Wilson
57*d2a9692aSJani Nikula static const struct kobj_attribute mmio_attr =
586e57cc39SChris Wilson __ATTR(mmio_base, 0444, mmio_show, NULL);
596e57cc39SChris Wilson
604ec76dbeSChris Wilson static const char * const vcs_caps[] = {
614ec76dbeSChris Wilson [ilog2(I915_VIDEO_CLASS_CAPABILITY_HEVC)] = "hevc",
624ec76dbeSChris Wilson [ilog2(I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC)] = "sfc",
634ec76dbeSChris Wilson };
644ec76dbeSChris Wilson
654ec76dbeSChris Wilson static const char * const vecs_caps[] = {
664ec76dbeSChris Wilson [ilog2(I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC)] = "sfc",
674ec76dbeSChris Wilson };
684ec76dbeSChris Wilson
repr_trim(char * buf,ssize_t len)694ec76dbeSChris Wilson static ssize_t repr_trim(char *buf, ssize_t len)
704ec76dbeSChris Wilson {
714ec76dbeSChris Wilson /* Trim off the trailing space and replace with a newline */
724ec76dbeSChris Wilson if (len > PAGE_SIZE)
734ec76dbeSChris Wilson len = PAGE_SIZE;
744ec76dbeSChris Wilson if (len > 0)
754ec76dbeSChris Wilson buf[len - 1] = '\n';
764ec76dbeSChris Wilson
774ec76dbeSChris Wilson return len;
784ec76dbeSChris Wilson }
794ec76dbeSChris Wilson
804ec76dbeSChris Wilson static ssize_t
__caps_show(struct intel_engine_cs * engine,unsigned long caps,char * buf,bool show_unknown)814ec76dbeSChris Wilson __caps_show(struct intel_engine_cs *engine,
826971e07bSChris Wilson unsigned long caps, char *buf, bool show_unknown)
834ec76dbeSChris Wilson {
844ec76dbeSChris Wilson const char * const *repr;
854ec76dbeSChris Wilson int count, n;
864ec76dbeSChris Wilson ssize_t len;
874ec76dbeSChris Wilson
884ec76dbeSChris Wilson switch (engine->class) {
894ec76dbeSChris Wilson case VIDEO_DECODE_CLASS:
904ec76dbeSChris Wilson repr = vcs_caps;
914ec76dbeSChris Wilson count = ARRAY_SIZE(vcs_caps);
924ec76dbeSChris Wilson break;
934ec76dbeSChris Wilson
944ec76dbeSChris Wilson case VIDEO_ENHANCEMENT_CLASS:
954ec76dbeSChris Wilson repr = vecs_caps;
964ec76dbeSChris Wilson count = ARRAY_SIZE(vecs_caps);
974ec76dbeSChris Wilson break;
984ec76dbeSChris Wilson
994ec76dbeSChris Wilson default:
1004ec76dbeSChris Wilson repr = NULL;
1014ec76dbeSChris Wilson count = 0;
1024ec76dbeSChris Wilson break;
1034ec76dbeSChris Wilson }
1046971e07bSChris Wilson GEM_BUG_ON(count > BITS_PER_LONG);
1054ec76dbeSChris Wilson
1064ec76dbeSChris Wilson len = 0;
1076971e07bSChris Wilson for_each_set_bit(n, &caps, show_unknown ? BITS_PER_LONG : count) {
1084ec76dbeSChris Wilson if (n >= count || !repr[n]) {
1094ec76dbeSChris Wilson if (GEM_WARN_ON(show_unknown))
1101f16fdbbSNirmoy Das len += sysfs_emit_at(buf, len, "[%x] ", n);
1114ec76dbeSChris Wilson } else {
1121f16fdbbSNirmoy Das len += sysfs_emit_at(buf, len, "%s ", repr[n]);
1134ec76dbeSChris Wilson }
1144ec76dbeSChris Wilson if (GEM_WARN_ON(len >= PAGE_SIZE))
1154ec76dbeSChris Wilson break;
1164ec76dbeSChris Wilson }
1174ec76dbeSChris Wilson return repr_trim(buf, len);
1184ec76dbeSChris Wilson }
1194ec76dbeSChris Wilson
1204ec76dbeSChris Wilson static ssize_t
caps_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1214ec76dbeSChris Wilson caps_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1224ec76dbeSChris Wilson {
1234ec76dbeSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
1244ec76dbeSChris Wilson
1254ec76dbeSChris Wilson return __caps_show(engine, engine->uabi_capabilities, buf, true);
1264ec76dbeSChris Wilson }
1274ec76dbeSChris Wilson
128*d2a9692aSJani Nikula static const struct kobj_attribute caps_attr =
1294ec76dbeSChris Wilson __ATTR(capabilities, 0444, caps_show, NULL);
1304ec76dbeSChris Wilson
1314ec76dbeSChris Wilson static ssize_t
all_caps_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1324ec76dbeSChris Wilson all_caps_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1334ec76dbeSChris Wilson {
1344ec76dbeSChris Wilson return __caps_show(kobj_to_engine(kobj), -1, buf, false);
1354ec76dbeSChris Wilson }
1364ec76dbeSChris Wilson
137*d2a9692aSJani Nikula static const struct kobj_attribute all_caps_attr =
1384ec76dbeSChris Wilson __ATTR(known_capabilities, 0444, all_caps_show, NULL);
1394ec76dbeSChris Wilson
1401a2695a7SChris Wilson static ssize_t
max_spin_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)141062444bbSChris Wilson max_spin_store(struct kobject *kobj, struct kobj_attribute *attr,
142062444bbSChris Wilson const char *buf, size_t count)
143062444bbSChris Wilson {
144062444bbSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
145568944afSJohn Harrison unsigned long long duration, clamped;
146062444bbSChris Wilson int err;
147062444bbSChris Wilson
148062444bbSChris Wilson /*
149062444bbSChris Wilson * When waiting for a request, if is it currently being executed
150062444bbSChris Wilson * on the GPU, we busywait for a short while before sleeping. The
151062444bbSChris Wilson * premise is that most requests are short, and if it is already
152062444bbSChris Wilson * executing then there is a good chance that it will complete
153062444bbSChris Wilson * before we can setup the interrupt handler and go to sleep.
154062444bbSChris Wilson * We try to offset the cost of going to sleep, by first spinning
155062444bbSChris Wilson * on the request -- if it completed in less time than it would take
156062444bbSChris Wilson * to go sleep, process the interrupt and return back to the client,
157062444bbSChris Wilson * then we have saved the client some latency, albeit at the cost
158062444bbSChris Wilson * of spinning on an expensive CPU core.
159062444bbSChris Wilson *
160062444bbSChris Wilson * While we try to avoid waiting at all for a request that is unlikely
161062444bbSChris Wilson * to complete, deciding how long it is worth spinning is for is an
162062444bbSChris Wilson * arbitrary decision: trading off power vs latency.
163062444bbSChris Wilson */
164062444bbSChris Wilson
165062444bbSChris Wilson err = kstrtoull(buf, 0, &duration);
166062444bbSChris Wilson if (err)
167062444bbSChris Wilson return err;
168062444bbSChris Wilson
169568944afSJohn Harrison clamped = intel_clamp_max_busywait_duration_ns(engine, duration);
170568944afSJohn Harrison if (duration != clamped)
171062444bbSChris Wilson return -EINVAL;
172062444bbSChris Wilson
173062444bbSChris Wilson WRITE_ONCE(engine->props.max_busywait_duration_ns, duration);
174062444bbSChris Wilson
175062444bbSChris Wilson return count;
176062444bbSChris Wilson }
177062444bbSChris Wilson
178062444bbSChris Wilson static ssize_t
max_spin_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)179062444bbSChris Wilson max_spin_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
180062444bbSChris Wilson {
181062444bbSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
182062444bbSChris Wilson
1831f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->props.max_busywait_duration_ns);
184062444bbSChris Wilson }
185062444bbSChris Wilson
186*d2a9692aSJani Nikula static const struct kobj_attribute max_spin_attr =
187062444bbSChris Wilson __ATTR(max_busywait_duration_ns, 0644, max_spin_show, max_spin_store);
188062444bbSChris Wilson
189062444bbSChris Wilson static ssize_t
max_spin_default(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1907a0ba6b4SChris Wilson max_spin_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1917a0ba6b4SChris Wilson {
1927a0ba6b4SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
1937a0ba6b4SChris Wilson
1941f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->defaults.max_busywait_duration_ns);
1957a0ba6b4SChris Wilson }
1967a0ba6b4SChris Wilson
197*d2a9692aSJani Nikula static const struct kobj_attribute max_spin_def =
1987a0ba6b4SChris Wilson __ATTR(max_busywait_duration_ns, 0444, max_spin_default, NULL);
1997a0ba6b4SChris Wilson
2007a0ba6b4SChris Wilson static ssize_t
timeslice_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)2011a2695a7SChris Wilson timeslice_store(struct kobject *kobj, struct kobj_attribute *attr,
2021a2695a7SChris Wilson const char *buf, size_t count)
2031a2695a7SChris Wilson {
2041a2695a7SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
205568944afSJohn Harrison unsigned long long duration, clamped;
2061a2695a7SChris Wilson int err;
2071a2695a7SChris Wilson
2081a2695a7SChris Wilson /*
2091a2695a7SChris Wilson * Execlists uses a scheduling quantum (a timeslice) to alternate
2101a2695a7SChris Wilson * execution between ready-to-run contexts of equal priority. This
2111a2695a7SChris Wilson * ensures that all users (though only if they of equal importance)
2121a2695a7SChris Wilson * have the opportunity to run and prevents livelocks where contexts
2131a2695a7SChris Wilson * may have implicit ordering due to userspace semaphores.
2141a2695a7SChris Wilson */
2151a2695a7SChris Wilson
2161a2695a7SChris Wilson err = kstrtoull(buf, 0, &duration);
2171a2695a7SChris Wilson if (err)
2181a2695a7SChris Wilson return err;
2191a2695a7SChris Wilson
220568944afSJohn Harrison clamped = intel_clamp_timeslice_duration_ms(engine, duration);
221568944afSJohn Harrison if (duration != clamped)
2221a2695a7SChris Wilson return -EINVAL;
2231a2695a7SChris Wilson
2241a2695a7SChris Wilson WRITE_ONCE(engine->props.timeslice_duration_ms, duration);
2251a2695a7SChris Wilson
2261a2695a7SChris Wilson if (execlists_active(&engine->execlists))
2271a2695a7SChris Wilson set_timer_ms(&engine->execlists.timer, duration);
2281a2695a7SChris Wilson
2291a2695a7SChris Wilson return count;
2301a2695a7SChris Wilson }
2311a2695a7SChris Wilson
2321a2695a7SChris Wilson static ssize_t
timeslice_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)2331a2695a7SChris Wilson timeslice_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
2341a2695a7SChris Wilson {
2351a2695a7SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
2361a2695a7SChris Wilson
2371f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->props.timeslice_duration_ms);
2381a2695a7SChris Wilson }
2391a2695a7SChris Wilson
240*d2a9692aSJani Nikula static const struct kobj_attribute timeslice_duration_attr =
2411a2695a7SChris Wilson __ATTR(timeslice_duration_ms, 0644, timeslice_show, timeslice_store);
2421a2695a7SChris Wilson
24372338a1fSChris Wilson static ssize_t
timeslice_default(struct kobject * kobj,struct kobj_attribute * attr,char * buf)2447a0ba6b4SChris Wilson timeslice_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
2457a0ba6b4SChris Wilson {
2467a0ba6b4SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
2477a0ba6b4SChris Wilson
2481f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->defaults.timeslice_duration_ms);
2497a0ba6b4SChris Wilson }
2507a0ba6b4SChris Wilson
251*d2a9692aSJani Nikula static const struct kobj_attribute timeslice_duration_def =
2527a0ba6b4SChris Wilson __ATTR(timeslice_duration_ms, 0444, timeslice_default, NULL);
2537a0ba6b4SChris Wilson
2547a0ba6b4SChris Wilson static ssize_t
stop_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)25572338a1fSChris Wilson stop_store(struct kobject *kobj, struct kobj_attribute *attr,
25672338a1fSChris Wilson const char *buf, size_t count)
25772338a1fSChris Wilson {
25872338a1fSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
259568944afSJohn Harrison unsigned long long duration, clamped;
26072338a1fSChris Wilson int err;
26172338a1fSChris Wilson
26272338a1fSChris Wilson /*
26372338a1fSChris Wilson * When we allow ourselves to sleep before a GPU reset after disabling
26472338a1fSChris Wilson * submission, even for a few milliseconds, gives an innocent context
26572338a1fSChris Wilson * the opportunity to clear the GPU before the reset occurs. However,
26672338a1fSChris Wilson * how long to sleep depends on the typical non-preemptible duration
26772338a1fSChris Wilson * (a similar problem to determining the ideal preempt-reset timeout
26872338a1fSChris Wilson * or even the heartbeat interval).
26972338a1fSChris Wilson */
27072338a1fSChris Wilson
27172338a1fSChris Wilson err = kstrtoull(buf, 0, &duration);
27272338a1fSChris Wilson if (err)
27372338a1fSChris Wilson return err;
27472338a1fSChris Wilson
275568944afSJohn Harrison clamped = intel_clamp_stop_timeout_ms(engine, duration);
276568944afSJohn Harrison if (duration != clamped)
27772338a1fSChris Wilson return -EINVAL;
27872338a1fSChris Wilson
27972338a1fSChris Wilson WRITE_ONCE(engine->props.stop_timeout_ms, duration);
28072338a1fSChris Wilson return count;
28172338a1fSChris Wilson }
28272338a1fSChris Wilson
28372338a1fSChris Wilson static ssize_t
stop_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)28472338a1fSChris Wilson stop_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
28572338a1fSChris Wilson {
28672338a1fSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
28772338a1fSChris Wilson
2881f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->props.stop_timeout_ms);
28972338a1fSChris Wilson }
29072338a1fSChris Wilson
291*d2a9692aSJani Nikula static const struct kobj_attribute stop_timeout_attr =
29272338a1fSChris Wilson __ATTR(stop_timeout_ms, 0644, stop_show, stop_store);
29372338a1fSChris Wilson
294db3d8338SChris Wilson static ssize_t
stop_default(struct kobject * kobj,struct kobj_attribute * attr,char * buf)2957a0ba6b4SChris Wilson stop_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
2967a0ba6b4SChris Wilson {
2977a0ba6b4SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
2987a0ba6b4SChris Wilson
2991f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->defaults.stop_timeout_ms);
3007a0ba6b4SChris Wilson }
3017a0ba6b4SChris Wilson
302*d2a9692aSJani Nikula static const struct kobj_attribute stop_timeout_def =
3037a0ba6b4SChris Wilson __ATTR(stop_timeout_ms, 0444, stop_default, NULL);
3047a0ba6b4SChris Wilson
3057a0ba6b4SChris Wilson static ssize_t
preempt_timeout_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)306db3d8338SChris Wilson preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr,
307db3d8338SChris Wilson const char *buf, size_t count)
308db3d8338SChris Wilson {
309db3d8338SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
310568944afSJohn Harrison unsigned long long timeout, clamped;
311db3d8338SChris Wilson int err;
312db3d8338SChris Wilson
313db3d8338SChris Wilson /*
314db3d8338SChris Wilson * After initialising a preemption request, we give the current
315db3d8338SChris Wilson * resident a small amount of time to vacate the GPU. The preemption
316db3d8338SChris Wilson * request is for a higher priority context and should be immediate to
317db3d8338SChris Wilson * maintain high quality of service (and avoid priority inversion).
318db3d8338SChris Wilson * However, the preemption granularity of the GPU can be quite coarse
319db3d8338SChris Wilson * and so we need a compromise.
320db3d8338SChris Wilson */
321db3d8338SChris Wilson
322db3d8338SChris Wilson err = kstrtoull(buf, 0, &timeout);
323db3d8338SChris Wilson if (err)
324db3d8338SChris Wilson return err;
325db3d8338SChris Wilson
326568944afSJohn Harrison clamped = intel_clamp_preempt_timeout_ms(engine, timeout);
327568944afSJohn Harrison if (timeout != clamped)
328db3d8338SChris Wilson return -EINVAL;
329db3d8338SChris Wilson
330db3d8338SChris Wilson WRITE_ONCE(engine->props.preempt_timeout_ms, timeout);
331db3d8338SChris Wilson
332db3d8338SChris Wilson if (READ_ONCE(engine->execlists.pending[0]))
333db3d8338SChris Wilson set_timer_ms(&engine->execlists.preempt, timeout);
334db3d8338SChris Wilson
335db3d8338SChris Wilson return count;
336db3d8338SChris Wilson }
337db3d8338SChris Wilson
338db3d8338SChris Wilson static ssize_t
preempt_timeout_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)339db3d8338SChris Wilson preempt_timeout_show(struct kobject *kobj, struct kobj_attribute *attr,
340db3d8338SChris Wilson char *buf)
341db3d8338SChris Wilson {
342db3d8338SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
343db3d8338SChris Wilson
3441f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->props.preempt_timeout_ms);
345db3d8338SChris Wilson }
346db3d8338SChris Wilson
347*d2a9692aSJani Nikula static const struct kobj_attribute preempt_timeout_attr =
348db3d8338SChris Wilson __ATTR(preempt_timeout_ms, 0644, preempt_timeout_show, preempt_timeout_store);
349db3d8338SChris Wilson
3509a40bdddSChris Wilson static ssize_t
preempt_timeout_default(struct kobject * kobj,struct kobj_attribute * attr,char * buf)3517a0ba6b4SChris Wilson preempt_timeout_default(struct kobject *kobj, struct kobj_attribute *attr,
3527a0ba6b4SChris Wilson char *buf)
3537a0ba6b4SChris Wilson {
3547a0ba6b4SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
3557a0ba6b4SChris Wilson
3561f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->defaults.preempt_timeout_ms);
3577a0ba6b4SChris Wilson }
3587a0ba6b4SChris Wilson
359*d2a9692aSJani Nikula static const struct kobj_attribute preempt_timeout_def =
3607a0ba6b4SChris Wilson __ATTR(preempt_timeout_ms, 0444, preempt_timeout_default, NULL);
3617a0ba6b4SChris Wilson
3627a0ba6b4SChris Wilson static ssize_t
heartbeat_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)3639a40bdddSChris Wilson heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr,
3649a40bdddSChris Wilson const char *buf, size_t count)
3659a40bdddSChris Wilson {
3669a40bdddSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
367568944afSJohn Harrison unsigned long long delay, clamped;
3689a40bdddSChris Wilson int err;
3699a40bdddSChris Wilson
3709a40bdddSChris Wilson /*
3719a40bdddSChris Wilson * We monitor the health of the system via periodic heartbeat pulses.
3729a40bdddSChris Wilson * The pulses also provide the opportunity to perform garbage
3739a40bdddSChris Wilson * collection. However, we interpret an incomplete pulse (a missed
3749a40bdddSChris Wilson * heartbeat) as an indication that the system is no longer responsive,
3759a40bdddSChris Wilson * i.e. hung, and perform an engine or full GPU reset. Given that the
3769a40bdddSChris Wilson * preemption granularity can be very coarse on a system, the optimal
3779a40bdddSChris Wilson * value for any workload is unknowable!
3789a40bdddSChris Wilson */
3799a40bdddSChris Wilson
3809a40bdddSChris Wilson err = kstrtoull(buf, 0, &delay);
3819a40bdddSChris Wilson if (err)
3829a40bdddSChris Wilson return err;
3839a40bdddSChris Wilson
384568944afSJohn Harrison clamped = intel_clamp_heartbeat_interval_ms(engine, delay);
385568944afSJohn Harrison if (delay != clamped)
3869a40bdddSChris Wilson return -EINVAL;
3879a40bdddSChris Wilson
3889a40bdddSChris Wilson err = intel_engine_set_heartbeat(engine, delay);
3899a40bdddSChris Wilson if (err)
3909a40bdddSChris Wilson return err;
3919a40bdddSChris Wilson
3929a40bdddSChris Wilson return count;
3939a40bdddSChris Wilson }
3949a40bdddSChris Wilson
3959a40bdddSChris Wilson static ssize_t
heartbeat_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)3969a40bdddSChris Wilson heartbeat_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
3979a40bdddSChris Wilson {
3989a40bdddSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
3999a40bdddSChris Wilson
4001f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->props.heartbeat_interval_ms);
4019a40bdddSChris Wilson }
4029a40bdddSChris Wilson
403*d2a9692aSJani Nikula static const struct kobj_attribute heartbeat_interval_attr =
4049a40bdddSChris Wilson __ATTR(heartbeat_interval_ms, 0644, heartbeat_show, heartbeat_store);
4059a40bdddSChris Wilson
4067a0ba6b4SChris Wilson static ssize_t
heartbeat_default(struct kobject * kobj,struct kobj_attribute * attr,char * buf)4077a0ba6b4SChris Wilson heartbeat_default(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
4087a0ba6b4SChris Wilson {
4097a0ba6b4SChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj);
4107a0ba6b4SChris Wilson
4111f16fdbbSNirmoy Das return sysfs_emit(buf, "%lu\n", engine->defaults.heartbeat_interval_ms);
4127a0ba6b4SChris Wilson }
4137a0ba6b4SChris Wilson
414*d2a9692aSJani Nikula static const struct kobj_attribute heartbeat_interval_def =
4157a0ba6b4SChris Wilson __ATTR(heartbeat_interval_ms, 0444, heartbeat_default, NULL);
4167a0ba6b4SChris Wilson
kobj_engine_release(struct kobject * kobj)4174ec76dbeSChris Wilson static void kobj_engine_release(struct kobject *kobj)
4184ec76dbeSChris Wilson {
4194ec76dbeSChris Wilson kfree(kobj);
4204ec76dbeSChris Wilson }
4214ec76dbeSChris Wilson
42201361096SThomas Weißschuh static const struct kobj_type kobj_engine_type = {
4234ec76dbeSChris Wilson .release = kobj_engine_release,
4244ec76dbeSChris Wilson .sysfs_ops = &kobj_sysfs_ops
4254ec76dbeSChris Wilson };
4264ec76dbeSChris Wilson
4274ec76dbeSChris Wilson static struct kobject *
kobj_engine(struct kobject * dir,struct intel_engine_cs * engine)4284ec76dbeSChris Wilson kobj_engine(struct kobject *dir, struct intel_engine_cs *engine)
4294ec76dbeSChris Wilson {
4304ec76dbeSChris Wilson struct kobj_engine *ke;
4314ec76dbeSChris Wilson
4324ec76dbeSChris Wilson ke = kzalloc(sizeof(*ke), GFP_KERNEL);
4334ec76dbeSChris Wilson if (!ke)
4344ec76dbeSChris Wilson return NULL;
4354ec76dbeSChris Wilson
4364ec76dbeSChris Wilson kobject_init(&ke->base, &kobj_engine_type);
4374ec76dbeSChris Wilson ke->engine = engine;
4384ec76dbeSChris Wilson
4394ec76dbeSChris Wilson if (kobject_add(&ke->base, dir, "%s", engine->name)) {
4404ec76dbeSChris Wilson kobject_put(&ke->base);
4414ec76dbeSChris Wilson return NULL;
4424ec76dbeSChris Wilson }
4434ec76dbeSChris Wilson
4444ec76dbeSChris Wilson /* xfer ownership to sysfs tree */
4454ec76dbeSChris Wilson return &ke->base;
4464ec76dbeSChris Wilson }
4474ec76dbeSChris Wilson
add_defaults(struct kobj_engine * parent)4487a0ba6b4SChris Wilson static void add_defaults(struct kobj_engine *parent)
4497a0ba6b4SChris Wilson {
450*d2a9692aSJani Nikula static const struct attribute * const files[] = {
4517a0ba6b4SChris Wilson &max_spin_def.attr,
4527a0ba6b4SChris Wilson &stop_timeout_def.attr,
4537a0ba6b4SChris Wilson #if CONFIG_DRM_I915_HEARTBEAT_INTERVAL
4547a0ba6b4SChris Wilson &heartbeat_interval_def.attr,
4557a0ba6b4SChris Wilson #endif
4567a0ba6b4SChris Wilson NULL
4577a0ba6b4SChris Wilson };
4587a0ba6b4SChris Wilson struct kobj_engine *ke;
4597a0ba6b4SChris Wilson
4607a0ba6b4SChris Wilson ke = kzalloc(sizeof(*ke), GFP_KERNEL);
4617a0ba6b4SChris Wilson if (!ke)
4627a0ba6b4SChris Wilson return;
4637a0ba6b4SChris Wilson
4647a0ba6b4SChris Wilson kobject_init(&ke->base, &kobj_engine_type);
4657a0ba6b4SChris Wilson ke->engine = parent->engine;
4667a0ba6b4SChris Wilson
4677a0ba6b4SChris Wilson if (kobject_add(&ke->base, &parent->base, "%s", ".defaults")) {
4687a0ba6b4SChris Wilson kobject_put(&ke->base);
4697a0ba6b4SChris Wilson return;
4707a0ba6b4SChris Wilson }
4717a0ba6b4SChris Wilson
4727a0ba6b4SChris Wilson if (sysfs_create_files(&ke->base, files))
4737a0ba6b4SChris Wilson return;
4747a0ba6b4SChris Wilson
4757a0ba6b4SChris Wilson if (intel_engine_has_timeslices(ke->engine) &&
4767a0ba6b4SChris Wilson sysfs_create_file(&ke->base, ×lice_duration_def.attr))
4777a0ba6b4SChris Wilson return;
4787a0ba6b4SChris Wilson
4797a0ba6b4SChris Wilson if (intel_engine_has_preempt_reset(ke->engine) &&
4807a0ba6b4SChris Wilson sysfs_create_file(&ke->base, &preempt_timeout_def.attr))
4817a0ba6b4SChris Wilson return;
4827a0ba6b4SChris Wilson }
4837a0ba6b4SChris Wilson
intel_engines_add_sysfs(struct drm_i915_private * i915)4844ec76dbeSChris Wilson void intel_engines_add_sysfs(struct drm_i915_private *i915)
4854ec76dbeSChris Wilson {
486*d2a9692aSJani Nikula static const struct attribute * const files[] = {
4874ec76dbeSChris Wilson &name_attr.attr,
4884ec76dbeSChris Wilson &class_attr.attr,
4894ec76dbeSChris Wilson &inst_attr.attr,
4906e57cc39SChris Wilson &mmio_attr.attr,
4914ec76dbeSChris Wilson &caps_attr.attr,
4924ec76dbeSChris Wilson &all_caps_attr.attr,
493062444bbSChris Wilson &max_spin_attr.attr,
49472338a1fSChris Wilson &stop_timeout_attr.attr,
4959a40bdddSChris Wilson #if CONFIG_DRM_I915_HEARTBEAT_INTERVAL
4969a40bdddSChris Wilson &heartbeat_interval_attr.attr,
4979a40bdddSChris Wilson #endif
4984ec76dbeSChris Wilson NULL
4994ec76dbeSChris Wilson };
5004ec76dbeSChris Wilson
5014ec76dbeSChris Wilson struct device *kdev = i915->drm.primary->kdev;
5024ec76dbeSChris Wilson struct intel_engine_cs *engine;
5034ec76dbeSChris Wilson struct kobject *dir;
5044ec76dbeSChris Wilson
5054ec76dbeSChris Wilson dir = kobject_create_and_add("engine", &kdev->kobj);
5064ec76dbeSChris Wilson if (!dir)
5074ec76dbeSChris Wilson return;
5084ec76dbeSChris Wilson
5094ec76dbeSChris Wilson for_each_uabi_engine(engine, i915) {
5104ec76dbeSChris Wilson struct kobject *kobj;
5114ec76dbeSChris Wilson
5124ec76dbeSChris Wilson kobj = kobj_engine(dir, engine);
5134ec76dbeSChris Wilson if (!kobj)
5144ec76dbeSChris Wilson goto err_engine;
5154ec76dbeSChris Wilson
5164ec76dbeSChris Wilson if (sysfs_create_files(kobj, files))
5174ec76dbeSChris Wilson goto err_object;
5184ec76dbeSChris Wilson
5191a2695a7SChris Wilson if (intel_engine_has_timeslices(engine) &&
5201a2695a7SChris Wilson sysfs_create_file(kobj, ×lice_duration_attr.attr))
5211a2695a7SChris Wilson goto err_engine;
5221a2695a7SChris Wilson
523db3d8338SChris Wilson if (intel_engine_has_preempt_reset(engine) &&
524db3d8338SChris Wilson sysfs_create_file(kobj, &preempt_timeout_attr.attr))
525db3d8338SChris Wilson goto err_engine;
526db3d8338SChris Wilson
5277a0ba6b4SChris Wilson add_defaults(container_of(kobj, struct kobj_engine, base));
5287a0ba6b4SChris Wilson
5294ec76dbeSChris Wilson if (0) {
5304ec76dbeSChris Wilson err_object:
5314ec76dbeSChris Wilson kobject_put(kobj);
5324ec76dbeSChris Wilson err_engine:
5334ec76dbeSChris Wilson dev_err(kdev, "Failed to add sysfs engine '%s'\n",
5344ec76dbeSChris Wilson engine->name);
5354ec76dbeSChris Wilson break;
5364ec76dbeSChris Wilson }
5374ec76dbeSChris Wilson }
5384ec76dbeSChris Wilson }
539