diff options
author | Jonathan Gray <jsg@jsg.id.au> | 2013-03-05 21:33:18 +1100 |
---|---|---|
committer | Jonathan Gray <jsg@jsg.id.au> | 2013-03-05 21:33:18 +1100 |
commit | b01644984518c8ad617faedab6240d870194b7a3 (patch) | |
tree | 9b7c3a9c588f8d90541d1cb7b39291778965c7f4 | |
parent | 85ef5c9012ed11ea9bb73d0666d76b21a6bc1fc5 (diff) |
unstub the ring throttle ioctl
-rw-r--r-- | sys/dev/pci/drm/drmP.h | 3 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_dma.c | 26 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_drv.c | 2 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_drv.h | 16 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_gem.c | 119 |
5 files changed, 157 insertions, 9 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h index f0318e04db5..cb4796ec8eb 100644 --- a/sys/dev/pci/drm/drmP.h +++ b/sys/dev/pci/drm/drmP.h @@ -119,6 +119,8 @@ #define PAGE_ALIGN(addr) (((addr) + PAGE_MASK) & ~PAGE_MASK) #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ +#define msecs_to_jiffies(x) (((int64_t)(x)) * hz / 1000) +#define time_after_eq(a,b) ((long)(b) - (long)(a) <= 0) #define drm_msleep(x, msg) delay(x * 1000) extern struct cfdriver drm_cd; @@ -353,6 +355,7 @@ struct drm_file { int minor; u_int obj_id; /*next gem id*/ struct list_head fbs; + void *driver_priv; }; struct drm_lock_data { diff --git a/sys/dev/pci/drm/i915_dma.c b/sys/dev/pci/drm/i915_dma.c index 07451bb22b9..2a6ffcc250e 100644 --- a/sys/dev/pci/drm/i915_dma.c +++ b/sys/dev/pci/drm/i915_dma.c @@ -345,3 +345,29 @@ i915_driver_lastclose(struct drm_device *dev) } dev_priv->agpdmat = NULL; } + +int +i915_driver_open(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv; + + file_priv = malloc(sizeof(*file_priv), M_DRM, M_WAITOK); + if (!file_priv) + return ENOMEM; + + file->driver_priv = file_priv; + + mtx_init(&file_priv->mm.lock, IPL_NONE); + INIT_LIST_HEAD(&file_priv->mm.request_list); + + return 0; +} + +void +i915_driver_close(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + + i915_gem_release(dev, file); + free(file_priv, M_DRM); +} diff --git a/sys/dev/pci/drm/i915_drv.c b/sys/dev/pci/drm/i915_drv.c index fe88909ccfb..c720b3869a6 100644 --- a/sys/dev/pci/drm/i915_drv.c +++ b/sys/dev/pci/drm/i915_drv.c @@ -417,6 +417,8 @@ static struct drm_driver_info inteldrm_driver = { .buf_priv_size = 1, /* No dev_priv */ .file_priv_size = sizeof(struct inteldrm_file), .ioctl = inteldrm_ioctl, + .open = i915_driver_open, + .close = i915_driver_close, .lastclose = i915_driver_lastclose, .gem_init_object = i915_gem_init_object, diff --git a/sys/dev/pci/drm/i915_drv.h b/sys/dev/pci/drm/i915_drv.h index efc187c058c..40665eab1a6 100644 --- a/sys/dev/pci/drm/i915_drv.h +++ b/sys/dev/pci/drm/i915_drv.h @@ -951,6 +951,13 @@ struct drm_i915_gem_object { #define to_intel_bo(x) container_of(x,struct drm_i915_gem_object, base) +struct drm_i915_file_private { + struct { + struct mutex lock; + struct list_head request_list; + } mm; +}; + /** * Request queue structure. * @@ -969,6 +976,11 @@ struct drm_i915_gem_request { uint32_t seqno; /** Postion in the ringbuffer of the end of the request */ uint32_t tail; + /** Time at which this request was emitted, in ticks. */ + unsigned long emitted_ticks; + struct drm_i915_file_private *file_priv; + /** file_priv list entry for this request */ + struct list_head client_list; }; u_int32_t inteldrm_read_hws(struct inteldrm_softc *, int); @@ -1144,6 +1156,8 @@ void intel_teardown_mchbar(struct inteldrm_softc *, int i915_getparam(struct inteldrm_softc *dev_priv, void *data); int i915_setparam(struct inteldrm_softc *dev_priv, void *data); void i915_kernel_lost_context(struct drm_device *); +int i915_driver_open(struct drm_device *, struct drm_file *); +void i915_driver_close(struct drm_device *, struct drm_file *); /* i915_drv.c */ void inteldrm_wipe_mappings(struct drm_obj *); @@ -1152,6 +1166,7 @@ void inteldrm_purge_obj(struct drm_obj *); void inteldrm_chipset_flush(struct inteldrm_softc *); int intel_gpu_reset(struct drm_device *); int i915_reset(struct drm_device *); +void inteldrm_timeout(void *); /* i915_gem_evict.c */ int i915_gem_evict_everything(struct inteldrm_softc *); @@ -1200,6 +1215,7 @@ int i915_gem_object_get_fence(struct drm_i915_gem_object *); int i915_gem_object_put_fence(struct drm_i915_gem_object *); void i915_gem_reset(struct drm_device *); void i915_gem_clflush_object(struct drm_i915_gem_object *); +void i915_gem_release(struct drm_device *, struct drm_file *); /* intel_opregion.c */ int intel_opregion_setup(struct drm_device *dev); diff --git a/sys/dev/pci/drm/i915_gem.c b/sys/dev/pci/drm/i915_gem.c index afa68270e14..2997ad8728b 100644 --- a/sys/dev/pci/drm/i915_gem.c +++ b/sys/dev/pci/drm/i915_gem.c @@ -73,6 +73,9 @@ void i915_gem_reset_ring_lists(drm_i915_private_t *, void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *); int i915_gem_gtt_rebind_object(struct drm_i915_gem_object *, enum i915_cache_level); +void i915_gem_request_remove_from_client(struct drm_i915_gem_request *); + +extern int ticks; static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) @@ -1048,13 +1051,23 @@ i915_add_request(struct intel_ring_buffer *ring, DRM_DEBUG("%d\n", seqno); - /* XXX request timing for throttle */ request->seqno = seqno; request->ring = ring; request->tail = request_ring_position; + request->emitted_ticks = ticks; was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); + if (file) { + struct drm_i915_file_private *file_priv = file->driver_priv; + + mtx_enter(&file_priv->mm.lock); + request->file_priv = file_priv; + list_add_tail(&request->client_list, + &file_priv->mm.request_list); + mtx_leave(&file_priv->mm.lock); + } + ring->outstanding_lazy_request = 0; if (dev_priv->mm.suspended == 0) { @@ -1070,7 +1083,21 @@ i915_add_request(struct intel_ring_buffer *ring, return 0; } -// i915_gem_request_remove_from_client +void +i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) +{ + struct drm_i915_file_private *file_priv = request->file_priv; + + if (!file_priv) + return; + + mtx_enter(&file_priv->mm.lock); + if (request->file_priv) { + list_del(&request->client_list); + request->file_priv = NULL; + } + mtx_leave(&file_priv->mm.lock); +} void i915_gem_reset_ring_lists(drm_i915_private_t *dev_priv, @@ -1084,7 +1111,7 @@ i915_gem_reset_ring_lists(drm_i915_private_t *dev_priv, list); list_del(&request->list); -// i915_gem_request_remove_from_client(request); + i915_gem_request_remove_from_client(request); free(request, M_DRM); } @@ -1193,6 +1220,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) ring->last_retired_head = request->tail; list_del(&request->list); + i915_gem_request_remove_from_client(request); drm_free(request); } @@ -2224,17 +2252,68 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, int write) /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * + * Note that if we were to use the current jiffies each time around the loop, + * we wouldn't escape the function with any frames outstanding if the time to + * render a frame was over 20ms. + * * This should get us reasonable parallelism between CPU and GPU but also * relatively low latency when blocking on a particular request to finish. */ int -i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) +i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) { -#if 0 - struct inteldrm_file *intel_file = (struct inteldrm_file *)file_priv; - u_int32_t seqno; -#endif - int ret = 0; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_file_private *file_priv = file->driver_priv; + unsigned long recent_enough = ticks - msecs_to_jiffies(20); + struct drm_i915_gem_request *request; + struct intel_ring_buffer *ring = NULL; + u32 seqno = 0; + int ret, retries; + + if (atomic_read(&dev_priv->mm.wedged)) + return EIO; + + mtx_enter(&file_priv->mm.lock); + list_for_each_entry(request, &file_priv->mm.request_list, client_list) { + if (time_after_eq(request->emitted_ticks, recent_enough)) + break; + + ring = request->ring; + seqno = request->seqno; + } + mtx_leave(&file_priv->mm.lock); + + if (seqno == 0) + return 0; + + ret = 0; + if (!i915_seqno_passed(ring->get_seqno(ring, false), seqno)) { + /* And wait for the seqno passing without holding any locks and + * causing extra latency for others. This is safe as the irq + * generation is designed to be run atomically and so is + * lockless. + */ + if (ring->irq_get(ring)) { + while (ret == 0 && + !(i915_seqno_passed(ring->get_seqno(ring, false), seqno) || + atomic_read(&dev_priv->mm.wedged))) + ret = msleep(ring, &dev_priv->irq_lock, PCATCH, + "915thr", 0); + ring->irq_put(ring); + } else { + for (retries = 300; retries > 0; retries--) { + if (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || + atomic_read(&dev_priv->mm.wedged)) + break; + DELAY(1000); + } + if (retries == 0) + ret = EBUSY; + } + } + + if (ret == 0) + inteldrm_timeout(dev_priv); return ret; } @@ -2995,6 +3074,28 @@ i915_gem_phys_pwrite(struct drm_device *dev, return ret; } +void +i915_gem_release(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + + /* Clean up our request list when the client is going away, so that + * later retire_requests won't dereference our soon-to-be-gone + * file_priv. + */ + mtx_enter(&file_priv->mm.lock); + while (!list_empty(&file_priv->mm.request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&file_priv->mm.request_list, + struct drm_i915_gem_request, + client_list); + list_del(&request->client_list); + request->file_priv = NULL; + } + mtx_leave(&file_priv->mm.lock); +} + // i915_gem_release // mutex_is_locked_by // i915_gem_inactive_shrink |