blob: 71cacda4dc793ed7680d7ab7df64ddd19bcfd437 [file] [log] [blame]
Naveen Ramaraj959d37f2012-04-23 11:59:01 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <mach/ocmem.h>
14#include <mach/ocmem_priv.h>
15#include <linux/genalloc.h>
16
17/* All allocator operations are serialized by ocmem driver */
Naveen Ramaraj135cd672012-04-23 12:13:28 -070018
19/* The allocators work as follows:
20 Constraints:
21 1) There is no IOMMU access to OCMEM hence successive allocations
22 in the zone must be physically contiguous
23 2) Allocations must be freed in reverse order within a zone.
24
25 z->z_start: Fixed pointer to the start of a zone
26 z->z_end: Fixed pointer to the end of a zone
27
28 z->z_head: Movable pointer to the next free area when growing at head
29 Fixed on zones that grow from tail
30
31 z->z_tail: Movable pointer to the next free area when growing at tail
32 Fixed on zones that grow from head
33
34 z->z_free: Free space in a zone that is updated on an allocation/free
35
36 reserve: Enable libgenpool to simulate tail allocations
37*/
38
Naveen Ramaraj959d37f2012-04-23 11:59:01 -070039unsigned long allocate_head(struct ocmem_zone *z, unsigned long size)
40{
41
42 unsigned long offset;
43
44 offset = gen_pool_alloc(z->z_pool, size);
45
46 if (!offset)
47 return -ENOMEM;
48
49 z->z_head += size;
50 z->z_free -= size;
51 return offset;
52}
53
Naveen Ramaraj135cd672012-04-23 12:13:28 -070054unsigned long allocate_tail(struct ocmem_zone *z, unsigned long size)
55{
56 unsigned long offset;
57 unsigned long reserve;
58 unsigned long head;
59
60 if (z->z_tail < (z->z_head + size))
61 return -ENOMEM;
62
63 reserve = z->z_tail - z->z_head - size;
64 if (reserve) {
65 head = gen_pool_alloc(z->z_pool, reserve);
66 offset = gen_pool_alloc(z->z_pool, size);
67 gen_pool_free(z->z_pool, head, reserve);
68 } else
69 offset = gen_pool_alloc(z->z_pool, size);
70
71 if (!offset)
72 return -ENOMEM;
73
74 z->z_tail -= size;
75 z->z_free -= size;
76 return offset;
77}
78
Naveen Ramaraj959d37f2012-04-23 11:59:01 -070079int free_head(struct ocmem_zone *z, unsigned long offset,
80 unsigned long size)
81{
82 if (offset > z->z_head) {
83 pr_err("ocmem: Detected out of order free "
84 "leading to fragmentation\n");
85 return -EINVAL;
86 }
87 gen_pool_free(z->z_pool, offset, size);
88 z->z_head -= size;
89 z->z_free += size;
90 return 0;
91}
Naveen Ramaraj135cd672012-04-23 12:13:28 -070092
93int free_tail(struct ocmem_zone *z, unsigned long offset,
94 unsigned long size)
95{
96 if (offset > z->z_tail) {
97 pr_err("ocmem: Detected out of order free "
98 "leading to fragmentation\n");
99 return -EINVAL;
100 }
101 gen_pool_free(z->z_pool, offset, size);
102 z->z_tail += size;
103 z->z_free += size;
104 return 0;
105}