1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2017 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included 12bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 21bf215546Sopenharmony_ci */ 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci/** 24bf215546Sopenharmony_ci * @file iris_bufmgr.c 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * The Iris buffer manager. 27bf215546Sopenharmony_ci * 28bf215546Sopenharmony_ci * XXX: write better comments 29bf215546Sopenharmony_ci * - BOs 30bf215546Sopenharmony_ci * - Explain BO cache 31bf215546Sopenharmony_ci * - main interface to GEM in the kernel 32bf215546Sopenharmony_ci */ 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include <xf86drm.h> 35bf215546Sopenharmony_ci#include <util/u_atomic.h> 36bf215546Sopenharmony_ci#include <fcntl.h> 37bf215546Sopenharmony_ci#include <stdio.h> 38bf215546Sopenharmony_ci#include <stdlib.h> 39bf215546Sopenharmony_ci#include <string.h> 40bf215546Sopenharmony_ci#include <unistd.h> 41bf215546Sopenharmony_ci#include <assert.h> 42bf215546Sopenharmony_ci#include <sys/ioctl.h> 43bf215546Sopenharmony_ci#include <sys/mman.h> 44bf215546Sopenharmony_ci#include <sys/stat.h> 45bf215546Sopenharmony_ci#include <sys/types.h> 46bf215546Sopenharmony_ci#include <stdbool.h> 47bf215546Sopenharmony_ci#include <time.h> 48bf215546Sopenharmony_ci#include <unistd.h> 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci#include "errno.h" 51bf215546Sopenharmony_ci#include "common/intel_aux_map.h" 52bf215546Sopenharmony_ci#include "common/intel_clflush.h" 53bf215546Sopenharmony_ci#include "dev/intel_debug.h" 54bf215546Sopenharmony_ci#include "common/intel_gem.h" 55bf215546Sopenharmony_ci#include "dev/intel_device_info.h" 56bf215546Sopenharmony_ci#include "isl/isl.h" 57bf215546Sopenharmony_ci#include "os/os_mman.h" 58bf215546Sopenharmony_ci#include "util/debug.h" 59bf215546Sopenharmony_ci#include "util/macros.h" 60bf215546Sopenharmony_ci#include "util/hash_table.h" 61bf215546Sopenharmony_ci#include "util/list.h" 62bf215546Sopenharmony_ci#include "util/os_file.h" 63bf215546Sopenharmony_ci#include "util/u_dynarray.h" 64bf215546Sopenharmony_ci#include "util/vma.h" 65bf215546Sopenharmony_ci#include "iris_bufmgr.h" 66bf215546Sopenharmony_ci#include "iris_context.h" 67bf215546Sopenharmony_ci#include "string.h" 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci#include "drm-uapi/i915_drm.h" 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci#ifdef HAVE_VALGRIND 72bf215546Sopenharmony_ci#include <valgrind.h> 73bf215546Sopenharmony_ci#include <memcheck.h> 74bf215546Sopenharmony_ci#define VG(x) x 75bf215546Sopenharmony_ci#else 76bf215546Sopenharmony_ci#define VG(x) 77bf215546Sopenharmony_ci#endif 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci/* VALGRIND_FREELIKE_BLOCK unfortunately does not actually undo the earlier 80bf215546Sopenharmony_ci * VALGRIND_MALLOCLIKE_BLOCK but instead leaves vg convinced the memory is 81bf215546Sopenharmony_ci * leaked. All because it does not call VG(cli_free) from its 82bf215546Sopenharmony_ci * VG_USERREQ__FREELIKE_BLOCK handler. Instead of treating the memory like 83bf215546Sopenharmony_ci * and allocation, we mark it available for use upon mmapping and remove 84bf215546Sopenharmony_ci * it upon unmapping. 85bf215546Sopenharmony_ci */ 86bf215546Sopenharmony_ci#define VG_DEFINED(ptr, size) VG(VALGRIND_MAKE_MEM_DEFINED(ptr, size)) 87bf215546Sopenharmony_ci#define VG_NOACCESS(ptr, size) VG(VALGRIND_MAKE_MEM_NOACCESS(ptr, size)) 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci/* On FreeBSD PAGE_SIZE is already defined in 90bf215546Sopenharmony_ci * /usr/include/machine/param.h that is indirectly 91bf215546Sopenharmony_ci * included here. 92bf215546Sopenharmony_ci */ 93bf215546Sopenharmony_ci#ifndef PAGE_SIZE 94bf215546Sopenharmony_ci#define PAGE_SIZE 4096 95bf215546Sopenharmony_ci#endif 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci#define WARN_ONCE(cond, fmt...) do { \ 98bf215546Sopenharmony_ci if (unlikely(cond)) { \ 99bf215546Sopenharmony_ci static bool _warned = false; \ 100bf215546Sopenharmony_ci if (!_warned) { \ 101bf215546Sopenharmony_ci fprintf(stderr, "WARNING: "); \ 102bf215546Sopenharmony_ci fprintf(stderr, fmt); \ 103bf215546Sopenharmony_ci _warned = true; \ 104bf215546Sopenharmony_ci } \ 105bf215546Sopenharmony_ci } \ 106bf215546Sopenharmony_ci} while (0) 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci#define FILE_DEBUG_FLAG DEBUG_BUFMGR 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci/** 111bf215546Sopenharmony_ci * For debugging purposes, this returns a time in seconds. 112bf215546Sopenharmony_ci */ 113bf215546Sopenharmony_cistatic double 114bf215546Sopenharmony_ciget_time(void) 115bf215546Sopenharmony_ci{ 116bf215546Sopenharmony_ci struct timespec tp; 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &tp); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci return tp.tv_sec + tp.tv_nsec / 1000000000.0; 121bf215546Sopenharmony_ci} 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_cistatic inline int 124bf215546Sopenharmony_ciatomic_add_unless(int *v, int add, int unless) 125bf215546Sopenharmony_ci{ 126bf215546Sopenharmony_ci int c, old; 127bf215546Sopenharmony_ci c = p_atomic_read(v); 128bf215546Sopenharmony_ci while (c != unless && (old = p_atomic_cmpxchg(v, c, c + add)) != c) 129bf215546Sopenharmony_ci c = old; 130bf215546Sopenharmony_ci return c == unless; 131bf215546Sopenharmony_ci} 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_cistatic const char * 134bf215546Sopenharmony_cimemzone_name(enum iris_memory_zone memzone) 135bf215546Sopenharmony_ci{ 136bf215546Sopenharmony_ci const char *names[] = { 137bf215546Sopenharmony_ci [IRIS_MEMZONE_SHADER] = "shader", 138bf215546Sopenharmony_ci [IRIS_MEMZONE_BINDER] = "binder", 139bf215546Sopenharmony_ci [IRIS_MEMZONE_BINDLESS] = "scratchsurf", 140bf215546Sopenharmony_ci [IRIS_MEMZONE_SURFACE] = "surface", 141bf215546Sopenharmony_ci [IRIS_MEMZONE_DYNAMIC] = "dynamic", 142bf215546Sopenharmony_ci [IRIS_MEMZONE_OTHER] = "other", 143bf215546Sopenharmony_ci [IRIS_MEMZONE_BORDER_COLOR_POOL] = "bordercolor", 144bf215546Sopenharmony_ci }; 145bf215546Sopenharmony_ci assert(memzone < ARRAY_SIZE(names)); 146bf215546Sopenharmony_ci return names[memzone]; 147bf215546Sopenharmony_ci} 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_cistruct bo_cache_bucket { 150bf215546Sopenharmony_ci /** List of cached BOs. */ 151bf215546Sopenharmony_ci struct list_head head; 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci /** Size of this bucket, in bytes. */ 154bf215546Sopenharmony_ci uint64_t size; 155bf215546Sopenharmony_ci}; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_cistruct bo_export { 158bf215546Sopenharmony_ci /** File descriptor associated with a handle export. */ 159bf215546Sopenharmony_ci int drm_fd; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci /** GEM handle in drm_fd */ 162bf215546Sopenharmony_ci uint32_t gem_handle; 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci struct list_head link; 165bf215546Sopenharmony_ci}; 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_cistruct iris_memregion { 168bf215546Sopenharmony_ci struct drm_i915_gem_memory_class_instance region; 169bf215546Sopenharmony_ci uint64_t size; 170bf215546Sopenharmony_ci}; 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci#define NUM_SLAB_ALLOCATORS 3 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_cistruct iris_slab { 175bf215546Sopenharmony_ci struct pb_slab base; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci unsigned entry_size; 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci /** The BO representing the entire slab */ 180bf215546Sopenharmony_ci struct iris_bo *bo; 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci /** Array of iris_bo structs representing BOs allocated out of this slab */ 183bf215546Sopenharmony_ci struct iris_bo *entries; 184bf215546Sopenharmony_ci}; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci#define BUCKET_ARRAY_SIZE (14 * 4) 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_cistruct iris_bufmgr { 189bf215546Sopenharmony_ci /** 190bf215546Sopenharmony_ci * List into the list of bufmgr. 191bf215546Sopenharmony_ci */ 192bf215546Sopenharmony_ci struct list_head link; 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci uint32_t refcount; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci int fd; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci simple_mtx_t lock; 199bf215546Sopenharmony_ci simple_mtx_t bo_deps_lock; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci /** Array of lists of cached gem objects of power-of-two sizes */ 202bf215546Sopenharmony_ci struct bo_cache_bucket cache_bucket[BUCKET_ARRAY_SIZE]; 203bf215546Sopenharmony_ci int num_buckets; 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci /** Same as cache_bucket, but for local memory gem objects */ 206bf215546Sopenharmony_ci struct bo_cache_bucket local_cache_bucket[BUCKET_ARRAY_SIZE]; 207bf215546Sopenharmony_ci int num_local_buckets; 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci /** Same as cache_bucket, but for local-preferred memory gem objects */ 210bf215546Sopenharmony_ci struct bo_cache_bucket local_preferred_cache_bucket[BUCKET_ARRAY_SIZE]; 211bf215546Sopenharmony_ci int num_local_preferred_buckets; 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci time_t time; 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci struct hash_table *name_table; 216bf215546Sopenharmony_ci struct hash_table *handle_table; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci /** 219bf215546Sopenharmony_ci * List of BOs which we've effectively freed, but are hanging on to 220bf215546Sopenharmony_ci * until they're idle before closing and returning the VMA. 221bf215546Sopenharmony_ci */ 222bf215546Sopenharmony_ci struct list_head zombie_list; 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci struct util_vma_heap vma_allocator[IRIS_MEMZONE_COUNT]; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci uint64_t vma_min_align; 227bf215546Sopenharmony_ci struct iris_memregion vram, sys; 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci /* Used only when use_global_vm is true. */ 230bf215546Sopenharmony_ci uint32_t global_vm_id; 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci int next_screen_id; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci bool has_llc:1; 235bf215546Sopenharmony_ci bool has_local_mem:1; 236bf215546Sopenharmony_ci bool has_mmap_offset:1; 237bf215546Sopenharmony_ci bool has_tiling_uapi:1; 238bf215546Sopenharmony_ci bool has_userptr_probe:1; 239bf215546Sopenharmony_ci bool bo_reuse:1; 240bf215546Sopenharmony_ci bool use_global_vm:1; 241bf215546Sopenharmony_ci bool all_vram_mappable:1; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci struct intel_aux_map_context *aux_map_ctx; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci struct pb_slabs bo_slabs[NUM_SLAB_ALLOCATORS]; 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci struct iris_border_color_pool border_color_pool; 248bf215546Sopenharmony_ci}; 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_cistatic simple_mtx_t global_bufmgr_list_mutex = _SIMPLE_MTX_INITIALIZER_NP; 251bf215546Sopenharmony_cistatic struct list_head global_bufmgr_list = { 252bf215546Sopenharmony_ci .next = &global_bufmgr_list, 253bf215546Sopenharmony_ci .prev = &global_bufmgr_list, 254bf215546Sopenharmony_ci}; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_cistatic void bo_free(struct iris_bo *bo); 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_cistatic struct iris_bo * 259bf215546Sopenharmony_cifind_and_ref_external_bo(struct hash_table *ht, unsigned int key) 260bf215546Sopenharmony_ci{ 261bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search(ht, &key); 262bf215546Sopenharmony_ci struct iris_bo *bo = entry ? entry->data : NULL; 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci if (bo) { 265bf215546Sopenharmony_ci assert(iris_bo_is_external(bo)); 266bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 267bf215546Sopenharmony_ci assert(!bo->real.reusable); 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci /* Being non-reusable, the BO cannot be in the cache lists, but it 270bf215546Sopenharmony_ci * may be in the zombie list if it had reached zero references, but 271bf215546Sopenharmony_ci * we hadn't yet closed it...and then reimported the same BO. If it 272bf215546Sopenharmony_ci * is, then remove it since it's now been resurrected. 273bf215546Sopenharmony_ci */ 274bf215546Sopenharmony_ci if (list_is_linked(&bo->head)) 275bf215546Sopenharmony_ci list_del(&bo->head); 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci iris_bo_reference(bo); 278bf215546Sopenharmony_ci } 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci return bo; 281bf215546Sopenharmony_ci} 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_cistatic void 284bf215546Sopenharmony_cibucket_info_for_heap(struct iris_bufmgr *bufmgr, enum iris_heap heap, 285bf215546Sopenharmony_ci struct bo_cache_bucket **cache_bucket, int **num_buckets) 286bf215546Sopenharmony_ci{ 287bf215546Sopenharmony_ci switch (heap) { 288bf215546Sopenharmony_ci case IRIS_HEAP_SYSTEM_MEMORY: 289bf215546Sopenharmony_ci *cache_bucket = bufmgr->cache_bucket; 290bf215546Sopenharmony_ci *num_buckets = &bufmgr->num_buckets; 291bf215546Sopenharmony_ci break; 292bf215546Sopenharmony_ci case IRIS_HEAP_DEVICE_LOCAL: 293bf215546Sopenharmony_ci *cache_bucket = bufmgr->local_cache_bucket; 294bf215546Sopenharmony_ci *num_buckets = &bufmgr->num_local_buckets; 295bf215546Sopenharmony_ci break; 296bf215546Sopenharmony_ci case IRIS_HEAP_DEVICE_LOCAL_PREFERRED: 297bf215546Sopenharmony_ci *cache_bucket = bufmgr->local_preferred_cache_bucket; 298bf215546Sopenharmony_ci *num_buckets = &bufmgr->num_local_preferred_buckets; 299bf215546Sopenharmony_ci break; 300bf215546Sopenharmony_ci case IRIS_HEAP_MAX: 301bf215546Sopenharmony_ci default: 302bf215546Sopenharmony_ci *cache_bucket = NULL; 303bf215546Sopenharmony_ci *num_buckets = NULL; 304bf215546Sopenharmony_ci unreachable("invalid heap"); 305bf215546Sopenharmony_ci } 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci assert(**num_buckets < BUCKET_ARRAY_SIZE); 308bf215546Sopenharmony_ci} 309bf215546Sopenharmony_ci/** 310bf215546Sopenharmony_ci * This function finds the correct bucket fit for the input size. 311bf215546Sopenharmony_ci * The function works with O(1) complexity when the requested size 312bf215546Sopenharmony_ci * was queried instead of iterating the size through all the buckets. 313bf215546Sopenharmony_ci */ 314bf215546Sopenharmony_cistatic struct bo_cache_bucket * 315bf215546Sopenharmony_cibucket_for_size(struct iris_bufmgr *bufmgr, uint64_t size, 316bf215546Sopenharmony_ci enum iris_heap heap) 317bf215546Sopenharmony_ci{ 318bf215546Sopenharmony_ci /* Calculating the pages and rounding up to the page size. */ 319bf215546Sopenharmony_ci const unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci /* Row Bucket sizes clz((x-1) | 3) Row Column 322bf215546Sopenharmony_ci * in pages stride size 323bf215546Sopenharmony_ci * 0: 1 2 3 4 -> 30 30 30 30 4 1 324bf215546Sopenharmony_ci * 1: 5 6 7 8 -> 29 29 29 29 4 1 325bf215546Sopenharmony_ci * 2: 10 12 14 16 -> 28 28 28 28 8 2 326bf215546Sopenharmony_ci * 3: 20 24 28 32 -> 27 27 27 27 16 4 327bf215546Sopenharmony_ci */ 328bf215546Sopenharmony_ci const unsigned row = 30 - __builtin_clz((pages - 1) | 3); 329bf215546Sopenharmony_ci const unsigned row_max_pages = 4 << row; 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci /* The '& ~2' is the special case for row 1. In row 1, max pages / 332bf215546Sopenharmony_ci * 2 is 2, but the previous row maximum is zero (because there is 333bf215546Sopenharmony_ci * no previous row). All row maximum sizes are power of 2, so that 334bf215546Sopenharmony_ci * is the only case where that bit will be set. 335bf215546Sopenharmony_ci */ 336bf215546Sopenharmony_ci const unsigned prev_row_max_pages = (row_max_pages / 2) & ~2; 337bf215546Sopenharmony_ci int col_size_log2 = row - 1; 338bf215546Sopenharmony_ci col_size_log2 += (col_size_log2 < 0); 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci const unsigned col = (pages - prev_row_max_pages + 341bf215546Sopenharmony_ci ((1 << col_size_log2) - 1)) >> col_size_log2; 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci /* Calculating the index based on the row and column. */ 344bf215546Sopenharmony_ci const unsigned index = (row * 4) + (col - 1); 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci int *num_buckets; 347bf215546Sopenharmony_ci struct bo_cache_bucket *buckets; 348bf215546Sopenharmony_ci bucket_info_for_heap(bufmgr, heap, &buckets, &num_buckets); 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci return (index < *num_buckets) ? &buckets[index] : NULL; 351bf215546Sopenharmony_ci} 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_cienum iris_memory_zone 354bf215546Sopenharmony_ciiris_memzone_for_address(uint64_t address) 355bf215546Sopenharmony_ci{ 356bf215546Sopenharmony_ci STATIC_ASSERT(IRIS_MEMZONE_OTHER_START > IRIS_MEMZONE_DYNAMIC_START); 357bf215546Sopenharmony_ci STATIC_ASSERT(IRIS_MEMZONE_DYNAMIC_START > IRIS_MEMZONE_SURFACE_START); 358bf215546Sopenharmony_ci STATIC_ASSERT(IRIS_MEMZONE_SURFACE_START > IRIS_MEMZONE_BINDLESS_START); 359bf215546Sopenharmony_ci STATIC_ASSERT(IRIS_MEMZONE_BINDLESS_START > IRIS_MEMZONE_BINDER_START); 360bf215546Sopenharmony_ci STATIC_ASSERT(IRIS_MEMZONE_BINDER_START > IRIS_MEMZONE_SHADER_START); 361bf215546Sopenharmony_ci STATIC_ASSERT(IRIS_BORDER_COLOR_POOL_ADDRESS == IRIS_MEMZONE_DYNAMIC_START); 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci if (address >= IRIS_MEMZONE_OTHER_START) 364bf215546Sopenharmony_ci return IRIS_MEMZONE_OTHER; 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci if (address == IRIS_BORDER_COLOR_POOL_ADDRESS) 367bf215546Sopenharmony_ci return IRIS_MEMZONE_BORDER_COLOR_POOL; 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci if (address > IRIS_MEMZONE_DYNAMIC_START) 370bf215546Sopenharmony_ci return IRIS_MEMZONE_DYNAMIC; 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci if (address >= IRIS_MEMZONE_SURFACE_START) 373bf215546Sopenharmony_ci return IRIS_MEMZONE_SURFACE; 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci if (address >= IRIS_MEMZONE_BINDLESS_START) 376bf215546Sopenharmony_ci return IRIS_MEMZONE_BINDLESS; 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci if (address >= IRIS_MEMZONE_BINDER_START) 379bf215546Sopenharmony_ci return IRIS_MEMZONE_BINDER; 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_ci return IRIS_MEMZONE_SHADER; 382bf215546Sopenharmony_ci} 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci/** 385bf215546Sopenharmony_ci * Allocate a section of virtual memory for a buffer, assigning an address. 386bf215546Sopenharmony_ci * 387bf215546Sopenharmony_ci * This uses either the bucket allocator for the given size, or the large 388bf215546Sopenharmony_ci * object allocator (util_vma). 389bf215546Sopenharmony_ci */ 390bf215546Sopenharmony_cistatic uint64_t 391bf215546Sopenharmony_civma_alloc(struct iris_bufmgr *bufmgr, 392bf215546Sopenharmony_ci enum iris_memory_zone memzone, 393bf215546Sopenharmony_ci uint64_t size, 394bf215546Sopenharmony_ci uint64_t alignment) 395bf215546Sopenharmony_ci{ 396bf215546Sopenharmony_ci simple_mtx_assert_locked(&bufmgr->lock); 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci /* Force minimum alignment based on device requirements */ 399bf215546Sopenharmony_ci assert((alignment & (alignment - 1)) == 0); 400bf215546Sopenharmony_ci alignment = MAX2(alignment, bufmgr->vma_min_align); 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci if (memzone == IRIS_MEMZONE_BORDER_COLOR_POOL) 403bf215546Sopenharmony_ci return IRIS_BORDER_COLOR_POOL_ADDRESS; 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci uint64_t addr = 406bf215546Sopenharmony_ci util_vma_heap_alloc(&bufmgr->vma_allocator[memzone], size, alignment); 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci assert((addr >> 48ull) == 0); 409bf215546Sopenharmony_ci assert((addr % alignment) == 0); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci return intel_canonical_address(addr); 412bf215546Sopenharmony_ci} 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_cistatic void 415bf215546Sopenharmony_civma_free(struct iris_bufmgr *bufmgr, 416bf215546Sopenharmony_ci uint64_t address, 417bf215546Sopenharmony_ci uint64_t size) 418bf215546Sopenharmony_ci{ 419bf215546Sopenharmony_ci simple_mtx_assert_locked(&bufmgr->lock); 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci if (address == IRIS_BORDER_COLOR_POOL_ADDRESS) 422bf215546Sopenharmony_ci return; 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci /* Un-canonicalize the address. */ 425bf215546Sopenharmony_ci address = intel_48b_address(address); 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci if (address == 0ull) 428bf215546Sopenharmony_ci return; 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci enum iris_memory_zone memzone = iris_memzone_for_address(address); 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci assert(memzone < ARRAY_SIZE(bufmgr->vma_allocator)); 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci util_vma_heap_free(&bufmgr->vma_allocator[memzone], address, size); 435bf215546Sopenharmony_ci} 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_cistatic bool 438bf215546Sopenharmony_ciiris_bo_busy_gem(struct iris_bo *bo) 439bf215546Sopenharmony_ci{ 440bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 443bf215546Sopenharmony_ci struct drm_i915_gem_busy busy = { .handle = bo->gem_handle }; 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); 446bf215546Sopenharmony_ci if (ret == 0) { 447bf215546Sopenharmony_ci return busy.busy; 448bf215546Sopenharmony_ci } 449bf215546Sopenharmony_ci return false; 450bf215546Sopenharmony_ci} 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci/* A timeout of 0 just checks for busyness. */ 453bf215546Sopenharmony_cistatic int 454bf215546Sopenharmony_ciiris_bo_wait_syncobj(struct iris_bo *bo, int64_t timeout_ns) 455bf215546Sopenharmony_ci{ 456bf215546Sopenharmony_ci int ret = 0; 457bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci /* If we know it's idle, don't bother with the kernel round trip */ 460bf215546Sopenharmony_ci if (bo->idle) 461bf215546Sopenharmony_ci return 0; 462bf215546Sopenharmony_ci 463bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->bo_deps_lock); 464bf215546Sopenharmony_ci 465bf215546Sopenharmony_ci uint32_t handles[bo->deps_size * IRIS_BATCH_COUNT * 2]; 466bf215546Sopenharmony_ci int handle_count = 0; 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci for (int d = 0; d < bo->deps_size; d++) { 469bf215546Sopenharmony_ci for (int b = 0; b < IRIS_BATCH_COUNT; b++) { 470bf215546Sopenharmony_ci struct iris_syncobj *r = bo->deps[d].read_syncobjs[b]; 471bf215546Sopenharmony_ci struct iris_syncobj *w = bo->deps[d].write_syncobjs[b]; 472bf215546Sopenharmony_ci if (r) 473bf215546Sopenharmony_ci handles[handle_count++] = r->handle; 474bf215546Sopenharmony_ci if (w) 475bf215546Sopenharmony_ci handles[handle_count++] = w->handle; 476bf215546Sopenharmony_ci } 477bf215546Sopenharmony_ci } 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_ci if (handle_count == 0) 480bf215546Sopenharmony_ci goto out; 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci /* Unlike the gem wait, negative values are not infinite here. */ 483bf215546Sopenharmony_ci int64_t timeout_abs = os_time_get_absolute_timeout(timeout_ns); 484bf215546Sopenharmony_ci if (timeout_abs < 0) 485bf215546Sopenharmony_ci timeout_abs = INT64_MAX; 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci struct drm_syncobj_wait args = { 488bf215546Sopenharmony_ci .handles = (uintptr_t) handles, 489bf215546Sopenharmony_ci .timeout_nsec = timeout_abs, 490bf215546Sopenharmony_ci .count_handles = handle_count, 491bf215546Sopenharmony_ci .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, 492bf215546Sopenharmony_ci }; 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_ci ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 495bf215546Sopenharmony_ci if (ret != 0) { 496bf215546Sopenharmony_ci ret = -errno; 497bf215546Sopenharmony_ci goto out; 498bf215546Sopenharmony_ci } 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci /* We just waited everything, so clean all the deps. */ 501bf215546Sopenharmony_ci for (int d = 0; d < bo->deps_size; d++) { 502bf215546Sopenharmony_ci for (int b = 0; b < IRIS_BATCH_COUNT; b++) { 503bf215546Sopenharmony_ci iris_syncobj_reference(bufmgr, &bo->deps[d].write_syncobjs[b], NULL); 504bf215546Sopenharmony_ci iris_syncobj_reference(bufmgr, &bo->deps[d].read_syncobjs[b], NULL); 505bf215546Sopenharmony_ci } 506bf215546Sopenharmony_ci } 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ciout: 509bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->bo_deps_lock); 510bf215546Sopenharmony_ci return ret; 511bf215546Sopenharmony_ci} 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_cistatic bool 514bf215546Sopenharmony_ciiris_bo_busy_syncobj(struct iris_bo *bo) 515bf215546Sopenharmony_ci{ 516bf215546Sopenharmony_ci return iris_bo_wait_syncobj(bo, 0) == -ETIME; 517bf215546Sopenharmony_ci} 518bf215546Sopenharmony_ci 519bf215546Sopenharmony_cibool 520bf215546Sopenharmony_ciiris_bo_busy(struct iris_bo *bo) 521bf215546Sopenharmony_ci{ 522bf215546Sopenharmony_ci bool busy; 523bf215546Sopenharmony_ci if (iris_bo_is_external(bo)) 524bf215546Sopenharmony_ci busy = iris_bo_busy_gem(bo); 525bf215546Sopenharmony_ci else 526bf215546Sopenharmony_ci busy = iris_bo_busy_syncobj(bo); 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_ci bo->idle = !busy; 529bf215546Sopenharmony_ci 530bf215546Sopenharmony_ci return busy; 531bf215546Sopenharmony_ci} 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ciint 534bf215546Sopenharmony_ciiris_bo_madvise(struct iris_bo *bo, int state) 535bf215546Sopenharmony_ci{ 536bf215546Sopenharmony_ci /* We can't madvise suballocated BOs. */ 537bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 538bf215546Sopenharmony_ci 539bf215546Sopenharmony_ci struct drm_i915_gem_madvise madv = { 540bf215546Sopenharmony_ci .handle = bo->gem_handle, 541bf215546Sopenharmony_ci .madv = state, 542bf215546Sopenharmony_ci .retained = 1, 543bf215546Sopenharmony_ci }; 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_ci intel_ioctl(bo->bufmgr->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv); 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci return madv.retained; 548bf215546Sopenharmony_ci} 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_cistatic struct iris_bo * 551bf215546Sopenharmony_cibo_calloc(void) 552bf215546Sopenharmony_ci{ 553bf215546Sopenharmony_ci struct iris_bo *bo = calloc(1, sizeof(*bo)); 554bf215546Sopenharmony_ci if (!bo) 555bf215546Sopenharmony_ci return NULL; 556bf215546Sopenharmony_ci 557bf215546Sopenharmony_ci list_inithead(&bo->real.exports); 558bf215546Sopenharmony_ci 559bf215546Sopenharmony_ci bo->hash = _mesa_hash_pointer(bo); 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci return bo; 562bf215546Sopenharmony_ci} 563bf215546Sopenharmony_ci 564bf215546Sopenharmony_cistatic void 565bf215546Sopenharmony_cibo_unmap(struct iris_bo *bo) 566bf215546Sopenharmony_ci{ 567bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 568bf215546Sopenharmony_ci 569bf215546Sopenharmony_ci VG_NOACCESS(bo->real.map, bo->size); 570bf215546Sopenharmony_ci os_munmap(bo->real.map, bo->size); 571bf215546Sopenharmony_ci bo->real.map = NULL; 572bf215546Sopenharmony_ci} 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_cistatic struct pb_slabs * 575bf215546Sopenharmony_ciget_slabs(struct iris_bufmgr *bufmgr, uint64_t size) 576bf215546Sopenharmony_ci{ 577bf215546Sopenharmony_ci for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 578bf215546Sopenharmony_ci struct pb_slabs *slabs = &bufmgr->bo_slabs[i]; 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci if (size <= 1ull << (slabs->min_order + slabs->num_orders - 1)) 581bf215546Sopenharmony_ci return slabs; 582bf215546Sopenharmony_ci } 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci unreachable("should have found a valid slab for this size"); 585bf215546Sopenharmony_ci} 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_ci/* Return the power of two size of a slab entry matching the input size. */ 588bf215546Sopenharmony_cistatic unsigned 589bf215546Sopenharmony_ciget_slab_pot_entry_size(struct iris_bufmgr *bufmgr, unsigned size) 590bf215546Sopenharmony_ci{ 591bf215546Sopenharmony_ci unsigned entry_size = util_next_power_of_two(size); 592bf215546Sopenharmony_ci unsigned min_entry_size = 1 << bufmgr->bo_slabs[0].min_order; 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci return MAX2(entry_size, min_entry_size); 595bf215546Sopenharmony_ci} 596bf215546Sopenharmony_ci 597bf215546Sopenharmony_ci/* Return the slab entry alignment. */ 598bf215546Sopenharmony_cistatic unsigned 599bf215546Sopenharmony_ciget_slab_entry_alignment(struct iris_bufmgr *bufmgr, unsigned size) 600bf215546Sopenharmony_ci{ 601bf215546Sopenharmony_ci unsigned entry_size = get_slab_pot_entry_size(bufmgr, size); 602bf215546Sopenharmony_ci 603bf215546Sopenharmony_ci if (size <= entry_size * 3 / 4) 604bf215546Sopenharmony_ci return entry_size / 4; 605bf215546Sopenharmony_ci 606bf215546Sopenharmony_ci return entry_size; 607bf215546Sopenharmony_ci} 608bf215546Sopenharmony_ci 609bf215546Sopenharmony_cistatic bool 610bf215546Sopenharmony_ciiris_can_reclaim_slab(void *priv, struct pb_slab_entry *entry) 611bf215546Sopenharmony_ci{ 612bf215546Sopenharmony_ci struct iris_bo *bo = container_of(entry, struct iris_bo, slab.entry); 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci return !iris_bo_busy(bo); 615bf215546Sopenharmony_ci} 616bf215546Sopenharmony_ci 617bf215546Sopenharmony_cistatic void 618bf215546Sopenharmony_ciiris_slab_free(void *priv, struct pb_slab *pslab) 619bf215546Sopenharmony_ci{ 620bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = priv; 621bf215546Sopenharmony_ci struct iris_slab *slab = (void *) pslab; 622bf215546Sopenharmony_ci struct intel_aux_map_context *aux_map_ctx = bufmgr->aux_map_ctx; 623bf215546Sopenharmony_ci 624bf215546Sopenharmony_ci assert(!slab->bo->aux_map_address); 625bf215546Sopenharmony_ci 626bf215546Sopenharmony_ci /* Since we're freeing the whole slab, all buffers allocated out of it 627bf215546Sopenharmony_ci * must be reclaimable. We require buffers to be idle to be reclaimed 628bf215546Sopenharmony_ci * (see iris_can_reclaim_slab()), so we know all entries must be idle. 629bf215546Sopenharmony_ci * Therefore, we can safely unmap their aux table entries. 630bf215546Sopenharmony_ci */ 631bf215546Sopenharmony_ci for (unsigned i = 0; i < pslab->num_entries; i++) { 632bf215546Sopenharmony_ci struct iris_bo *bo = &slab->entries[i]; 633bf215546Sopenharmony_ci if (aux_map_ctx && bo->aux_map_address) { 634bf215546Sopenharmony_ci intel_aux_map_unmap_range(aux_map_ctx, bo->address, bo->size); 635bf215546Sopenharmony_ci bo->aux_map_address = 0; 636bf215546Sopenharmony_ci } 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ci /* Unref read/write dependency syncobjs and free the array. */ 639bf215546Sopenharmony_ci for (int d = 0; d < bo->deps_size; d++) { 640bf215546Sopenharmony_ci for (int b = 0; b < IRIS_BATCH_COUNT; b++) { 641bf215546Sopenharmony_ci iris_syncobj_reference(bufmgr, &bo->deps[d].write_syncobjs[b], NULL); 642bf215546Sopenharmony_ci iris_syncobj_reference(bufmgr, &bo->deps[d].read_syncobjs[b], NULL); 643bf215546Sopenharmony_ci } 644bf215546Sopenharmony_ci } 645bf215546Sopenharmony_ci free(bo->deps); 646bf215546Sopenharmony_ci } 647bf215546Sopenharmony_ci 648bf215546Sopenharmony_ci iris_bo_unreference(slab->bo); 649bf215546Sopenharmony_ci 650bf215546Sopenharmony_ci free(slab->entries); 651bf215546Sopenharmony_ci free(slab); 652bf215546Sopenharmony_ci} 653bf215546Sopenharmony_ci 654bf215546Sopenharmony_cistatic struct pb_slab * 655bf215546Sopenharmony_ciiris_slab_alloc(void *priv, 656bf215546Sopenharmony_ci unsigned heap, 657bf215546Sopenharmony_ci unsigned entry_size, 658bf215546Sopenharmony_ci unsigned group_index) 659bf215546Sopenharmony_ci{ 660bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = priv; 661bf215546Sopenharmony_ci struct iris_slab *slab = calloc(1, sizeof(struct iris_slab)); 662bf215546Sopenharmony_ci unsigned flags = heap == IRIS_HEAP_SYSTEM_MEMORY ? BO_ALLOC_SMEM : 663bf215546Sopenharmony_ci heap == IRIS_HEAP_DEVICE_LOCAL ? BO_ALLOC_LMEM : 0; 664bf215546Sopenharmony_ci unsigned slab_size = 0; 665bf215546Sopenharmony_ci /* We only support slab allocation for IRIS_MEMZONE_OTHER */ 666bf215546Sopenharmony_ci enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER; 667bf215546Sopenharmony_ci 668bf215546Sopenharmony_ci if (!slab) 669bf215546Sopenharmony_ci return NULL; 670bf215546Sopenharmony_ci 671bf215546Sopenharmony_ci struct pb_slabs *slabs = bufmgr->bo_slabs; 672bf215546Sopenharmony_ci 673bf215546Sopenharmony_ci /* Determine the slab buffer size. */ 674bf215546Sopenharmony_ci for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 675bf215546Sopenharmony_ci unsigned max_entry_size = 676bf215546Sopenharmony_ci 1 << (slabs[i].min_order + slabs[i].num_orders - 1); 677bf215546Sopenharmony_ci 678bf215546Sopenharmony_ci if (entry_size <= max_entry_size) { 679bf215546Sopenharmony_ci /* The slab size is twice the size of the largest possible entry. */ 680bf215546Sopenharmony_ci slab_size = max_entry_size * 2; 681bf215546Sopenharmony_ci 682bf215546Sopenharmony_ci if (!util_is_power_of_two_nonzero(entry_size)) { 683bf215546Sopenharmony_ci assert(util_is_power_of_two_nonzero(entry_size * 4 / 3)); 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ci /* If the entry size is 3/4 of a power of two, we would waste 686bf215546Sopenharmony_ci * space and not gain anything if we allocated only twice the 687bf215546Sopenharmony_ci * power of two for the backing buffer: 688bf215546Sopenharmony_ci * 689bf215546Sopenharmony_ci * 2 * 3/4 = 1.5 usable with buffer size 2 690bf215546Sopenharmony_ci * 691bf215546Sopenharmony_ci * Allocating 5 times the entry size leads us to the next power 692bf215546Sopenharmony_ci * of two and results in a much better memory utilization: 693bf215546Sopenharmony_ci * 694bf215546Sopenharmony_ci * 5 * 3/4 = 3.75 usable with buffer size 4 695bf215546Sopenharmony_ci */ 696bf215546Sopenharmony_ci if (entry_size * 5 > slab_size) 697bf215546Sopenharmony_ci slab_size = util_next_power_of_two(entry_size * 5); 698bf215546Sopenharmony_ci } 699bf215546Sopenharmony_ci 700bf215546Sopenharmony_ci /* The largest slab should have the same size as the PTE fragment 701bf215546Sopenharmony_ci * size to get faster address translation. 702bf215546Sopenharmony_ci * 703bf215546Sopenharmony_ci * TODO: move this to intel_device_info? 704bf215546Sopenharmony_ci */ 705bf215546Sopenharmony_ci const unsigned pte_size = 2 * 1024 * 1024; 706bf215546Sopenharmony_ci 707bf215546Sopenharmony_ci if (i == NUM_SLAB_ALLOCATORS - 1 && slab_size < pte_size) 708bf215546Sopenharmony_ci slab_size = pte_size; 709bf215546Sopenharmony_ci 710bf215546Sopenharmony_ci break; 711bf215546Sopenharmony_ci } 712bf215546Sopenharmony_ci } 713bf215546Sopenharmony_ci assert(slab_size != 0); 714bf215546Sopenharmony_ci 715bf215546Sopenharmony_ci slab->bo = 716bf215546Sopenharmony_ci iris_bo_alloc(bufmgr, "slab", slab_size, slab_size, memzone, flags); 717bf215546Sopenharmony_ci if (!slab->bo) 718bf215546Sopenharmony_ci goto fail; 719bf215546Sopenharmony_ci 720bf215546Sopenharmony_ci slab_size = slab->bo->size; 721bf215546Sopenharmony_ci 722bf215546Sopenharmony_ci slab->base.num_entries = slab_size / entry_size; 723bf215546Sopenharmony_ci slab->base.num_free = slab->base.num_entries; 724bf215546Sopenharmony_ci slab->entry_size = entry_size; 725bf215546Sopenharmony_ci slab->entries = calloc(slab->base.num_entries, sizeof(*slab->entries)); 726bf215546Sopenharmony_ci if (!slab->entries) 727bf215546Sopenharmony_ci goto fail_bo; 728bf215546Sopenharmony_ci 729bf215546Sopenharmony_ci list_inithead(&slab->base.free); 730bf215546Sopenharmony_ci 731bf215546Sopenharmony_ci for (unsigned i = 0; i < slab->base.num_entries; i++) { 732bf215546Sopenharmony_ci struct iris_bo *bo = &slab->entries[i]; 733bf215546Sopenharmony_ci 734bf215546Sopenharmony_ci bo->size = entry_size; 735bf215546Sopenharmony_ci bo->bufmgr = bufmgr; 736bf215546Sopenharmony_ci bo->hash = _mesa_hash_pointer(bo); 737bf215546Sopenharmony_ci bo->gem_handle = 0; 738bf215546Sopenharmony_ci bo->address = slab->bo->address + i * entry_size; 739bf215546Sopenharmony_ci bo->aux_map_address = 0; 740bf215546Sopenharmony_ci bo->index = -1; 741bf215546Sopenharmony_ci bo->refcount = 0; 742bf215546Sopenharmony_ci bo->idle = true; 743bf215546Sopenharmony_ci 744bf215546Sopenharmony_ci bo->slab.entry.slab = &slab->base; 745bf215546Sopenharmony_ci bo->slab.entry.group_index = group_index; 746bf215546Sopenharmony_ci bo->slab.entry.entry_size = entry_size; 747bf215546Sopenharmony_ci 748bf215546Sopenharmony_ci bo->slab.real = iris_get_backing_bo(slab->bo); 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_ci list_addtail(&bo->slab.entry.head, &slab->base.free); 751bf215546Sopenharmony_ci } 752bf215546Sopenharmony_ci 753bf215546Sopenharmony_ci return &slab->base; 754bf215546Sopenharmony_ci 755bf215546Sopenharmony_cifail_bo: 756bf215546Sopenharmony_ci iris_bo_unreference(slab->bo); 757bf215546Sopenharmony_cifail: 758bf215546Sopenharmony_ci free(slab); 759bf215546Sopenharmony_ci return NULL; 760bf215546Sopenharmony_ci} 761bf215546Sopenharmony_ci 762bf215546Sopenharmony_cistatic enum iris_heap 763bf215546Sopenharmony_ciflags_to_heap(struct iris_bufmgr *bufmgr, unsigned flags) 764bf215546Sopenharmony_ci{ 765bf215546Sopenharmony_ci if (bufmgr->vram.size > 0 && 766bf215546Sopenharmony_ci !(flags & BO_ALLOC_SMEM) && 767bf215546Sopenharmony_ci !(flags & BO_ALLOC_COHERENT)) { 768bf215546Sopenharmony_ci return flags & BO_ALLOC_LMEM ? IRIS_HEAP_DEVICE_LOCAL : 769bf215546Sopenharmony_ci IRIS_HEAP_DEVICE_LOCAL_PREFERRED; 770bf215546Sopenharmony_ci } else { 771bf215546Sopenharmony_ci assert(!(flags & BO_ALLOC_LMEM)); 772bf215546Sopenharmony_ci return IRIS_HEAP_SYSTEM_MEMORY; 773bf215546Sopenharmony_ci } 774bf215546Sopenharmony_ci} 775bf215546Sopenharmony_ci 776bf215546Sopenharmony_cistatic struct iris_bo * 777bf215546Sopenharmony_cialloc_bo_from_slabs(struct iris_bufmgr *bufmgr, 778bf215546Sopenharmony_ci const char *name, 779bf215546Sopenharmony_ci uint64_t size, 780bf215546Sopenharmony_ci uint32_t alignment, 781bf215546Sopenharmony_ci unsigned flags) 782bf215546Sopenharmony_ci{ 783bf215546Sopenharmony_ci if (flags & BO_ALLOC_NO_SUBALLOC) 784bf215546Sopenharmony_ci return NULL; 785bf215546Sopenharmony_ci 786bf215546Sopenharmony_ci struct pb_slabs *last_slab = &bufmgr->bo_slabs[NUM_SLAB_ALLOCATORS - 1]; 787bf215546Sopenharmony_ci unsigned max_slab_entry_size = 788bf215546Sopenharmony_ci 1 << (last_slab->min_order + last_slab->num_orders - 1); 789bf215546Sopenharmony_ci 790bf215546Sopenharmony_ci if (size > max_slab_entry_size) 791bf215546Sopenharmony_ci return NULL; 792bf215546Sopenharmony_ci 793bf215546Sopenharmony_ci struct pb_slab_entry *entry; 794bf215546Sopenharmony_ci 795bf215546Sopenharmony_ci enum iris_heap heap = flags_to_heap(bufmgr, flags); 796bf215546Sopenharmony_ci 797bf215546Sopenharmony_ci unsigned alloc_size = size; 798bf215546Sopenharmony_ci 799bf215546Sopenharmony_ci /* Always use slabs for sizes less than 4 KB because the kernel aligns 800bf215546Sopenharmony_ci * everything to 4 KB. 801bf215546Sopenharmony_ci */ 802bf215546Sopenharmony_ci if (size < alignment && alignment <= 4 * 1024) 803bf215546Sopenharmony_ci alloc_size = alignment; 804bf215546Sopenharmony_ci 805bf215546Sopenharmony_ci if (alignment > get_slab_entry_alignment(bufmgr, alloc_size)) { 806bf215546Sopenharmony_ci /* 3/4 allocations can return too small alignment. 807bf215546Sopenharmony_ci * Try again with a power of two allocation size. 808bf215546Sopenharmony_ci */ 809bf215546Sopenharmony_ci unsigned pot_size = get_slab_pot_entry_size(bufmgr, alloc_size); 810bf215546Sopenharmony_ci 811bf215546Sopenharmony_ci if (alignment <= pot_size) { 812bf215546Sopenharmony_ci /* This size works but wastes some memory to fulfill the alignment. */ 813bf215546Sopenharmony_ci alloc_size = pot_size; 814bf215546Sopenharmony_ci } else { 815bf215546Sopenharmony_ci /* can't fulfill alignment requirements */ 816bf215546Sopenharmony_ci return NULL; 817bf215546Sopenharmony_ci } 818bf215546Sopenharmony_ci } 819bf215546Sopenharmony_ci 820bf215546Sopenharmony_ci struct pb_slabs *slabs = get_slabs(bufmgr, alloc_size); 821bf215546Sopenharmony_ci entry = pb_slab_alloc(slabs, alloc_size, heap); 822bf215546Sopenharmony_ci if (!entry) { 823bf215546Sopenharmony_ci /* Clean up and try again... */ 824bf215546Sopenharmony_ci pb_slabs_reclaim(slabs); 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci entry = pb_slab_alloc(slabs, alloc_size, heap); 827bf215546Sopenharmony_ci } 828bf215546Sopenharmony_ci if (!entry) 829bf215546Sopenharmony_ci return NULL; 830bf215546Sopenharmony_ci 831bf215546Sopenharmony_ci struct iris_bo *bo = container_of(entry, struct iris_bo, slab.entry); 832bf215546Sopenharmony_ci 833bf215546Sopenharmony_ci if (bo->aux_map_address && bo->bufmgr->aux_map_ctx) { 834bf215546Sopenharmony_ci /* This buffer was associated with an aux-buffer range. We only allow 835bf215546Sopenharmony_ci * slab allocated buffers to be reclaimed when idle (not in use by an 836bf215546Sopenharmony_ci * executing batch). (See iris_can_reclaim_slab().) So we know that 837bf215546Sopenharmony_ci * our previous aux mapping is no longer in use, and we can safely 838bf215546Sopenharmony_ci * remove it. 839bf215546Sopenharmony_ci */ 840bf215546Sopenharmony_ci intel_aux_map_unmap_range(bo->bufmgr->aux_map_ctx, bo->address, 841bf215546Sopenharmony_ci bo->size); 842bf215546Sopenharmony_ci bo->aux_map_address = 0; 843bf215546Sopenharmony_ci } 844bf215546Sopenharmony_ci 845bf215546Sopenharmony_ci p_atomic_set(&bo->refcount, 1); 846bf215546Sopenharmony_ci bo->name = name; 847bf215546Sopenharmony_ci bo->size = size; 848bf215546Sopenharmony_ci 849bf215546Sopenharmony_ci /* Zero the contents if necessary. If this fails, fall back to 850bf215546Sopenharmony_ci * allocating a fresh BO, which will always be zeroed by the kernel. 851bf215546Sopenharmony_ci */ 852bf215546Sopenharmony_ci if (flags & BO_ALLOC_ZEROED) { 853bf215546Sopenharmony_ci void *map = iris_bo_map(NULL, bo, MAP_WRITE | MAP_RAW); 854bf215546Sopenharmony_ci if (map) { 855bf215546Sopenharmony_ci memset(map, 0, bo->size); 856bf215546Sopenharmony_ci } else { 857bf215546Sopenharmony_ci pb_slab_free(slabs, &bo->slab.entry); 858bf215546Sopenharmony_ci return NULL; 859bf215546Sopenharmony_ci } 860bf215546Sopenharmony_ci } 861bf215546Sopenharmony_ci 862bf215546Sopenharmony_ci return bo; 863bf215546Sopenharmony_ci} 864bf215546Sopenharmony_ci 865bf215546Sopenharmony_cistatic struct iris_bo * 866bf215546Sopenharmony_cialloc_bo_from_cache(struct iris_bufmgr *bufmgr, 867bf215546Sopenharmony_ci struct bo_cache_bucket *bucket, 868bf215546Sopenharmony_ci uint32_t alignment, 869bf215546Sopenharmony_ci enum iris_memory_zone memzone, 870bf215546Sopenharmony_ci enum iris_mmap_mode mmap_mode, 871bf215546Sopenharmony_ci unsigned flags, 872bf215546Sopenharmony_ci bool match_zone) 873bf215546Sopenharmony_ci{ 874bf215546Sopenharmony_ci if (!bucket) 875bf215546Sopenharmony_ci return NULL; 876bf215546Sopenharmony_ci 877bf215546Sopenharmony_ci struct iris_bo *bo = NULL; 878bf215546Sopenharmony_ci 879bf215546Sopenharmony_ci simple_mtx_assert_locked(&bufmgr->lock); 880bf215546Sopenharmony_ci 881bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, cur, &bucket->head, head) { 882bf215546Sopenharmony_ci assert(iris_bo_is_real(cur)); 883bf215546Sopenharmony_ci 884bf215546Sopenharmony_ci /* Find one that's got the right mapping type. We used to swap maps 885bf215546Sopenharmony_ci * around but the kernel doesn't allow this on discrete GPUs. 886bf215546Sopenharmony_ci */ 887bf215546Sopenharmony_ci if (mmap_mode != cur->real.mmap_mode) 888bf215546Sopenharmony_ci continue; 889bf215546Sopenharmony_ci 890bf215546Sopenharmony_ci /* Try a little harder to find one that's already in the right memzone */ 891bf215546Sopenharmony_ci if (match_zone && memzone != iris_memzone_for_address(cur->address)) 892bf215546Sopenharmony_ci continue; 893bf215546Sopenharmony_ci 894bf215546Sopenharmony_ci /* If the last BO in the cache is busy, there are no idle BOs. Bail, 895bf215546Sopenharmony_ci * either falling back to a non-matching memzone, or if that fails, 896bf215546Sopenharmony_ci * allocating a fresh buffer. 897bf215546Sopenharmony_ci */ 898bf215546Sopenharmony_ci if (iris_bo_busy(cur)) 899bf215546Sopenharmony_ci return NULL; 900bf215546Sopenharmony_ci 901bf215546Sopenharmony_ci list_del(&cur->head); 902bf215546Sopenharmony_ci 903bf215546Sopenharmony_ci /* Tell the kernel we need this BO. If it still exists, we're done! */ 904bf215546Sopenharmony_ci if (iris_bo_madvise(cur, I915_MADV_WILLNEED)) { 905bf215546Sopenharmony_ci bo = cur; 906bf215546Sopenharmony_ci break; 907bf215546Sopenharmony_ci } 908bf215546Sopenharmony_ci 909bf215546Sopenharmony_ci /* This BO was purged, throw it out and keep looking. */ 910bf215546Sopenharmony_ci bo_free(cur); 911bf215546Sopenharmony_ci } 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_ci if (!bo) 914bf215546Sopenharmony_ci return NULL; 915bf215546Sopenharmony_ci 916bf215546Sopenharmony_ci if (bo->aux_map_address) { 917bf215546Sopenharmony_ci /* This buffer was associated with an aux-buffer range. We make sure 918bf215546Sopenharmony_ci * that buffers are not reused from the cache while the buffer is (busy) 919bf215546Sopenharmony_ci * being used by an executing batch. Since we are here, the buffer is no 920bf215546Sopenharmony_ci * longer being used by a batch and the buffer was deleted (in order to 921bf215546Sopenharmony_ci * end up in the cache). Therefore its old aux-buffer range can be 922bf215546Sopenharmony_ci * removed from the aux-map. 923bf215546Sopenharmony_ci */ 924bf215546Sopenharmony_ci if (bo->bufmgr->aux_map_ctx) 925bf215546Sopenharmony_ci intel_aux_map_unmap_range(bo->bufmgr->aux_map_ctx, bo->address, 926bf215546Sopenharmony_ci bo->size); 927bf215546Sopenharmony_ci bo->aux_map_address = 0; 928bf215546Sopenharmony_ci } 929bf215546Sopenharmony_ci 930bf215546Sopenharmony_ci /* If the cached BO isn't in the right memory zone, or the alignment 931bf215546Sopenharmony_ci * isn't sufficient, free the old memory and assign it a new address. 932bf215546Sopenharmony_ci */ 933bf215546Sopenharmony_ci if (memzone != iris_memzone_for_address(bo->address) || 934bf215546Sopenharmony_ci bo->address % alignment != 0) { 935bf215546Sopenharmony_ci vma_free(bufmgr, bo->address, bo->size); 936bf215546Sopenharmony_ci bo->address = 0ull; 937bf215546Sopenharmony_ci } 938bf215546Sopenharmony_ci 939bf215546Sopenharmony_ci /* Zero the contents if necessary. If this fails, fall back to 940bf215546Sopenharmony_ci * allocating a fresh BO, which will always be zeroed by the kernel. 941bf215546Sopenharmony_ci */ 942bf215546Sopenharmony_ci if (flags & BO_ALLOC_ZEROED) { 943bf215546Sopenharmony_ci void *map = iris_bo_map(NULL, bo, MAP_WRITE | MAP_RAW); 944bf215546Sopenharmony_ci if (map) { 945bf215546Sopenharmony_ci memset(map, 0, bo->size); 946bf215546Sopenharmony_ci } else { 947bf215546Sopenharmony_ci bo_free(bo); 948bf215546Sopenharmony_ci return NULL; 949bf215546Sopenharmony_ci } 950bf215546Sopenharmony_ci } 951bf215546Sopenharmony_ci 952bf215546Sopenharmony_ci return bo; 953bf215546Sopenharmony_ci} 954bf215546Sopenharmony_ci 955bf215546Sopenharmony_cistatic struct iris_bo * 956bf215546Sopenharmony_cialloc_fresh_bo(struct iris_bufmgr *bufmgr, uint64_t bo_size, unsigned flags) 957bf215546Sopenharmony_ci{ 958bf215546Sopenharmony_ci struct iris_bo *bo = bo_calloc(); 959bf215546Sopenharmony_ci if (!bo) 960bf215546Sopenharmony_ci return NULL; 961bf215546Sopenharmony_ci 962bf215546Sopenharmony_ci bo->real.heap = flags_to_heap(bufmgr, flags); 963bf215546Sopenharmony_ci 964bf215546Sopenharmony_ci /* If we have vram size, we have multiple memory regions and should choose 965bf215546Sopenharmony_ci * one of them. 966bf215546Sopenharmony_ci */ 967bf215546Sopenharmony_ci if (bufmgr->vram.size > 0) { 968bf215546Sopenharmony_ci /* All new BOs we get from the kernel are zeroed, so we don't need to 969bf215546Sopenharmony_ci * worry about that here. 970bf215546Sopenharmony_ci */ 971bf215546Sopenharmony_ci struct drm_i915_gem_memory_class_instance regions[2]; 972bf215546Sopenharmony_ci uint32_t nregions = 0; 973bf215546Sopenharmony_ci switch (bo->real.heap) { 974bf215546Sopenharmony_ci case IRIS_HEAP_DEVICE_LOCAL_PREFERRED: 975bf215546Sopenharmony_ci /* For vram allocations, still use system memory as a fallback. */ 976bf215546Sopenharmony_ci regions[nregions++] = bufmgr->vram.region; 977bf215546Sopenharmony_ci regions[nregions++] = bufmgr->sys.region; 978bf215546Sopenharmony_ci break; 979bf215546Sopenharmony_ci case IRIS_HEAP_DEVICE_LOCAL: 980bf215546Sopenharmony_ci regions[nregions++] = bufmgr->vram.region; 981bf215546Sopenharmony_ci break; 982bf215546Sopenharmony_ci case IRIS_HEAP_SYSTEM_MEMORY: 983bf215546Sopenharmony_ci regions[nregions++] = bufmgr->sys.region; 984bf215546Sopenharmony_ci break; 985bf215546Sopenharmony_ci case IRIS_HEAP_MAX: 986bf215546Sopenharmony_ci unreachable("invalid heap for BO"); 987bf215546Sopenharmony_ci } 988bf215546Sopenharmony_ci 989bf215546Sopenharmony_ci struct drm_i915_gem_create_ext_memory_regions ext_regions = { 990bf215546Sopenharmony_ci .base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS }, 991bf215546Sopenharmony_ci .num_regions = nregions, 992bf215546Sopenharmony_ci .regions = (uintptr_t)regions, 993bf215546Sopenharmony_ci }; 994bf215546Sopenharmony_ci 995bf215546Sopenharmony_ci struct drm_i915_gem_create_ext create = { 996bf215546Sopenharmony_ci .size = bo_size, 997bf215546Sopenharmony_ci .extensions = (uintptr_t)&ext_regions, 998bf215546Sopenharmony_ci }; 999bf215546Sopenharmony_ci 1000bf215546Sopenharmony_ci if (!bufmgr->all_vram_mappable && 1001bf215546Sopenharmony_ci bo->real.heap == IRIS_HEAP_DEVICE_LOCAL_PREFERRED) { 1002bf215546Sopenharmony_ci create.flags |= I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS; 1003bf215546Sopenharmony_ci } 1004bf215546Sopenharmony_ci 1005bf215546Sopenharmony_ci /* It should be safe to use GEM_CREATE_EXT without checking, since we are 1006bf215546Sopenharmony_ci * in the side of the branch where discrete memory is available. So we 1007bf215546Sopenharmony_ci * can assume GEM_CREATE_EXT is supported already. 1008bf215546Sopenharmony_ci */ 1009bf215546Sopenharmony_ci if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create) != 0) { 1010bf215546Sopenharmony_ci free(bo); 1011bf215546Sopenharmony_ci return NULL; 1012bf215546Sopenharmony_ci } 1013bf215546Sopenharmony_ci bo->gem_handle = create.handle; 1014bf215546Sopenharmony_ci } else { 1015bf215546Sopenharmony_ci struct drm_i915_gem_create create = { .size = bo_size }; 1016bf215546Sopenharmony_ci 1017bf215546Sopenharmony_ci /* All new BOs we get from the kernel are zeroed, so we don't need to 1018bf215546Sopenharmony_ci * worry about that here. 1019bf215546Sopenharmony_ci */ 1020bf215546Sopenharmony_ci if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) { 1021bf215546Sopenharmony_ci free(bo); 1022bf215546Sopenharmony_ci return NULL; 1023bf215546Sopenharmony_ci } 1024bf215546Sopenharmony_ci bo->gem_handle = create.handle; 1025bf215546Sopenharmony_ci } 1026bf215546Sopenharmony_ci 1027bf215546Sopenharmony_ci bo->bufmgr = bufmgr; 1028bf215546Sopenharmony_ci bo->size = bo_size; 1029bf215546Sopenharmony_ci bo->idle = true; 1030bf215546Sopenharmony_ci 1031bf215546Sopenharmony_ci if (bufmgr->vram.size == 0) { 1032bf215546Sopenharmony_ci /* Calling set_domain() will allocate pages for the BO outside of the 1033bf215546Sopenharmony_ci * struct mutex lock in the kernel, which is more efficient than waiting 1034bf215546Sopenharmony_ci * to create them during the first execbuf that uses the BO. 1035bf215546Sopenharmony_ci */ 1036bf215546Sopenharmony_ci struct drm_i915_gem_set_domain sd = { 1037bf215546Sopenharmony_ci .handle = bo->gem_handle, 1038bf215546Sopenharmony_ci .read_domains = I915_GEM_DOMAIN_CPU, 1039bf215546Sopenharmony_ci .write_domain = 0, 1040bf215546Sopenharmony_ci }; 1041bf215546Sopenharmony_ci 1042bf215546Sopenharmony_ci intel_ioctl(bo->bufmgr->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &sd); 1043bf215546Sopenharmony_ci } 1044bf215546Sopenharmony_ci 1045bf215546Sopenharmony_ci return bo; 1046bf215546Sopenharmony_ci} 1047bf215546Sopenharmony_ci 1048bf215546Sopenharmony_ciconst char * 1049bf215546Sopenharmony_ciiris_heap_to_string[IRIS_HEAP_MAX] = { 1050bf215546Sopenharmony_ci [IRIS_HEAP_SYSTEM_MEMORY] = "system", 1051bf215546Sopenharmony_ci [IRIS_HEAP_DEVICE_LOCAL] = "local", 1052bf215546Sopenharmony_ci [IRIS_HEAP_DEVICE_LOCAL_PREFERRED] = "local-preferred", 1053bf215546Sopenharmony_ci}; 1054bf215546Sopenharmony_ci 1055bf215546Sopenharmony_cistruct iris_bo * 1056bf215546Sopenharmony_ciiris_bo_alloc(struct iris_bufmgr *bufmgr, 1057bf215546Sopenharmony_ci const char *name, 1058bf215546Sopenharmony_ci uint64_t size, 1059bf215546Sopenharmony_ci uint32_t alignment, 1060bf215546Sopenharmony_ci enum iris_memory_zone memzone, 1061bf215546Sopenharmony_ci unsigned flags) 1062bf215546Sopenharmony_ci{ 1063bf215546Sopenharmony_ci struct iris_bo *bo; 1064bf215546Sopenharmony_ci unsigned int page_size = getpagesize(); 1065bf215546Sopenharmony_ci enum iris_heap heap = flags_to_heap(bufmgr, flags); 1066bf215546Sopenharmony_ci bool local = heap != IRIS_HEAP_SYSTEM_MEMORY; 1067bf215546Sopenharmony_ci struct bo_cache_bucket *bucket = bucket_for_size(bufmgr, size, heap); 1068bf215546Sopenharmony_ci 1069bf215546Sopenharmony_ci if (memzone != IRIS_MEMZONE_OTHER || (flags & BO_ALLOC_COHERENT)) 1070bf215546Sopenharmony_ci flags |= BO_ALLOC_NO_SUBALLOC; 1071bf215546Sopenharmony_ci 1072bf215546Sopenharmony_ci bo = alloc_bo_from_slabs(bufmgr, name, size, alignment, flags); 1073bf215546Sopenharmony_ci 1074bf215546Sopenharmony_ci if (bo) 1075bf215546Sopenharmony_ci return bo; 1076bf215546Sopenharmony_ci 1077bf215546Sopenharmony_ci /* Round the size up to the bucket size, or if we don't have caching 1078bf215546Sopenharmony_ci * at this size, a multiple of the page size. 1079bf215546Sopenharmony_ci */ 1080bf215546Sopenharmony_ci uint64_t bo_size = 1081bf215546Sopenharmony_ci bucket ? bucket->size : MAX2(ALIGN(size, page_size), page_size); 1082bf215546Sopenharmony_ci 1083bf215546Sopenharmony_ci bool is_coherent = bufmgr->has_llc || 1084bf215546Sopenharmony_ci (bufmgr->vram.size > 0 && !local) || 1085bf215546Sopenharmony_ci (flags & BO_ALLOC_COHERENT); 1086bf215546Sopenharmony_ci bool is_scanout = (flags & BO_ALLOC_SCANOUT) != 0; 1087bf215546Sopenharmony_ci 1088bf215546Sopenharmony_ci enum iris_mmap_mode mmap_mode; 1089bf215546Sopenharmony_ci if (!bufmgr->all_vram_mappable && heap == IRIS_HEAP_DEVICE_LOCAL) 1090bf215546Sopenharmony_ci mmap_mode = IRIS_MMAP_NONE; 1091bf215546Sopenharmony_ci else if (!local && is_coherent && !is_scanout) 1092bf215546Sopenharmony_ci mmap_mode = IRIS_MMAP_WB; 1093bf215546Sopenharmony_ci else 1094bf215546Sopenharmony_ci mmap_mode = IRIS_MMAP_WC; 1095bf215546Sopenharmony_ci 1096bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1097bf215546Sopenharmony_ci 1098bf215546Sopenharmony_ci /* Get a buffer out of the cache if available. First, we try to find 1099bf215546Sopenharmony_ci * one with a matching memory zone so we can avoid reallocating VMA. 1100bf215546Sopenharmony_ci */ 1101bf215546Sopenharmony_ci bo = alloc_bo_from_cache(bufmgr, bucket, alignment, memzone, mmap_mode, 1102bf215546Sopenharmony_ci flags, true); 1103bf215546Sopenharmony_ci 1104bf215546Sopenharmony_ci /* If that fails, we try for any cached BO, without matching memzone. */ 1105bf215546Sopenharmony_ci if (!bo) { 1106bf215546Sopenharmony_ci bo = alloc_bo_from_cache(bufmgr, bucket, alignment, memzone, mmap_mode, 1107bf215546Sopenharmony_ci flags, false); 1108bf215546Sopenharmony_ci } 1109bf215546Sopenharmony_ci 1110bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1111bf215546Sopenharmony_ci 1112bf215546Sopenharmony_ci if (!bo) { 1113bf215546Sopenharmony_ci bo = alloc_fresh_bo(bufmgr, bo_size, flags); 1114bf215546Sopenharmony_ci if (!bo) 1115bf215546Sopenharmony_ci return NULL; 1116bf215546Sopenharmony_ci } 1117bf215546Sopenharmony_ci 1118bf215546Sopenharmony_ci if (bo->address == 0ull) { 1119bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1120bf215546Sopenharmony_ci bo->address = vma_alloc(bufmgr, memzone, bo->size, alignment); 1121bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1122bf215546Sopenharmony_ci 1123bf215546Sopenharmony_ci if (bo->address == 0ull) 1124bf215546Sopenharmony_ci goto err_free; 1125bf215546Sopenharmony_ci } 1126bf215546Sopenharmony_ci 1127bf215546Sopenharmony_ci bo->name = name; 1128bf215546Sopenharmony_ci p_atomic_set(&bo->refcount, 1); 1129bf215546Sopenharmony_ci bo->real.reusable = bucket && bufmgr->bo_reuse; 1130bf215546Sopenharmony_ci bo->index = -1; 1131bf215546Sopenharmony_ci bo->real.kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED; 1132bf215546Sopenharmony_ci 1133bf215546Sopenharmony_ci /* By default, capture all driver-internal buffers like shader kernels, 1134bf215546Sopenharmony_ci * surface states, dynamic states, border colors, and so on. 1135bf215546Sopenharmony_ci */ 1136bf215546Sopenharmony_ci if (memzone < IRIS_MEMZONE_OTHER) 1137bf215546Sopenharmony_ci bo->real.kflags |= EXEC_OBJECT_CAPTURE; 1138bf215546Sopenharmony_ci 1139bf215546Sopenharmony_ci assert(bo->real.map == NULL || bo->real.mmap_mode == mmap_mode); 1140bf215546Sopenharmony_ci bo->real.mmap_mode = mmap_mode; 1141bf215546Sopenharmony_ci 1142bf215546Sopenharmony_ci /* On integrated GPUs, enable snooping to ensure coherency if needed. 1143bf215546Sopenharmony_ci * For discrete, we instead use SMEM and avoid WB maps for coherency. 1144bf215546Sopenharmony_ci */ 1145bf215546Sopenharmony_ci if ((flags & BO_ALLOC_COHERENT) && 1146bf215546Sopenharmony_ci !bufmgr->has_llc && bufmgr->vram.size == 0) { 1147bf215546Sopenharmony_ci struct drm_i915_gem_caching arg = { 1148bf215546Sopenharmony_ci .handle = bo->gem_handle, 1149bf215546Sopenharmony_ci .caching = 1, 1150bf215546Sopenharmony_ci }; 1151bf215546Sopenharmony_ci if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_CACHING, &arg) != 0) 1152bf215546Sopenharmony_ci goto err_free; 1153bf215546Sopenharmony_ci 1154bf215546Sopenharmony_ci bo->real.reusable = false; 1155bf215546Sopenharmony_ci } 1156bf215546Sopenharmony_ci 1157bf215546Sopenharmony_ci DBG("bo_create: buf %d (%s) (%s memzone) (%s) %llub\n", bo->gem_handle, 1158bf215546Sopenharmony_ci bo->name, memzone_name(memzone), iris_heap_to_string[bo->real.heap], 1159bf215546Sopenharmony_ci (unsigned long long) size); 1160bf215546Sopenharmony_ci 1161bf215546Sopenharmony_ci return bo; 1162bf215546Sopenharmony_ci 1163bf215546Sopenharmony_cierr_free: 1164bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1165bf215546Sopenharmony_ci bo_free(bo); 1166bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1167bf215546Sopenharmony_ci return NULL; 1168bf215546Sopenharmony_ci} 1169bf215546Sopenharmony_ci 1170bf215546Sopenharmony_cistruct iris_bo * 1171bf215546Sopenharmony_ciiris_bo_create_userptr(struct iris_bufmgr *bufmgr, const char *name, 1172bf215546Sopenharmony_ci void *ptr, size_t size, 1173bf215546Sopenharmony_ci enum iris_memory_zone memzone) 1174bf215546Sopenharmony_ci{ 1175bf215546Sopenharmony_ci struct drm_gem_close close = { 0, }; 1176bf215546Sopenharmony_ci struct iris_bo *bo; 1177bf215546Sopenharmony_ci 1178bf215546Sopenharmony_ci bo = bo_calloc(); 1179bf215546Sopenharmony_ci if (!bo) 1180bf215546Sopenharmony_ci return NULL; 1181bf215546Sopenharmony_ci 1182bf215546Sopenharmony_ci struct drm_i915_gem_userptr arg = { 1183bf215546Sopenharmony_ci .user_ptr = (uintptr_t)ptr, 1184bf215546Sopenharmony_ci .user_size = size, 1185bf215546Sopenharmony_ci .flags = bufmgr->has_userptr_probe ? I915_USERPTR_PROBE : 0, 1186bf215546Sopenharmony_ci }; 1187bf215546Sopenharmony_ci if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_USERPTR, &arg)) 1188bf215546Sopenharmony_ci goto err_free; 1189bf215546Sopenharmony_ci bo->gem_handle = arg.handle; 1190bf215546Sopenharmony_ci 1191bf215546Sopenharmony_ci if (!bufmgr->has_userptr_probe) { 1192bf215546Sopenharmony_ci /* Check the buffer for validity before we try and use it in a batch */ 1193bf215546Sopenharmony_ci struct drm_i915_gem_set_domain sd = { 1194bf215546Sopenharmony_ci .handle = bo->gem_handle, 1195bf215546Sopenharmony_ci .read_domains = I915_GEM_DOMAIN_CPU, 1196bf215546Sopenharmony_ci }; 1197bf215546Sopenharmony_ci if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &sd)) 1198bf215546Sopenharmony_ci goto err_close; 1199bf215546Sopenharmony_ci } 1200bf215546Sopenharmony_ci 1201bf215546Sopenharmony_ci bo->name = name; 1202bf215546Sopenharmony_ci bo->size = size; 1203bf215546Sopenharmony_ci bo->real.map = ptr; 1204bf215546Sopenharmony_ci 1205bf215546Sopenharmony_ci bo->bufmgr = bufmgr; 1206bf215546Sopenharmony_ci bo->real.kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED; 1207bf215546Sopenharmony_ci 1208bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1209bf215546Sopenharmony_ci bo->address = vma_alloc(bufmgr, memzone, size, 1); 1210bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1211bf215546Sopenharmony_ci 1212bf215546Sopenharmony_ci if (bo->address == 0ull) 1213bf215546Sopenharmony_ci goto err_close; 1214bf215546Sopenharmony_ci 1215bf215546Sopenharmony_ci p_atomic_set(&bo->refcount, 1); 1216bf215546Sopenharmony_ci bo->real.userptr = true; 1217bf215546Sopenharmony_ci bo->index = -1; 1218bf215546Sopenharmony_ci bo->idle = true; 1219bf215546Sopenharmony_ci bo->real.mmap_mode = IRIS_MMAP_WB; 1220bf215546Sopenharmony_ci 1221bf215546Sopenharmony_ci return bo; 1222bf215546Sopenharmony_ci 1223bf215546Sopenharmony_cierr_close: 1224bf215546Sopenharmony_ci close.handle = bo->gem_handle; 1225bf215546Sopenharmony_ci intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_CLOSE, &close); 1226bf215546Sopenharmony_cierr_free: 1227bf215546Sopenharmony_ci free(bo); 1228bf215546Sopenharmony_ci return NULL; 1229bf215546Sopenharmony_ci} 1230bf215546Sopenharmony_ci 1231bf215546Sopenharmony_ci/** 1232bf215546Sopenharmony_ci * Returns a iris_bo wrapping the given buffer object handle. 1233bf215546Sopenharmony_ci * 1234bf215546Sopenharmony_ci * This can be used when one application needs to pass a buffer object 1235bf215546Sopenharmony_ci * to another. 1236bf215546Sopenharmony_ci */ 1237bf215546Sopenharmony_cistruct iris_bo * 1238bf215546Sopenharmony_ciiris_bo_gem_create_from_name(struct iris_bufmgr *bufmgr, 1239bf215546Sopenharmony_ci const char *name, unsigned int handle) 1240bf215546Sopenharmony_ci{ 1241bf215546Sopenharmony_ci struct iris_bo *bo; 1242bf215546Sopenharmony_ci 1243bf215546Sopenharmony_ci /* At the moment most applications only have a few named bo. 1244bf215546Sopenharmony_ci * For instance, in a DRI client only the render buffers passed 1245bf215546Sopenharmony_ci * between X and the client are named. And since X returns the 1246bf215546Sopenharmony_ci * alternating names for the front/back buffer a linear search 1247bf215546Sopenharmony_ci * provides a sufficiently fast match. 1248bf215546Sopenharmony_ci */ 1249bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1250bf215546Sopenharmony_ci bo = find_and_ref_external_bo(bufmgr->name_table, handle); 1251bf215546Sopenharmony_ci if (bo) 1252bf215546Sopenharmony_ci goto out; 1253bf215546Sopenharmony_ci 1254bf215546Sopenharmony_ci struct drm_gem_open open_arg = { .name = handle }; 1255bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_OPEN, &open_arg); 1256bf215546Sopenharmony_ci if (ret != 0) { 1257bf215546Sopenharmony_ci DBG("Couldn't reference %s handle 0x%08x: %s\n", 1258bf215546Sopenharmony_ci name, handle, strerror(errno)); 1259bf215546Sopenharmony_ci bo = NULL; 1260bf215546Sopenharmony_ci goto out; 1261bf215546Sopenharmony_ci } 1262bf215546Sopenharmony_ci /* Now see if someone has used a prime handle to get this 1263bf215546Sopenharmony_ci * object from the kernel before by looking through the list 1264bf215546Sopenharmony_ci * again for a matching gem_handle 1265bf215546Sopenharmony_ci */ 1266bf215546Sopenharmony_ci bo = find_and_ref_external_bo(bufmgr->handle_table, open_arg.handle); 1267bf215546Sopenharmony_ci if (bo) 1268bf215546Sopenharmony_ci goto out; 1269bf215546Sopenharmony_ci 1270bf215546Sopenharmony_ci bo = bo_calloc(); 1271bf215546Sopenharmony_ci if (!bo) { 1272bf215546Sopenharmony_ci struct drm_gem_close close = { .handle = open_arg.handle, }; 1273bf215546Sopenharmony_ci intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_CLOSE, &close); 1274bf215546Sopenharmony_ci goto out; 1275bf215546Sopenharmony_ci } 1276bf215546Sopenharmony_ci 1277bf215546Sopenharmony_ci p_atomic_set(&bo->refcount, 1); 1278bf215546Sopenharmony_ci 1279bf215546Sopenharmony_ci bo->size = open_arg.size; 1280bf215546Sopenharmony_ci bo->bufmgr = bufmgr; 1281bf215546Sopenharmony_ci bo->gem_handle = open_arg.handle; 1282bf215546Sopenharmony_ci bo->name = name; 1283bf215546Sopenharmony_ci bo->real.global_name = handle; 1284bf215546Sopenharmony_ci bo->real.reusable = false; 1285bf215546Sopenharmony_ci bo->real.imported = true; 1286bf215546Sopenharmony_ci bo->real.mmap_mode = IRIS_MMAP_NONE; 1287bf215546Sopenharmony_ci bo->real.kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED; 1288bf215546Sopenharmony_ci bo->address = vma_alloc(bufmgr, IRIS_MEMZONE_OTHER, bo->size, 1); 1289bf215546Sopenharmony_ci 1290bf215546Sopenharmony_ci if (bo->address == 0ull) { 1291bf215546Sopenharmony_ci bo_free(bo); 1292bf215546Sopenharmony_ci bo = NULL; 1293bf215546Sopenharmony_ci goto out; 1294bf215546Sopenharmony_ci } 1295bf215546Sopenharmony_ci 1296bf215546Sopenharmony_ci _mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo); 1297bf215546Sopenharmony_ci _mesa_hash_table_insert(bufmgr->name_table, &bo->real.global_name, bo); 1298bf215546Sopenharmony_ci 1299bf215546Sopenharmony_ci DBG("bo_create_from_handle: %d (%s)\n", handle, bo->name); 1300bf215546Sopenharmony_ci 1301bf215546Sopenharmony_ciout: 1302bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1303bf215546Sopenharmony_ci return bo; 1304bf215546Sopenharmony_ci} 1305bf215546Sopenharmony_ci 1306bf215546Sopenharmony_cistatic void 1307bf215546Sopenharmony_cibo_close(struct iris_bo *bo) 1308bf215546Sopenharmony_ci{ 1309bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1310bf215546Sopenharmony_ci 1311bf215546Sopenharmony_ci simple_mtx_assert_locked(&bufmgr->lock); 1312bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1313bf215546Sopenharmony_ci 1314bf215546Sopenharmony_ci if (iris_bo_is_external(bo)) { 1315bf215546Sopenharmony_ci struct hash_entry *entry; 1316bf215546Sopenharmony_ci 1317bf215546Sopenharmony_ci if (bo->real.global_name) { 1318bf215546Sopenharmony_ci entry = _mesa_hash_table_search(bufmgr->name_table, 1319bf215546Sopenharmony_ci &bo->real.global_name); 1320bf215546Sopenharmony_ci _mesa_hash_table_remove(bufmgr->name_table, entry); 1321bf215546Sopenharmony_ci } 1322bf215546Sopenharmony_ci 1323bf215546Sopenharmony_ci entry = _mesa_hash_table_search(bufmgr->handle_table, &bo->gem_handle); 1324bf215546Sopenharmony_ci _mesa_hash_table_remove(bufmgr->handle_table, entry); 1325bf215546Sopenharmony_ci 1326bf215546Sopenharmony_ci list_for_each_entry_safe(struct bo_export, export, &bo->real.exports, link) { 1327bf215546Sopenharmony_ci struct drm_gem_close close = { .handle = export->gem_handle }; 1328bf215546Sopenharmony_ci intel_ioctl(export->drm_fd, DRM_IOCTL_GEM_CLOSE, &close); 1329bf215546Sopenharmony_ci 1330bf215546Sopenharmony_ci list_del(&export->link); 1331bf215546Sopenharmony_ci free(export); 1332bf215546Sopenharmony_ci } 1333bf215546Sopenharmony_ci } else { 1334bf215546Sopenharmony_ci assert(list_is_empty(&bo->real.exports)); 1335bf215546Sopenharmony_ci } 1336bf215546Sopenharmony_ci 1337bf215546Sopenharmony_ci /* Close this object */ 1338bf215546Sopenharmony_ci struct drm_gem_close close = { .handle = bo->gem_handle }; 1339bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_CLOSE, &close); 1340bf215546Sopenharmony_ci if (ret != 0) { 1341bf215546Sopenharmony_ci DBG("DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n", 1342bf215546Sopenharmony_ci bo->gem_handle, bo->name, strerror(errno)); 1343bf215546Sopenharmony_ci } 1344bf215546Sopenharmony_ci 1345bf215546Sopenharmony_ci if (bo->aux_map_address && bo->bufmgr->aux_map_ctx) { 1346bf215546Sopenharmony_ci intel_aux_map_unmap_range(bo->bufmgr->aux_map_ctx, bo->address, 1347bf215546Sopenharmony_ci bo->size); 1348bf215546Sopenharmony_ci } 1349bf215546Sopenharmony_ci 1350bf215546Sopenharmony_ci /* Return the VMA for reuse */ 1351bf215546Sopenharmony_ci vma_free(bo->bufmgr, bo->address, bo->size); 1352bf215546Sopenharmony_ci 1353bf215546Sopenharmony_ci for (int d = 0; d < bo->deps_size; d++) { 1354bf215546Sopenharmony_ci for (int b = 0; b < IRIS_BATCH_COUNT; b++) { 1355bf215546Sopenharmony_ci iris_syncobj_reference(bufmgr, &bo->deps[d].write_syncobjs[b], NULL); 1356bf215546Sopenharmony_ci iris_syncobj_reference(bufmgr, &bo->deps[d].read_syncobjs[b], NULL); 1357bf215546Sopenharmony_ci } 1358bf215546Sopenharmony_ci } 1359bf215546Sopenharmony_ci free(bo->deps); 1360bf215546Sopenharmony_ci 1361bf215546Sopenharmony_ci free(bo); 1362bf215546Sopenharmony_ci} 1363bf215546Sopenharmony_ci 1364bf215546Sopenharmony_cistatic void 1365bf215546Sopenharmony_cibo_free(struct iris_bo *bo) 1366bf215546Sopenharmony_ci{ 1367bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1368bf215546Sopenharmony_ci 1369bf215546Sopenharmony_ci simple_mtx_assert_locked(&bufmgr->lock); 1370bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1371bf215546Sopenharmony_ci 1372bf215546Sopenharmony_ci if (!bo->real.userptr && bo->real.map) 1373bf215546Sopenharmony_ci bo_unmap(bo); 1374bf215546Sopenharmony_ci 1375bf215546Sopenharmony_ci if (bo->idle) { 1376bf215546Sopenharmony_ci bo_close(bo); 1377bf215546Sopenharmony_ci } else { 1378bf215546Sopenharmony_ci /* Defer closing the GEM BO and returning the VMA for reuse until the 1379bf215546Sopenharmony_ci * BO is idle. Just move it to the dead list for now. 1380bf215546Sopenharmony_ci */ 1381bf215546Sopenharmony_ci list_addtail(&bo->head, &bufmgr->zombie_list); 1382bf215546Sopenharmony_ci } 1383bf215546Sopenharmony_ci} 1384bf215546Sopenharmony_ci 1385bf215546Sopenharmony_ci/** Frees all cached buffers significantly older than @time. */ 1386bf215546Sopenharmony_cistatic void 1387bf215546Sopenharmony_cicleanup_bo_cache(struct iris_bufmgr *bufmgr, time_t time) 1388bf215546Sopenharmony_ci{ 1389bf215546Sopenharmony_ci int i; 1390bf215546Sopenharmony_ci 1391bf215546Sopenharmony_ci simple_mtx_assert_locked(&bufmgr->lock); 1392bf215546Sopenharmony_ci 1393bf215546Sopenharmony_ci if (bufmgr->time == time) 1394bf215546Sopenharmony_ci return; 1395bf215546Sopenharmony_ci 1396bf215546Sopenharmony_ci for (i = 0; i < bufmgr->num_buckets; i++) { 1397bf215546Sopenharmony_ci struct bo_cache_bucket *bucket = &bufmgr->cache_bucket[i]; 1398bf215546Sopenharmony_ci 1399bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) { 1400bf215546Sopenharmony_ci if (time - bo->real.free_time <= 1) 1401bf215546Sopenharmony_ci break; 1402bf215546Sopenharmony_ci 1403bf215546Sopenharmony_ci list_del(&bo->head); 1404bf215546Sopenharmony_ci 1405bf215546Sopenharmony_ci bo_free(bo); 1406bf215546Sopenharmony_ci } 1407bf215546Sopenharmony_ci } 1408bf215546Sopenharmony_ci 1409bf215546Sopenharmony_ci for (i = 0; i < bufmgr->num_local_buckets; i++) { 1410bf215546Sopenharmony_ci struct bo_cache_bucket *bucket = &bufmgr->local_cache_bucket[i]; 1411bf215546Sopenharmony_ci 1412bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) { 1413bf215546Sopenharmony_ci if (time - bo->real.free_time <= 1) 1414bf215546Sopenharmony_ci break; 1415bf215546Sopenharmony_ci 1416bf215546Sopenharmony_ci list_del(&bo->head); 1417bf215546Sopenharmony_ci 1418bf215546Sopenharmony_ci bo_free(bo); 1419bf215546Sopenharmony_ci } 1420bf215546Sopenharmony_ci } 1421bf215546Sopenharmony_ci 1422bf215546Sopenharmony_ci for (i = 0; i < bufmgr->num_local_preferred_buckets; i++) { 1423bf215546Sopenharmony_ci struct bo_cache_bucket *bucket = &bufmgr->local_preferred_cache_bucket[i]; 1424bf215546Sopenharmony_ci 1425bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) { 1426bf215546Sopenharmony_ci if (time - bo->real.free_time <= 1) 1427bf215546Sopenharmony_ci break; 1428bf215546Sopenharmony_ci 1429bf215546Sopenharmony_ci list_del(&bo->head); 1430bf215546Sopenharmony_ci 1431bf215546Sopenharmony_ci bo_free(bo); 1432bf215546Sopenharmony_ci } 1433bf215546Sopenharmony_ci } 1434bf215546Sopenharmony_ci 1435bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bufmgr->zombie_list, head) { 1436bf215546Sopenharmony_ci /* Stop once we reach a busy BO - all others past this point were 1437bf215546Sopenharmony_ci * freed more recently so are likely also busy. 1438bf215546Sopenharmony_ci */ 1439bf215546Sopenharmony_ci if (!bo->idle && iris_bo_busy(bo)) 1440bf215546Sopenharmony_ci break; 1441bf215546Sopenharmony_ci 1442bf215546Sopenharmony_ci list_del(&bo->head); 1443bf215546Sopenharmony_ci bo_close(bo); 1444bf215546Sopenharmony_ci } 1445bf215546Sopenharmony_ci 1446bf215546Sopenharmony_ci bufmgr->time = time; 1447bf215546Sopenharmony_ci} 1448bf215546Sopenharmony_ci 1449bf215546Sopenharmony_cistatic void 1450bf215546Sopenharmony_cibo_unreference_final(struct iris_bo *bo, time_t time) 1451bf215546Sopenharmony_ci{ 1452bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1453bf215546Sopenharmony_ci struct bo_cache_bucket *bucket; 1454bf215546Sopenharmony_ci 1455bf215546Sopenharmony_ci DBG("bo_unreference final: %d (%s)\n", bo->gem_handle, bo->name); 1456bf215546Sopenharmony_ci 1457bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1458bf215546Sopenharmony_ci 1459bf215546Sopenharmony_ci bucket = NULL; 1460bf215546Sopenharmony_ci if (bo->real.reusable) 1461bf215546Sopenharmony_ci bucket = bucket_for_size(bufmgr, bo->size, bo->real.heap); 1462bf215546Sopenharmony_ci /* Put the buffer into our internal cache for reuse if we can. */ 1463bf215546Sopenharmony_ci if (bucket && iris_bo_madvise(bo, I915_MADV_DONTNEED)) { 1464bf215546Sopenharmony_ci bo->real.free_time = time; 1465bf215546Sopenharmony_ci bo->name = NULL; 1466bf215546Sopenharmony_ci 1467bf215546Sopenharmony_ci list_addtail(&bo->head, &bucket->head); 1468bf215546Sopenharmony_ci } else { 1469bf215546Sopenharmony_ci bo_free(bo); 1470bf215546Sopenharmony_ci } 1471bf215546Sopenharmony_ci} 1472bf215546Sopenharmony_ci 1473bf215546Sopenharmony_civoid 1474bf215546Sopenharmony_ciiris_bo_unreference(struct iris_bo *bo) 1475bf215546Sopenharmony_ci{ 1476bf215546Sopenharmony_ci if (bo == NULL) 1477bf215546Sopenharmony_ci return; 1478bf215546Sopenharmony_ci 1479bf215546Sopenharmony_ci assert(p_atomic_read(&bo->refcount) > 0); 1480bf215546Sopenharmony_ci 1481bf215546Sopenharmony_ci if (atomic_add_unless(&bo->refcount, -1, 1)) { 1482bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1483bf215546Sopenharmony_ci struct timespec time; 1484bf215546Sopenharmony_ci 1485bf215546Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &time); 1486bf215546Sopenharmony_ci 1487bf215546Sopenharmony_ci if (bo->gem_handle == 0) { 1488bf215546Sopenharmony_ci pb_slab_free(get_slabs(bufmgr, bo->size), &bo->slab.entry); 1489bf215546Sopenharmony_ci } else { 1490bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1491bf215546Sopenharmony_ci 1492bf215546Sopenharmony_ci if (p_atomic_dec_zero(&bo->refcount)) { 1493bf215546Sopenharmony_ci bo_unreference_final(bo, time.tv_sec); 1494bf215546Sopenharmony_ci cleanup_bo_cache(bufmgr, time.tv_sec); 1495bf215546Sopenharmony_ci } 1496bf215546Sopenharmony_ci 1497bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1498bf215546Sopenharmony_ci } 1499bf215546Sopenharmony_ci } 1500bf215546Sopenharmony_ci} 1501bf215546Sopenharmony_ci 1502bf215546Sopenharmony_cistatic void 1503bf215546Sopenharmony_cibo_wait_with_stall_warning(struct util_debug_callback *dbg, 1504bf215546Sopenharmony_ci struct iris_bo *bo, 1505bf215546Sopenharmony_ci const char *action) 1506bf215546Sopenharmony_ci{ 1507bf215546Sopenharmony_ci bool busy = dbg && !bo->idle; 1508bf215546Sopenharmony_ci double elapsed = unlikely(busy) ? -get_time() : 0.0; 1509bf215546Sopenharmony_ci 1510bf215546Sopenharmony_ci iris_bo_wait_rendering(bo); 1511bf215546Sopenharmony_ci 1512bf215546Sopenharmony_ci if (unlikely(busy)) { 1513bf215546Sopenharmony_ci elapsed += get_time(); 1514bf215546Sopenharmony_ci if (elapsed > 1e-5) /* 0.01ms */ { 1515bf215546Sopenharmony_ci perf_debug(dbg, "%s a busy \"%s\" BO stalled and took %.03f ms.\n", 1516bf215546Sopenharmony_ci action, bo->name, elapsed * 1000); 1517bf215546Sopenharmony_ci } 1518bf215546Sopenharmony_ci } 1519bf215546Sopenharmony_ci} 1520bf215546Sopenharmony_ci 1521bf215546Sopenharmony_cistatic void 1522bf215546Sopenharmony_ciprint_flags(unsigned flags) 1523bf215546Sopenharmony_ci{ 1524bf215546Sopenharmony_ci if (flags & MAP_READ) 1525bf215546Sopenharmony_ci DBG("READ "); 1526bf215546Sopenharmony_ci if (flags & MAP_WRITE) 1527bf215546Sopenharmony_ci DBG("WRITE "); 1528bf215546Sopenharmony_ci if (flags & MAP_ASYNC) 1529bf215546Sopenharmony_ci DBG("ASYNC "); 1530bf215546Sopenharmony_ci if (flags & MAP_PERSISTENT) 1531bf215546Sopenharmony_ci DBG("PERSISTENT "); 1532bf215546Sopenharmony_ci if (flags & MAP_COHERENT) 1533bf215546Sopenharmony_ci DBG("COHERENT "); 1534bf215546Sopenharmony_ci if (flags & MAP_RAW) 1535bf215546Sopenharmony_ci DBG("RAW "); 1536bf215546Sopenharmony_ci DBG("\n"); 1537bf215546Sopenharmony_ci} 1538bf215546Sopenharmony_ci 1539bf215546Sopenharmony_cistatic void * 1540bf215546Sopenharmony_ciiris_bo_gem_mmap_legacy(struct util_debug_callback *dbg, struct iris_bo *bo) 1541bf215546Sopenharmony_ci{ 1542bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1543bf215546Sopenharmony_ci 1544bf215546Sopenharmony_ci assert(bufmgr->vram.size == 0); 1545bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1546bf215546Sopenharmony_ci assert(bo->real.mmap_mode == IRIS_MMAP_WB || 1547bf215546Sopenharmony_ci bo->real.mmap_mode == IRIS_MMAP_WC); 1548bf215546Sopenharmony_ci 1549bf215546Sopenharmony_ci struct drm_i915_gem_mmap mmap_arg = { 1550bf215546Sopenharmony_ci .handle = bo->gem_handle, 1551bf215546Sopenharmony_ci .size = bo->size, 1552bf215546Sopenharmony_ci .flags = bo->real.mmap_mode == IRIS_MMAP_WC ? I915_MMAP_WC : 0, 1553bf215546Sopenharmony_ci }; 1554bf215546Sopenharmony_ci 1555bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg); 1556bf215546Sopenharmony_ci if (ret != 0) { 1557bf215546Sopenharmony_ci DBG("%s:%d: Error mapping buffer %d (%s): %s .\n", 1558bf215546Sopenharmony_ci __FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno)); 1559bf215546Sopenharmony_ci return NULL; 1560bf215546Sopenharmony_ci } 1561bf215546Sopenharmony_ci void *map = (void *) (uintptr_t) mmap_arg.addr_ptr; 1562bf215546Sopenharmony_ci 1563bf215546Sopenharmony_ci return map; 1564bf215546Sopenharmony_ci} 1565bf215546Sopenharmony_ci 1566bf215546Sopenharmony_cistatic void * 1567bf215546Sopenharmony_ciiris_bo_gem_mmap_offset(struct util_debug_callback *dbg, struct iris_bo *bo) 1568bf215546Sopenharmony_ci{ 1569bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1570bf215546Sopenharmony_ci 1571bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1572bf215546Sopenharmony_ci 1573bf215546Sopenharmony_ci struct drm_i915_gem_mmap_offset mmap_arg = { 1574bf215546Sopenharmony_ci .handle = bo->gem_handle, 1575bf215546Sopenharmony_ci }; 1576bf215546Sopenharmony_ci 1577bf215546Sopenharmony_ci if (bufmgr->has_local_mem) { 1578bf215546Sopenharmony_ci /* On discrete memory platforms, we cannot control the mmap caching mode 1579bf215546Sopenharmony_ci * at mmap time. Instead, it's fixed when the object is created (this 1580bf215546Sopenharmony_ci * is a limitation of TTM). 1581bf215546Sopenharmony_ci * 1582bf215546Sopenharmony_ci * On DG1, our only currently enabled discrete platform, there is no 1583bf215546Sopenharmony_ci * control over what mode we get. For SMEM, we always get WB because 1584bf215546Sopenharmony_ci * it's fast (probably what we want) and when the device views SMEM 1585bf215546Sopenharmony_ci * across PCIe, it's always snooped. The only caching mode allowed by 1586bf215546Sopenharmony_ci * DG1 hardware for LMEM is WC. 1587bf215546Sopenharmony_ci */ 1588bf215546Sopenharmony_ci if (bo->real.heap != IRIS_HEAP_SYSTEM_MEMORY) 1589bf215546Sopenharmony_ci assert(bo->real.mmap_mode == IRIS_MMAP_WC); 1590bf215546Sopenharmony_ci else 1591bf215546Sopenharmony_ci assert(bo->real.mmap_mode == IRIS_MMAP_WB); 1592bf215546Sopenharmony_ci 1593bf215546Sopenharmony_ci mmap_arg.flags = I915_MMAP_OFFSET_FIXED; 1594bf215546Sopenharmony_ci } else { 1595bf215546Sopenharmony_ci /* Only integrated platforms get to select a mmap caching mode here */ 1596bf215546Sopenharmony_ci static const uint32_t mmap_offset_for_mode[] = { 1597bf215546Sopenharmony_ci [IRIS_MMAP_UC] = I915_MMAP_OFFSET_UC, 1598bf215546Sopenharmony_ci [IRIS_MMAP_WC] = I915_MMAP_OFFSET_WC, 1599bf215546Sopenharmony_ci [IRIS_MMAP_WB] = I915_MMAP_OFFSET_WB, 1600bf215546Sopenharmony_ci }; 1601bf215546Sopenharmony_ci assert(bo->real.mmap_mode != IRIS_MMAP_NONE); 1602bf215546Sopenharmony_ci assert(bo->real.mmap_mode < ARRAY_SIZE(mmap_offset_for_mode)); 1603bf215546Sopenharmony_ci mmap_arg.flags = mmap_offset_for_mode[bo->real.mmap_mode]; 1604bf215546Sopenharmony_ci } 1605bf215546Sopenharmony_ci 1606bf215546Sopenharmony_ci /* Get the fake offset back */ 1607bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &mmap_arg); 1608bf215546Sopenharmony_ci if (ret != 0) { 1609bf215546Sopenharmony_ci DBG("%s:%d: Error preparing buffer %d (%s): %s .\n", 1610bf215546Sopenharmony_ci __FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno)); 1611bf215546Sopenharmony_ci return NULL; 1612bf215546Sopenharmony_ci } 1613bf215546Sopenharmony_ci 1614bf215546Sopenharmony_ci /* And map it */ 1615bf215546Sopenharmony_ci void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 1616bf215546Sopenharmony_ci bufmgr->fd, mmap_arg.offset); 1617bf215546Sopenharmony_ci if (map == MAP_FAILED) { 1618bf215546Sopenharmony_ci DBG("%s:%d: Error mapping buffer %d (%s): %s .\n", 1619bf215546Sopenharmony_ci __FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno)); 1620bf215546Sopenharmony_ci return NULL; 1621bf215546Sopenharmony_ci } 1622bf215546Sopenharmony_ci 1623bf215546Sopenharmony_ci return map; 1624bf215546Sopenharmony_ci} 1625bf215546Sopenharmony_ci 1626bf215546Sopenharmony_civoid * 1627bf215546Sopenharmony_ciiris_bo_map(struct util_debug_callback *dbg, 1628bf215546Sopenharmony_ci struct iris_bo *bo, unsigned flags) 1629bf215546Sopenharmony_ci{ 1630bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1631bf215546Sopenharmony_ci void *map = NULL; 1632bf215546Sopenharmony_ci 1633bf215546Sopenharmony_ci if (bo->gem_handle == 0) { 1634bf215546Sopenharmony_ci struct iris_bo *real = iris_get_backing_bo(bo); 1635bf215546Sopenharmony_ci uint64_t offset = bo->address - real->address; 1636bf215546Sopenharmony_ci map = iris_bo_map(dbg, real, flags | MAP_ASYNC) + offset; 1637bf215546Sopenharmony_ci } else { 1638bf215546Sopenharmony_ci assert(bo->real.mmap_mode != IRIS_MMAP_NONE); 1639bf215546Sopenharmony_ci if (bo->real.mmap_mode == IRIS_MMAP_NONE) 1640bf215546Sopenharmony_ci return NULL; 1641bf215546Sopenharmony_ci 1642bf215546Sopenharmony_ci if (!bo->real.map) { 1643bf215546Sopenharmony_ci DBG("iris_bo_map: %d (%s)\n", bo->gem_handle, bo->name); 1644bf215546Sopenharmony_ci map = bufmgr->has_mmap_offset ? iris_bo_gem_mmap_offset(dbg, bo) 1645bf215546Sopenharmony_ci : iris_bo_gem_mmap_legacy(dbg, bo); 1646bf215546Sopenharmony_ci if (!map) { 1647bf215546Sopenharmony_ci return NULL; 1648bf215546Sopenharmony_ci } 1649bf215546Sopenharmony_ci 1650bf215546Sopenharmony_ci VG_DEFINED(map, bo->size); 1651bf215546Sopenharmony_ci 1652bf215546Sopenharmony_ci if (p_atomic_cmpxchg(&bo->real.map, NULL, map)) { 1653bf215546Sopenharmony_ci VG_NOACCESS(map, bo->size); 1654bf215546Sopenharmony_ci os_munmap(map, bo->size); 1655bf215546Sopenharmony_ci } 1656bf215546Sopenharmony_ci } 1657bf215546Sopenharmony_ci assert(bo->real.map); 1658bf215546Sopenharmony_ci map = bo->real.map; 1659bf215546Sopenharmony_ci } 1660bf215546Sopenharmony_ci 1661bf215546Sopenharmony_ci DBG("iris_bo_map: %d (%s) -> %p\n", 1662bf215546Sopenharmony_ci bo->gem_handle, bo->name, bo->real.map); 1663bf215546Sopenharmony_ci print_flags(flags); 1664bf215546Sopenharmony_ci 1665bf215546Sopenharmony_ci if (!(flags & MAP_ASYNC)) { 1666bf215546Sopenharmony_ci bo_wait_with_stall_warning(dbg, bo, "memory mapping"); 1667bf215546Sopenharmony_ci } 1668bf215546Sopenharmony_ci 1669bf215546Sopenharmony_ci return map; 1670bf215546Sopenharmony_ci} 1671bf215546Sopenharmony_ci 1672bf215546Sopenharmony_ci/** Waits for all GPU rendering with the object to have completed. */ 1673bf215546Sopenharmony_civoid 1674bf215546Sopenharmony_ciiris_bo_wait_rendering(struct iris_bo *bo) 1675bf215546Sopenharmony_ci{ 1676bf215546Sopenharmony_ci /* We require a kernel recent enough for WAIT_IOCTL support. 1677bf215546Sopenharmony_ci * See intel_init_bufmgr() 1678bf215546Sopenharmony_ci */ 1679bf215546Sopenharmony_ci iris_bo_wait(bo, -1); 1680bf215546Sopenharmony_ci} 1681bf215546Sopenharmony_ci 1682bf215546Sopenharmony_cistatic int 1683bf215546Sopenharmony_ciiris_bo_wait_gem(struct iris_bo *bo, int64_t timeout_ns) 1684bf215546Sopenharmony_ci{ 1685bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1686bf215546Sopenharmony_ci 1687bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1688bf215546Sopenharmony_ci struct drm_i915_gem_wait wait = { 1689bf215546Sopenharmony_ci .bo_handle = bo->gem_handle, 1690bf215546Sopenharmony_ci .timeout_ns = timeout_ns, 1691bf215546Sopenharmony_ci }; 1692bf215546Sopenharmony_ci 1693bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_WAIT, &wait); 1694bf215546Sopenharmony_ci if (ret != 0) 1695bf215546Sopenharmony_ci return -errno; 1696bf215546Sopenharmony_ci 1697bf215546Sopenharmony_ci return 0; 1698bf215546Sopenharmony_ci} 1699bf215546Sopenharmony_ci 1700bf215546Sopenharmony_ci/** 1701bf215546Sopenharmony_ci * Waits on a BO for the given amount of time. 1702bf215546Sopenharmony_ci * 1703bf215546Sopenharmony_ci * @bo: buffer object to wait for 1704bf215546Sopenharmony_ci * @timeout_ns: amount of time to wait in nanoseconds. 1705bf215546Sopenharmony_ci * If value is less than 0, an infinite wait will occur. 1706bf215546Sopenharmony_ci * 1707bf215546Sopenharmony_ci * Returns 0 if the wait was successful ie. the last batch referencing the 1708bf215546Sopenharmony_ci * object has completed within the allotted time. Otherwise some negative return 1709bf215546Sopenharmony_ci * value describes the error. Of particular interest is -ETIME when the wait has 1710bf215546Sopenharmony_ci * failed to yield the desired result. 1711bf215546Sopenharmony_ci * 1712bf215546Sopenharmony_ci * Similar to iris_bo_wait_rendering except a timeout parameter allows 1713bf215546Sopenharmony_ci * the operation to give up after a certain amount of time. Another subtle 1714bf215546Sopenharmony_ci * difference is the internal locking semantics are different (this variant does 1715bf215546Sopenharmony_ci * not hold the lock for the duration of the wait). This makes the wait subject 1716bf215546Sopenharmony_ci * to a larger userspace race window. 1717bf215546Sopenharmony_ci * 1718bf215546Sopenharmony_ci * The implementation shall wait until the object is no longer actively 1719bf215546Sopenharmony_ci * referenced within a batch buffer at the time of the call. The wait will 1720bf215546Sopenharmony_ci * not guarantee that the buffer is re-issued via another thread, or an flinked 1721bf215546Sopenharmony_ci * handle. Userspace must make sure this race does not occur if such precision 1722bf215546Sopenharmony_ci * is important. 1723bf215546Sopenharmony_ci * 1724bf215546Sopenharmony_ci * Note that some kernels have broken the infinite wait for negative values 1725bf215546Sopenharmony_ci * promise, upgrade to latest stable kernels if this is the case. 1726bf215546Sopenharmony_ci */ 1727bf215546Sopenharmony_ciint 1728bf215546Sopenharmony_ciiris_bo_wait(struct iris_bo *bo, int64_t timeout_ns) 1729bf215546Sopenharmony_ci{ 1730bf215546Sopenharmony_ci int ret; 1731bf215546Sopenharmony_ci 1732bf215546Sopenharmony_ci if (iris_bo_is_external(bo)) 1733bf215546Sopenharmony_ci ret = iris_bo_wait_gem(bo, timeout_ns); 1734bf215546Sopenharmony_ci else 1735bf215546Sopenharmony_ci ret = iris_bo_wait_syncobj(bo, timeout_ns); 1736bf215546Sopenharmony_ci 1737bf215546Sopenharmony_ci if (ret != 0) 1738bf215546Sopenharmony_ci return -errno; 1739bf215546Sopenharmony_ci 1740bf215546Sopenharmony_ci bo->idle = true; 1741bf215546Sopenharmony_ci 1742bf215546Sopenharmony_ci return ret; 1743bf215546Sopenharmony_ci} 1744bf215546Sopenharmony_ci 1745bf215546Sopenharmony_cistatic void 1746bf215546Sopenharmony_ciiris_bufmgr_destroy(struct iris_bufmgr *bufmgr) 1747bf215546Sopenharmony_ci{ 1748bf215546Sopenharmony_ci iris_destroy_border_color_pool(&bufmgr->border_color_pool); 1749bf215546Sopenharmony_ci 1750bf215546Sopenharmony_ci /* Free aux-map buffers */ 1751bf215546Sopenharmony_ci intel_aux_map_finish(bufmgr->aux_map_ctx); 1752bf215546Sopenharmony_ci 1753bf215546Sopenharmony_ci /* bufmgr will no longer try to free VMA entries in the aux-map */ 1754bf215546Sopenharmony_ci bufmgr->aux_map_ctx = NULL; 1755bf215546Sopenharmony_ci 1756bf215546Sopenharmony_ci for (int i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 1757bf215546Sopenharmony_ci if (bufmgr->bo_slabs[i].groups) 1758bf215546Sopenharmony_ci pb_slabs_deinit(&bufmgr->bo_slabs[i]); 1759bf215546Sopenharmony_ci } 1760bf215546Sopenharmony_ci 1761bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1762bf215546Sopenharmony_ci /* Free any cached buffer objects we were going to reuse */ 1763bf215546Sopenharmony_ci for (int i = 0; i < bufmgr->num_buckets; i++) { 1764bf215546Sopenharmony_ci struct bo_cache_bucket *bucket = &bufmgr->cache_bucket[i]; 1765bf215546Sopenharmony_ci 1766bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) { 1767bf215546Sopenharmony_ci list_del(&bo->head); 1768bf215546Sopenharmony_ci 1769bf215546Sopenharmony_ci bo_free(bo); 1770bf215546Sopenharmony_ci } 1771bf215546Sopenharmony_ci } 1772bf215546Sopenharmony_ci 1773bf215546Sopenharmony_ci for (int i = 0; i < bufmgr->num_local_buckets; i++) { 1774bf215546Sopenharmony_ci struct bo_cache_bucket *bucket = &bufmgr->local_cache_bucket[i]; 1775bf215546Sopenharmony_ci 1776bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) { 1777bf215546Sopenharmony_ci list_del(&bo->head); 1778bf215546Sopenharmony_ci 1779bf215546Sopenharmony_ci bo_free(bo); 1780bf215546Sopenharmony_ci } 1781bf215546Sopenharmony_ci } 1782bf215546Sopenharmony_ci 1783bf215546Sopenharmony_ci for (int i = 0; i < bufmgr->num_local_preferred_buckets; i++) { 1784bf215546Sopenharmony_ci struct bo_cache_bucket *bucket = &bufmgr->local_preferred_cache_bucket[i]; 1785bf215546Sopenharmony_ci 1786bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bucket->head, head) { 1787bf215546Sopenharmony_ci list_del(&bo->head); 1788bf215546Sopenharmony_ci 1789bf215546Sopenharmony_ci bo_free(bo); 1790bf215546Sopenharmony_ci } 1791bf215546Sopenharmony_ci } 1792bf215546Sopenharmony_ci 1793bf215546Sopenharmony_ci /* Close any buffer objects on the dead list. */ 1794bf215546Sopenharmony_ci list_for_each_entry_safe(struct iris_bo, bo, &bufmgr->zombie_list, head) { 1795bf215546Sopenharmony_ci list_del(&bo->head); 1796bf215546Sopenharmony_ci bo_close(bo); 1797bf215546Sopenharmony_ci } 1798bf215546Sopenharmony_ci 1799bf215546Sopenharmony_ci _mesa_hash_table_destroy(bufmgr->name_table, NULL); 1800bf215546Sopenharmony_ci _mesa_hash_table_destroy(bufmgr->handle_table, NULL); 1801bf215546Sopenharmony_ci 1802bf215546Sopenharmony_ci for (int z = 0; z < IRIS_MEMZONE_COUNT; z++) 1803bf215546Sopenharmony_ci util_vma_heap_finish(&bufmgr->vma_allocator[z]); 1804bf215546Sopenharmony_ci 1805bf215546Sopenharmony_ci close(bufmgr->fd); 1806bf215546Sopenharmony_ci 1807bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1808bf215546Sopenharmony_ci 1809bf215546Sopenharmony_ci simple_mtx_destroy(&bufmgr->lock); 1810bf215546Sopenharmony_ci simple_mtx_destroy(&bufmgr->bo_deps_lock); 1811bf215546Sopenharmony_ci 1812bf215546Sopenharmony_ci free(bufmgr); 1813bf215546Sopenharmony_ci} 1814bf215546Sopenharmony_ci 1815bf215546Sopenharmony_ciint 1816bf215546Sopenharmony_ciiris_gem_get_tiling(struct iris_bo *bo, uint32_t *tiling) 1817bf215546Sopenharmony_ci{ 1818bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1819bf215546Sopenharmony_ci 1820bf215546Sopenharmony_ci if (!bufmgr->has_tiling_uapi) { 1821bf215546Sopenharmony_ci *tiling = I915_TILING_NONE; 1822bf215546Sopenharmony_ci return 0; 1823bf215546Sopenharmony_ci } 1824bf215546Sopenharmony_ci 1825bf215546Sopenharmony_ci struct drm_i915_gem_get_tiling ti = { .handle = bo->gem_handle }; 1826bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_GET_TILING, &ti); 1827bf215546Sopenharmony_ci 1828bf215546Sopenharmony_ci if (ret) { 1829bf215546Sopenharmony_ci DBG("gem_get_tiling failed for BO %u: %s\n", 1830bf215546Sopenharmony_ci bo->gem_handle, strerror(errno)); 1831bf215546Sopenharmony_ci } 1832bf215546Sopenharmony_ci 1833bf215546Sopenharmony_ci *tiling = ti.tiling_mode; 1834bf215546Sopenharmony_ci 1835bf215546Sopenharmony_ci return ret; 1836bf215546Sopenharmony_ci} 1837bf215546Sopenharmony_ci 1838bf215546Sopenharmony_ciint 1839bf215546Sopenharmony_ciiris_gem_set_tiling(struct iris_bo *bo, const struct isl_surf *surf) 1840bf215546Sopenharmony_ci{ 1841bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1842bf215546Sopenharmony_ci uint32_t tiling_mode = isl_tiling_to_i915_tiling(surf->tiling); 1843bf215546Sopenharmony_ci int ret; 1844bf215546Sopenharmony_ci 1845bf215546Sopenharmony_ci /* If we can't do map_gtt, the set/get_tiling API isn't useful. And it's 1846bf215546Sopenharmony_ci * actually not supported by the kernel in those cases. 1847bf215546Sopenharmony_ci */ 1848bf215546Sopenharmony_ci if (!bufmgr->has_tiling_uapi) 1849bf215546Sopenharmony_ci return 0; 1850bf215546Sopenharmony_ci 1851bf215546Sopenharmony_ci /* GEM_SET_TILING is slightly broken and overwrites the input on the 1852bf215546Sopenharmony_ci * error path, so we have to open code intel_ioctl(). 1853bf215546Sopenharmony_ci */ 1854bf215546Sopenharmony_ci do { 1855bf215546Sopenharmony_ci struct drm_i915_gem_set_tiling set_tiling = { 1856bf215546Sopenharmony_ci .handle = bo->gem_handle, 1857bf215546Sopenharmony_ci .tiling_mode = tiling_mode, 1858bf215546Sopenharmony_ci .stride = surf->row_pitch_B, 1859bf215546Sopenharmony_ci }; 1860bf215546Sopenharmony_ci ret = ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling); 1861bf215546Sopenharmony_ci } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 1862bf215546Sopenharmony_ci 1863bf215546Sopenharmony_ci if (ret) { 1864bf215546Sopenharmony_ci DBG("gem_set_tiling failed for BO %u: %s\n", 1865bf215546Sopenharmony_ci bo->gem_handle, strerror(errno)); 1866bf215546Sopenharmony_ci } 1867bf215546Sopenharmony_ci 1868bf215546Sopenharmony_ci return ret; 1869bf215546Sopenharmony_ci} 1870bf215546Sopenharmony_ci 1871bf215546Sopenharmony_cistruct iris_bo * 1872bf215546Sopenharmony_ciiris_bo_import_dmabuf(struct iris_bufmgr *bufmgr, int prime_fd) 1873bf215546Sopenharmony_ci{ 1874bf215546Sopenharmony_ci uint32_t handle; 1875bf215546Sopenharmony_ci struct iris_bo *bo; 1876bf215546Sopenharmony_ci 1877bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1878bf215546Sopenharmony_ci int ret = drmPrimeFDToHandle(bufmgr->fd, prime_fd, &handle); 1879bf215546Sopenharmony_ci if (ret) { 1880bf215546Sopenharmony_ci DBG("import_dmabuf: failed to obtain handle from fd: %s\n", 1881bf215546Sopenharmony_ci strerror(errno)); 1882bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1883bf215546Sopenharmony_ci return NULL; 1884bf215546Sopenharmony_ci } 1885bf215546Sopenharmony_ci 1886bf215546Sopenharmony_ci /* 1887bf215546Sopenharmony_ci * See if the kernel has already returned this buffer to us. Just as 1888bf215546Sopenharmony_ci * for named buffers, we must not create two bo's pointing at the same 1889bf215546Sopenharmony_ci * kernel object 1890bf215546Sopenharmony_ci */ 1891bf215546Sopenharmony_ci bo = find_and_ref_external_bo(bufmgr->handle_table, handle); 1892bf215546Sopenharmony_ci if (bo) 1893bf215546Sopenharmony_ci goto out; 1894bf215546Sopenharmony_ci 1895bf215546Sopenharmony_ci bo = bo_calloc(); 1896bf215546Sopenharmony_ci if (!bo) 1897bf215546Sopenharmony_ci goto out; 1898bf215546Sopenharmony_ci 1899bf215546Sopenharmony_ci p_atomic_set(&bo->refcount, 1); 1900bf215546Sopenharmony_ci 1901bf215546Sopenharmony_ci /* Determine size of bo. The fd-to-handle ioctl really should 1902bf215546Sopenharmony_ci * return the size, but it doesn't. If we have kernel 3.12 or 1903bf215546Sopenharmony_ci * later, we can lseek on the prime fd to get the size. Older 1904bf215546Sopenharmony_ci * kernels will just fail, in which case we fall back to the 1905bf215546Sopenharmony_ci * provided (estimated or guess size). */ 1906bf215546Sopenharmony_ci ret = lseek(prime_fd, 0, SEEK_END); 1907bf215546Sopenharmony_ci if (ret != -1) 1908bf215546Sopenharmony_ci bo->size = ret; 1909bf215546Sopenharmony_ci 1910bf215546Sopenharmony_ci bo->bufmgr = bufmgr; 1911bf215546Sopenharmony_ci bo->name = "prime"; 1912bf215546Sopenharmony_ci bo->real.reusable = false; 1913bf215546Sopenharmony_ci bo->real.imported = true; 1914bf215546Sopenharmony_ci bo->real.mmap_mode = IRIS_MMAP_NONE; 1915bf215546Sopenharmony_ci bo->real.kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED; 1916bf215546Sopenharmony_ci bo->gem_handle = handle; 1917bf215546Sopenharmony_ci 1918bf215546Sopenharmony_ci /* From the Bspec, Memory Compression - Gfx12: 1919bf215546Sopenharmony_ci * 1920bf215546Sopenharmony_ci * The base address for the surface has to be 64K page aligned and the 1921bf215546Sopenharmony_ci * surface is expected to be padded in the virtual domain to be 4 4K 1922bf215546Sopenharmony_ci * pages. 1923bf215546Sopenharmony_ci * 1924bf215546Sopenharmony_ci * The dmabuf may contain a compressed surface. Align the BO to 64KB just 1925bf215546Sopenharmony_ci * in case. We always align to 64KB even on platforms where we don't need 1926bf215546Sopenharmony_ci * to, because it's a fairly reasonable thing to do anyway. 1927bf215546Sopenharmony_ci */ 1928bf215546Sopenharmony_ci bo->address = vma_alloc(bufmgr, IRIS_MEMZONE_OTHER, bo->size, 64 * 1024); 1929bf215546Sopenharmony_ci 1930bf215546Sopenharmony_ci if (bo->address == 0ull) { 1931bf215546Sopenharmony_ci bo_free(bo); 1932bf215546Sopenharmony_ci bo = NULL; 1933bf215546Sopenharmony_ci goto out; 1934bf215546Sopenharmony_ci } 1935bf215546Sopenharmony_ci 1936bf215546Sopenharmony_ci _mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo); 1937bf215546Sopenharmony_ci 1938bf215546Sopenharmony_ciout: 1939bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1940bf215546Sopenharmony_ci return bo; 1941bf215546Sopenharmony_ci} 1942bf215546Sopenharmony_ci 1943bf215546Sopenharmony_cistatic void 1944bf215546Sopenharmony_ciiris_bo_mark_exported_locked(struct iris_bo *bo) 1945bf215546Sopenharmony_ci{ 1946bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1947bf215546Sopenharmony_ci 1948bf215546Sopenharmony_ci /* We cannot export suballocated BOs. */ 1949bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1950bf215546Sopenharmony_ci simple_mtx_assert_locked(&bufmgr->lock); 1951bf215546Sopenharmony_ci 1952bf215546Sopenharmony_ci if (!iris_bo_is_external(bo)) 1953bf215546Sopenharmony_ci _mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo); 1954bf215546Sopenharmony_ci 1955bf215546Sopenharmony_ci if (!bo->real.exported) { 1956bf215546Sopenharmony_ci /* If a BO is going to be used externally, it could be sent to the 1957bf215546Sopenharmony_ci * display HW. So make sure our CPU mappings don't assume cache 1958bf215546Sopenharmony_ci * coherency since display is outside that cache. 1959bf215546Sopenharmony_ci */ 1960bf215546Sopenharmony_ci bo->real.exported = true; 1961bf215546Sopenharmony_ci bo->real.reusable = false; 1962bf215546Sopenharmony_ci } 1963bf215546Sopenharmony_ci} 1964bf215546Sopenharmony_ci 1965bf215546Sopenharmony_civoid 1966bf215546Sopenharmony_ciiris_bo_mark_exported(struct iris_bo *bo) 1967bf215546Sopenharmony_ci{ 1968bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1969bf215546Sopenharmony_ci 1970bf215546Sopenharmony_ci /* We cannot export suballocated BOs. */ 1971bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1972bf215546Sopenharmony_ci 1973bf215546Sopenharmony_ci if (bo->real.exported) { 1974bf215546Sopenharmony_ci assert(!bo->real.reusable); 1975bf215546Sopenharmony_ci return; 1976bf215546Sopenharmony_ci } 1977bf215546Sopenharmony_ci 1978bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 1979bf215546Sopenharmony_ci iris_bo_mark_exported_locked(bo); 1980bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 1981bf215546Sopenharmony_ci} 1982bf215546Sopenharmony_ci 1983bf215546Sopenharmony_ciint 1984bf215546Sopenharmony_ciiris_bo_export_dmabuf(struct iris_bo *bo, int *prime_fd) 1985bf215546Sopenharmony_ci{ 1986bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 1987bf215546Sopenharmony_ci 1988bf215546Sopenharmony_ci /* We cannot export suballocated BOs. */ 1989bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 1990bf215546Sopenharmony_ci 1991bf215546Sopenharmony_ci iris_bo_mark_exported(bo); 1992bf215546Sopenharmony_ci 1993bf215546Sopenharmony_ci if (drmPrimeHandleToFD(bufmgr->fd, bo->gem_handle, 1994bf215546Sopenharmony_ci DRM_CLOEXEC | DRM_RDWR, prime_fd) != 0) 1995bf215546Sopenharmony_ci return -errno; 1996bf215546Sopenharmony_ci 1997bf215546Sopenharmony_ci return 0; 1998bf215546Sopenharmony_ci} 1999bf215546Sopenharmony_ci 2000bf215546Sopenharmony_ciuint32_t 2001bf215546Sopenharmony_ciiris_bo_export_gem_handle(struct iris_bo *bo) 2002bf215546Sopenharmony_ci{ 2003bf215546Sopenharmony_ci /* We cannot export suballocated BOs. */ 2004bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 2005bf215546Sopenharmony_ci 2006bf215546Sopenharmony_ci iris_bo_mark_exported(bo); 2007bf215546Sopenharmony_ci 2008bf215546Sopenharmony_ci return bo->gem_handle; 2009bf215546Sopenharmony_ci} 2010bf215546Sopenharmony_ci 2011bf215546Sopenharmony_ciint 2012bf215546Sopenharmony_ciiris_bo_flink(struct iris_bo *bo, uint32_t *name) 2013bf215546Sopenharmony_ci{ 2014bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 2015bf215546Sopenharmony_ci 2016bf215546Sopenharmony_ci /* We cannot export suballocated BOs. */ 2017bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 2018bf215546Sopenharmony_ci 2019bf215546Sopenharmony_ci if (!bo->real.global_name) { 2020bf215546Sopenharmony_ci struct drm_gem_flink flink = { .handle = bo->gem_handle }; 2021bf215546Sopenharmony_ci 2022bf215546Sopenharmony_ci if (intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_FLINK, &flink)) 2023bf215546Sopenharmony_ci return -errno; 2024bf215546Sopenharmony_ci 2025bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 2026bf215546Sopenharmony_ci if (!bo->real.global_name) { 2027bf215546Sopenharmony_ci iris_bo_mark_exported_locked(bo); 2028bf215546Sopenharmony_ci bo->real.global_name = flink.name; 2029bf215546Sopenharmony_ci _mesa_hash_table_insert(bufmgr->name_table, &bo->real.global_name, bo); 2030bf215546Sopenharmony_ci } 2031bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 2032bf215546Sopenharmony_ci } 2033bf215546Sopenharmony_ci 2034bf215546Sopenharmony_ci *name = bo->real.global_name; 2035bf215546Sopenharmony_ci return 0; 2036bf215546Sopenharmony_ci} 2037bf215546Sopenharmony_ci 2038bf215546Sopenharmony_ciint 2039bf215546Sopenharmony_ciiris_bo_export_gem_handle_for_device(struct iris_bo *bo, int drm_fd, 2040bf215546Sopenharmony_ci uint32_t *out_handle) 2041bf215546Sopenharmony_ci{ 2042bf215546Sopenharmony_ci /* We cannot export suballocated BOs. */ 2043bf215546Sopenharmony_ci assert(iris_bo_is_real(bo)); 2044bf215546Sopenharmony_ci 2045bf215546Sopenharmony_ci /* Only add the new GEM handle to the list of export if it belongs to a 2046bf215546Sopenharmony_ci * different GEM device. Otherwise we might close the same buffer multiple 2047bf215546Sopenharmony_ci * times. 2048bf215546Sopenharmony_ci */ 2049bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = bo->bufmgr; 2050bf215546Sopenharmony_ci int ret = os_same_file_description(drm_fd, bufmgr->fd); 2051bf215546Sopenharmony_ci WARN_ONCE(ret < 0, 2052bf215546Sopenharmony_ci "Kernel has no file descriptor comparison support: %s\n", 2053bf215546Sopenharmony_ci strerror(errno)); 2054bf215546Sopenharmony_ci if (ret == 0) { 2055bf215546Sopenharmony_ci *out_handle = iris_bo_export_gem_handle(bo); 2056bf215546Sopenharmony_ci return 0; 2057bf215546Sopenharmony_ci } 2058bf215546Sopenharmony_ci 2059bf215546Sopenharmony_ci struct bo_export *export = calloc(1, sizeof(*export)); 2060bf215546Sopenharmony_ci if (!export) 2061bf215546Sopenharmony_ci return -ENOMEM; 2062bf215546Sopenharmony_ci 2063bf215546Sopenharmony_ci export->drm_fd = drm_fd; 2064bf215546Sopenharmony_ci 2065bf215546Sopenharmony_ci int dmabuf_fd = -1; 2066bf215546Sopenharmony_ci int err = iris_bo_export_dmabuf(bo, &dmabuf_fd); 2067bf215546Sopenharmony_ci if (err) { 2068bf215546Sopenharmony_ci free(export); 2069bf215546Sopenharmony_ci return err; 2070bf215546Sopenharmony_ci } 2071bf215546Sopenharmony_ci 2072bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 2073bf215546Sopenharmony_ci err = drmPrimeFDToHandle(drm_fd, dmabuf_fd, &export->gem_handle); 2074bf215546Sopenharmony_ci close(dmabuf_fd); 2075bf215546Sopenharmony_ci if (err) { 2076bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 2077bf215546Sopenharmony_ci free(export); 2078bf215546Sopenharmony_ci return err; 2079bf215546Sopenharmony_ci } 2080bf215546Sopenharmony_ci 2081bf215546Sopenharmony_ci bool found = false; 2082bf215546Sopenharmony_ci list_for_each_entry(struct bo_export, iter, &bo->real.exports, link) { 2083bf215546Sopenharmony_ci if (iter->drm_fd != drm_fd) 2084bf215546Sopenharmony_ci continue; 2085bf215546Sopenharmony_ci /* Here we assume that for a given DRM fd, we'll always get back the 2086bf215546Sopenharmony_ci * same GEM handle for a given buffer. 2087bf215546Sopenharmony_ci */ 2088bf215546Sopenharmony_ci assert(iter->gem_handle == export->gem_handle); 2089bf215546Sopenharmony_ci free(export); 2090bf215546Sopenharmony_ci export = iter; 2091bf215546Sopenharmony_ci found = true; 2092bf215546Sopenharmony_ci break; 2093bf215546Sopenharmony_ci } 2094bf215546Sopenharmony_ci if (!found) 2095bf215546Sopenharmony_ci list_addtail(&export->link, &bo->real.exports); 2096bf215546Sopenharmony_ci 2097bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 2098bf215546Sopenharmony_ci 2099bf215546Sopenharmony_ci *out_handle = export->gem_handle; 2100bf215546Sopenharmony_ci 2101bf215546Sopenharmony_ci return 0; 2102bf215546Sopenharmony_ci} 2103bf215546Sopenharmony_ci 2104bf215546Sopenharmony_cistatic void 2105bf215546Sopenharmony_ciadd_bucket(struct iris_bufmgr *bufmgr, int size, enum iris_heap heap) 2106bf215546Sopenharmony_ci{ 2107bf215546Sopenharmony_ci int *num_buckets; 2108bf215546Sopenharmony_ci struct bo_cache_bucket *buckets; 2109bf215546Sopenharmony_ci bucket_info_for_heap(bufmgr, heap, &buckets, &num_buckets); 2110bf215546Sopenharmony_ci 2111bf215546Sopenharmony_ci unsigned int i = (*num_buckets)++; 2112bf215546Sopenharmony_ci 2113bf215546Sopenharmony_ci list_inithead(&buckets[i].head); 2114bf215546Sopenharmony_ci buckets[i].size = size; 2115bf215546Sopenharmony_ci 2116bf215546Sopenharmony_ci assert(bucket_for_size(bufmgr, size, heap) == &buckets[i]); 2117bf215546Sopenharmony_ci assert(bucket_for_size(bufmgr, size - 2048, heap) == &buckets[i]); 2118bf215546Sopenharmony_ci assert(bucket_for_size(bufmgr, size + 1, heap) != &buckets[i]); 2119bf215546Sopenharmony_ci} 2120bf215546Sopenharmony_ci 2121bf215546Sopenharmony_cistatic void 2122bf215546Sopenharmony_ciinit_cache_buckets(struct iris_bufmgr *bufmgr, enum iris_heap heap) 2123bf215546Sopenharmony_ci{ 2124bf215546Sopenharmony_ci uint64_t size, cache_max_size = 64 * 1024 * 1024; 2125bf215546Sopenharmony_ci 2126bf215546Sopenharmony_ci /* OK, so power of two buckets was too wasteful of memory. 2127bf215546Sopenharmony_ci * Give 3 other sizes between each power of two, to hopefully 2128bf215546Sopenharmony_ci * cover things accurately enough. (The alternative is 2129bf215546Sopenharmony_ci * probably to just go for exact matching of sizes, and assume 2130bf215546Sopenharmony_ci * that for things like composited window resize the tiled 2131bf215546Sopenharmony_ci * width/height alignment and rounding of sizes to pages will 2132bf215546Sopenharmony_ci * get us useful cache hit rates anyway) 2133bf215546Sopenharmony_ci */ 2134bf215546Sopenharmony_ci add_bucket(bufmgr, PAGE_SIZE, heap); 2135bf215546Sopenharmony_ci add_bucket(bufmgr, PAGE_SIZE * 2, heap); 2136bf215546Sopenharmony_ci add_bucket(bufmgr, PAGE_SIZE * 3, heap); 2137bf215546Sopenharmony_ci 2138bf215546Sopenharmony_ci /* Initialize the linked lists for BO reuse cache. */ 2139bf215546Sopenharmony_ci for (size = 4 * PAGE_SIZE; size <= cache_max_size; size *= 2) { 2140bf215546Sopenharmony_ci add_bucket(bufmgr, size, heap); 2141bf215546Sopenharmony_ci 2142bf215546Sopenharmony_ci add_bucket(bufmgr, size + size * 1 / 4, heap); 2143bf215546Sopenharmony_ci add_bucket(bufmgr, size + size * 2 / 4, heap); 2144bf215546Sopenharmony_ci add_bucket(bufmgr, size + size * 3 / 4, heap); 2145bf215546Sopenharmony_ci } 2146bf215546Sopenharmony_ci} 2147bf215546Sopenharmony_ci 2148bf215546Sopenharmony_civoid 2149bf215546Sopenharmony_ciiris_hw_context_set_unrecoverable(struct iris_bufmgr *bufmgr, 2150bf215546Sopenharmony_ci uint32_t ctx_id) 2151bf215546Sopenharmony_ci{ 2152bf215546Sopenharmony_ci /* Upon declaring a GPU hang, the kernel will zap the guilty context 2153bf215546Sopenharmony_ci * back to the default logical HW state and attempt to continue on to 2154bf215546Sopenharmony_ci * our next submitted batchbuffer. However, our render batches assume 2155bf215546Sopenharmony_ci * the previous GPU state is preserved, and only emit commands needed 2156bf215546Sopenharmony_ci * to incrementally change that state. In particular, we inherit the 2157bf215546Sopenharmony_ci * STATE_BASE_ADDRESS and PIPELINE_SELECT settings, which are critical. 2158bf215546Sopenharmony_ci * With default base addresses, our next batches will almost certainly 2159bf215546Sopenharmony_ci * cause more GPU hangs, leading to repeated hangs until we're banned 2160bf215546Sopenharmony_ci * or the machine is dead. 2161bf215546Sopenharmony_ci * 2162bf215546Sopenharmony_ci * Here we tell the kernel not to attempt to recover our context but 2163bf215546Sopenharmony_ci * immediately (on the next batchbuffer submission) report that the 2164bf215546Sopenharmony_ci * context is lost, and we will do the recovery ourselves. Ideally, 2165bf215546Sopenharmony_ci * we'll have two lost batches instead of a continual stream of hangs. 2166bf215546Sopenharmony_ci */ 2167bf215546Sopenharmony_ci struct drm_i915_gem_context_param p = { 2168bf215546Sopenharmony_ci .ctx_id = ctx_id, 2169bf215546Sopenharmony_ci .param = I915_CONTEXT_PARAM_RECOVERABLE, 2170bf215546Sopenharmony_ci .value = false, 2171bf215546Sopenharmony_ci }; 2172bf215546Sopenharmony_ci intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p); 2173bf215546Sopenharmony_ci} 2174bf215546Sopenharmony_ci 2175bf215546Sopenharmony_civoid 2176bf215546Sopenharmony_ciiris_hw_context_set_vm_id(struct iris_bufmgr *bufmgr, uint32_t ctx_id) 2177bf215546Sopenharmony_ci{ 2178bf215546Sopenharmony_ci if (!bufmgr->use_global_vm) 2179bf215546Sopenharmony_ci return; 2180bf215546Sopenharmony_ci 2181bf215546Sopenharmony_ci struct drm_i915_gem_context_param p = { 2182bf215546Sopenharmony_ci .ctx_id = ctx_id, 2183bf215546Sopenharmony_ci .param = I915_CONTEXT_PARAM_VM, 2184bf215546Sopenharmony_ci .value = bufmgr->global_vm_id, 2185bf215546Sopenharmony_ci }; 2186bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p); 2187bf215546Sopenharmony_ci if (ret != 0) { 2188bf215546Sopenharmony_ci DBG("DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM failed: %s\n", 2189bf215546Sopenharmony_ci strerror(errno)); 2190bf215546Sopenharmony_ci } 2191bf215546Sopenharmony_ci} 2192bf215546Sopenharmony_ci 2193bf215546Sopenharmony_ciuint32_t 2194bf215546Sopenharmony_ciiris_create_hw_context(struct iris_bufmgr *bufmgr) 2195bf215546Sopenharmony_ci{ 2196bf215546Sopenharmony_ci struct drm_i915_gem_context_create create = { }; 2197bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create); 2198bf215546Sopenharmony_ci if (ret != 0) { 2199bf215546Sopenharmony_ci DBG("DRM_IOCTL_I915_GEM_CONTEXT_CREATE failed: %s\n", strerror(errno)); 2200bf215546Sopenharmony_ci return 0; 2201bf215546Sopenharmony_ci } 2202bf215546Sopenharmony_ci 2203bf215546Sopenharmony_ci iris_hw_context_set_unrecoverable(bufmgr, create.ctx_id); 2204bf215546Sopenharmony_ci iris_hw_context_set_vm_id(bufmgr, create.ctx_id); 2205bf215546Sopenharmony_ci 2206bf215546Sopenharmony_ci return create.ctx_id; 2207bf215546Sopenharmony_ci} 2208bf215546Sopenharmony_ci 2209bf215546Sopenharmony_ciint 2210bf215546Sopenharmony_ciiris_kernel_context_get_priority(struct iris_bufmgr *bufmgr, uint32_t ctx_id) 2211bf215546Sopenharmony_ci{ 2212bf215546Sopenharmony_ci struct drm_i915_gem_context_param p = { 2213bf215546Sopenharmony_ci .ctx_id = ctx_id, 2214bf215546Sopenharmony_ci .param = I915_CONTEXT_PARAM_PRIORITY, 2215bf215546Sopenharmony_ci }; 2216bf215546Sopenharmony_ci intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p); 2217bf215546Sopenharmony_ci return p.value; /* on error, return 0 i.e. default priority */ 2218bf215546Sopenharmony_ci} 2219bf215546Sopenharmony_ci 2220bf215546Sopenharmony_ciint 2221bf215546Sopenharmony_ciiris_hw_context_set_priority(struct iris_bufmgr *bufmgr, 2222bf215546Sopenharmony_ci uint32_t ctx_id, 2223bf215546Sopenharmony_ci int priority) 2224bf215546Sopenharmony_ci{ 2225bf215546Sopenharmony_ci struct drm_i915_gem_context_param p = { 2226bf215546Sopenharmony_ci .ctx_id = ctx_id, 2227bf215546Sopenharmony_ci .param = I915_CONTEXT_PARAM_PRIORITY, 2228bf215546Sopenharmony_ci .value = priority, 2229bf215546Sopenharmony_ci }; 2230bf215546Sopenharmony_ci int err; 2231bf215546Sopenharmony_ci 2232bf215546Sopenharmony_ci err = 0; 2233bf215546Sopenharmony_ci if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p)) 2234bf215546Sopenharmony_ci err = -errno; 2235bf215546Sopenharmony_ci 2236bf215546Sopenharmony_ci return err; 2237bf215546Sopenharmony_ci} 2238bf215546Sopenharmony_ci 2239bf215546Sopenharmony_ciuint32_t 2240bf215546Sopenharmony_ciiris_clone_hw_context(struct iris_bufmgr *bufmgr, uint32_t ctx_id) 2241bf215546Sopenharmony_ci{ 2242bf215546Sopenharmony_ci uint32_t new_ctx = iris_create_hw_context(bufmgr); 2243bf215546Sopenharmony_ci 2244bf215546Sopenharmony_ci if (new_ctx) { 2245bf215546Sopenharmony_ci int priority = iris_kernel_context_get_priority(bufmgr, ctx_id); 2246bf215546Sopenharmony_ci iris_hw_context_set_priority(bufmgr, new_ctx, priority); 2247bf215546Sopenharmony_ci } 2248bf215546Sopenharmony_ci 2249bf215546Sopenharmony_ci return new_ctx; 2250bf215546Sopenharmony_ci} 2251bf215546Sopenharmony_ci 2252bf215546Sopenharmony_civoid 2253bf215546Sopenharmony_ciiris_destroy_kernel_context(struct iris_bufmgr *bufmgr, uint32_t ctx_id) 2254bf215546Sopenharmony_ci{ 2255bf215546Sopenharmony_ci struct drm_i915_gem_context_destroy d = { .ctx_id = ctx_id }; 2256bf215546Sopenharmony_ci 2257bf215546Sopenharmony_ci if (ctx_id != 0 && 2258bf215546Sopenharmony_ci intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &d) != 0) { 2259bf215546Sopenharmony_ci fprintf(stderr, "DRM_IOCTL_I915_GEM_CONTEXT_DESTROY failed: %s\n", 2260bf215546Sopenharmony_ci strerror(errno)); 2261bf215546Sopenharmony_ci } 2262bf215546Sopenharmony_ci} 2263bf215546Sopenharmony_ci 2264bf215546Sopenharmony_ciint 2265bf215546Sopenharmony_ciiris_reg_read(struct iris_bufmgr *bufmgr, uint32_t offset, uint64_t *result) 2266bf215546Sopenharmony_ci{ 2267bf215546Sopenharmony_ci struct drm_i915_reg_read reg_read = { .offset = offset }; 2268bf215546Sopenharmony_ci int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_REG_READ, ®_read); 2269bf215546Sopenharmony_ci 2270bf215546Sopenharmony_ci *result = reg_read.val; 2271bf215546Sopenharmony_ci return ret; 2272bf215546Sopenharmony_ci} 2273bf215546Sopenharmony_ci 2274bf215546Sopenharmony_cistatic struct intel_buffer * 2275bf215546Sopenharmony_ciintel_aux_map_buffer_alloc(void *driver_ctx, uint32_t size) 2276bf215546Sopenharmony_ci{ 2277bf215546Sopenharmony_ci struct intel_buffer *buf = malloc(sizeof(struct intel_buffer)); 2278bf215546Sopenharmony_ci if (!buf) 2279bf215546Sopenharmony_ci return NULL; 2280bf215546Sopenharmony_ci 2281bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = (struct iris_bufmgr *)driver_ctx; 2282bf215546Sopenharmony_ci 2283bf215546Sopenharmony_ci unsigned int page_size = getpagesize(); 2284bf215546Sopenharmony_ci size = MAX2(ALIGN(size, page_size), page_size); 2285bf215546Sopenharmony_ci 2286bf215546Sopenharmony_ci struct iris_bo *bo = alloc_fresh_bo(bufmgr, size, 0); 2287bf215546Sopenharmony_ci if (!bo) { 2288bf215546Sopenharmony_ci free(buf); 2289bf215546Sopenharmony_ci return NULL; 2290bf215546Sopenharmony_ci } 2291bf215546Sopenharmony_ci 2292bf215546Sopenharmony_ci simple_mtx_lock(&bufmgr->lock); 2293bf215546Sopenharmony_ci 2294bf215546Sopenharmony_ci bo->address = vma_alloc(bufmgr, IRIS_MEMZONE_OTHER, bo->size, 64 * 1024); 2295bf215546Sopenharmony_ci if (bo->address == 0ull) { 2296bf215546Sopenharmony_ci free(buf); 2297bf215546Sopenharmony_ci bo_free(bo); 2298bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 2299bf215546Sopenharmony_ci return NULL; 2300bf215546Sopenharmony_ci } 2301bf215546Sopenharmony_ci 2302bf215546Sopenharmony_ci simple_mtx_unlock(&bufmgr->lock); 2303bf215546Sopenharmony_ci 2304bf215546Sopenharmony_ci bo->name = "aux-map"; 2305bf215546Sopenharmony_ci p_atomic_set(&bo->refcount, 1); 2306bf215546Sopenharmony_ci bo->index = -1; 2307bf215546Sopenharmony_ci bo->real.kflags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED | 2308bf215546Sopenharmony_ci EXEC_OBJECT_CAPTURE; 2309bf215546Sopenharmony_ci bo->real.mmap_mode = 2310bf215546Sopenharmony_ci bo->real.heap != IRIS_HEAP_SYSTEM_MEMORY ? IRIS_MMAP_WC : IRIS_MMAP_WB; 2311bf215546Sopenharmony_ci 2312bf215546Sopenharmony_ci buf->driver_bo = bo; 2313bf215546Sopenharmony_ci buf->gpu = bo->address; 2314bf215546Sopenharmony_ci buf->gpu_end = buf->gpu + bo->size; 2315bf215546Sopenharmony_ci buf->map = iris_bo_map(NULL, bo, MAP_WRITE | MAP_RAW); 2316bf215546Sopenharmony_ci return buf; 2317bf215546Sopenharmony_ci} 2318bf215546Sopenharmony_ci 2319bf215546Sopenharmony_cistatic void 2320bf215546Sopenharmony_ciintel_aux_map_buffer_free(void *driver_ctx, struct intel_buffer *buffer) 2321bf215546Sopenharmony_ci{ 2322bf215546Sopenharmony_ci iris_bo_unreference((struct iris_bo*)buffer->driver_bo); 2323bf215546Sopenharmony_ci free(buffer); 2324bf215546Sopenharmony_ci} 2325bf215546Sopenharmony_ci 2326bf215546Sopenharmony_cistatic struct intel_mapped_pinned_buffer_alloc aux_map_allocator = { 2327bf215546Sopenharmony_ci .alloc = intel_aux_map_buffer_alloc, 2328bf215546Sopenharmony_ci .free = intel_aux_map_buffer_free, 2329bf215546Sopenharmony_ci}; 2330bf215546Sopenharmony_ci 2331bf215546Sopenharmony_cistatic int 2332bf215546Sopenharmony_cigem_param(int fd, int name) 2333bf215546Sopenharmony_ci{ 2334bf215546Sopenharmony_ci int v = -1; /* No param uses (yet) the sign bit, reserve it for errors */ 2335bf215546Sopenharmony_ci 2336bf215546Sopenharmony_ci struct drm_i915_getparam gp = { .param = name, .value = &v }; 2337bf215546Sopenharmony_ci if (intel_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 2338bf215546Sopenharmony_ci return -1; 2339bf215546Sopenharmony_ci 2340bf215546Sopenharmony_ci return v; 2341bf215546Sopenharmony_ci} 2342bf215546Sopenharmony_ci 2343bf215546Sopenharmony_cistatic bool 2344bf215546Sopenharmony_ciiris_bufmgr_get_meminfo(struct iris_bufmgr *bufmgr, 2345bf215546Sopenharmony_ci struct intel_device_info *devinfo) 2346bf215546Sopenharmony_ci{ 2347bf215546Sopenharmony_ci bufmgr->sys.region.memory_class = devinfo->mem.sram.mem_class; 2348bf215546Sopenharmony_ci bufmgr->sys.region.memory_instance = devinfo->mem.sram.mem_instance; 2349bf215546Sopenharmony_ci bufmgr->sys.size = devinfo->mem.sram.mappable.size; 2350bf215546Sopenharmony_ci 2351bf215546Sopenharmony_ci bufmgr->vram.region.memory_class = devinfo->mem.vram.mem_class; 2352bf215546Sopenharmony_ci bufmgr->vram.region.memory_instance = devinfo->mem.vram.mem_instance; 2353bf215546Sopenharmony_ci bufmgr->vram.size = devinfo->mem.vram.mappable.size; 2354bf215546Sopenharmony_ci 2355bf215546Sopenharmony_ci return true; 2356bf215546Sopenharmony_ci} 2357bf215546Sopenharmony_ci 2358bf215546Sopenharmony_cistatic void 2359bf215546Sopenharmony_ciiris_bufmgr_init_global_vm(int fd, struct iris_bufmgr *bufmgr) 2360bf215546Sopenharmony_ci{ 2361bf215546Sopenharmony_ci struct drm_i915_gem_context_param gcp = { 2362bf215546Sopenharmony_ci .ctx_id = 0, 2363bf215546Sopenharmony_ci .param = I915_CONTEXT_PARAM_VM, 2364bf215546Sopenharmony_ci }; 2365bf215546Sopenharmony_ci 2366bf215546Sopenharmony_ci if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &gcp)) { 2367bf215546Sopenharmony_ci bufmgr->use_global_vm = false; 2368bf215546Sopenharmony_ci bufmgr->global_vm_id = 0; 2369bf215546Sopenharmony_ci } else { 2370bf215546Sopenharmony_ci bufmgr->use_global_vm = true; 2371bf215546Sopenharmony_ci bufmgr->global_vm_id = gcp.value; 2372bf215546Sopenharmony_ci } 2373bf215546Sopenharmony_ci} 2374bf215546Sopenharmony_ci 2375bf215546Sopenharmony_ci/** 2376bf215546Sopenharmony_ci * Initializes the GEM buffer manager, which uses the kernel to allocate, map, 2377bf215546Sopenharmony_ci * and manage map buffer objections. 2378bf215546Sopenharmony_ci * 2379bf215546Sopenharmony_ci * \param fd File descriptor of the opened DRM device. 2380bf215546Sopenharmony_ci */ 2381bf215546Sopenharmony_cistatic struct iris_bufmgr * 2382bf215546Sopenharmony_ciiris_bufmgr_create(struct intel_device_info *devinfo, int fd, bool bo_reuse) 2383bf215546Sopenharmony_ci{ 2384bf215546Sopenharmony_ci if (devinfo->gtt_size <= IRIS_MEMZONE_OTHER_START) 2385bf215546Sopenharmony_ci return NULL; 2386bf215546Sopenharmony_ci 2387bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = calloc(1, sizeof(*bufmgr)); 2388bf215546Sopenharmony_ci if (bufmgr == NULL) 2389bf215546Sopenharmony_ci return NULL; 2390bf215546Sopenharmony_ci 2391bf215546Sopenharmony_ci /* Handles to buffer objects belong to the device fd and are not 2392bf215546Sopenharmony_ci * reference counted by the kernel. If the same fd is used by 2393bf215546Sopenharmony_ci * multiple parties (threads sharing the same screen bufmgr, or 2394bf215546Sopenharmony_ci * even worse the same device fd passed to multiple libraries) 2395bf215546Sopenharmony_ci * ownership of those handles is shared by those independent parties. 2396bf215546Sopenharmony_ci * 2397bf215546Sopenharmony_ci * Don't do this! Ensure that each library/bufmgr has its own device 2398bf215546Sopenharmony_ci * fd so that its namespace does not clash with another. 2399bf215546Sopenharmony_ci */ 2400bf215546Sopenharmony_ci bufmgr->fd = os_dupfd_cloexec(fd); 2401bf215546Sopenharmony_ci 2402bf215546Sopenharmony_ci p_atomic_set(&bufmgr->refcount, 1); 2403bf215546Sopenharmony_ci 2404bf215546Sopenharmony_ci simple_mtx_init(&bufmgr->lock, mtx_plain); 2405bf215546Sopenharmony_ci simple_mtx_init(&bufmgr->bo_deps_lock, mtx_plain); 2406bf215546Sopenharmony_ci 2407bf215546Sopenharmony_ci iris_bufmgr_init_global_vm(fd, bufmgr); 2408bf215546Sopenharmony_ci 2409bf215546Sopenharmony_ci list_inithead(&bufmgr->zombie_list); 2410bf215546Sopenharmony_ci 2411bf215546Sopenharmony_ci bufmgr->has_llc = devinfo->has_llc; 2412bf215546Sopenharmony_ci bufmgr->has_local_mem = devinfo->has_local_mem; 2413bf215546Sopenharmony_ci bufmgr->has_tiling_uapi = devinfo->has_tiling_uapi; 2414bf215546Sopenharmony_ci bufmgr->bo_reuse = bo_reuse; 2415bf215546Sopenharmony_ci bufmgr->has_mmap_offset = gem_param(fd, I915_PARAM_MMAP_GTT_VERSION) >= 4; 2416bf215546Sopenharmony_ci bufmgr->has_userptr_probe = 2417bf215546Sopenharmony_ci gem_param(fd, I915_PARAM_HAS_USERPTR_PROBE) >= 1; 2418bf215546Sopenharmony_ci iris_bufmgr_get_meminfo(bufmgr, devinfo); 2419bf215546Sopenharmony_ci bufmgr->all_vram_mappable = intel_vram_all_mappable(devinfo); 2420bf215546Sopenharmony_ci 2421bf215546Sopenharmony_ci STATIC_ASSERT(IRIS_MEMZONE_SHADER_START == 0ull); 2422bf215546Sopenharmony_ci const uint64_t _4GB = 1ull << 32; 2423bf215546Sopenharmony_ci const uint64_t _2GB = 1ul << 31; 2424bf215546Sopenharmony_ci 2425bf215546Sopenharmony_ci /* The STATE_BASE_ADDRESS size field can only hold 1 page shy of 4GB */ 2426bf215546Sopenharmony_ci const uint64_t _4GB_minus_1 = _4GB - PAGE_SIZE; 2427bf215546Sopenharmony_ci 2428bf215546Sopenharmony_ci util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_SHADER], 2429bf215546Sopenharmony_ci PAGE_SIZE, _4GB_minus_1 - PAGE_SIZE); 2430bf215546Sopenharmony_ci util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_BINDER], 2431bf215546Sopenharmony_ci IRIS_MEMZONE_BINDER_START, IRIS_BINDER_ZONE_SIZE); 2432bf215546Sopenharmony_ci util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_BINDLESS], 2433bf215546Sopenharmony_ci IRIS_MEMZONE_BINDLESS_START, IRIS_BINDLESS_SIZE); 2434bf215546Sopenharmony_ci util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_SURFACE], 2435bf215546Sopenharmony_ci IRIS_MEMZONE_SURFACE_START, _4GB_minus_1 - 2436bf215546Sopenharmony_ci IRIS_BINDER_ZONE_SIZE - IRIS_BINDLESS_SIZE); 2437bf215546Sopenharmony_ci 2438bf215546Sopenharmony_ci /* Wa_2209859288: the Tigerlake PRM's workarounds volume says: 2439bf215546Sopenharmony_ci * 2440bf215546Sopenharmony_ci * "PSDunit is dropping MSB of the blend state pointer from SD FIFO" 2441bf215546Sopenharmony_ci * "Limit the Blend State Pointer to < 2G" 2442bf215546Sopenharmony_ci * 2443bf215546Sopenharmony_ci * We restrict the dynamic state pool to 2GB so that we don't ever get a 2444bf215546Sopenharmony_ci * BLEND_STATE pointer with the MSB set. We aren't likely to need the 2445bf215546Sopenharmony_ci * full 4GB for dynamic state anyway. 2446bf215546Sopenharmony_ci */ 2447bf215546Sopenharmony_ci const uint64_t dynamic_pool_size = 2448bf215546Sopenharmony_ci (devinfo->ver >= 12 ? _2GB : _4GB_minus_1) - IRIS_BORDER_COLOR_POOL_SIZE; 2449bf215546Sopenharmony_ci util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_DYNAMIC], 2450bf215546Sopenharmony_ci IRIS_MEMZONE_DYNAMIC_START + IRIS_BORDER_COLOR_POOL_SIZE, 2451bf215546Sopenharmony_ci dynamic_pool_size); 2452bf215546Sopenharmony_ci 2453bf215546Sopenharmony_ci /* Leave the last 4GB out of the high vma range, so that no state 2454bf215546Sopenharmony_ci * base address + size can overflow 48 bits. 2455bf215546Sopenharmony_ci */ 2456bf215546Sopenharmony_ci util_vma_heap_init(&bufmgr->vma_allocator[IRIS_MEMZONE_OTHER], 2457bf215546Sopenharmony_ci IRIS_MEMZONE_OTHER_START, 2458bf215546Sopenharmony_ci (devinfo->gtt_size - _4GB) - IRIS_MEMZONE_OTHER_START); 2459bf215546Sopenharmony_ci 2460bf215546Sopenharmony_ci init_cache_buckets(bufmgr, IRIS_HEAP_SYSTEM_MEMORY); 2461bf215546Sopenharmony_ci init_cache_buckets(bufmgr, IRIS_HEAP_DEVICE_LOCAL); 2462bf215546Sopenharmony_ci init_cache_buckets(bufmgr, IRIS_HEAP_DEVICE_LOCAL_PREFERRED); 2463bf215546Sopenharmony_ci 2464bf215546Sopenharmony_ci unsigned min_slab_order = 8; /* 256 bytes */ 2465bf215546Sopenharmony_ci unsigned max_slab_order = 20; /* 1 MB (slab size = 2 MB) */ 2466bf215546Sopenharmony_ci unsigned num_slab_orders_per_allocator = 2467bf215546Sopenharmony_ci (max_slab_order - min_slab_order) / NUM_SLAB_ALLOCATORS; 2468bf215546Sopenharmony_ci 2469bf215546Sopenharmony_ci /* Divide the size order range among slab managers. */ 2470bf215546Sopenharmony_ci for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 2471bf215546Sopenharmony_ci unsigned min_order = min_slab_order; 2472bf215546Sopenharmony_ci unsigned max_order = 2473bf215546Sopenharmony_ci MIN2(min_order + num_slab_orders_per_allocator, max_slab_order); 2474bf215546Sopenharmony_ci 2475bf215546Sopenharmony_ci if (!pb_slabs_init(&bufmgr->bo_slabs[i], min_order, max_order, 2476bf215546Sopenharmony_ci IRIS_HEAP_MAX, true, bufmgr, 2477bf215546Sopenharmony_ci iris_can_reclaim_slab, 2478bf215546Sopenharmony_ci iris_slab_alloc, 2479bf215546Sopenharmony_ci (void *) iris_slab_free)) { 2480bf215546Sopenharmony_ci free(bufmgr); 2481bf215546Sopenharmony_ci return NULL; 2482bf215546Sopenharmony_ci } 2483bf215546Sopenharmony_ci min_slab_order = max_order + 1; 2484bf215546Sopenharmony_ci } 2485bf215546Sopenharmony_ci 2486bf215546Sopenharmony_ci bufmgr->name_table = 2487bf215546Sopenharmony_ci _mesa_hash_table_create(NULL, _mesa_hash_uint, _mesa_key_uint_equal); 2488bf215546Sopenharmony_ci bufmgr->handle_table = 2489bf215546Sopenharmony_ci _mesa_hash_table_create(NULL, _mesa_hash_uint, _mesa_key_uint_equal); 2490bf215546Sopenharmony_ci 2491bf215546Sopenharmony_ci bufmgr->vma_min_align = 2492bf215546Sopenharmony_ci devinfo->verx10 >= 125 ? 2 * 1024 * 1024 : 2493bf215546Sopenharmony_ci (devinfo->has_local_mem ? 64 * 1024 : PAGE_SIZE); 2494bf215546Sopenharmony_ci 2495bf215546Sopenharmony_ci if (devinfo->has_aux_map) { 2496bf215546Sopenharmony_ci bufmgr->aux_map_ctx = intel_aux_map_init(bufmgr, &aux_map_allocator, 2497bf215546Sopenharmony_ci devinfo); 2498bf215546Sopenharmony_ci assert(bufmgr->aux_map_ctx); 2499bf215546Sopenharmony_ci } 2500bf215546Sopenharmony_ci 2501bf215546Sopenharmony_ci iris_init_border_color_pool(bufmgr, &bufmgr->border_color_pool); 2502bf215546Sopenharmony_ci 2503bf215546Sopenharmony_ci return bufmgr; 2504bf215546Sopenharmony_ci} 2505bf215546Sopenharmony_ci 2506bf215546Sopenharmony_cistatic struct iris_bufmgr * 2507bf215546Sopenharmony_ciiris_bufmgr_ref(struct iris_bufmgr *bufmgr) 2508bf215546Sopenharmony_ci{ 2509bf215546Sopenharmony_ci p_atomic_inc(&bufmgr->refcount); 2510bf215546Sopenharmony_ci return bufmgr; 2511bf215546Sopenharmony_ci} 2512bf215546Sopenharmony_ci 2513bf215546Sopenharmony_civoid 2514bf215546Sopenharmony_ciiris_bufmgr_unref(struct iris_bufmgr *bufmgr) 2515bf215546Sopenharmony_ci{ 2516bf215546Sopenharmony_ci simple_mtx_lock(&global_bufmgr_list_mutex); 2517bf215546Sopenharmony_ci if (p_atomic_dec_zero(&bufmgr->refcount)) { 2518bf215546Sopenharmony_ci list_del(&bufmgr->link); 2519bf215546Sopenharmony_ci iris_bufmgr_destroy(bufmgr); 2520bf215546Sopenharmony_ci } 2521bf215546Sopenharmony_ci simple_mtx_unlock(&global_bufmgr_list_mutex); 2522bf215546Sopenharmony_ci} 2523bf215546Sopenharmony_ci 2524bf215546Sopenharmony_ci/** Returns a new unique id, to be used by screens. */ 2525bf215546Sopenharmony_ciint 2526bf215546Sopenharmony_ciiris_bufmgr_create_screen_id(struct iris_bufmgr *bufmgr) 2527bf215546Sopenharmony_ci{ 2528bf215546Sopenharmony_ci return p_atomic_inc_return(&bufmgr->next_screen_id) - 1; 2529bf215546Sopenharmony_ci} 2530bf215546Sopenharmony_ci 2531bf215546Sopenharmony_ci/** 2532bf215546Sopenharmony_ci * Gets an already existing GEM buffer manager or create a new one. 2533bf215546Sopenharmony_ci * 2534bf215546Sopenharmony_ci * \param fd File descriptor of the opened DRM device. 2535bf215546Sopenharmony_ci */ 2536bf215546Sopenharmony_cistruct iris_bufmgr * 2537bf215546Sopenharmony_ciiris_bufmgr_get_for_fd(struct intel_device_info *devinfo, int fd, bool bo_reuse) 2538bf215546Sopenharmony_ci{ 2539bf215546Sopenharmony_ci struct stat st; 2540bf215546Sopenharmony_ci 2541bf215546Sopenharmony_ci if (fstat(fd, &st)) 2542bf215546Sopenharmony_ci return NULL; 2543bf215546Sopenharmony_ci 2544bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = NULL; 2545bf215546Sopenharmony_ci 2546bf215546Sopenharmony_ci simple_mtx_lock(&global_bufmgr_list_mutex); 2547bf215546Sopenharmony_ci list_for_each_entry(struct iris_bufmgr, iter_bufmgr, &global_bufmgr_list, link) { 2548bf215546Sopenharmony_ci struct stat iter_st; 2549bf215546Sopenharmony_ci if (fstat(iter_bufmgr->fd, &iter_st)) 2550bf215546Sopenharmony_ci continue; 2551bf215546Sopenharmony_ci 2552bf215546Sopenharmony_ci if (st.st_rdev == iter_st.st_rdev) { 2553bf215546Sopenharmony_ci assert(iter_bufmgr->bo_reuse == bo_reuse); 2554bf215546Sopenharmony_ci bufmgr = iris_bufmgr_ref(iter_bufmgr); 2555bf215546Sopenharmony_ci goto unlock; 2556bf215546Sopenharmony_ci } 2557bf215546Sopenharmony_ci } 2558bf215546Sopenharmony_ci 2559bf215546Sopenharmony_ci bufmgr = iris_bufmgr_create(devinfo, fd, bo_reuse); 2560bf215546Sopenharmony_ci if (bufmgr) 2561bf215546Sopenharmony_ci list_addtail(&bufmgr->link, &global_bufmgr_list); 2562bf215546Sopenharmony_ci 2563bf215546Sopenharmony_ci unlock: 2564bf215546Sopenharmony_ci simple_mtx_unlock(&global_bufmgr_list_mutex); 2565bf215546Sopenharmony_ci 2566bf215546Sopenharmony_ci return bufmgr; 2567bf215546Sopenharmony_ci} 2568bf215546Sopenharmony_ci 2569bf215546Sopenharmony_ciint 2570bf215546Sopenharmony_ciiris_bufmgr_get_fd(struct iris_bufmgr *bufmgr) 2571bf215546Sopenharmony_ci{ 2572bf215546Sopenharmony_ci return bufmgr->fd; 2573bf215546Sopenharmony_ci} 2574bf215546Sopenharmony_ci 2575bf215546Sopenharmony_civoid* 2576bf215546Sopenharmony_ciiris_bufmgr_get_aux_map_context(struct iris_bufmgr *bufmgr) 2577bf215546Sopenharmony_ci{ 2578bf215546Sopenharmony_ci return bufmgr->aux_map_ctx; 2579bf215546Sopenharmony_ci} 2580bf215546Sopenharmony_ci 2581bf215546Sopenharmony_cisimple_mtx_t * 2582bf215546Sopenharmony_ciiris_bufmgr_get_bo_deps_lock(struct iris_bufmgr *bufmgr) 2583bf215546Sopenharmony_ci{ 2584bf215546Sopenharmony_ci return &bufmgr->bo_deps_lock; 2585bf215546Sopenharmony_ci} 2586bf215546Sopenharmony_ci 2587bf215546Sopenharmony_cistruct iris_border_color_pool * 2588bf215546Sopenharmony_ciiris_bufmgr_get_border_color_pool(struct iris_bufmgr *bufmgr) 2589bf215546Sopenharmony_ci{ 2590bf215546Sopenharmony_ci return &bufmgr->border_color_pool; 2591bf215546Sopenharmony_ci} 2592bf215546Sopenharmony_ci 2593bf215546Sopenharmony_ciuint64_t 2594bf215546Sopenharmony_ciiris_bufmgr_vram_size(struct iris_bufmgr *bufmgr) 2595bf215546Sopenharmony_ci{ 2596bf215546Sopenharmony_ci return bufmgr->vram.size; 2597bf215546Sopenharmony_ci} 2598bf215546Sopenharmony_ci 2599bf215546Sopenharmony_ciuint64_t 2600bf215546Sopenharmony_ciiris_bufmgr_sram_size(struct iris_bufmgr *bufmgr) 2601bf215546Sopenharmony_ci{ 2602bf215546Sopenharmony_ci return bufmgr->sys.size; 2603bf215546Sopenharmony_ci} 2604