1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * © Copyright 2018 Alyssa Rosenzweig 3bf215546Sopenharmony_ci * Copyright (C) 2019 Collabora, Ltd. 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22bf215546Sopenharmony_ci * SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <unistd.h> 27bf215546Sopenharmony_ci#include <sys/mman.h> 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "pan_device.h" 30bf215546Sopenharmony_ci#include "pan_mempool.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci/* Knockoff u_upload_mgr. Uploads wherever we left off, allocating new entries 33bf215546Sopenharmony_ci * when needed. 34bf215546Sopenharmony_ci * 35bf215546Sopenharmony_ci * In "owned" mode, a single parent owns the entire pool, and the pool owns all 36bf215546Sopenharmony_ci * created BOs. All BOs are tracked and addable as 37bf215546Sopenharmony_ci * panfrost_pool_get_bo_handles. Freeing occurs at the level of an entire pool. 38bf215546Sopenharmony_ci * This is useful for streaming uploads, where the batch owns the pool. 39bf215546Sopenharmony_ci * 40bf215546Sopenharmony_ci * In "unowned" mode, the pool is freestanding. It does not track created BOs 41bf215546Sopenharmony_ci * or hold references. Instead, the consumer must manage the created BOs. This 42bf215546Sopenharmony_ci * is more flexible, enabling non-transient CSO state or shader code to be 43bf215546Sopenharmony_ci * packed with conservative lifetime handling. 44bf215546Sopenharmony_ci */ 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_cistatic struct panfrost_bo * 47bf215546Sopenharmony_cipanfrost_pool_alloc_backing(struct panfrost_pool *pool, size_t bo_sz) 48bf215546Sopenharmony_ci{ 49bf215546Sopenharmony_ci /* We don't know what the BO will be used for, so let's flag it 50bf215546Sopenharmony_ci * RW and attach it to both the fragment and vertex/tiler jobs. 51bf215546Sopenharmony_ci * TODO: if we want fine grained BO assignment we should pass 52bf215546Sopenharmony_ci * flags to this function and keep the read/write, 53bf215546Sopenharmony_ci * fragment/vertex+tiler pools separate. 54bf215546Sopenharmony_ci */ 55bf215546Sopenharmony_ci struct panfrost_bo *bo = panfrost_bo_create(pool->base.dev, bo_sz, 56bf215546Sopenharmony_ci pool->base.create_flags, pool->base.label); 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci if (pool->owned) 59bf215546Sopenharmony_ci util_dynarray_append(&pool->bos, struct panfrost_bo *, bo); 60bf215546Sopenharmony_ci else 61bf215546Sopenharmony_ci panfrost_bo_unreference(pool->transient_bo); 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci pool->transient_bo = bo; 64bf215546Sopenharmony_ci pool->transient_offset = 0; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci return bo; 67bf215546Sopenharmony_ci} 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_civoid 70bf215546Sopenharmony_cipanfrost_pool_init(struct panfrost_pool *pool, void *memctx, 71bf215546Sopenharmony_ci struct panfrost_device *dev, 72bf215546Sopenharmony_ci unsigned create_flags, size_t slab_size, const char *label, 73bf215546Sopenharmony_ci bool prealloc, bool owned) 74bf215546Sopenharmony_ci{ 75bf215546Sopenharmony_ci memset(pool, 0, sizeof(*pool)); 76bf215546Sopenharmony_ci pan_pool_init(&pool->base, dev, create_flags, slab_size, label); 77bf215546Sopenharmony_ci pool->owned = owned; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci if (owned) 80bf215546Sopenharmony_ci util_dynarray_init(&pool->bos, memctx); 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci if (prealloc) 83bf215546Sopenharmony_ci panfrost_pool_alloc_backing(pool, pool->base.slab_size); 84bf215546Sopenharmony_ci} 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_civoid 87bf215546Sopenharmony_cipanfrost_pool_cleanup(struct panfrost_pool *pool) 88bf215546Sopenharmony_ci{ 89bf215546Sopenharmony_ci if (!pool->owned) { 90bf215546Sopenharmony_ci panfrost_bo_unreference(pool->transient_bo); 91bf215546Sopenharmony_ci return; 92bf215546Sopenharmony_ci } 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci util_dynarray_foreach(&pool->bos, struct panfrost_bo *, bo) 95bf215546Sopenharmony_ci panfrost_bo_unreference(*bo); 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci util_dynarray_fini(&pool->bos); 98bf215546Sopenharmony_ci} 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_civoid 101bf215546Sopenharmony_cipanfrost_pool_get_bo_handles(struct panfrost_pool *pool, uint32_t *handles) 102bf215546Sopenharmony_ci{ 103bf215546Sopenharmony_ci assert(pool->owned && "pool does not track BOs in unowned mode"); 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci unsigned idx = 0; 106bf215546Sopenharmony_ci util_dynarray_foreach(&pool->bos, struct panfrost_bo *, bo) { 107bf215546Sopenharmony_ci assert((*bo)->gem_handle > 0); 108bf215546Sopenharmony_ci handles[idx++] = (*bo)->gem_handle; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci /* Update the BO access flags so that panfrost_bo_wait() knows 111bf215546Sopenharmony_ci * about all pending accesses. 112bf215546Sopenharmony_ci * We only keep the READ/WRITE info since this is all the BO 113bf215546Sopenharmony_ci * wait logic cares about. 114bf215546Sopenharmony_ci * We also preserve existing flags as this batch might not 115bf215546Sopenharmony_ci * be the first one to access the BO. 116bf215546Sopenharmony_ci */ 117bf215546Sopenharmony_ci (*bo)->gpu_access |= PAN_BO_ACCESS_RW; 118bf215546Sopenharmony_ci } 119bf215546Sopenharmony_ci} 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci#define PAN_GUARD_SIZE 4096 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_cistatic struct panfrost_ptr 124bf215546Sopenharmony_cipanfrost_pool_alloc_aligned(struct panfrost_pool *pool, size_t sz, unsigned alignment) 125bf215546Sopenharmony_ci{ 126bf215546Sopenharmony_ci assert(alignment == util_next_power_of_two(alignment)); 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci /* Find or create a suitable BO */ 129bf215546Sopenharmony_ci struct panfrost_bo *bo = pool->transient_bo; 130bf215546Sopenharmony_ci unsigned offset = ALIGN_POT(pool->transient_offset, alignment); 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci#ifdef PAN_DBG_OVERFLOW 133bf215546Sopenharmony_ci if (unlikely(pool->base.dev->debug & PAN_DBG_OVERFLOW) && 134bf215546Sopenharmony_ci !(pool->base.create_flags & PAN_BO_INVISIBLE)) { 135bf215546Sopenharmony_ci unsigned aligned = ALIGN_POT(sz, sysconf(_SC_PAGESIZE)); 136bf215546Sopenharmony_ci unsigned bo_size = aligned + PAN_GUARD_SIZE; 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci bo = panfrost_pool_alloc_backing(pool, bo_size); 139bf215546Sopenharmony_ci memset(bo->ptr.cpu, 0xbb, bo_size); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci /* Place the object as close as possible to the protected 142bf215546Sopenharmony_ci * region at the end of the buffer while keeping alignment. */ 143bf215546Sopenharmony_ci offset = ROUND_DOWN_TO(aligned - sz, alignment); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci if (mprotect(bo->ptr.cpu + aligned, 146bf215546Sopenharmony_ci PAN_GUARD_SIZE, PROT_NONE) == -1) 147bf215546Sopenharmony_ci perror("mprotect"); 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci pool->transient_bo = NULL; 150bf215546Sopenharmony_ci } 151bf215546Sopenharmony_ci#endif 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci /* If we don't fit, allocate a new backing */ 154bf215546Sopenharmony_ci if (unlikely(bo == NULL || (offset + sz) >= pool->base.slab_size)) { 155bf215546Sopenharmony_ci bo = panfrost_pool_alloc_backing(pool, 156bf215546Sopenharmony_ci ALIGN_POT(MAX2(pool->base.slab_size, sz), 4096)); 157bf215546Sopenharmony_ci offset = 0; 158bf215546Sopenharmony_ci } 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci pool->transient_offset = offset + sz; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci struct panfrost_ptr ret = { 163bf215546Sopenharmony_ci .cpu = bo->ptr.cpu + offset, 164bf215546Sopenharmony_ci .gpu = bo->ptr.gpu + offset, 165bf215546Sopenharmony_ci }; 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci return ret; 168bf215546Sopenharmony_ci} 169bf215546Sopenharmony_ciPAN_POOL_ALLOCATOR(struct panfrost_pool, panfrost_pool_alloc_aligned) 170