From 5de53016e764a181d0eca842a558a72173ed2f1c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 3 Jul 2023 12:01:11 +0200 Subject: [PATCH 01/64] panfrost: Abstract some kernel driver operations We have generic BO management and device management layers that directly call kernel driver-specific ioctls. With the new kernel driver for v10 hardware being pushed, we want to abstract some low-level operations so pan_{bo,device}.{c,h} don't become a mess. Signed-off-by: Boris Brezillon --- src/panfrost/lib/kmod/meson.build | 39 +++ src/panfrost/lib/kmod/pan_kmod.c | 89 ++++++ src/panfrost/lib/kmod/pan_kmod.h | 221 +++++++++++++ src/panfrost/lib/kmod/pan_kmod_backend.h | 72 +++++ src/panfrost/lib/kmod/panfrost_kmod.c | 377 +++++++++++++++++++++++ src/panfrost/lib/meson.build | 5 +- 6 files changed, 801 insertions(+), 2 deletions(-) create mode 100644 src/panfrost/lib/kmod/meson.build create mode 100644 src/panfrost/lib/kmod/pan_kmod.c create mode 100644 src/panfrost/lib/kmod/pan_kmod.h create mode 100644 src/panfrost/lib/kmod/pan_kmod_backend.h create mode 100644 src/panfrost/lib/kmod/panfrost_kmod.c diff --git a/src/panfrost/lib/kmod/meson.build b/src/panfrost/lib/kmod/meson.build new file mode 100644 index 00000000000..1278dc6f394 --- /dev/null +++ b/src/panfrost/lib/kmod/meson.build @@ -0,0 +1,39 @@ +# Copyright © 2023 Collabora + +# 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. + +libpankmod_lib_files = files( + 'pan_kmod.c', + 'panfrost_kmod.c', +) + +libpankmod_lib = static_library( + 'pankmod_lib', + [libpankmod_lib_files], + include_directories : [inc_include, inc_src, inc_panfrost], + c_args : [no_override_init_args], + gnu_symbol_visibility : 'hidden', + dependencies: [dep_libdrm, idep_mesautil], + build_by_default : false, +) + +libpankmod_dep = declare_dependency( + include_directories: [inc_include, inc_src], + dependencies: [dep_libdrm], +) diff --git a/src/panfrost/lib/kmod/pan_kmod.c b/src/panfrost/lib/kmod/pan_kmod.c new file mode 100644 index 00000000000..99e671feba9 --- /dev/null +++ b/src/panfrost/lib/kmod/pan_kmod.c @@ -0,0 +1,89 @@ +/* + * Copyright © 2023 Collabora, Ltd. + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include "util/macros.h" +#include "pan_kmod.h" + +extern const struct pan_kmod_ops panfrost_kmod_ops; + +static const struct { + const char *name; + const struct pan_kmod_ops *ops; +} drivers[] = { + {"panfrost", &panfrost_kmod_ops}, +}; + +static void * +default_zalloc(const struct pan_kmod_allocator *allocator, size_t size) +{ + return rzalloc_size(allocator, size); +} + +static void +default_free(const struct pan_kmod_allocator *allocator, void *data) +{ + return ralloc_free(data); +} + +static const struct pan_kmod_allocator * +create_default_allocator(void) +{ + struct pan_kmod_allocator *allocator = + rzalloc(NULL, struct pan_kmod_allocator); + + if (allocator) { + allocator->zalloc = default_zalloc; + allocator->free = default_free; + } + + return allocator; +} + +struct pan_kmod_dev * +pan_kmod_dev_create(int fd, const struct pan_kmod_allocator *allocator) +{ + drmVersionPtr version = drmGetVersion(fd); + + if (!version) + return NULL; + + if (!allocator) { + allocator = create_default_allocator(); + if (!allocator) + return NULL; + } + + for (unsigned i = 0; i < ARRAY_SIZE(drivers); i++) { + if (!strcmp(drivers[i].name, version->name)) { + const struct pan_kmod_ops *ops = drivers[i].ops; + struct pan_kmod_dev *dev; + + dev = ops->dev_create(fd, version, allocator); + if (dev) + return dev; + break; + } + } + + if (allocator->zalloc == default_zalloc) + ralloc_free((void *)allocator); + + return NULL; +} + +void +pan_kmod_dev_destroy(struct pan_kmod_dev *dev) +{ + const struct pan_kmod_allocator *allocator = dev->allocator; + + dev->ops->dev_destroy(dev); + + if (allocator->zalloc == default_zalloc) + ralloc_free((void *)allocator); +} diff --git a/src/panfrost/lib/kmod/pan_kmod.h b/src/panfrost/lib/kmod/pan_kmod.h new file mode 100644 index 00000000000..ef1e199ed19 --- /dev/null +++ b/src/panfrost/lib/kmod/pan_kmod.h @@ -0,0 +1,221 @@ +/* + * Copyright © 2023 Collabora, Ltd. + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#include "util/macros.h" +#include "util/os_file.h" +#include "util/os_mman.h" +#include "util/ralloc.h" + +struct pan_kmod_dev; + +enum pan_kmod_vm_flags { + PAN_KMOD_VM_FLAG_AUTO_VA = BITFIELD_BIT(0), +}; + +struct pan_kmod_vm { + uint32_t flags; + uint32_t handle; + struct pan_kmod_dev *dev; +}; + +enum pan_kmod_bo_flags { + PAN_KMOD_BO_FLAG_EXECUTABLE = BITFIELD_BIT(0), + PAN_KMOD_BO_FLAG_ALLOC_ON_FAULT = BITFIELD_BIT(1), + PAN_KMOD_BO_FLAG_NO_MMAP = BITFIELD_BIT(2), + PAN_KMOD_BO_FLAG_EXPORTED = BITFIELD_BIT(3), + PAN_KMOD_BO_FLAG_IMPORTED = BITFIELD_BIT(4), + PAN_KMOD_BO_FLAG_GPU_UNCACHED = BITFIELD_BIT(5), +}; + +struct pan_kmod_bo { + size_t size; + uint32_t handle; + uint32_t flags; + struct pan_kmod_vm *exclusive_vm; + struct pan_kmod_dev *dev; +}; + +struct pan_kmod_dev_props { + uint32_t gpu_prod_id; + uint32_t gpu_revision; + uint64_t shader_present; + uint32_t tiler_features; + uint32_t mem_features; + uint32_t mmu_features; + uint32_t texture_features[4]; + uint32_t thread_tls_alloc; + uint32_t afbc_features; +}; + +struct pan_kmod_allocator { + void *(*zalloc)(const struct pan_kmod_allocator *allocator, size_t size); + void (*free)(const struct pan_kmod_allocator *allocator, void *data); + void *priv; +}; + +#define PAN_KMOD_VM_MAP_AUTO_VA ~0ull +#define PAN_KMOD_VM_MAP_FAILED ~0ull + +struct pan_kmod_ops { + struct pan_kmod_dev *(*dev_create)( + int fd, const drmVersionPtr version, + const struct pan_kmod_allocator *allocator); + void (*dev_destroy)(struct pan_kmod_dev *dev); + void (*dev_query_props)(struct pan_kmod_dev *dev, + struct pan_kmod_dev_props *props); + struct pan_kmod_bo *(*bo_alloc)(struct pan_kmod_dev *dev, + struct pan_kmod_vm *exclusive_vm, + size_t size, uint32_t flags); + void (*bo_free)(struct pan_kmod_bo *bo); + struct pan_kmod_bo *(*bo_import)(struct pan_kmod_dev *dev, int fd); + int (*bo_export)(struct pan_kmod_bo *bo); + off_t (*bo_get_mmap_offset)(struct pan_kmod_bo *bo); + bool (*bo_wait)(struct pan_kmod_bo *bo, int64_t timeout_ns, + bool for_read_only_access); + void (*bo_make_evictable)(struct pan_kmod_bo *bo); + bool (*bo_make_unevictable)(struct pan_kmod_bo *bo); + struct pan_kmod_vm *(*vm_create)(struct pan_kmod_dev *dev, uint32_t flags, + uint64_t va_start, uint64_t va_range); + void (*vm_destroy)(struct pan_kmod_vm *vm); + uint64_t (*vm_map)(struct pan_kmod_vm *vm, struct pan_kmod_bo *bo, + uint64_t va, off_t offset, size_t size); + void (*vm_unmap)(struct pan_kmod_vm *vm, uint64_t va, size_t size); +}; + +struct pan_kmod_driver { + struct { + uint32_t major; + uint32_t minor; + } version; +}; + +struct pan_kmod_dev { + int fd; + struct pan_kmod_driver driver; + const struct pan_kmod_ops *ops; + const struct pan_kmod_allocator *allocator; +}; + +struct pan_kmod_dev * +pan_kmod_dev_create(int fd, const struct pan_kmod_allocator *allocator); + +void pan_kmod_dev_destroy(struct pan_kmod_dev *dev); + +static inline void +pan_kmod_dev_query_props(struct pan_kmod_dev *dev, + struct pan_kmod_dev_props *props) +{ + dev->ops->dev_query_props(dev, props); +} + +static inline struct pan_kmod_bo * +pan_kmod_bo_alloc(struct pan_kmod_dev *dev, struct pan_kmod_vm *exclusive_vm, + size_t size, uint32_t flags) +{ + return dev->ops->bo_alloc(dev, exclusive_vm, size, flags); +} + +static inline void +pan_kmod_bo_free(struct pan_kmod_bo *bo) +{ + bo->dev->ops->bo_free(bo); +} + +static inline struct pan_kmod_bo * +pan_kmod_bo_import(struct pan_kmod_dev *dev, int fd) +{ + return dev->ops->bo_import(dev, fd); +} + +static inline int +pan_kmod_bo_export(struct pan_kmod_bo *bo) +{ + if (bo->exclusive_vm) + return -1; + + return bo->dev->ops->bo_export(bo); +} + +static inline bool +pan_kmod_bo_wait(struct pan_kmod_bo *bo, int64_t timeout_ns, + bool for_read_only_access) +{ + return bo->dev->ops->bo_wait(bo, timeout_ns, for_read_only_access); +} + +static inline void +pan_kmod_bo_make_evictable(struct pan_kmod_bo *bo) +{ + if (bo->dev->ops->bo_make_evictable) + bo->dev->ops->bo_make_evictable(bo); +} + +static inline bool +pan_kmod_bo_make_unevictable(struct pan_kmod_bo *bo) +{ + if (bo->dev->ops->bo_make_unevictable) + return bo->dev->ops->bo_make_unevictable(bo); + + return true; +} + +static inline void * +pan_kmod_bo_mmap(struct pan_kmod_bo *bo, off_t bo_offset, size_t size, int prot, + int flags) +{ + off_t mmap_offset; + + if (bo_offset + size > bo->size) + return MAP_FAILED; + + mmap_offset = bo->dev->ops->bo_get_mmap_offset(bo); + if (mmap_offset < 0) + return MAP_FAILED; + + return os_mmap(NULL, size, prot, flags, bo->dev->fd, + mmap_offset + bo_offset); +} + +static inline struct pan_kmod_vm * +pan_kmod_vm_create(struct pan_kmod_dev *dev, uint32_t flags, uint64_t va_start, + uint64_t va_range) +{ + return dev->ops->vm_create(dev, flags, va_start, va_range); +} + +static inline void +pan_kmod_vm_destroy(struct pan_kmod_vm *vm) +{ + vm->dev->ops->vm_destroy(vm); +} + +static inline uint64_t +pan_kmod_vm_map(struct pan_kmod_vm *vm, struct pan_kmod_bo *bo, uint64_t va, + off_t offset, size_t size) +{ + if (!!(vm->flags & PAN_KMOD_VM_FLAG_AUTO_VA) != + (va == PAN_KMOD_VM_MAP_AUTO_VA)) + return PAN_KMOD_VM_MAP_FAILED; + + return vm->dev->ops->vm_map(vm, bo, va, offset, size); +} + +static inline void +pan_kmod_vm_unmap(struct pan_kmod_vm *vm, uint64_t va, size_t size) +{ + vm->dev->ops->vm_unmap(vm, va, size); +} + +static inline uint32_t +pan_kmod_vm_handle(struct pan_kmod_vm *vm) +{ + return vm->handle; +} diff --git a/src/panfrost/lib/kmod/pan_kmod_backend.h b/src/panfrost/lib/kmod/pan_kmod_backend.h new file mode 100644 index 00000000000..0148a672e62 --- /dev/null +++ b/src/panfrost/lib/kmod/pan_kmod_backend.h @@ -0,0 +1,72 @@ +/* + * Copyright © 2023 Collabora, Ltd. + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include "pan_kmod.h" + +static inline void +pan_kmod_dev_init(struct pan_kmod_dev *dev, int fd, drmVersionPtr version, + const struct pan_kmod_ops *ops, + const struct pan_kmod_allocator *allocator) +{ + dev->driver.version.major = version->version_major; + dev->driver.version.minor = version->version_minor; + dev->fd = fd; + dev->ops = ops; + dev->allocator = allocator; +} + +static inline void +pan_kmod_dev_cleanup(struct pan_kmod_dev *dev) +{ + close(dev->fd); +} + +static inline void * +pan_kmod_alloc(const struct pan_kmod_allocator *allocator, size_t size) +{ + return allocator->zalloc(allocator, size); +} + +static inline void +pan_kmod_free(const struct pan_kmod_allocator *allocator, void *data) +{ + return allocator->free(allocator, data); +} + +static inline void * +pan_kmod_dev_alloc(struct pan_kmod_dev *dev, size_t size) +{ + return pan_kmod_alloc(dev->allocator, size); +} + +static inline void +pan_kmod_dev_free(const struct pan_kmod_dev *dev, void *data) +{ + return pan_kmod_free(dev->allocator, data); +} + +static inline void +pan_kmod_bo_init(struct pan_kmod_bo *bo, struct pan_kmod_dev *dev, + struct pan_kmod_vm *exclusive_vm, size_t size, uint32_t flags, + uint32_t handle) +{ + bo->dev = dev; + bo->exclusive_vm = exclusive_vm; + bo->size = size; + bo->flags = flags; + bo->handle = handle; +} + +static inline void +pan_kmod_vm_init(struct pan_kmod_vm *vm, struct pan_kmod_dev *dev, + uint32_t handle, uint32_t flags) +{ + vm->dev = dev; + vm->handle = handle; + vm->flags = flags; +} diff --git a/src/panfrost/lib/kmod/panfrost_kmod.c b/src/panfrost/lib/kmod/panfrost_kmod.c new file mode 100644 index 00000000000..607f86c46a5 --- /dev/null +++ b/src/panfrost/lib/kmod/panfrost_kmod.c @@ -0,0 +1,377 @@ +/* + * Copyright © 2023 Collabora, Ltd. + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include "util/hash_table.h" +#include "util/macros.h" + +#include "drm-uapi/panfrost_drm.h" + +#include "pan_kmod_backend.h" + +const struct pan_kmod_ops panfrost_kmod_ops; + +struct panfrost_kmod_vm { + struct pan_kmod_vm base; + struct hash_table_u64 *va_to_bo; +}; + +struct panfrost_kmod_dev { + struct pan_kmod_dev base; + struct panfrost_kmod_vm *vm; +}; + +struct panfrost_kmod_bo { + struct pan_kmod_bo base; + uint64_t offset; +}; + +static struct pan_kmod_dev * +panfrost_kmod_dev_create(int fd, drmVersionPtr version, + const struct pan_kmod_allocator *allocator) +{ + struct panfrost_kmod_dev *panfrost_dev = + pan_kmod_alloc(allocator, sizeof(*panfrost_dev)); + if (!panfrost_dev) + return NULL; + + pan_kmod_dev_init(&panfrost_dev->base, fd, version, &panfrost_kmod_ops, + allocator); + return &panfrost_dev->base; +} + +static void +panfrost_kmod_dev_destroy(struct pan_kmod_dev *dev) +{ + struct panfrost_kmod_dev *panfrost_dev = + container_of(dev, struct panfrost_kmod_dev, base); + + pan_kmod_dev_cleanup(dev); + pan_kmod_free(dev->allocator, panfrost_dev); +} + +/* Abstraction over the raw drm_panfrost_get_param ioctl for fetching + * information about devices */ + +static __u64 +panfrost_query_raw(int fd, enum drm_panfrost_param param, bool required, + unsigned default_value) +{ + struct drm_panfrost_get_param get_param = {}; + ASSERTED int ret; + + get_param.param = param; + ret = drmIoctl(fd, DRM_IOCTL_PANFROST_GET_PARAM, &get_param); + + if (ret) { + assert(!required); + return default_value; + } + + return get_param.value; +} + +static void +panfrost_dev_query_props(struct pan_kmod_dev *dev, + struct pan_kmod_dev_props *props) +{ + int fd = dev->fd; + + memset(props, 0, sizeof(*props)); + props->gpu_prod_id = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_GPU_PROD_ID, true, 0); + props->gpu_revision = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_GPU_REVISION, true, 0); + props->shader_present = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_SHADER_PRESENT, false, 0xffff); + props->tiler_features = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_TILER_FEATURES, false, 0x809); + props->mem_features = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_MEM_FEATURES, true, 0); + props->mmu_features = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_MEM_FEATURES, false, 0); + + for (unsigned i = 0; i < ARRAY_SIZE(props->texture_features); i++) { + /* If unspecified, assume ASTC/ETC only. Factory default for Juno, and + * should exist on any Mali configuration. All hardware should report + * these texture formats but the kernel might not be new enough. */ + static const uint32_t default_tex_features[4] = {0xfe001e, 0, 0, 0}; + + props->texture_features[i] = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_TEXTURE_FEATURES0 + i, false, + default_tex_features[i]); + } + + props->thread_tls_alloc = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_THREAD_TLS_ALLOC, false, 0); + props->afbc_features = + panfrost_query_raw(fd, DRM_PANFROST_PARAM_AFBC_FEATURES, false, 0); +} + +static uint32_t to_panfrost_bo_flags(struct pan_kmod_dev *dev, uint32_t flags) +{ + uint32_t panfrost_flags = 0; + + if (dev->driver.version.major > 1 || dev->driver.version.minor >= 1) { + if (flags & PAN_KMOD_BO_FLAG_ALLOC_ON_FAULT) + panfrost_flags |= PANFROST_BO_HEAP; + if (!(flags & PAN_KMOD_BO_FLAG_EXECUTABLE)) + panfrost_flags |= PANFROST_BO_NOEXEC; + } + + return panfrost_flags; +} + +static struct pan_kmod_bo * +panfrost_kmod_bo_alloc(struct pan_kmod_dev *dev, + struct pan_kmod_vm *exclusive_vm, size_t size, + uint32_t flags) +{ + /* We can't map GPU uncached. */ + if (flags & PAN_KMOD_BO_FLAG_GPU_UNCACHED) + return NULL; + + struct panfrost_kmod_bo *bo = pan_kmod_dev_alloc(dev, sizeof(*bo)); + if (!bo) + return NULL; + + struct drm_panfrost_create_bo req = { + .size = size, + .flags = to_panfrost_bo_flags(dev, flags), + }; + + int ret = drmIoctl(dev->fd, DRM_IOCTL_PANFROST_CREATE_BO, &req); + if (ret) + goto err_free_bo; + + pan_kmod_bo_init(&bo->base, dev, exclusive_vm, req.size, flags, req.handle); + bo->offset = req.offset; + return &bo->base; + +err_free_bo: + pan_kmod_dev_free(dev, bo); + return NULL; +} + +static void +panfrost_kmod_bo_free(struct pan_kmod_bo *bo) +{ + drmCloseBufferHandle(bo->dev->fd, bo->handle); + pan_kmod_dev_free(bo->dev, bo); +} + +static struct pan_kmod_bo * +panfrost_kmod_bo_import(struct pan_kmod_dev *dev, int fd) +{ + struct panfrost_kmod_bo *panfrost_bo = + pan_kmod_dev_alloc(dev, sizeof(*panfrost_bo)); + if (!panfrost_bo) + return NULL; + + uint32_t handle; + int ret = drmPrimeFDToHandle(dev->fd, fd, &handle); + if (ret) + goto err_free_bo; + + struct drm_panfrost_get_bo_offset get_bo_offset = {}; + ret = drmIoctl(dev->fd, DRM_IOCTL_PANFROST_GET_BO_OFFSET, &get_bo_offset); + if (ret) + goto err_close_handle; + + panfrost_bo->offset = get_bo_offset.offset; + + size_t size = lseek(fd, 0, SEEK_END); + if (size == 0 || size == (size_t)-1) + goto err_close_handle; + + pan_kmod_bo_init(&panfrost_bo->base, dev, NULL, size, + PAN_KMOD_BO_FLAG_IMPORTED, handle); + return &panfrost_bo->base; + +err_close_handle: + drmCloseBufferHandle(dev->fd, handle); + +err_free_bo: + pan_kmod_dev_free(dev, panfrost_bo); + return NULL; +} + +static inline int +panfrost_kmod_bo_export(struct pan_kmod_bo *bo) +{ + struct drm_prime_handle args = { + .handle = bo->handle, + .flags = DRM_CLOEXEC, + }; + int ret = drmIoctl(bo->dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); + if (ret == -1) + return -1; + + bo->flags |= PAN_KMOD_BO_FLAG_EXPORTED; + return args.fd; +} + +static off_t +panfrost_kmod_bo_get_mmap_offset(struct pan_kmod_bo *bo) +{ + struct panfrost_kmod_bo *panfrost_bo = + container_of(bo, struct panfrost_kmod_bo, base); + + return panfrost_bo->offset; +} + +static bool +panfrost_kmod_bo_wait(struct pan_kmod_bo *bo, int64_t timeout_ns, + bool for_read_only_access) +{ + struct drm_panfrost_wait_bo req = { + .handle = bo->handle, + .timeout_ns = timeout_ns, + }; + + /* The ioctl returns >= 0 value when the BO we are waiting for is ready + * -1 otherwise. + */ + if (drmIoctl(bo->dev->fd, DRM_IOCTL_PANFROST_WAIT_BO, &req) != -1) + return true; + + assert(errno == ETIMEDOUT || errno == EBUSY); + return false; +} + +static void +panfrost_kmod_bo_make_evictable(struct pan_kmod_bo *bo) +{ + struct drm_panfrost_madvise req = { + .handle = bo->handle, + .madv = PANFROST_MADV_DONTNEED, + }; + + drmIoctl(bo->dev->fd, DRM_IOCTL_PANFROST_MADVISE, &req); +} + +static bool +panfrost_kmod_bo_make_unevictable(struct pan_kmod_bo *bo) +{ + struct drm_panfrost_madvise req = { + .handle = bo->handle, + .madv = PANFROST_MADV_WILLNEED, + }; + + if (drmIoctl(bo->dev->fd, DRM_IOCTL_PANFROST_MADVISE, &req) == 0 && + req.retained == 0) + return false; + + return true; +} + +static struct pan_kmod_vm * +panfrost_kmod_vm_create(struct pan_kmod_dev *dev, uint32_t flags, + uint64_t va_start, uint64_t va_range) +{ + struct panfrost_kmod_dev *panfrost_dev = + container_of(dev, struct panfrost_kmod_dev, base); + + /* Only one VM per device. */ + if (panfrost_dev->vm) + return NULL; + + /* Panfrost kernel driver doesn't support userspace VA management. */ + if (!(flags & PAN_KMOD_VM_FLAG_AUTO_VA)) + return NULL; + + /* 32-bit address space, with the lower 32MB reserved. */ + if (va_start != 0x2000000 || va_start + va_range != 1ull << 32) + return NULL; + + struct panfrost_kmod_vm *vm = pan_kmod_dev_alloc(dev, sizeof(*vm)); + if (!vm) + return NULL; + + pan_kmod_vm_init(&vm->base, dev, 0, flags); + vm->va_to_bo = _mesa_hash_table_u64_create(NULL); + if (!vm->va_to_bo) + goto err_free_vm; + + panfrost_dev->vm = vm; + return &vm->base; + +err_free_vm: + pan_kmod_dev_free(dev, vm); + return NULL; +} + +static void +panfrost_kmod_vm_destroy(struct pan_kmod_vm *vm) +{ + struct panfrost_kmod_dev *panfrost_dev = + container_of(vm->dev, struct panfrost_kmod_dev, base); + + panfrost_dev->vm = NULL; + pan_kmod_dev_free(vm->dev, vm); +} + +static uint64_t +panfrost_kmod_vm_map(struct pan_kmod_vm *vm, struct pan_kmod_bo *bo, + uint64_t va, off_t offset, size_t size) +{ + struct panfrost_kmod_vm *panfrost_vm = + container_of(vm, struct panfrost_kmod_vm, base); + struct panfrost_kmod_bo *panfrost_bo = + container_of(bo, struct panfrost_kmod_bo, base); + + /* Panfrost kernel driver doesn't support userspace VA management. */ + if (va != PAN_KMOD_VM_MAP_AUTO_VA) + return PAN_KMOD_VM_MAP_FAILED; + + /* Panfrost kernel driver only support full BO mapping. */ + if (offset != 0 || size != bo->size) + return PAN_KMOD_VM_MAP_FAILED; + + va = panfrost_bo->offset; + + /* Make sure we don't have a BO mapped at this address. */ + assert(_mesa_hash_table_u64_search(panfrost_vm->va_to_bo, va) == NULL); + + _mesa_hash_table_u64_insert(panfrost_vm->va_to_bo, va, bo); + return va; +} + +static void +panfrost_kmod_vm_unmap(struct pan_kmod_vm *vm, uint64_t va, size_t size) +{ + struct panfrost_kmod_vm *panfrost_vm = + container_of(vm, struct panfrost_kmod_vm, base); + ASSERTED struct panfrost_kmod_bo *panfrost_bo = + _mesa_hash_table_u64_search(panfrost_vm->va_to_bo, va); + + assert(panfrost_bo && panfrost_bo->base.size == size && + panfrost_bo->offset == va); + + _mesa_hash_table_u64_remove(panfrost_vm->va_to_bo, va); +} + +const struct pan_kmod_ops panfrost_kmod_ops = { + .dev_create = panfrost_kmod_dev_create, + .dev_destroy = panfrost_kmod_dev_destroy, + .dev_query_props = panfrost_dev_query_props, + .bo_alloc = panfrost_kmod_bo_alloc, + .bo_free = panfrost_kmod_bo_free, + .bo_import = panfrost_kmod_bo_import, + .bo_export = panfrost_kmod_bo_export, + .bo_get_mmap_offset = panfrost_kmod_bo_get_mmap_offset, + .bo_wait = panfrost_kmod_bo_wait, + .bo_make_evictable = panfrost_kmod_bo_make_evictable, + .bo_make_unevictable = panfrost_kmod_bo_make_unevictable, + .vm_create = panfrost_kmod_vm_create, + .vm_destroy = panfrost_kmod_vm_destroy, + .vm_map = panfrost_kmod_vm_map, + .vm_unmap = panfrost_kmod_vm_unmap, +}; diff --git a/src/panfrost/lib/meson.build b/src/panfrost/lib/meson.build index 139f34b9afa..8f94153a765 100644 --- a/src/panfrost/lib/meson.build +++ b/src/panfrost/lib/meson.build @@ -20,6 +20,7 @@ # SOFTWARE. subdir('genxml') +subdir('kmod') pixel_format_versions = ['6', '7', '9'] libpanfrost_pixel_format = [] @@ -92,13 +93,13 @@ libpanfrost_lib = static_library( gnu_symbol_visibility : 'hidden', dependencies: [dep_libdrm, idep_nir, idep_mesautil], build_by_default : false, - link_with: [libpanfrost_pixel_format, libpanfrost_per_arch], + link_with: [libpanfrost_pixel_format, libpanfrost_per_arch, libpankmod_lib], ) libpanfrost_dep = declare_dependency( link_with: [libpanfrost_lib, libpanfrost_decode, libpanfrost_midgard, libpanfrost_bifrost, libpanfrost_pixel_format, libpanfrost_per_arch], include_directories: [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux, inc_panfrost_hw, inc_panfrost], - dependencies: [dep_libdrm, idep_nir, idep_pan_packers], + dependencies: [dep_libdrm, libpankmod_dep, idep_nir, idep_pan_packers], ) if with_tests -- 2.42.0