@@ -137,6 +137,62 @@ static const struct drm_i915_cmd_table gen7_blt_cmds[] = {
{ blt_cmds, ARRAY_SIZE(blt_cmds) },
};
+#define CLIENT_MASK 0xE0000000
+#define SUBCLIENT_MASK 0x18000000
+#define MI_CLIENT 0x00000000
+#define RC_CLIENT 0x60000000
+#define BC_CLIENT 0x40000000
+#define MEDIA_SUBCLIENT 0x10000000
+
+static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
+{
+ u32 client = cmd_header & CLIENT_MASK;
+ u32 subclient = cmd_header & SUBCLIENT_MASK;
+
+ if (client == MI_CLIENT)
+ return 0x3F;
+ else if (client == RC_CLIENT) {
+ if (subclient == MEDIA_SUBCLIENT)
+ return 0xFFFF;
+ else
+ return 0xFF;
+ }
+
+ DRM_DEBUG_DRIVER("CMD: Abnormal rcs cmd length! 0x%08X\n", cmd_header);
+ return 0;
+}
+
+static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header)
+{
+ u32 client = cmd_header & CLIENT_MASK;
+ u32 subclient = cmd_header & SUBCLIENT_MASK;
+
+ if (client == MI_CLIENT)
+ return 0x3F;
+ else if (client == RC_CLIENT) {
+ if (subclient == MEDIA_SUBCLIENT)
+ return 0xFFF;
+ else
+ return 0xFF;
+ }
+
+ DRM_DEBUG_DRIVER("CMD: Abnormal bsd cmd length! 0x%08X\n", cmd_header);
+ return 0;
+}
+
+static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
+{
+ u32 client = cmd_header & CLIENT_MASK;
+
+ if (client == MI_CLIENT)
+ return 0x3F;
+ else if (client == BC_CLIENT)
+ return 0xFF;
+
+ DRM_DEBUG_DRIVER("CMD: Abnormal blt cmd length! 0x%08X\n", cmd_header);
+ return 0;
+}
+
void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring)
{
if (!IS_GEN7(ring->dev))
@@ -152,18 +208,24 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring)
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;
default:
DRM_DEBUG("CMD: cmd_parser_init with unknown ring: %d\n",
@@ -169,6 +169,18 @@ struct intel_ring_buffer {
*/
const struct drm_i915_cmd_table *cmd_tables;
int cmd_table_count;
+
+ /**
+ * Returns the bitmask for the length field of the specified command.
+ * Return 0 for an unrecognized/invalid command.
+ *
+ * If the command parser finds an entry for a command in the ring's
+ * cmd_tables, it gets the command's length based on the table entry.
+ * If not, it calls this function to determine the per-ring length field
+ * encoding for the command (i.e. certain opcode ranges use certain bits
+ * to encode the command length in the header).
+ */
+ u32 (*get_cmd_length_mask)(u32 cmd_header);
};
static inline bool