Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 293601
b: refs/heads/master
c: a71d8d9
h: refs/heads/master
i:
  293599: 894c957
v: v3
  • Loading branch information
Chris Wilson authored and Daniel Vetter committed Feb 15, 2012
1 parent 6e3bfb5 commit 8b1df4c
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7c26e5c6edaec70f12984f7a3020864cc21e6fec
refs/heads/master: a71d8d94525e8fd855c0466fb586ae1cb008f3a2
5 changes: 5 additions & 0 deletions trunk/drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,9 @@ struct drm_i915_gem_request {
/** GEM sequence number associated with this request. */
uint32_t seqno;

/** Postion in the ringbuffer of the end of the request */
u32 tail;

/** Time at which this request was emitted, in jiffies. */
unsigned long emitted_jiffies;

Expand Down Expand Up @@ -1213,6 +1216,8 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
}

void i915_gem_retire_requests(struct drm_device *dev);
void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring);

void i915_gem_reset(struct drm_device *dev);
void i915_gem_clflush_object(struct drm_i915_gem_object *obj);
int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
Expand Down
17 changes: 16 additions & 1 deletion trunk/drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1605,12 +1605,20 @@ i915_add_request(struct intel_ring_buffer *ring,
{
drm_i915_private_t *dev_priv = ring->dev->dev_private;
uint32_t seqno;
u32 request_ring_position;
int was_empty;
int ret;

BUG_ON(request == NULL);
seqno = i915_gem_next_request_seqno(ring);

/* Record the position of the start of the request so that
* should we detect the updated seqno part-way through the
* GPU processing the request, we never over-estimate the
* position of the head.
*/
request_ring_position = intel_ring_get_tail(ring);

ret = ring->add_request(ring, &seqno);
if (ret)
return ret;
Expand All @@ -1619,6 +1627,7 @@ i915_add_request(struct intel_ring_buffer *ring,

request->seqno = seqno;
request->ring = ring;
request->tail = request_ring_position;
request->emitted_jiffies = jiffies;
was_empty = list_empty(&ring->request_list);
list_add_tail(&request->list, &ring->request_list);
Expand Down Expand Up @@ -1755,7 +1764,7 @@ void i915_gem_reset(struct drm_device *dev)
/**
* This function clears the request list as sequence numbers are passed.
*/
static void
void
i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
{
uint32_t seqno;
Expand Down Expand Up @@ -1783,6 +1792,12 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
break;

trace_i915_gem_request_retire(ring, request->seqno);
/* We know the GPU must have read the request to have
* sent us the seqno + interrupt, so use the position
* of tail of the request to update the last known position
* of the GPU head.
*/
ring->last_retired_head = request->tail;

list_del(&request->list);
i915_gem_request_remove_from_client(request);
Expand Down
83 changes: 83 additions & 0 deletions trunk/drivers/gpu/drm/i915/intel_ringbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ pc_render_add_request(struct intel_ring_buffer *ring,
PIPE_CONTROL_FLUSH(ring, scratch_addr);
scratch_addr += 128;
PIPE_CONTROL_FLUSH(ring, scratch_addr);

intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
PIPE_CONTROL_WRITE_FLUSH |
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
Expand Down Expand Up @@ -1107,11 +1108,89 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
return 0;
}

static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
bool was_interruptible;
int ret;

/* XXX As we have not yet audited all the paths to check that
* they are ready for ERESTARTSYS from intel_ring_begin, do not
* allow us to be interruptible by a signal.
*/
was_interruptible = dev_priv->mm.interruptible;
dev_priv->mm.interruptible = false;

ret = i915_wait_request(ring, seqno, true);

dev_priv->mm.interruptible = was_interruptible;

return ret;
}

static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
{
struct drm_i915_gem_request *request;
u32 seqno = 0;
int ret;

i915_gem_retire_requests_ring(ring);

if (ring->last_retired_head != -1) {
ring->head = ring->last_retired_head;
ring->last_retired_head = -1;
ring->space = ring_space(ring);
if (ring->space >= n)
return 0;
}

list_for_each_entry(request, &ring->request_list, list) {
int space;

if (request->tail == -1)
continue;

space = request->tail - (ring->tail + 8);
if (space < 0)
space += ring->size;
if (space >= n) {
seqno = request->seqno;
break;
}

/* Consume this request in case we need more space than
* is available and so need to prevent a race between
* updating last_retired_head and direct reads of
* I915_RING_HEAD. It also provides a nice sanity check.
*/
request->tail = -1;
}

if (seqno == 0)
return -ENOSPC;

ret = intel_ring_wait_seqno(ring, seqno);
if (ret)
return ret;

if (WARN_ON(ring->last_retired_head == -1))
return -ENOSPC;

ring->head = ring->last_retired_head;
ring->last_retired_head = -1;
ring->space = ring_space(ring);
if (WARN_ON(ring->space < n))
return -ENOSPC;

return 0;
}

int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
{
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long end;
int ret;
u32 head;

/* If the reported head position has wrapped or hasn't advanced,
Expand All @@ -1125,6 +1204,10 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
return 0;
}

ret = intel_ring_wait_request(ring, n);
if (ret != -ENOSPC)
return ret;

trace_i915_ring_wait_begin(ring);
if (drm_core_check_feature(dev, DRIVER_GEM))
/* With GEM the hangcheck timer should kick us out of the loop,
Expand Down
15 changes: 15 additions & 0 deletions trunk/drivers/gpu/drm/i915/intel_ringbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ struct intel_ring_buffer {
int effective_size;
struct intel_hw_status_page status_page;

/** We track the position of the requests in the ring buffer, and
* when each is retired we increment last_retired_head as the GPU
* must have finished processing the request and so we know we
* can advance the ringbuffer up to that position.
*
* last_retired_head is set to -1 after the value is consumed so
* we can detect new retirements.
*/
u32 last_retired_head;

spinlock_t irq_lock;
u32 irq_refcount;
u32 irq_mask;
Expand Down Expand Up @@ -193,6 +203,11 @@ int intel_init_blt_ring_buffer(struct drm_device *dev);
u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
void intel_ring_setup_status_page(struct intel_ring_buffer *ring);

static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring)
{
return ring->tail;
}

static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno)
{
if (ring->trace_irq_seqno == 0 && ring->irq_get(ring))
Expand Down

0 comments on commit 8b1df4c

Please sign in to comment.