Commit aa72044a authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-etnaviv-next' of git://git.pengutronix.de/git/lst/linux into drm-next

here is the pull request for the etnaviv DRM driver. It includes the DT bindings
and the driver itself, platform devicetree changes will be merged through the
respective SoC trees. Otherwise it's just a squashed version of the V2 patches
that have been on the list for a while.

* 'drm-etnaviv-next' of git://git.pengutronix.de/git/lst/linux:
  MAINTAINERS: add maintainer and reviewers for the etnaviv DRM driver
  drm/etnaviv: add initial etnaviv DRM driver
  drm/etnaviv: add devicetree bindings
  devicetree: add vendor prefix for Vivante Corporation
parents 45ad5ccf 8bb0bce9
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 one of
"fsl,imx-gpu-subsystem"
"marvell,dove-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"
A more specific compatible is not needed, as the cores contain chip
identification registers at fixed locations, which provide all the
necessary information to the driver.
- 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)
Optional properties:
- power-domains: a power domain consumer specifier according to
Documentation/devicetree/bindings/power/power_domain.txt
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";
power-domains = <&gpc 1>;
};
......@@ -241,6 +241,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.
......
......@@ -3743,6 +3743,15 @@ S: Maintained
F: drivers/gpu/drm/sti
F: Documentation/devicetree/bindings/display/st,stih4xx.txt
DRM DRIVERS FOR VIVANTE GPU IP
M: Lucas Stach <l.stach@pengutronix.de>
R: Russell King <linux+etnaviv@arm.linux.org.uk>
R: Christian Gmeiner <christian.gmeiner@gmail.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
F: drivers/gpu/drm/etnaviv
F: Documentation/devicetree/bindings/display/etnaviv
DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com>
L: linux-media@vger.kernel.org
......
......@@ -266,3 +266,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
source "drivers/gpu/drm/imx/Kconfig"
source "drivers/gpu/drm/vc4/Kconfig"
source "drivers/gpu/drm/etnaviv/Kconfig"
......@@ -75,3 +75,4 @@ obj-y += i2c/
obj-y += panel/
obj-y += bridge/
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
config DRM_ETNAVIV
tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
depends on DRM
depends on ARCH_MXC || ARCH_DOVE
select SHMEM
select TMPFS
select IOMMU_API
select IOMMU_SUPPORT
select WANT_DEV_COREDUMP
help
DRM driver for Vivante GPUs.
config DRM_ETNAVIV_REGISTER_LOGGING
bool "enable ETNAVIV register logging"
depends on DRM_ETNAVIV
help
Compile in support for logging register reads/writes in a format
that can be parsed by envytools demsm tool. If enabled, register
logging can be switched on via etnaviv.reglog=y module param.
etnaviv-y := \
etnaviv_buffer.o \
etnaviv_cmd_parser.o \
etnaviv_drv.o \
etnaviv_dump.o \
etnaviv_gem_prime.o \
etnaviv_gem_submit.o \
etnaviv_gem.o \
etnaviv_gpu.o \
etnaviv_iommu_v2.o \
etnaviv_iommu.o \
etnaviv_mmu.o
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o
#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 */
This diff is collapsed.
/*
* Copyright (C) 2014 Etnaviv Project
* Author: Christian Gmeiner <christian.gmeiner@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "etnaviv_gpu.h"
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
#include "common.xml.h"
#include "state.xml.h"
#include "cmdstream.xml.h"
/*
* Command Buffer helper:
*/
static inline void OUT(struct etnaviv_cmdbuf *buffer, u32 data)
{
u32 *vaddr = (u32 *)buffer->vaddr;
BUG_ON(buffer->user_size >= buffer->size);
vaddr[buffer->user_size / 4] = data;
buffer->user_size += 4;
}
static inline void CMD_LOAD_STATE(struct etnaviv_cmdbuf *buffer,
u32 reg, u32 value)
{
u32 index = reg >> VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR;
buffer->user_size = ALIGN(buffer->user_size, 8);
/* write a register via cmd stream */
OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE |
VIV_FE_LOAD_STATE_HEADER_COUNT(1) |
VIV_FE_LOAD_STATE_HEADER_OFFSET(index));
OUT(buffer, value);
}
static inline void CMD_END(struct etnaviv_cmdbuf *buffer)
{
buffer->user_size = ALIGN(buffer->user_size, 8);
OUT(buffer, VIV_FE_END_HEADER_OP_END);
}
static inline void CMD_WAIT(struct etnaviv_cmdbuf *buffer)
{
buffer->user_size = ALIGN(buffer->user_size, 8);
OUT(buffer, VIV_FE_WAIT_HEADER_OP_WAIT | 200);
}
static inline void CMD_LINK(struct etnaviv_cmdbuf *buffer,
u16 prefetch, u32 address)
{
buffer->user_size = ALIGN(buffer->user_size, 8);
OUT(buffer, VIV_FE_LINK_HEADER_OP_LINK |
VIV_FE_LINK_HEADER_PREFETCH(prefetch));
OUT(buffer, address);
}
static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer,
u32 from, u32 to)
{
buffer->user_size = ALIGN(buffer->user_size, 8);
OUT(buffer, VIV_FE_STALL_HEADER_OP_STALL);
OUT(buffer, VIV_FE_STALL_TOKEN_FROM(from) | VIV_FE_STALL_TOKEN_TO(to));
}
static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe)
{
u32 flush;
u32 stall;
/*
* This assumes that if we're switching to 2D, we're switching
* away from 3D, and vice versa. Hence, if we're switching to
* the 2D core, we need to flush the 3D depth and color caches,
* otherwise we need to flush the 2D pixel engine cache.
*/
if (pipe == ETNA_PIPE_2D)
flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR;
else
flush = VIVS_GL_FLUSH_CACHE_PE2D;
stall = VIVS_GL_SEMAPHORE_TOKEN_FROM(SYNC_RECIPIENT_FE) |
VIVS_GL_SEMAPHORE_TOKEN_TO(SYNC_RECIPIENT_PE);
CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush);
CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, stall);
CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
CMD_LOAD_STATE(buffer, VIVS_GL_PIPE_SELECT,
VIVS_GL_PIPE_SELECT_PIPE(pipe));
}
static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_cmdbuf *buf)
{
return buf->paddr - gpu->memory_base;
}
static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
struct etnaviv_cmdbuf *buf, u32 off, u32 len)
{
u32 size = buf->size;
u32 *ptr = buf->vaddr + off;
dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
ptr, gpu_va(gpu, buf) + off, size - len * 4 - off);
print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
ptr, len * 4, 0);
}
u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
{
struct etnaviv_cmdbuf *buffer = gpu->buffer;
/* initialize buffer */
buffer->user_size = 0;
CMD_WAIT(buffer);
CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + buffer->user_size - 4);
return buffer->user_size / 8;
}
void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
{
struct etnaviv_cmdbuf *buffer = gpu->buffer;
/* Replace the last WAIT with an END */
buffer->user_size -= 16;
CMD_END(buffer);
mb();
}
void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
struct etnaviv_cmdbuf *cmdbuf)
{
struct etnaviv_cmdbuf *buffer = gpu->buffer;
u32 *lw = buffer->vaddr + buffer->user_size - 16;
u32 back, link_target, link_size, reserve_size, extra_size = 0;
if (drm_debug & DRM_UT_DRIVER)
etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
/*
* If we need to flush the MMU prior to submitting this buffer, we
* will need to append a mmu flush load state, followed by a new
* link to this buffer - a total of four additional words.
*/
if (gpu->mmu->need_flush || gpu->switch_context) {
/* link command */
extra_size += 2;
/* flush command */
if (gpu->mmu->need_flush)
extra_size += 2;
/* pipe switch commands */
if (gpu->switch_context)
extra_size += 8;
}
reserve_size = (6 + extra_size) * 4;
/*
* if we are going to completely overflow the buffer, we need to wrap.
*/
if (buffer->user_size + reserve_size > buffer->size)
buffer->user_size = 0;
/* save offset back into main buffer */
back = buffer->user_size + reserve_size - 6 * 4;
link_target = gpu_va(gpu, buffer) + buffer->user_size;
link_size = 6;
/* Skip over any extra instructions */
link_target += extra_size * sizeof(u32);
if (drm_debug & DRM_UT_DRIVER)
pr_info("stream link to 0x%08x @ 0x%08x %p\n",
link_target, gpu_va(gpu, cmdbuf), cmdbuf->vaddr);
/* jump back from cmd to main buffer */
CMD_LINK(cmdbuf, link_size, link_target);
link_target = gpu_va(gpu, cmdbuf);
link_size = cmdbuf->size / 8;
if (drm_debug & DRM_UT_DRIVER) {
print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
cmdbuf->vaddr, cmdbuf->size, 0);
pr_info("link op: %p\n", lw);
pr_info("link addr: %p\n", lw + 1);
pr_info("addr: 0x%08x\n", link_target);
pr_info("back: 0x%08x\n", gpu_va(gpu, buffer) + back);
pr_info("event: %d\n", event);
}
if (gpu->mmu->need_flush || gpu->switch_context) {
u32 new_target = gpu_va(gpu, buffer) + buffer->user_size;
if (gpu->mmu->need_flush) {
/* Add the MMU flush */
CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU,
VIVS_GL_FLUSH_MMU_FLUSH_FEMMU |
VIVS_GL_FLUSH_MMU_FLUSH_UNK1 |
VIVS_GL_FLUSH_MMU_FLUSH_UNK2 |
VIVS_GL_FLUSH_MMU_FLUSH_PEMMU |
VIVS_GL_FLUSH_MMU_FLUSH_UNK4);
gpu->mmu->need_flush = false;
}
if (gpu->switch_context) {
etnaviv_cmd_select_pipe(buffer, cmdbuf->exec_state);
gpu->switch_context = false;
}
/* And the link to the first buffer */
CMD_LINK(buffer, link_size, link_target);
/* Update the link target to point to above instructions */
link_target = new_target;
link_size = extra_size;
}
/* trigger event */
CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
VIVS_GL_EVENT_FROM_PE);
/* append WAIT/LINK to main buffer */
CMD_WAIT(buffer);
CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + (buffer->user_size - 4));
/* Change WAIT into a LINK command; write the address first. */
*(lw + 1) = link_target;
mb();
*(lw) = VIV_FE_LINK_HEADER_OP_LINK |
VIV_FE_LINK_HEADER_PREFETCH(link_size);
mb();
if (drm_debug & DRM_UT_DRIVER)
etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
}
/*
* Copyright (C) 2015 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include "etnaviv_gem.h"
#include "etnaviv_gpu.h"
#include "cmdstream.xml.h"
#define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT)
struct etna_validation_state {
struct etnaviv_gpu *gpu;
const struct drm_etnaviv_gem_submit_reloc *relocs;
unsigned int num_relocs;
u32 *start;
};
static const struct {
u16 offset;
u16 size;
} etnaviv_sensitive_states[] __initconst = {
#define ST(start, num) { (start) >> 2, (num) }
/* 2D */
ST(0x1200, 1),
ST(0x1228, 1),
ST(0x1238, 1),
ST(0x1284, 1),
ST(0x128c, 1),
ST(0x1304, 1),
ST(0x1310, 1),
ST(0x1318, 1),
ST(0x12800, 4),
ST(0x128a0, 4),
ST(0x128c0, 4),
ST(0x12970, 4),
ST(0x12a00, 8),
ST(0x12b40, 8),
ST(0x12b80, 8),
ST(0x12ce0, 8),
/* 3D */
ST(0x0644, 1),
ST(0x064c, 1),
ST(0x0680, 8),
ST(0x1410, 1),
ST(0x1430, 1),
ST(0x1458, 1),
ST(0x1460, 8),
ST(0x1480, 8),
ST(0x1500, 8),
ST(0x1520, 8),
ST(0x1608, 1),
ST(0x1610, 1),
ST(0x1658, 1),
ST(0x165c, 1),
ST(0x1664, 1),
ST(0x1668, 1),
ST(0x16a4, 1),
ST(0x16c0, 8),
ST(0x16e0, 8),
ST(0x1740, 8),
ST(0x2400, 14 * 16),
ST(0x10800, 32 * 16),
#undef ST
};
#define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
static DECLARE_BITMAP(etnaviv_states, ETNAVIV_STATES_SIZE);
void __init etnaviv_validate_init(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(etnaviv_sensitive_states); i++)
bitmap_set(etnaviv_states, etnaviv_sensitive_states[i].offset,
etnaviv_sensitive_states[i].size);
}
static void etnaviv_warn_if_non_sensitive(struct etna_validation_state *state,
unsigned int buf_offset, unsigned int state_addr)
{
if (state->num_relocs && state->relocs->submit_offset < buf_offset) {
dev_warn_once(state->gpu->dev,
"%s: relocation for non-sensitive state 0x%x at offset %u\n",
__func__, state_addr,
state->relocs->submit_offset);
while (state->num_relocs &&
state->relocs->submit_offset < buf_offset) {
state->relocs++;
state->num_relocs--;
}
}
}
static bool etnaviv_validate_load_state(struct etna_validation_state *state,
u32 *ptr, unsigned int state_offset, unsigned int num)
{
unsigned int size = min(ETNAVIV_STATES_SIZE, state_offset + num);
unsigned int st_offset = state_offset, buf_offset;
for_each_set_bit_from(st_offset, etnaviv_states, size) {
buf_offset = (ptr - state->start +
st_offset - state_offset) * 4;
etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4);
if (state->num_relocs &&
state->relocs->submit_offset == buf_offset) {
state->relocs++;
state->num_relocs--;
continue;
}
dev_warn_ratelimited(state->gpu->dev,
"%s: load state touches restricted state 0x%x at offset %u\n",
__func__, st_offset * 4, buf_offset);
return false;
}
if (state->num_relocs) {
buf_offset = (ptr - state->start + num) * 4;
etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4 +
state->relocs->submit_offset -
buf_offset);
}
return true;
}
static uint8_t cmd_length[32] = {
[FE_OPCODE_DRAW_PRIMITIVES] = 4,
[FE_OPCODE_DRAW_INDEXED_PRIMITIVES] = 6,
[FE_OPCODE_NOP] = 2,
[FE_OPCODE_STALL] = 2,
};
bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, u32 *stream,
unsigned int size,
struct drm_etnaviv_gem_submit_reloc *relocs,
unsigned int reloc_size)
{
struct etna_validation_state state;
u32 *buf = stream;
u32 *end = buf + size;
state.gpu = gpu;
state.relocs = relocs;
state.num_relocs = reloc_size;
state.start = stream;
while (buf < end) {
u32 cmd = *buf;
unsigned int len, n, off;
unsigned int op = cmd >> 27;
switch (op) {
case FE_OPCODE_LOAD_STATE:
n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT);
len = ALIGN(1 + n, 2);
if (buf + len > end)
break;
off = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_OFFSET);
if (!etnaviv_validate_load_state(&state, buf + 1,
off, n))
return false;
break;
case FE_OPCODE_DRAW_2D:
n = EXTRACT(cmd, VIV_FE_DRAW_2D_HEADER_COUNT);
if (n == 0)
n = 256;
len = 2 + n * 2;
break;
default:
len = cmd_length[op];
if (len == 0) {
dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
__func__, op, buf - state.start);
return false;
}
break;
}
buf += len;
}
if (buf > end) {
dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
__func__, buf - state.start, size);
return false;
}
return true;
}
This diff is collapsed.
/*
* Copyright (C) 2015 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ETNAVIV_DRV_H__
#define __ETNAVIV_DRV_H__
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/sizes.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/etnaviv_drm.h>
struct etnaviv_cmdbuf;
struct etnaviv_gpu;
struct etnaviv_mmu;
struct etnaviv_gem_object;
struct etnaviv_gem_submit;
struct etnaviv_file_private {
/* currently we don't do anything useful with this.. but when
* per-context address spaces are supported we'd keep track of
* the context's page-tables here.
*/
int dummy;
};
struct etnaviv_drm_private {
int num_gpus;
struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
/* list of GEM objects: */
struct mutex gem_lock;
struct list_head gem_list;
struct workqueue_struct *wq;
};
static inline void etnaviv_queue_work(struct drm_device *dev,
struct work_struct *w)
{
struct etnaviv_drm_private *priv = dev->dev_private;
queue_work(priv->wq, w);
}
int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
struct drm_file *file);
int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma);
int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset);
int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu,
struct drm_gem_object *obj, u32 *iova);
void etnaviv_gem_put_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj);
struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj);
void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj);
void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct sg_table *sg);
int etnaviv_gem_prime_pin(struct drm_gem_object *obj);
void etnaviv_gem_prime_unpin(struct drm_gem_object *obj);
void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
struct timespec *timeout);
int etnaviv_gem_cpu_fini(struct drm_gem_object *obj);
void etnaviv_gem_free_object(struct drm_gem_object *obj);
int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
u32 size, u32 flags, u32 *handle);
struct drm_gem_object *etnaviv_gem_new_locked(struct drm_device *dev,
u32 size, u32 flags);
struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
u32 size, u32 flags);
int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
uintptr_t ptr, u32 size, u32 flags, u32 *handle);
u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
struct etnaviv_cmdbuf *cmdbuf);
void etnaviv_validate_init(void);
bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
u32 *stream, unsigned int size,
struct drm_etnaviv_gem_submit_reloc *relocs, unsigned int reloc_size);
#ifdef CONFIG_DEBUG_FS
void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
struct seq_file *m);
#endif
void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name,
const char *dbgname);
void etnaviv_writel(u32 data, void __iomem *addr);
u32 etnaviv_readl(const void __iomem *addr);
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
/*
* Return the storage size of a structure with a variable length array.
* The array is nelem elements of elem_size, where the base structure
* is defined by base. If the size overflows size_t, return zero.
*/
static inline size_t size_vstruct(size_t nelem, size_t elem_size, size_t base)
{
if (elem_size && nelem > (SIZE_MAX - base) / elem_size)
return 0;
return base + nelem * elem_size;
}
/* returns true if fence a comes after fence b */
static inline bool fence_after(u32 a, u32 b)
{
return (s32)(a - b) > 0;
}
static inline bool fence_after_eq(u32 a, u32 b)
{
return (s32)(a - b) >= 0;
}
static inline unsigned long etnaviv_timeout_to_jiffies(
const struct timespec *timeout)
{
unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
unsigned long start_jiffies = jiffies;
unsigned long remaining_jiffies;
if (time_after(start_jiffies, timeout_jiffies))
remaining_jiffies = 0;
else
remaining_jiffies = timeout_jiffies - start_jiffies;
return remaining_jiffies;
}
#endif /* __ETNAVIV_DRV_H__ */
/*
* Copyright (C) 2015 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/devcoredump.h>
#include "etnaviv_dump.h"
#include "etnaviv_gem.h"
#include "etnaviv_gpu.h"
#include "etnaviv_mmu.h"
#include "state.xml.h"
#include "state_hi.xml.h"
struct core_dump_iterator {
void *start;
struct etnaviv_dump_object_header *hdr;
void *data;
};
static const unsigned short etnaviv_dump_registers[] = {
VIVS_HI_AXI_STATUS,
VIVS_HI_CLOCK_CONTROL,
VIVS_HI_IDLE_STATE,
VIVS_HI_AXI_CONFIG,
VIVS_HI_INTR_ENBL,
VIVS_HI_CHIP_IDENTITY,
VIVS_HI_CHIP_FEATURE,
VIVS_HI_CHIP_MODEL,
VIVS_HI_CHIP_REV,
VIVS_HI_CHIP_DATE,
VIVS_HI_CHIP_TIME,
VIVS_HI_CHIP_MINOR_FEATURE_0,
VIVS_HI_CACHE_CONTROL,
VIVS_HI_AXI_CONTROL,
VIVS_PM_POWER_CONTROLS,
VIVS_PM_MODULE_CONTROLS,
VIVS_PM_MODULE_STATUS,
VIVS_PM_PULSE_EATER,
VIVS_MC_MMU_FE_PAGE_TABLE,
VIVS_MC_MMU_TX_PAGE_TABLE,
VIVS_MC_MMU_PE_PAGE_TABLE,
VIVS_MC_MMU_PEZ_PAGE_TABLE,
VIVS_MC_MMU_RA_PAGE_TABLE,
VIVS_MC_DEBUG_MEMORY,
VIVS_MC_MEMORY_BASE_ADDR_RA,
VIVS_MC_MEMORY_BASE_ADDR_FE,
VIVS_MC_MEMORY_BASE_ADDR_TX,
VIVS_MC_MEMORY_BASE_ADDR_PEZ,
VIVS_MC_MEMORY_BASE_ADDR_PE,
VIVS_MC_MEMORY_TIMING_CONTROL,
VIVS_MC_BUS_CONFIG,
VIVS_FE_DMA_STATUS,
VIVS_FE_DMA_DEBUG_STATE,
VIVS_FE_DMA_ADDRESS,
VIVS_FE_DMA_LOW,
VIVS_FE_DMA_HIGH,
VIVS_FE_AUTO_FLUSH,
};
static void etnaviv_core_dump_header(struct core_dump_iterator *iter,
u32 type, void *data_end)
{
struct etnaviv_dump_object_header *hdr = iter->hdr;
hdr->magic = cpu_to_le32(ETDUMP_MAGIC);
hdr->type = cpu_to_le32(type);
hdr->file_offset = cpu_to_le32(iter->data - iter->start);
hdr->file_size = cpu_to_le32(data_end - iter->data);
iter->hdr++;
iter->data += hdr->file_size;
}
static void etnaviv_core_dump_registers(struct core_dump_iterator *iter,
struct etnaviv_gpu *gpu)
{
struct etnaviv_dump_registers *reg = iter->data;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) {
reg->reg = etnaviv_dump_registers[i];
reg->value = gpu_read(gpu, etnaviv_dump_registers[i]);
}
etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg);
}
static void etnaviv_core_dump_mmu(struct core_dump_iterator *iter,
struct etnaviv_gpu *gpu, size_t mmu_size)
{
etnaviv_iommu_dump(gpu->mmu, iter->data);
etnaviv_core_dump_header(iter, ETDUMP_BUF_MMU, iter->data + mmu_size);
}
static void etnaviv_core_dump_mem(struct core_dump_iterator *iter, u32 type,
void *ptr, size_t size, u64 iova)
{
memcpy(iter->data, ptr, size);
iter->hdr->iova = cpu_to_le64(iova);
etnaviv_core_dump_header(iter, type, iter->data + size);
}
void etnaviv_core_dump(struct etnaviv_gpu *gpu)
{
struct core_dump_iterator iter;
struct etnaviv_vram_mapping *vram;
struct etnaviv_gem_object *obj;
struct etnaviv_cmdbuf *cmd;
unsigned int n_obj, n_bomap_pages;
size_t file_size, mmu_size;
__le64 *bomap, *bomap_start;
mmu_size = etnaviv_iommu_dump_size(gpu->mmu);
/* We always dump registers, mmu, ring and end marker */
n_obj = 4;
n_bomap_pages = 0;
file_size = ARRAY_SIZE(etnaviv_dump_registers) *
sizeof(struct etnaviv_dump_registers) +
mmu_size + gpu->buffer->size;
/* Add in the active command buffers */
list_for_each_entry(cmd, &gpu->active_cmd_list, node) {
file_size += cmd->size;
n_obj++;
}
/* Add in the active buffer objects */
list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
if (!vram->use)
continue;
obj = vram->object;
file_size += obj->base.size;
n_bomap_pages += obj->base.size >> PAGE_SHIFT;
n_obj++;
}
/* If we have any buffer objects, add a bomap object */
if (n_bomap_pages) {
file_size += n_bomap_pages * sizeof(__le64);
n_obj++;
}
/* Add the size of the headers */
file_size += sizeof(*iter.hdr) * n_obj;
/* Allocate the file in vmalloc memory, it's likely to be big */
iter.start = vmalloc(file_size);
if (!iter.start) {
dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
return;
}
/* Point the data member after the headers */
iter.hdr = iter.start;
iter.data = &iter.hdr[n_obj];
memset(iter.hdr, 0, iter.data - iter.start);
etnaviv_core_dump_registers(&iter, gpu);
etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
gpu->buffer->size, gpu->buffer->paddr);
list_for_each_entry(cmd, &gpu->active_cmd_list, node)
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
cmd->size, cmd->paddr);
/* Reserve space for the bomap */
if (n_bomap_pages) {
bomap_start = bomap = iter.data;
memset(bomap, 0, sizeof(*bomap) * n_bomap_pages);
etnaviv_core_dump_header(&iter, ETDUMP_BUF_BOMAP,
bomap + n_bomap_pages);
} else {
/* Silence warning */
bomap_start = bomap = NULL;
}
list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
struct page **pages;
void *vaddr;
if (vram->use == 0)
continue;
obj = vram->object;
pages = etnaviv_gem_get_pages(obj);
if (pages) {
int j;
iter.hdr->data[0] = bomap - bomap_start;
for (j = 0; j < obj->base.size >> PAGE_SHIFT; j++)
*bomap++ = cpu_to_le64(page_to_phys(*pages++));
}
iter.hdr->iova = cpu_to_le64(vram->iova);
vaddr = etnaviv_gem_vaddr(&obj->base);
if (vaddr && !IS_ERR(vaddr))
memcpy(iter.data, vaddr, obj->base.size);
etnaviv_core_dump_header(&iter, ETDUMP_BUF_BO, iter.data +
obj->base.size);
}
etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data);
dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
}
/*
* Copyright (C) 2015 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* Etnaviv devcoredump file definitions
*/
#ifndef ETNAVIV_DUMP_H
#define ETNAVIV_DUMP_H
#include <linux/types.h>
enum {
ETDUMP_MAGIC = 0x414e5445,
ETDUMP_BUF_REG = 0,
ETDUMP_BUF_MMU,
ETDUMP_BUF_RING,
ETDUMP_BUF_CMD,
ETDUMP_BUF_BOMAP,
ETDUMP_BUF_BO,
ETDUMP_BUF_END,
};
struct etnaviv_dump_object_header {
__le32 magic;
__le32 type;
__le32 file_offset;
__le32 file_size;
__le64 iova;
__le32 data[2];
};
/* Registers object, an array of these */
struct etnaviv_dump_registers {
__le32 reg;
__le32 value;
};
#ifdef __KERNEL__
struct etnaviv_gpu;
void etnaviv_core_dump(struct etnaviv_gpu *gpu);
#endif
#endif
This diff is collapsed.
/*
* Copyright (C) 2015 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ETNAVIV_GEM_H__
#define __ETNAVIV_GEM_H__
#include <linux/reservation.h>
#include "etnaviv_drv.h"
struct etnaviv_gem_ops;
struct etnaviv_gem_object;
struct etnaviv_gem_userptr {
uintptr_t ptr;
struct task_struct *task;
struct work_struct *work;
bool ro;
};
struct etnaviv_vram_mapping {
struct list_head obj_node;
struct list_head scan_node;
struct list_head mmu_node;
struct etnaviv_gem_object *object;
struct etnaviv_iommu *mmu;
struct drm_mm_node vram_node;
unsigned int use;
u32 iova;
};
struct etnaviv_gem_object {
struct drm_gem_object base;
const struct etnaviv_gem_ops *ops;
struct mutex lock;
u32 flags;
struct list_head gem_node;
struct etnaviv_gpu *gpu; /* non-null if active */
atomic_t gpu_active;
u32 access;
struct page **pages;
struct sg_table *sgt;
void *vaddr;
/* normally (resv == &_resv) except for imported bo's */
struct reservation_object *resv;
struct reservation_object _resv;
struct list_head vram_list;
/* cache maintenance */
u32 last_cpu_prep_op;
struct etnaviv_gem_userptr userptr;
};
static inline
struct etnaviv_gem_object *to_etnaviv_bo(struct drm_gem_object *obj)
{
return container_of(obj, struct etnaviv_gem_object, base);
}
struct etnaviv_gem_ops {
int (*get_pages)(struct etnaviv_gem_object *);
void (*release)(struct etnaviv_gem_object *);
};
static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj)
{
return atomic_read(&etnaviv_obj->gpu_active) != 0;
}
#define MAX_CMDS 4
/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
* associated with the cmdstream submission for synchronization (and
* make it easier to unwind when things go wrong, etc). This only
* lasts for the duration of the submit-ioctl.
*/
struct etnaviv_gem_submit {
struct drm_device *dev;
struct etnaviv_gpu *gpu;
struct ww_acquire_ctx ticket;
u32 fence;
unsigned int nr_bos;
struct {
u32 flags;
struct etnaviv_gem_object *obj;
u32 iova;
} bos[0];
};
int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
struct timespec *timeout);
int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
struct reservation_object *robj, const struct etnaviv_gem_ops *ops,
struct etnaviv_gem_object **res);
int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj);
struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj);
void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj);
#endif /* __ETNAVIV_GEM_H__ */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/dma-buf.h>
#include "etnaviv_drv.h"
#include "etnaviv_gem.h"
struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
BUG_ON(!etnaviv_obj->sgt); /* should have already pinned! */
return etnaviv_obj->sgt;
}
void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj)
{
return etnaviv_gem_vaddr(obj);
}
void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{
/* TODO msm_gem_vunmap() */
}
int etnaviv_gem_prime_pin(struct drm_gem_object *obj)
{
if (!obj->import_attach) {
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
mutex_lock(&etnaviv_obj->lock);
etnaviv_gem_get_pages(etnaviv_obj);
mutex_unlock(&etnaviv_obj->lock);
}
return 0;
}
void etnaviv_gem_prime_unpin(struct drm_gem_object *obj)
{
if (!obj->import_attach) {
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
mutex_lock(&etnaviv_obj->lock);
etnaviv_gem_put_pages(to_etnaviv_bo(obj));
mutex_unlock(&etnaviv_obj->lock);
}
}
static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj)
{
if (etnaviv_obj->vaddr)
dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf,
etnaviv_obj->vaddr);
/* Don't drop the pages for imported dmabuf, as they are not
* ours, just free the array we allocated:
*/
if (etnaviv_obj->pages)
drm_free_large(etnaviv_obj->pages);
drm_prime_gem_destroy(&etnaviv_obj->base, etnaviv_obj->sgt);
}
static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = {
/* .get_pages should never be called */
.release = etnaviv_gem_prime_release,
};
struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct sg_table *sgt)
{
struct etnaviv_gem_object *etnaviv_obj;
size_t size = PAGE_ALIGN(attach->dmabuf->size);
int ret, npages;
ret = etnaviv_gem_new_private(dev, size, ETNA_BO_WC,
attach->dmabuf->resv,
&etnaviv_gem_prime_ops, &etnaviv_obj);
if (ret < 0)
return ERR_PTR(ret);
npages = size / PAGE_SIZE;
etnaviv_obj->sgt = sgt;
etnaviv_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
if (!etnaviv_obj->pages) {
ret = -ENOMEM;
goto fail;
}
ret = drm_prime_sg_to_page_addr_arrays(sgt, etnaviv_obj->pages,
NULL, npages);
if (ret)
goto fail;
ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
if (ret)
goto fail;
return &etnaviv_obj->base;
fail:
drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
return ERR_PTR(ret);
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2015 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ETNAVIV_GPU_H__
#define __ETNAVIV_GPU_H__
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include "etnaviv_drv.h"
struct etnaviv_gem_submit;
struct etnaviv_chip_identity {
/* Chip model. */
u32 model;
/* Revision value.*/
u32 revision;
/* Supported feature fields. */
u32 features;
/* Supported minor feature fields. */
u32 minor_features0;
/* Supported minor feature 1 fields. */
u32 minor_features1;
/* Supported minor feature 2 fields. */
u32 minor_features2;
/* Supported minor feature 3 fields. */
u32 minor_features3;
/* Number of streams supported. */
u32 stream_count;
/* Total number of temporary registers per thread. */
u32 register_max;
/* Maximum number of threads. */
u32 thread_count;
/* Number of shader cores. */
u32 shader_core_count;
/* Size of the vertex cache. */
u32 vertex_cache_size;
/* Number of entries in the vertex output buffer. */
u32 vertex_output_buffer_size;
/* Number of pixel pipes. */
u32 pixel_pipes;
/* Number of instructions. */
u32 instruction_count;
/* Number of constants. */
u32 num_constants;
/* Buffer size */
u32 buffer_size;
};
struct etnaviv_event {
bool used;
struct fence *fence;
};
struct etnaviv_cmdbuf;
struct etnaviv_gpu {
struct drm_device *drm;
struct device *dev;
struct mutex lock;
struct etnaviv_chip_identity identity;
struct etnaviv_file_private *lastctx;
bool switch_context;
/* 'ring'-buffer: */
struct etnaviv_cmdbuf *buffer;
/* bus base address of memory */
u32 memory_base;
/* event management: */
struct etnaviv_event event[30];
struct completion event_free;
spinlock_t event_spinlock;
/* list of currently in-flight command buffers */
struct list_head active_cmd_list;
u32 idle_mask;
/* Fencing support */
u32 next_fence;
u32 active_fence;
u32 completed_fence;
u32 retired_fence;
wait_queue_head_t fence_event;
unsigned int fence_context;
spinlock_t fence_spinlock;
/* worker for handling active-list retiring: */
struct work_struct retire_work;
void __iomem *mmio;
int irq;
struct etnaviv_iommu *mmu;
/* Power Control: */
struct clk *clk_bus;
struct clk *clk_core;
struct clk *clk_shader;
/* Hang Detction: */
#define DRM_ETNAVIV_HANGCHECK_PERIOD 500 /* in ms */
#define DRM_ETNAVIV_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_ETNAVIV_HANGCHECK_PERIOD)
struct timer_list hangcheck_timer;
u32 hangcheck_fence;
u32 hangcheck_dma_addr;
struct work_struct recover_work;
};
struct etnaviv_cmdbuf {
/* device this cmdbuf is allocated for */
struct etnaviv_gpu *gpu;
/* user context key, must be unique between all active users */
struct etnaviv_file_private *ctx;
/* cmdbuf properties */
void *vaddr;
dma_addr_t paddr;
u32 size;
u32 user_size;
/* fence after which this buffer is to be disposed */
struct fence *fence;
/* target exec state */
u32 exec_state;
/* per GPU in-flight list */
struct list_head node;
/* BOs attached to this command buffer */
unsigned int nr_bos;
struct etnaviv_gem_object *bo[0];
};
static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)
{
etnaviv_writel(data, gpu->mmio + reg);
}
static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg)
{
return etnaviv_readl(gpu->mmio + reg);
}
static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence)
{
return fence_after_eq(gpu->completed_fence, fence);
}
static inline bool fence_retired(struct etnaviv_gpu *gpu, u32 fence)
{
return fence_after_eq(gpu->retired_fence, fence);
}
int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value);
int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
#ifdef CONFIG_DEBUG_FS
int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
#endif
int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
unsigned int context, bool exclusive);
void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
u32 fence, struct timespec *timeout);
int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf);
struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
u32 size, size_t nr_bos);
void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
extern struct platform_driver etnaviv_gpu_driver;
#endif /* __ETNAVIV_GPU_H__ */
/*
* Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/iommu.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include "etnaviv_gpu.h"
#include "etnaviv_mmu.h"
#include "etnaviv_iommu.h"
#include "state_hi.xml.h"
#define PT_SIZE SZ_2M
#define PT_ENTRIES (PT_SIZE / sizeof(u32))
#define GPU_MEM_START 0x80000000
struct etnaviv_iommu_domain_pgtable {
u32 *pgtable;
dma_addr_t paddr;
};
struct etnaviv_iommu_domain {
struct iommu_domain domain;
struct device *dev;
void *bad_page_cpu;
dma_addr_t bad_page_dma;
struct etnaviv_iommu_domain_pgtable pgtable;
spinlock_t map_lock;
};
static struct etnaviv_iommu_domain *to_etnaviv_domain(struct iommu_domain *domain)
{
return container_of(domain, struct etnaviv_iommu_domain, domain);
}
static int pgtable_alloc(struct etnaviv_iommu_domain_pgtable *pgtable,
size_t size)
{
pgtable->pgtable = dma_alloc_coherent(NULL, size, &pgtable->paddr, GFP_KERNEL);
if (!pgtable->pgtable)
return -ENOMEM;
return 0;
}
static void pgtable_free(struct etnaviv_iommu_domain_pgtable *pgtable,
size_t size)
{
dma_free_coherent(NULL, size, pgtable->pgtable, pgtable->paddr);
}
static u32 pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable,
unsigned long iova)
{
/* calcuate index into page table */
unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
phys_addr_t paddr;
paddr = pgtable->pgtable[index];
return paddr;
}
static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
unsigned long iova, phys_addr_t paddr)
{
/* calcuate index into page table */
unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
pgtable->pgtable[index] = paddr;
}
static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
{
u32 *p;
int ret, i;
etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
SZ_4K,
&etnaviv_domain->bad_page_dma,
GFP_KERNEL);
if (!etnaviv_domain->bad_page_cpu)
return -ENOMEM;
p = etnaviv_domain->bad_page_cpu;
for (i = 0; i < SZ_4K / 4; i++)
*p++ = 0xdead55aa;
ret = pgtable_alloc(&etnaviv_domain->pgtable, PT_SIZE);
if (ret < 0) {
dma_free_coherent(etnaviv_domain->dev, SZ_4K,
etnaviv_domain->bad_page_cpu,
etnaviv_domain->bad_page_dma);
return ret;
}
for (i = 0; i < PT_ENTRIES; i++)
etnaviv_domain->pgtable.pgtable[i] =
etnaviv_domain->bad_page_dma;
spin_lock_init(&etnaviv_domain->map_lock);
return 0;
}
static void etnaviv_domain_free(struct iommu_domain *domain)
{
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
pgtable_free(&etnaviv_domain->pgtable, PT_SIZE);
dma_free_coherent(etnaviv_domain->dev, SZ_4K,
etnaviv_domain->bad_page_cpu,
etnaviv_domain->bad_page_dma);
kfree(etnaviv_domain);
}
static int etnaviv_iommuv1_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
{
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
if (size != SZ_4K)
return -EINVAL;
spin_lock(&etnaviv_domain->map_lock);
pgtable_write(&etnaviv_domain->pgtable, iova, paddr);
spin_unlock(&etnaviv_domain->map_lock);
return 0;
}
static size_t etnaviv_iommuv1_unmap(struct iommu_domain *domain,
unsigned long iova, size_t size)
{
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
if (size != SZ_4K)
return -EINVAL;
spin_lock(&etnaviv_domain->map_lock);
pgtable_write(&etnaviv_domain->pgtable, iova,
etnaviv_domain->bad_page_dma);
spin_unlock(&etnaviv_domain->map_lock);
return SZ_4K;
}
static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain,
dma_addr_t iova)
{
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
return pgtable_read(&etnaviv_domain->pgtable, iova);
}
static size_t etnaviv_iommuv1_dump_size(struct iommu_domain *domain)
{
return PT_SIZE;
}
static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf)
{
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE);
}
static struct etnaviv_iommu_ops etnaviv_iommu_ops = {
.ops = {
.domain_free = etnaviv_domain_free,
.map = etnaviv_iommuv1_map,
.unmap = etnaviv_iommuv1_unmap,
.iova_to_phys = etnaviv_iommu_iova_to_phys,
.pgsize_bitmap = SZ_4K,
},
.dump_size = etnaviv_iommuv1_dump_size,
.dump = etnaviv_iommuv1_dump,
};
void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
struct iommu_domain *domain)
{
struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
u32 pgtable;
/* set page table address in MC */
pgtable = (u32)etnaviv_domain->pgtable.paddr;
gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable);
gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable);
gpu_write(gpu, VIVS_MC_MMU_PE_PAGE_TABLE, pgtable);
gpu_write(gpu, VIVS_MC_MMU_PEZ_PAGE_TABLE, pgtable);
gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);
}
struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu)
{
struct etnaviv_iommu_domain *etnaviv_domain;
int ret;
etnaviv_domain = kzalloc(sizeof(*etnaviv_domain), GFP_KERNEL);
if (!etnaviv_domain)
return NULL;
etnaviv_domain->dev = gpu->dev;
etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
etnaviv_domain->domain.ops = &etnaviv_iommu_ops.ops;
etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START;
etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K - 1;
ret = __etnaviv_iommu_init(etnaviv_domain);
if (ret)
goto out_free;
return &etnaviv_domain->domain;
out_free:
kfree(etnaviv_domain);
return NULL;
}
/*
* 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__ */
/*
* 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;
}
/*
* 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__ */
/*
* 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_gpu.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;
}
static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu *mmu,
struct etnaviv_vram_mapping *mapping)
{
struct etnaviv_gem_object *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);
}
int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
struct etnaviv_vram_mapping *mapping)
{
struct etnaviv_vram_mapping *free = NULL;
struct sg_table *sgt = etnaviv_obj->sgt;
struct drm_mm_node *node;
int ret;
lockdep_assert_held(&etnaviv_obj->lock);
mutex_lock(&mmu->lock);
/* 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->mmu_node, &mmu->mappings);
mutex_unlock(&mmu->lock);
return 0;
}
}
node = &mapping->vram_node;
while (1) {
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(free, &mmu->mappings, mmu_node) {
/* If this vram node has not been used, skip this. */
if (!free->vram_node.mm)
continue;
/*
* If the iova is pinned, then it's in-use,
* so we must keep its mapping.
*/
if (free->use)
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);
/*
* Unmap the blocks which need to be reaped from the MMU.
* Clear the mmu pointer to prevent the get_iova finding
* this mapping.
*/
list_for_each_entry_safe(m, n, &list, scan_node) {
etnaviv_iommu_remove_mapping(mmu, m);
m->mmu = NULL;
list_del_init(&m->mmu_node);
list_del_init(&m->scan_node);
}
/*
* We removed enough mappings so that the new allocation will
* succeed. Ensure that the MMU will be flushed before the
* associated commit requesting this mapping, and retry the
* allocation one more time.
*/
mmu->need_flush = true;
}
if (ret < 0) {
mutex_unlock(&mmu->lock);
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);
mutex_unlock(&mmu->lock);
return ret;
}
list_add_tail(&mapping->mmu_node, &mmu->mappings);
mutex_unlock(&mmu->lock);
return ret;
}
void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
struct etnaviv_vram_mapping *mapping)
{
WARN_ON(mapping->use);
mutex_lock(&mmu->lock);
/* If the vram node is on the mm, unmap and remove the node */
if (mapping->vram_node.mm == &mmu->mm)
etnaviv_iommu_remove_mapping(mmu, mapping);
list_del(&mapping->mmu_node);
mutex_unlock(&mmu->lock);
}
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 etnaviv_gpu *gpu,
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->gpu = gpu;
mmu->version = version;
mutex_init(&mmu->lock);
INIT_LIST_HEAD(&mmu->mappings);
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, gpu->dev);
return mmu;
}
size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu)
{
struct etnaviv_iommu_ops *ops;
ops = container_of(iommu->domain->ops, struct etnaviv_iommu_ops, ops);
return ops->dump_size(iommu->domain);
}
void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf)
{
struct etnaviv_iommu_ops *ops;
ops = container_of(iommu->domain->ops, struct etnaviv_iommu_ops, ops);
ops->dump(iommu->domain, buf);
}
/*
* 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_gpu;
struct etnaviv_vram_mapping;
struct etnaviv_iommu_ops {
struct iommu_ops ops;
size_t (*dump_size)(struct iommu_domain *);
void (*dump)(struct iommu_domain *, void *);
};
struct etnaviv_iommu {
struct etnaviv_gpu *gpu;
struct iommu_domain *domain;
enum etnaviv_iommu_version version;
/* memory manager for GPU address area */
struct mutex lock;
struct list_head mappings;
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_iommu *mmu,
struct etnaviv_vram_mapping *mapping);
void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu);
void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf);
struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu,
struct iommu_domain *domain, enum etnaviv_iommu_version version);
#endif /* __ETNAVIV_MMU_H__ */
This diff is collapsed.
This diff is collapsed.
/*
* 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.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 */
__u32 flags; /* in, placeholder for now, no defined values */
};
/*
* 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 */
__u32 flags; /* in, placeholder for now, no defined values */
};
/* 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.
*/
#define ETNA_WAIT_NONBLOCK 0x01
struct drm_etnaviv_wait_fence {
__u32 pipe; /* in */
__u32 fence; /* in */
__u32 flags; /* in, mask of ETNA_WAIT_x */
__u32 pad;
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 */
__u32 flags; /* in, mask of ETNA_WAIT_x */
__u32 pad;
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__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment