From 3a6fa9849e02cab3eceff9f7f308dbbc5b5e7231 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:47 -0800 Subject: drm/i915: Initial command parser table definitions Add command tables defining irregular length commands for each ring. This requires a few new command opcode definitions. v2: Whitespace adjustment in command definitions, sparse fix for !F OTC-Tracker: AXIA-4631 Change-Id: I064bceb457e15f46928058352afe76d918c58ef5 Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 157 +++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 0eaed44aee6d..d0f9a6fb7ba3 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -86,6 +86,148 @@ * general bitmasking mechanism. */ +#define STD_MI_OPCODE_MASK 0xFF800000 +#define STD_3D_OPCODE_MASK 0xFFFF0000 +#define STD_2D_OPCODE_MASK 0xFFC00000 +#define STD_MFX_OPCODE_MASK 0xFFFF0000 + +#define CMD(op, opm, f, lm, fl, ...) \ + { \ + .flags = (fl) | ((f) ? CMD_DESC_FIXED : 0), \ + .cmd = { (op), (opm) }, \ + .length = { (lm) }, \ + __VA_ARGS__ \ + } + +/* Convenience macros to compress the tables */ +#define SMI STD_MI_OPCODE_MASK +#define S3D STD_3D_OPCODE_MASK +#define S2D STD_2D_OPCODE_MASK +#define SMFX STD_MFX_OPCODE_MASK +#define F true +#define S CMD_DESC_SKIP +#define R CMD_DESC_REJECT +#define W CMD_DESC_REGISTER +#define B CMD_DESC_BITMASK +#define M CMD_DESC_MASTER + +/* Command Mask Fixed Len Action + ---------------------------------------------------------- */ +static const struct drm_i915_cmd_descriptor common_cmds[] = { + CMD( MI_NOOP, SMI, F, 1, S ), + CMD( MI_USER_INTERRUPT, SMI, F, 1, S ), + CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, S ), + CMD( MI_ARB_CHECK, SMI, F, 1, S ), + CMD( MI_REPORT_HEAD, SMI, F, 1, S ), + CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), + CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, S ), + CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, S ), + CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, S ), + CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, S ), + CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, S ), + CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), +}; + +static const struct drm_i915_cmd_descriptor render_cmds[] = { + CMD( MI_FLUSH, SMI, F, 1, S ), + CMD( MI_ARB_ON_OFF, SMI, F, 1, S ), + CMD( MI_PREDICATE, SMI, F, 1, S ), + CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ), + CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, S ), + CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, S ), + CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), + CMD( MI_UPDATE_GTT, SMI, !F, 0xFF, S ), + CMD( MI_CLFLUSH, SMI, !F, 0x3FF, S ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), + CMD( GFX_OP_3DSTATE_VF_STATISTICS, S3D, F, 1, S ), + CMD( PIPELINE_SELECT, S3D, F, 1, S ), + CMD( GPGPU_OBJECT, S3D, !F, 0xFF, S ), + CMD( GPGPU_WALKER, S3D, !F, 0xFF, S ), + CMD( GFX_OP_3DSTATE_SO_DECL_LIST, S3D, !F, 0x1FF, S ), +}; + +static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { + CMD( MI_SET_PREDICATE, SMI, F, 1, S ), + CMD( MI_RS_CONTROL, SMI, F, 1, S ), + CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), + CMD( MI_RS_CONTEXT, SMI, F, 1, S ), + CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, S ), + CMD( MI_RS_STORE_DATA_IMM, SMI, !F, 0xFF, S ), + CMD( MI_LOAD_URB_MEM, SMI, !F, 0xFF, S ), + CMD( MI_STORE_URB_MEM, SMI, !F, 0xFF, S ), + CMD( GFX_OP_3DSTATE_DX9_CONSTANTF_VS, S3D, !F, 0x7FF, S ), + CMD( GFX_OP_3DSTATE_DX9_CONSTANTF_PS, S3D, !F, 0x7FF, S ), + + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS, S3D, !F, 0x1FF, S ), +}; + +static const struct drm_i915_cmd_descriptor video_cmds[] = { + CMD( MI_ARB_ON_OFF, SMI, F, 1, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), + /* + * MFX_WAIT doesn't fit the way we handle length for most commands. + * It has a length field but it uses a non-standard length bias. + * It is always 1 dword though, so just treat it as fixed length. + */ + CMD( MFX_WAIT, SMFX, F, 1, S ), +}; + +static const struct drm_i915_cmd_descriptor vecs_cmds[] = { + CMD( MI_ARB_ON_OFF, SMI, F, 1, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), +}; + +static const struct drm_i915_cmd_descriptor blt_cmds[] = { + CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, S ), + CMD( COLOR_BLT, S2D, !F, 0x3F, S ), + CMD( SRC_COPY_BLT, S2D, !F, 0x3F, S ), +}; + +#undef CMD +#undef SMI +#undef S3D +#undef S2D +#undef SMFX +#undef F +#undef S +#undef R +#undef W +#undef B +#undef M + +static const struct drm_i915_cmd_table gen7_render_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { render_cmds, ARRAY_SIZE(render_cmds) }, +}; + +static const struct drm_i915_cmd_table hsw_render_ring_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { render_cmds, ARRAY_SIZE(render_cmds) }, + { hsw_render_cmds, ARRAY_SIZE(hsw_render_cmds) }, +}; + +static const struct drm_i915_cmd_table gen7_video_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { video_cmds, ARRAY_SIZE(video_cmds) }, +}; + +static const struct drm_i915_cmd_table hsw_vebox_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { vecs_cmds, ARRAY_SIZE(vecs_cmds) }, +}; + +static const struct drm_i915_cmd_table gen7_blt_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { blt_cmds, ARRAY_SIZE(blt_cmds) }, +}; + static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) { u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; @@ -200,15 +342,30 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) switch (ring->id) { case RCS: + if (IS_HASWELL(ring->dev)) { + ring->cmd_tables = hsw_render_ring_cmds; + ring->cmd_table_count = + ARRAY_SIZE(hsw_render_ring_cmds); + } else { + ring->cmd_tables = gen7_render_cmds; + ring->cmd_table_count = ARRAY_SIZE(gen7_render_cmds); + } + ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; break; case VCS: + ring->cmd_tables = gen7_video_cmds; + ring->cmd_table_count = ARRAY_SIZE(gen7_video_cmds); ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; case BCS: + ring->cmd_tables = gen7_blt_cmds; + ring->cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; break; case VECS: + ring->cmd_tables = hsw_vebox_cmds; + ring->cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds); /* VECS can use the same length_mask function as VCS */ ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; -- cgit v1.2.1 From 9c640d1d5132d8f3c699c62170dbfb6928ff8d96 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:48 -0800 Subject: drm/i915: Reject privileged commands The spec defines most of these commands as privileged. A few others, like the semaphore mbox command and some display commands, are also reserved for the driver's use. Subsequent patches relax some of these restrictions. v2: Rebased Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 54 ++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index d0f9a6fb7ba3..717aa693b3c8 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -116,27 +116,27 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_NOOP, SMI, F, 1, S ), CMD( MI_USER_INTERRUPT, SMI, F, 1, S ), - CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, S ), + CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, R ), CMD( MI_ARB_CHECK, SMI, F, 1, S ), CMD( MI_REPORT_HEAD, SMI, F, 1, S ), CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), - CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, S ), - CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, S ), - CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, S ), - CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, S ), - CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, S ), + CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), + CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), + CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, R ), + CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, R ), + CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, R ), CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), }; static const struct drm_i915_cmd_descriptor render_cmds[] = { CMD( MI_FLUSH, SMI, F, 1, S ), - CMD( MI_ARB_ON_OFF, SMI, F, 1, S ), + CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_PREDICATE, SMI, F, 1, S ), CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ), - CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, S ), - CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, S ), + CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), + CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ), CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), - CMD( MI_UPDATE_GTT, SMI, !F, 0xFF, S ), + CMD( MI_UPDATE_GTT, SMI, !F, 0xFF, R ), CMD( MI_CLFLUSH, SMI, !F, 0x3FF, S ), CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), CMD( GFX_OP_3DSTATE_VF_STATISTICS, S3D, F, 1, S ), @@ -151,7 +151,9 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { CMD( MI_RS_CONTROL, SMI, F, 1, S ), CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), CMD( MI_RS_CONTEXT, SMI, F, 1, S ), - CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, S ), + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ), + CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), + CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, R ), CMD( MI_RS_STORE_DATA_IMM, SMI, !F, 0xFF, S ), CMD( MI_LOAD_URB_MEM, SMI, !F, 0xFF, S ), CMD( MI_STORE_URB_MEM, SMI, !F, 0xFF, S ), @@ -166,8 +168,9 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { }; static const struct drm_i915_cmd_descriptor video_cmds[] = { - CMD( MI_ARB_ON_OFF, SMI, F, 1, S ), + CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), + CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), /* * MFX_WAIT doesn't fit the way we handle length for most commands. @@ -178,18 +181,25 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = { }; static const struct drm_i915_cmd_descriptor vecs_cmds[] = { - CMD( MI_ARB_ON_OFF, SMI, F, 1, S ), + CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), + CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), }; static const struct drm_i915_cmd_descriptor blt_cmds[] = { - CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, S ), + CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, S ), + CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), CMD( COLOR_BLT, S2D, !F, 0x3F, S ), CMD( SRC_COPY_BLT, S2D, !F, 0x3F, S ), }; +static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = { + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ), + CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), +}; + #undef CMD #undef SMI #undef S3D @@ -228,6 +238,12 @@ static const struct drm_i915_cmd_table gen7_blt_cmds[] = { { blt_cmds, ARRAY_SIZE(blt_cmds) }, }; +static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { blt_cmds, ARRAY_SIZE(blt_cmds) }, + { hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) }, +}; + static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) { u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; @@ -359,8 +375,14 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; case BCS: - ring->cmd_tables = gen7_blt_cmds; - ring->cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); + if (IS_HASWELL(ring->dev)) { + ring->cmd_tables = hsw_blt_ring_cmds; + ring->cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds); + } else { + ring->cmd_tables = gen7_blt_cmds; + ring->cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); + } + ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; break; case VECS: -- cgit v1.2.1 From 17c1eb15b02e864547e758fe92e400b3d62a2631 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:49 -0800 Subject: drm/i915: Allow some privileged commands from master The Intel DDX uses these to implement scanline waits in the X server. Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 717aa693b3c8..7b80a84345a0 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -116,7 +116,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_NOOP, SMI, F, 1, S ), CMD( MI_USER_INTERRUPT, SMI, F, 1, S ), - CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, R ), + CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, M ), CMD( MI_ARB_CHECK, SMI, F, 1, S ), CMD( MI_REPORT_HEAD, SMI, F, 1, S ), CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), @@ -151,7 +151,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { CMD( MI_RS_CONTROL, SMI, F, 1, S ), CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), CMD( MI_RS_CONTEXT, SMI, F, 1, S ), - CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ), + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, R ), CMD( MI_RS_STORE_DATA_IMM, SMI, !F, 0xFF, S ), @@ -196,7 +196,7 @@ static const struct drm_i915_cmd_descriptor blt_cmds[] = { }; static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = { - CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ), + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), }; -- cgit v1.2.1 From 5947de9b46d472f9596f77bb5a1655c0d6c99f7e Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:50 -0800 Subject: drm/i915: Add register whitelists for mesa These registers are currently used by mesa for blitting, transform feedback extensions, and performance monitoring extensions. v2: REG64 macro Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 7b80a84345a0..7249b512571d 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -244,6 +244,45 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { { hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) }, }; +/* + * Register whitelists, sorted by increasing register offset. + * + * Some registers that userspace accesses are 64 bits. The register + * access commands only allow 32-bit accesses. Hence, we have to include + * entries for both halves of the 64-bit registers. + */ + +/* Convenience macro for adding 64-bit registers */ +#define REG64(addr) (addr), (addr + sizeof(u32)) + +static const u32 gen7_render_regs[] = { + REG64(HS_INVOCATION_COUNT), + REG64(DS_INVOCATION_COUNT), + REG64(IA_VERTICES_COUNT), + REG64(IA_PRIMITIVES_COUNT), + REG64(VS_INVOCATION_COUNT), + REG64(GS_INVOCATION_COUNT), + REG64(GS_PRIMITIVES_COUNT), + REG64(CL_INVOCATION_COUNT), + REG64(CL_PRIMITIVES_COUNT), + REG64(PS_INVOCATION_COUNT), + REG64(PS_DEPTH_COUNT), + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)), + GEN7_SO_WRITE_OFFSET(0), + GEN7_SO_WRITE_OFFSET(1), + GEN7_SO_WRITE_OFFSET(2), + GEN7_SO_WRITE_OFFSET(3), +}; + +static const u32 gen7_blt_regs[] = { + BCS_SWCTRL, +}; + +#undef REG64 + static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) { u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; @@ -367,6 +406,9 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) ring->cmd_table_count = ARRAY_SIZE(gen7_render_cmds); } + ring->reg_table = gen7_render_regs; + ring->reg_count = ARRAY_SIZE(gen7_render_regs); + ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; break; case VCS: @@ -383,6 +425,9 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) ring->cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); } + ring->reg_table = gen7_blt_regs; + ring->reg_count = ARRAY_SIZE(gen7_blt_regs); + ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; break; case VECS: -- cgit v1.2.1 From 220375aa12c95744cd71d236f7c1ee39d277b6ed Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:51 -0800 Subject: drm/i915: Add register whitelist for DRM master These are used to implement scanline waits in the X server. v2: Use #defines instead of magic numbers Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 7249b512571d..0182c7cee32a 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -281,6 +281,19 @@ static const u32 gen7_blt_regs[] = { BCS_SWCTRL, }; +static const u32 ivb_master_regs[] = { + FORCEWAKE_MT, + DERRMR, + GEN7_PIPE_DE_LOAD_SL(PIPE_A), + GEN7_PIPE_DE_LOAD_SL(PIPE_B), + GEN7_PIPE_DE_LOAD_SL(PIPE_C), +}; + +static const u32 hsw_master_regs[] = { + FORCEWAKE_MT, + DERRMR, +}; + #undef REG64 static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) @@ -409,6 +422,14 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) ring->reg_table = gen7_render_regs; ring->reg_count = ARRAY_SIZE(gen7_render_regs); + if (IS_HASWELL(ring->dev)) { + ring->master_reg_table = hsw_master_regs; + ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); + } else { + ring->master_reg_table = ivb_master_regs; + ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); + } + ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; break; case VCS: @@ -428,6 +449,14 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) ring->reg_table = gen7_blt_regs; ring->reg_count = ARRAY_SIZE(gen7_blt_regs); + if (IS_HASWELL(ring->dev)) { + ring->master_reg_table = hsw_master_regs; + ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); + } else { + ring->master_reg_table = ivb_master_regs; + ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); + } + ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; break; case VECS: -- cgit v1.2.1 From f0a346bdafaf6fc4a51df9ddf1548fd888f860d8 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:52 -0800 Subject: drm/i915: Enable register whitelist checks MI_STORE_REGISTER_MEM, MI_LOAD_REGISTER_MEM, and MI_LOAD_REGISTER_IMM commands allow userspace access to registers. Only certain registers should be allowed for such access, so enable checking for those commands. Each ring gets its own register whitelist. MI_LOAD_REGISTER_REG on HSW also allows register access but is currently unused by userspace components. Leave it rejected. PIPE_CONTROL and MEDIA_VFE_STATE allow register access based on certain bits being set. Reject those as well. v2: trailing commas, rebased OTC-Tracker: AXIA-4631 Change-Id: Ie614a2f0eb2e5917de809e5a17957175d24cc44f Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 0182c7cee32a..1c313090efdc 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -122,9 +122,12 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), - CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, R ), - CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, R ), - CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, R ), + CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, + .reg = { .offset = 1, .mask = 0x007FFFFC } ), + CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W, + .reg = { .offset = 1, .mask = 0x007FFFFC } ), + CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, W, + .reg = { .offset = 1, .mask = 0x007FFFFC } ), CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), }; @@ -141,9 +144,21 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = { CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), CMD( GFX_OP_3DSTATE_VF_STATISTICS, S3D, F, 1, S ), CMD( PIPELINE_SELECT, S3D, F, 1, S ), + CMD( MEDIA_VFE_STATE, S3D, !F, 0xFFFF, B, + .bits = {{ + .offset = 2, + .mask = MEDIA_VFE_STATE_MMIO_ACCESS_MASK, + .expected = 0, + }}, ), CMD( GPGPU_OBJECT, S3D, !F, 0xFF, S ), CMD( GPGPU_WALKER, S3D, !F, 0xFF, S ), CMD( GFX_OP_3DSTATE_SO_DECL_LIST, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_PIPE_CONTROL(5), S3D, !F, 0xFF, B, + .bits = {{ + .offset = 1, + .mask = PIPE_CONTROL_MMIO_WRITE, + .expected = 0, + }}, ), }; static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { -- cgit v1.2.1 From b18b396b3a9a7f2a468bbcefa0ae09451b5ec832 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:53 -0800 Subject: drm/i915: Reject commands that explicitly generate interrupts The driver leaves most interrupts masked during normal operation, so there would have to be additional work to enable userspace to safely request/receive an interrupt. v2: trailing commas, rebased Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 1c313090efdc..d0e3fec73d3e 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -115,7 +115,7 @@ ---------------------------------------------------------- */ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_NOOP, SMI, F, 1, S ), - CMD( MI_USER_INTERRUPT, SMI, F, 1, S ), + CMD( MI_USER_INTERRUPT, SMI, F, 1, R ), CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, M ), CMD( MI_ARB_CHECK, SMI, F, 1, S ), CMD( MI_REPORT_HEAD, SMI, F, 1, S ), @@ -156,7 +156,7 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = { CMD( GFX_OP_PIPE_CONTROL(5), S3D, !F, 0xFF, B, .bits = {{ .offset = 1, - .mask = PIPE_CONTROL_MMIO_WRITE, + .mask = (PIPE_CONTROL_MMIO_WRITE | PIPE_CONTROL_NOTIFY), .expected = 0, }}, ), }; @@ -186,6 +186,12 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), + CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_FLUSH_DW_NOTIFY, + .expected = 0, + }}, ), CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), /* * MFX_WAIT doesn't fit the way we handle length for most commands. @@ -199,6 +205,12 @@ static const struct drm_i915_cmd_descriptor vecs_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), + CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_FLUSH_DW_NOTIFY, + .expected = 0, + }}, ), CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), }; @@ -206,6 +218,12 @@ static const struct drm_i915_cmd_descriptor blt_cmds[] = { CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, S ), CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), + CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_FLUSH_DW_NOTIFY, + .expected = 0, + }}, ), CMD( COLOR_BLT, S2D, !F, 0x3F, S ), CMD( SRC_COPY_BLT, S2D, !F, 0x3F, S ), }; -- cgit v1.2.1 From d4d4803513af986a5280d810e093cd2bc2e71d88 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:54 -0800 Subject: drm/i915: Enable PPGTT command parser checks Various commands that access memory have a bit to determine whether the graphics address specified in the command should use the GGTT or PPGTT for translation. These checks ensure that the bit indicates PPGTT translation. Most of these checks use the existing bit-checking infrastructure. The PIPE_CONTROL and MI_FLUSH_DW commands, however, are multi-function commands. The GGTT/PPGTT bit is only relevant for certain uses of the command. As such, this change also extends the bit-checking code to include a "condition" mask and offset. If the condition mask is non-zero then the parser only performs the bit check when the bits specified by the condition mask/offset are also non-zero. NOTE: At this point in the series PPGTT must be enabled for the parser to work correctly. If it's not enabled, userspace will not be setting the PPGTT bits the way the parser requires. VLV is the only platform where this is a problem, so at this point, we disable parsing for VLV. v2: whitespace and trailing commas fixes, rebased OTC-Tracker: AXIA-4631 Change-Id: I3f4c76b6734f1956ec47e698230f97d0998ff92b Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula [danvet: Drop the unecessary cast Jani spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 127 ++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index d0e3fec73d3e..bf4ffd8826ba 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -124,10 +124,20 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, .reg = { .offset = 1, .mask = 0x007FFFFC } ), - CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W, - .reg = { .offset = 1, .mask = 0x007FFFFC } ), - CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, W, - .reg = { .offset = 1, .mask = 0x007FFFFC } ), + CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, + .reg = { .offset = 1, .mask = 0x007FFFFC }, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, W | B, + .reg = { .offset = 1, .mask = 0x007FFFFC }, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), }; @@ -139,9 +149,31 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = { CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ), CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), CMD( MI_UPDATE_GTT, SMI, !F, 0xFF, R ), - CMD( MI_CLFLUSH, SMI, !F, 0x3FF, S ), - CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), + CMD( MI_CLFLUSH, SMI, !F, 0x3FF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_REPORT_PERF_COUNT, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 1, + .mask = MI_REPORT_PERF_COUNT_GGTT, + .expected = 0, + }}, ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), CMD( GFX_OP_3DSTATE_VF_STATISTICS, S3D, F, 1, S ), CMD( PIPELINE_SELECT, S3D, F, 1, S ), CMD( MEDIA_VFE_STATE, S3D, !F, 0xFFFF, B, @@ -158,6 +190,13 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = { .offset = 1, .mask = (PIPE_CONTROL_MMIO_WRITE | PIPE_CONTROL_NOTIFY), .expected = 0, + }, + { + .offset = 1, + .mask = PIPE_CONTROL_GLOBAL_GTT_IVB, + .expected = 0, + .condition_offset = 1, + .condition_mask = PIPE_CONTROL_POST_SYNC_OP_MASK, }}, ), }; @@ -184,15 +223,32 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { static const struct drm_i915_cmd_descriptor video_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), - CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, .bits = {{ .offset = 0, .mask = MI_FLUSH_DW_NOTIFY, .expected = 0, + }, + { + .offset = 1, + .mask = MI_FLUSH_DW_USE_GTT, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }}, ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, }}, ), - CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), /* * MFX_WAIT doesn't fit the way we handle length for most commands. * It has a length field but it uses a non-standard length bias. @@ -203,26 +259,55 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = { static const struct drm_i915_cmd_descriptor vecs_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), - CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, .bits = {{ .offset = 0, .mask = MI_FLUSH_DW_NOTIFY, .expected = 0, + }, + { + .offset = 1, + .mask = MI_FLUSH_DW_USE_GTT, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }}, ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, }}, ), - CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, S ), }; static const struct drm_i915_cmd_descriptor blt_cmds[] = { CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), - CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, .bits = {{ .offset = 0, .mask = MI_FLUSH_DW_NOTIFY, .expected = 0, + }, + { + .offset = 1, + .mask = MI_FLUSH_DW_USE_GTT, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, }}, ), CMD( COLOR_BLT, S2D, !F, 0x3F, S ), CMD( SRC_COPY_BLT, S2D, !F, 0x3F, S ), @@ -617,10 +702,20 @@ finish: */ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) { + drm_i915_private_t *dev_priv = ring->dev->dev_private; + /* No command tables indicates a platform without parsing */ if (!ring->cmd_tables) return false; + /* + * XXX: VLV is Gen7 and therefore has cmd_tables, but has PPGTT + * disabled. That will cause all of the parser's PPGTT checks to + * fail. For now, disable parsing when PPGTT is off. + */ + if (!dev_priv->mm.aliasing_ppgtt) + return false; + return (i915.enable_cmd_parser == 1); } @@ -737,6 +832,16 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, if (desc->bits[i].mask == 0) break; + if (desc->bits[i].condition_mask != 0) { + u32 offset = + desc->bits[i].condition_offset; + u32 condition = cmd[offset] & + desc->bits[i].condition_mask; + + if (condition == 0) + continue; + } + dword = cmd[desc->bits[i].offset] & desc->bits[i].mask; -- cgit v1.2.1 From 114d4f700878405a9fd65a6ade4f981514b82919 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:55 -0800 Subject: drm/i915: Reject commands that would store to global HWS page PIPE_CONTROL and MI_FLUSH_DW have bits that would write to the hardware status page. The driver stores request tracking info there, so don't let userspace overwrite it. v2: trailing comma fix, rebased Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index bf4ffd8826ba..a8f00dbc0dde 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -193,7 +193,8 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = { }, { .offset = 1, - .mask = PIPE_CONTROL_GLOBAL_GTT_IVB, + .mask = (PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_STORE_DATA_INDEX), .expected = 0, .condition_offset = 1, .condition_mask = PIPE_CONTROL_POST_SYNC_OP_MASK, @@ -242,6 +243,13 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = { .expected = 0, .condition_offset = 0, .condition_mask = MI_FLUSH_DW_OP_MASK, + }, + { + .offset = 0, + .mask = MI_FLUSH_DW_STORE_INDEX, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, }}, ), CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, .bits = {{ @@ -278,6 +286,13 @@ static const struct drm_i915_cmd_descriptor vecs_cmds[] = { .expected = 0, .condition_offset = 0, .condition_mask = MI_FLUSH_DW_OP_MASK, + }, + { + .offset = 0, + .mask = MI_FLUSH_DW_STORE_INDEX, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, }}, ), CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, .bits = {{ @@ -308,6 +323,13 @@ static const struct drm_i915_cmd_descriptor blt_cmds[] = { .expected = 0, .condition_offset = 0, .condition_mask = MI_FLUSH_DW_OP_MASK, + }, + { + .offset = 0, + .mask = MI_FLUSH_DW_STORE_INDEX, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, }}, ), CMD( COLOR_BLT, S2D, !F, 0x3F, S ), CMD( SRC_COPY_BLT, S2D, !F, 0x3F, S ), -- cgit v1.2.1 From d728c8ef8bea6e81f44933c0237531cda499577e Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:56 -0800 Subject: drm/i915: Add a CMD_PARSER_VERSION getparam So userspace can query the kernel for command parser support. v2: Add i915_cmd_parser_get_version(), history log, and kerneldoc OTC-Tracker: AXIA-4631 Change-Id: I58af650db9f6753c2dcac9c54ab432fd31db302f Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index a8f00dbc0dde..bae7c2f33692 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -896,3 +896,22 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, return ret; } + +/** + * i915_cmd_parser_get_version() - get the cmd parser version number + * + * The cmd parser maintains a simple increasing integer version number suitable + * for passing to userspace clients to determine what operations are permitted. + * + * Return: the current version number of the cmd parser + */ +int i915_cmd_parser_get_version(void) +{ + /* + * Command parser version history + * + * 1. Initial version. Checks batches and reports violations, but leaves + * hardware parsing enabled (so does not allow new use cases). + */ + return 1; +} -- cgit v1.2.1 From 180b813ced1d1341c07f25e5195228100921d327 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Tue, 25 Mar 2014 22:52:03 -0700 Subject: drm/i915: Add OACONTROL to the command parser register whitelist. Mesa needs to be able to write OACONTROL in order to expose the Observability Architecture's performance counters via OpenGL. Signed-off-by: Kenneth Graunke [danvet: Add comment that this is just a temporary work-around and that we need to check more things before we can allow OACONTROL writes for real everywhere.] [danvet 2: Squash in fixup to avoid a DRM_ERROR due to unsorted reg list, spotted by Jani.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index bae7c2f33692..788bd96b266b 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -407,6 +407,12 @@ static const u32 gen7_render_regs[] = { REG64(CL_PRIMITIVES_COUNT), REG64(PS_INVOCATION_COUNT), REG64(PS_DEPTH_COUNT), + /* + * FIXME: This is just to keep mesa working for now, we need to check + * that mesa resets this again and that it doesn't use any of the + * special modes which write into the gtt. + */ + OACONTROL, REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), -- cgit v1.2.1 From 77fec5560b5123be21b815f0217a9732b7da72c3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 31 Mar 2014 14:27:22 +0300 Subject: drm/i915: drop the typedef for drm_i915_private_t There are no longer users of drm_i915_private_t. Drop the typedef. Good riddance. Signed-off-by: Jani Nikula Acked-by: Chris Wilson [danvet: Add the hunk in i915_cmd_parser.c here which had to be relocated to the how this was merged.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 788bd96b266b..d8e5034bdb1d 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -730,7 +730,7 @@ finish: */ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = ring->dev->dev_private; + struct drm_i915_private *dev_priv = ring->dev->dev_private; /* No command tables indicates a platform without parsing */ if (!ring->cmd_tables) -- cgit v1.2.1 From 300233ee23d6ab8f05f0b673a278c66e6b19f079 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 27 Mar 2014 11:43:38 -0700 Subject: drm/i915: BUG_ON() when cmd/reg tables are not sorted As suggested during review, this makes it much more obvious when the tables are not sorted. Cc: Jani Nikula Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index d8e5034bdb1d..d25143424576 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -493,12 +493,13 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header) return 0; } -static void validate_cmds_sorted(struct intel_ring_buffer *ring) +static bool validate_cmds_sorted(struct intel_ring_buffer *ring) { int i; + bool ret = true; if (!ring->cmd_tables || ring->cmd_table_count == 0) - return; + return true; for (i = 0; i < ring->cmd_table_count; i++) { const struct drm_i915_cmd_table *table = &ring->cmd_tables[i]; @@ -510,35 +511,45 @@ static void validate_cmds_sorted(struct intel_ring_buffer *ring) &table->table[i]; u32 curr = desc->cmd.value & desc->cmd.mask; - if (curr < previous) + if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n", ring->id, i, j, curr, previous); + ret = false; + } previous = curr; } } + + return ret; } -static void check_sorted(int ring_id, const u32 *reg_table, int reg_count) +static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) { int i; u32 previous = 0; + bool ret = true; for (i = 0; i < reg_count; i++) { u32 curr = reg_table[i]; - if (curr < previous) + if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", ring_id, i, curr, previous); + ret = false; + } previous = curr; } + + return ret; } -static void validate_regs_sorted(struct intel_ring_buffer *ring) +static bool validate_regs_sorted(struct intel_ring_buffer *ring) { - check_sorted(ring->id, ring->reg_table, ring->reg_count); - check_sorted(ring->id, ring->master_reg_table, ring->master_reg_count); + return check_sorted(ring->id, ring->reg_table, ring->reg_count) && + check_sorted(ring->id, ring->master_reg_table, + ring->master_reg_count); } /** @@ -617,8 +628,8 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) BUG(); } - validate_cmds_sorted(ring); - validate_regs_sorted(ring); + BUG_ON(!validate_cmds_sorted(ring)); + BUG_ON(!validate_regs_sorted(ring)); } static const struct drm_i915_cmd_descriptor* -- cgit v1.2.1 From b651000b222701527c730b82ccb0ce42d99a6abe Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 27 Mar 2014 11:43:39 -0700 Subject: drm/i915: Refactor cmd parser checks into a function This brings the code a little more in line with kernel coding style. Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Reviewed-by: Kenneth Graunke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 136 +++++++++++++++++---------------- 1 file changed, 71 insertions(+), 65 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index d25143424576..ef7242e14979 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -758,6 +758,76 @@ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) return (i915.enable_cmd_parser == 1); } +static bool check_cmd(const struct intel_ring_buffer *ring, + const struct drm_i915_cmd_descriptor *desc, + const u32 *cmd, + const bool is_master) +{ + if (desc->flags & CMD_DESC_REJECT) { + DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); + return false; + } + + if ((desc->flags & CMD_DESC_MASTER) && !is_master) { + DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", + *cmd); + return false; + } + + if (desc->flags & CMD_DESC_REGISTER) { + u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; + + if (!valid_reg(ring->reg_table, + ring->reg_count, reg_addr)) { + if (!is_master || + !valid_reg(ring->master_reg_table, + ring->master_reg_count, + reg_addr)) { + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", + reg_addr, + *cmd, + ring->id); + return false; + } + } + } + + if (desc->flags & CMD_DESC_BITMASK) { + int i; + + for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) { + u32 dword; + + if (desc->bits[i].mask == 0) + break; + + if (desc->bits[i].condition_mask != 0) { + u32 offset = + desc->bits[i].condition_offset; + u32 condition = cmd[offset] & + desc->bits[i].condition_mask; + + if (condition == 0) + continue; + } + + dword = cmd[desc->bits[i].offset] & + desc->bits[i].mask; + + if (dword != desc->bits[i].expected) { + DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n", + *cmd, + desc->bits[i].mask, + desc->bits[i].expected, + dword, ring->id); + return false; + } + } + } + + return true; +} + #define LENGTH_BIAS 2 /** @@ -830,75 +900,11 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, break; } - if (desc->flags & CMD_DESC_REJECT) { - DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); + if (!check_cmd(ring, desc, cmd, is_master)) { ret = -EINVAL; break; } - if ((desc->flags & CMD_DESC_MASTER) && !is_master) { - DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", - *cmd); - ret = -EINVAL; - break; - } - - if (desc->flags & CMD_DESC_REGISTER) { - u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; - - if (!valid_reg(ring->reg_table, - ring->reg_count, reg_addr)) { - if (!is_master || - !valid_reg(ring->master_reg_table, - ring->master_reg_count, - reg_addr)) { - DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", - reg_addr, - *cmd, - ring->id); - ret = -EINVAL; - break; - } - } - } - - if (desc->flags & CMD_DESC_BITMASK) { - int i; - - for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) { - u32 dword; - - if (desc->bits[i].mask == 0) - break; - - if (desc->bits[i].condition_mask != 0) { - u32 offset = - desc->bits[i].condition_offset; - u32 condition = cmd[offset] & - desc->bits[i].condition_mask; - - if (condition == 0) - continue; - } - - dword = cmd[desc->bits[i].offset] & - desc->bits[i].mask; - - if (dword != desc->bits[i].expected) { - DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n", - *cmd, - desc->bits[i].mask, - desc->bits[i].expected, - dword, ring->id); - ret = -EINVAL; - break; - } - } - - if (ret) - break; - } - cmd += length; } -- cgit v1.2.1 From 6e66ea137ff5bd292ed734c53f569892068a7a70 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Fri, 28 Mar 2014 10:21:50 -0700 Subject: drm/i915: Track OACONTROL register enable/disable during parsing There is some thought that the data from the performance counters enabled via OACONTROL should only be available to the process that enabled counting. To limit snooping, require that any batch buffer which sets OACONTROL to a non-zero value also sets it back to 0 before the end of the batch. This requires limiting OACONTROL writes to happen via MI_LOAD_REGISTER_IMM so that we can access the value being written. This should be in line with the expected use case for writing OACONTROL. v2: Drop an unnecessary '? true : false' Cc: Kenneth Graunke Signed-off-by: Brad Volkin Reviewed-by: Kenneth Graunke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 35 ++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index ef7242e14979..5b45c191c4e7 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -407,12 +407,7 @@ static const u32 gen7_render_regs[] = { REG64(CL_PRIMITIVES_COUNT), REG64(PS_INVOCATION_COUNT), REG64(PS_DEPTH_COUNT), - /* - * FIXME: This is just to keep mesa working for now, we need to check - * that mesa resets this again and that it doesn't use any of the - * special modes which write into the gtt. - */ - OACONTROL, + OACONTROL, /* Only allowed for LRI and SRM. See below. */ REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), @@ -761,7 +756,8 @@ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) static bool check_cmd(const struct intel_ring_buffer *ring, const struct drm_i915_cmd_descriptor *desc, const u32 *cmd, - const bool is_master) + const bool is_master, + bool *oacontrol_set) { if (desc->flags & CMD_DESC_REJECT) { DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); @@ -777,6 +773,23 @@ static bool check_cmd(const struct intel_ring_buffer *ring, if (desc->flags & CMD_DESC_REGISTER) { u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; + /* + * OACONTROL requires some special handling for writes. We + * want to make sure that any batch which enables OA also + * disables it before the end of the batch. The goal is to + * prevent one process from snooping on the perf data from + * another process. To do that, we need to check the value + * that will be written to the register. Hence, limit + * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. + */ + if (reg_addr == OACONTROL) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) + return false; + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) + *oacontrol_set = (cmd[2] != 0); + } + if (!valid_reg(ring->reg_table, ring->reg_count, reg_addr)) { if (!is_master || @@ -851,6 +864,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, u32 *cmd, *batch_base, *batch_end; struct drm_i915_cmd_descriptor default_desc = { 0 }; int needs_clflush = 0; + bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); if (ret) { @@ -900,7 +914,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, break; } - if (!check_cmd(ring, desc, cmd, is_master)) { + if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { ret = -EINVAL; break; } @@ -908,6 +922,11 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, cmd += length; } + if (oacontrol_set) { + DRM_DEBUG_DRIVER("CMD: batch set OACONTROL but did not clear it\n"); + ret = -EINVAL; + } + if (cmd >= batch_end) { DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n"); ret = -EINVAL; -- cgit v1.2.1 From 86a2512124c1734c66bf240fac52a2af08aa1c6f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Apr 2014 11:24:20 +0300 Subject: drm/i915: fix command parser debug print format mismatches Drop the cast from the pointer diff to fix: drivers/gpu/drm/i915/i915_cmd_parser.c:405:4: warning: format '%td' expects argument of type 'ptrdiff_t', but argument 5 has type 'long unsigned int' [-Wformat] While at it, use %u for u32. Reported-by: Randy Dunlap Signed-off-by: Jani Nikula [danvet: After conflict resolution only the "While at it, ..." part was left standing ...] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 5b45c191c4e7..be09e7cd5afb 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -906,7 +906,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, length = ((*cmd & desc->length.mask) + LENGTH_BIAS); if ((batch_end - cmd) < length) { - DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%td\n", + DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n", *cmd, length, batch_end - cmd); -- cgit v1.2.1 From 113a047633eb7ee2a1d14cc258d7e5bca9215f73 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 8 Apr 2014 14:18:58 -0700 Subject: drm/i915: Add more registers to the whitelist for mesa These are additional registers needed for performance monitoring and ARB_draw_indirect extensions in mesa. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76719 Cc: Kenneth Graunke Signed-off-by: Brad Volkin Reviewed-by: Kenneth Graunke [danvet: Squash in fixup from Brad requested by Ken.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 29184d6c0027..9bac0979a294 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -408,10 +408,20 @@ static const u32 gen7_render_regs[] = { REG64(PS_INVOCATION_COUNT), REG64(PS_DEPTH_COUNT), OACONTROL, /* Only allowed for LRI and SRM. See below. */ + GEN7_3DPRIM_END_OFFSET, + GEN7_3DPRIM_START_VERTEX, + GEN7_3DPRIM_VERTEX_COUNT, + GEN7_3DPRIM_INSTANCE_COUNT, + GEN7_3DPRIM_START_INSTANCE, + GEN7_3DPRIM_BASE_VERTEX, REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(0)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), GEN7_SO_WRITE_OFFSET(0), GEN7_SO_WRITE_OFFSET(1), GEN7_SO_WRITE_OFFSET(2), -- cgit v1.2.1 From 122b250511e28c87043a6583988d4616895b5b53 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Apr 2014 16:59:00 +0200 Subject: drm/i915: Integrate cmd parser kerneldoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville noticed that we have this nice kerneldoc but it's not integrated anywhere. Fix this asap! Cc: Ville Syrjälä Cc: Brad Volkin Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 9bac0979a294..6ea94139e20b 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -28,7 +28,7 @@ #include "i915_drv.h" /** - * DOC: i915 batch buffer command parser + * DOC: batch buffer command parser * * Motivation: * Certain OpenGL features (e.g. transform feedback, performance monitoring) -- cgit v1.2.1 From 4b6eab597318784d838410da2d496707502f4898 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Mon, 28 Apr 2014 15:03:23 +0200 Subject: Revert "drm/i915: fix build warning on 32-bit (v2)" This reverts commit 60f2b4af1258c05e6b037af866be81abc24438f7. The same warning has been fixed in e5081a538a565284fec5f30a937d98e460d5e780 and these two commits got merged in 74e99a84de2d0980320612db8015ba606af42114 which caused another warning. Simply, the reverted commit casted the pointer difference to unsigned long and the other commit changed the output type from long to ptrdiff_t. The other commit fixes the original warning the better way so I'm reverting this commit now. Signed-off-by: Jan Moskyto Matejka Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 6ea94139e20b..69d34e47d3bc 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -919,7 +919,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n", *cmd, length, - (unsigned long)(batch_end - cmd)); + batch_end - cmd); ret = -EINVAL; break; } -- cgit v1.2.1 From 44e895a8a2e2c0512730d756f003a53835c8f7bf Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Sat, 10 May 2014 14:10:43 -0700 Subject: drm/i915: Use hash tables for the command parser For clients that submit large batch buffers the command parser has a substantial impact on performance. On my HSW ULT system performance drops as much as ~20% on some tests. Most of the time is spent in the command lookup code. Converting that from the current naive search to a hash table lookup reduces the performance drop to ~10%. The choice of value for I915_CMD_HASH_ORDER allows all commands currently used in the parser tables to hash to their own bucket (except for one collision on the render ring). The tradeoff is that it wastes memory. Because the opcodes for the commands in the tables are not particularly well distributed, reducing the order still leaves many buckets empty. The increased collisions don't seem to have a huge impact on the performance gain, but for now anyhow, the parser trades memory for performance. NB: Ville noticed that the error paths through the ring init code will leak memory. I've not addressed that here. We can do a follow up pass to handle all of the leaks. v2: improved comment describing selection of hash key mask (Damien) replace a BUG_ON() with an error return (Tvrtko, Ville) commit message improvements Signed-off-by: Brad Volkin Reviewed-by: Damien Lespiau Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 158 ++++++++++++++++++++++++++------- 1 file changed, 125 insertions(+), 33 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 69d34e47d3bc..d3a5b74746d1 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -498,16 +498,18 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header) return 0; } -static bool validate_cmds_sorted(struct intel_ring_buffer *ring) +static bool validate_cmds_sorted(struct intel_ring_buffer *ring, + const struct drm_i915_cmd_table *cmd_tables, + int cmd_table_count) { int i; bool ret = true; - if (!ring->cmd_tables || ring->cmd_table_count == 0) + if (!cmd_tables || cmd_table_count == 0) return true; - for (i = 0; i < ring->cmd_table_count; i++) { - const struct drm_i915_cmd_table *table = &ring->cmd_tables[i]; + for (i = 0; i < cmd_table_count; i++) { + const struct drm_i915_cmd_table *table = &cmd_tables[i]; u32 previous = 0; int j; @@ -557,6 +559,68 @@ static bool validate_regs_sorted(struct intel_ring_buffer *ring) ring->master_reg_count); } +struct cmd_node { + const struct drm_i915_cmd_descriptor *desc; + struct hlist_node node; +}; + +/* + * Different command ranges have different numbers of bits for the opcode. For + * example, MI commands use bits 31:23 while 3D commands use bits 31:16. The + * problem is that, for example, MI commands use bits 22:16 for other fields + * such as GGTT vs PPGTT bits. If we include those bits in the mask then when + * we mask a command from a batch it could hash to the wrong bucket due to + * non-opcode bits being set. But if we don't include those bits, some 3D + * commands may hash to the same bucket due to not including opcode bits that + * make the command unique. For now, we will risk hashing to the same bucket. + * + * If we attempt to generate a perfect hash, we should be able to look at bits + * 31:29 of a command from a batch buffer and use the full mask for that + * client. The existing INSTR_CLIENT_MASK/SHIFT defines can be used for this. + */ +#define CMD_HASH_MASK STD_MI_OPCODE_MASK + +static int init_hash_table(struct intel_ring_buffer *ring, + const struct drm_i915_cmd_table *cmd_tables, + int cmd_table_count) +{ + int i, j; + + hash_init(ring->cmd_hash); + + for (i = 0; i < cmd_table_count; i++) { + const struct drm_i915_cmd_table *table = &cmd_tables[i]; + + for (j = 0; j < table->count; j++) { + const struct drm_i915_cmd_descriptor *desc = + &table->table[j]; + struct cmd_node *desc_node = + kmalloc(sizeof(*desc_node), GFP_KERNEL); + + if (!desc_node) + return -ENOMEM; + + desc_node->desc = desc; + hash_add(ring->cmd_hash, &desc_node->node, + desc->cmd.value & CMD_HASH_MASK); + } + } + + return 0; +} + +static void fini_hash_table(struct intel_ring_buffer *ring) +{ + struct hlist_node *tmp; + struct cmd_node *desc_node; + int i; + + hash_for_each_safe(ring->cmd_hash, i, tmp, desc_node, node) { + hash_del(&desc_node->node); + kfree(desc_node); + } +} + /** * i915_cmd_parser_init_ring() - set cmd parser related fields for a ringbuffer * @ring: the ringbuffer to initialize @@ -564,21 +628,27 @@ static bool validate_regs_sorted(struct intel_ring_buffer *ring) * Optionally initializes fields related to batch buffer command parsing in the * struct intel_ring_buffer based on whether the platform requires software * command parsing. + * + * Return: non-zero if initialization fails */ -void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) +int i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) { + const struct drm_i915_cmd_table *cmd_tables; + int cmd_table_count; + int ret; + if (!IS_GEN7(ring->dev)) - return; + return 0; switch (ring->id) { case RCS: if (IS_HASWELL(ring->dev)) { - ring->cmd_tables = hsw_render_ring_cmds; - ring->cmd_table_count = + cmd_tables = hsw_render_ring_cmds; + cmd_table_count = ARRAY_SIZE(hsw_render_ring_cmds); } else { - ring->cmd_tables = gen7_render_cmds; - ring->cmd_table_count = ARRAY_SIZE(gen7_render_cmds); + cmd_tables = gen7_render_cmds; + cmd_table_count = ARRAY_SIZE(gen7_render_cmds); } ring->reg_table = gen7_render_regs; @@ -595,17 +665,17 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; break; case VCS: - ring->cmd_tables = gen7_video_cmds; - ring->cmd_table_count = ARRAY_SIZE(gen7_video_cmds); + cmd_tables = gen7_video_cmds; + cmd_table_count = ARRAY_SIZE(gen7_video_cmds); ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; case BCS: if (IS_HASWELL(ring->dev)) { - ring->cmd_tables = hsw_blt_ring_cmds; - ring->cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds); + cmd_tables = hsw_blt_ring_cmds; + cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds); } else { - ring->cmd_tables = gen7_blt_cmds; - ring->cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); + cmd_tables = gen7_blt_cmds; + cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); } ring->reg_table = gen7_blt_regs; @@ -622,8 +692,8 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; break; case VECS: - ring->cmd_tables = hsw_vebox_cmds; - ring->cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds); + cmd_tables = hsw_vebox_cmds; + cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds); /* VECS can use the same length_mask function as VCS */ ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; @@ -633,18 +703,45 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) BUG(); } - BUG_ON(!validate_cmds_sorted(ring)); + BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count)); BUG_ON(!validate_regs_sorted(ring)); + + ret = init_hash_table(ring, cmd_tables, cmd_table_count); + if (ret) { + DRM_ERROR("CMD: cmd_parser_init failed!\n"); + fini_hash_table(ring); + return ret; + } + + ring->needs_cmd_parser = true; + + return 0; +} + +/** + * i915_cmd_parser_fini_ring() - clean up cmd parser related fields + * @ring: the ringbuffer to clean up + * + * Releases any resources related to command parsing that may have been + * initialized for the specified ring. + */ +void i915_cmd_parser_fini_ring(struct intel_ring_buffer *ring) +{ + if (!ring->needs_cmd_parser) + return; + + fini_hash_table(ring); } static const struct drm_i915_cmd_descriptor* -find_cmd_in_table(const struct drm_i915_cmd_table *table, +find_cmd_in_table(struct intel_ring_buffer *ring, u32 cmd_header) { - int i; + struct cmd_node *desc_node; - for (i = 0; i < table->count; i++) { - const struct drm_i915_cmd_descriptor *desc = &table->table[i]; + hash_for_each_possible(ring->cmd_hash, desc_node, node, + cmd_header & CMD_HASH_MASK) { + const struct drm_i915_cmd_descriptor *desc = desc_node->desc; u32 masked_cmd = desc->cmd.mask & cmd_header; u32 masked_value = desc->cmd.value & desc->cmd.mask; @@ -668,16 +765,12 @@ find_cmd(struct intel_ring_buffer *ring, u32 cmd_header, struct drm_i915_cmd_descriptor *default_desc) { + const struct drm_i915_cmd_descriptor *desc; u32 mask; - int i; - - for (i = 0; i < ring->cmd_table_count; i++) { - const struct drm_i915_cmd_descriptor *desc; - desc = find_cmd_in_table(&ring->cmd_tables[i], cmd_header); - if (desc) - return desc; - } + desc = find_cmd_in_table(ring, cmd_header); + if (desc) + return desc; mask = ring->get_cmd_length_mask(cmd_header); if (!mask) @@ -748,8 +841,7 @@ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; - /* No command tables indicates a platform without parsing */ - if (!ring->cmd_tables) + if (!ring->needs_cmd_parser) return false; /* -- cgit v1.2.1 From a4872ba6d01454dfeb251d96f623ab5d1b0666a4 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 22 May 2014 14:13:33 +0100 Subject: drm/i915: s/intel_ring_buffer/intel_engine_cs In the upcoming patches we plan to break the correlation between engine command streamers (a.k.a. rings) and ringbuffers, so it makes sense to refactor the code and make the change obvious. No functional changes. Signed-off-by: Oscar Mateo Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index d3a5b74746d1..9d7954366bd2 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -498,7 +498,7 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header) return 0; } -static bool validate_cmds_sorted(struct intel_ring_buffer *ring, +static bool validate_cmds_sorted(struct intel_engine_cs *ring, const struct drm_i915_cmd_table *cmd_tables, int cmd_table_count) { @@ -552,7 +552,7 @@ static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) return ret; } -static bool validate_regs_sorted(struct intel_ring_buffer *ring) +static bool validate_regs_sorted(struct intel_engine_cs *ring) { return check_sorted(ring->id, ring->reg_table, ring->reg_count) && check_sorted(ring->id, ring->master_reg_table, @@ -580,7 +580,7 @@ struct cmd_node { */ #define CMD_HASH_MASK STD_MI_OPCODE_MASK -static int init_hash_table(struct intel_ring_buffer *ring, +static int init_hash_table(struct intel_engine_cs *ring, const struct drm_i915_cmd_table *cmd_tables, int cmd_table_count) { @@ -609,7 +609,7 @@ static int init_hash_table(struct intel_ring_buffer *ring, return 0; } -static void fini_hash_table(struct intel_ring_buffer *ring) +static void fini_hash_table(struct intel_engine_cs *ring) { struct hlist_node *tmp; struct cmd_node *desc_node; @@ -626,12 +626,12 @@ static void fini_hash_table(struct intel_ring_buffer *ring) * @ring: the ringbuffer to initialize * * Optionally initializes fields related to batch buffer command parsing in the - * struct intel_ring_buffer based on whether the platform requires software + * struct intel_engine_cs based on whether the platform requires software * command parsing. * * Return: non-zero if initialization fails */ -int i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) +int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) { const struct drm_i915_cmd_table *cmd_tables; int cmd_table_count; @@ -725,7 +725,7 @@ int i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) * Releases any resources related to command parsing that may have been * initialized for the specified ring. */ -void i915_cmd_parser_fini_ring(struct intel_ring_buffer *ring) +void i915_cmd_parser_fini_ring(struct intel_engine_cs *ring) { if (!ring->needs_cmd_parser) return; @@ -734,7 +734,7 @@ void i915_cmd_parser_fini_ring(struct intel_ring_buffer *ring) } static const struct drm_i915_cmd_descriptor* -find_cmd_in_table(struct intel_ring_buffer *ring, +find_cmd_in_table(struct intel_engine_cs *ring, u32 cmd_header) { struct cmd_node *desc_node; @@ -761,7 +761,7 @@ find_cmd_in_table(struct intel_ring_buffer *ring, * ring's default length encoding and returns default_desc. */ static const struct drm_i915_cmd_descriptor* -find_cmd(struct intel_ring_buffer *ring, +find_cmd(struct intel_engine_cs *ring, u32 cmd_header, struct drm_i915_cmd_descriptor *default_desc) { @@ -837,7 +837,7 @@ finish: * * Return: true if the ring requires software command parsing */ -bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) +bool i915_needs_cmd_parser(struct intel_engine_cs *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; @@ -855,7 +855,7 @@ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) return (i915.enable_cmd_parser == 1); } -static bool check_cmd(const struct intel_ring_buffer *ring, +static bool check_cmd(const struct intel_engine_cs *ring, const struct drm_i915_cmd_descriptor *desc, const u32 *cmd, const bool is_master, @@ -957,7 +957,7 @@ static bool check_cmd(const struct intel_ring_buffer *ring, * * Return: non-zero if the parser finds violations or otherwise fails */ -int i915_parse_cmds(struct intel_ring_buffer *ring, +int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, u32 batch_start_offset, bool is_master) -- cgit v1.2.1