18c2ecf20Sopenharmony_ci/***********************license start*************** 28c2ecf20Sopenharmony_ci * Author: Cavium Networks 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Contact: support@caviumnetworks.com 58c2ecf20Sopenharmony_ci * This file is part of the OCTEON SDK 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2003-2008 Cavium Networks 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License, Version 2, as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 158c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 168c2ecf20Sopenharmony_ci * NONINFRINGEMENT. See the GNU General Public License for more 178c2ecf20Sopenharmony_ci * details. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 208c2ecf20Sopenharmony_ci * along with this file; if not, write to the Free Software 218c2ecf20Sopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 228c2ecf20Sopenharmony_ci * or visit http://www.gnu.org/licenses/. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This file may also be available under a different license from Cavium. 258c2ecf20Sopenharmony_ci * Contact Cavium Networks for more information 268c2ecf20Sopenharmony_ci ***********************license end**************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Simple allocate only memory allocator. Used to allocate memory at 308c2ecf20Sopenharmony_ci * application start time. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/export.h> 348c2ecf20Sopenharmony_ci#include <linux/kernel.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx.h> 378c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-spinlock.h> 388c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-bootmem.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/*#define DEBUG */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct cvmx_bootmem_desc *cvmx_bootmem_desc; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* See header file for descriptions of functions */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/** 488c2ecf20Sopenharmony_ci * This macro returns a member of the 498c2ecf20Sopenharmony_ci * cvmx_bootmem_named_block_desc_t structure. These members can't 508c2ecf20Sopenharmony_ci * be directly addressed as they might be in memory not directly 518c2ecf20Sopenharmony_ci * reachable. In the case where bootmem is compiled with 528c2ecf20Sopenharmony_ci * LINUX_HOST, the structure itself might be located on a remote 538c2ecf20Sopenharmony_ci * Octeon. The argument "field" is the member name of the 548c2ecf20Sopenharmony_ci * cvmx_bootmem_named_block_desc_t to read. Regardless of the type 558c2ecf20Sopenharmony_ci * of the field, the return type is always a uint64_t. The "addr" 568c2ecf20Sopenharmony_ci * parameter is the physical address of the structure. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci#define CVMX_BOOTMEM_NAMED_GET_FIELD(addr, field) \ 598c2ecf20Sopenharmony_ci __cvmx_bootmem_desc_get(addr, \ 608c2ecf20Sopenharmony_ci offsetof(struct cvmx_bootmem_named_block_desc, field), \ 618c2ecf20Sopenharmony_ci sizeof_field(struct cvmx_bootmem_named_block_desc, field)) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * This function is the implementation of the get macros defined 658c2ecf20Sopenharmony_ci * for individual structure members. The argument are generated 668c2ecf20Sopenharmony_ci * by the macros inorder to read only the needed memory. 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * @param base 64bit physical address of the complete structure 698c2ecf20Sopenharmony_ci * @param offset Offset from the beginning of the structure to the member being 708c2ecf20Sopenharmony_ci * accessed. 718c2ecf20Sopenharmony_ci * @param size Size of the structure member. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * @return Value of the structure member promoted into a uint64_t. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic inline uint64_t __cvmx_bootmem_desc_get(uint64_t base, int offset, 768c2ecf20Sopenharmony_ci int size) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci base = (1ull << 63) | (base + offset); 798c2ecf20Sopenharmony_ci switch (size) { 808c2ecf20Sopenharmony_ci case 4: 818c2ecf20Sopenharmony_ci return cvmx_read64_uint32(base); 828c2ecf20Sopenharmony_ci case 8: 838c2ecf20Sopenharmony_ci return cvmx_read64_uint64(base); 848c2ecf20Sopenharmony_ci default: 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Wrapper functions are provided for reading/writing the size and 918c2ecf20Sopenharmony_ci * next block values as these may not be directly addressible (in 32 928c2ecf20Sopenharmony_ci * bit applications, for instance.) Offsets of data elements in 938c2ecf20Sopenharmony_ci * bootmem list, must match cvmx_bootmem_block_header_t. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci#define NEXT_OFFSET 0 968c2ecf20Sopenharmony_ci#define SIZE_OFFSET 8 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void cvmx_bootmem_phy_set_size(uint64_t addr, uint64_t size) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci cvmx_write64_uint64((addr + SIZE_OFFSET) | (1ull << 63), size); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void cvmx_bootmem_phy_set_next(uint64_t addr, uint64_t next) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci cvmx_write64_uint64((addr + NEXT_OFFSET) | (1ull << 63), next); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic uint64_t cvmx_bootmem_phy_get_size(uint64_t addr) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci return cvmx_read64_uint64((addr + SIZE_OFFSET) | (1ull << 63)); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic uint64_t cvmx_bootmem_phy_get_next(uint64_t addr) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci return cvmx_read64_uint64((addr + NEXT_OFFSET) | (1ull << 63)); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * Allocate a block of memory from the free list that was 1208c2ecf20Sopenharmony_ci * passed to the application by the bootloader within a specified 1218c2ecf20Sopenharmony_ci * address range. This is an allocate-only algorithm, so 1228c2ecf20Sopenharmony_ci * freeing memory is not possible. Allocation will fail if 1238c2ecf20Sopenharmony_ci * memory cannot be allocated in the requested range. 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * @size: Size in bytes of block to allocate 1268c2ecf20Sopenharmony_ci * @min_addr: defines the minimum address of the range 1278c2ecf20Sopenharmony_ci * @max_addr: defines the maximum address of the range 1288c2ecf20Sopenharmony_ci * @alignment: Alignment required - must be power of 2 1298c2ecf20Sopenharmony_ci * Returns pointer to block of memory, NULL on error 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_cistatic void *cvmx_bootmem_alloc_range(uint64_t size, uint64_t alignment, 1328c2ecf20Sopenharmony_ci uint64_t min_addr, uint64_t max_addr) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int64_t address; 1358c2ecf20Sopenharmony_ci address = 1368c2ecf20Sopenharmony_ci cvmx_bootmem_phy_alloc(size, min_addr, max_addr, alignment, 0); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (address > 0) 1398c2ecf20Sopenharmony_ci return cvmx_phys_to_ptr(address); 1408c2ecf20Sopenharmony_ci else 1418c2ecf20Sopenharmony_ci return NULL; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_civoid *cvmx_bootmem_alloc_address(uint64_t size, uint64_t address, 1458c2ecf20Sopenharmony_ci uint64_t alignment) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return cvmx_bootmem_alloc_range(size, alignment, address, 1488c2ecf20Sopenharmony_ci address + size); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_civoid *cvmx_bootmem_alloc_named_range(uint64_t size, uint64_t min_addr, 1528c2ecf20Sopenharmony_ci uint64_t max_addr, uint64_t align, 1538c2ecf20Sopenharmony_ci char *name) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci int64_t addr; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr, 1588c2ecf20Sopenharmony_ci align, name, 0); 1598c2ecf20Sopenharmony_ci if (addr >= 0) 1608c2ecf20Sopenharmony_ci return cvmx_phys_to_ptr(addr); 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci return NULL; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_civoid *cvmx_bootmem_alloc_named(uint64_t size, uint64_t alignment, char *name) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci return cvmx_bootmem_alloc_named_range(size, 0, 0, alignment, name); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cvmx_bootmem_alloc_named); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_civoid cvmx_bootmem_lock(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci cvmx_spinlock_lock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock)); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_civoid cvmx_bootmem_unlock(void) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci cvmx_spinlock_unlock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock)); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ciint cvmx_bootmem_init(void *mem_desc_ptr) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci /* Here we set the global pointer to the bootmem descriptor 1848c2ecf20Sopenharmony_ci * block. This pointer will be used directly, so we will set 1858c2ecf20Sopenharmony_ci * it up to be directly usable by the application. It is set 1868c2ecf20Sopenharmony_ci * up as follows for the various runtime/ABI combinations: 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * Linux 64 bit: Set XKPHYS bit 1898c2ecf20Sopenharmony_ci * Linux 32 bit: use mmap to create mapping, use virtual address 1908c2ecf20Sopenharmony_ci * CVMX 64 bit: use physical address directly 1918c2ecf20Sopenharmony_ci * CVMX 32 bit: use physical address directly 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * Note that the CVMX environment assumes the use of 1-1 TLB 1948c2ecf20Sopenharmony_ci * mappings so that the physical addresses can be used 1958c2ecf20Sopenharmony_ci * directly 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci if (!cvmx_bootmem_desc) { 1988c2ecf20Sopenharmony_ci#if defined(CVMX_ABI_64) 1998c2ecf20Sopenharmony_ci /* Set XKPHYS bit */ 2008c2ecf20Sopenharmony_ci cvmx_bootmem_desc = cvmx_phys_to_ptr(CAST64(mem_desc_ptr)); 2018c2ecf20Sopenharmony_ci#else 2028c2ecf20Sopenharmony_ci cvmx_bootmem_desc = (struct cvmx_bootmem_desc *) mem_desc_ptr; 2038c2ecf20Sopenharmony_ci#endif 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* 2108c2ecf20Sopenharmony_ci * The cvmx_bootmem_phy* functions below return 64 bit physical 2118c2ecf20Sopenharmony_ci * addresses, and expose more features that the cvmx_bootmem_functions 2128c2ecf20Sopenharmony_ci * above. These are required for full memory space access in 32 bit 2138c2ecf20Sopenharmony_ci * applications, as well as for using some advance features. Most 2148c2ecf20Sopenharmony_ci * applications should not need to use these. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min, 2188c2ecf20Sopenharmony_ci uint64_t address_max, uint64_t alignment, 2198c2ecf20Sopenharmony_ci uint32_t flags) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci uint64_t head_addr; 2238c2ecf20Sopenharmony_ci uint64_t ent_addr; 2248c2ecf20Sopenharmony_ci /* points to previous list entry, NULL current entry is head of list */ 2258c2ecf20Sopenharmony_ci uint64_t prev_addr = 0; 2268c2ecf20Sopenharmony_ci uint64_t new_ent_addr = 0; 2278c2ecf20Sopenharmony_ci uint64_t desired_min_addr; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#ifdef DEBUG 2308c2ecf20Sopenharmony_ci cvmx_dprintf("cvmx_bootmem_phy_alloc: req_size: 0x%llx, " 2318c2ecf20Sopenharmony_ci "min_addr: 0x%llx, max_addr: 0x%llx, align: 0x%llx\n", 2328c2ecf20Sopenharmony_ci (unsigned long long)req_size, 2338c2ecf20Sopenharmony_ci (unsigned long long)address_min, 2348c2ecf20Sopenharmony_ci (unsigned long long)address_max, 2358c2ecf20Sopenharmony_ci (unsigned long long)alignment); 2368c2ecf20Sopenharmony_ci#endif 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (cvmx_bootmem_desc->major_version > 3) { 2398c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: Incompatible bootmem descriptor " 2408c2ecf20Sopenharmony_ci "version: %d.%d at addr: %p\n", 2418c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->major_version, 2428c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->minor_version, 2438c2ecf20Sopenharmony_ci cvmx_bootmem_desc); 2448c2ecf20Sopenharmony_ci goto error_out; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * Do a variety of checks to validate the arguments. The 2498c2ecf20Sopenharmony_ci * allocator code will later assume that these checks have 2508c2ecf20Sopenharmony_ci * been made. We validate that the requested constraints are 2518c2ecf20Sopenharmony_ci * not self-contradictory before we look through the list of 2528c2ecf20Sopenharmony_ci * available memory. 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* 0 is not a valid req_size for this allocator */ 2568c2ecf20Sopenharmony_ci if (!req_size) 2578c2ecf20Sopenharmony_ci goto error_out; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Round req_size up to mult of minimum alignment bytes */ 2608c2ecf20Sopenharmony_ci req_size = (req_size + (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)) & 2618c2ecf20Sopenharmony_ci ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * Convert !0 address_min and 0 address_max to special case of 2658c2ecf20Sopenharmony_ci * range that specifies an exact memory block to allocate. Do 2668c2ecf20Sopenharmony_ci * this before other checks and adjustments so that this 2678c2ecf20Sopenharmony_ci * tranformation will be validated. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci if (address_min && !address_max) 2708c2ecf20Sopenharmony_ci address_max = address_min + req_size; 2718c2ecf20Sopenharmony_ci else if (!address_min && !address_max) 2728c2ecf20Sopenharmony_ci address_max = ~0ull; /* If no limits given, use max limits */ 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * Enforce minimum alignment (this also keeps the minimum free block 2778c2ecf20Sopenharmony_ci * req_size the same as the alignment req_size. 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ci if (alignment < CVMX_BOOTMEM_ALIGNMENT_SIZE) 2808c2ecf20Sopenharmony_ci alignment = CVMX_BOOTMEM_ALIGNMENT_SIZE; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * Adjust address minimum based on requested alignment (round 2848c2ecf20Sopenharmony_ci * up to meet alignment). Do this here so we can reject 2858c2ecf20Sopenharmony_ci * impossible requests up front. (NOP for address_min == 0) 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci if (alignment) 2888c2ecf20Sopenharmony_ci address_min = ALIGN(address_min, alignment); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Reject inconsistent args. We have adjusted these, so this 2928c2ecf20Sopenharmony_ci * may fail due to our internal changes even if this check 2938c2ecf20Sopenharmony_ci * would pass for the values the user supplied. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci if (req_size > address_max - address_min) 2968c2ecf20Sopenharmony_ci goto error_out; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Walk through the list entries - first fit found is returned */ 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 3018c2ecf20Sopenharmony_ci cvmx_bootmem_lock(); 3028c2ecf20Sopenharmony_ci head_addr = cvmx_bootmem_desc->head_addr; 3038c2ecf20Sopenharmony_ci ent_addr = head_addr; 3048c2ecf20Sopenharmony_ci for (; ent_addr; 3058c2ecf20Sopenharmony_ci prev_addr = ent_addr, 3068c2ecf20Sopenharmony_ci ent_addr = cvmx_bootmem_phy_get_next(ent_addr)) { 3078c2ecf20Sopenharmony_ci uint64_t usable_base, usable_max; 3088c2ecf20Sopenharmony_ci uint64_t ent_size = cvmx_bootmem_phy_get_size(ent_addr); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (cvmx_bootmem_phy_get_next(ent_addr) 3118c2ecf20Sopenharmony_ci && ent_addr > cvmx_bootmem_phy_get_next(ent_addr)) { 3128c2ecf20Sopenharmony_ci cvmx_dprintf("Internal bootmem_alloc() error: ent: " 3138c2ecf20Sopenharmony_ci "0x%llx, next: 0x%llx\n", 3148c2ecf20Sopenharmony_ci (unsigned long long)ent_addr, 3158c2ecf20Sopenharmony_ci (unsigned long long) 3168c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next(ent_addr)); 3178c2ecf20Sopenharmony_ci goto error_out; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * Determine if this is an entry that can satisify the 3228c2ecf20Sopenharmony_ci * request Check to make sure entry is large enough to 3238c2ecf20Sopenharmony_ci * satisfy request. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci usable_base = 3268c2ecf20Sopenharmony_ci ALIGN(max(address_min, ent_addr), alignment); 3278c2ecf20Sopenharmony_ci usable_max = min(address_max, ent_addr + ent_size); 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * We should be able to allocate block at address 3308c2ecf20Sopenharmony_ci * usable_base. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci desired_min_addr = usable_base; 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * Determine if request can be satisfied from the 3368c2ecf20Sopenharmony_ci * current entry. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (!((ent_addr + ent_size) > usable_base 3398c2ecf20Sopenharmony_ci && ent_addr < address_max 3408c2ecf20Sopenharmony_ci && req_size <= usable_max - usable_base)) 3418c2ecf20Sopenharmony_ci continue; 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * We have found an entry that has room to satisfy the 3448c2ecf20Sopenharmony_ci * request, so allocate it from this entry. If end 3458c2ecf20Sopenharmony_ci * CVMX_BOOTMEM_FLAG_END_ALLOC set, then allocate from 3468c2ecf20Sopenharmony_ci * the end of this block rather than the beginning. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci if (flags & CVMX_BOOTMEM_FLAG_END_ALLOC) { 3498c2ecf20Sopenharmony_ci desired_min_addr = usable_max - req_size; 3508c2ecf20Sopenharmony_ci /* 3518c2ecf20Sopenharmony_ci * Align desired address down to required 3528c2ecf20Sopenharmony_ci * alignment. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci desired_min_addr &= ~(alignment - 1); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Match at start of entry */ 3588c2ecf20Sopenharmony_ci if (desired_min_addr == ent_addr) { 3598c2ecf20Sopenharmony_ci if (req_size < ent_size) { 3608c2ecf20Sopenharmony_ci /* 3618c2ecf20Sopenharmony_ci * big enough to create a new block 3628c2ecf20Sopenharmony_ci * from top portion of block. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci new_ent_addr = ent_addr + req_size; 3658c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(new_ent_addr, 3668c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next(ent_addr)); 3678c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(new_ent_addr, 3688c2ecf20Sopenharmony_ci ent_size - 3698c2ecf20Sopenharmony_ci req_size); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* 3728c2ecf20Sopenharmony_ci * Adjust next pointer as following 3738c2ecf20Sopenharmony_ci * code uses this. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(ent_addr, 3768c2ecf20Sopenharmony_ci new_ent_addr); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* 3808c2ecf20Sopenharmony_ci * adjust prev ptr or head to remove this 3818c2ecf20Sopenharmony_ci * entry from list. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (prev_addr) 3848c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(prev_addr, 3858c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next(ent_addr)); 3868c2ecf20Sopenharmony_ci else 3878c2ecf20Sopenharmony_ci /* 3888c2ecf20Sopenharmony_ci * head of list being returned, so 3898c2ecf20Sopenharmony_ci * update head ptr. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci cvmx_bootmem_desc->head_addr = 3928c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next(ent_addr); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 3958c2ecf20Sopenharmony_ci cvmx_bootmem_unlock(); 3968c2ecf20Sopenharmony_ci return desired_min_addr; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * block returned doesn't start at beginning of entry, 4008c2ecf20Sopenharmony_ci * so we know that we will be splitting a block off 4018c2ecf20Sopenharmony_ci * the front of this one. Create a new block from the 4028c2ecf20Sopenharmony_ci * beginning, add to list, and go to top of loop 4038c2ecf20Sopenharmony_ci * again. 4048c2ecf20Sopenharmony_ci * 4058c2ecf20Sopenharmony_ci * create new block from high portion of 4068c2ecf20Sopenharmony_ci * block, so that top block starts at desired 4078c2ecf20Sopenharmony_ci * addr. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci new_ent_addr = desired_min_addr; 4108c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(new_ent_addr, 4118c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next 4128c2ecf20Sopenharmony_ci (ent_addr)); 4138c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(new_ent_addr, 4148c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_size 4158c2ecf20Sopenharmony_ci (ent_addr) - 4168c2ecf20Sopenharmony_ci (desired_min_addr - 4178c2ecf20Sopenharmony_ci ent_addr)); 4188c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(ent_addr, 4198c2ecf20Sopenharmony_ci desired_min_addr - ent_addr); 4208c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(ent_addr, new_ent_addr); 4218c2ecf20Sopenharmony_ci /* Loop again to handle actual alloc from new block */ 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_cierror_out: 4248c2ecf20Sopenharmony_ci /* We didn't find anything, so return error */ 4258c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 4268c2ecf20Sopenharmony_ci cvmx_bootmem_unlock(); 4278c2ecf20Sopenharmony_ci return -1; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ciint __cvmx_bootmem_phy_free(uint64_t phy_addr, uint64_t size, uint32_t flags) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci uint64_t cur_addr; 4338c2ecf20Sopenharmony_ci uint64_t prev_addr = 0; /* zero is invalid */ 4348c2ecf20Sopenharmony_ci int retval = 0; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci#ifdef DEBUG 4378c2ecf20Sopenharmony_ci cvmx_dprintf("__cvmx_bootmem_phy_free addr: 0x%llx, size: 0x%llx\n", 4388c2ecf20Sopenharmony_ci (unsigned long long)phy_addr, (unsigned long long)size); 4398c2ecf20Sopenharmony_ci#endif 4408c2ecf20Sopenharmony_ci if (cvmx_bootmem_desc->major_version > 3) { 4418c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: Incompatible bootmem descriptor " 4428c2ecf20Sopenharmony_ci "version: %d.%d at addr: %p\n", 4438c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->major_version, 4448c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->minor_version, 4458c2ecf20Sopenharmony_ci cvmx_bootmem_desc); 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 0 is not a valid size for this allocator */ 4508c2ecf20Sopenharmony_ci if (!size) 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 4548c2ecf20Sopenharmony_ci cvmx_bootmem_lock(); 4558c2ecf20Sopenharmony_ci cur_addr = cvmx_bootmem_desc->head_addr; 4568c2ecf20Sopenharmony_ci if (cur_addr == 0 || phy_addr < cur_addr) { 4578c2ecf20Sopenharmony_ci /* add at front of list - special case with changing head ptr */ 4588c2ecf20Sopenharmony_ci if (cur_addr && phy_addr + size > cur_addr) 4598c2ecf20Sopenharmony_ci goto bootmem_free_done; /* error, overlapping section */ 4608c2ecf20Sopenharmony_ci else if (phy_addr + size == cur_addr) { 4618c2ecf20Sopenharmony_ci /* Add to front of existing first block */ 4628c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(phy_addr, 4638c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next 4648c2ecf20Sopenharmony_ci (cur_addr)); 4658c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(phy_addr, 4668c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_size 4678c2ecf20Sopenharmony_ci (cur_addr) + size); 4688c2ecf20Sopenharmony_ci cvmx_bootmem_desc->head_addr = phy_addr; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci } else { 4718c2ecf20Sopenharmony_ci /* New block before first block. OK if cur_addr is 0 */ 4728c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(phy_addr, cur_addr); 4738c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(phy_addr, size); 4748c2ecf20Sopenharmony_ci cvmx_bootmem_desc->head_addr = phy_addr; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci retval = 1; 4778c2ecf20Sopenharmony_ci goto bootmem_free_done; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Find place in list to add block */ 4818c2ecf20Sopenharmony_ci while (cur_addr && phy_addr > cur_addr) { 4828c2ecf20Sopenharmony_ci prev_addr = cur_addr; 4838c2ecf20Sopenharmony_ci cur_addr = cvmx_bootmem_phy_get_next(cur_addr); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (!cur_addr) { 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * We have reached the end of the list, add on to end, 4898c2ecf20Sopenharmony_ci * checking to see if we need to combine with last 4908c2ecf20Sopenharmony_ci * block 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ci if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) == 4938c2ecf20Sopenharmony_ci phy_addr) { 4948c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(prev_addr, 4958c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_size 4968c2ecf20Sopenharmony_ci (prev_addr) + size); 4978c2ecf20Sopenharmony_ci } else { 4988c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(prev_addr, phy_addr); 4998c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(phy_addr, size); 5008c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(phy_addr, 0); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci retval = 1; 5038c2ecf20Sopenharmony_ci goto bootmem_free_done; 5048c2ecf20Sopenharmony_ci } else { 5058c2ecf20Sopenharmony_ci /* 5068c2ecf20Sopenharmony_ci * insert between prev and cur nodes, checking for 5078c2ecf20Sopenharmony_ci * merge with either/both. 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ci if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) == 5108c2ecf20Sopenharmony_ci phy_addr) { 5118c2ecf20Sopenharmony_ci /* Merge with previous */ 5128c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(prev_addr, 5138c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_size 5148c2ecf20Sopenharmony_ci (prev_addr) + size); 5158c2ecf20Sopenharmony_ci if (phy_addr + size == cur_addr) { 5168c2ecf20Sopenharmony_ci /* Also merge with current */ 5178c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(prev_addr, 5188c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_size(cur_addr) + 5198c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_size(prev_addr)); 5208c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(prev_addr, 5218c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next(cur_addr)); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci retval = 1; 5248c2ecf20Sopenharmony_ci goto bootmem_free_done; 5258c2ecf20Sopenharmony_ci } else if (phy_addr + size == cur_addr) { 5268c2ecf20Sopenharmony_ci /* Merge with current */ 5278c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(phy_addr, 5288c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_size 5298c2ecf20Sopenharmony_ci (cur_addr) + size); 5308c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(phy_addr, 5318c2ecf20Sopenharmony_ci cvmx_bootmem_phy_get_next 5328c2ecf20Sopenharmony_ci (cur_addr)); 5338c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(prev_addr, phy_addr); 5348c2ecf20Sopenharmony_ci retval = 1; 5358c2ecf20Sopenharmony_ci goto bootmem_free_done; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* It is a standalone block, add in between prev and cur */ 5398c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_size(phy_addr, size); 5408c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(phy_addr, cur_addr); 5418c2ecf20Sopenharmony_ci cvmx_bootmem_phy_set_next(prev_addr, phy_addr); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci retval = 1; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cibootmem_free_done: 5478c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 5488c2ecf20Sopenharmony_ci cvmx_bootmem_unlock(); 5498c2ecf20Sopenharmony_ci return retval; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci/** 5548c2ecf20Sopenharmony_ci * Finds a named memory block by name. 5558c2ecf20Sopenharmony_ci * Also used for finding an unused entry in the named block table. 5568c2ecf20Sopenharmony_ci * 5578c2ecf20Sopenharmony_ci * @name: Name of memory block to find. If NULL pointer given, then 5588c2ecf20Sopenharmony_ci * finds unused descriptor, if available. 5598c2ecf20Sopenharmony_ci * 5608c2ecf20Sopenharmony_ci * @flags: Flags to control options for the allocation. 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * Returns Pointer to memory block descriptor, NULL if not found. 5638c2ecf20Sopenharmony_ci * If NULL returned when name parameter is NULL, then no memory 5648c2ecf20Sopenharmony_ci * block descriptors are available. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_cistatic struct cvmx_bootmem_named_block_desc * 5678c2ecf20Sopenharmony_ci cvmx_bootmem_phy_named_block_find(char *name, uint32_t flags) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci unsigned int i; 5708c2ecf20Sopenharmony_ci struct cvmx_bootmem_named_block_desc *named_block_array_ptr; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci#ifdef DEBUG 5738c2ecf20Sopenharmony_ci cvmx_dprintf("cvmx_bootmem_phy_named_block_find: %s\n", name); 5748c2ecf20Sopenharmony_ci#endif 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * Lock the structure to make sure that it is not being 5778c2ecf20Sopenharmony_ci * changed while we are examining it. 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 5808c2ecf20Sopenharmony_ci cvmx_bootmem_lock(); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Use XKPHYS for 64 bit linux */ 5838c2ecf20Sopenharmony_ci named_block_array_ptr = (struct cvmx_bootmem_named_block_desc *) 5848c2ecf20Sopenharmony_ci cvmx_phys_to_ptr(cvmx_bootmem_desc->named_block_array_addr); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci#ifdef DEBUG 5878c2ecf20Sopenharmony_ci cvmx_dprintf 5888c2ecf20Sopenharmony_ci ("cvmx_bootmem_phy_named_block_find: named_block_array_ptr: %p\n", 5898c2ecf20Sopenharmony_ci named_block_array_ptr); 5908c2ecf20Sopenharmony_ci#endif 5918c2ecf20Sopenharmony_ci if (cvmx_bootmem_desc->major_version == 3) { 5928c2ecf20Sopenharmony_ci for (i = 0; 5938c2ecf20Sopenharmony_ci i < cvmx_bootmem_desc->named_block_num_blocks; i++) { 5948c2ecf20Sopenharmony_ci if ((name && named_block_array_ptr[i].size 5958c2ecf20Sopenharmony_ci && !strncmp(name, named_block_array_ptr[i].name, 5968c2ecf20Sopenharmony_ci cvmx_bootmem_desc->named_block_name_len 5978c2ecf20Sopenharmony_ci - 1)) 5988c2ecf20Sopenharmony_ci || (!name && !named_block_array_ptr[i].size)) { 5998c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 6008c2ecf20Sopenharmony_ci cvmx_bootmem_unlock(); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return &(named_block_array_ptr[i]); 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci } else { 6068c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: Incompatible bootmem descriptor " 6078c2ecf20Sopenharmony_ci "version: %d.%d at addr: %p\n", 6088c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->major_version, 6098c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->minor_version, 6108c2ecf20Sopenharmony_ci cvmx_bootmem_desc); 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 6138c2ecf20Sopenharmony_ci cvmx_bootmem_unlock(); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return NULL; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_civoid *cvmx_bootmem_alloc_named_range_once(uint64_t size, uint64_t min_addr, 6198c2ecf20Sopenharmony_ci uint64_t max_addr, uint64_t align, 6208c2ecf20Sopenharmony_ci char *name, 6218c2ecf20Sopenharmony_ci void (*init) (void *)) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci int64_t addr; 6248c2ecf20Sopenharmony_ci void *ptr; 6258c2ecf20Sopenharmony_ci uint64_t named_block_desc_addr; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci named_block_desc_addr = (uint64_t) 6288c2ecf20Sopenharmony_ci cvmx_bootmem_phy_named_block_find(name, 6298c2ecf20Sopenharmony_ci (uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (named_block_desc_addr) { 6328c2ecf20Sopenharmony_ci addr = CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_desc_addr, 6338c2ecf20Sopenharmony_ci base_addr); 6348c2ecf20Sopenharmony_ci return cvmx_phys_to_ptr(addr); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr, 6388c2ecf20Sopenharmony_ci align, name, 6398c2ecf20Sopenharmony_ci (uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (addr < 0) 6428c2ecf20Sopenharmony_ci return NULL; 6438c2ecf20Sopenharmony_ci ptr = cvmx_phys_to_ptr(addr); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (init) 6468c2ecf20Sopenharmony_ci init(ptr); 6478c2ecf20Sopenharmony_ci else 6488c2ecf20Sopenharmony_ci memset(ptr, 0, size); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return ptr; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cvmx_bootmem_alloc_named_range_once); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistruct cvmx_bootmem_named_block_desc *cvmx_bootmem_find_named_block(char *name) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci return cvmx_bootmem_phy_named_block_find(name, 0); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cvmx_bootmem_find_named_block); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/** 6618c2ecf20Sopenharmony_ci * Frees a named block. 6628c2ecf20Sopenharmony_ci * 6638c2ecf20Sopenharmony_ci * @name: name of block to free 6648c2ecf20Sopenharmony_ci * @flags: flags for passing options 6658c2ecf20Sopenharmony_ci * 6668c2ecf20Sopenharmony_ci * Returns 0 on failure 6678c2ecf20Sopenharmony_ci * 1 on success 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_cistatic int cvmx_bootmem_phy_named_block_free(char *name, uint32_t flags) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct cvmx_bootmem_named_block_desc *named_block_ptr; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (cvmx_bootmem_desc->major_version != 3) { 6748c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: " 6758c2ecf20Sopenharmony_ci "%d.%d at addr: %p\n", 6768c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->major_version, 6778c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->minor_version, 6788c2ecf20Sopenharmony_ci cvmx_bootmem_desc); 6798c2ecf20Sopenharmony_ci return 0; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci#ifdef DEBUG 6828c2ecf20Sopenharmony_ci cvmx_dprintf("cvmx_bootmem_phy_named_block_free: %s\n", name); 6838c2ecf20Sopenharmony_ci#endif 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* 6868c2ecf20Sopenharmony_ci * Take lock here, as name lookup/block free/name free need to 6878c2ecf20Sopenharmony_ci * be atomic. 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci cvmx_bootmem_lock(); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci named_block_ptr = 6928c2ecf20Sopenharmony_ci cvmx_bootmem_phy_named_block_find(name, 6938c2ecf20Sopenharmony_ci CVMX_BOOTMEM_FLAG_NO_LOCKING); 6948c2ecf20Sopenharmony_ci if (named_block_ptr) { 6958c2ecf20Sopenharmony_ci#ifdef DEBUG 6968c2ecf20Sopenharmony_ci cvmx_dprintf("cvmx_bootmem_phy_named_block_free: " 6978c2ecf20Sopenharmony_ci "%s, base: 0x%llx, size: 0x%llx\n", 6988c2ecf20Sopenharmony_ci name, 6998c2ecf20Sopenharmony_ci (unsigned long long)named_block_ptr->base_addr, 7008c2ecf20Sopenharmony_ci (unsigned long long)named_block_ptr->size); 7018c2ecf20Sopenharmony_ci#endif 7028c2ecf20Sopenharmony_ci __cvmx_bootmem_phy_free(named_block_ptr->base_addr, 7038c2ecf20Sopenharmony_ci named_block_ptr->size, 7048c2ecf20Sopenharmony_ci CVMX_BOOTMEM_FLAG_NO_LOCKING); 7058c2ecf20Sopenharmony_ci named_block_ptr->size = 0; 7068c2ecf20Sopenharmony_ci /* Set size to zero to indicate block not used. */ 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci cvmx_bootmem_unlock(); 7108c2ecf20Sopenharmony_ci return named_block_ptr != NULL; /* 0 on failure, 1 on success */ 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ciint cvmx_bootmem_free_named(char *name) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci return cvmx_bootmem_phy_named_block_free(name, 0); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ciint64_t cvmx_bootmem_phy_named_block_alloc(uint64_t size, uint64_t min_addr, 7198c2ecf20Sopenharmony_ci uint64_t max_addr, 7208c2ecf20Sopenharmony_ci uint64_t alignment, 7218c2ecf20Sopenharmony_ci char *name, 7228c2ecf20Sopenharmony_ci uint32_t flags) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci int64_t addr_allocated; 7258c2ecf20Sopenharmony_ci struct cvmx_bootmem_named_block_desc *named_block_desc_ptr; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci#ifdef DEBUG 7288c2ecf20Sopenharmony_ci cvmx_dprintf("cvmx_bootmem_phy_named_block_alloc: size: 0x%llx, min: " 7298c2ecf20Sopenharmony_ci "0x%llx, max: 0x%llx, align: 0x%llx, name: %s\n", 7308c2ecf20Sopenharmony_ci (unsigned long long)size, 7318c2ecf20Sopenharmony_ci (unsigned long long)min_addr, 7328c2ecf20Sopenharmony_ci (unsigned long long)max_addr, 7338c2ecf20Sopenharmony_ci (unsigned long long)alignment, 7348c2ecf20Sopenharmony_ci name); 7358c2ecf20Sopenharmony_ci#endif 7368c2ecf20Sopenharmony_ci if (cvmx_bootmem_desc->major_version != 3) { 7378c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: " 7388c2ecf20Sopenharmony_ci "%d.%d at addr: %p\n", 7398c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->major_version, 7408c2ecf20Sopenharmony_ci (int)cvmx_bootmem_desc->minor_version, 7418c2ecf20Sopenharmony_ci cvmx_bootmem_desc); 7428c2ecf20Sopenharmony_ci return -1; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* 7468c2ecf20Sopenharmony_ci * Take lock here, as name lookup/block alloc/name add need to 7478c2ecf20Sopenharmony_ci * be atomic. 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 7508c2ecf20Sopenharmony_ci cvmx_spinlock_lock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock)); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* Get pointer to first available named block descriptor */ 7538c2ecf20Sopenharmony_ci named_block_desc_ptr = 7548c2ecf20Sopenharmony_ci cvmx_bootmem_phy_named_block_find(NULL, 7558c2ecf20Sopenharmony_ci flags | CVMX_BOOTMEM_FLAG_NO_LOCKING); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* 7588c2ecf20Sopenharmony_ci * Check to see if name already in use, return error if name 7598c2ecf20Sopenharmony_ci * not available or no more room for blocks. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci if (cvmx_bootmem_phy_named_block_find(name, 7628c2ecf20Sopenharmony_ci flags | CVMX_BOOTMEM_FLAG_NO_LOCKING) || !named_block_desc_ptr) { 7638c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 7648c2ecf20Sopenharmony_ci cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock)); 7658c2ecf20Sopenharmony_ci return -1; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* 7708c2ecf20Sopenharmony_ci * Round size up to mult of minimum alignment bytes We need 7718c2ecf20Sopenharmony_ci * the actual size allocated to allow for blocks to be 7728c2ecf20Sopenharmony_ci * coalesced when they are freed. The alloc routine does the 7738c2ecf20Sopenharmony_ci * same rounding up on all allocations. 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci size = ALIGN(size, CVMX_BOOTMEM_ALIGNMENT_SIZE); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci addr_allocated = cvmx_bootmem_phy_alloc(size, min_addr, max_addr, 7788c2ecf20Sopenharmony_ci alignment, 7798c2ecf20Sopenharmony_ci flags | CVMX_BOOTMEM_FLAG_NO_LOCKING); 7808c2ecf20Sopenharmony_ci if (addr_allocated >= 0) { 7818c2ecf20Sopenharmony_ci named_block_desc_ptr->base_addr = addr_allocated; 7828c2ecf20Sopenharmony_ci named_block_desc_ptr->size = size; 7838c2ecf20Sopenharmony_ci strncpy(named_block_desc_ptr->name, name, 7848c2ecf20Sopenharmony_ci cvmx_bootmem_desc->named_block_name_len); 7858c2ecf20Sopenharmony_ci named_block_desc_ptr->name[cvmx_bootmem_desc->named_block_name_len - 1] = 0; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) 7898c2ecf20Sopenharmony_ci cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock)); 7908c2ecf20Sopenharmony_ci return addr_allocated; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistruct cvmx_bootmem_desc *cvmx_bootmem_get_desc(void) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci return cvmx_bootmem_desc; 7968c2ecf20Sopenharmony_ci} 797