blob: 564991b5fc1d10587393f87358e29a6e1dbefc2f [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* A simple memory allocator to help allocating reserved memory pools.
*
* Copyright (C) 2022 Google LLC
*/
#include <linux/device.h>
#include <linux/genalloc.h>
#include <linux/log2.h>
#include <linux/types.h>
#include <gcip/gcip-mem-pool.h>
int gcip_mem_pool_init(struct gcip_mem_pool *pool, struct device *dev, unsigned long base_addr,
size_t size, size_t granule)
{
int ret;
if (!base_addr || granule == 0)
return -EINVAL;
if (base_addr % granule || size % granule)
return -EINVAL;
pool->gen_pool = gen_pool_create(ilog2(granule), -1);
if (!pool->gen_pool) {
dev_err(dev, "gcip memory pool allocate gen_pool failed");
return -ENOMEM;
}
ret = gen_pool_add(pool->gen_pool, base_addr, size, -1);
if (ret) {
gen_pool_destroy(pool->gen_pool);
pool->gen_pool = NULL;
dev_err(dev, "gcip failed to add memory to mem pool: %d", ret);
return ret;
}
pool->dev = dev;
pool->granule = granule;
pool->base_addr = base_addr;
return 0;
}
void gcip_mem_pool_exit(struct gcip_mem_pool *pool)
{
if (!pool->gen_pool)
return;
gen_pool_destroy(pool->gen_pool);
pool->gen_pool = NULL;
}
unsigned long gcip_mem_pool_alloc(struct gcip_mem_pool *pool, size_t size)
{
unsigned long addr;
addr = gen_pool_alloc(pool->gen_pool, size);
if (!addr)
return 0;
dev_dbg(pool->dev, "%s @ size = %#zx addr=%#lx", __func__, size, addr);
return addr;
}
void gcip_mem_pool_free(struct gcip_mem_pool *pool, unsigned long addr, size_t size)
{
dev_dbg(pool->dev, "%s @ size = %#zx addr=%#lx", __func__, size, addr);
size = ALIGN(size, pool->granule);
gen_pool_free(pool->gen_pool, addr, size);
}