diff mbox

drm/i915: init hardware to a known state on resume v3

Message ID 1366757201-5838-1-git-send-email-jbarnes@virtuousgeek.org (mailing list archive)
State New, archived
Headers show

Commit Message

Jesse Barnes April 23, 2013, 10:46 p.m. UTC
From: Zou Nanhai <nanhai.zou@intel.com>

Needed on SNB to avoid some RC6 related hangs.

v2: remove unneeded defines (Ken)
v3: update to agp-less driver (Jesse)
    fixup for new GEM APIs (Jesse)
    make debugfs use new locking (Jesse)

Signed-off-by: Zou Nanhai <nanhai.zou@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/Makefile       |    1 +
 drivers/gpu/drm/i915/i915_debugfs.c |   22 +
 drivers/gpu/drm/i915/i915_drv.c     |    8 +-
 drivers/gpu/drm/i915/i915_drv.h     |    7 +
 drivers/gpu/drm/i915/i965_defines.h |  141 +++++
 drivers/gpu/drm/i915/intel_3d.c     | 1085 +++++++++++++++++++++++++++++++++++
 6 files changed, 1263 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/i965_defines.h
 create mode 100644 drivers/gpu/drm/i915/intel_3d.c

Comments

Chris Wilson April 24, 2013, 9:22 a.m. UTC | #1
On Tue, Apr 23, 2013 at 03:46:41PM -0700, Jesse Barnes wrote:
> From: Zou Nanhai <nanhai.zou@intel.com>
> 
> Needed on SNB to avoid some RC6 related hangs.

IIRC, the wa was not for a hang, but for render corruption.

> v2: remove unneeded defines (Ken)
> v3: update to agp-less driver (Jesse)
>     fixup for new GEM APIs (Jesse)
>     make debugfs use new locking (Jesse)
> 
> Signed-off-by: Zou Nanhai <nanhai.zou@intel.com>
> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

Hmm, why do you want to emit gen6 state on gen7+? Please tidy up the
state emission, it is very very ugly, contains lots of redundancy and
some interesting choice of hard coded magic. The emit_wa() flush/idle
sequence doesn't do what you want, whereas emit_rect() does.
-Chris
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 91f3ac6..6253390 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -32,6 +32,7 @@  i915-y := i915_drv.o i915_dma.o i915_irq.o \
 	  intel_fb.o \
 	  intel_tv.o \
 	  intel_dvo.o \
+	  intel_3d.o \
 	  intel_ringbuffer.o \
 	  intel_overlay.o \
 	  intel_sprite.o \
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index a55630a..eb93539 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1444,6 +1444,26 @@  out:
 	return 0;
 }
 
+static int i915_gem_framebuffer_draw_3drect(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_crtc *crtc;
+	int pipe;
+
+	drm_modeset_lock_all(dev);
+	for_each_pipe(pipe) {
+		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+		if (!crtc->base.fb)
+			continue;
+		i915_render_rect(dev, to_intel_framebuffer(crtc->base.fb),
+				 100, 100, 100, 100);
+	}
+	drm_modeset_unlock_all(dev);
+	return 0;
+}
+
 static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -2110,6 +2130,8 @@  static struct drm_info_list i915_debugfs_list[] = {
 	{"i915_fbc_status", i915_fbc_status, 0},
 	{"i915_sr_status", i915_sr_status, 0},
 	{"i915_opregion", i915_opregion, 0},
+
+	{"i915_draw_rect",i915_gem_framebuffer_draw_3drect, 0},
 	{"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},
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 624cdfc..e31f305 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -512,7 +512,9 @@  static int i915_drm_freeze(struct drm_device *dev)
 
 	/* If KMS is active, we do the leavevt stuff here */
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-		int error = i915_gem_idle(dev);
+		int error;
+		gen6_suspend_workaround(dev);
+		error = i915_gem_idle(dev);
 		if (error) {
 			dev_err(&dev->pdev->dev,
 				"GEM idle failed, resume might fail\n");
@@ -639,6 +641,10 @@  static int __i915_drm_thaw(struct drm_device *dev)
 		dev_priv->enable_hotplug_processing = true;
 		/* Config may have changed between suspend and resume */
 		intel_resume_hotplug(dev);
+
+		mutex_lock(&dev->struct_mutex);
+		gen6_wakeup_workaround(dev);
+		mutex_unlock(&dev->struct_mutex);
 	}
 
 	intel_opregion_init(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a4234a8..4626e79 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1862,6 +1862,13 @@  extern bool i915_semaphore_is_enabled(struct drm_device *dev);
 int i915_reg_read_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file);
 
+extern void gen6_wakeup_workaround (struct drm_device *dev);
+extern void gen6_suspend_workaround (struct drm_device *dev);
+
+struct intel_framebuffer;
+extern void i915_render_rect(struct drm_device *dev,
+		struct intel_framebuffer *fb, int x, int y, int w, int h);
+
 /* overlay */
 #ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i965_defines.h b/drivers/gpu/drm/i915/i965_defines.h
new file mode 100644
index 0000000..02ee524
--- /dev/null
+++ b/drivers/gpu/drm/i915/i965_defines.h
@@ -0,0 +1,141 @@ 
+#ifndef _I965_DEFINES_H_
+#define _I965_DEFINES_H_
+
+#define CMD(pipeline,op,sub_op)		((3 << 29) |          \
+                                     ((pipeline) << 27) | \
+                                     ((op) << 24) |       \
+                                     ((sub_op) << 16))
+
+#define CMD_STATE_BASE_ADDRESS                  CMD(0, 1, 1)
+#define CMD_STATE_SIP                           CMD(0, 1, 2)
+#define CMD_PIPELINE_SELECT                     CMD(1, 1, 4)
+
+#define CMD_BINDING_TABLE_POINTERS              CMD(3, 0, 1)
+# define GEN6_BINDING_TABLE_MODIFY_PS           (1 << 12)/* for GEN6 */
+# define GEN6_BINDING_TABLE_MODIFY_GS           (1 << 9) /* for GEN6 */
+# define GEN6_BINDING_TABLE_MODIFY_VS           (1 << 8) /* for GEN6 */
+
+#define CMD_VERTEX_BUFFERS                      CMD(3, 0, 8)
+#define CMD_VERTEX_ELEMENTS                     CMD(3, 0, 9)
+#define CMD_DRAWING_RECTANGLE                   CMD(3, 1, 0)
+#define CMD_3DPRIMITIVE                         CMD(3, 3, 0)
+
+#define CMD_DEPTH_BUFFER                        CMD(3, 1, 5)
+# define CMD_DEPTH_BUFFER_TYPE_SHIFT            29
+# define CMD_DEPTH_BUFFER_FORMAT_SHIFT          18
+
+#define CMD_CLEAR_PARAMS                        CMD(3, 1, 0x10)
+/* DW1 */
+# define CMD_CLEAR_PARAMS_DEPTH_CLEAR_VALID     (1 << 15)
+
+/* for GEN6+ */
+#define GEN6_3DSTATE_SAMPLER_STATE_POINTERS	CMD(3, 0, 0x02)
+
+#define GEN6_3DSTATE_URB			CMD(3, 0, 0x05)
+/* DW1 */
+# define GEN6_3DSTATE_URB_VS_SIZE_SHIFT		16
+# define GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT	0
+/* DW2 */
+# define GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT	8
+# define GEN6_3DSTATE_URB_GS_SIZE_SHIFT		0
+
+#define GEN6_3DSTATE_VIEWPORT_STATE_POINTERS	CMD(3, 0, 0x0d)
+# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC		(1 << 12)
+# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_SF		(1 << 11)
+# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CLIP	(1 << 10)
+
+#define GEN6_3DSTATE_CC_STATE_POINTERS		CMD(3, 0, 0x0e)
+
+#define GEN6_3DSTATE_VS				CMD(3, 0, 0x10)
+
+#define GEN6_3DSTATE_GS				CMD(3, 0, 0x11)
+
+#define GEN6_3DSTATE_CLIP			CMD(3, 0, 0x12)
+
+#define GEN6_3DSTATE_SF				CMD(3, 0, 0x13)
+/* DW1 */
+# define GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT		22
+# define GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT	11
+# define GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT	4
+/* DW2 */
+/* DW3 */
+# define GEN6_3DSTATE_SF_CULL_BOTH			(0 << 29)
+# define GEN6_3DSTATE_SF_CULL_NONE			(1 << 29)
+# define GEN6_3DSTATE_SF_CULL_FRONT			(2 << 29)
+# define GEN6_3DSTATE_SF_CULL_BACK			(3 << 29)
+/* DW4 */
+# define GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT		25
+
+
+#define GEN6_3DSTATE_WM				CMD(3, 0, 0x14)
+/* DW2 */
+# define GEN6_3DSTATE_WM_SAMPLER_COUNT_SHIFT			27
+# define GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT	18
+/* DW4 */
+# define GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT		16
+/* DW5 */
+# define GEN6_3DSTATE_WM_MAX_THREADS_SHIFT			25
+# define GEN6_3DSTATE_WM_DISPATCH_ENABLE			(1 << 19)
+# define GEN6_3DSTATE_WM_16_DISPATCH_ENABLE			(1 << 1)
+# define GEN6_3DSTATE_WM_8_DISPATCH_ENABLE			(1 << 0)
+/* DW6 */
+# define GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT			20
+# define GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC		(1 << 10)
+
+
+#define GEN6_3DSTATE_CONSTANT_VS		CMD(3, 0, 0x15)
+#define GEN6_3DSTATE_CONSTANT_GS          	CMD(3, 0, 0x16)
+#define GEN6_3DSTATE_CONSTANT_PS          	CMD(3, 0, 0x17)
+
+#define GEN6_3DSTATE_SAMPLE_MASK		CMD(3, 0, 0x18)
+
+#define I965_SURFACEFORMAT_B8G8R8A8_UNORM	0x0C0
+#define I965_SURFACEFORMAT_R32G32_FLOAT		0x085
+
+
+#define GEN6_3DSTATE_MULTISAMPLE		CMD(3, 1, 0x0d)
+/* DW1 */
+# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER         (0 << 4)
+# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_UPPER_LEFT     (1 << 4)
+# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1                  (0 << 1)
+# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_4                  (2 << 1)
+# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_8                  (3 << 1)
+
+#define I965_DEPTHFORMAT_D32_FLOAT              1
+
+#define BASE_ADDRESS_MODIFY             (1 << 0)
+
+#define PIPELINE_SELECT_3D              0
+#define PIPELINE_SELECT_MEDIA           1
+
+#define I965_SURFACE_2D      1
+#define I965_SURFACE_NULL    7
+
+#define I965_VFCOMPONENT_NOSTORE      0
+#define I965_VFCOMPONENT_STORE_SRC    1
+#define I965_VFCOMPONENT_STORE_1_FLT  3
+
+#define GEN6_VE0_VERTEX_BUFFER_INDEX_SHIFT      26 /* for GEN6 */
+#define GEN6_VE0_VALID                  (1 << 25) /* for GEN6 */
+#define VE0_FORMAT_SHIFT		16
+#define VE0_OFFSET_SHIFT		0
+#define VE1_VFCOMPONENT_0_SHIFT		28
+#define VE1_VFCOMPONENT_1_SHIFT		24
+#define VE1_VFCOMPONENT_2_SHIFT		20
+#define VE1_VFCOMPONENT_3_SHIFT		16
+
+#define GEN6_VB0_BUFFER_INDEX_SHIFT     26
+#define GEN6_VB0_VERTEXDATA             (0 << 20)
+#define GEN6_VB0_INSTANCEDATA           (1 << 20)
+#define VB0_BUFFER_PITCH_SHIFT          0
+
+#define _3DPRIMITIVE_VERTEX_SEQUENTIAL  (0 << 15)
+#define _3DPRIMITIVE_TOPOLOGY_SHIFT     10
+
+#define _3DPRIM_POINTLIST         0x01
+#define _3DPRIM_RECTLIST          0x0F
+
+#define I965_TILEWALK_XMAJOR                 0
+#define I965_TILEWALK_YMAJOR                 1
+
+#endif /* _I965_DEFINES_H_ */
diff --git a/drivers/gpu/drm/i915/intel_3d.c b/drivers/gpu/drm/i915/intel_3d.c
new file mode 100644
index 0000000..629a977
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_3d.c
@@ -0,0 +1,1085 @@ 
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Zou Nan hai <nanhai.zou@intel.com>
+ *
+ */
+#include "intel_drv.h"
+#include "i915_drv.h"
+#include "i915_drm.h"
+#include "i965_defines.h"
+
+#define MAX_SURFACES						17
+
+static const uint32_t ps_kernel[][4] = {
+	{ 0x00600001, 0x200003a2, 0x00000000, 0x00000000 },
+	{ 0x00600001, 0x202003a2, 0x00000020, 0x00000000 },
+	{ 0x00600001, 0x204003fe, 0x00000000, 0x3f800000 },
+	{ 0x00600001, 0x206003fe, 0x00000000, 0x3f800000 },
+	{ 0x00600001, 0x208003fe, 0x00000000, 0x3f800000 },
+	{ 0x00600001, 0x20a003fe, 0x00000000, 0x3f800000 },
+	{ 0x00600001, 0x20c003fe, 0x00000000, 0x3f800000 },
+	{ 0x00600001, 0x20e003fe, 0x00000000, 0x3f800000 },
+	{ 0x00600001, 0x210003fe, 0x00000000, 0x00000000 },
+	{ 0x00600001, 0x212003fe, 0x00000000, 0x00000000 },
+	{ 0x05800031, 0x24001cc8, 0x00000040, 0x90019000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+	{ 0x0000007e, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+struct thread0
+{
+	unsigned int pad0:1;
+	unsigned int grf_reg_count:3;
+	unsigned int pad1:2;
+	unsigned int kernel_start_pointer:26;
+};
+
+struct thread1
+{
+	unsigned int ext_halt_exception_enable:1;
+	unsigned int sw_exception_enable:1;
+	unsigned int mask_stack_exception_enable:1;
+	unsigned int timeout_exception_enable:1;
+	unsigned int illegal_op_exception_enable:1;
+	unsigned int pad0:3;
+	unsigned int depth_coef_urb_read_offset:6;  /* WM only */
+	unsigned int pad1:2;
+	unsigned int floating_point_mode:1;
+	unsigned int thread_priority:1;
+	unsigned int binding_table_entry_count:8;
+	unsigned int pad3:5;
+	unsigned int single_program_flow:1;
+};
+
+struct thread2
+{
+	unsigned int per_thread_scratch_space:4;
+	unsigned int pad0:6;
+	unsigned int scratch_space_base_pointer:22;
+};
+
+
+struct thread3
+{
+	unsigned int dispatch_grf_start_reg:4;
+	unsigned int urb_entry_read_offset:6;
+	unsigned int pad0:1;
+	unsigned int urb_entry_read_length:6;
+	unsigned int pad1:1;
+	unsigned int const_urb_entry_read_offset:6;
+	unsigned int pad2:1;
+	unsigned int const_urb_entry_read_length:6;
+	unsigned int pad3:1;
+};
+
+struct gen6_wm_state {
+	struct thread0 thread0;
+	struct thread1 thread1;
+	struct thread2 thread2;
+	struct thread3 thread3;
+
+	struct {
+		unsigned int stats_enable:1;
+		unsigned int pad0:1;
+		unsigned int sampler_count:3;
+		unsigned int sampler_state_pointer:27;
+	} wm4;
+
+	struct {
+		unsigned int enable_8_pix:1;
+		unsigned int enable_16_pix:1;
+		unsigned int enable_32_pix:1;
+		unsigned int pad0:7;
+		unsigned int legacy_global_depth_bias:1;
+		unsigned int line_stipple:1;
+		unsigned int depth_offset:1;
+		unsigned int polygon_stipple:1;
+		unsigned int line_aa_region_width:2;
+		unsigned int line_endcap_aa_region_width:2;
+		unsigned int early_depth_test:1;
+		unsigned int thread_dispatch_enable:1;
+		unsigned int program_uses_depth:1;
+		unsigned int program_computes_depth:1;
+		unsigned int program_uses_killpixel:1;
+		unsigned int legacy_line_rast: 1;
+		unsigned int transposed_urb_read:1;
+		unsigned int max_threads:7;
+	} wm5;
+	float global_depth_offset_constant;
+	float global_depth_offset_scale;
+};
+
+struct gen6_cc_state {
+	struct {
+		unsigned int alpha_test_format:1;
+		unsigned int pad0:14;
+		unsigned int round_disable:1;
+		unsigned int bf_stencil_ref:8;
+		unsigned int stencil_ref:8;
+	} cc0;
+
+	union {
+		float alpha_ref_f;
+		struct {
+			unsigned int ui:8;
+			unsigned int pad0:24;
+		} alpha_ref_fi;
+	} cc1;
+
+	float constant_r;
+	float constant_g;
+	float constant_b;
+	float constant_a;
+};
+
+struct gen6_cc_viewport {
+	float min_depth;
+	float max_depth;
+};
+
+struct gen6_blend_state {
+	struct {
+		unsigned int dest_blend_factor:5;
+		unsigned int source_blend_factor:5;
+		unsigned int pad3:1;
+		unsigned int blend_func:3;
+		unsigned int pad2:1;
+		unsigned int ia_dest_blend_factor:5;
+		unsigned int ia_source_blend_factor:5;
+		unsigned int pad1:1;
+		unsigned int ia_blend_func:3;
+		unsigned int pad0:1;
+		unsigned int ia_blend_enable:1;
+		unsigned int blend_enable:1;
+	} blend0;
+
+	struct {
+		unsigned int post_blend_clamp_enable:1;
+		unsigned int pre_blend_clamp_enable:1;
+		unsigned int clamp_range:2;
+		unsigned int pad0:4;
+		unsigned int x_dither_offset:2;
+		unsigned int y_dither_offset:2;
+		unsigned int dither_enable:1;
+		unsigned int alpha_test_func:3;
+		unsigned int alpha_test_enable:1;
+		unsigned int pad1:1;
+		unsigned int logic_op_func:4;
+		unsigned int logic_op_enable:1;
+		unsigned int pad2:1;
+		unsigned int write_disable_b:1;
+		unsigned int write_disable_g:1;
+		unsigned int write_disable_r:1;
+		unsigned int write_disable_a:1;
+		unsigned int pad3:1;
+		unsigned int alpha_to_coverage_dither:1;
+		unsigned int alpha_to_one:1;
+		unsigned int alpha_to_coverage:1;
+	} blend1;
+};
+struct gen6_depth_stencil_state
+{
+	struct {
+		unsigned int pad0:3;
+		unsigned int bf_stencil_pass_depth_pass_op:3;
+		unsigned int bf_stencil_pass_depth_fail_op:3;
+		unsigned int bf_stencil_fail_op:3;
+		unsigned int bf_stencil_func:3;
+		unsigned int bf_stencil_enable:1;
+		unsigned int pad1:2;
+		unsigned int stencil_write_enable:1;
+		unsigned int stencil_pass_depth_pass_op:3;
+		unsigned int stencil_pass_depth_fail_op:3;
+		unsigned int stencil_fail_op:3;
+		unsigned int stencil_func:3;
+		unsigned int stencil_enable:1;
+	} ds0;
+
+	struct {
+		unsigned int bf_stencil_write_mask:8;
+		unsigned int bf_stencil_test_mask:8;
+		unsigned int stencil_write_mask:8;
+		unsigned int stencil_test_mask:8;
+	} ds1;
+
+	struct {
+		unsigned int pad0:26;
+		unsigned int depth_write_enable:1;
+		unsigned int depth_test_func:3;
+		unsigned int pad1:1;
+		unsigned int depth_test_enable:1;
+	} ds2;
+};
+
+struct gen6_surface_state {
+	struct {
+		unsigned int cube_pos_z:1;
+		unsigned int cube_neg_z:1;
+		unsigned int cube_pos_y:1;
+		unsigned int cube_neg_y:1;
+		unsigned int cube_pos_x:1;
+		unsigned int cube_neg_x:1;
+		unsigned int pad:2;
+		unsigned int render_cache_read_mode:1;
+		unsigned int cube_map_corner_mode:1;
+		unsigned int mipmap_layout_mode:1;
+		unsigned int vert_line_stride_ofs:1;
+		unsigned int vert_line_stride:1;
+		unsigned int color_blend:1;
+		unsigned int writedisable_blue:1;
+		unsigned int writedisable_green:1;
+		unsigned int writedisable_red:1;
+		unsigned int writedisable_alpha:1;
+		unsigned int surface_format:9;
+		unsigned int data_return_format:1;
+		unsigned int pad0:1;
+		unsigned int surface_type:3;
+	} ss0;
+
+	struct {
+		unsigned int base_addr;
+	} ss1;
+
+	struct {
+		unsigned int render_target_rotation:2;
+		unsigned int mip_count:4;
+		unsigned int width:13;
+		unsigned int height:13;
+	} ss2;
+
+	struct {
+		unsigned int tile_walk:1;
+		unsigned int tiled_surface:1;
+		unsigned int pad:1;
+		unsigned int pitch:18;
+		unsigned int depth:11;
+	} ss3;
+
+	struct {
+		unsigned int pad:19;
+		unsigned int min_array_elt:9;
+		unsigned int min_lod:4;
+	} ss4;
+
+	struct {
+		unsigned int pad:20;
+		unsigned int y_offset:4;
+		unsigned int pad2:1;
+		unsigned int x_offset:7;
+	} ss5;
+};
+
+#define SURFACE_STATE_SIZE ALIGN(sizeof(struct gen6_surface_state), 32)
+#define BINDING_TABLE_OFFSET (SURFACE_STATE_SIZE * MAX_SURFACES)
+
+
+struct gen6_render_context {
+	struct drm_i915_gem_object *vb;
+	struct drm_i915_gem_object *vs_state;
+	struct drm_i915_gem_object *sf_state;
+	struct drm_i915_gem_object *surface_state;
+	struct drm_i915_gem_object *wm_state;
+	struct drm_i915_gem_object *cc_state;
+	struct drm_i915_gem_object *cc_viewport;
+	struct drm_i915_gem_object *cc_blend;
+	struct drm_i915_gem_object *depth_stencil;
+	struct drm_i915_gem_object *ps_kernel;
+};
+
+
+static struct gen6_render_context gen6_rc;
+
+static struct drm_i915_gem_object *
+alloc_and_pin(struct drm_device *dev, int size)
+{
+	struct drm_i915_gem_object *obj;
+	obj = i915_gem_alloc_object(dev, size);
+	if (obj == NULL) {
+		DRM_ERROR("fail to allocate obj\n");
+		return NULL;
+	}
+	if (i915_gem_object_pin(obj, 4096, true, false)) {
+		DRM_ERROR("fail to pin obj\n");
+		drm_gem_object_unreference(&obj->base);
+		return NULL;
+	}
+	return obj;
+}
+
+static void
+unpin_and_free(struct drm_i915_gem_object *obj)
+{
+	i915_gem_object_unpin(obj);
+	drm_gem_object_unreference(&obj->base);
+}
+
+static void init_render_context(struct drm_device *dev)
+{
+	gen6_rc.vb = alloc_and_pin(dev, 4096);
+	if (gen6_rc.vb == NULL) {
+		DRM_DEBUG("failed to alloc vexter buffer\n");
+		goto vb_alloc_fail;
+	}
+
+	gen6_rc.surface_state = alloc_and_pin(dev,
+					      ALIGN(MAX_SURFACES*(SURFACE_STATE_SIZE+4), 4096));
+	if (gen6_rc.surface_state == NULL) {
+		DRM_DEBUG("failed to alloc surface state\n");
+		goto surface_alloc_fail;
+	}
+
+	gen6_rc.wm_state = alloc_and_pin(dev,
+					 ALIGN(sizeof(struct gen6_wm_state), 4096));
+	if (gen6_rc.wm_state == NULL) {
+		DRM_DEBUG("failed to alloc wm state\n");
+		goto wm_alloc_fail;
+	}
+
+	gen6_rc.cc_state = alloc_and_pin(dev,
+					 ALIGN(sizeof(struct gen6_cc_state), 4096));
+	if (gen6_rc.cc_state == NULL) {
+		DRM_DEBUG("failed to alloc cc state\n");
+		goto cc_alloc_fail;
+
+	}
+	gen6_rc.cc_viewport = alloc_and_pin(dev,
+					    ALIGN(sizeof(struct gen6_cc_viewport), 4096));
+	if (gen6_rc.cc_viewport == NULL) {
+		DRM_DEBUG("failed to alloc cc viewport\n");
+		goto cc_vp_alloc_fail;
+	}
+
+	gen6_rc.cc_blend = alloc_and_pin(dev,
+					 ALIGN(sizeof(struct gen6_blend_state), 4096));
+	if (gen6_rc.cc_blend == NULL) {
+		DRM_DEBUG("failed to alloc blend state\n");
+		goto cc_blend_alloc_fail;
+	}
+
+	gen6_rc.depth_stencil = alloc_and_pin(dev,
+					      ALIGN(sizeof(struct gen6_depth_stencil_state), 4096));
+	if (gen6_rc.depth_stencil == NULL) {
+		DRM_DEBUG("failed to alloc depth state\n");
+                goto cc_depth_stencil_alloc_fail;
+        }
+
+	gen6_rc.ps_kernel = alloc_and_pin(dev,
+					  ALIGN(sizeof(ps_kernel), 4096));
+	if (gen6_rc.ps_kernel == NULL) {
+		DRM_DEBUG("failed to alloc ps kernel\n");
+                goto ps_alloc_fail;
+        }
+	return;
+ps_alloc_fail:
+	drm_gem_object_unreference(&gen6_rc.depth_stencil->base);
+cc_depth_stencil_alloc_fail:
+	drm_gem_object_unreference(&gen6_rc.cc_blend->base);
+cc_blend_alloc_fail:
+	drm_gem_object_unreference(&gen6_rc.cc_viewport->base);
+cc_vp_alloc_fail:
+	drm_gem_object_unreference(&gen6_rc.cc_state->base);
+cc_alloc_fail:
+	drm_gem_object_unreference(&gen6_rc.wm_state->base);
+wm_alloc_fail:
+	drm_gem_object_unreference(&gen6_rc.surface_state->base);
+surface_alloc_fail:
+	drm_gem_object_unreference(&gen6_rc.vb->base);
+vb_alloc_fail:
+	return;
+}
+static void *map_buffer(struct drm_device *dev,
+			struct drm_local_map *map,
+			struct drm_i915_gem_object *obj,
+			int size)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	map->size = size;
+	map->offset = dev_priv->gtt.mappable_base + obj->gtt_offset;
+	map->type = 0;
+	map->flags = 0;
+	map->mtrr = 0;
+	drm_core_ioremap_wc(map, dev);
+	return map->handle;
+}
+
+static void upload_point_vertex(struct drm_device *dev)
+{
+	struct drm_local_map map;
+	unsigned int *vb;
+	vb = map_buffer(dev, &map, gen6_rc.vb, 4096);
+	vb[0] = 0;
+	vb[1] = 0;
+	vb[2] = 0;
+	vb[3] = 0;
+	drm_core_ioremapfree(&map, dev);
+}
+
+static void upload_rect_vertex(struct drm_device *dev)
+{
+	struct drm_local_map map;
+	unsigned int *vb;
+	int i;
+	vb = map_buffer(dev, &map, gen6_rc.vb, 4096);
+	i = 0;
+	vb[i++] = 0;
+	vb[i++] = 0;
+	vb[i++] = 0x43480000; /* 200.0 */
+	vb[i++] = 0x43480000; /* 200.0 */
+
+	vb[i++] = 0;
+	vb[i++] = 0;
+	vb[i++] = 0x42c80000; /* 100.0 */
+	vb[i++] = 0x43480000; /* 100.0 */
+
+	vb[i++] = 0;
+	vb[i++] = 0;
+	vb[i++] = 0x42c80000; /* 100.0 */
+	vb[i++] = 0x42c80000; /* 100.0 */
+	drm_core_ioremapfree(&map, dev);
+}
+
+static void
+setup_render_target_wa(struct drm_device *dev)
+{
+	struct drm_local_map map;
+	struct gen6_surface_state *ss;
+	unsigned int *binding_table;
+	ss = map_buffer(dev, &map, gen6_rc.surface_state, SURFACE_STATE_SIZE);
+	memset(ss, 0, SURFACE_STATE_SIZE);
+	ss->ss0.surface_type = I965_SURFACE_NULL;
+	ss->ss0.surface_format = I965_SURFACEFORMAT_B8G8R8A8_UNORM;
+	ss->ss0.color_blend = 0;
+	ss->ss1.base_addr = 0x10000;
+
+	ss->ss2.width = 127;
+	ss->ss2.height = 127;
+	ss->ss2.mip_count = 0;
+	ss->ss2.render_target_rotation = 0;
+	ss->ss3.pitch = 127;
+	binding_table = (unsigned int *)((unsigned char *)ss + BINDING_TABLE_OFFSET);
+	binding_table[0] = 0;
+	drm_core_ioremapfree(&map, dev);
+}
+
+static void
+setup_depth_stencil_wa(struct drm_device *dev)
+{
+	struct drm_local_map map;
+	struct gen6_depth_stencil_state *depth_stencil;
+	depth_stencil = map_buffer (dev, &map, gen6_rc.depth_stencil,
+				    sizeof(*depth_stencil));
+	memset(depth_stencil, 0, sizeof(*depth_stencil));
+	depth_stencil->ds2.depth_test_enable = 1;
+	drm_core_ioremapfree(&map, dev);
+}
+
+static void
+setup_render_target(struct drm_device *dev,
+		    struct intel_framebuffer *fb)
+{
+	struct drm_local_map map;
+	struct gen6_surface_state *ss;
+	unsigned int *binding_table;
+	ss = map_buffer(dev, &map, gen6_rc.surface_state, SURFACE_STATE_SIZE);
+	memset(ss, 0, SURFACE_STATE_SIZE);
+	ss->ss0.surface_type = I965_SURFACE_2D;
+	ss->ss0.surface_format = I965_SURFACEFORMAT_B8G8R8A8_UNORM;
+	ss->ss0.color_blend = 0;
+	ss->ss1.base_addr = fb->obj->gtt_offset;
+
+	ss->ss2.width = fb->base.width - 1;
+	ss->ss2.height = fb->base.height - 1;
+	ss->ss2.mip_count = 0;
+	ss->ss2.render_target_rotation = 0;
+	ss->ss3.pitch = fb->base.pitches[0] - 1;
+	switch (fb->obj->tiling_mode) {
+	case I915_TILING_NONE:
+		ss->ss3.tiled_surface = 0;
+		ss->ss3.tile_walk = 0;
+		break;
+	case I915_TILING_X:
+		ss->ss3.tiled_surface = 1;
+		ss->ss3.tile_walk = I965_TILEWALK_XMAJOR;
+		break;
+	case I915_TILING_Y:
+		ss->ss3.tiled_surface = 1;
+		ss->ss3.tile_walk = I965_TILEWALK_YMAJOR;
+		break;
+	}
+	binding_table = (unsigned int *)((unsigned char *)ss + BINDING_TABLE_OFFSET);
+	binding_table[0] = 0;
+	drm_core_ioremapfree(&map, dev);
+}
+
+static void
+setup_depth_stencil(struct drm_device *dev)
+{
+	struct drm_local_map map;
+	struct gen6_depth_stencil_state *depth_stencil;
+	depth_stencil = map_buffer(dev, &map, gen6_rc.depth_stencil,
+				   sizeof(*depth_stencil));
+	memset(depth_stencil, 0, sizeof(*depth_stencil));
+	drm_core_ioremapfree(&map, dev);
+}
+
+static void init_render_state(struct drm_device *dev)
+{
+	struct drm_local_map map;
+	{
+
+		struct gen6_cc_viewport *vp;
+		vp = map_buffer(dev, &map, gen6_rc.cc_viewport, sizeof(*vp));
+		memset(vp, 0, sizeof(*vp));
+		*(unsigned int *)&vp->min_depth = 0xf99a130c; /* -1.e35 */;
+		*(unsigned int *)&vp->max_depth = 0x799a130c; /* 1.e35 */;
+		drm_core_ioremapfree(&map, dev);
+	}
+	{
+		struct gen6_cc_state *cc;
+		cc = map_buffer(dev, &map, gen6_rc.cc_state, sizeof(*cc));
+		memset(cc, 0, sizeof(*cc));
+		drm_core_ioremapfree(&map, dev);
+	}
+	{
+		struct gen6_blend_state *blend_state;
+		blend_state = map_buffer (dev, &map, gen6_rc.cc_blend,
+					  sizeof(*blend_state));
+		memset(blend_state, 0, sizeof(*blend_state));
+		blend_state->blend1.logic_op_enable = 1;
+		blend_state->blend1.logic_op_func = 0xc;
+		drm_core_ioremapfree(&map, dev);
+	}
+	{
+		unsigned char *kernel;
+		kernel = map_buffer(dev, &map, gen6_rc.ps_kernel,
+				    sizeof(ps_kernel));
+		memcpy(kernel, ps_kernel, sizeof(ps_kernel));
+		drm_core_ioremapfree(&map, dev);
+	}
+}
+
+static int
+gen6_emit_state_base_address(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 10)) != 0)
+		return ret;
+	intel_ring_emit(ring, CMD_STATE_BASE_ADDRESS | (10 - 2));
+	intel_ring_emit(ring, BASE_ADDRESS_MODIFY); /* General state base address */
+	intel_ring_emit(ring,
+			gen6_rc.surface_state->gtt_offset| BASE_ADDRESS_MODIFY); /* Surface state base address */
+	intel_ring_emit(ring, BASE_ADDRESS_MODIFY); /* Dynamic state base address */
+	intel_ring_emit(ring, BASE_ADDRESS_MODIFY); /* Indirect object base address */
+	intel_ring_emit(ring, BASE_ADDRESS_MODIFY); /* Instruction base address */
+	intel_ring_emit (ring, BASE_ADDRESS_MODIFY); /* General state upper bound */
+	intel_ring_emit(ring, BASE_ADDRESS_MODIFY); /* Dynamic state upper bound */
+	intel_ring_emit(ring, BASE_ADDRESS_MODIFY); /* Indirect object upper bound */
+	intel_ring_emit(ring, BASE_ADDRESS_MODIFY); /* Instruction base */
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_invarient_states(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 8)) != 0)
+		return ret;
+	intel_ring_emit(ring, CMD_PIPELINE_SELECT | PIPELINE_SELECT_3D);
+	intel_ring_emit(ring, GEN6_3DSTATE_MULTISAMPLE | (3 - 2));
+	intel_ring_emit(ring, GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER |
+			GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1); /* 1 sample/pixel */
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, GEN6_3DSTATE_SAMPLE_MASK | (2 - 2));
+	intel_ring_emit(ring, 1);
+	intel_ring_emit(ring, CMD_STATE_SIP | 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_viewport_state_pointers(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if (intel_ring_begin(ring, 4))
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_VIEWPORT_STATE_POINTERS |
+			GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC |
+			(4 - 2));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, gen6_rc.cc_viewport->gtt_offset);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_urb(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 3))!= 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_URB | (3 - 2));
+	intel_ring_emit(ring, ((1 - 1) << GEN6_3DSTATE_URB_VS_SIZE_SHIFT) |
+			(24 << GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT));
+	intel_ring_emit(ring, (0 << GEN6_3DSTATE_URB_GS_SIZE_SHIFT) |
+			(24 << GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT));
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static  int
+gen6_emit_cc_state_pointers (struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 4)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_CC_STATE_POINTERS | (4 - 2));
+	intel_ring_emit(ring, gen6_rc.cc_blend->gtt_offset|1);
+	intel_ring_emit(ring, gen6_rc.depth_stencil->gtt_offset|1);
+	intel_ring_emit(ring, gen6_rc.cc_state->gtt_offset| 1);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_sampler_state_pointers(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 4)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_SAMPLER_STATE_POINTERS |
+			(4 - 2));
+	intel_ring_emit(ring, 0); /* VS */
+	intel_ring_emit(ring, 0); /* GS */
+	intel_ring_emit(ring, 0); /* WM */
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_vs_state(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 5)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_CONSTANT_VS | (5 - 2));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+
+	if ((intel_ring_begin(ring, 6)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_VS | (6 - 2));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, (1<<10));
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_gs_state(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 12)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_CONSTANT_GS | (5 - 2));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+
+	intel_ring_emit(ring, GEN6_3DSTATE_GS | (7 - 2));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, (1<<10));
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_clip_state(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 4)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_CLIP | (4 - 2));
+	intel_ring_emit(ring, 1<<10);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_sf_state(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 20)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_SF | (20 - 2));
+	intel_ring_emit(ring, (1 << GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT) |
+			(1 << GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT) |
+			(1 << GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, GEN6_3DSTATE_SF_CULL_NONE);
+	intel_ring_emit(ring, 2 << GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_wm_state(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 5)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_CONSTANT_PS |
+			(5 - 2));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+
+	if ((ret = intel_ring_begin(ring, 9)) != 0)
+		return ret;
+	intel_ring_emit(ring, GEN6_3DSTATE_WM | (9 - 2));
+	intel_ring_emit(ring, gen6_rc.ps_kernel->gtt_offset);
+	intel_ring_emit(ring, (0 << GEN6_3DSTATE_WM_SAMPLER_COUNT_SHIFT) |
+			(5 << GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT));
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, (6 << GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT));
+	intel_ring_emit(ring, ((60 - 1) << GEN6_3DSTATE_WM_MAX_THREADS_SHIFT) |
+			GEN6_3DSTATE_WM_DISPATCH_ENABLE |
+			GEN6_3DSTATE_WM_16_DISPATCH_ENABLE);
+	intel_ring_emit(ring, (1 << GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT) |
+			GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_binding_table(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 4)) != 0)
+		return ret;
+	intel_ring_emit(ring, CMD_BINDING_TABLE_POINTERS |
+			GEN6_BINDING_TABLE_MODIFY_PS |
+			(4 - 2));
+	intel_ring_emit(ring, 0);          /* vs */
+	intel_ring_emit(ring, 0);          /* gs */
+	intel_ring_emit(ring, BINDING_TABLE_OFFSET);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_depth_buffer_state(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret =intel_ring_begin(ring, 9)) != 0)
+		return ret;
+	intel_ring_emit(ring, CMD_DEPTH_BUFFER | (7 - 2));
+	intel_ring_emit(ring,
+			(I965_SURFACE_NULL << CMD_DEPTH_BUFFER_TYPE_SHIFT)
+			| (I965_DEPTHFORMAT_D32_FLOAT << CMD_DEPTH_BUFFER_FORMAT_SHIFT));
+	intel_ring_emit(ring, 0x20000);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+	intel_ring_emit(ring, 0);
+
+	intel_ring_emit(ring, CMD_CLEAR_PARAMS | (2 - 2));
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_drawing_rectangle (struct intel_ring_buffer *ring,
+			     struct intel_framebuffer *fb)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 4)) != 0)
+		return ret;
+	intel_ring_emit(ring, CMD_DRAWING_RECTANGLE | 2);
+	intel_ring_emit(ring, 0x00000000);
+	if (fb)
+		intel_ring_emit(ring, (fb->base.width - 1) | (fb->base.height - 1) << 16);
+	else	/* workaournd code */
+		intel_ring_emit(ring, 127 | (127 << 16));
+
+	intel_ring_emit(ring, 0x00000000);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_vertex_element_state(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 5)) != 0)
+		return ret;
+	intel_ring_emit(ring, CMD_VERTEX_ELEMENTS | (5 - 2));
+	intel_ring_emit(ring, (0 << GEN6_VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+			GEN6_VE0_VALID |
+			(I965_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) |
+			(0 << VE0_OFFSET_SHIFT));
+	intel_ring_emit(ring, (I965_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+			(I965_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) |
+			(I965_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT) |
+			(I965_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT));
+	intel_ring_emit(ring, (0 << GEN6_VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+			GEN6_VE0_VALID |
+			(I965_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) |
+			(8 << VE0_OFFSET_SHIFT));
+	intel_ring_emit(ring, (I965_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+			(I965_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) |
+			(I965_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT) |
+			(I965_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT));
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+emit_vertex_buffer(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 5)) != 0)
+		return ret;
+	intel_ring_emit(ring, CMD_VERTEX_BUFFERS | 3);
+	intel_ring_emit(ring,
+			(0 << GEN6_VB0_BUFFER_INDEX_SHIFT) |
+			GEN6_VB0_VERTEXDATA |
+			((4 * 4) << VB0_BUFFER_PITCH_SHIFT));
+	intel_ring_emit(ring, gen6_rc.vb->gtt_offset);
+	intel_ring_emit(ring, gen6_rc.vb->gtt_offset + 4096);
+	intel_ring_emit(ring, 0);
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_rect_vertex(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 6)) != 0)
+		return ret;
+	intel_ring_emit(ring,
+			CMD_3DPRIMITIVE |
+			_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+			(_3DPRIM_RECTLIST << _3DPRIMITIVE_TOPOLOGY_SHIFT) |
+			(0 << 9) |
+			4);
+	intel_ring_emit(ring, 3); /* vertex count per instance */
+	intel_ring_emit(ring, 0); /* start vertex offset */
+	intel_ring_emit(ring, 1); /* single instance */
+	intel_ring_emit(ring, 0); /* start instance location */
+	intel_ring_emit(ring, 0); /* index buffer offset, ignored */
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static int
+gen6_emit_point_vertex(struct intel_ring_buffer *ring)
+{
+	int ret;
+	if ((ret = intel_ring_begin(ring, 6)) != 0)
+		return ret;
+	intel_ring_emit(ring,
+			CMD_3DPRIMITIVE |
+			_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+			(_3DPRIM_POINTLIST << _3DPRIMITIVE_TOPOLOGY_SHIFT) |
+			(0 << 9) |
+			4);
+	intel_ring_emit(ring, 1); /* vertex count per instance */
+	intel_ring_emit(ring, 0); /* start vertex offset */
+	intel_ring_emit(ring, 1); /* single instance */
+	intel_ring_emit(ring, 0); /* start instance location */
+	intel_ring_emit(ring, 0); /* index buffer offset, ignored */
+	intel_ring_advance(ring);
+	return 0;
+}
+
+static void
+gen6_emit_wa(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+
+	upload_point_vertex(dev);
+	setup_render_target_wa(dev);
+	setup_depth_stencil_wa(dev);
+
+	gen6_emit_invarient_states(ring);
+	gen6_emit_state_base_address(ring);
+	gen6_emit_viewport_state_pointers(ring);
+	gen6_emit_urb(ring);
+	gen6_emit_cc_state_pointers(ring);
+	gen6_emit_sampler_state_pointers(ring);
+	gen6_emit_vs_state(ring);
+	gen6_emit_gs_state(ring);
+	gen6_emit_clip_state(ring);
+	gen6_emit_sf_state(ring);
+	gen6_emit_wm_state(ring);
+	gen6_emit_binding_table(ring);
+	gen6_emit_drawing_rectangle(ring, NULL);
+	gen6_emit_vertex_element_state(ring);
+	emit_vertex_buffer(ring);
+	gen6_emit_point_vertex(ring);
+	if (intel_ring_flush_all_caches(ring)) {
+		DRM_ERROR("fail to flush ring \n");
+		return;
+	}
+	if (intel_ring_idle(ring)) {
+		DRM_ERROR("fail to wait ring idle\n");
+		return;
+	}
+}
+
+static void
+gen6_emit_rect(struct drm_device *dev,
+	       struct intel_framebuffer *fb,
+	       int x, int y, int w, int h)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+	u32 seqno;
+	int ret;
+
+	upload_rect_vertex(dev);
+	setup_render_target(dev, fb);
+	setup_depth_stencil(dev);
+
+	gen6_emit_invarient_states(ring);
+	gen6_emit_state_base_address(ring);
+	gen6_emit_viewport_state_pointers(ring);
+	gen6_emit_urb(ring);
+	gen6_emit_cc_state_pointers(ring);
+	gen6_emit_sampler_state_pointers(ring);
+	gen6_emit_vs_state(ring);
+	gen6_emit_gs_state(ring);
+	gen6_emit_clip_state(ring);
+	gen6_emit_sf_state(ring);
+	gen6_emit_wm_state(ring);
+	gen6_emit_binding_table(ring);
+	gen6_emit_depth_buffer_state(ring);
+	gen6_emit_drawing_rectangle(ring, fb);
+	gen6_emit_vertex_element_state(ring);
+	emit_vertex_buffer(ring);
+	gen6_emit_rect_vertex(ring);
+	ret = i915_add_request(ring, NULL, &seqno);
+	if (ret)
+		return;
+
+	if (intel_ring_flush_all_caches(ring)) {
+		DRM_ERROR("fail to flush ring \n");
+		return;
+	}
+
+	if (i915_wait_seqno(ring, seqno)) {
+		DRM_ERROR("fail to wait request\n");
+		return;
+	}
+}
+
+static void
+release_render_context(struct drm_device *dev)
+{
+	unpin_and_free(gen6_rc.surface_state);
+	unpin_and_free(gen6_rc.wm_state);
+	unpin_and_free(gen6_rc.cc_state);
+	unpin_and_free(gen6_rc.cc_viewport);
+	unpin_and_free(gen6_rc.cc_blend);
+	unpin_and_free(gen6_rc.depth_stencil);
+	unpin_and_free(gen6_rc.ps_kernel);
+}
+
+void i915_render_rect(struct drm_device *dev,
+		      struct intel_framebuffer *fb,
+		      int x, int y, int w, int h)
+{
+	if (INTEL_INFO(dev)->gen == 6) {
+		mutex_lock(&dev->struct_mutex);
+		init_render_context(dev);
+		init_render_state(dev);
+		gen6_emit_rect(dev, fb, x, y, w, h);
+		release_render_context(dev);
+		mutex_unlock(&dev->struct_mutex);
+	}
+}
+
+void gen6_suspend_workaround(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+	if (INTEL_INFO(dev)->gen < 6)
+		return;
+	gen6_emit_depth_buffer_state(ring);
+}
+
+void gen6_wakeup_workaround(struct drm_device *dev)
+{
+	if (INTEL_INFO(dev)->gen < 6)
+		return;
+	init_render_context(dev);
+	init_render_state(dev);
+	gen6_emit_wa(dev);
+	release_render_context(dev);
+}