drm/i915/ilk: Don't disable SSC source if it's in use
[cascardo/linux.git] / drivers / gpu / drm / i915 / i915_cmd_parser.c
index 814d894..b0fd6a7 100644 (file)
@@ -215,7 +215,8 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = {
        CMD(  MI_RS_CONTEXT,                    SMI,    F,  1,      S  ),
        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_LOAD_REGISTER_REG,             SMI,   !F,  0xFF,   W,
+             .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 1 }    ),
        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  ),
@@ -444,6 +445,7 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
        REG64(CL_PRIMITIVES_COUNT),
        REG64(PS_INVOCATION_COUNT),
        REG64(PS_DEPTH_COUNT),
+       REG64_IDX(RING_TIMESTAMP, RENDER_RING_BASE),
        REG32(OACONTROL), /* Only allowed for LRI and SRM. See below. */
        REG64(MI_PREDICATE_SRC0),
        REG64(MI_PREDICATE_SRC1),
@@ -471,6 +473,25 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
        REG32(GEN7_L3SQCREG1),
        REG32(GEN7_L3CNTLREG2),
        REG32(GEN7_L3CNTLREG3),
+};
+
+static const struct drm_i915_reg_descriptor hsw_render_regs[] = {
+       REG64_IDX(HSW_CS_GPR, 0),
+       REG64_IDX(HSW_CS_GPR, 1),
+       REG64_IDX(HSW_CS_GPR, 2),
+       REG64_IDX(HSW_CS_GPR, 3),
+       REG64_IDX(HSW_CS_GPR, 4),
+       REG64_IDX(HSW_CS_GPR, 5),
+       REG64_IDX(HSW_CS_GPR, 6),
+       REG64_IDX(HSW_CS_GPR, 7),
+       REG64_IDX(HSW_CS_GPR, 8),
+       REG64_IDX(HSW_CS_GPR, 9),
+       REG64_IDX(HSW_CS_GPR, 10),
+       REG64_IDX(HSW_CS_GPR, 11),
+       REG64_IDX(HSW_CS_GPR, 12),
+       REG64_IDX(HSW_CS_GPR, 13),
+       REG64_IDX(HSW_CS_GPR, 14),
+       REG64_IDX(HSW_CS_GPR, 15),
        REG32(HSW_SCRATCH1,
              .mask = ~HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE,
              .value = 0),
@@ -500,6 +521,33 @@ static const struct drm_i915_reg_descriptor hsw_master_regs[] = {
 #undef REG64
 #undef REG32
 
+struct drm_i915_reg_table {
+       const struct drm_i915_reg_descriptor *regs;
+       int num_regs;
+       bool master;
+};
+
+static const struct drm_i915_reg_table ivb_render_reg_tables[] = {
+       { gen7_render_regs, ARRAY_SIZE(gen7_render_regs), false },
+       { ivb_master_regs, ARRAY_SIZE(ivb_master_regs), true },
+};
+
+static const struct drm_i915_reg_table ivb_blt_reg_tables[] = {
+       { gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs), false },
+       { ivb_master_regs, ARRAY_SIZE(ivb_master_regs), true },
+};
+
+static const struct drm_i915_reg_table hsw_render_reg_tables[] = {
+       { gen7_render_regs, ARRAY_SIZE(gen7_render_regs), false },
+       { hsw_render_regs, ARRAY_SIZE(hsw_render_regs), false },
+       { hsw_master_regs, ARRAY_SIZE(hsw_master_regs), true },
+};
+
+static const struct drm_i915_reg_table hsw_blt_reg_tables[] = {
+       { gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs), false },
+       { hsw_master_regs, ARRAY_SIZE(hsw_master_regs), true },
+};
+
 static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
 {
        u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
@@ -555,7 +603,7 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
        return 0;
 }
 
-static bool validate_cmds_sorted(struct intel_engine_cs *ring,
+static bool validate_cmds_sorted(struct intel_engine_cs *engine,
                                 const struct drm_i915_cmd_table *cmd_tables,
                                 int cmd_table_count)
 {
@@ -577,7 +625,7 @@ static bool validate_cmds_sorted(struct intel_engine_cs *ring,
 
                        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);
+                                         engine->id, i, j, curr, previous);
                                ret = false;
                        }
 
@@ -611,11 +659,18 @@ static bool check_sorted(int ring_id,
        return ret;
 }
 
-static bool validate_regs_sorted(struct intel_engine_cs *ring)
+static bool validate_regs_sorted(struct intel_engine_cs *engine)
 {
-       return check_sorted(ring->id, ring->reg_table, ring->reg_count) &&
-               check_sorted(ring->id, ring->master_reg_table,
-                            ring->master_reg_count);
+       int i;
+       const struct drm_i915_reg_table *table;
+
+       for (i = 0; i < engine->reg_table_count; i++) {
+               table = &engine->reg_tables[i];
+               if (!check_sorted(engine->id, table->regs, table->num_regs))
+                       return false;
+       }
+
+       return true;
 }
 
 struct cmd_node {
@@ -639,13 +694,13 @@ struct cmd_node {
  */
 #define CMD_HASH_MASK STD_MI_OPCODE_MASK
 
-static int init_hash_table(struct intel_engine_cs *ring,
+static int init_hash_table(struct intel_engine_cs *engine,
                           const struct drm_i915_cmd_table *cmd_tables,
                           int cmd_table_count)
 {
        int i, j;
 
-       hash_init(ring->cmd_hash);
+       hash_init(engine->cmd_hash);
 
        for (i = 0; i < cmd_table_count; i++) {
                const struct drm_i915_cmd_table *table = &cmd_tables[i];
@@ -660,7 +715,7 @@ static int init_hash_table(struct intel_engine_cs *ring,
                                return -ENOMEM;
 
                        desc_node->desc = desc;
-                       hash_add(ring->cmd_hash, &desc_node->node,
+                       hash_add(engine->cmd_hash, &desc_node->node,
                                 desc->cmd.value & CMD_HASH_MASK);
                }
        }
@@ -668,13 +723,13 @@ static int init_hash_table(struct intel_engine_cs *ring,
        return 0;
 }
 
-static void fini_hash_table(struct intel_engine_cs *ring)
+static void fini_hash_table(struct intel_engine_cs *engine)
 {
        struct hlist_node *tmp;
        struct cmd_node *desc_node;
        int i;
 
-       hash_for_each_safe(ring->cmd_hash, i, tmp, desc_node, node) {
+       hash_for_each_safe(engine->cmd_hash, i, tmp, desc_node, node) {
                hash_del(&desc_node->node);
                kfree(desc_node);
        }
@@ -682,7 +737,7 @@ static void fini_hash_table(struct intel_engine_cs *ring)
 
 /**
  * i915_cmd_parser_init_ring() - set cmd parser related fields for a ringbuffer
- * @ring: the ringbuffer to initialize
+ * @engine: the engine to initialize
  *
  * Optionally initializes fields related to batch buffer command parsing in the
  * struct intel_engine_cs based on whether the platform requires software
@@ -690,18 +745,18 @@ static void fini_hash_table(struct intel_engine_cs *ring)
  *
  * Return: non-zero if initialization fails
  */
-int i915_cmd_parser_init_ring(struct intel_engine_cs *ring)
+int i915_cmd_parser_init_ring(struct intel_engine_cs *engine)
 {
        const struct drm_i915_cmd_table *cmd_tables;
        int cmd_table_count;
        int ret;
 
-       if (!IS_GEN7(ring->dev))
+       if (!IS_GEN7(engine->i915))
                return 0;
 
-       switch (ring->id) {
+       switch (engine->id) {
        case RCS:
-               if (IS_HASWELL(ring->dev)) {
+               if (IS_HASWELL(engine->i915)) {
                        cmd_tables = hsw_render_ring_cmds;
                        cmd_table_count =
                                ARRAY_SIZE(hsw_render_ring_cmds);
@@ -710,26 +765,23 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring)
                        cmd_table_count = ARRAY_SIZE(gen7_render_cmds);
                }
 
-               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);
+               if (IS_HASWELL(engine->i915)) {
+                       engine->reg_tables = hsw_render_reg_tables;
+                       engine->reg_table_count = ARRAY_SIZE(hsw_render_reg_tables);
                } else {
-                       ring->master_reg_table = ivb_master_regs;
-                       ring->master_reg_count = ARRAY_SIZE(ivb_master_regs);
+                       engine->reg_tables = ivb_render_reg_tables;
+                       engine->reg_table_count = ARRAY_SIZE(ivb_render_reg_tables);
                }
 
-               ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
+               engine->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
                break;
        case VCS:
                cmd_tables = gen7_video_cmds;
                cmd_table_count = ARRAY_SIZE(gen7_video_cmds);
-               ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
+               engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
                break;
        case BCS:
-               if (IS_HASWELL(ring->dev)) {
+               if (IS_HASWELL(engine->i915)) {
                        cmd_tables = hsw_blt_ring_cmds;
                        cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds);
                } else {
@@ -737,70 +789,67 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring)
                        cmd_table_count = ARRAY_SIZE(gen7_blt_cmds);
                }
 
-               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);
+               if (IS_HASWELL(engine->i915)) {
+                       engine->reg_tables = hsw_blt_reg_tables;
+                       engine->reg_table_count = ARRAY_SIZE(hsw_blt_reg_tables);
                } else {
-                       ring->master_reg_table = ivb_master_regs;
-                       ring->master_reg_count = ARRAY_SIZE(ivb_master_regs);
+                       engine->reg_tables = ivb_blt_reg_tables;
+                       engine->reg_table_count = ARRAY_SIZE(ivb_blt_reg_tables);
                }
 
-               ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
+               engine->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
                break;
        case VECS:
                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;
+               engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
                break;
        default:
                DRM_ERROR("CMD: cmd_parser_init with unknown ring: %d\n",
-                         ring->id);
+                         engine->id);
                BUG();
        }
 
-       BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count));
-       BUG_ON(!validate_regs_sorted(ring));
+       BUG_ON(!validate_cmds_sorted(engine, cmd_tables, cmd_table_count));
+       BUG_ON(!validate_regs_sorted(engine));
 
-       WARN_ON(!hash_empty(ring->cmd_hash));
+       WARN_ON(!hash_empty(engine->cmd_hash));
 
-       ret = init_hash_table(ring, cmd_tables, cmd_table_count);
+       ret = init_hash_table(engine, cmd_tables, cmd_table_count);
        if (ret) {
                DRM_ERROR("CMD: cmd_parser_init failed!\n");
-               fini_hash_table(ring);
+               fini_hash_table(engine);
                return ret;
        }
 
-       ring->needs_cmd_parser = true;
+       engine->needs_cmd_parser = true;
 
        return 0;
 }
 
 /**
  * i915_cmd_parser_fini_ring() - clean up cmd parser related fields
- * @ring: the ringbuffer to clean up
+ * @engine: the engine 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_engine_cs *ring)
+void i915_cmd_parser_fini_ring(struct intel_engine_cs *engine)
 {
-       if (!ring->needs_cmd_parser)
+       if (!engine->needs_cmd_parser)
                return;
 
-       fini_hash_table(ring);
+       fini_hash_table(engine);
 }
 
 static const struct drm_i915_cmd_descriptor*
-find_cmd_in_table(struct intel_engine_cs *ring,
+find_cmd_in_table(struct intel_engine_cs *engine,
                  u32 cmd_header)
 {
        struct cmd_node *desc_node;
 
-       hash_for_each_possible(ring->cmd_hash, desc_node, node,
+       hash_for_each_possible(engine->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;
@@ -822,18 +871,18 @@ find_cmd_in_table(struct intel_engine_cs *ring,
  * ring's default length encoding and returns default_desc.
  */
 static const struct drm_i915_cmd_descriptor*
-find_cmd(struct intel_engine_cs *ring,
+find_cmd(struct intel_engine_cs *engine,
         u32 cmd_header,
         struct drm_i915_cmd_descriptor *default_desc)
 {
        const struct drm_i915_cmd_descriptor *desc;
        u32 mask;
 
-       desc = find_cmd_in_table(ring, cmd_header);
+       desc = find_cmd_in_table(engine, cmd_header);
        if (desc)
                return desc;
 
-       mask = ring->get_cmd_length_mask(cmd_header);
+       mask = engine->get_cmd_length_mask(cmd_header);
        if (!mask)
                return NULL;
 
@@ -848,12 +897,31 @@ static const struct drm_i915_reg_descriptor *
 find_reg(const struct drm_i915_reg_descriptor *table,
         int count, u32 addr)
 {
-       if (table) {
-               int i;
+       int i;
 
-               for (i = 0; i < count; i++) {
-                       if (i915_mmio_reg_offset(table[i].addr) == addr)
-                               return &table[i];
+       for (i = 0; i < count; i++) {
+               if (i915_mmio_reg_offset(table[i].addr) == addr)
+                       return &table[i];
+       }
+
+       return NULL;
+}
+
+static const struct drm_i915_reg_descriptor *
+find_reg_in_tables(const struct drm_i915_reg_table *tables,
+                  int count, bool is_master, u32 addr)
+{
+       int i;
+       const struct drm_i915_reg_table *table;
+       const struct drm_i915_reg_descriptor *reg;
+
+       for (i = 0; i < count; i++) {
+               table = &tables[i];
+               if (!table->master || is_master) {
+                       reg = find_reg(table->regs, table->num_regs,
+                                      addr);
+                       if (reg != NULL)
+                               return reg;
                }
        }
 
@@ -956,25 +1024,25 @@ unpin_src:
 
 /**
  * i915_needs_cmd_parser() - should a given ring use software command parsing?
- * @ring: the ring in question
+ * @engine: the engine in question
  *
  * Only certain platforms require software batch buffer command parsing, and
  * only when enabled via module parameter.
  *
  * Return: true if the ring requires software command parsing
  */
-bool i915_needs_cmd_parser(struct intel_engine_cs *ring)
+bool i915_needs_cmd_parser(struct intel_engine_cs *engine)
 {
-       if (!ring->needs_cmd_parser)
+       if (!engine->needs_cmd_parser)
                return false;
 
-       if (!USES_PPGTT(ring->dev))
+       if (!USES_PPGTT(engine->i915))
                return false;
 
        return (i915.enable_cmd_parser == 1);
 }
 
-static bool check_cmd(const struct intel_engine_cs *ring,
+static bool check_cmd(const struct intel_engine_cs *engine,
                      const struct drm_i915_cmd_descriptor *desc,
                      const u32 *cmd, u32 length,
                      const bool is_master,
@@ -1004,17 +1072,14 @@ static bool check_cmd(const struct intel_engine_cs *ring,
                     offset += step) {
                        const u32 reg_addr = cmd[offset] & desc->reg.mask;
                        const struct drm_i915_reg_descriptor *reg =
-                               find_reg(ring->reg_table, ring->reg_count,
-                                        reg_addr);
-
-                       if (!reg && is_master)
-                               reg = find_reg(ring->master_reg_table,
-                                              ring->master_reg_count,
-                                              reg_addr);
+                               find_reg_in_tables(engine->reg_tables,
+                                                  engine->reg_table_count,
+                                                  is_master,
+                                                  reg_addr);
 
                        if (!reg) {
                                DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n",
-                                                reg_addr, *cmd, ring->id);
+                                                reg_addr, *cmd, engine->id);
                                return false;
                        }
 
@@ -1034,6 +1099,11 @@ static bool check_cmd(const struct intel_engine_cs *ring,
                                        return false;
                                }
 
+                               if (desc->cmd.value == MI_LOAD_REGISTER_REG) {
+                                       DRM_DEBUG_DRIVER("CMD: Rejected LRR to OACONTROL\n");
+                                       return false;
+                               }
+
                                if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1))
                                        *oacontrol_set = (cmd[offset + 1] != 0);
                        }
@@ -1049,6 +1119,12 @@ static bool check_cmd(const struct intel_engine_cs *ring,
                                        return false;
                                }
 
+                               if (desc->cmd.value == MI_LOAD_REGISTER_REG) {
+                                       DRM_DEBUG_DRIVER("CMD: Rejected LRR to masked register 0x%08X\n",
+                                                        reg_addr);
+                                       return false;
+                               }
+
                                if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1) &&
                                    (offset + 2 > length ||
                                     (cmd[offset + 1] & reg->mask) != reg->value)) {
@@ -1087,7 +1163,7 @@ static bool check_cmd(const struct intel_engine_cs *ring,
                                                 *cmd,
                                                 desc->bits[i].mask,
                                                 desc->bits[i].expected,
-                                                dword, ring->id);
+                                                dword, engine->id);
                                return false;
                        }
                }
@@ -1100,7 +1176,7 @@ static bool check_cmd(const struct intel_engine_cs *ring,
 
 /**
  * i915_parse_cmds() - parse a submitted batch buffer for privilege violations
- * @ring: the ring on which the batch is to execute
+ * @engine: the engine on which the batch is to execute
  * @batch_obj: the batch buffer in question
  * @shadow_batch_obj: copy of the batch buffer in question
  * @batch_start_offset: byte offset in the batch at which execution starts
@@ -1113,7 +1189,7 @@ static bool check_cmd(const struct intel_engine_cs *ring,
  * Return: non-zero if the parser finds violations or otherwise fails; -EACCES
  * if the batch appears legal but should use hardware parsing
  */
-int i915_parse_cmds(struct intel_engine_cs *ring,
+int i915_parse_cmds(struct intel_engine_cs *engine,
                    struct drm_i915_gem_object *batch_obj,
                    struct drm_i915_gem_object *shadow_batch_obj,
                    u32 batch_start_offset,
@@ -1147,7 +1223,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
                if (*cmd == MI_BATCH_BUFFER_END)
                        break;
 
-               desc = find_cmd(ring, *cmd, &default_desc);
+               desc = find_cmd(engine, *cmd, &default_desc);
                if (!desc) {
                        DRM_DEBUG_DRIVER("CMD: Unrecognized command: 0x%08X\n",
                                         *cmd);
@@ -1179,7 +1255,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
                        break;
                }
 
-               if (!check_cmd(ring, desc, cmd, length, is_master,
+               if (!check_cmd(engine, desc, cmd, length, is_master,
                               &oacontrol_set)) {
                        ret = -EINVAL;
                        break;
@@ -1205,14 +1281,28 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
 
 /**
  * i915_cmd_parser_get_version() - get the cmd parser version number
+ * @dev_priv: i915 device private
  *
  * 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)
+int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv)
 {
+       struct intel_engine_cs *engine;
+       bool active = false;
+
+       /* If the command parser is not enabled, report 0 - unsupported */
+       for_each_engine(engine, dev_priv) {
+               if (i915_needs_cmd_parser(engine)) {
+                       active = true;
+                       break;
+               }
+       }
+       if (!active)
+               return 0;
+
        /*
         * Command parser version history
         *
@@ -1223,6 +1313,8 @@ int i915_cmd_parser_get_version(void)
         * 3. Allow access to the GPGPU_THREADS_DISPATCHED register.
         * 4. L3 atomic chicken bits of HSW_SCRATCH1 and HSW_ROW_CHICKEN3.
         * 5. GPGPU dispatch compute indirect registers.
+        * 6. TIMESTAMP register and Haswell CS GPR registers
+        * 7. Allow MI_LOAD_REGISTER_REG between whitelisted registers.
         */
-       return 5;
+       return 7;
 }