1 /* $NetBSD: i915_gem_throttle.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $ */ 2 3 /* 4 * SPDX-License-Identifier: MIT 5 * 6 * Copyright 2014-2016 Intel Corporation 7 */ 8 9 #include <sys/cdefs.h> 10 __KERNEL_RCSID(0, "$NetBSD: i915_gem_throttle.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $"); 11 12 #include <linux/jiffies.h> 13 14 #include <drm/drm_file.h> 15 16 #include "i915_drv.h" 17 #include "i915_gem_ioctls.h" 18 #include "i915_gem_object.h" 19 20 /* 21 * 20ms is a fairly arbitrary limit (greater than the average frame time) 22 * chosen to prevent the CPU getting more than a frame ahead of the GPU 23 * (when using lax throttling for the frontbuffer). We also use it to 24 * offer free GPU waitboosts for severely congested workloads. 25 */ 26 #define DRM_I915_THROTTLE_JIFFIES msecs_to_jiffies(20) 27 28 /* 29 * Throttle our rendering by waiting until the ring has completed our requests 30 * emitted over 20 msec ago. 31 * 32 * Note that if we were to use the current jiffies each time around the loop, 33 * we wouldn't escape the function with any frames outstanding if the time to 34 * render a frame was over 20ms. 35 * 36 * This should get us reasonable parallelism between CPU and GPU but also 37 * relatively low latency when blocking on a particular request to finish. 38 */ 39 int 40 i915_gem_throttle_ioctl(struct drm_device *dev, void *data, 41 struct drm_file *file) 42 { 43 struct drm_i915_file_private *file_priv = file->driver_priv; 44 unsigned long recent_enough = jiffies - DRM_I915_THROTTLE_JIFFIES; 45 struct i915_request *request, *target = NULL; 46 long ret; 47 48 /* ABI: return -EIO if already wedged */ 49 ret = intel_gt_terminally_wedged(&to_i915(dev)->gt); 50 if (ret) 51 return ret; 52 53 spin_lock(&file_priv->mm.lock); 54 list_for_each_entry(request, &file_priv->mm.request_list, client_link) { 55 if (time_after_eq(request->emitted_jiffies, recent_enough)) 56 break; 57 58 if (target && xchg(&target->file_priv, NULL)) 59 list_del(&target->client_link); 60 61 target = request; 62 } 63 if (target) 64 i915_request_get(target); 65 spin_unlock(&file_priv->mm.lock); 66 67 if (!target) 68 return 0; 69 70 ret = i915_request_wait(target, 71 I915_WAIT_INTERRUPTIBLE, 72 MAX_SCHEDULE_TIMEOUT); 73 i915_request_put(target); 74 75 return ret < 0 ? ret : 0; 76 } 77