summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gray <jsg@jsg.id.au>2013-03-05 21:33:18 +1100
committerJonathan Gray <jsg@jsg.id.au>2013-03-05 21:33:18 +1100
commitb01644984518c8ad617faedab6240d870194b7a3 (patch)
tree9b7c3a9c588f8d90541d1cb7b39291778965c7f4
parent85ef5c9012ed11ea9bb73d0666d76b21a6bc1fc5 (diff)
unstub the ring throttle ioctl
-rw-r--r--sys/dev/pci/drm/drmP.h3
-rw-r--r--sys/dev/pci/drm/i915_dma.c26
-rw-r--r--sys/dev/pci/drm/i915_drv.c2
-rw-r--r--sys/dev/pci/drm/i915_drv.h16
-rw-r--r--sys/dev/pci/drm/i915_gem.c119
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