libdrm: Merge remote-tracking branch 'aosp/upstream-main' into HEAD am: e2e1ef32ee am: bdbf71cace am: 77fe790444

Original change: https://android-review.googlesource.com/c/platform/external/libdrm/+/1906795

Change-Id: Ia397ef50af460ce375a1c32a75b06d7a07a47cc4
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 26eaf83..876be95 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,47 +12,181 @@
 # main repository, it's recommended to remove the image from the source
 # repository's container registry, so that the image from the main
 # repository's registry will be used there as well.
-variables:
-  UPSTREAM_REPO: mesa/drm
-  DEBIAN_TAG: "2021-02-11"
-  DEBIAN_VERSION: buster-slim
-  DEBIAN_IMAGE: "$CI_REGISTRY_IMAGE/debian/$DEBIAN_VERSION:$DEBIAN_TAG"
+.templates_sha: &template_sha 567700e483aabed992d0a4fea84994a0472deff6 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
 
 include:
-  - project: 'wayland/ci-templates'
-    ref: 0a9bdd33a98f05af6761ab118b5074952242aab0
-    file: '/templates/debian.yml'
+  - project: 'freedesktop/ci-templates'
+    ref: *template_sha
+    file:
+    - '/templates/debian.yml'
+    - '/templates/freebsd.yml'
+    - '/templates/ci-fairy.yml'
+
+variables:
+  FDO_UPSTREAM_REPO: mesa/drm
+  FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH"
 
 stages:
-  - containers
-  - build
+  - "Base container"
+  - "Build"
 
-
-# When & how to run the CI
-.ci-run-policy:
-  except:
-    - schedules
-  retry:
-    max: 2
-    when:
-      - runner_system_failure
+.ci-rules:
+  rules:
+    - when: on_success
 
 # CONTAINERS
 
-debian:
-  stage: containers
-  extends:
-    - .ci-run-policy
-    - .debian@container-ifnot-exists
+.os-debian:
   variables:
-    GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
-    DEBIAN_EXEC: 'bash .gitlab-ci/debian-install.sh'
+    BUILD_OS: debian
+    FDO_DISTRIBUTION_VERSION: buster
+    FDO_DISTRIBUTION_PACKAGES: 'build-essential docbook-xsl libatomic-ops-dev libcairo2-dev libcunit1-dev libpciaccess-dev meson ninja-build pkg-config python3 python3-pip python3-wheel python3-setuptools python3-docutils valgrind'
+    FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.52.1'
+    # bump this tag every time you change something which requires rebuilding the
+    # base image
+    FDO_DISTRIBUTION_TAG: "2021-08-03.0"
 
+.debian-x86_64:
+  extends:
+    - .os-debian
+  variables:
+    BUILD_ARCH: "x86-64"
+
+.debian-aarch64:
+  extends:
+    - .os-debian
+  variables:
+    BUILD_ARCH: "aarch64"
+
+.debian-armv7:
+  extends:
+    - .os-debian
+  variables:
+    BUILD_ARCH: "armv7"
+
+.os-freebsd:
+  variables:
+    BUILD_OS: freebsd
+    FDO_DISTRIBUTION_VERSION: "13.0"
+    FDO_DISTRIBUTION_PACKAGES: 'meson ninja pkgconf libpciaccess libpthread-stubs py38-docutils cairo'
+    # bump this tag every time you change something which requires rebuilding the
+    # base image
+    FDO_DISTRIBUTION_TAG: "2021-11-10.1"
+
+.freebsd-x86_64:
+  extends:
+    - .os-freebsd
+  variables:
+    BUILD_ARCH: "x86_64"
+
+# Build our base container image, which contains the core distribution, the
+# toolchain, and all our build dependencies. This will be reused in the build
+# stage.
+x86_64-debian-container_prep:
+  extends:
+    - .ci-rules
+    - .debian-x86_64
+    - .fdo.container-build@debian
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+
+aarch64-debian-container_prep:
+  extends:
+    - .ci-rules
+    - .debian-aarch64
+    - .fdo.container-build@debian
+  tags:
+    - aarch64
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+
+armv7-debian-container_prep:
+  extends:
+    - .ci-rules
+    - .debian-armv7
+    - .fdo.container-build@debian
+  tags:
+    - aarch64
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+    FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION"
+
+x86_64-freebsd-container_prep:
+  extends:
+    - .ci-rules
+    - .freebsd-x86_64
+    - .fdo.qemu-build@freebsd@x86_64
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+
+# Core build environment.
+.build-env:
+  variables:
+    MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined"
+
+# OS/architecture-specific variants
+.build-env-debian-x86_64:
+  extends:
+    - .fdo.suffixed-image@debian
+    - .debian-x86_64
+    - .build-env
+  needs:
+    - job: x86_64-debian-container_prep
+      artifacts: false
+
+.build-env-debian-aarch64:
+  extends:
+    - .fdo.suffixed-image@debian
+    - .debian-aarch64
+    - .build-env
+  variables:
+    # At least with the versions we have, the LSan runtime makes fork unusably
+    # slow on AArch64, which is bad news since the test suite decides to fork
+    # for every single subtest. For now, in order to get AArch64 builds and
+    # tests into CI, just assume that we're not going to leak any more on
+    # AArch64 than we would on ARMv7 or x86-64.
+    ASAN_OPTIONS: "detect_leaks=0"
+  tags:
+    - aarch64
+  needs:
+    - job: aarch64-debian-container_prep
+      artifacts: false
+
+.build-env-debian-armv7:
+  extends:
+    - .fdo.suffixed-image@debian
+    - .debian-armv7
+    - .build-env
+  tags:
+    - aarch64
+  needs:
+    - job: armv7-debian-container_prep
+      artifacts: false
+
+.build-env-freebsd-x86_64:
+  variables:
+    # Compiling with ASan+UBSan appears to trigger an infinite loop in the
+    # compiler shipped with FreeBSD 13.0, so we only use UBSan here.
+    # Additionally, sanitizers can't be used with b_lundef on FreeBSD.
+    MESON_BUILD_TYPE: "-Dbuildtype=debug -Db_sanitize=undefined -Db_lundef=false"
+  extends:
+    - .fdo.suffixed-image@freebsd
+    - .freebsd-x86_64
+    - .build-env
+  needs:
+    - job: x86_64-freebsd-container_prep
+      artifacts: false
 
 # BUILD
 
-.meson-build:
-  stage: build
+.do-build:
+  extends:
+    - .ci-rules
+  stage: "Build"
   variables:
     GIT_DEPTH: 10
   script:
@@ -74,7 +208,6 @@
         -D valgrind=auto
         -D vc4=true
         -D vmwgfx=true
-        ${CROSS+--cross /cross_file-$CROSS.txt}
     - ninja -C build
     - ninja -C build test
     - DESTDIR=$PWD/install ninja -C build install
@@ -83,34 +216,47 @@
     paths:
       - build/meson-logs/*
 
-meson-x86_64:
+.do-build-qemu:
   extends:
-    - .ci-run-policy
-    - .meson-build
-  image: $DEBIAN_IMAGE
-  needs:
-    - debian
+    - .ci-rules
+  stage: "Build"
+  script:
+    # Start the VM and copy our workspace to the VM
+    - /app/vmctl start
+    - scp -r $PWD "vm:"
+    # The `set +e is needed to ensure that we always copy the meson logs back to
+    # the workspace to see details about the failed tests.
+    - |
+      set +e
+      /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson build -D amdgpu=true -D cairo-tests=true -D intel=true -D libkms=true -D man-pages=true -D nouveau=false -D radeon=true -D valgrind=auto && ninja -C build"
+      set -ex
+      scp -r vm:$CI_PROJECT_NAME/build/meson-logs .
+      /app/vmctl exec "ninja -C $CI_PROJECT_NAME/build install"
+      mkdir -p $PREFIX && scp -r vm:$PREFIX/ $PREFIX/
+    # Finally, shut down the VM.
+    - /app/vmctl stop
+  artifacts:
+    when: on_failure
+    paths:
+      - build/meson-logs/*
 
-meson-i386:
-  extends: meson-x86_64
-  variables:
-    CROSS: i386
+# Full build and test.
+x86_64-debian-build:
+  extends:
+    - .build-env-debian-x86_64
+    - .do-build
 
-meson-aarch64:
-  extends: meson-x86_64
-  variables:
-    CROSS: arm64
+aarch64-debian-build:
+  extends:
+    - .build-env-debian-aarch64
+    - .do-build
 
-meson-armhf:
-  extends: meson-x86_64
-  variables:
-    CROSS: armhf
+armv7-debian-build:
+  extends:
+    - .build-env-debian-armv7
+    - .do-build
 
-meson-ppc64el:
-  extends: meson-x86_64
-  variables:
-    CROSS: ppc64el
-
+# Daily build
 meson-arch-daily:
   rules:
     - if: '$SCHEDULE == "arch-daily"'
@@ -126,4 +272,9 @@
         meson
         valgrind
         python-docutils
-  extends: .meson-build
+  extends: .do-build
+
+x86_64-freebsd-build:
+  extends:
+    - .build-env-freebsd-x86_64
+    - .do-build-qemu
diff --git a/amdgpu/amdgpu-symbols.txt b/amdgpu/amdgpu-symbols.txt
index a2ed652..af2b643 100644
--- a/amdgpu/amdgpu-symbols.txt
+++ b/amdgpu/amdgpu-symbols.txt
@@ -53,6 +53,7 @@
 amdgpu_cs_wait_fences
 amdgpu_cs_wait_semaphore
 amdgpu_device_deinitialize
+amdgpu_device_get_fd
 amdgpu_device_initialize
 amdgpu_find_bo_by_cpu_mapping
 amdgpu_get_marketing_name
diff --git a/amdgpu/amdgpu.h b/amdgpu/amdgpu.h
index b118dd4..cde8585 100644
--- a/amdgpu/amdgpu.h
+++ b/amdgpu/amdgpu.h
@@ -546,6 +546,19 @@
 */
 int amdgpu_device_deinitialize(amdgpu_device_handle device_handle);
 
+/**
+ *
+ * /param device_handle - \c [in] Device handle.
+ *                           See #amdgpu_device_initialize()
+ *
+ * \return Returns the drm fd used for operations on this
+ *         device. This is still owned by the library and hence
+ *         should not be closed. Guaranteed to be valid until
+ *         #amdgpu_device_deinitialize gets called.
+ *
+*/
+int amdgpu_device_get_fd(amdgpu_device_handle device_handle);
+
 /*
  * Memory Management
  *
diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c
index 76b4e5e..73fd27f 100644
--- a/amdgpu/amdgpu_device.c
+++ b/amdgpu/amdgpu_device.c
@@ -285,6 +285,11 @@
 	return 0;
 }
 
+drm_public int amdgpu_device_get_fd(amdgpu_device_handle device_handle)
+{
+	return device_handle->fd;
+}
+
 drm_public const char *amdgpu_get_marketing_name(amdgpu_device_handle dev)
 {
 	return dev->marketing_name;
diff --git a/core-symbols.txt b/core-symbols.txt
index ed0d803..31bbcf8 100644
--- a/core-symbols.txt
+++ b/core-symbols.txt
@@ -58,6 +58,7 @@
 drmGetContextTag
 drmGetDevice
 drmGetDevice2
+drmGetDeviceFromDevId
 drmGetDeviceNameFromFd
 drmGetDeviceNameFromFd2
 drmGetDevices
@@ -110,6 +111,7 @@
 drmModeDestroyPropertyBlob
 drmModeDetachMode
 drmModeDirtyFB
+drmModeFormatModifierBlobIterNext
 drmModeFreeConnector
 drmModeFreeCrtc
 drmModeFreeEncoder
diff --git a/data/amdgpu.ids b/data/amdgpu.ids
index ac5213b..0040a38 100644
--- a/data/amdgpu.ids
+++ b/data/amdgpu.ids
@@ -4,106 +4,106 @@
 # device_id,	revision_id,	product_name        <-- single tab after comma
 
 1.0.0
-15DD,	C3,	AMD Radeon(TM) Vega 3 Graphics
-15DD,	CB,	AMD Radeon(TM) Vega 3 Graphics
-15DD,	CE,	AMD Radeon(TM) Vega 3 Graphics
-15DD,	D8,	AMD Radeon(TM) Vega 3 Graphics
-15DD,	CC,	AMD Radeon(TM) Vega 6 Graphics
-15DD,	D9,	AMD Radeon(TM) Vega 6 Graphics
-15DD,	C2,	AMD Radeon(TM) Vega 8 Graphics
-15DD,	C4,	AMD Radeon(TM) Vega 8 Graphics
-15DD,	C8,	AMD Radeon(TM) Vega 8 Graphics
-15DD,	CA,	AMD Radeon(TM) Vega 8 Graphics
-15DD,	D1,	AMD Radeon(TM) Vega 8 Graphics
-15DD,	D5,	AMD Radeon(TM) Vega 8 Graphics
-15DD,	D7,	AMD Radeon(TM) Vega 8 Graphics
-15DD,	C3,	AMD Radeon(TM) Vega 10 Graphics
-15DD,	D0,	AMD Radeon(TM) Vega 10 Graphics
-15DD,	C1,	AMD Radeon(TM) Vega 11 Graphics
-15DD,	C6,	AMD Radeon(TM) Vega 11 Graphics
-15DD,	C9,	AMD Radeon(TM) Vega 11 Graphics
-15DD,	D3,	AMD Radeon(TM) Vega 11 Graphics
-15DD,	D6,	AMD Radeon(TM) Vega 11 Graphics
+15DD,	C3,	AMD Radeon Vega 3 Graphics
+15DD,	CB,	AMD Radeon Vega 3 Graphics
+15DD,	CE,	AMD Radeon Vega 3 Graphics
+15DD,	D8,	AMD Radeon Vega 3 Graphics
+15DD,	CC,	AMD Radeon Vega 6 Graphics
+15DD,	D9,	AMD Radeon Vega 6 Graphics
+15DD,	C2,	AMD Radeon Vega 8 Graphics
+15DD,	C4,	AMD Radeon Vega 8 Graphics
+15DD,	C8,	AMD Radeon Vega 8 Graphics
+15DD,	CA,	AMD Radeon Vega 8 Graphics
+15DD,	D1,	AMD Radeon Vega 8 Graphics
+15DD,	D5,	AMD Radeon Vega 8 Graphics
+15DD,	D7,	AMD Radeon Vega 8 Graphics
+15DD,	C3,	AMD Radeon Vega 10 Graphics
+15DD,	D0,	AMD Radeon Vega 10 Graphics
+15DD,	C1,	AMD Radeon Vega 11 Graphics
+15DD,	C6,	AMD Radeon Vega 11 Graphics
+15DD,	C9,	AMD Radeon Vega 11 Graphics
+15DD,	D3,	AMD Radeon Vega 11 Graphics
+15DD,	D6,	AMD Radeon Vega 11 Graphics
 15DD,	81,	AMD Ryzen Embedded V1807B with Radeon Vega Gfx
 15DD,	82,	AMD Ryzen Embedded V1756B with Radeon Vega Gfx
 15DD,	83,	AMD Ryzen Embedded V1605B with Radeon Vega Gfx
 15DD,	85,	AMD Ryzen Embedded V1202B with Radeon Vega Gfx
-15D8,	93,	AMD Radeon(TM) Vega 1 Graphics
-15D8,	C4,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	C5,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	CC,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	CE,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	CF,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	D4,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	DC,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	DD,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	DE,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	DF,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	E3,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	E4,	AMD Radeon(TM) Vega 3 Graphics
-15D8,	A3,	AMD Radeon(TM) Vega 6 Graphics
-15D8,	B3,	AMD Radeon(TM) Vega 6 Graphics
-15D8,	C3,	AMD Radeon(TM) Vega 6 Graphics
-15D8,	D3,	AMD Radeon(TM) Vega 6 Graphics
-15D8,	A2,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	B2,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	C2,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	C9,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	CB,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	D2,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	D9,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	DB,	AMD Radeon(TM) Vega 8 Graphics
-15D8,	A1,	AMD Radeon(TM) Vega 10 Graphics
-15D8,	B1,	AMD Radeon(TM) Vega 10 Graphics
-15D8,	C1,	AMD Radeon(TM) Vega 10 Graphics
-15D8,	D1,	AMD Radeon(TM) Vega 10 Graphics
-15D8,	C8,	AMD Radeon(TM) Vega 11 Graphics
-15D8,	CA,	AMD Radeon(TM) Vega 11 Graphics
-15D8,	D8,	AMD Radeon(TM) Vega 11 Graphics
-15D8,	DA,	AMD Radeon(TM) Vega 11 Graphics
+15D8,	93,	AMD Radeon Vega 1 Graphics
+15D8,	C4,	AMD Radeon Vega 3 Graphics
+15D8,	C5,	AMD Radeon Vega 3 Graphics
+15D8,	CC,	AMD Radeon Vega 3 Graphics
+15D8,	CE,	AMD Radeon Vega 3 Graphics
+15D8,	CF,	AMD Radeon Vega 3 Graphics
+15D8,	D4,	AMD Radeon Vega 3 Graphics
+15D8,	DC,	AMD Radeon Vega 3 Graphics
+15D8,	DD,	AMD Radeon Vega 3 Graphics
+15D8,	DE,	AMD Radeon Vega 3 Graphics
+15D8,	DF,	AMD Radeon Vega 3 Graphics
+15D8,	E3,	AMD Radeon Vega 3 Graphics
+15D8,	E4,	AMD Radeon Vega 3 Graphics
+15D8,	A3,	AMD Radeon Vega 6 Graphics
+15D8,	B3,	AMD Radeon Vega 6 Graphics
+15D8,	C3,	AMD Radeon Vega 6 Graphics
+15D8,	D3,	AMD Radeon Vega 6 Graphics
+15D8,	A2,	AMD Radeon Vega 8 Graphics
+15D8,	B2,	AMD Radeon Vega 8 Graphics
+15D8,	C2,	AMD Radeon Vega 8 Graphics
+15D8,	C9,	AMD Radeon Vega 8 Graphics
+15D8,	CB,	AMD Radeon Vega 8 Graphics
+15D8,	D2,	AMD Radeon Vega 8 Graphics
+15D8,	D9,	AMD Radeon Vega 8 Graphics
+15D8,	DB,	AMD Radeon Vega 8 Graphics
+15D8,	A1,	AMD Radeon Vega 10 Graphics
+15D8,	B1,	AMD Radeon Vega 10 Graphics
+15D8,	C1,	AMD Radeon Vega 10 Graphics
+15D8,	D1,	AMD Radeon Vega 10 Graphics
+15D8,	C8,	AMD Radeon Vega 11 Graphics
+15D8,	CA,	AMD Radeon Vega 11 Graphics
+15D8,	D8,	AMD Radeon Vega 11 Graphics
+15D8,	DA,	AMD Radeon Vega 11 Graphics
 15D8,	91,	AMD Ryzen Embedded R1606G with Radeon Vega Gfx
 15D8,	92,	AMD Ryzen Embedded R1505G with Radeon Vega Gfx
 15D8,	CF,	AMD Ryzen Embedded R1305G with Radeon Vega Gfx
 15D8,	E4,	AMD Ryzen Embedded R1102G with Radeon Vega Gfx
 163F,	AE,	AMD Custom GPU 0405
-6600,	0,	AMD Radeon HD 8600/8700M
-6600,	81,	AMD Radeon (TM) R7 M370
-6601,	0,	AMD Radeon (TM) HD 8500M/8700M
+6600,	0,	AMD Radeon HD 8600 / 8700M
+6600,	81,	AMD Radeon R7 M370
+6601,	0,	AMD Radeon HD 8500M / 8700M
 6604,	0,	AMD Radeon R7 M265 Series
-6604,	81,	AMD Radeon (TM) R7 M350
+6604,	81,	AMD Radeon R7 M350
 6605,	0,	AMD Radeon R7 M260 Series
-6605,	81,	AMD Radeon (TM) R7 M340
+6605,	81,	AMD Radeon R7 M340
 6606,	0,	AMD Radeon HD 8790M
-6607,	0,	AMD Radeon (TM) HD8530M
+6607,	0,	AMD Radeon HD 8530M
 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
+6610,	81,	AMD Radeon R7 350
+6610,	83,	AMD Radeon 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
+6640,	80,	AMD Radeon R9 M380
 6646,	0,	AMD Radeon R9 M280X
-6646,	80,	AMD Radeon (TM) R9 M470X
+6646,	80,	AMD Radeon R9 M470X
 6647,	0,	AMD Radeon R9 M270X
-6647,	80,	AMD Radeon (TM) R9 M380
+6647,	80,	AMD Radeon 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
+665F,	81,	AMD Radeon R7 300 Series
 6660,	0,	AMD Radeon HD 8600M Series
-6660,	81,	AMD Radeon (TM) R5 M335
-6660,	83,	AMD Radeon (TM) R5 M330
+6660,	81,	AMD Radeon R5 M335
+6660,	83,	AMD Radeon R5 M330
 6663,	0,	AMD Radeon HD 8500M Series
-6663,	83,	AMD Radeon (TM) R5 M320
+6663,	83,	AMD Radeon R5 M320
 6664,	0,	AMD Radeon R5 M200 Series
 6665,	0,	AMD Radeon R5 M200 Series
-6665,	83,	AMD Radeon (TM) R5 M320
+6665,	83,	AMD Radeon R5 M320
 6667,	0,	AMD Radeon R5 M200 Series
 666F,	0,	AMD Radeon HD 8500M
-66A1,	06,	AMD Radeon (TM) Pro VII
+66A1,	06,	AMD Radeon Pro VII
 66AF,	C1,	AMD Radeon VII
 6780,	0,	ATI FirePro V (FireGL V) Graphics Adapter
 678A,	0,	ATI FirePro V (FireGL V) Graphics Adapter
@@ -114,148 +114,148 @@
 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
+67B0,	80,	AMD Radeon R9 390 Series
 67B1,	0,	AMD Radeon R9 200 Series
-67B1,	80,	AMD Radeon (TM) R9 390 Series
+67B1,	80,	AMD Radeon 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
-67C4,	80,	AMD Radeon (TM) E9560/E9565 Graphics
-67C7,	00,	AMD Radeon (TM) Pro WX 5100 Graphics
-67C7,	80,	AMD Radeon (TM) E9390 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
+67DF,	C1,	AMD Radeon RX 580 Series
+67DF,	C2,	AMD Radeon RX 570 Series
+67DF,	C3,	AMD Radeon RX 580 Series
+67DF,	C4,	AMD Radeon RX 480 Graphics
+67DF,	C5,	AMD Radeon RX 470 Graphics
+67DF,	C6,	AMD Radeon RX 570 Series
+67DF,	C7,	AMD Radeon RX 480 Graphics
+67DF,	CF,	AMD Radeon RX 470 Graphics
+67DF,	D7,	AMD Radeon RX 470 Graphics
+67DF,	E0,	AMD Radeon RX 470 Series
+67DF,	E1,	AMD Radeon RX 590 Series
+67DF,	E3,	AMD Radeon RX Series
+67DF,	E7,	AMD Radeon RX 580 Series
+67DF,	EF,	AMD Radeon RX 570 Series
+67DF,	F7,	AMD Radeon RX P30PH
+67C2,	01,	AMD Radeon Pro V7350x2
+67C2,	02,	AMD Radeon Pro V7300X
+67C4,	00,	AMD Radeon Pro WX 7100 Graphics
+67C4,	80,	AMD Radeon E9560 / E9565 Graphics
+67C7,	00,	AMD Radeon Pro WX 5100 Graphics
+67C7,	80,	AMD Radeon E9390 Graphics
+67C0,	00,	AMD Radeon Pro WX 7100 Graphics
+67D0,	01,	AMD Radeon Pro V7350x2
+67D0,	02,	AMD Radeon Pro V7300X
+67E0,	00,	AMD Radeon Pro WX Series
+67E3,	00,	AMD Radeon Pro WX 4100
+67E8,	00,	AMD Radeon Pro WX Series
+67E8,	01,	AMD Radeon Pro WX Series
+67E8,	80,	AMD Radeon E9260 Graphics
+67EB,	00,	AMD Radeon Pro V5300X
+67EF,	C0,	AMD Radeon RX Graphics
+67EF,	C1,	AMD Radeon RX 460 Graphics
+67EF,	C3,	AMD Radeon RX Series
+67EF,	C5,	AMD Radeon RX 460 Graphics
+67EF,	C7,	AMD Radeon RX Graphics
+67EF,	CF,	AMD Radeon RX 460 Graphics
+67EF,	E2,	AMD Radeon RX 560X
+67EF,	E0,	AMD Radeon RX 560 Series
+67EF,	E1,	AMD Radeon RX Series
+67EF,	E3,	AMD Radeon RX Series
+67EF,	E5,	AMD Radeon RX 560 Series
+67EF,	EF,	AMD Radeon RX Graphics
+67EF,	FF,	AMD Radeon RX 460 Graphics
+67FF,	C0,	AMD Radeon RX Graphics
+67FF,	C1,	AMD Radeon RX Graphics
+67FF,	CF,	AMD Radeon RX 560 Series
+67FF,	EF,	AMD Radeon RX 560 Series
+67FF,	FF,	AMD Radeon RX 550 Series
 6800,	0,	AMD Radeon HD 7970M
-6801,	0,	AMD Radeon(TM) HD8970M
+6801,	0,	AMD Radeon HD 8970M
 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
+6810,	0,	AMD Radeon HD 8800 Series
+6810,	81,	AMD Radeon R7 370 Series
+6811,	0,	AMD Radeon HD 8800 Series
+6811,	81,	AMD Radeon 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
+6820,	81,	AMD Radeon R9 M375
+6820,	83,	AMD Radeon R9 M375X
 6821,	0,	AMD Radeon HD 8800M Series
-6821,	87,	AMD Radeon (TM) R7 M380
-6821,	83,	AMD Radeon R9 (TM) M370X
+6821,	87,	AMD Radeon R7 M380
+6821,	83,	AMD Radeon R9 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
+682B,	87,	AMD Radeon 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
+6837,	0,	AMD Radeon HD 7700 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
-6860,	07,	Radeon (TM) Pro V320
-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
+6860,	00,	AMD Radeon Instinct MI25
+6860,	01,	AMD Radeon Instinct MI25
+6860,	02,	AMD Radeon Instinct MI25
+6860,	03,	AMD Radeon Pro V340
+6860,	04,	AMD Radeon Instinct MI25x2
+6860,	07,	AMD Radeon Pro V320
+6861,	00,	AMD Radeon Pro WX 9100
+6862,	00,	AMD Radeon Pro SSG
+6863,	00,	AMD Radeon Vega Frontier Edition
+6864,	03,	AMD Radeon Pro V340
+6864,	04,	AMD Radeon Instinct MI25x2
+6868,	00,	AMD Radeon Pro WX 8200
+686C,	00,	AMD Radeon Instinct MI25 MxGPU
+686C,	01,	AMD Radeon Instinct MI25 MxGPU
+686C,	02,	AMD Radeon Instinct MI25 MxGPU
+686C,	03,	AMD Radeon Pro V340 MxGPU
+686C,	04,	AMD Radeon Instinct MI25x2 MxGPU
+686C,	05,	AMD Radeon Pro V340L MxGPU
+686C,	06,	AMD Radeon Instinct MI25 MxGPU
+687F,	C0,	AMD Radeon RX Vega
+687F,	C1,	AMD Radeon RX Vega
+687F,	C3,	AMD Radeon RX Vega
 6900,	0,	AMD Radeon R7 M260
-6900,	81,	AMD Radeon (TM) R7 M360
-6900,	83,	AMD Radeon (TM) R7 M340
+6900,	81,	AMD Radeon R7 M360
+6900,	83,	AMD Radeon 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
+6907,	87,	AMD Radeon 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
+6938,	F1,	AMD Radeon 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
-6981,	00,	AMD Radeon (TM) Pro WX 3200 Series
-6981,	01,	AMD Radeon (TM) Pro WX 3200 Series
-6981,	10,	AMD Radeon (TM) Pro WX 3200 Series
-6985,	00,	AMD Radeon Pro WX3100
+6939,	F1,	AMD Radeon R9 380 Series
+6980,	00,	AMD Radeon Pro WX 3100
+6981,	00,	AMD Radeon Pro WX 3200 Series
+6981,	01,	AMD Radeon Pro WX 3200 Series
+6981,	10,	AMD Radeon Pro WX 3200 Series
+6985,	00,	AMD Radeon Pro WX 3100
 6987,	80,	AMD Embedded Radeon E9171
-6987,	C0,	Radeon 550X Series
+6987,	C0,	AMD Radeon 550X Series
 6987,	C1,	AMD Radeon RX 640
-6987,	C3,	Radeon 540X Series
-6995,	00,	AMD Radeon Pro WX2100
-6997,	00,	Radeon Pro WX2100
+6987,	C3,	AMD Radeon 540X Series
+6995,	00,	AMD Radeon Pro WX 2100
+6997,	00,	AMD Radeon Pro WX 2100
 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 RX550/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
+699F,	C0,	AMD Radeon 500 Series
+699F,	C1,	AMD Radeon 540 Series
+699F,	C3,	AMD Radeon 500 Series
+699F,	C7,	AMD Radeon RX 550 / 550 Series
+7300,	C1,	AMD FirePro S9300 x2
+7300,	C8,	AMD Radeon R9 Fury Series
+7300,	C9,	AMD Radeon Pro Duo
+7300,	CB,	AMD Radeon R9 Fury Series
+7300,	CA,	AMD Radeon R9 Fury Series
 7312,	00,	AMD Radeon Pro W5700
 731E,	C6,	AMD Radeon RX 5700XTB
 731E,	C7,	AMD Radeon RX 5700B
@@ -267,14 +267,14 @@
 731F,	C5,	AMD Radeon RX 5700 XT
 731F,	CA,	AMD Radeon RX 5600 XT
 731F,	CB,	AMD Radeon RX 5600 OEM
-7340,	C1,	Radeon RX 5500M
-7340,	C5,	Radeon RX 5500 XT
-7340,	C7,	Radeon RX 5500
+7340,	C1,	AMD Radeon RX 5500M
+7340,	C5,	AMD Radeon RX 5500 XT
+7340,	C7,	AMD Radeon RX 5500
 7340,	C9,	AMD Radeon RX 5500XTB
-7340,	CF,	Radeon RX 5300
+7340,	CF,	AMD Radeon RX 5300
 7341,	00,	AMD Radeon Pro W5500
 7347,	00,	AMD Radeon Pro W5500M
-73A3,	00,	AMD Radeon PRO W6800
+73A3,	00,	AMD Radeon Pro W6800
 73AF,	C0,	AMD Radeon RX 6900 XT
 73BF,	C0,	AMD Radeon RX 6900 XT
 73BF,	C1,	AMD Radeon RX 6800 XT
@@ -283,8 +283,8 @@
 73DF,	C3,	AMD Radeon RX 6800M
 73DF,	C5,	AMD Radeon RX 6700 XT
 73DF,	CF,	AMD Radeon RX 6700M
-73E1,	00,	AMD Radeon PRO W6600M
-73E3,	00,	AMD Radeon PRO W6600
+73E1,	00,	AMD Radeon Pro W6600M
+73E3,	00,	AMD Radeon Pro W6600
 73FF,	C1,	AMD Radeon RX 6600 XT
 73FF,	C3,	AMD Radeon RX 6600M
 9874,	C4,	AMD Radeon R7 Graphics
diff --git a/meson.build b/meson.build
index 7ccfe84..5824da8 100644
--- a/meson.build
+++ b/meson.build
@@ -21,7 +21,7 @@
 project(
   'libdrm',
   ['c'],
-  version : '2.4.107',
+  version : '2.4.109',
   license : 'MIT',
   meson_version : '>= 0.46',
   default_options : ['buildtype=debugoptimized', 'c_std=gnu99'],
diff --git a/radeon/radeon_bo.h b/radeon/radeon_bo.h
index 37478a0..6e20c6c 100644
--- a/radeon/radeon_bo.h
+++ b/radeon/radeon_bo.h
@@ -48,7 +48,6 @@
     uint32_t                    size;
 };
 
-struct radeon_bo_manager;
 
 void radeon_bo_debug(struct radeon_bo *bo, const char *op);
 
diff --git a/tests/amdgpu/amdgpu_stress.c b/tests/amdgpu/amdgpu_stress.c
new file mode 100644
index 0000000..5c5c88c
--- /dev/null
+++ b/tests/amdgpu/amdgpu_stress.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2021 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "drm.h"
+#include "xf86drmMode.h"
+#include "xf86drm.h"
+#include "amdgpu.h"
+#include "amdgpu_drm.h"
+#include "amdgpu_internal.h"
+
+#define MAX_CARDS_SUPPORTED	4
+#define NUM_BUFFER_OBJECTS	1024
+
+#define SDMA_PACKET(op, sub_op, e)      ((((e) & 0xFFFF) << 16) |  \
+					(((sub_op) & 0xFF) << 8) | \
+					(((op) & 0xFF) << 0))
+
+#define SDMA_OPCODE_COPY				  1
+#       define SDMA_COPY_SUB_OPCODE_LINEAR		0
+
+
+#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
+
+
+/** Help string for command line parameters */
+static const char usage[] =
+	"Usage: %s [-?h] [-b v|g|vg size] "
+	"[-c from to size count]\n"
+	"where:\n"
+	"	b - Allocate a BO in VRAM, GTT or VRAM|GTT of size bytes.\n"
+	"	    This flag can be used multiple times. The first bo will\n"
+	"	    have id `1`, then second id `2`, ...\n"
+	"       c - Copy size bytes from BO (bo_id1) to BO (bo_id2), count times\n"
+	"       h - Display this help\n"
+	"\n"
+	"Sizes can be postfixes with k, m or g for kilo, mega and gigabyte scaling\n";
+
+/** Specified options strings for getopt */
+static const char options[]   = "?hb:c:";
+
+/* Open AMD devices.
+ * Returns the fd of the first device it could open.
+ */
+static int amdgpu_open_device(void)
+{
+	drmDevicePtr devices[MAX_CARDS_SUPPORTED];
+	unsigned int i;
+	int drm_count;
+
+	drm_count = drmGetDevices2(0, devices, MAX_CARDS_SUPPORTED);
+	if (drm_count < 0) {
+		fprintf(stderr, "drmGetDevices2() returned an error %d\n",
+			drm_count);
+		return drm_count;
+	}
+
+	for (i = 0; i < drm_count; i++) {
+		drmVersionPtr version;
+		int fd;
+
+		/* If this is not PCI device, skip*/
+		if (devices[i]->bustype != DRM_BUS_PCI)
+			continue;
+
+		/* If this is not AMD GPU vender ID, skip*/
+		if (devices[i]->deviceinfo.pci->vendor_id != 0x1002)
+			continue;
+
+		if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER))
+			continue;
+
+		fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
+
+		/* This node is not available. */
+		if (fd < 0) continue;
+
+		version = drmGetVersion(fd);
+		if (!version) {
+			fprintf(stderr,
+				"Warning: Cannot get version for %s."
+				"Error is %s\n",
+				devices[i]->nodes[DRM_NODE_RENDER],
+				strerror(errno));
+			close(fd);
+			continue;
+		}
+
+		if (strcmp(version->name, "amdgpu")) {
+			/* This is not AMDGPU driver, skip.*/
+			drmFreeVersion(version);
+			close(fd);
+			continue;
+		}
+
+		drmFreeVersion(version);
+		drmFreeDevices(devices, drm_count);
+		return fd;
+	}
+
+	return -1;
+}
+
+amdgpu_device_handle device_handle;
+amdgpu_context_handle context_handle;
+
+amdgpu_bo_handle resources[NUM_BUFFER_OBJECTS];
+uint64_t virtual[NUM_BUFFER_OBJECTS];
+unsigned int num_buffers;
+uint32_t *pm4;
+
+int alloc_bo(uint32_t domain, uint64_t size)
+{
+	struct amdgpu_bo_alloc_request request = {};
+	amdgpu_bo_handle bo;
+	amdgpu_va_handle va;
+	uint64_t addr;
+	int r;
+
+	if (num_buffers >= NUM_BUFFER_OBJECTS)
+		return -ENOSPC;
+
+	request.alloc_size = size;
+	request.phys_alignment = 0;
+	request.preferred_heap = domain;
+	request.flags = 0;
+	r = amdgpu_bo_alloc(device_handle, &request, &bo);
+	if (r)
+		return r;
+
+	r = amdgpu_va_range_alloc(device_handle, amdgpu_gpu_va_range_general,
+				  size, 0, 0, &addr, &va, 0);
+	if (r)
+		return r;
+
+	r = amdgpu_bo_va_op_raw(device_handle, bo, 0, size, addr,
+				AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
+				AMDGPU_VM_PAGE_EXECUTABLE, AMDGPU_VA_OP_MAP);
+	if (r)
+		return r;
+
+	resources[num_buffers] = bo;
+	virtual[num_buffers] = addr;
+	fprintf(stdout, "Allocated BO number %u at 0x%lx, domain 0x%x, size %lu\n",
+		num_buffers++, addr, domain, size);
+	return 0;
+}
+
+int submit_ib(uint32_t from, uint32_t to, uint64_t size, uint32_t count)
+{
+	struct amdgpu_cs_request ibs_request;
+	struct amdgpu_cs_fence fence_status;
+	struct amdgpu_cs_ib_info ib_info;
+	uint64_t copied = size, delta;
+	struct timespec start, stop;
+
+	uint64_t src = virtual[from];
+	uint64_t dst = virtual[to];
+	uint32_t expired;
+	int i, r;
+
+	i = 0;
+	while (size) {
+		uint64_t bytes = size < 0x40000 ? size : 0x40000;
+
+		if (device_handle->info.family_id == AMDGPU_FAMILY_SI) {
+			pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI, 0, 0, 0,
+						  bytes);
+			pm4[i++] = 0xffffffff & dst;
+			pm4[i++] = 0xffffffff & src;
+			pm4[i++] = (0xffffffff00000000 & dst) >> 32;
+			pm4[i++] = (0xffffffff00000000 & src) >> 32;
+		} else {
+			pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY,
+					       SDMA_COPY_SUB_OPCODE_LINEAR,
+					       0);
+			if ( device_handle->info.family_id >= AMDGPU_FAMILY_AI)
+				pm4[i++] = bytes - 1;
+			else
+				pm4[i++] = bytes;
+			pm4[i++] = 0;
+			pm4[i++] = 0xffffffff & src;
+			pm4[i++] = (0xffffffff00000000 & src) >> 32;
+			pm4[i++] = 0xffffffff & dst;
+			pm4[i++] = (0xffffffff00000000 & dst) >> 32;
+		}
+
+		size -= bytes;
+		src += bytes;
+		dst += bytes;
+	}
+
+	memset(&ib_info, 0, sizeof(ib_info));
+	ib_info.ib_mc_address = virtual[0];
+	ib_info.size = i;
+
+	memset(&ibs_request, 0, sizeof(ibs_request));
+	ibs_request.ip_type = AMDGPU_HW_IP_DMA;
+	ibs_request.ring = 0;
+	ibs_request.number_of_ibs = 1;
+	ibs_request.ibs = &ib_info;
+	ibs_request.fence_info.handle = NULL;
+
+	r = clock_gettime(CLOCK_MONOTONIC, &start);
+	if (r)
+		return errno;
+
+	r = amdgpu_bo_list_create(device_handle, num_buffers, resources, NULL,
+				  &ibs_request.resources);
+	if (r)
+		return r;
+
+	for (i = 0; i < count; ++i) {
+		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;
+
+	memset(&fence_status, 0, sizeof(fence_status));
+	fence_status.ip_type = ibs_request.ip_type;
+	fence_status.ip_instance = 0;
+	fence_status.ring = ibs_request.ring;
+	fence_status.context = context_handle;
+	fence_status.fence = ibs_request.seq_no;
+	r = amdgpu_cs_query_fence_status(&fence_status,
+					 AMDGPU_TIMEOUT_INFINITE,
+					 0, &expired);
+	if (r)
+		return r;
+
+	r = clock_gettime(CLOCK_MONOTONIC, &stop);
+	if (r)
+		return errno;
+
+	delta = stop.tv_nsec + stop.tv_sec * 1000000000UL;
+	delta -= start.tv_nsec + start.tv_sec * 1000000000UL;
+
+	fprintf(stdout, "Submitted %u IBs to copy from %u(%lx) to %u(%lx) %lu bytes took %lu usec\n",
+		count, from, virtual[from], to, virtual[to], copied, delta / 1000);
+	return 0;
+}
+
+void next_arg(int argc, char **argv, const char *msg)
+{
+	optarg = argv[optind++];
+	if (optind > argc || optarg[0] == '-') {
+		fprintf(stderr, "%s\n", msg);
+		exit(EXIT_FAILURE);
+	}
+}
+
+uint64_t parse_size(void)
+{
+	uint64_t size;
+	char ext[2];
+
+	ext[0] = 0;
+	if (sscanf(optarg, "%li%1[kmgKMG]", &size, ext) < 1) {
+		fprintf(stderr, "Can't parse size arg: %s\n", optarg);
+		exit(EXIT_FAILURE);
+	}
+	switch (ext[0]) {
+	case 'k':
+	case 'K':
+		size *= 1024;
+		break;
+	case 'm':
+	case 'M':
+		size *= 1024 * 1024;
+		break;
+	case 'g':
+	case 'G':
+		size *= 1024 * 1024 * 1024;
+		break;
+	default:
+		break;
+	}
+	return size;
+}
+
+int main(int argc, char **argv)
+{
+	uint32_t major_version, minor_version;
+	uint32_t domain, from, to, count;
+       	uint64_t size;
+	int fd, r, c;
+
+	fd = amdgpu_open_device();
+       	if (fd < 0) {
+		perror("Cannot open AMDGPU device");
+		exit(EXIT_FAILURE);
+	}
+
+	r = amdgpu_device_initialize(fd, &major_version, &minor_version, &device_handle);
+	if (r) {
+		fprintf(stderr, "amdgpu_device_initialize returned %d\n", r);
+		exit(EXIT_FAILURE);
+	}
+
+	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
+	if (r) {
+		fprintf(stderr, "amdgpu_cs_ctx_create returned %d\n", r);
+		exit(EXIT_FAILURE);
+	}
+
+	if (argc == 1) {
+		fprintf(stderr, usage, argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	r = alloc_bo(AMDGPU_GEM_DOMAIN_GTT, 2ULL * 1024 * 1024);
+	if (r) {
+		fprintf(stderr, "Buffer allocation failed with %d\n", r);
+		exit(EXIT_FAILURE);
+	}
+
+	r = amdgpu_bo_cpu_map(resources[0], (void **)&pm4);
+	if (r) {
+		fprintf(stderr, "Buffer mapping failed with %d\n", r);
+		exit(EXIT_FAILURE);
+	}
+
+	opterr = 0;
+	while ((c = getopt(argc, argv, options)) != -1) {
+		switch (c) {
+		case 'b':
+			if (!strcmp(optarg, "v"))
+				domain = AMDGPU_GEM_DOMAIN_VRAM;
+			else if (!strcmp(optarg, "g"))
+				domain = AMDGPU_GEM_DOMAIN_GTT;
+			else if (!strcmp(optarg, "vg"))
+				domain = AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT;
+			else {
+				fprintf(stderr, "Invalid domain: %s\n", optarg);
+				exit(EXIT_FAILURE);
+			}
+			next_arg(argc, argv, "Missing buffer size");
+			size = parse_size();
+			if (size < getpagesize()) {
+				fprintf(stderr, "Buffer size to small %lu\n", size);
+				exit(EXIT_FAILURE);
+			}
+			r = alloc_bo(domain, size);
+			if (r) {
+				fprintf(stderr, "Buffer allocation failed with %d\n", r);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'c':
+			if (sscanf(optarg, "%u", &from) != 1) {
+				fprintf(stderr, "Can't parse from buffer: %s\n", optarg);
+				exit(EXIT_FAILURE);
+			}
+			next_arg(argc, argv, "Missing to buffer");
+			if (sscanf(optarg, "%u", &to) != 1) {
+				fprintf(stderr, "Can't parse to buffer: %s\n", optarg);
+				exit(EXIT_FAILURE);
+			}
+			next_arg(argc, argv, "Missing size");
+			size = parse_size();
+			next_arg(argc, argv, "Missing count");
+			count = parse_size();
+			r = submit_ib(from, to, size, count);
+			if (r) {
+				fprintf(stderr, "IB submission failed with %d\n", r);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case '?':
+		case 'h':
+			fprintf(stderr, usage, argv[0]);
+			exit(EXIT_SUCCESS);
+		default:
+			fprintf(stderr, usage, argv[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	return EXIT_SUCCESS;
+}
diff --git a/tests/amdgpu/meson.build b/tests/amdgpu/meson.build
index e6e3081..3a3b760 100644
--- a/tests/amdgpu/meson.build
+++ b/tests/amdgpu/meson.build
@@ -33,3 +33,14 @@
     install : with_install_tests,
   )
 endif
+
+amdgpu_stress = executable(
+  'amdgpu_stress',
+  files(
+    'amdgpu_stress.c'
+  ),
+  dependencies : [dep_threads, dep_atomic_ops],
+  include_directories : [inc_root, inc_drm, include_directories('../../amdgpu')],
+  link_with : [libdrm, libdrm_amdgpu],
+  install : with_install_tests,
+)
diff --git a/tests/modeprint/modeprint.c b/tests/modeprint/modeprint.c
index ad727e1..f424f19 100644
--- a/tests/modeprint/modeprint.c
+++ b/tests/modeprint/modeprint.c
@@ -113,7 +113,7 @@
 
 	} else {
 		for (j = 0; j < props->count_enums; j++) {
-			printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name);
+			printf("\t\t%" PRId64 " = %s\n", props->enums[j].value, props->enums[j].name);
 			if (props->enums[j].value == value)
 				name = props->enums[j].name;
 		}
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index eca08ef..5fd22f7 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -300,11 +300,9 @@
 
 static void dump_in_formats(struct device *dev, uint32_t blob_id)
 {
-	uint32_t i, j;
+	drmModeFormatModifierIterator iter = {0};
 	drmModePropertyBlobPtr blob;
-	struct drm_format_modifier_blob *header;
-	uint32_t *formats;
-	struct drm_format_modifier *modifiers;
+	uint32_t fmt = 0;
 
 	printf("\t\tin_formats blob decoded:\n");
 	blob = drmModeGetPropertyBlob(dev->fd, blob_id);
@@ -313,23 +311,19 @@
 		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));
+	while (drmModeFormatModifierBlobIterNext(blob, &iter)) {
+		if (!fmt || fmt != iter.fmt) {
+			printf("%s\t\t\t", !fmt ? "" : "\n");
+			fmt = iter.fmt;
+			dump_fourcc(fmt);
+			printf(": ");
 		}
-		printf("\n");
+
+		printf(" %s", modifier_to_string(iter.mod));
 	}
 
+	printf("\n");
+
 	drmModeFreePropertyBlob(blob);
 }
 
@@ -381,7 +375,7 @@
 	if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) {
 		printf("\t\tenums:");
 		for (i = 0; i < prop->count_enums; i++)
-			printf(" %s=%llu", prop->enums[i].name,
+			printf(" %s=%"PRIu64, prop->enums[i].name,
 			       prop->enums[i].value);
 		printf("\n");
 	} else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
diff --git a/tests/proptest/proptest.c b/tests/proptest/proptest.c
index 5abbf02..0ab0907 100644
--- a/tests/proptest/proptest.c
+++ b/tests/proptest/proptest.c
@@ -126,7 +126,7 @@
 	if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) {
 		printf("\t\tenums:");
 		for (i = 0; i < prop->count_enums; i++)
-			printf(" %s=%llu", prop->enums[i].name,
+			printf(" %s=%"PRIu64, prop->enums[i].name,
 			       prop->enums[i].value);
 		printf("\n");
 	} else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
diff --git a/xf86drm.c b/xf86drm.c
index 2abc744..5933e4b 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -1559,8 +1559,8 @@
     memclear(map);
     map.offset  = offset;
     map.size    = size;
-    map.type    = type;
-    map.flags   = flags;
+    map.type    = (enum drm_map_type)type;
+    map.flags   = (enum drm_map_flags)flags;
     if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
         return -errno;
     if (handle)
@@ -1604,7 +1604,7 @@
     memclear(request);
     request.count     = count;
     request.size      = size;
-    request.flags     = flags;
+    request.flags     = (int)flags;
     request.agp_start = agp_offset;
 
     if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
@@ -1888,7 +1888,7 @@
     dma.send_count      = request->send_count;
     dma.send_indices    = request->send_list;
     dma.send_sizes      = request->send_sizes;
-    dma.flags           = request->flags;
+    dma.flags           = (enum drm_dma_flags)request->flags;
     dma.request_count   = request->request_count;
     dma.request_size    = request->request_size;
     dma.request_indices = request->request_list;
@@ -2825,8 +2825,8 @@
         return -errno;
     *offset = map.offset;
     *size   = map.size;
-    *type   = map.type;
-    *flags  = map.flags;
+    *type   = (drmMapType)map.type;
+    *flags  = (drmMapFlags)map.flags;
     *handle = (unsigned long)map.handle;
     *mtrr   = map.mtrr;
     return 0;
@@ -3377,8 +3377,9 @@
 
     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);
+            if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
+                        ent->d_name) < 0)
+                return NULL;
 
             closedir(sysdir);
             return strdup(dev_name);
@@ -3789,7 +3790,9 @@
     get_pci_path(maj, min, pci_path);
 
     for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
-        snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]);
+        if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0)
+            return -errno;
+
         fp = fopen(path, "r");
         if (!fp)
             return -errno;
@@ -3819,7 +3822,9 @@
 
     get_pci_path(maj, min, pci_path);
 
-    snprintf(path, PATH_MAX, "%s/config", pci_path);
+    if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0)
+        return -errno;
+
     fd = open(path, O_RDONLY);
     if (fd < 0)
         return -errno;
@@ -4497,19 +4502,16 @@
 #define MAX_DRM_NODES 256
 
 /**
- * Get information about the opened drm device
+ * Get information about a device from its dev_t identifier
  *
- * \param fd file descriptor of the drm device
+ * \param find_rdev dev_t identifier of the device
  * \param flags feature/behaviour bitmask
  * \param device the address of a drmDevicePtr where the information
  *               will be allocated in stored
  *
  * \return zero on success, negative error code otherwise.
- *
- * \note Unlike drmGetDevice it does not retrieve the pci device revision field
- * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
  */
-drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
+drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device)
 {
 #ifdef __OpenBSD__
     /*
@@ -4518,22 +4520,18 @@
      * Avoid stat'ing all of /dev needlessly by implementing this custom path.
      */
     drmDevicePtr     d;
-    struct stat      sbuf;
     char             node[PATH_MAX + 1];
     const char      *dev_name;
     int              node_type, subsystem_type;
     int              maj, min, n, ret;
 
-    if (fd == -1 || device == NULL)
+    if (device == NULL)
         return -EINVAL;
 
-    if (fstat(fd, &sbuf))
-        return -errno;
+    maj = major(find_rdev);
+    min = minor(find_rdev);
 
-    maj = major(sbuf.st_rdev);
-    min = minor(sbuf.st_rdev);
-
-    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min))
         return -EINVAL;
 
     node_type = drmGetMinorType(maj, min);
@@ -4566,26 +4564,20 @@
     drmDevicePtr d;
     DIR *sysdir;
     struct dirent *dent;
-    struct stat sbuf;
     int subsystem_type;
     int maj, min;
     int ret, i, node_count;
-    dev_t find_rdev;
 
     if (drm_device_validate_flags(flags))
         return -EINVAL;
 
-    if (fd == -1 || device == NULL)
+    if (device == NULL)
         return -EINVAL;
 
-    if (fstat(fd, &sbuf))
-        return -errno;
+    maj = major(find_rdev);
+    min = minor(find_rdev);
 
-    find_rdev = sbuf.st_rdev;
-    maj = major(sbuf.st_rdev);
-    min = minor(sbuf.st_rdev);
-
-    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
+    if (!drmNodeIsDRM(maj, min))
         return -EINVAL;
 
     subsystem_type = drmParseSubsystemType(maj, min);
@@ -4638,6 +4630,35 @@
  * Get information about the opened drm device
  *
  * \param fd file descriptor of the drm device
+ * \param flags feature/behaviour bitmask
+ * \param device the address of a drmDevicePtr where the information
+ *               will be allocated in stored
+ *
+ * \return zero on success, negative error code otherwise.
+ *
+ * \note Unlike drmGetDevice it does not retrieve the pci device revision field
+ * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
+ */
+drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
+{
+    struct stat sbuf;
+
+    if (fd == -1)
+        return -EINVAL;
+
+    if (fstat(fd, &sbuf))
+        return -errno;
+
+    if (!S_ISCHR(sbuf.st_mode))
+        return -EINVAL;
+
+    return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device);
+}
+
+/**
+ * Get information about the opened drm device
+ *
+ * \param fd file descriptor of the drm device
  * \param device the address of a drmDevicePtr where the information
  *               will be allocated in stored
  *
diff --git a/xf86drm.h b/xf86drm.h
index 31c1e97..1631396 100644
--- a/xf86drm.h
+++ b/xf86drm.h
@@ -917,6 +917,8 @@
 extern int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device);
 extern int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices);
 
+extern int drmGetDeviceFromDevId(dev_t dev_id, uint32_t flags, drmDevicePtr *device);
+
 extern int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b);
 
 extern int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle);
diff --git a/xf86drmMode.c b/xf86drmMode.c
index 0106954..84d3c77 100644
--- a/xf86drmMode.c
+++ b/xf86drmMode.c
@@ -33,6 +33,7 @@
  *
  */
 
+#include <assert.h>
 #include <limits.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -50,6 +51,7 @@
 #include "xf86drmMode.h"
 #include "xf86drm.h"
 #include <drm.h>
+#include <drm_fourcc.h>
 #include <string.h>
 #include <dirent.h>
 #include <unistd.h>
@@ -727,6 +729,112 @@
 	return r;
 }
 
+static inline const uint32_t *
+get_formats_ptr(const struct drm_format_modifier_blob *blob)
+{
+	return (const uint32_t *)(((uint8_t *)blob) + blob->formats_offset);
+}
+
+static inline const struct drm_format_modifier *
+get_modifiers_ptr(const struct drm_format_modifier_blob *blob)
+{
+	return (const struct drm_format_modifier *)(((uint8_t *)blob) +
+						    blob->modifiers_offset);
+}
+
+static bool _drmModeFormatModifierGetNext(const drmModePropertyBlobRes *blob,
+					  drmModeFormatModifierIterator *iter)
+{
+	const struct drm_format_modifier *blob_modifiers, *mod;
+	const struct drm_format_modifier_blob *fmt_mod_blob;
+	const uint32_t *blob_formats;
+
+	assert(blob && iter);
+
+	fmt_mod_blob = blob->data;
+	blob_modifiers = get_modifiers_ptr(fmt_mod_blob);
+	blob_formats = get_formats_ptr(fmt_mod_blob);
+
+	/* fmt_idx and mod_idx designate the number of processed formats
+	 * and modifiers.
+	 */
+	if (iter->fmt_idx >= fmt_mod_blob->count_formats ||
+	    iter->mod_idx >= fmt_mod_blob->count_modifiers)
+		return false;
+
+	iter->fmt = blob_formats[iter->fmt_idx];
+	iter->mod = DRM_FORMAT_MOD_INVALID;
+
+	/* From the latest valid found, get the next valid modifier */
+	while (iter->mod_idx < fmt_mod_blob->count_modifiers) {
+		mod = &blob_modifiers[iter->mod_idx++];
+
+		/* Check if the format that fmt_idx designates, belongs to
+		 * this modifier 64-bit window selected via mod->offset.
+		 */
+		if (iter->fmt_idx < mod->offset ||
+		    iter->fmt_idx >= mod->offset + 64)
+			continue;
+		if (!(mod->formats & (1 << (iter->fmt_idx - mod->offset))))
+			continue;
+
+		iter->mod = mod->modifier;
+		break;
+	}
+
+	if (iter->mod_idx == fmt_mod_blob->count_modifiers) {
+		iter->mod_idx = 0;
+		iter->fmt_idx++;
+	}
+
+	/* Since mod_idx reset, in order for the caller to iterate over
+	 * the last modifier of the last format, always return true here
+	 * and early return from the next call.
+	 */
+	return true;
+}
+
+/**
+ * Iterate over formats first and then over modifiers. On each call, iter->fmt
+ * is retained until all associated modifiers are returned. Then, either update
+ * iter->fmt with the next format, or exit if there aren't any left.
+ *
+ * NOTE: clients should not make any assumption on mod_idx and fmt_idx values
+ *
+ * @blob: valid kernel blob holding formats and modifiers
+ * @iter: input and output iterator data. Iter data must be initialised to zero
+ * @return: false, on error or there aren't any further formats or modifiers left.
+ *          true, on success and there are more formats or modifiers.
+ */
+drm_public bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob,
+						  drmModeFormatModifierIterator *iter)
+{
+	drmModeFormatModifierIterator tmp;
+	bool has_fmt;
+
+	if (!blob || !iter)
+		return false;
+
+	tmp.fmt_idx = iter->fmt_idx;
+	tmp.mod_idx = iter->mod_idx;
+
+	/* With the current state of things, DRM/KMS drivers are allowed to
+	 * construct blobs having formats and no modifiers. Userspace can't
+	 * legitimately abort in such cases.
+	 *
+	 * While waiting for the kernel to perhaps disallow formats with no
+	 * modifiers in IN_FORMATS blobs, skip the format altogether.
+	 */
+	do {
+		has_fmt = _drmModeFormatModifierGetNext(blob, &tmp);
+		if (has_fmt && tmp.mod != DRM_FORMAT_MOD_INVALID)
+			*iter = tmp;
+
+	} while (has_fmt && tmp.mod == DRM_FORMAT_MOD_INVALID);
+
+	return has_fmt;
+}
+
 drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
 {
 	if (!ptr)
diff --git a/xf86drmMode.h b/xf86drmMode.h
index de0e2fd..19bf91d 100644
--- a/xf86drmMode.h
+++ b/xf86drmMode.h
@@ -42,6 +42,7 @@
 
 #include <drm.h>
 #include <drm_mode.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -231,6 +232,12 @@
 	uint64_t *prop_values;
 } drmModeObjectProperties, *drmModeObjectPropertiesPtr;
 
+typedef struct _drmModeFormatModifierIterator {
+	uint32_t fmt_idx, mod_idx;
+	uint32_t fmt;
+	uint64_t mod;
+} drmModeFormatModifierIterator;
+
 typedef struct _drmModePlane {
 	uint32_t count_formats;
 	uint32_t *formats;
@@ -388,6 +395,8 @@
 extern void drmModeFreeProperty(drmModePropertyPtr ptr);
 
 extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id);
+extern bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob,
+					      drmModeFormatModifierIterator *iter);
 extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr);
 extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id,
 				    uint64_t value);