summaryrefslogtreecommitdiff
path: root/gcip-kernel-driver/drivers/gcip/gcip-mem-pool.c
blob: 564991b5fc1d10587393f87358e29a6e1dbefc2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 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);
}