Skip to content

Commit

Permalink
drm/i915: Introduce for_each_ring() macro
Browse files Browse the repository at this point in the history
In many places we wish to iterate over the rings associated with the
GPU, so refactor them to use a common macro.

Along the way, there are a few code removals that should be side-effect
free and some rearrangement which should only have a cosmetic impact,
such as error-state.

Note that this slightly changes the semantics in the hangcheck code:
We now always cycle through all enabled rings instead of
short-circuiting the logic.

v2: Pull in a couple of suggestions from Ben and Daniel for
intel_ring_initialized() and not removing the warning (just moving them
to a new home, closer to the error).

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>
[danvet: Added note to commit message about the small behaviour
change, suggested by Ben Widawsky.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Chris Wilson authored and Daniel Vetter committed May 19, 2012
1 parent e7e164d commit b451951
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 85 deletions.
9 changes: 3 additions & 6 deletions drivers/gpu/drm/i915/i915_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,14 +699,14 @@ static int i915_error_state(struct seq_file *m, void *unused)
struct drm_device *dev = error_priv->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_state *error = error_priv->error;
struct intel_ring_buffer *ring;
int i, j, page, offset, elt;

if (!error) {
seq_printf(m, "no error state collected\n");
return 0;
}


seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
error->time.tv_usec);
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
Expand All @@ -722,11 +722,8 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
}

i915_ring_error_state(m, dev, error, RCS);
if (HAS_BLT(dev))
i915_ring_error_state(m, dev, error, BCS);
if (HAS_BSD(dev))
i915_ring_error_state(m, dev, error, VCS);
for_each_ring(ring, dev_priv, i)
i915_ring_error_state(m, dev, error, i);

if (error->active_bo)
print_error_buffers(m, "Active",
Expand Down
10 changes: 5 additions & 5 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -893,15 +893,15 @@ int i915_reset(struct drm_device *dev)
*/
if (drm_core_check_feature(dev, DRIVER_MODESET) ||
!dev_priv->mm.suspended) {
struct intel_ring_buffer *ring;
int i;

dev_priv->mm.suspended = 0;

i915_gem_init_swizzling(dev);

dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
if (HAS_BSD(dev))
dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
if (HAS_BLT(dev))
dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
for_each_ring(ring, dev_priv, i)
ring->init(ring);

i915_gem_init_ppgtt(dev);

Expand Down
9 changes: 6 additions & 3 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,9 +410,7 @@ typedef struct drm_i915_private {
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
struct timer_list hangcheck_timer;
int hangcheck_count;
uint32_t last_acthd;
uint32_t last_acthd_bsd;
uint32_t last_acthd_blt;
uint32_t last_acthd[I915_NUM_RINGS];
uint32_t last_instdone;
uint32_t last_instdone1;

Expand Down Expand Up @@ -820,6 +818,11 @@ typedef struct drm_i915_private {
struct drm_property *force_audio_property;
} drm_i915_private_t;

/* Iterate over initialised rings */
#define for_each_ring(ring__, dev_priv__, i__) \
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
if (((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__)))

enum hdmi_force_audio {
HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */
HDMI_AUDIO_OFF, /* force turn off HDMI audio */
Expand Down
39 changes: 20 additions & 19 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1655,10 +1655,11 @@ void i915_gem_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
struct intel_ring_buffer *ring;
int i;

for (i = 0; i < I915_NUM_RINGS; i++)
i915_gem_reset_ring_lists(dev_priv, &dev_priv->ring[i]);
for_each_ring(ring, dev_priv, i)
i915_gem_reset_ring_lists(dev_priv, ring);

/* Remove anything from the flushing lists. The GPU cache is likely
* to be lost on reset along with the data, so simply move the
Expand Down Expand Up @@ -1763,17 +1764,19 @@ void
i915_gem_retire_requests(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int i;

for (i = 0; i < I915_NUM_RINGS; i++)
i915_gem_retire_requests_ring(&dev_priv->ring[i]);
for_each_ring(ring, dev_priv, i)
i915_gem_retire_requests_ring(ring);
}

static void
i915_gem_retire_work_handler(struct work_struct *work)
{
drm_i915_private_t *dev_priv;
struct drm_device *dev;
struct intel_ring_buffer *ring;
bool idle;
int i;

Expand All @@ -1793,9 +1796,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
* objects indefinitely.
*/
idle = true;
for (i = 0; i < I915_NUM_RINGS; i++) {
struct intel_ring_buffer *ring = &dev_priv->ring[i];

for_each_ring(ring, dev_priv, i) {
if (!list_empty(&ring->gpu_write_list)) {
struct drm_i915_gem_request *request;
int ret;
Expand Down Expand Up @@ -2137,13 +2138,18 @@ static int i915_ring_idle(struct intel_ring_buffer *ring)
int i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int ret, i;

/* Flush everything onto the inactive list. */
for (i = 0; i < I915_NUM_RINGS; i++) {
ret = i915_ring_idle(&dev_priv->ring[i]);
for_each_ring(ring, dev_priv, i) {
ret = i915_ring_idle(ring);
if (ret)
return ret;

/* Is the device fubar? */
if (WARN_ON(!list_empty(&ring->gpu_write_list)))
return -EBUSY;
}

return 0;
Expand Down Expand Up @@ -3463,9 +3469,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
/* GFX_MODE is per-ring on gen7+ */
}

for (i = 0; i < I915_NUM_RINGS; i++) {
ring = &dev_priv->ring[i];

for_each_ring(ring, dev_priv, i) {
if (INTEL_INFO(dev)->gen >= 7)
I915_WRITE(RING_MODE_GEN7(ring),
_MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
Expand Down Expand Up @@ -3581,18 +3585,19 @@ void
i915_gem_cleanup_ringbuffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int i;

for (i = 0; i < I915_NUM_RINGS; i++)
intel_cleanup_ring_buffer(&dev_priv->ring[i]);
for_each_ring(ring, dev_priv, i)
intel_cleanup_ring_buffer(ring);
}

int
i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret, i;
int ret;

if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
Expand All @@ -3614,10 +3619,6 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
BUG_ON(!list_empty(&dev_priv->mm.active_list));
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
for (i = 0; i < I915_NUM_RINGS; i++) {
BUG_ON(!list_empty(&dev_priv->ring[i].active_list));
BUG_ON(!list_empty(&dev_priv->ring[i].request_list));
}
mutex_unlock(&dev->struct_mutex);

ret = drm_irq_install(dev);
Expand Down
14 changes: 5 additions & 9 deletions drivers/gpu/drm/i915/i915_gem_evict.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj, *next;
bool lists_empty;
int ret,i;
int ret;

lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
Expand All @@ -178,17 +178,13 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)

trace_i915_gem_evict_everything(dev, purgeable_only);

ret = i915_gpu_idle(dev);
if (ret)
return ret;

/* The gpu_idle will flush everything in the write domain to the
* active list. Then we must move everything off the active list
* with retire requests.
*/
for (i = 0; i < I915_NUM_RINGS; i++)
if (WARN_ON(!list_empty(&dev_priv->ring[i].gpu_write_list)))
return -EBUSY;
ret = i915_gpu_idle(dev);
if (ret)
return ret;

i915_gem_retire_requests(dev);

Expand All @@ -203,5 +199,5 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
}
}

return ret;
return 0;
}
69 changes: 28 additions & 41 deletions drivers/gpu/drm/i915/i915_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1022,15 +1022,11 @@ static void i915_gem_record_rings(struct drm_device *dev,
struct drm_i915_error_state *error)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
struct drm_i915_gem_request *request;
int i, count;

for (i = 0; i < I915_NUM_RINGS; i++) {
struct intel_ring_buffer *ring = &dev_priv->ring[i];

if (ring->obj == NULL)
continue;

for_each_ring(ring, dev_priv, i) {
i915_record_ring_state(dev, error, ring);

error->ring[i].batchbuffer =
Expand Down Expand Up @@ -1295,6 +1291,8 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
void i915_handle_error(struct drm_device *dev, bool wedged)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int i;

i915_capture_error_state(dev);
i915_report_and_clear_eir(dev);
Expand All @@ -1306,11 +1304,8 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
/*
* Wakeup waiting processes so they don't hang
*/
wake_up_all(&dev_priv->ring[RCS].irq_queue);
if (HAS_BSD(dev))
wake_up_all(&dev_priv->ring[VCS].irq_queue);
if (HAS_BLT(dev))
wake_up_all(&dev_priv->ring[BCS].irq_queue);
for_each_ring(ring, dev_priv, i)
wake_up_all(&ring->irq_queue);
}

queue_work(dev_priv->wq, &dev_priv->error_work);
Expand Down Expand Up @@ -1515,11 +1510,6 @@ ring_last_seqno(struct intel_ring_buffer *ring)

static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
{
/* We don't check whether the ring even exists before calling this
* function. Hence check whether it's initialized. */
if (ring->obj == NULL)
return true;

if (list_empty(&ring->request_list) ||
i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
/* Issue a wake-up to catch stuck h/w. */
Expand Down Expand Up @@ -1553,26 +1543,25 @@ static bool i915_hangcheck_hung(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;

if (dev_priv->hangcheck_count++ > 1) {
bool hung = true;

DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
i915_handle_error(dev, true);

if (!IS_GEN2(dev)) {
struct intel_ring_buffer *ring;
int i;

/* Is the chip hanging on a WAIT_FOR_EVENT?
* If so we can simply poke the RB_WAIT bit
* and break the hang. This should work on
* all but the second generation chipsets.
*/
if (kick_ring(&dev_priv->ring[RCS]))
return false;

if (HAS_BSD(dev) && kick_ring(&dev_priv->ring[VCS]))
return false;

if (HAS_BLT(dev) && kick_ring(&dev_priv->ring[BCS]))
return false;
for_each_ring(ring, dev_priv, i)
hung &= !kick_ring(ring);
}

return true;
return hung;
}

return false;
Expand All @@ -1588,16 +1577,23 @@ void i915_hangcheck_elapsed(unsigned long data)
{
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt;
bool err = false;
uint32_t acthd[I915_NUM_RINGS], instdone, instdone1;
struct intel_ring_buffer *ring;
bool err = false, idle;
int i;

if (!i915_enable_hangcheck)
return;

memset(acthd, 0, sizeof(acthd));
idle = true;
for_each_ring(ring, dev_priv, i) {
idle &= i915_hangcheck_ring_idle(ring, &err);
acthd[i] = intel_ring_get_active_head(ring);
}

/* If all work is done then ACTHD clearly hasn't advanced. */
if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) {
if (idle) {
if (err) {
if (i915_hangcheck_hung(dev))
return;
Expand All @@ -1616,25 +1612,16 @@ void i915_hangcheck_elapsed(unsigned long data)
instdone = I915_READ(INSTDONE_I965);
instdone1 = I915_READ(INSTDONE1);
}
acthd = intel_ring_get_active_head(&dev_priv->ring[RCS]);
acthd_bsd = HAS_BSD(dev) ?
intel_ring_get_active_head(&dev_priv->ring[VCS]) : 0;
acthd_blt = HAS_BLT(dev) ?
intel_ring_get_active_head(&dev_priv->ring[BCS]) : 0;

if (dev_priv->last_acthd == acthd &&
dev_priv->last_acthd_bsd == acthd_bsd &&
dev_priv->last_acthd_blt == acthd_blt &&
if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 &&
dev_priv->last_instdone == instdone &&
dev_priv->last_instdone1 == instdone1) {
if (i915_hangcheck_hung(dev))
return;
} else {
dev_priv->hangcheck_count = 0;

dev_priv->last_acthd = acthd;
dev_priv->last_acthd_bsd = acthd_bsd;
dev_priv->last_acthd_blt = acthd_blt;
memcpy(dev_priv->last_acthd, acthd, sizeof(acthd));
dev_priv->last_instdone = instdone;
dev_priv->last_instdone1 = instdone1;
}
Expand Down
5 changes: 3 additions & 2 deletions drivers/gpu/drm/i915/intel_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2326,6 +2326,7 @@ int intel_enable_rc6(const struct drm_device *dev)

void gen6_enable_rps(struct drm_i915_private *dev_priv)
{
struct intel_ring_buffer *ring;
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
u32 pcu_mbox, rc6_mask = 0;
Expand Down Expand Up @@ -2360,8 +2361,8 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);

for (i = 0; i < I915_NUM_RINGS; i++)
I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
for_each_ring(ring, dev_priv, i)
I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);

I915_WRITE(GEN6_RC_SLEEP, 0);
I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
Expand Down
Loading

0 comments on commit b451951

Please sign in to comment.