2014-02-18 10:15:46 -08:00
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE .
*
* Authors :
* Brad Volkin < bradley . d . volkin @ intel . com >
*
*/
# include "i915_drv.h"
/**
2014-04-25 16:59:00 +02:00
* DOC : batch buffer command parser
2014-02-18 10:15:46 -08:00
*
* Motivation :
* Certain OpenGL features ( e . g . transform feedback , performance monitoring )
* require userspace code to submit batches containing commands such as
* MI_LOAD_REGISTER_IMM to access various registers . Unfortunately , some
* generations of the hardware will noop these commands in " unsecure " batches
* ( which includes all userspace batches submitted via i915 ) even though the
* commands may be safe and represent the intended programming model of the
* device .
*
* The software command parser is similar in operation to the command parsing
* done in hardware for unsecure batches . However , the software parser allows
* some operations that would be noop ' d by hardware , if the parser determines
* the operation is safe , and submits the batch as " secure " to prevent hardware
* parsing .
*
* Threats :
* At a high level , the hardware ( and software ) checks attempt to prevent
* granting userspace undue privileges . There are three categories of privilege .
*
* First , commands which are explicitly defined as privileged or which should
* only be used by the kernel driver . The parser generally rejects such
* commands , though it may allow some from the drm master process .
*
* Second , commands which access registers . To support correct / enhanced
* userspace functionality , particularly certain OpenGL extensions , the parser
* provides a whitelist of registers which userspace may safely access ( for both
* normal and drm master processes ) .
*
* Third , commands which access privileged memory ( i . e . GGTT , HWS page , etc ) .
* The parser always rejects such commands .
*
* The majority of the problematic commands fall in the MI_ * range , with only a
* few specific commands on each ring ( e . g . PIPE_CONTROL and MI_FLUSH_DW ) .
*
* Implementation :
* Each ring maintains tables of commands and registers which the parser uses in
* scanning batch buffers submitted to that ring .
*
* Since the set of commands that the parser must check for is significantly
* smaller than the number of commands supported , the parser tables contain only
* those commands required by the parser . This generally works because command
* opcode ranges have standard command length encodings . So for commands that
* the parser does not need to check , it can easily skip them . This is
2014-10-20 23:53:13 +09:00
* implemented via a per - ring length decoding vfunc .
2014-02-18 10:15:46 -08:00
*
* Unfortunately , there are a number of commands that do not follow the standard
* length encoding for their opcode range , primarily amongst the MI_ * commands .
* To handle this , the parser provides a way to define explicit " skip " entries
* in the per - ring command tables .
*
* Other command table entries map fairly directly to high level categories
* mentioned above : rejected , master - only , register whitelist . The parser
* implements a number of checks , including the privileged memory checks , via a
* general bitmasking mechanism .
*/
2014-02-18 10:15:47 -08:00
# 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 ) , \
2015-08-04 16:22:20 +01:00
. cmd = { ( op ) , ( opm ) } , \
2014-02-18 10:15:47 -08:00
. 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 ) ,
2014-02-18 10:15:53 -08:00
CMD ( MI_USER_INTERRUPT , SMI , F , 1 , R ) ,
2014-02-18 10:15:49 -08:00
CMD ( MI_WAIT_FOR_EVENT , SMI , F , 1 , M ) ,
2014-02-18 10:15:47 -08:00
CMD ( MI_ARB_CHECK , SMI , F , 1 , S ) ,
CMD ( MI_REPORT_HEAD , SMI , F , 1 , S ) ,
CMD ( MI_SUSPEND_FLUSH , SMI , F , 1 , S ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_SEMAPHORE_MBOX , SMI , ! F , 0xFF , R ) ,
CMD ( MI_STORE_DWORD_INDEX , SMI , ! F , 0xFF , R ) ,
2014-02-18 10:15:52 -08:00
CMD ( MI_LOAD_REGISTER_IMM ( 1 ) , SMI , ! F , 0xFF , W ,
2015-05-29 16:44:13 +03:00
. reg = { . offset = 1 , . mask = 0x007FFFFC , . step = 2 } ) ,
2015-09-02 12:29:40 +01:00
CMD ( MI_STORE_REGISTER_MEM , SMI , F , 3 , W | B ,
2014-02-18 10:15:54 -08:00
. reg = { . offset = 1 , . mask = 0x007FFFFC } ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
} } , ) ,
2015-09-02 12:29:40 +01:00
CMD ( MI_LOAD_REGISTER_MEM , SMI , F , 3 , W | B ,
2014-02-18 10:15:54 -08:00
. reg = { . offset = 1 , . mask = 0x007FFFFC } ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
} } , ) ,
2014-10-16 12:24:42 -07:00
/*
* MI_BATCH_BUFFER_START requires some special handling . It ' s not
* really a ' skip ' action but it doesn ' t seem like it ' s worth adding
* a new action . See i915_parse_cmds ( ) .
*/
2014-02-18 10:15:47 -08:00
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 ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_ARB_ON_OFF , SMI , F , 1 , R ) ,
2014-02-18 10:15:47 -08:00
CMD ( MI_PREDICATE , SMI , F , 1 , S ) ,
CMD ( MI_TOPOLOGY_FILTER , SMI , F , 1 , S ) ,
2014-11-21 09:35:36 -08:00
CMD ( MI_SET_APPID , SMI , F , 1 , S ) ,
2015-07-29 10:29:58 +02:00
CMD ( MI_DISPLAY_FLIP , SMI , ! F , 0xFF , R ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_SET_CONTEXT , SMI , ! F , 0xFF , R ) ,
2014-02-18 10:15:47 -08:00
CMD ( MI_URB_CLEAR , SMI , ! F , 0xFF , S ) ,
2014-02-18 10:15:54 -08:00
CMD ( MI_STORE_DWORD_IMM , SMI , ! F , 0x3F , B ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
} } , ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_UPDATE_GTT , SMI , ! F , 0xFF , R ) ,
2014-02-18 10:15:54 -08:00
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 ,
} } , ) ,
2014-02-18 10:15:47 -08:00
CMD ( GFX_OP_3DSTATE_VF_STATISTICS , S3D , F , 1 , S ) ,
CMD ( PIPELINE_SELECT , S3D , F , 1 , S ) ,
2014-02-18 10:15:52 -08:00
CMD ( MEDIA_VFE_STATE , S3D , ! F , 0xFFFF , B ,
. bits = { {
. offset = 2 ,
. mask = MEDIA_VFE_STATE_MMIO_ACCESS_MASK ,
. expected = 0 ,
} } , ) ,
2014-02-18 10:15:47 -08:00
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 ) ,
2014-02-18 10:15:52 -08:00
CMD ( GFX_OP_PIPE_CONTROL ( 5 ) , S3D , ! F , 0xFF , B ,
. bits = { {
. offset = 1 ,
2014-02-18 10:15:53 -08:00
. mask = ( PIPE_CONTROL_MMIO_WRITE | PIPE_CONTROL_NOTIFY ) ,
2014-02-18 10:15:52 -08:00
. expected = 0 ,
2014-02-18 10:15:54 -08:00
} ,
{
. offset = 1 ,
2014-02-18 10:15:55 -08:00
. mask = ( PIPE_CONTROL_GLOBAL_GTT_IVB |
PIPE_CONTROL_STORE_DATA_INDEX ) ,
2014-02-18 10:15:54 -08:00
. expected = 0 ,
. condition_offset = 1 ,
. condition_mask = PIPE_CONTROL_POST_SYNC_OP_MASK ,
2014-02-18 10:15:52 -08:00
} } , ) ,
2014-02-18 10:15:47 -08:00
} ;
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 ) ,
2014-11-21 09:35:36 -08:00
CMD ( MI_SET_APPID , SMI , F , 1 , S ) ,
2014-02-18 10:15:47 -08:00
CMD ( MI_RS_CONTEXT , SMI , F , 1 , S ) ,
2014-02-18 10:15:49 -08:00
CMD ( MI_LOAD_SCAN_LINES_INCL , SMI , ! F , 0x3F , M ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_LOAD_SCAN_LINES_EXCL , SMI , ! F , 0x3F , R ) ,
CMD ( MI_LOAD_REGISTER_REG , SMI , ! F , 0xFF , R ) ,
2014-02-18 10:15:47 -08:00
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 [ ] = {
2014-02-18 10:15:48 -08:00
CMD ( MI_ARB_ON_OFF , SMI , F , 1 , R ) ,
2014-11-21 09:35:36 -08:00
CMD ( MI_SET_APPID , SMI , F , 1 , S ) ,
2014-02-18 10:15:54 -08:00
CMD ( MI_STORE_DWORD_IMM , SMI , ! F , 0xFF , B ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
} } , ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_UPDATE_GTT , SMI , ! F , 0x3F , R ) ,
2014-02-18 10:15:53 -08:00
CMD ( MI_FLUSH_DW , SMI , ! F , 0x3F , B ,
. bits = { {
. offset = 0 ,
. mask = MI_FLUSH_DW_NOTIFY ,
. expected = 0 ,
2014-02-18 10:15:54 -08:00
} ,
{
. offset = 1 ,
. mask = MI_FLUSH_DW_USE_GTT ,
. expected = 0 ,
. condition_offset = 0 ,
. condition_mask = MI_FLUSH_DW_OP_MASK ,
2014-02-18 10:15:55 -08:00
} ,
{
. offset = 0 ,
. mask = MI_FLUSH_DW_STORE_INDEX ,
. expected = 0 ,
. condition_offset = 0 ,
. condition_mask = MI_FLUSH_DW_OP_MASK ,
2014-02-18 10:15:54 -08:00
} } , ) ,
CMD ( MI_CONDITIONAL_BATCH_BUFFER_END , SMI , ! F , 0xFF , B ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
2014-02-18 10:15:53 -08:00
} } , ) ,
2014-02-18 10:15:47 -08:00
/*
* 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 [ ] = {
2014-02-18 10:15:48 -08:00
CMD ( MI_ARB_ON_OFF , SMI , F , 1 , R ) ,
2014-11-21 09:35:36 -08:00
CMD ( MI_SET_APPID , SMI , F , 1 , S ) ,
2014-02-18 10:15:54 -08:00
CMD ( MI_STORE_DWORD_IMM , SMI , ! F , 0xFF , B ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
} } , ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_UPDATE_GTT , SMI , ! F , 0x3F , R ) ,
2014-02-18 10:15:53 -08:00
CMD ( MI_FLUSH_DW , SMI , ! F , 0x3F , B ,
. bits = { {
. offset = 0 ,
. mask = MI_FLUSH_DW_NOTIFY ,
. expected = 0 ,
2014-02-18 10:15:54 -08:00
} ,
{
. offset = 1 ,
. mask = MI_FLUSH_DW_USE_GTT ,
. expected = 0 ,
. condition_offset = 0 ,
. condition_mask = MI_FLUSH_DW_OP_MASK ,
2014-02-18 10:15:55 -08:00
} ,
{
. offset = 0 ,
. mask = MI_FLUSH_DW_STORE_INDEX ,
. expected = 0 ,
. condition_offset = 0 ,
. condition_mask = MI_FLUSH_DW_OP_MASK ,
2014-02-18 10:15:54 -08:00
} } , ) ,
CMD ( MI_CONDITIONAL_BATCH_BUFFER_END , SMI , ! F , 0xFF , B ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
2014-02-18 10:15:53 -08:00
} } , ) ,
2014-02-18 10:15:47 -08:00
} ;
static const struct drm_i915_cmd_descriptor blt_cmds [ ] = {
2014-02-18 10:15:48 -08:00
CMD ( MI_DISPLAY_FLIP , SMI , ! F , 0xFF , R ) ,
2014-02-18 10:15:54 -08:00
CMD ( MI_STORE_DWORD_IMM , SMI , ! F , 0x3FF , B ,
. bits = { {
. offset = 0 ,
. mask = MI_GLOBAL_GTT ,
. expected = 0 ,
} } , ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_UPDATE_GTT , SMI , ! F , 0x3F , R ) ,
2014-02-18 10:15:53 -08:00
CMD ( MI_FLUSH_DW , SMI , ! F , 0x3F , B ,
. bits = { {
. offset = 0 ,
. mask = MI_FLUSH_DW_NOTIFY ,
. expected = 0 ,
2014-02-18 10:15:54 -08:00
} ,
{
. offset = 1 ,
. mask = MI_FLUSH_DW_USE_GTT ,
. expected = 0 ,
. condition_offset = 0 ,
. condition_mask = MI_FLUSH_DW_OP_MASK ,
2014-02-18 10:15:55 -08:00
} ,
{
. offset = 0 ,
. mask = MI_FLUSH_DW_STORE_INDEX ,
. expected = 0 ,
. condition_offset = 0 ,
. condition_mask = MI_FLUSH_DW_OP_MASK ,
2014-02-18 10:15:53 -08:00
} } , ) ,
2014-02-18 10:15:47 -08:00
CMD ( COLOR_BLT , S2D , ! F , 0x3F , S ) ,
CMD ( SRC_COPY_BLT , S2D , ! F , 0x3F , S ) ,
} ;
2014-02-18 10:15:48 -08:00
static const struct drm_i915_cmd_descriptor hsw_blt_cmds [ ] = {
2014-02-18 10:15:49 -08:00
CMD ( MI_LOAD_SCAN_LINES_INCL , SMI , ! F , 0x3F , M ) ,
2014-02-18 10:15:48 -08:00
CMD ( MI_LOAD_SCAN_LINES_EXCL , SMI , ! F , 0x3F , R ) ,
} ;
2014-02-18 10:15:47 -08:00
# 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 ) } ,
} ;
2014-02-18 10:15:48 -08:00
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 ) } ,
} ;
2014-02-18 10:15:50 -08:00
/*
* Register whitelists , sorted by increasing register offset .
2015-05-29 16:44:14 +03:00
*/
/*
* An individual whitelist entry granting access to register addr . If
* mask is non - zero the argument of immediate register writes will be
* AND - ed with mask , and the command will be rejected if the result
* doesn ' t match value .
*
* Registers with non - zero mask are only allowed to be written using
* LRI .
*/
struct drm_i915_reg_descriptor {
u32 addr ;
u32 mask ;
u32 value ;
} ;
/* Convenience macro for adding 32-bit registers. */
# define REG32(address, ...) \
{ . addr = address , __VA_ARGS__ }
/*
* Convenience macro for adding 64 - bit registers .
2014-02-18 10:15:50 -08:00
*
* 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 .
*/
2015-05-29 16:44:14 +03:00
# define REG64(addr) \
REG32 ( addr ) , REG32 ( addr + sizeof ( u32 ) )
2014-02-18 10:15:50 -08:00
2015-05-29 16:44:14 +03:00
static const struct drm_i915_reg_descriptor gen7_render_regs [ ] = {
2014-12-11 13:28:09 -08:00
REG64 ( GPGPU_THREADS_DISPATCHED ) ,
2014-02-18 10:15:50 -08:00
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 ) ,
2015-05-29 16:44:14 +03:00
REG32 ( OACONTROL ) , /* Only allowed for LRI and SRM. See below. */
2014-11-07 19:00:26 +00:00
REG64 ( MI_PREDICATE_SRC0 ) ,
REG64 ( MI_PREDICATE_SRC1 ) ,
2015-05-29 16:44:14 +03:00
REG32 ( GEN7_3DPRIM_END_OFFSET ) ,
REG32 ( GEN7_3DPRIM_START_VERTEX ) ,
REG32 ( GEN7_3DPRIM_VERTEX_COUNT ) ,
REG32 ( GEN7_3DPRIM_INSTANCE_COUNT ) ,
REG32 ( GEN7_3DPRIM_START_INSTANCE ) ,
REG32 ( GEN7_3DPRIM_BASE_VERTEX ) ,
2015-10-01 23:09:58 -07:00
REG32 ( GEN7_GPGPU_DISPATCHDIMX ) ,
REG32 ( GEN7_GPGPU_DISPATCHDIMY ) ,
REG32 ( GEN7_GPGPU_DISPATCHDIMZ ) ,
2014-02-18 10:15:50 -08:00
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 ) ) ,
2014-04-08 14:18:58 -07:00
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 ) ) ,
2015-05-29 16:44:14 +03:00
REG32 ( GEN7_SO_WRITE_OFFSET ( 0 ) ) ,
REG32 ( GEN7_SO_WRITE_OFFSET ( 1 ) ) ,
REG32 ( GEN7_SO_WRITE_OFFSET ( 2 ) ) ,
REG32 ( GEN7_SO_WRITE_OFFSET ( 3 ) ) ,
REG32 ( GEN7_L3SQCREG1 ) ,
REG32 ( GEN7_L3CNTLREG2 ) ,
REG32 ( GEN7_L3CNTLREG3 ) ,
2015-05-29 16:44:15 +03:00
REG32 ( HSW_SCRATCH1 ,
. mask = ~ HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE ,
. value = 0 ) ,
REG32 ( HSW_ROW_CHICKEN3 ,
. mask = ~ ( HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE < < 16 |
HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE ) ,
. value = 0 ) ,
2014-02-18 10:15:50 -08:00
} ;
2015-05-29 16:44:14 +03:00
static const struct drm_i915_reg_descriptor gen7_blt_regs [ ] = {
REG32 ( BCS_SWCTRL ) ,
2014-02-18 10:15:50 -08:00
} ;
2015-05-29 16:44:14 +03:00
static const struct drm_i915_reg_descriptor ivb_master_regs [ ] = {
REG32 ( FORCEWAKE_MT ) ,
REG32 ( DERRMR ) ,
REG32 ( GEN7_PIPE_DE_LOAD_SL ( PIPE_A ) ) ,
REG32 ( GEN7_PIPE_DE_LOAD_SL ( PIPE_B ) ) ,
REG32 ( GEN7_PIPE_DE_LOAD_SL ( PIPE_C ) ) ,
2014-02-18 10:15:51 -08:00
} ;
2015-05-29 16:44:14 +03:00
static const struct drm_i915_reg_descriptor hsw_master_regs [ ] = {
REG32 ( FORCEWAKE_MT ) ,
REG32 ( DERRMR ) ,
2014-02-18 10:15:51 -08:00
} ;
2014-02-18 10:15:50 -08:00
# undef REG64
2015-05-29 16:44:14 +03:00
# undef REG32
2014-02-18 10:15:50 -08:00
2014-02-18 10:15:46 -08:00
static u32 gen7_render_get_cmd_length_mask ( u32 cmd_header )
{
u32 client = ( cmd_header & INSTR_CLIENT_MASK ) > > INSTR_CLIENT_SHIFT ;
u32 subclient =
( cmd_header & INSTR_SUBCLIENT_MASK ) > > INSTR_SUBCLIENT_SHIFT ;
if ( client = = INSTR_MI_CLIENT )
return 0x3F ;
else if ( client = = INSTR_RC_CLIENT ) {
if ( subclient = = INSTR_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 & INSTR_CLIENT_MASK ) > > INSTR_CLIENT_SHIFT ;
u32 subclient =
( cmd_header & INSTR_SUBCLIENT_MASK ) > > INSTR_SUBCLIENT_SHIFT ;
2014-11-21 09:35:36 -08:00
u32 op = ( cmd_header & INSTR_26_TO_24_MASK ) > > INSTR_26_TO_24_SHIFT ;
2014-02-18 10:15:46 -08:00
if ( client = = INSTR_MI_CLIENT )
return 0x3F ;
else if ( client = = INSTR_RC_CLIENT ) {
2014-11-21 09:35:36 -08:00
if ( subclient = = INSTR_MEDIA_SUBCLIENT ) {
if ( op = = 6 )
return 0xFFFF ;
else
return 0xFFF ;
} else
2014-02-18 10:15:46 -08:00
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 & INSTR_CLIENT_MASK ) > > INSTR_CLIENT_SHIFT ;
if ( client = = INSTR_MI_CLIENT )
return 0x3F ;
else if ( client = = INSTR_BC_CLIENT )
return 0xFF ;
DRM_DEBUG_DRIVER ( " CMD: Abnormal blt cmd length! 0x%08X \n " , cmd_header ) ;
return 0 ;
}
2014-05-22 14:13:33 +01:00
static bool validate_cmds_sorted ( struct intel_engine_cs * ring ,
2014-05-10 14:10:43 -07:00
const struct drm_i915_cmd_table * cmd_tables ,
int cmd_table_count )
2014-02-18 10:15:46 -08:00
{
int i ;
2014-03-27 11:43:38 -07:00
bool ret = true ;
2014-02-18 10:15:46 -08:00
2014-05-10 14:10:43 -07:00
if ( ! cmd_tables | | cmd_table_count = = 0 )
2014-03-27 11:43:38 -07:00
return true ;
2014-02-18 10:15:46 -08:00
2014-05-10 14:10:43 -07:00
for ( i = 0 ; i < cmd_table_count ; i + + ) {
const struct drm_i915_cmd_table * table = & cmd_tables [ i ] ;
2014-02-18 10:15:46 -08:00
u32 previous = 0 ;
int j ;
for ( j = 0 ; j < table - > count ; j + + ) {
const struct drm_i915_cmd_descriptor * desc =
2015-07-29 10:31:04 +02:00
& table - > table [ j ] ;
2014-02-18 10:15:46 -08:00
u32 curr = desc - > cmd . value & desc - > cmd . mask ;
2014-03-27 11:43:38 -07:00
if ( curr < previous ) {
2014-02-18 10:15:46 -08:00
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 ) ;
2014-03-27 11:43:38 -07:00
ret = false ;
}
2014-02-18 10:15:46 -08:00
previous = curr ;
}
}
2014-03-27 11:43:38 -07:00
return ret ;
2014-02-18 10:15:46 -08:00
}
2015-05-29 16:44:14 +03:00
static bool check_sorted ( int ring_id ,
const struct drm_i915_reg_descriptor * reg_table ,
int reg_count )
2014-02-18 10:15:46 -08:00
{
int i ;
u32 previous = 0 ;
2014-03-27 11:43:38 -07:00
bool ret = true ;
2014-02-18 10:15:46 -08:00
for ( i = 0 ; i < reg_count ; i + + ) {
2015-05-29 16:44:14 +03:00
u32 curr = reg_table [ i ] . addr ;
2014-02-18 10:15:46 -08:00
2014-03-27 11:43:38 -07:00
if ( curr < previous ) {
2014-02-18 10:15:46 -08:00
DRM_ERROR ( " CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X \n " ,
ring_id , i , curr , previous ) ;
2014-03-27 11:43:38 -07:00
ret = false ;
}
2014-02-18 10:15:46 -08:00
previous = curr ;
}
2014-03-27 11:43:38 -07:00
return ret ;
2014-02-18 10:15:46 -08:00
}
2014-05-22 14:13:33 +01:00
static bool validate_regs_sorted ( struct intel_engine_cs * ring )
2014-02-18 10:15:46 -08:00
{
2014-03-27 11:43:38 -07:00
return check_sorted ( ring - > id , ring - > reg_table , ring - > reg_count ) & &
check_sorted ( ring - > id , ring - > master_reg_table ,
ring - > master_reg_count ) ;
2014-02-18 10:15:46 -08:00
}
2014-05-10 14:10:43 -07:00
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 3 D 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 3 D
* 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
2014-05-22 14:13:33 +01:00
static int init_hash_table ( struct intel_engine_cs * ring ,
2014-05-10 14:10:43 -07:00
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 ;
}
2014-05-22 14:13:33 +01:00
static void fini_hash_table ( struct intel_engine_cs * ring )
2014-05-10 14:10:43 -07:00
{
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 ) ;
}
}
2014-02-18 10:15:46 -08:00
/**
* i915_cmd_parser_init_ring ( ) - set cmd parser related fields for a ringbuffer
* @ ring : the ringbuffer to initialize
*
* Optionally initializes fields related to batch buffer command parsing in the
2014-05-22 14:13:33 +01:00
* struct intel_engine_cs based on whether the platform requires software
2014-02-18 10:15:46 -08:00
* command parsing .
2014-05-10 14:10:43 -07:00
*
* Return : non - zero if initialization fails
2014-02-18 10:15:46 -08:00
*/
2014-05-22 14:13:33 +01:00
int i915_cmd_parser_init_ring ( struct intel_engine_cs * ring )
2014-02-18 10:15:46 -08:00
{
2014-05-10 14:10:43 -07:00
const struct drm_i915_cmd_table * cmd_tables ;
int cmd_table_count ;
int ret ;
2014-02-18 10:15:46 -08:00
if ( ! IS_GEN7 ( ring - > dev ) )
2014-05-10 14:10:43 -07:00
return 0 ;
2014-02-18 10:15:46 -08:00
switch ( ring - > id ) {
case RCS :
2014-02-18 10:15:47 -08:00
if ( IS_HASWELL ( ring - > dev ) ) {
2014-05-10 14:10:43 -07:00
cmd_tables = hsw_render_ring_cmds ;
cmd_table_count =
2014-02-18 10:15:47 -08:00
ARRAY_SIZE ( hsw_render_ring_cmds ) ;
} else {
2014-05-10 14:10:43 -07:00
cmd_tables = gen7_render_cmds ;
cmd_table_count = ARRAY_SIZE ( gen7_render_cmds ) ;
2014-02-18 10:15:47 -08:00
}
2014-02-18 10:15:50 -08:00
ring - > reg_table = gen7_render_regs ;
ring - > reg_count = ARRAY_SIZE ( gen7_render_regs ) ;
2014-02-18 10:15:51 -08:00
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 ) ;
}
2014-02-18 10:15:46 -08:00
ring - > get_cmd_length_mask = gen7_render_get_cmd_length_mask ;
break ;
case VCS :
2014-05-10 14:10:43 -07:00
cmd_tables = gen7_video_cmds ;
cmd_table_count = ARRAY_SIZE ( gen7_video_cmds ) ;
2014-02-18 10:15:46 -08:00
ring - > get_cmd_length_mask = gen7_bsd_get_cmd_length_mask ;
break ;
case BCS :
2014-02-18 10:15:48 -08:00
if ( IS_HASWELL ( ring - > dev ) ) {
2014-05-10 14:10:43 -07:00
cmd_tables = hsw_blt_ring_cmds ;
cmd_table_count = ARRAY_SIZE ( hsw_blt_ring_cmds ) ;
2014-02-18 10:15:48 -08:00
} else {
2014-05-10 14:10:43 -07:00
cmd_tables = gen7_blt_cmds ;
cmd_table_count = ARRAY_SIZE ( gen7_blt_cmds ) ;
2014-02-18 10:15:48 -08:00
}
2014-02-18 10:15:50 -08:00
ring - > reg_table = gen7_blt_regs ;
ring - > reg_count = ARRAY_SIZE ( gen7_blt_regs ) ;
2014-02-18 10:15:51 -08:00
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 ) ;
}
2014-02-18 10:15:46 -08:00
ring - > get_cmd_length_mask = gen7_blt_get_cmd_length_mask ;
break ;
case VECS :
2014-05-10 14:10:43 -07:00
cmd_tables = hsw_vebox_cmds ;
cmd_table_count = ARRAY_SIZE ( hsw_vebox_cmds ) ;
2014-02-18 10:15:46 -08:00
/* VECS can use the same length_mask function as VCS */
ring - > 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 ) ;
BUG ( ) ;
}
2014-05-10 14:10:43 -07:00
BUG_ON ( ! validate_cmds_sorted ( ring , cmd_tables , cmd_table_count ) ) ;
2014-03-27 11:43:38 -07:00
BUG_ON ( ! validate_regs_sorted ( ring ) ) ;
2014-05-10 14:10:43 -07:00
2014-11-20 00:33:08 +01:00
WARN_ON ( ! hash_empty ( ring - > cmd_hash ) ) ;
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 ;
2014-05-10 14:10:43 -07:00
}
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 .
*/
2014-05-22 14:13:33 +01:00
void i915_cmd_parser_fini_ring ( struct intel_engine_cs * ring )
2014-05-10 14:10:43 -07:00
{
if ( ! ring - > needs_cmd_parser )
return ;
fini_hash_table ( ring ) ;
2014-02-18 10:15:46 -08:00
}
static const struct drm_i915_cmd_descriptor *
2014-05-22 14:13:33 +01:00
find_cmd_in_table ( struct intel_engine_cs * ring ,
2014-02-18 10:15:46 -08:00
u32 cmd_header )
{
2014-05-10 14:10:43 -07:00
struct cmd_node * desc_node ;
2014-02-18 10:15:46 -08:00
2014-05-10 14:10:43 -07:00
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 ;
2014-02-18 10:15:46 -08:00
u32 masked_cmd = desc - > cmd . mask & cmd_header ;
u32 masked_value = desc - > cmd . value & desc - > cmd . mask ;
if ( masked_cmd = = masked_value )
return desc ;
}
return NULL ;
}
/*
* Returns a pointer to a descriptor for the command specified by cmd_header .
*
* The caller must supply space for a default descriptor via the default_desc
* parameter . If no descriptor for the specified command exists in the ring ' s
* command parser tables , this function fills in default_desc based on the
* ring ' s default length encoding and returns default_desc .
*/
static const struct drm_i915_cmd_descriptor *
2014-05-22 14:13:33 +01:00
find_cmd ( struct intel_engine_cs * ring ,
2014-02-18 10:15:46 -08:00
u32 cmd_header ,
struct drm_i915_cmd_descriptor * default_desc )
{
2014-05-10 14:10:43 -07:00
const struct drm_i915_cmd_descriptor * desc ;
2014-02-18 10:15:46 -08:00
u32 mask ;
2014-05-10 14:10:43 -07:00
desc = find_cmd_in_table ( ring , cmd_header ) ;
if ( desc )
return desc ;
2014-02-18 10:15:46 -08:00
mask = ring - > get_cmd_length_mask ( cmd_header ) ;
if ( ! mask )
return NULL ;
BUG_ON ( ! default_desc ) ;
default_desc - > flags = CMD_DESC_SKIP ;
default_desc - > length . mask = mask ;
return default_desc ;
}
2015-05-29 16:44:14 +03:00
static const struct drm_i915_reg_descriptor *
find_reg ( const struct drm_i915_reg_descriptor * table ,
int count , u32 addr )
2014-02-18 10:15:46 -08:00
{
2015-05-29 16:44:14 +03:00
if ( table ) {
2014-02-18 10:15:46 -08:00
int i ;
for ( i = 0 ; i < count ; i + + ) {
2015-05-29 16:44:14 +03:00
if ( table [ i ] . addr = = addr )
return & table [ i ] ;
2014-02-18 10:15:46 -08:00
}
}
2015-05-29 16:44:14 +03:00
return NULL ;
2014-02-18 10:15:46 -08:00
}
2015-01-14 11:20:57 +00:00
static u32 * vmap_batch ( struct drm_i915_gem_object * obj ,
unsigned start , unsigned len )
2014-02-18 10:15:46 -08:00
{
int i ;
void * addr = NULL ;
struct sg_page_iter sg_iter ;
2015-01-14 11:20:57 +00:00
int first_page = start > > PAGE_SHIFT ;
int last_page = ( len + start + 4095 ) > > PAGE_SHIFT ;
int npages = last_page - first_page ;
2014-02-18 10:15:46 -08:00
struct page * * pages ;
2015-01-14 11:20:57 +00:00
pages = drm_malloc_ab ( npages , sizeof ( * pages ) ) ;
2014-02-18 10:15:46 -08:00
if ( pages = = NULL ) {
DRM_DEBUG_DRIVER ( " Failed to get space for pages \n " ) ;
goto finish ;
}
i = 0 ;
2015-03-13 15:21:53 +02:00
for_each_sg_page ( obj - > pages - > sgl , & sg_iter , obj - > pages - > nents , first_page ) {
2015-01-14 11:20:57 +00:00
pages [ i + + ] = sg_page_iter_page ( & sg_iter ) ;
2015-03-13 15:21:53 +02:00
if ( i = = npages )
break ;
}
2014-02-18 10:15:46 -08:00
addr = vmap ( pages , i , 0 , PAGE_KERNEL ) ;
if ( addr = = NULL ) {
DRM_DEBUG_DRIVER ( " Failed to vmap pages \n " ) ;
goto finish ;
}
finish :
if ( pages )
drm_free_large ( pages ) ;
return ( u32 * ) addr ;
}
2014-12-11 12:13:09 -08:00
/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */
static u32 * copy_batch ( struct drm_i915_gem_object * dest_obj ,
2014-12-11 12:13:10 -08:00
struct drm_i915_gem_object * src_obj ,
u32 batch_start_offset ,
u32 batch_len )
2014-12-11 12:13:09 -08:00
{
int needs_clflush = 0 ;
2015-01-14 11:20:57 +00:00
void * src_base , * src ;
void * dst = NULL ;
int ret ;
2014-12-11 12:13:10 -08:00
2015-01-14 11:20:57 +00:00
if ( batch_len > dest_obj - > base . size | |
batch_len + batch_start_offset > src_obj - > base . size )
2014-12-11 12:13:10 -08:00
return ERR_PTR ( - E2BIG ) ;
2014-12-11 12:13:09 -08:00
2015-04-07 16:20:35 +01:00
if ( WARN_ON ( dest_obj - > pages_pin_count = = 0 ) )
return ERR_PTR ( - ENODEV ) ;
2014-12-11 12:13:09 -08:00
ret = i915_gem_obj_prepare_shmem_read ( src_obj , & needs_clflush ) ;
if ( ret ) {
2015-01-14 11:20:57 +00:00
DRM_DEBUG_DRIVER ( " CMD: failed to prepare shadow batch \n " ) ;
2014-12-11 12:13:09 -08:00
return ERR_PTR ( ret ) ;
}
2015-01-14 11:20:57 +00:00
src_base = vmap_batch ( src_obj , batch_start_offset , batch_len ) ;
2014-12-11 12:13:10 -08:00
if ( ! src_base ) {
2014-12-11 12:13:09 -08:00
DRM_DEBUG_DRIVER ( " CMD: Failed to vmap batch \n " ) ;
ret = - ENOMEM ;
goto unpin_src ;
}
ret = i915_gem_object_set_to_cpu_domain ( dest_obj , true ) ;
if ( ret ) {
2015-01-14 11:20:57 +00:00
DRM_DEBUG_DRIVER ( " CMD: Failed to set shadow batch to CPU \n " ) ;
2014-12-11 12:13:09 -08:00
goto unmap_src ;
}
2015-01-14 11:20:57 +00:00
dst = vmap_batch ( dest_obj , 0 , batch_len ) ;
if ( ! dst ) {
2014-12-11 12:13:09 -08:00
DRM_DEBUG_DRIVER ( " CMD: Failed to vmap shadow batch \n " ) ;
ret = - ENOMEM ;
goto unmap_src ;
}
2015-01-14 11:20:57 +00:00
src = src_base + offset_in_page ( batch_start_offset ) ;
if ( needs_clflush )
drm_clflush_virt_range ( src , batch_len ) ;
2014-12-11 12:13:10 -08:00
2015-01-14 11:20:57 +00:00
memcpy ( dst , src , batch_len ) ;
2014-12-11 12:13:09 -08:00
unmap_src :
2014-12-11 12:13:10 -08:00
vunmap ( src_base ) ;
2014-12-11 12:13:09 -08:00
unpin_src :
i915_gem_object_unpin_pages ( src_obj ) ;
2015-01-14 11:20:57 +00:00
return ret ? ERR_PTR ( ret ) : dst ;
2014-12-11 12:13:09 -08:00
}
2014-02-18 10:15:46 -08:00
/**
* i915_needs_cmd_parser ( ) - should a given ring use software command parsing ?
* @ ring : the ring in question
*
* Only certain platforms require software batch buffer command parsing , and
2014-10-20 23:53:13 +09:00
* only when enabled via module parameter .
2014-02-18 10:15:46 -08:00
*
* Return : true if the ring requires software command parsing
*/
2014-05-22 14:13:33 +01:00
bool i915_needs_cmd_parser ( struct intel_engine_cs * ring )
2014-02-18 10:15:46 -08:00
{
2014-05-10 14:10:43 -07:00
if ( ! ring - > needs_cmd_parser )
2014-02-18 10:15:46 -08:00
return false ;
2014-09-18 16:26:26 -07:00
if ( ! USES_PPGTT ( ring - > dev ) )
2014-02-18 10:15:54 -08:00
return false ;
2014-02-18 10:15:46 -08:00
return ( i915 . enable_cmd_parser = = 1 ) ;
}
2014-05-22 14:13:33 +01:00
static bool check_cmd ( const struct intel_engine_cs * ring ,
2014-03-27 11:43:39 -07:00
const struct drm_i915_cmd_descriptor * desc ,
2015-05-29 16:44:13 +03:00
const u32 * cmd , u32 length ,
2014-03-28 10:21:50 -07:00
const bool is_master ,
bool * oacontrol_set )
2014-03-27 11:43:39 -07:00
{
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 ) {
2014-03-28 10:21:50 -07:00
/*
2015-05-29 16:44:13 +03:00
* Get the distance between individual register offset
* fields if the command can perform more than one
* access at a time .
2014-03-28 10:21:50 -07:00
*/
2015-05-29 16:44:13 +03:00
const u32 step = desc - > reg . step ? desc - > reg . step : length ;
u32 offset ;
for ( offset = desc - > reg . offset ; offset < length ;
offset + = step ) {
const u32 reg_addr = cmd [ offset ] & desc - > reg . mask ;
2015-05-29 16:44:14 +03:00
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 ) ;
if ( ! reg ) {
DRM_DEBUG_DRIVER ( " CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d) \n " ,
reg_addr , * cmd , ring - > id ) ;
return false ;
}
2015-05-29 16:44:13 +03:00
/*
* 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 ) {
2015-08-04 16:22:20 +01:00
if ( desc - > cmd . value = = MI_LOAD_REGISTER_MEM ) {
2015-05-29 16:44:13 +03:00
DRM_DEBUG_DRIVER ( " CMD: Rejected LRM to OACONTROL \n " ) ;
return false ;
}
if ( desc - > cmd . value = = MI_LOAD_REGISTER_IMM ( 1 ) )
* oacontrol_set = ( cmd [ offset + 1 ] ! = 0 ) ;
2014-09-18 16:26:27 -07:00
}
2014-03-28 10:21:50 -07:00
2015-05-29 16:44:14 +03:00
/*
* Check the value written to the register against the
* allowed mask / value pair given in the whitelist entry .
*/
if ( reg - > mask ) {
2015-08-04 16:22:20 +01:00
if ( desc - > cmd . value = = MI_LOAD_REGISTER_MEM ) {
2015-05-29 16:44:14 +03:00
DRM_DEBUG_DRIVER ( " CMD: Rejected LRM 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 ) ) {
DRM_DEBUG_DRIVER ( " CMD: Rejected LRI to masked register 0x%08X \n " ,
reg_addr ) ;
2015-05-29 16:44:13 +03:00
return false ;
}
2014-03-27 11:43:39 -07:00
}
}
}
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 ;
}
2014-02-18 10:15:46 -08:00
# define LENGTH_BIAS 2
/**
* i915_parse_cmds ( ) - parse a submitted batch buffer for privilege violations
* @ ring : the ring on which the batch is to execute
* @ batch_obj : the batch buffer in question
2014-12-11 12:13:09 -08:00
* @ shadow_batch_obj : copy of the batch buffer in question
2014-02-18 10:15:46 -08:00
* @ batch_start_offset : byte offset in the batch at which execution starts
2014-12-11 12:13:10 -08:00
* @ batch_len : length of the commands in batch_obj
2014-02-18 10:15:46 -08:00
* @ is_master : is the submitting process the drm master ?
*
* Parses the specified batch buffer looking for privilege violations as
* described in the overview .
*
2014-10-16 12:24:42 -07:00
* Return : non - zero if the parser finds violations or otherwise fails ; - EACCES
* if the batch appears legal but should use hardware parsing
2014-02-18 10:15:46 -08:00
*/
2014-05-22 14:13:33 +01:00
int i915_parse_cmds ( struct intel_engine_cs * ring ,
2014-02-18 10:15:46 -08:00
struct drm_i915_gem_object * batch_obj ,
2014-12-11 12:13:09 -08:00
struct drm_i915_gem_object * shadow_batch_obj ,
2014-02-18 10:15:46 -08:00
u32 batch_start_offset ,
2014-12-11 12:13:10 -08:00
u32 batch_len ,
2014-02-18 10:15:46 -08:00
bool is_master )
{
u32 * cmd , * batch_base , * batch_end ;
struct drm_i915_cmd_descriptor default_desc = { 0 } ;
2014-03-28 10:21:50 -07:00
bool oacontrol_set = false ; /* OACONTROL tracking. See check_cmd() */
2015-01-14 11:20:57 +00:00
int ret = 0 ;
2014-12-11 12:13:12 -08:00
2014-12-11 12:13:10 -08:00
batch_base = copy_batch ( shadow_batch_obj , batch_obj ,
batch_start_offset , batch_len ) ;
2014-12-11 12:13:09 -08:00
if ( IS_ERR ( batch_base ) ) {
DRM_DEBUG_DRIVER ( " CMD: Failed to copy batch \n " ) ;
return PTR_ERR ( batch_base ) ;
2014-02-18 10:15:46 -08:00
}
2014-12-11 12:13:09 -08:00
/*
2014-12-11 12:13:10 -08:00
* We use the batch length as size because the shadow object is as
2014-12-11 12:13:09 -08:00
* large or larger and copy_batch ( ) will write MI_NOPs to the extra
* space . Parsing should be faster in some cases this way .
*/
2015-01-14 11:20:57 +00:00
batch_end = batch_base + ( batch_len / sizeof ( * batch_end ) ) ;
2014-02-18 10:15:46 -08:00
2015-01-14 11:20:57 +00:00
cmd = batch_base ;
2014-02-18 10:15:46 -08:00
while ( cmd < batch_end ) {
const struct drm_i915_cmd_descriptor * desc ;
u32 length ;
if ( * cmd = = MI_BATCH_BUFFER_END )
break ;
desc = find_cmd ( ring , * cmd , & default_desc ) ;
if ( ! desc ) {
DRM_DEBUG_DRIVER ( " CMD: Unrecognized command: 0x%08X \n " ,
* cmd ) ;
ret = - EINVAL ;
break ;
}
2014-10-16 12:24:42 -07:00
/*
* If the batch buffer contains a chained batch , return an
* error that tells the caller to abort and dispatch the
* workload as a non - secure batch .
*/
if ( desc - > cmd . value = = MI_BATCH_BUFFER_START ) {
ret = - EACCES ;
break ;
}
2014-02-18 10:15:46 -08:00
if ( desc - > flags & CMD_DESC_FIXED )
length = desc - > length . fixed ;
else
length = ( ( * cmd & desc - > length . mask ) + LENGTH_BIAS ) ;
if ( ( batch_end - cmd ) < length ) {
2014-04-02 11:24:20 +03:00
DRM_DEBUG_DRIVER ( " CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td \n " ,
2014-02-18 10:15:46 -08:00
* cmd ,
length ,
2014-04-28 15:03:23 +02:00
batch_end - cmd ) ;
2014-02-18 10:15:46 -08:00
ret = - EINVAL ;
break ;
}
2015-05-29 16:44:13 +03:00
if ( ! check_cmd ( ring , desc , cmd , length , is_master ,
& oacontrol_set ) ) {
2014-02-18 10:15:46 -08:00
ret = - EINVAL ;
break ;
}
cmd + = length ;
}
2014-03-28 10:21:50 -07:00
if ( oacontrol_set ) {
DRM_DEBUG_DRIVER ( " CMD: batch set OACONTROL but did not clear it \n " ) ;
ret = - EINVAL ;
}
2014-02-18 10:15:46 -08:00
if ( cmd > = batch_end ) {
DRM_DEBUG_DRIVER ( " CMD: Got to the end of the buffer w/o a BBE cmd! \n " ) ;
ret = - EINVAL ;
}
vunmap ( batch_base ) ;
return ret ;
}
2014-02-18 10:15:56 -08:00
/**
* 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 ) .
2014-11-07 19:00:26 +00:00
* 2. Allow access to the MI_PREDICATE_SRC0 and
* MI_PREDICATE_SRC1 registers .
2014-12-11 13:28:09 -08:00
* 3. Allow access to the GPGPU_THREADS_DISPATCHED register .
2015-06-15 14:03:29 +03:00
* 4. L3 atomic chicken bits of HSW_SCRATCH1 and HSW_ROW_CHICKEN3 .
2015-10-01 23:09:58 -07:00
* 5. GPGPU dispatch compute indirect registers .
2014-02-18 10:15:56 -08:00
*/
2015-10-01 23:09:58 -07:00
return 5 ;
2014-02-18 10:15:56 -08:00
}