* [PATCH 1/2] drm: add libdrm_amdgpu
@ 2015-04-21 16:39 Alex Deucher
2015-04-21 16:39 ` [PATCH 2/2] drm: add tests/amdgpu Alex Deucher
2015-04-23 16:23 ` [PATCH 1/2] drm: add libdrm_amdgpu Emil Velikov
0 siblings, 2 replies; 3+ messages in thread
From: Alex Deucher @ 2015-04-21 16:39 UTC (permalink / raw)
To: dri-devel; +Cc: Alex Deucher
This is the new ioctl wrapper used by the new admgpu driver.
It's primarily used by xf86-video-amdgpu and mesa.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
Makefile.am | 5 +
amdgpu/Makefile.am | 55 ++
amdgpu/amdgpu.h | 1278 ++++++++++++++++++++++++++++++++++++++++++++
amdgpu/amdgpu_bo.c | 622 +++++++++++++++++++++
amdgpu/amdgpu_cs.c | 981 ++++++++++++++++++++++++++++++++++
amdgpu/amdgpu_device.c | 242 +++++++++
amdgpu/amdgpu_gpu_info.c | 275 ++++++++++
amdgpu/amdgpu_internal.h | 210 ++++++++
amdgpu/amdgpu_vamgr.c | 169 ++++++
amdgpu/libdrm_amdgpu.pc.in | 10 +
amdgpu/util_double_list.h | 146 +++++
amdgpu/util_hash.c | 382 +++++++++++++
amdgpu/util_hash.h | 99 ++++
amdgpu/util_hash_table.c | 257 +++++++++
amdgpu/util_hash_table.h | 65 +++
amdgpu/util_math.h | 32 ++
configure.ac | 20 +
include/drm/amdgpu_drm.h | 600 +++++++++++++++++++++
18 files changed, 5448 insertions(+)
create mode 100644 amdgpu/Makefile.am
create mode 100644 amdgpu/amdgpu.h
create mode 100644 amdgpu/amdgpu_bo.c
create mode 100644 amdgpu/amdgpu_cs.c
create mode 100644 amdgpu/amdgpu_device.c
create mode 100644 amdgpu/amdgpu_gpu_info.c
create mode 100644 amdgpu/amdgpu_internal.h
create mode 100644 amdgpu/amdgpu_vamgr.c
create mode 100644 amdgpu/libdrm_amdgpu.pc.in
create mode 100644 amdgpu/util_double_list.h
create mode 100644 amdgpu/util_hash.c
create mode 100644 amdgpu/util_hash.h
create mode 100644 amdgpu/util_hash_table.c
create mode 100644 amdgpu/util_hash_table.h
create mode 100644 amdgpu/util_math.h
create mode 100644 include/drm/amdgpu_drm.h
diff --git a/Makefile.am b/Makefile.am
index 42d3d7f..5defeb2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,6 +57,10 @@ if HAVE_RADEON
RADEON_SUBDIR = radeon
endif
+if HAVE_AMDGPU
+AMDGPU_SUBDIR = amdgpu
+endif
+
if HAVE_OMAP
OMAP_SUBDIR = omap
endif
@@ -79,6 +83,7 @@ SUBDIRS = \
$(INTEL_SUBDIR) \
$(NOUVEAU_SUBDIR) \
$(RADEON_SUBDIR) \
+ $(AMDGPU_SUBDIR) \
$(OMAP_SUBDIR) \
$(EXYNOS_SUBDIR) \
$(FREEDRENO_SUBDIR) \
diff --git a/amdgpu/Makefile.am b/amdgpu/Makefile.am
new file mode 100644
index 0000000..9baf194
--- /dev/null
+++ b/amdgpu/Makefile.am
@@ -0,0 +1,55 @@
+# Copyright © 2008 Jérôme Glisse
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# Authors:
+# Jérôme Glisse <glisse@freedesktop.org>
+
+AM_CFLAGS = \
+ $(WARN_CFLAGS) -Wno-switch-enum \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/amdgpu \
+ $(PTHREADSTUBS_CFLAGS) \
+ -I$(top_srcdir)/include/drm
+
+libdrm_amdgpu_la_LTLIBRARIES = libdrm_amdgpu.la
+libdrm_amdgpu_ladir = $(libdir)
+libdrm_amdgpu_la_LDFLAGS = -version-number 1:0:1 -no-undefined
+libdrm_amdgpu_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
+
+libdrm_amdgpu_la_SOURCES = \
+ amdgpu_gpu_info.c \
+ amdgpu_device.c \
+ amdgpu_bo.c \
+ util_hash.c \
+ util_hash_table.c \
+ amdgpu_vamgr.c \
+ amdgpu_cs.c
+
+nodist_EXTRA_libdrm_amdgpu_la_SOURCES = dummy.cxx
+
+libdrm_amdgpuincludedir = ${includedir}/libdrm
+libdrm_amdgpuinclude_HEADERS = \
+ amdgpu.h
+
+pkgconfigdir = @pkgconfigdir@
+pkgconfig_DATA = libdrm_amdgpu.pc
+
+EXTRA_DIST = libdrm_amdgpu.pc.in
diff --git a/amdgpu/amdgpu.h b/amdgpu/amdgpu.h
new file mode 100644
index 0000000..90dc33c
--- /dev/null
+++ b/amdgpu/amdgpu.h
@@ -0,0 +1,1278 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+
+/**
+ * \file amdgpu.h
+ *
+ * Declare public libdrm_amdgpu API
+ *
+ * This file define API exposed by libdrm_amdgpu library.
+ * User wanted to use libdrm_amdgpu functionality must include
+ * this file.
+ *
+ */
+#ifndef _amdgpu_h_
+#define _amdgpu_h_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct drm_amdgpu_info_hw_ip;
+
+/*--------------------------------------------------------------------------*/
+/* --------------------------- Defines ------------------------------------ */
+/*--------------------------------------------------------------------------*/
+
+/**
+ * Define max. number of Command Buffers (IB) which could be sent to the single
+ * hardware IP to accommodate CE/DE requirements
+ *
+ * \sa amdgpu_cs_ib_info
+*/
+#define AMDGPU_CS_MAX_IBS_PER_SUBMIT 4
+
+/**
+ *
+ */
+#define AMDGPU_TIMEOUT_INFINITE 0xffffffffffffffffull
+
+/**
+ * The special flag for GFX submission to identify that this is CE IB
+ * \sa amdgpu_cs_ib_info
+*/
+#define AMDGPU_CS_GFX_IB_CE 0x1
+
+/**
+ * The special flag to mark that this IB will re-used
+ * by client and should not be automatically return back
+ * to free pool by libdrm_amdgpu when submission is completed.
+ *
+ * \sa amdgpu_cs_ib_info
+*/
+#define AMDGPU_CS_REUSE_IB 0x2
+
+/**
+ * The special resource flag for IB submission.
+ * When VRAM is full, some resources may be moved to GTT to make place
+ * for other resources which want to be in VRAM. This flag affects the order
+ * in which resources are moved back to VRAM until there is no space there.
+ * The resources with the highest priority will be moved first.
+ * The value can be between 0 and 15, inclusive.
+ */
+#define AMDGPU_IB_RESOURCE_PRIORITY(x) ((x) & 0xf)
+
+
+/*--------------------------------------------------------------------------*/
+/* ----------------------------- Enums ------------------------------------ */
+/*--------------------------------------------------------------------------*/
+
+/**
+ * Enum describing possible handle types
+ *
+ * \sa amdgpu_bo_import, amdgpu_bo_export
+ *
+*/
+enum amdgpu_bo_handle_type {
+ /** GEM flink name (needs DRM authentication, used by DRI2) */
+ amdgpu_bo_handle_type_gem_flink_name = 0,
+
+ /** KMS handle which is used by all driver ioctls */
+ amdgpu_bo_handle_type_kms = 1,
+
+ /** DMA-buf fd handle */
+ amdgpu_bo_handle_type_dma_buf_fd = 2
+};
+
+/**
+ * Enum describing possible context reset states
+ *
+ * \sa amdgpu_cs_query_reset_state()
+ *
+*/
+enum amdgpu_cs_ctx_reset_state {
+ /** No reset was detected */
+ amdgpu_cs_reset_no_error = 0,
+
+ /** Reset/TDR was detected and context caused */
+ amdgpu_cs_reset_guilty = 1,
+
+ /** Reset/TDR was detected caused by other context */
+ amdgpu_cs_reset_innocent = 2,
+
+ /** Reset TDR was detected by cause of it unknown */
+ amdgpu_cs_reset_unknown = 3
+};
+
+/**
+ * For performance reasons and to simplify logic libdrm_amdgpu will handle
+ * IBs only some pre-defined sizes.
+ *
+ * \sa amdgpu_cs_alloc_ib()
+ */
+enum amdgpu_cs_ib_size {
+ amdgpu_cs_ib_size_4K = 1,
+ amdgpu_cs_ib_size_16K = 2,
+ amdgpu_cs_ib_size_32K = 3,
+ amdgpu_cs_ib_size_64K = 4,
+ amdgpu_cs_ib_size_128K = 5
+};
+
+/** The number of different IB sizes */
+#define AMDGPU_CS_IB_SIZE_NUM 6
+
+
+/*--------------------------------------------------------------------------*/
+/* -------------------------- Datatypes ----------------------------------- */
+/*--------------------------------------------------------------------------*/
+
+/**
+ * Define opaque pointer to context associated with fd.
+ * This context will be returned as the result of
+ * "initialize" function and should be pass as the first
+ * parameter to any API call
+ */
+typedef struct amdgpu_device *amdgpu_device_handle;
+
+/**
+ * Define GPU Context type as pointer to opaque structure
+ * Example of GPU Context is the "rendering" context associated
+ * with OpenGL context (glCreateContext)
+ */
+typedef struct amdgpu_context *amdgpu_context_handle;
+
+/**
+ * Define handle for amdgpu resources: buffer, GDS, etc.
+ */
+typedef struct amdgpu_bo *amdgpu_bo_handle;
+
+/**
+ * Define handle to be used when dealing with command
+ * buffers (a.k.a. ibs)
+ *
+ */
+typedef struct amdgpu_ib *amdgpu_ib_handle;
+
+
+/*--------------------------------------------------------------------------*/
+/* -------------------------- Structures ---------------------------------- */
+/*--------------------------------------------------------------------------*/
+
+/**
+ * Structure describing memory allocation request
+ *
+ * \sa amdgpu_bo_alloc()
+ *
+*/
+struct amdgpu_bo_alloc_request {
+ /** Allocation request. It must be aligned correctly. */
+ uint64_t alloc_size;
+
+ /**
+ * It may be required to have some specific alignment requirements
+ * for physical back-up storage (e.g. for displayable surface).
+ * If 0 there is no special alignment requirement
+ */
+ uint64_t phys_alignment;
+
+ /**
+ * UMD should specify where to allocate memory and how it
+ * will be accessed by the CPU.
+ */
+ uint32_t preferred_heap;
+
+ /** Additional flags passed on allocation */
+ uint64_t flags;
+};
+
+/**
+ * Structure describing memory allocation request
+ *
+ * \sa amdgpu_bo_alloc()
+*/
+struct amdgpu_bo_alloc_result {
+ /** Assigned virtual MC Base Address */
+ uint64_t virtual_mc_base_address;
+
+ /** Handle of allocated memory to be used by the given process only. */
+ amdgpu_bo_handle buf_handle;
+};
+
+/**
+ * Special UMD specific information associated with buffer.
+ *
+ * It may be need to pass some buffer charactersitic as part
+ * of buffer sharing. Such information are defined UMD and
+ * opaque for libdrm_amdgpu as well for kernel driver.
+ *
+ * \sa amdgpu_bo_set_metadata(), amdgpu_bo_query_info,
+ * amdgpu_bo_import(), amdgpu_bo_export
+ *
+*/
+struct amdgpu_bo_metadata {
+ /** Special flag associated with surface */
+ uint64_t flags;
+
+ /**
+ * ASIC-specific tiling information (also used by DCE).
+ * The encoding is defined by the AMDGPU_TILING_* definitions.
+ */
+ uint64_t tiling_info;
+
+ /** Size of metadata associated with the buffer, in bytes. */
+ uint32_t size_metadata;
+
+ /** UMD specific metadata. Opaque for kernel */
+ uint32_t umd_metadata[64];
+};
+
+/**
+ * Structure describing allocated buffer. Client may need
+ * to query such information as part of 'sharing' buffers mechanism
+ *
+ * \sa amdgpu_bo_set_metadata(), amdgpu_bo_query_info(),
+ * amdgpu_bo_import(), amdgpu_bo_export()
+*/
+struct amdgpu_bo_info {
+ /** Allocated memory size */
+ uint64_t alloc_size;
+
+ /**
+ * It may be required to have some specific alignment requirements
+ * for physical back-up storage.
+ */
+ uint64_t phys_alignment;
+
+ /**
+ * Assigned virtual MC Base Address.
+ * \note This information will be returned only if this buffer was
+ * allocated in the same process otherwise 0 will be returned.
+ */
+ uint64_t virtual_mc_base_address;
+
+ /** Heap where to allocate memory. */
+ uint32_t preferred_heap;
+
+ /** Additional allocation flags. */
+ uint64_t alloc_flags;
+
+ /** Metadata associated with buffer if any. */
+ struct amdgpu_bo_metadata metadata;
+};
+
+/**
+ * Structure with information about "imported" buffer
+ *
+ * \sa amdgpu_bo_import()
+ *
+ */
+struct amdgpu_bo_import_result {
+ /** Handle of memory/buffer to use */
+ amdgpu_bo_handle buf_handle;
+
+ /** Buffer size */
+ uint64_t alloc_size;
+
+ /** Assigned virtual MC Base Address */
+ uint64_t virtual_mc_base_address;
+};
+
+
+/**
+ *
+ * Structure to describe GDS partitioning information.
+ * \note OA and GWS resources are asscoiated with GDS partition
+ *
+ * \sa amdgpu_gpu_resource_query_gds_info
+ *
+*/
+struct amdgpu_gds_resource_info {
+ uint32_t gds_gfx_partition_size;
+ uint32_t compute_partition_size;
+ uint32_t gds_total_size;
+ uint32_t gws_per_gfx_partition;
+ uint32_t gws_per_compute_partition;
+ uint32_t oa_per_gfx_partition;
+ uint32_t oa_per_compute_partition;
+};
+
+
+
+/**
+ * Structure describing result of request to allocate GDS
+ *
+ * \sa amdgpu_gpu_resource_gds_alloc
+ *
+*/
+struct amdgpu_gds_alloc_info {
+ /** Handle assigned to gds allocation */
+ amdgpu_bo_handle resource_handle;
+
+ /** How much was really allocated */
+ uint32_t gds_memory_size;
+
+ /** Number of GWS resources allocated */
+ uint32_t gws;
+
+ /** Number of OA resources allocated */
+ uint32_t oa;
+};
+
+/**
+ * Structure to described allocated command buffer (a.k.a. IB)
+ *
+ * \sa amdgpu_cs_alloc_ib()
+ *
+*/
+struct amdgpu_cs_ib_alloc_result {
+ /** IB allocation handle */
+ amdgpu_ib_handle handle;
+
+ /** Assigned GPU VM MC Address of command buffer */
+ uint64_t mc_address;
+
+ /** Address to be used for CPU access */
+ void *cpu;
+};
+
+/**
+ * Structure describing IB
+ *
+ * \sa amdgpu_cs_request, amdgpu_cs_submit()
+ *
+*/
+struct amdgpu_cs_ib_info {
+ /** Special flags */
+ uint64_t flags;
+
+ /** Handle of command buffer */
+ amdgpu_ib_handle ib_handle;
+
+ /**
+ * Size of Command Buffer to be submitted.
+ * - The size is in units of dwords (4 bytes).
+ * - Must be less or equal to the size of allocated IB
+ * - Could be 0
+ */
+ uint32_t size;
+};
+
+/**
+ * Structure describing submission request
+ *
+ * \note We could have several IBs as packet. e.g. CE, CE, DE case for gfx
+ *
+ * \sa amdgpu_cs_submit()
+*/
+struct amdgpu_cs_request {
+ /** Specify flags with additional information */
+ uint64_t flags;
+
+ /** Specify HW IP block type to which to send the IB. */
+ unsigned ip_type;
+
+ /** IP instance index if there are several IPs of the same type. */
+ unsigned ip_instance;
+
+ /**
+ * Specify ring index of the IP. We could have several rings
+ * in the same IP. E.g. 0 for SDMA0 and 1 for SDMA1.
+ */
+ uint32_t ring;
+
+ /**
+ * Specify number of resource handles passed.
+ * Size of 'handles' array
+ *
+ */
+ uint32_t number_of_resources;
+
+ /** Array of resources used by submission. */
+ amdgpu_bo_handle *resources;
+
+ /** Array of resources flags. This is optional and can be NULL. */
+ uint8_t *resource_flags;
+
+ /** Number of IBs to submit in the field ibs. */
+ uint32_t number_of_ibs;
+
+ /**
+ * IBs to submit. Those IBs will be submit together as single entity
+ */
+ struct amdgpu_cs_ib_info *ibs;
+};
+
+/**
+ * Structure describing request to check submission state using fence
+ *
+ * \sa amdgpu_cs_query_fence_status()
+ *
+*/
+struct amdgpu_cs_query_fence {
+
+ /** In which context IB was sent to execution */
+ amdgpu_context_handle context;
+
+ /** Timeout in nanoseconds. */
+ uint64_t timeout_ns;
+
+ /** To which HW IP type the fence belongs */
+ unsigned ip_type;
+
+ /** IP instance index if there are several IPs of the same type. */
+ unsigned ip_instance;
+
+ /** Ring index of the HW IP */
+ uint32_t ring;
+
+ /** Flags */
+ uint64_t flags;
+
+ /** Specify fence for which we need to check
+ * submission status.*/
+ uint64_t fence;
+};
+
+/**
+ * Structure which provide information about GPU VM MC Address space
+ * alignments requirements
+ *
+ * \sa amdgpu_query_buffer_size_alignment
+ */
+struct amdgpu_buffer_size_alignments {
+ /** Size alignment requirement for allocation in
+ * local memory */
+ uint64_t size_local;
+
+ /**
+ * Size alignment requirement for allocation in remote memory
+ */
+ uint64_t size_remote;
+};
+
+
+/**
+ * Structure which provide information about heap
+ *
+ * \sa amdgpu_query_heap_info()
+ *
+ */
+struct amdgpu_heap_info {
+ /** Theoretical max. available memory in the given heap */
+ uint64_t heap_size;
+
+ /**
+ * Number of bytes allocated in the heap. This includes all processes
+ * and private allocations in the kernel. It changes when new buffers
+ * are allocated, freed, and moved. It cannot be larger than
+ * heap_size.
+ */
+ uint64_t heap_usage;
+
+ /**
+ * Theoretical possible max. size of buffer which
+ * could be allocated in the given heap
+ */
+ uint64_t max_allocation;
+};
+
+
+
+/**
+ * Describe GPU h/w info needed for UMD correct initialization
+ *
+ * \sa amdgpu_query_gpu_info()
+*/
+struct amdgpu_gpu_info {
+ /** Asic id */
+ uint32_t asic_id;
+ /**< Chip revision */
+ uint32_t chip_rev;
+ /** Chip external revision */
+ uint32_t chip_external_rev;
+ /** Family ID */
+ uint32_t family_id;
+ /** Special flags */
+ uint64_t ids_flags;
+ /** max engine clock*/
+ uint64_t max_engine_clk;
+ /** number of shader engines */
+ uint32_t num_shader_engines;
+ /** number of shader arrays per engine */
+ uint32_t num_shader_arrays_per_engine;
+ /** Number of available good shader pipes */
+ uint32_t avail_quad_shader_pipes;
+ /** Max. number of shader pipes.(including good and bad pipes */
+ uint32_t max_quad_shader_pipes;
+ /** Number of parameter cache entries per shader quad pipe */
+ uint32_t cache_entries_per_quad_pipe;
+ /** Number of available graphics context */
+ uint32_t num_hw_gfx_contexts;
+ /** Number of render backend pipes */
+ uint32_t rb_pipes;
+ /** Active render backend pipe number */
+ uint32_t active_rb_pipes;
+ /** Enabled render backend pipe mask */
+ uint32_t enabled_rb_pipes_mask;
+ /** Frequency of GPU Counter */
+ uint32_t gpu_counter_freq;
+ /** CC_RB_BACKEND_DISABLE.BACKEND_DISABLE per SE */
+ uint32_t backend_disable[4];
+ /** Value of MC_ARB_RAMCFG register*/
+ uint32_t mc_arb_ramcfg;
+ /** Value of GB_ADDR_CONFIG */
+ uint32_t gb_addr_cfg;
+ /** Values of the GB_TILE_MODE0..31 registers */
+ uint32_t gb_tile_mode[32];
+ /** Values of GB_MACROTILE_MODE0..15 registers */
+ uint32_t gb_macro_tile_mode[16];
+ /** Value of PA_SC_RASTER_CONFIG register per SE */
+ uint32_t pa_sc_raster_cfg[4];
+ /** Value of PA_SC_RASTER_CONFIG_1 register per SE */
+ uint32_t pa_sc_raster_cfg1[4];
+ /* CU info */
+ uint32_t cu_active_number;
+ uint32_t cu_ao_mask;
+ uint32_t cu_bitmap[4][4];
+};
+
+
+/*--------------------------------------------------------------------------*/
+/*------------------------- Functions --------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Initialization / Cleanup
+ *
+*/
+
+
+/**
+ *
+ * \param fd - \c [in] File descriptor for AMD GPU device
+ * received previously as the result of
+ * e.g. drmOpen() call.
+ * For legacy fd type, the DRI2/DRI3 authentication
+ * should be done before calling this function.
+ * \param major_version - \c [out] Major version of library. It is assumed
+ * that adding new functionality will cause
+ * increase in major version
+ * \param minor_version - \c [out] Minor version of library
+ * \param device_handle - \c [out] Pointer to opaque context which should
+ * be passed as the first parameter on each
+ * API call
+ *
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ *
+ * \sa amdgpu_device_deinitialize()
+*/
+int amdgpu_device_initialize(int fd,
+ uint32_t *major_version,
+ uint32_t *minor_version,
+ amdgpu_device_handle *device_handle);
+
+
+
+/**
+ *
+ * When access to such library does not needed any more the special
+ * function must be call giving opportunity to clean up any
+ * resources if needed.
+ *
+ * \param device_handle - \c [in] Context associated with file
+ * descriptor for AMD GPU device
+ * received previously as the
+ * result e.g. of drmOpen() call.
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_device_initialize()
+ *
+*/
+int amdgpu_device_deinitialize(amdgpu_device_handle device_handle);
+
+
+/*
+ * Memory Management
+ *
+*/
+
+/**
+ * Allocate memory to be used by UMD for GPU related operations
+ *
+ * \param dev - \c [in] Device handle.
+ * See #amdgpu_device_initialize()
+ * \param alloc_buffer - \c [in] Pointer to the structure describing an
+ * allocation request
+ * \param info - \c [out] Pointer to structure which return
+ * information about allocated memory
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_free()
+*/
+int amdgpu_bo_alloc(amdgpu_device_handle dev,
+ struct amdgpu_bo_alloc_request *alloc_buffer,
+ struct amdgpu_bo_alloc_result *info);
+
+/**
+ * Associate opaque data with buffer to be queried by another UMD
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param buf_handle - \c [in] Buffer handle
+ * \param info - \c [in] Metadata to associated with buffer
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+*/
+int amdgpu_bo_set_metadata(amdgpu_bo_handle buf_handle,
+ struct amdgpu_bo_metadata *info);
+
+/**
+ * Query buffer information including metadata previusly associated with
+ * buffer.
+ *
+ * \param dev - \c [in] Device handle.
+ * See #amdgpu_device_initialize()
+ * \param buf_handle - \c [in] Buffer handle
+ * \param info - \c [out] Structure describing buffer
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_set_metadata(), amdgpu_bo_alloc()
+*/
+int amdgpu_bo_query_info(amdgpu_bo_handle buf_handle,
+ struct amdgpu_bo_info *info);
+
+/**
+ * Allow others to get access to buffer
+ *
+ * \param dev - \c [in] Device handle.
+ * See #amdgpu_device_initialize()
+ * \param buf_handle - \c [in] Buffer handle
+ * \param type - \c [in] Type of handle requested
+ * \param shared_handle - \c [out] Special "shared" handle
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_import()
+ *
+*/
+int amdgpu_bo_export(amdgpu_bo_handle buf_handle,
+ enum amdgpu_bo_handle_type type,
+ uint32_t *shared_handle);
+
+/**
+ * Request access to "shared" buffer
+ *
+ * \param dev - \c [in] Device handle.
+ * See #amdgpu_device_initialize()
+ * \param type - \c [in] Type of handle requested
+ * \param shared_handle - \c [in] Shared handle received as result "import"
+ * operation
+ * \param output - \c [out] Pointer to structure with information
+ * about imported buffer
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \note Buffer must be "imported" only using new "fd" (different from
+ * one used by "exporter").
+ *
+ * \sa amdgpu_bo_export()
+ *
+*/
+int amdgpu_bo_import(amdgpu_device_handle dev,
+ enum amdgpu_bo_handle_type type,
+ uint32_t shared_handle,
+ struct amdgpu_bo_import_result *output);
+
+/**
+ * Free previosuly allocated memory
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param buf_handle - \c [in] Buffer handle to free
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \note In the case of memory shared between different applications all
+ * resources will be “physically” freed only all such applications
+ * will be terminated
+ * \note If is UMD responsibility to ‘free’ buffer only when there is no
+ * more GPU access
+ *
+ * \sa amdgpu_bo_set_metadata(), amdgpu_bo_alloc()
+ *
+*/
+int amdgpu_bo_free(amdgpu_bo_handle buf_handle);
+
+/**
+ * Request CPU access to GPU accessable memory
+ *
+ * \param buf_handle - \c [in] Buffer handle
+ * \param cpu - \c [out] CPU address to be used for access
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_cpu_unmap()
+ *
+*/
+int amdgpu_bo_cpu_map(amdgpu_bo_handle buf_handle, void **cpu);
+
+/**
+ * Release CPU access to GPU memory
+ *
+ * \param buf_handle - \c [in] Buffer handle
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_cpu_map()
+ *
+*/
+int amdgpu_bo_cpu_unmap(amdgpu_bo_handle buf_handle);
+
+
+/**
+ * Wait until a buffer is not used by the device.
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_lib_initialize()
+ * \param buf_handle - \c [in] Buffer handle.
+ * \param timeout_ns - Timeout in nanoseconds.
+ * \param buffer_busy - 0 if buffer is idle, all GPU access was completed
+ * and no GPU access is scheduled.
+ * 1 GPU access is in fly or scheduled
+ *
+ * \return 0 - on success
+ * <0 - AMD specific error code
+ */
+int amdgpu_bo_wait_for_idle(amdgpu_bo_handle buf_handle,
+ uint64_t timeout_ns,
+ bool *buffer_busy);
+
+
+/*
+ * Special GPU Resources
+ *
+*/
+
+
+
+/**
+ * Query information about GDS
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param gds_info - \c [out] Pointer to structure to get GDS information
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_gpu_resource_query_gds_info(amdgpu_device_handle dev,
+ struct amdgpu_gds_resource_info *
+ gds_info);
+
+
+/**
+ * Allocate GDS partitions
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param gds_size - \c [in] Size of gds allocation. Must be aligned
+ * accordingly.
+ * \param alloc_info - \c [out] Pointer to structure to receive information
+ * about allocation
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ *
+*/
+int amdgpu_gpu_resource_gds_alloc(amdgpu_device_handle dev,
+ uint32_t gds_size,
+ struct amdgpu_gds_alloc_info *alloc_info);
+
+
+
+
+/**
+ * Release GDS resource. When GDS and associated resources not needed any
+ * more UMD should free them
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param handle - \c [in] Handle assigned to GDS allocation
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_gpu_resource_gds_free(amdgpu_bo_handle handle);
+
+
+
+/*
+ * GPU Execution context
+ *
+*/
+
+/**
+ * Create GPU execution Context
+ *
+ * For the purpose of GPU Scheduler and GPU Robustness extensions it is
+ * necessary to have information/identify rendering/compute contexts.
+ * It also may be needed to associate some specific requirements with such
+ * contexts. Kernel driver will guarantee that submission from the same
+ * context will always be executed in order (first come, first serve).
+ *
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param context - \c [out] GPU Context handle
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_cs_ctx_free()
+ *
+*/
+int amdgpu_cs_ctx_create(amdgpu_device_handle dev,
+ amdgpu_context_handle *context);
+
+/**
+ *
+ * Destroy GPU execution context when not needed any more
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param context - \c [in] GPU Context handle
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_cs_ctx_create()
+ *
+*/
+int amdgpu_cs_ctx_free(amdgpu_device_handle dev,
+ amdgpu_context_handle context);
+
+/**
+ * Query reset state for the specific GPU Context
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param context - \c [in] GPU Context handle
+ * \param state - \c [out] Reset state status
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_cs_ctx_create()
+ *
+*/
+int amdgpu_cs_query_reset_state(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ enum amdgpu_cs_ctx_reset_state *state);
+
+
+/*
+ * Command Buffers Management
+ *
+*/
+
+
+/**
+ * Allocate memory to be filled with PM4 packets and be served as the first
+ * entry point of execution (a.k.a. Indirect Buffer)
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param context - \c [in] GPU Context which will use IB
+ * \param ib_size - \c [in] Size of allocation
+ * \param output - \c [out] Pointer to structure to get information about
+ * allocated IB
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_cs_free_ib()
+ *
+*/
+int amdgpu_cs_alloc_ib(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ enum amdgpu_cs_ib_size ib_size,
+ struct amdgpu_cs_ib_alloc_result *output);
+
+/**
+ * If UMD has allocates IBs which doesn’t need any more than those IBs must
+ * be explicitly freed
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param context - \c [in] GPU Context containing IB
+ * \param handle - \c [in] IB handle
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \note Libdrm_amdgpu will guarantee that it will correctly detect when it
+ * is safe to return IB to free pool
+ *
+ * \sa amdgpu_cs_alloc_ib()
+ *
+*/
+int amdgpu_cs_free_ib(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ amdgpu_ib_handle handle);
+
+/**
+ * Send request to submit command buffers to hardware.
+ *
+ * Kernel driver could use GPU Scheduler to make decision when physically
+ * sent this request to the hardware. Accordingly this request could be put
+ * in queue and sent for execution later. The only guarantee is that request
+ * from the same GPU context to the same ip:ip_instance:ring will be executed in
+ * order.
+ *
+ *
+ * \param dev - \c [in] Device handle.
+ * See #amdgpu_device_initialize()
+ * \param context - \c [in] GPU Context
+ * \param flags - \c [in] Global submission flags
+ * \param ibs_request - \c [in] Pointer to submission requests.
+ * We could submit to the several
+ * engines/rings simulteniously as
+ * 'atomic' operation
+ * \param number_of_requests - \c [in] Number of submission requests
+ * \param fences - \c [out] Pointer to array of data to get
+ * fences to identify submission
+ * requests. Timestamps are valid
+ * in this GPU context and could be used
+ * to identify/detect completion of
+ * submission request
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \note It is assumed that by default IB will be returned to free pool
+ * automatically by libdrm_amdgpu when submission will completed.
+ * It is possible for UMD to make decision to re-use the same IB in
+ * this case it should be explicitly freed.\n
+ * Accordingly, by default, after submission UMD should not touch passed
+ * IBs. If UMD needs to re-use IB then the special flag AMDGPU_CS_REUSE_IB
+ * must be passed.
+ *
+ * \note It is required to pass correct resource list with buffer handles
+ * which will be accessible by command buffers from submission
+ * This will allow kernel driver to correctly implement "paging".
+ * Failure to do so will have unpredictable results.
+ *
+ * \sa amdgpu_command_buffer_alloc(), amdgpu_command_buffer_free(),
+ * amdgpu_cs_query_fence_status()
+ *
+*/
+int amdgpu_cs_submit(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ uint64_t flags,
+ struct amdgpu_cs_request *ibs_request,
+ uint32_t number_of_requests,
+ uint64_t *fences);
+
+/**
+ * Query status of Command Buffer Submission
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param fence - \c [in] Structure describing fence to query
+ * \param expired - \c [out] If fence expired or not.\n
+ * 0 – if fence is not expired\n
+ * !0 - otherwise
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+ * \note If UMD wants only to check operation status and returned immediately
+ * then timeout value as 0 must be passed. In this case success will be
+ * returned in the case if submission was completed or timeout error
+ * code.
+ *
+ * \sa amdgpu_cs_submit()
+*/
+int amdgpu_cs_query_fence_status(amdgpu_device_handle dev,
+ struct amdgpu_cs_query_fence *fence,
+ uint32_t *expired);
+
+
+/*
+ * Query / Info API
+ *
+*/
+
+
+/**
+ * Query allocation size alignments
+ *
+ * UMD should query information about GPU VM MC size alignments requirements
+ * to be able correctly choose required allocation size and implement
+ * internal optimization if needed.
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param info - \c [out] Pointer to structure to get size alignment
+ * requirements
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_query_buffer_size_alignment(amdgpu_device_handle dev,
+ struct amdgpu_buffer_size_alignments
+ *info);
+
+
+
+/**
+ * Query firmware versions
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param fw_type - \c [in] AMDGPU_INFO_FW_*
+ * \param ip_instance - \c [in] Index of the IP block of the same type.
+ * \param index - \c [in] Index of the engine. (for SDMA and MEC)
+ * \param version - \c [out] Pointer to to the "version" return value
+ * \param feature - \c [out] Pointer to to the "feature" return value
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_query_firmware_version(amdgpu_device_handle dev, unsigned fw_type,
+ unsigned ip_instance, unsigned index,
+ uint32_t *version, uint32_t *feature);
+
+
+
+/**
+ * Query the number of HW IP instances of a certain type.
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param type - \c [in] Hardware IP block type = AMDGPU_HW_IP_*
+ * \param count - \c [out] Pointer to structure to get information
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+*/
+int amdgpu_query_hw_ip_count(amdgpu_device_handle dev, unsigned type,
+ uint32_t *count);
+
+
+
+/**
+ * Query engine information
+ *
+ * This query allows UMD to query information different engines and their
+ * capabilities.
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param type - \c [in] Hardware IP block type = AMDGPU_HW_IP_*
+ * \param ip_instance - \c [in] Index of the IP block of the same type.
+ * \param info - \c [out] Pointer to structure to get information
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+*/
+int amdgpu_query_hw_ip_info(amdgpu_device_handle dev, unsigned type,
+ unsigned ip_instance,
+ struct drm_amdgpu_info_hw_ip *info);
+
+
+
+
+/**
+ * Query heap information
+ *
+ * This query allows UMD to query potentially available memory resources and
+ * adjust their logic if necessary.
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param heap - \c [in] Heap type
+ * \param info - \c [in] Pointer to structure to get needed information
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_query_heap_info(amdgpu_device_handle dev,
+ uint32_t heap,
+ uint32_t flags,
+ struct amdgpu_heap_info *info);
+
+
+
+/**
+ * Get the CRTC ID from the mode object ID
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param id - \c [in] Mode object ID
+ * \param result - \c [in] Pointer to the CRTC ID
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_query_crtc_from_id(amdgpu_device_handle dev, unsigned id,
+ int32_t *result);
+
+
+
+/**
+ * Query GPU H/w Info
+ *
+ * Query hardware specific information
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param heap - \c [in] Heap type
+ * \param info - \c [in] Pointer to structure to get needed information
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_query_gpu_info(amdgpu_device_handle dev,
+ struct amdgpu_gpu_info *info);
+
+
+
+/**
+ * Query hardware or driver information.
+ *
+ * The return size is query-specific and depends on the "info_id" parameter.
+ * No more than "size" bytes is returned.
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param info_id - \c [in] AMDGPU_INFO_*
+ * \param size - \c [in] Size of the returned value.
+ * \param value - \c [out] Pointer to the return value.
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX error code
+ *
+*/
+int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id,
+ unsigned size, void *value);
+
+
+
+/**
+ * Read a set of consecutive memory-mapped registers.
+ * Not all registers are allowed to be read by userspace.
+ *
+ * \param dev - \c [in] Device handle. See #amdgpu_device_initialize(
+ * \param dword_offset - \c [in] Register offset in dwords
+ * \param count - \c [in] The number of registers to read starting
+ * from the offset
+ * \param instance - \c [in] GRBM_GFX_INDEX selector. It may have other
+ * uses. Set it to 0xffffffff if unsure.
+ * \param flags - \c [in] Flags with additional information.
+ * \param values - \c [out] The pointer to return values.
+ *
+ * \return 0 on success\n
+ * >0 - AMD specific error code\n
+ * <0 - Negative POSIX error code
+ *
+*/
+int amdgpu_read_mm_registers(amdgpu_device_handle dev, unsigned dword_offset,
+ unsigned count, uint32_t instance, uint32_t flags,
+ uint32_t *values);
+
+
+
+/**
+ * Request GPU access to user allocated memory e.g. via "malloc"
+ *
+ * \param dev - [in] Device handle. See #amdgpu_device_initialize()
+ * \param cpu - [in] CPU address of user allocated memory which we
+ * want to map to GPU address space (make GPU accessible)
+ * (This address must be correctly aligned).
+ * \param size - [in] Size of allocation (must be correctly aligned)
+ * \param amdgpu_bo_alloc_result - [out] Handle of allocation to be passed as resource
+ * on submission and be used in other operations.(e.g. for VA submission)
+ * ( Temporally defined amdgpu_bo_alloc_result as parameter for return mc address. )
+ *
+ *
+ * \return 0 on success
+ * >0 - AMD specific error code
+ * <0 - Negative POSIX Error code
+ *
+ *
+ * \note
+ * This call doesn't guarantee that such memory will be persistently
+ * "locked" / make non-pageable. The purpose of this call is to provide
+ * opportunity for GPU get access to this resource during submission.
+ *
+ * The maximum amount of memory which could be mapped in this call depends
+ * if overcommit is disabled or not. If overcommit is disabled than the max.
+ * amount of memory to be pinned will be limited by left "free" size in total
+ * amount of memory which could be locked simultaneously ("GART" size).
+ *
+ * Supported (theoretical) max. size of mapping is restricted only by
+ * "GART" size.
+ *
+ * It is responsibility of caller to correctly specify access rights
+ * on VA assignment.
+*/
+int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev,
+ void *cpu,
+ uint64_t size,
+ struct amdgpu_bo_alloc_result *info);
+
+
+#endif /* #ifdef _amdgpu_h_ */
+
+
diff --git a/amdgpu/amdgpu_bo.c b/amdgpu/amdgpu_bo.c
new file mode 100644
index 0000000..ce7e9d1
--- /dev/null
+++ b/amdgpu/amdgpu_bo.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright © 2014 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define _FILE_OFFSET_BITS 64
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "xf86drm.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+#include "util_hash_table.h"
+
+static void amdgpu_close_kms_handle(amdgpu_device_handle dev,
+ uint32_t handle)
+{
+ struct drm_gem_close args = {};
+
+ args.handle = handle;
+ drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &args);
+}
+
+void amdgpu_bo_free_internal(amdgpu_bo_handle bo)
+{
+ /* Remove the buffer from the hash tables. */
+ pthread_mutex_lock(&bo->dev->bo_table_mutex);
+ util_hash_table_remove(bo->dev->bo_handles,
+ (void*)(uintptr_t)bo->handle);
+ if (bo->flink_name) {
+ util_hash_table_remove(bo->dev->bo_flink_names,
+ (void*)(uintptr_t)bo->flink_name);
+ }
+ pthread_mutex_unlock(&bo->dev->bo_table_mutex);
+
+ /* Release CPU access. */
+ if (bo->cpu_map_count > 0) {
+ bo->cpu_map_count = 1;
+ amdgpu_bo_cpu_unmap(bo);
+ }
+
+ amdgpu_close_kms_handle(bo->dev, bo->handle);
+ pthread_mutex_destroy(&bo->cpu_access_mutex);
+ amdgpu_vamgr_free_va(&bo->dev->vamgr, bo->virtual_mc_base_address, bo->alloc_size);
+ free(bo);
+}
+
+int amdgpu_bo_alloc(amdgpu_device_handle dev,
+ struct amdgpu_bo_alloc_request *alloc_buffer,
+ struct amdgpu_bo_alloc_result *info)
+{
+ struct amdgpu_bo *bo;
+ union drm_amdgpu_gem_create args;
+ unsigned heap = alloc_buffer->preferred_heap;
+ int r = 0;
+
+ /* It's an error if the heap is not specified */
+ if (!(heap & (AMDGPU_GEM_DOMAIN_GTT | AMDGPU_GEM_DOMAIN_VRAM)))
+ return -EINVAL;
+
+ bo = calloc(1, sizeof(struct amdgpu_bo));
+ if (!bo)
+ return -ENOMEM;
+
+ atomic_set(&bo->refcount, 1);
+ bo->dev = dev;
+ bo->alloc_size = alloc_buffer->alloc_size;
+
+ memset(&args, 0, sizeof(args));
+ args.in.bo_size = alloc_buffer->alloc_size;
+ args.in.alignment = alloc_buffer->phys_alignment;
+
+ /* Set the placement. */
+ args.in.domains = heap & AMDGPU_GEM_DOMAIN_MASK;
+ args.in.domain_flags = alloc_buffer->flags & AMDGPU_GEM_CREATE_CPU_GTT_MASK;
+
+ /* Allocate the buffer with the preferred heap. */
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_CREATE,
+ &args, sizeof(args));
+ if (r) {
+ free(bo);
+ return r;
+ }
+
+ bo->handle = args.out.handle;
+
+ pthread_mutex_init(&bo->cpu_access_mutex, NULL);
+
+ /* map the buffer to the GPU virtual address space */
+ {
+ union drm_amdgpu_gem_va va;
+
+ memset(&va, 0, sizeof(va));
+
+ bo->virtual_mc_base_address = amdgpu_vamgr_find_va(&dev->vamgr, alloc_buffer->alloc_size, alloc_buffer->phys_alignment);
+
+ va.in.handle = bo->handle;
+ va.in.operation = AMDGPU_VA_OP_MAP;
+ va.in.flags = AMDGPU_VM_PAGE_READABLE |
+ AMDGPU_VM_PAGE_WRITEABLE |
+ AMDGPU_VM_PAGE_EXECUTABLE;
+ va.in.va_address = bo->virtual_mc_base_address;
+
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_VA, &va, sizeof(va));
+ if (r || va.out.result == AMDGPU_VA_RESULT_ERROR) {
+ amdgpu_bo_free_internal(bo);
+ return r;
+ }
+ pthread_mutex_lock(&dev->bo_table_mutex);
+
+ util_hash_table_set(dev->bo_vas,
+ (void*)(uintptr_t)bo->virtual_mc_base_address, bo);
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ }
+
+ info->buf_handle = bo;
+ info->virtual_mc_base_address = bo->virtual_mc_base_address;
+ return 0;
+}
+
+int amdgpu_bo_set_metadata(amdgpu_bo_handle bo,
+ struct amdgpu_bo_metadata *info)
+{
+ struct drm_amdgpu_gem_metadata args = {};
+
+ args.handle = bo->handle;
+ args.op = AMDGPU_GEM_METADATA_OP_SET_METADATA;
+ args.data.flags = info->flags;
+ args.data.tiling_info = info->tiling_info;
+
+ if (info->size_metadata > sizeof(args.data.data))
+ return -EINVAL;
+
+ if (info->size_metadata) {
+ args.data.data_size_bytes = info->size_metadata;
+ memcpy(args.data.data, info->umd_metadata, info->size_metadata);
+ }
+
+ return drmCommandWriteRead(bo->dev->fd,
+ DRM_AMDGPU_GEM_METADATA,
+ &args, sizeof(args));
+}
+
+int amdgpu_bo_query_info(amdgpu_bo_handle bo,
+ struct amdgpu_bo_info *info)
+{
+ struct drm_amdgpu_gem_metadata metadata = {};
+ struct drm_amdgpu_gem_create_in bo_info = {};
+ struct drm_amdgpu_gem_op gem_op = {};
+ int r;
+
+ /* Query metadata. */
+ metadata.handle = bo->handle;
+ metadata.op = AMDGPU_GEM_METADATA_OP_GET_METADATA;
+
+ r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_METADATA,
+ &metadata, sizeof(metadata));
+ if (r)
+ return r;
+
+ if (metadata.data.data_size_bytes >
+ sizeof(info->metadata.umd_metadata))
+ return -EINVAL;
+
+ /* Query buffer info. */
+ gem_op.handle = bo->handle;
+ gem_op.op = AMDGPU_GEM_OP_GET_GEM_CREATE_INFO;
+ gem_op.value = (intptr_t)&bo_info;
+
+ r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_OP,
+ &gem_op, sizeof(gem_op));
+ if (r)
+ return r;
+
+ memset(info, 0, sizeof(*info));
+ info->alloc_size = bo_info.bo_size;
+ info->phys_alignment = bo_info.alignment;
+ info->virtual_mc_base_address = bo->virtual_mc_base_address;
+ info->preferred_heap = bo_info.domains;
+ info->alloc_flags = bo_info.domain_flags;
+ info->metadata.flags = metadata.data.flags;
+ info->metadata.tiling_info = metadata.data.tiling_info;
+
+ info->metadata.size_metadata = metadata.data.data_size_bytes;
+ if (metadata.data.data_size_bytes > 0)
+ memcpy(info->metadata.umd_metadata, metadata.data.data,
+ metadata.data.data_size_bytes);
+
+ return 0;
+}
+
+static void amdgpu_add_handle_to_table(amdgpu_bo_handle bo)
+{
+ pthread_mutex_lock(&bo->dev->bo_table_mutex);
+ util_hash_table_set(bo->dev->bo_handles,
+ (void*)(uintptr_t)bo->handle, bo);
+ pthread_mutex_unlock(&bo->dev->bo_table_mutex);
+}
+
+static int amdgpu_bo_export_flink(amdgpu_bo_handle bo)
+{
+ struct drm_gem_flink flink;
+ int fd, dma_fd;
+ uint32_t handle;
+ int r;
+
+ fd = bo->dev->fd;
+ handle = bo->handle;
+ if (bo->flink_name)
+ return 0;
+
+
+ if (bo->dev->flink_fd != bo->dev->fd) {
+ r = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
+ &dma_fd);
+ if (!r) {
+ r = drmPrimeFDToHandle(bo->dev->flink_fd, dma_fd, &handle);
+ close(dma_fd);
+ }
+ if (r)
+ return r;
+ fd = bo->dev->flink_fd;
+ }
+ memset(&flink, 0, sizeof(flink));
+ flink.handle = handle;
+
+ r = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+ if (r)
+ return r;
+
+ bo->flink_name = flink.name;
+
+ if (bo->dev->flink_fd != bo->dev->fd) {
+ struct drm_gem_close args = {};
+ args.handle = handle;
+ drmIoctl(bo->dev->flink_fd, DRM_IOCTL_GEM_CLOSE, &args);
+ }
+
+ pthread_mutex_lock(&bo->dev->bo_table_mutex);
+ util_hash_table_set(bo->dev->bo_flink_names,
+ (void*)(uintptr_t)bo->flink_name,
+ bo);
+ pthread_mutex_unlock(&bo->dev->bo_table_mutex);
+
+ return 0;
+}
+
+int amdgpu_bo_export(amdgpu_bo_handle bo,
+ enum amdgpu_bo_handle_type type,
+ uint32_t *shared_handle)
+{
+ int r;
+
+ switch (type) {
+ case amdgpu_bo_handle_type_gem_flink_name:
+ r = amdgpu_bo_export_flink(bo);
+ if (r)
+ return r;
+
+ *shared_handle = bo->flink_name;
+ return 0;
+
+ case amdgpu_bo_handle_type_kms:
+ r = amdgpu_bo_export_flink(bo);
+ if (r)
+ return r;
+
+ amdgpu_add_handle_to_table(bo);
+ *shared_handle = bo->handle;
+ return 0;
+
+ case amdgpu_bo_handle_type_dma_buf_fd:
+ amdgpu_add_handle_to_table(bo);
+ return drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
+ (int*)shared_handle);
+ }
+ return -EINVAL;
+}
+
+int amdgpu_bo_import(amdgpu_device_handle dev,
+ enum amdgpu_bo_handle_type type,
+ uint32_t shared_handle,
+ struct amdgpu_bo_import_result *output)
+{
+ struct drm_gem_open open_arg = {};
+ union drm_amdgpu_gem_va va;
+ struct amdgpu_bo *bo = NULL;
+ int r;
+ int dma_fd;
+ uint64_t dma_buf_size = 0;
+
+ /* Convert a DMA buf handle to a KMS handle now. */
+ if (type == amdgpu_bo_handle_type_dma_buf_fd) {
+ uint32_t handle;
+ off_t size;
+
+ /* Get a KMS handle. */
+ r = drmPrimeFDToHandle(dev->fd, shared_handle, &handle);
+ if (r) {
+ return r;
+ }
+
+ /* Query the buffer size. */
+ size = lseek(shared_handle, 0, SEEK_END);
+ if (size == (off_t)-1) {
+ amdgpu_close_kms_handle(dev, handle);
+ return -errno;
+ }
+ lseek(shared_handle, 0, SEEK_SET);
+
+ dma_buf_size = size;
+ shared_handle = handle;
+ }
+
+ /* We must maintain a list of pairs <handle, bo>, so that we always
+ * return the same amdgpu_bo instance for the same handle. */
+ pthread_mutex_lock(&dev->bo_table_mutex);
+
+ /* If we have already created a buffer with this handle, find it. */
+ switch (type) {
+ case amdgpu_bo_handle_type_gem_flink_name:
+ bo = util_hash_table_get(dev->bo_flink_names,
+ (void*)(uintptr_t)shared_handle);
+ break;
+
+ case amdgpu_bo_handle_type_dma_buf_fd:
+ bo = util_hash_table_get(dev->bo_handles,
+ (void*)(uintptr_t)shared_handle);
+ break;
+
+ case amdgpu_bo_handle_type_kms:
+ /* Importing a KMS handle in not allowed. */
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ return -EPERM;
+
+ default:
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ return -EINVAL;
+ }
+
+ if (bo) {
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+
+ /* The buffer already exists, just bump the refcount. */
+ atomic_inc(&bo->refcount);
+
+ output->buf_handle = bo;
+ output->alloc_size = bo->alloc_size;
+ output->virtual_mc_base_address =
+ bo->virtual_mc_base_address;
+ return 0;
+ }
+
+ bo = calloc(1, sizeof(struct amdgpu_bo));
+ if (!bo) {
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ if (type == amdgpu_bo_handle_type_dma_buf_fd) {
+ amdgpu_close_kms_handle(dev, shared_handle);
+ }
+ return -ENOMEM;
+ }
+
+ /* Open the handle. */
+ switch (type) {
+ case amdgpu_bo_handle_type_gem_flink_name:
+ open_arg.name = shared_handle;
+ r = drmIoctl(dev->flink_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
+ if (r) {
+ free(bo);
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ return r;
+ }
+
+ bo->handle = open_arg.handle;
+ if (dev->flink_fd != dev->fd) {
+ r = drmPrimeHandleToFD(dev->flink_fd, bo->handle, DRM_CLOEXEC, &dma_fd);
+ if (r) {
+ free(bo);
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ return r;
+ }
+ r = drmPrimeFDToHandle(dev->fd, dma_fd, &bo->handle );
+
+ close(dma_fd);
+
+ if (r) {
+ free(bo);
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ return r;
+ }
+ }
+ bo->flink_name = shared_handle;
+ bo->alloc_size = open_arg.size;
+ util_hash_table_set(dev->bo_flink_names,
+ (void*)(uintptr_t)bo->flink_name, bo);
+ break;
+
+ case amdgpu_bo_handle_type_dma_buf_fd:
+ bo->handle = shared_handle;
+ bo->alloc_size = dma_buf_size;
+ break;
+
+ case amdgpu_bo_handle_type_kms:
+ assert(0); /* unreachable */
+ }
+
+ /* Initialize it. */
+ atomic_set(&bo->refcount, 1);
+ bo->dev = dev;
+ pthread_mutex_init(&bo->cpu_access_mutex, NULL);
+
+ bo->virtual_mc_base_address = amdgpu_vamgr_find_va(&dev->vamgr, bo->alloc_size, 1 << 20);
+
+ memset(&va, 0, sizeof(va));
+ va.in.handle = bo->handle;
+ va.in.operation = AMDGPU_VA_OP_MAP;
+ va.in.va_address = bo->virtual_mc_base_address;
+ va.in.flags = AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
+ AMDGPU_VM_PAGE_EXECUTABLE;
+
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_VA, &va, sizeof(va));
+ if (r || va.out.result == AMDGPU_VA_RESULT_ERROR) {
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+ amdgpu_vamgr_free_va(&dev->vamgr, bo->virtual_mc_base_address, bo->alloc_size);
+ amdgpu_bo_reference(&bo, NULL);
+ return r;
+ }
+
+ util_hash_table_set(dev->bo_vas,
+ (void*)(uintptr_t)bo->virtual_mc_base_address, bo);
+ util_hash_table_set(dev->bo_handles, (void*)(uintptr_t)bo->handle, bo);
+ pthread_mutex_unlock(&dev->bo_table_mutex);
+
+ output->buf_handle = bo;
+ output->alloc_size = bo->alloc_size;
+ output->virtual_mc_base_address = bo->virtual_mc_base_address;
+ return 0;
+}
+
+int amdgpu_bo_free(amdgpu_bo_handle buf_handle)
+{
+ /* Just drop the reference. */
+ amdgpu_bo_reference(&buf_handle, NULL);
+ return 0;
+}
+
+int amdgpu_bo_cpu_map(amdgpu_bo_handle bo, void **cpu)
+{
+ union drm_amdgpu_gem_mmap args;
+ void *ptr;
+ int r;
+
+ pthread_mutex_lock(&bo->cpu_access_mutex);
+
+ if (bo->cpu_ptr) {
+ /* already mapped */
+ assert(bo->cpu_map_count > 0);
+ bo->cpu_map_count++;
+ *cpu = bo->cpu_ptr;
+ pthread_mutex_unlock(&bo->cpu_access_mutex);
+ return 0;
+ }
+
+ assert(bo->cpu_map_count == 0);
+
+ memset(&args, 0, sizeof(args));
+
+ /* Query the buffer address (args.addr_ptr).
+ * The kernel driver ignores the offset and size parameters. */
+ args.in.handle = bo->handle;
+
+ r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_MMAP, &args,
+ sizeof(args));
+ if (r) {
+ pthread_mutex_unlock(&bo->cpu_access_mutex);
+ return r;
+ }
+
+ /* Map the buffer. */
+ ptr = mmap(NULL, bo->alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ bo->dev->fd, args.out.addr_ptr);
+ if (ptr == MAP_FAILED) {
+ pthread_mutex_unlock(&bo->cpu_access_mutex);
+ return -errno;
+ }
+
+ bo->cpu_ptr = ptr;
+ bo->cpu_map_count = 1;
+ pthread_mutex_unlock(&bo->cpu_access_mutex);
+
+ *cpu = ptr;
+ return 0;
+}
+
+int amdgpu_bo_cpu_unmap(amdgpu_bo_handle bo)
+{
+ int r;
+
+ pthread_mutex_lock(&bo->cpu_access_mutex);
+ assert(bo->cpu_map_count >= 0);
+
+ if (bo->cpu_map_count == 0) {
+ /* not mapped */
+ pthread_mutex_unlock(&bo->cpu_access_mutex);
+ return -EBADMSG;
+ }
+
+ bo->cpu_map_count--;
+ if (bo->cpu_map_count > 0) {
+ /* mapped multiple times */
+ pthread_mutex_unlock(&bo->cpu_access_mutex);
+ return 0;
+ }
+
+ r = munmap(bo->cpu_ptr, bo->alloc_size) == 0 ? 0 : -errno;
+ bo->cpu_ptr = NULL;
+ pthread_mutex_unlock(&bo->cpu_access_mutex);
+ return r;
+}
+
+int amdgpu_query_buffer_size_alignment(amdgpu_device_handle dev,
+ struct amdgpu_buffer_size_alignments *info)
+{
+ info->size_local = dev->dev_info.pte_fragment_size;
+ info->size_remote = dev->dev_info.gart_page_size;
+ return 0;
+}
+
+int amdgpu_bo_wait_for_idle(amdgpu_bo_handle bo,
+ uint64_t timeout_ns,
+ bool *busy)
+{
+ union drm_amdgpu_gem_wait_idle args;
+ int r;
+
+ memset(&args, 0, sizeof(args));
+ args.in.handle = bo->handle;
+ args.in.timeout = amdgpu_cs_calculate_timeout(timeout_ns);
+
+ r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_WAIT_IDLE,
+ &args, sizeof(args));
+
+ if (r == 0) {
+ *busy = args.out.status;
+ return 0;
+ } else {
+ fprintf(stderr, "amdgpu: GEM_WAIT_IDLE failed with %i\n", r);
+ return r;
+ }
+}
+
+int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev,
+ void *cpu,
+ uint64_t size,
+ struct amdgpu_bo_alloc_result *info)
+{
+ int r;
+ struct amdgpu_bo *bo;
+ struct drm_amdgpu_gem_userptr args;
+ union drm_amdgpu_gem_va va;
+
+ memset(&args, 0, sizeof(args));
+ args.addr = (uint64_t)cpu;
+ args.flags = AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_REGISTER;
+ args.size = size;
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_USERPTR,
+ &args, sizeof(args));
+ if (r)
+ return r;
+
+ bo = calloc(1, sizeof(struct amdgpu_bo));
+ if (!bo)
+ return -ENOMEM;
+
+ atomic_set(&bo->refcount, 1);
+ bo->dev = dev;
+ bo->alloc_size = size;
+ bo->handle = args.handle;
+ bo->virtual_mc_base_address = amdgpu_vamgr_find_va(&dev->vamgr, size, 4 * 1024);
+
+ memset(&va, 0, sizeof(va));
+ va.in.handle = bo->handle;
+ va.in.operation = AMDGPU_VA_OP_MAP;
+ va.in.flags = AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
+ AMDGPU_VM_PAGE_EXECUTABLE;
+ va.in.va_address = bo->virtual_mc_base_address;
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_VA, &va, sizeof(va));
+ if (r || va.out.result == AMDGPU_VA_RESULT_ERROR) {
+ amdgpu_bo_free_internal(bo);
+ return r;
+ }
+ util_hash_table_set(dev->bo_vas,
+ (void*)(uintptr_t)bo->virtual_mc_base_address, bo);
+ info->buf_handle = bo;
+ info->virtual_mc_base_address = bo->virtual_mc_base_address;
+ return r;
+}
diff --git a/amdgpu/amdgpu_cs.c b/amdgpu/amdgpu_cs.c
new file mode 100644
index 0000000..614904d
--- /dev/null
+++ b/amdgpu/amdgpu_cs.c
@@ -0,0 +1,981 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/ioctl.h>
+
+#include "xf86drm.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+
+/**
+ * Create an IB buffer.
+ *
+ * \param dev - \c [in] Device handle
+ * \param context - \c [in] GPU Context
+ * \param ib_size - \c [in] Size of allocation
+ * \param ib - \c [out] return the pointer to the created IB buffer
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_create_ib(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ enum amdgpu_cs_ib_size ib_size,
+ amdgpu_ib_handle *ib)
+{
+ struct amdgpu_bo_alloc_request alloc_buffer;
+ struct amdgpu_bo_alloc_result info;
+ int r;
+ void *cpu;
+ struct amdgpu_ib *new_ib;
+
+ memset(&alloc_buffer, 0, sizeof(alloc_buffer));
+
+ switch (ib_size) {
+ case amdgpu_cs_ib_size_4K:
+ alloc_buffer.alloc_size = 4 * 1024;
+ break;
+ case amdgpu_cs_ib_size_16K:
+ alloc_buffer.alloc_size = 16 * 1024;
+ break;
+ case amdgpu_cs_ib_size_32K:
+ alloc_buffer.alloc_size = 32 * 1024;
+ break;
+ case amdgpu_cs_ib_size_64K:
+ alloc_buffer.alloc_size = 64 * 1024;
+ break;
+ case amdgpu_cs_ib_size_128K:
+ alloc_buffer.alloc_size = 128 * 1024;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ alloc_buffer.phys_alignment = 4 * 1024;
+
+ alloc_buffer.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
+
+ r = amdgpu_bo_alloc(dev,
+ &alloc_buffer,
+ &info);
+ if (r)
+ return r;
+
+ r = amdgpu_bo_cpu_map(info.buf_handle, &cpu);
+ if (r) {
+ amdgpu_bo_free(info.buf_handle);
+ return r;
+ }
+
+ new_ib = malloc(sizeof(struct amdgpu_ib));
+ if (NULL == new_ib) {
+ amdgpu_bo_cpu_unmap(info.buf_handle);
+ amdgpu_bo_free(info.buf_handle);
+ return -ENOMEM;
+ }
+
+ new_ib->buf_handle = info.buf_handle;
+ new_ib->cpu = cpu;
+ new_ib->virtual_mc_base_address = info.virtual_mc_base_address;
+ new_ib->ib_size = ib_size;
+ *ib = new_ib;
+ return 0;
+}
+
+/**
+ * Destroy an IB buffer.
+ *
+ * \param dev - \c [in] Device handle
+ * \param ib - \c [in] the IB buffer
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_destroy_ib(amdgpu_device_handle dev,
+ amdgpu_ib_handle ib)
+{
+ int r;
+ r = amdgpu_bo_cpu_unmap(ib->buf_handle);
+ if (r)
+ return r;
+
+ r = amdgpu_bo_free(ib->buf_handle);
+ if (r)
+ return r;
+
+ free(ib);
+ return 0;
+}
+
+/**
+ * Initialize IB pools to empty.
+ *
+ * \param context - \c [in] GPU Context
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_init_ib_pool(amdgpu_context_handle context)
+{
+ int i;
+ int r;
+
+ r = pthread_mutex_init(&context->pool_mutex, NULL);
+ if (r)
+ return r;
+
+ for (i = 0; i < AMDGPU_CS_IB_SIZE_NUM; i++)
+ LIST_INITHEAD(&context->ib_pools[i]);
+
+ return 0;
+}
+
+/**
+ * Allocate an IB buffer from IB pools.
+ *
+ * \param dev - \c [in] Device handle
+ * \param context - \c [in] GPU Context
+ * \param ib_size - \c [in] Size of allocation
+ * \param ib - \c [out] return the pointer to the allocated IB buffer
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_alloc_from_ib_pool(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ enum amdgpu_cs_ib_size ib_size,
+ amdgpu_ib_handle *ib)
+{
+ int r;
+ struct list_head *head;
+ head = &context->ib_pools[ib_size];
+
+ r = -ENOMEM;
+ pthread_mutex_lock(&context->pool_mutex);
+ if (!LIST_IS_EMPTY(head)) {
+ *ib = LIST_ENTRY(struct amdgpu_ib, head->next, list_node);
+ LIST_DEL(&(*ib)->list_node);
+ r = 0;
+ }
+ pthread_mutex_unlock(&context->pool_mutex);
+
+ return r;
+}
+
+/**
+ * Free an IB buffer to IB pools.
+ *
+ * \param context - \c [in] GPU Context
+ * \param ib - \c [in] the IB buffer
+ *
+ * \return N/A
+*/
+static void amdgpu_cs_free_to_ib_pool(amdgpu_context_handle context,
+ amdgpu_ib_handle ib)
+{
+ struct list_head *head;
+ head = &context->ib_pools[ib->ib_size];
+ pthread_mutex_lock(&context->pool_mutex);
+ LIST_ADD(&ib->list_node, head);
+ pthread_mutex_unlock(&context->pool_mutex);
+ return;
+}
+
+/**
+ * Destroy all IB buffers in pools
+ *
+ * \param dev - \c [in] Device handle
+ * \param context - \c [in] GPU Context
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_destroy_ib_pool(amdgpu_device_handle dev,
+ amdgpu_context_handle context)
+{
+ int i;
+ int r;
+ struct list_head *head;
+ struct amdgpu_ib *next;
+ struct amdgpu_ib *storage;
+
+ r = 0;
+ pthread_mutex_lock(&context->pool_mutex);
+ for (i = 0; i < AMDGPU_CS_IB_SIZE_NUM; i++) {
+ head = &context->ib_pools[i];
+ LIST_FOR_EACH_ENTRY_SAFE(next, storage, head, list_node) {
+ r = amdgpu_cs_destroy_ib(dev, next);
+ if (r)
+ break;
+ }
+ }
+ pthread_mutex_unlock(&context->pool_mutex);
+ pthread_mutex_destroy(&context->pool_mutex);
+ return r;
+}
+
+/**
+ * Initialize pending IB lists
+ *
+ * \param context - \c [in] GPU Context
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_init_pendings(amdgpu_context_handle context)
+{
+ unsigned ip, inst;
+ uint32_t ring;
+ int r;
+
+ r = pthread_mutex_init(&context->pendings_mutex, NULL);
+ if (r)
+ return r;
+
+ for (ip = 0; ip < AMDGPU_HW_IP_NUM; ip++)
+ for (inst = 0; inst < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; inst++)
+ for (ring = 0; ring < AMDGPU_CS_MAX_RINGS; ring++)
+ LIST_INITHEAD(&context->pendings[ip][inst][ring]);
+
+ LIST_INITHEAD(&context->freed);
+ return 0;
+}
+
+/**
+ * Free pending IBs
+ *
+ * \param dev - \c [in] Device handle
+ * \param context - \c [in] GPU Context
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_destroy_pendings(amdgpu_device_handle dev,
+ amdgpu_context_handle context)
+{
+ int ip, inst;
+ uint32_t ring;
+ int r;
+ struct amdgpu_ib *next;
+ struct amdgpu_ib *s;
+ struct list_head *head;
+
+ r = 0;
+ pthread_mutex_lock(&context->pendings_mutex);
+ for (ip = 0; ip < AMDGPU_HW_IP_NUM; ip++)
+ for (inst = 0; inst < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; inst++)
+ for (ring = 0; ring < AMDGPU_CS_MAX_RINGS; ring++) {
+ head = &context->pendings[ip][inst][ring];
+ LIST_FOR_EACH_ENTRY_SAFE(next, s, head, list_node) {
+ r = amdgpu_cs_destroy_ib(dev, next);
+ if (r)
+ break;
+ }
+ }
+
+ head = &context->freed;
+ LIST_FOR_EACH_ENTRY_SAFE(next, s, head, list_node) {
+ r = amdgpu_cs_destroy_ib(dev, next);
+ if (r)
+ break;
+ }
+
+ pthread_mutex_unlock(&context->pendings_mutex);
+ pthread_mutex_destroy(&context->pendings_mutex);
+ return r;
+}
+
+/**
+ * Add IB to pending IB lists without holding sequence_mutex.
+ *
+ * \param context - \c [in] GPU Context
+ * \param ib - \c [in] ib to added to pending lists
+ * \param ip - \c [in] hw ip block
+ * \param ip_instance - \c [in] instance of the hw ip block
+ * \param ring - \c [in] Ring of hw ip
+ *
+ * \return N/A
+*/
+static void amdgpu_cs_add_pending(amdgpu_context_handle context,
+ amdgpu_ib_handle ib,
+ unsigned ip, unsigned ip_instance,
+ uint32_t ring)
+{
+ struct list_head *head;
+ pthread_mutex_lock(&context->pendings_mutex);
+ head = &context->pendings[ip][ip_instance][ring];
+ LIST_ADDTAIL(&ib->list_node, head);
+ pthread_mutex_unlock(&context->pendings_mutex);
+ return;
+}
+
+/**
+ * Garbage collector on a pending IB list without holding pendings_mutex.
+ * This function by itself is not multithread safe.
+ *
+ * \param context - \c [in] GPU Context
+ * \param ip - \c [in] hw ip block
+ * \param ip_instance - \c [in] instance of the hw ip block
+ * \param ring - \c [in] Ring of hw ip
+ * \param expired_fence - \c [in] fence expired
+ *
+ * \return N/A
+ * \note Hold pendings_mutex before calling this function.
+*/
+static void amdgpu_cs_pending_gc_not_safe(amdgpu_context_handle context,
+ unsigned ip, unsigned ip_instance,
+ uint32_t ring,
+ uint64_t expired_fence)
+{
+ struct list_head *head;
+ struct amdgpu_ib *next;
+ struct amdgpu_ib *s;
+ int r;
+
+ head = &context->pendings[ip][ip_instance][ring];
+ LIST_FOR_EACH_ENTRY_SAFE(next, s, head, list_node)
+ if (next->cs_handle <= expired_fence) {
+ LIST_DEL(&next->list_node);
+ amdgpu_cs_free_to_ib_pool(context, next);
+ } else {
+ /* The pending list is a sorted list.
+ There is no need to continue. */
+ break;
+ }
+
+ /* walk the freed list as well */
+ head = &context->freed;
+ LIST_FOR_EACH_ENTRY_SAFE(next, s, head, list_node) {
+ bool busy;
+
+ r = amdgpu_bo_wait_for_idle(next->buf_handle, 0, &busy);
+ if (r || busy)
+ break;
+
+ LIST_DEL(&next->list_node);
+ amdgpu_cs_free_to_ib_pool(context, next);
+ }
+
+ return;
+}
+
+/**
+ * Garbage collector on a pending IB list
+ *
+ * \param context - \c [in] GPU Context
+ * \param ip - \c [in] hw ip block
+ * \param ip_instance - \c [in] instance of the hw ip block
+ * \param ring - \c [in] Ring of hw ip
+ * \param expired_fence - \c [in] fence expired
+ *
+ * \return N/A
+*/
+static void amdgpu_cs_pending_gc(amdgpu_context_handle context,
+ unsigned ip, unsigned ip_instance,
+ uint32_t ring,
+ uint64_t expired_fence)
+{
+ pthread_mutex_lock(&context->pendings_mutex);
+ amdgpu_cs_pending_gc_not_safe(context, ip, ip_instance, ring,
+ expired_fence);
+ pthread_mutex_unlock(&context->pendings_mutex);
+ return;
+}
+
+/**
+ * Garbage collector on all pending IB lists
+ *
+ * \param context - \c [in] GPU Context
+ *
+ * \return N/A
+*/
+static void amdgpu_cs_all_pending_gc(amdgpu_context_handle context)
+{
+ unsigned ip, inst;
+ uint32_t ring;
+ uint64_t expired_fences[AMDGPU_HW_IP_NUM][AMDGPU_HW_IP_INSTANCE_MAX_COUNT][AMDGPU_CS_MAX_RINGS];
+
+ pthread_mutex_lock(&context->sequence_mutex);
+ for (ip = 0; ip < AMDGPU_HW_IP_NUM; ip++)
+ for (inst = 0; inst < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; inst++)
+ for (ring = 0; ring < AMDGPU_CS_MAX_RINGS; ring++)
+ expired_fences[ip][inst][ring] =
+ context->expired_fences[ip][inst][ring];
+ pthread_mutex_unlock(&context->sequence_mutex);
+
+ pthread_mutex_lock(&context->pendings_mutex);
+ for (ip = 0; ip < AMDGPU_HW_IP_NUM; ip++)
+ for (inst = 0; inst < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; inst++)
+ for (ring = 0; ring < AMDGPU_CS_MAX_RINGS; ring++)
+ amdgpu_cs_pending_gc_not_safe(context, ip, inst, ring,
+ expired_fences[ip][inst][ring]);
+ pthread_mutex_unlock(&context->pendings_mutex);
+}
+
+/**
+ * Allocate an IB buffer
+ * If there is no free IB buffer in pools, create one.
+ *
+ * \param dev - \c [in] Device handle
+ * \param context - \c [in] GPU Context
+ * \param ib_size - \c [in] Size of allocation
+ * \param ib - \c [out] return the pointer to the allocated IB buffer
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+static int amdgpu_cs_alloc_ib_local(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ enum amdgpu_cs_ib_size ib_size,
+ amdgpu_ib_handle *ib)
+{
+ int r;
+
+ r = amdgpu_cs_alloc_from_ib_pool(dev, context, ib_size, ib);
+ if (!r)
+ return r;
+
+ amdgpu_cs_all_pending_gc(context);
+
+ /* Retry to allocate from free IB pools after garbage collector. */
+ r = amdgpu_cs_alloc_from_ib_pool(dev, context, ib_size, ib);
+ if (!r)
+ return r;
+
+ /* There is no suitable IB in free pools. Create one. */
+ r = amdgpu_cs_create_ib(dev, context, ib_size, ib);
+ return r;
+}
+
+int amdgpu_cs_alloc_ib(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ enum amdgpu_cs_ib_size ib_size,
+ struct amdgpu_cs_ib_alloc_result *output)
+{
+ int r;
+ amdgpu_ib_handle ib;
+
+ if (NULL == dev)
+ return -EINVAL;
+ if (NULL == context)
+ return -EINVAL;
+ if (NULL == output)
+ return -EINVAL;
+ if (ib_size >= AMDGPU_CS_IB_SIZE_NUM)
+ return -EINVAL;
+
+ r = amdgpu_cs_alloc_ib_local(dev, context, ib_size, &ib);
+ if (!r) {
+ output->handle = ib;
+ output->cpu = ib->cpu;
+ output->mc_address = ib->virtual_mc_base_address;
+ }
+
+ return r;
+}
+
+int amdgpu_cs_free_ib(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ amdgpu_ib_handle handle)
+{
+ if (NULL == dev)
+ return -EINVAL;
+ if (NULL == context)
+ return -EINVAL;
+ if (NULL == handle)
+ return -EINVAL;
+
+ pthread_mutex_lock(&context->pendings_mutex);
+ LIST_ADD(&handle->list_node, &context->freed);
+ pthread_mutex_unlock(&context->pendings_mutex);
+ return 0;
+}
+
+/**
+ * Create command submission context
+ *
+ * \param dev - \c [in] amdgpu device handle
+ * \param context - \c [out] amdgpu context handle
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+int amdgpu_cs_ctx_create(amdgpu_device_handle dev,
+ amdgpu_context_handle *context)
+{
+ struct amdgpu_context *gpu_context;
+ union drm_amdgpu_ctx args;
+ int r;
+
+ if (NULL == dev)
+ return -EINVAL;
+ if (NULL == context)
+ return -EINVAL;
+
+ gpu_context = calloc(1, sizeof(struct amdgpu_context));
+ if (NULL == gpu_context)
+ return -ENOMEM;
+
+ r = pthread_mutex_init(&gpu_context->sequence_mutex, NULL);
+ if (r)
+ goto error_mutex;
+
+ r = amdgpu_cs_init_ib_pool(gpu_context);
+ if (r)
+ goto error_pool;
+
+ r = amdgpu_cs_init_pendings(gpu_context);
+ if (r)
+ goto error_pendings;
+
+ r = amdgpu_cs_alloc_ib_local(dev, gpu_context, amdgpu_cs_ib_size_4K,
+ &gpu_context->fence_ib);
+ if (r)
+ goto error_fence_ib;
+
+
+ memset(&args, 0, sizeof(args));
+ args.in.op = AMDGPU_CTX_OP_ALLOC_CTX;
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CTX, &args, sizeof(args));
+ if (r)
+ goto error_kernel;
+
+ gpu_context->id = args.out.alloc.ctx_id;
+ *context = (amdgpu_context_handle)gpu_context;
+
+ return 0;
+
+error_kernel:
+ amdgpu_cs_free_ib(dev, gpu_context, gpu_context->fence_ib);
+
+error_fence_ib:
+ amdgpu_cs_destroy_pendings(dev, gpu_context);
+
+error_pendings:
+ amdgpu_cs_destroy_ib_pool(dev, gpu_context);
+
+error_pool:
+ pthread_mutex_destroy(&gpu_context->sequence_mutex);
+
+error_mutex:
+ free(gpu_context);
+ return r;
+}
+
+/**
+ * Release command submission context
+ *
+ * \param dev - \c [in] amdgpu device handle
+ * \param context - \c [in] amdgpu context handle
+ *
+ * \return 0 on success otherwise POSIX Error code
+*/
+int amdgpu_cs_ctx_free(amdgpu_device_handle dev,
+ amdgpu_context_handle context)
+{
+ int r;
+ union drm_amdgpu_ctx args;
+
+ if (NULL == dev)
+ return -EINVAL;
+ if (NULL == context)
+ return -EINVAL;
+
+ r = amdgpu_cs_free_ib(dev, context, context->fence_ib);
+ if (r)
+ return r;
+
+ r = amdgpu_cs_destroy_pendings(dev, context);
+ if (r)
+ return r;
+
+ r = amdgpu_cs_destroy_ib_pool(dev, context);
+ if (r)
+ return r;
+
+ pthread_mutex_destroy(&context->sequence_mutex);
+
+ /* now deal with kernel side */
+ memset(&args, 0, sizeof(args));
+ args.in.op = AMDGPU_CTX_OP_FREE_CTX;
+ args.in.ctx_id = context->id;
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CTX, &args, sizeof(args));
+
+ free(context);
+
+ return r;
+}
+
+static int amdgpu_cs_create_bo_list(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ struct amdgpu_cs_request *request,
+ amdgpu_ib_handle fence_ib,
+ uint32_t *handle)
+{
+ struct drm_amdgpu_bo_list_entry *list;
+ union drm_amdgpu_bo_list args;
+ unsigned num_resources;
+ unsigned i;
+ int r;
+
+ num_resources = request->number_of_resources;
+ if (fence_ib)
+ ++num_resources;
+
+ list = alloca(sizeof(struct drm_amdgpu_bo_list_entry) * num_resources);
+
+ memset(&args, 0, sizeof(args));
+ args.in.operation = AMDGPU_BO_LIST_OP_CREATE;
+ args.in.bo_number = num_resources;
+ args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry);
+ args.in.bo_info_ptr = (uint64_t)(uintptr_t)list;
+
+ for (i = 0; i < request->number_of_resources; i++) {
+ list[i].bo_handle = request->resources[i]->handle;
+ if (request->resource_flags)
+ list[i].bo_priority = request->resource_flags[i];
+ else
+ list[i].bo_priority = 0;
+ }
+
+ if (fence_ib)
+ list[i].bo_handle = fence_ib->buf_handle->handle;
+
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST,
+ &args, sizeof(args));
+ if (r)
+ return r;
+
+ *handle = args.out.list_handle;
+ return 0;
+}
+
+static int amdgpu_cs_free_bo_list(amdgpu_device_handle dev, uint32_t handle)
+{
+ union drm_amdgpu_bo_list args;
+ int r;
+
+ memset(&args, 0, sizeof(args));
+ args.in.operation = AMDGPU_BO_LIST_OP_DESTROY;
+ args.in.list_handle = handle;
+
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST,
+ &args, sizeof(args));
+
+ return r;
+}
+
+static uint32_t amdgpu_cs_fence_index(unsigned ip, unsigned ring)
+{
+ return ip * AMDGPU_CS_MAX_RINGS + ring;
+}
+
+/**
+ * Submit command to kernel DRM
+ * \param dev - \c [in] Device handle
+ * \param context - \c [in] GPU Context
+ * \param ibs_request - \c [in] Pointer to submission requests
+ * \param fence - \c [out] return fence for this submission
+ *
+ * \return 0 on success otherwise POSIX Error code
+ * \sa amdgpu_cs_submit()
+*/
+static int amdgpu_cs_submit_one(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ struct amdgpu_cs_request *ibs_request,
+ uint64_t *fence)
+{
+ int r;
+ uint32_t i, size;
+ union drm_amdgpu_cs cs;
+ uint64_t *chunk_array;
+ struct drm_amdgpu_cs_chunk *chunks;
+ struct drm_amdgpu_cs_chunk_data *chunk_data;
+
+ if (ibs_request->ip_type >= AMDGPU_HW_IP_NUM)
+ return -EINVAL;
+ if (ibs_request->ring >= AMDGPU_CS_MAX_RINGS)
+ return -EINVAL;
+ if (ibs_request->number_of_ibs > AMDGPU_CS_MAX_IBS_PER_SUBMIT)
+ return -EINVAL;
+
+ size = (ibs_request->number_of_ibs + 1) * ((sizeof(uint64_t) +
+ sizeof(struct drm_amdgpu_cs_chunk) +
+ sizeof(struct drm_amdgpu_cs_chunk_data)) +
+ ibs_request->number_of_resources + 1) *
+ sizeof(struct drm_amdgpu_bo_list_entry);
+ chunk_array = malloc(size);
+ if (NULL == chunk_array)
+ return -ENOMEM;
+ memset(chunk_array, 0, size);
+
+ chunks = (struct drm_amdgpu_cs_chunk *)(chunk_array + ibs_request->number_of_ibs + 1);
+ chunk_data = (struct drm_amdgpu_cs_chunk_data *)(chunks + ibs_request->number_of_ibs + 1);
+
+ memset(&cs, 0, sizeof(cs));
+ cs.in.chunks = (uint64_t)(uintptr_t)chunk_array;
+ cs.in.ctx_id = context->id;
+ cs.in.num_chunks = ibs_request->number_of_ibs;
+ /* IB chunks */
+ for (i = 0; i < ibs_request->number_of_ibs; i++) {
+ struct amdgpu_cs_ib_info *ib;
+ chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i];
+ chunks[i].chunk_id = AMDGPU_CHUNK_ID_IB;
+ chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_ib) / 4;
+ chunks[i].chunk_data = (uint64_t)(uintptr_t)&chunk_data[i];
+
+ ib = &ibs_request->ibs[i];
+
+ chunk_data[i].ib_data.handle = ib->ib_handle->buf_handle->handle;
+ chunk_data[i].ib_data.va_start = ib->ib_handle->virtual_mc_base_address;
+ chunk_data[i].ib_data.ib_bytes = ib->size * 4;
+ chunk_data[i].ib_data.ip_type = ibs_request->ip_type;
+ chunk_data[i].ib_data.ip_instance = ibs_request->ip_instance;
+ chunk_data[i].ib_data.ring = ibs_request->ring;
+
+ if (ib->flags & AMDGPU_CS_GFX_IB_CE)
+ chunk_data[i].ib_data.flags = AMDGPU_IB_FLAG_CE;
+ }
+
+ r = amdgpu_cs_create_bo_list(dev, context, ibs_request, NULL,
+ &cs.in.bo_list_handle);
+ if (r)
+ goto error_unlock;
+
+ pthread_mutex_lock(&context->sequence_mutex);
+
+ if (ibs_request->ip_type != AMDGPU_HW_IP_UVD &&
+ ibs_request->ip_type != AMDGPU_HW_IP_VCE) {
+ i = cs.in.num_chunks++;
+
+ /* fence chunk */
+ chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i];
+ chunks[i].chunk_id = AMDGPU_CHUNK_ID_FENCE;
+ chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_fence) / 4;
+ chunks[i].chunk_data = (uint64_t)(uintptr_t)&chunk_data[i];
+
+ /* fence bo handle */
+ chunk_data[i].fence_data.handle = context->fence_ib->buf_handle->handle;
+ /* offset */
+ chunk_data[i].fence_data.offset = amdgpu_cs_fence_index(
+ ibs_request->ip_type, ibs_request->ring);
+ chunk_data[i].fence_data.offset *= sizeof(uint64_t);
+ }
+
+ r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CS,
+ &cs, sizeof(cs));
+ if (r)
+ goto error_unlock;
+
+
+ /* Hold sequence_mutex while adding record to the pending list.
+ So the pending list is a sorted list according to fence value. */
+
+ for (i = 0; i < ibs_request->number_of_ibs; i++) {
+ struct amdgpu_cs_ib_info *ib;
+
+ ib = &ibs_request->ibs[i];
+ if (ib->flags & AMDGPU_CS_REUSE_IB)
+ continue;
+
+ ib->ib_handle->cs_handle = cs.out.handle;
+
+ amdgpu_cs_add_pending(context, ib->ib_handle, ibs_request->ip_type,
+ ibs_request->ip_instance,
+ ibs_request->ring);
+ }
+
+ *fence = cs.out.handle;
+
+ pthread_mutex_unlock(&context->sequence_mutex);
+
+ r = amdgpu_cs_free_bo_list(dev, cs.in.bo_list_handle);
+ if (r)
+ goto error_free;
+
+ free(chunk_array);
+ return 0;
+
+error_unlock:
+ pthread_mutex_unlock(&context->sequence_mutex);
+
+error_free:
+ free(chunk_array);
+ return r;
+}
+
+int amdgpu_cs_submit(amdgpu_device_handle dev,
+ amdgpu_context_handle context,
+ uint64_t flags,
+ struct amdgpu_cs_request *ibs_request,
+ uint32_t number_of_requests,
+ uint64_t *fences)
+{
+ int r;
+ uint32_t i;
+
+ if (NULL == dev)
+ return -EINVAL;
+ if (NULL == context)
+ return -EINVAL;
+ if (NULL == ibs_request)
+ return -EINVAL;
+ if (NULL == fences)
+ return -EINVAL;
+
+ r = 0;
+ for (i = 0; i < number_of_requests; i++) {
+ r = amdgpu_cs_submit_one(dev, context, ibs_request, fences);
+ if (r)
+ break;
+ fences++;
+ ibs_request++;
+ }
+
+ return r;
+}
+
+/**
+ * Calculate absolute timeout.
+ *
+ * \param timeout - \c [in] timeout in nanoseconds.
+ *
+ * \return absolute timeout in nanoseconds
+*/
+uint64_t amdgpu_cs_calculate_timeout(uint64_t timeout)
+{
+ int r;
+
+ if (timeout != AMDGPU_TIMEOUT_INFINITE) {
+ struct timespec current;
+ r = clock_gettime(CLOCK_MONOTONIC, ¤t);
+ if (r)
+ return r;
+
+ timeout += ((uint64_t)current.tv_sec) * 1000000000ull;
+ timeout += current.tv_nsec;
+ }
+ return timeout;
+}
+
+static int amdgpu_ioctl_wait_cs(amdgpu_device_handle dev,
+ unsigned ip,
+ unsigned ip_instance,
+ uint32_t ring,
+ uint64_t handle,
+ uint64_t timeout_ns,
+ bool *busy)
+{
+ union drm_amdgpu_wait_cs args;
+ int r;
+
+ memset(&args, 0, sizeof(args));
+ args.in.handle = handle;
+ args.in.ip_type = ip;
+ args.in.ip_instance = ip_instance;
+ args.in.ring = ring;
+ args.in.timeout = amdgpu_cs_calculate_timeout(timeout_ns);
+
+ /* Handle errors manually here because of timeout */
+ r = ioctl(dev->fd, DRM_IOCTL_AMDGPU_WAIT_CS, &args);
+ if (r == -1 && (errno == EINTR || errno == EAGAIN)) {
+ *busy = true;
+ return 0;
+ } else if (r)
+ return -errno;
+
+ *busy = args.out.status;
+ return 0;
+}
+
+int amdgpu_cs_query_fence_status(amdgpu_device_handle dev,
+ struct amdgpu_cs_query_fence *fence,
+ uint32_t *expired)
+{
+ amdgpu_context_handle context;
+ uint64_t *signaled_fence;
+ uint64_t *expired_fence;
+ unsigned ip_type, ip_instance;
+ uint32_t ring;
+ bool busy = true;
+ int r;
+
+ if (NULL == dev)
+ return -EINVAL;
+ if (NULL == fence)
+ return -EINVAL;
+ if (NULL == expired)
+ return -EINVAL;
+ if (NULL == fence->context)
+ return -EINVAL;
+ if (fence->ip_type >= AMDGPU_HW_IP_NUM)
+ return -EINVAL;
+ if (fence->ring >= AMDGPU_CS_MAX_RINGS)
+ return -EINVAL;
+
+ context = fence->context;
+ ip_type = fence->ip_type;
+ ip_instance = fence->ip_instance;
+ ring = fence->ring;
+ signaled_fence = context->fence_ib->cpu;
+ signaled_fence += amdgpu_cs_fence_index(ip_type, ring);
+ expired_fence = &context->expired_fences[ip_type][ip_instance][ring];
+ *expired = false;
+
+ pthread_mutex_lock(&context->sequence_mutex);
+ if (fence->fence <= *expired_fence) {
+ /* This fence value is expired already. */
+ pthread_mutex_unlock(&context->sequence_mutex);
+ *expired = true;
+ return 0;
+ }
+
+ if (fence->fence <= *signaled_fence) {
+ /* This fence value is signaled already. */
+ *expired_fence = *signaled_fence;
+ pthread_mutex_unlock(&context->sequence_mutex);
+ amdgpu_cs_pending_gc(context, ip_type, ip_instance, ring,
+ fence->fence);
+ *expired = true;
+ return 0;
+ }
+
+ pthread_mutex_unlock(&context->sequence_mutex);
+
+ r = amdgpu_ioctl_wait_cs(dev, ip_type, ip_instance, ring,
+ fence->fence, fence->timeout_ns, &busy);
+ if (!r && !busy) {
+ *expired = true;
+ pthread_mutex_lock(&context->sequence_mutex);
+ /* The thread doesn't hold sequence_mutex. Other thread could
+ update *expired_fence already. Check whether there is a
+ newerly expired fence. */
+ if (fence->fence > *expired_fence) {
+ *expired_fence = fence->fence;
+ pthread_mutex_unlock(&context->sequence_mutex);
+ amdgpu_cs_pending_gc(context, ip_type, ip_instance,
+ ring, fence->fence);
+ } else {
+ pthread_mutex_unlock(&context->sequence_mutex);
+ }
+ }
+
+ return r;
+}
+
diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c
new file mode 100644
index 0000000..66fa187
--- /dev/null
+++ b/amdgpu/amdgpu_device.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+
+/**
+ * \file amdgpu_device.c
+ *
+ * Implementation of functions for AMD GPU device
+ *
+ *
+ */
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "xf86drm.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+#include "util_hash_table.h"
+
+#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
+#define UINT_TO_PTR(x) ((void *)((intptr_t)(x)))
+#define RENDERNODE_MINOR_MASK 0xff7f
+
+pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct util_hash_table *fd_tab;
+
+static unsigned handle_hash(void *key)
+{
+ return PTR_TO_UINT(key);
+}
+
+static int handle_compare(void *key1, void *key2)
+{
+ return PTR_TO_UINT(key1) != PTR_TO_UINT(key2);
+}
+
+static unsigned fd_hash(void *key)
+{
+ int fd = PTR_TO_UINT(key);
+ struct stat stat;
+ fstat(fd, &stat);
+
+ if (!S_ISCHR(stat.st_mode))
+ return stat.st_dev ^ stat.st_ino;
+ else
+ return stat.st_dev ^ (stat.st_rdev & RENDERNODE_MINOR_MASK);
+}
+
+static int fd_compare(void *key1, void *key2)
+{
+ int fd1 = PTR_TO_UINT(key1);
+ int fd2 = PTR_TO_UINT(key2);
+ struct stat stat1, stat2;
+ fstat(fd1, &stat1);
+ fstat(fd2, &stat2);
+
+ if (!S_ISCHR(stat1.st_mode) || !S_ISCHR(stat2.st_mode))
+ return stat1.st_dev != stat2.st_dev ||
+ stat1.st_ino != stat2.st_ino;
+ else
+ return major(stat1.st_rdev) != major(stat2.st_rdev) ||
+ (minor(stat1.st_rdev) & RENDERNODE_MINOR_MASK) !=
+ (minor(stat2.st_rdev) & RENDERNODE_MINOR_MASK);
+}
+
+/**
+* Get the authenticated form fd,
+*
+* \param fd - \c [in] File descriptor for AMD GPU device
+* \param auth - \c [out] Pointer to output the fd is authenticated or not
+* A render node fd, output auth = 0
+* A legacy fd, get the authenticated for compatibility root
+*
+* \return 0 on success\n
+* >0 - AMD specific error code\n
+* <0 - Negative POSIX Error code
+*/
+static int amdgpu_get_auth(int fd, int *auth)
+{
+ int r = 0;
+ drm_client_t client;
+ struct stat stat1;
+ fstat(fd,&stat1);
+ if (minor(stat1.st_rdev) & ~RENDERNODE_MINOR_MASK)/* find a render node fd */
+ *auth = 0;
+ else {
+ client.idx=0;
+ r= drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client);
+ if (!r)
+ *auth = client.auth;
+ }
+ return r;
+}
+
+int amdgpu_device_initialize(int fd,
+ uint32_t *major_version,
+ uint32_t *minor_version,
+ amdgpu_device_handle *device_handle)
+{
+ struct amdgpu_device *dev;
+ drmVersionPtr version;
+ int r;
+ int flag_auth = 0;
+ int flag_authexist=0;
+ uint32_t accel_working;
+
+ *device_handle = NULL;
+
+ pthread_mutex_lock(&fd_mutex);
+ if (!fd_tab)
+ fd_tab = util_hash_table_create(fd_hash, fd_compare);
+ r = amdgpu_get_auth(fd, &flag_auth);
+ if (r) {
+ pthread_mutex_unlock(&fd_mutex);
+ return r;
+ }
+ dev = util_hash_table_get(fd_tab, UINT_TO_PTR(fd));
+ if (dev) {
+ r = amdgpu_get_auth(dev->fd, &flag_authexist);
+ if (r) {
+ pthread_mutex_unlock(&fd_mutex);
+ return r;
+ }
+ if ((flag_auth) && (!flag_authexist)) {
+ dev->flink_fd = fd;
+ }
+ *major_version = dev->major_version;
+ *minor_version = dev->minor_version;
+ amdgpu_device_reference(device_handle, dev);
+ pthread_mutex_unlock(&fd_mutex);
+ return 0;
+ }
+
+ dev = calloc(1, sizeof(struct amdgpu_device));
+ if (!dev) {
+ pthread_mutex_unlock(&fd_mutex);
+ return -ENOMEM;
+ }
+
+ atomic_set(&dev->refcount, 1);
+
+ version = drmGetVersion(fd);
+ if (version->version_major != 3) {
+ fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is "
+ "only compatible with 3.x.x.\n",
+ __func__,
+ version->version_major,
+ version->version_minor,
+ version->version_patchlevel);
+ drmFreeVersion(version);
+ r = -EBADF;
+ goto cleanup;
+ }
+
+ dev->fd = fd;
+ dev->flink_fd = fd;
+ dev->major_version = version->version_major;
+ dev->minor_version = version->version_minor;
+ drmFreeVersion(version);
+
+ dev->bo_flink_names = util_hash_table_create(handle_hash,
+ handle_compare);
+ dev->bo_handles = util_hash_table_create(handle_hash, handle_compare);
+ dev->bo_vas = util_hash_table_create(handle_hash, handle_compare);
+ pthread_mutex_init(&dev->bo_table_mutex, NULL);
+
+ /* Check if acceleration is working. */
+ r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working);
+ if (r)
+ goto cleanup;
+ if (!accel_working) {
+ r = -EBADF;
+ goto cleanup;
+ }
+
+ r = amdgpu_query_gpu_info_init(dev);
+ if (r)
+ goto cleanup;
+
+ amdgpu_vamgr_init(dev);
+
+ *major_version = dev->major_version;
+ *minor_version = dev->minor_version;
+ *device_handle = dev;
+ util_hash_table_set(fd_tab, UINT_TO_PTR(fd), dev);
+ pthread_mutex_unlock(&fd_mutex);
+
+ return 0;
+
+cleanup:
+ free(dev);
+ pthread_mutex_unlock(&fd_mutex);
+ return r;
+}
+
+void amdgpu_device_free_internal(amdgpu_device_handle dev)
+{
+ util_hash_table_destroy(dev->bo_flink_names);
+ util_hash_table_destroy(dev->bo_handles);
+ util_hash_table_destroy(dev->bo_vas);
+ pthread_mutex_destroy(&dev->bo_table_mutex);
+ pthread_mutex_destroy(&(dev->vamgr.bo_va_mutex));
+ util_hash_table_remove(fd_tab, UINT_TO_PTR(dev->fd));
+ free(dev);
+}
+
+int amdgpu_device_deinitialize(amdgpu_device_handle dev)
+{
+ amdgpu_device_reference(&dev, NULL);
+ return 0;
+}
+
+void amdgpu_device_reference(struct amdgpu_device **dst,
+ struct amdgpu_device *src)
+{
+ if (update_references(&(*dst)->refcount, &src->refcount))
+ amdgpu_device_free_internal(*dst);
+ *dst = src;
+}
diff --git a/amdgpu/amdgpu_gpu_info.c b/amdgpu/amdgpu_gpu_info.c
new file mode 100644
index 0000000..0b77731
--- /dev/null
+++ b/amdgpu/amdgpu_gpu_info.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright © 2014 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "amdgpu.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+#include "xf86drm.h"
+
+int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id,
+ unsigned size, void *value)
+{
+ struct drm_amdgpu_info request;
+
+ memset(&request, 0, sizeof(request));
+ request.return_pointer = (uintptr_t)value;
+ request.return_size = size;
+ request.query = info_id;
+
+ return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request,
+ sizeof(struct drm_amdgpu_info));
+}
+
+int amdgpu_query_crtc_from_id(amdgpu_device_handle dev, unsigned id,
+ int32_t *result)
+{
+ struct drm_amdgpu_info request;
+
+ memset(&request, 0, sizeof(request));
+ request.return_pointer = (uintptr_t)result;
+ request.return_size = sizeof(*result);
+ request.query = AMDGPU_INFO_CRTC_FROM_ID;
+ request.mode_crtc.id = id;
+
+ return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request,
+ sizeof(struct drm_amdgpu_info));
+}
+
+int amdgpu_read_mm_registers(amdgpu_device_handle dev, unsigned dword_offset,
+ unsigned count, uint32_t instance, uint32_t flags,
+ uint32_t *values)
+{
+ struct drm_amdgpu_info request;
+
+ memset(&request, 0, sizeof(request));
+ request.return_pointer = (uintptr_t)values;
+ request.return_size = count * sizeof(uint32_t);
+ request.query = AMDGPU_INFO_READ_MMR_REG;
+ request.read_mmr_reg.dword_offset = dword_offset;
+ request.read_mmr_reg.count = count;
+ request.read_mmr_reg.instance = instance;
+ request.read_mmr_reg.flags = flags;
+
+ return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request,
+ sizeof(struct drm_amdgpu_info));
+}
+
+int amdgpu_query_hw_ip_count(amdgpu_device_handle dev, unsigned type,
+ uint32_t *count)
+{
+ struct drm_amdgpu_info request;
+
+ memset(&request, 0, sizeof(request));
+ request.return_pointer = (uintptr_t)count;
+ request.return_size = sizeof(*count);
+ request.query = AMDGPU_INFO_HW_IP_COUNT;
+ request.query_hw_ip.type = type;
+
+ return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request,
+ sizeof(struct drm_amdgpu_info));
+}
+
+int amdgpu_query_hw_ip_info(amdgpu_device_handle dev, unsigned type,
+ unsigned ip_instance,
+ struct drm_amdgpu_info_hw_ip *info)
+{
+ struct drm_amdgpu_info request;
+
+ memset(&request, 0, sizeof(request));
+ request.return_pointer = (uintptr_t)info;
+ request.return_size = sizeof(*info);
+ request.query = AMDGPU_INFO_HW_IP_INFO;
+ request.query_hw_ip.type = type;
+ request.query_hw_ip.ip_instance = ip_instance;
+
+ return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request,
+ sizeof(struct drm_amdgpu_info));
+}
+
+int amdgpu_query_firmware_version(amdgpu_device_handle dev, unsigned fw_type,
+ unsigned ip_instance, unsigned index,
+ uint32_t *version, uint32_t *feature)
+{
+ struct drm_amdgpu_info request;
+ struct drm_amdgpu_info_firmware firmware;
+ int r;
+
+ memset(&request, 0, sizeof(request));
+ request.return_pointer = (uintptr_t)&firmware;
+ request.return_size = sizeof(firmware);
+ request.query = AMDGPU_INFO_FW_VERSION;
+ request.query_fw.fw_type = fw_type;
+ request.query_fw.ip_instance = ip_instance;
+ request.query_fw.index = index;
+
+ r = drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request,
+ sizeof(struct drm_amdgpu_info));
+ if (r)
+ return r;
+
+ *version = firmware.ver;
+ *feature = firmware.feature;
+ return 0;
+}
+
+int amdgpu_query_gpu_info_init(amdgpu_device_handle dev)
+{
+ int r, i;
+
+ r = amdgpu_query_info(dev, AMDGPU_INFO_DEV_INFO, sizeof(dev->dev_info),
+ &dev->dev_info);
+ if (r)
+ return r;
+
+ dev->info.asic_id = dev->dev_info.device_id;
+ dev->info.chip_rev = dev->dev_info.chip_rev;
+ dev->info.chip_external_rev = dev->dev_info.external_rev;
+ dev->info.family_id = dev->dev_info.family;
+ dev->info.max_engine_clk = dev->dev_info.max_engine_clock;
+ dev->info.gpu_counter_freq = dev->dev_info.gpu_counter_freq;
+ dev->info.enabled_rb_pipes_mask = dev->dev_info.enabled_rb_pipes_mask;
+ dev->info.rb_pipes = dev->dev_info.num_rb_pipes;
+ dev->info.ids_flags = dev->dev_info.ids_flags;
+ dev->info.num_hw_gfx_contexts = dev->dev_info.num_hw_gfx_contexts;
+ dev->info.num_shader_engines = dev->dev_info.num_shader_engines;
+ dev->info.num_shader_arrays_per_engine =
+ dev->dev_info.num_shader_arrays_per_engine;
+
+ for (i = 0; i < (int)dev->info.num_shader_engines; i++) {
+ unsigned instance = (i << AMDGPU_INFO_MMR_SE_INDEX_SHIFT) |
+ (AMDGPU_INFO_MMR_SH_INDEX_MASK <<
+ AMDGPU_INFO_MMR_SH_INDEX_SHIFT);
+
+ r = amdgpu_read_mm_registers(dev, 0x263d, 1, instance, 0,
+ &dev->info.backend_disable[i]);
+ if (r)
+ return r;
+ /* extract bitfield CC_RB_BACKEND_DISABLE.BACKEND_DISABLE */
+ dev->info.backend_disable[i] =
+ (dev->info.backend_disable[i] >> 16) & 0xff;
+
+ r = amdgpu_read_mm_registers(dev, 0xa0d4, 1, instance, 0,
+ &dev->info.pa_sc_raster_cfg[i]);
+ if (r)
+ return r;
+
+ r = amdgpu_read_mm_registers(dev, 0xa0d5, 1, instance, 0,
+ &dev->info.pa_sc_raster_cfg1[i]);
+ if (r)
+ return r;
+ }
+
+ r = amdgpu_read_mm_registers(dev, 0x2644, 32, 0xffffffff, 0,
+ dev->info.gb_tile_mode);
+ if (r)
+ return r;
+
+ r = amdgpu_read_mm_registers(dev, 0x2664, 16, 0xffffffff, 0,
+ dev->info.gb_macro_tile_mode);
+ if (r)
+ return r;
+
+ r = amdgpu_read_mm_registers(dev, 0x263e, 1, 0xffffffff, 0,
+ &dev->info.gb_addr_cfg);
+ if (r)
+ return r;
+
+ r = amdgpu_read_mm_registers(dev, 0x9d8, 1, 0xffffffff, 0,
+ &dev->info.mc_arb_ramcfg);
+ if (r)
+ return r;
+
+ dev->info.cu_active_number = dev->dev_info.cu_active_number;
+ dev->info.cu_ao_mask = dev->dev_info.cu_ao_mask;
+ memcpy(&dev->info.cu_bitmap[0][0], &dev->dev_info.cu_bitmap[0][0], sizeof(dev->info.cu_bitmap));
+
+ /* TODO: info->max_quad_shader_pipes is not set */
+ /* TODO: info->avail_quad_shader_pipes is not set */
+ /* TODO: info->cache_entries_per_quad_pipe is not set */
+ /* TODO: info->active_rb_pipes is not set */
+ return 0;
+}
+
+int amdgpu_query_gpu_info(amdgpu_device_handle dev,
+ struct amdgpu_gpu_info *info)
+{
+ /* Get ASIC info*/
+ *info = dev->info;
+
+ return 0;
+}
+
+int amdgpu_query_heap_info(amdgpu_device_handle dev,
+ uint32_t heap,
+ uint32_t flags,
+ struct amdgpu_heap_info *info)
+{
+ struct drm_amdgpu_info_vram_gtt vram_gtt_info;
+ int r;
+
+ r = amdgpu_query_info(dev, AMDGPU_INFO_VRAM_GTT,
+ sizeof(vram_gtt_info), &vram_gtt_info);
+ if (r)
+ return r;
+
+ /* Get heap information */
+ switch (heap) {
+ case AMDGPU_GEM_DOMAIN_VRAM:
+ /* query visible only vram heap */
+ if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
+ info->heap_size = vram_gtt_info.vram_cpu_accessible_size;
+ else /* query total vram heap */
+ info->heap_size = vram_gtt_info.vram_size;
+
+ info->max_allocation = vram_gtt_info.vram_cpu_accessible_size;
+
+ if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
+ r = amdgpu_query_info(dev, AMDGPU_INFO_VIS_VRAM_USAGE,
+ sizeof(info->heap_usage),
+ &info->heap_usage);
+ else
+ r = amdgpu_query_info(dev, AMDGPU_INFO_VRAM_USAGE,
+ sizeof(info->heap_usage),
+ &info->heap_usage);
+ if (r)
+ return r;
+ break;
+ case AMDGPU_GEM_DOMAIN_GTT:
+ info->heap_size = vram_gtt_info.gtt_size;
+ info->max_allocation = vram_gtt_info.vram_cpu_accessible_size;
+
+ r = amdgpu_query_info(dev, AMDGPU_INFO_GTT_USAGE,
+ sizeof(info->heap_usage),
+ &info->heap_usage);
+ if (r)
+ return r;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/amdgpu/amdgpu_internal.h b/amdgpu/amdgpu_internal.h
new file mode 100644
index 0000000..b27756d
--- /dev/null
+++ b/amdgpu/amdgpu_internal.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright © 2014 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _amdgpu_internal_h_
+#define _amdgpu_internal_h_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <pthread.h>
+#include "xf86atomic.h"
+#include "amdgpu.h"
+#include "util_double_list.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define AMDGPU_CS_MAX_RINGS 8
+
+struct amdgpu_bo_va_hole {
+ struct list_head list;
+ uint64_t offset;
+ uint64_t size;
+};
+
+struct amdgpu_bo_va_mgr {
+ /* the start virtual address */
+ uint64_t va_offset;
+ struct list_head va_holes;
+ pthread_mutex_t bo_va_mutex;
+ uint32_t va_alignment;
+};
+
+struct amdgpu_device {
+ atomic_t refcount;
+ int fd;
+ int flink_fd;
+ unsigned major_version;
+ unsigned minor_version;
+
+ /** List of buffer handles. Protected by bo_table_mutex. */
+ struct util_hash_table *bo_handles;
+ /** List of buffer GEM flink names. Protected by bo_table_mutex. */
+ struct util_hash_table *bo_flink_names;
+ /** List of buffer virtual memory ranges. Protected by bo_table_mutex. */
+ struct util_hash_table *bo_vas;
+ /** This protects all hash tables. */
+ pthread_mutex_t bo_table_mutex;
+ struct amdgpu_bo_va_mgr vamgr;
+ struct drm_amdgpu_info_device dev_info;
+ struct amdgpu_gpu_info info;
+};
+
+struct amdgpu_bo {
+ atomic_t refcount;
+ struct amdgpu_device *dev;
+
+ uint64_t alloc_size;
+ uint64_t virtual_mc_base_address;
+
+ uint32_t handle;
+ uint32_t flink_name;
+
+ pthread_mutex_t cpu_access_mutex;
+ void *cpu_ptr;
+ int cpu_map_count;
+};
+
+/*
+ * There are three mutexes.
+ * To avoid deadlock, only hold the mutexes in this order:
+ * sequence_mutex -> pendings_mutex -> pool_mutex.
+*/
+struct amdgpu_context {
+ /** Mutex for accessing fences and to maintain command submissions
+ and pending lists in good sequence. */
+ pthread_mutex_t sequence_mutex;
+ /** Buffer for user fences */
+ struct amdgpu_ib *fence_ib;
+ /** The newest expired fence for the ring of the ip blocks. */
+ uint64_t expired_fences[AMDGPU_HW_IP_NUM][AMDGPU_HW_IP_INSTANCE_MAX_COUNT][AMDGPU_CS_MAX_RINGS];
+ /** Mutex for accessing pendings list. */
+ pthread_mutex_t pendings_mutex;
+ /** Pending IBs. */
+ struct list_head pendings[AMDGPU_HW_IP_NUM][AMDGPU_HW_IP_INSTANCE_MAX_COUNT][AMDGPU_CS_MAX_RINGS];
+ /** Freed IBs not yet in pool */
+ struct list_head freed;
+ /** Mutex for accessing free ib pool. */
+ pthread_mutex_t pool_mutex;
+ /** Internal free IB pools. */
+ struct list_head ib_pools[AMDGPU_CS_IB_SIZE_NUM];
+ /* context id*/
+ uint32_t id;
+};
+
+struct amdgpu_ib {
+ struct list_head list_node;
+ amdgpu_bo_handle buf_handle;
+ void *cpu;
+ uint64_t virtual_mc_base_address;
+ enum amdgpu_cs_ib_size ib_size;
+ uint64_t cs_handle;
+};
+
+/**
+ * Functions.
+ */
+
+void amdgpu_device_free_internal(amdgpu_device_handle dev);
+
+void amdgpu_bo_free_internal(amdgpu_bo_handle bo);
+
+void amdgpu_vamgr_init(struct amdgpu_device *dev);
+
+uint64_t amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr,
+ uint64_t size, uint64_t alignment);
+
+void amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va,
+ uint64_t size);
+
+int amdgpu_query_gpu_info_init(amdgpu_device_handle dev);
+
+uint64_t amdgpu_cs_calculate_timeout(uint64_t timeout);
+
+/**
+ * Inline functions.
+ */
+
+/**
+ * Increment src and decrement dst as if we were updating references
+ * for an assignment between 2 pointers of some objects.
+ *
+ * \return true if dst is 0
+ */
+static inline bool update_references(atomic_t *dst, atomic_t *src)
+{
+ if (dst != src) {
+ /* bump src first */
+ if (src) {
+ assert(atomic_read(src) > 0);
+ atomic_inc(src);
+ }
+ if (dst) {
+ assert(atomic_read(dst) > 0);
+ return atomic_dec_and_test(dst);
+ }
+ }
+ return false;
+}
+
+/**
+ * Assignment between two amdgpu_bo pointers with reference counting.
+ *
+ * Usage:
+ * struct amdgpu_bo *dst = ... , *src = ...;
+ *
+ * dst = src;
+ * // No reference counting. Only use this when you need to move
+ * // a reference from one pointer to another.
+ *
+ * amdgpu_bo_reference(&dst, src);
+ * // Reference counters are updated. dst is decremented and src is
+ * // incremented. dst is freed if its reference counter is 0.
+ */
+static inline void amdgpu_bo_reference(struct amdgpu_bo **dst,
+ struct amdgpu_bo *src)
+{
+ if (update_references(&(*dst)->refcount, &src->refcount))
+ amdgpu_bo_free_internal(*dst);
+ *dst = src;
+}
+
+/**
+ * Assignment between two amdgpu_device pointers with reference counting.
+ *
+ * Usage:
+ * struct amdgpu_device *dst = ... , *src = ...;
+ *
+ * dst = src;
+ * // No reference counting. Only use this when you need to move
+ * // a reference from one pointer to another.
+ *
+ * amdgpu_device_reference(&dst, src);
+ * // Reference counters are updated. dst is decremented and src is
+ * // incremented. dst is freed if its reference counter is 0.
+ */
+void amdgpu_device_reference(struct amdgpu_device **dst,
+ struct amdgpu_device *src);
+#endif
diff --git a/amdgpu/amdgpu_vamgr.c b/amdgpu/amdgpu_vamgr.c
new file mode 100644
index 0000000..2335912
--- /dev/null
+++ b/amdgpu/amdgpu_vamgr.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "amdgpu.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+#include "util_math.h"
+
+void amdgpu_vamgr_init(struct amdgpu_device *dev)
+{
+ struct amdgpu_bo_va_mgr *vamgr = &dev->vamgr;
+
+ vamgr->va_offset = dev->dev_info.virtual_address_offset;
+ vamgr->va_alignment = dev->dev_info.virtual_address_alignment;
+
+ list_inithead(&vamgr->va_holes);
+ pthread_mutex_init(&vamgr->bo_va_mutex, NULL);
+}
+
+uint64_t amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr,
+ uint64_t size, uint64_t alignment)
+{
+ struct amdgpu_bo_va_hole *hole, *n;
+ uint64_t offset = 0, waste = 0;
+
+ alignment = MAX2(alignment, mgr->va_alignment);
+ size = ALIGN(size, mgr->va_alignment);
+
+ pthread_mutex_lock(&mgr->bo_va_mutex);
+ /* TODO: using more appropriate way to track the holes */
+ /* first look for a hole */
+ LIST_FOR_EACH_ENTRY_SAFE(hole, n, &mgr->va_holes, list) {
+ offset = hole->offset;
+ waste = offset % alignment;
+ waste = waste ? alignment - waste : 0;
+ offset += waste;
+ if (offset >= (hole->offset + hole->size)) {
+ continue;
+ }
+ if (!waste && hole->size == size) {
+ offset = hole->offset;
+ list_del(&hole->list);
+ free(hole);
+ pthread_mutex_unlock(&mgr->bo_va_mutex);
+ return offset;
+ }
+ if ((hole->size - waste) > size) {
+ if (waste) {
+ n = calloc(1,
+ sizeof(struct amdgpu_bo_va_hole));
+ n->size = waste;
+ n->offset = hole->offset;
+ list_add(&n->list, &hole->list);
+ }
+ hole->size -= (size + waste);
+ hole->offset += size + waste;
+ pthread_mutex_unlock(&mgr->bo_va_mutex);
+ return offset;
+ }
+ if ((hole->size - waste) == size) {
+ hole->size = waste;
+ pthread_mutex_unlock(&mgr->bo_va_mutex);
+ return offset;
+ }
+ }
+
+ offset = mgr->va_offset;
+ waste = offset % alignment;
+ waste = waste ? alignment - waste : 0;
+ if (waste) {
+ n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
+ n->size = waste;
+ n->offset = offset;
+ list_add(&n->list, &mgr->va_holes);
+ }
+ offset += waste;
+ mgr->va_offset += size + waste;
+ pthread_mutex_unlock(&mgr->bo_va_mutex);
+ return offset;
+}
+
+void amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va,
+ uint64_t size)
+{
+ struct amdgpu_bo_va_hole *hole;
+
+ size = ALIGN(size, mgr->va_alignment);
+
+ pthread_mutex_lock(&mgr->bo_va_mutex);
+ if ((va + size) == mgr->va_offset) {
+ mgr->va_offset = va;
+ /* Delete uppermost hole if it reaches the new top */
+ if (!LIST_IS_EMPTY(&mgr->va_holes)) {
+ hole = container_of(mgr->va_holes.next, hole, list);
+ if ((hole->offset + hole->size) == va) {
+ mgr->va_offset = hole->offset;
+ list_del(&hole->list);
+ free(hole);
+ }
+ }
+ } else {
+ struct amdgpu_bo_va_hole *next;
+
+ hole = container_of(&mgr->va_holes, hole, list);
+ LIST_FOR_EACH_ENTRY(next, &mgr->va_holes, list) {
+ if (next->offset < va)
+ break;
+ hole = next;
+ }
+
+ if (&hole->list != &mgr->va_holes) {
+ /* Grow upper hole if it's adjacent */
+ if (hole->offset == (va + size)) {
+ hole->offset = va;
+ hole->size += size;
+ /* Merge lower hole if it's adjacent */
+ if (next != hole
+ && &next->list != &mgr->va_holes
+ && (next->offset + next->size) == va) {
+ next->size += hole->size;
+ list_del(&hole->list);
+ free(hole);
+ }
+ goto out;
+ }
+ }
+
+ /* Grow lower hole if it's adjacent */
+ if (next != hole && &next->list != &mgr->va_holes &&
+ (next->offset + next->size) == va) {
+ next->size += size;
+ goto out;
+ }
+
+ /* FIXME on allocation failure we just lose virtual address space
+ * maybe print a warning
+ */
+ next = calloc(1, sizeof(struct amdgpu_bo_va_hole));
+ if (next) {
+ next->size = size;
+ next->offset = va;
+ list_add(&next->list, &hole->list);
+ }
+ }
+out:
+ pthread_mutex_unlock(&mgr->bo_va_mutex);
+}
diff --git a/amdgpu/libdrm_amdgpu.pc.in b/amdgpu/libdrm_amdgpu.pc.in
new file mode 100644
index 0000000..417865e
--- /dev/null
+++ b/amdgpu/libdrm_amdgpu.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdrm_amdgpu
+Description: Userspace interface to kernel DRM services for amdgpu
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -ldrm_amdgpu
+Cflags: -I${includedir} -I${includedir}/libdrm
diff --git a/amdgpu/util_double_list.h b/amdgpu/util_double_list.h
new file mode 100644
index 0000000..3f48ae2
--- /dev/null
+++ b/amdgpu/util_double_list.h
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *
+ * Copyright 2006 VMware, Inc., Bismarck, ND. USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * List macros heavily inspired by the Linux kernel
+ * list handling. No list looping yet.
+ *
+ * Is not threadsafe, so common operations need to
+ * be protected using an external mutex.
+ */
+
+#ifndef _U_DOUBLE_LIST_H_
+#define _U_DOUBLE_LIST_H_
+
+
+#include <stddef.h>
+
+
+struct list_head
+{
+ struct list_head *prev;
+ struct list_head *next;
+};
+
+static inline void list_inithead(struct list_head *item)
+{
+ item->prev = item;
+ item->next = item;
+}
+
+static inline void list_add(struct list_head *item, struct list_head *list)
+{
+ item->prev = list;
+ item->next = list->next;
+ list->next->prev = item;
+ list->next = item;
+}
+
+static inline void list_addtail(struct list_head *item, struct list_head *list)
+{
+ item->next = list;
+ item->prev = list->prev;
+ list->prev->next = item;
+ list->prev = item;
+}
+
+static inline void list_replace(struct list_head *from, struct list_head *to)
+{
+ to->prev = from->prev;
+ to->next = from->next;
+ from->next->prev = to;
+ from->prev->next = to;
+}
+
+static inline void list_del(struct list_head *item)
+{
+ item->prev->next = item->next;
+ item->next->prev = item->prev;
+ item->prev = item->next = NULL;
+}
+
+static inline void list_delinit(struct list_head *item)
+{
+ item->prev->next = item->next;
+ item->next->prev = item->prev;
+ item->next = item;
+ item->prev = item;
+}
+
+#define LIST_INITHEAD(__item) list_inithead(__item)
+#define LIST_ADD(__item, __list) list_add(__item, __list)
+#define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list)
+#define LIST_REPLACE(__from, __to) list_replace(__from, __to)
+#define LIST_DEL(__item) list_del(__item)
+#define LIST_DELINIT(__item) list_delinit(__item)
+
+#define LIST_ENTRY(__type, __item, __field) \
+ ((__type *)(((char *)(__item)) - offsetof(__type, __field)))
+
+#define LIST_IS_EMPTY(__list) \
+ ((__list)->next == (__list))
+
+/**
+ * Cast from a pointer to a member of a struct back to the containing struct.
+ *
+ * 'sample' MUST be initialized, or else the result is undefined!
+ */
+#ifndef container_of
+#define container_of(ptr, sample, member) \
+ (void *)((char *)(ptr) \
+ - ((char *)&(sample)->member - (char *)(sample)))
+#endif
+
+#define LIST_FOR_EACH_ENTRY(pos, head, member) \
+ for (pos = NULL, pos = container_of((head)->next, pos, member); \
+ &pos->member != (head); \
+ pos = container_of(pos->member.next, pos, member))
+
+#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \
+ for (pos = NULL, pos = container_of((head)->next, pos, member), \
+ storage = container_of(pos->member.next, pos, member); \
+ &pos->member != (head); \
+ pos = storage, storage = container_of(storage->member.next, storage, member))
+
+#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \
+ for (pos = NULL, pos = container_of((head)->prev, pos, member), \
+ storage = container_of(pos->member.prev, pos, member); \
+ &pos->member != (head); \
+ pos = storage, storage = container_of(storage->member.prev, storage, member))
+
+#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \
+ for (pos = NULL, pos = container_of((start), pos, member); \
+ &pos->member != (head); \
+ pos = container_of(pos->member.next, pos, member))
+
+#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \
+ for (pos = NULL, pos = container_of((start), pos, member); \
+ &pos->member != (head); \
+ pos = container_of(pos->member.prev, pos, member))
+
+#endif /*_U_DOUBLE_LIST_H_*/
diff --git a/amdgpu/util_hash.c b/amdgpu/util_hash.c
new file mode 100644
index 0000000..b1e12c4
--- /dev/null
+++ b/amdgpu/util_hash.c
@@ -0,0 +1,382 @@
+/**************************************************************************
+ *
+ * Copyright 2007 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+ /*
+ * Authors:
+ * Zack Rusin <zackr@vmware.com>
+ */
+
+#include "util_hash.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define MAX(a, b) ((a > b) ? (a) : (b))
+
+static const int MinNumBits = 4;
+
+static const unsigned char prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+/* Returns the smallest integer n such that
+ primeForNumBits(n) >= hint.
+*/
+static int countBits(int hint)
+{
+ int numBits = 0;
+ int bits = hint;
+
+ while (bits > 1) {
+ bits >>= 1;
+ numBits++;
+ }
+
+ if (numBits >= (int)sizeof(prime_deltas)) {
+ numBits = sizeof(prime_deltas) - 1;
+ } else if (primeForNumBits(numBits) < hint) {
+ ++numBits;
+ }
+ return numBits;
+}
+
+struct util_node {
+ struct util_node *next;
+ unsigned key;
+ void *value;
+};
+
+struct util_hash_data {
+ struct util_node *fakeNext;
+ struct util_node **buckets;
+ int size;
+ int nodeSize;
+ short userNumBits;
+ short numBits;
+ int numBuckets;
+};
+
+struct util_hash {
+ union {
+ struct util_hash_data *d;
+ struct util_node *e;
+ } data;
+};
+
+static void *util_data_allocate_node(struct util_hash_data *hash)
+{
+ return malloc(hash->nodeSize);
+}
+
+static void util_free_node(struct util_node *node)
+{
+ free(node);
+}
+
+static struct util_node *
+util_hash_create_node(struct util_hash *hash,
+ unsigned akey, void *avalue,
+ struct util_node **anextNode)
+{
+ struct util_node *node = util_data_allocate_node(hash->data.d);
+
+ if (!node)
+ return NULL;
+
+ node->key = akey;
+ node->value = avalue;
+
+ node->next = (struct util_node*)(*anextNode);
+ *anextNode = node;
+ ++hash->data.d->size;
+ return node;
+}
+
+static void util_data_rehash(struct util_hash_data *hash, int hint)
+{
+ if (hint < 0) {
+ hint = countBits(-hint);
+ if (hint < MinNumBits)
+ hint = MinNumBits;
+ hash->userNumBits = (short)hint;
+ while (primeForNumBits(hint) < (hash->size >> 1))
+ ++hint;
+ } else if (hint < MinNumBits) {
+ hint = MinNumBits;
+ }
+
+ if (hash->numBits != hint) {
+ struct util_node *e = (struct util_node *)(hash);
+ struct util_node **oldBuckets = hash->buckets;
+ int oldNumBuckets = hash->numBuckets;
+ int i = 0;
+
+ hash->numBits = (short)hint;
+ hash->numBuckets = primeForNumBits(hint);
+ hash->buckets = malloc(sizeof(struct util_node*) * hash->numBuckets);
+ for (i = 0; i < hash->numBuckets; ++i)
+ hash->buckets[i] = e;
+
+ for (i = 0; i < oldNumBuckets; ++i) {
+ struct util_node *firstNode = oldBuckets[i];
+ while (firstNode != e) {
+ unsigned h = firstNode->key;
+ struct util_node *lastNode = firstNode;
+ struct util_node *afterLastNode;
+ struct util_node **beforeFirstNode;
+
+ while (lastNode->next != e && lastNode->next->key == h)
+ lastNode = lastNode->next;
+
+ afterLastNode = lastNode->next;
+ beforeFirstNode = &hash->buckets[h % hash->numBuckets];
+ while (*beforeFirstNode != e)
+ beforeFirstNode = &(*beforeFirstNode)->next;
+ lastNode->next = *beforeFirstNode;
+ *beforeFirstNode = firstNode;
+ firstNode = afterLastNode;
+ }
+ }
+ free(oldBuckets);
+ }
+}
+
+static void util_data_might_grow(struct util_hash_data *hash)
+{
+ if (hash->size >= hash->numBuckets)
+ util_data_rehash(hash, hash->numBits + 1);
+}
+
+static void util_data_has_shrunk(struct util_hash_data *hash)
+{
+ if (hash->size <= (hash->numBuckets >> 3) &&
+ hash->numBits > hash->userNumBits) {
+ int max = MAX(hash->numBits-2, hash->userNumBits);
+ util_data_rehash(hash, max);
+ }
+}
+
+static struct util_node *util_data_first_node(struct util_hash_data *hash)
+{
+ struct util_node *e = (struct util_node *)(hash);
+ struct util_node **bucket = hash->buckets;
+ int n = hash->numBuckets;
+ while (n--) {
+ if (*bucket != e)
+ return *bucket;
+ ++bucket;
+ }
+ return e;
+}
+
+static struct util_node **util_hash_find_node(struct util_hash *hash, unsigned akey)
+{
+ struct util_node **node;
+
+ if (hash->data.d->numBuckets) {
+ node = (struct util_node **)(&hash->data.d->buckets[akey % hash->data.d->numBuckets]);
+ assert(*node == hash->data.e || (*node)->next);
+ while (*node != hash->data.e && (*node)->key != akey)
+ node = &(*node)->next;
+ } else {
+ node = (struct util_node **)((const struct util_node * const *)(&hash->data.e));
+ }
+ return node;
+}
+
+struct util_hash_iter util_hash_insert(struct util_hash *hash,
+ unsigned key, void *data)
+{
+ util_data_might_grow(hash->data.d);
+
+ {
+ struct util_node **nextNode = util_hash_find_node(hash, key);
+ struct util_node *node = util_hash_create_node(hash, key, data, nextNode);
+ if (!node) {
+ struct util_hash_iter null_iter = {hash, 0};
+ return null_iter;
+ }
+
+ {
+ struct util_hash_iter iter = {hash, node};
+ return iter;
+ }
+ }
+}
+
+struct util_hash * util_hash_create(void)
+{
+ struct util_hash *hash = malloc(sizeof(struct util_hash));
+ if (!hash)
+ return NULL;
+
+ hash->data.d = malloc(sizeof(struct util_hash_data));
+ if (!hash->data.d) {
+ free(hash);
+ return NULL;
+ }
+
+ hash->data.d->fakeNext = 0;
+ hash->data.d->buckets = 0;
+ hash->data.d->size = 0;
+ hash->data.d->nodeSize = sizeof(struct util_node);
+ hash->data.d->userNumBits = (short)MinNumBits;
+ hash->data.d->numBits = 0;
+ hash->data.d->numBuckets = 0;
+
+ return hash;
+}
+
+void util_hash_delete(struct util_hash *hash)
+{
+ struct util_node *e_for_x = (struct util_node *)(hash->data.d);
+ struct util_node **bucket = (struct util_node **)(hash->data.d->buckets);
+ int n = hash->data.d->numBuckets;
+ while (n--) {
+ struct util_node *cur = *bucket++;
+ while (cur != e_for_x) {
+ struct util_node *next = cur->next;
+ util_free_node(cur);
+ cur = next;
+ }
+ }
+ free(hash->data.d->buckets);
+ free(hash->data.d);
+ free(hash);
+}
+
+struct util_hash_iter util_hash_find(struct util_hash *hash,
+ unsigned key)
+{
+ struct util_node **nextNode = util_hash_find_node(hash, key);
+ struct util_hash_iter iter = {hash, *nextNode};
+ return iter;
+}
+
+unsigned util_hash_iter_key(struct util_hash_iter iter)
+{
+ if (!iter.node || iter.hash->data.e == iter.node)
+ return 0;
+ return iter.node->key;
+}
+
+void * util_hash_iter_data(struct util_hash_iter iter)
+{
+ if (!iter.node || iter.hash->data.e == iter.node)
+ return 0;
+ return iter.node->value;
+}
+
+static struct util_node *util_hash_data_next(struct util_node *node)
+{
+ union {
+ struct util_node *next;
+ struct util_node *e;
+ struct util_hash_data *d;
+ } a;
+ int start;
+ struct util_node **bucket;
+ int n;
+
+ a.next = node->next;
+ if (!a.next) {
+ /* iterating beyond the last element */
+ return 0;
+ }
+ if (a.next->next)
+ return a.next;
+
+ start = (node->key % a.d->numBuckets) + 1;
+ bucket = a.d->buckets + start;
+ n = a.d->numBuckets - start;
+ while (n--) {
+ if (*bucket != a.e)
+ return *bucket;
+ ++bucket;
+ }
+ return a.e;
+}
+
+struct util_hash_iter util_hash_iter_next(struct util_hash_iter iter)
+{
+ struct util_hash_iter next = {iter.hash, util_hash_data_next(iter.node)};
+ return next;
+}
+
+int util_hash_iter_is_null(struct util_hash_iter iter)
+{
+ if (!iter.node || iter.node == iter.hash->data.e)
+ return 1;
+ return 0;
+}
+
+void * util_hash_take(struct util_hash *hash,
+ unsigned akey)
+{
+ struct util_node **node = util_hash_find_node(hash, akey);
+ if (*node != hash->data.e) {
+ void *t = (*node)->value;
+ struct util_node *next = (*node)->next;
+ util_free_node(*node);
+ *node = next;
+ --hash->data.d->size;
+ util_data_has_shrunk(hash->data.d);
+ return t;
+ }
+ return 0;
+}
+
+struct util_hash_iter util_hash_first_node(struct util_hash *hash)
+{
+ struct util_hash_iter iter = {hash, util_data_first_node(hash->data.d)};
+ return iter;
+}
+
+struct util_hash_iter util_hash_erase(struct util_hash *hash, struct util_hash_iter iter)
+{
+ struct util_hash_iter ret = iter;
+ struct util_node *node = iter.node;
+ struct util_node **node_ptr;
+
+ if (node == hash->data.e)
+ return iter;
+
+ ret = util_hash_iter_next(ret);
+ node_ptr = (struct util_node**)(&hash->data.d->buckets[node->key % hash->data.d->numBuckets]);
+ while (*node_ptr != node)
+ node_ptr = &(*node_ptr)->next;
+ *node_ptr = node->next;
+ util_free_node(node);
+ --hash->data.d->size;
+ return ret;
+}
diff --git a/amdgpu/util_hash.h b/amdgpu/util_hash.h
new file mode 100644
index 0000000..8e0f9a2
--- /dev/null
+++ b/amdgpu/util_hash.h
@@ -0,0 +1,99 @@
+/**************************************************************************
+ *
+ * Copyright 2007 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * Hash implementation.
+ *
+ * This file provides a hash implementation that is capable of dealing
+ * with collisions. It stores colliding entries in linked list. All
+ * functions operating on the hash return an iterator. The iterator
+ * itself points to the collision list. If there wasn't any collision
+ * the list will have just one entry, otherwise client code should
+ * iterate over the entries to find the exact entry among ones that
+ * had the same key (e.g. memcmp could be used on the data to check
+ * that)
+ *
+ * @author Zack Rusin <zackr@vmware.com>
+ */
+
+#ifndef UTIL_HASH_H
+#define UTIL_HASH_H
+
+#include <stdbool.h>
+
+struct util_hash;
+struct util_node;
+
+struct util_hash_iter {
+ struct util_hash *hash;
+ struct util_node *node;
+};
+
+
+struct util_hash *util_hash_create(void);
+void util_hash_delete(struct util_hash *hash);
+
+
+/**
+ * Adds a data with the given key to the hash. If entry with the given
+ * key is already in the hash, this current entry is instered before it
+ * in the collision list.
+ * Function returns iterator pointing to the inserted item in the hash.
+ */
+struct util_hash_iter util_hash_insert(struct util_hash *hash, unsigned key,
+ void *data);
+
+/**
+ * Removes the item pointed to by the current iterator from the hash.
+ * Note that the data itself is not erased and if it was a malloc'ed pointer
+ * it will have to be freed after calling this function by the callee.
+ * Function returns iterator pointing to the item after the removed one in
+ * the hash.
+ */
+struct util_hash_iter util_hash_erase(struct util_hash *hash,
+ struct util_hash_iter iter);
+
+void *util_hash_take(struct util_hash *hash, unsigned key);
+
+
+struct util_hash_iter util_hash_first_node(struct util_hash *hash);
+
+/**
+ * Return an iterator pointing to the first entry in the collision list.
+ */
+struct util_hash_iter util_hash_find(struct util_hash *hash, unsigned key);
+
+
+int util_hash_iter_is_null(struct util_hash_iter iter);
+unsigned util_hash_iter_key(struct util_hash_iter iter);
+void *util_hash_iter_data(struct util_hash_iter iter);
+
+
+struct util_hash_iter util_hash_iter_next(struct util_hash_iter iter);
+
+#endif
diff --git a/amdgpu/util_hash_table.c b/amdgpu/util_hash_table.c
new file mode 100644
index 0000000..cb7213c
--- /dev/null
+++ b/amdgpu/util_hash_table.c
@@ -0,0 +1,257 @@
+/**************************************************************************
+ *
+ * Copyright 2008 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * General purpose hash table implementation.
+ *
+ * Just uses the util_hash for now, but it might be better switch to a linear
+ * probing hash table implementation at some point -- as it is said they have
+ * better lookup and cache performance and it appears to be possible to write
+ * a lock-free implementation of such hash tables .
+ *
+ * @author José Fonseca <jfonseca@vmware.com>
+ */
+
+
+
+#include "util_hash_table.h"
+#include "util_hash.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+struct util_hash_table
+{
+ struct util_hash *head;
+
+ /** Hash function */
+ unsigned (*make_hash)(void *key);
+
+ /** Compare two keys */
+ int (*compare)(void *key1, void *key2);
+};
+
+struct util_hash_table_item
+{
+ void *key;
+ void *value;
+};
+
+
+static struct util_hash_table_item *
+util_hash_table_item(struct util_hash_iter iter)
+{
+ return (struct util_hash_table_item *)util_hash_iter_data(iter);
+}
+
+struct util_hash_table *util_hash_table_create(unsigned (*hash)(void *key),
+ int (*compare)(void *key1, void *key2))
+{
+ struct util_hash_table *ht;
+
+ ht = malloc(sizeof(struct util_hash_table));
+ if(!ht)
+ return NULL;
+
+ ht->head = util_hash_create();
+ if(!ht->head) {
+ free(ht);
+ return NULL;
+ }
+
+ ht->make_hash = hash;
+ ht->compare = compare;
+
+ return ht;
+}
+
+static struct util_hash_iter
+util_hash_table_find_iter(struct util_hash_table *ht,
+ void *key, unsigned key_hash)
+{
+ struct util_hash_iter iter;
+ struct util_hash_table_item *item;
+
+ iter = util_hash_find(ht->head, key_hash);
+ while (!util_hash_iter_is_null(iter)) {
+ item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+ if (!ht->compare(item->key, key))
+ break;
+ iter = util_hash_iter_next(iter);
+ }
+
+ return iter;
+}
+
+static struct util_hash_table_item *
+util_hash_table_find_item(struct util_hash_table *ht,
+ void *key, unsigned key_hash)
+{
+ struct util_hash_iter iter;
+ struct util_hash_table_item *item;
+
+ iter = util_hash_find(ht->head, key_hash);
+ while (!util_hash_iter_is_null(iter)) {
+ item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+ if (!ht->compare(item->key, key))
+ return item;
+ iter = util_hash_iter_next(iter);
+ }
+
+ return NULL;
+}
+
+void util_hash_table_set(struct util_hash_table *ht, void *key, void *value)
+{
+ unsigned key_hash;
+ struct util_hash_table_item *item;
+ struct util_hash_iter iter;
+
+ assert(ht);
+ if (!ht)
+ return;
+
+ key_hash = ht->make_hash(key);
+
+ item = util_hash_table_find_item(ht, key, key_hash);
+ if(item) {
+ /* TODO: key/value destruction? */
+ item->value = value;
+ return;
+ }
+
+ item = malloc(sizeof(struct util_hash_table_item));
+ if(!item)
+ return;
+
+ item->key = key;
+ item->value = value;
+
+ iter = util_hash_insert(ht->head, key_hash, item);
+ if(util_hash_iter_is_null(iter)) {
+ free(item);
+ return;
+ }
+}
+
+void *util_hash_table_get(struct util_hash_table *ht, void *key)
+{
+ unsigned key_hash;
+ struct util_hash_table_item *item;
+
+ assert(ht);
+ if (!ht)
+ return NULL;
+
+ key_hash = ht->make_hash(key);
+
+ item = util_hash_table_find_item(ht, key, key_hash);
+ if(!item)
+ return NULL;
+
+ return item->value;
+}
+
+void util_hash_table_remove(struct util_hash_table *ht, void *key)
+{
+ unsigned key_hash;
+ struct util_hash_iter iter;
+ struct util_hash_table_item *item;
+
+ assert(ht);
+ if (!ht)
+ return;
+
+ key_hash = ht->make_hash(key);
+
+ iter = util_hash_table_find_iter(ht, key, key_hash);
+ if(util_hash_iter_is_null(iter))
+ return;
+
+ item = util_hash_table_item(iter);
+ assert(item);
+ free(item);
+
+ util_hash_erase(ht->head, iter);
+}
+
+void util_hash_table_clear(struct util_hash_table *ht)
+{
+ struct util_hash_iter iter;
+ struct util_hash_table_item *item;
+
+ assert(ht);
+ if (!ht)
+ return;
+
+ iter = util_hash_first_node(ht->head);
+ while (!util_hash_iter_is_null(iter)) {
+ item = (struct util_hash_table_item *)util_hash_take(ht->head, util_hash_iter_key(iter));
+ free(item);
+ iter = util_hash_first_node(ht->head);
+ }
+}
+
+void util_hash_table_foreach(struct util_hash_table *ht,
+ void (*callback)(void *key, void *value, void *data),
+ void *data)
+{
+ struct util_hash_iter iter;
+ struct util_hash_table_item *item;
+
+ assert(ht);
+ if (!ht)
+ return;
+
+ iter = util_hash_first_node(ht->head);
+ while (!util_hash_iter_is_null(iter)) {
+ item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+ callback(item->key, item->value, data);
+ iter = util_hash_iter_next(iter);
+ }
+}
+
+void util_hash_table_destroy(struct util_hash_table *ht)
+{
+ struct util_hash_iter iter;
+ struct util_hash_table_item *item;
+
+ assert(ht);
+ if (!ht)
+ return;
+
+ iter = util_hash_first_node(ht->head);
+ while (!util_hash_iter_is_null(iter)) {
+ item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+ free(item);
+ iter = util_hash_iter_next(iter);
+ }
+
+ util_hash_delete(ht->head);
+ free(ht);
+}
diff --git a/amdgpu/util_hash_table.h b/amdgpu/util_hash_table.h
new file mode 100644
index 0000000..04fe704
--- /dev/null
+++ b/amdgpu/util_hash_table.h
@@ -0,0 +1,65 @@
+/**************************************************************************
+ *
+ * Copyright 2008 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * General purpose hash table.
+ *
+ * @author José Fonseca <jfonseca@vmware.com>
+ */
+
+#ifndef U_HASH_TABLE_H_
+#define U_HASH_TABLE_H_
+
+/**
+ * Generic purpose hash table.
+ */
+struct util_hash_table;
+
+/**
+ * Create an hash table.
+ *
+ * @param hash hash function
+ * @param compare should return 0 for two equal keys.
+ */
+struct util_hash_table *util_hash_table_create(unsigned (*hash)(void *key),
+ int (*compare)(void *key1, void *key2));
+
+void util_hash_table_set(struct util_hash_table *ht, void *key, void *value);
+
+void *util_hash_table_get(struct util_hash_table *ht, void *key);
+
+void util_hash_table_remove(struct util_hash_table *ht, void *key);
+
+void util_hash_table_clear(struct util_hash_table *ht);
+
+void util_hash_table_foreach(struct util_hash_table *ht,
+ void (*callback)(void *key, void *value, void *data),
+ void *data);
+
+void util_hash_table_destroy(struct util_hash_table *ht);
+
+#endif /* U_HASH_TABLE_H_ */
diff --git a/amdgpu/util_math.h b/amdgpu/util_math.h
new file mode 100644
index 0000000..b8de0f8
--- /dev/null
+++ b/amdgpu/util_math.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+
+#ifndef _UTIL_MATH_H_
+#define _UTIL_MATH_H_
+
+#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) )
+#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) )
+
+#define ALIGN( value, alignment ) ( ((value) + (alignment) - 1) & ~((alignment) - 1) )
+
+#endif /*_UTIL_MATH_H_*/
diff --git a/configure.ac b/configure.ac
index 155d577..509f2d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
# Check for programs
AC_PROG_CC
+AC_PROG_CXX
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
@@ -74,6 +75,11 @@ AC_ARG_ENABLE(radeon,
[Enable support for radeon's KMS API (default: auto)]),
[RADEON=$enableval], [RADEON=auto])
+AC_ARG_ENABLE(amdgpu,
+ AS_HELP_STRING([--disable-amdgpu],
+ [Enable support for amdgpu's KMS API (default: auto)]),
+ [AMDGPU=$enableval], [AMDGPU=auto])
+
AC_ARG_ENABLE(nouveau,
AS_HELP_STRING([--disable-nouveau],
[Enable support for nouveau's KMS API (default: auto)]),
@@ -236,6 +242,9 @@ if test "x$drm_cv_atomic_primitives" = "xnone"; then
LIBDRM_ATOMICS_NOT_FOUND_MSG($RADEON, radeon, Radeon, radeon)
RADEON=no
+ LIBDRM_ATOMICS_NOT_FOUND_MSG($AMDGPU, amdgpu, AMD, amdgpu)
+ AMDGPU=no
+
LIBDRM_ATOMICS_NOT_FOUND_MSG($NOUVEAU, nouveau, NVIDIA, nouveau)
NOUVEAU=no
@@ -257,6 +266,9 @@ else
if test "x$RADEON" = xauto; then
RADEON=yes
fi
+ if test "x$AMDGPU" = xauto; then
+ AMDGPU=yes
+ fi
if test "x$NOUVEAU" = xauto; then
NOUVEAU=yes
fi
@@ -336,6 +348,11 @@ if test "x$RADEON" = xyes; then
AC_DEFINE(HAVE_RADEON, 1, [Have radeon support])
fi
+AM_CONDITIONAL(HAVE_AMDGPU, [test "x$AMDGPU" = xyes])
+if test "x$AMDGPU" = xyes; then
+ AC_DEFINE(HAVE_AMDGPU, 1, [Have amdgpu support])
+fi
+
AM_CONDITIONAL(HAVE_TEGRA, [test "x$TEGRA" = xyes])
if test "x$TEGRA" = xyes; then
AC_DEFINE(HAVE_TEGRA, 1, [Have Tegra support])
@@ -432,6 +449,8 @@ AC_CONFIG_FILES([
intel/libdrm_intel.pc
radeon/Makefile
radeon/libdrm_radeon.pc
+ amdgpu/Makefile
+ amdgpu/libdrm_amdgpu.pc
nouveau/Makefile
nouveau/libdrm_nouveau.pc
omap/Makefile
@@ -463,6 +482,7 @@ echo " libkms $LIBKMS"
echo " Intel API $INTEL"
echo " vmwgfx API $VMWGFX"
echo " Radeon API $RADEON"
+echo " AMDGPU API $AMDGPU"
echo " Nouveau API $NOUVEAU"
echo " OMAP API $OMAP"
echo " EXYNOS API $EXYNOS"
diff --git a/include/drm/amdgpu_drm.h b/include/drm/amdgpu_drm.h
new file mode 100644
index 0000000..d248d77
--- /dev/null
+++ b/include/drm/amdgpu_drm.h
@@ -0,0 +1,600 @@
+/* amdgpu_drm.h -- Public header for the amdgpu driver -*- linux-c -*-
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
+ * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Kevin E. Martin <martin@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#ifndef __AMDGPU_DRM_H__
+#define __AMDGPU_DRM_H__
+
+#include <drm.h>
+
+#define DRM_AMDGPU_GEM_CREATE 0x00
+#define DRM_AMDGPU_GEM_MMAP 0x01
+#define DRM_AMDGPU_CTX 0x02
+#define DRM_AMDGPU_BO_LIST 0x03
+#define DRM_AMDGPU_CS 0x04
+#define DRM_AMDGPU_INFO 0x05
+#define DRM_AMDGPU_GEM_METADATA 0x06
+#define DRM_AMDGPU_GEM_WAIT_IDLE 0x07
+#define DRM_AMDGPU_GEM_VA 0x08
+#define DRM_AMDGPU_WAIT_CS 0x09
+#define DRM_AMDGPU_GEM_OP 0x10
+#define DRM_AMDGPU_GEM_USERPTR 0x11
+
+#define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create)
+#define DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap)
+#define DRM_IOCTL_AMDGPU_CTX DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CTX, union drm_amdgpu_ctx)
+#define DRM_IOCTL_AMDGPU_BO_LIST DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_BO_LIST, union drm_amdgpu_bo_list)
+#define DRM_IOCTL_AMDGPU_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CS, union drm_amdgpu_cs)
+#define DRM_IOCTL_AMDGPU_INFO DRM_IOW(DRM_COMMAND_BASE + DRM_AMDGPU_INFO, struct drm_amdgpu_info)
+#define DRM_IOCTL_AMDGPU_GEM_METADATA DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_METADATA, struct drm_amdgpu_gem_metadata)
+#define DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_WAIT_IDLE, union drm_amdgpu_gem_wait_idle)
+#define DRM_IOCTL_AMDGPU_GEM_VA DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_VA, union drm_amdgpu_gem_va)
+#define DRM_IOCTL_AMDGPU_WAIT_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_WAIT_CS, union drm_amdgpu_wait_cs)
+#define DRM_IOCTL_AMDGPU_GEM_OP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_OP, struct drm_amdgpu_gem_op)
+#define DRM_IOCTL_AMDGPU_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_USERPTR, struct drm_amdgpu_gem_userptr)
+
+#define AMDGPU_GEM_DOMAIN_CPU 0x1
+#define AMDGPU_GEM_DOMAIN_GTT 0x2
+#define AMDGPU_GEM_DOMAIN_VRAM 0x4
+#define AMDGPU_GEM_DOMAIN_GDS 0x8
+#define AMDGPU_GEM_DOMAIN_GWS 0x10
+#define AMDGPU_GEM_DOMAIN_OA 0x20
+
+#define AMDGPU_GEM_DOMAIN_MASK 0x3F
+
+/* Flag that CPU access will be required for the case of VRAM domain */
+#define AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED (1 << 0)
+/* Flag that CPU access will not work, this VRAM domain is invisible */
+#define AMDGPU_GEM_CREATE_NO_CPU_ACCESS (1 << 1)
+/* Flag that un-cached attributes should be used for GTT */
+#define AMDGPU_GEM_CREATE_CPU_GTT_UC (1 << 2)
+/* Flag that USWC attributes should be used for GTT */
+#define AMDGPU_GEM_CREATE_CPU_GTT_WC (1 << 3)
+
+/* Flag mask for GTT domain_flags */
+#define AMDGPU_GEM_CREATE_CPU_GTT_MASK \
+ (AMDGPU_GEM_CREATE_CPU_GTT_WC | \
+ AMDGPU_GEM_CREATE_CPU_GTT_UC | \
+ AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | \
+ AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
+
+struct drm_amdgpu_gem_create_in {
+ /** the requested memory size */
+ uint64_t bo_size;
+ /** physical start_addr alignment in bytes for some HW requirements */
+ uint64_t alignment;
+ /** the requested memory domains */
+ uint64_t domains;
+ /** allocation flags */
+ uint64_t domain_flags;
+};
+
+struct drm_amdgpu_gem_create_out {
+ /** returned GEM object handle */
+ uint32_t handle;
+};
+
+union drm_amdgpu_gem_create {
+ struct drm_amdgpu_gem_create_in in;
+ struct drm_amdgpu_gem_create_out out;
+};
+
+/** Opcode to create new residency list. */
+#define AMDGPU_BO_LIST_OP_CREATE 0
+/** Opcode to destroy previously created residency list */
+#define AMDGPU_BO_LIST_OP_DESTROY 1
+/** Opcode to update resource information in the list */
+#define AMDGPU_BO_LIST_OP_UPDATE 2
+
+struct drm_amdgpu_bo_list_in {
+ /** Type of operation */
+ uint32_t operation;
+ /** Handle of list or 0 if we want to create one */
+ uint32_t list_handle;
+ /** Number of BOs in list */
+ uint32_t bo_number;
+ /** Size of each element describing BO */
+ uint32_t bo_info_size;
+ /** Pointer to array describing BOs */
+ uint64_t bo_info_ptr;
+};
+
+struct drm_amdgpu_bo_list_entry {
+ /** Handle of BO */
+ uint32_t bo_handle;
+ /** New (if specified) BO priority to be used during migration */
+ uint32_t bo_priority;
+};
+
+struct drm_amdgpu_bo_list_out {
+ /** Handle of resource list */
+ uint32_t list_handle;
+};
+
+union drm_amdgpu_bo_list {
+ struct drm_amdgpu_bo_list_in in;
+ struct drm_amdgpu_bo_list_out out;
+};
+
+/* context related */
+#define AMDGPU_CTX_OP_ALLOC_CTX 1
+#define AMDGPU_CTX_OP_FREE_CTX 2
+#define AMDGPU_CTX_OP_QUERY_STATE 3
+
+#define AMDGPU_CTX_OP_STATE_RUNNING 1
+
+struct drm_amdgpu_ctx_in {
+ uint32_t op;
+ uint32_t flags;
+ uint32_t ctx_id;
+ uint32_t pad;
+};
+
+union drm_amdgpu_ctx_out {
+ struct {
+ uint32_t ctx_id;
+ } alloc;
+
+ struct {
+ uint64_t flags;
+ uint64_t hangs;
+ } state;
+};
+
+union drm_amdgpu_ctx {
+ struct drm_amdgpu_ctx_in in;
+ union drm_amdgpu_ctx_out out;
+};
+
+/*
+ * This is not a reliable API and you should expect it to fail for any
+ * number of reasons and have fallback path that do not use userptr to
+ * perform any operation.
+ */
+#define AMDGPU_GEM_USERPTR_READONLY (1 << 0)
+#define AMDGPU_GEM_USERPTR_ANONONLY (1 << 1)
+#define AMDGPU_GEM_USERPTR_VALIDATE (1 << 2)
+#define AMDGPU_GEM_USERPTR_REGISTER (1 << 3)
+
+struct drm_amdgpu_gem_userptr {
+ uint64_t addr;
+ uint64_t size;
+ uint32_t flags;
+ uint32_t handle;
+};
+
+#define AMDGPU_TILING_MACRO 0x1
+#define AMDGPU_TILING_MICRO 0x2
+#define AMDGPU_TILING_SWAP_16BIT 0x4
+#define AMDGPU_TILING_R600_NO_SCANOUT AMDGPU_TILING_SWAP_16BIT
+#define AMDGPU_TILING_SWAP_32BIT 0x8
+/* this object requires a surface when mapped - i.e. front buffer */
+#define AMDGPU_TILING_SURFACE 0x10
+#define AMDGPU_TILING_MICRO_SQUARE 0x20
+#define AMDGPU_TILING_EG_BANKW_SHIFT 8
+#define AMDGPU_TILING_EG_BANKW_MASK 0xf
+#define AMDGPU_TILING_EG_BANKH_SHIFT 12
+#define AMDGPU_TILING_EG_BANKH_MASK 0xf
+#define AMDGPU_TILING_EG_MACRO_TILE_ASPECT_SHIFT 16
+#define AMDGPU_TILING_EG_MACRO_TILE_ASPECT_MASK 0xf
+#define AMDGPU_TILING_EG_TILE_SPLIT_SHIFT 24
+#define AMDGPU_TILING_EG_TILE_SPLIT_MASK 0xf
+#define AMDGPU_TILING_EG_STENCIL_TILE_SPLIT_SHIFT 28
+#define AMDGPU_TILING_EG_STENCIL_TILE_SPLIT_MASK 0xf
+
+#define AMDGPU_GEM_METADATA_OP_SET_METADATA 1
+#define AMDGPU_GEM_METADATA_OP_GET_METADATA 2
+
+/** The same structure is shared for input/output */
+struct drm_amdgpu_gem_metadata {
+ uint32_t handle; /* GEM Object handle */
+ uint32_t op; /** Do we want get or set metadata */
+ struct {
+ uint64_t flags;
+ uint64_t tiling_info; /* family specific tiling info */
+ uint32_t data_size_bytes;
+ uint32_t data[64];
+ } data;
+};
+
+struct drm_amdgpu_gem_mmap_in {
+ uint32_t handle; /** the GEM object handle */
+};
+
+struct drm_amdgpu_gem_mmap_out {
+ uint64_t addr_ptr; /** mmap offset from the vma offset manager */
+};
+
+union drm_amdgpu_gem_mmap {
+ struct drm_amdgpu_gem_mmap_in in;
+ struct drm_amdgpu_gem_mmap_out out;
+};
+
+struct drm_amdgpu_gem_wait_idle_in {
+ uint32_t handle; /* GEM object handle */
+ uint32_t flags;
+ uint64_t timeout; /* Timeout to wait. If 0 then returned immediately with the status */
+};
+
+struct drm_amdgpu_gem_wait_idle_out {
+ uint32_t status; /* BO status: 0 - BO is idle, 1 - BO is busy */
+ uint32_t domain; /* Returned current memory domain */
+};
+
+union drm_amdgpu_gem_wait_idle {
+ struct drm_amdgpu_gem_wait_idle_in in;
+ struct drm_amdgpu_gem_wait_idle_out out;
+};
+
+struct drm_amdgpu_wait_cs_in {
+ uint64_t handle;
+ uint64_t timeout;
+ uint32_t ip_type;
+ uint32_t ip_instance;
+ uint32_t ring;
+};
+
+struct drm_amdgpu_wait_cs_out {
+ uint64_t status;
+};
+
+union drm_amdgpu_wait_cs {
+ struct drm_amdgpu_wait_cs_in in;
+ struct drm_amdgpu_wait_cs_out out;
+};
+
+/* Sets or returns a value associated with a buffer. */
+struct drm_amdgpu_gem_op {
+ uint32_t handle; /* buffer */
+ uint32_t op; /* AMDGPU_GEM_OP_* */
+ uint64_t value; /* input or return value */
+};
+
+#define AMDGPU_GEM_OP_GET_GEM_CREATE_INFO 0
+#define AMDGPU_GEM_OP_SET_INITIAL_DOMAIN 1
+
+#define AMDGPU_VA_OP_MAP 1
+#define AMDGPU_VA_OP_UNMAP 2
+
+#define AMDGPU_VA_RESULT_OK 0
+#define AMDGPU_VA_RESULT_ERROR 1
+#define AMDGPU_VA_RESULT_VA_INVALID_ALIGNMENT 2
+
+/* Mapping flags */
+/* readable mapping */
+#define AMDGPU_VM_PAGE_READABLE (1 << 1)
+/* writable mapping */
+#define AMDGPU_VM_PAGE_WRITEABLE (1 << 2)
+/* executable mapping, new for VI */
+#define AMDGPU_VM_PAGE_EXECUTABLE (1 << 3)
+
+struct drm_amdgpu_gem_va_in {
+ /* GEM object handle */
+ uint32_t handle;
+ uint32_t pad;
+ /* map or unmap*/
+ uint32_t operation;
+ /* specify mapping flags */
+ uint32_t flags;
+ /* va address to assign . Must be correctly aligned.*/
+ uint64_t va_address;
+ /* Specify offset inside of BO to assign. Must be correctly aligned.*/
+ uint64_t offset_in_bo;
+ /* Specify mapping size. If 0 and offset is 0 then map the whole BO.*/
+ /* Must be correctly aligned. */
+ uint64_t map_size;
+};
+
+struct drm_amdgpu_gem_va_out {
+ uint32_t result;
+};
+
+union drm_amdgpu_gem_va {
+ struct drm_amdgpu_gem_va_in in;
+ struct drm_amdgpu_gem_va_out out;
+};
+
+#define AMDGPU_HW_IP_GFX 0
+#define AMDGPU_HW_IP_COMPUTE 1
+#define AMDGPU_HW_IP_DMA 2
+#define AMDGPU_HW_IP_UVD 3
+#define AMDGPU_HW_IP_VCE 4
+#define AMDGPU_HW_IP_NUM 5
+
+#define AMDGPU_HW_IP_INSTANCE_MAX_COUNT 1
+
+#define AMDGPU_CHUNK_ID_IB 0x01
+#define AMDGPU_CHUNK_ID_FENCE 0x02
+struct drm_amdgpu_cs_chunk {
+ uint32_t chunk_id;
+ uint32_t length_dw;
+ uint64_t chunk_data;
+};
+
+struct drm_amdgpu_cs_in {
+ /** Rendering context id */
+ uint32_t ctx_id;
+ /** Handle of resource list associated with CS */
+ uint32_t bo_list_handle;
+ uint32_t num_chunks;
+ uint32_t pad;
+ /* this points to uint64_t * which point to cs chunks */
+ uint64_t chunks;
+};
+
+struct drm_amdgpu_cs_out {
+ uint64_t handle;
+};
+
+union drm_amdgpu_cs {
+ struct drm_amdgpu_cs_in in;
+ struct drm_amdgpu_cs_out out;
+};
+
+/* Specify flags to be used for IB */
+
+/* This IB should be submitted to CE */
+#define AMDGPU_IB_FLAG_CE (1<<0)
+
+/* GDS is used by this IB */
+#define AMDGPU_IB_FLAG_GDS (1<<1)
+
+struct drm_amdgpu_cs_chunk_ib {
+ /**
+ * Handle of GEM object to be used as IB or 0 if it is already in
+ * residency list.
+ */
+ uint32_t handle;
+ uint32_t flags; /* IB Flags */
+ uint64_t va_start; /* Virtual address to begin IB execution */
+ uint32_t ib_bytes; /* Size of submission */
+ uint32_t ip_type; /* HW IP to submit to */
+ uint32_t ip_instance; /* HW IP index of the same type to submit to */
+ uint32_t ring; /* Ring index to submit to */
+};
+
+struct drm_amdgpu_cs_chunk_fence {
+ uint32_t handle;
+ uint32_t offset;
+};
+
+struct drm_amdgpu_cs_chunk_data {
+ union {
+ struct drm_amdgpu_cs_chunk_ib ib_data;
+ struct drm_amdgpu_cs_chunk_fence fence_data;
+ };
+};
+
+/**
+ * Query h/w info: Flag that this is integrated (a.h.a. fusion) GPU
+ *
+ */
+#define AMDGPU_IDS_FLAGS_FUSION 0x1
+
+/* indicate if acceleration can be working */
+#define AMDGPU_INFO_ACCEL_WORKING 0x00
+/* get the crtc_id from the mode object id? */
+#define AMDGPU_INFO_CRTC_FROM_ID 0x01
+/* query hw IP info */
+#define AMDGPU_INFO_HW_IP_INFO 0x02
+/* query hw IP instance count for the specified type */
+#define AMDGPU_INFO_HW_IP_COUNT 0x03
+/* timestamp for GL_ARB_timer_query */
+#define AMDGPU_INFO_TIMESTAMP 0x05
+/* Query the firmware version */
+#define AMDGPU_INFO_FW_VERSION 0x0e
+ /* Subquery id: Query VCE firmware version */
+ #define AMDGPU_INFO_FW_VCE 0x1
+ /* Subquery id: Query UVD firmware version */
+ #define AMDGPU_INFO_FW_UVD 0x2
+ /* Subquery id: Query GMC firmware version */
+ #define AMDGPU_INFO_FW_GMC 0x03
+ /* Subquery id: Query GFX ME firmware version */
+ #define AMDGPU_INFO_FW_GFX_ME 0x04
+ /* Subquery id: Query GFX PFP firmware version */
+ #define AMDGPU_INFO_FW_GFX_PFP 0x05
+ /* Subquery id: Query GFX CE firmware version */
+ #define AMDGPU_INFO_FW_GFX_CE 0x06
+ /* Subquery id: Query GFX RLC firmware version */
+ #define AMDGPU_INFO_FW_GFX_RLC 0x07
+ /* Subquery id: Query GFX MEC firmware version */
+ #define AMDGPU_INFO_FW_GFX_MEC 0x08
+ /* Subquery id: Query SMC firmware version */
+ #define AMDGPU_INFO_FW_SMC 0x0a
+ /* Subquery id: Query SDMA firmware version */
+ #define AMDGPU_INFO_FW_SDMA 0x0b
+/* number of bytes moved for TTM migration */
+#define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f
+/* the used VRAM size */
+#define AMDGPU_INFO_VRAM_USAGE 0x10
+/* the used GTT size */
+#define AMDGPU_INFO_GTT_USAGE 0x11
+/* Information about GDS, etc. resource configuration */
+#define AMDGPU_INFO_GDS_CONFIG 0x13
+/* Query information about VRAM and GTT domains */
+#define AMDGPU_INFO_VRAM_GTT 0x14
+/* Query information about register in MMR address space*/
+#define AMDGPU_INFO_READ_MMR_REG 0x15
+/* Query information about device: rev id, family, etc. */
+#define AMDGPU_INFO_DEV_INFO 0x16
+/* visible vram usage */
+#define AMDGPU_INFO_VIS_VRAM_USAGE 0x17
+
+#define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0
+#define AMDGPU_INFO_MMR_SE_INDEX_MASK 0xff
+#define AMDGPU_INFO_MMR_SH_INDEX_SHIFT 8
+#define AMDGPU_INFO_MMR_SH_INDEX_MASK 0xff
+
+/* Input structure for the INFO ioctl */
+struct drm_amdgpu_info {
+ /* Where the return value will be stored */
+ uint64_t return_pointer;
+ /* The size of the return value. Just like "size" in "snprintf",
+ * it limits how many bytes the kernel can write. */
+ uint32_t return_size;
+ /* The query request id. */
+ uint32_t query;
+
+ union {
+ struct {
+ uint32_t id;
+ } mode_crtc;
+
+ struct {
+ /** AMDGPU_HW_IP_* */
+ uint32_t type;
+ /**
+ * Index of the IP if there are more IPs of the same type.
+ * Ignored by AMDGPU_INFO_HW_IP_COUNT.
+ */
+ uint32_t ip_instance;
+ } query_hw_ip;
+
+ struct {
+ uint32_t dword_offset;
+ uint32_t count; /* number of registers to read */
+ uint32_t instance;
+ uint32_t flags;
+ } read_mmr_reg;
+
+ struct {
+ /** AMDGPU_INFO_FW_* */
+ uint32_t fw_type;
+ /** Index of the IP if there are more IPs of the same type. */
+ uint32_t ip_instance;
+ /**
+ * Index of the engine. Whether this is used depends
+ * on the firmware type. (e.g. MEC, SDMA)
+ */
+ uint32_t index;
+ } query_fw;
+ };
+};
+
+struct drm_amdgpu_info_gds {
+ /** GDS GFX partition size */
+ uint32_t gds_gfx_partition_size;
+ /** GDS compute partition size */
+ uint32_t compute_partition_size;
+ /** total GDS memory size */
+ uint32_t gds_total_size;
+ /** GWS size per GFX partition */
+ uint32_t gws_per_gfx_partition;
+ /** GSW size per compute partition */
+ uint32_t gws_per_compute_partition;
+ /** OA size per GFX partition */
+ uint32_t oa_per_gfx_partition;
+ /** OA size per compute partition */
+ uint32_t oa_per_compute_partition;
+};
+
+struct drm_amdgpu_info_vram_gtt {
+ uint64_t vram_size;
+ uint64_t vram_cpu_accessible_size;
+ uint64_t gtt_size;
+};
+
+struct drm_amdgpu_info_firmware {
+ uint32_t ver;
+ uint32_t feature;
+};
+
+struct drm_amdgpu_info_device {
+ /** PCI Device ID */
+ uint32_t device_id;
+ /** Internal chip revision: A0, A1, etc.) */
+ uint32_t chip_rev;
+ uint32_t external_rev;
+ /** Revision id in PCI Config space */
+ uint32_t pci_rev;
+ uint32_t family;
+ uint32_t num_shader_engines;
+ uint32_t num_shader_arrays_per_engine;
+ uint32_t gpu_counter_freq; /* in KHz */
+ uint64_t max_engine_clock; /* in KHz */
+ /* cu information */
+ uint32_t cu_active_number;
+ uint32_t cu_ao_mask;
+ uint32_t cu_bitmap[4][4];
+ /** Render backend pipe mask. One render backend is CB+DB. */
+ uint32_t enabled_rb_pipes_mask;
+ uint32_t num_rb_pipes;
+ uint32_t num_hw_gfx_contexts;
+ uint32_t _pad;
+ uint64_t ids_flags;
+ /** Starting virtual address for UMDs. */
+ uint64_t virtual_address_offset;
+ /** Required alignment of virtual addresses. */
+ uint32_t virtual_address_alignment;
+ /** Page table entry - fragment size */
+ uint32_t pte_fragment_size;
+ uint32_t gart_page_size;
+};
+
+struct drm_amdgpu_info_hw_ip {
+ /** Version of h/w IP */
+ uint32_t hw_ip_version_major;
+ uint32_t hw_ip_version_minor;
+ /** Capabilities */
+ uint64_t capabilities_flags;
+ /** Bitmask of available rings. Bit 0 means ring 0, etc. */
+ uint32_t available_rings;
+};
+
+/* Those correspond to the tile index to use, this is to explicitly state
+ * the API that is implicitly defined by the tile mode array.
+ */
+#define SI_TILE_MODE_COLOR_LINEAR_ALIGNED 8
+#define SI_TILE_MODE_COLOR_1D 13
+#define SI_TILE_MODE_COLOR_1D_SCANOUT 9
+#define SI_TILE_MODE_COLOR_2D_8BPP 14
+#define SI_TILE_MODE_COLOR_2D_16BPP 15
+#define SI_TILE_MODE_COLOR_2D_32BPP 16
+#define SI_TILE_MODE_COLOR_2D_64BPP 17
+#define SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP 11
+#define SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP 12
+#define SI_TILE_MODE_DEPTH_STENCIL_1D 4
+#define SI_TILE_MODE_DEPTH_STENCIL_2D 0
+#define SI_TILE_MODE_DEPTH_STENCIL_2D_2AA 3
+#define SI_TILE_MODE_DEPTH_STENCIL_2D_4AA 3
+#define SI_TILE_MODE_DEPTH_STENCIL_2D_8AA 2
+
+#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5
+
+/*
+ * Supported GPU families
+ */
+#define AMDGPU_FAMILY_UNKNOWN 0
+#define AMDGPU_FAMILY_CI 120 /* Bonaire, Hawaii */
+#define AMDGPU_FAMILY_KV 125 /* Kaveri, Kabini, Mullins */
+#define AMDGPU_FAMILY_VI 130 /* Iceland, Tonga */
+#define AMDGPU_FAMILY_CZ 135 /* Carrizo */
+
+#endif
--
1.8.3.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] drm: add tests/amdgpu
2015-04-21 16:39 [PATCH 1/2] drm: add libdrm_amdgpu Alex Deucher
@ 2015-04-21 16:39 ` Alex Deucher
2015-04-23 16:23 ` [PATCH 1/2] drm: add libdrm_amdgpu Emil Velikov
1 sibling, 0 replies; 3+ messages in thread
From: Alex Deucher @ 2015-04-21 16:39 UTC (permalink / raw)
To: dri-devel; +Cc: Alex Deucher
This adds some basic unit tests for the new amdgpu driver.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
configure.ac | 23 ++
tests/Makefile.am | 6 +
tests/amdgpu/Makefile.am | 24 ++
tests/amdgpu/amdgpu_test.c | 241 +++++++++++++
tests/amdgpu/amdgpu_test.h | 119 +++++++
tests/amdgpu/basic_tests.c | 676 ++++++++++++++++++++++++++++++++++++
tests/amdgpu/bo_tests.c | 151 ++++++++
tests/amdgpu/cs_tests.c | 319 +++++++++++++++++
tests/amdgpu/uvd_messages.h | 813 ++++++++++++++++++++++++++++++++++++++++++++
tests/kmstest/main.c | 1 +
10 files changed, 2373 insertions(+)
create mode 100644 tests/amdgpu/Makefile.am
create mode 100644 tests/amdgpu/amdgpu_test.c
create mode 100644 tests/amdgpu/amdgpu_test.h
create mode 100644 tests/amdgpu/basic_tests.c
create mode 100644 tests/amdgpu/bo_tests.c
create mode 100644 tests/amdgpu/cs_tests.c
create mode 100644 tests/amdgpu/uvd_messages.h
diff --git a/configure.ac b/configure.ac
index 509f2d4..0019f73 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,6 +351,28 @@ fi
AM_CONDITIONAL(HAVE_AMDGPU, [test "x$AMDGPU" = xyes])
if test "x$AMDGPU" = xyes; then
AC_DEFINE(HAVE_AMDGPU, 1, [Have amdgpu support])
+
+ # Detect cunit library
+ PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
+
+ # If pkg-config does not find cunit, check it using AC_CHECK_LIB. We
+ # do this because Debian (Ubuntu) lacks pkg-config file for cunit.
+ if test "x${have_cunit}" = "xno"; then
+ AC_CHECK_LIB([cunit], [CU_initialize_registry], [have_cunit=yes], [have_cunit=no])
+ if test "x${have_cunit}" = "xyes"; then
+ CUNIT_LIBS="-lcunit"
+ CUNIT_CFLAGS=""
+ AC_SUBST([CUNIT_LIBS])
+ AC_SUBST([CUNIT_CFLAGS])
+ fi
+ fi
+
+ AM_CONDITIONAL(HAVE_CUNIT, [test "x$have_cunit" != "xno"])
+ AC_DEFINE(HAVE_CUNIT, [test "x$have_cunit" != "xno"], [Enable CUNIT Have amdgpu support])
+
+ if test "x$have_cunit" = "xno"; then
+ AC_MSG_WARN([Could not find cunit library. Disabling amdgpu tests])
+ fi
fi
AM_CONDITIONAL(HAVE_TEGRA, [test "x$TEGRA" = xyes])
@@ -467,6 +489,7 @@ AC_CONFIG_FILES([
tests/kmstest/Makefile
tests/proptest/Makefile
tests/radeon/Makefile
+ tests/amdgpu/Makefile
tests/vbltest/Makefile
tests/exynos/Makefile
tests/tegra/Makefile
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 069285f..a980b3d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -8,6 +8,12 @@ if HAVE_RADEON
SUBDIRS += radeon
endif
+if HAVE_AMDGPU
+if HAVE_CUNIT
+SUBDIRS += amdgpu
+endif
+endif
+
if HAVE_EXYNOS
SUBDIRS += exynos
endif
diff --git a/tests/amdgpu/Makefile.am b/tests/amdgpu/Makefile.am
new file mode 100644
index 0000000..ba7339d
--- /dev/null
+++ b/tests/amdgpu/Makefile.am
@@ -0,0 +1,24 @@
+AM_CFLAGS = \
+ -I $(top_srcdir)/include/drm \
+ -I $(top_srcdir)/amdgpu \
+ -I $(top_srcdir)
+
+LDADD = $(top_builddir)/libdrm.la \
+ $(top_builddir)/amdgpu/libdrm_amdgpu.la
+
+if HAVE_INSTALL_TESTS
+bin_PROGRAMS = \
+ amdgpu_test
+else
+noinst_PROGRAMS = \
+ amdgpu_test
+endif
+
+amdgpu_test_CPPFLAGS = $(CUNIT_CFLAGS)
+amdgpu_test_LDFLAGS = $(CUNIT_LIBS)
+
+amdgpu_test_SOURCES = \
+ amdgpu_test.c \
+ basic_tests.c \
+ bo_tests.c \
+ cs_tests.c
diff --git a/tests/amdgpu/amdgpu_test.c b/tests/amdgpu/amdgpu_test.c
new file mode 100644
index 0000000..fc14b70
--- /dev/null
+++ b/tests/amdgpu/amdgpu_test.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "drm.h"
+#include "xf86drmMode.h"
+#include "xf86drm.h"
+
+#include "CUnit/Basic.h"
+
+#include "amdgpu_test.h"
+
+/**
+ * Open handles for amdgpu devices
+ *
+ */
+int drm_amdgpu[MAX_CARDS_SUPPORTED];
+
+/** The table of all known test suites to run */
+CU_SuiteInfo suites[] = {
+ { "Basic Tests", suite_basic_tests_init,
+ suite_basic_tests_clean, basic_tests },
+ { "BO Tests", suite_bo_tests_init,
+ suite_bo_tests_clean, bo_tests },
+ { "CS Tests", suite_cs_tests_init,
+ suite_cs_tests_clean, cs_tests },
+ CU_SUITE_INFO_NULL,
+};
+
+
+/** Display information about all suites and their tests */
+static void display_test_suites(void)
+{
+ int iSuite;
+ int iTest;
+
+ printf("Suites\n");
+
+ for (iSuite = 0; suites[iSuite].pName != NULL; iSuite++) {
+ printf("Suite id = %d: Name '%s'\n",
+ iSuite + 1, suites[iSuite].pName);
+
+ for (iTest = 0; suites[iSuite].pTests[iTest].pName != NULL;
+ iTest++) {
+ printf(" Test id %d: Name: '%s'\n", iTest + 1,
+ suites[iSuite].pTests[iTest].pName);
+ }
+ }
+}
+
+
+/** Help string for command line parameters */
+static const char usage[] = "Usage: %s [-hl] [<-s <suite id>> [-t <test id>]]\n"
+ "where:\n"
+ " l - Display all suites and their tests\n"
+ " h - Display this help\n";
+/** Specified options strings for getopt */
+static const char options[] = "hls:t:";
+
+/* The main() function for setting up and running the tests.
+ * Returns a CUE_SUCCESS on successful running, another
+ * CUnit error code on failure.
+ */
+int main(int argc, char **argv)
+{
+ int c; /* Character received from getopt */
+ int i = 0;
+ int suite_id = -1; /* By default run everything */
+ int test_id = -1; /* By default run all tests in the suite */
+ CU_pSuite pSuite = NULL;
+ CU_pTest pTest = NULL;
+
+ int aval = drmAvailable();
+
+ if (aval == 0) {
+ fprintf(stderr, "DRM driver is not available\n");
+ exit(EXIT_FAILURE);
+ }
+
+
+ for (i = 0; i < MAX_CARDS_SUPPORTED; i++)
+ drm_amdgpu[i] = 0;
+
+
+ /* Parse command line string */
+ opterr = 0; /* Do not print error messages from getopt */
+ while ((c = getopt(argc, argv, options)) != -1) {
+ switch (c) {
+ case 'l':
+ display_test_suites();
+ exit(EXIT_SUCCESS);
+ case 's':
+ suite_id = atoi(optarg);
+ break;
+ case 't':
+ test_id = atoi(optarg);
+ break;
+ case '?':
+ case 'h':
+ fprintf(stderr, usage, argv[0]);
+ exit(EXIT_SUCCESS);
+ default:
+ fprintf(stderr, usage, argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Try to open all possible radeon connections
+ * Right now: Open only the 0.
+ */
+ printf("Try to open the card 0..\n");
+ drm_amdgpu[0] = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
+
+ if (drm_amdgpu[0] == 1) {
+ perror("Cannot open /dev/dri/card0\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /** Display version of DRM driver */
+ drmVersionPtr retval;
+ drm_version_t *version = drmMalloc(sizeof(*version));
+
+ version->name_len = 0;
+ version->name = NULL;
+ version->date_len = 0;
+ version->date = NULL;
+ version->desc_len = 0;
+ version->desc = NULL;
+
+ if (drmIoctl(drm_amdgpu[0], DRM_IOCTL_VERSION, version)) {
+ perror("Could not get DRM driver version\n");
+ drmFree(version);
+ exit(EXIT_FAILURE);
+ }
+
+ if (version->name_len)
+ version->name = drmMalloc(version->name_len + 1);
+ if (version->date_len)
+ version->date = drmMalloc(version->date_len + 1);
+ if (version->desc_len)
+ version->desc = drmMalloc(version->desc_len + 1);
+
+ if (drmIoctl(drm_amdgpu[0], DRM_IOCTL_VERSION, version)) {
+ perror("Could not get information about DRM driver");
+ drmFree(version);
+ exit(EXIT_FAILURE);
+ }
+
+ /* The results might not be null-terminated strings. Add zero */
+ if (version->name_len)
+ version->name[version->name_len] = '\0';
+ if (version->date_len)
+ version->date[version->date_len] = '\0';
+ if (version->desc_len)
+ version->desc[version->desc_len] = '\0';
+
+ printf("DRM Driver: Name: [%s] : Date [%s] : Description [%s]\n",
+ version->name, version->date, version->desc);
+
+ drmFree(version);
+
+ /* Initialize test suites to run */
+
+ /* initialize the CUnit test registry */
+ if (CUE_SUCCESS != CU_initialize_registry())
+ return CU_get_error();
+
+ /* Register suites. */
+ if (CU_register_suites(suites) != CUE_SUCCESS) {
+ fprintf(stderr, "suite registration failed - %s\n",
+ CU_get_error_msg());
+ exit(EXIT_FAILURE);
+ }
+
+ /* Run tests using the CUnit Basic interface */
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+
+ if (suite_id != -1) { /* If user specify particular suite? */
+ pSuite = CU_get_suite_by_index((unsigned int) suite_id,
+ CU_get_registry());
+
+ if (pSuite) {
+ if (test_id != -1) { /* If user specify test id */
+ pTest = CU_get_test_by_index(
+ (unsigned int) test_id,
+ pSuite);
+ if (pTest)
+ CU_basic_run_test(pSuite, pTest);
+ else {
+ fprintf(stderr, "Invalid test id: %d\n",
+ test_id);
+ exit(EXIT_FAILURE);
+ }
+ } else
+ CU_basic_run_suite(pSuite);
+ } else {
+ fprintf(stderr, "Invalid suite id : %d\n",
+ suite_id);
+ exit(EXIT_FAILURE);
+ }
+ } else
+ CU_basic_run_tests();
+
+ CU_cleanup_registry();
+ return CU_get_error();
+}
diff --git a/tests/amdgpu/amdgpu_test.h b/tests/amdgpu/amdgpu_test.h
new file mode 100644
index 0000000..508e561
--- /dev/null
+++ b/tests/amdgpu/amdgpu_test.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+
+#ifndef _amdgpu_test_h_
+#define _amdgpu_test_h_
+
+#include "amdgpu.h"
+
+/**
+ * Define max. number of card in system which we are able to handle
+ */
+#define MAX_CARDS_SUPPORTED 4
+
+/* Forward reference for array to keep "drm" handles */
+extern int drm_amdgpu[MAX_CARDS_SUPPORTED];
+
+/************************* Basic test suite ********************************/
+
+/*
+ * Define basic test suite to serve as the starting point for future testing
+*/
+
+/**
+ * Initialize basic test suite
+ */
+int suite_basic_tests_init();
+
+/**
+ * Deinitialize basic test suite
+ */
+int suite_basic_tests_clean();
+
+/**
+ * Tests in basic test suite
+ */
+extern CU_TestInfo basic_tests[];
+
+/**
+ * Initialize bo test suite
+ */
+int suite_bo_tests_init();
+
+/**
+ * Deinitialize bo test suite
+ */
+int suite_bo_tests_clean();
+
+/**
+ * Tests in bo test suite
+ */
+extern CU_TestInfo bo_tests[];
+
+/**
+ * Initialize cs test suite
+ */
+int suite_cs_tests_init();
+
+/**
+ * Deinitialize cs test suite
+ */
+int suite_cs_tests_clean();
+
+/**
+ * Tests in cs test suite
+ */
+extern CU_TestInfo cs_tests[];
+
+/**
+ * Helper functions
+ */
+static inline amdgpu_bo_handle gpu_mem_alloc(
+ amdgpu_device_handle device_handle,
+ uint64_t size,
+ uint64_t alignment,
+ uint32_t type,
+ uint64_t flags,
+ uint64_t *vmc_addr)
+{
+ struct amdgpu_bo_alloc_request req = {0};
+ struct amdgpu_bo_alloc_result res = {0};
+ int r;
+
+ CU_ASSERT_NOT_EQUAL(vmc_addr, NULL);
+
+ req.alloc_size = size;
+ req.phys_alignment = alignment;
+ req.preferred_heap = type;
+ req.flags = flags;
+
+ r = amdgpu_bo_alloc(device_handle, &req, &res);
+ CU_ASSERT_EQUAL(r, 0);
+
+ CU_ASSERT_NOT_EQUAL(res.virtual_mc_base_address, 0);
+ CU_ASSERT_NOT_EQUAL(res.buf_handle, NULL);
+ *vmc_addr = res.virtual_mc_base_address;
+ return res.buf_handle;
+}
+
+#endif /* #ifdef _amdgpu_test_h_ */
diff --git a/tests/amdgpu/basic_tests.c b/tests/amdgpu/basic_tests.c
new file mode 100644
index 0000000..c53f6a0
--- /dev/null
+++ b/tests/amdgpu/basic_tests.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "CUnit/Basic.h"
+
+#include "amdgpu_test.h"
+#include "amdgpu_drm.h"
+
+static amdgpu_device_handle device_handle;
+static uint32_t major_version;
+static uint32_t minor_version;
+
+static void amdgpu_query_info_test(void);
+static void amdgpu_memory_alloc(void);
+static void amdgpu_command_submission_gfx(void);
+static void amdgpu_command_submission_compute(void);
+static void amdgpu_command_submission_sdma(void);
+static void amdgpu_userptr_test(void);
+
+CU_TestInfo basic_tests[] = {
+ { "Query Info Test", amdgpu_query_info_test },
+ { "Memory alloc Test", amdgpu_memory_alloc },
+ { "Userptr Test", amdgpu_userptr_test },
+ { "Command submission Test (GFX)", amdgpu_command_submission_gfx },
+ { "Command submission Test (Compute)", amdgpu_command_submission_compute },
+ { "Command submission Test (SDMA)", amdgpu_command_submission_sdma },
+ CU_TEST_INFO_NULL,
+};
+#define BUFFER_SIZE (8 * 1024)
+#define SDMA_PKT_HEADER_op_offset 0
+#define SDMA_PKT_HEADER_op_mask 0x000000FF
+#define SDMA_PKT_HEADER_op_shift 0
+#define SDMA_PKT_HEADER_OP(x) (((x) & SDMA_PKT_HEADER_op_mask) << SDMA_PKT_HEADER_op_shift)
+#define SDMA_OPCODE_CONSTANT_FILL 11
+# define SDMA_CONSTANT_FILL_EXTRA_SIZE(x) ((x) << 14)
+ /* 0 = byte fill
+ * 2 = DW fill
+ */
+#define SDMA_PACKET(op, sub_op, e) ((((e) & 0xFFFF) << 16) | \
+ (((sub_op) & 0xFF) << 8) | \
+ (((op) & 0xFF) << 0))
+#define SDMA_OPCODE_WRITE 2
+# define SDMA_WRITE_SUB_OPCODE_LINEAR 0
+# define SDMA_WRTIE_SUB_OPCODE_TILED 1
+
+#define SDMA_OPCODE_COPY 1
+# define SDMA_COPY_SUB_OPCODE_LINEAR 0
+
+int suite_basic_tests_init(void)
+{
+ int r;
+
+ r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+ &minor_version, &device_handle);
+
+ if (r == 0)
+ return CUE_SUCCESS;
+ else
+ return CUE_SINIT_FAILED;
+}
+
+int suite_basic_tests_clean(void)
+{
+ int r = amdgpu_device_deinitialize(device_handle);
+
+ if (r == 0)
+ return CUE_SUCCESS;
+ else
+ return CUE_SCLEAN_FAILED;
+}
+
+static void amdgpu_query_info_test(void)
+{
+ struct amdgpu_gpu_info gpu_info = {0};
+ uint32_t version, feature;
+ int r;
+
+ r = amdgpu_query_gpu_info(device_handle, &gpu_info);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_query_firmware_version(device_handle, AMDGPU_INFO_FW_VCE, 0,
+ 0, &version, &feature);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_memory_alloc(void)
+{
+ amdgpu_bo_handle bo;
+ uint64_t bo_mc;
+ int r;
+
+ /* Test visible VRAM */
+ bo = gpu_mem_alloc(device_handle,
+ 4096, 4096,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
+ &bo_mc);
+
+ r = amdgpu_bo_free(bo);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* Test invisible VRAM */
+ bo = gpu_mem_alloc(device_handle,
+ 4096, 4096,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_CREATE_NO_CPU_ACCESS,
+ &bo_mc);
+
+ r = amdgpu_bo_free(bo);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* Test GART Cacheable */
+ bo = gpu_mem_alloc(device_handle,
+ 4096, 4096,
+ AMDGPU_GEM_DOMAIN_GTT,
+ 0,
+ &bo_mc);
+
+ r = amdgpu_bo_free(bo);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* Test GART USWC */
+ bo = gpu_mem_alloc(device_handle,
+ 4096, 4096,
+ AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_GEM_CREATE_CPU_GTT_WC,
+ &bo_mc);
+
+ r = amdgpu_bo_free(bo);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_command_submission_gfx(void)
+{
+ amdgpu_context_handle context_handle;
+ struct amdgpu_cs_ib_alloc_result ib_result = {0};
+ struct amdgpu_cs_ib_alloc_result ib_result_ce = {0};
+ struct amdgpu_cs_request ibs_request = {0};
+ struct amdgpu_cs_ib_info ib_info[2];
+ struct amdgpu_cs_query_fence fence_status = {0};
+ uint32_t *ptr;
+ uint32_t expired;
+ int r;
+
+ r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_cs_alloc_ib(device_handle, context_handle,
+ amdgpu_cs_ib_size_4K, &ib_result);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_cs_alloc_ib(device_handle, context_handle,
+ amdgpu_cs_ib_size_4K, &ib_result_ce);
+ CU_ASSERT_EQUAL(r, 0);
+
+ memset(ib_info, 0, 2 * sizeof(struct amdgpu_cs_ib_info));
+
+ /* IT_SET_CE_DE_COUNTERS */
+ ptr = ib_result_ce.cpu;
+ ptr[0] = 0xc0008900;
+ ptr[1] = 0;
+ ptr[2] = 0xc0008400;
+ ptr[3] = 1;
+ ib_info[0].ib_handle = ib_result_ce.handle;
+ ib_info[0].size = 4;
+ ib_info[0].flags = AMDGPU_CS_GFX_IB_CE;
+
+ /* IT_WAIT_ON_CE_COUNTER */
+ ptr = ib_result.cpu;
+ ptr[0] = 0xc0008600;
+ ptr[1] = 0x00000001;
+ ib_info[1].ib_handle = ib_result.handle;
+ ib_info[1].size = 2;
+
+ ibs_request.ip_type = AMDGPU_HW_IP_GFX;
+ ibs_request.number_of_ibs = 2;
+ ibs_request.ibs = ib_info;
+
+ r = amdgpu_cs_submit(device_handle, context_handle, 0,
+ &ibs_request, 1, &fence_status.fence);
+ CU_ASSERT_EQUAL(r, 0);
+
+ fence_status.context = context_handle;
+ fence_status.timeout_ns = AMDGPU_TIMEOUT_INFINITE;
+ fence_status.ip_type = AMDGPU_HW_IP_GFX;
+
+ r = amdgpu_cs_query_fence_status(device_handle, &fence_status, &expired);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_cs_ctx_free(device_handle, context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_command_submission_compute(void)
+{
+ amdgpu_context_handle context_handle;
+ struct amdgpu_cs_ib_alloc_result ib_result;
+ struct amdgpu_cs_request ibs_request;
+ struct amdgpu_cs_ib_info ib_info;
+ struct amdgpu_cs_query_fence fence_status;
+ uint32_t *ptr;
+ uint32_t expired;
+ int i, r, instance;
+
+ r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ for (instance = 0; instance < 8; instance++) {
+ memset(&ib_result, 0, sizeof(struct amdgpu_cs_ib_alloc_result));
+ r = amdgpu_cs_alloc_ib(device_handle, context_handle,
+ amdgpu_cs_ib_size_4K, &ib_result);
+ CU_ASSERT_EQUAL(r, 0);
+
+ ptr = ib_result.cpu;
+ for (i = 0; i < 16; ++i)
+ ptr[i] = 0xffff1000;
+
+ memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info));
+ ib_info.ib_handle = ib_result.handle;
+ ib_info.size = 16;
+
+ memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request));
+ ibs_request.ip_type = AMDGPU_HW_IP_COMPUTE;
+ ibs_request.ring = instance;
+ ibs_request.number_of_ibs = 1;
+ ibs_request.ibs = &ib_info;
+
+ memset(&fence_status, 0, sizeof(struct amdgpu_cs_query_fence));
+ r = amdgpu_cs_submit(device_handle, context_handle, 0,
+ &ibs_request, 1, &fence_status.fence);
+ CU_ASSERT_EQUAL(r, 0);
+
+ fence_status.context = context_handle;
+ fence_status.timeout_ns = AMDGPU_TIMEOUT_INFINITE;
+ fence_status.ip_type = AMDGPU_HW_IP_COMPUTE;
+ fence_status.ring = instance;
+
+ r = amdgpu_cs_query_fence_status(device_handle, &fence_status, &expired);
+ CU_ASSERT_EQUAL(r, 0);
+ }
+
+ r = amdgpu_cs_ctx_free(device_handle, context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+/*
+ * caller need create/release:
+ * pm4_src, resources, ib_info, and ibs_request
+ * submit command stream described in ibs_request and wait for this IB accomplished
+ */
+static void amdgpu_sdma_test_exec_cs(amdgpu_context_handle context_handle,
+ int instance, int pm4_dw, uint32_t *pm4_src,
+ int res_cnt, amdgpu_bo_handle *resources,
+ struct amdgpu_cs_ib_info *ib_info,
+ struct amdgpu_cs_request *ibs_request)
+{
+ int r, i, j;
+ uint32_t expired;
+ uint32_t *ring_ptr;
+ struct amdgpu_cs_ib_alloc_result ib_result = {0};
+ struct amdgpu_cs_query_fence fence_status = {0};
+
+ /* prepare CS */
+ CU_ASSERT_NOT_EQUAL(pm4_src, NULL);
+ CU_ASSERT_NOT_EQUAL(resources, NULL);
+ CU_ASSERT_NOT_EQUAL(ib_info, NULL);
+ CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
+ CU_ASSERT_TRUE(pm4_dw <= 1024);
+
+ /* allocate IB */
+ r = amdgpu_cs_alloc_ib(device_handle, context_handle,
+ amdgpu_cs_ib_size_4K, &ib_result);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* copy PM4 packet to ring from caller */
+ ring_ptr = ib_result.cpu;
+ memcpy(ring_ptr, pm4_src, pm4_dw * sizeof(*pm4_src));
+
+ ib_info->ib_handle = ib_result.handle;
+ ib_info->size = pm4_dw;
+
+ ibs_request->ip_type = AMDGPU_HW_IP_DMA;
+ ibs_request->ring = instance;
+ ibs_request->number_of_ibs = 1;
+ ibs_request->ibs = ib_info;
+ ibs_request->number_of_resources = res_cnt;
+ ibs_request->resources = resources;
+
+
+ CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
+
+ /* submit CS */
+ r = amdgpu_cs_submit(device_handle, context_handle, 0,
+ ibs_request, 1, &fence_status.fence);
+ CU_ASSERT_EQUAL(r, 0);
+
+ fence_status.ip_type = AMDGPU_HW_IP_DMA;
+ fence_status.ring = ibs_request->ring;
+ fence_status.context = context_handle;
+ fence_status.timeout_ns = AMDGPU_TIMEOUT_INFINITE;
+
+ /* wait for IB accomplished */
+ r = amdgpu_cs_query_fence_status(device_handle, &fence_status,
+ &expired);
+ CU_ASSERT_EQUAL(r, 0);
+ CU_ASSERT_EQUAL(expired, true);
+}
+
+static void amdgpu_command_submission_sdma_write_linear(void)
+{
+ const int sdma_write_length = 128;
+ const int pm4_dw = 256;
+ amdgpu_context_handle context_handle;
+ amdgpu_bo_handle bo;
+ amdgpu_bo_handle *resources;
+ uint32_t *pm4;
+ struct amdgpu_cs_ib_info *ib_info;
+ struct amdgpu_cs_request *ibs_request;
+ uint64_t bo_mc;
+ volatile uint32_t *bo_cpu;
+ int i, j, r, loop;
+ uint64_t gtt_flags[3] = {0, AMDGPU_GEM_CREATE_CPU_GTT_UC,
+ AMDGPU_GEM_CREATE_CPU_GTT_WC};
+
+ pm4 = malloc(pm4_dw * 4);
+ CU_ASSERT_NOT_EQUAL(pm4, NULL);
+
+ ib_info = malloc(sizeof(*ib_info));
+ CU_ASSERT_NOT_EQUAL(ib_info, NULL);
+ memset(ib_info, 0, sizeof(*ib_info));
+
+ ibs_request = malloc(sizeof(*ibs_request));
+ CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
+ memset(ibs_request, 0, sizeof(*ibs_request));
+
+ r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* prepare resource */
+ resources = malloc(sizeof(amdgpu_bo_handle));
+ CU_ASSERT_NOT_EQUAL(resources, NULL);
+
+ loop = 0;
+ while(loop < 3) {
+ /* allocate UC bo for sDMA use */
+ bo = gpu_mem_alloc(device_handle,
+ sdma_write_length * sizeof(uint32_t),
+ 4096, AMDGPU_GEM_DOMAIN_GTT,
+ gtt_flags[loop], &bo_mc);
+
+ CU_ASSERT_EQUAL(amdgpu_bo_cpu_map(bo, (void **)&bo_cpu), 0);
+ CU_ASSERT_NOT_EQUAL(bo_cpu, NULL);
+
+ /* clear bo */
+ memset((void*)bo_cpu, 0, sdma_write_length * sizeof(uint32_t));
+
+
+ resources[0] = bo;
+
+ /* fullfill PM4: test DMA write-linear */
+ i = j = 0;
+ pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
+ SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+ pm4[i++] = 0xffffffff & bo_mc;
+ pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+ pm4[i++] = sdma_write_length;
+ while(j++ < sdma_write_length)
+ pm4[i++] = 0xdeadbeaf;
+
+ amdgpu_sdma_test_exec_cs(context_handle, 0,
+ i, pm4,
+ 1, resources,
+ ib_info, ibs_request);
+
+ /* verify if SDMA test result meets with expected */
+ i = 0;
+ while(i < sdma_write_length) {
+ CU_ASSERT_EQUAL(bo_cpu[i++], 0xdeadbeaf);
+ }
+ amdgpu_bo_free(bo);
+ loop++;
+ }
+ /* clean resources */
+ free(resources);
+ free(ibs_request);
+ free(ib_info);
+ free(pm4);
+
+ /* end of test */
+ r = amdgpu_cs_ctx_free(device_handle, context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_command_submission_sdma_const_fill(void)
+{
+ const int sdma_write_length = 1024 * 1024;
+ const int pm4_dw = 256;
+ amdgpu_context_handle context_handle;
+ amdgpu_bo_handle bo;
+ amdgpu_bo_handle *resources;
+ uint32_t *pm4;
+ struct amdgpu_cs_ib_info *ib_info;
+ struct amdgpu_cs_request *ibs_request;
+ uint64_t bo_mc;
+ volatile uint32_t *bo_cpu;
+ int i, j, r, loop;
+ uint64_t gtt_flags[3] = {0, AMDGPU_GEM_CREATE_CPU_GTT_UC,
+ AMDGPU_GEM_CREATE_CPU_GTT_WC};
+
+ pm4 = malloc(pm4_dw * 4);
+ CU_ASSERT_NOT_EQUAL(pm4, NULL);
+
+ ib_info = malloc(sizeof(*ib_info));
+ CU_ASSERT_NOT_EQUAL(ib_info, NULL);
+ memset(ib_info, 0, sizeof(*ib_info));
+
+ ibs_request = malloc(sizeof(*ibs_request));
+ CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
+ memset(ibs_request, 0, sizeof(*ibs_request));
+
+ r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* prepare resource */
+ resources = malloc(sizeof(amdgpu_bo_handle));
+ CU_ASSERT_NOT_EQUAL(resources, NULL);
+
+ loop = 0;
+ while(loop < 3) {
+ /* allocate UC bo for sDMA use */
+ bo = gpu_mem_alloc(device_handle,
+ sdma_write_length, 4096,
+ AMDGPU_GEM_DOMAIN_GTT,
+ gtt_flags[loop], &bo_mc);
+
+ CU_ASSERT_EQUAL(amdgpu_bo_cpu_map(bo, (void **)&bo_cpu), 0);
+ CU_ASSERT_NOT_EQUAL(bo_cpu, NULL);
+
+ /* clear bo */
+ memset((void*)bo_cpu, 0, sdma_write_length);
+
+ resources[0] = bo;
+
+ /* fullfill PM4: test DMA const fill */
+ i = j = 0;
+ pm4[i++] = SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0,
+ SDMA_CONSTANT_FILL_EXTRA_SIZE(2));
+ pm4[i++] = 0xffffffff & bo_mc;
+ pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+ pm4[i++] = 0xdeadbeaf;
+ pm4[i++] = sdma_write_length;
+
+ amdgpu_sdma_test_exec_cs(context_handle, 0,
+ i, pm4,
+ 1, resources,
+ ib_info, ibs_request);
+
+ /* verify if SDMA test result meets with expected */
+ i = 0;
+ while(i < (sdma_write_length / 4)) {
+ CU_ASSERT_EQUAL(bo_cpu[i++], 0xdeadbeaf);
+ }
+ amdgpu_bo_free(bo);
+ loop++;
+ }
+ /* clean resources */
+ free(resources);
+ free(ibs_request);
+ free(ib_info);
+ free(pm4);
+
+ /* end of test */
+ r = amdgpu_cs_ctx_free(device_handle, context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_command_submission_sdma_copy_linear(void)
+{
+ const int sdma_write_length = 1024;
+ const int pm4_dw = 256;
+ amdgpu_context_handle context_handle;
+ amdgpu_bo_handle bo1, bo2;
+ amdgpu_bo_handle *resources;
+ uint32_t *pm4;
+ struct amdgpu_cs_ib_info *ib_info;
+ struct amdgpu_cs_request *ibs_request;
+ uint64_t bo1_mc, bo2_mc;
+ volatile unsigned char *bo1_cpu, *bo2_cpu;
+ int i, j, r, loop1, loop2;
+ uint64_t gtt_flags[3] = {0, AMDGPU_GEM_CREATE_CPU_GTT_UC,
+ AMDGPU_GEM_CREATE_CPU_GTT_WC};
+
+ pm4 = malloc(pm4_dw * 4);
+ CU_ASSERT_NOT_EQUAL(pm4, NULL);
+
+ ib_info = malloc(sizeof(*ib_info));
+ CU_ASSERT_NOT_EQUAL(ib_info, NULL);
+ memset(ib_info, 0, sizeof(*ib_info));
+
+ ibs_request = malloc(sizeof(*ibs_request));
+ CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
+ memset(ibs_request, 0, sizeof(*ibs_request));
+
+ r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* prepare resource */
+ resources = malloc(2 * sizeof(amdgpu_bo_handle));
+ CU_ASSERT_NOT_EQUAL(resources, NULL);
+
+ loop1 = loop2 = 0;
+ /* run 9 circle to test all mapping combination */
+ while(loop1 < 3) {
+ while(loop2 < 3) {
+ /* allocate UC bo1for sDMA use */
+ bo1 = gpu_mem_alloc(device_handle,
+ sdma_write_length, 4096,
+ AMDGPU_GEM_DOMAIN_GTT,
+ gtt_flags[loop1], &bo1_mc);
+
+ CU_ASSERT_EQUAL(amdgpu_bo_cpu_map(bo1, (void **)&bo1_cpu), 0);
+ CU_ASSERT_NOT_EQUAL(bo1_cpu, NULL);
+
+ /* set bo1 */
+ memset((void*)bo1_cpu, 0xaa, sdma_write_length);
+
+ /* allocate UC bo2 for sDMA use */
+ bo2 = gpu_mem_alloc(device_handle,
+ sdma_write_length, 4096,
+ AMDGPU_GEM_DOMAIN_GTT,
+ gtt_flags[loop2], &bo2_mc);
+
+ CU_ASSERT_EQUAL(amdgpu_bo_cpu_map(bo2, (void **)&bo2_cpu), 0);
+ CU_ASSERT_NOT_EQUAL(bo2_cpu, NULL);
+
+ /* clear bo2 */
+ memset((void*)bo2_cpu, 0, sdma_write_length);
+
+ resources[0] = bo1;
+ resources[1] = bo2;
+
+ /* fullfill PM4: test DMA copy linear */
+ i = j = 0;
+ pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0);
+ pm4[i++] = sdma_write_length;
+ pm4[i++] = 0;
+ pm4[i++] = 0xffffffff & bo1_mc;
+ pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
+ pm4[i++] = 0xffffffff & bo2_mc;
+ pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+
+
+ amdgpu_sdma_test_exec_cs(context_handle, 0,
+ i, pm4,
+ 2, resources,
+ ib_info, ibs_request);
+
+ /* verify if SDMA test result meets with expected */
+ i = 0;
+ while(i < sdma_write_length) {
+ CU_ASSERT_EQUAL(bo2_cpu[i++], 0xaa);
+ }
+ amdgpu_bo_free(bo1);
+ amdgpu_bo_free(bo2);
+ loop2++;
+ }
+ loop1++;
+ }
+ /* clean resources */
+ free(resources);
+ free(ibs_request);
+ free(ib_info);
+ free(pm4);
+
+ /* end of test */
+ r = amdgpu_cs_ctx_free(device_handle, context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_command_submission_sdma(void)
+{
+ amdgpu_command_submission_sdma_write_linear();
+ amdgpu_command_submission_sdma_const_fill();
+ amdgpu_command_submission_sdma_copy_linear();
+}
+
+static void amdgpu_userptr_test(void)
+{
+ int i, r, j;
+ uint32_t *pm4 = NULL;
+ uint64_t bo_mc;
+ void *ptr = NULL;
+ int pm4_dw = 256;
+ int sdma_write_length = 4;
+ amdgpu_bo_handle handle;
+ amdgpu_context_handle context_handle;
+ struct amdgpu_cs_ib_info *ib_info;
+ struct amdgpu_cs_request *ibs_request;
+ struct amdgpu_bo_alloc_result res;
+
+ memset(&res, 0, sizeof(res));
+
+ pm4 = malloc(pm4_dw * sizeof(*pm4));
+ CU_ASSERT_NOT_EQUAL(pm4, NULL);
+
+ ib_info = malloc(sizeof(*ib_info));
+ CU_ASSERT_NOT_EQUAL(ib_info, NULL);
+
+ memset(ib_info, 0, sizeof(*ib_info));
+ ibs_request = malloc(sizeof(*ibs_request));
+ CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
+
+ memset(ibs_request, 0, sizeof(*ibs_request));
+ r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ ptr = memalign(BUFFER_SIZE);
+ CU_ASSERT_NOT_EQUAL(ptr, NULL);
+
+ r = amdgpu_create_bo_from_user_mem(device_handle,
+ ptr, BUFFER_SIZE, &res);
+ CU_ASSERT_EQUAL(r, 0);
+ bo_mc = res.virtual_mc_base_address;
+ handle = res.buf_handle;
+
+ j = i = 0;
+ pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
+ SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+ pm4[i++] = 0xffffffff & bo_mc;
+ pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+ pm4[i++] = sdma_write_length;
+
+ while (j++ < sdma_write_length)
+ pm4[i++] = 0xdeadbeaf;
+
+ amdgpu_sdma_test_exec_cs(context_handle, 0,
+ i, pm4,
+ 1, &handle,
+ ib_info, ibs_request);
+ i = 0;
+ while (i < sdma_write_length) {
+ CU_ASSERT_EQUAL(((int*)ptr)[i++], 0xdeadbeaf);
+ }
+ free(ibs_request);
+ free(ib_info);
+ free(pm4);
+ r = amdgpu_bo_free(res.buf_handle);
+ CU_ASSERT_EQUAL(r, 0);
+ free(ptr);
+
+ r = amdgpu_cs_ctx_free(device_handle, context_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
diff --git a/tests/amdgpu/bo_tests.c b/tests/amdgpu/bo_tests.c
new file mode 100644
index 0000000..73701b7
--- /dev/null
+++ b/tests/amdgpu/bo_tests.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+#include <stdio.h>
+
+#include "CUnit/Basic.h"
+
+#include "amdgpu_test.h"
+#include "amdgpu_drm.h"
+
+#define BUFFER_SIZE (4*1024)
+#define BUFFER_ALIGN (4*1024)
+
+static amdgpu_device_handle device_handle;
+static uint32_t major_version;
+static uint32_t minor_version;
+
+static amdgpu_bo_handle buffer_handle;
+static uint64_t virtual_mc_base_address;
+
+static void amdgpu_bo_export_import(void);
+static void amdgpu_bo_metadata(void);
+static void amdgpu_bo_map_unmap(void);
+
+CU_TestInfo bo_tests[] = {
+ { "Export/Import", amdgpu_bo_export_import },
+#if 0
+ { "Metadata", amdgpu_bo_metadata },
+#endif
+ { "CPU map/unmap", amdgpu_bo_map_unmap },
+ CU_TEST_INFO_NULL,
+};
+
+int suite_bo_tests_init(void)
+{
+ struct amdgpu_bo_alloc_request req = {0};
+ struct amdgpu_bo_alloc_result res = {0};
+ int r;
+
+ r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+ &minor_version, &device_handle);
+ if (r)
+ return CUE_SINIT_FAILED;
+
+ req.alloc_size = BUFFER_SIZE;
+ req.phys_alignment = BUFFER_ALIGN;
+ req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
+
+ r = amdgpu_bo_alloc(device_handle, &req, &res);
+ if (r)
+ return CUE_SINIT_FAILED;
+
+ buffer_handle = res.buf_handle;
+ virtual_mc_base_address = res.virtual_mc_base_address;
+
+ return CUE_SUCCESS;
+}
+
+int suite_bo_tests_clean(void)
+{
+ int r;
+
+ r = amdgpu_bo_free(buffer_handle);
+ if (r)
+ return CUE_SCLEAN_FAILED;
+
+ r = amdgpu_device_deinitialize(device_handle);
+ if (r)
+ return CUE_SCLEAN_FAILED;
+
+ return CUE_SUCCESS;
+}
+
+static void amdgpu_bo_export_import_do_type(enum amdgpu_bo_handle_type type)
+{
+ struct amdgpu_bo_import_result res = {0};
+ uint32_t shared_handle;
+ int r;
+
+ r = amdgpu_bo_export(buffer_handle, type, &shared_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_import(device_handle, type, shared_handle, &res);
+ CU_ASSERT_EQUAL(r, 0);
+
+ CU_ASSERT_EQUAL(res.buf_handle, buffer_handle);
+ CU_ASSERT_EQUAL(res.alloc_size, BUFFER_SIZE);
+
+ r = amdgpu_bo_free(res.buf_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_bo_export_import(void)
+{
+ amdgpu_bo_export_import_do_type(amdgpu_bo_handle_type_gem_flink_name);
+ amdgpu_bo_export_import_do_type(amdgpu_bo_handle_type_dma_buf_fd);
+}
+
+static void amdgpu_bo_metadata(void)
+{
+ struct amdgpu_bo_metadata meta = {0};
+ struct amdgpu_bo_info info = {0};
+ int r;
+
+ meta.size_metadata = 1;
+ meta.umd_metadata[0] = 0xdeadbeef;
+
+ r = amdgpu_bo_set_metadata(buffer_handle, &meta);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_query_info(buffer_handle, &info);
+ CU_ASSERT_EQUAL(r, 0);
+
+ CU_ASSERT_EQUAL(info.metadata.size_metadata, 1);
+ CU_ASSERT_EQUAL(info.metadata.umd_metadata[0], 0xdeadbeef);
+}
+
+static void amdgpu_bo_map_unmap(void)
+{
+ uint32_t *ptr;
+ int i, r;
+
+ r = amdgpu_bo_cpu_map(buffer_handle, (void **)&ptr);
+ CU_ASSERT_EQUAL(r, 0);
+ CU_ASSERT_NOT_EQUAL(ptr, NULL);
+
+ for (i = 0; i < (BUFFER_SIZE / 4); ++i)
+ ptr[i] = 0xdeadbeef;
+
+ r = amdgpu_bo_cpu_unmap(buffer_handle);
+ CU_ASSERT_EQUAL(r, 0);
+}
diff --git a/tests/amdgpu/cs_tests.c b/tests/amdgpu/cs_tests.c
new file mode 100644
index 0000000..f30d923
--- /dev/null
+++ b/tests/amdgpu/cs_tests.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+*/
+#include <stdio.h>
+
+#include "CUnit/Basic.h"
+
+#include "amdgpu/util_math.h"
+
+#include "amdgpu_test.h"
+#include "uvd_messages.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+
+#define IB_SIZE amdgpu_cs_ib_size_4K
+#define MAX_RESOURCES 16
+
+static amdgpu_device_handle device_handle;
+static uint32_t major_version;
+static uint32_t minor_version;
+static uint32_t family_id;
+
+static amdgpu_context_handle context_handle;
+static amdgpu_ib_handle ib_handle;
+uint32_t *ib_cpu;
+
+static amdgpu_bo_handle resources[MAX_RESOURCES];
+static unsigned num_resources;
+
+static void amdgpu_cs_uvd_create(void);
+static void amdgpu_cs_uvd_decode(void);
+static void amdgpu_cs_uvd_destroy(void);
+
+CU_TestInfo cs_tests[] = {
+ { "UVD create", amdgpu_cs_uvd_create },
+ { "UVD decode", amdgpu_cs_uvd_decode },
+ { "UVD destroy", amdgpu_cs_uvd_destroy },
+ CU_TEST_INFO_NULL,
+};
+
+int suite_cs_tests_init(void)
+{
+ struct amdgpu_cs_ib_alloc_result ib_result = {0};
+ int r;
+
+ r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+ &minor_version, &device_handle);
+ if (r)
+ return CUE_SINIT_FAILED;
+
+ family_id = device_handle->info.family_id;
+
+ r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+ if (r)
+ return CUE_SINIT_FAILED;
+
+ r = amdgpu_cs_alloc_ib(device_handle, context_handle,
+ IB_SIZE, &ib_result);
+ if (r)
+ return CUE_SINIT_FAILED;
+
+ ib_handle = ib_result.handle;
+ ib_cpu = ib_result.cpu;
+
+ return CUE_SUCCESS;
+}
+
+int suite_cs_tests_clean(void)
+{
+ int r;
+
+ r = amdgpu_cs_free_ib(device_handle, context_handle, ib_handle);
+ if (r)
+ return CUE_SCLEAN_FAILED;
+
+ r = amdgpu_cs_ctx_free(device_handle, context_handle);
+ if (r)
+ return CUE_SCLEAN_FAILED;
+
+ r = amdgpu_device_deinitialize(device_handle);
+ if (r)
+ return CUE_SCLEAN_FAILED;
+
+ return CUE_SUCCESS;
+}
+
+static int submit(unsigned ndw, unsigned ip)
+{
+ struct amdgpu_cs_ib_alloc_result ib_result = {0};
+ struct amdgpu_cs_request ibs_request = {0};
+ struct amdgpu_cs_ib_info ib_info = {0};
+ struct amdgpu_cs_query_fence fence_status = {0};
+ uint32_t expired;
+ int r;
+
+ ib_info.ib_handle = ib_handle;
+ ib_info.size = ndw;
+
+ ibs_request.ip_type = ip;
+ ibs_request.number_of_resources = num_resources;
+ ibs_request.resources = resources;
+ ibs_request.number_of_ibs = 1;
+ ibs_request.ibs = &ib_info;
+
+ r = amdgpu_cs_submit(device_handle, context_handle, 0,
+ &ibs_request, 1, &fence_status.fence);
+ if (r)
+ return r;
+
+ r = amdgpu_cs_alloc_ib(device_handle, context_handle,
+ IB_SIZE, &ib_result);
+ if (r)
+ return r;
+
+ ib_handle = ib_result.handle;
+ ib_cpu = ib_result.cpu;
+
+ fence_status.context = context_handle;
+ fence_status.timeout_ns = AMDGPU_TIMEOUT_INFINITE;
+ fence_status.ip_type = ip;
+
+ r = amdgpu_cs_query_fence_status(device_handle, &fence_status, &expired);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void uvd_cmd(uint64_t addr, unsigned cmd, int *idx)
+{
+ ib_cpu[(*idx)++] = 0x3BC4;
+ ib_cpu[(*idx)++] = addr;
+ ib_cpu[(*idx)++] = 0x3BC5;
+ ib_cpu[(*idx)++] = addr >> 32;
+ ib_cpu[(*idx)++] = 0x3BC3;
+ ib_cpu[(*idx)++] = cmd << 1;
+}
+
+static void amdgpu_cs_uvd_create(void)
+{
+ struct amdgpu_bo_alloc_request req = {0};
+ struct amdgpu_bo_alloc_result res = {0};
+ void *msg;
+ int i, r;
+
+ req.alloc_size = 4*1024;
+ req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
+
+ r = amdgpu_bo_alloc(device_handle, &req, &res);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_cpu_map(res.buf_handle, &msg);
+ CU_ASSERT_EQUAL(r, 0);
+
+ memcpy(msg, uvd_create_msg, sizeof(uvd_create_msg));
+ if (family_id >= AMDGPU_FAMILY_VI)
+ ((uint8_t*)msg)[0x10] = 7;
+
+ r = amdgpu_bo_cpu_unmap(res.buf_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ num_resources = 0;
+ resources[num_resources++] = res.buf_handle;
+
+ i = 0;
+ uvd_cmd(res.virtual_mc_base_address, 0x0, &i);
+ for (; i % 16; ++i)
+ ib_cpu[i] = 0x80000000;
+
+ r = submit(i, AMDGPU_HW_IP_UVD);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_free(resources[0]);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_cs_uvd_decode(void)
+{
+ const unsigned dpb_size = 15923584, dt_size = 737280;
+ uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, dt_addr, it_addr;
+ struct amdgpu_bo_alloc_request req = {0};
+ struct amdgpu_bo_alloc_result res = {0};
+ uint64_t sum;
+ uint8_t *ptr;
+ int i, r;
+
+ req.alloc_size = 4*1024; /* msg */
+ req.alloc_size += 4*1024; /* fb */
+ if (family_id >= AMDGPU_FAMILY_VI)
+ req.alloc_size += 4096; /*it_scaling_table*/
+ req.alloc_size += ALIGN(sizeof(uvd_bitstream), 4*1024);
+ req.alloc_size += ALIGN(dpb_size, 4*1024);
+ req.alloc_size += ALIGN(dt_size, 4*1024);
+
+ req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
+
+ r = amdgpu_bo_alloc(device_handle, &req, &res);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_cpu_map(res.buf_handle, (void **)&ptr);
+ CU_ASSERT_EQUAL(r, 0);
+
+ memcpy(ptr, uvd_decode_msg, sizeof(uvd_create_msg));
+ if (family_id >= AMDGPU_FAMILY_VI)
+ ptr[0x10] = 7;
+
+ ptr += 4*1024;
+ memset(ptr, 0, 4*1024);
+ if (family_id >= AMDGPU_FAMILY_VI) {
+ ptr += 4*1024;
+ memcpy(ptr, uvd_it_scaling_table, sizeof(uvd_it_scaling_table));
+ }
+
+ ptr += 4*1024;
+ memcpy(ptr, uvd_bitstream, sizeof(uvd_bitstream));
+
+ ptr += ALIGN(sizeof(uvd_bitstream), 4*1024);
+ memset(ptr, 0, dpb_size);
+
+ ptr += ALIGN(dpb_size, 4*1024);
+ memset(ptr, 0, dt_size);
+
+ num_resources = 0;
+ resources[num_resources++] = res.buf_handle;
+
+ msg_addr = res.virtual_mc_base_address;
+ fb_addr = msg_addr + 4*1024;
+ if (family_id >= AMDGPU_FAMILY_VI) {
+ it_addr = fb_addr + 4*1024;
+ bs_addr = it_addr + 4*1024;
+ } else
+ bs_addr = fb_addr + 4*1024;
+ dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024);
+ dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024);
+
+ i = 0;
+ uvd_cmd(msg_addr, 0x0, &i);
+ uvd_cmd(dpb_addr, 0x1, &i);
+ uvd_cmd(dt_addr, 0x2, &i);
+ uvd_cmd(fb_addr, 0x3, &i);
+ uvd_cmd(bs_addr, 0x100, &i);
+ if (family_id >= AMDGPU_FAMILY_VI)
+ uvd_cmd(it_addr, 0x204, &i);
+ ib_cpu[i++] = 0x3BC6;
+ ib_cpu[i++] = 0x1;
+ for (; i % 16; ++i)
+ ib_cpu[i] = 0x80000000;
+
+ r = submit(i, AMDGPU_HW_IP_UVD);
+ CU_ASSERT_EQUAL(r, 0);
+
+ /* TODO: use a real CRC32 */
+ for (i = 0, sum = 0; i < dt_size; ++i)
+ sum += ptr[i];
+ CU_ASSERT_EQUAL(sum, 0x20345d8);
+
+ r = amdgpu_bo_cpu_unmap(res.buf_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_free(resources[0]);
+ CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_cs_uvd_destroy(void)
+{
+ struct amdgpu_bo_alloc_request req = {0};
+ struct amdgpu_bo_alloc_result res = {0};
+ void *msg;
+ int i, r;
+
+ req.alloc_size = 4*1024;
+ req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
+
+ r = amdgpu_bo_alloc(device_handle, &req, &res);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_cpu_map(res.buf_handle, &msg);
+ CU_ASSERT_EQUAL(r, 0);
+
+ memcpy(msg, uvd_destroy_msg, sizeof(uvd_create_msg));
+ if (family_id >= AMDGPU_FAMILY_VI)
+ ((uint8_t*)msg)[0x10] = 7;
+
+ r = amdgpu_bo_cpu_unmap(res.buf_handle);
+ CU_ASSERT_EQUAL(r, 0);
+
+ num_resources = 0;
+ resources[num_resources++] = res.buf_handle;
+
+ i = 0;
+ uvd_cmd(res.virtual_mc_base_address, 0x0, &i);
+ for (; i % 16; ++i)
+ ib_cpu[i] = 0x80000000;
+
+ r = submit(i, AMDGPU_HW_IP_UVD);
+ CU_ASSERT_EQUAL(r, 0);
+
+ r = amdgpu_bo_free(resources[0]);
+ CU_ASSERT_EQUAL(r, 0);
+}
diff --git a/tests/amdgpu/uvd_messages.h b/tests/amdgpu/uvd_messages.h
new file mode 100644
index 0000000..d4069c9
--- /dev/null
+++ b/tests/amdgpu/uvd_messages.h
@@ -0,0 +1,813 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _uvd_messages_h_
+#define _uvd_messages_h_
+
+static uint8_t uvd_create_msg[] = {
+ 0xe4,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x03,0x00,0x00,
+ 0xe0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xf9,0xf2,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
+static uint8_t uvd_bitstream[] ={
+ 0x00,0x00,0x01,0x25,0xb8,0x20,0x20,0x21,0x44,0xc5,0x00,0x01,0x57,0x9b,0xef,0xbe,
+ 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,
+ 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,
+ 0xbe,0xfb,0xef,0xbe,0xff,0x87,0xff,0xc2,0x58,0x0e,0x00,0x02,0x02,0xa0,0x00,0x20,
+ 0x3a,0x00,0x0d,0x00,0x01,0x01,0xa4,0xcb,0x94,0x73,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xaf,0x00,0x00,0x01,0x25,0x00,0xa2,0xb8,0x20,0x20,0x21,0x44,
+ 0xc5,0x00,0x01,0x57,0x9b,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,
+ 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,
+ 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xff,0x87,0xff,0xc2,0x58,
+ 0x0e,0x00,0x02,0x02,0xa0,0x00,0x20,0x3a,0x00,0x0d,0x00,0x01,0x01,0xa4,0xcb,0x94,
+ 0x73,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xaf,0x00,0x00,0x01,0x25,
+ 0x00,0x51,0x2e,0x08,0x08,0x08,0x51,0x31,0x40,0x00,0x55,0xe6,0xfb,0xef,0xbe,0xfb,
+ 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,
+ 0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,
+ 0xfb,0xef,0xbf,0xe1,0xff,0xf0,0x96,0x03,0x80,0x00,0x80,0xa8,0x00,0x08,0x0e,0x80,
+ 0x03,0x40,0x00,0x40,0x69,0x32,0xe5,0x1c,0xfa,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xc0,0x00,0x00,0x01,0x25,0x00,0x79,0xae,0x08,0x08,0x08,0x51,0x31,
+ 0x40,0x00,0x55,0xe6,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,
+ 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,
+ 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbf,0xe1,0xff,0xf0,0x96,0x03,
+ 0x80,0x00,0x80,0xa8,0x00,0x08,0x0e,0x80,0x03,0x40,0x00,0x40,0x69,0x32,0xe5,0x1c,
+ 0xfa,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xc0,0x00,0x00,0x01,0x25,
+ 0x00,0x28,0x8b,0x82,0x02,0x02,0x14,0x4c,0x50,0x00,0x15,0x79,0xbe,0xfb,0xef,0xbe,
+ 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,
+ 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,
+ 0xbe,0xfb,0xef,0xf8,0x7f,0xfc,0x25,0x80,0xe0,0x00,0x20,0x2a,0x00,0x02,0x03,0xa0,
+ 0x00,0xd0,0x00,0x10,0x1a,0x4c,0xb9,0x47,0x3e,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,
+ 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,
+ 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,
+ 0xeb,0xae,0xba,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
+static uint8_t uvd_decode_msg[] = {
+ 0xe4,0x0d,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x44,0x40,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x03,0x00,0x00,0xe0,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0xf9,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xc0,0x03,0x00,0x00,0x80,0x07,0x00,0x00,0x60,0x09,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x02,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x88,0x00,0x00,0x00,
+ 0x01,0x00,0x00,0x01,0x00,0x03,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
+static uint8_t uvd_destroy_msg[] = {
+ 0xe4,0x0d,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
+static uint8_t uvd_it_scaling_table[] = {
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+};
+
+#endif /* _uvd_messages_h_ */
diff --git a/tests/kmstest/main.c b/tests/kmstest/main.c
index 7d50f5b..f39364f 100644
--- a/tests/kmstest/main.c
+++ b/tests/kmstest/main.c
@@ -62,6 +62,7 @@ static const char *drivers[] = {
"nouveau",
"vmwgfx",
"exynos",
+ "amdgpu",
"imx-drm",
"rockchip",
NULL
--
1.8.3.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 1/2] drm: add libdrm_amdgpu
2015-04-21 16:39 [PATCH 1/2] drm: add libdrm_amdgpu Alex Deucher
2015-04-21 16:39 ` [PATCH 2/2] drm: add tests/amdgpu Alex Deucher
@ 2015-04-23 16:23 ` Emil Velikov
1 sibling, 0 replies; 3+ messages in thread
From: Emil Velikov @ 2015-04-23 16:23 UTC (permalink / raw)
To: Alex Deucher, dri-devel; +Cc: Alex Deucher, emil.l.velikov
Hi Alex,
On 21/04/15 16:39, Alex Deucher wrote:
> This is the new ioctl wrapper used by the new admgpu driver.
> It's primarily used by xf86-video-amdgpu and mesa.
>
Glad to see amdgpu finally out :-)
Can we annotate the private symbols with drm_private, in both
declaration and definition ? It will hide the symbols, plus will make
the leap towards Solaris support a bit smaller.
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> ---
> Makefile.am | 5 +
> amdgpu/Makefile.am | 55 ++
> amdgpu/amdgpu.h | 1278 ++++++++++++++++++++++++++++++++++++++++++++
> amdgpu/amdgpu_bo.c | 622 +++++++++++++++++++++
> amdgpu/amdgpu_cs.c | 981 ++++++++++++++++++++++++++++++++++
> amdgpu/amdgpu_device.c | 242 +++++++++
> amdgpu/amdgpu_gpu_info.c | 275 ++++++++++
> amdgpu/amdgpu_internal.h | 210 ++++++++
> amdgpu/amdgpu_vamgr.c | 169 ++++++
> amdgpu/libdrm_amdgpu.pc.in | 10 +
> amdgpu/util_double_list.h | 146 +++++
> amdgpu/util_hash.c | 382 +++++++++++++
> amdgpu/util_hash.h | 99 ++++
> amdgpu/util_hash_table.c | 257 +++++++++
> amdgpu/util_hash_table.h | 65 +++
> amdgpu/util_math.h | 32 ++
> configure.ac | 20 +
> include/drm/amdgpu_drm.h | 600 +++++++++++++++++++++
> 18 files changed, 5448 insertions(+)
> create mode 100644 amdgpu/Makefile.am
> create mode 100644 amdgpu/amdgpu.h
> create mode 100644 amdgpu/amdgpu_bo.c
> create mode 100644 amdgpu/amdgpu_cs.c
> create mode 100644 amdgpu/amdgpu_device.c
> create mode 100644 amdgpu/amdgpu_gpu_info.c
> create mode 100644 amdgpu/amdgpu_internal.h
> create mode 100644 amdgpu/amdgpu_vamgr.c
> create mode 100644 amdgpu/libdrm_amdgpu.pc.in
> create mode 100644 amdgpu/util_double_list.h
> create mode 100644 amdgpu/util_hash.c
> create mode 100644 amdgpu/util_hash.h
> create mode 100644 amdgpu/util_hash_table.c
> create mode 100644 amdgpu/util_hash_table.h
> create mode 100644 amdgpu/util_math.h
> create mode 100644 include/drm/amdgpu_drm.h
>
> --- /dev/null
> +++ b/amdgpu/Makefile.am
> +AM_CFLAGS = \
> + $(WARN_CFLAGS)
> -Wno-switch-enum \
From a quick look you should be OK without this. If that's not the case,
it might be worth looking into ?
> + -I$(top_srcdir) \
> + -I$(top_srcdir)/amdgpu \
You can drop this line.
> + $(PTHREADSTUBS_CFLAGS) \
> + -I$(top_srcdir)/include/drm
> +
> +libdrm_amdgpu_la_LTLIBRARIES = libdrm_amdgpu.la
> +libdrm_amdgpu_ladir = $(libdir)
> +libdrm_amdgpu_la_LDFLAGS = -version-number 1:0:1 -no-undefined
Considering that this is the first public version shouldn't this be 1:0:0 ?
> +libdrm_amdgpu_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
> +
> +libdrm_amdgpu_la_SOURCES = \
> + amdgpu_gpu_info.c \
> + amdgpu_device.c \
> + amdgpu_bo.c \
> + util_hash.c \
> + util_hash_table.c \
> + amdgpu_vamgr.c \
> + amdgpu_cs.c
> +
Please include all files, and sort them alphabetically, something like:
amdgpu_bo.c
amdgpu_cs.c
amdgpu_device.c
amdgpu_gpu_info.c
amdgpu_internal.h
amdgpu_vamgr.c
util_double_list.h
util_hash.c
util_hash.h
util_hash_table.c
util_hash_table.h
util_math.h
One might want to drop util_double_list.h if you go for my suggestion below.
> +nodist_EXTRA_libdrm_amdgpu_la_SOURCES = dummy.cxx
> +
There are no C++ sources or static libs based on such so you can drop this.
> +EXTRA_DIST = libdrm_amdgpu.pc.in
You don't need this.
> --- /dev/null
> +++ b/amdgpu/amdgpu.h
> +#ifndef _amdgpu_h_
> +#define _amdgpu_h_
> +
Capitalise the header guard name ?
> +#include <stdint.h>
> +#include <stdbool.h>
> +
Albeit not so common in libdrm, you can add make the header C++ safe.
#if defined(__cplusplus)
extern "C" {
#endif
> +struct amdgpu_bo_alloc_request {
> + /** Allocation request. It must be aligned correctly. */
> + uint64_t alloc_size;
> +
> + /**
> + * It may be required to have some specific alignment requirements
> + * for physical back-up storage (e.g. for displayable surface).
> + * If 0 there is no special alignment requirement
> + */
> + uint64_t phys_alignment;
> +
> + /**
> + * UMD should specify where to allocate memory and how it
> + * will be accessed by the CPU.
> + */
> + uint32_t preferred_heap;
> +
Worth adding a pad ?
> + /** Additional flags passed on allocation */
> + uint64_t flags;
> +};
> +struct amdgpu_bo_info {
> + /** Allocated memory size */
> + uint64_t alloc_size;
> +
> + /**
> + * It may be required to have some specific alignment requirements
> + * for physical back-up storage.
> + */
> + uint64_t phys_alignment;
> +
> + /**
> + * Assigned virtual MC Base Address.
> + * \note This information will be returned only if this buffer was
> + * allocated in the same process otherwise 0 will be returned.
> + */
> + uint64_t virtual_mc_base_address;
> +
> + /** Heap where to allocate memory. */
> + uint32_t preferred_heap;
> +
Ditto.
> + /** Additional allocation flags. */
> + uint64_t alloc_flags;
> +
> + /** Metadata associated with buffer if any. */
> + struct amdgpu_bo_metadata metadata;
> +};
> +struct amdgpu_gds_alloc_info {
> + /** Handle assigned to gds allocation */
> + amdgpu_bo_handle resource_handle;
> +
> + /** How much was really allocated */
> + uint32_t gds_memory_size;
> +
> + /** Number of GWS resources allocated */
> + uint32_t gws;
> +
> + /** Number of OA resources allocated */
> + uint32_t oa;
Ditto.
> +struct amdgpu_cs_ib_info {
> + /** Special flags */
> + uint64_t flags;
> +
> + /** Handle of command buffer */
> + amdgpu_ib_handle ib_handle;
> +
> + /**
> + * Size of Command Buffer to be submitted.
> + * - The size is in units of dwords (4 bytes).
> + * - Must be less or equal to the size of allocated IB
> + * - Could be 0
> + */
> + uint32_t size;
Ditto.
> +struct amdgpu_cs_request {
> + /** Specify flags with additional information */
> + uint64_t flags;
> +
> + /** Specify HW IP block type to which to send the IB. */
> + unsigned ip_type;
> +
> + /** IP instance index if there are several IPs of the same type. */
> + unsigned ip_instance;
> +
> + /**
> + * Specify ring index of the IP. We could have several rings
> + * in the same IP. E.g. 0 for SDMA0 and 1 for SDMA1.
> + */
> + uint32_t ring;
> +
> + /**
> + * Specify number of resource handles passed.
> + * Size of 'handles' array
> + *
> + */
> + uint32_t number_of_resources;
> +
> + /** Array of resources used by submission. */
> + amdgpu_bo_handle *resources;
> +
> + /** Array of resources flags. This is optional and can be NULL. */
> + uint8_t *resource_flags;
> +
> + /** Number of IBs to submit in the field ibs. */
> + uint32_t number_of_ibs;
> +
Ditto.
> + /**
> + * IBs to submit. Those IBs will be submit together as single entity
> + */
> + struct amdgpu_cs_ib_info *ibs;
> +};
> +
> +/**
> + * Structure describing request to check submission state using fence
> + *
> + * \sa amdgpu_cs_query_fence_status()
> + *
> +*/
> +struct amdgpu_cs_query_fence {
> +
> + /** In which context IB was sent to execution */
> + amdgpu_context_handle context;
> +
> + /** Timeout in nanoseconds. */
> + uint64_t timeout_ns;
> +
> + /** To which HW IP type the fence belongs */
> + unsigned ip_type;
> +
> + /** IP instance index if there are several IPs of the same type. */
> + unsigned ip_instance;
> +
> + /** Ring index of the HW IP */
> + uint32_t ring;
> +
Ditto.
> + /** Flags */
> + uint64_t flags;
> +
> + /** Specify fence for which we need to check
> + * submission status.*/
> + uint64_t fence;
> --- /dev/null
> +++ b/amdgpu/amdgpu_bo.c
> +#define _FILE_OFFSET_BITS 64
How about
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
If you feel against poluting all the C sources with it, you should
ensure that amdgpu_internal.h is included before any other header in
every source and header file.
> +int amdgpu_bo_cpu_map(amdgpu_bo_handle bo, void **cpu)
> +{
> + union drm_amdgpu_gem_mmap args;
> + void *ptr;
> + int r;
> +
> + pthread_mutex_lock(&bo->cpu_access_mutex);
> +
> + if (bo->cpu_ptr) {
> + /* already mapped */
> + assert(bo->cpu_map_count > 0);
> + bo->cpu_map_count++;
> + *cpu = bo->cpu_ptr;
> + pthread_mutex_unlock(&bo->cpu_access_mutex);
> + return 0;
> + }
> +
> + assert(bo->cpu_map_count == 0);
> +
> + memset(&args, 0, sizeof(args));
> +
> + /* Query the buffer address (args.addr_ptr).
> + * The kernel driver ignores the offset and size parameters. */
> + args.in.handle = bo->handle;
> +
> + r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_MMAP, &args,
> + sizeof(args));
> + if (r) {
> + pthread_mutex_unlock(&bo->cpu_access_mutex);
> + return r;
> + }
> +
> + /* Map the buffer. */
> + ptr = mmap(NULL, bo->alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED,
Please use drm_mmap/drm_munmap.
> --- /dev/null
> +++ b/amdgpu/amdgpu_cs.c
> +static int amdgpu_cs_create_ib(amdgpu_device_handle dev,
> + amdgpu_context_handle context,
> + enum amdgpu_cs_ib_size ib_size,
> + amdgpu_ib_handle *ib)
> +{
> + new_ib = malloc(sizeof(struct amdgpu_ib));
> + if (NULL == new_ib) {
Use new_ib == NULL or !new_ib ? There are a few other places that can do so.
> --- /dev/null
> +++ b/amdgpu/amdgpu_device.c
> +static unsigned fd_hash(void *key)
> +{
> + int fd = PTR_TO_UINT(key);
> + struct stat stat;
> + fstat(fd, &stat);
> +
> + if (!S_ISCHR(stat.st_mode))
> + return stat.st_dev ^ stat.st_ino;
I'm a bit puzzled, how is this possible ?
> + else
> + return stat.st_dev ^ (stat.st_rdev & RENDERNODE_MINOR_MASK);
I'm not 100% sure that there won't be any side-effects with the idea of
using primary and render node interchangeably.
Plus one cannot mask out to get from the primary device to the render
one, or vice-versa. The minor number is not reliable (rightfully so),
thus one can use drmGet(Primary|Render)DeviceNameFromFd or introduce
their fd counterpart.
> +}
> +
> +static int fd_compare(void *key1, void *key2)
> +{
> + int fd1 = PTR_TO_UINT(key1);
> + int fd2 = PTR_TO_UINT(key2);
> + struct stat stat1, stat2;
> + fstat(fd1, &stat1);
> + fstat(fd2, &stat2);
> +
> + if (!S_ISCHR(stat1.st_mode) || !S_ISCHR(stat2.st_mode))
> + return stat1.st_dev != stat2.st_dev ||
> + stat1.st_ino != stat2.st_ino;
> + else
> + return major(stat1.st_rdev) != major(stat2.st_rdev) ||
> + (minor(stat1.st_rdev) & RENDERNODE_MINOR_MASK) !=
> + (minor(stat2.st_rdev) & RENDERNODE_MINOR_MASK);
Same comments apply.
> +}
> +
> +/**
> +* Get the authenticated form fd,
> +*
> +* \param fd - \c [in] File descriptor for AMD GPU device
> +* \param auth - \c [out] Pointer to output the fd is authenticated or not
> +* A render node fd, output auth = 0
> +* A legacy fd, get the authenticated for compatibility root
> +*
> +* \return 0 on success\n
> +* >0 - AMD specific error code\n
> +* <0 - Negative POSIX Error code
> +*/
> +static int amdgpu_get_auth(int fd, int *auth)
> +{
> + int r = 0;
> + drm_client_t client;
> + struct stat stat1;
> + fstat(fd,&stat1);
> + if (minor(stat1.st_rdev) & ~RENDERNODE_MINOR_MASK)/* find a render node fd */
Please use drmGetNodeTypeFromFd().
> --- /dev/null
> +++ b/amdgpu/amdgpu_internal.h
> @@ -0,0 +1,210 @@
> +#ifndef _amdgpu_internal_h_
> +#define _amdgpu_internal_h_
> +
Capital letters for the header guard ?
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include <assert.h>
> +#include <pthread.h>
> +#include "xf86atomic.h"
> +#include "amdgpu.h"
> +#include "util_double_list.h"
> +
> +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
> +
Drop this and use util_math.h where needed ?
> +/**
> + * Increment src and decrement dst as if we were updating references
> + * for an assignment between 2 pointers of some objects.
> + *
> + * \return true if dst is 0
> + */
> +static inline bool update_references(atomic_t *dst, atomic_t *src)
> +{
> + if (dst != src) {
> + /* bump src first */
> + if (src) {
> + assert(atomic_read(src) > 0);
> + atomic_inc(src);
> + }
> + if (dst) {
> + assert(atomic_read(dst) > 0);
> + return atomic_dec_and_test(dst);
Am I imagining something or does the assert conditions look a bit strange ?
> diff --git a/amdgpu/util_double_list.h b/amdgpu/util_double_list.h
> new file mode 100644
> index 0000000..3f48ae2
> --- /dev/null
> +++ b/amdgpu/util_double_list.h
There are already two identical copies of this file - let's not add a
third one.
freedreno/list.h
tests/radeon/list.h
How about we move it one level up, and update the current users (incl.
Makefile.sources)
> --- /dev/null
> +++ b/amdgpu/util_hash.c
> --- /dev/null
> +++ b/amdgpu/util_hash_table.c
Can one use the existing drmHash functions like omap and freedreno ?
Would be nice to avoid going the mesa's route which iirc has four
different implementations.
> --- /dev/null
> +++ b/amdgpu/util_math.h
FWIW we can move this a level up, so that others can use it. Obviously
there is no reason to be part of this series.
> diff --git a/configure.ac b/configure.ac
> index 155d577..509f2d4 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -36,6 +36,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
>
> # Check for programs
> AC_PROG_CC
> +AC_PROG_CXX
>
There are no C++ sources, so you don't need a C++ compiler.
> @@ -236,6 +242,9 @@ if test "x$drm_cv_atomic_primitives" = "xnone"; then
> LIBDRM_ATOMICS_NOT_FOUND_MSG($RADEON, radeon, Radeon, radeon)
> RADEON=no
>
> + LIBDRM_ATOMICS_NOT_FOUND_MSG($AMDGPU, amdgpu, AMD, amdgpu)
> + AMDGPU=no
> +
Glad to see this, unlike the original copy/paste of an insanely long
message previously :)
> +if test "x$AMDGPU" = xyes; then
> + AC_DEFINE(HAVE_AMDGPU, 1, [Have amdgpu support])
> +fi
> +
Unless you're planning to add support to libkms you can drop this.
> diff --git a/include/drm/amdgpu_drm.h b/include/drm/amdgpu_drm.h
> new file mode 100644
> index 0000000..d248d77
> --- /dev/null
> +++ b/include/drm/amdgpu_drm.h
> +struct drm_amdgpu_cs_in {
> + /** Rendering context id */
> + uint32_t ctx_id;
> + /** Handle of resource list associated with CS */
> + uint32_t bo_list_handle;
> + uint32_t num_chunks;
> + uint32_t pad;
> + /* this points to uint64_t * which point to cs chunks */
> + uint64_t chunks;
> +};
> +
> +struct drm_amdgpu_cs_out {
> + uint64_t handle;
> +};
> +
> +union drm_amdgpu_cs {
> + struct drm_amdgpu_cs_in in;
> + struct drm_amdgpu_cs_out out;
> +};
> +
Don't think I've seen similar contruct in any of the other drm drivers.
(Genuenly curious) What benefit does it bring ?
I think you want to add a trailing padding for the following structures.
I'm thinking of a case where, old 64bit userspace feeds in the last u32
as rubbish, to the kernel while the latter uses an updated/expanded
struct. In such case the driver will either reject the request, or worse
use the rubbish data.
struct drm_amdgpu_gem_metadata
struct drm_amdgpu_wait_cs_in
struct drm_amdgpu_info_hw_ip
struct drm_amdgpu_info_device
Cheers
Emil
P.S. Based on the coding style seems like this is the combined work of
3+ developers. Anyway glad to see that it's out :-)
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2015-04-23 15:24 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-21 16:39 [PATCH 1/2] drm: add libdrm_amdgpu Alex Deucher
2015-04-21 16:39 ` [PATCH 2/2] drm: add tests/amdgpu Alex Deucher
2015-04-23 16:23 ` [PATCH 1/2] drm: add libdrm_amdgpu Emil Velikov
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.