diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-12-13 11:54:50 -0500 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-12-14 06:34:46 -0500 |
commit | b13c2b96bf15b9dd0f1a45fd788f3a3025c5aec6 (patch) | |
tree | 6eb68ba8f5e4ec977efc3e087435ef272534915c | |
parent | 8d5203ca62539c6ab36a5bc2402c2de1de460e30 (diff) |
drm/i915/ringbuffer: Make IRQ refcnting atomic
In order to enforce the correct memory barriers for irq get/put, we need
to perform the actual counting using atomic operations.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 37 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.h | 4 |
4 files changed, 56 insertions, 46 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 27fa2a1b26a5..726c2ccd674c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -2000,17 +2000,19 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, | |||
2000 | trace_i915_gem_request_wait_begin(dev, seqno); | 2000 | trace_i915_gem_request_wait_begin(dev, seqno); |
2001 | 2001 | ||
2002 | ring->waiting_seqno = seqno; | 2002 | ring->waiting_seqno = seqno; |
2003 | ring->irq_get(ring); | 2003 | ret = -ENODEV; |
2004 | if (interruptible) | 2004 | if (ring->irq_get(ring)) { |
2005 | ret = wait_event_interruptible(ring->irq_queue, | 2005 | if (interruptible) |
2006 | i915_seqno_passed(ring->get_seqno(ring), seqno) | 2006 | ret = wait_event_interruptible(ring->irq_queue, |
2007 | || atomic_read(&dev_priv->mm.wedged)); | 2007 | i915_seqno_passed(ring->get_seqno(ring), seqno) |
2008 | else | 2008 | || atomic_read(&dev_priv->mm.wedged)); |
2009 | wait_event(ring->irq_queue, | 2009 | else |
2010 | i915_seqno_passed(ring->get_seqno(ring), seqno) | 2010 | wait_event(ring->irq_queue, |
2011 | || atomic_read(&dev_priv->mm.wedged)); | 2011 | i915_seqno_passed(ring->get_seqno(ring), seqno) |
2012 | || atomic_read(&dev_priv->mm.wedged)); | ||
2012 | 2013 | ||
2013 | ring->irq_put(ring); | 2014 | ring->irq_put(ring); |
2015 | } | ||
2014 | ring->waiting_seqno = 0; | 2016 | ring->waiting_seqno = 0; |
2015 | 2017 | ||
2016 | trace_i915_gem_request_wait_end(dev, seqno); | 2018 | trace_i915_gem_request_wait_end(dev, seqno); |
@@ -3157,14 +3159,15 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) | |||
3157 | * generation is designed to be run atomically and so is | 3159 | * generation is designed to be run atomically and so is |
3158 | * lockless. | 3160 | * lockless. |
3159 | */ | 3161 | */ |
3160 | ring->irq_get(ring); | 3162 | if (ring->irq_get(ring)) { |
3161 | ret = wait_event_interruptible(ring->irq_queue, | 3163 | ret = wait_event_interruptible(ring->irq_queue, |
3162 | i915_seqno_passed(ring->get_seqno(ring), seqno) | 3164 | i915_seqno_passed(ring->get_seqno(ring), seqno) |
3163 | || atomic_read(&dev_priv->mm.wedged)); | 3165 | || atomic_read(&dev_priv->mm.wedged)); |
3164 | ring->irq_put(ring); | 3166 | ring->irq_put(ring); |
3165 | 3167 | ||
3166 | if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) | 3168 | if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) |
3167 | ret = -EIO; | 3169 | ret = -EIO; |
3170 | } | ||
3168 | } | 3171 | } |
3169 | 3172 | ||
3170 | if (ret == 0) | 3173 | if (ret == 0) |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 02e4dd82f754..2ddb98b5c90f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -1186,10 +1186,9 @@ void i915_trace_irq_get(struct drm_device *dev, u32 seqno) | |||
1186 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 1186 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
1187 | struct intel_ring_buffer *ring = LP_RING(dev_priv); | 1187 | struct intel_ring_buffer *ring = LP_RING(dev_priv); |
1188 | 1188 | ||
1189 | if (dev_priv->trace_irq_seqno == 0) | 1189 | if (dev_priv->trace_irq_seqno == 0 && |
1190 | ring->irq_get(ring); | 1190 | ring->irq_get(ring)) |
1191 | 1191 | dev_priv->trace_irq_seqno = seqno; | |
1192 | dev_priv->trace_irq_seqno = seqno; | ||
1193 | } | 1192 | } |
1194 | 1193 | ||
1195 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) | 1194 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) |
@@ -1211,10 +1210,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
1211 | if (master_priv->sarea_priv) | 1210 | if (master_priv->sarea_priv) |
1212 | master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; | 1211 | master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; |
1213 | 1212 | ||
1214 | ring->irq_get(ring); | 1213 | ret = -ENODEV; |
1215 | DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ, | 1214 | if (ring->irq_get(ring)) { |
1216 | READ_BREADCRUMB(dev_priv) >= irq_nr); | 1215 | DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ, |
1217 | ring->irq_put(ring); | 1216 | READ_BREADCRUMB(dev_priv) >= irq_nr); |
1217 | ring->irq_put(ring); | ||
1218 | } | ||
1218 | 1219 | ||
1219 | if (ret == -EBUSY) { | 1220 | if (ret == -EBUSY) { |
1220 | DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", | 1221 | DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", |
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 74b99718a1fb..a3fd993e0de0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c | |||
@@ -327,25 +327,28 @@ ring_get_seqno(struct intel_ring_buffer *ring) | |||
327 | return intel_read_status_page(ring, I915_GEM_HWS_INDEX); | 327 | return intel_read_status_page(ring, I915_GEM_HWS_INDEX); |
328 | } | 328 | } |
329 | 329 | ||
330 | static void | 330 | static bool |
331 | render_ring_get_irq(struct intel_ring_buffer *ring) | 331 | render_ring_get_irq(struct intel_ring_buffer *ring) |
332 | { | 332 | { |
333 | struct drm_device *dev = ring->dev; | 333 | struct drm_device *dev = ring->dev; |
334 | 334 | ||
335 | if (dev->irq_enabled && ++ring->irq_refcount == 1) { | 335 | if (!dev->irq_enabled) |
336 | return false; | ||
337 | |||
338 | if (atomic_inc_return(&ring->irq_refcount) == 1) { | ||
336 | drm_i915_private_t *dev_priv = dev->dev_private; | 339 | drm_i915_private_t *dev_priv = dev->dev_private; |
337 | unsigned long irqflags; | 340 | unsigned long irqflags; |
338 | 341 | ||
339 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | 342 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
340 | |||
341 | if (HAS_PCH_SPLIT(dev)) | 343 | if (HAS_PCH_SPLIT(dev)) |
342 | ironlake_enable_graphics_irq(dev_priv, | 344 | ironlake_enable_graphics_irq(dev_priv, |
343 | GT_USER_INTERRUPT); | 345 | GT_USER_INTERRUPT); |
344 | else | 346 | else |
345 | i915_enable_irq(dev_priv, I915_USER_INTERRUPT); | 347 | i915_enable_irq(dev_priv, I915_USER_INTERRUPT); |
346 | |||
347 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | 348 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
348 | } | 349 | } |
350 | |||
351 | return true; | ||
349 | } | 352 | } |
350 | 353 | ||
351 | static void | 354 | static void |
@@ -353,8 +356,7 @@ render_ring_put_irq(struct intel_ring_buffer *ring) | |||
353 | { | 356 | { |
354 | struct drm_device *dev = ring->dev; | 357 | struct drm_device *dev = ring->dev; |
355 | 358 | ||
356 | BUG_ON(dev->irq_enabled && ring->irq_refcount == 0); | 359 | if (atomic_dec_and_test(&ring->irq_refcount)) { |
357 | if (dev->irq_enabled && --ring->irq_refcount == 0) { | ||
358 | drm_i915_private_t *dev_priv = dev->dev_private; | 360 | drm_i915_private_t *dev_priv = dev->dev_private; |
359 | unsigned long irqflags; | 361 | unsigned long irqflags; |
360 | 362 | ||
@@ -417,12 +419,15 @@ ring_add_request(struct intel_ring_buffer *ring, | |||
417 | return 0; | 419 | return 0; |
418 | } | 420 | } |
419 | 421 | ||
420 | static void | 422 | static bool |
421 | ring_get_irq(struct intel_ring_buffer *ring, u32 flag) | 423 | ring_get_irq(struct intel_ring_buffer *ring, u32 flag) |
422 | { | 424 | { |
423 | struct drm_device *dev = ring->dev; | 425 | struct drm_device *dev = ring->dev; |
424 | 426 | ||
425 | if (dev->irq_enabled && ++ring->irq_refcount == 1) { | 427 | if (!dev->irq_enabled) |
428 | return false; | ||
429 | |||
430 | if (atomic_inc_return(&ring->irq_refcount) == 1) { | ||
426 | drm_i915_private_t *dev_priv = dev->dev_private; | 431 | drm_i915_private_t *dev_priv = dev->dev_private; |
427 | unsigned long irqflags; | 432 | unsigned long irqflags; |
428 | 433 | ||
@@ -430,6 +435,8 @@ ring_get_irq(struct intel_ring_buffer *ring, u32 flag) | |||
430 | ironlake_enable_graphics_irq(dev_priv, flag); | 435 | ironlake_enable_graphics_irq(dev_priv, flag); |
431 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | 436 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
432 | } | 437 | } |
438 | |||
439 | return true; | ||
433 | } | 440 | } |
434 | 441 | ||
435 | static void | 442 | static void |
@@ -437,7 +444,7 @@ ring_put_irq(struct intel_ring_buffer *ring, u32 flag) | |||
437 | { | 444 | { |
438 | struct drm_device *dev = ring->dev; | 445 | struct drm_device *dev = ring->dev; |
439 | 446 | ||
440 | if (dev->irq_enabled && --ring->irq_refcount == 0) { | 447 | if (atomic_dec_and_test(&ring->irq_refcount)) { |
441 | drm_i915_private_t *dev_priv = dev->dev_private; | 448 | drm_i915_private_t *dev_priv = dev->dev_private; |
442 | unsigned long irqflags; | 449 | unsigned long irqflags; |
443 | 450 | ||
@@ -447,16 +454,15 @@ ring_put_irq(struct intel_ring_buffer *ring, u32 flag) | |||
447 | } | 454 | } |
448 | } | 455 | } |
449 | 456 | ||
450 | 457 | static bool | |
451 | static void | ||
452 | bsd_ring_get_irq(struct intel_ring_buffer *ring) | 458 | bsd_ring_get_irq(struct intel_ring_buffer *ring) |
453 | { | 459 | { |
454 | ring_get_irq(ring, GT_BSD_USER_INTERRUPT); | 460 | return ring_get_irq(ring, GT_BSD_USER_INTERRUPT); |
455 | } | 461 | } |
456 | static void | 462 | static void |
457 | bsd_ring_put_irq(struct intel_ring_buffer *ring) | 463 | bsd_ring_put_irq(struct intel_ring_buffer *ring) |
458 | { | 464 | { |
459 | ring_put_irq(ring, GT_BSD_USER_INTERRUPT); | 465 | ring_put_irq(ring, GT_BSD_USER_INTERRUPT); |
460 | } | 466 | } |
461 | 467 | ||
462 | static int | 468 | static int |
@@ -846,16 +852,16 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, | |||
846 | return 0; | 852 | return 0; |
847 | } | 853 | } |
848 | 854 | ||
849 | static void | 855 | static bool |
850 | gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring) | 856 | gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring) |
851 | { | 857 | { |
852 | ring_get_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); | 858 | return ring_get_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); |
853 | } | 859 | } |
854 | 860 | ||
855 | static void | 861 | static void |
856 | gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring) | 862 | gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring) |
857 | { | 863 | { |
858 | ring_put_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); | 864 | ring_put_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); |
859 | } | 865 | } |
860 | 866 | ||
861 | /* ring buffer for Video Codec for Gen6+ */ | 867 | /* ring buffer for Video Codec for Gen6+ */ |
@@ -876,16 +882,16 @@ static const struct intel_ring_buffer gen6_bsd_ring = { | |||
876 | 882 | ||
877 | /* Blitter support (SandyBridge+) */ | 883 | /* Blitter support (SandyBridge+) */ |
878 | 884 | ||
879 | static void | 885 | static bool |
880 | blt_ring_get_irq(struct intel_ring_buffer *ring) | 886 | blt_ring_get_irq(struct intel_ring_buffer *ring) |
881 | { | 887 | { |
882 | ring_get_irq(ring, GT_BLT_USER_INTERRUPT); | 888 | return ring_get_irq(ring, GT_BLT_USER_INTERRUPT); |
883 | } | 889 | } |
884 | 890 | ||
885 | static void | 891 | static void |
886 | blt_ring_put_irq(struct intel_ring_buffer *ring) | 892 | blt_ring_put_irq(struct intel_ring_buffer *ring) |
887 | { | 893 | { |
888 | ring_put_irq(ring, GT_BLT_USER_INTERRUPT); | 894 | ring_put_irq(ring, GT_BLT_USER_INTERRUPT); |
889 | } | 895 | } |
890 | 896 | ||
891 | 897 | ||
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 9652e4600b5e..8e2e357ad6ee 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h | |||
@@ -54,8 +54,8 @@ struct intel_ring_buffer { | |||
54 | u32 irq_seqno; /* last seq seem at irq time */ | 54 | u32 irq_seqno; /* last seq seem at irq time */ |
55 | u32 waiting_seqno; | 55 | u32 waiting_seqno; |
56 | u32 sync_seqno[I915_NUM_RINGS-1]; | 56 | u32 sync_seqno[I915_NUM_RINGS-1]; |
57 | u32 irq_refcount; | 57 | atomic_t irq_refcount; |
58 | void (*irq_get)(struct intel_ring_buffer *ring); | 58 | bool __must_check (*irq_get)(struct intel_ring_buffer *ring); |
59 | void (*irq_put)(struct intel_ring_buffer *ring); | 59 | void (*irq_put)(struct intel_ring_buffer *ring); |
60 | 60 | ||
61 | int (*init)(struct intel_ring_buffer *ring); | 61 | int (*init)(struct intel_ring_buffer *ring); |