All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFCv2 0/4] Etnaviv DRM driver again
@ 2015-09-11 14:10 Lucas Stach
  2015-09-11 14:10 ` [PATCH RFCv2 1/4] of: Add vendor prefix for Vivante Corporation Lucas Stach
                   ` (5 more replies)
  0 siblings, 6 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-11 14:10 UTC (permalink / raw)
  To: dri-devel; +Cc: Russell King, kernel

Hey all,

this is a new posting of the Etnaviv DRM driver for Vivante embedded GPUs.
This time I've squashed all patches to the DRM driver itself into a single commit
to make it easier for people to look at and review this stuff.

Aside from squashing of some of the trivial bugfixes I intend to keep all the
individual commits around to retain the authorship of people working on this
driver. If you want to look at the stream of commits please fetch

git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream

I've kept things in staging for now, as that's the place where Christian started
this driver, but would really like to move it to DRM proper _before_ merging. So
please review stuff with that in mind.

Since the last posting a lot of cleanups and bugfixes have landed, but also a major
rewrite of the userspace interface. The UAPI is now considerably simpler as a lot
of things that turned out to be not useful have been cut out. Also a pretty big
security issue has been fixed where the userspace could abuse the still mapped
command buffer to change the command stream after the kernel validated and patched
it up, but before actual GPU execution.

Thanks to Russell King GPU power management with proper state reinitialization is
now in place, which allows the GPU to be completely power gated when not in use,
but is also the foundation for GPU recovery after a hanging submit.

A modified version of Russell Kings xf86-video-armada driver driver that works on
top of the new UAPI is available at

git://git.pengutronix.de/git/lst/xf86-video-armada.git for-rmk

Regards,
Lucas

Christian Gmeiner (1):
  staging: etnaviv: add drm driver

Lucas Stach (2):
  staging: etnaviv: add devicetree bindings
  ARM: imx6: add Vivante GPU nodes

Philipp Zabel (1):
  of: Add vendor prefix for Vivante Corporation

 .../bindings/drm/etnaviv/etnaviv-drm.txt           |   44 +
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 arch/arm/boot/dts/imx6dl.dtsi                      |    5 +
 arch/arm/boot/dts/imx6q.dtsi                       |   15 +
 arch/arm/boot/dts/imx6qdl.dtsi                     |   21 +
 drivers/staging/Kconfig                            |    2 +
 drivers/staging/Makefile                           |    1 +
 drivers/staging/etnaviv/Kconfig                    |   20 +
 drivers/staging/etnaviv/Makefile                   |   18 +
 drivers/staging/etnaviv/cmdstream.xml.h            |  218 +++
 drivers/staging/etnaviv/common.xml.h               |  249 ++++
 drivers/staging/etnaviv/etnaviv_buffer.c           |  271 ++++
 drivers/staging/etnaviv/etnaviv_cmd_parser.c       |  119 ++
 drivers/staging/etnaviv/etnaviv_drv.c              |  705 ++++++++++
 drivers/staging/etnaviv/etnaviv_drv.h              |  138 ++
 drivers/staging/etnaviv/etnaviv_gem.c              |  887 ++++++++++++
 drivers/staging/etnaviv/etnaviv_gem.h              |  141 ++
 drivers/staging/etnaviv/etnaviv_gem_prime.c        |  121 ++
 drivers/staging/etnaviv/etnaviv_gem_submit.c       |  421 ++++++
 drivers/staging/etnaviv/etnaviv_gpu.c              | 1468 ++++++++++++++++++++
 drivers/staging/etnaviv/etnaviv_gpu.h              |  198 +++
 drivers/staging/etnaviv/etnaviv_iommu.c            |  221 +++
 drivers/staging/etnaviv/etnaviv_iommu.h            |   28 +
 drivers/staging/etnaviv/etnaviv_iommu_v2.c         |   33 +
 drivers/staging/etnaviv/etnaviv_iommu_v2.h         |   25 +
 drivers/staging/etnaviv/etnaviv_mmu.c              |  282 ++++
 drivers/staging/etnaviv/etnaviv_mmu.h              |   58 +
 drivers/staging/etnaviv/state.xml.h                |  351 +++++
 drivers/staging/etnaviv/state_hi.xml.h             |  407 ++++++
 include/uapi/drm/etnaviv_drm.h                     |  215 +++
 30 files changed, 6683 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/etnaviv/etnaviv-drm.txt
 create mode 100644 drivers/staging/etnaviv/Kconfig
 create mode 100644 drivers/staging/etnaviv/Makefile
 create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h
 create mode 100644 drivers/staging/etnaviv/common.xml.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h
 create mode 100644 drivers/staging/etnaviv/state.xml.h
 create mode 100644 drivers/staging/etnaviv/state_hi.xml.h
 create mode 100644 include/uapi/drm/etnaviv_drm.h

-- 
2.5.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* [PATCH RFCv2 1/4] of: Add vendor prefix for Vivante Corporation
  2015-09-11 14:10 [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
@ 2015-09-11 14:10 ` Lucas Stach
  2015-09-11 14:10 ` [PATCH RFCv2 2/4] staging: etnaviv: add devicetree bindings Lucas Stach
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-11 14:10 UTC (permalink / raw)
  To: dri-devel; +Cc: Russell King, kernel

From: Philipp Zabel <philipp.zabel@gmail.com>

Trivial patch to add Vivante Corporation to the list of
devicetree vendor prefixes.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index d444757c4d9e..688c7d190bfc 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -216,6 +216,7 @@ v3	V3 Semiconductor
 variscite	Variscite Ltd.
 via	VIA Technologies, Inc.
 virtio	Virtual I/O Device Specification, developed by the OASIS consortium
+vivante	Vivante Corporation
 voipac	Voipac Technologies s.r.o.
 wexler	Wexler
 winbond Winbond Electronics corp.
-- 
2.5.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH RFCv2 2/4] staging: etnaviv: add devicetree bindings
  2015-09-11 14:10 [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
  2015-09-11 14:10 ` [PATCH RFCv2 1/4] of: Add vendor prefix for Vivante Corporation Lucas Stach
@ 2015-09-11 14:10 ` Lucas Stach
  2015-09-11 14:10 ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Lucas Stach
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-11 14:10 UTC (permalink / raw)
  To: dri-devel; +Cc: Russell King, kernel

Etnaviv follows the same priciple as imx-drm to have a virtual
master device node to bind all the individual GPU cores together
into one DRM device.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 .../bindings/drm/etnaviv/etnaviv-drm.txt           | 44 ++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/etnaviv/etnaviv-drm.txt

diff --git a/Documentation/devicetree/bindings/drm/etnaviv/etnaviv-drm.txt b/Documentation/devicetree/bindings/drm/etnaviv/etnaviv-drm.txt
new file mode 100644
index 000000000000..e27082bdba0d
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/etnaviv/etnaviv-drm.txt
@@ -0,0 +1,44 @@
+Etnaviv DRM master device
+================================
+
+The Etnaviv DRM master device is a virtual device needed to list all
+Vivante GPU cores that comprise the GPU subsystem.
+
+Required properties:
+- compatible: Should be "fsl,imx-gpu-subsystem"
+- cores: Should contain a list of phandles pointing to Vivante GPU devices
+
+example:
+
+gpu-subsystem {
+	compatible = "fsl,imx-gpu-subsystem";
+	cores = <&gpu_2d>, <&gpu_3d>;
+};
+
+
+Vivante GPU core devices
+====================
+
+Required properties:
+- compatible: Should be "vivante,gc"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain the cores interrupt line
+- clocks: should contain one clock for entry in clock-names
+  see Documentation/devicetree/bindings/clock/clock-bindings.txt
+- clock-names:
+   - "bus":    AXI/register clock
+   - "core":   GPU core clock
+   - "shader": Shader clock (only required if GPU has feature PIPE_3D)
+
+example:
+
+gpu_3d: gpu@00130000 {
+	compatible = "vivante,gc";
+	reg = <0x00130000 0x4000>;
+	interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&clks IMX6QDL_CLK_GPU3D_AXI>,
+	         <&clks IMX6QDL_CLK_GPU3D_CORE>,
+	         <&clks IMX6QDL_CLK_GPU3D_SHADER>;
+	clock-names = "bus", "core", "shader";
+};
-- 
2.5.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-11 14:10 [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
  2015-09-11 14:10 ` [PATCH RFCv2 1/4] of: Add vendor prefix for Vivante Corporation Lucas Stach
  2015-09-11 14:10 ` [PATCH RFCv2 2/4] staging: etnaviv: add devicetree bindings Lucas Stach
@ 2015-09-11 14:10 ` Lucas Stach
  2015-09-14 13:16   ` Rob Clark
                     ` (3 more replies)
  2015-09-11 14:10 ` [PATCH RFCv2 4/4] ARM: imx6: add Vivante GPU nodes Lucas Stach
                   ` (2 subsequent siblings)
  5 siblings, 4 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-11 14:10 UTC (permalink / raw)
  To: dri-devel; +Cc: Russell King, kernel

From: Christian Gmeiner <christian.gmeiner@gmail.com>

This is a squashed commit of the complete etnaviv DRM driver in order
to make it easy for people to review the code by seeing the driver as a
whole and is not intended for merging in this form.

If you are interested in the history of individual commits:
git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream

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>
---
 drivers/staging/Kconfig                      |    2 +
 drivers/staging/Makefile                     |    1 +
 drivers/staging/etnaviv/Kconfig              |   20 +
 drivers/staging/etnaviv/Makefile             |   18 +
 drivers/staging/etnaviv/cmdstream.xml.h      |  218 ++++
 drivers/staging/etnaviv/common.xml.h         |  249 +++++
 drivers/staging/etnaviv/etnaviv_buffer.c     |  271 +++++
 drivers/staging/etnaviv/etnaviv_cmd_parser.c |  119 +++
 drivers/staging/etnaviv/etnaviv_drv.c        |  705 +++++++++++++
 drivers/staging/etnaviv/etnaviv_drv.h        |  138 +++
 drivers/staging/etnaviv/etnaviv_gem.c        |  887 ++++++++++++++++
 drivers/staging/etnaviv/etnaviv_gem.h        |  141 +++
 drivers/staging/etnaviv/etnaviv_gem_prime.c  |  121 +++
 drivers/staging/etnaviv/etnaviv_gem_submit.c |  421 ++++++++
 drivers/staging/etnaviv/etnaviv_gpu.c        | 1468 ++++++++++++++++++++++++++
 drivers/staging/etnaviv/etnaviv_gpu.h        |  198 ++++
 drivers/staging/etnaviv/etnaviv_iommu.c      |  221 ++++
 drivers/staging/etnaviv/etnaviv_iommu.h      |   28 +
 drivers/staging/etnaviv/etnaviv_iommu_v2.c   |   33 +
 drivers/staging/etnaviv/etnaviv_iommu_v2.h   |   25 +
 drivers/staging/etnaviv/etnaviv_mmu.c        |  282 +++++
 drivers/staging/etnaviv/etnaviv_mmu.h        |   58 +
 drivers/staging/etnaviv/state.xml.h          |  351 ++++++
 drivers/staging/etnaviv/state_hi.xml.h       |  407 +++++++
 include/uapi/drm/etnaviv_drm.h               |  215 ++++
 25 files changed, 6597 insertions(+)
 create mode 100644 drivers/staging/etnaviv/Kconfig
 create mode 100644 drivers/staging/etnaviv/Makefile
 create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h
 create mode 100644 drivers/staging/etnaviv/common.xml.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h
 create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c
 create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h
 create mode 100644 drivers/staging/etnaviv/state.xml.h
 create mode 100644 drivers/staging/etnaviv/state_hi.xml.h
 create mode 100644 include/uapi/drm/etnaviv_drm.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 7f6cae5beb90..5446fe4859ce 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -112,4 +112,6 @@ source "drivers/staging/fsl-mc/Kconfig"
 
 source "drivers/staging/wilc1000/Kconfig"
 
+source "drivers/staging/etnaviv/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 347f6477aa3e..9fd3c06b6bfd 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD)	+= clocking-wizard/
 obj-$(CONFIG_FB_TFT)		+= fbtft/
 obj-$(CONFIG_FSL_MC_BUS)	+= fsl-mc/
 obj-$(CONFIG_WILC1000)		+= wilc1000/
+obj-$(CONFIG_DRM_ETNAVIV)	+= etnaviv/
diff --git a/drivers/staging/etnaviv/Kconfig b/drivers/staging/etnaviv/Kconfig
new file mode 100644
index 000000000000..6f034eda914c
--- /dev/null
+++ b/drivers/staging/etnaviv/Kconfig
@@ -0,0 +1,20 @@
+
+config DRM_ETNAVIV
+	tristate "etnaviv DRM"
+	depends on DRM
+	select SHMEM
+	select TMPFS
+	select IOMMU_API
+	select IOMMU_SUPPORT
+	default y
+	help
+	  DRM driver for Vivante GPUs.
+
+config DRM_ETNAVIV_REGISTER_LOGGING
+	bool "etnaviv DRM register logging"
+	depends on DRM_ETNAVIV
+	default n
+	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.
diff --git a/drivers/staging/etnaviv/Makefile b/drivers/staging/etnaviv/Makefile
new file mode 100644
index 000000000000..2b71c31b6501
--- /dev/null
+++ b/drivers/staging/etnaviv/Makefile
@@ -0,0 +1,18 @@
+ccflags-y := -Iinclude/drm -Idrivers/staging/vivante
+ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
+	ccflags-y += -Werror
+endif
+
+etnaviv-y := \
+	etnaviv_cmd_parser.o \
+	etnaviv_drv.o \
+	etnaviv_gem.o \
+	etnaviv_gem_prime.o \
+	etnaviv_gem_submit.o \
+	etnaviv_gpu.o \
+	etnaviv_iommu.o \
+	etnaviv_iommu_v2.o \
+	etnaviv_mmu.o \
+	etnaviv_buffer.o
+
+obj-$(CONFIG_DRM_ETNAVIV)	+= etnaviv.o
diff --git a/drivers/staging/etnaviv/cmdstream.xml.h b/drivers/staging/etnaviv/cmdstream.xml.h
new file mode 100644
index 000000000000..8c44ba9a694e
--- /dev/null
+++ b/drivers/staging/etnaviv/cmdstream.xml.h
@@ -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 */
diff --git a/drivers/staging/etnaviv/common.xml.h b/drivers/staging/etnaviv/common.xml.h
new file mode 100644
index 000000000000..9e585d51fb78
--- /dev/null
+++ b/drivers/staging/etnaviv/common.xml.h
@@ -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 */
diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
new file mode 100644
index 000000000000..586f84316f1a
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -0,0 +1,271 @@
+/*
+ * 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;
+
+	if (pipe == ETNA_PIPE_2D)
+		flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR;
+	else
+		flush = VIVS_GL_FLUSH_CACHE_TEXTURE;
+
+	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_gem_submit *submit)
+{
+	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, submit->cmdbuf),
+			submit->cmdbuf->vaddr);
+
+	/* jump back from cmd to main buffer */
+	CMD_LINK(submit->cmdbuf, link_size, link_target);
+
+	link_target = gpu_va(gpu, submit->cmdbuf);
+	link_size = submit->cmdbuf->size / 8;
+
+
+
+	if (drm_debug & DRM_UT_DRIVER) {
+		print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
+			       submit->cmdbuf->vaddr, submit->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, submit->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;
+	}
+
+	/* Save the event and buffer position of the new event trigger */
+	gpu->event[event].fence = submit->fence;
+
+	/* take ownership of cmdbuffer*/
+	submit->cmdbuf->fence = submit->fence;
+	list_add_tail(&submit->cmdbuf->gpu_active_list, &gpu->active_cmd_list);
+	submit->cmdbuf = NULL;
+
+	/* 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);
+}
diff --git a/drivers/staging/etnaviv/etnaviv_cmd_parser.c b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
new file mode 100644
index 000000000000..5175d6eb3bdc
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
@@ -0,0 +1,119 @@
+/*
+ * 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)
+
+static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf,
+	unsigned int state, unsigned int num)
+{
+	return true;
+	if (0x1200 - state < num * 4)
+		return false;
+	if (0x1228 - state < num * 4)
+		return false;
+	if (0x1238 - state < num * 4)
+		return false;
+	if (0x1284 - state < num * 4)
+		return false;
+	if (0x128c - state < num * 4)
+		return false;
+	if (0x1304 - state < num * 4)
+		return false;
+	if (0x1310 - state < num * 4)
+		return false;
+	if (0x1318 - state < num * 4)
+		return false;
+	if (0x1280c - state < num * 4 + 0x0c)
+		return false;
+	if (0x128ac - state < num * 4 + 0x0c)
+		return false;
+	if (0x128cc - state < num * 4 + 0x0c)
+		return false;
+	if (0x1297c - state < num * 4 + 0x0c)
+		return false;
+	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, void *stream,
+			      unsigned int size)
+{
+	u32 *start = stream;
+	u32 *buf = start;
+	u32 *end = buf + size;
+
+	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(gpu, buf + 1,
+							 off * 4, n)) {
+				dev_warn(gpu->dev, "%s: load state covers restricted state (0x%x-0x%x) at offset %tu\n",
+					 __func__, off * 4, (off + n) * 4, buf - start);
+				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 - start);
+				return false;
+			}
+			break;
+		}
+
+		buf += len;
+	}
+
+	if (buf > end) {
+		dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
+			__func__, buf - start, size);
+		return false;
+	}
+
+	return true;
+}
diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
new file mode 100644
index 000000000000..30f6e5d0c91d
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -0,0 +1,705 @@
+/*
+ * 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/component.h>
+#include <linux/of_platform.h>
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_mmu.h"
+#include "etnaviv_gem.h"
+
+#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
+static bool reglog;
+MODULE_PARM_DESC(reglog, "Enable register read/write logging");
+module_param(reglog, bool, 0600);
+#else
+#define reglog 0
+#endif
+
+void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name,
+		const char *dbgname)
+{
+	struct resource *res;
+	void __iomem *ptr;
+
+	if (name)
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+	else
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	ptr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ptr)) {
+		dev_err(&pdev->dev, "failed to ioremap %s: %ld\n", name,
+			PTR_ERR(ptr));
+		return ptr;
+	}
+
+	if (reglog)
+		dev_printk(KERN_DEBUG, &pdev->dev, "IO:region %s 0x%p %08zx\n",
+			   dbgname, ptr, (size_t)resource_size(res));
+
+	return ptr;
+}
+
+void etnaviv_writel(u32 data, void __iomem *addr)
+{
+	if (reglog)
+		printk(KERN_DEBUG "IO:W %p %08x\n", addr, data);
+
+	writel(data, addr);
+}
+
+u32 etnaviv_readl(const void __iomem *addr)
+{
+	u32 val = readl(addr);
+
+	if (reglog)
+		printk(KERN_DEBUG "IO:R %p %08x\n", addr, val);
+
+	return val;
+}
+
+/*
+ * DRM operations:
+ */
+
+static int etnaviv_unload(struct drm_device *dev)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+
+	flush_workqueue(priv->wq);
+	destroy_workqueue(priv->wq);
+
+	component_unbind_all(dev->dev, dev);
+
+	dev->dev_private = NULL;
+
+	kfree(priv);
+
+	return 0;
+}
+
+
+static void load_gpu(struct drm_device *dev)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	unsigned int i;
+
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		struct etnaviv_gpu *g = priv->gpu[i];
+
+		if (g) {
+			int ret;
+
+			ret = etnaviv_gpu_init(g);
+			if (ret) {
+				dev_err(g->dev, "hw init failed: %d\n", ret);
+				priv->gpu[i] = NULL;
+			}
+		}
+	}
+}
+
+static int etnaviv_load(struct drm_device *dev, unsigned long flags)
+{
+	struct platform_device *pdev = dev->platformdev;
+	struct etnaviv_drm_private *priv;
+	int err;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(dev->dev, "failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	dev->dev_private = priv;
+
+	priv->wq = alloc_ordered_workqueue("etnaviv", 0);
+	if (!priv->wq) {
+		err = -ENOMEM;
+		goto err_wq;
+	}
+
+	INIT_LIST_HEAD(&priv->inactive_list);
+	priv->num_gpus = 0;
+
+	platform_set_drvdata(pdev, dev);
+
+	err = component_bind_all(dev->dev, dev);
+	if (err < 0)
+		goto err_bind;
+
+	load_gpu(dev);
+
+	return 0;
+
+err_bind:
+	flush_workqueue(priv->wq);
+	destroy_workqueue(priv->wq);
+err_wq:
+	kfree(priv);
+	return err;
+}
+
+static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
+{
+	struct etnaviv_file_private *ctx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	file->driver_priv = ctx;
+
+	return 0;
+}
+
+static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_file_private *ctx = file->driver_priv;
+	unsigned int i;
+
+	mutex_lock(&dev->struct_mutex);
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		struct etnaviv_gpu *gpu = priv->gpu[i];
+
+		if (gpu && gpu->lastctx == ctx)
+			gpu->lastctx = NULL;
+	}
+	mutex_unlock(&dev->struct_mutex);
+
+	kfree(ctx);
+}
+
+/*
+ * DRM debugfs:
+ */
+
+#ifdef CONFIG_DEBUG_FS
+static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gpu *gpu;
+	unsigned int i;
+
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		gpu = priv->gpu[i];
+		if (gpu) {
+			seq_printf(m, "Active Objects (%s):\n",
+				   dev_name(gpu->dev));
+			etnaviv_gem_describe_objects(&gpu->active_list, m);
+		}
+	}
+
+	seq_puts(m, "Inactive Objects:\n");
+	etnaviv_gem_describe_objects(&priv->inactive_list, m);
+
+	return 0;
+}
+
+static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m)
+{
+	return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
+}
+
+static int etnaviv_mmu_show(struct drm_device *dev, struct seq_file *m)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gpu *gpu;
+	unsigned int i;
+
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		gpu = priv->gpu[i];
+		if (gpu) {
+			seq_printf(m, "Active Objects (%s):\n",
+				   dev_name(gpu->dev));
+			drm_mm_dump_table(m, &gpu->mmu->mm);
+		}
+	}
+	return 0;
+}
+
+static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
+{
+	struct etnaviv_cmdbuf *buf = gpu->buffer;
+	u32 size = buf->size;
+	u32 *ptr = buf->vaddr;
+	u32 i;
+
+	seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
+			buf->vaddr, (u64)buf->paddr, size - buf->user_size);
+
+	for (i = 0; i < size / 4; i++) {
+		if (i && !(i % 4))
+			seq_puts(m, "\n");
+		if (i % 4 == 0)
+			seq_printf(m, "\t0x%p: ", ptr + i);
+		seq_printf(m, "%08x ", *(ptr + i));
+	}
+	seq_puts(m, "\n");
+}
+
+static int etnaviv_ring_show(struct drm_device *dev, struct seq_file *m)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gpu *gpu;
+	unsigned int i;
+
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		gpu = priv->gpu[i];
+		if (gpu) {
+			seq_printf(m, "Ring Buffer (%s): ",
+				   dev_name(gpu->dev));
+			etnaviv_buffer_dump(gpu, m);
+		}
+	}
+	return 0;
+}
+
+static int show_locked(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	int (*show)(struct drm_device *dev, struct seq_file *m) =
+			node->info_ent->data;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	ret = show(dev, m);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+static int show_each_gpu(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gpu *gpu;
+	int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
+			node->info_ent->data;
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		gpu = priv->gpu[i];
+		if (!gpu)
+			continue;
+
+		ret = show(gpu, m);
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
+static struct drm_info_list etnaviv_debugfs_list[] = {
+		{"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs},
+		{"gem", show_locked, 0, etnaviv_gem_show},
+		{ "mm", show_locked, 0, etnaviv_mm_show },
+		{"mmu", show_locked, 0, etnaviv_mmu_show},
+		{"ring", show_locked, 0, etnaviv_ring_show},
+};
+
+static int etnaviv_debugfs_init(struct drm_minor *minor)
+{
+	struct drm_device *dev = minor->dev;
+	int ret;
+
+	ret = drm_debugfs_create_files(etnaviv_debugfs_list,
+			ARRAY_SIZE(etnaviv_debugfs_list),
+			minor->debugfs_root, minor);
+
+	if (ret) {
+		dev_err(dev->dev, "could not install etnaviv_debugfs_list\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static void etnaviv_debugfs_cleanup(struct drm_minor *minor)
+{
+	drm_debugfs_remove_files(etnaviv_debugfs_list,
+			ARRAY_SIZE(etnaviv_debugfs_list), minor);
+}
+#endif
+
+/*
+ * DRM ioctls:
+ */
+
+static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
+		struct drm_file *file)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct drm_etnaviv_param *args = data;
+	struct etnaviv_gpu *gpu;
+
+	if (args->pipe >= ETNA_MAX_PIPES)
+		return -EINVAL;
+
+	gpu = priv->gpu[args->pipe];
+	if (!gpu)
+		return -ENXIO;
+
+	return etnaviv_gpu_get_param(gpu, args->param, &args->value);
+}
+
+static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
+		struct drm_file *file)
+{
+	struct drm_etnaviv_gem_new *args = data;
+
+	return etnaviv_gem_new_handle(dev, file, args->size,
+			args->flags, &args->handle);
+}
+
+#define TS(t) ((struct timespec){ \
+	.tv_sec = (t).tv_sec, \
+	.tv_nsec = (t).tv_nsec \
+})
+
+static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
+		struct drm_file *file)
+{
+	struct drm_etnaviv_gem_cpu_prep *args = data;
+	struct drm_gem_object *obj;
+	int ret;
+
+	obj = drm_gem_object_lookup(dev, file, args->handle);
+	if (!obj)
+		return -ENOENT;
+
+	ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout));
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	return ret;
+}
+
+static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
+		struct drm_file *file)
+{
+	struct drm_etnaviv_gem_cpu_fini *args = data;
+	struct drm_gem_object *obj;
+	int ret;
+
+	obj = drm_gem_object_lookup(dev, file, args->handle);
+	if (!obj)
+		return -ENOENT;
+
+	ret = etnaviv_gem_cpu_fini(obj);
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	return ret;
+}
+
+static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
+		struct drm_file *file)
+{
+	struct drm_etnaviv_gem_info *args = data;
+	struct drm_gem_object *obj;
+	int ret;
+
+	if (args->pad)
+		return -EINVAL;
+
+	obj = drm_gem_object_lookup(dev, file, args->handle);
+	if (!obj)
+		return -ENOENT;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret == 0) {
+		ret = etnaviv_gem_mmap_offset(obj, &args->offset);
+
+		mutex_unlock(&dev->struct_mutex);
+	}
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	return ret;
+}
+
+static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
+		struct drm_file *file)
+{
+	struct drm_etnaviv_wait_fence *args = data;
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gpu *gpu;
+
+	if (args->pipe >= ETNA_MAX_PIPES)
+		return -EINVAL;
+
+	gpu = priv->gpu[args->pipe];
+	if (!gpu)
+		return -ENXIO;
+
+	return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
+						    &TS(args->timeout));
+}
+
+static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
+	struct drm_file *file)
+{
+	struct drm_etnaviv_gem_userptr *args = data;
+	int access;
+
+	if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) ||
+	    args->flags == 0)
+		return -EINVAL;
+
+	if (offset_in_page(args->user_ptr | args->user_size) ||
+	    (uintptr_t)args->user_ptr != args->user_ptr ||
+	    (u32)args->user_size != args->user_size)
+		return -EINVAL;
+
+	if (args->flags & ETNA_USERPTR_WRITE)
+		access = VERIFY_WRITE;
+	else
+		access = VERIFY_READ;
+
+	if (!access_ok(access, (void __user *)(unsigned long)args->user_ptr,
+		       args->user_size))
+		return -EFAULT;
+
+	return etnaviv_gem_new_userptr(dev, file, args->user_ptr,
+				       args->user_size, args->flags,
+				       &args->handle);
+}
+
+static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
+	struct drm_file *file)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct drm_etnaviv_gem_wait *args = data;
+	struct drm_gem_object *obj;
+	struct etnaviv_gpu *gpu;
+	int ret;
+
+	if (args->pipe >= ETNA_MAX_PIPES)
+		return -EINVAL;
+
+	gpu = priv->gpu[args->pipe];
+	if (!gpu)
+		return -ENXIO;
+
+	obj = drm_gem_object_lookup(dev, file, args->handle);
+	if (!obj)
+		return -ENOENT;
+
+	ret = etnaviv_gem_wait_bo(gpu, obj, &TS(args->timeout));
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	return ret;
+}
+
+static const struct drm_ioctl_desc etnaviv_ioctls[] = {
+#define ETNA_IOCTL(n, func, flags) \
+	DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
+	ETNA_IOCTL(GET_PARAM,    get_param,    DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_NEW,      gem_new,      DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_INFO,     gem_info,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_SUBMIT,   gem_submit,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(WAIT_FENCE,   wait_fence,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_USERPTR,  gem_userptr,  DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_WAIT,     gem_wait,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+};
+
+static const struct vm_operations_struct vm_ops = {
+	.fault = etnaviv_gem_fault,
+	.open = drm_gem_vm_open,
+	.close = drm_gem_vm_close,
+};
+
+static const struct file_operations fops = {
+	.owner              = THIS_MODULE,
+	.open               = drm_open,
+	.release            = drm_release,
+	.unlocked_ioctl     = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl       = drm_compat_ioctl,
+#endif
+	.poll               = drm_poll,
+	.read               = drm_read,
+	.llseek             = no_llseek,
+	.mmap               = etnaviv_gem_mmap,
+};
+
+static struct drm_driver etnaviv_drm_driver = {
+	.driver_features    = DRIVER_HAVE_IRQ |
+				DRIVER_GEM |
+				DRIVER_PRIME |
+				DRIVER_RENDER,
+	.load               = etnaviv_load,
+	.unload             = etnaviv_unload,
+	.open               = etnaviv_open,
+	.preclose           = etnaviv_preclose,
+	.set_busid          = drm_platform_set_busid,
+	.gem_free_object    = etnaviv_gem_free_object,
+	.gem_vm_ops         = &vm_ops,
+	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+	.gem_prime_export   = drm_gem_prime_export,
+	.gem_prime_import   = drm_gem_prime_import,
+	.gem_prime_pin      = etnaviv_gem_prime_pin,
+	.gem_prime_unpin    = etnaviv_gem_prime_unpin,
+	.gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table,
+	.gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
+	.gem_prime_vmap     = etnaviv_gem_prime_vmap,
+	.gem_prime_vunmap   = etnaviv_gem_prime_vunmap,
+#ifdef CONFIG_DEBUG_FS
+	.debugfs_init       = etnaviv_debugfs_init,
+	.debugfs_cleanup    = etnaviv_debugfs_cleanup,
+#endif
+	.ioctls             = etnaviv_ioctls,
+	.num_ioctls         = DRM_ETNAVIV_NUM_IOCTLS,
+	.fops               = &fops,
+	.name               = "etnaviv",
+	.desc               = "etnaviv DRM",
+	.date               = "20150910",
+	.major              = 1,
+	.minor              = 0,
+};
+
+/*
+ * Platform driver:
+ */
+static int etnaviv_bind(struct device *dev)
+{
+	return drm_platform_init(&etnaviv_drm_driver, to_platform_device(dev));
+}
+
+static void etnaviv_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops etnaviv_master_ops = {
+	.bind = etnaviv_bind,
+	.unbind = etnaviv_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	struct device_node *np = data;
+
+	return dev->of_node == np;
+}
+
+static int compare_str(struct device *dev, void *data)
+{
+	return !strcmp(dev_name(dev), data);
+}
+
+static int etnaviv_pdev_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct component_match *match = NULL;
+
+	dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+	if (node) {
+		struct device_node *core_node;
+		int i;
+
+		for (i = 0; ; i++) {
+			core_node = of_parse_phandle(node, "cores", i);
+			if (!core_node)
+				break;
+
+			component_match_add(&pdev->dev, &match, compare_of,
+					    core_node);
+			of_node_put(core_node);
+		}
+	} else if (dev->platform_data) {
+		char **names = dev->platform_data;
+		unsigned i;
+
+		for (i = 0; names[i]; i++)
+			component_match_add(dev, &match, compare_str, names[i]);
+	}
+
+	return component_master_add_with_match(dev, &etnaviv_master_ops, match);
+}
+
+static int etnaviv_pdev_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &etnaviv_master_ops);
+
+	return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+	{ .compatible = "fsl,imx-gpu-subsystem" },
+	{ .compatible = "marvell,dove-gpu-subsystem" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
+static struct platform_driver etnaviv_platform_driver = {
+	.probe      = etnaviv_pdev_probe,
+	.remove     = etnaviv_pdev_remove,
+	.driver     = {
+		.owner  = THIS_MODULE,
+		.name   = "etnaviv",
+		.of_match_table = dt_match,
+	},
+};
+
+static int __init etnaviv_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&etnaviv_gpu_driver);
+	if (ret != 0)
+		return ret;
+
+	ret = platform_driver_register(&etnaviv_platform_driver);
+	if (ret != 0)
+		platform_driver_unregister(&etnaviv_gpu_driver);
+
+	return ret;
+}
+module_init(etnaviv_init);
+
+static void __exit etnaviv_exit(void)
+{
+	platform_driver_unregister(&etnaviv_gpu_driver);
+	platform_driver_unregister(&etnaviv_platform_driver);
+}
+module_exit(etnaviv_exit);
+
+MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>");
+MODULE_DESCRIPTION("etnaviv DRM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:etnaviv");
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
new file mode 100644
index 000000000000..719e33174e83
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -0,0 +1,138 @@
+/*
+ * 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_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];
+
+	u32 next_fence;
+
+	/* list of GEM objects: */
+	struct list_head inactive_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_locked(struct etnaviv_gpu *gpu,
+	struct drm_gem_object *obj, u32 *iova);
+int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
+	int id, u32 *iova);
+void etnaviv_gem_put_iova(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_locked(struct drm_gem_object *obj);
+void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
+dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj);
+void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
+		struct etnaviv_gpu *gpu, u32 access, u32 fence);
+void etnaviv_gem_move_to_inactive(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_gem_submit *submit);
+bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
+	void *stream, unsigned int size);
+
+#ifdef CONFIG_DEBUG_FS
+void etnaviv_gem_describe_objects(struct list_head *list, 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__)
+
+/* 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;
+}
+
+#endif /* __ETNAVIV_DRV_H__ */
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
new file mode 100644
index 000000000000..1381c952c52f
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -0,0 +1,887 @@
+/*
+ * 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/spinlock.h>
+#include <linux/shmem_fs.h>
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_mmu.h"
+
+static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct drm_device *dev = etnaviv_obj->base.dev;
+	struct sg_table *sgt = etnaviv_obj->sgt;
+
+	/*
+	 * For non-cached buffers, ensure the new pages are clean
+	 * because display controller, GPU, etc. are not coherent.
+	 */
+	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
+		dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+}
+
+static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct drm_device *dev = etnaviv_obj->base.dev;
+	struct sg_table *sgt = etnaviv_obj->sgt;
+
+	/*
+	 * For non-cached buffers, ensure the new pages are clean
+	 * because display controller, GPU, etc. are not coherent:
+	 *
+	 * WARNING: The DMA API does not support concurrent CPU
+	 * and device access to the memory area.  With BIDIRECTIONAL,
+	 * we will clean the cache lines which overlap the region,
+	 * and invalidate all cache lines (partially) contained in
+	 * the region.
+	 *
+	 * If you have dirty data in the overlapping cache lines,
+	 * that will corrupt the GPU-written data.  If you have
+	 * written into the remainder of the region, this can
+	 * discard those writes.
+	 */
+	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
+		dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+}
+
+/* called with dev->struct_mutex held */
+static int etnaviv_gem_shmem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct drm_device *dev = etnaviv_obj->base.dev;
+	struct page **p = drm_gem_get_pages(&etnaviv_obj->base);
+
+	if (IS_ERR(p)) {
+		dev_err(dev->dev, "could not get pages: %ld\n", PTR_ERR(p));
+		return PTR_ERR(p);
+	}
+
+	etnaviv_obj->pages = p;
+
+	return 0;
+}
+
+static void put_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+	if (etnaviv_obj->sgt) {
+		etnaviv_gem_scatterlist_unmap(etnaviv_obj);
+		sg_free_table(etnaviv_obj->sgt);
+		kfree(etnaviv_obj->sgt);
+		etnaviv_obj->sgt = NULL;
+	}
+	if (etnaviv_obj->pages) {
+		drm_gem_put_pages(&etnaviv_obj->base, etnaviv_obj->pages,
+				  true, false);
+
+		etnaviv_obj->pages = NULL;
+	}
+}
+
+struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+	int ret;
+
+	if (!etnaviv_obj->pages) {
+		ret = etnaviv_obj->ops->get_pages(etnaviv_obj);
+		if (ret < 0)
+			return ERR_PTR(ret);
+	}
+
+	if (!etnaviv_obj->sgt) {
+		struct drm_device *dev = etnaviv_obj->base.dev;
+		int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+		struct sg_table *sgt;
+
+		sgt = drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
+		if (IS_ERR(sgt)) {
+			dev_err(dev->dev, "failed to allocate sgt: %ld\n",
+				PTR_ERR(sgt));
+			return ERR_CAST(sgt);
+		}
+
+		etnaviv_obj->sgt = sgt;
+
+		etnaviv_gem_scatter_map(etnaviv_obj);
+	}
+
+	return etnaviv_obj->pages;
+}
+
+void etnaviv_gem_put_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+	/* when we start tracking the pin count, then do something here */
+}
+
+static int etnaviv_gem_mmap_obj(struct drm_gem_object *obj,
+		struct vm_area_struct *vma)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	pgprot_t vm_page_prot;
+
+	vma->vm_flags &= ~VM_PFNMAP;
+	vma->vm_flags |= VM_MIXEDMAP;
+
+	vm_page_prot = vm_get_page_prot(vma->vm_flags);
+
+	if (etnaviv_obj->flags & ETNA_BO_WC) {
+		vma->vm_page_prot = pgprot_writecombine(vm_page_prot);
+	} else if (etnaviv_obj->flags & ETNA_BO_UNCACHED) {
+		vma->vm_page_prot = pgprot_noncached(vm_page_prot);
+	} else {
+		/*
+		 * Shunt off cached objs to shmem file so they have their own
+		 * address_space (so unmap_mapping_range does what we want,
+		 * in particular in the case of mmap'd dmabufs)
+		 */
+		fput(vma->vm_file);
+		get_file(obj->filp);
+		vma->vm_pgoff = 0;
+		vma->vm_file  = obj->filp;
+
+		vma->vm_page_prot = vm_page_prot;
+	}
+
+	return 0;
+}
+
+int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct etnaviv_gem_object *obj;
+	int ret;
+
+	ret = drm_gem_mmap(filp, vma);
+	if (ret) {
+		DBG("mmap failed: %d", ret);
+		return ret;
+	}
+
+	obj = to_etnaviv_bo(vma->vm_private_data);
+	return etnaviv_gem_mmap_obj(vma->vm_private_data, vma);
+}
+
+int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct drm_gem_object *obj = vma->vm_private_data;
+	struct drm_device *dev = obj->dev;
+	struct page **pages, *page;
+	pgoff_t pgoff;
+	int ret;
+
+	/*
+	 * Make sure we don't parallel update on a fault, nor move or remove
+	 * something from beneath our feet.  Note that vm_insert_page() is
+	 * specifically coded to take care of this, so we don't have to.
+	 */
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		goto out;
+
+	/* make sure we have pages attached now */
+	pages = etnaviv_gem_get_pages(to_etnaviv_bo(obj));
+	mutex_unlock(&dev->struct_mutex);
+
+	if (IS_ERR(pages)) {
+		ret = PTR_ERR(pages);
+		goto out;
+	}
+
+	/* We don't use vmf->pgoff since that has the fake offset: */
+	pgoff = ((unsigned long)vmf->virtual_address -
+			vma->vm_start) >> PAGE_SHIFT;
+
+	page = pages[pgoff];
+
+	VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
+	     page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT);
+
+	ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
+
+out:
+	switch (ret) {
+	case -EAGAIN:
+	case 0:
+	case -ERESTARTSYS:
+	case -EINTR:
+	case -EBUSY:
+		/*
+		 * EBUSY is ok: this just means that another thread
+		 * already did the job.
+		 */
+		return VM_FAULT_NOPAGE;
+	case -ENOMEM:
+		return VM_FAULT_OOM;
+	default:
+		return VM_FAULT_SIGBUS;
+	}
+}
+
+/* get mmap offset - must be called under struct_mutex */
+int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset)
+{
+	int ret;
+
+	/* Make it mmapable */
+	ret = drm_gem_create_mmap_offset(obj);
+	if (ret)
+		dev_err(obj->dev->dev, "could not allocate mmap offset\n");
+	else
+		*offset = drm_vma_node_offset_addr(&obj->vma_node);
+
+	return ret;
+}
+
+/* should be called under struct_mutex.. although it can be called
+ * from atomic context without struct_mutex to acquire an extra
+ * iova ref if you know one is already held.
+ *
+ * That means when I do eventually need to add support for unpinning
+ * the refcnt counter needs to be atomic_t.
+ */
+int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
+	struct drm_gem_object *obj, u32 *iova)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	struct etnaviv_vram_mapping *mapping;
+	int ret = 0;
+
+	mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
+	if (!mapping) {
+		struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
+		if (IS_ERR(pages))
+			return PTR_ERR(pages);
+		ret = etnaviv_iommu_map_gem(gpu->mmu, etnaviv_obj,
+				gpu->memory_base, &mapping);
+	}
+
+	if (!ret)
+		*iova = mapping->iova;
+
+	return ret;
+}
+
+int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
+	int id, u32 *iova)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	struct etnaviv_vram_mapping *mapping =
+			etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
+	int ret;
+
+	/* this is safe right now because we don't unmap until the
+	 * bo is deleted:
+	 */
+	if (mapping) {
+		*iova = mapping->iova;
+		return 0;
+	}
+
+	mutex_lock(&obj->dev->struct_mutex);
+	ret = etnaviv_gem_get_iova_locked(gpu, obj, iova);
+	mutex_unlock(&obj->dev->struct_mutex);
+
+	return ret;
+}
+
+void etnaviv_gem_put_iova(struct drm_gem_object *obj)
+{
+	/*
+	 * XXX TODO ..
+	 * NOTE: probably don't need a _locked() version.. we wouldn't
+	 * normally unmap here, but instead just mark that it could be
+	 * unmapped (if the iova refcnt drops to zero), but then later
+	 * if another _get_iova_locked() fails we can start unmapping
+	 * things that are no longer needed..
+	 */
+}
+
+void *etnaviv_gem_vaddr_locked(struct drm_gem_object *obj)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
+
+	if (!etnaviv_obj->vaddr) {
+		struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
+
+		if (IS_ERR(pages))
+			return ERR_CAST(pages);
+
+		etnaviv_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
+				VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+	}
+
+	return etnaviv_obj->vaddr;
+}
+
+void *etnaviv_gem_vaddr(struct drm_gem_object *obj)
+{
+	void *ret;
+
+	mutex_lock(&obj->dev->struct_mutex);
+	ret = etnaviv_gem_vaddr_locked(obj);
+	mutex_unlock(&obj->dev->struct_mutex);
+
+	return ret;
+}
+
+dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
+
+	return etnaviv_obj->paddr;
+}
+
+void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
+	struct etnaviv_gpu *gpu, u32 access, u32 fence)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	etnaviv_obj->gpu = gpu;
+
+	if (access & ETNA_SUBMIT_BO_READ)
+		etnaviv_obj->read_fence = fence;
+	if (access & ETNA_SUBMIT_BO_WRITE)
+		etnaviv_obj->write_fence = fence;
+
+	etnaviv_obj->access |= access;
+
+	list_del_init(&etnaviv_obj->mm_list);
+	list_add_tail(&etnaviv_obj->mm_list, &gpu->active_list);
+}
+
+void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj)
+{
+	struct drm_device *dev = obj->dev;
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	etnaviv_obj->gpu = NULL;
+	etnaviv_obj->read_fence = 0;
+	etnaviv_obj->write_fence = 0;
+	etnaviv_obj->access = 0;
+	list_del_init(&etnaviv_obj->mm_list);
+	list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
+}
+
+static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
+{
+	if (op & ETNA_PREP_READ)
+		return DMA_FROM_DEVICE;
+	else if (op & ETNA_PREP_WRITE)
+		return DMA_TO_DEVICE;
+	else
+		return DMA_BIDIRECTIONAL;
+}
+
+int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
+		struct timespec *timeout)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	struct drm_device *dev = obj->dev;
+	int ret = 0;
+
+	if (is_active(etnaviv_obj)) {
+		struct etnaviv_gpu *gpu = etnaviv_obj->gpu;
+		u32 fence = 0;
+
+		if (op & ETNA_PREP_READ)
+			fence = etnaviv_obj->write_fence;
+		if (op & ETNA_PREP_WRITE)
+			fence = max(fence, etnaviv_obj->read_fence);
+		if (op & ETNA_PREP_NOSYNC)
+			timeout = NULL;
+
+		ret = etnaviv_gpu_wait_fence_interruptible(gpu, fence, timeout);
+	}
+
+	if (etnaviv_obj->flags & ETNA_BO_CACHED) {
+		if (!etnaviv_obj->sgt) {
+			void * ret;
+
+			mutex_lock(&dev->struct_mutex);
+			ret = etnaviv_gem_get_pages(etnaviv_obj);
+			mutex_unlock(&dev->struct_mutex);
+			if (IS_ERR(ret))
+				return PTR_ERR(ret);
+		}
+
+		dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
+				    etnaviv_obj->sgt->nents,
+				    etnaviv_op_to_dma_dir(op));
+		etnaviv_obj->last_cpu_prep_op = op;
+	}
+
+	return ret;
+}
+
+int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
+{
+	struct drm_device *dev = obj->dev;
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	if (etnaviv_obj->flags & ETNA_BO_CACHED) {
+		/* fini without a prep is almost certainly a userspace error */
+		WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
+		dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
+			etnaviv_obj->sgt->nents,
+			etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
+		etnaviv_obj->last_cpu_prep_op = 0;
+	}
+
+	return 0;
+}
+
+int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
+	struct timespec *timeout)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	return etnaviv_gpu_wait_obj_inactive(gpu, etnaviv_obj, timeout);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
+{
+	struct drm_device *dev = obj->dev;
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	unsigned long off = drm_vma_node_start(&obj->vma_node);
+
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08lx %p %zd\n",
+			etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
+			etnaviv_obj->read_fence, etnaviv_obj->write_fence,
+			obj->name, obj->refcount.refcount.counter,
+			off, etnaviv_obj->vaddr, obj->size);
+}
+
+void etnaviv_gem_describe_objects(struct list_head *list, struct seq_file *m)
+{
+	struct etnaviv_gem_object *etnaviv_obj;
+	int count = 0;
+	size_t size = 0;
+
+	list_for_each_entry(etnaviv_obj, list, mm_list) {
+		struct drm_gem_object *obj = &etnaviv_obj->base;
+
+		seq_puts(m, "   ");
+		etnaviv_gem_describe(obj, m);
+		count++;
+		size += obj->size;
+	}
+
+	seq_printf(m, "Total %d objects, %zu bytes\n", count, size);
+}
+#endif
+
+static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)
+{
+	if (etnaviv_obj->vaddr)
+		vunmap(etnaviv_obj->vaddr);
+	put_pages(etnaviv_obj);
+}
+
+static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {
+	.get_pages = etnaviv_gem_shmem_get_pages,
+	.release = etnaviv_gem_shmem_release,
+};
+
+void etnaviv_gem_free_object(struct drm_gem_object *obj)
+{
+	struct drm_device *dev = obj->dev;
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	struct etnaviv_vram_mapping *mapping, *tmp;
+
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	/* object should not be on active list: */
+	WARN_ON(is_active(etnaviv_obj));
+
+	list_del(&etnaviv_obj->mm_list);
+
+	list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
+				 obj_node)
+		etnaviv_iommu_unmap_gem(mapping);
+
+	drm_gem_free_mmap_offset(obj);
+	etnaviv_obj->ops->release(etnaviv_obj);
+	reservation_object_fini(&etnaviv_obj->_resv);
+	drm_gem_object_release(obj);
+
+	kfree(etnaviv_obj);
+}
+
+int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	int ret;
+
+	ret = mutex_lock_killable(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+static int etnaviv_gem_new_impl(struct drm_device *dev,
+		u32 size, u32 flags,
+		struct drm_gem_object **obj)
+{
+	struct etnaviv_gem_object *etnaviv_obj;
+	unsigned sz = sizeof(*etnaviv_obj);
+	bool valid = true;
+
+	/* validate flags */
+	switch (flags & ETNA_BO_CACHE_MASK) {
+	case ETNA_BO_UNCACHED:
+	case ETNA_BO_CACHED:
+	case ETNA_BO_WC:
+		break;
+	default:
+		valid = false;
+	}
+
+	if (!valid) {
+		dev_err(dev->dev, "invalid cache flag: %x\n",
+			(flags & ETNA_BO_CACHE_MASK));
+		return -EINVAL;
+	}
+
+	etnaviv_obj = kzalloc(sz, GFP_KERNEL);
+	if (!etnaviv_obj)
+		return -ENOMEM;
+
+	etnaviv_obj->flags = flags;
+
+	etnaviv_obj->resv = &etnaviv_obj->_resv;
+	reservation_object_init(&etnaviv_obj->_resv);
+
+	INIT_LIST_HEAD(&etnaviv_obj->submit_entry);
+	INIT_LIST_HEAD(&etnaviv_obj->mm_list);
+	INIT_LIST_HEAD(&etnaviv_obj->vram_list);
+
+	*obj = &etnaviv_obj->base;
+
+	return 0;
+}
+
+static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
+		u32 size, u32 flags)
+{
+	struct drm_gem_object *obj = NULL;
+	int ret;
+
+	size = PAGE_ALIGN(size);
+
+	ret = etnaviv_gem_new_impl(dev, size, flags, &obj);
+	if (ret)
+		goto fail;
+
+	to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops;
+	ret = drm_gem_object_init(dev, obj, size);
+	if (ret == 0) {
+		struct address_space *mapping;
+
+		/*
+		 * Our buffers are kept pinned, so allocating them
+		 * from the MOVABLE zone is a really bad idea, and
+		 * conflicts with CMA.  See coments above new_inode()
+		 * why this is required _and_ expected if you're
+		 * going to pin these pages.
+		 */
+		mapping = file_inode(obj->filp)->i_mapping;
+		mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
+	}
+
+	if (ret)
+		goto fail;
+
+	return obj;
+
+fail:
+	if (obj)
+		drm_gem_object_unreference_unlocked(obj);
+
+	return ERR_PTR(ret);
+}
+
+/* convenience method to construct a GEM buffer object, and userspace handle */
+int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
+		u32 size, u32 flags, u32 *handle)
+{
+	struct drm_gem_object *obj;
+	int ret;
+
+	obj = __etnaviv_gem_new(dev, size, flags);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	ret = etnaviv_gem_obj_add(dev, obj);
+	if (ret < 0) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
+
+	ret = drm_gem_handle_create(file, obj, handle);
+
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference_unlocked(obj);
+
+	return ret;
+}
+
+struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
+		u32 size, u32 flags)
+{
+	struct drm_gem_object *obj;
+	int ret;
+
+	obj = __etnaviv_gem_new(dev, size, flags);
+	if (IS_ERR(obj))
+		return obj;
+
+	ret = etnaviv_gem_obj_add(dev, obj);
+	if (ret < 0) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ERR_PTR(ret);
+	}
+
+	return obj;
+}
+
+int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
+	struct etnaviv_gem_object **res)
+{
+	struct drm_gem_object *obj;
+	int ret;
+
+	ret = etnaviv_gem_new_impl(dev, size, flags, &obj);
+	if (ret)
+		return ret;
+
+	drm_gem_private_object_init(dev, obj, size);
+
+	*res = to_etnaviv_bo(obj);
+
+	return 0;
+}
+
+struct etnaviv_vram_mapping *
+etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
+			     struct etnaviv_iommu *mmu)
+{
+	struct etnaviv_vram_mapping *mapping;
+
+	list_for_each_entry(mapping, &obj->vram_list, obj_node) {
+		if (mapping->mmu == mmu)
+			return mapping;
+	}
+
+	return NULL;
+}
+
+struct get_pages_work {
+	struct work_struct work;
+	struct mm_struct *mm;
+	struct task_struct *task;
+	struct etnaviv_gem_object *etnaviv_obj;
+};
+
+static struct page **etnaviv_gem_userptr_do_get_pages(
+	struct etnaviv_gem_object *etnaviv_obj, struct mm_struct *mm, struct task_struct *task)
+{
+	int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+	struct page **pvec;
+	uintptr_t ptr;
+
+	pvec = drm_malloc_ab(npages, sizeof(struct page *));
+	if (!pvec)
+		return ERR_PTR(-ENOMEM);
+
+	pinned = 0;
+	ptr = etnaviv_obj->userptr.ptr;
+
+	down_read(&mm->mmap_sem);
+	while (pinned < npages) {
+		ret = get_user_pages(task, mm, ptr, npages - pinned,
+				     !etnaviv_obj->userptr.ro, 0,
+				     pvec + pinned, NULL);
+		if (ret < 0)
+			break;
+
+		ptr += ret * PAGE_SIZE;
+		pinned += ret;
+	}
+	up_read(&mm->mmap_sem);
+
+	if (ret < 0) {
+		release_pages(pvec, pinned, 0);
+		drm_free_large(pvec);
+		return ERR_PTR(ret);
+	}
+
+	return pvec;
+}
+
+static void __etnaviv_gem_userptr_get_pages(struct work_struct *_work)
+{
+	struct get_pages_work *work = container_of(_work, typeof(*work), work);
+	struct etnaviv_gem_object *etnaviv_obj = work->etnaviv_obj;
+	struct drm_device *dev = etnaviv_obj->base.dev;
+	struct page **pvec;
+
+	pvec = etnaviv_gem_userptr_do_get_pages(etnaviv_obj, work->mm, work->task);
+
+	mutex_lock(&dev->struct_mutex);
+	if (IS_ERR(pvec)) {
+		etnaviv_obj->userptr.work = ERR_CAST(pvec);
+	} else {
+		etnaviv_obj->userptr.work = NULL;
+		etnaviv_obj->pages = pvec;
+	}
+
+	drm_gem_object_unreference(&etnaviv_obj->base);
+	mutex_unlock(&dev->struct_mutex);
+
+	mmput(work->mm);
+	put_task_struct(work->task);
+	kfree(work);
+}
+
+static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct page **pvec = NULL;
+	struct get_pages_work *work;
+	struct mm_struct *mm;
+	int ret, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+
+	if (etnaviv_obj->userptr.work) {
+		if (IS_ERR(etnaviv_obj->userptr.work)) {
+			ret = PTR_ERR(etnaviv_obj->userptr.work);
+			etnaviv_obj->userptr.work = NULL;
+		} else {
+			ret = -EAGAIN;
+		}
+		return ret;
+	}
+
+	mm = get_task_mm(etnaviv_obj->userptr.task);
+	pinned = 0;
+	if (mm == current->mm) {
+		pvec = drm_malloc_ab(npages, sizeof(struct page *));
+		if (!pvec) {
+			mmput(mm);
+			return -ENOMEM;
+		}
+
+		pinned = __get_user_pages_fast(etnaviv_obj->userptr.ptr, npages,
+					       !etnaviv_obj->userptr.ro, pvec);
+		if (pinned < 0) {
+			drm_free_large(pvec);
+			mmput(mm);
+			return pinned;
+		}
+
+		if (pinned == npages) {
+			etnaviv_obj->pages = pvec;
+			mmput(mm);
+			return 0;
+		}
+	}
+
+	release_pages(pvec, pinned, 0);
+	drm_free_large(pvec);
+
+	work = kmalloc(sizeof(*work), GFP_KERNEL);
+	if (!work) {
+		mmput(mm);
+		return -ENOMEM;
+	}
+
+	get_task_struct(current);
+	drm_gem_object_reference(&etnaviv_obj->base);
+
+	work->mm = mm;
+	work->task = current;
+	work->etnaviv_obj = etnaviv_obj;
+
+	etnaviv_obj->userptr.work = &work->work;
+	INIT_WORK(&work->work, __etnaviv_gem_userptr_get_pages);
+
+	etnaviv_queue_work(etnaviv_obj->base.dev, &work->work);
+
+	return -EAGAIN;
+}
+
+static void etnaviv_gem_userptr_release(struct etnaviv_gem_object *etnaviv_obj)
+{
+	if (etnaviv_obj->sgt) {
+		etnaviv_gem_scatterlist_unmap(etnaviv_obj);
+		sg_free_table(etnaviv_obj->sgt);
+		kfree(etnaviv_obj->sgt);
+	}
+	if (etnaviv_obj->pages) {
+		int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+
+		release_pages(etnaviv_obj->pages, npages, 0);
+		drm_free_large(etnaviv_obj->pages);
+	}
+	put_task_struct(etnaviv_obj->userptr.task);
+}
+
+static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops = {
+	.get_pages = etnaviv_gem_userptr_get_pages,
+	.release = etnaviv_gem_userptr_release,
+};
+
+int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
+	uintptr_t ptr, u32 size, u32 flags, u32 *handle)
+{
+	struct etnaviv_gem_object *etnaviv_obj;
+	int ret;
+
+	ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, &etnaviv_obj);
+	if (ret)
+		return ret;
+
+	etnaviv_obj->ops = &etnaviv_gem_userptr_ops;
+	etnaviv_obj->userptr.ptr = ptr;
+	etnaviv_obj->userptr.task = current;
+	etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);
+	get_task_struct(current);
+
+	ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
+		return ret;
+	}
+
+	ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);
+
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
+
+	return ret;
+}
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
new file mode 100644
index 000000000000..c991d12e7aed
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -0,0 +1,141 @@
+/*
+ * 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 etnaviv_gem_object *object;
+	struct etnaviv_iommu *mmu;
+	struct drm_mm_node vram_node;
+	u32 iova;
+};
+
+struct etnaviv_gem_object {
+	struct drm_gem_object base;
+	const struct etnaviv_gem_ops *ops;
+
+	u32 flags;
+
+	/* And object is either:
+	 *  inactive - on priv->inactive_list
+	 *  active   - on one one of the gpu's active_list..  well, at
+	 *     least for now we don't have (I don't think) hw sync between
+	 *     2d and 3d one devices which have both, meaning we need to
+	 *     block on submit if a bo is already on other ring
+	 *
+	 */
+	struct list_head mm_list;
+	struct etnaviv_gpu *gpu;     /* non-null if active */
+	u32 access;
+	u32 read_fence, write_fence;
+
+	/* Transiently in the process of submit ioctl, objects associated
+	 * with the submit are on submit->bo_list.. this only lasts for
+	 * the duration of the ioctl, so one bo can never be on multiple
+	 * submit lists.
+	 */
+	struct list_head submit_entry;
+
+	struct page **pages;
+	struct sg_table *sgt;
+	void *vaddr;
+
+	/* for ETNA_BO_CMDSTREAM */
+	dma_addr_t paddr;
+
+	/* normally (resv == &_resv) except for imported bo's */
+	struct reservation_object *resv;
+	struct reservation_object _resv;
+
+	struct list_head vram_list;
+
+	/* for buffer manipulation during submit */
+	bool is_ring_buffer;
+	u32 offset;
+
+	/* cache maintenance */
+	uint32_t 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 etnaviv_obj->gpu != NULL;
+}
+
+#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;
+	u32 exec_state;
+	struct list_head bo_list;
+	struct ww_acquire_ctx ticket;
+	u32 fence;
+	unsigned int nr_bos;
+	struct etnaviv_cmdbuf *cmdbuf;
+	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);
+struct etnaviv_vram_mapping *
+etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
+			     struct etnaviv_iommu *mmu);
+int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
+	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__ */
diff --git a/drivers/staging/etnaviv/etnaviv_gem_prime.c b/drivers/staging/etnaviv/etnaviv_gem_prime.c
new file mode 100644
index 000000000000..58c13ae7c345
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_gem_prime.c
@@ -0,0 +1,121 @@
+/*
+ * 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 drm_device *dev = obj->dev;
+
+		mutex_lock(&dev->struct_mutex);
+		etnaviv_gem_get_pages(to_etnaviv_bo(obj));
+		mutex_unlock(&dev->struct_mutex);
+	}
+	return 0;
+}
+
+void etnaviv_gem_prime_unpin(struct drm_gem_object *obj)
+{
+	if (!obj->import_attach) {
+		struct drm_device *dev = obj->dev;
+
+		mutex_lock(&dev->struct_mutex);
+		etnaviv_gem_put_pages(to_etnaviv_bo(obj));
+		mutex_unlock(&dev->struct_mutex);
+	}
+}
+
+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, &etnaviv_obj);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	npages = size / PAGE_SIZE;
+
+	etnaviv_obj->ops = &etnaviv_gem_prime_ops;
+	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);
+}
diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
new file mode 100644
index 000000000000..f886a3c66d30
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -0,0 +1,421 @@
+/*
+ * 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 "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, int nr)
+{
+	struct etnaviv_gem_submit *submit;
+	int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0]));
+
+	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;
+		submit->cmdbuf = NULL;
+
+		INIT_LIST_HEAD(&submit->bo_list);
+		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;
+		struct etnaviv_gem_object *etnaviv_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;
+		}
+
+		etnaviv_obj = to_etnaviv_bo(obj);
+
+		if (!list_empty(&etnaviv_obj->submit_entry)) {
+			DRM_ERROR("handle %u at index %u already on submit list\n",
+				  bo->handle, i);
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+
+		drm_gem_object_reference(obj);
+
+		submit->bos[i].obj = etnaviv_obj;
+
+		list_add_tail(&etnaviv_obj->submit_entry, &submit->bo_list);
+	}
+
+out_unlock:
+	submit->nr_bos = i;
+	spin_unlock(&file->table_lock);
+
+	return ret;
+}
+
+static void submit_unlock_unpin_bo(struct etnaviv_gem_submit *submit, int i)
+{
+	struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+	if (submit->bos[i].flags & BO_PINNED)
+		etnaviv_gem_put_iova(&etnaviv_obj->base);
+
+	if (submit->bos[i].flags & BO_LOCKED)
+		ww_mutex_unlock(&etnaviv_obj->resv->lock);
+
+	submit->bos[i].iova = 0;
+	submit->bos[i].flags &= ~(BO_LOCKED | BO_PINNED);
+}
+
+/* This is where we make sure all the bo's are reserved and pin'd: */
+static int submit_validate_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;
+		u32 iova;
+
+		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)
+				goto fail;
+			submit->bos[i].flags |= BO_LOCKED;
+		}
+
+
+		/* if locking succeeded, pin bo: */
+		ret = etnaviv_gem_get_iova_locked(submit->gpu,
+						  &etnaviv_obj->base, &iova);
+
+		/* this would break the logic in the fail path.. there is no
+		 * reason for this to happen, but just to be on the safe side
+		 * let's notice if this starts happening in the future:
+		 */
+		WARN_ON(ret == -EDEADLK);
+
+		if (ret)
+			goto fail;
+
+		submit->bos[i].flags |= BO_PINNED;
+		submit->bos[i].iova = iova;
+	}
+
+	ww_acquire_done(&submit->ticket);
+
+	return 0;
+
+fail:
+	for (; i >= 0; i--)
+		submit_unlock_unpin_bo(submit, i);
+
+	if (slow_locked > 0)
+		submit_unlock_unpin_bo(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_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, u32 nr_relocs, u64 relocs)
+{
+	u32 i, last_offset = 0;
+	u32 *ptr = stream;
+	int ret;
+
+	for (i = 0; i < nr_relocs; i++) {
+		struct drm_etnaviv_gem_submit_reloc submit_reloc;
+		struct etnaviv_gem_object *bobj;
+		void __user *userptr =
+			to_user_ptr(relocs + (i * sizeof(submit_reloc)));
+		u32 iova, off;
+
+		ret = copy_from_user(&submit_reloc, userptr,
+				     sizeof(submit_reloc));
+		if (ret)
+			return -EFAULT;
+
+		if (submit_reloc.submit_offset % 4) {
+			DRM_ERROR("non-aligned reloc offset: %u\n",
+					submit_reloc.submit_offset);
+			return -EINVAL;
+		}
+
+		/* offset in dwords: */
+		off = submit_reloc.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, submit_reloc.reloc_idx, &bobj, &iova);
+		if (ret)
+			return ret;
+
+		if (submit_reloc.reloc_offset >=
+		    bobj->base.size - sizeof(*ptr)) {
+			DRM_ERROR("relocation %u outside object", i);
+			return -EINVAL;
+		}
+
+		ptr[off] = iova + submit_reloc.reloc_offset;
+
+		last_offset = off;
+	}
+
+	return 0;
+}
+
+static void submit_cleanup(struct etnaviv_gem_submit *submit, bool fail)
+{
+	unsigned i;
+
+	for (i = 0; i < submit->nr_bos; i++) {
+		struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+		submit_unlock_unpin_bo(submit, i);
+		list_del_init(&etnaviv_obj->submit_entry);
+		drm_gem_object_unreference(&etnaviv_obj->base);
+	}
+
+	if (submit->cmdbuf)
+		etnaviv_gpu_cmdbuf_free(submit->cmdbuf);
+
+	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 etnaviv_file_private *ctx = file->driver_priv;
+	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;
+	}
+
+	/*
+	 * Copy the command submission and bo array to kernel space in
+	 * one go, and do this outside of the dev->struct_mutex lock.
+	 */
+	bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
+	stream = drm_malloc_ab(1, args->stream_size);
+	cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8);
+	if (!bos || !stream || !cmdbuf) {
+		ret = -ENOMEM;
+		goto err_submit_cmds;
+	}
+
+	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(stream, to_user_ptr(args->stream),
+			     args->stream_size);
+	if (ret) {
+		ret = -EFAULT;
+		goto err_submit_cmds;
+	}
+
+	/*
+	 * Avoid big circular locking dependency loops:
+	 * - reading debugfs results in mmap_sem depending on i_mutex_key#3
+	 *   (iterate_dir -> filldir64)
+	 * - struct_mutex depends on mmap_sem
+	 *   (vm_mmap_pgoff -> drm_gem_mmap)
+	 * then if we try to do a get_sync() under struct_mutex,
+	 * - genpd->lock depends on struct_mutex
+	 *   (etnaviv_ioctl_gem_submit -> pm_genpd_runtime_resume)
+	 * - (regulator) rdev->mutex depends on genpd->lock
+	 *   (pm_genpd_poweron -> regulator_enable)
+	 * - i_mutex_key#3 depends on rdev->mutex
+	 *   (create_regulator -> debugfs::start_creating)
+	 * and lockdep rightfully explodes.
+	 *
+	 * Avoid this by getting runtime PM outside of the struct_mutex lock.
+	 */
+	ret = etnaviv_gpu_pm_get_sync(gpu);
+	if (ret < 0)
+		goto err_submit_cmds;
+
+	mutex_lock(&dev->struct_mutex);
+
+	submit = submit_create(dev, gpu, args->nr_bos);
+	if (!submit) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	submit->exec_state = args->exec_state;
+
+	ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
+	if (ret)
+		goto out;
+
+	ret = submit_validate_objects(submit);
+	if (ret)
+		goto out;
+
+	if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = submit_reloc(submit, stream, args->stream_size / 4,
+			   args->nr_relocs, args->relocs);
+	if (ret)
+		goto out;
+
+	memcpy(cmdbuf->vaddr, stream, args->stream_size);
+	cmdbuf->user_size = ALIGN(args->stream_size, 8);
+	/* transfer ownership of cmdbuf to submit */
+	submit->cmdbuf = cmdbuf;
+	cmdbuf = NULL;
+
+	ret = etnaviv_gpu_submit(gpu, submit, ctx);
+
+	args->fence = submit->fence;
+
+out:
+	if (submit)
+		submit_cleanup(submit, !!ret);
+	mutex_unlock(&dev->struct_mutex);
+
+	etnaviv_gpu_pm_put(gpu);
+
+	/*
+	 * If we're returning -EAGAIN, it could be due to the userptr code
+	 * wanting to run its workqueue outside of the struct_mutex.
+	 * Flush our workqueue to ensure that it is run in a timely manner.
+	 */
+	if (ret == -EAGAIN)
+		flush_workqueue(priv->wq);
+
+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);
+
+	return ret;
+}
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
new file mode 100644
index 000000000000..e12fe3508db2
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -0,0 +1,1468 @@
+/*
+ * 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/component.h>
+#include <linux/of_device.h>
+#include "etnaviv_gpu.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_mmu.h"
+#include "etnaviv_iommu.h"
+#include "etnaviv_iommu_v2.h"
+#include "common.xml.h"
+#include "state.xml.h"
+#include "state_hi.xml.h"
+#include "cmdstream.xml.h"
+
+static const struct platform_device_id gpu_ids[] = {
+	{ .name = "etnaviv-gpu,2d" },
+	{ },
+};
+
+/*
+ * Driver functions:
+ */
+
+int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
+{
+	switch (param) {
+	case ETNAVIV_PARAM_GPU_MODEL:
+		*value = gpu->identity.model;
+		break;
+
+	case ETNAVIV_PARAM_GPU_REVISION:
+		*value = gpu->identity.revision;
+		break;
+
+	case ETNAVIV_PARAM_GPU_FEATURES_0:
+		*value = gpu->identity.features;
+		break;
+
+	case ETNAVIV_PARAM_GPU_FEATURES_1:
+		*value = gpu->identity.minor_features0;
+		break;
+
+	case ETNAVIV_PARAM_GPU_FEATURES_2:
+		*value = gpu->identity.minor_features1;
+		break;
+
+	case ETNAVIV_PARAM_GPU_FEATURES_3:
+		*value = gpu->identity.minor_features2;
+		break;
+
+	case ETNAVIV_PARAM_GPU_FEATURES_4:
+		*value = gpu->identity.minor_features3;
+		break;
+
+	case ETNAVIV_PARAM_GPU_STREAM_COUNT:
+		*value = gpu->identity.stream_count;
+		break;
+
+	case ETNAVIV_PARAM_GPU_REGISTER_MAX:
+		*value = gpu->identity.register_max;
+		break;
+
+	case ETNAVIV_PARAM_GPU_THREAD_COUNT:
+		*value = gpu->identity.thread_count;
+		break;
+
+	case ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE:
+		*value = gpu->identity.vertex_cache_size;
+		break;
+
+	case ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT:
+		*value = gpu->identity.shader_core_count;
+		break;
+
+	case ETNAVIV_PARAM_GPU_PIXEL_PIPES:
+		*value = gpu->identity.pixel_pipes;
+		break;
+
+	case ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE:
+		*value = gpu->identity.vertex_output_buffer_size;
+		break;
+
+	case ETNAVIV_PARAM_GPU_BUFFER_SIZE:
+		*value = gpu->identity.buffer_size;
+		break;
+
+	case ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT:
+		*value = gpu->identity.instruction_count;
+		break;
+
+	case ETNAVIV_PARAM_GPU_NUM_CONSTANTS:
+		*value = gpu->identity.num_constants;
+		break;
+
+	default:
+		DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void etnaviv_hw_specs(struct etnaviv_gpu *gpu)
+{
+	if (gpu->identity.minor_features0 &
+	    chipMinorFeatures0_MORE_MINOR_FEATURES) {
+		u32 specs[2];
+
+		specs[0] = gpu_read(gpu, VIVS_HI_CHIP_SPECS);
+		specs[1] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_2);
+
+		gpu->identity.stream_count =
+			(specs[0] & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
+				>> VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT;
+		gpu->identity.register_max =
+			(specs[0] & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
+				>> VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT;
+		gpu->identity.thread_count =
+			(specs[0] & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
+				>> VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT;
+		gpu->identity.vertex_cache_size =
+			(specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
+				>> VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT;
+		gpu->identity.shader_core_count =
+			(specs[0] & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
+				>> VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT;
+		gpu->identity.pixel_pipes =
+			(specs[0] & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
+				>> VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT;
+		gpu->identity.vertex_output_buffer_size =
+			(specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
+				>> VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT;
+
+		gpu->identity.buffer_size =
+			(specs[1] & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
+				>> VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT;
+		gpu->identity.instruction_count =
+			(specs[1] & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
+				>> VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT;
+		gpu->identity.num_constants =
+			(specs[1] & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
+				>> VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT;
+
+		gpu->identity.register_max = 1 << gpu->identity.register_max;
+		gpu->identity.thread_count = 1 << gpu->identity.thread_count;
+		gpu->identity.vertex_output_buffer_size =
+			1 << gpu->identity.vertex_output_buffer_size;
+	} else {
+		dev_err(gpu->dev, "TODO: determine GPU specs based on model\n");
+	}
+
+	switch (gpu->identity.instruction_count) {
+	case 0:
+		if ((gpu->identity.model == 0x2000 &&
+		     gpu->identity.revision == 0x5108) ||
+		    gpu->identity.model == 0x880)
+			gpu->identity.instruction_count = 512;
+		else
+			gpu->identity.instruction_count = 256;
+		break;
+
+	case 1:
+		gpu->identity.instruction_count = 1024;
+		break;
+
+	case 2:
+		gpu->identity.instruction_count = 2048;
+		break;
+
+	default:
+		gpu->identity.instruction_count = 256;
+		break;
+	}
+}
+
+static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
+{
+	u32 chipIdentity;
+
+	chipIdentity = gpu_read(gpu, VIVS_HI_CHIP_IDENTITY);
+
+	/* Special case for older graphic cores. */
+	if (VIVS_HI_CHIP_IDENTITY_FAMILY(chipIdentity) ==  0x01) {
+		gpu->identity.model    = 0x500; /* gc500 */
+		gpu->identity.revision = VIVS_HI_CHIP_IDENTITY_REVISION(chipIdentity);
+	} else {
+
+		gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL);
+		gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV);
+
+		/*
+		 * !!!! HACK ALERT !!!!
+		 * Because people change device IDs without letting software
+		 * know about it - here is the hack to make it all look the
+		 * same.  Only for GC400 family.
+		 */
+		if ((gpu->identity.model & 0xff00) == 0x0400 &&
+		    gpu->identity.model != 0x0420) {
+			gpu->identity.model = gpu->identity.model & 0x0400;
+		}
+
+		/* Another special case */
+		if (gpu->identity.model == 0x300 &&
+		    gpu->identity.revision == 0x2201) {
+			u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE);
+			u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME);
+
+			if (chipDate == 0x20080814 && chipTime == 0x12051100) {
+				/*
+				 * This IP has an ECO; put the correct
+				 * revision in it.
+				 */
+				gpu->identity.revision = 0x1051;
+			}
+		}
+	}
+
+	dev_info(gpu->dev, "model: GC%x, revision: %x\n",
+		 gpu->identity.model, gpu->identity.revision);
+
+	gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE);
+
+	/* Disable fast clear on GC700. */
+	if (gpu->identity.model == 0x700)
+		gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
+
+	if ((gpu->identity.model == 0x500 && gpu->identity.revision < 2) ||
+	    (gpu->identity.model == 0x300 && gpu->identity.revision < 0x2000)) {
+
+		/*
+		 * GC500 rev 1.x and GC300 rev < 2.0 doesn't have these
+		 * registers.
+		 */
+		gpu->identity.minor_features0 = 0;
+		gpu->identity.minor_features1 = 0;
+		gpu->identity.minor_features2 = 0;
+		gpu->identity.minor_features3 = 0;
+	} else
+		gpu->identity.minor_features0 =
+				gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_0);
+
+	if (gpu->identity.minor_features0 &
+	    chipMinorFeatures0_MORE_MINOR_FEATURES) {
+		gpu->identity.minor_features1 =
+				gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_1);
+		gpu->identity.minor_features2 =
+				gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_2);
+		gpu->identity.minor_features3 =
+				gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3);
+	}
+
+	/* GC600 idle register reports zero bits where modules aren't present */
+	if (gpu->identity.model == chipModel_GC600) {
+		gpu->idle_mask = VIVS_HI_IDLE_STATE_TX |
+				 VIVS_HI_IDLE_STATE_RA |
+				 VIVS_HI_IDLE_STATE_SE |
+				 VIVS_HI_IDLE_STATE_PA |
+				 VIVS_HI_IDLE_STATE_SH |
+				 VIVS_HI_IDLE_STATE_PE |
+				 VIVS_HI_IDLE_STATE_DE |
+				 VIVS_HI_IDLE_STATE_FE;
+	} else {
+		gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP;
+	}
+
+	etnaviv_hw_specs(gpu);
+}
+
+static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock)
+{
+	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock |
+		  VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD);
+	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
+}
+
+static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
+{
+	u32 control, idle;
+	unsigned long timeout;
+	bool failed = true;
+
+	/* TODO
+	 *
+	 * - clock gating
+	 * - puls eater
+	 * - what about VG?
+	 */
+
+	/* We hope that the GPU resets in under one second */
+	timeout = jiffies + msecs_to_jiffies(1000);
+
+	while (time_is_after_jiffies(timeout)) {
+		control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
+			  VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
+
+		/* enable clock */
+		etnaviv_gpu_load_clock(gpu, control);
+
+		/* Wait for stable clock.  Vivante's code waited for 1ms */
+		usleep_range(1000, 10000);
+
+		/* isolate the GPU. */
+		control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
+		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+		/* set soft reset. */
+		control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
+		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+		/* wait for reset. */
+		msleep(1);
+
+		/* reset soft reset bit. */
+		control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
+		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+		/* reset GPU isolation. */
+		control &= ~VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
+		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+		/* read idle register. */
+		idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+		/* try reseting again if FE it not idle */
+		if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) {
+			dev_dbg(gpu->dev, "FE is not idle\n");
+			continue;
+		}
+
+		/* read reset register. */
+		control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
+
+		/* is the GPU idle? */
+		if (((control & VIVS_HI_CLOCK_CONTROL_IDLE_3D) == 0) ||
+		    ((control & VIVS_HI_CLOCK_CONTROL_IDLE_2D) == 0)) {
+			dev_dbg(gpu->dev, "GPU is not idle\n");
+			continue;
+		}
+
+		failed = false;
+		break;
+	}
+
+	if (failed) {
+		idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+		control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
+
+		dev_err(gpu->dev, "GPU failed to reset: FE %sidle, 3D %sidle, 2D %sidle\n",
+			idle & VIVS_HI_IDLE_STATE_FE ? "" : "not ",
+			control & VIVS_HI_CLOCK_CONTROL_IDLE_3D ? "" : "not ",
+			control & VIVS_HI_CLOCK_CONTROL_IDLE_2D ? "" : "not ");
+
+		return -EBUSY;
+	}
+
+	/* We rely on the GPU running, so program the clock */
+	control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
+		  VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
+
+	/* enable clock */
+	etnaviv_gpu_load_clock(gpu, control);
+
+	return 0;
+}
+
+static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
+{
+	u16 prefetch;
+
+	if (gpu->identity.model == chipModel_GC320 &&
+	    gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400 &&
+	    (gpu->identity.revision == 0x5007 ||
+	     gpu->identity.revision == 0x5220)) {
+		u32 mc_memory_debug;
+
+		mc_memory_debug = gpu_read(gpu, VIVS_MC_DEBUG_MEMORY) & ~0xff;
+
+		if (gpu->identity.revision == 0x5007)
+			mc_memory_debug |= 0x0c;
+		else
+			mc_memory_debug |= 0x08;
+
+		gpu_write(gpu, VIVS_MC_DEBUG_MEMORY, mc_memory_debug);
+	}
+
+	/*
+	 * Update GPU AXI cache atttribute to "cacheable, no allocate".
+	 * This is necessary to prevent the iMX6 SoC locking up.
+	 */
+	gpu_write(gpu, VIVS_HI_AXI_CONFIG,
+		  VIVS_HI_AXI_CONFIG_AWCACHE(2) |
+		  VIVS_HI_AXI_CONFIG_ARCACHE(2));
+
+	/* GC2000 rev 5108 needs a special bus config */
+	if (gpu->identity.model == 0x2000 && gpu->identity.revision == 0x5108) {
+		u32 bus_config = gpu_read(gpu, VIVS_MC_BUS_CONFIG);
+		bus_config &= ~(VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK |
+				VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK);
+		bus_config |= VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(1) |
+			      VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(0);
+		gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config);
+	}
+
+	/* set base addresses */
+	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base);
+	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base);
+	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base);
+	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
+	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
+
+	/* setup the MMU page table pointers */
+	etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain);
+
+	/* Start command processor */
+	prefetch = etnaviv_buffer_init(gpu);
+
+	gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
+	gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS,
+		  gpu->buffer->paddr - gpu->memory_base);
+	gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
+		  VIVS_FE_COMMAND_CONTROL_ENABLE |
+		  VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
+}
+
+int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
+{
+	int ret, i;
+	struct iommu_domain *iommu;
+	enum etnaviv_iommu_version version;
+	bool mmuv2;
+
+	ret = pm_runtime_get_sync(gpu->dev);
+	if (ret < 0)
+		return ret;
+
+	etnaviv_hw_identify(gpu);
+
+	if (gpu->identity.model == 0) {
+		dev_err(gpu->dev, "Unknown GPU model\n");
+		pm_runtime_put_autosuspend(gpu->dev);
+		return -ENXIO;
+	}
+
+	ret = etnaviv_hw_reset(gpu);
+	if (ret)
+		goto fail;
+
+	/* Setup IOMMU.. eventually we will (I think) do this once per context
+	 * and have separate page tables per context.  For now, to keep things
+	 * simple and to get something working, just use a single address space:
+	 */
+	mmuv2 = gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION;
+	dev_dbg(gpu->dev, "mmuv2: %d\n", mmuv2);
+
+	if (!mmuv2) {
+		iommu = etnaviv_iommu_domain_alloc(gpu);
+		version = ETNAVIV_IOMMU_V1;
+	} else {
+		iommu = etnaviv_iommu_v2_domain_alloc(gpu);
+		version = ETNAVIV_IOMMU_V2;
+	}
+
+	if (!iommu) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	/* TODO: we will leak here memory - fix it! */
+
+	gpu->mmu = etnaviv_iommu_new(gpu->dev, iommu, version);
+	if (!gpu->mmu) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	/* Create buffer: */
+	gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE);
+	if (!gpu->buffer) {
+		ret = -ENOMEM;
+		dev_err(gpu->dev, "could not create command buffer\n");
+		goto fail;
+	}
+
+	/* Setup event management */
+	spin_lock_init(&gpu->event_spinlock);
+	init_completion(&gpu->event_free);
+	for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
+		gpu->event[i].used = false;
+		complete(&gpu->event_free);
+	}
+
+	/* Now program the hardware */
+	mutex_lock(&gpu->drm->struct_mutex);
+	etnaviv_gpu_hw_init(gpu);
+	mutex_unlock(&gpu->drm->struct_mutex);
+
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
+
+	return 0;
+
+fail:
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
+
+	return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+struct dma_debug {
+	u32 address[2];
+	u32 state[2];
+};
+
+static void verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug)
+{
+	u32 i;
+
+	debug->address[0] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
+	debug->state[0]   = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
+
+	for (i = 0; i < 500; i++) {
+		debug->address[1] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
+		debug->state[1]   = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
+
+		if (debug->address[0] != debug->address[1])
+			break;
+
+		if (debug->state[0] != debug->state[1])
+			break;
+	}
+}
+
+int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
+{
+	struct dma_debug debug;
+	u32 dma_lo, dma_hi, axi, idle;
+	int ret;
+
+	seq_printf(m, "%s Status:\n", dev_name(gpu->dev));
+
+	ret = pm_runtime_get_sync(gpu->dev);
+	if (ret < 0)
+		return ret;
+
+	ret = mutex_lock_interruptible(&gpu->drm->struct_mutex);
+	if (ret < 0)
+		goto err_rpm;
+
+	dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW);
+	dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH);
+	axi = gpu_read(gpu, VIVS_HI_AXI_STATUS);
+	idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+	verify_dma(gpu, &debug);
+
+	seq_puts(m, "\tfeatures\n");
+	seq_printf(m, "\t minor_features0: 0x%08x\n",
+		   gpu->identity.minor_features0);
+	seq_printf(m, "\t minor_features1: 0x%08x\n",
+		   gpu->identity.minor_features1);
+	seq_printf(m, "\t minor_features2: 0x%08x\n",
+		   gpu->identity.minor_features2);
+	seq_printf(m, "\t minor_features3: 0x%08x\n",
+		   gpu->identity.minor_features3);
+
+	seq_puts(m, "\tspecs\n");
+	seq_printf(m, "\t stream_count:  %d\n",
+			gpu->identity.stream_count);
+	seq_printf(m, "\t register_max: %d\n",
+			gpu->identity.register_max);
+	seq_printf(m, "\t thread_count: %d\n",
+			gpu->identity.thread_count);
+	seq_printf(m, "\t vertex_cache_size: %d\n",
+			gpu->identity.vertex_cache_size);
+	seq_printf(m, "\t shader_core_count: %d\n",
+			gpu->identity.shader_core_count);
+	seq_printf(m, "\t pixel_pipes: %d\n",
+			gpu->identity.pixel_pipes);
+	seq_printf(m, "\t vertex_output_buffer_size: %d\n",
+			gpu->identity.vertex_output_buffer_size);
+	seq_printf(m, "\t buffer_size: %d\n",
+			gpu->identity.buffer_size);
+	seq_printf(m, "\t instruction_count: %d\n",
+			gpu->identity.instruction_count);
+	seq_printf(m, "\t num_constants: %d\n",
+			gpu->identity.num_constants);
+
+	seq_printf(m, "\taxi: 0x%08x\n", axi);
+	seq_printf(m, "\tidle: 0x%08x\n", idle);
+	idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP;
+	if ((idle & VIVS_HI_IDLE_STATE_FE) == 0)
+		seq_puts(m, "\t FE is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_DE) == 0)
+		seq_puts(m, "\t DE is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_PE) == 0)
+		seq_puts(m, "\t PE is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_SH) == 0)
+		seq_puts(m, "\t SH is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_PA) == 0)
+		seq_puts(m, "\t PA is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_SE) == 0)
+		seq_puts(m, "\t SE is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_RA) == 0)
+		seq_puts(m, "\t RA is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_TX) == 0)
+		seq_puts(m, "\t TX is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_VG) == 0)
+		seq_puts(m, "\t VG is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_IM) == 0)
+		seq_puts(m, "\t IM is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_FP) == 0)
+		seq_puts(m, "\t FP is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_TS) == 0)
+		seq_puts(m, "\t TS is not idle\n");
+	if (idle & VIVS_HI_IDLE_STATE_AXI_LP)
+		seq_puts(m, "\t AXI low power mode\n");
+
+	if (gpu->identity.features & chipFeatures_DEBUG_MODE) {
+		u32 read0 = gpu_read(gpu, VIVS_MC_DEBUG_READ0);
+		u32 read1 = gpu_read(gpu, VIVS_MC_DEBUG_READ1);
+		u32 write = gpu_read(gpu, VIVS_MC_DEBUG_WRITE);
+
+		seq_puts(m, "\tMC\n");
+		seq_printf(m, "\t read0: 0x%08x\n", read0);
+		seq_printf(m, "\t read1: 0x%08x\n", read1);
+		seq_printf(m, "\t write: 0x%08x\n", write);
+	}
+
+	seq_puts(m, "\tDMA ");
+
+	if (debug.address[0] == debug.address[1] &&
+	    debug.state[0] == debug.state[1]) {
+		seq_puts(m, "seems to be stuck\n");
+	} else if (debug.address[0] == debug.address[1]) {
+		seq_puts(m, "adress is constant\n");
+	} else {
+		seq_puts(m, "is runing\n");
+	}
+
+	seq_printf(m, "\t address 0: 0x%08x\n", debug.address[0]);
+	seq_printf(m, "\t address 1: 0x%08x\n", debug.address[1]);
+	seq_printf(m, "\t state 0: 0x%08x\n", debug.state[0]);
+	seq_printf(m, "\t state 1: 0x%08x\n", debug.state[1]);
+	seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n",
+		   dma_lo, dma_hi);
+
+	ret = 0;
+
+	mutex_unlock(&gpu->drm->struct_mutex);
+
+err_rpm:
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
+
+	return ret;
+}
+#endif
+
+/*
+ * Power Management:
+ */
+static int enable_clk(struct etnaviv_gpu *gpu)
+{
+	if (gpu->clk_core)
+		clk_prepare_enable(gpu->clk_core);
+	if (gpu->clk_shader)
+		clk_prepare_enable(gpu->clk_shader);
+
+	return 0;
+}
+
+static int disable_clk(struct etnaviv_gpu *gpu)
+{
+	if (gpu->clk_core)
+		clk_disable_unprepare(gpu->clk_core);
+	if (gpu->clk_shader)
+		clk_disable_unprepare(gpu->clk_shader);
+
+	return 0;
+}
+
+static int enable_axi(struct etnaviv_gpu *gpu)
+{
+	if (gpu->clk_bus)
+		clk_prepare_enable(gpu->clk_bus);
+
+	return 0;
+}
+
+static int disable_axi(struct etnaviv_gpu *gpu)
+{
+	if (gpu->clk_bus)
+		clk_disable_unprepare(gpu->clk_bus);
+
+	return 0;
+}
+
+/*
+ * Hangcheck detection for locked gpu:
+ */
+static void recover_worker(struct work_struct *work)
+{
+	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
+					       recover_work);
+	struct drm_device *dev = gpu->drm;
+	unsigned long flags;
+	unsigned int i;
+
+	dev_err(gpu->dev, "hangcheck recover!\n");
+
+	if (pm_runtime_get_sync(gpu->dev) < 0)
+		return;
+
+	mutex_lock(&dev->struct_mutex);
+
+	etnaviv_hw_reset(gpu);
+
+	/* complete all events, the GPU won't do it after the reset */
+	spin_lock_irqsave(&gpu->event_spinlock, flags);
+	for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
+		if (!gpu->event[i].used)
+			continue;
+		gpu->event[i].used = false;
+		complete(&gpu->event_free);
+		/*
+		 * Decrement the PM count for each stuck event. This is safe
+		 * even in atomic context as we use ASYNC RPM here.
+		 */
+		pm_runtime_put_autosuspend(gpu->dev);
+	}
+	spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+	gpu->completed_fence = gpu->submitted_fence;
+
+	etnaviv_gpu_hw_init(gpu);
+	gpu->switch_context = true;
+
+	mutex_unlock(&dev->struct_mutex);
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
+
+	/* Retire the buffer objects in a work */
+	etnaviv_queue_work(gpu->drm, &gpu->retire_work);
+}
+
+static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
+{
+	DBG("%s", dev_name(gpu->dev));
+	mod_timer(&gpu->hangcheck_timer,
+		  round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES));
+}
+
+static void hangcheck_handler(unsigned long data)
+{
+	struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
+	u32 fence = gpu->completed_fence;
+	bool progress = false;
+
+	if (fence != gpu->hangcheck_fence) {
+		gpu->hangcheck_fence = fence;
+		progress = true;
+	}
+
+	if (!progress) {
+		u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
+		int change = dma_addr - gpu->hangcheck_dma_addr;
+
+		if (change < 0 || change > 16) {
+			gpu->hangcheck_dma_addr = dma_addr;
+			progress = true;
+		}
+	}
+
+	if (!progress && fence_after(gpu->submitted_fence, fence)) {
+		dev_err(gpu->dev, "hangcheck detected gpu lockup!\n");
+		dev_err(gpu->dev, "     completed fence: %u\n", fence);
+		dev_err(gpu->dev, "     submitted fence: %u\n",
+			gpu->submitted_fence);
+		etnaviv_queue_work(gpu->drm, &gpu->recover_work);
+	}
+
+	/* if still more pending work, reset the hangcheck timer: */
+	if (fence_after(gpu->submitted_fence, gpu->hangcheck_fence))
+		hangcheck_timer_reset(gpu);
+}
+
+static void hangcheck_disable(struct etnaviv_gpu *gpu)
+{
+	del_timer_sync(&gpu->hangcheck_timer);
+	cancel_work_sync(&gpu->recover_work);
+}
+
+/*
+ * event management:
+ */
+
+static unsigned int event_alloc(struct etnaviv_gpu *gpu)
+{
+	unsigned long ret, flags;
+	unsigned int i, event = ~0U;
+
+	ret = wait_for_completion_timeout(&gpu->event_free,
+					  msecs_to_jiffies(10 * 10000));
+	if (!ret)
+		dev_err(gpu->dev, "wait_for_completion_timeout failed");
+
+	spin_lock_irqsave(&gpu->event_spinlock, flags);
+
+	/* find first free event */
+	for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
+		if (gpu->event[i].used == false) {
+			gpu->event[i].used = true;
+			event = i;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+
+	return event;
+}
+
+static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpu->event_spinlock, flags);
+
+	if (gpu->event[event].used == false) {
+		dev_warn(gpu->dev, "event %u is already marked as free",
+			 event);
+		spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+	} else {
+		gpu->event[event].used = false;
+		spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+
+		complete(&gpu->event_free);
+	}
+}
+
+/*
+ * Cmdstream submission/retirement:
+ */
+
+struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size)
+{
+	struct etnaviv_cmdbuf *cmdbuf;
+
+	cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
+	if (!cmdbuf)
+		return NULL;
+
+	cmdbuf->vaddr = dma_alloc_writecombine(gpu->dev, size, &cmdbuf->paddr,
+					       GFP_KERNEL);
+	if (!cmdbuf->vaddr) {
+		kfree(cmdbuf);
+		return NULL;
+	}
+
+	cmdbuf->gpu = gpu;
+	cmdbuf->size = size;
+
+	return cmdbuf;
+}
+
+void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
+{
+	dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
+			      cmdbuf->vaddr, cmdbuf->paddr);
+	kfree(cmdbuf);
+}
+
+static void retire_worker(struct work_struct *work)
+{
+	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
+					       retire_work);
+	struct drm_device *dev = gpu->drm;
+	u32 fence = gpu->completed_fence;
+	struct etnaviv_cmdbuf *cmdbuf, *tmp;
+
+	mutex_lock(&dev->struct_mutex);
+
+	while (!list_empty(&gpu->active_list)) {
+		struct etnaviv_gem_object *obj;
+
+		obj = list_first_entry(&gpu->active_list,
+				struct etnaviv_gem_object, mm_list);
+
+		if ((!(obj->access & ETNA_SUBMIT_BO_READ) ||
+		     fence_after_eq(fence, obj->read_fence)) &&
+		    (!(obj->access & ETNA_SUBMIT_BO_WRITE) ||
+		     fence_after_eq(fence, obj->write_fence))) {
+			/* move to inactive: */
+			etnaviv_gem_move_to_inactive(&obj->base);
+			etnaviv_gem_put_iova(&obj->base);
+			drm_gem_object_unreference(&obj->base);
+		} else {
+			break;
+		}
+	}
+
+	list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list,
+				 gpu_active_list) {
+		if (fence_after_eq(fence, cmdbuf->fence)) {
+			etnaviv_gpu_cmdbuf_free(cmdbuf);
+			list_del(&cmdbuf->gpu_active_list);
+		}
+	}
+
+	gpu->retired_fence = fence;
+
+	mutex_unlock(&dev->struct_mutex);
+
+	wake_up_all(&gpu->fence_event);
+}
+
+static unsigned long etnaviv_timeout_to_jiffies(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;
+}
+
+int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
+	u32 fence, struct timespec *timeout)
+{
+	int ret;
+
+	if (fence_after(fence, gpu->submitted_fence)) {
+		DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
+				fence, gpu->submitted_fence);
+		return -EINVAL;
+	}
+
+	if (!timeout) {
+		/* No timeout was requested: just test for completion */
+		ret = fence_completed(gpu, fence) ? 0 : -EBUSY;
+	} else {
+		unsigned long remaining = etnaviv_timeout_to_jiffies(timeout);
+
+		ret = wait_event_interruptible_timeout(gpu->fence_event,
+						fence_completed(gpu, fence),
+						remaining);
+		if (ret == 0) {
+			DBG("timeout waiting for fence: %u (retired: %u completed: %u)",
+				fence, gpu->retired_fence,
+				gpu->completed_fence);
+			ret = -ETIMEDOUT;
+		} else if (ret != -ERESTARTSYS) {
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Wait for an object to become inactive.  This, on it's own, is not race
+ * free: the object is moved by the retire worker off the active list, and
+ * then the iova is put.  Moreover, the object could be re-submitted just
+ * after we notice that it's become inactive.
+ *
+ * Although the retirement happens under the struct_mutex, we don't want
+ * to hold that lock in this function.  Instead, the caller is responsible
+ * for ensuring that the retire worker has finished (which will happen, eg,
+ * when we unreference the object, an action which takes the struct_mutex.)
+ */
+int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
+	struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout)
+{
+	unsigned long remaining;
+	long ret;
+
+	if (!timeout)
+		return !is_active(etnaviv_obj) ? 0 : -EBUSY;
+
+	remaining = etnaviv_timeout_to_jiffies(timeout);
+
+	ret = wait_event_interruptible_timeout(gpu->fence_event,
+					       !is_active(etnaviv_obj),
+					       remaining);
+	if (ret > 0)
+		return 0;
+	else if (ret == -ERESTARTSYS)
+		return -ERESTARTSYS;
+	else
+		return -ETIMEDOUT;
+}
+
+int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu)
+{
+	return pm_runtime_get_sync(gpu->dev);
+}
+
+void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu)
+{
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
+}
+
+/* add bo's to gpu's ring, and kick gpu: */
+int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
+	struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx)
+{
+	struct drm_device *dev = gpu->drm;
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	unsigned int event, i;
+	int ret;
+
+	ret = pm_runtime_get_sync(gpu->dev);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * TODO
+	 *
+	 * - flush
+	 * - data endian
+	 * - prefetch
+	 *
+	 */
+
+	event = event_alloc(gpu);
+	if (unlikely(event == ~0U)) {
+		DRM_ERROR("no free event\n");
+		pm_runtime_put_autosuspend(gpu->dev);
+		return -EBUSY;
+	}
+
+	submit->fence = ++priv->next_fence;
+
+	gpu->submitted_fence = submit->fence;
+
+	if (gpu->lastctx != ctx) {
+		gpu->mmu->need_flush = true;
+		gpu->switch_context = true;
+		gpu->lastctx = ctx;
+	}
+
+	etnaviv_buffer_queue(gpu, event, submit);
+
+	for (i = 0; i < submit->nr_bos; i++) {
+		struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+		/* can't happen yet.. but when we add 2d support we'll have
+		 * to deal w/ cross-ring synchronization:
+		 */
+		WARN_ON(is_active(etnaviv_obj) && (etnaviv_obj->gpu != gpu));
+
+		if (!is_active(etnaviv_obj)) {
+			u32 iova;
+
+			/* ring takes a reference to the bo and iova: */
+			drm_gem_object_reference(&etnaviv_obj->base);
+			etnaviv_gem_get_iova_locked(gpu, &etnaviv_obj->base,
+						    &iova);
+		}
+
+		if (submit->bos[i].flags & (ETNA_SUBMIT_BO_READ |
+					    ETNA_SUBMIT_BO_WRITE))
+			etnaviv_gem_move_to_active(&etnaviv_obj->base, gpu,
+						   submit->bos[i].flags,
+						   submit->fence);
+	}
+	hangcheck_timer_reset(gpu);
+
+	return 0;
+}
+
+/*
+ * Init/Cleanup:
+ */
+static irqreturn_t irq_handler(int irq, void *data)
+{
+	struct etnaviv_gpu *gpu = data;
+	irqreturn_t ret = IRQ_NONE;
+
+	u32 intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE);
+
+	if (intr != 0) {
+		int event;
+
+		pm_runtime_mark_last_busy(gpu->dev);
+
+		dev_dbg(gpu->dev, "intr 0x%08x\n", intr);
+
+		if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) {
+			dev_err(gpu->dev, "AXI bus error\n");
+			intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR;
+		}
+
+		while ((event = ffs(intr)) != 0) {
+			event -= 1;
+
+			intr &= ~(1 << event);
+
+			dev_dbg(gpu->dev, "event %u\n", event);
+			/*
+			 * Events can be processed out of order.  Eg,
+			 * - allocate and queue event 0
+			 * - allocate event 1
+			 * - event 0 completes, we process it
+			 * - allocate and queue event 0
+			 * - event 1 and event 0 complete
+			 * we can end up processing event 0 first, then 1.
+			 */
+			if (fence_after(gpu->event[event].fence,
+					gpu->completed_fence))
+				gpu->completed_fence = gpu->event[event].fence;
+			event_free(gpu, event);
+
+			/*
+			 * We need to balance the runtime PM count caused by
+			 * each submission.  Upon submission, we increment
+			 * the runtime PM counter, and allocate one event.
+			 * So here, we put the runtime PM count for each
+			 * completed event.
+			 */
+			pm_runtime_put_autosuspend(gpu->dev);
+		}
+
+		/* Retire the buffer objects in a work */
+		etnaviv_queue_work(gpu->drm, &gpu->retire_work);
+
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
+{
+	int ret;
+
+	ret = enable_clk(gpu);
+	if (ret)
+		return ret;
+
+	ret = enable_axi(gpu);
+	if (ret) {
+		disable_clk(gpu);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
+{
+	int ret;
+
+	ret = disable_axi(gpu);
+	if (ret)
+		return ret;
+
+	ret = disable_clk(gpu);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
+{
+	if (gpu->buffer) {
+		unsigned long timeout;
+
+		/* Replace the last WAIT with END */
+		etnaviv_buffer_end(gpu);
+
+		/*
+		 * We know that only the FE is busy here, this should
+		 * happen quickly (as the WAIT is only 200 cycles).  If
+		 * we fail, just warn and continue.
+		 */
+		timeout = jiffies + msecs_to_jiffies(100);
+		do {
+			u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+			if ((idle & gpu->idle_mask) == gpu->idle_mask)
+				break;
+
+			if (time_is_before_jiffies(timeout)) {
+				dev_warn(gpu->dev,
+					 "timed out waiting for idle: idle=0x%x\n",
+					 idle);
+				break;
+			}
+
+			udelay(5);
+		} while (1);
+	}
+
+	return etnaviv_gpu_clk_disable(gpu);
+}
+
+#ifdef CONFIG_PM
+static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
+{
+	struct drm_device *drm = gpu->drm;
+	u32 clock;
+	int ret;
+
+	ret = mutex_lock_killable(&drm->struct_mutex);
+	if (ret)
+		return ret;
+
+	clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
+		VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
+
+	etnaviv_gpu_load_clock(gpu, clock);
+	etnaviv_gpu_hw_init(gpu);
+
+	gpu->switch_context = true;
+
+	mutex_unlock(&drm->struct_mutex);
+
+	return 0;
+}
+#endif
+
+static int etnaviv_gpu_bind(struct device *dev, struct device *master,
+	void *data)
+{
+	struct drm_device *drm = data;
+	struct etnaviv_drm_private *priv = drm->dev_private;
+	struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+	int ret;
+
+#ifdef CONFIG_PM
+	ret = pm_runtime_get_sync(gpu->dev);
+#else
+	ret = etnaviv_gpu_clk_enable(gpu);
+#endif
+	if (ret < 0)
+		return ret;
+
+	gpu->drm = drm;
+
+	INIT_LIST_HEAD(&gpu->active_list);
+	INIT_LIST_HEAD(&gpu->active_cmd_list);
+	INIT_WORK(&gpu->retire_work, retire_worker);
+	INIT_WORK(&gpu->recover_work, recover_worker);
+	init_waitqueue_head(&gpu->fence_event);
+
+	setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
+			(unsigned long)gpu);
+
+	priv->gpu[priv->num_gpus++] = gpu;
+
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
+
+	return 0;
+}
+
+static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
+	void *data)
+{
+	struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+
+	DBG("%s", dev_name(gpu->dev));
+
+	hangcheck_disable(gpu);
+
+	WARN_ON(!list_empty(&gpu->active_list));
+
+#ifdef CONFIG_PM
+	pm_runtime_get_sync(gpu->dev);
+	pm_runtime_put_sync_suspend(gpu->dev);
+#else
+	etnaviv_gpu_hw_suspend(gpu);
+#endif
+
+	if (gpu->buffer) {
+		etnaviv_gpu_cmdbuf_free(gpu->buffer);
+		gpu->buffer = NULL;
+	}
+
+	if (gpu->mmu) {
+		etnaviv_iommu_destroy(gpu->mmu);
+		gpu->mmu = NULL;
+	}
+
+	gpu->drm = NULL;
+}
+
+static const struct component_ops gpu_ops = {
+	.bind = etnaviv_gpu_bind,
+	.unbind = etnaviv_gpu_unbind,
+};
+
+static const struct of_device_id etnaviv_gpu_match[] = {
+	{
+		.compatible = "vivante,gc"
+	},
+	{ /* sentinel */ }
+};
+
+static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct etnaviv_gpu *gpu;
+	int err = 0;
+
+	gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL);
+	if (!gpu)
+		return -ENOMEM;
+
+	gpu->dev = &pdev->dev;
+
+	/*
+	 * Set the GPU base address to the start of physical memory.  This
+	 * ensures that if we have up to 2GB, the v1 MMU can address the
+	 * highest memory.  This is important as command buffers may be
+	 * allocated outside of this limit.
+	 */
+	gpu->memory_base = PHYS_OFFSET;
+
+	/* Map registers: */
+	gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev));
+	if (IS_ERR(gpu->mmio))
+		return PTR_ERR(gpu->mmio);
+
+	/* Get Interrupt: */
+	gpu->irq = platform_get_irq(pdev, 0);
+	if (gpu->irq < 0) {
+		err = gpu->irq;
+		dev_err(dev, "failed to get irq: %d\n", err);
+		goto fail;
+	}
+
+	err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0,
+			       dev_name(gpu->dev), gpu);
+	if (err) {
+		dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err);
+		goto fail;
+	}
+
+	/* Get Clocks: */
+	gpu->clk_bus = devm_clk_get(&pdev->dev, "bus");
+	DBG("clk_bus: %p", gpu->clk_bus);
+	if (IS_ERR(gpu->clk_bus))
+		gpu->clk_bus = NULL;
+
+	gpu->clk_core = devm_clk_get(&pdev->dev, "core");
+	DBG("clk_core: %p", gpu->clk_core);
+	if (IS_ERR(gpu->clk_core))
+		gpu->clk_core = NULL;
+
+	gpu->clk_shader = devm_clk_get(&pdev->dev, "shader");
+	DBG("clk_shader: %p", gpu->clk_shader);
+	if (IS_ERR(gpu->clk_shader))
+		gpu->clk_shader = NULL;
+
+	/* TODO: figure out max mapped size */
+	dev_set_drvdata(dev, gpu);
+
+	/*
+	 * We treat the device as initially suspended.  The runtime PM
+	 * autosuspend delay is rather arbitary: no measurements have
+	 * yet been performed to determine an appropriate value.
+	 */
+	pm_runtime_use_autosuspend(gpu->dev);
+	pm_runtime_set_autosuspend_delay(gpu->dev, 200);
+	pm_runtime_enable(gpu->dev);
+
+	err = component_add(&pdev->dev, &gpu_ops);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to register component: %d\n", err);
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	return err;
+}
+
+static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &gpu_ops);
+	pm_runtime_disable(&pdev->dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int etnaviv_gpu_rpm_suspend(struct device *dev)
+{
+	struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+	u32 idle, mask;
+
+	/* If we have outstanding fences, we're not idle */
+	if (gpu->completed_fence != gpu->submitted_fence)
+		return -EBUSY;
+
+	/* Check whether the hardware (except FE) is idle */
+	mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE;
+	idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask;
+	if (idle != mask)
+		return -EBUSY;
+
+	return etnaviv_gpu_hw_suspend(gpu);
+}
+
+static int etnaviv_gpu_rpm_resume(struct device *dev)
+{
+	struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+	int ret;
+
+	/* We must never runtime-PM resume holding struct_mutex */
+	if (gpu->drm && WARN_ON_ONCE(mutex_is_locked(&gpu->drm->struct_mutex)))
+		return -EDEADLK;
+
+	ret = etnaviv_gpu_clk_enable(gpu);
+	if (ret)
+		return ret;
+
+	/* Re-initialise the basic hardware state */
+	if (gpu->drm && gpu->buffer) {
+		ret = etnaviv_gpu_hw_resume(gpu);
+		if (ret) {
+			etnaviv_gpu_clk_disable(gpu);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
+	SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume,
+			   NULL)
+};
+
+struct platform_driver etnaviv_gpu_driver = {
+	.driver = {
+		.name = "etnaviv-gpu",
+		.owner = THIS_MODULE,
+		.pm = &etnaviv_gpu_pm_ops,
+		.of_match_table = etnaviv_gpu_match,
+	},
+	.probe = etnaviv_gpu_platform_probe,
+	.remove = etnaviv_gpu_platform_remove,
+	.id_table = gpu_ids,
+};
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
new file mode 100644
index 000000000000..3be5b481d8d1
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -0,0 +1,198 @@
+/*
+ * 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;
+	u32 fence;
+};
+
+struct etnaviv_cmdbuf;
+
+struct etnaviv_gpu {
+	struct drm_device *drm;
+	struct device *dev;
+	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 GEM active objects: */
+	struct list_head active_list;
+
+	/* list of currently in-flight command buffers */
+	struct list_head active_cmd_list;
+
+	u32 idle_mask;
+
+	/* Fencing support */
+	u32 submitted_fence;
+	u32 completed_fence;
+	u32 retired_fence;
+	wait_queue_head_t fence_event;
+
+	/* 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;
+	/* cmdbuf properties */
+	void *vaddr;
+	dma_addr_t paddr;
+	u32 size;
+	u32 user_size;
+	/* fence after which this buffer is to be disposed */
+	u32 fence;
+	/* per GPU in-flight list */
+	struct list_head gpu_active_list;
+};
+
+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
+
+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_file_private *ctx);
+struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
+					      u32 size);
+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__ */
diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
new file mode 100644
index 000000000000..9efb7d6092b4
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_iommu.c
@@ -0,0 +1,221 @@
+/*
+ * 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_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_iommu_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_iommu_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 struct iommu_ops etnaviv_iommu_ops = {
+		.domain_free = etnaviv_domain_free,
+		.map = etnaviv_iommu_map,
+		.unmap = etnaviv_iommu_unmap,
+		.iova_to_phys = etnaviv_iommu_iova_to_phys,
+		.pgsize_bitmap = SZ_4K,
+};
+
+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;
+	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;
+}
diff --git a/drivers/staging/etnaviv/etnaviv_iommu.h b/drivers/staging/etnaviv/etnaviv_iommu.h
new file mode 100644
index 000000000000..cf45503f6b6f
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_iommu.h
@@ -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__ */
diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.c b/drivers/staging/etnaviv/etnaviv_iommu_v2.c
new file mode 100644
index 000000000000..fbb4aed3dc80
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.c
@@ -0,0 +1,33 @@
+/*
+ * 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_iommu.h"
+#include "state_hi.xml.h"
+
+
+struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu)
+{
+	/* TODO */
+	return NULL;
+}
diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.h b/drivers/staging/etnaviv/etnaviv_iommu_v2.h
new file mode 100644
index 000000000000..603ea41c5389
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.h
@@ -0,0 +1,25 @@
+/*
+ * 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_V2_H__
+#define __ETNAVIV_IOMMU_V2_H__
+
+#include <linux/iommu.h>
+struct etnaviv_gpu;
+
+struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
+
+#endif /* __ETNAVIV_IOMMU_V2_H__ */
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
new file mode 100644
index 000000000000..ca317f633970
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_mmu.c
@@ -0,0 +1,282 @@
+/*
+ * 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 "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_mmu.h"
+
+static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device *dev,
+		unsigned long iova, int flags, void *arg)
+{
+	DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
+	return 0;
+}
+
+int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
+		struct sg_table *sgt, unsigned len, int prot)
+{
+	struct iommu_domain *domain = iommu->domain;
+	struct scatterlist *sg;
+	unsigned int da = iova;
+	unsigned int i, j;
+	int ret;
+
+	if (!domain || !sgt)
+		return -EINVAL;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		u32 pa = sg_dma_address(sg) - sg->offset;
+		size_t bytes = sg_dma_len(sg) + sg->offset;
+
+		VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
+
+		ret = iommu_map(domain, da, pa, bytes, prot);
+		if (ret)
+			goto fail;
+
+		da += bytes;
+	}
+
+	return 0;
+
+fail:
+	da = iova;
+
+	for_each_sg(sgt->sgl, sg, i, j) {
+		size_t bytes = sg_dma_len(sg) + sg->offset;
+
+		iommu_unmap(domain, da, bytes);
+		da += bytes;
+	}
+	return ret;
+}
+
+int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
+		struct sg_table *sgt, unsigned len)
+{
+	struct iommu_domain *domain = iommu->domain;
+	struct scatterlist *sg;
+	unsigned int da = iova;
+	int i;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		size_t bytes = sg_dma_len(sg) + sg->offset;
+		size_t unmapped;
+
+		unmapped = iommu_unmap(domain, da, bytes);
+		if (unmapped < bytes)
+			return unmapped;
+
+		VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
+
+		BUG_ON(!PAGE_ALIGNED(bytes));
+
+		da += bytes;
+	}
+
+	return 0;
+}
+
+int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
+	struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
+	struct etnaviv_vram_mapping **out_mapping)
+{
+	struct etnaviv_drm_private *priv = etnaviv_obj->base.dev->dev_private;
+	struct sg_table *sgt = etnaviv_obj->sgt;
+	struct etnaviv_vram_mapping *mapping, *free = NULL;
+	struct drm_mm_node *node;
+	int ret;
+
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&mapping->scan_node);
+	mapping->object = etnaviv_obj;
+	mapping->mmu = mmu;
+
+	/* v1 MMU can optimize single entry (contiguous) scatterlists */
+	if (sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
+		u32 iova;
+
+		iova = sg_dma_address(sgt->sgl) - memory_base;
+		if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
+			mapping->iova = iova;
+			list_add_tail(&mapping->obj_node,
+				      &etnaviv_obj->vram_list);
+			if (out_mapping)
+				*out_mapping = mapping;
+			return 0;
+		}
+	}
+
+	node = &mapping->vram_node;
+	while (1) {
+		struct etnaviv_gem_object *o;
+		struct etnaviv_vram_mapping *m, *n;
+		struct list_head list;
+		bool found;
+
+		ret = drm_mm_insert_node_in_range(&mmu->mm, node,
+			etnaviv_obj->base.size, 0, mmu->last_iova, ~0UL,
+			DRM_MM_SEARCH_DEFAULT);
+
+		if (ret != -ENOSPC)
+			break;
+
+		/*
+		 * If we did not search from the start of the MMU region,
+		 * try again in case there are free slots.
+		 */
+		if (mmu->last_iova) {
+			mmu->last_iova = 0;
+			mmu->need_flush = true;
+			continue;
+		}
+
+		/* Try to retire some entries */
+		drm_mm_init_scan(&mmu->mm, etnaviv_obj->base.size, 0, 0);
+
+		found = 0;
+		INIT_LIST_HEAD(&list);
+		list_for_each_entry(o, &priv->inactive_list, mm_list) {
+			free = etnaviv_gem_get_vram_mapping(o, mmu);
+			if (!free)
+				continue;
+
+			/*
+			 * If this vram node has not been used, skip this.
+			 */
+			if (!free->vram_node.mm)
+				continue;
+
+			/*
+			 * If it's on the submit list, then it is part of
+			 * a submission, and we want to keep its entry.
+			 */
+			if (!list_empty(&o->submit_entry))
+				continue;
+
+			list_add(&free->scan_node, &list);
+			if (drm_mm_scan_add_block(&free->vram_node)) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			/* Nothing found, clean up and fail */
+			list_for_each_entry_safe(m, n, &list, scan_node)
+				BUG_ON(drm_mm_scan_remove_block(&m->vram_node));
+			break;
+		}
+
+		/*
+		 * drm_mm does not allow any other operations while
+		 * scanning, so we have to remove all blocks first.
+		 * If drm_mm_scan_remove_block() returns false, we
+		 * can leave the block pinned.
+		 */
+		list_for_each_entry_safe(m, n, &list, scan_node)
+			if (!drm_mm_scan_remove_block(&m->vram_node))
+				list_del_init(&m->scan_node);
+
+		list_for_each_entry_safe(m, n, &list, scan_node) {
+			list_del_init(&m->scan_node);
+			etnaviv_iommu_unmap_gem(m);
+		}
+
+		/*
+		 * We removed enough mappings so that the new allocation will
+		 * succeed.  Ensure that the MMU will be flushed and retry
+		 * the allocation one more time.
+		 */
+		mmu->need_flush = true;
+	}
+
+	if (ret < 0) {
+		kfree(mapping);
+		return ret;
+	}
+
+	mmu->last_iova = node->start + etnaviv_obj->base.size;
+	mapping->iova = node->start;
+	ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size,
+				IOMMU_READ | IOMMU_WRITE);
+
+	if (ret < 0) {
+		drm_mm_remove_node(node);
+		kfree(mapping);
+		return ret;
+	}
+
+	list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);
+	if (out_mapping)
+		*out_mapping = mapping;
+
+	return ret;
+}
+
+void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping)
+{
+	struct etnaviv_iommu *mmu;
+	struct etnaviv_gem_object *etnaviv_obj;
+
+	if (!mapping)
+		return;
+
+	mmu = mapping->mmu;
+
+	/* If the vram node is on the mm, unmap and remove the node */
+	if (mapping->vram_node.mm == &mmu->mm) {
+		etnaviv_obj = mapping->object;
+		etnaviv_iommu_unmap(mmu, mapping->vram_node.start,
+				    etnaviv_obj->sgt, etnaviv_obj->base.size);
+		drm_mm_remove_node(&mapping->vram_node);
+	}
+
+	list_del(&mapping->obj_node);
+	kfree(mapping);
+}
+
+void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
+{
+	drm_mm_takedown(&mmu->mm);
+	iommu_domain_free(mmu->domain);
+	kfree(mmu);
+}
+
+struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev,
+	struct iommu_domain *domain, enum etnaviv_iommu_version version)
+{
+	struct etnaviv_iommu *mmu;
+
+	mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
+	if (!mmu)
+		return ERR_PTR(-ENOMEM);
+
+	mmu->domain = domain;
+	mmu->dev = dev;
+	mmu->version = version;
+
+	drm_mm_init(&mmu->mm, domain->geometry.aperture_start,
+		    domain->geometry.aperture_end -
+		      domain->geometry.aperture_start + 1);
+
+	iommu_set_fault_handler(domain, etnaviv_fault_handler, dev);
+
+	return mmu;
+}
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.h b/drivers/staging/etnaviv/etnaviv_mmu.h
new file mode 100644
index 000000000000..444ef296d2b4
--- /dev/null
+++ b/drivers/staging/etnaviv/etnaviv_mmu.h
@@ -0,0 +1,58 @@
+/*
+ * 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_MMU_H__
+#define __ETNAVIV_MMU_H__
+
+#include <linux/iommu.h>
+
+enum etnaviv_iommu_version {
+	ETNAVIV_IOMMU_V1 = 0,
+	ETNAVIV_IOMMU_V2,
+};
+
+struct etnaviv_vram_mapping;
+
+struct etnaviv_iommu {
+	struct device *dev;
+	struct iommu_domain *domain;
+
+	enum etnaviv_iommu_version version;
+
+	/* memory manager for GPU address area */
+	struct drm_mm mm;
+	u32 last_iova;
+	bool need_flush;
+};
+
+struct etnaviv_gem_object;
+
+int etnaviv_iommu_attach(struct etnaviv_iommu *iommu, const char **names,
+	int cnt);
+int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
+	struct sg_table *sgt, unsigned len, int prot);
+int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
+	struct sg_table *sgt, unsigned len);
+int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
+	struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
+	struct etnaviv_vram_mapping **mapping);
+void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping);
+void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
+
+struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev,
+	struct iommu_domain *domain, enum etnaviv_iommu_version version);
+
+#endif /* __ETNAVIV_MMU_H__ */
diff --git a/drivers/staging/etnaviv/state.xml.h b/drivers/staging/etnaviv/state.xml.h
new file mode 100644
index 000000000000..368218304566
--- /dev/null
+++ b/drivers/staging/etnaviv/state.xml.h
@@ -0,0 +1,351 @@
+#ifndef STATE_XML
+#define STATE_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.xml    (  18882 bytes, from 2015-03-25 11:42:32)
+- common.xml   (  18437 bytes, from 2015-03-25 11:27:41)
+- state_hi.xml (  23420 bytes, from 2015-03-25 11:47:21)
+- state_2d.xml (  51549 bytes, from 2015-03-25 11:25:06)
+- state_3d.xml (  54600 bytes, from 2015-03-25 11:25:19)
+- state_vg.xml (   5973 bytes, from 2015-03-25 11:26:01)
+
+Copyright (C) 2015
+*/
+
+
+#define VARYING_COMPONENT_USE_UNUSED				0x00000000
+#define VARYING_COMPONENT_USE_USED				0x00000001
+#define VARYING_COMPONENT_USE_POINTCOORD_X			0x00000002
+#define VARYING_COMPONENT_USE_POINTCOORD_Y			0x00000003
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK		0x000000ff
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT		0
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x)		(((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK)
+#define VIVS_FE							0x00000000
+
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0)		       (0x00000600 + 0x4*(i0))
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE			0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN			0x00000010
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK		0x0000000f
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT		0
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE			0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE	0x00000001
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT		0x00000002
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT	0x00000003
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT			0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT		0x00000005
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT		0x00000008
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT		0x00000009
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED		0x0000000b
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2	0x0000000c
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2	0x0000000d
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK		0x00000030
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT		4
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE		0x00000080
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK		0x00000700
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT		8
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK			0x00003000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT		12
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK		0x0000c000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT		14
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF		0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON		0x00008000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK		0x00ff0000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT		16
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK			0xff000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT		24
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK)
+
+#define VIVS_FE_CMD_STREAM_BASE_ADDR				0x00000640
+
+#define VIVS_FE_INDEX_STREAM_BASE_ADDR				0x00000644
+
+#define VIVS_FE_INDEX_STREAM_CONTROL				0x00000648
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK			0x00000003
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT		0
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR		0x00000000
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT	0x00000001
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT		0x00000002
+
+#define VIVS_FE_VERTEX_STREAM_BASE_ADDR				0x0000064c
+
+#define VIVS_FE_VERTEX_STREAM_CONTROL				0x00000650
+
+#define VIVS_FE_COMMAND_ADDRESS					0x00000654
+
+#define VIVS_FE_COMMAND_CONTROL					0x00000658
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK			0x0000ffff
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT			0
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x)			(((x) << VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK)
+#define VIVS_FE_COMMAND_CONTROL_ENABLE				0x00010000
+
+#define VIVS_FE_DMA_STATUS					0x0000065c
+
+#define VIVS_FE_DMA_DEBUG_STATE					0x00000660
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK			0x0000001f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT		0
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE			0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC			0x00000001
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0			0x00000002
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0			0x00000003
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1			0x00000004
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1			0x00000005
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR			0x00000006
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD			0x00000007
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL		0x00000008
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL		0x00000009
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA		0x0000000a
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX		0x0000000b
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW			0x0000000c
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0		0x0000000d
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1		0x0000000e
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0		0x0000000f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1		0x00000010
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO		0x00000011
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT			0x00000012
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK			0x00000013
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END			0x00000014
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL			0x00000015
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK		0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT		8
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START		0x00000100
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ		0x00000200
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END		0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK		0x00000c00
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT		10
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID	0x00000400
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID		0x00000800
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK		0x00003000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT		12
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX		0x00001000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL		0x00002000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK			0x0000c000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT		14
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE			0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR			0x00004000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC		0x00008000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK		0x00030000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT		16
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE		0x00010000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS		0x00020000
+
+#define VIVS_FE_DMA_ADDRESS					0x00000664
+
+#define VIVS_FE_DMA_LOW						0x00000668
+
+#define VIVS_FE_DMA_HIGH					0x0000066c
+
+#define VIVS_FE_AUTO_FLUSH					0x00000670
+
+#define VIVS_FE_UNK00678					0x00000678
+
+#define VIVS_FE_UNK0067C					0x0000067c
+
+#define VIVS_FE_VERTEX_STREAMS(i0)			       (0x00000000 + 0x4*(i0))
+#define VIVS_FE_VERTEX_STREAMS__ESIZE				0x00000004
+#define VIVS_FE_VERTEX_STREAMS__LEN				0x00000008
+
+#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0)		       (0x00000680 + 0x4*(i0))
+
+#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0)		       (0x000006a0 + 0x4*(i0))
+
+#define VIVS_FE_UNK00700(i0)				       (0x00000700 + 0x4*(i0))
+#define VIVS_FE_UNK00700__ESIZE					0x00000004
+#define VIVS_FE_UNK00700__LEN					0x00000010
+
+#define VIVS_FE_UNK00740(i0)				       (0x00000740 + 0x4*(i0))
+#define VIVS_FE_UNK00740__ESIZE					0x00000004
+#define VIVS_FE_UNK00740__LEN					0x00000010
+
+#define VIVS_FE_UNK00780(i0)				       (0x00000780 + 0x4*(i0))
+#define VIVS_FE_UNK00780__ESIZE					0x00000004
+#define VIVS_FE_UNK00780__LEN					0x00000010
+
+#define VIVS_GL							0x00000000
+
+#define VIVS_GL_PIPE_SELECT					0x00003800
+#define VIVS_GL_PIPE_SELECT_PIPE__MASK				0x00000001
+#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT				0
+#define VIVS_GL_PIPE_SELECT_PIPE(x)				(((x) << VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK)
+
+#define VIVS_GL_EVENT						0x00003804
+#define VIVS_GL_EVENT_EVENT_ID__MASK				0x0000001f
+#define VIVS_GL_EVENT_EVENT_ID__SHIFT				0
+#define VIVS_GL_EVENT_EVENT_ID(x)				(((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK)
+#define VIVS_GL_EVENT_FROM_FE					0x00000020
+#define VIVS_GL_EVENT_FROM_PE					0x00000040
+#define VIVS_GL_EVENT_SOURCE__MASK				0x00001f00
+#define VIVS_GL_EVENT_SOURCE__SHIFT				8
+#define VIVS_GL_EVENT_SOURCE(x)					(((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK)
+
+#define VIVS_GL_SEMAPHORE_TOKEN					0x00003808
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK			0x0000001f
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT			0
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x)				(((x) << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK)
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK			0x00001f00
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT			8
+#define VIVS_GL_SEMAPHORE_TOKEN_TO(x)				(((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK)
+
+#define VIVS_GL_FLUSH_CACHE					0x0000380c
+#define VIVS_GL_FLUSH_CACHE_DEPTH				0x00000001
+#define VIVS_GL_FLUSH_CACHE_COLOR				0x00000002
+#define VIVS_GL_FLUSH_CACHE_TEXTURE				0x00000004
+#define VIVS_GL_FLUSH_CACHE_PE2D				0x00000008
+#define VIVS_GL_FLUSH_CACHE_TEXTUREVS				0x00000010
+#define VIVS_GL_FLUSH_CACHE_SHADER_L1				0x00000020
+#define VIVS_GL_FLUSH_CACHE_SHADER_L2				0x00000040
+
+#define VIVS_GL_FLUSH_MMU					0x00003810
+#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU				0x00000001
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1				0x00000002
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2				0x00000004
+#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU				0x00000008
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4				0x00000010
+
+#define VIVS_GL_VERTEX_ELEMENT_CONFIG				0x00003814
+
+#define VIVS_GL_MULTI_SAMPLE_CONFIG				0x00003818
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK		0x00000003
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT		0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE		0x00000000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X		0x00000001
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X		0x00000002
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK		0x00000008
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK		0x000000f0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT		4
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x)		(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK		0x00000100
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK			0x00007000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT		12
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x)			(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK			0x00008000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK			0x00030000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT		16
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x)			(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK			0x00080000
+
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS			0x0000381c
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK		0x000000ff
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT		0
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x)			(((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK)
+
+#define VIVS_GL_VARYING_NUM_COMPONENTS				0x00003820
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK		0x00000007
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT		0
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK		0x00000070
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT		4
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK		0x00000700
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT		8
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK		0x00007000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT		12
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK		0x00070000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT		16
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK		0x00700000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT		20
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK		0x07000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT		24
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK		0x70000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT		28
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK)
+
+#define VIVS_GL_VARYING_COMPONENT_USE(i0)		       (0x00003828 + 0x4*(i0))
+#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE			0x00000004
+#define VIVS_GL_VARYING_COMPONENT_USE__LEN			0x00000002
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK		0x00000003
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT		0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK		0x0000000c
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT		2
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK		0x00000030
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT		4
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK		0x000000c0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT		6
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK		0x00000300
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT		8
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK		0x00000c00
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT		10
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK		0x00003000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT		12
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK		0x0000c000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT		14
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK		0x00030000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT		16
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK		0x000c0000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT		18
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK		0x00300000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT		20
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK		0x00c00000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT		22
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK		0x03000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT		24
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK		0x0c000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT		26
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK		0x30000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT		28
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK		0xc0000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT		30
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK)
+
+#define VIVS_GL_UNK03834					0x00003834
+
+#define VIVS_GL_UNK03838					0x00003838
+
+#define VIVS_GL_API_MODE					0x0000384c
+#define VIVS_GL_API_MODE_OPENGL					0x00000000
+#define VIVS_GL_API_MODE_OPENVG					0x00000001
+#define VIVS_GL_API_MODE_OPENCL					0x00000002
+
+#define VIVS_GL_CONTEXT_POINTER					0x00003850
+
+#define VIVS_GL_UNK03A00					0x00003a00
+
+#define VIVS_GL_STALL_TOKEN					0x00003c00
+#define VIVS_GL_STALL_TOKEN_FROM__MASK				0x0000001f
+#define VIVS_GL_STALL_TOKEN_FROM__SHIFT				0
+#define VIVS_GL_STALL_TOKEN_FROM(x)				(((x) << VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK)
+#define VIVS_GL_STALL_TOKEN_TO__MASK				0x00001f00
+#define VIVS_GL_STALL_TOKEN_TO__SHIFT				8
+#define VIVS_GL_STALL_TOKEN_TO(x)				(((x) << VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK)
+#define VIVS_GL_STALL_TOKEN_FLIP0				0x40000000
+#define VIVS_GL_STALL_TOKEN_FLIP1				0x80000000
+
+#define VIVS_DUMMY						0x00000000
+
+#define VIVS_DUMMY_DUMMY					0x0003fffc
+
+
+#endif /* STATE_XML */
diff --git a/drivers/staging/etnaviv/state_hi.xml.h b/drivers/staging/etnaviv/state_hi.xml.h
new file mode 100644
index 000000000000..0064f2640396
--- /dev/null
+++ b/drivers/staging/etnaviv/state_hi.xml.h
@@ -0,0 +1,407 @@
+#ifndef STATE_HI_XML
+#define STATE_HI_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_hi.xml (  23420 bytes, from 2015-03-25 11:47:21)
+- common.xml   (  18437 bytes, from 2015-03-25 11:27:41)
+
+Copyright (C) 2015
+*/
+
+
+#define MMU_EXCEPTION_SLAVE_NOT_PRESENT				0x00000001
+#define MMU_EXCEPTION_PAGE_NOT_PRESENT				0x00000002
+#define MMU_EXCEPTION_WRITE_VIOLATION				0x00000003
+#define VIVS_HI							0x00000000
+
+#define VIVS_HI_CLOCK_CONTROL					0x00000000
+#define VIVS_HI_CLOCK_CONTROL_CLK3D_DIS				0x00000001
+#define VIVS_HI_CLOCK_CONTROL_CLK2D_DIS				0x00000002
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK			0x000001fc
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT			2
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(x)			(((x) << VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT) & VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK)
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD			0x00000200
+#define VIVS_HI_CLOCK_CONTROL_DISABLE_RAM_CLK_GATING		0x00000400
+#define VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS		0x00000800
+#define VIVS_HI_CLOCK_CONTROL_SOFT_RESET			0x00001000
+#define VIVS_HI_CLOCK_CONTROL_IDLE_3D				0x00010000
+#define VIVS_HI_CLOCK_CONTROL_IDLE_2D				0x00020000
+#define VIVS_HI_CLOCK_CONTROL_IDLE_VG				0x00040000
+#define VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU			0x00080000
+#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK		0x00f00000
+#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT		20
+#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(x)		(((x) << VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT) & VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK)
+
+#define VIVS_HI_IDLE_STATE					0x00000004
+#define VIVS_HI_IDLE_STATE_FE					0x00000001
+#define VIVS_HI_IDLE_STATE_DE					0x00000002
+#define VIVS_HI_IDLE_STATE_PE					0x00000004
+#define VIVS_HI_IDLE_STATE_SH					0x00000008
+#define VIVS_HI_IDLE_STATE_PA					0x00000010
+#define VIVS_HI_IDLE_STATE_SE					0x00000020
+#define VIVS_HI_IDLE_STATE_RA					0x00000040
+#define VIVS_HI_IDLE_STATE_TX					0x00000080
+#define VIVS_HI_IDLE_STATE_VG					0x00000100
+#define VIVS_HI_IDLE_STATE_IM					0x00000200
+#define VIVS_HI_IDLE_STATE_FP					0x00000400
+#define VIVS_HI_IDLE_STATE_TS					0x00000800
+#define VIVS_HI_IDLE_STATE_AXI_LP				0x80000000
+
+#define VIVS_HI_AXI_CONFIG					0x00000008
+#define VIVS_HI_AXI_CONFIG_AWID__MASK				0x0000000f
+#define VIVS_HI_AXI_CONFIG_AWID__SHIFT				0
+#define VIVS_HI_AXI_CONFIG_AWID(x)				(((x) << VIVS_HI_AXI_CONFIG_AWID__SHIFT) & VIVS_HI_AXI_CONFIG_AWID__MASK)
+#define VIVS_HI_AXI_CONFIG_ARID__MASK				0x000000f0
+#define VIVS_HI_AXI_CONFIG_ARID__SHIFT				4
+#define VIVS_HI_AXI_CONFIG_ARID(x)				(((x) << VIVS_HI_AXI_CONFIG_ARID__SHIFT) & VIVS_HI_AXI_CONFIG_ARID__MASK)
+#define VIVS_HI_AXI_CONFIG_AWCACHE__MASK			0x00000f00
+#define VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT			8
+#define VIVS_HI_AXI_CONFIG_AWCACHE(x)				(((x) << VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_AWCACHE__MASK)
+#define VIVS_HI_AXI_CONFIG_ARCACHE__MASK			0x0000f000
+#define VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT			12
+#define VIVS_HI_AXI_CONFIG_ARCACHE(x)				(((x) << VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_ARCACHE__MASK)
+
+#define VIVS_HI_AXI_STATUS					0x0000000c
+#define VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK			0x0000000f
+#define VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT			0
+#define VIVS_HI_AXI_STATUS_WR_ERR_ID(x)				(((x) << VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK)
+#define VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK			0x000000f0
+#define VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT			4
+#define VIVS_HI_AXI_STATUS_RD_ERR_ID(x)				(((x) << VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK)
+#define VIVS_HI_AXI_STATUS_DET_WR_ERR				0x00000100
+#define VIVS_HI_AXI_STATUS_DET_RD_ERR				0x00000200
+
+#define VIVS_HI_INTR_ACKNOWLEDGE				0x00000010
+#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK			0x7fffffff
+#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT		0
+#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC(x)			(((x) << VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT) & VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK)
+#define VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR			0x80000000
+
+#define VIVS_HI_INTR_ENBL					0x00000014
+#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK			0xffffffff
+#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT			0
+#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC(x)			(((x) << VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT) & VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK)
+
+#define VIVS_HI_CHIP_IDENTITY					0x00000018
+#define VIVS_HI_CHIP_IDENTITY_FAMILY__MASK			0xff000000
+#define VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT			24
+#define VIVS_HI_CHIP_IDENTITY_FAMILY(x)				(((x) << VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT) & VIVS_HI_CHIP_IDENTITY_FAMILY__MASK)
+#define VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK			0x00ff0000
+#define VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT			16
+#define VIVS_HI_CHIP_IDENTITY_PRODUCT(x)			(((x) << VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT) & VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK)
+#define VIVS_HI_CHIP_IDENTITY_REVISION__MASK			0x0000f000
+#define VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT			12
+#define VIVS_HI_CHIP_IDENTITY_REVISION(x)			(((x) << VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT) & VIVS_HI_CHIP_IDENTITY_REVISION__MASK)
+
+#define VIVS_HI_CHIP_FEATURE					0x0000001c
+
+#define VIVS_HI_CHIP_MODEL					0x00000020
+
+#define VIVS_HI_CHIP_REV					0x00000024
+
+#define VIVS_HI_CHIP_DATE					0x00000028
+
+#define VIVS_HI_CHIP_TIME					0x0000002c
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_0				0x00000034
+
+#define VIVS_HI_CACHE_CONTROL					0x00000038
+
+#define VIVS_HI_MEMORY_COUNTER_RESET				0x0000003c
+
+#define VIVS_HI_PROFILE_READ_BYTES8				0x00000040
+
+#define VIVS_HI_PROFILE_WRITE_BYTES8				0x00000044
+
+#define VIVS_HI_CHIP_SPECS					0x00000048
+#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK			0x0000000f
+#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT			0
+#define VIVS_HI_CHIP_SPECS_STREAM_COUNT(x)			(((x) << VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK			0x000000f0
+#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT			4
+#define VIVS_HI_CHIP_SPECS_REGISTER_MAX(x)			(((x) << VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT) & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
+#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK			0x00000f00
+#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT			8
+#define VIVS_HI_CHIP_SPECS_THREAD_COUNT(x)			(((x) << VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK		0x0001f000
+#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT		12
+#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE(x)			(((x) << VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
+#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK		0x01f00000
+#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT		20
+#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT(x)			(((x) << VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK			0x0e000000
+#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT			25
+#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES(x)			(((x) << VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT) & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
+#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK	0xf0000000
+#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT	28
+#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE(x)		(((x) << VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
+
+#define VIVS_HI_PROFILE_WRITE_BURSTS				0x0000004c
+
+#define VIVS_HI_PROFILE_WRITE_REQUESTS				0x00000050
+
+#define VIVS_HI_PROFILE_READ_BURSTS				0x00000058
+
+#define VIVS_HI_PROFILE_READ_REQUESTS				0x0000005c
+
+#define VIVS_HI_PROFILE_READ_LASTS				0x00000060
+
+#define VIVS_HI_GP_OUT0						0x00000064
+
+#define VIVS_HI_GP_OUT1						0x00000068
+
+#define VIVS_HI_GP_OUT2						0x0000006c
+
+#define VIVS_HI_AXI_CONTROL					0x00000070
+#define VIVS_HI_AXI_CONTROL_WR_FULL_BURST_MODE			0x00000001
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_1				0x00000074
+
+#define VIVS_HI_PROFILE_TOTAL_CYCLES				0x00000078
+
+#define VIVS_HI_PROFILE_IDLE_CYCLES				0x0000007c
+
+#define VIVS_HI_CHIP_SPECS_2					0x00000080
+#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK			0x000000ff
+#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT			0
+#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE(x)			(((x) << VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
+#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK		0x0000ff00
+#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT		8
+#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT(x)		(((x) << VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK		0xffff0000
+#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT		16
+#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS(x)			(((x) << VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT) & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_2				0x00000084
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_3				0x00000088
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_4				0x00000094
+
+#define VIVS_PM							0x00000000
+
+#define VIVS_PM_POWER_CONTROLS					0x00000100
+#define VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING	0x00000001
+#define VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING	0x00000002
+#define VIVS_PM_POWER_CONTROLS_DISABLE_STARVE_MODULE_CLOCK_GATING	0x00000004
+#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK		0x000000f0
+#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT		4
+#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER(x)		(((x) << VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK)
+#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK		0xffff0000
+#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT		16
+#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER(x)		(((x) << VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK)
+
+#define VIVS_PM_MODULE_CONTROLS					0x00000104
+#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_FE	0x00000001
+#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_DE	0x00000002
+#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_PE	0x00000004
+
+#define VIVS_PM_MODULE_STATUS					0x00000108
+#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_FE		0x00000001
+#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_DE		0x00000002
+#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_PE		0x00000004
+
+#define VIVS_PM_PULSE_EATER					0x0000010c
+
+#define VIVS_MMUv2						0x00000000
+
+#define VIVS_MMUv2_SAFE_ADDRESS					0x00000180
+
+#define VIVS_MMUv2_CONFIGURATION				0x00000184
+#define VIVS_MMUv2_CONFIGURATION_MODE__MASK			0x00000001
+#define VIVS_MMUv2_CONFIGURATION_MODE__SHIFT			0
+#define VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K			0x00000000
+#define VIVS_MMUv2_CONFIGURATION_MODE_MODE1_K			0x00000001
+#define VIVS_MMUv2_CONFIGURATION_MODE_MASK			0x00000008
+#define VIVS_MMUv2_CONFIGURATION_FLUSH__MASK			0x00000010
+#define VIVS_MMUv2_CONFIGURATION_FLUSH__SHIFT			4
+#define VIVS_MMUv2_CONFIGURATION_FLUSH_FLUSH			0x00000010
+#define VIVS_MMUv2_CONFIGURATION_FLUSH_MASK			0x00000080
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS_MASK			0x00000100
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK			0xfffffc00
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT			10
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS(x)			(((x) << VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT) & VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK)
+
+#define VIVS_MMUv2_STATUS					0x00000188
+#define VIVS_MMUv2_STATUS_EXCEPTION0__MASK			0x00000003
+#define VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT			0
+#define VIVS_MMUv2_STATUS_EXCEPTION0(x)				(((x) << VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK)
+#define VIVS_MMUv2_STATUS_EXCEPTION1__MASK			0x00000030
+#define VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT			4
+#define VIVS_MMUv2_STATUS_EXCEPTION1(x)				(((x) << VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION1__MASK)
+#define VIVS_MMUv2_STATUS_EXCEPTION2__MASK			0x00000300
+#define VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT			8
+#define VIVS_MMUv2_STATUS_EXCEPTION2(x)				(((x) << VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION2__MASK)
+#define VIVS_MMUv2_STATUS_EXCEPTION3__MASK			0x00003000
+#define VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT			12
+#define VIVS_MMUv2_STATUS_EXCEPTION3(x)				(((x) << VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION3__MASK)
+
+#define VIVS_MMUv2_CONTROL					0x0000018c
+#define VIVS_MMUv2_CONTROL_ENABLE				0x00000001
+
+#define VIVS_MMUv2_EXCEPTION_ADDR(i0)			       (0x00000190 + 0x4*(i0))
+#define VIVS_MMUv2_EXCEPTION_ADDR__ESIZE			0x00000004
+#define VIVS_MMUv2_EXCEPTION_ADDR__LEN				0x00000004
+
+#define VIVS_MC							0x00000000
+
+#define VIVS_MC_MMU_FE_PAGE_TABLE				0x00000400
+
+#define VIVS_MC_MMU_TX_PAGE_TABLE				0x00000404
+
+#define VIVS_MC_MMU_PE_PAGE_TABLE				0x00000408
+
+#define VIVS_MC_MMU_PEZ_PAGE_TABLE				0x0000040c
+
+#define VIVS_MC_MMU_RA_PAGE_TABLE				0x00000410
+
+#define VIVS_MC_DEBUG_MEMORY					0x00000414
+#define VIVS_MC_DEBUG_MEMORY_SPECIAL_PATCH_GC320		0x00000008
+#define VIVS_MC_DEBUG_MEMORY_FAST_CLEAR_BYPASS			0x00100000
+#define VIVS_MC_DEBUG_MEMORY_COMPRESSION_BYPASS			0x00200000
+
+#define VIVS_MC_MEMORY_BASE_ADDR_RA				0x00000418
+
+#define VIVS_MC_MEMORY_BASE_ADDR_FE				0x0000041c
+
+#define VIVS_MC_MEMORY_BASE_ADDR_TX				0x00000420
+
+#define VIVS_MC_MEMORY_BASE_ADDR_PEZ				0x00000424
+
+#define VIVS_MC_MEMORY_BASE_ADDR_PE				0x00000428
+
+#define VIVS_MC_MEMORY_TIMING_CONTROL				0x0000042c
+
+#define VIVS_MC_MEMORY_FLUSH					0x00000430
+
+#define VIVS_MC_PROFILE_CYCLE_COUNTER				0x00000438
+
+#define VIVS_MC_DEBUG_READ0					0x0000043c
+
+#define VIVS_MC_DEBUG_READ1					0x00000440
+
+#define VIVS_MC_DEBUG_WRITE					0x00000444
+
+#define VIVS_MC_PROFILE_RA_READ					0x00000448
+
+#define VIVS_MC_PROFILE_TX_READ					0x0000044c
+
+#define VIVS_MC_PROFILE_FE_READ					0x00000450
+
+#define VIVS_MC_PROFILE_PE_READ					0x00000454
+
+#define VIVS_MC_PROFILE_DE_READ					0x00000458
+
+#define VIVS_MC_PROFILE_SH_READ					0x0000045c
+
+#define VIVS_MC_PROFILE_PA_READ					0x00000460
+
+#define VIVS_MC_PROFILE_SE_READ					0x00000464
+
+#define VIVS_MC_PROFILE_MC_READ					0x00000468
+
+#define VIVS_MC_PROFILE_HI_READ					0x0000046c
+
+#define VIVS_MC_PROFILE_CONFIG0					0x00000470
+#define VIVS_MC_PROFILE_CONFIG0_FE__MASK			0x0000000f
+#define VIVS_MC_PROFILE_CONFIG0_FE__SHIFT			0
+#define VIVS_MC_PROFILE_CONFIG0_FE_RESET			0x0000000f
+#define VIVS_MC_PROFILE_CONFIG0_DE__MASK			0x00000f00
+#define VIVS_MC_PROFILE_CONFIG0_DE__SHIFT			8
+#define VIVS_MC_PROFILE_CONFIG0_DE_RESET			0x00000f00
+#define VIVS_MC_PROFILE_CONFIG0_PE__MASK			0x000f0000
+#define VIVS_MC_PROFILE_CONFIG0_PE__SHIFT			16
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE	0x00000000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE	0x00010000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE	0x00020000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE	0x00030000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D		0x000b0000
+#define VIVS_MC_PROFILE_CONFIG0_PE_RESET			0x000f0000
+#define VIVS_MC_PROFILE_CONFIG0_SH__MASK			0x0f000000
+#define VIVS_MC_PROFILE_CONFIG0_SH__SHIFT			24
+#define VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES		0x04000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER		0x07000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER	0x08000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER		0x09000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER	0x0a000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER	0x0b000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER	0x0c000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER	0x0d000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER	0x0e000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_RESET			0x0f000000
+
+#define VIVS_MC_PROFILE_CONFIG1					0x00000474
+#define VIVS_MC_PROFILE_CONFIG1_PA__MASK			0x0000000f
+#define VIVS_MC_PROFILE_CONFIG1_PA__SHIFT			0
+#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER		0x00000003
+#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER		0x00000004
+#define VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER		0x00000005
+#define VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER	0x00000006
+#define VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER	0x00000007
+#define VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER		0x00000008
+#define VIVS_MC_PROFILE_CONFIG1_PA_RESET			0x0000000f
+#define VIVS_MC_PROFILE_CONFIG1_SE__MASK			0x00000f00
+#define VIVS_MC_PROFILE_CONFIG1_SE__SHIFT			8
+#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT	0x00000000
+#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT		0x00000100
+#define VIVS_MC_PROFILE_CONFIG1_SE_RESET			0x00000f00
+#define VIVS_MC_PROFILE_CONFIG1_RA__MASK			0x000f0000
+#define VIVS_MC_PROFILE_CONFIG1_RA__SHIFT			16
+#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT		0x00000000
+#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT		0x00010000
+#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z	0x00020000
+#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT	0x00030000
+#define VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER	0x00090000
+#define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER	0x000a0000
+#define VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT		0x000b0000
+#define VIVS_MC_PROFILE_CONFIG1_RA_RESET			0x000f0000
+#define VIVS_MC_PROFILE_CONFIG1_TX__MASK			0x0f000000
+#define VIVS_MC_PROFILE_CONFIG1_TX__SHIFT			24
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS	0x00000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS	0x01000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS	0x02000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS	0x03000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_UNKNOWN			0x04000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT		0x05000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT		0x06000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT		0x07000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT	0x08000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT	0x09000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_RESET			0x0f000000
+
+#define VIVS_MC_PROFILE_CONFIG2					0x00000478
+#define VIVS_MC_PROFILE_CONFIG2_MC__MASK			0x0000000f
+#define VIVS_MC_PROFILE_CONFIG2_MC__SHIFT			0
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE	0x00000001
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP	0x00000002
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE	0x00000003
+#define VIVS_MC_PROFILE_CONFIG2_MC_RESET			0x0000000f
+#define VIVS_MC_PROFILE_CONFIG2_HI__MASK			0x00000f00
+#define VIVS_MC_PROFILE_CONFIG2_HI__SHIFT			8
+#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED	0x00000000
+#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED	0x00000100
+#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED	0x00000200
+#define VIVS_MC_PROFILE_CONFIG2_HI_RESET			0x00000f00
+
+#define VIVS_MC_PROFILE_CONFIG3					0x0000047c
+
+#define VIVS_MC_BUS_CONFIG					0x00000480
+#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK			0x0000000f
+#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT			0
+#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(x)			(((x) << VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK)
+#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK			0x000000f0
+#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT			4
+#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(x)			(((x) << VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK)
+
+#define VIVS_MC_START_COMPOSITION				0x00000554
+
+#define VIVS_MC_128B_MERGE					0x00000558
+
+
+#endif /* STATE_HI_XML */
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
new file mode 100644
index 000000000000..5f1206b3f9ba
--- /dev/null
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -0,0 +1,215 @@
+/*
+ * 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_DRM_H__
+#define __ETNAVIV_DRM_H__
+
+#include <drm/drm.h>
+
+/* Please note that modifications to all structs defined here are
+ * subject to backwards-compatibility constraints:
+ *  1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
+ *     user/kernel compatibility
+ *  2) Keep fields aligned to their size
+ *  3) Because of how drm_ioctl() works, we can add new fields at
+ *     the end of an ioctl if some care is taken: drm_ioctl() will
+ *     zero out the new fields at the tail of the ioctl, so a zero
+ *     value should have a backwards compatible meaning.  And for
+ *     output params, userspace won't see the newly added output
+ *     fields.. so that has to be somehow ok.
+ */
+
+/* timeouts are specified in clock-monotonic absolute times (to simplify
+ * restarting interrupted ioctls).  The following struct is logically the
+ * same as 'struct timespec' but 32/64b ABI safe.
+ */
+struct drm_etnaviv_timespec {
+	__s64 tv_sec;          /* seconds */
+	__s64 tv_nsec;         /* nanoseconds */
+};
+
+#define ETNAVIV_PARAM_GPU_MODEL                     0x01
+#define ETNAVIV_PARAM_GPU_REVISION                  0x02
+#define ETNAVIV_PARAM_GPU_FEATURES_0                0x03
+#define ETNAVIV_PARAM_GPU_FEATURES_1                0x04
+#define ETNAVIV_PARAM_GPU_FEATURES_2                0x05
+#define ETNAVIV_PARAM_GPU_FEATURES_3                0x06
+#define ETNAVIV_PARAM_GPU_FEATURES_4                0x07
+
+#define ETNAVIV_PARAM_GPU_STREAM_COUNT              0x10
+#define ETNAVIV_PARAM_GPU_REGISTER_MAX              0x11
+#define ETNAVIV_PARAM_GPU_THREAD_COUNT              0x12
+#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE         0x13
+#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT         0x14
+#define ETNAVIV_PARAM_GPU_PIXEL_PIPES               0x15
+#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16
+#define ETNAVIV_PARAM_GPU_BUFFER_SIZE               0x17
+#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT         0x18
+#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS             0x19
+
+#define ETNA_MAX_PIPES 4
+
+struct drm_etnaviv_param {
+	__u32 pipe;           /* in */
+	__u32 param;          /* in, ETNAVIV_PARAM_x */
+	__u64 value;          /* out (get_param) or in (set_param) */
+};
+
+/*
+ * GEM buffers:
+ */
+
+#define ETNA_BO_CACHE_MASK   0x000f0000
+/* cache modes */
+#define ETNA_BO_CACHED       0x00010000
+#define ETNA_BO_WC           0x00020000
+#define ETNA_BO_UNCACHED     0x00040000
+/* map flags */
+#define ETNA_BO_FORCE_MMU    0x00100000
+
+struct drm_etnaviv_gem_new {
+	__u64 size;           /* in */
+	__u32 flags;          /* in, mask of ETNA_BO_x */
+	__u32 handle;         /* out */
+};
+
+struct drm_etnaviv_gem_info {
+	__u32 handle;         /* in */
+	__u32 pad;
+	__u64 offset;         /* out, offset to pass to mmap() */
+};
+
+#define ETNA_PREP_READ        0x01
+#define ETNA_PREP_WRITE       0x02
+#define ETNA_PREP_NOSYNC      0x04
+
+struct drm_etnaviv_gem_cpu_prep {
+	__u32 handle;         /* in */
+	__u32 op;             /* in, mask of ETNA_PREP_x */
+	struct drm_etnaviv_timespec timeout;   /* in */
+};
+
+struct drm_etnaviv_gem_cpu_fini {
+	__u32 handle;         /* in */
+};
+
+/*
+ * Cmdstream Submission:
+ */
+
+/* The value written into the cmdstream is logically:
+ * relocbuf->gpuaddr + reloc_offset
+ *
+ * NOTE that reloc's must be sorted by order of increasing submit_offset,
+ * otherwise EINVAL.
+ */
+struct drm_etnaviv_gem_submit_reloc {
+	__u32 submit_offset;  /* in, offset from submit_bo */
+	__u32 reloc_idx;      /* in, index of reloc_bo buffer */
+	__u64 reloc_offset;   /* in, offset from start of reloc_bo */
+};
+
+/* Each buffer referenced elsewhere in the cmdstream submit (ie. the
+ * cmdstream buffer(s) themselves or reloc entries) has one (and only
+ * one) entry in the submit->bos[] table.
+ *
+ * As a optimization, the current buffer (gpu virtual address) can be
+ * passed back through the 'presumed' field.  If on a subsequent reloc,
+ * userspace passes back a 'presumed' address that is still valid,
+ * then patching the cmdstream for this entry is skipped.  This can
+ * avoid kernel needing to map/access the cmdstream bo in the common
+ * case.
+ */
+#define ETNA_SUBMIT_BO_READ             0x0001
+#define ETNA_SUBMIT_BO_WRITE            0x0002
+struct drm_etnaviv_gem_submit_bo {
+	__u32 flags;          /* in, mask of ETNA_SUBMIT_BO_x */
+	__u32 handle;         /* in, GEM handle */
+	__u64 presumed;       /* in/out, presumed buffer address */
+};
+
+/* Each cmdstream submit consists of a table of buffers involved, and
+ * one or more cmdstream buffers.  This allows for conditional execution
+ * (context-restore), and IB buffers needed for per tile/bin draw cmds.
+ */
+#define ETNA_PIPE_3D      0x00
+#define ETNA_PIPE_2D      0x01
+#define ETNA_PIPE_VG      0x02
+struct drm_etnaviv_gem_submit {
+	__u32 fence;          /* out */
+	__u32 pipe;           /* in */
+	__u32 exec_state;     /* in, initial execution state (ETNA_PIPE_x) */
+	__u32 nr_bos;         /* in, number of submit_bo's */
+	__u32 nr_relocs;      /* in, number of submit_reloc's */
+	__u32 stream_size;    /* in, cmdstream size */
+	__u64 bos;            /* in, ptr to array of submit_bo's */
+	__u64 relocs;         /* in, ptr to array of submit_reloc's */
+	__u64 stream;         /* in, ptr to cmdstream */
+};
+
+/* The normal way to synchronize with the GPU is just to CPU_PREP on
+ * a buffer if you need to access it from the CPU (other cmdstream
+ * submission from same or other contexts, PAGE_FLIP ioctl, etc, all
+ * handle the required synchronization under the hood).  This ioctl
+ * mainly just exists as a way to implement the gallium pipe_fence
+ * APIs without requiring a dummy bo to synchronize on.
+ */
+struct drm_etnaviv_wait_fence {
+	__u32 pipe;           /* in */
+	__u32 fence;          /* in */
+	struct drm_etnaviv_timespec timeout;   /* in */
+};
+
+#define ETNA_USERPTR_READ	0x01
+#define ETNA_USERPTR_WRITE	0x02
+struct drm_etnaviv_gem_userptr {
+	__u64 user_ptr;	/* in, page aligned user pointer */
+	__u64 user_size;	/* in, page aligned user size */
+	__u32 flags;		/* in, flags */
+	__u32 handle;	/* out, non-zero handle */
+};
+
+struct drm_etnaviv_gem_wait {
+	__u32 pipe;				/* in */
+	__u32 handle;				/* in, bo to be waited for */
+	struct drm_etnaviv_timespec timeout;	/* in */
+};
+
+#define DRM_ETNAVIV_GET_PARAM          0x00
+/* placeholder:
+#define DRM_ETNAVIV_SET_PARAM          0x01
+ */
+#define DRM_ETNAVIV_GEM_NEW            0x02
+#define DRM_ETNAVIV_GEM_INFO           0x03
+#define DRM_ETNAVIV_GEM_CPU_PREP       0x04
+#define DRM_ETNAVIV_GEM_CPU_FINI       0x05
+#define DRM_ETNAVIV_GEM_SUBMIT         0x06
+#define DRM_ETNAVIV_WAIT_FENCE         0x07
+#define DRM_ETNAVIV_GEM_USERPTR        0x08
+#define DRM_ETNAVIV_GEM_WAIT           0x09
+#define DRM_ETNAVIV_NUM_IOCTLS         0x0a
+
+#define DRM_IOCTL_ETNAVIV_GET_PARAM    DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
+#define DRM_IOCTL_ETNAVIV_GEM_NEW      DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
+#define DRM_IOCTL_ETNAVIV_GEM_INFO     DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info)
+#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep)
+#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini)
+#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT   DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit)
+#define DRM_IOCTL_ETNAVIV_WAIT_FENCE   DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
+#define DRM_IOCTL_ETNAVIV_GEM_USERPTR  DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
+#define DRM_IOCTL_ETNAVIV_GEM_WAIT     DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
+
+#endif /* __ETNAVIV_DRM_H__ */
-- 
2.5.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH RFCv2 4/4] ARM: imx6: add Vivante GPU nodes
  2015-09-11 14:10 [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
                   ` (2 preceding siblings ...)
  2015-09-11 14:10 ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Lucas Stach
@ 2015-09-11 14:10 ` Lucas Stach
  2015-09-11 14:15 ` [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
  2015-10-20  9:36 ` Daniel Vetter
  5 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-11 14:10 UTC (permalink / raw)
  To: dri-devel; +Cc: Russell King, kernel

This adds the device nodes for 2D, 3D and VG GPU cores.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6dl.dtsi  |  5 +++++
 arch/arm/boot/dts/imx6q.dtsi   | 15 +++++++++++++++
 arch/arm/boot/dts/imx6qdl.dtsi | 21 +++++++++++++++++++++
 3 files changed, 41 insertions(+)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 4b0ec0703825..51c517a5cafd 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -104,6 +104,11 @@
 		compatible = "fsl,imx-display-subsystem";
 		ports = <&ipu1_di0>, <&ipu1_di1>;
 	};
+
+	gpu-subsystem {
+		compatible = "fsl,imx-gpu-subsystem";
+		cores = <&gpu_2d>, <&gpu_3d>;
+	};
 };
 
 &gpt {
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 399103b8e2c9..77d618b2870c 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -153,6 +153,16 @@
 			status = "disabled";
 		};
 
+		gpu_vg: gpu@02204000 {
+			compatible = "vivante,gc";
+			reg = <0x02204000 0x4000>;
+			interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clks IMX6QDL_CLK_OPENVG_AXI>,
+				 <&clks IMX6QDL_CLK_GPU2D_CORE>;
+			clock-names = "bus", "core";
+			power-domains = <&gpc 1>;
+		};
+
 		ipu2: ipu@02800000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -225,6 +235,11 @@
 		compatible = "fsl,imx-display-subsystem";
 		ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>;
 	};
+
+	gpu-subsystem {
+		compatible = "fsl,imx-gpu-subsystem";
+		cores = <&gpu_2d>, <&gpu_3d>, <&gpu_vg>;
+	};
 };
 
 &hdmi {
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index b57033e8c633..33a803eeed79 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -147,6 +147,27 @@
 			};
 		};
 
+		gpu_3d: gpu@00130000 {
+			compatible = "vivante,gc";
+			reg = <0x00130000 0x4000>;
+			interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clks IMX6QDL_CLK_GPU3D_AXI>,
+				 <&clks IMX6QDL_CLK_GPU3D_CORE>,
+				 <&clks IMX6QDL_CLK_GPU3D_SHADER>;
+			clock-names = "bus", "core", "shader";
+			power-domains = <&gpc 1>;
+		};
+
+		gpu_2d: gpu@00134000 {
+			compatible = "vivante,gc";
+			reg = <0x00134000 0x4000>;
+			interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clks IMX6QDL_CLK_GPU2D_AXI>,
+				 <&clks IMX6QDL_CLK_GPU2D_CORE>;
+			clock-names = "bus", "core";
+			power-domains = <&gpc 1>;
+		};
+
 		timer@00a00600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0x00a00600 0x20>;
-- 
2.5.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 0/4] Etnaviv DRM driver again
  2015-09-11 14:10 [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
                   ` (3 preceding siblings ...)
  2015-09-11 14:10 ` [PATCH RFCv2 4/4] ARM: imx6: add Vivante GPU nodes Lucas Stach
@ 2015-09-11 14:15 ` Lucas Stach
  2015-10-20  9:36 ` Daniel Vetter
  5 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-11 14:15 UTC (permalink / raw)
  To: dri-devel; +Cc: Russell King, kernel

Am Freitag, den 11.09.2015, 16:10 +0200 schrieb Lucas Stach:
> Hey all,
> 
> this is a new posting of the Etnaviv DRM driver for Vivante embedded GPUs.
> This time I've squashed all patches to the DRM driver itself into a single commit
> to make it easier for people to look at and review this stuff.
> 
Which seems to mean to that due to its size the most interesting patch
out of this series is now missing from the ML. I suppose it's held in
moderation, so if somebody could push it through I would be thankful.

Regards,
Lucas

> Aside from squashing of some of the trivial bugfixes I intend to keep all the
> individual commits around to retain the authorship of people working on this
> driver. If you want to look at the stream of commits please fetch
> 
> git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> 
> I've kept things in staging for now, as that's the place where Christian started
> this driver, but would really like to move it to DRM proper _before_ merging. So
> please review stuff with that in mind.
> 
> Since the last posting a lot of cleanups and bugfixes have landed, but also a major
> rewrite of the userspace interface. The UAPI is now considerably simpler as a lot
> of things that turned out to be not useful have been cut out. Also a pretty big
> security issue has been fixed where the userspace could abuse the still mapped
> command buffer to change the command stream after the kernel validated and patched
> it up, but before actual GPU execution.
> 
> Thanks to Russell King GPU power management with proper state reinitialization is
> now in place, which allows the GPU to be completely power gated when not in use,
> but is also the foundation for GPU recovery after a hanging submit.
> 
> A modified version of Russell Kings xf86-video-armada driver driver that works on
> top of the new UAPI is available at
> 
> git://git.pengutronix.de/git/lst/xf86-video-armada.git for-rmk
> 
> Regards,
> Lucas
> 
> Christian Gmeiner (1):
>   staging: etnaviv: add drm driver
> 
> Lucas Stach (2):
>   staging: etnaviv: add devicetree bindings
>   ARM: imx6: add Vivante GPU nodes
> 
> Philipp Zabel (1):
>   of: Add vendor prefix for Vivante Corporation
> 
>  .../bindings/drm/etnaviv/etnaviv-drm.txt           |   44 +
>  .../devicetree/bindings/vendor-prefixes.txt        |    1 +
>  arch/arm/boot/dts/imx6dl.dtsi                      |    5 +
>  arch/arm/boot/dts/imx6q.dtsi                       |   15 +
>  arch/arm/boot/dts/imx6qdl.dtsi                     |   21 +
>  drivers/staging/Kconfig                            |    2 +
>  drivers/staging/Makefile                           |    1 +
>  drivers/staging/etnaviv/Kconfig                    |   20 +
>  drivers/staging/etnaviv/Makefile                   |   18 +
>  drivers/staging/etnaviv/cmdstream.xml.h            |  218 +++
>  drivers/staging/etnaviv/common.xml.h               |  249 ++++
>  drivers/staging/etnaviv/etnaviv_buffer.c           |  271 ++++
>  drivers/staging/etnaviv/etnaviv_cmd_parser.c       |  119 ++
>  drivers/staging/etnaviv/etnaviv_drv.c              |  705 ++++++++++
>  drivers/staging/etnaviv/etnaviv_drv.h              |  138 ++
>  drivers/staging/etnaviv/etnaviv_gem.c              |  887 ++++++++++++
>  drivers/staging/etnaviv/etnaviv_gem.h              |  141 ++
>  drivers/staging/etnaviv/etnaviv_gem_prime.c        |  121 ++
>  drivers/staging/etnaviv/etnaviv_gem_submit.c       |  421 ++++++
>  drivers/staging/etnaviv/etnaviv_gpu.c              | 1468 ++++++++++++++++++++
>  drivers/staging/etnaviv/etnaviv_gpu.h              |  198 +++
>  drivers/staging/etnaviv/etnaviv_iommu.c            |  221 +++
>  drivers/staging/etnaviv/etnaviv_iommu.h            |   28 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.c         |   33 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.h         |   25 +
>  drivers/staging/etnaviv/etnaviv_mmu.c              |  282 ++++
>  drivers/staging/etnaviv/etnaviv_mmu.h              |   58 +
>  drivers/staging/etnaviv/state.xml.h                |  351 +++++
>  drivers/staging/etnaviv/state_hi.xml.h             |  407 ++++++
>  include/uapi/drm/etnaviv_drm.h                     |  215 +++
>  30 files changed, 6683 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/etnaviv/etnaviv-drm.txt
>  create mode 100644 drivers/staging/etnaviv/Kconfig
>  create mode 100644 drivers/staging/etnaviv/Makefile
>  create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h
>  create mode 100644 drivers/staging/etnaviv/common.xml.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h
>  create mode 100644 drivers/staging/etnaviv/state.xml.h
>  create mode 100644 drivers/staging/etnaviv/state_hi.xml.h
>  create mode 100644 include/uapi/drm/etnaviv_drm.h
> 

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-11 14:10 ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Lucas Stach
@ 2015-09-14 13:16   ` Rob Clark
  2015-09-16  7:56     ` Russell King - ARM Linux
  2015-09-16  6:11   ` Christian Gmeiner
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 100+ messages in thread
From: Rob Clark @ 2015-09-14 13:16 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, kernel, dri-devel

On Fri, Sep 11, 2015 at 10:10 AM, Lucas Stach <l.stach@pengutronix.de> wrote:
> From: Christian Gmeiner <christian.gmeiner@gmail.com>
>
> This is a squashed commit of the complete etnaviv DRM driver in order
> to make it easy for people to review the code by seeing the driver as a
> whole and is not intended for merging in this form.
>
> If you are interested in the history of individual commits:
> git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
>
> 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>
> ---
>  drivers/staging/Kconfig                      |    2 +
>  drivers/staging/Makefile                     |    1 +
>  drivers/staging/etnaviv/Kconfig              |   20 +
>  drivers/staging/etnaviv/Makefile             |   18 +
>  drivers/staging/etnaviv/cmdstream.xml.h      |  218 ++++
>  drivers/staging/etnaviv/common.xml.h         |  249 +++++
>  drivers/staging/etnaviv/etnaviv_buffer.c     |  271 +++++
>  drivers/staging/etnaviv/etnaviv_cmd_parser.c |  119 +++
>  drivers/staging/etnaviv/etnaviv_drv.c        |  705 +++++++++++++
>  drivers/staging/etnaviv/etnaviv_drv.h        |  138 +++
>  drivers/staging/etnaviv/etnaviv_gem.c        |  887 ++++++++++++++++
>  drivers/staging/etnaviv/etnaviv_gem.h        |  141 +++
>  drivers/staging/etnaviv/etnaviv_gem_prime.c  |  121 +++
>  drivers/staging/etnaviv/etnaviv_gem_submit.c |  421 ++++++++
>  drivers/staging/etnaviv/etnaviv_gpu.c        | 1468 ++++++++++++++++++++++++++
>  drivers/staging/etnaviv/etnaviv_gpu.h        |  198 ++++
>  drivers/staging/etnaviv/etnaviv_iommu.c      |  221 ++++
>  drivers/staging/etnaviv/etnaviv_iommu.h      |   28 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.c   |   33 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.h   |   25 +
>  drivers/staging/etnaviv/etnaviv_mmu.c        |  282 +++++
>  drivers/staging/etnaviv/etnaviv_mmu.h        |   58 +
>  drivers/staging/etnaviv/state.xml.h          |  351 ++++++
>  drivers/staging/etnaviv/state_hi.xml.h       |  407 +++++++
>  include/uapi/drm/etnaviv_drm.h               |  215 ++++
>  25 files changed, 6597 insertions(+)
>  create mode 100644 drivers/staging/etnaviv/Kconfig
>  create mode 100644 drivers/staging/etnaviv/Makefile
>  create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h
>  create mode 100644 drivers/staging/etnaviv/common.xml.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h
>  create mode 100644 drivers/staging/etnaviv/state.xml.h
>  create mode 100644 drivers/staging/etnaviv/state_hi.xml.h
>  create mode 100644 include/uapi/drm/etnaviv_drm.h
>
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index 7f6cae5beb90..5446fe4859ce 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -112,4 +112,6 @@ source "drivers/staging/fsl-mc/Kconfig"
>
>  source "drivers/staging/wilc1000/Kconfig"
>
> +source "drivers/staging/etnaviv/Kconfig"
> +
>  endif # STAGING
> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> index 347f6477aa3e..9fd3c06b6bfd 100644
> --- a/drivers/staging/Makefile
> +++ b/drivers/staging/Makefile
> @@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
>  obj-$(CONFIG_FB_TFT)           += fbtft/
>  obj-$(CONFIG_FSL_MC_BUS)       += fsl-mc/
>  obj-$(CONFIG_WILC1000)         += wilc1000/
> +obj-$(CONFIG_DRM_ETNAVIV)      += etnaviv/
> diff --git a/drivers/staging/etnaviv/Kconfig b/drivers/staging/etnaviv/Kconfig
> new file mode 100644
> index 000000000000..6f034eda914c
> --- /dev/null
> +++ b/drivers/staging/etnaviv/Kconfig
> @@ -0,0 +1,20 @@
> +
> +config DRM_ETNAVIV
> +       tristate "etnaviv DRM"
> +       depends on DRM
> +       select SHMEM
> +       select TMPFS
> +       select IOMMU_API
> +       select IOMMU_SUPPORT
> +       default y
> +       help
> +         DRM driver for Vivante GPUs.
> +
> +config DRM_ETNAVIV_REGISTER_LOGGING
> +       bool "etnaviv DRM register logging"
> +       depends on DRM_ETNAVIV
> +       default n
> +       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.

heh, ok, didn't realize anyone else was using demsm..  I guess that is
one of the things that I should clean up and get into upstream
envytools tree.  (And maybe come up with a better name.. if anyone has
any suggestions..)

BR,
-R

> diff --git a/drivers/staging/etnaviv/Makefile b/drivers/staging/etnaviv/Makefile
> new file mode 100644
> index 000000000000..2b71c31b6501
> --- /dev/null
> +++ b/drivers/staging/etnaviv/Makefile
> @@ -0,0 +1,18 @@
> +ccflags-y := -Iinclude/drm -Idrivers/staging/vivante
> +ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
> +       ccflags-y += -Werror
> +endif
> +
> +etnaviv-y := \
> +       etnaviv_cmd_parser.o \
> +       etnaviv_drv.o \
> +       etnaviv_gem.o \
> +       etnaviv_gem_prime.o \
> +       etnaviv_gem_submit.o \
> +       etnaviv_gpu.o \
> +       etnaviv_iommu.o \
> +       etnaviv_iommu_v2.o \
> +       etnaviv_mmu.o \
> +       etnaviv_buffer.o
> +
> +obj-$(CONFIG_DRM_ETNAVIV)      += etnaviv.o
> diff --git a/drivers/staging/etnaviv/cmdstream.xml.h b/drivers/staging/etnaviv/cmdstream.xml.h
> new file mode 100644
> index 000000000000..8c44ba9a694e
> --- /dev/null
> +++ b/drivers/staging/etnaviv/cmdstream.xml.h
> @@ -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 */
> diff --git a/drivers/staging/etnaviv/common.xml.h b/drivers/staging/etnaviv/common.xml.h
> new file mode 100644
> index 000000000000..9e585d51fb78
> --- /dev/null
> +++ b/drivers/staging/etnaviv/common.xml.h
> @@ -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 */
> diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
> new file mode 100644
> index 000000000000..586f84316f1a
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_buffer.c
> @@ -0,0 +1,271 @@
> +/*
> + * 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;
> +
> +       if (pipe == ETNA_PIPE_2D)
> +               flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR;
> +       else
> +               flush = VIVS_GL_FLUSH_CACHE_TEXTURE;
> +
> +       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_gem_submit *submit)
> +{
> +       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, submit->cmdbuf),
> +                       submit->cmdbuf->vaddr);
> +
> +       /* jump back from cmd to main buffer */
> +       CMD_LINK(submit->cmdbuf, link_size, link_target);
> +
> +       link_target = gpu_va(gpu, submit->cmdbuf);
> +       link_size = submit->cmdbuf->size / 8;
> +
> +
> +
> +       if (drm_debug & DRM_UT_DRIVER) {
> +               print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
> +                              submit->cmdbuf->vaddr, submit->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, submit->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;
> +       }
> +
> +       /* Save the event and buffer position of the new event trigger */
> +       gpu->event[event].fence = submit->fence;
> +
> +       /* take ownership of cmdbuffer*/
> +       submit->cmdbuf->fence = submit->fence;
> +       list_add_tail(&submit->cmdbuf->gpu_active_list, &gpu->active_cmd_list);
> +       submit->cmdbuf = NULL;
> +
> +       /* 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);
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_cmd_parser.c b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
> new file mode 100644
> index 000000000000..5175d6eb3bdc
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
> @@ -0,0 +1,119 @@
> +/*
> + * 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)
> +
> +static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf,
> +       unsigned int state, unsigned int num)
> +{
> +       return true;
> +       if (0x1200 - state < num * 4)
> +               return false;
> +       if (0x1228 - state < num * 4)
> +               return false;
> +       if (0x1238 - state < num * 4)
> +               return false;
> +       if (0x1284 - state < num * 4)
> +               return false;
> +       if (0x128c - state < num * 4)
> +               return false;
> +       if (0x1304 - state < num * 4)
> +               return false;
> +       if (0x1310 - state < num * 4)
> +               return false;
> +       if (0x1318 - state < num * 4)
> +               return false;
> +       if (0x1280c - state < num * 4 + 0x0c)
> +               return false;
> +       if (0x128ac - state < num * 4 + 0x0c)
> +               return false;
> +       if (0x128cc - state < num * 4 + 0x0c)
> +               return false;
> +       if (0x1297c - state < num * 4 + 0x0c)
> +               return false;
> +       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, void *stream,
> +                             unsigned int size)
> +{
> +       u32 *start = stream;
> +       u32 *buf = start;
> +       u32 *end = buf + size;
> +
> +       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(gpu, buf + 1,
> +                                                        off * 4, n)) {
> +                               dev_warn(gpu->dev, "%s: load state covers restricted state (0x%x-0x%x) at offset %tu\n",
> +                                        __func__, off * 4, (off + n) * 4, buf - start);
> +                               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 - start);
> +                               return false;
> +                       }
> +                       break;
> +               }
> +
> +               buf += len;
> +       }
> +
> +       if (buf > end) {
> +               dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
> +                       __func__, buf - start, size);
> +               return false;
> +       }
> +
> +       return true;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
> new file mode 100644
> index 000000000000..30f6e5d0c91d
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_drv.c
> @@ -0,0 +1,705 @@
> +/*
> + * 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/component.h>
> +#include <linux/of_platform.h>
> +
> +#include "etnaviv_drv.h"
> +#include "etnaviv_gpu.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_mmu.h"
> +#include "etnaviv_gem.h"
> +
> +#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
> +static bool reglog;
> +MODULE_PARM_DESC(reglog, "Enable register read/write logging");
> +module_param(reglog, bool, 0600);
> +#else
> +#define reglog 0
> +#endif
> +
> +void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name,
> +               const char *dbgname)
> +{
> +       struct resource *res;
> +       void __iomem *ptr;
> +
> +       if (name)
> +               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
> +       else
> +               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> +       ptr = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(ptr)) {
> +               dev_err(&pdev->dev, "failed to ioremap %s: %ld\n", name,
> +                       PTR_ERR(ptr));
> +               return ptr;
> +       }
> +
> +       if (reglog)
> +               dev_printk(KERN_DEBUG, &pdev->dev, "IO:region %s 0x%p %08zx\n",
> +                          dbgname, ptr, (size_t)resource_size(res));
> +
> +       return ptr;
> +}
> +
> +void etnaviv_writel(u32 data, void __iomem *addr)
> +{
> +       if (reglog)
> +               printk(KERN_DEBUG "IO:W %p %08x\n", addr, data);
> +
> +       writel(data, addr);
> +}
> +
> +u32 etnaviv_readl(const void __iomem *addr)
> +{
> +       u32 val = readl(addr);
> +
> +       if (reglog)
> +               printk(KERN_DEBUG "IO:R %p %08x\n", addr, val);
> +
> +       return val;
> +}
> +
> +/*
> + * DRM operations:
> + */
> +
> +static int etnaviv_unload(struct drm_device *dev)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +
> +       flush_workqueue(priv->wq);
> +       destroy_workqueue(priv->wq);
> +
> +       component_unbind_all(dev->dev, dev);
> +
> +       dev->dev_private = NULL;
> +
> +       kfree(priv);
> +
> +       return 0;
> +}
> +
> +
> +static void load_gpu(struct drm_device *dev)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               struct etnaviv_gpu *g = priv->gpu[i];
> +
> +               if (g) {
> +                       int ret;
> +
> +                       ret = etnaviv_gpu_init(g);
> +                       if (ret) {
> +                               dev_err(g->dev, "hw init failed: %d\n", ret);
> +                               priv->gpu[i] = NULL;
> +                       }
> +               }
> +       }
> +}
> +
> +static int etnaviv_load(struct drm_device *dev, unsigned long flags)
> +{
> +       struct platform_device *pdev = dev->platformdev;
> +       struct etnaviv_drm_private *priv;
> +       int err;
> +
> +       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +       if (!priv) {
> +               dev_err(dev->dev, "failed to allocate private data\n");
> +               return -ENOMEM;
> +       }
> +
> +       dev->dev_private = priv;
> +
> +       priv->wq = alloc_ordered_workqueue("etnaviv", 0);
> +       if (!priv->wq) {
> +               err = -ENOMEM;
> +               goto err_wq;
> +       }
> +
> +       INIT_LIST_HEAD(&priv->inactive_list);
> +       priv->num_gpus = 0;
> +
> +       platform_set_drvdata(pdev, dev);
> +
> +       err = component_bind_all(dev->dev, dev);
> +       if (err < 0)
> +               goto err_bind;
> +
> +       load_gpu(dev);
> +
> +       return 0;
> +
> +err_bind:
> +       flush_workqueue(priv->wq);
> +       destroy_workqueue(priv->wq);
> +err_wq:
> +       kfree(priv);
> +       return err;
> +}
> +
> +static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
> +{
> +       struct etnaviv_file_private *ctx;
> +
> +       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +       if (!ctx)
> +               return -ENOMEM;
> +
> +       file->driver_priv = ctx;
> +
> +       return 0;
> +}
> +
> +static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_file_private *ctx = file->driver_priv;
> +       unsigned int i;
> +
> +       mutex_lock(&dev->struct_mutex);
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               struct etnaviv_gpu *gpu = priv->gpu[i];
> +
> +               if (gpu && gpu->lastctx == ctx)
> +                       gpu->lastctx = NULL;
> +       }
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       kfree(ctx);
> +}
> +
> +/*
> + * DRM debugfs:
> + */
> +
> +#ifdef CONFIG_DEBUG_FS
> +static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (gpu) {
> +                       seq_printf(m, "Active Objects (%s):\n",
> +                                  dev_name(gpu->dev));
> +                       etnaviv_gem_describe_objects(&gpu->active_list, m);
> +               }
> +       }
> +
> +       seq_puts(m, "Inactive Objects:\n");
> +       etnaviv_gem_describe_objects(&priv->inactive_list, m);
> +
> +       return 0;
> +}
> +
> +static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
> +}
> +
> +static int etnaviv_mmu_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (gpu) {
> +                       seq_printf(m, "Active Objects (%s):\n",
> +                                  dev_name(gpu->dev));
> +                       drm_mm_dump_table(m, &gpu->mmu->mm);
> +               }
> +       }
> +       return 0;
> +}
> +
> +static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
> +{
> +       struct etnaviv_cmdbuf *buf = gpu->buffer;
> +       u32 size = buf->size;
> +       u32 *ptr = buf->vaddr;
> +       u32 i;
> +
> +       seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
> +                       buf->vaddr, (u64)buf->paddr, size - buf->user_size);
> +
> +       for (i = 0; i < size / 4; i++) {
> +               if (i && !(i % 4))
> +                       seq_puts(m, "\n");
> +               if (i % 4 == 0)
> +                       seq_printf(m, "\t0x%p: ", ptr + i);
> +               seq_printf(m, "%08x ", *(ptr + i));
> +       }
> +       seq_puts(m, "\n");
> +}
> +
> +static int etnaviv_ring_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (gpu) {
> +                       seq_printf(m, "Ring Buffer (%s): ",
> +                                  dev_name(gpu->dev));
> +                       etnaviv_buffer_dump(gpu, m);
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int show_locked(struct seq_file *m, void *arg)
> +{
> +       struct drm_info_node *node = (struct drm_info_node *) m->private;
> +       struct drm_device *dev = node->minor->dev;
> +       int (*show)(struct drm_device *dev, struct seq_file *m) =
> +                       node->info_ent->data;
> +       int ret;
> +
> +       ret = mutex_lock_interruptible(&dev->struct_mutex);
> +       if (ret)
> +               return ret;
> +
> +       ret = show(dev, m);
> +
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       return ret;
> +}
> +
> +static int show_each_gpu(struct seq_file *m, void *arg)
> +{
> +       struct drm_info_node *node = (struct drm_info_node *) m->private;
> +       struct drm_device *dev = node->minor->dev;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
> +                       node->info_ent->data;
> +       unsigned int i;
> +       int ret = 0;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (!gpu)
> +                       continue;
> +
> +               ret = show(gpu, m);
> +               if (ret < 0)
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +static struct drm_info_list etnaviv_debugfs_list[] = {
> +               {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs},
> +               {"gem", show_locked, 0, etnaviv_gem_show},
> +               { "mm", show_locked, 0, etnaviv_mm_show },
> +               {"mmu", show_locked, 0, etnaviv_mmu_show},
> +               {"ring", show_locked, 0, etnaviv_ring_show},
> +};
> +
> +static int etnaviv_debugfs_init(struct drm_minor *minor)
> +{
> +       struct drm_device *dev = minor->dev;
> +       int ret;
> +
> +       ret = drm_debugfs_create_files(etnaviv_debugfs_list,
> +                       ARRAY_SIZE(etnaviv_debugfs_list),
> +                       minor->debugfs_root, minor);
> +
> +       if (ret) {
> +               dev_err(dev->dev, "could not install etnaviv_debugfs_list\n");
> +               return ret;
> +       }
> +
> +       return ret;
> +}
> +
> +static void etnaviv_debugfs_cleanup(struct drm_minor *minor)
> +{
> +       drm_debugfs_remove_files(etnaviv_debugfs_list,
> +                       ARRAY_SIZE(etnaviv_debugfs_list), minor);
> +}
> +#endif
> +
> +/*
> + * DRM ioctls:
> + */
> +
> +static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct drm_etnaviv_param *args = data;
> +       struct etnaviv_gpu *gpu;
> +
> +       if (args->pipe >= ETNA_MAX_PIPES)
> +               return -EINVAL;
> +
> +       gpu = priv->gpu[args->pipe];
> +       if (!gpu)
> +               return -ENXIO;
> +
> +       return etnaviv_gpu_get_param(gpu, args->param, &args->value);
> +}
> +
> +static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_new *args = data;
> +
> +       return etnaviv_gem_new_handle(dev, file, args->size,
> +                       args->flags, &args->handle);
> +}
> +
> +#define TS(t) ((struct timespec){ \
> +       .tv_sec = (t).tv_sec, \
> +       .tv_nsec = (t).tv_nsec \
> +})
> +
> +static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_cpu_prep *args = data;
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout));
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_cpu_fini *args = data;
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = etnaviv_gem_cpu_fini(obj);
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_info *args = data;
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       if (args->pad)
> +               return -EINVAL;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = mutex_lock_interruptible(&dev->struct_mutex);
> +       if (ret == 0) {
> +               ret = etnaviv_gem_mmap_offset(obj, &args->offset);
> +
> +               mutex_unlock(&dev->struct_mutex);
> +       }
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_wait_fence *args = data;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +
> +       if (args->pipe >= ETNA_MAX_PIPES)
> +               return -EINVAL;
> +
> +       gpu = priv->gpu[args->pipe];
> +       if (!gpu)
> +               return -ENXIO;
> +
> +       return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
> +                                                   &TS(args->timeout));
> +}
> +
> +static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
> +       struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_userptr *args = data;
> +       int access;
> +
> +       if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) ||
> +           args->flags == 0)
> +               return -EINVAL;
> +
> +       if (offset_in_page(args->user_ptr | args->user_size) ||
> +           (uintptr_t)args->user_ptr != args->user_ptr ||
> +           (u32)args->user_size != args->user_size)
> +               return -EINVAL;
> +
> +       if (args->flags & ETNA_USERPTR_WRITE)
> +               access = VERIFY_WRITE;
> +       else
> +               access = VERIFY_READ;
> +
> +       if (!access_ok(access, (void __user *)(unsigned long)args->user_ptr,
> +                      args->user_size))
> +               return -EFAULT;
> +
> +       return etnaviv_gem_new_userptr(dev, file, args->user_ptr,
> +                                      args->user_size, args->flags,
> +                                      &args->handle);
> +}
> +
> +static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
> +       struct drm_file *file)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct drm_etnaviv_gem_wait *args = data;
> +       struct drm_gem_object *obj;
> +       struct etnaviv_gpu *gpu;
> +       int ret;
> +
> +       if (args->pipe >= ETNA_MAX_PIPES)
> +               return -EINVAL;
> +
> +       gpu = priv->gpu[args->pipe];
> +       if (!gpu)
> +               return -ENXIO;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = etnaviv_gem_wait_bo(gpu, obj, &TS(args->timeout));
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static const struct drm_ioctl_desc etnaviv_ioctls[] = {
> +#define ETNA_IOCTL(n, func, flags) \
> +       DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
> +       ETNA_IOCTL(GET_PARAM,    get_param,    DRM_UNLOCKED|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_NEW,      gem_new,      DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_INFO,     gem_info,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_SUBMIT,   gem_submit,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(WAIT_FENCE,   wait_fence,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_USERPTR,  gem_userptr,  DRM_UNLOCKED|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_WAIT,     gem_wait,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +};
> +
> +static const struct vm_operations_struct vm_ops = {
> +       .fault = etnaviv_gem_fault,
> +       .open = drm_gem_vm_open,
> +       .close = drm_gem_vm_close,
> +};
> +
> +static const struct file_operations fops = {
> +       .owner              = THIS_MODULE,
> +       .open               = drm_open,
> +       .release            = drm_release,
> +       .unlocked_ioctl     = drm_ioctl,
> +#ifdef CONFIG_COMPAT
> +       .compat_ioctl       = drm_compat_ioctl,
> +#endif
> +       .poll               = drm_poll,
> +       .read               = drm_read,
> +       .llseek             = no_llseek,
> +       .mmap               = etnaviv_gem_mmap,
> +};
> +
> +static struct drm_driver etnaviv_drm_driver = {
> +       .driver_features    = DRIVER_HAVE_IRQ |
> +                               DRIVER_GEM |
> +                               DRIVER_PRIME |
> +                               DRIVER_RENDER,
> +       .load               = etnaviv_load,
> +       .unload             = etnaviv_unload,
> +       .open               = etnaviv_open,
> +       .preclose           = etnaviv_preclose,
> +       .set_busid          = drm_platform_set_busid,
> +       .gem_free_object    = etnaviv_gem_free_object,
> +       .gem_vm_ops         = &vm_ops,
> +       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> +       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +       .gem_prime_export   = drm_gem_prime_export,
> +       .gem_prime_import   = drm_gem_prime_import,
> +       .gem_prime_pin      = etnaviv_gem_prime_pin,
> +       .gem_prime_unpin    = etnaviv_gem_prime_unpin,
> +       .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table,
> +       .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
> +       .gem_prime_vmap     = etnaviv_gem_prime_vmap,
> +       .gem_prime_vunmap   = etnaviv_gem_prime_vunmap,
> +#ifdef CONFIG_DEBUG_FS
> +       .debugfs_init       = etnaviv_debugfs_init,
> +       .debugfs_cleanup    = etnaviv_debugfs_cleanup,
> +#endif
> +       .ioctls             = etnaviv_ioctls,
> +       .num_ioctls         = DRM_ETNAVIV_NUM_IOCTLS,
> +       .fops               = &fops,
> +       .name               = "etnaviv",
> +       .desc               = "etnaviv DRM",
> +       .date               = "20150910",
> +       .major              = 1,
> +       .minor              = 0,
> +};
> +
> +/*
> + * Platform driver:
> + */
> +static int etnaviv_bind(struct device *dev)
> +{
> +       return drm_platform_init(&etnaviv_drm_driver, to_platform_device(dev));
> +}
> +
> +static void etnaviv_unbind(struct device *dev)
> +{
> +       drm_put_dev(dev_get_drvdata(dev));
> +}
> +
> +static const struct component_master_ops etnaviv_master_ops = {
> +       .bind = etnaviv_bind,
> +       .unbind = etnaviv_unbind,
> +};
> +
> +static int compare_of(struct device *dev, void *data)
> +{
> +       struct device_node *np = data;
> +
> +       return dev->of_node == np;
> +}
> +
> +static int compare_str(struct device *dev, void *data)
> +{
> +       return !strcmp(dev_name(dev), data);
> +}
> +
> +static int etnaviv_pdev_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct device_node *node = dev->of_node;
> +       struct component_match *match = NULL;
> +
> +       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
> +
> +       if (node) {
> +               struct device_node *core_node;
> +               int i;
> +
> +               for (i = 0; ; i++) {
> +                       core_node = of_parse_phandle(node, "cores", i);
> +                       if (!core_node)
> +                               break;
> +
> +                       component_match_add(&pdev->dev, &match, compare_of,
> +                                           core_node);
> +                       of_node_put(core_node);
> +               }
> +       } else if (dev->platform_data) {
> +               char **names = dev->platform_data;
> +               unsigned i;
> +
> +               for (i = 0; names[i]; i++)
> +                       component_match_add(dev, &match, compare_str, names[i]);
> +       }
> +
> +       return component_master_add_with_match(dev, &etnaviv_master_ops, match);
> +}
> +
> +static int etnaviv_pdev_remove(struct platform_device *pdev)
> +{
> +       component_master_del(&pdev->dev, &etnaviv_master_ops);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id dt_match[] = {
> +       { .compatible = "fsl,imx-gpu-subsystem" },
> +       { .compatible = "marvell,dove-gpu-subsystem" },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, dt_match);
> +
> +static struct platform_driver etnaviv_platform_driver = {
> +       .probe      = etnaviv_pdev_probe,
> +       .remove     = etnaviv_pdev_remove,
> +       .driver     = {
> +               .owner  = THIS_MODULE,
> +               .name   = "etnaviv",
> +               .of_match_table = dt_match,
> +       },
> +};
> +
> +static int __init etnaviv_init(void)
> +{
> +       int ret;
> +
> +       ret = platform_driver_register(&etnaviv_gpu_driver);
> +       if (ret != 0)
> +               return ret;
> +
> +       ret = platform_driver_register(&etnaviv_platform_driver);
> +       if (ret != 0)
> +               platform_driver_unregister(&etnaviv_gpu_driver);
> +
> +       return ret;
> +}
> +module_init(etnaviv_init);
> +
> +static void __exit etnaviv_exit(void)
> +{
> +       platform_driver_unregister(&etnaviv_gpu_driver);
> +       platform_driver_unregister(&etnaviv_platform_driver);
> +}
> +module_exit(etnaviv_exit);
> +
> +MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
> +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
> +MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>");
> +MODULE_DESCRIPTION("etnaviv DRM Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:etnaviv");
> diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
> new file mode 100644
> index 000000000000..719e33174e83
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_drv.h
> @@ -0,0 +1,138 @@
> +/*
> + * 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_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];
> +
> +       u32 next_fence;
> +
> +       /* list of GEM objects: */
> +       struct list_head inactive_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_locked(struct etnaviv_gpu *gpu,
> +       struct drm_gem_object *obj, u32 *iova);
> +int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
> +       int id, u32 *iova);
> +void etnaviv_gem_put_iova(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_locked(struct drm_gem_object *obj);
> +void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
> +dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj);
> +void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
> +               struct etnaviv_gpu *gpu, u32 access, u32 fence);
> +void etnaviv_gem_move_to_inactive(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_gem_submit *submit);
> +bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
> +       void *stream, unsigned int size);
> +
> +#ifdef CONFIG_DEBUG_FS
> +void etnaviv_gem_describe_objects(struct list_head *list, 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__)
> +
> +/* 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;
> +}
> +
> +#endif /* __ETNAVIV_DRV_H__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
> new file mode 100644
> index 000000000000..1381c952c52f
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem.c
> @@ -0,0 +1,887 @@
> +/*
> + * 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/spinlock.h>
> +#include <linux/shmem_fs.h>
> +
> +#include "etnaviv_drv.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_gpu.h"
> +#include "etnaviv_mmu.h"
> +
> +static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct sg_table *sgt = etnaviv_obj->sgt;
> +
> +       /*
> +        * For non-cached buffers, ensure the new pages are clean
> +        * because display controller, GPU, etc. are not coherent.
> +        */
> +       if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
> +               dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
> +}
> +
> +static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct sg_table *sgt = etnaviv_obj->sgt;
> +
> +       /*
> +        * For non-cached buffers, ensure the new pages are clean
> +        * because display controller, GPU, etc. are not coherent:
> +        *
> +        * WARNING: The DMA API does not support concurrent CPU
> +        * and device access to the memory area.  With BIDIRECTIONAL,
> +        * we will clean the cache lines which overlap the region,
> +        * and invalidate all cache lines (partially) contained in
> +        * the region.
> +        *
> +        * If you have dirty data in the overlapping cache lines,
> +        * that will corrupt the GPU-written data.  If you have
> +        * written into the remainder of the region, this can
> +        * discard those writes.
> +        */
> +       if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
> +               dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
> +}
> +
> +/* called with dev->struct_mutex held */
> +static int etnaviv_gem_shmem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct page **p = drm_gem_get_pages(&etnaviv_obj->base);
> +
> +       if (IS_ERR(p)) {
> +               dev_err(dev->dev, "could not get pages: %ld\n", PTR_ERR(p));
> +               return PTR_ERR(p);
> +       }
> +
> +       etnaviv_obj->pages = p;
> +
> +       return 0;
> +}
> +
> +static void put_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       if (etnaviv_obj->sgt) {
> +               etnaviv_gem_scatterlist_unmap(etnaviv_obj);
> +               sg_free_table(etnaviv_obj->sgt);
> +               kfree(etnaviv_obj->sgt);
> +               etnaviv_obj->sgt = NULL;
> +       }
> +       if (etnaviv_obj->pages) {
> +               drm_gem_put_pages(&etnaviv_obj->base, etnaviv_obj->pages,
> +                                 true, false);
> +
> +               etnaviv_obj->pages = NULL;
> +       }
> +}
> +
> +struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       int ret;
> +
> +       if (!etnaviv_obj->pages) {
> +               ret = etnaviv_obj->ops->get_pages(etnaviv_obj);
> +               if (ret < 0)
> +                       return ERR_PTR(ret);
> +       }
> +
> +       if (!etnaviv_obj->sgt) {
> +               struct drm_device *dev = etnaviv_obj->base.dev;
> +               int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +               struct sg_table *sgt;
> +
> +               sgt = drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
> +               if (IS_ERR(sgt)) {
> +                       dev_err(dev->dev, "failed to allocate sgt: %ld\n",
> +                               PTR_ERR(sgt));
> +                       return ERR_CAST(sgt);
> +               }
> +
> +               etnaviv_obj->sgt = sgt;
> +
> +               etnaviv_gem_scatter_map(etnaviv_obj);
> +       }
> +
> +       return etnaviv_obj->pages;
> +}
> +
> +void etnaviv_gem_put_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       /* when we start tracking the pin count, then do something here */
> +}
> +
> +static int etnaviv_gem_mmap_obj(struct drm_gem_object *obj,
> +               struct vm_area_struct *vma)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       pgprot_t vm_page_prot;
> +
> +       vma->vm_flags &= ~VM_PFNMAP;
> +       vma->vm_flags |= VM_MIXEDMAP;
> +
> +       vm_page_prot = vm_get_page_prot(vma->vm_flags);
> +
> +       if (etnaviv_obj->flags & ETNA_BO_WC) {
> +               vma->vm_page_prot = pgprot_writecombine(vm_page_prot);
> +       } else if (etnaviv_obj->flags & ETNA_BO_UNCACHED) {
> +               vma->vm_page_prot = pgprot_noncached(vm_page_prot);
> +       } else {
> +               /*
> +                * Shunt off cached objs to shmem file so they have their own
> +                * address_space (so unmap_mapping_range does what we want,
> +                * in particular in the case of mmap'd dmabufs)
> +                */
> +               fput(vma->vm_file);
> +               get_file(obj->filp);
> +               vma->vm_pgoff = 0;
> +               vma->vm_file  = obj->filp;
> +
> +               vma->vm_page_prot = vm_page_prot;
> +       }
> +
> +       return 0;
> +}
> +
> +int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       struct etnaviv_gem_object *obj;
> +       int ret;
> +
> +       ret = drm_gem_mmap(filp, vma);
> +       if (ret) {
> +               DBG("mmap failed: %d", ret);
> +               return ret;
> +       }
> +
> +       obj = to_etnaviv_bo(vma->vm_private_data);
> +       return etnaviv_gem_mmap_obj(vma->vm_private_data, vma);
> +}
> +
> +int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> +{
> +       struct drm_gem_object *obj = vma->vm_private_data;
> +       struct drm_device *dev = obj->dev;
> +       struct page **pages, *page;
> +       pgoff_t pgoff;
> +       int ret;
> +
> +       /*
> +        * Make sure we don't parallel update on a fault, nor move or remove
> +        * something from beneath our feet.  Note that vm_insert_page() is
> +        * specifically coded to take care of this, so we don't have to.
> +        */
> +       ret = mutex_lock_interruptible(&dev->struct_mutex);
> +       if (ret)
> +               goto out;
> +
> +       /* make sure we have pages attached now */
> +       pages = etnaviv_gem_get_pages(to_etnaviv_bo(obj));
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       if (IS_ERR(pages)) {
> +               ret = PTR_ERR(pages);
> +               goto out;
> +       }
> +
> +       /* We don't use vmf->pgoff since that has the fake offset: */
> +       pgoff = ((unsigned long)vmf->virtual_address -
> +                       vma->vm_start) >> PAGE_SHIFT;
> +
> +       page = pages[pgoff];
> +
> +       VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
> +            page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT);
> +
> +       ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
> +
> +out:
> +       switch (ret) {
> +       case -EAGAIN:
> +       case 0:
> +       case -ERESTARTSYS:
> +       case -EINTR:
> +       case -EBUSY:
> +               /*
> +                * EBUSY is ok: this just means that another thread
> +                * already did the job.
> +                */
> +               return VM_FAULT_NOPAGE;
> +       case -ENOMEM:
> +               return VM_FAULT_OOM;
> +       default:
> +               return VM_FAULT_SIGBUS;
> +       }
> +}
> +
> +/* get mmap offset - must be called under struct_mutex */
> +int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset)
> +{
> +       int ret;
> +
> +       /* Make it mmapable */
> +       ret = drm_gem_create_mmap_offset(obj);
> +       if (ret)
> +               dev_err(obj->dev->dev, "could not allocate mmap offset\n");
> +       else
> +               *offset = drm_vma_node_offset_addr(&obj->vma_node);
> +
> +       return ret;
> +}
> +
> +/* should be called under struct_mutex.. although it can be called
> + * from atomic context without struct_mutex to acquire an extra
> + * iova ref if you know one is already held.
> + *
> + * That means when I do eventually need to add support for unpinning
> + * the refcnt counter needs to be atomic_t.
> + */
> +int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
> +       struct drm_gem_object *obj, u32 *iova)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct etnaviv_vram_mapping *mapping;
> +       int ret = 0;
> +
> +       mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
> +       if (!mapping) {
> +               struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
> +               if (IS_ERR(pages))
> +                       return PTR_ERR(pages);
> +               ret = etnaviv_iommu_map_gem(gpu->mmu, etnaviv_obj,
> +                               gpu->memory_base, &mapping);
> +       }
> +
> +       if (!ret)
> +               *iova = mapping->iova;
> +
> +       return ret;
> +}
> +
> +int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
> +       int id, u32 *iova)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct etnaviv_vram_mapping *mapping =
> +                       etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
> +       int ret;
> +
> +       /* this is safe right now because we don't unmap until the
> +        * bo is deleted:
> +        */
> +       if (mapping) {
> +               *iova = mapping->iova;
> +               return 0;
> +       }
> +
> +       mutex_lock(&obj->dev->struct_mutex);
> +       ret = etnaviv_gem_get_iova_locked(gpu, obj, iova);
> +       mutex_unlock(&obj->dev->struct_mutex);
> +
> +       return ret;
> +}
> +
> +void etnaviv_gem_put_iova(struct drm_gem_object *obj)
> +{
> +       /*
> +        * XXX TODO ..
> +        * NOTE: probably don't need a _locked() version.. we wouldn't
> +        * normally unmap here, but instead just mark that it could be
> +        * unmapped (if the iova refcnt drops to zero), but then later
> +        * if another _get_iova_locked() fails we can start unmapping
> +        * things that are no longer needed..
> +        */
> +}
> +
> +void *etnaviv_gem_vaddr_locked(struct drm_gem_object *obj)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
> +
> +       if (!etnaviv_obj->vaddr) {
> +               struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
> +
> +               if (IS_ERR(pages))
> +                       return ERR_CAST(pages);
> +
> +               etnaviv_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
> +                               VM_MAP, pgprot_writecombine(PAGE_KERNEL));
> +       }
> +
> +       return etnaviv_obj->vaddr;
> +}
> +
> +void *etnaviv_gem_vaddr(struct drm_gem_object *obj)
> +{
> +       void *ret;
> +
> +       mutex_lock(&obj->dev->struct_mutex);
> +       ret = etnaviv_gem_vaddr_locked(obj);
> +       mutex_unlock(&obj->dev->struct_mutex);
> +
> +       return ret;
> +}
> +
> +dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
> +
> +       return etnaviv_obj->paddr;
> +}
> +
> +void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
> +       struct etnaviv_gpu *gpu, u32 access, u32 fence)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       etnaviv_obj->gpu = gpu;
> +
> +       if (access & ETNA_SUBMIT_BO_READ)
> +               etnaviv_obj->read_fence = fence;
> +       if (access & ETNA_SUBMIT_BO_WRITE)
> +               etnaviv_obj->write_fence = fence;
> +
> +       etnaviv_obj->access |= access;
> +
> +       list_del_init(&etnaviv_obj->mm_list);
> +       list_add_tail(&etnaviv_obj->mm_list, &gpu->active_list);
> +}
> +
> +void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> +       etnaviv_obj->gpu = NULL;
> +       etnaviv_obj->read_fence = 0;
> +       etnaviv_obj->write_fence = 0;
> +       etnaviv_obj->access = 0;
> +       list_del_init(&etnaviv_obj->mm_list);
> +       list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
> +}
> +
> +static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
> +{
> +       if (op & ETNA_PREP_READ)
> +               return DMA_FROM_DEVICE;
> +       else if (op & ETNA_PREP_WRITE)
> +               return DMA_TO_DEVICE;
> +       else
> +               return DMA_BIDIRECTIONAL;
> +}
> +
> +int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
> +               struct timespec *timeout)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct drm_device *dev = obj->dev;
> +       int ret = 0;
> +
> +       if (is_active(etnaviv_obj)) {
> +               struct etnaviv_gpu *gpu = etnaviv_obj->gpu;
> +               u32 fence = 0;
> +
> +               if (op & ETNA_PREP_READ)
> +                       fence = etnaviv_obj->write_fence;
> +               if (op & ETNA_PREP_WRITE)
> +                       fence = max(fence, etnaviv_obj->read_fence);
> +               if (op & ETNA_PREP_NOSYNC)
> +                       timeout = NULL;
> +
> +               ret = etnaviv_gpu_wait_fence_interruptible(gpu, fence, timeout);
> +       }
> +
> +       if (etnaviv_obj->flags & ETNA_BO_CACHED) {
> +               if (!etnaviv_obj->sgt) {
> +                       void * ret;
> +
> +                       mutex_lock(&dev->struct_mutex);
> +                       ret = etnaviv_gem_get_pages(etnaviv_obj);
> +                       mutex_unlock(&dev->struct_mutex);
> +                       if (IS_ERR(ret))
> +                               return PTR_ERR(ret);
> +               }
> +
> +               dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
> +                                   etnaviv_obj->sgt->nents,
> +                                   etnaviv_op_to_dma_dir(op));
> +               etnaviv_obj->last_cpu_prep_op = op;
> +       }
> +
> +       return ret;
> +}
> +
> +int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       if (etnaviv_obj->flags & ETNA_BO_CACHED) {
> +               /* fini without a prep is almost certainly a userspace error */
> +               WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
> +               dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
> +                       etnaviv_obj->sgt->nents,
> +                       etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
> +               etnaviv_obj->last_cpu_prep_op = 0;
> +       }
> +
> +       return 0;
> +}
> +
> +int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
> +       struct timespec *timeout)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       return etnaviv_gpu_wait_obj_inactive(gpu, etnaviv_obj, timeout);
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       unsigned long off = drm_vma_node_start(&obj->vma_node);
> +
> +       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> +       seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08lx %p %zd\n",
> +                       etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
> +                       etnaviv_obj->read_fence, etnaviv_obj->write_fence,
> +                       obj->name, obj->refcount.refcount.counter,
> +                       off, etnaviv_obj->vaddr, obj->size);
> +}
> +
> +void etnaviv_gem_describe_objects(struct list_head *list, struct seq_file *m)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj;
> +       int count = 0;
> +       size_t size = 0;
> +
> +       list_for_each_entry(etnaviv_obj, list, mm_list) {
> +               struct drm_gem_object *obj = &etnaviv_obj->base;
> +
> +               seq_puts(m, "   ");
> +               etnaviv_gem_describe(obj, m);
> +               count++;
> +               size += obj->size;
> +       }
> +
> +       seq_printf(m, "Total %d objects, %zu bytes\n", count, size);
> +}
> +#endif
> +
> +static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       if (etnaviv_obj->vaddr)
> +               vunmap(etnaviv_obj->vaddr);
> +       put_pages(etnaviv_obj);
> +}
> +
> +static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {
> +       .get_pages = etnaviv_gem_shmem_get_pages,
> +       .release = etnaviv_gem_shmem_release,
> +};
> +
> +void etnaviv_gem_free_object(struct drm_gem_object *obj)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct etnaviv_vram_mapping *mapping, *tmp;
> +
> +       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> +       /* object should not be on active list: */
> +       WARN_ON(is_active(etnaviv_obj));
> +
> +       list_del(&etnaviv_obj->mm_list);
> +
> +       list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
> +                                obj_node)
> +               etnaviv_iommu_unmap_gem(mapping);
> +
> +       drm_gem_free_mmap_offset(obj);
> +       etnaviv_obj->ops->release(etnaviv_obj);
> +       reservation_object_fini(&etnaviv_obj->_resv);
> +       drm_gem_object_release(obj);
> +
> +       kfree(etnaviv_obj);
> +}
> +
> +int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       int ret;
> +
> +       ret = mutex_lock_killable(&dev->struct_mutex);
> +       if (ret)
> +               return ret;
> +
> +       list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       return 0;
> +}
> +
> +static int etnaviv_gem_new_impl(struct drm_device *dev,
> +               u32 size, u32 flags,
> +               struct drm_gem_object **obj)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj;
> +       unsigned sz = sizeof(*etnaviv_obj);
> +       bool valid = true;
> +
> +       /* validate flags */
> +       switch (flags & ETNA_BO_CACHE_MASK) {
> +       case ETNA_BO_UNCACHED:
> +       case ETNA_BO_CACHED:
> +       case ETNA_BO_WC:
> +               break;
> +       default:
> +               valid = false;
> +       }
> +
> +       if (!valid) {
> +               dev_err(dev->dev, "invalid cache flag: %x\n",
> +                       (flags & ETNA_BO_CACHE_MASK));
> +               return -EINVAL;
> +       }
> +
> +       etnaviv_obj = kzalloc(sz, GFP_KERNEL);
> +       if (!etnaviv_obj)
> +               return -ENOMEM;
> +
> +       etnaviv_obj->flags = flags;
> +
> +       etnaviv_obj->resv = &etnaviv_obj->_resv;
> +       reservation_object_init(&etnaviv_obj->_resv);
> +
> +       INIT_LIST_HEAD(&etnaviv_obj->submit_entry);
> +       INIT_LIST_HEAD(&etnaviv_obj->mm_list);
> +       INIT_LIST_HEAD(&etnaviv_obj->vram_list);
> +
> +       *obj = &etnaviv_obj->base;
> +
> +       return 0;
> +}
> +
> +static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
> +               u32 size, u32 flags)
> +{
> +       struct drm_gem_object *obj = NULL;
> +       int ret;
> +
> +       size = PAGE_ALIGN(size);
> +
> +       ret = etnaviv_gem_new_impl(dev, size, flags, &obj);
> +       if (ret)
> +               goto fail;
> +
> +       to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops;
> +       ret = drm_gem_object_init(dev, obj, size);
> +       if (ret == 0) {
> +               struct address_space *mapping;
> +
> +               /*
> +                * Our buffers are kept pinned, so allocating them
> +                * from the MOVABLE zone is a really bad idea, and
> +                * conflicts with CMA.  See coments above new_inode()
> +                * why this is required _and_ expected if you're
> +                * going to pin these pages.
> +                */
> +               mapping = file_inode(obj->filp)->i_mapping;
> +               mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
> +       }
> +
> +       if (ret)
> +               goto fail;
> +
> +       return obj;
> +
> +fail:
> +       if (obj)
> +               drm_gem_object_unreference_unlocked(obj);
> +
> +       return ERR_PTR(ret);
> +}
> +
> +/* convenience method to construct a GEM buffer object, and userspace handle */
> +int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
> +               u32 size, u32 flags, u32 *handle)
> +{
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = __etnaviv_gem_new(dev, size, flags);
> +       if (IS_ERR(obj))
> +               return PTR_ERR(obj);
> +
> +       ret = etnaviv_gem_obj_add(dev, obj);
> +       if (ret < 0) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return ret;
> +       }
> +
> +       ret = drm_gem_handle_create(file, obj, handle);
> +
> +       /* drop reference from allocate - handle holds it now */
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
> +               u32 size, u32 flags)
> +{
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = __etnaviv_gem_new(dev, size, flags);
> +       if (IS_ERR(obj))
> +               return obj;
> +
> +       ret = etnaviv_gem_obj_add(dev, obj);
> +       if (ret < 0) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return obj;
> +}
> +
> +int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
> +       struct etnaviv_gem_object **res)
> +{
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       ret = etnaviv_gem_new_impl(dev, size, flags, &obj);
> +       if (ret)
> +               return ret;
> +
> +       drm_gem_private_object_init(dev, obj, size);
> +
> +       *res = to_etnaviv_bo(obj);
> +
> +       return 0;
> +}
> +
> +struct etnaviv_vram_mapping *
> +etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
> +                            struct etnaviv_iommu *mmu)
> +{
> +       struct etnaviv_vram_mapping *mapping;
> +
> +       list_for_each_entry(mapping, &obj->vram_list, obj_node) {
> +               if (mapping->mmu == mmu)
> +                       return mapping;
> +       }
> +
> +       return NULL;
> +}
> +
> +struct get_pages_work {
> +       struct work_struct work;
> +       struct mm_struct *mm;
> +       struct task_struct *task;
> +       struct etnaviv_gem_object *etnaviv_obj;
> +};
> +
> +static struct page **etnaviv_gem_userptr_do_get_pages(
> +       struct etnaviv_gem_object *etnaviv_obj, struct mm_struct *mm, struct task_struct *task)
> +{
> +       int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +       struct page **pvec;
> +       uintptr_t ptr;
> +
> +       pvec = drm_malloc_ab(npages, sizeof(struct page *));
> +       if (!pvec)
> +               return ERR_PTR(-ENOMEM);
> +
> +       pinned = 0;
> +       ptr = etnaviv_obj->userptr.ptr;
> +
> +       down_read(&mm->mmap_sem);
> +       while (pinned < npages) {
> +               ret = get_user_pages(task, mm, ptr, npages - pinned,
> +                                    !etnaviv_obj->userptr.ro, 0,
> +                                    pvec + pinned, NULL);
> +               if (ret < 0)
> +                       break;
> +
> +               ptr += ret * PAGE_SIZE;
> +               pinned += ret;
> +       }
> +       up_read(&mm->mmap_sem);
> +
> +       if (ret < 0) {
> +               release_pages(pvec, pinned, 0);
> +               drm_free_large(pvec);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return pvec;
> +}
> +
> +static void __etnaviv_gem_userptr_get_pages(struct work_struct *_work)
> +{
> +       struct get_pages_work *work = container_of(_work, typeof(*work), work);
> +       struct etnaviv_gem_object *etnaviv_obj = work->etnaviv_obj;
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct page **pvec;
> +
> +       pvec = etnaviv_gem_userptr_do_get_pages(etnaviv_obj, work->mm, work->task);
> +
> +       mutex_lock(&dev->struct_mutex);
> +       if (IS_ERR(pvec)) {
> +               etnaviv_obj->userptr.work = ERR_CAST(pvec);
> +       } else {
> +               etnaviv_obj->userptr.work = NULL;
> +               etnaviv_obj->pages = pvec;
> +       }
> +
> +       drm_gem_object_unreference(&etnaviv_obj->base);
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       mmput(work->mm);
> +       put_task_struct(work->task);
> +       kfree(work);
> +}
> +
> +static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct page **pvec = NULL;
> +       struct get_pages_work *work;
> +       struct mm_struct *mm;
> +       int ret, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +
> +       if (etnaviv_obj->userptr.work) {
> +               if (IS_ERR(etnaviv_obj->userptr.work)) {
> +                       ret = PTR_ERR(etnaviv_obj->userptr.work);
> +                       etnaviv_obj->userptr.work = NULL;
> +               } else {
> +                       ret = -EAGAIN;
> +               }
> +               return ret;
> +       }
> +
> +       mm = get_task_mm(etnaviv_obj->userptr.task);
> +       pinned = 0;
> +       if (mm == current->mm) {
> +               pvec = drm_malloc_ab(npages, sizeof(struct page *));
> +               if (!pvec) {
> +                       mmput(mm);
> +                       return -ENOMEM;
> +               }
> +
> +               pinned = __get_user_pages_fast(etnaviv_obj->userptr.ptr, npages,
> +                                              !etnaviv_obj->userptr.ro, pvec);
> +               if (pinned < 0) {
> +                       drm_free_large(pvec);
> +                       mmput(mm);
> +                       return pinned;
> +               }
> +
> +               if (pinned == npages) {
> +                       etnaviv_obj->pages = pvec;
> +                       mmput(mm);
> +                       return 0;
> +               }
> +       }
> +
> +       release_pages(pvec, pinned, 0);
> +       drm_free_large(pvec);
> +
> +       work = kmalloc(sizeof(*work), GFP_KERNEL);
> +       if (!work) {
> +               mmput(mm);
> +               return -ENOMEM;
> +       }
> +
> +       get_task_struct(current);
> +       drm_gem_object_reference(&etnaviv_obj->base);
> +
> +       work->mm = mm;
> +       work->task = current;
> +       work->etnaviv_obj = etnaviv_obj;
> +
> +       etnaviv_obj->userptr.work = &work->work;
> +       INIT_WORK(&work->work, __etnaviv_gem_userptr_get_pages);
> +
> +       etnaviv_queue_work(etnaviv_obj->base.dev, &work->work);
> +
> +       return -EAGAIN;
> +}
> +
> +static void etnaviv_gem_userptr_release(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       if (etnaviv_obj->sgt) {
> +               etnaviv_gem_scatterlist_unmap(etnaviv_obj);
> +               sg_free_table(etnaviv_obj->sgt);
> +               kfree(etnaviv_obj->sgt);
> +       }
> +       if (etnaviv_obj->pages) {
> +               int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +
> +               release_pages(etnaviv_obj->pages, npages, 0);
> +               drm_free_large(etnaviv_obj->pages);
> +       }
> +       put_task_struct(etnaviv_obj->userptr.task);
> +}
> +
> +static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops = {
> +       .get_pages = etnaviv_gem_userptr_get_pages,
> +       .release = etnaviv_gem_userptr_release,
> +};
> +
> +int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
> +       uintptr_t ptr, u32 size, u32 flags, u32 *handle)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj;
> +       int ret;
> +
> +       ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, &etnaviv_obj);
> +       if (ret)
> +               return ret;
> +
> +       etnaviv_obj->ops = &etnaviv_gem_userptr_ops;
> +       etnaviv_obj->userptr.ptr = ptr;
> +       etnaviv_obj->userptr.task = current;
> +       etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);
> +       get_task_struct(current);
> +
> +       ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
> +       if (ret) {
> +               drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
> +               return ret;
> +       }
> +
> +       ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);
> +
> +       /* drop reference from allocate - handle holds it now */
> +       drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
> +
> +       return ret;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
> new file mode 100644
> index 000000000000..c991d12e7aed
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem.h
> @@ -0,0 +1,141 @@
> +/*
> + * 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 etnaviv_gem_object *object;
> +       struct etnaviv_iommu *mmu;
> +       struct drm_mm_node vram_node;
> +       u32 iova;
> +};
> +
> +struct etnaviv_gem_object {
> +       struct drm_gem_object base;
> +       const struct etnaviv_gem_ops *ops;
> +
> +       u32 flags;
> +
> +       /* And object is either:
> +        *  inactive - on priv->inactive_list
> +        *  active   - on one one of the gpu's active_list..  well, at
> +        *     least for now we don't have (I don't think) hw sync between
> +        *     2d and 3d one devices which have both, meaning we need to
> +        *     block on submit if a bo is already on other ring
> +        *
> +        */
> +       struct list_head mm_list;
> +       struct etnaviv_gpu *gpu;     /* non-null if active */
> +       u32 access;
> +       u32 read_fence, write_fence;
> +
> +       /* Transiently in the process of submit ioctl, objects associated
> +        * with the submit are on submit->bo_list.. this only lasts for
> +        * the duration of the ioctl, so one bo can never be on multiple
> +        * submit lists.
> +        */
> +       struct list_head submit_entry;
> +
> +       struct page **pages;
> +       struct sg_table *sgt;
> +       void *vaddr;
> +
> +       /* for ETNA_BO_CMDSTREAM */
> +       dma_addr_t paddr;
> +
> +       /* normally (resv == &_resv) except for imported bo's */
> +       struct reservation_object *resv;
> +       struct reservation_object _resv;
> +
> +       struct list_head vram_list;
> +
> +       /* for buffer manipulation during submit */
> +       bool is_ring_buffer;
> +       u32 offset;
> +
> +       /* cache maintenance */
> +       uint32_t 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 etnaviv_obj->gpu != NULL;
> +}
> +
> +#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;
> +       u32 exec_state;
> +       struct list_head bo_list;
> +       struct ww_acquire_ctx ticket;
> +       u32 fence;
> +       unsigned int nr_bos;
> +       struct etnaviv_cmdbuf *cmdbuf;
> +       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);
> +struct etnaviv_vram_mapping *
> +etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
> +                            struct etnaviv_iommu *mmu);
> +int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
> +       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__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_gem_prime.c b/drivers/staging/etnaviv/etnaviv_gem_prime.c
> new file mode 100644
> index 000000000000..58c13ae7c345
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem_prime.c
> @@ -0,0 +1,121 @@
> +/*
> + * 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 drm_device *dev = obj->dev;
> +
> +               mutex_lock(&dev->struct_mutex);
> +               etnaviv_gem_get_pages(to_etnaviv_bo(obj));
> +               mutex_unlock(&dev->struct_mutex);
> +       }
> +       return 0;
> +}
> +
> +void etnaviv_gem_prime_unpin(struct drm_gem_object *obj)
> +{
> +       if (!obj->import_attach) {
> +               struct drm_device *dev = obj->dev;
> +
> +               mutex_lock(&dev->struct_mutex);
> +               etnaviv_gem_put_pages(to_etnaviv_bo(obj));
> +               mutex_unlock(&dev->struct_mutex);
> +       }
> +}
> +
> +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, &etnaviv_obj);
> +       if (ret < 0)
> +               return ERR_PTR(ret);
> +
> +       npages = size / PAGE_SIZE;
> +
> +       etnaviv_obj->ops = &etnaviv_gem_prime_ops;
> +       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);
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
> new file mode 100644
> index 000000000000..f886a3c66d30
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
> @@ -0,0 +1,421 @@
> +/*
> + * 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 "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, int nr)
> +{
> +       struct etnaviv_gem_submit *submit;
> +       int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0]));
> +
> +       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;
> +               submit->cmdbuf = NULL;
> +
> +               INIT_LIST_HEAD(&submit->bo_list);
> +               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;
> +               struct etnaviv_gem_object *etnaviv_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;
> +               }
> +
> +               etnaviv_obj = to_etnaviv_bo(obj);
> +
> +               if (!list_empty(&etnaviv_obj->submit_entry)) {
> +                       DRM_ERROR("handle %u at index %u already on submit list\n",
> +                                 bo->handle, i);
> +                       ret = -EINVAL;
> +                       goto out_unlock;
> +               }
> +
> +               drm_gem_object_reference(obj);
> +
> +               submit->bos[i].obj = etnaviv_obj;
> +
> +               list_add_tail(&etnaviv_obj->submit_entry, &submit->bo_list);
> +       }
> +
> +out_unlock:
> +       submit->nr_bos = i;
> +       spin_unlock(&file->table_lock);
> +
> +       return ret;
> +}
> +
> +static void submit_unlock_unpin_bo(struct etnaviv_gem_submit *submit, int i)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
> +
> +       if (submit->bos[i].flags & BO_PINNED)
> +               etnaviv_gem_put_iova(&etnaviv_obj->base);
> +
> +       if (submit->bos[i].flags & BO_LOCKED)
> +               ww_mutex_unlock(&etnaviv_obj->resv->lock);
> +
> +       submit->bos[i].iova = 0;
> +       submit->bos[i].flags &= ~(BO_LOCKED | BO_PINNED);
> +}
> +
> +/* This is where we make sure all the bo's are reserved and pin'd: */
> +static int submit_validate_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;
> +               u32 iova;
> +
> +               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)
> +                               goto fail;
> +                       submit->bos[i].flags |= BO_LOCKED;
> +               }
> +
> +
> +               /* if locking succeeded, pin bo: */
> +               ret = etnaviv_gem_get_iova_locked(submit->gpu,
> +                                                 &etnaviv_obj->base, &iova);
> +
> +               /* this would break the logic in the fail path.. there is no
> +                * reason for this to happen, but just to be on the safe side
> +                * let's notice if this starts happening in the future:
> +                */
> +               WARN_ON(ret == -EDEADLK);
> +
> +               if (ret)
> +                       goto fail;
> +
> +               submit->bos[i].flags |= BO_PINNED;
> +               submit->bos[i].iova = iova;
> +       }
> +
> +       ww_acquire_done(&submit->ticket);
> +
> +       return 0;
> +
> +fail:
> +       for (; i >= 0; i--)
> +               submit_unlock_unpin_bo(submit, i);
> +
> +       if (slow_locked > 0)
> +               submit_unlock_unpin_bo(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_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, u32 nr_relocs, u64 relocs)
> +{
> +       u32 i, last_offset = 0;
> +       u32 *ptr = stream;
> +       int ret;
> +
> +       for (i = 0; i < nr_relocs; i++) {
> +               struct drm_etnaviv_gem_submit_reloc submit_reloc;
> +               struct etnaviv_gem_object *bobj;
> +               void __user *userptr =
> +                       to_user_ptr(relocs + (i * sizeof(submit_reloc)));
> +               u32 iova, off;
> +
> +               ret = copy_from_user(&submit_reloc, userptr,
> +                                    sizeof(submit_reloc));
> +               if (ret)
> +                       return -EFAULT;
> +
> +               if (submit_reloc.submit_offset % 4) {
> +                       DRM_ERROR("non-aligned reloc offset: %u\n",
> +                                       submit_reloc.submit_offset);
> +                       return -EINVAL;
> +               }
> +
> +               /* offset in dwords: */
> +               off = submit_reloc.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, submit_reloc.reloc_idx, &bobj, &iova);
> +               if (ret)
> +                       return ret;
> +
> +               if (submit_reloc.reloc_offset >=
> +                   bobj->base.size - sizeof(*ptr)) {
> +                       DRM_ERROR("relocation %u outside object", i);
> +                       return -EINVAL;
> +               }
> +
> +               ptr[off] = iova + submit_reloc.reloc_offset;
> +
> +               last_offset = off;
> +       }
> +
> +       return 0;
> +}
> +
> +static void submit_cleanup(struct etnaviv_gem_submit *submit, bool fail)
> +{
> +       unsigned i;
> +
> +       for (i = 0; i < submit->nr_bos; i++) {
> +               struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
> +
> +               submit_unlock_unpin_bo(submit, i);
> +               list_del_init(&etnaviv_obj->submit_entry);
> +               drm_gem_object_unreference(&etnaviv_obj->base);
> +       }
> +
> +       if (submit->cmdbuf)
> +               etnaviv_gpu_cmdbuf_free(submit->cmdbuf);
> +
> +       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 etnaviv_file_private *ctx = file->driver_priv;
> +       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;
> +       }
> +
> +       /*
> +        * Copy the command submission and bo array to kernel space in
> +        * one go, and do this outside of the dev->struct_mutex lock.
> +        */
> +       bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
> +       stream = drm_malloc_ab(1, args->stream_size);
> +       cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8);
> +       if (!bos || !stream || !cmdbuf) {
> +               ret = -ENOMEM;
> +               goto err_submit_cmds;
> +       }
> +
> +       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(stream, to_user_ptr(args->stream),
> +                            args->stream_size);
> +       if (ret) {
> +               ret = -EFAULT;
> +               goto err_submit_cmds;
> +       }
> +
> +       /*
> +        * Avoid big circular locking dependency loops:
> +        * - reading debugfs results in mmap_sem depending on i_mutex_key#3
> +        *   (iterate_dir -> filldir64)
> +        * - struct_mutex depends on mmap_sem
> +        *   (vm_mmap_pgoff -> drm_gem_mmap)
> +        * then if we try to do a get_sync() under struct_mutex,
> +        * - genpd->lock depends on struct_mutex
> +        *   (etnaviv_ioctl_gem_submit -> pm_genpd_runtime_resume)
> +        * - (regulator) rdev->mutex depends on genpd->lock
> +        *   (pm_genpd_poweron -> regulator_enable)
> +        * - i_mutex_key#3 depends on rdev->mutex
> +        *   (create_regulator -> debugfs::start_creating)
> +        * and lockdep rightfully explodes.
> +        *
> +        * Avoid this by getting runtime PM outside of the struct_mutex lock.
> +        */
> +       ret = etnaviv_gpu_pm_get_sync(gpu);
> +       if (ret < 0)
> +               goto err_submit_cmds;
> +
> +       mutex_lock(&dev->struct_mutex);
> +
> +       submit = submit_create(dev, gpu, args->nr_bos);
> +       if (!submit) {
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +       submit->exec_state = args->exec_state;
> +
> +       ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
> +       if (ret)
> +               goto out;
> +
> +       ret = submit_validate_objects(submit);
> +       if (ret)
> +               goto out;
> +
> +       if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4)) {
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = submit_reloc(submit, stream, args->stream_size / 4,
> +                          args->nr_relocs, args->relocs);
> +       if (ret)
> +               goto out;
> +
> +       memcpy(cmdbuf->vaddr, stream, args->stream_size);
> +       cmdbuf->user_size = ALIGN(args->stream_size, 8);
> +       /* transfer ownership of cmdbuf to submit */
> +       submit->cmdbuf = cmdbuf;
> +       cmdbuf = NULL;
> +
> +       ret = etnaviv_gpu_submit(gpu, submit, ctx);
> +
> +       args->fence = submit->fence;
> +
> +out:
> +       if (submit)
> +               submit_cleanup(submit, !!ret);
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       etnaviv_gpu_pm_put(gpu);
> +
> +       /*
> +        * If we're returning -EAGAIN, it could be due to the userptr code
> +        * wanting to run its workqueue outside of the struct_mutex.
> +        * Flush our workqueue to ensure that it is run in a timely manner.
> +        */
> +       if (ret == -EAGAIN)
> +               flush_workqueue(priv->wq);
> +
> +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);
> +
> +       return ret;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
> new file mode 100644
> index 000000000000..e12fe3508db2
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gpu.c
> @@ -0,0 +1,1468 @@
> +/*
> + * 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/component.h>
> +#include <linux/of_device.h>
> +#include "etnaviv_gpu.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_mmu.h"
> +#include "etnaviv_iommu.h"
> +#include "etnaviv_iommu_v2.h"
> +#include "common.xml.h"
> +#include "state.xml.h"
> +#include "state_hi.xml.h"
> +#include "cmdstream.xml.h"
> +
> +static const struct platform_device_id gpu_ids[] = {
> +       { .name = "etnaviv-gpu,2d" },
> +       { },
> +};
> +
> +/*
> + * Driver functions:
> + */
> +
> +int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
> +{
> +       switch (param) {
> +       case ETNAVIV_PARAM_GPU_MODEL:
> +               *value = gpu->identity.model;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_REVISION:
> +               *value = gpu->identity.revision;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_0:
> +               *value = gpu->identity.features;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_1:
> +               *value = gpu->identity.minor_features0;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_2:
> +               *value = gpu->identity.minor_features1;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_3:
> +               *value = gpu->identity.minor_features2;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_4:
> +               *value = gpu->identity.minor_features3;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_STREAM_COUNT:
> +               *value = gpu->identity.stream_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_REGISTER_MAX:
> +               *value = gpu->identity.register_max;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_THREAD_COUNT:
> +               *value = gpu->identity.thread_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE:
> +               *value = gpu->identity.vertex_cache_size;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT:
> +               *value = gpu->identity.shader_core_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_PIXEL_PIPES:
> +               *value = gpu->identity.pixel_pipes;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE:
> +               *value = gpu->identity.vertex_output_buffer_size;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_BUFFER_SIZE:
> +               *value = gpu->identity.buffer_size;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT:
> +               *value = gpu->identity.instruction_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_NUM_CONSTANTS:
> +               *value = gpu->identity.num_constants;
> +               break;
> +
> +       default:
> +               DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void etnaviv_hw_specs(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->identity.minor_features0 &
> +           chipMinorFeatures0_MORE_MINOR_FEATURES) {
> +               u32 specs[2];
> +
> +               specs[0] = gpu_read(gpu, VIVS_HI_CHIP_SPECS);
> +               specs[1] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_2);
> +
> +               gpu->identity.stream_count =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT;
> +               gpu->identity.register_max =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT;
> +               gpu->identity.thread_count =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT;
> +               gpu->identity.vertex_cache_size =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT;
> +               gpu->identity.shader_core_count =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT;
> +               gpu->identity.pixel_pipes =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT;
> +               gpu->identity.vertex_output_buffer_size =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT;
> +
> +               gpu->identity.buffer_size =
> +                       (specs[1] & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT;
> +               gpu->identity.instruction_count =
> +                       (specs[1] & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT;
> +               gpu->identity.num_constants =
> +                       (specs[1] & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT;
> +
> +               gpu->identity.register_max = 1 << gpu->identity.register_max;
> +               gpu->identity.thread_count = 1 << gpu->identity.thread_count;
> +               gpu->identity.vertex_output_buffer_size =
> +                       1 << gpu->identity.vertex_output_buffer_size;
> +       } else {
> +               dev_err(gpu->dev, "TODO: determine GPU specs based on model\n");
> +       }
> +
> +       switch (gpu->identity.instruction_count) {
> +       case 0:
> +               if ((gpu->identity.model == 0x2000 &&
> +                    gpu->identity.revision == 0x5108) ||
> +                   gpu->identity.model == 0x880)
> +                       gpu->identity.instruction_count = 512;
> +               else
> +                       gpu->identity.instruction_count = 256;
> +               break;
> +
> +       case 1:
> +               gpu->identity.instruction_count = 1024;
> +               break;
> +
> +       case 2:
> +               gpu->identity.instruction_count = 2048;
> +               break;
> +
> +       default:
> +               gpu->identity.instruction_count = 256;
> +               break;
> +       }
> +}
> +
> +static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
> +{
> +       u32 chipIdentity;
> +
> +       chipIdentity = gpu_read(gpu, VIVS_HI_CHIP_IDENTITY);
> +
> +       /* Special case for older graphic cores. */
> +       if (VIVS_HI_CHIP_IDENTITY_FAMILY(chipIdentity) ==  0x01) {
> +               gpu->identity.model    = 0x500; /* gc500 */
> +               gpu->identity.revision = VIVS_HI_CHIP_IDENTITY_REVISION(chipIdentity);
> +       } else {
> +
> +               gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL);
> +               gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV);
> +
> +               /*
> +                * !!!! HACK ALERT !!!!
> +                * Because people change device IDs without letting software
> +                * know about it - here is the hack to make it all look the
> +                * same.  Only for GC400 family.
> +                */
> +               if ((gpu->identity.model & 0xff00) == 0x0400 &&
> +                   gpu->identity.model != 0x0420) {
> +                       gpu->identity.model = gpu->identity.model & 0x0400;
> +               }
> +
> +               /* Another special case */
> +               if (gpu->identity.model == 0x300 &&
> +                   gpu->identity.revision == 0x2201) {
> +                       u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE);
> +                       u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME);
> +
> +                       if (chipDate == 0x20080814 && chipTime == 0x12051100) {
> +                               /*
> +                                * This IP has an ECO; put the correct
> +                                * revision in it.
> +                                */
> +                               gpu->identity.revision = 0x1051;
> +                       }
> +               }
> +       }
> +
> +       dev_info(gpu->dev, "model: GC%x, revision: %x\n",
> +                gpu->identity.model, gpu->identity.revision);
> +
> +       gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE);
> +
> +       /* Disable fast clear on GC700. */
> +       if (gpu->identity.model == 0x700)
> +               gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
> +
> +       if ((gpu->identity.model == 0x500 && gpu->identity.revision < 2) ||
> +           (gpu->identity.model == 0x300 && gpu->identity.revision < 0x2000)) {
> +
> +               /*
> +                * GC500 rev 1.x and GC300 rev < 2.0 doesn't have these
> +                * registers.
> +                */
> +               gpu->identity.minor_features0 = 0;
> +               gpu->identity.minor_features1 = 0;
> +               gpu->identity.minor_features2 = 0;
> +               gpu->identity.minor_features3 = 0;
> +       } else
> +               gpu->identity.minor_features0 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_0);
> +
> +       if (gpu->identity.minor_features0 &
> +           chipMinorFeatures0_MORE_MINOR_FEATURES) {
> +               gpu->identity.minor_features1 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_1);
> +               gpu->identity.minor_features2 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_2);
> +               gpu->identity.minor_features3 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3);
> +       }
> +
> +       /* GC600 idle register reports zero bits where modules aren't present */
> +       if (gpu->identity.model == chipModel_GC600) {
> +               gpu->idle_mask = VIVS_HI_IDLE_STATE_TX |
> +                                VIVS_HI_IDLE_STATE_RA |
> +                                VIVS_HI_IDLE_STATE_SE |
> +                                VIVS_HI_IDLE_STATE_PA |
> +                                VIVS_HI_IDLE_STATE_SH |
> +                                VIVS_HI_IDLE_STATE_PE |
> +                                VIVS_HI_IDLE_STATE_DE |
> +                                VIVS_HI_IDLE_STATE_FE;
> +       } else {
> +               gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP;
> +       }
> +
> +       etnaviv_hw_specs(gpu);
> +}
> +
> +static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock)
> +{
> +       gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock |
> +                 VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD);
> +       gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
> +}
> +
> +static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
> +{
> +       u32 control, idle;
> +       unsigned long timeout;
> +       bool failed = true;
> +
> +       /* TODO
> +        *
> +        * - clock gating
> +        * - puls eater
> +        * - what about VG?
> +        */
> +
> +       /* We hope that the GPU resets in under one second */
> +       timeout = jiffies + msecs_to_jiffies(1000);
> +
> +       while (time_is_after_jiffies(timeout)) {
> +               control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
> +                         VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
> +
> +               /* enable clock */
> +               etnaviv_gpu_load_clock(gpu, control);
> +
> +               /* Wait for stable clock.  Vivante's code waited for 1ms */
> +               usleep_range(1000, 10000);
> +
> +               /* isolate the GPU. */
> +               control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* set soft reset. */
> +               control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* wait for reset. */
> +               msleep(1);
> +
> +               /* reset soft reset bit. */
> +               control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* reset GPU isolation. */
> +               control &= ~VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* read idle register. */
> +               idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +
> +               /* try reseting again if FE it not idle */
> +               if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) {
> +                       dev_dbg(gpu->dev, "FE is not idle\n");
> +                       continue;
> +               }
> +
> +               /* read reset register. */
> +               control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
> +
> +               /* is the GPU idle? */
> +               if (((control & VIVS_HI_CLOCK_CONTROL_IDLE_3D) == 0) ||
> +                   ((control & VIVS_HI_CLOCK_CONTROL_IDLE_2D) == 0)) {
> +                       dev_dbg(gpu->dev, "GPU is not idle\n");
> +                       continue;
> +               }
> +
> +               failed = false;
> +               break;
> +       }
> +
> +       if (failed) {
> +               idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +               control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
> +
> +               dev_err(gpu->dev, "GPU failed to reset: FE %sidle, 3D %sidle, 2D %sidle\n",
> +                       idle & VIVS_HI_IDLE_STATE_FE ? "" : "not ",
> +                       control & VIVS_HI_CLOCK_CONTROL_IDLE_3D ? "" : "not ",
> +                       control & VIVS_HI_CLOCK_CONTROL_IDLE_2D ? "" : "not ");
> +
> +               return -EBUSY;
> +       }
> +
> +       /* We rely on the GPU running, so program the clock */
> +       control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
> +                 VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
> +
> +       /* enable clock */
> +       etnaviv_gpu_load_clock(gpu, control);
> +
> +       return 0;
> +}
> +
> +static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
> +{
> +       u16 prefetch;
> +
> +       if (gpu->identity.model == chipModel_GC320 &&
> +           gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400 &&
> +           (gpu->identity.revision == 0x5007 ||
> +            gpu->identity.revision == 0x5220)) {
> +               u32 mc_memory_debug;
> +
> +               mc_memory_debug = gpu_read(gpu, VIVS_MC_DEBUG_MEMORY) & ~0xff;
> +
> +               if (gpu->identity.revision == 0x5007)
> +                       mc_memory_debug |= 0x0c;
> +               else
> +                       mc_memory_debug |= 0x08;
> +
> +               gpu_write(gpu, VIVS_MC_DEBUG_MEMORY, mc_memory_debug);
> +       }
> +
> +       /*
> +        * Update GPU AXI cache atttribute to "cacheable, no allocate".
> +        * This is necessary to prevent the iMX6 SoC locking up.
> +        */
> +       gpu_write(gpu, VIVS_HI_AXI_CONFIG,
> +                 VIVS_HI_AXI_CONFIG_AWCACHE(2) |
> +                 VIVS_HI_AXI_CONFIG_ARCACHE(2));
> +
> +       /* GC2000 rev 5108 needs a special bus config */
> +       if (gpu->identity.model == 0x2000 && gpu->identity.revision == 0x5108) {
> +               u32 bus_config = gpu_read(gpu, VIVS_MC_BUS_CONFIG);
> +               bus_config &= ~(VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK |
> +                               VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK);
> +               bus_config |= VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(1) |
> +                             VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(0);
> +               gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config);
> +       }
> +
> +       /* set base addresses */
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
> +
> +       /* setup the MMU page table pointers */
> +       etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain);
> +
> +       /* Start command processor */
> +       prefetch = etnaviv_buffer_init(gpu);
> +
> +       gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
> +       gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS,
> +                 gpu->buffer->paddr - gpu->memory_base);
> +       gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
> +                 VIVS_FE_COMMAND_CONTROL_ENABLE |
> +                 VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
> +}
> +
> +int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
> +{
> +       int ret, i;
> +       struct iommu_domain *iommu;
> +       enum etnaviv_iommu_version version;
> +       bool mmuv2;
> +
> +       ret = pm_runtime_get_sync(gpu->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       etnaviv_hw_identify(gpu);
> +
> +       if (gpu->identity.model == 0) {
> +               dev_err(gpu->dev, "Unknown GPU model\n");
> +               pm_runtime_put_autosuspend(gpu->dev);
> +               return -ENXIO;
> +       }
> +
> +       ret = etnaviv_hw_reset(gpu);
> +       if (ret)
> +               goto fail;
> +
> +       /* Setup IOMMU.. eventually we will (I think) do this once per context
> +        * and have separate page tables per context.  For now, to keep things
> +        * simple and to get something working, just use a single address space:
> +        */
> +       mmuv2 = gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION;
> +       dev_dbg(gpu->dev, "mmuv2: %d\n", mmuv2);
> +
> +       if (!mmuv2) {
> +               iommu = etnaviv_iommu_domain_alloc(gpu);
> +               version = ETNAVIV_IOMMU_V1;
> +       } else {
> +               iommu = etnaviv_iommu_v2_domain_alloc(gpu);
> +               version = ETNAVIV_IOMMU_V2;
> +       }
> +
> +       if (!iommu) {
> +               ret = -ENOMEM;
> +               goto fail;
> +       }
> +
> +       /* TODO: we will leak here memory - fix it! */
> +
> +       gpu->mmu = etnaviv_iommu_new(gpu->dev, iommu, version);
> +       if (!gpu->mmu) {
> +               ret = -ENOMEM;
> +               goto fail;
> +       }
> +
> +       /* Create buffer: */
> +       gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE);
> +       if (!gpu->buffer) {
> +               ret = -ENOMEM;
> +               dev_err(gpu->dev, "could not create command buffer\n");
> +               goto fail;
> +       }
> +
> +       /* Setup event management */
> +       spin_lock_init(&gpu->event_spinlock);
> +       init_completion(&gpu->event_free);
> +       for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
> +               gpu->event[i].used = false;
> +               complete(&gpu->event_free);
> +       }
> +
> +       /* Now program the hardware */
> +       mutex_lock(&gpu->drm->struct_mutex);
> +       etnaviv_gpu_hw_init(gpu);
> +       mutex_unlock(&gpu->drm->struct_mutex);
> +
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return 0;
> +
> +fail:
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return ret;
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct dma_debug {
> +       u32 address[2];
> +       u32 state[2];
> +};
> +
> +static void verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug)
> +{
> +       u32 i;
> +
> +       debug->address[0] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
> +       debug->state[0]   = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
> +
> +       for (i = 0; i < 500; i++) {
> +               debug->address[1] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
> +               debug->state[1]   = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
> +
> +               if (debug->address[0] != debug->address[1])
> +                       break;
> +
> +               if (debug->state[0] != debug->state[1])
> +                       break;
> +       }
> +}
> +
> +int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
> +{
> +       struct dma_debug debug;
> +       u32 dma_lo, dma_hi, axi, idle;
> +       int ret;
> +
> +       seq_printf(m, "%s Status:\n", dev_name(gpu->dev));
> +
> +       ret = pm_runtime_get_sync(gpu->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = mutex_lock_interruptible(&gpu->drm->struct_mutex);
> +       if (ret < 0)
> +               goto err_rpm;
> +
> +       dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW);
> +       dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH);
> +       axi = gpu_read(gpu, VIVS_HI_AXI_STATUS);
> +       idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +
> +       verify_dma(gpu, &debug);
> +
> +       seq_puts(m, "\tfeatures\n");
> +       seq_printf(m, "\t minor_features0: 0x%08x\n",
> +                  gpu->identity.minor_features0);
> +       seq_printf(m, "\t minor_features1: 0x%08x\n",
> +                  gpu->identity.minor_features1);
> +       seq_printf(m, "\t minor_features2: 0x%08x\n",
> +                  gpu->identity.minor_features2);
> +       seq_printf(m, "\t minor_features3: 0x%08x\n",
> +                  gpu->identity.minor_features3);
> +
> +       seq_puts(m, "\tspecs\n");
> +       seq_printf(m, "\t stream_count:  %d\n",
> +                       gpu->identity.stream_count);
> +       seq_printf(m, "\t register_max: %d\n",
> +                       gpu->identity.register_max);
> +       seq_printf(m, "\t thread_count: %d\n",
> +                       gpu->identity.thread_count);
> +       seq_printf(m, "\t vertex_cache_size: %d\n",
> +                       gpu->identity.vertex_cache_size);
> +       seq_printf(m, "\t shader_core_count: %d\n",
> +                       gpu->identity.shader_core_count);
> +       seq_printf(m, "\t pixel_pipes: %d\n",
> +                       gpu->identity.pixel_pipes);
> +       seq_printf(m, "\t vertex_output_buffer_size: %d\n",
> +                       gpu->identity.vertex_output_buffer_size);
> +       seq_printf(m, "\t buffer_size: %d\n",
> +                       gpu->identity.buffer_size);
> +       seq_printf(m, "\t instruction_count: %d\n",
> +                       gpu->identity.instruction_count);
> +       seq_printf(m, "\t num_constants: %d\n",
> +                       gpu->identity.num_constants);
> +
> +       seq_printf(m, "\taxi: 0x%08x\n", axi);
> +       seq_printf(m, "\tidle: 0x%08x\n", idle);
> +       idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP;
> +       if ((idle & VIVS_HI_IDLE_STATE_FE) == 0)
> +               seq_puts(m, "\t FE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_DE) == 0)
> +               seq_puts(m, "\t DE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_PE) == 0)
> +               seq_puts(m, "\t PE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_SH) == 0)
> +               seq_puts(m, "\t SH is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_PA) == 0)
> +               seq_puts(m, "\t PA is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_SE) == 0)
> +               seq_puts(m, "\t SE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_RA) == 0)
> +               seq_puts(m, "\t RA is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_TX) == 0)
> +               seq_puts(m, "\t TX is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_VG) == 0)
> +               seq_puts(m, "\t VG is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_IM) == 0)
> +               seq_puts(m, "\t IM is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_FP) == 0)
> +               seq_puts(m, "\t FP is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_TS) == 0)
> +               seq_puts(m, "\t TS is not idle\n");
> +       if (idle & VIVS_HI_IDLE_STATE_AXI_LP)
> +               seq_puts(m, "\t AXI low power mode\n");
> +
> +       if (gpu->identity.features & chipFeatures_DEBUG_MODE) {
> +               u32 read0 = gpu_read(gpu, VIVS_MC_DEBUG_READ0);
> +               u32 read1 = gpu_read(gpu, VIVS_MC_DEBUG_READ1);
> +               u32 write = gpu_read(gpu, VIVS_MC_DEBUG_WRITE);
> +
> +               seq_puts(m, "\tMC\n");
> +               seq_printf(m, "\t read0: 0x%08x\n", read0);
> +               seq_printf(m, "\t read1: 0x%08x\n", read1);
> +               seq_printf(m, "\t write: 0x%08x\n", write);
> +       }
> +
> +       seq_puts(m, "\tDMA ");
> +
> +       if (debug.address[0] == debug.address[1] &&
> +           debug.state[0] == debug.state[1]) {
> +               seq_puts(m, "seems to be stuck\n");
> +       } else if (debug.address[0] == debug.address[1]) {
> +               seq_puts(m, "adress is constant\n");
> +       } else {
> +               seq_puts(m, "is runing\n");
> +       }
> +
> +       seq_printf(m, "\t address 0: 0x%08x\n", debug.address[0]);
> +       seq_printf(m, "\t address 1: 0x%08x\n", debug.address[1]);
> +       seq_printf(m, "\t state 0: 0x%08x\n", debug.state[0]);
> +       seq_printf(m, "\t state 1: 0x%08x\n", debug.state[1]);
> +       seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n",
> +                  dma_lo, dma_hi);
> +
> +       ret = 0;
> +
> +       mutex_unlock(&gpu->drm->struct_mutex);
> +
> +err_rpm:
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return ret;
> +}
> +#endif
> +
> +/*
> + * Power Management:
> + */
> +static int enable_clk(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_core)
> +               clk_prepare_enable(gpu->clk_core);
> +       if (gpu->clk_shader)
> +               clk_prepare_enable(gpu->clk_shader);
> +
> +       return 0;
> +}
> +
> +static int disable_clk(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_core)
> +               clk_disable_unprepare(gpu->clk_core);
> +       if (gpu->clk_shader)
> +               clk_disable_unprepare(gpu->clk_shader);
> +
> +       return 0;
> +}
> +
> +static int enable_axi(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_bus)
> +               clk_prepare_enable(gpu->clk_bus);
> +
> +       return 0;
> +}
> +
> +static int disable_axi(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_bus)
> +               clk_disable_unprepare(gpu->clk_bus);
> +
> +       return 0;
> +}
> +
> +/*
> + * Hangcheck detection for locked gpu:
> + */
> +static void recover_worker(struct work_struct *work)
> +{
> +       struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
> +                                              recover_work);
> +       struct drm_device *dev = gpu->drm;
> +       unsigned long flags;
> +       unsigned int i;
> +
> +       dev_err(gpu->dev, "hangcheck recover!\n");
> +
> +       if (pm_runtime_get_sync(gpu->dev) < 0)
> +               return;
> +
> +       mutex_lock(&dev->struct_mutex);
> +
> +       etnaviv_hw_reset(gpu);
> +
> +       /* complete all events, the GPU won't do it after the reset */
> +       spin_lock_irqsave(&gpu->event_spinlock, flags);
> +       for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
> +               if (!gpu->event[i].used)
> +                       continue;
> +               gpu->event[i].used = false;
> +               complete(&gpu->event_free);
> +               /*
> +                * Decrement the PM count for each stuck event. This is safe
> +                * even in atomic context as we use ASYNC RPM here.
> +                */
> +               pm_runtime_put_autosuspend(gpu->dev);
> +       }
> +       spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +       gpu->completed_fence = gpu->submitted_fence;
> +
> +       etnaviv_gpu_hw_init(gpu);
> +       gpu->switch_context = true;
> +
> +       mutex_unlock(&dev->struct_mutex);
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       /* Retire the buffer objects in a work */
> +       etnaviv_queue_work(gpu->drm, &gpu->retire_work);
> +}
> +
> +static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
> +{
> +       DBG("%s", dev_name(gpu->dev));
> +       mod_timer(&gpu->hangcheck_timer,
> +                 round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES));
> +}
> +
> +static void hangcheck_handler(unsigned long data)
> +{
> +       struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
> +       u32 fence = gpu->completed_fence;
> +       bool progress = false;
> +
> +       if (fence != gpu->hangcheck_fence) {
> +               gpu->hangcheck_fence = fence;
> +               progress = true;
> +       }
> +
> +       if (!progress) {
> +               u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
> +               int change = dma_addr - gpu->hangcheck_dma_addr;
> +
> +               if (change < 0 || change > 16) {
> +                       gpu->hangcheck_dma_addr = dma_addr;
> +                       progress = true;
> +               }
> +       }
> +
> +       if (!progress && fence_after(gpu->submitted_fence, fence)) {
> +               dev_err(gpu->dev, "hangcheck detected gpu lockup!\n");
> +               dev_err(gpu->dev, "     completed fence: %u\n", fence);
> +               dev_err(gpu->dev, "     submitted fence: %u\n",
> +                       gpu->submitted_fence);
> +               etnaviv_queue_work(gpu->drm, &gpu->recover_work);
> +       }
> +
> +       /* if still more pending work, reset the hangcheck timer: */
> +       if (fence_after(gpu->submitted_fence, gpu->hangcheck_fence))
> +               hangcheck_timer_reset(gpu);
> +}
> +
> +static void hangcheck_disable(struct etnaviv_gpu *gpu)
> +{
> +       del_timer_sync(&gpu->hangcheck_timer);
> +       cancel_work_sync(&gpu->recover_work);
> +}
> +
> +/*
> + * event management:
> + */
> +
> +static unsigned int event_alloc(struct etnaviv_gpu *gpu)
> +{
> +       unsigned long ret, flags;
> +       unsigned int i, event = ~0U;
> +
> +       ret = wait_for_completion_timeout(&gpu->event_free,
> +                                         msecs_to_jiffies(10 * 10000));
> +       if (!ret)
> +               dev_err(gpu->dev, "wait_for_completion_timeout failed");
> +
> +       spin_lock_irqsave(&gpu->event_spinlock, flags);
> +
> +       /* find first free event */
> +       for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
> +               if (gpu->event[i].used == false) {
> +                       gpu->event[i].used = true;
> +                       event = i;
> +                       break;
> +               }
> +       }
> +
> +       spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +
> +       return event;
> +}
> +
> +static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&gpu->event_spinlock, flags);
> +
> +       if (gpu->event[event].used == false) {
> +               dev_warn(gpu->dev, "event %u is already marked as free",
> +                        event);
> +               spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +       } else {
> +               gpu->event[event].used = false;
> +               spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +
> +               complete(&gpu->event_free);
> +       }
> +}
> +
> +/*
> + * Cmdstream submission/retirement:
> + */
> +
> +struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size)
> +{
> +       struct etnaviv_cmdbuf *cmdbuf;
> +
> +       cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
> +       if (!cmdbuf)
> +               return NULL;
> +
> +       cmdbuf->vaddr = dma_alloc_writecombine(gpu->dev, size, &cmdbuf->paddr,
> +                                              GFP_KERNEL);
> +       if (!cmdbuf->vaddr) {
> +               kfree(cmdbuf);
> +               return NULL;
> +       }
> +
> +       cmdbuf->gpu = gpu;
> +       cmdbuf->size = size;
> +
> +       return cmdbuf;
> +}
> +
> +void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
> +{
> +       dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
> +                             cmdbuf->vaddr, cmdbuf->paddr);
> +       kfree(cmdbuf);
> +}
> +
> +static void retire_worker(struct work_struct *work)
> +{
> +       struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
> +                                              retire_work);
> +       struct drm_device *dev = gpu->drm;
> +       u32 fence = gpu->completed_fence;
> +       struct etnaviv_cmdbuf *cmdbuf, *tmp;
> +
> +       mutex_lock(&dev->struct_mutex);
> +
> +       while (!list_empty(&gpu->active_list)) {
> +               struct etnaviv_gem_object *obj;
> +
> +               obj = list_first_entry(&gpu->active_list,
> +                               struct etnaviv_gem_object, mm_list);
> +
> +               if ((!(obj->access & ETNA_SUBMIT_BO_READ) ||
> +                    fence_after_eq(fence, obj->read_fence)) &&
> +                   (!(obj->access & ETNA_SUBMIT_BO_WRITE) ||
> +                    fence_after_eq(fence, obj->write_fence))) {
> +                       /* move to inactive: */
> +                       etnaviv_gem_move_to_inactive(&obj->base);
> +                       etnaviv_gem_put_iova(&obj->base);
> +                       drm_gem_object_unreference(&obj->base);
> +               } else {
> +                       break;
> +               }
> +       }
> +
> +       list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list,
> +                                gpu_active_list) {
> +               if (fence_after_eq(fence, cmdbuf->fence)) {
> +                       etnaviv_gpu_cmdbuf_free(cmdbuf);
> +                       list_del(&cmdbuf->gpu_active_list);
> +               }
> +       }
> +
> +       gpu->retired_fence = fence;
> +
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       wake_up_all(&gpu->fence_event);
> +}
> +
> +static unsigned long etnaviv_timeout_to_jiffies(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;
> +}
> +
> +int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
> +       u32 fence, struct timespec *timeout)
> +{
> +       int ret;
> +
> +       if (fence_after(fence, gpu->submitted_fence)) {
> +               DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
> +                               fence, gpu->submitted_fence);
> +               return -EINVAL;
> +       }
> +
> +       if (!timeout) {
> +               /* No timeout was requested: just test for completion */
> +               ret = fence_completed(gpu, fence) ? 0 : -EBUSY;
> +       } else {
> +               unsigned long remaining = etnaviv_timeout_to_jiffies(timeout);
> +
> +               ret = wait_event_interruptible_timeout(gpu->fence_event,
> +                                               fence_completed(gpu, fence),
> +                                               remaining);
> +               if (ret == 0) {
> +                       DBG("timeout waiting for fence: %u (retired: %u completed: %u)",
> +                               fence, gpu->retired_fence,
> +                               gpu->completed_fence);
> +                       ret = -ETIMEDOUT;
> +               } else if (ret != -ERESTARTSYS) {
> +                       ret = 0;
> +               }
> +       }
> +
> +       return ret;
> +}
> +
> +/*
> + * Wait for an object to become inactive.  This, on it's own, is not race
> + * free: the object is moved by the retire worker off the active list, and
> + * then the iova is put.  Moreover, the object could be re-submitted just
> + * after we notice that it's become inactive.
> + *
> + * Although the retirement happens under the struct_mutex, we don't want
> + * to hold that lock in this function.  Instead, the caller is responsible
> + * for ensuring that the retire worker has finished (which will happen, eg,
> + * when we unreference the object, an action which takes the struct_mutex.)
> + */
> +int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
> +       struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout)
> +{
> +       unsigned long remaining;
> +       long ret;
> +
> +       if (!timeout)
> +               return !is_active(etnaviv_obj) ? 0 : -EBUSY;
> +
> +       remaining = etnaviv_timeout_to_jiffies(timeout);
> +
> +       ret = wait_event_interruptible_timeout(gpu->fence_event,
> +                                              !is_active(etnaviv_obj),
> +                                              remaining);
> +       if (ret > 0)
> +               return 0;
> +       else if (ret == -ERESTARTSYS)
> +               return -ERESTARTSYS;
> +       else
> +               return -ETIMEDOUT;
> +}
> +
> +int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu)
> +{
> +       return pm_runtime_get_sync(gpu->dev);
> +}
> +
> +void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu)
> +{
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +}
> +
> +/* add bo's to gpu's ring, and kick gpu: */
> +int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
> +       struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx)
> +{
> +       struct drm_device *dev = gpu->drm;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       unsigned int event, i;
> +       int ret;
> +
> +       ret = pm_runtime_get_sync(gpu->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       /*
> +        * TODO
> +        *
> +        * - flush
> +        * - data endian
> +        * - prefetch
> +        *
> +        */
> +
> +       event = event_alloc(gpu);
> +       if (unlikely(event == ~0U)) {
> +               DRM_ERROR("no free event\n");
> +               pm_runtime_put_autosuspend(gpu->dev);
> +               return -EBUSY;
> +       }
> +
> +       submit->fence = ++priv->next_fence;
> +
> +       gpu->submitted_fence = submit->fence;
> +
> +       if (gpu->lastctx != ctx) {
> +               gpu->mmu->need_flush = true;
> +               gpu->switch_context = true;
> +               gpu->lastctx = ctx;
> +       }
> +
> +       etnaviv_buffer_queue(gpu, event, submit);
> +
> +       for (i = 0; i < submit->nr_bos; i++) {
> +               struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
> +
> +               /* can't happen yet.. but when we add 2d support we'll have
> +                * to deal w/ cross-ring synchronization:
> +                */
> +               WARN_ON(is_active(etnaviv_obj) && (etnaviv_obj->gpu != gpu));
> +
> +               if (!is_active(etnaviv_obj)) {
> +                       u32 iova;
> +
> +                       /* ring takes a reference to the bo and iova: */
> +                       drm_gem_object_reference(&etnaviv_obj->base);
> +                       etnaviv_gem_get_iova_locked(gpu, &etnaviv_obj->base,
> +                                                   &iova);
> +               }
> +
> +               if (submit->bos[i].flags & (ETNA_SUBMIT_BO_READ |
> +                                           ETNA_SUBMIT_BO_WRITE))
> +                       etnaviv_gem_move_to_active(&etnaviv_obj->base, gpu,
> +                                                  submit->bos[i].flags,
> +                                                  submit->fence);
> +       }
> +       hangcheck_timer_reset(gpu);
> +
> +       return 0;
> +}
> +
> +/*
> + * Init/Cleanup:
> + */
> +static irqreturn_t irq_handler(int irq, void *data)
> +{
> +       struct etnaviv_gpu *gpu = data;
> +       irqreturn_t ret = IRQ_NONE;
> +
> +       u32 intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE);
> +
> +       if (intr != 0) {
> +               int event;
> +
> +               pm_runtime_mark_last_busy(gpu->dev);
> +
> +               dev_dbg(gpu->dev, "intr 0x%08x\n", intr);
> +
> +               if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) {
> +                       dev_err(gpu->dev, "AXI bus error\n");
> +                       intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR;
> +               }
> +
> +               while ((event = ffs(intr)) != 0) {
> +                       event -= 1;
> +
> +                       intr &= ~(1 << event);
> +
> +                       dev_dbg(gpu->dev, "event %u\n", event);
> +                       /*
> +                        * Events can be processed out of order.  Eg,
> +                        * - allocate and queue event 0
> +                        * - allocate event 1
> +                        * - event 0 completes, we process it
> +                        * - allocate and queue event 0
> +                        * - event 1 and event 0 complete
> +                        * we can end up processing event 0 first, then 1.
> +                        */
> +                       if (fence_after(gpu->event[event].fence,
> +                                       gpu->completed_fence))
> +                               gpu->completed_fence = gpu->event[event].fence;
> +                       event_free(gpu, event);
> +
> +                       /*
> +                        * We need to balance the runtime PM count caused by
> +                        * each submission.  Upon submission, we increment
> +                        * the runtime PM counter, and allocate one event.
> +                        * So here, we put the runtime PM count for each
> +                        * completed event.
> +                        */
> +                       pm_runtime_put_autosuspend(gpu->dev);
> +               }
> +
> +               /* Retire the buffer objects in a work */
> +               etnaviv_queue_work(gpu->drm, &gpu->retire_work);
> +
> +               ret = IRQ_HANDLED;
> +       }
> +
> +       return ret;
> +}
> +
> +static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
> +{
> +       int ret;
> +
> +       ret = enable_clk(gpu);
> +       if (ret)
> +               return ret;
> +
> +       ret = enable_axi(gpu);
> +       if (ret) {
> +               disable_clk(gpu);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
> +{
> +       int ret;
> +
> +       ret = disable_axi(gpu);
> +       if (ret)
> +               return ret;
> +
> +       ret = disable_clk(gpu);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->buffer) {
> +               unsigned long timeout;
> +
> +               /* Replace the last WAIT with END */
> +               etnaviv_buffer_end(gpu);
> +
> +               /*
> +                * We know that only the FE is busy here, this should
> +                * happen quickly (as the WAIT is only 200 cycles).  If
> +                * we fail, just warn and continue.
> +                */
> +               timeout = jiffies + msecs_to_jiffies(100);
> +               do {
> +                       u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +
> +                       if ((idle & gpu->idle_mask) == gpu->idle_mask)
> +                               break;
> +
> +                       if (time_is_before_jiffies(timeout)) {
> +                               dev_warn(gpu->dev,
> +                                        "timed out waiting for idle: idle=0x%x\n",
> +                                        idle);
> +                               break;
> +                       }
> +
> +                       udelay(5);
> +               } while (1);
> +       }
> +
> +       return etnaviv_gpu_clk_disable(gpu);
> +}
> +
> +#ifdef CONFIG_PM
> +static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
> +{
> +       struct drm_device *drm = gpu->drm;
> +       u32 clock;
> +       int ret;
> +
> +       ret = mutex_lock_killable(&drm->struct_mutex);
> +       if (ret)
> +               return ret;
> +
> +       clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
> +               VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
> +
> +       etnaviv_gpu_load_clock(gpu, clock);
> +       etnaviv_gpu_hw_init(gpu);
> +
> +       gpu->switch_context = true;
> +
> +       mutex_unlock(&drm->struct_mutex);
> +
> +       return 0;
> +}
> +#endif
> +
> +static int etnaviv_gpu_bind(struct device *dev, struct device *master,
> +       void *data)
> +{
> +       struct drm_device *drm = data;
> +       struct etnaviv_drm_private *priv = drm->dev_private;
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +       int ret;
> +
> +#ifdef CONFIG_PM
> +       ret = pm_runtime_get_sync(gpu->dev);
> +#else
> +       ret = etnaviv_gpu_clk_enable(gpu);
> +#endif
> +       if (ret < 0)
> +               return ret;
> +
> +       gpu->drm = drm;
> +
> +       INIT_LIST_HEAD(&gpu->active_list);
> +       INIT_LIST_HEAD(&gpu->active_cmd_list);
> +       INIT_WORK(&gpu->retire_work, retire_worker);
> +       INIT_WORK(&gpu->recover_work, recover_worker);
> +       init_waitqueue_head(&gpu->fence_event);
> +
> +       setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
> +                       (unsigned long)gpu);
> +
> +       priv->gpu[priv->num_gpus++] = gpu;
> +
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return 0;
> +}
> +
> +static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
> +       void *data)
> +{
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +
> +       DBG("%s", dev_name(gpu->dev));
> +
> +       hangcheck_disable(gpu);
> +
> +       WARN_ON(!list_empty(&gpu->active_list));
> +
> +#ifdef CONFIG_PM
> +       pm_runtime_get_sync(gpu->dev);
> +       pm_runtime_put_sync_suspend(gpu->dev);
> +#else
> +       etnaviv_gpu_hw_suspend(gpu);
> +#endif
> +
> +       if (gpu->buffer) {
> +               etnaviv_gpu_cmdbuf_free(gpu->buffer);
> +               gpu->buffer = NULL;
> +       }
> +
> +       if (gpu->mmu) {
> +               etnaviv_iommu_destroy(gpu->mmu);
> +               gpu->mmu = NULL;
> +       }
> +
> +       gpu->drm = NULL;
> +}
> +
> +static const struct component_ops gpu_ops = {
> +       .bind = etnaviv_gpu_bind,
> +       .unbind = etnaviv_gpu_unbind,
> +};
> +
> +static const struct of_device_id etnaviv_gpu_match[] = {
> +       {
> +               .compatible = "vivante,gc"
> +       },
> +       { /* sentinel */ }
> +};
> +
> +static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct etnaviv_gpu *gpu;
> +       int err = 0;
> +
> +       gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL);
> +       if (!gpu)
> +               return -ENOMEM;
> +
> +       gpu->dev = &pdev->dev;
> +
> +       /*
> +        * Set the GPU base address to the start of physical memory.  This
> +        * ensures that if we have up to 2GB, the v1 MMU can address the
> +        * highest memory.  This is important as command buffers may be
> +        * allocated outside of this limit.
> +        */
> +       gpu->memory_base = PHYS_OFFSET;
> +
> +       /* Map registers: */
> +       gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev));
> +       if (IS_ERR(gpu->mmio))
> +               return PTR_ERR(gpu->mmio);
> +
> +       /* Get Interrupt: */
> +       gpu->irq = platform_get_irq(pdev, 0);
> +       if (gpu->irq < 0) {
> +               err = gpu->irq;
> +               dev_err(dev, "failed to get irq: %d\n", err);
> +               goto fail;
> +       }
> +
> +       err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0,
> +                              dev_name(gpu->dev), gpu);
> +       if (err) {
> +               dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err);
> +               goto fail;
> +       }
> +
> +       /* Get Clocks: */
> +       gpu->clk_bus = devm_clk_get(&pdev->dev, "bus");
> +       DBG("clk_bus: %p", gpu->clk_bus);
> +       if (IS_ERR(gpu->clk_bus))
> +               gpu->clk_bus = NULL;
> +
> +       gpu->clk_core = devm_clk_get(&pdev->dev, "core");
> +       DBG("clk_core: %p", gpu->clk_core);
> +       if (IS_ERR(gpu->clk_core))
> +               gpu->clk_core = NULL;
> +
> +       gpu->clk_shader = devm_clk_get(&pdev->dev, "shader");
> +       DBG("clk_shader: %p", gpu->clk_shader);
> +       if (IS_ERR(gpu->clk_shader))
> +               gpu->clk_shader = NULL;
> +
> +       /* TODO: figure out max mapped size */
> +       dev_set_drvdata(dev, gpu);
> +
> +       /*
> +        * We treat the device as initially suspended.  The runtime PM
> +        * autosuspend delay is rather arbitary: no measurements have
> +        * yet been performed to determine an appropriate value.
> +        */
> +       pm_runtime_use_autosuspend(gpu->dev);
> +       pm_runtime_set_autosuspend_delay(gpu->dev, 200);
> +       pm_runtime_enable(gpu->dev);
> +
> +       err = component_add(&pdev->dev, &gpu_ops);
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to register component: %d\n", err);
> +               goto fail;
> +       }
> +
> +       return 0;
> +
> +fail:
> +       return err;
> +}
> +
> +static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
> +{
> +       component_del(&pdev->dev, &gpu_ops);
> +       pm_runtime_disable(&pdev->dev);
> +       return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int etnaviv_gpu_rpm_suspend(struct device *dev)
> +{
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +       u32 idle, mask;
> +
> +       /* If we have outstanding fences, we're not idle */
> +       if (gpu->completed_fence != gpu->submitted_fence)
> +               return -EBUSY;
> +
> +       /* Check whether the hardware (except FE) is idle */
> +       mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE;
> +       idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask;
> +       if (idle != mask)
> +               return -EBUSY;
> +
> +       return etnaviv_gpu_hw_suspend(gpu);
> +}
> +
> +static int etnaviv_gpu_rpm_resume(struct device *dev)
> +{
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +       int ret;
> +
> +       /* We must never runtime-PM resume holding struct_mutex */
> +       if (gpu->drm && WARN_ON_ONCE(mutex_is_locked(&gpu->drm->struct_mutex)))
> +               return -EDEADLK;
> +
> +       ret = etnaviv_gpu_clk_enable(gpu);
> +       if (ret)
> +               return ret;
> +
> +       /* Re-initialise the basic hardware state */
> +       if (gpu->drm && gpu->buffer) {
> +               ret = etnaviv_gpu_hw_resume(gpu);
> +               if (ret) {
> +                       etnaviv_gpu_clk_disable(gpu);
> +                       return ret;
> +               }
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
> +       SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume,
> +                          NULL)
> +};
> +
> +struct platform_driver etnaviv_gpu_driver = {
> +       .driver = {
> +               .name = "etnaviv-gpu",
> +               .owner = THIS_MODULE,
> +               .pm = &etnaviv_gpu_pm_ops,
> +               .of_match_table = etnaviv_gpu_match,
> +       },
> +       .probe = etnaviv_gpu_platform_probe,
> +       .remove = etnaviv_gpu_platform_remove,
> +       .id_table = gpu_ids,
> +};
> diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
> new file mode 100644
> index 000000000000..3be5b481d8d1
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gpu.h
> @@ -0,0 +1,198 @@
> +/*
> + * 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;
> +       u32 fence;
> +};
> +
> +struct etnaviv_cmdbuf;
> +
> +struct etnaviv_gpu {
> +       struct drm_device *drm;
> +       struct device *dev;
> +       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 GEM active objects: */
> +       struct list_head active_list;
> +
> +       /* list of currently in-flight command buffers */
> +       struct list_head active_cmd_list;
> +
> +       u32 idle_mask;
> +
> +       /* Fencing support */
> +       u32 submitted_fence;
> +       u32 completed_fence;
> +       u32 retired_fence;
> +       wait_queue_head_t fence_event;
> +
> +       /* 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;
> +       /* cmdbuf properties */
> +       void *vaddr;
> +       dma_addr_t paddr;
> +       u32 size;
> +       u32 user_size;
> +       /* fence after which this buffer is to be disposed */
> +       u32 fence;
> +       /* per GPU in-flight list */
> +       struct list_head gpu_active_list;
> +};
> +
> +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
> +
> +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_file_private *ctx);
> +struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
> +                                             u32 size);
> +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__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
> new file mode 100644
> index 000000000000..9efb7d6092b4
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu.c
> @@ -0,0 +1,221 @@
> +/*
> + * 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_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_iommu_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_iommu_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 struct iommu_ops etnaviv_iommu_ops = {
> +               .domain_free = etnaviv_domain_free,
> +               .map = etnaviv_iommu_map,
> +               .unmap = etnaviv_iommu_unmap,
> +               .iova_to_phys = etnaviv_iommu_iova_to_phys,
> +               .pgsize_bitmap = SZ_4K,
> +};
> +
> +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;
> +       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;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu.h b/drivers/staging/etnaviv/etnaviv_iommu.h
> new file mode 100644
> index 000000000000..cf45503f6b6f
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu.h
> @@ -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__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.c b/drivers/staging/etnaviv/etnaviv_iommu_v2.c
> new file mode 100644
> index 000000000000..fbb4aed3dc80
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.c
> @@ -0,0 +1,33 @@
> +/*
> + * 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_iommu.h"
> +#include "state_hi.xml.h"
> +
> +
> +struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu)
> +{
> +       /* TODO */
> +       return NULL;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.h b/drivers/staging/etnaviv/etnaviv_iommu_v2.h
> new file mode 100644
> index 000000000000..603ea41c5389
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.h
> @@ -0,0 +1,25 @@
> +/*
> + * 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_V2_H__
> +#define __ETNAVIV_IOMMU_V2_H__
> +
> +#include <linux/iommu.h>
> +struct etnaviv_gpu;
> +
> +struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
> +
> +#endif /* __ETNAVIV_IOMMU_V2_H__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
> new file mode 100644
> index 000000000000..ca317f633970
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_mmu.c
> @@ -0,0 +1,282 @@
> +/*
> + * 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 "etnaviv_drv.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_mmu.h"
> +
> +static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device *dev,
> +               unsigned long iova, int flags, void *arg)
> +{
> +       DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
> +       return 0;
> +}
> +
> +int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
> +               struct sg_table *sgt, unsigned len, int prot)
> +{
> +       struct iommu_domain *domain = iommu->domain;
> +       struct scatterlist *sg;
> +       unsigned int da = iova;
> +       unsigned int i, j;
> +       int ret;
> +
> +       if (!domain || !sgt)
> +               return -EINVAL;
> +
> +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +               u32 pa = sg_dma_address(sg) - sg->offset;
> +               size_t bytes = sg_dma_len(sg) + sg->offset;
> +
> +               VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
> +
> +               ret = iommu_map(domain, da, pa, bytes, prot);
> +               if (ret)
> +                       goto fail;
> +
> +               da += bytes;
> +       }
> +
> +       return 0;
> +
> +fail:
> +       da = iova;
> +
> +       for_each_sg(sgt->sgl, sg, i, j) {
> +               size_t bytes = sg_dma_len(sg) + sg->offset;
> +
> +               iommu_unmap(domain, da, bytes);
> +               da += bytes;
> +       }
> +       return ret;
> +}
> +
> +int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
> +               struct sg_table *sgt, unsigned len)
> +{
> +       struct iommu_domain *domain = iommu->domain;
> +       struct scatterlist *sg;
> +       unsigned int da = iova;
> +       int i;
> +
> +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +               size_t bytes = sg_dma_len(sg) + sg->offset;
> +               size_t unmapped;
> +
> +               unmapped = iommu_unmap(domain, da, bytes);
> +               if (unmapped < bytes)
> +                       return unmapped;
> +
> +               VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
> +
> +               BUG_ON(!PAGE_ALIGNED(bytes));
> +
> +               da += bytes;
> +       }
> +
> +       return 0;
> +}
> +
> +int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
> +       struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
> +       struct etnaviv_vram_mapping **out_mapping)
> +{
> +       struct etnaviv_drm_private *priv = etnaviv_obj->base.dev->dev_private;
> +       struct sg_table *sgt = etnaviv_obj->sgt;
> +       struct etnaviv_vram_mapping *mapping, *free = NULL;
> +       struct drm_mm_node *node;
> +       int ret;
> +
> +       mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
> +       if (!mapping)
> +               return -ENOMEM;
> +
> +       INIT_LIST_HEAD(&mapping->scan_node);
> +       mapping->object = etnaviv_obj;
> +       mapping->mmu = mmu;
> +
> +       /* v1 MMU can optimize single entry (contiguous) scatterlists */
> +       if (sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
> +               u32 iova;
> +
> +               iova = sg_dma_address(sgt->sgl) - memory_base;
> +               if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
> +                       mapping->iova = iova;
> +                       list_add_tail(&mapping->obj_node,
> +                                     &etnaviv_obj->vram_list);
> +                       if (out_mapping)
> +                               *out_mapping = mapping;
> +                       return 0;
> +               }
> +       }
> +
> +       node = &mapping->vram_node;
> +       while (1) {
> +               struct etnaviv_gem_object *o;
> +               struct etnaviv_vram_mapping *m, *n;
> +               struct list_head list;
> +               bool found;
> +
> +               ret = drm_mm_insert_node_in_range(&mmu->mm, node,
> +                       etnaviv_obj->base.size, 0, mmu->last_iova, ~0UL,
> +                       DRM_MM_SEARCH_DEFAULT);
> +
> +               if (ret != -ENOSPC)
> +                       break;
> +
> +               /*
> +                * If we did not search from the start of the MMU region,
> +                * try again in case there are free slots.
> +                */
> +               if (mmu->last_iova) {
> +                       mmu->last_iova = 0;
> +                       mmu->need_flush = true;
> +                       continue;
> +               }
> +
> +               /* Try to retire some entries */
> +               drm_mm_init_scan(&mmu->mm, etnaviv_obj->base.size, 0, 0);
> +
> +               found = 0;
> +               INIT_LIST_HEAD(&list);
> +               list_for_each_entry(o, &priv->inactive_list, mm_list) {
> +                       free = etnaviv_gem_get_vram_mapping(o, mmu);
> +                       if (!free)
> +                               continue;
> +
> +                       /*
> +                        * If this vram node has not been used, skip this.
> +                        */
> +                       if (!free->vram_node.mm)
> +                               continue;
> +
> +                       /*
> +                        * If it's on the submit list, then it is part of
> +                        * a submission, and we want to keep its entry.
> +                        */
> +                       if (!list_empty(&o->submit_entry))
> +                               continue;
> +
> +                       list_add(&free->scan_node, &list);
> +                       if (drm_mm_scan_add_block(&free->vram_node)) {
> +                               found = true;
> +                               break;
> +                       }
> +               }
> +
> +               if (!found) {
> +                       /* Nothing found, clean up and fail */
> +                       list_for_each_entry_safe(m, n, &list, scan_node)
> +                               BUG_ON(drm_mm_scan_remove_block(&m->vram_node));
> +                       break;
> +               }
> +
> +               /*
> +                * drm_mm does not allow any other operations while
> +                * scanning, so we have to remove all blocks first.
> +                * If drm_mm_scan_remove_block() returns false, we
> +                * can leave the block pinned.
> +                */
> +               list_for_each_entry_safe(m, n, &list, scan_node)
> +                       if (!drm_mm_scan_remove_block(&m->vram_node))
> +                               list_del_init(&m->scan_node);
> +
> +               list_for_each_entry_safe(m, n, &list, scan_node) {
> +                       list_del_init(&m->scan_node);
> +                       etnaviv_iommu_unmap_gem(m);
> +               }
> +
> +               /*
> +                * We removed enough mappings so that the new allocation will
> +                * succeed.  Ensure that the MMU will be flushed and retry
> +                * the allocation one more time.
> +                */
> +               mmu->need_flush = true;
> +       }
> +
> +       if (ret < 0) {
> +               kfree(mapping);
> +               return ret;
> +       }
> +
> +       mmu->last_iova = node->start + etnaviv_obj->base.size;
> +       mapping->iova = node->start;
> +       ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size,
> +                               IOMMU_READ | IOMMU_WRITE);
> +
> +       if (ret < 0) {
> +               drm_mm_remove_node(node);
> +               kfree(mapping);
> +               return ret;
> +       }
> +
> +       list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);
> +       if (out_mapping)
> +               *out_mapping = mapping;
> +
> +       return ret;
> +}
> +
> +void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping)
> +{
> +       struct etnaviv_iommu *mmu;
> +       struct etnaviv_gem_object *etnaviv_obj;
> +
> +       if (!mapping)
> +               return;
> +
> +       mmu = mapping->mmu;
> +
> +       /* If the vram node is on the mm, unmap and remove the node */
> +       if (mapping->vram_node.mm == &mmu->mm) {
> +               etnaviv_obj = mapping->object;
> +               etnaviv_iommu_unmap(mmu, mapping->vram_node.start,
> +                                   etnaviv_obj->sgt, etnaviv_obj->base.size);
> +               drm_mm_remove_node(&mapping->vram_node);
> +       }
> +
> +       list_del(&mapping->obj_node);
> +       kfree(mapping);
> +}
> +
> +void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
> +{
> +       drm_mm_takedown(&mmu->mm);
> +       iommu_domain_free(mmu->domain);
> +       kfree(mmu);
> +}
> +
> +struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev,
> +       struct iommu_domain *domain, enum etnaviv_iommu_version version)
> +{
> +       struct etnaviv_iommu *mmu;
> +
> +       mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
> +       if (!mmu)
> +               return ERR_PTR(-ENOMEM);
> +
> +       mmu->domain = domain;
> +       mmu->dev = dev;
> +       mmu->version = version;
> +
> +       drm_mm_init(&mmu->mm, domain->geometry.aperture_start,
> +                   domain->geometry.aperture_end -
> +                     domain->geometry.aperture_start + 1);
> +
> +       iommu_set_fault_handler(domain, etnaviv_fault_handler, dev);
> +
> +       return mmu;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_mmu.h b/drivers/staging/etnaviv/etnaviv_mmu.h
> new file mode 100644
> index 000000000000..444ef296d2b4
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_mmu.h
> @@ -0,0 +1,58 @@
> +/*
> + * 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_MMU_H__
> +#define __ETNAVIV_MMU_H__
> +
> +#include <linux/iommu.h>
> +
> +enum etnaviv_iommu_version {
> +       ETNAVIV_IOMMU_V1 = 0,
> +       ETNAVIV_IOMMU_V2,
> +};
> +
> +struct etnaviv_vram_mapping;
> +
> +struct etnaviv_iommu {
> +       struct device *dev;
> +       struct iommu_domain *domain;
> +
> +       enum etnaviv_iommu_version version;
> +
> +       /* memory manager for GPU address area */
> +       struct drm_mm mm;
> +       u32 last_iova;
> +       bool need_flush;
> +};
> +
> +struct etnaviv_gem_object;
> +
> +int etnaviv_iommu_attach(struct etnaviv_iommu *iommu, const char **names,
> +       int cnt);
> +int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
> +       struct sg_table *sgt, unsigned len, int prot);
> +int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
> +       struct sg_table *sgt, unsigned len);
> +int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
> +       struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
> +       struct etnaviv_vram_mapping **mapping);
> +void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping);
> +void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
> +
> +struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev,
> +       struct iommu_domain *domain, enum etnaviv_iommu_version version);
> +
> +#endif /* __ETNAVIV_MMU_H__ */
> diff --git a/drivers/staging/etnaviv/state.xml.h b/drivers/staging/etnaviv/state.xml.h
> new file mode 100644
> index 000000000000..368218304566
> --- /dev/null
> +++ b/drivers/staging/etnaviv/state.xml.h
> @@ -0,0 +1,351 @@
> +#ifndef STATE_XML
> +#define STATE_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.xml    (  18882 bytes, from 2015-03-25 11:42:32)
> +- common.xml   (  18437 bytes, from 2015-03-25 11:27:41)
> +- state_hi.xml (  23420 bytes, from 2015-03-25 11:47:21)
> +- state_2d.xml (  51549 bytes, from 2015-03-25 11:25:06)
> +- state_3d.xml (  54600 bytes, from 2015-03-25 11:25:19)
> +- state_vg.xml (   5973 bytes, from 2015-03-25 11:26:01)
> +
> +Copyright (C) 2015
> +*/
> +
> +
> +#define VARYING_COMPONENT_USE_UNUSED                           0x00000000
> +#define VARYING_COMPONENT_USE_USED                             0x00000001
> +#define VARYING_COMPONENT_USE_POINTCOORD_X                     0x00000002
> +#define VARYING_COMPONENT_USE_POINTCOORD_Y                     0x00000003
> +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK           0x000000ff
> +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT          0
> +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x)              (((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK)
> +#define VIVS_FE                                                        0x00000000
> +
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0)                     (0x00000600 + 0x4*(i0))
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE                   0x00000004
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN                     0x00000010
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK               0x0000000f
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT              0
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE                        0x00000000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE       0x00000001
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT               0x00000002
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT      0x00000003
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT                 0x00000004
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT                0x00000005
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT               0x00000008
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT          0x00000009
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED               0x0000000b
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2      0x0000000c
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2     0x0000000d
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK             0x00000030
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT            4
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x)                        (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE           0x00000080
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK             0x00000700
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT            8
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x)                        (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK                        0x00003000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT               12
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x)                   (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK          0x0000c000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT         14
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF            0x00000000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON             0x00008000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK              0x00ff0000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT             16
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x)                 (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK                        0xff000000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT               24
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x)                   (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK)
> +
> +#define VIVS_FE_CMD_STREAM_BASE_ADDR                           0x00000640
> +
> +#define VIVS_FE_INDEX_STREAM_BASE_ADDR                         0x00000644
> +
> +#define VIVS_FE_INDEX_STREAM_CONTROL                           0x00000648
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK                        0x00000003
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT               0
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR                0x00000000
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT       0x00000001
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT         0x00000002
> +
> +#define VIVS_FE_VERTEX_STREAM_BASE_ADDR                                0x0000064c
> +
> +#define VIVS_FE_VERTEX_STREAM_CONTROL                          0x00000650
> +
> +#define VIVS_FE_COMMAND_ADDRESS                                        0x00000654
> +
> +#define VIVS_FE_COMMAND_CONTROL                                        0x00000658
> +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK                 0x0000ffff
> +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT                        0
> +#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x)                    (((x) << VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK)
> +#define VIVS_FE_COMMAND_CONTROL_ENABLE                         0x00010000
> +
> +#define VIVS_FE_DMA_STATUS                                     0x0000065c
> +
> +#define VIVS_FE_DMA_DEBUG_STATE                                        0x00000660
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK                        0x0000001f
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT               0
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE                 0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC                  0x00000001
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0                 0x00000002
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0                        0x00000003
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1                 0x00000004
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1                        0x00000005
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR                        0x00000006
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD                        0x00000007
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL               0x00000008
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL            0x00000009
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA           0x0000000a
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX              0x0000000b
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW                 0x0000000c
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0              0x0000000d
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1              0x0000000e
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0              0x0000000f
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1              0x00000010
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO             0x00000011
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT                 0x00000012
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK                 0x00000013
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END                  0x00000014
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL                        0x00000015
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK            0x00000300
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT           8
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE             0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START            0x00000100
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ              0x00000200
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END              0x00000300
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK          0x00000c00
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT         10
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE           0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID       0x00000400
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID          0x00000800
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK            0x00003000
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT           12
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE             0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX          0x00001000
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL              0x00002000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK                        0x0000c000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT               14
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE                 0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR                        0x00004000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC              0x00008000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK             0x00030000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT            16
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE              0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE           0x00010000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS              0x00020000
> +
> +#define VIVS_FE_DMA_ADDRESS                                    0x00000664
> +
> +#define VIVS_FE_DMA_LOW                                                0x00000668
> +
> +#define VIVS_FE_DMA_HIGH                                       0x0000066c
> +
> +#define VIVS_FE_AUTO_FLUSH                                     0x00000670
> +
> +#define VIVS_FE_UNK00678                                       0x00000678
> +
> +#define VIVS_FE_UNK0067C                                       0x0000067c
> +
> +#define VIVS_FE_VERTEX_STREAMS(i0)                            (0x00000000 + 0x4*(i0))
> +#define VIVS_FE_VERTEX_STREAMS__ESIZE                          0x00000004
> +#define VIVS_FE_VERTEX_STREAMS__LEN                            0x00000008
> +
> +#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0)                  (0x00000680 + 0x4*(i0))
> +
> +#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0)                    (0x000006a0 + 0x4*(i0))
> +
> +#define VIVS_FE_UNK00700(i0)                                  (0x00000700 + 0x4*(i0))
> +#define VIVS_FE_UNK00700__ESIZE                                        0x00000004
> +#define VIVS_FE_UNK00700__LEN                                  0x00000010
> +
> +#define VIVS_FE_UNK00740(i0)                                  (0x00000740 + 0x4*(i0))
> +#define VIVS_FE_UNK00740__ESIZE                                        0x00000004
> +#define VIVS_FE_UNK00740__LEN                                  0x00000010
> +
> +#define VIVS_FE_UNK00780(i0)                                  (0x00000780 + 0x4*(i0))
> +#define VIVS_FE_UNK00780__ESIZE                                        0x00000004
> +#define VIVS_FE_UNK00780__LEN                                  0x00000010
> +
> +#define VIVS_GL                                                        0x00000000
> +
> +#define VIVS_GL_PIPE_SELECT                                    0x00003800
> +#define VIVS_GL_PIPE_SELECT_PIPE__MASK                         0x00000001
> +#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT                                0
> +#define VIVS_GL_PIPE_SELECT_PIPE(x)                            (((x) << VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK)
> +
> +#define VIVS_GL_EVENT                                          0x00003804
> +#define VIVS_GL_EVENT_EVENT_ID__MASK                           0x0000001f
> +#define VIVS_GL_EVENT_EVENT_ID__SHIFT                          0
> +#define VIVS_GL_EVENT_EVENT_ID(x)                              (((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK)
> +#define VIVS_GL_EVENT_FROM_FE                                  0x00000020
> +#define VIVS_GL_EVENT_FROM_PE                                  0x00000040
> +#define VIVS_GL_EVENT_SOURCE__MASK                             0x00001f00
> +#define VIVS_GL_EVENT_SOURCE__SHIFT                            8
> +#define VIVS_GL_EVENT_SOURCE(x)                                        (((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK)
> +
> +#define VIVS_GL_SEMAPHORE_TOKEN                                        0x00003808
> +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK                     0x0000001f
> +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT                    0
> +#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x)                                (((x) << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK)
> +#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK                       0x00001f00
> +#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT                      8
> +#define VIVS_GL_SEMAPHORE_TOKEN_TO(x)                          (((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK)
> +
> +#define VIVS_GL_FLUSH_CACHE                                    0x0000380c
> +#define VIVS_GL_FLUSH_CACHE_DEPTH                              0x00000001
> +#define VIVS_GL_FLUSH_CACHE_COLOR                              0x00000002
> +#define VIVS_GL_FLUSH_CACHE_TEXTURE                            0x00000004
> +#define VIVS_GL_FLUSH_CACHE_PE2D                               0x00000008
> +#define VIVS_GL_FLUSH_CACHE_TEXTUREVS                          0x00000010
> +#define VIVS_GL_FLUSH_CACHE_SHADER_L1                          0x00000020
> +#define VIVS_GL_FLUSH_CACHE_SHADER_L2                          0x00000040
> +
> +#define VIVS_GL_FLUSH_MMU                                      0x00003810
> +#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU                          0x00000001
> +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1                           0x00000002
> +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2                           0x00000004
> +#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU                          0x00000008
> +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4                           0x00000010
> +
> +#define VIVS_GL_VERTEX_ELEMENT_CONFIG                          0x00003814
> +
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG                            0x00003818
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK         0x00000003
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT                0
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE          0x00000000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X            0x00000001
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X            0x00000002
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK          0x00000008
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK         0x000000f0
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT                4
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x)            (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK)
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK          0x00000100
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK                        0x00007000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT               12
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x)                   (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK)
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK                 0x00008000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK                        0x00030000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT               16
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x)                   (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK)
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK                 0x00080000
> +
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS                       0x0000381c
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK             0x000000ff
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT            0
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x)                        (((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK)
> +
> +#define VIVS_GL_VARYING_NUM_COMPONENTS                         0x00003820
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK              0x00000007
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT             0
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK              0x00000070
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT             4
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK              0x00000700
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT             8
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK              0x00007000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT             12
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK              0x00070000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT             16
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK              0x00700000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT             20
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK              0x07000000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT             24
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK              0x70000000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT             28
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK)
> +
> +#define VIVS_GL_VARYING_COMPONENT_USE(i0)                     (0x00003828 + 0x4*(i0))
> +#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE                   0x00000004
> +#define VIVS_GL_VARYING_COMPONENT_USE__LEN                     0x00000002
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK              0x00000003
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT             0
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK              0x0000000c
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT             2
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK              0x00000030
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT             4
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK              0x000000c0
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT             6
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK              0x00000300
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT             8
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK              0x00000c00
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT             10
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK              0x00003000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT             12
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK              0x0000c000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT             14
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK              0x00030000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT             16
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK              0x000c0000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT             18
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK             0x00300000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT            20
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK             0x00c00000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT            22
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK             0x03000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT            24
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK             0x0c000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT            26
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK             0x30000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT            28
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK             0xc0000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT            30
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK)
> +
> +#define VIVS_GL_UNK03834                                       0x00003834
> +
> +#define VIVS_GL_UNK03838                                       0x00003838
> +
> +#define VIVS_GL_API_MODE                                       0x0000384c
> +#define VIVS_GL_API_MODE_OPENGL                                        0x00000000
> +#define VIVS_GL_API_MODE_OPENVG                                        0x00000001
> +#define VIVS_GL_API_MODE_OPENCL                                        0x00000002
> +
> +#define VIVS_GL_CONTEXT_POINTER                                        0x00003850
> +
> +#define VIVS_GL_UNK03A00                                       0x00003a00
> +
> +#define VIVS_GL_STALL_TOKEN                                    0x00003c00
> +#define VIVS_GL_STALL_TOKEN_FROM__MASK                         0x0000001f
> +#define VIVS_GL_STALL_TOKEN_FROM__SHIFT                                0
> +#define VIVS_GL_STALL_TOKEN_FROM(x)                            (((x) << VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK)
> +#define VIVS_GL_STALL_TOKEN_TO__MASK                           0x00001f00
> +#define VIVS_GL_STALL_TOKEN_TO__SHIFT                          8
> +#define VIVS_GL_STALL_TOKEN_TO(x)                              (((x) << VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK)
> +#define VIVS_GL_STALL_TOKEN_FLIP0                              0x40000000
> +#define VIVS_GL_STALL_TOKEN_FLIP1                              0x80000000
> +
> +#define VIVS_DUMMY                                             0x00000000
> +
> +#define VIVS_DUMMY_DUMMY                                       0x0003fffc
> +
> +
> +#endif /* STATE_XML */
> diff --git a/drivers/staging/etnaviv/state_hi.xml.h b/drivers/staging/etnaviv/state_hi.xml.h
> new file mode 100644
> index 000000000000..0064f2640396
> --- /dev/null
> +++ b/drivers/staging/etnaviv/state_hi.xml.h
> @@ -0,0 +1,407 @@
> +#ifndef STATE_HI_XML
> +#define STATE_HI_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_hi.xml (  23420 bytes, from 2015-03-25 11:47:21)
> +- common.xml   (  18437 bytes, from 2015-03-25 11:27:41)
> +
> +Copyright (C) 2015
> +*/
> +
> +
> +#define MMU_EXCEPTION_SLAVE_NOT_PRESENT                                0x00000001
> +#define MMU_EXCEPTION_PAGE_NOT_PRESENT                         0x00000002
> +#define MMU_EXCEPTION_WRITE_VIOLATION                          0x00000003
> +#define VIVS_HI                                                        0x00000000
> +
> +#define VIVS_HI_CLOCK_CONTROL                                  0x00000000
> +#define VIVS_HI_CLOCK_CONTROL_CLK3D_DIS                                0x00000001
> +#define VIVS_HI_CLOCK_CONTROL_CLK2D_DIS                                0x00000002
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK                 0x000001fc
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT                        2
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(x)                    (((x) << VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT) & VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK)
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD                  0x00000200
> +#define VIVS_HI_CLOCK_CONTROL_DISABLE_RAM_CLK_GATING           0x00000400
> +#define VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS          0x00000800
> +#define VIVS_HI_CLOCK_CONTROL_SOFT_RESET                       0x00001000
> +#define VIVS_HI_CLOCK_CONTROL_IDLE_3D                          0x00010000
> +#define VIVS_HI_CLOCK_CONTROL_IDLE_2D                          0x00020000
> +#define VIVS_HI_CLOCK_CONTROL_IDLE_VG                          0x00040000
> +#define VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU                      0x00080000
> +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK           0x00f00000
> +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT          20
> +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(x)              (((x) << VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT) & VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK)
> +
> +#define VIVS_HI_IDLE_STATE                                     0x00000004
> +#define VIVS_HI_IDLE_STATE_FE                                  0x00000001
> +#define VIVS_HI_IDLE_STATE_DE                                  0x00000002
> +#define VIVS_HI_IDLE_STATE_PE                                  0x00000004
> +#define VIVS_HI_IDLE_STATE_SH                                  0x00000008
> +#define VIVS_HI_IDLE_STATE_PA                                  0x00000010
> +#define VIVS_HI_IDLE_STATE_SE                                  0x00000020
> +#define VIVS_HI_IDLE_STATE_RA                                  0x00000040
> +#define VIVS_HI_IDLE_STATE_TX                                  0x00000080
> +#define VIVS_HI_IDLE_STATE_VG                                  0x00000100
> +#define VIVS_HI_IDLE_STATE_IM                                  0x00000200
> +#define VIVS_HI_IDLE_STATE_FP                                  0x00000400
> +#define VIVS_HI_IDLE_STATE_TS                                  0x00000800
> +#define VIVS_HI_IDLE_STATE_AXI_LP                              0x80000000
> +
> +#define VIVS_HI_AXI_CONFIG                                     0x00000008
> +#define VIVS_HI_AXI_CONFIG_AWID__MASK                          0x0000000f
> +#define VIVS_HI_AXI_CONFIG_AWID__SHIFT                         0
> +#define VIVS_HI_AXI_CONFIG_AWID(x)                             (((x) << VIVS_HI_AXI_CONFIG_AWID__SHIFT) & VIVS_HI_AXI_CONFIG_AWID__MASK)
> +#define VIVS_HI_AXI_CONFIG_ARID__MASK                          0x000000f0
> +#define VIVS_HI_AXI_CONFIG_ARID__SHIFT                         4
> +#define VIVS_HI_AXI_CONFIG_ARID(x)                             (((x) << VIVS_HI_AXI_CONFIG_ARID__SHIFT) & VIVS_HI_AXI_CONFIG_ARID__MASK)
> +#define VIVS_HI_AXI_CONFIG_AWCACHE__MASK                       0x00000f00
> +#define VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT                      8
> +#define VIVS_HI_AXI_CONFIG_AWCACHE(x)                          (((x) << VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_AWCACHE__MASK)
> +#define VIVS_HI_AXI_CONFIG_ARCACHE__MASK                       0x0000f000
> +#define VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT                      12
> +#define VIVS_HI_AXI_CONFIG_ARCACHE(x)                          (((x) << VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_ARCACHE__MASK)
> +
> +#define VIVS_HI_AXI_STATUS                                     0x0000000c
> +#define VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK                     0x0000000f
> +#define VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT                    0
> +#define VIVS_HI_AXI_STATUS_WR_ERR_ID(x)                                (((x) << VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK)
> +#define VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK                     0x000000f0
> +#define VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT                    4
> +#define VIVS_HI_AXI_STATUS_RD_ERR_ID(x)                                (((x) << VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK)
> +#define VIVS_HI_AXI_STATUS_DET_WR_ERR                          0x00000100
> +#define VIVS_HI_AXI_STATUS_DET_RD_ERR                          0x00000200
> +
> +#define VIVS_HI_INTR_ACKNOWLEDGE                               0x00000010
> +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK                        0x7fffffff
> +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT               0
> +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC(x)                   (((x) << VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT) & VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK)
> +#define VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR                 0x80000000
> +
> +#define VIVS_HI_INTR_ENBL                                      0x00000014
> +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK                  0xffffffff
> +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT                 0
> +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC(x)                     (((x) << VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT) & VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK)
> +
> +#define VIVS_HI_CHIP_IDENTITY                                  0x00000018
> +#define VIVS_HI_CHIP_IDENTITY_FAMILY__MASK                     0xff000000
> +#define VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT                    24
> +#define VIVS_HI_CHIP_IDENTITY_FAMILY(x)                                (((x) << VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT) & VIVS_HI_CHIP_IDENTITY_FAMILY__MASK)
> +#define VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK                    0x00ff0000
> +#define VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT                   16
> +#define VIVS_HI_CHIP_IDENTITY_PRODUCT(x)                       (((x) << VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT) & VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK)
> +#define VIVS_HI_CHIP_IDENTITY_REVISION__MASK                   0x0000f000
> +#define VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT                  12
> +#define VIVS_HI_CHIP_IDENTITY_REVISION(x)                      (((x) << VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT) & VIVS_HI_CHIP_IDENTITY_REVISION__MASK)
> +
> +#define VIVS_HI_CHIP_FEATURE                                   0x0000001c
> +
> +#define VIVS_HI_CHIP_MODEL                                     0x00000020
> +
> +#define VIVS_HI_CHIP_REV                                       0x00000024
> +
> +#define VIVS_HI_CHIP_DATE                                      0x00000028
> +
> +#define VIVS_HI_CHIP_TIME                                      0x0000002c
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_0                           0x00000034
> +
> +#define VIVS_HI_CACHE_CONTROL                                  0x00000038
> +
> +#define VIVS_HI_MEMORY_COUNTER_RESET                           0x0000003c
> +
> +#define VIVS_HI_PROFILE_READ_BYTES8                            0x00000040
> +
> +#define VIVS_HI_PROFILE_WRITE_BYTES8                           0x00000044
> +
> +#define VIVS_HI_CHIP_SPECS                                     0x00000048
> +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK                  0x0000000f
> +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT                 0
> +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT(x)                     (((x) << VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK                  0x000000f0
> +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT                 4
> +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX(x)                     (((x) << VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT) & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
> +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK                  0x00000f00
> +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT                 8
> +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT(x)                     (((x) << VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK             0x0001f000
> +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT            12
> +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE(x)                        (((x) << VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
> +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK             0x01f00000
> +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT            20
> +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT(x)                        (((x) << VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK                   0x0e000000
> +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT                  25
> +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES(x)                      (((x) << VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT) & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
> +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK     0xf0000000
> +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT    28
> +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE(x)                (((x) << VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
> +
> +#define VIVS_HI_PROFILE_WRITE_BURSTS                           0x0000004c
> +
> +#define VIVS_HI_PROFILE_WRITE_REQUESTS                         0x00000050
> +
> +#define VIVS_HI_PROFILE_READ_BURSTS                            0x00000058
> +
> +#define VIVS_HI_PROFILE_READ_REQUESTS                          0x0000005c
> +
> +#define VIVS_HI_PROFILE_READ_LASTS                             0x00000060
> +
> +#define VIVS_HI_GP_OUT0                                                0x00000064
> +
> +#define VIVS_HI_GP_OUT1                                                0x00000068
> +
> +#define VIVS_HI_GP_OUT2                                                0x0000006c
> +
> +#define VIVS_HI_AXI_CONTROL                                    0x00000070
> +#define VIVS_HI_AXI_CONTROL_WR_FULL_BURST_MODE                 0x00000001
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_1                           0x00000074
> +
> +#define VIVS_HI_PROFILE_TOTAL_CYCLES                           0x00000078
> +
> +#define VIVS_HI_PROFILE_IDLE_CYCLES                            0x0000007c
> +
> +#define VIVS_HI_CHIP_SPECS_2                                   0x00000080
> +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK                 0x000000ff
> +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT                        0
> +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE(x)                    (((x) << VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
> +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK           0x0000ff00
> +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT          8
> +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT(x)              (((x) << VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK               0xffff0000
> +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT              16
> +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS(x)                  (((x) << VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT) & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_2                           0x00000084
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_3                           0x00000088
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_4                           0x00000094
> +
> +#define VIVS_PM                                                        0x00000000
> +
> +#define VIVS_PM_POWER_CONTROLS                                 0x00000100
> +#define VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING      0x00000001
> +#define VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING       0x00000002
> +#define VIVS_PM_POWER_CONTROLS_DISABLE_STARVE_MODULE_CLOCK_GATING      0x00000004
> +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK           0x000000f0
> +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT          4
> +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER(x)              (((x) << VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK)
> +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK          0xffff0000
> +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT         16
> +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER(x)             (((x) << VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK)
> +
> +#define VIVS_PM_MODULE_CONTROLS                                        0x00000104
> +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_FE 0x00000001
> +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_DE 0x00000002
> +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_PE 0x00000004
> +
> +#define VIVS_PM_MODULE_STATUS                                  0x00000108
> +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_FE            0x00000001
> +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_DE            0x00000002
> +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_PE            0x00000004
> +
> +#define VIVS_PM_PULSE_EATER                                    0x0000010c
> +
> +#define VIVS_MMUv2                                             0x00000000
> +
> +#define VIVS_MMUv2_SAFE_ADDRESS                                        0x00000180
> +
> +#define VIVS_MMUv2_CONFIGURATION                               0x00000184
> +#define VIVS_MMUv2_CONFIGURATION_MODE__MASK                    0x00000001
> +#define VIVS_MMUv2_CONFIGURATION_MODE__SHIFT                   0
> +#define VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K                  0x00000000
> +#define VIVS_MMUv2_CONFIGURATION_MODE_MODE1_K                  0x00000001
> +#define VIVS_MMUv2_CONFIGURATION_MODE_MASK                     0x00000008
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH__MASK                   0x00000010
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH__SHIFT                  4
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH_FLUSH                   0x00000010
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH_MASK                    0x00000080
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS_MASK                  0x00000100
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK                 0xfffffc00
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT                        10
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS(x)                    (((x) << VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT) & VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK)
> +
> +#define VIVS_MMUv2_STATUS                                      0x00000188
> +#define VIVS_MMUv2_STATUS_EXCEPTION0__MASK                     0x00000003
> +#define VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT                    0
> +#define VIVS_MMUv2_STATUS_EXCEPTION0(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK)
> +#define VIVS_MMUv2_STATUS_EXCEPTION1__MASK                     0x00000030
> +#define VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT                    4
> +#define VIVS_MMUv2_STATUS_EXCEPTION1(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION1__MASK)
> +#define VIVS_MMUv2_STATUS_EXCEPTION2__MASK                     0x00000300
> +#define VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT                    8
> +#define VIVS_MMUv2_STATUS_EXCEPTION2(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION2__MASK)
> +#define VIVS_MMUv2_STATUS_EXCEPTION3__MASK                     0x00003000
> +#define VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT                    12
> +#define VIVS_MMUv2_STATUS_EXCEPTION3(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION3__MASK)
> +
> +#define VIVS_MMUv2_CONTROL                                     0x0000018c
> +#define VIVS_MMUv2_CONTROL_ENABLE                              0x00000001
> +
> +#define VIVS_MMUv2_EXCEPTION_ADDR(i0)                         (0x00000190 + 0x4*(i0))
> +#define VIVS_MMUv2_EXCEPTION_ADDR__ESIZE                       0x00000004
> +#define VIVS_MMUv2_EXCEPTION_ADDR__LEN                         0x00000004
> +
> +#define VIVS_MC                                                        0x00000000
> +
> +#define VIVS_MC_MMU_FE_PAGE_TABLE                              0x00000400
> +
> +#define VIVS_MC_MMU_TX_PAGE_TABLE                              0x00000404
> +
> +#define VIVS_MC_MMU_PE_PAGE_TABLE                              0x00000408
> +
> +#define VIVS_MC_MMU_PEZ_PAGE_TABLE                             0x0000040c
> +
> +#define VIVS_MC_MMU_RA_PAGE_TABLE                              0x00000410
> +
> +#define VIVS_MC_DEBUG_MEMORY                                   0x00000414
> +#define VIVS_MC_DEBUG_MEMORY_SPECIAL_PATCH_GC320               0x00000008
> +#define VIVS_MC_DEBUG_MEMORY_FAST_CLEAR_BYPASS                 0x00100000
> +#define VIVS_MC_DEBUG_MEMORY_COMPRESSION_BYPASS                        0x00200000
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_RA                            0x00000418
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_FE                            0x0000041c
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_TX                            0x00000420
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_PEZ                           0x00000424
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_PE                            0x00000428
> +
> +#define VIVS_MC_MEMORY_TIMING_CONTROL                          0x0000042c
> +
> +#define VIVS_MC_MEMORY_FLUSH                                   0x00000430
> +
> +#define VIVS_MC_PROFILE_CYCLE_COUNTER                          0x00000438
> +
> +#define VIVS_MC_DEBUG_READ0                                    0x0000043c
> +
> +#define VIVS_MC_DEBUG_READ1                                    0x00000440
> +
> +#define VIVS_MC_DEBUG_WRITE                                    0x00000444
> +
> +#define VIVS_MC_PROFILE_RA_READ                                        0x00000448
> +
> +#define VIVS_MC_PROFILE_TX_READ                                        0x0000044c
> +
> +#define VIVS_MC_PROFILE_FE_READ                                        0x00000450
> +
> +#define VIVS_MC_PROFILE_PE_READ                                        0x00000454
> +
> +#define VIVS_MC_PROFILE_DE_READ                                        0x00000458
> +
> +#define VIVS_MC_PROFILE_SH_READ                                        0x0000045c
> +
> +#define VIVS_MC_PROFILE_PA_READ                                        0x00000460
> +
> +#define VIVS_MC_PROFILE_SE_READ                                        0x00000464
> +
> +#define VIVS_MC_PROFILE_MC_READ                                        0x00000468
> +
> +#define VIVS_MC_PROFILE_HI_READ                                        0x0000046c
> +
> +#define VIVS_MC_PROFILE_CONFIG0                                        0x00000470
> +#define VIVS_MC_PROFILE_CONFIG0_FE__MASK                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG0_FE__SHIFT                      0
> +#define VIVS_MC_PROFILE_CONFIG0_FE_RESET                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG0_DE__MASK                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG0_DE__SHIFT                      8
> +#define VIVS_MC_PROFILE_CONFIG0_DE_RESET                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG0_PE__MASK                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG0_PE__SHIFT                      16
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE    0x00000000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE    0x00010000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE     0x00020000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE     0x00030000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D          0x000b0000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_RESET                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG0_SH__MASK                       0x0f000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH__SHIFT                      24
> +#define VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES               0x04000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER             0x07000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER      0x08000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER             0x09000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER    0x0a000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER     0x0b000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER      0x0c000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER     0x0d000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER      0x0e000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_RESET                       0x0f000000
> +
> +#define VIVS_MC_PROFILE_CONFIG1                                        0x00000474
> +#define VIVS_MC_PROFILE_CONFIG1_PA__MASK                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG1_PA__SHIFT                      0
> +#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER           0x00000003
> +#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER          0x00000004
> +#define VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER         0x00000005
> +#define VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER       0x00000006
> +#define VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER    0x00000007
> +#define VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER              0x00000008
> +#define VIVS_MC_PROFILE_CONFIG1_PA_RESET                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG1_SE__MASK                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG1_SE__SHIFT                      8
> +#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT       0x00000000
> +#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT          0x00000100
> +#define VIVS_MC_PROFILE_CONFIG1_SE_RESET                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG1_RA__MASK                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG1_RA__SHIFT                      16
> +#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT           0x00000000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT            0x00010000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z      0x00020000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT       0x00030000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER     0x00090000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER 0x000a0000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT           0x000b0000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_RESET                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG1_TX__MASK                       0x0f000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX__SHIFT                      24
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS     0x00000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS    0x01000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS    0x02000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS      0x03000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_UNKNOWN                     0x04000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT              0x05000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT                0x06000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT            0x07000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT       0x08000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT      0x09000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_RESET                       0x0f000000
> +
> +#define VIVS_MC_PROFILE_CONFIG2                                        0x00000478
> +#define VIVS_MC_PROFILE_CONFIG2_MC__MASK                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG2_MC__SHIFT                      0
> +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE     0x00000001
> +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP   0x00000002
> +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE    0x00000003
> +#define VIVS_MC_PROFILE_CONFIG2_MC_RESET                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG2_HI__MASK                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG2_HI__SHIFT                      8
> +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED     0x00000000
> +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED    0x00000100
> +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED       0x00000200
> +#define VIVS_MC_PROFILE_CONFIG2_HI_RESET                       0x00000f00
> +
> +#define VIVS_MC_PROFILE_CONFIG3                                        0x0000047c
> +
> +#define VIVS_MC_BUS_CONFIG                                     0x00000480
> +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK                 0x0000000f
> +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT                        0
> +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(x)                    (((x) << VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK)
> +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK                 0x000000f0
> +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT                        4
> +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(x)                    (((x) << VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK)
> +
> +#define VIVS_MC_START_COMPOSITION                              0x00000554
> +
> +#define VIVS_MC_128B_MERGE                                     0x00000558
> +
> +
> +#endif /* STATE_HI_XML */
> diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
> new file mode 100644
> index 000000000000..5f1206b3f9ba
> --- /dev/null
> +++ b/include/uapi/drm/etnaviv_drm.h
> @@ -0,0 +1,215 @@
> +/*
> + * 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_DRM_H__
> +#define __ETNAVIV_DRM_H__
> +
> +#include <drm/drm.h>
> +
> +/* Please note that modifications to all structs defined here are
> + * subject to backwards-compatibility constraints:
> + *  1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
> + *     user/kernel compatibility
> + *  2) Keep fields aligned to their size
> + *  3) Because of how drm_ioctl() works, we can add new fields at
> + *     the end of an ioctl if some care is taken: drm_ioctl() will
> + *     zero out the new fields at the tail of the ioctl, so a zero
> + *     value should have a backwards compatible meaning.  And for
> + *     output params, userspace won't see the newly added output
> + *     fields.. so that has to be somehow ok.
> + */
> +
> +/* timeouts are specified in clock-monotonic absolute times (to simplify
> + * restarting interrupted ioctls).  The following struct is logically the
> + * same as 'struct timespec' but 32/64b ABI safe.
> + */
> +struct drm_etnaviv_timespec {
> +       __s64 tv_sec;          /* seconds */
> +       __s64 tv_nsec;         /* nanoseconds */
> +};
> +
> +#define ETNAVIV_PARAM_GPU_MODEL                     0x01
> +#define ETNAVIV_PARAM_GPU_REVISION                  0x02
> +#define ETNAVIV_PARAM_GPU_FEATURES_0                0x03
> +#define ETNAVIV_PARAM_GPU_FEATURES_1                0x04
> +#define ETNAVIV_PARAM_GPU_FEATURES_2                0x05
> +#define ETNAVIV_PARAM_GPU_FEATURES_3                0x06
> +#define ETNAVIV_PARAM_GPU_FEATURES_4                0x07
> +
> +#define ETNAVIV_PARAM_GPU_STREAM_COUNT              0x10
> +#define ETNAVIV_PARAM_GPU_REGISTER_MAX              0x11
> +#define ETNAVIV_PARAM_GPU_THREAD_COUNT              0x12
> +#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE         0x13
> +#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT         0x14
> +#define ETNAVIV_PARAM_GPU_PIXEL_PIPES               0x15
> +#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16
> +#define ETNAVIV_PARAM_GPU_BUFFER_SIZE               0x17
> +#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT         0x18
> +#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS             0x19
> +
> +#define ETNA_MAX_PIPES 4
> +
> +struct drm_etnaviv_param {
> +       __u32 pipe;           /* in */
> +       __u32 param;          /* in, ETNAVIV_PARAM_x */
> +       __u64 value;          /* out (get_param) or in (set_param) */
> +};
> +
> +/*
> + * GEM buffers:
> + */
> +
> +#define ETNA_BO_CACHE_MASK   0x000f0000
> +/* cache modes */
> +#define ETNA_BO_CACHED       0x00010000
> +#define ETNA_BO_WC           0x00020000
> +#define ETNA_BO_UNCACHED     0x00040000
> +/* map flags */
> +#define ETNA_BO_FORCE_MMU    0x00100000
> +
> +struct drm_etnaviv_gem_new {
> +       __u64 size;           /* in */
> +       __u32 flags;          /* in, mask of ETNA_BO_x */
> +       __u32 handle;         /* out */
> +};
> +
> +struct drm_etnaviv_gem_info {
> +       __u32 handle;         /* in */
> +       __u32 pad;
> +       __u64 offset;         /* out, offset to pass to mmap() */
> +};
> +
> +#define ETNA_PREP_READ        0x01
> +#define ETNA_PREP_WRITE       0x02
> +#define ETNA_PREP_NOSYNC      0x04
> +
> +struct drm_etnaviv_gem_cpu_prep {
> +       __u32 handle;         /* in */
> +       __u32 op;             /* in, mask of ETNA_PREP_x */
> +       struct drm_etnaviv_timespec timeout;   /* in */
> +};
> +
> +struct drm_etnaviv_gem_cpu_fini {
> +       __u32 handle;         /* in */
> +};
> +
> +/*
> + * Cmdstream Submission:
> + */
> +
> +/* The value written into the cmdstream is logically:
> + * relocbuf->gpuaddr + reloc_offset
> + *
> + * NOTE that reloc's must be sorted by order of increasing submit_offset,
> + * otherwise EINVAL.
> + */
> +struct drm_etnaviv_gem_submit_reloc {
> +       __u32 submit_offset;  /* in, offset from submit_bo */
> +       __u32 reloc_idx;      /* in, index of reloc_bo buffer */
> +       __u64 reloc_offset;   /* in, offset from start of reloc_bo */
> +};
> +
> +/* Each buffer referenced elsewhere in the cmdstream submit (ie. the
> + * cmdstream buffer(s) themselves or reloc entries) has one (and only
> + * one) entry in the submit->bos[] table.
> + *
> + * As a optimization, the current buffer (gpu virtual address) can be
> + * passed back through the 'presumed' field.  If on a subsequent reloc,
> + * userspace passes back a 'presumed' address that is still valid,
> + * then patching the cmdstream for this entry is skipped.  This can
> + * avoid kernel needing to map/access the cmdstream bo in the common
> + * case.
> + */
> +#define ETNA_SUBMIT_BO_READ             0x0001
> +#define ETNA_SUBMIT_BO_WRITE            0x0002
> +struct drm_etnaviv_gem_submit_bo {
> +       __u32 flags;          /* in, mask of ETNA_SUBMIT_BO_x */
> +       __u32 handle;         /* in, GEM handle */
> +       __u64 presumed;       /* in/out, presumed buffer address */
> +};
> +
> +/* Each cmdstream submit consists of a table of buffers involved, and
> + * one or more cmdstream buffers.  This allows for conditional execution
> + * (context-restore), and IB buffers needed for per tile/bin draw cmds.
> + */
> +#define ETNA_PIPE_3D      0x00
> +#define ETNA_PIPE_2D      0x01
> +#define ETNA_PIPE_VG      0x02
> +struct drm_etnaviv_gem_submit {
> +       __u32 fence;          /* out */
> +       __u32 pipe;           /* in */
> +       __u32 exec_state;     /* in, initial execution state (ETNA_PIPE_x) */
> +       __u32 nr_bos;         /* in, number of submit_bo's */
> +       __u32 nr_relocs;      /* in, number of submit_reloc's */
> +       __u32 stream_size;    /* in, cmdstream size */
> +       __u64 bos;            /* in, ptr to array of submit_bo's */
> +       __u64 relocs;         /* in, ptr to array of submit_reloc's */
> +       __u64 stream;         /* in, ptr to cmdstream */
> +};
> +
> +/* The normal way to synchronize with the GPU is just to CPU_PREP on
> + * a buffer if you need to access it from the CPU (other cmdstream
> + * submission from same or other contexts, PAGE_FLIP ioctl, etc, all
> + * handle the required synchronization under the hood).  This ioctl
> + * mainly just exists as a way to implement the gallium pipe_fence
> + * APIs without requiring a dummy bo to synchronize on.
> + */
> +struct drm_etnaviv_wait_fence {
> +       __u32 pipe;           /* in */
> +       __u32 fence;          /* in */
> +       struct drm_etnaviv_timespec timeout;   /* in */
> +};
> +
> +#define ETNA_USERPTR_READ      0x01
> +#define ETNA_USERPTR_WRITE     0x02
> +struct drm_etnaviv_gem_userptr {
> +       __u64 user_ptr; /* in, page aligned user pointer */
> +       __u64 user_size;        /* in, page aligned user size */
> +       __u32 flags;            /* in, flags */
> +       __u32 handle;   /* out, non-zero handle */
> +};
> +
> +struct drm_etnaviv_gem_wait {
> +       __u32 pipe;                             /* in */
> +       __u32 handle;                           /* in, bo to be waited for */
> +       struct drm_etnaviv_timespec timeout;    /* in */
> +};
> +
> +#define DRM_ETNAVIV_GET_PARAM          0x00
> +/* placeholder:
> +#define DRM_ETNAVIV_SET_PARAM          0x01
> + */
> +#define DRM_ETNAVIV_GEM_NEW            0x02
> +#define DRM_ETNAVIV_GEM_INFO           0x03
> +#define DRM_ETNAVIV_GEM_CPU_PREP       0x04
> +#define DRM_ETNAVIV_GEM_CPU_FINI       0x05
> +#define DRM_ETNAVIV_GEM_SUBMIT         0x06
> +#define DRM_ETNAVIV_WAIT_FENCE         0x07
> +#define DRM_ETNAVIV_GEM_USERPTR        0x08
> +#define DRM_ETNAVIV_GEM_WAIT           0x09
> +#define DRM_ETNAVIV_NUM_IOCTLS         0x0a
> +
> +#define DRM_IOCTL_ETNAVIV_GET_PARAM    DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
> +#define DRM_IOCTL_ETNAVIV_GEM_NEW      DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
> +#define DRM_IOCTL_ETNAVIV_GEM_INFO     DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info)
> +#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep)
> +#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini)
> +#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT   DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit)
> +#define DRM_IOCTL_ETNAVIV_WAIT_FENCE   DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
> +#define DRM_IOCTL_ETNAVIV_GEM_USERPTR  DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
> +#define DRM_IOCTL_ETNAVIV_GEM_WAIT     DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
> +
> +#endif /* __ETNAVIV_DRM_H__ */
> --
> 2.5.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-11 14:10 ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Lucas Stach
  2015-09-14 13:16   ` Rob Clark
@ 2015-09-16  6:11   ` Christian Gmeiner
  2015-09-16  7:49     ` Russell King - ARM Linux
  2015-09-16 15:30     ` Lucas Stach
  2015-09-16  8:04   ` Russell King - ARM Linux
  2015-09-16 15:05   ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Eric Anholt
  3 siblings, 2 replies; 100+ messages in thread
From: Christian Gmeiner @ 2015-09-16  6:11 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, Sascha Hauer, DRI mailing list

Hi Lucas


2015-09-11 16:10 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> From: Christian Gmeiner <christian.gmeiner@gmail.com>
>
> This is a squashed commit of the complete etnaviv DRM driver in order
> to make it easy for people to review the code by seeing the driver as a
> whole and is not intended for merging in this form.
>
> If you are interested in the history of individual commits:
> git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
>
> 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>
> ---
>  drivers/staging/Kconfig                      |    2 +
>  drivers/staging/Makefile                     |    1 +
>  drivers/staging/etnaviv/Kconfig              |   20 +
>  drivers/staging/etnaviv/Makefile             |   18 +
>  drivers/staging/etnaviv/cmdstream.xml.h      |  218 ++++
>  drivers/staging/etnaviv/common.xml.h         |  249 +++++
>  drivers/staging/etnaviv/etnaviv_buffer.c     |  271 +++++
>  drivers/staging/etnaviv/etnaviv_cmd_parser.c |  119 +++
>  drivers/staging/etnaviv/etnaviv_drv.c        |  705 +++++++++++++
>  drivers/staging/etnaviv/etnaviv_drv.h        |  138 +++
>  drivers/staging/etnaviv/etnaviv_gem.c        |  887 ++++++++++++++++
>  drivers/staging/etnaviv/etnaviv_gem.h        |  141 +++
>  drivers/staging/etnaviv/etnaviv_gem_prime.c  |  121 +++
>  drivers/staging/etnaviv/etnaviv_gem_submit.c |  421 ++++++++
>  drivers/staging/etnaviv/etnaviv_gpu.c        | 1468 ++++++++++++++++++++++++++
>  drivers/staging/etnaviv/etnaviv_gpu.h        |  198 ++++
>  drivers/staging/etnaviv/etnaviv_iommu.c      |  221 ++++
>  drivers/staging/etnaviv/etnaviv_iommu.h      |   28 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.c   |   33 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.h   |   25 +
>  drivers/staging/etnaviv/etnaviv_mmu.c        |  282 +++++
>  drivers/staging/etnaviv/etnaviv_mmu.h        |   58 +
>  drivers/staging/etnaviv/state.xml.h          |  351 ++++++
>  drivers/staging/etnaviv/state_hi.xml.h       |  407 +++++++
>  include/uapi/drm/etnaviv_drm.h               |  215 ++++
>  25 files changed, 6597 insertions(+)
>  create mode 100644 drivers/staging/etnaviv/Kconfig
>  create mode 100644 drivers/staging/etnaviv/Makefile
>  create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h
>  create mode 100644 drivers/staging/etnaviv/common.xml.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h
>  create mode 100644 drivers/staging/etnaviv/state.xml.h
>  create mode 100644 drivers/staging/etnaviv/state_hi.xml.h
>  create mode 100644 include/uapi/drm/etnaviv_drm.h
>
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index 7f6cae5beb90..5446fe4859ce 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -112,4 +112,6 @@ source "drivers/staging/fsl-mc/Kconfig"
>
>  source "drivers/staging/wilc1000/Kconfig"
>
> +source "drivers/staging/etnaviv/Kconfig"
> +
>  endif # STAGING
> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> index 347f6477aa3e..9fd3c06b6bfd 100644
> --- a/drivers/staging/Makefile
> +++ b/drivers/staging/Makefile
> @@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
>  obj-$(CONFIG_FB_TFT)           += fbtft/
>  obj-$(CONFIG_FSL_MC_BUS)       += fsl-mc/
>  obj-$(CONFIG_WILC1000)         += wilc1000/
> +obj-$(CONFIG_DRM_ETNAVIV)      += etnaviv/
> diff --git a/drivers/staging/etnaviv/Kconfig b/drivers/staging/etnaviv/Kconfig
> new file mode 100644
> index 000000000000..6f034eda914c
> --- /dev/null
> +++ b/drivers/staging/etnaviv/Kconfig
> @@ -0,0 +1,20 @@
> +
> +config DRM_ETNAVIV
> +       tristate "etnaviv DRM"
> +       depends on DRM
> +       select SHMEM
> +       select TMPFS
> +       select IOMMU_API
> +       select IOMMU_SUPPORT
> +       default y
> +       help
> +         DRM driver for Vivante GPUs.
> +
> +config DRM_ETNAVIV_REGISTER_LOGGING
> +       bool "etnaviv DRM register logging"
> +       depends on DRM_ETNAVIV
> +       default n
> +       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.
> diff --git a/drivers/staging/etnaviv/Makefile b/drivers/staging/etnaviv/Makefile
> new file mode 100644
> index 000000000000..2b71c31b6501
> --- /dev/null
> +++ b/drivers/staging/etnaviv/Makefile
> @@ -0,0 +1,18 @@
> +ccflags-y := -Iinclude/drm -Idrivers/staging/vivante
> +ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
> +       ccflags-y += -Werror
> +endif
> +
> +etnaviv-y := \
> +       etnaviv_cmd_parser.o \
> +       etnaviv_drv.o \
> +       etnaviv_gem.o \
> +       etnaviv_gem_prime.o \
> +       etnaviv_gem_submit.o \
> +       etnaviv_gpu.o \
> +       etnaviv_iommu.o \
> +       etnaviv_iommu_v2.o \
> +       etnaviv_mmu.o \
> +       etnaviv_buffer.o
> +
> +obj-$(CONFIG_DRM_ETNAVIV)      += etnaviv.o
> diff --git a/drivers/staging/etnaviv/cmdstream.xml.h b/drivers/staging/etnaviv/cmdstream.xml.h
> new file mode 100644
> index 000000000000..8c44ba9a694e
> --- /dev/null
> +++ b/drivers/staging/etnaviv/cmdstream.xml.h
> @@ -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 */
> diff --git a/drivers/staging/etnaviv/common.xml.h b/drivers/staging/etnaviv/common.xml.h
> new file mode 100644
> index 000000000000..9e585d51fb78
> --- /dev/null
> +++ b/drivers/staging/etnaviv/common.xml.h
> @@ -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 */
> diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
> new file mode 100644
> index 000000000000..586f84316f1a
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_buffer.c
> @@ -0,0 +1,271 @@
> +/*
> + * 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;
> +
> +       if (pipe == ETNA_PIPE_2D)
> +               flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR;
> +       else
> +               flush = VIVS_GL_FLUSH_CACHE_TEXTURE;
> +
> +       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_gem_submit *submit)
> +{
> +       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, submit->cmdbuf),
> +                       submit->cmdbuf->vaddr);
> +
> +       /* jump back from cmd to main buffer */
> +       CMD_LINK(submit->cmdbuf, link_size, link_target);
> +
> +       link_target = gpu_va(gpu, submit->cmdbuf);
> +       link_size = submit->cmdbuf->size / 8;
> +
> +
> +
> +       if (drm_debug & DRM_UT_DRIVER) {
> +               print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
> +                              submit->cmdbuf->vaddr, submit->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, submit->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;
> +       }
> +
> +       /* Save the event and buffer position of the new event trigger */
> +       gpu->event[event].fence = submit->fence;
> +
> +       /* take ownership of cmdbuffer*/
> +       submit->cmdbuf->fence = submit->fence;
> +       list_add_tail(&submit->cmdbuf->gpu_active_list, &gpu->active_cmd_list);
> +       submit->cmdbuf = NULL;
> +
> +       /* 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);
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_cmd_parser.c b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
> new file mode 100644
> index 000000000000..5175d6eb3bdc
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
> @@ -0,0 +1,119 @@
> +/*
> + * 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)
> +
> +static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf,
> +       unsigned int state, unsigned int num)
> +{
> +       return true;
> +       if (0x1200 - state < num * 4)
> +               return false;
> +       if (0x1228 - state < num * 4)
> +               return false;
> +       if (0x1238 - state < num * 4)
> +               return false;
> +       if (0x1284 - state < num * 4)
> +               return false;
> +       if (0x128c - state < num * 4)
> +               return false;
> +       if (0x1304 - state < num * 4)
> +               return false;
> +       if (0x1310 - state < num * 4)
> +               return false;
> +       if (0x1318 - state < num * 4)
> +               return false;
> +       if (0x1280c - state < num * 4 + 0x0c)
> +               return false;
> +       if (0x128ac - state < num * 4 + 0x0c)
> +               return false;
> +       if (0x128cc - state < num * 4 + 0x0c)
> +               return false;
> +       if (0x1297c - state < num * 4 + 0x0c)
> +               return false;
> +       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, void *stream,
> +                             unsigned int size)
> +{
> +       u32 *start = stream;
> +       u32 *buf = start;
> +       u32 *end = buf + size;
> +
> +       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(gpu, buf + 1,
> +                                                        off * 4, n)) {
> +                               dev_warn(gpu->dev, "%s: load state covers restricted state (0x%x-0x%x) at offset %tu\n",
> +                                        __func__, off * 4, (off + n) * 4, buf - start);
> +                               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 - start);
> +                               return false;
> +                       }
> +                       break;
> +               }
> +
> +               buf += len;
> +       }
> +
> +       if (buf > end) {
> +               dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
> +                       __func__, buf - start, size);
> +               return false;
> +       }
> +
> +       return true;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
> new file mode 100644
> index 000000000000..30f6e5d0c91d
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_drv.c
> @@ -0,0 +1,705 @@
> +/*
> + * 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/component.h>
> +#include <linux/of_platform.h>
> +
> +#include "etnaviv_drv.h"
> +#include "etnaviv_gpu.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_mmu.h"
> +#include "etnaviv_gem.h"
> +
> +#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
> +static bool reglog;
> +MODULE_PARM_DESC(reglog, "Enable register read/write logging");
> +module_param(reglog, bool, 0600);
> +#else
> +#define reglog 0
> +#endif
> +
> +void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name,
> +               const char *dbgname)
> +{
> +       struct resource *res;
> +       void __iomem *ptr;
> +
> +       if (name)
> +               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
> +       else
> +               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> +       ptr = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(ptr)) {
> +               dev_err(&pdev->dev, "failed to ioremap %s: %ld\n", name,
> +                       PTR_ERR(ptr));
> +               return ptr;
> +       }
> +
> +       if (reglog)
> +               dev_printk(KERN_DEBUG, &pdev->dev, "IO:region %s 0x%p %08zx\n",
> +                          dbgname, ptr, (size_t)resource_size(res));
> +
> +       return ptr;
> +}
> +
> +void etnaviv_writel(u32 data, void __iomem *addr)
> +{
> +       if (reglog)
> +               printk(KERN_DEBUG "IO:W %p %08x\n", addr, data);
> +
> +       writel(data, addr);
> +}
> +
> +u32 etnaviv_readl(const void __iomem *addr)
> +{
> +       u32 val = readl(addr);
> +
> +       if (reglog)
> +               printk(KERN_DEBUG "IO:R %p %08x\n", addr, val);
> +
> +       return val;
> +}
> +
> +/*
> + * DRM operations:
> + */
> +
> +static int etnaviv_unload(struct drm_device *dev)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +
> +       flush_workqueue(priv->wq);
> +       destroy_workqueue(priv->wq);
> +
> +       component_unbind_all(dev->dev, dev);
> +
> +       dev->dev_private = NULL;
> +
> +       kfree(priv);
> +
> +       return 0;
> +}
> +
> +
> +static void load_gpu(struct drm_device *dev)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               struct etnaviv_gpu *g = priv->gpu[i];
> +
> +               if (g) {
> +                       int ret;
> +
> +                       ret = etnaviv_gpu_init(g);
> +                       if (ret) {
> +                               dev_err(g->dev, "hw init failed: %d\n", ret);
> +                               priv->gpu[i] = NULL;
> +                       }
> +               }
> +       }
> +}
> +
> +static int etnaviv_load(struct drm_device *dev, unsigned long flags)
> +{
> +       struct platform_device *pdev = dev->platformdev;
> +       struct etnaviv_drm_private *priv;
> +       int err;
> +
> +       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +       if (!priv) {
> +               dev_err(dev->dev, "failed to allocate private data\n");
> +               return -ENOMEM;
> +       }
> +
> +       dev->dev_private = priv;
> +
> +       priv->wq = alloc_ordered_workqueue("etnaviv", 0);
> +       if (!priv->wq) {
> +               err = -ENOMEM;
> +               goto err_wq;
> +       }
> +
> +       INIT_LIST_HEAD(&priv->inactive_list);
> +       priv->num_gpus = 0;
> +
> +       platform_set_drvdata(pdev, dev);
> +
> +       err = component_bind_all(dev->dev, dev);
> +       if (err < 0)
> +               goto err_bind;
> +
> +       load_gpu(dev);
> +
> +       return 0;
> +
> +err_bind:
> +       flush_workqueue(priv->wq);
> +       destroy_workqueue(priv->wq);
> +err_wq:
> +       kfree(priv);
> +       return err;
> +}
> +
> +static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
> +{
> +       struct etnaviv_file_private *ctx;
> +
> +       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +       if (!ctx)
> +               return -ENOMEM;
> +
> +       file->driver_priv = ctx;
> +
> +       return 0;
> +}
> +
> +static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_file_private *ctx = file->driver_priv;
> +       unsigned int i;
> +
> +       mutex_lock(&dev->struct_mutex);
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               struct etnaviv_gpu *gpu = priv->gpu[i];
> +
> +               if (gpu && gpu->lastctx == ctx)
> +                       gpu->lastctx = NULL;
> +       }
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       kfree(ctx);
> +}
> +
> +/*
> + * DRM debugfs:
> + */
> +
> +#ifdef CONFIG_DEBUG_FS
> +static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (gpu) {
> +                       seq_printf(m, "Active Objects (%s):\n",
> +                                  dev_name(gpu->dev));
> +                       etnaviv_gem_describe_objects(&gpu->active_list, m);
> +               }
> +       }
> +
> +       seq_puts(m, "Inactive Objects:\n");
> +       etnaviv_gem_describe_objects(&priv->inactive_list, m);
> +
> +       return 0;
> +}
> +
> +static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
> +}
> +
> +static int etnaviv_mmu_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (gpu) {
> +                       seq_printf(m, "Active Objects (%s):\n",
> +                                  dev_name(gpu->dev));
> +                       drm_mm_dump_table(m, &gpu->mmu->mm);
> +               }
> +       }
> +       return 0;
> +}
> +
> +static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
> +{
> +       struct etnaviv_cmdbuf *buf = gpu->buffer;
> +       u32 size = buf->size;
> +       u32 *ptr = buf->vaddr;
> +       u32 i;
> +
> +       seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
> +                       buf->vaddr, (u64)buf->paddr, size - buf->user_size);
> +
> +       for (i = 0; i < size / 4; i++) {
> +               if (i && !(i % 4))
> +                       seq_puts(m, "\n");
> +               if (i % 4 == 0)
> +                       seq_printf(m, "\t0x%p: ", ptr + i);
> +               seq_printf(m, "%08x ", *(ptr + i));
> +       }
> +       seq_puts(m, "\n");
> +}
> +
> +static int etnaviv_ring_show(struct drm_device *dev, struct seq_file *m)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       unsigned int i;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (gpu) {
> +                       seq_printf(m, "Ring Buffer (%s): ",
> +                                  dev_name(gpu->dev));
> +                       etnaviv_buffer_dump(gpu, m);
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int show_locked(struct seq_file *m, void *arg)
> +{
> +       struct drm_info_node *node = (struct drm_info_node *) m->private;
> +       struct drm_device *dev = node->minor->dev;
> +       int (*show)(struct drm_device *dev, struct seq_file *m) =
> +                       node->info_ent->data;
> +       int ret;
> +
> +       ret = mutex_lock_interruptible(&dev->struct_mutex);
> +       if (ret)
> +               return ret;
> +
> +       ret = show(dev, m);
> +
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       return ret;
> +}
> +
> +static int show_each_gpu(struct seq_file *m, void *arg)
> +{
> +       struct drm_info_node *node = (struct drm_info_node *) m->private;
> +       struct drm_device *dev = node->minor->dev;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +       int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
> +                       node->info_ent->data;
> +       unsigned int i;
> +       int ret = 0;
> +
> +       for (i = 0; i < ETNA_MAX_PIPES; i++) {
> +               gpu = priv->gpu[i];
> +               if (!gpu)
> +                       continue;
> +
> +               ret = show(gpu, m);
> +               if (ret < 0)
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +static struct drm_info_list etnaviv_debugfs_list[] = {
> +               {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs},
> +               {"gem", show_locked, 0, etnaviv_gem_show},
> +               { "mm", show_locked, 0, etnaviv_mm_show },
> +               {"mmu", show_locked, 0, etnaviv_mmu_show},
> +               {"ring", show_locked, 0, etnaviv_ring_show},
> +};
> +
> +static int etnaviv_debugfs_init(struct drm_minor *minor)
> +{
> +       struct drm_device *dev = minor->dev;
> +       int ret;
> +
> +       ret = drm_debugfs_create_files(etnaviv_debugfs_list,
> +                       ARRAY_SIZE(etnaviv_debugfs_list),
> +                       minor->debugfs_root, minor);
> +
> +       if (ret) {
> +               dev_err(dev->dev, "could not install etnaviv_debugfs_list\n");
> +               return ret;
> +       }
> +
> +       return ret;
> +}
> +
> +static void etnaviv_debugfs_cleanup(struct drm_minor *minor)
> +{
> +       drm_debugfs_remove_files(etnaviv_debugfs_list,
> +                       ARRAY_SIZE(etnaviv_debugfs_list), minor);
> +}
> +#endif
> +
> +/*
> + * DRM ioctls:
> + */
> +
> +static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct drm_etnaviv_param *args = data;
> +       struct etnaviv_gpu *gpu;
> +
> +       if (args->pipe >= ETNA_MAX_PIPES)
> +               return -EINVAL;
> +
> +       gpu = priv->gpu[args->pipe];
> +       if (!gpu)
> +               return -ENXIO;
> +
> +       return etnaviv_gpu_get_param(gpu, args->param, &args->value);
> +}
> +
> +static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_new *args = data;
> +
> +       return etnaviv_gem_new_handle(dev, file, args->size,
> +                       args->flags, &args->handle);
> +}
> +
> +#define TS(t) ((struct timespec){ \
> +       .tv_sec = (t).tv_sec, \
> +       .tv_nsec = (t).tv_nsec \
> +})
> +
> +static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_cpu_prep *args = data;
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout));
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_cpu_fini *args = data;
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = etnaviv_gem_cpu_fini(obj);
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_info *args = data;
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       if (args->pad)
> +               return -EINVAL;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = mutex_lock_interruptible(&dev->struct_mutex);
> +       if (ret == 0) {
> +               ret = etnaviv_gem_mmap_offset(obj, &args->offset);
> +
> +               mutex_unlock(&dev->struct_mutex);
> +       }
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_wait_fence *args = data;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gpu *gpu;
> +
> +       if (args->pipe >= ETNA_MAX_PIPES)
> +               return -EINVAL;
> +
> +       gpu = priv->gpu[args->pipe];
> +       if (!gpu)
> +               return -ENXIO;
> +
> +       return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
> +                                                   &TS(args->timeout));
> +}
> +
> +static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
> +       struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_userptr *args = data;
> +       int access;
> +
> +       if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) ||
> +           args->flags == 0)
> +               return -EINVAL;
> +
> +       if (offset_in_page(args->user_ptr | args->user_size) ||
> +           (uintptr_t)args->user_ptr != args->user_ptr ||
> +           (u32)args->user_size != args->user_size)
> +               return -EINVAL;
> +
> +       if (args->flags & ETNA_USERPTR_WRITE)
> +               access = VERIFY_WRITE;
> +       else
> +               access = VERIFY_READ;
> +
> +       if (!access_ok(access, (void __user *)(unsigned long)args->user_ptr,
> +                      args->user_size))
> +               return -EFAULT;
> +
> +       return etnaviv_gem_new_userptr(dev, file, args->user_ptr,
> +                                      args->user_size, args->flags,
> +                                      &args->handle);
> +}
> +
> +static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
> +       struct drm_file *file)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct drm_etnaviv_gem_wait *args = data;
> +       struct drm_gem_object *obj;
> +       struct etnaviv_gpu *gpu;
> +       int ret;
> +
> +       if (args->pipe >= ETNA_MAX_PIPES)
> +               return -EINVAL;
> +
> +       gpu = priv->gpu[args->pipe];
> +       if (!gpu)
> +               return -ENXIO;
> +
> +       obj = drm_gem_object_lookup(dev, file, args->handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       ret = etnaviv_gem_wait_bo(gpu, obj, &TS(args->timeout));
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +static const struct drm_ioctl_desc etnaviv_ioctls[] = {
> +#define ETNA_IOCTL(n, func, flags) \
> +       DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
> +       ETNA_IOCTL(GET_PARAM,    get_param,    DRM_UNLOCKED|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_NEW,      gem_new,      DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_INFO,     gem_info,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_SUBMIT,   gem_submit,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(WAIT_FENCE,   wait_fence,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_USERPTR,  gem_userptr,  DRM_UNLOCKED|DRM_RENDER_ALLOW),
> +       ETNA_IOCTL(GEM_WAIT,     gem_wait,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
> +};
> +
> +static const struct vm_operations_struct vm_ops = {
> +       .fault = etnaviv_gem_fault,
> +       .open = drm_gem_vm_open,
> +       .close = drm_gem_vm_close,
> +};
> +
> +static const struct file_operations fops = {
> +       .owner              = THIS_MODULE,
> +       .open               = drm_open,
> +       .release            = drm_release,
> +       .unlocked_ioctl     = drm_ioctl,
> +#ifdef CONFIG_COMPAT
> +       .compat_ioctl       = drm_compat_ioctl,
> +#endif
> +       .poll               = drm_poll,
> +       .read               = drm_read,
> +       .llseek             = no_llseek,
> +       .mmap               = etnaviv_gem_mmap,
> +};
> +
> +static struct drm_driver etnaviv_drm_driver = {
> +       .driver_features    = DRIVER_HAVE_IRQ |
> +                               DRIVER_GEM |
> +                               DRIVER_PRIME |
> +                               DRIVER_RENDER,
> +       .load               = etnaviv_load,
> +       .unload             = etnaviv_unload,
> +       .open               = etnaviv_open,
> +       .preclose           = etnaviv_preclose,
> +       .set_busid          = drm_platform_set_busid,
> +       .gem_free_object    = etnaviv_gem_free_object,
> +       .gem_vm_ops         = &vm_ops,
> +       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> +       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +       .gem_prime_export   = drm_gem_prime_export,
> +       .gem_prime_import   = drm_gem_prime_import,
> +       .gem_prime_pin      = etnaviv_gem_prime_pin,
> +       .gem_prime_unpin    = etnaviv_gem_prime_unpin,
> +       .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table,
> +       .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
> +       .gem_prime_vmap     = etnaviv_gem_prime_vmap,
> +       .gem_prime_vunmap   = etnaviv_gem_prime_vunmap,
> +#ifdef CONFIG_DEBUG_FS
> +       .debugfs_init       = etnaviv_debugfs_init,
> +       .debugfs_cleanup    = etnaviv_debugfs_cleanup,
> +#endif
> +       .ioctls             = etnaviv_ioctls,
> +       .num_ioctls         = DRM_ETNAVIV_NUM_IOCTLS,
> +       .fops               = &fops,
> +       .name               = "etnaviv",
> +       .desc               = "etnaviv DRM",
> +       .date               = "20150910",
> +       .major              = 1,
> +       .minor              = 0,
> +};
> +
> +/*
> + * Platform driver:
> + */
> +static int etnaviv_bind(struct device *dev)
> +{
> +       return drm_platform_init(&etnaviv_drm_driver, to_platform_device(dev));
> +}
> +
> +static void etnaviv_unbind(struct device *dev)
> +{
> +       drm_put_dev(dev_get_drvdata(dev));
> +}
> +
> +static const struct component_master_ops etnaviv_master_ops = {
> +       .bind = etnaviv_bind,
> +       .unbind = etnaviv_unbind,
> +};
> +
> +static int compare_of(struct device *dev, void *data)
> +{
> +       struct device_node *np = data;
> +
> +       return dev->of_node == np;
> +}
> +
> +static int compare_str(struct device *dev, void *data)
> +{
> +       return !strcmp(dev_name(dev), data);
> +}
> +
> +static int etnaviv_pdev_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct device_node *node = dev->of_node;
> +       struct component_match *match = NULL;
> +
> +       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
> +
> +       if (node) {
> +               struct device_node *core_node;
> +               int i;
> +
> +               for (i = 0; ; i++) {
> +                       core_node = of_parse_phandle(node, "cores", i);
> +                       if (!core_node)
> +                               break;
> +
> +                       component_match_add(&pdev->dev, &match, compare_of,
> +                                           core_node);
> +                       of_node_put(core_node);
> +               }
> +       } else if (dev->platform_data) {
> +               char **names = dev->platform_data;
> +               unsigned i;
> +
> +               for (i = 0; names[i]; i++)
> +                       component_match_add(dev, &match, compare_str, names[i]);
> +       }
> +
> +       return component_master_add_with_match(dev, &etnaviv_master_ops, match);
> +}
> +
> +static int etnaviv_pdev_remove(struct platform_device *pdev)
> +{
> +       component_master_del(&pdev->dev, &etnaviv_master_ops);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id dt_match[] = {
> +       { .compatible = "fsl,imx-gpu-subsystem" },
> +       { .compatible = "marvell,dove-gpu-subsystem" },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, dt_match);
> +
> +static struct platform_driver etnaviv_platform_driver = {
> +       .probe      = etnaviv_pdev_probe,
> +       .remove     = etnaviv_pdev_remove,
> +       .driver     = {
> +               .owner  = THIS_MODULE,
> +               .name   = "etnaviv",
> +               .of_match_table = dt_match,
> +       },
> +};
> +
> +static int __init etnaviv_init(void)
> +{
> +       int ret;
> +
> +       ret = platform_driver_register(&etnaviv_gpu_driver);
> +       if (ret != 0)
> +               return ret;
> +
> +       ret = platform_driver_register(&etnaviv_platform_driver);
> +       if (ret != 0)
> +               platform_driver_unregister(&etnaviv_gpu_driver);
> +
> +       return ret;
> +}
> +module_init(etnaviv_init);
> +
> +static void __exit etnaviv_exit(void)
> +{
> +       platform_driver_unregister(&etnaviv_gpu_driver);
> +       platform_driver_unregister(&etnaviv_platform_driver);
> +}
> +module_exit(etnaviv_exit);
> +
> +MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
> +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
> +MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>");
> +MODULE_DESCRIPTION("etnaviv DRM Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:etnaviv");
> diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
> new file mode 100644
> index 000000000000..719e33174e83
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_drv.h
> @@ -0,0 +1,138 @@
> +/*
> + * 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_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];
> +
> +       u32 next_fence;
> +
> +       /* list of GEM objects: */
> +       struct list_head inactive_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_locked(struct etnaviv_gpu *gpu,
> +       struct drm_gem_object *obj, u32 *iova);
> +int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
> +       int id, u32 *iova);
> +void etnaviv_gem_put_iova(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_locked(struct drm_gem_object *obj);
> +void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
> +dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj);
> +void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
> +               struct etnaviv_gpu *gpu, u32 access, u32 fence);
> +void etnaviv_gem_move_to_inactive(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_gem_submit *submit);
> +bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
> +       void *stream, unsigned int size);
> +
> +#ifdef CONFIG_DEBUG_FS
> +void etnaviv_gem_describe_objects(struct list_head *list, 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__)
> +
> +/* 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;
> +}
> +
> +#endif /* __ETNAVIV_DRV_H__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
> new file mode 100644
> index 000000000000..1381c952c52f
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem.c
> @@ -0,0 +1,887 @@
> +/*
> + * 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/spinlock.h>
> +#include <linux/shmem_fs.h>
> +
> +#include "etnaviv_drv.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_gpu.h"
> +#include "etnaviv_mmu.h"
> +
> +static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct sg_table *sgt = etnaviv_obj->sgt;
> +
> +       /*
> +        * For non-cached buffers, ensure the new pages are clean
> +        * because display controller, GPU, etc. are not coherent.
> +        */
> +       if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
> +               dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
> +}
> +
> +static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct sg_table *sgt = etnaviv_obj->sgt;
> +
> +       /*
> +        * For non-cached buffers, ensure the new pages are clean
> +        * because display controller, GPU, etc. are not coherent:
> +        *
> +        * WARNING: The DMA API does not support concurrent CPU
> +        * and device access to the memory area.  With BIDIRECTIONAL,
> +        * we will clean the cache lines which overlap the region,
> +        * and invalidate all cache lines (partially) contained in
> +        * the region.
> +        *
> +        * If you have dirty data in the overlapping cache lines,
> +        * that will corrupt the GPU-written data.  If you have
> +        * written into the remainder of the region, this can
> +        * discard those writes.
> +        */
> +       if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
> +               dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
> +}
> +
> +/* called with dev->struct_mutex held */
> +static int etnaviv_gem_shmem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct page **p = drm_gem_get_pages(&etnaviv_obj->base);
> +
> +       if (IS_ERR(p)) {
> +               dev_err(dev->dev, "could not get pages: %ld\n", PTR_ERR(p));
> +               return PTR_ERR(p);
> +       }
> +
> +       etnaviv_obj->pages = p;
> +
> +       return 0;
> +}
> +
> +static void put_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       if (etnaviv_obj->sgt) {
> +               etnaviv_gem_scatterlist_unmap(etnaviv_obj);
> +               sg_free_table(etnaviv_obj->sgt);
> +               kfree(etnaviv_obj->sgt);
> +               etnaviv_obj->sgt = NULL;
> +       }
> +       if (etnaviv_obj->pages) {
> +               drm_gem_put_pages(&etnaviv_obj->base, etnaviv_obj->pages,
> +                                 true, false);
> +
> +               etnaviv_obj->pages = NULL;
> +       }
> +}
> +
> +struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       int ret;
> +
> +       if (!etnaviv_obj->pages) {
> +               ret = etnaviv_obj->ops->get_pages(etnaviv_obj);
> +               if (ret < 0)
> +                       return ERR_PTR(ret);
> +       }
> +
> +       if (!etnaviv_obj->sgt) {
> +               struct drm_device *dev = etnaviv_obj->base.dev;
> +               int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +               struct sg_table *sgt;
> +
> +               sgt = drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
> +               if (IS_ERR(sgt)) {
> +                       dev_err(dev->dev, "failed to allocate sgt: %ld\n",
> +                               PTR_ERR(sgt));
> +                       return ERR_CAST(sgt);
> +               }
> +
> +               etnaviv_obj->sgt = sgt;
> +
> +               etnaviv_gem_scatter_map(etnaviv_obj);
> +       }
> +
> +       return etnaviv_obj->pages;
> +}
> +
> +void etnaviv_gem_put_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       /* when we start tracking the pin count, then do something here */
> +}
> +
> +static int etnaviv_gem_mmap_obj(struct drm_gem_object *obj,
> +               struct vm_area_struct *vma)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       pgprot_t vm_page_prot;
> +
> +       vma->vm_flags &= ~VM_PFNMAP;
> +       vma->vm_flags |= VM_MIXEDMAP;
> +
> +       vm_page_prot = vm_get_page_prot(vma->vm_flags);
> +
> +       if (etnaviv_obj->flags & ETNA_BO_WC) {
> +               vma->vm_page_prot = pgprot_writecombine(vm_page_prot);
> +       } else if (etnaviv_obj->flags & ETNA_BO_UNCACHED) {
> +               vma->vm_page_prot = pgprot_noncached(vm_page_prot);
> +       } else {
> +               /*
> +                * Shunt off cached objs to shmem file so they have their own
> +                * address_space (so unmap_mapping_range does what we want,
> +                * in particular in the case of mmap'd dmabufs)
> +                */
> +               fput(vma->vm_file);
> +               get_file(obj->filp);
> +               vma->vm_pgoff = 0;
> +               vma->vm_file  = obj->filp;
> +
> +               vma->vm_page_prot = vm_page_prot;
> +       }
> +
> +       return 0;
> +}
> +
> +int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       struct etnaviv_gem_object *obj;
> +       int ret;
> +
> +       ret = drm_gem_mmap(filp, vma);
> +       if (ret) {
> +               DBG("mmap failed: %d", ret);
> +               return ret;
> +       }
> +
> +       obj = to_etnaviv_bo(vma->vm_private_data);
> +       return etnaviv_gem_mmap_obj(vma->vm_private_data, vma);
> +}
> +
> +int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> +{
> +       struct drm_gem_object *obj = vma->vm_private_data;
> +       struct drm_device *dev = obj->dev;
> +       struct page **pages, *page;
> +       pgoff_t pgoff;
> +       int ret;
> +
> +       /*
> +        * Make sure we don't parallel update on a fault, nor move or remove
> +        * something from beneath our feet.  Note that vm_insert_page() is
> +        * specifically coded to take care of this, so we don't have to.
> +        */
> +       ret = mutex_lock_interruptible(&dev->struct_mutex);
> +       if (ret)
> +               goto out;
> +
> +       /* make sure we have pages attached now */
> +       pages = etnaviv_gem_get_pages(to_etnaviv_bo(obj));
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       if (IS_ERR(pages)) {
> +               ret = PTR_ERR(pages);
> +               goto out;
> +       }
> +
> +       /* We don't use vmf->pgoff since that has the fake offset: */
> +       pgoff = ((unsigned long)vmf->virtual_address -
> +                       vma->vm_start) >> PAGE_SHIFT;
> +
> +       page = pages[pgoff];
> +
> +       VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
> +            page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT);
> +
> +       ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
> +
> +out:
> +       switch (ret) {
> +       case -EAGAIN:
> +       case 0:
> +       case -ERESTARTSYS:
> +       case -EINTR:
> +       case -EBUSY:
> +               /*
> +                * EBUSY is ok: this just means that another thread
> +                * already did the job.
> +                */
> +               return VM_FAULT_NOPAGE;
> +       case -ENOMEM:
> +               return VM_FAULT_OOM;
> +       default:
> +               return VM_FAULT_SIGBUS;
> +       }
> +}
> +
> +/* get mmap offset - must be called under struct_mutex */
> +int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset)
> +{
> +       int ret;
> +
> +       /* Make it mmapable */
> +       ret = drm_gem_create_mmap_offset(obj);
> +       if (ret)
> +               dev_err(obj->dev->dev, "could not allocate mmap offset\n");
> +       else
> +               *offset = drm_vma_node_offset_addr(&obj->vma_node);
> +
> +       return ret;
> +}
> +
> +/* should be called under struct_mutex.. although it can be called
> + * from atomic context without struct_mutex to acquire an extra
> + * iova ref if you know one is already held.
> + *
> + * That means when I do eventually need to add support for unpinning
> + * the refcnt counter needs to be atomic_t.
> + */
> +int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
> +       struct drm_gem_object *obj, u32 *iova)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct etnaviv_vram_mapping *mapping;
> +       int ret = 0;
> +
> +       mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
> +       if (!mapping) {
> +               struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
> +               if (IS_ERR(pages))
> +                       return PTR_ERR(pages);
> +               ret = etnaviv_iommu_map_gem(gpu->mmu, etnaviv_obj,
> +                               gpu->memory_base, &mapping);
> +       }
> +
> +       if (!ret)
> +               *iova = mapping->iova;
> +
> +       return ret;
> +}
> +
> +int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
> +       int id, u32 *iova)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct etnaviv_vram_mapping *mapping =
> +                       etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
> +       int ret;
> +
> +       /* this is safe right now because we don't unmap until the
> +        * bo is deleted:
> +        */
> +       if (mapping) {
> +               *iova = mapping->iova;
> +               return 0;
> +       }
> +
> +       mutex_lock(&obj->dev->struct_mutex);
> +       ret = etnaviv_gem_get_iova_locked(gpu, obj, iova);
> +       mutex_unlock(&obj->dev->struct_mutex);
> +
> +       return ret;
> +}
> +
> +void etnaviv_gem_put_iova(struct drm_gem_object *obj)
> +{
> +       /*
> +        * XXX TODO ..
> +        * NOTE: probably don't need a _locked() version.. we wouldn't
> +        * normally unmap here, but instead just mark that it could be
> +        * unmapped (if the iova refcnt drops to zero), but then later
> +        * if another _get_iova_locked() fails we can start unmapping
> +        * things that are no longer needed..
> +        */
> +}
> +
> +void *etnaviv_gem_vaddr_locked(struct drm_gem_object *obj)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
> +
> +       if (!etnaviv_obj->vaddr) {
> +               struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
> +
> +               if (IS_ERR(pages))
> +                       return ERR_CAST(pages);
> +
> +               etnaviv_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
> +                               VM_MAP, pgprot_writecombine(PAGE_KERNEL));
> +       }
> +
> +       return etnaviv_obj->vaddr;
> +}
> +
> +void *etnaviv_gem_vaddr(struct drm_gem_object *obj)
> +{
> +       void *ret;
> +
> +       mutex_lock(&obj->dev->struct_mutex);
> +       ret = etnaviv_gem_vaddr_locked(obj);
> +       mutex_unlock(&obj->dev->struct_mutex);
> +
> +       return ret;
> +}
> +
> +dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
> +
> +       return etnaviv_obj->paddr;
> +}
> +
> +void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
> +       struct etnaviv_gpu *gpu, u32 access, u32 fence)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       etnaviv_obj->gpu = gpu;
> +
> +       if (access & ETNA_SUBMIT_BO_READ)
> +               etnaviv_obj->read_fence = fence;
> +       if (access & ETNA_SUBMIT_BO_WRITE)
> +               etnaviv_obj->write_fence = fence;
> +
> +       etnaviv_obj->access |= access;
> +
> +       list_del_init(&etnaviv_obj->mm_list);
> +       list_add_tail(&etnaviv_obj->mm_list, &gpu->active_list);
> +}
> +
> +void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> +       etnaviv_obj->gpu = NULL;
> +       etnaviv_obj->read_fence = 0;
> +       etnaviv_obj->write_fence = 0;
> +       etnaviv_obj->access = 0;
> +       list_del_init(&etnaviv_obj->mm_list);
> +       list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
> +}
> +
> +static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
> +{
> +       if (op & ETNA_PREP_READ)
> +               return DMA_FROM_DEVICE;
> +       else if (op & ETNA_PREP_WRITE)
> +               return DMA_TO_DEVICE;
> +       else
> +               return DMA_BIDIRECTIONAL;
> +}
> +
> +int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
> +               struct timespec *timeout)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct drm_device *dev = obj->dev;
> +       int ret = 0;
> +
> +       if (is_active(etnaviv_obj)) {
> +               struct etnaviv_gpu *gpu = etnaviv_obj->gpu;
> +               u32 fence = 0;
> +
> +               if (op & ETNA_PREP_READ)
> +                       fence = etnaviv_obj->write_fence;
> +               if (op & ETNA_PREP_WRITE)
> +                       fence = max(fence, etnaviv_obj->read_fence);
> +               if (op & ETNA_PREP_NOSYNC)
> +                       timeout = NULL;
> +
> +               ret = etnaviv_gpu_wait_fence_interruptible(gpu, fence, timeout);
> +       }
> +
> +       if (etnaviv_obj->flags & ETNA_BO_CACHED) {
> +               if (!etnaviv_obj->sgt) {
> +                       void * ret;
> +
> +                       mutex_lock(&dev->struct_mutex);
> +                       ret = etnaviv_gem_get_pages(etnaviv_obj);
> +                       mutex_unlock(&dev->struct_mutex);
> +                       if (IS_ERR(ret))
> +                               return PTR_ERR(ret);
> +               }
> +
> +               dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
> +                                   etnaviv_obj->sgt->nents,
> +                                   etnaviv_op_to_dma_dir(op));
> +               etnaviv_obj->last_cpu_prep_op = op;
> +       }
> +
> +       return ret;
> +}
> +
> +int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       if (etnaviv_obj->flags & ETNA_BO_CACHED) {
> +               /* fini without a prep is almost certainly a userspace error */
> +               WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
> +               dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
> +                       etnaviv_obj->sgt->nents,
> +                       etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
> +               etnaviv_obj->last_cpu_prep_op = 0;
> +       }
> +
> +       return 0;
> +}
> +
> +int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
> +       struct timespec *timeout)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +
> +       return etnaviv_gpu_wait_obj_inactive(gpu, etnaviv_obj, timeout);
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       unsigned long off = drm_vma_node_start(&obj->vma_node);
> +
> +       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> +       seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08lx %p %zd\n",
> +                       etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
> +                       etnaviv_obj->read_fence, etnaviv_obj->write_fence,
> +                       obj->name, obj->refcount.refcount.counter,
> +                       off, etnaviv_obj->vaddr, obj->size);
> +}
> +
> +void etnaviv_gem_describe_objects(struct list_head *list, struct seq_file *m)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj;
> +       int count = 0;
> +       size_t size = 0;
> +
> +       list_for_each_entry(etnaviv_obj, list, mm_list) {
> +               struct drm_gem_object *obj = &etnaviv_obj->base;
> +
> +               seq_puts(m, "   ");
> +               etnaviv_gem_describe(obj, m);
> +               count++;
> +               size += obj->size;
> +       }
> +
> +       seq_printf(m, "Total %d objects, %zu bytes\n", count, size);
> +}
> +#endif
> +
> +static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       if (etnaviv_obj->vaddr)
> +               vunmap(etnaviv_obj->vaddr);
> +       put_pages(etnaviv_obj);
> +}
> +
> +static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {
> +       .get_pages = etnaviv_gem_shmem_get_pages,
> +       .release = etnaviv_gem_shmem_release,
> +};
> +
> +void etnaviv_gem_free_object(struct drm_gem_object *obj)
> +{
> +       struct drm_device *dev = obj->dev;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       struct etnaviv_vram_mapping *mapping, *tmp;
> +
> +       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> +       /* object should not be on active list: */
> +       WARN_ON(is_active(etnaviv_obj));
> +
> +       list_del(&etnaviv_obj->mm_list);
> +
> +       list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
> +                                obj_node)
> +               etnaviv_iommu_unmap_gem(mapping);
> +
> +       drm_gem_free_mmap_offset(obj);
> +       etnaviv_obj->ops->release(etnaviv_obj);
> +       reservation_object_fini(&etnaviv_obj->_resv);
> +       drm_gem_object_release(obj);
> +
> +       kfree(etnaviv_obj);
> +}
> +
> +int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
> +{
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
> +       int ret;
> +
> +       ret = mutex_lock_killable(&dev->struct_mutex);
> +       if (ret)
> +               return ret;
> +
> +       list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       return 0;
> +}
> +
> +static int etnaviv_gem_new_impl(struct drm_device *dev,
> +               u32 size, u32 flags,
> +               struct drm_gem_object **obj)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj;
> +       unsigned sz = sizeof(*etnaviv_obj);
> +       bool valid = true;
> +
> +       /* validate flags */
> +       switch (flags & ETNA_BO_CACHE_MASK) {
> +       case ETNA_BO_UNCACHED:
> +       case ETNA_BO_CACHED:
> +       case ETNA_BO_WC:
> +               break;
> +       default:
> +               valid = false;
> +       }
> +
> +       if (!valid) {
> +               dev_err(dev->dev, "invalid cache flag: %x\n",
> +                       (flags & ETNA_BO_CACHE_MASK));
> +               return -EINVAL;
> +       }
> +
> +       etnaviv_obj = kzalloc(sz, GFP_KERNEL);
> +       if (!etnaviv_obj)
> +               return -ENOMEM;
> +
> +       etnaviv_obj->flags = flags;
> +
> +       etnaviv_obj->resv = &etnaviv_obj->_resv;
> +       reservation_object_init(&etnaviv_obj->_resv);
> +
> +       INIT_LIST_HEAD(&etnaviv_obj->submit_entry);
> +       INIT_LIST_HEAD(&etnaviv_obj->mm_list);
> +       INIT_LIST_HEAD(&etnaviv_obj->vram_list);
> +
> +       *obj = &etnaviv_obj->base;
> +
> +       return 0;
> +}
> +
> +static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
> +               u32 size, u32 flags)
> +{
> +       struct drm_gem_object *obj = NULL;
> +       int ret;
> +
> +       size = PAGE_ALIGN(size);
> +
> +       ret = etnaviv_gem_new_impl(dev, size, flags, &obj);
> +       if (ret)
> +               goto fail;
> +
> +       to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops;
> +       ret = drm_gem_object_init(dev, obj, size);
> +       if (ret == 0) {
> +               struct address_space *mapping;
> +
> +               /*
> +                * Our buffers are kept pinned, so allocating them
> +                * from the MOVABLE zone is a really bad idea, and
> +                * conflicts with CMA.  See coments above new_inode()
> +                * why this is required _and_ expected if you're
> +                * going to pin these pages.
> +                */
> +               mapping = file_inode(obj->filp)->i_mapping;
> +               mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
> +       }
> +
> +       if (ret)
> +               goto fail;
> +
> +       return obj;
> +
> +fail:
> +       if (obj)
> +               drm_gem_object_unreference_unlocked(obj);
> +
> +       return ERR_PTR(ret);
> +}
> +
> +/* convenience method to construct a GEM buffer object, and userspace handle */
> +int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
> +               u32 size, u32 flags, u32 *handle)
> +{
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = __etnaviv_gem_new(dev, size, flags);
> +       if (IS_ERR(obj))
> +               return PTR_ERR(obj);
> +
> +       ret = etnaviv_gem_obj_add(dev, obj);
> +       if (ret < 0) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return ret;
> +       }
> +
> +       ret = drm_gem_handle_create(file, obj, handle);
> +
> +       /* drop reference from allocate - handle holds it now */
> +       drm_gem_object_unreference_unlocked(obj);
> +
> +       return ret;
> +}
> +
> +struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
> +               u32 size, u32 flags)
> +{
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       obj = __etnaviv_gem_new(dev, size, flags);
> +       if (IS_ERR(obj))
> +               return obj;
> +
> +       ret = etnaviv_gem_obj_add(dev, obj);
> +       if (ret < 0) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return obj;
> +}
> +
> +int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
> +       struct etnaviv_gem_object **res)
> +{
> +       struct drm_gem_object *obj;
> +       int ret;
> +
> +       ret = etnaviv_gem_new_impl(dev, size, flags, &obj);
> +       if (ret)
> +               return ret;
> +
> +       drm_gem_private_object_init(dev, obj, size);
> +
> +       *res = to_etnaviv_bo(obj);
> +
> +       return 0;
> +}
> +
> +struct etnaviv_vram_mapping *
> +etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
> +                            struct etnaviv_iommu *mmu)
> +{
> +       struct etnaviv_vram_mapping *mapping;
> +
> +       list_for_each_entry(mapping, &obj->vram_list, obj_node) {
> +               if (mapping->mmu == mmu)
> +                       return mapping;
> +       }
> +
> +       return NULL;
> +}
> +
> +struct get_pages_work {
> +       struct work_struct work;
> +       struct mm_struct *mm;
> +       struct task_struct *task;
> +       struct etnaviv_gem_object *etnaviv_obj;
> +};
> +
> +static struct page **etnaviv_gem_userptr_do_get_pages(
> +       struct etnaviv_gem_object *etnaviv_obj, struct mm_struct *mm, struct task_struct *task)
> +{
> +       int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +       struct page **pvec;
> +       uintptr_t ptr;
> +
> +       pvec = drm_malloc_ab(npages, sizeof(struct page *));
> +       if (!pvec)
> +               return ERR_PTR(-ENOMEM);
> +
> +       pinned = 0;
> +       ptr = etnaviv_obj->userptr.ptr;
> +
> +       down_read(&mm->mmap_sem);
> +       while (pinned < npages) {
> +               ret = get_user_pages(task, mm, ptr, npages - pinned,
> +                                    !etnaviv_obj->userptr.ro, 0,
> +                                    pvec + pinned, NULL);
> +               if (ret < 0)
> +                       break;
> +
> +               ptr += ret * PAGE_SIZE;
> +               pinned += ret;
> +       }
> +       up_read(&mm->mmap_sem);
> +
> +       if (ret < 0) {
> +               release_pages(pvec, pinned, 0);
> +               drm_free_large(pvec);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return pvec;
> +}
> +
> +static void __etnaviv_gem_userptr_get_pages(struct work_struct *_work)
> +{
> +       struct get_pages_work *work = container_of(_work, typeof(*work), work);
> +       struct etnaviv_gem_object *etnaviv_obj = work->etnaviv_obj;
> +       struct drm_device *dev = etnaviv_obj->base.dev;
> +       struct page **pvec;
> +
> +       pvec = etnaviv_gem_userptr_do_get_pages(etnaviv_obj, work->mm, work->task);
> +
> +       mutex_lock(&dev->struct_mutex);
> +       if (IS_ERR(pvec)) {
> +               etnaviv_obj->userptr.work = ERR_CAST(pvec);
> +       } else {
> +               etnaviv_obj->userptr.work = NULL;
> +               etnaviv_obj->pages = pvec;
> +       }
> +
> +       drm_gem_object_unreference(&etnaviv_obj->base);
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       mmput(work->mm);
> +       put_task_struct(work->task);
> +       kfree(work);
> +}
> +
> +static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       struct page **pvec = NULL;
> +       struct get_pages_work *work;
> +       struct mm_struct *mm;
> +       int ret, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +
> +       if (etnaviv_obj->userptr.work) {
> +               if (IS_ERR(etnaviv_obj->userptr.work)) {
> +                       ret = PTR_ERR(etnaviv_obj->userptr.work);
> +                       etnaviv_obj->userptr.work = NULL;
> +               } else {
> +                       ret = -EAGAIN;
> +               }
> +               return ret;
> +       }
> +
> +       mm = get_task_mm(etnaviv_obj->userptr.task);
> +       pinned = 0;
> +       if (mm == current->mm) {
> +               pvec = drm_malloc_ab(npages, sizeof(struct page *));
> +               if (!pvec) {
> +                       mmput(mm);
> +                       return -ENOMEM;
> +               }
> +
> +               pinned = __get_user_pages_fast(etnaviv_obj->userptr.ptr, npages,
> +                                              !etnaviv_obj->userptr.ro, pvec);
> +               if (pinned < 0) {
> +                       drm_free_large(pvec);
> +                       mmput(mm);
> +                       return pinned;
> +               }
> +
> +               if (pinned == npages) {
> +                       etnaviv_obj->pages = pvec;
> +                       mmput(mm);
> +                       return 0;
> +               }
> +       }
> +
> +       release_pages(pvec, pinned, 0);
> +       drm_free_large(pvec);
> +
> +       work = kmalloc(sizeof(*work), GFP_KERNEL);
> +       if (!work) {
> +               mmput(mm);
> +               return -ENOMEM;
> +       }
> +
> +       get_task_struct(current);
> +       drm_gem_object_reference(&etnaviv_obj->base);
> +
> +       work->mm = mm;
> +       work->task = current;
> +       work->etnaviv_obj = etnaviv_obj;
> +
> +       etnaviv_obj->userptr.work = &work->work;
> +       INIT_WORK(&work->work, __etnaviv_gem_userptr_get_pages);
> +
> +       etnaviv_queue_work(etnaviv_obj->base.dev, &work->work);
> +
> +       return -EAGAIN;
> +}
> +
> +static void etnaviv_gem_userptr_release(struct etnaviv_gem_object *etnaviv_obj)
> +{
> +       if (etnaviv_obj->sgt) {
> +               etnaviv_gem_scatterlist_unmap(etnaviv_obj);
> +               sg_free_table(etnaviv_obj->sgt);
> +               kfree(etnaviv_obj->sgt);
> +       }
> +       if (etnaviv_obj->pages) {
> +               int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> +
> +               release_pages(etnaviv_obj->pages, npages, 0);
> +               drm_free_large(etnaviv_obj->pages);
> +       }
> +       put_task_struct(etnaviv_obj->userptr.task);
> +}
> +
> +static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops = {
> +       .get_pages = etnaviv_gem_userptr_get_pages,
> +       .release = etnaviv_gem_userptr_release,
> +};
> +
> +int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
> +       uintptr_t ptr, u32 size, u32 flags, u32 *handle)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj;
> +       int ret;
> +
> +       ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, &etnaviv_obj);
> +       if (ret)
> +               return ret;
> +
> +       etnaviv_obj->ops = &etnaviv_gem_userptr_ops;
> +       etnaviv_obj->userptr.ptr = ptr;
> +       etnaviv_obj->userptr.task = current;
> +       etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);
> +       get_task_struct(current);
> +
> +       ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
> +       if (ret) {
> +               drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
> +               return ret;
> +       }
> +
> +       ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);
> +
> +       /* drop reference from allocate - handle holds it now */
> +       drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
> +
> +       return ret;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
> new file mode 100644
> index 000000000000..c991d12e7aed
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem.h
> @@ -0,0 +1,141 @@
> +/*
> + * 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 etnaviv_gem_object *object;
> +       struct etnaviv_iommu *mmu;
> +       struct drm_mm_node vram_node;
> +       u32 iova;
> +};
> +
> +struct etnaviv_gem_object {
> +       struct drm_gem_object base;
> +       const struct etnaviv_gem_ops *ops;
> +
> +       u32 flags;
> +
> +       /* And object is either:
> +        *  inactive - on priv->inactive_list
> +        *  active   - on one one of the gpu's active_list..  well, at
> +        *     least for now we don't have (I don't think) hw sync between
> +        *     2d and 3d one devices which have both, meaning we need to
> +        *     block on submit if a bo is already on other ring
> +        *
> +        */
> +       struct list_head mm_list;
> +       struct etnaviv_gpu *gpu;     /* non-null if active */
> +       u32 access;
> +       u32 read_fence, write_fence;
> +
> +       /* Transiently in the process of submit ioctl, objects associated
> +        * with the submit are on submit->bo_list.. this only lasts for
> +        * the duration of the ioctl, so one bo can never be on multiple
> +        * submit lists.
> +        */
> +       struct list_head submit_entry;
> +
> +       struct page **pages;
> +       struct sg_table *sgt;
> +       void *vaddr;
> +
> +       /* for ETNA_BO_CMDSTREAM */
> +       dma_addr_t paddr;
> +
> +       /* normally (resv == &_resv) except for imported bo's */
> +       struct reservation_object *resv;
> +       struct reservation_object _resv;
> +
> +       struct list_head vram_list;
> +
> +       /* for buffer manipulation during submit */
> +       bool is_ring_buffer;
> +       u32 offset;
> +
> +       /* cache maintenance */
> +       uint32_t 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 etnaviv_obj->gpu != NULL;
> +}
> +
> +#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;
> +       u32 exec_state;
> +       struct list_head bo_list;
> +       struct ww_acquire_ctx ticket;
> +       u32 fence;
> +       unsigned int nr_bos;
> +       struct etnaviv_cmdbuf *cmdbuf;
> +       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);
> +struct etnaviv_vram_mapping *
> +etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
> +                            struct etnaviv_iommu *mmu);
> +int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
> +       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__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_gem_prime.c b/drivers/staging/etnaviv/etnaviv_gem_prime.c
> new file mode 100644
> index 000000000000..58c13ae7c345
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem_prime.c
> @@ -0,0 +1,121 @@
> +/*
> + * 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 drm_device *dev = obj->dev;
> +
> +               mutex_lock(&dev->struct_mutex);
> +               etnaviv_gem_get_pages(to_etnaviv_bo(obj));
> +               mutex_unlock(&dev->struct_mutex);
> +       }
> +       return 0;
> +}
> +
> +void etnaviv_gem_prime_unpin(struct drm_gem_object *obj)
> +{
> +       if (!obj->import_attach) {
> +               struct drm_device *dev = obj->dev;
> +
> +               mutex_lock(&dev->struct_mutex);
> +               etnaviv_gem_put_pages(to_etnaviv_bo(obj));
> +               mutex_unlock(&dev->struct_mutex);
> +       }
> +}
> +
> +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, &etnaviv_obj);
> +       if (ret < 0)
> +               return ERR_PTR(ret);
> +
> +       npages = size / PAGE_SIZE;
> +
> +       etnaviv_obj->ops = &etnaviv_gem_prime_ops;
> +       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);
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
> new file mode 100644
> index 000000000000..f886a3c66d30
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
> @@ -0,0 +1,421 @@
> +/*
> + * 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 "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, int nr)
> +{
> +       struct etnaviv_gem_submit *submit;
> +       int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0]));
> +
> +       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;
> +               submit->cmdbuf = NULL;
> +
> +               INIT_LIST_HEAD(&submit->bo_list);
> +               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;
> +               struct etnaviv_gem_object *etnaviv_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;
> +               }
> +
> +               etnaviv_obj = to_etnaviv_bo(obj);
> +
> +               if (!list_empty(&etnaviv_obj->submit_entry)) {
> +                       DRM_ERROR("handle %u at index %u already on submit list\n",
> +                                 bo->handle, i);
> +                       ret = -EINVAL;
> +                       goto out_unlock;
> +               }
> +
> +               drm_gem_object_reference(obj);
> +
> +               submit->bos[i].obj = etnaviv_obj;
> +
> +               list_add_tail(&etnaviv_obj->submit_entry, &submit->bo_list);
> +       }
> +
> +out_unlock:
> +       submit->nr_bos = i;
> +       spin_unlock(&file->table_lock);
> +
> +       return ret;
> +}
> +
> +static void submit_unlock_unpin_bo(struct etnaviv_gem_submit *submit, int i)
> +{
> +       struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
> +
> +       if (submit->bos[i].flags & BO_PINNED)
> +               etnaviv_gem_put_iova(&etnaviv_obj->base);
> +
> +       if (submit->bos[i].flags & BO_LOCKED)
> +               ww_mutex_unlock(&etnaviv_obj->resv->lock);
> +
> +       submit->bos[i].iova = 0;
> +       submit->bos[i].flags &= ~(BO_LOCKED | BO_PINNED);
> +}
> +
> +/* This is where we make sure all the bo's are reserved and pin'd: */
> +static int submit_validate_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;
> +               u32 iova;
> +
> +               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)
> +                               goto fail;
> +                       submit->bos[i].flags |= BO_LOCKED;
> +               }
> +
> +
> +               /* if locking succeeded, pin bo: */
> +               ret = etnaviv_gem_get_iova_locked(submit->gpu,
> +                                                 &etnaviv_obj->base, &iova);
> +
> +               /* this would break the logic in the fail path.. there is no
> +                * reason for this to happen, but just to be on the safe side
> +                * let's notice if this starts happening in the future:
> +                */
> +               WARN_ON(ret == -EDEADLK);
> +
> +               if (ret)
> +                       goto fail;
> +
> +               submit->bos[i].flags |= BO_PINNED;
> +               submit->bos[i].iova = iova;
> +       }
> +
> +       ww_acquire_done(&submit->ticket);
> +
> +       return 0;
> +
> +fail:
> +       for (; i >= 0; i--)
> +               submit_unlock_unpin_bo(submit, i);
> +
> +       if (slow_locked > 0)
> +               submit_unlock_unpin_bo(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_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, u32 nr_relocs, u64 relocs)
> +{
> +       u32 i, last_offset = 0;
> +       u32 *ptr = stream;
> +       int ret;
> +
> +       for (i = 0; i < nr_relocs; i++) {
> +               struct drm_etnaviv_gem_submit_reloc submit_reloc;
> +               struct etnaviv_gem_object *bobj;
> +               void __user *userptr =
> +                       to_user_ptr(relocs + (i * sizeof(submit_reloc)));
> +               u32 iova, off;
> +
> +               ret = copy_from_user(&submit_reloc, userptr,
> +                                    sizeof(submit_reloc));
> +               if (ret)
> +                       return -EFAULT;
> +
> +               if (submit_reloc.submit_offset % 4) {
> +                       DRM_ERROR("non-aligned reloc offset: %u\n",
> +                                       submit_reloc.submit_offset);
> +                       return -EINVAL;
> +               }
> +
> +               /* offset in dwords: */
> +               off = submit_reloc.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, submit_reloc.reloc_idx, &bobj, &iova);
> +               if (ret)
> +                       return ret;
> +
> +               if (submit_reloc.reloc_offset >=
> +                   bobj->base.size - sizeof(*ptr)) {
> +                       DRM_ERROR("relocation %u outside object", i);
> +                       return -EINVAL;
> +               }
> +
> +               ptr[off] = iova + submit_reloc.reloc_offset;
> +
> +               last_offset = off;
> +       }
> +
> +       return 0;
> +}
> +
> +static void submit_cleanup(struct etnaviv_gem_submit *submit, bool fail)
> +{
> +       unsigned i;
> +
> +       for (i = 0; i < submit->nr_bos; i++) {
> +               struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
> +
> +               submit_unlock_unpin_bo(submit, i);
> +               list_del_init(&etnaviv_obj->submit_entry);
> +               drm_gem_object_unreference(&etnaviv_obj->base);
> +       }
> +
> +       if (submit->cmdbuf)
> +               etnaviv_gpu_cmdbuf_free(submit->cmdbuf);
> +
> +       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 etnaviv_file_private *ctx = file->driver_priv;
> +       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;
> +       }
> +
> +       /*
> +        * Copy the command submission and bo array to kernel space in
> +        * one go, and do this outside of the dev->struct_mutex lock.
> +        */
> +       bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
> +       stream = drm_malloc_ab(1, args->stream_size);
> +       cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8);
> +       if (!bos || !stream || !cmdbuf) {
> +               ret = -ENOMEM;
> +               goto err_submit_cmds;
> +       }
> +
> +       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(stream, to_user_ptr(args->stream),
> +                            args->stream_size);
> +       if (ret) {
> +               ret = -EFAULT;
> +               goto err_submit_cmds;
> +       }
> +
> +       /*
> +        * Avoid big circular locking dependency loops:
> +        * - reading debugfs results in mmap_sem depending on i_mutex_key#3
> +        *   (iterate_dir -> filldir64)
> +        * - struct_mutex depends on mmap_sem
> +        *   (vm_mmap_pgoff -> drm_gem_mmap)
> +        * then if we try to do a get_sync() under struct_mutex,
> +        * - genpd->lock depends on struct_mutex
> +        *   (etnaviv_ioctl_gem_submit -> pm_genpd_runtime_resume)
> +        * - (regulator) rdev->mutex depends on genpd->lock
> +        *   (pm_genpd_poweron -> regulator_enable)
> +        * - i_mutex_key#3 depends on rdev->mutex
> +        *   (create_regulator -> debugfs::start_creating)
> +        * and lockdep rightfully explodes.
> +        *
> +        * Avoid this by getting runtime PM outside of the struct_mutex lock.
> +        */
> +       ret = etnaviv_gpu_pm_get_sync(gpu);
> +       if (ret < 0)
> +               goto err_submit_cmds;
> +
> +       mutex_lock(&dev->struct_mutex);
> +
> +       submit = submit_create(dev, gpu, args->nr_bos);
> +       if (!submit) {
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +       submit->exec_state = args->exec_state;
> +
> +       ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
> +       if (ret)
> +               goto out;
> +
> +       ret = submit_validate_objects(submit);
> +       if (ret)
> +               goto out;
> +
> +       if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4)) {
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = submit_reloc(submit, stream, args->stream_size / 4,
> +                          args->nr_relocs, args->relocs);
> +       if (ret)
> +               goto out;
> +
> +       memcpy(cmdbuf->vaddr, stream, args->stream_size);
> +       cmdbuf->user_size = ALIGN(args->stream_size, 8);
> +       /* transfer ownership of cmdbuf to submit */
> +       submit->cmdbuf = cmdbuf;
> +       cmdbuf = NULL;
> +
> +       ret = etnaviv_gpu_submit(gpu, submit, ctx);
> +
> +       args->fence = submit->fence;
> +
> +out:
> +       if (submit)
> +               submit_cleanup(submit, !!ret);
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       etnaviv_gpu_pm_put(gpu);
> +
> +       /*
> +        * If we're returning -EAGAIN, it could be due to the userptr code
> +        * wanting to run its workqueue outside of the struct_mutex.
> +        * Flush our workqueue to ensure that it is run in a timely manner.
> +        */
> +       if (ret == -EAGAIN)
> +               flush_workqueue(priv->wq);
> +
> +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);
> +
> +       return ret;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
> new file mode 100644
> index 000000000000..e12fe3508db2
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gpu.c
> @@ -0,0 +1,1468 @@
> +/*
> + * 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/component.h>
> +#include <linux/of_device.h>
> +#include "etnaviv_gpu.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_mmu.h"
> +#include "etnaviv_iommu.h"
> +#include "etnaviv_iommu_v2.h"
> +#include "common.xml.h"
> +#include "state.xml.h"
> +#include "state_hi.xml.h"
> +#include "cmdstream.xml.h"
> +
> +static const struct platform_device_id gpu_ids[] = {
> +       { .name = "etnaviv-gpu,2d" },
> +       { },
> +};
> +
> +/*
> + * Driver functions:
> + */
> +
> +int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
> +{
> +       switch (param) {
> +       case ETNAVIV_PARAM_GPU_MODEL:
> +               *value = gpu->identity.model;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_REVISION:
> +               *value = gpu->identity.revision;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_0:
> +               *value = gpu->identity.features;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_1:
> +               *value = gpu->identity.minor_features0;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_2:
> +               *value = gpu->identity.minor_features1;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_3:
> +               *value = gpu->identity.minor_features2;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_FEATURES_4:
> +               *value = gpu->identity.minor_features3;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_STREAM_COUNT:
> +               *value = gpu->identity.stream_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_REGISTER_MAX:
> +               *value = gpu->identity.register_max;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_THREAD_COUNT:
> +               *value = gpu->identity.thread_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE:
> +               *value = gpu->identity.vertex_cache_size;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT:
> +               *value = gpu->identity.shader_core_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_PIXEL_PIPES:
> +               *value = gpu->identity.pixel_pipes;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE:
> +               *value = gpu->identity.vertex_output_buffer_size;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_BUFFER_SIZE:
> +               *value = gpu->identity.buffer_size;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT:
> +               *value = gpu->identity.instruction_count;
> +               break;
> +
> +       case ETNAVIV_PARAM_GPU_NUM_CONSTANTS:
> +               *value = gpu->identity.num_constants;
> +               break;
> +
> +       default:
> +               DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void etnaviv_hw_specs(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->identity.minor_features0 &
> +           chipMinorFeatures0_MORE_MINOR_FEATURES) {
> +               u32 specs[2];
> +
> +               specs[0] = gpu_read(gpu, VIVS_HI_CHIP_SPECS);
> +               specs[1] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_2);
> +
> +               gpu->identity.stream_count =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT;
> +               gpu->identity.register_max =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT;
> +               gpu->identity.thread_count =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT;
> +               gpu->identity.vertex_cache_size =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT;
> +               gpu->identity.shader_core_count =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT;
> +               gpu->identity.pixel_pipes =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT;
> +               gpu->identity.vertex_output_buffer_size =
> +                       (specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT;
> +
> +               gpu->identity.buffer_size =
> +                       (specs[1] & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT;
> +               gpu->identity.instruction_count =
> +                       (specs[1] & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT;
> +               gpu->identity.num_constants =
> +                       (specs[1] & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
> +                               >> VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT;
> +
> +               gpu->identity.register_max = 1 << gpu->identity.register_max;
> +               gpu->identity.thread_count = 1 << gpu->identity.thread_count;
> +               gpu->identity.vertex_output_buffer_size =
> +                       1 << gpu->identity.vertex_output_buffer_size;
> +       } else {
> +               dev_err(gpu->dev, "TODO: determine GPU specs based on model\n");
> +       }
> +
> +       switch (gpu->identity.instruction_count) {
> +       case 0:
> +               if ((gpu->identity.model == 0x2000 &&
> +                    gpu->identity.revision == 0x5108) ||
> +                   gpu->identity.model == 0x880)
> +                       gpu->identity.instruction_count = 512;
> +               else
> +                       gpu->identity.instruction_count = 256;
> +               break;
> +
> +       case 1:
> +               gpu->identity.instruction_count = 1024;
> +               break;
> +
> +       case 2:
> +               gpu->identity.instruction_count = 2048;
> +               break;
> +
> +       default:
> +               gpu->identity.instruction_count = 256;
> +               break;
> +       }
> +}
> +
> +static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
> +{
> +       u32 chipIdentity;
> +
> +       chipIdentity = gpu_read(gpu, VIVS_HI_CHIP_IDENTITY);
> +
> +       /* Special case for older graphic cores. */
> +       if (VIVS_HI_CHIP_IDENTITY_FAMILY(chipIdentity) ==  0x01) {
> +               gpu->identity.model    = 0x500; /* gc500 */
> +               gpu->identity.revision = VIVS_HI_CHIP_IDENTITY_REVISION(chipIdentity);
> +       } else {
> +
> +               gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL);
> +               gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV);
> +
> +               /*
> +                * !!!! HACK ALERT !!!!
> +                * Because people change device IDs without letting software
> +                * know about it - here is the hack to make it all look the
> +                * same.  Only for GC400 family.
> +                */
> +               if ((gpu->identity.model & 0xff00) == 0x0400 &&
> +                   gpu->identity.model != 0x0420) {
> +                       gpu->identity.model = gpu->identity.model & 0x0400;
> +               }
> +
> +               /* Another special case */
> +               if (gpu->identity.model == 0x300 &&
> +                   gpu->identity.revision == 0x2201) {
> +                       u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE);
> +                       u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME);
> +
> +                       if (chipDate == 0x20080814 && chipTime == 0x12051100) {
> +                               /*
> +                                * This IP has an ECO; put the correct
> +                                * revision in it.
> +                                */
> +                               gpu->identity.revision = 0x1051;
> +                       }
> +               }
> +       }
> +
> +       dev_info(gpu->dev, "model: GC%x, revision: %x\n",
> +                gpu->identity.model, gpu->identity.revision);
> +
> +       gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE);
> +
> +       /* Disable fast clear on GC700. */
> +       if (gpu->identity.model == 0x700)
> +               gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
> +
> +       if ((gpu->identity.model == 0x500 && gpu->identity.revision < 2) ||
> +           (gpu->identity.model == 0x300 && gpu->identity.revision < 0x2000)) {
> +
> +               /*
> +                * GC500 rev 1.x and GC300 rev < 2.0 doesn't have these
> +                * registers.
> +                */
> +               gpu->identity.minor_features0 = 0;
> +               gpu->identity.minor_features1 = 0;
> +               gpu->identity.minor_features2 = 0;
> +               gpu->identity.minor_features3 = 0;
> +       } else
> +               gpu->identity.minor_features0 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_0);
> +
> +       if (gpu->identity.minor_features0 &
> +           chipMinorFeatures0_MORE_MINOR_FEATURES) {
> +               gpu->identity.minor_features1 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_1);
> +               gpu->identity.minor_features2 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_2);
> +               gpu->identity.minor_features3 =
> +                               gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3);
> +       }
> +
> +       /* GC600 idle register reports zero bits where modules aren't present */
> +       if (gpu->identity.model == chipModel_GC600) {
> +               gpu->idle_mask = VIVS_HI_IDLE_STATE_TX |
> +                                VIVS_HI_IDLE_STATE_RA |
> +                                VIVS_HI_IDLE_STATE_SE |
> +                                VIVS_HI_IDLE_STATE_PA |
> +                                VIVS_HI_IDLE_STATE_SH |
> +                                VIVS_HI_IDLE_STATE_PE |
> +                                VIVS_HI_IDLE_STATE_DE |
> +                                VIVS_HI_IDLE_STATE_FE;
> +       } else {
> +               gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP;
> +       }
> +
> +       etnaviv_hw_specs(gpu);
> +}
> +
> +static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock)
> +{
> +       gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock |
> +                 VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD);
> +       gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
> +}
> +
> +static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
> +{
> +       u32 control, idle;
> +       unsigned long timeout;
> +       bool failed = true;
> +
> +       /* TODO
> +        *
> +        * - clock gating
> +        * - puls eater
> +        * - what about VG?
> +        */
> +
> +       /* We hope that the GPU resets in under one second */
> +       timeout = jiffies + msecs_to_jiffies(1000);
> +
> +       while (time_is_after_jiffies(timeout)) {
> +               control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
> +                         VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
> +
> +               /* enable clock */
> +               etnaviv_gpu_load_clock(gpu, control);
> +
> +               /* Wait for stable clock.  Vivante's code waited for 1ms */
> +               usleep_range(1000, 10000);
> +
> +               /* isolate the GPU. */
> +               control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* set soft reset. */
> +               control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* wait for reset. */
> +               msleep(1);
> +
> +               /* reset soft reset bit. */
> +               control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* reset GPU isolation. */
> +               control &= ~VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
> +               gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
> +
> +               /* read idle register. */
> +               idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +
> +               /* try reseting again if FE it not idle */
> +               if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) {
> +                       dev_dbg(gpu->dev, "FE is not idle\n");
> +                       continue;
> +               }
> +
> +               /* read reset register. */
> +               control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
> +
> +               /* is the GPU idle? */
> +               if (((control & VIVS_HI_CLOCK_CONTROL_IDLE_3D) == 0) ||
> +                   ((control & VIVS_HI_CLOCK_CONTROL_IDLE_2D) == 0)) {
> +                       dev_dbg(gpu->dev, "GPU is not idle\n");
> +                       continue;
> +               }
> +
> +               failed = false;
> +               break;
> +       }
> +
> +       if (failed) {
> +               idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +               control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
> +
> +               dev_err(gpu->dev, "GPU failed to reset: FE %sidle, 3D %sidle, 2D %sidle\n",
> +                       idle & VIVS_HI_IDLE_STATE_FE ? "" : "not ",
> +                       control & VIVS_HI_CLOCK_CONTROL_IDLE_3D ? "" : "not ",
> +                       control & VIVS_HI_CLOCK_CONTROL_IDLE_2D ? "" : "not ");
> +
> +               return -EBUSY;
> +       }
> +
> +       /* We rely on the GPU running, so program the clock */
> +       control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
> +                 VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
> +
> +       /* enable clock */
> +       etnaviv_gpu_load_clock(gpu, control);
> +
> +       return 0;
> +}
> +
> +static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
> +{
> +       u16 prefetch;
> +
> +       if (gpu->identity.model == chipModel_GC320 &&
> +           gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400 &&
> +           (gpu->identity.revision == 0x5007 ||
> +            gpu->identity.revision == 0x5220)) {
> +               u32 mc_memory_debug;
> +
> +               mc_memory_debug = gpu_read(gpu, VIVS_MC_DEBUG_MEMORY) & ~0xff;
> +
> +               if (gpu->identity.revision == 0x5007)
> +                       mc_memory_debug |= 0x0c;
> +               else
> +                       mc_memory_debug |= 0x08;
> +
> +               gpu_write(gpu, VIVS_MC_DEBUG_MEMORY, mc_memory_debug);
> +       }
> +
> +       /*
> +        * Update GPU AXI cache atttribute to "cacheable, no allocate".
> +        * This is necessary to prevent the iMX6 SoC locking up.
> +        */
> +       gpu_write(gpu, VIVS_HI_AXI_CONFIG,
> +                 VIVS_HI_AXI_CONFIG_AWCACHE(2) |
> +                 VIVS_HI_AXI_CONFIG_ARCACHE(2));
> +
> +       /* GC2000 rev 5108 needs a special bus config */
> +       if (gpu->identity.model == 0x2000 && gpu->identity.revision == 0x5108) {
> +               u32 bus_config = gpu_read(gpu, VIVS_MC_BUS_CONFIG);
> +               bus_config &= ~(VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK |
> +                               VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK);
> +               bus_config |= VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(1) |
> +                             VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(0);
> +               gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config);
> +       }
> +
> +       /* set base addresses */
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
> +       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
> +
> +       /* setup the MMU page table pointers */
> +       etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain);
> +
> +       /* Start command processor */
> +       prefetch = etnaviv_buffer_init(gpu);
> +
> +       gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
> +       gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS,
> +                 gpu->buffer->paddr - gpu->memory_base);
> +       gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
> +                 VIVS_FE_COMMAND_CONTROL_ENABLE |
> +                 VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
> +}
> +
> +int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
> +{
> +       int ret, i;
> +       struct iommu_domain *iommu;
> +       enum etnaviv_iommu_version version;
> +       bool mmuv2;
> +
> +       ret = pm_runtime_get_sync(gpu->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       etnaviv_hw_identify(gpu);
> +
> +       if (gpu->identity.model == 0) {
> +               dev_err(gpu->dev, "Unknown GPU model\n");
> +               pm_runtime_put_autosuspend(gpu->dev);
> +               return -ENXIO;
> +       }
> +
> +       ret = etnaviv_hw_reset(gpu);
> +       if (ret)
> +               goto fail;
> +
> +       /* Setup IOMMU.. eventually we will (I think) do this once per context
> +        * and have separate page tables per context.  For now, to keep things
> +        * simple and to get something working, just use a single address space:
> +        */
> +       mmuv2 = gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION;
> +       dev_dbg(gpu->dev, "mmuv2: %d\n", mmuv2);
> +
> +       if (!mmuv2) {
> +               iommu = etnaviv_iommu_domain_alloc(gpu);
> +               version = ETNAVIV_IOMMU_V1;
> +       } else {
> +               iommu = etnaviv_iommu_v2_domain_alloc(gpu);
> +               version = ETNAVIV_IOMMU_V2;
> +       }
> +
> +       if (!iommu) {
> +               ret = -ENOMEM;
> +               goto fail;
> +       }
> +
> +       /* TODO: we will leak here memory - fix it! */
> +
> +       gpu->mmu = etnaviv_iommu_new(gpu->dev, iommu, version);
> +       if (!gpu->mmu) {
> +               ret = -ENOMEM;
> +               goto fail;
> +       }
> +
> +       /* Create buffer: */
> +       gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE);
> +       if (!gpu->buffer) {
> +               ret = -ENOMEM;
> +               dev_err(gpu->dev, "could not create command buffer\n");
> +               goto fail;
> +       }
> +
> +       /* Setup event management */
> +       spin_lock_init(&gpu->event_spinlock);
> +       init_completion(&gpu->event_free);
> +       for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
> +               gpu->event[i].used = false;
> +               complete(&gpu->event_free);
> +       }
> +
> +       /* Now program the hardware */
> +       mutex_lock(&gpu->drm->struct_mutex);
> +       etnaviv_gpu_hw_init(gpu);
> +       mutex_unlock(&gpu->drm->struct_mutex);
> +
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return 0;
> +
> +fail:
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return ret;
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct dma_debug {
> +       u32 address[2];
> +       u32 state[2];
> +};
> +
> +static void verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug)
> +{
> +       u32 i;
> +
> +       debug->address[0] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
> +       debug->state[0]   = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
> +
> +       for (i = 0; i < 500; i++) {
> +               debug->address[1] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
> +               debug->state[1]   = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
> +
> +               if (debug->address[0] != debug->address[1])
> +                       break;
> +
> +               if (debug->state[0] != debug->state[1])
> +                       break;
> +       }
> +}
> +
> +int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
> +{
> +       struct dma_debug debug;
> +       u32 dma_lo, dma_hi, axi, idle;
> +       int ret;
> +
> +       seq_printf(m, "%s Status:\n", dev_name(gpu->dev));
> +
> +       ret = pm_runtime_get_sync(gpu->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = mutex_lock_interruptible(&gpu->drm->struct_mutex);
> +       if (ret < 0)
> +               goto err_rpm;
> +
> +       dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW);
> +       dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH);
> +       axi = gpu_read(gpu, VIVS_HI_AXI_STATUS);
> +       idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +
> +       verify_dma(gpu, &debug);
> +
> +       seq_puts(m, "\tfeatures\n");
> +       seq_printf(m, "\t minor_features0: 0x%08x\n",
> +                  gpu->identity.minor_features0);
> +       seq_printf(m, "\t minor_features1: 0x%08x\n",
> +                  gpu->identity.minor_features1);
> +       seq_printf(m, "\t minor_features2: 0x%08x\n",
> +                  gpu->identity.minor_features2);
> +       seq_printf(m, "\t minor_features3: 0x%08x\n",
> +                  gpu->identity.minor_features3);
> +
> +       seq_puts(m, "\tspecs\n");
> +       seq_printf(m, "\t stream_count:  %d\n",
> +                       gpu->identity.stream_count);
> +       seq_printf(m, "\t register_max: %d\n",
> +                       gpu->identity.register_max);
> +       seq_printf(m, "\t thread_count: %d\n",
> +                       gpu->identity.thread_count);
> +       seq_printf(m, "\t vertex_cache_size: %d\n",
> +                       gpu->identity.vertex_cache_size);
> +       seq_printf(m, "\t shader_core_count: %d\n",
> +                       gpu->identity.shader_core_count);
> +       seq_printf(m, "\t pixel_pipes: %d\n",
> +                       gpu->identity.pixel_pipes);
> +       seq_printf(m, "\t vertex_output_buffer_size: %d\n",
> +                       gpu->identity.vertex_output_buffer_size);
> +       seq_printf(m, "\t buffer_size: %d\n",
> +                       gpu->identity.buffer_size);
> +       seq_printf(m, "\t instruction_count: %d\n",
> +                       gpu->identity.instruction_count);
> +       seq_printf(m, "\t num_constants: %d\n",
> +                       gpu->identity.num_constants);
> +
> +       seq_printf(m, "\taxi: 0x%08x\n", axi);
> +       seq_printf(m, "\tidle: 0x%08x\n", idle);
> +       idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP;
> +       if ((idle & VIVS_HI_IDLE_STATE_FE) == 0)
> +               seq_puts(m, "\t FE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_DE) == 0)
> +               seq_puts(m, "\t DE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_PE) == 0)
> +               seq_puts(m, "\t PE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_SH) == 0)
> +               seq_puts(m, "\t SH is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_PA) == 0)
> +               seq_puts(m, "\t PA is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_SE) == 0)
> +               seq_puts(m, "\t SE is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_RA) == 0)
> +               seq_puts(m, "\t RA is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_TX) == 0)
> +               seq_puts(m, "\t TX is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_VG) == 0)
> +               seq_puts(m, "\t VG is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_IM) == 0)
> +               seq_puts(m, "\t IM is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_FP) == 0)
> +               seq_puts(m, "\t FP is not idle\n");
> +       if ((idle & VIVS_HI_IDLE_STATE_TS) == 0)
> +               seq_puts(m, "\t TS is not idle\n");
> +       if (idle & VIVS_HI_IDLE_STATE_AXI_LP)
> +               seq_puts(m, "\t AXI low power mode\n");
> +
> +       if (gpu->identity.features & chipFeatures_DEBUG_MODE) {
> +               u32 read0 = gpu_read(gpu, VIVS_MC_DEBUG_READ0);
> +               u32 read1 = gpu_read(gpu, VIVS_MC_DEBUG_READ1);
> +               u32 write = gpu_read(gpu, VIVS_MC_DEBUG_WRITE);
> +
> +               seq_puts(m, "\tMC\n");
> +               seq_printf(m, "\t read0: 0x%08x\n", read0);
> +               seq_printf(m, "\t read1: 0x%08x\n", read1);
> +               seq_printf(m, "\t write: 0x%08x\n", write);
> +       }
> +
> +       seq_puts(m, "\tDMA ");
> +
> +       if (debug.address[0] == debug.address[1] &&
> +           debug.state[0] == debug.state[1]) {
> +               seq_puts(m, "seems to be stuck\n");
> +       } else if (debug.address[0] == debug.address[1]) {
> +               seq_puts(m, "adress is constant\n");
> +       } else {
> +               seq_puts(m, "is runing\n");
> +       }
> +
> +       seq_printf(m, "\t address 0: 0x%08x\n", debug.address[0]);
> +       seq_printf(m, "\t address 1: 0x%08x\n", debug.address[1]);
> +       seq_printf(m, "\t state 0: 0x%08x\n", debug.state[0]);
> +       seq_printf(m, "\t state 1: 0x%08x\n", debug.state[1]);
> +       seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n",
> +                  dma_lo, dma_hi);
> +
> +       ret = 0;
> +
> +       mutex_unlock(&gpu->drm->struct_mutex);
> +
> +err_rpm:
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return ret;
> +}
> +#endif
> +
> +/*
> + * Power Management:
> + */
> +static int enable_clk(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_core)
> +               clk_prepare_enable(gpu->clk_core);
> +       if (gpu->clk_shader)
> +               clk_prepare_enable(gpu->clk_shader);
> +
> +       return 0;
> +}
> +
> +static int disable_clk(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_core)
> +               clk_disable_unprepare(gpu->clk_core);
> +       if (gpu->clk_shader)
> +               clk_disable_unprepare(gpu->clk_shader);
> +
> +       return 0;
> +}
> +
> +static int enable_axi(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_bus)
> +               clk_prepare_enable(gpu->clk_bus);
> +
> +       return 0;
> +}
> +
> +static int disable_axi(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->clk_bus)
> +               clk_disable_unprepare(gpu->clk_bus);
> +
> +       return 0;
> +}
> +
> +/*
> + * Hangcheck detection for locked gpu:
> + */
> +static void recover_worker(struct work_struct *work)
> +{
> +       struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
> +                                              recover_work);
> +       struct drm_device *dev = gpu->drm;
> +       unsigned long flags;
> +       unsigned int i;
> +
> +       dev_err(gpu->dev, "hangcheck recover!\n");
> +
> +       if (pm_runtime_get_sync(gpu->dev) < 0)
> +               return;
> +
> +       mutex_lock(&dev->struct_mutex);
> +
> +       etnaviv_hw_reset(gpu);
> +
> +       /* complete all events, the GPU won't do it after the reset */
> +       spin_lock_irqsave(&gpu->event_spinlock, flags);
> +       for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
> +               if (!gpu->event[i].used)
> +                       continue;
> +               gpu->event[i].used = false;
> +               complete(&gpu->event_free);
> +               /*
> +                * Decrement the PM count for each stuck event. This is safe
> +                * even in atomic context as we use ASYNC RPM here.
> +                */
> +               pm_runtime_put_autosuspend(gpu->dev);
> +       }
> +       spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +       gpu->completed_fence = gpu->submitted_fence;
> +
> +       etnaviv_gpu_hw_init(gpu);
> +       gpu->switch_context = true;
> +
> +       mutex_unlock(&dev->struct_mutex);
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       /* Retire the buffer objects in a work */
> +       etnaviv_queue_work(gpu->drm, &gpu->retire_work);
> +}
> +
> +static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
> +{
> +       DBG("%s", dev_name(gpu->dev));
> +       mod_timer(&gpu->hangcheck_timer,
> +                 round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES));
> +}
> +
> +static void hangcheck_handler(unsigned long data)
> +{
> +       struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
> +       u32 fence = gpu->completed_fence;
> +       bool progress = false;
> +
> +       if (fence != gpu->hangcheck_fence) {
> +               gpu->hangcheck_fence = fence;
> +               progress = true;
> +       }
> +
> +       if (!progress) {
> +               u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
> +               int change = dma_addr - gpu->hangcheck_dma_addr;
> +
> +               if (change < 0 || change > 16) {
> +                       gpu->hangcheck_dma_addr = dma_addr;
> +                       progress = true;
> +               }
> +       }
> +
> +       if (!progress && fence_after(gpu->submitted_fence, fence)) {
> +               dev_err(gpu->dev, "hangcheck detected gpu lockup!\n");
> +               dev_err(gpu->dev, "     completed fence: %u\n", fence);
> +               dev_err(gpu->dev, "     submitted fence: %u\n",
> +                       gpu->submitted_fence);
> +               etnaviv_queue_work(gpu->drm, &gpu->recover_work);
> +       }
> +
> +       /* if still more pending work, reset the hangcheck timer: */
> +       if (fence_after(gpu->submitted_fence, gpu->hangcheck_fence))
> +               hangcheck_timer_reset(gpu);
> +}
> +
> +static void hangcheck_disable(struct etnaviv_gpu *gpu)
> +{
> +       del_timer_sync(&gpu->hangcheck_timer);
> +       cancel_work_sync(&gpu->recover_work);
> +}
> +
> +/*
> + * event management:
> + */
> +
> +static unsigned int event_alloc(struct etnaviv_gpu *gpu)
> +{
> +       unsigned long ret, flags;
> +       unsigned int i, event = ~0U;
> +
> +       ret = wait_for_completion_timeout(&gpu->event_free,
> +                                         msecs_to_jiffies(10 * 10000));
> +       if (!ret)
> +               dev_err(gpu->dev, "wait_for_completion_timeout failed");
> +
> +       spin_lock_irqsave(&gpu->event_spinlock, flags);
> +
> +       /* find first free event */
> +       for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
> +               if (gpu->event[i].used == false) {
> +                       gpu->event[i].used = true;
> +                       event = i;
> +                       break;
> +               }
> +       }
> +
> +       spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +
> +       return event;
> +}
> +
> +static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&gpu->event_spinlock, flags);
> +
> +       if (gpu->event[event].used == false) {
> +               dev_warn(gpu->dev, "event %u is already marked as free",
> +                        event);
> +               spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +       } else {
> +               gpu->event[event].used = false;
> +               spin_unlock_irqrestore(&gpu->event_spinlock, flags);
> +
> +               complete(&gpu->event_free);
> +       }
> +}
> +
> +/*
> + * Cmdstream submission/retirement:
> + */
> +
> +struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size)
> +{
> +       struct etnaviv_cmdbuf *cmdbuf;
> +
> +       cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
> +       if (!cmdbuf)
> +               return NULL;
> +
> +       cmdbuf->vaddr = dma_alloc_writecombine(gpu->dev, size, &cmdbuf->paddr,
> +                                              GFP_KERNEL);
> +       if (!cmdbuf->vaddr) {
> +               kfree(cmdbuf);
> +               return NULL;
> +       }
> +
> +       cmdbuf->gpu = gpu;
> +       cmdbuf->size = size;
> +
> +       return cmdbuf;
> +}
> +
> +void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
> +{
> +       dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
> +                             cmdbuf->vaddr, cmdbuf->paddr);
> +       kfree(cmdbuf);
> +}
> +
> +static void retire_worker(struct work_struct *work)
> +{
> +       struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
> +                                              retire_work);
> +       struct drm_device *dev = gpu->drm;
> +       u32 fence = gpu->completed_fence;
> +       struct etnaviv_cmdbuf *cmdbuf, *tmp;
> +
> +       mutex_lock(&dev->struct_mutex);
> +
> +       while (!list_empty(&gpu->active_list)) {
> +               struct etnaviv_gem_object *obj;
> +
> +               obj = list_first_entry(&gpu->active_list,
> +                               struct etnaviv_gem_object, mm_list);
> +
> +               if ((!(obj->access & ETNA_SUBMIT_BO_READ) ||
> +                    fence_after_eq(fence, obj->read_fence)) &&
> +                   (!(obj->access & ETNA_SUBMIT_BO_WRITE) ||
> +                    fence_after_eq(fence, obj->write_fence))) {
> +                       /* move to inactive: */
> +                       etnaviv_gem_move_to_inactive(&obj->base);
> +                       etnaviv_gem_put_iova(&obj->base);
> +                       drm_gem_object_unreference(&obj->base);
> +               } else {
> +                       break;
> +               }
> +       }
> +
> +       list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list,
> +                                gpu_active_list) {
> +               if (fence_after_eq(fence, cmdbuf->fence)) {
> +                       etnaviv_gpu_cmdbuf_free(cmdbuf);
> +                       list_del(&cmdbuf->gpu_active_list);
> +               }
> +       }
> +
> +       gpu->retired_fence = fence;
> +
> +       mutex_unlock(&dev->struct_mutex);
> +
> +       wake_up_all(&gpu->fence_event);
> +}
> +
> +static unsigned long etnaviv_timeout_to_jiffies(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;
> +}
> +
> +int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
> +       u32 fence, struct timespec *timeout)
> +{
> +       int ret;
> +
> +       if (fence_after(fence, gpu->submitted_fence)) {
> +               DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
> +                               fence, gpu->submitted_fence);
> +               return -EINVAL;
> +       }
> +
> +       if (!timeout) {
> +               /* No timeout was requested: just test for completion */
> +               ret = fence_completed(gpu, fence) ? 0 : -EBUSY;
> +       } else {
> +               unsigned long remaining = etnaviv_timeout_to_jiffies(timeout);
> +
> +               ret = wait_event_interruptible_timeout(gpu->fence_event,
> +                                               fence_completed(gpu, fence),
> +                                               remaining);
> +               if (ret == 0) {
> +                       DBG("timeout waiting for fence: %u (retired: %u completed: %u)",
> +                               fence, gpu->retired_fence,
> +                               gpu->completed_fence);
> +                       ret = -ETIMEDOUT;
> +               } else if (ret != -ERESTARTSYS) {
> +                       ret = 0;
> +               }
> +       }
> +
> +       return ret;
> +}
> +
> +/*
> + * Wait for an object to become inactive.  This, on it's own, is not race
> + * free: the object is moved by the retire worker off the active list, and
> + * then the iova is put.  Moreover, the object could be re-submitted just
> + * after we notice that it's become inactive.
> + *
> + * Although the retirement happens under the struct_mutex, we don't want
> + * to hold that lock in this function.  Instead, the caller is responsible
> + * for ensuring that the retire worker has finished (which will happen, eg,
> + * when we unreference the object, an action which takes the struct_mutex.)
> + */
> +int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
> +       struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout)
> +{
> +       unsigned long remaining;
> +       long ret;
> +
> +       if (!timeout)
> +               return !is_active(etnaviv_obj) ? 0 : -EBUSY;
> +
> +       remaining = etnaviv_timeout_to_jiffies(timeout);
> +
> +       ret = wait_event_interruptible_timeout(gpu->fence_event,
> +                                              !is_active(etnaviv_obj),
> +                                              remaining);
> +       if (ret > 0)
> +               return 0;
> +       else if (ret == -ERESTARTSYS)
> +               return -ERESTARTSYS;
> +       else
> +               return -ETIMEDOUT;
> +}
> +
> +int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu)
> +{
> +       return pm_runtime_get_sync(gpu->dev);
> +}
> +
> +void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu)
> +{
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +}
> +
> +/* add bo's to gpu's ring, and kick gpu: */
> +int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
> +       struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx)
> +{
> +       struct drm_device *dev = gpu->drm;
> +       struct etnaviv_drm_private *priv = dev->dev_private;
> +       unsigned int event, i;
> +       int ret;
> +
> +       ret = pm_runtime_get_sync(gpu->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       /*
> +        * TODO
> +        *
> +        * - flush
> +        * - data endian
> +        * - prefetch
> +        *
> +        */
> +
> +       event = event_alloc(gpu);
> +       if (unlikely(event == ~0U)) {
> +               DRM_ERROR("no free event\n");
> +               pm_runtime_put_autosuspend(gpu->dev);
> +               return -EBUSY;
> +       }
> +
> +       submit->fence = ++priv->next_fence;
> +
> +       gpu->submitted_fence = submit->fence;
> +
> +       if (gpu->lastctx != ctx) {
> +               gpu->mmu->need_flush = true;
> +               gpu->switch_context = true;
> +               gpu->lastctx = ctx;
> +       }
> +
> +       etnaviv_buffer_queue(gpu, event, submit);
> +
> +       for (i = 0; i < submit->nr_bos; i++) {
> +               struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
> +
> +               /* can't happen yet.. but when we add 2d support we'll have
> +                * to deal w/ cross-ring synchronization:
> +                */
> +               WARN_ON(is_active(etnaviv_obj) && (etnaviv_obj->gpu != gpu));
> +
> +               if (!is_active(etnaviv_obj)) {
> +                       u32 iova;
> +
> +                       /* ring takes a reference to the bo and iova: */
> +                       drm_gem_object_reference(&etnaviv_obj->base);
> +                       etnaviv_gem_get_iova_locked(gpu, &etnaviv_obj->base,
> +                                                   &iova);
> +               }
> +
> +               if (submit->bos[i].flags & (ETNA_SUBMIT_BO_READ |
> +                                           ETNA_SUBMIT_BO_WRITE))
> +                       etnaviv_gem_move_to_active(&etnaviv_obj->base, gpu,
> +                                                  submit->bos[i].flags,
> +                                                  submit->fence);
> +       }
> +       hangcheck_timer_reset(gpu);
> +
> +       return 0;
> +}
> +
> +/*
> + * Init/Cleanup:
> + */
> +static irqreturn_t irq_handler(int irq, void *data)
> +{
> +       struct etnaviv_gpu *gpu = data;
> +       irqreturn_t ret = IRQ_NONE;
> +
> +       u32 intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE);
> +
> +       if (intr != 0) {
> +               int event;
> +
> +               pm_runtime_mark_last_busy(gpu->dev);
> +
> +               dev_dbg(gpu->dev, "intr 0x%08x\n", intr);
> +
> +               if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) {
> +                       dev_err(gpu->dev, "AXI bus error\n");
> +                       intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR;
> +               }
> +
> +               while ((event = ffs(intr)) != 0) {
> +                       event -= 1;
> +
> +                       intr &= ~(1 << event);
> +
> +                       dev_dbg(gpu->dev, "event %u\n", event);
> +                       /*
> +                        * Events can be processed out of order.  Eg,
> +                        * - allocate and queue event 0
> +                        * - allocate event 1
> +                        * - event 0 completes, we process it
> +                        * - allocate and queue event 0
> +                        * - event 1 and event 0 complete
> +                        * we can end up processing event 0 first, then 1.
> +                        */
> +                       if (fence_after(gpu->event[event].fence,
> +                                       gpu->completed_fence))
> +                               gpu->completed_fence = gpu->event[event].fence;
> +                       event_free(gpu, event);
> +
> +                       /*
> +                        * We need to balance the runtime PM count caused by
> +                        * each submission.  Upon submission, we increment
> +                        * the runtime PM counter, and allocate one event.
> +                        * So here, we put the runtime PM count for each
> +                        * completed event.
> +                        */
> +                       pm_runtime_put_autosuspend(gpu->dev);
> +               }
> +
> +               /* Retire the buffer objects in a work */
> +               etnaviv_queue_work(gpu->drm, &gpu->retire_work);
> +
> +               ret = IRQ_HANDLED;
> +       }
> +
> +       return ret;
> +}
> +
> +static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
> +{
> +       int ret;
> +
> +       ret = enable_clk(gpu);
> +       if (ret)
> +               return ret;
> +
> +       ret = enable_axi(gpu);
> +       if (ret) {
> +               disable_clk(gpu);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
> +{
> +       int ret;
> +
> +       ret = disable_axi(gpu);
> +       if (ret)
> +               return ret;
> +
> +       ret = disable_clk(gpu);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
> +{
> +       if (gpu->buffer) {
> +               unsigned long timeout;
> +
> +               /* Replace the last WAIT with END */
> +               etnaviv_buffer_end(gpu);
> +
> +               /*
> +                * We know that only the FE is busy here, this should
> +                * happen quickly (as the WAIT is only 200 cycles).  If
> +                * we fail, just warn and continue.
> +                */
> +               timeout = jiffies + msecs_to_jiffies(100);
> +               do {
> +                       u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
> +
> +                       if ((idle & gpu->idle_mask) == gpu->idle_mask)
> +                               break;
> +
> +                       if (time_is_before_jiffies(timeout)) {
> +                               dev_warn(gpu->dev,
> +                                        "timed out waiting for idle: idle=0x%x\n",
> +                                        idle);
> +                               break;
> +                       }
> +
> +                       udelay(5);
> +               } while (1);
> +       }
> +
> +       return etnaviv_gpu_clk_disable(gpu);
> +}
> +
> +#ifdef CONFIG_PM
> +static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
> +{
> +       struct drm_device *drm = gpu->drm;
> +       u32 clock;
> +       int ret;
> +
> +       ret = mutex_lock_killable(&drm->struct_mutex);
> +       if (ret)
> +               return ret;
> +
> +       clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
> +               VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
> +
> +       etnaviv_gpu_load_clock(gpu, clock);
> +       etnaviv_gpu_hw_init(gpu);
> +
> +       gpu->switch_context = true;
> +
> +       mutex_unlock(&drm->struct_mutex);
> +
> +       return 0;
> +}
> +#endif
> +
> +static int etnaviv_gpu_bind(struct device *dev, struct device *master,
> +       void *data)
> +{
> +       struct drm_device *drm = data;
> +       struct etnaviv_drm_private *priv = drm->dev_private;
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +       int ret;
> +
> +#ifdef CONFIG_PM
> +       ret = pm_runtime_get_sync(gpu->dev);
> +#else
> +       ret = etnaviv_gpu_clk_enable(gpu);
> +#endif
> +       if (ret < 0)
> +               return ret;
> +
> +       gpu->drm = drm;
> +
> +       INIT_LIST_HEAD(&gpu->active_list);
> +       INIT_LIST_HEAD(&gpu->active_cmd_list);
> +       INIT_WORK(&gpu->retire_work, retire_worker);
> +       INIT_WORK(&gpu->recover_work, recover_worker);
> +       init_waitqueue_head(&gpu->fence_event);
> +
> +       setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
> +                       (unsigned long)gpu);
> +
> +       priv->gpu[priv->num_gpus++] = gpu;
> +
> +       pm_runtime_mark_last_busy(gpu->dev);
> +       pm_runtime_put_autosuspend(gpu->dev);
> +
> +       return 0;
> +}
> +
> +static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
> +       void *data)
> +{
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +
> +       DBG("%s", dev_name(gpu->dev));
> +
> +       hangcheck_disable(gpu);
> +
> +       WARN_ON(!list_empty(&gpu->active_list));
> +
> +#ifdef CONFIG_PM
> +       pm_runtime_get_sync(gpu->dev);
> +       pm_runtime_put_sync_suspend(gpu->dev);
> +#else
> +       etnaviv_gpu_hw_suspend(gpu);
> +#endif
> +
> +       if (gpu->buffer) {
> +               etnaviv_gpu_cmdbuf_free(gpu->buffer);
> +               gpu->buffer = NULL;
> +       }
> +
> +       if (gpu->mmu) {
> +               etnaviv_iommu_destroy(gpu->mmu);
> +               gpu->mmu = NULL;
> +       }
> +
> +       gpu->drm = NULL;
> +}
> +
> +static const struct component_ops gpu_ops = {
> +       .bind = etnaviv_gpu_bind,
> +       .unbind = etnaviv_gpu_unbind,
> +};
> +
> +static const struct of_device_id etnaviv_gpu_match[] = {
> +       {
> +               .compatible = "vivante,gc"
> +       },
> +       { /* sentinel */ }
> +};
> +
> +static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct etnaviv_gpu *gpu;
> +       int err = 0;
> +
> +       gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL);
> +       if (!gpu)
> +               return -ENOMEM;
> +
> +       gpu->dev = &pdev->dev;
> +
> +       /*
> +        * Set the GPU base address to the start of physical memory.  This
> +        * ensures that if we have up to 2GB, the v1 MMU can address the
> +        * highest memory.  This is important as command buffers may be
> +        * allocated outside of this limit.
> +        */
> +       gpu->memory_base = PHYS_OFFSET;
> +
> +       /* Map registers: */
> +       gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev));
> +       if (IS_ERR(gpu->mmio))
> +               return PTR_ERR(gpu->mmio);
> +
> +       /* Get Interrupt: */
> +       gpu->irq = platform_get_irq(pdev, 0);
> +       if (gpu->irq < 0) {
> +               err = gpu->irq;
> +               dev_err(dev, "failed to get irq: %d\n", err);
> +               goto fail;
> +       }
> +
> +       err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0,
> +                              dev_name(gpu->dev), gpu);
> +       if (err) {
> +               dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err);
> +               goto fail;
> +       }
> +
> +       /* Get Clocks: */
> +       gpu->clk_bus = devm_clk_get(&pdev->dev, "bus");
> +       DBG("clk_bus: %p", gpu->clk_bus);
> +       if (IS_ERR(gpu->clk_bus))
> +               gpu->clk_bus = NULL;
> +
> +       gpu->clk_core = devm_clk_get(&pdev->dev, "core");
> +       DBG("clk_core: %p", gpu->clk_core);
> +       if (IS_ERR(gpu->clk_core))
> +               gpu->clk_core = NULL;
> +
> +       gpu->clk_shader = devm_clk_get(&pdev->dev, "shader");
> +       DBG("clk_shader: %p", gpu->clk_shader);
> +       if (IS_ERR(gpu->clk_shader))
> +               gpu->clk_shader = NULL;
> +
> +       /* TODO: figure out max mapped size */
> +       dev_set_drvdata(dev, gpu);
> +
> +       /*
> +        * We treat the device as initially suspended.  The runtime PM
> +        * autosuspend delay is rather arbitary: no measurements have
> +        * yet been performed to determine an appropriate value.
> +        */
> +       pm_runtime_use_autosuspend(gpu->dev);
> +       pm_runtime_set_autosuspend_delay(gpu->dev, 200);
> +       pm_runtime_enable(gpu->dev);
> +
> +       err = component_add(&pdev->dev, &gpu_ops);
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to register component: %d\n", err);
> +               goto fail;
> +       }
> +
> +       return 0;
> +
> +fail:
> +       return err;
> +}
> +
> +static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
> +{
> +       component_del(&pdev->dev, &gpu_ops);
> +       pm_runtime_disable(&pdev->dev);
> +       return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int etnaviv_gpu_rpm_suspend(struct device *dev)
> +{
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +       u32 idle, mask;
> +
> +       /* If we have outstanding fences, we're not idle */
> +       if (gpu->completed_fence != gpu->submitted_fence)
> +               return -EBUSY;
> +
> +       /* Check whether the hardware (except FE) is idle */
> +       mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE;
> +       idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask;
> +       if (idle != mask)
> +               return -EBUSY;
> +
> +       return etnaviv_gpu_hw_suspend(gpu);
> +}
> +
> +static int etnaviv_gpu_rpm_resume(struct device *dev)
> +{
> +       struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
> +       int ret;
> +
> +       /* We must never runtime-PM resume holding struct_mutex */
> +       if (gpu->drm && WARN_ON_ONCE(mutex_is_locked(&gpu->drm->struct_mutex)))
> +               return -EDEADLK;
> +
> +       ret = etnaviv_gpu_clk_enable(gpu);
> +       if (ret)
> +               return ret;
> +
> +       /* Re-initialise the basic hardware state */
> +       if (gpu->drm && gpu->buffer) {
> +               ret = etnaviv_gpu_hw_resume(gpu);
> +               if (ret) {
> +                       etnaviv_gpu_clk_disable(gpu);
> +                       return ret;
> +               }
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
> +       SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume,
> +                          NULL)
> +};
> +
> +struct platform_driver etnaviv_gpu_driver = {
> +       .driver = {
> +               .name = "etnaviv-gpu",
> +               .owner = THIS_MODULE,
> +               .pm = &etnaviv_gpu_pm_ops,
> +               .of_match_table = etnaviv_gpu_match,
> +       },
> +       .probe = etnaviv_gpu_platform_probe,
> +       .remove = etnaviv_gpu_platform_remove,
> +       .id_table = gpu_ids,
> +};
> diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
> new file mode 100644
> index 000000000000..3be5b481d8d1
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_gpu.h
> @@ -0,0 +1,198 @@
> +/*
> + * 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;
> +       u32 fence;
> +};
> +
> +struct etnaviv_cmdbuf;
> +
> +struct etnaviv_gpu {
> +       struct drm_device *drm;
> +       struct device *dev;
> +       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 GEM active objects: */
> +       struct list_head active_list;
> +
> +       /* list of currently in-flight command buffers */
> +       struct list_head active_cmd_list;
> +
> +       u32 idle_mask;
> +
> +       /* Fencing support */
> +       u32 submitted_fence;
> +       u32 completed_fence;
> +       u32 retired_fence;
> +       wait_queue_head_t fence_event;
> +
> +       /* 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;
> +       /* cmdbuf properties */
> +       void *vaddr;
> +       dma_addr_t paddr;
> +       u32 size;
> +       u32 user_size;
> +       /* fence after which this buffer is to be disposed */
> +       u32 fence;
> +       /* per GPU in-flight list */
> +       struct list_head gpu_active_list;
> +};
> +
> +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
> +
> +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_file_private *ctx);
> +struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
> +                                             u32 size);
> +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__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
> new file mode 100644
> index 000000000000..9efb7d6092b4
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu.c
> @@ -0,0 +1,221 @@
> +/*
> + * 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_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_iommu_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_iommu_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 struct iommu_ops etnaviv_iommu_ops = {
> +               .domain_free = etnaviv_domain_free,
> +               .map = etnaviv_iommu_map,
> +               .unmap = etnaviv_iommu_unmap,
> +               .iova_to_phys = etnaviv_iommu_iova_to_phys,
> +               .pgsize_bitmap = SZ_4K,
> +};
> +
> +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;
> +       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;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu.h b/drivers/staging/etnaviv/etnaviv_iommu.h
> new file mode 100644
> index 000000000000..cf45503f6b6f
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu.h
> @@ -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__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.c b/drivers/staging/etnaviv/etnaviv_iommu_v2.c
> new file mode 100644
> index 000000000000..fbb4aed3dc80
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.c
> @@ -0,0 +1,33 @@
> +/*
> + * 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_iommu.h"
> +#include "state_hi.xml.h"
> +
> +
> +struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu)
> +{
> +       /* TODO */
> +       return NULL;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.h b/drivers/staging/etnaviv/etnaviv_iommu_v2.h
> new file mode 100644
> index 000000000000..603ea41c5389
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.h
> @@ -0,0 +1,25 @@
> +/*
> + * 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_V2_H__
> +#define __ETNAVIV_IOMMU_V2_H__
> +
> +#include <linux/iommu.h>
> +struct etnaviv_gpu;
> +
> +struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
> +
> +#endif /* __ETNAVIV_IOMMU_V2_H__ */
> diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
> new file mode 100644
> index 000000000000..ca317f633970
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_mmu.c
> @@ -0,0 +1,282 @@
> +/*
> + * 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 "etnaviv_drv.h"
> +#include "etnaviv_gem.h"
> +#include "etnaviv_mmu.h"
> +
> +static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device *dev,
> +               unsigned long iova, int flags, void *arg)
> +{
> +       DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
> +       return 0;
> +}
> +
> +int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
> +               struct sg_table *sgt, unsigned len, int prot)
> +{
> +       struct iommu_domain *domain = iommu->domain;
> +       struct scatterlist *sg;
> +       unsigned int da = iova;
> +       unsigned int i, j;
> +       int ret;
> +
> +       if (!domain || !sgt)
> +               return -EINVAL;
> +
> +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +               u32 pa = sg_dma_address(sg) - sg->offset;
> +               size_t bytes = sg_dma_len(sg) + sg->offset;
> +
> +               VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
> +
> +               ret = iommu_map(domain, da, pa, bytes, prot);
> +               if (ret)
> +                       goto fail;
> +
> +               da += bytes;
> +       }
> +
> +       return 0;
> +
> +fail:
> +       da = iova;
> +
> +       for_each_sg(sgt->sgl, sg, i, j) {
> +               size_t bytes = sg_dma_len(sg) + sg->offset;
> +
> +               iommu_unmap(domain, da, bytes);
> +               da += bytes;
> +       }
> +       return ret;
> +}
> +
> +int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
> +               struct sg_table *sgt, unsigned len)
> +{
> +       struct iommu_domain *domain = iommu->domain;
> +       struct scatterlist *sg;
> +       unsigned int da = iova;
> +       int i;
> +
> +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +               size_t bytes = sg_dma_len(sg) + sg->offset;
> +               size_t unmapped;
> +
> +               unmapped = iommu_unmap(domain, da, bytes);
> +               if (unmapped < bytes)
> +                       return unmapped;
> +
> +               VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
> +
> +               BUG_ON(!PAGE_ALIGNED(bytes));
> +
> +               da += bytes;
> +       }
> +
> +       return 0;
> +}
> +
> +int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
> +       struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
> +       struct etnaviv_vram_mapping **out_mapping)
> +{
> +       struct etnaviv_drm_private *priv = etnaviv_obj->base.dev->dev_private;
> +       struct sg_table *sgt = etnaviv_obj->sgt;
> +       struct etnaviv_vram_mapping *mapping, *free = NULL;
> +       struct drm_mm_node *node;
> +       int ret;
> +
> +       mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
> +       if (!mapping)
> +               return -ENOMEM;
> +
> +       INIT_LIST_HEAD(&mapping->scan_node);
> +       mapping->object = etnaviv_obj;
> +       mapping->mmu = mmu;
> +
> +       /* v1 MMU can optimize single entry (contiguous) scatterlists */
> +       if (sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
> +               u32 iova;
> +
> +               iova = sg_dma_address(sgt->sgl) - memory_base;
> +               if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
> +                       mapping->iova = iova;
> +                       list_add_tail(&mapping->obj_node,
> +                                     &etnaviv_obj->vram_list);
> +                       if (out_mapping)
> +                               *out_mapping = mapping;
> +                       return 0;
> +               }
> +       }
> +
> +       node = &mapping->vram_node;
> +       while (1) {
> +               struct etnaviv_gem_object *o;
> +               struct etnaviv_vram_mapping *m, *n;
> +               struct list_head list;
> +               bool found;
> +
> +               ret = drm_mm_insert_node_in_range(&mmu->mm, node,
> +                       etnaviv_obj->base.size, 0, mmu->last_iova, ~0UL,
> +                       DRM_MM_SEARCH_DEFAULT);
> +
> +               if (ret != -ENOSPC)
> +                       break;
> +
> +               /*
> +                * If we did not search from the start of the MMU region,
> +                * try again in case there are free slots.
> +                */
> +               if (mmu->last_iova) {
> +                       mmu->last_iova = 0;
> +                       mmu->need_flush = true;
> +                       continue;
> +               }
> +
> +               /* Try to retire some entries */
> +               drm_mm_init_scan(&mmu->mm, etnaviv_obj->base.size, 0, 0);
> +
> +               found = 0;
> +               INIT_LIST_HEAD(&list);
> +               list_for_each_entry(o, &priv->inactive_list, mm_list) {
> +                       free = etnaviv_gem_get_vram_mapping(o, mmu);
> +                       if (!free)
> +                               continue;
> +
> +                       /*
> +                        * If this vram node has not been used, skip this.
> +                        */
> +                       if (!free->vram_node.mm)
> +                               continue;
> +
> +                       /*
> +                        * If it's on the submit list, then it is part of
> +                        * a submission, and we want to keep its entry.
> +                        */
> +                       if (!list_empty(&o->submit_entry))
> +                               continue;
> +
> +                       list_add(&free->scan_node, &list);
> +                       if (drm_mm_scan_add_block(&free->vram_node)) {
> +                               found = true;
> +                               break;
> +                       }
> +               }
> +
> +               if (!found) {
> +                       /* Nothing found, clean up and fail */
> +                       list_for_each_entry_safe(m, n, &list, scan_node)
> +                               BUG_ON(drm_mm_scan_remove_block(&m->vram_node));
> +                       break;
> +               }
> +
> +               /*
> +                * drm_mm does not allow any other operations while
> +                * scanning, so we have to remove all blocks first.
> +                * If drm_mm_scan_remove_block() returns false, we
> +                * can leave the block pinned.
> +                */
> +               list_for_each_entry_safe(m, n, &list, scan_node)
> +                       if (!drm_mm_scan_remove_block(&m->vram_node))
> +                               list_del_init(&m->scan_node);
> +
> +               list_for_each_entry_safe(m, n, &list, scan_node) {
> +                       list_del_init(&m->scan_node);
> +                       etnaviv_iommu_unmap_gem(m);
> +               }
> +
> +               /*
> +                * We removed enough mappings so that the new allocation will
> +                * succeed.  Ensure that the MMU will be flushed and retry
> +                * the allocation one more time.
> +                */
> +               mmu->need_flush = true;
> +       }
> +
> +       if (ret < 0) {
> +               kfree(mapping);
> +               return ret;
> +       }
> +
> +       mmu->last_iova = node->start + etnaviv_obj->base.size;
> +       mapping->iova = node->start;
> +       ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size,
> +                               IOMMU_READ | IOMMU_WRITE);
> +
> +       if (ret < 0) {
> +               drm_mm_remove_node(node);
> +               kfree(mapping);
> +               return ret;
> +       }
> +
> +       list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);
> +       if (out_mapping)
> +               *out_mapping = mapping;
> +
> +       return ret;
> +}
> +
> +void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping)
> +{
> +       struct etnaviv_iommu *mmu;
> +       struct etnaviv_gem_object *etnaviv_obj;
> +
> +       if (!mapping)
> +               return;
> +
> +       mmu = mapping->mmu;
> +
> +       /* If the vram node is on the mm, unmap and remove the node */
> +       if (mapping->vram_node.mm == &mmu->mm) {
> +               etnaviv_obj = mapping->object;
> +               etnaviv_iommu_unmap(mmu, mapping->vram_node.start,
> +                                   etnaviv_obj->sgt, etnaviv_obj->base.size);
> +               drm_mm_remove_node(&mapping->vram_node);
> +       }
> +
> +       list_del(&mapping->obj_node);
> +       kfree(mapping);
> +}
> +
> +void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
> +{
> +       drm_mm_takedown(&mmu->mm);
> +       iommu_domain_free(mmu->domain);
> +       kfree(mmu);
> +}
> +
> +struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev,
> +       struct iommu_domain *domain, enum etnaviv_iommu_version version)
> +{
> +       struct etnaviv_iommu *mmu;
> +
> +       mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
> +       if (!mmu)
> +               return ERR_PTR(-ENOMEM);
> +
> +       mmu->domain = domain;
> +       mmu->dev = dev;
> +       mmu->version = version;
> +
> +       drm_mm_init(&mmu->mm, domain->geometry.aperture_start,
> +                   domain->geometry.aperture_end -
> +                     domain->geometry.aperture_start + 1);
> +
> +       iommu_set_fault_handler(domain, etnaviv_fault_handler, dev);
> +
> +       return mmu;
> +}
> diff --git a/drivers/staging/etnaviv/etnaviv_mmu.h b/drivers/staging/etnaviv/etnaviv_mmu.h
> new file mode 100644
> index 000000000000..444ef296d2b4
> --- /dev/null
> +++ b/drivers/staging/etnaviv/etnaviv_mmu.h
> @@ -0,0 +1,58 @@
> +/*
> + * 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_MMU_H__
> +#define __ETNAVIV_MMU_H__
> +
> +#include <linux/iommu.h>
> +
> +enum etnaviv_iommu_version {
> +       ETNAVIV_IOMMU_V1 = 0,
> +       ETNAVIV_IOMMU_V2,
> +};
> +
> +struct etnaviv_vram_mapping;
> +
> +struct etnaviv_iommu {
> +       struct device *dev;
> +       struct iommu_domain *domain;
> +
> +       enum etnaviv_iommu_version version;
> +
> +       /* memory manager for GPU address area */
> +       struct drm_mm mm;
> +       u32 last_iova;
> +       bool need_flush;
> +};
> +
> +struct etnaviv_gem_object;
> +
> +int etnaviv_iommu_attach(struct etnaviv_iommu *iommu, const char **names,
> +       int cnt);
> +int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
> +       struct sg_table *sgt, unsigned len, int prot);
> +int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
> +       struct sg_table *sgt, unsigned len);
> +int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
> +       struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
> +       struct etnaviv_vram_mapping **mapping);
> +void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping);
> +void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
> +
> +struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev,
> +       struct iommu_domain *domain, enum etnaviv_iommu_version version);
> +
> +#endif /* __ETNAVIV_MMU_H__ */
> diff --git a/drivers/staging/etnaviv/state.xml.h b/drivers/staging/etnaviv/state.xml.h
> new file mode 100644
> index 000000000000..368218304566
> --- /dev/null
> +++ b/drivers/staging/etnaviv/state.xml.h
> @@ -0,0 +1,351 @@
> +#ifndef STATE_XML
> +#define STATE_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.xml    (  18882 bytes, from 2015-03-25 11:42:32)
> +- common.xml   (  18437 bytes, from 2015-03-25 11:27:41)
> +- state_hi.xml (  23420 bytes, from 2015-03-25 11:47:21)
> +- state_2d.xml (  51549 bytes, from 2015-03-25 11:25:06)
> +- state_3d.xml (  54600 bytes, from 2015-03-25 11:25:19)
> +- state_vg.xml (   5973 bytes, from 2015-03-25 11:26:01)
> +
> +Copyright (C) 2015
> +*/
> +
> +
> +#define VARYING_COMPONENT_USE_UNUSED                           0x00000000
> +#define VARYING_COMPONENT_USE_USED                             0x00000001
> +#define VARYING_COMPONENT_USE_POINTCOORD_X                     0x00000002
> +#define VARYING_COMPONENT_USE_POINTCOORD_Y                     0x00000003
> +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK           0x000000ff
> +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT          0
> +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x)              (((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK)
> +#define VIVS_FE                                                        0x00000000
> +
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0)                     (0x00000600 + 0x4*(i0))
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE                   0x00000004
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN                     0x00000010
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK               0x0000000f
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT              0
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE                        0x00000000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE       0x00000001
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT               0x00000002
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT      0x00000003
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT                 0x00000004
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT                0x00000005
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT               0x00000008
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT          0x00000009
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED               0x0000000b
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2      0x0000000c
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2     0x0000000d
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK             0x00000030
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT            4
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x)                        (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE           0x00000080
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK             0x00000700
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT            8
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x)                        (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK                        0x00003000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT               12
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x)                   (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK          0x0000c000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT         14
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF            0x00000000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON             0x00008000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK              0x00ff0000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT             16
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x)                 (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK)
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK                        0xff000000
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT               24
> +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x)                   (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK)
> +
> +#define VIVS_FE_CMD_STREAM_BASE_ADDR                           0x00000640
> +
> +#define VIVS_FE_INDEX_STREAM_BASE_ADDR                         0x00000644
> +
> +#define VIVS_FE_INDEX_STREAM_CONTROL                           0x00000648
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK                        0x00000003
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT               0
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR                0x00000000
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT       0x00000001
> +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT         0x00000002
> +
> +#define VIVS_FE_VERTEX_STREAM_BASE_ADDR                                0x0000064c
> +
> +#define VIVS_FE_VERTEX_STREAM_CONTROL                          0x00000650
> +
> +#define VIVS_FE_COMMAND_ADDRESS                                        0x00000654
> +
> +#define VIVS_FE_COMMAND_CONTROL                                        0x00000658
> +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK                 0x0000ffff
> +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT                        0
> +#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x)                    (((x) << VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK)
> +#define VIVS_FE_COMMAND_CONTROL_ENABLE                         0x00010000
> +
> +#define VIVS_FE_DMA_STATUS                                     0x0000065c
> +
> +#define VIVS_FE_DMA_DEBUG_STATE                                        0x00000660
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK                        0x0000001f
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT               0
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE                 0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC                  0x00000001
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0                 0x00000002
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0                        0x00000003
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1                 0x00000004
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1                        0x00000005
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR                        0x00000006
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD                        0x00000007
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL               0x00000008
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL            0x00000009
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA           0x0000000a
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX              0x0000000b
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW                 0x0000000c
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0              0x0000000d
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1              0x0000000e
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0              0x0000000f
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1              0x00000010
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO             0x00000011
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT                 0x00000012
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK                 0x00000013
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END                  0x00000014
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL                        0x00000015
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK            0x00000300
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT           8
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE             0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START            0x00000100
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ              0x00000200
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END              0x00000300
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK          0x00000c00
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT         10
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE           0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID       0x00000400
> +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID          0x00000800
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK            0x00003000
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT           12
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE             0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX          0x00001000
> +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL              0x00002000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK                        0x0000c000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT               14
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE                 0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR                        0x00004000
> +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC              0x00008000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK             0x00030000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT            16
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE              0x00000000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE           0x00010000
> +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS              0x00020000
> +
> +#define VIVS_FE_DMA_ADDRESS                                    0x00000664
> +
> +#define VIVS_FE_DMA_LOW                                                0x00000668
> +
> +#define VIVS_FE_DMA_HIGH                                       0x0000066c
> +
> +#define VIVS_FE_AUTO_FLUSH                                     0x00000670
> +
> +#define VIVS_FE_UNK00678                                       0x00000678
> +
> +#define VIVS_FE_UNK0067C                                       0x0000067c
> +
> +#define VIVS_FE_VERTEX_STREAMS(i0)                            (0x00000000 + 0x4*(i0))
> +#define VIVS_FE_VERTEX_STREAMS__ESIZE                          0x00000004
> +#define VIVS_FE_VERTEX_STREAMS__LEN                            0x00000008
> +
> +#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0)                  (0x00000680 + 0x4*(i0))
> +
> +#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0)                    (0x000006a0 + 0x4*(i0))
> +
> +#define VIVS_FE_UNK00700(i0)                                  (0x00000700 + 0x4*(i0))
> +#define VIVS_FE_UNK00700__ESIZE                                        0x00000004
> +#define VIVS_FE_UNK00700__LEN                                  0x00000010
> +
> +#define VIVS_FE_UNK00740(i0)                                  (0x00000740 + 0x4*(i0))
> +#define VIVS_FE_UNK00740__ESIZE                                        0x00000004
> +#define VIVS_FE_UNK00740__LEN                                  0x00000010
> +
> +#define VIVS_FE_UNK00780(i0)                                  (0x00000780 + 0x4*(i0))
> +#define VIVS_FE_UNK00780__ESIZE                                        0x00000004
> +#define VIVS_FE_UNK00780__LEN                                  0x00000010
> +
> +#define VIVS_GL                                                        0x00000000
> +
> +#define VIVS_GL_PIPE_SELECT                                    0x00003800
> +#define VIVS_GL_PIPE_SELECT_PIPE__MASK                         0x00000001
> +#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT                                0
> +#define VIVS_GL_PIPE_SELECT_PIPE(x)                            (((x) << VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK)
> +
> +#define VIVS_GL_EVENT                                          0x00003804
> +#define VIVS_GL_EVENT_EVENT_ID__MASK                           0x0000001f
> +#define VIVS_GL_EVENT_EVENT_ID__SHIFT                          0
> +#define VIVS_GL_EVENT_EVENT_ID(x)                              (((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK)
> +#define VIVS_GL_EVENT_FROM_FE                                  0x00000020
> +#define VIVS_GL_EVENT_FROM_PE                                  0x00000040
> +#define VIVS_GL_EVENT_SOURCE__MASK                             0x00001f00
> +#define VIVS_GL_EVENT_SOURCE__SHIFT                            8
> +#define VIVS_GL_EVENT_SOURCE(x)                                        (((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK)
> +
> +#define VIVS_GL_SEMAPHORE_TOKEN                                        0x00003808
> +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK                     0x0000001f
> +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT                    0
> +#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x)                                (((x) << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK)
> +#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK                       0x00001f00
> +#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT                      8
> +#define VIVS_GL_SEMAPHORE_TOKEN_TO(x)                          (((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK)
> +
> +#define VIVS_GL_FLUSH_CACHE                                    0x0000380c
> +#define VIVS_GL_FLUSH_CACHE_DEPTH                              0x00000001
> +#define VIVS_GL_FLUSH_CACHE_COLOR                              0x00000002
> +#define VIVS_GL_FLUSH_CACHE_TEXTURE                            0x00000004
> +#define VIVS_GL_FLUSH_CACHE_PE2D                               0x00000008
> +#define VIVS_GL_FLUSH_CACHE_TEXTUREVS                          0x00000010
> +#define VIVS_GL_FLUSH_CACHE_SHADER_L1                          0x00000020
> +#define VIVS_GL_FLUSH_CACHE_SHADER_L2                          0x00000040
> +
> +#define VIVS_GL_FLUSH_MMU                                      0x00003810
> +#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU                          0x00000001
> +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1                           0x00000002
> +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2                           0x00000004
> +#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU                          0x00000008
> +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4                           0x00000010
> +
> +#define VIVS_GL_VERTEX_ELEMENT_CONFIG                          0x00003814
> +
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG                            0x00003818
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK         0x00000003
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT                0
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE          0x00000000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X            0x00000001
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X            0x00000002
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK          0x00000008
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK         0x000000f0
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT                4
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x)            (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK)
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK          0x00000100
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK                        0x00007000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT               12
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x)                   (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK)
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK                 0x00008000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK                        0x00030000
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT               16
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x)                   (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK)
> +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK                 0x00080000
> +
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS                       0x0000381c
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK             0x000000ff
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT            0
> +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x)                        (((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK)
> +
> +#define VIVS_GL_VARYING_NUM_COMPONENTS                         0x00003820
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK              0x00000007
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT             0
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK              0x00000070
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT             4
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK              0x00000700
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT             8
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK              0x00007000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT             12
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK              0x00070000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT             16
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK              0x00700000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT             20
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK              0x07000000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT             24
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK)
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK              0x70000000
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT             28
> +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x)                 (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK)
> +
> +#define VIVS_GL_VARYING_COMPONENT_USE(i0)                     (0x00003828 + 0x4*(i0))
> +#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE                   0x00000004
> +#define VIVS_GL_VARYING_COMPONENT_USE__LEN                     0x00000002
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK              0x00000003
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT             0
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK              0x0000000c
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT             2
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK              0x00000030
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT             4
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK              0x000000c0
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT             6
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK              0x00000300
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT             8
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK              0x00000c00
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT             10
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK              0x00003000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT             12
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK              0x0000c000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT             14
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK              0x00030000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT             16
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK              0x000c0000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT             18
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x)                 (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK             0x00300000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT            20
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK             0x00c00000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT            22
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK             0x03000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT            24
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK             0x0c000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT            26
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK             0x30000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT            28
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK)
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK             0xc0000000
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT            30
> +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x)                        (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK)
> +
> +#define VIVS_GL_UNK03834                                       0x00003834
> +
> +#define VIVS_GL_UNK03838                                       0x00003838
> +
> +#define VIVS_GL_API_MODE                                       0x0000384c
> +#define VIVS_GL_API_MODE_OPENGL                                        0x00000000
> +#define VIVS_GL_API_MODE_OPENVG                                        0x00000001
> +#define VIVS_GL_API_MODE_OPENCL                                        0x00000002
> +
> +#define VIVS_GL_CONTEXT_POINTER                                        0x00003850
> +
> +#define VIVS_GL_UNK03A00                                       0x00003a00
> +
> +#define VIVS_GL_STALL_TOKEN                                    0x00003c00
> +#define VIVS_GL_STALL_TOKEN_FROM__MASK                         0x0000001f
> +#define VIVS_GL_STALL_TOKEN_FROM__SHIFT                                0
> +#define VIVS_GL_STALL_TOKEN_FROM(x)                            (((x) << VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK)
> +#define VIVS_GL_STALL_TOKEN_TO__MASK                           0x00001f00
> +#define VIVS_GL_STALL_TOKEN_TO__SHIFT                          8
> +#define VIVS_GL_STALL_TOKEN_TO(x)                              (((x) << VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK)
> +#define VIVS_GL_STALL_TOKEN_FLIP0                              0x40000000
> +#define VIVS_GL_STALL_TOKEN_FLIP1                              0x80000000
> +
> +#define VIVS_DUMMY                                             0x00000000
> +
> +#define VIVS_DUMMY_DUMMY                                       0x0003fffc
> +
> +
> +#endif /* STATE_XML */
> diff --git a/drivers/staging/etnaviv/state_hi.xml.h b/drivers/staging/etnaviv/state_hi.xml.h
> new file mode 100644
> index 000000000000..0064f2640396
> --- /dev/null
> +++ b/drivers/staging/etnaviv/state_hi.xml.h
> @@ -0,0 +1,407 @@
> +#ifndef STATE_HI_XML
> +#define STATE_HI_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_hi.xml (  23420 bytes, from 2015-03-25 11:47:21)
> +- common.xml   (  18437 bytes, from 2015-03-25 11:27:41)
> +
> +Copyright (C) 2015
> +*/
> +
> +
> +#define MMU_EXCEPTION_SLAVE_NOT_PRESENT                                0x00000001
> +#define MMU_EXCEPTION_PAGE_NOT_PRESENT                         0x00000002
> +#define MMU_EXCEPTION_WRITE_VIOLATION                          0x00000003
> +#define VIVS_HI                                                        0x00000000
> +
> +#define VIVS_HI_CLOCK_CONTROL                                  0x00000000
> +#define VIVS_HI_CLOCK_CONTROL_CLK3D_DIS                                0x00000001
> +#define VIVS_HI_CLOCK_CONTROL_CLK2D_DIS                                0x00000002
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK                 0x000001fc
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT                        2
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(x)                    (((x) << VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT) & VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK)
> +#define VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD                  0x00000200
> +#define VIVS_HI_CLOCK_CONTROL_DISABLE_RAM_CLK_GATING           0x00000400
> +#define VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS          0x00000800
> +#define VIVS_HI_CLOCK_CONTROL_SOFT_RESET                       0x00001000
> +#define VIVS_HI_CLOCK_CONTROL_IDLE_3D                          0x00010000
> +#define VIVS_HI_CLOCK_CONTROL_IDLE_2D                          0x00020000
> +#define VIVS_HI_CLOCK_CONTROL_IDLE_VG                          0x00040000
> +#define VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU                      0x00080000
> +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK           0x00f00000
> +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT          20
> +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(x)              (((x) << VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT) & VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK)
> +
> +#define VIVS_HI_IDLE_STATE                                     0x00000004
> +#define VIVS_HI_IDLE_STATE_FE                                  0x00000001
> +#define VIVS_HI_IDLE_STATE_DE                                  0x00000002
> +#define VIVS_HI_IDLE_STATE_PE                                  0x00000004
> +#define VIVS_HI_IDLE_STATE_SH                                  0x00000008
> +#define VIVS_HI_IDLE_STATE_PA                                  0x00000010
> +#define VIVS_HI_IDLE_STATE_SE                                  0x00000020
> +#define VIVS_HI_IDLE_STATE_RA                                  0x00000040
> +#define VIVS_HI_IDLE_STATE_TX                                  0x00000080
> +#define VIVS_HI_IDLE_STATE_VG                                  0x00000100
> +#define VIVS_HI_IDLE_STATE_IM                                  0x00000200
> +#define VIVS_HI_IDLE_STATE_FP                                  0x00000400
> +#define VIVS_HI_IDLE_STATE_TS                                  0x00000800
> +#define VIVS_HI_IDLE_STATE_AXI_LP                              0x80000000
> +
> +#define VIVS_HI_AXI_CONFIG                                     0x00000008
> +#define VIVS_HI_AXI_CONFIG_AWID__MASK                          0x0000000f
> +#define VIVS_HI_AXI_CONFIG_AWID__SHIFT                         0
> +#define VIVS_HI_AXI_CONFIG_AWID(x)                             (((x) << VIVS_HI_AXI_CONFIG_AWID__SHIFT) & VIVS_HI_AXI_CONFIG_AWID__MASK)
> +#define VIVS_HI_AXI_CONFIG_ARID__MASK                          0x000000f0
> +#define VIVS_HI_AXI_CONFIG_ARID__SHIFT                         4
> +#define VIVS_HI_AXI_CONFIG_ARID(x)                             (((x) << VIVS_HI_AXI_CONFIG_ARID__SHIFT) & VIVS_HI_AXI_CONFIG_ARID__MASK)
> +#define VIVS_HI_AXI_CONFIG_AWCACHE__MASK                       0x00000f00
> +#define VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT                      8
> +#define VIVS_HI_AXI_CONFIG_AWCACHE(x)                          (((x) << VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_AWCACHE__MASK)
> +#define VIVS_HI_AXI_CONFIG_ARCACHE__MASK                       0x0000f000
> +#define VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT                      12
> +#define VIVS_HI_AXI_CONFIG_ARCACHE(x)                          (((x) << VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_ARCACHE__MASK)
> +
> +#define VIVS_HI_AXI_STATUS                                     0x0000000c
> +#define VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK                     0x0000000f
> +#define VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT                    0
> +#define VIVS_HI_AXI_STATUS_WR_ERR_ID(x)                                (((x) << VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK)
> +#define VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK                     0x000000f0
> +#define VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT                    4
> +#define VIVS_HI_AXI_STATUS_RD_ERR_ID(x)                                (((x) << VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK)
> +#define VIVS_HI_AXI_STATUS_DET_WR_ERR                          0x00000100
> +#define VIVS_HI_AXI_STATUS_DET_RD_ERR                          0x00000200
> +
> +#define VIVS_HI_INTR_ACKNOWLEDGE                               0x00000010
> +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK                        0x7fffffff
> +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT               0
> +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC(x)                   (((x) << VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT) & VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK)
> +#define VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR                 0x80000000
> +
> +#define VIVS_HI_INTR_ENBL                                      0x00000014
> +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK                  0xffffffff
> +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT                 0
> +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC(x)                     (((x) << VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT) & VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK)
> +
> +#define VIVS_HI_CHIP_IDENTITY                                  0x00000018
> +#define VIVS_HI_CHIP_IDENTITY_FAMILY__MASK                     0xff000000
> +#define VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT                    24
> +#define VIVS_HI_CHIP_IDENTITY_FAMILY(x)                                (((x) << VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT) & VIVS_HI_CHIP_IDENTITY_FAMILY__MASK)
> +#define VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK                    0x00ff0000
> +#define VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT                   16
> +#define VIVS_HI_CHIP_IDENTITY_PRODUCT(x)                       (((x) << VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT) & VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK)
> +#define VIVS_HI_CHIP_IDENTITY_REVISION__MASK                   0x0000f000
> +#define VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT                  12
> +#define VIVS_HI_CHIP_IDENTITY_REVISION(x)                      (((x) << VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT) & VIVS_HI_CHIP_IDENTITY_REVISION__MASK)
> +
> +#define VIVS_HI_CHIP_FEATURE                                   0x0000001c
> +
> +#define VIVS_HI_CHIP_MODEL                                     0x00000020
> +
> +#define VIVS_HI_CHIP_REV                                       0x00000024
> +
> +#define VIVS_HI_CHIP_DATE                                      0x00000028
> +
> +#define VIVS_HI_CHIP_TIME                                      0x0000002c
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_0                           0x00000034
> +
> +#define VIVS_HI_CACHE_CONTROL                                  0x00000038
> +
> +#define VIVS_HI_MEMORY_COUNTER_RESET                           0x0000003c
> +
> +#define VIVS_HI_PROFILE_READ_BYTES8                            0x00000040
> +
> +#define VIVS_HI_PROFILE_WRITE_BYTES8                           0x00000044
> +
> +#define VIVS_HI_CHIP_SPECS                                     0x00000048
> +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK                  0x0000000f
> +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT                 0
> +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT(x)                     (((x) << VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK                  0x000000f0
> +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT                 4
> +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX(x)                     (((x) << VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT) & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
> +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK                  0x00000f00
> +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT                 8
> +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT(x)                     (((x) << VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK             0x0001f000
> +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT            12
> +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE(x)                        (((x) << VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
> +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK             0x01f00000
> +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT            20
> +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT(x)                        (((x) << VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK                   0x0e000000
> +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT                  25
> +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES(x)                      (((x) << VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT) & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
> +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK     0xf0000000
> +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT    28
> +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE(x)                (((x) << VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
> +
> +#define VIVS_HI_PROFILE_WRITE_BURSTS                           0x0000004c
> +
> +#define VIVS_HI_PROFILE_WRITE_REQUESTS                         0x00000050
> +
> +#define VIVS_HI_PROFILE_READ_BURSTS                            0x00000058
> +
> +#define VIVS_HI_PROFILE_READ_REQUESTS                          0x0000005c
> +
> +#define VIVS_HI_PROFILE_READ_LASTS                             0x00000060
> +
> +#define VIVS_HI_GP_OUT0                                                0x00000064
> +
> +#define VIVS_HI_GP_OUT1                                                0x00000068
> +
> +#define VIVS_HI_GP_OUT2                                                0x0000006c
> +
> +#define VIVS_HI_AXI_CONTROL                                    0x00000070
> +#define VIVS_HI_AXI_CONTROL_WR_FULL_BURST_MODE                 0x00000001
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_1                           0x00000074
> +
> +#define VIVS_HI_PROFILE_TOTAL_CYCLES                           0x00000078
> +
> +#define VIVS_HI_PROFILE_IDLE_CYCLES                            0x0000007c
> +
> +#define VIVS_HI_CHIP_SPECS_2                                   0x00000080
> +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK                 0x000000ff
> +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT                        0
> +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE(x)                    (((x) << VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
> +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK           0x0000ff00
> +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT          8
> +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT(x)              (((x) << VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
> +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK               0xffff0000
> +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT              16
> +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS(x)                  (((x) << VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT) & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_2                           0x00000084
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_3                           0x00000088
> +
> +#define VIVS_HI_CHIP_MINOR_FEATURE_4                           0x00000094
> +
> +#define VIVS_PM                                                        0x00000000
> +
> +#define VIVS_PM_POWER_CONTROLS                                 0x00000100
> +#define VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING      0x00000001
> +#define VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING       0x00000002
> +#define VIVS_PM_POWER_CONTROLS_DISABLE_STARVE_MODULE_CLOCK_GATING      0x00000004
> +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK           0x000000f0
> +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT          4
> +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER(x)              (((x) << VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK)
> +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK          0xffff0000
> +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT         16
> +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER(x)             (((x) << VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK)
> +
> +#define VIVS_PM_MODULE_CONTROLS                                        0x00000104
> +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_FE 0x00000001
> +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_DE 0x00000002
> +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_PE 0x00000004
> +
> +#define VIVS_PM_MODULE_STATUS                                  0x00000108
> +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_FE            0x00000001
> +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_DE            0x00000002
> +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_PE            0x00000004
> +
> +#define VIVS_PM_PULSE_EATER                                    0x0000010c
> +
> +#define VIVS_MMUv2                                             0x00000000
> +
> +#define VIVS_MMUv2_SAFE_ADDRESS                                        0x00000180
> +
> +#define VIVS_MMUv2_CONFIGURATION                               0x00000184
> +#define VIVS_MMUv2_CONFIGURATION_MODE__MASK                    0x00000001
> +#define VIVS_MMUv2_CONFIGURATION_MODE__SHIFT                   0
> +#define VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K                  0x00000000
> +#define VIVS_MMUv2_CONFIGURATION_MODE_MODE1_K                  0x00000001
> +#define VIVS_MMUv2_CONFIGURATION_MODE_MASK                     0x00000008
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH__MASK                   0x00000010
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH__SHIFT                  4
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH_FLUSH                   0x00000010
> +#define VIVS_MMUv2_CONFIGURATION_FLUSH_MASK                    0x00000080
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS_MASK                  0x00000100
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK                 0xfffffc00
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT                        10
> +#define VIVS_MMUv2_CONFIGURATION_ADDRESS(x)                    (((x) << VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT) & VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK)
> +
> +#define VIVS_MMUv2_STATUS                                      0x00000188
> +#define VIVS_MMUv2_STATUS_EXCEPTION0__MASK                     0x00000003
> +#define VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT                    0
> +#define VIVS_MMUv2_STATUS_EXCEPTION0(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK)
> +#define VIVS_MMUv2_STATUS_EXCEPTION1__MASK                     0x00000030
> +#define VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT                    4
> +#define VIVS_MMUv2_STATUS_EXCEPTION1(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION1__MASK)
> +#define VIVS_MMUv2_STATUS_EXCEPTION2__MASK                     0x00000300
> +#define VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT                    8
> +#define VIVS_MMUv2_STATUS_EXCEPTION2(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION2__MASK)
> +#define VIVS_MMUv2_STATUS_EXCEPTION3__MASK                     0x00003000
> +#define VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT                    12
> +#define VIVS_MMUv2_STATUS_EXCEPTION3(x)                                (((x) << VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION3__MASK)
> +
> +#define VIVS_MMUv2_CONTROL                                     0x0000018c
> +#define VIVS_MMUv2_CONTROL_ENABLE                              0x00000001
> +
> +#define VIVS_MMUv2_EXCEPTION_ADDR(i0)                         (0x00000190 + 0x4*(i0))
> +#define VIVS_MMUv2_EXCEPTION_ADDR__ESIZE                       0x00000004
> +#define VIVS_MMUv2_EXCEPTION_ADDR__LEN                         0x00000004
> +
> +#define VIVS_MC                                                        0x00000000
> +
> +#define VIVS_MC_MMU_FE_PAGE_TABLE                              0x00000400
> +
> +#define VIVS_MC_MMU_TX_PAGE_TABLE                              0x00000404
> +
> +#define VIVS_MC_MMU_PE_PAGE_TABLE                              0x00000408
> +
> +#define VIVS_MC_MMU_PEZ_PAGE_TABLE                             0x0000040c
> +
> +#define VIVS_MC_MMU_RA_PAGE_TABLE                              0x00000410
> +
> +#define VIVS_MC_DEBUG_MEMORY                                   0x00000414
> +#define VIVS_MC_DEBUG_MEMORY_SPECIAL_PATCH_GC320               0x00000008
> +#define VIVS_MC_DEBUG_MEMORY_FAST_CLEAR_BYPASS                 0x00100000
> +#define VIVS_MC_DEBUG_MEMORY_COMPRESSION_BYPASS                        0x00200000
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_RA                            0x00000418
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_FE                            0x0000041c
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_TX                            0x00000420
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_PEZ                           0x00000424
> +
> +#define VIVS_MC_MEMORY_BASE_ADDR_PE                            0x00000428
> +
> +#define VIVS_MC_MEMORY_TIMING_CONTROL                          0x0000042c
> +
> +#define VIVS_MC_MEMORY_FLUSH                                   0x00000430
> +
> +#define VIVS_MC_PROFILE_CYCLE_COUNTER                          0x00000438
> +
> +#define VIVS_MC_DEBUG_READ0                                    0x0000043c
> +
> +#define VIVS_MC_DEBUG_READ1                                    0x00000440
> +
> +#define VIVS_MC_DEBUG_WRITE                                    0x00000444
> +
> +#define VIVS_MC_PROFILE_RA_READ                                        0x00000448
> +
> +#define VIVS_MC_PROFILE_TX_READ                                        0x0000044c
> +
> +#define VIVS_MC_PROFILE_FE_READ                                        0x00000450
> +
> +#define VIVS_MC_PROFILE_PE_READ                                        0x00000454
> +
> +#define VIVS_MC_PROFILE_DE_READ                                        0x00000458
> +
> +#define VIVS_MC_PROFILE_SH_READ                                        0x0000045c
> +
> +#define VIVS_MC_PROFILE_PA_READ                                        0x00000460
> +
> +#define VIVS_MC_PROFILE_SE_READ                                        0x00000464
> +
> +#define VIVS_MC_PROFILE_MC_READ                                        0x00000468
> +
> +#define VIVS_MC_PROFILE_HI_READ                                        0x0000046c
> +
> +#define VIVS_MC_PROFILE_CONFIG0                                        0x00000470
> +#define VIVS_MC_PROFILE_CONFIG0_FE__MASK                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG0_FE__SHIFT                      0
> +#define VIVS_MC_PROFILE_CONFIG0_FE_RESET                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG0_DE__MASK                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG0_DE__SHIFT                      8
> +#define VIVS_MC_PROFILE_CONFIG0_DE_RESET                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG0_PE__MASK                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG0_PE__SHIFT                      16
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE    0x00000000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE    0x00010000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE     0x00020000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE     0x00030000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D          0x000b0000
> +#define VIVS_MC_PROFILE_CONFIG0_PE_RESET                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG0_SH__MASK                       0x0f000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH__SHIFT                      24
> +#define VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES               0x04000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER             0x07000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER      0x08000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER             0x09000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER    0x0a000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER     0x0b000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER      0x0c000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER     0x0d000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER      0x0e000000
> +#define VIVS_MC_PROFILE_CONFIG0_SH_RESET                       0x0f000000
> +
> +#define VIVS_MC_PROFILE_CONFIG1                                        0x00000474
> +#define VIVS_MC_PROFILE_CONFIG1_PA__MASK                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG1_PA__SHIFT                      0
> +#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER           0x00000003
> +#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER          0x00000004
> +#define VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER         0x00000005
> +#define VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER       0x00000006
> +#define VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER    0x00000007
> +#define VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER              0x00000008
> +#define VIVS_MC_PROFILE_CONFIG1_PA_RESET                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG1_SE__MASK                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG1_SE__SHIFT                      8
> +#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT       0x00000000
> +#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT          0x00000100
> +#define VIVS_MC_PROFILE_CONFIG1_SE_RESET                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG1_RA__MASK                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG1_RA__SHIFT                      16
> +#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT           0x00000000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT            0x00010000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z      0x00020000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT       0x00030000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER     0x00090000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER 0x000a0000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT           0x000b0000
> +#define VIVS_MC_PROFILE_CONFIG1_RA_RESET                       0x000f0000
> +#define VIVS_MC_PROFILE_CONFIG1_TX__MASK                       0x0f000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX__SHIFT                      24
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS     0x00000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS    0x01000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS    0x02000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS      0x03000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_UNKNOWN                     0x04000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT              0x05000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT                0x06000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT            0x07000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT       0x08000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT      0x09000000
> +#define VIVS_MC_PROFILE_CONFIG1_TX_RESET                       0x0f000000
> +
> +#define VIVS_MC_PROFILE_CONFIG2                                        0x00000478
> +#define VIVS_MC_PROFILE_CONFIG2_MC__MASK                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG2_MC__SHIFT                      0
> +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE     0x00000001
> +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP   0x00000002
> +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE    0x00000003
> +#define VIVS_MC_PROFILE_CONFIG2_MC_RESET                       0x0000000f
> +#define VIVS_MC_PROFILE_CONFIG2_HI__MASK                       0x00000f00
> +#define VIVS_MC_PROFILE_CONFIG2_HI__SHIFT                      8
> +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED     0x00000000
> +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED    0x00000100
> +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED       0x00000200
> +#define VIVS_MC_PROFILE_CONFIG2_HI_RESET                       0x00000f00
> +
> +#define VIVS_MC_PROFILE_CONFIG3                                        0x0000047c
> +
> +#define VIVS_MC_BUS_CONFIG                                     0x00000480
> +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK                 0x0000000f
> +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT                        0
> +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(x)                    (((x) << VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK)
> +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK                 0x000000f0
> +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT                        4
> +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(x)                    (((x) << VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK)
> +
> +#define VIVS_MC_START_COMPOSITION                              0x00000554
> +
> +#define VIVS_MC_128B_MERGE                                     0x00000558
> +
> +
> +#endif /* STATE_HI_XML */
> diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
> new file mode 100644
> index 000000000000..5f1206b3f9ba
> --- /dev/null
> +++ b/include/uapi/drm/etnaviv_drm.h
> @@ -0,0 +1,215 @@
> +/*
> + * 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_DRM_H__
> +#define __ETNAVIV_DRM_H__
> +
> +#include <drm/drm.h>
> +
> +/* Please note that modifications to all structs defined here are
> + * subject to backwards-compatibility constraints:
> + *  1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
> + *     user/kernel compatibility
> + *  2) Keep fields aligned to their size
> + *  3) Because of how drm_ioctl() works, we can add new fields at
> + *     the end of an ioctl if some care is taken: drm_ioctl() will
> + *     zero out the new fields at the tail of the ioctl, so a zero
> + *     value should have a backwards compatible meaning.  And for
> + *     output params, userspace won't see the newly added output
> + *     fields.. so that has to be somehow ok.
> + */
> +
> +/* timeouts are specified in clock-monotonic absolute times (to simplify
> + * restarting interrupted ioctls).  The following struct is logically the
> + * same as 'struct timespec' but 32/64b ABI safe.
> + */
> +struct drm_etnaviv_timespec {
> +       __s64 tv_sec;          /* seconds */
> +       __s64 tv_nsec;         /* nanoseconds */
> +};
> +
> +#define ETNAVIV_PARAM_GPU_MODEL                     0x01
> +#define ETNAVIV_PARAM_GPU_REVISION                  0x02
> +#define ETNAVIV_PARAM_GPU_FEATURES_0                0x03
> +#define ETNAVIV_PARAM_GPU_FEATURES_1                0x04
> +#define ETNAVIV_PARAM_GPU_FEATURES_2                0x05
> +#define ETNAVIV_PARAM_GPU_FEATURES_3                0x06
> +#define ETNAVIV_PARAM_GPU_FEATURES_4                0x07
> +
> +#define ETNAVIV_PARAM_GPU_STREAM_COUNT              0x10
> +#define ETNAVIV_PARAM_GPU_REGISTER_MAX              0x11
> +#define ETNAVIV_PARAM_GPU_THREAD_COUNT              0x12
> +#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE         0x13
> +#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT         0x14
> +#define ETNAVIV_PARAM_GPU_PIXEL_PIPES               0x15
> +#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16
> +#define ETNAVIV_PARAM_GPU_BUFFER_SIZE               0x17
> +#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT         0x18
> +#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS             0x19
> +
> +#define ETNA_MAX_PIPES 4
> +
> +struct drm_etnaviv_param {
> +       __u32 pipe;           /* in */
> +       __u32 param;          /* in, ETNAVIV_PARAM_x */
> +       __u64 value;          /* out (get_param) or in (set_param) */
> +};
> +
> +/*
> + * GEM buffers:
> + */
> +
> +#define ETNA_BO_CACHE_MASK   0x000f0000
> +/* cache modes */
> +#define ETNA_BO_CACHED       0x00010000
> +#define ETNA_BO_WC           0x00020000
> +#define ETNA_BO_UNCACHED     0x00040000
> +/* map flags */
> +#define ETNA_BO_FORCE_MMU    0x00100000
> +
> +struct drm_etnaviv_gem_new {
> +       __u64 size;           /* in */
> +       __u32 flags;          /* in, mask of ETNA_BO_x */
> +       __u32 handle;         /* out */
> +};
> +
> +struct drm_etnaviv_gem_info {
> +       __u32 handle;         /* in */
> +       __u32 pad;
> +       __u64 offset;         /* out, offset to pass to mmap() */
> +};
> +
> +#define ETNA_PREP_READ        0x01
> +#define ETNA_PREP_WRITE       0x02
> +#define ETNA_PREP_NOSYNC      0x04
> +
> +struct drm_etnaviv_gem_cpu_prep {
> +       __u32 handle;         /* in */
> +       __u32 op;             /* in, mask of ETNA_PREP_x */
> +       struct drm_etnaviv_timespec timeout;   /* in */
> +};
> +
> +struct drm_etnaviv_gem_cpu_fini {
> +       __u32 handle;         /* in */
> +};
> +
> +/*
> + * Cmdstream Submission:
> + */
> +
> +/* The value written into the cmdstream is logically:
> + * relocbuf->gpuaddr + reloc_offset
> + *
> + * NOTE that reloc's must be sorted by order of increasing submit_offset,
> + * otherwise EINVAL.
> + */
> +struct drm_etnaviv_gem_submit_reloc {
> +       __u32 submit_offset;  /* in, offset from submit_bo */
> +       __u32 reloc_idx;      /* in, index of reloc_bo buffer */
> +       __u64 reloc_offset;   /* in, offset from start of reloc_bo */
> +};
> +
> +/* Each buffer referenced elsewhere in the cmdstream submit (ie. the
> + * cmdstream buffer(s) themselves or reloc entries) has one (and only
> + * one) entry in the submit->bos[] table.
> + *
> + * As a optimization, the current buffer (gpu virtual address) can be
> + * passed back through the 'presumed' field.  If on a subsequent reloc,
> + * userspace passes back a 'presumed' address that is still valid,
> + * then patching the cmdstream for this entry is skipped.  This can
> + * avoid kernel needing to map/access the cmdstream bo in the common
> + * case.
> + */
> +#define ETNA_SUBMIT_BO_READ             0x0001
> +#define ETNA_SUBMIT_BO_WRITE            0x0002
> +struct drm_etnaviv_gem_submit_bo {
> +       __u32 flags;          /* in, mask of ETNA_SUBMIT_BO_x */
> +       __u32 handle;         /* in, GEM handle */
> +       __u64 presumed;       /* in/out, presumed buffer address */
> +};
> +=

As presumed never gets used in the driver itself and I am not a big fan of it,
can we remove it? Do you see any usecase for it?


> +/* Each cmdstream submit consists of a table of buffers involved, and
> + * one or more cmdstream buffers.  This allows for conditional execution
> + * (context-restore), and IB buffers needed for per tile/bin draw cmds.
> + */
> +#define ETNA_PIPE_3D      0x00
> +#define ETNA_PIPE_2D      0x01
> +#define ETNA_PIPE_VG      0x02
> +struct drm_etnaviv_gem_submit {
> +       __u32 fence;          /* out */
> +       __u32 pipe;           /* in */
> +       __u32 exec_state;     /* in, initial execution state (ETNA_PIPE_x) */
> +       __u32 nr_bos;         /* in, number of submit_bo's */
> +       __u32 nr_relocs;      /* in, number of submit_reloc's */
> +       __u32 stream_size;    /* in, cmdstream size */
> +       __u64 bos;            /* in, ptr to array of submit_bo's */
> +       __u64 relocs;         /* in, ptr to array of submit_reloc's */
> +       __u64 stream;         /* in, ptr to cmdstream */
> +};
> +
> +/* The normal way to synchronize with the GPU is just to CPU_PREP on
> + * a buffer if you need to access it from the CPU (other cmdstream
> + * submission from same or other contexts, PAGE_FLIP ioctl, etc, all
> + * handle the required synchronization under the hood).  This ioctl
> + * mainly just exists as a way to implement the gallium pipe_fence
> + * APIs without requiring a dummy bo to synchronize on.
> + */
> +struct drm_etnaviv_wait_fence {
> +       __u32 pipe;           /* in */
> +       __u32 fence;          /* in */
> +       struct drm_etnaviv_timespec timeout;   /* in */
> +};
> +
> +#define ETNA_USERPTR_READ      0x01
> +#define ETNA_USERPTR_WRITE     0x02
> +struct drm_etnaviv_gem_userptr {
> +       __u64 user_ptr; /* in, page aligned user pointer */
> +       __u64 user_size;        /* in, page aligned user size */
> +       __u32 flags;            /* in, flags */
> +       __u32 handle;   /* out, non-zero handle */
> +};
> +
> +struct drm_etnaviv_gem_wait {
> +       __u32 pipe;                             /* in */
> +       __u32 handle;                           /* in, bo to be waited for */
> +       struct drm_etnaviv_timespec timeout;    /* in */
> +};
> +
> +#define DRM_ETNAVIV_GET_PARAM          0x00
> +/* placeholder:
> +#define DRM_ETNAVIV_SET_PARAM          0x01
> + */
> +#define DRM_ETNAVIV_GEM_NEW            0x02
> +#define DRM_ETNAVIV_GEM_INFO           0x03
> +#define DRM_ETNAVIV_GEM_CPU_PREP       0x04
> +#define DRM_ETNAVIV_GEM_CPU_FINI       0x05
> +#define DRM_ETNAVIV_GEM_SUBMIT         0x06
> +#define DRM_ETNAVIV_WAIT_FENCE         0x07
> +#define DRM_ETNAVIV_GEM_USERPTR        0x08
> +#define DRM_ETNAVIV_GEM_WAIT           0x09
> +#define DRM_ETNAVIV_NUM_IOCTLS         0x0a
> +
> +#define DRM_IOCTL_ETNAVIV_GET_PARAM    DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
> +#define DRM_IOCTL_ETNAVIV_GEM_NEW      DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
> +#define DRM_IOCTL_ETNAVIV_GEM_INFO     DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info)
> +#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep)
> +#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini)
> +#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT   DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit)
> +#define DRM_IOCTL_ETNAVIV_WAIT_FENCE   DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
> +#define DRM_IOCTL_ETNAVIV_GEM_USERPTR  DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
> +#define DRM_IOCTL_ETNAVIV_GEM_WAIT     DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
> +
> +#endif /* __ETNAVIV_DRM_H__ */
> --
> 2.5.0
>

Greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-16  6:11   ` Christian Gmeiner
@ 2015-09-16  7:49     ` Russell King - ARM Linux
  2015-09-16 15:30     ` Lucas Stach
  1 sibling, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-09-16  7:49 UTC (permalink / raw)
  To: Christian Gmeiner; +Cc: Sascha Hauer, DRI mailing list

On Wed, Sep 16, 2015 at 08:11:54AM +0200, Christian Gmeiner wrote:
> Hi Lucas
> 
> 
> 2015-09-11 16:10 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> > From: Christian Gmeiner <christian.gmeiner@gmail.com>
> >
> > This is a squashed commit of the complete etnaviv DRM driver in order
> > to make it easy for people to review the code by seeing the driver as a
> > whole and is not intended for merging in this form.
> >
> > If you are interested in the history of individual commits:
> > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> >
> > 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>
> > ---

[ cut thousands of lines ]

If there was some comments in this, I don't know where they are.  Expecting
people to read through thousands of lines to find where you've commented
is unreasonable.  Please trim appropriately, according to standard email
etiquette.  (it also helps to get this patch through mailing lists as it
then won't hit the size filters, and moderators don't have to keep
approving stuff.)

Thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-14 13:16   ` Rob Clark
@ 2015-09-16  7:56     ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-09-16  7:56 UTC (permalink / raw)
  To: Rob Clark; +Cc: kernel, dri-devel

On Mon, Sep 14, 2015 at 09:16:01AM -0400, Rob Clark wrote:
> On Fri, Sep 11, 2015 at 10:10 AM, Lucas Stach <l.stach@pengutronix.de> wrote:
> > From: Christian Gmeiner <christian.gmeiner@gmail.com>
> >
> > This is a squashed commit of the complete etnaviv DRM driver in order
> > to make it easy for people to review the code by seeing the driver as a
> > whole and is not intended for merging in this form.
> >
> > If you are interested in the history of individual commits:
> > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> >
> > 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>
> > ---
> >  drivers/staging/Kconfig                      |    2 +
> >  drivers/staging/Makefile                     |    1 +
> >  drivers/staging/etnaviv/Kconfig              |   20 +
> >  drivers/staging/etnaviv/Makefile             |   18 +
> >  drivers/staging/etnaviv/cmdstream.xml.h      |  218 ++++
> >  drivers/staging/etnaviv/common.xml.h         |  249 +++++
> >  drivers/staging/etnaviv/etnaviv_buffer.c     |  271 +++++
> >  drivers/staging/etnaviv/etnaviv_cmd_parser.c |  119 +++
> >  drivers/staging/etnaviv/etnaviv_drv.c        |  705 +++++++++++++
> >  drivers/staging/etnaviv/etnaviv_drv.h        |  138 +++
> >  drivers/staging/etnaviv/etnaviv_gem.c        |  887 ++++++++++++++++
> >  drivers/staging/etnaviv/etnaviv_gem.h        |  141 +++
> >  drivers/staging/etnaviv/etnaviv_gem_prime.c  |  121 +++
> >  drivers/staging/etnaviv/etnaviv_gem_submit.c |  421 ++++++++
> >  drivers/staging/etnaviv/etnaviv_gpu.c        | 1468 ++++++++++++++++++++++++++
> >  drivers/staging/etnaviv/etnaviv_gpu.h        |  198 ++++
> >  drivers/staging/etnaviv/etnaviv_iommu.c      |  221 ++++
> >  drivers/staging/etnaviv/etnaviv_iommu.h      |   28 +
> >  drivers/staging/etnaviv/etnaviv_iommu_v2.c   |   33 +
> >  drivers/staging/etnaviv/etnaviv_iommu_v2.h   |   25 +
> >  drivers/staging/etnaviv/etnaviv_mmu.c        |  282 +++++
> >  drivers/staging/etnaviv/etnaviv_mmu.h        |   58 +
> >  drivers/staging/etnaviv/state.xml.h          |  351 ++++++
> >  drivers/staging/etnaviv/state_hi.xml.h       |  407 +++++++
> >  include/uapi/drm/etnaviv_drm.h               |  215 ++++
> >  25 files changed, 6597 insertions(+)
> >  create mode 100644 drivers/staging/etnaviv/Kconfig
> >  create mode 100644 drivers/staging/etnaviv/Makefile
> >  create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h
> >  create mode 100644 drivers/staging/etnaviv/common.xml.h
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c
> >  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h
> >  create mode 100644 drivers/staging/etnaviv/state.xml.h
> >  create mode 100644 drivers/staging/etnaviv/state_hi.xml.h
> >  create mode 100644 include/uapi/drm/etnaviv_drm.h
> >
> > diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> > index 7f6cae5beb90..5446fe4859ce 100644
> > --- a/drivers/staging/Kconfig
> > +++ b/drivers/staging/Kconfig
> > @@ -112,4 +112,6 @@ source "drivers/staging/fsl-mc/Kconfig"
> >
> >  source "drivers/staging/wilc1000/Kconfig"
> >
> > +source "drivers/staging/etnaviv/Kconfig"
> > +
> >  endif # STAGING
> > diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> > index 347f6477aa3e..9fd3c06b6bfd 100644
> > --- a/drivers/staging/Makefile
> > +++ b/drivers/staging/Makefile
> > @@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
> >  obj-$(CONFIG_FB_TFT)           += fbtft/
> >  obj-$(CONFIG_FSL_MC_BUS)       += fsl-mc/
> >  obj-$(CONFIG_WILC1000)         += wilc1000/
> > +obj-$(CONFIG_DRM_ETNAVIV)      += etnaviv/
> > diff --git a/drivers/staging/etnaviv/Kconfig b/drivers/staging/etnaviv/Kconfig
> > new file mode 100644
> > index 000000000000..6f034eda914c
> > --- /dev/null
> > +++ b/drivers/staging/etnaviv/Kconfig
> > @@ -0,0 +1,20 @@
> > +
> > +config DRM_ETNAVIV
> > +       tristate "etnaviv DRM"
> > +       depends on DRM
> > +       select SHMEM
> > +       select TMPFS
> > +       select IOMMU_API
> > +       select IOMMU_SUPPORT
> > +       default y
> > +       help
> > +         DRM driver for Vivante GPUs.
> > +
> > +config DRM_ETNAVIV_REGISTER_LOGGING
> > +       bool "etnaviv DRM register logging"
> > +       depends on DRM_ETNAVIV
> > +       default n
> > +       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.
> 
> heh, ok, didn't realize anyone else was using demsm..  I guess that is
> one of the things that I should clean up and get into upstream
> envytools tree.  (And maybe come up with a better name.. if anyone has
> any suggestions..)

Do you think you can learn to trim your replies.  You are being
completely unreasonable here - leaving thousands of lines which are
not relevant to your reply still attached.  Not only is it a waste of
bandwidth, but it bloats people's mailboxes needlessly.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-11 14:10 ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Lucas Stach
  2015-09-14 13:16   ` Rob Clark
  2015-09-16  6:11   ` Christian Gmeiner
@ 2015-09-16  8:04   ` Russell King - ARM Linux
  2015-09-16 10:42     ` Christian Gmeiner
                       ` (2 more replies)
  2015-09-16 15:05   ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Eric Anholt
  3 siblings, 3 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-09-16  8:04 UTC (permalink / raw)
  To: Lucas Stach; +Cc: kernel, dri-devel

On Fri, Sep 11, 2015 at 04:10:13PM +0200, Lucas Stach wrote:
> From: Christian Gmeiner <christian.gmeiner@gmail.com>
> 
> This is a squashed commit of the complete etnaviv DRM driver in order
> to make it easy for people to review the code by seeing the driver as a
> whole and is not intended for merging in this form.
> 
> If you are interested in the history of individual commits:
> git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> 
> 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>

Lucas,

I know that the previous round, people said that they didn't like the
individual patches posted, but squashing everything together into one
patch is also not good.

It would make more sense (at least for me) if you squashed the work
that has already been done into one patch, and then post your updates
as individual patches.  That way, Christian and myself can see what
the changes are against some known without having to dig through your
git tree, and those who complained about all the patches last time
have fewer patches to look at.

Expecting those in the project to page through thousands of lines that
they already know about, hoping to spot the changes you've made is
really very unreasonable and error prone.  I will _NOT_ be wasting my
time reviewing this mega-patch exactly because of that.

I _might_, if I get time, pull a copy of your git tree to look at the
individual patches, but I'm not going to reply quoting bits of this
patch - I may reply with comments but without any context.

Sorry.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-16  8:04   ` Russell King - ARM Linux
@ 2015-09-16 10:42     ` Christian Gmeiner
  2015-09-16 15:36     ` Lucas Stach
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
  2 siblings, 0 replies; 100+ messages in thread
From: Christian Gmeiner @ 2015-09-16 10:42 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: Sascha Hauer, DRI mailing list

2015-09-16 10:04 GMT+02:00 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Fri, Sep 11, 2015 at 04:10:13PM +0200, Lucas Stach wrote:
>> From: Christian Gmeiner <christian.gmeiner@gmail.com>
>>
>> This is a squashed commit of the complete etnaviv DRM driver in order
>> to make it easy for people to review the code by seeing the driver as a
>> whole and is not intended for merging in this form.
>>
>> If you are interested in the history of individual commits:
>> git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
>>
>> 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>
>
> Lucas,
>
> I know that the previous round, people said that they didn't like the
> individual patches posted, but squashing everything together into one
> patch is also not good.
>
> It would make more sense (at least for me) if you squashed the work
> that has already been done into one patch, and then post your updates
> as individual patches.  That way, Christian and myself can see what
> the changes are against some known without having to dig through your
> git tree, and those who complained about all the patches last time
> have fewer patches to look at.
>
> Expecting those in the project to page through thousands of lines that
> they already know about, hoping to spot the changes you've made is
> really very unreasonable and error prone.  I will _NOT_ be wasting my
> time reviewing this mega-patch exactly because of that.
>

Yep it quite hard to review it that way - I only had a look at the
user space <-> kernel space api/abi.

greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-11 14:10 ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Lucas Stach
                     ` (2 preceding siblings ...)
  2015-09-16  8:04   ` Russell King - ARM Linux
@ 2015-09-16 15:05   ` Eric Anholt
  2015-09-16 16:51     ` Russell King - ARM Linux
  3 siblings, 1 reply; 100+ messages in thread
From: Eric Anholt @ 2015-09-16 15:05 UTC (permalink / raw)
  To: Lucas Stach, dri-devel; +Cc: Russell King, kernel


[-- Attachment #1.1: Type: text/plain, Size: 1062 bytes --]

Lucas Stach <l.stach@pengutronix.de> writes:

> From: Christian Gmeiner <christian.gmeiner@gmail.com>

> +static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf,
> +	unsigned int state, unsigned int num)
> +{
> +	return true;
> +	if (0x1200 - state < num * 4)
> +		return false;
> +	if (0x1228 - state < num * 4)
> +		return false;
> +	if (0x1238 - state < num * 4)
> +		return false;
> +	if (0x1284 - state < num * 4)
> +		return false;
> +	if (0x128c - state < num * 4)
> +		return false;
> +	if (0x1304 - state < num * 4)
> +		return false;
> +	if (0x1310 - state < num * 4)
> +		return false;
> +	if (0x1318 - state < num * 4)
> +		return false;
> +	if (0x1280c - state < num * 4 + 0x0c)
> +		return false;
> +	if (0x128ac - state < num * 4 + 0x0c)
> +		return false;
> +	if (0x128cc - state < num * 4 + 0x0c)
> +		return false;
> +	if (0x1297c - state < num * 4 + 0x0c)
> +		return false;
> +	return true;
> +}

I was browsing the code, and noticed that it looks like you've got a
debugging early return in your validation function here.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-16  6:11   ` Christian Gmeiner
  2015-09-16  7:49     ` Russell King - ARM Linux
@ 2015-09-16 15:30     ` Lucas Stach
  1 sibling, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-16 15:30 UTC (permalink / raw)
  To: Christian Gmeiner; +Cc: Russell King, Sascha Hauer, DRI mailing list

Am Mittwoch, den 16.09.2015, 08:11 +0200 schrieb Christian Gmeiner:
> Hi Lucas
> 
> 
> 2015-09-11 16:10 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> > From: Christian Gmeiner <christian.gmeiner@gmail.com>
> > 
> > This is a squashed commit of the complete etnaviv DRM driver in
> > order
> > to make it easy for people to review the code by seeing the driver
> > as a
> > whole and is not intended for merging in this form.
> > 
> > If you are interested in the history of individual commits:
> > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> > 
> > 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>
> > ---

[...]

> > +/*
> > + * Cmdstream Submission:
> > + */
> > +
> > +/* The value written into the cmdstream is logically:
> > + * relocbuf->gpuaddr + reloc_offset
> > + *
> > + * NOTE that reloc's must be sorted by order of increasing
> > submit_offset,
> > + * otherwise EINVAL.
> > + */
> > +struct drm_etnaviv_gem_submit_reloc {
> > +       __u32 submit_offset;  /* in, offset from submit_bo */
> > +       __u32 reloc_idx;      /* in, index of reloc_bo buffer */
> > +       __u64 reloc_offset;   /* in, offset from start of reloc_bo
> > */
> > +};
> > +
> > +/* Each buffer referenced elsewhere in the cmdstream submit (ie.
> > the
> > + * cmdstream buffer(s) themselves or reloc entries) has one (and
> > only
> > + * one) entry in the submit->bos[] table.
> > + *
> > + * As a optimization, the current buffer (gpu virtual address) can
> > be
> > + * passed back through the 'presumed' field.  If on a subsequent
> > reloc,
> > + * userspace passes back a 'presumed' address that is still valid,
> > + * then patching the cmdstream for this entry is skipped.  This
> > can
> > + * avoid kernel needing to map/access the cmdstream bo in the
> > common
> > + * case.
> > + */
> > +#define ETNA_SUBMIT_BO_READ             0x0001
> > +#define ETNA_SUBMIT_BO_WRITE            0x0002
> > +struct drm_etnaviv_gem_submit_bo {
> > +       __u32 flags;          /* in, mask of ETNA_SUBMIT_BO_x */
> > +       __u32 handle;         /* in, GEM handle */
> > +       __u64 presumed;       /* in/out, presumed buffer address */
> > +};
> > +=
> 
> As presumed never gets used in the driver itself and I am not a big
> fan of it,
> can we remove it? Do you see any usecase for it?
> 
I think it could be useful to skip cmdstream patching on MMUv2. But to
be honest I don't know how much of a difference this will make, now
that we are operating on cached memory for the command stream as long
as possible. I'll try to get some performance profile, but at this
point I think it makes sense to get rid of it.

Regards
Lucas
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-16  8:04   ` Russell King - ARM Linux
  2015-09-16 10:42     ` Christian Gmeiner
@ 2015-09-16 15:36     ` Lucas Stach
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
  2 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-16 15:36 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: kernel, dri-devel

Am Mittwoch, den 16.09.2015, 09:04 +0100 schrieb Russell King - ARM
Linux:
> On Fri, Sep 11, 2015 at 04:10:13PM +0200, Lucas Stach wrote:
> > From: Christian Gmeiner <christian.gmeiner@gmail.com>
> > 
> > This is a squashed commit of the complete etnaviv DRM driver in
> > order
> > to make it easy for people to review the code by seeing the driver
> > as a
> > whole and is not intended for merging in this form.
> > 
> > If you are interested in the history of individual commits:
> > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> > 
> > 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>
> 
> Lucas,
> 
> I know that the previous round, people said that they didn't like the
> individual patches posted, but squashing everything together into one
> patch is also not good.
> 
I still think it's useful for those that haven't looked at that code
yet.

> It would make more sense (at least for me) if you squashed the work
> that has already been done into one patch, and then post your updates
> as individual patches.  That way, Christian and myself can see what
> the changes are against some known without having to dig through your
> git tree, and those who complained about all the patches last time
> have fewer patches to look at.
> 
> Expecting those in the project to page through thousands of lines
> that
> they already know about, hoping to spot the changes you've made is
> really very unreasonable and error prone.  I will _NOT_ be wasting my
> time reviewing this mega-patch exactly because of that.
> 
Sure, I will follow up with a partially squashed version to get you the
changes from RFCv1. If you have any comments before that I'm totally
fine with you posting them out of context. I'll take care of mapping
them back to patches.

Regards,
Lucas
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-16 15:05   ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Eric Anholt
@ 2015-09-16 16:51     ` Russell King - ARM Linux
  2015-09-16 18:43       ` Eric Anholt
  0 siblings, 1 reply; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-09-16 16:51 UTC (permalink / raw)
  To: Eric Anholt; +Cc: kernel, dri-devel

On Wed, Sep 16, 2015 at 11:05:11AM -0400, Eric Anholt wrote:
> Lucas Stach <l.stach@pengutronix.de> writes:
> 
> > From: Christian Gmeiner <christian.gmeiner@gmail.com>
> 
> > +static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf,
> > +	unsigned int state, unsigned int num)
> > +{
> > +	return true;
...
> > +}
> 
> I was browsing the code, and noticed that it looks like you've got a
> debugging early return in your validation function here.

That's because it's not quite ready to be enabled yet - the code as
it stands in my tree doesn't have the infrastructure to validate that
a LOADSTATE which touches an address register (or similar) has a
relocation appropriately marked, due to the way things happen.
Hopefully, when the user/kernel API is sorted, this can be resolved.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 3/4] staging: etnaviv: add drm driver
  2015-09-16 16:51     ` Russell King - ARM Linux
@ 2015-09-16 18:43       ` Eric Anholt
  0 siblings, 0 replies; 100+ messages in thread
From: Eric Anholt @ 2015-09-16 18:43 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: kernel, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 1039 bytes --]

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Wed, Sep 16, 2015 at 11:05:11AM -0400, Eric Anholt wrote:
>> Lucas Stach <l.stach@pengutronix.de> writes:
>> 
>> > From: Christian Gmeiner <christian.gmeiner@gmail.com>
>> 
>> > +static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf,
>> > +	unsigned int state, unsigned int num)
>> > +{
>> > +	return true;
> ...
>> > +}
>> 
>> I was browsing the code, and noticed that it looks like you've got a
>> debugging early return in your validation function here.
>
> That's because it's not quite ready to be enabled yet - the code as
> it stands in my tree doesn't have the infrastructure to validate that
> a LOADSTATE which touches an address register (or similar) has a
> relocation appropriately marked, due to the way things happen.
> Hopefully, when the user/kernel API is sorted, this can be resolved.

OK.  Validation code is painful to write, so I was just browsing what
was in here to see if I could pick up anything useful.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-09-16  8:04   ` Russell King - ARM Linux
  2015-09-16 10:42     ` Christian Gmeiner
  2015-09-16 15:36     ` Lucas Stach
@ 2015-09-25 11:57     ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 01/48] staging: etnaviv: avoid holding struct_mutex over dma_alloc_coherent() Lucas Stach
                         ` (48 more replies)
  2 siblings, 49 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

Hi Russell, Christian and whoever might be interested,

This series contains the individual changes between RFCv1 and RFCv2
of the etnaviv driver. This should make it easier to review the patches
for people already familiar with the first round of etnaviv patches.

Note that I opted to sort the patches a bit different than how they are
laid out in the etnaviv-for-upstream git branch to make logical
connections between patches a bit more clear and to not repeat patches
with only trivial changes from RFCv1 in this series.

Regards,
Lucas

Christian Gmeiner (5):
  staging: etnaviv: quiten down kernel log output
  staging: etnaviv: fix 'ret' may be used uninitialized in this function
  staging: etnaviv: fix error: 'etnaviv_gpu_hw_resume' defined but not
    used
  staging: etnaviv: debugfs: add possibility to dump kernel buffer
  staging: etnaviv: change etnaviv_buffer_init() to return prefetch

Lucas Stach (10):
  staging: etnaviv: remove compat MMU code
  staging: etnaviv: rename last remaining bits from msm to etnaviv
  staging: etnaviv: add proper license header to all files
  staging: etnaviv: implement simple hang recovery
  staging: etnaviv: map all buffers to the GPU
  staging: etnaviv: implement cache maintenance on cpu_(prep|fini)
  staging: etnaviv: remove submit type
  staging: etnaviv: rewrite submit interface to use copy from user
  staging: etnaviv: don't use GEM buffer for internal ring buffer
  staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI

Russell King (33):
  staging: etnaviv: avoid holding struct_mutex over dma_alloc_coherent()
  staging: etnaviv: restructure iommu handling
  staging: etnaviv: clean up public API (part 2)
  staging: etnaviv: rename last remaining msm_* symbols
  staging: etnaviv: add Dove GPU subsystem compatible
  staging: etnaviv: fix missing error cleanups in etnaviv_load()
  staging: etnaviv: fix off-by-one for iommu aperture end
  staging: etnaviv: avoid lockdep circular dependency warning
  staging: etnaviv: fix gpu debugfs show implementation
  staging: etnaviv: use vm_insert_page() rather than vm_insert_mixed()
  staging: etnaviv: etnaviv_gem_fault: reduce struct_mutex exposure
  staging: etnaviv: give etnaviv_gem_mmap_offset() a sane behaviour
  staging: etnaviv: allow etnaviv_ioctl_gem_info() locking to be
    interruptible
  staging: etnaviv: make context a per-GPU thing
  staging: etnaviv: switch to per-GPU fence completion implementation
  staging: etnaviv: provide etnaviv_queue_work()
  staging: etnaviv: use standard kernel types rather than stdint.h types
  staging: etnaviv: no need to initialise a list_head
  staging: etnaviv: fix oops caused by scanning for free blocks
  staging: etnaviv: clean up etnaviv_iommu_unmap_gem() signature
  staging: etnaviv: increase page table size to maximum
  staging: etnaviv: fix BUG_ON when removing module
  staging: etnaviv: provide a helper to load the GPU clock field
  staging: etnaviv: rename GPU clock functions
  staging: etnaviv: fix runtime resume
  staging: etnaviv: drop event ring buffer tracking
  staging: etnaviv: improve efficiency of command parser
  staging: etnaviv: no point looking up the mapping for cmdstream bos
  staging: etnaviv: copy submit command and bos in one go
  staging: etnaviv: remove cmd buffer offset validation in
    submit_reloc()
  staging: etnaviv: move mapping teardown into etnaviv_gem_free_object()
  staging: etnaviv: add support for GEM_WAIT ioctl
  staging: etnaviv: avoid pinning pages in CMA

 drivers/staging/etnaviv/etnaviv_buffer.c     | 123 ++++----
 drivers/staging/etnaviv/etnaviv_cmd_parser.c |  56 ++--
 drivers/staging/etnaviv/etnaviv_drv.c        | 217 ++++++++-------
 drivers/staging/etnaviv/etnaviv_drv.h        |  54 ++--
 drivers/staging/etnaviv/etnaviv_gem.c        | 370 ++++++++++++------------
 drivers/staging/etnaviv/etnaviv_gem.h        |  40 +--
 drivers/staging/etnaviv/etnaviv_gem_prime.c  |  10 +-
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 219 +++++++--------
 drivers/staging/etnaviv/etnaviv_gpu.c        | 403 ++++++++++++++++++++-------
 drivers/staging/etnaviv/etnaviv_gpu.h        | 107 ++++---
 drivers/staging/etnaviv/etnaviv_iommu.c      | 113 ++++----
 drivers/staging/etnaviv/etnaviv_iommu.h      |   2 +
 drivers/staging/etnaviv/etnaviv_mmu.c        |  75 ++---
 drivers/staging/etnaviv/etnaviv_mmu.h        |  15 +-
 include/uapi/drm/etnaviv_drm.h               | 100 +++----
 15 files changed, 1086 insertions(+), 818 deletions(-)

-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* [PATCH 01/48] staging: etnaviv: avoid holding struct_mutex over dma_alloc_coherent()
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 02/48] staging: etnaviv: restructure iommu handling Lucas Stach
                         ` (47 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Holding the DRM struct_mutex over a call to dma_alloc_coherent() is
asking for trouble; the DRM struct_mutex is held inside several other
system-wide locks, and when CMA is enabled, this causes the CMA lock
to be nested inside struct_mutex.

In conjunction with other system locks, this eventually causes a AB-BA
lock ordering bug, which becomes most apparent when using CPU hotplug:

[ INFO: possible circular locking dependency detected ]
3.19.0-rc6+ #1497 Not tainted
-------------------------------------------------------
bash/2154 is trying to acquire lock:
 (console_lock){+.+.+.}, at: [<c006b75c>] console_cpu_notify+0x28/0x34

but task is already holding lock:
 (cpu_hotplug.lock#2){+.+.+.}, at: [<c00270f0>] cpu_hotplug_begin+0x64/0xb8

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #5 (cpu_hotplug.lock#2){+.+.+.}:
       [<c06ecaac>] mutex_lock_nested+0x5c/0x3d8
       [<c00dad28>] lru_add_drain_all+0x1c/0x18c
       [<c010fbe8>] migrate_prep+0x10/0x18
       [<c00d5d74>] alloc_contig_range+0xd0/0x2cc
       [<c0111448>] cma_alloc+0xe0/0x1ac
       [<c0397268>] dma_alloc_from_contiguous+0x3c/0x44
       [<c001a7bc>] __alloc_from_contiguous+0x3c/0xe8
       [<c09a3b48>] atomic_pool_init+0x6c/0x15c
       [<c0008a5c>] do_one_initcall+0x88/0x1d8
       [<c099ee44>] kernel_init_freeable+0x110/0x1dc
       [<c06e3104>] kernel_init+0x10/0xec
       [<c000ecd0>] ret_from_fork+0x14/0x24

-> #4 (lock){+.+...}:
       [<c06ecaac>] mutex_lock_nested+0x5c/0x3d8
       [<c00dad28>] lru_add_drain_all+0x1c/0x18c
       [<c010fbe8>] migrate_prep+0x10/0x18
       [<c00d5d74>] alloc_contig_range+0xd0/0x2cc
       [<c0111448>] cma_alloc+0xe0/0x1ac
       [<c0397268>] dma_alloc_from_contiguous+0x3c/0x44
       [<c001a7bc>] __alloc_from_contiguous+0x3c/0xe8
       [<c09a3b48>] atomic_pool_init+0x6c/0x15c
       [<c0008a5c>] do_one_initcall+0x88/0x1d8
       [<c099ee44>] kernel_init_freeable+0x110/0x1dc
       [<c06e3104>] kernel_init+0x10/0xec
       [<c000ecd0>] ret_from_fork+0x14/0x24

-> #3 (cma_mutex){+.+.+.}:
       [<c06ecaac>] mutex_lock_nested+0x5c/0x3d8
       [<c0111438>] cma_alloc+0xd0/0x1ac
       [<c0397268>] dma_alloc_from_contiguous+0x3c/0x44
       [<c001a7bc>] __alloc_from_contiguous+0x3c/0xe8
       [<c001abbc>] __dma_alloc+0x15c/0x28c
       [<c001ae38>] arm_dma_alloc+0xa0/0xa8
       [<c0508a24>] etnaviv_iommu_domain_init+0x54/0x138
       [<c0508b54>] etnaviv_iommu_domain_alloc+0x4c/0xd8
       [<c0507c8c>] etnaviv_gpu_init+0x380/0x620
       [<c0503ff8>] etnaviv_load+0xc0/0x128
       [<c0369244>] drm_dev_register+0xac/0x10c
       [<c036ad1c>] drm_platform_init+0x48/0xd4
       [<c050382c>] etnaviv_bind+0x18/0x20
       [<c038d138>] try_to_bring_up_master+0x140/0x17c
       [<c038d2f0>] component_master_add_with_match+0x84/0xe0
       [<c0504114>] etnaviv_pdev_probe+0xb4/0x104
       [<c0392ed8>] platform_drv_probe+0x50/0xac
       [<c03916f0>] driver_probe_device+0x114/0x234
       [<c03918ac>] __driver_attach+0x9c/0xa0
       [<c038fd3c>] bus_for_each_dev+0x5c/0x90
       [<c03911e0>] driver_attach+0x24/0x28
       [<c0390e58>] bus_add_driver+0xe0/0x1d8
       [<c03920ac>] driver_register+0x80/0xfc
       [<c0392d60>] __platform_driver_register+0x50/0x64
       [<c09d8b08>] etnaviv_init+0x2c/0x4c
       [<c0008a5c>] do_one_initcall+0x88/0x1d8
       [<c099ee44>] kernel_init_freeable+0x110/0x1dc
       [<c06e3104>] kernel_init+0x10/0xec
       [<c000ecd0>] ret_from_fork+0x14/0x24

-> #2 (&dev->struct_mutex){+.+.+.}:
       [<c06ecaac>] mutex_lock_nested+0x5c/0x3d8
       [<c0364508>] drm_gem_mmap+0x3c/0xd4
       [<c037ef88>] drm_gem_cma_mmap+0x14/0x2c
       [<c00fd020>] mmap_region+0x3d0/0x6a4
       [<c00fd5d8>] do_mmap_pgoff+0x2e4/0x374
       [<c00e6c18>] vm_mmap_pgoff+0x6c/0x9c
       [<c00fbb98>] SyS_mmap_pgoff+0x94/0xb8
       [<c000ec00>] ret_fast_syscall+0x0/0x4c

-> #1 (&mm->mmap_sem){++++++}:
       [<c00f4a68>] might_fault+0x64/0x98
       [<c033dd3c>] con_set_unimap+0x160/0x25c
       [<c03381c8>] vt_ioctl+0x126c/0x1328
       [<c032bfdc>] tty_ioctl+0x498/0xc5c
       [<c012493c>] do_vfs_ioctl+0x84/0x66c
       [<c0124f60>] SyS_ioctl+0x3c/0x60
       [<c000ec00>] ret_fast_syscall+0x0/0x4c

-> #0 (console_lock){+.+.+.}:
       [<c00627f0>] lock_acquire+0xb0/0x124
       [<c00697cc>] console_lock+0x44/0x6c
       [<c006b75c>] console_cpu_notify+0x28/0x34
       [<c00431b0>] notifier_call_chain+0x4c/0x8c
       [<c00432cc>] __raw_notifier_call_chain+0x1c/0x24
       [<c0026d74>] __cpu_notify+0x34/0x50
       [<c0026da8>] cpu_notify+0x18/0x1c
       [<c0026eec>] cpu_notify_nofail+0x10/0x1c
       [<c06e3484>] _cpu_down+0x100/0x248
       [<c06e35f8>] cpu_down+0x2c/0x48
       [<c03939a8>] cpu_subsys_offline+0x14/0x18
       [<c038f6d0>] device_offline+0x90/0xc0
       [<c038f7e0>] online_store+0x4c/0x74
       [<c038d46c>] dev_attr_store+0x20/0x2c
       [<c017c0f8>] sysfs_kf_write+0x54/0x58
       [<c017b430>] kernfs_fop_write+0xfc/0x1ac
       [<c0114274>] vfs_write+0xac/0x1b4
       [<c01145b0>] SyS_write+0x44/0x90
       [<c000ec00>] ret_fast_syscall+0x0/0x4c

other info that might help us debug this:

Chain exists of:
  console_lock --> lock --> cpu_hotplug.lock#2

 Possible unsafe locking scenario:
       CPU0                    CPU1
       ----                    ----
  lock(cpu_hotplug.lock#2);
                               lock(lock);
                               lock(cpu_hotplug.lock#2);
  lock(console_lock);

 *** DEADLOCK ***

8 locks held by bash/2154:
 #0:  (sb_writers#5){.+.+.+}, at: [<c0114354>] vfs_write+0x18c/0x1b4
 #1:  (&of->mutex){+.+.+.}, at: [<c017b3bc>] kernfs_fop_write+0x88/0x1ac
 #2:  (s_active#40){.+.+.+}, at: [<c017b3c4>] kernfs_fop_write+0x90/0x1ac
 #3:  (device_hotplug_lock){+.+.+.}, at: [<c038e4d8>] lock_device_hotplug_sysfs+0x14/0x54
 #4:  (&dev->mutex){......}, at: [<c038f684>] device_offline+0x44/0xc0
 #5:  (cpu_add_remove_lock){+.+.+.}, at: [<c0026de0>] cpu_maps_update_begin+0x18/0x20
 #6:  (cpu_hotplug.lock){++++++}, at: [<c002708c>] cpu_hotplug_begin+0x0/0xb8
 #7:  (cpu_hotplug.lock#2){+.+.+.}, at: [<c00270f0>] cpu_hotplug_begin+0x64/0xb8
stack backtrace:
CPU: 0 PID: 2154 Comm: bash Not tainted 3.19.0-rc6+ #1497
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
Backtrace:
[<c0012280>] (dump_backtrace) from [<c0012418>] (show_stack+0x18/0x1c)
[<c0012400>] (show_stack) from [<c06e8eac>] (dump_stack+0x7c/0x98)
[<c06e8e30>] (dump_stack) from [<c06e6520>] (print_circular_bug+0x28c/0x2d8)
[<c06e6294>] (print_circular_bug) from [<c00621a8>] (__lock_acquire+0x1acc/0x1bb0)
[<c00606dc>] (__lock_acquire) from [<c00627f0>] (lock_acquire+0xb0/0x124)
[<c0062740>] (lock_acquire) from [<c00697cc>] (console_lock+0x44/0x6c)
[<c0069788>] (console_lock) from [<c006b75c>] (console_cpu_notify+0x28/0x34)
[<c006b734>] (console_cpu_notify) from [<c00431b0>] (notifier_call_chain+0x4c/0x8c)
[<c0043164>] (notifier_call_chain) from [<c00432cc>] (__raw_notifier_call_chain+0x1c/0x24)
[<c00432b0>] (__raw_notifier_call_chain) from [<c0026d74>] (__cpu_notify+0x34/0x50)
[<c0026d40>] (__cpu_notify) from [<c0026da8>] (cpu_notify+0x18/0x1c)
[<c0026d90>] (cpu_notify) from [<c0026eec>] (cpu_notify_nofail+0x10/0x1c)
[<c0026edc>] (cpu_notify_nofail) from [<c06e3484>] (_cpu_down+0x100/0x248)
[<c06e3384>] (_cpu_down) from [<c06e35f8>] (cpu_down+0x2c/0x48)
[<c06e35cc>] (cpu_down) from [<c03939a8>] (cpu_subsys_offline+0x14/0x18)
[<c0393994>] (cpu_subsys_offline) from [<c038f6d0>] (device_offline+0x90/0xc0)
[<c038f640>] (device_offline) from [<c038f7e0>] (online_store+0x4c/0x74)
[<c038f794>] (online_store) from [<c038d46c>] (dev_attr_store+0x20/0x2c)
[<c038d44c>] (dev_attr_store) from [<c017c0f8>] (sysfs_kf_write+0x54/0x58)
[<c017c0a4>] (sysfs_kf_write) from [<c017b430>] (kernfs_fop_write+0xfc/0x1ac)
[<c017b334>] (kernfs_fop_write) from [<c0114274>] (vfs_write+0xac/0x1b4)
[<c01141c8>] (vfs_write) from [<c01145b0>] (SyS_write+0x44/0x90)
[<c011456c>] (SyS_write) from [<c000ec00>] (ret_fast_syscall+0x0/0x4c)

The locking ordering for each of the chain backtraces are:

5: cpu_hotplug.lock (in lru_add_drain_all, get_online_cpus)
   lock (in lru_add_drain_all)
   cma_mutex (in cma_alloc)
4: lock (in lru_add_drain_all),
   cma_mutex (in cma_alloc)
3: cma_mutex (in cma_alloc)
   drm dev->struct_mutex (in etnaviv_load)
2: drm dev->struct_mutex (in drm_gem_mmap)
   mm->mmap_sem (in vm_mmap_pgoff)
1: mm->mmap_sem (in might_fault)
   console_lock (in con_set_unimap, console_lock)
0: console_lock (in console_cpu_notify, console_lock)
   cpu_hotplug.lock (in _cpu_down, cpu_hotplug_begin)

Hence the dependency chain of:
  cpu_hotplug.lock -> console_lock -> mmap_sem -> struct_mutex ->
    cma_mutex -> cpu_hotplug.lock *deadlock*

The operation which etnadrm needs to lock is not the allocations, but
the addition of the etnaviv_obj to the inactive list (to prevent the
list becoming corrupted.)  Move this to a separate operation which is
performed once all the setup of the object is complete, and move the
locking such that the allocation and setup is unlocked.

This is overall more efficient, as we permit multiple expensive
operations to occur in parallel (memory allocation) while only locking
what we need.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c       |  6 --
 drivers/staging/etnaviv/etnaviv_gem.c       | 94 +++++++++++++++++++----------
 drivers/staging/etnaviv/etnaviv_gem.h       |  1 +
 drivers/staging/etnaviv/etnaviv_gem_prime.c |  4 ++
 drivers/staging/etnaviv/etnaviv_gpu.c       |  2 +
 5 files changed, 69 insertions(+), 38 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 0dedbbeb1fa5..1ba480aed4fd 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -84,9 +84,7 @@ static int etnaviv_unload(struct drm_device *dev)
 	flush_workqueue(priv->wq);
 	destroy_workqueue(priv->wq);
 
-	mutex_lock(&dev->struct_mutex);
 	component_unbind_all(dev->dev, dev);
-	mutex_unlock(&dev->struct_mutex);
 
 	dev->dev_private = NULL;
 
@@ -138,16 +136,12 @@ static int etnaviv_load(struct drm_device *dev, unsigned long flags)
 
 	platform_set_drvdata(pdev, dev);
 
-	mutex_lock(&dev->struct_mutex);
-
 	err = component_bind_all(dev->dev, dev);
 	if (err < 0)
 		return err;
 
 	load_gpu(dev);
 
-	mutex_unlock(&dev->struct_mutex);
-
 	return 0;
 }
 
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 09800b0dec35..22407846320b 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -566,37 +566,26 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
 	kfree(etnaviv_obj);
 }
 
-/* convenience method to construct a GEM buffer object, and userspace handle */
-int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
-		uint32_t size, uint32_t flags, uint32_t *handle)
+int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
 {
-	struct drm_gem_object *obj;
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 	int ret;
 
-	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	ret = mutex_lock_killable(&dev->struct_mutex);
 	if (ret)
 		return ret;
 
-	obj = etnaviv_gem_new(dev, size, flags);
-
+	list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
 	mutex_unlock(&dev->struct_mutex);
 
-	if (IS_ERR(obj))
-		return PTR_ERR(obj);
-
-	ret = drm_gem_handle_create(file, obj, handle);
-
-	/* drop reference from allocate - handle holds it now */
-	drm_gem_object_unreference_unlocked(obj);
-
-	return ret;
+	return 0;
 }
 
 static int etnaviv_gem_new_impl(struct drm_device *dev,
 		uint32_t size, uint32_t flags,
 		struct drm_gem_object **obj)
 {
-	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct etnaviv_gem_object *etnaviv_obj;
 	unsigned sz = sizeof(*etnaviv_obj);
 	bool valid = true;
@@ -651,14 +640,12 @@ static int etnaviv_gem_new_impl(struct drm_device *dev,
 	return 0;
 }
 
-struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
+static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
 		uint32_t size, uint32_t flags)
 {
 	struct drm_gem_object *obj = NULL;
 	int ret;
 
-	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
 	size = PAGE_ALIGN(size);
 
 	ret = etnaviv_gem_new_impl(dev, size, flags, &obj);
@@ -681,11 +668,55 @@ struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
 
 fail:
 	if (obj)
-		drm_gem_object_unreference(obj);
+		drm_gem_object_unreference_unlocked(obj);
 
 	return ERR_PTR(ret);
 }
 
+/* convenience method to construct a GEM buffer object, and userspace handle */
+int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
+		uint32_t size, uint32_t flags, uint32_t *handle)
+{
+	struct drm_gem_object *obj;
+	int ret;
+
+	obj = __etnaviv_gem_new(dev, size, flags);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	ret = etnaviv_gem_obj_add(dev, obj);
+	if (ret < 0) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
+
+	ret = drm_gem_handle_create(file, obj, handle);
+
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference_unlocked(obj);
+
+	return ret;
+}
+
+struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
+		uint32_t size, uint32_t flags)
+{
+	struct drm_gem_object *obj;
+	int ret;
+
+	obj = __etnaviv_gem_new(dev, size, flags);
+	if (IS_ERR(obj))
+		return obj;
+
+	ret = etnaviv_gem_obj_add(dev, obj);
+	if (ret < 0) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ERR_PTR(ret);
+	}
+
+	return obj;
+}
+
 int etnaviv_gem_new_private(struct drm_device *dev, size_t size, uint32_t flags,
 	struct etnaviv_gem_object **res)
 {
@@ -879,22 +910,21 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
 	struct etnaviv_gem_object *etnaviv_obj;
 	int ret;
 
-	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, &etnaviv_obj);
 	if (ret)
 		return ret;
 
-	ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, &etnaviv_obj);
-	if (ret == 0) {
-		etnaviv_obj->ops = &etnaviv_gem_userptr_ops;
-		etnaviv_obj->userptr.ptr = ptr;
-		etnaviv_obj->userptr.task = current;
-		etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);
-		get_task_struct(current);
-	}
-	mutex_unlock(&dev->struct_mutex);
+	etnaviv_obj->ops = &etnaviv_gem_userptr_ops;
+	etnaviv_obj->userptr.ptr = ptr;
+	etnaviv_obj->userptr.task = current;
+	etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);
+	get_task_struct(current);
 
-	if (ret)
+	ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
 		return ret;
+	}
 
 	ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);
 
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index cc5e307465f6..c801b9a161e6 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -133,6 +133,7 @@ etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
 			     struct etnaviv_iommu *mmu);
 int etnaviv_gem_new_private(struct drm_device *dev, size_t size, uint32_t flags,
 	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);
 
diff --git a/drivers/staging/etnaviv/etnaviv_gem_prime.c b/drivers/staging/etnaviv/etnaviv_gem_prime.c
index aad5a96f9fba..cca569be98bf 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_prime.c
@@ -108,6 +108,10 @@ struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
 	if (ret)
 		goto fail;
 
+	ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
+	if (ret)
+		goto fail;
+
 	return &etnaviv_obj->base;
 
 fail:
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 9c06bc6c245d..dc02c69512ff 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -529,7 +529,9 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
 	}
 
 	/* Now program the hardware */
+	mutex_lock(&gpu->drm->struct_mutex);
 	etnaviv_gpu_hw_init(gpu);
+	mutex_unlock(&gpu->drm->struct_mutex);
 
 	pm_runtime_mark_last_busy(gpu->dev);
 	pm_runtime_put_autosuspend(gpu->dev);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 02/48] staging: etnaviv: restructure iommu handling
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
  2015-09-25 11:57       ` [PATCH 01/48] staging: etnaviv: avoid holding struct_mutex over dma_alloc_coherent() Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 03/48] staging: etnaviv: remove compat MMU code Lucas Stach
                         ` (46 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Restructure the IOMMU handling to allow Etnaviv DRM to work on v4.1
kernels, as well as previous kernel versions.  This also allows us
to implement runtime PM properly for Dove, where the GPU is powered
down and loses the MMU table pointer.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gpu.c   |  10 ++-
 drivers/staging/etnaviv/etnaviv_iommu.c | 120 ++++++++++++++++++++------------
 drivers/staging/etnaviv/etnaviv_iommu.h |   2 +
 3 files changed, 88 insertions(+), 44 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index dc02c69512ff..c230da7dd526 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -451,7 +451,8 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
 	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
 
-	/* FIXME: we need to program the GPU table pointer(s) here */
+	/* setup the MMU page table pointers */
+	etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain);
 
 	/* Start command processor */
 	words = etnaviv_buffer_init(gpu);
@@ -479,6 +480,13 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
 		return ret;
 
 	etnaviv_hw_identify(gpu);
+
+	if (gpu->identity.model == 0) {
+		dev_err(gpu->dev, "Unknown GPU model\n");
+		pm_runtime_put_autosuspend(gpu->dev);
+		return -ENXIO;
+	}
+
 	ret = etnaviv_hw_reset(gpu);
 	if (ret)
 		goto fail;
diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
index 71f94dac650b..5735319215a3 100644
--- a/drivers/staging/etnaviv/etnaviv_iommu.c
+++ b/drivers/staging/etnaviv/etnaviv_iommu.c
@@ -1,6 +1,6 @@
 /*
  * 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.
@@ -20,11 +20,16 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/bitops.h>
+#include <linux/version.h>
 
 #include "etnaviv_gpu.h"
 #include "etnaviv_iommu.h"
 #include "state_hi.xml.h"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+#define OLD_IOMMU
+#endif
+
 #define PT_SIZE		SZ_512K
 #define PT_ENTRIES	(PT_SIZE / sizeof(uint32_t))
 
@@ -36,12 +41,19 @@ struct etnaviv_iommu_domain_pgtable {
 };
 
 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)
 {
@@ -79,62 +91,72 @@ static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
 	pgtable->pgtable[index] = paddr;
 }
 
-static int etnaviv_iommu_domain_init(struct iommu_domain *domain)
+static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
 {
-	struct etnaviv_iommu_domain *etnaviv_domain;
 	uint32_t iova, *p;
 	int ret, i;
 
-	etnaviv_domain = kmalloc(sizeof(*etnaviv_domain), GFP_KERNEL);
-	if (!etnaviv_domain)
-		return -ENOMEM;
-
-	etnaviv_domain->bad_page_cpu = dma_alloc_coherent(NULL, SZ_4K,
+	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) {
-		kfree(etnaviv_domain);
+	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(NULL, SZ_4K, etnaviv_domain->bad_page_cpu,
+		dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+				  etnaviv_domain->bad_page_cpu,
 				  etnaviv_domain->bad_page_dma);
-		kfree(etnaviv_domain);
 		return ret;
 	}
 
-	for (iova = domain->geometry.aperture_start;
-	     iova < domain->geometry.aperture_end; iova += SZ_4K) {
+	for (iova = etnaviv_domain->domain.geometry.aperture_start;
+	     iova < etnaviv_domain->domain.geometry.aperture_end; iova += SZ_4K) {
 		pgtable_write(&etnaviv_domain->pgtable, iova,
 			      etnaviv_domain->bad_page_dma);
 	}
 
 	spin_lock_init(&etnaviv_domain->map_lock);
-	domain->priv = etnaviv_domain;
+
 	return 0;
 }
 
-static void etnaviv_iommu_domain_destroy(struct iommu_domain *domain)
+static void __etnaviv_iommu_free(struct etnaviv_iommu_domain *etnaviv_domain)
 {
-	struct etnaviv_iommu_domain *etnaviv_domain = domain->priv;
-
 	pgtable_free(&etnaviv_domain->pgtable, PT_SIZE);
 
-	dma_free_coherent(NULL, SZ_4K, etnaviv_domain->bad_page_cpu,
+	dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+			  etnaviv_domain->bad_page_cpu,
 			  etnaviv_domain->bad_page_dma);
+
 	kfree(etnaviv_domain);
+}
+
+#ifdef OLD_IOMMU
+static void etnaviv_iommu_domain_destroy(struct iommu_domain *domain)
+{
+	struct etnaviv_iommu_domain *etnaviv_domain = domain->priv;
+
+	__etnaviv_iommu_free(etnaviv_domain);
+
 	domain->priv = NULL;
 }
+#else
+static void etnaviv_domain_free(struct iommu_domain *domain)
+{
+	__etnaviv_iommu_free(to_etnaviv_domain(domain));
+}
+#endif
 
 static int etnaviv_iommu_map(struct iommu_domain *domain, unsigned long iova,
 	   phys_addr_t paddr, size_t size, int prot)
 {
-	struct etnaviv_iommu_domain *etnaviv_domain = domain->priv;
+	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
 
 	if (size != SZ_4K)
 		return -EINVAL;
@@ -149,7 +171,7 @@ static int etnaviv_iommu_map(struct iommu_domain *domain, unsigned long iova,
 static size_t etnaviv_iommu_unmap(struct iommu_domain *domain,
 	unsigned long iova, size_t size)
 {
-	struct etnaviv_iommu_domain *etnaviv_domain = domain->priv;
+	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
 
 	if (size != SZ_4K)
 		return -EINVAL;
@@ -165,41 +187,30 @@ static size_t etnaviv_iommu_unmap(struct iommu_domain *domain,
 static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain,
 	dma_addr_t iova)
 {
-	struct etnaviv_iommu_domain *etnaviv_domain = domain->priv;
+	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
 
 	return pgtable_read(&etnaviv_domain->pgtable, iova);
 }
 
 static struct iommu_ops etnaviv_iommu_ops = {
-		.domain_init = etnaviv_iommu_domain_init,
+#ifdef OLD_IOMMU
 		.domain_destroy = etnaviv_iommu_domain_destroy,
+#else
+		.domain_free = etnaviv_domain_free,
+#endif
 		.map = etnaviv_iommu_map,
 		.unmap = etnaviv_iommu_unmap,
 		.iova_to_phys = etnaviv_iommu_iova_to_phys,
 		.pgsize_bitmap = SZ_4K,
 };
 
-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 *domain;
-	struct etnaviv_iommu_domain *etnaviv_domain;
+	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
 	uint32_t pgtable;
-	int ret;
-
-	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
-	if (!domain)
-		return NULL;
-
-	domain->ops = &etnaviv_iommu_ops;
-	domain->geometry.aperture_start = GPU_MEM_START;
-	domain->geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K;
-
-	ret = domain->ops->domain_init(domain);
-	if (ret)
-		goto out_free;
 
 	/* set page table address in MC */
-	etnaviv_domain = domain->priv;
 	pgtable = (uint32_t)etnaviv_domain->pgtable.paddr;
 
 	gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable);
@@ -207,10 +218,33 @@ struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu)
 	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;
 
-	return domain;
+	etnaviv_domain->dev = gpu->dev;
+
+#ifndef OLD_IOMMU
+	etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
+#endif
+	etnaviv_domain->domain.ops = &etnaviv_iommu_ops;
+	etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START;
+	etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K;
+
+	ret = __etnaviv_iommu_init(etnaviv_domain);
+	if (ret)
+		goto out_free;
+
+	return &etnaviv_domain->domain;
 
 out_free:
-	kfree(domain);
+	kfree(etnaviv_domain);
 	return NULL;
 }
diff --git a/drivers/staging/etnaviv/etnaviv_iommu.h b/drivers/staging/etnaviv/etnaviv_iommu.h
index c0c359d4f166..cf45503f6b6f 100644
--- a/drivers/staging/etnaviv/etnaviv_iommu.h
+++ b/drivers/staging/etnaviv/etnaviv_iommu.h
@@ -21,6 +21,8 @@
 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__ */
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 03/48] staging: etnaviv: remove compat MMU code
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
  2015-09-25 11:57       ` [PATCH 01/48] staging: etnaviv: avoid holding struct_mutex over dma_alloc_coherent() Lucas Stach
  2015-09-25 11:57       ` [PATCH 02/48] staging: etnaviv: restructure iommu handling Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 12:18         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 04/48] staging: etnaviv: clean up public API (part 2) Lucas Stach
                         ` (45 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

There is no point in keeping backwards compatibility to older
kernel versions in a driver destined to mainline.

May squash this patch into
"staging: etnaviv: restructure iommu handling"

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_iommu.c | 33 +++------------------------------
 1 file changed, 3 insertions(+), 30 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
index 5735319215a3..8f92578ea3ee 100644
--- a/drivers/staging/etnaviv/etnaviv_iommu.c
+++ b/drivers/staging/etnaviv/etnaviv_iommu.c
@@ -20,16 +20,11 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/bitops.h>
-#include <linux/version.h>
 
 #include "etnaviv_gpu.h"
 #include "etnaviv_iommu.h"
 #include "state_hi.xml.h"
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
-#define OLD_IOMMU
-#endif
-
 #define PT_SIZE		SZ_512K
 #define PT_ENTRIES	(PT_SIZE / sizeof(uint32_t))
 
@@ -126,33 +121,17 @@ static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
 	return 0;
 }
 
-static void __etnaviv_iommu_free(struct etnaviv_iommu_domain *etnaviv_domain)
+static void etnaviv_domain_free(struct iommu_domain *domain)
 {
-	pgtable_free(&etnaviv_domain->pgtable, PT_SIZE);
+	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);
 }
 
-#ifdef OLD_IOMMU
-static void etnaviv_iommu_domain_destroy(struct iommu_domain *domain)
-{
-	struct etnaviv_iommu_domain *etnaviv_domain = domain->priv;
-
-	__etnaviv_iommu_free(etnaviv_domain);
-
-	domain->priv = NULL;
-}
-#else
-static void etnaviv_domain_free(struct iommu_domain *domain)
-{
-	__etnaviv_iommu_free(to_etnaviv_domain(domain));
-}
-#endif
-
 static int etnaviv_iommu_map(struct iommu_domain *domain, unsigned long iova,
 	   phys_addr_t paddr, size_t size, int prot)
 {
@@ -193,11 +172,7 @@ static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain,
 }
 
 static struct iommu_ops etnaviv_iommu_ops = {
-#ifdef OLD_IOMMU
-		.domain_destroy = etnaviv_iommu_domain_destroy,
-#else
 		.domain_free = etnaviv_domain_free,
-#endif
 		.map = etnaviv_iommu_map,
 		.unmap = etnaviv_iommu_unmap,
 		.iova_to_phys = etnaviv_iommu_iova_to_phys,
@@ -231,9 +206,7 @@ struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu)
 
 	etnaviv_domain->dev = gpu->dev;
 
-#ifndef OLD_IOMMU
 	etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
-#endif
 	etnaviv_domain->domain.ops = &etnaviv_iommu_ops;
 	etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START;
 	etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 04/48] staging: etnaviv: clean up public API (part 2)
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (2 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 03/48] staging: etnaviv: remove compat MMU code Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 05/48] staging: etnaviv: rename last remaining msm_* symbols Lucas Stach
                         ` (44 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

This fixes the preceding patch for updates I have in my tree.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index 093b28503f61..2de6ee0e75b4 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -259,13 +259,6 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, struct etnaviv_gem_ob
 			return -EINVAL;
 		}
 
-		/* Vivante hardware has no need for shifts or bitwise or-ing */
-		if (submit_reloc.shift || submit_reloc.or) {
-			DRM_ERROR("invalid shift or bitwise or at reloc %u\n",
-				  i);
-			return -EINVAL;
-		}
-
 		ret = submit_bo(submit, submit_reloc.reloc_idx, &bobj, &iova);
 		if (ret)
 			return ret;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 05/48] staging: etnaviv: rename last remaining msm_* symbols
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (3 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 04/48] staging: etnaviv: clean up public API (part 2) Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 06/48] staging: etnaviv: rename last remaining bits from msm to etnaviv Lucas Stach
                         ` (43 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Rename the last three msm_* symbols with an etnaviv_ prefix.  This
resolves some build errors when MSM and Etnaviv DRM drivers are both
built into the same kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c       | 6 +++---
 drivers/staging/etnaviv/etnaviv_drv.h       | 6 +++---
 drivers/staging/etnaviv/etnaviv_gem_prime.c | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 1ba480aed4fd..f7c21b45a991 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -532,12 +532,12 @@ static struct drm_driver etnaviv_drm_driver = {
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 	.gem_prime_export   = drm_gem_prime_export,
 	.gem_prime_import   = drm_gem_prime_import,
-	.gem_prime_pin      = msm_gem_prime_pin,
-	.gem_prime_unpin    = msm_gem_prime_unpin,
+	.gem_prime_pin      = etnaviv_gem_prime_pin,
+	.gem_prime_unpin    = etnaviv_gem_prime_unpin,
 	.gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table,
 	.gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
 	.gem_prime_vmap     = etnaviv_gem_prime_vmap,
-	.gem_prime_vunmap   = msm_gem_prime_vunmap,
+	.gem_prime_vunmap   = etnaviv_gem_prime_vunmap,
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init       = etnaviv_debugfs_init,
 	.debugfs_cleanup    = etnaviv_debugfs_cleanup,
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index d26ad84615e5..cde898f33c53 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -82,11 +82,11 @@ int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
 void etnaviv_gem_put_iova(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 msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+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 msm_gem_prime_pin(struct drm_gem_object *obj);
-void msm_gem_prime_unpin(struct drm_gem_object *obj);
+int etnaviv_gem_prime_pin(struct drm_gem_object *obj);
+void etnaviv_gem_prime_unpin(struct drm_gem_object *obj);
 void *etnaviv_gem_vaddr_locked(struct drm_gem_object *obj);
 void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
 dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj);
diff --git a/drivers/staging/etnaviv/etnaviv_gem_prime.c b/drivers/staging/etnaviv/etnaviv_gem_prime.c
index cca569be98bf..58c13ae7c345 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_prime.c
@@ -34,12 +34,12 @@ void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj)
 	return etnaviv_gem_vaddr(obj);
 }
 
-void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 {
 	/* TODO msm_gem_vunmap() */
 }
 
-int msm_gem_prime_pin(struct drm_gem_object *obj)
+int etnaviv_gem_prime_pin(struct drm_gem_object *obj)
 {
 	if (!obj->import_attach) {
 		struct drm_device *dev = obj->dev;
@@ -51,7 +51,7 @@ int msm_gem_prime_pin(struct drm_gem_object *obj)
 	return 0;
 }
 
-void msm_gem_prime_unpin(struct drm_gem_object *obj)
+void etnaviv_gem_prime_unpin(struct drm_gem_object *obj)
 {
 	if (!obj->import_attach) {
 		struct drm_device *dev = obj->dev;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 06/48] staging: etnaviv: rename last remaining bits from msm to etnaviv
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (4 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 05/48] staging: etnaviv: rename last remaining msm_* symbols Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 07/48] staging: etnaviv: quiten down kernel log output Lucas Stach
                         ` (42 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 2 +-
 drivers/staging/etnaviv/etnaviv_gpu.c        | 2 +-
 drivers/staging/etnaviv/etnaviv_gpu.h        | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index 2de6ee0e75b4..2c0eec63e3e1 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -24,7 +24,7 @@
  */
 
 #define BO_INVALID_FLAGS ~(ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE)
-/* make sure these don't conflict w/ MSM_SUBMIT_BO_x */
+/* make sure these don't conflict w/ ETNAVIV_SUBMIT_BO_x */
 #define BO_LOCKED   0x4000
 #define BO_PINNED   0x2000
 
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index c230da7dd526..0a8c0d3845dd 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -718,7 +718,7 @@ static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
 {
 	DBG("%s", dev_name(gpu->dev));
 	mod_timer(&gpu->hangcheck_timer,
-			round_jiffies_up(jiffies + DRM_MSM_HANGCHECK_JIFFIES));
+		  round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES));
 }
 
 static void hangcheck_handler(unsigned long data)
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 458e76d71eb9..9af65edd5bdc 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -123,8 +123,8 @@ struct etnaviv_gpu {
 	struct clk *clk_shader;
 
 	/* Hang Detction: */
-#define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */
-#define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD)
+#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;
 	uint32_t hangcheck_fence;
 	uint32_t hangcheck_dma_addr;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 07/48] staging: etnaviv: quiten down kernel log output
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (5 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 06/48] staging: etnaviv: rename last remaining bits from msm to etnaviv Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 08/48] staging: etnaviv: add proper license header to all files Lucas Stach
                         ` (41 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Christian Gmeiner <christian.gmeiner@gmail.com>

There is no need to spam the kernel logs with the GPU specs and features
at startup. If someone wants to know about this stuff debugfs should be
the right place to look at.

Also use better format specifiers to make it easier for humans to read.

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 64 ++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 31 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 0a8c0d3845dd..c541152a08dc 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -187,27 +187,6 @@ static void etnaviv_hw_specs(struct etnaviv_gpu *gpu)
 		gpu->identity.instruction_count = 256;
 		break;
 	}
-
-	dev_info(gpu->dev, "stream_count:  %x\n",
-		 gpu->identity.stream_count);
-	dev_info(gpu->dev, "register_max: %x\n",
-		 gpu->identity.register_max);
-	dev_info(gpu->dev, "thread_count: %x\n",
-		 gpu->identity.thread_count);
-	dev_info(gpu->dev, "vertex_cache_size: %x\n",
-		 gpu->identity.vertex_cache_size);
-	dev_info(gpu->dev, "shader_core_count: %x\n",
-		 gpu->identity.shader_core_count);
-	dev_info(gpu->dev, "pixel_pipes: %x\n",
-		 gpu->identity.pixel_pipes);
-	dev_info(gpu->dev, "vertex_output_buffer_size: %x\n",
-		 gpu->identity.vertex_output_buffer_size);
-	dev_info(gpu->dev, "buffer_size: %x\n",
-		 gpu->identity.buffer_size);
-	dev_info(gpu->dev, "instruction_count: %x\n",
-		 gpu->identity.instruction_count);
-	dev_info(gpu->dev, "num_constants: %x\n",
-		 gpu->identity.num_constants);
 }
 
 static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
@@ -252,7 +231,7 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
 		}
 	}
 
-	dev_info(gpu->dev, "model: %x - revision %x\n",
+	dev_info(gpu->dev, "model: GC%x, revision: %x\n",
 		 gpu->identity.model, gpu->identity.revision);
 
 	gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE);
@@ -286,15 +265,6 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
 				gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3);
 	}
 
-	dev_info(gpu->dev, "minor_features:  %x\n",
-		 gpu->identity.minor_features0);
-	dev_info(gpu->dev, "minor_features1: %x\n",
-		 gpu->identity.minor_features1);
-	dev_info(gpu->dev, "minor_features2: %x\n",
-		 gpu->identity.minor_features2);
-	dev_info(gpu->dev, "minor_features3: %x\n",
-		 gpu->identity.minor_features3);
-
 	/* GC600 idle register reports zero bits where modules aren't present */
 	if (gpu->identity.model == chipModel_GC600) {
 		gpu->idle_mask = VIVS_HI_IDLE_STATE_TX |
@@ -593,6 +563,38 @@ void etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
 
 	verify_dma(gpu, &debug);
 
+	seq_puts(m, "\tfeatures\n");
+	seq_printf(m, "\t minor_features0: 0x%08x\n",
+		   gpu->identity.minor_features0);
+	seq_printf(m, "\t minor_features1: 0x%08x\n",
+		   gpu->identity.minor_features1);
+	seq_printf(m, "\t minor_features2: 0x%08x\n",
+		   gpu->identity.minor_features2);
+	seq_printf(m, "\t minor_features3: 0x%08x\n",
+		   gpu->identity.minor_features3);
+
+	seq_puts(m, "\tspecs\n");
+	seq_printf(m, "\t stream_count:  %d\n",
+			gpu->identity.stream_count);
+	seq_printf(m, "\t register_max: %d\n",
+			gpu->identity.register_max);
+	seq_printf(m, "\t thread_count: %d\n",
+			gpu->identity.thread_count);
+	seq_printf(m, "\t vertex_cache_size: %d\n",
+			gpu->identity.vertex_cache_size);
+	seq_printf(m, "\t shader_core_count: %d\n",
+			gpu->identity.shader_core_count);
+	seq_printf(m, "\t pixel_pipes: %d\n",
+			gpu->identity.pixel_pipes);
+	seq_printf(m, "\t vertex_output_buffer_size: %d\n",
+			gpu->identity.vertex_output_buffer_size);
+	seq_printf(m, "\t buffer_size: %d\n",
+			gpu->identity.buffer_size);
+	seq_printf(m, "\t instruction_count: %d\n",
+			gpu->identity.instruction_count);
+	seq_printf(m, "\t num_constants: %d\n",
+			gpu->identity.num_constants);
+
 	seq_printf(m, "\taxi: 0x%08x\n", axi);
 	seq_printf(m, "\tidle: 0x%08x\n", idle);
 	idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 08/48] staging: etnaviv: add proper license header to all files
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (6 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 07/48] staging: etnaviv: quiten down kernel log output Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 09/48] staging: etnaviv: add Dove GPU subsystem compatible Lucas Stach
                         ` (40 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_buffer.c     |  2 +-
 drivers/staging/etnaviv/etnaviv_cmd_parser.c | 16 ++++++++++++++++
 drivers/staging/etnaviv/etnaviv_drv.c        |  3 +--
 drivers/staging/etnaviv/etnaviv_drv.h        |  3 +--
 drivers/staging/etnaviv/etnaviv_gem.c        |  3 +--
 drivers/staging/etnaviv/etnaviv_gem.h        |  3 +--
 drivers/staging/etnaviv/etnaviv_gem_submit.c |  3 +--
 drivers/staging/etnaviv/etnaviv_gpu.c        |  3 +--
 drivers/staging/etnaviv/etnaviv_gpu.h        |  3 +--
 drivers/staging/etnaviv/etnaviv_mmu.c        |  3 +--
 drivers/staging/etnaviv/etnaviv_mmu.h        |  3 +--
 11 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
index 85a5a15f0e02..816dc0c4a287 100644
--- a/drivers/staging/etnaviv/etnaviv_buffer.c
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 2014 Etnaviv Project
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_cmd_parser.c b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
index b429451baca5..d866b8e2381d 100644
--- a/drivers/staging/etnaviv/etnaviv_cmd_parser.c
+++ b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
@@ -1,3 +1,19 @@
+/*
+ * 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"
diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index f7c21b45a991..5a53c6969fcd 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index cde898f33c53..9abb7f8c2dc0 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 22407846320b..0b823a9566d3 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index c801b9a161e6..397b30f39708 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index 2c0eec63e3e1..eb3c5bd68418 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index c541152a08dc..dd885870cc7c 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 9af65edd5bdc..e0068cc7b7d6 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
index 6da6b8e0c6e5..ec01c8a560f4 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.c
+++ b/drivers/staging/etnaviv/etnaviv_mmu.c
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.h b/drivers/staging/etnaviv/etnaviv_mmu.h
index a8e48b2a61dc..94dbab736fc1 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.h
+++ b/drivers/staging/etnaviv/etnaviv_mmu.h
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
+ * 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
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 09/48] staging: etnaviv: add Dove GPU subsystem compatible
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (7 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 08/48] staging: etnaviv: add proper license header to all files Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 10/48] staging: etnaviv: fix missing error cleanups in etnaviv_load() Lucas Stach
                         ` (39 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 5a53c6969fcd..b2ce4a6467ed 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -622,6 +622,7 @@ static int etnaviv_pdev_remove(struct platform_device *pdev)
 
 static const struct of_device_id dt_match[] = {
 	{ .compatible = "fsl,imx-gpu-subsystem" },
+	{ .compatible = "marvell,dove-gpu-subsystem" },
 	{}
 };
 MODULE_DEVICE_TABLE(of, dt_match);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 10/48] staging: etnaviv: fix missing error cleanups in etnaviv_load()
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (8 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 09/48] staging: etnaviv: add Dove GPU subsystem compatible Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 11/48] staging: etnaviv: fix off-by-one for iommu aperture end Lucas Stach
                         ` (38 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

The only failure which etnaviv_load() implemented was for kzalloc().
Other failures (alloc_ordered_workqueue(), component_bind_all()) were
not implemented.  Add these.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index b2ce4a6467ed..8dcd7f19ecff 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -128,6 +128,11 @@ static int etnaviv_load(struct drm_device *dev, unsigned long flags)
 	dev->dev_private = priv;
 
 	priv->wq = alloc_ordered_workqueue("etnaviv", 0);
+	if (!priv->wq) {
+		err = -ENOMEM;
+		goto err_wq;
+	}
+
 	init_waitqueue_head(&priv->fence_event);
 
 	INIT_LIST_HEAD(&priv->inactive_list);
@@ -137,11 +142,18 @@ static int etnaviv_load(struct drm_device *dev, unsigned long flags)
 
 	err = component_bind_all(dev->dev, dev);
 	if (err < 0)
-		return err;
+		goto err_bind;
 
 	load_gpu(dev);
 
 	return 0;
+
+err_bind:
+	flush_workqueue(priv->wq);
+	destroy_workqueue(priv->wq);
+err_wq:
+	kfree(priv);
+	return err;
 }
 
 static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 11/48] staging: etnaviv: fix off-by-one for iommu aperture end
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (9 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 10/48] staging: etnaviv: fix missing error cleanups in etnaviv_load() Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 12/48] staging: etnaviv: avoid lockdep circular dependency warning Lucas Stach
                         ` (37 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

The aperture end address is inclusive, not exclusive.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
index 8f92578ea3ee..8aff23a310fb 100644
--- a/drivers/staging/etnaviv/etnaviv_iommu.c
+++ b/drivers/staging/etnaviv/etnaviv_iommu.c
@@ -209,7 +209,7 @@ struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu)
 	etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
 	etnaviv_domain->domain.ops = &etnaviv_iommu_ops;
 	etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START;
-	etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K;
+	etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K - 1;
 
 	ret = __etnaviv_iommu_init(etnaviv_domain);
 	if (ret)
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 12/48] staging: etnaviv: avoid lockdep circular dependency warning
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (10 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 11/48] staging: etnaviv: fix off-by-one for iommu aperture end Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 12:20         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 13/48] staging: etnaviv: fix gpu debugfs show implementation Lucas Stach
                         ` (36 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Avoid the below circular dependency warning by avoiding calling
pm_runtime_get_sync() at a point where struct_mutex is held, and we
may well provoke the power domain to be resumed.

We avoid this simply by referencing the runtime PM in the
etnaviv_gem_submit() function just before we take the lock, and
drop it after we drop the lock.  We leave the rest of the runtime
PM management in place - the runtime PM inside etnaviv_gpu_submit()
won't trigger a resume as the resume will have been done by
etnaviv_gem_submit() outside of the lock.

======================================================
[ INFO: possible circular locking dependency detected ]
4.1.0-rc2+ #1618 Not tainted
-------------------------------------------------------
bash/1261 is trying to acquire lock:
 (&mm->mmap_sem){++++++}, at: [<c010d9bc>] might_fault+0x44/0x98

but task is already holding lock:
 (&sb->s_type->i_mutex_key#3){+.+.+.}, at: [<c013f940>] iterate_dir+0x3c/0x108

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #6 (&sb->s_type->i_mutex_key#3){+.+.+.}:
       [<c075c084>] mutex_lock_nested+0x5c/0x3dc
       [<c02c4204>] start_creating+0x58/0xb4
       [<c02c4330>] debugfs_create_dir+0x14/0xcc
       [<c035ba3c>] create_regulator+0xcc/0x1fc
       [<c035db54>] _regulator_get+0x10c/0x208
       [<c035dc68>] regulator_get_optional+0x18/0x1c
       [<c035ecc0>] _devm_regulator_get+0x84/0xc0
       [<c035ed10>] devm_regulator_get_optional+0x14/0x18
       [<c0026594>] imx_gpc_probe+0x20/0x110
       [<c03cfb3c>] platform_drv_probe+0x50/0xac
       [<c03ce230>] driver_probe_device+0x1d4/0x278
       [<c03ce370>] __driver_attach+0x9c/0xa0
       [<c03cc794>] bus_for_each_dev+0x5c/0x90
       [<c03cdc50>] driver_attach+0x24/0x28
       [<c03cd8a4>] bus_add_driver+0xe0/0x1dc
       [<c03ceb9c>] driver_register+0x80/0xfc
       [<c03cf9c4>] __platform_driver_register+0x50/0x64
       [<c09f2948>] imx_pgc_init+0x18/0x20
       [<c00097bc>] do_one_initcall+0x88/0x1dc
       [<c09e9e4c>] kernel_init_freeable+0x114/0x1e0
       [<c0751720>] kernel_init+0x10/0xec
       [<c000fa78>] ret_from_fork+0x14/0x3c

-> #5 (&rdev->mutex){+.+.+.}:
       [<c075c084>] mutex_lock_nested+0x5c/0x3dc
       [<c035d830>] regulator_enable+0x48/0x12c
       [<c0026230>] imx6q_pm_pu_power_on+0x20/0x170
       [<c03ddc48>] genpd_power_on+0x38/0xf4
       [<c03df0e4>] __pm_genpd_poweron+0x1a4/0x1b4
       [<c03def2c>] pm_genpd_poweron+0x28/0x3c
       [<c03df64c>] genpd_dev_pm_attach+0xb4/0x12c
       [<c03d54d0>] dev_pm_domain_attach+0x10/0x14
       [<c03cfb20>] platform_drv_probe+0x34/0xac
       [<c03ce230>] driver_probe_device+0x1d4/0x278
       [<c03ce370>] __driver_attach+0x9c/0xa0
       [<c03cc794>] bus_for_each_dev+0x5c/0x90
       [<c03cdc50>] driver_attach+0x24/0x28
       [<c03cd8a4>] bus_add_driver+0xe0/0x1dc
       [<c03ceb9c>] driver_register+0x80/0xfc
       [<c03cf9c4>] __platform_driver_register+0x50/0x64
       [<c0a2701c>] etnaviv_init+0x18/0x4c
       [<c00097bc>] do_one_initcall+0x88/0x1dc
       [<c09e9e4c>] kernel_init_freeable+0x114/0x1e0
       [<c0751720>] kernel_init+0x10/0xec
       [<c000fa78>] ret_from_fork+0x14/0x3c

-> #4 (&genpd->lock){+.+...}:
       [<c075c084>] mutex_lock_nested+0x5c/0x3dc
       [<c03df18c>] pm_genpd_runtime_resume+0x98/0x230
       [<c03d6828>] __rpm_callback+0x3c/0x78
       [<c03d6894>] rpm_callback+0x30/0x90
       [<c03d78d4>] rpm_resume+0x3c4/0x5a4
       [<c03d7d50>] __pm_runtime_resume+0x70/0x90
       [<c053de14>] etnaviv_gpu_submit+0x30/0x220
       [<c053c1c8>] etnaviv_ioctl_gem_submit+0x9a4/0xaf0
       [<c03a01c4>] drm_ioctl+0x2a4/0x4e4
       [<c013efb4>] do_vfs_ioctl+0x84/0x66c
       [<c013f5d8>] SyS_ioctl+0x3c/0x60
       [<c000f9a0>] ret_fast_syscall+0x0/0x54

-> #3 (reservation_ww_class_mutex){+.+.+.}:
       [<c075c468>] __ww_mutex_lock_interruptible+0x64/0x6f8
       [<c053bca0>] etnaviv_ioctl_gem_submit+0x47c/0xaf0
       [<c03a01c4>] drm_ioctl+0x2a4/0x4e4
       [<c013efb4>] do_vfs_ioctl+0x84/0x66c
       [<c013f5d8>] SyS_ioctl+0x3c/0x60
       [<c000f9a0>] ret_fast_syscall+0x0/0x54

-> #2 (reservation_ww_class_acquire){+.+.+.}:
       [<c053b990>] etnaviv_ioctl_gem_submit+0x16c/0xaf0
       [<c03a01c4>] drm_ioctl+0x2a4/0x4e4
       [<c013efb4>] do_vfs_ioctl+0x84/0x66c
       [<c013f5d8>] SyS_ioctl+0x3c/0x60
       [<c000f9a0>] ret_fast_syscall+0x0/0x54

-> #1 (&dev->struct_mutex){+.+.+.}:
       [<c075c084>] mutex_lock_nested+0x5c/0x3dc
       [<c039ea20>] drm_gem_mmap+0x3c/0xe0
       [<c03bb724>] drm_gem_cma_mmap+0x14/0x2c
       [<c0115bf4>] mmap_region+0x3d0/0x6a4
       [<c01161ac>] do_mmap_pgoff+0x2e4/0x374
       [<c0101764>] vm_mmap_pgoff+0x6c/0x9c
       [<c011475c>] SyS_mmap_pgoff+0x94/0xb8
       [<c000f9a0>] ret_fast_syscall+0x0/0x54

-> #0 (&mm->mmap_sem){++++++}:
       [<c006d880>] lock_acquire+0xa0/0x120
       [<c010d9dc>] might_fault+0x64/0x98
       [<c013f670>] filldir64+0x74/0x184
       [<c01555f4>] dcache_readdir+0x1c8/0x28c
       [<c013f98c>] iterate_dir+0x88/0x108
       [<c013fb7c>] SyS_getdents64+0x7c/0xec
       [<c000f9a0>] ret_fast_syscall+0x0/0x54

other info that might help us debug this:

Chain exists of:
  &mm->mmap_sem --> &rdev->mutex --> &sb->s_type->i_mutex_key#3

 Possible unsafe locking scenario:

       CPU0                    CPU1
       ----                    ----
  lock(&sb->s_type->i_mutex_key#3);
                               lock(&rdev->mutex);
                               lock(&sb->s_type->i_mutex_key#3);
  lock(&mm->mmap_sem);

 *** DEADLOCK ***

1 lock held by bash/1261:
 #0:  (&sb->s_type->i_mutex_key#3){+.+.+.}, at: [<c013f940>] iterate_dir+0x3c/0x108

stack backtrace:
CPU: 0 PID: 1261 Comm: bash Not tainted 4.1.0-rc2+ #1618
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
Backtrace:
[<c00130c8>] (dump_backtrace) from [<c0013264>] (show_stack+0x18/0x1c)
 r6:c0c27a28 r5:c0c26d68 r4:00000000 r3:00000000
[<c001324c>] (show_stack) from [<c0757dd4>] (dump_stack+0x7c/0x98)
[<c0757d58>] (dump_stack) from [<c0754e90>] (print_circular_bug+0x28c/0x2e0)
 r4:c0c39e58 r3:ecd43200
[<c0754c04>] (print_circular_bug) from [<c006d024>] (__lock_acquire+0x1944/0x1c34)
 r10:c14aee7c r8:ecd436a0 r7:ecd43200 r6:c149d2dc r5:00000001 r4:ecd436b8
[<c006b6e0>] (__lock_acquire) from [<c006d880>] (lock_acquire+0xa0/0x120)
 r10:c0aeab14 r9:60070013 r8:00000001 r7:00000000 r6:00000000 r5:ed244e88
 r4:00000000
[<c006d7e0>] (lock_acquire) from [<c010d9dc>] (might_fault+0x64/0x98)
 r10:edc02508 r9:00000000 r8:0000001c r7:00000018 r6:00000001 r5:00d16028
 r4:00000000
[<c010d978>] (might_fault) from [<c013f670>] (filldir64+0x74/0x184)
 r4:eb935f60
[<c013f5fc>] (filldir64) from [<c01555f4>] (dcache_readdir+0x1c8/0x28c)
 r10:edc02508 r9:eb935f60 r8:e6d1b09c r7:e8074780 r6:e6d1b000 r5:eb935f60
 r4:edc02508
[<c015542c>] (dcache_readdir) from [<c013f98c>] (iterate_dir+0x88/0x108)
 r10:edc044b8 r9:eb935f60 r8:e8074788 r7:00000000 r6:e8074780 r5:00000000
 r4:00000000
[<c013f904>] (iterate_dir) from [<c013fb7c>] (SyS_getdents64+0x7c/0xec)
 r10:00000000 r9:eb934000 r8:e8074780 r7:e8074780 r6:00008000 r5:00d16008
 r4:000a6b4c
[<c013fb00>] (SyS_getdents64) from [<c000f9a0>] (ret_fast_syscall+0x0/0x54)
 r10:00000000 r8:c000fb84 r7:000000d9 r6:00d1600c r5:00d16008 r4:000a6b4c

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 23 +++++++++++++++++++++++
 drivers/staging/etnaviv/etnaviv_gpu.c        | 25 ++++++++++++++++++++++++-
 drivers/staging/etnaviv/etnaviv_gpu.h        |  2 ++
 3 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index eb3c5bd68418..647d16fee98b 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -313,6 +313,27 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	if (args->nr_cmds > MAX_CMDS)
 		return -EINVAL;
 
+	/*
+	 * Avoid big circular locking dependency loops:
+	 * - reading debugfs results in mmap_sem depending on i_mutex_key#3
+	 *   (iterate_dir -> filldir64)
+	 * - struct_mutex depends on mmap_sem
+	 *   (vm_mmap_pgoff -> drm_gem_mmap)
+	 * then if we try to do a get_sync() under struct_mutex,
+	 * - genpd->lock depends on struct_mutex
+	 *   (etnaviv_ioctl_gem_submit -> pm_genpd_runtime_resume)
+	 * - (regulator) rdev->mutex depends on genpd->lock
+	 *   (pm_genpd_poweron -> regulator_enable)
+	 * - i_mutex_key#3 depends on rdev->mutex
+	 *   (create_regulator -> debugfs::start_creating)
+	 * and lockdep rightfully explodes.
+	 *
+	 * Avoid this by getting runtime PM outside of the struct_mutex lock.
+	 */
+	ret = etnaviv_gpu_pm_get_sync(gpu);
+	if (ret < 0)
+		return ret;
+
 	mutex_lock(&dev->struct_mutex);
 
 	submit = submit_create(dev, gpu, args->nr_bos);
@@ -412,6 +433,8 @@ out:
 		submit_cleanup(submit, !!ret);
 	mutex_unlock(&dev->struct_mutex);
 
+	etnaviv_gpu_pm_put(gpu);
+
 	/*
 	 * If we're returning -EAGAIN, it could be due to the userptr code
 	 * wanting to run its workqueue outside of the struct_mutex.
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index dd885870cc7c..570bcd60025b 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -857,6 +857,17 @@ void etnaviv_gpu_retire(struct etnaviv_gpu *gpu)
 	queue_work(priv->wq, &gpu->retire_work);
 }
 
+int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu)
+{
+	return pm_runtime_get_sync(gpu->dev);
+}
+
+void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu)
+{
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
+}
+
 /* add bo's to gpu's ring, and kick gpu: */
 int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 	struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx)
@@ -1234,15 +1245,27 @@ static int etnaviv_gpu_rpm_suspend(struct device *dev)
 static int etnaviv_gpu_rpm_resume(struct device *dev)
 {
 	struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+	struct drm_device *drm = gpu->drm;
 	int ret;
 
+	/* We must never runtime-PM resume holding struct_mutex */
+	if (drm && WARN_ON_ONCE(mutex_is_locked(&drm->struct_mutex)))
+		return -EDEADLK;
+
 	ret = etnaviv_gpu_resume(gpu);
 	if (ret)
 		return ret;
 
 	/* Re-initialise the basic hardware state */
-	if (gpu->drm && gpu->buffer)
+	if (drm && gpu->buffer) {
+		ret = mutex_lock_killable(&drm->struct_mutex);
+		if (ret) {
+			etnaviv_gpu_suspend(gpu);
+			return ret;
+		}
 		etnaviv_gpu_hw_init(gpu);
+		mutex_unlock(&drm->struct_mutex);
+	}
 
 	return 0;
 }
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index e0068cc7b7d6..21e45e875e73 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -152,6 +152,8 @@ void etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
 int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 	struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx);
+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;
 
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 13/48] staging: etnaviv: fix gpu debugfs show implementation
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (11 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 12/48] staging: etnaviv: avoid lockdep circular dependency warning Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 14/48] staging: etnaviv: use vm_insert_page() rather than vm_insert_mixed() Lucas Stach
                         ` (35 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 43 ++++++++++++++++++++---------------
 drivers/staging/etnaviv/etnaviv_gpu.c | 21 ++++++++++++++---
 drivers/staging/etnaviv/etnaviv_gpu.h |  2 +-
 3 files changed, 44 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 8dcd7f19ecff..1071c449f3d4 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -187,23 +187,6 @@ static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file)
  */
 
 #ifdef CONFIG_DEBUG_FS
-static int etnaviv_gpu_show(struct drm_device *dev, struct seq_file *m)
-{
-	struct etnaviv_drm_private *priv = dev->dev_private;
-	struct etnaviv_gpu *gpu;
-	unsigned int i;
-
-	for (i = 0; i < ETNA_MAX_PIPES; i++) {
-		gpu = priv->gpu[i];
-		if (gpu) {
-			seq_printf(m, "%s Status:\n", dev_name(gpu->dev));
-			etnaviv_gpu_debugfs(gpu, m);
-		}
-	}
-
-	return 0;
-}
-
 static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
 {
 	struct etnaviv_drm_private *priv = dev->dev_private;
@@ -266,8 +249,32 @@ static int show_locked(struct seq_file *m, void *arg)
 	return ret;
 }
 
+static int show_each_gpu(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gpu *gpu;
+	int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
+			node->info_ent->data;
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		gpu = priv->gpu[i];
+		if (!gpu)
+			continue;
+
+		ret = show(gpu, m);
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
 static struct drm_info_list etnaviv_debugfs_list[] = {
-		{"gpu", show_locked, 0, etnaviv_gpu_show},
+		{"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs},
 		{"gem", show_locked, 0, etnaviv_gem_show},
 		{ "mm", show_locked, 0, etnaviv_mm_show },
 		{"mmu", show_locked, 0, etnaviv_mmu_show},
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 570bcd60025b..9f4e99855517 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -547,13 +547,21 @@ static void verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug)
 	}
 }
 
-void etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
+int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
 {
 	struct dma_debug debug;
 	u32 dma_lo, dma_hi, axi, idle;
+	int ret;
+
+	seq_printf(m, "%s Status:\n", dev_name(gpu->dev));
+
+	ret = pm_runtime_get_sync(gpu->dev);
+	if (ret < 0)
+		return ret;
 
-	if (pm_runtime_get_sync(gpu->dev) < 0)
-		return;
+	ret = mutex_lock_interruptible(&gpu->drm->struct_mutex);
+	if (ret < 0)
+		goto err_rpm;
 
 	dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW);
 	dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH);
@@ -653,8 +661,15 @@ void etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
 	seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n",
 		   dma_lo, dma_hi);
 
+	ret = 0;
+
+	mutex_unlock(&gpu->drm->struct_mutex);
+
+err_rpm:
 	pm_runtime_mark_last_busy(gpu->dev);
 	pm_runtime_put_autosuspend(gpu->dev);
+
+	return ret;
 }
 #endif
 
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 21e45e875e73..6b4f241c0ca6 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -146,7 +146,7 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, uint32_t param,
 int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
 
 #ifdef CONFIG_DEBUG_FS
-void etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
+int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
 #endif
 
 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 14/48] staging: etnaviv: use vm_insert_page() rather than vm_insert_mixed()
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (12 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 13/48] staging: etnaviv: fix gpu debugfs show implementation Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 15/48] staging: etnaviv: etnaviv_gem_fault: reduce struct_mutex exposure Lucas Stach
                         ` (34 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

We're only ever going to insert using a pointer to a struct page.  Use
vm_insert_page() rather than converting back and forth between a
struct page and a PFN.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 0b823a9566d3..69360c899b78 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -217,8 +217,7 @@ int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct drm_device *dev = obj->dev;
-	struct page **pages;
-	unsigned long pfn;
+	struct page **pages, *page;
 	pgoff_t pgoff;
 	int ret;
 
@@ -240,12 +239,12 @@ int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 	pgoff = ((unsigned long)vmf->virtual_address -
 			vma->vm_start) >> PAGE_SHIFT;
 
-	pfn = page_to_pfn(pages[pgoff]);
+	page = pages[pgoff];
 
 	VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
-			pfn, pfn << PAGE_SHIFT);
+	     page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT);
 
-	ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
+	ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
 
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 15/48] staging: etnaviv: etnaviv_gem_fault: reduce struct_mutex exposure
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (13 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 14/48] staging: etnaviv: use vm_insert_page() rather than vm_insert_mixed() Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 16/48] staging: etnaviv: give etnaviv_gem_mmap_offset() a sane behaviour Lucas Stach
                         ` (33 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Reduce the exposure of struct_mutex to an absolute minimum.  We only
need to take this lock over the call to etnaviv_gem_get_pages() as
vm_insert_page() already does a properly synchronised update of the
PTE (using the pte table lock.)

Reducing the code covered by this lock allows for more parallel
execution in SMP environments.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 69360c899b78..522e5a6c3612 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -221,8 +221,10 @@ int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 	pgoff_t pgoff;
 	int ret;
 
-	/* Make sure we don't parallel update on a fault, nor move or remove
-	 * something from beneath our feet
+	/*
+	 * Make sure we don't parallel update on a fault, nor move or remove
+	 * something from beneath our feet.  Note that vm_insert_page() is
+	 * specifically coded to take care of this, so we don't have to.
 	 */
 	ret = mutex_lock_interruptible(&dev->struct_mutex);
 	if (ret)
@@ -230,9 +232,11 @@ int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
 	/* make sure we have pages attached now */
 	pages = etnaviv_gem_get_pages(to_etnaviv_bo(obj));
+	mutex_unlock(&dev->struct_mutex);
+
 	if (IS_ERR(pages)) {
 		ret = PTR_ERR(pages);
-		goto out_unlock;
+		goto out;
 	}
 
 	/* We don't use vmf->pgoff since that has the fake offset: */
@@ -246,8 +250,6 @@ int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
 	ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
 
-out_unlock:
-	mutex_unlock(&dev->struct_mutex);
 out:
 	switch (ret) {
 	case -EAGAIN:
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 16/48] staging: etnaviv: give etnaviv_gem_mmap_offset() a sane behaviour
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (14 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 15/48] staging: etnaviv: etnaviv_gem_fault: reduce struct_mutex exposure Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 17/48] staging: etnaviv: allow etnaviv_ioctl_gem_info() locking to be interruptible Lucas Stach
                         ` (32 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

etnaviv_gem_mmap_offset() returned zero if drm_gem_create_mmap_offset()
failed.  This is incorrect behaviour as etnaviv_ioctl_gem_info() does
not detect this condition, so it returns success.

Fix this by re-architecting etnaviv_gem_mmap_offset().  Merge
mmap_offset() into this function, and change its prototype to accept a
pointer to the "offset" return value, thereby allowing it to return a
standard negative errno code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c |  4 ++--
 drivers/staging/etnaviv/etnaviv_drv.h |  2 +-
 drivers/staging/etnaviv/etnaviv_gem.c | 26 +++++++-------------------
 3 files changed, 10 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 1071c449f3d4..9962318075c5 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -438,7 +438,7 @@ static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
 {
 	struct drm_etnaviv_gem_info *args = data;
 	struct drm_gem_object *obj;
-	int ret = 0;
+	int ret;
 
 	if (args->pad)
 		return -EINVAL;
@@ -447,7 +447,7 @@ static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
 	if (!obj)
 		return -ENOENT;
 
-	args->offset = etnaviv_gem_mmap_offset(obj);
+	ret = etnaviv_gem_mmap_offset(obj, &args->offset);
 
 	drm_gem_object_unreference_unlocked(obj);
 
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index 9abb7f8c2dc0..37992342bbf0 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -73,7 +73,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 
 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);
-uint64_t etnaviv_gem_mmap_offset(struct drm_gem_object *obj);
+int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, uint64_t *offset);
 int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
 	struct drm_gem_object *obj, uint32_t *iova);
 int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 522e5a6c3612..38dee80d996c 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -270,33 +270,21 @@ out:
 }
 
 /** get mmap offset */
-static uint64_t mmap_offset(struct drm_gem_object *obj)
+int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, uint64_t *offset)
 {
 	struct drm_device *dev = obj->dev;
 	int ret;
 
-	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
+	mutex_lock(&dev->struct_mutex);
 	/* Make it mmapable */
 	ret = drm_gem_create_mmap_offset(obj);
-
-	if (ret) {
+	if (ret)
 		dev_err(dev->dev, "could not allocate mmap offset\n");
-		return 0;
-	}
-
-	return drm_vma_node_offset_addr(&obj->vma_node);
-}
-
-uint64_t etnaviv_gem_mmap_offset(struct drm_gem_object *obj)
-{
-	uint64_t offset;
-
-	mutex_lock(&obj->dev->struct_mutex);
-	offset = mmap_offset(obj);
-	mutex_unlock(&obj->dev->struct_mutex);
+	else
+		*offset = drm_vma_node_offset_addr(&obj->vma_node);
+	mutex_unlock(&dev->struct_mutex);
 
-	return offset;
+	return ret;
 }
 
 /* should be called under struct_mutex.. although it can be called
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 17/48] staging: etnaviv: allow etnaviv_ioctl_gem_info() locking to be interruptible
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (15 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 16/48] staging: etnaviv: give etnaviv_gem_mmap_offset() a sane behaviour Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 18/48] staging: etnaviv: make context a per-GPU thing Lucas Stach
                         ` (31 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Move the locking out of etnaviv_gem_mmap_offset() into its solitary
caller, and take the mutex using mutex_lock_interruptible().  This
allows etnaviv_ioctl_gem_info() to handle signals while trying to
obtain this lock.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 7 ++++++-
 drivers/staging/etnaviv/etnaviv_gem.c | 7 ++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 9962318075c5..a87de2e79fee 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -447,7 +447,12 @@ static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
 	if (!obj)
 		return -ENOENT;
 
-	ret = etnaviv_gem_mmap_offset(obj, &args->offset);
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret == 0) {
+		ret = etnaviv_gem_mmap_offset(obj, &args->offset);
+
+		mutex_unlock(&dev->struct_mutex);
+	}
 
 	drm_gem_object_unreference_unlocked(obj);
 
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 38dee80d996c..b1984a4ac0c5 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -269,20 +269,17 @@ out:
 	}
 }
 
-/** get mmap offset */
+/* get mmap offset - must be called under struct_mutex */
 int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, uint64_t *offset)
 {
-	struct drm_device *dev = obj->dev;
 	int ret;
 
-	mutex_lock(&dev->struct_mutex);
 	/* Make it mmapable */
 	ret = drm_gem_create_mmap_offset(obj);
 	if (ret)
-		dev_err(dev->dev, "could not allocate mmap offset\n");
+		dev_err(obj->dev->dev, "could not allocate mmap offset\n");
 	else
 		*offset = drm_vma_node_offset_addr(&obj->vma_node);
-	mutex_unlock(&dev->struct_mutex);
 
 	return ret;
 }
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 18/48] staging: etnaviv: make context a per-GPU thing
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (16 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 17/48] staging: etnaviv: allow etnaviv_ioctl_gem_info() locking to be interruptible Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 19/48] staging: etnaviv: switch to per-GPU fence completion implementation Lucas Stach
                         ` (30 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Tracking the current context on a system wide level is incorrect: if the
context for one GPU core changes, the context does not change on other
GPU cores.  Make the context tracking a per-GPU thing.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 9 +++++++--
 drivers/staging/etnaviv/etnaviv_drv.h | 1 -
 drivers/staging/etnaviv/etnaviv_gpu.c | 5 ++---
 drivers/staging/etnaviv/etnaviv_gpu.h | 1 +
 4 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index a87de2e79fee..7ec4b224b589 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -173,10 +173,15 @@ static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file)
 {
 	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct etnaviv_file_private *ctx = file->driver_priv;
+	unsigned int i;
 
 	mutex_lock(&dev->struct_mutex);
-	if (ctx == priv->lastctx)
-		priv->lastctx = NULL;
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		struct etnaviv_gpu *gpu = priv->gpu[i];
+
+		if (gpu && gpu->lastctx == ctx)
+			gpu->lastctx = NULL;
+	}
 	mutex_unlock(&dev->struct_mutex);
 
 	kfree(ctx);
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index 37992342bbf0..f7aff4b2562c 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -52,7 +52,6 @@ struct etnaviv_file_private {
 struct etnaviv_drm_private {
 	int num_gpus;
 	struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
-	struct etnaviv_file_private *lastctx;
 
 	uint32_t next_fence, completed_fence;
 	wait_queue_head_t fence_event;
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 9f4e99855517..2dbf25121a07 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -916,15 +916,14 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 
 	gpu->submitted_fence = submit->fence;
 
-	if (priv->lastctx != ctx) {
+	if (gpu->lastctx != ctx) {
 		gpu->mmu->need_flush = true;
 		gpu->switch_context = true;
+		gpu->lastctx = ctx;
 	}
 
 	etnaviv_buffer_queue(gpu, event, submit);
 
-	priv->lastctx = ctx;
-
 	for (i = 0; i < submit->nr_bos; i++) {
 		struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
 
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 6b4f241c0ca6..67f6097ba576 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -87,6 +87,7 @@ struct etnaviv_gpu {
 	struct drm_device *drm;
 	struct device *dev;
 	struct etnaviv_chip_identity identity;
+	struct etnaviv_file_private *lastctx;
 	bool switch_context;
 
 	/* 'ring'-buffer: */
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 19/48] staging: etnaviv: switch to per-GPU fence completion implementation
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (17 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 18/48] staging: etnaviv: make context a per-GPU thing Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 20/48] staging: etnaviv: provide etnaviv_queue_work() Lucas Stach
                         ` (29 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Having a global fence completion implementation in the presence of
mutliple GPU cores which can complete out of order is buggy.  Consider
the case of two processes submitting work for two GPU cores:

	GPU A				GPU B
	priv->completed_fence = 0
	gpu->submitted_fence = 0	gpu->submitted_fence = 0
	gpu->retired_fence = 0		gpu->retired_fence = 0

	process A submits work,
	allocated fence 1,
	gpu->submitted_fence = 1,
	priv->next_fence = 2
					process B submits work,
					allocated fence 2,
					gpu->submitted_fence = 2,
					priv->next_fence = 3

					GPU B finishes,
					gpu->retired_fence = 2
					runs work queue,
					priv->completed_fence = 2

At this point, GPU A's buffers have fence 1, and when tested by
etnaviv_wait_fence_interruptable(), it compares fence 1 to the global
priv->completed_fence, and decides that GPU A has also finished its
work.

This is plainly incorrect at this point.

Solve this by moving etnaviv_wait_fence_interruptable() into the GPU
code, and arrange for it to decide whether the fence has completed
based upon the GPUs submitted and retired fence markers.

This allows us to get rid of the global priv->completed_fence, and
change the global fence wait queue to a per-GPU fence wait queue, thus
avoiding disturbing sleepers on other (busy) GPUs.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 64 ++---------------------------------
 drivers/staging/etnaviv/etnaviv_drv.h |  8 +----
 drivers/staging/etnaviv/etnaviv_gem.c |  7 ++--
 drivers/staging/etnaviv/etnaviv_gpu.c | 44 ++++++++++++++++++++++--
 drivers/staging/etnaviv/etnaviv_gpu.h | 12 ++++++-
 5 files changed, 58 insertions(+), 77 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 7ec4b224b589..4f97bb667278 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -133,8 +133,6 @@ static int etnaviv_load(struct drm_device *dev, unsigned long flags)
 		goto err_wq;
 	}
 
-	init_waitqueue_head(&priv->fence_event);
-
 	INIT_LIST_HEAD(&priv->inactive_list);
 	priv->num_gpus = 0;
 
@@ -310,64 +308,6 @@ static void etnaviv_debugfs_cleanup(struct drm_minor *minor)
 #endif
 
 /*
- * Fences:
- */
-int etnaviv_wait_fence_interruptable(struct drm_device *dev,
-		struct etnaviv_gpu *gpu, uint32_t fence,
-		struct timespec *timeout)
-{
-	struct etnaviv_drm_private *priv = dev->dev_private;
-	int ret;
-
-	if (fence_after(fence, gpu->submitted_fence)) {
-		DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
-				fence, gpu->submitted_fence);
-		return -EINVAL;
-	}
-
-	if (!timeout) {
-		/* no-wait: */
-		ret = fence_completed(dev, fence) ? 0 : -EBUSY;
-	} else {
-		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;
-
-		ret = wait_event_interruptible_timeout(priv->fence_event,
-				fence_completed(dev, fence),
-				remaining_jiffies);
-
-		if (ret == 0) {
-			DBG("timeout waiting for fence: %u (completed: %u)",
-					fence, priv->completed_fence);
-			ret = -ETIMEDOUT;
-		} else if (ret != -ERESTARTSYS) {
-			ret = 0;
-		}
-	}
-
-	return ret;
-}
-
-/* called from workqueue */
-void etnaviv_update_fence(struct drm_device *dev, uint32_t fence)
-{
-	struct etnaviv_drm_private *priv = dev->dev_private;
-
-	mutex_lock(&dev->struct_mutex);
-	if (fence_after(fence, priv->completed_fence))
-		priv->completed_fence = fence;
-	mutex_unlock(&dev->struct_mutex);
-
-	wake_up_all(&priv->fence_event);
-}
-
-/*
  * DRM ioctls:
  */
 
@@ -478,8 +418,8 @@ static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
 	if (!gpu)
 		return -ENXIO;
 
-	return etnaviv_wait_fence_interruptable(dev, gpu,
-		args->fence, &TS(args->timeout));
+	return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
+						    &TS(args->timeout));
 }
 
 static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index f7aff4b2562c..98536090e947 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -53,8 +53,7 @@ struct etnaviv_drm_private {
 	int num_gpus;
 	struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
 
-	uint32_t next_fence, completed_fence;
-	wait_queue_head_t fence_event;
+	uint32_t next_fence;
 
 	/* list of GEM objects: */
 	struct list_head inactive_list;
@@ -62,11 +61,6 @@ struct etnaviv_drm_private {
 	struct workqueue_struct *wq;
 };
 
-int etnaviv_wait_fence_interruptable(struct drm_device *dev,
-		struct etnaviv_gpu *gpu, uint32_t fence,
-		struct timespec *timeout);
-void etnaviv_update_fence(struct drm_device *dev, uint32_t fence);
-
 int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		struct drm_file *file);
 
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index b1984a4ac0c5..aaa0f5eaeabd 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -429,13 +429,11 @@ void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj)
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
 		struct timespec *timeout)
 {
-
-	struct drm_device *dev = obj->dev;
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-
 	int ret = 0;
 
 	if (is_active(etnaviv_obj)) {
+		struct etnaviv_gpu *gpu = etnaviv_obj->gpu;
 		uint32_t fence = 0;
 
 		if (op & ETNA_PREP_READ)
@@ -445,8 +443,7 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
 		if (op & ETNA_PREP_NOSYNC)
 			timeout = NULL;
 
-		ret = etnaviv_wait_fence_interruptable(dev, etnaviv_obj->gpu,
-						       fence, timeout);
+		ret = etnaviv_gpu_wait_fence_interruptible(gpu, fence, timeout);
 	}
 
 	/* TODO cache maintenance */
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 2dbf25121a07..39fe69414679 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -838,8 +838,6 @@ static void retire_worker(struct work_struct *work)
 	struct drm_device *dev = gpu->drm;
 	uint32_t fence = gpu->retired_fence;
 
-	etnaviv_update_fence(gpu->drm, fence);
-
 	mutex_lock(&dev->struct_mutex);
 
 	while (!list_empty(&gpu->active_list)) {
@@ -862,6 +860,8 @@ static void retire_worker(struct work_struct *work)
 	}
 
 	mutex_unlock(&dev->struct_mutex);
+
+	wake_up_all(&gpu->fence_event);
 }
 
 /* call from irq handler to schedule work to retire bo's */
@@ -872,6 +872,45 @@ void etnaviv_gpu_retire(struct etnaviv_gpu *gpu)
 	queue_work(priv->wq, &gpu->retire_work);
 }
 
+int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
+	uint32_t fence, struct timespec *timeout)
+{
+	int ret;
+
+	if (fence_after(fence, gpu->submitted_fence)) {
+		DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
+				fence, gpu->submitted_fence);
+		return -EINVAL;
+	}
+
+	if (!timeout) {
+		/* No timeout was requested: just test for completion */
+		ret = fence_completed(gpu, fence) ? 0 : -EBUSY;
+	} else {
+		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;
+
+		ret = wait_event_interruptible_timeout(gpu->fence_event,
+						fence_completed(gpu, fence),
+						remaining_jiffies);
+		if (ret == 0) {
+			DBG("timeout waiting for fence: %u (completed: %u)",
+					fence, gpu->retired_fence);
+			ret = -ETIMEDOUT;
+		} else if (ret != -ERESTARTSYS) {
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu)
 {
 	return pm_runtime_get_sync(gpu->dev);
@@ -1095,6 +1134,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
 	INIT_LIST_HEAD(&gpu->active_list);
 	INIT_WORK(&gpu->retire_work, retire_worker);
 	INIT_WORK(&gpu->recover_work, recover_worker);
+	init_waitqueue_head(&gpu->fence_event);
 
 	setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
 			(unsigned long)gpu);
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 67f6097ba576..49f369b5a4b5 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -105,9 +105,12 @@ struct etnaviv_gpu {
 	struct list_head active_list;
 
 	uint32_t idle_mask;
+	uint32_t last_ring_pos;
+
+	/* Fencing support */
 	uint32_t submitted_fence;
 	uint32_t retired_fence;
-	uint32_t last_ring_pos;
+	wait_queue_head_t fence_event;
 
 	/* worker for handling active-list retiring: */
 	struct work_struct retire_work;
@@ -141,6 +144,11 @@ 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, uint32_t fence)
+{
+	return fence_after_eq(gpu->retired_fence, fence);
+}
+
 int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, uint32_t param,
 	uint64_t *value);
 
@@ -151,6 +159,8 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
 #endif
 
 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
+int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
+	uint32_t fence, struct timespec *timeout);
 int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 	struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx);
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 20/48] staging: etnaviv: provide etnaviv_queue_work()
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (18 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 19/48] staging: etnaviv: switch to per-GPU fence completion implementation Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 21/48] staging: etnaviv: use standard kernel types rather than stdint.h types Lucas Stach
                         ` (28 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Provide a helper to queue a work_struct onto our private workqueue.
This avoids repetitions of:

	struct drm_device *dev = ...
	struct etnaviv_private *priv = dev->dev_private;

	queue_work(priv->wq, w);

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.h |  7 +++++++
 drivers/staging/etnaviv/etnaviv_gem.c |  4 +---
 drivers/staging/etnaviv/etnaviv_gpu.c | 18 +++++-------------
 3 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index 98536090e947..8f9c1f747b4e 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -61,6 +61,13 @@ struct etnaviv_drm_private {
 	struct workqueue_struct *wq;
 };
 
+static void etnaviv_queue_work(struct drm_device *dev, struct work_struct *w)
+{
+	struct etnaviv_drm_private *priv = drm->dev_private;
+
+	queue_work(priv->wq, w);
+}
+
 int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		struct drm_file *file);
 
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index aaa0f5eaeabd..6e114a390101 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -800,7 +800,6 @@ static void __etnaviv_gem_userptr_get_pages(struct work_struct *_work)
 
 static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)
 {
-	struct etnaviv_drm_private *priv;
 	struct page **pvec = NULL;
 	struct get_pages_work *work;
 	struct mm_struct *mm;
@@ -859,8 +858,7 @@ static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)
 	etnaviv_obj->userptr.work = &work->work;
 	INIT_WORK(&work->work, __etnaviv_gem_userptr_get_pages);
 
-	priv = etnaviv_obj->base.dev->dev_private;
-	queue_work(priv->wq, &work->work);
+	etnaviv_queue_work(etnaviv_obj->base.dev, &work->work);
 
 	return -EAGAIN;
 }
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 39fe69414679..4f2174431c2b 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -727,7 +727,8 @@ static void recover_worker(struct work_struct *work)
 	/* TODO gpu->funcs->recover(gpu); */
 	mutex_unlock(&dev->struct_mutex);
 
-	etnaviv_gpu_retire(gpu);
+	/* Retire the buffer objects in a work */
+	etnaviv_queue_work(gpu->dev, &gpu->retire_work);
 }
 
 static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
@@ -740,8 +741,6 @@ static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
 static void hangcheck_handler(unsigned long data)
 {
 	struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
-	struct drm_device *dev = gpu->drm;
-	struct etnaviv_drm_private *priv = dev->dev_private;
 	uint32_t fence = gpu->retired_fence;
 	bool progress = false;
 
@@ -765,7 +764,7 @@ static void hangcheck_handler(unsigned long data)
 		dev_err(gpu->dev, "     completed fence: %u\n", fence);
 		dev_err(gpu->dev, "     submitted fence: %u\n",
 			gpu->submitted_fence);
-		queue_work(priv->wq, &gpu->recover_work);
+		etnaviv_queue_work(gpu->dev, &gpu->recover_work);
 	}
 
 	/* if still more pending work, reset the hangcheck timer: */
@@ -864,14 +863,6 @@ static void retire_worker(struct work_struct *work)
 	wake_up_all(&gpu->fence_event);
 }
 
-/* call from irq handler to schedule work to retire bo's */
-void etnaviv_gpu_retire(struct etnaviv_gpu *gpu)
-{
-	struct etnaviv_drm_private *priv = gpu->drm->dev_private;
-
-	queue_work(priv->wq, &gpu->retire_work);
-}
-
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
 	uint32_t fence, struct timespec *timeout)
 {
@@ -1044,7 +1035,8 @@ static irqreturn_t irq_handler(int irq, void *data)
 			pm_runtime_put_autosuspend(gpu->dev);
 		}
 
-		etnaviv_gpu_retire(gpu);
+		/* Retire the buffer objects in a work */
+		etnaviv_queue_work(gpu->dev, &gpu->retire_work);
 
 		ret = IRQ_HANDLED;
 	}
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 21/48] staging: etnaviv: use standard kernel types rather than stdint.h types
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (19 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 20/48] staging: etnaviv: provide etnaviv_queue_work() Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 22/48] staging: etnaviv: no need to initialise a list_head Lucas Stach
                         ` (27 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

The Linux kernel dislikes the use of stdint.h types.  In order to
prepare this code for merging, we need to convert to the preferred
types, which are u8/u16/u32/u64 for unsigned ints of the specified
size, and s8/s16/s32/s64 for signed ints of the same.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_buffer.c     | 10 ++--
 drivers/staging/etnaviv/etnaviv_drv.c        |  2 +-
 drivers/staging/etnaviv/etnaviv_drv.h        | 31 +++++-----
 drivers/staging/etnaviv/etnaviv_gem.c        | 28 ++++-----
 drivers/staging/etnaviv/etnaviv_gem.h        | 24 ++++----
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 14 ++---
 drivers/staging/etnaviv/etnaviv_gpu.c        | 19 +++----
 drivers/staging/etnaviv/etnaviv_gpu.h        | 59 ++++++++++---------
 drivers/staging/etnaviv/etnaviv_iommu.c      | 12 ++--
 drivers/staging/etnaviv/etnaviv_mmu.c        | 10 ++--
 drivers/staging/etnaviv/etnaviv_mmu.h        |  8 +--
 include/uapi/drm/etnaviv_drm.h               | 85 ++++++++++++++--------------
 12 files changed, 150 insertions(+), 152 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
index 816dc0c4a287..01a29793aed3 100644
--- a/drivers/staging/etnaviv/etnaviv_buffer.c
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -28,7 +28,7 @@
  */
 
 
-static inline void OUT(struct etnaviv_gem_object *buffer, uint32_t data)
+static inline void OUT(struct etnaviv_gem_object *buffer, u32 data)
 {
 	u32 *vaddr = (u32 *)buffer->vaddr;
 
@@ -183,7 +183,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	 * if we are going to completely overflow the buffer, we need to wrap.
 	 */
 	if (buffer->offset + reserve_size >
-	    buffer->base.size / sizeof(uint32_t))
+	    buffer->base.size / sizeof(u32))
 		buffer->offset = 0;
 
 	/* save offset back into main buffer */
@@ -192,7 +192,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	link_size = 6;
 
 	/* Skip over any extra instructions */
-	link_target += extra_size * sizeof(uint32_t);
+	link_target += extra_size * sizeof(u32);
 
 	/* update offset for every cmd stream */
 	for (i = submit->nr_cmds; i--; ) {
@@ -232,8 +232,8 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	}
 
 	if (gpu->mmu->need_flush || gpu->switch_context) {
-		uint32_t new_target = gpu_va(gpu, buffer) + buffer->offset *
-					sizeof(uint32_t);
+		u32 new_target = gpu_va(gpu, buffer) + buffer->offset *
+					sizeof(u32);
 
 		if (gpu->mmu->need_flush) {
 			/* Add the MMU flush */
diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 4f97bb667278..d7133e4450c6 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -434,7 +434,7 @@ static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
 
 	if (offset_in_page(args->user_ptr | args->user_size) ||
 	    (uintptr_t)args->user_ptr != args->user_ptr ||
-	    (uint32_t)args->user_size != args->user_size)
+	    (u32)args->user_size != args->user_size)
 		return -EINVAL;
 
 	if (args->flags & ETNA_USERPTR_WRITE)
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index 8f9c1f747b4e..b98db8c11ef3 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -53,7 +53,7 @@ struct etnaviv_drm_private {
 	int num_gpus;
 	struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
 
-	uint32_t next_fence;
+	u32 next_fence;
 
 	/* list of GEM objects: */
 	struct list_head inactive_list;
@@ -61,9 +61,10 @@ struct etnaviv_drm_private {
 	struct workqueue_struct *wq;
 };
 
-static void etnaviv_queue_work(struct drm_device *dev, struct work_struct *w)
+static inline void etnaviv_queue_work(struct drm_device *dev,
+	struct work_struct *w)
 {
-	struct etnaviv_drm_private *priv = drm->dev_private;
+	struct etnaviv_drm_private *priv = dev->dev_private;
 
 	queue_work(priv->wq, w);
 }
@@ -73,11 +74,11 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 
 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, uint64_t *offset);
+int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset);
 int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
-	struct drm_gem_object *obj, uint32_t *iova);
+	struct drm_gem_object *obj, u32 *iova);
 int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
-	int id, uint32_t *iova);
+	int id, u32 *iova);
 void etnaviv_gem_put_iova(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);
@@ -90,18 +91,18 @@ void *etnaviv_gem_vaddr_locked(struct drm_gem_object *obj);
 void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
 dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj);
 void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
-		struct etnaviv_gpu *gpu, uint32_t access, uint32_t fence);
+		struct etnaviv_gpu *gpu, u32 access, u32 fence);
 void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj);
-int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
+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,
-		uint32_t size, uint32_t flags, uint32_t *handle);
+		u32 size, u32 flags, u32 *handle);
 struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
-		uint32_t size, uint32_t flags);
+		u32 size, u32 flags);
 int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
-	uintptr_t ptr, uint32_t size, uint32_t flags, uint32_t *handle);
+	uintptr_t ptr, u32 size, u32 flags, u32 *handle);
 u32 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,
@@ -122,14 +123,14 @@ u32 etnaviv_readl(const void __iomem *addr);
 #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 
 /* returns true if fence a comes after fence b */
-static inline bool fence_after(uint32_t a, uint32_t b)
+static inline bool fence_after(u32 a, u32 b)
 {
-	return (int32_t)(a - b) > 0;
+	return (s32)(a - b) > 0;
 }
 
-static inline bool fence_after_eq(uint32_t a, uint32_t b)
+static inline bool fence_after_eq(u32 a, u32 b)
 {
-	return (int32_t)(a - b) >= 0;
+	return (s32)(a - b) >= 0;
 }
 
 static inline bool fence_completed(struct drm_device *dev, uint32_t fence)
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 6e114a390101..23e655de7925 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -270,7 +270,7 @@ out:
 }
 
 /* get mmap offset - must be called under struct_mutex */
-int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, uint64_t *offset)
+int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset)
 {
 	int ret;
 
@@ -292,7 +292,7 @@ int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, uint64_t *offset)
  * the refcnt counter needs to be atomic_t.
  */
 int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
-	struct drm_gem_object *obj, uint32_t *iova)
+	struct drm_gem_object *obj, u32 *iova)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 	struct etnaviv_vram_mapping *mapping =
@@ -319,7 +319,7 @@ int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
 }
 
 int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
-	int id, uint32_t *iova)
+	int id, u32 *iova)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 	struct etnaviv_vram_mapping *mapping =
@@ -393,7 +393,7 @@ dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj)
 }
 
 void etnaviv_gem_move_to_active(struct drm_gem_object *obj,
-	struct etnaviv_gpu *gpu, uint32_t access, uint32_t fence)
+	struct etnaviv_gpu *gpu, u32 access, u32 fence)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 
@@ -426,7 +426,7 @@ void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj)
 	list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
 }
 
-int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
+int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
 		struct timespec *timeout)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
@@ -434,7 +434,7 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
 
 	if (is_active(etnaviv_obj)) {
 		struct etnaviv_gpu *gpu = etnaviv_obj->gpu;
-		uint32_t fence = 0;
+		u32 fence = 0;
 
 		if (op & ETNA_PREP_READ)
 			fence = etnaviv_obj->write_fence;
@@ -462,11 +462,11 @@ static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
 {
 	struct drm_device *dev = obj->dev;
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-	uint64_t off = drm_vma_node_start(&obj->vma_node);
+	unsigned long off = drm_vma_node_start(&obj->vma_node);
 
 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-	seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %zd\n",
+	seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08lx %p %zd\n",
 			etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
 			etnaviv_obj->read_fence, etnaviv_obj->write_fence,
 			obj->name, obj->refcount.refcount.counter,
@@ -565,7 +565,7 @@ int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
 }
 
 static int etnaviv_gem_new_impl(struct drm_device *dev,
-		uint32_t size, uint32_t flags,
+		u32 size, u32 flags,
 		struct drm_gem_object **obj)
 {
 	struct etnaviv_gem_object *etnaviv_obj;
@@ -623,7 +623,7 @@ static int etnaviv_gem_new_impl(struct drm_device *dev,
 }
 
 static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
-		uint32_t size, uint32_t flags)
+		u32 size, u32 flags)
 {
 	struct drm_gem_object *obj = NULL;
 	int ret;
@@ -657,7 +657,7 @@ fail:
 
 /* convenience method to construct a GEM buffer object, and userspace handle */
 int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
-		uint32_t size, uint32_t flags, uint32_t *handle)
+		u32 size, u32 flags, u32 *handle)
 {
 	struct drm_gem_object *obj;
 	int ret;
@@ -681,7 +681,7 @@ int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
 }
 
 struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
-		uint32_t size, uint32_t flags)
+		u32 size, u32 flags)
 {
 	struct drm_gem_object *obj;
 	int ret;
@@ -699,7 +699,7 @@ struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
 	return obj;
 }
 
-int etnaviv_gem_new_private(struct drm_device *dev, size_t size, uint32_t flags,
+int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
 	struct etnaviv_gem_object **res)
 {
 	struct drm_gem_object *obj;
@@ -885,7 +885,7 @@ static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops = {
 };
 
 int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
-	uintptr_t ptr, uint32_t size, uint32_t flags, uint32_t *handle)
+	uintptr_t ptr, u32 size, u32 flags, u32 *handle)
 {
 	struct etnaviv_gem_object *etnaviv_obj;
 	int ret;
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index 397b30f39708..08f0e6464cc7 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -33,14 +33,14 @@ struct etnaviv_vram_mapping {
 	struct list_head obj_head;
 	struct etnaviv_iommu *mmu;
 	struct drm_mm_node vram_node;
-	uint32_t iova;
+	u32 iova;
 };
 
 struct etnaviv_gem_object {
 	struct drm_gem_object base;
 	const struct etnaviv_gem_ops *ops;
 
-	uint32_t flags;
+	u32 flags;
 
 	/* And object is either:
 	 *  inactive - on priv->inactive_list
@@ -52,8 +52,8 @@ struct etnaviv_gem_object {
 	 */
 	struct list_head mm_list;
 	struct etnaviv_gpu *gpu;     /* non-null if active */
-	uint32_t access;
-	uint32_t read_fence, write_fence;
+	u32 access;
+	u32 read_fence, write_fence;
 
 	/* Transiently in the process of submit ioctl, objects associated
 	 * with the submit are on submit->bo_list.. this only lasts for
@@ -108,29 +108,29 @@ static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj)
 struct etnaviv_gem_submit {
 	struct drm_device *dev;
 	struct etnaviv_gpu *gpu;
-	uint32_t exec_state;
+	u32 exec_state;
 	struct list_head bo_list;
 	struct ww_acquire_ctx ticket;
-	uint32_t fence;
+	u32 fence;
 	unsigned int nr_cmds;
 	unsigned int nr_bos;
 	struct {
-		uint32_t type;
-		uint32_t offset; /* in dwords */
-		uint32_t size;  /* in dwords */
+		u32 type;
+		u32 offset; /* in dwords */
+		u32 size;  /* in dwords */
 		struct etnaviv_gem_object *obj;
 	} cmd[MAX_CMDS];
 	struct {
-		uint32_t flags;
+		u32 flags;
 		struct etnaviv_gem_object *obj;
-		uint32_t iova;
+		u32 iova;
 	} bos[0];
 };
 
 struct etnaviv_vram_mapping *
 etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
 			     struct etnaviv_iommu *mmu);
-int etnaviv_gem_new_private(struct drm_device *dev, size_t size, uint32_t flags,
+int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
 	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);
diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index 647d16fee98b..e2c94f476810 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -139,7 +139,7 @@ static int submit_validate_objects(struct etnaviv_gem_submit *submit)
 retry:
 	for (i = 0; i < submit->nr_bos; i++) {
 		struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
-		uint32_t iova;
+		u32 iova;
 
 		if (slow_locked == i)
 			slow_locked = -1;
@@ -201,8 +201,8 @@ fail:
 	return ret;
 }
 
-static int submit_bo(struct etnaviv_gem_submit *submit, uint32_t idx,
-		struct etnaviv_gem_object **obj, uint32_t *iova)
+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",
@@ -220,10 +220,10 @@ static int submit_bo(struct etnaviv_gem_submit *submit, uint32_t idx,
 
 /* process the reloc's and patch up the cmdstream as needed: */
 static int submit_reloc(struct etnaviv_gem_submit *submit, struct etnaviv_gem_object *obj,
-		uint32_t offset, uint32_t nr_relocs, uint64_t relocs)
+		u32 offset, u32 nr_relocs, u64 relocs)
 {
-	uint32_t i, last_offset = 0;
-	uint32_t *ptr = obj->vaddr;
+	u32 i, last_offset = 0;
+	u32 *ptr = obj->vaddr;
 	int ret;
 
 	if (offset % 4) {
@@ -236,7 +236,7 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, struct etnaviv_gem_ob
 		struct etnaviv_gem_object *bobj;
 		void __user *userptr =
 			to_user_ptr(relocs + (i * sizeof(submit_reloc)));
-		uint32_t iova, off;
+		u32 iova, off;
 
 		ret = copy_from_user(&submit_reloc, userptr,
 				     sizeof(submit_reloc));
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 4f2174431c2b..233b2197eb37 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -35,8 +35,7 @@ static const struct platform_device_id gpu_ids[] = {
  * Driver functions:
  */
 
-int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, uint32_t param,
-	uint64_t *value)
+int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
 {
 	switch (param) {
 	case ETNAVIV_PARAM_GPU_MODEL:
@@ -728,7 +727,7 @@ static void recover_worker(struct work_struct *work)
 	mutex_unlock(&dev->struct_mutex);
 
 	/* Retire the buffer objects in a work */
-	etnaviv_queue_work(gpu->dev, &gpu->retire_work);
+	etnaviv_queue_work(gpu->drm, &gpu->retire_work);
 }
 
 static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
@@ -741,7 +740,7 @@ static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
 static void hangcheck_handler(unsigned long data)
 {
 	struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
-	uint32_t fence = gpu->retired_fence;
+	u32 fence = gpu->retired_fence;
 	bool progress = false;
 
 	if (fence != gpu->hangcheck_fence) {
@@ -750,7 +749,7 @@ static void hangcheck_handler(unsigned long data)
 	}
 
 	if (!progress) {
-		uint32_t dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
+		u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
 		int change = dma_addr - gpu->hangcheck_dma_addr;
 
 		if (change < 0 || change > 16) {
@@ -764,7 +763,7 @@ static void hangcheck_handler(unsigned long data)
 		dev_err(gpu->dev, "     completed fence: %u\n", fence);
 		dev_err(gpu->dev, "     submitted fence: %u\n",
 			gpu->submitted_fence);
-		etnaviv_queue_work(gpu->dev, &gpu->recover_work);
+		etnaviv_queue_work(gpu->drm, &gpu->recover_work);
 	}
 
 	/* if still more pending work, reset the hangcheck timer: */
@@ -835,7 +834,7 @@ static void retire_worker(struct work_struct *work)
 	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
 					       retire_work);
 	struct drm_device *dev = gpu->drm;
-	uint32_t fence = gpu->retired_fence;
+	u32 fence = gpu->retired_fence;
 
 	mutex_lock(&dev->struct_mutex);
 
@@ -864,7 +863,7 @@ static void retire_worker(struct work_struct *work)
 }
 
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
-	uint32_t fence, struct timespec *timeout)
+	u32 fence, struct timespec *timeout)
 {
 	int ret;
 
@@ -963,7 +962,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 		WARN_ON(is_active(etnaviv_obj) && (etnaviv_obj->gpu != gpu));
 
 		if (!is_active(etnaviv_obj)) {
-			uint32_t iova;
+			u32 iova;
 
 			/* ring takes a reference to the bo and iova: */
 			drm_gem_object_reference(&etnaviv_obj->base);
@@ -1036,7 +1035,7 @@ static irqreturn_t irq_handler(int irq, void *data)
 		}
 
 		/* Retire the buffer objects in a work */
-		etnaviv_queue_work(gpu->dev, &gpu->retire_work);
+		etnaviv_queue_work(gpu->drm, &gpu->retire_work);
 
 		ret = IRQ_HANDLED;
 	}
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 49f369b5a4b5..44af5ca3f633 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -26,61 +26,61 @@ struct etnaviv_gem_submit;
 
 struct etnaviv_chip_identity {
 	/* Chip model. */
-	uint32_t model;
+	u32 model;
 
 	/* Revision value.*/
-	uint32_t revision;
+	u32 revision;
 
 	/* Supported feature fields. */
-	uint32_t features;
+	u32 features;
 
 	/* Supported minor feature fields. */
-	uint32_t minor_features0;
+	u32 minor_features0;
 
 	/* Supported minor feature 1 fields. */
-	uint32_t minor_features1;
+	u32 minor_features1;
 
 	/* Supported minor feature 2 fields. */
-	uint32_t minor_features2;
+	u32 minor_features2;
 
 	/* Supported minor feature 3 fields. */
-	uint32_t minor_features3;
+	u32 minor_features3;
 
 	/* Number of streams supported. */
-	uint32_t stream_count;
+	u32 stream_count;
 
 	/* Total number of temporary registers per thread. */
-	uint32_t register_max;
+	u32 register_max;
 
 	/* Maximum number of threads. */
-	uint32_t thread_count;
+	u32 thread_count;
 
 	/* Number of shader cores. */
-	uint32_t shader_core_count;
+	u32 shader_core_count;
 
 	/* Size of the vertex cache. */
-	uint32_t vertex_cache_size;
+	u32 vertex_cache_size;
 
 	/* Number of entries in the vertex output buffer. */
-	uint32_t vertex_output_buffer_size;
+	u32 vertex_output_buffer_size;
 
 	/* Number of pixel pipes. */
-	uint32_t pixel_pipes;
+	u32 pixel_pipes;
 
 	/* Number of instructions. */
-	uint32_t instruction_count;
+	u32 instruction_count;
 
 	/* Number of constants. */
-	uint32_t num_constants;
+	u32 num_constants;
 
 	/* Buffer size */
-	uint32_t buffer_size;
+	u32 buffer_size;
 };
 
 struct etnaviv_event {
 	bool used;
-	uint32_t fence;
-	uint32_t ring_pos;
+	u32 fence;
+	u32 ring_pos;
 };
 
 struct etnaviv_gpu {
@@ -94,7 +94,7 @@ struct etnaviv_gpu {
 	struct drm_gem_object *buffer;
 
 	/* bus base address of memory  */
-	uint32_t memory_base;
+	u32 memory_base;
 
 	/* event management: */
 	struct etnaviv_event event[30];
@@ -104,12 +104,12 @@ struct etnaviv_gpu {
 	/* list of GEM active objects: */
 	struct list_head active_list;
 
-	uint32_t idle_mask;
-	uint32_t last_ring_pos;
+	u32 idle_mask;
+	u32 last_ring_pos;
 
 	/* Fencing support */
-	uint32_t submitted_fence;
-	uint32_t retired_fence;
+	u32 submitted_fence;
+	u32 retired_fence;
 	wait_queue_head_t fence_event;
 
 	/* worker for handling active-list retiring: */
@@ -129,8 +129,8 @@ struct etnaviv_gpu {
 #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;
-	uint32_t hangcheck_fence;
-	uint32_t hangcheck_dma_addr;
+	u32 hangcheck_fence;
+	u32 hangcheck_dma_addr;
 	struct work_struct recover_work;
 };
 
@@ -144,13 +144,12 @@ 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, uint32_t fence)
+static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence)
 {
 	return fence_after_eq(gpu->retired_fence, fence);
 }
 
-int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, uint32_t param,
-	uint64_t *value);
+int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value);
 
 int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
 
@@ -160,7 +159,7 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
 
 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
-	uint32_t fence, struct timespec *timeout);
+	u32 fence, struct timespec *timeout);
 int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 	struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx);
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
index 8aff23a310fb..73ba65205705 100644
--- a/drivers/staging/etnaviv/etnaviv_iommu.c
+++ b/drivers/staging/etnaviv/etnaviv_iommu.c
@@ -26,12 +26,12 @@
 #include "state_hi.xml.h"
 
 #define PT_SIZE		SZ_512K
-#define PT_ENTRIES	(PT_SIZE / sizeof(uint32_t))
+#define PT_ENTRIES	(PT_SIZE / sizeof(u32))
 
 #define GPU_MEM_START	0x80000000
 
 struct etnaviv_iommu_domain_pgtable {
-	uint32_t *pgtable;
+	u32 *pgtable;
 	dma_addr_t paddr;
 };
 
@@ -65,7 +65,7 @@ static void pgtable_free(struct etnaviv_iommu_domain_pgtable *pgtable,
 	dma_free_coherent(NULL, size, pgtable->pgtable, pgtable->paddr);
 }
 
-static uint32_t pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable,
+static u32 pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable,
 			   unsigned long iova)
 {
 	/* calcuate index into page table */
@@ -88,7 +88,7 @@ static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
 
 static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
 {
-	uint32_t iova, *p;
+	u32 iova, *p;
 	int ret, i;
 
 	etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
@@ -183,10 +183,10 @@ void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
 	struct iommu_domain *domain)
 {
 	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
-	uint32_t pgtable;
+	u32 pgtable;
 
 	/* set page table address in MC */
-	pgtable = (uint32_t)etnaviv_domain->pgtable.paddr;
+	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);
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
index ec01c8a560f4..754bcbc0c19a 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.c
+++ b/drivers/staging/etnaviv/etnaviv_mmu.c
@@ -25,7 +25,7 @@ static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device *dev,
 	return 0;
 }
 
-int etnaviv_iommu_map(struct etnaviv_iommu *iommu, uint32_t iova,
+int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
 		struct sg_table *sgt, unsigned len, int prot)
 {
 	struct iommu_domain *domain = iommu->domain;
@@ -64,7 +64,7 @@ fail:
 	return ret;
 }
 
-int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, uint32_t iova,
+int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
 		struct sg_table *sgt, unsigned len)
 {
 	struct iommu_domain *domain = iommu->domain;
@@ -91,7 +91,7 @@ int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, uint32_t iova,
 }
 
 int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
-	struct etnaviv_gem_object *etnaviv_obj, uint32_t memory_base,
+	struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
 	struct etnaviv_vram_mapping **out_mapping)
 {
 	struct etnaviv_drm_private *priv = etnaviv_obj->base.dev->dev_private;
@@ -109,7 +109,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 
 	/* v1 MMU can optimize single entry (contiguous) scatterlists */
 	if (sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
-		uint32_t iova;
+		u32 iova;
 
 		iova = sg_dma_address(sgt->sgl) - memory_base;
 		if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
@@ -227,7 +227,7 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
 			     struct etnaviv_vram_mapping *mapping)
 {
 	if (mapping) {
-		uint32_t offset = mapping->vram_node.start;
+		u32 offset = mapping->vram_node.start;
 
 		if (mapping->iova >= 0x80000000) {
 			etnaviv_iommu_unmap(mmu, offset, etnaviv_obj->sgt,
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.h b/drivers/staging/etnaviv/etnaviv_mmu.h
index 94dbab736fc1..1d619e91f457 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.h
+++ b/drivers/staging/etnaviv/etnaviv_mmu.h
@@ -34,7 +34,7 @@ struct etnaviv_iommu {
 
 	/* memory manager for GPU address area */
 	struct drm_mm mm;
-	uint32_t last_iova;
+	u32 last_iova;
 	bool need_flush;
 };
 
@@ -42,12 +42,12 @@ struct etnaviv_gem_object;
 
 int etnaviv_iommu_attach(struct etnaviv_iommu *iommu, const char **names,
 	int cnt);
-int etnaviv_iommu_map(struct etnaviv_iommu *iommu, uint32_t iova,
+int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
 	struct sg_table *sgt, unsigned len, int prot);
-int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, uint32_t iova,
+int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
 	struct sg_table *sgt, unsigned len);
 int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
-	struct etnaviv_gem_object *etnaviv_obj, uint32_t memory_base,
+	struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
 	struct etnaviv_vram_mapping **mapping);
 void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
 	struct etnaviv_gem_object *etnaviv_obj,
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index c6ce72ae4dbe..0aca6b189e63 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -17,12 +17,11 @@
 #ifndef __ETNAVIV_DRM_H__
 #define __ETNAVIV_DRM_H__
 
-#include <stddef.h>
 #include <drm/drm.h>
 
 /* Please note that modifications to all structs defined here are
  * subject to backwards-compatibility constraints:
- *  1) Do not use pointers, use uint64_t instead for 32 bit / 64 bit
+ *  1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
  *     user/kernel compatibility
  *  2) Keep fields aligned to their size
  *  3) Because of how drm_ioctl() works, we can add new fields at
@@ -38,8 +37,8 @@
  * same as 'struct timespec' but 32/64b ABI safe.
  */
 struct drm_etnaviv_timespec {
-	int64_t tv_sec;          /* seconds */
-	int64_t tv_nsec;         /* nanoseconds */
+	__s64 tv_sec;          /* seconds */
+	__s64 tv_nsec;         /* nanoseconds */
 };
 
 #define ETNAVIV_PARAM_GPU_MODEL                     0x01
@@ -64,9 +63,9 @@ struct drm_etnaviv_timespec {
 #define ETNA_MAX_PIPES 4
 
 struct drm_etnaviv_param {
-	uint32_t pipe;           /* in */
-	uint32_t param;          /* in, ETNAVIV_PARAM_x */
-	uint64_t value;          /* out (get_param) or in (set_param) */
+	__u32 pipe;           /* in */
+	__u32 param;          /* in, ETNAVIV_PARAM_x */
+	__u64 value;          /* out (get_param) or in (set_param) */
 };
 
 /*
@@ -83,15 +82,15 @@ struct drm_etnaviv_param {
 #define ETNA_BO_FORCE_MMU    0x00100000
 
 struct drm_etnaviv_gem_new {
-	uint64_t size;           /* in */
-	uint32_t flags;          /* in, mask of ETNA_BO_x */
-	uint32_t handle;         /* out */
+	__u64 size;           /* in */
+	__u32 flags;          /* in, mask of ETNA_BO_x */
+	__u32 handle;         /* out */
 };
 
 struct drm_etnaviv_gem_info {
-	uint32_t handle;         /* in */
-	uint32_t pad;
-	uint64_t offset;         /* out, offset to pass to mmap() */
+	__u32 handle;         /* in */
+	__u32 pad;
+	__u64 offset;         /* out, offset to pass to mmap() */
 };
 
 #define ETNA_PREP_READ        0x01
@@ -99,13 +98,13 @@ struct drm_etnaviv_gem_info {
 #define ETNA_PREP_NOSYNC      0x04
 
 struct drm_etnaviv_gem_cpu_prep {
-	uint32_t handle;         /* in */
-	uint32_t op;             /* in, mask of ETNA_PREP_x */
+	__u32 handle;         /* in */
+	__u32 op;             /* in, mask of ETNA_PREP_x */
 	struct drm_etnaviv_timespec timeout;   /* in */
 };
 
 struct drm_etnaviv_gem_cpu_fini {
-	uint32_t handle;         /* in */
+	__u32 handle;         /* in */
 };
 
 /*
@@ -119,9 +118,9 @@ struct drm_etnaviv_gem_cpu_fini {
  * otherwise EINVAL.
  */
 struct drm_etnaviv_gem_submit_reloc {
-	uint32_t submit_offset;  /* in, offset from submit_bo */
-	uint32_t reloc_idx;      /* in, index of reloc_bo buffer */
-	uint64_t reloc_offset;   /* in, offset from start of reloc_bo */
+	__u32 submit_offset;  /* in, offset from submit_bo */
+	__u32 reloc_idx;      /* in, index of reloc_bo buffer */
+	__u64 reloc_offset;   /* in, offset from start of reloc_bo */
 };
 
 /* submit-types:
@@ -132,13 +131,13 @@ struct drm_etnaviv_gem_submit_reloc {
 #define ETNA_SUBMIT_CMD_BUF             0x0001
 #define ETNA_SUBMIT_CMD_CTX_RESTORE_BUF 0x0002
 struct drm_etnaviv_gem_submit_cmd {
-	uint32_t type;           /* in, one of ETNA_SUBMIT_CMD_x */
-	uint32_t submit_idx;     /* in, index of submit_bo cmdstream buffer */
-	uint32_t submit_offset;  /* in, offset into submit_bo */
-	uint32_t size;           /* in, cmdstream size */
-	uint32_t pad;
-	uint32_t nr_relocs;      /* in, number of submit_reloc's */
-	uint64_t relocs;         /* in, ptr to array of submit_reloc's */
+	__u32 type;           /* in, one of ETNA_SUBMIT_CMD_x */
+	__u32 submit_idx;     /* in, index of submit_bo cmdstream buffer */
+	__u32 submit_offset;  /* in, offset into submit_bo */
+	__u32 size;           /* in, cmdstream size */
+	__u32 pad;
+	__u32 nr_relocs;      /* in, number of submit_reloc's */
+	__u64 relocs;         /* in, ptr to array of submit_reloc's */
 };
 
 /* Each buffer referenced elsewhere in the cmdstream submit (ie. the
@@ -155,9 +154,9 @@ struct drm_etnaviv_gem_submit_cmd {
 #define ETNA_SUBMIT_BO_READ             0x0001
 #define ETNA_SUBMIT_BO_WRITE            0x0002
 struct drm_etnaviv_gem_submit_bo {
-	uint32_t flags;          /* in, mask of ETNA_SUBMIT_BO_x */
-	uint32_t handle;         /* in, GEM handle */
-	uint64_t presumed;       /* in/out, presumed buffer address */
+	__u32 flags;          /* in, mask of ETNA_SUBMIT_BO_x */
+	__u32 handle;         /* in, GEM handle */
+	__u64 presumed;       /* in/out, presumed buffer address */
 };
 
 /* Each cmdstream submit consists of a table of buffers involved, and
@@ -168,14 +167,14 @@ struct drm_etnaviv_gem_submit_bo {
 #define ETNA_PIPE_2D      0x01
 #define ETNA_PIPE_VG      0x02
 struct drm_etnaviv_gem_submit {
-	uint32_t pipe;           /* in */
-	uint32_t exec_state;     /* in, initial execution state (ETNA_PIPE_x) */
-	uint32_t fence;          /* out */
-	uint32_t nr_bos;         /* in, number of submit_bo's */
-	uint32_t nr_cmds;        /* in, number of submit_cmd's */
-	uint32_t pad;
-	uint64_t bos;            /* in, ptr to array of submit_bo's */
-	uint64_t cmds;           /* in, ptr to array of submit_cmd's */
+	__u32 pipe;           /* in */
+	__u32 exec_state;     /* in, initial execution state (ETNA_PIPE_x) */
+	__u32 fence;          /* out */
+	__u32 nr_bos;         /* in, number of submit_bo's */
+	__u32 nr_cmds;        /* in, number of submit_cmd's */
+	__u32 pad;
+	__u64 bos;            /* in, ptr to array of submit_bo's */
+	__u64 cmds;           /* in, ptr to array of submit_cmd's */
 };
 
 /* The normal way to synchronize with the GPU is just to CPU_PREP on
@@ -186,18 +185,18 @@ struct drm_etnaviv_gem_submit {
  * APIs without requiring a dummy bo to synchronize on.
  */
 struct drm_etnaviv_wait_fence {
-	uint32_t pipe;           /* in */
-	uint32_t fence;          /* in */
+	__u32 pipe;           /* in */
+	__u32 fence;          /* in */
 	struct drm_etnaviv_timespec timeout;   /* in */
 };
 
 #define ETNA_USERPTR_READ	0x01
 #define ETNA_USERPTR_WRITE	0x02
 struct drm_etnaviv_gem_userptr {
-	uint64_t user_ptr;	/* in, page aligned user pointer */
-	uint64_t user_size;	/* in, page aligned user size */
-	uint32_t flags;		/* in, flags */
-	uint32_t handle;	/* out, non-zero handle */
+	__u64 user_ptr;	/* in, page aligned user pointer */
+	__u64 user_size;	/* in, page aligned user size */
+	__u32 flags;		/* in, flags */
+	__u32 handle;	/* out, non-zero handle */
 };
 
 #define DRM_ETNAVIV_GET_PARAM          0x00
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 22/48] staging: etnaviv: no need to initialise a list_head
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (20 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 21/48] staging: etnaviv: use standard kernel types rather than stdint.h types Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 23/48] staging: etnaviv: fix oops caused by scanning for free blocks Lucas Stach
                         ` (26 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

There's no need to initialise a list_head which is only going to be
added with list_add() to an existing list.  Remove this redundant code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_mmu.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
index 754bcbc0c19a..f40d4ec5ade7 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.c
+++ b/drivers/staging/etnaviv/etnaviv_mmu.c
@@ -104,7 +104,6 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 	if (!mapping)
 		return -ENOMEM;
 
-	INIT_LIST_HEAD(&mapping->obj_head);
 	mapping->mmu = mmu;
 
 	/* v1 MMU can optimize single entry (contiguous) scatterlists */
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 23/48] staging: etnaviv: fix oops caused by scanning for free blocks
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (21 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 22/48] staging: etnaviv: no need to initialise a list_head Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 24/48] staging: etnaviv: clean up etnaviv_iommu_unmap_gem() signature Lucas Stach
                         ` (25 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

The drm_mm scanning for free MMU blocks walks the list of inactive
objects, looking up their vram node.  Unfortunately, the code assumes
that if it has a vram node, it is registered into drm_mm.

However, there are two cases when a vram node is created - whenever a
MMU entry has to be allocated (when it is registered into the drm_mm)
and when a direct mapping is registered (which isn't.)  The direct
mapping case has vram_node.mm NULL, which causes an oops in
drm_mm_scan_add_block().

The list of objects on the scanning list was also broken - we would end
up calling drm_mm_remove_block() multiple times for the same 'free'
vram node, instead of walking the list of scanned blocks.  Fix this by
having a separate list for scanned blocks.

Fixes: ("staging: etnaviv: allow to map buffer object into multiple address spaces")
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c |  4 ++--
 drivers/staging/etnaviv/etnaviv_gem.h |  5 ++++-
 drivers/staging/etnaviv/etnaviv_mmu.c | 36 +++++++++++++++++++++--------------
 3 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 23e655de7925..256ec0775133 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -508,7 +508,7 @@ static void etnaviv_free_obj(struct drm_gem_object *obj)
 	struct etnaviv_vram_mapping *mapping, *tmp;
 
 	list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
-				 obj_head) {
+				 obj_node) {
 		etnaviv_iommu_unmap_gem(mapping->mmu, etnaviv_obj, mapping);
 	}
 }
@@ -722,7 +722,7 @@ etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
 {
 	struct etnaviv_vram_mapping *mapping;
 
-	list_for_each_entry(mapping, &obj->vram_list, obj_head) {
+	list_for_each_entry(mapping, &obj->vram_list, obj_node) {
 		if (mapping->mmu == mmu)
 			return mapping;
 	}
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index 08f0e6464cc7..f3136d86d73e 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -21,6 +21,7 @@
 #include "etnaviv_drv.h"
 
 struct etnaviv_gem_ops;
+struct etnaviv_gem_object;
 
 struct etnaviv_gem_userptr {
 	uintptr_t ptr;
@@ -30,7 +31,9 @@ struct etnaviv_gem_userptr {
 };
 
 struct etnaviv_vram_mapping {
-	struct list_head obj_head;
+	struct list_head obj_node;
+	struct list_head scan_node;
+	struct etnaviv_gem_object *object;
 	struct etnaviv_iommu *mmu;
 	struct drm_mm_node vram_node;
 	u32 iova;
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
index f40d4ec5ade7..b327d37f5111 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.c
+++ b/drivers/staging/etnaviv/etnaviv_mmu.c
@@ -104,6 +104,8 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 	if (!mapping)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&mapping->scan_node);
+	mapping->object = etnaviv_obj;
 	mapping->mmu = mmu;
 
 	/* v1 MMU can optimize single entry (contiguous) scatterlists */
@@ -113,7 +115,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 		iova = sg_dma_address(sgt->sgl) - memory_base;
 		if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
 			mapping->iova = iova;
-			list_add_tail(&mapping->obj_head,
+			list_add_tail(&mapping->obj_node,
 				      &etnaviv_obj->vram_list);
 			if (out_mapping)
 				*out_mapping = mapping;
@@ -123,7 +125,8 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 
 	node = &mapping->vram_node;
 	while (1) {
-		struct etnaviv_gem_object *o, *n;
+		struct etnaviv_gem_object *o;
+		struct etnaviv_vram_mapping *m, *n;
 		struct list_head list;
 		bool found;
 
@@ -155,13 +158,19 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 				continue;
 
 			/*
+			 * If this vram node has not been used, skip this.
+			 */
+			if (!free->vram_node.mm)
+				continue;
+
+			/*
 			 * If it's on the submit list, then it is part of
 			 * a submission, and we want to keep its entry.
 			 */
 			if (!list_empty(&o->submit_entry))
 				continue;
 
-			list_add(&o->submit_entry, &list);
+			list_add(&free->scan_node, &list);
 			if (drm_mm_scan_add_block(&free->vram_node)) {
 				found = true;
 				break;
@@ -170,8 +179,8 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 
 		if (!found) {
 			/* Nothing found, clean up and fail */
-			list_for_each_entry_safe(o, n, &list, submit_entry)
-				BUG_ON(drm_mm_scan_remove_block(&free->vram_node));
+			list_for_each_entry_safe(m, n, &list, scan_node)
+				BUG_ON(drm_mm_scan_remove_block(&m->vram_node));
 			break;
 		}
 
@@ -181,13 +190,13 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 		 * If drm_mm_scan_remove_block() returns false, we
 		 * can leave the block pinned.
 		 */
-		list_for_each_entry_safe(o, n, &list, submit_entry)
-			if (!drm_mm_scan_remove_block(&free->vram_node))
-				list_del_init(&o->submit_entry);
+		list_for_each_entry_safe(m, n, &list, scan_node)
+			if (!drm_mm_scan_remove_block(&m->vram_node))
+				list_del_init(&m->scan_node);
 
-		list_for_each_entry_safe(o, n, &list, submit_entry) {
-			list_del_init(&o->submit_entry);
-			etnaviv_iommu_unmap_gem(mmu, o, free);
+		list_for_each_entry_safe(m, n, &list, scan_node) {
+			list_del_init(&m->scan_node);
+			etnaviv_iommu_unmap_gem(mmu, m->object, m);
 		}
 
 		/*
@@ -214,7 +223,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 		return ret;
 	}
 
-	list_add_tail(&mapping->obj_head, &etnaviv_obj->vram_list);
+	list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);
 	if (out_mapping)
 		*out_mapping = mapping;
 
@@ -233,9 +242,8 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
 					    etnaviv_obj->base.size);
 			drm_mm_remove_node(&mapping->vram_node);
 		}
-		list_del(&mapping->obj_head);
+		list_del(&mapping->obj_node);
 		kfree(mapping);
-		mapping = NULL;
 	}
 }
 
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 24/48] staging: etnaviv: clean up etnaviv_iommu_unmap_gem() signature
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (22 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 23/48] staging: etnaviv: fix oops caused by scanning for free blocks Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 25/48] staging: etnaviv: increase page table size to maximum Lucas Stach
                         ` (24 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

The mapping structure contains everything we need; avoid passing extra
data in rather than using the data we have stored in the structure.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c |  2 +-
 drivers/staging/etnaviv/etnaviv_mmu.c | 31 ++++++++++++++++++-------------
 drivers/staging/etnaviv/etnaviv_mmu.h |  4 +---
 3 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 256ec0775133..3a68295eaee4 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -509,7 +509,7 @@ static void etnaviv_free_obj(struct drm_gem_object *obj)
 
 	list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
 				 obj_node) {
-		etnaviv_iommu_unmap_gem(mapping->mmu, etnaviv_obj, mapping);
+		etnaviv_iommu_unmap_gem(mapping);
 	}
 }
 
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c b/drivers/staging/etnaviv/etnaviv_mmu.c
index b327d37f5111..ca317f633970 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.c
+++ b/drivers/staging/etnaviv/etnaviv_mmu.c
@@ -196,7 +196,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 
 		list_for_each_entry_safe(m, n, &list, scan_node) {
 			list_del_init(&m->scan_node);
-			etnaviv_iommu_unmap_gem(mmu, m->object, m);
+			etnaviv_iommu_unmap_gem(m);
 		}
 
 		/*
@@ -230,21 +230,26 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 	return ret;
 }
 
-void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
-			     struct etnaviv_gem_object *etnaviv_obj,
-			     struct etnaviv_vram_mapping *mapping)
+void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping)
 {
-	if (mapping) {
-		u32 offset = mapping->vram_node.start;
+	struct etnaviv_iommu *mmu;
+	struct etnaviv_gem_object *etnaviv_obj;
 
-		if (mapping->iova >= 0x80000000) {
-			etnaviv_iommu_unmap(mmu, offset, etnaviv_obj->sgt,
-					    etnaviv_obj->base.size);
-			drm_mm_remove_node(&mapping->vram_node);
-		}
-		list_del(&mapping->obj_node);
-		kfree(mapping);
+	if (!mapping)
+		return;
+
+	mmu = mapping->mmu;
+
+	/* If the vram node is on the mm, unmap and remove the node */
+	if (mapping->vram_node.mm == &mmu->mm) {
+		etnaviv_obj = mapping->object;
+		etnaviv_iommu_unmap(mmu, mapping->vram_node.start,
+				    etnaviv_obj->sgt, etnaviv_obj->base.size);
+		drm_mm_remove_node(&mapping->vram_node);
 	}
+
+	list_del(&mapping->obj_node);
+	kfree(mapping);
 }
 
 void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
diff --git a/drivers/staging/etnaviv/etnaviv_mmu.h b/drivers/staging/etnaviv/etnaviv_mmu.h
index 1d619e91f457..444ef296d2b4 100644
--- a/drivers/staging/etnaviv/etnaviv_mmu.h
+++ b/drivers/staging/etnaviv/etnaviv_mmu.h
@@ -49,9 +49,7 @@ int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
 int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
 	struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
 	struct etnaviv_vram_mapping **mapping);
-void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
-	struct etnaviv_gem_object *etnaviv_obj,
-	struct etnaviv_vram_mapping *mapping);
+void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping);
 void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
 
 struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev,
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 25/48] staging: etnaviv: increase page table size to maximum
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (23 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 24/48] staging: etnaviv: clean up etnaviv_iommu_unmap_gem() signature Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 26/48] staging: etnaviv: fix BUG_ON when removing module Lucas Stach
                         ` (23 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Running the cairo trace "firefox-36-20090609" results in the Xorg server
trying to queue up 319M of buffer objects in a single commit (due to the
number of drawing operations that will fit into a 32K command buffer.)
This causes the commit ioctl to return -ENOSPC as the MMU is unable to
map all these buffer objects simultaneously.

There are three workarounds possible:
- Increase the GPU MMU table size
- Decrease the command buffer size
- Implement reconstruction of the command buffer on -ENOSPC return

All three should be implemented, but the first is only applicable to the
kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_iommu.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c b/drivers/staging/etnaviv/etnaviv_iommu.c
index 73ba65205705..9efb7d6092b4 100644
--- a/drivers/staging/etnaviv/etnaviv_iommu.c
+++ b/drivers/staging/etnaviv/etnaviv_iommu.c
@@ -25,7 +25,7 @@
 #include "etnaviv_iommu.h"
 #include "state_hi.xml.h"
 
-#define PT_SIZE		SZ_512K
+#define PT_SIZE		SZ_2M
 #define PT_ENTRIES	(PT_SIZE / sizeof(u32))
 
 #define GPU_MEM_START	0x80000000
@@ -88,7 +88,7 @@ static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
 
 static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
 {
-	u32 iova, *p;
+	u32 *p;
 	int ret, i;
 
 	etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
@@ -110,11 +110,9 @@ static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
 		return ret;
 	}
 
-	for (iova = etnaviv_domain->domain.geometry.aperture_start;
-	     iova < etnaviv_domain->domain.geometry.aperture_end; iova += SZ_4K) {
-		pgtable_write(&etnaviv_domain->pgtable, iova,
-			      etnaviv_domain->bad_page_dma);
-	}
+	for (i = 0; i < PT_ENTRIES; i++)
+		etnaviv_domain->pgtable.pgtable[i] =
+			etnaviv_domain->bad_page_dma;
 
 	spin_lock_init(&etnaviv_domain->map_lock);
 
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 26/48] staging: etnaviv: fix BUG_ON when removing module
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (24 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 25/48] staging: etnaviv: increase page table size to maximum Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 27/48] staging: etnaviv: provide a helper to load the GPU clock field Lucas Stach
                         ` (22 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 233b2197eb37..b12d46075732 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -1157,7 +1157,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
 #endif
 
 	if (gpu->buffer) {
-		drm_gem_object_unreference(gpu->buffer);
+		drm_gem_object_unreference_unlocked(gpu->buffer);
 		gpu->buffer = NULL;
 	}
 
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 27/48] staging: etnaviv: provide a helper to load the GPU clock field
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (25 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 26/48] staging: etnaviv: fix BUG_ON when removing module Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 28/48] staging: etnaviv: rename GPU clock functions Lucas Stach
                         ` (21 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

The GPU requires a double-write to set the clock divisor.  Rather than
open-coding this knowledge in a couple of places, provide a helper to
do this instead.  This avoids spreading this knowledge around the
driver.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index b12d46075732..d274fcf9f5b1 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -280,6 +280,13 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
 	etnaviv_hw_specs(gpu);
 }
 
+static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock)
+{
+	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock |
+		  VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD);
+	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
+}
+
 static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
 {
 	u32 control, idle;
@@ -301,9 +308,7 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
 			  VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
 
 		/* enable clock */
-		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control |
-			  VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD);
-		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+		etnaviv_gpu_load_clock(gpu, control);
 
 		/* Wait for stable clock.  Vivante's code waited for 1ms */
 		usleep_range(1000, 10000);
@@ -367,9 +372,7 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
 		  VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
 
 	/* enable clock */
-	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control |
-		  VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD);
-	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+	etnaviv_gpu_load_clock(gpu, control);
 
 	return 0;
 }
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 28/48] staging: etnaviv: rename GPU clock functions
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (26 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 27/48] staging: etnaviv: provide a helper to load the GPU clock field Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 29/48] staging: etnaviv: fix runtime resume Lucas Stach
                         ` (20 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Rename the GPU clock functions for what they actually are, splitting
the clock disable out from etnaviv_gpu_suspend().  This allows us to
fix etnaviv_gpu_rpm_resume(), which needed only to disable the clocks
on failure, rather than trying to stop an uninitialised GPU.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index d274fcf9f5b1..2a6560be4c51 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -1046,7 +1046,7 @@ static irqreturn_t irq_handler(int irq, void *data)
 	return ret;
 }
 
-static int etnaviv_gpu_resume(struct etnaviv_gpu *gpu)
+static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
 {
 	int ret;
 
@@ -1063,10 +1063,23 @@ static int etnaviv_gpu_resume(struct etnaviv_gpu *gpu)
 	return 0;
 }
 
-static int etnaviv_gpu_suspend(struct etnaviv_gpu *gpu)
+static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
 {
 	int ret;
 
+	ret = disable_axi(gpu);
+	if (ret)
+		return ret;
+
+	ret = disable_clk(gpu);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int etnaviv_gpu_suspend(struct etnaviv_gpu *gpu)
+{
 	if (gpu->buffer) {
 		unsigned long timeout;
 
@@ -1096,15 +1109,7 @@ static int etnaviv_gpu_suspend(struct etnaviv_gpu *gpu)
 		} while (1);
 	}
 
-	ret = disable_axi(gpu);
-	if (ret)
-		return ret;
-
-	ret = disable_clk(gpu);
-	if (ret)
-		return ret;
-
-	return 0;
+	return etnaviv_gpu_clk_disable(gpu);
 }
 
 static int etnaviv_gpu_bind(struct device *dev, struct device *master,
@@ -1118,7 +1123,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
 #ifdef CONFIG_PM
 	ret = pm_runtime_get_sync(gpu->dev);
 #else
-	ret = etnaviv_gpu_resume(gpu);
+	ret = etnaviv_gpu_clk_enable(gpu);
 #endif
 	if (ret < 0)
 		return ret;
@@ -1300,7 +1305,7 @@ static int etnaviv_gpu_rpm_resume(struct device *dev)
 	if (drm && WARN_ON_ONCE(mutex_is_locked(&drm->struct_mutex)))
 		return -EDEADLK;
 
-	ret = etnaviv_gpu_resume(gpu);
+	ret = etnaviv_gpu_clk_enable(gpu);
 	if (ret)
 		return ret;
 
@@ -1308,7 +1313,7 @@ static int etnaviv_gpu_rpm_resume(struct device *dev)
 	if (drm && gpu->buffer) {
 		ret = mutex_lock_killable(&drm->struct_mutex);
 		if (ret) {
-			etnaviv_gpu_suspend(gpu);
+			etnaviv_gpu_clk_disable(gpu);
 			return ret;
 		}
 		etnaviv_gpu_hw_init(gpu);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 29/48] staging: etnaviv: fix runtime resume
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (27 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 28/48] staging: etnaviv: rename GPU clock functions Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 30/48] staging: etnaviv: drop event ring buffer tracking Lucas Stach
                         ` (19 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

When resuming a core, especially if it has been powered down by a PM
domain, we need to re-initialise the clock control register, and
perform a reload of the context.

This is important where we have a GPU with multiple execution states,
where we must select the appropriate execution state prior to
processing any further GPU operations from userspace.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 38 ++++++++++++++++++++++++++---------
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 2a6560be4c51..7b618ed69201 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -1078,7 +1078,7 @@ static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
 	return 0;
 }
 
-static int etnaviv_gpu_suspend(struct etnaviv_gpu *gpu)
+static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
 {
 	if (gpu->buffer) {
 		unsigned long timeout;
@@ -1112,6 +1112,29 @@ static int etnaviv_gpu_suspend(struct etnaviv_gpu *gpu)
 	return etnaviv_gpu_clk_disable(gpu);
 }
 
+static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
+{
+	struct drm_device *drm = gpu->drm;
+	u32 clock;
+	int ret;
+
+	ret = mutex_lock_killable(&drm->struct_mutex);
+	if (ret)
+		return ret;
+
+	clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
+		VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
+
+	etnaviv_gpu_load_clock(gpu, clock);
+	etnaviv_gpu_hw_init(gpu);
+
+	gpu->switch_context = true;
+
+	mutex_unlock(&drm->struct_mutex);
+
+	return 0;
+}
+
 static int etnaviv_gpu_bind(struct device *dev, struct device *master,
 	void *data)
 {
@@ -1161,7 +1184,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
 	pm_runtime_get_sync(gpu->dev);
 	pm_runtime_put_sync_suspend(gpu->dev);
 #else
-	etnaviv_gpu_suspend(gpu);
+	etnaviv_gpu_hw_suspend(gpu);
 #endif
 
 	if (gpu->buffer) {
@@ -1292,17 +1315,16 @@ static int etnaviv_gpu_rpm_suspend(struct device *dev)
 	if (idle != mask)
 		return -EBUSY;
 
-	return etnaviv_gpu_suspend(gpu);
+	return etnaviv_gpu_hw_suspend(gpu);
 }
 
 static int etnaviv_gpu_rpm_resume(struct device *dev)
 {
 	struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
-	struct drm_device *drm = gpu->drm;
 	int ret;
 
 	/* We must never runtime-PM resume holding struct_mutex */
-	if (drm && WARN_ON_ONCE(mutex_is_locked(&drm->struct_mutex)))
+	if (gpu->drm && WARN_ON_ONCE(mutex_is_locked(&gpu->drm->struct_mutex)))
 		return -EDEADLK;
 
 	ret = etnaviv_gpu_clk_enable(gpu);
@@ -1310,14 +1332,12 @@ static int etnaviv_gpu_rpm_resume(struct device *dev)
 		return ret;
 
 	/* Re-initialise the basic hardware state */
-	if (drm && gpu->buffer) {
-		ret = mutex_lock_killable(&drm->struct_mutex);
+	if (gpu->drm && gpu->buffer) {
+		ret = etnaviv_gpu_hw_resume(gpu);
 		if (ret) {
 			etnaviv_gpu_clk_disable(gpu);
 			return ret;
 		}
-		etnaviv_gpu_hw_init(gpu);
-		mutex_unlock(&drm->struct_mutex);
 	}
 
 	return 0;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 30/48] staging: etnaviv: drop event ring buffer tracking
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (28 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 29/48] staging: etnaviv: fix runtime resume Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 31/48] staging: etnaviv: improve efficiency of command parser Lucas Stach
                         ` (18 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_buffer.c | 1 -
 drivers/staging/etnaviv/etnaviv_gpu.c    | 4 +---
 drivers/staging/etnaviv/etnaviv_gpu.h    | 2 --
 3 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
index 01a29793aed3..cbeebfde680a 100644
--- a/drivers/staging/etnaviv/etnaviv_buffer.c
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -262,7 +262,6 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 
 	/* Save the event and buffer position of the new event trigger */
 	gpu->event[event].fence = submit->fence;
-	gpu->event[event].ring_pos = buffer->offset;
 
 	/* trigger event */
 	CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 7b618ed69201..137c09293375 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -1021,10 +1021,8 @@ static irqreturn_t irq_handler(int irq, void *data)
 			 * - event 1 and event 0 complete
 			 * we can end up processing event 0 first, then 1.
 			 */
-			if (fence_after(gpu->event[event].fence, gpu->retired_fence)) {
+			if (fence_after(gpu->event[event].fence, gpu->retired_fence))
 				gpu->retired_fence = gpu->event[event].fence;
-				gpu->last_ring_pos = gpu->event[event].ring_pos;
-			}
 			event_free(gpu, event);
 
 			/*
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 44af5ca3f633..b88340302571 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -80,7 +80,6 @@ struct etnaviv_chip_identity {
 struct etnaviv_event {
 	bool used;
 	u32 fence;
-	u32 ring_pos;
 };
 
 struct etnaviv_gpu {
@@ -105,7 +104,6 @@ struct etnaviv_gpu {
 	struct list_head active_list;
 
 	u32 idle_mask;
-	u32 last_ring_pos;
 
 	/* Fencing support */
 	u32 submitted_fence;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 31/48] staging: etnaviv: improve efficiency of command parser
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (29 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 30/48] staging: etnaviv: drop event ring buffer tracking Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 32/48] staging: etnaviv: no point looking up the mapping for cmdstream bos Lucas Stach
                         ` (17 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Performance analysis indicates that the command parser is a hot spot
in the code.  We can improve the efficiency of the command parser by
storing the command length in a table, rather than decoding the
command manually via a switch statement.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_cmd_parser.c | 34 +++++++++++++---------------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_cmd_parser.c b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
index d866b8e2381d..7ae6ddb4306e 100644
--- a/drivers/staging/etnaviv/etnaviv_cmd_parser.c
+++ b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
@@ -54,6 +54,13 @@ static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf,
 	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,
 	struct etnaviv_gem_object *obj, unsigned int offset, unsigned int size)
 {
@@ -69,7 +76,7 @@ bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
 		switch (op) {
 		case FE_OPCODE_LOAD_STATE:
 			n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT);
-			len = 1 + n;
+			len = ALIGN(1 + n, 2);
 			if (buf + len > end)
 				break;
 
@@ -89,26 +96,17 @@ bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
 			len = 2 + n * 2;
 			break;
 
-		case FE_OPCODE_DRAW_PRIMITIVES:
-			len = 4;
-			break;
-
-		case FE_OPCODE_DRAW_INDEXED_PRIMITIVES:
-			len = 6;
-			break;
-
-		case FE_OPCODE_NOP:
-		case FE_OPCODE_STALL:
-			len = 2;
-			break;
-
 		default:
-			dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
-				__func__, op, buf - start);
-			return false;
+			len = cmd_length[op];
+			if (len == 0) {
+				dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
+					__func__, op, buf - start);
+				return false;
+			}
+			break;
 		}
 
-		buf += ALIGN(len, 2);
+		buf += len;
 	}
 
 	if (buf > end) {
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 32/48] staging: etnaviv: no point looking up the mapping for cmdstream bos
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (30 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 31/48] staging: etnaviv: improve efficiency of command parser Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 33/48] staging: etnaviv: copy submit command and bos in one go Lucas Stach
                         ` (16 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 3a68295eaee4..02c5e46dca75 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -295,8 +295,7 @@ int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
 	struct drm_gem_object *obj, u32 *iova)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-	struct etnaviv_vram_mapping *mapping =
-			etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
+	struct etnaviv_vram_mapping *mapping;
 	int ret = 0;
 
 	if (etnaviv_obj->flags & ETNA_BO_CMDSTREAM) {
@@ -304,6 +303,7 @@ int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
 		return 0;
 	}
 
+	mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
 	if (!mapping) {
 		struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
 		if (IS_ERR(pages))
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 33/48] staging: etnaviv: copy submit command and bos in one go
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (31 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 32/48] staging: etnaviv: no point looking up the mapping for cmdstream bos Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 34/48] staging: etnaviv: remove cmd buffer offset validation in submit_reloc() Lucas Stach
                         ` (15 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

On GPU submission, copy the submit command and bo structures in one go
and outside of dev->struct_mutex.  There are two reasons:

- This avoids the overhead from calling and checking copy_from_user()
  multiple times.
- Holding dev->struct_mutex over a page fault should be avoided as this
  will block all users of the GPU while page IO is being performed.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 98 ++++++++++++++++------------
 1 file changed, 57 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index e2c94f476810..f94b6e8fb4fb 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -55,41 +55,34 @@ static struct etnaviv_gem_submit *submit_create(struct drm_device *dev,
 }
 
 static int submit_lookup_objects(struct etnaviv_gem_submit *submit,
-		struct drm_etnaviv_gem_submit *args, struct drm_file *file)
+	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; i < args->nr_bos; i++) {
-		struct drm_etnaviv_gem_submit_bo submit_bo;
+	for (i = 0, bo = submit_bos; i < nr_bos; i++, bo++) {
 		struct drm_gem_object *obj;
 		struct etnaviv_gem_object *etnaviv_obj;
-		void __user *userptr =
-			to_user_ptr(args->bos + (i * sizeof(submit_bo)));
-
-		ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
-		if (ret) {
-			ret = -EFAULT;
-			goto out_unlock;
-		}
 
-		if (submit_bo.flags & BO_INVALID_FLAGS) {
-			DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
+		if (bo->flags & BO_INVALID_FLAGS) {
+			DRM_ERROR("invalid flags: %x\n", bo->flags);
 			ret = -EINVAL;
 			goto out_unlock;
 		}
 
-		submit->bos[i].flags = submit_bo.flags;
+		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, submit_bo.handle);
+		obj = idr_find(&file->object_idr, bo->handle);
 		if (!obj) {
 			DRM_ERROR("invalid handle %u at index %u\n",
-				  submit_bo.handle, i);
+				  bo->handle, i);
 			ret = -EINVAL;
 			goto out_unlock;
 		}
@@ -98,7 +91,7 @@ static int submit_lookup_objects(struct etnaviv_gem_submit *submit,
 
 		if (!list_empty(&etnaviv_obj->submit_entry)) {
 			DRM_ERROR("handle %u at index %u already on submit list\n",
-				  submit_bo.handle, i);
+				  bo->handle, i);
 			ret = -EINVAL;
 			goto out_unlock;
 		}
@@ -298,6 +291,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct drm_etnaviv_gem_submit *args = data;
 	struct etnaviv_file_private *ctx = file->driver_priv;
+	struct drm_etnaviv_gem_submit_cmd *cmds;
+	struct drm_etnaviv_gem_submit_bo *bos;
 	struct etnaviv_gem_submit *submit;
 	struct etnaviv_gpu *gpu;
 	unsigned i;
@@ -314,6 +309,29 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		return -EINVAL;
 
 	/*
+	 * Copy the command submission and bo array to kernel space in
+	 * one go, and do this outside of the dev->struct_mutex lock.
+	 */
+	cmds = drm_malloc_ab(args->nr_cmds, sizeof(*cmds));
+	bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
+	if (!cmds || !bos)
+		return -ENOMEM;
+
+	ret = copy_from_user(cmds, to_user_ptr(args->cmds),
+			     args->nr_cmds * sizeof(*cmds));
+	if (ret) {
+		ret = -EFAULT;
+		goto err_submit_cmds;
+	}
+
+	ret = copy_from_user(bos, to_user_ptr(args->bos),
+			     args->nr_bos * sizeof(*bos));
+	if (ret) {
+		ret = -EFAULT;
+		goto err_submit_cmds;
+	}
+
+	/*
 	 * Avoid big circular locking dependency loops:
 	 * - reading debugfs results in mmap_sem depending on i_mutex_key#3
 	 *   (iterate_dir -> filldir64)
@@ -332,7 +350,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	 */
 	ret = etnaviv_gpu_pm_get_sync(gpu);
 	if (ret < 0)
-		return ret;
+		goto err_submit_cmds;
 
 	mutex_lock(&dev->struct_mutex);
 
@@ -343,7 +361,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	}
 	submit->exec_state = args->exec_state;
 
-	ret = submit_lookup_objects(submit, args, file);
+	ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
 	if (ret)
 		goto out;
 
@@ -352,19 +370,11 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		goto out;
 
 	for (i = 0; i < args->nr_cmds; i++) {
-		struct drm_etnaviv_gem_submit_cmd submit_cmd;
-		void __user *userptr =
-			to_user_ptr(args->cmds + (i * sizeof(submit_cmd)));
+		struct drm_etnaviv_gem_submit_cmd *submit_cmd = cmds + i;
 		struct etnaviv_gem_object *etnaviv_obj;
 		unsigned max_size;
 
-		ret = copy_from_user(&submit_cmd, userptr, sizeof(submit_cmd));
-		if (ret) {
-			ret = -EFAULT;
-			goto out;
-		}
-
-		ret = submit_bo(submit, submit_cmd.submit_idx, &etnaviv_obj,
+		ret = submit_bo(submit, submit_cmd->submit_idx, &etnaviv_obj,
 				NULL);
 		if (ret)
 			goto out;
@@ -375,16 +385,16 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 			goto out;
 		}
 
-		if (submit_cmd.size % 4) {
+		if (submit_cmd->size % 4) {
 			DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
-					submit_cmd.size);
+					submit_cmd->size);
 			ret = -EINVAL;
 			goto out;
 		}
 
-		if (submit_cmd.submit_offset % 8) {
+		if (submit_cmd->submit_offset % 8) {
 			DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
-					submit_cmd.size);
+					submit_cmd->size);
 			ret = -EINVAL;
 			goto out;
 		}
@@ -395,17 +405,17 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		 */
 		max_size = etnaviv_obj->base.size - 8;
 
-		if (submit_cmd.size > max_size ||
-		    submit_cmd.submit_offset > max_size - submit_cmd.size) {
+		if (submit_cmd->size > max_size ||
+		    submit_cmd->submit_offset > max_size - submit_cmd->size) {
 			DRM_ERROR("invalid cmdstream size: %u\n",
-				  submit_cmd.size);
+				  submit_cmd->size);
 			ret = -EINVAL;
 			goto out;
 		}
 
-		submit->cmd[i].type = submit_cmd.type;
-		submit->cmd[i].offset = submit_cmd.submit_offset / 4;
-		submit->cmd[i].size = submit_cmd.size / 4;
+		submit->cmd[i].type = submit_cmd->type;
+		submit->cmd[i].offset = submit_cmd->submit_offset / 4;
+		submit->cmd[i].size = submit_cmd->size / 4;
 		submit->cmd[i].obj = etnaviv_obj;
 
 		if (!etnaviv_cmd_validate_one(gpu, etnaviv_obj,
@@ -416,8 +426,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		}
 
 		ret = submit_reloc(submit, etnaviv_obj,
-				   submit_cmd.submit_offset,
-				   submit_cmd.nr_relocs, submit_cmd.relocs);
+				   submit_cmd->submit_offset,
+				   submit_cmd->nr_relocs, submit_cmd->relocs);
 		if (ret)
 			goto out;
 	}
@@ -443,5 +453,11 @@ out:
 	if (ret == -EAGAIN)
 		flush_workqueue(priv->wq);
 
+ err_submit_cmds:
+	if (bos)
+		drm_free_large(bos);
+	if (cmds)
+		drm_free_large(cmds);
+
 	return ret;
 }
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 34/48] staging: etnaviv: remove cmd buffer offset validation in submit_reloc()
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (32 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 33/48] staging: etnaviv: copy submit command and bos in one go Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 35/48] staging: etnaviv: move mapping teardown into etnaviv_gem_free_object() Lucas Stach
                         ` (14 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

We've already validated the command buffer offset, there's no need to
repeat it elsewhere.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index f94b6e8fb4fb..a0bc61946036 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -219,11 +219,6 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, struct etnaviv_gem_ob
 	u32 *ptr = obj->vaddr;
 	int ret;
 
-	if (offset % 4) {
-		DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
-		return -EINVAL;
-	}
-
 	for (i = 0; i < nr_relocs; i++) {
 		struct drm_etnaviv_gem_submit_reloc submit_reloc;
 		struct etnaviv_gem_object *bobj;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 35/48] staging: etnaviv: move mapping teardown into etnaviv_gem_free_object()
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (33 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 34/48] staging: etnaviv: remove cmd buffer offset validation in submit_reloc() Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 36/48] staging: etnaviv: add support for GEM_WAIT ioctl Lucas Stach
                         ` (13 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Move the mapping teardown directly into etnaviv_gem_free_object().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 02c5e46dca75..1c003afc9ab1 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -502,17 +502,6 @@ static const struct etnaviv_gem_ops etnaviv_gem_cmd_ops = {
 	.release = etnaviv_gem_cmd_release,
 };
 
-static void etnaviv_free_obj(struct drm_gem_object *obj)
-{
-	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-	struct etnaviv_vram_mapping *mapping, *tmp;
-
-	list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
-				 obj_node) {
-		etnaviv_iommu_unmap_gem(mapping);
-	}
-}
-
 static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)
 {
 	if (etnaviv_obj->vaddr)
@@ -529,6 +518,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	struct etnaviv_vram_mapping *mapping, *tmp;
 
 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
@@ -537,8 +527,9 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
 
 	list_del(&etnaviv_obj->mm_list);
 
-	if (!(etnaviv_obj->flags & ETNA_BO_CMDSTREAM))
-		etnaviv_free_obj(obj);
+	list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
+				 obj_node)
+		etnaviv_iommu_unmap_gem(mapping);
 
 	drm_gem_free_mmap_offset(obj);
 	etnaviv_obj->ops->release(etnaviv_obj);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 36/48] staging: etnaviv: add support for GEM_WAIT ioctl
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (34 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 35/48] staging: etnaviv: move mapping teardown into etnaviv_gem_free_object() Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 37/48] staging: etnaviv: avoid pinning pages in CMA Lucas Stach
                         ` (12 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Add support for the new GEM_WAIT ioctl, which waits for the kernel to
finish with the GEM object (all render complete, and has been retired).
This is different from the WAIT_FENCE ioctl, which just waits for
rendering to complete.

This is an important distinction, as when a gem object is retired and
freed, the kernel will invalidate the cache for this object, which
effectively changes the data userspace sees.  If userspace merely
waits for rendering to complete, there is a race condition where a
userptr BO can be free()d and re-used, and the kernel's invalidation
then corrupts the malloc() free lists.

GEM_WAIT is not fully race free: if the BO is re-submitted via a
different thread, we can't report this (indeed, this could happen
after the call has returned.)  It is up to userspace to ensure that
such behaviour does not occur.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 29 +++++++++++++
 drivers/staging/etnaviv/etnaviv_gem.c |  8 ++++
 drivers/staging/etnaviv/etnaviv_gem.h |  2 +
 drivers/staging/etnaviv/etnaviv_gpu.c | 76 +++++++++++++++++++++++++++--------
 drivers/staging/etnaviv/etnaviv_gpu.h |  8 ++++
 include/uapi/drm/etnaviv_drm.h        | 10 ++++-
 6 files changed, 116 insertions(+), 17 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index d7133e4450c6..85dbe3813859 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -19,6 +19,7 @@
 
 #include "etnaviv_drv.h"
 #include "etnaviv_gpu.h"
+#include "etnaviv_gem.h"
 #include "etnaviv_mmu.h"
 
 #ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
@@ -451,6 +452,33 @@ static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
 				       &args->handle);
 }
 
+static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
+	struct drm_file *file)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct drm_etnaviv_gem_wait *args = data;
+	struct drm_gem_object *obj;
+	struct etnaviv_gpu *gpu;
+	int ret;
+
+	if (args->pipe >= ETNA_MAX_PIPES)
+		return -EINVAL;
+
+	gpu = priv->gpu[args->pipe];
+	if (!gpu)
+		return -ENXIO;
+
+	obj = drm_gem_object_lookup(dev, file, args->handle);
+	if (!obj)
+		return -ENOENT;
+
+	ret = etnaviv_gem_wait_bo(gpu, obj, &TS(args->timeout));
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	return ret;
+}
+
 static const struct drm_ioctl_desc etnaviv_ioctls[] = {
 #define ETNA_IOCTL(n, func, flags) \
 	DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
@@ -462,6 +490,7 @@ static const struct drm_ioctl_desc etnaviv_ioctls[] = {
 	ETNA_IOCTL(GEM_SUBMIT,   gem_submit,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
 	ETNA_IOCTL(WAIT_FENCE,   wait_fence,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
 	ETNA_IOCTL(GEM_USERPTR,  gem_userptr,  DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	ETNA_IOCTL(GEM_WAIT,     gem_wait,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
 };
 
 static const struct vm_operations_struct vm_ops = {
diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 1c003afc9ab1..2518f897fdd8 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -457,6 +457,14 @@ int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
 	return 0;
 }
 
+int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
+	struct timespec *timeout)
+{
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	return etnaviv_gpu_wait_obj_inactive(gpu, etnaviv_obj, timeout);
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
 {
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index f3136d86d73e..4d5455a3fe39 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -130,6 +130,8 @@ struct etnaviv_gem_submit {
 	} bos[0];
 };
 
+int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
+	struct timespec *timeout);
 struct etnaviv_vram_mapping *
 etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
 			     struct etnaviv_iommu *mmu);
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 137c09293375..f89fa869885e 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -743,7 +743,7 @@ static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
 static void hangcheck_handler(unsigned long data)
 {
 	struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
-	u32 fence = gpu->retired_fence;
+	u32 fence = gpu->completed_fence;
 	bool progress = false;
 
 	if (fence != gpu->hangcheck_fence) {
@@ -837,7 +837,7 @@ static void retire_worker(struct work_struct *work)
 	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
 					       retire_work);
 	struct drm_device *dev = gpu->drm;
-	u32 fence = gpu->retired_fence;
+	u32 fence = gpu->completed_fence;
 
 	mutex_lock(&dev->struct_mutex);
 
@@ -860,11 +860,27 @@ static void retire_worker(struct work_struct *work)
 		}
 	}
 
+	gpu->retired_fence = fence;
+
 	mutex_unlock(&dev->struct_mutex);
 
 	wake_up_all(&gpu->fence_event);
 }
 
+static unsigned long etnaviv_timeout_to_jiffies(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;
+}
+
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
 	u32 fence, struct timespec *timeout)
 {
@@ -880,21 +896,15 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
 		/* No timeout was requested: just test for completion */
 		ret = fence_completed(gpu, fence) ? 0 : -EBUSY;
 	} else {
-		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;
+		unsigned long remaining = etnaviv_timeout_to_jiffies(timeout);
 
 		ret = wait_event_interruptible_timeout(gpu->fence_event,
 						fence_completed(gpu, fence),
-						remaining_jiffies);
+						remaining);
 		if (ret == 0) {
-			DBG("timeout waiting for fence: %u (completed: %u)",
-					fence, gpu->retired_fence);
+			DBG("timeout waiting for fence: %u (retired: %u completed: %u)",
+				fence, gpu->retired_fence,
+				gpu->completed_fence);
 			ret = -ETIMEDOUT;
 		} else if (ret != -ERESTARTSYS) {
 			ret = 0;
@@ -904,6 +914,39 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
 	return ret;
 }
 
+/*
+ * Wait for an object to become inactive.  This, on it's own, is not race
+ * free: the object is moved by the retire worker off the active list, and
+ * then the iova is put.  Moreover, the object could be re-submitted just
+ * after we notice that it's become inactive.
+ *
+ * Although the retirement happens under the struct_mutex, we don't want
+ * to hold that lock in this function.  Instead, the caller is responsible
+ * for ensuring that the retire worker has finished (which will happen, eg,
+ * when we unreference the object, an action which takes the struct_mutex.)
+ */
+int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
+	struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout)
+{
+	unsigned long remaining;
+	long ret;
+
+	if (!timeout)
+		return !is_active(etnaviv_obj) ? 0 : -EBUSY;
+
+	remaining = etnaviv_timeout_to_jiffies(timeout);
+
+	ret = wait_event_interruptible_timeout(gpu->fence_event,
+					       !is_active(etnaviv_obj),
+					       remaining);
+	if (ret > 0)
+		return 0;
+	else if (ret == -ERESTARTSYS)
+		return -ERESTARTSYS;
+	else
+		return -ETIMEDOUT;
+}
+
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu)
 {
 	return pm_runtime_get_sync(gpu->dev);
@@ -1021,8 +1064,9 @@ static irqreturn_t irq_handler(int irq, void *data)
 			 * - event 1 and event 0 complete
 			 * we can end up processing event 0 first, then 1.
 			 */
-			if (fence_after(gpu->event[event].fence, gpu->retired_fence))
-				gpu->retired_fence = gpu->event[event].fence;
+			if (fence_after(gpu->event[event].fence,
+					gpu->completed_fence))
+				gpu->completed_fence = gpu->event[event].fence;
 			event_free(gpu, event);
 
 			/*
@@ -1304,7 +1348,7 @@ static int etnaviv_gpu_rpm_suspend(struct device *dev)
 	u32 idle, mask;
 
 	/* If we have outstanding fences, we're not idle */
-	if (gpu->retired_fence != gpu->submitted_fence)
+	if (gpu->completed_fence != gpu->submitted_fence)
 		return -EBUSY;
 
 	/* Check whether the hardware (except FE) is idle */
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index b88340302571..374f37f3665f 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -107,6 +107,7 @@ struct etnaviv_gpu {
 
 	/* Fencing support */
 	u32 submitted_fence;
+	u32 completed_fence;
 	u32 retired_fence;
 	wait_queue_head_t fence_event;
 
@@ -144,6 +145,11 @@ static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 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);
 }
 
@@ -158,6 +164,8 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
 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_file_private *ctx);
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index 0aca6b189e63..7cc749c30970 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -199,6 +199,12 @@ struct drm_etnaviv_gem_userptr {
 	__u32 handle;	/* out, non-zero handle */
 };
 
+struct drm_etnaviv_gem_wait {
+	__u32 pipe;				/* in */
+	__u32 handle;				/* in, bo to be waited for */
+	struct drm_etnaviv_timespec timeout;	/* in */
+};
+
 #define DRM_ETNAVIV_GET_PARAM          0x00
 /* placeholder:
 #define DRM_ETNAVIV_SET_PARAM          0x01
@@ -210,7 +216,8 @@ struct drm_etnaviv_gem_userptr {
 #define DRM_ETNAVIV_GEM_SUBMIT         0x06
 #define DRM_ETNAVIV_WAIT_FENCE         0x07
 #define DRM_ETNAVIV_GEM_USERPTR        0x08
-#define DRM_ETNAVIV_NUM_IOCTLS         0x09
+#define DRM_ETNAVIV_GEM_WAIT           0x09
+#define DRM_ETNAVIV_NUM_IOCTLS         0x0a
 
 #define DRM_IOCTL_ETNAVIV_GET_PARAM    DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
 #define DRM_IOCTL_ETNAVIV_GEM_NEW      DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
@@ -220,5 +227,6 @@ struct drm_etnaviv_gem_userptr {
 #define DRM_IOCTL_ETNAVIV_GEM_SUBMIT   DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit)
 #define DRM_IOCTL_ETNAVIV_WAIT_FENCE   DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
 #define DRM_IOCTL_ETNAVIV_GEM_USERPTR  DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
+#define DRM_IOCTL_ETNAVIV_GEM_WAIT     DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
 
 #endif /* __ETNAVIV_DRM_H__ */
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 37/48] staging: etnaviv: avoid pinning pages in CMA
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (35 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 36/48] staging: etnaviv: add support for GEM_WAIT ioctl Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 38/48] staging: etnaviv: fix 'ret' may be used uninitialized in this function Lucas Stach
                         ` (11 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Russell King <rmk+kernel@arm.linux.org.uk>

The CMA memory area is shared between CMA and other users.  In order to
allow CMA to work, non-CMA allocations in this area must be for movable
pages, so that a CMA allocation can reclaim its memory from other users
when required.

Page cache backed allocations, such as pages allocated via shmem, are by
default marked as "movable" allocations, which means that they can come
from the CMA region.

However, in etnaviv's case, we allocate shmem pages, and then we pin
these pages for the life of the buffer.  This prevents the pages being
reclaimed, and causes CMA failures.

new_inode() in fs/inode.c even says:

 * Allocates a new inode for given superblock. The default gfp_mask
 * for allocations related to inode->i_mapping is GFP_HIGHUSER_MOVABLE.
 * If HIGHMEM pages are unsuitable or it is known that pages allocated
 * for the page cache are not reclaimable or migratable,
 * mapping_set_gfp_mask() must be called with suitable flags on the
 * newly created inode's mapping

Etnaviv shmem pages are not reclaimable nor migratable once they're
pinned, so etnaviv is not conforming with this requirement.  Change the
gfp_mask to GFP_HIGHUSER, so we can still allocate from highmem, but not
from the CMA area.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 2518f897fdd8..5c2462d6130d 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -640,6 +640,19 @@ static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
 	} else {
 		to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops;
 		ret = drm_gem_object_init(dev, obj, size);
+		if (ret == 0) {
+			struct address_space *mapping;
+
+			/*
+			 * Our buffers are kept pinned, so allocating them
+			 * from the MOVABLE zone is a really bad idea, and
+			 * conflicts with CMA.  See coments above new_inode()
+			 * why this is required _and_ expected if you're
+			 * going to pin these pages.
+			 */
+			mapping = file_inode(obj->filp)->i_mapping;
+			mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
+		}
 	}
 
 	if (ret)
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 38/48] staging: etnaviv: fix 'ret' may be used uninitialized in this function
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (36 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 37/48] staging: etnaviv: avoid pinning pages in CMA Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 39/48] staging: etnaviv: fix error: 'etnaviv_gpu_hw_resume' defined but not used Lucas Stach
                         ` (10 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Christian Gmeiner <christian.gmeiner@gmail.com>

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 5c2462d6130d..3e08f0694021 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -752,7 +752,7 @@ struct get_pages_work {
 static struct page **etnaviv_gem_userptr_do_get_pages(
 	struct etnaviv_gem_object *etnaviv_obj, struct mm_struct *mm, struct task_struct *task)
 {
-	int ret, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+	int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
 	struct page **pvec;
 	uintptr_t ptr;
 
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 39/48] staging: etnaviv: fix error: 'etnaviv_gpu_hw_resume' defined but not used
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (37 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 38/48] staging: etnaviv: fix 'ret' may be used uninitialized in this function Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-09-25 11:57       ` [PATCH 40/48] staging: etnaviv: debugfs: add possibility to dump kernel buffer Lucas Stach
                         ` (9 subsequent siblings)
  48 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Christian Gmeiner <christian.gmeiner@gmail.com>

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index f89fa869885e..948c85a8a591 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -1154,6 +1154,7 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
 	return etnaviv_gpu_clk_disable(gpu);
 }
 
+#ifdef CONFIG_PM
 static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
 {
 	struct drm_device *drm = gpu->drm;
@@ -1176,6 +1177,7 @@ static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
 
 	return 0;
 }
+#endif
 
 static int etnaviv_gpu_bind(struct device *dev, struct device *master,
 	void *data)
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 40/48] staging: etnaviv: debugfs: add possibility to dump kernel buffer
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (38 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 39/48] staging: etnaviv: fix error: 'etnaviv_gpu_hw_resume' defined but not used Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 11:38         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 41/48] staging: etnaviv: change etnaviv_buffer_init() to return prefetch Lucas Stach
                         ` (8 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Christian Gmeiner <christian.gmeiner@gmail.com>

This is very useful for debugging issues regarding command
buffer processing.

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
---
 drivers/staging/etnaviv/etnaviv_drv.c | 39 +++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index 85dbe3813859..d55d2c9f4d0f 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -21,6 +21,7 @@
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
 #include "etnaviv_mmu.h"
+#include "etnaviv_gem.h"
 
 #ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
 static bool reglog;
@@ -234,6 +235,43 @@ static int etnaviv_mmu_show(struct drm_device *dev, struct seq_file *m)
 	return 0;
 }
 
+static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
+{
+	struct etnaviv_gem_object *obj = to_etnaviv_bo(gpu->buffer);
+	u32 size = obj->base.size;
+	u32 *ptr = obj->vaddr;
+	u32 i;
+
+	seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
+			obj->vaddr, (u64)obj->paddr, size - (obj->offset * 4));
+
+	for (i = 0; i < size / 4; i++) {
+		if (i && !(i % 4))
+			seq_puts(m, "\n");
+		if (i % 4 == 0)
+			seq_printf(m, "\t0x%p: ", ptr + i);
+		seq_printf(m, "%08x ", *(ptr + i));
+	}
+	seq_puts(m, "\n");
+}
+
+static int etnaviv_ring_show(struct drm_device *dev, struct seq_file *m)
+{
+	struct etnaviv_drm_private *priv = dev->dev_private;
+	struct etnaviv_gpu *gpu;
+	unsigned int i;
+
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		gpu = priv->gpu[i];
+		if (gpu) {
+			seq_printf(m, "Ring Buffer (%s): ",
+				   dev_name(gpu->dev));
+			etnaviv_buffer_dump(gpu, m);
+		}
+	}
+	return 0;
+}
+
 static int show_locked(struct seq_file *m, void *arg)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -282,6 +320,7 @@ static struct drm_info_list etnaviv_debugfs_list[] = {
 		{"gem", show_locked, 0, etnaviv_gem_show},
 		{ "mm", show_locked, 0, etnaviv_mm_show },
 		{"mmu", show_locked, 0, etnaviv_mmu_show},
+		{"ring", show_locked, 0, etnaviv_ring_show},
 };
 
 static int etnaviv_debugfs_init(struct drm_minor *minor)
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 41/48] staging: etnaviv: change etnaviv_buffer_init() to return prefetch
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (39 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 40/48] staging: etnaviv: debugfs: add possibility to dump kernel buffer Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 11:38         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 42/48] staging: etnaviv: implement simple hang recovery Lucas Stach
                         ` (7 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

From: Christian Gmeiner <christian.gmeiner@gmail.com>

etnaviv_buffer_init() creates a very simple command buffer
to be able to start the FE. FE fetches 'prefetch' number of 64 bit
words via DMA and starts to execute the read buffer.

This is a very simple code cleanup and pushes the whole buffer
logic (alignment, cmd buffer commands, etc.) into etnaviv_buffer.c

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
---
 drivers/staging/etnaviv/etnaviv_buffer.c | 4 ++--
 drivers/staging/etnaviv/etnaviv_drv.h    | 2 +-
 drivers/staging/etnaviv/etnaviv_gpu.c    | 9 +++------
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
index cbeebfde680a..1994eceae1ae 100644
--- a/drivers/staging/etnaviv/etnaviv_buffer.c
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -124,7 +124,7 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
 			ptr, len * 4, 0);
 }
 
-u32 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
+u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
 {
 	struct etnaviv_gem_object *buffer = to_etnaviv_bo(gpu->buffer);
 
@@ -135,7 +135,7 @@ u32 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
 	CMD_WAIT(buffer);
 	CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + ((buffer->offset - 1) * 4));
 
-	return buffer->offset;
+	return buffer->offset / 2;
 }
 
 void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index b98db8c11ef3..40629207b04f 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -103,7 +103,7 @@ 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);
-u32 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
+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_gem_submit *submit);
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 948c85a8a591..84dedb77ea76 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -379,7 +379,7 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
 
 static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 {
-	u32 words; /* 32 bit words */
+	u16 prefetch;
 
 	if (gpu->identity.model == chipModel_GC320 &&
 	    gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400 &&
@@ -426,17 +426,14 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 	etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain);
 
 	/* Start command processor */
-	words = etnaviv_buffer_init(gpu);
-
-	/* convert number of 32 bit words to number of 64 bit words */
-	words = ALIGN(words, 2) / 2;
+	prefetch = etnaviv_buffer_init(gpu);
 
 	gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
 	gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS,
 		  etnaviv_gem_paddr_locked(gpu->buffer) - gpu->memory_base);
 	gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
 		  VIVS_FE_COMMAND_CONTROL_ENABLE |
-		  VIVS_FE_COMMAND_CONTROL_PREFETCH(words));
+		  VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
 }
 
 int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 42/48] staging: etnaviv: implement simple hang recovery
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (40 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 41/48] staging: etnaviv: change etnaviv_buffer_init() to return prefetch Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 15:43         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 43/48] staging: etnaviv: map all buffers to the GPU Lucas Stach
                         ` (6 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

Not bullet proof yet, as this possibly shoots down more submits than
necessary. However it allows for fairly rapid turnarounds during
userspace development.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 84dedb77ea76..39ac08d26260 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -719,12 +719,40 @@ static void recover_worker(struct work_struct *work)
 	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
 					       recover_work);
 	struct drm_device *dev = gpu->drm;
+	unsigned long flags;
+	unsigned int i;
 
 	dev_err(gpu->dev, "hangcheck recover!\n");
 
+	if (pm_runtime_get_sync(gpu->dev) < 0)
+		return;
+
 	mutex_lock(&dev->struct_mutex);
-	/* TODO gpu->funcs->recover(gpu); */
+
+	etnaviv_hw_reset(gpu);
+
+	/* complete all events, the GPU won't do it after the reset */
+	spin_lock_irqsave(&gpu->event_spinlock, flags);
+	for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
+		if (!gpu->event[i].used)
+			continue;
+		gpu->event[i].used = false;
+		complete(&gpu->event_free);
+		/*
+		 * Decrement the PM count for each stuck event. This is safe
+		 * even in atomic context as we use ASYNC RPM here.
+		 */
+		pm_runtime_put_autosuspend(gpu->dev);
+	}
+	spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+	gpu->completed_fence = gpu->submitted_fence;
+
+	etnaviv_gpu_hw_init(gpu);
+	gpu->switch_context = true;
+
 	mutex_unlock(&dev->struct_mutex);
+	pm_runtime_mark_last_busy(gpu->dev);
+	pm_runtime_put_autosuspend(gpu->dev);
 
 	/* Retire the buffer objects in a work */
 	etnaviv_queue_work(gpu->drm, &gpu->retire_work);
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 43/48] staging: etnaviv: map all buffers to the GPU
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (41 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 42/48] staging: etnaviv: implement simple hang recovery Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 15:23         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 44/48] staging: etnaviv: implement cache maintenance on cpu_(prep|fini) Lucas Stach
                         ` (5 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

This redefines how we do cache handling in the following way:

All buffer are pushed into the GPU domain initially, this will only
be done when populating the buffers backing store, but for simplicity
userspace can assume that the buffer is owned by the GPU as soon as it
constructs a GEM handle. The memory is only implicitly pulled back into
the CPU domain when destroying the handle.

Uncached and writecombined buffers can stay in the GPU domain for their
entire lifetime, as any modification to them will be seen by the GPU
either immediately or latest when the write buffers get flushed when
linking a new submit into the GPUs command stream.

If any modifications needs to be done to a cached buffer they must be
pulled into the CPU domain before and pushed to the GPU afterwards in
an explicit manner.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 3e08f0694021..5ee43861095d 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -31,9 +31,8 @@ static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
 	 * For non-cached buffers, ensure the new pages are clean
 	 * because display controller, GPU, etc. are not coherent.
 	 */
-	if (etnaviv_obj->flags & (ETNA_BO_WC|ETNA_BO_CACHED)) {
+	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK) {
 		dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
-		dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
 	} else {
 		struct scatterlist *sg;
 		unsigned int i;
@@ -67,8 +66,7 @@ static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj
 	 * written into the remainder of the region, this can
 	 * discard those writes.
 	 */
-	if (etnaviv_obj->flags & (ETNA_BO_WC|ETNA_BO_CACHED)) {
-		dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK) {
 		dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
 	}
 }
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 44/48] staging: etnaviv: implement cache maintenance on cpu_(prep|fini)
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (42 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 43/48] staging: etnaviv: map all buffers to the GPU Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 15:23         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 45/48] staging: etnaviv: remove submit type Lucas Stach
                         ` (4 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

This makes sure that we are satifying the cache handling rules outlined
in the previous commit. Cached buffers are pulled into the CPU domain
before access and pushed to the GPU again when the CPU is done.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 41 +++++++++++++++++++++++++++++++++--
 drivers/staging/etnaviv/etnaviv_gem.h |  3 +++
 2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 5ee43861095d..c9300f1e03d5 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -424,10 +424,21 @@ void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj)
 	list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list);
 }
 
+static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
+{
+	if (op & ETNA_PREP_READ)
+		return DMA_FROM_DEVICE;
+	else if (op & ETNA_PREP_WRITE)
+		return DMA_TO_DEVICE;
+	else
+		return DMA_BIDIRECTIONAL;
+}
+
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
 		struct timespec *timeout)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+	struct drm_device *dev = obj->dev;
 	int ret = 0;
 
 	if (is_active(etnaviv_obj)) {
@@ -444,14 +455,40 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
 		ret = etnaviv_gpu_wait_fence_interruptible(gpu, fence, timeout);
 	}
 
-	/* TODO cache maintenance */
+	if (etnaviv_obj->flags & ETNA_BO_CACHED) {
+		if (!etnaviv_obj->sgt) {
+			void * ret;
+
+			mutex_lock(&dev->struct_mutex);
+			ret = etnaviv_gem_get_pages(etnaviv_obj);
+			mutex_unlock(&dev->struct_mutex);
+			if (IS_ERR(ret))
+				return PTR_ERR(ret);
+		}
+
+		dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
+				    etnaviv_obj->sgt->nents,
+				    etnaviv_op_to_dma_dir(op));
+		etnaviv_obj->last_cpu_prep_op = op;
+	}
 
 	return ret;
 }
 
 int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
 {
-	/* TODO cache maintenance */
+	struct drm_device *dev = obj->dev;
+	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+	if (etnaviv_obj->flags & ETNA_BO_CACHED) {
+		/* fini without a prep is almost certainly a userspace error */
+		WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
+		dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
+			etnaviv_obj->sgt->nents,
+			etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
+		etnaviv_obj->last_cpu_prep_op = 0;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index 4d5455a3fe39..25f7afbc779a 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -82,6 +82,9 @@ struct etnaviv_gem_object {
 	bool is_ring_buffer;
 	u32 offset;
 
+	/* cache maintenance */
+	uint32_t last_cpu_prep_op;
+
 	struct etnaviv_gem_userptr userptr;
 };
 
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 45/48] staging: etnaviv: remove submit type
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (43 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 44/48] staging: etnaviv: implement cache maintenance on cpu_(prep|fini) Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 14:41         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user Lucas Stach
                         ` (3 subsequent siblings)
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

There is no point in having a context restore buffer, as the need for tracking
GPU hardware state in userspace and the fact that we need to submit all states
that reference memory buffers anyway to ensure proper patching of the
relocations, eat away from the potential benefit.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_gem.h        | 1 -
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 1 -
 include/uapi/drm/etnaviv_drm.h               | 8 --------
 3 files changed, 10 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index 25f7afbc779a..5112c5458306 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -121,7 +121,6 @@ struct etnaviv_gem_submit {
 	unsigned int nr_cmds;
 	unsigned int nr_bos;
 	struct {
-		u32 type;
 		u32 offset; /* in dwords */
 		u32 size;  /* in dwords */
 		struct etnaviv_gem_object *obj;
diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index a0bc61946036..73c1378e96a1 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -408,7 +408,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 			goto out;
 		}
 
-		submit->cmd[i].type = submit_cmd->type;
 		submit->cmd[i].offset = submit_cmd->submit_offset / 4;
 		submit->cmd[i].size = submit_cmd->size / 4;
 		submit->cmd[i].obj = etnaviv_obj;
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index 7cc749c30970..1515fa4f6986 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -123,15 +123,7 @@ struct drm_etnaviv_gem_submit_reloc {
 	__u64 reloc_offset;   /* in, offset from start of reloc_bo */
 };
 
-/* submit-types:
- *   BUF - this cmd buffer is executed normally.
- *   CTX_RESTORE_BUF - only executed if there has been a GPU context
- *      switch since the last SUBMIT ioctl
- */
-#define ETNA_SUBMIT_CMD_BUF             0x0001
-#define ETNA_SUBMIT_CMD_CTX_RESTORE_BUF 0x0002
 struct drm_etnaviv_gem_submit_cmd {
-	__u32 type;           /* in, one of ETNA_SUBMIT_CMD_x */
 	__u32 submit_idx;     /* in, index of submit_bo cmdstream buffer */
 	__u32 submit_offset;  /* in, offset into submit_bo */
 	__u32 size;           /* in, cmdstream size */
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (44 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 45/48] staging: etnaviv: remove submit type Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 14:41         ` Russell King - ARM Linux
  2015-10-26 20:48         ` Russell King - ARM Linux
  2015-09-25 11:57       ` [PATCH 47/48] staging: etnaviv: don't use GEM buffer for internal ring buffer Lucas Stach
                         ` (2 subsequent siblings)
  48 siblings, 2 replies; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

This rewrites the submit interface to copy the command stream from user
memory. This mitigates a potential attack vector of the old interface
where userspace could submit a command buffer that would be validated by
the kernel, but is still mapped into userspace. This could be exploited
by changing the command stream after validation but before the actual
GPU execution.

A nice side effect is that validation and reloc patching can now operate
on cached memory and only the final result is copied to a writecombined
command buffer which should make those operations a bit more efficient.

A simplification to the interface is the removal of the ability to push
multiple command buffers per submit. As we don't use it for context
restore buffers and the fact that userspace doesn't need to work with
a fixed command buffer size anymore, with the potential risk to overflow
its size in the middle of an atomic stream section, there is no need
for this complication anymore.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_buffer.c     |  48 +++++------
 drivers/staging/etnaviv/etnaviv_cmd_parser.c |   6 +-
 drivers/staging/etnaviv/etnaviv_drv.h        |   4 +-
 drivers/staging/etnaviv/etnaviv_gem.h        |   7 +-
 drivers/staging/etnaviv/etnaviv_gem_submit.c | 122 ++++++++++-----------------
 drivers/staging/etnaviv/etnaviv_gpu.c        |  38 +++++++++
 drivers/staging/etnaviv/etnaviv_gpu.h        |  20 +++++
 include/uapi/drm/etnaviv_drm.h               |  18 ++--
 8 files changed, 136 insertions(+), 127 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
index 1994eceae1ae..76c646076b05 100644
--- a/drivers/staging/etnaviv/etnaviv_buffer.c
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -111,6 +111,11 @@ static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_gem_object *obj)
 	return obj->paddr - gpu->memory_base;
 }
 
+static u32 gpu_va_raw(struct etnaviv_gpu *gpu, u32 paddr)
+{
+	return paddr - gpu->memory_base;
+}
+
 static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
 	struct etnaviv_gem_object *obj, u32 off, u32 len)
 {
@@ -153,10 +158,9 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	struct etnaviv_gem_submit *submit)
 {
 	struct etnaviv_gem_object *buffer = to_etnaviv_bo(gpu->buffer);
-	struct etnaviv_gem_object *cmd;
 	u32 *lw = buffer->vaddr + ((buffer->offset - 4) * 4);
+	u32 *usercmd = submit->cmdbuf->vaddr;
 	u32 back, link_target, link_size, reserve_size, extra_size = 0;
-	u32 i;
 
 	if (drm_debug & DRM_UT_DRIVER)
 		etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
@@ -194,35 +198,24 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	/* Skip over any extra instructions */
 	link_target += extra_size * sizeof(u32);
 
-	/* update offset for every cmd stream */
-	for (i = submit->nr_cmds; i--; ) {
-		cmd = submit->cmd[i].obj;
+	if (drm_debug & DRM_UT_DRIVER)
+		pr_info("stream link to 0x%08x @ 0x%08x %p\n",
+			link_target, gpu_va_raw(gpu, submit->cmdbuf->paddr),
+			submit->cmdbuf->vaddr);
 
-		cmd->offset = submit->cmd[i].offset + submit->cmd[i].size;
+	/* jump back from cmd to main buffer */
+	usercmd[submit->cmdbuf->user_size/4] = VIV_FE_LINK_HEADER_OP_LINK |
+				    VIV_FE_LINK_HEADER_PREFETCH(link_size);
+	usercmd[submit->cmdbuf->user_size/4 + 1] = link_target;
 
-		if (drm_debug & DRM_UT_DRIVER)
-			pr_info("stream link from buffer %u to 0x%08x @ 0x%08x %p\n",
-				i, link_target,
-				gpu_va(gpu, cmd) + cmd->offset * 4,
-				cmd->vaddr + cmd->offset * 4);
+	link_target = gpu_va_raw(gpu, submit->cmdbuf->paddr);
+	link_size = submit->cmdbuf->size / 8;
 
-		/* jump back from last cmd to main buffer */
-		CMD_LINK(cmd, link_size, link_target);
 
-		/* update the size */
-		submit->cmd[i].size = cmd->offset - submit->cmd[i].offset;
-
-		link_target = gpu_va(gpu, cmd) + submit->cmd[i].offset * 4;
-		link_size = submit->cmd[i].size * 2;
-	}
 
 	if (drm_debug & DRM_UT_DRIVER) {
-		for (i = 0; i < submit->nr_cmds; i++) {
-			struct etnaviv_gem_object *obj = submit->cmd[i].obj;
-
-			etnaviv_buffer_dump(gpu, obj, submit->cmd[i].offset,
-					submit->cmd[i].size);
-		}
+		print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
+			       submit->cmdbuf->vaddr, submit->cmdbuf->size, 0);
 
 		pr_info("link op: %p\n", lw);
 		pr_info("link addr: %p\n", lw + 1);
@@ -263,6 +256,11 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	/* Save the event and buffer position of the new event trigger */
 	gpu->event[event].fence = submit->fence;
 
+	/* take ownership of cmdbuffer*/
+	submit->cmdbuf->fence = submit->fence;
+	list_add_tail(&submit->cmdbuf->gpu_active_list, &gpu->active_cmd_list);
+	submit->cmdbuf = NULL;
+
 	/* trigger event */
 	CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
 		       VIVS_GL_EVENT_FROM_PE);
diff --git a/drivers/staging/etnaviv/etnaviv_cmd_parser.c b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
index 7ae6ddb4306e..5175d6eb3bdc 100644
--- a/drivers/staging/etnaviv/etnaviv_cmd_parser.c
+++ b/drivers/staging/etnaviv/etnaviv_cmd_parser.c
@@ -61,10 +61,10 @@ static uint8_t cmd_length[32] = {
 	[FE_OPCODE_STALL] = 2,
 };
 
-bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_object *obj, unsigned int offset, unsigned int size)
+bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, void *stream,
+			      unsigned int size)
 {
-	u32 *start = obj->vaddr + offset * 4;
+	u32 *start = stream;
 	u32 *buf = start;
 	u32 *end = buf + size;
 
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index 40629207b04f..2b4b87bdda18 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -99,6 +99,8 @@ 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,
@@ -108,7 +110,7 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
 void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	struct etnaviv_gem_submit *submit);
 bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_object *obj, unsigned int offset, unsigned int size);
+	void *stream, unsigned int size);
 
 #ifdef CONFIG_DEBUG_FS
 void etnaviv_gem_describe_objects(struct list_head *list, struct seq_file *m);
diff --git a/drivers/staging/etnaviv/etnaviv_gem.h b/drivers/staging/etnaviv/etnaviv_gem.h
index 5112c5458306..c991d12e7aed 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.h
+++ b/drivers/staging/etnaviv/etnaviv_gem.h
@@ -118,13 +118,8 @@ struct etnaviv_gem_submit {
 	struct list_head bo_list;
 	struct ww_acquire_ctx ticket;
 	u32 fence;
-	unsigned int nr_cmds;
 	unsigned int nr_bos;
-	struct {
-		u32 offset; /* in dwords */
-		u32 size;  /* in dwords */
-		struct etnaviv_gem_object *obj;
-	} cmd[MAX_CMDS];
+	struct etnaviv_cmdbuf *cmdbuf;
 	struct {
 		u32 flags;
 		struct etnaviv_gem_object *obj;
diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c b/drivers/staging/etnaviv/etnaviv_gem_submit.c
index 73c1378e96a1..f886a3c66d30 100644
--- a/drivers/staging/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c
@@ -45,7 +45,7 @@ static struct etnaviv_gem_submit *submit_create(struct drm_device *dev,
 
 		/* initially, until copy_from_user() and bo lookup succeeds: */
 		submit->nr_bos = 0;
-		submit->nr_cmds = 0;
+		submit->cmdbuf = NULL;
 
 		INIT_LIST_HEAD(&submit->bo_list);
 		ww_acquire_init(&submit->ticket, &reservation_ww_class);
@@ -212,11 +212,11 @@ static int submit_bo(struct etnaviv_gem_submit *submit, u32 idx,
 }
 
 /* process the reloc's and patch up the cmdstream as needed: */
-static int submit_reloc(struct etnaviv_gem_submit *submit, struct etnaviv_gem_object *obj,
-		u32 offset, u32 nr_relocs, u64 relocs)
+static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream,
+		u32 size, u32 nr_relocs, u64 relocs)
 {
 	u32 i, last_offset = 0;
-	u32 *ptr = obj->vaddr;
+	u32 *ptr = stream;
 	int ret;
 
 	for (i = 0; i < nr_relocs; i++) {
@@ -240,7 +240,7 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, struct etnaviv_gem_ob
 		/* offset in dwords: */
 		off = submit_reloc.submit_offset / 4;
 
-		if ((off >= (obj->base.size / 4)) ||
+		if ((off >= size ) ||
 				(off < last_offset)) {
 			DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
 			return -EINVAL;
@@ -276,6 +276,9 @@ static void submit_cleanup(struct etnaviv_gem_submit *submit, bool fail)
 		drm_gem_object_unreference(&etnaviv_obj->base);
 	}
 
+	if (submit->cmdbuf)
+		etnaviv_gpu_cmdbuf_free(submit->cmdbuf);
+
 	ww_acquire_fini(&submit->ticket);
 	kfree(submit);
 }
@@ -286,11 +289,11 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct drm_etnaviv_gem_submit *args = data;
 	struct etnaviv_file_private *ctx = file->driver_priv;
-	struct drm_etnaviv_gem_submit_cmd *cmds;
 	struct drm_etnaviv_gem_submit_bo *bos;
 	struct etnaviv_gem_submit *submit;
+	struct etnaviv_cmdbuf *cmdbuf;
 	struct etnaviv_gpu *gpu;
-	unsigned i;
+	void *stream;
 	int ret;
 
 	if (args->pipe >= ETNA_MAX_PIPES)
@@ -300,27 +303,33 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	if (!gpu)
 		return -ENXIO;
 
-	if (args->nr_cmds > MAX_CMDS)
+	if (args->stream_size % 4) {
+		DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
+			  args->stream_size);
 		return -EINVAL;
+	}
 
 	/*
 	 * Copy the command submission and bo array to kernel space in
 	 * one go, and do this outside of the dev->struct_mutex lock.
 	 */
-	cmds = drm_malloc_ab(args->nr_cmds, sizeof(*cmds));
 	bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
-	if (!cmds || !bos)
-		return -ENOMEM;
+	stream = drm_malloc_ab(1, args->stream_size);
+	cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8);
+	if (!bos || !stream || !cmdbuf) {
+		ret = -ENOMEM;
+		goto err_submit_cmds;
+	}
 
-	ret = copy_from_user(cmds, to_user_ptr(args->cmds),
-			     args->nr_cmds * sizeof(*cmds));
+	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(bos, to_user_ptr(args->bos),
-			     args->nr_bos * sizeof(*bos));
+	ret = copy_from_user(stream, to_user_ptr(args->stream),
+			     args->stream_size);
 	if (ret) {
 		ret = -EFAULT;
 		goto err_submit_cmds;
@@ -364,69 +373,21 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	if (ret)
 		goto out;
 
-	for (i = 0; i < args->nr_cmds; i++) {
-		struct drm_etnaviv_gem_submit_cmd *submit_cmd = cmds + i;
-		struct etnaviv_gem_object *etnaviv_obj;
-		unsigned max_size;
-
-		ret = submit_bo(submit, submit_cmd->submit_idx, &etnaviv_obj,
-				NULL);
-		if (ret)
-			goto out;
-
-		if (!(etnaviv_obj->flags & ETNA_BO_CMDSTREAM)) {
-			DRM_ERROR("cmdstream bo has flag ETNA_BO_CMDSTREAM not set\n");
-			ret = -EINVAL;
-			goto out;
-		}
-
-		if (submit_cmd->size % 4) {
-			DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
-					submit_cmd->size);
-			ret = -EINVAL;
-			goto out;
-		}
-
-		if (submit_cmd->submit_offset % 8) {
-			DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
-					submit_cmd->size);
-			ret = -EINVAL;
-			goto out;
-		}
-
-		/*
-		 * We must have space to add a LINK command at the end of
-		 * the command buffer.
-		 */
-		max_size = etnaviv_obj->base.size - 8;
-
-		if (submit_cmd->size > max_size ||
-		    submit_cmd->submit_offset > max_size - submit_cmd->size) {
-			DRM_ERROR("invalid cmdstream size: %u\n",
-				  submit_cmd->size);
-			ret = -EINVAL;
-			goto out;
-		}
-
-		submit->cmd[i].offset = submit_cmd->submit_offset / 4;
-		submit->cmd[i].size = submit_cmd->size / 4;
-		submit->cmd[i].obj = etnaviv_obj;
-
-		if (!etnaviv_cmd_validate_one(gpu, etnaviv_obj,
-					      submit->cmd[i].offset,
-					      submit->cmd[i].size)) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		ret = submit_reloc(submit, etnaviv_obj,
-				   submit_cmd->submit_offset,
-				   submit_cmd->nr_relocs, submit_cmd->relocs);
-		if (ret)
-			goto out;
+	if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4)) {
+		ret = -EINVAL;
+		goto out;
 	}
 
-	submit->nr_cmds = i;
+	ret = submit_reloc(submit, stream, args->stream_size / 4,
+			   args->nr_relocs, args->relocs);
+	if (ret)
+		goto out;
+
+	memcpy(cmdbuf->vaddr, stream, args->stream_size);
+	cmdbuf->user_size = ALIGN(args->stream_size, 8);
+	/* transfer ownership of cmdbuf to submit */
+	submit->cmdbuf = cmdbuf;
+	cmdbuf = NULL;
 
 	ret = etnaviv_gpu_submit(gpu, submit, ctx);
 
@@ -447,11 +408,14 @@ out:
 	if (ret == -EAGAIN)
 		flush_workqueue(priv->wq);
 
- err_submit_cmds:
+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 (cmds)
-		drm_free_large(cmds);
 
 	return ret;
 }
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index 39ac08d26260..f8b507406e41 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -857,12 +857,41 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
  * Cmdstream submission/retirement:
  */
 
+struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size)
+{
+	struct etnaviv_cmdbuf *cmdbuf;
+
+	cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
+	if (!cmdbuf)
+		return NULL;
+
+	cmdbuf->vaddr = dma_alloc_writecombine(gpu->dev, size, &cmdbuf->paddr,
+					       GFP_KERNEL);
+	if (!cmdbuf->vaddr) {
+		kfree(cmdbuf);
+		return NULL;
+	}
+
+	cmdbuf->gpu = gpu;
+	cmdbuf->size = size;
+
+	return cmdbuf;
+}
+
+void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
+{
+	dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
+			      cmdbuf->vaddr, cmdbuf->paddr);
+	kfree(cmdbuf);
+}
+
 static void retire_worker(struct work_struct *work)
 {
 	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
 					       retire_work);
 	struct drm_device *dev = gpu->drm;
 	u32 fence = gpu->completed_fence;
+	struct etnaviv_cmdbuf *cmdbuf, *tmp;
 
 	mutex_lock(&dev->struct_mutex);
 
@@ -885,6 +914,14 @@ static void retire_worker(struct work_struct *work)
 		}
 	}
 
+	list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list,
+				 gpu_active_list) {
+		if (fence_after_eq(fence, cmdbuf->fence)) {
+			etnaviv_gpu_cmdbuf_free(cmdbuf);
+			list_del(&cmdbuf->gpu_active_list);
+		}
+	}
+
 	gpu->retired_fence = fence;
 
 	mutex_unlock(&dev->struct_mutex);
@@ -1223,6 +1260,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
 	gpu->drm = drm;
 
 	INIT_LIST_HEAD(&gpu->active_list);
+	INIT_LIST_HEAD(&gpu->active_cmd_list);
 	INIT_WORK(&gpu->retire_work, retire_worker);
 	INIT_WORK(&gpu->recover_work, recover_worker);
 	init_waitqueue_head(&gpu->fence_event);
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index 374f37f3665f..ee1c8504e4c8 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -103,6 +103,9 @@ struct etnaviv_gpu {
 	/* list of GEM active objects: */
 	struct list_head active_list;
 
+	/* list of currently in-flight command buffers */
+	struct list_head active_cmd_list;
+
 	u32 idle_mask;
 
 	/* Fencing support */
@@ -133,6 +136,20 @@ struct etnaviv_gpu {
 	struct work_struct recover_work;
 };
 
+struct etnaviv_cmdbuf {
+	/* device this cmdbuf is allocated for */
+	struct etnaviv_gpu *gpu;
+	/* cmdbuf properties */
+	void *vaddr;
+	dma_addr_t paddr;
+	u32 size;
+	u32 user_size;
+	/* fence after which this buffer is to be disposed */
+	u32 fence;
+	/* per GPU in-flight list */
+	struct list_head gpu_active_list;
+};
+
 static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)
 {
 	etnaviv_writel(data, gpu->mmio + reg);
@@ -168,6 +185,9 @@ 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_file_private *ctx);
+struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
+					      u32 size);
+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);
 
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index 1515fa4f6986..689caf93c85d 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -123,15 +123,6 @@ struct drm_etnaviv_gem_submit_reloc {
 	__u64 reloc_offset;   /* in, offset from start of reloc_bo */
 };
 
-struct drm_etnaviv_gem_submit_cmd {
-	__u32 submit_idx;     /* in, index of submit_bo cmdstream buffer */
-	__u32 submit_offset;  /* in, offset into submit_bo */
-	__u32 size;           /* in, cmdstream size */
-	__u32 pad;
-	__u32 nr_relocs;      /* in, number of submit_reloc's */
-	__u64 relocs;         /* in, ptr to array of submit_reloc's */
-};
-
 /* Each buffer referenced elsewhere in the cmdstream submit (ie. the
  * cmdstream buffer(s) themselves or reloc entries) has one (and only
  * one) entry in the submit->bos[] table.
@@ -159,14 +150,15 @@ struct drm_etnaviv_gem_submit_bo {
 #define ETNA_PIPE_2D      0x01
 #define ETNA_PIPE_VG      0x02
 struct drm_etnaviv_gem_submit {
+	__u32 fence;          /* out */
 	__u32 pipe;           /* in */
 	__u32 exec_state;     /* in, initial execution state (ETNA_PIPE_x) */
-	__u32 fence;          /* out */
 	__u32 nr_bos;         /* in, number of submit_bo's */
-	__u32 nr_cmds;        /* in, number of submit_cmd's */
-	__u32 pad;
+	__u32 nr_relocs;      /* in, number of submit_reloc's */
+	__u32 stream_size;    /* in, cmdstream size */
 	__u64 bos;            /* in, ptr to array of submit_bo's */
-	__u64 cmds;           /* in, ptr to array of submit_cmd's */
+	__u64 relocs;         /* in, ptr to array of submit_reloc's */
+	__u64 stream;         /* in, ptr to cmdstream */
 };
 
 /* The normal way to synchronize with the GPU is just to CPU_PREP on
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 47/48] staging: etnaviv: don't use GEM buffer for internal ring buffer
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (45 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user Lucas Stach
@ 2015-09-25 11:57       ` Lucas Stach
  2015-10-21 14:51         ` Russell King - ARM Linux
  2015-09-25 11:58       ` [PATCH 48/48] staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI Lucas Stach
  2015-09-28  9:46       ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Christian Gmeiner
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:57 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

Instead of using a GEM buffer for the kernel internal ring buffer
use the newly introduced cmdbuf object. This removes the last remaining
user of the CMDSTREAM GEM flag.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_buffer.c | 90 ++++++++++++++------------------
 drivers/staging/etnaviv/etnaviv_drv.c    |  8 +--
 drivers/staging/etnaviv/etnaviv_gpu.c    | 13 +++--
 drivers/staging/etnaviv/etnaviv_gpu.h    |  4 +-
 4 files changed, 53 insertions(+), 62 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
index 76c646076b05..586f84316f1a 100644
--- a/drivers/staging/etnaviv/etnaviv_buffer.c
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -28,21 +28,22 @@
  */
 
 
-static inline void OUT(struct etnaviv_gem_object *buffer, u32 data)
+static inline void OUT(struct etnaviv_cmdbuf *buffer, u32 data)
 {
 	u32 *vaddr = (u32 *)buffer->vaddr;
 
-	BUG_ON(buffer->offset >= buffer->base.size / sizeof(*vaddr));
+	BUG_ON(buffer->user_size >= buffer->size);
 
-	vaddr[buffer->offset++] = data;
+	vaddr[buffer->user_size / 4] = data;
+	buffer->user_size += 4;
 }
 
-static inline void CMD_LOAD_STATE(struct etnaviv_gem_object *buffer,
+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->offset = ALIGN(buffer->offset, 2);
+	buffer->user_size = ALIGN(buffer->user_size, 8);
 
 	/* write a register via cmd stream */
 	OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE |
@@ -51,40 +52,40 @@ static inline void CMD_LOAD_STATE(struct etnaviv_gem_object *buffer,
 	OUT(buffer, value);
 }
 
-static inline void CMD_END(struct etnaviv_gem_object *buffer)
+static inline void CMD_END(struct etnaviv_cmdbuf *buffer)
 {
-	buffer->offset = ALIGN(buffer->offset, 2);
+	buffer->user_size = ALIGN(buffer->user_size, 8);
 
 	OUT(buffer, VIV_FE_END_HEADER_OP_END);
 }
 
-static inline void CMD_WAIT(struct etnaviv_gem_object *buffer)
+static inline void CMD_WAIT(struct etnaviv_cmdbuf *buffer)
 {
-	buffer->offset = ALIGN(buffer->offset, 2);
+	buffer->user_size = ALIGN(buffer->user_size, 8);
 
 	OUT(buffer, VIV_FE_WAIT_HEADER_OP_WAIT | 200);
 }
 
-static inline void CMD_LINK(struct etnaviv_gem_object *buffer,
+static inline void CMD_LINK(struct etnaviv_cmdbuf *buffer,
 	u16 prefetch, u32 address)
 {
-	buffer->offset = ALIGN(buffer->offset, 2);
+	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_gem_object *buffer,
+static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer,
 	u32 from, u32 to)
 {
-	buffer->offset = ALIGN(buffer->offset, 2);
+	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_gem_object *buffer, u8 pipe)
+static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe)
 {
 	u32 flush;
 	u32 stall;
@@ -106,24 +107,19 @@ static void etnaviv_cmd_select_pipe(struct etnaviv_gem_object *buffer, u8 pipe)
 		       VIVS_GL_PIPE_SELECT_PIPE(pipe));
 }
 
-static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_gem_object *obj)
+static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_cmdbuf *buf)
 {
-	return obj->paddr - gpu->memory_base;
-}
-
-static u32 gpu_va_raw(struct etnaviv_gpu *gpu, u32 paddr)
-{
-	return paddr - gpu->memory_base;
+	return buf->paddr - gpu->memory_base;
 }
 
 static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_object *obj, u32 off, u32 len)
+	struct etnaviv_cmdbuf *buf, u32 off, u32 len)
 {
-	u32 size = obj->base.size;
-	u32 *ptr = obj->vaddr + off;
+	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, obj) + off, size - len * 4 - off);
+			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);
@@ -131,24 +127,23 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
 
 u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
 {
-	struct etnaviv_gem_object *buffer = to_etnaviv_bo(gpu->buffer);
+	struct etnaviv_cmdbuf *buffer = gpu->buffer;
 
 	/* initialize buffer */
-	buffer->offset = 0;
-	buffer->is_ring_buffer = true;
+	buffer->user_size = 0;
 
 	CMD_WAIT(buffer);
-	CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + ((buffer->offset - 1) * 4));
+	CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + buffer->user_size - 4);
 
-	return buffer->offset / 2;
+	return buffer->user_size / 8;
 }
 
 void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
 {
-	struct etnaviv_gem_object *buffer = to_etnaviv_bo(gpu->buffer);
+	struct etnaviv_cmdbuf *buffer = gpu->buffer;
 
 	/* Replace the last WAIT with an END */
-	buffer->offset -= 4;
+	buffer->user_size -= 16;
 
 	CMD_END(buffer);
 	mb();
@@ -157,9 +152,8 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
 void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	struct etnaviv_gem_submit *submit)
 {
-	struct etnaviv_gem_object *buffer = to_etnaviv_bo(gpu->buffer);
-	u32 *lw = buffer->vaddr + ((buffer->offset - 4) * 4);
-	u32 *usercmd = submit->cmdbuf->vaddr;
+	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)
@@ -181,18 +175,17 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 			extra_size += 8;
 	}
 
-	reserve_size = 6 + extra_size;
+	reserve_size = (6 + extra_size) * 4;
 
 	/*
 	 * if we are going to completely overflow the buffer, we need to wrap.
 	 */
-	if (buffer->offset + reserve_size >
-	    buffer->base.size / sizeof(u32))
-		buffer->offset = 0;
+	if (buffer->user_size + reserve_size > buffer->size)
+		buffer->user_size = 0;
 
 	/* save offset back into main buffer */
-	back = buffer->offset + reserve_size - 6;
-	link_target = gpu_va(gpu, buffer) + buffer->offset * 4;
+	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 */
@@ -200,15 +193,13 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 
 	if (drm_debug & DRM_UT_DRIVER)
 		pr_info("stream link to 0x%08x @ 0x%08x %p\n",
-			link_target, gpu_va_raw(gpu, submit->cmdbuf->paddr),
+			link_target, gpu_va(gpu, submit->cmdbuf),
 			submit->cmdbuf->vaddr);
 
 	/* jump back from cmd to main buffer */
-	usercmd[submit->cmdbuf->user_size/4] = VIV_FE_LINK_HEADER_OP_LINK |
-				    VIV_FE_LINK_HEADER_PREFETCH(link_size);
-	usercmd[submit->cmdbuf->user_size/4 + 1] = link_target;
+	CMD_LINK(submit->cmdbuf, link_size, link_target);
 
-	link_target = gpu_va_raw(gpu, submit->cmdbuf->paddr);
+	link_target = gpu_va(gpu, submit->cmdbuf);
 	link_size = submit->cmdbuf->size / 8;
 
 
@@ -220,13 +211,12 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 		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 * 4));
+		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->offset *
-					sizeof(u32);
+		u32 new_target = gpu_va(gpu, buffer) + buffer->user_size;
 
 		if (gpu->mmu->need_flush) {
 			/* Add the MMU flush */
@@ -267,7 +257,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 
 	/* append WAIT/LINK to main buffer */
 	CMD_WAIT(buffer);
-	CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + ((buffer->offset - 1) * 4));
+	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;
diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c
index d55d2c9f4d0f..30f6e5d0c91d 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.c
+++ b/drivers/staging/etnaviv/etnaviv_drv.c
@@ -237,13 +237,13 @@ static int etnaviv_mmu_show(struct drm_device *dev, struct seq_file *m)
 
 static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
 {
-	struct etnaviv_gem_object *obj = to_etnaviv_bo(gpu->buffer);
-	u32 size = obj->base.size;
-	u32 *ptr = obj->vaddr;
+	struct etnaviv_cmdbuf *buf = gpu->buffer;
+	u32 size = buf->size;
+	u32 *ptr = buf->vaddr;
 	u32 i;
 
 	seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
-			obj->vaddr, (u64)obj->paddr, size - (obj->offset * 4));
+			buf->vaddr, (u64)buf->paddr, size - buf->user_size);
 
 	for (i = 0; i < size / 4; i++) {
 		if (i && !(i % 4))
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index f8b507406e41..e12fe3508db2 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -430,7 +430,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 
 	gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
 	gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS,
-		  etnaviv_gem_paddr_locked(gpu->buffer) - gpu->memory_base);
+		  gpu->buffer->paddr - gpu->memory_base);
 	gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
 		  VIVS_FE_COMMAND_CONTROL_ENABLE |
 		  VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
@@ -488,11 +488,10 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
 	}
 
 	/* Create buffer: */
-	gpu->buffer = etnaviv_gem_new(gpu->drm, PAGE_SIZE, ETNA_BO_CMDSTREAM);
-	if (IS_ERR(gpu->buffer)) {
-		ret = PTR_ERR(gpu->buffer);
-		gpu->buffer = NULL;
-		dev_err(gpu->dev, "could not create buffer: %d\n", ret);
+	gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE);
+	if (!gpu->buffer) {
+		ret = -ENOMEM;
+		dev_err(gpu->dev, "could not create command buffer\n");
 		goto fail;
 	}
 
@@ -1295,7 +1294,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
 #endif
 
 	if (gpu->buffer) {
-		drm_gem_object_unreference_unlocked(gpu->buffer);
+		etnaviv_gpu_cmdbuf_free(gpu->buffer);
 		gpu->buffer = NULL;
 	}
 
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h
index ee1c8504e4c8..3be5b481d8d1 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.h
+++ b/drivers/staging/etnaviv/etnaviv_gpu.h
@@ -82,6 +82,8 @@ struct etnaviv_event {
 	u32 fence;
 };
 
+struct etnaviv_cmdbuf;
+
 struct etnaviv_gpu {
 	struct drm_device *drm;
 	struct device *dev;
@@ -90,7 +92,7 @@ struct etnaviv_gpu {
 	bool switch_context;
 
 	/* 'ring'-buffer: */
-	struct drm_gem_object *buffer;
+	struct etnaviv_cmdbuf *buffer;
 
 	/* bus base address of memory  */
 	u32 memory_base;
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH 48/48] staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (46 preceding siblings ...)
  2015-09-25 11:57       ` [PATCH 47/48] staging: etnaviv: don't use GEM buffer for internal ring buffer Lucas Stach
@ 2015-09-25 11:58       ` Lucas Stach
  2015-10-21 15:29         ` Russell King - ARM Linux
  2015-09-28  9:46       ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Christian Gmeiner
  48 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-25 11:58 UTC (permalink / raw)
  To: Russell King, Christian Gmeiner; +Cc: dri-devel

Neither userspace nor the kernel internal functions use the CMDSTREAM
GEM type anymore. Remove it from the public API and clean up all related
functions.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 127 +++++++---------------------------
 include/uapi/drm/etnaviv_drm.h        |   1 -
 2 files changed, 26 insertions(+), 102 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index c9300f1e03d5..1381c952c52f 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -31,19 +31,8 @@ static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
 	 * For non-cached buffers, ensure the new pages are clean
 	 * because display controller, GPU, etc. are not coherent.
 	 */
-	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK) {
+	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
 		dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
-	} else {
-		struct scatterlist *sg;
-		unsigned int i;
-
-		for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-			sg_dma_address(sg) = sg_phys(sg);
-#ifdef CONFIG_NEED_SG_DMA_LENGTH
-			sg_dma_len(sg) = sg->length;
-#endif
-		}
-	}
 }
 
 static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)
@@ -66,9 +55,8 @@ static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj
 	 * written into the remainder of the region, this can
 	 * discard those writes.
 	 */
-	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK) {
+	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
 		dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
-	}
 }
 
 /* called with dev->struct_mutex held */
@@ -138,27 +126,6 @@ void etnaviv_gem_put_pages(struct etnaviv_gem_object *etnaviv_obj)
 	/* when we start tracking the pin count, then do something here */
 }
 
-static int etnaviv_gem_mmap_cmd(struct drm_gem_object *obj,
-	struct vm_area_struct *vma)
-{
-	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-	int ret;
-
-	/*
-	 * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
-	 * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
-	 * the whole buffer.
-	 */
-	vma->vm_flags &= ~VM_PFNMAP;
-	vma->vm_pgoff = 0;
-
-	ret = dma_mmap_coherent(obj->dev->dev, vma,
-				etnaviv_obj->vaddr, etnaviv_obj->paddr,
-				vma->vm_end - vma->vm_start);
-
-	return ret;
-}
-
 static int etnaviv_gem_mmap_obj(struct drm_gem_object *obj,
 		struct vm_area_struct *vma)
 {
@@ -203,12 +170,7 @@ int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 	}
 
 	obj = to_etnaviv_bo(vma->vm_private_data);
-	if (obj->flags & ETNA_BO_CMDSTREAM)
-		ret = etnaviv_gem_mmap_cmd(vma->vm_private_data, vma);
-	else
-		ret = etnaviv_gem_mmap_obj(vma->vm_private_data, vma);
-
-	return ret;
+	return etnaviv_gem_mmap_obj(vma->vm_private_data, vma);
 }
 
 int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -296,11 +258,6 @@ int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu,
 	struct etnaviv_vram_mapping *mapping;
 	int ret = 0;
 
-	if (etnaviv_obj->flags & ETNA_BO_CMDSTREAM) {
-		*iova = etnaviv_obj->paddr;
-		return 0;
-	}
-
 	mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
 	if (!mapping) {
 		struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
@@ -535,16 +492,6 @@ void etnaviv_gem_describe_objects(struct list_head *list, struct seq_file *m)
 }
 #endif
 
-static void etnaviv_gem_cmd_release(struct etnaviv_gem_object *etnaviv_obj)
-{
-	dma_free_coherent(etnaviv_obj->base.dev->dev, etnaviv_obj->base.size,
-		etnaviv_obj->vaddr, etnaviv_obj->paddr);
-}
-
-static const struct etnaviv_gem_ops etnaviv_gem_cmd_ops = {
-	.release = etnaviv_gem_cmd_release,
-};
-
 static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)
 {
 	if (etnaviv_obj->vaddr)
@@ -607,24 +554,18 @@ static int etnaviv_gem_new_impl(struct drm_device *dev,
 	bool valid = true;
 
 	/* validate flags */
-	if (flags & ETNA_BO_CMDSTREAM) {
-		if ((flags & ETNA_BO_CACHE_MASK) != 0)
-			valid = false;
-	} else {
-		switch (flags & ETNA_BO_CACHE_MASK) {
-		case ETNA_BO_UNCACHED:
-		case ETNA_BO_CACHED:
-		case ETNA_BO_WC:
-			break;
-		default:
-			valid = false;
-		}
+	switch (flags & ETNA_BO_CACHE_MASK) {
+	case ETNA_BO_UNCACHED:
+	case ETNA_BO_CACHED:
+	case ETNA_BO_WC:
+		break;
+	default:
+		valid = false;
 	}
 
 	if (!valid) {
-		dev_err(dev->dev, "invalid cache flag: %x (cmd: %d)\n",
-				(flags & ETNA_BO_CACHE_MASK),
-				(flags & ETNA_BO_CMDSTREAM));
+		dev_err(dev->dev, "invalid cache flag: %x\n",
+			(flags & ETNA_BO_CACHE_MASK));
 		return -EINVAL;
 	}
 
@@ -632,16 +573,6 @@ static int etnaviv_gem_new_impl(struct drm_device *dev,
 	if (!etnaviv_obj)
 		return -ENOMEM;
 
-	if (flags & ETNA_BO_CMDSTREAM) {
-		etnaviv_obj->vaddr = dma_alloc_coherent(dev->dev, size,
-				&etnaviv_obj->paddr, GFP_KERNEL);
-
-		if (!etnaviv_obj->vaddr) {
-			kfree(etnaviv_obj);
-			return -ENOMEM;
-		}
-	}
-
 	etnaviv_obj->flags = flags;
 
 	etnaviv_obj->resv = &etnaviv_obj->_resv;
@@ -668,26 +599,20 @@ static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
 	if (ret)
 		goto fail;
 
-	ret = 0;
-	if (flags & ETNA_BO_CMDSTREAM) {
-		to_etnaviv_bo(obj)->ops = &etnaviv_gem_cmd_ops;
-		drm_gem_private_object_init(dev, obj, size);
-	} else {
-		to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops;
-		ret = drm_gem_object_init(dev, obj, size);
-		if (ret == 0) {
-			struct address_space *mapping;
-
-			/*
-			 * Our buffers are kept pinned, so allocating them
-			 * from the MOVABLE zone is a really bad idea, and
-			 * conflicts with CMA.  See coments above new_inode()
-			 * why this is required _and_ expected if you're
-			 * going to pin these pages.
-			 */
-			mapping = file_inode(obj->filp)->i_mapping;
-			mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
-		}
+	to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops;
+	ret = drm_gem_object_init(dev, obj, size);
+	if (ret == 0) {
+		struct address_space *mapping;
+
+		/*
+		 * Our buffers are kept pinned, so allocating them
+		 * from the MOVABLE zone is a really bad idea, and
+		 * conflicts with CMA.  See coments above new_inode()
+		 * why this is required _and_ expected if you're
+		 * going to pin these pages.
+		 */
+		mapping = file_inode(obj->filp)->i_mapping;
+		mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
 	}
 
 	if (ret)
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index 689caf93c85d..5f1206b3f9ba 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -72,7 +72,6 @@ struct drm_etnaviv_param {
  * GEM buffers:
  */
 
-#define ETNA_BO_CMDSTREAM    0x00000001
 #define ETNA_BO_CACHE_MASK   0x000f0000
 /* cache modes */
 #define ETNA_BO_CACHED       0x00010000
-- 
2.5.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH 03/48] staging: etnaviv: remove compat MMU code
  2015-09-25 11:57       ` [PATCH 03/48] staging: etnaviv: remove compat MMU code Lucas Stach
@ 2015-09-25 12:18         ` Russell King - ARM Linux
  2015-10-21 11:35           ` Russell King - ARM Linux
  0 siblings, 1 reply; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-09-25 12:18 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:15PM +0200, Lucas Stach wrote:
> There is no point in keeping backwards compatibility to older
> kernel versions in a driver destined to mainline.

You are correct, however the repository I keep is always based on the
previous non-rc kernel release, and I want it to work not only with
that release, but also the future -rc's as well.  It means that from
time to time, I will include compatibility across a merge window, but
I do intend to drop it.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 12/48] staging: etnaviv: avoid lockdep circular dependency warning
  2015-09-25 11:57       ` [PATCH 12/48] staging: etnaviv: avoid lockdep circular dependency warning Lucas Stach
@ 2015-09-25 12:20         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-09-25 12:20 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:24PM +0200, Lucas Stach wrote:
> +	/* We must never runtime-PM resume holding struct_mutex */
> +	if (drm && WARN_ON_ONCE(mutex_is_locked(&drm->struct_mutex)))
> +		return -EDEADLK;

This actually needs dropping from the patch - and we'll rely on lockdep
to validate this.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
                         ` (47 preceding siblings ...)
  2015-09-25 11:58       ` [PATCH 48/48] staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI Lucas Stach
@ 2015-09-28  9:46       ` Christian Gmeiner
  2015-09-28 10:39         ` Lucas Stach
  48 siblings, 1 reply; 100+ messages in thread
From: Christian Gmeiner @ 2015-09-28  9:46 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, DRI mailing list

Hi Lucas.

I think I have run into a cache flush / cache coherency issue. I will
try to reproduce this issue with a small example and will
keep you updated.

Greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner


2015-09-25 13:57 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> Hi Russell, Christian and whoever might be interested,
>
> This series contains the individual changes between RFCv1 and RFCv2
> of the etnaviv driver. This should make it easier to review the patches
> for people already familiar with the first round of etnaviv patches.
>
> Note that I opted to sort the patches a bit different than how they are
> laid out in the etnaviv-for-upstream git branch to make logical
> connections between patches a bit more clear and to not repeat patches
> with only trivial changes from RFCv1 in this series.
>
> Regards,
> Lucas
>
> Christian Gmeiner (5):
>   staging: etnaviv: quiten down kernel log output
>   staging: etnaviv: fix 'ret' may be used uninitialized in this function
>   staging: etnaviv: fix error: 'etnaviv_gpu_hw_resume' defined but not
>     used
>   staging: etnaviv: debugfs: add possibility to dump kernel buffer
>   staging: etnaviv: change etnaviv_buffer_init() to return prefetch
>
> Lucas Stach (10):
>   staging: etnaviv: remove compat MMU code
>   staging: etnaviv: rename last remaining bits from msm to etnaviv
>   staging: etnaviv: add proper license header to all files
>   staging: etnaviv: implement simple hang recovery
>   staging: etnaviv: map all buffers to the GPU
>   staging: etnaviv: implement cache maintenance on cpu_(prep|fini)
>   staging: etnaviv: remove submit type
>   staging: etnaviv: rewrite submit interface to use copy from user
>   staging: etnaviv: don't use GEM buffer for internal ring buffer
>   staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI
>
> Russell King (33):
>   staging: etnaviv: avoid holding struct_mutex over dma_alloc_coherent()
>   staging: etnaviv: restructure iommu handling
>   staging: etnaviv: clean up public API (part 2)
>   staging: etnaviv: rename last remaining msm_* symbols
>   staging: etnaviv: add Dove GPU subsystem compatible
>   staging: etnaviv: fix missing error cleanups in etnaviv_load()
>   staging: etnaviv: fix off-by-one for iommu aperture end
>   staging: etnaviv: avoid lockdep circular dependency warning
>   staging: etnaviv: fix gpu debugfs show implementation
>   staging: etnaviv: use vm_insert_page() rather than vm_insert_mixed()
>   staging: etnaviv: etnaviv_gem_fault: reduce struct_mutex exposure
>   staging: etnaviv: give etnaviv_gem_mmap_offset() a sane behaviour
>   staging: etnaviv: allow etnaviv_ioctl_gem_info() locking to be
>     interruptible
>   staging: etnaviv: make context a per-GPU thing
>   staging: etnaviv: switch to per-GPU fence completion implementation
>   staging: etnaviv: provide etnaviv_queue_work()
>   staging: etnaviv: use standard kernel types rather than stdint.h types
>   staging: etnaviv: no need to initialise a list_head
>   staging: etnaviv: fix oops caused by scanning for free blocks
>   staging: etnaviv: clean up etnaviv_iommu_unmap_gem() signature
>   staging: etnaviv: increase page table size to maximum
>   staging: etnaviv: fix BUG_ON when removing module
>   staging: etnaviv: provide a helper to load the GPU clock field
>   staging: etnaviv: rename GPU clock functions
>   staging: etnaviv: fix runtime resume
>   staging: etnaviv: drop event ring buffer tracking
>   staging: etnaviv: improve efficiency of command parser
>   staging: etnaviv: no point looking up the mapping for cmdstream bos
>   staging: etnaviv: copy submit command and bos in one go
>   staging: etnaviv: remove cmd buffer offset validation in
>     submit_reloc()
>   staging: etnaviv: move mapping teardown into etnaviv_gem_free_object()
>   staging: etnaviv: add support for GEM_WAIT ioctl
>   staging: etnaviv: avoid pinning pages in CMA
>
>  drivers/staging/etnaviv/etnaviv_buffer.c     | 123 ++++----
>  drivers/staging/etnaviv/etnaviv_cmd_parser.c |  56 ++--
>  drivers/staging/etnaviv/etnaviv_drv.c        | 217 ++++++++-------
>  drivers/staging/etnaviv/etnaviv_drv.h        |  54 ++--
>  drivers/staging/etnaviv/etnaviv_gem.c        | 370 ++++++++++++------------
>  drivers/staging/etnaviv/etnaviv_gem.h        |  40 +--
>  drivers/staging/etnaviv/etnaviv_gem_prime.c  |  10 +-
>  drivers/staging/etnaviv/etnaviv_gem_submit.c | 219 +++++++--------
>  drivers/staging/etnaviv/etnaviv_gpu.c        | 403 ++++++++++++++++++++-------
>  drivers/staging/etnaviv/etnaviv_gpu.h        | 107 ++++---
>  drivers/staging/etnaviv/etnaviv_iommu.c      | 113 ++++----
>  drivers/staging/etnaviv/etnaviv_iommu.h      |   2 +
>  drivers/staging/etnaviv/etnaviv_mmu.c        |  75 ++---
>  drivers/staging/etnaviv/etnaviv_mmu.h        |  15 +-
>  include/uapi/drm/etnaviv_drm.h               | 100 +++----
>  15 files changed, 1086 insertions(+), 818 deletions(-)
>
> --
> 2.5.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-09-28  9:46       ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Christian Gmeiner
@ 2015-09-28 10:39         ` Lucas Stach
  2015-09-30  7:53           ` Christian Gmeiner
  0 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-09-28 10:39 UTC (permalink / raw)
  To: Christian Gmeiner; +Cc: Russell King, DRI mailing list

Hi Christian,

Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
> Hi Lucas.
> 
> I think I have run into a cache flush / cache coherency issue. I will
> try to reproduce this issue with a small example and will
> keep you updated.

What are the symptoms of the issue you are hitting? Maybe I can
reproduce or see if I have an idea right away.

Regards,
Lucas
-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-09-28 10:39         ` Lucas Stach
@ 2015-09-30  7:53           ` Christian Gmeiner
  2015-10-01  8:50             ` Lucas Stach
  2015-10-13  8:25             ` Lucas Stach
  0 siblings, 2 replies; 100+ messages in thread
From: Christian Gmeiner @ 2015-09-30  7:53 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, DRI mailing list

Hi Lucas,

2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> Hi Christian,
>
> Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
>> Hi Lucas.
>>
>> I think I have run into a cache flush / cache coherency issue. I will
>> try to reproduce this issue with a small example and will
>> keep you updated.
>
> What are the symptoms of the issue you are hitting? Maybe I can
> reproduce or see if I have an idea right away.
>

With the help of the etnaviv_2d_test in my libdrm repo on github I was able
to test different bo flags.

ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
The rendering result looks as expected. If I try ETNA_BO_WC the rendering
result looks different for every run.

debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
Version: 1.0.0
  Name: etnaviv
  Date: 20150910
  Description: etnaviv DRM
bo cpu prep: 0
debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
052880d433e1bf495e268206addd4087  /tmp/etna.bmp
debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
Version: 1.0.0
  Name: etnaviv
  Date: 20150910
  Description: etnaviv DRM
bo cpu prep: 0
debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
Version: 1.0.0
  Name: etnaviv
  Date: 20150910
  Description: etnaviv DRM
bo cpu prep: 0
debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp

etna_cmd_stream_finish() waits until the submitted command stream was
processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
help.

I am doing something wrong? Should this work in theory?

diff --git a/tests/etnaviv/etnaviv_2d_test.c b/tests/etnaviv/etnaviv_2d_test.c
index e1ee8a8..037da5b 100644
--- a/tests/etnaviv/etnaviv_2d_test.c
+++ b/tests/etnaviv/etnaviv_2d_test.c
@@ -200,7 +200,7 @@ int main(int argc, char *argv[])
                goto fail;
        }

-       bmp = etna_bo_new(dev, bmp_size, ETNA_BO_UNCACHED);
+       bmp = etna_bo_new(dev, bmp_size, ETNA_BO_WC);
        if (!bmp) {
                ret = 5;
                goto fail;
@@ -218,8 +218,10 @@ int main(int argc, char *argv[])

        etna_cmd_stream_finish(stream);

+       int state = etna_bo_cpu_prep(bmp, DRM_ETNA_PREP_READ);
+       printf("bo cpu prep: %d\n", state);
        bmp_dump32(etna_bo_map(bmp), width, height, false, "/tmp/etna.bmp");
-
+       etna_bo_cpu_fini(bmp);
 fail:
        if (stream)
                etna_cmd_stream_del(stream);

Greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-09-30  7:53           ` Christian Gmeiner
@ 2015-10-01  8:50             ` Lucas Stach
  2015-10-13  8:25             ` Lucas Stach
  1 sibling, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-10-01  8:50 UTC (permalink / raw)
  To: Christian Gmeiner; +Cc: Russell King, DRI mailing list

Am Mittwoch, den 30.09.2015, 09:53 +0200 schrieb Christian Gmeiner:
> Hi Lucas,
> 
> 2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> > Hi Christian,
> >
> > Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
> >> Hi Lucas.
> >>
> >> I think I have run into a cache flush / cache coherency issue. I will
> >> try to reproduce this issue with a small example and will
> >> keep you updated.
> >
> > What are the symptoms of the issue you are hitting? Maybe I can
> > reproduce or see if I have an idea right away.
> >
> 
> With the help of the etnaviv_2d_test in my libdrm repo on github I was able
> to test different bo flags.
> 
> ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
> The rendering result looks as expected. If I try ETNA_BO_WC the rendering
> result looks different for every run.
> 
I have an idea what's going wrong here. Will keep you updated.

Regards,
Lucas

> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> Version: 1.0.0
>   Name: etnaviv
>   Date: 20150910
>   Description: etnaviv DRM
> bo cpu prep: 0
> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> 052880d433e1bf495e268206addd4087  /tmp/etna.bmp
> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> Version: 1.0.0
>   Name: etnaviv
>   Date: 20150910
>   Description: etnaviv DRM
> bo cpu prep: 0
> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> Version: 1.0.0
>   Name: etnaviv
>   Date: 20150910
>   Description: etnaviv DRM
> bo cpu prep: 0
> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp
> 
> etna_cmd_stream_finish() waits until the submitted command stream was
> processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
> help.
> 
> I am doing something wrong? Should this work in theory?
> 
> diff --git a/tests/etnaviv/etnaviv_2d_test.c b/tests/etnaviv/etnaviv_2d_test.c
> index e1ee8a8..037da5b 100644
> --- a/tests/etnaviv/etnaviv_2d_test.c
> +++ b/tests/etnaviv/etnaviv_2d_test.c
> @@ -200,7 +200,7 @@ int main(int argc, char *argv[])
>                 goto fail;
>         }
> 
> -       bmp = etna_bo_new(dev, bmp_size, ETNA_BO_UNCACHED);
> +       bmp = etna_bo_new(dev, bmp_size, ETNA_BO_WC);
>         if (!bmp) {
>                 ret = 5;
>                 goto fail;
> @@ -218,8 +218,10 @@ int main(int argc, char *argv[])
> 
>         etna_cmd_stream_finish(stream);
> 
> +       int state = etna_bo_cpu_prep(bmp, DRM_ETNA_PREP_READ);
> +       printf("bo cpu prep: %d\n", state);
>         bmp_dump32(etna_bo_map(bmp), width, height, false, "/tmp/etna.bmp");
> -
> +       etna_bo_cpu_fini(bmp);
>  fail:
>         if (stream)
>                 etna_cmd_stream_del(stream);
> 
> Greets
> --
> Christian Gmeiner, MSc
> 
> https://soundcloud.com/christian-gmeiner

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-09-30  7:53           ` Christian Gmeiner
  2015-10-01  8:50             ` Lucas Stach
@ 2015-10-13  8:25             ` Lucas Stach
  2015-10-20  7:20               ` Christian Gmeiner
  1 sibling, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-10-13  8:25 UTC (permalink / raw)
  To: Christian Gmeiner; +Cc: Russell King, DRI mailing list

Am Mittwoch, den 30.09.2015, 09:53 +0200 schrieb Christian Gmeiner:
> Hi Lucas,
> 
> 2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> > Hi Christian,
> >
> > Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
> >> Hi Lucas.
> >>
> >> I think I have run into a cache flush / cache coherency issue. I will
> >> try to reproduce this issue with a small example and will
> >> keep you updated.
> >
> > What are the symptoms of the issue you are hitting? Maybe I can
> > reproduce or see if I have an idea right away.
> >
> 
> With the help of the etnaviv_2d_test in my libdrm repo on github I was able
> to test different bo flags.
> 
> ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
> The rendering result looks as expected. If I try ETNA_BO_WC the rendering
> result looks different for every run.
> 
> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> Version: 1.0.0
>   Name: etnaviv
>   Date: 20150910
>   Description: etnaviv DRM
> bo cpu prep: 0
> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> 052880d433e1bf495e268206addd4087  /tmp/etna.bmp
> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> Version: 1.0.0
>   Name: etnaviv
>   Date: 20150910
>   Description: etnaviv DRM
> bo cpu prep: 0
> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> Version: 1.0.0
>   Name: etnaviv
>   Date: 20150910
>   Description: etnaviv DRM
> bo cpu prep: 0
> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp
> 
> etna_cmd_stream_finish() waits until the submitted command stream was
> processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
> help.
> 
> I am doing something wrong? Should this work in theory?
> 
For the record: this is caused by the "shared attribute override enable"
bit in the AUX_CTRL register of the PL310 cache controller not being
set, which makes it non-compliant with the ARMv7 ARM specified behavior
of conflicting memory aliases.
The etnaviv kernel driver makes sure to clean the cachable alias before
handing out the pages, but without this bit set the L2 controller will
turn the userspace bufferable reads into "cachable, no allocate" which
will lead to userspace hitting stale, non-evicted cache lines.

This can be worked around by adding a "arm,shared-override" property to
the L2 cache DT node. This will only work if the kernel is booted in
secure state and will fault on a NS kernel. So this should be considered
a hack and the bootloader/firmware should make sure to set this bit.

Regards,
Lucas

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-10-13  8:25             ` Lucas Stach
@ 2015-10-20  7:20               ` Christian Gmeiner
  2015-10-20  9:00                 ` Lucas Stach
  0 siblings, 1 reply; 100+ messages in thread
From: Christian Gmeiner @ 2015-10-20  7:20 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, DRI mailing list

Hi Lucas,

2015-10-13 10:25 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> Am Mittwoch, den 30.09.2015, 09:53 +0200 schrieb Christian Gmeiner:
>> Hi Lucas,
>>
>> 2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
>> > Hi Christian,
>> >
>> > Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
>> >> Hi Lucas.
>> >>
>> >> I think I have run into a cache flush / cache coherency issue. I will
>> >> try to reproduce this issue with a small example and will
>> >> keep you updated.
>> >
>> > What are the symptoms of the issue you are hitting? Maybe I can
>> > reproduce or see if I have an idea right away.
>> >
>>
>> With the help of the etnaviv_2d_test in my libdrm repo on github I was able
>> to test different bo flags.
>>
>> ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
>> The rendering result looks as expected. If I try ETNA_BO_WC the rendering
>> result looks different for every run.
>>
>> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> Version: 1.0.0
>>   Name: etnaviv
>>   Date: 20150910
>>   Description: etnaviv DRM
>> bo cpu prep: 0
>> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> 052880d433e1bf495e268206addd4087  /tmp/etna.bmp
>> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> Version: 1.0.0
>>   Name: etnaviv
>>   Date: 20150910
>>   Description: etnaviv DRM
>> bo cpu prep: 0
>> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
>> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> Version: 1.0.0
>>   Name: etnaviv
>>   Date: 20150910
>>   Description: etnaviv DRM
>> bo cpu prep: 0
>> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp
>>
>> etna_cmd_stream_finish() waits until the submitted command stream was
>> processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
>> help.
>>
>> I am doing something wrong? Should this work in theory?
>>
> For the record: this is caused by the "shared attribute override enable"
> bit in the AUX_CTRL register of the PL310 cache controller not being
> set, which makes it non-compliant with the ARMv7 ARM specified behavior
> of conflicting memory aliases.
> The etnaviv kernel driver makes sure to clean the cachable alias before
> handing out the pages, but without this bit set the L2 controller will
> turn the userspace bufferable reads into "cachable, no allocate" which
> will lead to userspace hitting stale, non-evicted cache lines.
>
> This can be worked around by adding a "arm,shared-override" property to
> the L2 cache DT node. This will only work if the kernel is booted in
> secure state and will fault on a NS kernel. So this should be considered
> a hack and the bootloader/firmware should make sure to set this bit.
>

Is the kernel able to detect this faulty environment? It would be great
if we can warn the user about this issue and 'convert' all ETNA_BO_WC
request to ETNA_BO_CACHED or ETNA_BO_UNCACHED.

Else there might be some bug reports in the future where something is
broken due to a bad environment and these kind of bugs are hard to
sort out.

greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-10-20  7:20               ` Christian Gmeiner
@ 2015-10-20  9:00                 ` Lucas Stach
  2015-10-20  9:09                   ` Jon Nettleton
  2015-10-20  9:39                   ` Christian Gmeiner
  0 siblings, 2 replies; 100+ messages in thread
From: Lucas Stach @ 2015-10-20  9:00 UTC (permalink / raw)
  To: Christian Gmeiner; +Cc: Russell King, DRI mailing list

Am Dienstag, den 20.10.2015, 09:20 +0200 schrieb Christian Gmeiner:
> Hi Lucas,
> 
> 2015-10-13 10:25 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> > Am Mittwoch, den 30.09.2015, 09:53 +0200 schrieb Christian Gmeiner:
> >> Hi Lucas,
> >>
> >> 2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> >> > Hi Christian,
> >> >
> >> > Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
> >> >> Hi Lucas.
> >> >>
> >> >> I think I have run into a cache flush / cache coherency issue. I will
> >> >> try to reproduce this issue with a small example and will
> >> >> keep you updated.
> >> >
> >> > What are the symptoms of the issue you are hitting? Maybe I can
> >> > reproduce or see if I have an idea right away.
> >> >
> >>
> >> With the help of the etnaviv_2d_test in my libdrm repo on github I was able
> >> to test different bo flags.
> >>
> >> ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
> >> The rendering result looks as expected. If I try ETNA_BO_WC the rendering
> >> result looks different for every run.
> >>
> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> >> Version: 1.0.0
> >>   Name: etnaviv
> >>   Date: 20150910
> >>   Description: etnaviv DRM
> >> bo cpu prep: 0
> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> >> 052880d433e1bf495e268206addd4087  /tmp/etna.bmp
> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> >> Version: 1.0.0
> >>   Name: etnaviv
> >>   Date: 20150910
> >>   Description: etnaviv DRM
> >> bo cpu prep: 0
> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> >> f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
> >> Version: 1.0.0
> >>   Name: etnaviv
> >>   Date: 20150910
> >>   Description: etnaviv DRM
> >> bo cpu prep: 0
> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
> >> de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp
> >>
> >> etna_cmd_stream_finish() waits until the submitted command stream was
> >> processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
> >> help.
> >>
> >> I am doing something wrong? Should this work in theory?
> >>
> > For the record: this is caused by the "shared attribute override enable"
> > bit in the AUX_CTRL register of the PL310 cache controller not being
> > set, which makes it non-compliant with the ARMv7 ARM specified behavior
> > of conflicting memory aliases.
> > The etnaviv kernel driver makes sure to clean the cachable alias before
> > handing out the pages, but without this bit set the L2 controller will
> > turn the userspace bufferable reads into "cachable, no allocate" which
> > will lead to userspace hitting stale, non-evicted cache lines.
> >
> > This can be worked around by adding a "arm,shared-override" property to
> > the L2 cache DT node. This will only work if the kernel is booted in
> > secure state and will fault on a NS kernel. So this should be considered
> > a hack and the bootloader/firmware should make sure to set this bit.
> >
> 
> Is the kernel able to detect this faulty environment? It would be great
> if we can warn the user about this issue and 'convert' all ETNA_BO_WC
> request to ETNA_BO_CACHED or ETNA_BO_UNCACHED.
> 
> Else there might be some bug reports in the future where something is
> broken due to a bad environment and these kind of bugs are hard to
> sort out.
> 
I don't think we should work around a platform issue in individual
drivers. I mean etnaviv makes the issue really visible, but not having
this bit set in the PL310 controller makes the whole platform
non-conforming to what is specified in the ARMv7 ARM, so the platform
may exhibit all kinds of subtle breakages anyway.

We may check for this bit in the PL310 initialization and warn the user
that a firmware update might be needed to fix this. This should be
enough to sort out bug reports caused by this specific issue.

Regards,
Lucas
-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-10-20  9:00                 ` Lucas Stach
@ 2015-10-20  9:09                   ` Jon Nettleton
  2015-10-20  9:40                     ` Christian Gmeiner
  2015-10-20 10:42                     ` Fabio Estevam
  2015-10-20  9:39                   ` Christian Gmeiner
  1 sibling, 2 replies; 100+ messages in thread
From: Jon Nettleton @ 2015-10-20  9:09 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, DRI mailing list

On Tue, Oct 20, 2015 at 11:00 AM, Lucas Stach <l.stach@pengutronix.de> wrote:
> Am Dienstag, den 20.10.2015, 09:20 +0200 schrieb Christian Gmeiner:
>> Hi Lucas,
>>
>> 2015-10-13 10:25 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
>> > Am Mittwoch, den 30.09.2015, 09:53 +0200 schrieb Christian Gmeiner:
>> >> Hi Lucas,
>> >>
>> >> 2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
>> >> > Hi Christian,
>> >> >
>> >> > Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
>> >> >> Hi Lucas.
>> >> >>
>> >> >> I think I have run into a cache flush / cache coherency issue. I will
>> >> >> try to reproduce this issue with a small example and will
>> >> >> keep you updated.
>> >> >
>> >> > What are the symptoms of the issue you are hitting? Maybe I can
>> >> > reproduce or see if I have an idea right away.
>> >> >
>> >>
>> >> With the help of the etnaviv_2d_test in my libdrm repo on github I was able
>> >> to test different bo flags.
>> >>
>> >> ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
>> >> The rendering result looks as expected. If I try ETNA_BO_WC the rendering
>> >> result looks different for every run.
>> >>
>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> >> Version: 1.0.0
>> >>   Name: etnaviv
>> >>   Date: 20150910
>> >>   Description: etnaviv DRM
>> >> bo cpu prep: 0
>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> >> 052880d433e1bf495e268206addd4087  /tmp/etna.bmp
>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> >> Version: 1.0.0
>> >>   Name: etnaviv
>> >>   Date: 20150910
>> >>   Description: etnaviv DRM
>> >> bo cpu prep: 0
>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> >> f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> >> Version: 1.0.0
>> >>   Name: etnaviv
>> >>   Date: 20150910
>> >>   Description: etnaviv DRM
>> >> bo cpu prep: 0
>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> >> de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp
>> >>
>> >> etna_cmd_stream_finish() waits until the submitted command stream was
>> >> processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
>> >> help.
>> >>
>> >> I am doing something wrong? Should this work in theory?
>> >>
>> > For the record: this is caused by the "shared attribute override enable"
>> > bit in the AUX_CTRL register of the PL310 cache controller not being
>> > set, which makes it non-compliant with the ARMv7 ARM specified behavior
>> > of conflicting memory aliases.
>> > The etnaviv kernel driver makes sure to clean the cachable alias before
>> > handing out the pages, but without this bit set the L2 controller will
>> > turn the userspace bufferable reads into "cachable, no allocate" which
>> > will lead to userspace hitting stale, non-evicted cache lines.
>> >
>> > This can be worked around by adding a "arm,shared-override" property to
>> > the L2 cache DT node. This will only work if the kernel is booted in
>> > secure state and will fault on a NS kernel. So this should be considered
>> > a hack and the bootloader/firmware should make sure to set this bit.
>> >
>>
>> Is the kernel able to detect this faulty environment? It would be great
>> if we can warn the user about this issue and 'convert' all ETNA_BO_WC
>> request to ETNA_BO_CACHED or ETNA_BO_UNCACHED.
>>
>> Else there might be some bug reports in the future where something is
>> broken due to a bad environment and these kind of bugs are hard to
>> sort out.
>>
> I don't think we should work around a platform issue in individual
> drivers. I mean etnaviv makes the issue really visible, but not having
> this bit set in the PL310 controller makes the whole platform
> non-conforming to what is specified in the ARMv7 ARM, so the platform
> may exhibit all kinds of subtle breakages anyway.
>
> We may check for this bit in the PL310 initialization and warn the user
> that a firmware update might be needed to fix this. This should be
> enough to sort out bug reports caused by this specific issue.
>

I agree, although we can also point them to the device-tree option to
workaround the problem temporarily.

Christian, fyi I have fixed this in u-boot for all the SolidRun platforms.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 0/4] Etnaviv DRM driver again
  2015-09-11 14:10 [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
                   ` (4 preceding siblings ...)
  2015-09-11 14:15 ` [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
@ 2015-10-20  9:36 ` Daniel Vetter
  2015-10-21 17:04   ` Russell King - ARM Linux
  5 siblings, 1 reply; 100+ messages in thread
From: Daniel Vetter @ 2015-10-20  9:36 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, kernel, dri-devel

On Fri, Sep 11, 2015 at 04:10:10PM +0200, Lucas Stach wrote:
> Hey all,
> 
> this is a new posting of the Etnaviv DRM driver for Vivante embedded GPUs.
> This time I've squashed all patches to the DRM driver itself into a single commit
> to make it easier for people to look at and review this stuff.
> 
> Aside from squashing of some of the trivial bugfixes I intend to keep all the
> individual commits around to retain the authorship of people working on this
> driver. If you want to look at the stream of commits please fetch
> 
> git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream

Finally unlazied and looked at this, assuming it's v2. Piles of comments:

- Please don't use dev->struct_mutex in new driver code. With latest
  linux-next there's no reason at all for driver's to use it, and doing so
  will massively encumber your driver with everything else.

  There's a bit a trick involved since as-is struct_mutex allows you to do
  horrible leaky locking designs around gem_free_object. On a quick look
  to fix this you probably need a mutex for the drm_mm and various lists,
  plus per object reservations.  Tricky part is the eviction logic in
  etnaviv_iommu_map_gem, where you need to trylock eviction candidates. If
  you can't lock them you can't evict them anyway, so no harm done.

  If that's too much just replace it with your own lock and trylock in
  gem_free_object, punting to a worker if that fails (ttm has a
  deferred_free list for that, protected by a spinlock).

- ->load and ->unload are deprecated hooks becaus fundamentally racy (and
  we can't fix it since it would break dri 1 crap). Please use instead:

	drm_dev_alloc();
	/* load code */
	drm_dev_register();

  and

	drm_dev_unregister();
	/* unload code */
	drm_dev_unref();

  Laurent just sent a nice patch for rcar to do that conversion. That will
  also get rid of the deprecated drm_platform_init and drm_dev_put.

- check pad for 0 in gem_info ioctl.

- the flags check for gem_new seems leaky since you only check for flags &
  ETNA_BO_CACHE_MASK.

- similar input validation issue for op in gem_cpu_prep

- maybe add a flags/op to future-proof gem_cpu_fini just in case? Might be
  useful to optimize cache flushing.

- gem_submit_bo->flags gets it rigth, yay!

- the naming in gem_submit_reloc confuses me a bit, but that's just a
  bikeshed ;-)

- gem_submit seems to miss a flag, ime definitely needed (just to be able
  to extend to future hw iterations)

- gem_submit->exec_state doesn't seem to be validated (it's just an if
  (exec_state == 2D) ... else ... in cmd_select_pipe)

- all the array allocations aren't checked for integer overflows in
  gem_submit. Just use kmalloc_array or similar to get this right. That
  means you need to allocations in submit_create, but imo better safe than
  security-buggy. Similar problem in submit_reloc, but there
  copy_from_user will protect you since you only copy individual structs.
  Still a bit fragile.

- flags for gem_wait_fence perhaps? Probably not needed ever.

- gem_userptr should probably check for page alignment since that's the
  only unit you can map into the iommu. At least I didn't spot that check
  anywhere.

Random reading all around and looks pretty overall.

One more question: Do you have validation tests for the basic ioctl
interfaces? I'd like to push igt as the general drm gpu tests suite, and
we now have support to run testcases on non-i915 drivers. Some are generic
and run everywhere (lots more need to be converted to be generic), but I'd
also welcome driver-specific tests, maybe in an etnaviv subdirectory.

> I've kept things in staging for now, as that's the place where Christian started
> this driver, but would really like to move it to DRM proper _before_ merging. So
> please review stuff with that in mind.

Yeah, staging is the place where drm drivers get all forgotten about. Imo
reasonable good drivers should land directly in drm and it's better to
apply the last polish there.

Cheers, Daniel

> Since the last posting a lot of cleanups and bugfixes have landed, but also a major
> rewrite of the userspace interface. The UAPI is now considerably simpler as a lot
> of things that turned out to be not useful have been cut out. Also a pretty big
> security issue has been fixed where the userspace could abuse the still mapped
> command buffer to change the command stream after the kernel validated and patched
> it up, but before actual GPU execution.
> 
> Thanks to Russell King GPU power management with proper state reinitialization is
> now in place, which allows the GPU to be completely power gated when not in use,
> but is also the foundation for GPU recovery after a hanging submit.
> 
> A modified version of Russell Kings xf86-video-armada driver driver that works on
> top of the new UAPI is available at
> 
> git://git.pengutronix.de/git/lst/xf86-video-armada.git for-rmk
> 
> Regards,
> Lucas
> 
> Christian Gmeiner (1):
>   staging: etnaviv: add drm driver
> 
> Lucas Stach (2):
>   staging: etnaviv: add devicetree bindings
>   ARM: imx6: add Vivante GPU nodes
> 
> Philipp Zabel (1):
>   of: Add vendor prefix for Vivante Corporation
> 
>  .../bindings/drm/etnaviv/etnaviv-drm.txt           |   44 +
>  .../devicetree/bindings/vendor-prefixes.txt        |    1 +
>  arch/arm/boot/dts/imx6dl.dtsi                      |    5 +
>  arch/arm/boot/dts/imx6q.dtsi                       |   15 +
>  arch/arm/boot/dts/imx6qdl.dtsi                     |   21 +
>  drivers/staging/Kconfig                            |    2 +
>  drivers/staging/Makefile                           |    1 +
>  drivers/staging/etnaviv/Kconfig                    |   20 +
>  drivers/staging/etnaviv/Makefile                   |   18 +
>  drivers/staging/etnaviv/cmdstream.xml.h            |  218 +++
>  drivers/staging/etnaviv/common.xml.h               |  249 ++++
>  drivers/staging/etnaviv/etnaviv_buffer.c           |  271 ++++
>  drivers/staging/etnaviv/etnaviv_cmd_parser.c       |  119 ++
>  drivers/staging/etnaviv/etnaviv_drv.c              |  705 ++++++++++
>  drivers/staging/etnaviv/etnaviv_drv.h              |  138 ++
>  drivers/staging/etnaviv/etnaviv_gem.c              |  887 ++++++++++++
>  drivers/staging/etnaviv/etnaviv_gem.h              |  141 ++
>  drivers/staging/etnaviv/etnaviv_gem_prime.c        |  121 ++
>  drivers/staging/etnaviv/etnaviv_gem_submit.c       |  421 ++++++
>  drivers/staging/etnaviv/etnaviv_gpu.c              | 1468 ++++++++++++++++++++
>  drivers/staging/etnaviv/etnaviv_gpu.h              |  198 +++
>  drivers/staging/etnaviv/etnaviv_iommu.c            |  221 +++
>  drivers/staging/etnaviv/etnaviv_iommu.h            |   28 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.c         |   33 +
>  drivers/staging/etnaviv/etnaviv_iommu_v2.h         |   25 +
>  drivers/staging/etnaviv/etnaviv_mmu.c              |  282 ++++
>  drivers/staging/etnaviv/etnaviv_mmu.h              |   58 +
>  drivers/staging/etnaviv/state.xml.h                |  351 +++++
>  drivers/staging/etnaviv/state_hi.xml.h             |  407 ++++++
>  include/uapi/drm/etnaviv_drm.h                     |  215 +++
>  30 files changed, 6683 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/etnaviv/etnaviv-drm.txt
>  create mode 100644 drivers/staging/etnaviv/Kconfig
>  create mode 100644 drivers/staging/etnaviv/Makefile
>  create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h
>  create mode 100644 drivers/staging/etnaviv/common.xml.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c
>  create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h
>  create mode 100644 drivers/staging/etnaviv/state.xml.h
>  create mode 100644 drivers/staging/etnaviv/state_hi.xml.h
>  create mode 100644 include/uapi/drm/etnaviv_drm.h
> 
> -- 
> 2.5.0
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-10-20  9:00                 ` Lucas Stach
  2015-10-20  9:09                   ` Jon Nettleton
@ 2015-10-20  9:39                   ` Christian Gmeiner
  1 sibling, 0 replies; 100+ messages in thread
From: Christian Gmeiner @ 2015-10-20  9:39 UTC (permalink / raw)
  To: Lucas Stach; +Cc: Russell King, DRI mailing list

Hi Lucas,


2015-10-20 11:00 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
> Am Dienstag, den 20.10.2015, 09:20 +0200 schrieb Christian Gmeiner:
>> Hi Lucas,
>>
>> 2015-10-13 10:25 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
>> > Am Mittwoch, den 30.09.2015, 09:53 +0200 schrieb Christian Gmeiner:
>> >> Hi Lucas,
>> >>
>> >> 2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
>> >> > Hi Christian,
>> >> >
>> >> > Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
>> >> >> Hi Lucas.
>> >> >>
>> >> >> I think I have run into a cache flush / cache coherency issue. I will
>> >> >> try to reproduce this issue with a small example and will
>> >> >> keep you updated.
>> >> >
>> >> > What are the symptoms of the issue you are hitting? Maybe I can
>> >> > reproduce or see if I have an idea right away.
>> >> >
>> >>
>> >> With the help of the etnaviv_2d_test in my libdrm repo on github I was able
>> >> to test different bo flags.
>> >>
>> >> ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
>> >> The rendering result looks as expected. If I try ETNA_BO_WC the rendering
>> >> result looks different for every run.
>> >>
>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> >> Version: 1.0.0
>> >>   Name: etnaviv
>> >>   Date: 20150910
>> >>   Description: etnaviv DRM
>> >> bo cpu prep: 0
>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> >> 052880d433e1bf495e268206addd4087  /tmp/etna.bmp
>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> >> Version: 1.0.0
>> >>   Name: etnaviv
>> >>   Date: 20150910
>> >>   Description: etnaviv DRM
>> >> bo cpu prep: 0
>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> >> f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>> >> Version: 1.0.0
>> >>   Name: etnaviv
>> >>   Date: 20150910
>> >>   Description: etnaviv DRM
>> >> bo cpu prep: 0
>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>> >> de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp
>> >>
>> >> etna_cmd_stream_finish() waits until the submitted command stream was
>> >> processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
>> >> help.
>> >>
>> >> I am doing something wrong? Should this work in theory?
>> >>
>> > For the record: this is caused by the "shared attribute override enable"
>> > bit in the AUX_CTRL register of the PL310 cache controller not being
>> > set, which makes it non-compliant with the ARMv7 ARM specified behavior
>> > of conflicting memory aliases.
>> > The etnaviv kernel driver makes sure to clean the cachable alias before
>> > handing out the pages, but without this bit set the L2 controller will
>> > turn the userspace bufferable reads into "cachable, no allocate" which
>> > will lead to userspace hitting stale, non-evicted cache lines.
>> >
>> > This can be worked around by adding a "arm,shared-override" property to
>> > the L2 cache DT node. This will only work if the kernel is booted in
>> > secure state and will fault on a NS kernel. So this should be considered
>> > a hack and the bootloader/firmware should make sure to set this bit.
>> >
>>
>> Is the kernel able to detect this faulty environment? It would be great
>> if we can warn the user about this issue and 'convert' all ETNA_BO_WC
>> request to ETNA_BO_CACHED or ETNA_BO_UNCACHED.
>>
>> Else there might be some bug reports in the future where something is
>> broken due to a bad environment and these kind of bugs are hard to
>> sort out.
>>
> I don't think we should work around a platform issue in individual
> drivers. I mean etnaviv makes the issue really visible, but not having
> this bit set in the PL310 controller makes the whole platform
> non-conforming to what is specified in the ARMv7 ARM, so the platform
> may exhibit all kinds of subtle breakages anyway.
>

I am fine with that.

> We may check for this bit in the PL310 initialization and warn the user
> that a firmware update might be needed to fix this. This should be
> enough to sort out bug reports caused by this specific issue.
>

That is all I want. If you have a patch for that put me on CC and I can
test/review it.

greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-10-20  9:09                   ` Jon Nettleton
@ 2015-10-20  9:40                     ` Christian Gmeiner
  2015-10-20 10:42                     ` Fabio Estevam
  1 sibling, 0 replies; 100+ messages in thread
From: Christian Gmeiner @ 2015-10-20  9:40 UTC (permalink / raw)
  To: Jon Nettleton; +Cc: Russell King, DRI mailing list

Hi Jon,

2015-10-20 11:09 GMT+02:00 Jon Nettleton <jon.nettleton@gmail.com>:
> On Tue, Oct 20, 2015 at 11:00 AM, Lucas Stach <l.stach@pengutronix.de> wrote:
>> Am Dienstag, den 20.10.2015, 09:20 +0200 schrieb Christian Gmeiner:
>>> Hi Lucas,
>>>
>>> 2015-10-13 10:25 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
>>> > Am Mittwoch, den 30.09.2015, 09:53 +0200 schrieb Christian Gmeiner:
>>> >> Hi Lucas,
>>> >>
>>> >> 2015-09-28 12:39 GMT+02:00 Lucas Stach <l.stach@pengutronix.de>:
>>> >> > Hi Christian,
>>> >> >
>>> >> > Am Montag, den 28.09.2015, 11:46 +0200 schrieb Christian Gmeiner:
>>> >> >> Hi Lucas.
>>> >> >>
>>> >> >> I think I have run into a cache flush / cache coherency issue. I will
>>> >> >> try to reproduce this issue with a small example and will
>>> >> >> keep you updated.
>>> >> >
>>> >> > What are the symptoms of the issue you are hitting? Maybe I can
>>> >> > reproduce or see if I have an idea right away.
>>> >> >
>>> >>
>>> >> With the help of the etnaviv_2d_test in my libdrm repo on github I was able
>>> >> to test different bo flags.
>>> >>
>>> >> ETNA_BO_UNCACHED and ETNA_BO_CACHED are working as expected.
>>> >> The rendering result looks as expected. If I try ETNA_BO_WC the rendering
>>> >> result looks different for every run.
>>> >>
>>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>>> >> Version: 1.0.0
>>> >>   Name: etnaviv
>>> >>   Date: 20150910
>>> >>   Description: etnaviv DRM
>>> >> bo cpu prep: 0
>>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>>> >> 052880d433e1bf495e268206addd4087  /tmp/etna.bmp
>>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>>> >> Version: 1.0.0
>>> >>   Name: etnaviv
>>> >>   Date: 20150910
>>> >>   Description: etnaviv DRM
>>> >> bo cpu prep: 0
>>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>>> >> f1a02a52d81c0b79b098877e6b7d9303  /tmp/etna.bmp
>>> >> debian@cubox:~/libdrm$ tests/etnaviv/etnaviv_2d_test /dev/dri/card1
>>> >> Version: 1.0.0
>>> >>   Name: etnaviv
>>> >>   Date: 20150910
>>> >>   Description: etnaviv DRM
>>> >> bo cpu prep: 0
>>> >> debian@cubox:~/libdrm$ md5sum /tmp/etna.bmp
>>> >> de5a428eb1f6567849ef40a944a995b8  /tmp/etna.bmp
>>> >>
>>> >> etna_cmd_stream_finish() waits until the submitted command stream was
>>> >> processed by the GPU. I tried to use etna_bo_cpu_prep(..) but I that did not
>>> >> help.
>>> >>
>>> >> I am doing something wrong? Should this work in theory?
>>> >>
>>> > For the record: this is caused by the "shared attribute override enable"
>>> > bit in the AUX_CTRL register of the PL310 cache controller not being
>>> > set, which makes it non-compliant with the ARMv7 ARM specified behavior
>>> > of conflicting memory aliases.
>>> > The etnaviv kernel driver makes sure to clean the cachable alias before
>>> > handing out the pages, but without this bit set the L2 controller will
>>> > turn the userspace bufferable reads into "cachable, no allocate" which
>>> > will lead to userspace hitting stale, non-evicted cache lines.
>>> >
>>> > This can be worked around by adding a "arm,shared-override" property to
>>> > the L2 cache DT node. This will only work if the kernel is booted in
>>> > secure state and will fault on a NS kernel. So this should be considered
>>> > a hack and the bootloader/firmware should make sure to set this bit.
>>> >
>>>
>>> Is the kernel able to detect this faulty environment? It would be great
>>> if we can warn the user about this issue and 'convert' all ETNA_BO_WC
>>> request to ETNA_BO_CACHED or ETNA_BO_UNCACHED.
>>>
>>> Else there might be some bug reports in the future where something is
>>> broken due to a bad environment and these kind of bugs are hard to
>>> sort out.
>>>
>> I don't think we should work around a platform issue in individual
>> drivers. I mean etnaviv makes the issue really visible, but not having
>> this bit set in the PL310 controller makes the whole platform
>> non-conforming to what is specified in the ARMv7 ARM, so the platform
>> may exhibit all kinds of subtle breakages anyway.
>>
>> We may check for this bit in the PL310 initialization and warn the user
>> that a firmware update might be needed to fix this. This should be
>> enough to sort out bug reports caused by this specific issue.
>>
>
> I agree, although we can also point them to the device-tree option to
> workaround the problem temporarily.
>
> Christian, fyi I have fixed this in u-boot for all the SolidRun platforms.

Great - will update all my devices.

greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 00/48] Etnaviv changes RFCv1->RFCv2
  2015-10-20  9:09                   ` Jon Nettleton
  2015-10-20  9:40                     ` Christian Gmeiner
@ 2015-10-20 10:42                     ` Fabio Estevam
  1 sibling, 0 replies; 100+ messages in thread
From: Fabio Estevam @ 2015-10-20 10:42 UTC (permalink / raw)
  To: Jon Nettleton; +Cc: Russell King, DRI mailing list

Hi Jon,

On Tue, Oct 20, 2015 at 7:09 AM, Jon Nettleton <jon.nettleton@gmail.com> wrote:

> I agree, although we can also point them to the device-tree option to
> workaround the problem temporarily.
>
> Christian, fyi I have fixed this in u-boot for all the SolidRun platforms.

This is fixed in mainline U-boot for mx6:
http://git.denx.de/?p=u-boot.git;a=commitdiff;h=b4ed9f86df441d7ac304f70cc711c257e7c8ebf1;hp=9927d60f4aadcecbd3143400d01ad4500438ea4f
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 03/48] staging: etnaviv: remove compat MMU code
  2015-09-25 12:18         ` Russell King - ARM Linux
@ 2015-10-21 11:35           ` Russell King - ARM Linux
  2015-10-21 12:37             ` Lucas Stach
  0 siblings, 1 reply; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 11:35 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:18:48PM +0100, Russell King - ARM Linux wrote:
> On Fri, Sep 25, 2015 at 01:57:15PM +0200, Lucas Stach wrote:
> > There is no point in keeping backwards compatibility to older
> > kernel versions in a driver destined to mainline.
> 
> You are correct, however the repository I keep is always based on the
> previous non-rc kernel release, and I want it to work not only with
> that release, but also the future -rc's as well.  It means that from
> time to time, I will include compatibility across a merge window, but
> I do intend to drop it.

I'm not sure what version you've generated this patch against, but I
can't apply it without significant changes to your patch.

I think instead, I'm going to create a patch removing the v4.1 code
from my commit myself, and merge it into my original commit as the
4.1 code is no longer relevant.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 40/48] staging: etnaviv: debugfs: add possibility to dump kernel buffer
  2015-09-25 11:57       ` [PATCH 40/48] staging: etnaviv: debugfs: add possibility to dump kernel buffer Lucas Stach
@ 2015-10-21 11:38         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 11:38 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:52PM +0200, Lucas Stach wrote:
> From: Christian Gmeiner <christian.gmeiner@gmail.com>
> 
> This is very useful for debugging issues regarding command
> buffer processing.
> 
> Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 41/48] staging: etnaviv: change etnaviv_buffer_init() to return prefetch
  2015-09-25 11:57       ` [PATCH 41/48] staging: etnaviv: change etnaviv_buffer_init() to return prefetch Lucas Stach
@ 2015-10-21 11:38         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 11:38 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:53PM +0200, Lucas Stach wrote:
> From: Christian Gmeiner <christian.gmeiner@gmail.com>
> 
> etnaviv_buffer_init() creates a very simple command buffer
> to be able to start the FE. FE fetches 'prefetch' number of 64 bit
> words via DMA and starts to execute the read buffer.
> 
> This is a very simple code cleanup and pushes the whole buffer
> logic (alignment, cmd buffer commands, etc.) into etnaviv_buffer.c
> 
> Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 03/48] staging: etnaviv: remove compat MMU code
  2015-10-21 11:35           ` Russell King - ARM Linux
@ 2015-10-21 12:37             ` Lucas Stach
  2015-10-21 13:37               ` Russell King - ARM Linux
  0 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-10-21 12:37 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: dri-devel

Am Mittwoch, den 21.10.2015, 12:35 +0100 schrieb Russell King - ARM
Linux:
> On Fri, Sep 25, 2015 at 01:18:48PM +0100, Russell King - ARM Linux wrote:
> > On Fri, Sep 25, 2015 at 01:57:15PM +0200, Lucas Stach wrote:
> > > There is no point in keeping backwards compatibility to older
> > > kernel versions in a driver destined to mainline.
> > 
> > You are correct, however the repository I keep is always based on the
> > previous non-rc kernel release, and I want it to work not only with
> > that release, but also the future -rc's as well.  It means that from
> > time to time, I will include compatibility across a merge window, but
> > I do intend to drop it.
> 
> I'm not sure what version you've generated this patch against, but I
> can't apply it without significant changes to your patch.
> 
> I think instead, I'm going to create a patch removing the v4.1 code
> from my commit myself, and merge it into my original commit as the
> 4.1 code is no longer relevant.
> 

That's fine with me.

Regards,
Lucas
-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 03/48] staging: etnaviv: remove compat MMU code
  2015-10-21 12:37             ` Lucas Stach
@ 2015-10-21 13:37               ` Russell King - ARM Linux
  2015-10-21 14:53                 ` Lucas Stach
  0 siblings, 1 reply; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 13:37 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Wed, Oct 21, 2015 at 02:37:16PM +0200, Lucas Stach wrote:
> Am Mittwoch, den 21.10.2015, 12:35 +0100 schrieb Russell King - ARM
> Linux:
> > On Fri, Sep 25, 2015 at 01:18:48PM +0100, Russell King - ARM Linux wrote:
> > > On Fri, Sep 25, 2015 at 01:57:15PM +0200, Lucas Stach wrote:
> > > > There is no point in keeping backwards compatibility to older
> > > > kernel versions in a driver destined to mainline.
> > > 
> > > You are correct, however the repository I keep is always based on the
> > > previous non-rc kernel release, and I want it to work not only with
> > > that release, but also the future -rc's as well.  It means that from
> > > time to time, I will include compatibility across a merge window, but
> > > I do intend to drop it.
> > 
> > I'm not sure what version you've generated this patch against, but I
> > can't apply it without significant changes to your patch.
> > 
> > I think instead, I'm going to create a patch removing the v4.1 code
> > from my commit myself, and merge it into my original commit as the
> > 4.1 code is no longer relevant.
> > 
> 
> That's fine with me.

Applying these patches on top of my drm-etnaviv-devel branch:

staging: etnaviv: debugfs: add possibility to dump kernel buffer
staging: etnaviv: change etnaviv_buffer_init() to return prefetch
staging: etnaviv: remove submit type
staging: etnaviv: rewrite submit interface to use copy from user

with the corresponding DDX changes results in a kernel which silently
locks solid when Xorg starts up.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 45/48] staging: etnaviv: remove submit type
  2015-09-25 11:57       ` [PATCH 45/48] staging: etnaviv: remove submit type Lucas Stach
@ 2015-10-21 14:41         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 14:41 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:57PM +0200, Lucas Stach wrote:
> There is no point in having a context restore buffer, as the need for tracking
> GPU hardware state in userspace and the fact that we need to submit all states
> that reference memory buffers anyway to ensure proper patching of the
> relocations, eat away from the potential benefit.
> 
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user
  2015-09-25 11:57       ` [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user Lucas Stach
@ 2015-10-21 14:41         ` Russell King - ARM Linux
  2015-10-26 20:48         ` Russell King - ARM Linux
  1 sibling, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 14:41 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:58PM +0200, Lucas Stach wrote:
> This rewrites the submit interface to copy the command stream from user
> memory. This mitigates a potential attack vector of the old interface
> where userspace could submit a command buffer that would be validated by
> the kernel, but is still mapped into userspace. This could be exploited
> by changing the command stream after validation but before the actual
> GPU execution.
> 
> A nice side effect is that validation and reloc patching can now operate
> on cached memory and only the final result is copied to a writecombined
> command buffer which should make those operations a bit more efficient.
> 
> A simplification to the interface is the removal of the ability to push
> multiple command buffers per submit. As we don't use it for context
> restore buffers and the fact that userspace doesn't need to work with
> a fixed command buffer size anymore, with the potential risk to overflow
> its size in the middle of an atomic stream section, there is no need
> for this complication anymore.
> 
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 47/48] staging: etnaviv: don't use GEM buffer for internal ring buffer
  2015-09-25 11:57       ` [PATCH 47/48] staging: etnaviv: don't use GEM buffer for internal ring buffer Lucas Stach
@ 2015-10-21 14:51         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 14:51 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:59PM +0200, Lucas Stach wrote:
> Instead of using a GEM buffer for the kernel internal ring buffer
> use the newly introduced cmdbuf object. This removes the last remaining
> user of the CMDSTREAM GEM flag.
> 
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 03/48] staging: etnaviv: remove compat MMU code
  2015-10-21 13:37               ` Russell King - ARM Linux
@ 2015-10-21 14:53                 ` Lucas Stach
  2015-10-21 15:13                   ` Russell King - ARM Linux
  0 siblings, 1 reply; 100+ messages in thread
From: Lucas Stach @ 2015-10-21 14:53 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: dri-devel

Am Mittwoch, den 21.10.2015, 14:37 +0100 schrieb Russell King - ARM
Linux:
> On Wed, Oct 21, 2015 at 02:37:16PM +0200, Lucas Stach wrote:
> > Am Mittwoch, den 21.10.2015, 12:35 +0100 schrieb Russell King - ARM
> > Linux:
> > > On Fri, Sep 25, 2015 at 01:18:48PM +0100, Russell King - ARM Linux wrote:
> > > > On Fri, Sep 25, 2015 at 01:57:15PM +0200, Lucas Stach wrote:
> > > > > There is no point in keeping backwards compatibility to older
> > > > > kernel versions in a driver destined to mainline.
> > > > 
> > > > You are correct, however the repository I keep is always based on the
> > > > previous non-rc kernel release, and I want it to work not only with
> > > > that release, but also the future -rc's as well.  It means that from
> > > > time to time, I will include compatibility across a merge window, but
> > > > I do intend to drop it.
> > > 
> > > I'm not sure what version you've generated this patch against, but I
> > > can't apply it without significant changes to your patch.
> > > 
> > > I think instead, I'm going to create a patch removing the v4.1 code
> > > from my commit myself, and merge it into my original commit as the
> > > 4.1 code is no longer relevant.
> > > 
> > 
> > That's fine with me.
> 
> Applying these patches on top of my drm-etnaviv-devel branch:
> 
> staging: etnaviv: debugfs: add possibility to dump kernel buffer
> staging: etnaviv: change etnaviv_buffer_init() to return prefetch
> staging: etnaviv: remove submit type
> staging: etnaviv: rewrite submit interface to use copy from user
> 
> with the corresponding DDX changes results in a kernel which silently
> locks solid when Xorg starts up.
> 
For the ML records:

As discussed on IRC this is another case of missing input validation
with userspace passing in wrong reloc offsets, the kernel omitting
proper validation and consequently stomping over unrelated memory.


-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 03/48] staging: etnaviv: remove compat MMU code
  2015-10-21 14:53                 ` Lucas Stach
@ 2015-10-21 15:13                   ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 15:13 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Wed, Oct 21, 2015 at 04:53:50PM +0200, Lucas Stach wrote:
> Am Mittwoch, den 21.10.2015, 14:37 +0100 schrieb Russell King - ARM
> Linux:
> > On Wed, Oct 21, 2015 at 02:37:16PM +0200, Lucas Stach wrote:
> > > Am Mittwoch, den 21.10.2015, 12:35 +0100 schrieb Russell King - ARM
> > > Linux:
> > > > On Fri, Sep 25, 2015 at 01:18:48PM +0100, Russell King - ARM Linux wrote:
> > > > > On Fri, Sep 25, 2015 at 01:57:15PM +0200, Lucas Stach wrote:
> > > > > > There is no point in keeping backwards compatibility to older
> > > > > > kernel versions in a driver destined to mainline.
> > > > > 
> > > > > You are correct, however the repository I keep is always based on the
> > > > > previous non-rc kernel release, and I want it to work not only with
> > > > > that release, but also the future -rc's as well.  It means that from
> > > > > time to time, I will include compatibility across a merge window, but
> > > > > I do intend to drop it.
> > > > 
> > > > I'm not sure what version you've generated this patch against, but I
> > > > can't apply it without significant changes to your patch.
> > > > 
> > > > I think instead, I'm going to create a patch removing the v4.1 code
> > > > from my commit myself, and merge it into my original commit as the
> > > > 4.1 code is no longer relevant.
> > > > 
> > > 
> > > That's fine with me.
> > 
> > Applying these patches on top of my drm-etnaviv-devel branch:
> > 
> > staging: etnaviv: debugfs: add possibility to dump kernel buffer
> > staging: etnaviv: change etnaviv_buffer_init() to return prefetch
> > staging: etnaviv: remove submit type
> > staging: etnaviv: rewrite submit interface to use copy from user
> > 
> > with the corresponding DDX changes results in a kernel which silently
> > locks solid when Xorg starts up.
> > 
> For the ML records:
> 
> As discussed on IRC this is another case of missing input validation
> with userspace passing in wrong reloc offsets, the kernel omitting
> proper validation and consequently stomping over unrelated memory.

I think it wasn't stomping on unrelated memory, but on parts of the
command buffer which were part of valid commands for the GPU - and
changing them to be invalid commands.

I wonder how many GPU drivers that's possible - how many verify that
the list of relocations points to places that need addresses filled
in and not GPU commands... and can relocations be used to exploit the
GPU to do something it shouldn't.

I guess that's less of a problem where the GPU sits behind an IOMMU
which prevents it getting at random bits of user memory, but allowing
userspace to trample over the command stream in this way can't be good.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 43/48] staging: etnaviv: map all buffers to the GPU
  2015-09-25 11:57       ` [PATCH 43/48] staging: etnaviv: map all buffers to the GPU Lucas Stach
@ 2015-10-21 15:23         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 15:23 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:55PM +0200, Lucas Stach wrote:
> This redefines how we do cache handling in the following way:
> 
> All buffer are pushed into the GPU domain initially, this will only
> be done when populating the buffers backing store, but for simplicity
> userspace can assume that the buffer is owned by the GPU as soon as it
> constructs a GEM handle. The memory is only implicitly pulled back into
> the CPU domain when destroying the handle.
> 
> Uncached and writecombined buffers can stay in the GPU domain for their
> entire lifetime, as any modification to them will be seen by the GPU
> either immediately or latest when the write buffers get flushed when
> linking a new submit into the GPUs command stream.
> 
> If any modifications needs to be done to a cached buffer they must be
> pulled into the CPU domain before and pushed to the GPU afterwards in
> an explicit manner.
> 
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 44/48] staging: etnaviv: implement cache maintenance on cpu_(prep|fini)
  2015-09-25 11:57       ` [PATCH 44/48] staging: etnaviv: implement cache maintenance on cpu_(prep|fini) Lucas Stach
@ 2015-10-21 15:23         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 15:23 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:56PM +0200, Lucas Stach wrote:
> This makes sure that we are satifying the cache handling rules outlined
> in the previous commit. Cached buffers are pulled into the CPU domain
> before access and pushed to the GPU again when the CPU is done.
> 
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 48/48] staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI
  2015-09-25 11:58       ` [PATCH 48/48] staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI Lucas Stach
@ 2015-10-21 15:29         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 15:29 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:58:00PM +0200, Lucas Stach wrote:
> Neither userspace nor the kernel internal functions use the CMDSTREAM
> GEM type anymore. Remove it from the public API and clean up all related
> functions.
> 
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 42/48] staging: etnaviv: implement simple hang recovery
  2015-09-25 11:57       ` [PATCH 42/48] staging: etnaviv: implement simple hang recovery Lucas Stach
@ 2015-10-21 15:43         ` Russell King - ARM Linux
  0 siblings, 0 replies; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 15:43 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:54PM +0200, Lucas Stach wrote:
> Not bullet proof yet, as this possibly shoots down more submits than
> necessary. However it allows for fairly rapid turnarounds during
> userspace development.
> 
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

Applied, thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 0/4] Etnaviv DRM driver again
  2015-10-20  9:36 ` Daniel Vetter
@ 2015-10-21 17:04   ` Russell King - ARM Linux
  2015-10-22  7:12     ` Daniel Vetter
  0 siblings, 1 reply; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-21 17:04 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: kernel, dri-devel

On Tue, Oct 20, 2015 at 11:36:27AM +0200, Daniel Vetter wrote:
> On Fri, Sep 11, 2015 at 04:10:10PM +0200, Lucas Stach wrote:
> > Hey all,
> > 
> > this is a new posting of the Etnaviv DRM driver for Vivante embedded GPUs.
> > This time I've squashed all patches to the DRM driver itself into a single commit
> > to make it easier for people to look at and review this stuff.
> > 
> > Aside from squashing of some of the trivial bugfixes I intend to keep all the
> > individual commits around to retain the authorship of people working on this
> > driver. If you want to look at the stream of commits please fetch
> > 
> > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> 
> Finally unlazied and looked at this, assuming it's v2. Piles of comments:
> 
> - Please don't use dev->struct_mutex in new driver code. With latest
>   linux-next there's no reason at all for driver's to use it, and doing so
>   will massively encumber your driver with everything else.
> 
>   There's a bit a trick involved since as-is struct_mutex allows you to do
>   horrible leaky locking designs around gem_free_object. On a quick look
>   to fix this you probably need a mutex for the drm_mm and various lists,
>   plus per object reservations.  Tricky part is the eviction logic in
>   etnaviv_iommu_map_gem, where you need to trylock eviction candidates. If
>   you can't lock them you can't evict them anyway, so no harm done.
> 
>   If that's too much just replace it with your own lock and trylock in
>   gem_free_object, punting to a worker if that fails (ttm has a
>   deferred_free list for that, protected by a spinlock).
> 
> - ->load and ->unload are deprecated hooks becaus fundamentally racy (and
>   we can't fix it since it would break dri 1 crap). Please use instead:
> 
> 	drm_dev_alloc();
> 	/* load code */
> 	drm_dev_register();
> 
>   and
> 
> 	drm_dev_unregister();
> 	/* unload code */
> 	drm_dev_unref();
> 
>   Laurent just sent a nice patch for rcar to do that conversion. That will
>   also get rid of the deprecated drm_platform_init and drm_dev_put.
> 
> - check pad for 0 in gem_info ioctl.

My tree already does this, and afaik it was part of Christian's patches.
I'm not sure whether Lucas' patches are missing something.

+static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
+               struct drm_file *file)
+{
+       struct drm_etnaviv_gem_info *args = data;
+       struct drm_gem_object *obj;
+       int ret = 0;
+
+       if (args->pad)
+               return -EINVAL;

Did you miss it?

> - the flags check for gem_new seems leaky since you only check for flags &
>   ETNA_BO_CACHE_MASK.

Fixed in etnaviv_ioctl_gem_new().

> - similar input validation issue for op in gem_cpu_prep

Fixed in etnaviv_ioctl_gem_cpu_prep().

> - maybe add a flags/op to future-proof gem_cpu_fini just in case? Might be
>   useful to optimize cache flushing.

Having just merged Lucas' patch, which carries the op from gem_cpu_prep()
over to gem_cpu_fini(), I'm wondering if this is hiding a potential
problem - what if two threads call gem_cpu_prep() but with different 'op'
arguments.  Seems rather fragile, as 'etnaviv_obj->last_cpu_prep_op'
becomes rather indeterminant.

> - the naming in gem_submit_reloc confuses me a bit, but that's just a
>   bikeshed ;-)
> 
> - gem_submit seems to miss a flag, ime definitely needed (just to be able
>   to extend to future hw iterations)

Grumble, another API revision I'll need to maintain in the DDX driver.
(Even though this isn't in mainline, I'm already up to three different
kernel APIs for etnadrm.)  If we do this, I'll want to lump it together
with other API changes (like the one below for flags) so I'll wait until
we've got an answer to the gem_wait_fence question.

> - gem_submit->exec_state doesn't seem to be validated (it's just an if
>   (exec_state == 2D) ... else ... in cmd_select_pipe)

Fixed.

> - all the array allocations aren't checked for integer overflows in
>   gem_submit. Just use kmalloc_array or similar to get this right. That
>   means you need to allocations in submit_create, but imo better safe than
>   security-buggy. Similar problem in submit_reloc, but there
>   copy_from_user will protect you since you only copy individual structs.
>   Still a bit fragile.

I'm not sure kmalloc_array() is the right answer there, but I'll look
into it - I'd really like to avoid doing lots of small kmalloc()s all
over the place as each one has a non-zero cost.  The more we can lump
together, the better - but it has to be done safely.

> - flags for gem_wait_fence perhaps? Probably not needed ever.

We could, to be on the safe side, add some padding to the struct, and
not call it "flags" until we need flags.  Christian, Lucas, any thoughts
from the 3D and VG point of view on this?

> - gem_userptr should probably check for page alignment since that's the
>   only unit you can map into the iommu. At least I didn't spot that check
>   anywhere.

Added (even though it'll probably break Xvideo...)  I'll give it a test
later this afternoon/evening.

> Random reading all around and looks pretty overall.
> 
> One more question: Do you have validation tests for the basic ioctl
> interfaces? I'd like to push igt as the general drm gpu tests suite, and
> we now have support to run testcases on non-i915 drivers. Some are generic
> and run everywhere (lots more need to be converted to be generic), but I'd
> also welcome driver-specific tests, maybe in an etnaviv subdirectory.

I don't think we have - my validation is "does it work with my DDX
driver without rendering errors" which so far has proven to be good
at finding bugs.  This doesn't use libdrm-etnaviv as I need to maintain
compatibility with libetnaviv's API (the original open source library
that talks to Vivante's open source kernel space) to avoid having to
maintain two near-identical GPU backends.

Christian uses his libdrm-etnaviv library plugged into mesa.  So we
have two independently created and maintained code bases talking to
this kernel interface.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 0/4] Etnaviv DRM driver again
  2015-10-21 17:04   ` Russell King - ARM Linux
@ 2015-10-22  7:12     ` Daniel Vetter
  2015-10-22  8:19       ` Lucas Stach
  2015-10-22  8:42       ` Lucas Stach
  0 siblings, 2 replies; 100+ messages in thread
From: Daniel Vetter @ 2015-10-22  7:12 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: kernel, dri-devel

On Wed, Oct 21, 2015 at 06:04:01PM +0100, Russell King - ARM Linux wrote:
> On Tue, Oct 20, 2015 at 11:36:27AM +0200, Daniel Vetter wrote:
> > On Fri, Sep 11, 2015 at 04:10:10PM +0200, Lucas Stach wrote:
> > > Hey all,
> > > 
> > > this is a new posting of the Etnaviv DRM driver for Vivante embedded GPUs.
> > > This time I've squashed all patches to the DRM driver itself into a single commit
> > > to make it easier for people to look at and review this stuff.
> > > 
> > > Aside from squashing of some of the trivial bugfixes I intend to keep all the
> > > individual commits around to retain the authorship of people working on this
> > > driver. If you want to look at the stream of commits please fetch
> > > 
> > > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> > 
> > Finally unlazied and looked at this, assuming it's v2. Piles of comments:
> > 
> > - Please don't use dev->struct_mutex in new driver code. With latest
> >   linux-next there's no reason at all for driver's to use it, and doing so
> >   will massively encumber your driver with everything else.
> > 
> >   There's a bit a trick involved since as-is struct_mutex allows you to do
> >   horrible leaky locking designs around gem_free_object. On a quick look
> >   to fix this you probably need a mutex for the drm_mm and various lists,
> >   plus per object reservations.  Tricky part is the eviction logic in
> >   etnaviv_iommu_map_gem, where you need to trylock eviction candidates. If
> >   you can't lock them you can't evict them anyway, so no harm done.
> > 
> >   If that's too much just replace it with your own lock and trylock in
> >   gem_free_object, punting to a worker if that fails (ttm has a
> >   deferred_free list for that, protected by a spinlock).
> > 
> > - ->load and ->unload are deprecated hooks becaus fundamentally racy (and
> >   we can't fix it since it would break dri 1 crap). Please use instead:
> > 
> > 	drm_dev_alloc();
> > 	/* load code */
> > 	drm_dev_register();
> > 
> >   and
> > 
> > 	drm_dev_unregister();
> > 	/* unload code */
> > 	drm_dev_unref();
> > 
> >   Laurent just sent a nice patch for rcar to do that conversion. That will
> >   also get rid of the deprecated drm_platform_init and drm_dev_put.
> > 
> > - check pad for 0 in gem_info ioctl.
> 
> My tree already does this, and afaik it was part of Christian's patches.
> I'm not sure whether Lucas' patches are missing something.
> 
> +static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
> +               struct drm_file *file)
> +{
> +       struct drm_etnaviv_gem_info *args = data;
> +       struct drm_gem_object *obj;
> +       int ret = 0;
> +
> +       if (args->pad)
> +               return -EINVAL;
> 
> Did you miss it?

That wasn't there, I guess I looked at an outdated tree :()
> 
> > - the flags check for gem_new seems leaky since you only check for flags &
> >   ETNA_BO_CACHE_MASK.
> 
> Fixed in etnaviv_ioctl_gem_new().
> 
> > - similar input validation issue for op in gem_cpu_prep
> 
> Fixed in etnaviv_ioctl_gem_cpu_prep().
> 
> > - maybe add a flags/op to future-proof gem_cpu_fini just in case? Might be
> >   useful to optimize cache flushing.
> 
> Having just merged Lucas' patch, which carries the op from gem_cpu_prep()
> over to gem_cpu_fini(), I'm wondering if this is hiding a potential
> problem - what if two threads call gem_cpu_prep() but with different 'op'
> arguments.  Seems rather fragile, as 'etnaviv_obj->last_cpu_prep_op'
> becomes rather indeterminant.

Hm, dropping last_cpu_prep_op and adding it to the fini ioctl might be an
option. But I have no idea whether the dma api likes that really. Wrt
safety I don't think there's a concern here - if userspace decides to be
buggy wrt coherency tracking it'll get all the pieces.

> > - the naming in gem_submit_reloc confuses me a bit, but that's just a
> >   bikeshed ;-)
> > 
> > - gem_submit seems to miss a flag, ime definitely needed (just to be able
> >   to extend to future hw iterations)
> 
> Grumble, another API revision I'll need to maintain in the DDX driver.
> (Even though this isn't in mainline, I'm already up to three different
> kernel APIs for etnadrm.)  If we do this, I'll want to lump it together
> with other API changes (like the one below for flags) so I'll wait until
> we've got an answer to the gem_wait_fence question.
> 
> > - gem_submit->exec_state doesn't seem to be validated (it's just an if
> >   (exec_state == 2D) ... else ... in cmd_select_pipe)
> 
> Fixed.
> 
> > - all the array allocations aren't checked for integer overflows in
> >   gem_submit. Just use kmalloc_array or similar to get this right. That
> >   means you need to allocations in submit_create, but imo better safe than
> >   security-buggy. Similar problem in submit_reloc, but there
> >   copy_from_user will protect you since you only copy individual structs.
> >   Still a bit fragile.
> 
> I'm not sure kmalloc_array() is the right answer there, but I'll look
> into it - I'd really like to avoid doing lots of small kmalloc()s all
> over the place as each one has a non-zero cost.  The more we can lump
> together, the better - but it has to be done safely.

That was just my preference since I have a hard time reasonining about
overflow checks so like to avoid them.

> > - flags for gem_wait_fence perhaps? Probably not needed ever.
> 
> We could, to be on the safe side, add some padding to the struct, and
> not call it "flags" until we need flags.  Christian, Lucas, any thoughts
> from the 3D and VG point of view on this?

Whatever you call it you must check that it's 0, otherwise it'll be
garbage-filled by some userspace and unuseable.

> > - gem_userptr should probably check for page alignment since that's the
> >   only unit you can map into the iommu. At least I didn't spot that check
> >   anywhere.
> 
> Added (even though it'll probably break Xvideo...)  I'll give it a test
> later this afternoon/evening.

Same issue on the intel side, we just expect userspace to round things to
pages. Same like mmapping a file.

> > Random reading all around and looks pretty overall.
> > 
> > One more question: Do you have validation tests for the basic ioctl
> > interfaces? I'd like to push igt as the general drm gpu tests suite, and
> > we now have support to run testcases on non-i915 drivers. Some are generic
> > and run everywhere (lots more need to be converted to be generic), but I'd
> > also welcome driver-specific tests, maybe in an etnaviv subdirectory.
> 
> I don't think we have - my validation is "does it work with my DDX
> driver without rendering errors" which so far has proven to be good
> at finding bugs.  This doesn't use libdrm-etnaviv as I need to maintain
> compatibility with libetnaviv's API (the original open source library
> that talks to Vivante's open source kernel space) to avoid having to
> maintain two near-identical GPU backends.
> 
> Christian uses his libdrm-etnaviv library plugged into mesa.  So we
> have two independently created and maintained code bases talking to
> this kernel interface.

Ime with igt the value of a testsuite is more in exercising corner cases,
to avoid too much trouble with security holes (do we validate really
everything). And to make it easier to create specific testcases for bugs
you'll find which are hard to reproduce by just running piglit over mesa
or xts&rendercheck over the ddx. And especially for those bugs it's nice
to have some basic tests in place so it won't take you forever (which
means no one will do it) to write the corner-case tests for when you do
hit some obscure bug.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 0/4] Etnaviv DRM driver again
  2015-10-22  7:12     ` Daniel Vetter
@ 2015-10-22  8:19       ` Lucas Stach
  2015-10-22  8:42       ` Lucas Stach
  1 sibling, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-10-22  8:19 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Russell King - ARM Linux, kernel, dri-devel

Am Donnerstag, den 22.10.2015, 09:12 +0200 schrieb Daniel Vetter:
> On Wed, Oct 21, 2015 at 06:04:01PM +0100, Russell King - ARM Linux wrote:
> > On Tue, Oct 20, 2015 at 11:36:27AM +0200, Daniel Vetter wrote:
> > > On Fri, Sep 11, 2015 at 04:10:10PM +0200, Lucas Stach wrote:
> > > > Hey all,
> > > > 
> > > > this is a new posting of the Etnaviv DRM driver for Vivante embedded GPUs.
> > > > This time I've squashed all patches to the DRM driver itself into a single commit
> > > > to make it easier for people to look at and review this stuff.
> > > > 
> > > > Aside from squashing of some of the trivial bugfixes I intend to keep all the
> > > > individual commits around to retain the authorship of people working on this
> > > > driver. If you want to look at the stream of commits please fetch
> > > > 
> > > > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream
> > > 
> > > Finally unlazied and looked at this, assuming it's v2. Piles of comments:
> > > 
> > > - Please don't use dev->struct_mutex in new driver code. With latest
> > >   linux-next there's no reason at all for driver's to use it, and doing so
> > >   will massively encumber your driver with everything else.
> > > 
> > >   There's a bit a trick involved since as-is struct_mutex allows you to do
> > >   horrible leaky locking designs around gem_free_object. On a quick look
> > >   to fix this you probably need a mutex for the drm_mm and various lists,
> > >   plus per object reservations.  Tricky part is the eviction logic in
> > >   etnaviv_iommu_map_gem, where you need to trylock eviction candidates. If
> > >   you can't lock them you can't evict them anyway, so no harm done.
> > > 
> > >   If that's too much just replace it with your own lock and trylock in
> > >   gem_free_object, punting to a worker if that fails (ttm has a
> > >   deferred_free list for that, protected by a spinlock).
> > > 
> > > - ->load and ->unload are deprecated hooks becaus fundamentally racy (and
> > >   we can't fix it since it would break dri 1 crap). Please use instead:
> > > 
> > > 	drm_dev_alloc();
> > > 	/* load code */
> > > 	drm_dev_register();
> > > 
> > >   and
> > > 
> > > 	drm_dev_unregister();
> > > 	/* unload code */
> > > 	drm_dev_unref();
> > > 
> > >   Laurent just sent a nice patch for rcar to do that conversion. That will
> > >   also get rid of the deprecated drm_platform_init and drm_dev_put.
> > > 
> > > - check pad for 0 in gem_info ioctl.
> > 
> > My tree already does this, and afaik it was part of Christian's patches.
> > I'm not sure whether Lucas' patches are missing something.
> > 
> > +static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
> > +               struct drm_file *file)
> > +{
> > +       struct drm_etnaviv_gem_info *args = data;
> > +       struct drm_gem_object *obj;
> > +       int ret = 0;
> > +
> > +       if (args->pad)
> > +               return -EINVAL;
> > 
> > Did you miss it?
> 
> That wasn't there, I guess I looked at an outdated tree :()

The tree you've looked at was up-to-date until yesterday when Russell
pulled patches into his tree and build atop of that. I've just looked at
that tree again and it certainly includes the above check.

> > 
> > > - the flags check for gem_new seems leaky since you only check for flags &
> > >   ETNA_BO_CACHE_MASK.
> > 
> > Fixed in etnaviv_ioctl_gem_new().
> > 
> > > - similar input validation issue for op in gem_cpu_prep
> > 
> > Fixed in etnaviv_ioctl_gem_cpu_prep().
> > 
> > > - maybe add a flags/op to future-proof gem_cpu_fini just in case? Might be
> > >   useful to optimize cache flushing.
> > 
> > Having just merged Lucas' patch, which carries the op from gem_cpu_prep()
> > over to gem_cpu_fini(), I'm wondering if this is hiding a potential
> > problem - what if two threads call gem_cpu_prep() but with different 'op'
> > arguments.  Seems rather fragile, as 'etnaviv_obj->last_cpu_prep_op'
> > becomes rather indeterminant.
> 
> Hm, dropping last_cpu_prep_op and adding it to the fini ioctl might be an
> option. But I have no idea whether the dma api likes that really. Wrt
> safety I don't think there's a concern here - if userspace decides to be
> buggy wrt coherency tracking it'll get all the pieces.
> 
Yes, this is unsafe right now with multiple threads.

But I think we can't just allow multiple userspace threads to prepare a
buffer with different OPs, I'm not even sure it's a good idea to let 2
threads prepare the buffer at the same time at all (even if the OPs are
compatible, this gets really funny about when to write back the caches).
So I think we need to block the second thread until the first one does a
fini.

This might have some performance implications, but it makes it a lot
easier to get the coherency rules straight.

> > > - the naming in gem_submit_reloc confuses me a bit, but that's just a
> > >   bikeshed ;-)
> > > 
> > > - gem_submit seems to miss a flag, ime definitely needed (just to be able
> > >   to extend to future hw iterations)
> > 
> > Grumble, another API revision I'll need to maintain in the DDX driver.
> > (Even though this isn't in mainline, I'm already up to three different
> > kernel APIs for etnadrm.)  If we do this, I'll want to lump it together
> > with other API changes (like the one below for flags) so I'll wait until
> > we've got an answer to the gem_wait_fence question.
> > 
> > > - gem_submit->exec_state doesn't seem to be validated (it's just an if
> > >   (exec_state == 2D) ... else ... in cmd_select_pipe)
> > 
> > Fixed.
> > 
> > > - all the array allocations aren't checked for integer overflows in
> > >   gem_submit. Just use kmalloc_array or similar to get this right. That
> > >   means you need to allocations in submit_create, but imo better safe than
> > >   security-buggy. Similar problem in submit_reloc, but there
> > >   copy_from_user will protect you since you only copy individual structs.
> > >   Still a bit fragile.
> > 
> > I'm not sure kmalloc_array() is the right answer there, but I'll look
> > into it - I'd really like to avoid doing lots of small kmalloc()s all
> > over the place as each one has a non-zero cost.  The more we can lump
> > together, the better - but it has to be done safely.
> 
> That was just my preference since I have a hard time reasonining about
> overflow checks so like to avoid them.
> 
> > > - flags for gem_wait_fence perhaps? Probably not needed ever.
> > 
> > We could, to be on the safe side, add some padding to the struct, and
> > not call it "flags" until we need flags.  Christian, Lucas, any thoughts
> > from the 3D and VG point of view on this?
> 
> Whatever you call it you must check that it's 0, otherwise it'll be
> garbage-filled by some userspace and unuseable.
> 
If we already need to check for 0, we might as well call it flags. I
need to think about this a bit more if I can conceive any usage.

> > > - gem_userptr should probably check for page alignment since that's the
> > >   only unit you can map into the iommu. At least I didn't spot that check
> > >   anywhere.
> > 
> > Added (even though it'll probably break Xvideo...)  I'll give it a test
> > later this afternoon/evening.
> 
> Same issue on the intel side, we just expect userspace to round things to
> pages. Same like mmapping a file.
> 
> > > Random reading all around and looks pretty overall.
> > > 
> > > One more question: Do you have validation tests for the basic ioctl
> > > interfaces? I'd like to push igt as the general drm gpu tests suite, and
> > > we now have support to run testcases on non-i915 drivers. Some are generic
> > > and run everywhere (lots more need to be converted to be generic), but I'd
> > > also welcome driver-specific tests, maybe in an etnaviv subdirectory.
> > 
> > I don't think we have - my validation is "does it work with my DDX
> > driver without rendering errors" which so far has proven to be good
> > at finding bugs.  This doesn't use libdrm-etnaviv as I need to maintain
> > compatibility with libetnaviv's API (the original open source library
> > that talks to Vivante's open source kernel space) to avoid having to
> > maintain two near-identical GPU backends.
> > 
> > Christian uses his libdrm-etnaviv library plugged into mesa.  So we
> > have two independently created and maintained code bases talking to
> > this kernel interface.
> 
> Ime with igt the value of a testsuite is more in exercising corner cases,
> to avoid too much trouble with security holes (do we validate really
> everything). And to make it easier to create specific testcases for bugs
> you'll find which are hard to reproduce by just running piglit over mesa
> or xts&rendercheck over the ddx. And especially for those bugs it's nice
> to have some basic tests in place so it won't take you forever (which
> means no one will do it) to write the corner-case tests for when you do
> hit some obscure bug.

We don't have any tests right now as it's already enough work to keep
the existing userspace parts in sync with the changing API. I agree that
having simple tests for corner cases and discovered issues is a good
idea once the API is hammered out.

Regards,
Lucas

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH RFCv2 0/4] Etnaviv DRM driver again
  2015-10-22  7:12     ` Daniel Vetter
  2015-10-22  8:19       ` Lucas Stach
@ 2015-10-22  8:42       ` Lucas Stach
  1 sibling, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-10-22  8:42 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Russell King - ARM Linux, kernel, dri-devel

Am Donnerstag, den 22.10.2015, 09:12 +0200 schrieb Daniel Vetter:
[...]

> > > - all the array allocations aren't checked for integer overflows in
> > >   gem_submit. Just use kmalloc_array or similar to get this right. That
> > >   means you need to allocations in submit_create, but imo better safe than
> > >   security-buggy. Similar problem in submit_reloc, but there
> > >   copy_from_user will protect you since you only copy individual structs.
> > >   Still a bit fragile.
> > 
> > I'm not sure kmalloc_array() is the right answer there, but I'll look
> > into it - I'd really like to avoid doing lots of small kmalloc()s all
> > over the place as each one has a non-zero cost.  The more we can lump
> > together, the better - but it has to be done safely.
> 
> That was just my preference since I have a hard time reasonining about
> overflow checks so like to avoid them.
> 
We might just get some reasonable limits on the number of allowed
objects per submit in place, like 64k buffers and relocs should be
enough for everyone. *famous last words*

Regards,
Lucas

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user
  2015-09-25 11:57       ` [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user Lucas Stach
  2015-10-21 14:41         ` Russell King - ARM Linux
@ 2015-10-26 20:48         ` Russell King - ARM Linux
  2015-10-27 10:46           ` Lucas Stach
  1 sibling, 1 reply; 100+ messages in thread
From: Russell King - ARM Linux @ 2015-10-26 20:48 UTC (permalink / raw)
  To: Lucas Stach; +Cc: dri-devel

On Fri, Sep 25, 2015 at 01:57:58PM +0200, Lucas Stach wrote:
> +void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
> +{
> +	dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
> +			      cmdbuf->vaddr, cmdbuf->paddr);
> +	kfree(cmdbuf);
> +}
...
> @@ -885,6 +914,14 @@ static void retire_worker(struct work_struct *work)
> +	list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list,
> +				 gpu_active_list) {
> +		if (fence_after_eq(fence, cmdbuf->fence)) {
> +			etnaviv_gpu_cmdbuf_free(cmdbuf);
> +			list_del(&cmdbuf->gpu_active_list);

I mentioned that I'd left one of my machines on a soak test - with vlc
running with a video clip, but in pause mode.  vlc continues writing
frames to the etnaviv Xv GPU backend, thereby exercising these code
paths.  After about 39 hours, the above provoked the oops below, which
is a use-after-free bug.  Fix on its way to my git branch once builds
and reboots are complete.

Unable to handle kernel NULL pointer dereference at virtual address 00000004
pgd = c0004000
[00000004] *pgd=00000000
Internal error: Oops: 817 [#1] SMP ARM
Modules linked in: bnep rfcomm bluetooth algif_hash af_alg nfsd exportfs caam_jr rc_cec coda snd_soc_fsl_spdif imx_pcm_dma imx_sdma v4l2_mem2mem videobuf2_dma_contig cecd_dw_hdmi caam videobuf2_vmalloc videobuf2_memops imx2_wdt imx_thermal snd_soc_imx_spdif
CPU: 0 PID: 9381 Comm: kworker/u8:0 Not tainted 4.3.0-rc6+ #1862[140431.268864] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
Workqueue: etnaviv retire_worker
task: ea478000 ti: ea638000 task.ti: ea638000
PC is at retire_worker+0x108/0x158
LR is at mark_held_locks+0x74/0x98
pc : [<c0544134>]    lr : [<c0077838>]    psr: 200f0013
sp : ea639e58  ip : 0000022e  fp : ea639e8c
r10: 00000200  r9 : 00000100  r8 : ee28b5b0
r7 : ee28b5f0  r6 : 00385989  r5 : ee28b598  r4 : ed0eeb40
r3 : c05439f0  r2 : 00000080  r1 : 00000000  r0 : 00000001
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c5387d  Table: 3d02804a  DAC: 00000051
Process kworker/u8:0 (pid: 9381, stack limit = 0xea638210)
Stack: (0xea639e58 to 0xea63a000)
9e40:                                                       ea639e74 ee2b2834
9e60: c0077a58 ee28b5f0 e9595880 ee822000 ea639eb0 00000000 c09f40f8 ee1a4600
9e80: ea639eec ea639e90 c0047b4c c0544038 00000001 00000000 c0047ab8 ee822000
...
Backtrace:
[<c054402c>] (retire_worker) from [<c0047b4c>] (process_one_work+0x1c4/0x4b0)
 r10:ee1a4600 r9:c09f40f8 r8:00000000 r7:ea639eb0 r6:ee822000 r5:e9595880
 r4:ee28b5f0
[<c0047988>] (process_one_work) from [<c0047ea8>] (worker_thread+0x34/0x4b0)
 r10:ee822000 r9:ee822000 r8:00000088 r7:e9595898 r6:e9595880 r5:00000001
 r4:ee822030
[<c0047e74>] (worker_thread) from [<c004e0f4>] (kthread+0xe0/0xfc)
 r10:00000000 r9:00000000 r8:00000000 r7:c0047e74 r6:e9595880 r5:00000000
 r4:e1fdc800
[<c004e014>] (kthread) from [<c000fcf0>] (ret_from_fork+0x14/0x24)
 r7:00000000 r6:00000000 r5:c004e014 r4:e1fdc800
Code: ba000006 ebffff50 e594301c e5941018 (e5813004)
 ---[ end trace d430e2a4bd7d6777 ]---

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user
  2015-10-26 20:48         ` Russell King - ARM Linux
@ 2015-10-27 10:46           ` Lucas Stach
  0 siblings, 0 replies; 100+ messages in thread
From: Lucas Stach @ 2015-10-27 10:46 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: dri-devel

Am Montag, den 26.10.2015, 20:48 +0000 schrieb Russell King - ARM Linux:
> On Fri, Sep 25, 2015 at 01:57:58PM +0200, Lucas Stach wrote:
> > +void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
> > +{
> > +	dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
> > +			      cmdbuf->vaddr, cmdbuf->paddr);
> > +	kfree(cmdbuf);
> > +}
> ...
> > @@ -885,6 +914,14 @@ static void retire_worker(struct work_struct *work)
> > +	list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list,
> > +				 gpu_active_list) {
> > +		if (fence_after_eq(fence, cmdbuf->fence)) {
> > +			etnaviv_gpu_cmdbuf_free(cmdbuf);
> > +			list_del(&cmdbuf->gpu_active_list);
> 
> I mentioned that I'd left one of my machines on a soak test - with vlc
> running with a video clip, but in pause mode.  vlc continues writing
> frames to the etnaviv Xv GPU backend, thereby exercising these code
> paths.  After about 39 hours, the above provoked the oops below, which
> is a use-after-free bug.  Fix on its way to my git branch once builds
> and reboots are complete.
> 
Urgh, thanks for fixing that.

Regards,
Lucas

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 100+ messages in thread

end of thread, other threads:[~2015-10-27 10:46 UTC | newest]

Thread overview: 100+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-11 14:10 [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
2015-09-11 14:10 ` [PATCH RFCv2 1/4] of: Add vendor prefix for Vivante Corporation Lucas Stach
2015-09-11 14:10 ` [PATCH RFCv2 2/4] staging: etnaviv: add devicetree bindings Lucas Stach
2015-09-11 14:10 ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Lucas Stach
2015-09-14 13:16   ` Rob Clark
2015-09-16  7:56     ` Russell King - ARM Linux
2015-09-16  6:11   ` Christian Gmeiner
2015-09-16  7:49     ` Russell King - ARM Linux
2015-09-16 15:30     ` Lucas Stach
2015-09-16  8:04   ` Russell King - ARM Linux
2015-09-16 10:42     ` Christian Gmeiner
2015-09-16 15:36     ` Lucas Stach
2015-09-25 11:57     ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Lucas Stach
2015-09-25 11:57       ` [PATCH 01/48] staging: etnaviv: avoid holding struct_mutex over dma_alloc_coherent() Lucas Stach
2015-09-25 11:57       ` [PATCH 02/48] staging: etnaviv: restructure iommu handling Lucas Stach
2015-09-25 11:57       ` [PATCH 03/48] staging: etnaviv: remove compat MMU code Lucas Stach
2015-09-25 12:18         ` Russell King - ARM Linux
2015-10-21 11:35           ` Russell King - ARM Linux
2015-10-21 12:37             ` Lucas Stach
2015-10-21 13:37               ` Russell King - ARM Linux
2015-10-21 14:53                 ` Lucas Stach
2015-10-21 15:13                   ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 04/48] staging: etnaviv: clean up public API (part 2) Lucas Stach
2015-09-25 11:57       ` [PATCH 05/48] staging: etnaviv: rename last remaining msm_* symbols Lucas Stach
2015-09-25 11:57       ` [PATCH 06/48] staging: etnaviv: rename last remaining bits from msm to etnaviv Lucas Stach
2015-09-25 11:57       ` [PATCH 07/48] staging: etnaviv: quiten down kernel log output Lucas Stach
2015-09-25 11:57       ` [PATCH 08/48] staging: etnaviv: add proper license header to all files Lucas Stach
2015-09-25 11:57       ` [PATCH 09/48] staging: etnaviv: add Dove GPU subsystem compatible Lucas Stach
2015-09-25 11:57       ` [PATCH 10/48] staging: etnaviv: fix missing error cleanups in etnaviv_load() Lucas Stach
2015-09-25 11:57       ` [PATCH 11/48] staging: etnaviv: fix off-by-one for iommu aperture end Lucas Stach
2015-09-25 11:57       ` [PATCH 12/48] staging: etnaviv: avoid lockdep circular dependency warning Lucas Stach
2015-09-25 12:20         ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 13/48] staging: etnaviv: fix gpu debugfs show implementation Lucas Stach
2015-09-25 11:57       ` [PATCH 14/48] staging: etnaviv: use vm_insert_page() rather than vm_insert_mixed() Lucas Stach
2015-09-25 11:57       ` [PATCH 15/48] staging: etnaviv: etnaviv_gem_fault: reduce struct_mutex exposure Lucas Stach
2015-09-25 11:57       ` [PATCH 16/48] staging: etnaviv: give etnaviv_gem_mmap_offset() a sane behaviour Lucas Stach
2015-09-25 11:57       ` [PATCH 17/48] staging: etnaviv: allow etnaviv_ioctl_gem_info() locking to be interruptible Lucas Stach
2015-09-25 11:57       ` [PATCH 18/48] staging: etnaviv: make context a per-GPU thing Lucas Stach
2015-09-25 11:57       ` [PATCH 19/48] staging: etnaviv: switch to per-GPU fence completion implementation Lucas Stach
2015-09-25 11:57       ` [PATCH 20/48] staging: etnaviv: provide etnaviv_queue_work() Lucas Stach
2015-09-25 11:57       ` [PATCH 21/48] staging: etnaviv: use standard kernel types rather than stdint.h types Lucas Stach
2015-09-25 11:57       ` [PATCH 22/48] staging: etnaviv: no need to initialise a list_head Lucas Stach
2015-09-25 11:57       ` [PATCH 23/48] staging: etnaviv: fix oops caused by scanning for free blocks Lucas Stach
2015-09-25 11:57       ` [PATCH 24/48] staging: etnaviv: clean up etnaviv_iommu_unmap_gem() signature Lucas Stach
2015-09-25 11:57       ` [PATCH 25/48] staging: etnaviv: increase page table size to maximum Lucas Stach
2015-09-25 11:57       ` [PATCH 26/48] staging: etnaviv: fix BUG_ON when removing module Lucas Stach
2015-09-25 11:57       ` [PATCH 27/48] staging: etnaviv: provide a helper to load the GPU clock field Lucas Stach
2015-09-25 11:57       ` [PATCH 28/48] staging: etnaviv: rename GPU clock functions Lucas Stach
2015-09-25 11:57       ` [PATCH 29/48] staging: etnaviv: fix runtime resume Lucas Stach
2015-09-25 11:57       ` [PATCH 30/48] staging: etnaviv: drop event ring buffer tracking Lucas Stach
2015-09-25 11:57       ` [PATCH 31/48] staging: etnaviv: improve efficiency of command parser Lucas Stach
2015-09-25 11:57       ` [PATCH 32/48] staging: etnaviv: no point looking up the mapping for cmdstream bos Lucas Stach
2015-09-25 11:57       ` [PATCH 33/48] staging: etnaviv: copy submit command and bos in one go Lucas Stach
2015-09-25 11:57       ` [PATCH 34/48] staging: etnaviv: remove cmd buffer offset validation in submit_reloc() Lucas Stach
2015-09-25 11:57       ` [PATCH 35/48] staging: etnaviv: move mapping teardown into etnaviv_gem_free_object() Lucas Stach
2015-09-25 11:57       ` [PATCH 36/48] staging: etnaviv: add support for GEM_WAIT ioctl Lucas Stach
2015-09-25 11:57       ` [PATCH 37/48] staging: etnaviv: avoid pinning pages in CMA Lucas Stach
2015-09-25 11:57       ` [PATCH 38/48] staging: etnaviv: fix 'ret' may be used uninitialized in this function Lucas Stach
2015-09-25 11:57       ` [PATCH 39/48] staging: etnaviv: fix error: 'etnaviv_gpu_hw_resume' defined but not used Lucas Stach
2015-09-25 11:57       ` [PATCH 40/48] staging: etnaviv: debugfs: add possibility to dump kernel buffer Lucas Stach
2015-10-21 11:38         ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 41/48] staging: etnaviv: change etnaviv_buffer_init() to return prefetch Lucas Stach
2015-10-21 11:38         ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 42/48] staging: etnaviv: implement simple hang recovery Lucas Stach
2015-10-21 15:43         ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 43/48] staging: etnaviv: map all buffers to the GPU Lucas Stach
2015-10-21 15:23         ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 44/48] staging: etnaviv: implement cache maintenance on cpu_(prep|fini) Lucas Stach
2015-10-21 15:23         ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 45/48] staging: etnaviv: remove submit type Lucas Stach
2015-10-21 14:41         ` Russell King - ARM Linux
2015-09-25 11:57       ` [PATCH 46/48] staging: etnaviv: rewrite submit interface to use copy from user Lucas Stach
2015-10-21 14:41         ` Russell King - ARM Linux
2015-10-26 20:48         ` Russell King - ARM Linux
2015-10-27 10:46           ` Lucas Stach
2015-09-25 11:57       ` [PATCH 47/48] staging: etnaviv: don't use GEM buffer for internal ring buffer Lucas Stach
2015-10-21 14:51         ` Russell King - ARM Linux
2015-09-25 11:58       ` [PATCH 48/48] staging: etnaviv: remove CMDSTREAM GEM allocation from UAPI Lucas Stach
2015-10-21 15:29         ` Russell King - ARM Linux
2015-09-28  9:46       ` [PATCH 00/48] Etnaviv changes RFCv1->RFCv2 Christian Gmeiner
2015-09-28 10:39         ` Lucas Stach
2015-09-30  7:53           ` Christian Gmeiner
2015-10-01  8:50             ` Lucas Stach
2015-10-13  8:25             ` Lucas Stach
2015-10-20  7:20               ` Christian Gmeiner
2015-10-20  9:00                 ` Lucas Stach
2015-10-20  9:09                   ` Jon Nettleton
2015-10-20  9:40                     ` Christian Gmeiner
2015-10-20 10:42                     ` Fabio Estevam
2015-10-20  9:39                   ` Christian Gmeiner
2015-09-16 15:05   ` [PATCH RFCv2 3/4] staging: etnaviv: add drm driver Eric Anholt
2015-09-16 16:51     ` Russell King - ARM Linux
2015-09-16 18:43       ` Eric Anholt
2015-09-11 14:10 ` [PATCH RFCv2 4/4] ARM: imx6: add Vivante GPU nodes Lucas Stach
2015-09-11 14:15 ` [PATCH RFCv2 0/4] Etnaviv DRM driver again Lucas Stach
2015-10-20  9:36 ` Daniel Vetter
2015-10-21 17:04   ` Russell King - ARM Linux
2015-10-22  7:12     ` Daniel Vetter
2015-10-22  8:19       ` Lucas Stach
2015-10-22  8:42       ` Lucas Stach

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.