Path: blob/21.2-virgl/src/gallium/drivers/iris/iris_bufmgr.c
4565 views
/*1* Copyright © 2017 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included11* in all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS14* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING18* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER19* DEALINGS IN THE SOFTWARE.20*/2122/**23* @file iris_bufmgr.c24*25* The Iris buffer manager.26*27* XXX: write better comments28* - BOs29* - Explain BO cache30* - main interface to GEM in the kernel31*/3233#include <xf86drm.h>34#include <util/u_atomic.h>35#include <fcntl.h>36#include <stdio.h>37#include <stdlib.h>38#include <string.h>39#include <unistd.h>40#include <assert.h>41#include <sys/ioctl.h>42#include <sys/mman.h>43#include <sys/stat.h>44#include <sys/types.h>45#include <stdbool.h>46#include <time.h>47#include <unistd.h>4849#include "errno.h"50#include "common/intel_aux_map.h"51#include "common/intel_clflush.h"52#include "dev/intel_debug.h"53#include "common/intel_gem.h"54#include "dev/intel_device_info.h"55#include "isl/isl.h"56#include "main/macros.h"57#include "os/os_mman.h"58#include "util/debug.h"59#include "util/macros.h"60#include "util/hash_table.h"61#include "util/list.h"62#include "util/os_file.h"63#include "util/u_dynarray.h"64#include "util/vma.h"65#include "iris_bufmgr.h"66#include "iris_context.h"67#include "string.h"6869#include "drm-uapi/i915_drm.h"7071#ifdef HAVE_VALGRIND72#include <valgrind.h>73#include <memcheck.h>74#define VG(x) x75#else76#define VG(x)77#endif7879/* VALGRIND_FREELIKE_BLOCK unfortunately does not actually undo the earlier80* VALGRIND_MALLOCLIKE_BLOCK but instead leaves vg convinced the memory is81* leaked. All because it does not call VG(cli_free) from its82* VG_USERREQ__FREELIKE_BLOCK handler. Instead of treating the memory like83* and allocation, we mark it available for use upon mmapping and remove84* it upon unmapping.85*/86#define VG_DEFINED(ptr, size) VG(VALGRIND_MAKE_MEM_DEFINED(ptr, size))87#define VG_NOACCESS(ptr, size) VG(VALGRIND_MAKE_MEM_NOACCESS(ptr, size))8889/* On FreeBSD PAGE_SIZE is already defined in90* /usr/include/machine/param.h that is indirectly91* included here.92*/93#ifndef PAGE_SIZE94#define PAGE_SIZE 409695#endif9697#define WARN_ONCE(cond, fmt...) do { \98if (unlikely(cond)) { \99static bool _warned = false; \100if (!_warned) { \101fprintf(stderr, "WARNING: "); \102fprintf(stderr, fmt); \103_warned = true; \104} \105} \106} while (0)107108#define FILE_DEBUG_FLAG DEBUG_BUFMGR109110/**111* For debugging purposes, this returns a time in seconds.112*/113static double114get_time(void)115{116struct timespec tp;117118clock_gettime(CLOCK_MONOTONIC, &tp);119120return tp.tv_sec + tp.tv_nsec / 1000000000.0;121}122123static inline int124atomic_add_unless(int *v, int add, int unless)125{126int c, old;127c = p_atomic_read(v);128while (c != unless && (old = p_atomic_cmpxchg(v, c, c + add)) != c)129c = old;130return c == unless;131}132133static const char *134memzone_name(enum iris_memory_zone memzone)135{136const char *names[] = {137[IRIS_MEMZONE_SHADER] = "shader",138[IRIS_MEMZONE_BINDER] = "binder",139[IRIS_MEMZONE_BINDLESS] = "scratchsurf",140[IRIS_MEMZONE_SURFACE] = "surface",141[IRIS_MEMZONE_DYNAMIC] = "dynamic",142[IRIS_MEMZONE_OTHER] = "other",143[IRIS_MEMZONE_BORDER_COLOR_POOL] = "bordercolor",144};145assert(memzone < ARRAY_SIZE(names));146return names[memzone];147}148149struct bo_cache_bucket {150/** List of cached BOs. */151struct list_head head;152153/** Size of this bucket, in bytes. */154uint64_t size;155};156157struct bo_export {158/** File descriptor associated with a handle export. */159int drm_fd;160161/** GEM handle in drm_fd */162uint32_t gem_handle;163164struct list_head link;165};166167struct iris_memregion {168struct drm_i915_gem_memory_class_instance region;169uint64_t size;170};171172struct iris_bufmgr {173/**174* List into the list of bufmgr.175*/176struct list_head link;177178uint32_t refcount;179180int fd;181182simple_mtx_t lock;183184/** Array of lists of cached gem objects of power-of-two sizes */185struct bo_cache_bucket cache_bucket[14 * 4];186int num_buckets;187188/** Same as cache_bucket, but for local memory gem objects */189struct bo_cache_bucket local_cache_bucket[14 * 4];190int num_local_buckets;191192time_t time;193194struct hash_table *name_table;195struct hash_table *handle_table;196197/**198* List of BOs which we've effectively freed, but are hanging on to199* until they're idle before closing and returning the VMA.200*/201struct list_head zombie_list;202203struct util_vma_heap vma_allocator[IRIS_MEMZONE_COUNT];204205uint64_t vma_min_align;206struct iris_memregion vram, sys;207208bool has_llc:1;209bool has_mmap_offset:1;210bool has_tiling_uapi:1;211bool bo_reuse:1;212213struct intel_aux_map_context *aux_map_ctx;214};215216static simple_mtx_t global_bufmgr_list_mutex = _SIMPLE_MTX_INITIALIZER_NP;217static struct list_head global_bufmgr_list = {218.next = &global_bufmgr_list,219.prev = &global_bufmgr_list,220};221222static void bo_free(struct iris_bo *bo);223224static struct iris_bo *225find_and_ref_external_bo(struct hash_table *ht, unsigned int key)226{227struct hash_entry *entry = _mesa_hash_table_search(ht, &key);228struct iris_bo *bo = entry ? entry->data : NULL;229230if (bo) {231assert(iris_bo_is_external(bo));232assert(!bo->reusable);233234/* Being non-reusable, the BO cannot be in the cache lists, but it235* may be in the zombie list if it had reached zero references, but236* we hadn't yet closed it...and then reimported the same BO. If it237* is, then remove it since it's now been resurrected.238*/239if (list_is_linked(&bo->head))240list_del(&bo->head);241242iris_bo_reference(bo);243}244245return bo;246}247248/**249* This function finds the correct bucket fit for the input size.250* The function works with O(1) complexity when the requested size251* was queried instead of iterating the size through all the buckets.252*/253static struct bo_cache_bucket *254bucket_for_size(struct iris_bufmgr *bufmgr, uint64_t size, bool local)255{256/* Calculating the pages and rounding up to the page size. */257const unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;258259/* Row Bucket sizes clz((x-1) | 3) Row Column260* in pages stride size261* 0: 1 2 3 4 -> 30 30 30 30 4 1262* 1: 5 6 7 8 -> 29 29 29 29 4 1263* 2: 10 12 14 16 -> 28 28 28 28 8 2264* 3: 20 24 28 32 -> 27 27 27 27 16 4265*/266const unsigned row = 30 - __builtin_clz((pages - 1) | 3);267const unsigned row_max_pages = 4 << row;268269/* The '& ~2' is the special case for row 1. In row 1, max pages /270* 2 is 2, but the previous row maximum is zero (because there is271* no previous row). All row maximum sizes are power of 2, so that272* is the only case where that bit will be set.273*/274const unsigned prev_row_max_pages = (row_max_pages / 2) & ~2;275int col_size_log2 = row - 1;276col_size_log2 += (col_size_log2 < 0);277278const unsigned col = (pages - prev_row_max_pages +279((1 << col_size_log2) - 1)) >> col_size_log2;280281/* Calculating the index based on the row and column. */282const unsigned index = (row * 4) + (col - 1);283284int num_buckets = local ? bufmgr->num_local_buckets : bufmgr->num_buckets;285struct bo_cache_bucket *buckets = local ?286bufmgr->local_cache_bucket : bufmgr->cache_bucket;287288return (index < num_buckets) ? &buckets[index] : NULL;289}290291enum iris_memory_zone292iris_memzone_for_address(uint64_t address)293{294STATIC_ASSERT(IRIS_MEMZONE_OTHER_START > IRIS_MEMZONE_DYNAMIC_START);295STATIC_ASSERT(IRIS_MEMZONE_DYNAMIC_START > IRIS_MEMZONE_SURFACE_START);296STATIC_ASSERT(IRIS_MEMZONE_SURFACE_START > IRIS_MEMZONE_BINDLESS_START);297STATIC_ASSERT(IRIS_MEMZONE_BINDLESS_START > IRIS_MEMZONE_BINDER_START);298STATIC_ASSERT(IRIS_MEMZONE_BINDER_START > IRIS_MEMZONE_SHADER_START);299STATIC_ASSERT(IRIS_BORDER_COLOR_POOL_ADDRESS == IRIS_MEMZONE_DYNAMIC_START);300301if (address >= IRIS_MEMZONE_OTHER_START)302return IRIS_MEMZONE_OTHER;303304if (address == IRIS_BORDER_COLOR_POOL_ADDRESS)305return IRIS_MEMZONE_BORDER_COLOR_POOL;306307if (address > IRIS_MEMZONE_DYNAMIC_START)308return IRIS_MEMZONE_DYNAMIC;309310if (address >= IRIS_MEMZONE_SURFACE_START)311return IRIS_MEMZONE_SURFACE;312313if (address >= IRIS_MEMZONE_BINDLESS_START)314return IRIS_MEMZONE_BINDLESS;315316if (address >= IRIS_MEMZONE_BINDER_START)317return IRIS_MEMZONE_BINDER;318319return IRIS_MEMZONE_SHADER;320}321322/**323* Allocate a section of virtual memory for a buffer, assigning an address.324*325* This uses either the bucket allocator for the given size, or the large326* object allocator (util_vma).327*/328static uint64_t329vma_alloc(struct iris_bufmgr *bufmgr,330enum iris_memory_zone memzone,331uint64_t size,332uint64_t alignment)333{334/* Force minimum alignment based on device requirements */335assert((alignment & (alignment - 1)) == 0);336alignment = MAX2(alignment, bufmgr->vma_min_align);337338if (memzone == IRIS_MEMZONE_BORDER_COLOR_POOL)339return IRIS_BORDER_COLOR_POOL_ADDRESS;340341/* The binder handles its own allocations. Return non-zero here. */342if (memzone == IRIS_MEMZONE_BINDER)343return IRIS_MEMZONE_BINDER_START;344345uint64_t addr =346util_vma_heap_alloc(&bufmgr->vma_allocator[memzone], size, alignment);347348assert((addr >> 48ull) == 0);349assert((addr % alignment) == 0);350351return intel_canonical_address(addr);352}353354static void355vma_free(struct iris_bufmgr *bufmgr,356uint64_t address,357uint64_t size)358{359if (address == IRIS_BORDER_COLOR_POOL_ADDRESS)360return;361362/* Un-canonicalize the address. */363address = intel_48b_address(address);364365if (address == 0ull)366return;367368enum iris_memory_zone memzone = iris_memzone_for_address(address);369370/* The binder handles its own allocations. */371if (memzone == IRIS_MEMZONE_BINDER)372return;373374assert(memzone < ARRAY_SIZE(bufmgr->vma_allocator));375376util_vma_heap_free(&bufmgr->vma_allocator[memzone], address, size);377}378379int380iris_bo_busy(struct iris_bo *bo)381{382struct iris_bufmgr *bufmgr = bo->bufmgr;383struct drm_i915_gem_busy busy = { .handle = bo->gem_handle };384385int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);386if (ret == 0) {387bo->idle = !busy.busy;388return busy.busy;389}390return false;391}392393int394iris_bo_madvise(struct iris_bo *bo, int state)395{396struct drm_i915_gem_madvise madv = {397.handle = bo->gem_handle,398.madv = state,399.retained = 1,400};401402intel_ioctl(bo->bufmgr->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);403404return madv.retained;405}406407static struct iris_bo *408bo_calloc(void)409{410struct iris_bo *bo = calloc(1, sizeof(*bo));411if (!bo)412return NULL;413414list_inithead(&bo->exports);415416bo->hash = _mesa_hash_pointer(bo);417418return bo;419}420421static void422bo_unmap(struct iris_bo *bo)423{424VG_NOACCESS(bo->map, bo->size);425os_munmap(bo->map, bo->size);426bo->map = NULL;427}428429static struct iris_bo *430alloc_bo_from_cache(struct iris_bufmgr *bufmgr,431struct bo_cache_bucket *bucket,432uint32_t alignment,433enum iris_memory_zone memzone,434enum iris_mmap_mode mmap_mode,435unsigned flags,436bool match_zone)437{438if (!bucket)439return NULL;440441struct iris_bo *bo = NULL;442443list_for_each_entry_safe(struct iris_bo, cur, &bucket->head, head) {444/* Find one that's got the right mapping type. We used to swap maps445* around but the kernel doesn't allow this on discrete GPUs.446*/447if (mmap_mode != cur->mmap_mode)448continue;449450/* Try a little harder to find one that's already in the right memzone */451if (match_zone && memzone != iris_memzone_for_address(cur->gtt_offset))452continue;453454/* If the last BO in the cache is busy, there are no idle BOs. Bail,455* either falling back to a non-matching memzone, or if that fails,456* allocating a fresh buffer.457*/458if (iris_bo_busy(cur))459return NULL;460461list_del(&cur->head);462463/* Tell the kernel we need this BO. If it still exists, we're done! */464if (iris_bo_madvise(cur, I915_MADV_WILLNEED)) {465bo = cur;466break;467}468469/* This BO was purged, throw it out and keep looking. */470bo_free(cur);471}472473if (!bo)474return NULL;475476if (bo->aux_map_address) {477/* This buffer was associated with an aux-buffer range. We make sure478* that buffers are not reused from the cache while the buffer is (busy)479* being used by an executing batch. Since we are here, the buffer is no480* longer being used by a batch and the buffer was deleted (in order to481* end up in the cache). Therefore its old aux-buffer range can be482* removed from the aux-map.483*/484if (bo->bufmgr->aux_map_ctx)485intel_aux_map_unmap_range(bo->bufmgr->aux_map_ctx, bo->gtt_offset,486bo->size);487bo->aux_map_address = 0;488}489490/* If the cached BO isn't in the right memory zone, or the alignment491* isn't sufficient, free the old memory and assign it a new address.492*/493if (memzone != iris_memzone_for_address(bo->gtt_offset) ||494bo->gtt_offset % alignment != 0) {495vma_free(bufmgr, bo->gtt_offset, bo->size);496bo->gtt_offset = 0ull;497}498499/* Zero the contents if necessary. If this fails, fall back to500* allocating a fresh BO, which will always be zeroed by the kernel.501*/502if (flags & BO_ALLOC_ZEROED) {503void *map = iris_bo_map(NULL, bo, MAP_WRITE | MAP_RAW);504if (map) {505memset(map, 0, bo->size);506} else {507bo_free(bo);508return NULL;509}510}511512return bo;513}514515static struct iris_bo *516alloc_fresh_bo(struct iris_bufmgr *bufmgr, uint64_t bo_size, bool local)517{518struct iris_bo *bo = bo_calloc();519if (!bo)520return NULL;521522/* If we have vram size, we have multiple memory regions and should choose523* one of them.524*/525if (bufmgr->vram.size > 0) {526/* All new BOs we get from the kernel are zeroed, so we don't need to527* worry about that here.528*/529struct drm_i915_gem_memory_class_instance regions[2];530uint32_t nregions = 0;531if (local) {532/* For vram allocations, still use system memory as a fallback. */533regions[nregions++] = bufmgr->vram.region;534regions[nregions++] = bufmgr->sys.region;535} else {536regions[nregions++] = bufmgr->sys.region;537}538539struct drm_i915_gem_create_ext_memory_regions ext_regions = {540.base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS },541.num_regions = nregions,542.regions = (uintptr_t)regions,543};544545struct drm_i915_gem_create_ext create = {546.size = bo_size,547.extensions = (uintptr_t)&ext_regions,548};549550/* It should be safe to use GEM_CREATE_EXT without checking, since we are551* in the side of the branch where discrete memory is available. So we552* can assume GEM_CREATE_EXT is supported already.553*/554if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create) != 0) {555free(bo);556return NULL;557}558bo->gem_handle = create.handle;559} else {560struct drm_i915_gem_create create = { .size = bo_size };561562/* All new BOs we get from the kernel are zeroed, so we don't need to563* worry about that here.564*/565if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {566free(bo);567return NULL;568}569bo->gem_handle = create.handle;570}571572bo->bufmgr = bufmgr;573bo->size = bo_size;574bo->idle = true;575bo->local = local;576577/* Calling set_domain() will allocate pages for the BO outside of the578* struct mutex lock in the kernel, which is more efficient than waiting579* to create them during the first execbuf that uses the BO.580*/581struct drm_i915_gem_set_domain sd = {582.handle = bo->gem_handle,583.read_domains = I915_GEM_DOMAIN_CPU,584.write_domain = 0,585};586587if (intel_ioctl(bo->bufmgr->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &sd) != 0) {588bo_free(bo);589return NULL;590}591592return bo;593}594595struct iris_bo *596iris_bo_alloc(struct iris_bufmgr *bufmgr,597const char *name,598uint64_t size,599uint32_t alignment,600enum iris_memory_zone memzone,601unsigned flags)602{603struct iris_bo *bo;604unsigned int page_size = getpagesize();605bool local = bufmgr->vram.size > 0 &&606!(flags & BO_ALLOC_COHERENT || flags & BO_ALLOC_SMEM);607struct bo_cache_bucket *bucket = bucket_for_size(bufmgr, size, local);608609/* Round the size up to the bucket size, or if we don't have caching610* at this size, a multiple of the page size.611*/612uint64_t bo_size =613bucket ? bucket->size : MAX2(ALIGN(size, page_size), page_size);614615bool is_coherent = bufmgr->has_llc || (flags & BO_ALLOC_COHERENT);616enum iris_mmap_mode mmap_mode =617!local && is_coherent ? IRIS_MMAP_WB : IRIS_MMAP_WC;618619simple_mtx_lock(&bufmgr->lock);620621/* Get a buffer out of the cache if available. First, we try to find622* one with a matching memory zone so we can avoid reallocating VMA.623*/624bo = alloc_bo_from_cache(bufmgr, bucket, alignment, memzone, mmap_mode,625flags, true);626627/* If that fails, we try for any cached BO, without matching memzone. */628if (!bo) {629bo = alloc_bo_from_cache(bufmgr, bucket, alignment, memzone, mmap_mode,630flags, false);631}632633simple_mtx_unlock(&bufmgr->lock);634635if (!bo) {636bo = alloc_fresh_bo(bufmgr, bo_size, local);637if (!bo)638return NULL;639}640641if (bo->gtt_offset == 0ull) {642simple_mtx_lock(&bufmgr->lock);643bo->gtt_offset = vma_alloc(bufmgr, memzone, bo->size, alignment);644simple_mtx_unlock(&bufmgr->lock);645646if (bo->gtt_offset == 0ull)647goto err_free;648}649650bo->name = name;651p_atomic_set(&bo->refcount, 1);652bo->reusable = bucket && bufmgr->bo_reuse;653bo->index = -1;654bo->kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED;655656/* By default, capture all driver-internal buffers like shader kernels,657* surface states, dynamic states, border colors, and so on.658*/659if (memzone < IRIS_MEMZONE_OTHER)660bo->kflags |= EXEC_OBJECT_CAPTURE;661662assert(bo->map == NULL || bo->mmap_mode == mmap_mode);663bo->mmap_mode = mmap_mode;664665/* On integrated GPUs, enable snooping to ensure coherency if needed.666* For discrete, we instead use SMEM and avoid WB maps for coherency.667*/668if ((flags & BO_ALLOC_COHERENT) &&669!bufmgr->has_llc && bufmgr->vram.size == 0) {670struct drm_i915_gem_caching arg = {671.handle = bo->gem_handle,672.caching = 1,673};674if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_CACHING, &arg) != 0)675goto err_free;676677bo->reusable = false;678}679680DBG("bo_create: buf %d (%s) (%s memzone) (%s) %llub\n", bo->gem_handle,681bo->name, memzone_name(memzone), bo->local ? "local" : "system",682(unsigned long long) size);683684return bo;685686err_free:687bo_free(bo);688return NULL;689}690691struct iris_bo *692iris_bo_create_userptr(struct iris_bufmgr *bufmgr, const char *name,693void *ptr, size_t size,694enum iris_memory_zone memzone)695{696struct drm_gem_close close = { 0, };697struct iris_bo *bo;698699bo = bo_calloc();700if (!bo)701return NULL;702703struct drm_i915_gem_userptr arg = {704.user_ptr = (uintptr_t)ptr,705.user_size = size,706};707if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_USERPTR, &arg))708goto err_free;709bo->gem_handle = arg.handle;710711/* Check the buffer for validity before we try and use it in a batch */712struct drm_i915_gem_set_domain sd = {713.handle = bo->gem_handle,714.read_domains = I915_GEM_DOMAIN_CPU,715};716if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &sd))717goto err_close;718719bo->name = name;720bo->size = size;721bo->map = ptr;722723bo->bufmgr = bufmgr;724bo->kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED;725726simple_mtx_lock(&bufmgr->lock);727bo->gtt_offset = vma_alloc(bufmgr, memzone, size, 1);728simple_mtx_unlock(&bufmgr->lock);729730if (bo->gtt_offset == 0ull)731goto err_close;732733p_atomic_set(&bo->refcount, 1);734bo->userptr = true;735bo->index = -1;736bo->idle = true;737bo->mmap_mode = IRIS_MMAP_WB;738739return bo;740741err_close:742close.handle = bo->gem_handle;743intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_CLOSE, &close);744err_free:745free(bo);746return NULL;747}748749/**750* Returns a iris_bo wrapping the given buffer object handle.751*752* This can be used when one application needs to pass a buffer object753* to another.754*/755struct iris_bo *756iris_bo_gem_create_from_name(struct iris_bufmgr *bufmgr,757const char *name, unsigned int handle)758{759struct iris_bo *bo;760761/* At the moment most applications only have a few named bo.762* For instance, in a DRI client only the render buffers passed763* between X and the client are named. And since X returns the764* alternating names for the front/back buffer a linear search765* provides a sufficiently fast match.766*/767simple_mtx_lock(&bufmgr->lock);768bo = find_and_ref_external_bo(bufmgr->name_table, handle);769if (bo)770goto out;771772struct drm_gem_open open_arg = { .name = handle };773int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_OPEN, &open_arg);774if (ret != 0) {775DBG("Couldn't reference %s handle 0x%08x: %s\n",776name, handle, strerror(errno));777bo = NULL;778goto out;779}780/* Now see if someone has used a prime handle to get this781* object from the kernel before by looking through the list782* again for a matching gem_handle783*/784bo = find_and_ref_external_bo(bufmgr->handle_table, open_arg.handle);785if (bo)786goto out;787788bo = bo_calloc();789if (!bo)790goto out;791792p_atomic_set(&bo->refcount, 1);793794bo->size = open_arg.size;795bo->bufmgr = bufmgr;796bo->gem_handle = open_arg.handle;797bo->name = name;798bo->global_name = handle;799bo->reusable = false;800bo->imported = true;801bo->mmap_mode = IRIS_MMAP_WC;802bo->kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED;803bo->gtt_offset = vma_alloc(bufmgr, IRIS_MEMZONE_OTHER, bo->size, 1);804805_mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo);806_mesa_hash_table_insert(bufmgr->name_table, &bo->global_name, bo);807808DBG("bo_create_from_handle: %d (%s)\n", handle, bo->name);809810out:811simple_mtx_unlock(&bufmgr->lock);812return bo;813}814815static void816bo_close(struct iris_bo *bo)817{818struct iris_bufmgr *bufmgr = bo->bufmgr;819820if (iris_bo_is_external(bo)) {821struct hash_entry *entry;822823if (bo->global_name) {824entry = _mesa_hash_table_search(bufmgr->name_table, &bo->global_name);825_mesa_hash_table_remove(bufmgr->name_table, entry);826}827828entry = _mesa_hash_table_search(bufmgr->handle_table, &bo->gem_handle);829_mesa_hash_table_remove(bufmgr->handle_table, entry);830831list_for_each_entry_safe(struct bo_export, export, &bo->exports, link) {832struct drm_gem_close close = { .handle = export->gem_handle };833intel_ioctl(export->drm_fd, DRM_IOCTL_GEM_CLOSE, &close);834835list_del(&export->link);836free(export);837}838} else {839assert(list_is_empty(&bo->exports));840}841842/* Close this object */843struct drm_gem_close close = { .handle = bo->gem_handle };844int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_CLOSE, &close);845if (ret != 0) {846DBG("DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n",847bo->gem_handle, bo->name, strerror(errno));848}849850if (bo->aux_map_address && bo->bufmgr->aux_map_ctx) {851intel_aux_map_unmap_range(bo->bufmgr->aux_map_ctx, bo->gtt_offset,852bo->size);853}854855/* Return the VMA for reuse */856vma_free(bo->bufmgr, bo->gtt_offset, bo->size);857858free(bo);859}860861static void862bo_free(struct iris_bo *bo)863{864struct iris_bufmgr *bufmgr = bo->bufmgr;865866if (!bo->userptr && bo->map)867bo_unmap(bo);868869if (bo->idle) {870bo_close(bo);871} else {872/* Defer closing the GEM BO and returning the VMA for reuse until the873* BO is idle. Just move it to the dead list for now.874*/875list_addtail(&bo->head, &bufmgr->zombie_list);876}877}878879/** Frees all cached buffers significantly older than @time. */880static void881cleanup_bo_cache(struct iris_bufmgr *bufmgr, time_t time)882{883int i;884885if (bufmgr->time == time)886return;887888for (i = 0; i < bufmgr->num_buckets; i++) {889struct bo_cache_bucket *bucket = &bufmgr->cache_bucket[i];890891list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) {892if (time - bo->free_time <= 1)893break;894895list_del(&bo->head);896897bo_free(bo);898}899}900901for (i = 0; i < bufmgr->num_local_buckets; i++) {902struct bo_cache_bucket *bucket = &bufmgr->local_cache_bucket[i];903904list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) {905if (time - bo->free_time <= 1)906break;907908list_del(&bo->head);909910bo_free(bo);911}912}913914list_for_each_entry_safe(struct iris_bo, bo, &bufmgr->zombie_list, head) {915/* Stop once we reach a busy BO - all others past this point were916* freed more recently so are likely also busy.917*/918if (!bo->idle && iris_bo_busy(bo))919break;920921list_del(&bo->head);922bo_close(bo);923}924925bufmgr->time = time;926}927928static void929bo_unreference_final(struct iris_bo *bo, time_t time)930{931struct iris_bufmgr *bufmgr = bo->bufmgr;932struct bo_cache_bucket *bucket;933934DBG("bo_unreference final: %d (%s)\n", bo->gem_handle, bo->name);935936bucket = NULL;937if (bo->reusable)938bucket = bucket_for_size(bufmgr, bo->size, bo->local);939/* Put the buffer into our internal cache for reuse if we can. */940if (bucket && iris_bo_madvise(bo, I915_MADV_DONTNEED)) {941bo->free_time = time;942bo->name = NULL;943944list_addtail(&bo->head, &bucket->head);945} else {946bo_free(bo);947}948}949950void951iris_bo_unreference(struct iris_bo *bo)952{953if (bo == NULL)954return;955956assert(p_atomic_read(&bo->refcount) > 0);957958if (atomic_add_unless(&bo->refcount, -1, 1)) {959struct iris_bufmgr *bufmgr = bo->bufmgr;960struct timespec time;961962clock_gettime(CLOCK_MONOTONIC, &time);963964simple_mtx_lock(&bufmgr->lock);965966if (p_atomic_dec_zero(&bo->refcount)) {967bo_unreference_final(bo, time.tv_sec);968cleanup_bo_cache(bufmgr, time.tv_sec);969}970971simple_mtx_unlock(&bufmgr->lock);972}973}974975static void976bo_wait_with_stall_warning(struct pipe_debug_callback *dbg,977struct iris_bo *bo,978const char *action)979{980bool busy = dbg && !bo->idle;981double elapsed = unlikely(busy) ? -get_time() : 0.0;982983iris_bo_wait_rendering(bo);984985if (unlikely(busy)) {986elapsed += get_time();987if (elapsed > 1e-5) /* 0.01ms */ {988perf_debug(dbg, "%s a busy \"%s\" BO stalled and took %.03f ms.\n",989action, bo->name, elapsed * 1000);990}991}992}993994static void995print_flags(unsigned flags)996{997if (flags & MAP_READ)998DBG("READ ");999if (flags & MAP_WRITE)1000DBG("WRITE ");1001if (flags & MAP_ASYNC)1002DBG("ASYNC ");1003if (flags & MAP_PERSISTENT)1004DBG("PERSISTENT ");1005if (flags & MAP_COHERENT)1006DBG("COHERENT ");1007if (flags & MAP_RAW)1008DBG("RAW ");1009DBG("\n");1010}10111012static void *1013iris_bo_gem_mmap_legacy(struct pipe_debug_callback *dbg, struct iris_bo *bo)1014{1015struct iris_bufmgr *bufmgr = bo->bufmgr;10161017struct drm_i915_gem_mmap mmap_arg = {1018.handle = bo->gem_handle,1019.size = bo->size,1020.flags = bo->mmap_mode == IRIS_MMAP_WC ? I915_MMAP_WC : 0,1021};10221023int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);1024if (ret != 0) {1025DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",1026__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));1027return NULL;1028}1029void *map = (void *) (uintptr_t) mmap_arg.addr_ptr;10301031return map;1032}10331034static void *1035iris_bo_gem_mmap_offset(struct pipe_debug_callback *dbg, struct iris_bo *bo)1036{1037struct iris_bufmgr *bufmgr = bo->bufmgr;10381039struct drm_i915_gem_mmap_offset mmap_arg = {1040.handle = bo->gem_handle,1041};10421043if (bo->mmap_mode == IRIS_MMAP_WB)1044mmap_arg.flags = I915_MMAP_OFFSET_WB;1045else if (bo->mmap_mode == IRIS_MMAP_WC)1046mmap_arg.flags = I915_MMAP_OFFSET_WC;1047else1048mmap_arg.flags = I915_MMAP_OFFSET_UC;10491050/* Get the fake offset back */1051int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &mmap_arg);1052if (ret != 0) {1053DBG("%s:%d: Error preparing buffer %d (%s): %s .\n",1054__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));1055return NULL;1056}10571058/* And map it */1059void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,1060bufmgr->fd, mmap_arg.offset);1061if (map == MAP_FAILED) {1062DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",1063__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));1064return NULL;1065}10661067return map;1068}10691070void *1071iris_bo_map(struct pipe_debug_callback *dbg,1072struct iris_bo *bo, unsigned flags)1073{1074struct iris_bufmgr *bufmgr = bo->bufmgr;10751076if (!bo->map) {1077DBG("iris_bo_map: %d (%s)\n", bo->gem_handle, bo->name);1078void *map = bufmgr->has_mmap_offset ? iris_bo_gem_mmap_offset(dbg, bo)1079: iris_bo_gem_mmap_legacy(dbg, bo);1080if (!map) {1081return NULL;1082}10831084VG_DEFINED(map, bo->size);10851086if (p_atomic_cmpxchg(&bo->map, NULL, map)) {1087VG_NOACCESS(map, bo->size);1088os_munmap(map, bo->size);1089}1090}1091assert(bo->map);10921093DBG("iris_bo_map: %d (%s) -> %p\n", bo->gem_handle, bo->name, bo->map);1094print_flags(flags);10951096if (!(flags & MAP_ASYNC)) {1097bo_wait_with_stall_warning(dbg, bo, "memory mapping");1098}10991100return bo->map;1101}11021103/** Waits for all GPU rendering with the object to have completed. */1104void1105iris_bo_wait_rendering(struct iris_bo *bo)1106{1107/* We require a kernel recent enough for WAIT_IOCTL support.1108* See intel_init_bufmgr()1109*/1110iris_bo_wait(bo, -1);1111}11121113/**1114* Waits on a BO for the given amount of time.1115*1116* @bo: buffer object to wait for1117* @timeout_ns: amount of time to wait in nanoseconds.1118* If value is less than 0, an infinite wait will occur.1119*1120* Returns 0 if the wait was successful ie. the last batch referencing the1121* object has completed within the allotted time. Otherwise some negative return1122* value describes the error. Of particular interest is -ETIME when the wait has1123* failed to yield the desired result.1124*1125* Similar to iris_bo_wait_rendering except a timeout parameter allows1126* the operation to give up after a certain amount of time. Another subtle1127* difference is the internal locking semantics are different (this variant does1128* not hold the lock for the duration of the wait). This makes the wait subject1129* to a larger userspace race window.1130*1131* The implementation shall wait until the object is no longer actively1132* referenced within a batch buffer at the time of the call. The wait will1133* not guarantee that the buffer is re-issued via another thread, or an flinked1134* handle. Userspace must make sure this race does not occur if such precision1135* is important.1136*1137* Note that some kernels have broken the infinite wait for negative values1138* promise, upgrade to latest stable kernels if this is the case.1139*/1140int1141iris_bo_wait(struct iris_bo *bo, int64_t timeout_ns)1142{1143struct iris_bufmgr *bufmgr = bo->bufmgr;11441145/* If we know it's idle, don't bother with the kernel round trip */1146if (bo->idle && !iris_bo_is_external(bo))1147return 0;11481149struct drm_i915_gem_wait wait = {1150.bo_handle = bo->gem_handle,1151.timeout_ns = timeout_ns,1152};1153int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_WAIT, &wait);1154if (ret != 0)1155return -errno;11561157bo->idle = true;11581159return ret;1160}11611162static void1163iris_bufmgr_destroy(struct iris_bufmgr *bufmgr)1164{1165/* Free aux-map buffers */1166intel_aux_map_finish(bufmgr->aux_map_ctx);11671168/* bufmgr will no longer try to free VMA entries in the aux-map */1169bufmgr->aux_map_ctx = NULL;11701171simple_mtx_destroy(&bufmgr->lock);11721173/* Free any cached buffer objects we were going to reuse */1174for (int i = 0; i < bufmgr->num_buckets; i++) {1175struct bo_cache_bucket *bucket = &bufmgr->cache_bucket[i];11761177list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) {1178list_del(&bo->head);11791180bo_free(bo);1181}1182}11831184/* Close any buffer objects on the dead list. */1185list_for_each_entry_safe(struct iris_bo, bo, &bufmgr->zombie_list, head) {1186list_del(&bo->head);1187bo_close(bo);1188}11891190_mesa_hash_table_destroy(bufmgr->name_table, NULL);1191_mesa_hash_table_destroy(bufmgr->handle_table, NULL);11921193for (int z = 0; z < IRIS_MEMZONE_COUNT; z++) {1194if (z != IRIS_MEMZONE_BINDER)1195util_vma_heap_finish(&bufmgr->vma_allocator[z]);1196}11971198close(bufmgr->fd);11991200free(bufmgr);1201}12021203int1204iris_gem_get_tiling(struct iris_bo *bo, uint32_t *tiling)1205{1206struct iris_bufmgr *bufmgr = bo->bufmgr;12071208if (!bufmgr->has_tiling_uapi) {1209*tiling = I915_TILING_NONE;1210return 0;1211}12121213struct drm_i915_gem_get_tiling ti = { .handle = bo->gem_handle };1214int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_GET_TILING, &ti);12151216if (ret) {1217DBG("gem_get_tiling failed for BO %u: %s\n",1218bo->gem_handle, strerror(errno));1219}12201221*tiling = ti.tiling_mode;12221223return ret;1224}12251226int1227iris_gem_set_tiling(struct iris_bo *bo, const struct isl_surf *surf)1228{1229struct iris_bufmgr *bufmgr = bo->bufmgr;1230uint32_t tiling_mode = isl_tiling_to_i915_tiling(surf->tiling);1231int ret;12321233/* If we can't do map_gtt, the set/get_tiling API isn't useful. And it's1234* actually not supported by the kernel in those cases.1235*/1236if (!bufmgr->has_tiling_uapi)1237return 0;12381239/* GEM_SET_TILING is slightly broken and overwrites the input on the1240* error path, so we have to open code intel_ioctl().1241*/1242do {1243struct drm_i915_gem_set_tiling set_tiling = {1244.handle = bo->gem_handle,1245.tiling_mode = tiling_mode,1246.stride = surf->row_pitch_B,1247};1248ret = ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);1249} while (ret == -1 && (errno == EINTR || errno == EAGAIN));12501251if (ret) {1252DBG("gem_set_tiling failed for BO %u: %s\n",1253bo->gem_handle, strerror(errno));1254}12551256return ret;1257}12581259struct iris_bo *1260iris_bo_import_dmabuf(struct iris_bufmgr *bufmgr, int prime_fd)1261{1262uint32_t handle;1263struct iris_bo *bo;12641265simple_mtx_lock(&bufmgr->lock);1266int ret = drmPrimeFDToHandle(bufmgr->fd, prime_fd, &handle);1267if (ret) {1268DBG("import_dmabuf: failed to obtain handle from fd: %s\n",1269strerror(errno));1270simple_mtx_unlock(&bufmgr->lock);1271return NULL;1272}12731274/*1275* See if the kernel has already returned this buffer to us. Just as1276* for named buffers, we must not create two bo's pointing at the same1277* kernel object1278*/1279bo = find_and_ref_external_bo(bufmgr->handle_table, handle);1280if (bo)1281goto out;12821283bo = bo_calloc();1284if (!bo)1285goto out;12861287p_atomic_set(&bo->refcount, 1);12881289/* Determine size of bo. The fd-to-handle ioctl really should1290* return the size, but it doesn't. If we have kernel 3.12 or1291* later, we can lseek on the prime fd to get the size. Older1292* kernels will just fail, in which case we fall back to the1293* provided (estimated or guess size). */1294ret = lseek(prime_fd, 0, SEEK_END);1295if (ret != -1)1296bo->size = ret;12971298bo->bufmgr = bufmgr;1299bo->name = "prime";1300bo->reusable = false;1301bo->imported = true;1302bo->mmap_mode = IRIS_MMAP_WC;1303bo->kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED;13041305/* From the Bspec, Memory Compression - Gfx12:1306*1307* The base address for the surface has to be 64K page aligned and the1308* surface is expected to be padded in the virtual domain to be 4 4K1309* pages.1310*1311* The dmabuf may contain a compressed surface. Align the BO to 64KB just1312* in case. We always align to 64KB even on platforms where we don't need1313* to, because it's a fairly reasonable thing to do anyway.1314*/1315bo->gtt_offset =1316vma_alloc(bufmgr, IRIS_MEMZONE_OTHER, bo->size, 64 * 1024);13171318bo->gem_handle = handle;1319_mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo);13201321out:1322simple_mtx_unlock(&bufmgr->lock);1323return bo;1324}13251326static void1327iris_bo_mark_exported_locked(struct iris_bo *bo)1328{1329if (!iris_bo_is_external(bo))1330_mesa_hash_table_insert(bo->bufmgr->handle_table, &bo->gem_handle, bo);13311332if (!bo->exported) {1333/* If a BO is going to be used externally, it could be sent to the1334* display HW. So make sure our CPU mappings don't assume cache1335* coherency since display is outside that cache.1336*/1337bo->exported = true;1338bo->reusable = false;1339}1340}13411342void1343iris_bo_mark_exported(struct iris_bo *bo)1344{1345struct iris_bufmgr *bufmgr = bo->bufmgr;13461347if (bo->exported) {1348assert(!bo->reusable);1349return;1350}13511352simple_mtx_lock(&bufmgr->lock);1353iris_bo_mark_exported_locked(bo);1354simple_mtx_unlock(&bufmgr->lock);1355}13561357int1358iris_bo_export_dmabuf(struct iris_bo *bo, int *prime_fd)1359{1360struct iris_bufmgr *bufmgr = bo->bufmgr;13611362iris_bo_mark_exported(bo);13631364if (drmPrimeHandleToFD(bufmgr->fd, bo->gem_handle,1365DRM_CLOEXEC | DRM_RDWR, prime_fd) != 0)1366return -errno;13671368return 0;1369}13701371uint32_t1372iris_bo_export_gem_handle(struct iris_bo *bo)1373{1374iris_bo_mark_exported(bo);13751376return bo->gem_handle;1377}13781379int1380iris_bo_flink(struct iris_bo *bo, uint32_t *name)1381{1382struct iris_bufmgr *bufmgr = bo->bufmgr;13831384if (!bo->global_name) {1385struct drm_gem_flink flink = { .handle = bo->gem_handle };13861387if (intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_FLINK, &flink))1388return -errno;13891390simple_mtx_lock(&bufmgr->lock);1391if (!bo->global_name) {1392iris_bo_mark_exported_locked(bo);1393bo->global_name = flink.name;1394_mesa_hash_table_insert(bufmgr->name_table, &bo->global_name, bo);1395}1396simple_mtx_unlock(&bufmgr->lock);1397}13981399*name = bo->global_name;1400return 0;1401}14021403int1404iris_bo_export_gem_handle_for_device(struct iris_bo *bo, int drm_fd,1405uint32_t *out_handle)1406{1407/* Only add the new GEM handle to the list of export if it belongs to a1408* different GEM device. Otherwise we might close the same buffer multiple1409* times.1410*/1411struct iris_bufmgr *bufmgr = bo->bufmgr;1412int ret = os_same_file_description(drm_fd, bufmgr->fd);1413WARN_ONCE(ret < 0,1414"Kernel has no file descriptor comparison support: %s\n",1415strerror(errno));1416if (ret == 0) {1417*out_handle = iris_bo_export_gem_handle(bo);1418return 0;1419}14201421struct bo_export *export = calloc(1, sizeof(*export));1422if (!export)1423return -ENOMEM;14241425export->drm_fd = drm_fd;14261427int dmabuf_fd = -1;1428int err = iris_bo_export_dmabuf(bo, &dmabuf_fd);1429if (err) {1430free(export);1431return err;1432}14331434simple_mtx_lock(&bufmgr->lock);1435err = drmPrimeFDToHandle(drm_fd, dmabuf_fd, &export->gem_handle);1436close(dmabuf_fd);1437if (err) {1438simple_mtx_unlock(&bufmgr->lock);1439free(export);1440return err;1441}14421443bool found = false;1444list_for_each_entry(struct bo_export, iter, &bo->exports, link) {1445if (iter->drm_fd != drm_fd)1446continue;1447/* Here we assume that for a given DRM fd, we'll always get back the1448* same GEM handle for a given buffer.1449*/1450assert(iter->gem_handle == export->gem_handle);1451free(export);1452export = iter;1453found = true;1454break;1455}1456if (!found)1457list_addtail(&export->link, &bo->exports);14581459simple_mtx_unlock(&bufmgr->lock);14601461*out_handle = export->gem_handle;14621463return 0;1464}14651466static void1467add_bucket(struct iris_bufmgr *bufmgr, int size, bool local)1468{1469unsigned int i = local ?1470bufmgr->num_local_buckets : bufmgr->num_buckets;14711472struct bo_cache_bucket *buckets = local ?1473bufmgr->local_cache_bucket : bufmgr->cache_bucket;14741475assert(i < ARRAY_SIZE(bufmgr->cache_bucket));14761477list_inithead(&buckets[i].head);1478buckets[i].size = size;14791480if (local)1481bufmgr->num_local_buckets++;1482else1483bufmgr->num_buckets++;14841485assert(bucket_for_size(bufmgr, size, local) == &buckets[i]);1486assert(bucket_for_size(bufmgr, size - 2048, local) == &buckets[i]);1487assert(bucket_for_size(bufmgr, size + 1, local) != &buckets[i]);1488}14891490static void1491init_cache_buckets(struct iris_bufmgr *bufmgr, bool local)1492{1493uint64_t size, cache_max_size = 64 * 1024 * 1024;14941495/* OK, so power of two buckets was too wasteful of memory.1496* Give 3 other sizes between each power of two, to hopefully1497* cover things accurately enough. (The alternative is1498* probably to just go for exact matching of sizes, and assume1499* that for things like composited window resize the tiled1500* width/height alignment and rounding of sizes to pages will1501* get us useful cache hit rates anyway)1502*/1503add_bucket(bufmgr, PAGE_SIZE, local);1504add_bucket(bufmgr, PAGE_SIZE * 2, local);1505add_bucket(bufmgr, PAGE_SIZE * 3, local);15061507/* Initialize the linked lists for BO reuse cache. */1508for (size = 4 * PAGE_SIZE; size <= cache_max_size; size *= 2) {1509add_bucket(bufmgr, size, local);15101511add_bucket(bufmgr, size + size * 1 / 4, local);1512add_bucket(bufmgr, size + size * 2 / 4, local);1513add_bucket(bufmgr, size + size * 3 / 4, local);1514}1515}15161517uint32_t1518iris_create_hw_context(struct iris_bufmgr *bufmgr)1519{1520struct drm_i915_gem_context_create create = { };1521int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);1522if (ret != 0) {1523DBG("DRM_IOCTL_I915_GEM_CONTEXT_CREATE failed: %s\n", strerror(errno));1524return 0;1525}15261527/* Upon declaring a GPU hang, the kernel will zap the guilty context1528* back to the default logical HW state and attempt to continue on to1529* our next submitted batchbuffer. However, our render batches assume1530* the previous GPU state is preserved, and only emit commands needed1531* to incrementally change that state. In particular, we inherit the1532* STATE_BASE_ADDRESS and PIPELINE_SELECT settings, which are critical.1533* With default base addresses, our next batches will almost certainly1534* cause more GPU hangs, leading to repeated hangs until we're banned1535* or the machine is dead.1536*1537* Here we tell the kernel not to attempt to recover our context but1538* immediately (on the next batchbuffer submission) report that the1539* context is lost, and we will do the recovery ourselves. Ideally,1540* we'll have two lost batches instead of a continual stream of hangs.1541*/1542struct drm_i915_gem_context_param p = {1543.ctx_id = create.ctx_id,1544.param = I915_CONTEXT_PARAM_RECOVERABLE,1545.value = false,1546};1547intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p);15481549return create.ctx_id;1550}15511552static int1553iris_hw_context_get_priority(struct iris_bufmgr *bufmgr, uint32_t ctx_id)1554{1555struct drm_i915_gem_context_param p = {1556.ctx_id = ctx_id,1557.param = I915_CONTEXT_PARAM_PRIORITY,1558};1559intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p);1560return p.value; /* on error, return 0 i.e. default priority */1561}15621563int1564iris_hw_context_set_priority(struct iris_bufmgr *bufmgr,1565uint32_t ctx_id,1566int priority)1567{1568struct drm_i915_gem_context_param p = {1569.ctx_id = ctx_id,1570.param = I915_CONTEXT_PARAM_PRIORITY,1571.value = priority,1572};1573int err;15741575err = 0;1576if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p))1577err = -errno;15781579return err;1580}15811582uint32_t1583iris_clone_hw_context(struct iris_bufmgr *bufmgr, uint32_t ctx_id)1584{1585uint32_t new_ctx = iris_create_hw_context(bufmgr);15861587if (new_ctx) {1588int priority = iris_hw_context_get_priority(bufmgr, ctx_id);1589iris_hw_context_set_priority(bufmgr, new_ctx, priority);1590}15911592return new_ctx;1593}15941595void1596iris_destroy_hw_context(struct iris_bufmgr *bufmgr, uint32_t ctx_id)1597{1598struct drm_i915_gem_context_destroy d = { .ctx_id = ctx_id };15991600if (ctx_id != 0 &&1601intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &d) != 0) {1602fprintf(stderr, "DRM_IOCTL_I915_GEM_CONTEXT_DESTROY failed: %s\n",1603strerror(errno));1604}1605}16061607int1608iris_reg_read(struct iris_bufmgr *bufmgr, uint32_t offset, uint64_t *result)1609{1610struct drm_i915_reg_read reg_read = { .offset = offset };1611int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_REG_READ, ®_read);16121613*result = reg_read.val;1614return ret;1615}16161617static uint64_t1618iris_gtt_size(int fd)1619{1620/* We use the default (already allocated) context to determine1621* the default configuration of the virtual address space.1622*/1623struct drm_i915_gem_context_param p = {1624.param = I915_CONTEXT_PARAM_GTT_SIZE,1625};1626if (!intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p))1627return p.value;16281629return 0;1630}16311632static struct intel_buffer *1633intel_aux_map_buffer_alloc(void *driver_ctx, uint32_t size)1634{1635struct intel_buffer *buf = malloc(sizeof(struct intel_buffer));1636if (!buf)1637return NULL;16381639struct iris_bufmgr *bufmgr = (struct iris_bufmgr *)driver_ctx;16401641struct iris_bo *bo =1642iris_bo_alloc(bufmgr, "aux-map", size, 64 * 1024,1643IRIS_MEMZONE_OTHER, 0);16441645buf->driver_bo = bo;1646buf->gpu = bo->gtt_offset;1647buf->gpu_end = buf->gpu + bo->size;1648buf->map = iris_bo_map(NULL, bo, MAP_WRITE | MAP_RAW);1649return buf;1650}16511652static void1653intel_aux_map_buffer_free(void *driver_ctx, struct intel_buffer *buffer)1654{1655iris_bo_unreference((struct iris_bo*)buffer->driver_bo);1656free(buffer);1657}16581659static struct intel_mapped_pinned_buffer_alloc aux_map_allocator = {1660.alloc = intel_aux_map_buffer_alloc,1661.free = intel_aux_map_buffer_free,1662};16631664static int1665gem_param(int fd, int name)1666{1667int v = -1; /* No param uses (yet) the sign bit, reserve it for errors */16681669struct drm_i915_getparam gp = { .param = name, .value = &v };1670if (intel_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))1671return -1;16721673return v;1674}16751676static bool1677iris_bufmgr_query_meminfo(struct iris_bufmgr *bufmgr)1678{1679struct drm_i915_query_memory_regions *meminfo =1680intel_i915_query_alloc(bufmgr->fd, DRM_I915_QUERY_MEMORY_REGIONS);1681if (meminfo == NULL)1682return false;16831684for (int i = 0; i < meminfo->num_regions; i++) {1685const struct drm_i915_memory_region_info *mem = &meminfo->regions[i];1686switch (mem->region.memory_class) {1687case I915_MEMORY_CLASS_SYSTEM:1688bufmgr->sys.region = mem->region;1689bufmgr->sys.size = mem->probed_size;1690break;1691case I915_MEMORY_CLASS_DEVICE:1692bufmgr->vram.region = mem->region;1693bufmgr->vram.size = mem->probed_size;1694break;1695default:1696break;1697}1698}16991700free(meminfo);17011702return true;1703}17041705/**1706* Initializes the GEM buffer manager, which uses the kernel to allocate, map,1707* and manage map buffer objections.1708*1709* \param fd File descriptor of the opened DRM device.1710*/1711static struct iris_bufmgr *1712iris_bufmgr_create(struct intel_device_info *devinfo, int fd, bool bo_reuse)1713{1714uint64_t gtt_size = iris_gtt_size(fd);1715if (gtt_size <= IRIS_MEMZONE_OTHER_START)1716return NULL;17171718struct iris_bufmgr *bufmgr = calloc(1, sizeof(*bufmgr));1719if (bufmgr == NULL)1720return NULL;17211722/* Handles to buffer objects belong to the device fd and are not1723* reference counted by the kernel. If the same fd is used by1724* multiple parties (threads sharing the same screen bufmgr, or1725* even worse the same device fd passed to multiple libraries)1726* ownership of those handles is shared by those independent parties.1727*1728* Don't do this! Ensure that each library/bufmgr has its own device1729* fd so that its namespace does not clash with another.1730*/1731bufmgr->fd = os_dupfd_cloexec(fd);17321733p_atomic_set(&bufmgr->refcount, 1);17341735simple_mtx_init(&bufmgr->lock, mtx_plain);17361737list_inithead(&bufmgr->zombie_list);17381739bufmgr->has_llc = devinfo->has_llc;1740bufmgr->has_tiling_uapi = devinfo->has_tiling_uapi;1741bufmgr->bo_reuse = bo_reuse;1742bufmgr->has_mmap_offset = gem_param(fd, I915_PARAM_MMAP_GTT_VERSION) >= 4;1743iris_bufmgr_query_meminfo(bufmgr);17441745STATIC_ASSERT(IRIS_MEMZONE_SHADER_START == 0ull);1746const uint64_t _4GB = 1ull << 32;1747const uint64_t _2GB = 1ul << 31;17481749/* The STATE_BASE_ADDRESS size field can only hold 1 page shy of 4GB */1750const uint64_t _4GB_minus_1 = _4GB - PAGE_SIZE;17511752util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_SHADER],1753PAGE_SIZE, _4GB_minus_1 - PAGE_SIZE);1754util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_BINDLESS],1755IRIS_MEMZONE_BINDLESS_START, IRIS_BINDLESS_SIZE);1756util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_SURFACE],1757IRIS_MEMZONE_SURFACE_START,1758_4GB_minus_1 - IRIS_MAX_BINDERS * IRIS_BINDER_SIZE -1759IRIS_BINDLESS_SIZE);1760/* TODO: Why does limiting to 2GB help some state items on gfx12?1761* - CC Viewport Pointer1762* - Blend State Pointer1763* - Color Calc State Pointer1764*/1765const uint64_t dynamic_pool_size =1766(devinfo->ver >= 12 ? _2GB : _4GB_minus_1) - IRIS_BORDER_COLOR_POOL_SIZE;1767util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_DYNAMIC],1768IRIS_MEMZONE_DYNAMIC_START + IRIS_BORDER_COLOR_POOL_SIZE,1769dynamic_pool_size);17701771/* Leave the last 4GB out of the high vma range, so that no state1772* base address + size can overflow 48 bits.1773*/1774util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_OTHER],1775IRIS_MEMZONE_OTHER_START,1776(gtt_size - _4GB) - IRIS_MEMZONE_OTHER_START);17771778init_cache_buckets(bufmgr, false);1779init_cache_buckets(bufmgr, true);17801781bufmgr->name_table =1782_mesa_hash_table_create(NULL, _mesa_hash_uint, _mesa_key_uint_equal);1783bufmgr->handle_table =1784_mesa_hash_table_create(NULL, _mesa_hash_uint, _mesa_key_uint_equal);17851786bufmgr->vma_min_align = devinfo->has_local_mem ? 64 * 1024 : PAGE_SIZE;17871788if (devinfo->has_aux_map) {1789bufmgr->aux_map_ctx = intel_aux_map_init(bufmgr, &aux_map_allocator,1790devinfo);1791assert(bufmgr->aux_map_ctx);1792}17931794return bufmgr;1795}17961797static struct iris_bufmgr *1798iris_bufmgr_ref(struct iris_bufmgr *bufmgr)1799{1800p_atomic_inc(&bufmgr->refcount);1801return bufmgr;1802}18031804void1805iris_bufmgr_unref(struct iris_bufmgr *bufmgr)1806{1807simple_mtx_lock(&global_bufmgr_list_mutex);1808if (p_atomic_dec_zero(&bufmgr->refcount)) {1809list_del(&bufmgr->link);1810iris_bufmgr_destroy(bufmgr);1811}1812simple_mtx_unlock(&global_bufmgr_list_mutex);1813}18141815/**1816* Gets an already existing GEM buffer manager or create a new one.1817*1818* \param fd File descriptor of the opened DRM device.1819*/1820struct iris_bufmgr *1821iris_bufmgr_get_for_fd(struct intel_device_info *devinfo, int fd, bool bo_reuse)1822{1823struct stat st;18241825if (fstat(fd, &st))1826return NULL;18271828struct iris_bufmgr *bufmgr = NULL;18291830simple_mtx_lock(&global_bufmgr_list_mutex);1831list_for_each_entry(struct iris_bufmgr, iter_bufmgr, &global_bufmgr_list, link) {1832struct stat iter_st;1833if (fstat(iter_bufmgr->fd, &iter_st))1834continue;18351836if (st.st_rdev == iter_st.st_rdev) {1837assert(iter_bufmgr->bo_reuse == bo_reuse);1838bufmgr = iris_bufmgr_ref(iter_bufmgr);1839goto unlock;1840}1841}18421843bufmgr = iris_bufmgr_create(devinfo, fd, bo_reuse);1844if (bufmgr)1845list_addtail(&bufmgr->link, &global_bufmgr_list);18461847unlock:1848simple_mtx_unlock(&global_bufmgr_list_mutex);18491850return bufmgr;1851}18521853int1854iris_bufmgr_get_fd(struct iris_bufmgr *bufmgr)1855{1856return bufmgr->fd;1857}18581859void*1860iris_bufmgr_get_aux_map_context(struct iris_bufmgr *bufmgr)1861{1862return bufmgr->aux_map_ctx;1863}186418651866