mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
drm/etnaviv: add initial etnaviv DRM driver
This adds the etnaviv DRM driver and hooks it up in Makefiles and Kconfig. Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
committed by
Lucas Stach
parent
f04b205ac1
commit
a8c21a5451
@@ -266,3 +266,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
|
||||
source "drivers/gpu/drm/imx/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/vc4/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/etnaviv/Kconfig"
|
||||
|
||||
@@ -75,3 +75,4 @@ obj-y += i2c/
|
||||
obj-y += panel/
|
||||
obj-y += bridge/
|
||||
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
|
||||
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
config DRM_ETNAVIV
|
||||
tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
|
||||
depends on DRM
|
||||
depends on ARCH_MXC || ARCH_DOVE
|
||||
select SHMEM
|
||||
select TMPFS
|
||||
select IOMMU_API
|
||||
select IOMMU_SUPPORT
|
||||
select WANT_DEV_COREDUMP
|
||||
help
|
||||
DRM driver for Vivante GPUs.
|
||||
|
||||
config DRM_ETNAVIV_REGISTER_LOGGING
|
||||
bool "enable ETNAVIV register logging"
|
||||
depends on DRM_ETNAVIV
|
||||
help
|
||||
Compile in support for logging register reads/writes in a format
|
||||
that can be parsed by envytools demsm tool. If enabled, register
|
||||
logging can be switched on via etnaviv.reglog=y module param.
|
||||
@@ -0,0 +1,14 @@
|
||||
etnaviv-y := \
|
||||
etnaviv_buffer.o \
|
||||
etnaviv_cmd_parser.o \
|
||||
etnaviv_drv.o \
|
||||
etnaviv_dump.o \
|
||||
etnaviv_gem_prime.o \
|
||||
etnaviv_gem_submit.o \
|
||||
etnaviv_gem.o \
|
||||
etnaviv_gpu.o \
|
||||
etnaviv_iommu_v2.o \
|
||||
etnaviv_iommu.o \
|
||||
etnaviv_mmu.o
|
||||
|
||||
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o
|
||||
@@ -0,0 +1,218 @@
|
||||
#ifndef CMDSTREAM_XML
|
||||
#define CMDSTREAM_XML
|
||||
|
||||
/* Autogenerated file, DO NOT EDIT manually!
|
||||
|
||||
This file was generated by the rules-ng-ng headergen tool in this git repository:
|
||||
http://0x04.net/cgit/index.cgi/rules-ng-ng
|
||||
git clone git://0x04.net/rules-ng-ng
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- cmdstream.xml ( 12589 bytes, from 2014-02-17 14:57:56)
|
||||
- common.xml ( 18437 bytes, from 2015-03-25 11:27:41)
|
||||
|
||||
Copyright (C) 2014
|
||||
*/
|
||||
|
||||
|
||||
#define FE_OPCODE_LOAD_STATE 0x00000001
|
||||
#define FE_OPCODE_END 0x00000002
|
||||
#define FE_OPCODE_NOP 0x00000003
|
||||
#define FE_OPCODE_DRAW_2D 0x00000004
|
||||
#define FE_OPCODE_DRAW_PRIMITIVES 0x00000005
|
||||
#define FE_OPCODE_DRAW_INDEXED_PRIMITIVES 0x00000006
|
||||
#define FE_OPCODE_WAIT 0x00000007
|
||||
#define FE_OPCODE_LINK 0x00000008
|
||||
#define FE_OPCODE_STALL 0x00000009
|
||||
#define FE_OPCODE_CALL 0x0000000a
|
||||
#define FE_OPCODE_RETURN 0x0000000b
|
||||
#define FE_OPCODE_CHIP_SELECT 0x0000000d
|
||||
#define PRIMITIVE_TYPE_POINTS 0x00000001
|
||||
#define PRIMITIVE_TYPE_LINES 0x00000002
|
||||
#define PRIMITIVE_TYPE_LINE_STRIP 0x00000003
|
||||
#define PRIMITIVE_TYPE_TRIANGLES 0x00000004
|
||||
#define PRIMITIVE_TYPE_TRIANGLE_STRIP 0x00000005
|
||||
#define PRIMITIVE_TYPE_TRIANGLE_FAN 0x00000006
|
||||
#define PRIMITIVE_TYPE_LINE_LOOP 0x00000007
|
||||
#define PRIMITIVE_TYPE_QUADS 0x00000008
|
||||
#define VIV_FE_LOAD_STATE 0x00000000
|
||||
|
||||
#define VIV_FE_LOAD_STATE_HEADER 0x00000000
|
||||
#define VIV_FE_LOAD_STATE_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_LOAD_STATE_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE 0x08000000
|
||||
#define VIV_FE_LOAD_STATE_HEADER_FIXP 0x04000000
|
||||
#define VIV_FE_LOAD_STATE_HEADER_COUNT__MASK 0x03ff0000
|
||||
#define VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT 16
|
||||
#define VIV_FE_LOAD_STATE_HEADER_COUNT(x) (((x) << VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK)
|
||||
#define VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK 0x0000ffff
|
||||
#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT 0
|
||||
#define VIV_FE_LOAD_STATE_HEADER_OFFSET(x) (((x) << VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT) & VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK)
|
||||
#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR 2
|
||||
|
||||
#define VIV_FE_END 0x00000000
|
||||
|
||||
#define VIV_FE_END_HEADER 0x00000000
|
||||
#define VIV_FE_END_HEADER_EVENT_ID__MASK 0x0000001f
|
||||
#define VIV_FE_END_HEADER_EVENT_ID__SHIFT 0
|
||||
#define VIV_FE_END_HEADER_EVENT_ID(x) (((x) << VIV_FE_END_HEADER_EVENT_ID__SHIFT) & VIV_FE_END_HEADER_EVENT_ID__MASK)
|
||||
#define VIV_FE_END_HEADER_EVENT_ENABLE 0x00000100
|
||||
#define VIV_FE_END_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_END_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_END_HEADER_OP_END 0x10000000
|
||||
|
||||
#define VIV_FE_NOP 0x00000000
|
||||
|
||||
#define VIV_FE_NOP_HEADER 0x00000000
|
||||
#define VIV_FE_NOP_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_NOP_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_NOP_HEADER_OP_NOP 0x18000000
|
||||
|
||||
#define VIV_FE_DRAW_2D 0x00000000
|
||||
|
||||
#define VIV_FE_DRAW_2D_HEADER 0x00000000
|
||||
#define VIV_FE_DRAW_2D_HEADER_COUNT__MASK 0x0000ff00
|
||||
#define VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT 8
|
||||
#define VIV_FE_DRAW_2D_HEADER_COUNT(x) (((x) << VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_COUNT__MASK)
|
||||
#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK 0x07ff0000
|
||||
#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT 16
|
||||
#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT(x) (((x) << VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK)
|
||||
#define VIV_FE_DRAW_2D_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_DRAW_2D_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D 0x20000000
|
||||
|
||||
#define VIV_FE_DRAW_2D_TOP_LEFT 0x00000008
|
||||
#define VIV_FE_DRAW_2D_TOP_LEFT_X__MASK 0x0000ffff
|
||||
#define VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT 0
|
||||
#define VIV_FE_DRAW_2D_TOP_LEFT_X(x) (((x) << VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_X__MASK)
|
||||
#define VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK 0xffff0000
|
||||
#define VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT 16
|
||||
#define VIV_FE_DRAW_2D_TOP_LEFT_Y(x) (((x) << VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK)
|
||||
|
||||
#define VIV_FE_DRAW_2D_BOTTOM_RIGHT 0x0000000c
|
||||
#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK 0x0000ffff
|
||||
#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT 0
|
||||
#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x) (((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK)
|
||||
#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK 0xffff0000
|
||||
#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT 16
|
||||
#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(x) (((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK)
|
||||
|
||||
#define VIV_FE_DRAW_PRIMITIVES 0x00000000
|
||||
|
||||
#define VIV_FE_DRAW_PRIMITIVES_HEADER 0x00000000
|
||||
#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES 0x28000000
|
||||
|
||||
#define VIV_FE_DRAW_PRIMITIVES_COMMAND 0x00000004
|
||||
#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff
|
||||
#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT 0
|
||||
#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE(x) (((x) << VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK)
|
||||
|
||||
#define VIV_FE_DRAW_PRIMITIVES_START 0x00000008
|
||||
|
||||
#define VIV_FE_DRAW_PRIMITIVES_COUNT 0x0000000c
|
||||
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES 0x00000000
|
||||
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER 0x00000000
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES 0x30000000
|
||||
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND 0x00000004
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT 0
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE(x) (((x) << VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK)
|
||||
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_START 0x00000008
|
||||
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COUNT 0x0000000c
|
||||
|
||||
#define VIV_FE_DRAW_INDEXED_PRIMITIVES_OFFSET 0x00000010
|
||||
|
||||
#define VIV_FE_WAIT 0x00000000
|
||||
|
||||
#define VIV_FE_WAIT_HEADER 0x00000000
|
||||
#define VIV_FE_WAIT_HEADER_DELAY__MASK 0x0000ffff
|
||||
#define VIV_FE_WAIT_HEADER_DELAY__SHIFT 0
|
||||
#define VIV_FE_WAIT_HEADER_DELAY(x) (((x) << VIV_FE_WAIT_HEADER_DELAY__SHIFT) & VIV_FE_WAIT_HEADER_DELAY__MASK)
|
||||
#define VIV_FE_WAIT_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_WAIT_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_WAIT_HEADER_OP_WAIT 0x38000000
|
||||
|
||||
#define VIV_FE_LINK 0x00000000
|
||||
|
||||
#define VIV_FE_LINK_HEADER 0x00000000
|
||||
#define VIV_FE_LINK_HEADER_PREFETCH__MASK 0x0000ffff
|
||||
#define VIV_FE_LINK_HEADER_PREFETCH__SHIFT 0
|
||||
#define VIV_FE_LINK_HEADER_PREFETCH(x) (((x) << VIV_FE_LINK_HEADER_PREFETCH__SHIFT) & VIV_FE_LINK_HEADER_PREFETCH__MASK)
|
||||
#define VIV_FE_LINK_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_LINK_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_LINK_HEADER_OP_LINK 0x40000000
|
||||
|
||||
#define VIV_FE_LINK_ADDRESS 0x00000004
|
||||
|
||||
#define VIV_FE_STALL 0x00000000
|
||||
|
||||
#define VIV_FE_STALL_HEADER 0x00000000
|
||||
#define VIV_FE_STALL_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_STALL_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_STALL_HEADER_OP_STALL 0x48000000
|
||||
|
||||
#define VIV_FE_STALL_TOKEN 0x00000004
|
||||
#define VIV_FE_STALL_TOKEN_FROM__MASK 0x0000001f
|
||||
#define VIV_FE_STALL_TOKEN_FROM__SHIFT 0
|
||||
#define VIV_FE_STALL_TOKEN_FROM(x) (((x) << VIV_FE_STALL_TOKEN_FROM__SHIFT) & VIV_FE_STALL_TOKEN_FROM__MASK)
|
||||
#define VIV_FE_STALL_TOKEN_TO__MASK 0x00001f00
|
||||
#define VIV_FE_STALL_TOKEN_TO__SHIFT 8
|
||||
#define VIV_FE_STALL_TOKEN_TO(x) (((x) << VIV_FE_STALL_TOKEN_TO__SHIFT) & VIV_FE_STALL_TOKEN_TO__MASK)
|
||||
|
||||
#define VIV_FE_CALL 0x00000000
|
||||
|
||||
#define VIV_FE_CALL_HEADER 0x00000000
|
||||
#define VIV_FE_CALL_HEADER_PREFETCH__MASK 0x0000ffff
|
||||
#define VIV_FE_CALL_HEADER_PREFETCH__SHIFT 0
|
||||
#define VIV_FE_CALL_HEADER_PREFETCH(x) (((x) << VIV_FE_CALL_HEADER_PREFETCH__SHIFT) & VIV_FE_CALL_HEADER_PREFETCH__MASK)
|
||||
#define VIV_FE_CALL_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_CALL_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_CALL_HEADER_OP_CALL 0x50000000
|
||||
|
||||
#define VIV_FE_CALL_ADDRESS 0x00000004
|
||||
|
||||
#define VIV_FE_CALL_RETURN_PREFETCH 0x00000008
|
||||
|
||||
#define VIV_FE_CALL_RETURN_ADDRESS 0x0000000c
|
||||
|
||||
#define VIV_FE_RETURN 0x00000000
|
||||
|
||||
#define VIV_FE_RETURN_HEADER 0x00000000
|
||||
#define VIV_FE_RETURN_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_RETURN_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_RETURN_HEADER_OP_RETURN 0x58000000
|
||||
|
||||
#define VIV_FE_CHIP_SELECT 0x00000000
|
||||
|
||||
#define VIV_FE_CHIP_SELECT_HEADER 0x00000000
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_OP__MASK 0xf8000000
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_OP__SHIFT 27
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_OP_CHIP_SELECT 0x68000000
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP15 0x00008000
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP14 0x00004000
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP13 0x00002000
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP12 0x00001000
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP11 0x00000800
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP10 0x00000400
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP9 0x00000200
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP8 0x00000100
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP7 0x00000080
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP6 0x00000040
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP5 0x00000020
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP4 0x00000010
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP3 0x00000008
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP2 0x00000004
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP1 0x00000002
|
||||
#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP0 0x00000001
|
||||
|
||||
|
||||
#endif /* CMDSTREAM_XML */
|
||||
@@ -0,0 +1,249 @@
|
||||
#ifndef COMMON_XML
|
||||
#define COMMON_XML
|
||||
|
||||
/* Autogenerated file, DO NOT EDIT manually!
|
||||
|
||||
This file was generated by the rules-ng-ng headergen tool in this git repository:
|
||||
http://0x04.net/cgit/index.cgi/rules-ng-ng
|
||||
git clone git://0x04.net/rules-ng-ng
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- state_vg.xml ( 5973 bytes, from 2015-03-25 11:26:01)
|
||||
- common.xml ( 18437 bytes, from 2015-03-25 11:27:41)
|
||||
|
||||
Copyright (C) 2015
|
||||
*/
|
||||
|
||||
|
||||
#define PIPE_ID_PIPE_3D 0x00000000
|
||||
#define PIPE_ID_PIPE_2D 0x00000001
|
||||
#define SYNC_RECIPIENT_FE 0x00000001
|
||||
#define SYNC_RECIPIENT_RA 0x00000005
|
||||
#define SYNC_RECIPIENT_PE 0x00000007
|
||||
#define SYNC_RECIPIENT_DE 0x0000000b
|
||||
#define SYNC_RECIPIENT_VG 0x0000000f
|
||||
#define SYNC_RECIPIENT_TESSELATOR 0x00000010
|
||||
#define SYNC_RECIPIENT_VG2 0x00000011
|
||||
#define SYNC_RECIPIENT_TESSELATOR2 0x00000012
|
||||
#define SYNC_RECIPIENT_VG3 0x00000013
|
||||
#define SYNC_RECIPIENT_TESSELATOR3 0x00000014
|
||||
#define ENDIAN_MODE_NO_SWAP 0x00000000
|
||||
#define ENDIAN_MODE_SWAP_16 0x00000001
|
||||
#define ENDIAN_MODE_SWAP_32 0x00000002
|
||||
#define chipModel_GC300 0x00000300
|
||||
#define chipModel_GC320 0x00000320
|
||||
#define chipModel_GC350 0x00000350
|
||||
#define chipModel_GC355 0x00000355
|
||||
#define chipModel_GC400 0x00000400
|
||||
#define chipModel_GC410 0x00000410
|
||||
#define chipModel_GC420 0x00000420
|
||||
#define chipModel_GC450 0x00000450
|
||||
#define chipModel_GC500 0x00000500
|
||||
#define chipModel_GC530 0x00000530
|
||||
#define chipModel_GC600 0x00000600
|
||||
#define chipModel_GC700 0x00000700
|
||||
#define chipModel_GC800 0x00000800
|
||||
#define chipModel_GC860 0x00000860
|
||||
#define chipModel_GC880 0x00000880
|
||||
#define chipModel_GC1000 0x00001000
|
||||
#define chipModel_GC2000 0x00002000
|
||||
#define chipModel_GC2100 0x00002100
|
||||
#define chipModel_GC4000 0x00004000
|
||||
#define RGBA_BITS_R 0x00000001
|
||||
#define RGBA_BITS_G 0x00000002
|
||||
#define RGBA_BITS_B 0x00000004
|
||||
#define RGBA_BITS_A 0x00000008
|
||||
#define chipFeatures_FAST_CLEAR 0x00000001
|
||||
#define chipFeatures_SPECIAL_ANTI_ALIASING 0x00000002
|
||||
#define chipFeatures_PIPE_3D 0x00000004
|
||||
#define chipFeatures_DXT_TEXTURE_COMPRESSION 0x00000008
|
||||
#define chipFeatures_DEBUG_MODE 0x00000010
|
||||
#define chipFeatures_Z_COMPRESSION 0x00000020
|
||||
#define chipFeatures_YUV420_SCALER 0x00000040
|
||||
#define chipFeatures_MSAA 0x00000080
|
||||
#define chipFeatures_DC 0x00000100
|
||||
#define chipFeatures_PIPE_2D 0x00000200
|
||||
#define chipFeatures_ETC1_TEXTURE_COMPRESSION 0x00000400
|
||||
#define chipFeatures_FAST_SCALER 0x00000800
|
||||
#define chipFeatures_HIGH_DYNAMIC_RANGE 0x00001000
|
||||
#define chipFeatures_YUV420_TILER 0x00002000
|
||||
#define chipFeatures_MODULE_CG 0x00004000
|
||||
#define chipFeatures_MIN_AREA 0x00008000
|
||||
#define chipFeatures_NO_EARLY_Z 0x00010000
|
||||
#define chipFeatures_NO_422_TEXTURE 0x00020000
|
||||
#define chipFeatures_BUFFER_INTERLEAVING 0x00040000
|
||||
#define chipFeatures_BYTE_WRITE_2D 0x00080000
|
||||
#define chipFeatures_NO_SCALER 0x00100000
|
||||
#define chipFeatures_YUY2_AVERAGING 0x00200000
|
||||
#define chipFeatures_HALF_PE_CACHE 0x00400000
|
||||
#define chipFeatures_HALF_TX_CACHE 0x00800000
|
||||
#define chipFeatures_YUY2_RENDER_TARGET 0x01000000
|
||||
#define chipFeatures_MEM32 0x02000000
|
||||
#define chipFeatures_PIPE_VG 0x04000000
|
||||
#define chipFeatures_VGTS 0x08000000
|
||||
#define chipFeatures_FE20 0x10000000
|
||||
#define chipFeatures_BYTE_WRITE_3D 0x20000000
|
||||
#define chipFeatures_RS_YUV_TARGET 0x40000000
|
||||
#define chipFeatures_32_BIT_INDICES 0x80000000
|
||||
#define chipMinorFeatures0_FLIP_Y 0x00000001
|
||||
#define chipMinorFeatures0_DUAL_RETURN_BUS 0x00000002
|
||||
#define chipMinorFeatures0_ENDIANNESS_CONFIG 0x00000004
|
||||
#define chipMinorFeatures0_TEXTURE_8K 0x00000008
|
||||
#define chipMinorFeatures0_CORRECT_TEXTURE_CONVERTER 0x00000010
|
||||
#define chipMinorFeatures0_SPECIAL_MSAA_LOD 0x00000020
|
||||
#define chipMinorFeatures0_FAST_CLEAR_FLUSH 0x00000040
|
||||
#define chipMinorFeatures0_2DPE20 0x00000080
|
||||
#define chipMinorFeatures0_CORRECT_AUTO_DISABLE 0x00000100
|
||||
#define chipMinorFeatures0_RENDERTARGET_8K 0x00000200
|
||||
#define chipMinorFeatures0_2BITPERTILE 0x00000400
|
||||
#define chipMinorFeatures0_SEPARATE_TILE_STATUS_WHEN_INTERLEAVED 0x00000800
|
||||
#define chipMinorFeatures0_SUPER_TILED 0x00001000
|
||||
#define chipMinorFeatures0_VG_20 0x00002000
|
||||
#define chipMinorFeatures0_TS_EXTENDED_COMMANDS 0x00004000
|
||||
#define chipMinorFeatures0_COMPRESSION_FIFO_FIXED 0x00008000
|
||||
#define chipMinorFeatures0_HAS_SIGN_FLOOR_CEIL 0x00010000
|
||||
#define chipMinorFeatures0_VG_FILTER 0x00020000
|
||||
#define chipMinorFeatures0_VG_21 0x00040000
|
||||
#define chipMinorFeatures0_SHADER_HAS_W 0x00080000
|
||||
#define chipMinorFeatures0_HAS_SQRT_TRIG 0x00100000
|
||||
#define chipMinorFeatures0_MORE_MINOR_FEATURES 0x00200000
|
||||
#define chipMinorFeatures0_MC20 0x00400000
|
||||
#define chipMinorFeatures0_MSAA_SIDEBAND 0x00800000
|
||||
#define chipMinorFeatures0_BUG_FIXES0 0x01000000
|
||||
#define chipMinorFeatures0_VAA 0x02000000
|
||||
#define chipMinorFeatures0_BYPASS_IN_MSAA 0x04000000
|
||||
#define chipMinorFeatures0_HZ 0x08000000
|
||||
#define chipMinorFeatures0_NEW_TEXTURE 0x10000000
|
||||
#define chipMinorFeatures0_2D_A8_TARGET 0x20000000
|
||||
#define chipMinorFeatures0_CORRECT_STENCIL 0x40000000
|
||||
#define chipMinorFeatures0_ENHANCE_VR 0x80000000
|
||||
#define chipMinorFeatures1_RSUV_SWIZZLE 0x00000001
|
||||
#define chipMinorFeatures1_V2_COMPRESSION 0x00000002
|
||||
#define chipMinorFeatures1_VG_DOUBLE_BUFFER 0x00000004
|
||||
#define chipMinorFeatures1_EXTRA_EVENT_STATES 0x00000008
|
||||
#define chipMinorFeatures1_NO_STRIPING_NEEDED 0x00000010
|
||||
#define chipMinorFeatures1_TEXTURE_STRIDE 0x00000020
|
||||
#define chipMinorFeatures1_BUG_FIXES3 0x00000040
|
||||
#define chipMinorFeatures1_AUTO_DISABLE 0x00000080
|
||||
#define chipMinorFeatures1_AUTO_RESTART_TS 0x00000100
|
||||
#define chipMinorFeatures1_DISABLE_PE_GATING 0x00000200
|
||||
#define chipMinorFeatures1_L2_WINDOWING 0x00000400
|
||||
#define chipMinorFeatures1_HALF_FLOAT 0x00000800
|
||||
#define chipMinorFeatures1_PIXEL_DITHER 0x00001000
|
||||
#define chipMinorFeatures1_TWO_STENCIL_REFERENCE 0x00002000
|
||||
#define chipMinorFeatures1_EXTENDED_PIXEL_FORMAT 0x00004000
|
||||
#define chipMinorFeatures1_CORRECT_MIN_MAX_DEPTH 0x00008000
|
||||
#define chipMinorFeatures1_2D_DITHER 0x00010000
|
||||
#define chipMinorFeatures1_BUG_FIXES5 0x00020000
|
||||
#define chipMinorFeatures1_NEW_2D 0x00040000
|
||||
#define chipMinorFeatures1_NEW_FP 0x00080000
|
||||
#define chipMinorFeatures1_TEXTURE_HALIGN 0x00100000
|
||||
#define chipMinorFeatures1_NON_POWER_OF_TWO 0x00200000
|
||||
#define chipMinorFeatures1_LINEAR_TEXTURE_SUPPORT 0x00400000
|
||||
#define chipMinorFeatures1_HALTI0 0x00800000
|
||||
#define chipMinorFeatures1_CORRECT_OVERFLOW_VG 0x01000000
|
||||
#define chipMinorFeatures1_NEGATIVE_LOG_FIX 0x02000000
|
||||
#define chipMinorFeatures1_RESOLVE_OFFSET 0x04000000
|
||||
#define chipMinorFeatures1_OK_TO_GATE_AXI_CLOCK 0x08000000
|
||||
#define chipMinorFeatures1_MMU_VERSION 0x10000000
|
||||
#define chipMinorFeatures1_WIDE_LINE 0x20000000
|
||||
#define chipMinorFeatures1_BUG_FIXES6 0x40000000
|
||||
#define chipMinorFeatures1_FC_FLUSH_STALL 0x80000000
|
||||
#define chipMinorFeatures2_LINE_LOOP 0x00000001
|
||||
#define chipMinorFeatures2_LOGIC_OP 0x00000002
|
||||
#define chipMinorFeatures2_UNK2 0x00000004
|
||||
#define chipMinorFeatures2_SUPERTILED_TEXTURE 0x00000008
|
||||
#define chipMinorFeatures2_UNK4 0x00000010
|
||||
#define chipMinorFeatures2_RECT_PRIMITIVE 0x00000020
|
||||
#define chipMinorFeatures2_COMPOSITION 0x00000040
|
||||
#define chipMinorFeatures2_CORRECT_AUTO_DISABLE_COUNT 0x00000080
|
||||
#define chipMinorFeatures2_UNK8 0x00000100
|
||||
#define chipMinorFeatures2_UNK9 0x00000200
|
||||
#define chipMinorFeatures2_UNK10 0x00000400
|
||||
#define chipMinorFeatures2_SAMPLERBASE_16 0x00000800
|
||||
#define chipMinorFeatures2_UNK12 0x00001000
|
||||
#define chipMinorFeatures2_UNK13 0x00002000
|
||||
#define chipMinorFeatures2_UNK14 0x00004000
|
||||
#define chipMinorFeatures2_EXTRA_TEXTURE_STATE 0x00008000
|
||||
#define chipMinorFeatures2_FULL_DIRECTFB 0x00010000
|
||||
#define chipMinorFeatures2_2D_TILING 0x00020000
|
||||
#define chipMinorFeatures2_THREAD_WALKER_IN_PS 0x00040000
|
||||
#define chipMinorFeatures2_TILE_FILLER 0x00080000
|
||||
#define chipMinorFeatures2_UNK20 0x00100000
|
||||
#define chipMinorFeatures2_2D_MULTI_SOURCE_BLIT 0x00200000
|
||||
#define chipMinorFeatures2_UNK22 0x00400000
|
||||
#define chipMinorFeatures2_UNK23 0x00800000
|
||||
#define chipMinorFeatures2_UNK24 0x01000000
|
||||
#define chipMinorFeatures2_MIXED_STREAMS 0x02000000
|
||||
#define chipMinorFeatures2_2D_420_L2CACHE 0x04000000
|
||||
#define chipMinorFeatures2_UNK27 0x08000000
|
||||
#define chipMinorFeatures2_2D_NO_INDEX8_BRUSH 0x10000000
|
||||
#define chipMinorFeatures2_TEXTURE_TILED_READ 0x20000000
|
||||
#define chipMinorFeatures2_UNK30 0x40000000
|
||||
#define chipMinorFeatures2_UNK31 0x80000000
|
||||
#define chipMinorFeatures3_ROTATION_STALL_FIX 0x00000001
|
||||
#define chipMinorFeatures3_UNK1 0x00000002
|
||||
#define chipMinorFeatures3_2D_MULTI_SOURCE_BLT_EX 0x00000004
|
||||
#define chipMinorFeatures3_UNK3 0x00000008
|
||||
#define chipMinorFeatures3_UNK4 0x00000010
|
||||
#define chipMinorFeatures3_UNK5 0x00000020
|
||||
#define chipMinorFeatures3_UNK6 0x00000040
|
||||
#define chipMinorFeatures3_UNK7 0x00000080
|
||||
#define chipMinorFeatures3_UNK8 0x00000100
|
||||
#define chipMinorFeatures3_UNK9 0x00000200
|
||||
#define chipMinorFeatures3_BUG_FIXES10 0x00000400
|
||||
#define chipMinorFeatures3_UNK11 0x00000800
|
||||
#define chipMinorFeatures3_BUG_FIXES11 0x00001000
|
||||
#define chipMinorFeatures3_UNK13 0x00002000
|
||||
#define chipMinorFeatures3_UNK14 0x00004000
|
||||
#define chipMinorFeatures3_UNK15 0x00008000
|
||||
#define chipMinorFeatures3_UNK16 0x00010000
|
||||
#define chipMinorFeatures3_UNK17 0x00020000
|
||||
#define chipMinorFeatures3_UNK18 0x00040000
|
||||
#define chipMinorFeatures3_UNK19 0x00080000
|
||||
#define chipMinorFeatures3_UNK20 0x00100000
|
||||
#define chipMinorFeatures3_UNK21 0x00200000
|
||||
#define chipMinorFeatures3_UNK22 0x00400000
|
||||
#define chipMinorFeatures3_UNK23 0x00800000
|
||||
#define chipMinorFeatures3_UNK24 0x01000000
|
||||
#define chipMinorFeatures3_UNK25 0x02000000
|
||||
#define chipMinorFeatures3_UNK26 0x04000000
|
||||
#define chipMinorFeatures3_UNK27 0x08000000
|
||||
#define chipMinorFeatures3_UNK28 0x10000000
|
||||
#define chipMinorFeatures3_UNK29 0x20000000
|
||||
#define chipMinorFeatures3_UNK30 0x40000000
|
||||
#define chipMinorFeatures3_UNK31 0x80000000
|
||||
#define chipMinorFeatures4_UNK0 0x00000001
|
||||
#define chipMinorFeatures4_UNK1 0x00000002
|
||||
#define chipMinorFeatures4_UNK2 0x00000004
|
||||
#define chipMinorFeatures4_UNK3 0x00000008
|
||||
#define chipMinorFeatures4_UNK4 0x00000010
|
||||
#define chipMinorFeatures4_UNK5 0x00000020
|
||||
#define chipMinorFeatures4_UNK6 0x00000040
|
||||
#define chipMinorFeatures4_UNK7 0x00000080
|
||||
#define chipMinorFeatures4_UNK8 0x00000100
|
||||
#define chipMinorFeatures4_UNK9 0x00000200
|
||||
#define chipMinorFeatures4_UNK10 0x00000400
|
||||
#define chipMinorFeatures4_UNK11 0x00000800
|
||||
#define chipMinorFeatures4_UNK12 0x00001000
|
||||
#define chipMinorFeatures4_UNK13 0x00002000
|
||||
#define chipMinorFeatures4_UNK14 0x00004000
|
||||
#define chipMinorFeatures4_UNK15 0x00008000
|
||||
#define chipMinorFeatures4_UNK16 0x00010000
|
||||
#define chipMinorFeatures4_UNK17 0x00020000
|
||||
#define chipMinorFeatures4_UNK18 0x00040000
|
||||
#define chipMinorFeatures4_UNK19 0x00080000
|
||||
#define chipMinorFeatures4_UNK20 0x00100000
|
||||
#define chipMinorFeatures4_UNK21 0x00200000
|
||||
#define chipMinorFeatures4_UNK22 0x00400000
|
||||
#define chipMinorFeatures4_UNK23 0x00800000
|
||||
#define chipMinorFeatures4_UNK24 0x01000000
|
||||
#define chipMinorFeatures4_UNK25 0x02000000
|
||||
#define chipMinorFeatures4_UNK26 0x04000000
|
||||
#define chipMinorFeatures4_UNK27 0x08000000
|
||||
#define chipMinorFeatures4_UNK28 0x10000000
|
||||
#define chipMinorFeatures4_UNK29 0x20000000
|
||||
#define chipMinorFeatures4_UNK30 0x40000000
|
||||
#define chipMinorFeatures4_UNK31 0x80000000
|
||||
|
||||
#endif /* COMMON_XML */
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Etnaviv Project
|
||||
* Author: Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "etnaviv_gpu.h"
|
||||
#include "etnaviv_gem.h"
|
||||
#include "etnaviv_mmu.h"
|
||||
|
||||
#include "common.xml.h"
|
||||
#include "state.xml.h"
|
||||
#include "cmdstream.xml.h"
|
||||
|
||||
/*
|
||||
* Command Buffer helper:
|
||||
*/
|
||||
|
||||
|
||||
static inline void OUT(struct etnaviv_cmdbuf *buffer, u32 data)
|
||||
{
|
||||
u32 *vaddr = (u32 *)buffer->vaddr;
|
||||
|
||||
BUG_ON(buffer->user_size >= buffer->size);
|
||||
|
||||
vaddr[buffer->user_size / 4] = data;
|
||||
buffer->user_size += 4;
|
||||
}
|
||||
|
||||
static inline void CMD_LOAD_STATE(struct etnaviv_cmdbuf *buffer,
|
||||
u32 reg, u32 value)
|
||||
{
|
||||
u32 index = reg >> VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR;
|
||||
|
||||
buffer->user_size = ALIGN(buffer->user_size, 8);
|
||||
|
||||
/* write a register via cmd stream */
|
||||
OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE |
|
||||
VIV_FE_LOAD_STATE_HEADER_COUNT(1) |
|
||||
VIV_FE_LOAD_STATE_HEADER_OFFSET(index));
|
||||
OUT(buffer, value);
|
||||
}
|
||||
|
||||
static inline void CMD_END(struct etnaviv_cmdbuf *buffer)
|
||||
{
|
||||
buffer->user_size = ALIGN(buffer->user_size, 8);
|
||||
|
||||
OUT(buffer, VIV_FE_END_HEADER_OP_END);
|
||||
}
|
||||
|
||||
static inline void CMD_WAIT(struct etnaviv_cmdbuf *buffer)
|
||||
{
|
||||
buffer->user_size = ALIGN(buffer->user_size, 8);
|
||||
|
||||
OUT(buffer, VIV_FE_WAIT_HEADER_OP_WAIT | 200);
|
||||
}
|
||||
|
||||
static inline void CMD_LINK(struct etnaviv_cmdbuf *buffer,
|
||||
u16 prefetch, u32 address)
|
||||
{
|
||||
buffer->user_size = ALIGN(buffer->user_size, 8);
|
||||
|
||||
OUT(buffer, VIV_FE_LINK_HEADER_OP_LINK |
|
||||
VIV_FE_LINK_HEADER_PREFETCH(prefetch));
|
||||
OUT(buffer, address);
|
||||
}
|
||||
|
||||
static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer,
|
||||
u32 from, u32 to)
|
||||
{
|
||||
buffer->user_size = ALIGN(buffer->user_size, 8);
|
||||
|
||||
OUT(buffer, VIV_FE_STALL_HEADER_OP_STALL);
|
||||
OUT(buffer, VIV_FE_STALL_TOKEN_FROM(from) | VIV_FE_STALL_TOKEN_TO(to));
|
||||
}
|
||||
|
||||
static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe)
|
||||
{
|
||||
u32 flush;
|
||||
u32 stall;
|
||||
|
||||
/*
|
||||
* This assumes that if we're switching to 2D, we're switching
|
||||
* away from 3D, and vice versa. Hence, if we're switching to
|
||||
* the 2D core, we need to flush the 3D depth and color caches,
|
||||
* otherwise we need to flush the 2D pixel engine cache.
|
||||
*/
|
||||
if (pipe == ETNA_PIPE_2D)
|
||||
flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR;
|
||||
else
|
||||
flush = VIVS_GL_FLUSH_CACHE_PE2D;
|
||||
|
||||
stall = VIVS_GL_SEMAPHORE_TOKEN_FROM(SYNC_RECIPIENT_FE) |
|
||||
VIVS_GL_SEMAPHORE_TOKEN_TO(SYNC_RECIPIENT_PE);
|
||||
|
||||
CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush);
|
||||
CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, stall);
|
||||
|
||||
CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
|
||||
|
||||
CMD_LOAD_STATE(buffer, VIVS_GL_PIPE_SELECT,
|
||||
VIVS_GL_PIPE_SELECT_PIPE(pipe));
|
||||
}
|
||||
|
||||
static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_cmdbuf *buf)
|
||||
{
|
||||
return buf->paddr - gpu->memory_base;
|
||||
}
|
||||
|
||||
static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
|
||||
struct etnaviv_cmdbuf *buf, u32 off, u32 len)
|
||||
{
|
||||
u32 size = buf->size;
|
||||
u32 *ptr = buf->vaddr + off;
|
||||
|
||||
dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
|
||||
ptr, gpu_va(gpu, buf) + off, size - len * 4 - off);
|
||||
|
||||
print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
ptr, len * 4, 0);
|
||||
}
|
||||
|
||||
u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
|
||||
{
|
||||
struct etnaviv_cmdbuf *buffer = gpu->buffer;
|
||||
|
||||
/* initialize buffer */
|
||||
buffer->user_size = 0;
|
||||
|
||||
CMD_WAIT(buffer);
|
||||
CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + buffer->user_size - 4);
|
||||
|
||||
return buffer->user_size / 8;
|
||||
}
|
||||
|
||||
void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
|
||||
{
|
||||
struct etnaviv_cmdbuf *buffer = gpu->buffer;
|
||||
|
||||
/* Replace the last WAIT with an END */
|
||||
buffer->user_size -= 16;
|
||||
|
||||
CMD_END(buffer);
|
||||
mb();
|
||||
}
|
||||
|
||||
void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
|
||||
struct etnaviv_cmdbuf *cmdbuf)
|
||||
{
|
||||
struct etnaviv_cmdbuf *buffer = gpu->buffer;
|
||||
u32 *lw = buffer->vaddr + buffer->user_size - 16;
|
||||
u32 back, link_target, link_size, reserve_size, extra_size = 0;
|
||||
|
||||
if (drm_debug & DRM_UT_DRIVER)
|
||||
etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
|
||||
|
||||
/*
|
||||
* If we need to flush the MMU prior to submitting this buffer, we
|
||||
* will need to append a mmu flush load state, followed by a new
|
||||
* link to this buffer - a total of four additional words.
|
||||
*/
|
||||
if (gpu->mmu->need_flush || gpu->switch_context) {
|
||||
/* link command */
|
||||
extra_size += 2;
|
||||
/* flush command */
|
||||
if (gpu->mmu->need_flush)
|
||||
extra_size += 2;
|
||||
/* pipe switch commands */
|
||||
if (gpu->switch_context)
|
||||
extra_size += 8;
|
||||
}
|
||||
|
||||
reserve_size = (6 + extra_size) * 4;
|
||||
|
||||
/*
|
||||
* if we are going to completely overflow the buffer, we need to wrap.
|
||||
*/
|
||||
if (buffer->user_size + reserve_size > buffer->size)
|
||||
buffer->user_size = 0;
|
||||
|
||||
/* save offset back into main buffer */
|
||||
back = buffer->user_size + reserve_size - 6 * 4;
|
||||
link_target = gpu_va(gpu, buffer) + buffer->user_size;
|
||||
link_size = 6;
|
||||
|
||||
/* Skip over any extra instructions */
|
||||
link_target += extra_size * sizeof(u32);
|
||||
|
||||
if (drm_debug & DRM_UT_DRIVER)
|
||||
pr_info("stream link to 0x%08x @ 0x%08x %p\n",
|
||||
link_target, gpu_va(gpu, cmdbuf), cmdbuf->vaddr);
|
||||
|
||||
/* jump back from cmd to main buffer */
|
||||
CMD_LINK(cmdbuf, link_size, link_target);
|
||||
|
||||
link_target = gpu_va(gpu, cmdbuf);
|
||||
link_size = cmdbuf->size / 8;
|
||||
|
||||
|
||||
|
||||
if (drm_debug & DRM_UT_DRIVER) {
|
||||
print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
cmdbuf->vaddr, cmdbuf->size, 0);
|
||||
|
||||
pr_info("link op: %p\n", lw);
|
||||
pr_info("link addr: %p\n", lw + 1);
|
||||
pr_info("addr: 0x%08x\n", link_target);
|
||||
pr_info("back: 0x%08x\n", gpu_va(gpu, buffer) + back);
|
||||
pr_info("event: %d\n", event);
|
||||
}
|
||||
|
||||
if (gpu->mmu->need_flush || gpu->switch_context) {
|
||||
u32 new_target = gpu_va(gpu, buffer) + buffer->user_size;
|
||||
|
||||
if (gpu->mmu->need_flush) {
|
||||
/* Add the MMU flush */
|
||||
CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU,
|
||||
VIVS_GL_FLUSH_MMU_FLUSH_FEMMU |
|
||||
VIVS_GL_FLUSH_MMU_FLUSH_UNK1 |
|
||||
VIVS_GL_FLUSH_MMU_FLUSH_UNK2 |
|
||||
VIVS_GL_FLUSH_MMU_FLUSH_PEMMU |
|
||||
VIVS_GL_FLUSH_MMU_FLUSH_UNK4);
|
||||
|
||||
gpu->mmu->need_flush = false;
|
||||
}
|
||||
|
||||
if (gpu->switch_context) {
|
||||
etnaviv_cmd_select_pipe(buffer, cmdbuf->exec_state);
|
||||
gpu->switch_context = false;
|
||||
}
|
||||
|
||||
/* And the link to the first buffer */
|
||||
CMD_LINK(buffer, link_size, link_target);
|
||||
|
||||
/* Update the link target to point to above instructions */
|
||||
link_target = new_target;
|
||||
link_size = extra_size;
|
||||
}
|
||||
|
||||
/* trigger event */
|
||||
CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
|
||||
VIVS_GL_EVENT_FROM_PE);
|
||||
|
||||
/* append WAIT/LINK to main buffer */
|
||||
CMD_WAIT(buffer);
|
||||
CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + (buffer->user_size - 4));
|
||||
|
||||
/* Change WAIT into a LINK command; write the address first. */
|
||||
*(lw + 1) = link_target;
|
||||
mb();
|
||||
*(lw) = VIV_FE_LINK_HEADER_OP_LINK |
|
||||
VIV_FE_LINK_HEADER_PREFETCH(link_size);
|
||||
mb();
|
||||
|
||||
if (drm_debug & DRM_UT_DRIVER)
|
||||
etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Etnaviv Project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "etnaviv_gem.h"
|
||||
#include "etnaviv_gpu.h"
|
||||
|
||||
#include "cmdstream.xml.h"
|
||||
|
||||
#define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT)
|
||||
|
||||
struct etna_validation_state {
|
||||
struct etnaviv_gpu *gpu;
|
||||
const struct drm_etnaviv_gem_submit_reloc *relocs;
|
||||
unsigned int num_relocs;
|
||||
u32 *start;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
u16 offset;
|
||||
u16 size;
|
||||
} etnaviv_sensitive_states[] __initconst = {
|
||||
#define ST(start, num) { (start) >> 2, (num) }
|
||||
/* 2D */
|
||||
ST(0x1200, 1),
|
||||
ST(0x1228, 1),
|
||||
ST(0x1238, 1),
|
||||
ST(0x1284, 1),
|
||||
ST(0x128c, 1),
|
||||
ST(0x1304, 1),
|
||||
ST(0x1310, 1),
|
||||
ST(0x1318, 1),
|
||||
ST(0x12800, 4),
|
||||
ST(0x128a0, 4),
|
||||
ST(0x128c0, 4),
|
||||
ST(0x12970, 4),
|
||||
ST(0x12a00, 8),
|
||||
ST(0x12b40, 8),
|
||||
ST(0x12b80, 8),
|
||||
ST(0x12ce0, 8),
|
||||
/* 3D */
|
||||
ST(0x0644, 1),
|
||||
ST(0x064c, 1),
|
||||
ST(0x0680, 8),
|
||||
ST(0x1410, 1),
|
||||
ST(0x1430, 1),
|
||||
ST(0x1458, 1),
|
||||
ST(0x1460, 8),
|
||||
ST(0x1480, 8),
|
||||
ST(0x1500, 8),
|
||||
ST(0x1520, 8),
|
||||
ST(0x1608, 1),
|
||||
ST(0x1610, 1),
|
||||
ST(0x1658, 1),
|
||||
ST(0x165c, 1),
|
||||
ST(0x1664, 1),
|
||||
ST(0x1668, 1),
|
||||
ST(0x16a4, 1),
|
||||
ST(0x16c0, 8),
|
||||
ST(0x16e0, 8),
|
||||
ST(0x1740, 8),
|
||||
ST(0x2400, 14 * 16),
|
||||
ST(0x10800, 32 * 16),
|
||||
#undef ST
|
||||
};
|
||||
|
||||
#define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
|
||||
static DECLARE_BITMAP(etnaviv_states, ETNAVIV_STATES_SIZE);
|
||||
|
||||
void __init etnaviv_validate_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(etnaviv_sensitive_states); i++)
|
||||
bitmap_set(etnaviv_states, etnaviv_sensitive_states[i].offset,
|
||||
etnaviv_sensitive_states[i].size);
|
||||
}
|
||||
|
||||
static void etnaviv_warn_if_non_sensitive(struct etna_validation_state *state,
|
||||
unsigned int buf_offset, unsigned int state_addr)
|
||||
{
|
||||
if (state->num_relocs && state->relocs->submit_offset < buf_offset) {
|
||||
dev_warn_once(state->gpu->dev,
|
||||
"%s: relocation for non-sensitive state 0x%x at offset %u\n",
|
||||
__func__, state_addr,
|
||||
state->relocs->submit_offset);
|
||||
while (state->num_relocs &&
|
||||
state->relocs->submit_offset < buf_offset) {
|
||||
state->relocs++;
|
||||
state->num_relocs--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool etnaviv_validate_load_state(struct etna_validation_state *state,
|
||||
u32 *ptr, unsigned int state_offset, unsigned int num)
|
||||
{
|
||||
unsigned int size = min(ETNAVIV_STATES_SIZE, state_offset + num);
|
||||
unsigned int st_offset = state_offset, buf_offset;
|
||||
|
||||
for_each_set_bit_from(st_offset, etnaviv_states, size) {
|
||||
buf_offset = (ptr - state->start +
|
||||
st_offset - state_offset) * 4;
|
||||
|
||||
etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4);
|
||||
if (state->num_relocs &&
|
||||
state->relocs->submit_offset == buf_offset) {
|
||||
state->relocs++;
|
||||
state->num_relocs--;
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_warn_ratelimited(state->gpu->dev,
|
||||
"%s: load state touches restricted state 0x%x at offset %u\n",
|
||||
__func__, st_offset * 4, buf_offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state->num_relocs) {
|
||||
buf_offset = (ptr - state->start + num) * 4;
|
||||
etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4 +
|
||||
state->relocs->submit_offset -
|
||||
buf_offset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint8_t cmd_length[32] = {
|
||||
[FE_OPCODE_DRAW_PRIMITIVES] = 4,
|
||||
[FE_OPCODE_DRAW_INDEXED_PRIMITIVES] = 6,
|
||||
[FE_OPCODE_NOP] = 2,
|
||||
[FE_OPCODE_STALL] = 2,
|
||||
};
|
||||
|
||||
bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, u32 *stream,
|
||||
unsigned int size,
|
||||
struct drm_etnaviv_gem_submit_reloc *relocs,
|
||||
unsigned int reloc_size)
|
||||
{
|
||||
struct etna_validation_state state;
|
||||
u32 *buf = stream;
|
||||
u32 *end = buf + size;
|
||||
|
||||
state.gpu = gpu;
|
||||
state.relocs = relocs;
|
||||
state.num_relocs = reloc_size;
|
||||
state.start = stream;
|
||||
|
||||
while (buf < end) {
|
||||
u32 cmd = *buf;
|
||||
unsigned int len, n, off;
|
||||
unsigned int op = cmd >> 27;
|
||||
|
||||
switch (op) {
|
||||
case FE_OPCODE_LOAD_STATE:
|
||||
n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT);
|
||||
len = ALIGN(1 + n, 2);
|
||||
if (buf + len > end)
|
||||
break;
|
||||
|
||||
off = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_OFFSET);
|
||||
if (!etnaviv_validate_load_state(&state, buf + 1,
|
||||
off, n))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case FE_OPCODE_DRAW_2D:
|
||||
n = EXTRACT(cmd, VIV_FE_DRAW_2D_HEADER_COUNT);
|
||||
if (n == 0)
|
||||
n = 256;
|
||||
len = 2 + n * 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
len = cmd_length[op];
|
||||
if (len == 0) {
|
||||
dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
|
||||
__func__, op, buf - state.start);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
buf += len;
|
||||
}
|
||||
|
||||
if (buf > end) {
|
||||
dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
|
||||
__func__, buf - state.start, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Etnaviv Project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ETNAVIV_DRV_H__
|
||||
#define __ETNAVIV_DRV_H__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/etnaviv_drm.h>
|
||||
|
||||
struct etnaviv_cmdbuf;
|
||||
struct etnaviv_gpu;
|
||||
struct etnaviv_mmu;
|
||||
struct etnaviv_gem_object;
|
||||
struct etnaviv_gem_submit;
|
||||
|
||||
struct etnaviv_file_private {
|
||||
/* currently we don't do anything useful with this.. but when
|
||||
* per-context address spaces are supported we'd keep track of
|
||||
* the context's page-tables here.
|
||||
*/
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct etnaviv_drm_private {
|
||||
int num_gpus;
|
||||
struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
|
||||
|
||||
/* list of GEM objects: */
|
||||
struct mutex gem_lock;
|
||||
struct list_head gem_list;
|
||||
|
||||
struct workqueue_struct *wq;
|
||||
};
|
||||
|
||||
static inline void etnaviv_queue_work(struct drm_device *dev,
|
||||
struct work_struct *w)
|
||||
{
|
||||
struct etnaviv_drm_private *priv = dev->dev_private;
|
||||
|
||||
queue_work(priv->wq, w);
|
||||
}
|
||||
|
||||
int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
struct drm_file *file);
|
||||
|
||||
int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma);
|
||||
int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset);
|
||||
int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu,
|
||||
struct drm_gem_object *obj, u32 *iova);
|
||||
void etnaviv_gem_put_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj);
|
||||
struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj);
|
||||
void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj);
|
||||
void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach, struct sg_table *sg);
|
||||
int etnaviv_gem_prime_pin(struct drm_gem_object *obj);
|
||||
void etnaviv_gem_prime_unpin(struct drm_gem_object *obj);
|
||||
void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
|
||||
int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
|
||||
struct timespec *timeout);
|
||||
int etnaviv_gem_cpu_fini(struct drm_gem_object *obj);
|
||||
void etnaviv_gem_free_object(struct drm_gem_object *obj);
|
||||
int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
|
||||
u32 size, u32 flags, u32 *handle);
|
||||
struct drm_gem_object *etnaviv_gem_new_locked(struct drm_device *dev,
|
||||
u32 size, u32 flags);
|
||||
struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
|
||||
u32 size, u32 flags);
|
||||
int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
|
||||
uintptr_t ptr, u32 size, u32 flags, u32 *handle);
|
||||
u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
|
||||
void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
|
||||
void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
|
||||
struct etnaviv_cmdbuf *cmdbuf);
|
||||
void etnaviv_validate_init(void);
|
||||
bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
|
||||
u32 *stream, unsigned int size,
|
||||
struct drm_etnaviv_gem_submit_reloc *relocs, unsigned int reloc_size);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
|
||||
struct seq_file *m);
|
||||
#endif
|
||||
|
||||
void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name,
|
||||
const char *dbgname);
|
||||
void etnaviv_writel(u32 data, void __iomem *addr);
|
||||
u32 etnaviv_readl(const void __iomem *addr);
|
||||
|
||||
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Return the storage size of a structure with a variable length array.
|
||||
* The array is nelem elements of elem_size, where the base structure
|
||||
* is defined by base. If the size overflows size_t, return zero.
|
||||
*/
|
||||
static inline size_t size_vstruct(size_t nelem, size_t elem_size, size_t base)
|
||||
{
|
||||
if (elem_size && nelem > (SIZE_MAX - base) / elem_size)
|
||||
return 0;
|
||||
return base + nelem * elem_size;
|
||||
}
|
||||
|
||||
/* returns true if fence a comes after fence b */
|
||||
static inline bool fence_after(u32 a, u32 b)
|
||||
{
|
||||
return (s32)(a - b) > 0;
|
||||
}
|
||||
|
||||
static inline bool fence_after_eq(u32 a, u32 b)
|
||||
{
|
||||
return (s32)(a - b) >= 0;
|
||||
}
|
||||
|
||||
static inline unsigned long etnaviv_timeout_to_jiffies(
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
|
||||
unsigned long start_jiffies = jiffies;
|
||||
unsigned long remaining_jiffies;
|
||||
|
||||
if (time_after(start_jiffies, timeout_jiffies))
|
||||
remaining_jiffies = 0;
|
||||
else
|
||||
remaining_jiffies = timeout_jiffies - start_jiffies;
|
||||
|
||||
return remaining_jiffies;
|
||||
}
|
||||
|
||||
#endif /* __ETNAVIV_DRV_H__ */
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Etnaviv Project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/devcoredump.h>
|
||||
#include "etnaviv_dump.h"
|
||||
#include "etnaviv_gem.h"
|
||||
#include "etnaviv_gpu.h"
|
||||
#include "etnaviv_mmu.h"
|
||||
#include "state.xml.h"
|
||||
#include "state_hi.xml.h"
|
||||
|
||||
struct core_dump_iterator {
|
||||
void *start;
|
||||
struct etnaviv_dump_object_header *hdr;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static const unsigned short etnaviv_dump_registers[] = {
|
||||
VIVS_HI_AXI_STATUS,
|
||||
VIVS_HI_CLOCK_CONTROL,
|
||||
VIVS_HI_IDLE_STATE,
|
||||
VIVS_HI_AXI_CONFIG,
|
||||
VIVS_HI_INTR_ENBL,
|
||||
VIVS_HI_CHIP_IDENTITY,
|
||||
VIVS_HI_CHIP_FEATURE,
|
||||
VIVS_HI_CHIP_MODEL,
|
||||
VIVS_HI_CHIP_REV,
|
||||
VIVS_HI_CHIP_DATE,
|
||||
VIVS_HI_CHIP_TIME,
|
||||
VIVS_HI_CHIP_MINOR_FEATURE_0,
|
||||
VIVS_HI_CACHE_CONTROL,
|
||||
VIVS_HI_AXI_CONTROL,
|
||||
VIVS_PM_POWER_CONTROLS,
|
||||
VIVS_PM_MODULE_CONTROLS,
|
||||
VIVS_PM_MODULE_STATUS,
|
||||
VIVS_PM_PULSE_EATER,
|
||||
VIVS_MC_MMU_FE_PAGE_TABLE,
|
||||
VIVS_MC_MMU_TX_PAGE_TABLE,
|
||||
VIVS_MC_MMU_PE_PAGE_TABLE,
|
||||
VIVS_MC_MMU_PEZ_PAGE_TABLE,
|
||||
VIVS_MC_MMU_RA_PAGE_TABLE,
|
||||
VIVS_MC_DEBUG_MEMORY,
|
||||
VIVS_MC_MEMORY_BASE_ADDR_RA,
|
||||
VIVS_MC_MEMORY_BASE_ADDR_FE,
|
||||
VIVS_MC_MEMORY_BASE_ADDR_TX,
|
||||
VIVS_MC_MEMORY_BASE_ADDR_PEZ,
|
||||
VIVS_MC_MEMORY_BASE_ADDR_PE,
|
||||
VIVS_MC_MEMORY_TIMING_CONTROL,
|
||||
VIVS_MC_BUS_CONFIG,
|
||||
VIVS_FE_DMA_STATUS,
|
||||
VIVS_FE_DMA_DEBUG_STATE,
|
||||
VIVS_FE_DMA_ADDRESS,
|
||||
VIVS_FE_DMA_LOW,
|
||||
VIVS_FE_DMA_HIGH,
|
||||
VIVS_FE_AUTO_FLUSH,
|
||||
};
|
||||
|
||||
static void etnaviv_core_dump_header(struct core_dump_iterator *iter,
|
||||
u32 type, void *data_end)
|
||||
{
|
||||
struct etnaviv_dump_object_header *hdr = iter->hdr;
|
||||
|
||||
hdr->magic = cpu_to_le32(ETDUMP_MAGIC);
|
||||
hdr->type = cpu_to_le32(type);
|
||||
hdr->file_offset = cpu_to_le32(iter->data - iter->start);
|
||||
hdr->file_size = cpu_to_le32(data_end - iter->data);
|
||||
|
||||
iter->hdr++;
|
||||
iter->data += hdr->file_size;
|
||||
}
|
||||
|
||||
static void etnaviv_core_dump_registers(struct core_dump_iterator *iter,
|
||||
struct etnaviv_gpu *gpu)
|
||||
{
|
||||
struct etnaviv_dump_registers *reg = iter->data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) {
|
||||
reg->reg = etnaviv_dump_registers[i];
|
||||
reg->value = gpu_read(gpu, etnaviv_dump_registers[i]);
|
||||
}
|
||||
|
||||
etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg);
|
||||
}
|
||||
|
||||
static void etnaviv_core_dump_mmu(struct core_dump_iterator *iter,
|
||||
struct etnaviv_gpu *gpu, size_t mmu_size)
|
||||
{
|
||||
etnaviv_iommu_dump(gpu->mmu, iter->data);
|
||||
|
||||
etnaviv_core_dump_header(iter, ETDUMP_BUF_MMU, iter->data + mmu_size);
|
||||
}
|
||||
|
||||
static void etnaviv_core_dump_mem(struct core_dump_iterator *iter, u32 type,
|
||||
void *ptr, size_t size, u64 iova)
|
||||
{
|
||||
memcpy(iter->data, ptr, size);
|
||||
|
||||
iter->hdr->iova = cpu_to_le64(iova);
|
||||
|
||||
etnaviv_core_dump_header(iter, type, iter->data + size);
|
||||
}
|
||||
|
||||
void etnaviv_core_dump(struct etnaviv_gpu *gpu)
|
||||
{
|
||||
struct core_dump_iterator iter;
|
||||
struct etnaviv_vram_mapping *vram;
|
||||
struct etnaviv_gem_object *obj;
|
||||
struct etnaviv_cmdbuf *cmd;
|
||||
unsigned int n_obj, n_bomap_pages;
|
||||
size_t file_size, mmu_size;
|
||||
__le64 *bomap, *bomap_start;
|
||||
|
||||
mmu_size = etnaviv_iommu_dump_size(gpu->mmu);
|
||||
|
||||
/* We always dump registers, mmu, ring and end marker */
|
||||
n_obj = 4;
|
||||
n_bomap_pages = 0;
|
||||
file_size = ARRAY_SIZE(etnaviv_dump_registers) *
|
||||
sizeof(struct etnaviv_dump_registers) +
|
||||
mmu_size + gpu->buffer->size;
|
||||
|
||||
/* Add in the active command buffers */
|
||||
list_for_each_entry(cmd, &gpu->active_cmd_list, node) {
|
||||
file_size += cmd->size;
|
||||
n_obj++;
|
||||
}
|
||||
|
||||
/* Add in the active buffer objects */
|
||||
list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
|
||||
if (!vram->use)
|
||||
continue;
|
||||
|
||||
obj = vram->object;
|
||||
file_size += obj->base.size;
|
||||
n_bomap_pages += obj->base.size >> PAGE_SHIFT;
|
||||
n_obj++;
|
||||
}
|
||||
|
||||
/* If we have any buffer objects, add a bomap object */
|
||||
if (n_bomap_pages) {
|
||||
file_size += n_bomap_pages * sizeof(__le64);
|
||||
n_obj++;
|
||||
}
|
||||
|
||||
/* Add the size of the headers */
|
||||
file_size += sizeof(*iter.hdr) * n_obj;
|
||||
|
||||
/* Allocate the file in vmalloc memory, it's likely to be big */
|
||||
iter.start = vmalloc(file_size);
|
||||
if (!iter.start) {
|
||||
dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Point the data member after the headers */
|
||||
iter.hdr = iter.start;
|
||||
iter.data = &iter.hdr[n_obj];
|
||||
|
||||
memset(iter.hdr, 0, iter.data - iter.start);
|
||||
|
||||
etnaviv_core_dump_registers(&iter, gpu);
|
||||
etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
|
||||
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
|
||||
gpu->buffer->size, gpu->buffer->paddr);
|
||||
|
||||
list_for_each_entry(cmd, &gpu->active_cmd_list, node)
|
||||
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
|
||||
cmd->size, cmd->paddr);
|
||||
|
||||
/* Reserve space for the bomap */
|
||||
if (n_bomap_pages) {
|
||||
bomap_start = bomap = iter.data;
|
||||
memset(bomap, 0, sizeof(*bomap) * n_bomap_pages);
|
||||
etnaviv_core_dump_header(&iter, ETDUMP_BUF_BOMAP,
|
||||
bomap + n_bomap_pages);
|
||||
} else {
|
||||
/* Silence warning */
|
||||
bomap_start = bomap = NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
|
||||
struct page **pages;
|
||||
void *vaddr;
|
||||
|
||||
if (vram->use == 0)
|
||||
continue;
|
||||
|
||||
obj = vram->object;
|
||||
|
||||
pages = etnaviv_gem_get_pages(obj);
|
||||
if (pages) {
|
||||
int j;
|
||||
|
||||
iter.hdr->data[0] = bomap - bomap_start;
|
||||
|
||||
for (j = 0; j < obj->base.size >> PAGE_SHIFT; j++)
|
||||
*bomap++ = cpu_to_le64(page_to_phys(*pages++));
|
||||
}
|
||||
|
||||
iter.hdr->iova = cpu_to_le64(vram->iova);
|
||||
|
||||
vaddr = etnaviv_gem_vaddr(&obj->base);
|
||||
if (vaddr && !IS_ERR(vaddr))
|
||||
memcpy(iter.data, vaddr, obj->base.size);
|
||||
|
||||
etnaviv_core_dump_header(&iter, ETDUMP_BUF_BO, iter.data +
|
||||
obj->base.size);
|
||||
}
|
||||
|
||||
etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data);
|
||||
|
||||
dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Etnaviv Project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Etnaviv devcoredump file definitions
|
||||
*/
|
||||
#ifndef ETNAVIV_DUMP_H
|
||||
#define ETNAVIV_DUMP_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
ETDUMP_MAGIC = 0x414e5445,
|
||||
ETDUMP_BUF_REG = 0,
|
||||
ETDUMP_BUF_MMU,
|
||||
ETDUMP_BUF_RING,
|
||||
ETDUMP_BUF_CMD,
|
||||
ETDUMP_BUF_BOMAP,
|
||||
ETDUMP_BUF_BO,
|
||||
ETDUMP_BUF_END,
|
||||
};
|
||||
|
||||
struct etnaviv_dump_object_header {
|
||||
__le32 magic;
|
||||
__le32 type;
|
||||
__le32 file_offset;
|
||||
__le32 file_size;
|
||||
__le64 iova;
|
||||
__le32 data[2];
|
||||
};
|
||||
|
||||
/* Registers object, an array of these */
|
||||
struct etnaviv_dump_registers {
|
||||
__le32 reg;
|
||||
__le32 value;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
struct etnaviv_gpu;
|
||||
void etnaviv_core_dump(struct etnaviv_gpu *gpu);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Etnaviv Project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ETNAVIV_GEM_H__
|
||||
#define __ETNAVIV_GEM_H__
|
||||
|
||||
#include <linux/reservation.h>
|
||||
#include "etnaviv_drv.h"
|
||||
|
||||
struct etnaviv_gem_ops;
|
||||
struct etnaviv_gem_object;
|
||||
|
||||
struct etnaviv_gem_userptr {
|
||||
uintptr_t ptr;
|
||||
struct task_struct *task;
|
||||
struct work_struct *work;
|
||||
bool ro;
|
||||
};
|
||||
|
||||
struct etnaviv_vram_mapping {
|
||||
struct list_head obj_node;
|
||||
struct list_head scan_node;
|
||||
struct list_head mmu_node;
|
||||
struct etnaviv_gem_object *object;
|
||||
struct etnaviv_iommu *mmu;
|
||||
struct drm_mm_node vram_node;
|
||||
unsigned int use;
|
||||
u32 iova;
|
||||
};
|
||||
|
||||
struct etnaviv_gem_object {
|
||||
struct drm_gem_object base;
|
||||
const struct etnaviv_gem_ops *ops;
|
||||
struct mutex lock;
|
||||
|
||||
u32 flags;
|
||||
|
||||
struct list_head gem_node;
|
||||
struct etnaviv_gpu *gpu; /* non-null if active */
|
||||
atomic_t gpu_active;
|
||||
u32 access;
|
||||
|
||||
struct page **pages;
|
||||
struct sg_table *sgt;
|
||||
void *vaddr;
|
||||
|
||||
/* normally (resv == &_resv) except for imported bo's */
|
||||
struct reservation_object *resv;
|
||||
struct reservation_object _resv;
|
||||
|
||||
struct list_head vram_list;
|
||||
|
||||
/* cache maintenance */
|
||||
u32 last_cpu_prep_op;
|
||||
|
||||
struct etnaviv_gem_userptr userptr;
|
||||
};
|
||||
|
||||
static inline
|
||||
struct etnaviv_gem_object *to_etnaviv_bo(struct drm_gem_object *obj)
|
||||
{
|
||||
return container_of(obj, struct etnaviv_gem_object, base);
|
||||
}
|
||||
|
||||
struct etnaviv_gem_ops {
|
||||
int (*get_pages)(struct etnaviv_gem_object *);
|
||||
void (*release)(struct etnaviv_gem_object *);
|
||||
};
|
||||
|
||||
static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj)
|
||||
{
|
||||
return atomic_read(&etnaviv_obj->gpu_active) != 0;
|
||||
}
|
||||
|
||||
#define MAX_CMDS 4
|
||||
|
||||
/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
|
||||
* associated with the cmdstream submission for synchronization (and
|
||||
* make it easier to unwind when things go wrong, etc). This only
|
||||
* lasts for the duration of the submit-ioctl.
|
||||
*/
|
||||
struct etnaviv_gem_submit {
|
||||
struct drm_device *dev;
|
||||
struct etnaviv_gpu *gpu;
|
||||
struct ww_acquire_ctx ticket;
|
||||
u32 fence;
|
||||
unsigned int nr_bos;
|
||||
struct {
|
||||
u32 flags;
|
||||
struct etnaviv_gem_object *obj;
|
||||
u32 iova;
|
||||
} bos[0];
|
||||
};
|
||||
|
||||
int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
|
||||
struct timespec *timeout);
|
||||
int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
|
||||
struct reservation_object *robj, const struct etnaviv_gem_ops *ops,
|
||||
struct etnaviv_gem_object **res);
|
||||
int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj);
|
||||
struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj);
|
||||
void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj);
|
||||
|
||||
#endif /* __ETNAVIV_GEM_H__ */
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
#include "etnaviv_drv.h"
|
||||
#include "etnaviv_gem.h"
|
||||
|
||||
|
||||
struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
||||
{
|
||||
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
|
||||
|
||||
BUG_ON(!etnaviv_obj->sgt); /* should have already pinned! */
|
||||
|
||||
return etnaviv_obj->sgt;
|
||||
}
|
||||
|
||||
void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj)
|
||||
{
|
||||
return etnaviv_gem_vaddr(obj);
|
||||
}
|
||||
|
||||
void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
|
||||
{
|
||||
/* TODO msm_gem_vunmap() */
|
||||
}
|
||||
|
||||
int etnaviv_gem_prime_pin(struct drm_gem_object *obj)
|
||||
{
|
||||
if (!obj->import_attach) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
|
||||
|
||||
mutex_lock(&etnaviv_obj->lock);
|
||||
etnaviv_gem_get_pages(etnaviv_obj);
|
||||
mutex_unlock(&etnaviv_obj->lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void etnaviv_gem_prime_unpin(struct drm_gem_object *obj)
|
||||
{
|
||||
if (!obj->import_attach) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
|
||||
|
||||
mutex_lock(&etnaviv_obj->lock);
|
||||
etnaviv_gem_put_pages(to_etnaviv_bo(obj));
|
||||
mutex_unlock(&etnaviv_obj->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj)
|
||||
{
|
||||
if (etnaviv_obj->vaddr)
|
||||
dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf,
|
||||
etnaviv_obj->vaddr);
|
||||
|
||||
/* Don't drop the pages for imported dmabuf, as they are not
|
||||
* ours, just free the array we allocated:
|
||||
*/
|
||||
if (etnaviv_obj->pages)
|
||||
drm_free_large(etnaviv_obj->pages);
|
||||
|
||||
drm_prime_gem_destroy(&etnaviv_obj->base, etnaviv_obj->sgt);
|
||||
}
|
||||
|
||||
static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = {
|
||||
/* .get_pages should never be called */
|
||||
.release = etnaviv_gem_prime_release,
|
||||
};
|
||||
|
||||
struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach, struct sg_table *sgt)
|
||||
{
|
||||
struct etnaviv_gem_object *etnaviv_obj;
|
||||
size_t size = PAGE_ALIGN(attach->dmabuf->size);
|
||||
int ret, npages;
|
||||
|
||||
ret = etnaviv_gem_new_private(dev, size, ETNA_BO_WC,
|
||||
attach->dmabuf->resv,
|
||||
&etnaviv_gem_prime_ops, &etnaviv_obj);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
npages = size / PAGE_SIZE;
|
||||
|
||||
etnaviv_obj->sgt = sgt;
|
||||
etnaviv_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
|
||||
if (!etnaviv_obj->pages) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = drm_prime_sg_to_page_addr_arrays(sgt, etnaviv_obj->pages,
|
||||
NULL, npages);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return &etnaviv_obj->base;
|
||||
|
||||
fail:
|
||||
drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Etnaviv Project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/reservation.h>
|
||||
#include "etnaviv_drv.h"
|
||||
#include "etnaviv_gpu.h"
|
||||
#include "etnaviv_gem.h"
|
||||
|
||||
/*
|
||||
* Cmdstream submission:
|
||||
*/
|
||||
|
||||
#define BO_INVALID_FLAGS ~(ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE)
|
||||
/* make sure these don't conflict w/ ETNAVIV_SUBMIT_BO_x */
|
||||
#define BO_LOCKED 0x4000
|
||||
#define BO_PINNED 0x2000
|
||||
|
||||
static inline void __user *to_user_ptr(u64 address)
|
||||
{
|
||||
return (void __user *)(uintptr_t)address;
|
||||
}
|
||||
|
||||
static struct etnaviv_gem_submit *submit_create(struct drm_device *dev,
|
||||
struct etnaviv_gpu *gpu, size_t nr)
|
||||
{
|
||||
struct etnaviv_gem_submit *submit;
|
||||
size_t sz = size_vstruct(nr, sizeof(submit->bos[0]), sizeof(*submit));
|
||||
|
||||
submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
|
||||
if (submit) {
|
||||
submit->dev = dev;
|
||||
submit->gpu = gpu;
|
||||
|
||||
/* initially, until copy_from_user() and bo lookup succeeds: */
|
||||
submit->nr_bos = 0;
|
||||
|
||||
ww_acquire_init(&submit->ticket, &reservation_ww_class);
|
||||
}
|
||||
|
||||
return submit;
|
||||
}
|
||||
|
||||
static int submit_lookup_objects(struct etnaviv_gem_submit *submit,
|
||||
struct drm_file *file, struct drm_etnaviv_gem_submit_bo *submit_bos,
|
||||
unsigned nr_bos)
|
||||
{
|
||||
struct drm_etnaviv_gem_submit_bo *bo;
|
||||
unsigned i;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&file->table_lock);
|
||||
|
||||
for (i = 0, bo = submit_bos; i < nr_bos; i++, bo++) {
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
if (bo->flags & BO_INVALID_FLAGS) {
|
||||
DRM_ERROR("invalid flags: %x\n", bo->flags);
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
submit->bos[i].flags = bo->flags;
|
||||
|
||||
/* normally use drm_gem_object_lookup(), but for bulk lookup
|
||||
* all under single table_lock just hit object_idr directly:
|
||||
*/
|
||||
obj = idr_find(&file->object_idr, bo->handle);
|
||||
if (!obj) {
|
||||
DRM_ERROR("invalid handle %u at index %u\n",
|
||||
bo->handle, i);
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a refcount on the object. The file table lock
|
||||
* prevents the object_idr's refcount on this being dropped.
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
|
||||
submit->bos[i].obj = to_etnaviv_bo(obj);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
submit->nr_bos = i;
|
||||
spin_unlock(&file->table_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i)
|
||||
{
|
||||
if (submit->bos[i].flags & BO_LOCKED) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
|
||||
|
||||
ww_mutex_unlock(&etnaviv_obj->resv->lock);
|
||||
submit->bos[i].flags &= ~BO_LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
static int submit_lock_objects(struct etnaviv_gem_submit *submit)
|
||||
{
|
||||
int contended, slow_locked = -1, i, ret = 0;
|
||||
|
||||
retry:
|
||||
for (i = 0; i < submit->nr_bos; i++) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
|
||||
|
||||
if (slow_locked == i)
|
||||
slow_locked = -1;
|
||||
|
||||
contended = i;
|
||||
|
||||
if (!(submit->bos[i].flags & BO_LOCKED)) {
|
||||
ret = ww_mutex_lock_interruptible(&etnaviv_obj->resv->lock,
|
||||
&submit->ticket);
|
||||
if (ret == -EALREADY)
|
||||
DRM_ERROR("BO at index %u already on submit list\n",
|
||||
i);
|
||||
if (ret)
|
||||
goto fail;
|
||||
submit->bos[i].flags |= BO_LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
ww_acquire_done(&submit->ticket);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (; i >= 0; i--)
|
||||
submit_unlock_object(submit, i);
|
||||
|
||||
if (slow_locked > 0)
|
||||
submit_unlock_object(submit, slow_locked);
|
||||
|
||||
if (ret == -EDEADLK) {
|
||||
struct etnaviv_gem_object *etnaviv_obj;
|
||||
|
||||
etnaviv_obj = submit->bos[contended].obj;
|
||||
|
||||
/* we lost out in a seqno race, lock and retry.. */
|
||||
ret = ww_mutex_lock_slow_interruptible(&etnaviv_obj->resv->lock,
|
||||
&submit->ticket);
|
||||
if (!ret) {
|
||||
submit->bos[contended].flags |= BO_LOCKED;
|
||||
slow_locked = contended;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int submit_fence_sync(const struct etnaviv_gem_submit *submit)
|
||||
{
|
||||
unsigned int context = submit->gpu->fence_context;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < submit->nr_bos; i++) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
|
||||
bool write = submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE;
|
||||
|
||||
ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void submit_unpin_objects(struct etnaviv_gem_submit *submit)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < submit->nr_bos; i++) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
|
||||
|
||||
if (submit->bos[i].flags & BO_PINNED)
|
||||
etnaviv_gem_put_iova(submit->gpu, &etnaviv_obj->base);
|
||||
|
||||
submit->bos[i].iova = 0;
|
||||
submit->bos[i].flags &= ~BO_PINNED;
|
||||
}
|
||||
}
|
||||
|
||||
static int submit_pin_objects(struct etnaviv_gem_submit *submit)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < submit->nr_bos; i++) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
|
||||
u32 iova;
|
||||
|
||||
ret = etnaviv_gem_get_iova(submit->gpu, &etnaviv_obj->base,
|
||||
&iova);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
submit->bos[i].flags |= BO_PINNED;
|
||||
submit->bos[i].iova = iova;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int submit_bo(struct etnaviv_gem_submit *submit, u32 idx,
|
||||
struct etnaviv_gem_object **obj, u32 *iova)
|
||||
{
|
||||
if (idx >= submit->nr_bos) {
|
||||
DRM_ERROR("invalid buffer index: %u (out of %u)\n",
|
||||
idx, submit->nr_bos);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj)
|
||||
*obj = submit->bos[idx].obj;
|
||||
if (iova)
|
||||
*iova = submit->bos[idx].iova;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* process the reloc's and patch up the cmdstream as needed: */
|
||||
static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream,
|
||||
u32 size, const struct drm_etnaviv_gem_submit_reloc *relocs,
|
||||
u32 nr_relocs)
|
||||
{
|
||||
u32 i, last_offset = 0;
|
||||
u32 *ptr = stream;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < nr_relocs; i++) {
|
||||
const struct drm_etnaviv_gem_submit_reloc *r = relocs + i;
|
||||
struct etnaviv_gem_object *bobj;
|
||||
u32 iova, off;
|
||||
|
||||
if (unlikely(r->flags)) {
|
||||
DRM_ERROR("invalid reloc flags\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (r->submit_offset % 4) {
|
||||
DRM_ERROR("non-aligned reloc offset: %u\n",
|
||||
r->submit_offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* offset in dwords: */
|
||||
off = r->submit_offset / 4;
|
||||
|
||||
if ((off >= size ) ||
|
||||
(off < last_offset)) {
|
||||
DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = submit_bo(submit, r->reloc_idx, &bobj, &iova);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (r->reloc_offset >=
|
||||
bobj->base.size - sizeof(*ptr)) {
|
||||
DRM_ERROR("relocation %u outside object", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ptr[off] = iova + r->reloc_offset;
|
||||
|
||||
last_offset = off;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void submit_cleanup(struct etnaviv_gem_submit *submit)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < submit->nr_bos; i++) {
|
||||
struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
|
||||
|
||||
submit_unlock_object(submit, i);
|
||||
drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
|
||||
}
|
||||
|
||||
ww_acquire_fini(&submit->ticket);
|
||||
kfree(submit);
|
||||
}
|
||||
|
||||
int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct etnaviv_drm_private *priv = dev->dev_private;
|
||||
struct drm_etnaviv_gem_submit *args = data;
|
||||
struct drm_etnaviv_gem_submit_reloc *relocs;
|
||||
struct drm_etnaviv_gem_submit_bo *bos;
|
||||
struct etnaviv_gem_submit *submit;
|
||||
struct etnaviv_cmdbuf *cmdbuf;
|
||||
struct etnaviv_gpu *gpu;
|
||||
void *stream;
|
||||
int ret;
|
||||
|
||||
if (args->pipe >= ETNA_MAX_PIPES)
|
||||
return -EINVAL;
|
||||
|
||||
gpu = priv->gpu[args->pipe];
|
||||
if (!gpu)
|
||||
return -ENXIO;
|
||||
|
||||
if (args->stream_size % 4) {
|
||||
DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
|
||||
args->stream_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (args->exec_state != ETNA_PIPE_3D &&
|
||||
args->exec_state != ETNA_PIPE_2D &&
|
||||
args->exec_state != ETNA_PIPE_VG) {
|
||||
DRM_ERROR("invalid exec_state: 0x%x\n", args->exec_state);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the command submission and bo array to kernel space in
|
||||
* one go, and do this outside of any locks.
|
||||
*/
|
||||
bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
|
||||
relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs));
|
||||
stream = drm_malloc_ab(1, args->stream_size);
|
||||
cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8,
|
||||
args->nr_bos);
|
||||
if (!bos || !relocs || !stream || !cmdbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_submit_cmds;
|
||||
}
|
||||
|
||||
cmdbuf->exec_state = args->exec_state;
|
||||
cmdbuf->ctx = file->driver_priv;
|
||||
|
||||
ret = copy_from_user(bos, to_user_ptr(args->bos),
|
||||
args->nr_bos * sizeof(*bos));
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
goto err_submit_cmds;
|
||||
}
|
||||
|
||||
ret = copy_from_user(relocs, to_user_ptr(args->relocs),
|
||||
args->nr_relocs * sizeof(*relocs));
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
goto err_submit_cmds;
|
||||
}
|
||||
|
||||
ret = copy_from_user(stream, to_user_ptr(args->stream),
|
||||
args->stream_size);
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
goto err_submit_cmds;
|
||||
}
|
||||
|
||||
submit = submit_create(dev, gpu, args->nr_bos);
|
||||
if (!submit) {
|
||||
ret = -ENOMEM;
|
||||
goto err_submit_cmds;
|
||||
}
|
||||
|
||||
ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
|
||||
if (ret)
|
||||
goto err_submit_objects;
|
||||
|
||||
ret = submit_lock_objects(submit);
|
||||
if (ret)
|
||||
goto err_submit_objects;
|
||||
|
||||
if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4,
|
||||
relocs, args->nr_relocs)) {
|
||||
ret = -EINVAL;
|
||||
goto err_submit_objects;
|
||||
}
|
||||
|
||||
ret = submit_fence_sync(submit);
|
||||
if (ret)
|
||||
goto err_submit_objects;
|
||||
|
||||
ret = submit_pin_objects(submit);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = submit_reloc(submit, stream, args->stream_size / 4,
|
||||
relocs, args->nr_relocs);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
memcpy(cmdbuf->vaddr, stream, args->stream_size);
|
||||
cmdbuf->user_size = ALIGN(args->stream_size, 8);
|
||||
|
||||
ret = etnaviv_gpu_submit(gpu, submit, cmdbuf);
|
||||
if (ret == 0)
|
||||
cmdbuf = NULL;
|
||||
|
||||
args->fence = submit->fence;
|
||||
|
||||
out:
|
||||
submit_unpin_objects(submit);
|
||||
|
||||
/*
|
||||
* If we're returning -EAGAIN, it may be due to the userptr code
|
||||
* wanting to run its workqueue outside of any locks. Flush our
|
||||
* workqueue to ensure that it is run in a timely manner.
|
||||
*/
|
||||
if (ret == -EAGAIN)
|
||||
flush_workqueue(priv->wq);
|
||||
|
||||
err_submit_objects:
|
||||
submit_cleanup(submit);
|
||||
|
||||
err_submit_cmds:
|
||||
/* if we still own the cmdbuf */
|
||||
if (cmdbuf)
|
||||
etnaviv_gpu_cmdbuf_free(cmdbuf);
|
||||
if (stream)
|
||||
drm_free_large(stream);
|
||||
if (bos)
|
||||
drm_free_large(bos);
|
||||
if (relocs)
|
||||
drm_free_large(relocs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Etnaviv Project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ETNAVIV_GPU_H__
|
||||
#define __ETNAVIV_GPU_H__
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "etnaviv_drv.h"
|
||||
|
||||
struct etnaviv_gem_submit;
|
||||
|
||||
struct etnaviv_chip_identity {
|
||||
/* Chip model. */
|
||||
u32 model;
|
||||
|
||||
/* Revision value.*/
|
||||
u32 revision;
|
||||
|
||||
/* Supported feature fields. */
|
||||
u32 features;
|
||||
|
||||
/* Supported minor feature fields. */
|
||||
u32 minor_features0;
|
||||
|
||||
/* Supported minor feature 1 fields. */
|
||||
u32 minor_features1;
|
||||
|
||||
/* Supported minor feature 2 fields. */
|
||||
u32 minor_features2;
|
||||
|
||||
/* Supported minor feature 3 fields. */
|
||||
u32 minor_features3;
|
||||
|
||||
/* Number of streams supported. */
|
||||
u32 stream_count;
|
||||
|
||||
/* Total number of temporary registers per thread. */
|
||||
u32 register_max;
|
||||
|
||||
/* Maximum number of threads. */
|
||||
u32 thread_count;
|
||||
|
||||
/* Number of shader cores. */
|
||||
u32 shader_core_count;
|
||||
|
||||
/* Size of the vertex cache. */
|
||||
u32 vertex_cache_size;
|
||||
|
||||
/* Number of entries in the vertex output buffer. */
|
||||
u32 vertex_output_buffer_size;
|
||||
|
||||
/* Number of pixel pipes. */
|
||||
u32 pixel_pipes;
|
||||
|
||||
/* Number of instructions. */
|
||||
u32 instruction_count;
|
||||
|
||||
/* Number of constants. */
|
||||
u32 num_constants;
|
||||
|
||||
/* Buffer size */
|
||||
u32 buffer_size;
|
||||
};
|
||||
|
||||
struct etnaviv_event {
|
||||
bool used;
|
||||
struct fence *fence;
|
||||
};
|
||||
|
||||
struct etnaviv_cmdbuf;
|
||||
|
||||
struct etnaviv_gpu {
|
||||
struct drm_device *drm;
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
struct etnaviv_chip_identity identity;
|
||||
struct etnaviv_file_private *lastctx;
|
||||
bool switch_context;
|
||||
|
||||
/* 'ring'-buffer: */
|
||||
struct etnaviv_cmdbuf *buffer;
|
||||
|
||||
/* bus base address of memory */
|
||||
u32 memory_base;
|
||||
|
||||
/* event management: */
|
||||
struct etnaviv_event event[30];
|
||||
struct completion event_free;
|
||||
spinlock_t event_spinlock;
|
||||
|
||||
/* list of currently in-flight command buffers */
|
||||
struct list_head active_cmd_list;
|
||||
|
||||
u32 idle_mask;
|
||||
|
||||
/* Fencing support */
|
||||
u32 next_fence;
|
||||
u32 active_fence;
|
||||
u32 completed_fence;
|
||||
u32 retired_fence;
|
||||
wait_queue_head_t fence_event;
|
||||
unsigned int fence_context;
|
||||
spinlock_t fence_spinlock;
|
||||
|
||||
/* worker for handling active-list retiring: */
|
||||
struct work_struct retire_work;
|
||||
|
||||
void __iomem *mmio;
|
||||
int irq;
|
||||
|
||||
struct etnaviv_iommu *mmu;
|
||||
|
||||
/* Power Control: */
|
||||
struct clk *clk_bus;
|
||||
struct clk *clk_core;
|
||||
struct clk *clk_shader;
|
||||
|
||||
/* Hang Detction: */
|
||||
#define DRM_ETNAVIV_HANGCHECK_PERIOD 500 /* in ms */
|
||||
#define DRM_ETNAVIV_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_ETNAVIV_HANGCHECK_PERIOD)
|
||||
struct timer_list hangcheck_timer;
|
||||
u32 hangcheck_fence;
|
||||
u32 hangcheck_dma_addr;
|
||||
struct work_struct recover_work;
|
||||
};
|
||||
|
||||
struct etnaviv_cmdbuf {
|
||||
/* device this cmdbuf is allocated for */
|
||||
struct etnaviv_gpu *gpu;
|
||||
/* user context key, must be unique between all active users */
|
||||
struct etnaviv_file_private *ctx;
|
||||
/* cmdbuf properties */
|
||||
void *vaddr;
|
||||
dma_addr_t paddr;
|
||||
u32 size;
|
||||
u32 user_size;
|
||||
/* fence after which this buffer is to be disposed */
|
||||
struct fence *fence;
|
||||
/* target exec state */
|
||||
u32 exec_state;
|
||||
/* per GPU in-flight list */
|
||||
struct list_head node;
|
||||
/* BOs attached to this command buffer */
|
||||
unsigned int nr_bos;
|
||||
struct etnaviv_gem_object *bo[0];
|
||||
};
|
||||
|
||||
static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)
|
||||
{
|
||||
etnaviv_writel(data, gpu->mmio + reg);
|
||||
}
|
||||
|
||||
static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg)
|
||||
{
|
||||
return etnaviv_readl(gpu->mmio + reg);
|
||||
}
|
||||
|
||||
static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence)
|
||||
{
|
||||
return fence_after_eq(gpu->completed_fence, fence);
|
||||
}
|
||||
|
||||
static inline bool fence_retired(struct etnaviv_gpu *gpu, u32 fence)
|
||||
{
|
||||
return fence_after_eq(gpu->retired_fence, fence);
|
||||
}
|
||||
|
||||
int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value);
|
||||
|
||||
int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
|
||||
#endif
|
||||
|
||||
int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
|
||||
unsigned int context, bool exclusive);
|
||||
|
||||
void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
|
||||
int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
|
||||
u32 fence, struct timespec *timeout);
|
||||
int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
|
||||
struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
|
||||
int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
|
||||
struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf);
|
||||
struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
|
||||
u32 size, size_t nr_bos);
|
||||
void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
|
||||
int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
|
||||
void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
|
||||
|
||||
extern struct platform_driver etnaviv_gpu_driver;
|
||||
|
||||
#endif /* __ETNAVIV_GPU_H__ */
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include "etnaviv_gpu.h"
|
||||
#include "etnaviv_mmu.h"
|
||||
#include "etnaviv_iommu.h"
|
||||
#include "state_hi.xml.h"
|
||||
|
||||
#define PT_SIZE SZ_2M
|
||||
#define PT_ENTRIES (PT_SIZE / sizeof(u32))
|
||||
|
||||
#define GPU_MEM_START 0x80000000
|
||||
|
||||
struct etnaviv_iommu_domain_pgtable {
|
||||
u32 *pgtable;
|
||||
dma_addr_t paddr;
|
||||
};
|
||||
|
||||
struct etnaviv_iommu_domain {
|
||||
struct iommu_domain domain;
|
||||
struct device *dev;
|
||||
void *bad_page_cpu;
|
||||
dma_addr_t bad_page_dma;
|
||||
struct etnaviv_iommu_domain_pgtable pgtable;
|
||||
spinlock_t map_lock;
|
||||
};
|
||||
|
||||
static struct etnaviv_iommu_domain *to_etnaviv_domain(struct iommu_domain *domain)
|
||||
{
|
||||
return container_of(domain, struct etnaviv_iommu_domain, domain);
|
||||
}
|
||||
|
||||
static int pgtable_alloc(struct etnaviv_iommu_domain_pgtable *pgtable,
|
||||
size_t size)
|
||||
{
|
||||
pgtable->pgtable = dma_alloc_coherent(NULL, size, &pgtable->paddr, GFP_KERNEL);
|
||||
if (!pgtable->pgtable)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pgtable_free(struct etnaviv_iommu_domain_pgtable *pgtable,
|
||||
size_t size)
|
||||
{
|
||||
dma_free_coherent(NULL, size, pgtable->pgtable, pgtable->paddr);
|
||||
}
|
||||
|
||||
static u32 pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable,
|
||||
unsigned long iova)
|
||||
{
|
||||
/* calcuate index into page table */
|
||||
unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
|
||||
phys_addr_t paddr;
|
||||
|
||||
paddr = pgtable->pgtable[index];
|
||||
|
||||
return paddr;
|
||||
}
|
||||
|
||||
static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
|
||||
unsigned long iova, phys_addr_t paddr)
|
||||
{
|
||||
/* calcuate index into page table */
|
||||
unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
|
||||
|
||||
pgtable->pgtable[index] = paddr;
|
||||
}
|
||||
|
||||
static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
|
||||
{
|
||||
u32 *p;
|
||||
int ret, i;
|
||||
|
||||
etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
|
||||
SZ_4K,
|
||||
&etnaviv_domain->bad_page_dma,
|
||||
GFP_KERNEL);
|
||||
if (!etnaviv_domain->bad_page_cpu)
|
||||
return -ENOMEM;
|
||||
|
||||
p = etnaviv_domain->bad_page_cpu;
|
||||
for (i = 0; i < SZ_4K / 4; i++)
|
||||
*p++ = 0xdead55aa;
|
||||
|
||||
ret = pgtable_alloc(&etnaviv_domain->pgtable, PT_SIZE);
|
||||
if (ret < 0) {
|
||||
dma_free_coherent(etnaviv_domain->dev, SZ_4K,
|
||||
etnaviv_domain->bad_page_cpu,
|
||||
etnaviv_domain->bad_page_dma);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < PT_ENTRIES; i++)
|
||||
etnaviv_domain->pgtable.pgtable[i] =
|
||||
etnaviv_domain->bad_page_dma;
|
||||
|
||||
spin_lock_init(&etnaviv_domain->map_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void etnaviv_domain_free(struct iommu_domain *domain)
|
||||
{
|
||||
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
|
||||
|
||||
pgtable_free(&etnaviv_domain->pgtable, PT_SIZE);
|
||||
|
||||
dma_free_coherent(etnaviv_domain->dev, SZ_4K,
|
||||
etnaviv_domain->bad_page_cpu,
|
||||
etnaviv_domain->bad_page_dma);
|
||||
|
||||
kfree(etnaviv_domain);
|
||||
}
|
||||
|
||||
static int etnaviv_iommuv1_map(struct iommu_domain *domain, unsigned long iova,
|
||||
phys_addr_t paddr, size_t size, int prot)
|
||||
{
|
||||
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
|
||||
|
||||
if (size != SZ_4K)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&etnaviv_domain->map_lock);
|
||||
pgtable_write(&etnaviv_domain->pgtable, iova, paddr);
|
||||
spin_unlock(&etnaviv_domain->map_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t etnaviv_iommuv1_unmap(struct iommu_domain *domain,
|
||||
unsigned long iova, size_t size)
|
||||
{
|
||||
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
|
||||
|
||||
if (size != SZ_4K)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&etnaviv_domain->map_lock);
|
||||
pgtable_write(&etnaviv_domain->pgtable, iova,
|
||||
etnaviv_domain->bad_page_dma);
|
||||
spin_unlock(&etnaviv_domain->map_lock);
|
||||
|
||||
return SZ_4K;
|
||||
}
|
||||
|
||||
static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain,
|
||||
dma_addr_t iova)
|
||||
{
|
||||
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
|
||||
|
||||
return pgtable_read(&etnaviv_domain->pgtable, iova);
|
||||
}
|
||||
|
||||
static size_t etnaviv_iommuv1_dump_size(struct iommu_domain *domain)
|
||||
{
|
||||
return PT_SIZE;
|
||||
}
|
||||
|
||||
static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf)
|
||||
{
|
||||
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
|
||||
|
||||
memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE);
|
||||
}
|
||||
|
||||
static struct etnaviv_iommu_ops etnaviv_iommu_ops = {
|
||||
.ops = {
|
||||
.domain_free = etnaviv_domain_free,
|
||||
.map = etnaviv_iommuv1_map,
|
||||
.unmap = etnaviv_iommuv1_unmap,
|
||||
.iova_to_phys = etnaviv_iommu_iova_to_phys,
|
||||
.pgsize_bitmap = SZ_4K,
|
||||
},
|
||||
.dump_size = etnaviv_iommuv1_dump_size,
|
||||
.dump = etnaviv_iommuv1_dump,
|
||||
};
|
||||
|
||||
void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
|
||||
struct iommu_domain *domain)
|
||||
{
|
||||
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
|
||||
u32 pgtable;
|
||||
|
||||
/* set page table address in MC */
|
||||
pgtable = (u32)etnaviv_domain->pgtable.paddr;
|
||||
|
||||
gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable);
|
||||
gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable);
|
||||
gpu_write(gpu, VIVS_MC_MMU_PE_PAGE_TABLE, pgtable);
|
||||
gpu_write(gpu, VIVS_MC_MMU_PEZ_PAGE_TABLE, pgtable);
|
||||
gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);
|
||||
}
|
||||
|
||||
struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu)
|
||||
{
|
||||
struct etnaviv_iommu_domain *etnaviv_domain;
|
||||
int ret;
|
||||
|
||||
etnaviv_domain = kzalloc(sizeof(*etnaviv_domain), GFP_KERNEL);
|
||||
if (!etnaviv_domain)
|
||||
return NULL;
|
||||
|
||||
etnaviv_domain->dev = gpu->dev;
|
||||
|
||||
etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
|
||||
etnaviv_domain->domain.ops = &etnaviv_iommu_ops.ops;
|
||||
etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START;
|
||||
etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K - 1;
|
||||
|
||||
ret = __etnaviv_iommu_init(etnaviv_domain);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
return &etnaviv_domain->domain;
|
||||
|
||||
out_free:
|
||||
kfree(etnaviv_domain);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ETNAVIV_IOMMU_H__
|
||||
#define __ETNAVIV_IOMMU_H__
|
||||
|
||||
#include <linux/iommu.h>
|
||||
struct etnaviv_gpu;
|
||||
|
||||
struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu);
|
||||
void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
|
||||
struct iommu_domain *domain);
|
||||
struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
|
||||
|
||||
#endif /* __ETNAVIV_IOMMU_H__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user