2 * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
4 * Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
5 * Lajos Molnar <molnar@ti.com>
6 * Andy Gross <andy.gross@ti.com>
8 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/errno.h>
22 #include <linux/sched.h>
23 #include <linux/wait.h>
24 #include <linux/bitmap.h>
25 #include <linux/slab.h>
28 static unsigned long mask
[8];
30 * pos position in bitmap
34 * stride slots in a row
36 static void free_slots(unsigned long pos
, uint16_t w
, uint16_t h
,
37 unsigned long *map
, uint16_t stride
)
41 for (i
= 0; i
< h
; i
++, pos
+= stride
)
42 bitmap_clear(map
, pos
, w
);
49 * num_bits number of bits in bitmap
51 static int r2l_b2t_1d(uint16_t w
, unsigned long *pos
, unsigned long *map
,
54 unsigned long search_count
= 0;
56 bool area_found
= false;
60 while (search_count
< num_bits
) {
61 bit
= find_next_bit(map
, num_bits
, *pos
);
63 if (bit
- *pos
>= w
) {
64 /* found a long enough free area */
65 bitmap_set(map
, *pos
, w
);
70 search_count
= num_bits
- bit
+ w
;
74 return (area_found
) ? 0 : -ENOMEM
;
80 * a = align in slots (mask, 2^n-1, 0 is unaligned)
81 * offset = offset in bytes from 4KiB
82 * pos = position in bitmap for buffer
84 * num_bits = size of bitmap
85 * stride = bits in one row of container
87 static int l2r_t2b(uint16_t w
, uint16_t h
, uint16_t a
, int16_t offset
,
88 unsigned long *pos
, unsigned long slot_bytes
,
89 unsigned long *map
, size_t num_bits
, size_t slot_stride
)
94 unsigned long slots_per_band
= PAGE_SIZE
/ slot_bytes
;
95 unsigned long bit_offset
= (offset
> 0) ? offset
/ slot_bytes
: 0;
96 unsigned long curr_bit
= bit_offset
;
98 /* reset alignment to 1 if we are matching a specific offset */
99 /* adjust alignment - 1 to get to the format expected in bitmaps */
100 a
= (offset
> 0) ? 0 : a
- 1;
102 /* FIXME Return error if slots_per_band > stride */
104 while (curr_bit
< num_bits
) {
105 *pos
= bitmap_find_next_zero_area(map
, num_bits
, curr_bit
, w
,
108 /* skip forward if we are not at right offset */
109 if (bit_offset
> 0 && (*pos
% slots_per_band
!= bit_offset
)) {
110 curr_bit
= ALIGN(*pos
, slots_per_band
) + bit_offset
;
114 /* skip forward to next row if we overlap end of row */
115 if ((*pos
% slot_stride
) + w
> slot_stride
) {
116 curr_bit
= ALIGN(*pos
, slot_stride
) + bit_offset
;
120 /* TODO: Handle overlapping 4K boundaries */
122 /* break out of look if we will go past end of container */
123 if ((*pos
+ slot_stride
* h
) > num_bits
)
126 /* generate mask that represents out matching pattern */
127 bitmap_clear(mask
, 0, slot_stride
);
128 bitmap_set(mask
, (*pos
% BITS_PER_LONG
), w
);
130 /* assume the area is free until we find an overlap */
133 /* check subsequent rows to see if complete area is free */
134 for (i
= 1; i
< h
; i
++) {
135 index
= *pos
/ BITS_PER_LONG
+ i
* 8;
136 if (bitmap_intersects(&map
[index
], mask
,
137 (*pos
% BITS_PER_LONG
) + w
)) {
146 /* go forward past this match */
148 curr_bit
= ALIGN(*pos
, slots_per_band
) + bit_offset
;
150 curr_bit
= *pos
+ a
+ 1;
154 /* set area as in-use. iterate over rows */
155 for (i
= 0, index
= *pos
; i
< h
; i
++, index
+= slot_stride
)
156 bitmap_set(map
, index
, w
);
159 return (area_free
) ? 0 : -ENOMEM
;
162 static s32
sita_reserve_1d(struct tcm
*tcm
, u32 num_slots
,
163 struct tcm_area
*area
)
168 spin_lock(&(tcm
->lock
));
169 ret
= r2l_b2t_1d(num_slots
, &pos
, tcm
->bitmap
, tcm
->map_size
);
171 area
->p0
.x
= pos
% tcm
->width
;
172 area
->p0
.y
= pos
/ tcm
->width
;
173 area
->p1
.x
= (pos
+ num_slots
- 1) % tcm
->width
;
174 area
->p1
.y
= (pos
+ num_slots
- 1) / tcm
->width
;
176 spin_unlock(&(tcm
->lock
));
181 static s32
sita_reserve_2d(struct tcm
*tcm
, u16 h
, u16 w
, u16 align
,
182 int16_t offset
, uint16_t slot_bytes
,
183 struct tcm_area
*area
)
188 spin_lock(&(tcm
->lock
));
189 ret
= l2r_t2b(w
, h
, align
, offset
, &pos
, slot_bytes
, tcm
->bitmap
,
190 tcm
->map_size
, tcm
->width
);
193 area
->p0
.x
= pos
% tcm
->width
;
194 area
->p0
.y
= pos
/ tcm
->width
;
195 area
->p1
.x
= area
->p0
.x
+ w
- 1;
196 area
->p1
.y
= area
->p0
.y
+ h
- 1;
198 spin_unlock(&(tcm
->lock
));
203 static void sita_deinit(struct tcm
*tcm
)
208 static s32
sita_free(struct tcm
*tcm
, struct tcm_area
*area
)
213 pos
= area
->p0
.x
+ area
->p0
.y
* tcm
->width
;
215 w
= area
->p1
.x
- area
->p0
.x
+ 1;
216 h
= area
->p1
.y
- area
->p0
.y
+ 1;
218 w
= area
->p1
.x
+ area
->p1
.y
* tcm
->width
- pos
+ 1;
222 spin_lock(&(tcm
->lock
));
223 free_slots(pos
, w
, h
, tcm
->bitmap
, tcm
->width
);
224 spin_unlock(&(tcm
->lock
));
228 struct tcm
*sita_init(u16 width
, u16 height
)
231 size_t map_size
= BITS_TO_LONGS(width
*height
) * sizeof(unsigned long);
233 if (width
== 0 || height
== 0)
236 tcm
= kzalloc(sizeof(*tcm
) + map_size
, GFP_KERNEL
);
240 /* Updating the pointers to SiTA implementation APIs */
241 tcm
->height
= height
;
243 tcm
->reserve_2d
= sita_reserve_2d
;
244 tcm
->reserve_1d
= sita_reserve_1d
;
245 tcm
->free
= sita_free
;
246 tcm
->deinit
= sita_deinit
;
248 spin_lock_init(&tcm
->lock
);
249 tcm
->bitmap
= (unsigned long *)(tcm
+ 1);
250 bitmap_clear(tcm
->bitmap
, 0, width
*height
);
252 tcm
->map_size
= width
*height
;