diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_cmd_parser.c | 758 |
1 files changed, 667 insertions, 91 deletions
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 4cf6d020d513..9d7954366bd2 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include "i915_drv.h" | 28 | #include "i915_drv.h" |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * DOC: i915 batch buffer command parser | 31 | * DOC: batch buffer command parser |
32 | * | 32 | * |
33 | * Motivation: | 33 | * Motivation: |
34 | * Certain OpenGL features (e.g. transform feedback, performance monitoring) | 34 | * Certain OpenGL features (e.g. transform feedback, performance monitoring) |
@@ -86,6 +86,367 @@ | |||
86 | * general bitmasking mechanism. | 86 | * general bitmasking mechanism. |
87 | */ | 87 | */ |
88 | 88 | ||
89 | #define STD_MI_OPCODE_MASK 0xFF800000 | ||
90 | #define STD_3D_OPCODE_MASK 0xFFFF0000 | ||
91 | #define STD_2D_OPCODE_MASK 0xFFC00000 | ||
92 | #define STD_MFX_OPCODE_MASK 0xFFFF0000 | ||
93 | |||
94 | #define CMD(op, opm, f, lm, fl, ...) \ | ||
95 | { \ | ||
96 | .flags = (fl) | ((f) ? CMD_DESC_FIXED : 0), \ | ||
97 | .cmd = { (op), (opm) }, \ | ||
98 | .length = { (lm) }, \ | ||
99 | __VA_ARGS__ \ | ||
100 | } | ||
101 | |||
102 | /* Convenience macros to compress the tables */ | ||
103 | #define SMI STD_MI_OPCODE_MASK | ||
104 | #define S3D STD_3D_OPCODE_MASK | ||
105 | #define S2D STD_2D_OPCODE_MASK | ||
106 | #define SMFX STD_MFX_OPCODE_MASK | ||
107 | #define F true | ||
108 | #define S CMD_DESC_SKIP | ||
109 | #define R CMD_DESC_REJECT | ||
110 | #define W CMD_DESC_REGISTER | ||
111 | #define B CMD_DESC_BITMASK | ||
112 | #define M CMD_DESC_MASTER | ||
113 | |||
114 | /* Command Mask Fixed Len Action | ||
115 | ---------------------------------------------------------- */ | ||
116 | static const struct drm_i915_cmd_descriptor common_cmds[] = { | ||
117 | CMD( MI_NOOP, SMI, F, 1, S ), | ||
118 | CMD( MI_USER_INTERRUPT, SMI, F, 1, R ), | ||
119 | CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, M ), | ||
120 | CMD( MI_ARB_CHECK, SMI, F, 1, S ), | ||
121 | CMD( MI_REPORT_HEAD, SMI, F, 1, S ), | ||
122 | CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), | ||
123 | CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), | ||
124 | CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), | ||
125 | CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, | ||
126 | .reg = { .offset = 1, .mask = 0x007FFFFC } ), | ||
127 | CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, | ||
128 | .reg = { .offset = 1, .mask = 0x007FFFFC }, | ||
129 | .bits = {{ | ||
130 | .offset = 0, | ||
131 | .mask = MI_GLOBAL_GTT, | ||
132 | .expected = 0, | ||
133 | }}, ), | ||
134 | CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, W | B, | ||
135 | .reg = { .offset = 1, .mask = 0x007FFFFC }, | ||
136 | .bits = {{ | ||
137 | .offset = 0, | ||
138 | .mask = MI_GLOBAL_GTT, | ||
139 | .expected = 0, | ||
140 | }}, ), | ||
141 | CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), | ||
142 | }; | ||
143 | |||
144 | static const struct drm_i915_cmd_descriptor render_cmds[] = { | ||
145 | CMD( MI_FLUSH, SMI, F, 1, S ), | ||
146 | CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), | ||
147 | CMD( MI_PREDICATE, SMI, F, 1, S ), | ||
148 | CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ), | ||
149 | CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), | ||
150 | CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ), | ||
151 | CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), | ||
152 | CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B, | ||
153 | .bits = {{ | ||
154 | .offset = 0, | ||
155 | .mask = MI_GLOBAL_GTT, | ||
156 | .expected = 0, | ||
157 | }}, ), | ||
158 | CMD( MI_UPDATE_GTT, SMI, !F, 0xFF, R ), | ||
159 | CMD( MI_CLFLUSH, SMI, !F, 0x3FF, B, | ||
160 | .bits = {{ | ||
161 | .offset = 0, | ||
162 | .mask = MI_GLOBAL_GTT, | ||
163 | .expected = 0, | ||
164 | }}, ), | ||
165 | CMD( MI_REPORT_PERF_COUNT, SMI, !F, 0x3F, B, | ||
166 | .bits = {{ | ||
167 | .offset = 1, | ||
168 | .mask = MI_REPORT_PERF_COUNT_GGTT, | ||
169 | .expected = 0, | ||
170 | }}, ), | ||
171 | CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, | ||
172 | .bits = {{ | ||
173 | .offset = 0, | ||
174 | .mask = MI_GLOBAL_GTT, | ||
175 | .expected = 0, | ||
176 | }}, ), | ||
177 | CMD( GFX_OP_3DSTATE_VF_STATISTICS, S3D, F, 1, S ), | ||
178 | CMD( PIPELINE_SELECT, S3D, F, 1, S ), | ||
179 | CMD( MEDIA_VFE_STATE, S3D, !F, 0xFFFF, B, | ||
180 | .bits = {{ | ||
181 | .offset = 2, | ||
182 | .mask = MEDIA_VFE_STATE_MMIO_ACCESS_MASK, | ||
183 | .expected = 0, | ||
184 | }}, ), | ||
185 | CMD( GPGPU_OBJECT, S3D, !F, 0xFF, S ), | ||
186 | CMD( GPGPU_WALKER, S3D, !F, 0xFF, S ), | ||
187 | CMD( GFX_OP_3DSTATE_SO_DECL_LIST, S3D, !F, 0x1FF, S ), | ||
188 | CMD( GFX_OP_PIPE_CONTROL(5), S3D, !F, 0xFF, B, | ||
189 | .bits = {{ | ||
190 | .offset = 1, | ||
191 | .mask = (PIPE_CONTROL_MMIO_WRITE | PIPE_CONTROL_NOTIFY), | ||
192 | .expected = 0, | ||
193 | }, | ||
194 | { | ||
195 | .offset = 1, | ||
196 | .mask = (PIPE_CONTROL_GLOBAL_GTT_IVB | | ||
197 | PIPE_CONTROL_STORE_DATA_INDEX), | ||
198 | .expected = 0, | ||
199 | .condition_offset = 1, | ||
200 | .condition_mask = PIPE_CONTROL_POST_SYNC_OP_MASK, | ||
201 | }}, ), | ||
202 | }; | ||
203 | |||
204 | static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { | ||
205 | CMD( MI_SET_PREDICATE, SMI, F, 1, S ), | ||
206 | CMD( MI_RS_CONTROL, SMI, F, 1, S ), | ||
207 | CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), | ||
208 | CMD( MI_RS_CONTEXT, SMI, F, 1, S ), | ||
209 | CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), | ||
210 | CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), | ||
211 | CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, R ), | ||
212 | CMD( MI_RS_STORE_DATA_IMM, SMI, !F, 0xFF, S ), | ||
213 | CMD( MI_LOAD_URB_MEM, SMI, !F, 0xFF, S ), | ||
214 | CMD( MI_STORE_URB_MEM, SMI, !F, 0xFF, S ), | ||
215 | CMD( GFX_OP_3DSTATE_DX9_CONSTANTF_VS, S3D, !F, 0x7FF, S ), | ||
216 | CMD( GFX_OP_3DSTATE_DX9_CONSTANTF_PS, S3D, !F, 0x7FF, S ), | ||
217 | |||
218 | CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS, S3D, !F, 0x1FF, S ), | ||
219 | CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS, S3D, !F, 0x1FF, S ), | ||
220 | CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS, S3D, !F, 0x1FF, S ), | ||
221 | CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS, S3D, !F, 0x1FF, S ), | ||
222 | CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS, S3D, !F, 0x1FF, S ), | ||
223 | }; | ||
224 | |||
225 | static const struct drm_i915_cmd_descriptor video_cmds[] = { | ||
226 | CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), | ||
227 | CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, | ||
228 | .bits = {{ | ||
229 | .offset = 0, | ||
230 | .mask = MI_GLOBAL_GTT, | ||
231 | .expected = 0, | ||
232 | }}, ), | ||
233 | CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), | ||
234 | CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, | ||
235 | .bits = {{ | ||
236 | .offset = 0, | ||
237 | .mask = MI_FLUSH_DW_NOTIFY, | ||
238 | .expected = 0, | ||
239 | }, | ||
240 | { | ||
241 | .offset = 1, | ||
242 | .mask = MI_FLUSH_DW_USE_GTT, | ||
243 | .expected = 0, | ||
244 | .condition_offset = 0, | ||
245 | .condition_mask = MI_FLUSH_DW_OP_MASK, | ||
246 | }, | ||
247 | { | ||
248 | .offset = 0, | ||
249 | .mask = MI_FLUSH_DW_STORE_INDEX, | ||
250 | .expected = 0, | ||
251 | .condition_offset = 0, | ||
252 | .condition_mask = MI_FLUSH_DW_OP_MASK, | ||
253 | }}, ), | ||
254 | CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, | ||
255 | .bits = {{ | ||
256 | .offset = 0, | ||
257 | .mask = MI_GLOBAL_GTT, | ||
258 | .expected = 0, | ||
259 | }}, ), | ||
260 | /* | ||
261 | * MFX_WAIT doesn't fit the way we handle length for most commands. | ||
262 | * It has a length field but it uses a non-standard length bias. | ||
263 | * It is always 1 dword though, so just treat it as fixed length. | ||
264 | */ | ||
265 | CMD( MFX_WAIT, SMFX, F, 1, S ), | ||
266 | }; | ||
267 | |||
268 | static const struct drm_i915_cmd_descriptor vecs_cmds[] = { | ||
269 | CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), | ||
270 | CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, | ||
271 | .bits = {{ | ||
272 | .offset = 0, | ||
273 | .mask = MI_GLOBAL_GTT, | ||
274 | .expected = 0, | ||
275 | }}, ), | ||
276 | CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), | ||
277 | CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, | ||
278 | .bits = {{ | ||
279 | .offset = 0, | ||
280 | .mask = MI_FLUSH_DW_NOTIFY, | ||
281 | .expected = 0, | ||
282 | }, | ||
283 | { | ||
284 | .offset = 1, | ||
285 | .mask = MI_FLUSH_DW_USE_GTT, | ||
286 | .expected = 0, | ||
287 | .condition_offset = 0, | ||
288 | .condition_mask = MI_FLUSH_DW_OP_MASK, | ||
289 | }, | ||
290 | { | ||
291 | .offset = 0, | ||
292 | .mask = MI_FLUSH_DW_STORE_INDEX, | ||
293 | .expected = 0, | ||
294 | .condition_offset = 0, | ||
295 | .condition_mask = MI_FLUSH_DW_OP_MASK, | ||
296 | }}, ), | ||
297 | CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, | ||
298 | .bits = {{ | ||
299 | .offset = 0, | ||
300 | .mask = MI_GLOBAL_GTT, | ||
301 | .expected = 0, | ||
302 | }}, ), | ||
303 | }; | ||
304 | |||
305 | static const struct drm_i915_cmd_descriptor blt_cmds[] = { | ||
306 | CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), | ||
307 | CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, B, | ||
308 | .bits = {{ | ||
309 | .offset = 0, | ||
310 | .mask = MI_GLOBAL_GTT, | ||
311 | .expected = 0, | ||
312 | }}, ), | ||
313 | CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), | ||
314 | CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, | ||
315 | .bits = {{ | ||
316 | .offset = 0, | ||
317 | .mask = MI_FLUSH_DW_NOTIFY, | ||
318 | .expected = 0, | ||
319 | }, | ||
320 | { | ||
321 | .offset = 1, | ||
322 | .mask = MI_FLUSH_DW_USE_GTT, | ||
323 | .expected = 0, | ||
324 | .condition_offset = 0, | ||
325 | .condition_mask = MI_FLUSH_DW_OP_MASK, | ||
326 | }, | ||
327 | { | ||
328 | .offset = 0, | ||
329 | .mask = MI_FLUSH_DW_STORE_INDEX, | ||
330 | .expected = 0, | ||
331 | .condition_offset = 0, | ||
332 | .condition_mask = MI_FLUSH_DW_OP_MASK, | ||
333 | }}, ), | ||
334 | CMD( COLOR_BLT, S2D, !F, 0x3F, S ), | ||
335 | CMD( SRC_COPY_BLT, S2D, !F, 0x3F, S ), | ||
336 | }; | ||
337 | |||
338 | static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = { | ||
339 | CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), | ||
340 | CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), | ||
341 | }; | ||
342 | |||
343 | #undef CMD | ||
344 | #undef SMI | ||
345 | #undef S3D | ||
346 | #undef S2D | ||
347 | #undef SMFX | ||
348 | #undef F | ||
349 | #undef S | ||
350 | #undef R | ||
351 | #undef W | ||
352 | #undef B | ||
353 | #undef M | ||
354 | |||
355 | static const struct drm_i915_cmd_table gen7_render_cmds[] = { | ||
356 | { common_cmds, ARRAY_SIZE(common_cmds) }, | ||
357 | { render_cmds, ARRAY_SIZE(render_cmds) }, | ||
358 | }; | ||
359 | |||
360 | static const struct drm_i915_cmd_table hsw_render_ring_cmds[] = { | ||
361 | { common_cmds, ARRAY_SIZE(common_cmds) }, | ||
362 | { render_cmds, ARRAY_SIZE(render_cmds) }, | ||
363 | { hsw_render_cmds, ARRAY_SIZE(hsw_render_cmds) }, | ||
364 | }; | ||
365 | |||
366 | static const struct drm_i915_cmd_table gen7_video_cmds[] = { | ||
367 | { common_cmds, ARRAY_SIZE(common_cmds) }, | ||
368 | { video_cmds, ARRAY_SIZE(video_cmds) }, | ||
369 | }; | ||
370 | |||
371 | static const struct drm_i915_cmd_table hsw_vebox_cmds[] = { | ||
372 | { common_cmds, ARRAY_SIZE(common_cmds) }, | ||
373 | { vecs_cmds, ARRAY_SIZE(vecs_cmds) }, | ||
374 | }; | ||
375 | |||
376 | static const struct drm_i915_cmd_table gen7_blt_cmds[] = { | ||
377 | { common_cmds, ARRAY_SIZE(common_cmds) }, | ||
378 | { blt_cmds, ARRAY_SIZE(blt_cmds) }, | ||
379 | }; | ||
380 | |||
381 | static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { | ||
382 | { common_cmds, ARRAY_SIZE(common_cmds) }, | ||
383 | { blt_cmds, ARRAY_SIZE(blt_cmds) }, | ||
384 | { hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) }, | ||
385 | }; | ||
386 | |||
387 | /* | ||
388 | * Register whitelists, sorted by increasing register offset. | ||
389 | * | ||
390 | * Some registers that userspace accesses are 64 bits. The register | ||
391 | * access commands only allow 32-bit accesses. Hence, we have to include | ||
392 | * entries for both halves of the 64-bit registers. | ||
393 | */ | ||
394 | |||
395 | /* Convenience macro for adding 64-bit registers */ | ||
396 | #define REG64(addr) (addr), (addr + sizeof(u32)) | ||
397 | |||
398 | static const u32 gen7_render_regs[] = { | ||
399 | REG64(HS_INVOCATION_COUNT), | ||
400 | REG64(DS_INVOCATION_COUNT), | ||
401 | REG64(IA_VERTICES_COUNT), | ||
402 | REG64(IA_PRIMITIVES_COUNT), | ||
403 | REG64(VS_INVOCATION_COUNT), | ||
404 | REG64(GS_INVOCATION_COUNT), | ||
405 | REG64(GS_PRIMITIVES_COUNT), | ||
406 | REG64(CL_INVOCATION_COUNT), | ||
407 | REG64(CL_PRIMITIVES_COUNT), | ||
408 | REG64(PS_INVOCATION_COUNT), | ||
409 | REG64(PS_DEPTH_COUNT), | ||
410 | OACONTROL, /* Only allowed for LRI and SRM. See below. */ | ||
411 | GEN7_3DPRIM_END_OFFSET, | ||
412 | GEN7_3DPRIM_START_VERTEX, | ||
413 | GEN7_3DPRIM_VERTEX_COUNT, | ||
414 | GEN7_3DPRIM_INSTANCE_COUNT, | ||
415 | GEN7_3DPRIM_START_INSTANCE, | ||
416 | GEN7_3DPRIM_BASE_VERTEX, | ||
417 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), | ||
418 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), | ||
419 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), | ||
420 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)), | ||
421 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(0)), | ||
422 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), | ||
423 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), | ||
424 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), | ||
425 | GEN7_SO_WRITE_OFFSET(0), | ||
426 | GEN7_SO_WRITE_OFFSET(1), | ||
427 | GEN7_SO_WRITE_OFFSET(2), | ||
428 | GEN7_SO_WRITE_OFFSET(3), | ||
429 | }; | ||
430 | |||
431 | static const u32 gen7_blt_regs[] = { | ||
432 | BCS_SWCTRL, | ||
433 | }; | ||
434 | |||
435 | static const u32 ivb_master_regs[] = { | ||
436 | FORCEWAKE_MT, | ||
437 | DERRMR, | ||
438 | GEN7_PIPE_DE_LOAD_SL(PIPE_A), | ||
439 | GEN7_PIPE_DE_LOAD_SL(PIPE_B), | ||
440 | GEN7_PIPE_DE_LOAD_SL(PIPE_C), | ||
441 | }; | ||
442 | |||
443 | static const u32 hsw_master_regs[] = { | ||
444 | FORCEWAKE_MT, | ||
445 | DERRMR, | ||
446 | }; | ||
447 | |||
448 | #undef REG64 | ||
449 | |||
89 | static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) | 450 | static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) |
90 | { | 451 | { |
91 | u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; | 452 | u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; |
@@ -137,15 +498,18 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header) | |||
137 | return 0; | 498 | return 0; |
138 | } | 499 | } |
139 | 500 | ||
140 | static void validate_cmds_sorted(struct intel_ring_buffer *ring) | 501 | static bool validate_cmds_sorted(struct intel_engine_cs *ring, |
502 | const struct drm_i915_cmd_table *cmd_tables, | ||
503 | int cmd_table_count) | ||
141 | { | 504 | { |
142 | int i; | 505 | int i; |
506 | bool ret = true; | ||
143 | 507 | ||
144 | if (!ring->cmd_tables || ring->cmd_table_count == 0) | 508 | if (!cmd_tables || cmd_table_count == 0) |
145 | return; | 509 | return true; |
146 | 510 | ||
147 | for (i = 0; i < ring->cmd_table_count; i++) { | 511 | for (i = 0; i < cmd_table_count; i++) { |
148 | const struct drm_i915_cmd_table *table = &ring->cmd_tables[i]; | 512 | const struct drm_i915_cmd_table *table = &cmd_tables[i]; |
149 | u32 previous = 0; | 513 | u32 previous = 0; |
150 | int j; | 514 | int j; |
151 | 515 | ||
@@ -154,35 +518,107 @@ static void validate_cmds_sorted(struct intel_ring_buffer *ring) | |||
154 | &table->table[i]; | 518 | &table->table[i]; |
155 | u32 curr = desc->cmd.value & desc->cmd.mask; | 519 | u32 curr = desc->cmd.value & desc->cmd.mask; |
156 | 520 | ||
157 | if (curr < previous) | 521 | if (curr < previous) { |
158 | DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n", | 522 | DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n", |
159 | ring->id, i, j, curr, previous); | 523 | ring->id, i, j, curr, previous); |
524 | ret = false; | ||
525 | } | ||
160 | 526 | ||
161 | previous = curr; | 527 | previous = curr; |
162 | } | 528 | } |
163 | } | 529 | } |
530 | |||
531 | return ret; | ||
164 | } | 532 | } |
165 | 533 | ||
166 | static void check_sorted(int ring_id, const u32 *reg_table, int reg_count) | 534 | static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) |
167 | { | 535 | { |
168 | int i; | 536 | int i; |
169 | u32 previous = 0; | 537 | u32 previous = 0; |
538 | bool ret = true; | ||
170 | 539 | ||
171 | for (i = 0; i < reg_count; i++) { | 540 | for (i = 0; i < reg_count; i++) { |
172 | u32 curr = reg_table[i]; | 541 | u32 curr = reg_table[i]; |
173 | 542 | ||
174 | if (curr < previous) | 543 | if (curr < previous) { |
175 | DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", | 544 | DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", |
176 | ring_id, i, curr, previous); | 545 | ring_id, i, curr, previous); |
546 | ret = false; | ||
547 | } | ||
177 | 548 | ||
178 | previous = curr; | 549 | previous = curr; |
179 | } | 550 | } |
551 | |||
552 | return ret; | ||
553 | } | ||
554 | |||
555 | static bool validate_regs_sorted(struct intel_engine_cs *ring) | ||
556 | { | ||
557 | return check_sorted(ring->id, ring->reg_table, ring->reg_count) && | ||
558 | check_sorted(ring->id, ring->master_reg_table, | ||
559 | ring->master_reg_count); | ||
560 | } | ||
561 | |||
562 | struct cmd_node { | ||
563 | const struct drm_i915_cmd_descriptor *desc; | ||
564 | struct hlist_node node; | ||
565 | }; | ||
566 | |||
567 | /* | ||
568 | * Different command ranges have different numbers of bits for the opcode. For | ||
569 | * example, MI commands use bits 31:23 while 3D commands use bits 31:16. The | ||
570 | * problem is that, for example, MI commands use bits 22:16 for other fields | ||
571 | * such as GGTT vs PPGTT bits. If we include those bits in the mask then when | ||
572 | * we mask a command from a batch it could hash to the wrong bucket due to | ||
573 | * non-opcode bits being set. But if we don't include those bits, some 3D | ||
574 | * commands may hash to the same bucket due to not including opcode bits that | ||
575 | * make the command unique. For now, we will risk hashing to the same bucket. | ||
576 | * | ||
577 | * If we attempt to generate a perfect hash, we should be able to look at bits | ||
578 | * 31:29 of a command from a batch buffer and use the full mask for that | ||
579 | * client. The existing INSTR_CLIENT_MASK/SHIFT defines can be used for this. | ||
580 | */ | ||
581 | #define CMD_HASH_MASK STD_MI_OPCODE_MASK | ||
582 | |||
583 | static int init_hash_table(struct intel_engine_cs *ring, | ||
584 | const struct drm_i915_cmd_table *cmd_tables, | ||
585 | int cmd_table_count) | ||
586 | { | ||
587 | int i, j; | ||
588 | |||
589 | hash_init(ring->cmd_hash); | ||
590 | |||
591 | for (i = 0; i < cmd_table_count; i++) { | ||
592 | const struct drm_i915_cmd_table *table = &cmd_tables[i]; | ||
593 | |||
594 | for (j = 0; j < table->count; j++) { | ||
595 | const struct drm_i915_cmd_descriptor *desc = | ||
596 | &table->table[j]; | ||
597 | struct cmd_node *desc_node = | ||
598 | kmalloc(sizeof(*desc_node), GFP_KERNEL); | ||
599 | |||
600 | if (!desc_node) | ||
601 | return -ENOMEM; | ||
602 | |||
603 | desc_node->desc = desc; | ||
604 | hash_add(ring->cmd_hash, &desc_node->node, | ||
605 | desc->cmd.value & CMD_HASH_MASK); | ||
606 | } | ||
607 | } | ||
608 | |||
609 | return 0; | ||
180 | } | 610 | } |
181 | 611 | ||
182 | static void validate_regs_sorted(struct intel_ring_buffer *ring) | 612 | static void fini_hash_table(struct intel_engine_cs *ring) |
183 | { | 613 | { |
184 | check_sorted(ring->id, ring->reg_table, ring->reg_count); | 614 | struct hlist_node *tmp; |
185 | check_sorted(ring->id, ring->master_reg_table, ring->master_reg_count); | 615 | struct cmd_node *desc_node; |
616 | int i; | ||
617 | |||
618 | hash_for_each_safe(ring->cmd_hash, i, tmp, desc_node, node) { | ||
619 | hash_del(&desc_node->node); | ||
620 | kfree(desc_node); | ||
621 | } | ||
186 | } | 622 | } |
187 | 623 | ||
188 | /** | 624 | /** |
@@ -190,25 +626,74 @@ static void validate_regs_sorted(struct intel_ring_buffer *ring) | |||
190 | * @ring: the ringbuffer to initialize | 626 | * @ring: the ringbuffer to initialize |
191 | * | 627 | * |
192 | * Optionally initializes fields related to batch buffer command parsing in the | 628 | * Optionally initializes fields related to batch buffer command parsing in the |
193 | * struct intel_ring_buffer based on whether the platform requires software | 629 | * struct intel_engine_cs based on whether the platform requires software |
194 | * command parsing. | 630 | * command parsing. |
631 | * | ||
632 | * Return: non-zero if initialization fails | ||
195 | */ | 633 | */ |
196 | void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) | 634 | int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) |
197 | { | 635 | { |
636 | const struct drm_i915_cmd_table *cmd_tables; | ||
637 | int cmd_table_count; | ||
638 | int ret; | ||
639 | |||
198 | if (!IS_GEN7(ring->dev)) | 640 | if (!IS_GEN7(ring->dev)) |
199 | return; | 641 | return 0; |
200 | 642 | ||
201 | switch (ring->id) { | 643 | switch (ring->id) { |
202 | case RCS: | 644 | case RCS: |
645 | if (IS_HASWELL(ring->dev)) { | ||
646 | cmd_tables = hsw_render_ring_cmds; | ||
647 | cmd_table_count = | ||
648 | ARRAY_SIZE(hsw_render_ring_cmds); | ||
649 | } else { | ||
650 | cmd_tables = gen7_render_cmds; | ||
651 | cmd_table_count = ARRAY_SIZE(gen7_render_cmds); | ||
652 | } | ||
653 | |||
654 | ring->reg_table = gen7_render_regs; | ||
655 | ring->reg_count = ARRAY_SIZE(gen7_render_regs); | ||
656 | |||
657 | if (IS_HASWELL(ring->dev)) { | ||
658 | ring->master_reg_table = hsw_master_regs; | ||
659 | ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); | ||
660 | } else { | ||
661 | ring->master_reg_table = ivb_master_regs; | ||
662 | ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); | ||
663 | } | ||
664 | |||
203 | ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; | 665 | ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; |
204 | break; | 666 | break; |
205 | case VCS: | 667 | case VCS: |
668 | cmd_tables = gen7_video_cmds; | ||
669 | cmd_table_count = ARRAY_SIZE(gen7_video_cmds); | ||
206 | ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; | 670 | ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; |
207 | break; | 671 | break; |
208 | case BCS: | 672 | case BCS: |
673 | if (IS_HASWELL(ring->dev)) { | ||
674 | cmd_tables = hsw_blt_ring_cmds; | ||
675 | cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds); | ||
676 | } else { | ||
677 | cmd_tables = gen7_blt_cmds; | ||
678 | cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); | ||
679 | } | ||
680 | |||
681 | ring->reg_table = gen7_blt_regs; | ||
682 | ring->reg_count = ARRAY_SIZE(gen7_blt_regs); | ||
683 | |||
684 | if (IS_HASWELL(ring->dev)) { | ||
685 | ring->master_reg_table = hsw_master_regs; | ||
686 | ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); | ||
687 | } else { | ||
688 | ring->master_reg_table = ivb_master_regs; | ||
689 | ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); | ||
690 | } | ||
691 | |||
209 | ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; | 692 | ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; |
210 | break; | 693 | break; |
211 | case VECS: | 694 | case VECS: |
695 | cmd_tables = hsw_vebox_cmds; | ||
696 | cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds); | ||
212 | /* VECS can use the same length_mask function as VCS */ | 697 | /* VECS can use the same length_mask function as VCS */ |
213 | ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; | 698 | ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; |
214 | break; | 699 | break; |
@@ -218,18 +703,45 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) | |||
218 | BUG(); | 703 | BUG(); |
219 | } | 704 | } |
220 | 705 | ||
221 | validate_cmds_sorted(ring); | 706 | BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count)); |
222 | validate_regs_sorted(ring); | 707 | BUG_ON(!validate_regs_sorted(ring)); |
708 | |||
709 | ret = init_hash_table(ring, cmd_tables, cmd_table_count); | ||
710 | if (ret) { | ||
711 | DRM_ERROR("CMD: cmd_parser_init failed!\n"); | ||
712 | fini_hash_table(ring); | ||
713 | return ret; | ||
714 | } | ||
715 | |||
716 | ring->needs_cmd_parser = true; | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | /** | ||
722 | * i915_cmd_parser_fini_ring() - clean up cmd parser related fields | ||
723 | * @ring: the ringbuffer to clean up | ||
724 | * | ||
725 | * Releases any resources related to command parsing that may have been | ||
726 | * initialized for the specified ring. | ||
727 | */ | ||
728 | void i915_cmd_parser_fini_ring(struct intel_engine_cs *ring) | ||
729 | { | ||
730 | if (!ring->needs_cmd_parser) | ||
731 | return; | ||
732 | |||
733 | fini_hash_table(ring); | ||
223 | } | 734 | } |
224 | 735 | ||
225 | static const struct drm_i915_cmd_descriptor* | 736 | static const struct drm_i915_cmd_descriptor* |
226 | find_cmd_in_table(const struct drm_i915_cmd_table *table, | 737 | find_cmd_in_table(struct intel_engine_cs *ring, |
227 | u32 cmd_header) | 738 | u32 cmd_header) |
228 | { | 739 | { |
229 | int i; | 740 | struct cmd_node *desc_node; |
230 | 741 | ||
231 | for (i = 0; i < table->count; i++) { | 742 | hash_for_each_possible(ring->cmd_hash, desc_node, node, |
232 | const struct drm_i915_cmd_descriptor *desc = &table->table[i]; | 743 | cmd_header & CMD_HASH_MASK) { |
744 | const struct drm_i915_cmd_descriptor *desc = desc_node->desc; | ||
233 | u32 masked_cmd = desc->cmd.mask & cmd_header; | 745 | u32 masked_cmd = desc->cmd.mask & cmd_header; |
234 | u32 masked_value = desc->cmd.value & desc->cmd.mask; | 746 | u32 masked_value = desc->cmd.value & desc->cmd.mask; |
235 | 747 | ||
@@ -249,20 +761,16 @@ find_cmd_in_table(const struct drm_i915_cmd_table *table, | |||
249 | * ring's default length encoding and returns default_desc. | 761 | * ring's default length encoding and returns default_desc. |
250 | */ | 762 | */ |
251 | static const struct drm_i915_cmd_descriptor* | 763 | static const struct drm_i915_cmd_descriptor* |
252 | find_cmd(struct intel_ring_buffer *ring, | 764 | find_cmd(struct intel_engine_cs *ring, |
253 | u32 cmd_header, | 765 | u32 cmd_header, |
254 | struct drm_i915_cmd_descriptor *default_desc) | 766 | struct drm_i915_cmd_descriptor *default_desc) |
255 | { | 767 | { |
768 | const struct drm_i915_cmd_descriptor *desc; | ||
256 | u32 mask; | 769 | u32 mask; |
257 | int i; | ||
258 | 770 | ||
259 | for (i = 0; i < ring->cmd_table_count; i++) { | 771 | desc = find_cmd_in_table(ring, cmd_header); |
260 | const struct drm_i915_cmd_descriptor *desc; | 772 | if (desc) |
261 | 773 | return desc; | |
262 | desc = find_cmd_in_table(&ring->cmd_tables[i], cmd_header); | ||
263 | if (desc) | ||
264 | return desc; | ||
265 | } | ||
266 | 774 | ||
267 | mask = ring->get_cmd_length_mask(cmd_header); | 775 | mask = ring->get_cmd_length_mask(cmd_header); |
268 | if (!mask) | 776 | if (!mask) |
@@ -329,15 +837,112 @@ finish: | |||
329 | * | 837 | * |
330 | * Return: true if the ring requires software command parsing | 838 | * Return: true if the ring requires software command parsing |
331 | */ | 839 | */ |
332 | bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) | 840 | bool i915_needs_cmd_parser(struct intel_engine_cs *ring) |
333 | { | 841 | { |
334 | /* No command tables indicates a platform without parsing */ | 842 | struct drm_i915_private *dev_priv = ring->dev->dev_private; |
335 | if (!ring->cmd_tables) | 843 | |
844 | if (!ring->needs_cmd_parser) | ||
845 | return false; | ||
846 | |||
847 | /* | ||
848 | * XXX: VLV is Gen7 and therefore has cmd_tables, but has PPGTT | ||
849 | * disabled. That will cause all of the parser's PPGTT checks to | ||
850 | * fail. For now, disable parsing when PPGTT is off. | ||
851 | */ | ||
852 | if (!dev_priv->mm.aliasing_ppgtt) | ||
336 | return false; | 853 | return false; |
337 | 854 | ||
338 | return (i915.enable_cmd_parser == 1); | 855 | return (i915.enable_cmd_parser == 1); |
339 | } | 856 | } |
340 | 857 | ||
858 | static bool check_cmd(const struct intel_engine_cs *ring, | ||
859 | const struct drm_i915_cmd_descriptor *desc, | ||
860 | const u32 *cmd, | ||
861 | const bool is_master, | ||
862 | bool *oacontrol_set) | ||
863 | { | ||
864 | if (desc->flags & CMD_DESC_REJECT) { | ||
865 | DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); | ||
866 | return false; | ||
867 | } | ||
868 | |||
869 | if ((desc->flags & CMD_DESC_MASTER) && !is_master) { | ||
870 | DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", | ||
871 | *cmd); | ||
872 | return false; | ||
873 | } | ||
874 | |||
875 | if (desc->flags & CMD_DESC_REGISTER) { | ||
876 | u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; | ||
877 | |||
878 | /* | ||
879 | * OACONTROL requires some special handling for writes. We | ||
880 | * want to make sure that any batch which enables OA also | ||
881 | * disables it before the end of the batch. The goal is to | ||
882 | * prevent one process from snooping on the perf data from | ||
883 | * another process. To do that, we need to check the value | ||
884 | * that will be written to the register. Hence, limit | ||
885 | * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. | ||
886 | */ | ||
887 | if (reg_addr == OACONTROL) { | ||
888 | if (desc->cmd.value == MI_LOAD_REGISTER_MEM) | ||
889 | return false; | ||
890 | |||
891 | if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) | ||
892 | *oacontrol_set = (cmd[2] != 0); | ||
893 | } | ||
894 | |||
895 | if (!valid_reg(ring->reg_table, | ||
896 | ring->reg_count, reg_addr)) { | ||
897 | if (!is_master || | ||
898 | !valid_reg(ring->master_reg_table, | ||
899 | ring->master_reg_count, | ||
900 | reg_addr)) { | ||
901 | DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", | ||
902 | reg_addr, | ||
903 | *cmd, | ||
904 | ring->id); | ||
905 | return false; | ||
906 | } | ||
907 | } | ||
908 | } | ||
909 | |||
910 | if (desc->flags & CMD_DESC_BITMASK) { | ||
911 | int i; | ||
912 | |||
913 | for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) { | ||
914 | u32 dword; | ||
915 | |||
916 | if (desc->bits[i].mask == 0) | ||
917 | break; | ||
918 | |||
919 | if (desc->bits[i].condition_mask != 0) { | ||
920 | u32 offset = | ||
921 | desc->bits[i].condition_offset; | ||
922 | u32 condition = cmd[offset] & | ||
923 | desc->bits[i].condition_mask; | ||
924 | |||
925 | if (condition == 0) | ||
926 | continue; | ||
927 | } | ||
928 | |||
929 | dword = cmd[desc->bits[i].offset] & | ||
930 | desc->bits[i].mask; | ||
931 | |||
932 | if (dword != desc->bits[i].expected) { | ||
933 | DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n", | ||
934 | *cmd, | ||
935 | desc->bits[i].mask, | ||
936 | desc->bits[i].expected, | ||
937 | dword, ring->id); | ||
938 | return false; | ||
939 | } | ||
940 | } | ||
941 | } | ||
942 | |||
943 | return true; | ||
944 | } | ||
945 | |||
341 | #define LENGTH_BIAS 2 | 946 | #define LENGTH_BIAS 2 |
342 | 947 | ||
343 | /** | 948 | /** |
@@ -352,7 +957,7 @@ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) | |||
352 | * | 957 | * |
353 | * Return: non-zero if the parser finds violations or otherwise fails | 958 | * Return: non-zero if the parser finds violations or otherwise fails |
354 | */ | 959 | */ |
355 | int i915_parse_cmds(struct intel_ring_buffer *ring, | 960 | int i915_parse_cmds(struct intel_engine_cs *ring, |
356 | struct drm_i915_gem_object *batch_obj, | 961 | struct drm_i915_gem_object *batch_obj, |
357 | u32 batch_start_offset, | 962 | u32 batch_start_offset, |
358 | bool is_master) | 963 | bool is_master) |
@@ -361,6 +966,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, | |||
361 | u32 *cmd, *batch_base, *batch_end; | 966 | u32 *cmd, *batch_base, *batch_end; |
362 | struct drm_i915_cmd_descriptor default_desc = { 0 }; | 967 | struct drm_i915_cmd_descriptor default_desc = { 0 }; |
363 | int needs_clflush = 0; | 968 | int needs_clflush = 0; |
969 | bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ | ||
364 | 970 | ||
365 | ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); | 971 | ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); |
366 | if (ret) { | 972 | if (ret) { |
@@ -402,76 +1008,27 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, | |||
402 | length = ((*cmd & desc->length.mask) + LENGTH_BIAS); | 1008 | length = ((*cmd & desc->length.mask) + LENGTH_BIAS); |
403 | 1009 | ||
404 | if ((batch_end - cmd) < length) { | 1010 | if ((batch_end - cmd) < length) { |
405 | DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%td\n", | 1011 | DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n", |
406 | *cmd, | 1012 | *cmd, |
407 | length, | 1013 | length, |
408 | (unsigned long)(batch_end - cmd)); | 1014 | batch_end - cmd); |
409 | ret = -EINVAL; | 1015 | ret = -EINVAL; |
410 | break; | 1016 | break; |
411 | } | 1017 | } |
412 | 1018 | ||
413 | if (desc->flags & CMD_DESC_REJECT) { | 1019 | if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { |
414 | DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); | ||
415 | ret = -EINVAL; | 1020 | ret = -EINVAL; |
416 | break; | 1021 | break; |
417 | } | 1022 | } |
418 | 1023 | ||
419 | if ((desc->flags & CMD_DESC_MASTER) && !is_master) { | ||
420 | DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", | ||
421 | *cmd); | ||
422 | ret = -EINVAL; | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | if (desc->flags & CMD_DESC_REGISTER) { | ||
427 | u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; | ||
428 | |||
429 | if (!valid_reg(ring->reg_table, | ||
430 | ring->reg_count, reg_addr)) { | ||
431 | if (!is_master || | ||
432 | !valid_reg(ring->master_reg_table, | ||
433 | ring->master_reg_count, | ||
434 | reg_addr)) { | ||
435 | DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", | ||
436 | reg_addr, | ||
437 | *cmd, | ||
438 | ring->id); | ||
439 | ret = -EINVAL; | ||
440 | break; | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | if (desc->flags & CMD_DESC_BITMASK) { | ||
446 | int i; | ||
447 | |||
448 | for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) { | ||
449 | u32 dword; | ||
450 | |||
451 | if (desc->bits[i].mask == 0) | ||
452 | break; | ||
453 | |||
454 | dword = cmd[desc->bits[i].offset] & | ||
455 | desc->bits[i].mask; | ||
456 | |||
457 | if (dword != desc->bits[i].expected) { | ||
458 | DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n", | ||
459 | *cmd, | ||
460 | desc->bits[i].mask, | ||
461 | desc->bits[i].expected, | ||
462 | dword, ring->id); | ||
463 | ret = -EINVAL; | ||
464 | break; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if (ret) | ||
469 | break; | ||
470 | } | ||
471 | |||
472 | cmd += length; | 1024 | cmd += length; |
473 | } | 1025 | } |
474 | 1026 | ||
1027 | if (oacontrol_set) { | ||
1028 | DRM_DEBUG_DRIVER("CMD: batch set OACONTROL but did not clear it\n"); | ||
1029 | ret = -EINVAL; | ||
1030 | } | ||
1031 | |||
475 | if (cmd >= batch_end) { | 1032 | if (cmd >= batch_end) { |
476 | DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n"); | 1033 | DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n"); |
477 | ret = -EINVAL; | 1034 | ret = -EINVAL; |
@@ -483,3 +1040,22 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, | |||
483 | 1040 | ||
484 | return ret; | 1041 | return ret; |
485 | } | 1042 | } |
1043 | |||
1044 | /** | ||
1045 | * i915_cmd_parser_get_version() - get the cmd parser version number | ||
1046 | * | ||
1047 | * The cmd parser maintains a simple increasing integer version number suitable | ||
1048 | * for passing to userspace clients to determine what operations are permitted. | ||
1049 | * | ||
1050 | * Return: the current version number of the cmd parser | ||
1051 | */ | ||
1052 | int i915_cmd_parser_get_version(void) | ||
1053 | { | ||
1054 | /* | ||
1055 | * Command parser version history | ||
1056 | * | ||
1057 | * 1. Initial version. Checks batches and reports violations, but leaves | ||
1058 | * hardware parsing enabled (so does not allow new use cases). | ||
1059 | */ | ||
1060 | return 1; | ||
1061 | } | ||