Merge tag 'char-misc-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[deliverable/linux.git] / drivers / gpu / drm / omapdrm / tcm-sita.c
1 /*
2 * tcm-sita.c
3 *
4 * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
5 *
6 * Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
7 * Lajos Molnar <molnar@ti.com>
8 *
9 * Copyright (C) 2009-2010 Texas Instruments, Inc.
10 *
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.
14 *
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.
18 *
19 */
20 #include <linux/slab.h>
21 #include <linux/spinlock.h>
22
23 #include "tcm-sita.h"
24
25 #define ALIGN_DOWN(value, align) ((value) & ~((align) - 1))
26
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;
30
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);
39
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);
45
46 static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
47 struct tcm_area *field, struct tcm_area *area);
48
49 static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
50 struct tcm_area *field, struct tcm_area *area);
51
52 static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
53 struct tcm_area *field, struct tcm_area *area);
54
55 /*********************************************
56 * Support Infrastructure Methods
57 *********************************************/
58 static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h);
59
60 static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
61 struct tcm_area *field, s32 criteria,
62 struct score *best);
63
64 static void get_nearness_factor(struct tcm_area *field,
65 struct tcm_area *candidate,
66 struct nearness_factor *nf);
67
68 static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
69 struct neighbor_stats *stat);
70
71 static void fill_area(struct tcm *tcm,
72 struct tcm_area *area, struct tcm_area *parent);
73
74
75 /*********************************************/
76
77 /*********************************************
78 * Utility Methods
79 *********************************************/
80 struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
81 {
82 struct tcm *tcm;
83 struct sita_pvt *pvt;
84 struct tcm_area area = {0};
85 s32 i;
86
87 if (width == 0 || height == 0)
88 return NULL;
89
90 tcm = kmalloc(sizeof(*tcm), GFP_KERNEL);
91 pvt = kmalloc(sizeof(*pvt), GFP_KERNEL);
92 if (!tcm || !pvt)
93 goto error;
94
95 memset(tcm, 0, sizeof(*tcm));
96 memset(pvt, 0, sizeof(*pvt));
97
98 /* Updating the pointers to SiTA implementation APIs */
99 tcm->height = height;
100 tcm->width = width;
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;
106
107 spin_lock_init(&(pvt->lock));
108
109 /* Creating tam map */
110 pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL);
111 if (!pvt->map)
112 goto error;
113
114 for (i = 0; i < tcm->width; i++) {
115 pvt->map[i] =
116 kmalloc(sizeof(**pvt->map) * tcm->height,
117 GFP_KERNEL);
118 if (pvt->map[i] == NULL) {
119 while (i--)
120 kfree(pvt->map[i]);
121 kfree(pvt->map);
122 goto error;
123 }
124 }
125
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;
129
130 } else {
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;
135 }
136
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));
141 return tcm;
142
143 error:
144 kfree(tcm);
145 kfree(pvt);
146 return NULL;
147 }
148
149 static void sita_deinit(struct tcm *tcm)
150 {
151 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
152 struct tcm_area area = {0};
153 s32 i;
154
155 area.p1.x = tcm->width - 1;
156 area.p1.y = tcm->height - 1;
157
158 spin_lock(&(pvt->lock));
159 fill_area(tcm, &area, NULL);
160 spin_unlock(&(pvt->lock));
161
162 for (i = 0; i < tcm->height; i++)
163 kfree(pvt->map[i]);
164 kfree(pvt->map);
165 kfree(pvt);
166 }
167
168 /**
169 * Reserve a 1D area in the container
170 *
171 * @param num_slots size of 1D area
172 * @param area pointer to the area that will be populated with the
173 * reserved area
174 *
175 * @return 0 on success, non-0 error value on failure.
176 */
177 static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
178 struct tcm_area *area)
179 {
180 s32 ret;
181 struct tcm_area field = {0};
182 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
183
184 spin_lock(&(pvt->lock));
185
186 /* Scanning entire container */
187 assign(&field, tcm->width - 1, tcm->height - 1, 0, 0);
188
189 ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area);
190 if (!ret)
191 /* update map */
192 fill_area(tcm, area, area);
193
194 spin_unlock(&(pvt->lock));
195 return ret;
196 }
197
198 /**
199 * Reserve a 2D area in the container
200 *
201 * @param w width
202 * @param h height
203 * @param area pointer to the area that will be populated with the reserved
204 * area
205 *
206 * @return 0 on success, non-0 error value on failure.
207 */
208 static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
209 struct tcm_area *area)
210 {
211 s32 ret;
212 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
213
214 /* not supporting more than 64 as alignment */
215 if (align > 64)
216 return -EINVAL;
217
218 /* we prefer 1, 32 and 64 as alignment */
219 align = align <= 1 ? 1 : align <= 32 ? 32 : 64;
220
221 spin_lock(&(pvt->lock));
222 ret = scan_areas_and_find_fit(tcm, w, h, align, area);
223 if (!ret)
224 /* update map */
225 fill_area(tcm, area, area);
226
227 spin_unlock(&(pvt->lock));
228 return ret;
229 }
230
231 /**
232 * Unreserve a previously allocated 2D or 1D area
233 * @param area area to be freed
234 * @return 0 - success
235 */
236 static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
237 {
238 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
239
240 spin_lock(&(pvt->lock));
241
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);
245
246 /* Clear the contents of the associated tiles in the map */
247 fill_area(tcm, area, NULL);
248
249 spin_unlock(&(pvt->lock));
250
251 return 0;
252 }
253
254 /**
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
259 * <= p0.y
260 */
261
262 /**
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.
265 *
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)
271 *
272 * @return 0 on success, non-0 error value on failure.
273 */
274 static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
275 struct tcm_area *field, struct tcm_area *area)
276 {
277 s32 x, y;
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};
281
282 start_x = field->p0.x;
283 end_x = field->p1.x;
284 start_y = field->p0.y;
285 end_y = field->p1.y;
286
287 /* check scan area co-ordinates */
288 if (field->p0.x < field->p1.x ||
289 field->p1.y < field->p0.y)
290 return -EINVAL;
291
292 /* check if allocation would fit in scan area */
293 if (w > LEN(start_x, end_x) || h > LEN(end_y, start_y))
294 return -ENOSPC;
295
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;
299
300 /* check if allocation would still fit in scan area */
301 if (start_x < end_x)
302 return -ENOSPC;
303
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)) {
308 found_x = x;
309
310 /* update best candidate */
311 if (update_candidate(tcm, x, y, w, h, field,
312 CR_R2L_T2B, &best))
313 goto done;
314
315 /* change upper x bound */
316 end_x = x + 1;
317 break;
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);
321 }
322 }
323
324 /* break if you find a free area shouldering the scan field */
325 if (found_x == start_x)
326 break;
327 }
328
329 if (!best.a.tcm)
330 return -ENOSPC;
331 done:
332 assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
333 return 0;
334 }
335
336 /**
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.
339 *
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)
345 *
346 * @return 0 on success, non-0 error value on failure.
347 */
348 static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
349 struct tcm_area *field, struct tcm_area *area)
350 {
351 s32 x, y;
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};
355
356 start_x = field->p0.x;
357 end_x = field->p1.x;
358 start_y = field->p0.y;
359 end_y = field->p1.y;
360
361 /* check scan area co-ordinates */
362 if (field->p1.x < field->p0.x ||
363 field->p1.y < field->p0.y)
364 return -EINVAL;
365
366 /* check if allocation would fit in scan area */
367 if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y))
368 return -ENOSPC;
369
370 start_x = ALIGN(start_x, align);
371
372 /* check if allocation would still fit in scan area */
373 if (w > LEN(end_x, start_x))
374 return -ENOSPC;
375
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;
379
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)) {
384 found_x = x;
385
386 /* update best candidate */
387 if (update_candidate(tcm, x, y, w, h, field,
388 CR_L2R_T2B, &best))
389 goto done;
390 /* change upper x bound */
391 end_x = x - 1;
392
393 break;
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);
397 }
398 }
399
400 /* break if you find a free area shouldering the scan field */
401 if (found_x == start_x)
402 break;
403 }
404
405 if (!best.a.tcm)
406 return -ENOSPC;
407 done:
408 assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
409 return 0;
410 }
411
412 /**
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.
415 *
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
419 * position
420 * @param field area to scan (inclusive)
421 *
422 * @return 0 on success, non-0 error value on failure.
423 */
424 static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
425 struct tcm_area *field, struct tcm_area *area)
426 {
427 s32 found = 0;
428 s16 x, y;
429 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
430 struct tcm_area *p;
431
432 /* check scan area co-ordinates */
433 if (field->p0.y < field->p1.y)
434 return -EINVAL;
435
436 /**
437 * Currently we only support full width 1D scan field, which makes sense
438 * since 1D slot-ordering spans the full container width.
439 */
440 if (tcm->width != field->p0.x - field->p1.x + 1)
441 return -EINVAL;
442
443 /* check if allocation would fit in scan area */
444 if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y))
445 return -ENOSPC;
446
447 x = field->p0.x;
448 y = field->p0.y;
449
450 /* find num_slots consecutive free slots to the left */
451 while (found < num_slots) {
452 if (y < 0)
453 return -ENOSPC;
454
455 /* remember bottom-right corner */
456 if (found == 0) {
457 area->p1.x = x;
458 area->p1.y = y;
459 }
460
461 /* skip busy regions */
462 p = pvt->map[x][y];
463 if (p) {
464 /* move to left of 2D areas, top left of 1D */
465 x = p->p0.x;
466 if (!p->is2d)
467 y = p->p0.y;
468
469 /* start over */
470 found = 0;
471 } else {
472 /* count consecutive free slots */
473 found++;
474 if (found == num_slots)
475 break;
476 }
477
478 /* move to the left */
479 if (x == 0)
480 y--;
481 x = (x ? : tcm->width) - 1;
482
483 }
484
485 /* set top-left corner */
486 area->p0.x = x;
487 area->p0.y = y;
488 return 0;
489 }
490
491 /**
492 * Find a place for a 2D area of given size inside a scan field based on its
493 * alignment needs.
494 *
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
499 *
500 * @return 0 on success, non-0 error value on failure.
501 */
502 static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
503 struct tcm_area *area)
504 {
505 s32 ret = 0;
506 struct tcm_area field = {0};
507 u16 boundary_x, boundary_y;
508 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
509
510 if (align > 1) {
511 /* prefer top-left corner */
512 boundary_x = pvt->div_pt.x - 1;
513 boundary_y = pvt->div_pt.y - 1;
514
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;
520
521 assign(&field, 0, 0, boundary_x, boundary_y);
522 ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
523
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);
530 }
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;
535
536 /* expand width and height if needed */
537 if (w > (tcm->width - pvt->div_pt.x))
538 boundary_x = 0;
539 if (h > pvt->div_pt.y)
540 boundary_y = tcm->height - 1;
541
542 assign(&field, tcm->width - 1, 0, boundary_x, boundary_y);
543 ret = scan_r2l_t2b(tcm, w, h, align, &field, area);
544
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,
551 area);
552 }
553 }
554
555 return ret;
556 }
557
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)
560 {
561 u16 x = 0, y = 0;
562 for (y = y0; y < y0 + h; y++) {
563 for (x = x0; x < x0 + w; x++) {
564 if (map[x][y])
565 return false;
566 }
567 }
568 return true;
569 }
570
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)
574 {
575 s32 x, y;
576 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
577 struct tcm_area a, a_;
578
579 /* set area's tcm; otherwise, enumerator considers it invalid */
580 area->tcm = tcm;
581
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;
586
587 }
588 }
589
590 /**
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.
593 *
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
598 *
599 * @return 1 (true) if the candidate area is known to be the final best, so no
600 * more searching should be performed
601 */
602 static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
603 struct tcm_area *field, s32 criteria,
604 struct score *best)
605 {
606 struct score me; /* score for area */
607
608 /*
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.
612 */
613 bool first = criteria & CR_BIAS_HORIZONTAL;
614
615 assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1);
616
617 /* calculate score for current candidate */
618 if (!first) {
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);
622 }
623
624 /* the 1st candidate is always the best */
625 if (!best->a.tcm)
626 goto better;
627
628 BUG_ON(first);
629
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)))
639 goto better;
640
641 /* not better, keep going */
642 return 0;
643
644 better:
645 /* save current area as best */
646 memcpy(best, &me, sizeof(me));
647 best->a.tcm = tcm;
648 return first;
649 }
650
651 /**
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.
654 */
655 static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area,
656 struct nearness_factor *nf)
657 {
658 /**
659 * Using signed math as field coordinates may be reversed if
660 * search direction is right-to-left or bottom-to-top.
661 */
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);
666 }
667
668 /* get neighbor statistics */
669 static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
670 struct neighbor_stats *stat)
671 {
672 s16 x = 0, y = 0;
673 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
674
675 /* Clearing any exisiting values */
676 memset(stat, 0, sizeof(*stat));
677
678 /* process top & bottom edges */
679 for (x = area->p0.x; x <= area->p1.x; x++) {
680 if (area->p0.y == 0)
681 stat->edge++;
682 else if (pvt->map[x][area->p0.y - 1])
683 stat->busy++;
684
685 if (area->p1.y == tcm->height - 1)
686 stat->edge++;
687 else if (pvt->map[x][area->p1.y + 1])
688 stat->busy++;
689 }
690
691 /* process left & right edges */
692 for (y = area->p0.y; y <= area->p1.y; ++y) {
693 if (area->p0.x == 0)
694 stat->edge++;
695 else if (pvt->map[area->p0.x - 1][y])
696 stat->busy++;
697
698 if (area->p1.x == tcm->width - 1)
699 stat->edge++;
700 else if (pvt->map[area->p1.x + 1][y])
701 stat->busy++;
702 }
703 }
This page took 0.046977 seconds and 5 git commands to generate.