summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Widawsky <ben@bwidawsk.net>2011-08-31 11:09:48 -0700
committerBen Widawsky <ben@bwidawsk.net>2011-08-31 11:09:48 -0700
commitcefd7d64ee5bc0abb3925b93eb98ecb891739cc8 (patch)
treea2b239bb6d45ef84af52cc9eda4093fbdcd8d629
parent4584b6dc2f3d6cdde613c53c7d6a0467594ff71f (diff)
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c22
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c175
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h8
3 files changed, 199 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 3c395a59da35..b04b8fece112 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1274,6 +1274,27 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
return 0;
}
+static int i915_dump_ring_timestamps(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!i915_timestamp_batch)
+ return 0;
+
+ i915_dump_object(m, dev_priv->mm.gtt_mapping,
+ dev_priv->ring[RCS].timestamp_obj);
+ if (dev_priv->ring[VCS].timestamp_obj)
+ i915_dump_object(m, dev_priv->mm.gtt_mapping,
+ dev_priv->ring[VCS].timestamp_obj);
+ if (dev_priv->ring[BCS].timestamp_obj)
+ i915_dump_object(m, dev_priv->mm.gtt_mapping,
+ dev_priv->ring[BCS].timestamp_obj);
+
+ return 0;
+}
+
static int
i915_wedged_open(struct inode *inode,
struct file *filp)
@@ -1655,6 +1676,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
{"i915_context_status", i915_context_status, 0},
{"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
+ {"i915_dump_ring_timestamps", i915_dump_ring_timestamps, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 4b9f325a6b72..e3db5855967d 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -27,6 +27,7 @@
*
*/
+#include <linux/ring_buffer.h>
#include "drmP.h"
#include "drm.h"
#include "i915_drv.h"
@@ -203,6 +204,14 @@ static int init_ring_common(struct intel_ring_buffer *ring)
ring->space = ring_space(ring);
}
+ if (i915_timestamp_batch) {
+ /* We'd like to use the generic ringbuffer interface... */
+ ring->timestamp_obj = i915_gem_alloc_object(ring->dev, 4096);
+ if (WARN_ON(i915_gem_object_pin(ring->timestamp_obj, 4096,
+ true))) {
+ i915_gem_free_object(&ring->timestamp_obj->base);
+ }
+ }
return 0;
}
@@ -696,13 +705,167 @@ bsd_ring_put_irq(struct intel_ring_buffer *ring)
spin_unlock(&ring->irq_lock);
}
+static void
+increment_timestamp_offset(struct intel_ring_buffer *ring,
+ struct intel_timestamp_data **ptr)
+{
+ u64 size;
+ if (!ring->timestamp_obj->gtt_space)
+ return;
+
+ size = ring->timestamp_obj->gtt_space->size;
+ (*ptr)++;
+ if (((u64)ring->timestamp_head + sizeof(*ring->timestamp_head)) > size)
+ (*ptr) = 0;
+}
+
+static inline uint32_t
+get_timestamp_before(struct intel_ring_buffer *ring)
+{
+ return ((ring->timestamp_obj->gtt_offset)) +
+ ((uint32_t)((off_t)(&ring->timestamp_head->before)));
+}
+
+static inline uint32_t
+get_timestamp_after(struct intel_ring_buffer *ring)
+{
+ return ((ring->timestamp_obj->gtt_offset)) +
+ ((uint32_t)((off_t)(&ring->timestamp_head->after)));
+}
+
+static inline uint32_t
+get_timestamp_pid(struct intel_ring_buffer *ring)
+{
+ return ((ring->timestamp_obj->gtt_offset)) +
+ ((uint32_t)((off_t)(&ring->timestamp_head->pid)));
+}
+
+static void
+pc_insert_timestamp(struct intel_ring_buffer *ring,
+ bool before)
+{
+ struct drm_device *dev = ring->dev;
+ int ret;
+ u32 offset, pid_offset, dwords;
+
+ if (WARN_ON_ONCE(ring->timestamp_obj == NULL))
+ return;
+
+ pid_offset = get_timestamp_pid(ring);
+
+ if (before) {
+ dwords = 10;
+ offset = get_timestamp_before(ring);
+ } else {
+ dwords = 4;
+ offset = get_timestamp_after(ring);
+ }
+
+ if (WARN_ON((offset % 8) || (pid_offset % 8)))
+ return;
+
+ if (INTEL_INFO(dev)->gen >= 6) {
+ ret = intel_ring_begin(ring, dwords);
+ if (ret)
+ return;
+
+ if (before) {
+ intel_ring_emit(ring, GFX_OP_PIPE_CONTROLn(3));
+ intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE);
+ intel_ring_emit(ring, (pid_offset) |
+ PIPE_CONTROL_GLOBAL_GTT);
+ intel_ring_emit(ring, current->pid);
+ intel_ring_emit(ring, 0);
+ }
+
+ intel_ring_emit(ring, GFX_OP_PIPE_CONTROLn(2));
+ intel_ring_emit(ring, PIPE_CONTROL_TSC_WRITE);
+ intel_ring_emit(ring, offset |
+ PIPE_CONTROL_GLOBAL_GTT);
+ intel_ring_emit(ring, 0);
+
+ if (before)
+ intel_ring_emit(ring, MI_NOOP);
+ else
+ increment_timestamp_offset(ring, &ring->timestamp_head);
+ } else if (INTEL_INFO(dev)->gen >= 4) {
+ ret = intel_ring_begin(ring, dwords);
+ if (ret)
+ return;
+ if (before) {
+ intel_ring_emit(ring, GFX_OP_PIPE_CONTROL |
+ PIPE_CONTROL_QW_WRITE | 2);
+ intel_ring_emit(ring, (pid_offset) |
+ PIPE_CONTROL_GLOBAL_GTT);
+ intel_ring_emit(ring, current->pid);
+ intel_ring_emit(ring, 0);
+ }
+ intel_ring_emit(ring, GFX_OP_PIPE_CONTROL |
+ PIPE_CONTROL_TSC_WRITE | 2);
+ intel_ring_emit(ring, offset | PIPE_CONTROL_GLOBAL_GTT);
+ intel_ring_emit(ring, 0);
+ intel_ring_emit(ring, MI_NOOP);
+ if (before)
+ intel_ring_emit(ring, MI_NOOP);
+ else
+ increment_timestamp_offset(ring, &ring->timestamp_head);
+ } else {
+ WARN_ONCE(1, "Gen3 GPUs are not supported");
+ return;
+ }
+
+ intel_ring_advance(ring);
+}
+
static int
-timestamp_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
+render_ring_timestamp_execbuffer(struct intel_ring_buffer *ring,
+ u32 offset,
+ u32 length)
{
- return ring->dispatch_execbuffer(ring, offset, length);
+ int ret;
+ pc_insert_timestamp(ring, true);
+ ret = ring->dispatch_execbuffer(ring, offset, length);
+ pc_insert_timestamp(ring, false);
+ return ret;
}
static int
+blt_timestamp_execbuffer(struct intel_ring_buffer *ring,
+ u32 offset,
+ u32 length)
+{
+ int ret;
+
+ if (!intel_ring_begin(ring, 8)) {
+ intel_ring_emit(ring, MI_STORE_DWORD_IMM(3) | MI_MEM_VIRTUAL |
+MI_STORE_DWORD_QWORD);
+ intel_ring_emit(ring, 0);
+ intel_ring_emit(ring, get_timestamp_pid(ring));
+ intel_ring_emit(ring, current->pid);
+ intel_ring_emit(ring, ring->name[0]);
+ intel_ring_emit(ring, MI_STORE_REGISTER_MEM);
+ intel_ring_emit(ring, 0x2358);
+ intel_ring_emit(ring, get_timestamp_before(ring));
+ intel_ring_advance(ring);
+ }
+
+ ret = ring->dispatch_execbuffer(ring, offset, length);
+ if (ret)
+ return ret;
+
+ if (!intel_ring_begin(ring, 4)) {
+ intel_ring_emit(ring, MI_STORE_REGISTER_MEM);
+ intel_ring_emit(ring, 0x2358);
+ intel_ring_emit(ring, get_timestamp_after(ring));
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
+ }
+
+ increment_timestamp_offset(ring, &ring->timestamp_head);
+
+ return ret;
+}
+static int
ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
{
int ret;
@@ -1032,7 +1195,7 @@ static const struct intel_ring_buffer render_ring = {
.irq_get = render_ring_get_irq,
.irq_put = render_ring_put_irq,
.dispatch_execbuffer = render_ring_dispatch_execbuffer,
- .timestamp_execbuffer = timestamp_execbuffer,
+ .timestamp_execbuffer = render_ring_timestamp_execbuffer,
.cleanup = render_ring_cleanup,
};
@@ -1051,7 +1214,7 @@ static const struct intel_ring_buffer bsd_ring = {
.irq_get = bsd_ring_get_irq,
.irq_put = bsd_ring_put_irq,
.dispatch_execbuffer = ring_dispatch_execbuffer,
- .timestamp_execbuffer = timestamp_execbuffer,
+ .timestamp_execbuffer = NULL,
};
@@ -1162,7 +1325,7 @@ static const struct intel_ring_buffer gen6_bsd_ring = {
.irq_get = gen6_bsd_ring_get_irq,
.irq_put = gen6_bsd_ring_put_irq,
.dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
- .timestamp_execbuffer = timestamp_execbuffer,
+ .timestamp_execbuffer = render_ring_timestamp_execbuffer,
};
/* Blitter support (SandyBridge+) */
@@ -1293,7 +1456,7 @@ static const struct intel_ring_buffer gen6_blt_ring = {
.irq_get = blt_ring_get_irq,
.irq_put = blt_ring_put_irq,
.dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
- .timestamp_execbuffer = timestamp_execbuffer,
+ .timestamp_execbuffer = blt_timestamp_execbuffer,
.cleanup = blt_ring_cleanup,
};
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index d313e2810552..9297b79ff437 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -33,6 +33,12 @@ struct intel_hw_status_page {
#define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base))
#define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base))
+struct intel_timestamp_data {
+ u64 pid;
+ u64 before;
+ u64 after;
+} __attribute__((packed, aligned(8)));
+
struct intel_ring_buffer {
const char *name;
enum intel_ring_id {
@@ -59,6 +65,8 @@ struct intel_ring_buffer {
u32 trace_irq_seqno;
u32 waiting_seqno;
u32 sync_seqno[I915_NUM_RINGS-1];
+ struct drm_i915_gem_object *timestamp_obj;
+ struct intel_timestamp_data *timestamp_head;
bool __must_check (*irq_get)(struct intel_ring_buffer *ring);
void (*irq_put)(struct intel_ring_buffer *ring);