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 reserved
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])