diff options
author | David Daney <ddaney@caviumnetworks.com> | 2009-05-05 17:35:16 -0700 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-06-17 11:06:29 +0100 |
commit | 6fa044ab8ab609bf95423b2841e20a2f4bb3a86d (patch) | |
tree | 666130477775132de1058596cabc17646ce03ed7 /arch/mips/cavium-octeon | |
parent | ce65cc8fe22a572ea9ec88e203388558b6b863af (diff) |
MIPS: Add named alloc functions to OCTEON boot monitor memory allocator.
The various Octeon ethernet drivers use these new functions.
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/cavium-octeon')
-rw-r--r-- | arch/mips/cavium-octeon/executive/cvmx-bootmem.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c index 4f5a08b37ccd..25666da17b22 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c +++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c @@ -31,6 +31,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <asm/octeon/cvmx.h> #include <asm/octeon/cvmx-spinlock.h> @@ -97,6 +98,33 @@ void *cvmx_bootmem_alloc(uint64_t size, uint64_t alignment) return cvmx_bootmem_alloc_range(size, alignment, 0, 0); } +void *cvmx_bootmem_alloc_named_range(uint64_t size, uint64_t min_addr, + uint64_t max_addr, uint64_t align, + char *name) +{ + int64_t addr; + + addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr, + align, name, 0); + if (addr >= 0) + return cvmx_phys_to_ptr(addr); + else + return NULL; +} + +void *cvmx_bootmem_alloc_named_address(uint64_t size, uint64_t address, + char *name) +{ + return cvmx_bootmem_alloc_named_range(size, address, address + size, + 0, name); +} + +void *cvmx_bootmem_alloc_named(uint64_t size, uint64_t alignment, char *name) +{ + return cvmx_bootmem_alloc_named_range(size, 0, 0, alignment, name); +} +EXPORT_SYMBOL(cvmx_bootmem_alloc_named); + int cvmx_bootmem_free_named(char *name) { return cvmx_bootmem_phy_named_block_free(name, 0); @@ -106,6 +134,7 @@ struct cvmx_bootmem_named_block_desc *cvmx_bootmem_find_named_block(char *name) { return cvmx_bootmem_phy_named_block_find(name, 0); } +EXPORT_SYMBOL(cvmx_bootmem_find_named_block); void cvmx_bootmem_lock(void) { @@ -584,3 +613,78 @@ int cvmx_bootmem_phy_named_block_free(char *name, uint32_t flags) cvmx_bootmem_unlock(); return named_block_ptr != NULL; /* 0 on failure, 1 on success */ } + +int64_t cvmx_bootmem_phy_named_block_alloc(uint64_t size, uint64_t min_addr, + uint64_t max_addr, + uint64_t alignment, + char *name, + uint32_t flags) +{ + int64_t addr_allocated; + struct cvmx_bootmem_named_block_desc *named_block_desc_ptr; + +#ifdef DEBUG + cvmx_dprintf("cvmx_bootmem_phy_named_block_alloc: size: 0x%llx, min: " + "0x%llx, max: 0x%llx, align: 0x%llx, name: %s\n", + (unsigned long long)size, + (unsigned long long)min_addr, + (unsigned long long)max_addr, + (unsigned long long)alignment, + name); +#endif + if (cvmx_bootmem_desc->major_version != 3) { + cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: " + "%d.%d at addr: %p\n", + (int)cvmx_bootmem_desc->major_version, + (int)cvmx_bootmem_desc->minor_version, + cvmx_bootmem_desc); + return -1; + } + + /* + * Take lock here, as name lookup/block alloc/name add need to + * be atomic. + */ + if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) + cvmx_spinlock_lock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock)); + + /* Get pointer to first available named block descriptor */ + named_block_desc_ptr = + cvmx_bootmem_phy_named_block_find(NULL, + flags | CVMX_BOOTMEM_FLAG_NO_LOCKING); + + /* + * Check to see if name already in use, return error if name + * not available or no more room for blocks. + */ + if (cvmx_bootmem_phy_named_block_find(name, + flags | CVMX_BOOTMEM_FLAG_NO_LOCKING) || !named_block_desc_ptr) { + if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) + cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock)); + return -1; + } + + + /* + * Round size up to mult of minimum alignment bytes We need + * the actual size allocated to allow for blocks to be + * coallesced when they are freed. The alloc routine does the + * same rounding up on all allocations. + */ + size = __ALIGN_MASK(size, (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)); + + addr_allocated = cvmx_bootmem_phy_alloc(size, min_addr, max_addr, + alignment, + flags | CVMX_BOOTMEM_FLAG_NO_LOCKING); + if (addr_allocated >= 0) { + named_block_desc_ptr->base_addr = addr_allocated; + named_block_desc_ptr->size = size; + strncpy(named_block_desc_ptr->name, name, + cvmx_bootmem_desc->named_block_name_len); + named_block_desc_ptr->name[cvmx_bootmem_desc->named_block_name_len - 1] = 0; + } + + if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) + cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock)); + return addr_allocated; +} |