Path: blob/21.2-virgl/src/gallium/drivers/crocus/crocus_bufmgr.c
4570 views
/*1* Copyright © 2017 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included11* in all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS14* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING18* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER19* DEALINGS IN THE SOFTWARE.20*/2122/**23* @file crocus_bufmgr.c24*25* The crocus buffer manager.26*27* XXX: write better comments28* - BOs29* - Explain BO cache30* - main interface to GEM in the kernel31*/3233#ifdef HAVE_CONFIG_H34#include "config.h"35#endif3637#include <xf86drm.h>38#include <util/u_atomic.h>39#include <fcntl.h>40#include <stdio.h>41#include <stdlib.h>42#include <string.h>43#include <unistd.h>44#include <assert.h>45#include <sys/ioctl.h>46#include <sys/mman.h>47#include <sys/stat.h>48#include <sys/types.h>49#include <stdbool.h>50#include <time.h>5152#include "errno.h"53#include "common/intel_clflush.h"54#include "dev/intel_debug.h"55#include "common/intel_gem.h"56#include "dev/intel_device_info.h"57#include "main/macros.h"58#include "util/debug.h"59#include "util/macros.h"60#include "util/hash_table.h"61#include "util/list.h"62#include "util/os_file.h"63#include "util/u_dynarray.h"64#include "util/vma.h"65#include "crocus_bufmgr.h"66#include "crocus_context.h"67#include "string.h"6869#include "drm-uapi/i915_drm.h"7071#ifdef HAVE_VALGRIND72#include <valgrind.h>73#include <memcheck.h>74#define VG(x) x75#else76#define VG(x)77#endif7879/**80* For debugging purposes, this returns a time in seconds.81*/82static double83get_time(void)84{85struct timespec tp;8687clock_gettime(CLOCK_MONOTONIC, &tp);8889return tp.tv_sec + tp.tv_nsec / 1000000000.0;90}9192/* VALGRIND_FREELIKE_BLOCK unfortunately does not actually undo the earlier93* VALGRIND_MALLOCLIKE_BLOCK but instead leaves vg convinced the memory is94* leaked. All because it does not call VG(cli_free) from its95* VG_USERREQ__FREELIKE_BLOCK handler. Instead of treating the memory like96* and allocation, we mark it available for use upon mmapping and remove97* it upon unmapping.98*/99#define VG_DEFINED(ptr, size) VG(VALGRIND_MAKE_MEM_DEFINED(ptr, size))100#define VG_NOACCESS(ptr, size) VG(VALGRIND_MAKE_MEM_NOACCESS(ptr, size))101102#define PAGE_SIZE 4096103104#define WARN_ONCE(cond, fmt...) do { \105if (unlikely(cond)) { \106static bool _warned = false; \107if (!_warned) { \108fprintf(stderr, "WARNING: "); \109fprintf(stderr, fmt); \110_warned = true; \111} \112} \113} while (0)114115#define FILE_DEBUG_FLAG DEBUG_BUFMGR116117struct bo_cache_bucket {118/** List of cached BOs. */119struct list_head head;120121/** Size of this bucket, in bytes. */122uint64_t size;123};124125struct bo_export {126/** File descriptor associated with a handle export. */127int drm_fd;128129/** GEM handle in drm_fd */130uint32_t gem_handle;131132struct list_head link;133};134135struct crocus_bufmgr {136/**137* List into the list of bufmgr.138*/139struct list_head link;140141uint32_t refcount;142143int fd;144145simple_mtx_t lock;146147/** Array of lists of cached gem objects of power-of-two sizes */148struct bo_cache_bucket cache_bucket[14 * 4];149int num_buckets;150time_t time;151152struct hash_table *name_table;153struct hash_table *handle_table;154155/**156* List of BOs which we've effectively freed, but are hanging on to157* until they're idle before closing and returning the VMA.158*/159struct list_head zombie_list;160161bool has_llc:1;162bool has_mmap_offset:1;163bool has_tiling_uapi:1;164bool bo_reuse:1;165};166167static simple_mtx_t global_bufmgr_list_mutex = _SIMPLE_MTX_INITIALIZER_NP;168static struct list_head global_bufmgr_list = {169.next = &global_bufmgr_list,170.prev = &global_bufmgr_list,171};172173static int bo_set_tiling_internal(struct crocus_bo *bo, uint32_t tiling_mode,174uint32_t stride);175176static void bo_free(struct crocus_bo *bo);177178static uint32_t179key_hash_uint(const void *key)180{181return _mesa_hash_data(key, 4);182}183184static bool185key_uint_equal(const void *a, const void *b)186{187return *((unsigned *) a) == *((unsigned *) b);188}189190static struct crocus_bo *191find_and_ref_external_bo(struct hash_table *ht, unsigned int key)192{193struct hash_entry *entry = _mesa_hash_table_search(ht, &key);194struct crocus_bo *bo = entry ? entry->data : NULL;195196if (bo) {197assert(bo->external);198assert(!bo->reusable);199200/* Being non-reusable, the BO cannot be in the cache lists, but it201* may be in the zombie list if it had reached zero references, but202* we hadn't yet closed it...and then reimported the same BO. If it203* is, then remove it since it's now been resurrected.204*/205if (bo->head.prev || bo->head.next)206list_del(&bo->head);207208crocus_bo_reference(bo);209}210211return bo;212}213214/**215* This function finds the correct bucket fit for the input size.216* The function works with O(1) complexity when the requested size217* was queried instead of iterating the size through all the buckets.218*/219static struct bo_cache_bucket *220bucket_for_size(struct crocus_bufmgr *bufmgr, uint64_t size)221{222/* Calculating the pages and rounding up to the page size. */223const unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;224225/* Row Bucket sizes clz((x-1) | 3) Row Column226* in pages stride size227* 0: 1 2 3 4 -> 30 30 30 30 4 1228* 1: 5 6 7 8 -> 29 29 29 29 4 1229* 2: 10 12 14 16 -> 28 28 28 28 8 2230* 3: 20 24 28 32 -> 27 27 27 27 16 4231*/232const unsigned row = 30 - __builtin_clz((pages - 1) | 3);233const unsigned row_max_pages = 4 << row;234235/* The '& ~2' is the special case for row 1. In row 1, max pages /236* 2 is 2, but the previous row maximum is zero (because there is237* no previous row). All row maximum sizes are power of 2, so that238* is the only case where that bit will be set.239*/240const unsigned prev_row_max_pages = (row_max_pages / 2) & ~2;241int col_size_log2 = row - 1;242col_size_log2 += (col_size_log2 < 0);243244const unsigned col = (pages - prev_row_max_pages +245((1 << col_size_log2) - 1)) >> col_size_log2;246247/* Calculating the index based on the row and column. */248const unsigned index = (row * 4) + (col - 1);249250return (index < bufmgr->num_buckets) ?251&bufmgr->cache_bucket[index] : NULL;252}253254255int256crocus_bo_busy(struct crocus_bo *bo)257{258struct crocus_bufmgr *bufmgr = bo->bufmgr;259struct drm_i915_gem_busy busy = { .handle = bo->gem_handle };260261int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);262if (ret == 0) {263bo->idle = !busy.busy;264return busy.busy;265}266return false;267}268269int270crocus_bo_madvise(struct crocus_bo *bo, int state)271{272struct drm_i915_gem_madvise madv = {273.handle = bo->gem_handle,274.madv = state,275.retained = 1,276};277278intel_ioctl(bo->bufmgr->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);279280return madv.retained;281}282283static struct crocus_bo *284bo_calloc(void)285{286struct crocus_bo *bo = calloc(1, sizeof(*bo));287if (!bo)288return NULL;289290list_inithead(&bo->exports);291bo->hash = _mesa_hash_pointer(bo);292return bo;293}294295static struct crocus_bo *296alloc_bo_from_cache(struct crocus_bufmgr *bufmgr,297struct bo_cache_bucket *bucket,298uint32_t alignment,299unsigned flags)300{301if (!bucket)302return NULL;303304struct crocus_bo *bo = NULL;305306list_for_each_entry_safe(struct crocus_bo, cur, &bucket->head, head) {307/* If the last BO in the cache is busy, there are no idle BOs. Bail,308* either falling back to a non-matching memzone, or if that fails,309* allocating a fresh buffer.310*/311if (crocus_bo_busy(cur))312return NULL;313314list_del(&cur->head);315316/* Tell the kernel we need this BO. If it still exists, we're done! */317if (crocus_bo_madvise(cur, I915_MADV_WILLNEED)) {318bo = cur;319break;320}321322/* This BO was purged, throw it out and keep looking. */323bo_free(cur);324}325326if (!bo)327return NULL;328329/* Zero the contents if necessary. If this fails, fall back to330* allocating a fresh BO, which will always be zeroed by the kernel.331*/332if (flags & BO_ALLOC_ZEROED) {333void *map = crocus_bo_map(NULL, bo, MAP_WRITE | MAP_RAW);334if (map) {335memset(map, 0, bo->size);336} else {337bo_free(bo);338return NULL;339}340}341342return bo;343}344345static struct crocus_bo *346alloc_fresh_bo(struct crocus_bufmgr *bufmgr, uint64_t bo_size)347{348struct crocus_bo *bo = bo_calloc();349if (!bo)350return NULL;351352struct drm_i915_gem_create create = { .size = bo_size };353354/* All new BOs we get from the kernel are zeroed, so we don't need to355* worry about that here.356*/357if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {358free(bo);359return NULL;360}361362bo->gem_handle = create.handle;363bo->bufmgr = bufmgr;364bo->size = bo_size;365bo->idle = true;366bo->tiling_mode = I915_TILING_NONE;367bo->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;368bo->stride = 0;369370/* Calling set_domain() will allocate pages for the BO outside of the371* struct mutex lock in the kernel, which is more efficient than waiting372* to create them during the first execbuf that uses the BO.373*/374struct drm_i915_gem_set_domain sd = {375.handle = bo->gem_handle,376.read_domains = I915_GEM_DOMAIN_CPU,377.write_domain = 0,378};379380if (intel_ioctl(bo->bufmgr->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &sd) != 0) {381bo_free(bo);382return NULL;383}384385return bo;386}387388static struct crocus_bo *389bo_alloc_internal(struct crocus_bufmgr *bufmgr,390const char *name,391uint64_t size,392uint32_t alignment,393unsigned flags,394uint32_t tiling_mode,395uint32_t stride)396{397struct crocus_bo *bo;398unsigned int page_size = getpagesize();399struct bo_cache_bucket *bucket = bucket_for_size(bufmgr, size);400401/* Round the size up to the bucket size, or if we don't have caching402* at this size, a multiple of the page size.403*/404uint64_t bo_size =405bucket ? bucket->size : MAX2(ALIGN(size, page_size), page_size);406407simple_mtx_lock(&bufmgr->lock);408409/* Get a buffer out of the cache if available. First, we try to find410* one with a matching memory zone so we can avoid reallocating VMA.411*/412bo = alloc_bo_from_cache(bufmgr, bucket, alignment, flags);413414simple_mtx_unlock(&bufmgr->lock);415416if (!bo) {417bo = alloc_fresh_bo(bufmgr, bo_size);418if (!bo)419return NULL;420}421422if (bo_set_tiling_internal(bo, tiling_mode, stride))423goto err_free;424425bo->name = name;426p_atomic_set(&bo->refcount, 1);427bo->reusable = bucket && bufmgr->bo_reuse;428bo->cache_coherent = bufmgr->has_llc;429bo->index = -1;430bo->kflags = 0;431432if ((flags & BO_ALLOC_COHERENT) && !bo->cache_coherent) {433struct drm_i915_gem_caching arg = {434.handle = bo->gem_handle,435.caching = 1,436};437if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_CACHING, &arg) == 0) {438bo->cache_coherent = true;439bo->reusable = false;440}441}442443DBG("bo_create: buf %d (%s) %llub\n", bo->gem_handle,444bo->name, (unsigned long long) size);445446return bo;447448err_free:449bo_free(bo);450return NULL;451}452453struct crocus_bo *454crocus_bo_alloc(struct crocus_bufmgr *bufmgr,455const char *name,456uint64_t size)457{458return bo_alloc_internal(bufmgr, name, size, 1,4590, I915_TILING_NONE, 0);460}461462struct crocus_bo *463crocus_bo_alloc_tiled(struct crocus_bufmgr *bufmgr, const char *name,464uint64_t size, uint32_t alignment,465uint32_t tiling_mode, uint32_t pitch, unsigned flags)466{467return bo_alloc_internal(bufmgr, name, size, alignment,468flags, tiling_mode, pitch);469}470471struct crocus_bo *472crocus_bo_create_userptr(struct crocus_bufmgr *bufmgr, const char *name,473void *ptr, size_t size)474{475struct crocus_bo *bo;476477bo = bo_calloc();478if (!bo)479return NULL;480481struct drm_i915_gem_userptr arg = {482.user_ptr = (uintptr_t)ptr,483.user_size = size,484};485if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_USERPTR, &arg))486goto err_free;487bo->gem_handle = arg.handle;488489/* Check the buffer for validity before we try and use it in a batch */490struct drm_i915_gem_set_domain sd = {491.handle = bo->gem_handle,492.read_domains = I915_GEM_DOMAIN_CPU,493};494if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &sd))495goto err_close;496497bo->name = name;498bo->size = size;499bo->map_cpu = ptr;500501bo->bufmgr = bufmgr;502bo->kflags = 0;503504p_atomic_set(&bo->refcount, 1);505bo->userptr = true;506bo->cache_coherent = true;507bo->index = -1;508bo->idle = true;509510return bo;511512err_close:513intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_CLOSE, &bo->gem_handle);514err_free:515free(bo);516return NULL;517}518519/**520* Returns a crocus_bo wrapping the given buffer object handle.521*522* This can be used when one application needs to pass a buffer object523* to another.524*/525struct crocus_bo *526crocus_bo_gem_create_from_name(struct crocus_bufmgr *bufmgr,527const char *name, unsigned int handle)528{529struct crocus_bo *bo;530531/* At the moment most applications only have a few named bo.532* For instance, in a DRI client only the render buffers passed533* between X and the client are named. And since X returns the534* alternating names for the front/back buffer a linear search535* provides a sufficiently fast match.536*/537simple_mtx_lock(&bufmgr->lock);538bo = find_and_ref_external_bo(bufmgr->name_table, handle);539if (bo)540goto out;541542struct drm_gem_open open_arg = { .name = handle };543int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_OPEN, &open_arg);544if (ret != 0) {545DBG("Couldn't reference %s handle 0x%08x: %s\n",546name, handle, strerror(errno));547bo = NULL;548goto out;549}550/* Now see if someone has used a prime handle to get this551* object from the kernel before by looking through the list552* again for a matching gem_handle553*/554bo = find_and_ref_external_bo(bufmgr->handle_table, open_arg.handle);555if (bo)556goto out;557558bo = bo_calloc();559if (!bo)560goto out;561562p_atomic_set(&bo->refcount, 1);563564bo->size = open_arg.size;565bo->gtt_offset = 0;566bo->bufmgr = bufmgr;567bo->gem_handle = open_arg.handle;568bo->name = name;569bo->global_name = handle;570bo->reusable = false;571bo->external = true;572bo->kflags = 0;573574_mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo);575_mesa_hash_table_insert(bufmgr->name_table, &bo->global_name, bo);576577struct drm_i915_gem_get_tiling get_tiling = { .handle = bo->gem_handle };578ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);579if (ret != 0)580goto err_unref;581582bo->tiling_mode = get_tiling.tiling_mode;583bo->swizzle_mode = get_tiling.swizzle_mode;584/* XXX stride is unknown */585DBG("bo_create_from_handle: %d (%s)\n", handle, bo->name);586587out:588simple_mtx_unlock(&bufmgr->lock);589return bo;590591err_unref:592bo_free(bo);593simple_mtx_unlock(&bufmgr->lock);594return NULL;595}596597static void598bo_close(struct crocus_bo *bo)599{600struct crocus_bufmgr *bufmgr = bo->bufmgr;601602if (bo->external) {603struct hash_entry *entry;604605if (bo->global_name) {606entry = _mesa_hash_table_search(bufmgr->name_table, &bo->global_name);607_mesa_hash_table_remove(bufmgr->name_table, entry);608}609610entry = _mesa_hash_table_search(bufmgr->handle_table, &bo->gem_handle);611_mesa_hash_table_remove(bufmgr->handle_table, entry);612}613614/* Close this object */615struct drm_gem_close close = { .handle = bo->gem_handle };616int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_CLOSE, &close);617if (ret != 0) {618DBG("DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n",619bo->gem_handle, bo->name, strerror(errno));620}621622free(bo);623}624625static void626bo_free(struct crocus_bo *bo)627{628struct crocus_bufmgr *bufmgr = bo->bufmgr;629630if (bo->map_cpu && !bo->userptr) {631VG_NOACCESS(bo->map_cpu, bo->size);632munmap(bo->map_cpu, bo->size);633}634if (bo->map_wc) {635VG_NOACCESS(bo->map_wc, bo->size);636munmap(bo->map_wc, bo->size);637}638if (bo->map_gtt) {639VG_NOACCESS(bo->map_gtt, bo->size);640munmap(bo->map_gtt, bo->size);641}642643if (bo->idle) {644bo_close(bo);645} else {646/* Defer closing the GEM BO and returning the VMA for reuse until the647* BO is idle. Just move it to the dead list for now.648*/649list_addtail(&bo->head, &bufmgr->zombie_list);650}651}652653/** Frees all cached buffers significantly older than @time. */654static void655cleanup_bo_cache(struct crocus_bufmgr *bufmgr, time_t time)656{657int i;658659if (bufmgr->time == time)660return;661662for (i = 0; i < bufmgr->num_buckets; i++) {663struct bo_cache_bucket *bucket = &bufmgr->cache_bucket[i];664665list_for_each_entry_safe(struct crocus_bo, bo, &bucket->head, head) {666if (time - bo->free_time <= 1)667break;668669list_del(&bo->head);670671bo_free(bo);672}673}674675list_for_each_entry_safe(struct crocus_bo, bo, &bufmgr->zombie_list, head) {676/* Stop once we reach a busy BO - all others past this point were677* freed more recently so are likely also busy.678*/679if (!bo->idle && crocus_bo_busy(bo))680break;681682list_del(&bo->head);683bo_close(bo);684}685686bufmgr->time = time;687}688689static void690bo_unreference_final(struct crocus_bo *bo, time_t time)691{692struct crocus_bufmgr *bufmgr = bo->bufmgr;693struct bo_cache_bucket *bucket;694695DBG("bo_unreference final: %d (%s)\n", bo->gem_handle, bo->name);696697bucket = NULL;698if (bo->reusable)699bucket = bucket_for_size(bufmgr, bo->size);700/* Put the buffer into our internal cache for reuse if we can. */701if (bucket && crocus_bo_madvise(bo, I915_MADV_DONTNEED)) {702bo->free_time = time;703bo->name = NULL;704705list_addtail(&bo->head, &bucket->head);706} else {707bo_free(bo);708}709}710711void712__crocus_bo_unreference(struct crocus_bo *bo)713{714struct crocus_bufmgr *bufmgr = bo->bufmgr;715struct timespec time;716717clock_gettime(CLOCK_MONOTONIC, &time);718719simple_mtx_lock(&bufmgr->lock);720721if (p_atomic_dec_zero(&bo->refcount)) {722bo_unreference_final(bo, time.tv_sec);723cleanup_bo_cache(bufmgr, time.tv_sec);724}725726simple_mtx_unlock(&bufmgr->lock);727}728729static void730bo_wait_with_stall_warning(struct pipe_debug_callback *dbg,731struct crocus_bo *bo,732const char *action)733{734bool busy = dbg && !bo->idle;735double elapsed = unlikely(busy) ? -get_time() : 0.0;736737crocus_bo_wait_rendering(bo);738739if (unlikely(busy)) {740elapsed += get_time();741if (elapsed > 1e-5) /* 0.01ms */ {742perf_debug(dbg, "%s a busy \"%s\" BO stalled and took %.03f ms.\n",743action, bo->name, elapsed * 1000);744}745}746}747748static void749print_flags(unsigned flags)750{751if (flags & MAP_READ)752DBG("READ ");753if (flags & MAP_WRITE)754DBG("WRITE ");755if (flags & MAP_ASYNC)756DBG("ASYNC ");757if (flags & MAP_PERSISTENT)758DBG("PERSISTENT ");759if (flags & MAP_COHERENT)760DBG("COHERENT ");761if (flags & MAP_RAW)762DBG("RAW ");763DBG("\n");764}765766static void *767crocus_bo_gem_mmap_legacy(struct pipe_debug_callback *dbg,768struct crocus_bo *bo, bool wc)769{770struct crocus_bufmgr *bufmgr = bo->bufmgr;771772struct drm_i915_gem_mmap mmap_arg = {773.handle = bo->gem_handle,774.size = bo->size,775.flags = wc ? I915_MMAP_WC : 0,776};777778int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);779if (ret != 0) {780DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",781__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));782return NULL;783}784void *map = (void *) (uintptr_t) mmap_arg.addr_ptr;785786return map;787}788789static void *790crocus_bo_gem_mmap_offset(struct pipe_debug_callback *dbg, struct crocus_bo *bo,791bool wc)792{793struct crocus_bufmgr *bufmgr = bo->bufmgr;794795struct drm_i915_gem_mmap_offset mmap_arg = {796.handle = bo->gem_handle,797.flags = wc ? I915_MMAP_OFFSET_WC : I915_MMAP_OFFSET_WB,798};799800/* Get the fake offset back */801int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &mmap_arg);802if (ret != 0) {803DBG("%s:%d: Error preparing buffer %d (%s): %s .\n",804__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));805return NULL;806}807808/* And map it */809void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,810bufmgr->fd, mmap_arg.offset);811if (map == MAP_FAILED) {812DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",813__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));814return NULL;815}816817return map;818}819820static void *821crocus_bo_gem_mmap(struct pipe_debug_callback *dbg, struct crocus_bo *bo, bool wc)822{823struct crocus_bufmgr *bufmgr = bo->bufmgr;824825if (bufmgr->has_mmap_offset)826return crocus_bo_gem_mmap_offset(dbg, bo, wc);827else828return crocus_bo_gem_mmap_legacy(dbg, bo, wc);829}830831static void *832crocus_bo_map_cpu(struct pipe_debug_callback *dbg,833struct crocus_bo *bo, unsigned flags)834{835/* We disallow CPU maps for writing to non-coherent buffers, as the836* CPU map can become invalidated when a batch is flushed out, which837* can happen at unpredictable times. You should use WC maps instead.838*/839assert(bo->cache_coherent || !(flags & MAP_WRITE));840841if (!bo->map_cpu) {842DBG("crocus_bo_map_cpu: %d (%s)\n", bo->gem_handle, bo->name);843844void *map = crocus_bo_gem_mmap(dbg, bo, false);845if (!map) {846return NULL;847}848849VG_DEFINED(map, bo->size);850851if (p_atomic_cmpxchg(&bo->map_cpu, NULL, map)) {852VG_NOACCESS(map, bo->size);853munmap(map, bo->size);854}855}856assert(bo->map_cpu);857858DBG("crocus_bo_map_cpu: %d (%s) -> %p, ", bo->gem_handle, bo->name,859bo->map_cpu);860print_flags(flags);861862if (!(flags & MAP_ASYNC)) {863bo_wait_with_stall_warning(dbg, bo, "CPU mapping");864}865866if (!bo->cache_coherent && !bo->bufmgr->has_llc) {867/* If we're reusing an existing CPU mapping, the CPU caches may868* contain stale data from the last time we read from that mapping.869* (With the BO cache, it might even be data from a previous buffer!)870* Even if it's a brand new mapping, the kernel may have zeroed the871* buffer via CPU writes.872*873* We need to invalidate those cachelines so that we see the latest874* contents, and so long as we only read from the CPU mmap we do not875* need to write those cachelines back afterwards.876*877* On LLC, the emprical evidence suggests that writes from the GPU878* that bypass the LLC (i.e. for scanout) do *invalidate* the CPU879* cachelines. (Other reads, such as the display engine, bypass the880* LLC entirely requiring us to keep dirty pixels for the scanout881* out of any cache.)882*/883intel_invalidate_range(bo->map_cpu, bo->size);884}885886return bo->map_cpu;887}888889static void *890crocus_bo_map_wc(struct pipe_debug_callback *dbg,891struct crocus_bo *bo, unsigned flags)892{893if (!bo->map_wc) {894DBG("crocus_bo_map_wc: %d (%s)\n", bo->gem_handle, bo->name);895896void *map = crocus_bo_gem_mmap(dbg, bo, true);897if (!map) {898return NULL;899}900901VG_DEFINED(map, bo->size);902903if (p_atomic_cmpxchg(&bo->map_wc, NULL, map)) {904VG_NOACCESS(map, bo->size);905munmap(map, bo->size);906}907}908assert(bo->map_wc);909910DBG("crocus_bo_map_wc: %d (%s) -> %p\n", bo->gem_handle, bo->name, bo->map_wc);911print_flags(flags);912913if (!(flags & MAP_ASYNC)) {914bo_wait_with_stall_warning(dbg, bo, "WC mapping");915}916917return bo->map_wc;918}919920/**921* Perform an uncached mapping via the GTT.922*923* Write access through the GTT is not quite fully coherent. On low power924* systems especially, like modern Atoms, we can observe reads from RAM before925* the write via GTT has landed. A write memory barrier that flushes the Write926* Combining Buffer (i.e. sfence/mfence) is not sufficient to order the later927* read after the write as the GTT write suffers a small delay through the GTT928* indirection. The kernel uses an uncached mmio read to ensure the GTT write929* is ordered with reads (either by the GPU, WB or WC) and unconditionally930* flushes prior to execbuf submission. However, if we are not informing the931* kernel about our GTT writes, it will not flush before earlier access, such932* as when using the cmdparser. Similarly, we need to be careful if we should933* ever issue a CPU read immediately following a GTT write.934*935* Telling the kernel about write access also has one more important936* side-effect. Upon receiving notification about the write, it cancels any937* scanout buffering for FBC/PSR and friends. Later FBC/PSR is then flushed by938* either SW_FINISH or DIRTYFB. The presumption is that we never write to the939* actual scanout via a mmaping, only to a backbuffer and so all the FBC/PSR940* tracking is handled on the buffer exchange instead.941*/942static void *943crocus_bo_map_gtt(struct pipe_debug_callback *dbg,944struct crocus_bo *bo, unsigned flags)945{946struct crocus_bufmgr *bufmgr = bo->bufmgr;947948/* If we don't support get/set_tiling, there's no support for GTT mapping949* either (it won't do any de-tiling for us).950*/951assert(bufmgr->has_tiling_uapi);952953/* Get a mapping of the buffer if we haven't before. */954if (bo->map_gtt == NULL) {955DBG("bo_map_gtt: mmap %d (%s)\n", bo->gem_handle, bo->name);956957struct drm_i915_gem_mmap_gtt mmap_arg = { .handle = bo->gem_handle };958959/* Get the fake offset back... */960int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg);961if (ret != 0) {962DBG("%s:%d: Error preparing buffer map %d (%s): %s .\n",963__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));964return NULL;965}966967/* and mmap it. */968void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE,969MAP_SHARED, bufmgr->fd, mmap_arg.offset);970if (map == MAP_FAILED) {971DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",972__FILE__, __LINE__, bo->gem_handle, bo->name, strerror(errno));973return NULL;974}975976/* We don't need to use VALGRIND_MALLOCLIKE_BLOCK because Valgrind will977* already intercept this mmap call. However, for consistency between978* all the mmap paths, we mark the pointer as defined now and mark it979* as inaccessible afterwards.980*/981VG_DEFINED(map, bo->size);982983if (p_atomic_cmpxchg(&bo->map_gtt, NULL, map)) {984VG_NOACCESS(map, bo->size);985munmap(map, bo->size);986}987}988assert(bo->map_gtt);989990DBG("bo_map_gtt: %d (%s) -> %p, ", bo->gem_handle, bo->name, bo->map_gtt);991print_flags(flags);992993if (!(flags & MAP_ASYNC)) {994bo_wait_with_stall_warning(dbg, bo, "GTT mapping");995}996997return bo->map_gtt;998}9991000static bool1001can_map_cpu(struct crocus_bo *bo, unsigned flags)1002{1003if (bo->cache_coherent)1004return true;10051006/* Even if the buffer itself is not cache-coherent (such as a scanout), on1007* an LLC platform reads always are coherent (as they are performed via the1008* central system agent). It is just the writes that we need to take special1009* care to ensure that land in main memory and not stick in the CPU cache.1010*/1011if (!(flags & MAP_WRITE) && bo->bufmgr->has_llc)1012return true;10131014/* If PERSISTENT or COHERENT are set, the mmapping needs to remain valid1015* across batch flushes where the kernel will change cache domains of the1016* bo, invalidating continued access to the CPU mmap on non-LLC device.1017*1018* Similarly, ASYNC typically means that the buffer will be accessed via1019* both the CPU and the GPU simultaneously. Batches may be executed that1020* use the BO even while it is mapped. While OpenGL technically disallows1021* most drawing while non-persistent mappings are active, we may still use1022* the GPU for blits or other operations, causing batches to happen at1023* inconvenient times.1024*1025* If RAW is set, we expect the caller to be able to handle a WC buffer1026* more efficiently than the involuntary clflushes.1027*/1028if (flags & (MAP_PERSISTENT | MAP_COHERENT | MAP_ASYNC | MAP_RAW))1029return false;10301031return !(flags & MAP_WRITE);1032}10331034void *1035crocus_bo_map(struct pipe_debug_callback *dbg,1036struct crocus_bo *bo, unsigned flags)1037{1038if (bo->tiling_mode != I915_TILING_NONE && !(flags & MAP_RAW))1039return crocus_bo_map_gtt(dbg, bo, flags);10401041void *map;10421043if (can_map_cpu(bo, flags))1044map = crocus_bo_map_cpu(dbg, bo, flags);1045else1046map = crocus_bo_map_wc(dbg, bo, flags);10471048/* Allow the attempt to fail by falling back to the GTT where necessary.1049*1050* Not every buffer can be mmaped directly using the CPU (or WC), for1051* example buffers that wrap stolen memory or are imported from other1052* devices. For those, we have little choice but to use a GTT mmapping.1053* However, if we use a slow GTT mmapping for reads where we expected fast1054* access, that order of magnitude difference in throughput will be clearly1055* expressed by angry users.1056*1057* We skip MAP_RAW because we want to avoid map_gtt's fence detiling.1058*/1059if (!map && !(flags & MAP_RAW)) {1060perf_debug(dbg, "Fallback GTT mapping for %s with access flags %x\n",1061bo->name, flags);1062map = crocus_bo_map_gtt(dbg, bo, flags);1063}10641065return map;1066}10671068/** Waits for all GPU rendering with the object to have completed. */1069void1070crocus_bo_wait_rendering(struct crocus_bo *bo)1071{1072/* We require a kernel recent enough for WAIT_IOCTL support.1073* See intel_init_bufmgr()1074*/1075crocus_bo_wait(bo, -1);1076}10771078/**1079* Waits on a BO for the given amount of time.1080*1081* @bo: buffer object to wait for1082* @timeout_ns: amount of time to wait in nanoseconds.1083* If value is less than 0, an infinite wait will occur.1084*1085* Returns 0 if the wait was successful ie. the last batch referencing the1086* object has completed within the allotted time. Otherwise some negative return1087* value describes the error. Of particular interest is -ETIME when the wait has1088* failed to yield the desired result.1089*1090* Similar to crocus_bo_wait_rendering except a timeout parameter allows1091* the operation to give up after a certain amount of time. Another subtle1092* difference is the internal locking semantics are different (this variant does1093* not hold the lock for the duration of the wait). This makes the wait subject1094* to a larger userspace race window.1095*1096* The implementation shall wait until the object is no longer actively1097* referenced within a batch buffer at the time of the call. The wait will1098* not guarantee that the buffer is re-issued via another thread, or an flinked1099* handle. Userspace must make sure this race does not occur if such precision1100* is important.1101*1102* Note that some kernels have broken the inifite wait for negative values1103* promise, upgrade to latest stable kernels if this is the case.1104*/1105int1106crocus_bo_wait(struct crocus_bo *bo, int64_t timeout_ns)1107{1108struct crocus_bufmgr *bufmgr = bo->bufmgr;11091110/* If we know it's idle, don't bother with the kernel round trip */1111if (bo->idle && !bo->external)1112return 0;11131114struct drm_i915_gem_wait wait = {1115.bo_handle = bo->gem_handle,1116.timeout_ns = timeout_ns,1117};1118int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_WAIT, &wait);1119if (ret != 0)1120return -errno;11211122bo->idle = true;11231124return ret;1125}11261127static void1128crocus_bufmgr_destroy(struct crocus_bufmgr *bufmgr)1129{1130simple_mtx_destroy(&bufmgr->lock);11311132/* Free any cached buffer objects we were going to reuse */1133for (int i = 0; i < bufmgr->num_buckets; i++) {1134struct bo_cache_bucket *bucket = &bufmgr->cache_bucket[i];11351136list_for_each_entry_safe(struct crocus_bo, bo, &bucket->head, head) {1137list_del(&bo->head);11381139bo_free(bo);1140}1141}11421143/* Close any buffer objects on the dead list. */1144list_for_each_entry_safe(struct crocus_bo, bo, &bufmgr->zombie_list, head) {1145list_del(&bo->head);1146bo_close(bo);1147}11481149_mesa_hash_table_destroy(bufmgr->name_table, NULL);1150_mesa_hash_table_destroy(bufmgr->handle_table, NULL);11511152close(bufmgr->fd);11531154free(bufmgr);1155}11561157static int1158bo_set_tiling_internal(struct crocus_bo *bo, uint32_t tiling_mode,1159uint32_t stride)1160{1161struct crocus_bufmgr *bufmgr = bo->bufmgr;1162struct drm_i915_gem_set_tiling set_tiling;1163int ret;11641165if (bo->global_name == 0 &&1166tiling_mode == bo->tiling_mode && stride == bo->stride)1167return 0;11681169memset(&set_tiling, 0, sizeof(set_tiling));1170do {1171/* set_tiling is slightly broken and overwrites the1172* input on the error path, so we have to open code1173* drm_ioctl.1174*/1175set_tiling.handle = bo->gem_handle;1176set_tiling.tiling_mode = tiling_mode;1177set_tiling.stride = stride;11781179ret = ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);1180} while (ret == -1 && (errno == EINTR || errno == EAGAIN));1181if (ret == -1)1182return -errno;11831184bo->tiling_mode = set_tiling.tiling_mode;1185bo->swizzle_mode = set_tiling.swizzle_mode;1186bo->stride = set_tiling.stride;1187return 0;1188}11891190int1191crocus_bo_get_tiling(struct crocus_bo *bo, uint32_t *tiling_mode,1192uint32_t *swizzle_mode)1193{1194*tiling_mode = bo->tiling_mode;1195*swizzle_mode = bo->swizzle_mode;1196return 0;1197}11981199struct crocus_bo *1200crocus_bo_import_dmabuf(struct crocus_bufmgr *bufmgr, int prime_fd,1201uint64_t modifier)1202{1203uint32_t handle;1204struct crocus_bo *bo;12051206simple_mtx_lock(&bufmgr->lock);1207int ret = drmPrimeFDToHandle(bufmgr->fd, prime_fd, &handle);1208if (ret) {1209DBG("import_dmabuf: failed to obtain handle from fd: %s\n",1210strerror(errno));1211simple_mtx_unlock(&bufmgr->lock);1212return NULL;1213}12141215/*1216* See if the kernel has already returned this buffer to us. Just as1217* for named buffers, we must not create two bo's pointing at the same1218* kernel object1219*/1220bo = find_and_ref_external_bo(bufmgr->handle_table, handle);1221if (bo)1222goto out;12231224bo = bo_calloc();1225if (!bo)1226goto out;12271228p_atomic_set(&bo->refcount, 1);12291230/* Determine size of bo. The fd-to-handle ioctl really should1231* return the size, but it doesn't. If we have kernel 3.12 or1232* later, we can lseek on the prime fd to get the size. Older1233* kernels will just fail, in which case we fall back to the1234* provided (estimated or guess size). */1235ret = lseek(prime_fd, 0, SEEK_END);1236if (ret != -1)1237bo->size = ret;12381239bo->bufmgr = bufmgr;1240bo->name = "prime";1241bo->reusable = false;1242bo->external = true;1243bo->kflags = 0;1244bo->gem_handle = handle;1245_mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo);12461247const struct isl_drm_modifier_info *mod_info =1248isl_drm_modifier_get_info(modifier);1249if (mod_info) {1250bo->tiling_mode = isl_tiling_to_i915_tiling(mod_info->tiling);1251} else if (bufmgr->has_tiling_uapi) {1252struct drm_i915_gem_get_tiling get_tiling = { .handle = bo->gem_handle };1253if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling))1254goto err;12551256bo->tiling_mode = get_tiling.tiling_mode;1257} else {1258bo->tiling_mode = I915_TILING_NONE;1259}12601261out:1262simple_mtx_unlock(&bufmgr->lock);1263return bo;12641265err:1266bo_free(bo);1267simple_mtx_unlock(&bufmgr->lock);1268return NULL;1269}12701271struct crocus_bo *1272crocus_bo_import_dmabuf_no_mods(struct crocus_bufmgr *bufmgr,1273int prime_fd)1274{1275uint32_t handle;1276struct crocus_bo *bo;12771278simple_mtx_lock(&bufmgr->lock);1279int ret = drmPrimeFDToHandle(bufmgr->fd, prime_fd, &handle);1280if (ret) {1281DBG("import_dmabuf: failed to obtain handle from fd: %s\n",1282strerror(errno));1283simple_mtx_unlock(&bufmgr->lock);1284return NULL;1285}12861287/*1288* See if the kernel has already returned this buffer to us. Just as1289* for named buffers, we must not create two bo's pointing at the same1290* kernel object1291*/1292bo = find_and_ref_external_bo(bufmgr->handle_table, handle);1293if (bo)1294goto out;12951296bo = bo_calloc();1297if (!bo)1298goto out;12991300p_atomic_set(&bo->refcount, 1);13011302/* Determine size of bo. The fd-to-handle ioctl really should1303* return the size, but it doesn't. If we have kernel 3.12 or1304* later, we can lseek on the prime fd to get the size. Older1305* kernels will just fail, in which case we fall back to the1306* provided (estimated or guess size). */1307ret = lseek(prime_fd, 0, SEEK_END);1308if (ret != -1)1309bo->size = ret;13101311bo->bufmgr = bufmgr;1312bo->name = "prime";1313bo->reusable = false;1314bo->external = true;1315bo->kflags = 0;1316bo->gem_handle = handle;1317_mesa_hash_table_insert(bufmgr->handle_table, &bo->gem_handle, bo);13181319out:1320simple_mtx_unlock(&bufmgr->lock);1321return bo;1322}13231324static void1325crocus_bo_make_external_locked(struct crocus_bo *bo)1326{1327if (!bo->external) {1328_mesa_hash_table_insert(bo->bufmgr->handle_table, &bo->gem_handle, bo);1329bo->external = true;1330bo->reusable = false;1331}1332}13331334static void1335crocus_bo_make_external(struct crocus_bo *bo)1336{1337struct crocus_bufmgr *bufmgr = bo->bufmgr;13381339if (bo->external) {1340assert(!bo->reusable);1341return;1342}13431344simple_mtx_lock(&bufmgr->lock);1345crocus_bo_make_external_locked(bo);1346simple_mtx_unlock(&bufmgr->lock);1347}13481349int1350crocus_bo_export_dmabuf(struct crocus_bo *bo, int *prime_fd)1351{1352struct crocus_bufmgr *bufmgr = bo->bufmgr;13531354crocus_bo_make_external(bo);13551356if (drmPrimeHandleToFD(bufmgr->fd, bo->gem_handle,1357DRM_CLOEXEC, prime_fd) != 0)1358return -errno;13591360return 0;1361}13621363uint32_t1364crocus_bo_export_gem_handle(struct crocus_bo *bo)1365{1366crocus_bo_make_external(bo);13671368return bo->gem_handle;1369}13701371int1372crocus_bo_flink(struct crocus_bo *bo, uint32_t *name)1373{1374struct crocus_bufmgr *bufmgr = bo->bufmgr;13751376if (!bo->global_name) {1377struct drm_gem_flink flink = { .handle = bo->gem_handle };13781379if (intel_ioctl(bufmgr->fd, DRM_IOCTL_GEM_FLINK, &flink))1380return -errno;13811382simple_mtx_lock(&bufmgr->lock);1383if (!bo->global_name) {1384crocus_bo_make_external_locked(bo);1385bo->global_name = flink.name;1386_mesa_hash_table_insert(bufmgr->name_table, &bo->global_name, bo);1387}1388simple_mtx_unlock(&bufmgr->lock);1389}13901391*name = bo->global_name;1392return 0;1393}13941395int1396crocus_bo_export_gem_handle_for_device(struct crocus_bo *bo, int drm_fd,1397uint32_t *out_handle)1398{1399/* Only add the new GEM handle to the list of export if it belongs to a1400* different GEM device. Otherwise we might close the same buffer multiple1401* times.1402*/1403struct crocus_bufmgr *bufmgr = bo->bufmgr;1404int ret = os_same_file_description(drm_fd, bufmgr->fd);1405WARN_ONCE(ret < 0,1406"Kernel has no file descriptor comparison support: %s\n",1407strerror(errno));1408if (ret == 0) {1409*out_handle = crocus_bo_export_gem_handle(bo);1410return 0;1411}14121413struct bo_export *export = calloc(1, sizeof(*export));1414if (!export)1415return -ENOMEM;14161417export->drm_fd = drm_fd;14181419int dmabuf_fd = -1;1420int err = crocus_bo_export_dmabuf(bo, &dmabuf_fd);1421if (err) {1422free(export);1423return err;1424}14251426simple_mtx_lock(&bufmgr->lock);1427err = drmPrimeFDToHandle(drm_fd, dmabuf_fd, &export->gem_handle);1428close(dmabuf_fd);1429if (err) {1430simple_mtx_unlock(&bufmgr->lock);1431free(export);1432return err;1433}14341435bool found = false;1436list_for_each_entry(struct bo_export, iter, &bo->exports, link) {1437if (iter->drm_fd != drm_fd)1438continue;1439/* Here we assume that for a given DRM fd, we'll always get back the1440* same GEM handle for a given buffer.1441*/1442assert(iter->gem_handle == export->gem_handle);1443free(export);1444export = iter;1445found = true;1446break;1447}1448if (!found)1449list_addtail(&export->link, &bo->exports);14501451simple_mtx_unlock(&bufmgr->lock);14521453*out_handle = export->gem_handle;14541455return 0;1456}14571458static void1459add_bucket(struct crocus_bufmgr *bufmgr, int size)1460{1461unsigned int i = bufmgr->num_buckets;14621463assert(i < ARRAY_SIZE(bufmgr->cache_bucket));14641465list_inithead(&bufmgr->cache_bucket[i].head);1466bufmgr->cache_bucket[i].size = size;1467bufmgr->num_buckets++;14681469assert(bucket_for_size(bufmgr, size) == &bufmgr->cache_bucket[i]);1470assert(bucket_for_size(bufmgr, size - 2048) == &bufmgr->cache_bucket[i]);1471assert(bucket_for_size(bufmgr, size + 1) != &bufmgr->cache_bucket[i]);1472}14731474static void1475init_cache_buckets(struct crocus_bufmgr *bufmgr)1476{1477uint64_t size, cache_max_size = 64 * 1024 * 1024;14781479/* OK, so power of two buckets was too wasteful of memory.1480* Give 3 other sizes between each power of two, to hopefully1481* cover things accurately enough. (The alternative is1482* probably to just go for exact matching of sizes, and assume1483* that for things like composited window resize the tiled1484* width/height alignment and rounding of sizes to pages will1485* get us useful cache hit rates anyway)1486*/1487add_bucket(bufmgr, PAGE_SIZE);1488add_bucket(bufmgr, PAGE_SIZE * 2);1489add_bucket(bufmgr, PAGE_SIZE * 3);14901491/* Initialize the linked lists for BO reuse cache. */1492for (size = 4 * PAGE_SIZE; size <= cache_max_size; size *= 2) {1493add_bucket(bufmgr, size);14941495add_bucket(bufmgr, size + size * 1 / 4);1496add_bucket(bufmgr, size + size * 2 / 4);1497add_bucket(bufmgr, size + size * 3 / 4);1498}1499}15001501uint32_t1502crocus_create_hw_context(struct crocus_bufmgr *bufmgr)1503{1504struct drm_i915_gem_context_create create = { };1505int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);1506if (ret != 0) {1507DBG("DRM_IOCTL_I915_GEM_CONTEXT_CREATE failed: %s\n", strerror(errno));1508return 0;1509}15101511/* Upon declaring a GPU hang, the kernel will zap the guilty context1512* back to the default logical HW state and attempt to continue on to1513* our next submitted batchbuffer. However, our render batches assume1514* the previous GPU state is preserved, and only emit commands needed1515* to incrementally change that state. In particular, we inherit the1516* STATE_BASE_ADDRESS and PIPELINE_SELECT settings, which are critical.1517* With default base addresses, our next batches will almost certainly1518* cause more GPU hangs, leading to repeated hangs until we're banned1519* or the machine is dead.1520*1521* Here we tell the kernel not to attempt to recover our context but1522* immediately (on the next batchbuffer submission) report that the1523* context is lost, and we will do the recovery ourselves. Ideally,1524* we'll have two lost batches instead of a continual stream of hangs.1525*/1526struct drm_i915_gem_context_param p = {1527.ctx_id = create.ctx_id,1528.param = I915_CONTEXT_PARAM_RECOVERABLE,1529.value = false,1530};1531drmIoctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p);15321533return create.ctx_id;1534}15351536static int1537crocus_hw_context_get_priority(struct crocus_bufmgr *bufmgr, uint32_t ctx_id)1538{1539struct drm_i915_gem_context_param p = {1540.ctx_id = ctx_id,1541.param = I915_CONTEXT_PARAM_PRIORITY,1542};1543drmIoctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p);1544return p.value; /* on error, return 0 i.e. default priority */1545}15461547int1548crocus_hw_context_set_priority(struct crocus_bufmgr *bufmgr,1549uint32_t ctx_id,1550int priority)1551{1552struct drm_i915_gem_context_param p = {1553.ctx_id = ctx_id,1554.param = I915_CONTEXT_PARAM_PRIORITY,1555.value = priority,1556};1557int err;15581559err = 0;1560if (intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p))1561err = -errno;15621563return err;1564}15651566uint32_t1567crocus_clone_hw_context(struct crocus_bufmgr *bufmgr, uint32_t ctx_id)1568{1569uint32_t new_ctx = crocus_create_hw_context(bufmgr);15701571if (new_ctx) {1572int priority = crocus_hw_context_get_priority(bufmgr, ctx_id);1573crocus_hw_context_set_priority(bufmgr, new_ctx, priority);1574}15751576return new_ctx;1577}15781579void1580crocus_destroy_hw_context(struct crocus_bufmgr *bufmgr, uint32_t ctx_id)1581{1582struct drm_i915_gem_context_destroy d = { .ctx_id = ctx_id };15831584if (ctx_id != 0 &&1585intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &d) != 0) {1586fprintf(stderr, "DRM_IOCTL_I915_GEM_CONTEXT_DESTROY failed: %s\n",1587strerror(errno));1588}1589}15901591int1592crocus_reg_read(struct crocus_bufmgr *bufmgr, uint32_t offset, uint64_t *result)1593{1594struct drm_i915_reg_read reg_read = { .offset = offset };1595int ret = intel_ioctl(bufmgr->fd, DRM_IOCTL_I915_REG_READ, ®_read);15961597*result = reg_read.val;1598return ret;1599}16001601static int1602gem_param(int fd, int name)1603{1604int v = -1; /* No param uses (yet) the sign bit, reserve it for errors */16051606struct drm_i915_getparam gp = { .param = name, .value = &v };1607if (intel_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))1608return -1;16091610return v;1611}16121613/**1614* Initializes the GEM buffer manager, which uses the kernel to allocate, map,1615* and manage map buffer objections.1616*1617* \param fd File descriptor of the opened DRM device.1618*/1619static struct crocus_bufmgr *1620crocus_bufmgr_create(struct intel_device_info *devinfo, int fd, bool bo_reuse)1621{1622struct crocus_bufmgr *bufmgr = calloc(1, sizeof(*bufmgr));1623if (bufmgr == NULL)1624return NULL;16251626/* Handles to buffer objects belong to the device fd and are not1627* reference counted by the kernel. If the same fd is used by1628* multiple parties (threads sharing the same screen bufmgr, or1629* even worse the same device fd passed to multiple libraries)1630* ownership of those handles is shared by those independent parties.1631*1632* Don't do this! Ensure that each library/bufmgr has its own device1633* fd so that its namespace does not clash with another.1634*/1635bufmgr->fd = os_dupfd_cloexec(fd);16361637p_atomic_set(&bufmgr->refcount, 1);16381639simple_mtx_init(&bufmgr->lock, mtx_plain);16401641list_inithead(&bufmgr->zombie_list);16421643bufmgr->has_llc = devinfo->has_llc;1644bufmgr->has_tiling_uapi = devinfo->has_tiling_uapi;1645bufmgr->bo_reuse = bo_reuse;1646bufmgr->has_mmap_offset = gem_param(fd, I915_PARAM_MMAP_GTT_VERSION) >= 4;16471648init_cache_buckets(bufmgr);16491650bufmgr->name_table =1651_mesa_hash_table_create(NULL, key_hash_uint, key_uint_equal);1652bufmgr->handle_table =1653_mesa_hash_table_create(NULL, key_hash_uint, key_uint_equal);16541655return bufmgr;1656}16571658static struct crocus_bufmgr *1659crocus_bufmgr_ref(struct crocus_bufmgr *bufmgr)1660{1661p_atomic_inc(&bufmgr->refcount);1662return bufmgr;1663}16641665void1666crocus_bufmgr_unref(struct crocus_bufmgr *bufmgr)1667{1668simple_mtx_lock(&global_bufmgr_list_mutex);1669if (p_atomic_dec_zero(&bufmgr->refcount)) {1670list_del(&bufmgr->link);1671crocus_bufmgr_destroy(bufmgr);1672}1673simple_mtx_unlock(&global_bufmgr_list_mutex);1674}16751676/**1677* Gets an already existing GEM buffer manager or create a new one.1678*1679* \param fd File descriptor of the opened DRM device.1680*/1681struct crocus_bufmgr *1682crocus_bufmgr_get_for_fd(struct intel_device_info *devinfo, int fd, bool bo_reuse)1683{1684struct stat st;16851686if (fstat(fd, &st))1687return NULL;16881689struct crocus_bufmgr *bufmgr = NULL;16901691simple_mtx_lock(&global_bufmgr_list_mutex);1692list_for_each_entry(struct crocus_bufmgr, iter_bufmgr, &global_bufmgr_list, link) {1693struct stat iter_st;1694if (fstat(iter_bufmgr->fd, &iter_st))1695continue;16961697if (st.st_rdev == iter_st.st_rdev) {1698assert(iter_bufmgr->bo_reuse == bo_reuse);1699bufmgr = crocus_bufmgr_ref(iter_bufmgr);1700goto unlock;1701}1702}17031704bufmgr = crocus_bufmgr_create(devinfo, fd, bo_reuse);1705if (bufmgr)1706list_addtail(&bufmgr->link, &global_bufmgr_list);17071708unlock:1709simple_mtx_unlock(&global_bufmgr_list_mutex);17101711return bufmgr;1712}17131714int1715crocus_bufmgr_get_fd(struct crocus_bufmgr *bufmgr)1716{1717return bufmgr->fd;1718}171917201721