diff options
Diffstat (limited to 'lib')
95 files changed, 6837 insertions, 817 deletions
diff --git a/lib/libdrm/.editorconfig b/lib/libdrm/.editorconfig new file mode 100644 index 000000000..29b4f393b --- /dev/null +++ b/lib/libdrm/.editorconfig @@ -0,0 +1,23 @@ +# To use this config with your editor, follow the instructions at: +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +insert_final_newline = true + +[*.{c,h}] +indent_style = space +indent_size = 4 + +[{Makefile.*,*.mk}] +indent_style = tab + +[*.m4] +indent_style = space +indent_size = 2 + +[{meson.build,meson_options.txt}] +indent_style = space +indent_size = 2 diff --git a/lib/libdrm/Android.common.mk b/lib/libdrm/Android.common.mk new file mode 100644 index 000000000..37c2b23a1 --- /dev/null +++ b/lib/libdrm/Android.common.mk @@ -0,0 +1,22 @@ +# XXX: Consider moving these to config.h analogous to autoconf. +LOCAL_CFLAGS += \ + -DMAJOR_IN_SYSMACROS=1 \ + -DHAVE_ALLOCA_H=0 \ + -DHAVE_SYS_SELECT_H=0 \ + -DHAVE_SYS_SYSCTL_H=0 \ + -DHAVE_VISIBILITY=1 \ + -fvisibility=hidden \ + -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 + +LOCAL_CFLAGS += \ + -Wno-error \ + -Wno-unused-parameter \ + -Wno-missing-field-initializers \ + -Wno-pointer-arith \ + -Wno-enum-conversion + +# Quiet down the build system and remove any .h files from the sources +LOCAL_SRC_FILES := $(patsubst %.h, , $(LOCAL_SRC_FILES)) +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH) + +LOCAL_PROPRIETARY_MODULE := true diff --git a/lib/libdrm/CONTRIBUTING.rst b/lib/libdrm/CONTRIBUTING.rst new file mode 100644 index 000000000..96f1e4fb0 --- /dev/null +++ b/lib/libdrm/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/lib/libdrm/CleanSpec.mk b/lib/libdrm/CleanSpec.mk new file mode 100644 index 000000000..28a11db4e --- /dev/null +++ b/lib/libdrm/CleanSpec.mk @@ -0,0 +1,4 @@ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/include/libdrm) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/include/freedreno) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdrm_*intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libdrm_*intermediates) diff --git a/lib/libdrm/README.rst b/lib/libdrm/README.rst new file mode 100644 index 000000000..da995d0b3 --- /dev/null +++ b/lib/libdrm/README.rst @@ -0,0 +1,33 @@ +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 +--------- + +To set up meson: + + 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. diff --git a/lib/libdrm/RELEASING b/lib/libdrm/RELEASING new file mode 100644 index 000000000..903c1761d --- /dev/null +++ b/lib/libdrm/RELEASING @@ -0,0 +1,40 @@ +The release criteria for libdrm is essentially "if you need a release, +make one". There is no designated release engineer or maintainer. +Anybody is free to make a release if there's a certain feature or bug +fix they need in a released version of libdrm. + +When new ioctl definitions are merged into drm-next, we will add +support to libdrm, at which point we typically create a new release. +However, this is up to whoever is driving the feature in question. + +Follow these steps to release a new version of libdrm: + + 1) Bump the version number in 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 `ninja -C builddir/ dist` to generate the tarballs. + Make sure that the version number of the tarball name in + builddir/meson-dist/ matches the number you bumped to. Move that + tarball to the libdrm repo root for the release script to pick up. + + 3) Push the updated master branch with the bumped version number: + + git push origin master + + assuming the remote for the upstream libdrm repo is called origin. + + 4) Use the release.sh script from the xorg/util/modular repo to + upload the tarballs to the freedesktop.org download area and + create an announce email template. The script takes one argument: + the path to the libdrm checkout. So, if a checkout of modular is + at the same level than the libdrm repo: + + ./modular/release.sh libdrm + + This copies the two tarballs to freedesktop.org and creates + libdrm-2.4.16.announce which has a detailed summary of the + changes, links to the tarballs, MD5 and SHA1 sums and pre-filled + out email headers. Fill out the blank between the email headers + and the list of changes with a brief message of what changed or + what prompted this release. Send out the email and you're done! diff --git a/lib/libdrm/amdgpu/.editorconfig b/lib/libdrm/amdgpu/.editorconfig new file mode 100644 index 000000000..426273fd5 --- /dev/null +++ b/lib/libdrm/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/lib/libdrm/amdgpu/Android.mk b/lib/libdrm/amdgpu/Android.mk new file mode 100644 index 000000000..1f028d0b9 --- /dev/null +++ b/lib/libdrm/amdgpu/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_AMDGPU_FILES, LIBDRM_AMDGPU_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_amdgpu + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_AMDGPU_FILES) + +LOCAL_CFLAGS := \ + -DAMDGPU_ASIC_ID_TABLE=\"/vendor/etc/hwdata/amdgpu.ids\" + +LOCAL_REQUIRED_MODULES := amdgpu.ids + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/lib/libdrm/amdgpu/amdgpu-symbols.txt b/lib/libdrm/amdgpu/amdgpu-symbols.txt new file mode 100644 index 000000000..e3bafaabd --- /dev/null +++ b/lib/libdrm/amdgpu/amdgpu-symbols.txt @@ -0,0 +1,74 @@ +amdgpu_bo_alloc +amdgpu_bo_cpu_map +amdgpu_bo_cpu_unmap +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_ctx_override_priority +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_cs_query_reset_state2 +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_export_sync_file2 +amdgpu_cs_syncobj_import_sync_file +amdgpu_cs_syncobj_import_sync_file2 +amdgpu_cs_syncobj_query +amdgpu_cs_syncobj_query2 +amdgpu_cs_syncobj_reset +amdgpu_cs_syncobj_signal +amdgpu_cs_syncobj_timeline_signal +amdgpu_cs_syncobj_timeline_wait +amdgpu_cs_syncobj_transfer +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 +amdgpu_query_firmware_version +amdgpu_query_gds_info +amdgpu_query_gpu_info +amdgpu_query_heap_info +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 diff --git a/lib/libdrm/amdgpu/amdgpu.h b/lib/libdrm/amdgpu/amdgpu.h index bcac4cb77..188179c9c 100644 --- a/lib/libdrm/amdgpu/amdgpu.h +++ b/lib/libdrm/amdgpu/amdgpu.h @@ -1606,6 +1606,24 @@ int amdgpu_cs_syncobj_timeline_wait(amdgpu_device_handle dev, int amdgpu_cs_syncobj_query(amdgpu_device_handle dev, uint32_t *handles, uint64_t *points, unsigned num_handles); +/** + * Query sync objects last signaled or submitted point. + * + * \param dev - \c [in] self-explanatory + * \param handles - \c [in] array of sync object handles + * \param points - \c [out] array of sync points returned, which presents + * syncobj payload. + * \param num_handles - \c [in] self-explanatory + * \param flags - \c [in] a bitmask of DRM_SYNCOBJ_QUERY_FLAGS_* + * + * \return 0 on success\n + * -ETIME - Timeout + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_query2(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles, uint32_t flags); /** * Export kernel sync object to shareable fd. diff --git a/lib/libdrm/amdgpu/amdgpu_cs.c b/lib/libdrm/amdgpu/amdgpu_cs.c index 56502950b..fad484bf7 100644 --- a/lib/libdrm/amdgpu/amdgpu_cs.c +++ b/lib/libdrm/amdgpu/amdgpu_cs.c @@ -28,7 +28,7 @@ #include <pthread.h> #include <sched.h> #include <sys/ioctl.h> -#ifdef HAVE_ALLOCA_H +#if HAVE_ALLOCA_H # include <alloca.h> #endif @@ -220,15 +220,15 @@ drm_public int amdgpu_cs_query_reset_state2(amdgpu_context_handle context, static int amdgpu_cs_submit_one(amdgpu_context_handle context, struct amdgpu_cs_request *ibs_request) { - union drm_amdgpu_cs cs; - uint64_t *chunk_array; struct drm_amdgpu_cs_chunk *chunks; struct drm_amdgpu_cs_chunk_data *chunk_data; struct drm_amdgpu_cs_chunk_dep *dependencies = NULL; struct drm_amdgpu_cs_chunk_dep *sem_dependencies = NULL; + amdgpu_device_handle dev = context->dev; struct list_head *sem_list; amdgpu_semaphore_handle sem, tmp; - uint32_t i, size, sem_count = 0; + uint32_t i, size, num_chunks, bo_list_handle = 0, sem_count = 0; + uint64_t seq_no; bool user_fence; int r = 0; @@ -244,23 +244,18 @@ static int amdgpu_cs_submit_one(amdgpu_context_handle context, size = ibs_request->number_of_ibs + (user_fence ? 2 : 1) + 1; - chunk_array = alloca(sizeof(uint64_t) * size); chunks = alloca(sizeof(struct drm_amdgpu_cs_chunk) * size); size = ibs_request->number_of_ibs + (user_fence ? 1 : 0); chunk_data = alloca(sizeof(struct drm_amdgpu_cs_chunk_data) * size); - memset(&cs, 0, sizeof(cs)); - cs.in.chunks = (uint64_t)(uintptr_t)chunk_array; - cs.in.ctx_id = context->id; if (ibs_request->resources) - cs.in.bo_list_handle = ibs_request->resources->handle; - cs.in.num_chunks = ibs_request->number_of_ibs; + bo_list_handle = ibs_request->resources->handle; + num_chunks = ibs_request->number_of_ibs; /* IB chunks */ for (i = 0; i < ibs_request->number_of_ibs; i++) { struct amdgpu_cs_ib_info *ib; - chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i]; chunks[i].chunk_id = AMDGPU_CHUNK_ID_IB; chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_ib) / 4; chunks[i].chunk_data = (uint64_t)(uintptr_t)&chunk_data[i]; @@ -279,10 +274,9 @@ static int amdgpu_cs_submit_one(amdgpu_context_handle context, pthread_mutex_lock(&context->sequence_mutex); if (user_fence) { - i = cs.in.num_chunks++; + i = num_chunks++; /* fence chunk */ - chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i]; chunks[i].chunk_id = AMDGPU_CHUNK_ID_FENCE; chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_fence) / 4; chunks[i].chunk_data = (uint64_t)(uintptr_t)&chunk_data[i]; @@ -295,7 +289,7 @@ static int amdgpu_cs_submit_one(amdgpu_context_handle context, } if (ibs_request->number_of_dependencies) { - dependencies = malloc(sizeof(struct drm_amdgpu_cs_chunk_dep) * + dependencies = alloca(sizeof(struct drm_amdgpu_cs_chunk_dep) * ibs_request->number_of_dependencies); if (!dependencies) { r = -ENOMEM; @@ -312,10 +306,9 @@ static int amdgpu_cs_submit_one(amdgpu_context_handle context, dep->handle = info->fence; } - i = cs.in.num_chunks++; + i = num_chunks++; /* dependencies chunk */ - chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i]; chunks[i].chunk_id = AMDGPU_CHUNK_ID_DEPENDENCIES; chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_dep) / 4 * ibs_request->number_of_dependencies; @@ -326,7 +319,7 @@ static int amdgpu_cs_submit_one(amdgpu_context_handle context, LIST_FOR_EACH_ENTRY(sem, sem_list, list) sem_count++; if (sem_count) { - sem_dependencies = malloc(sizeof(struct drm_amdgpu_cs_chunk_dep) * sem_count); + sem_dependencies = alloca(sizeof(struct drm_amdgpu_cs_chunk_dep) * sem_count); if (!sem_dependencies) { r = -ENOMEM; goto error_unlock; @@ -345,26 +338,23 @@ static int amdgpu_cs_submit_one(amdgpu_context_handle context, amdgpu_cs_reset_sem(sem); amdgpu_cs_unreference_sem(sem); } - i = cs.in.num_chunks++; + i = num_chunks++; /* dependencies chunk */ - chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i]; chunks[i].chunk_id = AMDGPU_CHUNK_ID_DEPENDENCIES; chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_dep) / 4 * sem_count; chunks[i].chunk_data = (uint64_t)(uintptr_t)sem_dependencies; } - r = drmCommandWriteRead(context->dev->fd, DRM_AMDGPU_CS, - &cs, sizeof(cs)); + r = amdgpu_cs_submit_raw2(dev, context, bo_list_handle, num_chunks, + chunks, &seq_no); if (r) goto error_unlock; - ibs_request->seq_no = cs.out.handle; + ibs_request->seq_no = seq_no; context->last_seq[ibs_request->ip_type][ibs_request->ip_instance][ibs_request->ring] = ibs_request->seq_no; error_unlock: pthread_mutex_unlock(&context->sequence_mutex); - free(dependencies); - free(sem_dependencies); return r; } @@ -740,6 +730,16 @@ drm_public int amdgpu_cs_syncobj_query(amdgpu_device_handle dev, return drmSyncobjQuery(dev->fd, handles, points, num_handles); } +drm_public int amdgpu_cs_syncobj_query2(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles, uint32_t flags) +{ + if (!dev) + return -EINVAL; + + return drmSyncobjQuery2(dev->fd, handles, points, num_handles, flags); +} + drm_public int amdgpu_cs_export_syncobj(amdgpu_device_handle dev, uint32_t handle, int *shared_fd) diff --git a/lib/libdrm/amdgpu/amdgpu_internal.h b/lib/libdrm/amdgpu/amdgpu_internal.h index a340abbdf..37a7c9d56 100644 --- a/lib/libdrm/amdgpu/amdgpu_internal.h +++ b/lib/libdrm/amdgpu/amdgpu_internal.h @@ -102,7 +102,7 @@ struct amdgpu_bo { pthread_mutex_t cpu_access_mutex; void *cpu_ptr; - int cpu_map_count; + int64_t cpu_map_count; }; struct amdgpu_bo_list { diff --git a/lib/libdrm/amdgpu/meson.build b/lib/libdrm/amdgpu/meson.build index 8168993a7..a1781f595 100644 --- a/lib/libdrm/amdgpu/meson.build +++ b/lib/libdrm/amdgpu/meson.build @@ -58,8 +58,11 @@ ext_libdrm_amdgpu = declare_dependency( ) test( - 'amdgpu-symbol-check', - find_program('amdgpu-symbol-check'), - env : env_test, - args : libdrm_amdgpu, + 'amdgpu-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_amdgpu, + '--symbols-file', files('amdgpu-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/android/gralloc_handle.h b/lib/libdrm/android/gralloc_handle.h new file mode 100644 index 000000000..d3d975eeb --- /dev/null +++ b/lib/libdrm/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/lib/libdrm/core-symbols.txt b/lib/libdrm/core-symbols.txt new file mode 100644 index 000000000..1ff4ecaaf --- /dev/null +++ b/lib/libdrm/core-symbols.txt @@ -0,0 +1,197 @@ +drmAddBufs +drmAddContextPrivateMapping +drmAddContextTag +drmAddMap +drmAgpAcquire +drmAgpAlloc +drmAgpBase +drmAgpBind +drmAgpDeviceId +drmAgpEnable +drmAgpFree +drmAgpGetMode +drmAgpMemoryAvail +drmAgpMemoryUsed +drmAgpRelease +drmAgpSize +drmAgpUnbind +drmAgpVendorId +drmAgpVersionMajor +drmAgpVersionMinor +drmAuthMagic +drmAvailable +drmCheckModesettingSupported +drmClose +drmCloseOnce +drmCommandNone +drmCommandRead +drmCommandWrite +drmCommandWriteRead +drmCreateContext +drmCreateDrawable +drmCrtcGetSequence +drmCrtcQueueSequence +drmCtlInstHandler +drmCtlUninstHandler +drmDelContextTag +drmDestroyContext +drmDestroyDrawable +drmDevicesEqual +drmDMA +drmDropMaster +drmError +drmFinish +drmFree +drmFreeBufs +drmFreeBusid +drmFreeDevice +drmFreeDevices +drmFreeReservedContextList +drmFreeVersion +drmGetBufInfo +drmGetBusid +drmGetCap +drmGetClient +drmGetContextFlags +drmGetContextPrivateMapping +drmGetContextTag +drmGetDevice +drmGetDevice2 +drmGetDeviceNameFromFd +drmGetDeviceNameFromFd2 +drmGetDevices +drmGetDevices2 +drmGetEntry +drmGetHashTable +drmGetInterruptFromBusID +drmGetLibVersion +drmGetLock +drmGetMagic +drmGetMap +drmGetNodeTypeFromFd +drmGetPrimaryDeviceNameFromFd +drmGetRenderDeviceNameFromFd +drmGetReservedContextList +drmGetStats +drmGetVersion +drmHandleEvent +drmHashCreate +drmHashDelete +drmHashDestroy +drmHashFirst +drmHashInsert +drmHashLookup +drmHashNext +drmIoctl +drmIsMaster +drmMalloc +drmMap +drmMapBufs +drmMarkBufs +drmModeAddFB +drmModeAddFB2 +drmModeAddFB2WithModifiers +drmModeAtomicAddProperty +drmModeAtomicAlloc +drmModeAtomicCommit +drmModeAtomicDuplicate +drmModeAtomicFree +drmModeAtomicGetCursor +drmModeAtomicMerge +drmModeAtomicSetCursor +drmModeAttachMode +drmModeConnectorSetProperty +drmModeCreateLease +drmModeCreatePropertyBlob +drmModeCrtcGetGamma +drmModeCrtcSetGamma +drmModeDestroyPropertyBlob +drmModeDetachMode +drmModeDirtyFB +drmModeFreeConnector +drmModeFreeCrtc +drmModeFreeEncoder +drmModeFreeFB +drmModeFreeFB2 +drmModeFreeModeInfo +drmModeFreeObjectProperties +drmModeFreePlane +drmModeFreePlaneResources +drmModeFreeProperty +drmModeFreePropertyBlob +drmModeFreeResources +drmModeGetConnector +drmModeGetConnectorCurrent +drmModeGetCrtc +drmModeGetEncoder +drmModeGetFB +drmModeGetFB2 +drmModeGetLease +drmModeGetPlane +drmModeGetPlaneResources +drmModeGetProperty +drmModeGetPropertyBlob +drmModeGetResources +drmModeListLessees +drmModeMoveCursor +drmModeObjectGetProperties +drmModeObjectSetProperty +drmModePageFlip +drmModePageFlipTarget +drmModeRevokeLease +drmModeRmFB +drmModeSetCrtc +drmModeSetCursor +drmModeSetCursor2 +drmModeSetPlane +drmMsg +drmOpen +drmOpenControl +drmOpenOnce +drmOpenOnceWithType +drmOpenRender +drmOpenWithType +drmPrimeFDToHandle +drmPrimeHandleToFD +drmRandom +drmRandomCreate +drmRandomDestroy +drmRandomDouble +drmRmMap +drmScatterGatherAlloc +drmScatterGatherFree +drmSetBusid +drmSetClientCap +drmSetContextFlags +drmSetInterfaceVersion +drmSetMaster +drmSetServerInfo +drmSLCreate +drmSLDelete +drmSLDestroy +drmSLDump +drmSLFirst +drmSLInsert +drmSLLookup +drmSLLookupNeighbors +drmSLNext +drmSwitchToContext +drmSyncobjCreate +drmSyncobjDestroy +drmSyncobjExportSyncFile +drmSyncobjFDToHandle +drmSyncobjHandleToFD +drmSyncobjImportSyncFile +drmSyncobjQuery +drmSyncobjQuery2 +drmSyncobjReset +drmSyncobjSignal +drmSyncobjTimelineSignal +drmSyncobjTimelineWait +drmSyncobjTransfer +drmSyncobjWait +drmUnlock +drmUnmap +drmUnmapBufs +drmUpdateDrawableInfo +drmWaitVBlank diff --git a/lib/libdrm/data/Android.mk b/lib/libdrm/data/Android.mk new file mode 100644 index 000000000..62013f0cb --- /dev/null +++ b/lib/libdrm/data/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := amdgpu.ids +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hwdata +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) diff --git a/lib/libdrm/data/amdgpu.ids b/lib/libdrm/data/amdgpu.ids index f61497e4a..d0de378db 100644 --- a/lib/libdrm/data/amdgpu.ids +++ b/lib/libdrm/data/amdgpu.ids @@ -4,10 +4,67 @@ # 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, 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, 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 6600, 0, AMD Radeon HD 8600/8700M 6600, 81, AMD Radeon (TM) R7 M370 6601, 0, AMD Radeon (TM) HD 8500M/8700M @@ -45,6 +102,7 @@ 6665, 83, AMD Radeon (TM) R5 M320 6667, 0, AMD Radeon R5 M200 Series 666F, 0, AMD Radeon HD 8500M +66A1, 06, AMD Radeon (TM) 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 @@ -140,6 +198,7 @@ 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 @@ -174,9 +233,13 @@ 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 6987, 80, AMD Embedded Radeon E9171 6987, C0, 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 @@ -184,12 +247,27 @@ 699F, C0, Radeon 500 Series 699F, C1, Radeon 540 Series 699F, C3, Radeon 500 Series -699F, C7, Radeon 550 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 +7312, 00, AMD Radeon Pro W5700 +731F, C0, AMD Radeon RX 5700 XT 50th Anniversary +731F, C1, AMD Radeon RX 5700 XT +731F, C2, AMD Radeon RX 5600M +731F, C3, AMD Radeon RX 5700M +731F, C4, AMD Radeon RX 5700 +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, CF, Radeon RX 5300 +7341, 00, AMD Radeon Pro W5500 +7347, 00, AMD Radeon Pro W5500M 9874, C4, AMD Radeon R7 Graphics 9874, C5, AMD Radeon R6 Graphics 9874, C6, AMD Radeon R6 Graphics @@ -199,4 +277,5 @@ 9874, 87, AMD Radeon R5 Graphics 9874, 85, AMD Radeon R6 Graphics 9874, 84, AMD Radeon R7 Graphics +6FDF, E7, AMD Radeon RX 590 GME 6FDF, EF, AMD Radeon RX 580 2048SP diff --git a/lib/libdrm/etnaviv/Android.mk b/lib/libdrm/etnaviv/Android.mk new file mode 100644 index 000000000..390f9a989 --- /dev/null +++ b/lib/libdrm/etnaviv/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_ETNAVIV_FILES, LIBDRM_ETNAVIV_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_etnaviv + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_ETNAVIV_FILES) + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/lib/libdrm/etnaviv/etnaviv-symbols.txt b/lib/libdrm/etnaviv/etnaviv-symbols.txt new file mode 100644 index 000000000..f48ceceac --- /dev/null +++ b/lib/libdrm/etnaviv/etnaviv-symbols.txt @@ -0,0 +1,36 @@ +etna_device_new +etna_device_new_dup +etna_device_ref +etna_device_del +etna_device_fd +etna_gpu_new +etna_gpu_del +etna_gpu_get_param +etna_pipe_new +etna_pipe_del +etna_pipe_wait +etna_pipe_wait_ns +etna_bo_new +etna_bo_from_name +etna_bo_from_dmabuf +etna_bo_ref +etna_bo_del +etna_bo_get_name +etna_bo_handle +etna_bo_dmabuf +etna_bo_size +etna_bo_map +etna_bo_cpu_prep +etna_bo_cpu_fini +etna_cmd_stream_new +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 diff --git a/lib/libdrm/etnaviv/meson.build b/lib/libdrm/etnaviv/meson.build index 1ecf29404..6040cf632 100644 --- a/lib/libdrm/etnaviv/meson.build +++ b/lib/libdrm/etnaviv/meson.build @@ -53,8 +53,11 @@ ext_libdrm_etnaviv = declare_dependency( ) test( - 'etnaviv-symbol-check', - find_program('etnaviv-symbol-check'), - env : env_test, - args : libdrm_etnaviv, + 'etnaviv-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_etnaviv, + '--symbols-file', files('etnaviv-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/exynos/exynos-symbols.txt b/lib/libdrm/exynos/exynos-symbols.txt new file mode 100644 index 000000000..c67484140 --- /dev/null +++ b/lib/libdrm/exynos/exynos-symbols.txt @@ -0,0 +1,23 @@ +exynos_bo_create +exynos_bo_destroy +exynos_bo_from_name +exynos_bo_get_info +exynos_bo_get_name +exynos_bo_handle +exynos_bo_map +exynos_device_create +exynos_device_destroy +exynos_prime_fd_to_handle +exynos_prime_handle_to_fd +exynos_vidi_connection +exynos_handle_event +g2d_blend +g2d_copy +g2d_copy_with_scale +g2d_exec +g2d_config_event +g2d_fini +g2d_init +g2d_move +g2d_scale_and_blend +g2d_solid_fill diff --git a/lib/libdrm/exynos/meson.build b/lib/libdrm/exynos/meson.build index 0136cb2a8..40d66fc1a 100644 --- a/lib/libdrm/exynos/meson.build +++ b/lib/libdrm/exynos/meson.build @@ -47,8 +47,11 @@ pkg.generate( ) test( - 'exynos-symbol-check', - find_program('exynos-symbol-check'), - env : env_test, - args : libdrm_exynos, + 'exynos-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_exynos, + '--symbols-file', files('exynos-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/freedreno/freedreno-symbols.txt b/lib/libdrm/freedreno/freedreno-symbols.txt new file mode 100644 index 000000000..471ca9974 --- /dev/null +++ b/lib/libdrm/freedreno/freedreno-symbols.txt @@ -0,0 +1,45 @@ +fd_bo_cpu_fini +fd_bo_cpu_prep +fd_bo_del +fd_bo_dmabuf +fd_bo_from_dmabuf +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 +fd_device_fd +fd_device_new +fd_device_new_dup +fd_device_ref +fd_device_version +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 +fd_ringbuffer_del +fd_ringbuffer_emit_reloc_ring_full +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_ringbuffer_flush2 diff --git a/lib/libdrm/freedreno/kgsl/README b/lib/libdrm/freedreno/kgsl/README new file mode 100644 index 000000000..c46ba08b9 --- /dev/null +++ b/lib/libdrm/freedreno/kgsl/README @@ -0,0 +1,26 @@ +This is a historical description of what is now the kgsl backend +in libdrm freedreno (before the upstream drm/msm driver). Note +that the kgsl backend requires the "kgsl-drm" shim driver, which +usually is in disrepair (QCOM does not build it for android), and +due to random differences between different downstream android +kernel branches it may or may not work. So YMMV. + +Original README: +---------------- + +Note that current msm kernel driver is a bit strange. It provides a +DRM interface for GEM, which is basically sufficient to have DRI2 +working. But it does not provide KMS. And interface to 2d and 3d +cores is via different other devices (/dev/kgsl-*). This is not +quite how I'd write a DRM driver, but at this stage it is useful for +xf86-video-freedreno and fdre (and eventual gallium driver) to be +able to work on existing kernel driver from QCOM, to allow to +capture cmdstream dumps from the binary blob drivers without having +to reboot. So libdrm_freedreno attempts to hide most of the crazy. +The intention is that when there is a proper kernel driver, it will +be mostly just changes in libdrm_freedreno to adapt the gallium +driver and xf86-video-freedreno (ignoring the fbdev->KMS changes). + +So don't look at freedreno as an example of how to write a libdrm +module or a DRM driver.. it is just an attempt to paper over a non- +standard kernel driver architecture. diff --git a/lib/libdrm/freedreno/meson.build b/lib/libdrm/freedreno/meson.build index 5d8d8e9bb..63b84fc94 100644 --- a/lib/libdrm/freedreno/meson.build +++ b/lib/libdrm/freedreno/meson.build @@ -70,8 +70,11 @@ pkg.generate( ) test( - 'freedreno-symbol-check', - find_program('freedreno-symbol-check'), - env : env_test, - args : libdrm_freedreno, + 'freedreno-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_freedreno, + '--symbols-file', files('freedreno-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/include/drm/amdgpu_drm.h b/lib/libdrm/include/drm/amdgpu_drm.h index 4fe35d600..4e873dcbe 100644 --- a/lib/libdrm/include/drm/amdgpu_drm.h +++ b/lib/libdrm/include/drm/amdgpu_drm.h @@ -125,13 +125,19 @@ extern "C" { /* 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. + * for the second page onward should be set to NC. It should never + * be used by user space applications. */ -#define AMDGPU_GEM_CREATE_MQD_GFX9 (1 << 8) +#define AMDGPU_GEM_CREATE_CP_MQD_GFX9 (1 << 8) /* Flag that BO may contain sensitive data that must be wiped before * releasing the memory */ #define AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE (1 << 9) +/* Flag that BO will be encrypted and that the TMZ bit should be + * set in the PTEs when mapping this buffer via GPUVM or + * accessing it with various hw blocks + */ +#define AMDGPU_GEM_CREATE_ENCRYPTED (1 << 10) struct drm_amdgpu_gem_create_in { /** the requested memory size */ @@ -345,6 +351,10 @@ struct drm_amdgpu_gem_userptr { #define AMDGPU_TILING_DCC_PITCH_MAX_MASK 0x3FFF #define AMDGPU_TILING_DCC_INDEPENDENT_64B_SHIFT 43 #define AMDGPU_TILING_DCC_INDEPENDENT_64B_MASK 0x1 +#define AMDGPU_TILING_DCC_INDEPENDENT_128B_SHIFT 44 +#define AMDGPU_TILING_DCC_INDEPENDENT_128B_MASK 0x1 +#define AMDGPU_TILING_SCANOUT_SHIFT 63 +#define AMDGPU_TILING_SCANOUT_MASK 0x1 /* Set/Get helpers for tiling flags. */ #define AMDGPU_TILING_SET(field, value) \ @@ -500,6 +510,8 @@ struct drm_amdgpu_gem_op { #define AMDGPU_VM_MTYPE_CC (3 << 5) /* Use UC MTYPE instead of default MTYPE */ #define AMDGPU_VM_MTYPE_UC (4 << 5) +/* Use RW MTYPE instead of default MTYPE */ +#define AMDGPU_VM_MTYPE_RW (5 << 5) struct drm_amdgpu_gem_va { /** GEM object handle */ @@ -552,7 +564,7 @@ struct drm_amdgpu_cs_in { /** Handle of resource list associated with CS */ __u32 bo_list_handle; __u32 num_chunks; - __u32 _pad; + __u32 flags; /** this points to __u64 * which point to cs chunks */ __u64 chunks; }; @@ -586,6 +598,14 @@ union drm_amdgpu_cs { */ #define AMDGPU_IB_FLAG_RESET_GDS_MAX_WAVE_ID (1 << 4) +/* Flag the IB as secure (TMZ) + */ +#define AMDGPU_IB_FLAGS_SECURE (1 << 5) + +/* Tell KMD to flush and invalidate caches + */ +#define AMDGPU_IB_FLAG_EMIT_MEM_SYNC (1 << 6) + struct drm_amdgpu_cs_chunk_ib { __u32 _pad; /** AMDGPU_IB_FLAG_* */ @@ -701,6 +721,9 @@ struct drm_amdgpu_cs_chunk_data { /* Subquery id: Query DMCU firmware version */ #define AMDGPU_INFO_FW_DMCU 0x12 #define AMDGPU_INFO_FW_TA 0x13 + /* Subquery id: Query DMCUB firmware version */ + #define AMDGPU_INFO_FW_DMCUB 0x14 + /* number of bytes moved for TTM migration */ #define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f /* the used VRAM size */ diff --git a/lib/libdrm/include/drm/drm_fourcc.h b/lib/libdrm/include/drm/drm_fourcc.h index 5c69090d5..ed0258c63 100644 --- a/lib/libdrm/include/drm/drm_fourcc.h +++ b/lib/libdrm/include/drm/drm_fourcc.h @@ -58,6 +58,30 @@ extern "C" { * may preserve meaning - such as number of planes - from the fourcc code, * whereas others may not. * + * Modifiers must uniquely encode buffer layout. In other words, a buffer must + * match only a single modifier. A modifier must not be a subset of layouts of + * another modifier. For instance, it's incorrect to encode pitch alignment in + * a modifier: a buffer may match a 64-pixel aligned modifier and a 32-pixel + * aligned modifier. That said, modifiers can have implicit minimal + * requirements. + * + * For modifiers where the combination of fourcc code and modifier can alias, + * a canonical pair needs to be defined and used by all drivers. Preferred + * combinations are also encouraged where all combinations might lead to + * confusion and unnecessarily reduced interoperability. An example for the + * latter is AFBC, where the ABGR layouts are preferred over ARGB layouts. + * + * There are two kinds of modifier users: + * + * - Kernel and user-space drivers: for drivers it's important that modifiers + * don't alias, otherwise two drivers might support the same format but use + * different aliases, preventing them from sharing buffers in an efficient + * format. + * - Higher-level programs interfacing with KMS/GBM/EGL/Vulkan/etc: these users + * see modifiers as opaque tokens they can check for equality and intersect. + * These users musn't need to know to reason about the modifier value + * (i.e. they are not expected to extract information out of the modifier). + * * Vendors should document their modifier usage in as much detail as * possible, to ensure maximum compatibility across devices, drivers and * applications. @@ -69,7 +93,7 @@ extern "C" { #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 */ +#define DRM_FORMAT_BIG_ENDIAN (1U<<31) /* format is big endian instead of little endian */ /* Reserve 0 for the invalid format specifier */ #define DRM_FORMAT_INVALID 0 @@ -155,6 +179,12 @@ extern "C" { #define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */ #define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ +/* + * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits + * of unused padding per component: + */ +#define DRM_FORMAT_AXBXGXRX106106106106 fourcc_code('A', 'B', '1', '0') /* [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian */ + /* packed YCbCr */ #define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ #define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ @@ -236,6 +266,12 @@ extern "C" { #define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ +/* + * 2 plane YCbCr + * index 0 = Y plane, [39:0] Y3:Y2:Y1:Y0 little endian + * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian + */ +#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ /* * 2 plane YCbCr MSB aligned @@ -265,6 +301,22 @@ extern "C" { */ #define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ +/* 3 plane non-subsampled (444) YCbCr + * 16 bits per component, but only 10 bits are used and 6 bits are padded + * index 0: Y plane, [15:0] Y:x [10:6] little endian + * index 1: Cb plane, [15:0] Cb:x [10:6] little endian + * index 2: Cr plane, [15:0] Cr:x [10:6] little endian + */ +#define DRM_FORMAT_Q410 fourcc_code('Q', '4', '1', '0') + +/* 3 plane non-subsampled (444) YCrCb + * 16 bits per component, but only 10 bits are used and 6 bits are padded + * index 0: Y plane, [15:0] Y:x [10:6] little endian + * index 1: Cr plane, [15:0] Cr:x [10:6] little endian + * index 2: Cb plane, [15:0] Cb:x [10:6] little endian + */ +#define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') + /* * 3 plane YCbCr * index 0: Y plane, [7:0] Y @@ -298,7 +350,6 @@ extern "C" { */ /* 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 @@ -309,6 +360,7 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 +#define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a /* add more to the end as needed */ @@ -323,8 +375,33 @@ extern "C" { * When adding a new token please document the layout with a code comment, * similar to the fourcc codes above. drm_fourcc.h is considered the * authoritative source for all of these. + * + * Generic modifier names: + * + * DRM_FORMAT_MOD_GENERIC_* definitions are used to provide vendor-neutral names + * for layouts which are common across multiple vendors. To preserve + * compatibility, in cases where a vendor-specific definition already exists and + * a generic name for it is desired, the common name is a purely symbolic alias + * and must use the same numerical value as the original definition. + * + * Note that generic names should only be used for modifiers which describe + * generic layouts (such as pixel re-ordering), which may have + * independently-developed support across multiple vendors. + * + * In future cases where a generic layout is identified before merging with a + * vendor-specific modifier, a new 'GENERIC' vendor or modifier using vendor + * 'NONE' could be considered. This should only be for obvious, exceptional + * cases to avoid polluting the 'GENERIC' namespace with modifiers which only + * apply to a single vendor. + * + * Generic names should not be used for cases where multiple hardware vendors + * have implementations of the same standardised compression scheme (such as + * AFBC). In those cases, all implementations should use the same format + * modifier(s), reflecting the vendor of the standard. */ +#define DRM_FORMAT_MOD_GENERIC_16_16_TILE DRM_FORMAT_MOD_SAMSUNG_16_16_TILE + /* * Invalid Modifier * @@ -344,6 +421,16 @@ extern "C" { */ #define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0) +/* + * Deprecated: use DRM_FORMAT_MOD_LINEAR instead + * + * The "none" format modifier doesn't actually mean that the modifier is + * implicit, instead it means that the layout is linear. Whether modifiers are + * used is out-of-band information carried in an API-specific way (e.g. in a + * flag for drm_mode_fb_cmd2). + */ +#define DRM_FORMAT_MOD_NONE 0 + /* Intel framebuffer modifiers */ /* @@ -354,9 +441,12 @@ extern "C" { * a platform-dependent stride. On top of that the memory can apply * platform-depending swizzling of some higher address bits into bit6. * - * This format is highly platforms specific and not useful for cross-driver - * sharing. It exists since on a given platform it does uniquely identify the - * layout in a simple way for i915-specific userspace. + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. */ #define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1) @@ -369,9 +459,12 @@ extern "C" { * memory can apply platform-depending swizzling of some higher address bits * into bit6. * - * This format is highly platforms specific and not useful for cross-driver - * sharing. It exists since on a given platform it does uniquely identify the - * layout in a simple way for i915-specific userspace. + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. */ #define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) @@ -411,6 +504,30 @@ extern "C" { #define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5) /* + * Intel color control surfaces (CCS) for Gen-12 render compression. + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS fourcc_mod_code(INTEL, 6) + +/* + * Intel color control surfaces (CCS) for Gen-12 media compression + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. For semi-planar formats like NV12, CCS planes follow the + * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces, + * planes 2 and 3 for the respective CCS. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS fourcc_mod_code(INTEL, 7) + +/* * 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 @@ -497,7 +614,113 @@ extern "C" { #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 + * Generalized Block Linear layout, used by desktop GPUs starting with NV50/G80, + * and Tegra GPUs starting with Tegra K1. + * + * Pixels are arranged in Groups of Bytes (GOBs). GOB size and layout varies + * based on the architecture generation. GOBs themselves are then arranged in + * 3D blocks, with the block dimensions (in terms of GOBs) always being a power + * of two, and hence expressible as their log2 equivalent (E.g., "2" represents + * a block depth or height of "4"). + * + * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format + * in full detail. + * + * Macro + * Bits Param Description + * ---- ----- ----------------------------------------------------------------- + * + * 3:0 h log2(height) of each block, in GOBs. Placed here for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 4:4 - Must be 1, to indicate block-linear layout. Necessary for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 8:5 - Reserved (To support 3D-surfaces with variable log2(depth) block + * size). Must be zero. + * + * Note there is no log2(width) parameter. Some portions of the + * hardware support a block width of two gobs, but it is impractical + * to use due to lack of support elsewhere, and has no known + * benefits. + * + * 11:9 - Reserved (To support 2D-array textures with variable array stride + * in blocks, specified via log2(tile width in blocks)). Must be + * zero. + * + * 19:12 k Page Kind. This value directly maps to a field in the page + * tables of all GPUs >= NV50. It affects the exact layout of bits + * in memory and can be derived from the tuple + * + * (format, GPU model, compression type, samples per pixel) + * + * Where compression type is defined below. If GPU model were + * implied by the format modifier, format, or memory buffer, page + * kind would not need to be included in the modifier itself, but + * since the modifier should define the layout of the associated + * memory buffer independent from any device or other context, it + * must be included here. + * + * 21:20 g GOB Height and Page Kind Generation. The height of a GOB changed + * starting with Fermi GPUs. Additionally, the mapping between page + * kind and bit layout has changed at various points. + * + * 0 = Gob Height 8, Fermi - Volta, Tegra K1+ Page Kind mapping + * 1 = Gob Height 4, G80 - GT2XX Page Kind mapping + * 2 = Gob Height 8, Turing+ Page Kind mapping + * 3 = Reserved for future use. + * + * 22:22 s Sector layout. On Tegra GPUs prior to Xavier, there is a further + * bit remapping step that occurs at an even lower level than the + * page kind and block linear swizzles. This causes the layout of + * surfaces mapped in those SOC's GPUs to be incompatible with the + * equivalent mapping on other GPUs in the same system. + * + * 0 = Tegra K1 - Tegra Parker/TX2 Layout. + * 1 = Desktop GPU and Tegra Xavier+ Layout + * + * 25:23 c Lossless Framebuffer Compression type. + * + * 0 = none + * 1 = ROP/3D, layout 1, exact compression format implied by Page + * Kind field + * 2 = ROP/3D, layout 2, exact compression format implied by Page + * Kind field + * 3 = CDE horizontal + * 4 = CDE vertical + * 5 = Reserved for future use + * 6 = Reserved for future use + * 7 = Reserved for future use + * + * 55:25 - Reserved for future use. Must be zero. + */ +#define DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(c, s, g, k, h) \ + fourcc_mod_code(NVIDIA, (0x10 | \ + ((h) & 0xf) | \ + (((k) & 0xff) << 12) | \ + (((g) & 0x3) << 20) | \ + (((s) & 0x1) << 22) | \ + (((c) & 0x7) << 23))) + +/* To grandfather in prior block linear format modifiers to the above layout, + * the page kind "0", which corresponds to "pitch/linear" and hence is unusable + * with block-linear layouts, is remapped within drivers to the value 0xfe, + * which corresponds to the "generic" kind used for simple single-sample + * uncompressed color formats on Fermi - Volta GPUs. + */ +static __inline__ __u64 +drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) +{ + if (!(modifier & 0x10) || (modifier & (0xff << 12))) + return modifier; + else + return modifier | (0xfe << 12); +} + +/* + * 16Bx2 Block Linear layout, used by 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. @@ -518,20 +741,20 @@ extern "C" { * in full detail. */ #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(v) \ - fourcc_mod_code(NVIDIA, 0x10 | ((v) & 0xf)) + DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0, (v)) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB \ - fourcc_mod_code(NVIDIA, 0x10) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB \ - fourcc_mod_code(NVIDIA, 0x11) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB \ - fourcc_mod_code(NVIDIA, 0x12) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB \ - fourcc_mod_code(NVIDIA, 0x13) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB \ - fourcc_mod_code(NVIDIA, 0x14) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \ - fourcc_mod_code(NVIDIA, 0x15) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) /* * Some Broadcom modifiers take parameters, for example the number of @@ -648,7 +871,21 @@ extern "C" { * Further information on the use of AFBC modifiers can be found in * Documentation/gpu/afbc.rst */ -#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) fourcc_mod_code(ARM, __afbc_mode) + +/* + * The top 4 bits (out of the 56 bits alloted for specifying vendor specific + * modifiers) denote the category for modifiers. Currently we have only two + * categories of modifiers ie AFBC and MISC. We can have a maximum of sixteen + * different categories. + */ +#define DRM_FORMAT_MOD_ARM_CODE(__type, __val) \ + fourcc_mod_code(ARM, ((__u64)(__type) << 52) | ((__val) & 0x000fffffffffffffULL)) + +#define DRM_FORMAT_MOD_ARM_TYPE_AFBC 0x00 +#define DRM_FORMAT_MOD_ARM_TYPE_MISC 0x01 + +#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFBC, __afbc_mode) /* * AFBC superblock size @@ -742,6 +979,28 @@ extern "C" { */ #define AFBC_FORMAT_MOD_BCH (1ULL << 11) +/* AFBC uncompressed storage mode + * + * Indicates that the buffer is using AFBC uncompressed storage mode. + * In this mode all superblock payloads in the buffer use the uncompressed + * storage mode, which is usually only used for data which cannot be compressed. + * The buffer layout is the same as for AFBC buffers without USM set, this only + * affects the storage mode of the individual superblocks. Note that even a + * buffer without USM set may use uncompressed storage mode for some or all + * superblocks, USM just guarantees it for all. + */ +#define AFBC_FORMAT_MOD_USM (1ULL << 12) + +/* + * Arm 16x16 Block U-Interleaved modifier + * + * This is used by Arm Mali Utgard and Midgard GPUs. It divides the image + * into 16x16 pixel blocks. Blocks are stored linearly in order, but pixels + * in the block are reordered. + */ +#define DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_MISC, 1ULL) + /* * Allwinner tiled modifier * @@ -756,6 +1015,220 @@ extern "C" { */ #define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) +/* + * Amlogic Video Framebuffer Compression modifiers + * + * Amlogic uses a proprietary lossless image compression protocol and format + * for their hardware video codec accelerators, either video decoders or + * video input encoders. + * + * It considerably reduces memory bandwidth while writing and reading + * frames in memory. + * + * The underlying storage is considered to be 3 components, 8bit or 10-bit + * per component YCbCr 420, single plane : + * - DRM_FORMAT_YUV420_8BIT + * - DRM_FORMAT_YUV420_10BIT + * + * The first 8 bits of the mode defines the layout, then the following 8 bits + * defines the options changing the layout. + * + * Not all combinations are valid, and different SoCs may support different + * combinations of layout and options. + */ +#define __fourcc_mod_amlogic_layout_mask 0xf +#define __fourcc_mod_amlogic_options_shift 8 +#define __fourcc_mod_amlogic_options_mask 0xf + +#define DRM_FORMAT_MOD_AMLOGIC_FBC(__layout, __options) \ + fourcc_mod_code(AMLOGIC, \ + ((__layout) & __fourcc_mod_amlogic_layout_mask) | \ + (((__options) & __fourcc_mod_amlogic_options_mask) \ + << __fourcc_mod_amlogic_options_shift)) + +/* Amlogic FBC Layouts */ + +/* + * Amlogic FBC Basic Layout + * + * The basic layout is composed of: + * - a body content organized in 64x32 superblocks with 4096 bytes per + * superblock in default mode. + * - a 32 bytes per 128x64 header block + * + * This layout is transferrable between Amlogic SoCs supporting this modifier. + */ +#define AMLOGIC_FBC_LAYOUT_BASIC (1ULL) + +/* + * Amlogic FBC Scatter Memory layout + * + * Indicates the header contains IOMMU references to the compressed + * frames content to optimize memory access and layout. + * + * In this mode, only the header memory address is needed, thus the + * content memory organization is tied to the current producer + * execution and cannot be saved/dumped neither transferrable between + * Amlogic SoCs supporting this modifier. + * + * Due to the nature of the layout, these buffers are not expected to + * be accessible by the user-space clients, but only accessible by the + * hardware producers and consumers. + * + * The user-space clients should expect a failure while trying to mmap + * the DMA-BUF handle returned by the producer. + */ +#define AMLOGIC_FBC_LAYOUT_SCATTER (2ULL) + +/* Amlogic FBC Layout Options Bit Mask */ + +/* + * Amlogic FBC Memory Saving mode + * + * Indicates the storage is packed when pixel size is multiple of word + * boudaries, i.e. 8bit should be stored in this mode to save allocation + * memory. + * + * This mode reduces body layout to 3072 bytes per 64x32 superblock with + * the basic layout and 3200 bytes per 64x32 superblock combined with + * the scatter layout. + */ +#define AMLOGIC_FBC_OPTION_MEM_SAVING (1ULL << 0) + +/* + * AMD modifiers + * + * Memory layout: + * + * without DCC: + * - main surface + * + * with DCC & without DCC_RETILE: + * - main surface in plane 0 + * - DCC surface in plane 1 (RB-aligned, pipe-aligned if DCC_PIPE_ALIGN is set) + * + * with DCC & DCC_RETILE: + * - main surface in plane 0 + * - displayable DCC surface in plane 1 (not RB-aligned & not pipe-aligned) + * - pipe-aligned DCC surface in plane 2 (RB-aligned & pipe-aligned) + * + * For multi-plane formats the above surfaces get merged into one plane for + * each format plane, based on the required alignment only. + * + * Bits Parameter Notes + * ----- ------------------------ --------------------------------------------- + * + * 7:0 TILE_VERSION Values are AMD_FMT_MOD_TILE_VER_* + * 12:8 TILE Values are AMD_FMT_MOD_TILE_<version>_* + * 13 DCC + * 14 DCC_RETILE + * 15 DCC_PIPE_ALIGN + * 16 DCC_INDEPENDENT_64B + * 17 DCC_INDEPENDENT_128B + * 19:18 DCC_MAX_COMPRESSED_BLOCK Values are AMD_FMT_MOD_DCC_BLOCK_* + * 20 DCC_CONSTANT_ENCODE + * 23:21 PIPE_XOR_BITS Only for some chips + * 26:24 BANK_XOR_BITS Only for some chips + * 29:27 PACKERS Only for some chips + * 32:30 RB Only for some chips + * 35:33 PIPE Only for some chips + * 55:36 - Reserved for future use, must be zero + */ +#define AMD_FMT_MOD fourcc_mod_code(AMD, 0) + +#define IS_AMD_FMT_MOD(val) (((val) >> 56) == DRM_FORMAT_MOD_VENDOR_AMD) + +/* Reserve 0 for GFX8 and older */ +#define AMD_FMT_MOD_TILE_VER_GFX9 1 +#define AMD_FMT_MOD_TILE_VER_GFX10 2 +#define AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS 3 + +/* + * 64K_S is the same for GFX9/GFX10/GFX10_RBPLUS and hence has GFX9 as canonical + * version. + */ +#define AMD_FMT_MOD_TILE_GFX9_64K_S 9 + +/* + * 64K_D for non-32 bpp is the same for GFX9/GFX10/GFX10_RBPLUS and hence has + * GFX9 as canonical version. + */ +#define AMD_FMT_MOD_TILE_GFX9_64K_D 10 +#define AMD_FMT_MOD_TILE_GFX9_64K_S_X 25 +#define AMD_FMT_MOD_TILE_GFX9_64K_D_X 26 +#define AMD_FMT_MOD_TILE_GFX9_64K_R_X 27 + +#define AMD_FMT_MOD_DCC_BLOCK_64B 0 +#define AMD_FMT_MOD_DCC_BLOCK_128B 1 +#define AMD_FMT_MOD_DCC_BLOCK_256B 2 + +#define AMD_FMT_MOD_TILE_VERSION_SHIFT 0 +#define AMD_FMT_MOD_TILE_VERSION_MASK 0xFF +#define AMD_FMT_MOD_TILE_SHIFT 8 +#define AMD_FMT_MOD_TILE_MASK 0x1F + +/* Whether DCC compression is enabled. */ +#define AMD_FMT_MOD_DCC_SHIFT 13 +#define AMD_FMT_MOD_DCC_MASK 0x1 + +/* + * Whether to include two DCC surfaces, one which is rb & pipe aligned, and + * one which is not-aligned. + */ +#define AMD_FMT_MOD_DCC_RETILE_SHIFT 14 +#define AMD_FMT_MOD_DCC_RETILE_MASK 0x1 + +/* Only set if DCC_RETILE = false */ +#define AMD_FMT_MOD_DCC_PIPE_ALIGN_SHIFT 15 +#define AMD_FMT_MOD_DCC_PIPE_ALIGN_MASK 0x1 + +#define AMD_FMT_MOD_DCC_INDEPENDENT_64B_SHIFT 16 +#define AMD_FMT_MOD_DCC_INDEPENDENT_64B_MASK 0x1 +#define AMD_FMT_MOD_DCC_INDEPENDENT_128B_SHIFT 17 +#define AMD_FMT_MOD_DCC_INDEPENDENT_128B_MASK 0x1 +#define AMD_FMT_MOD_DCC_MAX_COMPRESSED_BLOCK_SHIFT 18 +#define AMD_FMT_MOD_DCC_MAX_COMPRESSED_BLOCK_MASK 0x3 + +/* + * DCC supports embedding some clear colors directly in the DCC surface. + * However, on older GPUs the rendering HW ignores the embedded clear color + * and prefers the driver provided color. This necessitates doing a fastclear + * eliminate operation before a process transfers control. + * + * If this bit is set that means the fastclear eliminate is not needed for these + * embeddable colors. + */ +#define AMD_FMT_MOD_DCC_CONSTANT_ENCODE_SHIFT 20 +#define AMD_FMT_MOD_DCC_CONSTANT_ENCODE_MASK 0x1 + +/* + * The below fields are for accounting for per GPU differences. These are only + * relevant for GFX9 and later and if the tile field is *_X/_T. + * + * PIPE_XOR_BITS = always needed + * BANK_XOR_BITS = only for TILE_VER_GFX9 + * PACKERS = only for TILE_VER_GFX10_RBPLUS + * RB = only for TILE_VER_GFX9 & DCC + * PIPE = only for TILE_VER_GFX9 & DCC & (DCC_RETILE | DCC_PIPE_ALIGN) + */ +#define AMD_FMT_MOD_PIPE_XOR_BITS_SHIFT 21 +#define AMD_FMT_MOD_PIPE_XOR_BITS_MASK 0x7 +#define AMD_FMT_MOD_BANK_XOR_BITS_SHIFT 24 +#define AMD_FMT_MOD_BANK_XOR_BITS_MASK 0x7 +#define AMD_FMT_MOD_PACKERS_SHIFT 27 +#define AMD_FMT_MOD_PACKERS_MASK 0x7 +#define AMD_FMT_MOD_RB_SHIFT 30 +#define AMD_FMT_MOD_RB_MASK 0x7 +#define AMD_FMT_MOD_PIPE_SHIFT 33 +#define AMD_FMT_MOD_PIPE_MASK 0x7 + +#define AMD_FMT_MOD_SET(field, value) \ + ((uint64_t)(value) << AMD_FMT_MOD_##field##_SHIFT) +#define AMD_FMT_MOD_GET(field, value) \ + (((value) >> AMD_FMT_MOD_##field##_SHIFT) & AMD_FMT_MOD_##field##_MASK) +#define AMD_FMT_MOD_CLEAR(field) \ + (~((uint64_t)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT)) + #if defined(__cplusplus) } #endif diff --git a/lib/libdrm/include/drm/drm_mode.h b/lib/libdrm/include/drm/drm_mode.h index 5fe6c649f..96416e6df 100644 --- a/lib/libdrm/include/drm/drm_mode.h +++ b/lib/libdrm/include/drm/drm_mode.h @@ -33,6 +33,15 @@ extern "C" { #endif +/** + * DOC: overview + * + * DRM exposes many UAPI and structure definition to have a consistent + * and standardized interface with user. + * Userspace can refer to these structure definitions and UAPI formats + * to communicate to driver + */ + #define DRM_CONNECTOR_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 #define DRM_PROP_NAME_LEN 32 @@ -323,14 +332,19 @@ struct drm_mode_get_encoder { /* This is for connectors with multiple signal types. */ /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ 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, + DRM_MODE_SUBCONNECTOR_Automatic = 0, /* DVI-I, TV */ + DRM_MODE_SUBCONNECTOR_Unknown = 0, /* DVI-I, TV, DP */ + DRM_MODE_SUBCONNECTOR_VGA = 1, /* DP */ + DRM_MODE_SUBCONNECTOR_DVID = 3, /* DVI-I DP */ + DRM_MODE_SUBCONNECTOR_DVIA = 4, /* DVI-I */ + DRM_MODE_SUBCONNECTOR_Composite = 5, /* TV */ + DRM_MODE_SUBCONNECTOR_SVIDEO = 6, /* TV */ + DRM_MODE_SUBCONNECTOR_Component = 8, /* TV */ + DRM_MODE_SUBCONNECTOR_SCART = 9, /* TV */ + DRM_MODE_SUBCONNECTOR_DisplayPort = 10, /* DP */ + DRM_MODE_SUBCONNECTOR_HDMIA = 11, /* DP */ + DRM_MODE_SUBCONNECTOR_Native = 15, /* DP */ + DRM_MODE_SUBCONNECTOR_Wireless = 18, /* DP */ }; #define DRM_MODE_CONNECTOR_Unknown 0 @@ -352,6 +366,7 @@ enum drm_mode_subconnector { #define DRM_MODE_CONNECTOR_DSI 16 #define DRM_MODE_CONNECTOR_DPI 17 #define DRM_MODE_CONNECTOR_WRITEBACK 18 +#define DRM_MODE_CONNECTOR_SPI 19 struct drm_mode_get_connector { @@ -487,7 +502,7 @@ struct drm_mode_fb_cmd2 { * In case of planar formats, this ioctl allows up to 4 * buffer objects with offsets and pitches per plane. * The pitch and offset order is dictated by the fourcc, - * e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as: + * e.g. NV12 (https://fourcc.org/yuv.php#NV12) is described as: * * YUV 4:2:0 image with a plane of 8 bit Y samples * followed by an interleaved U/V plane containing @@ -630,6 +645,92 @@ struct drm_color_lut { __u16 reserved; }; +/** + * struct hdr_metadata_infoframe - HDR Metadata Infoframe Data. + * + * HDR Metadata Infoframe as per CTA 861.G spec. This is expected + * to match exactly with the spec. + * + * Userspace is expected to pass the metadata information as per + * the format described in this structure. + */ +struct hdr_metadata_infoframe { + /** + * @eotf: Electro-Optical Transfer Function (EOTF) + * used in the stream. + */ + __u8 eotf; + /** + * @metadata_type: Static_Metadata_Descriptor_ID. + */ + __u8 metadata_type; + /** + * @display_primaries: Color Primaries of the Data. + * These are coded as unsigned 16-bit values in units of + * 0.00002, where 0x0000 represents zero and 0xC350 + * represents 1.0000. + * @display_primaries.x: X cordinate of color primary. + * @display_primaries.y: Y cordinate of color primary. + */ + struct { + __u16 x, y; + } display_primaries[3]; + /** + * @white_point: White Point of Colorspace Data. + * These are coded as unsigned 16-bit values in units of + * 0.00002, where 0x0000 represents zero and 0xC350 + * represents 1.0000. + * @white_point.x: X cordinate of whitepoint of color primary. + * @white_point.y: Y cordinate of whitepoint of color primary. + */ + struct { + __u16 x, y; + } white_point; + /** + * @max_display_mastering_luminance: Max Mastering Display Luminance. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_display_mastering_luminance; + /** + * @min_display_mastering_luminance: Min Mastering Display Luminance. + * This value is coded as an unsigned 16-bit value in units of + * 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + * represents 6.5535 cd/m2. + */ + __u16 min_display_mastering_luminance; + /** + * @max_cll: Max Content Light Level. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_cll; + /** + * @max_fall: Max Frame Average Light Level. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_fall; +}; + +/** + * struct hdr_output_metadata - HDR output metadata + * + * Metadata Information to be passed from userspace + */ +struct hdr_output_metadata { + /** + * @metadata_type: Static_Metadata_Descriptor_ID. + */ + __u32 metadata_type; + /** + * @hdmi_metadata_type1: HDR Metadata Infoframe. + */ + union { + struct hdr_metadata_infoframe hdmi_metadata_type1; + }; +}; + #define DRM_MODE_PAGE_FLIP_EVENT 0x01 #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 @@ -803,6 +904,10 @@ struct drm_format_modifier { }; /** + * struct drm_mode_create_blob - Create New block property + * @data: Pointer to data to copy. + * @length: Length of data to copy. + * @blob_id: new property ID. * Create a new 'blob' data property, copying length bytes from data pointer, * and returning new blob ID. */ @@ -816,13 +921,27 @@ struct drm_mode_create_blob { }; /** + * struct drm_mode_destroy_blob - Destroy user blob + * @blob_id: blob_id to destroy * Destroy a user-created blob property. + * + * User-space can release blobs as soon as they do not need to refer to them by + * their blob object ID. For instance, if you are using a MODE_ID blob in an + * atomic commit and you will not make another commit re-using the same ID, you + * can destroy the blob as soon as the commit has been issued, without waiting + * for it to complete. */ struct drm_mode_destroy_blob { __u32 blob_id; }; /** + * struct drm_mode_create_lease - Create lease + * @object_ids: Pointer to array of object ids. + * @object_count: Number of object ids. + * @flags: flags for new FD. + * @lessee_id: unique identifier for lessee. + * @fd: file descriptor to new drm_master file. * Lease mode resources, creating another drm_master. */ struct drm_mode_create_lease { @@ -840,6 +959,10 @@ struct drm_mode_create_lease { }; /** + * struct drm_mode_list_lessees - List lessees + * @count_lessees: Number of lessees. + * @pad: pad. + * @lessees_ptr: Pointer to lessess. * List lesses from a drm_master */ struct drm_mode_list_lessees { @@ -860,6 +983,10 @@ struct drm_mode_list_lessees { }; /** + * struct drm_mode_get_lease - Get Lease + * @count_objects: Number of leased objects. + * @pad: pad. + * @objects_ptr: Pointer to objects. * Get leased objects */ struct drm_mode_get_lease { @@ -880,6 +1007,8 @@ struct drm_mode_get_lease { }; /** + * struct drm_mode_revoke_lease - Revoke lease + * @lessee_id: Unique ID of lessee. * Revoke lease */ struct drm_mode_revoke_lease { diff --git a/lib/libdrm/include/drm/nouveau_drm.h b/lib/libdrm/include/drm/nouveau_drm.h index d42105c86..4f9414890 100644 --- a/lib/libdrm/include/drm/nouveau_drm.h +++ b/lib/libdrm/include/drm/nouveau_drm.h @@ -73,15 +73,11 @@ struct drm_nouveau_gpuobj_free { uint32_t handle; }; -/* FIXME : maybe unify {GET,SET}PARAMs */ #define NOUVEAU_GETPARAM_PCI_VENDOR 3 #define NOUVEAU_GETPARAM_PCI_DEVICE 4 #define NOUVEAU_GETPARAM_BUS_TYPE 5 -#define NOUVEAU_GETPARAM_FB_PHYSICAL 6 -#define NOUVEAU_GETPARAM_AGP_PHYSICAL 7 #define NOUVEAU_GETPARAM_FB_SIZE 8 #define NOUVEAU_GETPARAM_AGP_SIZE 9 -#define NOUVEAU_GETPARAM_PCI_PHYSICAL 10 #define NOUVEAU_GETPARAM_CHIPSET_ID 11 #define NOUVEAU_GETPARAM_VM_VRAM_BASE 12 #define NOUVEAU_GETPARAM_GRAPH_UNITS 13 @@ -175,12 +171,12 @@ struct drm_nouveau_gem_pushbuf { __u64 push; __u32 suffix0; __u32 suffix1; +#define NOUVEAU_GEM_PUSHBUF_SYNC (1ULL << 0) __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 { __u32 handle; @@ -191,29 +187,68 @@ struct drm_nouveau_gem_cpu_fini { __u32 handle; }; -enum nouveau_bus_type { - NV_AGP = 0, - NV_PCI = 1, - NV_PCIE = 2, -}; - -struct drm_nouveau_sarea { -}; - -#define DRM_NOUVEAU_GETPARAM 0x00 -#define DRM_NOUVEAU_SETPARAM 0x01 -#define DRM_NOUVEAU_CHANNEL_ALLOC 0x02 -#define DRM_NOUVEAU_CHANNEL_FREE 0x03 -#define DRM_NOUVEAU_GROBJ_ALLOC 0x04 -#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x05 -#define DRM_NOUVEAU_GPUOBJ_FREE 0x06 +#define DRM_NOUVEAU_GETPARAM 0x00 /* deprecated */ +#define DRM_NOUVEAU_SETPARAM 0x01 /* deprecated */ +#define DRM_NOUVEAU_CHANNEL_ALLOC 0x02 /* deprecated */ +#define DRM_NOUVEAU_CHANNEL_FREE 0x03 /* deprecated */ +#define DRM_NOUVEAU_GROBJ_ALLOC 0x04 /* deprecated */ +#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x05 /* deprecated */ +#define DRM_NOUVEAU_GPUOBJ_FREE 0x06 /* deprecated */ #define DRM_NOUVEAU_NVIF 0x07 +#define DRM_NOUVEAU_SVM_INIT 0x08 +#define DRM_NOUVEAU_SVM_BIND 0x09 #define DRM_NOUVEAU_GEM_NEW 0x40 #define DRM_NOUVEAU_GEM_PUSHBUF 0x41 #define DRM_NOUVEAU_GEM_CPU_PREP 0x42 #define DRM_NOUVEAU_GEM_CPU_FINI 0x43 #define DRM_NOUVEAU_GEM_INFO 0x44 +struct drm_nouveau_svm_init { + __u64 unmanaged_addr; + __u64 unmanaged_size; +}; + +struct drm_nouveau_svm_bind { + __u64 header; + __u64 va_start; + __u64 va_end; + __u64 npages; + __u64 stride; + __u64 result; + __u64 reserved0; + __u64 reserved1; +}; + +#define NOUVEAU_SVM_BIND_COMMAND_SHIFT 0 +#define NOUVEAU_SVM_BIND_COMMAND_BITS 8 +#define NOUVEAU_SVM_BIND_COMMAND_MASK ((1 << 8) - 1) +#define NOUVEAU_SVM_BIND_PRIORITY_SHIFT 8 +#define NOUVEAU_SVM_BIND_PRIORITY_BITS 8 +#define NOUVEAU_SVM_BIND_PRIORITY_MASK ((1 << 8) - 1) +#define NOUVEAU_SVM_BIND_TARGET_SHIFT 16 +#define NOUVEAU_SVM_BIND_TARGET_BITS 32 +#define NOUVEAU_SVM_BIND_TARGET_MASK 0xffffffff + +/* + * Below is use to validate ioctl argument, userspace can also use it to make + * sure that no bit are set beyond known fields for a given kernel version. + */ +#define NOUVEAU_SVM_BIND_VALID_BITS 48 +#define NOUVEAU_SVM_BIND_VALID_MASK ((1ULL << NOUVEAU_SVM_BIND_VALID_BITS) - 1) + + +/* + * NOUVEAU_BIND_COMMAND__MIGRATE: synchronous migrate to target memory. + * result: number of page successfuly migrate to the target memory. + */ +#define NOUVEAU_SVM_BIND_COMMAND__MIGRATE 0 + +/* + * NOUVEAU_SVM_BIND_HEADER_TARGET__GPU_VRAM: target the GPU VRAM memory. + */ +#define NOUVEAU_SVM_BIND_TARGET__GPU_VRAM (1UL << 31) + + #if defined(__cplusplus) } #endif diff --git a/lib/libdrm/intel/.gitignore b/lib/libdrm/intel/.gitignore new file mode 100644 index 000000000..528b40869 --- /dev/null +++ b/lib/libdrm/intel/.gitignore @@ -0,0 +1 @@ +test_decode diff --git a/lib/libdrm/intel/intel-symbols.txt b/lib/libdrm/intel/intel-symbols.txt new file mode 100644 index 000000000..132df96a7 --- /dev/null +++ b/lib/libdrm/intel/intel-symbols.txt @@ -0,0 +1,83 @@ +drm_intel_bo_alloc +drm_intel_bo_alloc_for_render +drm_intel_bo_alloc_tiled +drm_intel_bo_alloc_userptr +drm_intel_bo_busy +drm_intel_bo_disable_reuse +drm_intel_bo_emit_reloc +drm_intel_bo_emit_reloc_fence +drm_intel_bo_exec +drm_intel_bo_fake_alloc_static +drm_intel_bo_fake_disable_backing_store +drm_intel_bo_flink +drm_intel_bo_gem_create_from_name +drm_intel_bo_gem_create_from_prime +drm_intel_bo_gem_export_to_prime +drm_intel_bo_get_subdata +drm_intel_bo_get_tiling +drm_intel_bo_is_reusable +drm_intel_bo_madvise +drm_intel_bo_map +drm_intel_bo_mrb_exec +drm_intel_bo_pin +drm_intel_bo_reference +drm_intel_bo_references +drm_intel_bo_set_softpin_offset +drm_intel_bo_set_tiling +drm_intel_bo_subdata +drm_intel_bo_unmap +drm_intel_bo_unpin +drm_intel_bo_unreference +drm_intel_bo_use_48b_address_range +drm_intel_bo_wait_rendering +drm_intel_bufmgr_check_aperture_space +drm_intel_bufmgr_destroy +drm_intel_bufmgr_fake_contended_lock_take +drm_intel_bufmgr_fake_evict_all +drm_intel_bufmgr_fake_init +drm_intel_bufmgr_fake_set_exec_callback +drm_intel_bufmgr_fake_set_fence_callback +drm_intel_bufmgr_fake_set_last_dispatch +drm_intel_bufmgr_gem_can_disable_implicit_sync +drm_intel_bufmgr_gem_enable_fenced_relocs +drm_intel_bufmgr_gem_enable_reuse +drm_intel_bufmgr_gem_get_devid +drm_intel_bufmgr_gem_init +drm_intel_bufmgr_gem_set_aub_annotations +drm_intel_bufmgr_gem_set_aub_dump +drm_intel_bufmgr_gem_set_aub_filename +drm_intel_bufmgr_gem_set_vma_cache_size +drm_intel_bufmgr_set_debug +drm_intel_decode +drm_intel_decode_context_alloc +drm_intel_decode_context_free +drm_intel_decode_set_batch_pointer +drm_intel_decode_set_dump_past_end +drm_intel_decode_set_head_tail +drm_intel_decode_set_output_file +drm_intel_gem_bo_aub_dump_bmp +drm_intel_gem_bo_clear_relocs +drm_intel_gem_bo_context_exec +drm_intel_gem_bo_disable_implicit_sync +drm_intel_gem_bo_enable_implicit_sync +drm_intel_gem_bo_fence_exec +drm_intel_gem_bo_get_reloc_count +drm_intel_gem_bo_map__cpu +drm_intel_gem_bo_map__gtt +drm_intel_gem_bo_map__wc +drm_intel_gem_bo_map_gtt +drm_intel_gem_bo_map_unsynchronized +drm_intel_gem_bo_start_gtt_access +drm_intel_gem_bo_unmap_gtt +drm_intel_gem_bo_wait +drm_intel_gem_context_create +drm_intel_gem_context_destroy +drm_intel_gem_context_get_id +drm_intel_get_aperture_sizes +drm_intel_get_eu_total +drm_intel_get_min_eu_in_pool +drm_intel_get_pipe_from_crtc_id +drm_intel_get_pooled_eu +drm_intel_get_reset_stats +drm_intel_get_subslice_total +drm_intel_reg_read diff --git a/lib/libdrm/intel/intel_chipset.c b/lib/libdrm/intel/intel_chipset.c index f6e37ee7f..439db3e55 100644 --- a/lib/libdrm/intel/intel_chipset.c +++ b/lib/libdrm/intel/intel_chipset.c @@ -35,6 +35,8 @@ static const struct pci_device { uint16_t gen; } pciids[] = { /* Keep ids sorted by gen; latest gen first */ + INTEL_RKL_IDS(12), + INTEL_DG1_IDS(12), INTEL_TGL_12_IDS(12), INTEL_EHL_IDS(11), INTEL_ICL_11_IDS(11), diff --git a/lib/libdrm/intel/meson.build b/lib/libdrm/intel/meson.build index 355bf35d4..4d3f1ebda 100644 --- a/lib/libdrm/intel/meson.build +++ b/lib/libdrm/intel/meson.build @@ -92,9 +92,13 @@ test( find_program('tests/gen7-2d-copy.batch.sh'), workdir : meson.current_build_dir(), ) + test( - 'intel-symbol-check', - find_program('intel-symbol-check'), - env : env_test, - args : libdrm_intel, + 'intel-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_intel, + '--symbols-file', files('intel-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/intel/tests/.gitignore b/lib/libdrm/intel/tests/.gitignore new file mode 100644 index 000000000..e9d01ecb2 --- /dev/null +++ b/lib/libdrm/intel/tests/.gitignore @@ -0,0 +1 @@ +*-new.txt diff --git a/lib/libdrm/intel/tests/test-batch.sh b/lib/libdrm/intel/tests/test-batch.sh index a94057ffc..b85f639a1 100755 --- a/lib/libdrm/intel/tests/test-batch.sh +++ b/lib/libdrm/intel/tests/test-batch.sh @@ -1,6 +1,6 @@ #!/bin/sh -TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +TEST_FILENAME=`echo "$0" | sed 's|\.sh$||'` ./test_decode $TEST_FILENAME ret=$? diff --git a/lib/libdrm/libkms/kms-symbols.txt b/lib/libdrm/libkms/kms-symbols.txt new file mode 100644 index 000000000..e0ba8c91c --- /dev/null +++ b/lib/libdrm/libkms/kms-symbols.txt @@ -0,0 +1,8 @@ +kms_bo_create +kms_bo_destroy +kms_bo_get_prop +kms_bo_map +kms_bo_unmap +kms_create +kms_destroy +kms_get_prop diff --git a/lib/libdrm/libkms/meson.build b/lib/libdrm/libkms/meson.build index 04f018af6..216be4df4 100644 --- a/lib/libdrm/libkms/meson.build +++ b/lib/libdrm/libkms/meson.build @@ -68,8 +68,11 @@ pkg.generate( ) test( - 'kms-symbol-check', - find_program('kms-symbol-check'), - env : env_test, - args : libkms, + 'kms-symbols-check', + symbols_check, + args : [ + '--lib', libkms, + '--symbols-file', files('kms-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/man/drm-kms.7.rst b/lib/libdrm/man/drm-kms.7.rst new file mode 100644 index 000000000..e91fbe274 --- /dev/null +++ b/lib/libdrm/man/drm-kms.7.rst @@ -0,0 +1,229 @@ +======= +drm-kms +======= + +------------------- +Kernel Mode-Setting +------------------- + +:Date: September 2012 +:Manual section: 7 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include <xf86drm.h>`` + +``#include <xf86drmMode.h>`` + +Description +=========== + +Each DRM device provides access to manage which monitors and displays are +currently used and what frames to be displayed. This task is called *Kernel +Mode-Setting* (KMS). Historically, this was done in user-space and called +*User-space Mode-Setting* (UMS). Almost all open-source drivers now provide the +KMS kernel API to do this in the kernel, however, many non-open-source binary +drivers from different vendors still do not support this. You can use +**drmModeSettingSupported**\ (3) to check whether your driver supports this. To +understand how KMS works, we need to introduce 5 objects: *CRTCs*, *Planes*, +*Encoders*, *Connectors* and *Framebuffers*. + +CRTCs + A *CRTC* short for *CRT Controller* is an abstraction representing a part of + the chip that contains a pointer to a scanout buffer. Therefore, the number + of CRTCs available determines how many independent scanout buffers can be + active at any given time. The CRTC structure contains several fields to + support this: a pointer to some video memory (abstracted as a frame-buffer + object), a list of driven connectors, a display mode and an (x, y) offset + into the video memory to support panning or configurations where one piece + of video memory spans multiple CRTCs. A CRTC is the central point where + configuration of displays happens. You select which objects to use, which + modes and which parameters and then configure each CRTC via + **drmModeCrtcSet**\ (3) to drive the display devices. + +Planes + A *plane* respresents an image source that can be blended with or overlayed + on top of a CRTC during the scanout process. Planes are associated with a + frame-buffer to crop a portion of the image memory (source) and optionally + scale it to a destination size. The result is then blended with or overlayed + on top of a CRTC. Planes are not provided by all hardware and the number of + available planes is limited. If planes are not available or if not enough + planes are available, the user should fall back to normal software blending + (via GPU or CPU). + +Encoders + An *encoder* takes pixel data from a CRTC and converts it to a format + suitable for any attached connectors. On some devices, it may be possible to + have a CRTC send data to more than one encoder. In that case, both encoders + would receive data from the same scanout buffer, resulting in a *cloned* + display configuration across the connectors attached to each encoder. + +Connectors + A *connector* is the final destination of pixel-data on a device, and + usually connects directly to an external display device like a monitor or + laptop panel. A connector can only be attached to one encoder at a time. The + connector is also the structure where information about the attached display + is kept, so it contains fields for display data, *EDID* data, *DPMS* and + *connection status*, and information about modes supported on the attached + displays. + +Framebuffers + *Framebuffers* are abstract memory objects that provide a source of pixel + data to scanout to a CRTC. Applications explicitly request the creation of + framebuffers and can control their behavior. Framebuffers rely on the + underneath memory manager for low-level memory operations. When creating a + framebuffer, applications pass a memory handle through the API which is used + as backing storage. The framebuffer itself is only an abstract object with + no data. It just refers to memory buffers that must be created with the + **drm-memory**\ (7) API. + +Mode-Setting +------------ + +Before mode-setting can be performed, an application needs to call +**drmSetMaster**\ (3) to become *DRM-Master*. It then has exclusive access to +the KMS API. A call to **drmModeGetResources**\ (3) returns a list of *CRTCs*, +*Connectors*, *Encoders* and *Planes*. + +Normal procedure now includes: First, you select which connectors you want to +use. Users are mostly interested in which monitor or display-panel is active so +you need to make sure to arrange them in the correct logical order and select +the correct ones to use. For each connector, you need to find a CRTC to drive +this connector. If you want to clone output to two or more connectors, you may +use a single CRTC for all cloned connectors (if the hardware supports this). To +find a suitable CRTC, you need to iterate over the list of encoders that are +available for each connector. Each encoder contains a list of CRTCs that it can +work with and you simply select one of these CRTCs. If you later program the +CRTC to control a connector, it automatically selects the best encoder. +However, this procedure is needed so your CRTC has at least one working encoder +for the selected connector. See the *Examples* section below for more +information. + +All valid modes for a connector can be retrieved with a call to +drmModeGetConnector3 You need to select the mode you want to use and save it. +The first mode in the list is the default mode with the highest resolution +possible and often a suitable choice. + +After you have a working connector+CRTC+mode combination, you need to create a +framebuffer that is used for scanout. Memory buffer allocation is +driver-depedent and described in **drm-memory**\ (7). You need to create a +buffer big enough for your selected mode. Now you can create a framebuffer +object that uses your memory-buffer as scanout buffer. You can do this with +**drmModeAddFB**\ (3) and **drmModeAddFB2**\ (3). + +As a last step, you want to program your CRTC to drive your selected connector. +You can do this with a call to **drmModeSetCrtc**\ (3). + +Page-Flipping +------------- + +A call to **drmModeSetCrtc**\ (3) is executed immediately and forces the CRTC +to use the new scanout buffer. If you want smooth-transitions without tearing, +you probably use double-buffering. You need to create one framebuffer object +for each buffer you use. You can then call **drmModeSetCrtc**\ (3) on the next +buffer to flip. If you want to synchronize your flips with *vertical-blanks*, +you can use **drmModePageFlip**\ (3) which schedules your page-flip for the +next *vblank*. + +Planes +------ + +Planes are controlled independently from CRTCs. That is, a call to +**drmModeSetCrtc**\ (3) does not affect planes. Instead, you need to call +**drmModeSetPlane**\ (3) to configure a plane. This requires the plane ID, a +CRTC, a framebuffer and offsets into the plane-framebuffer and the +CRTC-framebuffer. The CRTC then blends the content from the plane over the CRTC +framebuffer buffer during scanout. As this does not involve any +software-blending, it is way faster than traditional blending. However, plane +resources are limited. See **drmModeGetPlaneResources**\ (3) for more +information. + +Cursors +------- + +Similar to planes, many hardware also supports cursors. A cursor is a very +small buffer with an image that is blended over the CRTC framebuffer. You can +set a different cursor for each CRTC with **drmModeSetCursor**\ (3) and move it +on the screen with **drmModeMoveCursor**\ (3). This allows to move the cursor +on the screen without rerendering. If no hardware cursors are supported, you +need to rerender for each frame the cursor is moved. + +Examples +======== + +Some examples of how basic mode-setting can be done. See the man-page of each +DRM function for more information. + +CRTC/Encoder Selection +---------------------- + +If you retrieved all display configuration information via +**drmModeGetResources**\ (3) as ``drmModeRes *res``, selected a connector from +the list in ``res->connectors`` and retrieved the connector-information as +``drmModeConnector *conn`` via **drmModeGetConnector**\ (3) then this example +shows, how you can find a suitable CRTC id to drive this connector. This +function takes a file-descriptor to the DRM device (see **drmOpen**\ (3)) as +``fd``, a pointer to the retrieved resources as ``res`` and a pointer to the +selected connector as ``conn``. It returns an integer smaller than 0 on +failure, otherwise, a valid CRTC id is returned. + +:: + + static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn) + { + drmModeEncoder *enc; + unsigned int i, j; + + /* iterate all encoders of this connector */ + for (i = 0; i < conn->count_encoders; ++i) { + enc = drmModeGetEncoder(fd, conn->encoders[i]); + if (!enc) { + /* cannot retrieve encoder, ignoring... */ + continue; + } + + /* iterate all global CRTCs */ + for (j = 0; j < res->count_crtcs; ++j) { + /* check whether this CRTC works with the encoder */ + if (!(enc->possible_crtcs & (1 << j))) + continue; + + + /* Here you need to check that no other connector + * currently uses the CRTC with id "crtc". If you intend + * to drive one connector only, then you can skip this + * step. Otherwise, simply scan your list of configured + * connectors and CRTCs whether this CRTC is already + * used. If it is, then simply continue the search here. */ + if (res->crtcs[j] "is unused") { + drmModeFreeEncoder(enc); + return res->crtcs[j]; + } + } + + drmModeFreeEncoder(enc); + } + + /* cannot find a suitable CRTC */ + return -ENOENT; + } + +Reporting Bugs +============== + +Bugs in this manual should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-memory**\ (7), **drmModeGetResources**\ (3), +**drmModeGetConnector**\ (3), **drmModeGetEncoder**\ (3), +**drmModeGetCrtc**\ (3), **drmModeSetCrtc**\ (3), **drmModeGetFB**\ (3), +**drmModeAddFB**\ (3), **drmModeAddFB2**\ (3), **drmModeRmFB**\ (3), +**drmModePageFlip**\ (3), **drmModeGetPlaneResources**\ (3), +**drmModeGetPlane**\ (3), **drmModeSetPlane**\ (3), **drmModeSetCursor**\ (3), +**drmModeMoveCursor**\ (3), **drmSetMaster**\ (3), **drmAvailable**\ (3), +**drmCheckModesettingSupported**\ (3), **drmOpen**\ (3) diff --git a/lib/libdrm/man/drm-memory.7.rst b/lib/libdrm/man/drm-memory.7.rst new file mode 100644 index 000000000..c272c9948 --- /dev/null +++ b/lib/libdrm/man/drm-memory.7.rst @@ -0,0 +1,322 @@ +========== +drm-memory +========== + +--------------------- +DRM Memory Management +--------------------- + +:Date: September 2012 +:Manual section: 7 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include <xf86drm.h>`` + +Description +=========== + +Many modern high-end GPUs come with their own memory managers. They even +include several different caches that need to be synchronized during access. +Textures, framebuffers, command buffers and more need to be stored in memory +that can be accessed quickly by the GPU. Therefore, memory management on GPUs +is highly driver- and hardware-dependent. + +However, there are several frameworks in the kernel that are used by more than +one driver. These can be used for trivial mode-setting without requiring +driver-dependent code. But for hardware-accelerated rendering you need to read +the manual pages for the driver you want to work with. + +Dumb-Buffers +------------ + +Almost all in-kernel DRM hardware drivers support an API called *Dumb-Buffers*. +This API allows to create buffers of arbitrary size that can be used for +scanout. These buffers can be memory mapped via **mmap**\ (2) so you can render +into them on the CPU. However, GPU access to these buffers is often not +possible. Therefore, they are fine for simple tasks but not suitable for +complex compositions and renderings. + +The ``DRM_IOCTL_MODE_CREATE_DUMB`` ioctl can be used to create a dumb buffer. +The kernel will return a 32-bit handle that can be used to manage the buffer +with the DRM API. You can create framebuffers with **drmModeAddFB**\ (3) and +use it for mode-setting and scanout. To access the buffer, you first need to +retrieve the offset of the buffer. The ``DRM_IOCTL_MODE_MAP_DUMB`` ioctl +requests the DRM subsystem to prepare the buffer for memory-mapping and returns +a fake-offset that can be used with **mmap**\ (2). + +The ``DRM_IOCTL_MODE_CREATE_DUMB`` ioctl takes as argument a structure of type +``struct drm_mode_create_dumb``: + +:: + + struct drm_mode_create_dumb { + __u32 height; + __u32 width; + __u32 bpp; + __u32 flags; + + __u32 handle; + __u32 pitch; + __u64 size; + }; + +The fields *height*, *width*, *bpp* and *flags* have to be provided by the +caller. The other fields are filled by the kernel with the return values. +*height* and *width* are the dimensions of the rectangular buffer that is +created. *bpp* is the number of bits-per-pixel and must be a multiple of 8. You +most commonly want to pass 32 here. The flags field is currently unused and +must be zeroed. Different flags to modify the behavior may be added in the +future. After calling the ioctl, the handle, pitch and size fields are filled +by the kernel. *handle* is a 32-bit gem handle that identifies the buffer. This +is used by several other calls that take a gem-handle or memory-buffer as +argument. The *pitch* field is the pitch (or stride) of the new buffer. Most +drivers use 32-bit or 64-bit aligned stride-values. The size field contains the +absolute size in bytes of the buffer. This can normally also be computed with +``(height * pitch + width) * bpp / 4``. + +To prepare the buffer for **mmap**\ (2) you need to use the +``DRM_IOCTL_MODE_MAP_DUMB`` ioctl. It takes as argument a structure of type +``struct drm_mode_map_dumb``: + +:: + + struct drm_mode_map_dumb { + __u32 handle; + __u32 pad; + + __u64 offset; + }; + +You need to put the gem-handle that was previously retrieved via +``DRM_IOCTL_MODE_CREATE_DUMB`` into the *handle* field. The *pad* field is +unused padding and must be zeroed. After completion, the *offset* field will +contain an offset that can be used with **mmap**\ (2) on the DRM +file-descriptor. + +If you don't need your dumb-buffer, anymore, you have to destroy it with +``DRM_IOCTL_MODE_DESTROY_DUMB``. If you close the DRM file-descriptor, all open +dumb-buffers are automatically destroyed. This ioctl takes as argument a +structure of type ``struct drm_mode_destroy_dumb``: + +:: + + struct drm_mode_destroy_dumb { + __u32 handle; + }; + +You only need to put your handle into the *handle* field. After this call, the +handle is invalid and may be reused for new buffers by the dumb-API. + +TTM +--- + +*TTM* stands for *Translation Table Manager* and is a generic memory-manager +provided by the kernel. It does not provide a common user-space API so you need +to look at each driver interface if you want to use it. See for instance the +radeon man pages for more information on memory-management with radeon and TTM. + +GEM +--- + +*GEM* stands for *Graphics Execution Manager* and is a generic DRM +memory-management framework in the kernel, that is used by many different +drivers. GEM is designed to manage graphics memory, control access to the +graphics device execution context and handle essentially NUMA environment +unique to modern graphics hardware. GEM allows multiple applications to share +graphics device resources without the need to constantly reload the entire +graphics card. Data may be shared between multiple applications with gem +ensuring that the correct memory synchronization occurs. + +GEM provides simple mechanisms to manage graphics data and control execution +flow within the linux DRM subsystem. However, GEM is not a complete framework +that is fully driver independent. Instead, if provides many functions that are +shared between many drivers, but each driver has to implement most of +memory-management with driver-dependent ioctls. This manpage tries to describe +the semantics (and if it applies, the syntax) that is shared between all +drivers that use GEM. + +All GEM APIs are defined as **ioctl**\ (2) on the DRM file descriptor. An +application must be authorized via **drmAuthMagic**\ (3) to the current +DRM-Master to access the GEM subsystem. A driver that does not support GEM will +return ``ENODEV`` for all these ioctls. Invalid object handles return +``EINVAL`` and invalid object names return ``ENOENT``. + +Gem provides explicit memory management primitives. System pages are allocated +when the object is created, either as the fundamental storage for hardware +where system memory is used by the graphics processor directly, or as backing +store for graphics-processor resident memory. + +Objects are referenced from user-space using handles. These are, for all +intents and purposes, equivalent to file descriptors but avoid the overhead. +Newer kernel drivers also support the **drm-prime** (7) infrastructure which +can return real file-descriptor for GEM-handles using the linux DMA-BUF API. +Objects may be published with a name so that other applications and processes +can access them. The name remains valid as long as the object exists. +GEM-objects are reference counted in the kernel. The object is only destroyed +when all handles from user-space were closed. + +GEM-buffers cannot be created with a generic API. Each driver provides its own +API to create GEM-buffers. See for example ``DRM_I915_GEM_CREATE``, +``DRM_NOUVEAU_GEM_NEW`` or ``DRM_RADEON_GEM_CREATE``. Each of these ioctls +returns a GEM-handle that can be passed to different generic ioctls. The +*libgbm* library from the *mesa3D* distribution tries to provide a +driver-independent API to create GBM buffers and retrieve a GBM-handle to them. +It allows to create buffers for different use-cases including scanout, +rendering, cursors and CPU-access. See the libgbm library for more information +or look at the driver-dependent man-pages (for example **drm-intel**\ (7) or +**drm-radeon**\ (7)). + +GEM-buffers can be closed with the ``DRM_IOCTL_GEM_CLOSE`` ioctl. It takes as +argument a structure of type ``struct drm_gem_close``: + +:: + + struct drm_gem_close { + __u32 handle; + __u32 pad; + }; + +The *handle* field is the GEM-handle to be closed. The *pad* field is unused +padding. It must be zeroed. After this call the GEM handle cannot be used by +this process anymore and may be reused for new GEM objects by the GEM API. + +If you want to share GEM-objects between different processes, you can create a +name for them and pass this name to other processes which can then open this +GEM-object. Names are currently 32-bit integer IDs and have no special +protection. That is, if you put a name on your GEM-object, every other client +that has access to the DRM device and is authenticated via +**drmAuthMagic**\ (3) to the current DRM-Master, can *guess* the name and open +or access the GEM-object. If you want more fine-grained access control, you can +use the new **drm-prime**\ (7) API to retrieve file-descriptors for +GEM-handles. To create a name for a GEM-handle, you use the +``DRM_IOCTL_GEM_FLINK`` ioctl. It takes as argument a structure of type +``struct drm_gem_flink``: + +:: + + struct drm_gem_flink { + __u32 handle; + __u32 name; + }; + +You have to put your handle into the *handle* field. After completion, the +kernel has put the new unique name into the name field. You can now pass +this name to other processes which can then import the name with the +``DRM_IOCTL_GEM_OPEN`` ioctl. It takes as argument a structure of type +``struct drm_gem_open``: + +:: + + struct drm_gem_open { + __u32 name; + + __u32 handle; + __u32 size; + }; + +You have to fill in the *name* field with the name of the GEM-object that you +want to open. The kernel will fill in the *handle* and *size* fields with the +new handle and size of the GEM-object. You can now access the GEM-object via +the handle as if you created it with the GEM API. + +Besides generic buffer management, the GEM API does not provide any generic +access. Each driver implements its own functionality on top of this API. This +includes execution-buffers, GTT management, context creation, CPU access, GPU +I/O and more. The next higher-level API is *OpenGL*. So if you want to use more +GPU features, you should use the *mesa3D* library to create OpenGL contexts on +DRM devices. This does *not* require any windowing-system like X11, but can +also be done on raw DRM devices. However, this is beyond the scope of this +man-page. You may have a look at other mesa3D man pages, including libgbm and +libEGL. 2D software-rendering (rendering with the CPU) can be achieved with the +dumb-buffer-API in a driver-independent fashion, however, for +hardware-accelerated 2D or 3D rendering you must use OpenGL. Any other API that +tries to abstract the driver-internals to access GEM-execution-buffers and +other GPU internals, would simply reinvent OpenGL so it is not provided. But if +you need more detailed information for a specific driver, you may have a look +into the driver-manpages, including **drm-intel**\ (7), **drm-radeon**\ (7) and +**drm-nouveau**\ (7). However, the **drm-prime**\ (7) infrastructure and the +generic GEM API as described here allow display-managers to handle +graphics-buffers and render-clients without any deeper knowledge of the GPU +that is used. Moreover, it allows to move objects between GPUs and implement +complex display-servers that don't do any rendering on their own. See its +man-page for more information. + +Examples +======== + +This section includes examples for basic memory-management tasks. + +Dumb-Buffers +------------ + +This examples shows how to create a dumb-buffer via the generic DRM API. +This is driver-independent (as long as the driver supports dumb-buffers) +and provides memory-mapped buffers that can be used for scanout. This +example creates a full-HD 1920x1080 buffer with 32 bits-per-pixel and a +color-depth of 24 bits. The buffer is then bound to a framebuffer which +can be used for scanout with the KMS API (see **drm-kms**\ (7)). + +:: + + struct drm_mode_create_dumb creq; + struct drm_mode_destroy_dumb dreq; + struct drm_mode_map_dumb mreq; + uint32_t fb; + int ret; + void *map; + + /* create dumb buffer */ + memset(&creq, 0, sizeof(creq)); + creq.width = 1920; + creq.height = 1080; + creq.bpp = 32; + ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); + if (ret < 0) { + /* buffer creation failed; see "errno" for more error codes */ + ... + } + /* creq.pitch, creq.handle and creq.size are filled by this ioctl with + * the requested values and can be used now. */ + + /* create framebuffer object for the dumb-buffer */ + ret = drmModeAddFB(fd, 1920, 1080, 24, 32, creq.pitch, creq.handle, &fb); + if (ret) { + /* frame buffer creation failed; see "errno" */ + ... + } + /* the framebuffer "fb" can now used for scanout with KMS */ + + /* prepare buffer for memory mapping */ + memset(&mreq, 0, sizeof(mreq)); + mreq.handle = creq.handle; + ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); + if (ret) { + /* DRM buffer preparation failed; see "errno" */ + ... + } + /* mreq.offset now contains the new offset that can be used with mmap() */ + + /* perform actual memory mapping */ + map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); + if (map == MAP_FAILED) { + /* memory-mapping failed; see "errno" */ + ... + } + + /* clear the framebuffer to 0 */ + memset(map, 0, creq.size); + +Reporting Bugs +============== + +Bugs in this manual should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-kms**\ (7), **drm-prime**\ (7), **drmAvailable**\ (3), +**drmOpen**\ (3), **drm-intel**\ (7), **drm-radeon**\ (7), **drm-nouveau**\ (7) diff --git a/lib/libdrm/man/drm.7.rst b/lib/libdrm/man/drm.7.rst new file mode 100644 index 000000000..c9b5696ff --- /dev/null +++ b/lib/libdrm/man/drm.7.rst @@ -0,0 +1,91 @@ +=== +drm +=== + +------------------------ +Direct Rendering Manager +------------------------ + +:Date: September 2012 +:Manual section: 7 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include <xf86drm.h>`` + +Description +=========== + +The *Direct Rendering Manager* (DRM) is a framework to manage *Graphics +Processing Units* (GPUs). It is designed to support the needs of complex +graphics devices, usually containing programmable pipelines well suited +to 3D graphics acceleration. Furthermore, it is responsible for memory +management, interrupt handling and DMA to provide a uniform interface to +applications. + +In earlier days, the kernel framework was solely used to provide raw +hardware access to privileged user-space processes which implement all +the hardware abstraction layers. But more and more tasks were moved into +the kernel. All these interfaces are based on **ioctl**\ (2) commands on +the DRM character device. The *libdrm* library provides wrappers for these +system-calls and many helpers to simplify the API. + +When a GPU is detected, the DRM system loads a driver for the detected +hardware type. Each connected GPU is then presented to user-space via a +character-device that is usually available as ``/dev/dri/card0`` and can +be accessed with **open**\ (2) and **close**\ (2). However, it still +depends on the graphics driver which interfaces are available on these +devices. If an interface is not available, the syscalls will fail with +``EINVAL``. + +Authentication +-------------- + +All DRM devices provide authentication mechanisms. Only a DRM master is +allowed to perform mode-setting or modify core state and only one user +can be DRM master at a time. See **drmSetMaster**\ (3) for information +on how to become DRM master and what the limitations are. Other DRM users +can be authenticated to the DRM-Master via **drmAuthMagic**\ (3) so they +can perform buffer allocations and rendering. + +Mode-Setting +------------ + +Managing connected monitors and displays and changing the current modes +is called *Mode-Setting*. This is restricted to the current DRM master. +Historically, this was implemented in user-space, but new DRM drivers +implement a kernel interface to perform mode-setting called *Kernel Mode +Setting* (KMS). If your hardware-driver supports it, you can use the KMS +API provided by DRM. This includes allocating framebuffers, selecting +modes and managing CRTCs and encoders. See **drm-kms**\ (7) for more. + +Memory Management +----------------- + +The most sophisticated tasks for GPUs today is managing memory objects. +Textures, framebuffers, command-buffers and all other kinds of commands +for the GPU have to be stored in memory. The DRM driver takes care of +managing all memory objects, flushing caches, synchronizing access and +providing CPU access to GPU memory. All memory management is hardware +driver dependent. However, two generic frameworks are available that are +used by most DRM drivers. These are the *Translation Table Manager* +(TTM) and the *Graphics Execution Manager* (GEM). They provide generic +APIs to create, destroy and access buffers from user-space. However, +there are still many differences between the drivers so driver-depedent +code is still needed. Many helpers are provided in *libgbm* (Graphics +Buffer Manager) from the *Mesa* project. For more information on DRM +memory management, see **drm-memory**\ (7). + +Reporting Bugs +============== + +Bugs in this manual should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues. + +See Also +======== + +**drm-kms**\ (7), **drm-memory**\ (7), **drmSetMaster**\ (3), +**drmAuthMagic**\ (3), **drmAvailable**\ (3), **drmOpen**\ (3) diff --git a/lib/libdrm/man/drmAvailable.3.rst b/lib/libdrm/man/drmAvailable.3.rst new file mode 100644 index 000000000..5da77bebf --- /dev/null +++ b/lib/libdrm/man/drmAvailable.3.rst @@ -0,0 +1,41 @@ +============ +drmAvailable +============ + +----------------------------------------------------- +determine whether a DRM kernel driver has been loaded +----------------------------------------------------- + +:Date: September 2012 +:Manual section: 3 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include <xf86drm.h>`` + +``int drmAvailable(void);`` + +Description +=========== + +``drmAvailable`` allows the caller to determine whether a kernel DRM +driver is loaded. + +Return Value +============ + +``drmAvailable`` returns 1 if a DRM driver is currently loaded. +Otherwise 0 is returned. + +Reporting Bugs +============== + +Bugs in this function should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drmOpen**\ (3) diff --git a/lib/libdrm/man/drmHandleEvent.3.rst b/lib/libdrm/man/drmHandleEvent.3.rst new file mode 100644 index 000000000..ecc63ed09 --- /dev/null +++ b/lib/libdrm/man/drmHandleEvent.3.rst @@ -0,0 +1,62 @@ +============== +drmHandleEvent +============== + +----------------------------------- +read and process pending DRM events +----------------------------------- + +:Date: September 2012 +:Manual section: 3 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include <xf86drm.h>`` + +``int drmHandleEvent(int fd, drmEventContextPtr evctx);`` + +Description +=========== + +``drmHandleEvent`` processes outstanding DRM events on the DRM +file-descriptor passed as ``fd``. This function should be called after +the DRM file-descriptor has polled readable; it will read the events and +use the passed-in ``evctx`` structure to call function pointers with the +parameters noted below: + +:: + + typedef struct _drmEventContext { + int version; + void (*vblank_handler) (int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data) + void (*page_flip_handler) (int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data) + } drmEventContext, *drmEventContextPtr; + +Return Value +============ + +``drmHandleEvent`` returns 0 on success, or if there is no data to +read from the file-descriptor. Returns -1 if the read on the +file-descriptor fails or returns less than a full event record. + +Reporting Bugs +============== + +Bugs in this function should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-kms**\ (7), **drmModePageFlip**\ (3), +**drmWaitVBlank**\ (3) diff --git a/lib/libdrm/man/drmModeGetResources.3.rst b/lib/libdrm/man/drmModeGetResources.3.rst new file mode 100644 index 000000000..d1358d224 --- /dev/null +++ b/lib/libdrm/man/drmModeGetResources.3.rst @@ -0,0 +1,92 @@ +=================== +drmModeGetResources +=================== + +-------------------------------------------------- +retrieve current display configuration information +-------------------------------------------------- + +:Date: September 2012 +:Manual section: 3 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include <xf86drm.h>`` + +``#include <xf86drmMode.h>`` + +``drmModeResPtr drmModeGetResources(int fd);`` + +Description +=========== + +``drmModeGetResources`` allocates, populates, and returns a drmModeRes +structure containing information about the current display +configuration. The structure contains the following fields: + +:: + + typedef struct _drmModeRes { + int count_fbs; + uint32_t *fbs; + + int count_crtcs; + uint32_t *crtcs; + + int count_connectors; + uint32_t *connectors; + + int count_encoders; + uint32_t *encoders; + + uint32_t min_width, max_width; + uint32_t min_height, max_height; + } drmModeRes, *drmModeResPtr; + +The *count_fbs* and *fbs* fields indicate the number of currently allocated +framebuffer objects (i.e., objects that can be attached to a given CRTC +or sprite for display). + +The *count_crtcs* and *crtcs* fields list the available CRTCs in the +configuration. A CRTC is simply an object that can scan out a +framebuffer to a display sink, and contains mode timing and relative +position information. CRTCs drive encoders, which are responsible for +converting the pixel stream into a specific display protocol (e.g., MIPI +or HDMI). + +The *count_connectors* and *connectors* fields list the available physical +connectors on the system. Note that some of these may not be exposed +from the chassis (e.g., LVDS or eDP). Connectors are attached to +encoders and contain information about the attached display sink (e.g., +width and height in mm, subpixel ordering, and various other +properties). + +The *count_encoders* and *encoders* fields list the available encoders on +the device. Each encoder may be associated with a CRTC, and may be used +to drive a particular encoder. + +The *min_\** and *max_\** fields indicate the maximum size of a framebuffer +for this device (i.e., the scanout size limit). + +Return Value +============ + +``drmModeGetResources`` returns a drmModeRes structure pointer on +success, NULL on failure. The returned structure must be freed with +**drmModeFreeResources**\ (3). + +Reporting Bugs +============== + +Bugs in this function should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-kms**\ (7), **drmModeGetFB**\ (3), **drmModeAddFB**\ (3), +**drmModeAddFB2**\ (3), **drmModeRmFB**\ (3), **drmModeDirtyFB**\ (3), +**drmModeGetCrtc**\ (3), **drmModeSetCrtc** (3), **drmModeGetEncoder** (3), +**drmModeGetConnector**\ (3) diff --git a/lib/libdrm/man/meson.build b/lib/libdrm/man/meson.build index 45eaeda0f..92a4c375f 100644 --- a/lib/libdrm/man/meson.build +++ b/lib/libdrm/man/meson.build @@ -18,50 +18,23 @@ # 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, +rst_pages = [ + ['drm', '7'], + ['drm-kms', '7'], + ['drm-memory', '7'], + ['drmAvailable', '3'], + ['drmHandleEvent', '3'], + ['drmModeGetResources', '3'], ] - -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, - ) +foreach page : rst_pages + name = page[0] + '.' + page[1] + rst = files(name + '.rst') custom_target( - '@0@.7'.format(x), - input : gen, - output : '@0@.7'.format(x, '7'), - command : [prog_xslt, '-o', '@OUTPUT@', xsltproc_args, '@INPUT@'], + name, + input : rst, + output : name, + command : [prog_rst2man, '@INPUT@', '@OUTPUT@'], install : true, - install_dir : join_paths(get_option('mandir'), 'man7'), - build_by_default : true, + install_dir : join_paths(get_option('mandir'), 'man' + page[1]), ) endforeach diff --git a/lib/libdrm/meson.build b/lib/libdrm/meson.build index fc02f5527..a4d8d7074 100644 --- a/lib/libdrm/meson.build +++ b/lib/libdrm/meson.build @@ -21,7 +21,7 @@ project( 'libdrm', ['c'], - version : '2.4.100', + version : '2.4.104', license : 'MIT', meson_version : '>= 0.43', default_options : ['buildtype=debugoptimized', 'c_std=gnu99'], @@ -44,14 +44,18 @@ dep_threads = dependency('threads') cc = meson.get_compiler('c') +symbols_check = find_program('symbols-check.py') +prog_nm = find_program('nm') + # Check for atomics intel_atomics = false lib_atomics = false dep_atomic_ops = dependency('atomic_ops', required : false) -if cc.compiles(''' +if cc.links(''' 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); } + int main() { } ''', name : 'Intel Atomics') intel_atomics = true @@ -179,13 +183,23 @@ else dep_rt = [] endif dep_m = cc.find_library('m', required : false) -# From Niclas Zeising: -# FreeBSD requires sys/types.h for sys/sysctl.h, add it as part of the -# includes when checking for headers. -foreach header : ['sys/sysctl.h', 'sys/select.h', 'alloca.h'] - config.set('HAVE_' + header.underscorify().to_upper(), - cc.compiles('#include <sys/types.h>\n#include <@0@>'.format(header), name : '@0@ works'.format(header))) + +# The header is not required on Linux, and is in fact deprecated in glibc 2.30+ +if ['linux'].contains(host_machine.system()) + config.set10('HAVE_SYS_SYSCTL_H', false) +else + # From Niclas Zeising: + # FreeBSD requires sys/types.h for sys/sysctl.h, so add it as part of + # the includes when checking for headers. + config.set10('HAVE_SYS_SYSCTL_H', + cc.compiles('#include <sys/types.h>\n#include <sys/sysctl.h>', name : 'sys/sysctl.h works')) +endif + +foreach header : ['sys/select.h', 'alloca.h'] + config.set10('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') and cc.has_header_symbol('sys/sysmacros.h', 'minor') and cc.has_header_symbol('sys/sysmacros.h', 'makedev')) @@ -235,7 +249,11 @@ else endif _valgrind = get_option('valgrind') if _valgrind != 'false' - dep_valgrind = dependency('valgrind', required : _valgrind == 'true') + if with_freedreno + dep_valgrind = dependency('valgrind', required : _valgrind == 'true', version : '>=3.10.0') + else + dep_valgrind = dependency('valgrind', required : _valgrind == 'true') + endif with_valgrind = dep_valgrind.found() else dep_valgrind = [] @@ -243,18 +261,8 @@ else 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() +prog_rst2man = find_program('rst2man', required: with_man_pages == 'true') +with_man_pages = with_man_pages != 'false' and prog_rst2man.found() config.set10('HAVE_VISIBILITY', cc.compiles('''int foo_hidden(void) __attribute__((visibility(("hidden"))));''', @@ -281,7 +289,7 @@ config_file = configure_file( configuration : config, output : 'config.h', ) -add_project_arguments('-include', 'config.h', language : 'c') +add_project_arguments('-include', '@0@'.format(config_file), language : 'c') inc_root = include_directories('.') inc_drm = include_directories('include/drm') @@ -301,6 +309,16 @@ libdrm = shared_library( install : true, ) +test( + 'core-symbols-check', + symbols_check, + args : [ + '--lib', libdrm, + '--symbols-file', files('core-symbols.txt'), + '--nm', prog_nm.path(), + ], +) + ext_libdrm = declare_dependency( link_with : libdrm, include_directories : [inc_root, inc_drm], @@ -331,9 +349,6 @@ pkg.generate( description : 'Userspace interface to kernel DRM services', ) -env_test = environment() -env_test.set('NM', find_program('nm').path()) - if with_libkms subdir('libkms') endif diff --git a/lib/libdrm/nouveau/meson.build b/lib/libdrm/nouveau/meson.build index 56e952ca5..9bd58fca5 100644 --- a/lib/libdrm/nouveau/meson.build +++ b/lib/libdrm/nouveau/meson.build @@ -52,8 +52,11 @@ pkg.generate( ) test( - 'nouveau-symbol-check', - find_program('nouveau-symbol-check'), - env : env_test, - args : libdrm_nouveau, + 'nouveau-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_nouveau, + '--symbols-file', files('nouveau-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/nouveau/nouveau-symbols.txt b/lib/libdrm/nouveau/nouveau-symbols.txt new file mode 100644 index 000000000..ef8032f29 --- /dev/null +++ b/lib/libdrm/nouveau/nouveau-symbols.txt @@ -0,0 +1,41 @@ +nouveau_bo_map +nouveau_bo_name_get +nouveau_bo_name_ref +nouveau_bo_new +nouveau_bo_prime_handle_ref +nouveau_bo_ref +nouveau_bo_set_prime +nouveau_bo_wait +nouveau_bo_wrap +nouveau_bufctx_del +nouveau_bufctx_mthd +nouveau_bufctx_new +nouveau_bufctx_refn +nouveau_bufctx_reset +nouveau_client_del +nouveau_client_new +nouveau_device_del +nouveau_device_new +nouveau_device_open +nouveau_device_open_existing +nouveau_device_wrap +nouveau_drm_del +nouveau_drm_new +nouveau_getparam +nouveau_object_del +nouveau_object_mclass +nouveau_object_mthd +nouveau_object_new +nouveau_object_sclass_get +nouveau_object_sclass_put +nouveau_pushbuf_bufctx +nouveau_pushbuf_data +nouveau_pushbuf_del +nouveau_pushbuf_kick +nouveau_pushbuf_new +nouveau_pushbuf_refd +nouveau_pushbuf_refn +nouveau_pushbuf_reloc +nouveau_pushbuf_space +nouveau_pushbuf_validate +nouveau_setparam diff --git a/lib/libdrm/omap/Android.mk b/lib/libdrm/omap/Android.mk new file mode 100644 index 000000000..b25cca13c --- /dev/null +++ b/lib/libdrm/omap/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libdrm_omap +LOCAL_VENDOR_MODULE := true + +LOCAL_SRC_FILES := omap_drm.c + +LOCAL_SHARED_LIBRARIES := libdrm + +include $(LIBDRM_COMMON_MK) + +include $(BUILD_SHARED_LIBRARY) diff --git a/lib/libdrm/omap/meson.build b/lib/libdrm/omap/meson.build index f3ea36dbf..53330b61b 100644 --- a/lib/libdrm/omap/meson.build +++ b/lib/libdrm/omap/meson.build @@ -47,8 +47,11 @@ pkg.generate( ) test( - 'omap-symbol-check', - find_program('omap-symbol-check'), - env : env_test, - args : libdrm_omap, + 'omap-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_omap, + '--symbols-file', files('omap-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/omap/omap-symbols.txt b/lib/libdrm/omap/omap-symbols.txt new file mode 100644 index 000000000..749d0f7cf --- /dev/null +++ b/lib/libdrm/omap/omap-symbols.txt @@ -0,0 +1,18 @@ +omap_bo_cpu_fini +omap_bo_cpu_prep +omap_bo_del +omap_bo_dmabuf +omap_bo_from_dmabuf +omap_bo_from_name +omap_bo_get_name +omap_bo_handle +omap_bo_map +omap_bo_new +omap_bo_new_tiled +omap_bo_ref +omap_bo_size +omap_device_del +omap_device_new +omap_device_ref +omap_get_param +omap_set_param diff --git a/lib/libdrm/radeon/meson.build b/lib/libdrm/radeon/meson.build index 662b5bcef..ca128329c 100644 --- a/lib/libdrm/radeon/meson.build +++ b/lib/libdrm/radeon/meson.build @@ -57,8 +57,11 @@ pkg.generate( ) test( - 'radeon-symbol-check', - find_program('radeon-symbol-check'), - env : env_test, - args : libdrm_radeon, + 'radeon-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_radeon, + '--symbols-file', files('radeon-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/radeon/radeon-symbols.txt b/lib/libdrm/radeon/radeon-symbols.txt new file mode 100644 index 000000000..5a532d830 --- /dev/null +++ b/lib/libdrm/radeon/radeon-symbols.txt @@ -0,0 +1,44 @@ +radeon_bo_debug +radeon_bo_get_handle +radeon_bo_get_src_domain +radeon_bo_get_tiling +radeon_bo_is_busy +radeon_bo_is_referenced_by_cs +radeon_bo_is_static +radeon_bo_manager_gem_ctor +radeon_bo_manager_gem_dtor +radeon_bo_map +radeon_bo_open +radeon_bo_ref +radeon_bo_set_tiling +radeon_bo_unmap +radeon_bo_unref +radeon_bo_wait +radeon_cs_begin +radeon_cs_create +radeon_cs_destroy +radeon_cs_emit +radeon_cs_end +radeon_cs_erase +radeon_cs_get_id +radeon_cs_manager_gem_ctor +radeon_cs_manager_gem_dtor +radeon_cs_need_flush +radeon_cs_print +radeon_cs_set_limit +radeon_cs_space_add_persistent_bo +radeon_cs_space_check +radeon_cs_space_check_with_bo +radeon_cs_space_reset_bos +radeon_cs_space_set_flush +radeon_cs_write_reloc +radeon_gem_bo_open_prime +radeon_gem_get_kernel_name +radeon_gem_get_reloc_in_cs +radeon_gem_name_bo +radeon_gem_prime_share_bo +radeon_gem_set_domain +radeon_surface_best +radeon_surface_init +radeon_surface_manager_free +radeon_surface_manager_new diff --git a/lib/libdrm/symbols-check.py b/lib/libdrm/symbols-check.py new file mode 100644 index 000000000..2e7ba68d1 --- /dev/null +++ b/lib/libdrm/symbols-check.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +import argparse +import os +import platform +import subprocess + +# This list contains symbols that _might_ be exported for some platforms +PLATFORM_SYMBOLS = [ + '__bss_end__', + '__bss_start__', + '__bss_start', + '__end__', + '_bss_end__', + '_edata', + '_end', + '_fini', + '_init', +] + + +def get_symbols(nm, lib): + ''' + List all the (non platform-specific) symbols exported by the library + ''' + symbols = [] + platform_name = platform.system() + output = subprocess.check_output([nm, '-gP', lib], + stderr=open(os.devnull, 'w')).decode("ascii") + for line in output.splitlines(): + fields = line.split() + if len(fields) == 2 or fields[1] == 'U': + continue + symbol_name = fields[0] + if platform_name == 'Linux': + if symbol_name in PLATFORM_SYMBOLS: + continue + elif platform_name == 'Darwin': + assert symbol_name[0] == '_' + symbol_name = symbol_name[1:] + symbols.append(symbol_name) + + return symbols + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--symbols-file', + action='store', + required=True, + help='path to file containing symbols') + parser.add_argument('--lib', + action='store', + required=True, + help='path to library') + parser.add_argument('--nm', + action='store', + required=True, + help='path to binary (or name in $PATH)') + args = parser.parse_args() + + try: + lib_symbols = get_symbols(args.nm, args.lib) + except: + # We can't run this test, but we haven't technically failed it either + # Return the GNU "skip" error code + exit(77) + mandatory_symbols = [] + optional_symbols = [] + with open(args.symbols_file) as symbols_file: + qualifier_optional = '(optional)' + for line in symbols_file.readlines(): + + # Strip comments + line = line.split('#')[0] + line = line.strip() + if not line: + continue + + # Line format: + # [qualifier] symbol + qualifier = None + symbol = None + + fields = line.split() + if len(fields) == 1: + symbol = fields[0] + elif len(fields) == 2: + qualifier = fields[0] + symbol = fields[1] + else: + print(args.symbols_file + ': invalid format: ' + line) + exit(1) + + # The only supported qualifier is 'optional', which means the + # symbol doesn't have to be exported by the library + if qualifier and not qualifier == qualifier_optional: + print(args.symbols_file + ': invalid qualifier: ' + qualifier) + exit(1) + + if qualifier == qualifier_optional: + optional_symbols.append(symbol) + else: + mandatory_symbols.append(symbol) + + unknown_symbols = [] + for symbol in lib_symbols: + if symbol in mandatory_symbols: + continue + if symbol in optional_symbols: + continue + unknown_symbols.append(symbol) + + missing_symbols = [ + sym for sym in mandatory_symbols if sym not in lib_symbols + ] + + for symbol in unknown_symbols: + print(args.lib + ': unknown symbol exported: ' + symbol) + + for symbol in missing_symbols: + print(args.lib + ': missing symbol: ' + symbol) + + if unknown_symbols or missing_symbols: + exit(1) + exit(0) + + +if __name__ == '__main__': + main() diff --git a/lib/libdrm/tegra/.gitignore b/lib/libdrm/tegra/.gitignore new file mode 100644 index 000000000..74cfe47a2 --- /dev/null +++ b/lib/libdrm/tegra/.gitignore @@ -0,0 +1 @@ +libdrm_tegra.pc diff --git a/lib/libdrm/tegra/meson.build b/lib/libdrm/tegra/meson.build index ce56ddcfc..88613b9cd 100644 --- a/lib/libdrm/tegra/meson.build +++ b/lib/libdrm/tegra/meson.build @@ -46,8 +46,11 @@ pkg.generate( ) test( - 'tegra-symbol-check', - find_program('tegra-symbol-check'), - env : env_test, - args : libdrm_tegra, + 'tegra-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_tegra, + '--symbols-file', files('tegra-symbols.txt'), + '--nm', prog_nm.path(), + ], ) diff --git a/lib/libdrm/tegra/tegra-symbols.txt b/lib/libdrm/tegra/tegra-symbols.txt new file mode 100644 index 000000000..5e3e955f2 --- /dev/null +++ b/lib/libdrm/tegra/tegra-symbols.txt @@ -0,0 +1,13 @@ +drm_tegra_bo_get_flags +drm_tegra_bo_get_handle +drm_tegra_bo_get_tiling +drm_tegra_bo_map +drm_tegra_bo_new +drm_tegra_bo_ref +drm_tegra_bo_set_flags +drm_tegra_bo_set_tiling +drm_tegra_bo_unmap +drm_tegra_bo_unref +drm_tegra_bo_wrap +drm_tegra_close +drm_tegra_new diff --git a/lib/libdrm/tests/Android.mk b/lib/libdrm/tests/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/lib/libdrm/tests/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/lib/libdrm/tests/amdgpu/amdgpu_test.c b/lib/libdrm/tests/amdgpu/amdgpu_test.c index 5aadd7e64..8c867678b 100644 --- a/lib/libdrm/tests/amdgpu/amdgpu_test.c +++ b/lib/libdrm/tests/amdgpu/amdgpu_test.c @@ -58,6 +58,7 @@ #define VM_TESTS_STR "VM Tests" #define RAS_TESTS_STR "RAS Tests" #define SYNCOBJ_TIMELINE_TESTS_STR "SYNCOBJ TIMELINE Tests" +#define SECURITY_TESTS_STR "Security Tests" /** * Open handles for amdgpu devices @@ -130,6 +131,12 @@ static CU_SuiteInfo suites[] = { .pCleanupFunc = suite_syncobj_timeline_tests_clean, .pTests = syncobj_timeline_tests, }, + { + .pName = SECURITY_TESTS_STR, + .pInitFunc = suite_security_tests_init, + .pCleanupFunc = suite_security_tests_clean, + .pTests = security_tests, + }, CU_SUITE_INFO_NULL, }; @@ -149,7 +156,7 @@ static CU_BOOL always_active() static Suites_Active_Status suites_active_stat[] = { { .pName = BASIC_TESTS_STR, - .pActive = always_active, + .pActive = suite_basic_tests_enable, }, { .pName = BO_TESTS_STR, @@ -187,6 +194,10 @@ static Suites_Active_Status suites_active_stat[] = { .pName = SYNCOBJ_TIMELINE_TESTS_STR, .pActive = suite_syncobj_timeline_tests_enable, }, + { + .pName = SECURITY_TESTS_STR, + .pActive = suite_security_tests_enable, + }, }; @@ -202,44 +213,42 @@ static void display_test_suites(void) CU_pSuite pSuite = NULL; CU_pTest pTest = NULL; - printf("Suites\n"); + printf("%5s: %2s: %8s: %s\n", "What", "ID", "Status", "Name"); for (iSuite = 0; suites[iSuite].pName != NULL; iSuite++) { pSuite = CU_get_suite_by_index((unsigned int) iSuite + 1, - CU_get_registry()); + 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"); - + printf("Suite: %2d: %8s: %s\n", + iSuite + 1, + pSuite->fActive ? "ENABLED" : "DISABLED", + suites[iSuite].pName); + if (!pSuite->fActive) + continue; for (iTest = 0; suites[iSuite].pTests[iTest].pName != NULL; - iTest++) { - + iTest++) { pTest = CU_get_test_by_index((unsigned int) iTest + 1, - pSuite); - + 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"); + printf(" Test: %2d: %8s: %s\n", + iTest + 1, + pSuite->fActive && pTest->fActive ? "ENABLED" : "DISABLED", + suites[iSuite].pTests[iTest].pName); } } } - /** Help string for command line parameters */ static const char usage[] = "Usage: %s [-hlpr] [<-s <suite id>> [-t <test id>] [-f]] " @@ -452,6 +461,41 @@ static void amdgpu_disable_suites() "sdma ring block test (set amdgpu.lockup_timeout=50)", CU_FALSE)) fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring bad dispatch test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "compute ring bad dispatch test (set amdgpu.lockup_timeout=50,50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring bad slow dispatch test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "compute ring bad slow dispatch test (set amdgpu.lockup_timeout=50,50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring bad draw test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring slow bad draw 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()); diff --git a/lib/libdrm/tests/amdgpu/amdgpu_test.h b/lib/libdrm/tests/amdgpu/amdgpu_test.h index 36675ea3f..98cec6989 100644 --- a/lib/libdrm/tests/amdgpu/amdgpu_test.h +++ b/lib/libdrm/tests/amdgpu/amdgpu_test.h @@ -55,6 +55,11 @@ int suite_basic_tests_init(); int suite_basic_tests_clean(); /** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_basic_tests_enable(void); + +/** * Tests in basic test suite */ extern CU_TestInfo basic_tests[]; @@ -236,6 +241,37 @@ CU_BOOL suite_syncobj_timeline_tests_enable(void); */ extern CU_TestInfo syncobj_timeline_tests[]; +void amdgpu_dispatch_hang_helper(amdgpu_device_handle device_handle, uint32_t ip_type); +void amdgpu_dispatch_hang_slow_helper(amdgpu_device_handle device_handle, uint32_t ip_type); +void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t ring, + int hang); +void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint32_t ring); + +/** + * Initialize security test suite + */ +int suite_security_tests_init(); + +/** + * Deinitialize security test suite + */ +int suite_security_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_security_tests_enable(void); + +/** + * Tests in security test suite + */ +extern CU_TestInfo security_tests[]; + +extern void +amdgpu_command_submission_write_linear_helper_with_secure(amdgpu_device_handle + device, + unsigned ip_type, + bool secure); /** * Helper functions @@ -413,4 +449,26 @@ static inline CU_ErrorCode amdgpu_set_test_active(const char *suite_name, return r; } +static inline bool asic_is_arcturus(uint32_t asic_id) +{ + switch(asic_id) { + /* Arcturus asic DID */ + case 0x738C: + case 0x7388: + case 0x738E: + return true; + default: + return false; + } +} + +void amdgpu_test_exec_cs_helper_raw(amdgpu_device_handle device_handle, + 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, + bool secure); + #endif /* #ifdef _AMDGPU_TEST_H_ */ diff --git a/lib/libdrm/tests/amdgpu/basic_tests.c b/lib/libdrm/tests/amdgpu/basic_tests.c index ab2a6728a..dc9ed947d 100644 --- a/lib/libdrm/tests/amdgpu/basic_tests.c +++ b/lib/libdrm/tests/amdgpu/basic_tests.c @@ -30,7 +30,7 @@ #endif #include <sys/stat.h> #include <fcntl.h> -#ifdef HAVE_ALLOCA_H +#if HAVE_ALLOCA_H # include <alloca.h> #endif #include <sys/wait.h> @@ -39,6 +39,7 @@ #include "amdgpu_test.h" #include "amdgpu_drm.h" +#include "amdgpu_internal.h" #include "util_math.h" static amdgpu_device_handle device_handle; @@ -69,7 +70,7 @@ static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, 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 }, { "Userptr Test", amdgpu_userptr_test }, @@ -86,7 +87,7 @@ CU_TestInfo basic_tests[] = { { "GPU reset Test", amdgpu_gpu_reset_test }, CU_TEST_INFO_NULL, }; -#define BUFFER_SIZE (8 * 1024) +#define BUFFER_SIZE (MAX2(8 * 1024, getpagesize())) #define SDMA_PKT_HEADER_op_offset 0 #define SDMA_PKT_HEADER_op_mask 0x000000FF #define SDMA_PKT_HEADER_op_shift 0 @@ -106,6 +107,20 @@ CU_TestInfo basic_tests[] = { #define SDMA_OPCODE_COPY 1 # define SDMA_COPY_SUB_OPCODE_LINEAR 0 +#define SDMA_OPCODE_ATOMIC 10 +# define SDMA_ATOMIC_LOOP(x) ((x) << 0) + /* 0 - single_pass_atomic. + * 1 - loop_until_compare_satisfied. + */ +# define SDMA_ATOMIC_TMZ(x) ((x) << 2) + /* 0 - non-TMZ. + * 1 - TMZ. + */ +# define SDMA_ATOMIC_OPCODE(x) ((x) << 9) + /* TC_OP_ATOMIC_CMPSWAP_RTN_32 0x00000008 + * same as Packet 3 + */ + #define GFX_COMPUTE_NOP 0xffff1000 #define SDMA_NOP 0x0 @@ -157,6 +172,20 @@ CU_TestInfo basic_tests[] = { * 2 - ce */ +#define PACKET3_ATOMIC_MEM 0x1E +#define TC_OP_ATOMIC_CMPSWAP_RTN_32 0x00000008 +#define ATOMIC_MEM_COMMAND(x) ((x) << 8) + /* 0 - single_pass_atomic. + * 1 - loop_until_compare_satisfied. + */ +#define ATOMIC_MEM_CACHEPOLICAY(x) ((x) << 25) + /* 0 - lru. + * 1 - stream. + */ +#define ATOMIC_MEM_ENGINESEL(x) ((x) << 30) + /* 0 - micro_engine. + */ + #define PACKET3_DMA_DATA 0x50 /* 1. header * 2. CONTROL @@ -306,7 +335,9 @@ static uint32_t shader_bin[] = { enum cs_type { CS_BUFFERCLEAR, - CS_BUFFERCOPY + CS_BUFFERCOPY, + CS_HANG, + CS_HANG_SLOW }; static const uint32_t bufferclear_cs_shader_gfx9[] = { @@ -355,7 +386,9 @@ static const uint32_t preamblecache_gfx9[] = { enum ps_type { PS_CONST, - PS_TEX + PS_TEX, + PS_HANG, + PS_HANG_SLOW }; static const uint32_t ps_const_shader_gfx9[] = { @@ -461,13 +494,67 @@ static const uint32_t cached_cmd_gfx9[] = { 0xc0016900, 0x0, 0x0, 0xc0026900, 0x3, 0x2a, 0x0, 0xc0046900, 0xa, 0x0, 0x0, 0x0, 0x200020, 0xc0016900, 0x83, 0xffff, 0xc0026900, 0x8e, 0xf, 0xf, - 0xc0056900, 0x105, 0x0, 0x0, 0x0, 0x0, 0x1a, + 0xc0056900, 0x105, 0x0, 0x0, 0x0, 0x0, 0x12, 0xc0026900, 0x10b, 0x0, 0x0, 0xc0016900, 0x1e0, 0x0, 0xc0036900, 0x200, 0x0, 0x10000, 0xcc0011, 0xc0026900, 0x292, 0x20, 0x60201b8, 0xc0026900, 0x2b0, 0x0, 0x0, 0xc0016900, 0x2f8, 0x0 }; +unsigned int memcpy_ps_hang[] = { + 0xFFFFFFFF, 0xBEFE0A7E, 0xBEFC0304, 0xC0C20100, + 0xC0800300, 0xC8080000, 0xC80C0100, 0xC8090001, + 0xC80D0101, 0xBF8C007F, 0xF0800F00, 0x00010002, + 0xBEFE040C, 0xBF8C0F70, 0xBF800000, 0xBF800000, + 0xF800180F, 0x03020100, 0xBF810000 +}; + +struct amdgpu_test_shader { + uint32_t *shader; + uint32_t header_length; + uint32_t body_length; + uint32_t foot_length; +}; + +unsigned int memcpy_cs_hang_slow_ai_codes[] = { + 0xd1fd0000, 0x04010c08, 0xe00c2000, 0x80000100, + 0xbf8c0f70, 0xe01c2000, 0x80010100, 0xbf810000 +}; + +struct amdgpu_test_shader memcpy_cs_hang_slow_ai = { + memcpy_cs_hang_slow_ai_codes, + 4, + 3, + 1 +}; + +unsigned int memcpy_cs_hang_slow_rv_codes[] = { + 0x8e00860c, 0x32000000, 0xe00c2000, 0x80010100, + 0xbf8c0f70, 0xe01c2000, 0x80020100, 0xbf810000 +}; + +struct amdgpu_test_shader memcpy_cs_hang_slow_rv = { + memcpy_cs_hang_slow_rv_codes, + 4, + 3, + 1 +}; + +unsigned int memcpy_ps_hang_slow_ai_codes[] = { + 0xbefc000c, 0xbe8e017e, 0xbefe077e, 0xd4080000, + 0xd4090001, 0xd40c0100, 0xd40d0101, 0xf0800f00, + 0x00400002, 0xbefe010e, 0xbf8c0f70, 0xbf800000, + 0xbf800000, 0xbf800000, 0xbf800000, 0xc400180f, + 0x03020100, 0xbf810000 +}; + +struct amdgpu_test_shader memcpy_ps_hang_slow_ai = { + memcpy_ps_hang_slow_ai_codes, + 7, + 2, + 9 +}; + 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, @@ -528,6 +615,43 @@ int amdgpu_bo_alloc_and_map_raw(amdgpu_device_handle dev, unsigned size, +CU_BOOL suite_basic_tests_enable(void) +{ + uint32_t asic_id; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + asic_id = device_handle->info.asic_id; + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + /* disable gfx engine basic test cases for Arturus due to no CPG */ + if (asic_is_arcturus(asic_id)) { + if (amdgpu_set_test_active("Basic Tests", + "Command submission Test (GFX)", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + + if (amdgpu_set_test_active("Basic Tests", + "Command submission Test (Multi-Fence)", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + + if (amdgpu_set_test_active("Basic Tests", + "Sync dependency Test", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + } + + return CU_TRUE; +} + int suite_basic_tests_init(void) { struct amdgpu_gpu_info gpu_info = {0}; @@ -1174,12 +1298,15 @@ static void amdgpu_command_submission_compute(void) * pm4_src, resources, ib_info, and ibs_request * submit command stream described in ibs_request and wait for this IB accomplished */ -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) +void +amdgpu_test_exec_cs_helper_raw(amdgpu_device_handle device_handle, + 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, + bool secure) { int r; uint32_t expired; @@ -1211,6 +1338,8 @@ static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, ib_info->ib_mc_address = ib_result_mc_address; ib_info->size = pm4_dw; + if (secure) + ib_info->flags |= AMDGPU_IB_FLAGS_SECURE; ibs_request->ip_type = ip_type; ibs_request->ring = instance; @@ -1252,7 +1381,24 @@ static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, CU_ASSERT_EQUAL(r, 0); } -static void amdgpu_command_submission_write_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) +{ + amdgpu_test_exec_cs_helper_raw(device_handle, context_handle, + ip_type, instance, pm4_dw, pm4_src, + res_cnt, resources, ib_info, + ibs_request, false); +} + +void +amdgpu_command_submission_write_linear_helper_with_secure(amdgpu_device_handle + device, unsigned + ip_type, bool secure) { const int sdma_write_length = 128; const int pm4_dw = 256; @@ -1264,6 +1410,7 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) struct amdgpu_cs_request *ibs_request; uint64_t bo_mc; volatile uint32_t *bo_cpu; + uint32_t bo_cpu_origin; int i, j, r, loop, ring_id; uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC}; amdgpu_va_handle va_handle; @@ -1278,10 +1425,14 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) 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); + r = amdgpu_query_hw_ip_info(device, ip_type, 0, &hw_ip_info); CU_ASSERT_EQUAL(r, 0); - r = amdgpu_cs_ctx_create(device_handle, &context_handle); + for (i = 0; secure && (i < 2); i++) + gtt_flags[i] |= AMDGPU_GEM_CREATE_ENCRYPTED; + + r = amdgpu_cs_ctx_create(device, &context_handle); + CU_ASSERT_EQUAL(r, 0); /* prepare resource */ @@ -1292,7 +1443,7 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) loop = 0; while(loop < 2) { /* allocate UC bo for sDMA use */ - r = amdgpu_bo_alloc_and_map(device_handle, + r = amdgpu_bo_alloc_and_map(device, sdma_write_length * sizeof(uint32_t), 4096, AMDGPU_GEM_DOMAIN_GTT, gtt_flags[loop], &bo, (void**)&bo_cpu, @@ -1312,8 +1463,9 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) sdma_write_length); else pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE, - SDMA_WRITE_SUB_OPCODE_LINEAR, 0); - pm4[i++] = 0xffffffff & bo_mc; + SDMA_WRITE_SUB_OPCODE_LINEAR, + secure ? SDMA_ATOMIC_TMZ(1) : 0); + pm4[i++] = 0xfffffffc & bo_mc; pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; if (family_id >= AMDGPU_FAMILY_AI) pm4[i++] = sdma_write_length - 1; @@ -1331,16 +1483,99 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) pm4[i++] = 0xdeadbeaf; } - amdgpu_test_exec_cs_helper(context_handle, - ip_type, ring_id, - i, pm4, - 1, resources, - ib_info, ibs_request); + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, secure); /* verify if SDMA test result meets with expected */ i = 0; - while(i < sdma_write_length) { - CU_ASSERT_EQUAL(bo_cpu[i++], 0xdeadbeaf); + if (!secure) { + while(i < sdma_write_length) { + CU_ASSERT_EQUAL(bo_cpu[i++], 0xdeadbeaf); + } + } else if (ip_type == AMDGPU_HW_IP_GFX) { + memset((void*)pm4, 0, pm4_dw * sizeof(uint32_t)); + pm4[i++] = PACKET3(PACKET3_ATOMIC_MEM, 7); + /* atomic opcode for 32b w/ RTN and ATOMIC_SWAPCMP_RTN + * command, 1-loop_until_compare_satisfied. + * single_pass_atomic, 0-lru + * engine_sel, 0-micro_engine + */ + pm4[i++] = (TC_OP_ATOMIC_CMPSWAP_RTN_32 | + ATOMIC_MEM_COMMAND(1) | + ATOMIC_MEM_CACHEPOLICAY(0) | + ATOMIC_MEM_ENGINESEL(0)); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = 0x12345678; + pm4[i++] = 0x0; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = 0x0; + pm4[i++] = 0x100; + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, true); + } else if (ip_type == AMDGPU_HW_IP_DMA) { + /* restore the bo_cpu to compare */ + bo_cpu_origin = bo_cpu[0]; + memset((void*)pm4, 0, pm4_dw * sizeof(uint32_t)); + /* atomic opcode for 32b w/ RTN and ATOMIC_SWAPCMP_RTN + * loop, 1-loop_until_compare_satisfied. + * single_pass_atomic, 0-lru + */ + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_ATOMIC, + 0, + SDMA_ATOMIC_LOOP(1) | + SDMA_ATOMIC_TMZ(1) | + SDMA_ATOMIC_OPCODE(TC_OP_ATOMIC_CMPSWAP_RTN_32)); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = 0x12345678; + pm4[i++] = 0x0; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = 0x0; + pm4[i++] = 0x100; + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, true); + /* DMA's atomic behavir is unlike GFX + * If the comparing data is not equal to destination data, + * For GFX, loop again till gfx timeout(system hang). + * For DMA, loop again till timer expired and then send interrupt. + * So testcase can't use interrupt mechanism. + * We take another way to verify. When the comparing data is not + * equal to destination data, overwrite the source data to the destination + * buffer. Otherwise, original destination data unchanged. + * So if the bo_cpu data is overwritten, the result is passed. + */ + CU_ASSERT_NOT_EQUAL(bo_cpu[0], bo_cpu_origin); + + /* compare again for the case of dest_data != cmp_data */ + i = 0; + /* restore again, here dest_data should be */ + bo_cpu_origin = bo_cpu[0]; + memset((void*)pm4, 0, pm4_dw * sizeof(uint32_t)); + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_ATOMIC, + 0, + SDMA_ATOMIC_LOOP(1) | + SDMA_ATOMIC_TMZ(1) | + SDMA_ATOMIC_OPCODE(TC_OP_ATOMIC_CMPSWAP_RTN_32)); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = 0x87654321; + pm4[i++] = 0x0; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = 0x0; + pm4[i++] = 0x100; + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, true); + /* here bo_cpu[0] should be unchanged, still is 0x12345678, otherwise failed*/ + CU_ASSERT_EQUAL(bo_cpu[0], bo_cpu_origin); } r = amdgpu_bo_unmap_and_free(bo, va_handle, bo_mc, @@ -1360,6 +1595,13 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) CU_ASSERT_EQUAL(r, 0); } +static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) +{ + amdgpu_command_submission_write_linear_helper_with_secure(device_handle, + ip_type, + false); +} + static void amdgpu_command_submission_sdma_write_linear(void) { amdgpu_command_submission_write_linear_helper(AMDGPU_HW_IP_DMA); @@ -2065,6 +2307,37 @@ static void amdgpu_sync_dependency_test(void) free(ibs_request.dependencies); } +static int amdgpu_dispatch_load_cs_shader_hang_slow(uint32_t *ptr, int family) +{ + struct amdgpu_test_shader *shader; + int i, loop = 0x10000; + + switch (family) { + case AMDGPU_FAMILY_AI: + shader = &memcpy_cs_hang_slow_ai; + break; + case AMDGPU_FAMILY_RV: + shader = &memcpy_cs_hang_slow_rv; + break; + default: + return -1; + break; + } + + memcpy(ptr, shader->shader, shader->header_length * sizeof(uint32_t)); + + for (i = 0; i < loop; i++) + memcpy(ptr + shader->header_length + shader->body_length * i, + shader->shader + shader->header_length, + shader->body_length * sizeof(uint32_t)); + + memcpy(ptr + shader->header_length + shader->body_length * loop, + shader->shader + shader->header_length + shader->body_length, + shader->foot_length * sizeof(uint32_t)); + + return 0; +} + static int amdgpu_dispatch_load_cs_shader(uint8_t *ptr, int cs_type) { @@ -2080,6 +2353,10 @@ static int amdgpu_dispatch_load_cs_shader(uint8_t *ptr, shader = buffercopy_cs_shader_gfx9; shader_size = sizeof(buffercopy_cs_shader_gfx9); break; + case CS_HANG: + shader = memcpy_ps_hang; + shader_size = sizeof(memcpy_ps_hang); + break; default: return -1; break; @@ -2300,7 +2577,8 @@ static void amdgpu_memset_dispatch_test(amdgpu_device_handle device_handle, static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, uint32_t ip_type, - uint32_t ring) + uint32_t ring, + int hang) { amdgpu_context_handle context_handle; amdgpu_bo_handle bo_src, bo_dst, bo_shader, bo_cmd, resources[4]; @@ -2316,7 +2594,8 @@ static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, int bo_cmd_size = 4096; struct amdgpu_cs_request ibs_request = {0}; struct amdgpu_cs_ib_info ib_info= {0}; - uint32_t expired; + uint32_t expired, hang_state, hangs; + enum cs_type cs_type; amdgpu_bo_list_handle bo_list; struct amdgpu_cs_fence fence_status = {0}; @@ -2337,7 +2616,8 @@ static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, CU_ASSERT_EQUAL(r, 0); memset(ptr_shader, 0, bo_shader_size); - r = amdgpu_dispatch_load_cs_shader(ptr_shader, CS_BUFFERCOPY ); + cs_type = hang ? CS_HANG : CS_BUFFERCOPY; + r = amdgpu_dispatch_load_cs_shader(ptr_shader, cs_type); CU_ASSERT_EQUAL(r, 0); r = amdgpu_bo_alloc_and_map(device_handle, bo_dst_size, 4096, @@ -2423,14 +2703,21 @@ static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, r = amdgpu_cs_query_fence_status(&fence_status, AMDGPU_TIMEOUT_INFINITE, 0, &expired); - CU_ASSERT_EQUAL(r, 0); - CU_ASSERT_EQUAL(expired, true); - /* verify if memcpy test result meets with expected */ - i = 0; - while(i < bo_dst_size) { - CU_ASSERT_EQUAL(ptr_dst[i], ptr_src[i]); - i++; + if (!hang) { + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + /* verify if memcpy test result meets with expected */ + i = 0; + while(i < bo_dst_size) { + CU_ASSERT_EQUAL(ptr_dst[i], ptr_src[i]); + i++; + } + } else { + r = amdgpu_cs_query_reset_state(context_handle, &hang_state, &hangs); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(hang_state, AMDGPU_CTX_UNKNOWN_RESET); } r = amdgpu_bo_list_destroy(bo_list); @@ -2464,7 +2751,7 @@ static void amdgpu_compute_dispatch_test(void) for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { amdgpu_memset_dispatch_test(device_handle, AMDGPU_HW_IP_COMPUTE, ring_id); - amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_COMPUTE, ring_id); + amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_COMPUTE, ring_id, 0); } } @@ -2481,10 +2768,226 @@ static void amdgpu_gfx_dispatch_test(void) for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { amdgpu_memset_dispatch_test(device_handle, AMDGPU_HW_IP_GFX, ring_id); - amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_GFX, ring_id); + amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_GFX, ring_id, 0); + } +} + +void amdgpu_dispatch_hang_helper(amdgpu_device_handle device_handle, uint32_t ip_type) +{ + int r; + struct drm_amdgpu_info_hw_ip info; + uint32_t ring_id; + + r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &info); + CU_ASSERT_EQUAL(r, 0); + if (!info.available_rings) + printf("SKIP ... as there's no ring for ip %d\n", ip_type); + + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 1); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); + } +} + +static void amdgpu_memcpy_dispatch_hang_slow_test(amdgpu_device_handle device_handle, + uint32_t ip_type, uint32_t ring) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle bo_src, bo_dst, bo_shader, bo_cmd, resources[4]; + volatile unsigned char *ptr_dst; + void *ptr_shader; + unsigned char *ptr_src; + uint32_t *ptr_cmd; + uint64_t mc_address_src, mc_address_dst, mc_address_shader, mc_address_cmd; + amdgpu_va_handle va_src, va_dst, va_shader, va_cmd; + int i, r; + int bo_dst_size = 0x4000000; + int bo_shader_size = 0x400000; + int bo_cmd_size = 4096; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info= {0}; + uint32_t hang_state, hangs, expired; + struct amdgpu_gpu_info gpu_info = {0}; + amdgpu_bo_list_handle bo_list; + struct amdgpu_cs_fence fence_status = {0}; + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + 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(device_handle, bo_cmd_size, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &bo_cmd, (void **)&ptr_cmd, + &mc_address_cmd, &va_cmd); + CU_ASSERT_EQUAL(r, 0); + memset(ptr_cmd, 0, bo_cmd_size); + + r = amdgpu_bo_alloc_and_map(device_handle, bo_shader_size, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, + &bo_shader, &ptr_shader, + &mc_address_shader, &va_shader); + CU_ASSERT_EQUAL(r, 0); + memset(ptr_shader, 0, bo_shader_size); + + r = amdgpu_dispatch_load_cs_shader_hang_slow(ptr_shader, gpu_info.family_id); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, bo_dst_size, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, + &bo_src, (void **)&ptr_src, + &mc_address_src, &va_src); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, bo_dst_size, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, + &bo_dst, (void **)&ptr_dst, + &mc_address_dst, &va_dst); + CU_ASSERT_EQUAL(r, 0); + + memset(ptr_src, 0x55, bo_dst_size); + + i = 0; + i += amdgpu_dispatch_init(ptr_cmd + i, ip_type); + + /* Issue commands to set cu mask used in current dispatch */ + i += amdgpu_dispatch_write_cumask(ptr_cmd + i); + + /* Writes shader state to HW */ + i += amdgpu_dispatch_write2hw(ptr_cmd + i, mc_address_shader); + + /* Write constant data */ + /* Writes the texture resource constants data to the SGPRs */ + ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 4); + ptr_cmd[i++] = 0x240; + ptr_cmd[i++] = mc_address_src; + ptr_cmd[i++] = (mc_address_src >> 32) | 0x100000; + ptr_cmd[i++] = 0x400000; + ptr_cmd[i++] = 0x74fac; + + /* Writes the UAV constant data to the SGPRs. */ + ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 4); + ptr_cmd[i++] = 0x244; + ptr_cmd[i++] = mc_address_dst; + ptr_cmd[i++] = (mc_address_dst >> 32) | 0x100000; + ptr_cmd[i++] = 0x400000; + ptr_cmd[i++] = 0x74fac; + + /* clear mmCOMPUTE_RESOURCE_LIMITS */ + ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 1); + ptr_cmd[i++] = 0x215; + ptr_cmd[i++] = 0; + + /* dispatch direct command */ + ptr_cmd[i++] = PACKET3_COMPUTE(PACKET3_DISPATCH_DIRECT, 3); + ptr_cmd[i++] = 0x10000; + ptr_cmd[i++] = 1; + ptr_cmd[i++] = 1; + ptr_cmd[i++] = 1; + + while (i & 7) + ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ + + resources[0] = bo_shader; + resources[1] = bo_src; + resources[2] = bo_dst; + resources[3] = bo_cmd; + r = amdgpu_bo_list_create(device_handle, 4, resources, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ib_info.ib_mc_address = mc_address_cmd; + ib_info.size = i; + ibs_request.ip_type = ip_type; + ibs_request.ring = ring; + ibs_request.resources = bo_list; + 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); + CU_ASSERT_EQUAL(r, 0); + + fence_status.ip_type = ip_type; + fence_status.ip_instance = 0; + fence_status.ring = ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request.seq_no; + + /* wait for IB accomplished */ + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + + r = amdgpu_cs_query_reset_state(context_handle, &hang_state, &hangs); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(hang_state, AMDGPU_CTX_UNKNOWN_RESET); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo_src, va_src, mc_address_src, bo_dst_size); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_unmap_and_free(bo_dst, va_dst, mc_address_dst, bo_dst_size); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo_cmd, va_cmd, mc_address_cmd, bo_cmd_size); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo_shader, va_shader, mc_address_shader, bo_shader_size); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +void amdgpu_dispatch_hang_slow_helper(amdgpu_device_handle device_handle, uint32_t ip_type) +{ + int r; + struct drm_amdgpu_info_hw_ip info; + uint32_t ring_id; + + r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &info); + CU_ASSERT_EQUAL(r, 0); + if (!info.available_rings) + printf("SKIP ... as there's no ring for ip %d\n", ip_type); + + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); + amdgpu_memcpy_dispatch_hang_slow_test(device_handle, ip_type, ring_id); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); } } +static int amdgpu_draw_load_ps_shader_hang_slow(uint32_t *ptr, int family) +{ + struct amdgpu_test_shader *shader; + int i, loop = 0x40000; + + switch (family) { + case AMDGPU_FAMILY_AI: + case AMDGPU_FAMILY_RV: + shader = &memcpy_ps_hang_slow_ai; + break; + default: + return -1; + break; + } + + memcpy(ptr, shader->shader, shader->header_length * sizeof(uint32_t)); + + for (i = 0; i < loop; i++) + memcpy(ptr + shader->header_length + shader->body_length * i, + shader->shader + shader->header_length, + shader->body_length * sizeof(uint32_t)); + + memcpy(ptr + shader->header_length + shader->body_length * loop, + shader->shader + shader->header_length + shader->body_length, + shader->foot_length * sizeof(uint32_t)); + + return 0; +} + static int amdgpu_draw_load_ps_shader(uint8_t *ptr, int ps_type) { int i; @@ -2510,6 +3013,12 @@ static int amdgpu_draw_load_ps_shader(uint8_t *ptr, int ps_type) patchinfo_code_size = ps_tex_shader_patchinfo_code_size_gfx9; patchcode_offset = ps_tex_shader_patchinfo_offset_gfx9; break; + case PS_HANG: + shader = memcpy_ps_hang; + shader_size = sizeof(memcpy_ps_hang); + + memcpy(ptr, shader, shader_size); + return 0; default: return -1; break; @@ -2566,7 +3075,8 @@ static int amdgpu_draw_init(uint32_t *ptr) } static int amdgpu_draw_setup_and_write_drawblt_surf_info(uint32_t *ptr, - uint64_t dst_addr) + uint64_t dst_addr, + int hang_slow) { int i = 0; @@ -2591,7 +3101,7 @@ static int amdgpu_draw_setup_and_write_drawblt_surf_info(uint32_t *ptr, ptr[i++] = 0x318; ptr[i++] = dst_addr >> 8; ptr[i++] = dst_addr >> 40; - ptr[i++] = 0x7c01f; + ptr[i++] = hang_slow ? 0x1ffc7ff : 0x7c01f; ptr[i++] = 0; ptr[i++] = 0x50438; ptr[i++] = 0x10140000; @@ -2600,7 +3110,7 @@ static int amdgpu_draw_setup_and_write_drawblt_surf_info(uint32_t *ptr, /* mmCB_MRT0_EPITCH */ ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); ptr[i++] = 0x1e8; - ptr[i++] = 0x1f; + ptr[i++] = hang_slow ? 0x7ff : 0x1f; /* 0xA32B CB_COLOR1_BASE */ ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); @@ -2626,7 +3136,7 @@ static int amdgpu_draw_setup_and_write_drawblt_surf_info(uint32_t *ptr, return i; } -static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr) +static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr, int hang_slow) { int i = 0; const uint32_t *cached_cmd_ptr; @@ -2658,6 +3168,8 @@ static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr) cached_cmd_size = sizeof(cached_cmd_gfx9); memcpy(ptr + i, cached_cmd_ptr, cached_cmd_size); + if (hang_slow) + *(ptr + i + 12) = 0x8000800; i += cached_cmd_size/sizeof(uint32_t); return i; @@ -2665,7 +3177,8 @@ static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr) static int amdgpu_draw_vs_RectPosTexFast_write2hw(uint32_t *ptr, int ps_type, - uint64_t shader_addr) + uint64_t shader_addr, + int hang_slow) { int i = 0; @@ -2707,8 +3220,8 @@ static int amdgpu_draw_vs_RectPosTexFast_write2hw(uint32_t *ptr, ptr[i++] = PACKET3(PKT3_SET_SH_REG, 4); ptr[i++] = 0x4c; i += 2; - ptr[i++] = 0x42000000; - ptr[i++] = 0x42000000; + ptr[i++] = hang_slow ? 0x45000000 : 0x42000000; + ptr[i++] = hang_slow ? 0x45000000 : 0x42000000; ptr[i++] = PACKET3(PKT3_SET_SH_REG, 4); ptr[i++] = 0x50; @@ -2845,11 +3358,11 @@ void amdgpu_memset_draw(amdgpu_device_handle device_handle, i = 0; i += amdgpu_draw_init(ptr_cmd + i); - i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst); + i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, 0); - i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i); + i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, 0); - i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_CONST, mc_address_shader_vs); + i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_CONST, mc_address_shader_vs, 0); i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_CONST, mc_address_shader_ps); @@ -2869,7 +3382,7 @@ void amdgpu_memset_draw(amdgpu_device_handle device_handle, resources[1] = bo_shader_ps; resources[2] = bo_shader_vs; resources[3] = bo_cmd; - r = amdgpu_bo_list_create(device_handle, 3, resources, NULL, &bo_list); + r = amdgpu_bo_list_create(device_handle, 4, resources, NULL, &bo_list); CU_ASSERT_EQUAL(r, 0); ib_info.ib_mc_address = mc_address_cmd; @@ -2963,7 +3476,7 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, amdgpu_bo_handle bo_shader_vs, uint64_t mc_address_shader_ps, uint64_t mc_address_shader_vs, - uint32_t ring) + uint32_t ring, int hang) { amdgpu_context_handle context_handle; amdgpu_bo_handle bo_dst, bo_src, bo_cmd, resources[5]; @@ -2977,7 +3490,8 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, int bo_cmd_size = 4096; struct amdgpu_cs_request ibs_request = {0}; struct amdgpu_cs_ib_info ib_info= {0}; - uint32_t hang_state, hangs, expired; + uint32_t hang_state, hangs; + uint32_t expired; amdgpu_bo_list_handle bo_list; struct amdgpu_cs_fence fence_status = {0}; @@ -3008,11 +3522,11 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, i = 0; i += amdgpu_draw_init(ptr_cmd + i); - i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst); + i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, 0); - i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i); + i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, 0); - i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_vs); + i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_vs, 0); i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_ps); @@ -3068,14 +3582,20 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, r = amdgpu_cs_query_fence_status(&fence_status, AMDGPU_TIMEOUT_INFINITE, 0, &expired); - CU_ASSERT_EQUAL(r, 0); - CU_ASSERT_EQUAL(expired, true); + if (!hang) { + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); - /* verify if memcpy test result meets with expected */ - i = 0; - while(i < bo_size) { - CU_ASSERT_EQUAL(ptr_dst[i], ptr_src[i]); - i++; + /* verify if memcpy test result meets with expected */ + i = 0; + while(i < bo_size) { + CU_ASSERT_EQUAL(ptr_dst[i], ptr_src[i]); + i++; + } + } else { + r = amdgpu_cs_query_reset_state(context_handle, &hang_state, &hangs); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(hang_state, AMDGPU_CTX_UNKNOWN_RESET); } r = amdgpu_bo_list_destroy(bo_list); @@ -3093,7 +3613,8 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, CU_ASSERT_EQUAL(r, 0); } -static void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t ring) +void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t ring, + int hang) { amdgpu_bo_handle bo_shader_ps, bo_shader_vs; void *ptr_shader_ps; @@ -3101,6 +3622,7 @@ static void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t uint64_t mc_address_shader_ps, mc_address_shader_vs; amdgpu_va_handle va_shader_ps, va_shader_vs; int bo_shader_size = 4096; + enum ps_type ps_type = hang ? PS_HANG : PS_TEX; int r; r = amdgpu_bo_alloc_and_map(device_handle, bo_shader_size, 4096, @@ -3117,14 +3639,14 @@ static void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t CU_ASSERT_EQUAL(r, 0); memset(ptr_shader_vs, 0, bo_shader_size); - r = amdgpu_draw_load_ps_shader(ptr_shader_ps, PS_TEX); + r = amdgpu_draw_load_ps_shader(ptr_shader_ps, ps_type); CU_ASSERT_EQUAL(r, 0); r = amdgpu_draw_load_vs_shader(ptr_shader_vs); CU_ASSERT_EQUAL(r, 0); amdgpu_memcpy_draw(device_handle, bo_shader_ps, bo_shader_vs, - mc_address_shader_ps, mc_address_shader_vs, ring); + mc_address_shader_ps, mc_address_shader_vs, ring, hang); r = amdgpu_bo_unmap_and_free(bo_shader_ps, va_shader_ps, mc_address_shader_ps, bo_shader_size); CU_ASSERT_EQUAL(r, 0); @@ -3146,10 +3668,172 @@ static void amdgpu_draw_test(void) for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { amdgpu_memset_draw_test(device_handle, ring_id); - amdgpu_memcpy_draw_test(device_handle, ring_id); + amdgpu_memcpy_draw_test(device_handle, ring_id, 0); } } +void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint32_t ring) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle bo_shader_ps, bo_shader_vs; + amdgpu_bo_handle bo_dst, bo_src, bo_cmd, resources[5]; + void *ptr_shader_ps; + void *ptr_shader_vs; + volatile unsigned char *ptr_dst; + unsigned char *ptr_src; + uint32_t *ptr_cmd; + uint64_t mc_address_dst, mc_address_src, mc_address_cmd; + uint64_t mc_address_shader_ps, mc_address_shader_vs; + amdgpu_va_handle va_shader_ps, va_shader_vs; + amdgpu_va_handle va_dst, va_src, va_cmd; + struct amdgpu_gpu_info gpu_info = {0}; + int i, r; + int bo_size = 0x4000000; + int bo_shader_ps_size = 0x400000; + int bo_shader_vs_size = 4096; + int bo_cmd_size = 4096; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info= {0}; + uint32_t hang_state, hangs, expired; + amdgpu_bo_list_handle bo_list; + struct amdgpu_cs_fence fence_status = {0}; + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + 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(device_handle, bo_cmd_size, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &bo_cmd, (void **)&ptr_cmd, + &mc_address_cmd, &va_cmd); + CU_ASSERT_EQUAL(r, 0); + memset(ptr_cmd, 0, bo_cmd_size); + + r = amdgpu_bo_alloc_and_map(device_handle, bo_shader_ps_size, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, + &bo_shader_ps, &ptr_shader_ps, + &mc_address_shader_ps, &va_shader_ps); + CU_ASSERT_EQUAL(r, 0); + memset(ptr_shader_ps, 0, bo_shader_ps_size); + + r = amdgpu_bo_alloc_and_map(device_handle, bo_shader_vs_size, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, + &bo_shader_vs, &ptr_shader_vs, + &mc_address_shader_vs, &va_shader_vs); + CU_ASSERT_EQUAL(r, 0); + memset(ptr_shader_vs, 0, bo_shader_vs_size); + + r = amdgpu_draw_load_ps_shader_hang_slow(ptr_shader_ps, gpu_info.family_id); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_draw_load_vs_shader(ptr_shader_vs); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, bo_size, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, + &bo_src, (void **)&ptr_src, + &mc_address_src, &va_src); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, bo_size, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, + &bo_dst, (void **)&ptr_dst, + &mc_address_dst, &va_dst); + CU_ASSERT_EQUAL(r, 0); + + memset(ptr_src, 0x55, bo_size); + + i = 0; + i += amdgpu_draw_init(ptr_cmd + i); + + i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, 1); + + i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, 1); + + i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_TEX, + mc_address_shader_vs, 1); + + i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_ps); + + ptr_cmd[i++] = PACKET3(PKT3_SET_SH_REG, 8); + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = mc_address_src >> 8; + ptr_cmd[i++] = mc_address_src >> 40 | 0x10e00000; + ptr_cmd[i++] = 0x1ffc7ff; + ptr_cmd[i++] = 0x90500fac; + ptr_cmd[i++] = 0xffe000; + i += 3; + + ptr_cmd[i++] = PACKET3(PKT3_SET_SH_REG, 4); + ptr_cmd[i++] = 0x14; + ptr_cmd[i++] = 0x92; + i += 3; + + ptr_cmd[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr_cmd[i++] = 0x191; + ptr_cmd[i++] = 0; + + i += amdgpu_draw_draw(ptr_cmd + i); + + while (i & 7) + ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ + + resources[0] = bo_dst; + resources[1] = bo_src; + resources[2] = bo_shader_ps; + resources[3] = bo_shader_vs; + resources[4] = bo_cmd; + r = amdgpu_bo_list_create(device_handle, 5, resources, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ib_info.ib_mc_address = mc_address_cmd; + ib_info.size = i; + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ring = ring; + ibs_request.resources = bo_list; + 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); + CU_ASSERT_EQUAL(r, 0); + + fence_status.ip_type = AMDGPU_HW_IP_GFX; + fence_status.ip_instance = 0; + fence_status.ring = ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request.seq_no; + + /* wait for IB accomplished */ + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + + r = amdgpu_cs_query_reset_state(context_handle, &hang_state, &hangs); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(hang_state, AMDGPU_CTX_UNKNOWN_RESET); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo_dst, va_dst, mc_address_dst, bo_size); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_unmap_and_free(bo_src, va_src, mc_address_src, bo_size); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo_cmd, va_cmd, mc_address_cmd, bo_cmd_size); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo_shader_ps, va_shader_ps, mc_address_shader_ps, bo_shader_ps_size); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_unmap_and_free(bo_shader_vs, va_shader_vs, mc_address_shader_vs, bo_shader_vs_size); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + static void amdgpu_gpu_reset_test(void) { int r; diff --git a/lib/libdrm/tests/amdgpu/cs_tests.c b/lib/libdrm/tests/amdgpu/cs_tests.c index 7ad0f0dcb..10124c159 100644 --- a/lib/libdrm/tests/amdgpu/cs_tests.c +++ b/lib/libdrm/tests/amdgpu/cs_tests.c @@ -64,17 +64,21 @@ CU_TestInfo cs_tests[] = { CU_BOOL suite_cs_tests_enable(void) { + uint32_t asic_id; + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, &minor_version, &device_handle)) return CU_FALSE; family_id = device_handle->info.family_id; + asic_id = device_handle->info.asic_id; if (amdgpu_device_deinitialize(device_handle)) return CU_FALSE; - if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI) { + if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI || + asic_is_arcturus(asic_id)) { printf("\n\nThe ASIC NOT support UVD, suite disabled\n"); return CU_FALSE; } @@ -358,6 +362,7 @@ static void amdgpu_cs_uvd_decode(void) bs_addr = fb_addr + 4*1024; dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024); + ctx_addr = 0; if (family_id >= AMDGPU_FAMILY_VI) { if ((family_id == AMDGPU_FAMILY_AI) || (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A || diff --git a/lib/libdrm/tests/amdgpu/deadlock_tests.c b/lib/libdrm/tests/amdgpu/deadlock_tests.c index 91368c156..248cc339a 100644 --- a/lib/libdrm/tests/amdgpu/deadlock_tests.c +++ b/lib/libdrm/tests/amdgpu/deadlock_tests.c @@ -24,7 +24,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#ifdef HAVE_ALLOCA_H +#if HAVE_ALLOCA_H # include <alloca.h> #endif @@ -114,10 +114,17 @@ static void amdgpu_deadlock_compute(void); static void amdgpu_illegal_reg_access(); static void amdgpu_illegal_mem_access(); static void amdgpu_deadlock_sdma(void); +static void amdgpu_dispatch_hang_gfx(void); +static void amdgpu_dispatch_hang_compute(void); +static void amdgpu_dispatch_hang_slow_gfx(void); +static void amdgpu_dispatch_hang_slow_compute(void); +static void amdgpu_draw_hang_gfx(void); +static void amdgpu_draw_hang_slow_gfx(void); CU_BOOL suite_deadlock_tests_enable(void) { CU_BOOL enable = CU_TRUE; + uint32_t asic_id; if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, &minor_version, &device_handle)) @@ -134,6 +141,15 @@ CU_BOOL suite_deadlock_tests_enable(void) enable = CU_FALSE; } + asic_id = device_handle->info.asic_id; + if (asic_is_arcturus(asic_id)) { + if (amdgpu_set_test_active("Deadlock Tests", + "gfx ring block test (set amdgpu.lockup_timeout=50)", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + } + if (device_handle->info.family_id >= AMDGPU_FAMILY_AI) use_uc_mtype = 1; @@ -178,6 +194,12 @@ CU_TestInfo deadlock_tests[] = { { "sdma ring block test (set amdgpu.lockup_timeout=50)", amdgpu_deadlock_sdma }, { "illegal reg access test", amdgpu_illegal_reg_access }, { "illegal mem access test (set amdgpu.vm_fault_stop=2)", amdgpu_illegal_mem_access }, + { "gfx ring bad dispatch test (set amdgpu.lockup_timeout=50)", amdgpu_dispatch_hang_gfx }, + { "compute ring bad dispatch test (set amdgpu.lockup_timeout=50,50)", amdgpu_dispatch_hang_compute }, + { "gfx ring bad slow dispatch test (set amdgpu.lockup_timeout=50)", amdgpu_dispatch_hang_slow_gfx }, + { "compute ring bad slow dispatch test (set amdgpu.lockup_timeout=50,50)", amdgpu_dispatch_hang_slow_compute }, + { "gfx ring bad draw test (set amdgpu.lockup_timeout=50)", amdgpu_draw_hang_gfx }, + { "gfx ring slow bad draw test (set amdgpu.lockup_timeout=50)", amdgpu_draw_hang_slow_gfx }, CU_TEST_INFO_NULL, }; @@ -478,3 +500,57 @@ static void amdgpu_illegal_mem_access() { bad_access_helper(0); } + +static void amdgpu_dispatch_hang_gfx(void) +{ + amdgpu_dispatch_hang_helper(device_handle, AMDGPU_HW_IP_GFX); +} + +static void amdgpu_dispatch_hang_compute(void) +{ + amdgpu_dispatch_hang_helper(device_handle, AMDGPU_HW_IP_COMPUTE); +} + +static void amdgpu_dispatch_hang_slow_gfx(void) +{ + amdgpu_dispatch_hang_slow_helper(device_handle, AMDGPU_HW_IP_GFX); +} + +static void amdgpu_dispatch_hang_slow_compute(void) +{ + amdgpu_dispatch_hang_slow_helper(device_handle, AMDGPU_HW_IP_COMPUTE); +} + +static void amdgpu_draw_hang_gfx(void) +{ + int r; + struct drm_amdgpu_info_hw_ip info; + uint32_t ring_id; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); + CU_ASSERT_EQUAL(r, 0); + if (!info.available_rings) + printf("SKIP ... as there's no graphic ring\n"); + + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { + amdgpu_memcpy_draw_test(device_handle, ring_id, 0); + amdgpu_memcpy_draw_test(device_handle, ring_id, 1); + amdgpu_memcpy_draw_test(device_handle, ring_id, 0); + } +} + +static void amdgpu_draw_hang_slow_gfx(void) +{ + struct drm_amdgpu_info_hw_ip info; + uint32_t ring_id; + int r; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); + CU_ASSERT_EQUAL(r, 0); + + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { + amdgpu_memcpy_draw_test(device_handle, ring_id, 0); + amdgpu_memcpy_draw_hang_slow_test(device_handle, ring_id); + amdgpu_memcpy_draw_test(device_handle, ring_id, 0); + } +} diff --git a/lib/libdrm/tests/amdgpu/decode_messages.h b/lib/libdrm/tests/amdgpu/decode_messages.h index bd6fe4b69..ee1deb4f9 100644 --- a/lib/libdrm/tests/amdgpu/decode_messages.h +++ b/lib/libdrm/tests/amdgpu/decode_messages.h @@ -361,7 +361,7 @@ static const uint8_t uvd_decode_msg[] = { }; static const uint8_t avc_decode_msg[] = { - 0x02,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x88,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x85,0x00,0x00,0x00,0x88,0x00,0x00,0x00, 0x01,0x00,0x00,0x01,0x00,0x03,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, @@ -826,7 +826,7 @@ 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, + 0x5c,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,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, @@ -845,4 +845,10 @@ static const uint8_t vcn_dec_destroy_msg[] = { 0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00, }; +static const uint8_t feedback_msg[] = { + 0x2c,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + #endif /* _DECODE_MESSAGES_H_ */ diff --git a/lib/libdrm/tests/amdgpu/meson.build b/lib/libdrm/tests/amdgpu/meson.build index 1726cb438..eb16a50c1 100644 --- a/lib/libdrm/tests/amdgpu/meson.build +++ b/lib/libdrm/tests/amdgpu/meson.build @@ -24,9 +24,9 @@ if dep_cunit.found() 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', 'ras_tests.c', 'syncobj_tests.c', + 'vm_tests.c', 'ras_tests.c', 'syncobj_tests.c', 'security_tests.c', ), - dependencies : [dep_cunit, dep_threads], + dependencies : [dep_cunit, 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/lib/libdrm/tests/amdgpu/ras_tests.c b/lib/libdrm/tests/amdgpu/ras_tests.c index c1c543c12..810bf1727 100644 --- a/lib/libdrm/tests/amdgpu/ras_tests.c +++ b/lib/libdrm/tests/amdgpu/ras_tests.c @@ -30,6 +30,9 @@ #include <fcntl.h> #include <stdio.h> #include "xf86drm.h" +#include <limits.h> + +#define PATH_SIZE PATH_MAX #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) @@ -498,7 +501,7 @@ static int get_file_contents(char *file, char *buf, int size); static int amdgpu_ras_lookup_id(drmDevicePtr device) { - char path[1024]; + char path[PATH_SIZE]; char str[128]; drmPciBusInfo info; int i; @@ -507,7 +510,7 @@ static int amdgpu_ras_lookup_id(drmDevicePtr device) for (i = 0; i < MAX_CARDS_SUPPORTED; i++) { memset(str, 0, sizeof(str)); memset(&info, 0, sizeof(info)); - sprintf(path, "/sys/kernel/debug/dri/%d/name", i); + snprintf(path, PATH_SIZE, "/sys/kernel/debug/dri/%d/name", i); if (get_file_contents(path, str, sizeof(str)) <= 0) continue; @@ -522,146 +525,24 @@ static int amdgpu_ras_lookup_id(drmDevicePtr device) return -1; } -CU_BOOL suite_ras_tests_enable(void) -{ - amdgpu_device_handle device_handle; - uint32_t major_version; - uint32_t minor_version; - int i; - drmDevicePtr device; - - for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) { - if (amdgpu_device_initialize(drm_amdgpu[i], &major_version, - &minor_version, &device_handle)) - continue; - - if (drmGetDevice2(drm_amdgpu[i], - DRM_DEVICE_GET_PCI_REVISION, - &device)) - continue; - - if (device->bustype == DRM_BUS_PCI && - amdgpu_ras_lookup_capability(device_handle)) { - amdgpu_device_deinitialize(device_handle); - return CU_TRUE; - } - - if (amdgpu_device_deinitialize(device_handle)) - continue; - } - - return CU_FALSE; -} - -int suite_ras_tests_init(void) -{ - drmDevicePtr device; - amdgpu_device_handle device_handle; - uint32_t major_version; - uint32_t minor_version; - uint32_t capability; - struct ras_test_mask test_mask; - int id; - int i; - int r; - - for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) { - r = amdgpu_device_initialize(drm_amdgpu[i], &major_version, - &minor_version, &device_handle); - if (r) - continue; - - if (drmGetDevice2(drm_amdgpu[i], - DRM_DEVICE_GET_PCI_REVISION, - &device)) { - amdgpu_device_deinitialize(device_handle); - continue; - } - - if (device->bustype != DRM_BUS_PCI) { - amdgpu_device_deinitialize(device_handle); - continue; - } - - capability = amdgpu_ras_lookup_capability(device_handle); - if (capability == 0) { - amdgpu_device_deinitialize(device_handle); - continue; - - } - - id = amdgpu_ras_lookup_id(device); - if (id == -1) { - amdgpu_device_deinitialize(device_handle); - continue; - } - - test_mask = amdgpu_ras_get_test_mask(device); - - devices[devices_count++] = (struct amdgpu_ras_data) { - device_handle, id, capability, test_mask, - }; - } - - if (devices_count == 0) - return CUE_SINIT_FAILED; - - return CUE_SUCCESS; -} - -int suite_ras_tests_clean(void) -{ - int r; - int i; - int ret = CUE_SUCCESS; - - for (i = 0; i < devices_count; i++) { - r = amdgpu_device_deinitialize(devices[i].device_handle); - if (r) - ret = CUE_SCLEAN_FAILED; - } - return ret; -} - -static void amdgpu_ras_disable_test(void); -static void amdgpu_ras_enable_test(void); -static void amdgpu_ras_inject_test(void); -static void amdgpu_ras_query_test(void); -static void amdgpu_ras_basic_test(void); - -CU_TestInfo ras_tests[] = { - { "ras basic test", amdgpu_ras_basic_test }, - { "ras query test", amdgpu_ras_query_test }, - { "ras inject test", amdgpu_ras_inject_test }, - { "ras disable test", amdgpu_ras_disable_test }, -#if 0 - { "ras enable test", amdgpu_ras_enable_test }, -#endif - CU_TEST_INFO_NULL, -}; - //helpers static int test_card; -static char sysfs_path[1024]; -static char debugfs_path[1024]; +static char sysfs_path[PATH_SIZE]; +static char debugfs_path[PATH_SIZE]; static uint32_t ras_mask; static amdgpu_device_handle device_handle; -static int set_test_card(int card) +static void set_test_card(int card) { - int i; - test_card = card; - sprintf(sysfs_path, "/sys/class/drm/card%d/device/ras/", devices[card].id); - sprintf(debugfs_path, "/sys/kernel/debug/dri/%d/ras/", devices[card].id); + snprintf(sysfs_path, PATH_SIZE, "/sys/class/drm/card%d/device/ras/", devices[card].id); + snprintf(debugfs_path, PATH_SIZE, "/sys/kernel/debug/dri/%d/ras/", devices[card].id); ras_mask = devices[card].capability; device_handle = devices[card].device_handle; ras_block_mask_inject = devices[card].test_mask.inject_mask; ras_block_mask_query = devices[card].test_mask.query_mask; ras_block_mask_basic = devices[card].test_mask.basic_mask; - - return 0; } static const char *get_ras_sysfs_root(void) @@ -727,10 +608,11 @@ static int amdgpu_ras_is_feature_supported(enum amdgpu_ras_block block) static int amdgpu_ras_invoke(struct ras_debug_if *data) { - char path[1024]; + char path[PATH_SIZE]; int ret; - sprintf(path, "%s%s", get_ras_debugfs_root(), "ras_ctrl"); + snprintf(path, sizeof(path), "%s", get_ras_debugfs_root()); + strncat(path, "ras_ctrl", sizeof(path) - strlen(path)); ret = set_file_contents(path, (char *)data, sizeof(*data)) - sizeof(*data); @@ -741,15 +623,16 @@ static int amdgpu_ras_query_err_count(enum amdgpu_ras_block block, unsigned long *ue, unsigned long *ce) { char buf[64]; - char name[1024]; - int ret; + char name[PATH_SIZE]; *ue = *ce = 0; if (amdgpu_ras_is_feature_supported(block) <= 0) return -1; - sprintf(name, "%s%s%s", get_ras_sysfs_root(), ras_block_str(block), "_err_count"); + snprintf(name, sizeof(name), "%s", get_ras_sysfs_root()); + strncat(name, ras_block_str(block), sizeof(name) - strlen(name)); + strncat(name, "_err_count", sizeof(name) - strlen(name)); if (is_file_ok(name, O_RDONLY)) return 0; @@ -779,7 +662,7 @@ static int amdgpu_ras_inject(enum amdgpu_ras_block block, inject->head.block = block; inject->head.type = type; inject->head.sub_block_index = sub_block; - strncpy(inject->head.name, ras_block_str(block), 32); + strncpy(inject->head.name, ras_block_str(block), sizeof(inject->head.name)-1); inject->address = address; inject->value = value; @@ -956,13 +839,11 @@ static void amdgpu_ras_query_test(void) static void amdgpu_ras_basic_test(void) { - unsigned long ue, ce; - char name[1024]; int ret; int i; int j; uint32_t features; - char path[1024]; + char path[PATH_SIZE]; ret = is_file_ok("/sys/module/amdgpu/parameters/ras_mask", O_RDONLY); CU_ASSERT_EQUAL(ret, 0); @@ -974,11 +855,15 @@ static void amdgpu_ras_basic_test(void) sizeof(features), &features); CU_ASSERT_EQUAL(ret, 0); - sprintf(path, "%s%s", get_ras_debugfs_root(), "ras_ctrl"); + snprintf(path, sizeof(path), "%s", get_ras_debugfs_root()); + strncat(path, "ras_ctrl", sizeof(path) - strlen(path)); + ret = is_file_ok(path, O_WRONLY); CU_ASSERT_EQUAL(ret, 0); - sprintf(path, "%s%s", get_ras_sysfs_root(), "features"); + snprintf(path, sizeof(path), "%s", get_ras_sysfs_root()); + strncat(path, "features", sizeof(path) - strlen(path)); + ret = is_file_ok(path, O_RDONLY); CU_ASSERT_EQUAL(ret, 0); @@ -990,13 +875,129 @@ static void amdgpu_ras_basic_test(void) if (!((1 << j) & ras_block_mask_basic)) continue; - sprintf(path, "%s%s%s", get_ras_sysfs_root(), ras_block_str(j), "_err_count"); + snprintf(path, sizeof(path), "%s", get_ras_sysfs_root()); + strncat(path, ras_block_str(j), sizeof(path) - strlen(path)); + strncat(path, "_err_count", sizeof(path) - strlen(path)); + ret = is_file_ok(path, O_RDONLY); CU_ASSERT_EQUAL(ret, 0); - sprintf(path, "%s%s%s", get_ras_debugfs_root(), ras_block_str(j), "_err_inject"); + snprintf(path, sizeof(path), "%s", get_ras_debugfs_root()); + strncat(path, ras_block_str(j), sizeof(path) - strlen(path)); + strncat(path, "_err_inject", sizeof(path) - strlen(path)); + ret = is_file_ok(path, O_WRONLY); CU_ASSERT_EQUAL(ret, 0); } } } + +CU_TestInfo ras_tests[] = { + { "ras basic test", amdgpu_ras_basic_test }, + { "ras query test", amdgpu_ras_query_test }, + { "ras inject test", amdgpu_ras_inject_test }, + { "ras disable test", amdgpu_ras_disable_test }, + { "ras enable test", amdgpu_ras_enable_test }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_ras_tests_enable(void) +{ + amdgpu_device_handle device_handle; + uint32_t major_version; + uint32_t minor_version; + int i; + drmDevicePtr device; + + for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) { + if (amdgpu_device_initialize(drm_amdgpu[i], &major_version, + &minor_version, &device_handle)) + continue; + + if (drmGetDevice2(drm_amdgpu[i], + DRM_DEVICE_GET_PCI_REVISION, + &device)) + continue; + + if (device->bustype == DRM_BUS_PCI && + amdgpu_ras_lookup_capability(device_handle)) { + amdgpu_device_deinitialize(device_handle); + return CU_TRUE; + } + + if (amdgpu_device_deinitialize(device_handle)) + continue; + } + + return CU_FALSE; +} + +int suite_ras_tests_init(void) +{ + drmDevicePtr device; + amdgpu_device_handle device_handle; + uint32_t major_version; + uint32_t minor_version; + uint32_t capability; + struct ras_test_mask test_mask; + int id; + int i; + int r; + + for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) { + r = amdgpu_device_initialize(drm_amdgpu[i], &major_version, + &minor_version, &device_handle); + if (r) + continue; + + if (drmGetDevice2(drm_amdgpu[i], + DRM_DEVICE_GET_PCI_REVISION, + &device)) { + amdgpu_device_deinitialize(device_handle); + continue; + } + + if (device->bustype != DRM_BUS_PCI) { + amdgpu_device_deinitialize(device_handle); + continue; + } + + capability = amdgpu_ras_lookup_capability(device_handle); + if (capability == 0) { + amdgpu_device_deinitialize(device_handle); + continue; + + } + + id = amdgpu_ras_lookup_id(device); + if (id == -1) { + amdgpu_device_deinitialize(device_handle); + continue; + } + + test_mask = amdgpu_ras_get_test_mask(device); + + devices[devices_count++] = (struct amdgpu_ras_data) { + device_handle, id, capability, test_mask, + }; + } + + if (devices_count == 0) + return CUE_SINIT_FAILED; + + return CUE_SUCCESS; +} + +int suite_ras_tests_clean(void) +{ + int r; + int i; + int ret = CUE_SUCCESS; + + for (i = 0; i < devices_count; i++) { + r = amdgpu_device_deinitialize(devices[i].device_handle); + if (r) + ret = CUE_SCLEAN_FAILED; + } + return ret; +} diff --git a/lib/libdrm/tests/amdgpu/security_tests.c b/lib/libdrm/tests/amdgpu/security_tests.c new file mode 100644 index 000000000..eed695a38 --- /dev/null +++ b/lib/libdrm/tests/amdgpu/security_tests.c @@ -0,0 +1,485 @@ +/* + * Copyright 2019 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" + +#include <string.h> +#include <unistd.h> +#ifdef __FreeBSD__ +#include <sys/endian.h> +#else +#include <endian.h> +#endif +#include <strings.h> +#include <xf86drm.h> + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; + +static struct drm_amdgpu_info_hw_ip sdma_info; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(_Arr) (sizeof(_Arr)/sizeof((_Arr)[0])) +#endif + + +/* --------------------- Secure bounce test ------------------------ * + * + * The secure bounce test tests that we can evict a TMZ buffer, + * and page it back in, via a bounce buffer, as it encryption/decryption + * depends on its physical address, and have the same data, i.e. data + * integrity is preserved. + * + * The steps are as follows (from Christian K.): + * + * Buffer A which is TMZ protected and filled by the CPU with a + * certain pattern. That the GPU is reading only random nonsense from + * that pattern is irrelevant for the test. + * + * This buffer A is then secure copied into buffer B which is also + * TMZ protected. + * + * Buffer B is moved around, from VRAM to GTT, GTT to SYSTEM, + * etc. + * + * Then, we use another secure copy of buffer B back to buffer A. + * + * And lastly we check with the CPU the pattern. + * + * Assuming that we don't have memory contention and buffer A stayed + * at the same place, we should still see the same pattern when read + * by the CPU. + * + * If we don't see the same pattern then something in the buffer + * migration code is not working as expected. + */ + +#define SECURE_BOUNCE_TEST_STR "secure bounce" +#define SECURE_BOUNCE_FAILED_STR SECURE_BOUNCE_TEST_STR " failed" + +#define PRINT_ERROR(_Res) fprintf(stderr, "%s:%d: %s (%d)\n", \ + __func__, __LINE__, strerror(-(_Res)), _Res) + +#define PACKET_LCOPY_SIZE 7 +#define PACKET_NOP_SIZE 12 + +struct sec_amdgpu_bo { + struct amdgpu_bo *bo; + struct amdgpu_va *va; +}; + +struct command_ctx { + struct amdgpu_device *dev; + struct amdgpu_cs_ib_info cs_ibinfo; + struct amdgpu_cs_request cs_req; + struct amdgpu_context *context; + int ring_id; +}; + +/** + * amdgpu_bo_alloc_map -- Allocate and map a buffer object (BO) + * @dev: The AMDGPU device this BO belongs to. + * @size: The size of the BO. + * @alignment: Alignment of the BO. + * @gem_domain: One of AMDGPU_GEM_DOMAIN_xyz. + * @alloc_flags: One of AMDGPU_GEM_CREATE_xyz. + * @sbo: the result + * + * Allocate a buffer object (BO) with the desired attributes + * as specified by the argument list and write out the result + * into @sbo. + * + * Return 0 on success and @sbo->bo and @sbo->va are set, + * or -errno on error. + */ +static int amdgpu_bo_alloc_map(struct amdgpu_device *dev, + unsigned size, + unsigned alignment, + unsigned gem_domain, + uint64_t alloc_flags, + struct sec_amdgpu_bo *sbo) +{ + void *cpu; + uint64_t mc_addr; + + return amdgpu_bo_alloc_and_map_raw(dev, + size, + alignment, + gem_domain, + alloc_flags, + 0, + &sbo->bo, + &cpu, &mc_addr, + &sbo->va); +} + +static void amdgpu_bo_unmap_free(struct sec_amdgpu_bo *sbo, + const uint64_t size) +{ + (void) amdgpu_bo_unmap_and_free(sbo->bo, + sbo->va, + sbo->va->address, + size); + sbo->bo = NULL; + sbo->va = NULL; +} + +static void amdgpu_sdma_lcopy(uint32_t *packet, + const uint64_t dst, + const uint64_t src, + const uint32_t size, + const int secure) +{ + /* Set the packet to Linear copy with TMZ set. + */ + packet[0] = htole32(secure << 18 | 1); + packet[1] = htole32(size-1); + packet[2] = htole32(0); + packet[3] = htole32((uint32_t)(src & 0xFFFFFFFFU)); + packet[4] = htole32((uint32_t)(src >> 32)); + packet[5] = htole32((uint32_t)(dst & 0xFFFFFFFFU)); + packet[6] = htole32((uint32_t)(dst >> 32)); +} + +static void amdgpu_sdma_nop(uint32_t *packet, uint32_t nop_count) +{ + /* A packet of the desired number of NOPs. + */ + packet[0] = htole32(nop_count << 16); + for ( ; nop_count > 0; nop_count--) + packet[nop_count-1] = 0; +} + +/** + * amdgpu_bo_lcopy -- linear copy with TMZ set, using sDMA + * @dev: AMDGPU device to which both buffer objects belong to + * @dst: destination buffer object + * @src: source buffer object + * @size: size of memory to move, in bytes. + * @secure: Set to 1 to perform secure copy, 0 for clear + * + * Issues and waits for completion of a Linear Copy with TMZ + * set, to the sDMA engine. @size should be a multiple of + * at least 16 bytes. + */ +static void amdgpu_bo_lcopy(struct command_ctx *ctx, + struct sec_amdgpu_bo *dst, + struct sec_amdgpu_bo *src, + const uint32_t size, + int secure) +{ + struct amdgpu_bo *bos[] = { dst->bo, src->bo }; + uint32_t packet[PACKET_LCOPY_SIZE]; + + amdgpu_sdma_lcopy(packet, + dst->va->address, + src->va->address, + size, secure); + amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context, + AMDGPU_HW_IP_DMA, ctx->ring_id, + ARRAY_SIZE(packet), packet, + ARRAY_SIZE(bos), bos, + &ctx->cs_ibinfo, &ctx->cs_req, + secure == 1); +} + +/** + * amdgpu_bo_move -- Evoke a move of the buffer object (BO) + * @dev: device to which this buffer object belongs to + * @bo: the buffer object to be moved + * @whereto: one of AMDGPU_GEM_DOMAIN_xyz + * @secure: set to 1 to submit secure IBs + * + * Evokes a move of the buffer object @bo to the GEM domain + * descibed by @whereto. + * + * Returns 0 on sucess; -errno on error. + */ +static int amdgpu_bo_move(struct command_ctx *ctx, + struct amdgpu_bo *bo, + uint64_t whereto, + int secure) +{ + struct amdgpu_bo *bos[] = { bo }; + struct drm_amdgpu_gem_op gop = { + .handle = bo->handle, + .op = AMDGPU_GEM_OP_SET_PLACEMENT, + .value = whereto, + }; + uint32_t packet[PACKET_NOP_SIZE]; + int res; + + /* Change the buffer's placement. + */ + res = drmIoctl(ctx->dev->fd, DRM_IOCTL_AMDGPU_GEM_OP, &gop); + if (res) + return -errno; + + /* Now issue a NOP to actually evoke the MM to move + * it to the desired location. + */ + amdgpu_sdma_nop(packet, PACKET_NOP_SIZE); + amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context, + AMDGPU_HW_IP_DMA, ctx->ring_id, + ARRAY_SIZE(packet), packet, + ARRAY_SIZE(bos), bos, + &ctx->cs_ibinfo, &ctx->cs_req, + secure == 1); + return 0; +} + +/* Safe, O Sec! + */ +static const uint8_t secure_pattern[] = { 0x5A, 0xFE, 0x05, 0xEC }; + +#define SECURE_BUFFER_SIZE (4 * 1024 * sizeof(secure_pattern)) + +static void amdgpu_secure_bounce(void) +{ + struct sec_amdgpu_bo alice, bob; + struct command_ctx sb_ctx; + long page_size; + uint8_t *pp; + int res; + + page_size = sysconf(_SC_PAGESIZE); + + memset(&sb_ctx, 0, sizeof(sb_ctx)); + sb_ctx.dev = device_handle; + res = amdgpu_cs_ctx_create(sb_ctx.dev, &sb_ctx.context); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + return; + } + + /* Use the first present ring. + */ + res = ffs(sdma_info.available_rings) - 1; + if (res == -1) { + PRINT_ERROR(-ENOENT); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + goto Out_free_ctx; + } + sb_ctx.ring_id = res; + + /* Allocate a buffer named Alice in VRAM. + */ + res = amdgpu_bo_alloc_map(device_handle, + SECURE_BUFFER_SIZE, + page_size, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_ENCRYPTED, + &alice); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + return; + } + + /* Fill Alice with a pattern. + */ + for (pp = alice.bo->cpu_ptr; + pp < (typeof(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE; + pp += sizeof(secure_pattern)) + memcpy(pp, secure_pattern, sizeof(secure_pattern)); + + /* Allocate a buffer named Bob in VRAM. + */ + res = amdgpu_bo_alloc_map(device_handle, + SECURE_BUFFER_SIZE, + page_size, + AMDGPU_GEM_DOMAIN_VRAM, + 0 /* AMDGPU_GEM_CREATE_ENCRYPTED */, + &bob); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + goto Out_free_Alice; + } + + /* sDMA clear copy from Alice to Bob. + */ + amdgpu_bo_lcopy(&sb_ctx, &bob, &alice, SECURE_BUFFER_SIZE, 0); + + /* Move Bob to the GTT domain. + */ + res = amdgpu_bo_move(&sb_ctx, bob.bo, AMDGPU_GEM_DOMAIN_GTT, 0); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + goto Out_free_all; + } + + /* sDMA clear copy from Bob to Alice. + */ + amdgpu_bo_lcopy(&sb_ctx, &alice, &bob, SECURE_BUFFER_SIZE, 0); + + /* Verify the contents of Alice. + */ + for (pp = alice.bo->cpu_ptr; + pp < (typeof(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE; + pp += sizeof(secure_pattern)) { + res = memcmp(pp, secure_pattern, sizeof(secure_pattern)); + if (res) { + fprintf(stderr, SECURE_BOUNCE_FAILED_STR); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + break; + } + } + +Out_free_all: + amdgpu_bo_unmap_free(&bob, SECURE_BUFFER_SIZE); +Out_free_Alice: + amdgpu_bo_unmap_free(&alice, SECURE_BUFFER_SIZE); +Out_free_ctx: + res = amdgpu_cs_ctx_free(sb_ctx.context); + CU_ASSERT_EQUAL(res, 0); +} + +/* ----------------------------------------------------------------- */ + +static void amdgpu_security_alloc_buf_test(void) +{ + amdgpu_bo_handle bo; + amdgpu_va_handle va_handle; + uint64_t bo_mc; + int r; + + /* Test secure buffer allocation in VRAM */ + bo = gpu_mem_alloc(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_ENCRYPTED, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test secure buffer allocation in system memory */ + bo = gpu_mem_alloc(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_ENCRYPTED, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test secure buffer allocation in invisible VRAM */ + bo = gpu_mem_alloc(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_ENCRYPTED | + 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); +} + +static void amdgpu_security_gfx_submission_test(void) +{ + amdgpu_command_submission_write_linear_helper_with_secure(device_handle, + AMDGPU_HW_IP_GFX, + true); +} + +static void amdgpu_security_sdma_submission_test(void) +{ + amdgpu_command_submission_write_linear_helper_with_secure(device_handle, + AMDGPU_HW_IP_DMA, + true); +} + +/* ----------------------------------------------------------------- */ + +CU_TestInfo security_tests[] = { + { "allocate secure buffer test", amdgpu_security_alloc_buf_test }, + { "graphics secure command submission", amdgpu_security_gfx_submission_test }, + { "sDMA secure command submission", amdgpu_security_sdma_submission_test }, + { SECURE_BOUNCE_TEST_STR, amdgpu_secure_bounce }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_security_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_RV) { + printf("\n\nDon't support TMZ (trust memory zone), security suite disabled\n"); + enable = CU_FALSE; + } + + if ((major_version < 3) || + ((major_version == 3) && (minor_version < 37))) { + printf("\n\nDon't support TMZ (trust memory zone), kernel DRM version (%d.%d)\n", + major_version, minor_version); + printf("is older, security suite disabled\n"); + enable = CU_FALSE; + } + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + return enable; +} + +int suite_security_tests_init(void) +{ + int res; + + res = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + if (res) { + PRINT_ERROR(res); + return CUE_SINIT_FAILED; + } + + res = amdgpu_query_hw_ip_info(device_handle, + AMDGPU_HW_IP_DMA, + 0, &sdma_info); + if (res) { + PRINT_ERROR(res); + return CUE_SINIT_FAILED; + } + + return CUE_SUCCESS; +} + +int suite_security_tests_clean(void) +{ + int res; + + res = amdgpu_device_deinitialize(device_handle); + if (res) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} diff --git a/lib/libdrm/tests/amdgpu/syncobj_tests.c b/lib/libdrm/tests/amdgpu/syncobj_tests.c index 869ed88ea..3a7b38eb1 100644 --- a/lib/libdrm/tests/amdgpu/syncobj_tests.c +++ b/lib/libdrm/tests/amdgpu/syncobj_tests.c @@ -96,7 +96,7 @@ static int syncobj_command_submission_helper(uint32_t syncobj_handle, bool struct amdgpu_cs_fence fence_status; amdgpu_bo_list_handle bo_list; amdgpu_va_handle va_handle; - uint32_t expired, flags; + uint32_t expired; int i, r; uint64_t seq_no; static uint32_t *ptr; diff --git a/lib/libdrm/tests/amdgpu/vce_tests.c b/lib/libdrm/tests/amdgpu/vce_tests.c index 0026826ea..5434e4445 100644 --- a/lib/libdrm/tests/amdgpu/vce_tests.c +++ b/lib/libdrm/tests/amdgpu/vce_tests.c @@ -96,7 +96,7 @@ CU_TestInfo vce_tests[] = { CU_BOOL suite_vce_tests_enable(void) { - uint32_t version, feature; + uint32_t version, feature, asic_id; CU_BOOL ret_mv = CU_FALSE; if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, @@ -107,6 +107,7 @@ CU_BOOL suite_vce_tests_enable(void) chip_rev = device_handle->info.chip_rev; chip_id = device_handle->info.chip_external_rev; ids_flags = device_handle->info.ids_flags; + asic_id = device_handle->info.asic_id; amdgpu_query_firmware_version(device_handle, AMDGPU_INFO_FW_VCE, 0, 0, &version, &feature); @@ -114,7 +115,8 @@ CU_BOOL suite_vce_tests_enable(void) if (amdgpu_device_deinitialize(device_handle)) return CU_FALSE; - if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI) { + if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI || + asic_is_arcturus(asic_id)) { printf("\n\nThe ASIC NOT support VCE, suite disabled\n"); return CU_FALSE; } diff --git a/lib/libdrm/tests/amdgpu/vcn_tests.c b/lib/libdrm/tests/amdgpu/vcn_tests.c index ad438f35c..3a4588623 100644 --- a/lib/libdrm/tests/amdgpu/vcn_tests.c +++ b/lib/libdrm/tests/amdgpu/vcn_tests.c @@ -56,6 +56,11 @@ static amdgpu_device_handle device_handle; static uint32_t major_version; static uint32_t minor_version; static uint32_t family_id; +static uint32_t chip_rev; +static uint32_t chip_id; +static uint32_t asic_id; +static uint32_t chip_rev; +static uint32_t chip_id; static amdgpu_context_handle context_handle; static amdgpu_bo_handle ib_handle; @@ -89,34 +94,74 @@ CU_TestInfo vcn_tests[] = { CU_BOOL suite_vcn_tests_enable(void) { + struct drm_amdgpu_info_hw_ip info; + int r; 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; + asic_id = device_handle->info.asic_id; + chip_rev = device_handle->info.chip_rev; + chip_id = device_handle->info.chip_external_rev; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_VCN_DEC, 0, &info); if (amdgpu_device_deinitialize(device_handle)) return CU_FALSE; - - if (family_id < AMDGPU_FAMILY_RV) { + if (r != 0 || !info.available_rings || + (family_id < AMDGPU_FAMILY_RV && + (family_id == AMDGPU_FAMILY_AI && + chip_id != (chip_rev + 0x32)))) { /* Arcturus */ printf("\n\nThe ASIC NOT support VCN, suite disabled\n"); return CU_FALSE; } + if (family_id == AMDGPU_FAMILY_AI) { + amdgpu_set_test_active("VCN Tests", "VCN ENC create", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN ENC decode", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN ENC destroy", CU_FALSE); + } + if (family_id == AMDGPU_FAMILY_RV) { - reg.data0 = 0x81c4; - reg.data1 = 0x81c5; - reg.cmd = 0x81c3; - reg.nop = 0x81ff; - reg.cntl = 0x81c6; + if (chip_id >= (chip_rev + 0x91)) { + reg.data0 = 0x504; + reg.data1 = 0x505; + reg.cmd = 0x503; + reg.nop = 0x53f; + reg.cntl = 0x506; + } else { + reg.data0 = 0x81c4; + reg.data1 = 0x81c5; + reg.cmd = 0x81c3; + reg.nop = 0x81ff; + reg.cntl = 0x81c6; + } } else if (family_id == AMDGPU_FAMILY_NV) { - reg.data0 = 0x504; - reg.data1 = 0x505; - reg.cmd = 0x503; - reg.nop = 0x53f; - reg.cntl = 0x506; + if (chip_id == (chip_rev + 0x28)) { + reg.data0 = 0x10; + reg.data1 = 0x11; + reg.cmd = 0xf; + reg.nop = 0x29; + reg.cntl = 0x26d; + } + else { + reg.data0 = 0x504; + reg.data1 = 0x505; + reg.cmd = 0x503; + reg.nop = 0x53f; + reg.cntl = 0x506; + } + } else if (family_id == AMDGPU_FAMILY_AI) { + reg.data0 = 0x10; + reg.data1 = 0x11; + reg.cmd = 0xf; + reg.nop = 0x29; + reg.cntl = 0x26d; } else return CU_FALSE; @@ -333,6 +378,7 @@ static void amdgpu_cs_vcn_dec_decode(void) avc_decode_msg, sizeof(avc_decode_msg)); dec += 4*1024; + memcpy(dec, feedback_msg, sizeof(feedback_msg)); dec += 4*1024; memcpy(dec, uvd_it_scaling_table, sizeof(uvd_it_scaling_table)); diff --git a/lib/libdrm/tests/amdgpu/vm_tests.c b/lib/libdrm/tests/amdgpu/vm_tests.c index 69bc46839..95011ea06 100644 --- a/lib/libdrm/tests/amdgpu/vm_tests.c +++ b/lib/libdrm/tests/amdgpu/vm_tests.c @@ -104,6 +104,14 @@ static void amdgpu_vmid_reserve_test(void) amdgpu_bo_list_handle bo_list; amdgpu_va_handle va_handle; static uint32_t *ptr; + struct amdgpu_gpu_info gpu_info = {0}; + unsigned gc_ip_type; + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + CU_ASSERT_EQUAL(r, 0); + + gc_ip_type = (asic_is_arcturus(gpu_info.asic_id)) ? + AMDGPU_HW_IP_COMPUTE : AMDGPU_HW_IP_GFX; r = amdgpu_cs_ctx_create(device_handle, &context_handle); CU_ASSERT_EQUAL(r, 0); @@ -133,7 +141,7 @@ static void amdgpu_vmid_reserve_test(void) ib_info.size = 16; memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); - ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ip_type = gc_ip_type; ibs_request.ring = 0; ibs_request.number_of_ibs = 1; ibs_request.ibs = &ib_info; @@ -146,7 +154,7 @@ static void amdgpu_vmid_reserve_test(void) 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_type = gc_ip_type; fence_status.ip_instance = 0; fence_status.ring = 0; fence_status.fence = ibs_request.seq_no; diff --git a/lib/libdrm/tests/etnaviv/etnaviv_2d_test.c b/lib/libdrm/tests/etnaviv/etnaviv_2d_test.c index 8dd77b666..9fcdae184 100644 --- a/lib/libdrm/tests/etnaviv/etnaviv_2d_test.c +++ b/lib/libdrm/tests/etnaviv/etnaviv_2d_test.c @@ -147,6 +147,27 @@ static void gen_cmd_stream(struct etna_cmd_stream *stream, struct etna_bo *bmp, etna_set_state(stream, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_PE2D); } +int etna_check_image(uint32_t *p, int width, int height) +{ + int i; + uint32_t expected; + + for (i = 0; i < width * height; i++) { + if (i%8 < 4 && i%(width*8) < width*4 && i%width < 8*16 && i < width*8*16) + expected = 0xff40ff40; + else + expected = 0x00000000; + + if (p[i] != expected) { + fprintf(stderr, "Offset %d: expected: 0x%08x, got: 0x%08x\n", + i, expected, p[i]); + return -1; + } + } + + return 0; +} + int main(int argc, char *argv[]) { const int width = 256; @@ -161,10 +182,19 @@ int main(int argc, char *argv[]) drmVersionPtr version; int fd, ret = 0; + uint64_t feat; + int core = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s /dev/dri/<device> [<etna.bmp>]\n", argv[0]); + return 1; + } fd = open(argv[1], O_RDWR); - if (fd < 0) + if (fd < 0) { + perror(argv[1]); return 1; + } version = drmGetVersion(fd); if (version) { @@ -178,25 +208,44 @@ int main(int argc, char *argv[]) dev = etna_device_new(fd); if (!dev) { + perror("etna_device_new"); ret = 2; goto out; } - /* TODO: we assume that core 0 is a 2D capable one */ - gpu = etna_gpu_new(dev, 0); - if (!gpu) { - ret = 3; - goto out_device; - } + do { + gpu = etna_gpu_new(dev, core); + if (!gpu) { + perror("etna_gpu_new"); + ret = 3; + goto out_device; + } + + if (etna_gpu_get_param(gpu, ETNA_GPU_FEATURES_0, &feat)) { + perror("etna_gpu_get_param"); + ret = 4; + goto out_device; + } + + if ((feat & (1 << 9)) == 0) { + /* GPU not 2D capable. */ + etna_gpu_del(gpu); + gpu = NULL; + } + + core++; + } while (!gpu); pipe = etna_pipe_new(gpu, ETNA_PIPE_2D); if (!pipe) { + perror("etna_pipe_new"); ret = 4; goto out_gpu; } bmp = etna_bo_new(dev, bmp_size, ETNA_BO_UNCACHED); if (!bmp) { + perror("etna_bo_new"); ret = 5; goto out_pipe; } @@ -204,6 +253,7 @@ int main(int argc, char *argv[]) stream = etna_cmd_stream_new(pipe, 0x300, NULL, NULL); if (!stream) { + perror("etna_cmd_stream_new"); ret = 6; goto out_bo; } @@ -213,7 +263,11 @@ int main(int argc, char *argv[]) etna_cmd_stream_finish(stream); - bmp_dump32(etna_bo_map(bmp), width, height, false, "/tmp/etna.bmp"); + if (argc > 2) + bmp_dump32(etna_bo_map(bmp), width, height, false, argv[2]); + + if (etna_check_image(etna_bo_map(bmp), width, height)) + ret = 7; etna_cmd_stream_del(stream); diff --git a/lib/libdrm/tests/kms/kms-steal-crtc.c b/lib/libdrm/tests/kms/kms-steal-crtc.c index cd40758db..4d884c079 100644 --- a/lib/libdrm/tests/kms/kms-steal-crtc.c +++ b/lib/libdrm/tests/kms/kms-steal-crtc.c @@ -28,7 +28,7 @@ #include <stdint.h> #include <string.h> #include <unistd.h> -#ifdef HAVE_SYS_SELECT_H +#if HAVE_SYS_SELECT_H #include <sys/select.h> #endif diff --git a/lib/libdrm/tests/kms/kms-universal-planes.c b/lib/libdrm/tests/kms/kms-universal-planes.c index 2163c987c..1d7938802 100644 --- a/lib/libdrm/tests/kms/kms-universal-planes.c +++ b/lib/libdrm/tests/kms/kms-universal-planes.c @@ -28,7 +28,7 @@ #include <stdio.h> #include <string.h> #include <unistd.h> -#ifdef HAVE_SYS_SELECT_H +#if HAVE_SYS_SELECT_H #include <sys/select.h> #endif diff --git a/lib/libdrm/tests/kms/libkms-test-screen.c b/lib/libdrm/tests/kms/libkms-test-screen.c index bbe972a0b..d00ae5477 100644 --- a/lib/libdrm/tests/kms/libkms-test-screen.c +++ b/lib/libdrm/tests/kms/libkms-test-screen.c @@ -42,7 +42,9 @@ static void kms_screen_probe(struct kms_screen *screen) else screen->connected = false; - memcpy(&screen->mode, &con->modes[0], sizeof(drmModeModeInfo)); + if (con->modes) + memcpy(&screen->mode, &con->modes[0], sizeof(drmModeModeInfo)); + screen->width = screen->mode.hdisplay; screen->height = screen->mode.vdisplay; diff --git a/lib/libdrm/tests/meson.build b/lib/libdrm/tests/meson.build index 6c8ddd9c2..196edbfa9 100644 --- a/lib/libdrm/tests/meson.build +++ b/lib/libdrm/tests/meson.build @@ -64,23 +64,15 @@ hash = executable( 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, + install : with_install_tests, ) -test('random', random, timeout : 240) test('hash', hash) test('drmsl', drmsl) test('drmdevice', drmdevice) diff --git a/lib/libdrm/tests/modetest/modetest.c b/lib/libdrm/tests/modetest/modetest.c index e66be6607..fc75383a4 100644 --- a/lib/libdrm/tests/modetest/modetest.c +++ b/lib/libdrm/tests/modetest/modetest.c @@ -51,9 +51,10 @@ #include <errno.h> #include <poll.h> #include <sys/time.h> -#ifdef HAVE_SYS_SELECT_H +#if HAVE_SYS_SELECT_H #include <sys/select.h> #endif +#include <math.h> #include "xf86drm.h" #include "xf86drmMode.h" @@ -99,14 +100,16 @@ struct plane { }; struct resources { - drmModeRes *res; - drmModePlaneRes *plane_res; - struct crtc *crtcs; + int count_crtcs; struct encoder *encoders; + int count_encoders; struct connector *connectors; + int count_connectors; struct fb *fbs; + int count_fbs; struct plane *planes; + uint32_t count_planes; }; struct device { @@ -132,6 +135,12 @@ static inline int64_t U642I64(uint64_t val) return (int64_t)*((int64_t *)&val); } +static float mode_vrefresh(drmModeModeInfo *mode) +{ + return mode->clock * 1000.00 + / (mode->htotal * mode->vtotal); +} + #define bit_name_fn(res) \ const char * res##_str(int type) { \ unsigned int i; \ @@ -192,7 +201,7 @@ static void dump_encoders(struct device *dev) printf("Encoders:\n"); printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); - for (i = 0; i < dev->resources->res->count_encoders; i++) { + for (i = 0; i < dev->resources->count_encoders; i++) { encoder = dev->resources->encoders[i].encoder; if (!encoder) continue; @@ -207,11 +216,12 @@ static void dump_encoders(struct device *dev) printf("\n"); } -static void dump_mode(drmModeModeInfo *mode) +static void dump_mode(drmModeModeInfo *mode, int index) { - printf(" %s %d %d %d %d %d %d %d %d %d %d", + printf(" #%i %s %.2f %d %d %d %d %d %d %d %d %d", + index, mode->name, - mode->vrefresh, + mode_vrefresh(mode), mode->hdisplay, mode->hsync_start, mode->hsync_end, @@ -426,7 +436,7 @@ static void dump_connectors(struct device *dev) printf("Connectors:\n"); printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n"); - for (i = 0; i < dev->resources->res->count_connectors; i++) { + for (i = 0; i < dev->resources->count_connectors; i++) { struct connector *_connector = &dev->resources->connectors[i]; drmModeConnector *connector = _connector->connector; if (!connector) @@ -446,10 +456,10 @@ static void dump_connectors(struct device *dev) if (connector->count_modes) { printf(" modes:\n"); - printf("\tname refresh (Hz) hdisp hss hse htot vdisp " - "vss vse vtot)\n"); + printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot\n"); for (j = 0; j < connector->count_modes; j++) - dump_mode(&connector->modes[j]); + dump_mode(&connector->modes[j], j); } if (_connector->props) { @@ -470,7 +480,7 @@ static void dump_crtcs(struct device *dev) printf("CRTCs:\n"); printf("id\tfb\tpos\tsize\n"); - for (i = 0; i < dev->resources->res->count_crtcs; i++) { + for (i = 0; i < dev->resources->count_crtcs; i++) { struct crtc *_crtc = &dev->resources->crtcs[i]; drmModeCrtc *crtc = _crtc->crtc; if (!crtc) @@ -481,7 +491,7 @@ static void dump_crtcs(struct device *dev) crtc->buffer_id, crtc->x, crtc->y, crtc->width, crtc->height); - dump_mode(&crtc->mode); + dump_mode(&crtc->mode, 0); if (_crtc->props) { printf(" props:\n"); @@ -503,7 +513,7 @@ static void dump_framebuffers(struct device *dev) printf("Frame buffers:\n"); printf("id\tsize\tpitch\n"); - for (i = 0; i < dev->resources->res->count_fbs; i++) { + for (i = 0; i < dev->resources->count_fbs; i++) { fb = dev->resources->fbs[i].fb; if (!fb) continue; @@ -523,10 +533,7 @@ static void dump_planes(struct device *dev) printf("Planes:\n"); printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); - if (!dev->resources->plane_res) - return; - - for (i = 0; i < dev->resources->plane_res->count_planes; i++) { + for (i = 0; i < dev->resources->count_planes; i++) { struct plane *plane = &dev->resources->planes[i]; drmModePlane *ovr = plane->plane; if (!ovr) @@ -567,11 +574,11 @@ static void free_resources(struct resources *res) if (!res) return; -#define free_resource(_res, __res, type, Type) \ +#define free_resource(_res, type, Type) \ do { \ if (!(_res)->type##s) \ break; \ - for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ if (!(_res)->type##s[i].type) \ break; \ drmModeFree##Type((_res)->type##s[i].type); \ @@ -579,42 +586,38 @@ static void free_resources(struct resources *res) free((_res)->type##s); \ } while (0) -#define free_properties(_res, __res, type) \ +#define free_properties(_res, type) \ do { \ - for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ - drmModeFreeObjectProperties(res->type##s[i].props); \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ + unsigned int j; \ + for (j = 0; j < res->type##s[i].props->count_props; ++j)\ + drmModeFreeProperty(res->type##s[i].props_info[j]);\ free(res->type##s[i].props_info); \ + drmModeFreeObjectProperties(res->type##s[i].props); \ } \ } while (0) - if (res->res) { - free_properties(res, res, crtc); - - free_resource(res, res, crtc, Crtc); - free_resource(res, res, encoder, Encoder); + free_properties(res, plane); + free_resource(res, plane, Plane); - for (i = 0; i < res->res->count_connectors; i++) - free(res->connectors[i].name); + free_properties(res, connector); + free_properties(res, crtc); - free_resource(res, res, connector, Connector); - free_resource(res, res, fb, FB); + for (i = 0; i < res->count_connectors; i++) + free(res->connectors[i].name); - drmModeFreeResources(res->res); - } - - if (res->plane_res) { - free_properties(res, plane_res, plane); - - free_resource(res, plane_res, plane, Plane); - - drmModeFreePlaneResources(res->plane_res); - } + free_resource(res, fb, FB); + free_resource(res, connector, Connector); + free_resource(res, encoder, Encoder); + free_resource(res, crtc, Crtc); free(res); } static struct resources *get_resources(struct device *dev) { + drmModeRes *_res; + drmModePlaneRes *plane_res; struct resources *res; int i; @@ -624,40 +627,51 @@ static struct resources *get_resources(struct device *dev) drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - res->res = drmModeGetResources(dev->fd); - if (!res->res) { + _res = drmModeGetResources(dev->fd); + if (!_res) { fprintf(stderr, "drmModeGetResources failed: %s\n", strerror(errno)); - goto error; + free(res); + return NULL; } - res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs)); - res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders)); - res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors)); - res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs)); + res->count_crtcs = _res->count_crtcs; + res->count_encoders = _res->count_encoders; + res->count_connectors = _res->count_connectors; + res->count_fbs = _res->count_fbs; - if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) + res->crtcs = calloc(res->count_crtcs, sizeof(*res->crtcs)); + res->encoders = calloc(res->count_encoders, sizeof(*res->encoders)); + res->connectors = calloc(res->count_connectors, sizeof(*res->connectors)); + res->fbs = calloc(res->count_fbs, sizeof(*res->fbs)); + + if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) { + drmModeFreeResources(_res); goto error; + } #define get_resource(_res, __res, type, Type) \ do { \ - for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ - (_res)->type##s[i].type = \ - drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \ - if (!(_res)->type##s[i].type) \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ + uint32_t type##id = (__res)->type##s[i]; \ + (_res)->type##s[i].type = \ + drmModeGet##Type(dev->fd, type##id); \ + if (!(_res)->type##s[i].type) \ fprintf(stderr, "could not get %s %i: %s\n", \ - #type, (_res)->__res->type##s[i], \ + #type, type##id, \ strerror(errno)); \ } \ } while (0) - get_resource(res, res, crtc, Crtc); - get_resource(res, res, encoder, Encoder); - get_resource(res, res, connector, Connector); - get_resource(res, res, fb, FB); + get_resource(res, _res, crtc, Crtc); + get_resource(res, _res, encoder, Encoder); + get_resource(res, _res, connector, Connector); + get_resource(res, _res, fb, FB); + + drmModeFreeResources(_res); /* Set the name of all connectors based on the type name and the per-type ID. */ - for (i = 0; i < res->res->count_connectors; i++) { + for (i = 0; i < res->count_connectors; i++) { struct connector *connector = &res->connectors[i]; drmModeConnector *conn = connector->connector; int num; @@ -669,9 +683,9 @@ static struct resources *get_resources(struct device *dev) goto error; } -#define get_properties(_res, __res, type, Type) \ +#define get_properties(_res, type, Type) \ do { \ - for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ struct type *obj = &res->type##s[i]; \ unsigned int j; \ obj->props = \ @@ -694,25 +708,30 @@ static struct resources *get_resources(struct device *dev) } \ } while (0) - get_properties(res, res, crtc, CRTC); - get_properties(res, res, connector, CONNECTOR); + get_properties(res, crtc, CRTC); + get_properties(res, connector, CONNECTOR); - for (i = 0; i < res->res->count_crtcs; ++i) + for (i = 0; i < res->count_crtcs; ++i) res->crtcs[i].mode = &res->crtcs[i].crtc->mode; - res->plane_res = drmModeGetPlaneResources(dev->fd); - if (!res->plane_res) { + plane_res = drmModeGetPlaneResources(dev->fd); + if (!plane_res) { fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", strerror(errno)); return res; } - res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes)); - if (!res->planes) + res->count_planes = plane_res->count_planes; + + res->planes = calloc(res->count_planes, sizeof(*res->planes)); + if (!res->planes) { + drmModeFreePlaneResources(plane_res); goto error; + } get_resource(res, plane_res, plane, Plane); - get_properties(res, plane_res, plane, PLANE); + drmModeFreePlaneResources(plane_res); + get_properties(res, plane, PLANE); return res; @@ -721,17 +740,31 @@ error: return NULL; } -static int get_crtc_index(struct device *dev, uint32_t id) +static struct crtc *get_crtc_by_id(struct device *dev, uint32_t id) { int i; - for (i = 0; i < dev->resources->res->count_crtcs; ++i) { + for (i = 0; i < dev->resources->count_crtcs; ++i) { drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; if (crtc && crtc->crtc_id == id) - return i; + return &dev->resources->crtcs[i]; } - return -1; + return NULL; +} + +static uint32_t get_crtc_mask(struct device *dev, struct crtc *crtc) +{ + unsigned int i; + + for (i = 0; i < (unsigned int)dev->resources->count_crtcs; i++) { + if (crtc->crtc->crtc_id == dev->resources->crtcs[i].crtc->crtc_id) + return 1 << i; + } + /* Unreachable: crtc->crtc is one of resources->crtcs[] */ + /* Don't return zero or static analysers will complain */ + abort(); + return 0; } static drmModeConnector *get_connector_by_name(struct device *dev, const char *name) @@ -739,7 +772,7 @@ static drmModeConnector *get_connector_by_name(struct device *dev, const char *n struct connector *connector; int i; - for (i = 0; i < dev->resources->res->count_connectors; i++) { + for (i = 0; i < dev->resources->count_connectors; i++) { connector = &dev->resources->connectors[i]; if (strcmp(connector->name, name) == 0) @@ -754,7 +787,7 @@ static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) drmModeConnector *connector; int i; - for (i = 0; i < dev->resources->res->count_connectors; i++) { + for (i = 0; i < dev->resources->count_connectors; i++) { connector = dev->resources->connectors[i].connector; if (connector && connector->connector_id == id) return connector; @@ -768,7 +801,7 @@ static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) drmModeEncoder *encoder; int i; - for (i = 0; i < dev->resources->res->count_encoders; i++) { + for (i = 0; i < dev->resources->count_encoders; i++) { encoder = dev->resources->encoders[i].encoder; if (encoder && encoder->encoder_id == id) return encoder; @@ -795,7 +828,7 @@ struct pipe_arg { uint32_t crtc_id; char mode_str[64]; char format_str[5]; - unsigned int vrefresh; + float vrefresh; unsigned int fourcc; drmModeModeInfo *mode; struct crtc *crtc; @@ -822,7 +855,7 @@ struct plane_arg { static drmModeModeInfo * connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, - const unsigned int vrefresh) + const float vrefresh) { drmModeConnector *connector; drmModeModeInfo *mode; @@ -832,16 +865,27 @@ connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, if (!connector || !connector->count_modes) return NULL; + /* Pick by Index */ + if (mode_str[0] == '#') { + int index = atoi(mode_str + 1); + + if (index >= connector->count_modes || index < 0) + return NULL; + return &connector->modes[index]; + } + + /* Pick by Name */ for (i = 0; i < connector->count_modes; i++) { mode = &connector->modes[i]; if (!strcmp(mode->name, mode_str)) { - /* If the vertical refresh frequency is not specified then return the - * first mode that match with the name. Else, return the mode that match - * the name and the specified vertical refresh frequency. + /* If the vertical refresh frequency is not specified + * then return the first mode that match with the name. + * Else, return the mode that match the name and + * the specified vertical refresh frequency. */ if (vrefresh == 0) return mode; - else if (mode->vrefresh == vrefresh) + else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005) return mode; } } @@ -861,7 +905,7 @@ static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) uint32_t crtcs_for_connector = 0; drmModeConnector *connector; drmModeEncoder *encoder; - int idx; + struct crtc *crtc; connector = get_connector_by_id(dev, pipe->con_ids[i]); if (!connector) @@ -873,10 +917,10 @@ static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) continue; crtcs_for_connector |= encoder->possible_crtcs; - - idx = get_crtc_index(dev, encoder->crtc_id); - if (idx >= 0) - active_crtcs |= 1 << idx; + crtc = get_crtc_by_id(dev, encoder->crtc_id); + if (!crtc) + continue; + active_crtcs |= get_crtc_mask(dev, crtc); } possible_crtcs &= crtcs_for_connector; @@ -907,7 +951,13 @@ static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) mode = connector_find_mode(dev, pipe->con_ids[i], pipe->mode_str, pipe->vrefresh); if (mode == NULL) { - fprintf(stderr, + if (pipe->vrefresh) + fprintf(stderr, + "failed to find mode " + "\"%s-%.2fHz\" for connector %s\n", + pipe->mode_str, pipe->vrefresh, pipe->cons[i]); + else + fprintf(stderr, "failed to find mode \"%s\" for connector %s\n", pipe->mode_str, pipe->cons[i]); return -EINVAL; @@ -918,16 +968,10 @@ static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) * locate a CRTC that can be attached to all the connectors. */ if (pipe->crtc_id != (uint32_t)-1) { - for (i = 0; i < dev->resources->res->count_crtcs; i++) { - struct crtc *crtc = &dev->resources->crtcs[i]; - - if (pipe->crtc_id == crtc->crtc->crtc_id) { - pipe->crtc = crtc; - break; - } - } + pipe->crtc = get_crtc_by_id(dev, pipe->crtc_id); } else { pipe->crtc = pipe_find_crtc(dev, pipe); + pipe->crtc_id = pipe->crtc->crtc->crtc_id; } if (!pipe->crtc) { @@ -965,9 +1009,9 @@ static bool set_property(struct device *dev, struct property_arg *p) p->obj_type = 0; p->prop_id = 0; -#define find_object(_res, __res, type, Type) \ +#define find_object(_res, type, Type) \ do { \ - for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ struct type *obj = &(_res)->type##s[i]; \ if (obj->type->type##_id != p->obj_id) \ continue; \ @@ -978,11 +1022,11 @@ static bool set_property(struct device *dev, struct property_arg *p) } \ } while(0) \ - find_object(dev->resources, res, crtc, CRTC); + find_object(dev->resources, crtc, CRTC); if (p->obj_type == 0) - find_object(dev->resources, res, connector, CONNECTOR); + find_object(dev->resources, connector, CONNECTOR); if (p->obj_type == 0) - find_object(dev->resources, plane_res, plane, PLANE); + find_object(dev->resources, plane, PLANE); if (p->obj_type == 0) { fprintf(stderr, "Object %i not found, can't set property\n", p->obj_id); @@ -1041,7 +1085,7 @@ page_flip_handler(int fd, unsigned int frame, else new_fb_id = pipe->fb_id[0]; - drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id, + drmModePageFlip(fd, pipe->crtc_id, new_fb_id, DRM_MODE_PAGE_FLIP_EVENT, pipe); pipe->current_fb_id = new_fb_id; pipe->swap_count++; @@ -1128,26 +1172,41 @@ static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc) } } +static int +bo_fb_create(int fd, unsigned int fourcc, const uint32_t w, const uint32_t h, + enum util_fill_pattern pat, struct bo **out_bo, unsigned int *out_fb_id) +{ + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + struct bo *bo; + unsigned int fb_id; + + bo = bo_create(fd, fourcc, w, h, handles, pitches, offsets, pat); + + if (bo == NULL) + return -1; + + if (drmModeAddFB2(fd, w, h, fourcc, handles, pitches, offsets, &fb_id, 0)) { + fprintf(stderr, "failed to add fb (%ux%u): %s\n", w, h, strerror(errno)); + bo_destroy(bo); + return -1; + } + *out_bo = bo; + *out_fb_id = fb_id; + return 0; +} + 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; - } - } - + crtc = get_crtc_by_id(dev, p->crtc_id); if (!crtc) { fprintf(stderr, "CRTC %u not found\n", p->crtc_id); return -1; @@ -1161,17 +1220,9 @@ static int atomic_set_plane(struct device *dev, struct plane_arg *p, 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)); + if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, + pattern, &plane_bo, &p->fb_id)) return -1; - } } p->bo = plane_bo; @@ -1207,34 +1258,23 @@ static int atomic_set_plane(struct device *dev, struct plane_arg *p, static int set_plane(struct device *dev, struct plane_arg *p) { drmModePlane *ovr; - uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; uint32_t plane_id; - struct bo *plane_bo; - uint32_t plane_flags = 0; int crtc_x, crtc_y, crtc_w, crtc_h; struct crtc *crtc = NULL; - unsigned int pipe; - unsigned int i; + unsigned int i, crtc_mask; /* 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]; - pipe = i; - break; - } - } - + crtc = get_crtc_by_id(dev, p->crtc_id); if (!crtc) { fprintf(stderr, "CRTC %u not found\n", p->crtc_id); return -1; } - + crtc_mask = get_crtc_mask(dev, crtc); plane_id = p->plane_id; - for (i = 0; i < dev->resources->plane_res->count_planes; i++) { + for (i = 0; i < dev->resources->count_planes; i++) { ovr = dev->resources->planes[i].plane; if (!ovr) continue; @@ -1245,35 +1285,26 @@ static int set_plane(struct device *dev, struct plane_arg *p) if (!format_support(ovr, p->fourcc)) continue; - if ((ovr->possible_crtcs & (1 << pipe)) && + if ((ovr->possible_crtcs & crtc_mask) && (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) { plane_id = ovr->plane_id; break; } } - if (i == dev->resources->plane_res->count_planes) { + if (i == dev->resources->count_planes) { fprintf(stderr, "no unused plane available for CRTC %u\n", - crtc->crtc->crtc_id); + p->crtc_id); return -1; } fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", p->w, p->h, p->format_str, plane_id); - plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles, - pitches, offsets, secondary_fill); - if (plane_bo == NULL) - return -1; - - p->bo = plane_bo; - /* just use single plane format for now.. */ - if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc, - handles, pitches, offsets, &p->fb_id, plane_flags)) { - fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); + if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, + secondary_fill, &p->bo, &p->fb_id)) return -1; - } crtc_w = p->w * p->scale; crtc_h = p->h * p->scale; @@ -1287,15 +1318,15 @@ static int set_plane(struct device *dev, struct plane_arg *p) } /* note src coords (last 4 args) are in Q16 format */ - if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id, - plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, + if (drmModeSetPlane(dev->fd, plane_id, p->crtc_id, p->fb_id, + 0, crtc_x, crtc_y, crtc_w, crtc_h, 0, 0, p->w << 16, p->h << 16)) { fprintf(stderr, "failed to enable plane: %s\n", strerror(errno)); return -1; } - ovr->crtc_id = crtc->crtc->crtc_id; + ovr->crtc_id = p->crtc_id; return 0; } @@ -1317,6 +1348,41 @@ static void atomic_set_planes(struct device *dev, struct plane_arg *p, } } +static void +atomic_test_page_flip(struct device *dev, struct pipe_arg *pipe_args, + struct plane_arg *plane_args, unsigned int plane_count) +{ + int ret; + + gettimeofday(&pipe_args->start, NULL); + pipe_args->swap_count = 0; + + while (true) { + 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; + } + + 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; + } + } +} + static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) { unsigned int i; @@ -1372,131 +1438,269 @@ static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int c } } -static void atomic_set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) +static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) { + drmModeConnector *connector; unsigned int i; - unsigned int j; - int ret; + uint32_t id; + char *endp; - for (i = 0; i < count; i++) { - struct pipe_arg *pipe = &pipes[i]; + for (i = 0; i < pipe->num_cons; i++) { + id = strtoul(pipe->cons[i], &endp, 10); + if (endp == pipe->cons[i]) { + connector = get_connector_by_name(dev, pipe->cons[i]); + if (!connector) { + fprintf(stderr, "no connector named '%s'\n", + pipe->cons[i]); + return -ENODEV; + } - ret = pipe_find_crtc_and_mode(dev, pipe); - if (ret < 0) + id = connector->connector_id; + } + + pipe->con_ids[i] = id; + } + + return 0; +} + +static int pipe_attempt_connector(struct device *dev, drmModeConnector *con, + struct pipe_arg *pipe) +{ + char *con_str; + int i; + + con_str = calloc(8, sizeof(char)); + if (!con_str) + return -1; + + sprintf(con_str, "%d", con->connector_id); + strcpy(pipe->format_str, "XR24"); + pipe->fourcc = util_format_fourcc(pipe->format_str); + pipe->num_cons = 1; + pipe->con_ids = calloc(1, sizeof(*pipe->con_ids)); + pipe->cons = calloc(1, sizeof(*pipe->cons)); + + if (!pipe->con_ids || !pipe->cons) + goto free_con_str; + + pipe->con_ids[0] = con->connector_id; + pipe->cons[0] = (const char*)con_str; + + pipe->crtc = pipe_find_crtc(dev, pipe); + if (!pipe->crtc) + goto free_all; + + pipe->crtc_id = pipe->crtc->crtc->crtc_id; + + /* Return the first mode if no preferred. */ + pipe->mode = &con->modes[0]; + + for (i = 0; i < con->count_modes; i++) { + drmModeModeInfo *current_mode = &con->modes[i]; + + if (current_mode->type & DRM_MODE_TYPE_PREFERRED) { + pipe->mode = current_mode; + break; + } + } + + sprintf(pipe->mode_str, "%dx%d", pipe->mode->hdisplay, pipe->mode->vdisplay); + + return 0; + +free_all: + free(pipe->cons); + free(pipe->con_ids); +free_con_str: + free(con_str); + return -1; +} + +static int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes) +{ + struct pipe_arg *pipes; + struct resources *res = dev->resources; + drmModeConnector *con = NULL; + int i, connected = 0, attempted = 0; + + for (i = 0; i < res->count_connectors; i++) { + con = res->connectors[i].connector; + if (!con || con->connection != DRM_MODE_CONNECTED) continue; + connected++; + } + if (!connected) { + printf("no connected connector!\n"); + return 0; } - for (i = 0; i < count; i++) { - struct pipe_arg *pipe = &pipes[i]; - uint32_t blob_id; + pipes = calloc(connected, sizeof(struct pipe_arg)); + if (!pipes) + return 0; - if (pipe->mode == NULL) + for (i = 0; i < res->count_connectors && attempted < connected; i++) { + con = res->connectors[i].connector; + if (!con || con->connection != DRM_MODE_CONNECTED) continue; - printf("setting mode %s-%dHz on connectors ", - pipe->mode_str, pipe->mode->vrefresh); - 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); + if (pipe_attempt_connector(dev, con, &pipes[attempted]) < 0) { + printf("failed fetching preferred mode for connector\n"); + continue; } - 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); + attempted++; } + + *out_pipes = pipes; + return attempted; } -static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) +static struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc *crtc) { unsigned int i; - unsigned int j; - for (i = 0; i < count; i++) { - struct pipe_arg *pipe = &pipes[i]; - - if (pipe->mode == NULL) + for (i = 0; i < dev->resources->count_planes; i++) { + struct plane *plane = &dev->resources->planes[i]; + drmModePlane *ovr = plane->plane; + if (!ovr) continue; - for (j = 0; j < pipe->num_cons; ++j) - add_property(dev, pipe->con_ids[j], "CRTC_ID",0); + // XXX: add is_primary_plane and (?) format checks - add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", 0); - add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 0); + if (ovr->possible_crtcs & get_crtc_mask(dev, crtc)) + return plane; } + return NULL; } static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) { - uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; - unsigned int fb_id; - struct bo *bo; - unsigned int i; - unsigned int j; - int ret, x; - - dev->mode.width = 0; - dev->mode.height = 0; - dev->mode.fb_id = 0; + unsigned int i, j; + int ret, x = 0; + int preferred = count == 0; for (i = 0; i < count; i++) { struct pipe_arg *pipe = &pipes[i]; + ret = pipe_resolve_connectors(dev, pipe); + if (ret < 0) + return; + ret = pipe_find_crtc_and_mode(dev, pipe); if (ret < 0) continue; + } + if (preferred) { + struct pipe_arg *pipe_args; - dev->mode.width += pipe->mode->hdisplay; - if (dev->mode.height < pipe->mode->vdisplay) - dev->mode.height = pipe->mode->vdisplay; + count = pipe_find_preferred(dev, &pipe_args); + if (!count) { + fprintf(stderr, "can't find any preferred connector/mode.\n"); + return; + } + pipes = pipe_args; } - bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width, - dev->mode.height, handles, pitches, offsets, - primary_fill); - if (bo == NULL) - return; + if (!dev->use_atomic) { + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; - dev->mode.bo = bo; + if (pipe->mode == NULL) + continue; - ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, - pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0); - if (ret) { - fprintf(stderr, "failed to add fb (%ux%u): %s\n", - dev->mode.width, dev->mode.height, strerror(errno)); - return; - } + if (!preferred) { + dev->mode.width += pipe->mode->hdisplay; + if (dev->mode.height < pipe->mode->vdisplay) + dev->mode.height = pipe->mode->vdisplay; + } else { + /* XXX: Use a clone mode, more like atomic. We could do per + * connector bo/fb, so we don't have the stretched image. + */ + if (dev->mode.width < pipe->mode->hdisplay) + dev->mode.width = pipe->mode->hdisplay; + if (dev->mode.height < pipe->mode->vdisplay) + dev->mode.height = pipe->mode->vdisplay; + } + } - dev->mode.fb_id = fb_id; + if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, + primary_fill, &dev->mode.bo, &dev->mode.fb_id)) + return; + } - x = 0; 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("setting mode %s-%.2fHz on connectors ", + pipe->mode->name, mode_vrefresh(pipe->mode)); + for (j = 0; j < pipe->num_cons; ++j) { printf("%s, ", pipe->cons[j]); - printf("crtc %d\n", pipe->crtc->crtc->crtc_id); + if (dev->use_atomic) + add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc_id); + } + printf("crtc %d\n", pipe->crtc_id); - ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id, - x, 0, pipe->con_ids, pipe->num_cons, - pipe->mode); + if (!dev->use_atomic) { + ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, dev->mode.fb_id, + x, 0, pipe->con_ids, pipe->num_cons, + pipe->mode); - /* XXX: Actually check if this is needed */ - drmModeDirtyFB(dev->fd, fb_id, NULL, 0); + /* XXX: Actually check if this is needed */ + drmModeDirtyFB(dev->fd, dev->mode.fb_id, NULL, 0); - x += pipe->mode->hdisplay; + if (!preferred) + x += pipe->mode->hdisplay; - if (ret) { - fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); - return; + if (ret) { + fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); + return; + } + + set_gamma(dev, pipe->crtc_id, pipe->fourcc); + } else { + drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id); + add_property(dev, pipe->crtc_id, "MODE_ID", blob_id); + add_property(dev, pipe->crtc_id, "ACTIVE", 1); + + /* By default atomic modeset does not set a primary plane, shrug */ + if (preferred) { + struct plane *plane = get_primary_plane_by_crtc(dev, pipe->crtc); + struct plane_arg plane_args = { + .plane_id = plane->plane->plane_id, + .crtc_id = pipe->crtc_id, + .w = pipe->mode->hdisplay, + .h = pipe->mode->vdisplay, + .scale = 1.0, + .format_str = "XR24", + .fourcc = util_format_fourcc(pipe->format_str), + }; + + atomic_set_planes(dev, &plane_args, 1, false); + } } + } +} + +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]; - set_gamma(dev, pipe->crtc->crtc->crtc_id, pipe->fourcc); + 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_id, "MODE_ID", 0); + add_property(dev, pipe->crtc_id, "ACTIVE", 0); } } @@ -1542,7 +1746,7 @@ static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int for (i = 0; i < count; i++) { struct pipe_arg *pipe = &pipes[i]; ret = cursor_init(dev->fd, handles[0], - pipe->crtc->crtc->crtc_id, + pipe->crtc_id, pipe->mode->hdisplay, pipe->mode->vdisplay, cw, ch); if (ret) { @@ -1565,34 +1769,23 @@ static void clear_cursors(struct device *dev) static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) { - uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; unsigned int other_fb_id; struct bo *other_bo; drmEventContext evctx; unsigned int i; int ret; - other_bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width, - dev->mode.height, handles, pitches, offsets, - UTIL_PATTERN_PLAIN); - if (other_bo == NULL) + if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, + UTIL_PATTERN_PLAIN, &other_bo, &other_fb_id)) return; - ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, - pipes[0].fourcc, handles, pitches, offsets, - &other_fb_id, 0); - if (ret) { - fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); - goto err; - } - for (i = 0; i < count; i++) { struct pipe_arg *pipe = &pipes[i]; if (pipe->mode == NULL) continue; - ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id, + ret = drmModePageFlip(dev->fd, pipe->crtc_id, other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, pipe); if (ret) { @@ -1650,7 +1843,6 @@ static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned err_rmfb: drmModeRmFB(dev->fd, other_fb_id); -err: bo_destroy(other_bo); } @@ -1695,6 +1887,8 @@ static int parse_connector(struct pipe_arg *pipe, const char *arg) return -1; /* Parse the remaining parameters. */ + if (!endp) + return -1; if (*endp == '@') { arg = endp + 1; pipe->crtc_id = strtoul(arg, &endp, 10); @@ -1713,7 +1907,7 @@ static int parse_connector(struct pipe_arg *pipe, const char *arg) pipe->mode_str[len] = '\0'; if (*p == '-') { - pipe->vrefresh = strtoul(p + 1, &endp, 10); + pipe->vrefresh = strtof(p + 1, &endp); p = endp; } @@ -1811,7 +2005,7 @@ static void parse_fill_patterns(char *arg) static void usage(char *name) { - fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name); + fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name); fprintf(stderr, "\n Query options:\n\n"); fprintf(stderr, "\t-c\tlist connectors\n"); @@ -1821,9 +2015,10 @@ static void usage(char *name) fprintf(stderr, "\n Test options:\n\n"); fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); - fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n"); + fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>]\tset a mode\n"); fprintf(stderr, "\t-C\ttest hw cursor\n"); fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); + fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n"); fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); fprintf(stderr, "\t-a \tuse atomic API\n"); fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n"); @@ -1837,60 +2032,7 @@ static void usage(char *name) exit(0); } -static int page_flipping_supported(void) -{ - /*FIXME: generic ioctl needed? */ - return 1; -#if 0 - int ret, value; - struct drm_i915_getparam gp; - - gp.param = I915_PARAM_HAS_PAGEFLIPPING; - gp.value = &value; - - ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); - if (ret) { - fprintf(stderr, "drm_i915_getparam: %m\n"); - return 0; - } - - return *gp.value; -#endif -} - -static int cursor_supported(void) -{ - /*FIXME: generic ioctl needed? */ - return 1; -} - -static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) -{ - drmModeConnector *connector; - unsigned int i; - uint32_t id; - char *endp; - - for (i = 0; i < pipe->num_cons; i++) { - id = strtoul(pipe->cons[i], &endp, 10); - if (endp == pipe->cons[i]) { - connector = get_connector_by_name(dev, pipe->cons[i]); - if (!connector) { - fprintf(stderr, "no connector named '%s'\n", - pipe->cons[i]); - return -ENODEV; - } - - id = connector->connector_id; - } - - pipe->con_ids[i] = id; - } - - return 0; -} - -static char optstr[] = "acdD:efF:M:P:ps:Cvw:"; +static char optstr[] = "acdD:efF:M:P:ps:Cvrw:"; int main(int argc, char **argv) { @@ -1901,6 +2043,7 @@ int main(int argc, char **argv) int drop_master = 0; int test_vsync = 0; int test_cursor = 0; + int set_preferred = 0; int use_atomic = 0; char *device = NULL; char *module = NULL; @@ -1922,12 +2065,15 @@ int main(int argc, char **argv) switch (c) { case 'a': use_atomic = 1; + /* Preserve the default behaviour of dumping all information. */ + args--; break; case 'c': connectors = 1; break; case 'D': device = optarg; + /* Preserve the default behaviour of dumping all information. */ args--; break; case 'd': @@ -1985,6 +2131,9 @@ int main(int argc, char **argv) case 'v': test_vsync = 1; break; + case 'r': + set_preferred = 1; + break; case 'w': prop_args = realloc(prop_args, (prop_count + 1) * sizeof *prop_args); @@ -2005,51 +2154,45 @@ int main(int argc, char **argv) } } - if (!args || (args == 1 && use_atomic)) + /* Dump all the details when no* arguments are provided. */ + if (!args) 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); + if (test_vsync && !count) { + fprintf(stderr, "page flipping requires at least one -s option.\n"); return -1; } - - dev.use_atomic = use_atomic; - - if (test_vsync && !page_flipping_supported()) { - fprintf(stderr, "page flipping not supported by drm.\n"); + if (set_preferred && count) { + fprintf(stderr, "cannot use -r (preferred) when -s (mode) is set\n"); return -1; } - if (test_vsync && !count) { - fprintf(stderr, "page flipping requires at least one -s option.\n"); + if (set_preferred && plane_count) { + fprintf(stderr, "cannot use -r (preferred) when -P (plane) is set\n"); return -1; } - if (test_cursor && !cursor_supported()) { - fprintf(stderr, "hw cursor not supported by drm.\n"); + dev.fd = util_open(device, module); + if (dev.fd < 0) return -1; + + if (use_atomic) { + ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1); + if (ret) { + fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno)); + drmClose(dev.fd); + return -1; + } } + dev.use_atomic = use_atomic; + dev.resources = get_resources(&dev); if (!dev.resources) { drmClose(dev.fd); return 1; } - for (i = 0; i < count; i++) { - if (pipe_resolve_connectors(&dev, &pipe_args[i]) < 0) { - free_resources(dev.resources); - drmClose(dev.fd); - return 1; - } - } - #define dump_resource(dev, res) if (res) dump_##res(dev) dump_resource(&dev, encoders); @@ -2064,7 +2207,7 @@ int main(int argc, char **argv) if (dev.use_atomic) { dev.req = drmModeAtomicAlloc(); - if (count && plane_count) { + if (set_preferred || (count && plane_count)) { uint64_t cap = 0; ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); @@ -2073,8 +2216,11 @@ int main(int argc, char **argv) return 1; } - atomic_set_mode(&dev, pipe_args, count); - atomic_set_planes(&dev, plane_args, plane_count, false); + if (set_preferred || count) + set_mode(&dev, pipe_args, count); + + if (plane_count) + atomic_set_planes(&dev, plane_args, plane_count, false); ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); if (ret) { @@ -2082,33 +2228,8 @@ int main(int argc, char **argv) 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 (test_vsync) + atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count); if (drop_master) drmDropMaster(dev.fd); @@ -2118,20 +2239,24 @@ int main(int argc, char **argv) drmModeAtomicFree(dev.req); dev.req = drmModeAtomicAlloc(); - atomic_clear_mode(&dev, pipe_args, count); - atomic_clear_planes(&dev, plane_args, plane_count); + /* XXX: properly teardown the preferred mode/plane state */ + if (plane_count) + atomic_clear_planes(&dev, plane_args, plane_count); + + if (count) + atomic_clear_mode(&dev, pipe_args, count); + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); - if (ret) { + if (ret) fprintf(stderr, "Atomic Commit failed\n"); - return 1; - } - atomic_clear_FB(&dev, plane_args, plane_count); + if (plane_count) + atomic_clear_FB(&dev, plane_args, plane_count); } drmModeAtomicFree(dev.req); } else { - if (count || plane_count) { + if (set_preferred || count || plane_count) { uint64_t cap = 0; ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); @@ -2140,7 +2265,7 @@ int main(int argc, char **argv) return 1; } - if (count) + if (set_preferred || count) set_mode(&dev, pipe_args, count); if (plane_count) @@ -2163,12 +2288,13 @@ int main(int argc, char **argv) if (plane_count) clear_planes(&dev, plane_args, plane_count); - if (count) + if (set_preferred || count) clear_mode(&dev); } } free_resources(dev.resources); + drmClose(dev.fd); return 0; } diff --git a/lib/libdrm/tests/nouveau/.gitignore b/lib/libdrm/tests/nouveau/.gitignore new file mode 100644 index 000000000..837bfb912 --- /dev/null +++ b/lib/libdrm/tests/nouveau/.gitignore @@ -0,0 +1 @@ +threaded diff --git a/lib/libdrm/tests/nouveau/threaded.c b/lib/libdrm/tests/nouveau/threaded.c index 3669bcd32..ddbac74ec 100644 --- a/lib/libdrm/tests/nouveau/threaded.c +++ b/lib/libdrm/tests/nouveau/threaded.c @@ -36,7 +36,11 @@ static int failed; static int import_fd; +#if defined(__GLIBC__) || defined(__FreeBSD__) int ioctl(int fd, unsigned long request, ...) +#else +int ioctl(int fd, int request, ...) +#endif { va_list va; int ret; diff --git a/lib/libdrm/tests/proptest/Android.mk b/lib/libdrm/tests/proptest/Android.mk new file mode 100644 index 000000000..91a590fc9 --- /dev/null +++ b/lib/libdrm/tests/proptest/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_SRC_FILES := $(PROPTEST_FILES) + +LOCAL_MODULE := proptest + +LOCAL_SHARED_LIBRARIES := libdrm +LOCAL_STATIC_LIBRARIES := libdrm_util + +include $(LIBDRM_COMMON_MK) +include $(BUILD_EXECUTABLE) diff --git a/lib/libdrm/tests/tegra/.gitignore b/lib/libdrm/tests/tegra/.gitignore new file mode 100644 index 000000000..5c5216c5c --- /dev/null +++ b/lib/libdrm/tests/tegra/.gitignore @@ -0,0 +1 @@ +openclose diff --git a/lib/libdrm/tests/ttmtest/AUTHORS b/lib/libdrm/tests/ttmtest/AUTHORS new file mode 100644 index 000000000..fa4a089d1 --- /dev/null +++ b/lib/libdrm/tests/ttmtest/AUTHORS @@ -0,0 +1 @@ +Thomas Hellström <thomas-at-tungstengraphics.com> and others. diff --git a/lib/libdrm/tests/ttmtest/ChangeLog b/lib/libdrm/tests/ttmtest/ChangeLog new file mode 100644 index 000000000..4588c8db1 --- /dev/null +++ b/lib/libdrm/tests/ttmtest/ChangeLog @@ -0,0 +1,23 @@ +2006-01-24 Thomas Hellström <thomas-at-tungstengraphics.com> + + * configure.ac: + * src/ttmtest.c: + + Fixed include path. + +2006-01-24 Thomas Hellström <thomas-at-tungstengraphics.com> + + * AUTHORS: + * Makefile.am: + * configure.ac: + * reconf: + * src/Makefile.am: + * src/ttmtest.c: (fastrdtsc), (time_diff), (releaseContext), + (testAGP), (main): + * src/xf86dri.c: (uniDRIDestroyContext), (uniDRICreateDrawable), + (uniDRIDestroyDrawable), (uniDRIGetDrawableInfo): + * src/xf86dri.h: + * src/xf86dristr.h: + + Initial import of the ttmtest utility. +
\ No newline at end of file diff --git a/lib/libdrm/tests/ttmtest/Makefile.am b/lib/libdrm/tests/ttmtest/Makefile.am new file mode 100644 index 000000000..af437a64d --- /dev/null +++ b/lib/libdrm/tests/ttmtest/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/lib/libdrm/tests/ttmtest/NEWS b/lib/libdrm/tests/ttmtest/NEWS new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/lib/libdrm/tests/ttmtest/NEWS diff --git a/lib/libdrm/tests/ttmtest/README b/lib/libdrm/tests/ttmtest/README new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/lib/libdrm/tests/ttmtest/README diff --git a/lib/libdrm/tests/ttmtest/configure.ac b/lib/libdrm/tests/ttmtest/configure.ac new file mode 100644 index 000000000..c41e91ac0 --- /dev/null +++ b/lib/libdrm/tests/ttmtest/configure.ac @@ -0,0 +1,33 @@ +AC_INIT +AC_PROG_CC +AC_PATH_X +if test "x$no_x" != "xyes"; then + savecpp="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -I$x_includes" + AC_CHECK_HEADER($x_includes/X11/Xlib.h,,\ + [AC_MSG_ERROR(Could not find X installation.)]) + CPPFLAGS="$savecpp" + MDRIINC="-I$x_includes" + LIBS="-L$x_libraries $LIBS" +else + AC_MSG_ERROR(Could not find X installation. Aborting.) +fi +AC_ARG_WITH(libdrm, + AC_HELP_STRING([--with-libdrm=DIR], + [Installation prefix of libdrm [[default=/usr]]]), + [libdrmpref="$withval"], + [libdrmpref="/usr"]) +savecpp="$CPPFLAGS" +MDRIINC="-I$libdrmpref/include -I$libdrmpref/include/drm -I$x_includes" +CPPFLAGS="$CPPFLAGS $MDRIINC" +AC_CHECK_HEADER(xf86drm.h,,\ + [AC_MSG_ERROR(Could not find libdrm installation. Use --with-libdrm=<libdrm_installation_prefix>)]) +AC_CHECK_HEADER(drm.h,,\ + [AC_MSG_ERROR(Could not find libdrm installation. Use --with-libdrm=<libdrm_installation_prefix>)]) +CPPFLAGS="$savecpp" +LIBS="-L$libdrmpref/lib64 -L$libdrmpref/lib $LIBS" +AC_SUBST(MDRIINC) +AC_SYS_LARGEFILE +AM_INIT_AUTOMAKE(minidri,0.1.0) +AM_CONFIG_HEADER(config.h) +AC_OUTPUT([Makefile src/Makefile]) diff --git a/lib/libdrm/tests/ttmtest/reconf b/lib/libdrm/tests/ttmtest/reconf new file mode 100755 index 000000000..e64d00acc --- /dev/null +++ b/lib/libdrm/tests/ttmtest/reconf @@ -0,0 +1,2 @@ +#!/bin/sh +autoreconf -v --install || exit 1
\ No newline at end of file diff --git a/lib/libdrm/tests/ttmtest/src/Makefile.am b/lib/libdrm/tests/ttmtest/src/Makefile.am new file mode 100644 index 000000000..b7ee8291b --- /dev/null +++ b/lib/libdrm/tests/ttmtest/src/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = @MDRIINC@ +bin_PROGRAMS = ttmtest +ttmtest_SOURCES = \ + ttmtest.c \ + xf86dri.c \ + xf86dri.h \ + xf86dristr.h +ttmtest_LDADD = -ldrm -lXext -lX11 diff --git a/lib/libdrm/tests/ttmtest/src/ttmtest.c b/lib/libdrm/tests/ttmtest/src/ttmtest.c new file mode 100644 index 000000000..36df24287 --- /dev/null +++ b/lib/libdrm/tests/ttmtest/src/ttmtest.c @@ -0,0 +1,430 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <stdint.h> +#include <drm/drm.h> +#include "xf86dri.h" +#include "xf86drm.h" +#include "stdio.h" +#include "sys/types.h" +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include "sys/mman.h" + +typedef struct +{ + enum + { + haveNothing, + haveDisplay, + haveConnection, + haveDriverName, + haveDeviceInfo, + haveDRM, + haveContext + } + state; + + Display *display; + int screen; + drm_handle_t sAreaOffset; + char *curBusID; + char *driverName; + int drmFD; + XVisualInfo visualInfo; + XID id; + drm_context_t hwContext; + void *driPriv; + int driPrivSize; + int fbSize; + int fbOrigin; + int fbStride; + drm_handle_t fbHandle; + int ddxDriverMajor; + int ddxDriverMinor; + int ddxDriverPatch; +} TinyDRIContext; + +#ifndef __x86_64__ +static unsigned +fastrdtsc(void) +{ + unsigned eax; + __asm__ volatile ("\t" + "pushl %%ebx\n\t" + "cpuid\n\t" ".byte 0x0f, 0x31\n\t" "popl %%ebx\n":"=a" (eax) + :"0"(0) + :"ecx", "edx", "cc"); + + return eax; +} +#else +static unsigned +fastrdtsc(void) +{ + unsigned eax; + __asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax) + :"0"(0) + :"ecx", "edx", "ebx", "cc"); + + return eax; +} +#endif + +void +bmError(int val, const char *file, const char *function, int line) +{ + fprintf(stderr, "Fatal video memory manager error \"%s\".\n" + "Check kernel logs or set the LIBGL_DEBUG\n" + "environment variable to \"verbose\" for more info.\n" + "Detected in file %s, line %d, function %s.\n", + strerror(-val), file, line, function); + abort(); +} + +#define BM_CKFATAL(val) \ + do{ \ + int tstVal = (val); \ + if (tstVal) \ + bmError(tstVal, __FILE__, __FUNCTION__, __LINE__); \ + } while(0); + +static unsigned +time_diff(unsigned t, unsigned t2) +{ + return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1)); +} + +static int +releaseContext(TinyDRIContext * ctx) +{ + switch (ctx->state) { + case haveContext: + uniDRIDestroyContext(ctx->display, ctx->screen, ctx->id); + case haveDRM: + drmClose(ctx->drmFD); + case haveDeviceInfo: + XFree(ctx->driPriv); + case haveDriverName: + XFree(ctx->driverName); + case haveConnection: + XFree(ctx->curBusID); + uniDRICloseConnection(ctx->display, ctx->screen); + case haveDisplay: + XCloseDisplay(ctx->display); + default: + break; + } + return -1; +} + +static void +readBuf(void *buf, unsigned long size) +{ + volatile unsigned *buf32 = (unsigned *)buf; + unsigned *end = (unsigned *)buf32 + size / sizeof(*buf32); + + while (buf32 < end) { + (void)*buf32++; + } +} + +static int +benchmarkBuffer(TinyDRIContext * ctx, unsigned long size, + unsigned long *ticks) +{ + unsigned long curTime, oldTime; + int ret; + drmBO buf; + void *virtual; + + /* + * Test system memory objects. + */ + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOCreate(ctx->drmFD, size, 0, NULL, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_LOCAL, 0, &buf)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOMap(ctx->drmFD, &buf, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0xF0, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0x0F, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + readBuf(virtual, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + /* + * Test TT bound buffer objects. + */ + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf, + DRM_BO_FLAG_MEM_TT, + DRM_BO_MASK_MEM, + 0,0,0)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOMap(ctx->drmFD, &buf, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0xF0, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0x0F, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + readBuf(virtual, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf)); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf, + DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEM, 0, 0,0)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + /* + * Test cached buffers objects. + */ + + oldTime = fastrdtsc(); + ret = drmBOSetStatus(ctx->drmFD, &buf, + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_CACHED | + DRM_BO_FLAG_FORCE_CACHING, + DRM_BO_MASK_MEMTYPE | + DRM_BO_FLAG_FORCE_CACHING, + 0, 0, 0); + curTime = fastrdtsc(); + + if (ret) { + printf("Couldn't bind cached. Probably no support\n"); + BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf)); + return 1; + } + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOMap(ctx->drmFD, &buf, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual)); + + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0xF0, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0x0F, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + readBuf(virtual, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf)); + BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf)); + + return 0; +} + +static void +testAGP(TinyDRIContext * ctx) +{ + unsigned long ticks[128], *pTicks; + unsigned long size = 8 * 1024; + int ret; + + ret = benchmarkBuffer(ctx, size, ticks); + if (ret < 0) { + fprintf(stderr, "Buffer error %s\n", strerror(-ret)); + return; + } + pTicks = ticks; + + printf("Buffer size %d bytes\n", size); + printf("System memory timings ********************************\n"); + printf("Creation took %12lu ticks\n", *pTicks++); + printf("Mapping took %12lu ticks\n", *pTicks++); + printf("Writing took %12lu ticks\n", *pTicks++); + printf("Writing Again took %12lu ticks\n", *pTicks++); + printf("Reading took %12lu ticks\n", *pTicks++); + printf("Unmapping took %12lu ticks\n", *pTicks++); + + printf("\nTT Memory timings ************************************\n"); + printf("Moving to TT took %12lu ticks\n", *pTicks++); + printf("Mapping in TT took %12lu ticks\n", *pTicks++); + printf("Writing to TT took %12lu ticks\n", *pTicks++); + printf("Writing again to TT took %12lu ticks\n", *pTicks++); + printf("Reading from TT took %12lu ticks\n", *pTicks++); + printf("Moving to system took %12lu ticks\n", *pTicks++); + + if (ret == 1) + return; + + printf("\nCached TT Memory timings *****************************\n"); + printf("Moving to CTT took %12lu ticks\n", *pTicks++); + printf("Mapping in CTT took %12lu ticks\n", *pTicks++); + printf("Writing to CTT took %12lu ticks\n", *pTicks++); + printf("Re-writing to CTT took %12lu ticks\n", *pTicks++); + printf("Reading from CTT took %12lu ticks\n", *pTicks++); + printf("\n\n"); +} + +int +main() +{ + int ret, screen, isCapable; + char *displayName = ":0"; + TinyDRIContext ctx; + unsigned magic; + + ctx.screen = 0; + ctx.state = haveNothing; + ctx.display = XOpenDisplay(displayName); + if (!ctx.display) { + fprintf(stderr, "Could not open display\n"); + return releaseContext(&ctx); + } + ctx.state = haveDisplay; + + ret = + uniDRIQueryDirectRenderingCapable(ctx.display, ctx.screen, + &isCapable); + if (!ret || !isCapable) { + fprintf(stderr, "No DRI on this display:sceen\n"); + return releaseContext(&ctx); + } + + if (!uniDRIOpenConnection(ctx.display, ctx.screen, &ctx.sAreaOffset, + &ctx.curBusID)) { + fprintf(stderr, "Could not open DRI connection.\n"); + return releaseContext(&ctx); + } + ctx.state = haveConnection; + + if (!uniDRIGetClientDriverName(ctx.display, ctx.screen, + &ctx.ddxDriverMajor, &ctx.ddxDriverMinor, + &ctx.ddxDriverPatch, &ctx.driverName)) { + fprintf(stderr, "Could not get DRI driver name.\n"); + return releaseContext(&ctx); + } + ctx.state = haveDriverName; + + if (!uniDRIGetDeviceInfo(ctx.display, ctx.screen, + &ctx.fbHandle, &ctx.fbOrigin, &ctx.fbSize, + &ctx.fbStride, &ctx.driPrivSize, &ctx.driPriv)) { + fprintf(stderr, "Could not get DRI device info.\n"); + return releaseContext(&ctx); + } + ctx.state = haveDriverName; + + if ((ctx.drmFD = drmOpen(NULL, ctx.curBusID)) < 0) { + perror("DRM Device could not be opened"); + return releaseContext(&ctx); + } + ctx.state = haveDRM; + + drmGetMagic(ctx.drmFD, &magic); + if (!uniDRIAuthConnection(ctx.display, ctx.screen, magic)) { + fprintf(stderr, "Could not get X server to authenticate us.\n"); + return releaseContext(&ctx); + } + + ret = XMatchVisualInfo(ctx.display, ctx.screen, 24, TrueColor, + &ctx.visualInfo); + if (!ret) { + ret = XMatchVisualInfo(ctx.display, ctx.screen, 16, TrueColor, + &ctx.visualInfo); + if (!ret) { + fprintf(stderr, "Could not find a matching visual.\n"); + return releaseContext(&ctx); + } + } + + if (!uniDRICreateContext(ctx.display, ctx.screen, ctx.visualInfo.visual, + &ctx.id, &ctx.hwContext)) { + fprintf(stderr, "Could not create DRI context.\n"); + return releaseContext(&ctx); + } + ctx.state = haveContext; + + testAGP(&ctx); + + releaseContext(&ctx); + printf("Terminating normally\n"); + return 0; +} diff --git a/lib/libdrm/tests/ttmtest/src/xf86dri.c b/lib/libdrm/tests/ttmtest/src/xf86dri.c new file mode 100644 index 000000000..e6e0b8977 --- /dev/null +++ b/lib/libdrm/tests/ttmtest/src/xf86dri.c @@ -0,0 +1,603 @@ +/* $XFree86: xc/lib/GL/dri/XF86dri.c,v 1.13 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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 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: + * Kevin E. Martin <martin@valinux.com> + * Jens Owen <jens@tungstengraphics.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +/* THIS IS NOT AN X CONSORTIUM STANDARD */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <X11/Xlibint.h> +#include <X11/extensions/Xext.h> +#include <X11/extensions/extutil.h> +#include <stdint.h> +#include "xf86dristr.h" + +static XExtensionInfo _xf86dri_info_data; +static XExtensionInfo *xf86dri_info = &_xf86dri_info_data; +static char xf86dri_extension_name[] = XF86DRINAME; + +#define uniDRICheckExtension(dpy,i,val) \ + XextCheckExtension (dpy, i, xf86dri_extension_name, val) + +/***************************************************************************** + * * + * private utility routines * + * * + *****************************************************************************/ + +static int close_display(Display * dpy, XExtCodes * extCodes); +static /* const */ XExtensionHooks xf86dri_extension_hooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + close_display, /* close_display */ + NULL, /* wire_to_event */ + NULL, /* event_to_wire */ + NULL, /* error */ + NULL, /* error_string */ +}; + +static +XEXT_GENERATE_FIND_DISPLAY(find_display, xf86dri_info, + xf86dri_extension_name, &xf86dri_extension_hooks, 0, NULL) + + static XEXT_GENERATE_CLOSE_DISPLAY(close_display, xf86dri_info) + +/***************************************************************************** + * * + * public XFree86-DRI Extension routines * + * * + *****************************************************************************/ +#if 0 +#include <stdio.h> +#define TRACE(msg) fprintf(stderr,"uniDRI%s\n", msg); +#else +#define TRACE(msg) +#endif + Bool uniDRIQueryExtension(dpy, event_basep, error_basep) + Display *dpy; + int *event_basep, *error_basep; +{ + XExtDisplayInfo *info = find_display(dpy); + + TRACE("QueryExtension..."); + if (XextHasExtension(info)) { + *event_basep = info->codes->first_event; + *error_basep = info->codes->first_error; + TRACE("QueryExtension... return True"); + return True; + } else { + TRACE("QueryExtension... return False"); + return False; + } +} + +Bool +uniDRIQueryVersion(dpy, majorVersion, minorVersion, patchVersion) + Display *dpy; + int *majorVersion; + int *minorVersion; + int *patchVersion; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIQueryVersionReply rep; + xXF86DRIQueryVersionReq *req; + + TRACE("QueryVersion..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryVersion, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryVersion; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return False"); + return False; + } + *majorVersion = rep.majorVersion; + *minorVersion = rep.minorVersion; + *patchVersion = rep.patchVersion; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return True"); + return True; +} + +Bool +uniDRIQueryDirectRenderingCapable(dpy, screen, isCapable) + Display *dpy; + int screen; + Bool *isCapable; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIQueryDirectRenderingCapableReply rep; + xXF86DRIQueryDirectRenderingCapableReq *req; + + TRACE("QueryDirectRenderingCapable..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryDirectRenderingCapable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryDirectRenderingCapable; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return False"); + return False; + } + *isCapable = rep.isCapable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return True"); + return True; +} + +Bool +uniDRIOpenConnection(dpy, screen, hSAREA, busIdString) + Display *dpy; + int screen; + drm_handle_t *hSAREA; + char **busIdString; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIOpenConnectionReply rep; + xXF86DRIOpenConnectionReq *req; + + TRACE("OpenConnection..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIOpenConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIOpenConnection; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + + *hSAREA = rep.hSAREALow; +#ifdef LONG64 + if (sizeof(drm_handle_t) == 8) { + *hSAREA |= ((unsigned long)rep.hSAREAHigh) << 32; + } +#endif + if (rep.length) { + if (!(*busIdString = (char *)Xcalloc(rep.busIdStringLength + 1, 1))) { + _XEatData(dpy, ((rep.busIdStringLength + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + _XReadPad(dpy, *busIdString, rep.busIdStringLength); + } else { + *busIdString = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return True"); + return True; +} + +Bool +uniDRIAuthConnection(dpy, screen, magic) + Display *dpy; + int screen; + drm_magic_t magic; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIAuthConnectionReq *req; + xXF86DRIAuthConnectionReply rep; + + TRACE("AuthConnection..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIAuthConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIAuthConnection; + req->screen = screen; + req->magic = magic; + rep.authenticated = 0; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse) || !rep.authenticated) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return False"); + return False; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return True"); + return True; +} + +Bool +uniDRICloseConnection(dpy, screen) + Display *dpy; + int screen; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRICloseConnectionReq *req; + + TRACE("CloseConnection..."); + + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICloseConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICloseConnection; + req->screen = screen; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CloseConnection... return True"); + return True; +} + +Bool +uniDRIGetClientDriverName(dpy, screen, ddxDriverMajorVersion, + ddxDriverMinorVersion, ddxDriverPatchVersion, clientDriverName) + Display *dpy; + int screen; + int *ddxDriverMajorVersion; + int *ddxDriverMinorVersion; + int *ddxDriverPatchVersion; + char **clientDriverName; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIGetClientDriverNameReply rep; + xXF86DRIGetClientDriverNameReq *req; + + TRACE("GetClientDriverName..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetClientDriverName, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetClientDriverName; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + + *ddxDriverMajorVersion = rep.ddxDriverMajorVersion; + *ddxDriverMinorVersion = rep.ddxDriverMinorVersion; + *ddxDriverPatchVersion = rep.ddxDriverPatchVersion; + + if (rep.length) { + if (!(*clientDriverName = + (char *)Xcalloc(rep.clientDriverNameLength + 1, 1))) { + _XEatData(dpy, ((rep.clientDriverNameLength + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + _XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength); + } else { + *clientDriverName = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return True"); + return True; +} + +Bool +uniDRICreateContextWithConfig(dpy, screen, configID, context, hHWContext) + Display *dpy; + int screen; + int configID; + XID *context; + drm_context_t *hHWContext; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRICreateContextReply rep; + xXF86DRICreateContextReq *req; + + TRACE("CreateContext..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateContext; + req->visual = configID; + req->screen = screen; + *context = XAllocID(dpy); + req->context = *context; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return False"); + return False; + } + *hHWContext = rep.hHWContext; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return True"); + return True; +} + +Bool +uniDRICreateContext(dpy, screen, visual, context, hHWContext) + Display *dpy; + int screen; + Visual *visual; + XID *context; + drm_context_t *hHWContext; +{ + return uniDRICreateContextWithConfig(dpy, screen, visual->visualid, + context, hHWContext); +} + +Bool +uniDRIDestroyContext(Display * ndpy, int screen, XID context) +{ + Display *const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIDestroyContextReq *req; + + TRACE("DestroyContext..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyContext; + req->screen = screen; + req->context = context; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyContext... return True"); + return True; +} + +Bool +uniDRICreateDrawable(Display * ndpy, int screen, + Drawable drawable, drm_drawable_t * hHWDrawable) +{ + Display *const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display(dpy); + xXF86DRICreateDrawableReply rep; + xXF86DRICreateDrawableReq *req; + + TRACE("CreateDrawable..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateDrawable; + req->screen = screen; + req->drawable = drawable; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return False"); + return False; + } + *hHWDrawable = rep.hHWDrawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return True"); + return True; +} + +Bool +uniDRIDestroyDrawable(Display * ndpy, int screen, Drawable drawable) +{ + Display *const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIDestroyDrawableReq *req; + + TRACE("DestroyDrawable..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyDrawable; + req->screen = screen; + req->drawable = drawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyDrawable... return True"); + return True; +} + +Bool +uniDRIGetDrawableInfo(Display * dpy, int screen, Drawable drawable, + unsigned int *index, unsigned int *stamp, + int *X, int *Y, int *W, int *H, + int *numClipRects, drm_clip_rect_t ** pClipRects, + int *backX, int *backY, + int *numBackClipRects, drm_clip_rect_t ** pBackClipRects) +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIGetDrawableInfoReply rep; + xXF86DRIGetDrawableInfoReq *req; + int total_rects; + + TRACE("GetDrawableInfo..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDrawableInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDrawableInfo; + req->screen = screen; + req->drawable = drawable; + + if (!_XReply(dpy, (xReply *) & rep, 1, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } + *index = rep.drawableTableIndex; + *stamp = rep.drawableTableStamp; + *X = (int)rep.drawableX; + *Y = (int)rep.drawableY; + *W = (int)rep.drawableWidth; + *H = (int)rep.drawableHeight; + *numClipRects = rep.numClipRects; + total_rects = *numClipRects; + + *backX = rep.backX; + *backY = rep.backY; + *numBackClipRects = rep.numBackClipRects; + total_rects += *numBackClipRects; + +#if 0 + /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks + * backwards compatibility (Because of the >> 2 shift) but the fix + * enables multi-threaded apps to work. + */ + if (rep.length != ((((SIZEOF(xXF86DRIGetDrawableInfoReply) - + SIZEOF(xGenericReply) + + total_rects * sizeof(drm_clip_rect_t)) + + 3) & ~3) >> 2)) { + _XEatData(dpy, rep.length); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } +#endif + + if (*numClipRects) { + int len = sizeof(drm_clip_rect_t) * (*numClipRects); + + *pClipRects = (drm_clip_rect_t *) Xcalloc(len, 1); + if (*pClipRects) + _XRead(dpy, (char *)*pClipRects, len); + } else { + *pClipRects = NULL; + } + + if (*numBackClipRects) { + int len = sizeof(drm_clip_rect_t) * (*numBackClipRects); + + *pBackClipRects = (drm_clip_rect_t *) Xcalloc(len, 1); + if (*pBackClipRects) + _XRead(dpy, (char *)*pBackClipRects, len); + } else { + *pBackClipRects = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return True"); + return True; +} + +Bool +uniDRIGetDeviceInfo(dpy, screen, hFrameBuffer, + fbOrigin, fbSize, fbStride, devPrivateSize, pDevPrivate) + Display *dpy; + int screen; + drm_handle_t *hFrameBuffer; + int *fbOrigin; + int *fbSize; + int *fbStride; + int *devPrivateSize; + void **pDevPrivate; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIGetDeviceInfoReply rep; + xXF86DRIGetDeviceInfoReq *req; + + TRACE("GetDeviceInfo..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDeviceInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDeviceInfo; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + + *hFrameBuffer = rep.hFrameBufferLow; +#ifdef LONG64 + if (sizeof(drm_handle_t) == 8) { + *hFrameBuffer |= ((unsigned long)rep.hFrameBufferHigh) << 32; + } +#endif + + *fbOrigin = rep.framebufferOrigin; + *fbSize = rep.framebufferSize; + *fbStride = rep.framebufferStride; + *devPrivateSize = rep.devPrivateSize; + + if (rep.length) { + if (!(*pDevPrivate = (void *)Xcalloc(rep.devPrivateSize, 1))) { + _XEatData(dpy, ((rep.devPrivateSize + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + _XRead(dpy, (char *)*pDevPrivate, rep.devPrivateSize); + } else { + *pDevPrivate = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return True"); + return True; +} diff --git a/lib/libdrm/tests/ttmtest/src/xf86dri.h b/lib/libdrm/tests/ttmtest/src/xf86dri.h new file mode 100644 index 000000000..8fb78968e --- /dev/null +++ b/lib/libdrm/tests/ttmtest/src/xf86dri.h @@ -0,0 +1,116 @@ +/* $XFree86: xc/lib/GL/dri/xf86dri.h,v 1.8 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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 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. + +**************************************************************************/ + +/** + * \file xf86dri.h + * Protocol numbers and function prototypes for DRI X protocol. + * + * \author Kevin E. Martin <martin@valinux.com> + * \author Jens Owen <jens@tungstengraphics.com> + * \author Rickard E. (Rik) Faith <faith@valinux.com> + */ + +#ifndef _XF86DRI_H_ +#define _XF86DRI_H_ + +#include <X11/Xfuncproto.h> +#include <drm/drm.h> + +#define X_XF86DRIQueryVersion 0 +#define X_XF86DRIQueryDirectRenderingCapable 1 +#define X_XF86DRIOpenConnection 2 +#define X_XF86DRICloseConnection 3 +#define X_XF86DRIGetClientDriverName 4 +#define X_XF86DRICreateContext 5 +#define X_XF86DRIDestroyContext 6 +#define X_XF86DRICreateDrawable 7 +#define X_XF86DRIDestroyDrawable 8 +#define X_XF86DRIGetDrawableInfo 9 +#define X_XF86DRIGetDeviceInfo 10 +#define X_XF86DRIAuthConnection 11 +#define X_XF86DRIOpenFullScreen 12 /* Deprecated */ +#define X_XF86DRICloseFullScreen 13 /* Deprecated */ + +#define XF86DRINumberEvents 0 + +#define XF86DRIClientNotLocal 0 +#define XF86DRIOperationNotSupported 1 +#define XF86DRINumberErrors (XF86DRIOperationNotSupported + 1) + +#ifndef _XF86DRI_SERVER_ + +_XFUNCPROTOBEGIN + Bool uniDRIQueryExtension(Display * dpy, int *event_base, + int *error_base); + +Bool uniDRIQueryVersion(Display * dpy, int *majorVersion, int *minorVersion, + int *patchVersion); + +Bool uniDRIQueryDirectRenderingCapable(Display * dpy, int screen, + Bool * isCapable); + +Bool uniDRIOpenConnection(Display * dpy, int screen, drm_handle_t * hSAREA, + char **busIDString); + +Bool uniDRIAuthConnection(Display * dpy, int screen, drm_magic_t magic); + +Bool uniDRICloseConnection(Display * dpy, int screen); + +Bool uniDRIGetClientDriverName(Display * dpy, int screen, + int *ddxDriverMajorVersion, int *ddxDriverMinorVersion, + int *ddxDriverPatchVersion, char **clientDriverName); + +Bool uniDRICreateContext(Display * dpy, int screen, Visual * visual, + XID * ptr_to_returned_context_id, drm_context_t * hHWContext); + +Bool uniDRICreateContextWithConfig(Display * dpy, int screen, int configID, + XID * ptr_to_returned_context_id, drm_context_t * hHWContext); + +extern Bool uniDRIDestroyContext(Display * dpy, int screen, XID context_id); + +extern Bool uniDRICreateDrawable(Display * dpy, int screen, + Drawable drawable, drm_drawable_t * hHWDrawable); + +extern Bool uniDRIDestroyDrawable(Display * dpy, int screen, + Drawable drawable); + +Bool uniDRIGetDrawableInfo(Display * dpy, int screen, Drawable drawable, + unsigned int *index, unsigned int *stamp, + int *X, int *Y, int *W, int *H, + int *numClipRects, drm_clip_rect_t ** pClipRects, + int *backX, int *backY, + int *numBackClipRects, drm_clip_rect_t ** pBackClipRects); + +Bool uniDRIGetDeviceInfo(Display * dpy, int screen, + drm_handle_t * hFrameBuffer, int *fbOrigin, int *fbSize, + int *fbStride, int *devPrivateSize, void **pDevPrivate); + +_XFUNCPROTOEND +#endif /* _XF86DRI_SERVER_ */ +#endif /* _XF86DRI_H_ */ diff --git a/lib/libdrm/tests/ttmtest/src/xf86dristr.h b/lib/libdrm/tests/ttmtest/src/xf86dristr.h new file mode 100644 index 000000000..2730d1a7e --- /dev/null +++ b/lib/libdrm/tests/ttmtest/src/xf86dristr.h @@ -0,0 +1,390 @@ +/* $XFree86: xc/lib/GL/dri/xf86dristr.h,v 1.10 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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 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: + * Kevin E. Martin <martin@valinux.com> + * Jens Owen <jens@tungstengraphics.com> + * Rickard E. (Rik) Fiath <faith@valinux.com> + * + */ + +#ifndef _XF86DRISTR_H_ +#define _XF86DRISTR_H_ + +#include "xf86dri.h" + +#define XF86DRINAME "XFree86-DRI" + +/* The DRI version number. This was originally set to be the same as the + * XFree86 version number. However, this version is really independent of + * the XFree86 version. + * + * Version History: + * 4.0.0: Original + * 4.0.1: Patch to bump clipstamp when windows are destroyed, 28 May 02 + * 4.1.0: Add transition from single to multi in DRMInfo rec, 24 Jun 02 + */ +#define XF86DRI_MAJOR_VERSION 4 +#define XF86DRI_MINOR_VERSION 1 +#define XF86DRI_PATCH_VERSION 0 + +typedef struct _XF86DRIQueryVersion +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIQueryVersion */ + CARD16 length B16; +} xXF86DRIQueryVersionReq; + +#define sz_xXF86DRIQueryVersionReq 4 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD16 majorVersion B16; /* major version of DRI protocol */ + CARD16 minorVersion B16; /* minor version of DRI protocol */ + CARD32 patchVersion B32; /* patch version of DRI protocol */ + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIQueryVersionReply; + +#define sz_xXF86DRIQueryVersionReply 32 + +typedef struct _XF86DRIQueryDirectRenderingCapable +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* X_DRIQueryDirectRenderingCapable */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIQueryDirectRenderingCapableReq; + +#define sz_xXF86DRIQueryDirectRenderingCapableReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + BOOL isCapable; + BOOL pad2; + BOOL pad3; + BOOL pad4; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; + CARD32 pad9 B32; +} xXF86DRIQueryDirectRenderingCapableReply; + +#define sz_xXF86DRIQueryDirectRenderingCapableReply 32 + +typedef struct _XF86DRIOpenConnection +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIOpenConnectionReq; + +#define sz_xXF86DRIOpenConnectionReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hSAREALow B32; + CARD32 hSAREAHigh B32; + CARD32 busIdStringLength B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xXF86DRIOpenConnectionReply; + +#define sz_xXF86DRIOpenConnectionReply 32 + +typedef struct _XF86DRIAuthConnection +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; + CARD32 magic B32; +} xXF86DRIAuthConnectionReq; + +#define sz_xXF86DRIAuthConnectionReq 12 + +typedef struct +{ + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 authenticated B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIAuthConnectionReply; + +#define zx_xXF86DRIAuthConnectionReply 32 + +typedef struct _XF86DRICloseConnection +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRICloseConnectionReq; + +#define sz_xXF86DRICloseConnectionReq 8 + +typedef struct _XF86DRIGetClientDriverName +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetClientDriverName */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetClientDriverNameReq; + +#define sz_xXF86DRIGetClientDriverNameReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 ddxDriverMajorVersion B32; + CARD32 ddxDriverMinorVersion B32; + CARD32 ddxDriverPatchVersion B32; + CARD32 clientDriverNameLength B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIGetClientDriverNameReply; + +#define sz_xXF86DRIGetClientDriverNameReply 32 + +typedef struct _XF86DRICreateContext +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 visual B32; + CARD32 context B32; +} xXF86DRICreateContextReq; + +#define sz_xXF86DRICreateContextReq 16 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWContext B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateContextReply; + +#define sz_xXF86DRICreateContextReply 32 + +typedef struct _XF86DRIDestroyContext +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 context B32; +} xXF86DRIDestroyContextReq; + +#define sz_xXF86DRIDestroyContextReq 12 + +typedef struct _XF86DRICreateDrawable +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICreateDrawableReq; + +#define sz_xXF86DRICreateDrawableReq 12 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWDrawable B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateDrawableReply; + +#define sz_xXF86DRICreateDrawableReply 32 + +typedef struct _XF86DRIDestroyDrawable +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIDestroyDrawableReq; + +#define sz_xXF86DRIDestroyDrawableReq 12 + +typedef struct _XF86DRIGetDrawableInfo +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDrawableInfo */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIGetDrawableInfoReq; + +#define sz_xXF86DRIGetDrawableInfoReq 12 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 drawableTableIndex B32; + CARD32 drawableTableStamp B32; + INT16 drawableX B16; + INT16 drawableY B16; + INT16 drawableWidth B16; + INT16 drawableHeight B16; + CARD32 numClipRects B32; + INT16 backX B16; + INT16 backY B16; + CARD32 numBackClipRects B32; +} xXF86DRIGetDrawableInfoReply; + +#define sz_xXF86DRIGetDrawableInfoReply 36 + +typedef struct _XF86DRIGetDeviceInfo +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDeviceInfo */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetDeviceInfoReq; + +#define sz_xXF86DRIGetDeviceInfoReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hFrameBufferLow B32; + CARD32 hFrameBufferHigh B32; + CARD32 framebufferOrigin B32; + CARD32 framebufferSize B32; + CARD32 framebufferStride B32; + CARD32 devPrivateSize B32; +} xXF86DRIGetDeviceInfoReply; + +#define sz_xXF86DRIGetDeviceInfoReply 32 + +typedef struct _XF86DRIOpenFullScreen +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIOpenFullScreenReq; + +#define sz_xXF86DRIOpenFullScreenReq 12 + +typedef struct +{ + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 isFullScreen B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIOpenFullScreenReply; + +#define sz_xXF86DRIOpenFullScreenReply 32 + +typedef struct _XF86DRICloseFullScreen +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICloseFullScreenReq; + +#define sz_xXF86DRICloseFullScreenReq 12 + +typedef struct +{ + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xXF86DRICloseFullScreenReply; + +#define sz_xXF86DRICloseFullScreenReply 32 + +#endif /* _XF86DRISTR_H_ */ diff --git a/lib/libdrm/tests/util/Android.mk b/lib/libdrm/tests/util/Android.mk new file mode 100644 index 000000000..12eccb42a --- /dev/null +++ b/lib/libdrm/tests/util/Android.mk @@ -0,0 +1,38 @@ +# +# Copyright © 2015 NVIDIA 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_util + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(UTIL_FILES) + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LIBDRM_TOP)/tests + +include $(LIBDRM_COMMON_MK) +include $(BUILD_STATIC_LIBRARY) diff --git a/lib/libdrm/tests/util/kms.c b/lib/libdrm/tests/util/kms.c index dd1bbee3c..08b48fe58 100644 --- a/lib/libdrm/tests/util/kms.c +++ b/lib/libdrm/tests/util/kms.c @@ -147,6 +147,8 @@ static const char * const modules[] = { "stm", "sun4i-drm", "armada-drm", + "komeda", + "imx-dcss", }; int util_open(const char *device, const char *module) diff --git a/lib/libdrm/tests/vbltest/vbltest.c b/lib/libdrm/tests/vbltest/vbltest.c index 48708d201..1c2b519ee 100644 --- a/lib/libdrm/tests/vbltest/vbltest.c +++ b/lib/libdrm/tests/vbltest/vbltest.c @@ -33,7 +33,7 @@ #include <errno.h> #include <poll.h> #include <sys/time.h> -#ifdef HAVE_SYS_SELECT_H +#if HAVE_SYS_SELECT_H #include <sys/select.h> #endif |