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, ×lice_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, ×lice_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