Path: blob/master/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
26481 views
/***********************license start***************1* Author: Cavium Networks2*3* Contact: [email protected]4* This file is part of the OCTEON SDK5*6* Copyright (c) 2003-2008 Cavium Networks7*8* This file is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License, Version 2, as10* published by the Free Software Foundation.11*12* This file is distributed in the hope that it will be useful, but13* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty14* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or15* NONINFRINGEMENT. See the GNU General Public License for more16* details.17*18* You should have received a copy of the GNU General Public License19* along with this file; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21* or visit http://www.gnu.org/licenses/.22*23* This file may also be available under a different license from Cavium.24* Contact Cavium Networks for more information25***********************license end**************************************/2627/*28* Simple allocate only memory allocator. Used to allocate memory at29* application start time.30*/3132#include <linux/export.h>33#include <linux/kernel.h>3435#include <asm/octeon/cvmx.h>36#include <asm/octeon/cvmx-spinlock.h>37#include <asm/octeon/cvmx-bootmem.h>3839/*#define DEBUG */404142static struct cvmx_bootmem_desc *cvmx_bootmem_desc;4344/* See header file for descriptions of functions */4546/*47* This macro returns a member of the48* cvmx_bootmem_named_block_desc_t structure. These members can't49* be directly addressed as they might be in memory not directly50* reachable. In the case where bootmem is compiled with51* LINUX_HOST, the structure itself might be located on a remote52* Octeon. The argument "field" is the member name of the53* cvmx_bootmem_named_block_desc_t to read. Regardless of the type54* of the field, the return type is always a uint64_t. The "addr"55* parameter is the physical address of the structure.56*/57#define CVMX_BOOTMEM_NAMED_GET_FIELD(addr, field) \58__cvmx_bootmem_desc_get(addr, \59offsetof(struct cvmx_bootmem_named_block_desc, field), \60sizeof_field(struct cvmx_bootmem_named_block_desc, field))6162/*63* This function is the implementation of the get macros defined64* for individual structure members. The argument are generated65* by the macros inorder to read only the needed memory.66*67* @param base 64bit physical address of the complete structure68* @param offset Offset from the beginning of the structure to the member being69* accessed.70* @param size Size of the structure member.71*72* @return Value of the structure member promoted into a uint64_t.73*/74static inline uint64_t __cvmx_bootmem_desc_get(uint64_t base, int offset,75int size)76{77base = (1ull << 63) | (base + offset);78switch (size) {79case 4:80return cvmx_read64_uint32(base);81case 8:82return cvmx_read64_uint64(base);83default:84return 0;85}86}8788/*89* Wrapper functions are provided for reading/writing the size and90* next block values as these may not be directly addressible (in 3291* bit applications, for instance.) Offsets of data elements in92* bootmem list, must match cvmx_bootmem_block_header_t.93*/94#define NEXT_OFFSET 095#define SIZE_OFFSET 89697static void cvmx_bootmem_phy_set_size(uint64_t addr, uint64_t size)98{99cvmx_write64_uint64((addr + SIZE_OFFSET) | (1ull << 63), size);100}101102static void cvmx_bootmem_phy_set_next(uint64_t addr, uint64_t next)103{104cvmx_write64_uint64((addr + NEXT_OFFSET) | (1ull << 63), next);105}106107static uint64_t cvmx_bootmem_phy_get_size(uint64_t addr)108{109return cvmx_read64_uint64((addr + SIZE_OFFSET) | (1ull << 63));110}111112static uint64_t cvmx_bootmem_phy_get_next(uint64_t addr)113{114return cvmx_read64_uint64((addr + NEXT_OFFSET) | (1ull << 63));115}116117/*118* Allocate a block of memory from the free list that was119* passed to the application by the bootloader within a specified120* address range. This is an allocate-only algorithm, so121* freeing memory is not possible. Allocation will fail if122* memory cannot be allocated in the requested range.123*124* @size: Size in bytes of block to allocate125* @min_addr: defines the minimum address of the range126* @max_addr: defines the maximum address of the range127* @alignment: Alignment required - must be power of 2128* Returns pointer to block of memory, NULL on error129*/130static void *cvmx_bootmem_alloc_range(uint64_t size, uint64_t alignment,131uint64_t min_addr, uint64_t max_addr)132{133int64_t address;134address =135cvmx_bootmem_phy_alloc(size, min_addr, max_addr, alignment, 0);136137if (address > 0)138return cvmx_phys_to_ptr(address);139else140return NULL;141}142143void *cvmx_bootmem_alloc_address(uint64_t size, uint64_t address,144uint64_t alignment)145{146return cvmx_bootmem_alloc_range(size, alignment, address,147address + size);148}149150void *cvmx_bootmem_alloc_named_range(uint64_t size, uint64_t min_addr,151uint64_t max_addr, uint64_t align,152char *name)153{154int64_t addr;155156addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr,157align, name, 0);158if (addr >= 0)159return cvmx_phys_to_ptr(addr);160else161return NULL;162}163164void *cvmx_bootmem_alloc_named(uint64_t size, uint64_t alignment, char *name)165{166return cvmx_bootmem_alloc_named_range(size, 0, 0, alignment, name);167}168EXPORT_SYMBOL(cvmx_bootmem_alloc_named);169170void cvmx_bootmem_lock(void)171{172cvmx_spinlock_lock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock));173}174175void cvmx_bootmem_unlock(void)176{177cvmx_spinlock_unlock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock));178}179180int cvmx_bootmem_init(void *mem_desc_ptr)181{182/* Here we set the global pointer to the bootmem descriptor183* block. This pointer will be used directly, so we will set184* it up to be directly usable by the application. It is set185* up as follows for the various runtime/ABI combinations:186*187* Linux 64 bit: Set XKPHYS bit188* Linux 32 bit: use mmap to create mapping, use virtual address189* CVMX 64 bit: use physical address directly190* CVMX 32 bit: use physical address directly191*192* Note that the CVMX environment assumes the use of 1-1 TLB193* mappings so that the physical addresses can be used194* directly195*/196if (!cvmx_bootmem_desc) {197#if defined(CVMX_ABI_64)198/* Set XKPHYS bit */199cvmx_bootmem_desc = cvmx_phys_to_ptr(CAST64(mem_desc_ptr));200#else201cvmx_bootmem_desc = (struct cvmx_bootmem_desc *) mem_desc_ptr;202#endif203}204205return 0;206}207208/*209* The cvmx_bootmem_phy* functions below return 64 bit physical210* addresses, and expose more features that the cvmx_bootmem_functions211* above. These are required for full memory space access in 32 bit212* applications, as well as for using some advance features. Most213* applications should not need to use these.214*/215216int64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min,217uint64_t address_max, uint64_t alignment,218uint32_t flags)219{220221uint64_t head_addr;222uint64_t ent_addr;223/* points to previous list entry, NULL current entry is head of list */224uint64_t prev_addr = 0;225uint64_t new_ent_addr = 0;226uint64_t desired_min_addr;227228#ifdef DEBUG229cvmx_dprintf("cvmx_bootmem_phy_alloc: req_size: 0x%llx, "230"min_addr: 0x%llx, max_addr: 0x%llx, align: 0x%llx\n",231(unsigned long long)req_size,232(unsigned long long)address_min,233(unsigned long long)address_max,234(unsigned long long)alignment);235#endif236237if (cvmx_bootmem_desc->major_version > 3) {238cvmx_dprintf("ERROR: Incompatible bootmem descriptor "239"version: %d.%d at addr: %p\n",240(int)cvmx_bootmem_desc->major_version,241(int)cvmx_bootmem_desc->minor_version,242cvmx_bootmem_desc);243goto error_out;244}245246/*247* Do a variety of checks to validate the arguments. The248* allocator code will later assume that these checks have249* been made. We validate that the requested constraints are250* not self-contradictory before we look through the list of251* available memory.252*/253254/* 0 is not a valid req_size for this allocator */255if (!req_size)256goto error_out;257258/* Round req_size up to mult of minimum alignment bytes */259req_size = (req_size + (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)) &260~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1);261262/*263* Convert !0 address_min and 0 address_max to special case of264* range that specifies an exact memory block to allocate. Do265* this before other checks and adjustments so that this266* transformation will be validated.267*/268if (address_min && !address_max)269address_max = address_min + req_size;270else if (!address_min && !address_max)271address_max = ~0ull; /* If no limits given, use max limits */272273274/*275* Enforce minimum alignment (this also keeps the minimum free block276* req_size the same as the alignment req_size.277*/278if (alignment < CVMX_BOOTMEM_ALIGNMENT_SIZE)279alignment = CVMX_BOOTMEM_ALIGNMENT_SIZE;280281/*282* Adjust address minimum based on requested alignment (round283* up to meet alignment). Do this here so we can reject284* impossible requests up front. (NOP for address_min == 0)285*/286if (alignment)287address_min = ALIGN(address_min, alignment);288289/*290* Reject inconsistent args. We have adjusted these, so this291* may fail due to our internal changes even if this check292* would pass for the values the user supplied.293*/294if (req_size > address_max - address_min)295goto error_out;296297/* Walk through the list entries - first fit found is returned */298299if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))300cvmx_bootmem_lock();301head_addr = cvmx_bootmem_desc->head_addr;302ent_addr = head_addr;303for (; ent_addr;304prev_addr = ent_addr,305ent_addr = cvmx_bootmem_phy_get_next(ent_addr)) {306uint64_t usable_base, usable_max;307uint64_t ent_size = cvmx_bootmem_phy_get_size(ent_addr);308309if (cvmx_bootmem_phy_get_next(ent_addr)310&& ent_addr > cvmx_bootmem_phy_get_next(ent_addr)) {311cvmx_dprintf("Internal bootmem_alloc() error: ent: "312"0x%llx, next: 0x%llx\n",313(unsigned long long)ent_addr,314(unsigned long long)315cvmx_bootmem_phy_get_next(ent_addr));316goto error_out;317}318319/*320* Determine if this is an entry that can satisfy the321* request Check to make sure entry is large enough to322* satisfy request.323*/324usable_base =325ALIGN(max(address_min, ent_addr), alignment);326usable_max = min(address_max, ent_addr + ent_size);327/*328* We should be able to allocate block at address329* usable_base.330*/331332desired_min_addr = usable_base;333/*334* Determine if request can be satisfied from the335* current entry.336*/337if (!((ent_addr + ent_size) > usable_base338&& ent_addr < address_max339&& req_size <= usable_max - usable_base))340continue;341/*342* We have found an entry that has room to satisfy the343* request, so allocate it from this entry. If end344* CVMX_BOOTMEM_FLAG_END_ALLOC set, then allocate from345* the end of this block rather than the beginning.346*/347if (flags & CVMX_BOOTMEM_FLAG_END_ALLOC) {348desired_min_addr = usable_max - req_size;349/*350* Align desired address down to required351* alignment.352*/353desired_min_addr &= ~(alignment - 1);354}355356/* Match at start of entry */357if (desired_min_addr == ent_addr) {358if (req_size < ent_size) {359/*360* big enough to create a new block361* from top portion of block.362*/363new_ent_addr = ent_addr + req_size;364cvmx_bootmem_phy_set_next(new_ent_addr,365cvmx_bootmem_phy_get_next(ent_addr));366cvmx_bootmem_phy_set_size(new_ent_addr,367ent_size -368req_size);369370/*371* Adjust next pointer as following372* code uses this.373*/374cvmx_bootmem_phy_set_next(ent_addr,375new_ent_addr);376}377378/*379* adjust prev ptr or head to remove this380* entry from list.381*/382if (prev_addr)383cvmx_bootmem_phy_set_next(prev_addr,384cvmx_bootmem_phy_get_next(ent_addr));385else386/*387* head of list being returned, so388* update head ptr.389*/390cvmx_bootmem_desc->head_addr =391cvmx_bootmem_phy_get_next(ent_addr);392393if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))394cvmx_bootmem_unlock();395return desired_min_addr;396}397/*398* block returned doesn't start at beginning of entry,399* so we know that we will be splitting a block off400* the front of this one. Create a new block from the401* beginning, add to list, and go to top of loop402* again.403*404* create new block from high portion of405* block, so that top block starts at desired406* addr.407*/408new_ent_addr = desired_min_addr;409cvmx_bootmem_phy_set_next(new_ent_addr,410cvmx_bootmem_phy_get_next411(ent_addr));412cvmx_bootmem_phy_set_size(new_ent_addr,413cvmx_bootmem_phy_get_size414(ent_addr) -415(desired_min_addr -416ent_addr));417cvmx_bootmem_phy_set_size(ent_addr,418desired_min_addr - ent_addr);419cvmx_bootmem_phy_set_next(ent_addr, new_ent_addr);420/* Loop again to handle actual alloc from new block */421}422error_out:423/* We didn't find anything, so return error */424if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))425cvmx_bootmem_unlock();426return -1;427}428429int __cvmx_bootmem_phy_free(uint64_t phy_addr, uint64_t size, uint32_t flags)430{431uint64_t cur_addr;432uint64_t prev_addr = 0; /* zero is invalid */433int retval = 0;434435#ifdef DEBUG436cvmx_dprintf("__cvmx_bootmem_phy_free addr: 0x%llx, size: 0x%llx\n",437(unsigned long long)phy_addr, (unsigned long long)size);438#endif439if (cvmx_bootmem_desc->major_version > 3) {440cvmx_dprintf("ERROR: Incompatible bootmem descriptor "441"version: %d.%d at addr: %p\n",442(int)cvmx_bootmem_desc->major_version,443(int)cvmx_bootmem_desc->minor_version,444cvmx_bootmem_desc);445return 0;446}447448/* 0 is not a valid size for this allocator */449if (!size)450return 0;451452if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))453cvmx_bootmem_lock();454cur_addr = cvmx_bootmem_desc->head_addr;455if (cur_addr == 0 || phy_addr < cur_addr) {456/* add at front of list - special case with changing head ptr */457if (cur_addr && phy_addr + size > cur_addr)458goto bootmem_free_done; /* error, overlapping section */459else if (phy_addr + size == cur_addr) {460/* Add to front of existing first block */461cvmx_bootmem_phy_set_next(phy_addr,462cvmx_bootmem_phy_get_next463(cur_addr));464cvmx_bootmem_phy_set_size(phy_addr,465cvmx_bootmem_phy_get_size466(cur_addr) + size);467cvmx_bootmem_desc->head_addr = phy_addr;468469} else {470/* New block before first block. OK if cur_addr is 0 */471cvmx_bootmem_phy_set_next(phy_addr, cur_addr);472cvmx_bootmem_phy_set_size(phy_addr, size);473cvmx_bootmem_desc->head_addr = phy_addr;474}475retval = 1;476goto bootmem_free_done;477}478479/* Find place in list to add block */480while (cur_addr && phy_addr > cur_addr) {481prev_addr = cur_addr;482cur_addr = cvmx_bootmem_phy_get_next(cur_addr);483}484485if (!cur_addr) {486/*487* We have reached the end of the list, add on to end,488* checking to see if we need to combine with last489* block490*/491if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) ==492phy_addr) {493cvmx_bootmem_phy_set_size(prev_addr,494cvmx_bootmem_phy_get_size495(prev_addr) + size);496} else {497cvmx_bootmem_phy_set_next(prev_addr, phy_addr);498cvmx_bootmem_phy_set_size(phy_addr, size);499cvmx_bootmem_phy_set_next(phy_addr, 0);500}501retval = 1;502goto bootmem_free_done;503} else {504/*505* insert between prev and cur nodes, checking for506* merge with either/both.507*/508if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) ==509phy_addr) {510/* Merge with previous */511cvmx_bootmem_phy_set_size(prev_addr,512cvmx_bootmem_phy_get_size513(prev_addr) + size);514if (phy_addr + size == cur_addr) {515/* Also merge with current */516cvmx_bootmem_phy_set_size(prev_addr,517cvmx_bootmem_phy_get_size(cur_addr) +518cvmx_bootmem_phy_get_size(prev_addr));519cvmx_bootmem_phy_set_next(prev_addr,520cvmx_bootmem_phy_get_next(cur_addr));521}522retval = 1;523goto bootmem_free_done;524} else if (phy_addr + size == cur_addr) {525/* Merge with current */526cvmx_bootmem_phy_set_size(phy_addr,527cvmx_bootmem_phy_get_size528(cur_addr) + size);529cvmx_bootmem_phy_set_next(phy_addr,530cvmx_bootmem_phy_get_next531(cur_addr));532cvmx_bootmem_phy_set_next(prev_addr, phy_addr);533retval = 1;534goto bootmem_free_done;535}536537/* It is a standalone block, add in between prev and cur */538cvmx_bootmem_phy_set_size(phy_addr, size);539cvmx_bootmem_phy_set_next(phy_addr, cur_addr);540cvmx_bootmem_phy_set_next(prev_addr, phy_addr);541542}543retval = 1;544545bootmem_free_done:546if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))547cvmx_bootmem_unlock();548return retval;549550}551552/*553* Finds a named memory block by name.554* Also used for finding an unused entry in the named block table.555*556* @name: Name of memory block to find. If NULL pointer given, then557* finds unused descriptor, if available.558*559* @flags: Flags to control options for the allocation.560*561* Returns Pointer to memory block descriptor, NULL if not found.562* If NULL returned when name parameter is NULL, then no memory563* block descriptors are available.564*/565static struct cvmx_bootmem_named_block_desc *566cvmx_bootmem_phy_named_block_find(char *name, uint32_t flags)567{568unsigned int i;569struct cvmx_bootmem_named_block_desc *named_block_array_ptr;570571#ifdef DEBUG572cvmx_dprintf("cvmx_bootmem_phy_named_block_find: %s\n", name);573#endif574/*575* Lock the structure to make sure that it is not being576* changed while we are examining it.577*/578if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))579cvmx_bootmem_lock();580581/* Use XKPHYS for 64 bit linux */582named_block_array_ptr = (struct cvmx_bootmem_named_block_desc *)583cvmx_phys_to_ptr(cvmx_bootmem_desc->named_block_array_addr);584585#ifdef DEBUG586cvmx_dprintf587("cvmx_bootmem_phy_named_block_find: named_block_array_ptr: %p\n",588named_block_array_ptr);589#endif590if (cvmx_bootmem_desc->major_version == 3) {591for (i = 0;592i < cvmx_bootmem_desc->named_block_num_blocks; i++) {593if ((name && named_block_array_ptr[i].size594&& !strncmp(name, named_block_array_ptr[i].name,595cvmx_bootmem_desc->named_block_name_len596- 1))597|| (!name && !named_block_array_ptr[i].size)) {598if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))599cvmx_bootmem_unlock();600601return &(named_block_array_ptr[i]);602}603}604} else {605cvmx_dprintf("ERROR: Incompatible bootmem descriptor "606"version: %d.%d at addr: %p\n",607(int)cvmx_bootmem_desc->major_version,608(int)cvmx_bootmem_desc->minor_version,609cvmx_bootmem_desc);610}611if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))612cvmx_bootmem_unlock();613614return NULL;615}616617void *cvmx_bootmem_alloc_named_range_once(uint64_t size, uint64_t min_addr,618uint64_t max_addr, uint64_t align,619char *name,620void (*init) (void *))621{622int64_t addr;623void *ptr;624uint64_t named_block_desc_addr;625626named_block_desc_addr = (uint64_t)627cvmx_bootmem_phy_named_block_find(name,628(uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING);629630if (named_block_desc_addr) {631addr = CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_desc_addr,632base_addr);633return cvmx_phys_to_ptr(addr);634}635636addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr,637align, name,638(uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING);639640if (addr < 0)641return NULL;642ptr = cvmx_phys_to_ptr(addr);643644if (init)645init(ptr);646else647memset(ptr, 0, size);648649return ptr;650}651EXPORT_SYMBOL(cvmx_bootmem_alloc_named_range_once);652653struct cvmx_bootmem_named_block_desc *cvmx_bootmem_find_named_block(char *name)654{655return cvmx_bootmem_phy_named_block_find(name, 0);656}657EXPORT_SYMBOL(cvmx_bootmem_find_named_block);658659/*660* Frees a named block.661*662* @name: name of block to free663* @flags: flags for passing options664*665* Returns 0 on failure666* 1 on success667*/668static int cvmx_bootmem_phy_named_block_free(char *name, uint32_t flags)669{670struct cvmx_bootmem_named_block_desc *named_block_ptr;671672if (cvmx_bootmem_desc->major_version != 3) {673cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: "674"%d.%d at addr: %p\n",675(int)cvmx_bootmem_desc->major_version,676(int)cvmx_bootmem_desc->minor_version,677cvmx_bootmem_desc);678return 0;679}680#ifdef DEBUG681cvmx_dprintf("cvmx_bootmem_phy_named_block_free: %s\n", name);682#endif683684/*685* Take lock here, as name lookup/block free/name free need to686* be atomic.687*/688cvmx_bootmem_lock();689690named_block_ptr =691cvmx_bootmem_phy_named_block_find(name,692CVMX_BOOTMEM_FLAG_NO_LOCKING);693if (named_block_ptr) {694#ifdef DEBUG695cvmx_dprintf("cvmx_bootmem_phy_named_block_free: "696"%s, base: 0x%llx, size: 0x%llx\n",697name,698(unsigned long long)named_block_ptr->base_addr,699(unsigned long long)named_block_ptr->size);700#endif701__cvmx_bootmem_phy_free(named_block_ptr->base_addr,702named_block_ptr->size,703CVMX_BOOTMEM_FLAG_NO_LOCKING);704named_block_ptr->size = 0;705/* Set size to zero to indicate block not used. */706}707708cvmx_bootmem_unlock();709return named_block_ptr != NULL; /* 0 on failure, 1 on success */710}711712int cvmx_bootmem_free_named(char *name)713{714return cvmx_bootmem_phy_named_block_free(name, 0);715}716717int64_t cvmx_bootmem_phy_named_block_alloc(uint64_t size, uint64_t min_addr,718uint64_t max_addr,719uint64_t alignment,720char *name,721uint32_t flags)722{723int64_t addr_allocated;724struct cvmx_bootmem_named_block_desc *named_block_desc_ptr;725726#ifdef DEBUG727cvmx_dprintf("cvmx_bootmem_phy_named_block_alloc: size: 0x%llx, min: "728"0x%llx, max: 0x%llx, align: 0x%llx, name: %s\n",729(unsigned long long)size,730(unsigned long long)min_addr,731(unsigned long long)max_addr,732(unsigned long long)alignment,733name);734#endif735if (cvmx_bootmem_desc->major_version != 3) {736cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: "737"%d.%d at addr: %p\n",738(int)cvmx_bootmem_desc->major_version,739(int)cvmx_bootmem_desc->minor_version,740cvmx_bootmem_desc);741return -1;742}743744/*745* Take lock here, as name lookup/block alloc/name add need to746* be atomic.747*/748if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))749cvmx_spinlock_lock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));750751/* Get pointer to first available named block descriptor */752named_block_desc_ptr =753cvmx_bootmem_phy_named_block_find(NULL,754flags | CVMX_BOOTMEM_FLAG_NO_LOCKING);755756/*757* Check to see if name already in use, return error if name758* not available or no more room for blocks.759*/760if (cvmx_bootmem_phy_named_block_find(name,761flags | CVMX_BOOTMEM_FLAG_NO_LOCKING) || !named_block_desc_ptr) {762if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))763cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));764return -1;765}766767768/*769* Round size up to mult of minimum alignment bytes We need770* the actual size allocated to allow for blocks to be771* coalesced when they are freed. The alloc routine does the772* same rounding up on all allocations.773*/774size = ALIGN(size, CVMX_BOOTMEM_ALIGNMENT_SIZE);775776addr_allocated = cvmx_bootmem_phy_alloc(size, min_addr, max_addr,777alignment,778flags | CVMX_BOOTMEM_FLAG_NO_LOCKING);779if (addr_allocated >= 0) {780named_block_desc_ptr->base_addr = addr_allocated;781named_block_desc_ptr->size = size;782strscpy(named_block_desc_ptr->name, name,783cvmx_bootmem_desc->named_block_name_len);784}785786if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))787cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));788return addr_allocated;789}790791struct cvmx_bootmem_desc *cvmx_bootmem_get_desc(void)792{793return cvmx_bootmem_desc;794}795796797