@@ -1203,7 +1203,7 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
(dev)->pci_device == 0x2A42 || \
(dev)->pci_device == 0x2E42)
-#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev))
+#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev) || IS_GEN6(dev))
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
@@ -4504,7 +4504,11 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
goto cleanup_pipe_control;
if (HAS_BSD(dev)) {
- dev_priv->bsd_ring = bsd_ring;
+ if (IS_GEN6(dev))
+ dev_priv->bsd_ring = gen6_bsd_ring;
+ else
+ dev_priv->bsd_ring = bsd_ring;
+
ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
if (ret)
goto cleanup_render_ring;
@@ -312,6 +312,10 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
u32 de_iir, gt_iir, de_ier, pch_iir;
struct drm_i915_master_private *master_priv;
struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+ u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
+
+ if (IS_GEN6(dev))
+ bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
@@ -342,10 +346,9 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
dev_priv->hangcheck_count = 0;
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
}
- if (gt_iir & GT_BSD_USER_INTERRUPT)
+ if (gt_iir & bsd_usr_interrupt)
DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
-
if (de_iir & DE_GSE)
ironlake_opregion_gse_intr(dev);
@@ -1381,17 +1384,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
(void) I915_READ(DEIER);
- /* Gen6 only needs render pipe_control now */
if (IS_GEN6(dev))
- render_mask = GT_PIPE_NOTIFY;
+ render_mask = GT_PIPE_NOTIFY | GT_GEN6_BSD_USER_INTERRUPT;
dev_priv->gt_irq_mask_reg = ~render_mask;
dev_priv->gt_irq_enable_reg = render_mask;
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
- if (IS_GEN6(dev))
+ if (IS_GEN6(dev)) {
I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
+ I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
+ }
+
I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
(void) I915_READ(GTIER);
@@ -192,11 +192,11 @@
#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
#define MI_STORE_DWORD_INDEX_SHIFT 2
#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1)
+#define MI_FLUSH_DW MI_INSTR(0x26, 2) /* for GEN6 */
#define MI_BATCH_BUFFER MI_INSTR(0x30, 1)
#define MI_BATCH_NON_SECURE (1)
#define MI_BATCH_NON_SECURE_I965 (1<<8)
#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0)
-
/*
* 3D instructions used by the kernel
*/
@@ -476,6 +476,24 @@
#define BSD_HWS_PGA 0x04080
/*
+ * video command stream instruction and interrupt control register defines
+ * for GEN6
+ */
+#define GEN6_BSD_RING_TAIL 0x12030
+#define GEN6_BSD_RING_HEAD 0x12034
+#define GEN6_BSD_RING_START 0x12038
+#define GEN6_BSD_RING_CTL 0x1203c
+#define GEN6_BSD_RING_ACTHD 0x12074
+#define GEN6_BSD_HWS_PGA 0x14080
+
+#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
+#define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3)
+
+#define GEN6_BSD_IMR 0x120a8
+#define GEN6_BSD_IMR_USER_INTERRUPT (1 << 12)
+#define GEN6_BSD_RNCID 0x12198
+
+/*
* Framebuffer compression (915+ only)
*/
@@ -2507,7 +2525,7 @@
#define GT_SYNC_STATUS (1 << 2)
#define GT_USER_INTERRUPT (1 << 0)
#define GT_BSD_USER_INTERRUPT (1 << 5)
-
+#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12)
#define GTISR 0x44010
#define GTIMR 0x44014
@@ -32,6 +32,7 @@
#include "i915_drv.h"
#include "i915_drm.h"
#include "i915_trace.h"
+#include "intel_drv.h"
static u32 i915_gem_get_seqno(struct drm_device *dev)
{
@@ -874,3 +875,123 @@ struct intel_ring_buffer bsd_ring = {
.status_page = {NULL, 0, NULL},
.map = {0,}
};
+
+static void gen6_bsd_setup_status_page(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ I915_WRITE(GEN6_BSD_HWS_PGA, ring->status_page.gfx_addr);
+ I915_READ(GEN6_BSD_HWS_PGA);
+}
+
+static inline unsigned int gen6_bsd_ring_get_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(GEN6_BSD_RING_HEAD) & HEAD_ADDR;
+}
+
+static inline unsigned int gen6_bsd_ring_get_tail(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(GEN6_BSD_RING_TAIL) & TAIL_ADDR;
+}
+
+static inline void gen6_bsd_ring_set_tail(struct drm_device *dev,
+ u32 value)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ /* Every tail move must follow the sequence below */
+ I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL, 0x00010001);
+ I915_WRITE(GEN6_BSD_RNCID, 0x00000000);
+
+ if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
+ GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0,
+ 50, 0))
+ DRM_ERROR("timed out waiting for IDLE Indicator\n");
+
+ I915_WRITE(GEN6_BSD_RING_TAIL, value);
+ I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL, 0x00010000);
+}
+
+static inline unsigned int gen6_bsd_ring_get_active_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(GEN6_BSD_RING_ACTHD);
+}
+
+static inline void gen6_bsd_ring_advance_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ gen6_bsd_ring_set_tail(dev, ring->tail);
+}
+
+static void gen6_bsd_ring_flush(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
+{
+ intel_ring_begin(dev, ring, 4);
+ intel_ring_emit(dev, ring, MI_FLUSH_DW);
+ intel_ring_emit(dev, ring, 0);
+ intel_ring_emit(dev, ring, 0);
+ intel_ring_emit(dev, ring, 0);
+ intel_ring_advance(dev, ring);
+}
+
+static int
+gen6_bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_execbuffer2 *exec,
+ struct drm_clip_rect *cliprects,
+ uint64_t exec_offset)
+{
+ uint32_t exec_start;
+ exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+ intel_ring_begin(dev, ring, 2);
+ intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); /* bit0-7 is the length on GEN6+ */
+ intel_ring_emit(dev, ring, exec_start);
+ intel_ring_advance(dev, ring);
+ return 0;
+}
+
+/* ring buffer for Video Codec for Gen6+ */
+struct intel_ring_buffer gen6_bsd_ring = {
+ .name = "gen6 bsd ring",
+ .regs = {
+ .ctl = GEN6_BSD_RING_CTL,
+ .head = GEN6_BSD_RING_HEAD,
+ .tail = GEN6_BSD_RING_TAIL,
+ .start = GEN6_BSD_RING_START
+ },
+ .ring_flag = I915_EXEC_BSD,
+ .size = 32 * PAGE_SIZE,
+ .alignment = PAGE_SIZE,
+ .virtual_start = NULL,
+ .dev = NULL,
+ .gem_object = NULL,
+ .head = 0,
+ .tail = 0,
+ .space = 0,
+ .user_irq_refcount = 0,
+ .irq_gem_seqno = 0,
+ .waiting_gem_seqno = 0,
+ .setup_status_page = gen6_bsd_setup_status_page,
+ .init = init_bsd_ring,
+ .get_head = gen6_bsd_ring_get_head,
+ .get_tail = gen6_bsd_ring_get_tail,
+ .set_tail = gen6_bsd_ring_set_tail,
+ .get_active_head = gen6_bsd_ring_get_active_head,
+ .advance_ring = gen6_bsd_ring_advance_ring,
+ .flush = gen6_bsd_ring_flush,
+ .add_request = bsd_ring_add_request,
+ .get_gem_seqno = bsd_ring_get_gem_seqno,
+ .user_irq_get = bsd_ring_get_user_irq,
+ .user_irq_put = bsd_ring_put_user_irq,
+ .dispatch_gem_execbuffer = gen6_bsd_ring_dispatch_gem_execbuffer,
+ .status_page = {NULL, 0, NULL},
+ .map = {0,}
+};
@@ -129,5 +129,6 @@ u32 intel_ring_get_seqno(struct drm_device *dev,
extern struct intel_ring_buffer render_ring;
extern struct intel_ring_buffer bsd_ring;
+extern struct intel_ring_buffer gen6_bsd_ring;
#endif /* _INTEL_RINGBUFFER_H_ */