1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2015-2019 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 /*! 25 * @file poolalloc.h 26 * @brief This file contains the interfaces for pool allocator. 27 * A chained sub-allocator originally designed to sub-allocate GPU 28 * frame buffer given out by PMA (physical memory allocator). 29 * 30 * The only requirement of a node in the chained allocator is that the ratio 31 * between upSTreamPageSize and allocPageSize is less or equal to 64. 32 * 33 * @bug Make more abstract -- fix up the variable names 34 */ 35 36 37 #ifndef _NV_POOLALLOC_H_ 38 #define _NV_POOLALLOC_H_ 39 40 #include "nvtypes.h" 41 #include "nvstatus.h" 42 #include "nvport/nvport.h" 43 #include "containers/list.h" 44 45 #ifdef __cplusplus 46 extern "C" { 47 #endif 48 49 typedef struct poolnode POOLNODE; 50 51 /*! 52 * Each node corresponds to one page of upStreamPageSize 53 * The pool allocator sub-allocates from each of these pages. 54 */ 55 struct poolnode 56 { 57 NvU64 pageAddr; // Address of the page to sub-allocate 58 NvU64 bitmap; // The bit map for this page. Only used if the 59 // node represents a partially allocated node 60 POOLNODE *pParent; // The upstream pool node in case this node is 61 // allocated from the upper pool. 62 ListNode node; // For intrusive lists. 63 }; 64 65 MAKE_INTRUSIVE_LIST(PoolNodeList, POOLNODE, node); 66 67 /*! 68 * The handle contains a generic metadata field that is needed for fast 69 * access. In the case of a linked list implementation of the pool allocator, 70 * the metadata is the pointer to the node that contains the page it was 71 * sub-allocated from 72 */ 73 typedef struct poolallocHandle 74 { 75 NvU64 address; // The base address for this chunk 76 void *pMetadata; // The opaque metadata for storing necessary info 77 } POOLALLOC_HANDLE; 78 79 80 // non-intrusive list of page handles 81 MAKE_LIST(PoolPageHandleList, POOLALLOC_HANDLE); 82 83 /*! 84 * @brief Callback function to upstream allocators for allocating new pages 85 * 86 * This function only allocate 1 page at a time right now 87 * 88 * @param[in] ctxPtr Provides context to upstream allocator 89 * @param[in] pageSize Not really needed. For debugging only 90 * @param[out] pPage The output page handle from upstream 91 * 92 * @return NV_OK if successfully allocated NvF32 totalTest, doneTest, failTest; the page 93 * NV_ERR_NO_MEMORY if allocator cannot allocate enough backing 94 * NV_ERR_BAD_PARAM if any parameter is invalid or size info is not 95 * multiple of SMALLEST_PAGE_SIZE 96 * 97 */ 98 typedef NV_STATUS (*allocCallback_t)(void *ctxPtr, NvU64 pageSize, 99 POOLALLOC_HANDLE *pPage); 100 101 /*! 102 * @brief Callback function to upstream allocators for freeing unused pages 103 * 104 * This function only allocate 1 page at a time right now 105 * 106 * @param[in] ctxPtr Provides context to upstream allocator 107 * @param[in] pageSize Not really needed. For debugging only 108 * @param[in] pPage The input page handle to be freed 109 * 110 */ 111 typedef void (*freeCallback_t)(void *ctxPtr, NvU64 pageSize, POOLALLOC_HANDLE *pPage); 112 113 /*! 114 * Structure representing a pool. 115 */ 116 typedef struct poolalloc 117 { 118 PoolNodeList freeList; // List of nodes representing free pages 119 PoolNodeList fullList; // List of nodes representing fully allocated pages 120 PoolNodeList partialList; // List of nodes representing partially allocated pages 121 122 PORT_MEM_ALLOCATOR *pAllocator; 123 124 struct 125 { 126 allocCallback_t allocCb; // Callback to upstream allocator 127 freeCallback_t freeCb; // Callback to free pages 128 void *pUpstreamCtx; // The context to pass to upstream allocator 129 } callBackInfo; 130 131 NvU64 upstreamPageSize; // Page size for upstream allocations 132 NvU64 allocPageSize; // Page size to give out 133 NvU32 ratio; // Ratio == upstreamPageSize / allocPageSize 134 NvU32 flags; // POOLALLOC_FLAGS_* 135 } POOLALLOC; 136 137 138 /*! 139 * Dump the lists maintained by the pools. 140 */ 141 void poolAllocPrint(POOLALLOC *pPool); 142 143 /*! 144 * If _AUTO_POPULATE is set to ENABLE then poolAllocate will call upstream function to repopulate 145 * the pool when it runs out of memory. If set to DISABLE, poolAllocate will fail when it runs out of memory 146 * By default this is disabled as for usecases like page tables or context buffers since upstream function can call 147 * into PMA with GPU lock held which has a possibility of deadlocking 148 */ 149 #define NV_RMPOOL_FLAGS_AUTO_POPULATE 1:0 150 #define NV_RMPOOL_FLAGS_AUTO_POPULATE_DEFAULT 0x0 151 #define NV_RMPOOL_FLAGS_AUTO_POPULATE_DISABLE 0x0 152 #define NV_RMPOOL_FLAGS_AUTO_POPULATE_ENABLE 0x1 153 154 /*! 155 * @brief This function initializes a pool allocator object 156 * 157 * This function establishes a link from this allocator to its upstream 158 * allocator by registering a callback function that lazily allocates memory 159 * if needed. 160 * 161 * @param[in] upstreamPageSize The page size granularity managed by 162 * the allocator 163 * @param[in] allocPageSize The page size to hand out 164 * @param[in] allocCb The allocation callback function 165 * @param[in] freeCb The free callback function 166 * @param[in] pUpstreamCtxPtr The context pointer for the upstream 167 * allocator, passed back on callback 168 * @param[in] mallocFun The allocator for internal strutures 169 * @param[in] freeFun The free for internal structures 170 * @param[in] pAllocCtxPtr The context pointer for the special 171 * allocator 172 * @param[in] flags POOLALLOC_FLAGS_* 173 * 174 * @return A pointer to a POOLALLOC structure if the initialization 175 * succeeded; NULL otherwise 176 * 177 */ 178 179 POOLALLOC *poolInitialize(NvU64 upstreamPageSize, NvU64 allocPageSize, 180 allocCallback_t allocCb, freeCallback_t freeCb, void *pUpstreamCtxPtr, 181 PORT_MEM_ALLOCATOR *pAllocator, NvU32 flags); 182 183 184 /*! 185 * @brief Reserves numPages from upstream allocator. After the call 186 * freeListSize will equal to/greater than numPages. 187 * 188 * Since it will call into the upstream allocator, the page size of those 189 * pages will be the upstream page size. 190 * 191 * @param[in] pPool The pool allocator 192 * @param[out] numPages Number of pages to reserve 193 * 194 * @return NV_OK if successful 195 * NV_ERR_NO_MEMORY if allocator cannot allocate enough backing 196 * NV_ERR_BAD_PARAM if any parameter is invalid 197 * 198 */ 199 NV_STATUS poolReserve(POOLALLOC *pPool, NvU64 numPages); 200 201 202 /*! 203 * @brief This call will give back any free pages. After the call 204 * freeListSize will be less or equal to preserveNum. 205 * 206 * If the allocator has less or equal number of pages than preserveNum before 207 * the call, this function will simply return. 208 * 209 * @param[in] pPool The pool allocator to trim from 210 * @param[in] preserveNum The number of pages that we try to preserve 211 */ 212 void poolTrim(POOLALLOC *pPool, NvU64 preserveNum); 213 214 215 /*! 216 * @brief This function allocates memory from the allocator and returns one 217 * page of the fixed allocPageSize as specified in the initialization function 218 * 219 * The implementation does not guarantee the allocated pages are contiguous. 220 * Although there is no potential synchronization issues, if two allocation 221 * happen to lie on upstream page bundaries, the allocation will most likely 222 * be discontiguous. 223 * 224 * This function will also callback to upstream allocator to get more pages if 225 * it does not have enough pages already reserved. 226 * 227 * @param[in] pPool The pool allocator 228 * @param[out] pPageHandle The allocation handle that contains address and 229 * metadata for optimization 230 * 231 * @return NV_OK if successful 232 * NV_ERR_NO_MEMORY if allocator cannot allocate enough backing 233 * NV_ERR_BAD_PARAM if any parameter is invalid 234 */ 235 NV_STATUS poolAllocate(POOLALLOC *pPool, POOLALLOC_HANDLE *pPageHandle); 236 237 238 /*! 239 * @brief This function allocates memory from the allocator and returns numPages 240 * of the fixed allocPageSize as specified in the initialization function 241 * 242 * These pages are allocated contiguously and the single start address is returned. 243 * Although there is no potential synchronization issues, if two allocation 244 * happen to lie on upstream page bundaries, the allocation will most likely 245 * be discontiguous. 246 * 247 * This function will not callback to upstream allocator to get more pages as 248 * this is relying on a single chunk of free pages to make contiguous allocations. 249 * So the max number of pages that can be allocated contiguously is the number of pages 250 * fit in upstream page size i.e the "ratio" of this pool 251 * 252 * @param[in] pPool The pool allocator 253 * @param[in] numPages The number of pages requested to be allocated 254 * @param[out] pPageHandleList The allocation handles that contain addresses and 255 * metadata for optimization 256 * 257 * @return NV_OK if successful 258 * NV_ERR_NO_MEMORY if allocator cannot allocate enough backing 259 * NV_ERR_BAD_PARAM if any parameter is invalid 260 */ 261 NV_STATUS poolAllocateContig(POOLALLOC *pPool, NvU32 numPages, PoolPageHandleList *pPageHandleList); 262 263 /*! 264 * @brief This function frees the page based on the allocPageSize 265 * 266 * @param[in] pPool The pool allocator 267 * @param[out] pPageHandle The allocation handle that contains address and 268 * metadata for optimization 269 * 270 */ 271 void poolFree(POOLALLOC *pPool, POOLALLOC_HANDLE *pPageHandle); 272 273 274 /*! 275 * @brief Destroys the pool allocator and frees memory 276 */ 277 void poolDestroy(POOLALLOC *pPool); 278 279 /*! 280 * @briefs Returns the lengths of a pool's lists 281 */ 282 void poolGetListLength(POOLALLOC *pPool, NvU32 *pFreeListLength, 283 NvU32 *pPartialListLength, NvU32 *pFullListLength); 284 285 #ifdef __cplusplus 286 } 287 #endif 288 289 #endif /* _NV_POOLALLOC_H_ */ 290