4 * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
6 * Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
7 * Lajos Molnar <molnar@ti.com>
9 * Copyright (C) 2009-2010 Texas Instruments, Inc.
11 * This package is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 #include <linux/slab.h>
21 #include <linux/spinlock.h>
25 #define ALIGN_DOWN(value, align) ((value) & ~((align) - 1))
27 /* Individual selection criteria for different scan areas */
28 static s32 CR_L2R_T2B
= CR_BIAS_HORIZONTAL
;
29 static s32 CR_R2L_T2B
= CR_DIAGONAL_BALANCE
;
31 /*********************************************
32 * TCM API - Sita Implementation
33 *********************************************/
34 static s32
sita_reserve_2d(struct tcm
*tcm
, u16 h
, u16 w
, u8 align
,
35 struct tcm_area
*area
);
36 static s32
sita_reserve_1d(struct tcm
*tcm
, u32 slots
, struct tcm_area
*area
);
37 static s32
sita_free(struct tcm
*tcm
, struct tcm_area
*area
);
38 static void sita_deinit(struct tcm
*tcm
);
40 /*********************************************
41 * Main Scanner functions
42 *********************************************/
43 static s32
scan_areas_and_find_fit(struct tcm
*tcm
, u16 w
, u16 h
, u16 align
,
44 struct tcm_area
*area
);
46 static s32
scan_l2r_t2b(struct tcm
*tcm
, u16 w
, u16 h
, u16 align
,
47 struct tcm_area
*field
, struct tcm_area
*area
);
49 static s32
scan_r2l_t2b(struct tcm
*tcm
, u16 w
, u16 h
, u16 align
,
50 struct tcm_area
*field
, struct tcm_area
*area
);
52 static s32
scan_r2l_b2t_one_dim(struct tcm
*tcm
, u32 num_slots
,
53 struct tcm_area
*field
, struct tcm_area
*area
);
55 /*********************************************
56 * Support Infrastructure Methods
57 *********************************************/
58 static s32
is_area_free(struct tcm_area
***map
, u16 x0
, u16 y0
, u16 w
, u16 h
);
60 static s32
update_candidate(struct tcm
*tcm
, u16 x0
, u16 y0
, u16 w
, u16 h
,
61 struct tcm_area
*field
, s32 criteria
,
64 static void get_nearness_factor(struct tcm_area
*field
,
65 struct tcm_area
*candidate
,
66 struct nearness_factor
*nf
);
68 static void get_neighbor_stats(struct tcm
*tcm
, struct tcm_area
*area
,
69 struct neighbor_stats
*stat
);
71 static void fill_area(struct tcm
*tcm
,
72 struct tcm_area
*area
, struct tcm_area
*parent
);
75 /*********************************************/
77 /*********************************************
79 *********************************************/
80 struct tcm
*sita_init(u16 width
, u16 height
, struct tcm_pt
*attr
)
84 struct tcm_area area
= {0};
87 if (width
== 0 || height
== 0)
90 tcm
= kmalloc(sizeof(*tcm
), GFP_KERNEL
);
91 pvt
= kmalloc(sizeof(*pvt
), GFP_KERNEL
);
95 memset(tcm
, 0, sizeof(*tcm
));
96 memset(pvt
, 0, sizeof(*pvt
));
98 /* Updating the pointers to SiTA implementation APIs */
101 tcm
->reserve_2d
= sita_reserve_2d
;
102 tcm
->reserve_1d
= sita_reserve_1d
;
103 tcm
->free
= sita_free
;
104 tcm
->deinit
= sita_deinit
;
105 tcm
->pvt
= (void *)pvt
;
107 spin_lock_init(&(pvt
->lock
));
109 /* Creating tam map */
110 pvt
->map
= kmalloc(sizeof(*pvt
->map
) * tcm
->width
, GFP_KERNEL
);
114 for (i
= 0; i
< tcm
->width
; i
++) {
116 kmalloc(sizeof(**pvt
->map
) * tcm
->height
,
118 if (pvt
->map
[i
] == NULL
) {
126 if (attr
&& attr
->x
<= tcm
->width
&& attr
->y
<= tcm
->height
) {
127 pvt
->div_pt
.x
= attr
->x
;
128 pvt
->div_pt
.y
= attr
->y
;
131 /* Defaulting to 3:1 ratio on width for 2D area split */
132 /* Defaulting to 3:1 ratio on height for 2D and 1D split */
133 pvt
->div_pt
.x
= (tcm
->width
* 3) / 4;
134 pvt
->div_pt
.y
= (tcm
->height
* 3) / 4;
137 spin_lock(&(pvt
->lock
));
138 assign(&area
, 0, 0, width
- 1, height
- 1);
139 fill_area(tcm
, &area
, NULL
);
140 spin_unlock(&(pvt
->lock
));
149 static void sita_deinit(struct tcm
*tcm
)
151 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
152 struct tcm_area area
= {0};
155 area
.p1
.x
= tcm
->width
- 1;
156 area
.p1
.y
= tcm
->height
- 1;
158 spin_lock(&(pvt
->lock
));
159 fill_area(tcm
, &area
, NULL
);
160 spin_unlock(&(pvt
->lock
));
162 for (i
= 0; i
< tcm
->height
; i
++)
169 * Reserve a 1D area in the container
171 * @param num_slots size of 1D area
172 * @param area pointer to the area that will be populated with the
175 * @return 0 on success, non-0 error value on failure.
177 static s32
sita_reserve_1d(struct tcm
*tcm
, u32 num_slots
,
178 struct tcm_area
*area
)
181 struct tcm_area field
= {0};
182 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
184 spin_lock(&(pvt
->lock
));
186 /* Scanning entire container */
187 assign(&field
, tcm
->width
- 1, tcm
->height
- 1, 0, 0);
189 ret
= scan_r2l_b2t_one_dim(tcm
, num_slots
, &field
, area
);
192 fill_area(tcm
, area
, area
);
194 spin_unlock(&(pvt
->lock
));
199 * Reserve a 2D area in the container
203 * @param area pointer to the area that will be populated with the reesrved
206 * @return 0 on success, non-0 error value on failure.
208 static s32
sita_reserve_2d(struct tcm
*tcm
, u16 h
, u16 w
, u8 align
,
209 struct tcm_area
*area
)
212 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
214 /* not supporting more than 64 as alignment */
218 /* we prefer 1, 32 and 64 as alignment */
219 align
= align
<= 1 ? 1 : align
<= 32 ? 32 : 64;
221 spin_lock(&(pvt
->lock
));
222 ret
= scan_areas_and_find_fit(tcm
, w
, h
, align
, area
);
225 fill_area(tcm
, area
, area
);
227 spin_unlock(&(pvt
->lock
));
232 * Unreserve a previously allocated 2D or 1D area
233 * @param area area to be freed
234 * @return 0 - success
236 static s32
sita_free(struct tcm
*tcm
, struct tcm_area
*area
)
238 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
240 spin_lock(&(pvt
->lock
));
242 /* check that this is in fact an existing area */
243 WARN_ON(pvt
->map
[area
->p0
.x
][area
->p0
.y
] != area
||
244 pvt
->map
[area
->p1
.x
][area
->p1
.y
] != area
);
246 /* Clear the contents of the associated tiles in the map */
247 fill_area(tcm
, area
, NULL
);
249 spin_unlock(&(pvt
->lock
));
255 * Note: In general the cordinates in the scan field area relevant to the can
256 * sweep directions. The scan origin (e.g. top-left corner) will always be
257 * the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x
258 * and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y
263 * Raster scan horizontally right to left from top to bottom to find a place for
264 * a 2D area of given size inside a scan field.
266 * @param w width of desired area
267 * @param h height of desired area
268 * @param align desired area alignment
269 * @param area pointer to the area that will be set to the best position
270 * @param field area to scan (inclusive)
272 * @return 0 on success, non-0 error value on failure.
274 static s32
scan_r2l_t2b(struct tcm
*tcm
, u16 w
, u16 h
, u16 align
,
275 struct tcm_area
*field
, struct tcm_area
*area
)
278 s16 start_x
, end_x
, start_y
, end_y
, found_x
= -1;
279 struct tcm_area
***map
= ((struct sita_pvt
*)tcm
->pvt
)->map
;
280 struct score best
= {{0}, {0}, {0}, 0};
282 start_x
= field
->p0
.x
;
284 start_y
= field
->p0
.y
;
287 /* check scan area co-ordinates */
288 if (field
->p0
.x
< field
->p1
.x
||
289 field
->p1
.y
< field
->p0
.y
)
292 /* check if allocation would fit in scan area */
293 if (w
> LEN(start_x
, end_x
) || h
> LEN(end_y
, start_y
))
296 /* adjust start_x and end_y, as allocation would not fit beyond */
297 start_x
= ALIGN_DOWN(start_x
- w
+ 1, align
); /* - 1 to be inclusive */
298 end_y
= end_y
- h
+ 1;
300 /* check if allocation would still fit in scan area */
304 /* scan field top-to-bottom, right-to-left */
305 for (y
= start_y
; y
<= end_y
; y
++) {
306 for (x
= start_x
; x
>= end_x
; x
-= align
) {
307 if (is_area_free(map
, x
, y
, w
, h
)) {
310 /* update best candidate */
311 if (update_candidate(tcm
, x
, y
, w
, h
, field
,
315 /* change upper x bound */
318 } else if (map
[x
][y
] && map
[x
][y
]->is2d
) {
319 /* step over 2D areas */
320 x
= ALIGN(map
[x
][y
]->p0
.x
- w
+ 1, align
);
324 /* break if you find a free area shouldering the scan field */
325 if (found_x
== start_x
)
332 assign(area
, best
.a
.p0
.x
, best
.a
.p0
.y
, best
.a
.p1
.x
, best
.a
.p1
.y
);
337 * Raster scan horizontally left to right from top to bottom to find a place for
338 * a 2D area of given size inside a scan field.
340 * @param w width of desired area
341 * @param h height of desired area
342 * @param align desired area alignment
343 * @param area pointer to the area that will be set to the best position
344 * @param field area to scan (inclusive)
346 * @return 0 on success, non-0 error value on failure.
348 static s32
scan_l2r_t2b(struct tcm
*tcm
, u16 w
, u16 h
, u16 align
,
349 struct tcm_area
*field
, struct tcm_area
*area
)
352 s16 start_x
, end_x
, start_y
, end_y
, found_x
= -1;
353 struct tcm_area
***map
= ((struct sita_pvt
*)tcm
->pvt
)->map
;
354 struct score best
= {{0}, {0}, {0}, 0};
356 start_x
= field
->p0
.x
;
358 start_y
= field
->p0
.y
;
361 /* check scan area co-ordinates */
362 if (field
->p1
.x
< field
->p0
.x
||
363 field
->p1
.y
< field
->p0
.y
)
366 /* check if allocation would fit in scan area */
367 if (w
> LEN(end_x
, start_x
) || h
> LEN(end_y
, start_y
))
370 start_x
= ALIGN(start_x
, align
);
372 /* check if allocation would still fit in scan area */
373 if (w
> LEN(end_x
, start_x
))
376 /* adjust end_x and end_y, as allocation would not fit beyond */
377 end_x
= end_x
- w
+ 1; /* + 1 to be inclusive */
378 end_y
= end_y
- h
+ 1;
380 /* scan field top-to-bottom, left-to-right */
381 for (y
= start_y
; y
<= end_y
; y
++) {
382 for (x
= start_x
; x
<= end_x
; x
+= align
) {
383 if (is_area_free(map
, x
, y
, w
, h
)) {
386 /* update best candidate */
387 if (update_candidate(tcm
, x
, y
, w
, h
, field
,
390 /* change upper x bound */
394 } else if (map
[x
][y
] && map
[x
][y
]->is2d
) {
395 /* step over 2D areas */
396 x
= ALIGN_DOWN(map
[x
][y
]->p1
.x
, align
);
400 /* break if you find a free area shouldering the scan field */
401 if (found_x
== start_x
)
408 assign(area
, best
.a
.p0
.x
, best
.a
.p0
.y
, best
.a
.p1
.x
, best
.a
.p1
.y
);
413 * Raster scan horizontally right to left from bottom to top to find a place
414 * for a 1D area of given size inside a scan field.
416 * @param num_slots size of desired area
417 * @param align desired area alignment
418 * @param area pointer to the area that will be set to the best
420 * @param field area to scan (inclusive)
422 * @return 0 on success, non-0 error value on failure.
424 static s32
scan_r2l_b2t_one_dim(struct tcm
*tcm
, u32 num_slots
,
425 struct tcm_area
*field
, struct tcm_area
*area
)
429 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
432 /* check scan area co-ordinates */
433 if (field
->p0
.y
< field
->p1
.y
)
437 * Currently we only support full width 1D scan field, which makes sense
438 * since 1D slot-ordering spans the full container width.
440 if (tcm
->width
!= field
->p0
.x
- field
->p1
.x
+ 1)
443 /* check if allocation would fit in scan area */
444 if (num_slots
> tcm
->width
* LEN(field
->p0
.y
, field
->p1
.y
))
450 /* find num_slots consecutive free slots to the left */
451 while (found
< num_slots
) {
455 /* remember bottom-right corner */
461 /* skip busy regions */
464 /* move to left of 2D areas, top left of 1D */
472 /* count consecutive free slots */
474 if (found
== num_slots
)
478 /* move to the left */
481 x
= (x
? : tcm
->width
) - 1;
485 /* set top-left corner */
492 * Find a place for a 2D area of given size inside a scan field based on its
495 * @param w width of desired area
496 * @param h height of desired area
497 * @param align desired area alignment
498 * @param area pointer to the area that will be set to the best position
500 * @return 0 on success, non-0 error value on failure.
502 static s32
scan_areas_and_find_fit(struct tcm
*tcm
, u16 w
, u16 h
, u16 align
,
503 struct tcm_area
*area
)
506 struct tcm_area field
= {0};
507 u16 boundary_x
, boundary_y
;
508 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
511 /* prefer top-left corner */
512 boundary_x
= pvt
->div_pt
.x
- 1;
513 boundary_y
= pvt
->div_pt
.y
- 1;
515 /* expand width and height if needed */
516 if (w
> pvt
->div_pt
.x
)
517 boundary_x
= tcm
->width
- 1;
518 if (h
> pvt
->div_pt
.y
)
519 boundary_y
= tcm
->height
- 1;
521 assign(&field
, 0, 0, boundary_x
, boundary_y
);
522 ret
= scan_l2r_t2b(tcm
, w
, h
, align
, &field
, area
);
524 /* scan whole container if failed, but do not scan 2x */
525 if (ret
!= 0 && (boundary_x
!= tcm
->width
- 1 ||
526 boundary_y
!= tcm
->height
- 1)) {
527 /* scan the entire container if nothing found */
528 assign(&field
, 0, 0, tcm
->width
- 1, tcm
->height
- 1);
529 ret
= scan_l2r_t2b(tcm
, w
, h
, align
, &field
, area
);
531 } else if (align
== 1) {
532 /* prefer top-right corner */
533 boundary_x
= pvt
->div_pt
.x
;
534 boundary_y
= pvt
->div_pt
.y
- 1;
536 /* expand width and height if needed */
537 if (w
> (tcm
->width
- pvt
->div_pt
.x
))
539 if (h
> pvt
->div_pt
.y
)
540 boundary_y
= tcm
->height
- 1;
542 assign(&field
, tcm
->width
- 1, 0, boundary_x
, boundary_y
);
543 ret
= scan_r2l_t2b(tcm
, w
, h
, align
, &field
, area
);
545 /* scan whole container if failed, but do not scan 2x */
546 if (ret
!= 0 && (boundary_x
!= 0 ||
547 boundary_y
!= tcm
->height
- 1)) {
548 /* scan the entire container if nothing found */
549 assign(&field
, tcm
->width
- 1, 0, 0, tcm
->height
- 1);
550 ret
= scan_r2l_t2b(tcm
, w
, h
, align
, &field
,
558 /* check if an entire area is free */
559 static s32
is_area_free(struct tcm_area
***map
, u16 x0
, u16 y0
, u16 w
, u16 h
)
562 for (y
= y0
; y
< y0
+ h
; y
++) {
563 for (x
= x0
; x
< x0
+ w
; x
++) {
571 /* fills an area with a parent tcm_area */
572 static void fill_area(struct tcm
*tcm
, struct tcm_area
*area
,
573 struct tcm_area
*parent
)
576 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
577 struct tcm_area a
, a_
;
579 /* set area's tcm; otherwise, enumerator considers it invalid */
582 tcm_for_each_slice(a
, *area
, a_
) {
583 for (x
= a
.p0
.x
; x
<= a
.p1
.x
; ++x
)
584 for (y
= a
.p0
.y
; y
<= a
.p1
.y
; ++y
)
585 pvt
->map
[x
][y
] = parent
;
591 * Compares a candidate area to the current best area, and if it is a better
592 * fit, it updates the best to this one.
594 * @param x0, y0, w, h top, left, width, height of candidate area
595 * @param field scan field
596 * @param criteria scan criteria
597 * @param best best candidate and its scores
599 * @return 1 (true) if the candidate area is known to be the final best, so no
600 * more searching should be performed
602 static s32
update_candidate(struct tcm
*tcm
, u16 x0
, u16 y0
, u16 w
, u16 h
,
603 struct tcm_area
*field
, s32 criteria
,
606 struct score me
; /* score for area */
609 * NOTE: For horizontal bias we always give the first found, because our
610 * scan is horizontal-raster-based and the first candidate will always
611 * have the horizontal bias.
613 bool first
= criteria
& CR_BIAS_HORIZONTAL
;
615 assign(&me
.a
, x0
, y0
, x0
+ w
- 1, y0
+ h
- 1);
617 /* calculate score for current candidate */
619 get_neighbor_stats(tcm
, &me
.a
, &me
.n
);
620 me
.neighs
= me
.n
.edge
+ me
.n
.busy
;
621 get_nearness_factor(field
, &me
.a
, &me
.f
);
624 /* the 1st candidate is always the best */
630 /* diagonal balance check */
631 if ((criteria
& CR_DIAGONAL_BALANCE
) &&
632 best
->neighs
<= me
.neighs
&&
633 (best
->neighs
< me
.neighs
||
634 /* this implies that neighs and occupied match */
635 best
->n
.busy
< me
.n
.busy
||
636 (best
->n
.busy
== me
.n
.busy
&&
637 /* check the nearness factor */
638 best
->f
.x
+ best
->f
.y
> me
.f
.x
+ me
.f
.y
)))
641 /* not better, keep going */
645 /* save current area as best */
646 memcpy(best
, &me
, sizeof(me
));
652 * Calculate the nearness factor of an area in a search field. The nearness
653 * factor is smaller if the area is closer to the search origin.
655 static void get_nearness_factor(struct tcm_area
*field
, struct tcm_area
*area
,
656 struct nearness_factor
*nf
)
659 * Using signed math as field coordinates may be reversed if
660 * search direction is right-to-left or bottom-to-top.
662 nf
->x
= (s32
)(area
->p0
.x
- field
->p0
.x
) * 1000 /
663 (field
->p1
.x
- field
->p0
.x
);
664 nf
->y
= (s32
)(area
->p0
.y
- field
->p0
.y
) * 1000 /
665 (field
->p1
.y
- field
->p0
.y
);
668 /* get neighbor statistics */
669 static void get_neighbor_stats(struct tcm
*tcm
, struct tcm_area
*area
,
670 struct neighbor_stats
*stat
)
673 struct sita_pvt
*pvt
= (struct sita_pvt
*)tcm
->pvt
;
675 /* Clearing any exisiting values */
676 memset(stat
, 0, sizeof(*stat
));
678 /* process top & bottom edges */
679 for (x
= area
->p0
.x
; x
<= area
->p1
.x
; x
++) {
682 else if (pvt
->map
[x
][area
->p0
.y
- 1])
685 if (area
->p1
.y
== tcm
->height
- 1)
687 else if (pvt
->map
[x
][area
->p1
.y
+ 1])
691 /* process left & right edges */
692 for (y
= area
->p0
.y
; y
<= area
->p1
.y
; ++y
) {
695 else if (pvt
->map
[area
->p0
.x
- 1][y
])
698 if (area
->p1
.x
== tcm
->width
- 1)
700 else if (pvt
->map
[area
->p1
.x
+ 1][y
])