diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_cmd_parser.c | 209 |
1 files changed, 135 insertions, 74 deletions
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 61ae8ff4eaed..306d9e4e5cf3 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c | |||
@@ -123,7 +123,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { | |||
123 | CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), | 123 | CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), |
124 | CMD( MI_STORE_DWORD_INDEX, 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, | 125 | CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, |
126 | .reg = { .offset = 1, .mask = 0x007FFFFC } ), | 126 | .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ), |
127 | CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, | 127 | CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, |
128 | .reg = { .offset = 1, .mask = 0x007FFFFC }, | 128 | .reg = { .offset = 1, .mask = 0x007FFFFC }, |
129 | .bits = {{ | 129 | .bits = {{ |
@@ -395,16 +395,38 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { | |||
395 | 395 | ||
396 | /* | 396 | /* |
397 | * Register whitelists, sorted by increasing register offset. | 397 | * Register whitelists, sorted by increasing register offset. |
398 | */ | ||
399 | |||
400 | /* | ||
401 | * An individual whitelist entry granting access to register addr. If | ||
402 | * mask is non-zero the argument of immediate register writes will be | ||
403 | * AND-ed with mask, and the command will be rejected if the result | ||
404 | * doesn't match value. | ||
405 | * | ||
406 | * Registers with non-zero mask are only allowed to be written using | ||
407 | * LRI. | ||
408 | */ | ||
409 | struct drm_i915_reg_descriptor { | ||
410 | u32 addr; | ||
411 | u32 mask; | ||
412 | u32 value; | ||
413 | }; | ||
414 | |||
415 | /* Convenience macro for adding 32-bit registers. */ | ||
416 | #define REG32(address, ...) \ | ||
417 | { .addr = address, __VA_ARGS__ } | ||
418 | |||
419 | /* | ||
420 | * Convenience macro for adding 64-bit registers. | ||
398 | * | 421 | * |
399 | * Some registers that userspace accesses are 64 bits. The register | 422 | * Some registers that userspace accesses are 64 bits. The register |
400 | * access commands only allow 32-bit accesses. Hence, we have to include | 423 | * access commands only allow 32-bit accesses. Hence, we have to include |
401 | * entries for both halves of the 64-bit registers. | 424 | * entries for both halves of the 64-bit registers. |
402 | */ | 425 | */ |
426 | #define REG64(addr) \ | ||
427 | REG32(addr), REG32(addr + sizeof(u32)) | ||
403 | 428 | ||
404 | /* Convenience macro for adding 64-bit registers */ | 429 | static const struct drm_i915_reg_descriptor gen7_render_regs[] = { |
405 | #define REG64(addr) (addr), (addr + sizeof(u32)) | ||
406 | |||
407 | static const u32 gen7_render_regs[] = { | ||
408 | REG64(GPGPU_THREADS_DISPATCHED), | 430 | REG64(GPGPU_THREADS_DISPATCHED), |
409 | REG64(HS_INVOCATION_COUNT), | 431 | REG64(HS_INVOCATION_COUNT), |
410 | REG64(DS_INVOCATION_COUNT), | 432 | REG64(DS_INVOCATION_COUNT), |
@@ -417,15 +439,15 @@ static const u32 gen7_render_regs[] = { | |||
417 | REG64(CL_PRIMITIVES_COUNT), | 439 | REG64(CL_PRIMITIVES_COUNT), |
418 | REG64(PS_INVOCATION_COUNT), | 440 | REG64(PS_INVOCATION_COUNT), |
419 | REG64(PS_DEPTH_COUNT), | 441 | REG64(PS_DEPTH_COUNT), |
420 | OACONTROL, /* Only allowed for LRI and SRM. See below. */ | 442 | REG32(OACONTROL), /* Only allowed for LRI and SRM. See below. */ |
421 | REG64(MI_PREDICATE_SRC0), | 443 | REG64(MI_PREDICATE_SRC0), |
422 | REG64(MI_PREDICATE_SRC1), | 444 | REG64(MI_PREDICATE_SRC1), |
423 | GEN7_3DPRIM_END_OFFSET, | 445 | REG32(GEN7_3DPRIM_END_OFFSET), |
424 | GEN7_3DPRIM_START_VERTEX, | 446 | REG32(GEN7_3DPRIM_START_VERTEX), |
425 | GEN7_3DPRIM_VERTEX_COUNT, | 447 | REG32(GEN7_3DPRIM_VERTEX_COUNT), |
426 | GEN7_3DPRIM_INSTANCE_COUNT, | 448 | REG32(GEN7_3DPRIM_INSTANCE_COUNT), |
427 | GEN7_3DPRIM_START_INSTANCE, | 449 | REG32(GEN7_3DPRIM_START_INSTANCE), |
428 | GEN7_3DPRIM_BASE_VERTEX, | 450 | REG32(GEN7_3DPRIM_BASE_VERTEX), |
429 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), | 451 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), |
430 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), | 452 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), |
431 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), | 453 | REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), |
@@ -434,33 +456,41 @@ static const u32 gen7_render_regs[] = { | |||
434 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), | 456 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), |
435 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), | 457 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), |
436 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), | 458 | REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), |
437 | GEN7_SO_WRITE_OFFSET(0), | 459 | REG32(GEN7_SO_WRITE_OFFSET(0)), |
438 | GEN7_SO_WRITE_OFFSET(1), | 460 | REG32(GEN7_SO_WRITE_OFFSET(1)), |
439 | GEN7_SO_WRITE_OFFSET(2), | 461 | REG32(GEN7_SO_WRITE_OFFSET(2)), |
440 | GEN7_SO_WRITE_OFFSET(3), | 462 | REG32(GEN7_SO_WRITE_OFFSET(3)), |
441 | GEN7_L3SQCREG1, | 463 | REG32(GEN7_L3SQCREG1), |
442 | GEN7_L3CNTLREG2, | 464 | REG32(GEN7_L3CNTLREG2), |
443 | GEN7_L3CNTLREG3, | 465 | REG32(GEN7_L3CNTLREG3), |
466 | REG32(HSW_SCRATCH1, | ||
467 | .mask = ~HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE, | ||
468 | .value = 0), | ||
469 | REG32(HSW_ROW_CHICKEN3, | ||
470 | .mask = ~(HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE << 16 | | ||
471 | HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE), | ||
472 | .value = 0), | ||
444 | }; | 473 | }; |
445 | 474 | ||
446 | static const u32 gen7_blt_regs[] = { | 475 | static const struct drm_i915_reg_descriptor gen7_blt_regs[] = { |
447 | BCS_SWCTRL, | 476 | REG32(BCS_SWCTRL), |
448 | }; | 477 | }; |
449 | 478 | ||
450 | static const u32 ivb_master_regs[] = { | 479 | static const struct drm_i915_reg_descriptor ivb_master_regs[] = { |
451 | FORCEWAKE_MT, | 480 | REG32(FORCEWAKE_MT), |
452 | DERRMR, | 481 | REG32(DERRMR), |
453 | GEN7_PIPE_DE_LOAD_SL(PIPE_A), | 482 | REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_A)), |
454 | GEN7_PIPE_DE_LOAD_SL(PIPE_B), | 483 | REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_B)), |
455 | GEN7_PIPE_DE_LOAD_SL(PIPE_C), | 484 | REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_C)), |
456 | }; | 485 | }; |
457 | 486 | ||
458 | static const u32 hsw_master_regs[] = { | 487 | static const struct drm_i915_reg_descriptor hsw_master_regs[] = { |
459 | FORCEWAKE_MT, | 488 | REG32(FORCEWAKE_MT), |
460 | DERRMR, | 489 | REG32(DERRMR), |
461 | }; | 490 | }; |
462 | 491 | ||
463 | #undef REG64 | 492 | #undef REG64 |
493 | #undef REG32 | ||
464 | 494 | ||
465 | static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) | 495 | static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) |
466 | { | 496 | { |
@@ -550,14 +580,16 @@ static bool validate_cmds_sorted(struct intel_engine_cs *ring, | |||
550 | return ret; | 580 | return ret; |
551 | } | 581 | } |
552 | 582 | ||
553 | static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) | 583 | static bool check_sorted(int ring_id, |
584 | const struct drm_i915_reg_descriptor *reg_table, | ||
585 | int reg_count) | ||
554 | { | 586 | { |
555 | int i; | 587 | int i; |
556 | u32 previous = 0; | 588 | u32 previous = 0; |
557 | bool ret = true; | 589 | bool ret = true; |
558 | 590 | ||
559 | for (i = 0; i < reg_count; i++) { | 591 | for (i = 0; i < reg_count; i++) { |
560 | u32 curr = reg_table[i]; | 592 | u32 curr = reg_table[i].addr; |
561 | 593 | ||
562 | if (curr < previous) { | 594 | if (curr < previous) { |
563 | DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", | 595 | DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", |
@@ -804,18 +836,20 @@ find_cmd(struct intel_engine_cs *ring, | |||
804 | return default_desc; | 836 | return default_desc; |
805 | } | 837 | } |
806 | 838 | ||
807 | static bool valid_reg(const u32 *table, int count, u32 addr) | 839 | static const struct drm_i915_reg_descriptor * |
840 | find_reg(const struct drm_i915_reg_descriptor *table, | ||
841 | int count, u32 addr) | ||
808 | { | 842 | { |
809 | if (table && count != 0) { | 843 | if (table) { |
810 | int i; | 844 | int i; |
811 | 845 | ||
812 | for (i = 0; i < count; i++) { | 846 | for (i = 0; i < count; i++) { |
813 | if (table[i] == addr) | 847 | if (table[i].addr == addr) |
814 | return true; | 848 | return &table[i]; |
815 | } | 849 | } |
816 | } | 850 | } |
817 | 851 | ||
818 | return false; | 852 | return NULL; |
819 | } | 853 | } |
820 | 854 | ||
821 | static u32 *vmap_batch(struct drm_i915_gem_object *obj, | 855 | static u32 *vmap_batch(struct drm_i915_gem_object *obj, |
@@ -869,6 +903,9 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, | |||
869 | batch_len + batch_start_offset > src_obj->base.size) | 903 | batch_len + batch_start_offset > src_obj->base.size) |
870 | return ERR_PTR(-E2BIG); | 904 | return ERR_PTR(-E2BIG); |
871 | 905 | ||
906 | if (WARN_ON(dest_obj->pages_pin_count == 0)) | ||
907 | return ERR_PTR(-ENODEV); | ||
908 | |||
872 | ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush); | 909 | ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush); |
873 | if (ret) { | 910 | if (ret) { |
874 | DRM_DEBUG_DRIVER("CMD: failed to prepare shadow batch\n"); | 911 | DRM_DEBUG_DRIVER("CMD: failed to prepare shadow batch\n"); |
@@ -882,13 +919,6 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, | |||
882 | goto unpin_src; | 919 | goto unpin_src; |
883 | } | 920 | } |
884 | 921 | ||
885 | ret = i915_gem_object_get_pages(dest_obj); | ||
886 | if (ret) { | ||
887 | DRM_DEBUG_DRIVER("CMD: Failed to get pages for shadow batch\n"); | ||
888 | goto unmap_src; | ||
889 | } | ||
890 | i915_gem_object_pin_pages(dest_obj); | ||
891 | |||
892 | ret = i915_gem_object_set_to_cpu_domain(dest_obj, true); | 922 | ret = i915_gem_object_set_to_cpu_domain(dest_obj, true); |
893 | if (ret) { | 923 | if (ret) { |
894 | DRM_DEBUG_DRIVER("CMD: Failed to set shadow batch to CPU\n"); | 924 | DRM_DEBUG_DRIVER("CMD: Failed to set shadow batch to CPU\n"); |
@@ -898,7 +928,6 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, | |||
898 | dst = vmap_batch(dest_obj, 0, batch_len); | 928 | dst = vmap_batch(dest_obj, 0, batch_len); |
899 | if (!dst) { | 929 | if (!dst) { |
900 | DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n"); | 930 | DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n"); |
901 | i915_gem_object_unpin_pages(dest_obj); | ||
902 | ret = -ENOMEM; | 931 | ret = -ENOMEM; |
903 | goto unmap_src; | 932 | goto unmap_src; |
904 | } | 933 | } |
@@ -939,7 +968,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring) | |||
939 | 968 | ||
940 | static bool check_cmd(const struct intel_engine_cs *ring, | 969 | static bool check_cmd(const struct intel_engine_cs *ring, |
941 | const struct drm_i915_cmd_descriptor *desc, | 970 | const struct drm_i915_cmd_descriptor *desc, |
942 | const u32 *cmd, | 971 | const u32 *cmd, u32 length, |
943 | const bool is_master, | 972 | const bool is_master, |
944 | bool *oacontrol_set) | 973 | bool *oacontrol_set) |
945 | { | 974 | { |
@@ -955,38 +984,70 @@ static bool check_cmd(const struct intel_engine_cs *ring, | |||
955 | } | 984 | } |
956 | 985 | ||
957 | if (desc->flags & CMD_DESC_REGISTER) { | 986 | if (desc->flags & CMD_DESC_REGISTER) { |
958 | u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; | ||
959 | |||
960 | /* | 987 | /* |
961 | * OACONTROL requires some special handling for writes. We | 988 | * Get the distance between individual register offset |
962 | * want to make sure that any batch which enables OA also | 989 | * fields if the command can perform more than one |
963 | * disables it before the end of the batch. The goal is to | 990 | * access at a time. |
964 | * prevent one process from snooping on the perf data from | ||
965 | * another process. To do that, we need to check the value | ||
966 | * that will be written to the register. Hence, limit | ||
967 | * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. | ||
968 | */ | 991 | */ |
969 | if (reg_addr == OACONTROL) { | 992 | const u32 step = desc->reg.step ? desc->reg.step : length; |
970 | if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { | 993 | u32 offset; |
971 | DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); | 994 | |
995 | for (offset = desc->reg.offset; offset < length; | ||
996 | offset += step) { | ||
997 | const u32 reg_addr = cmd[offset] & desc->reg.mask; | ||
998 | const struct drm_i915_reg_descriptor *reg = | ||
999 | find_reg(ring->reg_table, ring->reg_count, | ||
1000 | reg_addr); | ||
1001 | |||
1002 | if (!reg && is_master) | ||
1003 | reg = find_reg(ring->master_reg_table, | ||
1004 | ring->master_reg_count, | ||
1005 | reg_addr); | ||
1006 | |||
1007 | if (!reg) { | ||
1008 | DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", | ||
1009 | reg_addr, *cmd, ring->id); | ||
972 | return false; | 1010 | return false; |
973 | } | 1011 | } |
974 | 1012 | ||
975 | if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) | 1013 | /* |
976 | *oacontrol_set = (cmd[2] != 0); | 1014 | * OACONTROL requires some special handling for |
977 | } | 1015 | * writes. We want to make sure that any batch which |
1016 | * enables OA also disables it before the end of the | ||
1017 | * batch. The goal is to prevent one process from | ||
1018 | * snooping on the perf data from another process. To do | ||
1019 | * that, we need to check the value that will be written | ||
1020 | * to the register. Hence, limit OACONTROL writes to | ||
1021 | * only MI_LOAD_REGISTER_IMM commands. | ||
1022 | */ | ||
1023 | if (reg_addr == OACONTROL) { | ||
1024 | if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { | ||
1025 | DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); | ||
1026 | return false; | ||
1027 | } | ||
1028 | |||
1029 | if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) | ||
1030 | *oacontrol_set = (cmd[offset + 1] != 0); | ||
1031 | } | ||
978 | 1032 | ||
979 | if (!valid_reg(ring->reg_table, | 1033 | /* |
980 | ring->reg_count, reg_addr)) { | 1034 | * Check the value written to the register against the |
981 | if (!is_master || | 1035 | * allowed mask/value pair given in the whitelist entry. |
982 | !valid_reg(ring->master_reg_table, | 1036 | */ |
983 | ring->master_reg_count, | 1037 | if (reg->mask) { |
984 | reg_addr)) { | 1038 | if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { |
985 | DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", | 1039 | DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n", |
986 | reg_addr, | 1040 | reg_addr); |
987 | *cmd, | 1041 | return false; |
988 | ring->id); | 1042 | } |
989 | return false; | 1043 | |
1044 | if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1) && | ||
1045 | (offset + 2 > length || | ||
1046 | (cmd[offset + 1] & reg->mask) != reg->value)) { | ||
1047 | DRM_DEBUG_DRIVER("CMD: Rejected LRI to masked register 0x%08X\n", | ||
1048 | reg_addr); | ||
1049 | return false; | ||
1050 | } | ||
990 | } | 1051 | } |
991 | } | 1052 | } |
992 | } | 1053 | } |
@@ -1110,7 +1171,8 @@ int i915_parse_cmds(struct intel_engine_cs *ring, | |||
1110 | break; | 1171 | break; |
1111 | } | 1172 | } |
1112 | 1173 | ||
1113 | if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { | 1174 | if (!check_cmd(ring, desc, cmd, length, is_master, |
1175 | &oacontrol_set)) { | ||
1114 | ret = -EINVAL; | 1176 | ret = -EINVAL; |
1115 | break; | 1177 | break; |
1116 | } | 1178 | } |
@@ -1129,7 +1191,6 @@ int i915_parse_cmds(struct intel_engine_cs *ring, | |||
1129 | } | 1191 | } |
1130 | 1192 | ||
1131 | vunmap(batch_base); | 1193 | vunmap(batch_base); |
1132 | i915_gem_object_unpin_pages(shadow_batch_obj); | ||
1133 | 1194 | ||
1134 | return ret; | 1195 | return ret; |
1135 | } | 1196 | } |