Merge aosp/master into aosp/pie-gsi

BUG: 123765087
BUG: 123764798 (Milestone)
BUG: 77276633 (OKR)
Test: Builds
Change-Id: Id8c2e6140ac987f8dd1c0f189559459bbb51dbc3
diff --git a/.editorconfig b/.editorconfig
index 893b7be..29b4f39 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -17,3 +17,7 @@
 [*.m4]
 indent_style = space
 indent_size = 2
+
+[{meson.build,meson_options.txt}]
+indent_style = space
+indent_size = 2
diff --git a/.gitignore b/.gitignore
index d51e619..811348a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,3 @@
-bsd-core/*/@
-bsd-core/*/machine
-*~
 *.1
 *.3
 *.5
@@ -17,17 +14,22 @@
 *.o.cmd
 *.sw?
 *.trs
+*~
+.*check*
+.*install*
 .depend
 .deps
 .libs
 .tmp_versions
-.*check*
-.*install*
+/_build*
+/build*
 Makefile
 Makefile.in
 TAGS
 aclocal.m4
 autom4te.cache
+bsd-core/*/@
+bsd-core/*/machine
 build-aux
 bus_if.h
 compile
@@ -47,21 +49,22 @@
 export_syms
 i915.kld
 install-sh
-libdrm/config.h.in
 libdrm.pc
-libdrm_intel.pc
-libdrm_nouveau.pc
-libdrm_radeon.pc
-libdrm_omap.pc
+libdrm/config.h.in
+libdrm_amdgpu.pc
+libdrm_etnaviv.pc
 libdrm_exynos.pc
 libdrm_freedreno.pc
-libdrm_amdgpu.pc
+libdrm_intel.pc
+libdrm_nouveau.pc
+libdrm_omap.pc
+libdrm_radeon.pc
 libdrm_vc4.pc
-libdrm_etnaviv.pc
 libkms.pc
 libtool
 ltmain.sh
 mach64.kld
+man/*.3
 man/.man_fixup
 mga.kld
 missing
@@ -74,35 +77,34 @@
 sis.kld
 stamp-h1
 tdfx.kld
-via.kld
-tests/auth
 tests/amdgpu/amdgpu_test
+tests/auth
 tests/dristat
 tests/drmdevice
 tests/drmsl
 tests/drmstat
+tests/etnaviv/etnaviv_2d_test
+tests/etnaviv/etnaviv_bo_cache_test
+tests/etnaviv/etnaviv_cmd_stream_test
+tests/exynos/exynos_fimg2d_event
+tests/exynos/exynos_fimg2d_perf
+tests/exynos/exynos_fimg2d_test
 tests/getclient
 tests/getstats
 tests/getversion
 tests/hash
-tests/lock
-tests/openclose
-tests/random
-tests/setversion
-tests/updatedraw
-tests/modeprint/modeprint
-tests/modetest/modetest
-tests/name_from_fd
-tests/proptest/proptest
 tests/kms/kms-steal-crtc
 tests/kms/kms-universal-planes
 tests/kmstest/kmstest
-tests/vbltest/vbltest
+tests/lock
+tests/modeprint/modeprint
+tests/modetest/modetest
+tests/name_from_fd
+tests/openclose
+tests/proptest/proptest
 tests/radeon/radeon_ttm
-tests/exynos/exynos_fimg2d_event
-tests/exynos/exynos_fimg2d_perf
-tests/exynos/exynos_fimg2d_test
-tests/etnaviv/etnaviv_2d_test
-tests/etnaviv/etnaviv_cmd_stream_test
-tests/etnaviv/etnaviv_bo_cache_test
-man/*.3
+tests/random
+tests/setversion
+tests/updatedraw
+tests/vbltest/vbltest
+via.kld
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..a0edfdf
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,159 @@
+.artifacts-meson: &artifacts-meson
+  when: always
+  paths:
+   - _build/meson-logs
+
+.artifacts-autotools: &artifacts-autotools
+  when: always
+  paths:
+    - _build/*.log
+    - _build/*/*.log
+    - _build/*/*/*.log
+
+.meson-build: &meson-build
+  - meson _build
+      -D amdgpu=true
+      -D cairo-tests=true
+      -D etnaviv=true
+      -D exynos=true
+      -D freedreno=true
+      -D freedreno-kgsl=true
+      -D intel=true
+      -D libkms=true
+      -D man-pages=true
+      -D nouveau=true
+      -D omap=true
+      -D radeon=true
+      -D tegra=true
+      -D udev=true
+      -D valgrind=true
+      -D vc4=true
+      -D vmwgfx=true
+  - ninja -C _build
+  - ninja -C _build test
+
+.autotools-build: &autotools-build
+  - mkdir _build
+  - cd _build
+  - ../autogen.sh
+      --enable-udev
+      --enable-libkms
+      --enable-intel
+      --enable-radeon
+      --enable-amdgpu
+      --enable-nouveau
+      --enable-vmwgfx
+      --enable-omap-experimental-api
+      --enable-exynos-experimental-api
+      --enable-freedreno
+      --enable-freedreno-kgsl
+      --enable-tegra-experimental-api
+      --enable-vc4
+      --enable-etnaviv-experimental-api
+  - make
+  - make check
+
+latest-meson:
+  stage: build
+  image: base/archlinux:latest
+  before_script:
+    - pacman -Syu --noconfirm --needed
+        base-devel
+        meson
+        libpciaccess
+        libxslt docbook-xsl
+        valgrind
+        libatomic_ops
+        cairo cunit
+  script: *meson-build
+
+latest-autotools:
+  stage: build
+  image: base/archlinux:latest
+  artifacts: *artifacts-autotools
+  before_script:
+    - pacman -Syu --noconfirm --needed
+        base-devel
+        libpciaccess
+        libxslt docbook-xsl
+        valgrind
+        libatomic_ops
+        cairo cunit
+        xorg-util-macros
+        git # autogen.sh depends on git
+  script: *autotools-build
+
+oldest-meson:
+  stage: build
+  image: debian:stable
+  artifacts: *artifacts-meson
+  before_script:
+    - printf > /etc/dpkg/dpkg.cfg.d/99-exclude-cruft "%s\n"
+        'path-exclude=/usr/share/doc/*'
+        'path-exclude=/usr/share/man/*'
+    - printf > /usr/sbin/policy-rc.d "%s\n"
+        '#!/bin/sh'
+        'exit 101'
+    - chmod +x /usr/sbin/policy-rc.d
+    - apt-get update
+    - apt-get -y --no-install-recommends install
+        build-essential
+        pkg-config
+        xsltproc
+        libxslt1-dev docbook-xsl
+        valgrind
+        libatomic-ops-dev
+        libcairo2-dev libcunit1-dev
+        ninja-build
+        python3 python3-pip
+        wget
+    # We need `--no-check-certificate` here because Debian's CA list is
+    # too old to know about LetsEncrypt's CA, so it refuses to connect
+    # to FreeDesktop.org
+    - LIBPCIACCESS_VERSION=libpciaccess-0.10 &&
+      wget --no-check-certificate https://xorg.freedesktop.org/releases/individual/lib/$LIBPCIACCESS_VERSION.tar.bz2 &&
+      tar -jxvf $LIBPCIACCESS_VERSION.tar.bz2 &&
+      (cd $LIBPCIACCESS_VERSION && ./configure --prefix=$HOME/prefix && make install)
+    - pip3 install wheel setuptools
+    - pip3 install meson==0.43
+    - export PKG_CONFIG_PATH=$HOME/prefix/lib/pkgconfig:$HOME/prefix/share/pkgconfig
+    - export LD_LIBRARY_PATH="$HOME/prefix/lib:$LD_LIBRARY_PATH"
+  script: *meson-build
+
+oldest-autotools:
+  stage: build
+  image: debian:stable
+  artifacts: *artifacts-autotools
+  before_script:
+    - printf > /etc/dpkg/dpkg.cfg.d/99-exclude-cruft "%s\n"
+        'path-exclude=/usr/share/doc/*'
+        'path-exclude=/usr/share/man/*'
+    - printf > /usr/sbin/policy-rc.d "%s\n"
+        '#!/bin/sh'
+        'exit 101'
+    - chmod +x /usr/sbin/policy-rc.d
+    - apt-get update
+    - apt-get -y --no-install-recommends install
+        build-essential
+        automake
+        autoconf
+        libtool
+        pkg-config
+        xsltproc
+        libxslt1-dev docbook-xsl
+        valgrind
+        libatomic-ops-dev
+        libcairo2-dev libcunit1-dev
+        wget
+        xutils-dev
+        git # autogen.sh depends on git
+    # We need `--no-check-certificate` here because Debian's CA list is
+    # too old to know about LetsEncrypt's CA, so it refuses to connect
+    # to FreeDesktop.org
+    - LIBPCIACCESS_VERSION=libpciaccess-0.10 &&
+      wget --no-check-certificate https://xorg.freedesktop.org/releases/individual/lib/$LIBPCIACCESS_VERSION.tar.bz2 &&
+      tar -jxvf $LIBPCIACCESS_VERSION.tar.bz2 &&
+      (cd $LIBPCIACCESS_VERSION && ./configure --prefix=$HOME/prefix && make install)
+    - export PKG_CONFIG_PATH=$HOME/prefix/lib/pkgconfig:$HOME/prefix/share/pkgconfig
+    - export LD_LIBRARY_PATH="$HOME/prefix/lib:$LD_LIBRARY_PATH"
+  script: *autotools-build
diff --git a/Android.bp b/Android.bp
index 429c22c..9121068 100644
--- a/Android.bp
+++ b/Android.bp
@@ -54,7 +54,7 @@
         "libdrm_sources",
     ],
 
-    export_include_dirs: ["include/drm"],
+    export_include_dirs: ["include/drm", "android"],
 
     cflags: [
         "-Wno-enum-conversion",
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000..96f1e4f
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,105 @@
+Contributing to libdrm
+======================
+
+Submitting Patches
+------------------
+
+Patches should be sent to dri-devel@lists.freedesktop.org, using git
+send-email. For patches only touching driver specific code one of the driver
+mailing lists (like amd-gfx@lists.freedesktop.org) is also appropriate. See git
+documentation for help:
+
+http://git-scm.com/documentation
+
+Since dri-devel is a very busy mailing list please use --subject-prefix="PATCH
+libdrm" to make it easier to find libdrm patches. This is best done by running
+
+    git config --local format.subjectprefix "PATCH libdrm"
+
+The first line of a commit message should contain a prefix indicating what part
+is affected by the patch followed by one sentence that describes the change. For
+examples:
+
+    amdgpu: Use uint32_t i in amdgpu_find_bo_by_cpu_mapping
+
+The body of the commit message should describe what the patch changes and why,
+and also note any particular side effects. For a recommended reading on
+writing commit messages, see:
+
+http://who-t.blogspot.de/2009/12/on-commit-messages.html
+
+Your patches should also include a Signed-off-by line with your name and email
+address. If you're not the patch's original author, you should also gather
+S-o-b's by them (and/or whomever gave the patch to you.) The significance of
+this is that it certifies that you created the patch, that it was created under
+an appropriate open source license, or provided to you under those terms.  This
+lets us indicate a chain of responsibility for the copyright status of the code.
+For more details:
+
+https://developercertificate.org/
+
+We won't reject patches that lack S-o-b, but it is strongly recommended.
+
+Review and Merging
+------------------
+
+Patches should have at least one positive review (Reviewed-by: tag) or
+indication of approval (Acked-by: tag) before merging. For any code shared
+between drivers this is mandatory.
+
+Please note that kernel/userspace API header files have special rules, see
+include/drm/README.
+
+Coding style in the project loosely follows the CodingStyle of the linux kernel:
+
+https://www.kernel.org/doc/html/latest/process/coding-style.html?highlight=coding%20style
+
+Commit Rights
+-------------
+
+Commit rights will be granted to anyone who requests them and fulfills the
+below criteria:
+
+- Submitted a few (5-10 as a rule of thumb) non-trivial (not just simple
+  spelling fixes and whitespace adjustment) patches that have been merged
+  already. Since libdrm is just a glue library between the kernel and userspace
+  drivers, merged patches to those components also count towards the commit
+  criteria.
+
+- Are actively participating on discussions about their work (on the mailing
+  list or IRC). This should not be interpreted as a requirement to review other
+  peoples patches but just make sure that patch submission isn't one-way
+  communication. Cross-review is still highly encouraged.
+
+- Will be regularly contributing further patches. This includes regular
+  contributors to other parts of the open source graphics stack who only
+  do the oddball rare patch within libdrm itself.
+
+- Agrees to use their commit rights in accordance with the documented merge
+  criteria, tools, and processes.
+
+To apply for commit rights ("Developer" role in gitlab) send a mail to
+dri-devel@lists.freedesktop.org and please ping the maintainers if your request
+is stuck.
+
+Committers are encouraged to request their commit rights get removed when they
+no longer contribute to the project. Commit rights will be reinstated when they
+come back to the project.
+
+Maintainers and committers should encourage contributors to request commit
+rights, as especially junior contributors tend to underestimate their skills.
+
+Code of Conduct
+---------------
+
+Please be aware the fd.o Code of Conduct also applies to libdrm:
+
+https://www.freedesktop.org/wiki/CodeOfConduct/
+
+See the gitlab project owners for contact details of the libdrm maintainers.
+
+Abuse of commit rights, like engaging in commit fights or willfully pushing
+patches that violate the documented merge criteria, will also be handled through
+the Code of Conduct enforcement process.
+
+Happy hacking!
diff --git a/Makefile.am b/Makefile.am
index 2bf644b..730de1f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -96,10 +96,6 @@
 endif
 endif
 
-if HAVE_ROCKCHIP
-ROCKCHIP_SUBDIR = rockchip
-endif
-
 SUBDIRS = \
 	. \
 	$(LIBKMS_SUBDIR) \
@@ -113,9 +109,9 @@
 	$(TEGRA_SUBDIR) \
 	$(VC4_SUBDIR) \
 	$(ETNAVIV_SUBDIR) \
+	data \
 	tests \
-	$(MAN_SUBDIR) \
-	$(ROCKCHIP_SUBDIR)
+	$(MAN_SUBDIR)
 
 libdrm_la_LTLIBRARIES = libdrm.la
 libdrm_ladir = $(libdir)
@@ -125,6 +121,7 @@
 libdrm_la_CPPFLAGS = -I$(top_srcdir)/include/drm
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	$(VALGRIND_CFLAGS)
 
 libdrm_la_SOURCES = $(LIBDRM_FILES)
@@ -139,7 +136,37 @@
 klibdrminclude_HEADERS += $(LIBDRM_INCLUDE_VMWGFX_H_FILES)
 endif
 
-EXTRA_DIST = include/drm/README
+EXTRA_DIST = \
+	include/drm/README \
+	amdgpu/meson.build \
+	data/meson.build \
+	etnaviv/meson.build \
+	exynos/meson.build \
+	freedreno/meson.build \
+	intel/meson.build \
+	libkms/meson.build \
+	man/meson.build \
+	nouveau/meson.build \
+	omap/meson.build \
+	radeon/meson.build \
+	tegra/meson.build \
+	tests/amdgpu/meson.build \
+	tests/etnaviv/meson.build \
+	tests/exynos/meson.build \
+	tests/kms/meson.build \
+	tests/kmstest/meson.build \
+	tests/meson.build \
+	tests/modeprint/meson.build \
+	tests/modetest/meson.build \
+	tests/nouveau/meson.build \
+	tests/proptest/meson.build \
+	tests/radeon/meson.build \
+	tests/tegra/meson.build \
+	tests/util/meson.build \
+	tests/vbltest/meson.build \
+	vc4/meson.build \
+	meson.build \
+	meson_options.txt
 
 copy-headers :
 	cp -r $(kernel_source)/include/uapi/drm/*.h $(top_srcdir)/include/drm/
diff --git a/Makefile.sources b/Makefile.sources
index 10aa1d0..55290fe 100644
--- a/Makefile.sources
+++ b/Makefile.sources
@@ -25,6 +25,7 @@
 	include/drm/i915_drm.h \
 	include/drm/mach64_drm.h \
 	include/drm/mga_drm.h \
+	include/drm/msm_drm.h \
 	include/drm/nouveau_drm.h \
 	include/drm/qxl_drm.h \
 	include/drm/r128_drm.h \
@@ -37,5 +38,8 @@
 	include/drm/via_drm.h \
 	include/drm/virtgpu_drm.h
 
+LIBDRM_INCLUDE_ANDROID_H_FILES := \
+	android/gralloc_handle.h
+
 LIBDRM_INCLUDE_VMWGFX_H_FILES := \
 	include/drm/vmwgfx_drm.h
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..7b4c82d
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,5 @@
+# Default code reviewers picked from top 3 or more developers.
+# Please update this list if you find better candidates.
+adelva@google.com
+john.stultz@linaro.org
+seanpaul@google.com
diff --git a/README b/README
deleted file mode 100644
index 26cab9d..0000000
--- a/README
+++ /dev/null
@@ -1,41 +0,0 @@
-libdrm - userspace library for drm
-
-This  is libdrm,  a userspace  library for  accessing the  DRM, direct
-rendering  manager, on  Linux,  BSD and  other  operating systems that
-support the  ioctl interface.  The library  provides wrapper functions
-for the  ioctls to avoid  exposing the kernel interface  directly, and
-for chipsets with drm memory manager, support for tracking relocations
-and  buffers.   libdrm  is  a  low-level library,  typically  used  by
-graphics drivers  such as the Mesa  DRI drivers, the  X drivers, libva
-and  similar projects.  New  functionality in  the kernel  DRM drivers
-typically requires  a new  libdrm, but a  new libdrm will  always work
-with an older kernel.
-
-
-Compiling
----------
-
-libdrm  is  a  standard  autotools  package and  follows  the  normal
-configure, build  and install steps.   The first step is  to configure
-the package, which is done by running the configure shell script:
-
-	./configure
-
-By default, libdrm  will install into the /usr/local/  prefix.  If you
-want  to  install   this  DRM  to  replace  your   system  copy,  pass
---prefix=/usr and  --exec-prefix=/ to configure.  If  you are building
-libdrm  from a  git checkout,  you first  need to  run  the autogen.sh
-script.  You can  pass any options to autogen.sh  that you would other
-wise  pass to configure,  or you  can just  re-run configure  with the
-options you need once autogen.sh finishes.
-
-Next step is to build libdrm:
-
-	make
-
-and once make finishes successfully, install the package using
-
-	make install
-
-If you are installing into a system location, you will need to be root
-to perform the install step.
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..e47cb24
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,61 @@
+libdrm - userspace library for drm
+----------------------------------
+
+This is libdrm, a userspace library for accessing the DRM, direct rendering
+manager, on Linux, BSD and other operating systems that support the ioctl
+interface.
+The library provides wrapper functions for the ioctls to avoid exposing the
+kernel interface directly, and for chipsets with drm memory manager, support
+for tracking relocations and buffers.
+New functionality in the kernel DRM drivers typically requires a new libdrm,
+but a new libdrm will always work with an older kernel.
+
+libdrm is a low-level library, typically used by graphics drivers such as
+the Mesa drivers, the X drivers, libva and similar projects.
+
+
+Compiling
+---------
+
+libdrm has two build systems, a legacy autotools build system, and a newer
+meson build system. The meson build system is much faster, and offers a
+slightly different interface, but otherwise provides an equivalent feature set.
+
+To use it:
+
+    meson builddir/
+
+By default this will install into /usr/local, you can change your prefix
+with --prefix=/usr (or `meson configure builddir/ -Dprefix=/usr` after 
+the initial meson setup).
+
+Then use ninja to build and install:
+
+    ninja -C builddir/ install
+
+If you are installing into a system location you will need to run install
+separately, and as root.
+
+
+Alternatively you can invoke autotools configure:
+
+	./configure
+
+By default, libdrm  will install into the /usr/local/  prefix.  If you
+want  to  install   this  DRM  to  replace  your   system  copy,  pass
+--prefix=/usr and  --exec-prefix=/ to configure.  If  you are building
+libdrm  from a  git checkout,  you first  need to  run  the autogen.sh
+script.  You can  pass any options to autogen.sh  that you would other
+wise  pass to configure,  or you  can just  re-run configure  with the
+options you need once autogen.sh finishes.
+
+Next step is to build libdrm:
+
+	make
+
+and once make finishes successfully, install the package using
+
+	make install
+
+If you are installing into a system location, you will need to be root
+to perform the install step.
diff --git a/RELEASING b/RELEASING
index 262ca08..7e03e3b 100644
--- a/RELEASING
+++ b/RELEASING
@@ -9,9 +9,9 @@
 
 Follow these steps to release a new version of libdrm:
 
-  1) Bump the version number in configure.ac. We seem to have settled
-     for 2.4.x as the versioning scheme for libdrm, so just bump the
-     micro version.
+  1) Bump the version number in configure.ac and meson.build. We seem
+     to have settled for 2.4.x as the versioning scheme for libdrm, so
+     just bump the  micro version.
 
   2) Run autoconf and then re-run ./configure so the build system
      picks up the new version number.
diff --git a/amdgpu/.editorconfig b/amdgpu/.editorconfig
new file mode 100644
index 0000000..426273f
--- /dev/null
+++ b/amdgpu/.editorconfig
@@ -0,0 +1,13 @@
+# To use this config with your editor, follow the instructions at:
+# http://editorconfig.org
+
+[*]
+charset = utf-8
+indent_style = tab
+indent_size = 8
+tab_width = 8
+insert_final_newline = true
+
+[meson.build]
+indent_style = space
+indent_size = 2
diff --git a/amdgpu/Android.bp b/amdgpu/Android.bp
index a63b617..976f03e 100644
--- a/amdgpu/Android.bp
+++ b/amdgpu/Android.bp
@@ -2,6 +2,11 @@
 
 cc_library_shared {
     name: "libdrm_amdgpu",
+
+    cflags: [
+	"-DAMDGPU_ASIC_ID_TABLE=\"/vendor/etc/hwdata/amdgpu.ids\""
+    ],
+
     defaults: [
         "libdrm_defaults",
         "libdrm_amdgpu_sources",
diff --git a/amdgpu/Android.sources.bp b/amdgpu/Android.sources.bp
index 62b8f05..be85283 100644
--- a/amdgpu/Android.sources.bp
+++ b/amdgpu/Android.sources.bp
@@ -3,12 +3,13 @@
 cc_defaults {
     name: "libdrm_amdgpu_sources",
     srcs: [
+	"amdgpu_asic_id.c",
         "amdgpu_bo.c",
         "amdgpu_cs.c",
         "amdgpu_device.c",
         "amdgpu_gpu_info.c",
         "amdgpu_vamgr.c",
-        "util_hash.c",
-        "util_hash_table.c",
+	"amdgpu_vm.c",
+        "handle_table.c",
     ],
 }
diff --git a/amdgpu/Makefile.am b/amdgpu/Makefile.am
index cf7bc1b..ef8ab05 100644
--- a/amdgpu/Makefile.am
+++ b/amdgpu/Makefile.am
@@ -26,16 +26,21 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	-I$(top_srcdir)/include/drm
 
+libdrmdatadir = @libdrmdatadir@
+AM_CPPFLAGS = -DAMDGPU_ASIC_ID_TABLE=\"${libdrmdatadir}/amdgpu.ids\"
+
 libdrm_amdgpu_la_LTLIBRARIES = libdrm_amdgpu.la
 libdrm_amdgpu_ladir = $(libdir)
 libdrm_amdgpu_la_LDFLAGS = -version-number 1:0:0 -no-undefined
 libdrm_amdgpu_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
 
 libdrm_amdgpu_la_SOURCES = $(LIBDRM_AMDGPU_FILES)
+amdgpu_asic_id.lo: $(top_srcdir)/data/amdgpu.ids
 
 libdrm_amdgpuincludedir = ${includedir}/libdrm
 libdrm_amdgpuinclude_HEADERS = $(LIBDRM_AMDGPU_H_FILES)
@@ -43,5 +48,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_amdgpu.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = amdgpu-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/amdgpu/Makefile.sources b/amdgpu/Makefile.sources
index 487b9e0..d6df324 100644
--- a/amdgpu/Makefile.sources
+++ b/amdgpu/Makefile.sources
@@ -1,15 +1,14 @@
 LIBDRM_AMDGPU_FILES := \
-	amdgpu_asic_id.h \
+	amdgpu_asic_id.c \
 	amdgpu_bo.c \
 	amdgpu_cs.c \
 	amdgpu_device.c \
 	amdgpu_gpu_info.c \
 	amdgpu_internal.h \
 	amdgpu_vamgr.c \
-	util_hash.c \
-	util_hash.h \
-	util_hash_table.c \
-	util_hash_table.h
+	amdgpu_vm.c \
+	handle_table.c \
+	handle_table.h
 
 LIBDRM_AMDGPU_H_FILES := \
 	amdgpu.h
diff --git a/amdgpu/amdgpu-symbol-check b/amdgpu/amdgpu-symbol-check
index 87f4fd2..96a44b4 100755
--- a/amdgpu/amdgpu-symbol-check
+++ b/amdgpu/amdgpu-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.am/libdrm_amdgpuinclude_HEADERS
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_amdgpu.so} | awk '{print $3}' | while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_amdgpu.so} | awk '{print $3}' | while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
@@ -16,25 +18,48 @@
 amdgpu_bo_export
 amdgpu_bo_free
 amdgpu_bo_import
+amdgpu_bo_inc_ref
+amdgpu_bo_list_create_raw
+amdgpu_bo_list_destroy_raw
 amdgpu_bo_list_create
 amdgpu_bo_list_destroy
 amdgpu_bo_list_update
 amdgpu_bo_query_info
 amdgpu_bo_set_metadata
 amdgpu_bo_va_op
+amdgpu_bo_va_op_raw
 amdgpu_bo_wait_for_idle
 amdgpu_create_bo_from_user_mem
+amdgpu_cs_chunk_fence_info_to_data
+amdgpu_cs_chunk_fence_to_dep
 amdgpu_cs_create_semaphore
+amdgpu_cs_create_syncobj
+amdgpu_cs_create_syncobj2
 amdgpu_cs_ctx_create
+amdgpu_cs_ctx_create2
 amdgpu_cs_ctx_free
 amdgpu_cs_destroy_semaphore
+amdgpu_cs_destroy_syncobj
+amdgpu_cs_export_syncobj
+amdgpu_cs_fence_to_handle
+amdgpu_cs_import_syncobj
 amdgpu_cs_query_fence_status
 amdgpu_cs_query_reset_state
+amdgpu_query_sw_info
 amdgpu_cs_signal_semaphore
 amdgpu_cs_submit
+amdgpu_cs_submit_raw
+amdgpu_cs_submit_raw2
+amdgpu_cs_syncobj_export_sync_file
+amdgpu_cs_syncobj_import_sync_file
+amdgpu_cs_syncobj_reset
+amdgpu_cs_syncobj_signal
+amdgpu_cs_syncobj_wait
+amdgpu_cs_wait_fences
 amdgpu_cs_wait_semaphore
 amdgpu_device_deinitialize
 amdgpu_device_initialize
+amdgpu_find_bo_by_cpu_mapping
 amdgpu_get_marketing_name
 amdgpu_query_buffer_size_alignment
 amdgpu_query_crtc_from_id
@@ -45,10 +70,13 @@
 amdgpu_query_hw_ip_count
 amdgpu_query_hw_ip_info
 amdgpu_query_info
+amdgpu_query_sensor_info
 amdgpu_read_mm_registers
 amdgpu_va_range_alloc
 amdgpu_va_range_free
 amdgpu_va_range_query
+amdgpu_vm_reserve_vmid
+amdgpu_vm_unreserve_vmid
 EOF
 done)
 
diff --git a/amdgpu/amdgpu.h b/amdgpu/amdgpu.h
index 7b26a04..d6de3b8 100644
--- a/amdgpu/amdgpu.h
+++ b/amdgpu/amdgpu.h
@@ -37,7 +37,12 @@
 #include <stdint.h>
 #include <stdbool.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct drm_amdgpu_info_hw_ip;
+struct drm_amdgpu_bo_list_entry;
 
 /*--------------------------------------------------------------------------*/
 /* --------------------------- Defines ------------------------------------ */
@@ -80,7 +85,12 @@
 	amdgpu_bo_handle_type_kms = 1,
 
 	/** DMA-buf fd handle */
-	amdgpu_bo_handle_type_dma_buf_fd = 2
+	amdgpu_bo_handle_type_dma_buf_fd = 2,
+
+	/** KMS handle, but re-importing as a DMABUF handle through
+	 *  drmPrimeHandleToFD is forbidden. (Glamor does that)
+	 */
+	amdgpu_bo_handle_type_kms_noimport = 3,
 };
 
 /** Define known types of GPU VM VA ranges */
@@ -90,6 +100,10 @@
 	amdgpu_gpu_va_range_general = 0
 };
 
+enum amdgpu_sw_info {
+	amdgpu_sw_info_address32_hi = 0,
+};
+
 /*--------------------------------------------------------------------------*/
 /* -------------------------- Datatypes ----------------------------------- */
 /*--------------------------------------------------------------------------*/
@@ -665,6 +679,29 @@
 				    amdgpu_bo_handle *buf_handle);
 
 /**
+ * Validate if the user memory comes from BO
+ *
+ * \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 buf_handle - [out] Buffer handle for the userptr memory
+ * if the user memory is not from BO, the buf_handle will be NULL.
+ * \param offset_in_bo - [out] offset in this BO for this user memory
+ *
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_find_bo_by_cpu_mapping(amdgpu_device_handle dev,
+				  void *cpu,
+				  uint64_t size,
+				  amdgpu_bo_handle *buf_handle,
+				  uint64_t *offset_in_bo);
+
+/**
  * Free previosuly allocated memory
  *
  * \param   dev	       - \c [in] Device handle. See #amdgpu_device_initialize()
@@ -685,7 +722,17 @@
 int amdgpu_bo_free(amdgpu_bo_handle buf_handle);
 
 /**
- * Request CPU access to GPU accessible memory
+ * Increase the reference count of a buffer object
+ *
+ * \param   bo - \c [in]  Buffer object handle to increase the reference count
+ *
+ * \sa amdgpu_bo_alloc(), amdgpu_bo_free()
+ *
+*/
+void amdgpu_bo_inc_ref(amdgpu_bo_handle bo);
+
+/**
+ * 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
@@ -733,6 +780,37 @@
  *
  * \param   dev			- \c [in] Device handle.
  *				   See #amdgpu_device_initialize()
+ * \param   number_of_buffers	- \c [in] Number of BOs in the list
+ * \param   buffers		- \c [in] List of BO handles
+ * \param   result		- \c [out] Created BO list handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_list_destroy_raw(), amdgpu_cs_submit_raw2()
+*/
+int amdgpu_bo_list_create_raw(amdgpu_device_handle dev,
+			      uint32_t number_of_buffers,
+			      struct drm_amdgpu_bo_list_entry *buffers,
+			      uint32_t *result);
+
+/**
+ * Destroys a BO list handle.
+ *
+ * \param   bo_list	- \c [in] BO list handle.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_list_create_raw(), amdgpu_cs_submit_raw2()
+*/
+int amdgpu_bo_list_destroy_raw(amdgpu_device_handle dev, uint32_t bo_list);
+
+/**
+ * Creates a BO list handle for command submission.
+ *
+ * \param   dev			- \c [in] Device handle.
+ *				   See #amdgpu_device_initialize()
  * \param   number_of_resources	- \c [in] Number of BOs in the list
  * \param   resources		- \c [in] List of BO handles
  * \param   resource_prios	- \c [in] Optional priority for each handle
@@ -794,8 +872,9 @@
  * 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
+ * \param   dev      - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param   priority - \c [in] Context creation flags. See AMDGPU_CTX_PRIORITY_*
+ * \param   context  - \c [out] GPU Context handle
  *
  * \return   0 on success\n
  *          <0 - Negative POSIX Error code
@@ -803,6 +882,18 @@
  * \sa amdgpu_cs_ctx_free()
  *
 */
+int amdgpu_cs_ctx_create2(amdgpu_device_handle dev,
+			 uint32_t priority,
+			 amdgpu_context_handle *context);
+/**
+ * Create GPU execution Context
+ *
+ * Refer to amdgpu_cs_ctx_create2 for full documentation. This call
+ * is missing the priority parameter.
+ *
+ * \sa amdgpu_cs_ctx_create2()
+ *
+*/
 int amdgpu_cs_ctx_create(amdgpu_device_handle dev,
 			 amdgpu_context_handle *context);
 
@@ -907,6 +998,29 @@
 				 uint64_t flags,
 				 uint32_t *expired);
 
+/**
+ *  Wait for multiple fences
+ *
+ * \param   fences      - \c [in] The fence array to wait
+ * \param   fence_count - \c [in] The fence count
+ * \param   wait_all    - \c [in] If true, wait all fences to be signaled,
+ *                                otherwise, wait at least one fence
+ * \param   timeout_ns  - \c [in] The timeout to wait, in nanoseconds
+ * \param   status      - \c [out] '1' for signaled, '0' for timeout
+ * \param   first       - \c [out] the index of the first signaled fence from @fences
+ *
+ * \return  0 on success
+ *          <0 - Negative POSIX Error code
+ *
+ * \note    Currently it supports only one amdgpu_device. All fences come from
+ *          the same amdgpu_device with the same fd.
+*/
+int amdgpu_cs_wait_fences(struct amdgpu_cs_fence *fences,
+			  uint32_t fence_count,
+			  bool wait_all,
+			  uint64_t timeout_ns,
+			  uint32_t *status, uint32_t *first);
+
 /*
  * Query / Info API
  *
@@ -1046,6 +1160,23 @@
 		      unsigned size, void *value);
 
 /**
+ * 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    - \c [in] amdgpu_sw_info_*
+ * \param   value   - \c [out] Pointer to the return value.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX error code
+ *
+*/
+int amdgpu_query_sw_info(amdgpu_device_handle dev, enum amdgpu_sw_info info,
+			 void *value);
+
+/**
  * Query information about GDS
  *
  * \param   dev	     - \c [in] Device handle. See #amdgpu_device_initialize()
@@ -1059,6 +1190,24 @@
 			struct amdgpu_gds_resource_info *gds_info);
 
 /**
+ * Query information about sensor.
+ *
+ * The return size is query-specific and depends on the "sensor_type"
+ * parameter. No more than "size" bytes is returned.
+ *
+ * \param   dev         - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param   sensor_type - \c [in] AMDGPU_INFO_SENSOR_*
+ * \param   size        - \c [in] Size of the returned value.
+ * \param   value       - \c [out] Pointer to the return value.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_query_sensor_info(amdgpu_device_handle dev, unsigned sensor_type,
+			     unsigned size, void *value);
+
+/**
  * Read a set of consecutive memory-mapped registers.
  * Not all registers are allowed to be read by userspace.
  *
@@ -1083,6 +1232,7 @@
  * Flag to request VA address range in the 32bit address space
 */
 #define AMDGPU_VA_RANGE_32_BIT		0x1
+#define AMDGPU_VA_RANGE_HIGH		0x2
 
 /**
  * Allocate virtual address range
@@ -1186,6 +1336,34 @@
 		    uint32_t ops);
 
 /**
+ *  VA mapping/unmapping for a buffer object or PRT region.
+ *
+ * This is not a simple drop-in extension for amdgpu_bo_va_op; instead, all
+ * parameters are treated "raw", i.e. size is not automatically aligned, and
+ * all flags must be specified explicitly.
+ *
+ * \param  dev		- \c [in] device handle
+ * \param  bo		- \c [in] BO handle (may be NULL)
+ * \param  offset	- \c [in] Start offset to map
+ * \param  size		- \c [in] Size to map
+ * \param  addr		- \c [in] Start virtual address.
+ * \param  flags	- \c [in] Supported flags for mapping/unmapping
+ * \param  ops		- \c [in] AMDGPU_VA_OP_MAP or AMDGPU_VA_OP_UNMAP
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+
+int amdgpu_bo_va_op_raw(amdgpu_device_handle dev,
+			amdgpu_bo_handle bo,
+			uint64_t offset,
+			uint64_t size,
+			uint64_t addr,
+			uint64_t flags,
+			uint32_t ops);
+
+/**
  *  create semaphore
  *
  * \param   sem	   - \c [out] semaphore handle
@@ -1255,4 +1433,238 @@
 */
 const char *amdgpu_get_marketing_name(amdgpu_device_handle dev);
 
+/**
+ *  Create kernel sync object
+ *
+ * \param   dev         - \c [in]  device handle
+ * \param   flags       - \c [in]  flags that affect creation
+ * \param   syncobj     - \c [out] sync object handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_create_syncobj2(amdgpu_device_handle dev,
+			      uint32_t  flags,
+			      uint32_t *syncobj);
+
+/**
+ *  Create kernel sync object
+ *
+ * \param   dev	      - \c [in]  device handle
+ * \param   syncobj   - \c [out] sync object handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_create_syncobj(amdgpu_device_handle dev,
+			     uint32_t *syncobj);
+/**
+ *  Destroy kernel sync object
+ *
+ * \param   dev	    - \c [in] device handle
+ * \param   syncobj - \c [in] sync object handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_destroy_syncobj(amdgpu_device_handle dev,
+			      uint32_t syncobj);
+
+/**
+ * Reset kernel sync objects to unsignalled state.
+ *
+ * \param dev           - \c [in] device handle
+ * \param syncobjs      - \c [in] array of sync object handles
+ * \param syncobj_count - \c [in] number of handles in syncobjs
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_syncobj_reset(amdgpu_device_handle dev,
+			    const uint32_t *syncobjs, uint32_t syncobj_count);
+
+/**
+ * Signal kernel sync objects.
+ *
+ * \param dev           - \c [in] device handle
+ * \param syncobjs      - \c [in] array of sync object handles
+ * \param syncobj_count - \c [in] number of handles in syncobjs
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_syncobj_signal(amdgpu_device_handle dev,
+			     const uint32_t *syncobjs, uint32_t syncobj_count);
+
+/**
+ *  Wait for one or all sync objects to signal.
+ *
+ * \param   dev	    - \c [in] self-explanatory
+ * \param   handles - \c [in] array of sync object handles
+ * \param   num_handles - \c [in] self-explanatory
+ * \param   timeout_nsec - \c [in] self-explanatory
+ * \param   flags   - \c [in] a bitmask of DRM_SYNCOBJ_WAIT_FLAGS_*
+ * \param   first_signaled - \c [in] self-explanatory
+ *
+ * \return   0 on success\n
+ *          -ETIME - Timeout
+ *          <0 - Negative POSIX Error code
+ *
+ */
+int amdgpu_cs_syncobj_wait(amdgpu_device_handle dev,
+			   uint32_t *handles, unsigned num_handles,
+			   int64_t timeout_nsec, unsigned flags,
+			   uint32_t *first_signaled);
+
+/**
+ *  Export kernel sync object to shareable fd.
+ *
+ * \param   dev	       - \c [in] device handle
+ * \param   syncobj    - \c [in] sync object handle
+ * \param   shared_fd  - \c [out] shared file descriptor.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_export_syncobj(amdgpu_device_handle dev,
+			     uint32_t syncobj,
+			     int *shared_fd);
+/**
+ *  Import kernel sync object from shareable fd.
+ *
+ * \param   dev	       - \c [in] device handle
+ * \param   shared_fd  - \c [in] shared file descriptor.
+ * \param   syncobj    - \c [out] sync object handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_import_syncobj(amdgpu_device_handle dev,
+			     int shared_fd,
+			     uint32_t *syncobj);
+
+/**
+ *  Export kernel sync object to a sync_file.
+ *
+ * \param   dev	       - \c [in] device handle
+ * \param   syncobj    - \c [in] sync object handle
+ * \param   sync_file_fd - \c [out] sync_file file descriptor.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+ */
+int amdgpu_cs_syncobj_export_sync_file(amdgpu_device_handle dev,
+				       uint32_t syncobj,
+				       int *sync_file_fd);
+
+/**
+ *  Import kernel sync object from a sync_file.
+ *
+ * \param   dev	       - \c [in] device handle
+ * \param   syncobj    - \c [in] sync object handle
+ * \param   sync_file_fd - \c [in] sync_file file descriptor.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+ */
+int amdgpu_cs_syncobj_import_sync_file(amdgpu_device_handle dev,
+				       uint32_t syncobj,
+				       int sync_file_fd);
+
+/**
+ * Export an amdgpu fence as a handle (syncobj or fd).
+ *
+ * \param what		AMDGPU_FENCE_TO_HANDLE_GET_{SYNCOBJ, FD}
+ * \param out_handle	returned handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ */
+int amdgpu_cs_fence_to_handle(amdgpu_device_handle dev,
+			      struct amdgpu_cs_fence *fence,
+			      uint32_t what,
+			      uint32_t *out_handle);
+
+/**
+ *  Submit raw command submission to kernel
+ *
+ * \param   dev	       - \c [in] device handle
+ * \param   context    - \c [in] context handle for context id
+ * \param   bo_list_handle - \c [in] request bo list handle (0 for none)
+ * \param   num_chunks - \c [in] number of CS chunks to submit
+ * \param   chunks     - \c [in] array of CS chunks
+ * \param   seq_no     - \c [out] output sequence number for submission.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+ */
+struct drm_amdgpu_cs_chunk;
+struct drm_amdgpu_cs_chunk_dep;
+struct drm_amdgpu_cs_chunk_data;
+
+int amdgpu_cs_submit_raw(amdgpu_device_handle dev,
+			 amdgpu_context_handle context,
+			 amdgpu_bo_list_handle bo_list_handle,
+			 int num_chunks,
+			 struct drm_amdgpu_cs_chunk *chunks,
+			 uint64_t *seq_no);
+
+/**
+ * Submit raw command submission to the kernel with a raw BO list handle.
+ *
+ * \param   dev	       - \c [in] device handle
+ * \param   context    - \c [in] context handle for context id
+ * \param   bo_list_handle - \c [in] raw bo list handle (0 for none)
+ * \param   num_chunks - \c [in] number of CS chunks to submit
+ * \param   chunks     - \c [in] array of CS chunks
+ * \param   seq_no     - \c [out] output sequence number for submission.
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+ * \sa amdgpu_bo_list_create_raw(), amdgpu_bo_list_destroy_raw()
+ */
+int amdgpu_cs_submit_raw2(amdgpu_device_handle dev,
+			  amdgpu_context_handle context,
+			  uint32_t bo_list_handle,
+			  int num_chunks,
+			  struct drm_amdgpu_cs_chunk *chunks,
+			  uint64_t *seq_no);
+
+void amdgpu_cs_chunk_fence_to_dep(struct amdgpu_cs_fence *fence,
+				  struct drm_amdgpu_cs_chunk_dep *dep);
+void amdgpu_cs_chunk_fence_info_to_data(struct amdgpu_cs_fence_info *fence_info,
+					struct drm_amdgpu_cs_chunk_data *data);
+
+/**
+ * Reserve VMID
+ * \param   context - \c [in]  GPU Context
+ * \param   flags - \c [in]  TBD
+ *
+ * \return  0 on success otherwise POSIX Error code
+*/
+int amdgpu_vm_reserve_vmid(amdgpu_device_handle dev, uint32_t flags);
+
+/**
+ * Free reserved VMID
+ * \param   context - \c [in]  GPU Context
+ * \param   flags - \c [in]  TBD
+ *
+ * \return  0 on success otherwise POSIX Error code
+*/
+int amdgpu_vm_unreserve_vmid(amdgpu_device_handle dev, uint32_t flags);
+
+#ifdef __cplusplus
+}
+#endif
 #endif /* #ifdef _AMDGPU_H_ */
diff --git a/amdgpu/amdgpu_asic_id.c b/amdgpu/amdgpu_asic_id.c
new file mode 100644
index 0000000..a5007ff
--- /dev/null
+++ b/amdgpu/amdgpu_asic_id.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright © 2017 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "xf86drm.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+
+static int parse_one_line(struct amdgpu_device *dev, const char *line)
+{
+	char *buf, *saveptr;
+	char *s_did;
+	uint32_t did;
+	char *s_rid;
+	uint32_t rid;
+	char *s_name;
+	char *endptr;
+	int r = -EINVAL;
+
+	/* ignore empty line and commented line */
+	if (strlen(line) == 0 || line[0] == '#')
+		return -EAGAIN;
+
+	buf = strdup(line);
+	if (!buf)
+		return -ENOMEM;
+
+	/* device id */
+	s_did = strtok_r(buf, ",", &saveptr);
+	if (!s_did)
+		goto out;
+
+	did = strtol(s_did, &endptr, 16);
+	if (*endptr)
+		goto out;
+
+	if (did != dev->info.asic_id) {
+		r = -EAGAIN;
+		goto out;
+	}
+
+	/* revision id */
+	s_rid = strtok_r(NULL, ",", &saveptr);
+	if (!s_rid)
+		goto out;
+
+	rid = strtol(s_rid, &endptr, 16);
+	if (*endptr)
+		goto out;
+
+	if (rid != dev->info.pci_rev_id) {
+		r = -EAGAIN;
+		goto out;
+	}
+
+	/* marketing name */
+	s_name = strtok_r(NULL, ",", &saveptr);
+	if (!s_name)
+		goto out;
+
+	/* trim leading whitespaces or tabs */
+	while (isblank(*s_name))
+		s_name++;
+	if (strlen(s_name) == 0)
+		goto out;
+
+	dev->marketing_name = strdup(s_name);
+	if (dev->marketing_name)
+		r = 0;
+	else
+		r = -ENOMEM;
+
+out:
+	free(buf);
+
+	return r;
+}
+
+void amdgpu_parse_asic_ids(struct amdgpu_device *dev)
+{
+	FILE *fp;
+	char *line = NULL;
+	size_t len = 0;
+	ssize_t n;
+	int line_num = 1;
+	int r = 0;
+
+	fp = fopen(AMDGPU_ASIC_ID_TABLE, "r");
+	if (!fp) {
+		fprintf(stderr, "%s: %s\n", AMDGPU_ASIC_ID_TABLE,
+			strerror(errno));
+		return;
+	}
+
+	/* 1st valid line is file version */
+	while ((n = getline(&line, &len, fp)) != -1) {
+		/* trim trailing newline */
+		if (line[n - 1] == '\n')
+			line[n - 1] = '\0';
+
+		/* ignore empty line and commented line */
+		if (strlen(line) == 0 || line[0] == '#') {
+			line_num++;
+			continue;
+		}
+
+		drmMsg("%s version: %s\n", AMDGPU_ASIC_ID_TABLE, line);
+		break;
+	}
+
+	while ((n = getline(&line, &len, fp)) != -1) {
+		/* trim trailing newline */
+		if (line[n - 1] == '\n')
+			line[n - 1] = '\0';
+
+		r = parse_one_line(dev, line);
+		if (r != -EAGAIN)
+			break;
+
+		line_num++;
+	}
+
+	if (r == -EINVAL) {
+		fprintf(stderr, "Invalid format: %s: line %d: %s\n",
+			AMDGPU_ASIC_ID_TABLE, line_num, line);
+	} else if (r && r != -EAGAIN) {
+		fprintf(stderr, "%s: Cannot parse ASIC IDs: %s\n",
+			__func__, strerror(-r));
+	}
+
+	free(line);
+	fclose(fp);
+}
diff --git a/amdgpu/amdgpu_asic_id.h b/amdgpu/amdgpu_asic_id.h
deleted file mode 100644
index 3e7d736..0000000
--- a/amdgpu/amdgpu_asic_id.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright © 2016 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_ASIC_ID_H__
-#define __AMDGPU_ASIC_ID_H__
-
-static struct amdgpu_asic_id_table_t {
-	uint32_t did;
-	uint32_t rid;
-	const char *marketing_name;
-} const amdgpu_asic_id_table [] = {
-	{0x6600,	0x0,	"AMD Radeon HD 8600/8700M"},
-	{0x6600,	0x81,	"AMD Radeon R7 M370"},
-	{0x6601,	0x0,	"AMD Radeon HD 8500M/8700M"},
-	{0x6604,	0x0,	"AMD Radeon R7 M265 Series"},
-	{0x6604,	0x81,	"AMD Radeon R7 M350"},
-	{0x6605,	0x0,	"AMD Radeon R7 M260 Series"},
-	{0x6605,	0x81,	"AMD Radeon R7 M340"},
-	{0x6606,	0x0,	"AMD Radeon HD 8790M"},
-	{0x6607,	0x0,	"AMD Radeon HD8530M"},
-	{0x6608,	0x0,	"AMD FirePro W2100"},
-	{0x6610,	0x0,	"AMD Radeon HD 8600 Series"},
-	{0x6610,	0x81,	"AMD Radeon R7 350"},
-	{0x6610,	0x83,	"AMD Radeon R5 340"},
-	{0x6611,	0x0,	"AMD Radeon HD 8500 Series"},
-	{0x6613,	0x0,	"AMD Radeon HD 8500 series"},
-	{0x6617,	0xC7,	"AMD Radeon R7 240 Series"},
-	{0x6640,	0x0,	"AMD Radeon HD 8950"},
-	{0x6640,	0x80,	"AMD Radeon R9 M380"},
-	{0x6646,	0x0,	"AMD Radeon R9 M280X"},
-	{0x6646,	0x80,	"AMD Radeon R9 M470X"},
-	{0x6647,	0x0,	"AMD Radeon R9 M270X"},
-	{0x6647,	0x80,	"AMD Radeon R9 M380"},
-	{0x6649,	0x0,	"AMD FirePro W5100"},
-	{0x6658,	0x0,	"AMD Radeon R7 200 Series"},
-	{0x665C,	0x0,	"AMD Radeon HD 7700 Series"},
-	{0x665D,	0x0,	"AMD Radeon R7 200 Series"},
-	{0x665F,	0x81,	"AMD Radeon R7 300 Series"},
-	{0x6660,	0x0,	"AMD Radeon HD 8600M Series"},
-	{0x6660,	0x81,	"AMD Radeon R5 M335"},
-	{0x6660,	0x83,	"AMD Radeon R5 M330"},
-	{0x6663,	0x0,	"AMD Radeon HD 8500M Series"},
-	{0x6663,	0x83,	"AMD Radeon R5 M320"},
-	{0x6664,	0x0,	"AMD Radeon R5 M200 Series"},
-	{0x6665,	0x0,	"AMD Radeon R5 M200 Series"},
-	{0x6665,	0x83,	"AMD Radeon R5 M320"},
-	{0x6667,	0x0,	"AMD Radeon R5 M200 Series"},
-	{0x666F,	0x0,	"AMD Radeon HD 8500M"},
-	{0x6780,	0x0,	"ATI FirePro V (FireGL V) Graphics Adapter"},
-	{0x678A,	0x0,	"ATI FirePro V (FireGL V) Graphics Adapter"},
-	{0x6798,	0x0,	"AMD Radeon HD 7900 Series"},
-	{0x679A,	0x0,	"AMD Radeon HD 7900 Series"},
-	{0x679B,	0x0,	"AMD Radeon HD 7900 Series"},
-	{0x679E,	0x0,	"AMD Radeon HD 7800 Series"},
-	{0x67A0,	0x0,	"HAWAII XTGL (67A0)"},
-	{0x67A1,	0x0,	"HAWAII GL40 (67A1)"},
-	{0x67B0,	0x0,	"AMD Radeon R9 200 Series"},
-	{0x67B0,	0x80,	"AMD Radeon R9 390 Series"},
-	{0x67B1,	0x0,	"AMD Radeon R9 200 Series"},
-	{0x67B1,	0x80,	"AMD Radeon R9 390 Series"},
-	{0x67B9,	0x0,	"AMD Radeon R9 200 Series"},
-	{0x67DF,	0xC4,	"AMD Radeon RX 480 Graphics"},
-	{0x67DF,	0xC5,	"AMD Radeon RX 470 Graphics"},
-	{0x67DF,	0xC7,	"AMD Radeon RX 480 Graphics"},
-	{0x67DF,	0xCF,	"AMD Radeon RX 470 Graphics"},
-	{0x67C4,	0x00,	"AMD Radeon Pro WX 7100 Graphics"},
-	{0x67C7,	0x00,	"AMD Radeon Pro WX 5100 Graphics"},
-	{0x67C0,	0x00,	"AMD Radeon Pro WX 7100 Graphics"},
-	{0x67E0,	0x00,	"AMD Radeon Pro WX Series Graphics"},
-	{0x67E3,	0x00,	"AMD Radeon Pro WX 4100 Graphics"},
-	{0x67E8,	0x00,	"AMD Radeon Pro WX Series Graphics"},
-	{0x67E8,	0x01,	"AMD Radeon Pro WX Series Graphics"},
-	{0x67E8,	0x80,	"AMD Radeon E9260 Graphics"},
-	{0x67EB,	0x00,	"AMD Radeon Pro WX Series Graphics"},
-	{0x67EF,	0xC0,	"AMD Radeon RX Graphics"},
-	{0x67EF,	0xC1,	"AMD Radeon RX 460 Graphics"},
-	{0x67EF,	0xC5,	"AMD Radeon RX 460 Graphics"},
-	{0x67EF,	0xC7,	"AMD Radeon RX Graphics"},
-	{0x67EF,	0xCF,	"AMD Radeon RX 460 Graphics"},
-	{0x67EF,	0xEF,	"AMD Radeon RX Graphics"},
-	{0x67FF,	0xC0,	"AMD Radeon RX Graphics"},
-	{0x67FF,	0xC1,	"AMD Radeon RX Graphics"},
-	{0x6800,	0x0,	"AMD Radeon HD 7970M"},
-	{0x6801,	0x0,	"AMD Radeon(TM) HD8970M"},
-	{0x6808,	0x0,	"ATI FirePro V(FireGL V) Graphics Adapter"},
-	{0x6809,	0x0,	"ATI FirePro V(FireGL V) Graphics Adapter"},
-	{0x6810,	0x0,	"AMD Radeon(TM) HD 8800 Series"},
-	{0x6810,	0x81,	"AMD Radeon R7 370 Series"},
-	{0x6811,	0x0,	"AMD Radeon(TM) HD8800 Series"},
-	{0x6811,	0x81,	"AMD Radeon R7 300 Series"},
-	{0x6818,	0x0,	"AMD Radeon HD 7800 Series"},
-	{0x6819,	0x0,	"AMD Radeon HD 7800 Series"},
-	{0x6820,	0x0,	"AMD Radeon HD 8800M Series"},
-	{0x6820,	0x81,	"AMD Radeon R9 M375"},
-	{0x6820,	0x83,	"AMD Radeon R9 M375X"},
-	{0x6821,	0x0,	"AMD Radeon HD 8800M Series"},
-	{0x6821,	0x87,	"AMD Radeon R7 M380"},
-	{0x6821,	0x83,	"AMD Radeon R9 M370X"},
-	{0x6822,	0x0,	"AMD Radeon E8860"},
-	{0x6823,	0x0,	"AMD Radeon HD 8800M Series"},
-	{0x6825,	0x0,	"AMD Radeon HD 7800M Series"},
-	{0x6827,	0x0,	"AMD Radeon HD 7800M Series"},
-	{0x6828,	0x0,	"ATI FirePro V(FireGL V) Graphics Adapter"},
-	{0x682B,	0x0,	"AMD Radeon HD 8800M Series"},
-	{0x682B,	0x87,	"AMD Radeon R9 M360"},
-	{0x682C,	0x0,	"AMD FirePro W4100"},
-	{0x682D,	0x0,	"AMD Radeon HD 7700M Series"},
-	{0x682F,	0x0,	"AMD Radeon HD 7700M Series"},
-	{0x6835,	0x0,	"AMD Radeon R7 Series / HD 9000 Series"},
-	{0x6837,	0x0,	"AMD Radeon HD7700 Series"},
-	{0x683D,	0x0,	"AMD Radeon HD 7700 Series"},
-	{0x683F,	0x0,	"AMD Radeon HD 7700 Series"},
-	{0x6900,	0x0,	"AMD Radeon R7 M260"},
-	{0x6900,	0x81,	"AMD Radeon R7 M360"},
-	{0x6900,	0x83,	"AMD Radeon R7 M340"},
-	{0x6901,	0x0,	"AMD Radeon R5 M255"},
-	{0x6907,	0x0,	"AMD Radeon R5 M255"},
-	{0x6907,	0x87,	"AMD Radeon R5 M315"},
-	{0x6920,	0x0,	"AMD Radeon R9 M395X"},
-	{0x6920,	0x1,	"AMD Radeon R9 M390X"},
-	{0x6921,	0x0,	"AMD Radeon R9 M295X"},
-	{0x6929,	0x0,	"AMD FirePro S7150"},
-	{0x692B,	0x0,	"AMD FirePro W7100"},
-	{0x6938,	0x0,	"AMD Radeon R9 200 Series"},
-	{0x6938,	0xF0,	"AMD Radeon R9 200 Series"},
-	{0x6938,	0xF1,	"AMD Radeon R9 380 Series"},
-	{0x6939,	0xF0,	"AMD Radeon R9 200 Series"},
-	{0x6939,	0x0,	"AMD Radeon R9 200 Series"},
-	{0x6939,	0xF1,	"AMD Radeon R9 380 Series"},
-	{0x7300,	0xC8,	"AMD Radeon R9 Fury Series"},
-	{0x7300,	0xCB,	"AMD Radeon R9 Fury Series"},
-	{0x7300,	0xCA,	"AMD Radeon R9 Fury Series"},
-	{0x9874,	0xC4,	"AMD Radeon R7 Graphics"},
-	{0x9874,	0xC5,	"AMD Radeon R6 Graphics"},
-	{0x9874,	0xC6,	"AMD Radeon R6 Graphics"},
-	{0x9874,	0xC7,	"AMD Radeon R5 Graphics"},
-	{0x9874,	0x81,	"AMD Radeon R6 Graphics"},
-	{0x9874,	0x87,	"AMD Radeon R5 Graphics"},
-	{0x9874,	0x85,	"AMD Radeon R6 Graphics"},
-	{0x9874,	0x84,	"AMD Radeon R7 Graphics"},
-
-	{0x0000,	0x0,	"\0"},
-};
-#endif
diff --git a/amdgpu/amdgpu_bo.c b/amdgpu/amdgpu_bo.c
index d30fd1e..32ee358 100644
--- a/amdgpu/amdgpu_bo.c
+++ b/amdgpu/amdgpu_bo.c
@@ -22,10 +22,6 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -41,7 +37,6 @@
 #include "xf86drm.h"
 #include "amdgpu_drm.h"
 #include "amdgpu_internal.h"
-#include "util_hash_table.h"
 #include "util_math.h"
 
 static void amdgpu_close_kms_handle(amdgpu_device_handle dev,
@@ -53,41 +48,12 @@
 	drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &args);
 }
 
-drm_private 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);
-	free(bo);
-}
-
-int amdgpu_bo_alloc(amdgpu_device_handle dev,
-		    struct amdgpu_bo_alloc_request *alloc_buffer,
-		    amdgpu_bo_handle *buf_handle)
+static int amdgpu_bo_create(amdgpu_device_handle dev,
+			    uint64_t size,
+			    uint32_t handle,
+			    amdgpu_bo_handle *buf_handle)
 {
 	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)
@@ -95,34 +61,54 @@
 
 	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;
-	args.in.domain_flags = alloc_buffer->flags;
-
-	/* 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;
-
+	bo->alloc_size = size;
+	bo->handle = handle;
 	pthread_mutex_init(&bo->cpu_access_mutex, NULL);
 
 	*buf_handle = bo;
 	return 0;
 }
 
-int amdgpu_bo_set_metadata(amdgpu_bo_handle bo,
-			   struct amdgpu_bo_metadata *info)
+drm_public int amdgpu_bo_alloc(amdgpu_device_handle dev,
+			       struct amdgpu_bo_alloc_request *alloc_buffer,
+			       amdgpu_bo_handle *buf_handle)
+{
+	union drm_amdgpu_gem_create args;
+	int r;
+
+	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 = alloc_buffer->preferred_heap;
+	args.in.domain_flags = alloc_buffer->flags;
+
+	/* Allocate the buffer with the preferred heap. */
+	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_CREATE,
+				&args, sizeof(args));
+	if (r)
+		goto out;
+
+	r = amdgpu_bo_create(dev, alloc_buffer->alloc_size, args.out.handle,
+			     buf_handle);
+	if (r) {
+		amdgpu_close_kms_handle(dev, args.out.handle);
+		goto out;
+	}
+
+	pthread_mutex_lock(&dev->bo_table_mutex);
+	r = handle_table_insert(&dev->bo_handles, (*buf_handle)->handle,
+				*buf_handle);
+	pthread_mutex_unlock(&dev->bo_table_mutex);
+	if (r)
+		amdgpu_bo_free(*buf_handle);
+out:
+	return r;
+}
+
+drm_public int amdgpu_bo_set_metadata(amdgpu_bo_handle bo,
+				      struct amdgpu_bo_metadata *info)
 {
 	struct drm_amdgpu_gem_metadata args = {};
 
@@ -144,8 +130,8 @@
 				   &args, sizeof(args));
 }
 
-int amdgpu_bo_query_info(amdgpu_bo_handle bo,
-			 struct amdgpu_bo_info *info)
+drm_public 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 = {};
@@ -195,14 +181,6 @@
 	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;
@@ -243,17 +221,15 @@
 	}
 
 	pthread_mutex_lock(&bo->dev->bo_table_mutex);
-	util_hash_table_set(bo->dev->bo_flink_names,
-			    (void*)(uintptr_t)bo->flink_name,
-			    bo);
+	r = handle_table_insert(&bo->dev->bo_flink_names, bo->flink_name, bo);
 	pthread_mutex_unlock(&bo->dev->bo_table_mutex);
 
-	return 0;
+	return r;
 }
 
-int amdgpu_bo_export(amdgpu_bo_handle bo,
-		     enum amdgpu_bo_handle_type type,
-		     uint32_t *shared_handle)
+drm_public int amdgpu_bo_export(amdgpu_bo_handle bo,
+				enum amdgpu_bo_handle_type type,
+				uint32_t *shared_handle)
 {
 	int r;
 
@@ -267,26 +243,29 @@
 		return 0;
 
 	case amdgpu_bo_handle_type_kms:
-		amdgpu_add_handle_to_table(bo);
+	case amdgpu_bo_handle_type_kms_noimport:
 		*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 drmPrimeHandleToFD(bo->dev->fd, bo->handle,
+					  DRM_CLOEXEC | DRM_RDWR,
+					  (int*)shared_handle);
 	}
 	return -EINVAL;
 }
 
-int amdgpu_bo_import(amdgpu_device_handle dev,
-		     enum amdgpu_bo_handle_type type,
-		     uint32_t shared_handle,
+drm_public 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 = {};
+	struct drm_gem_close close_arg = {};
 	struct amdgpu_bo *bo = NULL;
-	int r;
+	uint32_t handle = 0, flink_name = 0;
+	uint64_t alloc_size = 0;
+	int r = 0;
 	int dma_fd;
 	uint64_t dma_buf_size = 0;
 
@@ -296,21 +275,18 @@
 
 	/* 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;
-		}
+		if (r)
+			goto unlock;
 
 		/* Query the buffer size. */
 		size = lseek(shared_handle, 0, SEEK_END);
 		if (size == (off_t)-1) {
-			pthread_mutex_unlock(&dev->bo_table_mutex);
-			amdgpu_close_kms_handle(dev, handle);
-			return -errno;
+			r = -errno;
+			goto free_bo_handle;
 		}
 		lseek(shared_handle, 0, SEEK_SET);
 
@@ -321,110 +297,148 @@
 	/* 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);
+		bo = handle_table_lookup(&dev->bo_flink_names, shared_handle);
 		break;
 
 	case amdgpu_bo_handle_type_dma_buf_fd:
-		bo = util_hash_table_get(dev->bo_handles,
-					 (void*)(uintptr_t)shared_handle);
+		bo = handle_table_lookup(&dev->bo_handles, shared_handle);
 		break;
 
 	case amdgpu_bo_handle_type_kms:
+	case amdgpu_bo_handle_type_kms_noimport:
 		/* Importing a KMS handle in not allowed. */
-		pthread_mutex_unlock(&dev->bo_table_mutex);
-		return -EPERM;
+		r = -EPERM;
+		goto unlock;
 
 	default:
-		pthread_mutex_unlock(&dev->bo_table_mutex);
-		return -EINVAL;
+		r = -EINVAL;
+		goto unlock;
 	}
 
 	if (bo) {
-		pthread_mutex_unlock(&dev->bo_table_mutex);
-
 		/* The buffer already exists, just bump the refcount. */
 		atomic_inc(&bo->refcount);
+		pthread_mutex_unlock(&dev->bo_table_mutex);
 
 		output->buf_handle = bo;
 		output->alloc_size = bo->alloc_size;
 		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;
-		}
+		if (r)
+			goto unlock;
 
-		bo->handle = open_arg.handle;
+		flink_name = shared_handle;
+		handle = open_arg.handle;
+		alloc_size = open_arg.size;
 		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 );
-
+			r = drmPrimeHandleToFD(dev->flink_fd, handle,
+					       DRM_CLOEXEC, &dma_fd);
+			if (r)
+				goto free_bo_handle;
+			r = drmPrimeFDToHandle(dev->fd, dma_fd, &handle);
 			close(dma_fd);
-
-			if (r) {
-				free(bo);
-				pthread_mutex_unlock(&dev->bo_table_mutex);
-				return r;
-			}
+			if (r)
+				goto free_bo_handle;
+			close_arg.handle = open_arg.handle;
+			r = drmIoctl(dev->flink_fd, DRM_IOCTL_GEM_CLOSE,
+				     &close_arg);
+			if (r)
+				goto free_bo_handle;
 		}
-		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;
+		handle = shared_handle;
+		alloc_size = dma_buf_size;
 		break;
 
 	case amdgpu_bo_handle_type_kms:
+	case amdgpu_bo_handle_type_kms_noimport:
 		assert(0); /* unreachable */
 	}
 
 	/* Initialize it. */
-	atomic_set(&bo->refcount, 1);
-	bo->dev = dev;
-	pthread_mutex_init(&bo->cpu_access_mutex, NULL);
+	r = amdgpu_bo_create(dev, alloc_size, handle, &bo);
+	if (r)
+		goto free_bo_handle;
 
-	util_hash_table_set(dev->bo_handles, (void*)(uintptr_t)bo->handle, bo);
-	pthread_mutex_unlock(&dev->bo_table_mutex);
+	r = handle_table_insert(&dev->bo_handles, bo->handle, bo);
+	if (r)
+		goto free_bo_handle;
+	if (flink_name) {
+		bo->flink_name = flink_name;
+		r = handle_table_insert(&dev->bo_flink_names, flink_name,
+					bo);
+		if (r)
+			goto remove_handle;
+
+	}
 
 	output->buf_handle = bo;
 	output->alloc_size = bo->alloc_size;
+	pthread_mutex_unlock(&dev->bo_table_mutex);
 	return 0;
+
+remove_handle:
+	handle_table_remove(&dev->bo_handles, bo->handle);
+free_bo_handle:
+	if (flink_name && !close_arg.handle && open_arg.handle) {
+		close_arg.handle = open_arg.handle;
+		drmIoctl(dev->flink_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
+	}
+	if (bo)
+		amdgpu_bo_free(bo);
+	else
+		amdgpu_close_kms_handle(dev, handle);
+unlock:
+	pthread_mutex_unlock(&dev->bo_table_mutex);
+	return r;
 }
 
-int amdgpu_bo_free(amdgpu_bo_handle buf_handle)
+drm_public int amdgpu_bo_free(amdgpu_bo_handle buf_handle)
 {
-	/* Just drop the reference. */
-	amdgpu_bo_reference(&buf_handle, NULL);
+	struct amdgpu_device *dev;
+	struct amdgpu_bo *bo = buf_handle;
+
+	assert(bo != NULL);
+	dev = bo->dev;
+	pthread_mutex_lock(&dev->bo_table_mutex);
+
+	if (update_references(&bo->refcount, NULL)) {
+		/* Remove the buffer from the hash tables. */
+		handle_table_remove(&dev->bo_handles, bo->handle);
+
+		if (bo->flink_name)
+			handle_table_remove(&dev->bo_flink_names,
+					    bo->flink_name);
+
+		/* Release CPU access. */
+		if (bo->cpu_map_count > 0) {
+			bo->cpu_map_count = 1;
+			amdgpu_bo_cpu_unmap(bo);
+		}
+
+		amdgpu_close_kms_handle(dev, bo->handle);
+		pthread_mutex_destroy(&bo->cpu_access_mutex);
+		free(bo);
+	}
+
+	pthread_mutex_unlock(&dev->bo_table_mutex);
 	return 0;
 }
 
-int amdgpu_bo_cpu_map(amdgpu_bo_handle bo, void **cpu)
+drm_public void amdgpu_bo_inc_ref(amdgpu_bo_handle bo)
+{
+	atomic_inc(&bo->refcount);
+}
+
+drm_public int amdgpu_bo_cpu_map(amdgpu_bo_handle bo, void **cpu)
 {
 	union drm_amdgpu_gem_mmap args;
 	void *ptr;
@@ -472,7 +486,7 @@
 	return 0;
 }
 
-int amdgpu_bo_cpu_unmap(amdgpu_bo_handle bo)
+drm_public int amdgpu_bo_cpu_unmap(amdgpu_bo_handle bo)
 {
 	int r;
 
@@ -498,7 +512,7 @@
 	return r;
 }
 
-int amdgpu_query_buffer_size_alignment(amdgpu_device_handle dev,
+drm_public 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;
@@ -506,8 +520,8 @@
 	return 0;
 }
 
-int amdgpu_bo_wait_for_idle(amdgpu_bo_handle bo,
-			    uint64_t timeout_ns,
+drm_public int amdgpu_bo_wait_for_idle(amdgpu_bo_handle bo,
+				       uint64_t timeout_ns,
 			    bool *busy)
 {
 	union drm_amdgpu_gem_wait_idle args;
@@ -529,13 +543,54 @@
 	}
 }
 
-int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev,
-				    void *cpu,
-				    uint64_t size,
-				    amdgpu_bo_handle *buf_handle)
+drm_public int amdgpu_find_bo_by_cpu_mapping(amdgpu_device_handle dev,
+					     void *cpu,
+					     uint64_t size,
+					     amdgpu_bo_handle *buf_handle,
+					     uint64_t *offset_in_bo)
+{
+	struct amdgpu_bo *bo;
+	uint32_t i;
+	int r = 0;
+
+	if (cpu == NULL || size == 0)
+		return -EINVAL;
+
+	/*
+	 * Workaround for a buggy application which tries to import previously
+	 * exposed CPU pointers. If we find a real world use case we should
+	 * improve that by asking the kernel for the right handle.
+	 */
+	pthread_mutex_lock(&dev->bo_table_mutex);
+	for (i = 0; i < dev->bo_handles.max_key; i++) {
+		bo = handle_table_lookup(&dev->bo_handles, i);
+		if (!bo || !bo->cpu_ptr || size > bo->alloc_size)
+			continue;
+		if (cpu >= bo->cpu_ptr &&
+		    cpu < (void*)((uintptr_t)bo->cpu_ptr + bo->alloc_size))
+			break;
+	}
+
+	if (i < dev->bo_handles.max_key) {
+		atomic_inc(&bo->refcount);
+		*buf_handle = bo;
+		*offset_in_bo = (uintptr_t)cpu - (uintptr_t)bo->cpu_ptr;
+	} else {
+		*buf_handle = NULL;
+		*offset_in_bo = 0;
+		r = -ENXIO;
+	}
+	pthread_mutex_unlock(&dev->bo_table_mutex);
+
+	return r;
+}
+
+drm_public int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev,
+					      void *cpu,
+					      uint64_t size,
+					      amdgpu_bo_handle *buf_handle)
 {
 	int r;
-	struct amdgpu_bo *bo;
 	struct drm_amdgpu_gem_userptr args;
 
 	args.addr = (uintptr_t)cpu;
@@ -545,27 +600,63 @@
 	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_USERPTR,
 				&args, sizeof(args));
 	if (r)
-		return r;
+		goto out;
 
-	bo = calloc(1, sizeof(struct amdgpu_bo));
-	if (!bo)
-		return -ENOMEM;
+	r = amdgpu_bo_create(dev, size, args.handle, buf_handle);
+	if (r) {
+		amdgpu_close_kms_handle(dev, args.handle);
+		goto out;
+	}
 
-	atomic_set(&bo->refcount, 1);
-	bo->dev = dev;
-	bo->alloc_size = size;
-	bo->handle = args.handle;
-
-	*buf_handle = bo;
-
+	pthread_mutex_lock(&dev->bo_table_mutex);
+	r = handle_table_insert(&dev->bo_handles, (*buf_handle)->handle,
+				*buf_handle);
+	pthread_mutex_unlock(&dev->bo_table_mutex);
+	if (r)
+		amdgpu_bo_free(*buf_handle);
+out:
 	return r;
 }
 
-int amdgpu_bo_list_create(amdgpu_device_handle dev,
-			  uint32_t number_of_resources,
-			  amdgpu_bo_handle *resources,
-			  uint8_t *resource_prios,
-			  amdgpu_bo_list_handle *result)
+drm_public int amdgpu_bo_list_create_raw(amdgpu_device_handle dev,
+					 uint32_t number_of_buffers,
+					 struct drm_amdgpu_bo_list_entry *buffers,
+					 uint32_t *result)
+{
+	union drm_amdgpu_bo_list args;
+	int r;
+
+	memset(&args, 0, sizeof(args));
+	args.in.operation = AMDGPU_BO_LIST_OP_CREATE;
+	args.in.bo_number = number_of_buffers;
+	args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry);
+	args.in.bo_info_ptr = (uint64_t)(uintptr_t)buffers;
+
+	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST,
+				&args, sizeof(args));
+	if (!r)
+		*result = args.out.list_handle;
+	return r;
+}
+
+drm_public int amdgpu_bo_list_destroy_raw(amdgpu_device_handle dev,
+					  uint32_t bo_list)
+{
+	union drm_amdgpu_bo_list args;
+
+	memset(&args, 0, sizeof(args));
+	args.in.operation = AMDGPU_BO_LIST_OP_DESTROY;
+	args.in.list_handle = bo_list;
+
+	return drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST,
+				   &args, sizeof(args));
+}
+
+drm_public int amdgpu_bo_list_create(amdgpu_device_handle dev,
+				     uint32_t number_of_resources,
+				     amdgpu_bo_handle *resources,
+				     uint8_t *resource_prios,
+				     amdgpu_bo_list_handle *result)
 {
 	struct drm_amdgpu_bo_list_entry *list;
 	union drm_amdgpu_bo_list args;
@@ -616,7 +707,7 @@
 	return 0;
 }
 
-int amdgpu_bo_list_destroy(amdgpu_bo_list_handle list)
+drm_public int amdgpu_bo_list_destroy(amdgpu_bo_list_handle list)
 {
 	union drm_amdgpu_bo_list args;
 	int r;
@@ -634,10 +725,10 @@
 	return r;
 }
 
-int amdgpu_bo_list_update(amdgpu_bo_list_handle handle,
-			  uint32_t number_of_resources,
-			  amdgpu_bo_handle *resources,
-			  uint8_t *resource_prios)
+drm_public int amdgpu_bo_list_update(amdgpu_bo_list_handle handle,
+				     uint32_t number_of_resources,
+				     amdgpu_bo_handle *resources,
+				     uint8_t *resource_prios)
 {
 	struct drm_amdgpu_bo_list_entry *list;
 	union drm_amdgpu_bo_list args;
@@ -652,7 +743,7 @@
 		return -EINVAL;
 
 	list = malloc(number_of_resources * sizeof(struct drm_amdgpu_bo_list_entry));
-	if (list == NULL)
+	if (!list)
 		return -ENOMEM;
 
 	args.in.operation = AMDGPU_BO_LIST_OP_UPDATE;
@@ -675,29 +766,45 @@
 	return r;
 }
 
-int amdgpu_bo_va_op(amdgpu_bo_handle bo,
-		     uint64_t offset,
-		     uint64_t size,
-		     uint64_t addr,
-		     uint64_t flags,
-		     uint32_t ops)
+drm_public int amdgpu_bo_va_op(amdgpu_bo_handle bo,
+			       uint64_t offset,
+			       uint64_t size,
+			       uint64_t addr,
+			       uint64_t flags,
+			       uint32_t ops)
 {
 	amdgpu_device_handle dev = bo->dev;
+
+	size = ALIGN(size, getpagesize());
+
+	return amdgpu_bo_va_op_raw(dev, bo, offset, size, addr,
+				   AMDGPU_VM_PAGE_READABLE |
+				   AMDGPU_VM_PAGE_WRITEABLE |
+				   AMDGPU_VM_PAGE_EXECUTABLE, ops);
+}
+
+drm_public int amdgpu_bo_va_op_raw(amdgpu_device_handle dev,
+				   amdgpu_bo_handle bo,
+				   uint64_t offset,
+				   uint64_t size,
+				   uint64_t addr,
+				   uint64_t flags,
+				   uint32_t ops)
+{
 	struct drm_amdgpu_gem_va va;
 	int r;
 
-	if (ops != AMDGPU_VA_OP_MAP && ops != AMDGPU_VA_OP_UNMAP)
+	if (ops != AMDGPU_VA_OP_MAP && ops != AMDGPU_VA_OP_UNMAP &&
+	    ops != AMDGPU_VA_OP_REPLACE && ops != AMDGPU_VA_OP_CLEAR)
 		return -EINVAL;
 
 	memset(&va, 0, sizeof(va));
-	va.handle = bo->handle;
+	va.handle = bo ? bo->handle : 0;
 	va.operation = ops;
-	va.flags = AMDGPU_VM_PAGE_READABLE |
-		   AMDGPU_VM_PAGE_WRITEABLE |
-		   AMDGPU_VM_PAGE_EXECUTABLE;
+	va.flags = flags;
 	va.va_address = addr;
 	va.offset_in_bo = offset;
-	va.map_size = ALIGN(size, getpagesize());
+	va.map_size = size;
 
 	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_VA, &va, sizeof(va));
 
diff --git a/amdgpu/amdgpu_cs.c b/amdgpu/amdgpu_cs.c
index fb5b3a8..ba158f2 100644
--- a/amdgpu/amdgpu_cs.c
+++ b/amdgpu/amdgpu_cs.c
@@ -21,10 +21,6 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -46,26 +42,26 @@
 /**
  * Create command submission context
  *
- * \param   dev - \c [in] amdgpu device handle
- * \param   context - \c [out] amdgpu context handle
+ * \param   dev      - \c [in] Device handle. See #amdgpu_device_initialize()
+ * \param   priority - \c [in] Context creation flags. See AMDGPU_CTX_PRIORITY_*
+ * \param   context  - \c [out] GPU Context handle
  *
  * \return  0 on success otherwise POSIX Error code
 */
-int amdgpu_cs_ctx_create(amdgpu_device_handle dev,
-			 amdgpu_context_handle *context)
+drm_public int amdgpu_cs_ctx_create2(amdgpu_device_handle dev,
+				     uint32_t priority,
+				     amdgpu_context_handle *context)
 {
 	struct amdgpu_context *gpu_context;
 	union drm_amdgpu_ctx args;
 	int i, j, k;
 	int r;
 
-	if (NULL == dev)
-		return -EINVAL;
-	if (NULL == context)
+	if (!dev || !context)
 		return -EINVAL;
 
 	gpu_context = calloc(1, sizeof(struct amdgpu_context));
-	if (NULL == gpu_context)
+	if (!gpu_context)
 		return -ENOMEM;
 
 	gpu_context->dev = dev;
@@ -77,6 +73,8 @@
 	/* Create the context */
 	memset(&args, 0, sizeof(args));
 	args.in.op = AMDGPU_CTX_OP_ALLOC_CTX;
+	args.in.priority = priority;
+
 	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CTX, &args, sizeof(args));
 	if (r)
 		goto error;
@@ -96,6 +94,12 @@
 	return r;
 }
 
+drm_public int amdgpu_cs_ctx_create(amdgpu_device_handle dev,
+				    amdgpu_context_handle *context)
+{
+	return amdgpu_cs_ctx_create2(dev, AMDGPU_CTX_PRIORITY_NORMAL, context);
+}
+
 /**
  * Release command submission context
  *
@@ -104,13 +108,13 @@
  *
  * \return  0 on success otherwise POSIX Error code
 */
-int amdgpu_cs_ctx_free(amdgpu_context_handle context)
+drm_public int amdgpu_cs_ctx_free(amdgpu_context_handle context)
 {
 	union drm_amdgpu_ctx args;
 	int i, j, k;
 	int r;
 
-	if (NULL == context)
+	if (!context)
 		return -EINVAL;
 
 	pthread_mutex_destroy(&context->sequence_mutex);
@@ -138,8 +142,8 @@
 	return r;
 }
 
-int amdgpu_cs_query_reset_state(amdgpu_context_handle context,
-				uint32_t *state, uint32_t *hangs)
+drm_public int amdgpu_cs_query_reset_state(amdgpu_context_handle context,
+					   uint32_t *state, uint32_t *hangs)
 {
 	union drm_amdgpu_ctx args;
 	int r;
@@ -188,8 +192,6 @@
 		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;
 	if (ibs_request->number_of_ibs == 0) {
 		ibs_request->seq_no = AMDGPU_NULL_SUBMIT_SEQ;
 		return 0;
@@ -322,17 +324,15 @@
 	return r;
 }
 
-int amdgpu_cs_submit(amdgpu_context_handle context,
-		     uint64_t flags,
-		     struct amdgpu_cs_request *ibs_request,
-		     uint32_t number_of_requests)
+drm_public int amdgpu_cs_submit(amdgpu_context_handle context,
+				uint64_t flags,
+				struct amdgpu_cs_request *ibs_request,
+				uint32_t number_of_requests)
 {
 	uint32_t i;
 	int r;
 
-	if (NULL == context)
-		return -EINVAL;
-	if (NULL == ibs_request)
+	if (!context || !ibs_request)
 		return -EINVAL;
 
 	r = 0;
@@ -408,19 +408,15 @@
 	return 0;
 }
 
-int amdgpu_cs_query_fence_status(struct amdgpu_cs_fence *fence,
-				 uint64_t timeout_ns,
-				 uint64_t flags,
-				 uint32_t *expired)
+drm_public int amdgpu_cs_query_fence_status(struct amdgpu_cs_fence *fence,
+					    uint64_t timeout_ns,
+					    uint64_t flags,
+					    uint32_t *expired)
 {
 	bool busy = true;
 	int r;
 
-	if (NULL == fence)
-		return -EINVAL;
-	if (NULL == expired)
-		return -EINVAL;
-	if (NULL == fence->context)
+	if (!fence || !expired || !fence->context)
 		return -EINVAL;
 	if (fence->ip_type >= AMDGPU_HW_IP_NUM)
 		return -EINVAL;
@@ -443,15 +439,83 @@
 	return r;
 }
 
-int amdgpu_cs_create_semaphore(amdgpu_semaphore_handle *sem)
+static int amdgpu_ioctl_wait_fences(struct amdgpu_cs_fence *fences,
+				    uint32_t fence_count,
+				    bool wait_all,
+				    uint64_t timeout_ns,
+				    uint32_t *status,
+				    uint32_t *first)
+{
+	struct drm_amdgpu_fence *drm_fences;
+	amdgpu_device_handle dev = fences[0].context->dev;
+	union drm_amdgpu_wait_fences args;
+	int r;
+	uint32_t i;
+
+	drm_fences = alloca(sizeof(struct drm_amdgpu_fence) * fence_count);
+	for (i = 0; i < fence_count; i++) {
+		drm_fences[i].ctx_id = fences[i].context->id;
+		drm_fences[i].ip_type = fences[i].ip_type;
+		drm_fences[i].ip_instance = fences[i].ip_instance;
+		drm_fences[i].ring = fences[i].ring;
+		drm_fences[i].seq_no = fences[i].fence;
+	}
+
+	memset(&args, 0, sizeof(args));
+	args.in.fences = (uint64_t)(uintptr_t)drm_fences;
+	args.in.fence_count = fence_count;
+	args.in.wait_all = wait_all;
+	args.in.timeout_ns = amdgpu_cs_calculate_timeout(timeout_ns);
+
+	r = drmIoctl(dev->fd, DRM_IOCTL_AMDGPU_WAIT_FENCES, &args);
+	if (r)
+		return -errno;
+
+	*status = args.out.status;
+
+	if (first)
+		*first = args.out.first_signaled;
+
+	return 0;
+}
+
+drm_public int amdgpu_cs_wait_fences(struct amdgpu_cs_fence *fences,
+				     uint32_t fence_count,
+				     bool wait_all,
+				     uint64_t timeout_ns,
+				     uint32_t *status,
+				     uint32_t *first)
+{
+	uint32_t i;
+
+	/* Sanity check */
+	if (!fences || !status || !fence_count)
+		return -EINVAL;
+
+	for (i = 0; i < fence_count; i++) {
+		if (NULL == fences[i].context)
+			return -EINVAL;
+		if (fences[i].ip_type >= AMDGPU_HW_IP_NUM)
+			return -EINVAL;
+		if (fences[i].ring >= AMDGPU_CS_MAX_RINGS)
+			return -EINVAL;
+	}
+
+	*status = 0;
+
+	return amdgpu_ioctl_wait_fences(fences, fence_count, wait_all,
+					timeout_ns, status, first);
+}
+
+drm_public int amdgpu_cs_create_semaphore(amdgpu_semaphore_handle *sem)
 {
 	struct amdgpu_semaphore *gpu_semaphore;
 
-	if (NULL == sem)
+	if (!sem)
 		return -EINVAL;
 
 	gpu_semaphore = calloc(1, sizeof(struct amdgpu_semaphore));
-	if (NULL == gpu_semaphore)
+	if (!gpu_semaphore)
 		return -ENOMEM;
 
 	atomic_set(&gpu_semaphore->refcount, 1);
@@ -460,20 +524,18 @@
 	return 0;
 }
 
-int amdgpu_cs_signal_semaphore(amdgpu_context_handle ctx,
-			       uint32_t ip_type,
+drm_public int amdgpu_cs_signal_semaphore(amdgpu_context_handle ctx,
+					  uint32_t ip_type,
 			       uint32_t ip_instance,
 			       uint32_t ring,
 			       amdgpu_semaphore_handle sem)
 {
-	if (NULL == ctx)
+	if (!ctx || !sem)
 		return -EINVAL;
 	if (ip_type >= AMDGPU_HW_IP_NUM)
 		return -EINVAL;
 	if (ring >= AMDGPU_CS_MAX_RINGS)
 		return -EINVAL;
-	if (NULL == sem)
-		return -EINVAL;
 	/* sem has been signaled */
 	if (sem->signal_fence.context)
 		return -EINVAL;
@@ -488,22 +550,20 @@
 	return 0;
 }
 
-int amdgpu_cs_wait_semaphore(amdgpu_context_handle ctx,
-			     uint32_t ip_type,
+drm_public int amdgpu_cs_wait_semaphore(amdgpu_context_handle ctx,
+					uint32_t ip_type,
 			     uint32_t ip_instance,
 			     uint32_t ring,
 			     amdgpu_semaphore_handle sem)
 {
-	if (NULL == ctx)
+	if (!ctx || !sem)
 		return -EINVAL;
 	if (ip_type >= AMDGPU_HW_IP_NUM)
 		return -EINVAL;
 	if (ring >= AMDGPU_CS_MAX_RINGS)
 		return -EINVAL;
-	if (NULL == sem)
-		return -EINVAL;
 	/* must signal first */
-	if (NULL == sem->signal_fence.context)
+	if (!sem->signal_fence.context)
 		return -EINVAL;
 
 	pthread_mutex_lock(&ctx->sequence_mutex);
@@ -514,12 +574,10 @@
 
 static int amdgpu_cs_reset_sem(amdgpu_semaphore_handle sem)
 {
-	if (NULL == sem)
-		return -EINVAL;
-	if (NULL == sem->signal_fence.context)
+	if (!sem || !sem->signal_fence.context)
 		return -EINVAL;
 
-	sem->signal_fence.context = NULL;;
+	sem->signal_fence.context = NULL;
 	sem->signal_fence.ip_type = 0;
 	sem->signal_fence.ip_instance = 0;
 	sem->signal_fence.ring = 0;
@@ -530,7 +588,7 @@
 
 static int amdgpu_cs_unreference_sem(amdgpu_semaphore_handle sem)
 {
-	if (NULL == sem)
+	if (!sem)
 		return -EINVAL;
 
 	if (update_references(&sem->refcount, NULL))
@@ -538,7 +596,204 @@
 	return 0;
 }
 
-int amdgpu_cs_destroy_semaphore(amdgpu_semaphore_handle sem)
+drm_public int amdgpu_cs_destroy_semaphore(amdgpu_semaphore_handle sem)
 {
 	return amdgpu_cs_unreference_sem(sem);
 }
+
+drm_public int amdgpu_cs_create_syncobj2(amdgpu_device_handle dev,
+					 uint32_t  flags,
+					 uint32_t *handle)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjCreate(dev->fd, flags, handle);
+}
+
+drm_public int amdgpu_cs_create_syncobj(amdgpu_device_handle dev,
+					uint32_t *handle)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjCreate(dev->fd, 0, handle);
+}
+
+drm_public int amdgpu_cs_destroy_syncobj(amdgpu_device_handle dev,
+					 uint32_t handle)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjDestroy(dev->fd, handle);
+}
+
+drm_public int amdgpu_cs_syncobj_reset(amdgpu_device_handle dev,
+				       const uint32_t *syncobjs,
+				       uint32_t syncobj_count)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjReset(dev->fd, syncobjs, syncobj_count);
+}
+
+drm_public int amdgpu_cs_syncobj_signal(amdgpu_device_handle dev,
+					const uint32_t *syncobjs,
+					uint32_t syncobj_count)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjSignal(dev->fd, syncobjs, syncobj_count);
+}
+
+drm_public int amdgpu_cs_syncobj_wait(amdgpu_device_handle dev,
+				      uint32_t *handles, unsigned num_handles,
+				      int64_t timeout_nsec, unsigned flags,
+				      uint32_t *first_signaled)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjWait(dev->fd, handles, num_handles, timeout_nsec,
+			      flags, first_signaled);
+}
+
+drm_public int amdgpu_cs_export_syncobj(amdgpu_device_handle dev,
+					uint32_t handle,
+					int *shared_fd)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjHandleToFD(dev->fd, handle, shared_fd);
+}
+
+drm_public int amdgpu_cs_import_syncobj(amdgpu_device_handle dev,
+					int shared_fd,
+					uint32_t *handle)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjFDToHandle(dev->fd, shared_fd, handle);
+}
+
+drm_public int amdgpu_cs_syncobj_export_sync_file(amdgpu_device_handle dev,
+						  uint32_t syncobj,
+						  int *sync_file_fd)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjExportSyncFile(dev->fd, syncobj, sync_file_fd);
+}
+
+drm_public int amdgpu_cs_syncobj_import_sync_file(amdgpu_device_handle dev,
+						  uint32_t syncobj,
+						  int sync_file_fd)
+{
+	if (NULL == dev)
+		return -EINVAL;
+
+	return drmSyncobjImportSyncFile(dev->fd, syncobj, sync_file_fd);
+}
+
+drm_public int amdgpu_cs_submit_raw(amdgpu_device_handle dev,
+				    amdgpu_context_handle context,
+				    amdgpu_bo_list_handle bo_list_handle,
+				    int num_chunks,
+				    struct drm_amdgpu_cs_chunk *chunks,
+				    uint64_t *seq_no)
+{
+	union drm_amdgpu_cs cs;
+	uint64_t *chunk_array;
+	int i, r;
+	if (num_chunks == 0)
+		return -EINVAL;
+
+	memset(&cs, 0, sizeof(cs));
+	chunk_array = alloca(sizeof(uint64_t) * num_chunks);
+	for (i = 0; i < num_chunks; i++)
+		chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i];
+	cs.in.chunks = (uint64_t)(uintptr_t)chunk_array;
+	cs.in.ctx_id = context->id;
+	cs.in.bo_list_handle = bo_list_handle ? bo_list_handle->handle : 0;
+	cs.in.num_chunks = num_chunks;
+	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CS,
+				&cs, sizeof(cs));
+	if (r)
+		return r;
+
+	if (seq_no)
+		*seq_no = cs.out.handle;
+	return 0;
+}
+
+drm_public int amdgpu_cs_submit_raw2(amdgpu_device_handle dev,
+				     amdgpu_context_handle context,
+				     uint32_t bo_list_handle,
+				     int num_chunks,
+				     struct drm_amdgpu_cs_chunk *chunks,
+				     uint64_t *seq_no)
+{
+	union drm_amdgpu_cs cs;
+	uint64_t *chunk_array;
+	int i, r;
+
+	memset(&cs, 0, sizeof(cs));
+	chunk_array = alloca(sizeof(uint64_t) * num_chunks);
+	for (i = 0; i < num_chunks; i++)
+		chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i];
+	cs.in.chunks = (uint64_t)(uintptr_t)chunk_array;
+	cs.in.ctx_id = context->id;
+	cs.in.bo_list_handle = bo_list_handle;
+	cs.in.num_chunks = num_chunks;
+	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CS,
+				&cs, sizeof(cs));
+	if (!r && seq_no)
+		*seq_no = cs.out.handle;
+	return r;
+}
+
+drm_public void amdgpu_cs_chunk_fence_info_to_data(struct amdgpu_cs_fence_info *fence_info,
+					struct drm_amdgpu_cs_chunk_data *data)
+{
+	data->fence_data.handle = fence_info->handle->handle;
+	data->fence_data.offset = fence_info->offset * sizeof(uint64_t);
+}
+
+drm_public void amdgpu_cs_chunk_fence_to_dep(struct amdgpu_cs_fence *fence,
+					struct drm_amdgpu_cs_chunk_dep *dep)
+{
+	dep->ip_type = fence->ip_type;
+	dep->ip_instance = fence->ip_instance;
+	dep->ring = fence->ring;
+	dep->ctx_id = fence->context->id;
+	dep->handle = fence->fence;
+}
+
+drm_public int amdgpu_cs_fence_to_handle(amdgpu_device_handle dev,
+					 struct amdgpu_cs_fence *fence,
+					 uint32_t what,
+					 uint32_t *out_handle)
+{
+	union drm_amdgpu_fence_to_handle fth;
+	int r;
+
+	memset(&fth, 0, sizeof(fth));
+	fth.in.fence.ctx_id = fence->context->id;
+	fth.in.fence.ip_type = fence->ip_type;
+	fth.in.fence.ip_instance = fence->ip_instance;
+	fth.in.fence.ring = fence->ring;
+	fth.in.fence.seq_no = fence->fence;
+	fth.in.what = what;
+
+	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_FENCE_TO_HANDLE,
+				&fth, sizeof(fth));
+	if (r == 0)
+		*out_handle = fth.out.handle;
+	return r;
+}
diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c
index f4ede03..362494b 100644
--- a/amdgpu/amdgpu_device.c
+++ b/amdgpu/amdgpu_device.c
@@ -28,62 +28,26 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <sys/stat.h>
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "xf86drm.h"
 #include "amdgpu_drm.h"
 #include "amdgpu_internal.h"
-#include "util_hash_table.h"
 #include "util_math.h"
-#include "amdgpu_asic_id.h"
 
 #define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
-#define UINT_TO_PTR(x) ((void *)((intptr_t)(x)))
 
 static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
-static struct util_hash_table *fd_tab;
+static amdgpu_device_handle fd_list;
 
-static unsigned handle_hash(void *key)
+static int fd_compare(int fd1, int fd2)
 {
-	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);
-	char *name = drmGetPrimaryDeviceNameFromFd(fd);
-	unsigned result = 0;
-	char *c;
-
-	if (name == NULL)
-		return 0;
-
-	for (c = name; *c; ++c)
-		result += *c;
-
-	free(name);
-
-	return result;
-}
-
-static int fd_compare(void *key1, void *key2)
-{
-	int fd1 = PTR_TO_UINT(key1);
-	int fd2 = PTR_TO_UINT(key2);
 	char *name1 = drmGetPrimaryDeviceNameFromFd(fd1);
 	char *name2 = drmGetPrimaryDeviceNameFromFd(fd2);
 	int result;
@@ -131,17 +95,26 @@
 
 static void amdgpu_device_free_internal(amdgpu_device_handle dev)
 {
-	amdgpu_vamgr_deinit(dev->vamgr);
-	free(dev->vamgr);
-	amdgpu_vamgr_deinit(dev->vamgr_32);
-	free(dev->vamgr_32);
-	util_hash_table_destroy(dev->bo_flink_names);
-	util_hash_table_destroy(dev->bo_handles);
-	pthread_mutex_destroy(&dev->bo_table_mutex);
-	util_hash_table_remove(fd_tab, UINT_TO_PTR(dev->fd));
+	amdgpu_device_handle *node = &fd_list;
+
+	pthread_mutex_lock(&fd_mutex);
+	while (*node != dev && (*node)->next)
+		node = &(*node)->next;
+	*node = (*node)->next;
+	pthread_mutex_unlock(&fd_mutex);
+
 	close(dev->fd);
 	if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd))
 		close(dev->flink_fd);
+
+	amdgpu_vamgr_deinit(&dev->vamgr_32);
+	amdgpu_vamgr_deinit(&dev->vamgr);
+	amdgpu_vamgr_deinit(&dev->vamgr_high_32);
+	amdgpu_vamgr_deinit(&dev->vamgr_high);
+	handle_table_fini(&dev->bo_handles);
+	handle_table_fini(&dev->bo_flink_names);
+	pthread_mutex_destroy(&dev->bo_table_mutex);
+	free(dev->marketing_name);
 	free(dev);
 }
 
@@ -160,17 +133,17 @@
  *    // incremented. dst is freed if its reference counter is 0.
  */
 static void amdgpu_device_reference(struct amdgpu_device **dst,
-			     struct amdgpu_device *src)
+				    struct amdgpu_device *src)
 {
 	if (update_references(&(*dst)->refcount, &src->refcount))
 		amdgpu_device_free_internal(*dst);
 	*dst = src;
 }
 
-int amdgpu_device_initialize(int fd,
-			     uint32_t *major_version,
-			     uint32_t *minor_version,
-			     amdgpu_device_handle *device_handle)
+drm_public 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;
@@ -183,22 +156,28 @@
 	*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) {
+		fprintf(stderr, "%s: amdgpu_get_auth (1) failed (%i)\n",
+			__func__, r);
 		pthread_mutex_unlock(&fd_mutex);
 		return r;
 	}
-	dev = util_hash_table_get(fd_tab, UINT_TO_PTR(fd));
+
+	for (dev = fd_list; dev; dev = dev->next)
+		if (fd_compare(dev->fd, fd) == 0)
+			break;
+
 	if (dev) {
 		r = amdgpu_get_auth(dev->fd, &flag_authexist);
 		if (r) {
+			fprintf(stderr, "%s: amdgpu_get_auth (2) failed (%i)\n",
+				__func__, r);
 			pthread_mutex_unlock(&fd_mutex);
 			return r;
 		}
 		if ((flag_auth) && (!flag_authexist)) {
-			dev->flink_fd = dup(fd);
+			dev->flink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
 		}
 		*major_version = dev->major_version;
 		*minor_version = dev->minor_version;
@@ -209,6 +188,7 @@
 
 	dev = calloc(1, sizeof(struct amdgpu_device));
 	if (!dev) {
+		fprintf(stderr, "%s: calloc failed\n", __func__);
 		pthread_mutex_unlock(&fd_mutex);
 		return -ENOMEM;
 	}
@@ -231,66 +211,66 @@
 		goto cleanup;
 	}
 
-	dev->fd = dup(fd);
+	dev->fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
 	dev->flink_fd = dev->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);
 	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)
+	if (r) {
+		fprintf(stderr, "%s: amdgpu_query_info(ACCEL_WORKING) failed (%i)\n",
+			__func__, r);
 		goto cleanup;
+	}
 	if (!accel_working) {
+		fprintf(stderr, "%s: AMDGPU_INFO_ACCEL_WORKING = 0\n", __func__);
 		r = -EBADF;
 		goto cleanup;
 	}
 
 	r = amdgpu_query_gpu_info_init(dev);
-	if (r)
+	if (r) {
+		fprintf(stderr, "%s: amdgpu_query_gpu_info_init failed\n", __func__);
 		goto cleanup;
+	}
 
-	dev->vamgr = calloc(1, sizeof(struct amdgpu_bo_va_mgr));
-	if (dev->vamgr == NULL)
-		goto cleanup;
-
-	amdgpu_vamgr_init(dev->vamgr, dev->dev_info.virtual_address_offset,
-			  dev->dev_info.virtual_address_max,
+	start = dev->dev_info.virtual_address_offset;
+	max = MIN2(dev->dev_info.virtual_address_max, 0x100000000ULL);
+	amdgpu_vamgr_init(&dev->vamgr_32, start, max,
 			  dev->dev_info.virtual_address_alignment);
 
-	max = MIN2(dev->dev_info.virtual_address_max, 0xffffffff);
-	start = amdgpu_vamgr_find_va(dev->vamgr,
-				     max - dev->dev_info.virtual_address_offset,
-				     dev->dev_info.virtual_address_alignment, 0);
-	if (start > 0xffffffff)
-		goto free_va; /* shouldn't get here */
-
-	dev->vamgr_32 =  calloc(1, sizeof(struct amdgpu_bo_va_mgr));
-	if (dev->vamgr_32 == NULL)
-		goto free_va;
-	amdgpu_vamgr_init(dev->vamgr_32, start, max,
+	start = max;
+	max = MAX2(dev->dev_info.virtual_address_max, 0x100000000ULL);
+	amdgpu_vamgr_init(&dev->vamgr, start, max,
 			  dev->dev_info.virtual_address_alignment);
 
+	start = dev->dev_info.high_va_offset;
+	max = MIN2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) +
+		   0x100000000ULL);
+	amdgpu_vamgr_init(&dev->vamgr_high_32, start, max,
+			  dev->dev_info.virtual_address_alignment);
+
+	start = max;
+	max = MAX2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) +
+		   0x100000000ULL);
+	amdgpu_vamgr_init(&dev->vamgr_high, start, max,
+			  dev->dev_info.virtual_address_alignment);
+
+	amdgpu_parse_asic_ids(dev);
+
 	*major_version = dev->major_version;
 	*minor_version = dev->minor_version;
 	*device_handle = dev;
-	util_hash_table_set(fd_tab, UINT_TO_PTR(dev->fd), dev);
+	dev->next = fd_list;
+	fd_list = dev;
 	pthread_mutex_unlock(&fd_mutex);
 
 	return 0;
 
-free_va:
-	r = -ENOMEM;
-	amdgpu_vamgr_free_va(dev->vamgr, start,
-			     max - dev->dev_info.virtual_address_offset);
-	amdgpu_vamgr_deinit(dev->vamgr);
-	free(dev->vamgr);
-
 cleanup:
 	if (dev->fd >= 0)
 		close(dev->fd);
@@ -299,22 +279,30 @@
 	return r;
 }
 
-int amdgpu_device_deinitialize(amdgpu_device_handle dev)
+drm_public int amdgpu_device_deinitialize(amdgpu_device_handle dev)
 {
 	amdgpu_device_reference(&dev, NULL);
 	return 0;
 }
 
-const char *amdgpu_get_marketing_name(amdgpu_device_handle dev)
+drm_public const char *amdgpu_get_marketing_name(amdgpu_device_handle dev)
 {
-	const struct amdgpu_asic_id_table_t *t = amdgpu_asic_id_table;
+	return dev->marketing_name;
+}
 
-	while (t->did) {
-		if ((t->did == dev->info.asic_id) &&
-		    (t->rid == dev->info.pci_rev_id))
-			return t->marketing_name;
-		t++;
+drm_public int amdgpu_query_sw_info(amdgpu_device_handle dev,
+				    enum amdgpu_sw_info info,
+				    void *value)
+{
+	uint32_t *val32 = (uint32_t*)value;
+
+	switch (info) {
+	case amdgpu_sw_info_address32_hi:
+		if (dev->vamgr_high_32.va_max)
+			*val32 = (dev->vamgr_high_32.va_max - 1) >> 32;
+		else
+			*val32 = (dev->vamgr_32.va_max - 1) >> 32;
+		return 0;
 	}
-
-	return NULL;
+	return -EINVAL;
 }
diff --git a/amdgpu/amdgpu_gpu_info.c b/amdgpu/amdgpu_gpu_info.c
index 66c7e0e..777087f 100644
--- a/amdgpu/amdgpu_gpu_info.c
+++ b/amdgpu/amdgpu_gpu_info.c
@@ -22,10 +22,6 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <string.h>
 
@@ -34,8 +30,8 @@
 #include "amdgpu_internal.h"
 #include "xf86drm.h"
 
-int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id,
-		      unsigned size, void *value)
+drm_public int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id,
+				 unsigned size, void *value)
 {
 	struct drm_amdgpu_info request;
 
@@ -48,8 +44,8 @@
 			       sizeof(struct drm_amdgpu_info));
 }
 
-int amdgpu_query_crtc_from_id(amdgpu_device_handle dev, unsigned id,
-			      int32_t *result)
+drm_public int amdgpu_query_crtc_from_id(amdgpu_device_handle dev, unsigned id,
+					 int32_t *result)
 {
 	struct drm_amdgpu_info request;
 
@@ -63,9 +59,9 @@
 			       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)
+drm_public 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;
 
@@ -82,8 +78,9 @@
 			       sizeof(struct drm_amdgpu_info));
 }
 
-int amdgpu_query_hw_ip_count(amdgpu_device_handle dev, unsigned type,
-			     uint32_t *count)
+drm_public int amdgpu_query_hw_ip_count(amdgpu_device_handle dev,
+					unsigned type,
+					uint32_t *count)
 {
 	struct drm_amdgpu_info request;
 
@@ -97,9 +94,9 @@
 			       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)
+drm_public 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;
 
@@ -114,9 +111,9 @@
 			       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)
+drm_public 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 = {};
@@ -169,54 +166,58 @@
 	dev->info.vce_harvest_config = dev->dev_info.vce_harvest_config;
 	dev->info.pci_rev_id = dev->dev_info.pci_rev;
 
-	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);
+	if (dev->info.family_id < AMDGPU_FAMILY_AI) {
+		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, 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]);
+			r = amdgpu_read_mm_registers(dev, 0xa0d4, 1, instance, 0,
+						     &dev->info.pa_sc_raster_cfg[i]);
+			if (r)
+				return r;
+
+			if (dev->info.family_id >= AMDGPU_FAMILY_CI) {
+				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, 0x263e, 1, 0xffffffff, 0,
+					     &dev->info.gb_addr_cfg);
+	if (r)
+		return r;
+
+	if (dev->info.family_id < AMDGPU_FAMILY_AI) {
+		r = amdgpu_read_mm_registers(dev, 0x2644, 32, 0xffffffff, 0,
+					     dev->info.gb_tile_mode);
 		if (r)
 			return r;
 
 		if (dev->info.family_id >= AMDGPU_FAMILY_CI) {
-			r = amdgpu_read_mm_registers(dev, 0xa0d5, 1, instance, 0,
-					     &dev->info.pa_sc_raster_cfg1[i]);
+			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, 0x2644, 32, 0xffffffff, 0,
-				     dev->info.gb_tile_mode);
-	if (r)
-		return r;
-
-	if (dev->info.family_id >= AMDGPU_FAMILY_CI) {
-		r = amdgpu_read_mm_registers(dev, 0x2664, 16, 0xffffffff, 0,
-					     dev->info.gb_macro_tile_mode);
+		r = amdgpu_read_mm_registers(dev, 0x9d8, 1, 0xffffffff, 0,
+					     &dev->info.mc_arb_ramcfg);
 		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));
@@ -227,21 +228,22 @@
 	return 0;
 }
 
-int amdgpu_query_gpu_info(amdgpu_device_handle dev,
-			struct amdgpu_gpu_info *info)
+drm_public int amdgpu_query_gpu_info(amdgpu_device_handle dev,
+				     struct amdgpu_gpu_info *info)
 {
-	if ((dev == NULL) || (info == NULL))
+	if (!dev || !info)
 		return -EINVAL;
+
 	/* 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)
+drm_public 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;
@@ -290,13 +292,13 @@
 	return 0;
 }
 
-int amdgpu_query_gds_info(amdgpu_device_handle dev,
-			struct amdgpu_gds_resource_info *gds_info)
+drm_public int amdgpu_query_gds_info(amdgpu_device_handle dev,
+				     struct amdgpu_gds_resource_info *gds_info)
 {
 	struct drm_amdgpu_info_gds gds_config = {};
         int r;
 
-	if (gds_info == NULL)
+	if (!gds_info)
 		return -EINVAL;
 
         r = amdgpu_query_info(dev, AMDGPU_INFO_GDS_CONFIG,
@@ -314,3 +316,18 @@
 
 	return 0;
 }
+
+drm_public int amdgpu_query_sensor_info(amdgpu_device_handle dev, unsigned sensor_type,
+					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 = AMDGPU_INFO_SENSOR;
+	request.sensor_info.type = sensor_type;
+
+	return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request,
+			       sizeof(struct drm_amdgpu_info));
+}
diff --git a/amdgpu/amdgpu_internal.h b/amdgpu/amdgpu_internal.h
index 4f039b6..a340abb 100644
--- a/amdgpu/amdgpu_internal.h
+++ b/amdgpu/amdgpu_internal.h
@@ -25,10 +25,6 @@
 #ifndef _AMDGPU_INTERNAL_H_
 #define _AMDGPU_INTERNAL_H_
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <assert.h>
 #include <pthread.h>
 
@@ -36,6 +32,7 @@
 #include "xf86atomic.h"
 #include "amdgpu.h"
 #include "util_double_list.h"
+#include "handle_table.h"
 
 #define AMDGPU_CS_MAX_RINGS 8
 /* do not use below macro if b is not power of 2 aligned value */
@@ -53,8 +50,6 @@
 };
 
 struct amdgpu_bo_va_mgr {
-	/* the start virtual address */
-	uint64_t va_offset;
 	uint64_t va_max;
 	struct list_head va_holes;
 	pthread_mutex_t bo_va_mutex;
@@ -71,23 +66,29 @@
 
 struct amdgpu_device {
 	atomic_t refcount;
+	struct amdgpu_device *next;
 	int fd;
 	int flink_fd;
 	unsigned major_version;
 	unsigned minor_version;
 
+	char *marketing_name;
 	/** List of buffer handles. Protected by bo_table_mutex. */
-	struct util_hash_table *bo_handles;
+	struct handle_table bo_handles;
 	/** List of buffer GEM flink names. Protected by bo_table_mutex. */
-	struct util_hash_table *bo_flink_names;
+	struct handle_table bo_flink_names;
 	/** This protects all hash tables. */
 	pthread_mutex_t bo_table_mutex;
 	struct drm_amdgpu_info_device dev_info;
 	struct amdgpu_gpu_info info;
-	/** The global VA manager for the whole virtual address space */
-	struct amdgpu_bo_va_mgr *vamgr;
+	/** The VA manager for the lower virtual address space */
+	struct amdgpu_bo_va_mgr vamgr;
 	/** The VA manager for the 32bit address space */
-	struct amdgpu_bo_va_mgr *vamgr_32;
+	struct amdgpu_bo_va_mgr vamgr_32;
+	/** The VA manager for the high virtual address space */
+	struct amdgpu_bo_va_mgr vamgr_high;
+	/** The VA manager for the 32bit high address space */
+	struct amdgpu_bo_va_mgr vamgr_high_32;
 };
 
 struct amdgpu_bo {
@@ -135,19 +136,12 @@
  * Functions.
  */
 
-drm_private void amdgpu_bo_free_internal(amdgpu_bo_handle bo);
-
 drm_private void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, uint64_t start,
 		       uint64_t max, uint64_t alignment);
 
 drm_private void amdgpu_vamgr_deinit(struct amdgpu_bo_va_mgr *mgr);
 
-drm_private uint64_t
-amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr, uint64_t size,
-		     uint64_t alignment, uint64_t base_required);
-
-drm_private void
-amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va, uint64_t size);
+drm_private void amdgpu_parse_asic_ids(struct amdgpu_device *dev);
 
 drm_private int amdgpu_query_gpu_info_init(amdgpu_device_handle dev);
 
@@ -179,26 +173,4 @@
 	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;
-}
-
 #endif
diff --git a/amdgpu/amdgpu_vamgr.c b/amdgpu/amdgpu_vamgr.c
index 8a707cb..d25d421 100644
--- a/amdgpu/amdgpu_vamgr.c
+++ b/amdgpu/amdgpu_vamgr.c
@@ -21,10 +21,6 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
@@ -33,26 +29,34 @@
 #include "amdgpu_internal.h"
 #include "util_math.h"
 
-int amdgpu_va_range_query(amdgpu_device_handle dev,
-			  enum amdgpu_gpu_va_range type, uint64_t *start, uint64_t *end)
+drm_public int amdgpu_va_range_query(amdgpu_device_handle dev,
+				     enum amdgpu_gpu_va_range type,
+				     uint64_t *start, uint64_t *end)
 {
-	if (type == amdgpu_gpu_va_range_general) {
-		*start = dev->dev_info.virtual_address_offset;
-		*end = dev->dev_info.virtual_address_max;
-		return 0;
-	}
-	return -EINVAL;
+	if (type != amdgpu_gpu_va_range_general)
+		return -EINVAL;
+
+	*start = dev->dev_info.virtual_address_offset;
+	*end = dev->dev_info.virtual_address_max;
+	return 0;
 }
 
 drm_private void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, uint64_t start,
-			      uint64_t max, uint64_t alignment)
+				   uint64_t max, uint64_t alignment)
 {
-	mgr->va_offset = start;
+	struct amdgpu_bo_va_hole *n;
+
 	mgr->va_max = max;
 	mgr->va_alignment = alignment;
 
 	list_inithead(&mgr->va_holes);
 	pthread_mutex_init(&mgr->bo_va_mutex, NULL);
+	pthread_mutex_lock(&mgr->bo_va_mutex);
+	n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
+	n->size = mgr->va_max - start;
+	n->offset = start;
+	list_add(&n->list, &mgr->va_holes);
+	pthread_mutex_unlock(&mgr->bo_va_mutex);
 }
 
 drm_private void amdgpu_vamgr_deinit(struct amdgpu_bo_va_mgr *mgr)
@@ -65,13 +69,14 @@
 	pthread_mutex_destroy(&mgr->bo_va_mutex);
 }
 
-drm_private uint64_t
+static drm_private uint64_t
 amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr, uint64_t size,
 		     uint64_t alignment, uint64_t base_required)
 {
 	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);
 
@@ -79,12 +84,10 @@
 		return AMDGPU_INVALID_VA_ADDRESS;
 
 	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) {
+	LIST_FOR_EACH_ENTRY_SAFE_REV(hole, n, &mgr->va_holes, list) {
 		if (base_required) {
-			if(hole->offset > base_required ||
-				(hole->offset + hole->size) < (base_required + size))
+			if (hole->offset > base_required ||
+			    (hole->offset + hole->size) < (base_required + size))
 				continue;
 			waste = base_required - hole->offset;
 			offset = base_required;
@@ -123,41 +126,14 @@
 		}
 	}
 
-	if (base_required) {
-		if (base_required < mgr->va_offset) {
-			pthread_mutex_unlock(&mgr->bo_va_mutex);
-			return AMDGPU_INVALID_VA_ADDRESS;
-		}
-		offset = mgr->va_offset;
-		waste = base_required - mgr->va_offset;
-	} else {
-		offset = mgr->va_offset;
-		waste = offset % alignment;
-		waste = waste ? alignment - waste : 0;
-	}
-
-	if (offset + waste + size > mgr->va_max) {
-		pthread_mutex_unlock(&mgr->bo_va_mutex);
-		return AMDGPU_INVALID_VA_ADDRESS;
-	}
-
-	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;
+	return AMDGPU_INVALID_VA_ADDRESS;
 }
 
-drm_private void
+static drm_private void
 amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va, uint64_t size)
 {
-	struct amdgpu_bo_va_hole *hole;
+	struct amdgpu_bo_va_hole *hole, *next;
 
 	if (va == AMDGPU_INVALID_VA_ADDRESS)
 		return;
@@ -165,80 +141,77 @@
 	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;
+	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);
 			}
-		}
-	} 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);
-		}
 	}
+
+	/* 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);
 }
 
-int amdgpu_va_range_alloc(amdgpu_device_handle dev,
-			  enum amdgpu_gpu_va_range va_range_type,
-			  uint64_t size,
-			  uint64_t va_base_alignment,
-			  uint64_t va_base_required,
-			  uint64_t *va_base_allocated,
-			  amdgpu_va_handle *va_range_handle,
-			  uint64_t flags)
+drm_public int amdgpu_va_range_alloc(amdgpu_device_handle dev,
+				     enum amdgpu_gpu_va_range va_range_type,
+				     uint64_t size,
+				     uint64_t va_base_alignment,
+				     uint64_t va_base_required,
+				     uint64_t *va_base_allocated,
+				     amdgpu_va_handle *va_range_handle,
+				     uint64_t flags)
 {
 	struct amdgpu_bo_va_mgr *vamgr;
 
-	if (flags & AMDGPU_VA_RANGE_32_BIT)
-		vamgr = dev->vamgr_32;
-	else
-		vamgr = dev->vamgr;
+	/* Clear the flag when the high VA manager is not initialized */
+	if (flags & AMDGPU_VA_RANGE_HIGH && !dev->vamgr_high_32.va_max)
+		flags &= ~AMDGPU_VA_RANGE_HIGH;
+
+	if (flags & AMDGPU_VA_RANGE_HIGH) {
+		if (flags & AMDGPU_VA_RANGE_32_BIT)
+			vamgr = &dev->vamgr_high_32;
+		else
+			vamgr = &dev->vamgr_high;
+	} else {
+		if (flags & AMDGPU_VA_RANGE_32_BIT)
+			vamgr = &dev->vamgr_32;
+		else
+			vamgr = &dev->vamgr;
+	}
 
 	va_base_alignment = MAX2(va_base_alignment, vamgr->va_alignment);
 	size = ALIGN(size, vamgr->va_alignment);
@@ -249,7 +222,10 @@
 	if (!(flags & AMDGPU_VA_RANGE_32_BIT) &&
 	    (*va_base_allocated == AMDGPU_INVALID_VA_ADDRESS)) {
 		/* fallback to 32bit address */
-		vamgr = dev->vamgr_32;
+		if (flags & AMDGPU_VA_RANGE_HIGH)
+			vamgr = &dev->vamgr_high_32;
+		else
+			vamgr = &dev->vamgr_32;
 		*va_base_allocated = amdgpu_vamgr_find_va(vamgr, size,
 					va_base_alignment, va_base_required);
 	}
@@ -274,7 +250,7 @@
 	return 0;
 }
 
-int amdgpu_va_range_free(amdgpu_va_handle va_range_handle)
+drm_public int amdgpu_va_range_free(amdgpu_va_handle va_range_handle)
 {
 	if(!va_range_handle || !va_range_handle->address)
 		return 0;
diff --git a/amdgpu/amdgpu_vm.c b/amdgpu/amdgpu_vm.c
new file mode 100644
index 0000000..7e6e28f
--- /dev/null
+++ b/amdgpu/amdgpu_vm.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 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 "amdgpu.h"
+#include "amdgpu_drm.h"
+#include "xf86drm.h"
+#include "amdgpu_internal.h"
+
+drm_public int amdgpu_vm_reserve_vmid(amdgpu_device_handle dev, uint32_t flags)
+{
+	union drm_amdgpu_vm vm;
+
+	vm.in.op = AMDGPU_VM_OP_RESERVE_VMID;
+	vm.in.flags = flags;
+
+	return drmCommandWriteRead(dev->fd, DRM_AMDGPU_VM,
+				   &vm, sizeof(vm));
+}
+
+drm_public int amdgpu_vm_unreserve_vmid(amdgpu_device_handle dev,
+					uint32_t flags)
+{
+	union drm_amdgpu_vm vm;
+
+	vm.in.op = AMDGPU_VM_OP_UNRESERVE_VMID;
+	vm.in.flags = flags;
+
+	return drmCommandWriteRead(dev->fd, DRM_AMDGPU_VM,
+				   &vm, sizeof(vm));
+}
diff --git a/amdgpu/handle_table.c b/amdgpu/handle_table.c
new file mode 100644
index 0000000..4fdd29d
--- /dev/null
+++ b/amdgpu/handle_table.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018 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 <errno.h>
+#include <unistd.h>
+#include "handle_table.h"
+#include "util_math.h"
+
+drm_private int handle_table_insert(struct handle_table *table, uint32_t key,
+				    void *value)
+{
+	if (key >= table->max_key) {
+		uint32_t alignment = sysconf(_SC_PAGESIZE) / sizeof(void*);
+		uint32_t max_key = ALIGN(key + 1, alignment);
+		void **values;
+
+		values = realloc(table->values, max_key * sizeof(void *));
+		if (!values)
+			return -ENOMEM;
+
+		memset(values + table->max_key, 0, (max_key - table->max_key) *
+		       sizeof(void *));
+
+		table->max_key = max_key;
+		table->values = values;
+	}
+	table->values[key] = value;
+	return 0;
+}
+
+drm_private void handle_table_remove(struct handle_table *table, uint32_t key)
+{
+	if (key < table->max_key)
+		table->values[key] = NULL;
+}
+
+drm_private void *handle_table_lookup(struct handle_table *table, uint32_t key)
+{
+	if (key < table->max_key)
+		return table->values[key];
+	else
+		return NULL;
+}
+
+drm_private void handle_table_fini(struct handle_table *table)
+{
+	free(table->values);
+	table->max_key = 0;
+	table->values = NULL;
+}
diff --git a/amdgpu/handle_table.h b/amdgpu/handle_table.h
new file mode 100644
index 0000000..461193f
--- /dev/null
+++ b/amdgpu/handle_table.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 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 _HANDLE_TABLE_H_
+#define _HANDLE_TABLE_H_
+
+#include <stdint.h>
+#include "libdrm_macros.h"
+
+struct handle_table {
+	uint32_t	max_key;
+	void		**values;
+};
+
+drm_private int handle_table_insert(struct handle_table *table, uint32_t key,
+				    void *value);
+drm_private void handle_table_remove(struct handle_table *table, uint32_t key);
+drm_private void *handle_table_lookup(struct handle_table *table, uint32_t key);
+drm_private void handle_table_fini(struct handle_table *table);
+
+#endif /* _HANDLE_TABLE_H_ */
diff --git a/amdgpu/meson.build b/amdgpu/meson.build
new file mode 100644
index 0000000..7c8ccc7
--- /dev/null
+++ b/amdgpu/meson.build
@@ -0,0 +1,65 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+
+datadir_amdgpu = join_paths(get_option('prefix'), get_option('datadir'), 'libdrm')
+
+libdrm_amdgpu = shared_library(
+  'drm_amdgpu',
+  [
+    files(
+      'amdgpu_asic_id.c', 'amdgpu_bo.c', 'amdgpu_cs.c', 'amdgpu_device.c',
+      'amdgpu_gpu_info.c', 'amdgpu_vamgr.c', 'amdgpu_vm.c', 'handle_table.c',
+    ),
+    config_file,
+  ],
+  c_args : [
+    libdrm_c_args,
+    '-DAMDGPU_ASIC_ID_TABLE="@0@"'.format(join_paths(datadir_amdgpu, 'amdgpu.ids')),
+  ],
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  dependencies : [dep_pthread_stubs, dep_atomic_ops],
+  version : '1.0.0',
+  install : true,
+)
+
+install_headers('amdgpu.h', subdir : 'libdrm')
+
+pkg.generate(
+  name : 'libdrm_amdgpu',
+  libraries : libdrm_amdgpu,
+  subdirs : ['.', 'libdrm'],
+  version : meson.project_version(),
+  requires_private : 'libdrm',
+  description : 'Userspace interface to kernel DRM services for amdgpu',
+)
+
+ext_libdrm_amdgpu = declare_dependency(
+  link_with : [libdrm, libdrm_amdgpu],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+test(
+  'amdgpu-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('amdgpu-symbol-check'), libdrm_amdgpu]
+)
diff --git a/amdgpu/util_hash.c b/amdgpu/util_hash.c
deleted file mode 100644
index 87cb671..0000000
--- a/amdgpu/util_hash.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/**************************************************************************
- *
- * 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>
-  */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#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;
-}
-
-drm_private 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;
-      }
-   }
-}
-
-drm_private 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;
-}
-
-drm_private 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);
-}
-
-drm_private 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;
-}
-
-drm_private 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;
-}
-
-drm_private 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;
-}
-
-drm_private 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;
-}
-
-drm_private int util_hash_iter_is_null(struct util_hash_iter iter)
-{
-   if (!iter.node || iter.node == iter.hash->data.e)
-      return 1;
-   return 0;
-}
-
-drm_private 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;
-}
-
-drm_private 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;
-}
-
-drm_private 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
deleted file mode 100644
index 01a4779..0000000
--- a/amdgpu/util_hash.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/**************************************************************************
- *
- * 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
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdbool.h>
-
-#include "libdrm_macros.h"
-
-struct util_hash;
-struct util_node;
-
-struct util_hash_iter {
-	struct util_hash *hash;
-	struct util_node *node;
-};
-
-
-drm_private struct util_hash *util_hash_create(void);
-drm_private 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.
- */
-drm_private 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.
- */
-drm_private struct util_hash_iter
-util_hash_erase(struct util_hash *hash, struct util_hash_iter iter);
-
-drm_private void *util_hash_take(struct util_hash *hash, unsigned key);
-
-
-drm_private struct util_hash_iter util_hash_first_node(struct util_hash *hash);
-
-/**
- * Return an iterator pointing to the first entry in the collision list.
- */
-drm_private struct util_hash_iter
-util_hash_find(struct util_hash *hash, unsigned key);
-
-
-drm_private int util_hash_iter_is_null(struct util_hash_iter iter);
-drm_private unsigned util_hash_iter_key(struct util_hash_iter iter);
-drm_private void *util_hash_iter_data(struct util_hash_iter iter);
-
-
-drm_private 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
deleted file mode 100644
index fa7f6ea..0000000
--- a/amdgpu/util_hash_table.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/**************************************************************************
- *
- * 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>
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#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);
-}
-
-drm_private 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;
-}
-
-drm_private 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;
-	}
-}
-
-drm_private 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;
-}
-
-drm_private 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);
-}
-
-drm_private 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);
-	}
-}
-
-drm_private 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);
-	}
-}
-
-drm_private 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
deleted file mode 100644
index e000128..0000000
--- a/amdgpu/util_hash_table.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/**************************************************************************
- *
- * 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_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "libdrm_macros.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.
- */
-drm_private struct util_hash_table *
-util_hash_table_create(unsigned (*hash)(void *key),
-		       int (*compare)(void *key1, void *key2));
-
-drm_private void
-util_hash_table_set(struct util_hash_table *ht, void *key, void *value);
-
-drm_private void *util_hash_table_get(struct util_hash_table *ht, void *key);
-
-drm_private void util_hash_table_remove(struct util_hash_table *ht, void *key);
-
-drm_private void util_hash_table_clear(struct util_hash_table *ht);
-
-drm_private void util_hash_table_foreach(struct util_hash_table *ht,
-			void (*callback)(void *key, void *value, void *data),
-			void *data);
-
-drm_private void util_hash_table_destroy(struct util_hash_table *ht);
-
-#endif /* U_HASH_TABLE_H_ */
diff --git a/android/gralloc_handle.h b/android/gralloc_handle.h
new file mode 100644
index 0000000..d3d975e
--- /dev/null
+++ b/android/gralloc_handle.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ * Copyright (C) 2016 Linaro, Ltd., Rob Herring <robh@kernel.org>
+ * Copyright (C) 2018 Collabora, Robert Foss <robert.foss@collabora.com>
+ *
+ * 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 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.
+ */
+
+#ifndef __ANDROID_GRALLOC_HANDLE_H__
+#define __ANDROID_GRALLOC_HANDLE_H__
+
+#include <cutils/native_handle.h>
+#include <stdint.h>
+
+/* support users of drm_gralloc/gbm_gralloc */
+#define gralloc_gbm_handle_t gralloc_handle_t
+#define gralloc_drm_handle_t gralloc_handle_t
+
+struct gralloc_handle_t {
+	native_handle_t base;
+
+	/* dma-buf file descriptor
+	 * Must be located first since, native_handle_t is allocated
+	 * using native_handle_create(), which allocates space for
+	 * sizeof(native_handle_t) + sizeof(int) * (numFds + numInts)
+	 * numFds = GRALLOC_HANDLE_NUM_FDS
+	 * numInts = GRALLOC_HANDLE_NUM_INTS
+	 * Where numFds represents the number of FDs and
+	 * numInts represents the space needed for the
+	 * remainder of this struct.
+	 * And the FDs are expected to be found first following
+	 * native_handle_t.
+	 */
+	int prime_fd;
+
+	/* api variables */
+	uint32_t magic; /* differentiate between allocator impls */
+	uint32_t version; /* api version */
+
+	uint32_t width; /* width of buffer in pixels */
+	uint32_t height; /* height of buffer in pixels */
+	uint32_t format; /* pixel format (Android) */
+	uint32_t usage; /* android libhardware usage flags */
+
+	uint32_t stride; /* the stride in bytes */
+	int data_owner; /* owner of data (for validation) */
+	uint64_t modifier __attribute__((aligned(8))); /* buffer modifiers */
+
+	union {
+		void *data; /* pointer to struct gralloc_gbm_bo_t */
+		uint64_t reserved;
+	} __attribute__((aligned(8)));
+};
+
+#define GRALLOC_HANDLE_VERSION 4
+#define GRALLOC_HANDLE_MAGIC 0x60585350
+#define GRALLOC_HANDLE_NUM_FDS 1
+#define GRALLOC_HANDLE_NUM_INTS (	\
+	((sizeof(struct gralloc_handle_t) - sizeof(native_handle_t))/sizeof(int))	\
+	 - GRALLOC_HANDLE_NUM_FDS)
+
+static inline struct gralloc_handle_t *gralloc_handle(buffer_handle_t handle)
+{
+	return (struct gralloc_handle_t *)handle;
+}
+
+/**
+ * Create a buffer handle.
+ */
+static inline native_handle_t *gralloc_handle_create(int32_t width,
+                                                     int32_t height,
+                                                     int32_t hal_format,
+                                                     int32_t usage)
+{
+	struct gralloc_handle_t *handle;
+	native_handle_t *nhandle = native_handle_create(GRALLOC_HANDLE_NUM_FDS,
+							GRALLOC_HANDLE_NUM_INTS);
+
+	if (!nhandle)
+		return NULL;
+
+	handle = gralloc_handle(nhandle);
+	handle->magic = GRALLOC_HANDLE_MAGIC;
+	handle->version = GRALLOC_HANDLE_VERSION;
+	handle->width = width;
+	handle->height = height;
+	handle->format = hal_format;
+	handle->usage = usage;
+	handle->prime_fd = -1;
+
+	return nhandle;
+}
+
+#endif
diff --git a/autogen.sh b/autogen.sh
index d82ab18..13d6991 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -6,15 +6,15 @@
 ORIGDIR=`pwd`
 cd "$srcdir"
 
-autoreconf --force --verbose --install || exit 1
-cd "$ORIGDIR" || exit $?
-
-git config --local --get format.subjectPrefix ||
+git config --local --get format.subjectPrefix >/dev/null ||
     git config --local format.subjectPrefix "PATCH libdrm" 2>/dev/null
 
-git config --local --get sendemail.to ||
+git config --local --get sendemail.to >/dev/null ||
     git config --local sendemail.to "dri-devel@lists.freedesktop.org" 2>/dev/null
 
+autoreconf --force --verbose --install || exit 1
+cd "$ORIGDIR" || exit $?
+
 if test -z "$NOCONFIGURE"; then
     "$srcdir"/configure "$@"
 fi
diff --git a/configure.ac b/configure.ac
index 1da9d86..7e7c8d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@
 
 AC_PREREQ([2.63])
 AC_INIT([libdrm],
-        [2.4.75],
+        [2.4.97],
         [https://bugs.freedesktop.org/enter_bug.cgi?product=DRI],
         [libdrm])
 
@@ -28,6 +28,7 @@
 AC_CONFIG_SRCDIR([Makefile.am])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
+PKG_PROG_PKG_CONFIG
 
 # Require xorg-macros minimum of 1.12 for XORG_WITH_XSLTPROC
 m4_ifndef([XORG_MACROS_VERSION],
@@ -44,6 +45,7 @@
 # Check for programs
 AC_PROG_CC
 AC_PROG_CC_C99
+AC_PROG_NM
 
 if test "x$ac_cv_prog_cc_c99" = xno; then
 	AC_MSG_ERROR([Building libdrm requires C99 enabled compiler])
@@ -53,20 +55,39 @@
 AC_SYS_LARGEFILE
 AC_FUNC_ALLOCA
 
+save_CFLAGS="$CFLAGS"
+export CFLAGS="$CFLAGS -Werror"
 AC_HEADER_MAJOR
+CFLAGS="$save_CFLAGS"
+
 AC_CHECK_HEADERS([sys/sysctl.h sys/select.h])
 
 # Initialize libtool
 LT_PREREQ([2.2])
 LT_INIT([disable-static])
 
+dnl pthread-stubs is mandatory on some BSD platforms, due to the nature of the
+dnl project. Even then there's a notable issue as described in the project README
+case "$host_os" in
+linux* | cygwin* | darwin* | solaris* | *-gnu* | gnu* | openbsd*)
+    pthread_stubs_possible="no"
+    ;;
+* )
+    pthread_stubs_possible="yes"
+    ;;
+esac
 
-
-AC_SUBST(PTHREADSTUBS_CFLAGS)
-AC_SUBST(PTHREADSTUBS_LIBS)
+if test "x$pthread_stubs_possible" = xyes; then
+    PKG_CHECK_MODULES(PTHREADSTUBS, pthread-stubs >= 0.4)
+    AC_SUBST(PTHREADSTUBS_CFLAGS)
+    AC_SUBST(PTHREADSTUBS_LIBS)
+fi
 
 pkgconfigdir=${libdir}/pkgconfig
 AC_SUBST(pkgconfigdir)
+libdrmdatadir=${datadir}/libdrm
+AC_SUBST(libdrmdatadir)
+
 AC_ARG_ENABLE([udev],
               [AS_HELP_STRING([--enable-udev],
                               [Enable support for using udev instead of mknod (default: disabled)])],
@@ -127,11 +148,6 @@
 	      [Enable support for Tegra's experimental API (default: disabled)]),
 	      [TEGRA=$enableval], [TEGRA=no])
 
-AC_ARG_ENABLE(rockchip-experimental-api,
-	      AS_HELP_STRING([--enable-rockchip-experimental-api],
-	      [Enable support for rockchip's experimental API (default: disabled)]),
-	      [ROCKCHIP=$enableval], [ROCKCHIP=no])
-
 AC_ARG_ENABLE(vc4,
 	      AS_HELP_STRING([--disable-vc4],
 	      [Enable support for vc4's API (default: auto, enabled on arm)]),
@@ -173,7 +189,9 @@
                              [AC_MSG_ERROR([Couldn't find clock_gettime])])])
 AC_SUBST([CLOCK_LIB])
 
-AC_CHECK_FUNCS([open_memstream], [HAVE_OPEN_MEMSTREAM=yes])
+AC_CHECK_FUNCS([open_memstream],
+               [AC_DEFINE([HAVE_OPEN_MEMSTREAM], 1, [Have open_memstream()])],
+               [AC_DEFINE([HAVE_OPEN_MEMSTREAM], 0)])
 
 dnl Use lots of warning flags with with gcc and compatible compilers
 
@@ -182,7 +200,7 @@
 dnl else.  If for any reason you need to force a recheck, just change
 dnl MAYBE_WARN in an ignorable way (like adding whitespace)
 
-MAYBE_WARN="-Wall -Wextra \
+MAYBE_WARN="-Wall -Wextra -Werror=undef \
 -Wsign-compare -Werror-implicit-function-declaration \
 -Wpointer-arith -Wwrite-strings -Wstrict-prototypes \
 -Wmissing-prototypes -Wmissing-declarations -Wnested-externs \
@@ -244,9 +262,13 @@
 if test "x$drm_cv_atomic_primitives" = xIntel; then
 	AC_DEFINE(HAVE_LIBDRM_ATOMIC_PRIMITIVES, 1,
 		[Enable if your compiler supports the Intel __sync_* atomic primitives])
+else
+	AC_DEFINE(HAVE_LIBDRM_ATOMIC_PRIMITIVES, 0)
 fi
 if test "x$drm_cv_atomic_primitives" = "xlibatomic-ops"; then
 	AC_DEFINE(HAVE_LIB_ATOMIC_OPS, 1, [Enable if you have libatomic-ops-dev installed])
+else
+	AC_DEFINE(HAVE_LIB_ATOMIC_OPS, 0)
 fi
 
 dnl Print out the approapriate message considering the value set be the
@@ -325,6 +347,8 @@
 
 if test "x$UDEV" = xyes; then
 	AC_DEFINE(UDEV, 1, [Have UDEV support])
+else
+	AC_DEFINE(UDEV, 0)
 fi
 
 AC_CANONICAL_HOST
@@ -343,32 +367,34 @@
 AM_CONDITIONAL(HAVE_INTEL, [test "x$INTEL" = xyes])
 if test "x$INTEL" = xyes; then
 	AC_DEFINE(HAVE_INTEL, 1, [Have intel support])
+else
+	AC_DEFINE(HAVE_INTEL, 0)
 fi
 
 AM_CONDITIONAL(HAVE_VMWGFX, [test "x$VMWGFX" = xyes])
 if test "x$VMWGFX" = xyes; then
 	AC_DEFINE(HAVE_VMWGFX, 1, [Have vmwgfx kernel headers])
+else
+	AC_DEFINE(HAVE_VMWGFX, 0)
 fi
 
 AM_CONDITIONAL(HAVE_NOUVEAU, [test "x$NOUVEAU" = xyes])
 if test "x$NOUVEAU" = xyes; then
 	AC_DEFINE(HAVE_NOUVEAU, 1, [Have nouveau (nvidia) support])
+else
+	AC_DEFINE(HAVE_NOUVEAU, 0)
 fi
 
 AM_CONDITIONAL(HAVE_OMAP, [test "x$OMAP" = xyes])
-if test "x$OMAP" = xyes; then
-	AC_DEFINE(HAVE_OMAP, 1, [Have OMAP support])
-fi
 
 AM_CONDITIONAL(HAVE_EXYNOS, [test "x$EXYNOS" = xyes])
 if test "x$EXYNOS" = xyes; then
 	AC_DEFINE(HAVE_EXYNOS, 1, [Have EXYNOS support])
+else
+	AC_DEFINE(HAVE_EXYNOS, 0)
 fi
 
 AM_CONDITIONAL(HAVE_FREEDRENO, [test "x$FREEDRENO" = xyes])
-if test "x$FREEDRENO" = xyes; then
-	AC_DEFINE(HAVE_FREEDRENO, 1, [Have freedreno support])
-fi
 
 if test "x$FREEDRENO_KGSL" = xyes; then
 	if test "x$FREEDRENO" != xyes; then
@@ -378,11 +404,15 @@
 AM_CONDITIONAL(HAVE_FREEDRENO_KGSL, [test "x$FREEDRENO_KGSL" = xyes])
 if test "x$FREEDRENO_KGSL" = xyes; then
 	AC_DEFINE(HAVE_FREEDRENO_KGSL, 1, [Have freedreno support for KGSL kernel interface])
+else
+	AC_DEFINE(HAVE_FREEDRENO_KGSL, 0)
 fi
 
 AM_CONDITIONAL(HAVE_RADEON, [test "x$RADEON" = xyes])
 if test "x$RADEON" = xyes; then
 	AC_DEFINE(HAVE_RADEON, 1, [Have radeon support])
+else
+	AC_DEFINE(HAVE_RADEON, 0)
 fi
 
 if test "x$AMDGPU" != xno; then
@@ -409,36 +439,25 @@
 if test "x$AMDGPU" = xyes; then
 	AC_DEFINE(HAVE_AMDGPU, 1, [Have amdgpu support])
 
-	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
+else
+	AC_DEFINE(HAVE_AMDGPU, 0)
 fi
 
 AM_CONDITIONAL(HAVE_TEGRA, [test "x$TEGRA" = xyes])
-if test "x$TEGRA" = xyes; then
-	AC_DEFINE(HAVE_TEGRA, 1, [Have Tegra support])
-fi
-
-AM_CONDITIONAL(HAVE_ROCKCHIP, [test "x$ROCKCHIP" = xyes])
-if test "x$ROCKCHIP" = xyes; then
-	AC_DEFINE(HAVE_ROCKCHIP, 1, [Have ROCKCHIP support])
 
 AM_CONDITIONAL(HAVE_VC4, [test "x$VC4" = xyes])
 if test "x$VC4" = xyes; then
 	AC_DEFINE(HAVE_VC4, 1, [Have VC4 support])
+else
+	AC_DEFINE(HAVE_VC4, 0)
 fi
 
 AM_CONDITIONAL(HAVE_ETNAVIV, [test "x$ETNAVIV" = xyes])
-if test "x$ETNAVIV" = xyes; then
-	AC_DEFINE(HAVE_ETNAVIV, 1, [Have etnaviv support])
-fi
 
 AM_CONDITIONAL(HAVE_INSTALL_TESTS, [test "x$INSTALL_TESTS" = xyes])
-if test "x$INSTALL_TESTS" = xyes; then
-	AC_DEFINE(HAVE_INSTALL_TESTS, 1, [Install test programs])
-fi
 
 AC_ARG_ENABLE([cairo-tests],
               [AS_HELP_STRING([--enable-cairo-tests],
@@ -456,6 +475,8 @@
 		AC_MSG_ERROR([Cairo support required but not present])
 	fi
 	AC_DEFINE(HAVE_CAIRO, 1, [Have Cairo support])
+else
+	AC_DEFINE(HAVE_CAIRO, 0)
 fi
 AC_MSG_RESULT([$CAIRO])
 AM_CONDITIONAL(HAVE_CAIRO, [test "x$CAIRO" = xyes])
@@ -497,6 +518,8 @@
 		AC_MSG_ERROR([Valgrind support required but not present])
 	fi
 	AC_DEFINE([HAVE_VALGRIND], 1, [Use valgrind intrinsics to suppress false warnings])
+else
+	AC_DEFINE([HAVE_VALGRIND], 0)
 fi
 
 AC_MSG_RESULT([$VALGRIND])
@@ -514,11 +537,16 @@
 
 if test "x$HAVE_ATTRIBUTE_VISIBILITY" = xyes; then
     AC_DEFINE(HAVE_VISIBILITY, 1, [Compiler supports __attribute__(("hidden"))])
+else
+    AC_DEFINE(HAVE_VISIBILITY, 0)
 fi
 
+CFLAGS="$CFLAGS -include config.h"
+
 AC_SUBST(WARN_CFLAGS)
 AC_CONFIG_FILES([
 	Makefile
+	data/Makefile
 	libkms/Makefile
 	libkms/libkms.pc
 	intel/Makefile
@@ -537,8 +565,6 @@
 	freedreno/libdrm_freedreno.pc
 	tegra/Makefile
 	tegra/libdrm_tegra.pc
-	rockchip/Makefile
-	rockchip/libdrm_rockchip.pc
 	vc4/Makefile
 	vc4/libdrm_vc4.pc
 	etnaviv/Makefile
@@ -555,7 +581,6 @@
 	tests/exynos/Makefile
 	tests/tegra/Makefile
 	tests/nouveau/Makefile
-	tests/planetest/Makefile
 	tests/etnaviv/Makefile
 	tests/util/Makefile
 	man/Makefile
@@ -575,7 +600,6 @@
 echo "  EXYNOS API     $EXYNOS"
 echo "  Freedreno API  $FREEDRENO (kgsl: $FREEDRENO_KGSL)"
 echo "  Tegra API      $TEGRA"
-echo "  Rockchip API   $ROCKCHIP"
 echo "  VC4 API        $VC4"
 echo "  Etnaviv API    $ETNAVIV"
 echo ""
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644
index 0000000..897a7f3
--- /dev/null
+++ b/data/Makefile.am
@@ -0,0 +1,25 @@
+#  Copyright © 2017 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
+#  on 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
+#  ADAM JACKSON 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.
+
+libdrmdatadir = @libdrmdatadir@
+if HAVE_AMDGPU
+dist_libdrmdata_DATA = amdgpu.ids
+endif
diff --git a/data/amdgpu.ids b/data/amdgpu.ids
new file mode 100644
index 0000000..d9ed566
--- /dev/null
+++ b/data/amdgpu.ids
@@ -0,0 +1,197 @@
+# List of AMDGPU IDs
+#
+# Syntax:
+# device_id,	revision_id,	product_name        <-- single tab after comma
+
+1.0.0
+6600,	0,	AMD Radeon HD 8600/8700M
+6600,	81,	AMD Radeon (TM) R7 M370
+6601,	0,	AMD Radeon (TM) HD 8500M/8700M
+6604,	0,	AMD Radeon R7 M265 Series
+6604,	81,	AMD Radeon (TM) R7 M350
+6605,	0,	AMD Radeon R7 M260 Series
+6605,	81,	AMD Radeon (TM) R7 M340
+6606,	0,	AMD Radeon HD 8790M
+6607,	0,	AMD Radeon (TM) HD8530M
+6608,	0,	AMD FirePro W2100
+6610,	0,	AMD Radeon HD 8600 Series
+6610,	81,	AMD Radeon (TM) R7 350
+6610,	83,	AMD Radeon (TM) R5 340
+6611,	0,	AMD Radeon HD 8500 Series
+6613,	0,	AMD Radeon HD 8500 series
+6617,	C7,	AMD Radeon R7 240 Series
+6640,	0,	AMD Radeon HD 8950
+6640,	80,	AMD Radeon (TM) R9 M380
+6646,	0,	AMD Radeon R9 M280X
+6646,	80,	AMD Radeon (TM) R9 M470X
+6647,	0,	AMD Radeon R9 M270X
+6647,	80,	AMD Radeon (TM) R9 M380
+6649,	0,	AMD FirePro W5100
+6658,	0,	AMD Radeon R7 200 Series
+665C,	0,	AMD Radeon HD 7700 Series
+665D,	0,	AMD Radeon R7 200 Series
+665F,	81,	AMD Radeon (TM) R7 300 Series
+6660,	0,	AMD Radeon HD 8600M Series
+6660,	81,	AMD Radeon (TM) R5 M335
+6660,	83,	AMD Radeon (TM) R5 M330
+6663,	0,	AMD Radeon HD 8500M Series
+6663,	83,	AMD Radeon (TM) R5 M320
+6664,	0,	AMD Radeon R5 M200 Series
+6665,	0,	AMD Radeon R5 M200 Series
+6665,	83,	AMD Radeon (TM) R5 M320
+6667,	0,	AMD Radeon R5 M200 Series
+666F,	0,	AMD Radeon HD 8500M
+6780,	0,	ATI FirePro V (FireGL V) Graphics Adapter
+678A,	0,	ATI FirePro V (FireGL V) Graphics Adapter
+6798,	0,	AMD Radeon HD 7900 Series
+679A,	0,	AMD Radeon HD 7900 Series
+679B,	0,	AMD Radeon HD 7900 Series
+679E,	0,	AMD Radeon HD 7800 Series
+67A0,	0,	AMD Radeon FirePro W9100
+67A1,	0,	AMD Radeon FirePro W8100
+67B0,	0,	AMD Radeon R9 200 Series
+67B0,	80,	AMD Radeon (TM) R9 390 Series
+67B1,	0,	AMD Radeon R9 200 Series
+67B1,	80,	AMD Radeon (TM) R9 390 Series
+67B9,	0,	AMD Radeon R9 200 Series
+67DF,	C1,	Radeon RX 580 Series
+67DF,	C2,	Radeon RX 570 Series
+67DF,	C3,	Radeon RX 580 Series
+67DF,	C4,	AMD Radeon (TM) RX 480 Graphics
+67DF,	C5,	AMD Radeon (TM) RX 470 Graphics
+67DF,	C6,	Radeon RX 570 Series
+67DF,	C7,	AMD Radeon (TM) RX 480 Graphics
+67DF,	CF,	AMD Radeon (TM) RX 470 Graphics
+67DF,	D7,	Radeon(TM) RX 470 Graphics
+67DF,	E0,	Radeon RX 470 Series
+67DF,	E1,	Radeon RX 590 Series
+67DF,	E3,	Radeon RX Series
+67DF,	E7,	Radeon RX 580 Series
+67DF,	EF,	Radeon RX 570 Series
+67DF,	F7,	Radeon RX P30PH
+67C2,	01,	AMD Radeon (TM) Pro V7350x2
+67C2,	02,	AMD Radeon (TM) Pro V7300X
+67C4,	00,	AMD Radeon (TM) Pro WX 7100 Graphics
+67C7,	00,	AMD Radeon (TM) Pro WX 5100 Graphics
+67C0,	00,	AMD Radeon (TM) Pro WX 7100 Graphics
+67D0,	01,	AMD Radeon (TM) Pro V7350x2
+67D0,	02,	AMD Radeon (TM) Pro V7300X
+67E0,	00,	AMD Radeon (TM) Pro WX Series
+67E3,	00,	AMD Radeon (TM) Pro WX 4100
+67E8,	00,	AMD Radeon (TM) Pro WX Series
+67E8,	01,	AMD Radeon (TM) Pro WX Series
+67E8,	80,	AMD Radeon (TM) E9260 Graphics
+67EB,	00,	AMD Radeon (TM) Pro V5300X
+67EF,	C0,	AMD Radeon (TM) RX Graphics
+67EF,	C1,	AMD Radeon (TM) RX 460 Graphics
+67EF,	C3,	Radeon RX Series
+67EF,	C5,	AMD Radeon (TM) RX 460 Graphics
+67EF,	C7,	AMD Radeon (TM) RX Graphics
+67EF,	CF,	AMD Radeon (TM) RX 460 Graphics
+67EF,	E2,	RX 560X
+67EF,	E0,	Radeon RX 560 Series
+67EF,	E1,	Radeon RX Series
+67EF,	E3,	Radeon RX Series
+67EF,	E5,	Radeon RX 560 Series
+67EF,	EF,	AMD Radeon (TM) RX Graphics
+67EF,	FF,	Radeon(TM) RX 460 Graphics
+67FF,	C0,	AMD Radeon (TM) RX Graphics
+67FF,	C1,	AMD Radeon (TM) RX Graphics
+67FF,	CF,	Radeon RX 560 Series
+67FF,	EF,	Radeon RX 560 Series
+67FF,	FF,	Radeon RX 550 Series
+6800,	0,	AMD Radeon HD 7970M
+6801,	0,	AMD Radeon(TM) HD8970M
+6808,	0,	ATI FirePro V(FireGL V) Graphics Adapter
+6809,	0,	ATI FirePro V(FireGL V) Graphics Adapter
+6810,	0,	AMD Radeon(TM) HD 8800 Series
+6810,	81,	AMD Radeon (TM) R7 370 Series
+6811,	0,	AMD Radeon(TM) HD8800 Series
+6811,	81,	AMD Radeon (TM) R7 300 Series
+6818,	0,	AMD Radeon HD 7800 Series
+6819,	0,	AMD Radeon HD 7800 Series
+6820,	0,	AMD Radeon HD 8800M Series
+6820,	81,	AMD Radeon (TM) R9 M375
+6820,	83,	AMD Radeon (TM) R9 M375X
+6821,	0,	AMD Radeon HD 8800M Series
+6821,	87,	AMD Radeon (TM) R7 M380
+6821,	83,	AMD Radeon R9 (TM) M370X
+6822,	0,	AMD Radeon E8860
+6823,	0,	AMD Radeon HD 8800M Series
+6825,	0,	AMD Radeon HD 7800M Series
+6827,	0,	AMD Radeon HD 7800M Series
+6828,	0,	ATI FirePro V(FireGL V) Graphics Adapter
+682B,	0,	AMD Radeon HD 8800M Series
+682B,	87,	AMD Radeon (TM) R9 M360
+682C,	0,	AMD FirePro W4100
+682D,	0,	AMD Radeon HD 7700M Series
+682F,	0,	AMD Radeon HD 7700M Series
+6835,	0,	AMD Radeon R7 Series / HD 9000 Series
+6837,	0,	AMD Radeon HD7700 Series
+683D,	0,	AMD Radeon HD 7700 Series
+683F,	0,	AMD Radeon HD 7700 Series
+6860,	00,	Radeon Instinct MI25
+6860,	01,	Radeon Instinct MI25
+6860,	02,	Radeon Instinct MI25
+6860,	03,	Radeon Pro V340
+6860,	04,	Radeon Instinct MI25x2
+6861,	00,	Radeon Pro WX 9100
+6862,	00,	Radeon Pro SSG
+6863,	00,	Radeon Vega Frontier Edition
+6864,	03,	Radeon Pro V340
+6864,	04,	Instinct MI25x2
+6868,	00,	Radeon (TM) PRO WX 8200
+686C,	00,	Radeon Instinct MI25 MxGPU
+686C,	01,	Radeon Instinct MI25 MxGPU
+686C,	02,	Radeon Instinct MI25 MxGPU
+686C,	03,	Radeon Pro V340 MxGPU
+686C,	04,	Radeon Instinct MI25x2 MxGPU
+686C,	05,	Radeon Pro V340L MxGPU
+686C,	06,	Radeon Instinct MI25 MxGPU
+687F,	C0,	Radeon RX Vega
+687F,	C1,	Radeon RX Vega
+687F,	C3,	Radeon RX Vega
+6900,	0,	AMD Radeon R7 M260
+6900,	81,	AMD Radeon (TM) R7 M360
+6900,	83,	AMD Radeon (TM) R7 M340
+6901,	0,	AMD Radeon R5 M255
+6907,	0,	AMD Radeon R5 M255
+6907,	87,	AMD Radeon (TM) R5 M315
+6920,	0,	AMD RADEON R9 M395X
+6920,	1,	AMD RADEON R9 M390X
+6921,	0,	AMD Radeon R9 M295X
+6929,	0,	AMD FirePro S7150
+692B,	0,	AMD FirePro W7100
+6938,	0,	AMD Radeon R9 200 Series
+6938,	F0,	AMD Radeon R9 200 Series
+6938,	F1,	AMD Radeon (TM) R9 380 Series
+6939,	F0,	AMD Radeon R9 200 Series
+6939,	0,	AMD Radeon R9 200 Series
+6939,	F1,	AMD Radeon (TM) R9 380 Series
+6980,	00,	Radeon Pro WX3100
+6985,	00,	AMD Radeon Pro WX3100
+6987,	80,	AMD Embedded Radeon E9171
+6987,	C0,	Radeon 550X Series
+6987,	C3,	Radeon 540X Series
+6995,	00,	AMD Radeon Pro WX2100
+6997,	00,	Radeon Pro WX2100
+699F,	81,	AMD Embedded Radeon E9170 Series
+699F,	C0,	Radeon 500 Series
+699F,	C1,	Radeon 540 Series
+699F,	C3,	Radeon 500 Series
+699F,	C7,	Radeon 550 Series
+7300,	C1,	AMD FirePro (TM) S9300 x2
+7300,	C8,	AMD Radeon (TM) R9 Fury Series
+7300,	C9,	Radeon (TM) Pro Duo
+7300,	CB,	AMD Radeon (TM) R9 Fury Series
+7300,	CA,	AMD Radeon (TM) R9 Fury Series
+9874,	C4,	AMD Radeon R7 Graphics
+9874,	C5,	AMD Radeon R6 Graphics
+9874,	C6,	AMD Radeon R6 Graphics
+9874,	C7,	AMD Radeon R5 Graphics
+9874,	C8,	AMD Radeon R7 Graphics
+9874,	81,	AMD Radeon R6 Graphics
+9874,	87,	AMD Radeon R5 Graphics
+9874,	85,	AMD Radeon R6 Graphics
+9874,	84,	AMD Radeon R7 Graphics
+6FDF,	EF,	AMD Radeon RX 580 2048SP
diff --git a/data/meson.build b/data/meson.build
new file mode 100644
index 0000000..9c26b66
--- /dev/null
+++ b/data/meson.build
@@ -0,0 +1,27 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+if with_amdgpu
+  install_data(
+    'amdgpu.ids',
+    install_mode : 'rw-r--r--',
+    install_dir : datadir_amdgpu,
+  )
+endif
diff --git a/etnaviv/Makefile.am b/etnaviv/Makefile.am
index be96ba8..648e3c5 100644
--- a/etnaviv/Makefile.am
+++ b/etnaviv/Makefile.am
@@ -2,6 +2,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	-I$(top_srcdir)/include/drm
@@ -22,5 +23,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_etnaviv.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = etnaviv-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/etnaviv/Makefile.sources b/etnaviv/Makefile.sources
index 5258056..0eb7378 100644
--- a/etnaviv/Makefile.sources
+++ b/etnaviv/Makefile.sources
@@ -3,6 +3,7 @@
 	etnaviv_gpu.c \
 	etnaviv_bo.c \
 	etnaviv_bo_cache.c \
+	etnaviv_perfmon.c \
 	etnaviv_pipe.c \
 	etnaviv_cmd_stream.c \
 	etnaviv_drm.h \
diff --git a/etnaviv/etnaviv-symbol-check b/etnaviv/etnaviv-symbol-check
index 22afd16..1891068 100755
--- a/etnaviv/etnaviv-symbol-check
+++ b/etnaviv/etnaviv-symbol-check
@@ -1,5 +1,7 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.sources/LIBDRM_ETNAVIV_H_FILES
 
@@ -39,8 +41,14 @@
 etna_cmd_stream_del
 etna_cmd_stream_timestamp
 etna_cmd_stream_flush
+etna_cmd_stream_flush2
 etna_cmd_stream_finish
+etna_cmd_stream_perf
 etna_cmd_stream_reloc
+etna_perfmon_create
+etna_perfmon_del
+etna_perfmon_get_dom_by_name
+etna_perfmon_get_sig_by_name
 EOF
 done)
 
diff --git a/etnaviv/etnaviv_bo.c b/etnaviv/etnaviv_bo.c
index 4ad0434..43ce6b4 100644
--- a/etnaviv/etnaviv_bo.c
+++ b/etnaviv/etnaviv_bo.c
@@ -24,10 +24,6 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "etnaviv_priv.h"
 #include "etnaviv_drmif.h"
 
@@ -108,7 +104,7 @@
 }
 
 /* allocate a new (un-tiled) buffer object */
-struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size,
+drm_public struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size,
 		uint32_t flags)
 {
 	struct etna_bo *bo;
@@ -135,7 +131,7 @@
 	return bo;
 }
 
-struct etna_bo *etna_bo_ref(struct etna_bo *bo)
+drm_public struct etna_bo *etna_bo_ref(struct etna_bo *bo)
 {
 	atomic_inc(&bo->refcnt);
 
@@ -163,7 +159,8 @@
 }
 
 /* import a buffer object from DRI2 name */
-struct etna_bo *etna_bo_from_name(struct etna_device *dev, uint32_t name)
+drm_public struct etna_bo *etna_bo_from_name(struct etna_device *dev,
+		uint32_t name)
 {
 	struct etna_bo *bo;
 	struct drm_gem_open req = {
@@ -173,7 +170,7 @@
 	pthread_mutex_lock(&table_lock);
 
 	/* check name table first, to see if bo is already open: */
-	bo = lookup_bo(dev->name_table, req.handle);
+	bo = lookup_bo(dev->name_table, name);
 	if (bo)
 		goto out_unlock;
 
@@ -200,16 +197,21 @@
  * fd so caller should close() the fd when it is otherwise done
  * with it (even if it is still using the 'struct etna_bo *')
  */
-struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd)
+drm_public struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd)
 {
 	struct etna_bo *bo;
 	int ret, size;
 	uint32_t handle;
 
+	/* take the lock before calling drmPrimeFDToHandle to avoid
+	 * racing against etna_bo_del, which might invalidate the
+	 * returned handle.
+	 */
 	pthread_mutex_lock(&table_lock);
 
 	ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
 	if (ret) {
+		pthread_mutex_unlock(&table_lock);
 		return NULL;
 	}
 
@@ -230,7 +232,7 @@
 }
 
 /* destroy a buffer object */
-void etna_bo_del(struct etna_bo *bo)
+drm_public void etna_bo_del(struct etna_bo *bo)
 {
 	struct etna_device *dev = bo->dev;
 
@@ -252,7 +254,7 @@
 }
 
 /* get the global flink/DRI2 buffer name */
-int etna_bo_get_name(struct etna_bo *bo, uint32_t *name)
+drm_public int etna_bo_get_name(struct etna_bo *bo, uint32_t *name)
 {
 	if (!bo->name) {
 		struct drm_gem_flink req = {
@@ -276,7 +278,7 @@
 	return 0;
 }
 
-uint32_t etna_bo_handle(struct etna_bo *bo)
+drm_public uint32_t etna_bo_handle(struct etna_bo *bo)
 {
 	return bo->handle;
 }
@@ -284,7 +286,7 @@
 /* caller owns the dmabuf fd that is returned and is responsible
  * to close() it when done
  */
-int etna_bo_dmabuf(struct etna_bo *bo)
+drm_public int etna_bo_dmabuf(struct etna_bo *bo)
 {
 	int ret, prime_fd;
 
@@ -300,12 +302,12 @@
 	return prime_fd;
 }
 
-uint32_t etna_bo_size(struct etna_bo *bo)
+drm_public uint32_t etna_bo_size(struct etna_bo *bo)
 {
 	return bo->size;
 }
 
-void *etna_bo_map(struct etna_bo *bo)
+drm_public void *etna_bo_map(struct etna_bo *bo)
 {
 	if (!bo->map) {
 		if (!bo->offset) {
@@ -323,7 +325,7 @@
 	return bo->map;
 }
 
-int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op)
+drm_public int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op)
 {
 	struct drm_etnaviv_gem_cpu_prep req = {
 		.handle = bo->handle,
@@ -336,7 +338,7 @@
 			&req, sizeof(req));
 }
 
-void etna_bo_cpu_fini(struct etna_bo *bo)
+drm_public void etna_bo_cpu_fini(struct etna_bo *bo)
 {
 	struct drm_etnaviv_gem_cpu_fini req = {
 		.handle = bo->handle,
diff --git a/etnaviv/etnaviv_bo_cache.c b/etnaviv/etnaviv_bo_cache.c
index 8924651..c81de26 100644
--- a/etnaviv/etnaviv_bo_cache.c
+++ b/etnaviv/etnaviv_bo_cache.c
@@ -24,10 +24,6 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "etnaviv_priv.h"
 #include "etnaviv_drmif.h"
 
@@ -124,20 +120,32 @@
 
 static struct etna_bo *find_in_bucket(struct etna_bo_bucket *bucket, uint32_t flags)
 {
-	struct etna_bo *bo = NULL;
+	struct etna_bo *bo = NULL, *tmp;
 
 	pthread_mutex_lock(&table_lock);
-	while (!LIST_IS_EMPTY(&bucket->list)) {
-		bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list);
 
-		if (bo->flags == flags && is_idle(bo)) {
-			list_del(&bo->list);
-			break;
+	if (LIST_IS_EMPTY(&bucket->list))
+		goto out_unlock;
+
+	LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bucket->list, list) {
+		/* skip BOs with different flags */
+		if (bo->flags != flags)
+			continue;
+
+		/* check if the first BO with matching flags is idle */
+		if (is_idle(bo)) {
+			list_delinit(&bo->list);
+			goto out_unlock;
 		}
 
-		bo = NULL;
+		/* If the oldest BO is still busy, don't try younger ones */
 		break;
 	}
+
+	/* There was no matching buffer found */
+	bo = NULL;
+
+out_unlock:
 	pthread_mutex_unlock(&table_lock);
 
 	return bo;
diff --git a/etnaviv/etnaviv_cmd_stream.c b/etnaviv/etnaviv_cmd_stream.c
index 9ce3f36..7139c32 100644
--- a/etnaviv/etnaviv_cmd_stream.c
+++ b/etnaviv/etnaviv_cmd_stream.c
@@ -24,10 +24,6 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <assert.h>
 
 #include "etnaviv_drmif.h"
@@ -59,7 +55,8 @@
     return (struct etna_cmd_stream_priv *)stream;
 }
 
-struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, uint32_t size,
+drm_public struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe,
+        uint32_t size,
 		void (*reset_notify)(struct etna_cmd_stream *stream, void *priv),
 		void *priv)
 {
@@ -99,12 +96,13 @@
 	return NULL;
 }
 
-void etna_cmd_stream_del(struct etna_cmd_stream *stream)
+drm_public void etna_cmd_stream_del(struct etna_cmd_stream *stream)
 {
 	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
 
 	free(stream->buffer);
 	free(priv->submit.relocs);
+	free(priv->submit.pmrs);
 	free(priv);
 }
 
@@ -115,13 +113,14 @@
 	stream->offset = 0;
 	priv->submit.nr_bos = 0;
 	priv->submit.nr_relocs = 0;
+	priv->submit.nr_pmrs = 0;
 	priv->nr_bos = 0;
 
 	if (priv->reset_notify)
 		priv->reset_notify(stream, priv->reset_notify_priv);
 }
 
-uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream)
+drm_public uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream)
 {
 	return etna_cmd_stream_priv(stream)->last_timestamp;
 }
@@ -177,7 +176,8 @@
 	return idx;
 }
 
-static void flush(struct etna_cmd_stream *stream)
+static void flush(struct etna_cmd_stream *stream, int in_fence_fd,
+		  int *out_fence_fd)
 {
 	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
 	int ret, id = priv->pipe->id;
@@ -190,10 +190,20 @@
 		.nr_bos = priv->submit.nr_bos,
 		.relocs = VOID2U64(priv->submit.relocs),
 		.nr_relocs = priv->submit.nr_relocs,
+		.pmrs = VOID2U64(priv->submit.pmrs),
+		.nr_pmrs = priv->submit.nr_pmrs,
 		.stream = VOID2U64(stream->buffer),
 		.stream_size = stream->offset * 4, /* in bytes */
 	};
 
+	if (in_fence_fd != -1) {
+		req.flags |= ETNA_SUBMIT_FENCE_FD_IN | ETNA_SUBMIT_NO_IMPLICIT;
+		req.fence_fd = in_fence_fd;
+	}
+
+	if (out_fence_fd)
+		req.flags |= ETNA_SUBMIT_FENCE_FD_OUT;
+
 	ret = drmCommandWriteRead(gpu->dev->fd, DRM_ETNAVIV_GEM_SUBMIT,
 			&req, sizeof(req));
 
@@ -208,24 +218,36 @@
 		bo->current_stream = NULL;
 		etna_bo_del(bo);
 	}
+
+	if (out_fence_fd)
+		*out_fence_fd = req.fence_fd;
 }
 
-void etna_cmd_stream_flush(struct etna_cmd_stream *stream)
+drm_public void etna_cmd_stream_flush(struct etna_cmd_stream *stream)
 {
-	flush(stream);
+	flush(stream, -1, NULL);
 	reset_buffer(stream);
 }
 
-void etna_cmd_stream_finish(struct etna_cmd_stream *stream)
+drm_public void etna_cmd_stream_flush2(struct etna_cmd_stream *stream,
+									   int in_fence_fd,
+									   int *out_fence_fd)
+{
+	flush(stream, in_fence_fd, out_fence_fd);
+	reset_buffer(stream);
+}
+
+drm_public void etna_cmd_stream_finish(struct etna_cmd_stream *stream)
 {
 	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
 
-	flush(stream);
+	flush(stream, -1, NULL);
 	etna_pipe_wait(priv->pipe, priv->last_timestamp, 5000);
 	reset_buffer(stream);
 }
 
-void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, const struct etna_reloc *r)
+drm_public void etna_cmd_stream_reloc(struct etna_cmd_stream *stream,
+									  const struct etna_reloc *r)
 {
 	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
 	struct drm_etnaviv_gem_submit_reloc *reloc;
@@ -241,3 +263,19 @@
 
 	etna_cmd_stream_emit(stream, addr);
 }
+
+drm_public void etna_cmd_stream_perf(struct etna_cmd_stream *stream, const struct etna_perf *p)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+	struct drm_etnaviv_gem_submit_pmr *pmr;
+	uint32_t idx = APPEND(&priv->submit, pmrs);
+
+	pmr = &priv->submit.pmrs[idx];
+
+	pmr->flags = p->flags;
+	pmr->sequence = p->sequence;
+	pmr->read_offset = p->offset;
+	pmr->read_idx = bo2idx(stream, p->bo, ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE);
+	pmr->domain = p->signal->domain->id;
+	pmr->signal = p->signal->signal;
+}
diff --git a/etnaviv/etnaviv_device.c b/etnaviv/etnaviv_device.c
index 3ce9203..699df25 100644
--- a/etnaviv/etnaviv_device.c
+++ b/etnaviv/etnaviv_device.c
@@ -24,10 +24,6 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
@@ -45,7 +41,7 @@
 
 static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
 
-struct etna_device *etna_device_new(int fd)
+drm_public struct etna_device *etna_device_new(int fd)
 {
 	struct etna_device *dev = calloc(sizeof(*dev), 1);
 
@@ -63,7 +59,7 @@
 
 /* like etna_device_new() but creates it's own private dup() of the fd
  * which is close()d when the device is finalized. */
-struct etna_device *etna_device_new_dup(int fd)
+drm_public struct etna_device *etna_device_new_dup(int fd)
 {
 	int dup_fd = dup(fd);
 	struct etna_device *dev = etna_device_new(dup_fd);
@@ -76,7 +72,7 @@
 	return dev;
 }
 
-struct etna_device *etna_device_ref(struct etna_device *dev)
+drm_public struct etna_device *etna_device_ref(struct etna_device *dev)
 {
 	atomic_inc(&dev->refcnt);
 
@@ -103,7 +99,7 @@
 	etna_device_del_impl(dev);
 }
 
-void etna_device_del(struct etna_device *dev)
+drm_public void etna_device_del(struct etna_device *dev)
 {
 	if (!atomic_dec_and_test(&dev->refcnt))
 		return;
@@ -113,7 +109,7 @@
 	pthread_mutex_unlock(&table_lock);
 }
 
-int etna_device_fd(struct etna_device *dev)
+drm_public int etna_device_fd(struct etna_device *dev)
 {
    return dev->fd;
 }
diff --git a/etnaviv/etnaviv_drm.h b/etnaviv/etnaviv_drm.h
index 2584c1c..0d5c49d 100644
--- a/etnaviv/etnaviv_drm.h
+++ b/etnaviv/etnaviv_drm.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 /*
  * Copyright (C) 2015 Etnaviv Project
  *
@@ -54,6 +55,12 @@
 #define ETNAVIV_PARAM_GPU_FEATURES_4                0x07
 #define ETNAVIV_PARAM_GPU_FEATURES_5                0x08
 #define ETNAVIV_PARAM_GPU_FEATURES_6                0x09
+#define ETNAVIV_PARAM_GPU_FEATURES_7                0x0a
+#define ETNAVIV_PARAM_GPU_FEATURES_8                0x0b
+#define ETNAVIV_PARAM_GPU_FEATURES_9                0x0c
+#define ETNAVIV_PARAM_GPU_FEATURES_10               0x0d
+#define ETNAVIV_PARAM_GPU_FEATURES_11               0x0e
+#define ETNAVIV_PARAM_GPU_FEATURES_12               0x0f
 
 #define ETNAVIV_PARAM_GPU_STREAM_COUNT              0x10
 #define ETNAVIV_PARAM_GPU_REGISTER_MAX              0x11
@@ -150,10 +157,29 @@
 	__u64 presumed;       /* in/out, presumed buffer address */
 };
 
+/* performance monitor request (pmr) */
+#define ETNA_PM_PROCESS_PRE             0x0001
+#define ETNA_PM_PROCESS_POST            0x0002
+struct drm_etnaviv_gem_submit_pmr {
+	__u32 flags;          /* in, when to process request (ETNA_PM_PROCESS_x) */
+	__u8  domain;         /* in, pm domain */
+	__u8  pad;
+	__u16 signal;         /* in, pm signal */
+	__u32 sequence;       /* in, sequence number */
+	__u32 read_offset;    /* in, offset from read_bo */
+	__u32 read_idx;       /* in, index of read_bo buffer */
+};
+
 /* Each cmdstream submit consists of a table of buffers involved, and
  * one or more cmdstream buffers.  This allows for conditional execution
  * (context-restore), and IB buffers needed for per tile/bin draw cmds.
  */
+#define ETNA_SUBMIT_NO_IMPLICIT         0x0001
+#define ETNA_SUBMIT_FENCE_FD_IN         0x0002
+#define ETNA_SUBMIT_FENCE_FD_OUT        0x0004
+#define ETNA_SUBMIT_FLAGS		(ETNA_SUBMIT_NO_IMPLICIT | \
+					 ETNA_SUBMIT_FENCE_FD_IN | \
+					 ETNA_SUBMIT_FENCE_FD_OUT)
 #define ETNA_PIPE_3D      0x00
 #define ETNA_PIPE_2D      0x01
 #define ETNA_PIPE_VG      0x02
@@ -167,6 +193,11 @@
 	__u64 bos;            /* in, ptr to array of submit_bo's */
 	__u64 relocs;         /* in, ptr to array of submit_reloc's */
 	__u64 stream;         /* in, ptr to cmdstream */
+	__u32 flags;          /* in, mask of ETNA_SUBMIT_x */
+	__s32 fence_fd;       /* in/out, fence fd (see ETNA_SUBMIT_FENCE_FD_x) */
+	__u64 pmrs;           /* in, ptr to array of submit_pmr's */
+	__u32 nr_pmrs;        /* in, number of submit_pmr's */
+	__u32 pad;
 };
 
 /* The normal way to synchronize with the GPU is just to CPU_PREP on
@@ -202,6 +233,27 @@
 	struct drm_etnaviv_timespec timeout;	/* in */
 };
 
+/*
+ * Performance Monitor (PM):
+ */
+
+struct drm_etnaviv_pm_domain {
+	__u32 pipe;       /* in */
+	__u8  iter;       /* in/out, select pm domain at index iter */
+	__u8  id;         /* out, id of domain */
+	__u16 nr_signals; /* out, how many signals does this domain provide */
+	char  name[64];   /* out, name of domain */
+};
+
+struct drm_etnaviv_pm_signal {
+	__u32 pipe;       /* in */
+	__u8  domain;     /* in, pm domain index */
+	__u8  pad;
+	__u16 iter;       /* in/out, select pm source at index iter */
+	__u16 id;         /* out, id of signal */
+	char  name[64];   /* out, name of domain */
+};
+
 #define DRM_ETNAVIV_GET_PARAM          0x00
 /* placeholder:
 #define DRM_ETNAVIV_SET_PARAM          0x01
@@ -214,7 +266,9 @@
 #define DRM_ETNAVIV_WAIT_FENCE         0x07
 #define DRM_ETNAVIV_GEM_USERPTR        0x08
 #define DRM_ETNAVIV_GEM_WAIT           0x09
-#define DRM_ETNAVIV_NUM_IOCTLS         0x0a
+#define DRM_ETNAVIV_PM_QUERY_DOM       0x0a
+#define DRM_ETNAVIV_PM_QUERY_SIG       0x0b
+#define DRM_ETNAVIV_NUM_IOCTLS         0x0c
 
 #define DRM_IOCTL_ETNAVIV_GET_PARAM    DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
 #define DRM_IOCTL_ETNAVIV_GEM_NEW      DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
@@ -225,6 +279,8 @@
 #define DRM_IOCTL_ETNAVIV_WAIT_FENCE   DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
 #define DRM_IOCTL_ETNAVIV_GEM_USERPTR  DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
 #define DRM_IOCTL_ETNAVIV_GEM_WAIT     DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
+#define DRM_IOCTL_ETNAVIV_PM_QUERY_DOM DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_PM_QUERY_DOM, struct drm_etnaviv_pm_domain)
+#define DRM_IOCTL_ETNAVIV_PM_QUERY_SIG DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_PM_QUERY_SIG, struct drm_etnaviv_pm_signal)
 
 #if defined(__cplusplus)
 }
diff --git a/etnaviv/etnaviv_drmif.h b/etnaviv/etnaviv_drmif.h
index 8119baa..5a6bef8 100644
--- a/etnaviv/etnaviv_drmif.h
+++ b/etnaviv/etnaviv_drmif.h
@@ -35,6 +35,9 @@
 struct etna_gpu;
 struct etna_device;
 struct etna_cmd_stream;
+struct etna_perfmon;
+struct etna_perfmon_domain;
+struct etna_perfmon_signal;
 
 enum etna_pipe_id {
 	ETNA_PIPE_3D = 0,
@@ -142,6 +145,8 @@
 void etna_cmd_stream_del(struct etna_cmd_stream *stream);
 uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream);
 void etna_cmd_stream_flush(struct etna_cmd_stream *stream);
+void etna_cmd_stream_flush2(struct etna_cmd_stream *stream, int in_fence_fd,
+			    int *out_fence_fd);
 void etna_cmd_stream_finish(struct etna_cmd_stream *stream);
 
 static inline uint32_t etna_cmd_stream_avail(struct etna_cmd_stream *stream)
@@ -188,4 +193,24 @@
 
 void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, const struct etna_reloc *r);
 
+/* performance monitoring functions:
+ */
+
+struct etna_perfmon *etna_perfmon_create(struct etna_pipe *pipe);
+void etna_perfmon_del(struct etna_perfmon *perfmon);
+struct etna_perfmon_domain *etna_perfmon_get_dom_by_name(struct etna_perfmon *pm, const char *name);
+struct etna_perfmon_signal *etna_perfmon_get_sig_by_name(struct etna_perfmon_domain *dom, const char *name);
+
+struct etna_perf {
+#define ETNA_PM_PROCESS_PRE             0x0001
+#define ETNA_PM_PROCESS_POST            0x0002
+	uint32_t flags;
+	uint32_t sequence;
+	struct etna_perfmon_signal *signal;
+	struct etna_bo *bo;
+	uint32_t offset;
+};
+
+void etna_cmd_stream_perf(struct etna_cmd_stream *stream, const struct etna_perf *p);
+
 #endif /* ETNAVIV_DRMIF_H_ */
diff --git a/etnaviv/etnaviv_gpu.c b/etnaviv/etnaviv_gpu.c
index 35dec6c..dc4c126 100644
--- a/etnaviv/etnaviv_gpu.c
+++ b/etnaviv/etnaviv_gpu.c
@@ -24,10 +24,6 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "etnaviv_priv.h"
 #include "etnaviv_drmif.h"
 
@@ -48,7 +44,7 @@
 	return req.value;
 }
 
-struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core)
+drm_public struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core)
 {
 	struct etna_gpu *gpu;
 
@@ -61,32 +57,13 @@
 	gpu->dev = dev;
 	gpu->core = core;
 
-	/* get specs from kernel space */
-	gpu->specs.model    	= get_param(dev, core, ETNAVIV_PARAM_GPU_MODEL);
-	gpu->specs.revision 	= get_param(dev, core, ETNAVIV_PARAM_GPU_REVISION);
-	gpu->specs.features[0] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_0);
-	gpu->specs.features[1] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_1);
-	gpu->specs.features[2] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_2);
-	gpu->specs.features[3] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_3);
-	gpu->specs.features[4] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_4);
-	gpu->specs.features[5] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_5);
-	gpu->specs.features[6] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_6);
-	gpu->specs.stream_count = get_param(dev, core, ETNA_GPU_STREAM_COUNT);
-	gpu->specs.register_max = get_param(dev, core, ETNA_GPU_REGISTER_MAX);
-	gpu->specs.thread_count = get_param(dev, core, ETNA_GPU_THREAD_COUNT);
-	gpu->specs.vertex_cache_size = get_param(dev, core, ETNA_GPU_VERTEX_CACHE_SIZE);
-	gpu->specs.shader_core_count = get_param(dev, core, ETNA_GPU_SHADER_CORE_COUNT);
-	gpu->specs.pixel_pipes = get_param(dev, core, ETNA_GPU_PIXEL_PIPES);
-	gpu->specs.vertex_output_buffer_size = get_param(dev, core, ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE);
-	gpu->specs.buffer_size = get_param(dev, core, ETNA_GPU_BUFFER_SIZE);
-	gpu->specs.instruction_count = get_param(dev, core, ETNA_GPU_INSTRUCTION_COUNT);
-	gpu->specs.num_constants = get_param(dev, core, ETNA_GPU_NUM_CONSTANTS);
-	gpu->specs.num_varyings = get_param(dev, core, ETNA_GPU_NUM_VARYINGS);
+	gpu->model    	= get_param(dev, core, ETNAVIV_PARAM_GPU_MODEL);
+	gpu->revision 	= get_param(dev, core, ETNAVIV_PARAM_GPU_REVISION);
 
-	if (!gpu->specs.model)
+	if (!gpu->model)
 		goto fail;
 
-	INFO_MSG(" GPU model:          0x%x (rev %x)", gpu->specs.model, gpu->specs.revision);
+	INFO_MSG(" GPU model:          0x%x (rev %x)", gpu->model, gpu->revision);
 
 	return gpu;
 fail:
@@ -96,74 +73,77 @@
 	return NULL;
 }
 
-void etna_gpu_del(struct etna_gpu *gpu)
+drm_public void etna_gpu_del(struct etna_gpu *gpu)
 {
 	free(gpu);
 }
 
-int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param,
+drm_public int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param,
 		uint64_t *value)
 {
+	struct etna_device *dev = gpu->dev;
+	unsigned int core = gpu->core;
+
 	switch(param) {
 	case ETNA_GPU_MODEL:
-		*value = gpu->specs.model;
+		*value = gpu->model;
 		return 0;
 	case ETNA_GPU_REVISION:
-		*value = gpu->specs.revision;
+		*value = gpu->revision;
 		return 0;
 	case ETNA_GPU_FEATURES_0:
-		*value = gpu->specs.features[0];
+		*value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_0);
 		return 0;
 	case ETNA_GPU_FEATURES_1:
-		*value = gpu->specs.features[1];
+		*value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_1);
 		return 0;
 	case ETNA_GPU_FEATURES_2:
-		*value = gpu->specs.features[2];
+		*value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_2);
 		return 0;
 	case ETNA_GPU_FEATURES_3:
-		*value = gpu->specs.features[3];
+		*value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_3);
 		return 0;
 	case ETNA_GPU_FEATURES_4:
-		*value = gpu->specs.features[4];
+		*value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_4);
 		return 0;
 	case ETNA_GPU_FEATURES_5:
-		*value = gpu->specs.features[5];
+		*value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_5);
 		return 0;
 	case ETNA_GPU_FEATURES_6:
-		*value = gpu->specs.features[6];
+		*value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_6);
 		return 0;
 	case ETNA_GPU_STREAM_COUNT:
-		*value = gpu->specs.stream_count;
+		*value = get_param(dev, core, ETNA_GPU_STREAM_COUNT);
 		return 0;
 	case ETNA_GPU_REGISTER_MAX:
-		*value = gpu->specs.register_max;
+		*value = get_param(dev, core, ETNA_GPU_REGISTER_MAX);
 		return 0;
 	case ETNA_GPU_THREAD_COUNT:
-		*value = gpu->specs.thread_count;
+		*value = get_param(dev, core, ETNA_GPU_THREAD_COUNT);
 		return 0;
 	case ETNA_GPU_VERTEX_CACHE_SIZE:
-		*value = gpu->specs.vertex_cache_size;
+		*value = get_param(dev, core, ETNA_GPU_VERTEX_CACHE_SIZE);
 		return 0;
 	case ETNA_GPU_SHADER_CORE_COUNT:
-		*value = gpu->specs.shader_core_count;
+		*value = get_param(dev, core, ETNA_GPU_SHADER_CORE_COUNT);
 		return 0;
 	case ETNA_GPU_PIXEL_PIPES:
-		*value = gpu->specs.pixel_pipes;
+		*value = get_param(dev, core, ETNA_GPU_PIXEL_PIPES);
 		return 0;
 	case ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE:
-		*value = gpu->specs.vertex_output_buffer_size;
+		*value = get_param(dev, core, ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE);
 		return 0;
 	case ETNA_GPU_BUFFER_SIZE:
-		*value = gpu->specs.buffer_size;
+		*value = get_param(dev, core, ETNA_GPU_BUFFER_SIZE);
 		return 0;
 	case ETNA_GPU_INSTRUCTION_COUNT:
-		*value = gpu->specs.instruction_count;
+		*value = get_param(dev, core, ETNA_GPU_INSTRUCTION_COUNT);
 		return 0;
 	case ETNA_GPU_NUM_CONSTANTS:
-		*value = gpu->specs.num_constants;
+		*value = get_param(dev, core, ETNA_GPU_NUM_CONSTANTS);
 		return 0;
 	case ETNA_GPU_NUM_VARYINGS:
-		*value = gpu->specs.num_varyings;
+		*value = get_param(dev, core, ETNA_GPU_NUM_VARYINGS);
 		return 0;
 
 	default:
diff --git a/etnaviv/etnaviv_perfmon.c b/etnaviv/etnaviv_perfmon.c
new file mode 100644
index 0000000..f6576b8
--- /dev/null
+++ b/etnaviv/etnaviv_perfmon.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 Etnaviv Project
+ * Copyright (C) 2017 Zodiac Inflight Innovations
+ *
+ * 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:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#include "etnaviv_priv.h"
+
+static int etna_perfmon_query_signals(struct etna_perfmon *pm, struct etna_perfmon_domain *dom)
+{
+	struct etna_device *dev = pm->pipe->gpu->dev;
+	struct drm_etnaviv_pm_signal req = {
+		.pipe = pm->pipe->id,
+		.domain = dom->id
+	};
+
+	do {
+		struct etna_perfmon_signal *sig;
+		int ret;
+
+		ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_SIG, &req, sizeof(req));
+		if (ret)
+			break;
+
+		sig = calloc(1, sizeof(*sig));
+		if (!sig)
+			return -ENOMEM;
+
+		INFO_MSG("perfmon signal:");
+		INFO_MSG("id         = %d", req.id);
+		INFO_MSG("name       = %s", req.name);
+
+		sig->domain = dom;
+		sig->signal = req.id;
+		strncpy(sig->name, req.name, sizeof(sig->name));
+		list_addtail(&sig->head, &dom->signals);
+	} while (req.iter != 0xffff);
+
+	return 0;
+}
+
+static int etna_perfmon_query_domains(struct etna_perfmon *pm)
+{
+	struct etna_device *dev = pm->pipe->gpu->dev;
+	struct drm_etnaviv_pm_domain req = {
+		.pipe = pm->pipe->id
+	};
+
+	do {
+		struct etna_perfmon_domain *dom;
+		int ret;
+
+		ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_DOM, &req, sizeof(req));
+		if (ret)
+			break;
+
+		dom = calloc(1, sizeof(*dom));
+		if (!dom)
+			return -ENOMEM;
+
+		list_inithead(&dom->signals);
+		dom->id = req.id;
+		strncpy(dom->name, req.name, sizeof(dom->name));
+		list_addtail(&dom->head, &pm->domains);
+
+		INFO_MSG("perfmon domain:");
+		INFO_MSG("id         = %d", req.id);
+		INFO_MSG("name       = %s", req.name);
+		INFO_MSG("nr_signals = %d", req.nr_signals);
+
+		/* Query all available signals for this domain. */
+		if (req.nr_signals > 0) {
+			ret = etna_perfmon_query_signals(pm, dom);
+			if (ret)
+				return ret;
+		}
+	} while (req.iter != 0xff);
+
+	return 0;
+}
+
+static void etna_perfmon_free_signals(struct etna_perfmon_domain *dom)
+{
+	struct etna_perfmon_signal *sig, *next;
+
+	LIST_FOR_EACH_ENTRY_SAFE(sig, next, &dom->signals, head) {
+		list_del(&sig->head);
+		free(sig);
+	}
+}
+
+static void etna_perfmon_free_domains(struct etna_perfmon *pm)
+{
+	struct etna_perfmon_domain *dom, *next;
+
+	LIST_FOR_EACH_ENTRY_SAFE(dom, next, &pm->domains, head) {
+		etna_perfmon_free_signals(dom);
+		list_del(&dom->head);
+		free(dom);
+	}
+}
+
+drm_public struct etna_perfmon *etna_perfmon_create(struct etna_pipe *pipe)
+{
+	struct etna_perfmon *pm;
+	int ret;
+
+	pm = calloc(1, sizeof(*pm));
+	if (!pm) {
+		ERROR_MSG("allocation failed");
+		return NULL;
+	}
+
+	list_inithead(&pm->domains);
+	pm->pipe = pipe;
+
+	/* query all available domains and sources for this device */
+	ret = etna_perfmon_query_domains(pm);
+	if (ret)
+		goto fail;
+
+	return pm;
+
+fail:
+	etna_perfmon_del(pm);
+	return NULL;
+}
+
+drm_public void etna_perfmon_del(struct etna_perfmon *pm)
+{
+	if (!pm)
+		return;
+
+	etna_perfmon_free_domains(pm);
+	free(pm);
+}
+
+drm_public struct etna_perfmon_domain *etna_perfmon_get_dom_by_name(struct etna_perfmon *pm, const char *name)
+{
+	struct etna_perfmon_domain *dom;
+
+	if (pm) {
+		LIST_FOR_EACH_ENTRY(dom, &pm->domains, head) {
+			if (!strcmp(dom->name, name))
+				return dom;
+		}
+	}
+
+	return NULL;
+}
+
+drm_public struct etna_perfmon_signal *etna_perfmon_get_sig_by_name(struct etna_perfmon_domain *dom, const char *name)
+{
+	struct etna_perfmon_signal *signal;
+
+	if (dom) {
+		LIST_FOR_EACH_ENTRY(signal, &dom->signals, head) {
+			if (!strcmp(signal->name, name))
+				return signal;
+		}
+	}
+
+	return NULL;
+}
diff --git a/etnaviv/etnaviv_pipe.c b/etnaviv/etnaviv_pipe.c
index 94c5d37..4120a36 100644
--- a/etnaviv/etnaviv_pipe.c
+++ b/etnaviv/etnaviv_pipe.c
@@ -24,18 +24,14 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "etnaviv_priv.h"
 
-int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms)
+drm_public int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms)
 {
 	return etna_pipe_wait_ns(pipe, timestamp, ms * 1000000);
 }
 
-int etna_pipe_wait_ns(struct etna_pipe *pipe, uint32_t timestamp, uint64_t ns)
+drm_public int etna_pipe_wait_ns(struct etna_pipe *pipe, uint32_t timestamp, uint64_t ns)
 {
 	struct etna_device *dev = pipe->gpu->dev;
 	int ret;
@@ -59,12 +55,12 @@
 	return 0;
 }
 
-void etna_pipe_del(struct etna_pipe *pipe)
+drm_public void etna_pipe_del(struct etna_pipe *pipe)
 {
 	free(pipe);
 }
 
-struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id)
+drm_public struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id)
 {
 	struct etna_pipe *pipe;
 
diff --git a/etnaviv/etnaviv_priv.h b/etnaviv/etnaviv_priv.h
index feaa5ad..e45d364 100644
--- a/etnaviv/etnaviv_priv.h
+++ b/etnaviv/etnaviv_priv.h
@@ -47,25 +47,6 @@
 #include "etnaviv_drmif.h"
 #include "etnaviv_drm.h"
 
-#define VIV_FEATURES_WORD_COUNT 7
-
-struct etna_specs {
-	uint32_t model;
-	uint32_t revision;
-	uint32_t features[VIV_FEATURES_WORD_COUNT];
-	uint32_t stream_count;
-	uint32_t register_max;
-	uint32_t thread_count;
-	uint32_t shader_core_count;
-	uint32_t vertex_cache_size;
-	uint32_t vertex_output_buffer_size;
-	uint32_t pixel_pipes;
-	uint32_t instruction_count;
-	uint32_t num_constants;
-	uint32_t num_varyings;
-	uint32_t buffer_size;
-};
-
 struct etna_bo_bucket {
 	uint32_t size;
 	struct list_head list;
@@ -134,8 +115,9 @@
 
 struct etna_gpu {
 	struct etna_device *dev;
-	struct etna_specs specs;
 	uint32_t core;
+	uint32_t model;
+	uint32_t revision;
 };
 
 struct etna_pipe {
@@ -158,6 +140,10 @@
 		/* reloc's table: */
 		struct drm_etnaviv_gem_submit_reloc *relocs;
 		uint32_t nr_relocs, max_relocs;
+
+		/* perf's table: */
+		struct drm_etnaviv_gem_submit_pmr *pmrs;
+		uint32_t nr_pmrs, max_pmrs;
 	} submit;
 
 	/* should have matching entries in submit.bos: */
@@ -169,6 +155,27 @@
 	void *reset_notify_priv;
 };
 
+struct etna_perfmon {
+	struct list_head domains;
+	struct etna_pipe *pipe;
+};
+
+struct etna_perfmon_domain
+{
+	struct list_head head;
+	struct list_head signals;
+	uint8_t id;
+	char name[64];
+};
+
+struct etna_perfmon_signal
+{
+	struct list_head head;
+	struct etna_perfmon_domain *domain;
+	uint8_t signal;
+	char name[64];
+};
+
 #define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1))
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 
diff --git a/etnaviv/meson.build b/etnaviv/meson.build
new file mode 100644
index 0000000..515a4ed
--- /dev/null
+++ b/etnaviv/meson.build
@@ -0,0 +1,59 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+
+libdrm_etnaviv = shared_library(
+  'drm_etnaviv',
+  [
+    files(
+      'etnaviv_device.c', 'etnaviv_gpu.c', 'etnaviv_bo.c', 'etnaviv_bo_cache.c',
+      'etnaviv_perfmon.c', 'etnaviv_pipe.c', 'etnaviv_cmd_stream.c',
+    ),
+    config_file
+  ],
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  c_args : libdrm_c_args,
+  dependencies : [dep_pthread_stubs, dep_rt, dep_atomic_ops],
+  version : '1.0.0',
+  install : true,
+)
+
+install_headers('etnaviv_drmif.h', subdir : 'libdrm')
+
+pkg.generate(
+  name : 'libdrm_etnaviv',
+  libraries : libdrm_etnaviv,
+  subdirs : ['.', 'libdrm'],
+  version : meson.project_version(),
+  requires_private : 'libdrm',
+  description : 'Userspace interface to Tegra kernel DRM services',
+)
+
+ext_libdrm_etnaviv = declare_dependency(
+  link_with : [libdrm, libdrm_etnaviv],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+test(
+  'etnaviv-symbol-check',
+  prog_bash,
+  args : [files('etnaviv-symbol-check'), libdrm_etnaviv]
+)
diff --git a/exynos/Makefile.am b/exynos/Makefile.am
index f99f898..76b185d 100644
--- a/exynos/Makefile.am
+++ b/exynos/Makefile.am
@@ -1,5 +1,6 @@
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	-I$(top_srcdir)/include/drm
@@ -23,5 +24,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_exynos.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = exynos-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/exynos/exynos-symbol-check b/exynos/exynos-symbol-check
index 9692caa..49d611e 100755
--- a/exynos/exynos-symbol-check
+++ b/exynos/exynos-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.am/libdrm_exynos*_HEADERS
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_exynos.so} | awk '{print $3}'| while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_exynos.so} | awk '{print $3}'| while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
diff --git a/exynos/exynos_drm.c b/exynos/exynos_drm.c
index b961e52..078bf2c 100644
--- a/exynos/exynos_drm.c
+++ b/exynos/exynos_drm.c
@@ -24,10 +24,6 @@
  *    Inki Dae <inki.dae@samsung.com>
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -52,7 +48,7 @@
  *
  * if true, return the device object else NULL.
  */
-struct exynos_device * exynos_device_create(int fd)
+drm_public struct exynos_device * exynos_device_create(int fd)
 {
 	struct exynos_device *dev;
 
@@ -73,7 +69,7 @@
  *
  * @dev: exynos drm device object.
  */
-void exynos_device_destroy(struct exynos_device *dev)
+drm_public void exynos_device_destroy(struct exynos_device *dev)
 {
 	free(dev);
 }
@@ -91,8 +87,8 @@
  *
  * if true, return a exynos buffer object else NULL.
  */
-struct exynos_bo * exynos_bo_create(struct exynos_device *dev,
-					       size_t size, uint32_t flags)
+drm_public struct exynos_bo * exynos_bo_create(struct exynos_device *dev,
+                                               size_t size, uint32_t flags)
 {
 	struct exynos_bo *bo;
 	struct drm_exynos_gem_create req = {
@@ -145,8 +141,8 @@
  *
  * if true, return 0 else negative.
  */
-int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle,
-				  size_t *size, uint32_t *flags)
+drm_public int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle,
+                                  size_t *size, uint32_t *flags)
 {
 	int ret;
 	struct drm_exynos_gem_info req = {
@@ -171,7 +167,7 @@
  *
  * @bo: a exynos buffer object to be destroyed.
  */
-void exynos_bo_destroy(struct exynos_bo *bo)
+drm_public void exynos_bo_destroy(struct exynos_bo *bo)
 {
 	if (!bo)
 		return;
@@ -203,7 +199,7 @@
  * if true, return a exynos buffer object else NULL.
  *
  */
-struct exynos_bo *
+drm_public struct exynos_bo *
 exynos_bo_from_name(struct exynos_device *dev, uint32_t name)
 {
 	struct exynos_bo *bo;
@@ -246,7 +242,7 @@
  *
  * if true, return 0 else negative.
  */
-int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name)
+drm_public int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name)
 {
 	if (!bo->name) {
 		struct drm_gem_flink req = {
@@ -269,7 +265,7 @@
 	return 0;
 }
 
-uint32_t exynos_bo_handle(struct exynos_bo *bo)
+drm_public uint32_t exynos_bo_handle(struct exynos_bo *bo)
 {
 	return bo->handle;
 }
@@ -282,7 +278,7 @@
  *
  * if true, user pointer mmaped else NULL.
  */
-void *exynos_bo_map(struct exynos_bo *bo)
+drm_public void *exynos_bo_map(struct exynos_bo *bo)
 {
 	if (!bo->vaddr) {
 		struct exynos_device *dev = bo->dev;
@@ -319,7 +315,7 @@
  *
  * @return: 0 on success, -1 on error, and errno will be set
  */
-int
+drm_public int
 exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, int *fd)
 {
 	return drmPrimeHandleToFD(dev->fd, handle, 0, fd);
@@ -334,7 +330,7 @@
  *
  * @return: 0 on success, -1 on error, and errno will be set
  */
-int
+drm_public int
 exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, uint32_t *handle)
 {
 	return drmPrimeFDToHandle(dev->fd, fd, handle);
@@ -357,7 +353,7 @@
  *
  * if true, return 0 else negative.
  */
-int
+drm_public int
 exynos_vidi_connection(struct exynos_device *dev, uint32_t connect,
 		       uint32_t ext, void *edid)
 {
@@ -398,7 +394,7 @@
 	}
 }
 
-int
+drm_public int
 exynos_handle_event(struct exynos_device *dev, struct exynos_event_context *ctx)
 {
 	char buffer[1024];
@@ -417,7 +413,7 @@
 
 	i = 0;
 	while (i < len) {
-		e = (struct drm_event *) &buffer[i];
+		e = (struct drm_event *)(buffer + i);
 		switch (e->type) {
 		case DRM_EVENT_VBLANK:
 			if (evctx->version < 1 ||
diff --git a/exynos/exynos_drmif.h b/exynos/exynos_drmif.h
index 626e399..154439b 100644
--- a/exynos/exynos_drmif.h
+++ b/exynos/exynos_drmif.h
@@ -31,6 +31,10 @@
 #include <stdint.h>
 #include "exynos_drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct exynos_device {
 	int fd;
 };
@@ -109,4 +113,8 @@
 				struct exynos_event_context *ctx);
 
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* EXYNOS_DRMIF_H_ */
diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c
index 7f1d105..ac6fa68 100644
--- a/exynos/exynos_fimg2d.c
+++ b/exynos/exynos_fimg2d.c
@@ -3,17 +3,26 @@
  * Authors:
  *	Inki Dae <inki.dae@samsung.com>
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 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
+ * VA LINUX SYSTEMS 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.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -293,20 +302,6 @@
 }
 
 /*
- * g2d_reset - reset fimg2d hardware.
- *
- * @ctx: a pointer to g2d_context structure.
- *
- */
-static void g2d_reset(struct g2d_context *ctx)
-{
-	ctx->cmd_nr = 0;
-	ctx->cmd_buf_nr = 0;
-
-	g2d_add_cmd(ctx, SOFT_RESET_REG, 0x01);
-}
-
-/*
  * g2d_flush - submit all commands and values in user side command buffer
  *		to command queue aware of fimg2d dma.
  *
@@ -361,7 +356,7 @@
  *
  * fd: a file descriptor to an opened drm device.
  */
-struct g2d_context *g2d_init(int fd)
+drm_public struct g2d_context *g2d_init(int fd)
 {
 	struct drm_exynos_g2d_get_ver ver;
 	struct g2d_context *ctx;
@@ -389,7 +384,7 @@
 	return ctx;
 }
 
-void g2d_fini(struct g2d_context *ctx)
+drm_public void g2d_fini(struct g2d_context *ctx)
 {
 	free(ctx);
 }
@@ -405,7 +400,7 @@
  * @ctx: a pointer to g2d_context structure.
  * @userdata: a pointer to the user data
  */
-void g2d_config_event(struct g2d_context *ctx, void *userdata)
+drm_public void g2d_config_event(struct g2d_context *ctx, void *userdata)
 {
 	ctx->event_userdata = userdata;
 }
@@ -415,7 +410,7 @@
  *
  * @ctx: a pointer to g2d_context structure.
  */
-int g2d_exec(struct g2d_context *ctx)
+drm_public int g2d_exec(struct g2d_context *ctx)
 {
 	struct drm_exynos_g2d_exec exec;
 	int ret;
@@ -447,7 +442,7 @@
  * @w: width value to buffer filled with given color data.
  * @h: height value to buffer filled with given color data.
  */
-int
+drm_public int
 g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img,
 			unsigned int x, unsigned int y, unsigned int w,
 			unsigned int h)
@@ -500,7 +495,7 @@
  * @w: width value to source and destination buffers.
  * @h: height value to source and destination buffers.
  */
-int
+drm_public int
 g2d_copy(struct g2d_context *ctx, struct g2d_image *src,
 		struct g2d_image *dst, unsigned int src_x, unsigned int src_y,
 		unsigned int dst_x, unsigned dst_y, unsigned int w,
@@ -583,7 +578,7 @@
  * @w: width of rectangle to move.
  * @h: height of rectangle to move.
  */
-int
+drm_public int
 g2d_move(struct g2d_context *ctx, struct g2d_image *img,
 		unsigned int src_x, unsigned int src_y,
 		unsigned int dst_x, unsigned dst_y, unsigned int w,
@@ -681,7 +676,7 @@
  * @negative: indicate that it uses color negative to source and
  *	destination buffers.
  */
-int
+drm_public int
 g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src,
 				struct g2d_image *dst, unsigned int src_x,
 				unsigned int src_y, unsigned int src_w,
@@ -790,7 +785,7 @@
  * @h: height value to source and destination buffer.
  * @op: blend operation type.
  */
-int
+drm_public int
 g2d_blend(struct g2d_context *ctx, struct g2d_image *src,
 		struct g2d_image *dst, unsigned int src_x,
 		unsigned int src_y, unsigned int dst_x, unsigned int dst_y,
@@ -907,7 +902,7 @@
  * @dst_h: height value to destination buffer.
  * @op: blend operation type.
  */
-int
+drm_public int
 g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src,
 		struct g2d_image *dst, unsigned int src_x, unsigned int src_y,
 		unsigned int src_w, unsigned int src_h, unsigned int dst_x,
diff --git a/exynos/exynos_fimg2d.h b/exynos/exynos_fimg2d.h
index a825c68..a4dfbe7 100644
--- a/exynos/exynos_fimg2d.h
+++ b/exynos/exynos_fimg2d.h
@@ -3,11 +3,24 @@
  * Authors:
  *	Inki Dae <inki.dae@samsung.com>
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 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
+ * VA LINUX SYSTEMS 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.
  */
 
 #ifndef _FIMG2D_H_
diff --git a/exynos/fimg2d_reg.h b/exynos/fimg2d_reg.h
index 07dd634..d42296d 100644
--- a/exynos/fimg2d_reg.h
+++ b/exynos/fimg2d_reg.h
@@ -3,11 +3,24 @@
  * Authors:
  *	Inki Dae <inki.dae@samsung.com>
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 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
+ * VA LINUX SYSTEMS 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.
  */
 
 #ifndef _FIMG2D_REG_H_
diff --git a/exynos/meson.build b/exynos/meson.build
new file mode 100644
index 0000000..bdfc3fc
--- /dev/null
+++ b/exynos/meson.build
@@ -0,0 +1,54 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+libdrm_exynos = shared_library(
+  'drm_exynos',
+  [files('exynos_drm.c', 'exynos_fimg2d.c'), config_file],
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  dependencies : [dep_pthread_stubs],
+  version : '1.0.0',
+  install : true,
+)
+
+install_headers('exynos_drmif.h', subdir : 'libdrm')
+install_headers('exynos_drm.h', 'exynos_fimg2d.h', subdir : 'exynos')
+
+ext_libdrm_exynos = declare_dependency(
+  link_with : [libdrm, libdrm_exynos],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+pkg.generate(
+  name : 'libdrm_exynos',
+  libraries : libdrm_exynos,
+  subdirs : ['.', 'libdrm', 'exynos'],
+  version : '0.7',
+  requires_private : 'libdrm',
+  description : 'Userspace interface to exynos kernel DRM services',
+)
+
+test(
+  'exynos-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('exynos-symbol-check'), libdrm_exynos]
+)
diff --git a/freedreno/Makefile.am b/freedreno/Makefile.am
index 0771d14..3784503 100644
--- a/freedreno/Makefile.am
+++ b/freedreno/Makefile.am
@@ -3,8 +3,10 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
+	$(VALGRIND_CFLAGS) \
 	-I$(top_srcdir)/include/drm
 
 libdrm_freedreno_la_LTLIBRARIES = libdrm_freedreno.la
@@ -26,5 +28,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_freedreno.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = freedreno-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/freedreno/Makefile.sources b/freedreno/Makefile.sources
index 68a679b..ca89511 100644
--- a/freedreno/Makefile.sources
+++ b/freedreno/Makefile.sources
@@ -7,7 +7,6 @@
 	freedreno_bo_cache.c \
 	msm/msm_bo.c \
 	msm/msm_device.c \
-	msm/msm_drm.h \
 	msm/msm_pipe.c \
 	msm/msm_priv.h \
 	msm/msm_ringbuffer.c
diff --git a/freedreno/freedreno-symbol-check b/freedreno/freedreno-symbol-check
index 42f2c43..978026c 100755
--- a/freedreno/freedreno-symbol-check
+++ b/freedreno/freedreno-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.sources/LIBDRM_FREEDRENO_H_FILES
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_freedreno.so} | awk '{print $3}'| while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_freedreno.so} | awk '{print $3}'| while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
@@ -18,10 +20,12 @@
 fd_bo_from_fbdev
 fd_bo_from_handle
 fd_bo_from_name
+fd_bo_get_iova
 fd_bo_get_name
 fd_bo_handle
 fd_bo_map
 fd_bo_new
+fd_bo_put_iova
 fd_bo_ref
 fd_bo_size
 fd_device_del
@@ -33,6 +37,8 @@
 fd_pipe_del
 fd_pipe_get_param
 fd_pipe_new
+fd_pipe_new2
+fd_pipe_ref
 fd_pipe_wait
 fd_pipe_wait_timeout
 fd_ringbuffer_cmd_count
@@ -42,17 +48,16 @@
 fd_ringbuffer_flush
 fd_ringbuffer_grow
 fd_ringbuffer_new
+fd_ringbuffer_new_flags
+fd_ringbuffer_new_object
+fd_ringbuffer_ref
 fd_ringbuffer_reloc
 fd_ringbuffer_reloc2
 fd_ringbuffer_reset
 fd_ringbuffer_set_parent
+fd_ringbuffer_size
 fd_ringbuffer_timestamp
-fd_ringmarker_del
-fd_ringmarker_dwords
-fd_ringmarker_flush
 fd_ringbuffer_flush2
-fd_ringmarker_mark
-fd_ringmarker_new
 EOF
 done)
 
diff --git a/freedreno/freedreno_bo.c b/freedreno/freedreno_bo.c
index 996d6b9..efc5b71 100644
--- a/freedreno/freedreno_bo.c
+++ b/freedreno/freedreno_bo.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "freedreno_drmif.h"
 #include "freedreno_priv.h"
 
@@ -82,14 +78,15 @@
 	return bo;
 }
 
-struct fd_bo *
-fd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags)
+static struct fd_bo *
+bo_new(struct fd_device *dev, uint32_t size, uint32_t flags,
+		struct fd_bo_cache *cache)
 {
 	struct fd_bo *bo = NULL;
 	uint32_t handle;
 	int ret;
 
-	bo = fd_bo_cache_alloc(&dev->bo_cache, &size, flags);
+	bo = fd_bo_cache_alloc(cache, &size, flags);
 	if (bo)
 		return bo;
 
@@ -99,13 +96,37 @@
 
 	pthread_mutex_lock(&table_lock);
 	bo = bo_from_handle(dev, size, handle);
-	bo->bo_reuse = TRUE;
 	pthread_mutex_unlock(&table_lock);
 
+	VG_BO_ALLOC(bo);
+
 	return bo;
 }
 
-struct fd_bo *
+drm_public struct fd_bo *
+fd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags)
+{
+	struct fd_bo *bo = bo_new(dev, size, flags, &dev->bo_cache);
+	if (bo)
+		bo->bo_reuse = BO_CACHE;
+	return bo;
+}
+
+/* internal function to allocate bo's that use the ringbuffer cache
+ * instead of the normal bo_cache.  The purpose is, because cmdstream
+ * bo's get vmap'd on the kernel side, and that is expensive, we want
+ * to re-use cmdstream bo's for cmdstream and not unrelated purposes.
+ */
+drm_private struct fd_bo *
+fd_bo_new_ring(struct fd_device *dev, uint32_t size, uint32_t flags)
+{
+	struct fd_bo *bo = bo_new(dev, size, flags, &dev->ring_cache);
+	if (bo)
+		bo->bo_reuse = RING_CACHE;
+	return bo;
+}
+
+drm_public struct fd_bo *
 fd_bo_from_handle(struct fd_device *dev, uint32_t handle, uint32_t size)
 {
 	struct fd_bo *bo = NULL;
@@ -118,13 +139,15 @@
 
 	bo = bo_from_handle(dev, size, handle);
 
+	VG_BO_ALLOC(bo);
+
 out_unlock:
 	pthread_mutex_unlock(&table_lock);
 
 	return bo;
 }
 
-struct fd_bo *
+drm_public struct fd_bo *
 fd_bo_from_dmabuf(struct fd_device *dev, int fd)
 {
 	int ret, size;
@@ -134,6 +157,7 @@
 	pthread_mutex_lock(&table_lock);
 	ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
 	if (ret) {
+		pthread_mutex_unlock(&table_lock);
 		return NULL;
 	}
 
@@ -147,13 +171,15 @@
 
 	bo = bo_from_handle(dev, size, handle);
 
+	VG_BO_ALLOC(bo);
+
 out_unlock:
 	pthread_mutex_unlock(&table_lock);
 
 	return bo;
 }
 
-struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name)
+drm_public struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name)
 {
 	struct drm_gem_open req = {
 			.name = name,
@@ -177,8 +203,10 @@
 		goto out_unlock;
 
 	bo = bo_from_handle(dev, req.size, req.handle);
-	if (bo)
+	if (bo) {
 		set_name(bo, name);
+		VG_BO_ALLOC(bo);
+	}
 
 out_unlock:
 	pthread_mutex_unlock(&table_lock);
@@ -186,13 +214,23 @@
 	return bo;
 }
 
-struct fd_bo * fd_bo_ref(struct fd_bo *bo)
+drm_public uint64_t fd_bo_get_iova(struct fd_bo *bo)
+{
+	return bo->funcs->iova(bo);
+}
+
+drm_public void fd_bo_put_iova(struct fd_bo *bo)
+{
+	/* currently a no-op */
+}
+
+drm_public struct fd_bo * fd_bo_ref(struct fd_bo *bo)
 {
 	atomic_inc(&bo->refcnt);
 	return bo;
 }
 
-void fd_bo_del(struct fd_bo *bo)
+drm_public void fd_bo_del(struct fd_bo *bo)
 {
 	struct fd_device *dev = bo->dev;
 
@@ -201,7 +239,9 @@
 
 	pthread_mutex_lock(&table_lock);
 
-	if (bo->bo_reuse && (fd_bo_cache_free(&dev->bo_cache, bo) == 0))
+	if ((bo->bo_reuse == BO_CACHE) && (fd_bo_cache_free(&dev->bo_cache, bo) == 0))
+		goto out;
+	if ((bo->bo_reuse == RING_CACHE) && (fd_bo_cache_free(&dev->ring_cache, bo) == 0))
 		goto out;
 
 	bo_del(bo);
@@ -213,6 +253,8 @@
 /* Called under table_lock */
 drm_private void bo_del(struct fd_bo *bo)
 {
+	VG_BO_FREE(bo);
+
 	if (bo->map)
 		drm_munmap(bo->map, bo->size);
 
@@ -233,7 +275,7 @@
 	bo->funcs->destroy(bo);
 }
 
-int fd_bo_get_name(struct fd_bo *bo, uint32_t *name)
+drm_public int fd_bo_get_name(struct fd_bo *bo, uint32_t *name)
 {
 	if (!bo->name) {
 		struct drm_gem_flink req = {
@@ -249,7 +291,7 @@
 		pthread_mutex_lock(&table_lock);
 		set_name(bo, req.name);
 		pthread_mutex_unlock(&table_lock);
-		bo->bo_reuse = FALSE;
+		bo->bo_reuse = NO_CACHE;
 	}
 
 	*name = bo->name;
@@ -257,12 +299,12 @@
 	return 0;
 }
 
-uint32_t fd_bo_handle(struct fd_bo *bo)
+drm_public uint32_t fd_bo_handle(struct fd_bo *bo)
 {
 	return bo->handle;
 }
 
-int fd_bo_dmabuf(struct fd_bo *bo)
+drm_public int fd_bo_dmabuf(struct fd_bo *bo)
 {
 	int ret, prime_fd;
 
@@ -273,17 +315,17 @@
 		return ret;
 	}
 
-	bo->bo_reuse = FALSE;
+	bo->bo_reuse = NO_CACHE;
 
 	return prime_fd;
 }
 
-uint32_t fd_bo_size(struct fd_bo *bo)
+drm_public uint32_t fd_bo_size(struct fd_bo *bo)
 {
 	return bo->size;
 }
 
-void * fd_bo_map(struct fd_bo *bo)
+drm_public void * fd_bo_map(struct fd_bo *bo)
 {
 	if (!bo->map) {
 		uint64_t offset;
@@ -305,18 +347,18 @@
 }
 
 /* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */
-int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op)
+drm_public int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op)
 {
 	return bo->funcs->cpu_prep(bo, pipe, op);
 }
 
-void fd_bo_cpu_fini(struct fd_bo *bo)
+drm_public void fd_bo_cpu_fini(struct fd_bo *bo)
 {
 	bo->funcs->cpu_fini(bo);
 }
 
-#ifndef HAVE_FREEDRENO_KGSL
-struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size)
+#if !HAVE_FREEDRENO_KGSL
+drm_public struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size)
 {
     return NULL;
 }
diff --git a/freedreno/freedreno_bo_cache.c b/freedreno/freedreno_bo_cache.c
index 7becb0d..bb0605a 100644
--- a/freedreno/freedreno_bo_cache.c
+++ b/freedreno/freedreno_bo_cache.c
@@ -26,14 +26,9 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "freedreno_drmif.h"
 #include "freedreno_priv.h"
 
-
 drm_private void bo_del(struct fd_bo *bo);
 drm_private extern pthread_mutex_t table_lock;
 
@@ -54,7 +49,7 @@
  *    fill in for a bit smoother size curve..
  */
 drm_private void
-fd_bo_cache_init(struct fd_bo_cache *cache, int course)
+fd_bo_cache_init(struct fd_bo_cache *cache, int coarse)
 {
 	unsigned long size, cache_max_size = 64 * 1024 * 1024;
 
@@ -68,13 +63,13 @@
 	 */
 	add_bucket(cache, 4096);
 	add_bucket(cache, 4096 * 2);
-	if (!course)
+	if (!coarse)
 		add_bucket(cache, 4096 * 3);
 
 	/* Initialize the linked lists for BO reuse cache. */
 	for (size = 4 * 4096; size <= cache_max_size; size *= 2) {
 		add_bucket(cache, size);
-		if (!course) {
+		if (!coarse) {
 			add_bucket(cache, size + size * 1 / 4);
 			add_bucket(cache, size + size * 2 / 4);
 			add_bucket(cache, size + size * 3 / 4);
@@ -102,6 +97,7 @@
 			if (time && ((time - bo->free_time) <= 1))
 				break;
 
+			VG_BO_OBTAIN(bo);
 			list_del(&bo->list);
 			bo_del(bo);
 		}
@@ -177,6 +173,7 @@
 		*size = bucket->size;
 		bo = find_in_bucket(bucket, flags);
 		if (bo) {
+			VG_BO_OBTAIN(bo);
 			if (bo->funcs->madvise(bo, TRUE) <= 0) {
 				/* we've lost the backing pages, delete and try again: */
 				pthread_mutex_lock(&table_lock);
@@ -207,6 +204,7 @@
 		clock_gettime(CLOCK_MONOTONIC, &time);
 
 		bo->free_time = time.tv_sec;
+		VG_BO_RELEASE(bo);
 		list_addtail(&bo->list, &bucket->list);
 		fd_bo_cache_cleanup(cache, time.tv_sec);
 
diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c
index fcbf140..ac23430 100644
--- a/freedreno/freedreno_device.c
+++ b/freedreno/freedreno_device.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -42,7 +38,7 @@
 struct fd_device * kgsl_device_new(int fd);
 struct fd_device * msm_device_new(int fd);
 
-struct fd_device * fd_device_new(int fd)
+drm_public struct fd_device * fd_device_new(int fd)
 {
 	struct fd_device *dev;
 	drmVersionPtr version;
@@ -65,7 +61,7 @@
 
 		dev = msm_device_new(fd);
 		dev->version = version->version_minor;
-#ifdef HAVE_FREEDRENO_KGSL
+#if HAVE_FREEDRENO_KGSL
 	} else if (!strcmp(version->name, "kgsl")) {
 		DEBUG_MSG("kgsl DRM device");
 		dev = kgsl_device_new(fd);
@@ -86,6 +82,7 @@
 	dev->handle_table = drmHashCreate();
 	dev->name_table = drmHashCreate();
 	fd_bo_cache_init(&dev->bo_cache, FALSE);
+	fd_bo_cache_init(&dev->ring_cache, TRUE);
 
 	return dev;
 }
@@ -93,7 +90,7 @@
 /* like fd_device_new() but creates it's own private dup() of the fd
  * which is close()d when the device is finalized.
  */
-struct fd_device * fd_device_new_dup(int fd)
+drm_public struct fd_device * fd_device_new_dup(int fd)
 {
 	int dup_fd = dup(fd);
 	struct fd_device *dev = fd_device_new(dup_fd);
@@ -104,7 +101,7 @@
 	return dev;
 }
 
-struct fd_device * fd_device_ref(struct fd_device *dev)
+drm_public struct fd_device * fd_device_ref(struct fd_device *dev)
 {
 	atomic_inc(&dev->refcnt);
 	return dev;
@@ -112,12 +109,13 @@
 
 static void fd_device_del_impl(struct fd_device *dev)
 {
+	int close_fd = dev->closefd ? dev->fd : -1;
 	fd_bo_cache_cleanup(&dev->bo_cache, 0);
 	drmHashDestroy(dev->handle_table);
 	drmHashDestroy(dev->name_table);
-	if (dev->closefd)
-		close(dev->fd);
 	dev->funcs->destroy(dev);
+	if (close_fd >= 0)
+		close(close_fd);
 }
 
 drm_private void fd_device_del_locked(struct fd_device *dev)
@@ -127,7 +125,7 @@
 	fd_device_del_impl(dev);
 }
 
-void fd_device_del(struct fd_device *dev)
+drm_public void fd_device_del(struct fd_device *dev)
 {
 	if (!atomic_dec_and_test(&dev->refcnt))
 		return;
@@ -136,12 +134,12 @@
 	pthread_mutex_unlock(&table_lock);
 }
 
-int fd_device_fd(struct fd_device *dev)
+drm_public int fd_device_fd(struct fd_device *dev)
 {
 	return dev->fd;
 }
 
-enum fd_version fd_device_version(struct fd_device *dev)
+drm_public enum fd_version fd_device_version(struct fd_device *dev)
 {
 	return dev->version;
 }
diff --git a/freedreno/freedreno_drmif.h b/freedreno/freedreno_drmif.h
index 7a8073f..c95c21b 100644
--- a/freedreno/freedreno_drmif.h
+++ b/freedreno/freedreno_drmif.h
@@ -61,6 +61,7 @@
 	FD_CHIP_ID,
 	FD_MAX_FREQ,
 	FD_TIMESTAMP,
+	FD_NR_RINGS,      /* # of rings == # of distinct priority levels */
 };
 
 /* bo flags: */
@@ -93,6 +94,8 @@
 	FD_VERSION_MADVISE = 1,            /* kernel supports madvise */
 	FD_VERSION_UNLIMITED_CMDS = 1,     /* submits w/ >4 cmd buffers (growable ringbuffer) */
 	FD_VERSION_FENCE_FD = 2,           /* submit command supports in/out fences */
+	FD_VERSION_SUBMIT_QUEUES = 3,      /* submit queues and multiple priority levels */
+	FD_VERSION_BO_IOVA = 3,            /* supports fd_bo_get/put_iova() */
 };
 enum fd_version fd_device_version(struct fd_device *dev);
 
@@ -100,6 +103,8 @@
  */
 
 struct fd_pipe * fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id);
+struct fd_pipe * fd_pipe_new2(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio);
+struct fd_pipe * fd_pipe_ref(struct fd_pipe *pipe);
 void fd_pipe_del(struct fd_pipe *pipe);
 int fd_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param,
 		uint64_t *value);
@@ -120,6 +125,8 @@
 		uint32_t handle, uint32_t size);
 struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name);
 struct fd_bo * fd_bo_from_dmabuf(struct fd_device *dev, int fd);
+uint64_t fd_bo_get_iova(struct fd_bo *bo);
+void fd_bo_put_iova(struct fd_bo *bo);
 struct fd_bo * fd_bo_ref(struct fd_bo *bo);
 void fd_bo_del(struct fd_bo *bo);
 int fd_bo_get_name(struct fd_bo *bo, uint32_t *name);
diff --git a/freedreno/freedreno_pipe.c b/freedreno/freedreno_pipe.c
index 3f8c834..e82e644 100644
--- a/freedreno/freedreno_pipe.c
+++ b/freedreno/freedreno_pipe.c
@@ -26,60 +26,76 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "freedreno_drmif.h"
 #include "freedreno_priv.h"
 
-struct fd_pipe *
-fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id)
+/**
+ * priority of zero is highest priority, and higher numeric values are
+ * lower priorities
+ */
+drm_public struct fd_pipe *
+fd_pipe_new2(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio)
 {
-	struct fd_pipe *pipe = NULL;
+	struct fd_pipe *pipe;
 	uint64_t val;
 
 	if (id > FD_PIPE_MAX) {
 		ERROR_MSG("invalid pipe id: %d", id);
-		goto fail;
+		return NULL;
 	}
 
-	pipe = dev->funcs->pipe_new(dev, id);
+	if ((prio != 1) && (fd_device_version(dev) < FD_VERSION_SUBMIT_QUEUES)) {
+		ERROR_MSG("invalid priority!");
+		return NULL;
+	}
+
+	pipe = dev->funcs->pipe_new(dev, id, prio);
 	if (!pipe) {
 		ERROR_MSG("allocation failed");
-		goto fail;
+		return NULL;
 	}
 
 	pipe->dev = dev;
 	pipe->id = id;
+	atomic_set(&pipe->refcnt, 1);
 
 	fd_pipe_get_param(pipe, FD_GPU_ID, &val);
 	pipe->gpu_id = val;
 
 	return pipe;
-fail:
-	if (pipe)
-		fd_pipe_del(pipe);
-	return NULL;
 }
 
-void fd_pipe_del(struct fd_pipe *pipe)
+drm_public struct fd_pipe *
+fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id)
 {
+	return fd_pipe_new2(dev, id, 1);
+}
+
+drm_public struct fd_pipe * fd_pipe_ref(struct fd_pipe *pipe)
+{
+	atomic_inc(&pipe->refcnt);
+	return pipe;
+}
+
+drm_public void fd_pipe_del(struct fd_pipe *pipe)
+{
+	if (!atomic_dec_and_test(&pipe->refcnt))
+		return;
 	pipe->funcs->destroy(pipe);
 }
 
-int fd_pipe_get_param(struct fd_pipe *pipe,
+drm_public int fd_pipe_get_param(struct fd_pipe *pipe,
 				 enum fd_param_id param, uint64_t *value)
 {
 	return pipe->funcs->get_param(pipe, param, value);
 }
 
-int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp)
+drm_public int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp)
 {
 	return fd_pipe_wait_timeout(pipe, timestamp, ~0);
 }
 
-int fd_pipe_wait_timeout(struct fd_pipe *pipe, uint32_t timestamp,
+drm_public int fd_pipe_wait_timeout(struct fd_pipe *pipe, uint32_t timestamp,
 		uint64_t timeout)
 {
 	return pipe->funcs->wait(pipe, timestamp, timeout);
diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h
index 3217039..b8eac4b 100644
--- a/freedreno/freedreno_priv.h
+++ b/freedreno/freedreno_priv.h
@@ -29,10 +29,6 @@
 #ifndef FREEDRENO_PRIV_H_
 #define FREEDRENO_PRIV_H_
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
@@ -49,6 +45,7 @@
 #include "xf86atomic.h"
 
 #include "util_double_list.h"
+#include "util_math.h"
 
 #include "freedreno_drmif.h"
 #include "freedreno_ringbuffer.h"
@@ -66,7 +63,8 @@
 			uint32_t flags, uint32_t *handle);
 	struct fd_bo * (*bo_from_handle)(struct fd_device *dev,
 			uint32_t size, uint32_t handle);
-	struct fd_pipe * (*pipe_new)(struct fd_device *dev, enum fd_pipe_id id);
+	struct fd_pipe * (*pipe_new)(struct fd_device *dev, enum fd_pipe_id id,
+			unsigned prio);
 	void (*destroy)(struct fd_device *dev);
 };
 
@@ -100,8 +98,12 @@
 	const struct fd_device_funcs *funcs;
 
 	struct fd_bo_cache bo_cache;
+	struct fd_bo_cache ring_cache;
 
 	int closefd;        /* call close(fd) upon destruction */
+
+	/* just for valgrind: */
+	int bo_size;
 };
 
 drm_private void fd_bo_cache_init(struct fd_bo_cache *cache, int coarse);
@@ -114,7 +116,8 @@
 drm_private void fd_device_del_locked(struct fd_device *dev);
 
 struct fd_pipe_funcs {
-	struct fd_ringbuffer * (*ringbuffer_new)(struct fd_pipe *pipe, uint32_t size);
+	struct fd_ringbuffer * (*ringbuffer_new)(struct fd_pipe *pipe, uint32_t size,
+			enum fd_ringbuffer_flags flags);
 	int (*get_param)(struct fd_pipe *pipe, enum fd_param_id param, uint64_t *value);
 	int (*wait)(struct fd_pipe *pipe, uint32_t timestamp, uint64_t timeout);
 	void (*destroy)(struct fd_pipe *pipe);
@@ -124,14 +127,10 @@
 	struct fd_device *dev;
 	enum fd_pipe_id id;
 	uint32_t gpu_id;
+	atomic_t refcnt;
 	const struct fd_pipe_funcs *funcs;
 };
 
-struct fd_ringmarker {
-	struct fd_ringbuffer *ring;
-	uint32_t *cur;
-};
-
 struct fd_ringbuffer_funcs {
 	void * (*hostptr)(struct fd_ringbuffer *ring);
 	int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start,
@@ -141,8 +140,7 @@
 	void (*emit_reloc)(struct fd_ringbuffer *ring,
 			const struct fd_reloc *reloc);
 	uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring,
-			struct fd_ringbuffer *target, uint32_t cmd_idx,
-			uint32_t submit_offset, uint32_t size);
+			struct fd_ringbuffer *target, uint32_t cmd_idx);
 	uint32_t (*cmd_count)(struct fd_ringbuffer *ring);
 	void (*destroy)(struct fd_ringbuffer *ring);
 };
@@ -152,6 +150,7 @@
 	int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op);
 	void (*cpu_fini)(struct fd_bo *bo);
 	int (*madvise)(struct fd_bo *bo, int willneed);
+	uint64_t (*iova)(struct fd_bo *bo);
 	void (*destroy)(struct fd_bo *bo);
 };
 
@@ -164,12 +163,19 @@
 	atomic_t refcnt;
 	const struct fd_bo_funcs *funcs;
 
-	int bo_reuse;
+	enum {
+		NO_CACHE = 0,
+		BO_CACHE = 1,
+		RING_CACHE = 2,
+	} bo_reuse;
+
 	struct list_head list;   /* bucket-list entry */
 	time_t free_time;        /* time when added to bucket-list */
 };
 
-#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1))
+drm_private struct fd_bo *fd_bo_new_ring(struct fd_device *dev,
+		uint32_t size, uint32_t flags);
+
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 
 #define enable_debug 0  /* TODO make dynamic */
@@ -196,4 +202,57 @@
 	return ((char *)end) - ((char *)start);
 }
 
+#if HAVE_VALGRIND
+#  include <memcheck.h>
+
+/*
+ * For tracking the backing memory (if valgrind enabled, we force a mmap
+ * for the purposes of tracking)
+ */
+static inline void VG_BO_ALLOC(struct fd_bo *bo)
+{
+	if (bo && RUNNING_ON_VALGRIND) {
+		VALGRIND_MALLOCLIKE_BLOCK(fd_bo_map(bo), bo->size, 0, 1);
+	}
+}
+
+static inline void VG_BO_FREE(struct fd_bo *bo)
+{
+	VALGRIND_FREELIKE_BLOCK(bo->map, 0);
+}
+
+/*
+ * For tracking bo structs that are in the buffer-cache, so that valgrind
+ * doesn't attribute ownership to the first one to allocate the recycled
+ * bo.
+ *
+ * Note that the list_head in fd_bo is used to track the buffers in cache
+ * so disable error reporting on the range while they are in cache so
+ * valgrind doesn't squawk about list traversal.
+ *
+ */
+static inline void VG_BO_RELEASE(struct fd_bo *bo)
+{
+	if (RUNNING_ON_VALGRIND) {
+		VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size);
+		VALGRIND_MAKE_MEM_NOACCESS(bo, bo->dev->bo_size);
+		VALGRIND_FREELIKE_BLOCK(bo->map, 0);
+	}
+}
+static inline void VG_BO_OBTAIN(struct fd_bo *bo)
+{
+	if (RUNNING_ON_VALGRIND) {
+		VALGRIND_MAKE_MEM_DEFINED(bo, bo->dev->bo_size);
+		VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size);
+		VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1);
+	}
+}
+#else
+static inline void VG_BO_ALLOC(struct fd_bo *bo)   {}
+static inline void VG_BO_FREE(struct fd_bo *bo)    {}
+static inline void VG_BO_RELEASE(struct fd_bo *bo) {}
+static inline void VG_BO_OBTAIN(struct fd_bo *bo)  {}
+#endif
+
+
 #endif /* FREEDRENO_PRIV_H_ */
diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c
index 7310f1f..8f0093a 100644
--- a/freedreno/freedreno_ringbuffer.c
+++ b/freedreno/freedreno_ringbuffer.c
@@ -26,25 +26,30 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <assert.h>
 
 #include "freedreno_drmif.h"
 #include "freedreno_priv.h"
 #include "freedreno_ringbuffer.h"
 
-struct fd_ringbuffer *
-fd_ringbuffer_new(struct fd_pipe *pipe, uint32_t size)
+drm_public struct fd_ringbuffer *
+fd_ringbuffer_new_flags(struct fd_pipe *pipe, uint32_t size,
+		enum fd_ringbuffer_flags flags)
 {
 	struct fd_ringbuffer *ring;
 
-	ring = pipe->funcs->ringbuffer_new(pipe, size);
+	/* we can't really support "growable" rb's in general for
+	 * stateobj's since we need a single gpu addr (ie. can't
+	 * do the trick of a chain of IB packets):
+	 */
+	if (flags & FD_RINGBUFFER_OBJECT)
+		assert(size);
+
+	ring = pipe->funcs->ringbuffer_new(pipe, size, flags);
 	if (!ring)
 		return NULL;
 
+	ring->flags = flags;
 	ring->pipe = pipe;
 	ring->start = ring->funcs->hostptr(ring);
 	ring->end = &(ring->start[ring->size/4]);
@@ -54,23 +59,48 @@
 	return ring;
 }
 
-void fd_ringbuffer_del(struct fd_ringbuffer *ring)
+drm_public struct fd_ringbuffer *
+fd_ringbuffer_new(struct fd_pipe *pipe, uint32_t size)
 {
+	return fd_ringbuffer_new_flags(pipe, size, 0);
+}
+
+drm_public struct fd_ringbuffer *
+fd_ringbuffer_new_object(struct fd_pipe *pipe, uint32_t size)
+{
+	return fd_ringbuffer_new_flags(pipe, size, FD_RINGBUFFER_OBJECT);
+}
+
+drm_public void fd_ringbuffer_del(struct fd_ringbuffer *ring)
+{
+	if (!atomic_dec_and_test(&ring->refcnt))
+		return;
+
 	fd_ringbuffer_reset(ring);
 	ring->funcs->destroy(ring);
 }
 
+drm_public struct fd_ringbuffer *
+fd_ringbuffer_ref(struct fd_ringbuffer *ring)
+{
+	STATIC_ASSERT(sizeof(ring->refcnt) <= sizeof(ring->__pad));
+	atomic_inc(&ring->refcnt);
+	return ring;
+}
+
 /* ringbuffers which are IB targets should set the toplevel rb (ie.
  * the IB source) as it's parent before emitting reloc's, to ensure
  * the bookkeeping works out properly.
  */
-void fd_ringbuffer_set_parent(struct fd_ringbuffer *ring,
+drm_public void fd_ringbuffer_set_parent(struct fd_ringbuffer *ring,
 					 struct fd_ringbuffer *parent)
 {
+	/* state objects should not be parented! */
+	assert(!(ring->flags & FD_RINGBUFFER_OBJECT));
 	ring->parent = parent;
 }
 
-void fd_ringbuffer_reset(struct fd_ringbuffer *ring)
+drm_public void fd_ringbuffer_reset(struct fd_ringbuffer *ring)
 {
 	uint32_t *start = ring->start;
 	if (ring->pipe->id == FD_PIPE_2D)
@@ -80,18 +110,18 @@
 		ring->funcs->reset(ring);
 }
 
-int fd_ringbuffer_flush(struct fd_ringbuffer *ring)
+drm_public int fd_ringbuffer_flush(struct fd_ringbuffer *ring)
 {
 	return ring->funcs->flush(ring, ring->last_start, -1, NULL);
 }
 
-int fd_ringbuffer_flush2(struct fd_ringbuffer *ring, int in_fence_fd,
+drm_public int fd_ringbuffer_flush2(struct fd_ringbuffer *ring, int in_fence_fd,
 		int *out_fence_fd)
 {
 	return ring->funcs->flush(ring, ring->last_start, in_fence_fd, out_fence_fd);
 }
 
-void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords)
+drm_public void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords)
 {
 	assert(ring->funcs->grow);     /* unsupported on kgsl */
 
@@ -107,89 +137,46 @@
 	ring->cur = ring->last_start = ring->start;
 }
 
-uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring)
+drm_public uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring)
 {
 	return ring->last_timestamp;
 }
 
-void fd_ringbuffer_reloc(struct fd_ringbuffer *ring,
+drm_public void fd_ringbuffer_reloc(struct fd_ringbuffer *ring,
 				    const struct fd_reloc *reloc)
 {
 	assert(ring->pipe->gpu_id < 500);
 	ring->funcs->emit_reloc(ring, reloc);
 }
 
-void fd_ringbuffer_reloc2(struct fd_ringbuffer *ring,
+drm_public void fd_ringbuffer_reloc2(struct fd_ringbuffer *ring,
 				     const struct fd_reloc *reloc)
 {
 	ring->funcs->emit_reloc(ring, reloc);
 }
 
-void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-		struct fd_ringmarker *target, struct fd_ringmarker *end)
-{
-	uint32_t submit_offset, size;
-
-	/* This function is deprecated and not supported on 64b devices: */
-	assert(ring->pipe->gpu_id < 500);
-	assert(target->ring == end->ring);
-
-	submit_offset = offset_bytes(target->cur, target->ring->start);
-	size = offset_bytes(end->cur, target->cur);
-
-	ring->funcs->emit_reloc_ring(ring, target->ring, 0, submit_offset, size);
-}
-
-uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring)
+drm_public uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring)
 {
 	if (!ring->funcs->cmd_count)
 		return 1;
 	return ring->funcs->cmd_count(ring);
 }
 
-uint32_t
+drm_public uint32_t
 fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring,
 		struct fd_ringbuffer *target, uint32_t cmd_idx)
 {
-	uint32_t size = offset_bytes(target->cur, target->start);
-	return ring->funcs->emit_reloc_ring(ring, target, cmd_idx, 0, size);
+	return ring->funcs->emit_reloc_ring(ring, target, cmd_idx);
 }
 
-struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring)
+drm_public uint32_t
+fd_ringbuffer_size(struct fd_ringbuffer *ring)
 {
-	struct fd_ringmarker *marker = NULL;
-
-	marker = calloc(1, sizeof(*marker));
-	if (!marker) {
-		ERROR_MSG("allocation failed");
-		return NULL;
-	}
-
-	marker->ring = ring;
-
-	marker->cur = marker->ring->cur;
-
-	return marker;
+	/* only really needed for stateobj ringbuffers, and won't really
+	 * do what you expect for growable rb's.. so lets just restrict
+	 * this to stateobj's for now:
+	 */
+	assert(ring->flags & FD_RINGBUFFER_OBJECT);
+	return offset_bytes(ring->cur, ring->start);
 }
 
-void fd_ringmarker_del(struct fd_ringmarker *marker)
-{
-	free(marker);
-}
-
-void fd_ringmarker_mark(struct fd_ringmarker *marker)
-{
-	marker->cur = marker->ring->cur;
-}
-
-uint32_t fd_ringmarker_dwords(struct fd_ringmarker *start,
-					 struct fd_ringmarker *end)
-{
-	return end->cur - start->cur;
-}
-
-int fd_ringmarker_flush(struct fd_ringmarker *marker)
-{
-	struct fd_ringbuffer *ring = marker->ring;
-	return ring->funcs->flush(ring, marker->cur, -1, NULL);
-}
diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h
index c501fba..bc41a31 100644
--- a/freedreno/freedreno_ringbuffer.h
+++ b/freedreno/freedreno_ringbuffer.h
@@ -33,12 +33,33 @@
 
 /* the ringbuffer object is not opaque so that OUT_RING() type stuff
  * can be inlined.  Note that users should not make assumptions about
- * the size of this struct.. more stuff will be added when we eventually
- * have a kernel driver that can deal w/ reloc's..
+ * the size of this struct.
  */
 
 struct fd_ringbuffer_funcs;
-struct fd_ringmarker;
+
+enum fd_ringbuffer_flags {
+
+	/* Ringbuffer is a "state object", which is potentially reused
+	 * many times, rather than being used in one-shot mode linked
+	 * to a parent ringbuffer.
+	 */
+	FD_RINGBUFFER_OBJECT = 0x1,
+
+	/* Hint that the stateobj will be used for streaming state
+	 * that is used once or a few times and then discarded.
+	 *
+	 * For sub-allocation, non streaming stateobj's should be
+	 * sub-allocated from a page size buffer, so one long lived
+	 * state obj doesn't prevent other pages from being freed.
+	 * (Ie. it would be no worse than allocating a page sized
+	 * bo for each small non-streaming stateobj).
+	 *
+	 * But streaming stateobj's could be sub-allocated from a
+	 * larger buffer to reduce the alloc/del overhead.
+	 */
+	FD_RINGBUFFER_STREAMING = 0x2,
+};
 
 struct fd_ringbuffer {
 	int size;
@@ -47,13 +68,41 @@
 	const struct fd_ringbuffer_funcs *funcs;
 	uint32_t last_timestamp;
 	struct fd_ringbuffer *parent;
+
+	/* for users of fd_ringbuffer to store their own private per-
+	 * ringbuffer data
+	 */
+	void *user;
+
+	enum fd_ringbuffer_flags flags;
+
+	/* This is a bit gross, but we can't use atomic_t in exported
+	 * headers.  OTOH, we don't need the refcnt to be publicly
+	 * visible.  The only reason that this struct is exported is
+	 * because fd_ringbuffer_emit needs to be something that can
+	 * be inlined for performance reasons.
+	 */
+	union {
+#ifdef HAS_ATOMIC_OPS
+		atomic_t refcnt;
+#endif
+		uint64_t __pad;
+	};
 };
 
 struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe,
 		uint32_t size);
+will_be_deprecated
+struct fd_ringbuffer * fd_ringbuffer_new_object(struct fd_pipe *pipe,
+		uint32_t size);
+struct fd_ringbuffer * fd_ringbuffer_new_flags(struct fd_pipe *pipe,
+		uint32_t size, enum fd_ringbuffer_flags flags);
+
+struct fd_ringbuffer *fd_ringbuffer_ref(struct fd_ringbuffer *ring);
 void fd_ringbuffer_del(struct fd_ringbuffer *ring);
 void fd_ringbuffer_set_parent(struct fd_ringbuffer *ring,
 		struct fd_ringbuffer *parent);
+will_be_deprecated
 void fd_ringbuffer_reset(struct fd_ringbuffer *ring);
 int fd_ringbuffer_flush(struct fd_ringbuffer *ring);
 /* in_fence_fd: -1 for no in-fence, else fence fd
@@ -85,17 +134,9 @@
 
 void fd_ringbuffer_reloc2(struct fd_ringbuffer *ring, const struct fd_reloc *reloc);
 will_be_deprecated void fd_ringbuffer_reloc(struct fd_ringbuffer *ring, const struct fd_reloc *reloc);
-will_be_deprecated void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-		struct fd_ringmarker *target, struct fd_ringmarker *end);
 uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring);
 uint32_t fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring,
 		struct fd_ringbuffer *target, uint32_t cmd_idx);
-
-will_be_deprecated struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring);
-will_be_deprecated void fd_ringmarker_del(struct fd_ringmarker *marker);
-will_be_deprecated void fd_ringmarker_mark(struct fd_ringmarker *marker);
-will_be_deprecated uint32_t fd_ringmarker_dwords(struct fd_ringmarker *start,
-		struct fd_ringmarker *end);
-will_be_deprecated int fd_ringmarker_flush(struct fd_ringmarker *marker);
+uint32_t fd_ringbuffer_size(struct fd_ringbuffer *ring);
 
 #endif /* FREEDRENO_RINGBUFFER_H_ */
diff --git a/freedreno/kgsl/kgsl_bo.c b/freedreno/kgsl/kgsl_bo.c
index ab3485e..7a6af2f 100644
--- a/freedreno/kgsl/kgsl_bo.c
+++ b/freedreno/kgsl/kgsl_bo.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "kgsl_priv.h"
 
 #include <linux/fb.h>
@@ -181,7 +177,7 @@
 	return bo;
 }
 
-struct fd_bo *
+drm_public struct fd_bo *
 fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size)
 {
 	struct fd_bo *bo;
diff --git a/freedreno/kgsl/kgsl_device.c b/freedreno/kgsl/kgsl_device.c
index 175e837..914f341 100644
--- a/freedreno/kgsl/kgsl_device.c
+++ b/freedreno/kgsl/kgsl_device.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -61,5 +57,7 @@
 	dev = &kgsl_dev->base;
 	dev->funcs = &funcs;
 
+	dev->bo_size = sizeof(struct kgsl_bo);
+
 	return dev;
 }
diff --git a/freedreno/kgsl/kgsl_pipe.c b/freedreno/kgsl/kgsl_pipe.c
index 8a39eb4..0a8b658 100644
--- a/freedreno/kgsl/kgsl_pipe.c
+++ b/freedreno/kgsl/kgsl_pipe.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "kgsl_priv.h"
 
 
@@ -52,6 +48,7 @@
 		return 0;
 	case FD_MAX_FREQ:
 	case FD_TIMESTAMP:
+	case FD_NR_RINGS:
 		/* unsupported on kgsl */
 		return -1;
 	default:
@@ -210,7 +207,7 @@
 
 
 drm_private struct fd_pipe * kgsl_pipe_new(struct fd_device *dev,
-		enum fd_pipe_id id)
+		enum fd_pipe_id id, uint32_t prio)
 {
 	static const char *paths[] = {
 			[FD_PIPE_3D] = "/dev/kgsl-3d0",
diff --git a/freedreno/kgsl/kgsl_priv.h b/freedreno/kgsl/kgsl_priv.h
index 6ab6496..a6bf2d4 100644
--- a/freedreno/kgsl/kgsl_priv.h
+++ b/freedreno/kgsl/kgsl_priv.h
@@ -103,10 +103,10 @@
 drm_private void kgsl_pipe_process_pending(struct kgsl_pipe *pipe,
 		uint32_t timestamp);
 drm_private struct fd_pipe * kgsl_pipe_new(struct fd_device *dev,
-		enum fd_pipe_id id);
+		enum fd_pipe_id id, uint32_t prio);
 
 drm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe,
-		uint32_t size);
+		uint32_t size, enum fd_ringbuffer_flags flags);
 
 drm_private int kgsl_bo_new_handle(struct fd_device *dev,
 		uint32_t size, uint32_t flags, uint32_t *handle);
diff --git a/freedreno/kgsl/kgsl_ringbuffer.c b/freedreno/kgsl/kgsl_ringbuffer.c
index e4696b1..9abf0ad 100644
--- a/freedreno/kgsl/kgsl_ringbuffer.c
+++ b/freedreno/kgsl/kgsl_ringbuffer.c
@@ -26,12 +26,9 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <assert.h>
 
+#include "xf86atomic.h"
 #include "freedreno_ringbuffer.h"
 #include "kgsl_priv.h"
 
@@ -146,7 +143,7 @@
 		ibdesc.gpuaddr = kgsl_ring->bo->gpuaddr;
 		ibdesc.hostptr = kgsl_ring->bo->hostptr;
 		ibdesc.sizedwords = 0x145;
-		req.timestamp = (uint32_t)kgsl_ring->bo->hostptr;
+		req.timestamp = (uintptr_t)kgsl_ring->bo->hostptr;
 	}
 
 	do {
@@ -178,13 +175,12 @@
 }
 
 static uint32_t kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-		struct fd_ringbuffer *target, uint32_t cmd_idx,
-		uint32_t submit_offset, uint32_t size)
+		struct fd_ringbuffer *target, uint32_t cmd_idx)
 {
 	struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target);
 	assert(cmd_idx == 0);
-	(*ring->cur++) = target_ring->bo->gpuaddr + submit_offset;
-	return size;
+	(*ring->cur++) = target_ring->bo->gpuaddr;
+	return 	offset_bytes(target->cur, target->start);
 }
 
 static void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring)
@@ -206,11 +202,13 @@
 };
 
 drm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe,
-		uint32_t size)
+		uint32_t size, enum fd_ringbuffer_flags flags)
 {
 	struct kgsl_ringbuffer *kgsl_ring;
 	struct fd_ringbuffer *ring = NULL;
 
+	assert(!flags);
+
 	kgsl_ring = calloc(1, sizeof(*kgsl_ring));
 	if (!kgsl_ring) {
 		ERROR_MSG("allocation failed");
@@ -218,6 +216,8 @@
 	}
 
 	ring = &kgsl_ring->base;
+	atomic_set(&ring->refcnt, 1);
+
 	ring->funcs = &funcs;
 	ring->size = size;
 
diff --git a/freedreno/meson.build b/freedreno/meson.build
new file mode 100644
index 0000000..c9aba06
--- /dev/null
+++ b/freedreno/meson.build
@@ -0,0 +1,77 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+files_freedreno = files(
+  'freedreno_device.c',
+  'freedreno_pipe.c',
+  'freedreno_ringbuffer.c',
+  'freedreno_bo.c',
+  'freedreno_bo_cache.c',
+  'msm/msm_bo.c',
+  'msm/msm_device.c',
+  'msm/msm_pipe.c',
+  'msm/msm_ringbuffer.c',
+)
+
+if with_freedreno_kgsl
+  files_freedreno += files(
+    'kgsl/kgsl_bo.c',
+    'kgsl/kgsl_device.c',
+    'kgsl/kgsl_pipe.c',
+    'kgsl/kgsl_ringbuffer.c',
+  )
+endif
+
+libdrm_freedreno = shared_library(
+  'drm_freedreno',
+  [files_freedreno, config_file],
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_drm],
+  dependencies : [dep_valgrind, dep_pthread_stubs, dep_rt, dep_atomic_ops],
+  link_with : libdrm,
+  version : '1.0.0',
+  install : true,
+)
+
+ext_libdrm_freedreno = declare_dependency(
+  link_with : [libdrm, libdrm_freedreno],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+install_headers(
+  'freedreno_drmif.h', 'freedreno_ringbuffer.h',
+  subdir : 'freedreno'
+)
+
+pkg.generate(
+  name : 'libdrm_freedreno',
+  libraries : libdrm_freedreno,
+  subdirs : ['.', 'libdrm', 'freedreno'],
+  version : meson.project_version(),
+  requires_private : 'libdrm',
+  description : 'Userspace interface to freedreno kernel DRM services',
+)
+
+test(
+  'freedreno-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('freedreno-symbol-check'), libdrm_freedreno]
+)
diff --git a/freedreno/msm/msm_bo.c b/freedreno/msm/msm_bo.c
index 72471df..8b3d0bc 100644
--- a/freedreno/msm/msm_bo.c
+++ b/freedreno/msm/msm_bo.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "msm_priv.h"
 
 static int bo_allocate(struct msm_bo *msm_bo)
@@ -108,6 +104,18 @@
 	return req.retained;
 }
 
+static uint64_t msm_bo_iova(struct fd_bo *bo)
+{
+	struct drm_msm_gem_info req = {
+			.handle = bo->handle,
+			.flags = MSM_INFO_IOVA,
+	};
+
+	drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_INFO, &req, sizeof(req));
+
+	return req.offset;
+}
+
 static void msm_bo_destroy(struct fd_bo *bo)
 {
 	struct msm_bo *msm_bo = to_msm_bo(bo);
@@ -120,6 +128,7 @@
 		.cpu_prep = msm_bo_cpu_prep,
 		.cpu_fini = msm_bo_cpu_fini,
 		.madvise = msm_bo_madvise,
+		.iova = msm_bo_iova,
 		.destroy = msm_bo_destroy,
 };
 
diff --git a/freedreno/msm/msm_device.c b/freedreno/msm/msm_device.c
index 727baa4..58b0746 100644
--- a/freedreno/msm/msm_device.c
+++ b/freedreno/msm/msm_device.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -39,7 +35,6 @@
 static void msm_device_destroy(struct fd_device *dev)
 {
 	struct msm_device *msm_dev = to_msm_device(dev);
-	fd_bo_cache_cleanup(&msm_dev->ring_cache, 0);
 	free(msm_dev);
 }
 
@@ -62,7 +57,7 @@
 	dev = &msm_dev->base;
 	dev->funcs = &funcs;
 
-	fd_bo_cache_init(&msm_dev->ring_cache, TRUE);
+	dev->bo_size = sizeof(struct msm_bo);
 
 	return dev;
 }
diff --git a/freedreno/msm/msm_pipe.c b/freedreno/msm/msm_pipe.c
index f872e24..e070b31 100644
--- a/freedreno/msm/msm_pipe.c
+++ b/freedreno/msm/msm_pipe.c
@@ -26,10 +26,6 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include "msm_priv.h"
 
 static int query_param(struct fd_pipe *pipe, uint32_t param,
@@ -71,6 +67,8 @@
 		return query_param(pipe, MSM_PARAM_MAX_FREQ, value);
 	case FD_TIMESTAMP:
 		return query_param(pipe, MSM_PARAM_TIMESTAMP, value);
+	case FD_NR_RINGS:
+		return query_param(pipe, MSM_PARAM_NR_RINGS, value);
 	default:
 		ERROR_MSG("invalid param id: %d", param);
 		return -1;
@@ -83,6 +81,7 @@
 	struct fd_device *dev = pipe->dev;
 	struct drm_msm_wait_fence req = {
 			.fence = timestamp,
+			.queueid = to_msm_pipe(pipe)->queue_id,
 	};
 	int ret;
 
@@ -97,9 +96,54 @@
 	return 0;
 }
 
+static int open_submitqueue(struct fd_pipe *pipe, uint32_t prio)
+{
+	struct drm_msm_submitqueue req = {
+		.flags = 0,
+		.prio = prio,
+	};
+	uint64_t nr_rings = 1;
+	int ret;
+
+	if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) {
+		to_msm_pipe(pipe)->queue_id = 0;
+		return 0;
+	}
+
+	msm_pipe_get_param(pipe, FD_NR_RINGS, &nr_rings);
+
+	req.prio = MIN2(req.prio, MAX2(nr_rings, 1) - 1);
+
+	ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_NEW,
+			&req, sizeof(req));
+	if (ret) {
+		ERROR_MSG("could not create submitqueue! %d (%s)", ret, strerror(errno));
+		return ret;
+	}
+
+	to_msm_pipe(pipe)->queue_id = req.id;
+	return 0;
+}
+
+static void close_submitqueue(struct fd_pipe *pipe, uint32_t queue_id)
+{
+	if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES)
+		return;
+
+	drmCommandWrite(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE,
+			&queue_id, sizeof(queue_id));
+}
+
 static void msm_pipe_destroy(struct fd_pipe *pipe)
 {
 	struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
+	close_submitqueue(pipe, msm_pipe->queue_id);
+
+	if (msm_pipe->suballoc_ring) {
+		fd_ringbuffer_del(msm_pipe->suballoc_ring);
+		msm_pipe->suballoc_ring = NULL;
+	}
+
 	free(msm_pipe);
 }
 
@@ -122,7 +166,7 @@
 }
 
 drm_private struct fd_pipe * msm_pipe_new(struct fd_device *dev,
-		enum fd_pipe_id id)
+		enum fd_pipe_id id, uint32_t prio)
 {
 	static const uint32_t pipe_id[] = {
 			[FD_PIPE_3D] = MSM_PIPE_3D0,
@@ -157,6 +201,9 @@
 	INFO_MSG(" Chip-id:         0x%08x", msm_pipe->chip_id);
 	INFO_MSG(" GMEM size:       0x%08x", msm_pipe->gmem);
 
+	if (open_submitqueue(pipe, prio))
+		goto fail;
+
 	return pipe;
 fail:
 	if (pipe)
diff --git a/freedreno/msm/msm_priv.h b/freedreno/msm/msm_priv.h
index 6d670aa..cc951fb 100644
--- a/freedreno/msm/msm_priv.h
+++ b/freedreno/msm/msm_priv.h
@@ -56,6 +56,18 @@
 	uint32_t gpu_id;
 	uint32_t gmem;
 	uint32_t chip_id;
+	uint32_t queue_id;
+
+	/* Allow for sub-allocation of stateobj ring buffers (ie. sharing
+	 * the same underlying bo)..
+	 *
+	 * This takes advantage of each context having it's own fd_pipe,
+	 * so we don't have to worry about access from multiple threads.
+	 *
+	 * We also rely on previous stateobj having been fully constructed
+	 * so we can reclaim extra space at it's end.
+	 */
+	struct fd_ringbuffer *suballoc_ring;
 };
 
 static inline struct msm_pipe * to_msm_pipe(struct fd_pipe *x)
@@ -64,10 +76,10 @@
 }
 
 drm_private struct fd_pipe * msm_pipe_new(struct fd_device *dev,
-		enum fd_pipe_id id);
+		enum fd_pipe_id id, uint32_t prio);
 
 drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe,
-		uint32_t size);
+		uint32_t size, enum fd_ringbuffer_flags flags);
 
 struct msm_bo {
 	struct fd_bo base;
@@ -100,4 +112,30 @@
 	tv->tv_nsec = t.tv_nsec + ns - (s * 1000000000);
 }
 
+/*
+ * Stupid/simple growable array implementation:
+ */
+
+static inline void *
+grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz)
+{
+	if ((nr + 1) > *max) {
+		if ((*max * 2) < (nr + 1))
+			*max = nr + 5;
+		else
+			*max = *max * 2;
+		ptr = realloc(ptr, *max * sz);
+	}
+	return ptr;
+}
+
+#define DECLARE_ARRAY(type, name) \
+	unsigned nr_ ## name, max_ ## name; \
+	type * name;
+
+#define APPEND(x, name) ({ \
+	(x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \
+	(x)->nr_ ## name ++; \
+})
+
 #endif /* MSM_PRIV_H_ */
diff --git a/freedreno/msm/msm_ringbuffer.c b/freedreno/msm/msm_ringbuffer.c
index 17194f4..475c65d 100644
--- a/freedreno/msm/msm_ringbuffer.c
+++ b/freedreno/msm/msm_ringbuffer.c
@@ -26,13 +26,10 @@
  *    Rob Clark <robclark@freedesktop.org>
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <assert.h>
 #include <inttypes.h>
 
+#include "xf86atomic.h"
 #include "freedreno_ringbuffer.h"
 #include "msm_priv.h"
 
@@ -46,10 +43,12 @@
 	struct fd_bo *ring_bo;
 
 	/* reloc's table: */
-	struct drm_msm_gem_submit_reloc *relocs;
-	uint32_t nr_relocs, max_relocs;
+	DECLARE_ARRAY(struct drm_msm_gem_submit_reloc, relocs);
 
 	uint32_t size;
+
+	/* has cmd already been added to parent rb's submit.cmds table? */
+	int is_appended_to_submit;
 };
 
 struct msm_ringbuffer {
@@ -62,22 +61,18 @@
 	 */
 	struct {
 		/* bo's table: */
-		struct drm_msm_gem_submit_bo *bos;
-		uint32_t nr_bos, max_bos;
+		DECLARE_ARRAY(struct drm_msm_gem_submit_bo, bos);
 
 		/* cmd's table: */
-		struct drm_msm_gem_submit_cmd *cmds;
-		uint32_t nr_cmds, max_cmds;
+		DECLARE_ARRAY(struct drm_msm_gem_submit_cmd, cmds);
 	} submit;
 
 	/* should have matching entries in submit.bos: */
 	/* Note, only in parent ringbuffer */
-	struct fd_bo **bos;
-	uint32_t nr_bos, max_bos;
+	DECLARE_ARRAY(struct fd_bo *, bos);
 
 	/* should have matching entries in submit.cmds: */
-	struct msm_cmd **cmds;
-	uint32_t nr_cmds, max_cmds;
+	DECLARE_ARRAY(struct msm_cmd *, cmds);
 
 	/* List of physical cmdstream buffers (msm_cmd) assocated with this
 	 * logical fd_ringbuffer.
@@ -93,10 +88,24 @@
 	int is_growable;
 	unsigned cmd_count;
 
+	unsigned offset;    /* for sub-allocated stateobj rb's */
+
 	unsigned seqno;
 
 	/* maps fd_bo to idx: */
 	void *bo_table;
+
+	/* maps msm_cmd to drm_msm_gem_submit_cmd in parent rb.  Each rb has a
+	 * list of msm_cmd's which correspond to each chunk of cmdstream in
+	 * a 'growable' rb.  For each of those we need to create one
+	 * drm_msm_gem_submit_cmd in the parent rb which collects the state
+	 * for the submit ioctl.  Because we can have multiple IB's to the same
+	 * target rb (for example, or same stateobj emit multiple times), and
+	 * because in theory we can have multiple different rb's that have a
+	 * reference to a given target, we need a hashtable to track this per
+	 * rb.
+	 */
+	void *cmd_table;
 };
 
 static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x)
@@ -107,51 +116,25 @@
 #define INIT_SIZE 0x1000
 
 static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER;
-drm_private extern pthread_mutex_t table_lock;
 
-static void ring_bo_del(struct fd_device *dev, struct fd_bo *bo)
+static struct msm_cmd *current_cmd(struct fd_ringbuffer *ring)
 {
-	int ret;
-
-	pthread_mutex_lock(&table_lock);
-	ret = fd_bo_cache_free(&to_msm_device(dev)->ring_cache, bo);
-	pthread_mutex_unlock(&table_lock);
-
-	if (ret == 0)
-		return;
-
-	fd_bo_del(bo);
-}
-
-static struct fd_bo * ring_bo_new(struct fd_device *dev, uint32_t size)
-{
-	struct fd_bo *bo;
-
-	bo = fd_bo_cache_alloc(&to_msm_device(dev)->ring_cache, &size, 0);
-	if (bo)
-		return bo;
-
-	bo = fd_bo_new(dev, size, 0);
-	if (!bo)
-		return NULL;
-
-	/* keep ringbuffer bo's out of the normal bo cache: */
-	bo->bo_reuse = FALSE;
-
-	return bo;
+	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
+	assert(!LIST_IS_EMPTY(&msm_ring->cmd_list));
+	return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list);
 }
 
 static void ring_cmd_del(struct msm_cmd *cmd)
 {
-	if (cmd->ring_bo)
-		ring_bo_del(cmd->ring->pipe->dev, cmd->ring_bo);
+	fd_bo_del(cmd->ring_bo);
 	list_del(&cmd->list);
 	to_msm_ringbuffer(cmd->ring)->cmd_count--;
 	free(cmd->relocs);
 	free(cmd);
 }
 
-static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size)
+static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size,
+		enum fd_ringbuffer_flags flags)
 {
 	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
 	struct msm_cmd *cmd = calloc(1, sizeof(*cmd));
@@ -160,7 +143,48 @@
 		return NULL;
 
 	cmd->ring = ring;
-	cmd->ring_bo = ring_bo_new(ring->pipe->dev, size);
+
+	/* TODO separate suballoc buffer for small non-streaming state, using
+	 * smaller page-sized backing bo's.
+	 */
+	if (flags & FD_RINGBUFFER_STREAMING) {
+		struct msm_pipe *msm_pipe = to_msm_pipe(ring->pipe);
+		unsigned suballoc_offset = 0;
+		struct fd_bo *suballoc_bo = NULL;
+
+		if (msm_pipe->suballoc_ring) {
+			struct msm_ringbuffer *suballoc_ring = to_msm_ringbuffer(msm_pipe->suballoc_ring);
+
+			assert(msm_pipe->suballoc_ring->flags & FD_RINGBUFFER_OBJECT);
+			assert(suballoc_ring->cmd_count == 1);
+
+			suballoc_bo = current_cmd(msm_pipe->suballoc_ring)->ring_bo;
+
+			suballoc_offset = fd_ringbuffer_size(msm_pipe->suballoc_ring) +
+					suballoc_ring->offset;
+
+			suballoc_offset = ALIGN(suballoc_offset, 0x10);
+
+			if ((size + suballoc_offset) > suballoc_bo->size) {
+				suballoc_bo = NULL;
+			}
+		}
+
+		if (!suballoc_bo) {
+			cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, 0x8000, 0);
+			msm_ring->offset = 0;
+		} else {
+			cmd->ring_bo = fd_bo_ref(suballoc_bo);
+			msm_ring->offset = suballoc_offset;
+		}
+
+		if (msm_pipe->suballoc_ring)
+			fd_ringbuffer_del(msm_pipe->suballoc_ring);
+
+		msm_pipe->suballoc_ring = fd_ringbuffer_ref(ring);
+	} else {
+		cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, size, 0);
+	}
 	if (!cmd->ring_bo)
 		goto fail;
 
@@ -174,30 +198,6 @@
 	return NULL;
 }
 
-static void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz)
-{
-	if ((nr + 1) > *max) {
-		if ((*max * 2) < (nr + 1))
-			*max = nr + 5;
-		else
-			*max = *max * 2;
-		ptr = realloc(ptr, *max * sz);
-	}
-	return ptr;
-}
-
-#define APPEND(x, name) ({ \
-	(x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \
-	(x)->nr_ ## name ++; \
-})
-
-static struct msm_cmd *current_cmd(struct fd_ringbuffer *ring)
-{
-	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
-	assert(!LIST_IS_EMPTY(&msm_ring->cmd_list));
-	return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list);
-}
-
 static uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo)
 {
 	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
@@ -249,31 +249,43 @@
 	return idx;
 }
 
-static int check_cmd_bo(struct fd_ringbuffer *ring,
-		struct drm_msm_gem_submit_cmd *cmd, struct fd_bo *bo)
-{
-	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
-	return msm_ring->submit.bos[cmd->submit_idx].handle == bo->handle;
-}
-
 /* Ensure that submit has corresponding entry in cmds table for the
  * target cmdstream buffer:
+ *
+ * Returns TRUE if new cmd added (else FALSE if it was already in
+ * the cmds table)
  */
-static void get_cmd(struct fd_ringbuffer *ring, struct msm_cmd *target_cmd,
+static int get_cmd(struct fd_ringbuffer *ring, struct msm_cmd *target_cmd,
 		uint32_t submit_offset, uint32_t size, uint32_t type)
 {
 	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
 	struct drm_msm_gem_submit_cmd *cmd;
 	uint32_t i;
+	void *val;
 
-	/* figure out if we already have a cmd buf: */
-	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
+	if (!msm_ring->cmd_table)
+		msm_ring->cmd_table = drmHashCreate();
+
+	/* figure out if we already have a cmd buf.. short-circuit hash
+	 * lookup if:
+	 *  - target cmd has never been added to submit.cmds
+	 *  - target cmd is not a streaming stateobj (which unlike longer
+	 *    lived CSO stateobj, is not expected to be reused with multiple
+	 *    submits)
+	 */
+	if (target_cmd->is_appended_to_submit &&
+			!(target_cmd->ring->flags & FD_RINGBUFFER_STREAMING) &&
+			!drmHashLookup(msm_ring->cmd_table, (unsigned long)target_cmd, &val)) {
+		i = VOID2U64(val);
 		cmd = &msm_ring->submit.cmds[i];
-		if ((cmd->submit_offset == submit_offset) &&
-				(cmd->size == size) &&
-				(cmd->type == type) &&
-				check_cmd_bo(ring, cmd, target_cmd->ring_bo))
-			return;
+
+		assert(cmd->submit_offset == submit_offset);
+		assert(cmd->size == size);
+		assert(cmd->type == type);
+		assert(msm_ring->submit.bos[cmd->submit_idx].handle ==
+				target_cmd->ring_bo->handle);
+
+		return FALSE;
 	}
 
 	/* create cmd buf if not: */
@@ -287,27 +299,23 @@
 	cmd->size = size;
 	cmd->pad = 0;
 
+	target_cmd->is_appended_to_submit = TRUE;
+
+	if (!(target_cmd->ring->flags & FD_RINGBUFFER_STREAMING)) {
+		drmHashInsert(msm_ring->cmd_table, (unsigned long)target_cmd,
+				U642VOID(i));
+	}
+
 	target_cmd->size = size;
+
+	return TRUE;
 }
 
 static void * msm_ringbuffer_hostptr(struct fd_ringbuffer *ring)
 {
-	return fd_bo_map(current_cmd(ring)->ring_bo);
-}
-
-static uint32_t find_next_reloc_idx(struct msm_cmd *msm_cmd,
-		uint32_t start, uint32_t offset)
-{
-	uint32_t i;
-
-	/* a binary search would be more clever.. */
-	for (i = start; i < msm_cmd->nr_relocs; i++) {
-		struct drm_msm_gem_submit_reloc *reloc = &msm_cmd->relocs[i];
-		if (reloc->submit_offset >= offset)
-			return i;
-	}
-
-	return i;
+	struct msm_cmd *cmd = current_cmd(ring);
+	uint8_t *base = fd_bo_map(cmd->ring_bo);
+	return base + to_msm_ringbuffer(ring)->offset;
 }
 
 static void delete_cmds(struct msm_ringbuffer *msm_ring)
@@ -326,14 +334,20 @@
 
 	for (i = 0; i < msm_ring->nr_bos; i++) {
 		struct msm_bo *msm_bo = to_msm_bo(msm_ring->bos[i]);
+		if (!msm_bo)
+			continue;
 		msm_bo->current_ring_seqno = 0;
 		fd_bo_del(&msm_bo->base);
 	}
 
-	/* for each of the cmd buffers, clear their reloc's: */
-	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
-		struct msm_cmd *target_cmd = msm_ring->cmds[i];
-		target_cmd->nr_relocs = 0;
+	for (i = 0; i < msm_ring->nr_cmds; i++) {
+		struct msm_cmd *msm_cmd = msm_ring->cmds[i];
+
+		if (msm_cmd->ring == ring)
+			continue;
+
+		if (msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT)
+			fd_ringbuffer_del(msm_cmd->ring);
 	}
 
 	msm_ring->submit.nr_cmds = 0;
@@ -346,6 +360,11 @@
 		msm_ring->bo_table = NULL;
 	}
 
+	if (msm_ring->cmd_table) {
+		drmHashDestroy(msm_ring->cmd_table);
+		msm_ring->cmd_table = NULL;
+	}
+
 	if (msm_ring->is_growable) {
 		delete_cmds(msm_ring);
 	} else {
@@ -395,16 +414,63 @@
 	}
 }
 
+static struct drm_msm_gem_submit_reloc *
+handle_stateobj_relocs(struct fd_ringbuffer *parent, struct fd_ringbuffer *stateobj,
+		struct drm_msm_gem_submit_reloc *orig_relocs, unsigned nr_relocs)
+{
+	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(stateobj);
+	struct drm_msm_gem_submit_reloc *relocs = malloc(nr_relocs * sizeof(*relocs));
+	unsigned i;
+
+	for (i = 0; i < nr_relocs; i++) {
+		unsigned idx = orig_relocs[i].reloc_idx;
+		struct fd_bo *bo = msm_ring->bos[idx];
+		unsigned flags = 0;
+
+		if (msm_ring->submit.bos[idx].flags & MSM_SUBMIT_BO_READ)
+			flags |= FD_RELOC_READ;
+		if (msm_ring->submit.bos[idx].flags & MSM_SUBMIT_BO_WRITE)
+			flags |= FD_RELOC_WRITE;
+
+		relocs[i] = orig_relocs[i];
+		relocs[i].reloc_idx = bo2idx(parent, bo, flags);
+	}
+
+	/* stateobj rb's could have reloc's to other stateobj rb's which didn't
+	 * get propagated to the parent rb at _emit_reloc_ring() time (because
+	 * the parent wasn't known then), so fix that up now:
+	 */
+	for (i = 0; i < msm_ring->nr_cmds; i++) {
+		struct msm_cmd *msm_cmd = msm_ring->cmds[i];
+		struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i];
+
+		if (msm_ring->cmds[i]->ring == stateobj)
+			continue;
+
+		assert(msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT);
+
+		if (get_cmd(parent, msm_cmd, cmd->submit_offset, cmd->size, cmd->type)) {
+			fd_ringbuffer_ref(msm_cmd->ring);
+		}
+	}
+
+	return relocs;
+}
+
 static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start,
 		int in_fence_fd, int *out_fence_fd)
 {
 	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
+	struct msm_pipe *msm_pipe = to_msm_pipe(ring->pipe);
 	struct drm_msm_gem_submit req = {
-			.flags = to_msm_pipe(ring->pipe)->pipe,
+			.flags = msm_pipe->pipe,
+			.queueid = msm_pipe->queue_id,
 	};
 	uint32_t i;
 	int ret;
 
+	assert(!ring->parent);
+
 	if (in_fence_fd != -1) {
 		req.flags |= MSM_SUBMIT_FENCE_FD_IN | MSM_SUBMIT_NO_IMPLICIT;
 		req.fence_fd = in_fence_fd;
@@ -416,22 +482,35 @@
 
 	finalize_current_cmd(ring, last_start);
 
+	/* for each of the cmd's fix up their reloc's: */
+	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
+		struct msm_cmd *msm_cmd = msm_ring->cmds[i];
+		struct drm_msm_gem_submit_reloc *relocs = msm_cmd->relocs;
+		struct drm_msm_gem_submit_cmd *cmd;
+		unsigned nr_relocs = msm_cmd->nr_relocs;
+
+		/* for reusable stateobjs, the reloc table has reloc_idx that
+		 * points into it's own private bos table, rather than the global
+		 * bos table used for the submit, so we need to add the stateobj's
+		 * bos to the global table and construct new relocs table with
+		 * corresponding reloc_idx
+		 */
+		if (msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT) {
+			relocs = handle_stateobj_relocs(ring, msm_cmd->ring,
+					relocs, nr_relocs);
+		}
+
+		cmd = &msm_ring->submit.cmds[i];
+		cmd->relocs = VOID2U64(relocs);
+		cmd->nr_relocs = nr_relocs;
+	}
+
 	/* needs to be after get_cmd() as that could create bos/cmds table: */
 	req.bos = VOID2U64(msm_ring->submit.bos),
 	req.nr_bos = msm_ring->submit.nr_bos;
 	req.cmds = VOID2U64(msm_ring->submit.cmds),
 	req.nr_cmds = msm_ring->submit.nr_cmds;
 
-	/* for each of the cmd's fix up their reloc's: */
-	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
-		struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i];
-		struct msm_cmd *msm_cmd = msm_ring->cmds[i];
-		uint32_t a = find_next_reloc_idx(msm_cmd, 0, cmd->submit_offset);
-		uint32_t b = find_next_reloc_idx(msm_cmd, a, cmd->submit_offset + cmd->size);
-		cmd->relocs = VOID2U64(&msm_cmd->relocs[a]);
-		cmd->nr_relocs = (b > a) ? b - a : 0;
-	}
-
 	DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos);
 
 	ret = drmCommandWriteRead(ring->pipe->dev->fd, DRM_MSM_GEM_SUBMIT,
@@ -451,6 +530,15 @@
 		}
 	}
 
+	/* free dynamically constructed stateobj relocs tables: */
+	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
+		struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i];
+		struct msm_cmd *msm_cmd = msm_ring->cmds[i];
+		if (msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT) {
+			free(U642VOID(cmd->relocs));
+		}
+	}
+
 	flush_reset(ring);
 
 	return ret;
@@ -460,7 +548,7 @@
 {
 	assert(to_msm_ringbuffer(ring)->is_growable);
 	finalize_current_cmd(ring, ring->last_start);
-	ring_cmd_new(ring, size);
+	ring_cmd_new(ring, size, 0);
 }
 
 static void msm_ringbuffer_reset(struct fd_ringbuffer *ring)
@@ -484,7 +572,8 @@
 	reloc->reloc_offset = r->offset;
 	reloc->or = r->or;
 	reloc->shift = r->shift;
-	reloc->submit_offset = offset_bytes(ring->cur, ring->start);
+	reloc->submit_offset = offset_bytes(ring->cur, ring->start) +
+			to_msm_ringbuffer(ring)->offset;
 
 	addr = msm_bo->presumed;
 	if (reloc->shift < 0)
@@ -496,15 +585,21 @@
 	if (ring->pipe->gpu_id >= 500) {
 		struct drm_msm_gem_submit_reloc *reloc_hi;
 
+		/* NOTE: grab reloc_idx *before* APPEND() since that could
+		 * realloc() meaning that 'reloc' ptr is no longer valid:
+		 */
+		uint32_t reloc_idx = reloc->reloc_idx;
+
 		idx = APPEND(cmd, relocs);
 
 		reloc_hi = &cmd->relocs[idx];
 
-		reloc_hi->reloc_idx = reloc->reloc_idx;
+		reloc_hi->reloc_idx = reloc_idx;
 		reloc_hi->reloc_offset = r->offset;
 		reloc_hi->or = r->orhi;
 		reloc_hi->shift = r->shift - 32;
-		reloc_hi->submit_offset = offset_bytes(ring->cur, ring->start);
+		reloc_hi->submit_offset = offset_bytes(ring->cur, ring->start) +
+				to_msm_ringbuffer(ring)->offset;
 
 		addr = msm_bo->presumed >> 32;
 		if (reloc_hi->shift < 0)
@@ -516,13 +611,16 @@
 }
 
 static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-		struct fd_ringbuffer *target, uint32_t cmd_idx,
-		uint32_t submit_offset, uint32_t size)
+		struct fd_ringbuffer *target, uint32_t cmd_idx)
 {
 	struct msm_cmd *cmd = NULL;
+	struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target);
 	uint32_t idx = 0;
+	int added_cmd = FALSE;
+	uint32_t size;
+	uint32_t submit_offset = msm_target->offset;
 
-	LIST_FOR_EACH_ENTRY(cmd, &to_msm_ringbuffer(target)->cmd_list, list) {
+	LIST_FOR_EACH_ENTRY(cmd, &msm_target->cmd_list, list) {
 		if (idx == cmd_idx)
 			break;
 		idx++;
@@ -530,7 +628,7 @@
 
 	assert(cmd && (idx == cmd_idx));
 
-	if (idx < (to_msm_ringbuffer(target)->cmd_count - 1)) {
+	if (idx < (msm_target->cmd_count - 1)) {
 		/* All but the last cmd buffer is fully "baked" (ie. already has
 		 * done get_cmd() to add it to the cmds table).  But in this case,
 		 * the size we get is invalid (since it is calculated from the
@@ -538,7 +636,10 @@
 		 */
 		size = cmd->size;
 	} else {
-		get_cmd(ring, cmd, submit_offset, size, MSM_SUBMIT_CMD_IB_TARGET_BUF);
+		struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring;
+		size = offset_bytes(target->cur, target->start);
+		added_cmd = get_cmd(parent, cmd, submit_offset, size,
+				MSM_SUBMIT_CMD_IB_TARGET_BUF);
 	}
 
 	msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){
@@ -547,6 +648,14 @@
 		.offset = submit_offset,
 	});
 
+	/* Unlike traditional ringbuffers which are deleted as a set (after
+	 * being flushed), mesa can't really guarantee that a stateobj isn't
+	 * destroyed after emitted but before flush, so we must hold a ref:
+	 */
+	if (added_cmd && (target->flags & FD_RINGBUFFER_OBJECT)) {
+		fd_ringbuffer_ref(target);
+	}
+
 	return size;
 }
 
@@ -581,15 +690,15 @@
 };
 
 drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe,
-		uint32_t size)
+		uint32_t size, enum fd_ringbuffer_flags flags)
 {
 	struct msm_ringbuffer *msm_ring;
-	struct fd_ringbuffer *ring = NULL;
+	struct fd_ringbuffer *ring;
 
 	msm_ring = calloc(1, sizeof(*msm_ring));
 	if (!msm_ring) {
 		ERROR_MSG("allocation failed");
-		goto fail;
+		return NULL;
 	}
 
 	if (size == 0) {
@@ -602,15 +711,13 @@
 	msm_ring->seqno = ++to_msm_device(pipe->dev)->ring_cnt;
 
 	ring = &msm_ring->base;
+	atomic_set(&ring->refcnt, 1);
+
 	ring->funcs = &funcs;
 	ring->size = size;
 	ring->pipe = pipe;   /* needed in ring_cmd_new() */
 
-	ring_cmd_new(ring, size);
+	ring_cmd_new(ring, size, flags);
 
 	return ring;
-fail:
-	if (ring)
-		fd_ringbuffer_del(ring);
-	return NULL;
 }
diff --git a/include/drm/README b/include/drm/README
index a50b02c..ea2320c 100644
--- a/include/drm/README
+++ b/include/drm/README
@@ -67,9 +67,11 @@
 
 When and how to update these files
 ----------------------------------
+Note: One should not do _any_ changes to the files apart from the steps below.
+
 In order to update the files do the following:
  - Switch to a Linux kernel tree/branch which is not rebased.
-For example: airlied/drm-next
+   For example: drm-next (https://cgit.freedesktop.org/drm/drm)
  - Install the headers via `make headers_install' to a separate location.
  - Copy the drm header[s] + git add + git commit.
  - Note: Your commit message must include:
@@ -84,47 +86,21 @@
 This section contains a list of headers and the respective "issues" they might
 have relative to their kernel equivalent.
 
-Nearly all headers:
- - Missing extern C notation.
-Status: Trivial.
-
 Most UMS headers:
  - Not using fixed size integers - compat ioctls are broken.
 Status: ?
 Promote to fixed size ints, which match the current (32bit) ones.
 
-
-amdgpu_drm.h
- - Using the stdint.h uint*_t over the respective __u* ones
-Status: Trivial.
-
-drm_mode.h
- - Missing DPI encode/connector pair.
-Status: Trivial.
-
-i915_drm.h
- - Missing PARAMS - HAS_POOLED_EU, MIN_EU_IN_POOL CONTEXT_PARAM_NO_ERROR_CAPTURE
-Status: Trivial.
-
-mga_drm.h
- - Typo fix, use struct over typedef.
-Status: Trivial.
-
 nouveau_drm.h
  - Missing macros NOUVEAU_GETPARAM*, NOUVEAU_DRM_HEADER_PATCHLEVEL, structs,
-enums, using stdint.h over the __u* types.
-Status: ?
-
-qxl_drm.h
- - Using the stdint.h uint*_t over the respective __u* ones
-Status: Trivial.
+enums
+Status: Deliberate UABI choice; nouveau hides the exact kernel ABI behind libdrm
 
 r128_drm.h
  - Broken compat ioctls.
 
 radeon_drm.h
- - Missing RADEON_TILING_R600_NO_SCANOUT, CIK_TILE_MODE_*, broken UMS ioctls,
-using stdint types.
+ - Missing RADEON_TILING_R600_NO_SCANOUT, CIK_TILE_MODE_*, broken UMS ioctls
  - Both kernel and libdrm: missing padding -
 drm_radeon_gem_{create,{g,s}et_tiling,set_domain} others ?
 Status: ?
@@ -146,11 +122,6 @@
  - License mismatch, missing DRM_IOCTL_OMAP_GEM_NEW and related struct
 Status: ?
 
-msm_drm.h (located in $TOP/freedreno/msm/)
- - License mismatch, missing MSM_PIPE_*, MSM_SUBMIT_*. Renamed
-drm_msm_gem_submit::flags, missing drm_msm_gem_submit::fence_fd.
-Status: ?
-
 exynos_drm.h (living in $TOP/exynos)
  - License mismatch, now using fixed size ints (but not everywhere). Lots of
 new stuff.
diff --git a/include/drm/amdgpu_drm.h b/include/drm/amdgpu_drm.h
index d8f2497..be84e43 100644
--- a/include/drm/amdgpu_drm.h
+++ b/include/drm/amdgpu_drm.h
@@ -50,6 +50,10 @@
 #define DRM_AMDGPU_WAIT_CS		0x09
 #define DRM_AMDGPU_GEM_OP		0x10
 #define DRM_AMDGPU_GEM_USERPTR		0x11
+#define DRM_AMDGPU_WAIT_FENCES		0x12
+#define DRM_AMDGPU_VM			0x13
+#define DRM_AMDGPU_FENCE_TO_HANDLE	0x14
+#define DRM_AMDGPU_SCHED		0x15
 
 #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)
@@ -63,13 +67,46 @@
 #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 DRM_IOCTL_AMDGPU_WAIT_FENCES	DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_WAIT_FENCES, union drm_amdgpu_wait_fences)
+#define DRM_IOCTL_AMDGPU_VM		DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_VM, union drm_amdgpu_vm)
+#define DRM_IOCTL_AMDGPU_FENCE_TO_HANDLE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_FENCE_TO_HANDLE, union drm_amdgpu_fence_to_handle)
+#define DRM_IOCTL_AMDGPU_SCHED		DRM_IOW(DRM_COMMAND_BASE + DRM_AMDGPU_SCHED, union drm_amdgpu_sched)
 
+/**
+ * DOC: memory domains
+ *
+ * %AMDGPU_GEM_DOMAIN_CPU	System memory that is not GPU accessible.
+ * Memory in this pool could be swapped out to disk if there is pressure.
+ *
+ * %AMDGPU_GEM_DOMAIN_GTT	GPU accessible system memory, mapped into the
+ * GPU's virtual address space via gart. Gart memory linearizes non-contiguous
+ * pages of system memory, allows GPU access system memory in a linezrized
+ * fashion.
+ *
+ * %AMDGPU_GEM_DOMAIN_VRAM	Local video memory. For APUs, it is memory
+ * carved out by the BIOS.
+ *
+ * %AMDGPU_GEM_DOMAIN_GDS	Global on-chip data storage used to share data
+ * across shader threads.
+ *
+ * %AMDGPU_GEM_DOMAIN_GWS	Global wave sync, used to synchronize the
+ * execution of all the waves on a device.
+ *
+ * %AMDGPU_GEM_DOMAIN_OA	Ordered append, used by 3D or Compute engines
+ * for appending data.
+ */
 #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		(AMDGPU_GEM_DOMAIN_CPU | \
+					 AMDGPU_GEM_DOMAIN_GTT | \
+					 AMDGPU_GEM_DOMAIN_VRAM | \
+					 AMDGPU_GEM_DOMAIN_GDS | \
+					 AMDGPU_GEM_DOMAIN_GWS | \
+					 AMDGPU_GEM_DOMAIN_OA)
 
 /* Flag that CPU access will be required for the case of VRAM domain */
 #define AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED	(1 << 0)
@@ -79,22 +116,34 @@
 #define AMDGPU_GEM_CREATE_CPU_GTT_USWC		(1 << 2)
 /* Flag that the memory should be in VRAM and cleared */
 #define AMDGPU_GEM_CREATE_VRAM_CLEARED		(1 << 3)
+/* Flag that create shadow bo(GTT) while allocating vram bo */
+#define AMDGPU_GEM_CREATE_SHADOW		(1 << 4)
+/* Flag that allocating the BO should use linear VRAM */
+#define AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS	(1 << 5)
+/* Flag that BO is always valid in this VM */
+#define AMDGPU_GEM_CREATE_VM_ALWAYS_VALID	(1 << 6)
+/* Flag that BO sharing will be explicitly synchronized */
+#define AMDGPU_GEM_CREATE_EXPLICIT_SYNC		(1 << 7)
+/* Flag that indicates allocating MQD gart on GFX9, where the mtype
+ * for the second page onward should be set to NC.
+ */
+#define AMDGPU_GEM_CREATE_MQD_GFX9		(1 << 8)
 
 struct drm_amdgpu_gem_create_in  {
 	/** the requested memory size */
-	uint64_t bo_size;
+	__u64 bo_size;
 	/** physical start_addr alignment in bytes for some HW requirements */
-	uint64_t alignment;
+	__u64 alignment;
 	/** the requested memory domains */
-	uint64_t domains;
+	__u64 domains;
 	/** allocation flags */
-	uint64_t domain_flags;
+	__u64 domain_flags;
 };
 
 struct drm_amdgpu_gem_create_out  {
 	/** returned GEM object handle */
-	uint32_t handle;
-	uint32_t _pad;
+	__u32 handle;
+	__u32 _pad;
 };
 
 union drm_amdgpu_gem_create {
@@ -111,28 +160,28 @@
 
 struct drm_amdgpu_bo_list_in {
 	/** Type of operation */
-	uint32_t operation;
+	__u32 operation;
 	/** Handle of list or 0 if we want to create one */
-	uint32_t list_handle;
+	__u32 list_handle;
 	/** Number of BOs in list  */
-	uint32_t bo_number;
+	__u32 bo_number;
 	/** Size of each element describing BO */
-	uint32_t bo_info_size;
+	__u32 bo_info_size;
 	/** Pointer to array describing BOs */
-	uint64_t bo_info_ptr;
+	__u64 bo_info_ptr;
 };
 
 struct drm_amdgpu_bo_list_entry {
 	/** Handle of BO */
-	uint32_t bo_handle;
+	__u32 bo_handle;
 	/** New (if specified) BO priority to be used during migration */
-	uint32_t bo_priority;
+	__u32 bo_priority;
 };
 
 struct drm_amdgpu_bo_list_out {
 	/** Handle of resource list  */
-	uint32_t list_handle;
-	uint32_t _pad;
+	__u32 list_handle;
+	__u32 _pad;
 };
 
 union drm_amdgpu_bo_list {
@@ -144,6 +193,7 @@
 #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_QUERY_STATE2	4
 
 /* GPU reset status */
 #define AMDGPU_CTX_NO_RESET		0
@@ -154,28 +204,44 @@
 /* unknown cause */
 #define AMDGPU_CTX_UNKNOWN_RESET	3
 
+/* indicate gpu reset occured after ctx created */
+#define AMDGPU_CTX_QUERY2_FLAGS_RESET    (1<<0)
+/* indicate vram lost occured after ctx created */
+#define AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST (1<<1)
+/* indicate some job from this context once cause gpu hang */
+#define AMDGPU_CTX_QUERY2_FLAGS_GUILTY   (1<<2)
+
+/* Context priority level */
+#define AMDGPU_CTX_PRIORITY_UNSET       -2048
+#define AMDGPU_CTX_PRIORITY_VERY_LOW    -1023
+#define AMDGPU_CTX_PRIORITY_LOW         -512
+#define AMDGPU_CTX_PRIORITY_NORMAL      0
+/* Selecting a priority above NORMAL requires CAP_SYS_NICE or DRM_MASTER */
+#define AMDGPU_CTX_PRIORITY_HIGH        512
+#define AMDGPU_CTX_PRIORITY_VERY_HIGH   1023
+
 struct drm_amdgpu_ctx_in {
 	/** AMDGPU_CTX_OP_* */
-	uint32_t	op;
+	__u32	op;
 	/** For future use, no flags defined so far */
-	uint32_t	flags;
-	uint32_t	ctx_id;
-	uint32_t	_pad;
+	__u32	flags;
+	__u32	ctx_id;
+	__s32	priority;
 };
 
 union drm_amdgpu_ctx_out {
 		struct {
-			uint32_t	ctx_id;
-			uint32_t	_pad;
+			__u32	ctx_id;
+			__u32	_pad;
 		} alloc;
 
 		struct {
 			/** For future use, no flags defined so far */
-			uint64_t	flags;
+			__u64	flags;
 			/** Number of resets caused by this context so far. */
-			uint32_t	hangs;
+			__u32	hangs;
 			/** Reset status since the last call of the ioctl. */
-			uint32_t	reset_status;
+			__u32	reset_status;
 		} state;
 };
 
@@ -184,6 +250,41 @@
 	union drm_amdgpu_ctx_out out;
 };
 
+/* vm ioctl */
+#define AMDGPU_VM_OP_RESERVE_VMID	1
+#define AMDGPU_VM_OP_UNRESERVE_VMID	2
+
+struct drm_amdgpu_vm_in {
+	/** AMDGPU_VM_OP_* */
+	__u32	op;
+	__u32	flags;
+};
+
+struct drm_amdgpu_vm_out {
+	/** For future use, no flags defined so far */
+	__u64	flags;
+};
+
+union drm_amdgpu_vm {
+	struct drm_amdgpu_vm_in in;
+	struct drm_amdgpu_vm_out out;
+};
+
+/* sched ioctl */
+#define AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE	1
+
+struct drm_amdgpu_sched_in {
+	/* AMDGPU_SCHED_OP_* */
+	__u32	op;
+	__u32	fd;
+	__s32	priority;
+	__u32	flags;
+};
+
+union drm_amdgpu_sched {
+	struct drm_amdgpu_sched_in in;
+};
+
 /*
  * 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
@@ -195,14 +296,15 @@
 #define AMDGPU_GEM_USERPTR_REGISTER	(1 << 3)
 
 struct drm_amdgpu_gem_userptr {
-	uint64_t		addr;
-	uint64_t		size;
+	__u64		addr;
+	__u64		size;
 	/* AMDGPU_GEM_USERPTR_* */
-	uint32_t		flags;
+	__u32		flags;
 	/* Resulting GEM handle */
-	uint32_t		handle;
+	__u32		handle;
 };
 
+/* SI-CI-VI: */
 /* same meaning as the GB_TILE_MODE and GL_MACRO_TILE_MODE fields */
 #define AMDGPU_TILING_ARRAY_MODE_SHIFT			0
 #define AMDGPU_TILING_ARRAY_MODE_MASK			0xf
@@ -221,10 +323,21 @@
 #define AMDGPU_TILING_NUM_BANKS_SHIFT			21
 #define AMDGPU_TILING_NUM_BANKS_MASK			0x3
 
+/* GFX9 and later: */
+#define AMDGPU_TILING_SWIZZLE_MODE_SHIFT		0
+#define AMDGPU_TILING_SWIZZLE_MODE_MASK			0x1f
+#define AMDGPU_TILING_DCC_OFFSET_256B_SHIFT		5
+#define AMDGPU_TILING_DCC_OFFSET_256B_MASK		0xFFFFFF
+#define AMDGPU_TILING_DCC_PITCH_MAX_SHIFT		29
+#define AMDGPU_TILING_DCC_PITCH_MAX_MASK		0x3FFF
+#define AMDGPU_TILING_DCC_INDEPENDENT_64B_SHIFT		43
+#define AMDGPU_TILING_DCC_INDEPENDENT_64B_MASK		0x1
+
+/* Set/Get helpers for tiling flags. */
 #define AMDGPU_TILING_SET(field, value) \
-	(((value) & AMDGPU_TILING_##field##_MASK) << AMDGPU_TILING_##field##_SHIFT)
+	(((__u64)(value) & AMDGPU_TILING_##field##_MASK) << AMDGPU_TILING_##field##_SHIFT)
 #define AMDGPU_TILING_GET(value, field) \
-	(((value) >> AMDGPU_TILING_##field##_SHIFT) & AMDGPU_TILING_##field##_MASK)
+	(((__u64)(value) >> AMDGPU_TILING_##field##_SHIFT) & AMDGPU_TILING_##field##_MASK)
 
 #define AMDGPU_GEM_METADATA_OP_SET_METADATA                  1
 #define AMDGPU_GEM_METADATA_OP_GET_METADATA                  2
@@ -232,28 +345,28 @@
 /** The same structure is shared for input/output */
 struct drm_amdgpu_gem_metadata {
 	/** GEM Object handle */
-	uint32_t	handle;
+	__u32	handle;
 	/** Do we want get or set metadata */
-	uint32_t	op;
+	__u32	op;
 	struct {
 		/** For future use, no flags defined so far */
-		uint64_t	flags;
+		__u64	flags;
 		/** family specific tiling info */
-		uint64_t	tiling_info;
-		uint32_t	data_size_bytes;
-		uint32_t	data[64];
+		__u64	tiling_info;
+		__u32	data_size_bytes;
+		__u32	data[64];
 	} data;
 };
 
 struct drm_amdgpu_gem_mmap_in {
 	/** the GEM object handle */
-	uint32_t handle;
-	uint32_t _pad;
+	__u32 handle;
+	__u32 _pad;
 };
 
 struct drm_amdgpu_gem_mmap_out {
 	/** mmap offset from the vma offset manager */
-	uint64_t addr_ptr;
+	__u64 addr_ptr;
 };
 
 union drm_amdgpu_gem_mmap {
@@ -263,18 +376,18 @@
 
 struct drm_amdgpu_gem_wait_idle_in {
 	/** GEM object handle */
-	uint32_t handle;
+	__u32 handle;
 	/** For future use, no flags defined so far */
-	uint32_t flags;
+	__u32 flags;
 	/** Absolute timeout to wait */
-	uint64_t timeout;
+	__u64 timeout;
 };
 
 struct drm_amdgpu_gem_wait_idle_out {
 	/** BO status:  0 - BO is idle, 1 - BO is busy */
-	uint32_t status;
+	__u32 status;
 	/** Returned current memory domain */
-	uint32_t domain;
+	__u32 domain;
 };
 
 union drm_amdgpu_gem_wait_idle {
@@ -283,19 +396,22 @@
 };
 
 struct drm_amdgpu_wait_cs_in {
-	/** Command submission handle */
-	uint64_t handle;
+	/* Command submission handle
+         * handle equals 0 means none to wait for
+         * handle equals ~0ull means wait for the latest sequence number
+         */
+	__u64 handle;
 	/** Absolute timeout to wait */
-	uint64_t timeout;
-	uint32_t ip_type;
-	uint32_t ip_instance;
-	uint32_t ring;
-	uint32_t ctx_id;
+	__u64 timeout;
+	__u32 ip_type;
+	__u32 ip_instance;
+	__u32 ring;
+	__u32 ctx_id;
 };
 
 struct drm_amdgpu_wait_cs_out {
 	/** CS status:  0 - CS completed, 1 - CS still busy */
-	uint64_t status;
+	__u64 status;
 };
 
 union drm_amdgpu_wait_cs {
@@ -303,21 +419,49 @@
 	struct drm_amdgpu_wait_cs_out out;
 };
 
+struct drm_amdgpu_fence {
+	__u32 ctx_id;
+	__u32 ip_type;
+	__u32 ip_instance;
+	__u32 ring;
+	__u64 seq_no;
+};
+
+struct drm_amdgpu_wait_fences_in {
+	/** This points to uint64_t * which points to fences */
+	__u64 fences;
+	__u32 fence_count;
+	__u32 wait_all;
+	__u64 timeout_ns;
+};
+
+struct drm_amdgpu_wait_fences_out {
+	__u32 status;
+	__u32 first_signaled;
+};
+
+union drm_amdgpu_wait_fences {
+	struct drm_amdgpu_wait_fences_in in;
+	struct drm_amdgpu_wait_fences_out out;
+};
+
 #define AMDGPU_GEM_OP_GET_GEM_CREATE_INFO	0
 #define AMDGPU_GEM_OP_SET_PLACEMENT		1
 
 /* Sets or returns a value associated with a buffer. */
 struct drm_amdgpu_gem_op {
 	/** GEM object handle */
-	uint32_t	handle;
+	__u32	handle;
 	/** AMDGPU_GEM_OP_* */
-	uint32_t	op;
+	__u32	op;
 	/** Input or return value */
-	uint64_t	value;
+	__u64	value;
 };
 
 #define AMDGPU_VA_OP_MAP			1
 #define AMDGPU_VA_OP_UNMAP			2
+#define AMDGPU_VA_OP_CLEAR			3
+#define AMDGPU_VA_OP_REPLACE			4
 
 /* Delay the page table update till the next CS */
 #define AMDGPU_VM_DELAY_UPDATE		(1 << 0)
@@ -329,21 +473,35 @@
 #define AMDGPU_VM_PAGE_WRITEABLE	(1 << 2)
 /* executable mapping, new for VI */
 #define AMDGPU_VM_PAGE_EXECUTABLE	(1 << 3)
+/* partially resident texture */
+#define AMDGPU_VM_PAGE_PRT		(1 << 4)
+/* MTYPE flags use bit 5 to 8 */
+#define AMDGPU_VM_MTYPE_MASK		(0xf << 5)
+/* Default MTYPE. Pre-AI must use this.  Recommended for newer ASICs. */
+#define AMDGPU_VM_MTYPE_DEFAULT		(0 << 5)
+/* Use NC MTYPE instead of default MTYPE */
+#define AMDGPU_VM_MTYPE_NC		(1 << 5)
+/* Use WC MTYPE instead of default MTYPE */
+#define AMDGPU_VM_MTYPE_WC		(2 << 5)
+/* Use CC MTYPE instead of default MTYPE */
+#define AMDGPU_VM_MTYPE_CC		(3 << 5)
+/* Use UC MTYPE instead of default MTYPE */
+#define AMDGPU_VM_MTYPE_UC		(4 << 5)
 
 struct drm_amdgpu_gem_va {
 	/** GEM object handle */
-	uint32_t handle;
-	uint32_t _pad;
+	__u32 handle;
+	__u32 _pad;
 	/** AMDGPU_VA_OP_* */
-	uint32_t operation;
+	__u32 operation;
 	/** AMDGPU_VM_PAGE_* */
-	uint32_t flags;
+	__u32 flags;
 	/** va address to assign . Must be correctly aligned.*/
-	uint64_t va_address;
+	__u64 va_address;
 	/** Specify offset inside of BO to assign. Must be correctly aligned.*/
-	uint64_t offset_in_bo;
+	__u64 offset_in_bo;
 	/** Specify mapping size. Must be correctly aligned. */
-	uint64_t map_size;
+	__u64 map_size;
 };
 
 #define AMDGPU_HW_IP_GFX          0
@@ -351,33 +509,40 @@
 #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_UVD_ENC      5
+#define AMDGPU_HW_IP_VCN_DEC      6
+#define AMDGPU_HW_IP_VCN_ENC      7
+#define AMDGPU_HW_IP_VCN_JPEG     8
+#define AMDGPU_HW_IP_NUM          9
 
 #define AMDGPU_HW_IP_INSTANCE_MAX_COUNT 1
 
 #define AMDGPU_CHUNK_ID_IB		0x01
 #define AMDGPU_CHUNK_ID_FENCE		0x02
 #define AMDGPU_CHUNK_ID_DEPENDENCIES	0x03
+#define AMDGPU_CHUNK_ID_SYNCOBJ_IN      0x04
+#define AMDGPU_CHUNK_ID_SYNCOBJ_OUT     0x05
+#define AMDGPU_CHUNK_ID_BO_HANDLES      0x06
 
 struct drm_amdgpu_cs_chunk {
-	uint32_t		chunk_id;
-	uint32_t		length_dw;
-	uint64_t		chunk_data;
+	__u32		chunk_id;
+	__u32		length_dw;
+	__u64		chunk_data;
 };
 
 struct drm_amdgpu_cs_in {
 	/** Rendering context id */
-	uint32_t		ctx_id;
+	__u32		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;
+	__u32		bo_list_handle;
+	__u32		num_chunks;
+	__u32		_pad;
+	/** this points to __u64 * which point to cs chunks */
+	__u64		chunks;
 };
 
 struct drm_amdgpu_cs_out {
-	uint64_t handle;
+	__u64 handle;
 };
 
 union drm_amdgpu_cs {
@@ -390,36 +555,62 @@
 /* This IB should be submitted to CE */
 #define AMDGPU_IB_FLAG_CE	(1<<0)
 
-/* CE Preamble */
+/* Preamble flag, which means the IB could be dropped if no context switch */
 #define AMDGPU_IB_FLAG_PREAMBLE (1<<1)
 
+/* Preempt flag, IB should set Pre_enb bit if PREEMPT flag detected */
+#define AMDGPU_IB_FLAG_PREEMPT (1<<2)
+
+/* The IB fence should do the L2 writeback but not invalidate any shader
+ * caches (L2/vL1/sL1/I$). */
+#define AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE (1 << 3)
+
 struct drm_amdgpu_cs_chunk_ib {
-	uint32_t _pad;
+	__u32 _pad;
 	/** AMDGPU_IB_FLAG_* */
-	uint32_t flags;
+	__u32 flags;
 	/** Virtual address to begin IB execution */
-	uint64_t va_start;
+	__u64 va_start;
 	/** Size of submission */
-	uint32_t ib_bytes;
+	__u32 ib_bytes;
 	/** HW IP to submit to */
-	uint32_t ip_type;
+	__u32 ip_type;
 	/** HW IP index of the same type to submit to  */
-	uint32_t ip_instance;
+	__u32 ip_instance;
 	/** Ring index to submit to */
-	uint32_t ring;
+	__u32 ring;
 };
 
 struct drm_amdgpu_cs_chunk_dep {
-	uint32_t ip_type;
-	uint32_t ip_instance;
-	uint32_t ring;
-	uint32_t ctx_id;
-	uint64_t handle;
+	__u32 ip_type;
+	__u32 ip_instance;
+	__u32 ring;
+	__u32 ctx_id;
+	__u64 handle;
 };
 
 struct drm_amdgpu_cs_chunk_fence {
-	uint32_t handle;
-	uint32_t offset;
+	__u32 handle;
+	__u32 offset;
+};
+
+struct drm_amdgpu_cs_chunk_sem {
+	__u32 handle;
+};
+
+#define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ	0
+#define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ_FD	1
+#define AMDGPU_FENCE_TO_HANDLE_GET_SYNC_FILE_FD	2
+
+union drm_amdgpu_fence_to_handle {
+	struct {
+		struct drm_amdgpu_fence fence;
+		__u32 what;
+		__u32 pad;
+	} in;
+	struct {
+		__u32 handle;
+	} out;
 };
 
 struct drm_amdgpu_cs_chunk_data {
@@ -434,6 +625,7 @@
  *
  */
 #define AMDGPU_IDS_FLAGS_FUSION         0x1
+#define AMDGPU_IDS_FLAGS_PREEMPTION     0x2
 
 /* indicate if acceleration can be working */
 #define AMDGPU_INFO_ACCEL_WORKING		0x00
@@ -467,6 +659,20 @@
 	#define AMDGPU_INFO_FW_SMC		0x0a
 	/* Subquery id: Query SDMA firmware version */
 	#define AMDGPU_INFO_FW_SDMA		0x0b
+	/* Subquery id: Query PSP SOS firmware version */
+	#define AMDGPU_INFO_FW_SOS		0x0c
+	/* Subquery id: Query PSP ASD firmware version */
+	#define AMDGPU_INFO_FW_ASD		0x0d
+	/* Subquery id: Query VCN firmware version */
+	#define AMDGPU_INFO_FW_VCN		0x0e
+	/* Subquery id: Query GFX RLC SRLC firmware version */
+	#define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_CNTL 0x0f
+	/* Subquery id: Query GFX RLC SRLG firmware version */
+	#define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_GPM_MEM 0x10
+	/* Subquery id: Query GFX RLC SRLS firmware version */
+	#define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_SRM_MEM 0x11
+	/* Subquery id: Query DMCU firmware version */
+	#define AMDGPU_INFO_FW_DMCU		0x12
 /* number of bytes moved for TTM migration */
 #define AMDGPU_INFO_NUM_BYTES_MOVED		0x0f
 /* the used VRAM size */
@@ -483,6 +689,43 @@
 #define AMDGPU_INFO_DEV_INFO			0x16
 /* visible vram usage */
 #define AMDGPU_INFO_VIS_VRAM_USAGE		0x17
+/* number of TTM buffer evictions */
+#define AMDGPU_INFO_NUM_EVICTIONS		0x18
+/* Query memory about VRAM and GTT domains */
+#define AMDGPU_INFO_MEMORY			0x19
+/* Query vce clock table */
+#define AMDGPU_INFO_VCE_CLOCK_TABLE		0x1A
+/* Query vbios related information */
+#define AMDGPU_INFO_VBIOS			0x1B
+	/* Subquery id: Query vbios size */
+	#define AMDGPU_INFO_VBIOS_SIZE		0x1
+	/* Subquery id: Query vbios image */
+	#define AMDGPU_INFO_VBIOS_IMAGE		0x2
+/* Query UVD handles */
+#define AMDGPU_INFO_NUM_HANDLES			0x1C
+/* Query sensor related information */
+#define AMDGPU_INFO_SENSOR			0x1D
+	/* Subquery id: Query GPU shader clock */
+	#define AMDGPU_INFO_SENSOR_GFX_SCLK		0x1
+	/* Subquery id: Query GPU memory clock */
+	#define AMDGPU_INFO_SENSOR_GFX_MCLK		0x2
+	/* Subquery id: Query GPU temperature */
+	#define AMDGPU_INFO_SENSOR_GPU_TEMP		0x3
+	/* Subquery id: Query GPU load */
+	#define AMDGPU_INFO_SENSOR_GPU_LOAD		0x4
+	/* Subquery id: Query average GPU power	*/
+	#define AMDGPU_INFO_SENSOR_GPU_AVG_POWER	0x5
+	/* Subquery id: Query northbridge voltage */
+	#define AMDGPU_INFO_SENSOR_VDDNB		0x6
+	/* Subquery id: Query graphics voltage */
+	#define AMDGPU_INFO_SENSOR_VDDGFX		0x7
+	/* Subquery id: Query GPU stable pstate shader clock */
+	#define AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_SCLK		0x8
+	/* Subquery id: Query GPU stable pstate memory clock */
+	#define AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_MCLK		0x9
+/* Number of VRAM page faults on CPU access. */
+#define AMDGPU_INFO_NUM_VRAM_CPU_PAGE_FAULTS	0x1E
+#define AMDGPU_INFO_VRAM_LOST_COUNTER		0x1F
 
 #define AMDGPU_INFO_MMR_SE_INDEX_SHIFT	0
 #define AMDGPU_INFO_MMR_SE_INDEX_MASK	0xff
@@ -491,86 +734,123 @@
 
 struct drm_amdgpu_query_fw {
 	/** AMDGPU_INFO_FW_* */
-	uint32_t fw_type;
+	__u32 fw_type;
 	/**
 	 * Index of the IP if there are more IPs of
 	 * the same type.
 	 */
-	uint32_t ip_instance;
+	__u32 ip_instance;
 	/**
 	 * Index of the engine. Whether this is used depends
 	 * on the firmware type. (e.g. MEC, SDMA)
 	 */
-	uint32_t index;
-	uint32_t _pad;
+	__u32 index;
+	__u32 _pad;
 };
 
 /* Input structure for the INFO ioctl */
 struct drm_amdgpu_info {
 	/* Where the return value will be stored */
-	uint64_t return_pointer;
+	__u64 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;
+	__u32 return_size;
 	/* The query request id. */
-	uint32_t query;
+	__u32 query;
 
 	union {
 		struct {
-			uint32_t id;
-			uint32_t _pad;
+			__u32 id;
+			__u32 _pad;
 		} mode_crtc;
 
 		struct {
 			/** AMDGPU_HW_IP_* */
-			uint32_t type;
+			__u32 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;
+			__u32 ip_instance;
 		} query_hw_ip;
 
 		struct {
-			uint32_t dword_offset;
+			__u32 dword_offset;
 			/** number of registers to read */
-			uint32_t count;
-			uint32_t instance;
+			__u32 count;
+			__u32 instance;
 			/** For future use, no flags defined so far */
-			uint32_t flags;
+			__u32 flags;
 		} read_mmr_reg;
 
 		struct drm_amdgpu_query_fw query_fw;
+
+		struct {
+			__u32 type;
+			__u32 offset;
+		} vbios_info;
+
+		struct {
+			__u32 type;
+		} sensor_info;
 	};
 };
 
 struct drm_amdgpu_info_gds {
 	/** GDS GFX partition size */
-	uint32_t gds_gfx_partition_size;
+	__u32 gds_gfx_partition_size;
 	/** GDS compute partition size */
-	uint32_t compute_partition_size;
+	__u32 compute_partition_size;
 	/** total GDS memory size */
-	uint32_t gds_total_size;
+	__u32 gds_total_size;
 	/** GWS size per GFX partition */
-	uint32_t gws_per_gfx_partition;
+	__u32 gws_per_gfx_partition;
 	/** GSW size per compute partition */
-	uint32_t gws_per_compute_partition;
+	__u32 gws_per_compute_partition;
 	/** OA size per GFX partition */
-	uint32_t oa_per_gfx_partition;
+	__u32 oa_per_gfx_partition;
 	/** OA size per compute partition */
-	uint32_t oa_per_compute_partition;
-	uint32_t _pad;
+	__u32 oa_per_compute_partition;
+	__u32 _pad;
 };
 
 struct drm_amdgpu_info_vram_gtt {
-	uint64_t vram_size;
-	uint64_t vram_cpu_accessible_size;
-	uint64_t gtt_size;
+	__u64 vram_size;
+	__u64 vram_cpu_accessible_size;
+	__u64 gtt_size;
+};
+
+struct drm_amdgpu_heap_info {
+	/** max. physical memory */
+	__u64 total_heap_size;
+
+	/** Theoretical max. available memory in the given heap */
+	__u64 usable_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.
+	 */
+	__u64 heap_usage;
+
+	/**
+	 * Theoretical possible max. size of buffer which
+	 * could be allocated in the given heap
+	 */
+	__u64 max_allocation;
+};
+
+struct drm_amdgpu_memory_info {
+	struct drm_amdgpu_heap_info vram;
+	struct drm_amdgpu_heap_info cpu_accessible_vram;
+	struct drm_amdgpu_heap_info gtt;
 };
 
 struct drm_amdgpu_info_firmware {
-	uint32_t ver;
-	uint32_t feature;
+	__u32 ver;
+	__u32 feature;
 };
 
 #define AMDGPU_VRAM_TYPE_UNKNOWN 0
@@ -581,74 +861,139 @@
 #define AMDGPU_VRAM_TYPE_GDDR5 5
 #define AMDGPU_VRAM_TYPE_HBM   6
 #define AMDGPU_VRAM_TYPE_DDR3  7
+#define AMDGPU_VRAM_TYPE_DDR4  8
 
 struct drm_amdgpu_info_device {
 	/** PCI Device ID */
-	uint32_t device_id;
+	__u32 device_id;
 	/** Internal chip revision: A0, A1, etc.) */
-	uint32_t chip_rev;
-	uint32_t external_rev;
+	__u32 chip_rev;
+	__u32 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;
+	__u32 pci_rev;
+	__u32 family;
+	__u32 num_shader_engines;
+	__u32 num_shader_arrays_per_engine;
 	/* in KHz */
-	uint32_t gpu_counter_freq;
-	uint64_t max_engine_clock;
-	uint64_t max_memory_clock;
+	__u32 gpu_counter_freq;
+	__u64 max_engine_clock;
+	__u64 max_memory_clock;
 	/* cu information */
-	uint32_t cu_active_number;
-	uint32_t cu_ao_mask;
-	uint32_t cu_bitmap[4][4];
+	__u32 cu_active_number;
+	/* NOTE: cu_ao_mask is INVALID, DON'T use it */
+	__u32 cu_ao_mask;
+	__u32 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;
+	__u32 enabled_rb_pipes_mask;
+	__u32 num_rb_pipes;
+	__u32 num_hw_gfx_contexts;
+	__u32 _pad;
+	__u64 ids_flags;
 	/** Starting virtual address for UMDs. */
-	uint64_t virtual_address_offset;
+	__u64 virtual_address_offset;
 	/** The maximum virtual address */
-	uint64_t virtual_address_max;
+	__u64 virtual_address_max;
 	/** Required alignment of virtual addresses. */
-	uint32_t virtual_address_alignment;
+	__u32 virtual_address_alignment;
 	/** Page table entry - fragment size */
-	uint32_t pte_fragment_size;
-	uint32_t gart_page_size;
+	__u32 pte_fragment_size;
+	__u32 gart_page_size;
 	/** constant engine ram size*/
-	uint32_t ce_ram_size;
+	__u32 ce_ram_size;
 	/** video memory type info*/
-	uint32_t vram_type;
+	__u32 vram_type;
 	/** video memory bit width*/
-	uint32_t vram_bit_width;
+	__u32 vram_bit_width;
 	/* vce harvesting instance */
-	uint32_t vce_harvest_config;
+	__u32 vce_harvest_config;
+	/* gfx double offchip LDS buffers */
+	__u32 gc_double_offchip_lds_buf;
+	/* NGG Primitive Buffer */
+	__u64 prim_buf_gpu_addr;
+	/* NGG Position Buffer */
+	__u64 pos_buf_gpu_addr;
+	/* NGG Control Sideband */
+	__u64 cntl_sb_buf_gpu_addr;
+	/* NGG Parameter Cache */
+	__u64 param_buf_gpu_addr;
+	__u32 prim_buf_size;
+	__u32 pos_buf_size;
+	__u32 cntl_sb_buf_size;
+	__u32 param_buf_size;
+	/* wavefront size*/
+	__u32 wave_front_size;
+	/* shader visible vgprs*/
+	__u32 num_shader_visible_vgprs;
+	/* CU per shader array*/
+	__u32 num_cu_per_sh;
+	/* number of tcc blocks*/
+	__u32 num_tcc_blocks;
+	/* gs vgt table depth*/
+	__u32 gs_vgt_table_depth;
+	/* gs primitive buffer depth*/
+	__u32 gs_prim_buffer_depth;
+	/* max gs wavefront per vgt*/
+	__u32 max_gs_waves_per_vgt;
+	__u32 _pad1;
+	/* always on cu bitmap */
+	__u32 cu_ao_bitmap[4][4];
+	/** Starting high virtual address for UMDs. */
+	__u64 high_va_offset;
+	/** The maximum high virtual address */
+	__u64 high_va_max;
 };
 
 struct drm_amdgpu_info_hw_ip {
 	/** Version of h/w IP */
-	uint32_t  hw_ip_version_major;
-	uint32_t  hw_ip_version_minor;
+	__u32  hw_ip_version_major;
+	__u32  hw_ip_version_minor;
 	/** Capabilities */
-	uint64_t  capabilities_flags;
+	__u64  capabilities_flags;
 	/** command buffer address start alignment*/
-	uint32_t  ib_start_alignment;
+	__u32  ib_start_alignment;
 	/** command buffer size alignment*/
-	uint32_t  ib_size_alignment;
+	__u32  ib_size_alignment;
 	/** Bitmask of available rings. Bit 0 means ring 0, etc. */
-	uint32_t  available_rings;
-	uint32_t  _pad;
+	__u32  available_rings;
+	__u32  _pad;
+};
+
+struct drm_amdgpu_info_num_handles {
+	/** Max handles as supported by firmware for UVD */
+	__u32  uvd_max_handles;
+	/** Handles currently in use for UVD */
+	__u32  uvd_used_handles;
+};
+
+#define AMDGPU_VCE_CLOCK_TABLE_ENTRIES		6
+
+struct drm_amdgpu_info_vce_clock_table_entry {
+	/** System clock */
+	__u32 sclk;
+	/** Memory clock */
+	__u32 mclk;
+	/** VCE clock */
+	__u32 eclk;
+	__u32 pad;
+};
+
+struct drm_amdgpu_info_vce_clock_table {
+	struct drm_amdgpu_info_vce_clock_table_entry entries[AMDGPU_VCE_CLOCK_TABLE_ENTRIES];
+	__u32 num_valid_entries;
+	__u32 pad;
 };
 
 /*
  * Supported GPU families
  */
 #define AMDGPU_FAMILY_UNKNOWN			0
+#define AMDGPU_FAMILY_SI			110 /* Hainan, Oland, Verde, Pitcairn, Tahiti */
 #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, Stoney */
+#define AMDGPU_FAMILY_AI			141 /* Vega10 */
+#define AMDGPU_FAMILY_RV			142 /* Raven */
 
 #if defined(__cplusplus)
 }
diff --git a/include/drm/drm.h b/include/drm/drm.h
index f6fd5c2..85c685a 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -641,6 +641,8 @@
 #define DRM_CAP_CURSOR_HEIGHT		0x9
 #define DRM_CAP_ADDFB2_MODIFIERS	0x10
 #define DRM_CAP_PAGE_FLIP_TARGET	0x11
+#define DRM_CAP_CRTC_IN_VBLANK_EVENT	0x12
+#define DRM_CAP_SYNCOBJ		0x13
 
 /** DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {
@@ -672,6 +674,22 @@
  */
 #define DRM_CLIENT_CAP_ATOMIC	3
 
+/**
+ * DRM_CLIENT_CAP_ASPECT_RATIO
+ *
+ * If set to 1, the DRM core will provide aspect ratio information in modes.
+ */
+#define DRM_CLIENT_CAP_ASPECT_RATIO    4
+
+/**
+ * DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
+ *
+ * If set to 1, the DRM core will expose special connectors to be used for
+ * writing back to memory the scene setup in the commit. Depends on client
+ * also supporting DRM_CLIENT_CAP_ATOMIC
+ */
+#define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS	5
+
 /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
 	__u64 capability;
@@ -690,6 +708,67 @@
 	__s32 fd;
 };
 
+struct drm_syncobj_create {
+	__u32 handle;
+#define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+	__u32 flags;
+};
+
+struct drm_syncobj_destroy {
+	__u32 handle;
+	__u32 pad;
+};
+
+#define DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE (1 << 0)
+#define DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE (1 << 0)
+struct drm_syncobj_handle {
+	__u32 handle;
+	__u32 flags;
+
+	__s32 fd;
+	__u32 pad;
+};
+
+#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
+#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
+struct drm_syncobj_wait {
+	__u64 handles;
+	/* absolute timeout */
+	__s64 timeout_nsec;
+	__u32 count_handles;
+	__u32 flags;
+	__u32 first_signaled; /* only valid when not waiting all */
+	__u32 pad;
+};
+
+struct drm_syncobj_array {
+	__u64 handles;
+	__u32 count_handles;
+	__u32 pad;
+};
+
+/* Query current scanout sequence number */
+struct drm_crtc_get_sequence {
+	__u32 crtc_id;		/* requested crtc_id */
+	__u32 active;		/* return: crtc output is active */
+	__u64 sequence;		/* return: most recent vblank sequence */
+	__s64 sequence_ns;	/* return: most recent time of first pixel out */
+};
+
+/* Queue event to be delivered at specified sequence. Time stamp marks
+ * when the first pixel of the refresh cycle leaves the display engine
+ * for the display
+ */
+#define DRM_CRTC_SEQUENCE_RELATIVE		0x00000001	/* sequence is relative to current */
+#define DRM_CRTC_SEQUENCE_NEXT_ON_MISS		0x00000002	/* Use next sequence if we've missed */
+
+struct drm_crtc_queue_sequence {
+	__u32 crtc_id;
+	__u32 flags;
+	__u64 sequence;		/* on input, target sequence. on output, actual sequence */
+	__u64 user_data;	/* user data passed to event */
+};
+
 #if defined(__cplusplus)
 }
 #endif
@@ -772,6 +851,9 @@
 
 #define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, union drm_wait_vblank)
 
+#define DRM_IOCTL_CRTC_GET_SEQUENCE	DRM_IOWR(0x3b, struct drm_crtc_get_sequence)
+#define DRM_IOCTL_CRTC_QUEUE_SEQUENCE	DRM_IOWR(0x3c, struct drm_crtc_queue_sequence)
+
 #define DRM_IOCTL_UPDATE_DRAW		DRM_IOW(0x3f, struct drm_update_draw)
 
 #define DRM_IOCTL_MODE_GETRESOURCES	DRM_IOWR(0xA0, struct drm_mode_card_res)
@@ -808,6 +890,19 @@
 #define DRM_IOCTL_MODE_CREATEPROPBLOB	DRM_IOWR(0xBD, struct drm_mode_create_blob)
 #define DRM_IOCTL_MODE_DESTROYPROPBLOB	DRM_IOWR(0xBE, struct drm_mode_destroy_blob)
 
+#define DRM_IOCTL_SYNCOBJ_CREATE	DRM_IOWR(0xBF, struct drm_syncobj_create)
+#define DRM_IOCTL_SYNCOBJ_DESTROY	DRM_IOWR(0xC0, struct drm_syncobj_destroy)
+#define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD	DRM_IOWR(0xC1, struct drm_syncobj_handle)
+#define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE	DRM_IOWR(0xC2, struct drm_syncobj_handle)
+#define DRM_IOCTL_SYNCOBJ_WAIT		DRM_IOWR(0xC3, struct drm_syncobj_wait)
+#define DRM_IOCTL_SYNCOBJ_RESET		DRM_IOWR(0xC4, struct drm_syncobj_array)
+#define DRM_IOCTL_SYNCOBJ_SIGNAL	DRM_IOWR(0xC5, struct drm_syncobj_array)
+
+#define DRM_IOCTL_MODE_CREATE_LEASE	DRM_IOWR(0xC6, struct drm_mode_create_lease)
+#define DRM_IOCTL_MODE_LIST_LESSEES	DRM_IOWR(0xC7, struct drm_mode_list_lessees)
+#define DRM_IOCTL_MODE_GET_LEASE	DRM_IOWR(0xC8, struct drm_mode_get_lease)
+#define DRM_IOCTL_MODE_REVOKE_LEASE	DRM_IOWR(0xC9, struct drm_mode_revoke_lease)
+
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x9f.
@@ -838,6 +933,7 @@
 
 #define DRM_EVENT_VBLANK 0x01
 #define DRM_EVENT_FLIP_COMPLETE 0x02
+#define DRM_EVENT_CRTC_SEQUENCE	0x03
 
 struct drm_event_vblank {
 	struct drm_event base;
@@ -845,7 +941,17 @@
 	__u32 tv_sec;
 	__u32 tv_usec;
 	__u32 sequence;
-	__u32 reserved;
+	__u32 crtc_id; /* 0 on older kernels that do not support this */
+};
+
+/* Event delivered at sequence. Time stamp marks when the first pixel
+ * of the refresh cycle leaves the display engine for the display
+ */
+struct drm_event_crtc_sequence {
+	struct drm_event	base;
+	__u64			user_data;
+	__s64			time_ns;
+	__u64			sequence;
 };
 
 /* typedef area */
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
index 4d8da69..139632b 100644
--- a/include/drm/drm_fourcc.h
+++ b/include/drm/drm_fourcc.h
@@ -26,21 +26,71 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * DOC: overview
+ *
+ * In the DRM subsystem, framebuffer pixel formats are described using the
+ * fourcc codes defined in `include/uapi/drm/drm_fourcc.h`. In addition to the
+ * fourcc code, a Format Modifier may optionally be provided, in order to
+ * further describe the buffer's format - for example tiling or compression.
+ *
+ * Format Modifiers
+ * ----------------
+ *
+ * Format modifiers are used in conjunction with a fourcc code, forming a
+ * unique fourcc:modifier pair. This format:modifier pair must fully define the
+ * format and data layout of the buffer, and should be the only way to describe
+ * that particular buffer.
+ *
+ * Having multiple fourcc:modifier pairs which describe the same layout should
+ * be avoided, as such aliases run the risk of different drivers exposing
+ * different names for the same data format, forcing userspace to understand
+ * that they are aliases.
+ *
+ * Format modifiers may change any property of the buffer, including the number
+ * of planes and/or the required allocation size. Format modifiers are
+ * vendor-namespaced, and as such the relationship between a fourcc code and a
+ * modifier is specific to the modifer being used. For example, some modifiers
+ * may preserve meaning - such as number of planes - from the fourcc code,
+ * whereas others may not.
+ *
+ * Vendors should document their modifier usage in as much detail as
+ * possible, to ensure maximum compatibility across devices, drivers and
+ * applications.
+ *
+ * The authoritative list of format modifier codes is found in
+ * `include/uapi/drm/drm_fourcc.h`
+ */
+
 #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
 				 ((__u32)(c) << 16) | ((__u32)(d) << 24))
 
 #define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */
 
+/* Reserve 0 for the invalid format specifier */
+#define DRM_FORMAT_INVALID	0
+
 /* color index */
 #define DRM_FORMAT_C8		fourcc_code('C', '8', ' ', ' ') /* [7:0] C */
 
 /* 8 bpp Red */
 #define DRM_FORMAT_R8		fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
 
+/* 16 bpp Red */
+#define DRM_FORMAT_R16		fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
+
 /* 16 bpp RG */
 #define DRM_FORMAT_RG88		fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
 #define DRM_FORMAT_GR88		fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
 
+/* 32 bpp RG */
+#define DRM_FORMAT_RG1616	fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
+#define DRM_FORMAT_GR1616	fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
+
 /* 8 bpp RGB */
 #define DRM_FORMAT_RGB332	fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
 #define DRM_FORMAT_BGR233	fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */
@@ -103,6 +153,20 @@
 #define DRM_FORMAT_AYUV		fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
 
 /*
+ * 2 plane RGB + A
+ * index 0 = RGB plane, same format as the corresponding non _A8 format has
+ * index 1 = A plane, [7:0] A
+ */
+#define DRM_FORMAT_XRGB8888_A8	fourcc_code('X', 'R', 'A', '8')
+#define DRM_FORMAT_XBGR8888_A8	fourcc_code('X', 'B', 'A', '8')
+#define DRM_FORMAT_RGBX8888_A8	fourcc_code('R', 'X', 'A', '8')
+#define DRM_FORMAT_BGRX8888_A8	fourcc_code('B', 'X', 'A', '8')
+#define DRM_FORMAT_RGB888_A8	fourcc_code('R', '8', 'A', '8')
+#define DRM_FORMAT_BGR888_A8	fourcc_code('B', '8', 'A', '8')
+#define DRM_FORMAT_RGB565_A8	fourcc_code('R', '5', 'A', '8')
+#define DRM_FORMAT_BGR565_A8	fourcc_code('B', '5', 'A', '8')
+
+/*
  * 2 plane YCbCr
  * index 0 = Y plane, [7:0] Y
  * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
@@ -150,15 +214,21 @@
 
 /* Vendor Ids: */
 #define DRM_FORMAT_MOD_NONE           0
+#define DRM_FORMAT_MOD_VENDOR_NONE    0
 #define DRM_FORMAT_MOD_VENDOR_INTEL   0x01
 #define DRM_FORMAT_MOD_VENDOR_AMD     0x02
-#define DRM_FORMAT_MOD_VENDOR_NV      0x03
+#define DRM_FORMAT_MOD_VENDOR_NVIDIA  0x03
 #define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04
 #define DRM_FORMAT_MOD_VENDOR_QCOM    0x05
+#define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06
+#define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07
+#define DRM_FORMAT_MOD_VENDOR_ARM     0x08
 /* add more to the end as needed */
 
+#define DRM_FORMAT_RESERVED	      ((1ULL << 56) - 1)
+
 #define fourcc_mod_code(vendor, val) \
-	((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL))
+	((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL))
 
 /*
  * Format Modifier tokens:
@@ -168,6 +238,25 @@
  * authoritative source for all of these.
  */
 
+/*
+ * Invalid Modifier
+ *
+ * This modifier can be used as a sentinel to terminate the format modifiers
+ * list, or to initialize a variable with an invalid modifier. It might also be
+ * used to report an error back to userspace for certain APIs.
+ */
+#define DRM_FORMAT_MOD_INVALID	fourcc_mod_code(NONE, DRM_FORMAT_RESERVED)
+
+/*
+ * Linear Layout
+ *
+ * Just plain linear layout. Note that this is different from no specifying any
+ * modifier (e.g. not setting DRM_MODE_FB_MODIFIERS in the DRM_ADDFB2 ioctl),
+ * which tells the driver to also take driver-internal information into account
+ * and so might actually result in a tiled framebuffer.
+ */
+#define DRM_FORMAT_MOD_LINEAR	fourcc_mod_code(NONE, 0)
+
 /* Intel framebuffer modifiers */
 
 /*
@@ -215,6 +304,26 @@
 #define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3)
 
 /*
+ * Intel color control surface (CCS) for render compression
+ *
+ * The framebuffer format must be one of the 8:8:8:8 RGB formats.
+ * The main surface will be plane index 0 and must be Y/Yf-tiled,
+ * the CCS will be plane index 1.
+ *
+ * Each CCS tile matches a 1024x512 pixel area of the main surface.
+ * To match certain aspects of the 3D hardware the CCS is
+ * considered to be made up of normal 128Bx32 Y tiles, Thus
+ * the CCS pitch must be specified in multiples of 128 bytes.
+ *
+ * In reality the CCS tile appears to be a 64Bx64 Y tile, composed
+ * of QWORD (8 bytes) chunks instead of OWORD (16 bytes) chunks.
+ * But that fact is not relevant unless the memory is accessed
+ * directly.
+ */
+#define I915_FORMAT_MOD_Y_TILED_CCS	fourcc_mod_code(INTEL, 4)
+#define I915_FORMAT_MOD_Yf_TILED_CCS	fourcc_mod_code(INTEL, 5)
+
+/*
  * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks
  *
  * Macroblocks are laid in a Z-shape, and each pixel data is following the
@@ -229,4 +338,290 @@
  */
 #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE	fourcc_mod_code(SAMSUNG, 1)
 
+/*
+ * Qualcomm Compressed Format
+ *
+ * Refers to a compressed variant of the base format that is compressed.
+ * Implementation may be platform and base-format specific.
+ *
+ * Each macrotile consists of m x n (mostly 4 x 4) tiles.
+ * Pixel data pitch/stride is aligned with macrotile width.
+ * Pixel data height is aligned with macrotile height.
+ * Entire pixel data buffer is aligned with 4k(bytes).
+ */
+#define DRM_FORMAT_MOD_QCOM_COMPRESSED	fourcc_mod_code(QCOM, 1)
+
+/* Vivante framebuffer modifiers */
+
+/*
+ * Vivante 4x4 tiling layout
+ *
+ * This is a simple tiled layout using tiles of 4x4 pixels in a row-major
+ * layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_TILED		fourcc_mod_code(VIVANTE, 1)
+
+/*
+ * Vivante 64x64 super-tiling layout
+ *
+ * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile
+ * contains 8x4 groups of 2x4 tiles of 4x4 pixels (like above) each, all in row-
+ * major layout.
+ *
+ * For more information: see
+ * https://github.com/etnaviv/etna_viv/blob/master/doc/hardware.md#texture-tiling
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED	fourcc_mod_code(VIVANTE, 2)
+
+/*
+ * Vivante 4x4 tiling layout for dual-pipe
+ *
+ * Same as the 4x4 tiling layout, except every second 4x4 pixel tile starts at a
+ * different base address. Offsets from the base addresses are therefore halved
+ * compared to the non-split tiled layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED	fourcc_mod_code(VIVANTE, 3)
+
+/*
+ * Vivante 64x64 super-tiling layout for dual-pipe
+ *
+ * Same as the 64x64 super-tiling layout, except every second 4x4 pixel tile
+ * starts at a different base address. Offsets from the base addresses are
+ * therefore halved compared to the non-split super-tiled layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4)
+
+/* NVIDIA frame buffer modifiers */
+
+/*
+ * Tegra Tiled Layout, used by Tegra 2, 3 and 4.
+ *
+ * Pixels are arranged in simple tiles of 16 x 16 bytes.
+ */
+#define DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED fourcc_mod_code(NVIDIA, 1)
+
+/*
+ * 16Bx2 Block Linear layout, used by desktop GPUs, and Tegra K1 and later
+ *
+ * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked
+ * vertically by a power of 2 (1 to 32 GOBs) to form a block.
+ *
+ * Within a GOB, data is ordered as 16B x 2 lines sectors laid in Z-shape.
+ *
+ * Parameter 'v' is the log2 encoding of the number of GOBs stacked vertically.
+ * Valid values are:
+ *
+ * 0 == ONE_GOB
+ * 1 == TWO_GOBS
+ * 2 == FOUR_GOBS
+ * 3 == EIGHT_GOBS
+ * 4 == SIXTEEN_GOBS
+ * 5 == THIRTYTWO_GOBS
+ *
+ * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format
+ * in full detail.
+ */
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(v) \
+	fourcc_mod_code(NVIDIA, 0x10 | ((v) & 0xf))
+
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB \
+	fourcc_mod_code(NVIDIA, 0x10)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB \
+	fourcc_mod_code(NVIDIA, 0x11)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB \
+	fourcc_mod_code(NVIDIA, 0x12)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB \
+	fourcc_mod_code(NVIDIA, 0x13)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB \
+	fourcc_mod_code(NVIDIA, 0x14)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \
+	fourcc_mod_code(NVIDIA, 0x15)
+
+/*
+ * Some Broadcom modifiers take parameters, for example the number of
+ * vertical lines in the image. Reserve the lower 32 bits for modifier
+ * type, and the next 24 bits for parameters. Top 8 bits are the
+ * vendor code.
+ */
+#define __fourcc_mod_broadcom_param_shift 8
+#define __fourcc_mod_broadcom_param_bits 48
+#define fourcc_mod_broadcom_code(val, params) \
+	fourcc_mod_code(BROADCOM, ((((__u64)params) << __fourcc_mod_broadcom_param_shift) | val))
+#define fourcc_mod_broadcom_param(m) \
+	((int)(((m) >> __fourcc_mod_broadcom_param_shift) &	\
+	       ((1ULL << __fourcc_mod_broadcom_param_bits) - 1)))
+#define fourcc_mod_broadcom_mod(m) \
+	((m) & ~(((1ULL << __fourcc_mod_broadcom_param_bits) - 1) <<	\
+		 __fourcc_mod_broadcom_param_shift))
+
+/*
+ * Broadcom VC4 "T" format
+ *
+ * This is the primary layout that the V3D GPU can texture from (it
+ * can't do linear).  The T format has:
+ *
+ * - 64b utiles of pixels in a raster-order grid according to cpp.  It's 4x4
+ *   pixels at 32 bit depth.
+ *
+ * - 1k subtiles made of a 4x4 raster-order grid of 64b utiles (so usually
+ *   16x16 pixels).
+ *
+ * - 4k tiles made of a 2x2 grid of 1k subtiles (so usually 32x32 pixels).  On
+ *   even 4k tile rows, they're arranged as (BL, TL, TR, BR), and on odd rows
+ *   they're (TR, BR, BL, TL), where bottom left is start of memory.
+ *
+ * - an image made of 4k tiles in rows either left-to-right (even rows of 4k
+ *   tiles) or right-to-left (odd rows of 4k tiles).
+ */
+#define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED fourcc_mod_code(BROADCOM, 1)
+
+/*
+ * Broadcom SAND format
+ *
+ * This is the native format that the H.264 codec block uses.  For VC4
+ * HVS, it is only valid for H.264 (NV12/21) and RGBA modes.
+ *
+ * The image can be considered to be split into columns, and the
+ * columns are placed consecutively into memory.  The width of those
+ * columns can be either 32, 64, 128, or 256 pixels, but in practice
+ * only 128 pixel columns are used.
+ *
+ * The pitch between the start of each column is set to optimally
+ * switch between SDRAM banks. This is passed as the number of lines
+ * of column width in the modifier (we can't use the stride value due
+ * to various core checks that look at it , so you should set the
+ * stride to width*cpp).
+ *
+ * Note that the column height for this format modifier is the same
+ * for all of the planes, assuming that each column contains both Y
+ * and UV.  Some SAND-using hardware stores UV in a separate tiled
+ * image from Y to reduce the column height, which is not supported
+ * with these modifiers.
+ */
+
+#define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \
+	fourcc_mod_broadcom_code(2, v)
+#define DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(v) \
+	fourcc_mod_broadcom_code(3, v)
+#define DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(v) \
+	fourcc_mod_broadcom_code(4, v)
+#define DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(v) \
+	fourcc_mod_broadcom_code(5, v)
+
+#define DRM_FORMAT_MOD_BROADCOM_SAND32 \
+	DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(0)
+#define DRM_FORMAT_MOD_BROADCOM_SAND64 \
+	DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(0)
+#define DRM_FORMAT_MOD_BROADCOM_SAND128 \
+	DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(0)
+#define DRM_FORMAT_MOD_BROADCOM_SAND256 \
+	DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0)
+
+/* Broadcom UIF format
+ *
+ * This is the common format for the current Broadcom multimedia
+ * blocks, including V3D 3.x and newer, newer video codecs, and
+ * displays.
+ *
+ * The image consists of utiles (64b blocks), UIF blocks (2x2 utiles),
+ * and macroblocks (4x4 UIF blocks).  Those 4x4 UIF block groups are
+ * stored in columns, with padding between the columns to ensure that
+ * moving from one column to the next doesn't hit the same SDRAM page
+ * bank.
+ *
+ * To calculate the padding, it is assumed that each hardware block
+ * and the software driving it knows the platform's SDRAM page size,
+ * number of banks, and XOR address, and that it's identical between
+ * all blocks using the format.  This tiling modifier will use XOR as
+ * necessary to reduce the padding.  If a hardware block can't do XOR,
+ * the assumption is that a no-XOR tiling modifier will be created.
+ */
+#define DRM_FORMAT_MOD_BROADCOM_UIF fourcc_mod_code(BROADCOM, 6)
+
+/*
+ * Arm Framebuffer Compression (AFBC) modifiers
+ *
+ * AFBC is a proprietary lossless image compression protocol and format.
+ * It provides fine-grained random access and minimizes the amount of data
+ * transferred between IP blocks.
+ *
+ * AFBC has several features which may be supported and/or used, which are
+ * represented using bits in the modifier. Not all combinations are valid,
+ * and different devices or use-cases may support different combinations.
+ */
+#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode)	fourcc_mod_code(ARM, __afbc_mode)
+
+/*
+ * AFBC superblock size
+ *
+ * Indicates the superblock size(s) used for the AFBC buffer. The buffer
+ * size (in pixels) must be aligned to a multiple of the superblock size.
+ * Four lowest significant bits(LSBs) are reserved for block size.
+ */
+#define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK      0xf
+#define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16     (1ULL)
+#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8      (2ULL)
+
+/*
+ * AFBC lossless colorspace transform
+ *
+ * Indicates that the buffer makes use of the AFBC lossless colorspace
+ * transform.
+ */
+#define AFBC_FORMAT_MOD_YTR     (1ULL <<  4)
+
+/*
+ * AFBC block-split
+ *
+ * Indicates that the payload of each superblock is split. The second
+ * half of the payload is positioned at a predefined offset from the start
+ * of the superblock payload.
+ */
+#define AFBC_FORMAT_MOD_SPLIT   (1ULL <<  5)
+
+/*
+ * AFBC sparse layout
+ *
+ * This flag indicates that the payload of each superblock must be stored at a
+ * predefined position relative to the other superblocks in the same AFBC
+ * buffer. This order is the same order used by the header buffer. In this mode
+ * each superblock is given the same amount of space as an uncompressed
+ * superblock of the particular format would require, rounding up to the next
+ * multiple of 128 bytes in size.
+ */
+#define AFBC_FORMAT_MOD_SPARSE  (1ULL <<  6)
+
+/*
+ * AFBC copy-block restrict
+ *
+ * Buffers with this flag must obey the copy-block restriction. The restriction
+ * is such that there are no copy-blocks referring across the border of 8x8
+ * blocks. For the subsampled data the 8x8 limitation is also subsampled.
+ */
+#define AFBC_FORMAT_MOD_CBR     (1ULL <<  7)
+
+/*
+ * AFBC tiled layout
+ *
+ * The tiled layout groups superblocks in 8x8 or 4x4 tiles, where all
+ * superblocks inside a tile are stored together in memory. 8x8 tiles are used
+ * for pixel formats up to and including 32 bpp while 4x4 tiles are used for
+ * larger bpp formats. The order between the tiles is scan line.
+ * When the tiled layout is used, the buffer size (in pixels) must be aligned
+ * to the tile size.
+ */
+#define AFBC_FORMAT_MOD_TILED   (1ULL <<  8)
+
+/*
+ * AFBC solid color blocks
+ *
+ * Indicates that the buffer makes use of solid-color blocks, whereby bandwidth
+ * can be reduced if a whole superblock is a single color.
+ */
+#define AFBC_FORMAT_MOD_SC      (1ULL <<  9)
+
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* DRM_FOURCC_H */
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 6708e2b..d3e0fe3 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -38,16 +38,28 @@
 #define DRM_DISPLAY_MODE_LEN	32
 #define DRM_PROP_NAME_LEN	32
 
-#define DRM_MODE_TYPE_BUILTIN	(1<<0)
-#define DRM_MODE_TYPE_CLOCK_C	((1<<1) | DRM_MODE_TYPE_BUILTIN)
-#define DRM_MODE_TYPE_CRTC_C	((1<<2) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_BUILTIN	(1<<0) /* deprecated */
+#define DRM_MODE_TYPE_CLOCK_C	((1<<1) | DRM_MODE_TYPE_BUILTIN) /* deprecated */
+#define DRM_MODE_TYPE_CRTC_C	((1<<2) | DRM_MODE_TYPE_BUILTIN) /* deprecated */
 #define DRM_MODE_TYPE_PREFERRED	(1<<3)
-#define DRM_MODE_TYPE_DEFAULT	(1<<4)
+#define DRM_MODE_TYPE_DEFAULT	(1<<4) /* deprecated */
 #define DRM_MODE_TYPE_USERDEF	(1<<5)
 #define DRM_MODE_TYPE_DRIVER	(1<<6)
 
+#define DRM_MODE_TYPE_ALL	(DRM_MODE_TYPE_PREFERRED |	\
+				 DRM_MODE_TYPE_USERDEF |	\
+				 DRM_MODE_TYPE_DRIVER)
+
 /* Video mode flags */
-/* bit compatible with the xorg definitions. */
+/* bit compatible with the xrandr RR_ definitions (bits 0-13)
+ *
+ * ABI warning: Existing userspace really expects
+ * the mode flags to match the xrandr definitions. Any
+ * changes that don't match the xrandr definitions will
+ * likely need a new client cap or some other mechanism
+ * to avoid breaking existing userspace. This includes
+ * allocating new flags in the previously unused bits!
+ */
 #define DRM_MODE_FLAG_PHSYNC			(1<<0)
 #define DRM_MODE_FLAG_NHSYNC			(1<<1)
 #define DRM_MODE_FLAG_PVSYNC			(1<<2)
@@ -58,8 +70,8 @@
 #define DRM_MODE_FLAG_PCSYNC			(1<<7)
 #define DRM_MODE_FLAG_NCSYNC			(1<<8)
 #define DRM_MODE_FLAG_HSKEW			(1<<9) /* hskew provided */
-#define DRM_MODE_FLAG_BCAST			(1<<10)
-#define DRM_MODE_FLAG_PIXMUX			(1<<11)
+#define DRM_MODE_FLAG_BCAST			(1<<10) /* deprecated */
+#define DRM_MODE_FLAG_PIXMUX			(1<<11) /* deprecated */
 #define DRM_MODE_FLAG_DBLCLK			(1<<12)
 #define DRM_MODE_FLAG_CLKDIV2			(1<<13)
  /*
@@ -67,7 +79,7 @@
   * (define not exposed to user space).
   */
 #define DRM_MODE_FLAG_3D_MASK			(0x1f<<14)
-#define  DRM_MODE_FLAG_3D_NONE			(0<<14)
+#define  DRM_MODE_FLAG_3D_NONE		(0<<14)
 #define  DRM_MODE_FLAG_3D_FRAME_PACKING		(1<<14)
 #define  DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE	(2<<14)
 #define  DRM_MODE_FLAG_3D_LINE_ALTERNATIVE	(3<<14)
@@ -77,6 +89,46 @@
 #define  DRM_MODE_FLAG_3D_TOP_AND_BOTTOM	(7<<14)
 #define  DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF	(8<<14)
 
+/* Picture aspect ratio options */
+#define DRM_MODE_PICTURE_ASPECT_NONE		0
+#define DRM_MODE_PICTURE_ASPECT_4_3		1
+#define DRM_MODE_PICTURE_ASPECT_16_9		2
+#define DRM_MODE_PICTURE_ASPECT_64_27		3
+#define DRM_MODE_PICTURE_ASPECT_256_135		4
+
+/* Content type options */
+#define DRM_MODE_CONTENT_TYPE_NO_DATA		0
+#define DRM_MODE_CONTENT_TYPE_GRAPHICS		1
+#define DRM_MODE_CONTENT_TYPE_PHOTO		2
+#define DRM_MODE_CONTENT_TYPE_CINEMA		3
+#define DRM_MODE_CONTENT_TYPE_GAME		4
+
+/* Aspect ratio flag bitmask (4 bits 22:19) */
+#define DRM_MODE_FLAG_PIC_AR_MASK		(0x0F<<19)
+#define  DRM_MODE_FLAG_PIC_AR_NONE \
+			(DRM_MODE_PICTURE_ASPECT_NONE<<19)
+#define  DRM_MODE_FLAG_PIC_AR_4_3 \
+			(DRM_MODE_PICTURE_ASPECT_4_3<<19)
+#define  DRM_MODE_FLAG_PIC_AR_16_9 \
+			(DRM_MODE_PICTURE_ASPECT_16_9<<19)
+#define  DRM_MODE_FLAG_PIC_AR_64_27 \
+			(DRM_MODE_PICTURE_ASPECT_64_27<<19)
+#define  DRM_MODE_FLAG_PIC_AR_256_135 \
+			(DRM_MODE_PICTURE_ASPECT_256_135<<19)
+
+#define  DRM_MODE_FLAG_ALL	(DRM_MODE_FLAG_PHSYNC |		\
+				 DRM_MODE_FLAG_NHSYNC |		\
+				 DRM_MODE_FLAG_PVSYNC |		\
+				 DRM_MODE_FLAG_NVSYNC |		\
+				 DRM_MODE_FLAG_INTERLACE |	\
+				 DRM_MODE_FLAG_DBLSCAN |	\
+				 DRM_MODE_FLAG_CSYNC |		\
+				 DRM_MODE_FLAG_PCSYNC |		\
+				 DRM_MODE_FLAG_NCSYNC |		\
+				 DRM_MODE_FLAG_HSKEW |		\
+				 DRM_MODE_FLAG_DBLCLK |		\
+				 DRM_MODE_FLAG_CLKDIV2 |	\
+				 DRM_MODE_FLAG_3D_MASK)
 
 /* DPMS flags */
 /* bit compatible with the xorg definitions. */
@@ -92,11 +144,6 @@
 #define DRM_MODE_SCALE_CENTER		2 /* Centered, no scaling */
 #define DRM_MODE_SCALE_ASPECT		3 /* Full screen, preserve aspect */
 
-/* Picture aspect ratio options */
-#define DRM_MODE_PICTURE_ASPECT_NONE	0
-#define DRM_MODE_PICTURE_ASPECT_4_3	1
-#define DRM_MODE_PICTURE_ASPECT_16_9	2
-
 /* Dithering mode options */
 #define DRM_MODE_DITHERING_OFF	0
 #define DRM_MODE_DITHERING_ON	1
@@ -107,13 +154,61 @@
 #define DRM_MODE_DIRTY_ON       1
 #define DRM_MODE_DIRTY_ANNOTATE 2
 
-/* rotation property bits */
-#define DRM_ROTATE_0	0
-#define DRM_ROTATE_90	1
-#define DRM_ROTATE_180	2
-#define DRM_ROTATE_270	3
-#define DRM_REFLECT_X	4
-#define DRM_REFLECT_Y	5
+/* Link Status options */
+#define DRM_MODE_LINK_STATUS_GOOD	0
+#define DRM_MODE_LINK_STATUS_BAD	1
+
+/*
+ * DRM_MODE_ROTATE_<degrees>
+ *
+ * Signals that a drm plane is been rotated <degrees> degrees in counter
+ * clockwise direction.
+ *
+ * This define is provided as a convenience, looking up the property id
+ * using the name->prop id lookup is the preferred method.
+ */
+#define DRM_MODE_ROTATE_0       (1<<0)
+#define DRM_MODE_ROTATE_90      (1<<1)
+#define DRM_MODE_ROTATE_180     (1<<2)
+#define DRM_MODE_ROTATE_270     (1<<3)
+
+/*
+ * DRM_MODE_ROTATE_MASK
+ *
+ * Bitmask used to look for drm plane rotations.
+ */
+#define DRM_MODE_ROTATE_MASK (\
+		DRM_MODE_ROTATE_0  | \
+		DRM_MODE_ROTATE_90  | \
+		DRM_MODE_ROTATE_180 | \
+		DRM_MODE_ROTATE_270)
+
+/*
+ * DRM_MODE_REFLECT_<axis>
+ *
+ * Signals that the contents of a drm plane is reflected along the <axis> axis,
+ * in the same way as mirroring.
+ * See kerneldoc chapter "Plane Composition Properties" for more details.
+ *
+ * This define is provided as a convenience, looking up the property id
+ * using the name->prop id lookup is the preferred method.
+ */
+#define DRM_MODE_REFLECT_X      (1<<4)
+#define DRM_MODE_REFLECT_Y      (1<<5)
+
+/*
+ * DRM_MODE_REFLECT_MASK
+ *
+ * Bitmask used to look for drm plane reflections.
+ */
+#define DRM_MODE_REFLECT_MASK (\
+		DRM_MODE_REFLECT_X | \
+		DRM_MODE_REFLECT_Y)
+
+/* Content Protection Flags */
+#define DRM_MODE_CONTENT_PROTECTION_UNDESIRED	0
+#define DRM_MODE_CONTENT_PROTECTION_DESIRED     1
+#define DRM_MODE_CONTENT_PROTECTION_ENABLED     2
 
 struct drm_mode_modeinfo {
 	__u32 clock;
@@ -228,14 +323,16 @@
 
 /* This is for connectors with multiple signal types. */
 /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
-#define DRM_MODE_SUBCONNECTOR_Automatic	0
-#define DRM_MODE_SUBCONNECTOR_Unknown	0
-#define DRM_MODE_SUBCONNECTOR_DVID	3
-#define DRM_MODE_SUBCONNECTOR_DVIA	4
-#define DRM_MODE_SUBCONNECTOR_Composite	5
-#define DRM_MODE_SUBCONNECTOR_SVIDEO	6
-#define DRM_MODE_SUBCONNECTOR_Component	8
-#define DRM_MODE_SUBCONNECTOR_SCART	9
+enum drm_mode_subconnector {
+	DRM_MODE_SUBCONNECTOR_Automatic = 0,
+	DRM_MODE_SUBCONNECTOR_Unknown = 0,
+	DRM_MODE_SUBCONNECTOR_DVID = 3,
+	DRM_MODE_SUBCONNECTOR_DVIA = 4,
+	DRM_MODE_SUBCONNECTOR_Composite = 5,
+	DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
+	DRM_MODE_SUBCONNECTOR_Component = 8,
+	DRM_MODE_SUBCONNECTOR_SCART = 9,
+};
 
 #define DRM_MODE_CONNECTOR_Unknown	0
 #define DRM_MODE_CONNECTOR_VGA		1
@@ -255,6 +352,7 @@
 #define DRM_MODE_CONNECTOR_VIRTUAL      15
 #define DRM_MODE_CONNECTOR_DSI		16
 #define DRM_MODE_CONNECTOR_DPI		17
+#define DRM_MODE_CONNECTOR_WRITEBACK	18
 
 struct drm_mode_get_connector {
 
@@ -280,7 +378,7 @@
 	__u32 pad;
 };
 
-#define DRM_MODE_PROP_PENDING	(1<<0)
+#define DRM_MODE_PROP_PENDING	(1<<0) /* deprecated, do not use */
 #define DRM_MODE_PROP_RANGE	(1<<1)
 #define DRM_MODE_PROP_IMMUTABLE	(1<<2)
 #define DRM_MODE_PROP_ENUM	(1<<3) /* enumerated type with text strings */
@@ -400,17 +498,20 @@
 	 * offsets[1].  Note that offsets[0] will generally
 	 * be 0 (but this is not required).
 	 *
-	 * To accommodate tiled, compressed, etc formats, a per-plane
+	 * To accommodate tiled, compressed, etc formats, a
 	 * modifier can be specified.  The default value of zero
 	 * indicates "native" format as specified by the fourcc.
-	 * Vendor specific modifier token.  This allows, for example,
-	 * different tiling/swizzling pattern on different planes.
-	 * See discussion above of DRM_FORMAT_MOD_xxx.
+	 * Vendor specific modifier token.  Note that even though
+	 * it looks like we have a modifier per-plane, we in fact
+	 * do not. The modifier for each plane must be identical.
+	 * Thus all combinations of different data layouts for
+	 * multi plane formats must be enumerated as separate
+	 * modifiers.
 	 */
 	__u32 handles[4];
 	__u32 pitches[4]; /* pitch for each plane */
 	__u32 offsets[4]; /* offset of each plane */
-	__u64 modifier[4]; /* ie, tiling, compressed (per plane) */
+	__u64 modifier[4]; /* ie, tiling, compress */
 };
 
 #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01
@@ -512,8 +613,11 @@
 };
 
 struct drm_color_ctm {
-	/* Conversion matrix in S31.32 format. */
-	__s64 matrix[9];
+	/*
+	 * Conversion matrix in S31.32 sign-magnitude
+	 * (not two's complement!) format.
+	 */
+	__u64 matrix[9];
 };
 
 struct drm_color_lut {
@@ -637,13 +741,6 @@
 		DRM_MODE_ATOMIC_NONBLOCK |\
 		DRM_MODE_ATOMIC_ALLOW_MODESET)
 
-#define DRM_MODE_ATOMIC_FLAGS (\
-		DRM_MODE_PAGE_FLIP_EVENT |\
-		DRM_MODE_PAGE_FLIP_ASYNC |\
-		DRM_MODE_ATOMIC_TEST_ONLY |\
-		DRM_MODE_ATOMIC_NONBLOCK |\
-		DRM_MODE_ATOMIC_ALLOW_MODESET)
-
 struct drm_mode_atomic {
 	__u32 flags;
 	__u32 count_objs;
@@ -655,6 +752,56 @@
 	__u64 user_data;
 };
 
+struct drm_format_modifier_blob {
+#define FORMAT_BLOB_CURRENT 1
+	/* Version of this blob format */
+	__u32 version;
+
+	/* Flags */
+	__u32 flags;
+
+	/* Number of fourcc formats supported */
+	__u32 count_formats;
+
+	/* Where in this blob the formats exist (in bytes) */
+	__u32 formats_offset;
+
+	/* Number of drm_format_modifiers */
+	__u32 count_modifiers;
+
+	/* Where in this blob the modifiers exist (in bytes) */
+	__u32 modifiers_offset;
+
+	/* __u32 formats[] */
+	/* struct drm_format_modifier modifiers[] */
+};
+
+struct drm_format_modifier {
+	/* Bitmask of formats in get_plane format list this info applies to. The
+	 * offset allows a sliding window of which 64 formats (bits).
+	 *
+	 * Some examples:
+	 * In today's world with < 65 formats, and formats 0, and 2 are
+	 * supported
+	 * 0x0000000000000005
+	 *		  ^-offset = 0, formats = 5
+	 *
+	 * If the number formats grew to 128, and formats 98-102 are
+	 * supported with the modifier:
+	 *
+	 * 0x0000007c00000000 0000000000000000
+	 *		  ^
+	 *		  |__offset = 64, formats = 0x7c00000000
+	 *
+	 */
+	__u64 formats;
+	__u32 offset;
+	__u32 pad;
+
+	/* The modifier that applies to the >get_plane format list bitmask. */
+	__u64 modifier;
+};
+
 /**
  * Create a new 'blob' data property, copying length bytes from data pointer,
  * and returning new blob ID.
@@ -675,6 +822,72 @@
 	__u32 blob_id;
 };
 
+/**
+ * Lease mode resources, creating another drm_master.
+ */
+struct drm_mode_create_lease {
+	/** Pointer to array of object ids (__u32) */
+	__u64 object_ids;
+	/** Number of object ids */
+	__u32 object_count;
+	/** flags for new FD (O_CLOEXEC, etc) */
+	__u32 flags;
+
+	/** Return: unique identifier for lessee. */
+	__u32 lessee_id;
+	/** Return: file descriptor to new drm_master file */
+	__u32 fd;
+};
+
+/**
+ * List lesses from a drm_master
+ */
+struct drm_mode_list_lessees {
+	/** Number of lessees.
+	 * On input, provides length of the array.
+	 * On output, provides total number. No
+	 * more than the input number will be written
+	 * back, so two calls can be used to get
+	 * the size and then the data.
+	 */
+	__u32 count_lessees;
+	__u32 pad;
+
+	/** Pointer to lessees.
+	 * pointer to __u64 array of lessee ids
+	 */
+	__u64 lessees_ptr;
+};
+
+/**
+ * Get leased objects
+ */
+struct drm_mode_get_lease {
+	/** Number of leased objects.
+	 * On input, provides length of the array.
+	 * On output, provides total number. No
+	 * more than the input number will be written
+	 * back, so two calls can be used to get
+	 * the size and then the data.
+	 */
+	__u32 count_objects;
+	__u32 pad;
+
+	/** Pointer to objects.
+	 * pointer to __u32 array of object ids
+	 */
+	__u64 objects_ptr;
+};
+
+/**
+ * Revoke lease
+ */
+struct drm_mode_revoke_lease {
+	/** Unique ID of lessee
+	 */
+	__u32 lessee_id;
+};
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/include/drm/drm_sarea.h b/include/drm/drm_sarea.h
index 502934e..93025be 100644
--- a/include/drm/drm_sarea.h
+++ b/include/drm/drm_sarea.h
@@ -34,6 +34,10 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* SAREA area needs to be at least a page */
 #if defined(__alpha__)
 #define SAREA_MAX                       0x2000U
@@ -81,4 +85,8 @@
 typedef struct drm_sarea_frame drm_sarea_frame_t;
 typedef struct drm_sarea drm_sarea_t;
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif				/* _DRM_SAREA_H_ */
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 5ebe046..268b585 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -86,6 +86,62 @@
 	I915_MOCS_CACHED,
 };
 
+/*
+ * Different engines serve different roles, and there may be more than one
+ * engine serving each role. enum drm_i915_gem_engine_class provides a
+ * classification of the role of the engine, which may be used when requesting
+ * operations to be performed on a certain subset of engines, or for providing
+ * information about that group.
+ */
+enum drm_i915_gem_engine_class {
+	I915_ENGINE_CLASS_RENDER	= 0,
+	I915_ENGINE_CLASS_COPY		= 1,
+	I915_ENGINE_CLASS_VIDEO		= 2,
+	I915_ENGINE_CLASS_VIDEO_ENHANCE	= 3,
+
+	I915_ENGINE_CLASS_INVALID	= -1
+};
+
+/**
+ * DOC: perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915
+ *
+ */
+
+enum drm_i915_pmu_engine_sample {
+	I915_SAMPLE_BUSY = 0,
+	I915_SAMPLE_WAIT = 1,
+	I915_SAMPLE_SEMA = 2
+};
+
+#define I915_PMU_SAMPLE_BITS (4)
+#define I915_PMU_SAMPLE_MASK (0xf)
+#define I915_PMU_SAMPLE_INSTANCE_BITS (8)
+#define I915_PMU_CLASS_SHIFT \
+	(I915_PMU_SAMPLE_BITS + I915_PMU_SAMPLE_INSTANCE_BITS)
+
+#define __I915_PMU_ENGINE(class, instance, sample) \
+	((class) << I915_PMU_CLASS_SHIFT | \
+	(instance) << I915_PMU_SAMPLE_BITS | \
+	(sample))
+
+#define I915_PMU_ENGINE_BUSY(class, instance) \
+	__I915_PMU_ENGINE(class, instance, I915_SAMPLE_BUSY)
+
+#define I915_PMU_ENGINE_WAIT(class, instance) \
+	__I915_PMU_ENGINE(class, instance, I915_SAMPLE_WAIT)
+
+#define I915_PMU_ENGINE_SEMA(class, instance) \
+	__I915_PMU_ENGINE(class, instance, I915_SAMPLE_SEMA)
+
+#define __I915_PMU_OTHER(x) (__I915_PMU_ENGINE(0xff, 0xff, 0xf) + 1 + (x))
+
+#define I915_PMU_ACTUAL_FREQUENCY	__I915_PMU_OTHER(0)
+#define I915_PMU_REQUESTED_FREQUENCY	__I915_PMU_OTHER(1)
+#define I915_PMU_INTERRUPTS		__I915_PMU_OTHER(2)
+#define I915_PMU_RC6_RESIDENCY		__I915_PMU_OTHER(3)
+
+#define I915_PMU_LAST I915_PMU_RC6_RESIDENCY
+
 /* Each region is a minimum of 16k, and there are at most 255 of them.
  */
 #define I915_NR_TEX_REGIONS 255	/* table size 2k - maximum due to use
@@ -260,6 +316,9 @@
 #define DRM_I915_GEM_CONTEXT_GETPARAM	0x34
 #define DRM_I915_GEM_CONTEXT_SETPARAM	0x35
 #define DRM_I915_PERF_OPEN		0x36
+#define DRM_I915_PERF_ADD_CONFIG	0x37
+#define DRM_I915_PERF_REMOVE_CONFIG	0x38
+#define DRM_I915_QUERY			0x39
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -315,6 +374,9 @@
 #define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param)
 #define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param)
 #define DRM_IOCTL_I915_PERF_OPEN	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param)
+#define DRM_IOCTL_I915_PERF_ADD_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config)
+#define DRM_IOCTL_I915_PERF_REMOVE_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)
+#define DRM_IOCTL_I915_QUERY			DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -393,10 +455,20 @@
 #define I915_PARAM_MIN_EU_IN_POOL	 39
 #define I915_PARAM_MMAP_GTT_VERSION	 40
 
-/* Query whether DRM_I915_GEM_EXECBUFFER2 supports user defined execution
+/*
+ * Query whether DRM_I915_GEM_EXECBUFFER2 supports user defined execution
  * priorities and the driver will attempt to execute batches in priority order.
+ * The param returns a capability bitmask, nonzero implies that the scheduler
+ * is enabled, with different features present according to the mask.
+ *
+ * The initial priority for each batch is supplied by the context and is
+ * controlled via I915_CONTEXT_PARAM_PRIORITY.
  */
 #define I915_PARAM_HAS_SCHEDULER	 41
+#define   I915_SCHEDULER_CAP_ENABLED	(1ul << 0)
+#define   I915_SCHEDULER_CAP_PRIORITY	(1ul << 1)
+#define   I915_SCHEDULER_CAP_PREEMPTION	(1ul << 2)
+
 #define I915_PARAM_HUC_STATUS		 42
 
 /* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to opt-out of
@@ -412,6 +484,73 @@
  */
 #define I915_PARAM_HAS_EXEC_FENCE	 44
 
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to capture
+ * user specified bufffers for post-mortem debugging of GPU hangs. See
+ * EXEC_OBJECT_CAPTURE.
+ */
+#define I915_PARAM_HAS_EXEC_CAPTURE	 45
+
+#define I915_PARAM_SLICE_MASK		 46
+
+/* Assuming it's uniform for each slice, this queries the mask of subslices
+ * per-slice for this system.
+ */
+#define I915_PARAM_SUBSLICE_MASK	 47
+
+/*
+ * Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying the batch buffer
+ * as the first execobject as opposed to the last. See I915_EXEC_BATCH_FIRST.
+ */
+#define I915_PARAM_HAS_EXEC_BATCH_FIRST	 48
+
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of
+ * drm_i915_gem_exec_fence structures.  See I915_EXEC_FENCE_ARRAY.
+ */
+#define I915_PARAM_HAS_EXEC_FENCE_ARRAY  49
+
+/*
+ * Query whether every context (both per-file default and user created) is
+ * isolated (insofar as HW supports). If this parameter is not true, then
+ * freshly created contexts may inherit values from an existing context,
+ * rather than default HW values. If true, it also ensures (insofar as HW
+ * supports) that all state set by this context will not leak to any other
+ * context.
+ *
+ * As not every engine across every gen support contexts, the returned
+ * value reports the support of context isolation for individual engines by
+ * returning a bitmask of each engine class set to true if that class supports
+ * isolation.
+ */
+#define I915_PARAM_HAS_CONTEXT_ISOLATION 50
+
+/* Frequency of the command streamer timestamps given by the *_TIMESTAMP
+ * registers. This used to be fixed per platform but from CNL onwards, this
+ * might vary depending on the parts.
+ */
+#define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51
+
+/*
+ * Once upon a time we supposed that writes through the GGTT would be
+ * immediately in physical memory (once flushed out of the CPU path). However,
+ * on a few different processors and chipsets, this is not necessarily the case
+ * as the writes appear to be buffered internally. Thus a read of the backing
+ * storage (physical memory) via a different path (with different physical tags
+ * to the indirect write via the GGTT) will see stale values from before
+ * the GGTT write. Inside the kernel, we can for the most part keep track of
+ * the different read/write domains in use (e.g. set-domain), but the assumption
+ * of coherency is baked into the ABI, hence reporting its true state in this
+ * parameter.
+ *
+ * Reports true when writes via mmap_gtt are immediately visible following an
+ * lfence to flush the WCB.
+ *
+ * Reports false when writes via mmap_gtt are indeterminately delayed in an in
+ * internal buffer and are _not_ immediately visible to third parties accessing
+ * directly via mmap_cpu/mmap_wc. Use of mmap_gtt as part of an IPC
+ * communications channel when reporting false is strongly disadvised.
+ */
+#define I915_PARAM_MMAP_GTT_COHERENT	52
+
 typedef struct drm_i915_getparam {
 	__s32 param;
 	/*
@@ -666,6 +805,8 @@
 #define I915_GEM_DOMAIN_VERTEX		0x00000020
 /** GTT domain - aperture and scanout */
 #define I915_GEM_DOMAIN_GTT		0x00000040
+/** WC domain - uncached access */
+#define I915_GEM_DOMAIN_WC		0x00000080
 /** @} */
 
 struct drm_i915_gem_exec_object {
@@ -773,8 +914,15 @@
  * I915_PARAM_HAS_EXEC_FENCE to order execbufs and execute them asynchronously.
  */
 #define EXEC_OBJECT_ASYNC		(1<<6)
+/* Request that the contents of this execobject be copied into the error
+ * state upon a GPU hang involving this batch for post-mortem debugging.
+ * These buffers are recorded in no particular order as "user" in
+ * /sys/class/drm/cardN/error. Query I915_PARAM_HAS_EXEC_CAPTURE to see
+ * if the kernel supports this flag.
+ */
+#define EXEC_OBJECT_CAPTURE		(1<<7)
 /* All remaining bits are MBZ and RESERVED FOR FUTURE USE */
-#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_ASYNC<<1)
+#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_CAPTURE<<1)
 	__u64 flags;
 
 	union {
@@ -784,6 +932,18 @@
 	__u64 rsvd2;
 };
 
+struct drm_i915_gem_exec_fence {
+	/**
+	 * User's handle for a drm_syncobj to wait on or signal.
+	 */
+	__u32 handle;
+
+#define I915_EXEC_FENCE_WAIT            (1<<0)
+#define I915_EXEC_FENCE_SIGNAL          (1<<1)
+#define __I915_EXEC_FENCE_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SIGNAL << 1))
+	__u32 flags;
+};
+
 struct drm_i915_gem_execbuffer2 {
 	/**
 	 * List of gem_exec_object2 structs
@@ -798,7 +958,11 @@
 	__u32 DR1;
 	__u32 DR4;
 	__u32 num_cliprects;
-	/** This is a struct drm_clip_rect *cliprects */
+	/**
+	 * This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY
+	 * is not set.  If I915_EXEC_FENCE_ARRAY is set, then this is a
+	 * struct drm_i915_gem_exec_fence *fences.
+	 */
 	__u64 cliprects_ptr;
 #define I915_EXEC_RING_MASK              (7<<0)
 #define I915_EXEC_DEFAULT                (0<<0)
@@ -889,7 +1053,24 @@
  */
 #define I915_EXEC_FENCE_OUT		(1<<17)
 
-#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_OUT<<1))
+/*
+ * Traditionally the execbuf ioctl has only considered the final element in
+ * the execobject[] to be the executable batch. Often though, the client
+ * will known the batch object prior to construction and being able to place
+ * it into the execobject[] array first can simplify the relocation tracking.
+ * Setting I915_EXEC_BATCH_FIRST tells execbuf to use element 0 of the
+ * execobject[] as the * batch instead (the default is to use the last
+ * element).
+ */
+#define I915_EXEC_BATCH_FIRST		(1<<18)
+
+/* Setting I915_FENCE_ARRAY implies that num_cliprects and cliprects_ptr
+ * define an array of i915_gem_exec_fence structures which specify a set of
+ * dma fences to wait upon or signal.
+ */
+#define I915_EXEC_FENCE_ARRAY   (1<<19)
+
+#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1))
 
 #define I915_EXEC_CONTEXT_ID_MASK	(0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
@@ -1201,7 +1382,9 @@
  * active on a given plane.
  */
 
-#define I915_SET_COLORKEY_NONE		(1<<0) /* disable color key matching */
+#define I915_SET_COLORKEY_NONE		(1<<0) /* Deprecated. Instead set
+						* flags==0 to disable colorkeying.
+						*/
 #define I915_SET_COLORKEY_DESTINATION	(1<<1)
 #define I915_SET_COLORKEY_SOURCE	(1<<2)
 struct drm_intel_sprite_colorkey {
@@ -1239,14 +1422,16 @@
 	 * be specified
 	 */
 	__u64 offset;
+#define I915_REG_READ_8B_WA (1ul << 0)
+
 	__u64 val; /* Return value */
 };
 /* Known registers:
  *
  * Render engine timestamp - 0x2358 + 64bit - gen7+
  * - Note this register returns an invalid value if using the default
- *   single instruction 8byte read, in order to workaround that use
- *   offset (0x2538 | 1) instead.
+ *   single instruction 8byte read, in order to workaround that pass
+ *   flag I915_REG_READ_8B_WA in offset field.
  *
  */
 
@@ -1289,17 +1474,26 @@
 #define I915_CONTEXT_PARAM_GTT_SIZE	0x3
 #define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE	0x4
 #define I915_CONTEXT_PARAM_BANNABLE	0x5
+#define I915_CONTEXT_PARAM_PRIORITY	0x6
+#define   I915_CONTEXT_MAX_USER_PRIORITY	1023 /* inclusive */
+#define   I915_CONTEXT_DEFAULT_PRIORITY		0
+#define   I915_CONTEXT_MIN_USER_PRIORITY	-1023 /* inclusive */
 	__u64 value;
 };
 
 enum drm_i915_oa_format {
-	I915_OA_FORMAT_A13 = 1,
-	I915_OA_FORMAT_A29,
-	I915_OA_FORMAT_A13_B8_C8,
-	I915_OA_FORMAT_B4_C8,
-	I915_OA_FORMAT_A45_B8_C8,
-	I915_OA_FORMAT_B4_C8_A16,
-	I915_OA_FORMAT_C4_B8,
+	I915_OA_FORMAT_A13 = 1,	    /* HSW only */
+	I915_OA_FORMAT_A29,	    /* HSW only */
+	I915_OA_FORMAT_A13_B8_C8,   /* HSW only */
+	I915_OA_FORMAT_B4_C8,	    /* HSW only */
+	I915_OA_FORMAT_A45_B8_C8,   /* HSW only */
+	I915_OA_FORMAT_B4_C8_A16,   /* HSW only */
+	I915_OA_FORMAT_C4_B8,	    /* HSW+ */
+
+	/* Gen8+ */
+	I915_OA_FORMAT_A12,
+	I915_OA_FORMAT_A12_B8_C8,
+	I915_OA_FORMAT_A32u40_A4u32_B8_C8,
 
 	I915_OA_FORMAT_MAX	    /* non-ABI */
 };
@@ -1424,6 +1618,127 @@
 	DRM_I915_PERF_RECORD_MAX /* non-ABI */
 };
 
+/**
+ * Structure to upload perf dynamic configuration into the kernel.
+ */
+struct drm_i915_perf_oa_config {
+	/** String formatted like "%08x-%04x-%04x-%04x-%012x" */
+	char uuid[36];
+
+	__u32 n_mux_regs;
+	__u32 n_boolean_regs;
+	__u32 n_flex_regs;
+
+	/*
+	 * These fields are pointers to tuples of u32 values (register address,
+	 * value). For example the expected length of the buffer pointed by
+	 * mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs).
+	 */
+	__u64 mux_regs_ptr;
+	__u64 boolean_regs_ptr;
+	__u64 flex_regs_ptr;
+};
+
+struct drm_i915_query_item {
+	__u64 query_id;
+#define DRM_I915_QUERY_TOPOLOGY_INFO    1
+
+	/*
+	 * When set to zero by userspace, this is filled with the size of the
+	 * data to be written at the data_ptr pointer. The kernel sets this
+	 * value to a negative value to signal an error on a particular query
+	 * item.
+	 */
+	__s32 length;
+
+	/*
+	 * Unused for now. Must be cleared to zero.
+	 */
+	__u32 flags;
+
+	/*
+	 * Data will be written at the location pointed by data_ptr when the
+	 * value of length matches the length of the data to be written by the
+	 * kernel.
+	 */
+	__u64 data_ptr;
+};
+
+struct drm_i915_query {
+	__u32 num_items;
+
+	/*
+	 * Unused for now. Must be cleared to zero.
+	 */
+	__u32 flags;
+
+	/*
+	 * This points to an array of num_items drm_i915_query_item structures.
+	 */
+	__u64 items_ptr;
+};
+
+/*
+ * Data written by the kernel with query DRM_I915_QUERY_TOPOLOGY_INFO :
+ *
+ * data: contains the 3 pieces of information :
+ *
+ * - the slice mask with one bit per slice telling whether a slice is
+ *   available. The availability of slice X can be queried with the following
+ *   formula :
+ *
+ *           (data[X / 8] >> (X % 8)) & 1
+ *
+ * - the subslice mask for each slice with one bit per subslice telling
+ *   whether a subslice is available. The availability of subslice Y in slice
+ *   X can be queried with the following formula :
+ *
+ *           (data[subslice_offset +
+ *                 X * subslice_stride +
+ *                 Y / 8] >> (Y % 8)) & 1
+ *
+ * - the EU mask for each subslice in each slice with one bit per EU telling
+ *   whether an EU is available. The availability of EU Z in subslice Y in
+ *   slice X can be queried with the following formula :
+ *
+ *           (data[eu_offset +
+ *                 (X * max_subslices + Y) * eu_stride +
+ *                 Z / 8] >> (Z % 8)) & 1
+ */
+struct drm_i915_query_topology_info {
+	/*
+	 * Unused for now. Must be cleared to zero.
+	 */
+	__u16 flags;
+
+	__u16 max_slices;
+	__u16 max_subslices;
+	__u16 max_eus_per_subslice;
+
+	/*
+	 * Offset in data[] at which the subslice masks are stored.
+	 */
+	__u16 subslice_offset;
+
+	/*
+	 * Stride at which each of the subslice masks for each slice are
+	 * stored.
+	 */
+	__u16 subslice_stride;
+
+	/*
+	 * Offset in data[] at which the EU masks are stored.
+	 */
+	__u16 eu_offset;
+
+	/*
+	 * Stride at which each of the EU masks for each subslice are stored.
+	 */
+	__u16 eu_stride;
+
+	__u8 data[];
+};
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/include/drm/mga_drm.h b/include/drm/mga_drm.h
index b630e8f..7930011 100644
--- a/include/drm/mga_drm.h
+++ b/include/drm/mga_drm.h
@@ -37,6 +37,10 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the Xserver file (mga_sarea.h)
  */
@@ -107,7 +111,7 @@
  */
 #define MGA_NR_SAREA_CLIPRECTS	8
 
-/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
+/* 2 heaps (1 for card, 1 for agp), each divided into up to 128
  * regions, subject to a minimum region size of (1<<16) == 64k.
  *
  * Clients may subdivide regions internally, but when sharing between
@@ -248,7 +252,7 @@
 #define DRM_MGA_DMA_BOOTSTRAP  0x0c
 
 #define DRM_IOCTL_MGA_INIT     DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t)
-#define DRM_IOCTL_MGA_FLUSH    DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t)
+#define DRM_IOCTL_MGA_FLUSH    DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, struct drm_lock)
 #define DRM_IOCTL_MGA_RESET    DRM_IO(  DRM_COMMAND_BASE + DRM_MGA_RESET)
 #define DRM_IOCTL_MGA_SWAP     DRM_IO(  DRM_COMMAND_BASE + DRM_MGA_SWAP)
 #define DRM_IOCTL_MGA_CLEAR    DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_CLEAR, drm_mga_clear_t)
@@ -416,4 +420,8 @@
 	void *value;
 } drm_mga_getparam_t;
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/freedreno/msm/msm_drm.h b/include/drm/msm_drm.h
similarity index 87%
rename from freedreno/msm/msm_drm.h
rename to include/drm/msm_drm.h
index ed4c8d4..c06d0a5 100644
--- a/freedreno/msm/msm_drm.h
+++ b/include/drm/msm_drm.h
@@ -25,7 +25,6 @@
 #ifndef __MSM_DRM_H__
 #define __MSM_DRM_H__
 
-#include <stddef.h>
 #include "drm.h"
 
 #if defined(__cplusplus)
@@ -73,6 +72,8 @@
 #define MSM_PARAM_CHIP_ID    0x03
 #define MSM_PARAM_MAX_FREQ   0x04
 #define MSM_PARAM_TIMESTAMP  0x05
+#define MSM_PARAM_GMEM_BASE  0x06
+#define MSM_PARAM_NR_RINGS   0x07
 
 struct drm_msm_param {
 	__u32 pipe;           /* in, MSM_PIPE_x */
@@ -104,10 +105,14 @@
 	__u32 handle;         /* out */
 };
 
+#define MSM_INFO_IOVA	0x01
+
+#define MSM_INFO_FLAGS (MSM_INFO_IOVA)
+
 struct drm_msm_gem_info {
 	__u32 handle;         /* in */
-	__u32 pad;
-	__u64 offset;         /* out, offset to pass to mmap() */
+	__u32 flags;	      /* in - combination of MSM_INFO_* flags */
+	__u64 offset;         /* out, mmap() offset or iova */
 };
 
 #define MSM_PREP_READ        0x01
@@ -167,7 +172,7 @@
 	__u32 size;           /* in, cmdstream size */
 	__u32 pad;
 	__u32 nr_relocs;      /* in, number of submit_reloc's */
-	__u64 __user relocs;  /* in, ptr to array of submit_reloc's */
+	__u64 relocs;         /* in, ptr to array of submit_reloc's */
 };
 
 /* Each buffer referenced elsewhere in the cmdstream submit (ie. the
@@ -196,10 +201,12 @@
 #define MSM_SUBMIT_NO_IMPLICIT   0x80000000 /* disable implicit sync */
 #define MSM_SUBMIT_FENCE_FD_IN   0x40000000 /* enable input fence_fd */
 #define MSM_SUBMIT_FENCE_FD_OUT  0x20000000 /* enable output fence_fd */
+#define MSM_SUBMIT_SUDO          0x10000000 /* run submitted cmds from RB */
 #define MSM_SUBMIT_FLAGS                ( \
 		MSM_SUBMIT_NO_IMPLICIT   | \
 		MSM_SUBMIT_FENCE_FD_IN   | \
 		MSM_SUBMIT_FENCE_FD_OUT  | \
+		MSM_SUBMIT_SUDO          | \
 		0)
 
 /* Each cmdstream submit consists of a table of buffers involved, and
@@ -211,9 +218,10 @@
 	__u32 fence;          /* out */
 	__u32 nr_bos;         /* in, number of submit_bo's */
 	__u32 nr_cmds;        /* in, number of submit_cmd's */
-	__u64 __user bos;     /* in, ptr to array of submit_bo's */
-	__u64 __user cmds;    /* in, ptr to array of submit_cmd's */
+	__u64 bos;            /* in, ptr to array of submit_bo's */
+	__u64 cmds;           /* in, ptr to array of submit_cmd's */
 	__s32 fence_fd;       /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */
+	__u32 queueid;         /* in, submitqueue id */
 };
 
 /* The normal way to synchronize with the GPU is just to CPU_PREP on
@@ -227,6 +235,7 @@
 	__u32 fence;          /* in */
 	__u32 pad;
 	struct drm_msm_timespec timeout;   /* in */
+	__u32 queueid;         /* in, submitqueue id */
 };
 
 /* madvise provides a way to tell the kernel in case a buffers contents
@@ -250,6 +259,20 @@
 	__u32 retained;       /* out, whether backing store still exists */
 };
 
+/*
+ * Draw queues allow the user to set specific submission parameter. Command
+ * submissions specify a specific submitqueue to use.  ID 0 is reserved for
+ * backwards compatibility as a "default" submitqueue
+ */
+
+#define MSM_SUBMITQUEUE_FLAGS (0)
+
+struct drm_msm_submitqueue {
+	__u32 flags;   /* in, MSM_SUBMITQUEUE_x */
+	__u32 prio;    /* in, Priority level */
+	__u32 id;      /* out, identifier */
+};
+
 #define DRM_MSM_GET_PARAM              0x00
 /* placeholder:
 #define DRM_MSM_SET_PARAM              0x01
@@ -261,7 +284,11 @@
 #define DRM_MSM_GEM_SUBMIT             0x06
 #define DRM_MSM_WAIT_FENCE             0x07
 #define DRM_MSM_GEM_MADVISE            0x08
-#define DRM_MSM_NUM_IOCTLS             0x09
+/* placeholder:
+#define DRM_MSM_GEM_SVM_NEW            0x09
+ */
+#define DRM_MSM_SUBMITQUEUE_NEW        0x0A
+#define DRM_MSM_SUBMITQUEUE_CLOSE      0x0B
 
 #define DRM_IOCTL_MSM_GET_PARAM        DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
 #define DRM_IOCTL_MSM_GEM_NEW          DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new)
@@ -271,6 +298,8 @@
 #define DRM_IOCTL_MSM_GEM_SUBMIT       DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_SUBMIT, struct drm_msm_gem_submit)
 #define DRM_IOCTL_MSM_WAIT_FENCE       DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_WAIT_FENCE, struct drm_msm_wait_fence)
 #define DRM_IOCTL_MSM_GEM_MADVISE      DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_MADVISE, struct drm_msm_gem_madvise)
+#define DRM_IOCTL_MSM_SUBMITQUEUE_NEW    DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_NEW, struct drm_msm_submitqueue)
+#define DRM_IOCTL_MSM_SUBMITQUEUE_CLOSE  DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_CLOSE, __u32)
 
 #if defined(__cplusplus)
 }
diff --git a/include/drm/nouveau_class.h b/include/drm/nouveau_class.h
deleted file mode 100644
index 8d63877..0000000
--- a/include/drm/nouveau_class.h
+++ /dev/null
@@ -1,651 +0,0 @@
-#ifndef __NVIF_CLASS_H__
-#define __NVIF_CLASS_H__
-
-/*******************************************************************************
- * class identifiers
- ******************************************************************************/
-
-/* the below match nvidia-assigned (either in hw, or sw) class numbers */
-#define NV_DEVICE                                                    0x00000080
-
-#define NV_DMA_FROM_MEMORY                                           0x00000002
-#define NV_DMA_TO_MEMORY                                             0x00000003
-#define NV_DMA_IN_MEMORY                                             0x0000003d
-
-#define FERMI_TWOD_A                                                 0x0000902d
-
-#define FERMI_MEMORY_TO_MEMORY_FORMAT_A                              0x0000903d
-
-#define KEPLER_INLINE_TO_MEMORY_A                                    0x0000a040
-#define KEPLER_INLINE_TO_MEMORY_B                                    0x0000a140
-
-#define NV04_DISP                                                    0x00000046
-
-#define NV03_CHANNEL_DMA                                             0x0000006b
-#define NV10_CHANNEL_DMA                                             0x0000006e
-#define NV17_CHANNEL_DMA                                             0x0000176e
-#define NV40_CHANNEL_DMA                                             0x0000406e
-#define NV50_CHANNEL_DMA                                             0x0000506e
-#define G82_CHANNEL_DMA                                              0x0000826e
-
-#define NV50_CHANNEL_GPFIFO                                          0x0000506f
-#define G82_CHANNEL_GPFIFO                                           0x0000826f
-#define FERMI_CHANNEL_GPFIFO                                         0x0000906f
-#define KEPLER_CHANNEL_GPFIFO_A                                      0x0000a06f
-#define MAXWELL_CHANNEL_GPFIFO_A                                     0x0000b06f
-
-#define NV50_DISP                                                    0x00005070
-#define G82_DISP                                                     0x00008270
-#define GT200_DISP                                                   0x00008370
-#define GT214_DISP                                                   0x00008570
-#define GT206_DISP                                                   0x00008870
-#define GF110_DISP                                                   0x00009070
-#define GK104_DISP                                                   0x00009170
-#define GK110_DISP                                                   0x00009270
-#define GM107_DISP                                                   0x00009470
-#define GM204_DISP                                                   0x00009570
-
-#define NV50_DISP_CURSOR                                             0x0000507a
-#define G82_DISP_CURSOR                                              0x0000827a
-#define GT214_DISP_CURSOR                                            0x0000857a
-#define GF110_DISP_CURSOR                                            0x0000907a
-#define GK104_DISP_CURSOR                                            0x0000917a
-
-#define NV50_DISP_OVERLAY                                            0x0000507b
-#define G82_DISP_OVERLAY                                             0x0000827b
-#define GT214_DISP_OVERLAY                                           0x0000857b
-#define GF110_DISP_OVERLAY                                           0x0000907b
-#define GK104_DISP_OVERLAY                                           0x0000917b
-
-#define NV50_DISP_BASE_CHANNEL_DMA                                   0x0000507c
-#define G82_DISP_BASE_CHANNEL_DMA                                    0x0000827c
-#define GT200_DISP_BASE_CHANNEL_DMA                                  0x0000837c
-#define GT214_DISP_BASE_CHANNEL_DMA                                  0x0000857c
-#define GF110_DISP_BASE_CHANNEL_DMA                                  0x0000907c
-#define GK104_DISP_BASE_CHANNEL_DMA                                  0x0000917c
-#define GK110_DISP_BASE_CHANNEL_DMA                                  0x0000927c
-
-#define NV50_DISP_CORE_CHANNEL_DMA                                   0x0000507d
-#define G82_DISP_CORE_CHANNEL_DMA                                    0x0000827d
-#define GT200_DISP_CORE_CHANNEL_DMA                                  0x0000837d
-#define GT214_DISP_CORE_CHANNEL_DMA                                  0x0000857d
-#define GT206_DISP_CORE_CHANNEL_DMA                                  0x0000887d
-#define GF110_DISP_CORE_CHANNEL_DMA                                  0x0000907d
-#define GK104_DISP_CORE_CHANNEL_DMA                                  0x0000917d
-#define GK110_DISP_CORE_CHANNEL_DMA                                  0x0000927d
-#define GM107_DISP_CORE_CHANNEL_DMA                                  0x0000947d
-#define GM204_DISP_CORE_CHANNEL_DMA                                  0x0000957d
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA                                0x0000507e
-#define G82_DISP_OVERLAY_CHANNEL_DMA                                 0x0000827e
-#define GT200_DISP_OVERLAY_CHANNEL_DMA                               0x0000837e
-#define GT214_DISP_OVERLAY_CHANNEL_DMA                               0x0000857e
-#define GF110_DISP_OVERLAY_CONTROL_DMA                               0x0000907e
-#define GK104_DISP_OVERLAY_CONTROL_DMA                               0x0000917e
-
-#define FERMI_A                                                      0x00009097
-#define FERMI_B                                                      0x00009197
-#define FERMI_C                                                      0x00009297
-
-#define KEPLER_A                                                     0x0000a097
-#define KEPLER_B                                                     0x0000a197
-#define KEPLER_C                                                     0x0000a297
-
-#define MAXWELL_A                                                    0x0000b097
-#define MAXWELL_B                                                    0x0000b197
-
-#define FERMI_COMPUTE_A                                              0x000090c0
-#define FERMI_COMPUTE_B                                              0x000091c0
-
-#define KEPLER_COMPUTE_A                                             0x0000a0c0
-#define KEPLER_COMPUTE_B                                             0x0000a1c0
-
-#define MAXWELL_COMPUTE_A                                            0x0000b0c0
-#define MAXWELL_COMPUTE_B                                            0x0000b1c0
-
-#define MAXWELL_DMA_COPY_A                                           0x0000b0b5
-
-/*******************************************************************************
- * client
- ******************************************************************************/
-
-#define NV_CLIENT_DEVLIST                                                  0x00
-
-struct nv_client_devlist_v0 {
-	__u8  version;
-	__u8  count;
-	__u8  pad02[6];
-	__u64 device[];
-};
-
-
-/*******************************************************************************
- * device
- ******************************************************************************/
-
-struct nv_device_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__u64 device;	/* device identifier, ~0 for client default */
-#define NV_DEVICE_V0_DISABLE_IDENTIFY                     0x0000000000000001ULL
-#define NV_DEVICE_V0_DISABLE_MMIO                         0x0000000000000002ULL
-#define NV_DEVICE_V0_DISABLE_VBIOS                        0x0000000000000004ULL
-#define NV_DEVICE_V0_DISABLE_CORE                         0x0000000000000008ULL
-#define NV_DEVICE_V0_DISABLE_DISP                         0x0000000000010000ULL
-#define NV_DEVICE_V0_DISABLE_FIFO                         0x0000000000020000ULL
-#define NV_DEVICE_V0_DISABLE_GR                           0x0000000100000000ULL
-#define NV_DEVICE_V0_DISABLE_MPEG                         0x0000000200000000ULL
-#define NV_DEVICE_V0_DISABLE_ME                           0x0000000400000000ULL
-#define NV_DEVICE_V0_DISABLE_VP                           0x0000000800000000ULL
-#define NV_DEVICE_V0_DISABLE_CIPHER                       0x0000001000000000ULL
-#define NV_DEVICE_V0_DISABLE_BSP                          0x0000002000000000ULL
-#define NV_DEVICE_V0_DISABLE_MSPPP                        0x0000004000000000ULL
-#define NV_DEVICE_V0_DISABLE_CE0                          0x0000008000000000ULL
-#define NV_DEVICE_V0_DISABLE_CE1                          0x0000010000000000ULL
-#define NV_DEVICE_V0_DISABLE_VIC                          0x0000020000000000ULL
-#define NV_DEVICE_V0_DISABLE_MSENC                        0x0000040000000000ULL
-#define NV_DEVICE_V0_DISABLE_CE2                          0x0000080000000000ULL
-#define NV_DEVICE_V0_DISABLE_MSVLD                        0x0000100000000000ULL
-#define NV_DEVICE_V0_DISABLE_SEC                          0x0000200000000000ULL
-#define NV_DEVICE_V0_DISABLE_MSPDEC                       0x0000400000000000ULL
-	__u64 disable;	/* disable particular subsystems */
-	__u64 debug0;	/* as above, but *internal* ids, and *NOT* ABI */
-};
-
-#define NV_DEVICE_V0_INFO                                                  0x00
-#define NV_DEVICE_V0_ZCULL_INFO                                            0x01
-
-struct nv_device_info_v0 {
-	__u8  version;
-#define NV_DEVICE_INFO_V0_IGP                                              0x00
-#define NV_DEVICE_INFO_V0_PCI                                              0x01
-#define NV_DEVICE_INFO_V0_AGP                                              0x02
-#define NV_DEVICE_INFO_V0_PCIE                                             0x03
-#define NV_DEVICE_INFO_V0_SOC                                              0x04
-	__u8  platform;
-	__u16 chipset;	/* from NV_PMC_BOOT_0 */
-	__u8  revision;	/* from NV_PMC_BOOT_0 */
-#define NV_DEVICE_INFO_V0_TNT                                              0x01
-#define NV_DEVICE_INFO_V0_CELSIUS                                          0x02
-#define NV_DEVICE_INFO_V0_KELVIN                                           0x03
-#define NV_DEVICE_INFO_V0_RANKINE                                          0x04
-#define NV_DEVICE_INFO_V0_CURIE                                            0x05
-#define NV_DEVICE_INFO_V0_TESLA                                            0x06
-#define NV_DEVICE_INFO_V0_FERMI                                            0x07
-#define NV_DEVICE_INFO_V0_KEPLER                                           0x08
-#define NV_DEVICE_INFO_V0_MAXWELL                                          0x09
-	__u8  family;
-	__u8  pad06[2];
-	__u64 ram_size;
-	__u64 ram_user;
-};
-
-struct nv_device_zcull_info_v0 {
-	__u8  version;
-	__u8  pad03[3];
-	__u32 image_size;
-	__u32 width_align_pixels;
-	__u32 height_align_pixels;
-	__u32 pixel_squares_by_aliquots;
-	__u32 aliquot_total;
-	__u32 region_byte_multiplier;
-	__u32 region_header_size;
-	__u32 subregion_header_size;
-	__u32 subregion_width_align_pixels;
-	__u32 subregion_height_align_pixels;
-	__u32 subregion_count;
-};
-
-/*******************************************************************************
- * context dma
- ******************************************************************************/
-
-struct nv_dma_v0 {
-	__u8  version;
-#define NV_DMA_V0_TARGET_VM                                                0x00
-#define NV_DMA_V0_TARGET_VRAM                                              0x01
-#define NV_DMA_V0_TARGET_PCI                                               0x02
-#define NV_DMA_V0_TARGET_PCI_US                                            0x03
-#define NV_DMA_V0_TARGET_AGP                                               0x04
-	__u8  target;
-#define NV_DMA_V0_ACCESS_VM                                                0x00
-#define NV_DMA_V0_ACCESS_RD                                                0x01
-#define NV_DMA_V0_ACCESS_WR                                                0x02
-#define NV_DMA_V0_ACCESS_RDWR                 (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR)
-	__u8  access;
-	__u8  pad03[5];
-	__u64 start;
-	__u64 limit;
-	/* ... chipset-specific class data */
-};
-
-struct nv50_dma_v0 {
-	__u8  version;
-#define NV50_DMA_V0_PRIV_VM                                                0x00
-#define NV50_DMA_V0_PRIV_US                                                0x01
-#define NV50_DMA_V0_PRIV__S                                                0x02
-	__u8  priv;
-#define NV50_DMA_V0_PART_VM                                                0x00
-#define NV50_DMA_V0_PART_256                                               0x01
-#define NV50_DMA_V0_PART_1KB                                               0x02
-	__u8  part;
-#define NV50_DMA_V0_COMP_NONE                                              0x00
-#define NV50_DMA_V0_COMP_1                                                 0x01
-#define NV50_DMA_V0_COMP_2                                                 0x02
-#define NV50_DMA_V0_COMP_VM                                                0x03
-	__u8  comp;
-#define NV50_DMA_V0_KIND_PITCH                                             0x00
-#define NV50_DMA_V0_KIND_VM                                                0x7f
-	__u8  kind;
-	__u8  pad05[3];
-};
-
-struct gf100_dma_v0 {
-	__u8  version;
-#define GF100_DMA_V0_PRIV_VM                                               0x00
-#define GF100_DMA_V0_PRIV_US                                               0x01
-#define GF100_DMA_V0_PRIV__S                                               0x02
-	__u8  priv;
-#define GF100_DMA_V0_KIND_PITCH                                            0x00
-#define GF100_DMA_V0_KIND_VM                                               0xff
-	__u8  kind;
-	__u8  pad03[5];
-};
-
-struct gf110_dma_v0 {
-	__u8  version;
-#define GF110_DMA_V0_PAGE_LP                                               0x00
-#define GF110_DMA_V0_PAGE_SP                                               0x01
-	__u8  page;
-#define GF110_DMA_V0_KIND_PITCH                                            0x00
-#define GF110_DMA_V0_KIND_VM                                               0xff
-	__u8  kind;
-	__u8  pad03[5];
-};
-
-
-/*******************************************************************************
- * perfmon
- ******************************************************************************/
-
-struct nvif_perfctr_v0 {
-	__u8  version;
-	__u8  pad01[1];
-	__u16 logic_op;
-	__u8  pad04[4];
-	char  name[4][64];
-};
-
-#define NVIF_PERFCTR_V0_QUERY                                              0x00
-#define NVIF_PERFCTR_V0_SAMPLE                                             0x01
-#define NVIF_PERFCTR_V0_READ                                               0x02
-
-struct nvif_perfctr_query_v0 {
-	__u8  version;
-	__u8  pad01[3];
-	__u32 iter;
-	char  name[64];
-};
-
-struct nvif_perfctr_sample {
-};
-
-struct nvif_perfctr_read_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__u32 ctr;
-	__u32 clk;
-};
-
-
-/*******************************************************************************
- * device control
- ******************************************************************************/
-
-#define NVIF_CONTROL_PSTATE_INFO                                           0x00
-#define NVIF_CONTROL_PSTATE_ATTR                                           0x01
-#define NVIF_CONTROL_PSTATE_USER                                           0x02
-
-struct nvif_ustate {
-	__s8 min;
-	__s8 max;
-};
-
-struct nvif_control_pstate_info_v0 {
-	__u8  version;
-	__u8  count; /* out: number of power states */
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE                         (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON                         (-2)
-	struct {
-		struct nvif_ustate dc; // pwrsrc == 0
-		struct nvif_ustate ac; // pwrsrc == 1
-	}     ustate; /* out: target pstate index */
-	__s8  pwrsrc; /* out: current power source */
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN                         (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON                         (-2)
-	__s8  pstate; /* out: current pstate index */
-	__u8  pad06[2];
-};
-
-struct nvif_control_pstate_attr_v0 {
-	__u8  version;
-#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT                          (-1)
-	__s8  state; /*  in: index of pstate to query
-		      * out: pstate identifier
-		      */
-	__u8  index; /*  in: index of attribute to query
-		      * out: index of next attribute, or 0 if no more
-		      */
-	__u8  pad03[5];
-	__u32 min;
-	__u32 max;
-	char  name[32];
-	char  unit[16];
-};
-
-struct nvif_control_pstate_user_v0 {
-	__u8  version;
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN                          (-1)
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON                          (-2)
-	struct nvif_ustate ustate; /*  in: pstate identifier */
-	__s8  pwrsrc; /*  in: target power source */
-	__u8  pad03[5];
-};
-
-
-/*******************************************************************************
- * DMA FIFO channels
- ******************************************************************************/
-
-struct nv03_channel_dma_v0 {
-	__u8  version;
-	__u8  chid;
-	__u8  pad02[2];
-	__u32 pushbuf;
-	__u64 offset;
-};
-
-#define G82_CHANNEL_DMA_V0_NTFY_UEVENT                                     0x00
-
-/*******************************************************************************
- * GPFIFO channels
- ******************************************************************************/
-
-struct nv50_channel_gpfifo_v0 {
-	__u8  version;
-	__u8  chid;
-	__u8  pad01[6];
-	__u32 pushbuf;
-	__u32 ilength;
-	__u64 ioffset;
-};
-
-struct kepler_channel_gpfifo_a_v0 {
-	__u8  version;
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR                               0x01
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPDEC                           0x02
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPPP                            0x04
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSVLD                            0x08
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0                              0x10
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1                              0x20
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC                              0x40
-	__u8  engine;
-	__u16 chid;
-	__u8  pad04[4];
-	__u32 pushbuf;
-	__u32 ilength;
-	__u64 ioffset;
-};
-
-#define CHANNEL_GPFIFO_ERROR_NOTIFIER_EEVENT                               0x01
-
-/*******************************************************************************
- * legacy display
- ******************************************************************************/
-
-#define NV04_DISP_NTFY_VBLANK                                              0x00
-#define NV04_DISP_NTFY_CONN                                                0x01
-
-struct nv04_disp_mthd_v0 {
-	__u8  version;
-#define NV04_DISP_SCANOUTPOS                                               0x00
-	__u8  method;
-	__u8  head;
-	__u8  pad03[5];
-};
-
-struct nv04_disp_scanoutpos_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__s64 time[2];
-	__u16 vblanks;
-	__u16 vblanke;
-	__u16 vtotal;
-	__u16 vline;
-	__u16 hblanks;
-	__u16 hblanke;
-	__u16 htotal;
-	__u16 hline;
-};
-
-/*******************************************************************************
- * display
- ******************************************************************************/
-
-#define NV50_DISP_MTHD                                                     0x00
-
-struct nv50_disp_mthd_v0 {
-	__u8  version;
-#define NV50_DISP_SCANOUTPOS                                               0x00
-	__u8  method;
-	__u8  head;
-	__u8  pad03[5];
-};
-
-struct nv50_disp_mthd_v1 {
-	__u8  version;
-#define NV50_DISP_MTHD_V1_DAC_PWR                                          0x10
-#define NV50_DISP_MTHD_V1_DAC_LOAD                                         0x11
-#define NV50_DISP_MTHD_V1_SOR_PWR                                          0x20
-#define NV50_DISP_MTHD_V1_SOR_HDA_ELD                                      0x21
-#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR                                     0x22
-#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT                                  0x23
-#define NV50_DISP_MTHD_V1_SOR_DP_PWR                                       0x24
-#define NV50_DISP_MTHD_V1_PIOR_PWR                                         0x30
-	__u8  method;
-	__u16 hasht;
-	__u16 hashm;
-	__u8  pad06[2];
-};
-
-struct nv50_disp_dac_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  data;
-	__u8  vsync;
-	__u8  hsync;
-	__u8  pad05[3];
-};
-
-struct nv50_disp_dac_load_v0 {
-	__u8  version;
-	__u8  load;
-	__u8  pad02[2];
-	__u32 data;
-};
-
-struct nv50_disp_sor_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  pad02[6];
-};
-
-struct nv50_disp_sor_hda_eld_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__u8  data[];
-};
-
-struct nv50_disp_sor_hdmi_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  max_ac_packet;
-	__u8  rekey;
-	__u8  pad04[4];
-};
-
-struct nv50_disp_sor_lvds_script_v0 {
-	__u8  version;
-	__u8  pad01[1];
-	__u16 script;
-	__u8  pad04[4];
-};
-
-struct nv50_disp_sor_dp_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  pad02[6];
-};
-
-struct nv50_disp_pior_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  type;
-	__u8  pad03[5];
-};
-
-/* core */
-struct nv50_disp_core_channel_dma_v0 {
-	__u8  version;
-	__u8  pad01[3];
-	__u32 pushbuf;
-};
-
-#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
-
-/* cursor immediate */
-struct nv50_disp_cursor_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-};
-
-#define NV50_DISP_CURSOR_V0_NTFY_UEVENT                                    0x00
-
-/* base */
-struct nv50_disp_base_channel_dma_v0 {
-	__u8  version;
-	__u8  pad01[2];
-	__u8  head;
-	__u32 pushbuf;
-};
-
-#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
-
-/* overlay */
-struct nv50_disp_overlay_channel_dma_v0 {
-	__u8  version;
-	__u8  pad01[2];
-	__u8  head;
-	__u32 pushbuf;
-};
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT                       0x00
-
-/* overlay immediate */
-struct nv50_disp_overlay_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-};
-
-#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT                                   0x00
-
-/*******************************************************************************
- * fermi
- ******************************************************************************/
-
-#define FERMI_A_ZBC_COLOR                                                  0x00
-#define FERMI_A_ZBC_DEPTH                                                  0x01
-#define FERMI_A_ZCULL_BIND                                                 0x02
-#define FERMI_A_ZBC_QUERY_COLOR                                            0x03
-#define FERMI_A_ZBC_QUERY_DEPTH                                            0x04
-#define FERMI_A_ZBC_QUERY_TABLE_SIZE                                       0x05
-
-struct fermi_a_zbc_color_v0 {
-	__u8  version;
-#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO                                      0x01
-#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE                                 0x02
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32                       0x04
-#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16                           0x08
-#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16                       0x0c
-#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16                       0x10
-#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16                       0x14
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16                       0x16
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8                                  0x18
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8                               0x1c
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10                               0x20
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10                           0x24
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8                                  0x28
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8                               0x2c
-#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8                              0x30
-#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8                              0x34
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8                              0x38
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10                               0x3c
-#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11                              0x40
-	__u8  format;
-	__u8  index;
-	__u8  pad03[5];
-	__u32 ds[4];
-	__u32 l2[4];
-};
-
-struct fermi_a_zbc_query_v0 {
-	__u8 version;
-	__u8 pad03[3];
-	__u32 ds[4];
-	__u32 l2[4];
-	__u32 format;
-	__u32 index;
-	__u32 table_size;
-};
-
-struct fermi_a_zbc_depth_v0 {
-	__u8  version;
-#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32                                      0x01
-	__u8  format;
-	__u8  index;
-	__u8  pad03[5];
-	__u32 ds;
-	__u32 l2;
-};
-
-struct fermi_a_zcull_bind_v0 {
-	__u8  version;
-	__u8  pad03[3];
-#define FERMI_A_ZCULL_BIND_MODE_GLOBAL                                     0x00
-#define FERMI_A_ZCULL_BIND_MODE_NO_CTXSW                                   0x01
-#define FERMI_A_ZCULL_BIND_MODE_SEPARATE_BUFFER                            0x02
-	__u32 mode;
-	__u64 gpu_va;
-};
-
-#define KEPLER_SET_CHANNEL_PRIORITY                                        0x00
-#define KEPLER_SET_CHANNEL_TIMEOUT                                         0x01
-
-struct kepler_set_channel_priority_v0 {
-	__u8  version;
-#define KEPLER_SET_CHANNEL_PRIORITY_LOW                                    0x00
-#define KEPLER_SET_CHANNEL_PRIORITY_MEDIUM                                 0x01
-#define KEPLER_SET_CHANNEL_PRIORITY_HIGH                                   0x02
-	__u8 priority;
-	__u8  pad03[6];
-};
-
-struct kepler_set_channel_timeout_v0 {
-	__u8  version;
-	__u8  pad03[3];
-	__u32 timeout_ms;
-};
-
-#endif
diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h
index 1372f53..d42105c 100644
--- a/include/drm/nouveau_drm.h
+++ b/include/drm/nouveau_drm.h
@@ -27,13 +27,11 @@
 
 #define NOUVEAU_DRM_HEADER_PATCHLEVEL 16
 
-/* reserved object handles when using deprecated object APIs - these
- * are here so that libdrm can allow interoperability with the new
- * object APIs
- */
-#define NOUVEAU_ABI16_CLIENT   0xffffffff
-#define NOUVEAU_ABI16_DEVICE   0xdddddddd
-#define NOUVEAU_ABI16_CHAN(n) (0xcccc0000 | (n))
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
 
 struct drm_nouveau_channel_alloc {
 	uint32_t     fb_ctxdma_handle;
@@ -106,6 +104,7 @@
 #define NOUVEAU_GEM_DOMAIN_MAPPABLE  (1 << 3)
 #define NOUVEAU_GEM_DOMAIN_COHERENT  (1 << 4)
 
+#define NOUVEAU_GEM_TILE_COMP        0x00030000 /* nv50-only */
 #define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00
 #define NOUVEAU_GEM_TILE_16BPP       0x00000001
 #define NOUVEAU_GEM_TILE_32BPP       0x00000002
@@ -113,40 +112,34 @@
 #define NOUVEAU_GEM_TILE_NONCONTIG   0x00000008
 
 struct drm_nouveau_gem_info {
-	uint32_t handle;
-	uint32_t domain;
-	uint64_t size;
-	uint64_t offset;
-	uint64_t map_handle;
-	uint32_t tile_mode;
-	uint32_t tile_flags;
-};
-
-struct drm_nouveau_gem_set_tiling {
-	uint32_t handle;
-	uint32_t tile_mode;
-	uint32_t tile_flags;
+	__u32 handle;
+	__u32 domain;
+	__u64 size;
+	__u64 offset;
+	__u64 map_handle;
+	__u32 tile_mode;
+	__u32 tile_flags;
 };
 
 struct drm_nouveau_gem_new {
 	struct drm_nouveau_gem_info info;
-	uint32_t channel_hint;
-	uint32_t align;
+	__u32 channel_hint;
+	__u32 align;
 };
 
 #define NOUVEAU_GEM_MAX_BUFFERS 1024
 struct drm_nouveau_gem_pushbuf_bo_presumed {
-	uint32_t valid;
-	uint32_t domain;
-	uint64_t offset;
+	__u32 valid;
+	__u32 domain;
+	__u64 offset;
 };
 
 struct drm_nouveau_gem_pushbuf_bo {
-	uint64_t user_priv;
-	uint32_t handle;
-	uint32_t read_domains;
-	uint32_t write_domains;
-	uint32_t valid_domains;
+	__u64 user_priv;
+	__u32 handle;
+	__u32 read_domains;
+	__u32 write_domains;
+	__u32 valid_domains;
 	struct drm_nouveau_gem_pushbuf_bo_presumed presumed;
 };
 
@@ -155,75 +148,47 @@
 #define NOUVEAU_GEM_RELOC_OR   (1 << 2)
 #define NOUVEAU_GEM_MAX_RELOCS 1024
 struct drm_nouveau_gem_pushbuf_reloc {
-	uint32_t reloc_bo_index;
-	uint32_t reloc_bo_offset;
-	uint32_t bo_index;
-	uint32_t flags;
-	uint32_t data;
-	uint32_t vor;
-	uint32_t tor;
+	__u32 reloc_bo_index;
+	__u32 reloc_bo_offset;
+	__u32 bo_index;
+	__u32 flags;
+	__u32 data;
+	__u32 vor;
+	__u32 tor;
 };
 
 #define NOUVEAU_GEM_MAX_PUSH 512
 struct drm_nouveau_gem_pushbuf_push {
-	uint32_t bo_index;
-	uint32_t pad;
-	uint64_t offset;
-	uint64_t length;
+	__u32 bo_index;
+	__u32 pad;
+	__u64 offset;
+	__u64 length;
 };
 
 struct drm_nouveau_gem_pushbuf {
-	uint32_t channel;
-	uint32_t nr_buffers;
-	uint64_t buffers;
-	uint32_t nr_relocs;
-	uint32_t nr_push;
-	uint64_t relocs;
-	uint64_t push;
-	uint32_t suffix0;
-	uint32_t suffix1;
-	uint64_t vram_available;
-	uint64_t gart_available;
-};
-
-#define NOUVEAU_GEM_PUSHBUF_2_FENCE_WAIT                             0x00000001
-#define NOUVEAU_GEM_PUSHBUF_2_FENCE_EMIT                             0x00000002
-struct drm_nouveau_gem_pushbuf_2 {
-	uint32_t channel;
-	uint32_t flags;
-	uint32_t nr_push;
-	uint32_t nr_buffers;
-	int32_t  fence; /* in/out, depends on flags */
-	uint32_t pad;
-	uint64_t push; /* in raw hw format */
-	uint64_t buffers; /* ptr to drm_nouveau_gem_pushbuf_bo */
-	uint64_t vram_available;
-	uint64_t gart_available;
+	__u32 channel;
+	__u32 nr_buffers;
+	__u64 buffers;
+	__u32 nr_relocs;
+	__u32 nr_push;
+	__u64 relocs;
+	__u64 push;
+	__u32 suffix0;
+	__u32 suffix1;
+	__u64 vram_available;
+	__u64 gart_available;
 };
 
 #define NOUVEAU_GEM_CPU_PREP_NOWAIT                                  0x00000001
 #define NOUVEAU_GEM_CPU_PREP_NOBLOCK                                 0x00000002
 #define NOUVEAU_GEM_CPU_PREP_WRITE                                   0x00000004
 struct drm_nouveau_gem_cpu_prep {
-	uint32_t handle;
-	uint32_t flags;
+	__u32 handle;
+	__u32 flags;
 };
 
 struct drm_nouveau_gem_cpu_fini {
-	uint32_t handle;
-};
-
-#define NOUVEAU_GEM_AS_SPARSE	0x00000001
-struct drm_nouveau_gem_as_alloc {
-	uint64_t pages;     /* in, page length */
-	uint32_t page_size; /* in, byte page size */
-	uint32_t flags; /* in, flags of address space */
-	uint64_t align; /* in, requested alignment in bytes */
-	uint64_t address; /* in/out, non-zero for fixed address allocation */
-};
-
-struct drm_nouveau_gem_as_free {
-	uint64_t address;   /* in, byte address */
+	__u32 handle;
 };
 
 enum nouveau_bus_type {
@@ -235,34 +200,6 @@
 struct drm_nouveau_sarea {
 };
 
-#define NOUVEAU_GEM_CHANNEL_FIFO_ERROR_IDLE_TIMEOUT	8
-#define NOUVEAU_GEM_CHANNEL_GR_ERROR_SW_NOTIFY		13
-#define NOUVEAU_GEM_CHANNEL_FIFO_ERROR_MMU_ERR_FLT	31
-#define NOUVEAU_GEM_CHANNEL_PBDMA_ERROR			32
-struct drm_nouveau_gem_set_error_notifier {
-	uint32_t channel;
-	uint32_t buffer;
-	uint32_t offset; /* in bytes, u32-aligned */
-};
-
-struct drm_nouveau_gem_map {
-	uint32_t handle;
-	uint32_t domain;
-	uint64_t offset;
-	uint64_t delta;
-	uint64_t length;
-	uint32_t tile_mode;
-	uint32_t tile_flags;
-};
-
-struct drm_nouveau_gem_unmap {
-	uint32_t handle;
-	uint32_t pad;
-	uint64_t offset;
-	uint64_t delta;
-	uint64_t length;
-};
-
 #define DRM_NOUVEAU_GETPARAM           0x00
 #define DRM_NOUVEAU_SETPARAM           0x01
 #define DRM_NOUVEAU_CHANNEL_ALLOC      0x02
@@ -277,14 +214,8 @@
 #define DRM_NOUVEAU_GEM_CPU_FINI       0x43
 #define DRM_NOUVEAU_GEM_INFO           0x44
 
-/* The ioctls below are marked as staging */
-#define DRM_NOUVEAU_GEM_SET_TILING     0x50
-#define DRM_NOUVEAU_GEM_PUSHBUF_2      0x51
-#define DRM_NOUVEAU_GEM_SET_INFO       0x52
-#define DRM_NOUVEAU_GEM_AS_ALLOC       0x53
-#define DRM_NOUVEAU_GEM_AS_FREE        0x54
-#define DRM_NOUVEAU_GEM_SET_ERROR_NOTIFIER 0x55
-#define DRM_NOUVEAU_GEM_MAP            0x56
-#define DRM_NOUVEAU_GEM_UNMAP          0x57
+#if defined(__cplusplus)
+}
+#endif
 
 #endif /* __NOUVEAU_DRM_H__ */
diff --git a/include/drm/nouveau_ioctl.h b/include/drm/nouveau_ioctl.h
deleted file mode 100644
index 4cd8e32..0000000
--- a/include/drm/nouveau_ioctl.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef __NVIF_IOCTL_H__
-#define __NVIF_IOCTL_H__
-
-struct nvif_ioctl_v0 {
-	__u8  version;
-#define NVIF_IOCTL_V0_OWNER_NVIF                                           0x00
-#define NVIF_IOCTL_V0_OWNER_ANY                                            0xff
-	__u8  owner;
-#define NVIF_IOCTL_V0_NOP                                                  0x00
-#define NVIF_IOCTL_V0_SCLASS                                               0x01
-#define NVIF_IOCTL_V0_NEW                                                  0x02
-#define NVIF_IOCTL_V0_DEL                                                  0x03
-#define NVIF_IOCTL_V0_MTHD                                                 0x04
-#define NVIF_IOCTL_V0_RD                                                   0x05
-#define NVIF_IOCTL_V0_WR                                                   0x06
-#define NVIF_IOCTL_V0_MAP                                                  0x07
-#define NVIF_IOCTL_V0_UNMAP                                                0x08
-#define NVIF_IOCTL_V0_NTFY_NEW                                             0x09
-#define NVIF_IOCTL_V0_NTFY_DEL                                             0x0a
-#define NVIF_IOCTL_V0_NTFY_GET                                             0x0b
-#define NVIF_IOCTL_V0_NTFY_PUT                                             0x0c
-	__u8  type;
-	__u8  path_nr;
-#define NVIF_IOCTL_V0_ROUTE_NVIF                                           0x00
-#define NVIF_IOCTL_V0_ROUTE_HIDDEN                                         0xff
-	__u8  pad04[3];
-	__u8  route;
-	__u64 token;
-	__u32 path[8];		/* in reverse */
-	__u8  data[];		/* ioctl data (below) */
-};
-
-struct nvif_ioctl_nop {
-};
-
-struct nvif_ioctl_sclass_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  count;
-	__u8  pad02[6];
-	__u32 oclass[];
-};
-
-struct nvif_ioctl_new_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  pad01[6];
-	__u8  route;
-	__u64 token;
-	__u32 handle;
-/* these class numbers are made up by us, and not nvidia-assigned */
-#define NVIF_IOCTL_NEW_V0_PERFCTR                                    0x0000ffff
-#define NVIF_IOCTL_NEW_V0_CONTROL                                    0x0000fffe
-	__u32 oclass;
-	__u8  data[];		/* class data (class.h) */
-};
-
-struct nvif_ioctl_del {
-};
-
-struct nvif_ioctl_rd_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  size;
-	__u8  pad02[2];
-	__u32 data;
-	__u64 addr;
-};
-
-struct nvif_ioctl_wr_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  size;
-	__u8  pad02[2];
-	__u32 data;
-	__u64 addr;
-};
-
-struct nvif_ioctl_map_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  pad01[3];
-	__u32 length;
-	__u64 handle;
-};
-
-struct nvif_ioctl_unmap {
-};
-
-struct nvif_ioctl_ntfy_new_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  event;
-	__u8  index;
-	__u8  pad03[5];
-	__u8  data[];		/* event request data (event.h) */
-};
-
-struct nvif_ioctl_ntfy_del_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  index;
-	__u8  pad02[6];
-};
-
-struct nvif_ioctl_ntfy_get_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  index;
-	__u8  pad02[6];
-};
-
-struct nvif_ioctl_ntfy_put_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  index;
-	__u8  pad02[6];
-};
-
-struct nvif_ioctl_mthd_v0 {
-	/* nvif_ioctl ... */
-	__u8  version;
-	__u8  method;
-	__u8  pad02[6];
-	__u8  data[];		/* method data (class.h) */
-};
-
-#endif
diff --git a/include/drm/qxl_drm.h b/include/drm/qxl_drm.h
index 1e331a8..880999d 100644
--- a/include/drm/qxl_drm.h
+++ b/include/drm/qxl_drm.h
@@ -24,13 +24,16 @@
 #ifndef QXL_DRM_H
 #define QXL_DRM_H
 
-#include <stddef.h>
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* Please note that modifications to all structs defined here are
  * subject to backwards-compatibility constraints.
  *
- * Do not use pointers, use uint64_t instead for 32 bit / 64 bit user/kernel
+ * Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel
  * compatibility Keep fields aligned to their size
  */
 
@@ -48,14 +51,14 @@
 #define DRM_QXL_ALLOC_SURF  0x06
 
 struct drm_qxl_alloc {
-	uint32_t size;
-	uint32_t handle; /* 0 is an invalid handle */
+	__u32 size;
+	__u32 handle; /* 0 is an invalid handle */
 };
 
 struct drm_qxl_map {
-	uint64_t offset; /* use for mmap system call */
-	uint32_t handle;
-	uint32_t pad;
+	__u64 offset; /* use for mmap system call */
+	__u32 handle;
+	__u32 pad;
 };
 
 /*
@@ -68,59 +71,58 @@
 #define QXL_RELOC_TYPE_SURF 2
 
 struct drm_qxl_reloc {
-	uint64_t src_offset; /* offset into src_handle or src buffer */
-	uint64_t dst_offset; /* offset in dest handle */
-	uint32_t src_handle; /* dest handle to compute address from */
-	uint32_t dst_handle; /* 0 if to command buffer */
-	uint32_t reloc_type;
-	uint32_t pad;
+	__u64 src_offset; /* offset into src_handle or src buffer */
+	__u64 dst_offset; /* offset in dest handle */
+	__u32 src_handle; /* dest handle to compute address from */
+	__u32 dst_handle; /* 0 if to command buffer */
+	__u32 reloc_type;
+	__u32 pad;
 };
 
 struct drm_qxl_command {
-	uint64_t	 command; /* void* */
-	uint64_t	 relocs; /* struct drm_qxl_reloc* */
-	uint32_t		type;
-	uint32_t		command_size;
-	uint32_t		relocs_num;
-	uint32_t                pad;
+	__u64		command; /* void* */
+	__u64		relocs; /* struct drm_qxl_reloc* */
+	__u32		type;
+	__u32		command_size;
+	__u32		relocs_num;
+	__u32                pad;
 };
 
-/* XXX: call it drm_qxl_commands? */
 struct drm_qxl_execbuffer {
-	uint32_t		flags;		/* for future use */
-	uint32_t		commands_num;
-	uint64_t	 commands;	/* struct drm_qxl_command* */
+	__u32		flags;		/* for future use */
+	__u32		commands_num;
+	__u64		commands;	/* struct drm_qxl_command* */
 };
 
 struct drm_qxl_update_area {
-	uint32_t handle;
-	uint32_t top;
-	uint32_t left;
-	uint32_t bottom;
-	uint32_t right;
-	uint32_t pad;
+	__u32 handle;
+	__u32 top;
+	__u32 left;
+	__u32 bottom;
+	__u32 right;
+	__u32 pad;
 };
 
 #define QXL_PARAM_NUM_SURFACES 1 /* rom->n_surfaces */
 #define QXL_PARAM_MAX_RELOCS 2
 struct drm_qxl_getparam {
-	uint64_t param;
-	uint64_t value;
+	__u64 param;
+	__u64 value;
 };
 
 /* these are one bit values */
 struct drm_qxl_clientcap {
-	uint32_t index;
-	uint32_t pad;
+	__u32 index;
+	__u32 pad;
 };
 
 struct drm_qxl_alloc_surf {
-	uint32_t format;
-	uint32_t width;
-	uint32_t height;
-	int32_t stride;
-	uint32_t handle;
-	uint32_t pad;
+	__u32 format;
+	__u32 width;
+	__u32 height;
+	__s32 stride;
+	__u32 handle;
+	__u32 pad;
 };
 
 #define DRM_IOCTL_QXL_ALLOC \
@@ -149,4 +151,8 @@
 	DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_ALLOC_SURF,\
 		struct drm_qxl_alloc_surf)
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/include/drm/r128_drm.h b/include/drm/r128_drm.h
index ede78ff..bf431a0 100644
--- a/include/drm/r128_drm.h
+++ b/include/drm/r128_drm.h
@@ -33,6 +33,12 @@
 #ifndef __R128_DRM_H__
 #define __R128_DRM_H__
 
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the X server file (r128_sarea.h)
  */
@@ -323,4 +329,8 @@
 	void *value;
 } drm_r128_getparam_t;
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index f09cc04..a1e385d 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -797,9 +797,9 @@
 #define RADEON_GEM_DOMAIN_VRAM		0x4
 
 struct drm_radeon_gem_info {
-	uint64_t	gart_size;
-	uint64_t	vram_size;
-	uint64_t	vram_visible;
+	__u64	gart_size;
+	__u64	vram_size;
+	__u64	vram_visible;
 };
 
 #define RADEON_GEM_NO_BACKING_STORE	(1 << 0)
@@ -811,11 +811,11 @@
 #define RADEON_GEM_NO_CPU_ACCESS	(1 << 4)
 
 struct drm_radeon_gem_create {
-	uint64_t	size;
-	uint64_t	alignment;
-	uint32_t	handle;
-	uint32_t	initial_domain;
-	uint32_t	flags;
+	__u64	size;
+	__u64	alignment;
+	__u32	handle;
+	__u32	initial_domain;
+	__u32	flags;
 };
 
 /*
@@ -829,10 +829,10 @@
 #define RADEON_GEM_USERPTR_REGISTER	(1 << 3)
 
 struct drm_radeon_gem_userptr {
-	uint64_t		addr;
-	uint64_t		size;
-	uint32_t		flags;
-	uint32_t		handle;
+	__u64		addr;
+	__u64		size;
+	__u32		flags;
+	__u32		handle;
 };
 
 #define RADEON_TILING_MACRO				0x1
@@ -855,72 +855,72 @@
 #define RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK	0xf
 
 struct drm_radeon_gem_set_tiling {
-	uint32_t	handle;
-	uint32_t	tiling_flags;
-	uint32_t	pitch;
+	__u32	handle;
+	__u32	tiling_flags;
+	__u32	pitch;
 };
 
 struct drm_radeon_gem_get_tiling {
-	uint32_t	handle;
-	uint32_t	tiling_flags;
-	uint32_t	pitch;
+	__u32	handle;
+	__u32	tiling_flags;
+	__u32	pitch;
 };
 
 struct drm_radeon_gem_mmap {
-	uint32_t	handle;
-	uint32_t	pad;
-	uint64_t	offset;
-	uint64_t	size;
-	uint64_t	addr_ptr;
+	__u32	handle;
+	__u32	pad;
+	__u64	offset;
+	__u64	size;
+	__u64	addr_ptr;
 };
 
 struct drm_radeon_gem_set_domain {
-	uint32_t	handle;
-	uint32_t	read_domains;
-	uint32_t	write_domain;
+	__u32	handle;
+	__u32	read_domains;
+	__u32	write_domain;
 };
 
 struct drm_radeon_gem_wait_idle {
-	uint32_t	handle;
-	uint32_t	pad;
+	__u32	handle;
+	__u32	pad;
 };
 
 struct drm_radeon_gem_busy {
-	uint32_t	handle;
-	uint32_t        domain;
+	__u32	handle;
+	__u32        domain;
 };
 
 struct drm_radeon_gem_pread {
 	/** Handle for the object being read. */
-	uint32_t handle;
-	uint32_t pad;
+	__u32 handle;
+	__u32 pad;
 	/** Offset into the object to read from */
-	uint64_t offset;
+	__u64 offset;
 	/** Length of data to read */
-	uint64_t size;
+	__u64 size;
 	/** Pointer to write the data into. */
 	/* void *, but pointers are not 32/64 compatible */
-	uint64_t data_ptr;
+	__u64 data_ptr;
 };
 
 struct drm_radeon_gem_pwrite {
 	/** Handle for the object being written to. */
-	uint32_t handle;
-	uint32_t pad;
+	__u32 handle;
+	__u32 pad;
 	/** Offset into the object to write to */
-	uint64_t offset;
+	__u64 offset;
 	/** Length of data to write */
-	uint64_t size;
+	__u64 size;
 	/** Pointer to read the data from. */
 	/* void *, but pointers are not 32/64 compatible */
-	uint64_t data_ptr;
+	__u64 data_ptr;
 };
 
 /* Sets or returns a value associated with a buffer. */
 struct drm_radeon_gem_op {
-	uint32_t	handle; /* buffer */
-	uint32_t	op;     /* RADEON_GEM_OP_* */
-	uint64_t	value;  /* input or return value */
+	__u32	handle; /* buffer */
+	__u32	op;     /* RADEON_GEM_OP_* */
+	__u64	value;  /* input or return value */
 };
 
 #define RADEON_GEM_OP_GET_INITIAL_DOMAIN	0
@@ -940,11 +940,11 @@
 #define RADEON_VM_PAGE_SNOOPED		(1 << 4)
 
 struct drm_radeon_gem_va {
-	uint32_t		handle;
-	uint32_t		operation;
-	uint32_t		vm_id;
-	uint32_t		flags;
-	uint64_t		offset;
+	__u32		handle;
+	__u32		operation;
+	__u32		vm_id;
+	__u32		flags;
+	__u64		offset;
 };
 
 #define RADEON_CHUNK_ID_RELOCS	0x01
@@ -966,29 +966,29 @@
 /* 0 = normal, + = higher priority, - = lower priority */
 
 struct drm_radeon_cs_chunk {
-	uint32_t		chunk_id;
-	uint32_t		length_dw;
-	uint64_t		chunk_data;
+	__u32		chunk_id;
+	__u32		length_dw;
+	__u64		chunk_data;
 };
 
 /* drm_radeon_cs_reloc.flags */
 #define RADEON_RELOC_PRIO_MASK		(0xf << 0)
 
 struct drm_radeon_cs_reloc {
-	uint32_t		handle;
-	uint32_t		read_domains;
-	uint32_t		write_domain;
-	uint32_t		flags;
+	__u32		handle;
+	__u32		read_domains;
+	__u32		write_domain;
+	__u32		flags;
 };
 
 struct drm_radeon_cs {
-	uint32_t		num_chunks;
-	uint32_t		cs_id;
-	/* this points to uint64_t * which point to cs chunks */
-	uint64_t		chunks;
+	__u32		num_chunks;
+	__u32		cs_id;
+	/* this points to __u64 * which point to cs chunks */
+	__u64		chunks;
 	/* updates to the limits after this CS ioctl */
-	uint64_t		gart_limit;
-	uint64_t		vram_limit;
+	__u64		gart_limit;
+	__u64		vram_limit;
 };
 
 #define RADEON_INFO_DEVICE_ID		0x00
@@ -1047,9 +1047,9 @@
 #define RADEON_INFO_GPU_RESET_COUNTER	0x26
 
 struct drm_radeon_info {
-	uint32_t		request;
-	uint32_t		pad;
-	uint64_t		value;
+	__u32		request;
+	__u32		pad;
+	__u64		value;
 };
 
 /* Those correspond to the tile index to use, this is to explicitly state
diff --git a/include/drm/savage_drm.h b/include/drm/savage_drm.h
index f7a75ef..1a91234 100644
--- a/include/drm/savage_drm.h
+++ b/include/drm/savage_drm.h
@@ -26,10 +26,16 @@
 #ifndef __SAVAGE_DRM_H__
 #define __SAVAGE_DRM_H__
 
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #ifndef __SAVAGE_SAREA_DEFINES__
 #define __SAVAGE_SAREA_DEFINES__
 
-/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
+/* 2 heaps (1 for card, 1 for agp), each divided into up to 128
  * regions, subject to a minimum region size of (1<<16) == 64k.
  *
  * Clients may subdivide regions internally, but when sharing between
@@ -63,10 +69,10 @@
 #define DRM_SAVAGE_BCI_EVENT_EMIT	0x02
 #define DRM_SAVAGE_BCI_EVENT_WAIT	0x03
 
-#define DRM_IOCTL_SAVAGE_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t)
-#define DRM_IOCTL_SAVAGE_CMDBUF		DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t)
-#define DRM_IOCTL_SAVAGE_EVENT_EMIT	DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t)
-#define DRM_IOCTL_SAVAGE_EVENT_WAIT	DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t)
+#define DRM_IOCTL_SAVAGE_BCI_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t)
+#define DRM_IOCTL_SAVAGE_BCI_CMDBUF		DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t)
+#define DRM_IOCTL_SAVAGE_BCI_EVENT_EMIT	DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t)
+#define DRM_IOCTL_SAVAGE_BCI_EVENT_WAIT	DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t)
 
 #define SAVAGE_DMA_PCI	1
 #define SAVAGE_DMA_AGP	3
@@ -207,4 +213,8 @@
 	} clear1;		/* SAVAGE_CMD_CLEAR data */
 };
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/include/drm/sis_drm.h b/include/drm/sis_drm.h
index 30f7b38..8e51bb9 100644
--- a/include/drm/sis_drm.h
+++ b/include/drm/sis_drm.h
@@ -27,6 +27,12 @@
 #ifndef __SIS_DRM_H__
 #define __SIS_DRM_H__
 
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* SiS specific ioctls */
 #define NOT_USED_0_3
 #define DRM_SIS_FB_ALLOC	0x04
@@ -64,4 +70,8 @@
 	unsigned int offset, size;
 } drm_sis_fb_t;
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif				/* __SIS_DRM_H__ */
diff --git a/include/drm/tegra_drm.h b/include/drm/tegra_drm.h
index 1be09c4..6c07919 100644
--- a/include/drm/tegra_drm.h
+++ b/include/drm/tegra_drm.h
@@ -1,196 +1,649 @@
 /*
  * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
+ * 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:
  *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * 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 _UAPI_TEGRA_DRM_H_
-#define _UAPI_TEGRA_DRM_H_
+#ifndef _TEGRA_DRM_H_
+#define _TEGRA_DRM_H_
 
-#include <drm/drm.h>
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
 
 #define DRM_TEGRA_GEM_CREATE_TILED     (1 << 0)
 #define DRM_TEGRA_GEM_CREATE_BOTTOM_UP (1 << 1)
 
+/**
+ * struct drm_tegra_gem_create - parameters for the GEM object creation IOCTL
+ */
 struct drm_tegra_gem_create {
+	/**
+	 * @size:
+	 *
+	 * The size, in bytes, of the buffer object to be created.
+	 */
 	__u64 size;
+
+	/**
+	 * @flags:
+	 *
+	 * A bitmask of flags that influence the creation of GEM objects:
+	 *
+	 * DRM_TEGRA_GEM_CREATE_TILED
+	 *   Use the 16x16 tiling format for this buffer.
+	 *
+	 * DRM_TEGRA_GEM_CREATE_BOTTOM_UP
+	 *   The buffer has a bottom-up layout.
+	 */
 	__u32 flags;
+
+	/**
+	 * @handle:
+	 *
+	 * The handle of the created GEM object. Set by the kernel upon
+	 * successful completion of the IOCTL.
+	 */
 	__u32 handle;
 };
 
+/**
+ * struct drm_tegra_gem_mmap - parameters for the GEM mmap IOCTL
+ */
 struct drm_tegra_gem_mmap {
+	/**
+	 * @handle:
+	 *
+	 * Handle of the GEM object to obtain an mmap offset for.
+	 */
 	__u32 handle;
+
+	/**
+	 * @pad:
+	 *
+	 * Structure padding that may be used in the future. Must be 0.
+	 */
 	__u32 pad;
+
+	/**
+	 * @offset:
+	 *
+	 * The mmap offset for the given GEM object. Set by the kernel upon
+	 * successful completion of the IOCTL.
+	 */
 	__u64 offset;
 };
 
+/**
+ * struct drm_tegra_syncpt_read - parameters for the read syncpoint IOCTL
+ */
 struct drm_tegra_syncpt_read {
+	/**
+	 * @id:
+	 *
+	 * ID of the syncpoint to read the current value from.
+	 */
 	__u32 id;
+
+	/**
+	 * @value:
+	 *
+	 * The current syncpoint value. Set by the kernel upon successful
+	 * completion of the IOCTL.
+	 */
 	__u32 value;
 };
 
+/**
+ * struct drm_tegra_syncpt_incr - parameters for the increment syncpoint IOCTL
+ */
 struct drm_tegra_syncpt_incr {
+	/**
+	 * @id:
+	 *
+	 * ID of the syncpoint to increment.
+	 */
 	__u32 id;
+
+	/**
+	 * @pad:
+	 *
+	 * Structure padding that may be used in the future. Must be 0.
+	 */
 	__u32 pad;
 };
 
+/**
+ * struct drm_tegra_syncpt_wait - parameters for the wait syncpoint IOCTL
+ */
 struct drm_tegra_syncpt_wait {
+	/**
+	 * @id:
+	 *
+	 * ID of the syncpoint to wait on.
+	 */
 	__u32 id;
+
+	/**
+	 * @thresh:
+	 *
+	 * Threshold value for which to wait.
+	 */
 	__u32 thresh;
+
+	/**
+	 * @timeout:
+	 *
+	 * Timeout, in milliseconds, to wait.
+	 */
 	__u32 timeout;
+
+	/**
+	 * @value:
+	 *
+	 * The new syncpoint value after the wait. Set by the kernel upon
+	 * successful completion of the IOCTL.
+	 */
 	__u32 value;
 };
 
 #define DRM_TEGRA_NO_TIMEOUT	(0xffffffff)
 
+/**
+ * struct drm_tegra_open_channel - parameters for the open channel IOCTL
+ */
 struct drm_tegra_open_channel {
+	/**
+	 * @client:
+	 *
+	 * The client ID for this channel.
+	 */
 	__u32 client;
+
+	/**
+	 * @pad:
+	 *
+	 * Structure padding that may be used in the future. Must be 0.
+	 */
 	__u32 pad;
+
+	/**
+	 * @context:
+	 *
+	 * The application context of this channel. Set by the kernel upon
+	 * successful completion of the IOCTL. This context needs to be passed
+	 * to the DRM_TEGRA_CHANNEL_CLOSE or the DRM_TEGRA_SUBMIT IOCTLs.
+	 */
 	__u64 context;
 };
 
+/**
+ * struct drm_tegra_close_channel - parameters for the close channel IOCTL
+ */
 struct drm_tegra_close_channel {
+	/**
+	 * @context:
+	 *
+	 * The application context of this channel. This is obtained from the
+	 * DRM_TEGRA_OPEN_CHANNEL IOCTL.
+	 */
 	__u64 context;
 };
 
+/**
+ * struct drm_tegra_get_syncpt - parameters for the get syncpoint IOCTL
+ */
 struct drm_tegra_get_syncpt {
+	/**
+	 * @context:
+	 *
+	 * The application context identifying the channel for which to obtain
+	 * the syncpoint ID.
+	 */
 	__u64 context;
+
+	/**
+	 * @index:
+	 *
+	 * Index of the client syncpoint for which to obtain the ID.
+	 */
 	__u32 index;
+
+	/**
+	 * @id:
+	 *
+	 * The ID of the given syncpoint. Set by the kernel upon successful
+	 * completion of the IOCTL.
+	 */
 	__u32 id;
 };
 
+/**
+ * struct drm_tegra_get_syncpt_base - parameters for the get wait base IOCTL
+ */
 struct drm_tegra_get_syncpt_base {
+	/**
+	 * @context:
+	 *
+	 * The application context identifying for which channel to obtain the
+	 * wait base.
+	 */
 	__u64 context;
+
+	/**
+	 * @syncpt:
+	 *
+	 * ID of the syncpoint for which to obtain the wait base.
+	 */
 	__u32 syncpt;
+
+	/**
+	 * @id:
+	 *
+	 * The ID of the wait base corresponding to the client syncpoint. Set
+	 * by the kernel upon successful completion of the IOCTL.
+	 */
 	__u32 id;
 };
 
+/**
+ * struct drm_tegra_syncpt - syncpoint increment operation
+ */
 struct drm_tegra_syncpt {
+	/**
+	 * @id:
+	 *
+	 * ID of the syncpoint to operate on.
+	 */
 	__u32 id;
+
+	/**
+	 * @incrs:
+	 *
+	 * Number of increments to perform for the syncpoint.
+	 */
 	__u32 incrs;
 };
 
+/**
+ * struct drm_tegra_cmdbuf - structure describing a command buffer
+ */
 struct drm_tegra_cmdbuf {
+	/**
+	 * @handle:
+	 *
+	 * Handle to a GEM object containing the command buffer.
+	 */
 	__u32 handle;
+
+	/**
+	 * @offset:
+	 *
+	 * Offset, in bytes, into the GEM object identified by @handle at
+	 * which the command buffer starts.
+	 */
 	__u32 offset;
+
+	/**
+	 * @words:
+	 *
+	 * Number of 32-bit words in this command buffer.
+	 */
 	__u32 words;
+
+	/**
+	 * @pad:
+	 *
+	 * Structure padding that may be used in the future. Must be 0.
+	 */
 	__u32 pad;
 };
 
+/**
+ * struct drm_tegra_reloc - GEM object relocation structure
+ */
 struct drm_tegra_reloc {
 	struct {
+		/**
+		 * @cmdbuf.handle:
+		 *
+		 * Handle to the GEM object containing the command buffer for
+		 * which to perform this GEM object relocation.
+		 */
 		__u32 handle;
+
+		/**
+		 * @cmdbuf.offset:
+		 *
+		 * Offset, in bytes, into the command buffer at which to
+		 * insert the relocated address.
+		 */
 		__u32 offset;
 	} cmdbuf;
 	struct {
+		/**
+		 * @target.handle:
+		 *
+		 * Handle to the GEM object to be relocated.
+		 */
 		__u32 handle;
+
+		/**
+		 * @target.offset:
+		 *
+		 * Offset, in bytes, into the target GEM object at which the
+		 * relocated data starts.
+		 */
 		__u32 offset;
 	} target;
+
+	/**
+	 * @shift:
+	 *
+	 * The number of bits by which to shift relocated addresses.
+	 */
 	__u32 shift;
+
+	/**
+	 * @pad:
+	 *
+	 * Structure padding that may be used in the future. Must be 0.
+	 */
 	__u32 pad;
 };
 
+/**
+ * struct drm_tegra_waitchk - wait check structure
+ */
 struct drm_tegra_waitchk {
+	/**
+	 * @handle:
+	 *
+	 * Handle to the GEM object containing a command stream on which to
+	 * perform the wait check.
+	 */
 	__u32 handle;
+
+	/**
+	 * @offset:
+	 *
+	 * Offset, in bytes, of the location in the command stream to perform
+	 * the wait check on.
+	 */
 	__u32 offset;
+
+	/**
+	 * @syncpt:
+	 *
+	 * ID of the syncpoint to wait check.
+	 */
 	__u32 syncpt;
+
+	/**
+	 * @thresh:
+	 *
+	 * Threshold value for which to check.
+	 */
 	__u32 thresh;
 };
 
+/**
+ * struct drm_tegra_submit - job submission structure
+ */
 struct drm_tegra_submit {
+	/**
+	 * @context:
+	 *
+	 * The application context identifying the channel to use for the
+	 * execution of this job.
+	 */
 	__u64 context;
-	__u32 num_syncpts;
-	__u32 num_cmdbufs;
-	__u32 num_relocs;
-	__u32 num_waitchks;
-	__u32 waitchk_mask;
-	__u32 timeout;
-	__u32 pad;
-	__u64 syncpts;
-	__u64 cmdbufs;
-	__u64 relocs;
-	__u64 waitchks;
-	__u32 fence;		/* Return value */
 
-	__u32 reserved[5];	/* future expansion */
+	/**
+	 * @num_syncpts:
+	 *
+	 * The number of syncpoints operated on by this job. This defines the
+	 * length of the array pointed to by @syncpts.
+	 */
+	__u32 num_syncpts;
+
+	/**
+	 * @num_cmdbufs:
+	 *
+	 * The number of command buffers to execute as part of this job. This
+	 * defines the length of the array pointed to by @cmdbufs.
+	 */
+	__u32 num_cmdbufs;
+
+	/**
+	 * @num_relocs:
+	 *
+	 * The number of relocations to perform before executing this job.
+	 * This defines the length of the array pointed to by @relocs.
+	 */
+	__u32 num_relocs;
+
+	/**
+	 * @num_waitchks:
+	 *
+	 * The number of wait checks to perform as part of this job. This
+	 * defines the length of the array pointed to by @waitchks.
+	 */
+	__u32 num_waitchks;
+
+	/**
+	 * @waitchk_mask:
+	 *
+	 * Bitmask of valid wait checks.
+	 */
+	__u32 waitchk_mask;
+
+	/**
+	 * @timeout:
+	 *
+	 * Timeout, in milliseconds, before this job is cancelled.
+	 */
+	__u32 timeout;
+
+	/**
+	 * @syncpts:
+	 *
+	 * A pointer to an array of &struct drm_tegra_syncpt structures that
+	 * specify the syncpoint operations performed as part of this job.
+	 * The number of elements in the array must be equal to the value
+	 * given by @num_syncpts.
+	 */
+	__u64 syncpts;
+
+	/**
+	 * @cmdbufs:
+	 *
+	 * A pointer to an array of &struct drm_tegra_cmdbuf structures that
+	 * define the command buffers to execute as part of this job. The
+	 * number of elements in the array must be equal to the value given
+	 * by @num_syncpts.
+	 */
+	__u64 cmdbufs;
+
+	/**
+	 * @relocs:
+	 *
+	 * A pointer to an array of &struct drm_tegra_reloc structures that
+	 * specify the relocations that need to be performed before executing
+	 * this job. The number of elements in the array must be equal to the
+	 * value given by @num_relocs.
+	 */
+	__u64 relocs;
+
+	/**
+	 * @waitchks:
+	 *
+	 * A pointer to an array of &struct drm_tegra_waitchk structures that
+	 * specify the wait checks to be performed while executing this job.
+	 * The number of elements in the array must be equal to the value
+	 * given by @num_waitchks.
+	 */
+	__u64 waitchks;
+
+	/**
+	 * @fence:
+	 *
+	 * The threshold of the syncpoint associated with this job after it
+	 * has been completed. Set by the kernel upon successful completion of
+	 * the IOCTL. This can be used with the DRM_TEGRA_SYNCPT_WAIT IOCTL to
+	 * wait for this job to be finished.
+	 */
+	__u32 fence;
+
+	/**
+	 * @reserved:
+	 *
+	 * This field is reserved for future use. Must be 0.
+	 */
+	__u32 reserved[5];
 };
 
 #define DRM_TEGRA_GEM_TILING_MODE_PITCH 0
 #define DRM_TEGRA_GEM_TILING_MODE_TILED 1
 #define DRM_TEGRA_GEM_TILING_MODE_BLOCK 2
 
+/**
+ * struct drm_tegra_gem_set_tiling - parameters for the set tiling IOCTL
+ */
 struct drm_tegra_gem_set_tiling {
-	/* input */
+	/**
+	 * @handle:
+	 *
+	 * Handle to the GEM object for which to set the tiling parameters.
+	 */
 	__u32 handle;
+
+	/**
+	 * @mode:
+	 *
+	 * The tiling mode to set. Must be one of:
+	 *
+	 * DRM_TEGRA_GEM_TILING_MODE_PITCH
+	 *   pitch linear format
+	 *
+	 * DRM_TEGRA_GEM_TILING_MODE_TILED
+	 *   16x16 tiling format
+	 *
+	 * DRM_TEGRA_GEM_TILING_MODE_BLOCK
+	 *   16Bx2 tiling format
+	 */
 	__u32 mode;
+
+	/**
+	 * @value:
+	 *
+	 * The value to set for the tiling mode parameter.
+	 */
 	__u32 value;
+
+	/**
+	 * @pad:
+	 *
+	 * Structure padding that may be used in the future. Must be 0.
+	 */
 	__u32 pad;
 };
 
+/**
+ * struct drm_tegra_gem_get_tiling - parameters for the get tiling IOCTL
+ */
 struct drm_tegra_gem_get_tiling {
-	/* input */
+	/**
+	 * @handle:
+	 *
+	 * Handle to the GEM object for which to query the tiling parameters.
+	 */
 	__u32 handle;
-	/* output */
+
+	/**
+	 * @mode:
+	 *
+	 * The tiling mode currently associated with the GEM object. Set by
+	 * the kernel upon successful completion of the IOCTL.
+	 */
 	__u32 mode;
+
+	/**
+	 * @value:
+	 *
+	 * The tiling mode parameter currently associated with the GEM object.
+	 * Set by the kernel upon successful completion of the IOCTL.
+	 */
 	__u32 value;
+
+	/**
+	 * @pad:
+	 *
+	 * Structure padding that may be used in the future. Must be 0.
+	 */
 	__u32 pad;
 };
 
 #define DRM_TEGRA_GEM_BOTTOM_UP		(1 << 0)
 #define DRM_TEGRA_GEM_FLAGS		(DRM_TEGRA_GEM_BOTTOM_UP)
 
+/**
+ * struct drm_tegra_gem_set_flags - parameters for the set flags IOCTL
+ */
 struct drm_tegra_gem_set_flags {
-	/* input */
+	/**
+	 * @handle:
+	 *
+	 * Handle to the GEM object for which to set the flags.
+	 */
 	__u32 handle;
-	/* output */
+
+	/**
+	 * @flags:
+	 *
+	 * The flags to set for the GEM object.
+	 */
 	__u32 flags;
 };
 
+/**
+ * struct drm_tegra_gem_get_flags - parameters for the get flags IOCTL
+ */
 struct drm_tegra_gem_get_flags {
-	/* input */
+	/**
+	 * @handle:
+	 *
+	 * Handle to the GEM object for which to query the flags.
+	 */
 	__u32 handle;
-	/* output */
+
+	/**
+	 * @flags:
+	 *
+	 * The flags currently associated with the GEM object. Set by the
+	 * kernel upon successful completion of the IOCTL.
+	 */
 	__u32 flags;
 };
 
-enum request_type {
-	DRM_TEGRA_REQ_TYPE_CLK_KHZ = 0,
-	DRM_TEGRA_REQ_TYPE_BW_KBPS,
-};
-
-struct drm_tegra_get_clk_rate {
-	/* class ID*/
-	__u32 id;
-	/* request type: KBps or KHz */
-	__u32 type;
-	/* numeric value for type */
-	__u64 data;
-};
-
-struct drm_tegra_set_clk_rate {
-	/* class ID*/
-	__u32 id;
-	/* request type: KBps or KHz */
-	__u32 type;
-	/* numeric value for type */
-	__u64 data;
-};
-
-struct drm_tegra_keepon {
-	/* channel context (from opening a channel) */
-	__u64 context;
-};
-
 #define DRM_TEGRA_GEM_CREATE		0x00
 #define DRM_TEGRA_GEM_MMAP		0x01
 #define DRM_TEGRA_SYNCPT_READ		0x02
@@ -205,10 +658,6 @@
 #define DRM_TEGRA_GEM_GET_TILING	0x0b
 #define DRM_TEGRA_GEM_SET_FLAGS		0x0c
 #define DRM_TEGRA_GEM_GET_FLAGS		0x0d
-#define DRM_TEGRA_GET_CLK_RATE		0x0e
-#define DRM_TEGRA_SET_CLK_RATE		0x0f
-#define DRM_TEGRA_START_KEEPON		0x10
-#define DRM_TEGRA_STOP_KEEPON		0x11
 
 #define DRM_IOCTL_TEGRA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_CREATE, struct drm_tegra_gem_create)
 #define DRM_IOCTL_TEGRA_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_MMAP, struct drm_tegra_gem_mmap)
@@ -216,7 +665,7 @@
 #define DRM_IOCTL_TEGRA_SYNCPT_INCR DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_INCR, struct drm_tegra_syncpt_incr)
 #define DRM_IOCTL_TEGRA_SYNCPT_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_WAIT, struct drm_tegra_syncpt_wait)
 #define DRM_IOCTL_TEGRA_OPEN_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_OPEN_CHANNEL, struct drm_tegra_open_channel)
-#define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_open_channel)
+#define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_close_channel)
 #define DRM_IOCTL_TEGRA_GET_SYNCPT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT, struct drm_tegra_get_syncpt)
 #define DRM_IOCTL_TEGRA_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SUBMIT, struct drm_tegra_submit)
 #define DRM_IOCTL_TEGRA_GET_SYNCPT_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT_BASE, struct drm_tegra_get_syncpt_base)
@@ -224,9 +673,9 @@
 #define DRM_IOCTL_TEGRA_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_TILING, struct drm_tegra_gem_get_tiling)
 #define DRM_IOCTL_TEGRA_GEM_SET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_FLAGS, struct drm_tegra_gem_set_flags)
 #define DRM_IOCTL_TEGRA_GEM_GET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_FLAGS, struct drm_tegra_gem_get_flags)
-#define DRM_IOCTL_TEGRA_GET_CLK_RATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_CLK_RATE, struct drm_tegra_get_clk_rate)
-#define DRM_IOCTL_TEGRA_SET_CLK_RATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SET_CLK_RATE, struct drm_tegra_set_clk_rate)
-#define DRM_IOCTL_TEGRA_START_KEEPON DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_START_KEEPON, struct drm_tegra_keepon)
-#define DRM_IOCTL_TEGRA_STOP_KEEPON DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_STOP_KEEPON, struct drm_tegra_keepon)
+
+#if defined(__cplusplus)
+}
+#endif
 
 #endif
diff --git a/include/drm/vc4_drm.h b/include/drm/vc4_drm.h
index 319881d..31f50de 100644
--- a/include/drm/vc4_drm.h
+++ b/include/drm/vc4_drm.h
@@ -38,6 +38,13 @@
 #define DRM_VC4_CREATE_SHADER_BO                  0x05
 #define DRM_VC4_GET_HANG_STATE                    0x06
 #define DRM_VC4_GET_PARAM                         0x07
+#define DRM_VC4_SET_TILING                        0x08
+#define DRM_VC4_GET_TILING                        0x09
+#define DRM_VC4_LABEL_BO                          0x0a
+#define DRM_VC4_GEM_MADVISE                       0x0b
+#define DRM_VC4_PERFMON_CREATE                    0x0c
+#define DRM_VC4_PERFMON_DESTROY                   0x0d
+#define DRM_VC4_PERFMON_GET_VALUES                0x0e
 
 #define DRM_IOCTL_VC4_SUBMIT_CL           DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
 #define DRM_IOCTL_VC4_WAIT_SEQNO          DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
@@ -47,6 +54,13 @@
 #define DRM_IOCTL_VC4_CREATE_SHADER_BO    DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
 #define DRM_IOCTL_VC4_GET_HANG_STATE      DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
 #define DRM_IOCTL_VC4_GET_PARAM           DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_PARAM, struct drm_vc4_get_param)
+#define DRM_IOCTL_VC4_SET_TILING          DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SET_TILING, struct drm_vc4_set_tiling)
+#define DRM_IOCTL_VC4_GET_TILING          DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling)
+#define DRM_IOCTL_VC4_LABEL_BO            DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo)
+#define DRM_IOCTL_VC4_GEM_MADVISE         DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GEM_MADVISE, struct drm_vc4_gem_madvise)
+#define DRM_IOCTL_VC4_PERFMON_CREATE      DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_CREATE, struct drm_vc4_perfmon_create)
+#define DRM_IOCTL_VC4_PERFMON_DESTROY     DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_DESTROY, struct drm_vc4_perfmon_destroy)
+#define DRM_IOCTL_VC4_PERFMON_GET_VALUES  DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_GET_VALUES, struct drm_vc4_perfmon_get_values)
 
 struct drm_vc4_submit_rcl_surface {
 	__u32 hindex; /* Handle index, or ~0 if not present. */
@@ -149,12 +163,38 @@
 	__u32 pad:24;
 
 #define VC4_SUBMIT_CL_USE_CLEAR_COLOR			(1 << 0)
+/* By default, the kernel gets to choose the order that the tiles are
+ * rendered in.  If this is set, then the tiles will be rendered in a
+ * raster order, with the right-to-left vs left-to-right and
+ * top-to-bottom vs bottom-to-top dictated by
+ * VC4_SUBMIT_CL_RCL_ORDER_INCREASING_*.  This allows overlapping
+ * blits to be implemented using the 3D engine.
+ */
+#define VC4_SUBMIT_CL_FIXED_RCL_ORDER			(1 << 1)
+#define VC4_SUBMIT_CL_RCL_ORDER_INCREASING_X		(1 << 2)
+#define VC4_SUBMIT_CL_RCL_ORDER_INCREASING_Y		(1 << 3)
 	__u32 flags;
 
 	/* Returned value of the seqno of this render job (for the
 	 * wait ioctl).
 	 */
 	__u64 seqno;
+
+	/* ID of the perfmon to attach to this job. 0 means no perfmon. */
+	__u32 perfmonid;
+
+	/* Syncobj handle to wait on. If set, processing of this render job
+	 * will not start until the syncobj is signaled. 0 means ignore.
+	 */
+	__u32 in_sync;
+
+	/* Syncobj handle to export fence to. If set, the fence in the syncobj
+	 * will be replaced with a fence that signals upon completion of this
+	 * render job. 0 means ignore.
+	 */
+	__u32 out_sync;
+
+	__u32 pad2;
 };
 
 /**
@@ -288,6 +328,9 @@
 #define DRM_VC4_PARAM_SUPPORTS_BRANCHES		3
 #define DRM_VC4_PARAM_SUPPORTS_ETC1		4
 #define DRM_VC4_PARAM_SUPPORTS_THREADED_FS	5
+#define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER	6
+#define DRM_VC4_PARAM_SUPPORTS_MADVISE		7
+#define DRM_VC4_PARAM_SUPPORTS_PERFMON		8
 
 struct drm_vc4_get_param {
 	__u32 param;
@@ -295,6 +338,103 @@
 	__u64 value;
 };
 
+struct drm_vc4_get_tiling {
+	__u32 handle;
+	__u32 flags;
+	__u64 modifier;
+};
+
+struct drm_vc4_set_tiling {
+	__u32 handle;
+	__u32 flags;
+	__u64 modifier;
+};
+
+/**
+ * struct drm_vc4_label_bo - Attach a name to a BO for debug purposes.
+ */
+struct drm_vc4_label_bo {
+	__u32 handle;
+	__u32 len;
+	__u64 name;
+};
+
+/*
+ * States prefixed with '__' are internal states and cannot be passed to the
+ * DRM_IOCTL_VC4_GEM_MADVISE ioctl.
+ */
+#define VC4_MADV_WILLNEED			0
+#define VC4_MADV_DONTNEED			1
+#define __VC4_MADV_PURGED			2
+#define __VC4_MADV_NOTSUPP			3
+
+struct drm_vc4_gem_madvise {
+	__u32 handle;
+	__u32 madv;
+	__u32 retained;
+	__u32 pad;
+};
+
+enum {
+	VC4_PERFCNT_FEP_VALID_PRIMS_NO_RENDER,
+	VC4_PERFCNT_FEP_VALID_PRIMS_RENDER,
+	VC4_PERFCNT_FEP_CLIPPED_QUADS,
+	VC4_PERFCNT_FEP_VALID_QUADS,
+	VC4_PERFCNT_TLB_QUADS_NOT_PASSING_STENCIL,
+	VC4_PERFCNT_TLB_QUADS_NOT_PASSING_Z_AND_STENCIL,
+	VC4_PERFCNT_TLB_QUADS_PASSING_Z_AND_STENCIL,
+	VC4_PERFCNT_TLB_QUADS_ZERO_COVERAGE,
+	VC4_PERFCNT_TLB_QUADS_NON_ZERO_COVERAGE,
+	VC4_PERFCNT_TLB_QUADS_WRITTEN_TO_COLOR_BUF,
+	VC4_PERFCNT_PLB_PRIMS_OUTSIDE_VIEWPORT,
+	VC4_PERFCNT_PLB_PRIMS_NEED_CLIPPING,
+	VC4_PERFCNT_PSE_PRIMS_REVERSED,
+	VC4_PERFCNT_QPU_TOTAL_IDLE_CYCLES,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_VERTEX_COORD_SHADING,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_FRAGMENT_SHADING,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_EXEC_VALID_INST,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_TMUS,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_SCOREBOARD,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_VARYINGS,
+	VC4_PERFCNT_QPU_TOTAL_INST_CACHE_HIT,
+	VC4_PERFCNT_QPU_TOTAL_INST_CACHE_MISS,
+	VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_HIT,
+	VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_MISS,
+	VC4_PERFCNT_TMU_TOTAL_TEXT_QUADS_PROCESSED,
+	VC4_PERFCNT_TMU_TOTAL_TEXT_CACHE_MISS,
+	VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VDW_STALLED,
+	VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VCD_STALLED,
+	VC4_PERFCNT_L2C_TOTAL_L2_CACHE_HIT,
+	VC4_PERFCNT_L2C_TOTAL_L2_CACHE_MISS,
+	VC4_PERFCNT_NUM_EVENTS,
+};
+
+#define DRM_VC4_MAX_PERF_COUNTERS	16
+
+struct drm_vc4_perfmon_create {
+	__u32 id;
+	__u32 ncounters;
+	__u8 events[DRM_VC4_MAX_PERF_COUNTERS];
+};
+
+struct drm_vc4_perfmon_destroy {
+	__u32 id;
+};
+
+/*
+ * Returns the values of the performance counters tracked by this
+ * perfmon (as an array of ncounters u64 values).
+ *
+ * No implicit synchronization is performed, so the user has to
+ * guarantee that any jobs using this perfmon have already been
+ * completed  (probably by blocking on the seqno returned by the
+ * last exec that used the perfmon).
+ */
+struct drm_vc4_perfmon_get_values {
+	__u32 id;
+	__u64 values_ptr;
+};
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/include/drm/via_drm.h b/include/drm/via_drm.h
index 182f879..8b69e81 100644
--- a/include/drm/via_drm.h
+++ b/include/drm/via_drm.h
@@ -26,6 +26,10 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* WARNING: These defines must be the same as what the Xserver uses.
  * if you change them, you must change the defines in the Xserver.
  */
@@ -272,4 +276,8 @@
 	drm_via_blitsync_t sync;
 } drm_via_dmablit_t;
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif				/* _VIA_DRM_H_ */
diff --git a/include/drm/virtgpu_drm.h b/include/drm/virtgpu_drm.h
index 91a31ff..9a781f0 100644
--- a/include/drm/virtgpu_drm.h
+++ b/include/drm/virtgpu_drm.h
@@ -63,6 +63,7 @@
 };
 
 #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
+#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */
 
 struct drm_virtgpu_getparam {
 	__u64 param;
diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h
index 5b68b4d..0bc784f 100644
--- a/include/drm/vmwgfx_drm.h
+++ b/include/drm/vmwgfx_drm.h
@@ -30,6 +30,10 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define DRM_VMW_MAX_SURFACE_FACES 6
 #define DRM_VMW_MAX_MIP_LEVELS 24
 
@@ -37,6 +41,7 @@
 #define DRM_VMW_GET_PARAM            0
 #define DRM_VMW_ALLOC_DMABUF         1
 #define DRM_VMW_UNREF_DMABUF         2
+#define DRM_VMW_HANDLE_CLOSE         2
 #define DRM_VMW_CURSOR_BYPASS        3
 /* guarded by DRM_VMW_PARAM_NUM_STREAMS != 0*/
 #define DRM_VMW_CONTROL_STREAM       4
@@ -292,13 +297,17 @@
  * @version: Allows expanding the execbuf ioctl parameters without breaking
  * backwards compatibility, since user-space will always tell the kernel
  * which version it uses.
- * @flags: Execbuf flags. None currently.
+ * @flags: Execbuf flags.
+ * @imported_fence_fd:  FD for a fence imported from another device
  *
  * Argument to the DRM_VMW_EXECBUF Ioctl.
  */
 
 #define DRM_VMW_EXECBUF_VERSION 2
 
+#define DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD (1 << 0)
+#define DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD (1 << 1)
+
 struct drm_vmw_execbuf_arg {
 	__u64 commands;
 	__u32 command_size;
@@ -307,7 +316,7 @@
 	__u32 version;
 	__u32 flags;
 	__u32 context_handle;
-	__u32 pad64;
+	__s32 imported_fence_fd;
 };
 
 /**
@@ -323,6 +332,7 @@
  * @passed_seqno: The highest seqno number processed by the hardware
  * so far. This can be used to mark user-space fence objects as signaled, and
  * to determine whether a fence seqno might be stale.
+ * @fd: FD associated with the fence, -1 if not exported
  * @error: This member should've been set to -EFAULT on submission.
  * The following actions should be take on completion:
  * error == -EFAULT: Fence communication failed. The host is synchronized.
@@ -340,7 +350,7 @@
 	__u32 mask;
 	__u32 seqno;
 	__u32 passed_seqno;
-	__u32 pad64;
+	__s32 fd;
 	__s32 error;
 };
 
@@ -1087,4 +1097,32 @@
 	enum drm_vmw_extended_context req;
 	struct drm_vmw_context_arg rep;
 };
+
+/*************************************************************************/
+/*
+ * DRM_VMW_HANDLE_CLOSE - Close a user-space handle and release its
+ * underlying resource.
+ *
+ * Note that this ioctl is overlaid on the DRM_VMW_UNREF_DMABUF Ioctl.
+ * The ioctl arguments therefore need to be identical in layout.
+ *
+ */
+
+/**
+ * struct drm_vmw_handle_close_arg
+ *
+ * @handle: Handle to close.
+ *
+ * Argument to the DRM_VMW_HANDLE_CLOSE Ioctl.
+ */
+struct drm_vmw_handle_close_arg {
+	__u32 handle;
+	__u32 pad64;
+};
+
+
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/intel/Android.sources.bp b/intel/Android.sources.bp
index 459c070..46e0328 100644
--- a/intel/Android.sources.bp
+++ b/intel/Android.sources.bp
@@ -7,6 +7,7 @@
         "intel_bufmgr_fake.c",
         "intel_bufmgr_gem.c",
         "intel_decode.c",
+        "intel_chipset.c",
         "mm.c",
     ],
 }
diff --git a/intel/Makefile.am b/intel/Makefile.am
index c52e8c0..bad44f5 100644
--- a/intel/Makefile.am
+++ b/intel/Makefile.am
@@ -26,6 +26,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	$(PCIACCESS_CFLAGS) \
@@ -56,6 +57,7 @@
 	tests/gen7-2d-copy.batch \
 	tests/gen7-3d.batch
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = \
 	$(BATCHES:.batch=.batch.sh) \
 	intel-symbol-check
diff --git a/intel/Makefile.sources b/intel/Makefile.sources
index 6947ab7..aa27e27 100644
--- a/intel/Makefile.sources
+++ b/intel/Makefile.sources
@@ -1,10 +1,12 @@
 LIBDRM_INTEL_FILES := \
+	i915_pciids.h \
 	intel_bufmgr.c \
 	intel_bufmgr_priv.h \
 	intel_bufmgr_fake.c \
 	intel_bufmgr_gem.c \
 	intel_decode.c \
 	intel_chipset.h \
+	intel_chipset.c \
 	mm.c \
 	mm.h \
 	uthash.h
diff --git a/intel/i915_pciids.h b/intel/i915_pciids.h
new file mode 100644
index 0000000..fd965ff
--- /dev/null
+++ b/intel/i915_pciids.h
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2013 Intel Corporation
+ * 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 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.
+ */
+#ifndef _I915_PCIIDS_H
+#define _I915_PCIIDS_H
+
+/*
+ * A pci_device_id struct {
+ *	__u32 vendor, device;
+ *      __u32 subvendor, subdevice;
+ *	__u32 class, class_mask;
+ *	kernel_ulong_t driver_data;
+ * };
+ * Don't use C99 here because "class" is reserved and we want to
+ * give userspace flexibility.
+ */
+#define INTEL_VGA_DEVICE(id, info) {		\
+	0x8086,	id,				\
+	~0, ~0,					\
+	0x030000, 0xff0000,			\
+	(unsigned long) info }
+
+#define INTEL_QUANTA_VGA_DEVICE(info) {		\
+	0x8086,	0x16a,				\
+	0x152d,	0x8990,				\
+	0x030000, 0xff0000,			\
+	(unsigned long) info }
+
+#define INTEL_I810_IDS(info)					\
+	INTEL_VGA_DEVICE(0x7121, info), /* I810 */		\
+	INTEL_VGA_DEVICE(0x7123, info), /* I810_DC100 */	\
+	INTEL_VGA_DEVICE(0x7125, info)  /* I810_E */
+
+#define INTEL_I815_IDS(info)					\
+	INTEL_VGA_DEVICE(0x1132, info)  /* I815*/
+
+#define INTEL_I830_IDS(info)				\
+	INTEL_VGA_DEVICE(0x3577, info)
+
+#define INTEL_I845G_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2562, info)
+
+#define INTEL_I85X_IDS(info)				\
+	INTEL_VGA_DEVICE(0x3582, info), /* I855_GM */ \
+	INTEL_VGA_DEVICE(0x358e, info)
+
+#define INTEL_I865G_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2572, info) /* I865_G */
+
+#define INTEL_I915G_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2582, info), /* I915_G */ \
+	INTEL_VGA_DEVICE(0x258a, info)  /* E7221_G */
+
+#define INTEL_I915GM_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2592, info) /* I915_GM */
+
+#define INTEL_I945G_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2772, info) /* I945_G */
+
+#define INTEL_I945GM_IDS(info)				\
+	INTEL_VGA_DEVICE(0x27a2, info), /* I945_GM */ \
+	INTEL_VGA_DEVICE(0x27ae, info)  /* I945_GME */
+
+#define INTEL_I965G_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2972, info), /* I946_GZ */	\
+	INTEL_VGA_DEVICE(0x2982, info),	/* G35_G */	\
+	INTEL_VGA_DEVICE(0x2992, info),	/* I965_Q */	\
+	INTEL_VGA_DEVICE(0x29a2, info)	/* I965_G */
+
+#define INTEL_G33_IDS(info)				\
+	INTEL_VGA_DEVICE(0x29b2, info), /* Q35_G */ \
+	INTEL_VGA_DEVICE(0x29c2, info),	/* G33_G */ \
+	INTEL_VGA_DEVICE(0x29d2, info)	/* Q33_G */
+
+#define INTEL_I965GM_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2a02, info),	/* I965_GM */ \
+	INTEL_VGA_DEVICE(0x2a12, info)  /* I965_GME */
+
+#define INTEL_GM45_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2a42, info) /* GM45_G */
+
+#define INTEL_G45_IDS(info)				\
+	INTEL_VGA_DEVICE(0x2e02, info), /* IGD_E_G */ \
+	INTEL_VGA_DEVICE(0x2e12, info), /* Q45_G */ \
+	INTEL_VGA_DEVICE(0x2e22, info), /* G45_G */ \
+	INTEL_VGA_DEVICE(0x2e32, info), /* G41_G */ \
+	INTEL_VGA_DEVICE(0x2e42, info), /* B43_G */ \
+	INTEL_VGA_DEVICE(0x2e92, info)	/* B43_G.1 */
+
+#define INTEL_PINEVIEW_IDS(info)			\
+	INTEL_VGA_DEVICE(0xa001, info),			\
+	INTEL_VGA_DEVICE(0xa011, info)
+
+#define INTEL_IRONLAKE_D_IDS(info) \
+	INTEL_VGA_DEVICE(0x0042, info)
+
+#define INTEL_IRONLAKE_M_IDS(info) \
+	INTEL_VGA_DEVICE(0x0046, info)
+
+#define INTEL_SNB_D_GT1_IDS(info) \
+	INTEL_VGA_DEVICE(0x0102, info), \
+	INTEL_VGA_DEVICE(0x010A, info)
+
+#define INTEL_SNB_D_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x0112, info), \
+	INTEL_VGA_DEVICE(0x0122, info)
+
+#define INTEL_SNB_D_IDS(info) \
+	INTEL_SNB_D_GT1_IDS(info), \
+	INTEL_SNB_D_GT2_IDS(info)
+
+#define INTEL_SNB_M_GT1_IDS(info) \
+	INTEL_VGA_DEVICE(0x0106, info)
+
+#define INTEL_SNB_M_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x0116, info), \
+	INTEL_VGA_DEVICE(0x0126, info)
+
+#define INTEL_SNB_M_IDS(info) \
+	INTEL_SNB_M_GT1_IDS(info), \
+	INTEL_SNB_M_GT2_IDS(info)
+
+#define INTEL_IVB_M_GT1_IDS(info) \
+	INTEL_VGA_DEVICE(0x0156, info) /* GT1 mobile */
+
+#define INTEL_IVB_M_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x0166, info) /* GT2 mobile */
+
+#define INTEL_IVB_M_IDS(info) \
+	INTEL_IVB_M_GT1_IDS(info), \
+	INTEL_IVB_M_GT2_IDS(info)
+
+#define INTEL_IVB_D_GT1_IDS(info) \
+	INTEL_VGA_DEVICE(0x0152, info), /* GT1 desktop */ \
+	INTEL_VGA_DEVICE(0x015a, info)  /* GT1 server */
+
+#define INTEL_IVB_D_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x0162, info), /* GT2 desktop */ \
+	INTEL_VGA_DEVICE(0x016a, info)  /* GT2 server */
+
+#define INTEL_IVB_D_IDS(info) \
+	INTEL_IVB_D_GT1_IDS(info), \
+	INTEL_IVB_D_GT2_IDS(info)
+
+#define INTEL_IVB_Q_IDS(info) \
+	INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */
+
+#define INTEL_HSW_GT1_IDS(info) \
+	INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \
+	INTEL_VGA_DEVICE(0x040a, info), /* GT1 server */ \
+	INTEL_VGA_DEVICE(0x040B, info), /* GT1 reserved */ \
+	INTEL_VGA_DEVICE(0x040E, info), /* GT1 reserved */ \
+	INTEL_VGA_DEVICE(0x0C02, info), /* SDV GT1 desktop */ \
+	INTEL_VGA_DEVICE(0x0C0A, info), /* SDV GT1 server */ \
+	INTEL_VGA_DEVICE(0x0C0B, info), /* SDV GT1 reserved */ \
+	INTEL_VGA_DEVICE(0x0C0E, info), /* SDV GT1 reserved */ \
+	INTEL_VGA_DEVICE(0x0A02, info), /* ULT GT1 desktop */ \
+	INTEL_VGA_DEVICE(0x0A0A, info), /* ULT GT1 server */ \
+	INTEL_VGA_DEVICE(0x0A0B, info), /* ULT GT1 reserved */ \
+	INTEL_VGA_DEVICE(0x0D02, info), /* CRW GT1 desktop */ \
+	INTEL_VGA_DEVICE(0x0D0A, info), /* CRW GT1 server */ \
+	INTEL_VGA_DEVICE(0x0D0B, info), /* CRW GT1 reserved */ \
+	INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \
+	INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \
+	INTEL_VGA_DEVICE(0x0C06, info), /* SDV GT1 mobile */ \
+	INTEL_VGA_DEVICE(0x0A06, info), /* ULT GT1 mobile */ \
+	INTEL_VGA_DEVICE(0x0A0E, info), /* ULX GT1 mobile */ \
+	INTEL_VGA_DEVICE(0x0D06, info)  /* CRW GT1 mobile */
+
+#define INTEL_HSW_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \
+	INTEL_VGA_DEVICE(0x041a, info), /* GT2 server */ \
+	INTEL_VGA_DEVICE(0x041B, info), /* GT2 reserved */ \
+	INTEL_VGA_DEVICE(0x041E, info), /* GT2 reserved */ \
+	INTEL_VGA_DEVICE(0x0C12, info), /* SDV GT2 desktop */ \
+	INTEL_VGA_DEVICE(0x0C1A, info), /* SDV GT2 server */ \
+	INTEL_VGA_DEVICE(0x0C1B, info), /* SDV GT2 reserved */ \
+	INTEL_VGA_DEVICE(0x0C1E, info), /* SDV GT2 reserved */ \
+	INTEL_VGA_DEVICE(0x0A12, info), /* ULT GT2 desktop */ \
+	INTEL_VGA_DEVICE(0x0A1A, info), /* ULT GT2 server */ \
+	INTEL_VGA_DEVICE(0x0A1B, info), /* ULT GT2 reserved */ \
+	INTEL_VGA_DEVICE(0x0D12, info), /* CRW GT2 desktop */ \
+	INTEL_VGA_DEVICE(0x0D1A, info), /* CRW GT2 server */ \
+	INTEL_VGA_DEVICE(0x0D1B, info), /* CRW GT2 reserved */ \
+	INTEL_VGA_DEVICE(0x0D1E, info), /* CRW GT2 reserved */ \
+	INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \
+	INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \
+	INTEL_VGA_DEVICE(0x0C16, info), /* SDV GT2 mobile */ \
+	INTEL_VGA_DEVICE(0x0A16, info), /* ULT GT2 mobile */ \
+	INTEL_VGA_DEVICE(0x0A1E, info), /* ULX GT2 mobile */ \
+	INTEL_VGA_DEVICE(0x0D16, info)  /* CRW GT2 mobile */
+
+#define INTEL_HSW_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \
+	INTEL_VGA_DEVICE(0x042a, info), /* GT3 server */ \
+	INTEL_VGA_DEVICE(0x042B, info), /* GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x042E, info), /* GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x0C22, info), /* SDV GT3 desktop */ \
+	INTEL_VGA_DEVICE(0x0C2A, info), /* SDV GT3 server */ \
+	INTEL_VGA_DEVICE(0x0C2B, info), /* SDV GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x0C2E, info), /* SDV GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x0A22, info), /* ULT GT3 desktop */ \
+	INTEL_VGA_DEVICE(0x0A2A, info), /* ULT GT3 server */ \
+	INTEL_VGA_DEVICE(0x0A2B, info), /* ULT GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x0D22, info), /* CRW GT3 desktop */ \
+	INTEL_VGA_DEVICE(0x0D2A, info), /* CRW GT3 server */ \
+	INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x0D2E, info), /* CRW GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x0C26, info), /* SDV GT3 mobile */ \
+	INTEL_VGA_DEVICE(0x0A26, info), /* ULT GT3 mobile */ \
+	INTEL_VGA_DEVICE(0x0A2E, info), /* ULT GT3 reserved */ \
+	INTEL_VGA_DEVICE(0x0D26, info)  /* CRW GT3 mobile */
+
+#define INTEL_HSW_IDS(info) \
+	INTEL_HSW_GT1_IDS(info), \
+	INTEL_HSW_GT2_IDS(info), \
+	INTEL_HSW_GT3_IDS(info)
+
+#define INTEL_VLV_IDS(info) \
+	INTEL_VGA_DEVICE(0x0f30, info), \
+	INTEL_VGA_DEVICE(0x0f31, info), \
+	INTEL_VGA_DEVICE(0x0f32, info), \
+	INTEL_VGA_DEVICE(0x0f33, info), \
+	INTEL_VGA_DEVICE(0x0157, info), \
+	INTEL_VGA_DEVICE(0x0155, info)
+
+#define INTEL_BDW_GT1_IDS(info)  \
+	INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \
+	INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
+	INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \
+	INTEL_VGA_DEVICE(0x160E, info), /* GT1 ULX */ \
+	INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \
+	INTEL_VGA_DEVICE(0x160D, info)  /* GT1 Workstation */
+
+#define INTEL_BDW_GT2_IDS(info)  \
+	INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */	\
+	INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \
+	INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \
+	INTEL_VGA_DEVICE(0x161E, info), /* GT2 ULX */ \
+	INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \
+	INTEL_VGA_DEVICE(0x161D, info)  /* GT2 Workstation */
+
+#define INTEL_BDW_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \
+	INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \
+	INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \
+	INTEL_VGA_DEVICE(0x162E, info),  /* ULX */\
+	INTEL_VGA_DEVICE(0x162A, info), /* Server */ \
+	INTEL_VGA_DEVICE(0x162D, info)  /* Workstation */
+
+#define INTEL_BDW_RSVD_IDS(info) \
+	INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \
+	INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \
+	INTEL_VGA_DEVICE(0x163B, info), /* Iris */ \
+	INTEL_VGA_DEVICE(0x163E, info), /* ULX */ \
+	INTEL_VGA_DEVICE(0x163A, info), /* Server */ \
+	INTEL_VGA_DEVICE(0x163D, info)  /* Workstation */
+
+#define INTEL_BDW_IDS(info) \
+	INTEL_BDW_GT1_IDS(info), \
+	INTEL_BDW_GT2_IDS(info), \
+	INTEL_BDW_GT3_IDS(info), \
+	INTEL_BDW_RSVD_IDS(info)
+
+#define INTEL_CHV_IDS(info) \
+	INTEL_VGA_DEVICE(0x22b0, info), \
+	INTEL_VGA_DEVICE(0x22b1, info), \
+	INTEL_VGA_DEVICE(0x22b2, info), \
+	INTEL_VGA_DEVICE(0x22b3, info)
+
+#define INTEL_SKL_GT1_IDS(info)	\
+	INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \
+	INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \
+	INTEL_VGA_DEVICE(0x1902, info), /* DT  GT1 */ \
+	INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
+	INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */
+
+#define INTEL_SKL_GT2_IDS(info)	\
+	INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
+	INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
+	INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \
+	INTEL_VGA_DEVICE(0x1912, info), /* DT  GT2 */ \
+	INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \
+	INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x191D, info)  /* WKS GT2 */
+
+#define INTEL_SKL_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
+	INTEL_VGA_DEVICE(0x192D, info)  /* SRV GT3 */
+
+#define INTEL_SKL_GT4_IDS(info) \
+	INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */ \
+	INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4 */ \
+	INTEL_VGA_DEVICE(0x193D, info), /* WKS GT4 */ \
+	INTEL_VGA_DEVICE(0x192A, info), /* SRV GT4 */ \
+	INTEL_VGA_DEVICE(0x193A, info)  /* SRV GT4e */
+
+#define INTEL_SKL_IDS(info)	 \
+	INTEL_SKL_GT1_IDS(info), \
+	INTEL_SKL_GT2_IDS(info), \
+	INTEL_SKL_GT3_IDS(info), \
+	INTEL_SKL_GT4_IDS(info)
+
+#define INTEL_BXT_IDS(info) \
+	INTEL_VGA_DEVICE(0x0A84, info), \
+	INTEL_VGA_DEVICE(0x1A84, info), \
+	INTEL_VGA_DEVICE(0x1A85, info), \
+	INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ \
+	INTEL_VGA_DEVICE(0x5A85, info)  /* APL HD Graphics 500 */
+
+#define INTEL_GLK_IDS(info) \
+	INTEL_VGA_DEVICE(0x3184, info), \
+	INTEL_VGA_DEVICE(0x3185, info)
+
+#define INTEL_KBL_GT1_IDS(info)	\
+	INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \
+	INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \
+	INTEL_VGA_DEVICE(0x5902, info), /* DT  GT1 */ \
+	INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */ \
+	INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \
+	INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */
+
+#define INTEL_KBL_GT2_IDS(info)	\
+	INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \
+	INTEL_VGA_DEVICE(0x5917, info), /* Mobile GT2 */ \
+	INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \
+	INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \
+	INTEL_VGA_DEVICE(0x5912, info), /* DT  GT2 */ \
+	INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \
+	INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */
+
+#define INTEL_KBL_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x5927, info) /* ULT GT3 */
+
+#define INTEL_KBL_GT4_IDS(info) \
+	INTEL_VGA_DEVICE(0x593B, info) /* Halo GT4 */
+
+/* AML/KBL Y GT2 */
+#define INTEL_AML_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x591C, info),  /* ULX GT2 */ \
+	INTEL_VGA_DEVICE(0x87C0, info) /* ULX GT2 */
+
+#define INTEL_KBL_IDS(info) \
+	INTEL_KBL_GT1_IDS(info), \
+	INTEL_KBL_GT2_IDS(info), \
+	INTEL_KBL_GT3_IDS(info), \
+	INTEL_KBL_GT4_IDS(info), \
+	INTEL_AML_GT2_IDS(info)
+
+/* CFL S */
+#define INTEL_CFL_S_GT1_IDS(info) \
+	INTEL_VGA_DEVICE(0x3E90, info), /* SRV GT1 */ \
+	INTEL_VGA_DEVICE(0x3E93, info), /* SRV GT1 */ \
+	INTEL_VGA_DEVICE(0x3E99, info)  /* SRV GT1 */
+
+#define INTEL_CFL_S_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x3E91, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x3E92, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x3E96, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x3E98, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x3E9A, info)  /* SRV GT2 */
+
+/* CFL H */
+#define INTEL_CFL_H_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x3E9B, info), /* Halo GT2 */ \
+	INTEL_VGA_DEVICE(0x3E94, info)  /* Halo GT2 */
+
+/* CFL U GT2 */
+#define INTEL_CFL_U_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x3EA9, info)
+
+/* CFL U GT3 */
+#define INTEL_CFL_U_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x3EA5, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x3EA6, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x3EA7, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x3EA8, info)  /* ULT GT3 */
+
+/* WHL/CFL U GT1 */
+#define INTEL_WHL_U_GT1_IDS(info) \
+	INTEL_VGA_DEVICE(0x3EA1, info)
+
+/* WHL/CFL U GT2 */
+#define INTEL_WHL_U_GT2_IDS(info) \
+	INTEL_VGA_DEVICE(0x3EA0, info)
+
+/* WHL/CFL U GT3 */
+#define INTEL_WHL_U_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x3EA2, info), \
+	INTEL_VGA_DEVICE(0x3EA3, info), \
+	INTEL_VGA_DEVICE(0x3EA4, info)
+
+#define INTEL_CFL_IDS(info)	   \
+	INTEL_CFL_S_GT1_IDS(info), \
+	INTEL_CFL_S_GT2_IDS(info), \
+	INTEL_CFL_H_GT2_IDS(info), \
+	INTEL_CFL_U_GT2_IDS(info), \
+	INTEL_CFL_U_GT3_IDS(info), \
+	INTEL_WHL_U_GT1_IDS(info), \
+	INTEL_WHL_U_GT2_IDS(info), \
+	INTEL_WHL_U_GT3_IDS(info)
+
+/* CNL */
+#define INTEL_CNL_IDS(info) \
+	INTEL_VGA_DEVICE(0x5A51, info), \
+	INTEL_VGA_DEVICE(0x5A59, info), \
+	INTEL_VGA_DEVICE(0x5A41, info), \
+	INTEL_VGA_DEVICE(0x5A49, info), \
+	INTEL_VGA_DEVICE(0x5A52, info), \
+	INTEL_VGA_DEVICE(0x5A5A, info), \
+	INTEL_VGA_DEVICE(0x5A42, info), \
+	INTEL_VGA_DEVICE(0x5A4A, info), \
+	INTEL_VGA_DEVICE(0x5A50, info), \
+	INTEL_VGA_DEVICE(0x5A40, info), \
+	INTEL_VGA_DEVICE(0x5A54, info), \
+	INTEL_VGA_DEVICE(0x5A5C, info), \
+	INTEL_VGA_DEVICE(0x5A44, info), \
+	INTEL_VGA_DEVICE(0x5A4C, info)
+
+/* ICL */
+#define INTEL_ICL_11_IDS(info) \
+	INTEL_VGA_DEVICE(0x8A50, info), \
+	INTEL_VGA_DEVICE(0x8A51, info), \
+	INTEL_VGA_DEVICE(0x8A5C, info), \
+	INTEL_VGA_DEVICE(0x8A5D, info), \
+	INTEL_VGA_DEVICE(0x8A52, info), \
+	INTEL_VGA_DEVICE(0x8A5A, info), \
+	INTEL_VGA_DEVICE(0x8A5B, info), \
+	INTEL_VGA_DEVICE(0x8A71, info), \
+	INTEL_VGA_DEVICE(0x8A70, info)
+
+#endif /* _I915_PCIIDS_H */
diff --git a/intel/intel-symbol-check b/intel/intel-symbol-check
index 2aa2d81..de377be 100755
--- a/intel/intel-symbol-check
+++ b/intel/intel-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.sources/LIBDRM_INTEL_H_FILES
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_intel.so} | awk '{print $3}' | while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_intel.so} | awk '{print $3}' | while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
diff --git a/intel/intel_bufmgr.c b/intel/intel_bufmgr.c
index 5bad93f..68d97c0 100644
--- a/intel/intel_bufmgr.c
+++ b/intel/intel_bufmgr.c
@@ -25,10 +25,6 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <string.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -49,21 +45,21 @@
  * Convenience functions for buffer management methods.
  */
 
-drm_intel_bo *
+drm_public drm_intel_bo *
 drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
 		   unsigned long size, unsigned int alignment)
 {
 	return bufmgr->bo_alloc(bufmgr, name, size, alignment);
 }
 
-drm_intel_bo *
+drm_public drm_intel_bo *
 drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name,
 			      unsigned long size, unsigned int alignment)
 {
 	return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment);
 }
 
-drm_intel_bo *
+drm_public drm_intel_bo *
 drm_intel_bo_alloc_userptr(drm_intel_bufmgr *bufmgr,
 			   const char *name, void *addr,
 			   uint32_t tiling_mode,
@@ -77,7 +73,7 @@
 	return NULL;
 }
 
-drm_intel_bo *
+drm_public drm_intel_bo *
 drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name,
                         int x, int y, int cpp, uint32_t *tiling_mode,
                         unsigned long *pitch, unsigned long flags)
@@ -86,13 +82,13 @@
 				      tiling_mode, pitch, flags);
 }
 
-void
+drm_public void
 drm_intel_bo_reference(drm_intel_bo *bo)
 {
 	bo->bufmgr->bo_reference(bo);
 }
 
-void
+drm_public void
 drm_intel_bo_unreference(drm_intel_bo *bo)
 {
 	if (bo == NULL)
@@ -101,26 +97,26 @@
 	bo->bufmgr->bo_unreference(bo);
 }
 
-int
+drm_public int
 drm_intel_bo_map(drm_intel_bo *buf, int write_enable)
 {
 	return buf->bufmgr->bo_map(buf, write_enable);
 }
 
-int
+drm_public int
 drm_intel_bo_unmap(drm_intel_bo *buf)
 {
 	return buf->bufmgr->bo_unmap(buf);
 }
 
-int
+drm_public int
 drm_intel_bo_subdata(drm_intel_bo *bo, unsigned long offset,
 		     unsigned long size, const void *data)
 {
 	return bo->bufmgr->bo_subdata(bo, offset, size, data);
 }
 
-int
+drm_public int
 drm_intel_bo_get_subdata(drm_intel_bo *bo, unsigned long offset,
 			 unsigned long size, void *data)
 {
@@ -139,26 +135,26 @@
 	return 0;
 }
 
-void
+drm_public void
 drm_intel_bo_wait_rendering(drm_intel_bo *bo)
 {
 	bo->bufmgr->bo_wait_rendering(bo);
 }
 
-void
+drm_public void
 drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr)
 {
 	bufmgr->destroy(bufmgr);
 }
 
-int
+drm_public int
 drm_intel_bo_exec(drm_intel_bo *bo, int used,
 		  drm_clip_rect_t * cliprects, int num_cliprects, int DR4)
 {
 	return bo->bufmgr->bo_exec(bo, used, cliprects, num_cliprects, DR4);
 }
 
-int
+drm_public int
 drm_intel_bo_mrb_exec(drm_intel_bo *bo, int used,
 		drm_clip_rect_t *cliprects, int num_cliprects, int DR4,
 		unsigned int rings)
@@ -178,19 +174,19 @@
 	}
 }
 
-void
+drm_public void
 drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug)
 {
 	bufmgr->debug = enable_debug;
 }
 
-int
+drm_public int
 drm_intel_bufmgr_check_aperture_space(drm_intel_bo ** bo_array, int count)
 {
 	return bo_array[0]->bufmgr->check_aperture_space(bo_array, count);
 }
 
-int
+drm_public int
 drm_intel_bo_flink(drm_intel_bo *bo, uint32_t * name)
 {
 	if (bo->bufmgr->bo_flink)
@@ -199,7 +195,7 @@
 	return -ENODEV;
 }
 
-int
+drm_public int
 drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
 			drm_intel_bo *target_bo, uint32_t target_offset,
 			uint32_t read_domains, uint32_t write_domain)
@@ -210,7 +206,7 @@
 }
 
 /* For fence registers, not GL fences */
-int
+drm_public int
 drm_intel_bo_emit_reloc_fence(drm_intel_bo *bo, uint32_t offset,
 			      drm_intel_bo *target_bo, uint32_t target_offset,
 			      uint32_t read_domains, uint32_t write_domain)
@@ -221,7 +217,7 @@
 }
 
 
-int
+drm_public int
 drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment)
 {
 	if (bo->bufmgr->bo_pin)
@@ -230,7 +226,7 @@
 	return -ENODEV;
 }
 
-int
+drm_public int
 drm_intel_bo_unpin(drm_intel_bo *bo)
 {
 	if (bo->bufmgr->bo_unpin)
@@ -239,7 +235,7 @@
 	return -ENODEV;
 }
 
-int
+drm_public int
 drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
 			uint32_t stride)
 {
@@ -250,7 +246,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
 			uint32_t * swizzle_mode)
 {
@@ -262,7 +258,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_bo_set_softpin_offset(drm_intel_bo *bo, uint64_t offset)
 {
 	if (bo->bufmgr->bo_set_softpin_offset)
@@ -271,7 +267,7 @@
 	return -ENODEV;
 }
 
-int
+drm_public int
 drm_intel_bo_disable_reuse(drm_intel_bo *bo)
 {
 	if (bo->bufmgr->bo_disable_reuse)
@@ -279,7 +275,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_bo_is_reusable(drm_intel_bo *bo)
 {
 	if (bo->bufmgr->bo_is_reusable)
@@ -287,7 +283,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_bo_busy(drm_intel_bo *bo)
 {
 	if (bo->bufmgr->bo_busy)
@@ -295,7 +291,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_bo_madvise(drm_intel_bo *bo, int madv)
 {
 	if (bo->bufmgr->bo_madvise)
@@ -303,7 +299,7 @@
 	return -1;
 }
 
-int
+drm_public int
 drm_intel_bo_use_48b_address_range(drm_intel_bo *bo, uint32_t enable)
 {
 	if (bo->bufmgr->bo_use_48b_address_range) {
@@ -314,13 +310,13 @@
 	return -ENODEV;
 }
 
-int
+drm_public int
 drm_intel_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo)
 {
 	return bo->bufmgr->bo_references(bo, target_bo);
 }
 
-int
+drm_public int
 drm_intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id)
 {
 	if (bufmgr->get_pipe_from_crtc_id)
@@ -364,7 +360,7 @@
 }
 #endif
 
-int
+drm_public int
 drm_intel_get_aperture_sizes(int fd, size_t *mappable, size_t *total)
 {
 
diff --git a/intel/intel_bufmgr_fake.c b/intel/intel_bufmgr_fake.c
index 641df6a..0cec51f 100644
--- a/intel/intel_bufmgr_fake.c
+++ b/intel/intel_bufmgr_fake.c
@@ -34,10 +34,6 @@
  * the bugs in the old texture manager.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
@@ -245,7 +241,7 @@
 	return 0;
 }
 
-void
+drm_public void
 drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr,
 					 unsigned int (*emit) (void *priv),
 					 void (*wait) (unsigned int fence,
@@ -768,7 +764,7 @@
  *  -- just evict everything
  *  -- and wait for idle
  */
-void
+drm_public void
 drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr)
 {
 	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
@@ -864,7 +860,7 @@
 				       4096);
 }
 
-drm_intel_bo *
+drm_public drm_intel_bo *
 drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr,
 			       const char *name,
 			       unsigned long offset,
@@ -959,7 +955,7 @@
  * Set the buffer as not requiring backing store, and instead get the callback
  * invoked whenever it would be set dirty.
  */
-void
+drm_public void
 drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo,
 					void (*invalidate_cb) (drm_intel_bo *bo,
 							       void *ptr),
@@ -1413,7 +1409,7 @@
 	bo_fake->write_domain = 0;
 }
 
-void
+drm_public void
 drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr,
 					     int (*exec) (drm_intel_bo *bo,
 							  unsigned int used,
@@ -1536,7 +1532,7 @@
  * Used by the X Server on LeaveVT, when the card memory is no longer our
  * own.
  */
-void
+drm_public void
 drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr)
 {
 	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
@@ -1571,7 +1567,7 @@
 	pthread_mutex_unlock(&bufmgr_fake->lock);
 }
 
-void
+drm_public void
 drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr,
 					volatile unsigned int
 					*last_dispatch)
@@ -1581,7 +1577,7 @@
 	bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
 }
 
-drm_intel_bufmgr *
+drm_public drm_intel_bufmgr *
 drm_intel_bufmgr_fake_init(int fd, unsigned long low_offset,
 			   void *low_virtual, unsigned long size,
 			   volatile unsigned int *last_dispatch)
diff --git a/intel/intel_bufmgr_gem.c b/intel/intel_bufmgr_gem.c
index a665600..fbf4873 100644
--- a/intel/intel_bufmgr_gem.c
+++ b/intel/intel_bufmgr_gem.c
@@ -34,10 +34,6 @@
  *	    Dave Airlie <airlied@linux.ie>
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <xf86drm.h>
 #include <xf86atomic.h>
 #include <fcntl.h>
@@ -66,7 +62,7 @@
 #include "i915_drm.h"
 #include "uthash.h"
 
-#ifdef HAVE_VALGRIND
+#if HAVE_VALGRIND
 #include <valgrind.h>
 #include <memcheck.h>
 #define VG(x) x
@@ -270,20 +266,6 @@
 	bool is_userptr;
 
 	/**
-	 * Boolean of whether this buffer can be placed in the full 48-bit
-	 * address range on gen8+.
-	 *
-	 * By default, buffers will be keep in a 32-bit range, unless this
-	 * flag is explicitly set.
-	 */
-	bool use_48b_address_range;
-
-	/**
-	 * Whether this buffer is softpinned at offset specified by the user
-	 */
-	bool is_softpin;
-
-	/**
 	 * Size in bytes of this buffer and its relocation descendents.
 	 *
 	 * Used to avoid costly tree walking in
@@ -438,7 +420,7 @@
 
 		if (bo_gem->relocs == NULL && bo_gem->softpin_target == NULL) {
 			DBG("%2d: %d %s(%s)\n", i, bo_gem->gem_handle,
-			    bo_gem->is_softpin ? "*" : "",
+			    bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "",
 			    bo_gem->name);
 			continue;
 		}
@@ -452,7 +434,7 @@
 			    "%d (%s)@0x%08x %08x + 0x%08x\n",
 			    i,
 			    bo_gem->gem_handle,
-			    bo_gem->is_softpin ? "*" : "",
+			    bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "",
 			    bo_gem->name,
 			    upper_32_bits(bo_gem->relocs[j].offset),
 			    lower_32_bits(bo_gem->relocs[j].offset),
@@ -471,7 +453,7 @@
 			    "%d *(%s)@0x%08x %08x\n",
 			    i,
 			    bo_gem->gem_handle,
-			    bo_gem->is_softpin ? "*" : "",
+			    bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "",
 			    bo_gem->name,
 			    target_gem->gem_handle,
 			    target_gem->name,
@@ -541,14 +523,11 @@
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo;
 	int index;
-	int flags = 0;
+	unsigned long flags;
 
+	flags = 0;
 	if (need_fence)
 		flags |= EXEC_OBJECT_NEEDS_FENCE;
-	if (bo_gem->use_48b_address_range)
-		flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
-	if (bo_gem->is_softpin)
-		flags |= EXEC_OBJECT_PINNED;
 
 	if (bo_gem->validate_index != -1) {
 		bufmgr_gem->exec2_objects[bo_gem->validate_index].flags |= flags;
@@ -579,7 +558,7 @@
 	bufmgr_gem->exec2_objects[index].relocs_ptr = (uintptr_t)bo_gem->relocs;
 	bufmgr_gem->exec2_objects[index].alignment = bo->align;
 	bufmgr_gem->exec2_objects[index].offset = bo->offset64;
-	bufmgr_gem->exec2_objects[index].flags = flags | bo_gem->kflags;
+	bufmgr_gem->exec2_objects[index].flags = bo_gem->kflags | flags;
 	bufmgr_gem->exec2_objects[index].rsvd1 = 0;
 	bufmgr_gem->exec2_objects[index].rsvd2 = 0;
 	bufmgr_gem->exec_bos[index] = bo;
@@ -676,7 +655,6 @@
 	} else {
 		return false;
 	}
-	return (ret == 0 && busy.busy);
 }
 
 static int
@@ -832,6 +810,10 @@
 		}
 
 		bo_gem->gem_handle = create.handle;
+		HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+			 gem_handle, sizeof(bo_gem->gem_handle),
+			 bo_gem);
+
 		bo_gem->bo.handle = bo_gem->gem_handle;
 		bo_gem->bo.bufmgr = bufmgr;
 		bo_gem->bo.align = alignment;
@@ -844,10 +826,6 @@
 							 tiling_mode,
 							 stride))
 			goto err_free;
-
-		HASH_ADD(handle_hh, bufmgr_gem->handle_table,
-			 gem_handle, sizeof(bo_gem->gem_handle),
-			 bo_gem);
 	}
 
 	bo_gem->name = name;
@@ -857,7 +835,6 @@
 	bo_gem->used_as_reloc_target = false;
 	bo_gem->has_error = false;
 	bo_gem->reusable = true;
-	bo_gem->use_48b_address_range = false;
 
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, alignment);
 	pthread_mutex_unlock(&bufmgr_gem->lock);
@@ -1016,7 +993,6 @@
 	bo_gem->used_as_reloc_target = false;
 	bo_gem->has_error = false;
 	bo_gem->reusable = false;
-	bo_gem->use_48b_address_range = false;
 
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0);
 	pthread_mutex_unlock(&bufmgr_gem->lock);
@@ -1099,7 +1075,7 @@
  * This can be used when one application needs to pass a buffer object
  * to another.
  */
-drm_intel_bo *
+drm_public drm_intel_bo *
 drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr,
 				  const char *name,
 				  unsigned int handle)
@@ -1164,7 +1140,6 @@
 	bo_gem->bo.handle = open_arg.handle;
 	bo_gem->global_name = handle;
 	bo_gem->reusable = false;
-	bo_gem->use_48b_address_range = false;
 
 	HASH_ADD(handle_hh, bufmgr_gem->handle_table,
 		 gem_handle, sizeof(bo_gem->gem_handle), bo_gem);
@@ -1411,8 +1386,6 @@
 		bo_gem->name = NULL;
 		bo_gem->validate_index = -1;
 
-		bo_gem->kflags = 0;
-
 		DRMLISTADDTAIL(&bo_gem->head, &bucket->head);
 	} else {
 		drm_intel_gem_bo_free(bo);
@@ -1589,7 +1562,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
@@ -1648,11 +1621,11 @@
  * undefined).
  */
 
-int
+drm_public int
 drm_intel_gem_bo_map_unsynchronized(drm_intel_bo *bo)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
-#ifdef HAVE_VALGRIND
+#if HAVE_VALGRIND
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
 #endif
 	int ret;
@@ -1737,7 +1710,7 @@
 	return ret;
 }
 
-int
+drm_public int
 drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo)
 {
 	return drm_intel_gem_bo_unmap(bo);
@@ -1862,7 +1835,7 @@
  * Note that some kernels have broken the inifite wait for negative values
  * promise, upgrade to latest stable kernels if this is the case.
  */
-int
+drm_public int
 drm_intel_gem_bo_wait(drm_intel_bo *bo, int64_t timeout_ns)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
@@ -1898,7 +1871,7 @@
  * In combination with drm_intel_gem_bo_pin() and manual fence management, we
  * can do tiled pixmaps this way.
  */
-void
+drm_public void
 drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
@@ -2054,7 +2027,11 @@
 drm_intel_gem_bo_use_48b_address_range(drm_intel_bo *bo, uint32_t enable)
 {
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
-	bo_gem->use_48b_address_range = enable;
+
+	if (enable)
+		bo_gem->kflags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
+	else
+		bo_gem->kflags &= ~EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
 }
 
 static int
@@ -2071,7 +2048,7 @@
 		return -ENOMEM;
 	}
 
-	if (!target_bo_gem->is_softpin)
+	if (!(target_bo_gem->kflags & EXEC_OBJECT_PINNED))
 		return -EINVAL;
 	if (target_bo_gem == bo_gem)
 		return -EINVAL;
@@ -2103,7 +2080,7 @@
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
 	drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *)target_bo;
 
-	if (target_bo_gem->is_softpin)
+	if (target_bo_gem->kflags & EXEC_OBJECT_PINNED)
 		return drm_intel_gem_bo_add_softpin_target(bo, target_bo);
 	else
 		return do_bo_emit_reloc(bo, offset, target_bo, target_offset,
@@ -2121,7 +2098,7 @@
 				read_domains, write_domain, true);
 }
 
-int
+drm_public int
 drm_intel_gem_bo_get_reloc_count(drm_intel_bo *bo)
 {
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
@@ -2144,7 +2121,7 @@
  *
  * This also removes all softpinned targets being referenced by the BO.
  */
-void
+drm_public void
 drm_intel_gem_bo_clear_relocs(drm_intel_bo *bo, int start)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
@@ -2287,7 +2264,7 @@
 			/* If we're seeing softpinned object here it means that the kernel
 			 * has relocated our object... Indicating a programming error
 			 */
-			assert(!bo_gem->is_softpin);
+			assert(!(bo_gem->kflags & EXEC_OBJECT_PINNED));
 			DBG("BO %d (%s) migrated: 0x%08x %08x -> 0x%08x %08x\n",
 			    bo_gem->gem_handle, bo_gem->name,
 			    upper_32_bits(bo->offset64),
@@ -2300,7 +2277,7 @@
 	}
 }
 
-void
+drm_public void
 drm_intel_gem_bo_aub_dump_bmp(drm_intel_bo *bo,
 			      int x1, int y1, int width, int height,
 			      enum aub_dump_bmp_format format,
@@ -2502,14 +2479,14 @@
 			-1, NULL, flags);
 }
 
-int
+drm_public int
 drm_intel_gem_bo_context_exec(drm_intel_bo *bo, drm_intel_context *ctx,
 			      int used, unsigned int flags)
 {
 	return do_exec2(bo, used, ctx, NULL, 0, 0, -1, NULL, flags);
 }
 
-int
+drm_public int
 drm_intel_gem_bo_fence_exec(drm_intel_bo *bo,
 			    drm_intel_context *ctx,
 			    int used,
@@ -2643,13 +2620,14 @@
 {
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
 
-	bo_gem->is_softpin = true;
 	bo->offset64 = offset;
 	bo->offset = offset;
+	bo_gem->kflags |= EXEC_OBJECT_PINNED;
+
 	return 0;
 }
 
-drm_intel_bo *
+drm_public drm_intel_bo *
 drm_intel_bo_gem_create_from_prime(drm_intel_bufmgr *bufmgr, int prime_fd, int size)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
@@ -2709,7 +2687,6 @@
 	bo_gem->used_as_reloc_target = false;
 	bo_gem->has_error = false;
 	bo_gem->reusable = false;
-	bo_gem->use_48b_address_range = false;
 
 	memclear(get_tiling);
 	get_tiling.handle = bo_gem->gem_handle;
@@ -2733,7 +2710,7 @@
 	return NULL;
 }
 
-int
+drm_public int
 drm_intel_bo_gem_export_to_prime(drm_intel_bo *bo, int *prime_fd)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
@@ -2785,7 +2762,7 @@
  * size is only bounded by how many buffers of that size we've managed to have
  * in flight at once.
  */
-void
+drm_public void
 drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
@@ -2807,7 +2784,7 @@
  * which can be checked using drm_intel_bufmgr_can_disable_implicit_sync,
  * or subsequent execbufs involving the bo will generate EINVAL.
  */
-void
+drm_public void
 drm_intel_gem_bo_disable_implicit_sync(drm_intel_bo *bo)
 {
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
@@ -2826,7 +2803,7 @@
  * function can be used to restore the implicit sync before subsequent
  * rendering.
  */
-void
+drm_public void
 drm_intel_gem_bo_enable_implicit_sync(drm_intel_bo *bo)
 {
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
@@ -2838,7 +2815,7 @@
  * Query whether the kernel supports disabling of its implicit synchronisation
  * before execbuf. See drm_intel_gem_bo_disable_implicit_sync()
  */
-int
+drm_public int
 drm_intel_bufmgr_gem_can_disable_implicit_sync(drm_intel_bufmgr *bufmgr)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
@@ -2853,7 +2830,7 @@
  * allocation.  If this option is not enabled, all relocs will have fence
  * register allocated.
  */
-void
+drm_public void
 drm_intel_bufmgr_gem_enable_fenced_relocs(drm_intel_bufmgr *bufmgr)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
@@ -3132,7 +3109,7 @@
 	}
 }
 
-void
+drm_public void
 drm_intel_bufmgr_gem_set_vma_cache_size(drm_intel_bufmgr *bufmgr, int limit)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
@@ -3201,7 +3178,7 @@
 	return devid;
 }
 
-int
+drm_public int
 drm_intel_bufmgr_gem_get_devid(drm_intel_bufmgr *bufmgr)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
@@ -3215,7 +3192,7 @@
  * This function has to be called before drm_intel_bufmgr_gem_set_aub_dump()
  * for it to have any effect.
  */
-void
+drm_public void
 drm_intel_bufmgr_gem_set_aub_filename(drm_intel_bufmgr *bufmgr,
 				      const char *filename)
 {
@@ -3229,7 +3206,7 @@
  * You can set up a GTT and upload your objects into the referenced
  * space, then send off batchbuffers and get BMPs out the other end.
  */
-void
+drm_public void
 drm_intel_bufmgr_gem_set_aub_dump(drm_intel_bufmgr *bufmgr, int enable)
 {
 	fprintf(stderr, "libdrm aub dumping is deprecated.\n\n"
@@ -3239,7 +3216,7 @@
 		"See the intel_aubdump man page for more details.\n");
 }
 
-drm_intel_context *
+drm_public drm_intel_context *
 drm_intel_gem_context_create(drm_intel_bufmgr *bufmgr)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
@@ -3266,7 +3243,7 @@
 	return context;
 }
 
-int
+drm_public int
 drm_intel_gem_context_get_id(drm_intel_context *ctx, uint32_t *ctx_id)
 {
 	if (ctx == NULL)
@@ -3277,7 +3254,7 @@
 	return 0;
 }
 
-void
+drm_public void
 drm_intel_gem_context_destroy(drm_intel_context *ctx)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem;
@@ -3300,7 +3277,7 @@
 	free(ctx);
 }
 
-int
+drm_public int
 drm_intel_get_reset_stats(drm_intel_context *ctx,
 			  uint32_t *reset_count,
 			  uint32_t *active,
@@ -3334,7 +3311,7 @@
 	return ret;
 }
 
-int
+drm_public int
 drm_intel_reg_read(drm_intel_bufmgr *bufmgr,
 		   uint32_t offset,
 		   uint64_t *result)
@@ -3352,7 +3329,7 @@
 	return ret;
 }
 
-int
+drm_public int
 drm_intel_get_subslice_total(int fd, unsigned int *subslice_total)
 {
 	drm_i915_getparam_t gp;
@@ -3368,7 +3345,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_get_eu_total(int fd, unsigned int *eu_total)
 {
 	drm_i915_getparam_t gp;
@@ -3384,7 +3361,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drm_intel_get_pooled_eu(int fd)
 {
 	drm_i915_getparam_t gp;
@@ -3399,7 +3376,7 @@
 	return ret;
 }
 
-int
+drm_public int
 drm_intel_get_min_eu_in_pool(int fd)
 {
 	drm_i915_getparam_t gp;
@@ -3435,8 +3412,7 @@
  * default state (no annotations), call this function with a \c count
  * of zero.
  */
-void
-drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo,
+drm_public void drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo,
 					 drm_intel_aub_annotation *annotations,
 					 unsigned count)
 {
@@ -3477,7 +3453,7 @@
 	}
 }
 
-void *drm_intel_gem_bo_map__gtt(drm_intel_bo *bo)
+drm_public void *drm_intel_gem_bo_map__gtt(drm_intel_bo *bo)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
@@ -3525,7 +3501,7 @@
 	return bo_gem->gtt_virtual;
 }
 
-void *drm_intel_gem_bo_map__cpu(drm_intel_bo *bo)
+drm_public void *drm_intel_gem_bo_map__cpu(drm_intel_bo *bo)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
@@ -3569,7 +3545,7 @@
 	return bo_gem->mem_virtual;
 }
 
-void *drm_intel_gem_bo_map__wc(drm_intel_bo *bo)
+drm_public void *drm_intel_gem_bo_map__wc(drm_intel_bo *bo)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
@@ -3618,7 +3594,7 @@
  *
  * \param fd File descriptor of the opened DRM device.
  */
-drm_intel_bufmgr *
+drm_public drm_intel_bufmgr *
 drm_intel_bufmgr_gem_init(int fd, int batch_size)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem;
@@ -3679,9 +3655,7 @@
 		bufmgr_gem->gen = 7;
 	else if (IS_GEN8(bufmgr_gem->pci_device))
 		bufmgr_gem->gen = 8;
-	else if (IS_GEN9(bufmgr_gem->pci_device))
-		bufmgr_gem->gen = 9;
-	else {
+	else if (!intel_get_genx(bufmgr_gem->pci_device, &bufmgr_gem->gen)) {
 		free(bufmgr_gem);
 		bufmgr_gem = NULL;
 		goto exit;
diff --git a/intel/intel_chipset.c b/intel/intel_chipset.c
new file mode 100644
index 0000000..5aa4a2f
--- /dev/null
+++ b/intel/intel_chipset.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "intel_chipset.h"
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "i915_pciids.h"
+
+#undef INTEL_VGA_DEVICE
+#define INTEL_VGA_DEVICE(id, gen) { id, gen }
+
+static const struct pci_device {
+	uint16_t device;
+	uint16_t gen;
+} pciids[] = {
+	/* Keep ids sorted by gen; latest gen first */
+	INTEL_ICL_11_IDS(11),
+	INTEL_CNL_IDS(10),
+	INTEL_CFL_IDS(9),
+	INTEL_GLK_IDS(9),
+	INTEL_KBL_IDS(9),
+	INTEL_BXT_IDS(9),
+	INTEL_SKL_IDS(9),
+};
+
+drm_private bool intel_is_genx(unsigned int devid, int gen)
+{
+	const struct pci_device *p,
+		  *pend = pciids + sizeof(pciids) / sizeof(pciids[0]);
+
+	for (p = pciids; p < pend; p++) {
+		/* PCI IDs are sorted */
+		if (p->gen < gen)
+			break;
+
+		if (p->device != devid)
+			continue;
+
+		if (gen == p->gen)
+			return true;
+
+		break;
+	}
+
+	return false;
+}
+
+drm_private bool intel_get_genx(unsigned int devid, int *gen)
+{
+	const struct pci_device *p,
+		  *pend = pciids + sizeof(pciids) / sizeof(pciids[0]);
+
+	for (p = pciids; p < pend; p++) {
+		if (p->device != devid)
+			continue;
+
+		if (gen)
+			*gen = p->gen;
+
+		return true;
+	}
+
+	return false;
+}
diff --git a/intel/intel_chipset.h b/intel/intel_chipset.h
index 41fc0da..5db207c 100644
--- a/intel/intel_chipset.h
+++ b/intel/intel_chipset.h
@@ -165,61 +165,8 @@
 #define PCI_CHIP_CHERRYVIEW_2		0x22b2
 #define PCI_CHIP_CHERRYVIEW_3		0x22b3
 
-#define PCI_CHIP_SKYLAKE_DT_GT1		0x1902
-#define PCI_CHIP_SKYLAKE_ULT_GT1	0x1906
-#define PCI_CHIP_SKYLAKE_SRV_GT1	0x190A /* Reserved */
-#define PCI_CHIP_SKYLAKE_H_GT1		0x190B
-#define PCI_CHIP_SKYLAKE_ULX_GT1	0x190E /* Reserved */
 #define PCI_CHIP_SKYLAKE_DT_GT2		0x1912
-#define PCI_CHIP_SKYLAKE_FUSED0_GT2	0x1913 /* Reserved */
-#define PCI_CHIP_SKYLAKE_FUSED1_GT2	0x1915 /* Reserved */
-#define PCI_CHIP_SKYLAKE_ULT_GT2	0x1916
-#define PCI_CHIP_SKYLAKE_FUSED2_GT2	0x1917 /* Reserved */
-#define PCI_CHIP_SKYLAKE_SRV_GT2	0x191A /* Reserved */
-#define PCI_CHIP_SKYLAKE_HALO_GT2	0x191B
-#define PCI_CHIP_SKYLAKE_WKS_GT2 	0x191D
-#define PCI_CHIP_SKYLAKE_ULX_GT2	0x191E
-#define PCI_CHIP_SKYLAKE_MOBILE_GT2	0x1921 /* Reserved */
-#define PCI_CHIP_SKYLAKE_ULT_GT3_0	0x1923
-#define PCI_CHIP_SKYLAKE_ULT_GT3_1	0x1926
-#define PCI_CHIP_SKYLAKE_ULT_GT3_2	0x1927
-#define PCI_CHIP_SKYLAKE_SRV_GT4	0x192A
-#define PCI_CHIP_SKYLAKE_HALO_GT3	0x192B /* Reserved */
-#define PCI_CHIP_SKYLAKE_SRV_GT3	0x192D
-#define PCI_CHIP_SKYLAKE_DT_GT4		0x1932
-#define PCI_CHIP_SKYLAKE_SRV_GT4X	0x193A
-#define PCI_CHIP_SKYLAKE_H_GT4		0x193B
-#define PCI_CHIP_SKYLAKE_WKS_GT4	0x193D
-
-#define PCI_CHIP_KABYLAKE_ULT_GT2	0x5916
-#define PCI_CHIP_KABYLAKE_ULT_GT1_5	0x5913
-#define PCI_CHIP_KABYLAKE_ULT_GT1	0x5906
-#define PCI_CHIP_KABYLAKE_ULT_GT3_0	0x5923
-#define PCI_CHIP_KABYLAKE_ULT_GT3_1	0x5926
-#define PCI_CHIP_KABYLAKE_ULT_GT3_2	0x5927
-#define PCI_CHIP_KABYLAKE_ULT_GT2F	0x5921
-#define PCI_CHIP_KABYLAKE_ULX_GT1_5	0x5915
-#define PCI_CHIP_KABYLAKE_ULX_GT1	0x590E
-#define PCI_CHIP_KABYLAKE_ULX_GT2	0x591E
 #define PCI_CHIP_KABYLAKE_DT_GT2	0x5912
-#define PCI_CHIP_KABYLAKE_DT_GT1_5	0x5917
-#define PCI_CHIP_KABYLAKE_DT_GT1	0x5902
-#define PCI_CHIP_KABYLAKE_HALO_GT2	0x591B
-#define PCI_CHIP_KABYLAKE_HALO_GT4	0x593B
-#define PCI_CHIP_KABYLAKE_HALO_GT1_0	0x5908
-#define PCI_CHIP_KABYLAKE_HALO_GT1_1	0x590B
-#define PCI_CHIP_KABYLAKE_SRV_GT2	0x591A
-#define PCI_CHIP_KABYLAKE_SRV_GT1	0x590A
-#define PCI_CHIP_KABYLAKE_WKS_GT2	0x591D
-
-#define PCI_CHIP_BROXTON_0		0x0A84
-#define PCI_CHIP_BROXTON_1		0x1A84
-#define PCI_CHIP_BROXTON_2		0x5A84
-#define PCI_CHIP_BROXTON_3		0x1A85
-#define PCI_CHIP_BROXTON_4		0x5A85
-
-#define PCI_CHIP_GLK			0x3184
-#define PCI_CHIP_GLK_2X6		0x3185
 
 #define IS_MOBILE(devid)	((devid) == PCI_CHIP_I855_GM || \
 				 (devid) == PCI_CHIP_I915_GM || \
@@ -380,82 +327,16 @@
 #define IS_GEN8(devid)		(IS_BROADWELL(devid) || \
 				 IS_CHERRYVIEW(devid))
 
-#define IS_SKL_GT1(devid)	((devid) == PCI_CHIP_SKYLAKE_DT_GT1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_ULT_GT1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_SRV_GT1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_H_GT1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_ULX_GT1)
+/* New platforms use kernel pci ids */
+#include <stdbool.h>
+#include <libdrm_macros.h>
 
-#define IS_SKL_GT2(devid)	((devid) == PCI_CHIP_SKYLAKE_DT_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_FUSED0_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_FUSED1_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_ULT_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_FUSED2_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_SRV_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_HALO_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_WKS_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_ULX_GT2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_MOBILE_GT2)
+drm_private bool intel_is_genx(unsigned int devid, int gen);
+drm_private bool intel_get_genx(unsigned int devid, int *gen);
 
-#define IS_SKL_GT3(devid)	((devid) == PCI_CHIP_SKYLAKE_ULT_GT3_0	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_ULT_GT3_1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_ULT_GT3_2	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_HALO_GT3	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_SRV_GT3)
-
-#define IS_SKL_GT4(devid)	((devid) == PCI_CHIP_SKYLAKE_SRV_GT4	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_DT_GT4	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_SRV_GT4X	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_H_GT4	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_WKS_GT4)
-
-#define IS_KBL_GT1(devid)	((devid) == PCI_CHIP_KABYLAKE_ULT_GT1_5	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_ULX_GT1_5	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_DT_GT1_5	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT1	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_ULX_GT1	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_DT_GT1	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_HALO_GT1_0 || \
-				 (devid) == PCI_CHIP_KABYLAKE_HALO_GT1_1 || \
-				 (devid) == PCI_CHIP_KABYLAKE_SRV_GT1)
-
-#define IS_KBL_GT2(devid)	((devid) == PCI_CHIP_KABYLAKE_ULT_GT2	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT2F	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_ULX_GT2	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_DT_GT2	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_HALO_GT2	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_SRV_GT2	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_WKS_GT2)
-
-#define IS_KBL_GT3(devid)	((devid) == PCI_CHIP_KABYLAKE_ULT_GT3_0	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT3_1	|| \
-				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT3_2)
-
-#define IS_KBL_GT4(devid)	((devid) == PCI_CHIP_KABYLAKE_HALO_GT4)
-
-#define IS_KABYLAKE(devid)	(IS_KBL_GT1(devid) || \
-				 IS_KBL_GT2(devid) || \
-				 IS_KBL_GT3(devid) || \
-				 IS_KBL_GT4(devid))
-
-#define IS_SKYLAKE(devid)	(IS_SKL_GT1(devid) || \
-				 IS_SKL_GT2(devid) || \
-				 IS_SKL_GT3(devid) || \
-				 IS_SKL_GT4(devid))
-
-#define IS_BROXTON(devid)	((devid) == PCI_CHIP_BROXTON_0	|| \
-				 (devid) == PCI_CHIP_BROXTON_1	|| \
-				 (devid) == PCI_CHIP_BROXTON_2	|| \
-				 (devid) == PCI_CHIP_BROXTON_3	|| \
-				 (devid) == PCI_CHIP_BROXTON_4)
-
-#define IS_GEMINILAKE(devid)	((devid) == PCI_CHIP_GLK || \
-				 (devid) == PCI_CHIP_GLK_2X6)
-
-#define IS_GEN9(devid)		(IS_SKYLAKE(devid)  || \
-				 IS_BROXTON(devid)  || \
-				 IS_KABYLAKE(devid) || \
-				 IS_GEMINILAKE(devid))
+#define IS_GEN9(devid) intel_is_genx(devid, 9)
+#define IS_GEN10(devid) intel_is_genx(devid, 10)
+#define IS_GEN11(devid) intel_is_genx(devid, 11)
 
 #define IS_9XX(dev)		(IS_GEN3(dev) || \
 				 IS_GEN4(dev) || \
@@ -463,7 +344,6 @@
 				 IS_GEN6(dev) || \
 				 IS_GEN7(dev) || \
 				 IS_GEN8(dev) || \
-				 IS_GEN9(dev))
-
+				 intel_get_genx(dev, NULL))
 
 #endif /* _INTEL_CHIPSET_H */
diff --git a/intel/intel_decode.c b/intel/intel_decode.c
index 803d202..e0a5166 100644
--- a/intel/intel_decode.c
+++ b/intel/intel_decode.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <assert.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -3815,7 +3811,7 @@
 	return 1;
 }
 
-struct drm_intel_decode *
+drm_public struct drm_intel_decode *
 drm_intel_decode_context_alloc(uint32_t devid)
 {
 	struct drm_intel_decode *ctx;
@@ -3827,8 +3823,8 @@
 	ctx->devid = devid;
 	ctx->out = stdout;
 
-	if (IS_GEN9(devid))
-		ctx->gen = 9;
+	if (intel_get_genx(devid, &ctx->gen))
+		;
 	else if (IS_GEN8(devid))
 		ctx->gen = 8;
 	else if (IS_GEN7(devid))
@@ -3849,20 +3845,20 @@
 	return ctx;
 }
 
-void
+drm_public void
 drm_intel_decode_context_free(struct drm_intel_decode *ctx)
 {
 	free(ctx);
 }
 
-void
+drm_public void
 drm_intel_decode_set_dump_past_end(struct drm_intel_decode *ctx,
 				   int dump_past_end)
 {
 	ctx->dump_past_end = !!dump_past_end;
 }
 
-void
+drm_public void
 drm_intel_decode_set_batch_pointer(struct drm_intel_decode *ctx,
 				   void *data, uint32_t hw_offset, int count)
 {
@@ -3871,7 +3867,7 @@
 	ctx->base_count = count;
 }
 
-void
+drm_public void
 drm_intel_decode_set_head_tail(struct drm_intel_decode *ctx,
 			       uint32_t head, uint32_t tail)
 {
@@ -3879,7 +3875,7 @@
 	ctx->tail = tail;
 }
 
-void
+drm_public void
 drm_intel_decode_set_output_file(struct drm_intel_decode *ctx,
 				 FILE *output)
 {
@@ -3893,13 +3889,13 @@
  * \param count number of DWORDs to decode in the batch buffer
  * \param hw_offset hardware address for the buffer
  */
-void
+drm_public void
 drm_intel_decode(struct drm_intel_decode *ctx)
 {
 	int ret;
 	unsigned int index = 0;
 	uint32_t devid;
-	int size = ctx->base_count * 4;
+	int size;
 	void *temp;
 
 	if (!ctx)
@@ -3909,6 +3905,7 @@
 	 * the batchbuffer.  This lets us avoid a bunch of length
 	 * checking in statically sized packets.
 	 */
+	size = ctx->base_count * 4;
 	temp = malloc(size + 4096);
 	memcpy(temp, ctx->base_data, size);
 	memset((char *)temp + size, 0xd0, 4096);
diff --git a/intel/meson.build b/intel/meson.build
new file mode 100644
index 0000000..3d6bbac
--- /dev/null
+++ b/intel/meson.build
@@ -0,0 +1,106 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+libdrm_intel = shared_library(
+  'drm_intel',
+  [
+    files(
+      'intel_bufmgr.c', 'intel_bufmgr_fake.c', 'intel_bufmgr_gem.c',
+      'intel_decode.c', 'mm.c', 'intel_chipset.c',
+    ),
+    config_file,
+  ],
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  dependencies : [dep_pciaccess, dep_pthread_stubs, dep_rt, dep_valgrind, dep_atomic_ops],
+  c_args : libdrm_c_args,
+  version : '1.0.0',
+  install : true,
+)
+
+ext_libdrm_intel = declare_dependency(
+  link_with : [libdrm, libdrm_intel],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+install_headers(
+  'intel_bufmgr.h', 'intel_aub.h', 'intel_debug.h',
+  subdir : 'libdrm',
+)
+
+pkg.generate(
+  name : 'libdrm_intel',
+  libraries : libdrm_intel,
+  subdirs : ['.', 'libdrm'],
+  version : meson.project_version(),
+  requires : 'libdrm',
+  description : 'Userspace interface to intel kernel DRM services',
+)
+
+test_decode = executable(
+  'test_decode',
+  files('test_decode.c'),
+  include_directories : [inc_root, inc_drm],
+  link_with : [libdrm, libdrm_intel],
+  c_args : libdrm_c_args,
+)
+
+test(
+  'gen4-3d.batch',
+  prog_bash,
+  args : files('tests/gen4-3d.batch.sh'),
+  workdir : meson.current_build_dir(),
+)
+test(
+  'gen45-3d.batch',
+  prog_bash,
+  args : files('tests/gm45-3d.batch.sh'),
+  workdir : meson.current_build_dir(),
+)
+test(
+  'gen5-3d.batch',
+  prog_bash,
+  args : files('tests/gen5-3d.batch.sh'),
+  workdir : meson.current_build_dir(),
+)
+test(
+  'gen6-3d.batch',
+  prog_bash,
+  args : files('tests/gen6-3d.batch.sh'),
+  workdir : meson.current_build_dir(),
+)
+test(
+  'gen7-3d.batch',
+  prog_bash,
+  args : files('tests/gen7-3d.batch.sh'),
+  workdir : meson.current_build_dir(),
+)
+test(
+  'gen7-2d-copy.batch',
+  prog_bash,
+  args : files('tests/gen7-2d-copy.batch.sh'),
+  workdir : meson.current_build_dir(),
+)
+test(
+  'intel-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('intel-symbol-check'), libdrm_intel]
+)
diff --git a/intel/mm.c b/intel/mm.c
index 954e9dc..79d8719 100644
--- a/intel/mm.c
+++ b/intel/mm.c
@@ -22,10 +22,6 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <assert.h>
 
diff --git a/intel/mm.h b/intel/mm.h
index 8d83743..1b0f84f 100644
--- a/intel/mm.h
+++ b/intel/mm.h
@@ -29,10 +29,6 @@
 #ifndef MM_H
 #define MM_H
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include "libdrm_macros.h"
 
 struct mem_block {
diff --git a/intel/test_decode.c b/intel/test_decode.c
index b4eddcd..b9f5b92 100644
--- a/intel/test_decode.c
+++ b/intel/test_decode.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -91,7 +87,7 @@
 {
 	FILE *out = NULL;
 	void *ptr, *ref_ptr, *batch_ptr;
-#ifdef HAVE_OPEN_MEMSTREAM
+#if HAVE_OPEN_MEMSTREAM
 	size_t size;
 #endif
 	size_t ref_size, batch_size;
@@ -109,7 +105,7 @@
 	 * figure out how to output to a file in a safe and sane way
 	 * inside of an automake project's test infrastructure.
 	 */
-#ifdef HAVE_OPEN_MEMSTREAM
+#if HAVE_OPEN_MEMSTREAM
 	out = open_memstream((char **)&ptr, &size);
 #else
 	fprintf(stderr, "platform lacks open_memstream, skipping.\n");
diff --git a/libdrm_macros.h b/libdrm_macros.h
index b88fdce..0dca827 100644
--- a/libdrm_macros.h
+++ b/libdrm_macros.h
@@ -23,10 +23,12 @@
 #ifndef LIBDRM_LIBDRM_H
 #define LIBDRM_LIBDRM_H
 
-#if defined(HAVE_VISIBILITY)
+#if HAVE_VISIBILITY
 #  define drm_private __attribute__((visibility("hidden")))
+#  define drm_public  __attribute__((visibility("default")))
 #else
 #  define drm_private
+#  define drm_public
 #endif
 
 
diff --git a/libkms/Makefile.am b/libkms/Makefile.am
index 461fc35..ff4c1b2 100644
--- a/libkms/Makefile.am
+++ b/libkms/Makefile.am
@@ -2,6 +2,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)
 
@@ -39,5 +40,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libkms.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = kms-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/libkms/api.c b/libkms/api.c
index 354d8a2..caca1a8 100644
--- a/libkms/api.c
+++ b/libkms/api.c
@@ -26,10 +26,6 @@
  **************************************************************************/
 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -37,12 +33,12 @@
 #include "libdrm_macros.h"
 #include "internal.h"
 
-int kms_create(int fd, struct kms_driver **out)
+drm_public int kms_create(int fd, struct kms_driver **out)
 {
 	return linux_create(fd, out);
 }
 
-int kms_get_prop(struct kms_driver *kms, unsigned key, unsigned *out)
+drm_public int kms_get_prop(struct kms_driver *kms, unsigned key, unsigned *out)
 {
 	switch (key) {
 	case KMS_BO_TYPE:
@@ -53,7 +49,7 @@
 	return kms->get_prop(kms, key, out);
 }
 
-int kms_destroy(struct kms_driver **kms)
+drm_public int kms_destroy(struct kms_driver **kms)
 {
 	if (!(*kms))
 		return 0;
@@ -63,7 +59,7 @@
 	return 0;
 }
 
-int kms_bo_create(struct kms_driver *kms, const unsigned *attr, struct kms_bo **out)
+drm_public int kms_bo_create(struct kms_driver *kms, const unsigned *attr, struct kms_bo **out)
 {
 	unsigned width = 0;
 	unsigned height = 0;
@@ -101,7 +97,7 @@
 	return kms->bo_create(kms, width, height, type, attr, out);
 }
 
-int kms_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out)
+drm_public int kms_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out)
 {
 	switch (key) {
 	case KMS_PITCH:
@@ -117,17 +113,17 @@
 	return 0;
 }
 
-int kms_bo_map(struct kms_bo *bo, void **out)
+drm_public int kms_bo_map(struct kms_bo *bo, void **out)
 {
 	return bo->kms->bo_map(bo, out);
 }
 
-int kms_bo_unmap(struct kms_bo *bo)
+drm_public int kms_bo_unmap(struct kms_bo *bo)
 {
 	return bo->kms->bo_unmap(bo);
 }
 
-int kms_bo_destroy(struct kms_bo **bo)
+drm_public int kms_bo_destroy(struct kms_bo **bo)
 {
 	int ret;
 
diff --git a/libkms/dumb.c b/libkms/dumb.c
index b95a072..17efc10 100644
--- a/libkms/dumb.c
+++ b/libkms/dumb.c
@@ -26,10 +26,6 @@
  **************************************************************************/
 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/libkms/exynos.c b/libkms/exynos.c
index 0e97fb5..ef64a66 100644
--- a/libkms/exynos.c
+++ b/libkms/exynos.c
@@ -5,16 +5,26 @@
  *	SooChan Lim <sc1.lim@samsung.com>
  *      Sangjin LEE <lsj119@samsung.com>
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 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.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/libkms/intel.c b/libkms/intel.c
index 3d8ca05..859e7a0 100644
--- a/libkms/intel.c
+++ b/libkms/intel.c
@@ -26,10 +26,6 @@
  **************************************************************************/
 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/libkms/internal.h b/libkms/internal.h
index 905f5b1..8b386db 100644
--- a/libkms/internal.h
+++ b/libkms/internal.h
@@ -29,10 +29,6 @@
 #ifndef INTERNAL_H_
 #define INTERNAL_H_
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include "libdrm_macros.h"
 #include "libkms.h"
 
diff --git a/libkms/kms-symbol-check b/libkms/kms-symbol-check
index 658b269..30f444f 100755
--- a/libkms/kms-symbol-check
+++ b/libkms/kms-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.sources/LIBKMS_H_FILES
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libkms.so} | awk '{print $3}'| while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libkms.so} | awk '{print $3}'| while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
diff --git a/libkms/linux.c b/libkms/linux.c
index 0b50777..5620505 100644
--- a/libkms/linux.c
+++ b/libkms/linux.c
@@ -29,10 +29,6 @@
  * going from fd to pci id via fstat and udev.
  */
 
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -110,27 +106,27 @@
 	if (ret)
 		return ret;
 
-#ifdef HAVE_INTEL
+#if HAVE_INTEL
 	if (!strcmp(name, "intel"))
 		ret = intel_create(fd, out);
 	else
 #endif
-#ifdef HAVE_VMWGFX
+#if HAVE_VMWGFX
 	if (!strcmp(name, "vmwgfx"))
 		ret = vmwgfx_create(fd, out);
 	else
 #endif
-#ifdef HAVE_NOUVEAU
+#if HAVE_NOUVEAU
 	if (!strcmp(name, "nouveau"))
 		ret = nouveau_create(fd, out);
 	else
 #endif
-#ifdef HAVE_RADEON
+#if HAVE_RADEON
 	if (!strcmp(name, "radeon"))
 		ret = radeon_create(fd, out);
 	else
 #endif
-#ifdef HAVE_EXYNOS
+#if HAVE_EXYNOS
 	if (!strcmp(name, "exynos"))
 		ret = exynos_create(fd, out);
 	else
diff --git a/libkms/meson.build b/libkms/meson.build
new file mode 100644
index 0000000..dc93160
--- /dev/null
+++ b/libkms/meson.build
@@ -0,0 +1,75 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+libkms_include = [inc_root, inc_drm]
+files_libkms = files(
+  'linux.c',
+  'dumb.c',
+  'api.c',
+)
+if with_vmwgfx
+  files_libkms += files('vmwgfx.c')
+endif
+if with_intel
+  files_libkms += files('intel.c')
+endif
+if with_nouveau
+  files_libkms += files('nouveau.c')
+endif
+if with_radeon
+  files_libkms += files('radeon.c')
+endif
+if with_exynos
+  files_libkms += files('exynos.c')
+  libkms_include += include_directories('../exynos')
+endif
+
+libkms = shared_library(
+  'kms',
+  [files_libkms, config_file],
+  c_args : libdrm_c_args,
+  include_directories : libkms_include,
+  link_with : libdrm,
+  version : '1.0.0',
+  install : true,
+)
+
+ext_libkms = declare_dependency(
+  link_with : [libdrm, libkms],
+  include_directories : [libkms_include],
+)
+
+install_headers('libkms.h', subdir : 'libkms')
+
+pkg.generate(
+  name : 'libkms',
+  libraries : libkms,
+  subdirs : ['libkms'],
+  version : '1.0.0',
+  requires_private : 'libdrm',
+  description : 'Library that abstracts away the different mm interfaces for kernel drivers',
+)
+
+test(
+  'kms-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('kms-symbol-check'), libkms]
+)
diff --git a/libkms/nouveau.c b/libkms/nouveau.c
index d10e0fd..7fe23db 100644
--- a/libkms/nouveau.c
+++ b/libkms/nouveau.c
@@ -26,10 +26,6 @@
  **************************************************************************/
 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/libkms/radeon.c b/libkms/radeon.c
index aaeeaf3..2cb2b11 100644
--- a/libkms/radeon.c
+++ b/libkms/radeon.c
@@ -26,10 +26,6 @@
  **************************************************************************/
 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/libkms/vmwgfx.c b/libkms/vmwgfx.c
index 6a24fd4..f0e40be 100644
--- a/libkms/vmwgfx.c
+++ b/libkms/vmwgfx.c
@@ -26,10 +26,6 @@
  **************************************************************************/
 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/man/drm-kms.xml b/man/drm-kms.xml
index ae38dc8..eb04c26 100644
--- a/man/drm-kms.xml
+++ b/man/drm-kms.xml
@@ -309,8 +309,8 @@
   <refsect1>
     <title>Reporting Bugs</title>
     <para>Bugs in this manual should be reported to
-          http://bugs.freedesktop.org under the "Mesa" product, with "Other" or
-          "libdrm" as the component.</para>
+      https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&amp;component=libdrm
+      under the "DRI" product, component "libdrm"</para>
   </refsect1>
 
   <refsect1>
diff --git a/man/drm-memory.xml b/man/drm-memory.xml
index 6b4f075..3aa7cf2 100644
--- a/man/drm-memory.xml
+++ b/man/drm-memory.xml
@@ -410,8 +410,8 @@
   <refsect1>
     <title>Reporting Bugs</title>
     <para>Bugs in this manual should be reported to
-          http://bugs.freedesktop.org under the "Mesa" product, with "Other" or
-          "libdrm" as the component.</para>
+      https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&amp;component=libdrm
+      under the "DRI" product, component "libdrm"</para>
   </refsect1>
 
   <refsect1>
diff --git a/man/drm.xml b/man/drm.xml
index 5a49fe1..1f55966 100644
--- a/man/drm.xml
+++ b/man/drm.xml
@@ -50,7 +50,7 @@
 
     <para>In earlier days, the kernel framework was solely used to provide raw
           hardware access to priviledged user-space processes which implement
-          all the hardware abstraction layers. But more and more tasks where
+          all the hardware abstraction layers. But more and more tasks were
           moved into the kernel. All these interfaces are based on
           <citerefentry><refentrytitle>ioctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
           commands on the DRM character device. The <emphasis>libdrm</emphasis>
@@ -119,8 +119,8 @@
   <refsect1>
     <title>Reporting Bugs</title>
     <para>Bugs in this manual should be reported to
-          http://bugs.freedesktop.org under the "Mesa" product, with "Other" or
-          "libdrm" as the component.</para>
+      https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&amp;component=libdrm
+      under the "DRI" product, component "libdrm"</para>
   </refsect1>
 
   <refsect1>
diff --git a/man/drmAvailable.xml b/man/drmAvailable.xml
index 55bef94..1e5d787 100644
--- a/man/drmAvailable.xml
+++ b/man/drmAvailable.xml
@@ -61,8 +61,8 @@
   <refsect1>
     <title>Reporting Bugs</title>
     <para>Bugs in this function should be reported to
-          http://bugs.freedesktop.org under the "Mesa" product, with "Other" or
-          "libdrm" as the component.</para>
+      https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&amp;component=libdrm
+      under the "DRI" product, component "libdrm"</para>
   </refsect1>
 
   <refsect1>
diff --git a/man/drmHandleEvent.xml b/man/drmHandleEvent.xml
index b1006e5..8330442 100644
--- a/man/drmHandleEvent.xml
+++ b/man/drmHandleEvent.xml
@@ -86,8 +86,8 @@
   <refsect1>
     <title>Reporting Bugs</title>
     <para>Bugs in this function should be reported to
-          http://bugs.freedesktop.org under the "Mesa" product, with "Other" or
-          "libdrm" as the component.</para>
+      https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&amp;component=libdrm
+      under the "DRI" product, component "libdrm"</para>
   </refsect1>
 
   <refsect1>
diff --git a/man/drmModeGetResources.xml b/man/drmModeGetResources.xml
index 2f5e8c2..0ab6a68 100644
--- a/man/drmModeGetResources.xml
+++ b/man/drmModeGetResources.xml
@@ -116,8 +116,8 @@
   <refsect1>
     <title>Reporting Bugs</title>
     <para>Bugs in this function should be reported to
-          http://bugs.freedesktop.org under the "Mesa" product, with "Other" or
-          "libdrm" as the component.</para>
+      https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&amp;component=libdrm
+      under the "DRI" product, component "libdrm"</para>
   </refsect1>
 
   <refsect1>
diff --git a/man/meson.build b/man/meson.build
new file mode 100644
index 0000000..45eaeda
--- /dev/null
+++ b/man/meson.build
@@ -0,0 +1,67 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+xsltproc_args = [
+  '--stringparam', 'man.authors.section.enabled', '0',
+  '--stringparam', 'man.copyright.section.enabled', '0',
+  '--stringparam', 'funcsynopsis.style', 'ansi',
+  '--stringparam', 'man.output.quietly', '1',
+  '--nonet', manpage_style,
+]
+
+xmls = [
+  ['drm', '7'], ['drm-kms', '7'], ['drm-memory', '7'], ['drmAvailable', '3'],
+  ['drmHandleEvent', '3'], ['drmModeGetResources', '3']
+]
+foreach x : xmls
+  m = x[0]
+  s = x[1]
+  custom_target(
+    m,
+    input : files('@0@.xml'.format(m)),
+    output : '@0@.@1@'.format(m, s),
+    command : [prog_xslt, '-o', '@OUTPUT@', xsltproc_args, '@INPUT0@'],
+    install : true,
+    install_dir : join_paths(get_option('mandir'), 'man@0@'.format(s)),
+    build_by_default : true,
+  )
+endforeach
+
+foreach x : ['drm-mm', 'drm-gem', 'drm-ttm']
+  gen = custom_target(
+    'gen-@0@'.format(x),
+    input : 'drm-memory.xml',
+    output : '@0@.xml'.format(x),
+    command : [
+      prog_sed, '-e', 's@^\.so \([a-z_]\+\)\.\([0-9]\)$$@\.so man\2\/\1\.\2@',
+      '@INPUT@',
+    ],
+    capture : true,
+  )
+  custom_target(
+    '@0@.7'.format(x),
+    input : gen,
+    output : '@0@.7'.format(x, '7'),
+    command : [prog_xslt, '-o', '@OUTPUT@', xsltproc_args, '@INPUT@'],
+    install : true,
+    install_dir : join_paths(get_option('mandir'), 'man7'),
+    build_by_default : true,
+  )
+endforeach
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..b3eb846
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,386 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+project(
+  'libdrm',
+  ['c'],
+  version : '2.4.97',
+  license : 'MIT',
+  meson_version : '>= 0.43',
+  default_options : ['buildtype=debugoptimized', 'c_std=gnu99'],
+)
+
+pkg = import('pkgconfig')
+
+config = configuration_data()
+
+config.set10('UDEV', get_option('udev'))
+with_freedreno_kgsl = get_option('freedreno-kgsl')
+with_install_tests = get_option('install-test-programs')
+
+if ['freebsd', 'dragonfly', 'netbsd'].contains(host_machine.system())
+  dep_pthread_stubs = dependency('pthread-stubs', version : '>= 0.4')
+else
+  dep_pthread_stubs = []
+endif
+dep_threads = dependency('threads')
+
+cc = meson.get_compiler('c')
+
+# Check for atomics
+intel_atomics = false
+lib_atomics = false
+
+dep_atomic_ops = dependency('atomic_ops', required : false)
+if cc.compiles('''
+    int atomic_add(int *i) { return __sync_add_and_fetch (i, 1); }
+    int atomic_cmpxchg(int *i, int j, int k) { return __sync_val_compare_and_swap (i, j, k); }
+    ''',
+    name : 'Intel Atomics')
+  intel_atomics = true
+  with_atomics = true
+  dep_atomic_ops = []
+elif dep_atomic_ops.found()
+  lib_atomics = true
+  with_atomics = true
+elif cc.has_function('atomic_cas_uint')
+  with_atomics = true
+else
+  with_atomics = false
+endif
+
+config.set10('HAVE_LIBDRM_ATOMIC_PRIMITIVES', intel_atomics)
+config.set10('HAVE_LIB_ATOMIC_OPS', lib_atomics)
+
+with_intel = false
+_intel = get_option('intel')
+if _intel != 'false'
+  if _intel == 'true' and not with_atomics
+    error('libdrm_intel requires atomics.')
+  else
+    with_intel = _intel == 'true' or host_machine.cpu_family().startswith('x86')
+  endif
+endif
+
+with_radeon = false
+_radeon = get_option('radeon')
+if _radeon != 'false'
+  if _radeon == 'true' and not with_atomics
+    error('libdrm_radeon requires atomics.')
+  endif
+  with_radeon = true
+endif
+
+with_amdgpu = false
+_amdgpu = get_option('amdgpu')
+if _amdgpu != 'false'
+  if _amdgpu == 'true' and not with_atomics
+    error('libdrm_amdgpu requires atomics.')
+  endif
+  with_amdgpu = true
+endif
+
+with_nouveau = false
+_nouveau = get_option('nouveau')
+if _nouveau != 'false'
+  if _nouveau == 'true' and not with_atomics
+    error('libdrm_nouveau requires atomics.')
+  endif
+  with_nouveau = true
+endif
+
+with_vmwgfx = false
+_vmwgfx = get_option('vmwgfx')
+if _vmwgfx != 'false'
+  with_vmwgfx = true
+endif
+
+with_omap = false
+_omap = get_option('omap')
+if _omap == 'true'
+  if not with_atomics
+    error('libdrm_omap requires atomics.')
+  endif
+  with_omap = true
+endif
+
+with_freedreno = false
+_freedreno = get_option('freedreno')
+if _freedreno != 'false'
+  if _freedreno == 'true' and not with_atomics
+    error('libdrm_freedreno requires atomics.')
+  else
+    with_freedreno = _freedreno == 'true' or ['arm', 'aarch64'].contains(host_machine.cpu_family())
+  endif
+endif
+
+with_tegra = false
+_tegra = get_option('tegra')
+if _tegra == 'true'
+  if not with_atomics
+    error('libdrm_tegra requires atomics.')
+  endif
+  with_tegra = true
+endif
+
+with_etnaviv = false
+_etnaviv = get_option('etnaviv')
+if _etnaviv == 'true'
+  if not with_atomics
+    error('libdrm_etnaviv requires atomics.')
+  endif
+  with_etnaviv = true
+endif
+
+with_exynos = get_option('exynos') == 'true'
+
+with_vc4 = false
+_vc4 = get_option('vc4')
+if _vc4 != 'false'
+  with_vc4 = _vc4 == 'true' or ['arm', 'aarch64'].contains(host_machine.cpu_family())
+endif
+
+# XXX: Aparently only freebsd and dragonfly bsd actually need this (and
+# gnu/kfreebsd), not openbsd and netbsd
+with_libkms = false
+_libkms = get_option('libkms')
+if _libkms != 'false'
+  with_libkms = _libkms == 'true' or ['linux', 'freebsd', 'dragonfly'].contains(host_machine.system())
+endif
+
+# Among others FreeBSD does not have a separate dl library.
+if not cc.has_function('dlsym')
+  dep_dl = cc.find_library('dl', required : with_nouveau)
+else
+  dep_dl = []
+endif
+# clock_gettime might require -rt, or it might not. find out
+if not cc.has_function('clock_gettime', prefix : '#define _GNU_SOURCE\n#include <time.h>')
+  # XXX: untested
+  dep_rt = cc.find_library('rt')
+else
+  dep_rt = []
+endif
+dep_m = cc.find_library('m', required : false)
+foreach header : ['sys/sysctl.h', 'sys/select.h', 'alloca.h']
+  config.set('HAVE_' + header.underscorify().to_upper(),
+    cc.compiles('#include <@0@>'.format(header), name : '@0@ works'.format(header)))
+endforeach
+if cc.has_header_symbol('sys/sysmacros.h', 'major')
+  config.set10('MAJOR_IN_SYSMACROS', true)
+elif cc.has_header_symbol('sys/mkdev.h', 'major')
+  config.set10('MAJOR_IN_MKDEV', true)
+endif
+config.set10('HAVE_OPEN_MEMSTREAM', cc.has_function('open_memstream'))
+
+warn_c_args = []
+foreach a : ['-Wall', '-Wextra', '-Wsign-compare', '-Werror=undef',
+             '-Werror=implicit-function-declaration', '-Wpointer-arith',
+             '-Wwrite-strings', '-Wstrict-prototypes', '-Wmissing-prototypes',
+             '-Wmissing-declarations', '-Wnested-externs', '-Wpacked',
+             '-Wswitch-enum', '-Wmissing-format-attribute',
+             '-Wstrict-aliasing=2', '-Winit-self', '-Winline', '-Wshadow',
+             '-Wdeclaration-after-statement', '-Wold-style-definition']
+  if cc.has_argument(a)
+    warn_c_args += a
+  endif
+endforeach
+# GCC will never error for -Wno-*, so check for -W* then add -Wno-* to the list
+# of options
+foreach a : ['unused-parameter', 'attributes', 'long-long',
+             'missing-field-initializers']
+  if cc.has_argument('-W@0@'.format(a))
+    warn_c_args += '-Wno-@0@'.format(a)
+  endif
+endforeach
+
+# all c args:
+libdrm_c_args = warn_c_args + ['-fvisibility=hidden']
+
+
+dep_pciaccess = dependency('pciaccess', version : '>= 0.10', required : with_intel)
+dep_cunit = dependency('cunit', version : '>= 2.1', required : false)
+_cairo_tests = get_option('cairo-tests')
+if _cairo_tests != 'false'
+  dep_cairo = dependency('cairo', required : _cairo_tests == 'true')
+  with_cairo_tests = dep_cairo.found()
+else
+  dep_cairo = []
+  with_cairo_tests = false
+endif
+_valgrind = get_option('valgrind')
+if _valgrind != 'false'
+  dep_valgrind = dependency('valgrind', required : _valgrind == 'true')
+  with_valgrind = dep_valgrind.found()
+else
+  dep_valgrind = []
+  with_valgrind = false
+endif
+
+with_man_pages = get_option('man-pages')
+prog_xslt = find_program('xsltproc', required : with_man_pages == 'true')
+prog_sed = find_program('sed', required : with_man_pages == 'true')
+manpage_style = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
+if prog_xslt.found()
+  if run_command(prog_xslt, '--nonet', manpage_style).returncode() != 0
+    if with_man_pages == 'true'
+      error('Manpage style sheet cannot be found')
+    endif
+    with_man_pages = 'false'
+  endif
+endif
+with_man_pages = with_man_pages != 'false' and prog_xslt.found() and prog_sed.found()
+
+# Used for tets
+prog_bash = find_program('bash')
+
+config.set10('HAVE_VISIBILITY',
+  cc.compiles('''int foo_hidden(void) __attribute__((visibility(("hidden"))));''',
+              name : 'compiler supports __attribute__(("hidden"))'))
+
+foreach t : [
+             [with_exynos, 'EXYNOS'],
+             [with_freedreno_kgsl, 'FREEDRENO_KGSL'],
+             [with_intel, 'INTEL'],
+             [with_nouveau, 'NOUVEAU'],
+             [with_radeon, 'RADEON'],
+             [with_vc4, 'VC4'],
+             [with_vmwgfx, 'VMWGFX'],
+             [with_cairo_tests, 'CAIRO'],
+             [with_valgrind, 'VALGRIND'],
+            ]
+  config.set10('HAVE_@0@'.format(t[1]), t[0])
+endforeach
+if with_freedreno_kgsl and not with_freedreno
+  error('cannot enable freedreno-kgsl without freedreno support')
+endif
+config.set10('_GNU_SOURCE', true)
+config_file = configure_file(
+  configuration : config,
+  output : 'config.h',
+)
+add_project_arguments('-include', 'config.h', language : 'c')
+
+inc_root = include_directories('.')
+inc_drm = include_directories('include/drm')
+
+libdrm = shared_library(
+  'drm',
+  [files(
+     'xf86drm.c', 'xf86drmHash.c', 'xf86drmRandom.c', 'xf86drmSL.c',
+     'xf86drmMode.c'
+   ),
+   config_file,
+  ],
+  c_args : libdrm_c_args,
+  dependencies : [dep_valgrind, dep_rt, dep_m],
+  include_directories : inc_drm,
+  version : '2.4.0',
+  install : true,
+)
+
+ext_libdrm = declare_dependency(
+  link_with : libdrm,
+  include_directories : [inc_root, inc_drm],
+)
+
+install_headers('libsync.h', 'xf86drm.h', 'xf86drmMode.h')
+install_headers(
+  'include/drm/drm.h', 'include/drm/drm_fourcc.h', 'include/drm/drm_mode.h',
+  'include/drm/drm_sarea.h', 'include/drm/i915_drm.h',
+  'include/drm/mach64_drm.h', 'include/drm/mga_drm.h',
+  'include/drm/msm_drm.h', 'include/drm/nouveau_drm.h',
+  'include/drm/qxl_drm.h', 'include/drm/r128_drm.h',
+  'include/drm/radeon_drm.h', 'include/drm/amdgpu_drm.h',
+  'include/drm/savage_drm.h', 'include/drm/sis_drm.h',
+  'include/drm/tegra_drm.h', 'include/drm/vc4_drm.h',
+  'include/drm/via_drm.h', 'include/drm/virtgpu_drm.h',
+  subdir : 'libdrm',
+)
+if with_vmwgfx
+  install_headers('include/drm/vmwgfx_drm.h', subdir : 'libdrm')
+endif
+
+pkg.generate(
+  name : 'libdrm',
+  libraries : libdrm,
+  subdirs : ['.', 'libdrm'],
+  version : meson.project_version(),
+  description : 'Userspace interface to kernel DRM services',
+)
+
+env_test = environment()
+env_test.set('NM', find_program('nm').path())
+
+if with_libkms
+  subdir('libkms')
+endif
+if with_intel
+  subdir('intel')
+endif
+if with_nouveau
+  subdir('nouveau')
+endif
+if with_radeon
+  subdir('radeon')
+endif
+if with_amdgpu
+  subdir('amdgpu')
+endif
+if with_omap
+  subdir('omap')
+endif
+if with_exynos
+  subdir('exynos')
+endif
+if with_freedreno
+  subdir('freedreno')
+endif
+if with_tegra
+  subdir('tegra')
+endif
+if with_vc4
+  subdir('vc4')
+endif
+if with_etnaviv
+  subdir('etnaviv')
+endif
+if with_man_pages
+  subdir('man')
+endif
+subdir('data')
+subdir('tests')
+
+message('')
+message('@0@ will be compiled with:'.format(meson.project_name()))
+message('')
+message('  libkms         @0@'.format(with_libkms))
+message('  Intel API      @0@'.format(with_intel))
+message('  vmwgfx API     @0@'.format(with_vmwgfx))
+message('  Radeon API     @0@'.format(with_radeon))
+message('  AMDGPU API     @0@'.format(with_amdgpu))
+message('  Nouveau API    @0@'.format(with_nouveau))
+message('  OMAP API       @0@'.format(with_omap))
+message('  EXYNOS API     @0@'.format(with_exynos))
+message('  Freedreno API  @0@ (kgsl: @1@)'.format(with_freedreno, with_freedreno_kgsl))
+message('  Tegra API      @0@'.format(with_tegra))
+message('  VC4 API        @0@'.format(with_vc4))
+message('  Etnaviv API    @0@'.format(with_etnaviv))
+message('')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..8af33f1
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,143 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+option(
+  'libkms',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : 'Build libkms mm abstraction library.',
+)
+option(
+  'intel',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for Intel's KMS API.''',
+)
+option(
+  'radeon',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for radeons's KMS API.''',
+)
+option(
+  'amdgpu',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for amdgpu's KMS API.''',
+)
+option(
+  'nouveau',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for nouveau's KMS API.''',
+)
+option(
+  'vmwgfx',
+  type : 'combo',
+  value : 'true',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for vmgfx's KMS API.''',
+)
+option(
+  'omap',
+  type : 'combo',
+  value : 'false',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for OMAP's experimental KMS API.''',
+)
+option(
+  'exynos',
+  type : 'combo',
+  value : 'false',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for EXYNOS's experimental KMS API.''',
+)
+option(
+  'freedreno',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for freedreno's KMS API.''',
+)
+option(
+  'tegra',
+  type : 'combo',
+  value : 'false',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for Tegra's experimental KMS API.''',
+)
+option(
+  'vc4',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for vc4's KMS API.''',
+)
+option(
+  'etnaviv',
+  type : 'combo',
+  value : 'false',
+  choices : ['true', 'false', 'auto'],
+  description : '''Enable support for etnaviv's experimental KMS API.''',
+)
+option(
+  'cairo-tests',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : 'Enable support for Cairo rendering in tests.',
+)
+option(
+  'man-pages',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : 'Enable manpage generation and installation.',
+)
+option(
+  'valgrind',
+  type : 'combo',
+  value : 'auto',
+  choices : ['true', 'false', 'auto'],
+  description : 'Build libdrm with valgrind support.',
+)
+option(
+  'freedreno-kgsl',
+  type : 'boolean',
+  value : false,
+  description : 'Enable support for freedreno to use downstream android kernel API.',
+)
+option(
+  'install-test-programs',
+  type : 'boolean',
+  value : false,
+  description : 'Install test programs.',
+)
+option(
+  'udev',
+  type : 'boolean',
+  value : false,
+  description : 'Enable support for using udev instead of mknod.',
+)
diff --git a/nouveau/Makefile.am b/nouveau/Makefile.am
index 344a844..5574fd8 100644
--- a/nouveau/Makefile.am
+++ b/nouveau/Makefile.am
@@ -2,6 +2,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	-I$(top_srcdir)/include/drm \
@@ -29,5 +30,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_nouveau.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = nouveau-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/nouveau/abi16.c b/nouveau/abi16.c
index ee38c0c..ba2501e 100644
--- a/nouveau/abi16.c
+++ b/nouveau/abi16.c
@@ -22,10 +22,6 @@
  * Authors: Ben Skeggs
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
 #include <stdlib.h>
 #include <stdint.h>
 #include <stddef.h>
diff --git a/nouveau/bufctx.c b/nouveau/bufctx.c
index 4f76e5d..00924b3 100644
--- a/nouveau/bufctx.c
+++ b/nouveau/bufctx.c
@@ -22,10 +22,6 @@
  * Authors: Ben Skeggs
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -62,7 +58,7 @@
 	return (struct nouveau_bufctx_priv *)bctx;
 }
 
-int
+drm_public int
 nouveau_bufctx_new(struct nouveau_client *client, int bins,
 		   struct nouveau_bufctx **pbctx)
 {
@@ -82,7 +78,7 @@
 	return -ENOMEM;
 }
 
-void
+drm_public void
 nouveau_bufctx_del(struct nouveau_bufctx **pbctx)
 {
 	struct nouveau_bufctx_priv *pctx = nouveau_bufctx(*pbctx);
@@ -99,7 +95,7 @@
 	}
 }
 
-void
+drm_public void
 nouveau_bufctx_reset(struct nouveau_bufctx *bctx, int bin)
 {
 	struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx);
@@ -117,7 +113,7 @@
 	pbin->relocs  = 0;
 }
 
-struct nouveau_bufref *
+drm_public struct nouveau_bufref *
 nouveau_bufctx_refn(struct nouveau_bufctx *bctx, int bin,
 		    struct nouveau_bo *bo, uint32_t flags)
 {
@@ -144,7 +140,7 @@
 	return &pref->base;
 }
 
-struct nouveau_bufref *
+drm_public struct nouveau_bufref *
 nouveau_bufctx_mthd(struct nouveau_bufctx *bctx, int bin, uint32_t packet,
 		    struct nouveau_bo *bo, uint64_t data, uint32_t flags,
 		    uint32_t vor, uint32_t tor)
diff --git a/nouveau/meson.build b/nouveau/meson.build
new file mode 100644
index 0000000..0c1498d
--- /dev/null
+++ b/nouveau/meson.build
@@ -0,0 +1,59 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+
+libdrm_nouveau = shared_library(
+  'drm_nouveau',
+  [files( 'nouveau.c', 'pushbuf.c', 'bufctx.c', 'abi16.c'), config_file],
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  dependencies : [dep_threads, dep_atomic_ops],
+  version : '2.0.0',
+  install : true,
+)
+
+ext_libdrm_nouveau = declare_dependency(
+  link_with : [libdrm, libdrm_nouveau],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+install_headers('nouveau.h', subdir : 'libdrm/nouveau')
+install_headers(
+  'nvif/class.h', 'nvif/cl0080.h', 'nvif/cl9097.h', 'nvif/if0002.h',
+  'nvif/if0003.h', 'nvif/ioctl.h', 'nvif/unpack.h',
+  subdir : 'libdrm/nouveau/nvif'
+)
+
+pkg.generate(
+  name : 'libdrm_nouveau',
+  libraries : libdrm_nouveau,
+  subdirs : ['.', 'libdrm', 'libdrm/nouveau'],
+  version : meson.project_version(),
+  requires_private : 'libdrm',
+  description : 'Userspace interface to nouveau kernel DRM services',
+)
+
+test(
+  'nouveau-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('nouveau-symbol-check'), libdrm_nouveau]
+)
diff --git a/nouveau/nouveau-symbol-check b/nouveau/nouveau-symbol-check
index b265cea..6296244 100755
--- a/nouveau/nouveau-symbol-check
+++ b/nouveau/nouveau-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.sources/LIBDRM_NOUVEAU_H_FILES
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_nouveau.so} | awk '{print $3}'| while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_nouveau.so} | awk '{print $3}'| while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c
index e113a8f..f18d142 100644
--- a/nouveau/nouveau.c
+++ b/nouveau/nouveau.c
@@ -22,10 +22,6 @@
  * Authors: Ben Skeggs
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -92,7 +88,7 @@
 	return drmCommandWriteRead(drm->fd, DRM_NOUVEAU_NVIF, args, argc);
 }
 
-int
+drm_public int
 nouveau_object_mthd(struct nouveau_object *obj,
 		    uint32_t mthd, void *data, uint32_t size)
 {
@@ -127,14 +123,14 @@
 	return ret;
 }
 
-void
+drm_public void
 nouveau_object_sclass_put(struct nouveau_sclass **psclass)
 {
 	free(*psclass);
 	*psclass = NULL;
 }
 
-int
+drm_public int
 nouveau_object_sclass_get(struct nouveau_object *obj,
 			  struct nouveau_sclass **psclass)
 {
@@ -184,7 +180,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_object_mclass(struct nouveau_object *obj,
 		      const struct nouveau_mclass *mclass)
 {
@@ -286,7 +282,7 @@
 	return 0;
 }
 
-int
+drm_public int
 nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
 		   uint32_t oclass, void *data, uint32_t length,
 		   struct nouveau_object **pobj)
@@ -307,7 +303,7 @@
 	return 0;
 }
 
-void
+drm_public void
 nouveau_object_del(struct nouveau_object **pobj)
 {
 	struct nouveau_object *obj = *pobj;
@@ -318,14 +314,14 @@
 	}
 }
 
-void
+drm_public void
 nouveau_drm_del(struct nouveau_drm **pdrm)
 {
 	free(*pdrm);
 	*pdrm = NULL;
 }
 
-int
+drm_public int
 nouveau_drm_new(int fd, struct nouveau_drm **pdrm)
 {
 	struct nouveau_drm *drm;
@@ -357,14 +353,14 @@
  * is kept here to prevent AIGLX from crashing if the DDX is linked against
  * the new libdrm, but the DRI driver against the old
  */
-int
+drm_public int
 nouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd,
 			     drm_context_t ctx)
 {
 	return -EACCES;
 }
 
-int
+drm_public int
 nouveau_device_new(struct nouveau_object *parent, int32_t oclass,
 		   void *data, uint32_t size, struct nouveau_device **pdev)
 {
@@ -458,7 +454,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
 {
 	struct nouveau_drm *drm;
@@ -486,7 +482,7 @@
 	return 0;
 }
 
-int
+drm_public int
 nouveau_device_open(const char *busid, struct nouveau_device **pdev)
 {
 	int ret = -ENODEV, fd = drmOpen("nouveau", busid);
@@ -498,7 +494,7 @@
 	return ret;
 }
 
-void
+drm_public void
 nouveau_device_del(struct nouveau_device **pdev)
 {
 	struct nouveau_device_priv *nvdev = nouveau_device(*pdev);
@@ -517,7 +513,7 @@
 	}
 }
 
-int
+drm_public int
 nouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value)
 {
 	struct nouveau_drm *drm = nouveau_drm(&dev->object);
@@ -528,7 +524,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value)
 {
 	struct nouveau_drm *drm = nouveau_drm(&dev->object);
@@ -536,7 +532,7 @@
 	return drmCommandWrite(drm->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r));
 }
 
-int
+drm_public int
 nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient)
 {
 	struct nouveau_device_priv *nvdev = nouveau_device(dev);
@@ -575,7 +571,7 @@
 	return ret;
 }
 
-void
+drm_public void
 nouveau_client_del(struct nouveau_client **pclient)
 {
 	struct nouveau_client_priv *pcli = nouveau_client(*pclient);
@@ -622,7 +618,7 @@
 	free(nvbo);
 }
 
-int
+drm_public int
 nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align,
 	       uint64_t size, union nouveau_bo_config *config,
 	       struct nouveau_bo **pbo)
@@ -713,7 +709,7 @@
 	}
 }
 
-int
+drm_public int
 nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
 		struct nouveau_bo **pbo)
 {
@@ -725,7 +721,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name,
 		    struct nouveau_bo **pbo)
 {
@@ -754,7 +750,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name)
 {
 	struct drm_gem_flink req = { .handle = bo->handle };
@@ -776,7 +772,7 @@
 	return 0;
 }
 
-void
+drm_public void
 nouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref)
 {
 	struct nouveau_bo *ref = *pref;
@@ -790,7 +786,7 @@
 	*pref = bo;
 }
 
-int
+drm_public int
 nouveau_bo_prime_handle_ref(struct nouveau_device *dev, int prime_fd,
 			    struct nouveau_bo **bo)
 {
@@ -810,7 +806,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd)
 {
 	struct nouveau_drm *drm = nouveau_drm(&bo->device->object);
@@ -825,7 +821,7 @@
 	return 0;
 }
 
-int
+drm_public int
 nouveau_bo_wait(struct nouveau_bo *bo, uint32_t access,
 		struct nouveau_client *client)
 {
@@ -860,7 +856,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_bo_map(struct nouveau_bo *bo, uint32_t access,
 	       struct nouveau_client *client)
 {
diff --git a/nouveau/pushbuf.c b/nouveau/pushbuf.c
index 035e301..e5f73f0 100644
--- a/nouveau/pushbuf.c
+++ b/nouveau/pushbuf.c
@@ -22,10 +22,6 @@
  * Authors: Ben Skeggs
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -532,7 +528,7 @@
 	return ret;
 }
 
-int
+drm_public int
 nouveau_pushbuf_new(struct nouveau_client *client, struct nouveau_object *chan,
 		    int nr, uint32_t size, bool immediate,
 		    struct nouveau_pushbuf **ppush)
@@ -603,7 +599,7 @@
 	return 0;
 }
 
-void
+drm_public void
 nouveau_pushbuf_del(struct nouveau_pushbuf **ppush)
 {
 	struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(*ppush);
@@ -629,7 +625,7 @@
 	*ppush = NULL;
 }
 
-struct nouveau_bufctx *
+drm_public struct nouveau_bufctx *
 nouveau_pushbuf_bufctx(struct nouveau_pushbuf *push, struct nouveau_bufctx *ctx)
 {
 	struct nouveau_bufctx *prev = push->bufctx;
@@ -637,7 +633,7 @@
 	return prev;
 }
 
-int
+drm_public int
 nouveau_pushbuf_space(struct nouveau_pushbuf *push,
 		      uint32_t dwords, uint32_t relocs, uint32_t pushes)
 {
@@ -701,7 +697,7 @@
 	return flushed ? pushbuf_validate(push, false) : 0;
 }
 
-void
+drm_public void
 nouveau_pushbuf_data(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
 		     uint64_t offset, uint64_t length)
 {
@@ -732,14 +728,14 @@
 	}
 }
 
-int
+drm_public int
 nouveau_pushbuf_refn(struct nouveau_pushbuf *push,
 		     struct nouveau_pushbuf_refn *refs, int nr)
 {
 	return pushbuf_refn(push, true, refs, nr);
 }
 
-void
+drm_public void
 nouveau_pushbuf_reloc(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
 		      uint32_t data, uint32_t flags, uint32_t vor, uint32_t tor)
 {
@@ -747,13 +743,13 @@
 	push->cur++;
 }
 
-int
+drm_public int
 nouveau_pushbuf_validate(struct nouveau_pushbuf *push)
 {
 	return pushbuf_validate(push, true);
 }
 
-uint32_t
+drm_public uint32_t
 nouveau_pushbuf_refd(struct nouveau_pushbuf *push, struct nouveau_bo *bo)
 {
 	struct drm_nouveau_gem_pushbuf_bo *kref;
@@ -771,7 +767,7 @@
 	return flags;
 }
 
-int
+drm_public int
 nouveau_pushbuf_kick(struct nouveau_pushbuf *push, struct nouveau_object *chan)
 {
 	if (!push->channel)
diff --git a/omap/Android.bp b/omap/Android.bp
new file mode 100644
index 0000000..05ca7d2
--- /dev/null
+++ b/omap/Android.bp
@@ -0,0 +1,12 @@
+build = ["Android.sources.bp"]
+
+cc_library_shared {
+    name: "libdrm_omap",
+    defaults: [
+        "libdrm_defaults",
+        "libdrm_omap_sources",
+    ],
+    vendor: true,
+
+    shared_libs: ["libdrm"],
+}
diff --git a/omap/Android.sources.bp b/omap/Android.sources.bp
new file mode 100644
index 0000000..3c7da94
--- /dev/null
+++ b/omap/Android.sources.bp
@@ -0,0 +1,8 @@
+// Autogenerated with Android.sources.bp.mk
+
+cc_defaults {
+    name: "libdrm_omap_sources",
+    srcs: [
+	"omap_drm.c",
+    ],
+}
diff --git a/omap/Makefile.am b/omap/Makefile.am
index 599bb9d..38a1007 100644
--- a/omap/Makefile.am
+++ b/omap/Makefile.am
@@ -1,5 +1,6 @@
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	-I$(top_srcdir)/include/drm
@@ -20,5 +21,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_omap.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = omap-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/omap/meson.build b/omap/meson.build
new file mode 100644
index 0000000..54698c6
--- /dev/null
+++ b/omap/meson.build
@@ -0,0 +1,54 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+libdrm_omap = shared_library(
+  'drm_omap',
+  [files('omap_drm.c'), config_file],
+  include_directories : [inc_root, inc_drm],
+  c_args : libdrm_c_args,
+  link_with : libdrm,
+  dependencies : [dep_pthread_stubs, dep_atomic_ops],
+  version : '1.0.0',
+  install : true,
+)
+
+ext_libdrm_omap = declare_dependency(
+  link_with : [libdrm, libdrm_omap],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+install_headers('omap_drmif.h', subdir : 'libdrm')
+install_headers('omap_drm.h', subdir : 'omap')
+
+pkg.generate(
+  name : 'libdrm_omap',
+  libraries : libdrm_omap,
+  subdirs : ['.', 'libdrm', 'omap'],
+  version : '0.6',
+  requires_private : 'libdrm',
+  description : 'Userspace interface to omap kernel DRM services',
+)
+
+test(
+  'omap-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('omap-symbol-check'), libdrm_omap]
+)
diff --git a/omap/omap-symbol-check b/omap/omap-symbol-check
index 759c84b..16da3c4 100755
--- a/omap/omap-symbol-check
+++ b/omap/omap-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.am/libdrm_omap*HEADERS
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_omap.so} | awk '{print $3}'| while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_omap.so} | awk '{print $3}'| while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
diff --git a/omap/omap_drm.c b/omap/omap_drm.c
index 08ba64e..ffacea6 100644
--- a/omap/omap_drm.c
+++ b/omap/omap_drm.c
@@ -26,10 +26,6 @@
  *    Rob Clark <rob@ti.com>
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
@@ -92,7 +88,7 @@
 	return dev;
 }
 
-struct omap_device * omap_device_new(int fd)
+drm_public struct omap_device * omap_device_new(int fd)
 {
 	struct omap_device *dev = NULL;
 
@@ -115,13 +111,13 @@
 	return dev;
 }
 
-struct omap_device * omap_device_ref(struct omap_device *dev)
+drm_public struct omap_device * omap_device_ref(struct omap_device *dev)
 {
 	atomic_inc(&dev->refcnt);
 	return dev;
 }
 
-void omap_device_del(struct omap_device *dev)
+drm_public void omap_device_del(struct omap_device *dev)
 {
 	if (!atomic_dec_and_test(&dev->refcnt))
 		return;
@@ -132,7 +128,7 @@
 	free(dev);
 }
 
-int
+drm_public int
 omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value)
 {
 	struct drm_omap_param req = {
@@ -150,7 +146,7 @@
 	return 0;
 }
 
-int
+drm_public int
 omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value)
 {
 	struct drm_omap_param req = {
@@ -230,7 +226,7 @@
 
 
 /* allocate a new (un-tiled) buffer object */
-struct omap_bo *
+drm_public struct omap_bo *
 omap_bo_new(struct omap_device *dev, uint32_t size, uint32_t flags)
 {
 	union omap_gem_size gsize = {
@@ -243,7 +239,7 @@
 }
 
 /* allocate a new buffer object */
-struct omap_bo *
+drm_public struct omap_bo *
 omap_bo_new_tiled(struct omap_device *dev, uint32_t width,
 		  uint32_t height, uint32_t flags)
 {
@@ -259,7 +255,7 @@
 	return omap_bo_new_impl(dev, gsize, flags);
 }
 
-struct omap_bo *omap_bo_ref(struct omap_bo *bo)
+drm_public struct omap_bo *omap_bo_ref(struct omap_bo *bo)
 {
 	atomic_inc(&bo->refcnt);
 	return bo;
@@ -285,7 +281,7 @@
 }
 
 /* import a buffer object from DRI2 name */
-struct omap_bo *
+drm_public struct omap_bo *
 omap_bo_from_name(struct omap_device *dev, uint32_t name)
 {
 	struct omap_bo *bo = NULL;
@@ -319,7 +315,7 @@
  * fd so caller should close() the fd when it is otherwise done
  * with it (even if it is still using the 'struct omap_bo *')
  */
-struct omap_bo *
+drm_public struct omap_bo *
 omap_bo_from_dmabuf(struct omap_device *dev, int fd)
 {
 	struct omap_bo *bo = NULL;
@@ -351,7 +347,7 @@
 }
 
 /* destroy a buffer object */
-void omap_bo_del(struct omap_bo *bo)
+drm_public void omap_bo_del(struct omap_bo *bo)
 {
 	if (!bo) {
 		return;
@@ -384,7 +380,7 @@
 }
 
 /* get the global flink/DRI2 buffer name */
-int omap_bo_get_name(struct omap_bo *bo, uint32_t *name)
+drm_public int omap_bo_get_name(struct omap_bo *bo, uint32_t *name)
 {
 	if (!bo->name) {
 		struct drm_gem_flink req = {
@@ -405,7 +401,7 @@
 	return 0;
 }
 
-uint32_t omap_bo_handle(struct omap_bo *bo)
+drm_public uint32_t omap_bo_handle(struct omap_bo *bo)
 {
 	return bo->handle;
 }
@@ -413,12 +409,12 @@
 /* caller owns the dmabuf fd that is returned and is responsible
  * to close() it when done
  */
-int omap_bo_dmabuf(struct omap_bo *bo)
+drm_public int omap_bo_dmabuf(struct omap_bo *bo)
 {
 	if (bo->fd < 0) {
 		struct drm_prime_handle req = {
 				.handle = bo->handle,
-				.flags = DRM_CLOEXEC,
+				.flags = DRM_CLOEXEC | DRM_RDWR,
 		};
 		int ret;
 
@@ -432,7 +428,7 @@
 	return dup(bo->fd);
 }
 
-uint32_t omap_bo_size(struct omap_bo *bo)
+drm_public uint32_t omap_bo_size(struct omap_bo *bo)
 {
 	if (!bo->size) {
 		get_buffer_info(bo);
@@ -440,7 +436,7 @@
 	return bo->size;
 }
 
-void *omap_bo_map(struct omap_bo *bo)
+drm_public void *omap_bo_map(struct omap_bo *bo)
 {
 	if (!bo->map) {
 		if (!bo->offset) {
@@ -456,7 +452,7 @@
 	return bo->map;
 }
 
-int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op)
+drm_public int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op)
 {
 	struct drm_omap_gem_cpu_prep req = {
 			.handle = bo->handle,
@@ -466,7 +462,7 @@
 			DRM_OMAP_GEM_CPU_PREP, &req, sizeof(req));
 }
 
-int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op)
+drm_public int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op)
 {
 	struct drm_omap_gem_cpu_fini req = {
 			.handle = bo->handle,
diff --git a/radeon/Makefile.am b/radeon/Makefile.am
index e241531..e712a4a 100644
--- a/radeon/Makefile.am
+++ b/radeon/Makefile.am
@@ -26,6 +26,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	-I$(top_srcdir)/include/drm
@@ -43,5 +44,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_radeon.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = radeon-symbol-check
 EXTRA_DIST = $(LIBDRM_RADEON_BOF_FILES) $(TESTS)
diff --git a/radeon/meson.build b/radeon/meson.build
new file mode 100644
index 0000000..1fc5282
--- /dev/null
+++ b/radeon/meson.build
@@ -0,0 +1,64 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+
+libdrm_radeon = shared_library(
+  'drm_radeon',
+  [
+    files(
+      'radeon_bo_gem.c', 'radeon_cs_gem.c', 'radeon_cs_space.c', 'radeon_bo.c',
+      'radeon_cs.c', 'radeon_surface.c',
+    ),
+    config_file,
+  ],
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  dependencies : [dep_pthread_stubs, dep_atomic_ops],
+  version : '1.0.1',
+  install : true,
+)
+
+ext_libdrm_radeon = declare_dependency(
+  link_with : [libdrm, libdrm_radeon],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+install_headers(
+	'radeon_bo.h', 'radeon_cs.h', 'radeon_surface.h', 'radeon_bo_gem.h',
+	'radeon_cs_gem.h', 'radeon_bo_int.h', 'radeon_cs_int.h', 'r600_pci_ids.h',
+  subdir : 'libdrm'
+)
+
+pkg.generate(
+  name : 'libdrm_radeon',
+  libraries : libdrm_radeon,
+  subdirs : ['.', 'libdrm'],
+  version : meson.project_version(),
+  requires_private : 'libdrm',
+  description : 'Userspace interface to kernel DRM services for radeon',
+)
+
+test(
+  'radeon-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('radeon-symbol-check'), libdrm_radeon]
+)
diff --git a/radeon/radeon-symbol-check b/radeon/radeon-symbol-check
index 0bf2ffc..da605bb 100755
--- a/radeon/radeon-symbol-check
+++ b/radeon/radeon-symbol-check
@@ -1,9 +1,11 @@
 #!/bin/bash
 
+set -u
+
 # The following symbols (past the first five) are taken from the public headers.
 # A list of the latter should be available Makefile.sources/LIBDRM_RADEON_H_FILES
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_radeon.so} | awk '{print $3}'| while read func; do
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_radeon.so} | awk '{print $3}'| while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
 __bss_start
 _edata
diff --git a/radeon/radeon_bo.c b/radeon/radeon_bo.c
index 447f928..9192953 100644
--- a/radeon/radeon_bo.c
+++ b/radeon/radeon_bo.c
@@ -29,14 +29,11 @@
  *      Dave Airlie
  *      Jérôme Glisse <glisse@freedesktop.org>
  */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 #include <libdrm_macros.h>
 #include <radeon_bo.h>
 #include <radeon_bo_int.h>
 
-void radeon_bo_debug(struct radeon_bo *bo, const char *op)
+drm_public void radeon_bo_debug(struct radeon_bo *bo, const char *op)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
 
@@ -44,7 +41,7 @@
             op, bo, bo->handle, boi->size, boi->cref);
 }
 
-struct radeon_bo *
+drm_public struct radeon_bo *
 radeon_bo_open(struct radeon_bo_manager *bom, uint32_t handle, uint32_t size,
 	       uint32_t alignment, uint32_t domains, uint32_t flags)
 {
@@ -53,14 +50,14 @@
     return bo;
 }
 
-void radeon_bo_ref(struct radeon_bo *bo)
+drm_public void radeon_bo_ref(struct radeon_bo *bo)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     boi->cref++;
     boi->bom->funcs->bo_ref(boi);
 }
 
-struct radeon_bo *radeon_bo_unref(struct radeon_bo *bo)
+drm_public struct radeon_bo *radeon_bo_unref(struct radeon_bo *bo)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     if (bo == NULL)
@@ -70,19 +67,19 @@
     return boi->bom->funcs->bo_unref(boi);
 }
 
-int radeon_bo_map(struct radeon_bo *bo, int write)
+drm_public int radeon_bo_map(struct radeon_bo *bo, int write)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     return boi->bom->funcs->bo_map(boi, write);
 }
 
-int radeon_bo_unmap(struct radeon_bo *bo)
+drm_public int radeon_bo_unmap(struct radeon_bo *bo)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     return boi->bom->funcs->bo_unmap(boi);
 }
 
-int radeon_bo_wait(struct radeon_bo *bo)
+drm_public int radeon_bo_wait(struct radeon_bo *bo)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     if (!boi->bom->funcs->bo_wait)
@@ -90,13 +87,13 @@
     return boi->bom->funcs->bo_wait(boi);
 }
 
-int radeon_bo_is_busy(struct radeon_bo *bo, uint32_t *domain)
+drm_public int radeon_bo_is_busy(struct radeon_bo *bo, uint32_t *domain)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     return boi->bom->funcs->bo_is_busy(boi, domain);
 }
 
-int
+drm_public int
 radeon_bo_set_tiling(struct radeon_bo *bo,
                      uint32_t tiling_flags, uint32_t pitch)
 {
@@ -104,7 +101,7 @@
     return boi->bom->funcs->bo_set_tiling(boi, tiling_flags, pitch);
 }
 
-int
+drm_public int
 radeon_bo_get_tiling(struct radeon_bo *bo,
                      uint32_t *tiling_flags, uint32_t *pitch)
 {
@@ -112,7 +109,7 @@
     return boi->bom->funcs->bo_get_tiling(boi, tiling_flags, pitch);
 }
 
-int radeon_bo_is_static(struct radeon_bo *bo)
+drm_public int radeon_bo_is_static(struct radeon_bo *bo)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     if (boi->bom->funcs->bo_is_static)
@@ -120,19 +117,19 @@
     return 0;
 }
 
-int
+drm_public int
 radeon_bo_is_referenced_by_cs(struct radeon_bo *bo, struct radeon_cs *cs)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     return boi->cref > 1;
 }
 
-uint32_t radeon_bo_get_handle(struct radeon_bo *bo)
+drm_public uint32_t radeon_bo_get_handle(struct radeon_bo *bo)
 {
     return bo->handle;
 }
 
-uint32_t radeon_bo_get_src_domain(struct radeon_bo *bo)
+drm_public uint32_t radeon_bo_get_src_domain(struct radeon_bo *bo)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
     uint32_t src_domain;
diff --git a/radeon/radeon_bo_gem.c b/radeon/radeon_bo_gem.c
index fbd453d..86f7c00 100644
--- a/radeon/radeon_bo_gem.c
+++ b/radeon/radeon_bo_gem.c
@@ -29,9 +29,6 @@
  *      Dave Airlie
  *      Jérôme Glisse <glisse@freedesktop.org>
  */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -284,7 +281,7 @@
     .bo_is_referenced_by_cs = NULL,
 };
 
-struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd)
+drm_public struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd)
 {
     struct bo_manager_gem *bomg;
 
@@ -297,7 +294,7 @@
     return (struct radeon_bo_manager*)bomg;
 }
 
-void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom)
+drm_public void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom)
 {
     struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom;
 
@@ -307,21 +304,21 @@
     free(bomg);
 }
 
-uint32_t
+drm_public uint32_t
 radeon_gem_name_bo(struct radeon_bo *bo)
 {
     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
     return bo_gem->name;
 }
 
-void *
+drm_public void *
 radeon_gem_get_reloc_in_cs(struct radeon_bo *bo)
 {
     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
     return &bo_gem->reloc_in_cs;
 }
 
-int
+drm_public int
 radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name)
 {
     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
@@ -343,7 +340,7 @@
     return 0;
 }
 
-int
+drm_public int
 radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain)
 {
     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
@@ -361,7 +358,7 @@
     return r;
 }
 
-int radeon_gem_prime_share_bo(struct radeon_bo *bo, int *handle)
+drm_public int radeon_gem_prime_share_bo(struct radeon_bo *bo, int *handle)
 {
     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
     int ret;
@@ -370,7 +367,7 @@
     return ret;
 }
 
-struct radeon_bo *
+drm_public struct radeon_bo *
 radeon_gem_bo_open_prime(struct radeon_bo_manager *bom, int fd_handle, uint32_t size)
 {
     struct radeon_bo_gem *bo;
diff --git a/radeon/radeon_cs.c b/radeon/radeon_cs.c
index dffb869..1132d06 100644
--- a/radeon/radeon_cs.c
+++ b/radeon/radeon_cs.c
@@ -1,19 +1,16 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 #include "libdrm_macros.h"
 #include <stdio.h>
 #include "radeon_cs.h"
 #include "radeon_cs_int.h"
 
-struct radeon_cs *
+drm_public struct radeon_cs *
 radeon_cs_create(struct radeon_cs_manager *csm, uint32_t ndw)
 {
     struct radeon_cs_int *csi = csm->funcs->cs_create(csm, ndw);
     return (struct radeon_cs *)csi;
 }
 
-int
+drm_public int
 radeon_cs_write_reloc(struct radeon_cs *cs, struct radeon_bo *bo,
                       uint32_t read_domain, uint32_t write_domain,
                       uint32_t flags)
@@ -27,7 +24,7 @@
                                            flags);
 }
 
-int
+drm_public int
 radeon_cs_begin(struct radeon_cs *cs, uint32_t ndw,
                 const char *file, const char *func, int line)
 {
@@ -35,7 +32,7 @@
     return csi->csm->funcs->cs_begin(csi, ndw, file, func, line);
 }
 
-int
+drm_public int
 radeon_cs_end(struct radeon_cs *cs,
               const char *file, const char *func, int line)
 {
@@ -43,37 +40,37 @@
     return csi->csm->funcs->cs_end(csi, file, func, line);
 }
 
-int radeon_cs_emit(struct radeon_cs *cs)
+drm_public int radeon_cs_emit(struct radeon_cs *cs)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     return csi->csm->funcs->cs_emit(csi);
 }
 
-int radeon_cs_destroy(struct radeon_cs *cs)
+drm_public int radeon_cs_destroy(struct radeon_cs *cs)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     return csi->csm->funcs->cs_destroy(csi);
 }
 
-int radeon_cs_erase(struct radeon_cs *cs)
+drm_public int radeon_cs_erase(struct radeon_cs *cs)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     return csi->csm->funcs->cs_erase(csi);
 }
 
-int radeon_cs_need_flush(struct radeon_cs *cs)
+drm_public int radeon_cs_need_flush(struct radeon_cs *cs)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     return csi->csm->funcs->cs_need_flush(csi);
 }
 
-void radeon_cs_print(struct radeon_cs *cs, FILE *file)
+drm_public void radeon_cs_print(struct radeon_cs *cs, FILE *file)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     csi->csm->funcs->cs_print(csi, file);
 }
 
-void
+drm_public void
 radeon_cs_set_limit(struct radeon_cs *cs, uint32_t domain, uint32_t limit)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
@@ -83,7 +80,7 @@
         csi->csm->gart_limit = limit;
 }
 
-void radeon_cs_space_set_flush(struct radeon_cs *cs, 
+drm_public void radeon_cs_space_set_flush(struct radeon_cs *cs,
                                           void (*fn)(void *), void *data)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
@@ -91,7 +88,7 @@
     csi->space_flush_data = data;
 }
 
-uint32_t radeon_cs_get_id(struct radeon_cs *cs)
+drm_public uint32_t radeon_cs_get_id(struct radeon_cs *cs)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     return csi->id;
diff --git a/radeon/radeon_cs_gem.c b/radeon/radeon_cs_gem.c
index f3dccb6..ef070c6 100644
--- a/radeon/radeon_cs_gem.c
+++ b/radeon/radeon_cs_gem.c
@@ -29,9 +29,6 @@
  *      Nicolai Haehnle <prefect_@gmx.net>
  *      Jérôme Glisse <glisse@freedesktop.org>
  */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
 #include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -539,7 +536,7 @@
     return r;
 }
 
-struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd)
+drm_public struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd)
 {
     struct radeon_cs_manager_gem *csm;
 
@@ -553,7 +550,7 @@
     return &csm->base;
 }
 
-void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm)
+drm_public void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm)
 {
     free(csm);
 }
diff --git a/radeon/radeon_cs_space.c b/radeon/radeon_cs_space.c
index 69287be..039b041 100644
--- a/radeon/radeon_cs_space.c
+++ b/radeon/radeon_cs_space.c
@@ -25,9 +25,6 @@
  */
 /*
  */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 #include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -165,7 +162,7 @@
     return RADEON_CS_SPACE_OK;
 }
 
-void
+drm_public void
 radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo,
                                   uint32_t read_domains, uint32_t write_domain)
 {
@@ -209,7 +206,7 @@
     return 0;
 }
 
-int
+drm_public int
 radeon_cs_space_check_with_bo(struct radeon_cs *cs, struct radeon_bo *bo,
                               uint32_t read_domains, uint32_t write_domain)
 {
@@ -230,13 +227,13 @@
     return ret;
 }
 
-int radeon_cs_space_check(struct radeon_cs *cs)
+drm_public int radeon_cs_space_check(struct radeon_cs *cs)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     return radeon_cs_check_space_internal(csi, NULL);
 }
 
-void radeon_cs_space_reset_bos(struct radeon_cs *cs)
+drm_public void radeon_cs_space_reset_bos(struct radeon_cs *cs)
 {
     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
     int i;
diff --git a/radeon/radeon_surface.c b/radeon/radeon_surface.c
index 965be24..ea0a27a 100644
--- a/radeon/radeon_surface.c
+++ b/radeon/radeon_surface.c
@@ -26,9 +26,6 @@
  * Authors:
  *      Jérôme Glisse <jglisse@redhat.com>
  */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 #include <stdbool.h>
 #include <assert.h>
 #include <errno.h>
@@ -2411,7 +2408,7 @@
 /* ===========================================================================
  * public API
  */
-struct radeon_surface_manager *
+drm_public struct radeon_surface_manager *
 radeon_surface_manager_new(int fd)
 {
     struct radeon_surface_manager *surf_man;
@@ -2460,7 +2457,7 @@
     return NULL;
 }
 
-void
+drm_public void
 radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
 {
     free(surf_man);
@@ -2503,6 +2500,7 @@
         if (surf->npix_y > 1) {
             return -EINVAL;
         }
+        /* fallthrough */
     case RADEON_SURF_TYPE_2D:
         if (surf->npix_z > 1) {
             return -EINVAL;
@@ -2533,7 +2531,7 @@
     return 0;
 }
 
-int
+drm_public int
 radeon_surface_init(struct radeon_surface_manager *surf_man,
                     struct radeon_surface *surf)
 {
@@ -2550,7 +2548,7 @@
     return surf_man->surface_init(surf_man, surf);
 }
 
-int
+drm_public int
 radeon_surface_best(struct radeon_surface_manager *surf_man,
                     struct radeon_surface *surf)
 {
diff --git a/rockchip/Android.bp b/rockchip/Android.bp
deleted file mode 100644
index daceacc..0000000
--- a/rockchip/Android.bp
+++ /dev/null
@@ -1,13 +0,0 @@
-cc_library_shared {
-    name: "libdrm_rockchip",
-    vendor: true,
-    shared_libs: ["libdrm"],
-
-    srcs: ["rockchip_drm.c"],
-
-    cflags: [
-        "-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1",
-        "-Wall",
-        "-Werror",
-    ],
-}
diff --git a/rockchip/Makefile.am b/rockchip/Makefile.am
deleted file mode 100644
index 2ebb82f..0000000
--- a/rockchip/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-AM_CFLAGS = \
-	$(WARN_CFLAGS) \
-	-I$(top_srcdir) \
-	-I$(top_srcdir)/rockchip \
-	$(PTHREADSTUBS_CFLAGS) \
-	-I$(top_srcdir)/include/drm
-
-libdrm_rockchip_la_LTLIBRARIES = libdrm_rockchip.la
-libdrm_rockchip_ladir = $(libdir)
-libdrm_rockchip_la_LDFLAGS = -version-number 1:0:0 -no-undefined
-libdrm_rockchip_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
-
-libdrm_rockchip_la_SOURCES = \
-	rockchip_drm.c
-
-libdrm_rockchipincludedir = ${includedir}/libdrm
-libdrm_rockchipinclude_HEADERS = rockchip_drmif.h rockchip_drm.h
-
-pkgconfigdir = @pkgconfigdir@
-pkgconfig_DATA = libdrm_rockchip.pc
diff --git a/rockchip/libdrm_rockchip.pc.in b/rockchip/libdrm_rockchip.pc.in
deleted file mode 100644
index 13f22ac..0000000
--- a/rockchip/libdrm_rockchip.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: libdrm_rockchip
-Description: Userspace interface to rockchip kernel DRM services
-Version: 0.1
-Libs: -L${libdir} -ldrm_rockchip
-Cflags: -I${includedir} -I${includedir}/libdrm
-Requires.private: libdrm
diff --git a/rockchip/rockchip_drm.c b/rockchip/rockchip_drm.c
deleted file mode 100644
index 44a78be..0000000
--- a/rockchip/rockchip_drm.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) ROCKCHIP, Inc.
- * Author:yzq<yzq@rock-chips.com>
- *
- * based on exynos_drm.c
- *
- * 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.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/mman.h>
-#include <linux/stddef.h>
-
-#include <xf86drm.h>
-
-#include "rockchip_drm.h"
-#include "rockchip_drmif.h"
-
-/*
- * Create rockchip drm device object.
- *
- * @fd: file descriptor to rockchip drm driver opened.
- *
- * if true, return the device object else NULL.
- */
-struct rockchip_device *rockchip_device_create(int fd)
-{
-	struct rockchip_device *dev;
-
-	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, "failed to create device[%s].\n",
-				strerror(errno));
-		return NULL;
-	}
-
-	dev->fd = fd;
-
-	return dev;
-}
-
-/*
- * Destroy rockchip drm device object
- *
- * @dev: rockchip drm device object.
- */
-void rockchip_device_destroy(struct rockchip_device *dev)
-{
-	free(dev);
-}
-
-/*
- * Create a rockchip buffer object to rockchip drm device.
- *
- * @dev: rockchip drm device object.
- * @size: user-desired size.
- * flags: user-desired memory type.
- *	user can set one or more types among several types to memory
- *	allocation and cache attribute types. and as default,
- *	ROCKCHIP_BO_NONCONTIG and ROCKCHIP-BO_NONCACHABLE types would
- *	be used.
- *
- * if true, return a rockchip buffer object else NULL.
- */
-struct rockchip_bo *rockchip_bo_create(struct rockchip_device *dev,
-					size_t size, uint32_t flags)
-{
-	struct rockchip_bo *bo;
-	struct drm_rockchip_gem_create req = {
-		.size = size,
-		.flags = flags,
-	};
-
-	if (size == 0) {
-		fprintf(stderr, "invalid size.\n");
-		return NULL;
-	}
-
-	bo = calloc(1, sizeof(*bo));
-	if (!bo) {
-		fprintf(stderr, "failed to create bo[%s].\n",
-				strerror(errno));
-		goto fail;
-	}
-
-	bo->dev = dev;
-
-	if (drmIoctl(dev->fd, DRM_IOCTL_ROCKCHIP_GEM_CREATE, &req)){
-		fprintf(stderr, "failed to create gem object[%s].\n",
-				strerror(errno));
-		goto err_free_bo;
-	}
-
-	bo->handle = req.handle;
-	bo->size = size;
-	bo->flags = flags;
-
-	return bo;
-
-err_free_bo:
-	free(bo);
-fail:
-	return NULL;
-}
-
-struct rockchip_bo *rockchip_bo_from_handle(struct rockchip_device *dev,
-			uint32_t handle, uint32_t flags, uint32_t size)
-{
-	struct rockchip_bo *bo;
-
-	if (size == 0) {
-		fprintf(stderr, "invalid size.\n");
-		return NULL;
-	}
-
-	bo = calloc(1, sizeof(*bo));
-	if (!bo) {
-		fprintf(stderr, "failed to create bo[%s].\n",
-				strerror(errno));
-		return NULL;
-	}
-
-	bo->dev = dev;
-	bo->handle = handle;
-	bo->size = size;
-	bo->flags = flags;
-
-	return bo;
-}
-
-/*
- * Destroy a rockchip buffer object.
- *
- * @bo: a rockchip buffer object to be destroyed.
- */
-void rockchip_bo_destroy(struct rockchip_bo *bo)
-{
-	if (!bo)
-		return;
-
-	if (bo->vaddr)
-		munmap(bo->vaddr, bo->size);
-
-	if (bo->handle) {
-		struct drm_gem_close req = {
-			.handle = bo->handle,
-		};
-
-		drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
-	}
-
-	free(bo);
-}
-
-
-/*
- * Get a rockchip buffer object from a gem global object name.
- *
- * @dev: a rockchip device object.
- * @name: a gem global object name exported by another process.
- *
- * this interface is used to get a rockchip buffer object from a gem
- * global object name sent by another process for buffer sharing.
- *
- * if true, return a rockchip buffer object else NULL.
- *
- */
-struct rockchip_bo *rockchip_bo_from_name(struct rockchip_device *dev,
-						uint32_t name)
-{
-	struct rockchip_bo *bo;
-	struct drm_gem_open req = {
-		.name = name,
-	};
-
-	bo = calloc(1, sizeof(*bo));
-	if (!bo) {
-		fprintf(stderr, "failed to allocate bo[%s].\n",
-				strerror(errno));
-		return NULL;
-	}
-
-	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
-		fprintf(stderr, "failed to open gem object[%s].\n",
-				strerror(errno));
-		goto err_free_bo;
-	}
-
-	bo->dev = dev;
-	bo->name = name;
-	bo->handle = req.handle;
-
-	return bo;
-
-err_free_bo:
-	free(bo);
-	return NULL;
-}
-
-/*
- * Get a gem global object name from a gem object handle.
- *
- * @bo: a rockchip buffer object including gem handle.
- * @name: a gem global object name to be got by kernel driver.
- *
- * this interface is used to get a gem global object name from a gem object
- * handle to a buffer that wants to share it with another process.
- *
- * if true, return 0 else negative.
- */
-int rockchip_bo_get_name(struct rockchip_bo *bo, uint32_t *name)
-{
-	if (!bo->name) {
-		struct drm_gem_flink req = {
-			.handle = bo->handle,
-		};
-		int ret;
-
-		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
-		if (ret) {
-			fprintf(stderr, "failed to get gem global name[%s].\n",
-					strerror(errno));
-			return ret;
-		}
-
-		bo->name = req.name;
-	}
-
-	*name = bo->name;
-
-	return 0;
-}
-
-uint32_t rockchip_bo_handle(struct rockchip_bo *bo)
-{
-	return bo->handle;
-}
-
-/*
- * Mmap a buffer to user space.
- *
- * @bo: a rockchip buffer object including a gem object handle to be mmapped
- *	to user space.
- *
- * if true, user pointer mmaped else NULL.
- */
-void *rockchip_bo_map(struct rockchip_bo *bo)
-{
-	if (!bo->vaddr) {
-		struct rockchip_device *dev = bo->dev;
-		struct drm_rockchip_gem_map_off req = {
-			.handle = bo->handle,
-		};
-		int ret;
-
-		ret = drmIoctl(dev->fd, DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET, &req);
-		if (ret) {
-			fprintf(stderr, "failed to ioctl gem map offset[%s].\n",
-				strerror(errno));
-			return NULL;
-		}
-
-		bo->vaddr = mmap(0, bo->size, PROT_READ | PROT_WRITE,
-			   MAP_SHARED, dev->fd, req.offset);
-		if (bo->vaddr == MAP_FAILED) {
-			fprintf(stderr, "failed to mmap buffer[%s].\n",
-				strerror(errno));
-			return NULL;
-		}
-	}
-
-	return bo->vaddr;
-}
diff --git a/rockchip/rockchip_drm.h b/rockchip/rockchip_drm.h
deleted file mode 100644
index 13977d5..0000000
--- a/rockchip/rockchip_drm.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) Fuzhou Rockchip Electronics Co.Ltd
- * Authors:
- *       Mark Yao <yzq@rock-chips.com>
- *
- * based on exynos_drm.h
- *
- * 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.
- *
- */
-
-#ifndef _ROCKCHIP_DRM_H_
-#define _ROCKCHIP_DRM_H_
-
-#include <stdint.h>
-#include "drm.h"
-
-/**
- * User-desired buffer creation information structure.
- *
- * @size: user-desired memory allocation size.
- *	- this size value would be page-aligned internally.
- * @flags: user request for setting memory type or cache attributes.
- * @handle: returned a handle to created gem object.
- *	- this handle will be set by gem module of kernel side.
- */
-struct drm_rockchip_gem_create {
-	uint64_t size;
-	uint32_t flags;
-	uint32_t handle;
-};
-
-/**
- * A structure for getting buffer offset.
- *
- * @handle: a pointer to gem object created.
- * @pad: just padding to be 64-bit aligned.
- * @offset: relatived offset value of the memory region allocated.
- *	- this value should be set by user.
- */
-struct drm_rockchip_gem_map_off {
-	uint32_t handle;
-	uint32_t pad;
-	uint64_t offset;
-};
-
-#define DRM_ROCKCHIP_GEM_CREATE	0x00
-#define DRM_ROCKCHIP_GEM_MAP_OFFSET	0x01
-
-#define DRM_IOCTL_ROCKCHIP_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
-		DRM_ROCKCHIP_GEM_CREATE, struct drm_rockchip_gem_create)
-
-#define DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \
-		DRM_ROCKCHIP_GEM_MAP_OFFSET, struct drm_rockchip_gem_map_off)
-
-#endif
diff --git a/rockchip/rockchip_drmif.h b/rockchip/rockchip_drmif.h
deleted file mode 100644
index 5c549a0..0000000
--- a/rockchip/rockchip_drmif.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) ROCKCHIP, Inc.
- * Author:yzq<yzq@rock-chips.com>
- *
- * based on exynos_drmif.h
- *
- * 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.
- *
- */
-
-#ifndef ROCKCHIP_DRMIF_H_
-#define ROCKCHIP_DRMIF_H_
-
-#include <xf86drm.h>
-#include <stdint.h>
-#include "rockchip_drm.h"
-
-struct rockchip_device {
-	int fd;
-};
-
-/*
- * Rockchip Buffer Object structure.
- *
- * @dev: rockchip device object allocated.
- * @handle: a gem handle to gem object created.
- * @flags: indicate memory allocation and cache attribute types.
- * @size: size to the buffer created.
- * @vaddr: user space address to a gem buffer mmaped.
- * @name: a gem global handle from flink request.
- */
-struct rockchip_bo {
-	struct rockchip_device	*dev;
-	uint32_t		handle;
-	uint32_t		flags;
-	size_t			size;
-	void			*vaddr;
-	uint32_t		name;
-};
-
-/*
- * device related functions:
- */
-struct rockchip_device *rockchip_device_create(int fd);
-void rockchip_device_destroy(struct rockchip_device *dev);
-
-/*
- * buffer-object related functions:
- */
-struct rockchip_bo *rockchip_bo_create(struct rockchip_device *dev,
-			size_t size, uint32_t flags);
-int rockchip_bo_get_info(struct rockchip_device *dev, uint32_t handle,
-			size_t *size, uint32_t *flags);
-void rockchip_bo_destroy(struct rockchip_bo *bo);
-struct rockchip_bo *rockchip_bo_from_name(struct rockchip_device *dev,
-			uint32_t name);
-int rockchip_bo_get_name(struct rockchip_bo *bo, uint32_t *name);
-uint32_t rockchip_bo_handle(struct rockchip_bo *bo);
-struct rockchip_bo *rockchip_bo_from_handle(struct rockchip_device *dev,
-			uint32_t handle, uint32_t flags, uint32_t size);
-void *rockchip_bo_map(struct rockchip_bo *bo);
-#endif /* ROCKCHIP_DRMIF_H_ */
diff --git a/tegra/Makefile.am b/tegra/Makefile.am
index fb40be5..5311997 100644
--- a/tegra/Makefile.am
+++ b/tegra/Makefile.am
@@ -4,7 +4,8 @@
 
 AM_CFLAGS = \
 	@PTHREADSTUBS_CFLAGS@ \
-	$(WARN_CFLAGS)
+	$(WARN_CFLAGS) \
+	-fvisibility=hidden
 
 libdrm_tegra_ladir = $(libdir)
 libdrm_tegra_la_LTLIBRARIES = libdrm_tegra.la
@@ -21,5 +22,6 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_tegra.pc
 
+AM_TESTS_ENVIRONMENT = NM='$(NM)'
 TESTS = tegra-symbol-check
 EXTRA_DIST = $(TESTS)
diff --git a/tegra/meson.build b/tegra/meson.build
new file mode 100644
index 0000000..4bc454b
--- /dev/null
+++ b/tegra/meson.build
@@ -0,0 +1,53 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+libdrm_tegra = shared_library(
+  'drm_tegra',
+  [files('tegra.c'), config_file],
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  dependencies : [dep_pthread_stubs, dep_atomic_ops],
+  c_args : libdrm_c_args,
+  version : '0.0.0',
+  install : true,
+)
+
+ext_libdrm_tegra = declare_dependency(
+  link_with : [libdrm, libdrm_tegra],
+  include_directories : [inc_drm, include_directories('.')],
+)
+
+install_headers('tegra.h', subdir : 'libdrm')
+
+pkg.generate(
+  name : 'libdrm_tegra',
+  libraries : libdrm_tegra,
+  subdirs : ['.', 'libdrm'],
+  version : meson.project_version(),
+  requires_private : 'libdrm',
+  description : 'Userspace interface to Tegra kernel DRM services',
+)
+
+test(
+  'tegra-symbol-check',
+  prog_bash,
+  env : env_test,
+  args : [files('tegra-symbol-check'), libdrm_tegra]
+)
diff --git a/tegra/private.h b/tegra/private.h
index 571caa5..bb6c1a5 100644
--- a/tegra/private.h
+++ b/tegra/private.h
@@ -41,10 +41,9 @@
 struct drm_tegra_bo {
 	struct drm_tegra *drm;
 	uint32_t handle;
-	uint64_t offset;
+	uint32_t offset;
 	uint32_t flags;
 	uint32_t size;
-	uint32_t name;
 	atomic_t ref;
 	void *map;
 };
diff --git a/tegra/tegra-symbol-check b/tegra/tegra-symbol-check
index 4020831..8539b95 100755
--- a/tegra/tegra-symbol-check
+++ b/tegra/tegra-symbol-check
@@ -1,11 +1,16 @@
 #!/bin/bash
 
-# The following symbols (past the first five) are taken from the public headers.
-# A list of the latter should be available Makefile.sources/LIBDRM_FREEDRENO_H_FILES
+set -u
 
-FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_tegra.so} | awk '{print $3}'| while read func; do
+# The following symbols (past the first nine) are taken from tegra.h.
+
+FUNCS=$($NM -D --format=bsd --defined-only ${1-.libs/libdrm_tegra.so} | awk '{print $3}'| while read func; do
 ( grep -q "^$func$" || echo $func )  <<EOF
+__bss_end__
+__bss_start__
 __bss_start
+__end__
+_bss_end__
 _edata
 _end
 _fini
diff --git a/tegra/tegra.c b/tegra/tegra.c
index 66f19e9..cf00a3c 100644
--- a/tegra/tegra.c
+++ b/tegra/tegra.c
@@ -22,10 +22,6 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
 #include <errno.h>
 #include <fcntl.h>
 #include <string.h>
@@ -74,7 +70,7 @@
 	return 0;
 }
 
-int drm_tegra_new(struct drm_tegra **drmp, int fd)
+drm_public int drm_tegra_new(struct drm_tegra **drmp, int fd)
 {
 	bool supported = false;
 	drmVersionPtr version;
@@ -94,7 +90,7 @@
 	return drm_tegra_wrap(drmp, fd, false);
 }
 
-void drm_tegra_close(struct drm_tegra *drm)
+drm_public void drm_tegra_close(struct drm_tegra *drm)
 {
 	if (!drm)
 		return;
@@ -105,7 +101,7 @@
 	free(drm);
 }
 
-int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
+drm_public int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
 		     uint32_t flags, uint32_t size)
 {
 	struct drm_tegra_gem_create args;
@@ -143,7 +139,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
+drm_public int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
 		      uint32_t handle, uint32_t flags, uint32_t size)
 {
 	struct drm_tegra_bo *bo;
@@ -166,62 +162,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_name_ref(struct drm_tegra *drm, uint32_t name, uint32_t size,
-			 struct drm_tegra_bo **bop)
-{
-	struct drm_tegra_bo *bo;
-	struct drm_gem_open open_args;
-	struct drm_gem_close close_args;
-	int ret;
-
-	memset(&open_args, 0, sizeof(open_args));
-
-	open_args.name = name;
-
-	ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &open_args);
-	if (ret)
-		return ret;
-
-	ret = drm_tegra_bo_wrap(bop, drm, open_args.handle, 0, size);
-	if (ret)
-		goto err;
-
-	(*bop)->name = name;
-
-	return 0;
-
-err:
-	memset(&close_args, 0, sizeof(close_args));
-	close_args.handle = open_args.handle;
-	drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &close_args);
-
-	return ret;
-}
-
-int drm_tegra_bo_name_get(struct drm_tegra_bo *bo, uint32_t *name)
-{
-	struct drm_gem_flink args;
-	int ret;
-
-	args.handle =  bo->handle;
-
-	*name = bo->name;
-	if (*name && *name != ~0U)
-		return 0;
-
-	ret = drmIoctl(bo->drm->fd, DRM_IOCTL_GEM_FLINK, &args);
-	if (ret) {
-		*name = 0;
-		return ret;
-	}
-
-	bo->name = args.name;
-	*name = bo->name;
-
-	return 0;
-}
-
-struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo)
+drm_public struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo)
 {
 	if (bo)
 		atomic_inc(&bo->ref);
@@ -229,13 +170,13 @@
 	return bo;
 }
 
-void drm_tegra_bo_unref(struct drm_tegra_bo *bo)
+drm_public void drm_tegra_bo_unref(struct drm_tegra_bo *bo)
 {
 	if (bo && atomic_dec_and_test(&bo->ref))
 		drm_tegra_bo_free(bo);
 }
 
-int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle)
+drm_public int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle)
 {
 	if (!bo || !handle)
 		return -EINVAL;
@@ -245,7 +186,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr)
+drm_public int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr)
 {
 	struct drm_tegra *drm = bo->drm;
 
@@ -277,7 +218,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_unmap(struct drm_tegra_bo *bo)
+drm_public int drm_tegra_bo_unmap(struct drm_tegra_bo *bo)
 {
 	if (!bo)
 		return -EINVAL;
@@ -293,7 +234,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags)
+drm_public int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags)
 {
 	struct drm_tegra_gem_get_flags args;
 	struct drm_tegra *drm = bo->drm;
@@ -316,7 +257,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags)
+drm_public int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags)
 {
 	struct drm_tegra_gem_get_flags args;
 	struct drm_tegra *drm = bo->drm;
@@ -337,7 +278,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo,
+drm_public int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo,
 			    struct drm_tegra_bo_tiling *tiling)
 {
 	struct drm_tegra_gem_get_tiling args;
@@ -363,7 +304,7 @@
 	return 0;
 }
 
-int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo,
+drm_public int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo,
 			    const struct drm_tegra_bo_tiling *tiling)
 {
 	struct drm_tegra_gem_set_tiling args;
diff --git a/tegra/tegra.h b/tegra/tegra.h
index e10eab7..31b0995 100644
--- a/tegra/tegra.h
+++ b/tegra/tegra.h
@@ -38,11 +38,6 @@
 		     uint32_t flags, uint32_t size);
 int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
 		      uint32_t handle, uint32_t flags, uint32_t size);
-
-int drm_tegra_bo_name_ref(struct drm_tegra *drm, uint32_t name, uint32_t size,
-			 struct drm_tegra_bo **bop);
-int drm_tegra_bo_name_get(struct drm_tegra_bo *bo, uint32_t *name);
-
 struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo);
 void drm_tegra_bo_unref(struct drm_tegra_bo *bo);
 int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f2bb4d4..d274a3e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,7 +1,7 @@
 SUBDIRS = util kms modeprint proptest modetest vbltest
 
 if HAVE_LIBKMS
-SUBDIRS += kmstest planetest
+SUBDIRS += kmstest
 endif
 
 if HAVE_RADEON
@@ -32,6 +32,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS)\
+	-fvisibility=hidden \
 	-I $(top_srcdir)/include/drm \
 	-I $(top_srcdir)
 
@@ -43,5 +44,10 @@
 	random
 
 check_PROGRAMS = \
-	$(TESTS) \
-	drmdevice
+	$(TESTS)
+
+if HAVE_INSTALL_TESTS
+bin_PROGRAMS = drmdevice
+else
+check_PROGRAMS += drmdevice
+endif
diff --git a/tests/amdgpu/.editorconfig b/tests/amdgpu/.editorconfig
new file mode 120000
index 0000000..70734e4
--- /dev/null
+++ b/tests/amdgpu/.editorconfig
@@ -0,0 +1 @@
+../../amdgpu/.editorconfig
\ No newline at end of file
diff --git a/tests/amdgpu/Makefile.am b/tests/amdgpu/Makefile.am
index c1c3a32..447ff21 100644
--- a/tests/amdgpu/Makefile.am
+++ b/tests/amdgpu/Makefile.am
@@ -1,7 +1,9 @@
 AM_CFLAGS = \
+	-fvisibility=hidden \
 	-I $(top_srcdir)/include/drm \
 	-I $(top_srcdir)/amdgpu \
-	-I $(top_srcdir)
+	-I $(top_srcdir) \
+	-pthread
 
 LDADD = $(top_builddir)/libdrm.la \
 	$(top_builddir)/amdgpu/libdrm_amdgpu.la \
@@ -23,7 +25,12 @@
 	basic_tests.c \
 	bo_tests.c \
 	cs_tests.c \
-	uvd_messages.h \
+	decode_messages.h \
 	vce_tests.c \
 	vce_ib.h \
-	frame.h
+	frame.h \
+	uvd_enc_tests.c \
+	vcn_tests.c \
+	uve_ib.h \
+	deadlock_tests.c \
+	vm_tests.c
diff --git a/tests/amdgpu/amdgpu_test.c b/tests/amdgpu/amdgpu_test.c
index 3fd6820..ebf4409 100644
--- a/tests/amdgpu/amdgpu_test.c
+++ b/tests/amdgpu/amdgpu_test.c
@@ -21,10 +21,6 @@
  *
 */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -49,6 +45,17 @@
 #include "CUnit/Basic.h"
 
 #include "amdgpu_test.h"
+#include "amdgpu_internal.h"
+
+/* Test suite names */
+#define BASIC_TESTS_STR "Basic Tests"
+#define BO_TESTS_STR "BO Tests"
+#define CS_TESTS_STR "CS Tests"
+#define VCE_TESTS_STR "VCE Tests"
+#define VCN_TESTS_STR "VCN Tests"
+#define UVD_ENC_TESTS_STR "UVD ENC Tests"
+#define DEADLOCK_TESTS_STR "Deadlock Tests"
+#define VM_TESTS_STR "VM Tests"
 
 /**
  *  Open handles for amdgpu devices
@@ -62,49 +69,150 @@
 /** The table of all known test suites to run */
 static CU_SuiteInfo suites[] = {
 	{
-		.pName = "Basic Tests",
+		.pName = BASIC_TESTS_STR,
 		.pInitFunc = suite_basic_tests_init,
 		.pCleanupFunc = suite_basic_tests_clean,
 		.pTests = basic_tests,
 	},
 	{
-		.pName = "BO Tests",
+		.pName = BO_TESTS_STR,
 		.pInitFunc = suite_bo_tests_init,
 		.pCleanupFunc = suite_bo_tests_clean,
 		.pTests = bo_tests,
 	},
 	{
-		.pName = "CS Tests",
+		.pName = CS_TESTS_STR,
 		.pInitFunc = suite_cs_tests_init,
 		.pCleanupFunc = suite_cs_tests_clean,
 		.pTests = cs_tests,
 	},
 	{
-		.pName = "VCE Tests",
+		.pName = VCE_TESTS_STR,
 		.pInitFunc = suite_vce_tests_init,
 		.pCleanupFunc = suite_vce_tests_clean,
 		.pTests = vce_tests,
 	},
+	{
+		.pName = VCN_TESTS_STR,
+		.pInitFunc = suite_vcn_tests_init,
+		.pCleanupFunc = suite_vcn_tests_clean,
+		.pTests = vcn_tests,
+	},
+	{
+		.pName = UVD_ENC_TESTS_STR,
+		.pInitFunc = suite_uvd_enc_tests_init,
+		.pCleanupFunc = suite_uvd_enc_tests_clean,
+		.pTests = uvd_enc_tests,
+	},
+	{
+		.pName = DEADLOCK_TESTS_STR,
+		.pInitFunc = suite_deadlock_tests_init,
+		.pCleanupFunc = suite_deadlock_tests_clean,
+		.pTests = deadlock_tests,
+	},
+	{
+		.pName = VM_TESTS_STR,
+		.pInitFunc = suite_vm_tests_init,
+		.pCleanupFunc = suite_vm_tests_clean,
+		.pTests = vm_tests,
+	},
+
 	CU_SUITE_INFO_NULL,
 };
 
+typedef CU_BOOL (*active__stat_func)(void);
 
-/** Display information about all  suites and their tests */
+typedef struct Suites_Active_Status {
+	char*             pName;
+	active__stat_func pActive;
+}Suites_Active_Status;
+
+static CU_BOOL always_active()
+{
+	return CU_TRUE;
+}
+
+static Suites_Active_Status suites_active_stat[] = {
+		{
+			.pName = BASIC_TESTS_STR,
+			.pActive = always_active,
+		},
+		{
+			.pName = BO_TESTS_STR,
+			.pActive = always_active,
+		},
+		{
+			.pName = CS_TESTS_STR,
+			.pActive = suite_cs_tests_enable,
+		},
+		{
+			.pName = VCE_TESTS_STR,
+			.pActive = suite_vce_tests_enable,
+		},
+		{
+			.pName = VCN_TESTS_STR,
+			.pActive = suite_vcn_tests_enable,
+		},
+		{
+			.pName = UVD_ENC_TESTS_STR,
+			.pActive = suite_uvd_enc_tests_enable,
+		},
+		{
+			.pName = DEADLOCK_TESTS_STR,
+			.pActive = suite_deadlock_tests_enable,
+		},
+		{
+			.pName = VM_TESTS_STR,
+			.pActive = suite_vm_tests_enable,
+		},
+};
+
+
+/*
+ * Display information about all  suites and their tests
+ *
+ * NOTE: Must be run after registry is initialized and suites registered.
+ */
 static void display_test_suites(void)
 {
 	int iSuite;
 	int iTest;
+	CU_pSuite pSuite = NULL;
+	CU_pTest  pTest  = NULL;
 
 	printf("Suites\n");
 
 	for (iSuite = 0; suites[iSuite].pName != NULL; iSuite++) {
-		printf("Suite id = %d: Name '%s'\n",
-				iSuite + 1, suites[iSuite].pName);
+
+		pSuite = CU_get_suite_by_index((unsigned int) iSuite + 1,
+						      CU_get_registry());
+
+		if (!pSuite) {
+			fprintf(stderr, "Invalid suite id : %d\n", iSuite + 1);
+			continue;
+		}
+
+		printf("Suite id = %d: Name '%s status: %s'\n",
+				iSuite + 1, suites[iSuite].pName,
+				pSuite->fActive ? "ENABLED" : "DISABLED");
+
+
 
 		for (iTest = 0; suites[iSuite].pTests[iTest].pName != NULL;
 			iTest++) {
-			printf("	Test id %d: Name: '%s'\n", iTest + 1,
-					suites[iSuite].pTests[iTest].pName);
+
+			pTest = CU_get_test_by_index((unsigned int) iTest + 1,
+									pSuite);
+
+			if (!pTest) {
+				fprintf(stderr, "Invalid test id : %d\n", iTest + 1);
+				continue;
+			}
+
+			printf("Test id %d: Name: '%s status: %s'\n", iTest + 1,
+					suites[iSuite].pTests[iTest].pName,
+					pSuite->fActive && pTest->fActive ?
+						     "ENABLED" : "DISABLED");
 		}
 	}
 }
@@ -112,7 +220,7 @@
 
 /** Help string for command line parameters */
 static const char usage[] =
-	"Usage: %s [-hlpr] [<-s <suite id>> [-t <test id>]] "
+	"Usage: %s [-hlpr] [<-s <suite id>> [-t <test id>] [-f]] "
 	"[-b <pci_bus_id> [-d <pci_device_id>]]\n"
 	"where:\n"
 	"       l - Display all suites and their tests\n"
@@ -120,9 +228,10 @@
 	"       b - Specify device's PCI bus id to run tests\n"
 	"       d - Specify device's PCI device id to run tests (optional)\n"
 	"       p - Display information of AMDGPU devices in system\n"
+	"       f - Force executing inactive suite or test\n"
 	"       h - Display this help\n";
 /** Specified options strings for getopt */
-static const char options[]   = "hlrps:t:b:d:";
+static const char options[]   = "hlrps:t:b:d:f";
 
 /* Open AMD devices.
  * Return the number of AMD device openned.
@@ -130,7 +239,6 @@
 static int amdgpu_open_devices(int open_render_node)
 {
 	drmDevicePtr devices[MAX_CARDS_SUPPORTED];
-	int ret;
 	int i;
 	int drm_node;
 	int amd_index = 0;
@@ -264,29 +372,72 @@
 /* Find a match AMD device in PCI bus
  * Return the index of the device or -1 if not found
  */
-static int amdgpu_find_device(uint8_t bus, uint8_t dev)
+static int amdgpu_find_device(uint8_t bus, uint16_t dev)
 {
 	int i;
 	drmDevicePtr device;
 
-	for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >=0; i++)
+	for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) {
 		if (drmGetDevice2(drm_amdgpu[i],
 			DRM_DEVICE_GET_PCI_REVISION,
 			&device) == 0) {
 			if (device->bustype == DRM_BUS_PCI)
-				if (device->businfo.pci->bus == bus &&
-					device->businfo.pci->dev == dev) {
-
+				if ((bus == 0xFF || device->businfo.pci->bus == bus) &&
+					device->deviceinfo.pci->device_id == dev) {
 					drmFreeDevice(&device);
 					return i;
 				}
 
 			drmFreeDevice(&device);
 		}
+	}
 
 	return -1;
 }
 
+static void amdgpu_disable_suites()
+{
+	amdgpu_device_handle device_handle;
+	uint32_t major_version, minor_version, family_id;
+	int i;
+	int size = sizeof(suites_active_stat) / sizeof(suites_active_stat[0]);
+
+	if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+				   &minor_version, &device_handle))
+		return;
+
+	family_id = device_handle->info.family_id;
+
+	if (amdgpu_device_deinitialize(device_handle))
+		return;
+
+	/* Set active status for suites based on their policies */
+	for (i = 0; i < size; ++i)
+		if (amdgpu_set_suite_active(suites_active_stat[i].pName,
+				suites_active_stat[i].pActive()))
+			fprintf(stderr, "suite deactivation failed - %s\n", CU_get_error_msg());
+
+	/* Explicitly disable specific tests due to known bugs or preferences */
+	/*
+	* BUG: Compute ring stalls and never recovers when the address is
+	* written after the command already submitted
+	*/
+	if (amdgpu_set_test_active(DEADLOCK_TESTS_STR,
+			"compute ring block test (set amdgpu.lockup_timeout=50)", CU_FALSE))
+		fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg());
+
+	if (amdgpu_set_test_active(BO_TESTS_STR, "Metadata", CU_FALSE))
+		fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg());
+
+	if (amdgpu_set_test_active(BASIC_TESTS_STR, "bo eviction Test", CU_FALSE))
+		fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg());
+
+	/* This test was ran on GFX8 and GFX9 only */
+	if (family_id < AMDGPU_FAMILY_VI || family_id > AMDGPU_FAMILY_RV)
+		if (amdgpu_set_test_active(BASIC_TESTS_STR, "Sync dependency Test", CU_FALSE))
+			fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg());
+}
+
 /* The main() function for setting up and running the tests.
  * Returns a CUE_SUCCESS on successful running, another
  * CUnit error code on failure.
@@ -303,6 +454,8 @@
 	CU_pSuite pSuite = NULL;
 	CU_pTest  pTest  = NULL;
 	int test_device_index;
+	int display_list = 0;
+	int force_run = 0;
 
 	for (i = 0; i < MAX_CARDS_SUPPORTED; i++)
 		drm_amdgpu[i] = -1;
@@ -313,8 +466,8 @@
 	while ((c = getopt(argc, argv, options)) != -1) {
 		switch (c) {
 		case 'l':
-			display_test_suites();
-			exit(EXIT_SUCCESS);
+			display_list = 1;
+			break;
 		case 's':
 			suite_id = atoi(optarg);
 			break;
@@ -325,7 +478,7 @@
 			pci_bus_id = atoi(optarg);
 			break;
 		case 'd':
-			pci_device_id = atoi(optarg);
+			sscanf(optarg, "%x", &pci_device_id);
 			break;
 		case 'p':
 			display_devices = 1;
@@ -333,6 +486,9 @@
 		case 'r':
 			open_render_node = 1;
 			break;
+		case 'f':
+			force_run = 1;
+			break;
 		case '?':
 		case 'h':
 			fprintf(stderr, usage, argv[0]);
@@ -359,10 +515,10 @@
 		exit(EXIT_SUCCESS);
 	}
 
-	if (pci_bus_id > 0) {
+	if (pci_bus_id > 0 || pci_device_id) {
 		/* A device was specified to run the test */
-		test_device_index = amdgpu_find_device((uint8_t)pci_bus_id,
-							(uint8_t)pci_device_id);
+		test_device_index = amdgpu_find_device(pci_bus_id,
+						       pci_device_id);
 
 		if (test_device_index >= 0) {
 			/* Most tests run on device of drm_amdgpu[0].
@@ -398,17 +554,33 @@
 	/* Run tests using the CUnit Basic interface */
 	CU_basic_set_mode(CU_BRM_VERBOSE);
 
+	/* Disable suites and individual tests based on misc. conditions */
+	amdgpu_disable_suites();
+
+	if (display_list) {
+		display_test_suites();
+		goto end;
+	}
+
 	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 (force_run)
+				CU_set_suite_active(pSuite, CU_TRUE);
+
 			if (test_id != -1) {   /* If user specify test id */
 				pTest = CU_get_test_by_index(
 						(unsigned int) test_id,
 						pSuite);
-				if (pTest)
+				if (pTest) {
+					if (force_run)
+						CU_set_test_active(pTest, CU_TRUE);
+
 					CU_basic_run_test(pSuite, pTest);
+				}
 				else {
 					fprintf(stderr, "Invalid test id: %d\n",
 								test_id);
@@ -428,6 +600,7 @@
 	} else
 		CU_basic_run_tests();
 
+end:
 	CU_cleanup_registry();
 	amdgpu_close_devices();
 	return CU_get_error();
diff --git a/tests/amdgpu/amdgpu_test.h b/tests/amdgpu/amdgpu_test.h
index e30e231..af81eea 100644
--- a/tests/amdgpu/amdgpu_test.h
+++ b/tests/amdgpu/amdgpu_test.h
@@ -30,7 +30,7 @@
 /**
  * Define max. number of card in system which we are able to handle
  */
-#define MAX_CARDS_SUPPORTED     4
+#define MAX_CARDS_SUPPORTED     128
 
 /* Forward reference for array to keep "drm" handles */
 extern int drm_amdgpu[MAX_CARDS_SUPPORTED];
@@ -85,6 +85,11 @@
 int suite_cs_tests_clean();
 
 /**
+ * Decide if the suite is enabled by default or not.
+ */
+CU_BOOL suite_cs_tests_enable(void);
+
+/**
  * Tests in cs test suite
  */
 extern CU_TestInfo cs_tests[];
@@ -100,11 +105,96 @@
 int suite_vce_tests_clean();
 
 /**
+ * Decide if the suite is enabled by default or not.
+ */
+CU_BOOL suite_vce_tests_enable(void);
+
+/**
  * Tests in vce test suite
  */
 extern CU_TestInfo vce_tests[];
 
 /**
++ * Initialize vcn test suite
++ */
+int suite_vcn_tests_init();
+
+/**
++ * Deinitialize vcn test suite
++ */
+int suite_vcn_tests_clean();
+
+/**
+ * Decide if the suite is enabled by default or not.
+ */
+CU_BOOL suite_vcn_tests_enable(void);
+
+/**
++ * Tests in vcn test suite
++ */
+extern CU_TestInfo vcn_tests[];
+
+/**
+ * Initialize uvd enc test suite
+ */
+int suite_uvd_enc_tests_init();
+
+/**
+ * Deinitialize uvd enc test suite
+ */
+int suite_uvd_enc_tests_clean();
+
+/**
+ * Decide if the suite is enabled by default or not.
+ */
+CU_BOOL suite_uvd_enc_tests_enable(void);
+
+/**
+ * Tests in uvd enc test suite
+ */
+extern CU_TestInfo uvd_enc_tests[];
+
+/**
+ * Initialize deadlock test suite
+ */
+int suite_deadlock_tests_init();
+
+/**
+ * Deinitialize deadlock test suite
+ */
+int suite_deadlock_tests_clean();
+
+/**
+ * Decide if the suite is enabled by default or not.
+ */
+CU_BOOL suite_deadlock_tests_enable(void);
+
+/**
+ * Tests in uvd enc test suite
+ */
+extern CU_TestInfo deadlock_tests[];
+
+/**
+ * Initialize vm test suite
+ */
+int suite_vm_tests_init();
+
+/**
+ * Deinitialize deadlock test suite
+ */
+int suite_vm_tests_clean();
+
+/**
+ * Decide if the suite is enabled by default or not.
+ */
+CU_BOOL suite_vm_tests_enable(void);
+
+/**
+ * Tests in vm test suite
+ */
+extern CU_TestInfo vm_tests[];
+
+/**
  * Helper functions
  */
 static inline amdgpu_bo_handle gpu_mem_alloc(
@@ -117,11 +207,9 @@
 					amdgpu_va_handle *va_handle)
 {
 	struct amdgpu_bo_alloc_request req = {0};
-	amdgpu_bo_handle buf_handle;
+	amdgpu_bo_handle buf_handle = NULL;
 	int r;
 
-	CU_ASSERT_NOT_EQUAL(vmc_addr, NULL);
-
 	req.alloc_size = size;
 	req.phys_alignment = alignment;
 	req.preferred_heap = type;
@@ -129,17 +217,36 @@
 
 	r = amdgpu_bo_alloc(device_handle, &req, &buf_handle);
 	CU_ASSERT_EQUAL(r, 0);
+	if (r)
+		return NULL;
 
-	r = amdgpu_va_range_alloc(device_handle,
-				  amdgpu_gpu_va_range_general,
-				  size, alignment, 0, vmc_addr,
-				  va_handle, 0);
-	CU_ASSERT_EQUAL(r, 0);
+	if (vmc_addr && va_handle) {
+		r = amdgpu_va_range_alloc(device_handle,
+					  amdgpu_gpu_va_range_general,
+					  size, alignment, 0, vmc_addr,
+					  va_handle, 0);
+		CU_ASSERT_EQUAL(r, 0);
+		if (r)
+			goto error_free_bo;
 
-	r = amdgpu_bo_va_op(buf_handle, 0, size, *vmc_addr, 0, AMDGPU_VA_OP_MAP);
-	CU_ASSERT_EQUAL(r, 0);
+		r = amdgpu_bo_va_op(buf_handle, 0, size, *vmc_addr, 0,
+				    AMDGPU_VA_OP_MAP);
+		CU_ASSERT_EQUAL(r, 0);
+		if (r)
+			goto error_free_va;
+	}
 
 	return buf_handle;
+
+error_free_va:
+	r = amdgpu_va_range_free(*va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+error_free_bo:
+	r = amdgpu_bo_free(buf_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	return NULL;
 }
 
 static inline int gpu_mem_free(amdgpu_bo_handle bo,
@@ -149,28 +256,35 @@
 {
 	int r;
 
-	r = amdgpu_bo_va_op(bo, 0, size, vmc_addr, 0, AMDGPU_VA_OP_UNMAP);
-	CU_ASSERT_EQUAL(r, 0);
+	if (!bo)
+		return 0;
 
-	r = amdgpu_va_range_free(va_handle);
-	CU_ASSERT_EQUAL(r, 0);
+	if (va_handle) {
+		r = amdgpu_bo_va_op(bo, 0, size, vmc_addr, 0,
+				    AMDGPU_VA_OP_UNMAP);
+		CU_ASSERT_EQUAL(r, 0);
+		if (r)
+			return r;
+
+		r = amdgpu_va_range_free(va_handle);
+		CU_ASSERT_EQUAL(r, 0);
+		if (r)
+			return r;
+	}
 
 	r = amdgpu_bo_free(bo);
 	CU_ASSERT_EQUAL(r, 0);
 
-	return 0;
+	return r;
 }
 
 static inline int
-amdgpu_bo_alloc_and_map(amdgpu_device_handle dev, unsigned size,
-			unsigned alignment, unsigned heap, uint64_t flags,
-			amdgpu_bo_handle *bo, void **cpu, uint64_t *mc_address,
-			amdgpu_va_handle *va_handle)
+amdgpu_bo_alloc_wrap(amdgpu_device_handle dev, unsigned size,
+		     unsigned alignment, unsigned heap, uint64_t flags,
+		     amdgpu_bo_handle *bo)
 {
 	struct amdgpu_bo_alloc_request request = {};
 	amdgpu_bo_handle buf_handle;
-	amdgpu_va_handle handle;
-	uint64_t vmc_addr;
 	int r;
 
 	request.alloc_size = size;
@@ -182,36 +296,25 @@
 	if (r)
 		return r;
 
-	r = amdgpu_va_range_alloc(dev,
-				  amdgpu_gpu_va_range_general,
-				  size, alignment, 0, &vmc_addr,
-				  &handle, 0);
-	if (r)
-		goto error_va_alloc;
-
-	r = amdgpu_bo_va_op(buf_handle, 0, size, vmc_addr, 0, AMDGPU_VA_OP_MAP);
-	if (r)
-		goto error_va_map;
-
-	r = amdgpu_bo_cpu_map(buf_handle, cpu);
-	if (r)
-		goto error_cpu_map;
-
 	*bo = buf_handle;
-	*mc_address = vmc_addr;
-	*va_handle = handle;
 
 	return 0;
+}
 
-error_cpu_map:
-	amdgpu_bo_cpu_unmap(buf_handle);
+int amdgpu_bo_alloc_and_map_raw(amdgpu_device_handle dev, unsigned size,
+			unsigned alignment, unsigned heap, uint64_t alloc_flags,
+			uint64_t mapping_flags, amdgpu_bo_handle *bo, void **cpu,
+			uint64_t *mc_address,
+			amdgpu_va_handle *va_handle);
 
-error_va_map:
-	amdgpu_bo_va_op(buf_handle, 0, size, vmc_addr, 0, AMDGPU_VA_OP_UNMAP);
-
-error_va_alloc:
-	amdgpu_bo_free(buf_handle);
-	return r;
+static inline int
+amdgpu_bo_alloc_and_map(amdgpu_device_handle dev, unsigned size,
+			unsigned alignment, unsigned heap, uint64_t alloc_flags,
+			amdgpu_bo_handle *bo, void **cpu, uint64_t *mc_address,
+			amdgpu_va_handle *va_handle)
+{
+	return amdgpu_bo_alloc_and_map_raw(dev, size, alignment, heap,
+					alloc_flags, 0, bo, cpu, mc_address, va_handle);
 }
 
 static inline int
@@ -236,4 +339,35 @@
 	return amdgpu_bo_list_create(dev, bo2 ? 2 : 1, resources, NULL, list);
 }
 
+
+static inline CU_ErrorCode amdgpu_set_suite_active(const char *suite_name,
+							  CU_BOOL active)
+{
+	CU_ErrorCode r = CU_set_suite_active(CU_get_suite(suite_name), active);
+
+	if (r != CUE_SUCCESS)
+		fprintf(stderr, "Failed to obtain suite %s\n", suite_name);
+
+	return r;
+}
+
+static inline CU_ErrorCode amdgpu_set_test_active(const char *suite_name,
+				  const char *test_name, CU_BOOL active)
+{
+	CU_ErrorCode r;
+	CU_pSuite pSuite = CU_get_suite(suite_name);
+
+	if (!pSuite) {
+		fprintf(stderr, "Failed to obtain suite %s\n",
+				suite_name);
+		return CUE_NOSUITE;
+	}
+
+	r = CU_set_test_active(CU_get_test(pSuite, test_name), active);
+	if (r != CUE_SUCCESS)
+		fprintf(stderr, "Failed to obtain test %s\n", test_name);
+
+	return r;
+}
+
 #endif  /* #ifdef _AMDGPU_TEST_H_ */
diff --git a/tests/amdgpu/basic_tests.c b/tests/amdgpu/basic_tests.c
index bfda21b..dbae4d5 100644
--- a/tests/amdgpu/basic_tests.c
+++ b/tests/amdgpu/basic_tests.c
@@ -21,46 +21,55 @@
  *
 */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #ifdef HAVE_ALLOCA_H
 # include <alloca.h>
 #endif
+#include <sys/wait.h>
 
 #include "CUnit/Basic.h"
 
 #include "amdgpu_test.h"
 #include "amdgpu_drm.h"
+#include "util_math.h"
 
 static  amdgpu_device_handle device_handle;
 static  uint32_t  major_version;
 static  uint32_t  minor_version;
+static  uint32_t  family_id;
 
 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_multi_fence(void);
 static void amdgpu_command_submission_sdma(void);
 static void amdgpu_userptr_test(void);
 static void amdgpu_semaphore_test(void);
+static void amdgpu_sync_dependency_test(void);
+static void amdgpu_bo_eviction_test(void);
 
 static void amdgpu_command_submission_write_linear_helper(unsigned ip_type);
 static void amdgpu_command_submission_const_fill_helper(unsigned ip_type);
 static void amdgpu_command_submission_copy_linear_helper(unsigned ip_type);
-
+static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle,
+				       unsigned ip_type,
+				       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);
+ 
 CU_TestInfo basic_tests[] = {
 	{ "Query Info Test",  amdgpu_query_info_test },
-	{ "Memory alloc Test",  amdgpu_memory_alloc },
 	{ "Userptr Test",  amdgpu_userptr_test },
+	{ "bo eviction Test",  amdgpu_bo_eviction_test },
 	{ "Command submission Test (GFX)",  amdgpu_command_submission_gfx },
 	{ "Command submission Test (Compute)", amdgpu_command_submission_compute },
+	{ "Command submission Test (Multi-Fence)", amdgpu_command_submission_multi_fence },
 	{ "Command submission Test (SDMA)", amdgpu_command_submission_sdma },
 	{ "SW semaphore Test",  amdgpu_semaphore_test },
+	{ "Sync dependency Test",  amdgpu_sync_dependency_test },
 	CU_TEST_INFO_NULL,
 };
 #define BUFFER_SIZE (8 * 1024)
@@ -197,22 +206,170 @@
 #              define PACKET3_DMA_DATA_CMD_DAIC    (1 << 29)
 #              define PACKET3_DMA_DATA_CMD_RAW_WAIT  (1 << 30)
 
+#define SDMA_PACKET_SI(op, b, t, s, cnt)	((((op) & 0xF) << 28) |	\
+						(((b) & 0x1) << 26) |		\
+						(((t) & 0x1) << 23) |		\
+						(((s) & 0x1) << 22) |		\
+						(((cnt) & 0xFFFFF) << 0))
+#define	SDMA_OPCODE_COPY_SI	3
+#define SDMA_OPCODE_CONSTANT_FILL_SI	13
+#define SDMA_NOP_SI  0xf
+#define GFX_COMPUTE_NOP_SI 0x80000000
+#define	PACKET3_DMA_DATA_SI	0x41
+#              define PACKET3_DMA_DATA_SI_ENGINE(x)     ((x) << 27)
+		/* 0 - ME
+		 * 1 - PFP
+		 */
+#              define PACKET3_DMA_DATA_SI_DST_SEL(x)  ((x) << 20)
+		/* 0 - DST_ADDR using DAS
+		 * 1 - GDS
+		 * 3 - DST_ADDR using L2
+		 */
+#              define PACKET3_DMA_DATA_SI_SRC_SEL(x)  ((x) << 29)
+		/* 0 - SRC_ADDR using SAS
+		 * 1 - GDS
+		 * 2 - DATA
+		 * 3 - SRC_ADDR using L2
+		 */
+#              define PACKET3_DMA_DATA_SI_CP_SYNC     (1 << 31)
+
+
+#define PKT3_CONTEXT_CONTROL                   0x28
+#define     CONTEXT_CONTROL_LOAD_ENABLE(x)     (((unsigned)(x) & 0x1) << 31)
+#define     CONTEXT_CONTROL_LOAD_CE_RAM(x)     (((unsigned)(x) & 0x1) << 28)
+#define     CONTEXT_CONTROL_SHADOW_ENABLE(x)   (((unsigned)(x) & 0x1) << 31)
+
+#define PKT3_CLEAR_STATE                       0x12
+
+#define PKT3_SET_SH_REG                        0x76
+#define		PACKET3_SET_SH_REG_START			0x00002c00
+
+#define	PACKET3_DISPATCH_DIRECT				0x15
+
+
+/* gfx 8 */
+#define mmCOMPUTE_PGM_LO                                                        0x2e0c
+#define mmCOMPUTE_PGM_RSRC1                                                     0x2e12
+#define mmCOMPUTE_TMPRING_SIZE                                                  0x2e18
+#define mmCOMPUTE_USER_DATA_0                                                   0x2e40
+#define mmCOMPUTE_USER_DATA_1                                                   0x2e41
+#define mmCOMPUTE_RESOURCE_LIMITS                                               0x2e15
+#define mmCOMPUTE_NUM_THREAD_X                                                  0x2e07
+
+
+
+#define SWAP_32(num) (((num & 0xff000000) >> 24) | \
+		      ((num & 0x0000ff00) << 8) | \
+		      ((num & 0x00ff0000) >> 8) | \
+		      ((num & 0x000000ff) << 24))
+
+
+/* Shader code
+ * void main()
+{
+
+	float x = some_input;
+		for (unsigned i = 0; i < 1000000; i++)
+  	x = sin(x);
+
+	u[0] = 42u;
+}
+*/
+
+static  uint32_t shader_bin[] = {
+	SWAP_32(0x800082be), SWAP_32(0x02ff08bf), SWAP_32(0x7f969800), SWAP_32(0x040085bf),
+	SWAP_32(0x02810281), SWAP_32(0x02ff08bf), SWAP_32(0x7f969800), SWAP_32(0xfcff84bf),
+	SWAP_32(0xff0083be), SWAP_32(0x00f00000), SWAP_32(0xc10082be), SWAP_32(0xaa02007e),
+	SWAP_32(0x000070e0), SWAP_32(0x00000080), SWAP_32(0x000081bf)
+};
+
+#define CODE_OFFSET 512
+#define DATA_OFFSET 1024
+
+
+int amdgpu_bo_alloc_and_map_raw(amdgpu_device_handle dev, unsigned size,
+			unsigned alignment, unsigned heap, uint64_t alloc_flags,
+			uint64_t mapping_flags, amdgpu_bo_handle *bo, void **cpu,
+			uint64_t *mc_address,
+			amdgpu_va_handle *va_handle)
+{
+	struct amdgpu_bo_alloc_request request = {};
+	amdgpu_bo_handle buf_handle;
+	amdgpu_va_handle handle;
+	uint64_t vmc_addr;
+	int r;
+
+	request.alloc_size = size;
+	request.phys_alignment = alignment;
+	request.preferred_heap = heap;
+	request.flags = alloc_flags;
+
+	r = amdgpu_bo_alloc(dev, &request, &buf_handle);
+	if (r)
+		return r;
+
+	r = amdgpu_va_range_alloc(dev,
+				  amdgpu_gpu_va_range_general,
+				  size, alignment, 0, &vmc_addr,
+				  &handle, 0);
+	if (r)
+		goto error_va_alloc;
+
+	r = amdgpu_bo_va_op_raw(dev, buf_handle, 0,  ALIGN(size, getpagesize()), vmc_addr,
+				   AMDGPU_VM_PAGE_READABLE |
+				   AMDGPU_VM_PAGE_WRITEABLE |
+				   AMDGPU_VM_PAGE_EXECUTABLE |
+				   mapping_flags,
+				   AMDGPU_VA_OP_MAP);
+	if (r)
+		goto error_va_map;
+
+	r = amdgpu_bo_cpu_map(buf_handle, cpu);
+	if (r)
+		goto error_cpu_map;
+
+	*bo = buf_handle;
+	*mc_address = vmc_addr;
+	*va_handle = handle;
+
+	return 0;
+
+ error_cpu_map:
+	amdgpu_bo_cpu_unmap(buf_handle);
+
+ error_va_map:
+	amdgpu_bo_va_op(buf_handle, 0, size, vmc_addr, 0, AMDGPU_VA_OP_UNMAP);
+
+ error_va_alloc:
+	amdgpu_bo_free(buf_handle);
+	return r;
+}
+
+
+
 int suite_basic_tests_init(void)
 {
+	struct amdgpu_gpu_info gpu_info = {0};
 	int r;
 
 	r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
 				   &minor_version, &device_handle);
 
-	if (r == 0)
-		return CUE_SUCCESS;
-	else {
+	if (r) {
 		if ((r == -EACCES) && (errno == EACCES))
 			printf("\n\nError:%s. "
 				"Hint:Try to run this test program as root.",
 				strerror(errno));
 		return CUE_SINIT_FAILED;
 	}
+
+	r = amdgpu_query_gpu_info(device_handle, &gpu_info);
+	if (r)
+		return CUE_SINIT_FAILED;
+
+	family_id = gpu_info.family_id;
+
+	return CUE_SUCCESS;
 }
 
 int suite_basic_tests_clean(void)
@@ -239,53 +396,6 @@
 	CU_ASSERT_EQUAL(r, 0);
 }
 
-static void amdgpu_memory_alloc(void)
-{
-	amdgpu_bo_handle bo;
-	amdgpu_va_handle va_handle;
-	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, &va_handle);
-
-	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
-	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, &va_handle);
-
-	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
-	CU_ASSERT_EQUAL(r, 0);
-
-	/* Test GART Cacheable */
-	bo = gpu_mem_alloc(device_handle,
-			4096, 4096,
-			AMDGPU_GEM_DOMAIN_GTT,
-			0, &bo_mc, &va_handle);
-
-	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
-	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_USWC,
-			&bo_mc, &va_handle);
-
-	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
-	CU_ASSERT_EQUAL(r, 0);
-}
-
 static void amdgpu_command_submission_gfx_separate_ibs(void)
 {
 	amdgpu_context_handle context_handle;
@@ -299,7 +409,7 @@
 	uint32_t expired;
 	amdgpu_bo_list_handle bo_list;
 	amdgpu_va_handle va_handle, va_handle_ce;
-	int r;
+	int r, i = 0;
 
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	CU_ASSERT_EQUAL(r, 0);
@@ -324,12 +434,14 @@
 
 	/* IT_SET_CE_DE_COUNTERS */
 	ptr = ib_result_ce_cpu;
-	ptr[0] = 0xc0008900;
-	ptr[1] = 0;
-	ptr[2] = 0xc0008400;
-	ptr[3] = 1;
+	if (family_id != AMDGPU_FAMILY_SI) {
+		ptr[i++] = 0xc0008900;
+		ptr[i++] = 0;
+	}
+	ptr[i++] = 0xc0008400;
+	ptr[i++] = 1;
 	ib_info[0].ib_mc_address = ib_result_ce_mc_address;
-	ib_info[0].size = 4;
+	ib_info[0].size = i;
 	ib_info[0].flags = AMDGPU_IB_FLAG_CE;
 
 	/* IT_WAIT_ON_CE_COUNTER */
@@ -388,7 +500,7 @@
 	uint32_t expired;
 	amdgpu_bo_list_handle bo_list;
 	amdgpu_va_handle va_handle;
-	int r;
+	int r, i = 0;
 
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	CU_ASSERT_EQUAL(r, 0);
@@ -407,12 +519,14 @@
 
 	/* IT_SET_CE_DE_COUNTERS */
 	ptr = ib_result_cpu;
-	ptr[0] = 0xc0008900;
-	ptr[1] = 0;
-	ptr[2] = 0xc0008400;
-	ptr[3] = 1;
+	if (family_id != AMDGPU_FAMILY_SI) {
+		ptr[i++] = 0xc0008900;
+		ptr[i++] = 0;
+	}
+	ptr[i++] = 0xc0008400;
+	ptr[i++] = 1;
 	ib_info[0].ib_mc_address = ib_result_mc_address;
-	ib_info[0].size = 4;
+	ib_info[0].size = i;
 	ib_info[0].flags = AMDGPU_IB_FLAG_CE;
 
 	ptr = (uint32_t *)ib_result_cpu + 4;
@@ -467,6 +581,156 @@
 	amdgpu_command_submission_copy_linear_helper(AMDGPU_HW_IP_GFX);
 }
 
+static void amdgpu_bo_eviction_test(void)
+{
+	const int sdma_write_length = 1024;
+	const int pm4_dw = 256;
+	amdgpu_context_handle context_handle;
+	amdgpu_bo_handle bo1, bo2, vram_max[2], gtt_max[2];
+	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[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC};
+	amdgpu_va_handle bo1_va_handle, bo2_va_handle;
+	struct amdgpu_heap_info vram_info, gtt_info;
+
+	pm4 = calloc(pm4_dw, sizeof(*pm4));
+	CU_ASSERT_NOT_EQUAL(pm4, NULL);
+
+	ib_info = calloc(1, sizeof(*ib_info));
+	CU_ASSERT_NOT_EQUAL(ib_info, NULL);
+
+	ibs_request = calloc(1, sizeof(*ibs_request));
+	CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
+
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	/* prepare resource */
+	resources = calloc(4, sizeof(amdgpu_bo_handle));
+	CU_ASSERT_NOT_EQUAL(resources, NULL);
+
+	r = amdgpu_query_heap_info(device_handle, AMDGPU_GEM_DOMAIN_VRAM,
+				   0, &vram_info);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_alloc_wrap(device_handle, vram_info.max_allocation, 4096,
+				 AMDGPU_GEM_DOMAIN_VRAM, 0, &vram_max[0]);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_bo_alloc_wrap(device_handle, vram_info.max_allocation, 4096,
+				 AMDGPU_GEM_DOMAIN_VRAM, 0, &vram_max[1]);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_query_heap_info(device_handle, AMDGPU_GEM_DOMAIN_GTT,
+				   0, &gtt_info);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_alloc_wrap(device_handle, gtt_info.max_allocation, 4096,
+				 AMDGPU_GEM_DOMAIN_GTT, 0, &gtt_max[0]);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_bo_alloc_wrap(device_handle, gtt_info.max_allocation, 4096,
+				 AMDGPU_GEM_DOMAIN_GTT, 0, &gtt_max[1]);
+	CU_ASSERT_EQUAL(r, 0);
+
+
+
+	loop1 = loop2 = 0;
+	/* run 9 circle to test all mapping combination */
+	while(loop1 < 2) {
+		while(loop2 < 2) {
+			/* allocate UC bo1for sDMA use */
+			r = amdgpu_bo_alloc_and_map(device_handle,
+						    sdma_write_length, 4096,
+						    AMDGPU_GEM_DOMAIN_GTT,
+						    gtt_flags[loop1], &bo1,
+						    (void**)&bo1_cpu, &bo1_mc,
+						    &bo1_va_handle);
+			CU_ASSERT_EQUAL(r, 0);
+
+			/* set bo1 */
+			memset((void*)bo1_cpu, 0xaa, sdma_write_length);
+
+			/* allocate UC bo2 for sDMA use */
+			r = amdgpu_bo_alloc_and_map(device_handle,
+						    sdma_write_length, 4096,
+						    AMDGPU_GEM_DOMAIN_GTT,
+						    gtt_flags[loop2], &bo2,
+						    (void**)&bo2_cpu, &bo2_mc,
+						    &bo2_va_handle);
+			CU_ASSERT_EQUAL(r, 0);
+
+			/* clear bo2 */
+			memset((void*)bo2_cpu, 0, sdma_write_length);
+
+			resources[0] = bo1;
+			resources[1] = bo2;
+			resources[2] = vram_max[loop2];
+			resources[3] = gtt_max[loop2];
+
+			/* fulfill PM4: test DMA copy linear */
+			i = j = 0;
+			if (family_id == AMDGPU_FAMILY_SI) {
+				pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI, 0, 0, 0,
+							  sdma_write_length);
+				pm4[i++] = 0xffffffff & bo2_mc;
+				pm4[i++] = 0xffffffff & bo1_mc;
+				pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+				pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
+			} else {
+				pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0);
+				if (family_id >= AMDGPU_FAMILY_AI)
+					pm4[i++] = sdma_write_length - 1;
+				else
+					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_test_exec_cs_helper(context_handle,
+						   AMDGPU_HW_IP_DMA, 0,
+						   i, pm4,
+						   4, 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);
+			}
+			r = amdgpu_bo_unmap_and_free(bo1, bo1_va_handle, bo1_mc,
+						     sdma_write_length);
+			CU_ASSERT_EQUAL(r, 0);
+			r = amdgpu_bo_unmap_and_free(bo2, bo2_va_handle, bo2_mc,
+						     sdma_write_length);
+			CU_ASSERT_EQUAL(r, 0);
+			loop2++;
+		}
+		loop2 = 0;
+		loop1++;
+	}
+	amdgpu_bo_free(vram_max[0]);
+	amdgpu_bo_free(vram_max[1]);
+	amdgpu_bo_free(gtt_max[0]);
+	amdgpu_bo_free(gtt_max[1]);
+	/* clean resources */
+	free(resources);
+	free(ibs_request);
+	free(ib_info);
+	free(pm4);
+
+	/* end of test */
+	r = amdgpu_cs_ctx_free(context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+
 static void amdgpu_command_submission_gfx(void)
 {
 	/* write data using the CP */
@@ -493,10 +757,19 @@
 	struct amdgpu_cs_fence fence_status = {0};
 	uint32_t *ptr;
 	uint32_t expired;
+	uint32_t sdma_nop, gfx_nop;
 	amdgpu_bo_list_handle bo_list[2];
 	amdgpu_va_handle va_handle[2];
 	int r, i;
 
+	if (family_id == AMDGPU_FAMILY_SI) {
+		sdma_nop = SDMA_PACKET_SI(SDMA_NOP_SI, 0, 0, 0, 0);
+		gfx_nop = GFX_COMPUTE_NOP_SI;
+	} else {
+		sdma_nop = SDMA_PKT_HEADER_OP(SDMA_NOP);
+		gfx_nop = GFX_COMPUTE_NOP;
+	}
+
 	r = amdgpu_cs_create_semaphore(&sem);
 	CU_ASSERT_EQUAL(r, 0);
 	for (i = 0; i < 2; i++) {
@@ -516,7 +789,7 @@
 
 	/* 1. same context different engine */
 	ptr = ib_result_cpu[0];
-	ptr[0] = SDMA_NOP;
+	ptr[0] = sdma_nop;
 	ib_info[0].ib_mc_address = ib_result_mc_address[0];
 	ib_info[0].size = 1;
 
@@ -533,7 +806,7 @@
 	r = amdgpu_cs_wait_semaphore(context_handle[0], AMDGPU_HW_IP_GFX, 0, 0, sem);
 	CU_ASSERT_EQUAL(r, 0);
 	ptr = ib_result_cpu[1];
-	ptr[0] = GFX_COMPUTE_NOP;
+	ptr[0] = gfx_nop;
 	ib_info[1].ib_mc_address = ib_result_mc_address[1];
 	ib_info[1].size = 1;
 
@@ -557,7 +830,7 @@
 
 	/* 2. same engine different context */
 	ptr = ib_result_cpu[0];
-	ptr[0] = GFX_COMPUTE_NOP;
+	ptr[0] = gfx_nop;
 	ib_info[0].ib_mc_address = ib_result_mc_address[0];
 	ib_info[0].size = 1;
 
@@ -574,7 +847,7 @@
 	r = amdgpu_cs_wait_semaphore(context_handle[1], AMDGPU_HW_IP_GFX, 0, 0, sem);
 	CU_ASSERT_EQUAL(r, 0);
 	ptr = ib_result_cpu[1];
-	ptr[0] = GFX_COMPUTE_NOP;
+	ptr[0] = gfx_nop;
 	ib_info[1].ib_mc_address = ib_result_mc_address[1];
 	ib_info[1].size = 1;
 
@@ -595,6 +868,7 @@
 					 500000000, 0, &expired);
 	CU_ASSERT_EQUAL(r, 0);
 	CU_ASSERT_EQUAL(expired, true);
+
 	for (i = 0; i < 2; i++) {
 		r = amdgpu_bo_unmap_and_free(ib_result_handle[i], va_handle[i],
 					     ib_result_mc_address[i], 4096);
@@ -622,14 +896,18 @@
 	struct amdgpu_cs_fence fence_status;
 	uint32_t *ptr;
 	uint32_t expired;
-	int i, r, instance;
+	int r, instance;
 	amdgpu_bo_list_handle bo_list;
 	amdgpu_va_handle va_handle;
+	struct drm_amdgpu_info_hw_ip info;
+
+	r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_COMPUTE, 0, &info);
+	CU_ASSERT_EQUAL(r, 0);
 
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	CU_ASSERT_EQUAL(r, 0);
 
-	for (instance = 0; instance < 8; instance++) {
+	for (instance = 0; (1 << instance) & info.available_rings; instance++) {
 		r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096,
 					    AMDGPU_GEM_DOMAIN_GTT, 0,
 					    &ib_result_handle, &ib_result_cpu,
@@ -641,8 +919,8 @@
 		CU_ASSERT_EQUAL(r, 0);
 
 		ptr = ib_result_cpu;
-		for (i = 0; i < 16; ++i)
-			ptr[i] = 0xffff1000;
+		memset(ptr, 0, 16);
+		ptr[0]=PACKET3(PACKET3_NOP, 14);
 
 		memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info));
 		ib_info.ib_mc_address = ib_result_mc_address;
@@ -805,9 +1083,10 @@
 	struct amdgpu_cs_request *ibs_request;
 	uint64_t bo_mc;
 	volatile uint32_t *bo_cpu;
-	int i, j, r, loop;
+	int i, j, r, loop, ring_id;
 	uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC};
 	amdgpu_va_handle va_handle;
+	struct drm_amdgpu_info_hw_ip hw_ip_info;
 
 	pm4 = calloc(pm4_dw, sizeof(*pm4));
 	CU_ASSERT_NOT_EQUAL(pm4, NULL);
@@ -818,6 +1097,9 @@
 	ibs_request = calloc(1, sizeof(*ibs_request));
 	CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
 
+	r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &hw_ip_info);
+	CU_ASSERT_EQUAL(r, 0);
+
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	CU_ASSERT_EQUAL(r, 0);
 
@@ -825,58 +1107,66 @@
 	resources = calloc(1, sizeof(amdgpu_bo_handle));
 	CU_ASSERT_NOT_EQUAL(resources, NULL);
 
-	loop = 0;
-	while(loop < 2) {
-		/* allocate UC bo for sDMA use */
-		r = amdgpu_bo_alloc_and_map(device_handle,
-					    sdma_write_length * sizeof(uint32_t),
-					    4096, AMDGPU_GEM_DOMAIN_GTT,
-					    gtt_flags[loop], &bo, (void**)&bo_cpu,
-					    &bo_mc, &va_handle);
-		CU_ASSERT_EQUAL(r, 0);
+	for (ring_id = 0; (1 << ring_id) & hw_ip_info.available_rings; ring_id++) {
+		loop = 0;
+		while(loop < 2) {
+			/* allocate UC bo for sDMA use */
+			r = amdgpu_bo_alloc_and_map(device_handle,
+						    sdma_write_length * sizeof(uint32_t),
+						    4096, AMDGPU_GEM_DOMAIN_GTT,
+						    gtt_flags[loop], &bo, (void**)&bo_cpu,
+						    &bo_mc, &va_handle);
+			CU_ASSERT_EQUAL(r, 0);
 
-		/* clear bo */
-		memset((void*)bo_cpu, 0, sdma_write_length * sizeof(uint32_t));
+			/* clear bo */
+			memset((void*)bo_cpu, 0, sdma_write_length * sizeof(uint32_t));
 
+			resources[0] = bo;
 
-		resources[0] = bo;
+			/* fulfill PM4: test DMA write-linear */
+			i = j = 0;
+			if (ip_type == AMDGPU_HW_IP_DMA) {
+				if (family_id == AMDGPU_FAMILY_SI)
+					pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_WRITE, 0, 0, 0,
+								  sdma_write_length);
+				else
+					pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
+							       SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+				pm4[i++] = 0xffffffff & bo_mc;
+				pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+				if (family_id >= AMDGPU_FAMILY_AI)
+					pm4[i++] = sdma_write_length - 1;
+				else if (family_id != AMDGPU_FAMILY_SI)
+					pm4[i++] = sdma_write_length;
+				while(j++ < sdma_write_length)
+					pm4[i++] = 0xdeadbeaf;
+			} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
+				    (ip_type == AMDGPU_HW_IP_COMPUTE)) {
+				pm4[i++] = PACKET3(PACKET3_WRITE_DATA, 2 + sdma_write_length);
+				pm4[i++] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
+				pm4[i++] = 0xfffffffc & bo_mc;
+				pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+				while(j++ < sdma_write_length)
+					pm4[i++] = 0xdeadbeaf;
+			}
 
-		/* fulfill PM4: test DMA write-linear */
-		i = j = 0;
-		if (ip_type == AMDGPU_HW_IP_DMA) {
-			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;
-		} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
-			   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
-			pm4[i++] = PACKET3(PACKET3_WRITE_DATA, 2 + sdma_write_length);
-			pm4[i++] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
-			pm4[i++] = 0xfffffffc & bo_mc;
-			pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
-			while(j++ < sdma_write_length)
-				pm4[i++] = 0xdeadbeaf;
+			amdgpu_test_exec_cs_helper(context_handle,
+						   ip_type, ring_id,
+						   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);
+			}
+
+			r = amdgpu_bo_unmap_and_free(bo, va_handle, bo_mc,
+						     sdma_write_length * sizeof(uint32_t));
+			CU_ASSERT_EQUAL(r, 0);
+			loop++;
 		}
-
-		amdgpu_test_exec_cs_helper(context_handle,
-					   ip_type, 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);
-		}
-
-		r = amdgpu_bo_unmap_and_free(bo, va_handle, bo_mc,
-					     sdma_write_length * sizeof(uint32_t));
-		CU_ASSERT_EQUAL(r, 0);
-		loop++;
 	}
 	/* clean resources */
 	free(resources);
@@ -906,9 +1196,10 @@
 	struct amdgpu_cs_request *ibs_request;
 	uint64_t bo_mc;
 	volatile uint32_t *bo_cpu;
-	int i, j, r, loop;
+	int i, j, r, loop, ring_id;
 	uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC};
 	amdgpu_va_handle va_handle;
+	struct drm_amdgpu_info_hw_ip hw_ip_info;
 
 	pm4 = calloc(pm4_dw, sizeof(*pm4));
 	CU_ASSERT_NOT_EQUAL(pm4, NULL);
@@ -919,6 +1210,9 @@
 	ibs_request = calloc(1, sizeof(*ibs_request));
 	CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
 
+	r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &hw_ip_info);
+	CU_ASSERT_EQUAL(r, 0);
+
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	CU_ASSERT_EQUAL(r, 0);
 
@@ -926,60 +1220,86 @@
 	resources = calloc(1, sizeof(amdgpu_bo_handle));
 	CU_ASSERT_NOT_EQUAL(resources, NULL);
 
-	loop = 0;
-	while(loop < 2) {
-		/* allocate UC bo for sDMA use */
-		r = amdgpu_bo_alloc_and_map(device_handle,
-					    sdma_write_length, 4096,
-					    AMDGPU_GEM_DOMAIN_GTT,
-					    gtt_flags[loop], &bo, (void**)&bo_cpu,
-					    &bo_mc, &va_handle);
-		CU_ASSERT_EQUAL(r, 0);
+	for (ring_id = 0; (1 << ring_id) & hw_ip_info.available_rings; ring_id++) {
+		loop = 0;
+		while(loop < 2) {
+			/* allocate UC bo for sDMA use */
+			r = amdgpu_bo_alloc_and_map(device_handle,
+						    sdma_write_length, 4096,
+						    AMDGPU_GEM_DOMAIN_GTT,
+						    gtt_flags[loop], &bo, (void**)&bo_cpu,
+						    &bo_mc, &va_handle);
+			CU_ASSERT_EQUAL(r, 0);
 
-		/* clear bo */
-		memset((void*)bo_cpu, 0, sdma_write_length);
+			/* clear bo */
+			memset((void*)bo_cpu, 0, sdma_write_length);
 
-		resources[0] = bo;
+			resources[0] = bo;
 
-		/* fulfill PM4: test DMA const fill */
-		i = j = 0;
-		if (ip_type == AMDGPU_HW_IP_DMA) {
-			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;
-		} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
-			   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
-			pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5);
-			pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) |
-				PACKET3_DMA_DATA_DST_SEL(0) |
-				PACKET3_DMA_DATA_SRC_SEL(2) |
-				PACKET3_DMA_DATA_CP_SYNC;
-			pm4[i++] = 0xdeadbeaf;
-			pm4[i++] = 0;
-			pm4[i++] = 0xfffffffc & bo_mc;
-			pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
-			pm4[i++] = sdma_write_length;
+			/* fulfill PM4: test DMA const fill */
+			i = j = 0;
+			if (ip_type == AMDGPU_HW_IP_DMA) {
+				if (family_id == AMDGPU_FAMILY_SI) {
+					pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_CONSTANT_FILL_SI,
+								  0, 0, 0,
+								  sdma_write_length / 4);
+					pm4[i++] = 0xfffffffc & bo_mc;
+					pm4[i++] = 0xdeadbeaf;
+					pm4[i++] = (0xffffffff00000000 & bo_mc) >> 16;
+				} else {
+					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;
+					if (family_id >= AMDGPU_FAMILY_AI)
+						pm4[i++] = sdma_write_length - 1;
+					else
+						pm4[i++] = sdma_write_length;
+				}
+			} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
+				   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
+				if (family_id == AMDGPU_FAMILY_SI) {
+					pm4[i++] = PACKET3(PACKET3_DMA_DATA_SI, 4);
+					pm4[i++] = 0xdeadbeaf;
+					pm4[i++] = PACKET3_DMA_DATA_SI_ENGINE(0) |
+						   PACKET3_DMA_DATA_SI_DST_SEL(0) |
+						   PACKET3_DMA_DATA_SI_SRC_SEL(2) |
+						   PACKET3_DMA_DATA_SI_CP_SYNC;
+					pm4[i++] = 0xffffffff & bo_mc;
+					pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+					pm4[i++] = sdma_write_length;
+				} else {
+					pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5);
+					pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) |
+						   PACKET3_DMA_DATA_DST_SEL(0) |
+						   PACKET3_DMA_DATA_SRC_SEL(2) |
+						   PACKET3_DMA_DATA_CP_SYNC;
+					pm4[i++] = 0xdeadbeaf;
+					pm4[i++] = 0;
+					pm4[i++] = 0xfffffffc & bo_mc;
+					pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+					pm4[i++] = sdma_write_length;
+				}
+			}
+
+			amdgpu_test_exec_cs_helper(context_handle,
+						   ip_type, ring_id,
+						   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);
+			}
+
+			r = amdgpu_bo_unmap_and_free(bo, va_handle, bo_mc,
+						     sdma_write_length);
+			CU_ASSERT_EQUAL(r, 0);
+			loop++;
 		}
-
-		amdgpu_test_exec_cs_helper(context_handle,
-					   ip_type, 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);
-		}
-
-		r = amdgpu_bo_unmap_and_free(bo, va_handle, bo_mc,
-					     sdma_write_length);
-		CU_ASSERT_EQUAL(r, 0);
-		loop++;
 	}
 	/* clean resources */
 	free(resources);
@@ -1009,9 +1329,10 @@
 	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;
+	int i, j, r, loop1, loop2, ring_id;
 	uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC};
 	amdgpu_va_handle bo1_va_handle, bo2_va_handle;
+	struct drm_amdgpu_info_hw_ip hw_ip_info;
 
 	pm4 = calloc(pm4_dw, sizeof(*pm4));
 	CU_ASSERT_NOT_EQUAL(pm4, NULL);
@@ -1022,6 +1343,9 @@
 	ibs_request = calloc(1, sizeof(*ibs_request));
 	CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
 
+	r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &hw_ip_info);
+	CU_ASSERT_EQUAL(r, 0);
+
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	CU_ASSERT_EQUAL(r, 0);
 
@@ -1029,81 +1353,111 @@
 	resources = calloc(2, sizeof(amdgpu_bo_handle));
 	CU_ASSERT_NOT_EQUAL(resources, NULL);
 
-	loop1 = loop2 = 0;
-	/* run 9 circle to test all mapping combination */
-	while(loop1 < 2) {
-		while(loop2 < 2) {
-			/* allocate UC bo1for sDMA use */
-			r = amdgpu_bo_alloc_and_map(device_handle,
-						    sdma_write_length, 4096,
-						    AMDGPU_GEM_DOMAIN_GTT,
-						    gtt_flags[loop1], &bo1,
-						    (void**)&bo1_cpu, &bo1_mc,
-						    &bo1_va_handle);
-			CU_ASSERT_EQUAL(r, 0);
+	for (ring_id = 0; (1 << ring_id) & hw_ip_info.available_rings; ring_id++) {
+		loop1 = loop2 = 0;
+		/* run 9 circle to test all mapping combination */
+		while(loop1 < 2) {
+			while(loop2 < 2) {
+				/* allocate UC bo1for sDMA use */
+				r = amdgpu_bo_alloc_and_map(device_handle,
+							    sdma_write_length, 4096,
+							    AMDGPU_GEM_DOMAIN_GTT,
+							    gtt_flags[loop1], &bo1,
+							    (void**)&bo1_cpu, &bo1_mc,
+							    &bo1_va_handle);
+				CU_ASSERT_EQUAL(r, 0);
 
-			/* set bo1 */
-			memset((void*)bo1_cpu, 0xaa, sdma_write_length);
+				/* set bo1 */
+				memset((void*)bo1_cpu, 0xaa, sdma_write_length);
 
-			/* allocate UC bo2 for sDMA use */
-			r = amdgpu_bo_alloc_and_map(device_handle,
-						    sdma_write_length, 4096,
-						    AMDGPU_GEM_DOMAIN_GTT,
-						    gtt_flags[loop2], &bo2,
-						    (void**)&bo2_cpu, &bo2_mc,
-						    &bo2_va_handle);
-			CU_ASSERT_EQUAL(r, 0);
+				/* allocate UC bo2 for sDMA use */
+				r = amdgpu_bo_alloc_and_map(device_handle,
+							    sdma_write_length, 4096,
+							    AMDGPU_GEM_DOMAIN_GTT,
+							    gtt_flags[loop2], &bo2,
+							    (void**)&bo2_cpu, &bo2_mc,
+							    &bo2_va_handle);
+				CU_ASSERT_EQUAL(r, 0);
 
-			/* clear bo2 */
-			memset((void*)bo2_cpu, 0, sdma_write_length);
+				/* clear bo2 */
+				memset((void*)bo2_cpu, 0, sdma_write_length);
 
-			resources[0] = bo1;
-			resources[1] = bo2;
+				resources[0] = bo1;
+				resources[1] = bo2;
 
-			/* fulfill PM4: test DMA copy linear */
-			i = j = 0;
-			if (ip_type == AMDGPU_HW_IP_DMA) {
-				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;
-			} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
-				   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
-				pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5);
-				pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) |
-					PACKET3_DMA_DATA_DST_SEL(0) |
-					PACKET3_DMA_DATA_SRC_SEL(0) |
-					PACKET3_DMA_DATA_CP_SYNC;
-				pm4[i++] = 0xfffffffc & bo1_mc;
-				pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
-				pm4[i++] = 0xfffffffc & bo2_mc;
-				pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
-				pm4[i++] = sdma_write_length;
+				/* fulfill PM4: test DMA copy linear */
+				i = j = 0;
+				if (ip_type == AMDGPU_HW_IP_DMA) {
+					if (family_id == AMDGPU_FAMILY_SI) {
+						pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI,
+									  0, 0, 0,
+									  sdma_write_length);
+						pm4[i++] = 0xffffffff & bo2_mc;
+						pm4[i++] = 0xffffffff & bo1_mc;
+						pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+						pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
+					} else {
+						pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY,
+								       SDMA_COPY_SUB_OPCODE_LINEAR,
+								       0);
+						if (family_id >= AMDGPU_FAMILY_AI)
+							pm4[i++] = sdma_write_length - 1;
+						else
+							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;
+					}
+				} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
+					   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
+					if (family_id == AMDGPU_FAMILY_SI) {
+						pm4[i++] = PACKET3(PACKET3_DMA_DATA_SI, 4);
+						pm4[i++] = 0xfffffffc & bo1_mc;
+						pm4[i++] = PACKET3_DMA_DATA_SI_ENGINE(0) |
+							   PACKET3_DMA_DATA_SI_DST_SEL(0) |
+							   PACKET3_DMA_DATA_SI_SRC_SEL(0) |
+							   PACKET3_DMA_DATA_SI_CP_SYNC |
+							   (0xffff00000000 & bo1_mc) >> 32;
+						pm4[i++] = 0xfffffffc & bo2_mc;
+						pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+						pm4[i++] = sdma_write_length;
+					} else {
+						pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5);
+						pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) |
+							   PACKET3_DMA_DATA_DST_SEL(0) |
+							   PACKET3_DMA_DATA_SRC_SEL(0) |
+							   PACKET3_DMA_DATA_CP_SYNC;
+						pm4[i++] = 0xfffffffc & bo1_mc;
+						pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
+						pm4[i++] = 0xfffffffc & bo2_mc;
+						pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+						pm4[i++] = sdma_write_length;
+					}
+				}
+
+				amdgpu_test_exec_cs_helper(context_handle,
+							   ip_type, ring_id,
+							   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);
+				}
+				r = amdgpu_bo_unmap_and_free(bo1, bo1_va_handle, bo1_mc,
+							     sdma_write_length);
+				CU_ASSERT_EQUAL(r, 0);
+				r = amdgpu_bo_unmap_and_free(bo2, bo2_va_handle, bo2_mc,
+							     sdma_write_length);
+				CU_ASSERT_EQUAL(r, 0);
+				loop2++;
 			}
-
-			amdgpu_test_exec_cs_helper(context_handle,
-						   ip_type, 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);
-			}
-			r = amdgpu_bo_unmap_and_free(bo1, bo1_va_handle, bo1_mc,
-						     sdma_write_length);
-			CU_ASSERT_EQUAL(r, 0);
-			r = amdgpu_bo_unmap_and_free(bo2, bo2_va_handle, bo2_mc,
-						     sdma_write_length);
-			CU_ASSERT_EQUAL(r, 0);
-			loop2++;
+			loop1++;
 		}
-		loop1++;
 	}
 	/* clean resources */
 	free(resources);
@@ -1128,6 +1482,106 @@
 	amdgpu_command_submission_sdma_copy_linear();
 }
 
+static void amdgpu_command_submission_multi_fence_wait_all(bool wait_all)
+{
+	amdgpu_context_handle context_handle;
+	amdgpu_bo_handle ib_result_handle, ib_result_ce_handle;
+	void *ib_result_cpu, *ib_result_ce_cpu;
+	uint64_t ib_result_mc_address, ib_result_ce_mc_address;
+	struct amdgpu_cs_request ibs_request[2] = {0};
+	struct amdgpu_cs_ib_info ib_info[2];
+	struct amdgpu_cs_fence fence_status[2] = {0};
+	uint32_t *ptr;
+	uint32_t expired;
+	amdgpu_bo_list_handle bo_list;
+	amdgpu_va_handle va_handle, va_handle_ce;
+	int r;
+	int i = 0, ib_cs_num = 2;
+
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096,
+				    AMDGPU_GEM_DOMAIN_GTT, 0,
+				    &ib_result_handle, &ib_result_cpu,
+				    &ib_result_mc_address, &va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096,
+				    AMDGPU_GEM_DOMAIN_GTT, 0,
+				    &ib_result_ce_handle, &ib_result_ce_cpu,
+				    &ib_result_ce_mc_address, &va_handle_ce);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_get_bo_list(device_handle, ib_result_handle,
+			       ib_result_ce_handle, &bo_list);
+	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;
+	if (family_id != AMDGPU_FAMILY_SI) {
+		ptr[i++] = 0xc0008900;
+		ptr[i++] = 0;
+	}
+	ptr[i++] = 0xc0008400;
+	ptr[i++] = 1;
+	ib_info[0].ib_mc_address = ib_result_ce_mc_address;
+	ib_info[0].size = i;
+	ib_info[0].flags = AMDGPU_IB_FLAG_CE;
+
+	/* IT_WAIT_ON_CE_COUNTER */
+	ptr = ib_result_cpu;
+	ptr[0] = 0xc0008600;
+	ptr[1] = 0x00000001;
+	ib_info[1].ib_mc_address = ib_result_mc_address;
+	ib_info[1].size = 2;
+
+	for (i = 0; i < ib_cs_num; i++) {
+		ibs_request[i].ip_type = AMDGPU_HW_IP_GFX;
+		ibs_request[i].number_of_ibs = 2;
+		ibs_request[i].ibs = ib_info;
+		ibs_request[i].resources = bo_list;
+		ibs_request[i].fence_info.handle = NULL;
+	}
+
+	r = amdgpu_cs_submit(context_handle, 0,ibs_request, ib_cs_num);
+
+	CU_ASSERT_EQUAL(r, 0);
+
+	for (i = 0; i < ib_cs_num; i++) {
+		fence_status[i].context = context_handle;
+		fence_status[i].ip_type = AMDGPU_HW_IP_GFX;
+		fence_status[i].fence = ibs_request[i].seq_no;
+	}
+
+	r = amdgpu_cs_wait_fences(fence_status, ib_cs_num, wait_all,
+				AMDGPU_TIMEOUT_INFINITE,
+				&expired, NULL);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle,
+				     ib_result_mc_address, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_unmap_and_free(ib_result_ce_handle, va_handle_ce,
+				     ib_result_ce_mc_address, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_list_destroy(bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_cs_ctx_free(context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_command_submission_multi_fence(void)
+{
+	amdgpu_command_submission_multi_fence_wait_all(true);
+	amdgpu_command_submission_multi_fence_wait_all(false);
+}
+
 static void amdgpu_userptr_test(void)
 {
 	int i, r, j;
@@ -1175,15 +1629,28 @@
 	handle = buf_handle;
 
 	j = i = 0;
-	pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
-			       SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+
+	if (family_id == AMDGPU_FAMILY_SI)
+		pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_WRITE, 0, 0, 0,
+				sdma_write_length);
+	else
+		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;
+	if (family_id >= AMDGPU_FAMILY_AI)
+		pm4[i++] = sdma_write_length - 1;
+	else if (family_id != AMDGPU_FAMILY_SI)
+		pm4[i++] = sdma_write_length;
 
 	while (j++ < sdma_write_length)
 		pm4[i++] = 0xdeadbeaf;
 
+	if (!fork()) {
+		pm4[0] = 0x0;
+		exit(0);
+	}
+
 	amdgpu_test_exec_cs_helper(context_handle,
 				   AMDGPU_HW_IP_DMA, 0,
 				   i, pm4,
@@ -1207,4 +1674,212 @@
 
 	r = amdgpu_cs_ctx_free(context_handle);
 	CU_ASSERT_EQUAL(r, 0);
+
+	wait(NULL);
+}
+
+static void amdgpu_sync_dependency_test(void)
+{
+	amdgpu_context_handle context_handle[2];
+	amdgpu_bo_handle ib_result_handle;
+	void *ib_result_cpu;
+	uint64_t ib_result_mc_address;
+	struct amdgpu_cs_request ibs_request;
+	struct amdgpu_cs_ib_info ib_info;
+	struct amdgpu_cs_fence fence_status;
+	uint32_t expired;
+	int i, j, r;
+	amdgpu_bo_list_handle bo_list;
+	amdgpu_va_handle va_handle;
+	static uint32_t *ptr;
+	uint64_t seq_no;
+
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle[0]);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle[1]);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_alloc_and_map(device_handle, 8192, 4096,
+			AMDGPU_GEM_DOMAIN_GTT, 0,
+						    &ib_result_handle, &ib_result_cpu,
+						    &ib_result_mc_address, &va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL,
+			       &bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	ptr = ib_result_cpu;
+	i = 0;
+
+	memcpy(ptr + CODE_OFFSET , shader_bin, sizeof(shader_bin));
+
+	/* Dispatch minimal init config and verify it's executed */
+	ptr[i++] = PACKET3(PKT3_CONTEXT_CONTROL, 1);
+	ptr[i++] = 0x80000000;
+	ptr[i++] = 0x80000000;
+
+	ptr[i++] = PACKET3(PKT3_CLEAR_STATE, 0);
+	ptr[i++] = 0x80000000;
+
+
+	/* Program compute regs */
+	ptr[i++] = PACKET3(PKT3_SET_SH_REG, 2);
+	ptr[i++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START;
+	ptr[i++] = (ib_result_mc_address + CODE_OFFSET * 4) >> 8;
+	ptr[i++] = (ib_result_mc_address + CODE_OFFSET * 4) >> 40;
+
+
+	ptr[i++] = PACKET3(PKT3_SET_SH_REG, 2);
+	ptr[i++] = mmCOMPUTE_PGM_RSRC1 - PACKET3_SET_SH_REG_START;
+	/*
+	 * 002c0040         COMPUTE_PGM_RSRC1 <- VGPRS = 0
+	                                      SGPRS = 1
+	                                      PRIORITY = 0
+	                                      FLOAT_MODE = 192 (0xc0)
+	                                      PRIV = 0
+	                                      DX10_CLAMP = 1
+	                                      DEBUG_MODE = 0
+	                                      IEEE_MODE = 0
+	                                      BULKY = 0
+	                                      CDBG_USER = 0
+	 *
+	 */
+	ptr[i++] = 0x002c0040;
+
+
+	/*
+	 * 00000010         COMPUTE_PGM_RSRC2 <- SCRATCH_EN = 0
+	                                      USER_SGPR = 8
+	                                      TRAP_PRESENT = 0
+	                                      TGID_X_EN = 0
+	                                      TGID_Y_EN = 0
+	                                      TGID_Z_EN = 0
+	                                      TG_SIZE_EN = 0
+	                                      TIDIG_COMP_CNT = 0
+	                                      EXCP_EN_MSB = 0
+	                                      LDS_SIZE = 0
+	                                      EXCP_EN = 0
+	 *
+	 */
+	ptr[i++] = 0x00000010;
+
+
+/*
+ * 00000100         COMPUTE_TMPRING_SIZE <- WAVES = 256 (0x100)
+                                         WAVESIZE = 0
+ *
+ */
+	ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1);
+	ptr[i++] = mmCOMPUTE_TMPRING_SIZE - PACKET3_SET_SH_REG_START;
+	ptr[i++] = 0x00000100;
+
+	ptr[i++] = PACKET3(PKT3_SET_SH_REG, 2);
+	ptr[i++] = mmCOMPUTE_USER_DATA_0 - PACKET3_SET_SH_REG_START;
+	ptr[i++] = 0xffffffff & (ib_result_mc_address + DATA_OFFSET * 4);
+	ptr[i++] = (0xffffffff00000000 & (ib_result_mc_address + DATA_OFFSET * 4)) >> 32;
+
+	ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1);
+	ptr[i++] = mmCOMPUTE_RESOURCE_LIMITS - PACKET3_SET_SH_REG_START;
+	ptr[i++] = 0;
+
+	ptr[i++] = PACKET3(PKT3_SET_SH_REG, 3);
+	ptr[i++] = mmCOMPUTE_NUM_THREAD_X - PACKET3_SET_SH_REG_START;
+	ptr[i++] = 1;
+	ptr[i++] = 1;
+	ptr[i++] = 1;
+
+
+	/* Dispatch */
+	ptr[i++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3);
+	ptr[i++] = 1;
+	ptr[i++] = 1;
+	ptr[i++] = 1;
+	ptr[i++] = 0x00000045; /* DISPATCH DIRECT field */
+
+
+	while (i & 7)
+		ptr[i++] =  0xffff1000; /* type3 nop packet */
+
+	memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info));
+	ib_info.ib_mc_address = ib_result_mc_address;
+	ib_info.size = i;
+
+	memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request));
+	ibs_request.ip_type = AMDGPU_HW_IP_GFX;
+	ibs_request.ring = 0;
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.resources = bo_list;
+	ibs_request.fence_info.handle = NULL;
+
+	r = amdgpu_cs_submit(context_handle[1], 0,&ibs_request, 1);
+	CU_ASSERT_EQUAL(r, 0);
+	seq_no = ibs_request.seq_no;
+
+
+
+	/* Prepare second command with dependency on the first */
+	j = i;
+	ptr[i++] = PACKET3(PACKET3_WRITE_DATA, 3);
+	ptr[i++] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
+	ptr[i++] =          0xfffffffc & (ib_result_mc_address + DATA_OFFSET * 4);
+	ptr[i++] = (0xffffffff00000000 & (ib_result_mc_address + DATA_OFFSET * 4)) >> 32;
+	ptr[i++] = 99;
+
+	while (i & 7)
+		ptr[i++] =  0xffff1000; /* type3 nop packet */
+
+	memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info));
+	ib_info.ib_mc_address = ib_result_mc_address + j * 4;
+	ib_info.size = i - j;
+
+	memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request));
+	ibs_request.ip_type = AMDGPU_HW_IP_GFX;
+	ibs_request.ring = 0;
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.resources = bo_list;
+	ibs_request.fence_info.handle = NULL;
+
+	ibs_request.number_of_dependencies = 1;
+
+	ibs_request.dependencies = calloc(1, sizeof(*ibs_request.dependencies));
+	ibs_request.dependencies[0].context = context_handle[1];
+	ibs_request.dependencies[0].ip_instance = 0;
+	ibs_request.dependencies[0].ring = 0;
+	ibs_request.dependencies[0].fence = seq_no;
+
+
+	r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request, 1);
+	CU_ASSERT_EQUAL(r, 0);
+
+
+	memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence));
+	fence_status.context = context_handle[0];
+	fence_status.ip_type = AMDGPU_HW_IP_GFX;
+	fence_status.ip_instance = 0;
+	fence_status.ring = 0;
+	fence_status.fence = ibs_request.seq_no;
+
+	r = amdgpu_cs_query_fence_status(&fence_status,
+		       AMDGPU_TIMEOUT_INFINITE,0, &expired);
+	CU_ASSERT_EQUAL(r, 0);
+
+	/* Expect the second command to wait for shader to complete */
+	CU_ASSERT_EQUAL(ptr[DATA_OFFSET], 99);
+
+	r = amdgpu_bo_list_destroy(bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle,
+				     ib_result_mc_address, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_cs_ctx_free(context_handle[0]);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_cs_ctx_free(context_handle[1]);
+	CU_ASSERT_EQUAL(r, 0);
+
+	free(ibs_request.dependencies);
 }
diff --git a/tests/amdgpu/bo_tests.c b/tests/amdgpu/bo_tests.c
index 74b5e77..7cff4cf 100644
--- a/tests/amdgpu/bo_tests.c
+++ b/tests/amdgpu/bo_tests.c
@@ -21,16 +21,13 @@
  *
 */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdio.h>
 
 #include "CUnit/Basic.h"
 
 #include "amdgpu_test.h"
 #include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
 
 #define BUFFER_SIZE (4*1024)
 #define BUFFER_ALIGN (4*1024)
@@ -46,13 +43,17 @@
 static void amdgpu_bo_export_import(void);
 static void amdgpu_bo_metadata(void);
 static void amdgpu_bo_map_unmap(void);
+static void amdgpu_memory_alloc(void);
+static void amdgpu_mem_fail_alloc(void);
+static void amdgpu_bo_find_by_cpu_mapping(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 },
+	{ "Memory alloc Test",  amdgpu_memory_alloc },
+	{ "Memory fail alloc Test",  amdgpu_mem_fail_alloc },
+	{ "Find bo by CPU mapping",  amdgpu_bo_find_by_cpu_mapping },
 	CU_TEST_INFO_NULL,
 };
 
@@ -195,3 +196,123 @@
 	r = amdgpu_bo_cpu_unmap(buffer_handle);
 	CU_ASSERT_EQUAL(r, 0);
 }
+
+static void amdgpu_memory_alloc(void)
+{
+	amdgpu_bo_handle bo;
+	amdgpu_va_handle va_handle;
+	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, &va_handle);
+
+	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
+	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, &va_handle);
+
+	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	/* Test GART Cacheable */
+	bo = gpu_mem_alloc(device_handle,
+			4096, 4096,
+			AMDGPU_GEM_DOMAIN_GTT,
+			0, &bo_mc, &va_handle);
+
+	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
+	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_USWC,
+			&bo_mc, &va_handle);
+
+	r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	/* Test GDS */
+	bo = gpu_mem_alloc(device_handle, 1024, 0,
+			AMDGPU_GEM_DOMAIN_GDS, 0,
+			NULL, NULL);
+	r = gpu_mem_free(bo, NULL, 0, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	/* Test GWS */
+	bo = gpu_mem_alloc(device_handle, 1, 0,
+			AMDGPU_GEM_DOMAIN_GWS, 0,
+			NULL, NULL);
+	r = gpu_mem_free(bo, NULL, 0, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	/* Test OA */
+	bo = gpu_mem_alloc(device_handle, 1, 0,
+			AMDGPU_GEM_DOMAIN_OA, 0,
+			NULL, NULL);
+	r = gpu_mem_free(bo, NULL, 0, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_mem_fail_alloc(void)
+{
+	amdgpu_bo_handle bo;
+	int r;
+	struct amdgpu_bo_alloc_request req = {0};
+	amdgpu_bo_handle buf_handle;
+
+	/* Test impossible mem allocation, 1TB */
+	req.alloc_size = 0xE8D4A51000;
+	req.phys_alignment = 4096;
+	req.preferred_heap = AMDGPU_GEM_DOMAIN_VRAM;
+	req.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
+
+	r = amdgpu_bo_alloc(device_handle, &req, &buf_handle);
+	CU_ASSERT_EQUAL(r, -ENOMEM);
+
+	if (!r) {
+		r = amdgpu_bo_free(bo);
+		CU_ASSERT_EQUAL(r, 0);
+	}
+}
+
+static void amdgpu_bo_find_by_cpu_mapping(void)
+{
+	amdgpu_bo_handle bo_handle, find_bo_handle;
+	amdgpu_va_handle va_handle;
+	void *bo_cpu;
+	uint64_t bo_mc_address;
+	uint64_t offset;
+	int r;
+
+	r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096,
+				    AMDGPU_GEM_DOMAIN_GTT, 0,
+				    &bo_handle, &bo_cpu,
+				    &bo_mc_address, &va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_find_bo_by_cpu_mapping(device_handle,
+					  bo_cpu,
+					  4096,
+					  &find_bo_handle,
+					  &offset);
+	CU_ASSERT_EQUAL(r, 0);
+	CU_ASSERT_EQUAL(offset, 0);
+	CU_ASSERT_EQUAL(bo_handle->handle, find_bo_handle->handle);
+
+	atomic_dec(&find_bo_handle->refcount, 1);
+	r = amdgpu_bo_unmap_and_free(bo_handle, va_handle,
+				     bo_mc_address, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+}
diff --git a/tests/amdgpu/cs_tests.c b/tests/amdgpu/cs_tests.c
index 82c55aa..7ad0f0d 100644
--- a/tests/amdgpu/cs_tests.c
+++ b/tests/amdgpu/cs_tests.c
@@ -21,10 +21,6 @@
  *
 */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdio.h>
 
 #include "CUnit/Basic.h"
@@ -32,7 +28,7 @@
 #include "util_math.h"
 
 #include "amdgpu_test.h"
-#include "uvd_messages.h"
+#include "decode_messages.h"
 #include "amdgpu_drm.h"
 #include "amdgpu_internal.h"
 
@@ -66,6 +62,26 @@
 	CU_TEST_INFO_NULL,
 };
 
+CU_BOOL suite_cs_tests_enable(void)
+{
+	if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+					     &minor_version, &device_handle))
+		return CU_FALSE;
+
+	family_id = device_handle->info.family_id;
+
+	if (amdgpu_device_deinitialize(device_handle))
+		return CU_FALSE;
+
+
+	if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI) {
+		printf("\n\nThe ASIC NOT support UVD, suite disabled\n");
+		return CU_FALSE;
+	}
+
+	return CU_TRUE;
+}
+
 int suite_cs_tests_init(void)
 {
 	amdgpu_bo_handle ib_result_handle;
@@ -175,11 +191,11 @@
 
 static void uvd_cmd(uint64_t addr, unsigned cmd, int *idx)
 {
-	ib_cpu[(*idx)++] = 0x3BC4;
+	ib_cpu[(*idx)++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC4 : 0x81C4;
 	ib_cpu[(*idx)++] = addr;
-	ib_cpu[(*idx)++] = 0x3BC5;
+	ib_cpu[(*idx)++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC5 : 0x81C5;
 	ib_cpu[(*idx)++] = addr >> 32;
-	ib_cpu[(*idx)++] = 0x3BC3;
+	ib_cpu[(*idx)++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC3 : 0x81C3;
 	ib_cpu[(*idx)++] = cmd << 1;
 }
 
@@ -211,10 +227,13 @@
 	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;
-		/* chip polaris 10/11 */
-		if (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A) {
+		/* chip beyond polaris 10/11 */
+		if ((family_id == AMDGPU_FAMILY_AI) ||
+		    (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A ||
+		     chip_id == chip_rev+0x64)) {
 			/* dpb size */
 			((uint8_t*)msg)[0x28] = 0x00;
 			((uint8_t*)msg)[0x29] = 0x94;
@@ -250,7 +269,7 @@
 
 static void amdgpu_cs_uvd_decode(void)
 {
-	const unsigned dpb_size = 15923584, ctx_size = 5287680, dt_size = 737280;
+	const unsigned dpb_size = 15923584, dt_size = 737280;
 	uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, ctx_addr, dt_addr, it_addr;
 	struct amdgpu_bo_alloc_request req = {0};
 	amdgpu_bo_handle buf_handle;
@@ -286,14 +305,18 @@
 	r = amdgpu_bo_cpu_map(buf_handle, (void **)&ptr);
 	CU_ASSERT_EQUAL(r, 0);
 
-	memcpy(ptr, uvd_decode_msg, sizeof(uvd_create_msg));
+	memcpy(ptr, uvd_decode_msg, sizeof(uvd_decode_msg));
+	memcpy(ptr + sizeof(uvd_decode_msg), avc_decode_msg, sizeof(avc_decode_msg));
+
 	if (family_id >= AMDGPU_FAMILY_VI) {
 		ptr[0x10] = 7;
 		ptr[0x98] = 0x00;
 		ptr[0x99] = 0x02;
-		/* chip polaris10/11 */
-		if (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A) {
-			/*dpb size */
+		/* chip beyond polaris10/11 */
+		if ((family_id == AMDGPU_FAMILY_AI) ||
+		    (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A ||
+		     chip_id == chip_rev+0x64)) {
+			/* dpb size */
 			ptr[0x24] = 0x00;
 			ptr[0x25] = 0x94;
 			ptr[0x26] = 0x6B;
@@ -335,9 +358,12 @@
 		bs_addr = fb_addr + 4*1024;
 	dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024);
 
-	if ((family_id >= AMDGPU_FAMILY_VI) &&
-		(chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A)) {
-		ctx_addr = ALIGN(dpb_addr + 0x006B9400, 4*1024);
+	if (family_id >= AMDGPU_FAMILY_VI) {
+		if ((family_id == AMDGPU_FAMILY_AI) ||
+		    (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A ||
+		     chip_id == chip_rev+0x64)) {
+			ctx_addr = ALIGN(dpb_addr + 0x006B9400, 4*1024);
+		}
 	}
 
 	dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024);
@@ -348,12 +374,16 @@
 	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);
-		if (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A)
+		if ((family_id == AMDGPU_FAMILY_AI) ||
+		    (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A ||
+		     chip_id == chip_rev+0x64))
 			uvd_cmd(ctx_addr, 0x206, &i);
-}
-	ib_cpu[i++] = 0x3BC6;
+	}
+
+	ib_cpu[i++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC6 : 0x81C6;
 	ib_cpu[i++] = 0x1;
 	for (; i % 16; ++i)
 		ib_cpu[i] = 0x80000000;
@@ -364,7 +394,7 @@
 	/* TODO: use a real CRC32 */
 	for (i = 0, sum = 0; i < dt_size; ++i)
 		sum += ptr[i];
-	CU_ASSERT_EQUAL(sum, 0x20345d8);
+	CU_ASSERT_EQUAL(sum, SUM_DECODE);
 
 	r = amdgpu_bo_cpu_unmap(buf_handle);
 	CU_ASSERT_EQUAL(r, 0);
diff --git a/tests/amdgpu/deadlock_tests.c b/tests/amdgpu/deadlock_tests.c
new file mode 100644
index 0000000..a6c2635
--- /dev/null
+++ b/tests/amdgpu/deadlock_tests.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright 2017 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>
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+
+#include "CUnit/Basic.h"
+
+#include "amdgpu_test.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+
+#include <pthread.h>
+
+
+/*
+ * This defines the delay in MS after which memory location designated for
+ * compression against reference value is written to, unblocking command
+ * processor
+ */
+#define WRITE_MEM_ADDRESS_DELAY_MS 100
+
+#define	PACKET_TYPE3	3
+
+#define PACKET3(op, n)	((PACKET_TYPE3 << 30) |				\
+			 (((op) & 0xFF) << 8) |				\
+			 ((n) & 0x3FFF) << 16)
+
+#define	PACKET3_WAIT_REG_MEM				0x3C
+#define		WAIT_REG_MEM_FUNCTION(x)                ((x) << 0)
+		/* 0 - always
+		 * 1 - <
+		 * 2 - <=
+		 * 3 - ==
+		 * 4 - !=
+		 * 5 - >=
+		 * 6 - >
+		 */
+#define		WAIT_REG_MEM_MEM_SPACE(x)               ((x) << 4)
+		/* 0 - reg
+		 * 1 - mem
+		 */
+#define		WAIT_REG_MEM_OPERATION(x)               ((x) << 6)
+		/* 0 - wait_reg_mem
+		 * 1 - wr_wait_wr_reg
+		 */
+#define		WAIT_REG_MEM_ENGINE(x)                  ((x) << 8)
+		/* 0 - me
+		 * 1 - pfp
+		 */
+
+#define	PACKET3_WRITE_DATA				0x37
+#define		WRITE_DATA_DST_SEL(x)                   ((x) << 8)
+		/* 0 - register
+		 * 1 - memory (sync - via GRBM)
+		 * 2 - gl2
+		 * 3 - gds
+		 * 4 - reserved
+		 * 5 - memory (async - direct)
+		 */
+#define		WR_ONE_ADDR                             (1 << 16)
+#define		WR_CONFIRM                              (1 << 20)
+#define		WRITE_DATA_CACHE_POLICY(x)              ((x) << 25)
+		/* 0 - LRU
+		 * 1 - Stream
+		 */
+#define		WRITE_DATA_ENGINE_SEL(x)                ((x) << 30)
+		/* 0 - me
+		 * 1 - pfp
+		 * 2 - ce
+		 */
+
+#define mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR                                      0x54f
+
+static  amdgpu_device_handle device_handle;
+static  uint32_t  major_version;
+static  uint32_t  minor_version;
+
+static pthread_t stress_thread;
+static uint32_t *ptr;
+
+int use_uc_mtype = 0;
+
+static void amdgpu_deadlock_helper(unsigned ip_type);
+static void amdgpu_deadlock_gfx(void);
+static void amdgpu_deadlock_compute(void);
+static void amdgpu_illegal_reg_access();
+static void amdgpu_illegal_mem_access();
+
+CU_BOOL suite_deadlock_tests_enable(void)
+{
+	CU_BOOL enable = CU_TRUE;
+
+	if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+					     &minor_version, &device_handle))
+		return CU_FALSE;
+
+	/*
+	 * Only enable for ASICs supporting GPU reset and for which it's enabled
+	 * by default (currently GFX8/9 dGPUS)
+	 */
+	if (device_handle->info.family_id != AMDGPU_FAMILY_VI &&
+	    device_handle->info.family_id != AMDGPU_FAMILY_AI &&
+	    device_handle->info.family_id != AMDGPU_FAMILY_CI) {
+		printf("\n\nGPU reset is not enabled for the ASIC, deadlock suite disabled\n");
+		enable = CU_FALSE;
+	}
+
+	if (device_handle->info.family_id >= AMDGPU_FAMILY_AI)
+		use_uc_mtype = 1;
+
+	if (amdgpu_device_deinitialize(device_handle))
+		return CU_FALSE;
+
+	return enable;
+}
+
+int suite_deadlock_tests_init(void)
+{
+	int r;
+
+	r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+				   &minor_version, &device_handle);
+
+	if (r) {
+		if ((r == -EACCES) && (errno == EACCES))
+			printf("\n\nError:%s. "
+				"Hint:Try to run this test program as root.",
+				strerror(errno));
+		return CUE_SINIT_FAILED;
+	}
+
+	return CUE_SUCCESS;
+}
+
+int suite_deadlock_tests_clean(void)
+{
+	int r = amdgpu_device_deinitialize(device_handle);
+
+	if (r == 0)
+		return CUE_SUCCESS;
+	else
+		return CUE_SCLEAN_FAILED;
+}
+
+
+CU_TestInfo deadlock_tests[] = {
+	{ "gfx ring block test (set amdgpu.lockup_timeout=50)", amdgpu_deadlock_gfx },
+	{ "compute ring block test (set amdgpu.lockup_timeout=50)", amdgpu_deadlock_compute },
+	{ "illegal reg access test", amdgpu_illegal_reg_access },
+	{ "illegal mem access test (set amdgpu.vm_fault_stop=2)", amdgpu_illegal_mem_access },
+	CU_TEST_INFO_NULL,
+};
+
+static void *write_mem_address(void *data)
+{
+	int i;
+
+	/* useconds_t range is [0, 1,000,000] so use loop for waits > 1s */
+	for (i = 0; i < WRITE_MEM_ADDRESS_DELAY_MS; i++)
+		usleep(1000);
+
+	ptr[256] = 0x1;
+
+	return 0;
+}
+
+static void amdgpu_deadlock_gfx(void)
+{
+	amdgpu_deadlock_helper(AMDGPU_HW_IP_GFX);
+}
+
+static void amdgpu_deadlock_compute(void)
+{
+	amdgpu_deadlock_helper(AMDGPU_HW_IP_COMPUTE);
+}
+
+static void amdgpu_deadlock_helper(unsigned ip_type)
+{
+	amdgpu_context_handle context_handle;
+	amdgpu_bo_handle ib_result_handle;
+	void *ib_result_cpu;
+	uint64_t ib_result_mc_address;
+	struct amdgpu_cs_request ibs_request;
+	struct amdgpu_cs_ib_info ib_info;
+	struct amdgpu_cs_fence fence_status;
+	uint32_t expired;
+	int i, r;
+	amdgpu_bo_list_handle bo_list;
+	amdgpu_va_handle va_handle;
+
+	r = pthread_create(&stress_thread, NULL, write_mem_address, NULL);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_alloc_and_map_raw(device_handle, 4096, 4096,
+			AMDGPU_GEM_DOMAIN_GTT, 0, use_uc_mtype ? AMDGPU_VM_MTYPE_UC : 0,
+						    &ib_result_handle, &ib_result_cpu,
+						    &ib_result_mc_address, &va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL,
+			       &bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	ptr = ib_result_cpu;
+
+	ptr[0] = PACKET3(PACKET3_WAIT_REG_MEM, 5);
+	ptr[1] = (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
+			 WAIT_REG_MEM_FUNCTION(4) | /* != */
+			 WAIT_REG_MEM_ENGINE(0));  /* me */
+	ptr[2] = (ib_result_mc_address + 256*4) & 0xfffffffc;
+	ptr[3] = ((ib_result_mc_address + 256*4) >> 32) & 0xffffffff;
+	ptr[4] = 0x00000000; /* reference value */
+	ptr[5] = 0xffffffff; /* and mask */
+	ptr[6] = 0x00000004; /* poll interval */
+
+	for (i = 7; i < 16; ++i)
+		ptr[i] = 0xffff1000;
+
+
+	ptr[256] = 0x0; /* the memory we wait on to change */
+
+
+
+	memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info));
+	ib_info.ib_mc_address = ib_result_mc_address;
+	ib_info.size = 16;
+
+	memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request));
+	ibs_request.ip_type = ip_type;
+	ibs_request.ring = 0;
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.resources = bo_list;
+	ibs_request.fence_info.handle = NULL;
+
+	for (i = 0; i < 200; i++) {
+		r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1);
+		CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1);
+
+	}
+
+	memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence));
+	fence_status.context = context_handle;
+	fence_status.ip_type = ip_type;
+	fence_status.ip_instance = 0;
+	fence_status.ring = 0;
+	fence_status.fence = ibs_request.seq_no;
+
+	r = amdgpu_cs_query_fence_status(&fence_status,
+			AMDGPU_TIMEOUT_INFINITE,0, &expired);
+	CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1);
+
+	pthread_join(stress_thread, NULL);
+
+	r = amdgpu_bo_list_destroy(bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle,
+				     ib_result_mc_address, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_cs_ctx_free(context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void bad_access_helper(int reg_access)
+{
+	amdgpu_context_handle context_handle;
+	amdgpu_bo_handle ib_result_handle;
+	void *ib_result_cpu;
+	uint64_t ib_result_mc_address;
+	struct amdgpu_cs_request ibs_request;
+	struct amdgpu_cs_ib_info ib_info;
+	struct amdgpu_cs_fence fence_status;
+	uint32_t expired;
+	int i, r;
+	amdgpu_bo_list_handle bo_list;
+	amdgpu_va_handle va_handle;
+
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_alloc_and_map_raw(device_handle, 4096, 4096,
+			AMDGPU_GEM_DOMAIN_GTT, 0, 0,
+							&ib_result_handle, &ib_result_cpu,
+							&ib_result_mc_address, &va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL,
+				   &bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	ptr = ib_result_cpu;
+	i = 0;
+
+	ptr[i++] = PACKET3(PACKET3_WRITE_DATA, 3);
+	ptr[i++] = (reg_access ? WRITE_DATA_DST_SEL(0) : WRITE_DATA_DST_SEL(5))| WR_CONFIRM;
+	ptr[i++] = reg_access ? mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR : 0xdeadbee0;
+	ptr[i++] = 0;
+	ptr[i++] = 0xdeadbeef;
+
+	for (; i < 16; ++i)
+		ptr[i] = 0xffff1000;
+
+	memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info));
+	ib_info.ib_mc_address = ib_result_mc_address;
+	ib_info.size = 16;
+
+	memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request));
+	ibs_request.ip_type = AMDGPU_HW_IP_GFX;
+	ibs_request.ring = 0;
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.resources = bo_list;
+	ibs_request.fence_info.handle = NULL;
+
+	r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1);
+	CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1);
+
+
+	memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence));
+	fence_status.context = context_handle;
+	fence_status.ip_type = AMDGPU_HW_IP_GFX;
+	fence_status.ip_instance = 0;
+	fence_status.ring = 0;
+	fence_status.fence = ibs_request.seq_no;
+
+	r = amdgpu_cs_query_fence_status(&fence_status,
+			AMDGPU_TIMEOUT_INFINITE,0, &expired);
+	CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1);
+
+	r = amdgpu_bo_list_destroy(bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle,
+					 ib_result_mc_address, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_cs_ctx_free(context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_illegal_reg_access()
+{
+	bad_access_helper(1);
+}
+
+static void amdgpu_illegal_mem_access()
+{
+	bad_access_helper(0);
+}
diff --git a/tests/amdgpu/uvd_messages.h b/tests/amdgpu/decode_messages.h
similarity index 96%
rename from tests/amdgpu/uvd_messages.h
rename to tests/amdgpu/decode_messages.h
index 00235cb..bd6fe4b 100644
--- a/tests/amdgpu/uvd_messages.h
+++ b/tests/amdgpu/decode_messages.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Advanced Micro Devices, Inc.
+ * Copyright 2017 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"),
@@ -21,8 +21,10 @@
  *
  */
 
-#ifndef _UVD_MESSAGES_H_
-#define _UVD_MESSAGES_H_
+#ifndef _DECODE_MESSAGES_H_
+#define _DECODE_MESSAGES_H_
+
+#define SUM_DECODE 0x20345d8
 
 static const uint8_t uvd_create_msg[] = {
 	0xe4,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00,
@@ -356,6 +358,9 @@
 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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 const uint8_t avc_decode_msg[] = {
 	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,
@@ -810,4 +815,34 @@
 	0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
 };
 
-#endif /* _UVD_MESSAGES_H_ */
+static const uint8_t vcn_dec_create_msg[] = {
+	0x28,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x28,0x00,0x00,0x00,
+	0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x60,0x03,0x00,0x00,0xe0,0x01,0x00,0x00,
+};
+
+static const uint8_t vcn_dec_decode_msg[] = {
+	0x28,0x00,0x00,0x00,0x90,0x06,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+	0x03,0x00,0x44,0x40,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x38,0x00,0x00,0x00,
+	0xb4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0xec,0x00,0x00,0x00,
+	0x5c,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+	0x60,0x03,0x00,0x00,0xe0,0x01,0x00,0x00,0x80,0x05,0x00,0x00,0x00,0x94,0x6b,0x00,
+	0x96,0x4e,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x50,0x00,
+	0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,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,0x02,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,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,
+};
+
+static const uint8_t vcn_dec_destroy_msg[] = {
+	0x28,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
+	0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00,
+};
+
+#endif /* _DECODE_MESSAGES_H_ */
diff --git a/tests/amdgpu/frame.h b/tests/amdgpu/frame.h
index 4c946c2..335401c 100644
--- a/tests/amdgpu/frame.h
+++ b/tests/amdgpu/frame.h
@@ -24,7 +24,7 @@
 #ifndef _frame_h_
 #define _frame_h_
 
-const uint8_t frame[] = {
+static const uint8_t frame[] = {
 	0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
 	0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
 	0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa,
diff --git a/tests/amdgpu/meson.build b/tests/amdgpu/meson.build
new file mode 100644
index 0000000..4c1237c
--- /dev/null
+++ b/tests/amdgpu/meson.build
@@ -0,0 +1,34 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+if dep_cunit.found()
+  amdgpu_test = executable(
+    'amdgpu_test',
+    files(
+      'amdgpu_test.c', 'basic_tests.c', 'bo_tests.c', 'cs_tests.c',
+      'vce_tests.c', 'uvd_enc_tests.c', 'vcn_tests.c', 'deadlock_tests.c',
+      'vm_tests.c',
+    ),
+    dependencies : [dep_cunit, dep_threads],
+    include_directories : [inc_root, inc_drm, include_directories('../../amdgpu')],
+    link_with : [libdrm, libdrm_amdgpu],
+    install : with_install_tests,
+  )
+endif
diff --git a/tests/amdgpu/uvd_enc_tests.c b/tests/amdgpu/uvd_enc_tests.c
new file mode 100644
index 0000000..b4251bc
--- /dev/null
+++ b/tests/amdgpu/uvd_enc_tests.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright 2017 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 <inttypes.h>
+
+#include "CUnit/Basic.h"
+
+#include "util_math.h"
+
+#include "amdgpu_test.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+#include "frame.h"
+#include "uve_ib.h"
+
+#define IB_SIZE		4096
+#define MAX_RESOURCES	16
+
+struct amdgpu_uvd_enc_bo {
+	amdgpu_bo_handle handle;
+	amdgpu_va_handle va_handle;
+	uint64_t addr;
+	uint64_t size;
+	uint8_t *ptr;
+};
+
+struct amdgpu_uvd_enc {
+	unsigned width;
+	unsigned height;
+	struct amdgpu_uvd_enc_bo session;
+	struct amdgpu_uvd_enc_bo vbuf;
+	struct amdgpu_uvd_enc_bo bs;
+	struct amdgpu_uvd_enc_bo fb;
+	struct amdgpu_uvd_enc_bo cpb;
+};
+
+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_bo_handle ib_handle;
+static amdgpu_va_handle ib_va_handle;
+static uint64_t ib_mc_address;
+static uint32_t *ib_cpu;
+
+static struct amdgpu_uvd_enc enc;
+static amdgpu_bo_handle resources[MAX_RESOURCES];
+static unsigned num_resources;
+
+static void amdgpu_cs_uvd_enc_create(void);
+static void amdgpu_cs_uvd_enc_session_init(void);
+static void amdgpu_cs_uvd_enc_encode(void);
+static void amdgpu_cs_uvd_enc_destroy(void);
+
+
+CU_TestInfo uvd_enc_tests[] = {
+	{ "UVD ENC create",  amdgpu_cs_uvd_enc_create },
+	{ "UVD ENC session init",  amdgpu_cs_uvd_enc_session_init },
+	{ "UVD ENC encode",  amdgpu_cs_uvd_enc_encode },
+	{ "UVD ENC destroy",  amdgpu_cs_uvd_enc_destroy },
+	CU_TEST_INFO_NULL,
+};
+
+CU_BOOL suite_uvd_enc_tests_enable(void)
+{
+	int r;
+	struct drm_amdgpu_info_hw_ip info;
+
+	if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+					     &minor_version, &device_handle))
+		return CU_FALSE;
+
+	r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_UVD_ENC, 0, &info);
+
+	if (amdgpu_device_deinitialize(device_handle))
+		return CU_FALSE;
+
+	if (!info.available_rings)
+		printf("\n\nThe ASIC NOT support UVD ENC, suite disabled.\n");
+
+	return (r == 0 && (info.available_rings ? CU_TRUE : CU_FALSE));
+}
+
+
+int suite_uvd_enc_tests_init(void)
+{
+	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_bo_alloc_and_map(device_handle, IB_SIZE, 4096,
+				    AMDGPU_GEM_DOMAIN_GTT, 0,
+				    &ib_handle, (void**)&ib_cpu,
+				    &ib_mc_address, &ib_va_handle);
+	if (r)
+		return CUE_SINIT_FAILED;
+
+	return CUE_SUCCESS;
+}
+
+int suite_uvd_enc_tests_clean(void)
+{
+	int r;
+
+	r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle,
+				     ib_mc_address, IB_SIZE);
+	if (r)
+		return CUE_SCLEAN_FAILED;
+
+	r = amdgpu_cs_ctx_free(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_request ibs_request = {0};
+	struct amdgpu_cs_ib_info ib_info = {0};
+	struct amdgpu_cs_fence fence_status = {0};
+	uint32_t expired;
+	int r;
+
+	ib_info.ib_mc_address = ib_mc_address;
+	ib_info.size = ndw;
+
+	ibs_request.ip_type = ip;
+
+	r = amdgpu_bo_list_create(device_handle, num_resources, resources,
+				  NULL, &ibs_request.resources);
+	if (r)
+		return r;
+
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.fence_info.handle = NULL;
+
+	r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1);
+	if (r)
+		return r;
+
+	r = amdgpu_bo_list_destroy(ibs_request.resources);
+	if (r)
+		return r;
+
+	fence_status.context = context_handle;
+	fence_status.ip_type = ip;
+	fence_status.fence = ibs_request.seq_no;
+
+	r = amdgpu_cs_query_fence_status(&fence_status,
+					 AMDGPU_TIMEOUT_INFINITE,
+					 0, &expired);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+static void alloc_resource(struct amdgpu_uvd_enc_bo *uvd_enc_bo,
+			unsigned size, unsigned domain)
+{
+	struct amdgpu_bo_alloc_request req = {0};
+	amdgpu_bo_handle buf_handle;
+	amdgpu_va_handle va_handle;
+	uint64_t va = 0;
+	int r;
+
+	req.alloc_size = ALIGN(size, 4096);
+	req.preferred_heap = domain;
+	r = amdgpu_bo_alloc(device_handle, &req, &buf_handle);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_va_range_alloc(device_handle,
+				  amdgpu_gpu_va_range_general,
+				  req.alloc_size, 1, 0, &va,
+				  &va_handle, 0);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0,
+			    AMDGPU_VA_OP_MAP);
+	CU_ASSERT_EQUAL(r, 0);
+	uvd_enc_bo->addr = va;
+	uvd_enc_bo->handle = buf_handle;
+	uvd_enc_bo->size = req.alloc_size;
+	uvd_enc_bo->va_handle = va_handle;
+	r = amdgpu_bo_cpu_map(uvd_enc_bo->handle, (void **)&uvd_enc_bo->ptr);
+	CU_ASSERT_EQUAL(r, 0);
+	memset(uvd_enc_bo->ptr, 0, size);
+	r = amdgpu_bo_cpu_unmap(uvd_enc_bo->handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void free_resource(struct amdgpu_uvd_enc_bo *uvd_enc_bo)
+{
+	int r;
+
+	r = amdgpu_bo_va_op(uvd_enc_bo->handle, 0, uvd_enc_bo->size,
+			    uvd_enc_bo->addr, 0, AMDGPU_VA_OP_UNMAP);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_va_range_free(uvd_enc_bo->va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_free(uvd_enc_bo->handle);
+	CU_ASSERT_EQUAL(r, 0);
+	memset(uvd_enc_bo, 0, sizeof(*uvd_enc_bo));
+}
+
+static void amdgpu_cs_uvd_enc_create(void)
+{
+	enc.width = 160;
+	enc.height = 128;
+
+	num_resources  = 0;
+	alloc_resource(&enc.session, 128 * 1024, AMDGPU_GEM_DOMAIN_GTT);
+	resources[num_resources++] = enc.session.handle;
+	resources[num_resources++] = ib_handle;
+}
+
+static void check_result(struct amdgpu_uvd_enc *enc)
+{
+	uint64_t sum;
+	uint32_t s = 175602;
+	uint32_t *ptr, size;
+	int j, r;
+
+	r = amdgpu_bo_cpu_map(enc->fb.handle, (void **)&enc->fb.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+	ptr = (uint32_t *)enc->fb.ptr;
+	size = ptr[6];
+	r = amdgpu_bo_cpu_unmap(enc->fb.handle);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_bo_cpu_map(enc->bs.handle, (void **)&enc->bs.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+	for (j = 0, sum = 0; j < size; ++j)
+		sum += enc->bs.ptr[j];
+	CU_ASSERT_EQUAL(sum, s);
+	r = amdgpu_bo_cpu_unmap(enc->bs.handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+}
+
+static void amdgpu_cs_uvd_enc_session_init(void)
+{
+	int len, r;
+
+	len = 0;
+	memcpy((ib_cpu + len), uve_session_info, sizeof(uve_session_info));
+	len += sizeof(uve_session_info) / 4;
+	ib_cpu[len++] = enc.session.addr >> 32;
+	ib_cpu[len++] = enc.session.addr;
+
+	memcpy((ib_cpu + len), uve_task_info, sizeof(uve_task_info));
+	len += sizeof(uve_task_info) / 4;
+	ib_cpu[len++] = 0x000000d8;
+	ib_cpu[len++] = 0x00000000;
+	ib_cpu[len++] = 0x00000000;
+
+	memcpy((ib_cpu + len), uve_op_init, sizeof(uve_op_init));
+	len += sizeof(uve_op_init) / 4;
+
+	memcpy((ib_cpu + len), uve_session_init, sizeof(uve_session_init));
+	len += sizeof(uve_session_init) / 4;
+
+	memcpy((ib_cpu + len), uve_layer_ctrl, sizeof(uve_layer_ctrl));
+	len += sizeof(uve_layer_ctrl) / 4;
+
+	memcpy((ib_cpu + len), uve_slice_ctrl, sizeof(uve_slice_ctrl));
+	len += sizeof(uve_slice_ctrl) / 4;
+
+	memcpy((ib_cpu + len), uve_spec_misc, sizeof(uve_spec_misc));
+	len += sizeof(uve_spec_misc) / 4;
+
+	memcpy((ib_cpu + len), uve_rc_session_init, sizeof(uve_rc_session_init));
+	len += sizeof(uve_rc_session_init) / 4;
+
+	memcpy((ib_cpu + len), uve_deblocking_filter, sizeof(uve_deblocking_filter));
+	len += sizeof(uve_deblocking_filter) / 4;
+
+	memcpy((ib_cpu + len), uve_quality_params, sizeof(uve_quality_params));
+	len += sizeof(uve_quality_params) / 4;
+
+	memcpy((ib_cpu + len), uve_op_init_rc, sizeof(uve_op_init_rc));
+	len += sizeof(uve_op_init_rc) / 4;
+
+	memcpy((ib_cpu + len), uve_op_init_rc_vbv_level, sizeof(uve_op_init_rc_vbv_level));
+	len += sizeof(uve_op_init_rc_vbv_level) / 4;
+
+	r = submit(len, AMDGPU_HW_IP_UVD_ENC);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_cs_uvd_enc_encode(void)
+{
+	int len, r, i;
+	uint64_t luma_offset, chroma_offset;
+	uint32_t vbuf_size, bs_size = 0x003f4800, cpb_size;
+	unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16;
+	vbuf_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16) * 1.5;
+	cpb_size = vbuf_size * 10;
+
+
+	num_resources  = 0;
+	alloc_resource(&enc.fb, 4096, AMDGPU_GEM_DOMAIN_VRAM);
+	resources[num_resources++] = enc.fb.handle;
+	alloc_resource(&enc.bs, bs_size, AMDGPU_GEM_DOMAIN_VRAM);
+	resources[num_resources++] = enc.bs.handle;
+	alloc_resource(&enc.vbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM);
+	resources[num_resources++] = enc.vbuf.handle;
+	alloc_resource(&enc.cpb, cpb_size, AMDGPU_GEM_DOMAIN_VRAM);
+	resources[num_resources++] = enc.cpb.handle;
+	resources[num_resources++] = ib_handle;
+
+	r = amdgpu_bo_cpu_map(enc.vbuf.handle, (void **)&enc.vbuf.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+
+	memset(enc.vbuf.ptr, 0, vbuf_size);
+	for (i = 0; i < enc.height; ++i) {
+		memcpy(enc.vbuf.ptr, (frame + i * enc.width), enc.width);
+		enc.vbuf.ptr += ALIGN(enc.width, align);
+	}
+	for (i = 0; i < enc.height / 2; ++i) {
+		memcpy(enc.vbuf.ptr, ((frame + enc.height * enc.width) + i * enc.width), enc.width);
+		enc.vbuf.ptr += ALIGN(enc.width, align);
+	}
+
+	r = amdgpu_bo_cpu_unmap(enc.vbuf.handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	len = 0;
+	memcpy((ib_cpu + len), uve_session_info, sizeof(uve_session_info));
+	len += sizeof(uve_session_info) / 4;
+	ib_cpu[len++] = enc.session.addr >> 32;
+	ib_cpu[len++] = enc.session.addr;
+
+	memcpy((ib_cpu + len), uve_task_info, sizeof(uve_task_info));
+	len += sizeof(uve_task_info) / 4;
+	ib_cpu[len++] = 0x000005e0;
+	ib_cpu[len++] = 0x00000001;
+	ib_cpu[len++] = 0x00000001;
+
+	memcpy((ib_cpu + len), uve_nalu_buffer_1, sizeof(uve_nalu_buffer_1));
+	len += sizeof(uve_nalu_buffer_1) / 4;
+
+	memcpy((ib_cpu + len), uve_nalu_buffer_2, sizeof(uve_nalu_buffer_2));
+	len += sizeof(uve_nalu_buffer_2) / 4;
+
+	memcpy((ib_cpu + len), uve_nalu_buffer_3, sizeof(uve_nalu_buffer_3));
+	len += sizeof(uve_nalu_buffer_3) / 4;
+
+	memcpy((ib_cpu + len), uve_nalu_buffer_4, sizeof(uve_nalu_buffer_4));
+	len += sizeof(uve_nalu_buffer_4) / 4;
+
+	memcpy((ib_cpu + len), uve_slice_header, sizeof(uve_slice_header));
+	len += sizeof(uve_slice_header) / 4;
+
+	ib_cpu[len++] = 0x00000254;
+	ib_cpu[len++] = 0x00000010;
+	ib_cpu[len++] = enc.cpb.addr >> 32;
+	ib_cpu[len++] = enc.cpb.addr;
+	memcpy((ib_cpu + len), uve_ctx_buffer, sizeof(uve_ctx_buffer));
+	len += sizeof(uve_ctx_buffer) / 4;
+
+	memcpy((ib_cpu + len), uve_bitstream_buffer, sizeof(uve_bitstream_buffer));
+	len += sizeof(uve_bitstream_buffer) / 4;
+	ib_cpu[len++] = 0x00000000;
+	ib_cpu[len++] = enc.bs.addr >> 32;
+	ib_cpu[len++] = enc.bs.addr;
+	ib_cpu[len++] = 0x003f4800;
+	ib_cpu[len++] = 0x00000000;
+
+	memcpy((ib_cpu + len), uve_feedback_buffer, sizeof(uve_feedback_buffer));
+	len += sizeof(uve_feedback_buffer) / 4;
+	ib_cpu[len++] = enc.fb.addr >> 32;
+	ib_cpu[len++] = enc.fb.addr;
+	ib_cpu[len++] = 0x00000010;
+	ib_cpu[len++] = 0x00000028;
+
+	memcpy((ib_cpu + len), uve_feedback_buffer_additional, sizeof(uve_feedback_buffer_additional));
+	len += sizeof(uve_feedback_buffer_additional) / 4;
+
+	memcpy((ib_cpu + len), uve_intra_refresh, sizeof(uve_intra_refresh));
+	len += sizeof(uve_intra_refresh) / 4;
+
+	memcpy((ib_cpu + len), uve_layer_select, sizeof(uve_layer_select));
+	len += sizeof(uve_layer_select) / 4;
+
+	memcpy((ib_cpu + len), uve_rc_layer_init, sizeof(uve_rc_layer_init));
+	len += sizeof(uve_rc_layer_init) / 4;
+
+	memcpy((ib_cpu + len), uve_layer_select, sizeof(uve_layer_select));
+	len += sizeof(uve_layer_select) / 4;
+
+	memcpy((ib_cpu + len), uve_rc_per_pic, sizeof(uve_rc_per_pic));
+	len += sizeof(uve_rc_per_pic) / 4;
+
+	unsigned luma_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16);
+	luma_offset = enc.vbuf.addr;
+	chroma_offset = luma_offset + luma_size;
+	ib_cpu[len++] = 0x00000054;
+	ib_cpu[len++] = 0x0000000c;
+	ib_cpu[len++] = 0x00000002;
+	ib_cpu[len++] = 0x003f4800;
+	ib_cpu[len++] = luma_offset >> 32;
+	ib_cpu[len++] = luma_offset;
+	ib_cpu[len++] = chroma_offset >> 32;
+	ib_cpu[len++] = chroma_offset;
+	memcpy((ib_cpu + len), uve_encode_param, sizeof(uve_encode_param));
+	ib_cpu[len] = ALIGN(enc.width, align);
+	ib_cpu[len + 1] = ALIGN(enc.width, align);
+	len += sizeof(uve_encode_param) / 4;
+
+	memcpy((ib_cpu + len), uve_op_speed_enc_mode, sizeof(uve_op_speed_enc_mode));
+	len += sizeof(uve_op_speed_enc_mode) / 4;
+
+	memcpy((ib_cpu + len), uve_op_encode, sizeof(uve_op_encode));
+	len += sizeof(uve_op_encode) / 4;
+
+	r = submit(len, AMDGPU_HW_IP_UVD_ENC);
+	CU_ASSERT_EQUAL(r, 0);
+
+	check_result(&enc);
+
+	free_resource(&enc.fb);
+	free_resource(&enc.bs);
+	free_resource(&enc.vbuf);
+	free_resource(&enc.cpb);
+}
+
+static void amdgpu_cs_uvd_enc_destroy(void)
+{
+	int len, r;
+
+	num_resources  = 0;
+	resources[num_resources++] = ib_handle;
+
+	len = 0;
+	memcpy((ib_cpu + len), uve_session_info, sizeof(uve_session_info));
+	len += sizeof(uve_session_info) / 4;
+	ib_cpu[len++] = enc.session.addr >> 32;
+	ib_cpu[len++] = enc.session.addr;
+
+	memcpy((ib_cpu + len), uve_task_info, sizeof(uve_task_info));
+	len += sizeof(uve_task_info) / 4;
+	ib_cpu[len++] = 0xffffffff;
+	ib_cpu[len++] = 0x00000002;
+	ib_cpu[len++] = 0x00000000;
+
+	memcpy((ib_cpu + len), uve_op_close, sizeof(uve_op_close));
+	len += sizeof(uve_op_close) / 4;
+
+	r = submit(len, AMDGPU_HW_IP_UVD_ENC);
+	CU_ASSERT_EQUAL(r, 0);
+
+	free_resource(&enc.session);
+}
diff --git a/tests/amdgpu/uve_ib.h b/tests/amdgpu/uve_ib.h
new file mode 100644
index 0000000..cb72be2
--- /dev/null
+++ b/tests/amdgpu/uve_ib.h
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2017 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 _uve_ib_h_
+#define _uve_ib_h_
+
+static const uint32_t uve_session_info[] = {
+	0x00000018,
+	0x00000001,
+	0x00000000,
+	0x00010000,
+};
+
+static const uint32_t uve_task_info[] = {
+	0x00000014,
+	0x00000002,
+};
+
+static const uint32_t uve_session_init[] = {
+	0x00000020,
+	0x00000003,
+	0x000000c0,
+	0x00000080,
+	0x00000020,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const uint32_t uve_layer_ctrl[] = {
+	0x00000010,
+	0x00000004,
+	0x00000001,
+	0x00000001,
+};
+
+static const uint32_t uve_layer_select[] = {
+	0x0000000c,
+	0x00000005,
+	0x00000000,
+};
+
+static const uint32_t uve_slice_ctrl[] = {
+	0x00000014,
+	0x00000006,
+	0x00000000,
+	0x00000006,
+	0x00000006,
+};
+
+static const uint32_t uve_spec_misc[] = {
+	0x00000024,
+	0x00000007,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000001,
+	0x00000001,
+};
+
+static const uint32_t uve_rc_session_init[] = {
+	0x00000010,
+	0x00000008,
+	0x00000000,
+	0x00000040,
+};
+
+static const uint32_t uve_rc_layer_init[] = {
+	0x00000028,
+	0x00000009,
+	0x001e8480,
+	0x001e8480,
+	0x0000001e,
+	0x00000001,
+	0x0001046a,
+	0x0001046a,
+	0x0001046a,
+	0xaaaaaaaa,
+};
+
+static const uint32_t uve_deblocking_filter[] = {
+	0x00000020,
+	0x0000000e,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const uint32_t uve_quality_params[] = {
+	0x00000014,
+	0x0000000d,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const uint32_t uve_feedback_buffer[] = {
+	0x0000001c,
+	0x00000012,
+	0x00000000,
+};
+
+static const uint32_t uve_feedback_buffer_additional[] = {
+	0x00000108,
+	0x00000014,
+	0x00000001,
+	0x00000010,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const uint32_t uve_nalu_buffer_1[] = {
+	0x00000018,
+	0x00000013,
+	0x00000001,
+	0x00000007,
+	0x00000001,
+	0x46011000,
+};
+
+static const uint32_t uve_nalu_buffer_2[] = {
+	0x0000002c,
+	0x00000013,
+	0x00000002,
+	0x0000001b,
+	0x00000001,
+	0x40010c01,
+	0xffff0160,
+	0x00000300,
+	0xb0000003,
+	0x00000300,
+	0x962c0900,
+};
+
+static const uint32_t uve_nalu_buffer_3[] = {
+	0x00000034,
+	0x00000013,
+	0x00000003,
+	0x00000023,
+	0x00000001,
+	0x42010101,
+	0x60000003,
+	0x00b00000,
+	0x03000003,
+	0x0096a018,
+	0x2020708f,
+	0xcb924295,
+	0x12e08000,
+};
+
+static const uint32_t uve_nalu_buffer_4[] = {
+	0x0000001c,
+	0x00000013,
+	0x00000004,
+	0x0000000b,
+	0x00000001,
+	0x4401e0f1,
+	0x80992000,
+};
+
+static const uint32_t uve_slice_header[] = {
+	0x000000c8,
+	0x0000000b,
+	0x28010000,
+	0x40000000,
+	0x60000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000002,
+	0x00000010,
+	0x00000003,
+	0x00000000,
+	0x00000002,
+	0x00000002,
+	0x00000004,
+	0x00000000,
+	0x00000001,
+	0x00000000,
+	0x00000002,
+	0x00000003,
+	0x00000005,
+	0x00000000,
+	0x00000002,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const uint32_t uve_encode_param[] = {
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0xffffffff,
+	0x00000001,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const uint32_t uve_intra_refresh[] = {
+	0x00000014,
+	0x0000000f,
+	0x00000000,
+	0x00000000,
+	0x00000001,
+};
+
+static const uint32_t uve_ctx_buffer[] = {
+	0x00000000,
+	0x00000000,
+	0x000000a0,
+	0x000000a0,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const uint32_t uve_bitstream_buffer[] = {
+	0x0000001c,
+	0x00000011,
+};
+
+static const uint32_t uve_rc_per_pic[] = {
+	0x00000024,
+	0x0000000a,
+	0x0000001a,
+	0x00000000,
+	0x00000033,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000001,
+};
+
+static const uint32_t uve_op_init[] = {
+	0x00000008,
+	0x08000001,
+};
+
+static const uint32_t uve_op_close[] = {
+	0x00000008,
+	0x08000002,
+};
+
+static const uint32_t uve_op_encode[] = {
+	0x00000008,
+	0x08000003,
+};
+
+static const uint32_t uve_op_init_rc[] = {
+	0x00000008,
+	0x08000004,
+};
+
+static const uint32_t uve_op_init_rc_vbv_level[] = {
+	0x00000008,
+	0x08000005,
+};
+
+static const uint32_t uve_op_speed_enc_mode[] = {
+	0x00000008,
+	0x08000006,
+};
+
+static const uint32_t uve_op_balance_enc_mode[] = {
+	0x00000008,
+	0x08000007,
+};
+
+static const uint32_t uve_op_quality_enc_mode[] = {
+	0x00000008,
+	0x08000008,
+};
+#endif /*_uve_ib_h*/
diff --git a/tests/amdgpu/vce_ib.h b/tests/amdgpu/vce_ib.h
index 80ab179..f3108a0 100644
--- a/tests/amdgpu/vce_ib.h
+++ b/tests/amdgpu/vce_ib.h
@@ -315,4 +315,21 @@
 	0x00000008,
 	0x02000001,
 };
+
+static const uint32_t vce_mv_buffer[] = {
+	0x00000038,
+	0x0500000d,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
 #endif /*_vce_ib_h*/
diff --git a/tests/amdgpu/vce_tests.c b/tests/amdgpu/vce_tests.c
index de63aa1..b9e15ee 100644
--- a/tests/amdgpu/vce_tests.c
+++ b/tests/amdgpu/vce_tests.c
@@ -21,10 +21,6 @@
  *
 */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdio.h>
 #include <inttypes.h>
 
@@ -41,6 +37,7 @@
 
 #define IB_SIZE		4096
 #define MAX_RESOURCES	16
+#define FW_53_0_03 ((53 << 24) | (0 << 16) | (03 << 8))
 
 struct amdgpu_vce_bo {
 	amdgpu_bo_handle handle;
@@ -59,6 +56,9 @@
 	struct amdgpu_vce_bo cpb;
 	unsigned ib_len;
 	bool two_instance;
+	struct amdgpu_vce_bo mvrefbuf;
+	struct amdgpu_vce_bo mvb;
+	unsigned mvbuf_size;
 };
 
 static amdgpu_device_handle device_handle;
@@ -66,6 +66,10 @@
 static uint32_t minor_version;
 static uint32_t family_id;
 static uint32_t vce_harvest_config;
+static uint32_t chip_rev;
+static uint32_t chip_id;
+static uint32_t ids_flags;
+static bool is_mv_supported = true;
 
 static amdgpu_context_handle context_handle;
 static amdgpu_bo_handle ib_handle;
@@ -79,15 +83,61 @@
 
 static void amdgpu_cs_vce_create(void);
 static void amdgpu_cs_vce_encode(void);
+static void amdgpu_cs_vce_encode_mv(void);
 static void amdgpu_cs_vce_destroy(void);
 
 CU_TestInfo vce_tests[] = {
 	{ "VCE create",  amdgpu_cs_vce_create },
 	{ "VCE encode",  amdgpu_cs_vce_encode },
+	{ "VCE MV dump",  amdgpu_cs_vce_encode_mv },
 	{ "VCE destroy",  amdgpu_cs_vce_destroy },
 	CU_TEST_INFO_NULL,
 };
 
+CU_BOOL suite_vce_tests_enable(void)
+{
+	uint32_t version, feature;
+	CU_BOOL ret_mv = CU_FALSE;
+
+	if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+					     &minor_version, &device_handle))
+		return CU_FALSE;
+
+	family_id = device_handle->info.family_id;
+	chip_rev = device_handle->info.chip_rev;
+	chip_id = device_handle->info.chip_external_rev;
+	ids_flags = device_handle->info.ids_flags;
+
+	amdgpu_query_firmware_version(device_handle, AMDGPU_INFO_FW_VCE, 0,
+					  0, &version, &feature);
+
+	if (amdgpu_device_deinitialize(device_handle))
+		return CU_FALSE;
+
+	if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI) {
+		printf("\n\nThe ASIC NOT support VCE, suite disabled\n");
+		return CU_FALSE;
+	}
+
+	if (!(chip_id == (chip_rev + 0x3C) || /* FIJI */
+			chip_id == (chip_rev + 0x50) || /* Polaris 10*/
+			chip_id == (chip_rev + 0x5A) || /* Polaris 11*/
+			chip_id == (chip_rev + 0x64) || /* Polaris 12*/
+			(family_id >= AMDGPU_FAMILY_AI && !ids_flags))) /* dGPU > Polaris */
+		printf("\n\nThe ASIC NOT support VCE MV, suite disabled\n");
+	else if (FW_53_0_03 > version)
+		printf("\n\nThe ASIC FW version NOT support VCE MV, suite disabled\n");
+	else
+		ret_mv = CU_TRUE;
+
+	if (ret_mv == CU_FALSE) {
+		amdgpu_set_test_active("VCE Tests", "VCE MV dump", ret_mv);
+		is_mv_supported = false;
+	}
+
+	return CU_TRUE;
+}
+
 int suite_vce_tests_init(void)
 {
 	int r;
@@ -234,6 +284,7 @@
 
 static void amdgpu_cs_vce_create(void)
 {
+	unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16;
 	int len, r;
 
 	enc.width = vce_create[6];
@@ -250,6 +301,14 @@
 	memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo));
 	len += sizeof(vce_taskinfo) / 4;
 	memcpy((ib_cpu + len), vce_create, sizeof(vce_create));
+	ib_cpu[len + 8] = ALIGN(enc.width, align);
+	ib_cpu[len + 9] = ALIGN(enc.width, align);
+	if (is_mv_supported == true) {/* disableTwoInstance */
+		if (family_id >= AMDGPU_FAMILY_AI)
+			ib_cpu[len + 11] = 0x01000001;
+		else
+			ib_cpu[len + 11] = 0x01000201;
+	}
 	len += sizeof(vce_create) / 4;
 	memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback));
 	ib_cpu[len + 2] = enc.fb[0].addr >> 32;
@@ -281,20 +340,24 @@
 	memcpy((ib_cpu + len), vce_rdo, sizeof(vce_rdo));
 	len += sizeof(vce_rdo) / 4;
 	memcpy((ib_cpu + len), vce_pic_ctrl, sizeof(vce_pic_ctrl));
+	if (is_mv_supported == true)
+		ib_cpu[len + 27] = 0x00000001; /* encSliceMode */
 	len += sizeof(vce_pic_ctrl) / 4;
 
 	r = submit(len, AMDGPU_HW_IP_VCE);
 	CU_ASSERT_EQUAL(r, 0);
 }
 
-static  void amdgpu_cs_vce_encode_idr(struct amdgpu_vce_encode *enc)
+static void amdgpu_cs_vce_encode_idr(struct amdgpu_vce_encode *enc)
 {
 
 	uint64_t luma_offset, chroma_offset;
-	int len = 0, r;
+	unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16;
+	unsigned luma_size = ALIGN(enc->width, align) * ALIGN(enc->height, 16);
+	int len = 0, i, r;
 
 	luma_offset = enc->vbuf.addr;
-	chroma_offset = luma_offset + enc->width * enc->height;
+	chroma_offset = luma_offset + luma_size;
 
 	memcpy((ib_cpu + len), vce_session, sizeof(vce_session));
 	len += sizeof(vce_session) / 4;
@@ -309,6 +372,10 @@
 	ib_cpu[len + 3] = enc->cpb.addr;
 	len += sizeof(vce_context_buffer) / 4;
 	memcpy((ib_cpu + len), vce_aux_buffer, sizeof(vce_aux_buffer));
+	for (i = 0; i <  8; ++i)
+		ib_cpu[len + 2 + i] = luma_size * 1.5 * (i + 2);
+	for (i = 0; i <  8; ++i)
+		ib_cpu[len + 10 + i] = luma_size * 1.5;
 	len += sizeof(vce_aux_buffer) / 4;
 	memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback));
 	ib_cpu[len + 2] = enc->fb[0].addr >> 32;
@@ -319,8 +386,10 @@
 	ib_cpu[len + 10] = luma_offset;
 	ib_cpu[len + 11] = chroma_offset >> 32;
 	ib_cpu[len + 12] = chroma_offset;
-	ib_cpu[len + 73] = 0x7800;
-	ib_cpu[len + 74] = 0x7800 + 0x5000;
+	ib_cpu[len + 14] = ALIGN(enc->width, align);
+	ib_cpu[len + 15] = ALIGN(enc->width, align);
+	ib_cpu[len + 73] = luma_size * 1.5;
+	ib_cpu[len + 74] = luma_size * 2.5;
 	len += sizeof(vce_encode) / 4;
 	enc->ib_len = len;
 	if (!enc->two_instance) {
@@ -332,11 +401,13 @@
 static void amdgpu_cs_vce_encode_p(struct amdgpu_vce_encode *enc)
 {
 	uint64_t luma_offset, chroma_offset;
-	int len, r;
+	int len, i, r;
+	unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16;
+	unsigned luma_size = ALIGN(enc->width, align) * ALIGN(enc->height, 16);
 
 	len = (enc->two_instance) ? enc->ib_len : 0;
 	luma_offset = enc->vbuf.addr;
-	chroma_offset = luma_offset + enc->width * enc->height;
+	chroma_offset = luma_offset + luma_size;
 
 	if (!enc->two_instance) {
 		memcpy((ib_cpu + len), vce_session, sizeof(vce_session));
@@ -353,6 +424,10 @@
 	ib_cpu[len + 3] = enc->cpb.addr;
 	len += sizeof(vce_context_buffer) / 4;
 	memcpy((ib_cpu + len), vce_aux_buffer, sizeof(vce_aux_buffer));
+	for (i = 0; i <  8; ++i)
+		ib_cpu[len + 2 + i] = luma_size * 1.5 * (i + 2);
+	for (i = 0; i <  8; ++i)
+		ib_cpu[len + 10 + i] = luma_size * 1.5;
 	len += sizeof(vce_aux_buffer) / 4;
 	memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback));
 	ib_cpu[len + 2] = enc->fb[1].addr >> 32;
@@ -364,15 +439,17 @@
 	ib_cpu[len + 10] = luma_offset;
 	ib_cpu[len + 11] = chroma_offset >> 32;
 	ib_cpu[len + 12] = chroma_offset;
+	ib_cpu[len + 14] = ALIGN(enc->width, align);
+	ib_cpu[len + 15] = ALIGN(enc->width, align);
 	ib_cpu[len + 18] = 0;
 	ib_cpu[len + 19] = 0;
 	ib_cpu[len + 56] = 3;
 	ib_cpu[len + 57] = 0;
 	ib_cpu[len + 58] = 0;
-	ib_cpu[len + 59] = 0x7800;
-	ib_cpu[len + 60] = 0x7800 + 0x5000;
+	ib_cpu[len + 59] = luma_size * 1.5;
+	ib_cpu[len + 60] = luma_size * 2.5;
 	ib_cpu[len + 73] = 0;
-	ib_cpu[len + 74] = 0x5000;
+	ib_cpu[len + 74] = luma_size;
 	ib_cpu[len + 81] = 1;
 	ib_cpu[len + 82] = 1;
 	len += sizeof(vce_encode) / 4;
@@ -408,9 +485,10 @@
 static void amdgpu_cs_vce_encode(void)
 {
 	uint32_t vbuf_size, bs_size = 0x154000, cpb_size;
-	int r;
+	unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16;
+	int i, r;
 
-	vbuf_size = enc.width * enc.height * 1.5;
+	vbuf_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16) * 1.5;
 	cpb_size = vbuf_size * 10;
 	num_resources = 0;
 	alloc_resource(&enc.fb[0], 4096, AMDGPU_GEM_DOMAIN_GTT);
@@ -429,7 +507,17 @@
 
 	r = amdgpu_bo_cpu_map(enc.vbuf.handle, (void **)&enc.vbuf.ptr);
 	CU_ASSERT_EQUAL(r, 0);
-	memcpy(enc.vbuf.ptr, frame, sizeof(frame));
+
+	memset(enc.vbuf.ptr, 0, vbuf_size);
+	for (i = 0; i < enc.height; ++i) {
+		memcpy(enc.vbuf.ptr, (frame + i * enc.width), enc.width);
+		enc.vbuf.ptr += ALIGN(enc.width, align);
+	}
+	for (i = 0; i < enc.height / 2; ++i) {
+		memcpy(enc.vbuf.ptr, ((frame + enc.height * enc.width) + i * enc.width), enc.width);
+		enc.vbuf.ptr += ALIGN(enc.width, align);
+	}
+
 	r = amdgpu_bo_cpu_unmap(enc.vbuf.handle);
 	CU_ASSERT_EQUAL(r, 0);
 
@@ -474,6 +562,180 @@
 	free_resource(&enc.cpb);
 }
 
+static void amdgpu_cs_vce_mv(struct amdgpu_vce_encode *enc)
+{
+	uint64_t luma_offset, chroma_offset;
+	uint64_t mv_ref_luma_offset;
+	unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16;
+	unsigned luma_size = ALIGN(enc->width, align) * ALIGN(enc->height, 16);
+	int len = 0, i, r;
+
+	luma_offset = enc->vbuf.addr;
+	chroma_offset = luma_offset + luma_size;
+	mv_ref_luma_offset = enc->mvrefbuf.addr;
+
+	memcpy((ib_cpu + len), vce_session, sizeof(vce_session));
+	len += sizeof(vce_session) / 4;
+	memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo));
+	len += sizeof(vce_taskinfo) / 4;
+	memcpy((ib_cpu + len), vce_bs_buffer, sizeof(vce_bs_buffer));
+	ib_cpu[len + 2] = enc->bs[0].addr >> 32;
+	ib_cpu[len + 3] = enc->bs[0].addr;
+	len += sizeof(vce_bs_buffer) / 4;
+	memcpy((ib_cpu + len), vce_context_buffer, sizeof(vce_context_buffer));
+	ib_cpu[len + 2] = enc->cpb.addr >> 32;
+	ib_cpu[len + 3] = enc->cpb.addr;
+	len += sizeof(vce_context_buffer) / 4;
+	memcpy((ib_cpu + len), vce_aux_buffer, sizeof(vce_aux_buffer));
+	for (i = 0; i <  8; ++i)
+		ib_cpu[len + 2 + i] = luma_size * 1.5 * (i + 2);
+	for (i = 0; i <  8; ++i)
+		ib_cpu[len + 10 + i] = luma_size * 1.5;
+	len += sizeof(vce_aux_buffer) / 4;
+	memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback));
+	ib_cpu[len + 2] = enc->fb[0].addr >> 32;
+	ib_cpu[len + 3] = enc->fb[0].addr;
+	len += sizeof(vce_feedback) / 4;
+	memcpy((ib_cpu + len), vce_mv_buffer, sizeof(vce_mv_buffer));
+	ib_cpu[len + 2] = mv_ref_luma_offset >> 32;
+	ib_cpu[len + 3] = mv_ref_luma_offset;
+	ib_cpu[len + 4] = ALIGN(enc->width, align);
+	ib_cpu[len + 5] = ALIGN(enc->width, align);
+	ib_cpu[len + 6] = luma_size;
+	ib_cpu[len + 7] = enc->mvb.addr >> 32;
+	ib_cpu[len + 8] = enc->mvb.addr;
+	len += sizeof(vce_mv_buffer) / 4;
+	memcpy((ib_cpu + len), vce_encode, sizeof(vce_encode));
+	ib_cpu[len + 2] = 0;
+	ib_cpu[len + 3] = 0;
+	ib_cpu[len + 4] = 0x154000;
+	ib_cpu[len + 9] = luma_offset >> 32;
+	ib_cpu[len + 10] = luma_offset;
+	ib_cpu[len + 11] = chroma_offset >> 32;
+	ib_cpu[len + 12] = chroma_offset;
+	ib_cpu[len + 13] = ALIGN(enc->height, 16);;
+	ib_cpu[len + 14] = ALIGN(enc->width, align);
+	ib_cpu[len + 15] = ALIGN(enc->width, align);
+	/* encDisableMBOffloading-encDisableTwoPipeMode-encInputPicArrayMode-encInputPicAddrMode */
+	ib_cpu[len + 16] = 0x01010000;
+	ib_cpu[len + 18] = 0; /* encPicType */
+	ib_cpu[len + 19] = 0; /* encIdrFlag */
+	ib_cpu[len + 20] = 0; /* encIdrPicId */
+	ib_cpu[len + 21] = 0; /* encMGSKeyPic */
+	ib_cpu[len + 22] = 0; /* encReferenceFlag */
+	ib_cpu[len + 23] = 0; /* encTemporalLayerIndex */
+	ib_cpu[len + 55] = 0; /* pictureStructure */
+	ib_cpu[len + 56] = 0; /* encPicType -ref[0] */
+	ib_cpu[len + 61] = 0; /* pictureStructure */
+	ib_cpu[len + 62] = 0; /* encPicType -ref[1] */
+	ib_cpu[len + 67] = 0; /* pictureStructure */
+	ib_cpu[len + 68] = 0; /* encPicType -ref1 */
+	ib_cpu[len + 81] = 1; /* frameNumber */
+	ib_cpu[len + 82] = 2; /* pictureOrderCount */
+	ib_cpu[len + 83] = 0xffffffff; /* numIPicRemainInRCGOP */
+	ib_cpu[len + 84] = 0xffffffff; /* numPPicRemainInRCGOP */
+	ib_cpu[len + 85] = 0xffffffff; /* numBPicRemainInRCGOP */
+	ib_cpu[len + 86] = 0xffffffff; /* numIRPicRemainInRCGOP */
+	ib_cpu[len + 87] = 0; /* remainedIntraRefreshPictures */
+	len += sizeof(vce_encode) / 4;
+
+	enc->ib_len = len;
+	r = submit(len, AMDGPU_HW_IP_VCE);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void check_mv_result(struct amdgpu_vce_encode *enc)
+{
+	uint64_t sum;
+	uint32_t s = 140790;
+	uint32_t *ptr, size;
+	int i, j, r;
+
+	r = amdgpu_bo_cpu_map(enc->fb[0].handle, (void **)&enc->fb[0].ptr);
+	CU_ASSERT_EQUAL(r, 0);
+	ptr = (uint32_t *)enc->fb[0].ptr;
+	r = amdgpu_bo_cpu_unmap(enc->fb[0].handle);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_bo_cpu_map(enc->mvb.handle, (void **)&enc->mvb.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+	for (j = 0, sum = 0; j < enc->mvbuf_size; ++j)
+		sum += enc->mvb.ptr[j];
+	CU_ASSERT_EQUAL(sum, s);
+	r = amdgpu_bo_cpu_unmap(enc->mvb.handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_cs_vce_encode_mv(void)
+{
+	uint32_t vbuf_size, bs_size = 0x154000, cpb_size;
+	unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16;
+	int i, r;
+
+	vbuf_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16) * 1.5;
+	enc.mvbuf_size = ALIGN(enc.width, 16) * ALIGN(enc.height, 16) / 8;
+	cpb_size = vbuf_size * 10;
+	num_resources = 0;
+	alloc_resource(&enc.fb[0], 4096, AMDGPU_GEM_DOMAIN_GTT);
+	resources[num_resources++] = enc.fb[0].handle;
+	alloc_resource(&enc.bs[0], bs_size, AMDGPU_GEM_DOMAIN_GTT);
+	resources[num_resources++] = enc.bs[0].handle;
+	alloc_resource(&enc.mvb, enc.mvbuf_size, AMDGPU_GEM_DOMAIN_GTT);
+	resources[num_resources++] = enc.mvb.handle;
+	alloc_resource(&enc.vbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM);
+	resources[num_resources++] = enc.vbuf.handle;
+	alloc_resource(&enc.mvrefbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM);
+	resources[num_resources++] = enc.mvrefbuf.handle;
+	alloc_resource(&enc.cpb, cpb_size, AMDGPU_GEM_DOMAIN_VRAM);
+	resources[num_resources++] = enc.cpb.handle;
+	resources[num_resources++] = ib_handle;
+
+	r = amdgpu_bo_cpu_map(enc.vbuf.handle, (void **)&enc.vbuf.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+
+	memset(enc.vbuf.ptr, 0, vbuf_size);
+	for (i = 0; i < enc.height; ++i) {
+		memcpy(enc.vbuf.ptr, (frame + i * enc.width), enc.width);
+		enc.vbuf.ptr += ALIGN(enc.width, align);
+	}
+	for (i = 0; i < enc.height / 2; ++i) {
+		memcpy(enc.vbuf.ptr, ((frame + enc.height * enc.width) + i * enc.width), enc.width);
+		enc.vbuf.ptr += ALIGN(enc.width, align);
+	}
+
+	r = amdgpu_bo_cpu_unmap(enc.vbuf.handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_cpu_map(enc.mvrefbuf.handle, (void **)&enc.mvrefbuf.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+
+	memset(enc.mvrefbuf.ptr, 0, vbuf_size);
+	for (i = 0; i < enc.height; ++i) {
+		memcpy(enc.mvrefbuf.ptr, (frame + (enc.height - i -1) * enc.width), enc.width);
+		enc.mvrefbuf.ptr += ALIGN(enc.width, align);
+	}
+	for (i = 0; i < enc.height / 2; ++i) {
+		memcpy(enc.mvrefbuf.ptr,
+		((frame + enc.height * enc.width) + (enc.height / 2 - i -1) * enc.width), enc.width);
+		enc.mvrefbuf.ptr += ALIGN(enc.width, align);
+	}
+
+	r = amdgpu_bo_cpu_unmap(enc.mvrefbuf.handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	amdgpu_cs_vce_config();
+
+	vce_taskinfo[3] = 3;
+	amdgpu_cs_vce_mv(&enc);
+	check_mv_result(&enc);
+
+	free_resource(&enc.fb[0]);
+	free_resource(&enc.bs[0]);
+	free_resource(&enc.vbuf);
+	free_resource(&enc.cpb);
+	free_resource(&enc.mvrefbuf);
+	free_resource(&enc.mvb);
+}
+
 static void amdgpu_cs_vce_destroy(void)
 {
 	int len, r;
diff --git a/tests/amdgpu/vcn_tests.c b/tests/amdgpu/vcn_tests.c
new file mode 100644
index 0000000..859ec49
--- /dev/null
+++ b/tests/amdgpu/vcn_tests.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2017 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 <inttypes.h>
+
+#include "CUnit/Basic.h"
+
+#include "util_math.h"
+
+#include "amdgpu_test.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+#include "decode_messages.h"
+
+#define IB_SIZE		4096
+#define MAX_RESOURCES	16
+
+struct amdgpu_vcn_bo {
+	amdgpu_bo_handle handle;
+	amdgpu_va_handle va_handle;
+	uint64_t addr;
+	uint64_t size;
+	uint8_t *ptr;
+};
+
+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_bo_handle ib_handle;
+static amdgpu_va_handle ib_va_handle;
+static uint64_t ib_mc_address;
+static uint32_t *ib_cpu;
+
+static amdgpu_bo_handle resources[MAX_RESOURCES];
+static unsigned num_resources;
+
+static void amdgpu_cs_vcn_dec_create(void);
+static void amdgpu_cs_vcn_dec_decode(void);
+static void amdgpu_cs_vcn_dec_destroy(void);
+
+static void amdgpu_cs_vcn_enc_create(void);
+static void amdgpu_cs_vcn_enc_encode(void);
+static void amdgpu_cs_vcn_enc_destroy(void);
+
+CU_TestInfo vcn_tests[] = {
+
+	{ "VCN DEC create",  amdgpu_cs_vcn_dec_create },
+	{ "VCN DEC decode",  amdgpu_cs_vcn_dec_decode },
+	{ "VCN DEC destroy",  amdgpu_cs_vcn_dec_destroy },
+
+	{ "VCN ENC create",  amdgpu_cs_vcn_enc_create },
+	{ "VCN ENC decode",  amdgpu_cs_vcn_enc_encode },
+	{ "VCN ENC destroy",  amdgpu_cs_vcn_enc_destroy },
+	CU_TEST_INFO_NULL,
+};
+
+CU_BOOL suite_vcn_tests_enable(void)
+{
+
+	if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+				   &minor_version, &device_handle))
+		return CU_FALSE;
+
+	family_id = device_handle->info.family_id;
+
+	if (amdgpu_device_deinitialize(device_handle))
+			return CU_FALSE;
+
+
+	if (family_id < AMDGPU_FAMILY_RV) {
+		printf("\n\nThe ASIC NOT support VCN, suite disabled\n");
+		return CU_FALSE;
+	}
+
+	return CU_TRUE;
+}
+
+int suite_vcn_tests_init(void)
+{
+	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_bo_alloc_and_map(device_handle, IB_SIZE, 4096,
+				    AMDGPU_GEM_DOMAIN_GTT, 0,
+				    &ib_handle, (void**)&ib_cpu,
+				    &ib_mc_address, &ib_va_handle);
+	if (r)
+		return CUE_SINIT_FAILED;
+
+	return CUE_SUCCESS;
+}
+
+int suite_vcn_tests_clean(void)
+{
+	int r;
+
+	r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle,
+			     ib_mc_address, IB_SIZE);
+	if (r)
+		return CUE_SCLEAN_FAILED;
+
+	r = amdgpu_cs_ctx_free(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_request ibs_request = {0};
+	struct amdgpu_cs_ib_info ib_info = {0};
+	struct amdgpu_cs_fence fence_status = {0};
+	uint32_t expired;
+	int r;
+
+	ib_info.ib_mc_address = ib_mc_address;
+	ib_info.size = ndw;
+
+	ibs_request.ip_type = ip;
+
+	r = amdgpu_bo_list_create(device_handle, num_resources, resources,
+				  NULL, &ibs_request.resources);
+	if (r)
+		return r;
+
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.fence_info.handle = NULL;
+
+	r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1);
+	if (r)
+		return r;
+
+	r = amdgpu_bo_list_destroy(ibs_request.resources);
+	if (r)
+		return r;
+
+	fence_status.context = context_handle;
+	fence_status.ip_type = ip;
+	fence_status.fence = ibs_request.seq_no;
+
+	r = amdgpu_cs_query_fence_status(&fence_status,
+					 AMDGPU_TIMEOUT_INFINITE,
+					 0, &expired);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+static void alloc_resource(struct amdgpu_vcn_bo *vcn_bo,
+			unsigned size, unsigned domain)
+{
+	struct amdgpu_bo_alloc_request req = {0};
+	amdgpu_bo_handle buf_handle;
+	amdgpu_va_handle va_handle;
+	uint64_t va = 0;
+	int r;
+
+	req.alloc_size = ALIGN(size, 4096);
+	req.preferred_heap = domain;
+	r = amdgpu_bo_alloc(device_handle, &req, &buf_handle);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_va_range_alloc(device_handle,
+				  amdgpu_gpu_va_range_general,
+				  req.alloc_size, 1, 0, &va,
+				  &va_handle, 0);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0,
+			    AMDGPU_VA_OP_MAP);
+	CU_ASSERT_EQUAL(r, 0);
+	vcn_bo->addr = va;
+	vcn_bo->handle = buf_handle;
+	vcn_bo->size = req.alloc_size;
+	vcn_bo->va_handle = va_handle;
+	r = amdgpu_bo_cpu_map(vcn_bo->handle, (void **)&vcn_bo->ptr);
+	CU_ASSERT_EQUAL(r, 0);
+	memset(vcn_bo->ptr, 0, size);
+	r = amdgpu_bo_cpu_unmap(vcn_bo->handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void free_resource(struct amdgpu_vcn_bo *vcn_bo)
+{
+	int r;
+
+	r = amdgpu_bo_va_op(vcn_bo->handle, 0, vcn_bo->size,
+			    vcn_bo->addr, 0, AMDGPU_VA_OP_UNMAP);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_va_range_free(vcn_bo->va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_free(vcn_bo->handle);
+	CU_ASSERT_EQUAL(r, 0);
+	memset(vcn_bo, 0, sizeof(*vcn_bo));
+}
+
+static void vcn_dec_cmd(uint64_t addr, unsigned cmd, int *idx)
+{
+	ib_cpu[(*idx)++] = 0x81C4;
+	ib_cpu[(*idx)++] = addr;
+	ib_cpu[(*idx)++] = 0x81C5;
+	ib_cpu[(*idx)++] = addr >> 32;
+	ib_cpu[(*idx)++] = 0x81C3;
+	ib_cpu[(*idx)++] = cmd << 1;
+}
+
+static void amdgpu_cs_vcn_dec_create(void)
+{
+	struct amdgpu_vcn_bo msg_buf;
+	int len, r;
+
+	num_resources  = 0;
+	alloc_resource(&msg_buf, 4096, AMDGPU_GEM_DOMAIN_GTT);
+	resources[num_resources++] = msg_buf.handle;
+	resources[num_resources++] = ib_handle;
+
+	r = amdgpu_bo_cpu_map(msg_buf.handle, (void **)&msg_buf.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+
+	memset(msg_buf.ptr, 0, 4096);
+	memcpy(msg_buf.ptr, vcn_dec_create_msg, sizeof(vcn_dec_create_msg));
+
+	len = 0;
+	ib_cpu[len++] = 0x81C4;
+	ib_cpu[len++] = msg_buf.addr;
+	ib_cpu[len++] = 0x81C5;
+	ib_cpu[len++] = msg_buf.addr >> 32;
+	ib_cpu[len++] = 0x81C3;
+	ib_cpu[len++] = 0;
+	for (; len % 16; ) {
+		ib_cpu[len++] = 0x81ff;
+		ib_cpu[len++] = 0;
+	}
+
+	r = submit(len, AMDGPU_HW_IP_VCN_DEC);
+	CU_ASSERT_EQUAL(r, 0);
+
+	free_resource(&msg_buf);
+}
+
+static void amdgpu_cs_vcn_dec_decode(void)
+{
+	const unsigned dpb_size = 15923584, dt_size = 737280;
+	uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, ctx_addr, dt_addr, it_addr, sum;
+	struct amdgpu_vcn_bo dec_buf;
+	int size, len, i, r;
+	uint8_t *dec;
+
+	size = 4*1024; /* msg */
+	size += 4*1024; /* fb */
+	size += 4096; /*it_scaling_table*/
+	size += ALIGN(sizeof(uvd_bitstream), 4*1024);
+	size += ALIGN(dpb_size, 4*1024);
+	size += ALIGN(dt_size, 4*1024);
+
+	num_resources  = 0;
+	alloc_resource(&dec_buf, size, AMDGPU_GEM_DOMAIN_GTT);
+	resources[num_resources++] = dec_buf.handle;
+	resources[num_resources++] = ib_handle;
+
+	r = amdgpu_bo_cpu_map(dec_buf.handle, (void **)&dec_buf.ptr);
+	dec = dec_buf.ptr;
+
+	CU_ASSERT_EQUAL(r, 0);
+	memset(dec_buf.ptr, 0, size);
+	memcpy(dec_buf.ptr, vcn_dec_decode_msg, sizeof(vcn_dec_decode_msg));
+	memcpy(dec_buf.ptr + sizeof(vcn_dec_decode_msg),
+			avc_decode_msg, sizeof(avc_decode_msg));
+
+	dec += 4*1024;
+	dec += 4*1024;
+	memcpy(dec, uvd_it_scaling_table, sizeof(uvd_it_scaling_table));
+
+	dec += 4*1024;
+	memcpy(dec, uvd_bitstream, sizeof(uvd_bitstream));
+
+	dec += ALIGN(sizeof(uvd_bitstream), 4*1024);
+
+	dec += ALIGN(dpb_size, 4*1024);
+
+	msg_addr = dec_buf.addr;
+	fb_addr = msg_addr + 4*1024;
+	it_addr = fb_addr + 4*1024;
+	bs_addr = it_addr + 4*1024;
+	dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024);
+	ctx_addr = ALIGN(dpb_addr + 0x006B9400, 4*1024);
+	dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024);
+
+	len = 0;
+	vcn_dec_cmd(msg_addr, 0x0, &len);
+	vcn_dec_cmd(dpb_addr, 0x1, &len);
+	vcn_dec_cmd(dt_addr, 0x2, &len);
+	vcn_dec_cmd(fb_addr, 0x3, &len);
+	vcn_dec_cmd(bs_addr, 0x100, &len);
+	vcn_dec_cmd(it_addr, 0x204, &len);
+	vcn_dec_cmd(ctx_addr, 0x206, &len);
+
+	ib_cpu[len++] = 0x81C6;
+	ib_cpu[len++] = 0x1;
+	for (; len % 16; ) {
+		ib_cpu[len++] = 0x81ff;
+		ib_cpu[len++] = 0;
+	}
+
+	r = submit(len, AMDGPU_HW_IP_VCN_DEC);
+	CU_ASSERT_EQUAL(r, 0);
+
+	for (i = 0, sum = 0; i < dt_size; ++i)
+		sum += dec[i];
+
+	CU_ASSERT_EQUAL(sum, SUM_DECODE);
+
+	free_resource(&dec_buf);
+}
+
+static void amdgpu_cs_vcn_dec_destroy(void)
+{
+	struct amdgpu_vcn_bo msg_buf;
+	int len, r;
+
+	num_resources  = 0;
+	alloc_resource(&msg_buf, 1024, AMDGPU_GEM_DOMAIN_GTT);
+	resources[num_resources++] = msg_buf.handle;
+	resources[num_resources++] = ib_handle;
+
+	r = amdgpu_bo_cpu_map(msg_buf.handle, (void **)&msg_buf.ptr);
+	CU_ASSERT_EQUAL(r, 0);
+
+	memset(msg_buf.ptr, 0, 1024);
+	memcpy(msg_buf.ptr, vcn_dec_destroy_msg, sizeof(vcn_dec_destroy_msg));
+
+	len = 0;
+	ib_cpu[len++] = 0x81C4;
+	ib_cpu[len++] = msg_buf.addr;
+	ib_cpu[len++] = 0x81C5;
+	ib_cpu[len++] = msg_buf.addr >> 32;
+	ib_cpu[len++] = 0x81C3;
+	ib_cpu[len++] = 0;
+	for (; len % 16; ) {
+		ib_cpu[len++] = 0x81ff;
+		ib_cpu[len++] = 0;
+	}
+
+	r = submit(len, AMDGPU_HW_IP_VCN_DEC);
+	CU_ASSERT_EQUAL(r, 0);
+
+	free_resource(&msg_buf);
+}
+
+static void amdgpu_cs_vcn_enc_create(void)
+{
+	/* TODO */
+}
+
+static void amdgpu_cs_vcn_enc_encode(void)
+{
+	/* TODO */
+}
+
+static void amdgpu_cs_vcn_enc_destroy(void)
+{
+	/* TODO */
+}
diff --git a/tests/amdgpu/vm_tests.c b/tests/amdgpu/vm_tests.c
new file mode 100644
index 0000000..69bc468
--- /dev/null
+++ b/tests/amdgpu/vm_tests.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2017 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 "CUnit/Basic.h"
+
+#include "amdgpu_test.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+
+static  amdgpu_device_handle device_handle;
+static  uint32_t  major_version;
+static  uint32_t  minor_version;
+
+static void amdgpu_vmid_reserve_test(void);
+static void amdgpu_vm_unaligned_map(void);
+static void amdgpu_vm_mapping_test(void);
+
+CU_BOOL suite_vm_tests_enable(void)
+{
+    CU_BOOL enable = CU_TRUE;
+
+	if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+				     &minor_version, &device_handle))
+		return CU_FALSE;
+
+	if (device_handle->info.family_id == AMDGPU_FAMILY_SI) {
+		printf("\n\nCurrently hangs the CP on this ASIC, VM suite disabled\n");
+		enable = CU_FALSE;
+	}
+
+	if (amdgpu_device_deinitialize(device_handle))
+		return CU_FALSE;
+
+	return enable;
+}
+
+int suite_vm_tests_init(void)
+{
+	int r;
+
+	r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
+				   &minor_version, &device_handle);
+
+	if (r) {
+		if ((r == -EACCES) && (errno == EACCES))
+			printf("\n\nError:%s. "
+				"Hint:Try to run this test program as root.",
+				strerror(errno));
+		return CUE_SINIT_FAILED;
+	}
+
+	return CUE_SUCCESS;
+}
+
+int suite_vm_tests_clean(void)
+{
+	int r = amdgpu_device_deinitialize(device_handle);
+
+	if (r == 0)
+		return CUE_SUCCESS;
+	else
+		return CUE_SCLEAN_FAILED;
+}
+
+
+CU_TestInfo vm_tests[] = {
+	{ "resere vmid test",  amdgpu_vmid_reserve_test },
+	{ "unaligned map",  amdgpu_vm_unaligned_map },
+	{ "vm mapping test",  amdgpu_vm_mapping_test },
+	CU_TEST_INFO_NULL,
+};
+
+static void amdgpu_vmid_reserve_test(void)
+{
+	amdgpu_context_handle context_handle;
+	amdgpu_bo_handle ib_result_handle;
+	void *ib_result_cpu;
+	uint64_t ib_result_mc_address;
+	struct amdgpu_cs_request ibs_request;
+	struct amdgpu_cs_ib_info ib_info;
+	struct amdgpu_cs_fence fence_status;
+	uint32_t expired, flags;
+	int i, r;
+	amdgpu_bo_list_handle bo_list;
+	amdgpu_va_handle va_handle;
+	static uint32_t *ptr;
+
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	flags = 0;
+	r = amdgpu_vm_reserve_vmid(device_handle, flags);
+	CU_ASSERT_EQUAL(r, 0);
+
+
+	r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096,
+			AMDGPU_GEM_DOMAIN_GTT, 0,
+						    &ib_result_handle, &ib_result_cpu,
+						    &ib_result_mc_address, &va_handle);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL,
+			       &bo_list);
+	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_mc_address = ib_result_mc_address;
+	ib_info.size = 16;
+
+	memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request));
+	ibs_request.ip_type = AMDGPU_HW_IP_GFX;
+	ibs_request.ring = 0;
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.resources = bo_list;
+	ibs_request.fence_info.handle = NULL;
+
+	r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1);
+	CU_ASSERT_EQUAL(r, 0);
+
+
+	memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence));
+	fence_status.context = context_handle;
+	fence_status.ip_type = AMDGPU_HW_IP_GFX;
+	fence_status.ip_instance = 0;
+	fence_status.ring = 0;
+	fence_status.fence = ibs_request.seq_no;
+
+	r = amdgpu_cs_query_fence_status(&fence_status,
+			AMDGPU_TIMEOUT_INFINITE,0, &expired);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_list_destroy(bo_list);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle,
+				     ib_result_mc_address, 4096);
+	CU_ASSERT_EQUAL(r, 0);
+
+	flags = 0;
+	r = amdgpu_vm_unreserve_vmid(device_handle, flags);
+	CU_ASSERT_EQUAL(r, 0);
+
+
+	r = amdgpu_cs_ctx_free(context_handle);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_vm_unaligned_map(void)
+{
+	const uint64_t map_size = (4ULL << 30) - (2 << 12);
+	struct amdgpu_bo_alloc_request request = {};
+	amdgpu_bo_handle buf_handle;
+	amdgpu_va_handle handle;
+	uint64_t vmc_addr;
+	int r;
+
+	request.alloc_size = 4ULL << 30;
+	request.phys_alignment = 4096;
+	request.preferred_heap = AMDGPU_GEM_DOMAIN_VRAM;
+	request.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
+
+	r = amdgpu_bo_alloc(device_handle, &request, &buf_handle);
+	/* Don't let the test fail if the device doesn't have enough VRAM */
+	if (r)
+		return;
+
+	r = amdgpu_va_range_alloc(device_handle, amdgpu_gpu_va_range_general,
+				  4ULL << 30, 1ULL << 30, 0, &vmc_addr,
+				  &handle, 0);
+	CU_ASSERT_EQUAL(r, 0);
+	if (r)
+		goto error_va_alloc;
+
+	vmc_addr += 1 << 12;
+
+	r = amdgpu_bo_va_op(buf_handle, 0, map_size, vmc_addr, 0,
+			    AMDGPU_VA_OP_MAP);
+	CU_ASSERT_EQUAL(r, 0);
+	if (r)
+		goto error_va_alloc;
+
+	amdgpu_bo_va_op(buf_handle, 0, map_size, vmc_addr, 0,
+			AMDGPU_VA_OP_UNMAP);
+
+error_va_alloc:
+	amdgpu_bo_free(buf_handle);
+}
+
+static void amdgpu_vm_mapping_test(void)
+{
+	struct amdgpu_bo_alloc_request req = {0};
+	struct drm_amdgpu_info_device dev_info;
+	const uint64_t size = 4096;
+	amdgpu_bo_handle buf;
+	uint64_t addr;
+	int r;
+
+	req.alloc_size = size;
+	req.phys_alignment = 0;
+	req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
+	req.flags = 0;
+
+	r = amdgpu_bo_alloc(device_handle, &req, &buf);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_query_info(device_handle, AMDGPU_INFO_DEV_INFO,
+			      sizeof(dev_info), &dev_info);
+	CU_ASSERT_EQUAL(r, 0);
+
+	addr = dev_info.virtual_address_offset;
+	r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP);
+	CU_ASSERT_EQUAL(r, 0);
+
+	addr = dev_info.virtual_address_max - size;
+	r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP);
+	CU_ASSERT_EQUAL(r, 0);
+
+	if (dev_info.high_va_offset) {
+		addr = dev_info.high_va_offset;
+		r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP);
+		CU_ASSERT_EQUAL(r, 0);
+
+		addr = dev_info.high_va_max - size;
+		r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP);
+		CU_ASSERT_EQUAL(r, 0);
+	}
+
+	amdgpu_bo_free(buf);
+}
diff --git a/tests/drmdevice.c b/tests/drmdevice.c
index 9dd5098..f1c1cd3 100644
--- a/tests/drmdevice.c
+++ b/tests/drmdevice.c
@@ -36,67 +36,66 @@
 print_device_info(drmDevicePtr device, int i, bool print_revision)
 {
     printf("device[%i]\n", i);
-    printf("\tavailable_nodes %04x\n", device->available_nodes);
-    printf("\tnodes\n");
+    printf("+-> available_nodes %#04x\n", device->available_nodes);
+    printf("+-> nodes\n");
     for (int j = 0; j < DRM_NODE_MAX; j++)
         if (device->available_nodes & 1 << j)
-            printf("\t\tnodes[%d] %s\n", j, device->nodes[j]);
+            printf("|   +-> nodes[%d] %s\n", j, device->nodes[j]);
 
-    printf("\tbustype %04x\n", device->bustype);
-    printf("\tbusinfo\n");
+    printf("+-> bustype %04x\n", device->bustype);
     if (device->bustype == DRM_BUS_PCI) {
-        printf("\t\tpci\n");
-        printf("\t\t\tdomain\t%04x\n",device->businfo.pci->domain);
-        printf("\t\t\tbus\t%02x\n", device->businfo.pci->bus);
-        printf("\t\t\tdev\t%02x\n", device->businfo.pci->dev);
-        printf("\t\t\tfunc\t%1u\n", device->businfo.pci->func);
+        printf("|   +-> pci\n");
+        printf("|       +-> domain %04x\n",device->businfo.pci->domain);
+        printf("|       +-> bus    %02x\n", device->businfo.pci->bus);
+        printf("|       +-> dev    %02x\n", device->businfo.pci->dev);
+        printf("|       +-> func   %1u\n", device->businfo.pci->func);
 
-        printf("\tdeviceinfo\n");
-        printf("\t\tpci\n");
-        printf("\t\t\tvendor_id\t%04x\n", device->deviceinfo.pci->vendor_id);
-        printf("\t\t\tdevice_id\t%04x\n", device->deviceinfo.pci->device_id);
-        printf("\t\t\tsubvendor_id\t%04x\n", device->deviceinfo.pci->subvendor_id);
-        printf("\t\t\tsubdevice_id\t%04x\n", device->deviceinfo.pci->subdevice_id);
+        printf("+-> deviceinfo\n");
+        printf("    +-> pci\n");
+        printf("        +-> vendor_id     %04x\n", device->deviceinfo.pci->vendor_id);
+        printf("        +-> device_id     %04x\n", device->deviceinfo.pci->device_id);
+        printf("        +-> subvendor_id  %04x\n", device->deviceinfo.pci->subvendor_id);
+        printf("        +-> subdevice_id  %04x\n", device->deviceinfo.pci->subdevice_id);
         if (print_revision)
-            printf("\t\t\trevision_id\t%02x\n", device->deviceinfo.pci->revision_id);
+            printf("        +-> revision_id   %02x\n", device->deviceinfo.pci->revision_id);
         else
-            printf("\t\t\trevision_id\tIGNORED\n");
+            printf("        +-> revision_id   IGNORED\n");
 
     } else if (device->bustype == DRM_BUS_USB) {
-        printf("\t\tusb\n");
-        printf("\t\t\tbus\t%03u\n", device->businfo.usb->bus);
-        printf("\t\t\tdev\t%03u\n", device->businfo.usb->dev);
+        printf("|   +-> usb\n");
+        printf("|       +-> bus %03u\n", device->businfo.usb->bus);
+        printf("|       +-> dev %03u\n", device->businfo.usb->dev);
 
-        printf("\tdeviceinfo\n");
-        printf("\t\tusb\n");
-        printf("\t\t\tvendor\t%04x\n", device->deviceinfo.usb->vendor);
-        printf("\t\t\tproduct\t%04x\n", device->deviceinfo.usb->product);
+        printf("+-> deviceinfo\n");
+        printf("    +-> usb\n");
+        printf("        +-> vendor  %04x\n", device->deviceinfo.usb->vendor);
+        printf("        +-> product %04x\n", device->deviceinfo.usb->product);
     } else if (device->bustype == DRM_BUS_PLATFORM) {
         char **compatible = device->deviceinfo.platform->compatible;
 
-        printf("\t\tplatform\n");
-        printf("\t\t\tfullname\t%s\n", device->businfo.platform->fullname);
+        printf("|   +-> platform\n");
+        printf("|       +-> fullname\t%s\n", device->businfo.platform->fullname);
 
-        printf("\tdeviceinfo\n");
-        printf("\t\tplatform\n");
-        printf("\t\t\tcompatible\n");
+        printf("+-> deviceinfo\n");
+        printf("    +-> platform\n");
+        printf("        +-> compatible\n");
 
         while (*compatible) {
-            printf("\t\t\t\t%s\n", *compatible);
+            printf("                    %s\n", *compatible);
             compatible++;
         }
     } else if (device->bustype == DRM_BUS_HOST1X) {
-        char **compatible = device->deviceinfo.platform->compatible;
+        char **compatible = device->deviceinfo.host1x->compatible;
 
-        printf("\t\thost1x\n");
-        printf("\t\t\tfullname\t%s\n", device->businfo.host1x->fullname);
+        printf("|   +-> host1x\n");
+        printf("|       +-> fullname\t%s\n", device->businfo.host1x->fullname);
 
-        printf("\tdeviceinfo\n");
-        printf("\t\tplatform\n");
-        printf("\t\t\tcompatible\n");
+        printf("+-> deviceinfo\n");
+        printf("    +-> host1x\n");
+        printf("        +-> compatible\n");
 
         while (*compatible) {
-            printf("\t\t\t\t%s\n", *compatible);
+            printf("                    %s\n", *compatible);
             compatible++;
         }
     } else {
@@ -112,12 +111,16 @@
     drmDevicePtr device;
     int fd, ret, max_devices;
 
+    printf("--- Checking the number of DRM device available ---\n");
     max_devices = drmGetDevices2(0, NULL, 0);
 
     if (max_devices <= 0) {
-        printf("drmGetDevices2() has returned %d\n", max_devices);
-        return -1;
+        printf("drmGetDevices2() has not found any devices (errno=%d)\n",
+               -max_devices);
+        return 77;
     }
+    printf("--- Devices reported %d ---\n", max_devices);
+
 
     devices = calloc(max_devices, sizeof(drmDevicePtr));
     if (devices == NULL) {
@@ -125,6 +128,7 @@
         return -1;
     }
 
+    printf("--- Retrieving devices information (PCI device revision is ignored) ---\n");
     ret = drmGetDevices2(0, devices, max_devices);
     if (ret < 0) {
         printf("drmGetDevices2() returned an error %d\n", ret);
@@ -137,13 +141,14 @@
 
         for (int j = 0; j < DRM_NODE_MAX; j++) {
             if (devices[i]->available_nodes & 1 << j) {
-                printf("Opening device %d node %s\n", i, devices[i]->nodes[j]);
+                printf("--- Opening device node %s ---\n", devices[i]->nodes[j]);
                 fd = open(devices[i]->nodes[j], O_RDONLY | O_CLOEXEC, 0);
                 if (fd < 0) {
                     printf("Failed - %s (%d)\n", strerror(errno), errno);
                     continue;
                 }
 
+                printf("--- Retrieving device info, for node %s ---\n", devices[i]->nodes[j]);
                 if (drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, &device) == 0) {
                     print_device_info(device, i, true);
                     drmFreeDevice(&device);
diff --git a/tests/drmsl.c b/tests/drmsl.c
index d0ac0ef..d1b59a8 100644
--- a/tests/drmsl.c
+++ b/tests/drmsl.c
@@ -106,7 +106,9 @@
     return usec;
 }
 
-static void print_neighbors(void *list, unsigned long key)
+static void print_neighbors(void *list, unsigned long key,
+                            unsigned long expected_prev,
+                            unsigned long expected_next)
 {
     unsigned long prev_key = 0;
     unsigned long next_key = 0;
@@ -119,6 +121,16 @@
 				  &next_key, &next_value);
     printf("Neighbors of %5lu: %d %5lu %5lu\n",
 	   key, retval, prev_key, next_key);
+    if (prev_key != expected_prev) {
+        fprintf(stderr, "Unexpected neighbor: %5lu. Expected: %5lu\n",
+                prev_key, expected_prev);
+	exit(1);
+    }
+    if (next_key != expected_next) {
+        fprintf(stderr, "Unexpected neighbor: %5lu. Expected: %5lu\n",
+                next_key, expected_next);
+	exit(1);
+    }
 }
 
 int main(void)
@@ -138,13 +150,13 @@
     print(list);
     printf("\n==============================\n\n");
 
-    print_neighbors(list, 0);
-    print_neighbors(list, 50);
-    print_neighbors(list, 51);
-    print_neighbors(list, 123);
-    print_neighbors(list, 200);
-    print_neighbors(list, 213);
-    print_neighbors(list, 256);
+    print_neighbors(list, 0, 0, 50);
+    print_neighbors(list, 50, 0, 50);
+    print_neighbors(list, 51, 50, 123);
+    print_neighbors(list, 123, 50, 123);
+    print_neighbors(list, 200, 123, 213);
+    print_neighbors(list, 213, 123, 213);
+    print_neighbors(list, 256, 213, 256);
     printf("\n==============================\n\n");
 
     drmSLDelete(list, 50);
diff --git a/tests/drmstat.c b/tests/drmstat.c
deleted file mode 100644
index 023aa06..0000000
--- a/tests/drmstat.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* drmstat.c -- DRM device status and testing program
- * Created: Tue Jan  5 08:19:24 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * 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 (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
- * PRECISION INSIGHT 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: Rickard E. (Rik) Faith <faith@valinux.com>
- * 
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include <getopt.h>
-#include <strings.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#ifdef HAVE_ALLOCA_H
-# include <alloca.h>
-#endif
-#include "xf86drm.h"
-
-int sigio_fd;
-
-static double usec(struct timeval *end, struct timeval *start)
-{
-    double e = end->tv_sec   * 1000000 + end->tv_usec;
-    double s = start->tv_sec * 1000000 + start->tv_usec;
-
-    return e - s;
-}
-
-static void getversion(int fd)
-{
-    drmVersionPtr version;
-    
-    version = drmGetVersion(fd);
-    if (version) {
-	printf( "Name: %s\n", version->name ? version->name : "?" );
-	printf( "    Version: %d.%d.%d\n",
-		version->version_major,
-		version->version_minor,
-		version->version_patchlevel );
-	printf( "    Date: %s\n", version->date ? version->date : "?" );
-	printf( "    Desc: %s\n", version->desc ? version->desc : "?" );
-	drmFreeVersion(version);
-    } else {
-	printf( "No driver available\n" );
-    }
-}
-
-static void process_sigio(char *device)
-{
-    int              fd;
-
-    if ((fd = open(device, 0)) < 0) {
-	drmError(-errno, __func__);
-	exit(1);
-    }
-
-    sigio_fd = fd;
-    for (;;) sleep(60);
-}
-
-int main(int argc, char **argv)
-{
-    int            c;
-    int            r  = 0;
-    int            fd = -1;
-    drm_handle_t      handle;
-    void           *address;
-    char           *pt;
-    unsigned long  count;
-    unsigned long  offset;
-    unsigned long  size;
-    drm_context_t  context;
-    int            loops;
-    char           buf[1024];
-    int            i;
-    drmBufInfoPtr  info;
-    drmBufMapPtr   bufs;
-    drmLockPtr     lock;
-    int            secs;
-
-    while ((c = getopt(argc, argv,
-		       "lc:vo:O:f:s:w:W:b:r:R:P:L:C:XS:B:F:")) != EOF)
-	switch (c) {
-	case 'F':
-	    count  = strtoul(optarg, NULL, 0);
-	    if (!fork()) {
-		dup(fd);
-		sleep(count);
-	    }
-	    close(fd);
-	    break;
-	case 'v': getversion(fd);                                        break;
-	case 'X':
-	    if ((r = drmCreateContext(fd, &context))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    printf( "Got %d\n", context);
-	    break;
-	case 'S':
-	    process_sigio(optarg);
-	    break;
-	case 'C':
-	    if ((r = drmSwitchToContext(fd, strtoul(optarg, NULL, 0)))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    break;
-	case 'c':
-	    if ((r = drmSetBusid(fd,optarg))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    break;
-	case 'o':
-	    if ((fd = drmOpen(optarg, NULL)) < 0) {
-		drmError(fd, argv[0]);
-		return 1;
-	    }
-	    break;
-	case 'O':
-	    if ((fd = drmOpen(NULL, optarg)) < 0) {
-		drmError(fd, argv[0]);
-		return 1;
-	    }
-	    break;
-	case 'B':		/* Test buffer allocation */
-	    count  = strtoul(optarg, &pt, 0);
-	    size   = strtoul(pt+1, &pt, 0);
-	    secs   = strtoul(pt+1, NULL, 0);
-	    {
-		drmDMAReq      dma;
-		int            *indices, *sizes;
-
-		indices = alloca(sizeof(*indices) * count);
-		sizes   = alloca(sizeof(*sizes)   * count);
-		dma.context         = context;
-		dma.send_count      = 0;
-		dma.request_count   = count;
-		dma.request_size    = size;
-		dma.request_list    = indices;
-		dma.request_sizes   = sizes;
-		dma.flags           = DRM_DMA_WAIT;
-		if ((r = drmDMA(fd, &dma))) {
-		    drmError(r, argv[0]);
-		    return 1;
-		}
-		for (i = 0; i < dma.granted_count; i++) {
-		    printf("%5d: index = %d, size = %d\n",
-			   i, dma.request_list[i], dma.request_sizes[i]);
-		}
-		sleep(secs);
-		drmFreeBufs(fd, dma.granted_count, indices);
-	    }
-	    break;
-	case 'b':
-	    count   = strtoul(optarg, &pt, 0);
-	    size    = strtoul(pt+1, NULL, 0);
-	    if ((r = drmAddBufs(fd, count, size, 0, 65536)) < 0) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    if (!(info = drmGetBufInfo(fd))) {
-		drmError(0, argv[0]);
-		return 1;
-	    }
-	    for (i = 0; i < info->count; i++) {
-		printf("%5d buffers of size %6d (low = %d, high = %d)\n",
-		       info->list[i].count,
-		       info->list[i].size,
-		       info->list[i].low_mark,
-		       info->list[i].high_mark);
-	    }
-	    if ((r = drmMarkBufs(fd, 0.50, 0.80))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    if (!(info = drmGetBufInfo(fd))) {
-		drmError(0, argv[0]);
-		return 1;
-	    }
-	    for (i = 0; i < info->count; i++) {
-		printf("%5d buffers of size %6d (low = %d, high = %d)\n",
-		       info->list[i].count,
-		       info->list[i].size,
-		       info->list[i].low_mark,
-		       info->list[i].high_mark);
-	    }
-	    printf("===== /proc/dri/0/mem =====\n");
-	    sprintf(buf, "cat /proc/dri/0/mem");
-	    system(buf);
-#if 1
-	    if (!(bufs = drmMapBufs(fd))) {
-		drmError(0, argv[0]);
-		return 1;
-	    }
-	    printf("===============================\n");
-	    printf( "%d bufs\n", bufs->count);
-	    for (i = 0; i < bufs->count; i++) {
-		printf( "  %4d: %8d bytes at %p\n",
-			i,
-			bufs->list[i].total,
-			bufs->list[i].address);
-	    }
-	    printf("===== /proc/dri/0/vma =====\n");
-	    sprintf(buf, "cat /proc/dri/0/vma");
-	    system(buf);
-#endif
-	    break;
-	case 'f':
-	    offset  = strtoul(optarg, &pt, 0);
-	    size    = strtoul(pt+1, NULL, 0);
-	    handle  = 0;
-	    if ((r = drmAddMap(fd, offset, size,
-			       DRM_FRAME_BUFFER, 0, &handle))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    printf("0x%08lx:0x%04lx added\n", offset, size);
-	    printf("===== /proc/dri/0/mem =====\n");
-	    sprintf(buf, "cat /proc/dri/0/mem");
-	    system(buf);
-	    break;
-	case 'r':
-	case 'R':
-	    offset  = strtoul(optarg, &pt, 0);
-	    size    = strtoul(pt+1, NULL, 0);
-	    handle  = 0;
-	    if ((r = drmAddMap(fd, offset, size,
-			       DRM_REGISTERS,
-			       c == 'R' ? DRM_READ_ONLY : 0,
-			       &handle))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    printf("0x%08lx:0x%04lx added\n", offset, size);
-	    printf("===== /proc/dri/0/mem =====\n");
-	    sprintf(buf, "cat /proc/dri/0/mem");
-	    system(buf);
-	    break;
-	case 's':
-	    size = strtoul(optarg, &pt, 0);
-	    handle = 0;
-	    if ((r = drmAddMap(fd, 0, size,
-			       DRM_SHM, DRM_CONTAINS_LOCK,
-			       &handle))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    printf("0x%04lx byte shm added at 0x%08lx\n", size, handle);
-	    sprintf(buf, "cat /proc/dri/0/vm");
-	    system(buf);
-	    break;
-	case 'P':
-	    offset  = strtoul(optarg, &pt, 0);
-	    size    = strtoul(pt+1, NULL, 0);
-	    address = NULL;
-	    if ((r = drmMap(fd, offset, size, &address))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    printf("0x%08lx:0x%04lx mapped at %p for pid %d\n",
-		   offset, size, address, getpid());
-	    printf("===== /proc/dri/0/vma =====\n");
-	    sprintf(buf, "cat /proc/dri/0/vma");
-	    system(buf);
-	    mprotect((void *)offset, size, PROT_READ);
-	    printf("===== /proc/dri/0/vma =====\n");
-	    sprintf(buf, "cat /proc/dri/0/vma");
-	    system(buf);
-	    break;
-	case 'w':
-	case 'W':
-	    offset  = strtoul(optarg, &pt, 0);
-	    size    = strtoul(pt+1, NULL, 0);
-	    address = NULL;
-	    if ((r = drmMap(fd, offset, size, &address))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    printf("0x%08lx:0x%04lx mapped at %p for pid %d\n",
-		   offset, size, address, getpid());
-	    printf("===== /proc/%d/maps =====\n", getpid());
-	    sprintf(buf, "cat /proc/%d/maps", getpid());
-	    system(buf);
-	    printf("===== /proc/dri/0/mem =====\n");
-	    sprintf(buf, "cat /proc/dri/0/mem");
-	    system(buf);
-	    printf("===== /proc/dri/0/vma =====\n");
-	    sprintf(buf, "cat /proc/dri/0/vma");
-	    system(buf);
-	    printf("===== READING =====\n");
-	    for (i = 0; i < 0x10; i++)
-		printf("%02x ", (unsigned int)((unsigned char *)address)[i]);
-	    printf("\n");
-	    if (c == 'w') {
-		printf("===== WRITING =====\n");
-		for (i = 0; i < size; i+=2) {
-		    ((char *)address)[i]   = i & 0xff;
-		    ((char *)address)[i+1] = i & 0xff;
-		}
-	    }
-	    printf("===== READING =====\n");
-	    for (i = 0; i < 0x10; i++)
-		printf("%02x ", (unsigned int)((unsigned char *)address)[i]);
-	    printf("\n");
-	    printf("===== /proc/dri/0/vma =====\n");
-	    sprintf(buf, "cat /proc/dri/0/vma");
-	    system(buf);
-	    break;
-	case 'L':
-	    context = strtoul(optarg, &pt, 0);
-	    offset  = strtoul(pt+1, &pt, 0);
-	    size    = strtoul(pt+1, &pt, 0);
-	    loops   = strtoul(pt+1, NULL, 0);
-	    address = NULL;
-	    if ((r = drmMap(fd, offset, size, &address))) {
-		drmError(r, argv[0]);
-		return 1;
-	    }
-	    lock       = address;
-#if 1
-	    {
-		int            counter = 0;
-		struct timeval loop_start, loop_end;
-		struct timeval lock_start, lock_end;
-		double         wt;
-#define HISTOSIZE 9
-		int            histo[HISTOSIZE];
-		int            output = 0;
-		int            fast   = 0;
-
-		if (loops < 0) {
-		    loops = -loops;
-		    ++output;
-		}
-
-		for (i = 0; i < HISTOSIZE; i++) histo[i] = 0;
-
-		gettimeofday(&loop_start, NULL);
-		for (i = 0; i < loops; i++) {
-		    gettimeofday(&lock_start, NULL);
-		    DRM_LIGHT_LOCK_COUNT(fd,lock,context,fast);
-		    gettimeofday(&lock_end, NULL);
-		    DRM_UNLOCK(fd,lock,context);
-		    ++counter;
-		    wt = usec(&lock_end, &lock_start);
-		    if      (wt <=      2.5) ++histo[8];
-		    if      (wt <       5.0) ++histo[0];
-		    else if (wt <      50.0) ++histo[1];
-		    else if (wt <     500.0) ++histo[2];
-		    else if (wt <    5000.0) ++histo[3];
-		    else if (wt <   50000.0) ++histo[4];
-		    else if (wt <  500000.0) ++histo[5];
-		    else if (wt < 5000000.0) ++histo[6];
-		    else                     ++histo[7];
-		    if (output) printf( "%.2f uSec, %d fast\n", wt, fast);
-		}
-		gettimeofday(&loop_end, NULL);
-		printf( "Average wait time = %.2f usec, %d fast\n",
-			usec(&loop_end, &loop_start) /  counter, fast);
-		printf( "%9d <=     2.5 uS\n", histo[8]);
-		printf( "%9d <        5 uS\n", histo[0]);
-		printf( "%9d <       50 uS\n", histo[1]);
-		printf( "%9d <      500 uS\n", histo[2]);
-		printf( "%9d <     5000 uS\n", histo[3]);
-		printf( "%9d <    50000 uS\n", histo[4]);
-		printf( "%9d <   500000 uS\n", histo[5]);
-		printf( "%9d <  5000000 uS\n", histo[6]);
-		printf( "%9d >= 5000000 uS\n", histo[7]);
-	    }
-#else
-	    printf( "before lock: 0x%08x\n", lock->lock);
-	    printf( "lock: 0x%08x\n", lock->lock);
-	    sleep(5);
-	    printf( "unlock: 0x%08x\n", lock->lock);
-#endif
-	    break;
-	default:
-	    fprintf( stderr, "Usage: drmstat [options]\n" );
-	    return 1;
-	}
-
-    return r; 
-}
-
-int xf86ConfigDRI[10];
diff --git a/tests/etnaviv/Makefile.am b/tests/etnaviv/Makefile.am
index 0631864..3e0c612 100644
--- a/tests/etnaviv/Makefile.am
+++ b/tests/etnaviv/Makefile.am
@@ -1,4 +1,5 @@
 AM_CFLAGS = \
+	-fvisibility=hidden \
 	-I $(top_srcdir)/include/drm \
 	-I $(top_srcdir)/etnaviv \
 	-I $(top_srcdir)
@@ -28,6 +29,7 @@
 	write_bmp.h
 
 etnaviv_cmd_stream_test_LDADD = \
+	$(top_builddir)/libdrm.la \
 	$(top_builddir)/etnaviv/libdrm_etnaviv.la
 
 etnaviv_cmd_stream_test_SOURCES = \
diff --git a/tests/etnaviv/etnaviv_2d_test.c b/tests/etnaviv/etnaviv_2d_test.c
index 10751c7..8dd77b6 100644
--- a/tests/etnaviv/etnaviv_2d_test.c
+++ b/tests/etnaviv/etnaviv_2d_test.c
@@ -24,10 +24,6 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
diff --git a/tests/etnaviv/etnaviv_bo_cache_test.c b/tests/etnaviv/etnaviv_bo_cache_test.c
index fb01f8d..7fb0629 100644
--- a/tests/etnaviv/etnaviv_bo_cache_test.c
+++ b/tests/etnaviv/etnaviv_bo_cache_test.c
@@ -24,10 +24,6 @@
  *    Christian Gmeiner <christian.gmeiner@gmail.com>
  */
 
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
 #undef NDEBUG
 #include <assert.h>
 
diff --git a/tests/etnaviv/meson.build b/tests/etnaviv/meson.build
new file mode 100644
index 0000000..8b4a3cf
--- /dev/null
+++ b/tests/etnaviv/meson.build
@@ -0,0 +1,45 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+inc_etnaviv_tests = [inc_root, inc_drm, include_directories('../../etnaviv')]
+
+etnaviv_2d_test = executable(
+  'etnaviv_2d_test',
+  files('etnaviv_2d_test.c', 'write_bmp.c'),
+  include_directories : inc_etnaviv_tests,
+  link_with : [libdrm, libdrm_etnaviv],
+  install : with_install_tests,
+)
+
+etnaviv_cmd_stream_test = executable(
+  'etnaviv_cmd_stream_test',
+  files('etnaviv_cmd_stream_test.c'),
+  include_directories : inc_etnaviv_tests,
+  link_with : [libdrm, libdrm_etnaviv],
+  install : with_install_tests,
+)
+
+etnaviv_bo_cache_test = executable(
+  'etnaviv_bo_cache_test',
+  files('etnaviv_bo_cache_test.c'),
+  include_directories : inc_etnaviv_tests,
+  link_with : [libdrm, libdrm_etnaviv],
+  install : with_install_tests,
+)
diff --git a/tests/etnaviv/write_bmp.c b/tests/etnaviv/write_bmp.c
index 7ae0646..f7b6bc6 100644
--- a/tests/etnaviv/write_bmp.c
+++ b/tests/etnaviv/write_bmp.c
@@ -63,7 +63,7 @@
 	unsigned int unused[12];
 } __attribute__((__packed__));
 
-static int
+static void
 bmp_header_write(int fd, int width, int height, int bgra, int noflip, int alpha)
 {
 	struct bmp_header bmp_header = {
@@ -98,8 +98,6 @@
 
 	write(fd, &bmp_header, sizeof(struct bmp_header));
 	write(fd, &dib_header, sizeof(struct dib_header));
-
-	return 0;
 }
 
 void
diff --git a/tests/exynos/Makefile.am b/tests/exynos/Makefile.am
index b636172..9658fb4 100644
--- a/tests/exynos/Makefile.am
+++ b/tests/exynos/Makefile.am
@@ -1,6 +1,7 @@
 AM_CFLAGS = \
 	-pthread \
 	$(WARN_CFLAGS)\
+	-fvisibility=hidden \
 	-I $(top_srcdir)/include/drm \
 	-I $(top_srcdir)/libkms/ \
 	-I $(top_srcdir)/exynos \
diff --git a/tests/exynos/exynos_fimg2d_event.c b/tests/exynos/exynos_fimg2d_event.c
index 9ed5a30..353e087 100644
--- a/tests/exynos/exynos_fimg2d_event.c
+++ b/tests/exynos/exynos_fimg2d_event.c
@@ -1,17 +1,24 @@
 /*
  * Copyright (C) 2015 - Tobias Jakobi
  *
- * This is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation, either version 2 of the License,
- * or (at your option) any later version.
+ * 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:
  *
- * It is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with it. If not, see <http://www.gnu.org/licenses/>.
+ * 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
+ * VA LINUX SYSTEMS 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.
  */
 
 #include <unistd.h>
diff --git a/tests/exynos/exynos_fimg2d_perf.c b/tests/exynos/exynos_fimg2d_perf.c
index 1699bba..97691a7 100644
--- a/tests/exynos/exynos_fimg2d_perf.c
+++ b/tests/exynos/exynos_fimg2d_perf.c
@@ -1,17 +1,24 @@
 /*
  * Copyright (C) 2015 - Tobias Jakobi
  *
- * This is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation, either version 2 of the License,
- * or (at your option) any later version.
+ * 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:
  *
- * It is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with it. If not, see <http://www.gnu.org/licenses/>.
+ * 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
+ * VA LINUX SYSTEMS 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.
  */
 
 #include <stdlib.h>
@@ -267,13 +274,6 @@
 		goto out;
 	}
 
-	if (bufw == 0 || bufh == 0) {
-		fprintf(stderr, "error: buffer width/height should be non-zero.\n");
-		ret = -1;
-
-		goto out;
-	}
-
 	fd = drmOpen("exynos", NULL);
 	if (fd < 0) {
 		fprintf(stderr, "error: failed to open drm\n");
diff --git a/tests/exynos/exynos_fimg2d_test.c b/tests/exynos/exynos_fimg2d_test.c
index 797fb6e..99bb923 100644
--- a/tests/exynos/exynos_fimg2d_test.c
+++ b/tests/exynos/exynos_fimg2d_test.c
@@ -3,17 +3,26 @@
  * Authors:
  *	Inki Dae <inki.dae@samsung.com>
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 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
+ * VA LINUX SYSTEMS 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.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -59,7 +68,6 @@
 		if (!connector) {
 			fprintf(stderr, "could not get connector %i: %s\n",
 				resources->connectors[i], strerror(errno));
-			drmModeFreeConnector(connector);
 			continue;
 		}
 
@@ -98,7 +106,6 @@
 		if (!c->encoder) {
 			fprintf(stderr, "could not get encoder %i: %s\n",
 				resources->encoders[i], strerror(errno));
-			drmModeFreeEncoder(c->encoder);
 			continue;
 		}
 
@@ -264,7 +271,8 @@
 		userptr = (unsigned long)malloc(size);
 		if (!userptr) {
 			fprintf(stderr, "failed to allocate userptr.\n");
-			return -EFAULT;
+			ret = -EFAULT;
+			goto fail;
 		}
 
 		src_img.user_ptr[0].userptr = userptr;
@@ -469,7 +477,8 @@
 		userptr = (unsigned long)malloc(size);
 		if (!userptr) {
 			fprintf(stderr, "failed to allocate userptr.\n");
-			return -EFAULT;
+			ret = -EFAULT;
+			goto fail;
 		}
 
 		src_img.user_ptr[0].userptr = userptr;
@@ -520,9 +529,10 @@
 fail:
 	g2d_fini(ctx);
 
-	return 0;
+	return ret;
 }
 
+#ifdef EXYNOS_G2D_USERPTR_TEST
 static int g2d_blend_test(struct exynos_device *dev,
 					struct exynos_bo *src,
 					struct exynos_bo *dst,
@@ -557,7 +567,8 @@
 		userptr = (unsigned long)malloc(size);
 		if (!userptr) {
 			fprintf(stderr, "failed to allocate userptr.\n");
-			return -EFAULT;
+			ret = -EFAULT;
+			goto fail;
 		}
 
 		src_img.user_ptr[0].userptr = userptr;
@@ -619,8 +630,9 @@
 fail:
 	g2d_fini(ctx);
 
-	return 0;
+	return ret;
 }
+#endif
 
 static int g2d_checkerboard_test(struct exynos_device *dev,
 					struct exynos_bo *src,
@@ -645,8 +657,8 @@
 	dst_y = 0;
 
 	checkerboard = create_checkerboard_pattern(screen_width / 32, screen_height / 32, 32);
-	if (checkerboard == NULL) {
-		ret = -1;
+	if (!checkerboard) {
+		ret = -EFAULT;
 		goto fail;
 	}
 
@@ -755,8 +767,8 @@
 
 	dev = exynos_device_create(fd);
 	if (!dev) {
-		drmClose(dev->fd);
-		return -EFAULT;
+		ret = -EFAULT;
+		goto err_drm_close;
 	}
 
 	resources = drmModeGetResources(dev->fd);
@@ -764,7 +776,7 @@
 		fprintf(stderr, "drmModeGetResources failed: %s\n",
 				strerror(errno));
 		ret = -EFAULT;
-		goto err_drm_close;
+		goto err_dev_destory;
 	}
 
 	connector_find_mode(dev->fd, &con, resources);
@@ -773,7 +785,7 @@
 	if (!con.mode) {
 		fprintf(stderr, "failed to find usable connector\n");
 		ret = -EFAULT;
-		goto err_drm_close;
+		goto err_dev_destory;
 	}
 
 	screen_width = con.mode->hdisplay;
@@ -782,7 +794,7 @@
 	if (screen_width == 0 || screen_height == 0) {
 		fprintf(stderr, "failed to find sane resolution on connector\n");
 		ret = -EFAULT;
-		goto err_drm_close;
+		goto err_dev_destory;
 	}
 
 	printf("screen width = %d, screen height = %d\n", screen_width,
@@ -791,7 +803,7 @@
 	bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
 	if (!bo) {
 		ret = -EFAULT;
-		goto err_drm_close;
+		goto err_dev_destory;
 	}
 
 	handles[0] = bo->handle;
@@ -864,7 +876,7 @@
 	 *
 	 * Disable the test for now, until the kernel code has been sanitized.
 	 */
-#if 0
+#ifdef EXYNOS_G2D_USERPTR_TEST
 	ret  = g2d_blend_test(dev, src, bo, G2D_IMGBUF_USERPTR);
 	if (ret < 0)
 		fprintf(stderr, "failed to test blend operation.\n");
@@ -882,9 +894,11 @@
 err_destroy_buffer:
 	exynos_destroy_buffer(bo);
 
-err_drm_close:
-	drmClose(dev->fd);
+err_dev_destory:
 	exynos_device_destroy(dev);
 
-	return 0;
+err_drm_close:
+	drmClose(fd);
+
+	return ret;
 }
diff --git a/tests/exynos/meson.build b/tests/exynos/meson.build
new file mode 100644
index 0000000..3a048e8
--- /dev/null
+++ b/tests/exynos/meson.build
@@ -0,0 +1,54 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+inc_exynos = include_directories('../../exynos')
+
+if with_libkms
+  exynos_fimg2d_test = executable(
+    'exynos_fimg2d_test',
+    files('exynos_fimg2d_test.c'),
+    c_args : libdrm_c_args,
+    include_directories : [inc_root, inc_drm, inc_exynos,
+                           include_directories('../../libkms')],
+    link_with : [libdrm, libkms, libdrm_exynos],
+    dependencies : dep_threads,
+    install : with_install_tests,
+  )
+endif
+
+exynos_fimg2d_perf = executable(
+  'exynos_fimg2d_perf',
+  files('exynos_fimg2d_perf.c'),
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_drm, inc_exynos],
+  link_with : [libdrm, libdrm_exynos],
+  dependencies : dep_threads,
+  install : with_install_tests,
+)
+
+exynos_fimg2d_event = executable(
+  'exynos_fimg2d_event',
+  files('exynos_fimg2d_event.c'),
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_drm, inc_exynos],
+  link_with : [libdrm, libdrm_exynos],
+  dependencies : dep_threads,
+  install : with_install_tests,
+)
diff --git a/tests/kms/Makefile.am b/tests/kms/Makefile.am
index 6645af7..4224200 100644
--- a/tests/kms/Makefile.am
+++ b/tests/kms/Makefile.am
@@ -4,7 +4,8 @@
 	-I$(top_srcdir)
 
 AM_CFLAGS = \
-	$(WARN_CFLAGS)
+	$(WARN_CFLAGS) \
+	-fvisibility=hidden
 
 noinst_LTLIBRARIES = libkms-test.la
 
diff --git a/tests/kms/kms-steal-crtc.c b/tests/kms/kms-steal-crtc.c
index 4b830d2..cd40758 100644
--- a/tests/kms/kms-steal-crtc.c
+++ b/tests/kms/kms-steal-crtc.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
diff --git a/tests/kms/kms-universal-planes.c b/tests/kms/kms-universal-planes.c
index 89057bb..2163c98 100644
--- a/tests/kms/kms-universal-planes.c
+++ b/tests/kms/kms-universal-planes.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <fcntl.h>
 #include <getopt.h>
 #include <stdbool.h>
diff --git a/tests/kms/libkms-test-crtc.c b/tests/kms/libkms-test-crtc.c
index 3adb490..2c28fac 100644
--- a/tests/kms/libkms-test-crtc.c
+++ b/tests/kms/libkms-test-crtc.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include "libkms-test.h"
 
 struct kms_crtc *kms_crtc_create(struct kms_device *device, uint32_t id)
diff --git a/tests/kms/libkms-test-device.c b/tests/kms/libkms-test-device.c
index 53c7349..d3bb11c 100644
--- a/tests/kms/libkms-test-device.c
+++ b/tests/kms/libkms-test-device.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -67,7 +63,7 @@
 
 	device->screens = calloc(res->count_connectors, sizeof(screen));
 	if (!device->screens)
-		return;
+		goto err_free_resources;
 
 	for (i = 0; i < res->count_connectors; i++) {
 		unsigned int *count;
@@ -97,6 +93,7 @@
 		device->num_screens++;
 	}
 
+err_free_resources:
 	drmModeFreeResources(res);
 }
 
@@ -112,7 +109,7 @@
 
 	device->crtcs = calloc(res->count_crtcs, sizeof(crtc));
 	if (!device->crtcs)
-		return;
+		goto err_free_resources;
 
 	for (i = 0; i < res->count_crtcs; i++) {
 		crtc = kms_crtc_create(device, res->crtcs[i]);
@@ -123,6 +120,7 @@
 		device->num_crtcs++;
 	}
 
+err_free_resources:
 	drmModeFreeResources(res);
 }
 
@@ -138,7 +136,7 @@
 
 	device->planes = calloc(res->count_planes, sizeof(plane));
 	if (!device->planes)
-		return;
+		goto err_free_resources;
 
 	for (i = 0; i < res->count_planes; i++) {
 		plane = kms_plane_create(device, res->planes[i]);
@@ -149,6 +147,7 @@
 		device->num_planes++;
 	}
 
+err_free_resources:
 	drmModeFreePlaneResources(res);
 }
 
diff --git a/tests/kms/libkms-test-framebuffer.c b/tests/kms/libkms-test-framebuffer.c
index c9e5ad3..9bb2d95 100644
--- a/tests/kms/libkms-test-framebuffer.c
+++ b/tests/kms/libkms-test-framebuffer.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <string.h>
 
diff --git a/tests/kms/libkms-test-plane.c b/tests/kms/libkms-test-plane.c
index 8eb78af..6c40a3c 100644
--- a/tests/kms/libkms-test-plane.c
+++ b/tests/kms/libkms-test-plane.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <string.h>
 
diff --git a/tests/kms/libkms-test-screen.c b/tests/kms/libkms-test-screen.c
index 3369022..bbe972a 100644
--- a/tests/kms/libkms-test-screen.c
+++ b/tests/kms/libkms-test-screen.c
@@ -21,10 +21,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <string.h>
 
diff --git a/tests/kms/meson.build b/tests/kms/meson.build
new file mode 100644
index 0000000..91371aa
--- /dev/null
+++ b/tests/kms/meson.build
@@ -0,0 +1,49 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+
+libkms_test = static_library(
+  'kms-test',
+  files(
+    'libkms-test-crtc.c', 'libkms-test-device.c', 'libkms-test-framebuffer.c',
+    'libkms-test-plane.c', 'libkms-test-screen.c',
+  ),
+  include_directories : [inc_root, inc_tests, inc_drm],
+  link_with : libdrm,
+  c_args : libdrm_c_args,
+)
+
+kms_steal_crtc = executable(
+  'kms-steal-crtc',
+  files('kms-steal-crtc.c'),
+  dependencies : dep_cairo,
+  include_directories : [inc_root, inc_tests, inc_drm],
+  link_with : [libkms_test, libutil],
+  install : with_install_tests,
+)
+
+kms_universal_planes = executable(
+  'kms-universal-planes',
+  files('kms-universal-planes.c'),
+  dependencies : dep_cairo,
+  include_directories : [inc_root, inc_tests, inc_drm],
+  link_with : [libkms_test],
+  install : with_install_tests,
+)
diff --git a/tests/kmstest/Makefile.am b/tests/kmstest/Makefile.am
index ced541b..4c993b0 100644
--- a/tests/kmstest/Makefile.am
+++ b/tests/kmstest/Makefile.am
@@ -1,5 +1,6 @@
 AM_CFLAGS = \
 	$(WARN_CFLAGS)\
+	-fvisibility=hidden \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/libkms/ \
 	-I$(top_srcdir)/tests/ \
diff --git a/tests/kmstest/meson.build b/tests/kmstest/meson.build
new file mode 100644
index 0000000..4fb870f
--- /dev/null
+++ b/tests/kmstest/meson.build
@@ -0,0 +1,30 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+kmstest = executable(
+  'kmstest',
+  files('main.c'),
+  c_args : libdrm_c_args,
+  include_directories : [
+    inc_root, inc_tests, include_directories('../../libkms'), inc_drm,
+  ],
+  link_with : [libutil, libkms, libdrm],
+  install : with_install_tests,
+)
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000..6c8ddd9
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,86 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+inc_tests = include_directories('.')
+
+subdir('util')
+subdir('kms')
+subdir('modeprint')
+subdir('proptest')
+subdir('modetest')
+subdir('vbltest')
+if with_libkms
+  subdir('kmstest')
+endif
+if with_radeon
+  subdir('radeon')
+endif
+if with_amdgpu
+  subdir('amdgpu')
+endif
+if with_exynos
+  subdir('exynos')
+endif
+if with_tegra
+  subdir('tegra')
+endif
+if with_etnaviv
+  subdir('etnaviv')
+endif
+if with_nouveau
+  subdir('nouveau')
+endif
+
+drmsl = executable(
+  'drmsl',
+  files('drmsl.c'),
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  c_args : libdrm_c_args,
+)
+
+hash = executable(
+  'hash',
+  files('hash.c'),
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  c_args : libdrm_c_args,
+)
+
+random = executable(
+  'random',
+  files('random.c'),
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  c_args : libdrm_c_args,
+)
+
+drmdevice = executable(
+  'drmdevice',
+  files('drmdevice.c'),
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  c_args : libdrm_c_args,
+)
+
+test('random', random, timeout : 240)
+test('hash', hash)
+test('drmsl', drmsl)
+test('drmdevice', drmdevice)
diff --git a/tests/modeprint/Makefile.am b/tests/modeprint/Makefile.am
index 601dbc9..568185f 100644
--- a/tests/modeprint/Makefile.am
+++ b/tests/modeprint/Makefile.am
@@ -1,5 +1,6 @@
 AM_CFLAGS = \
 	$(WARN_CFLAGS)\
+	-fvisibility=hidden \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/tests \
 	-I$(top_srcdir)
@@ -15,4 +16,5 @@
 modeprint_SOURCES = \
 	modeprint.c
 modeprint_LDADD = \
+	$(top_builddir)/tests/util/libutil.la \
 	$(top_builddir)/libdrm.la
diff --git a/tests/modeprint/meson.build b/tests/modeprint/meson.build
new file mode 100644
index 0000000..0801808
--- /dev/null
+++ b/tests/modeprint/meson.build
@@ -0,0 +1,29 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+modeprint = executable(
+  'modeprint',
+  files('modeprint.c'),
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_tests, inc_drm],
+  link_with : [libdrm, libutil],
+  dependencies : dep_threads,
+  install : with_install_tests,
+)
diff --git a/tests/modeprint/modeprint.c b/tests/modeprint/modeprint.c
index 0d85410..ad727e1 100644
--- a/tests/modeprint/modeprint.c
+++ b/tests/modeprint/modeprint.c
@@ -42,6 +42,7 @@
 #include "xf86drmMode.h"
 
 #include "util/common.h"
+#include "util/kms.h"
 
 int current;
 int connectors;
@@ -54,20 +55,6 @@
 int fbs;
 char *module_name;
 
-static const char* getConnectionText(drmModeConnection conn)
-{
-	switch (conn) {
-	case DRM_MODE_CONNECTED:
-		return "connected";
-	case DRM_MODE_DISCONNECTED:
-		return "disconnected";
-	case DRM_MODE_UNKNOWNCONNECTION:
-	default:
-		return "unknown";
-	}
-
-}
-
 static int printMode(struct drm_mode_modeinfo *mode)
 {
 	if (full_modes) {
@@ -141,40 +128,24 @@
 	return 0;
 }
 
-static const char * const output_names[] = { "None",
-					     "VGA",
-					     "DVI-I",
-					     "DVI-D",
-					     "DVI-A",
-					     "Composite",
-					     "SVIDEO",
-					     "LVDS",
-					     "Component",
-					     "DIN",
-					     "DP",
-					     "HDMI-A",
-					     "HDMI-B",
-					     "TV",
-					     "eDP",
-					     "Virtual",
-					     "DSI",
-};
-
 static int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id)
 {
 	int i = 0;
 	struct drm_mode_modeinfo *mode = NULL;
 	drmModePropertyPtr props;
+	const char *connector_type_name = NULL;
 
-	if (connector->connector_type < ARRAY_SIZE(output_names))
-		printf("Connector: %s-%d\n", output_names[connector->connector_type],
+	connector_type_name = util_lookup_connector_type_name(connector->connector_type);
+
+	if (connector_type_name)
+		printf("Connector: %s-%d\n", connector_type_name,
 			connector->connector_type_id);
 	else
 		printf("Connector: %d-%d\n", connector->connector_type,
 			connector->connector_type_id);
 	printf("\tid             : %i\n", id);
 	printf("\tencoder id     : %i\n", connector->encoder_id);
-	printf("\tconn           : %s\n", getConnectionText(connector->connection));
+	printf("\tconn           : %s\n", util_lookup_connector_status_name(connector->connection));
 	printf("\tsize           : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight);
 	printf("\tcount_modes    : %i\n", connector->count_modes);
 	printf("\tcount_props    : %i\n", connector->count_props);
@@ -215,7 +186,13 @@
 
 static int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id)
 {
-	printf("Encoder\n");
+	const char *encoder_name;
+
+	encoder_name = util_lookup_encoder_type_name(encoder->encoder_type);
+	if (encoder_name)
+		printf("Encoder: %s\n", encoder_name);
+	else
+		printf("Encoder\n");
 	printf("\tid     :%i\n", id);
 	printf("\tcrtc_id   :%d\n", encoder->crtc_id);
 	printf("\ttype   :%d\n", encoder->encoder_type);
@@ -244,7 +221,7 @@
 	printf("\thandle    : %i\n", fb->handle);
 	printf("\twidth     : %i\n", fb->width);
 	printf("\theight    : %i\n", fb->height);
-	printf("\tpitch     : %i\n", fb->pitch);;
+	printf("\tpitch     : %i\n", fb->pitch);
 	printf("\tbpp       : %i\n", fb->bpp);
 	printf("\tdepth     : %i\n", fb->depth);
 	printf("\tbuffer_id : %i\n", fb->handle);
diff --git a/tests/modetest/Makefile.am b/tests/modetest/Makefile.am
index 4b296c8..5eebd96 100644
--- a/tests/modetest/Makefile.am
+++ b/tests/modetest/Makefile.am
@@ -3,6 +3,7 @@
 AM_CFLAGS = $(filter-out -Wpointer-arith, $(WARN_CFLAGS))
 
 AM_CFLAGS += \
+	-fvisibility=hidden \
 	-pthread \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/tests \
diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c
index 4fd310b..9b635c0 100644
--- a/tests/modetest/buffers.c
+++ b/tests/modetest/buffers.c
@@ -24,10 +24,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
diff --git a/tests/modetest/cursor.c b/tests/modetest/cursor.c
index 6de82a4..829bced 100644
--- a/tests/modetest/cursor.c
+++ b/tests/modetest/cursor.c
@@ -22,10 +22,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
diff --git a/tests/modetest/meson.build b/tests/modetest/meson.build
new file mode 100644
index 0000000..23d84a1
--- /dev/null
+++ b/tests/modetest/meson.build
@@ -0,0 +1,29 @@
+# Copyright © 2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+modetest = executable(
+  'modetest',
+  files('buffers.c', 'cursor.c', 'modetest.c'),
+  c_args : [libdrm_c_args, '-Wno-pointer-arith'],
+  include_directories : [inc_root, inc_tests, inc_drm],
+  dependencies : [dep_threads, dep_cairo],
+  link_with : [libdrm, libutil],
+  install : with_install_tests,
+)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index cd91119..975dcbc 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -38,10 +38,6 @@
  *       the mode has been programmed, along with possible test patterns.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <assert.h>
 #include <ctype.h>
 #include <stdbool.h>
@@ -123,6 +119,9 @@
 		struct bo *bo;
 		struct bo *cursor_bo;
 	} mode;
+
+	int use_atomic;
+	drmModeAtomicReq *req;
 };
 
 static inline int64_t U642I64(uint64_t val)
@@ -174,6 +173,15 @@
 
 static bit_name_fn(mode_flag)
 
+static void dump_fourcc(uint32_t fourcc)
+{
+	printf(" %c%c%c%c",
+		fourcc,
+		fourcc >> 8,
+		fourcc >> 16,
+		fourcc >> 24);
+}
+
 static void dump_encoders(struct device *dev)
 {
 	drmModeEncoder *encoder;
@@ -242,6 +250,89 @@
 	drmModeFreePropertyBlob(blob);
 }
 
+static const char *modifier_to_string(uint64_t modifier)
+{
+	switch (modifier) {
+	case DRM_FORMAT_MOD_INVALID:
+		return "INVALID";
+	case DRM_FORMAT_MOD_LINEAR:
+		return "LINEAR";
+	case I915_FORMAT_MOD_X_TILED:
+		return "X_TILED";
+	case I915_FORMAT_MOD_Y_TILED:
+		return "Y_TILED";
+	case I915_FORMAT_MOD_Yf_TILED:
+		return "Yf_TILED";
+	case I915_FORMAT_MOD_Y_TILED_CCS:
+		return "Y_TILED_CCS";
+	case I915_FORMAT_MOD_Yf_TILED_CCS:
+		return "Yf_TILED_CCS";
+	case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
+		return "SAMSUNG_64_32_TILE";
+	case DRM_FORMAT_MOD_VIVANTE_TILED:
+		return "VIVANTE_TILED";
+	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		return "VIVANTE_SUPER_TILED";
+	case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
+		return "VIVANTE_SPLIT_TILED";
+	case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
+		return "VIVANTE_SPLIT_SUPER_TILED";
+	case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
+		return "NVIDIA_TEGRA_TILED";
+	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0):
+		return "NVIDIA_16BX2_BLOCK(0)";
+	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1):
+		return "NVIDIA_16BX2_BLOCK(1)";
+	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2):
+		return "NVIDIA_16BX2_BLOCK(2)";
+	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3):
+		return "NVIDIA_16BX2_BLOCK(3)";
+	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4):
+		return "NVIDIA_16BX2_BLOCK(4)";
+	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5):
+		return "NVIDIA_16BX2_BLOCK(5)";
+	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+		return "MOD_BROADCOM_VC4_T_TILED";
+	default:
+		return "(UNKNOWN MODIFIER)";
+	}
+}
+
+static void dump_in_formats(struct device *dev, uint32_t blob_id)
+{
+	uint32_t i, j;
+	drmModePropertyBlobPtr blob;
+	struct drm_format_modifier_blob *header;
+	uint32_t *formats;
+	struct drm_format_modifier *modifiers;
+
+	printf("\t\tin_formats blob decoded:\n");
+	blob = drmModeGetPropertyBlob(dev->fd, blob_id);
+	if (!blob) {
+		printf("\n");
+		return;
+	}
+
+	header = blob->data;
+	formats = (uint32_t *) ((char *) header + header->formats_offset);
+	modifiers = (struct drm_format_modifier *)
+		((char *) header + header->modifiers_offset);
+
+	for (i = 0; i < header->count_formats; i++) {
+		printf("\t\t\t");
+		dump_fourcc(formats[i]);
+		printf(": ");
+		for (j = 0; j < header->count_modifiers; j++) {
+			uint64_t mask = 1ULL << i;
+			if (modifiers[j].formats & mask)
+				printf(" %s", modifier_to_string(modifiers[j].modifier));
+		}
+		printf("\n");
+	}
+
+	drmModeFreePropertyBlob(blob);
+}
+
 static void dump_prop(struct device *dev, drmModePropertyPtr prop,
 		      uint32_t prop_id, uint64_t value)
 {
@@ -319,6 +410,9 @@
 		printf(" %"PRId64"\n", value);
 	else
 		printf(" %"PRIu64"\n", value);
+
+	if (strcmp(prop->name, "IN_FORMATS") == 0)
+		dump_in_formats(dev, value);
 }
 
 static void dump_connectors(struct device *dev)
@@ -443,7 +537,7 @@
 
 		printf("  formats:");
 		for (j = 0; j < ovr->count_formats; j++)
-			printf(" %4.4s", (char *)&ovr->formats[j]);
+			dump_fourcc(ovr->formats[j]);
 		printf("\n");
 
 		if (plane->props) {
@@ -524,7 +618,6 @@
 		return NULL;
 
 	drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
-	drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1);
 
 	res->res = drmModeGetResources(dev->fd);
 	if (!res->res) {
@@ -562,10 +655,13 @@
 	for (i = 0; i < res->res->count_connectors; i++) {
 		struct connector *connector = &res->connectors[i];
 		drmModeConnector *conn = connector->connector;
+		int num;
 
-		asprintf(&connector->name, "%s-%u",
+		num = asprintf(&connector->name, "%s-%u",
 			 util_lookup_connector_type_name(conn->connector_type),
 			 conn->connector_type_id);
+		if (num < 0)
+			goto error;
 	}
 
 #define get_properties(_res, __res, type, Type)					\
@@ -712,7 +808,9 @@
 	uint32_t w, h;
 	double scale;
 	unsigned int fb_id;
+	unsigned int old_fb_id;
 	struct bo *bo;
+	struct bo *old_bo;
 	char format_str[5]; /* need to leave room for terminating \0 */
 	unsigned int fourcc;
 };
@@ -906,8 +1004,12 @@
 
 	p->prop_id = props->props[i];
 
-	ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
-				       p->prop_id, p->value);
+	if (!dev->use_atomic)
+		ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
+									   p->prop_id, p->value);
+	else
+		ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value);
+
 	if (ret < 0)
 		fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
 			obj_type, p->obj_id, p->name, p->value, strerror(errno));
@@ -956,6 +1058,94 @@
 	return false;
 }
 
+static void add_property(struct device *dev, uint32_t obj_id,
+			       const char *name, uint64_t value)
+{
+	struct property_arg p;
+
+	p.obj_id = obj_id;
+	strcpy(p.name, name);
+	p.value = value;
+
+	set_property(dev, &p);
+}
+
+static int atomic_set_plane(struct device *dev, struct plane_arg *p,
+							int pattern, bool update)
+{
+	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
+	struct bo *plane_bo;
+	int crtc_x, crtc_y, crtc_w, crtc_h;
+	struct crtc *crtc = NULL;
+	unsigned int i;
+	unsigned int old_fb_id;
+
+	/* Find an unused plane which can be connected to our CRTC. Find the
+	 * CRTC index first, then iterate over available planes.
+	 */
+	for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
+		if (p->crtc_id == dev->resources->res->crtcs[i]) {
+			crtc = &dev->resources->crtcs[i];
+			break;
+		}
+	}
+
+	if (!crtc) {
+		fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
+		return -1;
+	}
+
+	if (!update)
+		fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n",
+			p->w, p->h, p->format_str, p->plane_id, p->crtc_id);
+
+	plane_bo = p->old_bo;
+	p->old_bo = p->bo;
+
+	if (!plane_bo) {
+		plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h,
+				     handles, pitches, offsets, pattern);
+
+		if (plane_bo == NULL)
+			return -1;
+
+		if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
+			handles, pitches, offsets, &p->fb_id, 0)) {
+			fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
+			return -1;
+		}
+	}
+
+	p->bo = plane_bo;
+
+	old_fb_id = p->fb_id;
+	p->old_fb_id = old_fb_id;
+
+	crtc_w = p->w * p->scale;
+	crtc_h = p->h * p->scale;
+	if (!p->has_position) {
+		/* Default to the middle of the screen */
+		crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
+		crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
+	} else {
+		crtc_x = p->x;
+		crtc_y = p->y;
+	}
+
+	add_property(dev, p->plane_id, "FB_ID", p->fb_id);
+	add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id);
+	add_property(dev, p->plane_id, "SRC_X", 0);
+	add_property(dev, p->plane_id, "SRC_Y", 0);
+	add_property(dev, p->plane_id, "SRC_W", p->w << 16);
+	add_property(dev, p->plane_id, "SRC_H", p->h << 16);
+	add_property(dev, p->plane_id, "CRTC_X", crtc_x);
+	add_property(dev, p->plane_id, "CRTC_Y", crtc_y);
+	add_property(dev, p->plane_id, "CRTC_W", crtc_w);
+	add_property(dev, p->plane_id, "CRTC_H", crtc_h);
+
+	return 0;
+}
+
 static int set_plane(struct device *dev, struct plane_arg *p)
 {
 	drmModePlane *ovr;
@@ -997,7 +1187,8 @@
 		if (!format_support(ovr, p->fourcc))
 			continue;
 
-		if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id) {
+		if ((ovr->possible_crtcs & (1 << pipe)) &&
+		    (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) {
 			plane_id = ovr->plane_id;
 			break;
 		}
@@ -1051,6 +1242,64 @@
 	return 0;
 }
 
+static void atomic_set_planes(struct device *dev, struct plane_arg *p,
+			      unsigned int count, bool update)
+{
+	unsigned int i, pattern = UTIL_PATTERN_SMPTE;
+
+	/* set up planes */
+	for (i = 0; i < count; i++) {
+		if (i > 0)
+			pattern = UTIL_PATTERN_TILES;
+
+		if (atomic_set_plane(dev, &p[i], pattern, update))
+			return;
+	}
+}
+
+static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		add_property(dev, p[i].plane_id, "FB_ID", 0);
+		add_property(dev, p[i].plane_id, "CRTC_ID", 0);
+		add_property(dev, p[i].plane_id, "SRC_X", 0);
+		add_property(dev, p[i].plane_id, "SRC_Y", 0);
+		add_property(dev, p[i].plane_id, "SRC_W", 0);
+		add_property(dev, p[i].plane_id, "SRC_H", 0);
+		add_property(dev, p[i].plane_id, "CRTC_X", 0);
+		add_property(dev, p[i].plane_id, "CRTC_Y", 0);
+		add_property(dev, p[i].plane_id, "CRTC_W", 0);
+		add_property(dev, p[i].plane_id, "CRTC_H", 0);
+	}
+}
+
+static void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count)
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		if (p[i].fb_id) {
+			drmModeRmFB(dev->fd, p[i].fb_id);
+			p[i].fb_id = 0;
+		}
+		if (p[i].old_fb_id) {
+			drmModeRmFB(dev->fd, p[i].old_fb_id);
+			p[i].old_fb_id = 0;
+		}
+		if (p[i].bo) {
+			bo_destroy(p[i].bo);
+			p[i].bo = NULL;
+		}
+		if (p[i].old_bo) {
+			bo_destroy(p[i].old_bo);
+			p[i].old_bo = NULL;
+		}
+
+	}
+}
+
 static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
 {
 	unsigned int i;
@@ -1063,6 +1312,59 @@
 	}
 }
 
+static void atomic_set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
+{
+	unsigned int i;
+	unsigned int j;
+	int ret;
+
+	for (i = 0; i < count; i++) {
+		struct pipe_arg *pipe = &pipes[i];
+
+		ret = pipe_find_crtc_and_mode(dev, pipe);
+		if (ret < 0)
+			continue;
+	}
+
+	for (i = 0; i < count; i++) {
+		struct pipe_arg *pipe = &pipes[i];
+		uint32_t blob_id;
+
+		if (pipe->mode == NULL)
+			continue;
+
+		printf("setting mode %s-%dHz@%s on connectors ",
+		       pipe->mode_str, pipe->mode->vrefresh, pipe->format_str);
+		for (j = 0; j < pipe->num_cons; ++j) {
+			printf("%s, ", pipe->cons[j]);
+			add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc->crtc->crtc_id);
+		}
+		printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
+
+		drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
+		add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", blob_id);
+		add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 1);
+	}
+}
+
+static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
+{
+	unsigned int i;
+	unsigned int j;
+
+	for (i = 0; i < count; i++) {
+		struct pipe_arg *pipe = &pipes[i];
+
+		if (pipe->mode == NULL)
+			continue;
+
+		for (j = 0; j < pipe->num_cons; ++j)
+			add_property(dev, pipe->con_ids[j], "CRTC_ID",0);
+
+		add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", 0);
+		add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 0);
+	}
+}
 
 static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
 {
@@ -1438,7 +1740,7 @@
 
 static void usage(char *name)
 {
-	fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name);
+	fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
 
 	fprintf(stderr, "\n Query options:\n\n");
 	fprintf(stderr, "\t-c\tlist connectors\n");
@@ -1452,6 +1754,7 @@
 	fprintf(stderr, "\t-C\ttest hw cursor\n");
 	fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
 	fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
+	fprintf(stderr, "\t-a \tuse atomic API\n");
 
 	fprintf(stderr, "\n Generic options:\n\n");
 	fprintf(stderr, "\t-d\tdrop master after mode set\n");
@@ -1515,7 +1818,7 @@
 	return 0;
 }
 
-static char optstr[] = "cdD:efM:P:ps:Cvw:";
+static char optstr[] = "acdD:efM:P:ps:Cvw:";
 
 int main(int argc, char **argv)
 {
@@ -1526,6 +1829,7 @@
 	int drop_master = 0;
 	int test_vsync = 0;
 	int test_cursor = 0;
+	int use_atomic = 0;
 	char *device = NULL;
 	char *module = NULL;
 	unsigned int i;
@@ -1544,6 +1848,9 @@
 		args++;
 
 		switch (c) {
+		case 'a':
+			use_atomic = 1;
+			break;
 		case 'c':
 			connectors = 1;
 			break;
@@ -1623,13 +1930,22 @@
 		}
 	}
 
-	if (!args)
+	if (!args || (args == 1 && use_atomic))
 		encoders = connectors = crtcs = planes = framebuffers = 1;
 
 	dev.fd = util_open(device, module);
 	if (dev.fd < 0)
 		return -1;
 
+	ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
+	if (ret && use_atomic) {
+		fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
+		drmClose(dev.fd);
+		return -1;
+	}
+
+	dev.use_atomic = use_atomic;
+
 	if (test_vsync && !page_flipping_supported()) {
 		fprintf(stderr, "page flipping not supported by drm.\n");
 		return -1;
@@ -1670,40 +1986,111 @@
 	for (i = 0; i < prop_count; ++i)
 		set_property(&dev, &prop_args[i]);
 
-	if (count || plane_count) {
-		uint64_t cap = 0;
+	if (dev.use_atomic) {
+		dev.req = drmModeAtomicAlloc();
 
-		ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
-		if (ret || cap == 0) {
-			fprintf(stderr, "driver doesn't support the dumb buffer API\n");
-			return 1;
+		if (count && plane_count) {
+			uint64_t cap = 0;
+
+			ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
+			if (ret || cap == 0) {
+				fprintf(stderr, "driver doesn't support the dumb buffer API\n");
+				return 1;
+			}
+
+			atomic_set_mode(&dev, pipe_args, count);
+			atomic_set_planes(&dev, plane_args, plane_count, false);
+
+			ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+			if (ret) {
+				fprintf(stderr, "Atomic Commit failed [1]\n");
+				return 1;
+			}
+
+			gettimeofday(&pipe_args->start, NULL);
+			pipe_args->swap_count = 0;
+
+			while (test_vsync) {
+				drmModeAtomicFree(dev.req);
+				dev.req = drmModeAtomicAlloc();
+				atomic_set_planes(&dev, plane_args, plane_count, true);
+
+				ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+				if (ret) {
+					fprintf(stderr, "Atomic Commit failed [2]\n");
+					return 1;
+				}
+
+				pipe_args->swap_count++;
+				if (pipe_args->swap_count == 60) {
+					struct timeval end;
+					double t;
+
+					gettimeofday(&end, NULL);
+					t = end.tv_sec + end.tv_usec * 1e-6 -
+				    (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6);
+					fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t);
+					pipe_args->swap_count = 0;
+					pipe_args->start = end;
+				}
+			}
+
+			if (drop_master)
+				drmDropMaster(dev.fd);
+
+			getchar();
+
+			drmModeAtomicFree(dev.req);
+			dev.req = drmModeAtomicAlloc();
+
+			atomic_clear_mode(&dev, pipe_args, count);
+			atomic_clear_planes(&dev, plane_args, plane_count);
+			ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+			if (ret) {
+				fprintf(stderr, "Atomic Commit failed\n");
+				return 1;
+			}
+
+			atomic_clear_FB(&dev, plane_args, plane_count);
 		}
 
-		if (count)
-			set_mode(&dev, pipe_args, count);
+		drmModeAtomicFree(dev.req);
+	} else {
+		if (count || plane_count) {
+			uint64_t cap = 0;
 
-		if (plane_count)
-			set_planes(&dev, plane_args, plane_count);
+			ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
+			if (ret || cap == 0) {
+				fprintf(stderr, "driver doesn't support the dumb buffer API\n");
+				return 1;
+			}
 
-		if (test_cursor)
-			set_cursors(&dev, pipe_args, count);
+			if (count)
+				set_mode(&dev, pipe_args, count);
 
-		if (test_vsync)
-			test_page_flip(&dev, pipe_args, count);
+			if (plane_count)
+				set_planes(&dev, plane_args, plane_count);
 
-		if (drop_master)
-			drmDropMaster(dev.fd);
+			if (test_cursor)
+				set_cursors(&dev, pipe_args, count);
 
-		getchar();
+			if (test_vsync)
+				test_page_flip(&dev, pipe_args, count);
 
-		if (test_cursor)
-			clear_cursors(&dev);
+			if (drop_master)
+				drmDropMaster(dev.fd);
 
-		if (plane_count)
-			clear_planes(&dev, plane_args, plane_count);
+			getchar();
 
-		if (count)
-			clear_mode(&dev);
+			if (test_cursor)
+				clear_cursors(&dev);
+
+			if (plane_count)
+				clear_planes(&dev, plane_args, plane_count);
+
+			if (count)
+				clear_mode(&dev);
+		}
 	}
 
 	free_resources(dev.resources);
diff --git a/tests/nouveau/Makefile.am b/tests/nouveau/Makefile.am
index 3c799a8..554f43e 100644
--- a/tests/nouveau/Makefile.am
+++ b/tests/nouveau/Makefile.am
@@ -1,6 +1,7 @@
 AM_CFLAGS = \
 	-pthread \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/nouveau \
 	-I$(top_srcdir)
diff --git a/tests/nouveau/meson.build b/tests/nouveau/meson.build
new file mode 100644
index 0000000..ca4d44f
--- /dev/null
+++ b/tests/nouveau/meson.build
@@ -0,0 +1,30 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+threaded = executable(
+  'threaded',
+  files('threaded.c'),
+  dependencies : [dep_dl, dep_threads],
+  include_directories : [inc_root, inc_drm, include_directories('../../nouveau')],
+  link_with : [libdrm, libdrm_nouveau],
+  c_args : libdrm_c_args,
+)
+
+test('threaded', threaded)
diff --git a/tests/nouveau/threaded.c b/tests/nouveau/threaded.c
index 281af46..3669bcd 100644
--- a/tests/nouveau/threaded.c
+++ b/tests/nouveau/threaded.c
@@ -20,10 +20,6 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
 #include <sys/ioctl.h>
 #include <dlfcn.h>
 #include <fcntl.h>
diff --git a/tests/planetest/Android.bp b/tests/planetest/Android.bp
deleted file mode 100644
index 16dfc5b..0000000
--- a/tests/planetest/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-build = ["Android.sources.bp"]
-
-cc_test {
-    name: "planetest",
-    defaults: [
-        "planetest_common_sources",
-        "planetest_sources",
-    ],
-    shared_libs: ["libdrm"],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-        "-Wno-pointer-arith",
-    ],
-}
-
-cc_test {
-    name: "atomictest",
-    defaults: [
-        "planetest_common_sources",
-        "atomictest_sources",
-    ],
-    shared_libs: ["libdrm"],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-        "-Wno-pointer-arith",
-    ],
-}
diff --git a/tests/planetest/Android.sources.bp b/tests/planetest/Android.sources.bp
deleted file mode 100644
index 4a35bb5..0000000
--- a/tests/planetest/Android.sources.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Autogenerated with Android.sources.bp.mk
-
-cc_defaults {
-    name: "planetest_common_sources",
-    srcs: [
-        "bo.c",
-        "dev.c",
-        "modeset.c",
-    ],
-}
-
-cc_defaults {
-    name: "planetest_sources",
-    srcs: [
-        "planetest.c",
-    ],
-}
-
-cc_defaults {
-    name: "atomictest_sources",
-    srcs: [
-        "atomictest.c",
-    ],
-}
diff --git a/tests/planetest/Makefile.am b/tests/planetest/Makefile.am
deleted file mode 100644
index b82d05b..0000000
--- a/tests/planetest/Makefile.am
+++ /dev/null
@@ -1,30 +0,0 @@
-include Makefile.sources
-
-AM_CFLAGS = $(filter-out -Wpointer-arith, $(WARN_CFLAGS))
-
-AM_CFLAGS += \
-	-I$(top_srcdir)/include/drm \
-	-I$(top_srcdir)/libkms/ \
-	-I$(top_srcdir)
-
-PLANETEST_COMMON_LDADD = \
-	$(top_builddir)/libdrm.la \
-	$(top_builddir)/libkms/libkms.la \
-	-lpthread
-
-if HAVE_INSTALL_TESTS
-bin_PROGRAMS = \
-	atomictest \
-	planetest
-else
-noinst_PROGRAMS = \
-	atomictest \
-	planetest
-endif
-
-atomictest_CFLAGS=-DUSE_ATOMIC_API ${AM_CFLAGS}
-atomictest_SOURCES=${PLANETEST_COMMON_FILES} ${ATOMICTEST_FILES}
-planetest_SOURCES=${PLANETEST_COMMON_FILES} ${PLANETEST_FILES}
-
-atomictest_LDADD=${PLANETEST_COMMON_LDADD}
-planetest_LDADD=${PLANETEST_COMMON_LDADD}
diff --git a/tests/planetest/Makefile.sources b/tests/planetest/Makefile.sources
deleted file mode 100644
index 3cbeb2b..0000000
--- a/tests/planetest/Makefile.sources
+++ /dev/null
@@ -1,13 +0,0 @@
-PLANETEST_COMMON_FILES := \
-	bo.c \
-	bo.h \
-	dev.c \
-	dev.h \
-	modeset.c \
-	modeset.h
-
-ATOMICTEST_FILES := \
-	atomictest.c
-
-PLANETEST_FILES := \
-	planetest.c
diff --git a/tests/planetest/atomictest.c b/tests/planetest/atomictest.c
deleted file mode 100644
index 5fec911..0000000
--- a/tests/planetest/atomictest.c
+++ /dev/null
@@ -1,151 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/select.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <errno.h>
-
-#include <xf86drm.h>
-
-#include "dev.h"
-#include "bo.h"
-#include "modeset.h"
-
-static int terminate = 0;
-
-static void sigint_handler(int arg)
-{
-	terminate = 1;
-}
-
-static void
-page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
-		unsigned int tv_usec, void *user_data)
-{
-}
-
-static void incrementor(int *inc, int *val, int increment, int lower, int upper)
-{
-	if(*inc > 0)
-		*inc = *val + increment >= upper ? -1 : 1;
-	else
-		*inc = *val - increment <= lower ? 1 : -1;
-	*val += *inc * increment;
-}
-
-int main(int argc, char *argv[])
-{
-	int ret, i, j, num_test_planes;
-	int x_inc = 1, x = 0, y_inc = 1, y = 0;
-	uint32_t plane_w = 128, plane_h = 128;
-	struct sp_dev *dev;
-	struct sp_plane **plane = NULL;
-	struct sp_crtc *test_crtc;
-	fd_set fds;
-	drmModePropertySetPtr pset;
-	drmEventContext event_context = {
-		.version = DRM_EVENT_CONTEXT_VERSION,
-		.page_flip_handler = page_flip_handler,
-	};
-	int card = 0, crtc = 0;
-
-	signal(SIGINT, sigint_handler);
-
-	parse_arguments(argc, argv, &card, &crtc);
-
-	dev = create_sp_dev(card);
-	if (!dev) {
-		printf("Failed to create sp_dev\n");
-		return -1;
-	}
-
-	if (crtc >= dev->num_crtcs) {
-		printf("Invalid crtc %d (num=%d)\n", crtc, dev->num_crtcs);
-		return -1;
-	}
-
-	ret = initialize_screens(dev);
-	if (ret) {
-		printf("Failed to initialize screens\n");
-		goto out;
-	}
-	test_crtc = &dev->crtcs[crtc];
-
-	plane = calloc(dev->num_planes, sizeof(*plane));
-	if (!plane) {
-		printf("Failed to allocate plane array\n");
-		goto out;
-	}
-
-	/* Create our planes */
-	num_test_planes = test_crtc->num_planes;
-	for (i = 0; i < num_test_planes; i++) {
-		plane[i] = get_sp_plane(dev, test_crtc);
-		if (!plane[i]) {
-			printf("no unused planes available\n");
-			goto out;
-		}
-
-		plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16, plane[i]->format, 0);
-		if (!plane[i]->bo) {
-			printf("failed to create plane bo\n");
-			goto out;
-		}
-
-		fill_bo(plane[i]->bo, 0xFF, 0xFF, 0xFF, 0xFF);
-	}
-
-	pset = drmModePropertySetAlloc();
-	if (!pset) {
-		printf("Failed to allocate the property set\n");
-		goto out;
-	}
-
-	while (!terminate) {
-		FD_ZERO(&fds);
-		FD_SET(dev->fd, &fds);
-
-		incrementor(&x_inc, &x, 5, 0,
-			test_crtc->crtc->mode.hdisplay - plane_w);
-		incrementor(&y_inc, &y, 5, 0, test_crtc->crtc->mode.vdisplay -
-						plane_h * num_test_planes);
-
-		for (j = 0; j < num_test_planes; j++) {
-			ret = set_sp_plane_pset(dev, plane[j], pset, test_crtc,
-					x, y + j * plane_h);
-			if (ret) {
-				printf("failed to move plane %d\n", ret);
-				goto out;
-			}
-		}
-
-		ret = drmModePropertySetCommit(dev->fd,
-				DRM_MODE_PAGE_FLIP_EVENT, NULL, pset);
-		if (ret) {
-			printf("failed to commit properties ret=%d\n", ret);
-			goto out;
-		}
-
-		do {
-			ret = select(dev->fd + 1, &fds, NULL, NULL, NULL);
-		} while (ret == -1 && errno == EINTR);
-
-		if (FD_ISSET(dev->fd, &fds))
-			drmHandleEvent(dev->fd, &event_context);
-	}
-
-	drmModePropertySetFree(pset);
-
-	for (i = 0; i < num_test_planes; i++)
-		put_sp_plane(plane[i]);
-
-out:
-	destroy_sp_dev(dev);
-	free(plane);
-	return ret;
-}
diff --git a/tests/planetest/bo.c b/tests/planetest/bo.c
deleted file mode 100644
index d4b82c6..0000000
--- a/tests/planetest/bo.c
+++ /dev/null
@@ -1,234 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include "bo.h"
-#include "dev.h"
-
-#define MAKE_YUV_601_Y(r, g, b) \
-	((( 66 * (r) + 129 * (g) +  25 * (b) + 128) >> 8) + 16)
-#define MAKE_YUV_601_U(r, g, b) \
-	(((-38 * (r) -  74 * (g) + 112 * (b) + 128) >> 8) + 128)
-#define MAKE_YUV_601_V(r, g, b) \
-	(((112 * (r) -  94 * (g) -  18 * (b) + 128) >> 8) + 128)
-
-static void draw_rect_yuv(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
-		uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
-{
-	uint32_t i, j, xmax = x + width, ymax = y + height;
-
-	if (xmax > bo->width)
-		xmax = bo->width;
-	if (ymax > bo->height)
-		ymax = bo->height;
-
-	for (i = y; i < ymax; i++) {
-		uint8_t *luma = bo->map_addr + i * bo->pitch;
-
-		for (j = x; j < xmax; j++)
-			luma[j] = MAKE_YUV_601_Y(r, g, b);
-	}
-
-	for (i = y; i < ymax / 2; i++) {
-		uint8_t *chroma = bo->map_addr + (i + height) * bo->pitch;
-
-		for (j = x; j < xmax / 2; j++) {
-			chroma[j*2] = MAKE_YUV_601_U(r, g, b);
-			chroma[j*2 + 1] = MAKE_YUV_601_V(r, g, b);
-		}
-	}
-}
-
-void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
-{
-	if (bo->format == DRM_FORMAT_NV12)
-		draw_rect_yuv(bo, 0, 0, bo->width, bo->height, a, r, g, b);
-	else
-		draw_rect(bo, 0, 0, bo->width, bo->height, a, r, g, b);
-}
-
-void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
-		uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
-{
-	uint32_t i, j, xmax = x + width, ymax = y + height;
-
-	if (xmax > bo->width)
-		xmax = bo->width;
-	if (ymax > bo->height)
-		ymax = bo->height;
-
-	for (i = y; i < ymax; i++) {
-		uint8_t *row = bo->map_addr + i * bo->pitch;
-
-		for (j = x; j < xmax; j++) {
-			uint8_t *pixel = row + j * 4;
-
-			if (bo->format == DRM_FORMAT_ARGB8888 ||
-			    bo->format == DRM_FORMAT_XRGB8888)
-			{
-				pixel[0] = b;
-				pixel[1] = g;
-				pixel[2] = r;
-				pixel[3] = a;
-			} else if (bo->format == DRM_FORMAT_RGBA8888) {
-				pixel[0] = r;
-				pixel[1] = g;
-				pixel[2] = b;
-				pixel[3] = a;
-			}
-		}
-	}
-}
-
-static int add_fb_sp_bo(struct sp_bo *bo, uint32_t format)
-{
-	int ret;
-	uint32_t handles[4], pitches[4], offsets[4];
-
-	handles[0] = bo->handle;
-	pitches[0] = bo->pitch;
-	offsets[0] = 0;
-	if (bo->format == DRM_FORMAT_NV12) {
-		handles[1] = bo->handle;
-		pitches[1] = pitches[0];
-		offsets[1] = pitches[0] * bo->height;
-	}
-
-	ret = drmModeAddFB2(bo->dev->fd, bo->width, bo->height,
-			format, handles, pitches, offsets,
-			&bo->fb_id, bo->flags);
-	if (ret) {
-		printf("failed to create fb ret=%d\n", ret);
-		return ret;
-	}
-	return 0;
-}
-
-static int map_sp_bo(struct sp_bo *bo)
-{
-	int ret;
-	struct drm_mode_map_dumb md;
-
-	if (bo->map_addr)
-		return 0;
-
-	md.handle = bo->handle;
-	ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &md);
-	if (ret) {
-		printf("failed to map sp_bo ret=%d\n", ret);
-		return ret;
-	}
-
-	bo->map_addr = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
-				bo->dev->fd, md.offset);
-	if (bo->map_addr == MAP_FAILED) {
-		printf("failed to map bo ret=%d\n", -errno);
-		return -errno;
-	}
-	return 0;
-}
-
-static int format_to_bpp(uint32_t format)
-{
-	switch (format) {
-	case DRM_FORMAT_NV12:
-		return 8;
-	case DRM_FORMAT_ARGB8888:
-	case DRM_FORMAT_XRGB8888:
-	case DRM_FORMAT_RGBA8888:
-	default:
-		return 32;
-	}
-}
-
-struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height,
-		uint32_t depth, uint32_t format, uint32_t flags)
-{
-	int ret;
-	struct drm_mode_create_dumb cd;
-	struct sp_bo *bo;
-
-	bo = calloc(1, sizeof(*bo));
-	if (!bo)
-		return NULL;
-
-	if (format == DRM_FORMAT_NV12)
-		cd.height = height * 3 / 2;
-	else
-		cd.height = height;
-
-	cd.width = width;
-	cd.bpp = format_to_bpp(format);
-	cd.flags = flags;
-
-	ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &cd);
-	if (ret) {
-		printf("failed to create sp_bo %d\n", ret);
-		goto err;
-	}
-
-	bo->dev = dev;
-	bo->width = width;
-	bo->height = height;
-	bo->depth = depth;
-	bo->bpp = format_to_bpp(format);
-	bo->format = format;
-	bo->flags = flags;
-
-	bo->handle = cd.handle;
-	bo->pitch = cd.pitch;
-	bo->size = cd.size;
-
-	ret = add_fb_sp_bo(bo, format);
-	if (ret) {
-		printf("failed to add fb ret=%d\n", ret);
-		goto err;
-	}
-
-	ret = map_sp_bo(bo);
-	if (ret) {
-		printf("failed to map bo ret=%d\n", ret);
-		goto err;
-	}
-
-	return bo;
-
-err:
-	free_sp_bo(bo);
-	return NULL;
-}
-
-void free_sp_bo(struct sp_bo *bo)
-{
-	int ret;
-	struct drm_mode_destroy_dumb dd;
-
-	if (!bo)
-		return;
-
-	if (bo->map_addr)
-		munmap(bo->map_addr, bo->size);
-
-	if (bo->fb_id) {
-		ret = drmModeRmFB(bo->dev->fd, bo->fb_id);
-		if (ret)
-			printf("Failed to rmfb ret=%d!\n", ret);
-	}
-
-	if (bo->handle) {
-		dd.handle = bo->handle;
-		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dd);
-		if (ret)
-			printf("Failed to destroy buffer ret=%d\n", ret);
-	}
-
-	free(bo);
-}
diff --git a/tests/planetest/bo.h b/tests/planetest/bo.h
deleted file mode 100644
index 7471e12..0000000
--- a/tests/planetest/bo.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __BO_H_INCLUDED__
-#define __BO_H_INCLUDED__
-
-#include <stdint.h>
-
-struct sp_dev;
-
-struct sp_bo {
-	struct sp_dev *dev;
-
-	uint32_t width;
-	uint32_t height;
-	uint32_t depth;
-	uint32_t bpp;
-	uint32_t format;
-	uint32_t flags;
-
-	uint32_t fb_id;
-	uint32_t handle;
-	void *map_addr;
-	uint32_t pitch;
-	uint32_t size;
-};
-
-struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height,
-		uint32_t depth, uint32_t format, uint32_t flags);
-
-void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b);
-void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
-		uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b);
-
-void free_sp_bo(struct sp_bo *bo);
-
-#endif /* __BO_H_INCLUDED__ */
diff --git a/tests/planetest/dev.c b/tests/planetest/dev.c
deleted file mode 100644
index bd0968c..0000000
--- a/tests/planetest/dev.c
+++ /dev/null
@@ -1,367 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-
-#include <drm.h>
-#include <drm_fourcc.h>
-#include <errno.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#include "bo.h"
-#include "dev.h"
-#include "modeset.h"
-
-static void show_usage(char *name)
-{
-	printf("Usage: %s [OPTION]\n", name);
-	printf("   -c, --card      Index of dri card (ie: /dev/dri/cardN)\n");
-	printf("   -r, --crtc      Index of crtc to use for test\n");
-	printf("\n\n");
-}
-
-void parse_arguments(int argc, char *argv[], int *card, int *crtc)
-{
-	static struct option options[] = {
-		{ "card", required_argument, NULL, 'c' },
-		{ "crtc", required_argument, NULL, 'r' },
-		{ "help", no_argument, NULL, 'h' },
-	};
-	int option_index = 0;
-	int c;
-
-	*card = -1;
-	*crtc = -1;
-	do {
-		c = getopt_long(argc, argv, "c:r:h", options, &option_index);
-		switch (c) {
-		case 0:
-		case 'h':
-			show_usage(argv[0]);
-			exit(0);
-		case -1:
-			break;
-		case 'c':
-			if (optarg[0] < '0' || optarg[0] > '9') {
-				printf("Invalid card value '%s'!\n", optarg);
-				show_usage(argv[0]);
-				exit(-1);
-			}
-			*card = optarg[0] - '0';
-			break;
-		case 'r':
-			if (optarg[0] < '0' || optarg[0] > '9') {
-				printf("Invalid crtc value '%s'!\n", optarg);
-				show_usage(argv[0]);
-				exit(-1);
-			}
-			*crtc = optarg[0] - '0';
-			break;
-		}
-	} while (c != -1);
-
-	if (*card < 0 || *crtc < 0) {
-		show_usage(argv[0]);
-		exit(-1);
-	}
-}
-
-static uint32_t get_prop_id(struct sp_dev *dev,
-			drmModeObjectPropertiesPtr props, const char *name)
-{
-	drmModePropertyPtr p;
-	uint32_t i, prop_id = 0; /* Property ID should always be > 0 */
-
-	for (i = 0; !prop_id && i < props->count_props; i++) {
-		p = drmModeGetProperty(dev->fd, props->props[i]);
-		if (!strcmp(p->name, name))
-			prop_id = p->prop_id;
-		drmModeFreeProperty(p);
-	}
-	if (!prop_id)
-		printf("Could not find %s property\n", name);
-	return prop_id;
-}
-
-static int get_supported_format(struct sp_plane *plane, uint32_t *format)
-{
-	uint32_t i;
-
-	for (i = 0; i < plane->plane->count_formats; i++) {
-		if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 ||
-		    plane->plane->formats[i] == DRM_FORMAT_ARGB8888 ||
-		    plane->plane->formats[i] == DRM_FORMAT_RGBA8888 ||
-		    plane->plane->formats[i] == DRM_FORMAT_NV12) {
-			*format = plane->plane->formats[i];
-			return 0;
-		}
-	}
-	printf("No suitable formats found!\n");
-	return -ENOENT;
-}
-
-struct sp_dev *create_sp_dev(int card)
-{
-	struct sp_dev *dev;
-	int ret, fd, i, j;
-	drmModeRes *r = NULL;
-	drmModePlaneRes *pr = NULL;
-	char card_path[256];
-
-	snprintf(card_path, sizeof(card_path), "/dev/dri/card%d", card);
-
-	fd = open(card_path, O_RDWR);
-	if (fd < 0) {
-		printf("failed to open card0\n");
-		return NULL;
-	}
-
-	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		printf("failed to allocate dev\n");
-		return NULL;
-	}
-
-	dev->fd = fd;
-
-	ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
-	if (ret) {
-		printf("failed to set client cap\n");
-		goto err;
-	}
-
-	ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1);
-	if (ret) {
-		printf("Failed to set atomic cap %d", ret);
-		goto err;
-	}
-
-	r = drmModeGetResources(dev->fd);
-	if (!r) {
-		printf("failed to get r\n");
-		goto err;
-	}
-
-	dev->num_connectors = r->count_connectors;
-	dev->connectors = calloc(dev->num_connectors,
-				sizeof(struct sp_connector));
-	if (!dev->connectors) {
-		printf("failed to allocate connectors\n");
-		goto err;
-	}
-	for (i = 0; i < dev->num_connectors; i++) {
-		drmModeObjectPropertiesPtr props;
-		dev->connectors[i].conn = drmModeGetConnector(dev->fd,
-					r->connectors[i]);
-		if (!dev->connectors[i].conn) {
-			printf("failed to get connector %d\n", i);
-			goto err;
-		}
-
-		props = drmModeObjectGetProperties(dev->fd, r->connectors[i],
-				DRM_MODE_OBJECT_CONNECTOR);
-		if (!props) {
-			printf("failed to get connector properties\n");
-			goto err;
-		}
-
-		dev->connectors[i].crtc_id_pid = get_prop_id(dev, props,
-								"CRTC_ID");
-		drmModeFreeObjectProperties(props);
-		if (!dev->connectors[i].crtc_id_pid)
-			goto err;
-	}
-
-	dev->num_encoders = r->count_encoders;
-	dev->encoders = calloc(dev->num_encoders, sizeof(*dev->encoders));
-	if (!dev->encoders) {
-		printf("failed to allocate encoders\n");
-		goto err;
-	}
-	for (i = 0; i < dev->num_encoders; i++) {
-		dev->encoders[i] = drmModeGetEncoder(dev->fd, r->encoders[i]);
-		if (!dev->encoders[i]) {
-			printf("failed to get encoder %d\n", i);
-			goto err;
-		}
-	}
-
-	dev->num_crtcs = r->count_crtcs;
-	dev->crtcs = calloc(dev->num_crtcs, sizeof(struct sp_crtc));
-	if (!dev->crtcs) {
-		printf("failed to allocate crtcs\n");
-		goto err;
-	}
-	for (i = 0; i < dev->num_crtcs; i++) {
-		drmModeObjectPropertiesPtr props;
-
-		dev->crtcs[i].crtc = drmModeGetCrtc(dev->fd, r->crtcs[i]);
-		if (!dev->crtcs[i].crtc) {
-			printf("failed to get crtc %d\n", i);
-			goto err;
-		}
-		dev->crtcs[i].pipe = i;
-		dev->crtcs[i].num_planes = 0;
-
-		props = drmModeObjectGetProperties(dev->fd, r->crtcs[i],
-				DRM_MODE_OBJECT_CRTC);
-		if (!props) {
-			printf("failed to get crtc properties\n");
-			goto err;
-		}
-
-		dev->crtcs[i].mode_pid = get_prop_id(dev, props, "MODE_ID");
-		dev->crtcs[i].active_pid = get_prop_id(dev, props, "ACTIVE");
-		drmModeFreeObjectProperties(props);
-		if (!dev->crtcs[i].mode_pid || !dev->crtcs[i].active_pid)
-			goto err;
-	}
-
-	pr = drmModeGetPlaneResources(dev->fd);
-	if (!pr) {
-		printf("failed to get plane resources\n");
-		goto err;
-	}
-	dev->num_planes = pr->count_planes;
-	dev->planes = calloc(dev->num_planes, sizeof(struct sp_plane));
-	for(i = 0; i < dev->num_planes; i++) {
-		drmModeObjectPropertiesPtr props;
-		struct sp_plane *plane = &dev->planes[i];
-
-		plane->dev = dev;
-		plane->plane = drmModeGetPlane(dev->fd, pr->planes[i]);
-		if (!plane->plane) {
-			printf("failed to get plane %d\n", i);
-			goto err;
-		}
-		plane->bo = NULL;
-		plane->in_use = 0;
-
-		ret = get_supported_format(plane, &plane->format);
-		if (ret) {
-			printf("failed to get supported format: %d\n", ret);
-			goto err;
-		}
-
-		for (j = 0; j < dev->num_crtcs; j++) {
-			if (plane->plane->possible_crtcs & (1 << j))
-				dev->crtcs[j].num_planes++;
-		}
-
-		props = drmModeObjectGetProperties(dev->fd, pr->planes[i],
-				DRM_MODE_OBJECT_PLANE);
-		if (!props) {
-			printf("failed to get plane properties\n");
-			goto err;
-		}
-		plane->crtc_pid = get_prop_id(dev, props, "CRTC_ID");
-		if (!plane->crtc_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->fb_pid = get_prop_id(dev, props, "FB_ID");
-		if (!plane->fb_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->crtc_x_pid = get_prop_id(dev, props, "CRTC_X");
-		if (!plane->crtc_x_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->crtc_y_pid = get_prop_id(dev, props, "CRTC_Y");
-		if (!plane->crtc_y_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->crtc_w_pid = get_prop_id(dev, props, "CRTC_W");
-		if (!plane->crtc_w_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->crtc_h_pid = get_prop_id(dev, props, "CRTC_H");
-		if (!plane->crtc_h_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->src_x_pid = get_prop_id(dev, props, "SRC_X");
-		if (!plane->src_x_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->src_y_pid = get_prop_id(dev, props, "SRC_Y");
-		if (!plane->src_y_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->src_w_pid = get_prop_id(dev, props, "SRC_W");
-		if (!plane->src_w_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		plane->src_h_pid = get_prop_id(dev, props, "SRC_H");
-		if (!plane->src_h_pid) {
-			drmModeFreeObjectProperties(props);
-			goto err;
-		}
-		drmModeFreeObjectProperties(props);
-	}
-
-	if (pr)
-		drmModeFreePlaneResources(pr);
-	if (r)
-		drmModeFreeResources(r);
-
-	return dev;
-err:
-	if (pr)
-		drmModeFreePlaneResources(pr);
-	if (r)
-		drmModeFreeResources(r);
-	destroy_sp_dev(dev);
-	return NULL;
-}
-
-void destroy_sp_dev(struct sp_dev *dev)
-{
-	int i;
-
-	if (dev->planes) {
-		for (i = 0; i< dev->num_planes; i++) {
-			if (dev->planes[i].in_use)
-				put_sp_plane(&dev->planes[i]);
-			if (dev->planes[i].plane)
-				drmModeFreePlane(dev->planes[i].plane);
-			if (dev->planes[i].bo)
-				free_sp_bo(dev->planes[i].bo);
-		}
-		free(dev->planes);
-	}
-	if (dev->crtcs) {
-		for (i = 0; i< dev->num_crtcs; i++) {
-			if (dev->crtcs[i].crtc)
-				drmModeFreeCrtc(dev->crtcs[i].crtc);
-		}
-		free(dev->crtcs);
-	}
-	if (dev->encoders) {
-		for (i = 0; i< dev->num_encoders; i++) {
-			if (dev->encoders[i])
-				drmModeFreeEncoder(dev->encoders[i]);
-		}
-		free(dev->encoders);
-	}
-	if (dev->connectors) {
-		for (i = 0; i< dev->num_connectors; i++) {
-			if (dev->connectors[i].conn)
-				drmModeFreeConnector(dev->connectors[i].conn);
-		}
-		free(dev->connectors);
-	}
-
-	close(dev->fd);
-	free(dev);
-}
diff --git a/tests/planetest/dev.h b/tests/planetest/dev.h
deleted file mode 100644
index 04dec79..0000000
--- a/tests/planetest/dev.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef __DEV_H_INCLUDED__
-#define __DEV_H_INCLUDED__
-
-#include <stdint.h>
-#include <xf86drmMode.h>
-
-struct sp_bo;
-struct sp_dev;
-
-struct sp_plane {
-	struct sp_dev *dev;
-	drmModePlanePtr plane;
-	struct sp_bo *bo;
-	int in_use;
-	uint32_t format;
-
-	/* Property ID's */
-	uint32_t crtc_pid;
-	uint32_t fb_pid;
-	uint32_t zpos_pid;
-	uint32_t crtc_x_pid;
-	uint32_t crtc_y_pid;
-	uint32_t crtc_w_pid;
-	uint32_t crtc_h_pid;
-	uint32_t src_x_pid;
-	uint32_t src_y_pid;
-	uint32_t src_w_pid;
-	uint32_t src_h_pid;
-};
-
-struct sp_connector {
-	drmModeConnectorPtr conn;
-	uint32_t crtc_id_pid;
-};
-
-struct sp_crtc {
-	drmModeCrtcPtr crtc;
-	int pipe;
-	int num_planes;
-	uint32_t mode_pid;
-	uint32_t active_pid;
-};
-
-struct sp_dev {
-	int fd;
-
-	int num_connectors;
-	struct sp_connector *connectors;
-
-	int num_encoders;
-	drmModeEncoderPtr *encoders;
-
-	int num_crtcs;
-	struct sp_crtc *crtcs;
-
-	int num_planes;
-	struct sp_plane *planes;
-};
-
-void parse_arguments(int argc, char *argv[], int *card, int *crtc);
-
-struct sp_dev *create_sp_dev(int card);
-void destroy_sp_dev(struct sp_dev *dev);
-
-#endif /* __DEV_H_INCLUDED__ */
diff --git a/tests/planetest/modeset.c b/tests/planetest/modeset.c
deleted file mode 100644
index 037814e..0000000
--- a/tests/planetest/modeset.c
+++ /dev/null
@@ -1,232 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include "modeset.h"
-#include "bo.h"
-#include "dev.h"
-
-static int set_crtc_mode(struct sp_dev *dev, struct sp_crtc *crtc,
-			struct sp_connector *conn, drmModeModeInfoPtr mode)
-{
-	int ret;
-	struct drm_mode_create_blob create_blob;
-	drmModePropertySetPtr pset;
-
-	memset(&create_blob, 0, sizeof(create_blob));
-	create_blob.length = sizeof(struct drm_mode_modeinfo);
-	create_blob.data = (__u64)(uintptr_t)mode;
-
-	ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
-	if (ret) {
-		printf("Failed to create mode property blob %d", ret);
-		return ret;
-	}
-
-	pset = drmModePropertySetAlloc();
-	if (!pset) {
-		printf("Failed to allocate property set");
-		return -1;
-	}
-
-	ret = drmModePropertySetAdd(pset, crtc->crtc->crtc_id,
-				    crtc->mode_pid, create_blob.blob_id) ||
-	      drmModePropertySetAdd(pset, crtc->crtc->crtc_id,
-				    crtc->active_pid, 1) ||
-		drmModePropertySetAdd(pset, conn->conn->connector_id,
-				conn->crtc_id_pid, crtc->crtc->crtc_id);
-	if (ret) {
-		printf("Failed to add blob %d to pset", create_blob.blob_id);
-		drmModePropertySetFree(pset);
-		return ret;
-	}
-
-	ret = drmModePropertySetCommit(dev->fd, DRM_MODE_ATOMIC_ALLOW_MODESET,
-					NULL, pset);
-
-	drmModePropertySetFree(pset);
-
-	if (ret) {
-		printf("Failed to commit pset ret=%d\n", ret);
-		return ret;
-	}
-
-	memcpy(&crtc->crtc->mode, mode, sizeof(struct drm_mode_modeinfo));
-	crtc->crtc->mode_valid = 1;
-	return 0;
-}
-
-int initialize_screens(struct sp_dev *dev)
-{
-	int ret, i, j;
-	unsigned crtc_mask = 0;
-
-	for (i = 0; i < dev->num_connectors; i++) {
-		struct sp_connector *c = &dev->connectors[i];
-		drmModeModeInfoPtr m = NULL;
-		drmModeEncoderPtr e = NULL;
-		struct sp_crtc *cr = NULL;
-
-		if (c->conn->connection != DRM_MODE_CONNECTED)
-			continue;
-
-		if (!c->conn->count_modes) {
-			printf("connector has no modes, skipping\n");
-			continue;
-		}
-
-		/* Take the first unless there's a preferred mode */
-		m = &c->conn->modes[0];
-		for (j = 0; j < c->conn->count_modes; j++) {
-			drmModeModeInfoPtr tmp_m = &c->conn->modes[j];
-
-			if (!(tmp_m->type & DRM_MODE_TYPE_PREFERRED))
-				continue;
-
-			m = tmp_m;
-			break;
-		}
-
-		if (!c->conn->count_encoders) {
-			printf("no possible encoders for connector\n");
-			continue;
-		}
-
-		for (j = 0; j < dev->num_encoders; j++) {
-			e = dev->encoders[j];
-			if (e->encoder_id == c->conn->encoders[0])
-				break;
-		}
-		if (j == dev->num_encoders) {
-			printf("could not find encoder for the connector\n");
-			continue;
-		}
-
-		for (j = 0; j < dev->num_crtcs; j++) {
-			if ((1 << j) & crtc_mask)
-				continue;
-
-			cr = &dev->crtcs[j];
-
-			if ((1 << j) & e->possible_crtcs)
-				break;
-		}
-		if (j == dev->num_crtcs) {
-			printf("could not find crtc for the encoder\n");
-			continue;
-		}
-
-		ret = set_crtc_mode(dev, cr, c, m);
-		if (ret) {
-			printf("failed to set mode!\n");
-			continue;
-		}
-		crtc_mask |= 1 << j;
-	}
-	return 0;
-}
-
-struct sp_plane *get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc)
-{
-	int i;
-
-	for(i = 0; i < dev->num_planes; i++) {
-		struct sp_plane *p = &dev->planes[i];
-
-		if (p->in_use)
-			continue;
-
-		if (!(p->plane->possible_crtcs & (1 << crtc->pipe)))
-			continue;
-
-		p->in_use = 1;
-		return p;
-	}
-	return NULL;
-}
-
-void put_sp_plane(struct sp_plane *plane)
-{
-	drmModePlanePtr p;
-
-	/* Get the latest plane information (most notably the crtc_id) */
-	p = drmModeGetPlane(plane->dev->fd, plane->plane->plane_id);
-	if (p)
-		plane->plane = p;
-
-	if (plane->bo) {
-		free_sp_bo(plane->bo);
-		plane->bo = NULL;
-	}
-	plane->in_use = 0;
-}
-
-int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane,
-		struct sp_crtc *crtc, int x, int y)
-{
-	int ret;
-	uint32_t w, h;
-
-	w = plane->bo->width;
-	h = plane->bo->height;
-
-	if ((w + x) > crtc->crtc->mode.hdisplay)
-		w = crtc->crtc->mode.hdisplay - x;
-	if ((h + y) > crtc->crtc->mode.vdisplay)
-		h = crtc->crtc->mode.vdisplay - y;
-
-	ret = drmModeSetPlane(dev->fd, plane->plane->plane_id,
-			crtc->crtc->crtc_id, plane->bo->fb_id, 0, x, y, w, h,
-			0, 0, w << 16, h << 16);
-	if (ret) {
-		printf("failed to set plane to crtc ret=%d\n", ret);
-		return ret;
-	}
-
-	return ret;
-}
-int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane,
-		drmModePropertySetPtr pset, struct sp_crtc *crtc, int x, int y)
-{
-	int ret;
-	uint32_t w, h;
-
-	w = plane->bo->width;
-	h = plane->bo->height;
-
-	if ((w + x) > crtc->crtc->mode.hdisplay)
-		w = crtc->crtc->mode.hdisplay - x;
-	if ((h + y) > crtc->crtc->mode.vdisplay)
-		h = crtc->crtc->mode.vdisplay - y;
-
-	ret = drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->crtc_pid, crtc->crtc->crtc_id)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->fb_pid, plane->bo->fb_id)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->crtc_x_pid, x)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->crtc_y_pid, y)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->crtc_w_pid, w)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->crtc_h_pid, h)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->src_x_pid, 0)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->src_y_pid, 0)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->src_w_pid, w << 16)
-		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
-			plane->src_h_pid, h << 16);
-	if (ret) {
-		printf("failed to add properties to the set\n");
-		return -1;
-	}
-
-	return ret;
-}
diff --git a/tests/planetest/modeset.h b/tests/planetest/modeset.h
deleted file mode 100644
index 7e96574..0000000
--- a/tests/planetest/modeset.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __MODESET_H_INCLUDED__
-#define __MODESET_H_INCLUDED__
-
-struct sp_dev;
-struct sp_crtc;
-
-int initialize_screens(struct sp_dev *dev);
-
-
-struct sp_plane *get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc);
-void put_sp_plane(struct sp_plane *plane);
-
-int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane,
-		struct sp_crtc *crtc, int x, int y);
-
-int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane,
-		drmModePropertySetPtr pset, struct sp_crtc *crtc, int x, int y);
-
-#endif /* __MODESET_H_INCLUDED__ */
diff --git a/tests/planetest/planetest.c b/tests/planetest/planetest.c
deleted file mode 100644
index 5e187c9..0000000
--- a/tests/planetest/planetest.c
+++ /dev/null
@@ -1,116 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/select.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <errno.h>
-
-#include <xf86drm.h>
-
-#include "dev.h"
-#include "bo.h"
-#include "modeset.h"
-
-static int terminate = 0;
-
-static void sigint_handler(int arg)
-{
-	terminate = 1;
-}
-
-static void incrementor(int *inc, int *val, int increment, int lower, int upper)
-{
-	if(*inc > 0)
-		*inc = *val + increment >= upper ? -1 : 1;
-	else
-		*inc = *val - increment <= lower ? 1 : -1;
-	*val += *inc * increment;
-}
-
-int main(int argc, char *argv[])
-{
-	int ret, i, j, num_test_planes;
-	int x_inc = 1, x = 0, y_inc = 1, y = 0;
-	uint32_t plane_w = 128, plane_h = 128;
-	struct sp_dev *dev;
-	struct sp_plane **plane = NULL;
-	struct sp_crtc *test_crtc;
-	int card = 0, crtc = 0;
-
-	signal(SIGINT, sigint_handler);
-
-	parse_arguments(argc, argv, &card, &crtc);
-
-	dev = create_sp_dev(card);
-	if (!dev) {
-		printf("Failed to create sp_dev\n");
-		return -1;
-	}
-
-	if (crtc >= dev->num_crtcs) {
-		printf("Invalid crtc %d (num=%d)\n", crtc, dev->num_crtcs);
-		return -1;
-	}
-
-	ret = initialize_screens(dev);
-	if (ret) {
-		printf("Failed to initialize screens\n");
-		goto out;
-	}
-	test_crtc = &dev->crtcs[crtc];
-
-	plane = calloc(dev->num_planes, sizeof(*plane));
-	if (!plane) {
-		printf("Failed to allocate plane array\n");
-		goto out;
-	}
-
-	/* Create our planes */
-	num_test_planes = test_crtc->num_planes;
-	for (i = 0; i < num_test_planes; i++) {
-		plane[i] = get_sp_plane(dev, test_crtc);
-		if (!plane[i]) {
-			printf("no unused planes available\n");
-			goto out;
-		}
-
-		plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16,
-				plane[i]->format, 0);
-		if (!plane[i]->bo) {
-			printf("failed to create plane bo\n");
-			goto out;
-		}
-
-		fill_bo(plane[i]->bo, 0xFF, 0xFF, 0xFF, 0xFF);
-	}
-
-	while (!terminate) {
-		incrementor(&x_inc, &x, 5, 0,
-			test_crtc->crtc->mode.hdisplay - plane_w);
-		incrementor(&y_inc, &y, 5, 0, test_crtc->crtc->mode.vdisplay -
-						plane_h * num_test_planes);
-
-		for (j = 0; j < num_test_planes; j++) {
-			ret = set_sp_plane(dev, plane[j], test_crtc,
-					x, y + j * plane_h);
-			if (ret) {
-				printf("failed to set plane %d %d\n", j, ret);
-				goto out;
-			}
-		}
-		usleep(15 * 1000);
-	}
-
-	for (i = 0; i < num_test_planes; i++)
-		put_sp_plane(plane[i]);
-
-out:
-	destroy_sp_dev(dev);
-	free(plane);
-	return ret;
-}
diff --git a/tests/proptest/Makefile.am b/tests/proptest/Makefile.am
index 3fde46b..33b8705 100644
--- a/tests/proptest/Makefile.am
+++ b/tests/proptest/Makefile.am
@@ -2,6 +2,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS)\
+	-fvisibility=hidden \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/tests \
 	-I$(top_srcdir)
diff --git a/tests/proptest/meson.build b/tests/proptest/meson.build
new file mode 100644
index 0000000..9c87965
--- /dev/null
+++ b/tests/proptest/meson.build
@@ -0,0 +1,28 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+proptest = executable(
+  'proptest',
+  files('proptest.c'),
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_tests, inc_drm],
+  link_with : [libdrm, libutil],
+  install : with_install_tests,
+)
diff --git a/tests/radeon/Makefile.am b/tests/radeon/Makefile.am
index 9da7625..3d173e3 100644
--- a/tests/radeon/Makefile.am
+++ b/tests/radeon/Makefile.am
@@ -1,5 +1,6 @@
 AM_CFLAGS = \
 	$(WARN_CFLAGS)\
+	-fvisibility=hidden \
 	-I $(top_srcdir)/include/drm \
 	-I $(top_srcdir)
 
diff --git a/tests/radeon/meson.build b/tests/radeon/meson.build
new file mode 100644
index 0000000..bb345b7
--- /dev/null
+++ b/tests/radeon/meson.build
@@ -0,0 +1,27 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+radeon_ttm = executable(
+  'radeon_ttm',
+  files('rbo.c', 'radeon_ttm.c'),
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  c_args : libdrm_c_args,
+)
diff --git a/tests/tegra/Makefile.am b/tests/tegra/Makefile.am
index 8e625c8..b462a30 100644
--- a/tests/tegra/Makefile.am
+++ b/tests/tegra/Makefile.am
@@ -3,7 +3,9 @@
 	-I$(top_srcdir)/tegra \
 	-I$(top_srcdir)
 
-AM_CFLAGS = $(WARN_CFLAGS)
+AM_CFLAGS = \
+	$(WARN_CFLAGS) \
+	-fvisibility=hidden
 
 LDADD = \
 	../../tegra/libdrm_tegra.la \
diff --git a/tests/tegra/meson.build b/tests/tegra/meson.build
new file mode 100644
index 0000000..4f8c54f
--- /dev/null
+++ b/tests/tegra/meson.build
@@ -0,0 +1,27 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+openclose = executable(
+  'openclose',
+  files('openclose.c'),
+  include_directories : [inc_root, inc_drm, include_directories('../../tegra')],
+  c_args : libdrm_c_args,
+  link_with : [libdrm, libdrm_tegra],
+)
diff --git a/tests/tegra/openclose.c b/tests/tegra/openclose.c
index 881d8aa..f80f52d 100644
--- a/tests/tegra/openclose.c
+++ b/tests/tegra/openclose.c
@@ -20,10 +20,6 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/tests/util/format.c b/tests/util/format.c
index 043cfe7..15ac5e1 100644
--- a/tests/util/format.c
+++ b/tests/util/format.c
@@ -23,10 +23,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/tests/util/kms.c b/tests/util/kms.c
index 959b688..5af8bf2 100644
--- a/tests/util/kms.c
+++ b/tests/util/kms.c
@@ -37,10 +37,6 @@
  *       the mode has been programmed, along with possible test patterns.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -79,6 +75,7 @@
 	{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
 	{ DRM_MODE_ENCODER_DSI, "DSI" },
 	{ DRM_MODE_ENCODER_DPMST, "DPMST" },
+	{ DRM_MODE_ENCODER_DPI, "DPI" },
 };
 
 const char *util_lookup_encoder_type_name(unsigned int type)
@@ -117,6 +114,7 @@
 	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
 	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
 	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
+	{ DRM_MODE_CONNECTOR_DPI, "DPI" },
 };
 
 const char *util_lookup_connector_type_name(unsigned int type)
@@ -145,6 +143,9 @@
 	"virtio_gpu",
 	"mediatek",
 	"meson",
+	"pl111",
+	"stm",
+	"sun4i-drm",
 };
 
 int util_open(const char *device, const char *module)
diff --git a/tests/util/meson.build b/tests/util/meson.build
new file mode 100644
index 0000000..7fa1a4b
--- /dev/null
+++ b/tests/util/meson.build
@@ -0,0 +1,28 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+
+libutil = static_library(
+  'util',
+  [files('format.c', 'kms.c', 'pattern.c'), config_file],
+  include_directories : [inc_root, inc_drm],
+  link_with : libdrm,
+  dependencies : dep_cairo
+)
diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index 00b08a8..9fa0a41 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -23,10 +23,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -34,7 +30,7 @@
 
 #include <drm_fourcc.h>
 
-#ifdef HAVE_CAIRO
+#if HAVE_CAIRO
 #include <cairo.h>
 #include <math.h>
 #endif
@@ -546,10 +542,9 @@
 static void make_pwetty(void *data, unsigned int width, unsigned int height,
 			unsigned int stride, uint32_t format)
 {
-#ifdef HAVE_CAIRO
+#if HAVE_CAIRO
 	cairo_surface_t *surface;
 	cairo_t *cr;
-	int x, y;
 	cairo_format_t cairo_format;
 
 	/* we can ignore the order of R,G,B channels */
@@ -576,8 +571,8 @@
 	cairo_surface_destroy(surface);
 
 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
-	for (x = 0; x < width; x += 250)
-		for (y = 0; y < height; y += 250) {
+	for (unsigned x = 0; x < width; x += 250)
+		for (unsigned y = 0; y < height; y += 250) {
 			char buf[64];
 
 			cairo_move_to(cr, x, y - 20);
@@ -824,8 +819,8 @@
 	}
 }
 
-static void fill_plain(const struct util_format_info *info, void *planes[3],
-		       unsigned int width, unsigned int height,
+static void fill_plain(void *planes[3],
+		       unsigned int height,
 		       unsigned int stride)
 {
 	memset(planes[0], 0x77, stride * height);
@@ -861,7 +856,7 @@
 		return fill_smpte(info, planes, width, height, stride);
 
 	case UTIL_PATTERN_PLAIN:
-		return fill_plain(info, planes, width, height, stride);
+		return fill_plain(planes, height, stride);
 
 	default:
 		printf("Error: unsupported test pattern %u.\n", pattern);
diff --git a/tests/vbltest/Makefile.am b/tests/vbltest/Makefile.am
index 276afad..b6cd7a4 100644
--- a/tests/vbltest/Makefile.am
+++ b/tests/vbltest/Makefile.am
@@ -1,5 +1,6 @@
 AM_CFLAGS = \
 	$(WARN_CFLAGS)\
+	-fvisibility=hidden \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/tests \
 	-I$(top_srcdir)
diff --git a/tests/vbltest/meson.build b/tests/vbltest/meson.build
new file mode 100644
index 0000000..6339feb
--- /dev/null
+++ b/tests/vbltest/meson.build
@@ -0,0 +1,28 @@
+# Copyright © 2017-2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+vbltest = executable(
+  'vbltest',
+  files('vbltest.c'),
+  c_args : libdrm_c_args,
+  include_directories : [inc_root, inc_tests, inc_drm],
+  link_with : [libdrm, libutil],
+  install : with_install_tests,
+)
diff --git a/tests/vbltest/vbltest.c b/tests/vbltest/vbltest.c
index 3f6b803..48708d2 100644
--- a/tests/vbltest/vbltest.c
+++ b/tests/vbltest/vbltest.c
@@ -24,10 +24,6 @@
  * IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/util_math.h b/util_math.h
index 02b15a8..35bf451 100644
--- a/util_math.h
+++ b/util_math.h
@@ -29,6 +29,6 @@
 #define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C))
 
 #define __align_mask(value, mask)  (((value) + (mask)) & ~(mask))
-#define ALIGN(value, alignment)    __align_mask(value, (typeof(value))((alignment) - 1))
+#define ALIGN(value, alignment)    __align_mask(value, (__typeof__(value))((alignment) - 1))
 
 #endif /*_UTIL_MATH_H_*/
diff --git a/vc4/Makefile.am b/vc4/Makefile.am
index 7e486b4..5f82d04 100644
--- a/vc4/Makefile.am
+++ b/vc4/Makefile.am
@@ -23,6 +23,7 @@
 
 AM_CFLAGS = \
 	$(WARN_CFLAGS) \
+	-fvisibility=hidden \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
 	$(VALGRIND_CFLAGS) \
diff --git a/vc4/meson.build b/vc4/meson.build
new file mode 100644
index 0000000..0136987
--- /dev/null
+++ b/vc4/meson.build
@@ -0,0 +1,28 @@
+# Copyright © 2017 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice 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.
+
+install_headers('vc4_packet.h', 'vc4_qpu_defines.h', subdir : 'libdrm')
+
+pkg.generate(
+  name : 'libdrm_vc4',
+  version : meson.project_version(),
+  requires_private : 'libdrm',
+  description : 'Userspace interface to vc4 kernel DRM services',
+)
diff --git a/xf86atomic.h b/xf86atomic.h
index 922b37d..2d733bd 100644
--- a/xf86atomic.h
+++ b/xf86atomic.h
@@ -34,10 +34,6 @@
 #ifndef LIBDRM_ATOMICS_H
 #define LIBDRM_ATOMICS_H
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #if HAVE_LIBDRM_ATOMIC_PRIMITIVES
 
 #define HAS_ATOMIC_OPS 1
@@ -101,7 +97,7 @@
 
 #endif
 
-#if ! HAS_ATOMIC_OPS
+#if !defined(HAS_ATOMIC_OPS)
 #error libdrm requires atomic operations, please define them for your CPU/compiler.
 #endif
 
diff --git a/xf86drm.c b/xf86drm.c
index 82fb0e2..a5b0bb7 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -31,9 +31,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -62,6 +59,8 @@
 #endif
 #include <math.h>
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
 /* Not all systems have MAP_FAILED defined */
 #ifndef MAP_FAILED
 #define MAP_FAILED ((void *)-1)
@@ -102,7 +101,7 @@
 #define DRM_MAJOR 226 /* Linux */
 #endif
 
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__DragonFly__)
 struct drm_pciinfo {
 	uint16_t	domain;
 	uint8_t		bus;
@@ -124,7 +123,7 @@
 
 static drmServerInfoPtr drm_server_info;
 
-void drmSetServerInfo(drmServerInfoPtr info)
+drm_public void drmSetServerInfo(drmServerInfoPtr info)
 {
     drm_server_info = info;
 }
@@ -144,7 +143,7 @@
     return vfprintf(stderr, format, ap);
 }
 
-void
+drm_public void
 drmMsg(const char *format, ...)
 {
     va_list ap;
@@ -164,17 +163,17 @@
 
 static void *drmHashTable = NULL; /* Context switch callbacks */
 
-void *drmGetHashTable(void)
+drm_public void *drmGetHashTable(void)
 {
     return drmHashTable;
 }
 
-void *drmMalloc(int size)
+drm_public void *drmMalloc(int size)
 {
     return calloc(1, size);
 }
 
-void drmFree(void *pt)
+drm_public void drmFree(void *pt)
 {
     free(pt);
 }
@@ -182,7 +181,7 @@
 /**
  * Call ioctl, restarting if it is interupted
  */
-int
+drm_public int
 drmIoctl(int fd, unsigned long request, void *arg)
 {
     int ret;
@@ -202,7 +201,7 @@
     return st.st_rdev;
 }
 
-drmHashEntry *drmGetEntry(int fd)
+drm_public drmHashEntry *drmGetEntry(int fd)
 {
     unsigned long key = drmGetKeyFromFd(fd);
     void          *value;
@@ -293,7 +292,7 @@
  * If any other failure happened then it will output error mesage using
  * drmMsg() call.
  */
-#if !defined(UDEV)
+#if !UDEV
 static int chown_check_return(const char *path, uid_t owner, gid_t group)
 {
         int rv;
@@ -332,7 +331,7 @@
     int             fd;
     mode_t          devmode = DRM_DEV_MODE, serv_mode;
     gid_t           serv_group;
-#if !defined(UDEV)
+#if !UDEV
     int             isroot  = !geteuid();
     uid_t           user    = DRM_DEV_UID;
     gid_t           group   = DRM_DEV_GID;
@@ -361,7 +360,7 @@
         devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
     }
 
-#if !defined(UDEV)
+#if !UDEV
     if (stat(DRM_DIR_NAME, &st)) {
         if (!isroot)
             return DRM_ERR_NOT_ROOT;
@@ -408,13 +407,13 @@
     }
 #endif
 
-    fd = open(buf, O_RDWR, 0);
+    fd = open(buf, O_RDWR | O_CLOEXEC, 0);
     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
            fd, fd < 0 ? strerror(errno) : "OK");
     if (fd >= 0)
         return fd;
 
-#if !defined(UDEV)
+#if !UDEV
     /* Check if the device node is not what we expect it to be, and recreate it
      * and try again if so.
      */
@@ -428,7 +427,7 @@
             chmod(buf, devmode);
         }
     }
-    fd = open(buf, O_RDWR, 0);
+    fd = open(buf, O_RDWR | O_CLOEXEC, 0);
     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
            fd, fd < 0 ? strerror(errno) : "OK");
     if (fd >= 0)
@@ -477,7 +476,7 @@
     };
 
     sprintf(buf, dev_name, DRM_DIR_NAME, minor);
-    if ((fd = open(buf, O_RDWR, 0)) >= 0)
+    if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0)
         return fd;
     return -errno;
 }
@@ -493,7 +492,7 @@
  * minor and get version information.  For backward compatibility with older
  * Linux implementations, /proc/dri is also checked.
  */
-int drmAvailable(void)
+drm_public int drmAvailable(void)
 {
     drmVersionPtr version;
     int           retval = 0;
@@ -728,7 +727,7 @@
  * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
  * otherwise.
  */
-int drmOpen(const char *name, const char *busid)
+drm_public int drmOpen(const char *name, const char *busid)
 {
     return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
 }
@@ -749,7 +748,7 @@
  * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
  * otherwise.
  */
-int drmOpenWithType(const char *name, const char *busid, int type)
+drm_public int drmOpenWithType(const char *name, const char *busid, int type)
 {
     if (name != NULL && drm_server_info &&
         drm_server_info->load_module && !drmAvailable()) {
@@ -772,12 +771,12 @@
     return -1;
 }
 
-int drmOpenControl(int minor)
+drm_public int drmOpenControl(int minor)
 {
     return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
 }
 
-int drmOpenRender(int minor)
+drm_public int drmOpenRender(int minor)
 {
     return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
 }
@@ -791,7 +790,7 @@
  * It frees the memory pointed by \p %v as well as all the non-null strings
  * pointers in it.
  */
-void drmFreeVersion(drmVersionPtr v)
+drm_public void drmFreeVersion(drmVersionPtr v)
 {
     if (!v)
         return;
@@ -861,13 +860,11 @@
  * first with zeros to get the string lengths, and then the actually strings.
  * It also null-terminates them since they might not be already.
  */
-drmVersionPtr drmGetVersion(int fd)
+drm_public drmVersionPtr drmGetVersion(int fd)
 {
     drmVersionPtr retval;
     drm_version_t *version = drmMalloc(sizeof(*version));
 
-    memclear(*version);
-
     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
         drmFreeKernelVersion(version);
         return NULL;
@@ -911,7 +908,7 @@
  * This function allocates and fills a drm_version structure with a hard coded
  * version number.
  */
-drmVersionPtr drmGetLibVersion(int fd)
+drm_public drmVersionPtr drmGetLibVersion(int fd)
 {
     drm_version_t *version = drmMalloc(sizeof(*version));
 
@@ -932,7 +929,7 @@
     return (drmVersionPtr)version;
 }
 
-int drmGetCap(int fd, uint64_t capability, uint64_t *value)
+drm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value)
 {
     struct drm_get_cap cap;
     int ret;
@@ -948,7 +945,7 @@
     return 0;
 }
 
-int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
+drm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
 {
     struct drm_set_client_cap cap;
 
@@ -967,7 +964,7 @@
  * \internal
  * This function is just frees the memory pointed by \p busid.
  */
-void drmFreeBusid(const char *busid)
+drm_public void drmFreeBusid(const char *busid)
 {
     drmFree((void *)busid);
 }
@@ -985,7 +982,7 @@
  * get the string length and data, passing the arguments in a drm_unique
  * structure.
  */
-char *drmGetBusid(int fd)
+drm_public char *drmGetBusid(int fd)
 {
     drm_unique_t u;
 
@@ -994,8 +991,10 @@
     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
         return NULL;
     u.unique = drmMalloc(u.unique_len + 1);
-    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
+    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
+        drmFree(u.unique);
         return NULL;
+    }
     u.unique[u.unique_len] = '\0';
 
     return u.unique;
@@ -1014,7 +1013,7 @@
  * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
  * the arguments in a drm_unique structure.
  */
-int drmSetBusid(int fd, const char *busid)
+drm_public int drmSetBusid(int fd, const char *busid)
 {
     drm_unique_t u;
 
@@ -1028,7 +1027,7 @@
     return 0;
 }
 
-int drmGetMagic(int fd, drm_magic_t * magic)
+drm_public int drmGetMagic(int fd, drm_magic_t * magic)
 {
     drm_auth_t auth;
 
@@ -1041,7 +1040,7 @@
     return 0;
 }
 
-int drmAuthMagic(int fd, drm_magic_t magic)
+drm_public int drmAuthMagic(int fd, drm_magic_t magic)
 {
     drm_auth_t auth;
 
@@ -1102,8 +1101,8 @@
  * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
  * the arguments in a drm_map structure.
  */
-int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
-              drmMapFlags flags, drm_handle_t *handle)
+drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
+                         drmMapFlags flags, drm_handle_t *handle)
 {
     drm_map_t map;
 
@@ -1119,7 +1118,7 @@
     return 0;
 }
 
-int drmRmMap(int fd, drm_handle_t handle)
+drm_public int drmRmMap(int fd, drm_handle_t handle)
 {
     drm_map_t map;
 
@@ -1147,8 +1146,8 @@
  *
  * \sa drm_buf_desc.
  */
-int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
-               int agp_offset)
+drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
+                          int agp_offset)
 {
     drm_buf_desc_t request;
 
@@ -1163,7 +1162,7 @@
     return request.count;
 }
 
-int drmMarkBufs(int fd, double low, double high)
+drm_public int drmMarkBufs(int fd, double low, double high)
 {
     drm_buf_info_t info;
     int            i;
@@ -1214,7 +1213,7 @@
  * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
  * the arguments in a drm_buf_free structure.
  */
-int drmFreeBufs(int fd, int count, int *list)
+drm_public int drmFreeBufs(int fd, int count, int *list)
 {
     drm_buf_free_t request;
 
@@ -1235,7 +1234,7 @@
  * \internal
  * This function closes the file descriptor.
  */
-int drmClose(int fd)
+drm_public int drmClose(int fd)
 {
     unsigned long key    = drmGetKeyFromFd(fd);
     drmHashEntry  *entry = drmGetEntry(fd);
@@ -1266,7 +1265,8 @@
  * \internal
  * This function is a wrapper for mmap().
  */
-int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
+drm_public int drmMap(int fd, drm_handle_t handle, drmSize size,
+                      drmAddressPtr address)
 {
     static unsigned long pagesize_mask = 0;
 
@@ -1296,12 +1296,12 @@
  * \internal
  * This function is a wrapper for munmap().
  */
-int drmUnmap(drmAddress address, drmSize size)
+drm_public int drmUnmap(drmAddress address, drmSize size)
 {
     return drm_munmap(address, size);
 }
 
-drmBufInfoPtr drmGetBufInfo(int fd)
+drm_public drmBufInfoPtr drmGetBufInfo(int fd)
 {
     drm_buf_info_t info;
     drmBufInfoPtr  retval;
@@ -1351,7 +1351,7 @@
  * information about the buffers in a drm_buf_map structure into the
  * client-visible data structures.
  */
-drmBufMapPtr drmMapBufs(int fd)
+drm_public drmBufMapPtr drmMapBufs(int fd)
 {
     drm_buf_map_t bufs;
     drmBufMapPtr  retval;
@@ -1396,7 +1396,7 @@
  * Calls munmap() for every buffer stored in \p bufs and frees the
  * memory allocated by drmMapBufs().
  */
-int drmUnmapBufs(drmBufMapPtr bufs)
+drm_public int drmUnmapBufs(drmBufMapPtr bufs)
 {
     int i;
 
@@ -1424,7 +1424,7 @@
  * Assemble the arguments into a drm_dma structure and keeps issuing the
  * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
  */
-int drmDMA(int fd, drmDMAReqPtr request)
+drm_public int drmDMA(int fd, drmDMAReqPtr request)
 {
     drm_dma_t dma;
     int ret, i = 0;
@@ -1467,7 +1467,7 @@
  * This function translates the arguments into a drm_lock structure and issue
  * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
  */
-int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
+drm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
 {
     drm_lock_t lock;
 
@@ -1498,7 +1498,7 @@
  * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
  * argument in a drm_lock structure.
  */
-int drmUnlock(int fd, drm_context_t context)
+drm_public int drmUnlock(int fd, drm_context_t context)
 {
     drm_lock_t lock;
 
@@ -1507,7 +1507,7 @@
     return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
 }
 
-drm_context_t *drmGetReservedContextList(int fd, int *count)
+drm_public drm_context_t *drmGetReservedContextList(int fd, int *count)
 {
     drm_ctx_res_t res;
     drm_ctx_t     *list;
@@ -1523,14 +1523,12 @@
 
     if (!(list   = drmMalloc(res.count * sizeof(*list))))
         return NULL;
-    if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
-        drmFree(list);
-        return NULL;
-    }
+    if (!(retval = drmMalloc(res.count * sizeof(*retval))))
+        goto err_free_list;
 
     res.contexts = list;
     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
-        return NULL;
+        goto err_free_context;
 
     for (i = 0; i < res.count; i++)
         retval[i] = list[i].handle;
@@ -1538,9 +1536,15 @@
 
     *count = res.count;
     return retval;
+
+err_free_list:
+    drmFree(list);
+err_free_context:
+    drmFree(retval);
+    return NULL;
 }
 
-void drmFreeReservedContextList(drm_context_t *pt)
+drm_public void drmFreeReservedContextList(drm_context_t *pt)
 {
     drmFree(pt);
 }
@@ -1563,7 +1567,7 @@
  * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
  * argument in a drm_ctx structure.
  */
-int drmCreateContext(int fd, drm_context_t *handle)
+drm_public int drmCreateContext(int fd, drm_context_t *handle)
 {
     drm_ctx_t ctx;
 
@@ -1574,7 +1578,7 @@
     return 0;
 }
 
-int drmSwitchToContext(int fd, drm_context_t context)
+drm_public int drmSwitchToContext(int fd, drm_context_t context)
 {
     drm_ctx_t ctx;
 
@@ -1585,7 +1589,8 @@
     return 0;
 }
 
-int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
+drm_public int drmSetContextFlags(int fd, drm_context_t context,
+                                  drm_context_tFlags flags)
 {
     drm_ctx_t ctx;
 
@@ -1606,8 +1611,8 @@
     return 0;
 }
 
-int drmGetContextFlags(int fd, drm_context_t context,
-                       drm_context_tFlagsPtr flags)
+drm_public int drmGetContextFlags(int fd, drm_context_t context,
+                                  drm_context_tFlagsPtr flags)
 {
     drm_ctx_t ctx;
 
@@ -1640,7 +1645,7 @@
  * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
  * argument in a drm_ctx structure.
  */
-int drmDestroyContext(int fd, drm_context_t handle)
+drm_public int drmDestroyContext(int fd, drm_context_t handle)
 {
     drm_ctx_t ctx;
 
@@ -1651,7 +1656,7 @@
     return 0;
 }
 
-int drmCreateDrawable(int fd, drm_drawable_t *handle)
+drm_public int drmCreateDrawable(int fd, drm_drawable_t *handle)
 {
     drm_draw_t draw;
 
@@ -1662,7 +1667,7 @@
     return 0;
 }
 
-int drmDestroyDrawable(int fd, drm_drawable_t handle)
+drm_public int drmDestroyDrawable(int fd, drm_drawable_t handle)
 {
     drm_draw_t draw;
 
@@ -1673,9 +1678,9 @@
     return 0;
 }
 
-int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
-                          drm_drawable_info_type_t type, unsigned int num,
-                          void *data)
+drm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
+                                     drm_drawable_info_type_t type,
+                                     unsigned int num, void *data)
 {
     drm_update_draw_t update;
 
@@ -1691,6 +1696,46 @@
     return 0;
 }
 
+drm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence,
+                                  uint64_t *ns)
+{
+    struct drm_crtc_get_sequence get_seq;
+    int ret;
+
+    memclear(get_seq);
+    get_seq.crtc_id = crtcId;
+    ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
+    if (ret)
+        return ret;
+
+    if (sequence)
+        *sequence = get_seq.sequence;
+    if (ns)
+        *ns = get_seq.sequence_ns;
+    return 0;
+}
+
+drm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags,
+                                    uint64_t sequence,
+                                    uint64_t *sequence_queued,
+                                    uint64_t user_data)
+{
+    struct drm_crtc_queue_sequence queue_seq;
+    int ret;
+
+    memclear(queue_seq);
+    queue_seq.crtc_id = crtcId;
+    queue_seq.flags = flags;
+    queue_seq.sequence = sequence;
+    queue_seq.user_data = user_data;
+
+    ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
+    if (ret == 0 && sequence_queued)
+        *sequence_queued = queue_seq.sequence;
+
+    return ret;
+}
+
 /**
  * Acquire the AGP device.
  *
@@ -1703,7 +1748,7 @@
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
  */
-int drmAgpAcquire(int fd)
+drm_public int drmAgpAcquire(int fd)
 {
     if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
         return -errno;
@@ -1721,7 +1766,7 @@
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
  */
-int drmAgpRelease(int fd)
+drm_public int drmAgpRelease(int fd)
 {
     if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
         return -errno;
@@ -1741,7 +1786,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
  * argument in a drm_agp_mode structure.
  */
-int drmAgpEnable(int fd, unsigned long mode)
+drm_public int drmAgpEnable(int fd, unsigned long mode)
 {
     drm_agp_mode_t m;
 
@@ -1769,8 +1814,8 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
  * arguments in a drm_agp_buffer structure.
  */
-int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
-                unsigned long *address, drm_handle_t *handle)
+drm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
+                           unsigned long *address, drm_handle_t *handle)
 {
     drm_agp_buffer_t b;
 
@@ -1799,7 +1844,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
  * argument in a drm_agp_buffer structure.
  */
-int drmAgpFree(int fd, drm_handle_t handle)
+drm_public int drmAgpFree(int fd, drm_handle_t handle)
 {
     drm_agp_buffer_t b;
 
@@ -1824,7 +1869,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
  * argument in a drm_agp_binding structure.
  */
-int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
+drm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
 {
     drm_agp_binding_t b;
 
@@ -1849,7 +1894,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
  * the argument in a drm_agp_binding structure.
  */
-int drmAgpUnbind(int fd, drm_handle_t handle)
+drm_public int drmAgpUnbind(int fd, drm_handle_t handle)
 {
     drm_agp_binding_t b;
 
@@ -1872,7 +1917,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-int drmAgpVersionMajor(int fd)
+drm_public int drmAgpVersionMajor(int fd)
 {
     drm_agp_info_t i;
 
@@ -1895,7 +1940,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-int drmAgpVersionMinor(int fd)
+drm_public int drmAgpVersionMinor(int fd)
 {
     drm_agp_info_t i;
 
@@ -1918,7 +1963,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-unsigned long drmAgpGetMode(int fd)
+drm_public unsigned long drmAgpGetMode(int fd)
 {
     drm_agp_info_t i;
 
@@ -1941,7 +1986,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-unsigned long drmAgpBase(int fd)
+drm_public unsigned long drmAgpBase(int fd)
 {
     drm_agp_info_t i;
 
@@ -1964,7 +2009,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-unsigned long drmAgpSize(int fd)
+drm_public unsigned long drmAgpSize(int fd)
 {
     drm_agp_info_t i;
 
@@ -1987,7 +2032,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-unsigned long drmAgpMemoryUsed(int fd)
+drm_public unsigned long drmAgpMemoryUsed(int fd)
 {
     drm_agp_info_t i;
 
@@ -2010,7 +2055,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-unsigned long drmAgpMemoryAvail(int fd)
+drm_public unsigned long drmAgpMemoryAvail(int fd)
 {
     drm_agp_info_t i;
 
@@ -2033,7 +2078,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-unsigned int drmAgpVendorId(int fd)
+drm_public unsigned int drmAgpVendorId(int fd)
 {
     drm_agp_info_t i;
 
@@ -2056,7 +2101,7 @@
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
  */
-unsigned int drmAgpDeviceId(int fd)
+drm_public unsigned int drmAgpDeviceId(int fd)
 {
     drm_agp_info_t i;
 
@@ -2067,7 +2112,8 @@
     return i.id_device;
 }
 
-int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
+drm_public int drmScatterGatherAlloc(int fd, unsigned long size,
+                                     drm_handle_t *handle)
 {
     drm_scatter_gather_t sg;
 
@@ -2081,7 +2127,7 @@
     return 0;
 }
 
-int drmScatterGatherFree(int fd, drm_handle_t handle)
+drm_public int drmScatterGatherFree(int fd, drm_handle_t handle)
 {
     drm_scatter_gather_t sg;
 
@@ -2103,7 +2149,7 @@
  * \internal
  * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
  */
-int drmWaitVBlank(int fd, drmVBlankPtr vbl)
+drm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl)
 {
     struct timespec timeout, cur;
     int ret;
@@ -2135,7 +2181,7 @@
     return ret;
 }
 
-int drmError(int err, const char *label)
+drm_public int drmError(int err, const char *label)
 {
     switch (err) {
     case DRM_ERR_NO_DEVICE:
@@ -2172,7 +2218,7 @@
  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
  * argument in a drm_control structure.
  */
-int drmCtlInstHandler(int fd, int irq)
+drm_public int drmCtlInstHandler(int fd, int irq)
 {
     drm_control_t ctl;
 
@@ -2196,7 +2242,7 @@
  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
  * argument in a drm_control structure.
  */
-int drmCtlUninstHandler(int fd)
+drm_public int drmCtlUninstHandler(int fd)
 {
     drm_control_t ctl;
 
@@ -2208,7 +2254,7 @@
     return 0;
 }
 
-int drmFinish(int fd, int context, drmLockFlags flags)
+drm_public int drmFinish(int fd, int context, drmLockFlags flags)
 {
     drm_lock_t lock;
 
@@ -2239,7 +2285,8 @@
  * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
  * arguments in a drm_irq_busid structure.
  */
-int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
+drm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
+                                        int funcnum)
 {
     drm_irq_busid_t p;
 
@@ -2252,7 +2299,7 @@
     return p.irq;
 }
 
-int drmAddContextTag(int fd, drm_context_t context, void *tag)
+drm_public int drmAddContextTag(int fd, drm_context_t context, void *tag)
 {
     drmHashEntry  *entry = drmGetEntry(fd);
 
@@ -2263,14 +2310,14 @@
     return 0;
 }
 
-int drmDelContextTag(int fd, drm_context_t context)
+drm_public int drmDelContextTag(int fd, drm_context_t context)
 {
     drmHashEntry  *entry = drmGetEntry(fd);
 
     return drmHashDelete(entry->tagTable, context);
 }
 
-void *drmGetContextTag(int fd, drm_context_t context)
+drm_public void *drmGetContextTag(int fd, drm_context_t context)
 {
     drmHashEntry  *entry = drmGetEntry(fd);
     void          *value;
@@ -2281,8 +2328,8 @@
     return value;
 }
 
-int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
-                                drm_handle_t handle)
+drm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
+                                           drm_handle_t handle)
 {
     drm_ctx_priv_map_t map;
 
@@ -2295,8 +2342,8 @@
     return 0;
 }
 
-int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
-                                drm_handle_t *handle)
+drm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
+                                           drm_handle_t *handle)
 {
     drm_ctx_priv_map_t map;
 
@@ -2311,9 +2358,9 @@
     return 0;
 }
 
-int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
-              drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
-              int *mtrr)
+drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
+                         drmMapType *type, drmMapFlags *flags,
+                         drm_handle_t *handle, int *mtrr)
 {
     drm_map_t map;
 
@@ -2330,8 +2377,8 @@
     return 0;
 }
 
-int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
-                 unsigned long *magic, unsigned long *iocs)
+drm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
+                            unsigned long *magic, unsigned long *iocs)
 {
     drm_client_t client;
 
@@ -2347,7 +2394,7 @@
     return 0;
 }
 
-int drmGetStats(int fd, drmStatsT *stats)
+drm_public int drmGetStats(int fd, drmStatsT *stats)
 {
     drm_stats_t s;
     unsigned    i;
@@ -2485,7 +2532,7 @@
  * It issues a read-write ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
-int drmSetInterfaceVersion(int fd, drmSetVersion *version)
+drm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version)
 {
     int retcode = 0;
     drm_set_version_t sv;
@@ -2520,7 +2567,7 @@
  * It issues a ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
-int drmCommandNone(int fd, unsigned long drmCommandIndex)
+drm_public int drmCommandNone(int fd, unsigned long drmCommandIndex)
 {
     unsigned long request;
 
@@ -2547,8 +2594,8 @@
  * It issues a read ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
-int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
-                   unsigned long size)
+drm_public int drmCommandRead(int fd, unsigned long drmCommandIndex,
+                              void *data, unsigned long size)
 {
     unsigned long request;
 
@@ -2576,8 +2623,8 @@
  * It issues a write ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
-int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
-                    unsigned long size)
+drm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex,
+                               void *data, unsigned long size)
 {
     unsigned long request;
 
@@ -2605,8 +2652,8 @@
  * It issues a read-write ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
-int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
-                        unsigned long size)
+drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
+                                   void *data, unsigned long size)
 {
     unsigned long request;
 
@@ -2628,14 +2675,13 @@
 
 static int nr_fds = 0;
 
-int drmOpenOnce(void *unused,
-                const char *BusID,
-                int *newlyopened)
+drm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
 {
     return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
 }
 
-int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
+drm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened,
+                                   int type)
 {
     int i;
     int fd;
@@ -2668,7 +2714,7 @@
     return fd;
 }
 
-void drmCloseOnce(int fd)
+drm_public void drmCloseOnce(int fd)
 {
     int i;
 
@@ -2687,17 +2733,17 @@
     }
 }
 
-int drmSetMaster(int fd)
+drm_public int drmSetMaster(int fd)
 {
         return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
 }
 
-int drmDropMaster(int fd)
+drm_public int drmDropMaster(int fd)
 {
         return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
 }
 
-char *drmGetDeviceNameFromFd(int fd)
+drm_public char *drmGetDeviceNameFromFd(int fd)
 {
     char name[128];
     struct stat sbuf;
@@ -2723,7 +2769,21 @@
     return strdup(name);
 }
 
-int drmGetNodeTypeFromFd(int fd)
+static bool drmNodeIsDRM(int maj, int min)
+{
+#ifdef __linux__
+    char path[64];
+    struct stat sbuf;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
+             maj, min);
+    return stat(path, &sbuf) == 0;
+#else
+    return maj == DRM_MAJOR;
+#endif
+}
+
+drm_public int drmGetNodeTypeFromFd(int fd)
 {
     struct stat sbuf;
     int maj, min, type;
@@ -2734,7 +2794,7 @@
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
-    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
         errno = EINVAL;
         return -1;
     }
@@ -2745,7 +2805,8 @@
     return type;
 }
 
-int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
+drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
+                                  int *prime_fd)
 {
     struct drm_prime_handle args;
     int ret;
@@ -2762,7 +2823,7 @@
     return 0;
 }
 
-int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
+drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
 {
     struct drm_prime_handle args;
     int ret;
@@ -2781,12 +2842,11 @@
 {
 #ifdef __linux__
     DIR *sysdir;
-    struct dirent *pent, *ent;
+    struct dirent *ent;
     struct stat sbuf;
     const char *name = drmGetMinorName(type);
     int len;
     char dev_name[64], buf[64];
-    long name_max;
     int maj, min;
 
     if (!name)
@@ -2800,7 +2860,7 @@
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
-    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return NULL;
 
     snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
@@ -2809,30 +2869,18 @@
     if (!sysdir)
         return NULL;
 
-    name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
-    if (name_max == -1)
-        goto out_close_dir;
-
-    pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
-    if (pent == NULL)
-         goto out_close_dir;
-
-    while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
+    while ((ent = readdir(sysdir))) {
         if (strncmp(ent->d_name, name, len) == 0) {
             snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
                  ent->d_name);
 
-            free(pent);
             closedir(sysdir);
-
             return strdup(dev_name);
         }
     }
 
-    free(pent);
-
-out_close_dir:
     closedir(sysdir);
+    return NULL;
 #else
     struct stat sbuf;
     char buf[PATH_MAX + 1];
@@ -2846,7 +2894,7 @@
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
-    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return NULL;
 
     switch (type) {
@@ -2873,15 +2921,14 @@
 
     return strdup(buf);
 #endif
-    return NULL;
 }
 
-char *drmGetPrimaryDeviceNameFromFd(int fd)
+drm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
 {
     return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
 }
 
-char *drmGetRenderDeviceNameFromFd(int fd)
+drm_public char *drmGetRenderDeviceNameFromFd(int fd)
 {
     return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
 }
@@ -2930,12 +2977,26 @@
 }
 #endif
 
+/* Little white lie to avoid major rework of the existing code */
+#define DRM_BUS_VIRTIO 0x10
+
 static int drmParseSubsystemType(int maj, int min)
 {
 #ifdef __linux__
     char path[PATH_MAX + 1];
     char link[PATH_MAX + 1] = "";
     char *name;
+    struct {
+        const char *name;
+        int bus_type;
+    } bus_types[] = {
+        { "/pci", DRM_BUS_PCI },
+        { "/usb", DRM_BUS_USB },
+        { "/platform", DRM_BUS_PLATFORM },
+        { "/spi", DRM_BUS_PLATFORM },
+        { "/host1x", DRM_BUS_HOST1X },
+        { "/virtio", DRM_BUS_VIRTIO },
+    };
 
     snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
              maj, min);
@@ -2947,20 +3008,13 @@
     if (!name)
         return -EINVAL;
 
-    if (strncmp(name, "/pci", 4) == 0)
-        return DRM_BUS_PCI;
-
-    if (strncmp(name, "/usb", 4) == 0)
-        return DRM_BUS_USB;
-
-    if (strncmp(name, "/platform", 9) == 0)
-        return DRM_BUS_PLATFORM;
-
-    if (strncmp(name, "/host1x", 7) == 0)
-        return DRM_BUS_HOST1X;
+    for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
+        if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
+            return bus_types[i].bus_type;
+    }
 
     return -EINVAL;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
     return DRM_BUS_PCI;
 #else
 #warning "Missing implementation of drmParseSubsystemType"
@@ -2968,16 +3022,32 @@
 #endif
 }
 
+static void
+get_pci_path(int maj, int min, char *pci_path)
+{
+    char path[PATH_MAX + 1], *term;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+    if (!realpath(path, pci_path)) {
+        strcpy(pci_path, path);
+        return;
+    }
+
+    term = strrchr(pci_path, '/');
+    if (term && strncmp(term, "/virtio", 7) == 0)
+        *term = 0;
+}
+
 static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
 {
 #ifdef __linux__
     unsigned int domain, bus, dev, func;
-    char path[PATH_MAX + 1], *value;
+    char pci_path[PATH_MAX + 1], *value;
     int num;
 
-    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+    get_pci_path(maj, min, pci_path);
 
-    value = sysfs_uevent_get(path, "PCI_SLOT_NAME");
+    value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
     if (!value)
         return -ENOENT;
 
@@ -2993,7 +3063,7 @@
     info->func = func;
 
     return 0;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
     struct drm_pciinfo pinfo;
     int fd, type;
 
@@ -3023,32 +3093,32 @@
 #endif
 }
 
-static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
+drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
 {
     if (a == NULL || b == NULL)
-        return -1;
+        return 0;
 
     if (a->bustype != b->bustype)
-        return -1;
+        return 0;
 
     switch (a->bustype) {
     case DRM_BUS_PCI:
-        return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
+        return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
 
     case DRM_BUS_USB:
-        return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
+        return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
 
     case DRM_BUS_PLATFORM:
-        return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo));
+        return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
 
     case DRM_BUS_HOST1X:
-        return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo));
+        return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
 
     default:
         break;
     }
 
-    return -1;
+    return 0;
 }
 
 static int drmGetNodeType(const char *name)
@@ -3082,7 +3152,6 @@
                                       drmPciDeviceInfoPtr device,
                                       bool ignore_revision)
 {
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
     static const char *attrs[] = {
       "revision", /* Older kernels are missing the file, so check for it first */
       "vendor",
@@ -3090,14 +3159,15 @@
       "subsystem_vendor",
       "subsystem_device",
     };
-    char path[PATH_MAX + 1];
+    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
     unsigned int data[ARRAY_SIZE(attrs)];
     FILE *fp;
     int ret;
 
+    get_pci_path(maj, min, pci_path);
+
     for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
-        snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min,
-                 attrs[i]);
+        snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]);
         fp = fopen(path, "r");
         if (!fp)
             return -errno;
@@ -3121,11 +3191,13 @@
 static int parse_config_sysfs_file(int maj, int min,
                                    drmPciDeviceInfoPtr device)
 {
-    char path[PATH_MAX + 1];
+    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
     unsigned char config[64];
     int fd, ret;
 
-    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min);
+    get_pci_path(maj, min, pci_path);
+
+    snprintf(path, PATH_MAX, "%s/config", pci_path);
     fd = open(path, O_RDONLY);
     if (fd < 0)
         return -errno;
@@ -3157,7 +3229,7 @@
         return parse_config_sysfs_file(maj, min, device);
 
     return 0;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
     struct drm_pciinfo pinfo;
     int fd, type;
 
@@ -3220,7 +3292,7 @@
     }
 }
 
-void drmFreeDevice(drmDevicePtr *device)
+drm_public void drmFreeDevice(drmDevicePtr *device)
 {
     if (device == NULL)
         return;
@@ -3241,7 +3313,7 @@
     *device = NULL;
 }
 
-void drmFreeDevices(drmDevicePtr devices[], int count)
+drm_public void drmFreeDevices(drmDevicePtr devices[], int count)
 {
     int i;
 
@@ -3652,6 +3724,53 @@
     return ret;
 }
 
+static int
+process_device(drmDevicePtr *device, const char *d_name,
+               int req_subsystem_type,
+               bool fetch_deviceinfo, uint32_t flags)
+{
+    struct stat sbuf;
+    char node[PATH_MAX + 1];
+    int node_type, subsystem_type;
+    unsigned int maj, min;
+
+    node_type = drmGetNodeType(d_name);
+    if (node_type < 0)
+        return -1;
+
+    snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
+    if (stat(node, &sbuf))
+        return -1;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
+        return -1;
+
+    subsystem_type = drmParseSubsystemType(maj, min);
+    if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
+        return -1;
+
+    switch (subsystem_type) {
+    case DRM_BUS_PCI:
+    case DRM_BUS_VIRTIO:
+        return drmProcessPciDevice(device, node, node_type, maj, min,
+                                   fetch_deviceinfo, flags);
+    case DRM_BUS_USB:
+        return drmProcessUsbDevice(device, node, node_type, maj, min,
+                                   fetch_deviceinfo, flags);
+    case DRM_BUS_PLATFORM:
+        return drmProcessPlatformDevice(device, node, node_type, maj, min,
+                                        fetch_deviceinfo, flags);
+    case DRM_BUS_HOST1X:
+        return drmProcessHost1xDevice(device, node, node_type, maj, min,
+                                      fetch_deviceinfo, flags);
+    default:
+        return -1;
+   }
+}
+
 /* Consider devices located on the same bus as duplicate and fold the respective
  * entries into a single one.
  *
@@ -3663,7 +3782,7 @@
 
     for (i = 0; i < count; i++) {
         for (j = i + 1; j < count; j++) {
-            if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
+            if (drmDevicesEqual(local_devices[i], local_devices[j])) {
                 local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
                 node_type = log2(local_devices[j]->available_nodes);
                 memcpy(local_devices[i]->nodes[node_type],
@@ -3681,6 +3800,28 @@
         return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
 }
 
+static bool
+drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
+{
+    struct stat sbuf;
+
+    for (int i = 0; i < DRM_NODE_MAX; i++) {
+        if (device->available_nodes & 1 << i) {
+            if (stat(device->nodes[i], &sbuf) == 0 &&
+                sbuf.st_rdev == find_rdev)
+                return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * The kernel drm core has a number of places that assume maximum of
+ * 3x64 devices nodes. That's 64 for each of primary, control and
+ * render nodes. Rounded it up to 256 for simplicity.
+ */
+#define MAX_DRM_NODES 256
+
 /**
  * Get information about the opened drm device
  *
@@ -3694,7 +3835,7 @@
  * \note Unlike drmGetDevice it does not retrieve the pci device revision field
  * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
  */
-int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
+drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
 {
 #ifdef __OpenBSD__
     /*
@@ -3718,7 +3859,7 @@
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
-    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return -EINVAL;
 
     node_type = drmGetMinorType(min);
@@ -3761,16 +3902,14 @@
 
     return 0;
 #else
-    drmDevicePtr *local_devices;
+    drmDevicePtr local_devices[MAX_DRM_NODES];
     drmDevicePtr d;
     DIR *sysdir;
     struct dirent *dent;
     struct stat sbuf;
-    char node[PATH_MAX + 1];
-    int node_type, subsystem_type;
+    int subsystem_type;
     int maj, min;
     int ret, i, node_count;
-    int max_count = 16;
     dev_t find_rdev;
 
     if (drm_device_validate_flags(flags))
@@ -3786,112 +3925,52 @@
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
-    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return -EINVAL;
 
     subsystem_type = drmParseSubsystemType(maj, min);
-
-    local_devices = calloc(max_count, sizeof(drmDevicePtr));
-    if (local_devices == NULL)
-        return -ENOMEM;
+    if (subsystem_type < 0)
+        return subsystem_type;
 
     sysdir = opendir(DRM_DIR_NAME);
-    if (!sysdir) {
-        ret = -errno;
-        goto free_locals;
-    }
+    if (!sysdir)
+        return -errno;
 
     i = 0;
     while ((dent = readdir(sysdir))) {
-        node_type = drmGetNodeType(dent->d_name);
-        if (node_type < 0)
+        ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
+        if (ret)
             continue;
 
-        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
-        if (stat(node, &sbuf))
-            continue;
-
-        maj = major(sbuf.st_rdev);
-        min = minor(sbuf.st_rdev);
-
-        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
-            continue;
-
-        if (drmParseSubsystemType(maj, min) != subsystem_type)
-            continue;
-
-        switch (subsystem_type) {
-        case DRM_BUS_PCI:
-            ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
-            if (ret)
-                continue;
-
+        if (i >= MAX_DRM_NODES) {
+            fprintf(stderr, "More than %d drm nodes detected. "
+                    "Please report a bug - that should not happen.\n"
+                    "Skipping extra nodes\n", MAX_DRM_NODES);
             break;
-
-        case DRM_BUS_USB:
-            ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
-            if (ret)
-                continue;
-
-            break;
-
-        case DRM_BUS_PLATFORM:
-            ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
-            if (ret)
-                continue;
-
-            break;
-
-        case DRM_BUS_HOST1X:
-            ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
-            if (ret)
-                continue;
-
-            break;
-
-        default:
-            continue;
         }
-
-        if (i >= max_count) {
-            drmDevicePtr *temp;
-
-            max_count += 16;
-            temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
-            if (!temp)
-                goto free_devices;
-            local_devices = temp;
-        }
-
-        /* store target at local_devices[0] for ease to use below */
-        if (find_rdev == sbuf.st_rdev && i) {
-            local_devices[i] = local_devices[0];
-            local_devices[0] = d;
-        }
-        else
-            local_devices[i] = d;
+        local_devices[i] = d;
         i++;
     }
     node_count = i;
 
     drmFoldDuplicatedDevices(local_devices, node_count);
 
-    *device = local_devices[0];
-    drmFreeDevices(&local_devices[1], node_count - 1);
+    *device = NULL;
+
+    for (i = 0; i < node_count; i++) {
+        if (!local_devices[i])
+            continue;
+
+        if (drm_device_has_rdev(local_devices[i], find_rdev))
+            *device = local_devices[i];
+        else
+            drmFreeDevice(&local_devices[i]);
+    }
 
     closedir(sysdir);
-    free(local_devices);
     if (*device == NULL)
         return -ENODEV;
     return 0;
-
-free_devices:
-    drmFreeDevices(local_devices, i);
-    closedir(sysdir);
-
-free_locals:
-    free(local_devices);
-    return ret;
 #endif
 }
 
@@ -3904,7 +3983,7 @@
  *
  * \return zero on success, negative error code otherwise.
  */
-int drmGetDevice(int fd, drmDevicePtr *device)
+drm_public int drmGetDevice(int fd, drmDevicePtr *device)
 {
     return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
 }
@@ -3925,100 +4004,34 @@
  * \note Unlike drmGetDevices it does not retrieve the pci device revision field
  * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
  */
-int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
+drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
+                              int max_devices)
 {
-    drmDevicePtr *local_devices;
+    drmDevicePtr local_devices[MAX_DRM_NODES];
     drmDevicePtr device;
     DIR *sysdir;
     struct dirent *dent;
-    struct stat sbuf;
-    char node[PATH_MAX + 1];
-    int node_type, subsystem_type;
-    int maj, min;
     int ret, i, node_count, device_count;
-    int max_count = 16;
 
     if (drm_device_validate_flags(flags))
         return -EINVAL;
 
-    local_devices = calloc(max_count, sizeof(drmDevicePtr));
-    if (local_devices == NULL)
-        return -ENOMEM;
-
     sysdir = opendir(DRM_DIR_NAME);
-    if (!sysdir) {
-        ret = -errno;
-        goto free_locals;
-    }
+    if (!sysdir)
+        return -errno;
 
     i = 0;
     while ((dent = readdir(sysdir))) {
-        node_type = drmGetNodeType(dent->d_name);
-        if (node_type < 0)
+        ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
+        if (ret)
             continue;
 
-        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
-        if (stat(node, &sbuf))
-            continue;
-
-        maj = major(sbuf.st_rdev);
-        min = minor(sbuf.st_rdev);
-
-        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
-            continue;
-
-        subsystem_type = drmParseSubsystemType(maj, min);
-
-        if (subsystem_type < 0)
-            continue;
-
-        switch (subsystem_type) {
-        case DRM_BUS_PCI:
-            ret = drmProcessPciDevice(&device, node, node_type,
-                                      maj, min, devices != NULL, flags);
-            if (ret)
-                continue;
-
+        if (i >= MAX_DRM_NODES) {
+            fprintf(stderr, "More than %d drm nodes detected. "
+                    "Please report a bug - that should not happen.\n"
+                    "Skipping extra nodes\n", MAX_DRM_NODES);
             break;
-
-        case DRM_BUS_USB:
-            ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
-                                      devices != NULL, flags);
-            if (ret)
-                goto free_devices;
-
-            break;
-
-        case DRM_BUS_PLATFORM:
-            ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
-                                           devices != NULL, flags);
-            if (ret)
-                goto free_devices;
-
-            break;
-
-        case DRM_BUS_HOST1X:
-            ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
-                                         devices != NULL, flags);
-            if (ret)
-                goto free_devices;
-
-            break;
-
-        default:
-            continue;
         }
-
-        if (i >= max_count) {
-            drmDevicePtr *temp;
-
-            max_count += 16;
-            temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
-            if (!temp)
-                goto free_devices;
-            local_devices = temp;
-        }
-
         local_devices[i] = device;
         i++;
     }
@@ -4040,16 +4053,7 @@
     }
 
     closedir(sysdir);
-    free(local_devices);
     return device_count;
-
-free_devices:
-    drmFreeDevices(local_devices, i);
-    closedir(sysdir);
-
-free_locals:
-    free(local_devices);
-    return ret;
 }
 
 /**
@@ -4064,12 +4068,12 @@
  *         alternatively the number of devices stored in devices[], which is
  *         capped by the max_devices.
  */
-int drmGetDevices(drmDevicePtr devices[], int max_devices)
+drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
 {
     return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
 }
 
-char *drmGetDeviceNameFromFd2(int fd)
+drm_public char *drmGetDeviceNameFromFd2(int fd)
 {
 #ifdef __linux__
     struct stat sbuf;
@@ -4082,7 +4086,7 @@
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
-    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return NULL;
 
     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
@@ -4108,7 +4112,7 @@
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
-    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return NULL;
 
     node_type = drmGetMinorType(min);
@@ -4140,3 +4144,136 @@
     return strdup(node);
 #endif
 }
+
+drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
+{
+    struct drm_syncobj_create args;
+    int ret;
+
+    memclear(args);
+    args.flags = flags;
+    args.handle = 0;
+    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
+    if (ret)
+        return ret;
+    *handle = args.handle;
+    return 0;
+}
+
+drm_public int drmSyncobjDestroy(int fd, uint32_t handle)
+{
+    struct drm_syncobj_destroy args;
+
+    memclear(args);
+    args.handle = handle;
+    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
+}
+
+drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
+{
+    struct drm_syncobj_handle args;
+    int ret;
+
+    memclear(args);
+    args.fd = -1;
+    args.handle = handle;
+    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
+    if (ret)
+        return ret;
+    *obj_fd = args.fd;
+    return 0;
+}
+
+drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
+{
+    struct drm_syncobj_handle args;
+    int ret;
+
+    memclear(args);
+    args.fd = obj_fd;
+    args.handle = 0;
+    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
+    if (ret)
+        return ret;
+    *handle = args.handle;
+    return 0;
+}
+
+drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
+                                        int sync_file_fd)
+{
+    struct drm_syncobj_handle args;
+
+    memclear(args);
+    args.fd = sync_file_fd;
+    args.handle = handle;
+    args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
+    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
+}
+
+drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
+                                        int *sync_file_fd)
+{
+    struct drm_syncobj_handle args;
+    int ret;
+
+    memclear(args);
+    args.fd = -1;
+    args.handle = handle;
+    args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
+    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
+    if (ret)
+        return ret;
+    *sync_file_fd = args.fd;
+    return 0;
+}
+
+drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
+                              int64_t timeout_nsec, unsigned flags,
+                              uint32_t *first_signaled)
+{
+    struct drm_syncobj_wait args;
+    int ret;
+
+    memclear(args);
+    args.handles = (uintptr_t)handles;
+    args.timeout_nsec = timeout_nsec;
+    args.count_handles = num_handles;
+    args.flags = flags;
+
+    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
+    if (ret < 0)
+        return -errno;
+
+    if (first_signaled)
+        *first_signaled = args.first_signaled;
+    return ret;
+}
+
+drm_public int drmSyncobjReset(int fd, const uint32_t *handles,
+                               uint32_t handle_count)
+{
+    struct drm_syncobj_array args;
+    int ret;
+
+    memclear(args);
+    args.handles = (uintptr_t)handles;
+    args.count_handles = handle_count;
+
+    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
+    return ret;
+}
+
+drm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
+                                uint32_t handle_count)
+{
+    struct drm_syncobj_array args;
+    int ret;
+
+    memclear(args);
+    args.handles = (uintptr_t)handles;
+    args.count_handles = handle_count;
+
+    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
+    return ret;
+}
diff --git a/xf86drm.h b/xf86drm.h
index 0d92701..7773d71 100644
--- a/xf86drm.h
+++ b/xf86drm.h
@@ -636,6 +636,12 @@
 extern int           drmSetClientCap(int fd, uint64_t capability,
 				     uint64_t value);
 
+extern int           drmCrtcGetSequence(int fd, uint32_t crtcId,
+					uint64_t *sequence, uint64_t *ns);
+extern int           drmCrtcQueueSequence(int fd, uint32_t crtcId,
+					  uint32_t flags, uint64_t sequence,
+					  uint64_t *sequence_queued,
+					  uint64_t user_data);
 /* General user-level programmer's API: authenticated client and/or X */
 extern int           drmMap(int fd,
 			    drm_handle_t handle,
@@ -728,7 +734,7 @@
 extern int drmSetMaster(int fd);
 extern int drmDropMaster(int fd);
 
-#define DRM_EVENT_CONTEXT_VERSION 2
+#define DRM_EVENT_CONTEXT_VERSION 4
 
 typedef struct _drmEventContext {
 
@@ -748,6 +754,17 @@
 				  unsigned int tv_usec,
 				  void *user_data);
 
+	void (*page_flip_handler2)(int fd,
+				   unsigned int sequence,
+				   unsigned int tv_sec,
+				   unsigned int tv_usec,
+				   unsigned int crtc_id,
+				   void *user_data);
+
+	void (*sequence_handler)(int fd,
+				 uint64_t sequence,
+				 uint64_t ns,
+				 uint64_t user_data);
 } drmEventContext, *drmEventContextPtr;
 
 extern int drmHandleEvent(int fd, drmEventContextPtr evctx);
@@ -844,6 +861,21 @@
 extern int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device);
 extern int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices);
 
+extern int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b);
+
+extern int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle);
+extern int drmSyncobjDestroy(int fd, uint32_t handle);
+extern int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd);
+extern int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle);
+
+extern int drmSyncobjImportSyncFile(int fd, uint32_t handle, int sync_file_fd);
+extern int drmSyncobjExportSyncFile(int fd, uint32_t handle, int *sync_file_fd);
+extern int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
+			  int64_t timeout_nsec, unsigned flags,
+			  uint32_t *first_signaled);
+extern int drmSyncobjReset(int fd, const uint32_t *handles, uint32_t handle_count);
+extern int drmSyncobjSignal(int fd, const uint32_t *handles, uint32_t handle_count);
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/xf86drmHash.c b/xf86drmHash.c
index f287e61..2cf2b80 100644
--- a/xf86drmHash.c
+++ b/xf86drmHash.c
@@ -71,6 +71,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "libdrm_macros.h"
 #include "xf86drm.h"
 #include "xf86drmHash.h"
 
@@ -98,30 +99,21 @@
     }
 
     hash %= HASH_SIZE;
-#if DEBUG
-    printf( "Hash(%lu) = %lu\n", key, hash);
-#endif
     return hash;
 }
 
-void *drmHashCreate(void)
+drm_public void *drmHashCreate(void)
 {
     HashTablePtr table;
-    int          i;
 
     table           = drmMalloc(sizeof(*table));
     if (!table) return NULL;
     table->magic    = HASH_MAGIC;
-    table->entries  = 0;
-    table->hits     = 0;
-    table->partials = 0;
-    table->misses   = 0;
 
-    for (i = 0; i < HASH_SIZE; i++) table->buckets[i] = NULL;
     return table;
 }
 
-int drmHashDestroy(void *t)
+drm_public int drmHashDestroy(void *t)
 {
     HashTablePtr  table = (HashTablePtr)t;
     HashBucketPtr bucket;
@@ -172,7 +164,7 @@
     return NULL;
 }
 
-int drmHashLookup(void *t, unsigned long key, void **value)
+drm_public int drmHashLookup(void *t, unsigned long key, void **value)
 {
     HashTablePtr  table = (HashTablePtr)t;
     HashBucketPtr bucket;
@@ -185,7 +177,7 @@
     return 0;			/* Found */
 }
 
-int drmHashInsert(void *t, unsigned long key, void *value)
+drm_public int drmHashInsert(void *t, unsigned long key, void *value)
 {
     HashTablePtr  table = (HashTablePtr)t;
     HashBucketPtr bucket;
@@ -201,13 +193,10 @@
     bucket->value        = value;
     bucket->next         = table->buckets[hash];
     table->buckets[hash] = bucket;
-#if DEBUG
-    printf("Inserted %lu at %lu/%p\n", key, hash, bucket);
-#endif
     return 0;			/* Added to table */
 }
 
-int drmHashDelete(void *t, unsigned long key)
+drm_public int drmHashDelete(void *t, unsigned long key)
 {
     HashTablePtr  table = (HashTablePtr)t;
     unsigned long hash;
@@ -224,7 +213,7 @@
     return 0;
 }
 
-int drmHashNext(void *t, unsigned long *key, void **value)
+drm_public int drmHashNext(void *t, unsigned long *key, void **value)
 {
     HashTablePtr  table = (HashTablePtr)t;
 
@@ -241,7 +230,7 @@
     return 0;
 }
 
-int drmHashFirst(void *t, unsigned long *key, void **value)
+drm_public int drmHashFirst(void *t, unsigned long *key, void **value)
 {
     HashTablePtr  table = (HashTablePtr)t;
 
diff --git a/xf86drmMode.c b/xf86drmMode.c
index 2876b42..c878d9e 100644
--- a/xf86drmMode.c
+++ b/xf86drmMode.c
@@ -38,10 +38,6 @@
  * platforms find which headers to include to get uint32_t
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <limits.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -52,6 +48,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 
+#include "libdrm_macros.h"
 #include "xf86drmMode.h"
 #include "xf86drm.h"
 #include <drm.h>
@@ -96,7 +93,7 @@
  * A couple of free functions.
  */
 
-void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
+drm_public void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -104,7 +101,7 @@
 	drmFree(ptr);
 }
 
-void drmModeFreeResources(drmModeResPtr ptr)
+drm_public void drmModeFreeResources(drmModeResPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -116,7 +113,7 @@
 	drmFree(ptr);
 }
 
-void drmModeFreeFB(drmModeFBPtr ptr)
+drm_public void drmModeFreeFB(drmModeFBPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -125,7 +122,7 @@
 	drmFree(ptr);
 }
 
-void drmModeFreeCrtc(drmModeCrtcPtr ptr)
+drm_public void drmModeFreeCrtc(drmModeCrtcPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -133,7 +130,7 @@
 	drmFree(ptr);
 }
 
-void drmModeFreeConnector(drmModeConnectorPtr ptr)
+drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -145,7 +142,7 @@
 	drmFree(ptr);
 }
 
-void drmModeFreeEncoder(drmModeEncoderPtr ptr)
+drm_public void drmModeFreeEncoder(drmModeEncoderPtr ptr)
 {
 	drmFree(ptr);
 }
@@ -154,7 +151,7 @@
  * ModeSetting functions.
  */
 
-drmModeResPtr drmModeGetResources(int fd)
+drm_public drmModeResPtr drmModeGetResources(int fd)
 {
 	struct drm_mode_card_res res, counts;
 	drmModeResPtr r = 0;
@@ -248,9 +245,10 @@
 	return r;
 }
 
-int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
-		 uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
-		 uint32_t *buf_id)
+
+drm_public int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
+                            uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
+                            uint32_t *buf_id)
 {
 	struct drm_mode_fb_cmd f;
 	int ret;
@@ -270,10 +268,10 @@
 	return 0;
 }
 
-int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height,
-                               uint32_t pixel_format, uint32_t bo_handles[4],
-                               uint32_t pitches[4], uint32_t offsets[4],
-                               uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)
+drm_public int drmModeAddFB2WithModifiers(int fd, uint32_t width,
+		uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4],
+		const uint32_t pitches[4], const uint32_t offsets[4],
+		const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)
 {
 	struct drm_mode_fb_cmd2 f;
 	int ret;
@@ -296,10 +294,10 @@
 	return 0;
 }
 
-int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
-                  uint32_t pixel_format, uint32_t bo_handles[4],
-                  uint32_t pitches[4], uint32_t offsets[4],
-                  uint32_t *buf_id, uint32_t flags)
+drm_public int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
+		uint32_t pixel_format, const uint32_t bo_handles[4],
+		const uint32_t pitches[4], const uint32_t offsets[4],
+		uint32_t *buf_id, uint32_t flags)
 {
 	return drmModeAddFB2WithModifiers(fd, width, height,
 					  pixel_format, bo_handles,
@@ -307,12 +305,12 @@
 					  buf_id, flags);
 }
 
-int drmModeRmFB(int fd, uint32_t bufferId)
+drm_public int drmModeRmFB(int fd, uint32_t bufferId)
 {
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
 }
 
-drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
+drm_public drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
 {
 	struct drm_mode_fb_cmd info;
 	drmModeFBPtr r;
@@ -337,7 +335,7 @@
 	return r;
 }
 
-int drmModeDirtyFB(int fd, uint32_t bufferId,
+drm_public int drmModeDirtyFB(int fd, uint32_t bufferId,
 		   drmModeClipPtr clips, uint32_t num_clips)
 {
 	struct drm_mode_fb_dirty_cmd dirty;
@@ -354,7 +352,7 @@
  * Crtc functions
  */
 
-drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
+drm_public drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
 {
 	struct drm_mode_crtc crtc;
 	drmModeCrtcPtr r;
@@ -386,7 +384,7 @@
 	return r;
 }
 
-int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
+drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
 		   uint32_t x, uint32_t y, uint32_t *connectors, int count,
 		   drmModeModeInfoPtr mode)
 {
@@ -411,7 +409,8 @@
  * Cursor manipulation
  */
 
-int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
+drm_public int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle,
+								uint32_t width, uint32_t height)
 {
 	struct drm_mode_cursor arg;
 
@@ -425,7 +424,9 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
 }
 
-int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y)
+drm_public int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle,
+								 uint32_t width, uint32_t height, int32_t hot_x,
+								 int32_t hot_y)
 {
 	struct drm_mode_cursor2 arg;
 
@@ -441,7 +442,7 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR2, &arg);
 }
 
-int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
+drm_public int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
 {
 	struct drm_mode_cursor arg;
 
@@ -457,7 +458,7 @@
 /*
  * Encoder get
  */
-drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
+drm_public drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
 {
 	struct drm_mode_get_encoder enc;
 	drmModeEncoderPtr r = NULL;
@@ -589,17 +590,17 @@
 	return r;
 }
 
-drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
+drm_public drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
 {
 	return _drmModeGetConnector(fd, connector_id, 1);
 }
 
-drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
+drm_public drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
 {
 	return _drmModeGetConnector(fd, connector_id, 0);
 }
 
-int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
+drm_public int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
 {
 	struct drm_mode_mode_cmd res;
 
@@ -610,7 +611,7 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
 }
 
-int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
+drm_public int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
 {
 	struct drm_mode_mode_cmd res;
 
@@ -621,7 +622,7 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
 }
 
-drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
+drm_public drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
 {
 	struct drm_mode_get_property prop;
 	drmModePropertyPtr r;
@@ -675,7 +676,7 @@
 	return r;
 }
 
-void drmModeFreeProperty(drmModePropertyPtr ptr)
+drm_public void drmModeFreeProperty(drmModePropertyPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -685,7 +686,8 @@
 	drmFree(ptr);
 }
 
-drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
+drm_public drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd,
+														 uint32_t blob_id)
 {
 	struct drm_mode_get_blob blob;
 	drmModePropertyBlobPtr r;
@@ -716,7 +718,7 @@
 	return r;
 }
 
-void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
+drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -725,8 +727,9 @@
 	drmFree(ptr);
 }
 
-int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id,
-			     uint64_t value)
+drm_public int drmModeConnectorSetProperty(int fd, uint32_t connector_id,
+										   uint32_t property_id,
+										   uint64_t value)
 {
 	struct drm_mode_connector_set_property osp;
 
@@ -744,7 +747,7 @@
  *  -EINVAL or invalid bus id
  *  -ENOSYS if no modesetting support
 */
-int drmCheckModesettingSupported(const char *busid)
+drm_public int drmCheckModesettingSupported(const char *busid)
 {
 #if defined (__linux__)
 	char pci_dev_dir[1024];
@@ -831,8 +834,7 @@
 	}
 #elif defined(__DragonFly__)
 	return 0;
-#endif
-#ifdef __OpenBSD__
+#elif defined(__OpenBSD__)
 	int	fd;
 	struct drm_mode_card_res res;
 	drmModeResPtr r = 0;
@@ -853,8 +855,9 @@
 	return -ENOSYS;
 }
 
-int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
-			uint16_t *red, uint16_t *green, uint16_t *blue)
+drm_public int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
+								   uint16_t *red, uint16_t *green,
+								   uint16_t *blue)
 {
 	struct drm_mode_crtc_lut l;
 
@@ -868,8 +871,9 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_GETGAMMA, &l);
 }
 
-int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
-			uint16_t *red, uint16_t *green, uint16_t *blue)
+drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
+								   uint16_t *red, uint16_t *green,
+								   uint16_t *blue)
 {
 	struct drm_mode_crtc_lut l;
 
@@ -883,12 +887,14 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l);
 }
 
-int drmHandleEvent(int fd, drmEventContextPtr evctx)
+drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx)
 {
 	char buffer[1024];
 	int len, i;
 	struct drm_event *e;
 	struct drm_event_vblank *vblank;
+	struct drm_event_crtc_sequence *seq;
+	void *user_data;
 
 	/* The DRM read semantics guarantees that we always get only
 	 * complete events. */
@@ -915,15 +921,30 @@
 					      U642VOID (vblank->user_data));
 			break;
 		case DRM_EVENT_FLIP_COMPLETE:
-			if (evctx->version < 2 ||
-			    evctx->page_flip_handler == NULL)
-				break;
 			vblank = (struct drm_event_vblank *) e;
-			evctx->page_flip_handler(fd,
-						 vblank->sequence,
-						 vblank->tv_sec,
-						 vblank->tv_usec,
-						 U642VOID (vblank->user_data));
+			user_data = U642VOID (vblank->user_data);
+
+			if (evctx->version >= 3 && evctx->page_flip_handler2)
+				evctx->page_flip_handler2(fd,
+							 vblank->sequence,
+							 vblank->tv_sec,
+							 vblank->tv_usec,
+							 vblank->crtc_id,
+							 user_data);
+			else if (evctx->version >= 2 && evctx->page_flip_handler)
+				evctx->page_flip_handler(fd,
+							 vblank->sequence,
+							 vblank->tv_sec,
+							 vblank->tv_usec,
+							 user_data);
+			break;
+		case DRM_EVENT_CRTC_SEQUENCE:
+			seq = (struct drm_event_crtc_sequence *) e;
+			if (evctx->version >= 4 && evctx->sequence_handler)
+				evctx->sequence_handler(fd,
+							seq->sequence,
+							seq->time_ns,
+							seq->user_data);
 			break;
 		default:
 			break;
@@ -934,7 +955,7 @@
 	return 0;
 }
 
-int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
+drm_public int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
 		    uint32_t flags, void *user_data)
 {
 	struct drm_mode_crtc_page_flip flip;
@@ -948,7 +969,7 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
 }
 
-int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id,
+drm_public int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id,
 			  uint32_t flags, void *user_data,
 			  uint32_t target_vblank)
 {
@@ -964,7 +985,7 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target);
 }
 
-int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id,
+drm_public int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id,
 		    uint32_t fb_id, uint32_t flags,
 		    int32_t crtc_x, int32_t crtc_y,
 		    uint32_t crtc_w, uint32_t crtc_h,
@@ -990,7 +1011,7 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, &s);
 }
 
-drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
+drm_public drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
 {
 	struct drm_mode_get_plane ovr, counts;
 	drmModePlanePtr r = 0;
@@ -1041,7 +1062,7 @@
 	return r;
 }
 
-void drmModeFreePlane(drmModePlanePtr ptr)
+drm_public void drmModeFreePlane(drmModePlanePtr ptr)
 {
 	if (!ptr)
 		return;
@@ -1050,7 +1071,7 @@
 	drmFree(ptr);
 }
 
-drmModePlaneResPtr drmModeGetPlaneResources(int fd)
+drm_public drmModePlaneResPtr drmModeGetPlaneResources(int fd)
 {
 	struct drm_mode_get_plane_res res, counts;
 	drmModePlaneResPtr r = 0;
@@ -1095,7 +1116,7 @@
 	return r;
 }
 
-void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
+drm_public void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -1104,7 +1125,7 @@
 	drmFree(ptr);
 }
 
-drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
+drm_public drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
 						      uint32_t object_id,
 						      uint32_t object_type)
 {
@@ -1165,7 +1186,7 @@
 	return ret;
 }
 
-void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
+drm_public void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
 {
 	if (!ptr)
 		return;
@@ -1174,7 +1195,7 @@
 	drmFree(ptr);
 }
 
-int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type,
+drm_public int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type,
 			     uint32_t property_id, uint64_t value)
 {
 	struct drm_mode_obj_set_property prop;
@@ -1188,275 +1209,6 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop);
 }
 
-typedef struct _drmModePropertySetItem drmModePropertySetItem, *drmModePropertySetItemPtr;
-
-struct _drmModePropertySetItem {
-	uint32_t object_id;
-	uint32_t property_id;
-	bool is_blob;
-	uint64_t value;
-	void *blob;
-	drmModePropertySetItemPtr next;
-};
-
-struct _drmModePropertySet {
-	unsigned int count_objs;
-	unsigned int count_props;
-	unsigned int count_blobs;
-	drmModePropertySetItem list;
-};
-
-drmModePropertySetPtr drmModePropertySetAlloc(void)
-{
-	drmModePropertySetPtr set;
-
-	set = drmMalloc(sizeof *set);
-	if (!set)
-		return NULL;
-
-	set->list.next = NULL;
-	set->count_props = 0;
-	set->count_objs = 0;
-
-	return set;
-}
-
-int drmModePropertySetAdd(drmModePropertySetPtr set,
-			  uint32_t object_id,
-			  uint32_t property_id,
-			  uint64_t value)
-{
-	drmModePropertySetItemPtr prev = &set->list;
-	bool new_obj = false;
-
-	/* keep it sorted by object_id and property_id */
-	while (prev->next) {
-		if (prev->next->object_id > object_id)
-			break;
-
-		if (prev->next->object_id == object_id &&
-		    prev->next->property_id >= property_id)
-			break;
-
-		prev = prev->next;
-	}
-
-	if ((prev == &set->list || prev->object_id != object_id) &&
-	    (!prev->next || prev->next->object_id != object_id))
-		new_obj = true;
-
-	/* replace or add? */
-	if (prev->next &&
-	    prev->next->object_id == object_id &&
-	    prev->next->property_id == property_id) {
-		drmModePropertySetItemPtr item = prev->next;
-
-		if (item->is_blob)
-			return -EINVAL;
-
-		item->value = value;
-	} else {
-		drmModePropertySetItemPtr item;
-
-		item = drmMalloc(sizeof *item);
-		if (!item)
-			return -1;
-
-		item->object_id = object_id;
-		item->property_id = property_id;
-		item->value = value;
-		item->is_blob = false;
-		item->blob = NULL;
-
-		item->next = prev->next;
-		prev->next = item;
-
-		set->count_props++;
-	}
-
-	if (new_obj)
-		set->count_objs++;
-
-	return 0;
-}
-
-int drmModePropertySetAddBlob(drmModePropertySetPtr set,
-			      uint32_t object_id,
-			      uint32_t property_id,
-			      uint64_t length,
-			      void *data)
-{
-	drmModePropertySetItemPtr prev = &set->list;
-	bool new_obj = false;
-
-	/* keep it sorted by object_id and property_id */
-	while (prev->next) {
-		if (prev->next->object_id > object_id)
-			break;
-
-		if (prev->next->object_id == object_id &&
-		    prev->next->property_id >= property_id)
-			break;
-
-		prev = prev->next;
-	}
-
-	if ((prev == &set->list || prev->object_id != object_id) &&
-	    (!prev->next || prev->next->object_id != object_id))
-		new_obj = true;
-
-	/* replace or add? */
-	if (prev->next &&
-	    prev->next->object_id == object_id &&
-	    prev->next->property_id == property_id) {
-		drmModePropertySetItemPtr item = prev->next;
-
-		if (!item->is_blob)
-			return -EINVAL;
-
-		item->value = length;
-		item->blob = data;
-	} else {
-		drmModePropertySetItemPtr item;
-
-		item = drmMalloc(sizeof *item);
-		if (!item)
-			return -1;
-
-		item->object_id = object_id;
-		item->property_id = property_id;
-		item->is_blob = true;
-		item->value = length;
-		item->blob = data;
-
-		item->next = prev->next;
-		prev->next = item;
-
-		set->count_props++;
-		set->count_blobs++;
-	}
-
-	if (new_obj)
-		set->count_objs++;
-
-	return 0;
-}
-
-void drmModePropertySetFree(drmModePropertySetPtr set)
-{
-	drmModePropertySetItemPtr item;
-
-	if (!set)
-		return;
-
-	item = set->list.next;
-
-	while (item) {
-		drmModePropertySetItemPtr next = item->next;
-
-		drmFree(item);
-
-		item = next;
-	}
-
-	drmFree(set);
-}
-
-int drmModePropertySetCommit(int fd, uint32_t flags, void *user_data,
-			     drmModePropertySetPtr set)
-{
-	drmModePropertySetItemPtr item;
-	uint32_t *objs_ptr = NULL;
-	uint32_t *count_props_ptr = NULL;
-	uint32_t *props_ptr = NULL;
-	uint64_t *prop_values_ptr = NULL;
-	uint64_t *blob_values_ptr = NULL;
-	struct drm_mode_atomic atomic = { 0 };
-	unsigned int obj_idx = 0;
-	unsigned int prop_idx = 0;
-	unsigned int blob_idx = 0;
-	int ret = -1;
-
-	if (!set)
-		return -1;
-
-	objs_ptr = drmMalloc(set->count_objs * sizeof objs_ptr[0]);
-	if (!objs_ptr) {
-		errno = ENOMEM;
-		goto out;
-	}
-
-	count_props_ptr = drmMalloc(set->count_objs * sizeof count_props_ptr[0]);
-	if (!count_props_ptr) {
-		errno = ENOMEM;
-		goto out;
-	}
-
-	props_ptr = drmMalloc(set->count_props * sizeof props_ptr[0]);
-	if (!props_ptr) {
-		errno = ENOMEM;
-		goto out;
-	}
-
-	prop_values_ptr = drmMalloc(set->count_props * sizeof prop_values_ptr[0]);
-	if (!prop_values_ptr) {
-		errno = ENOMEM;
-		goto out;
-	}
-
-	blob_values_ptr = drmMalloc(set->count_blobs * sizeof blob_values_ptr[0]);
-	if (!blob_values_ptr) {
-		errno = ENOMEM;
-		goto out;
-	}
-
-	item = set->list.next;
-
-	while (item) {
-		int count_props = 0;
-		drmModePropertySetItemPtr next = item;
-
-		objs_ptr[obj_idx] = item->object_id;
-
-		while (next && next->object_id == item->object_id) {
-			props_ptr[prop_idx] = next->property_id;
-			prop_values_ptr[prop_idx] = next->value;
-			prop_idx++;
-
-			if (next->is_blob)
-				blob_values_ptr[blob_idx++] = VOID2U64(next->blob);
-
-			count_props++;
-
-			next = next->next;
-		}
-
-		count_props_ptr[obj_idx++] = count_props;
-
-		item = next;
-	}
-
-	atomic.count_objs = set->count_objs;
-	atomic.flags = flags;
-	atomic.objs_ptr = VOID2U64(objs_ptr);
-	atomic.count_props_ptr = VOID2U64(count_props_ptr);
-	atomic.props_ptr = VOID2U64(props_ptr);
-	atomic.prop_values_ptr = VOID2U64(prop_values_ptr);
-// TODO:
-//	atomic.blob_values_ptr = VOID2U64(blob_values_ptr);
-	atomic.user_data = VOID2U64(user_data);
-
-	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
-
-out:
-	drmFree(objs_ptr);
-	drmFree(count_props_ptr);
-	drmFree(props_ptr);
-	drmFree(prop_values_ptr);
-
-	return ret;
-}
-
 typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr;
 
 struct _drmModeAtomicReqItem {
@@ -1471,7 +1223,7 @@
 	drmModeAtomicReqItemPtr items;
 };
 
-drmModeAtomicReqPtr drmModeAtomicAlloc(void)
+drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void)
 {
 	drmModeAtomicReqPtr req;
 
@@ -1486,7 +1238,7 @@
 	return req;
 }
 
-drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old)
+drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old)
 {
 	drmModeAtomicReqPtr new;
 
@@ -1515,7 +1267,8 @@
 	return new;
 }
 
-int drmModeAtomicMerge(drmModeAtomicReqPtr base, drmModeAtomicReqPtr augment)
+drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base,
+                                  drmModeAtomicReqPtr augment)
 {
 	if (!base)
 		return -EINVAL;
@@ -1544,27 +1297,30 @@
 	return 0;
 }
 
-int drmModeAtomicGetCursor(drmModeAtomicReqPtr req)
+drm_public int drmModeAtomicGetCursor(drmModeAtomicReqPtr req)
 {
 	if (!req)
 		return -EINVAL;
 	return req->cursor;
 }
 
-void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor)
+drm_public void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor)
 {
 	if (req)
 		req->cursor = cursor;
 }
 
-int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
-			     uint32_t object_id,
-			     uint32_t property_id,
-			     uint64_t value)
+drm_public int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
+                                        uint32_t object_id,
+                                        uint32_t property_id,
+                                        uint64_t value)
 {
 	if (!req)
 		return -EINVAL;
 
+	if (object_id == 0 || property_id == 0)
+		return -EINVAL;
+
 	if (req->cursor >= req->size_items) {
 		const uint32_t item_size_inc = getpagesize() / sizeof(*req->items);
 		drmModeAtomicReqItemPtr new;
@@ -1586,7 +1342,7 @@
 	return req->cursor;
 }
 
-void drmModeAtomicFree(drmModeAtomicReqPtr req)
+drm_public void drmModeAtomicFree(drmModeAtomicReqPtr req)
 {
 	if (!req)
 		return;
@@ -1609,8 +1365,8 @@
 		return second->property_id - first->property_id;
 }
 
-int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, uint32_t flags,
-			void *user_data)
+drm_public int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req,
+                                   uint32_t flags, void *user_data)
 {
 	drmModeAtomicReqPtr sorted;
 	struct drm_mode_atomic atomic;
@@ -1714,8 +1470,9 @@
 	return ret;
 }
 
-int
-drmModeCreatePropertyBlob(int fd, const void *data, size_t length, uint32_t *id)
+drm_public int
+drmModeCreatePropertyBlob(int fd, const void *data, size_t length,
+                                     uint32_t *id)
 {
 	struct drm_mode_create_blob create;
 	int ret;
@@ -1738,7 +1495,7 @@
 	return 0;
 }
 
-int
+drm_public int
 drmModeDestroyPropertyBlob(int fd, uint32_t id)
 {
 	struct drm_mode_destroy_blob destroy;
@@ -1747,3 +1504,93 @@
 	destroy.blob_id = id;
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy);
 }
+
+drm_public int
+drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags,
+                   uint32_t *lessee_id)
+{
+	struct drm_mode_create_lease create;
+	int ret;
+
+	memclear(create);
+	create.object_ids = (uintptr_t) objects;
+	create.object_count = num_objects;
+	create.flags = flags;
+
+	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_LEASE, &create);
+	if (ret == 0) {
+		*lessee_id = create.lessee_id;
+		return create.fd;
+	}
+	return -errno;
+}
+
+drm_public drmModeLesseeListPtr
+drmModeListLessees(int fd)
+{
+	struct drm_mode_list_lessees list;
+	uint32_t count;
+	drmModeLesseeListPtr ret;
+
+	memclear(list);
+
+	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list))
+		return NULL;
+
+	count = list.count_lessees;
+	ret = drmMalloc(sizeof (drmModeLesseeListRes) + count * sizeof (ret->lessees[0]));
+	if (!ret)
+		return NULL;
+
+	list.lessees_ptr = VOID2U64(&ret->lessees[0]);
+	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) {
+		drmFree(ret);
+		return NULL;
+	}
+
+	ret->count = count;
+	return ret;
+}
+
+drm_public drmModeObjectListPtr
+drmModeGetLease(int fd)
+{
+	struct drm_mode_get_lease get;
+	uint32_t count;
+	drmModeObjectListPtr ret;
+
+	memclear(get);
+
+	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get))
+		return NULL;
+
+	count = get.count_objects;
+	ret = drmMalloc(sizeof (drmModeObjectListRes) + count * sizeof (ret->objects[0]));
+	if (!ret)
+		return NULL;
+
+	get.objects_ptr = VOID2U64(&ret->objects[0]);
+	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) {
+		drmFree(ret);
+		return NULL;
+	}
+
+	ret->count = count;
+	return ret;
+}
+
+drm_public int
+drmModeRevokeLease(int fd, uint32_t lessee_id)
+{
+	struct drm_mode_revoke_lease revoke;
+	int ret;
+
+	memclear(revoke);
+
+	revoke.lessee_id = lessee_id;
+
+	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_REVOKE_LEASE, &revoke);
+	if (ret == 0)
+		return 0;
+	return -errno;
+}
diff --git a/xf86drmMode.h b/xf86drmMode.h
index 9d73be9..3cd27ae 100644
--- a/xf86drmMode.h
+++ b/xf86drmMode.h
@@ -369,15 +369,16 @@
 			uint32_t *buf_id);
 /* ...with a specific pixel format */
 extern int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
-			 uint32_t pixel_format, uint32_t bo_handles[4],
-			 uint32_t pitches[4], uint32_t offsets[4],
+			 uint32_t pixel_format, const uint32_t bo_handles[4],
+			 const uint32_t pitches[4], const uint32_t offsets[4],
 			 uint32_t *buf_id, uint32_t flags);
 
 /* ...with format modifiers */
 int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height,
-			       uint32_t pixel_format, uint32_t bo_handles[4],
-			       uint32_t pitches[4], uint32_t offsets[4],
-			       uint64_t modifier[4], uint32_t *buf_id, uint32_t flags);
+			       uint32_t pixel_format, const uint32_t bo_handles[4],
+			       const uint32_t pitches[4], const uint32_t offsets[4],
+			       const uint64_t modifier[4], uint32_t *buf_id,
+				   uint32_t flags);
 
 /**
  * Destroies the given framebuffer.
@@ -498,25 +499,6 @@
 				    uint64_t value);
 
 
-typedef struct _drmModePropertySet drmModePropertySet, *drmModePropertySetPtr;
-
-extern drmModePropertySetPtr drmModePropertySetAlloc(void);
-
-extern int drmModePropertySetAdd(drmModePropertySetPtr set,
-				 uint32_t object_id,
-				 uint32_t property_id,
-				 uint64_t value);
-extern int drmModePropertySetAddBlob(drmModePropertySetPtr set,
-				     uint32_t object_id,
-				     uint32_t property_id,
-				     uint64_t length,
-				     void *blob);
-
-extern int drmModePropertySetCommit(int fd, uint32_t flags,
-				    void *user_data, drmModePropertySetPtr set);
-
-extern void drmModePropertySetFree(drmModePropertySetPtr set);
-
 typedef struct _drmModeAtomicReq drmModeAtomicReq, *drmModeAtomicReqPtr;
 
 extern drmModeAtomicReqPtr drmModeAtomicAlloc(void);
@@ -539,6 +521,28 @@
 				     uint32_t *id);
 extern int drmModeDestroyPropertyBlob(int fd, uint32_t id);
 
+/*
+ * DRM mode lease APIs. These create and manage new drm_masters with
+ * access to a subset of the available DRM resources
+ */
+
+extern int drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags, uint32_t *lessee_id);
+
+typedef struct drmModeLesseeList {
+	uint32_t count;
+	uint32_t lessees[0];
+} drmModeLesseeListRes, *drmModeLesseeListPtr;
+
+extern drmModeLesseeListPtr drmModeListLessees(int fd);
+
+typedef struct drmModeObjectList {
+	uint32_t count;
+	uint32_t objects[0];
+} drmModeObjectListRes, *drmModeObjectListPtr;
+
+extern drmModeObjectListPtr drmModeGetLease(int fd);
+
+extern int drmModeRevokeLease(int fd, uint32_t lessee_id);
 
 #if defined(__cplusplus)
 }
diff --git a/xf86drmRandom.c b/xf86drmRandom.c
index 81f0301..51e9676 100644
--- a/xf86drmRandom.c
+++ b/xf86drmRandom.c
@@ -74,12 +74,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "libdrm_macros.h"
 #include "xf86drm.h"
 #include "xf86drmRandom.h"
 
 #define RANDOM_MAGIC 0xfeedbeef
 
-void *drmRandomCreate(unsigned long seed)
+drm_public void *drmRandomCreate(unsigned long seed)
 {
     RandomState  *state;
 
@@ -109,13 +110,13 @@
     return state;
 }
 
-int drmRandomDestroy(void *state)
+drm_public int drmRandomDestroy(void *state)
 {
     drmFree(state);
     return 0;
 }
 
-unsigned long drmRandom(void *state)
+drm_public unsigned long drmRandom(void *state)
 {
     RandomState   *s = (RandomState *)state;
     unsigned long hi;
@@ -129,7 +130,7 @@
     return s->seed;
 }
 
-double drmRandomDouble(void *state)
+drm_public double drmRandomDouble(void *state)
 {
     RandomState *s = (RandomState *)state;
     
diff --git a/xf86drmSL.c b/xf86drmSL.c
index a12fa1d..3826df9 100644
--- a/xf86drmSL.c
+++ b/xf86drmSL.c
@@ -41,6 +41,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "libdrm_macros.h"
 #include "xf86drm.h"
 
 #define SL_LIST_MAGIC  0xfacade00LU
@@ -97,7 +98,7 @@
     return level;
 }
 
-void *drmSLCreate(void)
+drm_public void *drmSLCreate(void)
 {
     SkipListPtr  list;
     int          i;
@@ -114,7 +115,7 @@
     return list;
 }
 
-int drmSLDestroy(void *l)
+drm_public int drmSLDestroy(void *l)
 {
     SkipListPtr   list  = (SkipListPtr)l;
     SLEntryPtr    entry;
@@ -151,7 +152,7 @@
     return entry->forward[0];
 }
 
-int drmSLInsert(void *l, unsigned long key, void *value)
+drm_public int drmSLInsert(void *l, unsigned long key, void *value)
 {
     SkipListPtr   list  = (SkipListPtr)l;
     SLEntryPtr    entry;
@@ -184,7 +185,7 @@
     return 0;			/* Added to table */
 }
 
-int drmSLDelete(void *l, unsigned long key)
+drm_public int drmSLDelete(void *l, unsigned long key)
 {
     SkipListPtr   list = (SkipListPtr)l;
     SLEntryPtr    update[SL_MAX_LEVEL + 1];
@@ -211,7 +212,7 @@
     return 0;
 }
 
-int drmSLLookup(void *l, unsigned long key, void **value)
+drm_public int drmSLLookup(void *l, unsigned long key, void **value)
 {
     SkipListPtr   list = (SkipListPtr)l;
     SLEntryPtr    update[SL_MAX_LEVEL + 1];
@@ -227,9 +228,9 @@
     return -1;
 }
 
-int drmSLLookupNeighbors(void *l, unsigned long key,
-			 unsigned long *prev_key, void **prev_value,
-			 unsigned long *next_key, void **next_value)
+drm_public int drmSLLookupNeighbors(void *l, unsigned long key,
+                                    unsigned long *prev_key, void **prev_value,
+                                    unsigned long *next_key, void **next_value)
 {
     SkipListPtr   list = (SkipListPtr)l;
     SLEntryPtr    update[SL_MAX_LEVEL + 1] = {0};
@@ -253,7 +254,7 @@
     return retcode;
 }
 
-int drmSLNext(void *l, unsigned long *key, void **value)
+drm_public int drmSLNext(void *l, unsigned long *key, void **value)
 {
     SkipListPtr   list = (SkipListPtr)l;
     SLEntryPtr    entry;
@@ -272,7 +273,7 @@
     return 0;
 }
 
-int drmSLFirst(void *l, unsigned long *key, void **value)
+drm_public int drmSLFirst(void *l, unsigned long *key, void **value)
 {
     SkipListPtr   list = (SkipListPtr)l;
     
@@ -283,7 +284,7 @@
 }
 
 /* Dump internal data structures for debugging. */
-void drmSLDump(void *l)
+drm_public void drmSLDump(void *l)
 {
     SkipListPtr   list = (SkipListPtr)l;
     SLEntryPtr    entry;